#include "ProxyHeaders.hpp" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SortInterestZonesProcess::SortInterestZonesProcess( Stuff::NotationFile *config_file, const char* set_path, const Stuff::DynamicArrayOf &zone_array, BinSortProcess *bin_process, FindErrorsProcess *find_errors ): Process(config_file), zoneArray(zone_array) { Check_Object(config_file); Check_Pointer(set_path); Check_Object(&zone_array); configFile = config_file; setDirectory = set_path; zoneCounter = 0; setContents = NULL; trimmingTolerance = 1e-2f; Page *page = config_file->FindPage("InterestBSP"); if (page) page->GetEntry("TrimmingTolerance", &trimmingTolerance); sortProcess = bin_process; errorProcess = find_errors; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void SortInterestZonesProcess::SplitCallback(GenericProxy *proxy) { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void SortInterestZonesProcess::CreateCallback(GenericProxy *proxy) { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // FlattenHierarchyProcess* SortInterestZonesProcess::MakeFlattenHierarchyProcess( Stuff::NotationFile *config_file, GroupProxy *parent_group ) { Check_Object(this); return new FlattenHierarchyProcess(config_file, parent_group); } // //############################################################################ //########################### InterestBSP ############################## //############################################################################ // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // InterestBSP::~InterestBSP() { if (insideNode) { Check_Object(insideNode); delete insideNode; } if (outsideNode) { Check_Object(outsideNode); delete outsideNode; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // InterestBSP* InterestBSP::CreateBSPTree(SortInterestZonesProcess *process) { Check_Object(process); // //----------------------------------- // Create the candidate set of planes //----------------------------------- // DynamicArrayOf planes; Find_Planes_Of_Boxes(&planes, process->zoneArray); // //------------------------------------------------------------ // Create the scoreboard, and test each box against each plane //------------------------------------------------------------ // unsigned plane_count = planes.GetLength(); unsigned zone_count = process->zoneArray.GetLength(); DynamicArrayOf scoreboard(plane_count * zone_count); int *entry = &scoreboard[0]; for (unsigned plane=0; plane(entry - &scoreboard[0]) < plane_count * zone_count ); if ( planes[plane].ContainsAllOf( process->zoneArray[zone], process->planeThicknessTolerance ) ) *entry = ContainsAll; else if ( planes[plane].ContainsSomeOf( process->zoneArray[zone], process->planeThicknessTolerance ) ) *entry = Splits; else *entry = ContainsNone; } } // //----------------------------------------- // Create an index into the zones structure //----------------------------------------- // DynamicArrayOf index(zone_count); for (unsigned zone=0; zone &scoreboard, const Stuff::DynamicArrayOf &planes, Stuff::DynamicArrayOf &index, unsigned zone_count ) { Check_Object(&scoreboard); Check_Object(&planes); unsigned plane_count = planes.GetLength(); Verify(plane_count > 0); Verify(zone_count > 0); Verify(plane_count * zone_count == scoreboard.GetLength()); Check_Object(&index); unsigned active_count = index.GetLength(); Verify(active_count <= zone_count); Verify(active_count > 0); // //--------------------------------------------------------------------- // If the active zone list only contains one zone then we create a leaf // BSP node that holds it //--------------------------------------------------------------------- // InterestBSP *node = new InterestBSP; if (active_count == 1) { node->zoneIndex = index[0]; return node; } node->zoneIndex = zone_count; // //------------------------------------------------------------------------- // Our first step is to build a summary of the scoreboard information on // all the active zones across all the separation planes. The summary will // be based upon the balance achieved by that particular plane on the // current set of zones //------------------------------------------------------------------------- // DynamicArrayOf summary(plane_count); unsigned plane; for (plane=0; planedividingPlane = planes[best_plane]; Verify(!((active_count + best_balance)&1)); unsigned in_size = (active_count + best_balance) >> 1; unsigned out_size = active_count - in_size; DynamicArrayOf in(in_size); DynamicArrayOf out(out_size); // //---------------------------------------------------------------------- // Run through the list, moving the index values to the appropriate list //---------------------------------------------------------------------- // unsigned in_count = 0; unsigned out_count = 0; const int *row = &scoreboard[best_plane * zone_count]; for (unsigned i=0; iinsideNode = MakeBSPNode(process, scoreboard, planes, in, zone_count); Check_Object(node->insideNode); node->outsideNode = MakeBSPNode(process, scoreboard, planes, out, zone_count); Check_Object(node->outsideNode); return node; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void InterestBSP::SplitScene( SortInterestZonesProcess *process, SceneProxy *scene ) { Check_Object(this); Check_Object(process); Check_Object(scene); // //--------------------------------------- // Make sure that the process says its OK //--------------------------------------- // process->SplitCallback(scene); if (!process->continueProcess) return; // //---------------------------------------------------------------------- // We are not a leaf node, so find out how many children we need to test // against the BSP plane. If there are none, just return //---------------------------------------------------------------------- // unsigned child_count = scene->GetChildCount(); if (!child_count) return; // //-------------------------------------------------------------------- // If there are no children of this BSP node, we need to write out the // interest zone info //-------------------------------------------------------------------- // if (!insideNode && !outsideNode) { CreateInterestZone(process, scene); return; } // //------------------------------------------------------------------------ // Create the two new group nodes that the meshes will be sorted into, // then run through the original children and sort each one into the // appropriate set //------------------------------------------------------------------------ // GroupProxy *inside_set = scene->AppendNewGroupProxy(); Check_Object(inside_set); GroupProxy *outside_set = scene->AppendNewGroupProxy(); Check_Object(outside_set); ChildProxy *child = scene->UseFirstChildProxy(); for (unsigned i=0; iUseNextSiblingProxy(); if ( SplitMesh( process, Cast_Object(PolygonMeshProxy*, child), inside_set, outside_set ) ) child->DetachReference(); child = next; if (!process->continueProcess) break; } if (child) child->DetachReference(); if (!process->continueProcess) { inside_set->DetachReference(); outside_set->DetachReference(); return; } // //----------------------------------------------------------- // Now, split each group against the next lower BSP nodes //----------------------------------------------------------- // Check_Object(insideNode); if (insideNode->SplitGroup(process, inside_set)) inside_set->DetachReference(); if (!process->continueProcess) outside_set->DetachReference(); else { Check_Object(outsideNode); if (outsideNode->SplitGroup(process, outside_set)) outside_set->DetachReference(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool InterestBSP::SplitGroup( SortInterestZonesProcess *process, GroupProxy *group ) { Check_Object(this); Check_Object(process); Check_Object(group); // //--------------------------------------- // Make sure that the process says its OK //--------------------------------------- // process->SplitCallback(group); if (!process->continueProcess) return true; // //---------------------------------------------------------------------- // We are not a leaf node, so find out how many children we need to test // against the BSP plane. If there are none, just return //---------------------------------------------------------------------- // unsigned child_count = group->GetChildCount(); if (!child_count) { group->Destroy(); return false; } // //-------------------------------------------------------------------- // If there are no children of this BSP node, we need to write out the // interest zone info //-------------------------------------------------------------------- // if (!insideNode && !outsideNode) return CreateInterestZone(process, group); // //------------------------------------------------------------------------ // Create the two new group nodes that the meshes will be sorted into, // then run through the original children and sort each one into the // appropriate set //------------------------------------------------------------------------ // GroupProxy *inside_set = group->AppendNewGroupProxy(); Check_Object(inside_set); GroupProxy *outside_set = group->AppendNewGroupProxy(); Check_Object(outside_set); ChildProxy *child = group->UseFirstChildProxy(); for (unsigned i=0; iUseNextSiblingProxy(); if ( SplitMesh( process, Cast_Object(PolygonMeshProxy*, child), inside_set, outside_set ) ) child->DetachReference(); child = next; if (!process->continueProcess) break; } if (child) child->DetachReference(); if (!process->continueProcess) { inside_set->DetachReference(); outside_set->DetachReference(); return true; } // //----------------------------------------------------------- // Now, split each group against the next lower BSP nodes //----------------------------------------------------------- // Check_Object(insideNode); if (insideNode->SplitGroup(process, inside_set)) inside_set->DetachReference(); if (!process->continueProcess) outside_set->DetachReference(); else { Check_Object(outsideNode); if (outsideNode->SplitGroup(process, outside_set)) outside_set->DetachReference(); } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // static inline int Find_Side( Scalar distance, Scalar thickness ) { if (distance > thickness) return 1; else if (distance < -thickness) return -1; return 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool InterestBSP::SplitMesh( SortInterestZonesProcess *process, PolygonMeshProxy *mesh, GroupProxy *inside_set, GroupProxy *outside_set ) { Check_Object(this); Check_Object(mesh); Check_Object(inside_set); Check_Object(outside_set); // //--------------------------------------- // Make sure that the process says its OK //--------------------------------------- // process->SplitCallback(mesh); if (!process->continueProcess) return true; // //------------------------------------------------------------- // Rotate the separating plane into the local space of the mesh //------------------------------------------------------------- // LinearMatrix4D local_to_world; mesh->GetLocalToParent(&local_to_world); LinearMatrix4D world_to_local; world_to_local.Invert(local_to_world); Plane local_plane; local_plane.Multiply(dividingPlane, world_to_local); // //------------------------------------------------------------------------ // The first task is to find out which side of the plane the mesh is to // be on. We do this by looking at all the vertices and categorizing each // one //------------------------------------------------------------------------ // int type = 0; Scalar thickness = process->trimmingTolerance; DynamicArrayOf vertices; unsigned vertex_count = mesh->UseVertexArray(&vertices); unsigned i; VertexProxy *vertex; for (i=0; iGetPosition(&position); Scalar distance = local_plane.GetDistanceTo(position); if (distance < -thickness) type |= 1; else if (distance > thickness) type |= 2; if (type == 3) break; } mesh->DetachArrayReferences(&vertices); Verify(mesh->GetReferenceCount() == 1); // //------------------------------------------------------------------------- // Put the mesh in the correct bin based upon the index status. Make sure // to put empty or coplanar meshes on the inside mesh //------------------------------------------------------------------------- // if (type<2) { mesh->TransferAndAppendToParentGroup(inside_set); return true; } // //----------------------------------------------------------------------- // Case 2 means that the mesh fits totally outside the plane's half-space //----------------------------------------------------------------------- // else if (type==2) { mesh->TransferAndAppendToParentGroup(outside_set); return true; } // //------------------------------------------------------------------------- // If we get here, then we have to split the polygon mesh apart, so get the // list of polygons //------------------------------------------------------------------------- // Verify(type == 3); DynamicArrayOf old_polygons; unsigned old_polygon_count = mesh->UsePolygonArray(&old_polygons); // //--------------------------- // Create the polygon buffers //--------------------------- // DynamicArrayOf inside_polygons(old_polygon_count); unsigned inside_polygon_count = 0; DynamicArrayOf outside_polygons(old_polygon_count); unsigned outside_polygon_count = 0; DynamicArrayOf new_vertices(2*old_polygon_count); unsigned new_vertex_count = 0; // //----------------------------------------------------------------------- // Spin through the polygons, looking at each polygon to see if it can be // transferred as is to one side or the other //----------------------------------------------------------------------- // for (i=0; i old_indices; unsigned old_index_count = polygon->UseIndexArray(&old_indices); Verify(old_index_count >= 3); DynamicArrayOf distances(old_index_count); unsigned j; for (j=0; jGetVertexProxy(); Check_Object(vertex); Point3D position; vertex->GetPosition(&position); distances[j] = local_plane.GetDistanceTo(position); if (distances[j] < -thickness) type |= 1; else if (distances[j] > thickness) type |= 2; } // //----------------------------------------------------------------- // If the polygon is co-planar or inside, put it on the inside set //----------------------------------------------------------------- // if (type<2) { polygon->AttachReference(); inside_polygons[inside_polygon_count++] = polygon; polygon->DetachArrayReferences(&old_indices); continue; } // //----------------------------------------------------- // If the polygon is outside, put it on the outside set //----------------------------------------------------- // if (type==2) { polygon->AttachReference(); outside_polygons[outside_polygon_count++] = polygon; polygon->DetachArrayReferences(&old_indices); continue; } // //---------------------------------------------------------------------- // We have to split this polygon, which will basically mean that we will // build two new polygons, one per side //---------------------------------------------------------------------- // Verify(type==3); DynamicArrayOf inside_indices(old_index_count+1); unsigned inside_index_count = 0; DynamicArrayOf outside_indices(old_index_count+1); unsigned outside_index_count = 0; // //--------------------------- // Set up the trailing vertex //--------------------------- // Scalar distance_a = distances[old_index_count-1]; int side_a = Find_Side(distance_a, thickness); // //-------------------------- // Set up the testing vertex //-------------------------- // Scalar distance_b = distances[0]; int side_b = Find_Side(distance_b, thickness); Check_Object(old_indices[0]); VertexProxy *vertex_b = old_indices[0]->GetVertexProxy(); Check_Object(vertex_b); Point3D position_b; vertex_b->GetPosition(&position_b); // //-------------------------- // Set up the leading vertex //-------------------------- // unsigned lead_index = 1; Scalar distance_c = distances[lead_index]; int side_c = Find_Side(distance_c, thickness); Check_Object(old_indices[lead_index]); VertexProxy *vertex_c = old_indices[lead_index]->GetVertexProxy(); Check_Object(vertex_c); Point3D position_c; vertex_c->GetPosition(&position_c); // //------------------------- // Loop through the indices //------------------------- // Scalar welding = process->duplicateVertexTolerance; int crossings = 0; for (j=0; jGetVertexProxy(); Check_Object(vertex_c); vertex_c->GetPosition(&position_c); distance_c = distances[lead_index]; side_c = Find_Side(distance_c, thickness); } // //------------------------------------------------------------------- // Assign this vertex to either or both the inside or outside polygon // (it can go to both if it is on the plane //------------------------------------------------------------------- // if (side_b < 1) inside_indices[inside_index_count++] = vertex_b; if (side_b > -1) outside_indices[outside_index_count++] = vertex_b; // //------------------------------------------------ // Check to see if this index is a splitting index //------------------------------------------------ // Analyze_Vertex: if (!side_b && side_a && side_a == -side_c) { ++crossings; Verify(crossings < 3); side_a = side_b; } // //---------------------------------------------------------------- // Check to see if the edge from b to c needs to be split. If so, // calculate where the crossing would happen //---------------------------------------------------------------- // else if (side_b && side_b == -side_c) { Scalar lerp = distance_b / (distance_b - distance_c); Point3D position; position.Lerp(position_b, position_c, lerp); // //--------------------------------------------------------------- // Before we actually do the split, we need to make sure that new // vertex doesn't effectively duplicate either of the existing // vertices //--------------------------------------------------------------- // if ( Small_Enough(lerp) || Close_Enough(position, position_b, welding) ) { if (side_b > 0) inside_indices[inside_index_count++] = vertex_b; else outside_indices[outside_index_count++] = vertex_b; side_b = 0; distance_b = 0.0f; goto Analyze_Vertex; } else if ( Close_Enough(lerp, 1.0f) || Close_Enough(position, position_c, welding) ) { side_c = 0; distance_c = 0.0f; goto Analyze_Vertex; } // //---------------------- // Create the new vertex //---------------------- // vertex = VertexProxy::MakeProxy(); Check_Object(vertex); new_vertices[new_vertex_count++] = vertex; vertex->SetPosition(position); // //--------------- // Lerp the color //--------------- // RGBAColor color_b; if (vertex_b->GetColor(&color_b)) { RGBAColor color_c; #if defined(_ARMOR) bool result = #endif vertex_c->GetColor(&color_c); Verify(result); RGBAColor color; color.Lerp(color_b, color_c, lerp); vertex->SetColor(color); } // //--------------- // Lerp the color //--------------- // DynamicArrayOf > uv_b; if (vertex_b->GetUVs(&uv_b)) { DynamicArrayOf > uv_c; #if defined(_ARMOR) bool result = #endif vertex_c->GetUVs(&uv_c); Verify(result); Verify(uv_b.GetLength() == uv_c.GetLength()); DynamicArrayOf > uv; uv.SetLength(uv_b.GetLength()); for(unsigned uv_loop=0;uv_loopSetUVs(uv); } // //--------------- // Lerp the color //--------------- // Normal3D normal_b; if (vertex_b->GetNormal(&normal_b)) { Normal3D normal_c; #if defined(_ARMOR) bool result = #endif vertex_c->GetNormal(&normal_c); Verify(result); Normal3D normal; normal.Lerp(normal_b, normal_c, lerp); vertex->SetNormal(normal); } // //--------------------------------------- // Now, insert the vertex into both sides //--------------------------------------- // ++crossings; Verify(crossings < 3); inside_indices[inside_index_count++] = vertex; outside_indices[outside_index_count++] = vertex; side_a = 0; } } // //---------------------------------------------------------- // See if we actually ended up with a polygon on the outside //---------------------------------------------------------- // if (inside_index_count < 3) { Verify(outside_index_count >= 3); Move_It_Outside: polygon->AttachReference(); outside_polygons[outside_polygon_count++] = polygon; } // //--------------------------------------------------------- // See if we actually ended up with a polygon on the inside //--------------------------------------------------------- // else if (outside_index_count < 3) { Verify(inside_index_count >= 3); Move_It_Inside: polygon->AttachReference(); inside_polygons[inside_polygon_count++] = polygon; } // //------------------------------------------ // Construct the inside and outside polygons //------------------------------------------ // else { // //--------------------------------------------- // Make sure that the outside polygon isn't bad //--------------------------------------------- // Verify(outside_index_count >= 3); outside_indices.SetLength(outside_index_count); PolygonProxy *outside_polygon = PolygonProxy::MakeProxy(); Check_Object(outside_polygon); outside_polygon->SetPolygonIndices(outside_indices); if (outside_polygon->FindErrors(process->errorProcess) > 0) { outside_polygon->DetachReference(); goto Move_It_Inside; } // //-------------------------------------------- // Make sure that the inside polygon isn't bad //-------------------------------------------- // Verify(inside_index_count >= 3); inside_indices.SetLength(inside_index_count); PolygonProxy *inside_polygon = PolygonProxy::MakeProxy(); Check_Object(inside_polygon); inside_polygon->SetPolygonIndices(inside_indices); if (inside_polygon->FindErrors(process->errorProcess) > 0) { outside_polygon->DetachReference(); inside_polygon->DetachReference(); goto Move_It_Outside; } // //--------------------------------------------- // This is good, so actually setup both proxies //--------------------------------------------- // MultiState multi_state; polygon->UseMultiState(&multi_state); Check_Object(&multi_state); outside_polygon->SetStatesToMatch(multi_state); inside_polygon->SetStatesToMatch(multi_state); multi_state.DetachReferences(); outside_polygons[outside_polygon_count++] = outside_polygon; inside_polygons[inside_polygon_count++] = inside_polygon; } // //--------------------- // Clean up the polygon //--------------------- // polygon->DetachArrayReferences(&old_indices); } // //-------------------------------------------------- // See if we should just transfer the mesh after all //-------------------------------------------------- // bool destroy_mesh; if (!inside_polygon_count) { Verify(outside_polygon_count == old_polygon_count); mesh->TransferAndAppendToParentGroup(outside_set); destroy_mesh = false; } else if (!outside_polygon_count) { Verify(inside_polygon_count == old_polygon_count); mesh->TransferAndAppendToParentGroup(inside_set); destroy_mesh = false; } // //------------------------------------------------------ // Otherwise, create the new meshes and add the polygons //------------------------------------------------------ // else { PolygonMeshProxy *inside_mesh = inside_set->AppendNewPolygonMeshProxy(); Check_Object(inside_mesh); inside_polygons.SetLength(inside_polygon_count); inside_mesh->AddPolygons(process, inside_polygons); inside_mesh->DetachReference(); PolygonMeshProxy *outside_mesh = outside_set->AppendNewPolygonMeshProxy(); Check_Object(outside_mesh); outside_polygons.SetLength(outside_polygon_count); outside_mesh->AddPolygons(process, outside_polygons); outside_mesh->DetachReference(); destroy_mesh = true; } // //------------------------------------------------------------------------ // Clean up the buffer arrays. Passing NULL into the polygon detach array // function cleans up the abstract indices //------------------------------------------------------------------------ // for (i=0; iDetachReference(); for (i=0; iDetachReference(); for (i=0; iDetachReference(); // //------------------------------------ // This mesh may be no longer required //------------------------------------ // mesh->DetachArrayReferences(&old_polygons); Verify(mesh->GetReferenceCount() == 1); if (destroy_mesh) mesh->Destroy(); return !destroy_mesh; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool InterestBSP::CreateInterestZone( SortInterestZonesProcess *process, GenericProxy *proxy ) { Check_Object(this); Check_Object(process); Check_Object(proxy); // //--------------------------------------- // Make sure that the process says its OK //--------------------------------------- // process->CreateCallback(proxy); if (!process->continueProcess) return true; // //---------------------------------------------------------------------- // Create the node name for this interest zone, and assign it as the new // proxy name //---------------------------------------------------------------------- // MString zone_name = "iz"; char buffer[200]; _itoa(process->zoneCounter++, buffer, 10); zone_name += buffer; // //------------------------------------------------------------------------- // Get the centerpoint of the box, and then convert that to a linear // transform we can apply to the child meshes in order to get them centered // around the world origin //------------------------------------------------------------------------- // Check_Object(&process->zoneArray); const ExtentBox *box = &process->zoneArray[zoneIndex]; Check_Object(box); Point3D box_center; box->GetCenterpoint(&box_center); LinearMatrix4D box_to_world(box_center); LinearMatrix4D world_to_box; world_to_box.Invert(box_to_world); // //---------------------------------------------------------------------- // We need to see if we are working on a scene or group, and get the // proper child info from either //---------------------------------------------------------------------- // unsigned child_count; GroupProxy *basket; ChildProxy *child; GroupProxy *iz; if (proxy->IsDerivedFrom(GroupProxy::DefaultData)) { GroupProxy *group = Cast_Object(GroupProxy*, proxy); iz = group; child_count = group->GetChildCount(); basket = group->AppendNewGroupProxy(); child = group->UseFirstChildProxy(); iz->AttachReference(); } else { Verify(proxy->IsDerivedFrom(SceneProxy::DefaultData)); SceneProxy *scene = Cast_Object(SceneProxy*, proxy); child_count = scene->GetChildCount(); iz = scene->AppendNewGroupProxy(); basket = iz->AppendNewGroupProxy(); child = scene->UseFirstChildProxy(); } // //-------------------------------------------- // Name the basket and move each child into it //-------------------------------------------- // MString set_name = "floor"; set_name += buffer; iz->SetName(zone_name); basket->SetName(set_name); for (unsigned i=0; iUseNextSiblingProxy(); child->TransformLocalToParent(world_to_box); child->TransferAndAppendToParentGroup(basket); child->DetachReference(); child = next; } if (child) child->DetachReference(); // //------------------------------------------------------------------------ // Optimize the basket, and move it in the hierarchy to where it should be // viewed at //------------------------------------------------------------------------ // OptimizeBasket(process, basket); basket->SetLocalToParent(box_to_world); basket->DetachReference(); // //------------------------------------------------------------------------ // Now we need to generate the contents file for this interest zone. It // will specify a single entity which will try and hook up to the izset### // locator. //------------------------------------------------------------------------ // Check_Pointer(process->setDirectory); MString contents_name = process->setDirectory; contents_name += zone_name; contents_name += ".contents"; NotationFile contents_file; const char* page_name = "Floor"; Page *page = contents_file.SetPage(page_name); Check_Object(page); page->SetEntry("Model", "Floor.data"); char center_text[200]; sprintf(center_text, "%f %f %f", box_center.x, box_center.y, box_center.z); page->SetEntry("Translation", center_text); page->SetEntry("PreCollisionState", "NeverExecuteState"); page->SetEntry("PostCollisionState", "NeverExecuteState"); page->SetEntry("CollisionMask", "-1"); page->SetEntry("Collidee", "yes"); page->SetEntry("ParentedToInterestGraphFlag", "yes"); page->SetEntry("CanInterestFlag", "yes"); page->SetEntry("CulledInterestFlag", "yes"); MString locator_name = "\""; locator_name += set_name; locator_name += '"'; page->SetEntry("Locator", locator_name); contents_file.SaveAs(contents_name); // //----------------------------------------------------------------------- // Create the interest zone entry within the set contents file. The page // name will be InterestZone### //----------------------------------------------------------------------- // Check_Object(process->setContents); NotationFile *set_contents_file = process->setContents; page_name = zone_name; Page *set_page = set_contents_file->SetPage(page_name); Check_Object(set_page); set_page->SetEntry("Model", "InterestZone.data"); set_page->SetEntry("PreCollisionState", "NeverExecuteState"); set_page->SetEntry("PostCollisionState", "NeverExecuteState"); set_page->SetEntry("ParentedToInterestGraphFlag", "no"); set_page->SetEntry("CanInterestFlag", "yes"); set_page->SetEntry("CulledInterestFlag", "no"); // //------------------------------------------------------------------------ // Set up the locator the interest zone is to search for, put the box size // in ASCII, and finish the page //------------------------------------------------------------------------ // locator_name = "\""; locator_name += zone_name; locator_name += '"'; set_page->SetEntry("Locator", locator_name); set_page->SetEntry("ArmoryZoneFlag", "no"); sprintf( buffer, "%f,%f,%f,%f,%f,%f", box->minX, box->minY, box->minZ, box->maxX, box->maxY, box->maxZ ); set_page->SetEntry("Box", buffer); set_page->SetEntry("Contents", zone_name + ".contents"); // //---------------------------------------------------- // Hierarchy proxies must be discarded prior to return //---------------------------------------------------- // iz->DetachReference(); return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void InterestBSP::OptimizeBasket( SortInterestZonesProcess *process, GroupProxy *basket ) { Check_Object(this); Check_Object(process); Check_Object(basket); // //--------------------------- // Flatten out the transforms //--------------------------- // FlattenHierarchyProcess *flatten_hierarchy = process->MakeFlattenHierarchyProcess(process->configFile, basket); Check_Object(flatten_hierarchy); basket->FlattenHierarchy(flatten_hierarchy); Check_Object(flatten_hierarchy); delete flatten_hierarchy; // //-------------------------------------------------------------------------- // Now that all the children are split up by state, the next step is to fuse // polygon mesh children that have the same state //-------------------------------------------------------------------------- // unsigned child_count = basket->GetChildCount(); if (!child_count) return; // //--------------------------- // Set up the analysis arrays //--------------------------- // DynamicArrayOf meshes(child_count); DynamicArrayOf states(child_count); DynamicArrayOf > polygon_arrays(child_count); unsigned unique_states = 0; // //----------------------------------------------------------------- // Loop through each mesh looking for the proper state bin for each //----------------------------------------------------------------- // ChildProxy *child = basket->UseFirstChildProxy(); unsigned m, s; for (m=0; mUseNextSiblingProxy(); meshes[m] = Cast_Object(PolygonMeshProxy*, child); #if defined(_ARMOR) LinearMatrix4D test_matrix; Verify(!meshes[m]->GetLocalToParent(&test_matrix)); #endif // //------------------- // Find a state proxy //------------------- // DynamicArrayOf polygons; unsigned poly_count = meshes[m]->UsePolygonArray(&polygons); MultiState poly_states; polygons[0]->UseMultiState(&poly_states); // //------------------------------------------------------- // See if this state matches any of our previous children //------------------------------------------------------- // for (s=0; s0); // //------------------------------------------------------------------------ // Bucket sort each state separately. The state proxy was only needed for // the sorting, so we don't need it anymore //------------------------------------------------------------------------ // for (s=0; sDetachReferences(); basket->SortAndAddPolygons( process->sortProcess, polygon_arrays[s] ); meshes[s]->DetachArrayReferences(&polygon_arrays[s]); } // //---------------------- // Remove the old meshes //---------------------- // for (m=0; mGetReferenceCount() == 1); meshes[m]->Destroy(); } // //------------------------------------------------------------------------ // Now binsort everything. Since the meshes are already within the bucket // size, this will just create new groups to arrange them within //------------------------------------------------------------------------ // basket->BinSort(process->sortProcess); }