/////////////////////////////////////////////////////////////////////////////////// // NX.CPP - Platform independent interface to the platfrom specific engine code #include "gfx/nx.h" #include "gfx/NxSector.h" #include "gfx/NxTexMan.h" #include "core/debug.h" #include #include #include #include #include #include #include #include #include #ifdef __PLAT_NGPS__ // For wireframe debuging mode #include #include #include #include #endif #include namespace Nx { /////////////////////////////////////////////////////////////////// // CScene definitions /******************************************************************/ /* */ /* */ /******************************************************************/ CScene::CScene( int sector_table_size ) : mp_sector_man(NULL) { mp_sector_table = new Lst::HashTable< CSector >( sector_table_size ); // Dbg_MsgAssert(0,("secotr-tabel_size = %d\n",sector_table_size)) m_scene_filename[0] = '\0'; // Initilizing supersector and collision crap to NULL, as // we might not have any (like for skys and background stuff) mp_sector_man = NULL; mp_coll_sectors = NULL; mp_coll_sector_data = NULL; m_num_coll_sectors = 0; // Incremental update m_add_scene_filename[0] = '\0'; mp_add_tex_dict = NULL; mp_add_coll_sectors = NULL; mp_add_coll_sector_data = NULL; m_num_add_coll_sectors = 0; m_using_add_sectors = false; mp_orig_sectors = new Lst::Head < CSector >; mp_add_sectors = new Lst::Head < CSector >; m_in_super_sectors = false; m_sky = false; } /******************************************************************/ /* */ /* */ /******************************************************************/ CScene::~CScene() { // Mick: iterate over all the sectors, and delete them // (deleting the mp_sector_table just deletes the references to them) if (mp_sector_table) { mp_sector_table->IterateStart(); CSector *p_sector; while ((p_sector = mp_sector_table->IterateNext())) { p_sector->clear_flags(CSector::mIN_SUPER_SECTORS); // Tells cloned sectors it is OK to go away (and SuperSectors will be dead, anyway) delete p_sector; } delete mp_sector_table; } // Remove SuperSectors if (mp_sector_man) { delete mp_sector_man; } // Remove Collision if (mp_coll_sectors) { delete[] mp_coll_sectors; } if (mp_coll_sector_data) { Pip::Unload(m_coll_filename); } // And the toggle list heads if (mp_orig_sectors) { delete mp_orig_sectors; } if (mp_add_sectors) { delete mp_add_sectors; } // Check if additional texture dictionary was loaded if (mp_add_tex_dict) { Nx::CTexDictManager::sUnloadTextureDictionary(mp_add_tex_dict); } } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::UnloadAddScene() { if (m_using_add_sectors) { ToggleAddScene(); } if (!plat_unload_add_scene()) { return false; } if (mp_add_coll_sectors) { delete[] mp_add_coll_sectors; } if (mp_add_coll_sector_data) { Pip::Unload(m_add_coll_filename); } if (mp_orig_sectors) { Lst::Node< CSector > *obj_node, *next; for(obj_node = mp_orig_sectors->GetNext(); obj_node; obj_node = next) { next = obj_node->GetNext(); delete obj_node; } } if (mp_add_sectors) { Lst::Node< CSector > *obj_node, *next; for(obj_node = mp_add_sectors->GetNext(); obj_node; obj_node = next) { next = obj_node->GetNext(); DeleteSector(obj_node->GetData()); // And delete the sector itself delete obj_node; } } m_using_add_sectors = false; return true; } /******************************************************************/ /* */ /* */ /******************************************************************/ CSector * CScene::GetSector(uint32 sector_checksum) { return mp_sector_table->GetItem(sector_checksum); } /******************************************************************/ /* */ /* */ /******************************************************************/ void CScene::AddSector(CSector *pSector) { mp_sector_table->PutItem(pSector->GetChecksum(), pSector); } /******************************************************************/ /* */ /* */ /******************************************************************/ CSector * CScene::ReplaceSector(CSector *pSector) { CSector *p_old_sector = mp_sector_table->GetItem(pSector->GetChecksum()); // Possibly delete old sector if (p_old_sector) { //if (p_old_sector->get_flags() & CSector::mCLONE) //{ // DeleteSector(p_old_sector); //} else { remove_sector_from_table(p_old_sector->GetChecksum()); // can't delete something that is PIP'ed in p_old_sector->SetActive(false); //} // We also want this out of the SuperSectors p_old_sector->set_flags(CSector::mREMOVE_FROM_SUPER_SECTORS); // Also add to orig list Lst::Node *node = new Lst::Node(p_old_sector); mp_orig_sectors->AddToTail(node); Dbg_Message("Replacing sector %x", pSector->GetChecksum()); } else { Dbg_Message("Adding sector %x", pSector->GetChecksum()); } // And add new one // Garrett TODO: Should I check to see if there is a CCollObj here? Or UpdateSuperSectors()? Or does it matter? pSector->set_flags(CSector::mADD_TO_SUPER_SECTORS); // And do an UpdateSuperSectors() after all the calls AddSector(pSector); Lst::Node *node = new Lst::Node(pSector); mp_add_sectors->AddToTail(node); return p_old_sector; } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::ToggleAddScene() { if (mp_add_sectors->CountItems() == 0) { return false; } Lst::Head < CSector > *p_on_sectors, *p_off_sectors; Lst::Node< CSector > *obj_node, *next; CSector *p_sector; // Do actual toggle m_using_add_sectors = !m_using_add_sectors; // Figure out which to turn on and off if (m_using_add_sectors) { p_on_sectors = mp_add_sectors; p_off_sectors = mp_orig_sectors; } else { p_on_sectors = mp_orig_sectors; p_off_sectors = mp_add_sectors; } // Do off list first for(obj_node = p_off_sectors->GetNext(); obj_node; obj_node = next) { next = obj_node->GetNext(); p_sector = obj_node->GetData(); p_sector->set_flags(CSector::mREMOVE_FROM_SUPER_SECTORS); remove_sector_from_table(p_sector->GetChecksum()); p_sector->SetActive(false); //Dbg_Message("Removed sector %x in toggle", p_sector->GetChecksum()); } // Do on list for(obj_node = p_on_sectors->GetNext(); obj_node; obj_node = next) { next = obj_node->GetNext(); p_sector = obj_node->GetData(); p_sector->set_flags(CSector::mADD_TO_SUPER_SECTORS); AddSector(p_sector); p_sector->SetActive(true); //Dbg_Message("Added sector %x in toggle", p_sector->GetChecksum()); } // And update the SuperSectors UpdateSuperSectors(p_off_sectors); return m_using_add_sectors; } /******************************************************************/ /* */ /* */ /******************************************************************/ uint32 CScene::CloneSector(uint32 orig_sector_checksum, CScene *p_dest_scene, bool instance, bool add_to_super_sectors) { CSector *p_orig_sector = GetSector(orig_sector_checksum); if (p_orig_sector) { return CloneSector(p_orig_sector, p_dest_scene, instance, add_to_super_sectors); } else { return 0; } } /******************************************************************/ /* */ /* */ /******************************************************************/ uint32 CScene::CloneSector(CSector *p_orig_sector, CScene *p_dest_scene, bool instance, bool add_to_super_sectors) { // Use current scene if dest is NULL if (!p_dest_scene) { p_dest_scene = this; } CSector *p_new_sector = p_orig_sector->clone(instance, add_to_super_sectors, p_dest_scene); if (p_new_sector) { p_dest_scene->AddSector(p_new_sector); return p_new_sector->GetChecksum(); } else { return 0; } } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::DeleteSector(uint32 sector_checksum) { CSector *p_sector = GetSector(sector_checksum); if (p_sector) { return DeleteSector(p_sector); } else { return false; } } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::DeleteSector(CSector *p_sector) { if (p_sector->get_flags() & CSector::mIN_SUPER_SECTORS) { p_sector->set_flags(CSector::mMARKED_FOR_DELETION); // Can't delete, yet return false; } else { if (GetSector(p_sector->GetChecksum()) == p_sector) // Just in case we're doing this with AddSectors { mp_sector_table->FlushItem(p_sector->GetChecksum()); } delete p_sector; return true; } } /******************************************************************/ /* */ /* */ /******************************************************************/ void CScene::PostLoad(const char *p_name) { strcpy(m_scene_filename, p_name); // needs name for Pip::Unload() plat_post_load(); } /******************************************************************/ /* */ /* */ /******************************************************************/ void CScene::PostAdd(const char *p_name, Nx::CTexDict * p_tex_dict) { strcpy(m_add_scene_filename, p_name); // needs to store name somewhere for Pip::Unload(), if we use Pip mp_add_tex_dict = p_tex_dict; m_using_add_sectors = true; plat_post_add(); } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::read_collision(const char *p_name, char *p_pip_name, int &num_coll_sectors, CCollStaticTri * &p_coll_sectors, CCollObjTriData * &p_coll_sector_data, Mth::CBBox &bbox, bool is_net) { // for now collision is kind of assumed to be platform independent sprintf(p_pip_name,"levels\\%s\\%s%s.col.%s",p_name,p_name,is_net?"_net":"",CEngine::sGetPlatformExtension()); Dbg_Message ( "Loading collision %s....", p_pip_name ); bool found_point = false; uint8 *p_base_addr = (uint8 *) Pip::Load(p_pip_name); if (p_base_addr) { Nx::CCollObjTriData::SReadHeader *p_header = (Nx::CCollObjTriData::SReadHeader *) p_base_addr; p_base_addr += sizeof(Nx::CCollObjTriData::SReadHeader); #ifndef __PLAT_NGC__ Dbg_Message ( "Version # %d header sizeof %d", p_header->m_version, sizeof(Nx::CCollObjTriData)); Dbg_Message ( "Number of objects: %d verts: %d faces: %d", p_header->m_num_objects, p_header->m_total_num_verts, p_header->m_total_num_faces_large + p_header->m_total_num_faces_small); Dbg_Message ( "Small verts: %d Large verts: %d", p_header->m_total_num_verts_small, p_header->m_total_num_verts_large); #endif // __PLAT_NGC__ Dbg_MsgAssert(p_header->m_version >= 9, ("Collision version must be at least 9.")); // reserve space for objects num_coll_sectors = p_header->m_num_objects; p_coll_sector_data = (Nx::CCollObjTriData *) p_base_addr; //new Cld::CCollSector [m_num_coll_sectors]; // Calculate base addresses for vert and face arrays uint8 *p_base_vert_addr = (uint8 *) (p_coll_sector_data + num_coll_sectors); #ifndef __PLAT_NGC__ p_base_vert_addr = (uint8 *)(((uint)(p_base_vert_addr+15)) & 0xFFFFFFF0); // Align to 128 bit boundary #ifdef FIXED_POINT_VERTICES uint8 *p_base_intensity_addr = p_base_vert_addr + (p_header->m_total_num_verts_large * Nx::CCollObjTriData::GetVertElemSize() + p_header->m_total_num_verts_small * Nx::CCollObjTriData::GetVertSmallElemSize()); uint8 *p_base_face_addr = p_base_intensity_addr + p_header->m_total_num_verts; p_base_face_addr = (uint8 *)(((uint)(p_base_face_addr+3)) & 0xFFFFFFFC); // Align to 32 bit boundary #else uint8 *p_base_intensity_addr = NULL; uint8 *p_base_face_addr = p_base_vert_addr + (p_header->m_total_num_verts * Nx::CCollObjTriData::GetVertElemSize()); p_base_face_addr = (uint8 *)(((uint)(p_base_face_addr+15)) & 0xFFFFFFF0); // Align to 128 bit boundary #endif // FIXED_POINT_VERTICES #else uint8 *p_base_intensity_addr = NULL; uint8 *p_base_face_addr = p_base_vert_addr + (p_header->m_total_num_faces * Nx::CCollObjTriData::GetVertElemSize()); p_base_face_addr = (uint8 *)(((uint)(p_base_face_addr+3)) & 0xFFFFFFFC); // Align to 32 bit boundary #endif // __PLAT_NGC__ // Calculate addresses for BSP arrays #ifndef __PLAT_NGC__ uint8 *p_node_array_size = p_base_face_addr + (p_header->m_total_num_faces_large * Nx::CCollObjTriData::GetFaceElemSize() + p_header->m_total_num_faces_small * Nx::CCollObjTriData::GetFaceSmallElemSize()); p_node_array_size += ( p_header->m_total_num_faces_large & 1 ) ? 2 : 0; #else uint8 *p_node_array_size = p_base_face_addr + ( p_header->m_total_num_faces * Nx::CCollObjTriData::GetFaceElemSize() ); p_node_array_size += ( p_header->m_total_num_faces & 1 ) ? 2 : 0; #endif // __PLAT_NGC__ uint8 *p_base_node_addr = p_node_array_size + 4; uint8 *p_base_face_idx_addr = p_base_node_addr + *((int *) p_node_array_size); // Reserve space for collsion objects p_coll_sectors = new CCollStaticTri[p_header->m_num_objects]; // Read objects for (int oidx = 0; oidx < p_header->m_num_objects; oidx++) { p_coll_sector_data[oidx].InitCollObjTriData(this, p_base_vert_addr, p_base_intensity_addr, p_base_face_addr, p_base_node_addr, p_base_face_idx_addr); p_coll_sector_data[oidx].InitBSPTree(); p_coll_sectors[oidx].SetGeometry(&(p_coll_sector_data[oidx])); if (p_coll_sector_data[oidx].GetNumFaces() > 0) // only add bbox if there are some faces in the object..... { // Add to scene bbox bbox.AddPoint(p_coll_sector_data[oidx].GetBBox().GetMin()); bbox.AddPoint(p_coll_sector_data[oidx].GetBBox().GetMax()); found_point = true; } } if (!found_point) { // if there was no collision, then set up a dummy 200 inch bounding box at the origin bbox.AddPoint(Mth::Vector (-100,-100,-100)); bbox.AddPoint(Mth::Vector (100,100,100)); } } else { Dbg_Error ( "Could not open collision file\n" ); return false; } Dbg_Message ( "successfully read collision" ); return true; } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::LoadCollision(const char *p_name, bool is_net) { read_collision(p_name, m_coll_filename, m_num_coll_sectors, mp_coll_sectors, mp_coll_sector_data, m_collision_bbox, is_net); Dbg_Message("Scene bounding box: min (%f, %f, %f) max (%f, %f, %f)", m_collision_bbox.GetMin()[X], m_collision_bbox.GetMin()[Y], m_collision_bbox.GetMin()[Z], m_collision_bbox.GetMax()[X], m_collision_bbox.GetMax()[Y], m_collision_bbox.GetMax()[Z]); if (m_num_coll_sectors > 0) { // Create super sectors if (m_in_super_sectors) { mp_sector_man = new SSec::Manager; mp_sector_man->GenerateSuperSectors(m_collision_bbox); mp_sector_man->AddCollisionToSuperSectors(mp_coll_sectors, m_num_coll_sectors); } // Add to CSectors for (int i = 0; i < m_num_coll_sectors; i++) { CSector *p_sector = GetSector(mp_coll_sectors[i].GetChecksum()); if (!p_sector) // Don't assert now since there may not be renderable data { // Collision info, but not renderable // so, we still need to create a Sector, but with no renderable component p_sector = CreateSector(); // create empty secotr p_sector->SetChecksum(mp_coll_sectors[i].GetChecksum()); p_sector->SetActive(true); AddSector(p_sector); } p_sector->AddCollSector(&(mp_coll_sectors[i])); p_sector->set_flags(CSector::mIN_SUPER_SECTORS); } } CEngine::sGetWeather()->UpdateGrid(); return plat_load_collision(p_name); } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::AddCollision(const char *p_name) { Mth::CBBox add_collision_bbox; if (mp_coll_sectors == NULL) { return false; // collision not needed } read_collision(p_name, m_add_coll_filename, m_num_add_coll_sectors, mp_add_coll_sectors, mp_add_coll_sector_data, add_collision_bbox); if ((add_collision_bbox.GetMin()[X] < m_collision_bbox.GetMin()[X]) || (add_collision_bbox.GetMax()[X] > m_collision_bbox.GetMax()[X]) || (add_collision_bbox.GetMin()[Z] < m_collision_bbox.GetMin()[Z]) || (add_collision_bbox.GetMax()[Z] > m_collision_bbox.GetMax()[Z])) { Dbg_Message("Add Scene bounding box: min (%f, %f, %f) max (%f, %f, %f)", add_collision_bbox.GetMin()[X], add_collision_bbox.GetMin()[Y], add_collision_bbox.GetMin()[Z], add_collision_bbox.GetMax()[X], add_collision_bbox.GetMax()[Y], add_collision_bbox.GetMax()[Z]); Dbg_Message("Scene bounding box: min (%f, %f, %f) max (%f, %f, %f)", m_collision_bbox.GetMin()[X], m_collision_bbox.GetMin()[Y], m_collision_bbox.GetMin()[Z], m_collision_bbox.GetMax()[X], m_collision_bbox.GetMax()[Y], m_collision_bbox.GetMax()[Z]); Dbg_MsgAssert(add_collision_bbox.Within(m_collision_bbox), ("Can't add collision outside of original scene")); } if (m_num_add_coll_sectors > 0) { // Add to CSectors for (int i = 0; i < m_num_add_coll_sectors; i++) { CSector *p_sector = GetSector(mp_add_coll_sectors[i].GetChecksum()); if (!p_sector) // Don't assert now since there may not be renderable data { Dbg_Message("We don't necessarily want to be creating invisible sectors on an incremental update"); // Collision info, but not renderable // so, we still need to create a Sector, but with no renderable component p_sector = CreateSector(); // create empty secotr p_sector->SetChecksum(mp_add_coll_sectors[i].GetChecksum()); p_sector->SetActive(true); p_sector->set_flags(CSector::mADD_TO_SUPER_SECTORS); AddSector(p_sector); Lst::Node *node = new Lst::Node(p_sector); mp_add_sectors->AddToTail(node); } p_sector->AddCollSector(&(mp_add_coll_sectors[i])); Dbg_Assert(p_sector->get_flags() & CSector::mADD_TO_SUPER_SECTORS); } // Now add to SuperSectors UpdateSuperSectors(mp_orig_sectors); } return plat_add_collision(p_name); } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::CreateCollision(const Mth::CBBox & scene_bbox) { // Make sure we asked for it at scene creation if (!m_in_super_sectors) { return false; } m_collision_bbox = scene_bbox; mp_sector_man = new SSec::Manager; mp_sector_man->GenerateSuperSectors(m_collision_bbox); return true; } #ifdef __NOPT_ASSERT__ void CScene::DebugRenderCollision(uint32 ignore_1, uint32 ignore_0) { if (Nx::CEngine::GetWireframeMode() == 4 || Nx::CEngine::GetWireframeMode() == 5) { #ifdef __PLAT_NGPS__ #if 1 // Traverse the tree at the mesh level // so we can see the actual meshes CPs2Scene * p_ps2_scene = (CPs2Scene *) Nx::CEngine::sGetMainScene(); p_ps2_scene->GetEngineScene()->RenderWireframe(Nx::CEngine::GetWireframeMode()); #else Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().DebugHeap()); Mth::Vector *p_verts = new Mth::Vector[100000]; Mem::Manager::sHandle().PopContext(); Nx::CScene *p_scene = Nx::CEngine::sGetMainScene(); // crappy wireframe rendering of renderable, so we can see if there is any invislbe junk there Lst::HashTable< Nx::CSector > * p_sector_list = p_scene->GetSectorList(); int sectors = 0; int vert_count=0; int lines = 0; if (p_sector_list) { p_sector_list->IterateStart(); Nx::CSector *p_sector = p_sector_list->IterateNext(); while(p_sector && lines <100000) // Can't draw too many lines in this mode for some reason { if (p_sector->IsActive()) { Nx::CGeom *p_geom = p_sector->GetGeom(); if (p_geom) { NxPs2::CGeomNode *p_node = (((CPs2Geom*)p_geom)->GetEngineObject()); if (p_node->WasRendered()) { sectors++; // // Do renderable geometry int verts = p_geom->GetNumRenderVerts(); if ( verts > 3000) { // printf ("Strange no of verts %d on %s\n",verts, Script::FindChecksumName(p_sector->GetChecksum())); } if (verts < 30000) { //NxPs2::BeginLines3D(0x80000000 + (0x00ff00ff)); // Magenta vert_count += verts; #define peak 500 int n=p_geom->GetNumRenderPolys(); int r,g,b; r=g=b=0; if (n <= peak ) { r = (255 * (n)) / peak; // r ramps up (black to red) } else if (n <= peak * 2) { r = 255; b = (255 * (n - peak) / (peak)); // b&g ramps up (to white) g = b; } else { r = g = b = 255; } uint32 rgb = (b<<16)|(g<<8)|r; if (Nx::CEngine::GetWireframeMode() == 4) { NxPs2::BeginLines3D(0x80000000 + (0x00ffffff & p_sector->GetChecksum())); } else { NxPs2::BeginLines3D(0x80000000 + (0x00ffffff & rgb)); } p_geom->GetRenderVerts(p_verts); Mth::Vector *p_vert = p_verts+1; for (int i = 1; i < verts; i++) { NxPs2::DrawLine3D((*p_vert)[X],(*p_vert)[Y],(*p_vert)[Z],p_vert[-1][X],p_vert[-1][Y],p_vert[-1][Z]); p_vert++; lines++; } // end for NxPs2::EndLines3D(); } // end if } } } p_sector = p_sector_list->IterateNext(); } } // printf ("Renderable wireframe %d sectors, %d verts, %d lines\n",sectors, vert_count, lines); delete [] p_verts; #endif #endif } else { if (!m_in_super_sectors) { // if collision data is not being used, then just return return; } if (mp_coll_sectors) { for (int i = 0; i < m_num_coll_sectors; i++) { mp_coll_sectors[i].DebugRender(ignore_1,ignore_0); } } else { // Try finding the collision through the sectors mp_sector_table->IterateStart(); CSector *p_sector; while ((p_sector = mp_sector_table->IterateNext())) { if (p_sector->GetCollSector()) // Might not have it yet in park editor { p_sector->GetCollSector()->DebugRender(ignore_1, ignore_0); } } } } } #endif void CScene::DebugCheckForHoles() { for (int i = 0; i < m_num_coll_sectors; i++) { printf ("%4d/%d ",i,m_num_coll_sectors); CCollStaticTri *p_static_tri = static_cast(&(mp_coll_sectors[i])); Dbg_Assert(p_static_tri); p_static_tri->CheckForHoles(); } } // Return the number of collision sectors in the scene int CScene::GetNumCollSectors() { return m_num_coll_sectors; } // return a pointer to static collision data // for a collision sector // used CCollStaticTri * CScene::GetCollStatic(int n) { return &(mp_coll_sectors[n]); } /******************************************************************/ /* */ /* */ /******************************************************************/ void CScene::UpdateSuperSectors(Lst::Head *p_additional_remove_list) { // Check if we even have SuperSectors if (!mp_sector_man) { return; } Lst::Head< Nx::CCollStatic > coll_add_list; Lst::Head< Nx::CCollStatic > coll_remove_list; Lst::Head< Nx::CCollStatic > coll_update_list; Lst::Head< CSector > sector_delete_list; /* Mem::Heap *p_top_heap = Mem::Manager::sHandle().TopDownHeap(); Mem::Region *p_top_region = p_top_heap->mp_region; Ryan("UpdateSuperSectors()\n"); Ryan(" free %d\n", p_top_heap->mFreeMem.m_count + p_top_region->MemAvailable()); Ryan(" used %d\n", p_top_heap->mUsedMem.m_count); Ryan(" largest %d\n", p_top_heap->LargestFreeBlock()); */ // Allocate temp list on high heap Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap()); mp_sector_table->IterateStart(); Lst::Node< Nx::CCollStatic > *node; CSector *p_sector; // Make Add and remove list while ((p_sector = mp_sector_table->IterateNext())) { // Add List if (p_sector->get_flags() & CSector::mADD_TO_SUPER_SECTORS) { node = new Lst::Node< Nx::CCollStatic > ( p_sector->GetCollSector() ); coll_add_list.AddToTail(node); p_sector->clear_flags(CSector::mADD_TO_SUPER_SECTORS); p_sector->set_flags(CSector::mIN_SUPER_SECTORS); //Dbg_Message("Adding sector %x and collision %x of checksum %x", p_sector, p_sector->GetCollSector(), p_sector->GetChecksum()); //Mth::CBBox b_box = p_sector->GetCollSector()->GetGeometry()->GetBBox(); //Dbg_Message("Adding sector %x and collision %x and bounding box [%f,%f,%f]-[%f,%f,%f]", p_sector->GetChecksum(), p_sector->GetCollSector()->GetChecksum(), // b_box.GetMin()[X], b_box.GetMin()[Y], b_box.GetMin()[Z], // b_box.GetMax()[X], b_box.GetMax()[Y], b_box.GetMax()[Z]); Dbg_MsgAssert(!(p_sector->get_flags() & CSector::mINVALID_SUPER_SECTORS), ("Trying to add collision that needed updating")); } // Remove List if (p_sector->get_flags() & (CSector::mMARKED_FOR_DELETION | CSector::mREMOVE_FROM_SUPER_SECTORS)) { node = new Lst::Node< Nx::CCollStatic > ( p_sector->GetCollSector() ); coll_remove_list.AddToTail(node); // Also make a sector delete list if (p_sector->get_flags() & CSector::mMARKED_FOR_DELETION) { Lst::Node< CSector > *sec_node = new Lst::Node< CSector > (p_sector); sector_delete_list.AddToTail(sec_node); } else { p_sector->clear_flags(CSector::mREMOVE_FROM_SUPER_SECTORS); } //Dbg_Message("Deleting sector %x and collision %x of checksum %x", p_sector, p_sector->GetCollSector(), p_sector->GetChecksum()); //Mth::CBBox b_box = p_sector->GetCollSector()->GetGeometry()->GetBBox(); //Dbg_Message("Deleting sector %x and collision %x and bounding box [%f,%f,%f]-[%f,%f,%f]", p_sector->GetChecksum(), p_sector->GetCollSector()->GetChecksum(), // b_box.GetMin()[X], b_box.GetMin()[Y], b_box.GetMin()[Z], // b_box.GetMax()[X], b_box.GetMax()[Y], b_box.GetMax()[Z]); Dbg_MsgAssert(!(p_sector->get_flags() & CSector::mADD_TO_SUPER_SECTORS), ("Collision being both added and deleted from SuperSectors")); Dbg_MsgAssert(p_sector->get_flags() & CSector::mIN_SUPER_SECTORS, ("Trying to remove sector from SuperSector that isn't in any SuperSector")); Dbg_MsgAssert(!(p_sector->get_flags() & CSector::mINVALID_SUPER_SECTORS), ("Trying to remove collision that hasn't been updated")); } // Update List if (p_sector->get_flags() & CSector::mINVALID_SUPER_SECTORS) { node = new Lst::Node< Nx::CCollStatic > ( p_sector->GetCollSector() ); coll_update_list.AddToTail(node); p_sector->clear_flags(CSector::mINVALID_SUPER_SECTORS); //Mth::CBBox b_box = p_sector->GetCollSector()->GetGeometry()->GetBBox(); //Dbg_Message("Updating sector %x and collision %x and bounding box [%f,%f,%f]-[%f,%f,%f]", p_sector->GetChecksum(), p_sector->GetCollSector()->GetChecksum(), // b_box.GetMin()[X], b_box.GetMin()[Y], b_box.GetMin()[Z], // b_box.GetMax()[X], b_box.GetMax()[Y], b_box.GetMax()[Z]); Dbg_MsgAssert(p_sector->get_flags() & CSector::mIN_SUPER_SECTORS, ("Collision being updated that isn't in SuperSectors")); } } // Check additional remove list if (p_additional_remove_list) { Lst::Node< CSector > *obj_node, *next; for(obj_node = p_additional_remove_list->GetNext(); obj_node; obj_node = next) { next = obj_node->GetNext(); p_sector = obj_node->GetData(); Dbg_Assert(!(p_sector->get_flags() & CSector::mMARKED_FOR_DELETION)); // Make sure it shouldn't be deleted // Make sure it isn't already on the list bool new_node = true; if(coll_remove_list.CountItems() > 0) { Lst::Node *node_coll, *node_next; for(node_coll = coll_remove_list.GetNext(); node_coll; node_coll = node_next) { node_next = node_coll->GetNext(); if (node_coll->GetData() == p_sector->GetCollSector()) { new_node = false; break; } } } if (new_node) { node = new Lst::Node< Nx::CCollStatic > ( p_sector->GetCollSector() ); coll_remove_list.AddToTail(node); p_sector->clear_flags(CSector::mREMOVE_FROM_SUPER_SECTORS); //Dbg_Message("Deleting additional sector %x and collision %x of checksum %x", p_sector, p_sector->GetCollSector(), p_sector->GetChecksum()); //Dbg_Message("Deleting additional sector %x and collision %x", p_sector->GetChecksum(), p_sector->GetCollSector()->GetChecksum()); } } } Mem::Manager::sHandle().PopContext(); // Do the actual update mp_sector_man->UpdateCollisionSuperSectors(coll_add_list, coll_remove_list, coll_update_list); Lst::Node *node_coll, *node_next; // // Free lists // if(coll_add_list.CountItems() > 0) { for(node_coll = coll_add_list.GetNext(); node_coll; node_coll = node_next) { node_next = node_coll->GetNext(); delete node_coll; } } if(coll_remove_list.CountItems() > 0) { for(node_coll = coll_remove_list.GetNext(); node_coll; node_coll = node_next) { node_next = node_coll->GetNext(); delete node_coll; } } if(coll_update_list.CountItems() > 0) { for(node_coll = coll_update_list.GetNext(); node_coll; node_coll = node_next) { node_next = node_coll->GetNext(); delete node_coll; } } // And finally delete the marked sectors if(sector_delete_list.CountItems() > 0) { Lst::Node *node_sector, *node_sec_next; for(node_sector = sector_delete_list.GetNext(); node_sector; node_sector = node_sec_next) { node_sec_next = node_sector->GetNext(); p_sector = node_sector->GetData(); mp_sector_table->FlushItem(p_sector->GetChecksum()); p_sector->clear_flags(CSector::mIN_SUPER_SECTORS); delete p_sector; delete node_sector; } } } /******************************************************************/ /* */ /* */ /******************************************************************/ void CScene::ClearSuperSectors() { // Check if we even have SuperSectors if (!mp_sector_man) { return; } mp_sector_table->IterateStart(); CSector *p_sector; // Check all sectors to make sure they need deleting while ((p_sector = mp_sector_table->IterateNext())) { // Remove List if (p_sector->get_flags() & CSector::mMARKED_FOR_DELETION) { //Dbg_Message("Deleting sector %x and collision %x of checksum %x", p_sector, p_sector->GetCollSector(), p_sector->GetChecksum()); Dbg_MsgAssert(!(p_sector->get_flags() & CSector::mADD_TO_SUPER_SECTORS), ("Collision being both added and deleted from SuperSectors")); Dbg_MsgAssert(p_sector->get_flags() & CSector::mIN_SUPER_SECTORS, ("Trying to remove sector from SuperSector that isn't in any SuperSector")); Dbg_MsgAssert(!(p_sector->get_flags() & CSector::mINVALID_SUPER_SECTORS), ("Trying to remove collision that hasn't been updated")); p_sector->clear_flags(CSector::mIN_SUPER_SECTORS); delete p_sector; } else { Dbg_MsgAssert(0, ("Trying to clear SuperSectors even though sector %x hasn't been marked for deletion", p_sector->GetChecksum())); } } // Do the actual clear mp_sector_man->ClearCollisionSuperSectors(); // And clear the hash table mp_sector_table->FlushAllItems(); } // Given a bounding box, then set the active flag of those // sectors that intersect this box by at least a certain abount void CScene::SetActiveInBox(Mth::CBBox &box, bool active, float min_intersect) { Mth::CBBox smaller_box = box; // later.. // smaller_box.Shrink(min_intersect); mp_sector_table->IterateStart(); CSector *p_sector; while ((p_sector = mp_sector_table->IterateNext())) { // printf ("Checking sector\n"); if (smaller_box.Intersect(p_sector->GetBoundingBox())) { // printf("Setting active = %d\n",active); p_sector->SetActive(active); } } } /******************************************************************/ /* */ /* */ /******************************************************************/ // Create an empty sector CSector * CScene::CreateSector() { CSector *p_sector = plat_create_sector(); p_sector->mp_geom = NULL; p_sector->mp_coll_sector = NULL; return p_sector; } void CScene::GetMetrics(Script::CStruct * p_info) { p_info->AddString(CRCD(0xc3f4169a,"FileName"),GetSceneFilename()); int total_sectors = 0; int render_sectors = 0; int render_verts = 0; int render_polys = 0; int render_base_polys = 0; // Iterate over the sectors, counting verious things Lst::HashTable< Nx::CSector > * p_sector_list = GetSectorList(); if (p_sector_list) { p_sector_list->IterateStart(); Nx::CSector *p_sector = p_sector_list->IterateNext(); while(p_sector) { total_sectors++; Nx::CGeom *p_geom = p_sector->GetGeom(); if (p_geom) { // Do renderable geometry render_sectors++; render_verts += p_geom->GetNumRenderVerts(); render_polys += p_geom->GetNumRenderPolys(); render_base_polys += p_geom->GetNumRenderBasePolys(); } p_sector = p_sector_list->IterateNext(); } } p_info->AddInteger(CRCD(0x4a6bf967,"Sectors"),total_sectors); p_info->AddInteger(CRCD(0xac30a9d,"ColSectors"),GetNumCollSectors()); p_info->AddInteger(CRCD(0x969d3af6,"Verts"),render_verts); p_info->AddInteger(CRCD(0xd576df05,"Polys"),render_polys); p_info->AddInteger(CRCD(0x1e3061ee,"BasePolys"),render_base_polys); p_info->AddInteger(CRCD(0x5714c480,"TextureMemory"),GetTexDict()->GetFileSize()); } /******************************************************************/ /* */ /* */ /******************************************************************/ void CScene::SetMajorityColor(Image::RGBA rgba) { plat_set_majority_color(rgba); } /******************************************************************/ /* */ /* */ /******************************************************************/ Image::RGBA CScene::GetMajorityColor() const { return plat_get_majority_color(); } /******************************************************************/ /* */ /* */ /******************************************************************/ void CScene::plat_post_load() { printf ("STUB: PostLoad\n"); } /******************************************************************/ /* */ /* */ /******************************************************************/ void CScene::plat_post_add() { printf ("STUB: PostAdd\n"); } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::plat_load_textures(const char *p_name) { printf ("STUB: LoadTextures\n"); return false; } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::plat_load_collision(const char *p_name) { printf ("STUB: LoadCollision\n"); return false; } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::plat_add_collision(const char *p_name) { printf ("STUB: AddCollision\n"); return false; } /******************************************************************/ /* */ /* */ /******************************************************************/ bool CScene::plat_unload_add_scene() { printf ("STUB: UnloadAddScene\n"); return false; } /******************************************************************/ /* */ /* */ /******************************************************************/ CSector* CScene::plat_create_sector() { printf ("STUB: plat_create_sector\n"); return NULL; } /******************************************************************/ /* */ /* */ /******************************************************************/ void CScene::plat_set_majority_color(Image::RGBA rgba) { // STUB: only really needed on PS2, so ignorable on other platforms } /******************************************************************/ /* */ /* */ /******************************************************************/ Image::RGBA CScene::plat_get_majority_color() const { // STUB: only really needed on PS2, so ignorable on other platforms return Image::RGBA(0x80, 0x80, 0x80, 0x80); } } // namespace Nx