/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /////////////////////////////////////////////////////////////////////////////////////// // // GroupMgrClass.cpp // // Class definition for managing groups. // #include "stdafx.h" #include "groupmgr.h" #include "leveleditdoc.h" #include "cameramgr.h" #include "node.h" #include "sceneeditor.h" #include "utils.h" #include "wwmath.h" #include "waypointnode.h" #include "waypathnode.h" ///////////////////////////////////////////////////////////// // // Add_Node // ///////////////////////////////////////////////////////////// const GroupMgrClass & GroupMgrClass::operator= (const GroupMgrClass &src) { m_BoundingSphere = src.m_BoundingSphere; m_BoundingBox = src.m_BoundingBox; m_LowZCenter = src.m_LowZCenter; m_AbsCenter = src.m_AbsCenter; m_Name = src.m_Name; m_bDirty = src.m_bDirty; Free_List (); Import_Nodes (src.m_GroupList); // Return a reference to ourselves return *this; } ///////////////////////////////////////////////////////////// // // Export_Nodes // ///////////////////////////////////////////////////////////// void GroupMgrClass::Export_Nodes (NODE_LIST &node_list) { // // Add all the nodes from this group to the list // for (int index = 0; index < m_GroupList.Count (); index ++) { NodeClass *node = m_GroupList[index]; if (node != NULL) { node_list.Add_Unique (node); } } return ; } ///////////////////////////////////////////////////////////// // // Import_Nodes // ///////////////////////////////////////////////////////////// void GroupMgrClass::Import_Nodes (const NODE_LIST &node_list) { // Loop through all the entries in the list and add them // to our group. for (int index = 0; index < node_list.Count (); index ++) { Add_Node (node_list[index]); } return; } ///////////////////////////////////////////////////////////// // // Add_Node // ///////////////////////////////////////////////////////////// void GroupMgrClass::Add_Node (NodeClass *node) { if ((node != NULL) && (Is_Item_In_Group (node) == false)) { // // Add this item to the list // SAFE_ADD_REF (node); m_GroupList.Add (node); Recalc_Stats (); } return ; } ///////////////////////////////////////////////////////////// // // Remove_Node // ///////////////////////////////////////////////////////////// void GroupMgrClass::Remove_Node (NodeClass *node_to_remove) { bool found = false; for (int index = 0; !found && index < m_GroupList.Count (); index ++) { NodeClass *node = m_GroupList[index]; // // If this is the node we were looking for, then remove it // from the list and free our hold on it. // if (node == node_to_remove) { m_GroupList.Delete (index); MEMBER_RELEASE (node); found = true; } } if (found) { Recalc_Stats (); } return ; } ///////////////////////////////////////////////////////////// // // Reset // ///////////////////////////////////////////////////////////// void GroupMgrClass::Reset (void) { Free_List (); return ; } ///////////////////////////////////////////////////////////// // // Free_List // ///////////////////////////////////////////////////////////// void GroupMgrClass::Free_List (void) { for (int index = 0; index < m_GroupList.Count (); index ++) { NodeClass *node = m_GroupList[index]; MEMBER_RELEASE (node); } m_GroupList.Delete_All (); Recalc_Stats (); return ; } ///////////////////////////////////////////////////////////// // // Is_Item_In_Group // ///////////////////////////////////////////////////////////// bool GroupMgrClass::Is_Item_In_Group (NodeClass *node_to_find) { bool retval = false; // // Loop until we've found the node // for ( int index = 0; (retval == false) && (index < m_GroupList.Count ()); index ++) { NodeClass *node = m_GroupList[index]; retval = (node == node_to_find); } return retval; } ///////////////////////////////////////////////////////////// // // Clone_Group // ///////////////////////////////////////////////////////////// void GroupMgrClass::Clone_Group (void) { NODE_LIST temp_list; // // Duplicate the group list // for (int index = 0; index < m_GroupList.Count (); index ++) { NodeClass *node = m_GroupList[index]; temp_list.Add (node); } // Remove all items from the group m_GroupList.Delete_All (); // // Loop through and create clones of the items // for (index = 0; index < temp_list.Count (); index ++) { NodeClass *node = temp_list[index]; if (node->Get_Type () == NODE_TYPE_WAYPOINT) { // // Find where this waypoint is on the path // WaypointNodeClass *waypoint = (WaypointNodeClass *)node; WaypathNodeClass *path = waypoint->Peek_Waypath (); int index = path->Find_Index (waypoint); if (index >= 0) { // // Insert a new point one after the given point // path->Insert_Point (index + 1, waypoint->Get_Position ()); // // Add this new point to our group // WaypointNodeClass *new_point = NULL; path->Get_Point (index + 1, &new_point); if (new_point != NULL) { SAFE_ADD_REF (new_point); m_GroupList.Add (new_point); } } } else if (node->Get_Parent_Node () != NULL) { if (node->Get_Parent_Node ()->Can_Add_Child_Nodes ()) { // // Ask the parent node to create us a new child node, then add // it to the list // NodeClass *new_node = node->Get_Parent_Node ()->Add_Child_Node (node->Get_Transform ()); if (new_node != NULL) { SAFE_ADD_REF (new_node); m_GroupList.Add (new_node); } } } else { // // Create a new instance of this node, and add it to our list // NodeClass *new_node = ::Get_Scene_Editor ()->Clone_Node (node); if (new_node != NULL) { m_GroupList.Add (new_node); } } MEMBER_RELEASE (node); } Recalc_Stats (); return ; } ///////////////////////////////////////////////////////////// // // Recalc_Stats // ///////////////////////////////////////////////////////////// void GroupMgrClass::Recalc_Stats (void) { m_BoundingSphere.Init (Vector3 (0, 0, 0), 0); m_BoundingBox.Init (Vector3 (0, 0, 0), Vector3 (0, 0, 0)); m_LowZCenter = Vector3 (0, 0, 0); float low_z = WWMATH_FLOAT_MAX; // // Loop through all the nodes in the group // for (int index = 0; index < m_GroupList.Count (); index ++) { NodeClass *node = m_GroupList[index]; RenderObjClass *render_obj = node->Peek_Render_Obj (); if (render_obj != NULL) { if (index == 0) { m_BoundingBox = render_obj->Get_Bounding_Box (); m_BoundingSphere = render_obj->Get_Bounding_Sphere (); m_LowZCenter = render_obj->Get_Position (); low_z = m_LowZCenter.Z; } else { // // Add this node's stats to the pot // m_BoundingBox.Add_Box (render_obj->Get_Bounding_Box ()); m_BoundingSphere += render_obj->Get_Bounding_Sphere (); m_LowZCenter += render_obj->Get_Position (); if (render_obj->Get_Position ().Z < low_z) { low_z = render_obj->Get_Position ().Z; } } } } m_LowZCenter = m_LowZCenter / (float)m_GroupList.Count (); m_AbsCenter = m_LowZCenter; m_LowZCenter.Z = low_z; m_bDirty = false; return ; } ///////////////////////////////////////////////////////////// // // Hide // ///////////////////////////////////////////////////////////// void GroupMgrClass::Hide (bool hide) { // Loop through all the nodes in the group for (int index = 0; index < m_GroupList.Count (); index ++) { NodeClass *node = m_GroupList[index]; if (node != NULL) { // // Hide this node // node->Hide (hide); } } // Remember our 'state' m_bHidden = hide; return ; } //*********************************************************************************************// // // End of GroupMgrClass // //*********************************************************************************************// //*********************************************************************************************// // // Start of SelectionMgrClass // //*********************************************************************************************// ///////////////////////////////////////////////////////////// // // Add_Node // ///////////////////////////////////////////////////////////// void SelectionMgrClass::Add_Node (NodeClass *node) { if ((node != NULL) && (Is_Item_In_Group (node) == false)) { // // Show the selection box // node->Show_Selection_Box (true); } GroupMgrClass::Add_Node (node); return ; } ///////////////////////////////////////////////////////////// // // Remove_Node // ///////////////////////////////////////////////////////////// void SelectionMgrClass::Remove_Node (NodeClass *node) { // // Remove the selection box from this node // if (node != NULL) { node->Show_Selection_Box (false); } GroupMgrClass::Remove_Node (node); return ; } ///////////////////////////////////////////////////////////// // // Reset // ///////////////////////////////////////////////////////////// void SelectionMgrClass::Reset (void) { // Loop through all the nodes in the group for (int index = 0; index < m_GroupList.Count (); index ++) { NodeClass *node = m_GroupList[index]; if (node != NULL) { // // Remove the selection item from this node // node->Show_Selection_Box (false); } } GroupMgrClass::Reset (); return ; } ///////////////////////////////////////////////////////////// // // Clone_Group // ///////////////////////////////////////////////////////////// void SelectionMgrClass::Clone_Group (void) { // // Remove the selection box from around all the items // for (int index = 0; index < m_GroupList.Count (); index ++) { NodeClass *node = m_GroupList[index]; node->Show_Selection_Box (false); } // // Let the base class do the clone operation // GroupMgrClass::Clone_Group (); // // Show the selection box for all the cloned items // for (index = 0; index < m_GroupList.Count (); index ++) { NodeClass *node = m_GroupList[index]; node->Show_Selection_Box (true); } return ; } //*********************************************************************************************// // // End of GroupMgrClass // //*********************************************************************************************// //*********************************************************************************************// // // Start of UserGroupMgrClass // //*********************************************************************************************// ///////////////////////////////////////////////////////////// // // Recalc_Stats // ///////////////////////////////////////////////////////////// void UserGroupMgrClass::Recalc_Stats (void) { // Allow the base class to process this call GroupMgrClass::Recalc_Stats (); // Remove this group from the scene if its empty Update_Global_Group_List (); return ; } ///////////////////////////////////////////////////////////// // // Update_Global_Group_List // ///////////////////////////////////////////////////////////// void UserGroupMgrClass::Update_Global_Group_List (void) { if (m_GroupList.Count () == 0) { ::Get_Scene_Editor ()->Remove_Global_Group (this); } return ; } ///////////////////////////////////////////////////////////// // // Add_Node // ///////////////////////////////////////////////////////////// void UserGroupMgrClass::Add_Node (NodeClass *node) { GroupMgrClass::Add_Node (node); if (node != NULL) { } return ; } ///////////////////////////////////////////////////////////// // // Remove_Node // ///////////////////////////////////////////////////////////// void UserGroupMgrClass::Remove_Node (NodeClass *node) { bool in_list = Is_Item_In_Group (node); GroupMgrClass::Remove_Node (node); // OK to process? if (in_list && node != NULL) { } return ; } ///////////////////////////////////////////////////////////// // // ~UserGroupMgrClass // ///////////////////////////////////////////////////////////// UserGroupMgrClass::~UserGroupMgrClass (void) { return ; } //*********************************************************************************************// // // End of UserGroupMgrClass // //*********************************************************************************************//