#include #include #include #include #include #include #include "nx_init.h" #include "scene.h" #include "render.h" #include #include #include "occlude.h" #include "gfx/ngc/nx/mesh.h" #include "charpipeline\skinning.h" #include "gfx\NxMiscFX.h" #include #include #include #include #include "dolphin/base/ppcwgpipe.h" #include "dolphin/gx/gxvert.h" extern int g_object; extern int g_view_object; extern int g_material; extern NxNgc::sScene * g_view_scene; //extern u16 colorMap[]; bool g_skip_correctable = 0; #define SHADOW_TEXTURE_SIZE 256 extern uint8 * shadowTextureData; extern uint16 shadowPalette[16]; extern uint8 * zTextureData; extern uint8 * blurTextureData; NxNgc::sMaterial * p_last_material = NULL; uint32 last_color_override = 0; uint16 last_mesh_flags = 0; bool last_correct = true; bool reload_camera = false; Mtx g_matrix0; Mtx g_matrix90; Mtx g_matrix180; Mtx g_matrix270; Mth::Vector g_shadow_object_pos; int g_kill_layer = -1; extern "C" { extern void FakeEnvMap( ROMtx m, s16 * srcPos, s16 * srcNorm, float * dstBase, u32 count ); extern void FakeEnvMapSkin( ROMtx m, s16 * srcPosNorm, float * dstBase, u32 count ); extern void FakeEnvMapFloat( ROMtx m, float * srcPos, s16 * srcNorm, float * dstBase, u32 count ); } static float * sLastUV = NULL; static bool first_mat = false; //static bool one_mat = false; extern uint16 shadowPalette[16]; //bool gOverDraw = false; bool gMeshUseCorrection = false; bool gMeshUseAniso = false; const float CORRECTION_CUTOFF = ( 25.0f * 12.0f ); const float ANISO_CUTOFF = ( 100.0f * 12.0f ); int meshes_considered = 0; namespace NxNgc { Lst::HashTable< sTextureProjectionDetails > *pTextureProjectionDetailsTable = NULL; NsCamera current_cam; #ifdef SHORT_VERT static void cam_offset( float x, float y, float z ) { Mtx m; MTXTrans( m, x, y, z ); MTXConcat( EngineGlobals.current_uploaded, m, m ); GX::LoadPosMtxImm( m, GX_PNMTX0 ); } #endif // SHORT_VERT //static void reflect_uvs( sMesh * p_mesh, float * p_tex, s16 * p_posBuffer, s16 * p_normBuffer, int step ) //{ // if ( sLastUV == p_tex ) return; // // // Inverse transform the camera position by the local to world matrix. // NsMatrix mp; //// NsMatrix mi; // // mp.copy( *((NsMatrix*)EngineGlobals.current_uploaded) ); //// mp.copy( EngineGlobals.camera ); //#ifdef SHORT_VERT // NsVector v( p_mesh->m_offset_x, p_mesh->m_offset_y, p_mesh->m_offset_z ); // mp.translate( &v, NsMatrix_Combine_Post ); //#endif // SHORT_VERT //// mi.invert( mp ); //// mp.setRight( mi.getRight() ); //// mp.setUp( mi.getUp() ); //// mp.setAt( mi.getAt() ); // //// mp.invert(); // //// mp.setPosX( mi.getPosX() ); //// mp.setPosY( mi.getPosY() ); //// mp.setPosZ( mi.getPosZ() ); // // ROMtx sm; // // sm[0][0] = mp.getRightX(); // sm[1][0] = mp.getRightY(); // sm[2][0] = mp.getRightZ(); // // sm[0][1] = mp.getUpX(); // sm[1][1] = mp.getUpY(); // sm[2][1] = mp.getUpZ(); // // sm[0][2] = mp.getAtX(); // sm[1][2] = mp.getAtY(); // sm[2][2] = mp.getAtZ(); // // sm[3][0] = mp.getPosX(); // sm[3][1] = mp.getPosY(); // sm[3][2] = mp.getPosZ(); // // if ( step == 6 ) // { // // Skinned // FakeEnvMapSkin( sm, p_posBuffer, p_tex, p_mesh->m_num_vertex ); // } // else // { // // Not Skinned // GQRSetup6( p_mesh->m_vertex_format - 1, // Pos // GQR_TYPE_S16, // 0, // UV // GQR_TYPE_F32 ); // // GQRSetup7( 14, // Normal // GQR_TYPE_S16, // 0, // UV // GQR_TYPE_F32 ); // //// NsMatrix mn; //// mn.copy( mp ); ////// mn.invert(; //// mn.setPos( 0.0f, 0.0f, 0.0f ); //// //// float shift = (float)(1<<(p_mesh->m_vertex_format-1)); //// for ( int lp = 0; lp < p_mesh->m_num_vertex; lp++ ) //// { //// NsVector in, tpos, tnorm; //// in.x = (((float)p_posBuffer[(lp*3)+0])/shift); //// in.y = (((float)p_posBuffer[(lp*3)+1])/shift); //// in.z = (((float)p_posBuffer[(lp*3)+2])/shift); //// mp.multiply( &in, &tpos ); //// in.x = (((float)p_normBuffer[(lp*3)+0])/(float)(1<<14)); //// in.y = (((float)p_normBuffer[(lp*3)+1])/(float)(1<<14)); //// in.z = (((float)p_normBuffer[(lp*3)+2])/(float)(1<<14)); //// mn.multiply( &in, &tnorm ); ////// float z1 = 1.0f / 2000.0f; ////// p_tex[(lp*2)+0] = ( ( ( ( ( tpos.x / (tpos.z+(float)gAdd) ) * (float)gScale ) + tnorm.x ) + 1.0f ) * 0.5f ) * (float)gRepeat; ////// p_tex[(lp*2)+1] = ( ( ( ( ( tpos.y / (tpos.z+(float)gAdd) ) * (float)gScale ) + tnorm.y ) + 1.0f ) * 0.5f ) * (float)gRepeat; //// //// p_tex[(lp*2)+0] = ( ( ( ( ( tpos.x / ( tpos.z > 1 ? 1 : tpos.z ) ) + tnorm.x ) * 1.0f ) * 0.5f ) + 0.5f ); //// p_tex[(lp*2)+1] = ( ( ( ( ( tpos.y / ( tpos.z > 1 ? 1 : tpos.z ) ) + tnorm.y ) * 1.0f ) * 0.5f ) + 0.5f ); //// ////// p_tex[(lp*2)+0] = ( ( ( ( tpos.x + ( tnorm.x * tpos.z ) ) * ( 0.5f * tpos.z ) ) * ( 3.0f * tpos.z ) ) + ( 0.5f * tpos.z ) ); ////// p_tex[(lp*2)+1] = ( ( ( ( tpos.y + ( tnorm.y * tpos.z ) ) * ( 0.5f * tpos.z ) ) * ( 3.0f * tpos.z ) ) + ( 0.5f * tpos.z ) ); //// ////// p_tex[(lp*2)+0] = ( ( tnorm.x ) + 1.0f ) * 0.5f; ////// p_tex[(lp*2)+1] = ( ( tnorm.y ) + 1.0f ) * 0.5f; //// } // // FakeEnvMap( sm, p_posBuffer, p_normBuffer, p_tex, p_mesh->m_num_vertex ); // // // GQR back to normal. // GQRSetup7( GQR_SCALE_128, // Pos/Normal // GQR_TYPE_S16, // GQR_SCALE_128, // GQR_TYPE_S16 ); // GQRSetup6( GQR_SCALE_256, // Weights // GQR_TYPE_U8, // GQR_SCALE_256, // GQR_TYPE_U8 ); // } // sLastUV = p_tex; //} #ifndef SHORT_VERT //static void float_reflect_uvs( sMesh * p_mesh, float * p_tex, float * p_posBuffer, s16 * p_normBuffer, int step ) //{ // if ( sLastUV == p_tex ) return; // // // Inverse transform the camera position by the local to world matrix. // NsMatrix mp; // // mp.copy( *((NsMatrix*)EngineGlobals.current_uploaded) ); // // ROMtx sm; // // sm[0][0] = mp.getRightX(); // sm[1][0] = mp.getRightY(); // sm[2][0] = mp.getRightZ(); // // sm[0][1] = mp.getUpX(); // sm[1][1] = mp.getUpY(); // sm[2][1] = mp.getUpZ(); // // sm[0][2] = mp.getAtX(); // sm[1][2] = mp.getAtY(); // sm[2][2] = mp.getAtZ(); // // sm[3][0] = mp.getPosX(); // sm[3][1] = mp.getPosY(); // sm[3][2] = mp.getPosZ(); // //// GQRSetup6( 0, // Pos //// GQR_TYPE_F32, //// 0, // UV //// GQR_TYPE_F32 ); //// //// GQRSetup7( 14, // Normal //// GQR_TYPE_S16, //// 0, // UV //// GQR_TYPE_F32 ); // // FakeEnvMapFloat( sm, p_posBuffer, p_normBuffer, p_tex, p_mesh->m_num_vertex ); // //// // GQR back to normal. //// GQRSetup7( GQR_SCALE_128, // Pos/Normal //// GQR_TYPE_S16, //// GQR_SCALE_128, //// GQR_TYPE_S16 ); //// GQRSetup6( GQR_SCALE_256, // Weights //// GQR_TYPE_U8, //// GQR_SCALE_256, //// GQR_TYPE_U8 ); // sLastUV = p_tex; //} #endif // SHORT_VERT /******************************************************************/ /* */ /* */ /******************************************************************/ void init_render_system( void ) { pTextureProjectionDetailsTable = new Lst::HashTable< sTextureProjectionDetails >( 8 ); MTXRotDeg( g_matrix0, 'y', 0.0f ); MTXRotDeg( g_matrix90, 'y', 90.0f ); MTXRotDeg( g_matrix180, 'y', 180.0f ); MTXRotDeg( g_matrix270, 'y', 270.0f ); } void set_blend_mode( uint64 mode ) { // Low 32 bits contain the mode, high 32 bits contain the fixed alpha value. uint32 actual_mode = (uint32)mode; // uint32 fixed_alpha = (uint32)( mode >> 32 ); // Only do something if the blend mode is changing. // if( actual_mode != EngineGlobals.blend_mode_value ) { switch( actual_mode ) { case vBLEND_MODE_ADD: case vBLEND_MODE_ADD_FIXED: GX::SetBlendMode ( GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_ONE, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_TRUE ); break; case vBLEND_MODE_SUBTRACT: case vBLEND_MODE_SUB_FIXED: GX::SetBlendMode ( GX_BM_SUBTRACT, GX_BL_ZERO, GX_BL_ZERO, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_TRUE ); break; case vBLEND_MODE_BLEND: case vBLEND_MODE_BLEND_FIXED: GX::SetBlendMode ( GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_TRUE ); break; case vBLEND_MODE_BRIGHTEN: case vBLEND_MODE_BRIGHTEN_FIXED: GX::SetBlendMode ( GX_BM_BLEND, GX_BL_DSTCLR, GX_BL_ONE, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_TRUE ); break; case vBLEND_MODE_MODULATE_FIXED: case vBLEND_MODE_MODULATE: GX::SetBlendMode ( GX_BM_BLEND, GX_BL_DSTCLR, GX_BL_ZERO, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_TRUE ); break; case vBLEND_MODE_DIFFUSE: default: GX::SetBlendMode ( GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_TRUE ); break; } } } void set_render_state( uint32 type, uint32 state ) { switch( type ) { case RS_ZWRITEENABLE: { if( state > 0 ) { if( EngineGlobals.z_write_enabled == FALSE ) { GX::SetZMode ( EngineGlobals.z_test_enabled ? GX_TRUE : GX_FALSE, EngineGlobals.z_test_enabled ? GX_LEQUAL : GX_ALWAYS, GX_TRUE ); EngineGlobals.z_write_enabled = TRUE; } } else { if( EngineGlobals.z_write_enabled == TRUE ) { GX::SetZMode ( EngineGlobals.z_test_enabled ? GX_TRUE : GX_FALSE, EngineGlobals.z_test_enabled ? GX_LEQUAL : GX_ALWAYS, GX_FALSE ); EngineGlobals.z_write_enabled = FALSE; } } break; } case RS_ZTESTENABLE: { if( state > 0 ) { if( EngineGlobals.z_test_enabled == FALSE ) { GX::SetZMode ( GX_TRUE, GX_LEQUAL, EngineGlobals.z_write_enabled ? GX_TRUE : GX_FALSE ); EngineGlobals.z_test_enabled = TRUE; } } else { if( EngineGlobals.z_test_enabled == TRUE ) { GX::SetZMode ( GX_FALSE, GX_ALWAYS, EngineGlobals.z_write_enabled ? GX_TRUE : GX_FALSE ); EngineGlobals.z_test_enabled = FALSE; } } break; } case RS_ALPHACUTOFF: { // GX::SetAlphaCompare(GX_GREATER, 0, GX_AOP_AND, GX_GREATER, 0 ); // // Convert from state (where 1 means "render all pixels with alpha 1 or higher") to the D3D // if( state != EngineGlobals.alpha_ref ) // { // EngineGlobals.alpha_ref = state; // if( state > 0 ) // { // D3DDevice_SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL ); // D3DDevice_SetRenderState( D3DRS_ALPHAREF, state ); // D3DDevice_SetRenderState( D3DRS_ALPHATESTENABLE, TRUE ); // } // else // { // D3DDevice_SetRenderState( D3DRS_ALPHATESTENABLE, FALSE ); // } // } break; } } } /******************************************************************/ /* */ /* */ /******************************************************************/ float frustum_sort_mid( Mth::Vector& p_sphere ) { NsVector test_in; NsVector test_mid; // D3DXMATRIX *p_world_transform; // // // Build the composite transform if required. // if( p_bbox_transform ) // { // p_world_transform = p_bbox_transform; // } // else // { // p_world_transform = NULL; // } test_in.x = p_sphere[X]; test_in.y = p_sphere[Y]; test_in.z = p_sphere[Z]; EngineGlobals.local_to_camera.multiply( &test_in, &test_mid ); // if( p_world_transform ) // { // D3DXVec3Transform( &test_mid, &test_in, p_world_transform ); // test_in.x = test_mid.x; // test_in.y = test_mid.y; // test_in.z = test_mid.z; // } // D3DXVec3Transform( &test_mid, &test_in, &EngineGlobals.view_matrix ); return test_mid.z; } struct sSortedMeshEntry { sMesh *p_mesh; float sort; sSortedMeshEntry *pNext; }; //static sSortedMeshEntry sortedMeshArray[1000]; /******************************************************************/ /* */ /* */ /******************************************************************/ static int cmp( const void *p1, const void *p2 ) { return((sSortedMeshEntry*)p1)->sort < ((sSortedMeshEntry*)p2)->sort ? -1 : ((sSortedMeshEntry*)p1)->sort > ((sSortedMeshEntry*)p2)->sort ? 1 : 0; } /******************************************************************/ /* */ /* */ /******************************************************************/ void create_texture_projection_details( sTexture *p_texture, Nx::CNgcModel *p_model, sScene *p_scene ) { sTextureProjectionDetails *p_details = new sTextureProjectionDetails; p_details->p_model = p_model; p_details->p_scene = p_scene; p_details->p_texture = p_texture; // Flag this scene as receiving shadows. // p_scene->m_flags |= SCENE_FLAG_RECEIVE_SHADOWS; pTextureProjectionDetailsTable->PutItem((uint32)p_texture, p_details ); } /******************************************************************/ /* */ /* */ /******************************************************************/ void destroy_texture_projection_details( sTexture *p_texture ) { sTextureProjectionDetails *p_details = pTextureProjectionDetailsTable->GetItem((uint32)p_texture ); if( p_details ) { pTextureProjectionDetailsTable->FlushItem((uint32)p_texture ); delete p_details; } } /******************************************************************/ /* */ /* */ /******************************************************************/ void set_texture_projection_camera( sTexture *p_texture, NsVector * p_pos, NsVector * p_at ) { // NsMatrix view_matrix; sTextureProjectionDetails *p_details = pTextureProjectionDetailsTable->GetItem((uint32)p_texture ); if( p_details ) { NsVector up; // Check for 'straight down' vector. if(( p_pos->x == p_at->x ) && ( p_pos->z == p_at->z )) { // D3DXMatrixLookAtRH( &p_details->view_matrix, p_pos, p_at, &D3DXVECTOR3( 0.0f, 0.0f, 1.0f )); up.set( 0.0f, 0.0f, 1.0f ); } else { up.set( 0.0f, 1.0f, 0.0f ); // D3DXMatrixLookAtRH( &p_details->view_matrix, p_pos, p_at, &D3DXVECTOR3( 0.0f, 1.0f, 0.0f )); } // Get the 'right' vector as the cross product of camera 'at and world 'up'. // NsVector screen_right; // NsVector screen_up; // screen_right.cross( *p_at, up ); // screen_up.cross( screen_right, *p_at ); // // screen_right.normalize(); // screen_up.normalize(); // // p_details->view_matrix.setRight( &screen_right ); // p_details->view_matrix.setUp( &screen_up ); // p_details->view_matrix.setAt( p_at ); // p_details->view_matrix.setPos( p_pos ); p_details->view_matrix.lookAt( p_pos, &up, p_at ); // D3DXMatrixOrthoRH( &p_details->projection_matrix, 96.0f, 96.0f, 1.0f, 512.0f ); } } /******************************************************************/ /* */ /* */ /******************************************************************/ //static D3DXMATRIX world; //static D3DXMATRIX view; //static D3DXMATRIX projection; void set_camera( Mth::Matrix *p_matrix, Mth::Vector *p_position, float screen_angle, float aspect_ratio, float scale ) { NsMatrix m; NsFrame f; EngineGlobals.tx = 2.0f * tanf(screen_angle*8.72664626e-03f); // tan of half (angle in radians) EngineGlobals.ty = -(EngineGlobals.tx / aspect_ratio); EngineGlobals.near = -2.0; EngineGlobals.far = -40000.0; current_cam.perspective( EngineGlobals.tx, -EngineGlobals.ty, -EngineGlobals.near, -EngineGlobals.far * 2 ); // if ( scale > 1.0f ) // { // current_cam.SetViewMatrix( 2, 2, -0.999999f ); // current_cam.SetViewMatrix( 3, 2, 0.0f ); // } EngineGlobals.tx = tanf( Mth::DegToRad( screen_angle * 0.5f )); ; // tan of half (angle in radians) EngineGlobals.ty = -(EngineGlobals.tx / aspect_ratio); EngineGlobals.sx = 1.0f/sqrtf(1.0f+1.0f/(EngineGlobals.tx*EngineGlobals.tx)); EngineGlobals.sy = 1.0f/sqrtf(1.0f+1.0f/(EngineGlobals.ty*EngineGlobals.ty)); EngineGlobals.cx = 1.0f/sqrtf(1.0f+EngineGlobals.tx*EngineGlobals.tx); EngineGlobals.cy = 1.0f/sqrtf(1.0f+EngineGlobals.ty*EngineGlobals.ty); // EngineGlobals.near = -2.0; // EngineGlobals.far = -40000.0; m.setRight( -p_matrix->GetRight().GetX(), -p_matrix->GetRight().GetY(), -p_matrix->GetRight().GetZ() ); m.setUp( p_matrix->GetUp().GetX(), p_matrix->GetUp().GetY(), p_matrix->GetUp().GetZ() ); m.setAt( -p_matrix->GetAt().GetX(), -p_matrix->GetAt().GetY(), -p_matrix->GetAt().GetZ() ); m.setPos( p_position->GetX(), p_position->GetY(), p_position->GetZ() ); f.setModelMatrix( &m ); current_cam.setFrame( &f ); current_cam.begin(); // No need to end... EngineGlobals.world_to_camera = *current_cam.getCurrent(); EngineGlobals.local_to_camera = *current_cam.getCurrent(); EngineGlobals.camera = m; EngineGlobals.object_pos.x = 0.0f; EngineGlobals.object_pos.y = 0.0f; EngineGlobals.object_pos.z = 0.0f; MTXCopy ( (MtxPtr)current_cam.getCurrent(), EngineGlobals.current_uploaded ); // NsVector wscale( 1.0f, 1.0f, 1.0f ); //scale, scale, scale ); NsVector wscale( scale, scale, scale ); NsMatrix ms; ms.copy( m ); ms.scale( &wscale, NsMatrix_Combine_Pre ); f.setModelMatrix( &ms ); current_cam.setFrame( &f ); current_cam.end(); current_cam.begin(); // No need to end... // NsMatrix ms; // ms.setRight( m.getRightX() * scale, m.getRightY() * scale, m.getRightZ() * scale ); // ms.setUp( m.getUpX() * scale, m.getUpY() * scale, m.getUpZ() * scale ); // ms.setAt( m.getAtX() * scale, m.getAtY() * scale, m.getAtZ() * scale ); // ms.setPos( m.getPosX(), m.getPosY(), m.getPosZ() ); } /******************************************************************/ /* */ /* Checks a bounding box against the current view frustum */ /* (iBgnoring far clipping), */ /* returns true if any part is visible. */ /* Horribly inefficient at present. */ /* */ /******************************************************************/ bool frustum_check_box( Mtx m, Mth::CBBox& box ) { Vec test_in, test_out; uint32 cumulative_projection_space_outcode = 0xFF; float min_x = box.GetMin().GetX(); float min_y = box.GetMin().GetY(); float min_z = box.GetMin().GetZ(); float max_x = box.GetMax().GetX(); float max_y = box.GetMax().GetY(); float max_z = box.GetMax().GetZ(); for( uint32 v = 0; v < 8; ++v ) { uint32 projection_space_outcode = 0; test_in.x = ( v & 0x04 ) ? max_x : min_x; test_in.y = ( v & 0x02 ) ? max_y : min_y; test_in.z = ( v & 0x01 ) ? max_z : min_z; // At this point it's important to check to see whether the point is in postive or negative z-space, since // after the projection transform, both very large camera space z values and camera space z values where z < 0 // will give results with z > 1. (Camera space values in the range [0,near] give negative projection space z values). MTXMultVec( m, &test_in, &test_out ); // if(( -test_mid.z < 0.0f ) && ( !EngineGlobals.is_orthographic )) // { // test_out.x = -test_out.x; // test_out.y = -test_out.y; // } if( test_out.x > 1.0f ) { projection_space_outcode |= 0x01; } else if( test_out.x < -1.0f ) { projection_space_outcode |= 0x02; } if( test_out.y > 1.0f ) { projection_space_outcode |= 0x04; } else if( test_out.y < -1.0f ) { projection_space_outcode |= 0x08; } cumulative_projection_space_outcode &= projection_space_outcode; if( cumulative_projection_space_outcode == 0 ) { // Early out. return true; } } return false; } bool frustum_check_sphere( Mtx m, Mth::Vector& p_sphere ) { // Vec in; // Vec out; // // in.x = p_sphere[X]; // in.y = p_sphere[Y]; // in.z = p_sphere[Z]; // //// NsMatrix mat; //// mat.copy( EngineGlobals.local_to_camera ); //// NsVector s( 0.5f, 0.5f, 0.5f ); //// mat.scale( &s, NsMatrix_Combine_Post ); //// //// //// mat.multiply( &in, &out ); //// EngineGlobals.local_to_camera.multiply( &in, &out ); // // MTXMultVec( m, &in, &out ); // // float x = out.x; // float y = out.y; // float z = out.z; // float R = p_sphere[W]; // // if ( R < ( z - EngineGlobals.near ) ) return false; // if ( R < ( EngineGlobals.far - z ) ) return false; // // float sx_z = EngineGlobals.sx * z; // float cx_x = EngineGlobals.cx * x; // if ( R < ( sx_z - cx_x ) ) return false; // if ( R < ( sx_z + cx_x ) ) return false; // // float sy_z = EngineGlobals.sy * z; // float cy_y = EngineGlobals.cy * y; // if ( R < ( sy_z - cy_y ) ) return false; // if ( R < ( sy_z + cy_y ) ) return false; // // return true; Mth::CBBox bbox; Mth::Vector p; p.Set( p_sphere[X] + p_sphere[W], p_sphere[Y], p_sphere[Z] ); bbox.AddPoint( p ); p.Set( p_sphere[X] - p_sphere[W], p_sphere[Y], p_sphere[Z] ); bbox.AddPoint( p ); p.Set( p_sphere[X] , p_sphere[Y]+ p_sphere[W], p_sphere[Z] ); bbox.AddPoint( p ); p.Set( p_sphere[X] , p_sphere[Y]- p_sphere[W], p_sphere[Z] ); bbox.AddPoint( p ); p.Set( p_sphere[X] , p_sphere[Y], p_sphere[Z]+ p_sphere[W] ); bbox.AddPoint( p ); p.Set( p_sphere[X] , p_sphere[Y], p_sphere[Z]- p_sphere[W] ); bbox.AddPoint( p ); return frustum_check_box( m, bbox ); } /******************************************************************/ /* */ /* Checks a bounding box against the current view frustum */ /* (iBgnoring far clipping), */ /* returns true if any part is visible. */ /* Horribly inefficient at present. */ /* */ /******************************************************************/ bool frustum_check_box( Mth::CBBox& box ) { int lp; unsigned int code; unsigned int codeAND; f32 rx[8], ry[8], rz[8]; f32 p[GX_PROJECTION_SZ]; f32 vp[GX_VIEWPORT_SZ]; u32 clip_x; u32 clip_y; u32 clip_w; u32 clip_h; float clip_l; float clip_t; float clip_r; float clip_b; MtxPtr view; float minx, miny, minz; float maxx, maxy, maxz; GX::GetProjectionv( p ); GX::GetViewportv( vp ); GX::GetScissor ( &clip_x, &clip_y, &clip_w, &clip_h ); clip_l = (float)clip_x; clip_t = (float)clip_y; clip_r = (float)(clip_x + clip_w); clip_b = (float)(clip_y + clip_h); view = (MtxPtr)&EngineGlobals.local_to_camera; minx = box.GetMin().GetX(); miny = box.GetMin().GetY(); minz = box.GetMin().GetZ(); maxx = box.GetMax().GetX(); maxy = box.GetMax().GetY(); maxz = box.GetMax().GetZ(); GX::Project ( minx, miny, minz, view, p, vp, &rx[0], &ry[0], &rz[0] ); GX::Project ( minx, maxy, minz, view, p, vp, &rx[1], &ry[1], &rz[1] ); GX::Project ( maxx, miny, minz, view, p, vp, &rx[2], &ry[2], &rz[2] ); GX::Project ( maxx, maxy, minz, view, p, vp, &rx[3], &ry[3], &rz[3] ); GX::Project ( minx, miny, maxz, view, p, vp, &rx[4], &ry[4], &rz[4] ); GX::Project ( minx, maxy, maxz, view, p, vp, &rx[5], &ry[5], &rz[5] ); GX::Project ( maxx, miny, maxz, view, p, vp, &rx[6], &ry[6], &rz[6] ); GX::Project ( maxx, maxy, maxz, view, p, vp, &rx[7], &ry[7], &rz[7] ); // Generate clip code. {page 178, Procedural Elements for Computer Graphics} // 1001|1000|1010 // | | // ----+----+---- // 0001|0000|0010 // | | // ----+----+---- // 0101|0100|0110 // | | // // Addition: Bit 4 is used for z behind. codeAND = 0x001f; for ( lp = 0; lp < 8; lp++ ) { // Only check x/y if z is valid (if z is invalid, the x/y values will be garbage). if ( rz[lp] > 1.0f ) { code = (1<<4); } else { code = 0; if ( rx[lp] < clip_l ) code |= (1<<0); if ( rx[lp] > clip_r ) code |= (1<<1); if ( ry[lp] > clip_b ) code |= (1<<2); if ( ry[lp] < clip_t ) code |= (1<<3); } codeAND &= code; if ( !codeAND ) return true; } if ( !codeAND ) return true; return false; // m_cull.clipCodeAND = codeAND; // // If any bits are set in the AND code, the object is invisible. // if ( codeAND ) { // m_cull.visible = 0; // } // // return !m_cull.visible; // 0 = not culled, 1 = culled. // // NsVector test_in, test_out; // // uint32 cumulative_projection_space_outcode = 0xFF; // float min_x = box.GetMin().GetX(); // float min_y = box.GetMin().GetY(); // float min_z = box.GetMin().GetZ(); // float max_x = box.GetMax().GetX(); // float max_y = box.GetMax().GetY(); // float max_z = box.GetMax().GetZ(); // // for( uint32 v = 0; v < 8; ++v ) // { // uint32 projection_space_outcode = 0; // // test_in.x = ( v & 0x04 ) ? max_x : min_x; // test_in.y = ( v & 0x02 ) ? max_y : min_y; // test_in.z = ( v & 0x01 ) ? max_z : min_z; // // // At this point it's important to check to see whether the point is in postive or negative z-space, since // // after the projection transform, both very large camera space z values and camera space z values where z < 0 // // will give results with z > 1. (Camera space values in the range [0,near] give negative projection space z values). // EngineGlobals.local_to_camera.multiply( &test_in, &test_out ); //// MTXMultVec( m, &test_in, &test_out ); // //// if(( -test_mid.z < 0.0f ) && ( !EngineGlobals.is_orthographic )) //// { //// test_out.x = -test_out.x; //// test_out.y = -test_out.y; //// } // // if( test_out.x > 1.0f ) // { // projection_space_outcode |= 0x01; // } // else if( test_out.x < -1.0f ) // { // projection_space_outcode |= 0x02; // } // // if( test_out.y > 1.0f ) // { // projection_space_outcode |= 0x04; // } // else if( test_out.y < -1.0f ) // { // projection_space_outcode |= 0x08; // } // // cumulative_projection_space_outcode &= projection_space_outcode; // // if( cumulative_projection_space_outcode == 0 ) // { // // Early out. // return true; // } // } // return false; } /******************************************************************/ /* Quick determination of if something is visible or not, uses */ /* the previously calculated s and c vectors and the */ /* WorldToCamera transform (note, no attempt is made to ensure */ /* this is the same camera that the object will eventually be */ /* rendered with. */ /******************************************************************/ bool IsVisible( Mth::Vector &sphere ) { NsVector in; NsVector out; in.x = sphere.GetX(); in.y = sphere.GetY(); in.z = sphere.GetZ(); EngineGlobals.world_to_camera.multiply( &in, &out ); float x = out.x; float y = out.y; float z = out.z; float R = sphere[W]; if( //( -z + R < EngineGlobals.near ) || // if ( R < ( -10000.0f/*EngineGlobals.far*/ - z ) ) return false; ( R < ( z - EngineGlobals.near ) ) || ( R < ( EngineGlobals.far - z ) ) || ( R < EngineGlobals.sy * z + EngineGlobals.cy * y ) || ( R < EngineGlobals.sy * z - EngineGlobals.cy * y ) || ( R < EngineGlobals.sx * z - EngineGlobals.cx * x ) || ( R < EngineGlobals.sx * z + EngineGlobals.cx * x )) { return false; } else { if( TestSphereAgainstOccluders( &sphere )) { // Occluded. return false; } else { return true; } } // if (Rcat( m_matTexProj, matBiasScale ); // This is just for displaying the frustum lines. /* // Convert from homogeneous texmap coords to worldspace D3DXMATRIX matInvTexView, matInvTexProj; D3DXMatrixInverse( &matInvTexView, NULL, &matTexView ); D3DXMatrixInverse( &matInvTexProj, NULL, &matTexProj ); for( int i = 0; i < 8; i++ ) { D3DXVECTOR4 vT( 0.0f, 0.0f, 0.0f, 1.0f ); vT.x = (i%2) * ( i&0x2 ? -1.0f : 1.0f ); vT.y = (i%2) * ( i&0x4 ? -1.0f : 1.0f ); vT.z = (i%2) * ( 1.0f ); D3DXVec4Transform( &vT, &vT, &matInvTexProj ); D3DXVec4Transform( &vT, &vT, &matInvTexView ); g_FrustumLines[i].x = vT.x / vT.w; g_FrustumLines[i].y = vT.y / vT.w; g_FrustumLines[i].z = vT.z / vT.w; } */ } /******************************************************************/ /* */ /* */ /******************************************************************/ void render_shadow_targets( void ) { GX::SetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE); // D3DXMATRIX stored_view_matrix = EngineGlobals.view_matrix; // D3DXMATRIX stored_projection_matrix = EngineGlobals.projection_matrix; // Goes through the list of render target textures, rendering to each one in turn. pTextureProjectionDetailsTable->IterateStart(); sTextureProjectionDetails *p_details = pTextureProjectionDetailsTable->IterateNext(); // // // Set the basic pixel shader that just copies a single color (in C0) over. // EngineGlobals.pixel_shader_constants[0] = 1.0f; // EngineGlobals.pixel_shader_constants[1] = 1.0f; // EngineGlobals.pixel_shader_constants[2] = 1.0f; // EngineGlobals.pixel_shader_constants[3] = 1.0f; // EngineGlobals.upload_pixel_shader_constants = true; // set_pixel_shader( PixelShader3 ); // EngineGlobals.pixel_shader_override = PixelShader3; // // Clear background of shadow. // NsCamera cam; // cam.orthographic( 0, 0, 640, 448 ); // cam.begin(); // // GX::SetZMode ( GX_FALSE, GX_ALWAYS, GX_TRUE ); // //NsPrim::box( 0, 0, 256, 256, (GXColor){128,128,128,255} ); // float zf = -( EngineGlobals.far + 0.5f ); // NsPrim::quad( 0, 0, zf, 640, 0, zf, 640, 448, zf, 0, 448, zf, (GXColor){128,128,128,255} ); // cam.end(); while( p_details ) { if( p_details->p_model ) { // Set the new render target. /// D3DDevice_SetRenderTarget( p_details->p_texture->pD3DSurface, NULL ); // // D3DDevice_Clear( 0, 0, D3DCLEAR_TARGET, 0, 1.0f, 0 ); // Set the view and projection transforms. // EngineGlobals.view_matrix = p_details->view_matrix; // EngineGlobals.projection_matrix = p_details->projection_matrix; // EngineGlobals.is_orthographic = true; // Render all instances for the CGeom's contained in this model. int num_geoms = p_details->p_model->GetNumGeoms(); for( int i = 0; i < num_geoms; ++i ) { Nx::CNgcGeom *p_ngc_geom = static_cast( p_details->p_model->GetGeomByIndex( i )); CInstance *p_instance = p_ngc_geom->GetInstance(); if( p_instance->GetActive()) { // Create the camera and attach a frame. NsCamera cam; //NsFrame frame; //cam.setFrame( &frame ); // Assume parallel projection in this case. cam.orthographic(); cam.orthographic( 0, 0, 256, 256 ); cam.setViewWindow( 128, 128 ); // Position the camera somewhere near the object, pointing directly at it. float at[3]; float pos[3]; at[0] = p_instance->GetTransform()->GetPos()[X]; at[1] = p_instance->GetTransform()->GetPos()[Y]; at[2] = p_instance->GetTransform()->GetPos()[Z]; pos[0] = p_instance->GetTransform()->GetPos()[X]; pos[1] = p_instance->GetTransform()->GetPos()[Y] + 64.0f; pos[2] = p_instance->GetTransform()->GetPos()[Z]; g_shadow_object_pos = p_instance->GetTransform()->GetPos(); g_shadow_object_pos[Y] += ( 12.0f * 3.0f ); // Amount of leeway... // Also need to take account of the view offset. Mth::Vector object_up = p_instance->GetTransform()->GetUp(); at[0] += object_up.GetX() * 36.0f; at[1] += object_up.GetY() * 36.0f; at[2] += object_up.GetZ() * 36.0f; pos[0] += object_up.GetX() * 36.0f; pos[1] += object_up.GetY() * 36.0f; pos[2] += object_up.GetZ() * 36.0f; cam.pos( pos[0], pos[1], pos[2] ); cam.up( 1.0f, 0.0f, 0.0f ); cam.lookAt( at[0], at[1], at[2] ); // EngineGlobals.world_to_camera.identity(); // EngineGlobals.world_to_camera.setPos( pos[0], pos[1], pos[2] ); // EngineGlobals.world_to_camera.setRight( 1.0f, 0.0f, 0.0f ); // EngineGlobals.world_to_camera.setUp( 0.0f, 0.0f, 1.0f ); // EngineGlobals.world_to_camera.setAt( 0.0f, -1.0f, 0.0f ); cam.begin(); MTXCopy ( (MtxPtr)cam.getCurrent(), EngineGlobals.current_uploaded ); EngineGlobals.world_to_camera.copy( *cam.getCurrent() ); EngineGlobals.shadow_camera.copy( *cam.getCurrent() ); // Flag the scene as having the shadow version rendered. p_instance->GetScene()->m_flags |= SCENE_FLAG_RENDERING_SHADOW; // Render the model. // ROMtx bone_mtx[60]; // p_instance->Transform( vRENDER_SHADOW_1ST_PASS, bone_mtx, NULL ); // p_instance->ClearFlag( NxNgc::CInstance::INSTANCE_FLAG_TRANSFORM_ME ); p_instance->Render( vRENDER_SHADOW_1ST_PASS ); // Clear the flag the scene as having the shadow version rendered. p_instance->GetScene()->m_flags &= ~SCENE_FLAG_RENDERING_SHADOW; // Flag the scene as self shadowing. p_instance->GetScene()->m_flags |= SCENE_FLAG_SELF_SHADOWS; } } } p_details = pTextureProjectionDetailsTable->IterateNext(); } // // // Pixel shader override no longer required. // EngineGlobals.pixel_shader_override = 0; // // // Restore the view and projection transforms. // EngineGlobals.view_matrix = stored_view_matrix; // EngineGlobals.projection_matrix = stored_projection_matrix; // EngineGlobals.is_orthographic = false; // // // Restore the world transform. // D3DDevice_SetTransform( D3DTS_WORLD, &EngineGlobals.world_matrix ); // // // Restore the default render target. // D3DDevice_SetRenderTarget( EngineGlobals.p_RenderSurface, EngineGlobals.p_ZStencilSurface ); } /******************************************************************/ /* */ /* */ /******************************************************************/ void render_shadow_meshes( sScene *p_scene, int *p_mesh_indices, int num_meshes ) { } void figure_wibble_vc( sScene *p_scene ) { if ( !p_scene->mp_scene_data ) return; // The vertex color wibble flag is placed in pass 0. NxNgc::sMaterialVCWibbleKeyHeader * p_key_header = p_scene->mp_vc_wibble; NxNgc::sMaterialVCWibbleKey * p_key = (NxNgc::sMaterialVCWibbleKey *)&p_key_header[1]; int current_time = (int)Tmr::GetTime(); uint32 * p_col = p_scene->mp_col_pool; for ( int wibble = 0; wibble < p_scene->mp_scene_data->m_num_vc_wibbles; wibble++ ) { int num_keys = p_key_header->m_num_frames; int phase_shift = p_key_header->m_phase; // Time parameters. int start_time = p_key[0].m_time; int end_time = p_key[(num_keys - 1)].m_time; int period = end_time - start_time; int time = start_time + (( current_time + phase_shift ) % period ); // Locate the keyframe. int key; for( key = num_keys - 1; key >= 0; --key ) { if( time >= p_key[key].m_time ) { break; } } // Parameter expressing how far we are between between this keyframe and the next. float t = (float)( time - p_key[key].m_time ) / (float)( p_key[key+1].m_time - p_key[key].m_time ); // Interpolate the color. GXColor rgba; rgba.r = (uint8)((( 1.0f - t ) * p_key[key].m_color.r ) + ( t * p_key[key + 1].m_color.r )); rgba.g = (uint8)((( 1.0f - t ) * p_key[key].m_color.g ) + ( t * p_key[key + 1].m_color.g )); rgba.b = (uint8)((( 1.0f - t ) * p_key[key].m_color.b ) + ( t * p_key[key + 1].m_color.b )); rgba.a = (uint8)((( 1.0f - t ) * p_key[key].m_color.a ) + ( t * p_key[key + 1].m_color.a )); p_col[wibble] = *((uint32*)&rgba); // Next wibble sequence. p_key_header = (NxNgc::sMaterialVCWibbleKeyHeader *)&p_key[num_keys]; p_key = (NxNgc::sMaterialVCWibbleKey *)&p_key_header[1]; } } //sMaterialHeader * p_mat = p_mesh->mp_dl->m_material.p_header; //sMaterialPassHeader * p_pass = (sMaterialPassHeader *)&p_mat[1]; // Cached GX commands. float * g_p_pos = NULL; char * g_p_col0 = NULL; //char * g_p_col1 = NULL; GXColor g_col0 = (GXColor){0,0,0,0}; //GXColor g_col1 = (GXColor){0,0,0,0}; static void _reset( void ) { g_p_pos = NULL; g_p_col0 = NULL; // g_p_col1 = NULL; g_col0 = (GXColor){0,0,0,0}; // g_col1 = (GXColor){0,0,0,0}; GX::SetChanMatColor( GX_COLOR0A0, g_col0 ); // GX::SetChanMatColor( GX_COLOR0A0, g_col1 ); } static void _set_pos( float * p_pos ) { if ( g_p_pos != p_pos ) { GX::SetArray( GX_VA_POS, p_pos, sizeof( float ) * 3 ); g_p_pos = p_pos; } } static void _set_col0( char * p_col0 ) { if ( g_p_col0 != p_col0 ) { GX::SetArray( GX_VA_CLR0, p_col0, sizeof( uint32 ) ); g_p_col0 = p_col0; } } //static void _set_col1( char * p_col1 ) //{ // if ( g_p_col1 != p_col1 ) // { // GX::SetArray( GX_VA_CLR1, p_col1, sizeof( uint32 ) ); // g_p_col1 = p_col1; // } //} static void _set_mat0( GXColor col ) { if ( ( col.r != g_col0.r ) || ( col.g != g_col0.g ) || ( col.b != g_col0.b ) || ( col.a != g_col0.a ) ) { g_col0 = col; GX::SetChanMatColor( GX_COLOR0A0, col ); } } //static void _set_mat1( GXColor col ) //{ // if ( ( col.r != g_col1.r ) || ( col.g != g_col1.g ) || ( col.b != g_col1.b ) || ( col.a != g_col1.a ) ) // { // g_col1 = col; // GX::SetChanMatColor( GX_COLOR1A1, col ); // } //} static void submit_mesh( sScene *p_scene, sMesh * p_mesh, s16* p_posNormBuffer, Mth::Matrix * p_bone_xform, Mth::Matrix * p_instance_xform, int * p_array_base, int * p_col_base, int * p_layer, float * p_pm, GXColor * p_base_color, bool * set_base_color, bool * p_world_fog, uint32 flags ) { // if ( g_skip_correctable && p_mesh->mp_dl->m_material.p_header->m_flags & (1<<6) ) return; if ( (int)p_mesh->mp_dl->m_material.p_header->m_layer_id == g_kill_layer ) return; if ( !p_posNormBuffer ) { // Deal with cloned pos pools. if ( p_mesh->mp_dl->mp_pos_pool ) { _set_pos( p_mesh->mp_dl->mp_pos_pool ); } else { // Deal with verts outside of 65535. _set_pos( &p_scene->mp_pos_pool[p_mesh->mp_dl->m_array_base*3] ); } } // Deal with cloned color pools. if ( p_mesh->mp_dl->mp_col_pool ) { _set_col0( &((char*)p_mesh->mp_dl->mp_col_pool)[0] ); // if ( p_mesh->mp_dl->m_material.p_header->m_flags & (1<<6) ) // { // _set_col1( &((char*)p_mesh->mp_dl->mp_col_pool)[2] ); // } } else { // Deal with resetting cloned color pools. // Assumes that this isn't a skinned object. _set_col0( &((char*)p_scene->mp_col_pool)[0] ); // if ( p_mesh->mp_dl->m_material.p_header->m_flags & (1<<6) ) // { // _set_col1( &((char*)p_scene->mp_col_pool)[2] ); // } } // Deal with zbias. if ( (int)p_mesh->mp_dl->m_material.p_header->m_layer_id != *p_layer ) { *p_layer = p_mesh->mp_dl->m_material.p_header->m_layer_id; float layer = p_mesh->mp_dl->m_material.p_header->m_layer_id; float value = p_pm[6] + ( 150.0f * layer ) * p_pm[5]; GXWGFifo.u8 = GX_LOAD_XF_REG; GXWGFifo.u16 = 0; GXWGFifo.u16 = 0x1025; GXWGFifo.f32 = value; } // Billboard tweaking. // enum BillboardType // { // BBT_NOT_BILLBOARD, // BBT_SCREEN_ALIGNED, // BBT_AXIAL_ALIGNED, // }; // if ( p_mesh->mp_mod ) // { // Mtx t; // Mtx m; // //// MTXTrans( m, p_mesh->mp_mod.offset->GetX(), p_mesh->mp_mod.offset->GetY(), p_mesh->mp_mod.offset->GetZ() ); //// //// MTXRotAxisDeg( // // float w = p_mesh->mp_mod->offset[W]; // Mth::ERot90 rot = *((Mth::ERot90*)&w); // // if ( p_mesh->mp_mod->scale[X] > 1.0f ) OSReport( "X Scale > 1.0f: %8.3f\n", p_mesh->mp_mod->scale[X] ); // if ( p_mesh->mp_mod->scale[Y] > 1.0f ) OSReport( "Y Scale > 1.0f: %8.3f\n", p_mesh->mp_mod->scale[Y] ); // if ( p_mesh->mp_mod->scale[Z] > 1.0f ) OSReport( "Z Scale > 1.0f: %8.3f\n", p_mesh->mp_mod->scale[Z] ); // // switch ( rot ) // { // default: // case Mth::ROT_0: // MTXScaleApply( g_matrix0, t, p_mesh->mp_mod->scale[X], p_mesh->mp_mod->scale[Y], p_mesh->mp_mod->scale[Z] ); // break; // case Mth::ROT_90: // MTXScaleApply( g_matrix90, t, p_mesh->mp_mod->scale[X], p_mesh->mp_mod->scale[Y], p_mesh->mp_mod->scale[Z] ); // break; // case Mth::ROT_180: // MTXScaleApply( g_matrix180, t, p_mesh->mp_mod->scale[X], p_mesh->mp_mod->scale[Y], p_mesh->mp_mod->scale[Z] ); // break; // case Mth::ROT_270: // MTXScaleApply( g_matrix270, t, p_mesh->mp_mod->scale[X], p_mesh->mp_mod->scale[Y], p_mesh->mp_mod->scale[Z] ); // break; // } // t[0][3] = p_mesh->mp_mod->offset[X]; // t[1][3] = p_mesh->mp_mod->offset[Y]; // t[2][3] = p_mesh->mp_mod->offset[Z]; // MTXConcat( EngineGlobals.current_uploaded, t, m ); // // GX::LoadPosMtxImm( m, GX_PNMTX0 ); // reload_camera = true; // } // Set Fog color if necessary. bool mesh_world_fog = true; if ( p_mesh->mp_dl->m_material.p_header ) { switch ( p_mesh->mp_dl->m_material.p_header->m_base_blend ) { case vBLEND_MODE_ADD: case vBLEND_MODE_ADD_FIXED: case vBLEND_MODE_SUBTRACT: case vBLEND_MODE_SUB_FIXED: mesh_world_fog = false; break; default: break; } } if ( mesh_world_fog != *p_world_fog ) { *p_world_fog = mesh_world_fog; if ( mesh_world_fog ) { Nx::CFog::sSetFogColor(); } else { GX::SetFogColor( (GXColor){0,0,0,0} ); } } MaterialSubmit( p_mesh, p_scene ); switch ( p_mesh->mp_dl->mp_object_header->m_billboard_type ) { case 2: { NsMatrix* p_matrix = &EngineGlobals.world_to_camera; NsVector at = *p_matrix->getAt(); // at.x = -at.x; // at.y = -at.y; // at.z = -at.z; NsVector screen_right; NsVector screen_up; NsVector screen_at; NsMatrix root; // Create coordinate system based on camera at & pivot axis. screen_up.set( p_mesh->mp_dl->mp_object_header->m_axis[X], p_mesh->mp_dl->mp_object_header->m_axis[Y], p_mesh->mp_dl->mp_object_header->m_axis[Z] ); // screen_right.cross( *p_matrix->getAt(), screen_up ); screen_right.cross( at, screen_up ); screen_at.cross( screen_up, screen_right ); screen_right.normalize(); screen_at.normalize(); root.setRightX( screen_right.x ); root.setRightY( screen_up.x ); root.setRightZ( screen_at.x ); root.setUpX( screen_right.y ); root.setUpY( screen_up.y ); root.setUpZ( screen_at.y ); root.setAtX( screen_right.z ); root.setAtY( screen_up.z ); root.setAtZ( screen_at.z ); // root.setRightX( screen_right.x ); // root.setRightY( screen_right.y ); // root.setRightZ( screen_right.z ); // // root.setUpX( screen_up.x ); // root.setUpY( screen_up.y ); // root.setUpZ( screen_up.z ); // // root.setAtX( screen_at.x ); // root.setAtY( screen_at.y ); // root.setAtZ( screen_at.z ); root.setPosX( p_mesh->mp_dl->mp_object_header->m_origin[X] ); root.setPosY( p_mesh->mp_dl->mp_object_header->m_origin[Y] ); root.setPosZ( p_mesh->mp_dl->mp_object_header->m_origin[Z] ); root.cat( EngineGlobals.world_to_camera, root ); GX::LoadPosMtxImm( (MtxPtr)&root, GX_PNMTX0 ); //GXSetCurrentMtx( GX_PNMTX1 ); reload_camera = true; } break; case 1: { NsMatrix* p_matrix = &EngineGlobals.world_to_camera; NsMatrix root; // Just transpose the matrix for screen-facing. root.setRightX( p_matrix->getRightX() ); root.setRightY( p_matrix->getUpX() ); root.setRightZ( p_matrix->getAtX() ); root.setUpX( p_matrix->getRightY() ); root.setUpY( p_matrix->getUpY() ); root.setUpZ( p_matrix->getAtY() ); root.setAtX( p_matrix->getRightZ() ); root.setAtY( p_matrix->getUpZ() ); root.setAtZ( p_matrix->getAtZ() ); root.setPosX( p_mesh->mp_dl->mp_object_header->m_origin[X] ); root.setPosY( p_mesh->mp_dl->mp_object_header->m_origin[Y] ); root.setPosZ( p_mesh->mp_dl->mp_object_header->m_origin[Z] ); root.cat( EngineGlobals.world_to_camera, root ); GX::LoadPosMtxImm( (MtxPtr)&root, GX_PNMTX0 ); //GXSetCurrentMtx( GX_PNMTX1 ); reload_camera = true; } break; default: // Don't do anything - not a billboard. //GXSetCurrentMtx( GX_PNMTX0 ); break; } // // Create array of bone matrices if required. // NsMatrix bone_xform[80]; // if ( p_scene->m_numHierarchyObjects && p_bone_xform ) // { // for ( int bone = 0; bone < num_bones; bone++ ) // { // Mth::Matrix temp = p_bone_xform[bone] * *p_instance_xform; // NsMatrix local; // // local.setRightX( temp.GetRight()[X] ); // local.setRightY( temp.GetUp()[X] ); // local.setRightZ( temp.GetAt()[X] ); // // local.setUpX( temp.GetRight()[Y] ); // local.setUpY( temp.GetUp()[Y] ); // local.setUpZ( temp.GetAt()[Y] ); // // local.setAtX( temp.GetRight()[Z] ); // local.setAtY( temp.GetUp()[Z] ); // local.setAtZ( temp.GetAt()[Z] ); // // local.setPosX( temp.GetPos()[X] ); // local.setPosY( temp.GetPos()[Y] ); // local.setPosZ( temp.GetPos()[Z] ); // // bone_xform[bone].cat( EngineGlobals.world_to_camera, local ); // } // } if ( p_scene->m_numHierarchyObjects && p_bone_xform ) { NsMatrix bone_xform; Mth::Matrix temp = p_bone_xform[p_mesh->m_bone_idx] * *p_instance_xform; NsMatrix local; local.setRightX( temp.GetRight()[X] ); local.setRightY( temp.GetUp()[X] ); local.setRightZ( temp.GetAt()[X] ); local.setUpX( temp.GetRight()[Y] ); local.setUpY( temp.GetUp()[Y] ); local.setUpZ( temp.GetAt()[Y] ); local.setAtX( temp.GetRight()[Z] ); local.setAtY( temp.GetUp()[Z] ); local.setAtZ( temp.GetAt()[Z] ); local.setPosX( temp.GetPos()[X] ); local.setPosY( temp.GetPos()[Y] ); local.setPosZ( temp.GetPos()[Z] ); bone_xform.cat( EngineGlobals.world_to_camera, local ); GX::LoadPosMtxImm( (MtxPtr)&bone_xform, GX_PNMTX0 ); reload_camera = true; GX::LoadNrmMtxImm((MtxPtr)&bone_xform, GX_PNMTX0); } if ( /*p_scene->mp_scene_data->m_num_nrm ||*/ p_posNormBuffer || ( p_scene->m_numHierarchyObjects && p_bone_xform ) ) { // GXLightObj light_obj[3]; // // // Always set ambient & diffuse colors. // GX::SetChanAmbColor( GX_COLOR0A0, NxNgc::EngineGlobals.ambient_light_color ); //// GX::SetChanAmbColor( GX_COLOR0A0, (GXColor){128,128,128,255} ); //// GX::SetChanAmbColor( GX_COLOR1A1, NxNgc::EngineGlobals.ambient_light_color ); // // GX::InitLightColor( &light_obj[0], NxNgc::EngineGlobals.diffuse_light_color[0] ); // GX::InitLightPos( &light_obj[0], NxNgc::EngineGlobals.light_x[0], NxNgc::EngineGlobals.light_y[0], NxNgc::EngineGlobals.light_z[0] ); // GX::LoadLightObjImm( &light_obj[0], GX_LIGHT0 ); // // GX::InitLightColor( &light_obj[1], NxNgc::EngineGlobals.diffuse_light_color[1] ); // GX::InitLightPos( &light_obj[1], NxNgc::EngineGlobals.light_x[1], NxNgc::EngineGlobals.light_y[1], NxNgc::EngineGlobals.light_z[1] ); // GX::LoadLightObjImm( &light_obj[1], GX_LIGHT1 ); // // // Set channel control for diffuse. // GX::SetChanCtrl( GX_COLOR0, GX_ENABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT0|GX_LIGHT1, GX_DF_CLAMP, GX_AF_NONE ); // GX::SetChanCtrl( GX_ALPHA0, GX_DISABLE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); // //// if ( p_mesh->mp_dl->m_material.p_header->m_shininess > 0.0f ) //// { //// // Set channel control for specular. //// Vec ldir; //// //// ldir.x = 0.0f; //NxNgc::EngineGlobals.light_x[0] * ( 1.0f / 200000.0f ); //// ldir.y = 0.0f; //NxNgc::EngineGlobals.light_y[0] * ( 1.0f / 200000.0f ); //// ldir.z = -1.0f; //NxNgc::EngineGlobals.light_z[0] * ( 1.0f / 200000.0f ); //// //// GX::InitSpecularDirv( &light_obj[2], &ldir ); //// GX::InitLightShininess( &light_obj[2], 8.0f ); //// GX::InitLightColor( &light_obj[2], (GXColor){255,255,255,255} ); //// GX::LoadLightObjImm( &light_obj[2], GX_LIGHT2 ); //// //// GX::SetChanCtrl( GX_COLOR1, GX_ENABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT2, GX_DF_NONE, GX_AF_SPEC ); //// GX::SetChanCtrl( GX_ALPHA1, GX_DISABLE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); //// } // } else { if ( !*set_base_color ) { GX::SetChanCtrl( GX_COLOR0, GX_ENABLE, GX_SRC_VTX, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); GX::SetChanCtrl( GX_ALPHA0, GX_DISABLE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); //// if ( p_mesh->mp_dl->m_material.p_header->m_flags & (1<<6) ) // { // GX::SetChanCtrl( GX_COLOR1, GX_ENABLE, GX_SRC_VTX, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); // GX::SetChanCtrl( GX_ALPHA1, GX_DISABLE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); // } *set_base_color = true; } // GX::SetChanMatColor( GX_COLOR0A0, (GXColor){128,128,128,255} ); // GX::SetChanMatColor( GX_COLOR0A0, (GXColor){32,32,32,255} ); GXColor col; col.r = p_mesh->m_base_color.r; col.g = p_mesh->m_base_color.g; col.b = p_mesh->m_base_color.b; col.a = 255; //// if ( !(p_mesh->mp_dl->m_material.p_header->m_flags & (1<<7)) ) // if ( !(flags & vRENDER_LIT) ) // { // // Not sure why we need to force this to be set... //// _set_mat0( col ); //// GX::SetChanMatColor( GX_COLOR0A0, col ); //// if ( p_mesh->mp_dl->m_material.p_header->m_flags & (1<<6) ) // { //// _set_mat1( col ); //// GX::SetChanMatColor( GX_COLOR1A1, col ); // } //// *((uint32*)p_base_color) = *((uint32*)&col); // // col.r = col.r >> 1; // col.g = col.g >> 1; // col.b = col.b >> 1; // } // if ( *((uint32*)p_base_color) != *((uint32*)&col) ) { // p_mesh->m_base_color.a = 255; // GX::SetChanMatColor( GX_COLOR0A0, col ); _set_mat0( col ); // if ( p_mesh->mp_dl->m_material.p_header->m_flags & (1<<6) ) // { //// GX::SetChanMatColor( GX_COLOR1A1, col ); // _set_mat1( (GXColor){col.b,col.a,0,0} ); // } // *((uint32*)p_base_color) = *((uint32*)&col); } // GX::SetChanCtrl( GX_COLOR1A1, GX_DISABLE, GX_SRC_VTX, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); // GX::SetChanMatColor( GX_COLOR1A1, (GXColor){128,128,128,255} ); // GX::SetChanAmbColor( GX_COLOR1A1, (GXColor){128,128,128,255} ); // GX::SetChanMatColor( GX_COLOR0A0, (GXColor){64,64,64,128} ); // GX::SetChanAmbColor( GX_COLOR0A0, (GXColor){64,64,64,128} ); } // Major hack!!! // if ( p_posNormBuffer ) // { // unsigned char * p8 = (unsigned char *)&p_mesh->mp_dl[1]; // for ( uint lp = 0; lp < p_mesh->mp_dl->m_size; lp++ ) GXWGFifo.u8 = *p8++; // } // else // { /*if ( !p_mesh->mp_dl->mp_pos_pool )*/ GX::CallDisplayList ( &p_mesh->mp_dl[1], p_mesh->mp_dl->m_size ); // } if ( reload_camera ) { GX::LoadPosMtxImm( EngineGlobals.current_uploaded, GX_PNMTX0 ); // GX::LoadPosMtxImm( (Mtx)current_cam.getCurrent(), GX_PNMTX0 ); reload_camera = false; } // // Reload color texture if necessary. // if ( p_mesh->mp_dl->m_material.p_header->m_flags & (1<<5) ) // { // // Make sure color map is uploaded. // GX::UploadTexture( colorMap, // 64, //COLOR_MAP_SIZE, // 64, //COLOR_MAP_SIZE, // GX_TF_RGBA8, // GX_CLAMP, // GX_CLAMP, // GX_FALSE, // GX_LINEAR, // GX_LINEAR, // 0.0f, // 0.0f, // 0.0f, // GX_FALSE, // GX_TRUE, // GX_ANISO_1, // GX_TEXMAP7 ); // } } void render_scene( sScene *p_scene, s16* p_posNormBuffer, uint32 flags, Mth::Matrix * p_bone_xform, Mth::Matrix * p_instance_xform, int num_bones ) { // Don't render dictionary scenes. if( p_scene->m_is_dictionary ) { return; } // // This forces the texture to go into the unusable region. // GX::UploadTexture( colorMap, // 64, // 64, // GX_TF_RGBA8, // GX_CLAMP, // GX_CLAMP, // GX_FALSE, // GX_LINEAR, // GX_LINEAR, // 0.0f, // 0.0f, // 0.0f, // GX_FALSE, // GX_TRUE, // GX_ANISO_1, // GX_TEXMAP7 ); sLastUV = NULL; first_mat = true; p_last_material = NULL; last_correct = false; // if ( p_scene->m_numHierarchyObjects == 0 ) // { // // Not hierarchical, set to matrix 0. // GXSetCurrentMtx( GX_PNMTX0 ); // } ResetMaterialChange(); // int meshes_rendered = 0; figure_wibble_vc( p_scene ); #define MAX_SHADOW_MESHES 512 // int shadow_meshes = 0; // sMesh *pShadow[MAX_SHADOW_MESHES]; // sMesh *visible_mesh_array[2000]; // int visible_mesh_array_index = 0; // Increment the scene framestamp. //_scene->m_framestamp++; // Set up the texture generation matrix here. // Mtx light; // MTXLightOrtho( light, -128.0f, 128.0f, -128.0f, 128.0f, 0.5f, 0.5f, 0.5f, 0.5f ); // MTXConcat( light, (Mtx)&EngineGlobals.shadow_camera, light ); //#ifndef SHORT_VERT // GX::LoadTexMtxImm( light, GX_TEXMTX7, GX_MTX3x4 ); //#endif // SHORT_VERT if ( p_posNormBuffer ) { GX::SetArray( GX_VA_POS, p_posNormBuffer, sizeof( uint16 ) * 6 ); GX::SetArray( GX_VA_NRM, &p_posNormBuffer[3], sizeof( uint16 ) * 6 ); } else { GX::SetArray( GX_VA_POS, p_scene->mp_pos_pool, sizeof( float ) * 3 ); GX::SetArray( GX_VA_NRM, p_scene->mp_nrm_pool, sizeof( uint16 ) * 3 ); } int array_base = 0; int col_base = 2; int layer = -1; bool set_chan = false; GXColor base_color = { 0, 0, 0, 0 }; bool world_fog = true; Nx::CFog::sSetFogColor(); GX::SetChanMatColor( GX_COLOR0A0, base_color ); GX::SetChanMatColor( GX_COLOR1A1, base_color ); f32 pm[GX_PROJECTION_SZ]; GX::GetProjectionv( pm ); // if ( flags & vRENDER_NEW_TEST ) { // Pool setup. GX::SetArray( GX_VA_CLR0, &((char*)p_scene->mp_col_pool)[0], sizeof( uint32 ) ); GX::SetArray( GX_VA_CLR1, &((char*)p_scene->mp_col_pool)[2], sizeof( uint32 ) ); // GX::SetArray( GX_VA_CLR1, p_scene->mp_col_pool, sizeof( uint32 ) ); // GX::SetArray( GX_VA_TEX0, p_scene->mp_tex_pool, sizeof( float ) * 2 ); // // GX::SetArray( GX_VA_TEX1, p_scene->mp_tex_pool, sizeof( float ) * 2 ); // GX::SetArray( GX_VA_TEX2, p_scene->mp_tex_pool, sizeof( float ) * 2 ); // GX::SetArray( GX_VA_TEX3, p_scene->mp_tex_pool, sizeof( float ) * 2 ); GX::SetArray( GX_VA_TEX0, p_scene->mp_tex_pool, sizeof( uint16 ) * 2 ); GX::SetArray( GX_VA_TEX1, p_scene->mp_tex_pool, sizeof( uint16 ) * 2 ); GX::SetArray( GX_VA_TEX2, p_scene->mp_tex_pool, sizeof( uint16 ) * 2 ); GX::SetArray( GX_VA_TEX3, p_scene->mp_tex_pool, sizeof( uint16 ) * 2 ); // GXSetArray( GX_VA_TEX4, p_scene->mp_tex_pool, sizeof( float ) * 2 ); // GXSetArray( GX_VA_TEX5, p_scene->mp_tex_pool, sizeof( float ) * 2 ); // GXSetArray( GX_VA_TEX6, p_scene->mp_tex_pool, sizeof( float ) * 2 ); // GXSetArray( GX_VA_TEX7, p_scene->mp_tex_pool, sizeof( float ) * 2 ); //GXSetVtxAttrFmt( GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0 ); } if ( g_object == g_view_object ) g_view_scene = p_scene; // Render all meshes. # ifdef __USE_PROFILER__ Sys::VUProfiler->PushContext( 128,0,0 ); # endif // __USE_PROFILER__ // { // GX::SetFog( GX_FOG_NONE, 0.0f, 0.0f, 0.0f, 0.0f, (GXColor){0,0,0,0} ); // GX::SetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0 ); // // GX::SetTevColorInOp( GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_KONST, // GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ); // // GX::SetTevAlphaInOpSwap( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_KONST, // GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV, // GX_TEV_SWAP0, GX_TEV_SWAP0 ); // // GX::SetBlendMode ( GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_ONE, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_TRUE ); // // GX::SetTevKSel( GX_TEVSTAGE0, GX_TEV_KCSEL_K0, GX_TEV_KASEL_K0_A, GX_TEV_KCSEL_K0, GX_TEV_KASEL_K0_A ); // GX::SetTevKColor( GX_KCOLOR0, (GXColor){8,8,8,255} ); // GX::SetChanCtrl( GX_ALPHA0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); // GX::SetChanMatColor( GX_COLOR0A0, (GXColor){255,255,255,255}); // GX::SetChanAmbColor( GX_COLOR0A0, (GXColor){255,255,255,255}); // // GX::SetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE); // GX::SetTexChanTevIndCull( 0, 1, 1, 0, GX_CULL_NONE ); // } /////////////////////////////////////////////////////////////////////////////////////////// // Shadow Target. /////////////////////////////////////////////////////////////////////////////////////////// if ( flags & vRENDER_SHADOW_1ST_PASS ) { // GX::SetFog( GX_FOG_NONE, 0.0f, 0.0f, 0.0f, 0.0f, (GXColor){0,0,0,0} ); GX::SetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0 ); GX::SetTevColorInOp( GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_KONST, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ); GX::SetTevAlphaInOpSwap( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_KONST, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0 ); GX::SetBlendMode ( GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_TRUE ); // Replace GX::SetTevKSel( GX_TEVSTAGE0, GX_TEV_KCSEL_K0, GX_TEV_KASEL_K0_A, GX_TEV_KCSEL_K0, GX_TEV_KASEL_K0_A ); GX::SetTevKColor( GX_KCOLOR0, (GXColor){64,64,64,255} ); GX::SetChanCtrl( GX_ALPHA0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); GX::SetChanMatColor( GX_COLOR0A0, (GXColor){255,255,255,255}); GX::SetChanAmbColor( GX_COLOR0A0, (GXColor){255,255,255,255}); GX::SetChanMatColor( GX_COLOR1A1, (GXColor){255,255,255,255}); GX::SetChanAmbColor( GX_COLOR1A1, (GXColor){255,255,255,255}); base_color = (GXColor){ 255, 255, 255, 255 }; // GX::SetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE); GX::SetTexChanTevIndCull( 0, 1, 1, 0, GX_CULL_NONE ); for ( int mesh = 0; mesh < p_scene->m_num_filled_meshes; mesh++ ) { sMesh * p_mesh = p_scene->mpp_mesh_list[mesh]; if ( ( p_mesh->m_flags & sMesh::MESH_FLAG_VISIBLE ) && ( ( g_object != g_view_object ) || ( &p_scene->mp_material_header[g_material] != p_mesh->mp_dl->m_material.p_header ) ) ) { GX::CallDisplayList ( &p_mesh->mp_dl[1], p_mesh->mp_dl->m_size ); // submit_mesh( p_scene, p_mesh, p_posNormBuffer, p_bone_xform, p_instance_xform, &array_base, &col_base, &layer, pm, &world_fog, flags ); } } } /////////////////////////////////////////////////////////////////////////////////////////// // Opaque meshes. /////////////////////////////////////////////////////////////////////////////////////////// _reset(); if ( flags & vRENDER_OPAQUE ) { // GX::SetZMode( GX_TRUE, GX_LEQUAL, GX_TRUE ); for ( int mesh = 0; mesh < p_scene->m_num_opaque_meshes; mesh++ ) { sMesh * p_mesh = p_scene->mpp_mesh_list[mesh]; if ( ( p_mesh->m_flags & sMesh::MESH_FLAG_VISIBLE ) && ( ( g_object != g_view_object ) || ( &p_scene->mp_material_header[g_material] != p_mesh->mp_dl->m_material.p_header ) ) ) { submit_mesh( p_scene, p_mesh, p_posNormBuffer, p_bone_xform, p_instance_xform, &array_base, &col_base, &layer, pm, &base_color, &set_chan, &world_fog, flags ); } } } /////////////////////////////////////////////////////////////////////////////////////////// // Semitransparent meshes. /////////////////////////////////////////////////////////////////////////////////////////// if ( flags & vRENDER_SEMITRANSPARENT ) { // GX::SetZMode( GX_TRUE, GX_LEQUAL, GX_TRUE ); int opaque = p_scene->m_num_opaque_meshes; int presemi = opaque + p_scene->m_num_pre_semitrans_meshes; int dynsemi = presemi + p_scene->m_num_dynamic_semitrans_meshes; int postsemi = dynsemi + p_scene->m_num_post_semitrans_meshes; // Pre meshes. _reset(); for ( int mesh = opaque; mesh < presemi; mesh++ ) { sMesh * p_mesh = p_scene->mpp_mesh_list[mesh]; if ( ( p_mesh->m_flags & sMesh::MESH_FLAG_VISIBLE ) && ( ( g_object != g_view_object ) || ( &p_scene->mp_material_header[g_material] != p_mesh->mp_dl->m_material.p_header ) ) ) { submit_mesh( p_scene, p_mesh, p_posNormBuffer, p_bone_xform, p_instance_xform, &array_base, &col_base, &layer, pm, &base_color, &set_chan, &world_fog, flags ); } } // Dynamic meshes. sSortedMeshEntry sortedMeshArray[1000]; int next_sorted_mesh_entry = 0; for ( int mesh = presemi; mesh < dynsemi; mesh++ ) { sMesh * p_mesh = p_scene->mpp_mesh_list[mesh]; if ( ( p_mesh->m_flags & sMesh::MESH_FLAG_VISIBLE ) && ( ( g_object != g_view_object ) || ( &p_scene->mp_material_header[g_material] != p_mesh->mp_dl->m_material.p_header ) ) ) { sortedMeshArray[next_sorted_mesh_entry].p_mesh = p_mesh; sortedMeshArray[next_sorted_mesh_entry].sort = frustum_sort_mid( p_mesh->mp_dl->m_sphere ); ++next_sorted_mesh_entry; } } qsort( sortedMeshArray, next_sorted_mesh_entry, sizeof( sSortedMeshEntry ), cmp ); _reset(); for( int m = 0; m < next_sorted_mesh_entry; ++m ) { submit_mesh( p_scene, sortedMeshArray[m].p_mesh, p_posNormBuffer, p_bone_xform, p_instance_xform, &array_base, &col_base, &layer, pm, &base_color, &set_chan, &world_fog, flags ); } // Post meshes. _reset(); for ( int mesh = dynsemi; mesh < postsemi; mesh++ ) { sMesh * p_mesh = p_scene->mpp_mesh_list[mesh]; if ( ( p_mesh->m_flags & sMesh::MESH_FLAG_VISIBLE ) && ( ( g_object != g_view_object ) || ( &p_scene->mp_material_header[g_material] != p_mesh->mp_dl->m_material.p_header ) ) ) { submit_mesh( p_scene, p_mesh, p_posNormBuffer, p_bone_xform, p_instance_xform, &array_base, &col_base, &layer, pm, &base_color, &set_chan, &world_fog, flags ); } } } /////////////////////////////////////////////////////////////////////////////////////////// // Shadow Mesh. /////////////////////////////////////////////////////////////////////////////////////////// if ( flags & vRENDER_SHADOW_2ND_PASS ) { Nx::CFog::sEnableFog( false ); Mtx light; MTXLightOrtho( light, -128.0f, 128.0f, -128.0f, 128.0f, 0.5f, 0.5f, 0.5f, 0.5f ); MTXConcat( light, (Mtx)&EngineGlobals.shadow_camera, light ); GX::LoadTexMtxImm( light, GX_TEXMTX7, GX_MTX3x4 ); GX::SetZMode( GX_TRUE, GX_LEQUAL, GX_FALSE ); GX::SetZCompLoc( GX_TRUE ); GX::UploadTexture( shadowTextureData, SHADOW_TEXTURE_SIZE, SHADOW_TEXTURE_SIZE, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_TRUE, GX_ANISO_1, GX_TEXMAP0 ); GX::SetTexCoordScale( GX_TEXCOORD0, GX_TRUE, SHADOW_TEXTURE_SIZE, SHADOW_TEXTURE_SIZE ); GX::UploadPalette( shadowPalette, GX_TL_RGB5A3, GX_TLUT_16, GX_TEXMAP0 ); GX::SetTexChanTevIndCull( 1, 0, 1, 0, GX_CULL_NONE ); GX::SetTexCoordGen( GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_POS, GX_FALSE, GX_PTIDENTITY ); GX::SetCurrMtxPosTex03( GX_PNMTX0, GX_IDENTITY, GX_IDENTITY, GX_IDENTITY, GX_IDENTITY ); GX::SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0 ); // GX::SetBlendMode ( GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_TRUE ); // Replace GX::SetBlendMode( GX_BM_BLEND, GX_BL_DSTCLR, GX_BL_ZERO, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_TRUE ); GX::SetCurrMtxPosTex03( GX_PNMTX0, GX_TEXMTX7, GX_TEXMTX7, GX_TEXMTX7, GX_TEXMTX7 ); GX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL, GX_TEXCOORD0, GX_TEXMAP_NULL, GX_COLOR_NULL); GX::SetTevAlphaInOpSwap( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_DISABLE, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0 ); GX::SetTevColorInOp( GX_TEVSTAGE0, GX_CC_ONE, GX_CC_ZERO, GX_CC_TEXC, GX_CC_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_DISABLE, GX_TEVPREV ); //out_reg = (d (op) ((1.0 - c)*a + c*b) + bias) * scale; GX::SetVtxDesc( 2, GX_VA_POS, GX_DIRECT, GX_VA_TEX0, GX_DIRECT ); // visible_mesh_array[visible_mesh_array_index++] = p_scene->m_semitransparent_meshes[e]; // for ( int mesh = 0; mesh < p_scene->m_num_filled_meshes; mesh++ ) layer = 5; // Force subsequent materials to reset the layer. // float value = pm[6] + ( 80.0f * p_mesh->mp_dl->m_material.p_header->m_layer_id ) * pm[5]; float value = pm[6] + ( 150.0f * 5 ) * pm[5]; GXWGFifo.u8 = GX_LOAD_XF_REG; GXWGFifo.u16 = 0; GXWGFifo.u16 = 0x1025; GXWGFifo.f32 = value; // for ( int mesh = 0; mesh < ( p_scene->m_num_opaque_meshes + p_scene->m_num_pre_semitrans_meshes ); mesh++ ) for ( int mesh = 0; mesh < ( p_scene->m_num_filled_meshes ); mesh++ ) { sMesh * p_mesh = p_scene->mpp_mesh_list[mesh]; // if( frustum_check_sphere( light, p_scene->m_opaque_meshes[e]->m_sphere )) float by; // if ( p_mesh->mp_mod ) // { //// by = ( p_mesh->m_bottom_y * p_mesh->mp_mod->scale[Y] ) + p_mesh->mp_mod->offset[Y]; // by = p_mesh->mp_mod->offset[Y]; // } // else // { by = p_mesh->m_bottom_y; // } if ( ( p_mesh->m_flags & sMesh::MESH_FLAG_VISIBLE ) && frustum_check_sphere( light, p_mesh->mp_dl->m_sphere ) && ( g_shadow_object_pos[Y] > by ) && !( p_mesh->m_flags & sMesh::MESH_FLAG_NO_SKATER_SHADOW ) ) { // if ( (int)p_mesh->mp_dl->m_material.p_header->m_layer_id == g_kill_layer ) return; // Deal with cloned pos pools. if ( p_mesh->mp_dl->mp_pos_pool ) { array_base = -1; GX::SetArray( GX_VA_POS, p_mesh->mp_dl->mp_pos_pool, sizeof( float ) * 3 ); } else { // Deal with verts outside of 65535. if ( p_mesh->mp_dl->m_array_base != (uint32)array_base ) { array_base = p_mesh->mp_dl->m_array_base; // Assumes that this isn't a skinned object. GX::SetArray( GX_VA_POS, &p_scene->mp_pos_pool[p_mesh->mp_dl->m_array_base*3], sizeof( float ) * 3 ); } } GX::CallDisplayList ( &p_mesh->mp_dl[1], p_mesh->mp_dl->m_size ); // submit_mesh( p_scene, p_mesh, p_posNormBuffer, p_bone_xform, p_instance_xform, &array_base, &col_base, &layer, pm, &world_fog, flags ); } } Nx::CFog::sEnableFog( true ); world_fog = true; } // // Render opaque meshes. // if( (flags & vRENDER_OPAQUE) && !(flags & vRENDER_SHADOW_1ST_PASS) ) // { // for( int e = 0; e < p_scene->m_num_opaque_entries; ++e ) // { // if ( p_scene->m_opaque_meshes[e]->m_flags & sMesh::MESH_FLAG_VISIBLE ) // { // sMesh * p_mesh = p_scene->m_opaque_meshes[e]; // //// set_render_state( RS_ZWRITEENABLE, p_mesh->m_zwrite ); // // if ( flags & vRENDER_NEW_TEST ) // { // // Textured. // // First pass material setup. // sMaterialHeader * p_mat = p_mesh->mp_dl->m_material.p_header; // sMaterialPassHeader * p_pass = (sMaterialPassHeader *)&p_mat[1]; // // if ( p_pass[0].m_texture.p_data ) // { // if ( first_mat || !one_mat ) // { // first_mat = false; // // MaterialSubmit( p_mesh ); // } // GX::CallDisplayList ( &p_mesh->mp_dl[1], p_mesh->mp_dl->m_size ); // } // else // { // // Untextured. // if ( !(p_mesh->mp_dl->m_flags & 0x00200000) ) // { // GXSetNumTevStages( 1 ); // GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); // GXSetTevSwapMode( GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0 ); // GXSetNumTexGens( 0 ); // GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ); // GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ); //// GXSetAlphaCompare(GX_GREATER, 0, GX_AOP_AND, GX_GREATER, 0 ); // GXSetBlendMode ( GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_FALSE ); // GXSetTevAlphaIn ( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_RASA ); // GXSetTevColorIn ( GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC ); // GXSetChanCtrl( GX_COLOR0A0, GX_ENABLE, GX_SRC_VTX, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); // GXSetChanMatColor( GX_COLOR0A0, (GXColor){255,255,255,255} ); //// GXSetChanMatColor( GX_COLOR0A0, p_pass->m_color ); // // GX::CallDisplayList ( &p_mesh->mp_dl[1], p_mesh->mp_dl->m_size ); // } // } // } // else // { // multi_mesh( p_mesh, p_posNormBuffer ); // } // // // Now draw the opaque meshes with shadow mapped on them. // if( p_scene->m_flags & SCENE_FLAG_RECEIVE_SHADOWS ) // { // if( !( p_mesh->m_flags & sMesh::MESH_FLAG_NO_SKATER_SHADOW ) ) // { // if( frustum_check_sphere( light, p_scene->m_opaque_meshes[e]->m_sphere )) // { // //if( frustum_check_box( light, p_scene->m_opaque_meshes[e]->m_bbox )) // { // if ( shadow_meshes < MAX_SHADOW_MESHES ) // { // pShadow[shadow_meshes] = p_mesh; // shadow_meshes++; // } // } // } // } // } // } // } // } // //// Render semi-transparent meshes. // if( (flags & vRENDER_SEMITRANSPARENT) && !(flags & vRENDER_SHADOW_1ST_PASS) ) // { // int e = 0; // int next_sorted_mesh_entry = 0; // // // Semitransparent rendering is done in three stages. // // The first stage is meshes in the list up to the point where dynamic sorting starts. // // The second stage is meshes in the list which use dynamic sorting. // // The third stage is meshes in the list beyond the point where dynamic sorting ends. // for( ; e < p_scene->m_first_dynamic_sort_entry; ++e ) // { // if ( p_scene->m_semitransparent_meshes[e]->m_flags & sMesh::MESH_FLAG_VISIBLE ) // { // sMesh * p_mesh = p_scene->m_semitransparent_meshes[e]; // //// set_render_state( RS_ZWRITEENABLE, p_mesh->m_zwrite ); // // ++meshes_rendered; // // if ( flags & vRENDER_NEW_TEST ) // { // // Textured. // // First pass material setup. // sMaterialHeader * p_mat = p_mesh->mp_dl->m_material.p_header; // sMaterialPassHeader * p_pass = (sMaterialPassHeader *)&p_mat[1]; // // if ( p_pass[0].m_texture.p_data ) // { // if ( first_mat || !one_mat ) // { // first_mat = false; // // MaterialSubmit( p_mesh ); // } // // GX::CallDisplayList ( &p_mesh->mp_dl[1], p_mesh->mp_dl->m_size ); // } // else // { // // Untextured. // if ( !(p_mesh->mp_dl->m_flags & 0x00200000) ) // { // GXSetNumTevStages( 1 ); // GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); // GXSetTevSwapMode( GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0 ); // GXSetNumTexGens( 0 ); // GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ); // GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_2, GX_ENABLE, GX_TEVPREV ); // GXSetAlphaCompare(GX_GREATER, 0, GX_AOP_AND, GX_GREATER, 0 ); // GXSetBlendMode ( GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_FALSE ); // GXSetTevAlphaIn ( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_RASA ); // GXSetTevColorIn ( GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC ); // GXSetChanCtrl( GX_COLOR0A0, GX_ENABLE, GX_SRC_VTX, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); // GXSetChanMatColor( GX_COLOR0A0, p_pass->m_color ); // // GX::CallDisplayList ( &p_mesh->mp_dl[1], p_mesh->mp_dl->m_size ); // } // } // } // else // { // multi_mesh( p_mesh, p_posNormBuffer ); // } // } // } // // if( p_scene->m_num_dynamic_sort_entries > 0 ) // { // // Second stage - dynamically sorted meshes. // int last_dynamic_sort_entry = p_scene->m_first_dynamic_sort_entry + p_scene->m_num_dynamic_sort_entries; // for( ; e < last_dynamic_sort_entry; ++e ) // { // if ( p_scene->m_semitransparent_meshes[e]->m_flags & sMesh::MESH_FLAG_VISIBLE ) // { // ++meshes_rendered; // // Figure the midpoint of this mesh, and sort it into the render list. // float midpoint = frustum_sort_mid( p_scene->m_semitransparent_meshes[e]->m_sphere ); // //// // Add this mesh to the visible list. //// if( !( p_scene->m_semitransparent_meshes[e]->m_flags & sMesh::MESH_FLAG_NO_SKATER_SHADOW )) //// { //// visible_mesh_array[visible_mesh_array_index++] = p_scene->m_semitransparent_meshes[e]; //// } // // sortedMeshArray[next_sorted_mesh_entry].p_mesh = p_scene->m_semitransparent_meshes[e]; // sortedMeshArray[next_sorted_mesh_entry].sort = midpoint; // ++next_sorted_mesh_entry; // } // } // if( next_sorted_mesh_entry > 0 ) // { // // Sort the array into ascending sort order. // qsort( sortedMeshArray, next_sorted_mesh_entry, sizeof( sSortedMeshEntry ), cmp ); // // for( int m = 0; m < next_sorted_mesh_entry; ++m ) // { // sMesh * p_mesh = sortedMeshArray[m].p_mesh; // //// set_render_state( RS_ZWRITEENABLE, p_mesh->m_zwrite ); // // if ( flags & vRENDER_NEW_TEST ) // { // // Textured. // // First pass material setup. // sMaterialHeader * p_mat = p_mesh->mp_dl->m_material.p_header; // sMaterialPassHeader * p_pass = (sMaterialPassHeader *)&p_mat[1]; // // if ( p_pass[0].m_texture.p_data ) // { // if ( first_mat || !one_mat ) // { // first_mat = false; // // MaterialSubmit( p_mesh ); // } // // GX::CallDisplayList ( &p_mesh->mp_dl[1], p_mesh->mp_dl->m_size ); // } // else // { // // Untextured. // if ( !(p_mesh->mp_dl->m_flags & 0x00200000) ) // { // GXSetNumTevStages( 1 ); // GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); // GXSetTevSwapMode( GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0 ); // GXSetNumTexGens( 0 ); // GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ); // GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_2, GX_ENABLE, GX_TEVPREV ); // GXSetAlphaCompare(GX_GREATER, 0, GX_AOP_AND, GX_GREATER, 0 ); // GXSetBlendMode ( GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_FALSE ); // GXSetTevAlphaIn ( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_RASA ); // GXSetTevColorIn ( GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC ); // GXSetChanCtrl( GX_COLOR0A0, GX_ENABLE, GX_SRC_VTX, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); // GXSetChanMatColor( GX_COLOR0A0, p_pass->m_color ); // // GX::CallDisplayList ( &p_mesh->mp_dl[1], p_mesh->mp_dl->m_size ); // } // } // } // else // { // multi_mesh( p_mesh, p_posNormBuffer ); // } // } // } // // // Third stage - meshes after the dynamically sorted set. // for( ; e < p_scene->m_num_semitransparent_entries; ++e ) // { // if ( p_scene->m_semitransparent_meshes[e]->m_flags & sMesh::MESH_FLAG_VISIBLE ) // { // sMesh * p_mesh = p_scene->m_semitransparent_meshes[e]; // //// set_render_state( RS_ZWRITEENABLE, p_mesh->m_zwrite ); // // ++meshes_rendered; // // if ( flags & vRENDER_NEW_TEST ) // { // // Textured. // // First pass material setup. // sMaterialHeader * p_mat = p_mesh->mp_dl->m_material.p_header; // sMaterialPassHeader * p_pass = (sMaterialPassHeader *)&p_mat[1]; // // if ( p_pass[0].m_texture.p_data ) // { // if ( first_mat || !one_mat ) // { // first_mat = false; // // MaterialSubmit( p_mesh ); // } // // GX::CallDisplayList ( &p_mesh->mp_dl[1], p_mesh->mp_dl->m_size ); // } // else // { // // Untextured. // if ( !(p_mesh->mp_dl->m_flags & 0x00200000) ) // { // GXSetNumTevStages( 1 ); // GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); // GXSetTevSwapMode( GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0 ); // GXSetNumTexGens( 0 ); // GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ); // GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_2, GX_ENABLE, GX_TEVPREV ); // GXSetAlphaCompare(GX_GREATER, 0, GX_AOP_AND, GX_GREATER, 0 ); // GXSetBlendMode ( GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR, GX_TRUE, GX_FALSE, GX_FALSE ); // GXSetTevAlphaIn ( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_RASA ); // GXSetTevColorIn ( GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC ); // GXSetChanCtrl( GX_COLOR0A0, GX_ENABLE, GX_SRC_VTX, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); // GXSetChanMatColor( GX_COLOR0A0, p_pass->m_color ); // // GX::CallDisplayList ( &p_mesh->mp_dl[1], p_mesh->mp_dl->m_size ); // } // } // } // else // { // multi_mesh( p_mesh, p_posNormBuffer ); // } // } // } // } // //// // Now draw the semitransparent meshes with shadow mapped on them. //// if( p_scene->m_flags & SCENE_FLAG_RECEIVE_SHADOWS ) //// { //// render_shadow_meshes( p_scene, visible_mesh_array, visible_mesh_array_index ); //// } // } // //// if ( 0 ) // { // // Render shadow meshes. // if( flags & vRENDER_SHADOW_1ST_PASS ) // { // int e; // for( e = 0; e < p_scene->m_num_opaque_entries; ++e ) // { // if ( p_scene->m_opaque_meshes[e]->m_flags & sMesh::MESH_FLAG_VISIBLE ) // { // sMesh * p_mesh = p_scene->m_opaque_meshes[e]; // //// set_render_state( RS_ZWRITEENABLE, p_mesh->m_zwrite ); // // if ( p_posNormBuffer ) { // // Skinned. // multi_start_16 ( &p_posNormBuffer[0], &p_posNormBuffer[3], 6, 6 ); // } else { // // Not skinned. //#ifdef SHORT_VERT // cam_offset( p_mesh->m_offset_x, p_mesh->m_offset_y, p_mesh->m_offset_z ); // multi_start_16 ( p_mesh->mp_posBuffer, p_mesh->mp_normBuffer, 3, 3 ); //#else // multi_start ( p_mesh->mp_posBuffer, p_mesh->mp_normBuffer, 3, 3 ); //#endif // SHORT_VERT // } // // multi_end( p_mesh, vRENDER_SHADOW_1ST_PASS ); // } // } // // for( e = 0; e < p_scene->m_num_semitransparent_entries; ++e ) // { // if ( p_scene->m_semitransparent_meshes[e]->m_flags & sMesh::MESH_FLAG_VISIBLE ) // { // sMesh * p_mesh = p_scene->m_semitransparent_meshes[e]; // //// set_render_state( RS_ZWRITEENABLE, p_mesh->m_zwrite ); // // if ( p_posNormBuffer ) { // // Skinned. // multi_start_16 ( &p_posNormBuffer[0], &p_posNormBuffer[3], 6, 6 ); // } else { // // Not skinned. //#ifdef SHORT_VERT // cam_offset( p_mesh->m_offset_x, p_mesh->m_offset_y, p_mesh->m_offset_z ); // multi_start_16 ( p_mesh->mp_posBuffer, p_mesh->mp_normBuffer, 3, 3 ); //#else // multi_start ( p_mesh->mp_posBuffer, p_mesh->mp_normBuffer, 3, 3 ); //#endif // SHORT_VERT // } // // multi_end( p_mesh, vRENDER_SHADOW_1ST_PASS ); // } // } // } // // // Render shadows from list. //#if 1 // for ( int lp = 0; lp < shadow_meshes; lp++ ) // { // GXTlutObj palObj; // GXInitTlutObj( &palObj, &shadowPalette, GX_TL_RGB5A3, 16 ); // GXLoadTlut ( &palObj, GX_TLUT0 ); // // // Set up shadow map texture //#define SHADOW_TEXTURE_SIZE 256 //#define BLUR_TEXTURE_SIZE 64 // GXTexObj blurTexture; // GXTexObj shadowTexture; // GXInitTexObjCI( // &blurTexture, // blurTextureData, //shadowTextureData, // BLUR_TEXTURE_SIZE, //SHADOW_TEXTURE_SIZE, // BLUR_TEXTURE_SIZE, //SHADOW_TEXTURE_SIZE, // GX_TF_C4, // GX_CLAMP, // GX_CLAMP, // GX_FALSE, // GX_TLUT0 ); //// GXInitTexObjLOD(&blurTexture, GX_NEAR, GX_NEAR, 0, 0, 0, 0, 0, GX_ANISO_1); // GXLoadTexObj( &blurTexture, GX_TEXMAP5 ); // GXInitTexObjCI( // &shadowTexture, // shadowTextureData, // SHADOW_TEXTURE_SIZE, // SHADOW_TEXTURE_SIZE, // GX_TF_C4, // GX_CLAMP, // GX_CLAMP, // GX_FALSE, // GX_TLUT0 ); //// GXInitTexObjLOD(&shadowTexture, GX_NEAR, GX_NEAR, 0, 0, 0, 0, 0, GX_ANISO_1); // GXLoadTexObj( &shadowTexture, GX_TEXMAP6 ); // // // Offset the texture matrix. //#ifdef SHORT_VERT // Mtx m; // MTXTrans( m, pShadow[lp]->m_offset_x, pShadow[lp]->m_offset_y, pShadow[lp]->m_offset_z ); // MTXConcat( light, m, m ); // GXLoadTexMtxImm( m, GX_TEXMTX7, GX_MTX3x4 ); //#endif // SHORT_VERT // // if ( p_posNormBuffer ) { // // Skinned. // multi_start_16 ( &p_posNormBuffer[0], &p_posNormBuffer[3], 6, 6 ); // } else { // // Not skinned. //#ifdef SHORT_VERT // cam_offset( pShadow[lp]->m_offset_x, pShadow[lp]->m_offset_y, pShadow[lp]->m_offset_z ); // multi_start_16 ( pShadow[lp]->mp_posBuffer, pShadow[lp]->mp_normBuffer, 3, 3 ); //#else // multi_start ( pShadow[lp]->mp_posBuffer, pShadow[lp]->mp_normBuffer, 3, 3 ); //#endif // SHORT_VERT // } // // multi_end( pShadow[lp], vRENDER_SHADOW_2ND_PASS ); // } //#endif // } // //// if( flags & vRENDER_SEMITRANSPARENT ) //// { //// // Sort semi-transparent meshes. //// int bucket_size = p_scene->m_num_semitransparent_entries * 2; //// sMesh * sorted_meshes[bucket_size]; //// memset( sorted_meshes, 0, bucket_size * 4 ); //// for( int e = 0; e < p_scene->m_num_semitransparent_entries; ++e ) //// { //// if( p_scene->m_semitransparent_meshes[e]->m_flags & sMesh::MESH_FLAG_ACTIVE ) //// { //// // Frustum cull this set of meshes, using the associated bounding box. //// float z; //// if( frustum_check_sphere( p_scene->m_semitransparent_meshes[e]->m_sphere, &z )) //// { //// int index = (int)( z / ( 20000.0f / bucket_size ) ); //// if ( index < 0 ) index = 0; //// if ( index > (bucket_size - 1) ) index = (bucket_size - 1); //// //// if ( index >= (bucket_size / 2) ) //// { //// // Search backwards to find an empty slot. //// while ( sorted_meshes[index] ) index--; //// if ( index >= 0 ) //// { //// sorted_meshes[index] = p_scene->m_semitransparent_meshes[e]; //// } //// } //// else //// { //// // Search forwards to find an empty slot. //// while ( sorted_meshes[index] ) index++; //// if ( index < bucket_size ) //// { //// sorted_meshes[index] = p_scene->m_semitransparent_meshes[e]; //// } //// } //// } //// } //// } //// //// // Render semi-transparent meshes. //// for( int e = 0; e < bucket_size; ++e ) //// { //// if( sorted_meshes[e] ) //// { //// ++meshes_rendered; //// //// sMesh * p_mesh = sorted_meshes[e]; //// //// set_render_state( RS_ZWRITEENABLE, p_mesh->m_zwrite ); //// ////// if ( p_mesh->mp_uvBuffer && p_mesh->mp_material->pTex[0] ) //// { //// uint32 layer; //// //// if ( p_posNormBuffer ) { //// // Skinned. //// multi_start ( &p_posNormBuffer[0], &p_posNormBuffer[3], 6, 6 ); //// } else { //// // Not skinned. //// multi_start ( p_mesh->mp_posBuffer, p_mesh->mp_normBuffer, 3, 3 ); //// } //// multi_add_color ( p_mesh->mp_colBuffer ); //// int uv_set = 0; //// float * p_tex; //// for ( layer = 0; layer < p_mesh->mp_material->Passes ; layer++ ) //// { //// GXTexWrapMode u_mode; //// GXTexWrapMode v_mode; //// if ( p_mesh->mp_material->Flags[layer] & MATFLAG_ENVIRONMENT ) //// { //// p_tex = NULL; //// u_mode = GX_REPEAT; //// v_mode = GX_REPEAT; //// } //// else //// { //// p_tex = &p_mesh->mp_uvBuffer[2*uv_set]; //// u_mode = p_mesh->mp_material->UVAddressing[layer] & (1<<0) ? GX_CLAMP : GX_REPEAT; //// v_mode = p_mesh->mp_material->UVAddressing[layer] & (1<<1) ? GX_CLAMP : GX_REPEAT; //// } //// uv_set++; //// //// multi_add_texture ( p_tex, p_mesh->m_num_uv_sets, p_mesh->mp_material->uv_slot[layer], p_mesh->mp_material->Flags[layer], layer ); //// } //// //// multi_end( p_mesh, 0 ); //// } //// } //// } //// } // // if ( p_scene->m_numHierarchyObjects != 0 ) // { // // Hierarchical, set to matrix 0. // GXSetCurrentMtx( GX_PNMTX0 ); // } GX::SetProjectionv( pm ); g_object++; } /******************************************************************/ /* */ /* Sets MESH_FLAG_VISIBLE if visible for all meshes in this scene */ /* */ /******************************************************************/ int cull_scene( sScene *p_scene, uint32 flags ) { int meshes_visible = 0; // Cull all meshes. sMesh ** pp_mesh = p_scene->mpp_mesh_list; for( int e = 0; e < p_scene->m_num_filled_meshes; ++e ) { sMesh * p_mesh = pp_mesh[e]; if( ( p_mesh->m_flags & sMesh::MESH_FLAG_ACTIVE ) && ( p_mesh->GetVisibility() & EngineGlobals.viewport ) ) { Mth::Vector sphere = p_mesh->mp_dl->m_sphere; // Frustum cull this set of meshes, using the associated bounding box. if( frustum_check_sphere( sphere )) { // Sphere is visible. if( ( flags & vRENDER_OCCLUDED ) ) { if ( TestSphereAgainstOccluders( &sphere ) ) { // Occluded. p_mesh->m_flags &= ~sMesh::MESH_FLAG_VISIBLE; } else { // Not occluded. p_mesh->m_flags |= sMesh::MESH_FLAG_VISIBLE; ++meshes_visible; } } else { // Sphere being visible is enough. p_mesh->m_flags |= sMesh::MESH_FLAG_VISIBLE; ++meshes_visible; } } else { // Sphere not visible. p_mesh->m_flags &= ~sMesh::MESH_FLAG_VISIBLE; } } else { // Force to be not visible. p_mesh->m_flags &= ~sMesh::MESH_FLAG_VISIBLE; } } return meshes_visible; // make_scene_visible( p_scene ); // return p_scene->m_num_filled_meshes; } /******************************************************************/ /* */ /* Sets MESH_FLAG_VISIBLE for all meshes in this scene. */ /* */ /******************************************************************/ void make_scene_visible( sScene *p_scene ) { // Set all meshes to be visible. sMesh ** pp_mesh = p_scene->mpp_mesh_list; for( int e = 0; e < p_scene->m_num_filled_meshes; ++e ) { if( ( pp_mesh[e]->m_flags & sMesh::MESH_FLAG_ACTIVE ) && ( pp_mesh[e]->GetVisibility() & EngineGlobals.viewport ) ) { pp_mesh[e]->m_flags |= sMesh::MESH_FLAG_VISIBLE; } } } void render_begin( void ) { } void render_end( void ) { } } // namespace NxNgc