586 lines
13 KiB
C++
586 lines
13 KiB
C++
/*
|
|
** 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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
|
|
//
|
|
//*********************************************************************************************//
|