This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Tools/LevelEdit/OverlapPage.cpp

466 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/>.
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : LevelEdit *
* *
* $Archive:: /Commando/Code/Tools/LevelEdit/OverlapPage.cpp $*
* *
* Author:: Patrick Smith *
* *
* $Modtime:: 4/11/00 5:48p $*
* *
* $Revision:: 3 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "stdafx.h"
#include "leveledit.h"
#include "OverlapPage.h"
#include "nodemgr.h"
#include "node.h"
#include "coltest.h"
#include "icons.h"
#include "cameramgr.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// Local constants
/////////////////////////////////////////////////////////////////////////////
static const int TOOLBAR_HEIGHT = 25;
static const int TOOLBAR_V_SPACING = 5;
static const int TOOLBAR_V_BORDER = TOOLBAR_V_SPACING * 2;
static const int TOOLBAR_H_SPACING = 5;
static const int TOOLBAR_H_BORDER = TOOLBAR_H_SPACING * 2;
/////////////////////////////////////////////////////////////////////////////
//
// OverlapPageClass
//
/////////////////////////////////////////////////////////////////////////////
OverlapPageClass::OverlapPageClass(CWnd* pParent /*=NULL*/)
: CDialog(OverlapPageClass::IDD, pParent),
m_SoundsRoot (NULL),
m_LightsRoot (NULL)
{
//{{AFX_DATA_INIT(OverlapPageClass)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
Create (OverlapPageClass::IDD, pParent);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// ~OverlapPageClass
//
/////////////////////////////////////////////////////////////////////////////
OverlapPageClass::~OverlapPageClass (void)
{
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// DoDataExchange
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::DoDataExchange (CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(OverlapPageClass)
DDX_Control(pDX, IDC_OVERLAP_TREE, m_TreeCtrl);
//}}AFX_DATA_MAP
return ;
}
BEGIN_MESSAGE_MAP(OverlapPageClass, CDialog)
//{{AFX_MSG_MAP(OverlapPageClass)
ON_NOTIFY(TVN_DELETEITEM, IDC_OVERLAP_TREE, OnDeleteitemOverlapTree)
ON_WM_SIZE()
ON_WM_DESTROY()
ON_COMMAND(IDC_REFRESH, OnRefresh)
ON_NOTIFY(NM_DBLCLK, IDC_OVERLAP_TREE, OnDblclkOverlapTree)
ON_NOTIFY(TVN_ITEMEXPANDED, IDC_OVERLAP_TREE, OnItemexpandedOverlapTree)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//
// OnSize
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnSize
(
UINT nType,
int cx,
int cy
)
{
// Allow the base class to process this message
CDialog::OnSize (nType, cx, cy);
if (::IsWindow (m_TreeCtrl) && (cx > 0) && (cy > 0)) {
// Get the bounding rectangle of the form window
CRect parentrect;
GetWindowRect (&parentrect);
// Get the bounding rectangle of the toolbar
CRect toolbar_rect;
m_Toolbar.GetWindowRect (&toolbar_rect);
ScreenToClient (&toolbar_rect);
// Move the toolbar so it is in its correct position
m_Toolbar.SetWindowPos (NULL,
TOOLBAR_H_SPACING,
(cy - TOOLBAR_V_SPACING) - toolbar_rect.Height (),
cx - TOOLBAR_H_BORDER,
toolbar_rect.Height (),
SWP_NOZORDER);
// Get the bounding rectnagle of the list ctrl
RECT list_rect;
m_TreeCtrl.GetWindowRect (&list_rect);
CRect client_rect = list_rect;
ScreenToClient (&client_rect);
int list_height = ((cy - TOOLBAR_V_BORDER) - toolbar_rect.Height ()) - client_rect.top;
// Resize the tab control to fill the entire contents of the client area
m_TreeCtrl.SetWindowPos ( NULL,
0,
0,
cx-((list_rect.left - parentrect.left) << 1),
list_height,
SWP_NOZORDER | SWP_NOMOVE);
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnDestroy
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnDestroy (void)
{
// Free the state image list we associated with the control
CImageList *imagelist = m_TreeCtrl.GetImageList (TVSIL_STATE);
m_TreeCtrl.SetImageList (NULL, TVSIL_STATE);
SAFE_DELETE (imagelist);
// Remove the main image list we associated with the control
m_TreeCtrl.SetImageList (NULL, TVSIL_NORMAL);
m_TreeCtrl.DeleteAllItems ();
::RemoveProp (m_TreeCtrl, "TRANS_ACCS");
::RemoveProp (m_hWnd, "TRANS_ACCS");
// Allow the base class to process this message
CDialog::OnDestroy ();
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// OnInitDialog
//
////////////////////////////////////////////////////////////////////////////
BOOL
OverlapPageClass::OnInitDialog (void)
{
CDialog::OnInitDialog ();
m_Toolbar.CreateEx (this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP, CRect(0, 0, 0, 0), 101);
m_Toolbar.SetOwner (this);
m_Toolbar.LoadToolBar (IDR_OVERLAP_TOOLBAR);
m_Toolbar.SetBarStyle (m_Toolbar.GetBarStyle () | CBRS_TOOLTIPS | CBRS_FLYBY);
//
// Size the toolbar
//
CRect parentrect;
GetWindowRect (&parentrect);
m_Toolbar.SetWindowPos (NULL, 0, 0, parentrect.Width () - TOOLBAR_H_BORDER, TOOLBAR_HEIGHT, SWP_NOZORDER | SWP_NOMOVE);
//
// Pass the general use imagelist onto the tree control
//
m_TreeCtrl.SetImageList (::Get_Global_Image_List (), TVSIL_NORMAL);
SetProp (m_TreeCtrl, "TRANS_ACCS", (HANDLE)1);
SetProp (m_hWnd, "TRANS_ACCS", (HANDLE)1);
Reset_Tree ();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnDeleteitemOverlapTree
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnDeleteitemOverlapTree
(
NMHDR * pNMHDR,
LRESULT *pResult
)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
(*pResult) = 0;
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Build_Tree
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::Build_Tree (void)
{
Reset_Tree ();
//
// Fill the sub-nodes
//
Detect_Overlaps (m_SoundsRoot, NODE_TYPE_SOUND);
Detect_Overlaps (m_LightsRoot, NODE_TYPE_LIGHT);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Reset_Tree
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::Reset_Tree (void)
{
m_TreeCtrl.DeleteAllItems ();
//
// Insert the root nodes
//
m_SoundsRoot = m_TreeCtrl.InsertItem ("Sounds", FOLDER_ICON, FOLDER_ICON);
m_LightsRoot = m_TreeCtrl.InsertItem ("Lights", FOLDER_ICON, FOLDER_ICON);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Detect_Overlaps
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::Detect_Overlaps (HTREEITEM root_item, NODE_TYPE node_type)
{
//
// Loop over each node (of the given type) in the world
//
NodeClass *node1 = NULL;
for ( node1 = NodeMgrClass::Get_First (node_type);
node1 != NULL;
node1 = NodeMgrClass::Get_Next (node1, node_type))
{
//
// Check this node against every other node (of the sametype) in the world
//
HTREEITEM tree_item = NULL;
NodeClass *node2 = NULL;
for ( node2 = NodeMgrClass::Get_First (node_type);
node2 != NULL;
node2 = NodeMgrClass::Get_Next (node2, node_type))
{
if (node1 != node2) {
SphereClass sphere1 (node1->Get_Position (), node1->Get_Attenuation_Radius ());
SphereClass sphere2 (node2->Get_Position (), node2->Get_Attenuation_Radius ());
//
// Do these spheres intersect?
//
if (CollisionMath::Overlap_Test (sphere1, sphere2) != CollisionMath::OUTSIDE) {
//
// Add a tree entry for this node (if necessary)
//
if (tree_item == NULL) {
tree_item = Insert_Node (root_item, node1);
}
//
// Add this node as a sub-entry under the tree
//
Insert_Node (tree_item, node2);
}
}
}
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Insert_Node
//
/////////////////////////////////////////////////////////////////////////////
HTREEITEM
OverlapPageClass::Insert_Node (HTREEITEM parent_item, NodeClass *node)
{
//
// Add this node to the tree
//
int icon_index = node->Get_Icon_Index ();
HTREEITEM tree_item = m_TreeCtrl.InsertItem ( node->Get_Name (),
icon_index,
icon_index,
parent_item);
//
// Save the node's ID with the tree entry so we can look it up later...
//
if (tree_item != NULL) {
m_TreeCtrl.SetItemData (tree_item, node->Get_ID ());
}
return tree_item;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnRefresh
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnRefresh (void)
{
Build_Tree ();
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// OnDblclkOverlapTree
//
////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnDblclkOverlapTree
(
NMHDR * pNMHDR,
LRESULT * pResult
)
{
//
// Determine what client-coord location was double-clicked on
//
DWORD mouse_pos = ::GetMessagePos ();
POINT hit_point = { GET_X_LPARAM (mouse_pos), GET_Y_LPARAM (mouse_pos) };
m_TreeCtrl.ScreenToClient (&hit_point);
//
// Goto the node that was double-clicked on (if possible)
//
UINT flags = 0;
HTREEITEM tree_item = m_TreeCtrl.HitTest (hit_point, &flags);
if (tree_item != NULL && flags & TVHT_ONITEMLABEL) {
//
// Lookup the node from its ID
//
int node_id = m_TreeCtrl.GetItemData (tree_item);
NodeClass *node = NodeMgrClass::Find_Node (node_id);
if (node != NULL) {
//
// Reposition the camera so its looking at the node
//
::Get_Camera_Mgr ()->Goto_Node (node);
}
}
(*pResult) = 0;
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// OnItemexpandedOverlapTree
//
////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnItemexpandedOverlapTree
(
NMHDR * pNMHDR,
LRESULT * pResult
)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
//
// If this is a folder, then change its image based
// on its expanded state.
//
uint32 node_id = m_TreeCtrl.GetItemData (pNMTreeView->itemNew.hItem);
if (node_id == 0) {
if (pNMTreeView->itemNew.state & TVIS_EXPANDED) {
m_TreeCtrl.SetItemImage (pNMTreeView->itemNew.hItem, OPEN_FOLDER_ICON, OPEN_FOLDER_ICON);
} else {
m_TreeCtrl.SetItemImage (pNMTreeView->itemNew.hItem, FOLDER_ICON, FOLDER_ICON);
}
}
(*pResult) = 0;
return ;
}