thug/Code/Gfx/NGC/NX/scene.cpp

1151 lines
34 KiB
C++
Raw Normal View History

2016-02-13 21:39:12 +00:00
#include <sys/file/filesys.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "texture.h"
#include "mesh.h"
#include "scene.h"
#include "render.h"
#include <sys/ngc/p_gx.h>
#include "nx_init.h"
#include <sys/timer.h>
#include <dolphin\gd.h>
#include <gel/music/Ngc/p_music.h>
#define ENV_MAP_SCROLL_SCALE ( 1.0f / 32768.0f )
int g_dl = 1;
bool gOverDraw = false;
namespace NxNgc
{
static s32 last_audio_update = 0;
/******************************************************************/
/* */
/* */
/******************************************************************/
static void do_audio_update( void )
{
s32 t = OSGetTick();
if(( t < last_audio_update ) || ( OSDiffTick( t, last_audio_update ) > (s32)( OS_TIMER_CLOCK / 60 )))
{
last_audio_update = t;
Pcm::PCMAudio_Update();
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static int sort_by_material_draw_order( const void *p1, const void *p2 )
{
sMesh *p_mesh1 = *((sMesh**)p1 );
sMesh *p_mesh2 = *((sMesh**)p2 );
sMaterialHeader *p_material1 = p_mesh1->mp_dl->m_material.p_header;
sMaterialHeader *p_material2 = p_mesh2->mp_dl->m_material.p_header;
Dbg_Assert( p_material1 != NULL );
Dbg_Assert( p_material2 != NULL );
if( p_material1->m_draw_order == p_material2->m_draw_order )
{
// Have to do some special case processing for the situation where two or more meshes have the same draw order, but only some are
// marked as being dynamically sorted. In such a situation the non dynamically sorted ones should come first.
if( ( p_material1->m_flags & (1<<0) ) == ( p_material2->m_flags & (1<<0) ) )
{
if( p_material1 == p_material2 )
{
// Same material, no further sorting required.
return 0;
}
else
{
// If the blend mode is the same, sort by material address.
if( p_material1->m_base_blend == p_material2->m_base_blend )
{
// If the pixel shaders are the same, sort by material address, otherwise sort by pixel shader value.
if( p_material1->m_texture_dl_id == p_material2->m_texture_dl_id )
{
return ((uint32)p_material1 > (uint32)p_material2 ) ? 1 : -1;
}
else
{
return ((uint32)p_material1->m_texture_dl_id < (uint32)p_material2->m_texture_dl_id ) ? 1 : -1;
}
}
else
{
return ((uint32)p_material1->m_base_blend > (uint32)p_material2->m_base_blend ) ? 1 : -1;
}
}
}
else if( p_material1->m_flags & (1<<0) )
{
return 1;
}
return -1;
}
return ( p_material1->m_draw_order > p_material2->m_draw_order ) ? 1 : -1;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
#define INDEX_WORKBUFFER_SIZE 1700
#define MAX_STRIPS 1024
#define MAX_INDEX_WIDTH 7
// Maximum index width:
// 1 position
// 1 normal
// 2 colors
// 4 tex coord
static void hide_mesh( uint32 mask, sCASData *p_cas_data, uint32 num_entries, sMesh * p_mesh )
{
uint16 index_workbuffer[INDEX_WORKBUFFER_SIZE][MAX_INDEX_WIDTH];
uint32 new_indices_index = 0;
int index_strip_len[MAX_STRIPS];
int num_strips = 0;
// Clear strips.
for ( int lp = 0; lp < MAX_STRIPS; lp++ )
{
index_strip_len[lp] = 0;
}
unsigned char * p_start = (unsigned char *)&p_mesh->mp_dl[1];
unsigned char * p_end = &p_start[p_mesh->mp_dl->m_size];
p_start = &p_start[p_mesh->mp_dl->m_index_offset]; // Skip to actual 1st GDBegin.
unsigned char * p8 = p_start;
uint8 begin_token = p8[0]; // Save token for use when rebuilding mesh.
int stride = p_mesh->mp_dl->m_index_stride;
int w;
while ( p8 < p_end )
{
if ( ( p8[0] & 0xf8 ) == GX_TRIANGLESTRIP )
{
// Found a triangle strip - parse it.
int num_verts = ( p8[1] << 8 ) | p8[2];
p8 += 3; // Skip GDBegin
uint16 idx0[MAX_INDEX_WIDTH];
uint16 idx1[MAX_INDEX_WIDTH];
uint16 idx2[MAX_INDEX_WIDTH];
for ( w = 0; w < stride; w++ ) { idx1[w] = ( p8[0] << 8 ) | p8[1]; p8 += 2; }
for ( w = 0; w < stride; w++ ) { idx2[w] = ( p8[0] << 8 ) | p8[1]; p8 += 2; }
for ( int v = 2; v < num_verts; v++ )
{
// Read next index to form triangle.
for ( w = 0; w < stride; w++ ) idx0[w] = idx1[w];
for ( w = 0; w < stride; w++ ) idx1[w] = idx2[w];
for ( w = 0; w < stride; w++ ) { idx2[w] = ( p8[0] << 8 ) | p8[1]; p8 += 2; }
// There shuold be no degenerate triangles.
// ...check against every CAS entry.
bool keep = true;
for( uint32 entry = 0; entry < num_entries; ++entry )
{
// Check this CAS entry has the correct mask...
if( p_cas_data[entry].mask & mask )
{
// ...and the right mesh...
uint32 mesh = p_cas_data[entry].data0 >> 16;
// The CAS data is ordered first in increasing mesh size - so we can early out here if applicable.
if ( mesh > p_mesh->mp_dl->m_mesh_index )
{
break;
}
if ( mesh == p_mesh->mp_dl->m_mesh_index )
{
// ...and the correct index.
uint32 i0 = ( p_cas_data[entry].data0 & 0xFFFF );
// The CAS data is next ordered in increasing size of i0 - so we can early out here if applicable.
if ( i0 > idx0[0] )
{
break;
}
uint32 i1 = ( p_cas_data[entry].data1 >> 16 );
uint32 i2 = ( p_cas_data[entry].data1 & 0xFFFF );
if ( ( i0 == idx0[0] ) && ( i1 == idx1[0] ) && ( i2 == idx2[0] ) )
{
keep = false;
break;
}
}
}
}
// Copy index.
if ( keep )
{
if ( index_strip_len[num_strips] )
{
// Already put 1st triangle in, just add index.
for ( w = 0; w < stride; w++ ) index_workbuffer[new_indices_index][w] = idx2[w];
new_indices_index++;
index_strip_len[num_strips]++;
}
else
{
// 1st triangle, so add all 3 verts.
for ( w = 0; w < stride; w++ ) index_workbuffer[new_indices_index][w] = idx0[w];
new_indices_index ++;
for ( w = 0; w < stride; w++ ) index_workbuffer[new_indices_index][w] = idx1[w];
new_indices_index ++;
for ( w = 0; w < stride; w++ ) index_workbuffer[new_indices_index][w] = idx2[w];
new_indices_index ++;
index_strip_len[num_strips] += 3;
}
}
else
{
// If we don't keep this tri & we already started a strip, we need
// to start a new strip.
if ( index_strip_len[num_strips] )
{
// Need to start a new strip.
num_strips++;
}
}
}
// Start a new strip if we put data in this one.
if ( index_strip_len[num_strips] )
{
// Need to start a new strip.
num_strips++;
}
}
else
{
break;
}
}
do_audio_update();
Dbg_MsgAssert( new_indices_index <= INDEX_WORKBUFFER_SIZE, ( "Too many indices in new mesh: %d\n", new_indices_index ) );
// See if we'll fit in the existing buffer.
uint32 new_size = ( 3 * num_strips ) + ( sizeof( uint16 ) * stride * new_indices_index ) + p_mesh->mp_dl->m_index_offset;
// OSReport( "New: %d Old: %d Diff: %d\n", new_size, p_mesh->mp_dl->m_size, p_mesh->mp_dl->m_size - new_size );
// if ( new_size > p_mesh->mp_dl->m_original_dl_size )
// {
// // Need to allocate a new buffer for this.
// }
if ( new_size <= p_mesh->mp_dl->m_original_dl_size )
{
p8 = p_start;
int buffer_index = 0;
for ( int strip = 0; strip < num_strips; strip++ )
{
*p8++ = begin_token;
*p8++ = (uint8)(index_strip_len[strip] >> 8 );
*p8++ = (uint8)(index_strip_len[strip] & 0xff );
for ( int index = 0; index < index_strip_len[strip]; index++ )
{
for ( w = 0; w < stride; w++ )
{
*p8++ = (uint8)(index_workbuffer[buffer_index][w] >> 8 );
*p8++ = (uint8)(index_workbuffer[buffer_index][w] & 0xff );
}
buffer_index++;
}
}
// Set new size of display list.
int new_rounded_size = ( new_size + 31 ) & ~31;
p_mesh->mp_dl->m_size = new_rounded_size;
// Pad the DL with 0s to avoid spurious crap at the end & flush cache.
int pad_size = new_rounded_size - new_size;
for ( int pad = 0; pad < pad_size; pad++ ) *p8++ = 0;
DCFlushRange( &p_mesh->mp_dl[1], new_rounded_size );
}
else
{
#ifdef __NOPT_FINAL__
OSReport( "Warning: DL too big after hide_mesh - New: %d Old: %d Diff: %d\n", new_size, p_mesh->mp_dl->m_size, p_mesh->mp_dl->m_size - new_size );
#else
Dbg_MsgAssert( false, ( "Error: DL too big after hide_mesh - New: %d Old: %d Diff: %d\n", new_size, p_mesh->mp_dl->m_size, p_mesh->mp_dl->m_size - new_size ) );
#endif // __NOPT_FINAL__
}
do_audio_update();
}
sScene::sScene( void )
{
m_flags = 0;
m_num_meshes = 0; // No meshes as yet.
m_num_filled_meshes = 0;
mpp_mesh_list = NULL;
mp_hierarchyObjects = NULL;
m_numHierarchyObjects = 0;
mp_scene_data = NULL;
mp_dl = NULL;
mp_blend_dl = NULL;
mp_material_header = NULL;
mp_hierarchyObjects = NULL;
m_numHierarchyObjects = 0;
m_is_dictionary = false;
}
sScene::~sScene( void )
{
// Remove the material table.
// if( mp_material_array )
// {
// delete mp_material_array;
// }
//
// if( m_opaque_meshes != NULL )
// {
// delete [] m_opaque_meshes;
// }
// if( m_semitransparent_meshes != NULL )
// {
// delete [] m_semitransparent_meshes;
// }
//
// if ( mp_hierarchyObjects )
// {
// delete [] mp_hierarchyObjects;
// }
//
// // Go through, and see if any DLs got allocated.
// int dl = 0;
// for( uint s = 0; s < mp_scene_data->m_num_objects; ++s )
// {
// int num_mesh = mp_dl[dl].mp_object_header->m_num_meshes;
// for ( int m = 0; m < num_mesh; m++ )
// {
// if ( mp_dl[dl].mp_pos_pool )
// {
// }
// }
// }
if ( mp_scene_data && !( m_flags & SCENE_FLAG_CLONED_GEOM ) )
{
delete [] mp_scene_data;
}
if ( mpp_mesh_list )
{
delete [] mpp_mesh_list;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sScene::AddMeshes( int num_meshes, sMesh **pp_meshes )
{
// Add each mesh.
for( int m = 0; m < num_meshes; ++m )
{
if ( m_num_filled_meshes < m_num_meshes )
{
mpp_mesh_list[m_num_filled_meshes] = pp_meshes[m];
++m_num_filled_meshes;
}
else
{
Dbg_MsgAssert( false, ( "Too many meshes being added." ) );
}
}
// for( int m = 0; m < num_meshes; ++m )
// {
// sMaterialHeader * p_material = pp_meshes[m]->mp_dl->m_material.p_header;
// sMaterialPassHeader * p_pass = &mp_material_pass[p_material->m_pass_item];
//
// bool transparent = (( p_material ) && ( p_pass->m_flags & (1<<3) ));
//
// if ( transparent )
// {
// if ( m_num_filled_meshes < m_num_meshes )
// {
// mpp_mesh_list[m_num_filled_meshes] = pp_meshes[m];
// ++m_num_filled_meshes;
// }
// else
// {
// Dbg_MsgAssert( false, ( "Too many meshes being added." ) );
// }
// }
// }
//
// for( int m = 0; m < num_meshes; ++m )
// {
// sMaterialHeader * p_material = pp_meshes[m]->mp_dl->m_material.p_header;
// sMaterialPassHeader * p_pass = &mp_material_pass[p_material->m_pass_item];
//
// bool transparent = (( p_material ) && ( p_pass->m_flags & (1<<3) ));
//
// if ( !transparent )
// {
// if ( m_num_filled_meshes < m_num_meshes )
// {
// mpp_mesh_list[m_num_filled_meshes] = pp_meshes[m];
// ++m_num_filled_meshes;
// }
// else
// {
// Dbg_MsgAssert( false, ( "Too many meshes being added." ) );
// }
// }
// }
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sScene::CountMeshes( int num_meshes, sMesh **pp_meshes )
{
m_num_meshes += (uint16)num_meshes;
// // Count each mesh.
// for( int m = 0; m < num_meshes; ++m )
// {
// ++m_num_meshes;
//// bool transparent = (( pp_meshes[m]->mp_material ) && ( pp_meshes[m]->mp_material->Flags[0] & 0x40 ));
//// if( transparent )
//// {
//// ++m_num_semitransparent_entries;
//// }
//// else
//// {
//// ++m_num_opaque_entries;
//// }
// }
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sScene::CreateMeshArrays( void )
{
if ( m_num_meshes > 0 )
{
mpp_mesh_list = new sMesh*[m_num_meshes];
}
// if( m_num_semitransparent_entries > 0 )
// {
// m_semitransparent_meshes = new sMesh*[m_num_semitransparent_entries];
// }
//
// if( m_num_opaque_entries > 0 )
// {
// m_opaque_meshes = new sMesh*[m_num_opaque_entries];
// }
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sScene::FigureBoundingVolumes( void )
{
// // Figure bounding sphere assuming bounding box has already been set up (during individual mesh initialisation).
// Mth::Vector radial = ( m_bbox.GetMax() - m_bbox.GetMin() ) * 0.5f;
// Mth::Vector center = m_bbox.GetMin() + radial;
// m_sphere_center.set( center[X], center[Y], center[Z] );
// m_sphere_radius = sqrtf(( radial[X] * radial[X] ) + ( radial[Y] * radial[Y] ) + ( radial[Z] * radial[Z] ));
}
void sScene::RemoveMeshes( int num_meshes, sMesh **pp_meshes )
{
int num_opaque_entries_removed = 0;
int num_pre_semitransparent_entries_removed = 0;
int num_dynamic_semitransparent_entries_removed = 0;
int num_post_semitransparent_entries_removed = 0;
int opaque = m_num_opaque_meshes;
int presemi = opaque + m_num_pre_semitrans_meshes;
int dynsemi = presemi + m_num_dynamic_semitrans_meshes;
int postsemi = dynsemi + m_num_post_semitrans_meshes;
for( int m = 0; m < num_meshes; ++m )
{
sMesh *p_mesh = pp_meshes[m];
bool found = false;
// Search Opaque
for ( int i = 0; i < opaque; i++ )
{
if( mpp_mesh_list[i] == p_mesh )
{
found = true;
mpp_mesh_list[i] = NULL;
++num_opaque_entries_removed;
--m_num_opaque_meshes;
break;
}
}
if( found ) continue;
// Search Pre Semitransparent
for ( int i = opaque; i < presemi; i++ )
{
if( mpp_mesh_list[i] == p_mesh )
{
found = true;
mpp_mesh_list[i] = NULL;
++num_pre_semitransparent_entries_removed;
--m_num_pre_semitrans_meshes;
break;
}
}
if( found ) continue;
// Search Dynamic Semitransparent
for ( int i = presemi; i < dynsemi; i++ )
{
if( mpp_mesh_list[i] == p_mesh )
{
found = true;
mpp_mesh_list[i] = NULL;
++num_dynamic_semitransparent_entries_removed;
--m_num_dynamic_semitrans_meshes;
break;
}
}
if( found ) continue;
// Search Post Semitransparent
for ( int i = dynsemi; i < postsemi; i++ )
{
if( mpp_mesh_list[i] == p_mesh )
{
found = true;
mpp_mesh_list[i] = NULL;
++num_post_semitransparent_entries_removed;
--m_num_post_semitrans_meshes;
break;
}
}
Dbg_Assert( found );
}
// Now go through and compact the arrays.
// int total = m_num_opaque_meshes + m_num_pre_semitrans_meshes + m_num_dynamic_semitrans_meshes + m_num_post_semitrans_meshes;
int total_removed = num_opaque_entries_removed +
num_pre_semitransparent_entries_removed +
num_dynamic_semitransparent_entries_removed +
num_post_semitransparent_entries_removed;
for ( int lp = 0; lp < total_removed; lp++ )
{
for ( int i = 0; i < m_num_filled_meshes; i++ )
{
if( !mpp_mesh_list[i] )
{
// m_num_filled_meshes--;
// mpp_mesh_list[i] = mpp_mesh_list[m_num_filled_meshes];
// Only worth copying if there is anything beyond this mesh.
if( i < ( m_num_filled_meshes - 1 ))
{
memcpy( &mpp_mesh_list[i], &mpp_mesh_list[i + 1], sizeof( sMesh* ) * ( m_num_filled_meshes - ( i + 1 )));
}
m_num_filled_meshes--;
break;
}
}
}
// SortMeshes();
// m_num_filled_meshes -= total_removed;
}
void sScene::SortMeshes( void )
{
// Sort the list of meshes.
qsort( mpp_mesh_list, m_num_filled_meshes, sizeof( sMesh* ), sort_by_material_draw_order );
if ( mp_scene_data )
{
m_num_opaque_meshes = 0;
m_num_pre_semitrans_meshes = 0;
m_num_dynamic_semitrans_meshes = 0;
m_num_post_semitrans_meshes = 0;
// Force opaque to be before semitrans.
sMesh *p_mesh[8192];
int mesh_entry = 0;
Dbg_MsgAssert( m_num_filled_meshes < 8192, ( "Too many meshes for temporary sort buffer." ) );
// Find 1st dynamic entry.
int first_dynamic = -1;
for( int i = 0; i < m_num_filled_meshes; ++i )
{
if ( mpp_mesh_list[i] )
{
bool sorted = mpp_mesh_list[i]->mp_dl->m_material.p_header->m_flags & (1<<0) ? true : false;
if ( ( first_dynamic == -1 ) && sorted ) first_dynamic = i;
}
}
for ( int pass = 0; pass < 4; pass++ )
{
for( int i = 0; i < m_num_filled_meshes; ++i )
{
if ( mpp_mesh_list[i] )
{
bool transparent = ( mp_material_pass[mpp_mesh_list[i]->mp_dl->m_material.p_header->m_pass_item].m_flags & (1<<3) );
// bool transparent = ( mpp_mesh_list[i]->mp_dl->m_material.p_header->m_flags & (1<<3) ) ? true : false;
bool sorted = mpp_mesh_list[i]->mp_dl->m_material.p_header->m_flags & (1<<0) ? true : false;
if ( ( first_dynamic == -1 ) && sorted ) first_dynamic = i;
switch ( pass )
{
case 0: // Opaque
if ( !transparent )
{
p_mesh[mesh_entry] = mpp_mesh_list[i];
mpp_mesh_list[i] = NULL;
mesh_entry++;
m_num_opaque_meshes++;
}
break;
case 1: // Pre semi
if ( transparent && !sorted && ( i < first_dynamic ) )
{
// if ( mpp_mesh_list[i]->mp_dl ) printf( "Pre Semi: %d, %8.3f\n", i, mpp_mesh_list[i]->mp_dl->m_material.p_header->m_draw_order );
p_mesh[mesh_entry] = mpp_mesh_list[i];
mpp_mesh_list[i] = NULL;
mesh_entry++;
m_num_pre_semitrans_meshes++;
}
break;
case 2: // Dynamic semi
if ( transparent && sorted )
{
// if ( mpp_mesh_list[i]->mp_dl ) printf( "Dyn Semi: %d, %8.3f\n", i, mpp_mesh_list[i]->mp_dl->m_material.p_header->m_draw_order );
p_mesh[mesh_entry] = mpp_mesh_list[i];
mpp_mesh_list[i] = NULL;
mesh_entry++;
m_num_dynamic_semitrans_meshes++;
}
break;
case 3: // Post semi (everything else)...
// if ( transparent && !sorted && ( ( i >= first_dynamic ) && ( first_dynamic != -1 ) ) )
{
// if ( mpp_mesh_list[i]->mp_dl ) printf( "Pst Semi: %d, %8.3f\n", i, mpp_mesh_list[i]->mp_dl->m_material.p_header->m_draw_order );
p_mesh[mesh_entry] = mpp_mesh_list[i];
mpp_mesh_list[i] = NULL;
mesh_entry++;
m_num_post_semitrans_meshes++;
}
break;
default:
Dbg_MsgAssert( false, ( "This should never happen." ) );
break;
}
}
}
}
Dbg_MsgAssert( m_num_filled_meshes == mesh_entry, ( "Sorted meshes differs from actual meshes." ) );
// float order = p_mesh[0]->mp_dl->m_material.p_header->m_draw_order;
for( int i = 0; i < m_num_filled_meshes; ++i )
{
// Dbg_MsgAssert( p_mesh[i]->mp_dl->m_material.p_header->m_draw_order >= order, ( "Out of order on entry %d: last=%f, current = %f", i, order, p_mesh[i]->mp_dl->m_material.p_header->m_draw_order ) );
// order = p_mesh[i]->mp_dl->m_material.p_header->m_draw_order;
mpp_mesh_list[i] = p_mesh[i];
}
}
else
{
m_num_opaque_meshes = m_num_filled_meshes;
m_num_pre_semitrans_meshes = 0;
m_num_dynamic_semitrans_meshes = 0;
m_num_post_semitrans_meshes = 0;
}
}
sMaterial *sScene::GetMaterial( uint32 checksum )
{
// for ( int lp = 0; lp < m_num_materials; lp++ )
// {
// if( mp_material_array[lp].Checksum == checksum )
// {
// return &mp_material_array[lp];
// }
// }
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void sScene::HidePolys( uint32 mask, sCASData *p_cas_data, uint32 num_entries )
{
if(( num_entries == 0 ) || ( mask == 0 ))
{
return;
}
// For each mesh, need to find all cas data which references verts in that mesh.
for( int m = 0; m < this->m_num_filled_meshes; ++m )
{
sMesh *p_mesh = mpp_mesh_list[m];
hide_mesh( mask, p_cas_data, num_entries, p_mesh );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
sScene *LoadScene( const char *Filename, sScene *pScene )
{
return NULL;
}
void DeleteScene( sScene *pScene )
{
// // Iterate through the table of materials, deleting them.
// for ( int lp = 0; lp < pScene->m_num_materials; lp++ )
// {
// if( pScene->mp_material_array[lp].mp_wibble_vc_params )
// {
// for( uint32 i = 0; i < pScene->mp_material_array[lp].m_num_wibble_vc_anims; ++i )
// {
// delete [] pScene->mp_material_array[lp].mp_wibble_vc_params[i].mp_keyframes;
// }
// delete [] pScene->mp_material_array[lp].mp_wibble_vc_params;
// }
// if( pScene->mp_material_array[lp].mp_wibble_vc_colors )
// {
// delete [] pScene->mp_material_array[lp].mp_wibble_vc_colors;
// }
// if( pScene->mp_material_array[lp].m_pUVControl )
// {
// delete [] pScene->mp_material_array[lp].m_pUVControl;
// }
// }
// delete pScene->mp_material_array;
// pScene->mp_material_array = NULL;
//
// // Delete the scene itself.
delete pScene;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void MaterialBuild( sMesh * p_mesh, sScene * p_scene, bool bl, bool tx )
{
if ( !p_mesh->mp_dl->m_material.p_header ) return;
// Construct the DLs.
uint32 size;
Mem::Manager::sHandle().TopDownHeap()->PushAlign( 32 );
#define DL_BUILD_SIZE (8*1024)
uint8 * p_build_dl = new (Mem::Manager::sHandle().TopDownHeap()) uint8[DL_BUILD_SIZE];
// Build the texture upload DL.
DCFlushRange ( p_build_dl, DL_BUILD_SIZE );
GX::begin( p_build_dl, DL_BUILD_SIZE );
// multi_mesh( p_mesh, p_scene );
multi_mesh( p_mesh->mp_dl->m_material.p_header,
&p_scene->mp_material_pass[p_mesh->mp_dl->m_material.p_header->m_pass_item],
bl,
tx );
size = GX::end();
DCFlushRange ( p_build_dl, DL_BUILD_SIZE );
if ( size && ( size <= p_scene->mp_texture_dl[p_mesh->mp_dl->m_material.p_header->m_texture_dl_id].m_dl_size ) )
{
// p_mesh->mp_dl->mp_texture_dl = new uint8[size];
memcpy ( p_scene->mp_texture_dl[p_mesh->mp_dl->m_material.p_header->m_texture_dl_id].mp_dl, p_build_dl, size );
DCFlushRange ( p_scene->mp_texture_dl[p_mesh->mp_dl->m_material.p_header->m_texture_dl_id].mp_dl, size );
p_scene->mp_texture_dl[p_mesh->mp_dl->m_material.p_header->m_texture_dl_id].m_dl_size = (uint16)size;
}
else
{
// p_mesh->mp_dl->mp_texture_dl = NULL;
// p_mesh->mp_dl->m_texture_dl_size = 0;
}
Mem::Manager::sHandle().TopDownHeap()->PopAlign();
// Done constructing DL.
delete p_build_dl;
}
int g_material_id = -1;
GXBool g_comploc = (GXBool)2;
void ResetMaterialChange( void )
{
g_material_id = -1;
g_comploc = (GXBool)2;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
//static void MyGXProject (
// f32 x, // model coordinates
// f32 y,
// f32 z,
// f32 mtx[3][4], // model-view matrix
// f32* pm, // projection matrix, as returned by GXGetProjectionv
// f32* vp, // viewport, as returned by GXGetViewportv
// f32* sx, // screen coordinates
// f32* sy,
// f32* sz )
//{
// Vec peye;
// f32 xc, yc, zc, wc;
//
// ASSERTMSG(pm && vp && sx && sy && sz, GXERR_GET_NULL_PTR);
//
// // transform to eye space
// peye.x = mtx[0][0]*x + mtx[0][1]*y + mtx[0][2]*z + mtx[0][3];
// peye.y = mtx[1][0]*x + mtx[1][1]*y + mtx[1][2]*z + mtx[1][3];
// peye.z = mtx[2][0]*x + mtx[2][1]*y + mtx[2][2]*z + mtx[2][3];
//
// // My addition: Just a frig to stop stuff messing up as it gets close to the near plane.
// peye.z -= 512.0f;
// if ( peye.z > -1.0f ) peye.z = -1.0f;
//
// // transform to clip space
// if (pm[0] == (f32)GX_PERSPECTIVE) { // perspective
// xc = peye.x * pm[1] + peye.z * pm[2];
// yc = peye.y * pm[3] + peye.z * pm[4];
// zc = peye.z * pm[5] + pm[6];
// wc = 1.0f / -peye.z;
// } else { // ortho
// xc = peye.x * pm[1] + pm[2];
// yc = peye.y * pm[3] + pm[4];
// zc = peye.z * pm[5] + pm[6];
// wc = 1.0f;
// }
//
// // compute screen scale and offset
// *sx = xc * vp[2]/2 * wc + vp[0] + vp[2]/2;
// *sy = -yc * vp[3]/2 * wc + vp[1] + vp[3]/2;
// *sz = zc * (vp[5] - vp[4]) * wc + vp[5];
//}
//
void MaterialSubmit( sMesh * p_mesh, sScene *pScene = NULL )
{
if ( !pScene->mp_scene_data ) return;
if ( !p_mesh->mp_dl->m_material.p_header ) return;
// if ( !p_mesh->mp_dl->mp_texture_dl ) return;
if ( gOverDraw )
{
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 );
return;
}
// if ( g_dl /*&& !( p_mesh->mp_dl->m_material.p_header->m_flags & (1<<3) )*/ )
// if ( g_dl/* && !( p_mesh->mp_dl->m_material.p_header->m_flags & (1<<3) )*/ )
if ( g_dl && !( p_mesh->mp_dl->m_material.p_header->m_flags & ((1<<3)|(1<<4)) ) )
{
//// if ( p_mesh->mp_dl->m_material.p_header->m_material_dl_id != g_material_id )
// {
// g_material_id = p_mesh->mp_dl->m_material.p_header->m_material_dl_id;
//
// if ( pScene->mp_blend_dl[g_material_id].mp_dl && pScene->mp_blend_dl[g_material_id].m_dl_size )
// {
//// GX::CallDisplayList( pScene->mp_blend_dl[g_material_id].mp_dl, pScene->mp_blend_dl[g_material_id].m_dl_size );
// multi_mesh( p_mesh->mp_dl->m_material.p_header,
// &pScene->mp_material_pass[p_mesh->mp_dl->m_material.p_header->m_pass_item],
// true,
// false );
// }
// }
int tex_id = (int)p_mesh->mp_dl->m_material.p_header->m_texture_dl_id;
GX::CallDisplayList( pScene->mp_texture_dl[tex_id].mp_dl, pScene->mp_texture_dl[tex_id].m_dl_size );
}
else
{
multi_mesh( p_mesh->mp_dl->m_material.p_header,
&pScene->mp_material_pass[p_mesh->mp_dl->m_material.p_header->m_pass_item],
true,
true,
p_mesh->mp_dl->m_material.p_header->m_flags & (1<<6) ? true : false,
p_mesh->mp_dl->mp_object_header->m_num_skin_verts ? false : true );
}
// See if we need to upload env mapping matrices.
sMaterialHeader * p_mat = p_mesh->mp_dl->m_material.p_header;
sMaterialPassHeader *p_pass = &pScene->mp_material_pass[p_mat->m_pass_item];
// Set Comploc
u8 alphacutoff = p_mesh->mp_dl->m_material.p_header->m_alpha_cutoff;
GXBool comploc;
// if ( p_pass->m_texture.p_data && ( p_pass->m_texture.p_data->flags & NxNgc::sTexture::TEXTURE_FLAG_HAS_HOLES ) )
if ( alphacutoff > 0 )
{
comploc = GX_FALSE;
}
else
{
comploc = GX_TRUE;
}
comploc = GX_FALSE;
if ( g_comploc != comploc )
{
g_comploc = comploc;
GX::SetZCompLoc( comploc );
}
// GX::SetAlphaCompare(GX_GEQUAL, alphacutoff, GX_AOP_AND, GX_GEQUAL, alphacutoff );
// GX::SetZCompLoc( GX_FALSE );
GX::SetAlphaCompare(GX_GEQUAL, alphacutoff, GX_AOP_AND, GX_GEQUAL, alphacutoff );
for ( int lp = 0; lp < p_mat->m_passes; lp++, p_pass++ )
{
if ( p_pass->m_flags & ( (1<<1) | (1<<2) ) )
{
// UV Wibbled or Environment mapped.
GXTexMtx mtx;
switch ( lp )
{
case 0:
mtx = GX_TEXMTX0;
break;
case 1:
mtx = GX_TEXMTX1;
break;
case 2:
mtx = GX_TEXMTX2;
break;
case 3:
mtx = GX_TEXMTX3;
break;
default:
mtx = GX_IDENTITY;
break;
}
if( p_pass->m_flags & (1<<1) )
{
// Env mapping.
Mtx s, t, e, mv;
MTXInvXpose((Mtx)&EngineGlobals.local_to_camera, mv );
// Project bounding sphere into screen space to get a metric to scroll the environment map.
f32 p[GX_PROJECTION_SZ];
f32 vp[GX_VIEWPORT_SZ];
float rx, ry; //, rz;
GX::GetProjectionv( p );
GX::GetViewportv( vp );
float x = EngineGlobals.local_to_camera.getPosX();
float y = EngineGlobals.local_to_camera.getPosY();
// float z = EngineGlobals.local_to_camera.getPosZ();
rx = -x; //EngineGlobals.local_to_camera.getRightX()*x + EngineGlobals.local_to_camera.getRightY()*y + EngineGlobals.local_to_camera.getRightZ()*z;
ry = -y; //EngineGlobals.local_to_camera.getUpX()*x + EngineGlobals.local_to_camera.getUpY()*y + EngineGlobals.local_to_camera.getUpZ()*z;
// MyGXProject( p_mesh->mp_dl->m_sphere[X],
// p_mesh->mp_dl->m_sphere[Y],
// p_mesh->mp_dl->m_sphere[Z],
// (Mtx)&EngineGlobals.local_to_camera,
// p, vp, &rx, &ry, &rz );
float u;
float v;
float ut = (float)p_pass->m_u_tile;
float vt = (float)p_pass->m_v_tile;
ut = ( ut * (1.0f / (float)(1<<12)) );
vt = ( vt * (1.0f / (float)(1<<12)) );
u = ( rx * ( ENV_MAP_SCROLL_SCALE * ut ) );
v = ( ry * ( ENV_MAP_SCROLL_SCALE * vt ) );
u -= (float)(int)u; // Keep within +/-1.
v -= (float)(int)v;
// Create the rotational component.
MTXScale( s, 0.5f * ut, -0.5f * vt, 0.0f );
MTXTrans( t, 0.5f, 0.5f, 1.0f );
MTXConcat( t, s, e );
MTXConcat(e, mv, e);
e[0][3] += u;
e[1][3] += v;
GX::LoadTexMtxImm(e, mtx, GX_MTX2x4);
}
else
{
if ( p_pass->m_uv_enabled )
{
// Explicit matrix.
Mtx real;
// MTXCopy( p_pass->mp_explicit_wibble->m_matrix, real );
// real[0][3] = ( p_pass->mp_explicit_wibble->m_matrix[0][3] * -real[0][0] ) + ( p_pass->mp_explicit_wibble->m_matrix[1][3] * -real[0][1] );
// real[1][3] = ( p_pass->mp_explicit_wibble->m_matrix[0][3] * -real[1][0] ) + ( p_pass->mp_explicit_wibble->m_matrix[1][3] * -real[1][1] );
real[0][0] = ( (float)p_pass->m_uv_mat[0] ) * ( 1.0f / ((float)(1<<12)) );
real[0][1] = -( (float)p_pass->m_uv_mat[1] ) * ( 1.0f / ((float)(1<<12)) );
real[0][2] = 1.0f;
real[0][3] = ( (float)p_pass->m_uv_mat[2] ) * ( 1.0f / ((float)(1<<12)) ) - 1.0f;
real[1][0] = ( (float)p_pass->m_uv_mat[1] ) * ( 1.0f / ((float)(1<<12)) );
real[1][1] = ( (float)p_pass->m_uv_mat[0] ) * ( 1.0f / ((float)(1<<12)) );
real[1][2] = 1.0f;
real[1][3] = ( (float)p_pass->m_uv_mat[3] ) * ( 1.0f / ((float)(1<<12)) ) - 1.0f;
GX::LoadTexMtxImm( real, mtx, GX_MTX2x4 );
}
else
{
// Wibbled.
float uoff, voff, t;
t = (float)Tmr::GetTime() * 0.001f;
Mtx m;
sMaterialUVWibble * p_uv = &pScene->mp_uv_wibble[p_pass->m_uv_wibble_index];
uoff = ( t * p_uv->m_u_vel ) + ( p_uv->m_u_amp * sinf( p_uv->m_u_freq * t + p_uv->m_u_phase ));
voff = ( t * p_uv->m_v_vel ) + ( p_uv->m_v_amp * sinf( p_uv->m_v_freq * t + p_uv->m_v_phase ));
// Reduce offset mod 16 and put it in the range -8 to +8.
uoff += 8.0f;
uoff -= (float)(( (int)uoff >> 4 ) << 4 );
voff += 8.0f;
voff -= (float)(( (int)voff >> 4 ) << 4 );
uoff = ( uoff < 0.0f ) ? ( uoff + 8.0f ) : ( uoff - 8.0f );
voff = ( voff < 0.0f ) ? ( voff + 8.0f ) : ( voff - 8.0f );
MTXTrans( m, uoff, voff, 0.0f );
GX::LoadTexMtxImm(m, mtx, GX_MTX2x4);
}
}
}
}
}
} // namespace NxNgc