/*
** 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 .
*/
/***********************************************************************************************
*** 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/SceneEditor.cpp $*
* *
* Author:: Patrick Smith *
* *
* $Modtime:: 3/12/02 3:31p $*
* *
* $Revision:: 116 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "stdafx.h"
#include "sceneeditor.h"
#include "nodemgr.h"
#include "groupmgr.h"
#include "utils.h"
#include "matrix3d.h"
#include "vector.h"
#include "leveleditdoc.h"
#include "filemgr.h"
#include "cameramgr.h"
#include "leveleditview.h"
#include "hittestinfo.h"
#include "collisiongroups.h"
#include "mainfrm.h"
#include "wwaudio.h"
#include "audiblesound.h"
#include "mesh.h"
#include "staticphys.h"
#include "phys3.h"
#include "_assetmgr.h"
#include "editorassetmgr.h"
#include "humanphys.h"
#include "pathfindsectorbuilder.h"
#include "pathfind.h"
#include "node.h"
#include "mover.h"
#include "nodefunction.h"
#include "chunkio.h"
#include "decophys.h"
#include "VisPointNode.h"
#include "editorchunkids.h"
#include "presetmgr.h"
#include "combat.h"
#include "ccamera.h"
#include "visenum.h"
#include "staticaabtreecull.h"
#include "dynamicaabtreecull.h"
#include "soundscene.h"
#include "backgroundmgr.h"
#include "texture.h"
#include "smartgameobj.h"
#include "objectnode.h"
#include "mousemgr.h"
#include "lightnode.h"
#include "light.h"
#include "euler.h"
#include "w3d_file.h"
#include "part_emt.h"
#include "gameobjmanager.h"
#include "selectpresetdialog.h"
#include "actionparams.h"
#include "generatingvisdialog.h"
#include "generatingedgesampledvisdialog.h"
#include "generatinglightvisdialog.h"
#include "visgenprogress.h"
#include "vissectorsampler.h"
#include "vismgr.h"
#include "generatingmanualvisdialog.h"
#include "heightdb.h"
#include "staticanimphys.h"
#include "conversationmgr.h"
#include "building.h"
#include "buildingnode.h"
#include "vistable.h"
#include "rendobj.h"
#include "pscene.h"
#include "leveledit.h"
#include "visrendercontext.h"
#include "mapmgr.h"
#include "editableheightfield.h"
#include "heightfieldeditor.h"
#include "heightfieldmgr.h"
#include "pathmgr.h"
//////////////////////////////////////////////////////////////////////
//
// SceneEditorClass
//
//////////////////////////////////////////////////////////////////////
SceneEditorClass::SceneEditorClass (void)
: m_SelectionMgr (NULL),
m_bLightsOn (true),
m_bAggregateChildrenVisible (true),
m_bVisPointsDisplayed (0),
m_TotalVisPoints (0),
m_ManualVisPointsVisible (true),
m_MovingObject (NULL),
m_DisplaySoundSpheres (false),
m_DisplayLightSpheres (false),
m_ShowStaticAnimPhys (true),
m_ShowEditorObjects (true),
m_BuildingPowerEnabled (true),
m_CreateProxies (true),
PhysicsSceneClass ()
{
//
// Ensure that we are initialized
//
Initialize ();
//
// Set some default light settings
//
Enable_Sun_Light (true);
Set_Ambient_Light (Vector3 (0.3F, 0.3F, 0.3F));
Set_Sun_Light_Orientation (0.0F, DEG_TO_RADF (50.0F));
Update_Lighting ();
return ;
}
//////////////////////////////////////////////////////////////////////
//
// ~SceneEditorClass
//
//////////////////////////////////////////////////////////////////////
SceneEditorClass::~SceneEditorClass (void)
{
Empty_Local_Clipboard ();
Cleanup_Resources ();
Remove_All_Vis_Points ();
return ;
}
//////////////////////////////////////////////////////////////////////
//
// Initialize
//
//////////////////////////////////////////////////////////////////////
void
SceneEditorClass::Initialize (void)
{
//
// Load the lighting mode from the registry
//
int prelit_mode = theApp.GetProfileInt ("Config", "PrelitMode", WW3D::PRELIT_MODE_LIGHTMAP_MULTI_PASS);
WW3D::Set_Prelit_Mode ((WW3D::PrelitModeEnum)prelit_mode);
//
// Initialize some misc variables
//
ParticleEmitterClass::Set_Default_Remove_On_Complete (false);
Cleanup_Resources ();
m_ManualVisPointsVisible = true;
m_BuildingPowerEnabled = true;
PathfindClass::Get_Instance ()->Reset_Sectors ();
//
// Create the node and selection managers
//
m_SelectionMgr = new SelectionMgrClass;
//
// Reset our undo stack
//
m_UndoMgr.Purge_Buffers ();
//
// Set-up our collision groups
//
Disable_All_Collision_Detections (EDITOR_COLLISION_GROUP);
Disable_All_Collision_Detections (DEF_COLLISION_GROUP);
Enable_Collision_Detection (DEF_COLLISION_GROUP, DEF_COLLISION_GROUP);
Enable_All_Collision_Detections (MOUSE_CLICK_COLLISION_GROUP);
Enable_All_Collision_Detections (15);
Disable_All_Collision_Detections (STATIC_OBJ_COLLISION_GROUP);
Enable_Collision_Detection (STATIC_OBJ_COLLISION_GROUP, 15);
Disable_Collision_Detection (MOUSE_CLICK_COLLISION_GROUP, 15);
Enable_All_Collision_Detections (GAME_COLLISION_GROUP);
Disable_Collision_Detection (GAME_COLLISION_GROUP, EDITOR_COLLISION_GROUP);
//
// Refresh the per-level include file list
//
STRING_LIST &level_includes =::Get_File_Mgr ()->Get_Include_File_List ();
level_includes.Delete_All ();
//
// Reset the pathfind data
//
PathfindClass::Get_Instance ()->Reset_Sectors ();
PathfindClass::Get_Instance ()->Reset_Portals ();
//
// Reset the list of conversations
//
ConversationMgrClass::Reset_Conversations (ConversationMgrClass::CATEGORY_LEVEL, true);
//
// Reset the map
//
MapMgrClass::Set_Map_Title (0);
MapMgrClass::Set_Map_Texture ("");
MapMgrClass::Set_Map_Center (Vector2 (0.0F, 0.0F));
MapMgrClass::Set_Map_Scale (Vector2 (0.0F, 0.0F));
MapMgrClass::Cloud_All_Cells ();
//
// Initialize the heightfield system
//
HeightfieldMgrClass::Initialize ();
HeightfieldEditorClass::Initialize ();
return ;
}
//////////////////////////////////////////////////////////////////////
//
// Cleanup_Resources
//
//////////////////////////////////////////////////////////////////////
void
SceneEditorClass::Cleanup_Resources (void)
{
//
// Free the background sound
//
if (WWAudioClass::Get_Instance () != NULL) {
WWAudioClass::Get_Instance ()->Set_Background_Music (NULL);
}
//
// Cleanup the different managers
//
m_UndoMgr.Purge_Buffers ();
SAFE_DELETE (m_SelectionMgr);
NodeMgrClass::Free_Nodes ();
NetworkObjectMgrClass::Delete_Pending ();
// Remove all entries from the group list
Reset_Global_Groups_List ();
m_MovingObject = NULL;
//
// Shutdown the heightfield system
//
HeightfieldEditorClass::Shutdown ();
HeightfieldMgrClass::Shutdown ();
return ;
}
//////////////////////////////////////////////////////////////////////
//
// Create_Node
//
//////////////////////////////////////////////////////////////////////
NodeClass *
SceneEditorClass::Create_Node
(
PresetClass * preset,
Matrix3D * transform,
DWORD node_id,
bool add_to_scene
)
{
::Get_Main_View ()->Allow_Repaint (false);
CWaitCursor wait_cursor;
//
// Create the new node
//
NodeClass *node = NodeMgrClass::Create_Node (preset, node_id);
ASSERT (node != NULL);
if (node != NULL) {
//
// Find a good starting position for this node in the scene
//
if (transform != NULL) {
node->Set_Transform (*transform);
} else {
MoverClass::Position_Node (node);
}
//
// Add the new node to the scene
//
if (add_to_scene) {
node->Add_To_Scene ();
}
//
// Update the file manager's database
//
Update_File_Mgr (node);
//
// Repartition the static culling systems if we are dropping
// in a terrain.
//
if (node->Get_Type () == NODE_TYPE_TERRAIN) {
Re_Partition_Static_Lights ();
Re_Partition_Audio_System ();
} else if (node->Get_Type () == NODE_TYPE_WAYPATH) {
::Get_Mouse_Mgr ()->Set_Mouse_Mode (MouseMgrClass::MODE_WAYPATH_EDIT);
MMWaypathEditClass *mode = (MMWaypathEditClass *)::Get_Mouse_Mgr ()->Get_Mode_Mgr ();
if (mode != NULL) {
mode->Set_Waypath ((WaypathNodeClass *)node);
}
}
//
// Create any linked nodes and put them into the scene
//
if (preset != NULL) {
preset->Create_Linked_Nodes (node);
}
//
// Release our hold on the node
//
node->Release_Ref ();
}
Set_Modified (true);
::Get_Main_View ()->Allow_Repaint (true);
return node;
}
//////////////////////////////////////////////////////////////////////
//
// Clone_Node
//
//////////////////////////////////////////////////////////////////////
NodeClass *
SceneEditorClass::Clone_Node (NodeClass *node)
{
NodeClass *new_node = node->Clone ();
if (new_node != NULL) {
//
// Make sure the new node has a name and ID
//
NodeMgrClass::Setup_Node_Identity (*new_node);
NodeMgrClass::Add_Node (new_node);
//
// Add the new node to the scene
//
new_node->Add_To_Scene ();
//
// Update the file manager's database
//
Update_File_Mgr (new_node);
}
return new_node;
}
//////////////////////////////////////////////////////////////////////
//
// Reload_Lightmap_Models
//
//////////////////////////////////////////////////////////////////////
void
SceneEditorClass::Reload_Lightmap_Models (void)
{
//
// Save the setting in the registry
//
theApp.WriteProfileInt ("Config", "PrelitMode", WW3D::Get_Prelit_Mode ());
//
// Force free the assets...
//
WW3DAssetManager::Get_Instance ()->Free_Assets ();
//
// Reload the necessary "tool" assets
//
CLevelEditDoc *doc = ::Get_Current_Document ();
if (doc != NULL) {
doc->Preload_Human_Data ();
doc->Preload_Tool_Assets ();
}
//
// Reload all the nodes
//
NodeMgrClass::Reload_Nodes ();
//
// Make sure we don't toss vis
//
Validate_Vis ();
return ;
}
//////////////////////////////////////////////////////////////////////
//
// Add_Node
//
//////////////////////////////////////////////////////////////////////
void
SceneEditorClass::Add_Node (NodeClass *node)
{
NodeMgrClass::Add_Node (node);
node->Add_To_Scene ();
Update_File_Mgr (node);
return ;
}
//////////////////////////////////////////////////////////////////////
//
// Delete_Node
//
//////////////////////////////////////////////////////////////////////
bool
SceneEditorClass::Delete_Node (NodeClass *node, bool allow_undo)
{
// Add this operation to our undo manager
if (allow_undo) {
Begin_Operation (OPERATION_DELETE, node);
}
//
// Remove all files that this node was dependent on from the file manager's list
//
Update_File_Mgr (node, false);
//
// Remove the node from the level
//
node->Remove_From_Scene ();
node->Show_Selection_Box (false);
node->On_Delete ();
NodeMgrClass::Remove_Node (node);
// Notify the undo manager that this operation is over
if (allow_undo) {
End_Operation ();
}
Set_Modified (true);
return true;
}
//////////////////////////////////////////////////////////////////////
//
// Delete_Nodes
//
//////////////////////////////////////////////////////////////////////
bool
SceneEditorClass::Delete_Nodes (PresetClass *preset)
{
bool retval = true;
//
// Build a list of nodes to that are dependent on this preset
//
DynamicVectorClass node_removal_list;
for ( NodeClass *node = NodeMgrClass::Get_First ();
node != NULL;
node = NodeMgrClass::Get_Next (node))
{
if (node->Get_Preset () == preset) {
node_removal_list.Add (node);
}
}
//
// Remove these nodes from the level
//
for (int index = 0; index < node_removal_list.Count (); index ++) {
retval &= Delete_Node (node_removal_list[index], false);
}
return retval;
}
//////////////////////////////////////////////////////////////////////
//
// Update_File_Mgr
//
//////////////////////////////////////////////////////////////////////
void
SceneEditorClass::Update_File_Mgr
(
NodeClass * node,
bool add_node
)
{
::Get_File_Mgr ()->Update (node, add_node);
return ;
}
//////////////////////////////////////////////////////////////////////
//
// Clone_Objects
//
//////////////////////////////////////////////////////////////////////
bool
SceneEditorClass::Clone_Objects (void)
{
m_SelectionMgr->Clone_Group ();
//
// Loop through all the objects in the current selection
// and update the file manager's information based on them
//
int count = m_SelectionMgr->Get_Count ();
for (int index = 0; index < count; index ++) {
NodeClass *node = m_SelectionMgr->Get_At (index);
Update_File_Mgr (node);
}
Set_Modified ();
return true;
}
//////////////////////////////////////////////////////////////////////
//
// Add_Groups_To_List
//
//////////////////////////////////////////////////////////////////////
void
SceneEditorClass::Add_Groups_To_List
(
NodeClass & node,
GROUP_LIST &group_list
)
{
/*group_list += node.Get_Groups ();
// Loop through all the children of this node and
// add their groups to the list as well
for (NodeInstanceClass *child = node.Get_Child ();
child != NULL;
child = child->Get_Sibling ()) {
Add_Groups_To_List (*child, group_list);
}*/
return ;
}
//////////////////////////////////////////////////////////////////////
//
// Build_Group_List
//
//////////////////////////////////////////////////////////////////////
void
SceneEditorClass::Build_Group_List
(
GROUP_LIST & group_list,
NodeClass * node
)
{
if (node != NULL) {
Add_Groups_To_List (*node, group_list);
} else {
//
// Loop through all the objects in the current selection
// and add thier groups to this list
//
for (int index = 0; index < m_SelectionMgr->Get_Count (); index ++) {
NodeClass *node = m_SelectionMgr->Get_At (index);
if (node != NULL) {
Add_Groups_To_List (*node, group_list);
}
}
}
return ;
}
//////////////////////////////////////////////////////////////////////
//
// Add_Nodes_To_List
//
//////////////////////////////////////////////////////////////////////
void
SceneEditorClass::Add_Nodes_To_List
(
NodeClass &node,
NODE_LIST &node_list
)
{
//
// Loop through all the children of this node and
// add them and their children to the list as well
//
/*for (NodeInstanceClass *child = node.Get_Child ();
child != NULL;
child = child->Get_Sibling ()) {
if (child->Is_Owner_Only () == false) {
node_list.Add_Unique (child);
}
Add_Nodes_To_List (*child, node_list);
}*/
return ;
}
//////////////////////////////////////////////////////////////////////
//
// Build_Node_List
//
//////////////////////////////////////////////////////////////////////
Vector3
SceneEditorClass::Build_Node_List (NODE_LIST &node_list)
{
//
// Add all the nodes from the selection set to the list
//
for (int index = 0; index < m_SelectionMgr->Get_Count (); index ++) {
NodeClass *node = m_SelectionMgr->Get_At (index);
if (node != NULL) {
node_list.Add_Unique (node);
}
}
m_SelectionMgr->Set_Dirty ();
return m_SelectionMgr->Get_Center ();
}
//////////////////////////////////////////////////////////////////////
//
// Build_Node_List
//
//////////////////////////////////////////////////////////////////////
void
SceneEditorClass::Build_Node_List
(
NODE_LIST & node_list,
NodeClass * parent_node
)
{
//
// Build a complete list of all the groups in the selection set
//
GROUP_LIST group_list;
Build_Group_List (group_list, parent_node);
// Loop through all the objects of all the groups in the selection
// set and add them to the list
for (int group = 0; group < group_list.Count (); group ++) {
GroupMgrClass *group_mgr = group_list[group];
group_mgr->Set_Dirty ();
for (int index = 0; index < group_mgr->Get_Count (); index ++) {
NodeClass *node = group_mgr->Get_At (index);
if (node != NULL) {
node_list.Add_Unique (node);
Add_Nodes_To_List (*node, node_list);
}
}
}
//
// Don't forget to add the nodes from the selection group as well!
//
if (parent_node == NULL) {
for (int index = 0; index < m_SelectionMgr->Get_Count (); index ++) {
NodeClass *node = m_SelectionMgr->Get_At (index);
if (node != NULL) {
node_list.Add_Unique (node);
Add_Nodes_To_List (*node, node_list);
}
}
} else {
/*if (parent_node->Is_Owner_Only () == false) {
node_list.Add_Unique (pparent_node);
}
Add_Nodes_To_List (*pparent_node, node_list);*/
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Delete_Nodes
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::Delete_Nodes (void)
{
NODE_LIST affected_list;
//
// Build a list of all the nodes that are affected by this operation
//
for (int index = 0; index < m_SelectionMgr->Get_Count (); index ++) {
NodeClass *node = m_SelectionMgr->Get_At (index);
if (node != NULL) {
// Add this node to our list of affected nodes
affected_list.Add_Unique (node);
}
}
// Add this operation to our undo manager
Begin_Operation (OPERATION_DELETE, &affected_list);
//
// Perfrom the actual delete operation
//
for (index = 0; index < affected_list.Count (); index ++) {
Delete_Node (affected_list[index], false);
}
// Notify the undo manager that this operation is over
End_Operation ();
// Reset the contents of the selection.
// Note: We create a temporary group here to keep a refcount
// locked on the selected nodes while we delete the selection group.
// Remember, freeing the selection group decrements the node's refcounts.
//GroupMgrClass temp_group = *m_SelectionMgr;
m_SelectionMgr->Free_List ();
return ;
}
///////////////////////////////////////////////////////////////
//
// Set_Selection
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::Set_Selection (NodeClass *node)
{
// Is this item already in the list?
if (m_SelectionMgr->Is_Item_In_Group (node) == false) {
//
// Make this node the only selected node
//
m_SelectionMgr->Reset ();
m_SelectionMgr->Add_Node (node);
Update_Toolbars ();
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Toggle_Selection
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::Toggle_Selection (NodeClass *node)
{
//
// If this node isn't already in the selection set, then
// add it. However, if its in the selection set, remove it.
//
if (m_SelectionMgr->Is_Item_In_Group (node)) {
m_SelectionMgr->Remove_Node (node);
} else {
m_SelectionMgr->Add_Node (node);
}
Update_Toolbars ();
return ;
}
///////////////////////////////////////////////////////////////
//
// Update_Toolbars
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::Update_Toolbars (void)
{
bool show_ani_toolbar = false;
int frame = 0;
int max_frames = 0;
if (m_SelectionMgr->Get_Count () > 0) {
//
// Loop through all the objects in the current selection
// and output their names to the debug window...
//
CString selection_set = "Selection set: ";
int sel_count = min (m_SelectionMgr->Get_Count (), 4);
for (int index = 0; index < sel_count; index ++) {
NodeClass *node = m_SelectionMgr->Get_At (index);
selection_set += node->Get_Name ();
//
// Print vis-id and occluder status if we're only printing one object
//
PhysClass *phys_obj = node->Peek_Physics_Obj ();
if (m_SelectionMgr->Get_Count () == 1 && phys_obj != NULL) {
StaticPhysClass *static_phys_obj = phys_obj->As_StaticPhysClass();
if (static_phys_obj != NULL) {
selection_set += (" (");
CString visid_string;
visid_string.Format(" VisObjectId = %d, ",static_phys_obj->Get_Vis_Object_ID());
selection_set += visid_string;
visid_string.Format(" VisSectorId = %d, ",static_phys_obj->Get_Vis_Sector_ID());
selection_set += visid_string;
AABTreeLinkClass *link = (AABTreeLinkClass *)static_phys_obj->Get_Cull_Link ();
if (link != NULL) {
visid_string.Format(" CullLink = %d, ",link->Node->Index);
selection_set += visid_string;
}
if (!static_phys_obj->Is_Occluder()) {
selection_set += CString(" Non-Occluder ");
}
selection_set += (")");
} else if (node->Get_Type () == NODE_TYPE_LIGHT) {
selection_set += (" (");
CString visid_string;
visid_string.Format(" VisSectorId = %d, ",((LightNodeClass *)node)->Get_Vis_Sector_ID());
selection_set += visid_string;
selection_set += (")");
} else {
selection_set += (" (");
CString visid_string;
visid_string.Format(" VisObjectId = %d, ",phys_obj->Get_Vis_Object_ID());
selection_set += visid_string;
selection_set += (")");
}
}
selection_set += ", ";
}
if (sel_count < m_SelectionMgr->Get_Count ()) {
selection_set += "and many more....";
}
//
// Now output this string to the debug window
//
selection_set += "\r\n";
::Output_Message (selection_set);
}
// Show/hide the animation toolbar depending on the current state
CMainFrame *pmainwnd = (CMainFrame *)::AfxGetMainWnd ();
if (pmainwnd != NULL) {
pmainwnd->Show_Ani_Toolbar (show_ani_toolbar);
pmainwnd->Update_Ani_Frame (frame, max_frames);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Find_Node_At_Point
//
///////////////////////////////////////////////////////////////
NodeClass *
SceneEditorClass::Find_Node_At_Point (CPoint point, Vector3 *intersect_pt)
{
//
// Calculate the ray from the current camera pos through
// the mouse cursor.
//
Vector3 ray_start;
Vector3 ray_end;
MoverClass::Get_Mouse_Ray (point, 250.0F, ray_start, ray_end);
//
// Cast the ray into the world
//
CastResultStruct res;
if (intersect_pt != NULL) {
res.ComputeContactPoint = true;
}
PhysClass *physobj = MoverClass::Cast_Ray (res, ray_start, ray_end, MOUSE_CLICK_COLLISION_GROUP);
if ((physobj != NULL) && (physobj->Peek_Model() != NULL)) {
WWDEBUG_SAY(("Picked model: %s\r\n",physobj->Peek_Model()->Get_Name()));
}
//
// Get the node's pointer that was hit from the raycast
//
NodeClass *node = NULL;
if (physobj != NULL) {
HITTESTINFO *hit_info = (HITTESTINFO *)physobj->Peek_Model ()->Get_User_Data ();
if (hit_info != NULL && hit_info->Type == HITTESTINFO::Node) {
node = hit_info->node;
//
// Return the intersection point (if requested)
//
if (intersect_pt != NULL) {
(*intersect_pt) = res.ContactPoint;
}
}
}
// Return a pointer to the node
return node;
}
///////////////////////////////////////////////////////////////
//
// Execute_Function_At_Point
//
///////////////////////////////////////////////////////////////
bool
SceneEditorClass::Execute_Function_At_Point (CPoint point)
{
bool processed = false;
//
// Calculate the ray from the current camera pos through
// the mouse cursor.
//
Vector3 ray_start;
Vector3 ray_end;
MoverClass::Get_Mouse_Ray (point, 250.0F, ray_start, ray_end);
//
// Cast the ray into the world
//
CastResultStruct res;
PhysClass *physobj = MoverClass::Cast_Ray (res, ray_start, ray_end, MOUSE_CLICK_COLLISION_GROUP);
//
// Determine if the user clicked on a 'function'
//
NodeClass *node = NULL;
if (physobj != NULL) {
HITTESTINFO *hit_info = (HITTESTINFO *)physobj->Peek_Model ()->Get_User_Data ();
if ((hit_info != NULL) && hit_info->Type == HITTESTINFO::Function) {
hit_info->function->On_Click ();
processed = true;
}
}
// Return the true/false result code
return processed;
}
///////////////////////////////////////////////////////////////
//
// Move_Selected_Nodes
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::Move_Selected_Nodes (void)
{
float speed_modifier = ::Get_Camera_Mgr ()->Get_Speed_Modifier ();
float modifier = (::GetAsyncKeyState (VK_CONTROL) < 0) ? speed_modifier : 1.0F;
Matrix3D coord_system = ::Get_Camera_Mgr ()->Get_Camera ()->Get_Transform ();
bool move_object = false;
Vector3 delta (0, 0, 0);
if (::GetAsyncKeyState (VK_LEFT) < 0) {
//
// Move the objects along the x-axis of the current view
//
Vector3 movement (-0.05F * modifier, 0, 0);
delta += coord_system.Rotate_Vector (movement);
move_object = true;
} else if (::GetAsyncKeyState (VK_RIGHT) < 0) {
//
// Move the objects along the x-axis of the current view
//
Vector3 movement (0.05F * modifier, 0, 0);
delta += coord_system.Rotate_Vector (movement);
move_object = true;
}
if (::GetAsyncKeyState (VK_UP) < 0) {
//
// Should we move the object 'up'?
//
if (::GetAsyncKeyState (VK_SHIFT) < 0) {
delta += Vector3 (0, 0, 0.05F * modifier);
} else {
//
// Move the object along the 'ground-plane' at an axis orthogonal to the view's x-axis.
//
Vector3 y_vector = Vector3::Cross_Product (coord_system.Get_X_Vector (), Vector3 (0, 0, 1));
y_vector.Normalize ();
delta += y_vector * (-0.05F * modifier);
}
move_object = true;
} else if (::GetAsyncKeyState (VK_DOWN) < 0) {
//
// Should we move the object 'up'?
//
if (::GetAsyncKeyState (VK_SHIFT) < 0) {
delta += Vector3 (0, 0, -0.05F * modifier);
} else {
//
// Move the object along the 'ground-plane' at an axis orthogonal to the view's x-axis.
//
Vector3 y_vector = Vector3::Cross_Product (coord_system.Get_X_Vector (), Vector3 (0, 0, 1));
y_vector.Normalize ();
delta += y_vector * (0.05F * modifier);
}
move_object = true;
}
//
// Move the selected nodes if necessary
//
if (move_object) {
MoverClass::Move_Nodes (delta);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// On_Frame
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::On_Frame (void)
{
//
// Let the heightfield editor think
//
HeightfieldEditorClass::On_Frame_Update ();
//
// Get the currently 'focussed' process
//
HWND current_focus_wnd = ::GetFocus ();
DWORD process_id = 0;
if (current_focus_wnd != NULL) {
::GetWindowThreadProcessId (current_focus_wnd, &process_id);
}
//
// If we are the current process, then move the nodes
//
if (process_id == ::GetCurrentProcessId ()) {
Move_Selected_Nodes ();
}
if (m_MovingObject != NULL) {
PathMgrClass::Resolve_Paths (Vector3 (0, 0, 0));
PhysicalGameObj *game_obj = ((ObjectNodeClass *)m_MovingObject)->Peek_Game_Obj ();
((SmartGameObj *)game_obj)->Generate_Control ();
game_obj->Think ();
PhysClass *phys_obj = game_obj->Peek_Physical_Object ();
if (phys_obj != NULL) {
phys_obj->Timestep (TimeManager::Get_Frame_Seconds ());
}
game_obj->Post_Think ();
#if 0
ActionClass *action = ((SmartGameObj *)game_obj)->Get_Action ();
if (action != NULL && action->Get_Movement () == NULL) {
//m_MovingObject = NULL;
}
#endif
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Record_Vis_Info
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::Record_Vis_Info (const Matrix3D &view_transform, const Vector3 &sample_location)
{
// Put up an hour glass
CWaitCursor wait_cursor;
PresetClass *preset = PresetMgrClass::Get_First (CLASSID_VIS_POINT_DEF, PresetMgrClass::ID_CLASS);
if (preset == NULL) {
CString message = "Missing 'Manual Vis Point' preset. Please create a default preset under the 'Manual Vis Point' folder in the preset library.";
::MessageBox (::AfxGetMainWnd ()->m_hWnd, message, "Missing Preset", MB_OK | MB_ICONEXCLAMATION);
} else {
//
// When doing a manual vis, use the FOV and clip settings of the in-game camera
//
CameraClass *scene_cam = CombatManager::Get_Camera ();
WWASSERT (scene_cam != NULL);
float scene_znear = 0;
float scene_zfar = 0;
scene_cam->Get_Clip_Planes (scene_znear, scene_zfar);
scene_cam->Set_Clip_Planes (scene_znear, VIS_FAR_CLIP);
//
// Generate the 'vis' information
//
VisSampleClass vis_sample = Update_Vis (view_transform * Vector3 (0, 0, -scene_znear), view_transform, (VisDirBitsType)(VIS_FORWARD_BIT | VIS_DONT_RECENTER), scene_cam);
if (vis_sample.Get_Bits_Changed () > 0 && vis_sample.Sample_Rejected () == false) {
//
// Convert the matrix to an obj-space transform
//
Matrix3D cam_to_world (Vector3 (0, 0, -1), Vector3 (-1, 0, 0), Vector3 (0, 1, 0), Vector3 (0, 0, 0));
Matrix3D obj_tm = view_transform * cam_to_world;
//
// Create the UI
//
Create_Vis_Point (view_transform);
VisPointNodeClass *vis_point = new VisPointNodeClass (preset);
vis_point->Set_ID (::Get_Node_Mgr ().Get_Node_ID (vis_point->Get_Type ()));
vis_point->Initialize ();
vis_point->Add_To_Scene ();
vis_point->Set_Transform (obj_tm);
vis_point->Set_Vis_Tile_Location (sample_location);
vis_point->Save_Camera_Settings (*scene_cam);
vis_point->Hide (!m_ManualVisPointsVisible);
::Get_Node_Mgr ().Add_Node (vis_point);
vis_point->Release_Ref ();
Set_Modified (true);
}
//
// Put the normal settings back into the scene camera
//
scene_cam->Set_Clip_Planes (scene_znear, scene_zfar);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Begin_Operation
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::Begin_Operation
(
OPERATION_TYPE type,
NodeClass * node
)
{
if (node != NULL) {
// Build a list containing the node
NODE_LIST node_list;
node_list.Add_Unique (node);
// Pass this list onto the undo manager
Begin_Operation (type, &node_list);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Begin_Operation
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::Begin_Operation
(
OPERATION_TYPE type,
NODE_LIST * affected_list
)
{
NODE_LIST node_list;
//
// If necessary, build a complete list of all the nodes that will be
// affected by this operation
//
if (affected_list == NULL) {
Build_Node_List (node_list, NULL);
affected_list = &node_list;
}
m_UndoMgr.Begin_Operation (type, *affected_list);
return ;
}
///////////////////////////////////////////////////////////////
//
// End_Operation
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::End_Operation (void)
{
m_UndoMgr.End_Operation ();
return ;
}
///////////////////////////////////////////////////////////////
//
// Undo
//
///////////////////////////////////////////////////////////////
bool
SceneEditorClass::Undo (void)
{
m_UndoMgr.Perform_Undo ();
return true;
}
///////////////////////////////////////////////////////////////
//
// Cut_Objects
//
///////////////////////////////////////////////////////////////
bool
SceneEditorClass::Cut_Objects (void)
{
bool retval = false;
// Turn painting off
CLevelEditView::Allow_Repaint (false);
// Copy the objects to the clipboard, then delete them
if (Copy_Objects ()) {
Delete_Nodes ();
}
// Turn painting back on
CLevelEditView::Allow_Repaint (true);
// Return the true/false result code
return retval;
}
///////////////////////////////////////////////////////////////
//
// Copy_Objects
//
///////////////////////////////////////////////////////////////
bool
SceneEditorClass::Copy_Objects (void)
{
Empty_Local_Clipboard ();
// Loop through all the nodes in the current selection
// and 'copy' them.
int count = m_SelectionMgr->Get_Count ();
for (int index = 0; index < count; index ++) {
NodeClass *node = m_SelectionMgr->Get_At (index);
//
// Copy the node and add it to our 'clipboard'
//
NodeClass *node_copy = node->Clone ();
ASSERT (node_copy != NULL);
if (node_copy != NULL) {
node_copy->Remove_From_Scene ();
m_LocalClipboard.Add (node_copy);
}
}
return true;
}
///////////////////////////////////////////////////////////////
//
// Paste_Objects
//
///////////////////////////////////////////////////////////////
bool
SceneEditorClass::Paste_Objects (void)
{
bool retval = (m_LocalClipboard.Count () > 0);
// Turn painting off
CLevelEditView::Allow_Repaint (false);
// Reset the selection group
m_SelectionMgr->Reset ();
for (int index = 0; index < m_LocalClipboard.Count (); index ++) {
//
// Copy the node on the clipboard and add it to the scene
//
NodeClass *node = m_LocalClipboard[index];
NodeClass *node_copy = Clone_Node (node);
if (node_copy != NULL) {
m_SelectionMgr->Add_Node (node_copy);
MEMBER_RELEASE (node_copy);
}
}
//
// Cast the nodes along the line-of-sight ray for 500 meters
//
Vector3 ray_start;
Vector3 ray_end;
MoverClass::Get_LOS_Ray (500.0F, ray_start, ray_end);
MoverClass::Position_Nodes_Along_Ray (ray_start, ray_end);
// Turn painting back on
CLevelEditView::Allow_Repaint (true);
Update_Toolbars ();
// Return the true/false result code
return retval;
}
///////////////////////////////////////////////////////////////
//
// Can_Paste
//
///////////////////////////////////////////////////////////////
bool
SceneEditorClass::Can_Paste (void)
{
// Return the true/false result code
return bool(m_LocalClipboard.Count () > 0);
}
///////////////////////////////////////////////////////////////
//
// Empty_Local_Clipboard
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::Empty_Local_Clipboard (void)
{
// Loop through all the entries in the clipboard and delete them
for (int index = 0; index < m_LocalClipboard.Count (); index ++) {
MEMBER_RELEASE (m_LocalClipboard[index]);
}
// Reset the list
m_LocalClipboard.Delete_All ();
return ;
}
///////////////////////////////////////////////////////////////
//
// Add_Global_Group
//
///////////////////////////////////////////////////////////////
GroupMgrClass *
SceneEditorClass::Add_Global_Group
(
const CString & name,
NODE_LIST * initial_list
)
{
// Create a new group with the speicfied name
UserGroupMgrClass *group = new UserGroupMgrClass;
group->Set_Name (name);
// If we have a list of nodes to add to this group,
// then do so now.
if (initial_list != NULL) {
for (int index = 0; index < initial_list->Count (); index ++) {
group->Add_Node ((*initial_list)[index]);
}
}
// Add this new group manager to our global list
m_GroupsList.Add_Unique (group);
// Return a pointer to the new group
return group;
}
///////////////////////////////////////////////////////////////
//
// Remove_Global_Group
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::Remove_Global_Group (GroupMgrClass *group)
{
// If this group is in our global list, then remove
// it from the list, remove it from any UI, and free its memory.
if (m_GroupsList.Is_Item_In_List (group)) {
m_GroupsList.Remove (group);
Remove_Group_From_Toolbar (group);
SAFE_DELETE (group);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Reset_Global_Groups_List
//
///////////////////////////////////////////////////////////////
void
SceneEditorClass::Reset_Global_Groups_List (void)
{
// Loop through all the groups in our list and
// free their associated memory.
for (int index = 0; index < m_GroupsList.Count (); index ++) {
GroupMgrClass *group = m_GroupsList[index];
if (group != NULL) {
Remove_Group_From_Toolbar (group);
SAFE_DELETE (group);
}
}
// Remove all the entries from the list
m_GroupsList.Delete_All ();
return ;
}
////////////////////////////////////////////////////////////////
//
// Add_Group_To_Toolbar
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Add_Group_To_Toolbar (GroupMgrClass *group)
{
ASSERT (group != NULL);
// Get the form representing the groups list, and add this group to it
/*GroupsPageClass *group_page = ::Get_Groups_Form ();
if (group_page != NULL) {
group_page->Add_Group (group);
}*/
return ;
}
////////////////////////////////////////////////////////////////
//
// Remove_Group_From_Toolbar
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Remove_Group_From_Toolbar (GroupMgrClass *group)
{
ASSERT (group != NULL);
// Get the form representing the groups list, and remove this group from it
/*GroupsPageClass *group_page = ::Get_Groups_Form ();
if (group_page != NULL) {
group_page->Remove_Group (group);
}*/
return ;
}
////////////////////////////////////////////////////////////////
//
// Turn_Lights_On
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Turn_Lights_On (bool onoff)
{
m_bLightsOn = onoff;
//
// Loop through all the lights in the world
//
/*LightInstanceClass *plight = NULL;
for (plight = (LightInstanceClass *)::Get_Node_Mgr ().Get_First (NODE_TYPE_LIGHT);
plight != NULL;
plight = (LightInstanceClass *)::Get_Node_Mgr ().Get_Next (NODE_TYPE_LIGHT)) {
plight->Turn_Light_On (onoff);
}*/
::Refresh_Main_View ();
return ;
}
////////////////////////////////////////////////////////////////
//
// Lock_Nodes
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Lock_Nodes (bool lock)
{
//
// Loop through all the nodes in the current selection
//
for (int index = 0; index < m_SelectionMgr->Get_Count (); index ++) {
NodeClass *node = m_SelectionMgr->Get_At (index);
if (node != NULL) {
//
// Lock the node, this keep the node from moving during
// drag operations.
//
node->Lock (lock);
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Set_Background_Music
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Set_Background_Music (LPCTSTR filename)
{
//
// Stop the old sound
//
WWAudioClass::Get_Instance ()->Set_Background_Music (NULL);
//
// Remove the sound file from the file manager
//
if (m_BackgroundSoundFilename.GetLength () > 0) {
CString old_path = ::Get_File_Mgr ()->Make_Full_Path (m_BackgroundSoundFilename);
::Get_File_Mgr ()->Remove_File (::Get_File_Mgr ()->Find_File (old_path));
m_BackgroundSoundFilename.Empty ();
}
//
// Set the new background music
//
if ((filename != NULL) && (filename[0] != 0)) {
CString path = ::Get_File_Mgr ()->Make_Full_Path (filename);
if (::Get_File_Mgr ()->Does_File_Exist (path, true)) {
//
// Set the background music
//
::Set_Current_Directory (::Strip_Filename_From_Path (path));
WWAudioClass::Get_Instance ()->Set_Background_Music (::Get_Filename_From_Path (path));
//
// Add this sound to the file manager
//
::Get_File_Mgr ()->Add_File (path);
m_BackgroundSoundFilename = path;
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// View_Aggregate_Children
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::View_Aggregate_Children (bool view)
{
// Did the state change?
/*if (view != m_bAggregateChildrenVisible) {
m_bAggregateChildrenVisible = view;
// Make sure to reset the selection for this to work
m_SelectionMgr->Reset ();
// Update all the aggregates in the level
::Get_Node_Mgr ().Update_Aggregate_Instances ();
}*/
return ;
}
////////////////////////////////////////////////////////////////
//
// Display_Vis_Points
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Display_Vis_Points (bool onoff)
{
// Did the state change?
if (onoff != m_bVisPointsDisplayed) {
m_bVisPointsDisplayed = onoff;
//
// Show/hide all the vis points
//
for (int index = 0; index < m_VisPoints.Count (); index ++) {
DecorationPhysClass *vis_point = m_VisPoints[index];
if (vis_point != NULL) {
if (onoff) {
Add_Dynamic_Object (vis_point);
} else {
Remove_Object (vis_point);
}
}
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Create_Vis_Point
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Create_Vis_Point (const Matrix3D &transform)
{
//
// Create a new vis-point marker at the location
//
DecorationPhysClass *new_point = new DecorationPhysClass;
new_point->Set_Model_By_Name ("WAYSTART");
new_point->Set_Transform (transform);
new_point->Set_Collision_Group (0);
//
// Add this new point to our list
//
m_VisPoints.Add (new_point);
if (m_bVisPointsDisplayed) {
Add_Dynamic_Object (new_point);
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Remove_All_Vis_Points
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Remove_All_Vis_Points (void)
{
::Get_Main_View ()->Allow_Repaint (false);
CWaitCursor wait_cursor;
//
// Build a list of all the vis points in the world
//
for (int index = 0; index < m_VisPoints.Count (); index ++) {
DecorationPhysClass *vis_point = m_VisPoints[index];
if (vis_point != NULL) {
Remove_Object (vis_point);
vis_point->Release_Ref ();
}
}
m_VisPoints.Delete_All ();
::Get_Main_View ()->Allow_Repaint (true);
return ;
}
////////////////////////////////////////////////////////////////
//
// Discard_Vis
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Discard_Vis (void)
{
m_VisLog.Reset_Log ();
Remove_All_Vis_Points ();
PhysicsSceneClass::Internal_Vis_Reset ();
return ;
}
////////////////////////////////////////////////////////////////
//
// Reset_Vis
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Reset_Vis (bool doitnow)
{
m_VisLog.Reset_Log ();
Remove_All_Vis_Points ();
PhysicsSceneClass::Reset_Vis (doitnow);
return ;
}
////////////////////////////////////////////////////////////////
//
// Internal_Vis_Reset
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Internal_Vis_Reset (void)
{
if (VisResetNeeded) {
PhysicsSceneClass::Internal_Vis_Reset ();
//
// Ask all the nodes
//
NodeClass *node = NULL;
for ( node = NodeMgrClass::Get_First ();
node != NULL;
node = NodeMgrClass::Get_Next (node))
{
node->Update_Cached_Vis_IDs ();
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Get_Vis_Camera_FOV
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Get_Vis_Camera_FOV (double &hfov, double &vfov)
{
CameraClass *vis_camera = Get_Vis_Camera ();
WWASSERT (vis_camera != NULL);
if (vis_camera != NULL) {
hfov = vis_camera->Get_Horizontal_FOV ();
vfov = vis_camera->Get_Vertical_FOV ();
MEMBER_RELEASE (vis_camera);
} else {
hfov = 0;
vfov = 0;
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Get_Vis_Camera_Clip_Planes
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Get_Vis_Camera_Clip_Planes (float &znear, float &zfar)
{
CameraClass *vis_camera = Get_Vis_Camera ();
WWASSERT (vis_camera != NULL);
if (vis_camera != NULL) {
vis_camera->Get_Clip_Planes (znear, zfar);
MEMBER_RELEASE (vis_camera);
} else {
znear = 0;
zfar = 0;
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Get_Render_Camera
//
////////////////////////////////////////////////////////////////
CameraClass *
SceneEditorClass::Get_Render_Camera (void)
{
CameraClass *camera = NULL;
if (::Get_Camera_Mgr ()->Get_Camera_Mode () == CameraMgr::MODE_WALK_THROUGH) {
camera = CombatManager::Get_Camera ();
} else {
camera = ::Get_Camera_Mgr ()->Get_Camera ();
}
return camera;
}
////////////////////////////////////////////////////////////////
//
// Generate_Pathfind_Portals
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Generate_Pathfind_Portals (void)
{
CWaitCursor wait_cursor;
//
// Create a pathfind floodfiller object
//
PathfindSectorBuilderClass builder;
builder.Allow_Water_Floodfill (true);
builder.Initialize ();
//
// Find all the pathfind start-points in the level and add
// them to the floodfiller
//
NodeClass *node = NULL;
for ( node = NodeMgrClass::Get_First ();
node != NULL;
node = NodeMgrClass::Get_Next (node))
{
if (node->Get_Type () == NODE_TYPE_PATHFIND_START) {
builder.Add_Start_Point (node->Get_Transform ().Get_Translation ());
}
}
//
// Perform the floodfill from each of the start locations
//
builder.Generate_Sectors ();
builder.Compress_Sectors_For_Pathfind ();
//
// Build height data for flying vehicles
//
HeightDBClass::Generate ();
//
// Cleanup
//
builder.Shutdown ();
return ;
}
////////////////////////////////////////////////////////////////
//
// Export_VIS
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Export_VIS (LPCTSTR filename)
{
//
// Create the file
//
HANDLE hfile = ::CreateFile (filename,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
0L,
NULL);
ASSERT (hfile != INVALID_HANDLE_VALUE);
if (hfile != INVALID_HANDLE_VALUE) {
RawFileClass file_obj;
file_obj.Attach (hfile);
ChunkSaveClass chunk_save (&file_obj);
//
// Export the data to this file
//
Export_Vis_Data (chunk_save);
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Update_Selection_Boxes
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Update_Selection_Boxes (void)
{
//
// Loop through all the nodes in the current selection
//
for (int index = 0; index < m_SelectionMgr->Get_Count (); index ++) {
NodeClass *node = m_SelectionMgr->Get_At (index);
if (node != NULL) {
//
// Ask the node to update its selection box (color and pos)
//
node->Update_Selection_Box ();
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Re_Partition_Audio_System
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Re_Partition_Audio_System (void)
{
const AABoxClass & level_bounds = StaticCullingSystem->Get_Bounding_Box();
Vector3 min,max;
min = level_bounds.Center - level_bounds.Extent;
max = level_bounds.Center + level_bounds.Extent;
SoundSceneClass *sound_scene = WWAudioClass::Get_Instance ()->Get_Sound_Scene ();
if (sound_scene != NULL) {
sound_scene->Re_Partition (min, max);
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Are_Manual_Vis_Points_Visible
//
////////////////////////////////////////////////////////////////
bool
SceneEditorClass::Are_Manual_Vis_Points_Visible (void)
{
return m_ManualVisPointsVisible;
}
////////////////////////////////////////////////////////////////
//
// Show_Manual_Vis_Points
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Show_Manual_Vis_Points (bool show_points)
{
if (m_ManualVisPointsVisible != show_points) {
m_ManualVisPointsVisible = show_points;
NodeClass *node = NULL;
for ( node = NodeMgrClass::Get_First ();
node != NULL;
node = NodeMgrClass::Get_Next (node))
{
if (node->Get_Type () == NODE_TYPE_VIS_POINT) {
node->Hide (!m_ManualVisPointsVisible);
}
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// DoObjectGoto
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::DoObjectGoto (NodeClass *node1, NodeClass *node2)
{
SANITY_CHECK(node1 != NULL && node2 != NULL && node1->Get_Type () == NODE_TYPE_OBJECT) {
return ;
}
//
// Register all the waypaths with the pathfinding system
//
for ( NodeClass *node = NodeMgrClass::Get_First (NODE_TYPE_WAYPATH);
node != NULL;
node = NodeMgrClass::Get_Next (node, NODE_TYPE_WAYPATH))
{
node->Pre_Export ();
}
//
// Force the pathfind system to use any available waypath data
// in its evaluation
//
PathfindClass::Get_Instance ()->Generate_Waypath_Sectors_And_Portals ();
m_MovingObject = node1;
PhysicalGameObj *game_obj = ((ObjectNodeClass *)m_MovingObject)->Peek_Game_Obj ();
if (game_obj != NULL && game_obj->As_SmartGameObj () != NULL) {
ActionClass *action = ((SmartGameObj *)game_obj)->Get_Action ();
ActionParamsStruct parameters;
parameters.MoveLocation = node2->Get_Transform ().Get_Translation ();
parameters.MoveArrivedDistance = 3.0F;
action->Goto( parameters );
}
//
// Unregister all the waypaths with the pathfinding system
//
for ( node = NodeMgrClass::Get_First (NODE_TYPE_WAYPATH);
node != NULL;
node = NodeMgrClass::Get_Next (node, NODE_TYPE_WAYPATH))
{
node->Post_Export ();
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Export_Lights
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Export_Lights (LPCTSTR filename)
{
FileClass *file = _TheFileFactory->Get_File (filename);
if (file != NULL && file->Create () && file->Open (FileClass::WRITE)) {
//
// Write the first chunk header
//
ChunkSaveClass csave (file);
csave.Begin_Chunk (W3D_CHUNK_LIGHTSCAPE);
//
// Loop over all the lights in the scene
//
for ( NodeClass *node = NodeMgrClass::Get_First (NODE_TYPE_LIGHT);
node != NULL;
node = NodeMgrClass::Get_Next (node, NODE_TYPE_LIGHT))
{
LightNodeClass *light_node = (LightNodeClass *)node;
//
// Get the actual light from the editor object
//
LightClass *light = light_node->Peek_Light ();
if (light != NULL) {
//
// Save this light
//
csave.Begin_Chunk (W3D_CHUNK_LIGHTSCAPE_LIGHT);
light->Save_W3D (csave);
//
// Save the light's transform as well
//
csave.Begin_Chunk (W3D_CHUNK_LIGHT_TRANSFORM);
Matrix3D tm = light->Get_Transform ();
W3dLightTransformStruct w3d_tm ={ tm[0][0], tm[0][1], tm[0][2], tm[0][3],
tm[1][0], tm[1][1], tm[1][2], tm[1][3],
tm[2][0], tm[2][1], tm[2][2], tm[2][3] };
csave.Write (&w3d_tm, sizeof (w3d_tm));
csave.End_Chunk ();
csave.End_Chunk ();
}
}
csave.End_Chunk ();
//
// Close the file
//
file->Close ();
}
_TheFileFactory->Return_File (file);
return ;
}
////////////////////////////////////////////////////////////////
//
// Import_Lights
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Import_Lights
(
DynamicVectorClass & filename_list,
DynamicVectorClass * node_list
)
{
DynamicVectorClass light_list;
::Get_Main_View ()->Allow_Repaint (false);
//
// Build a list of light objects from the LIG files
//
for (int index = 0; index < filename_list.Count (); index ++) {
FileClass *file = _TheFileFactory->Get_File (filename_list[index]);
if (file != NULL && file->Open ()) {
//
// Read the lights from this file
//
ChunkLoadClass cload (file);
int group_id = 0;
while (cload.Open_Chunk ()) {
switch (cload.Cur_Chunk_ID ()) {
case W3D_CHUNK_LIGHTSCAPE:
Build_Light_List (cload, light_list, group_id ++);
break;
default:
ASSERT (0);
TRACE ("Unrecognized chunk id found while importing lights!\n");
break;
}
cload.Close_Chunk ();
}
file->Close ();
}
//
// Delete the file object
//
if (file != NULL) {
_TheFileFactory->Return_File (file);
}
}
//
// Make sure we don't get duplicate lights
//
Filter_Lights (light_list);
//
// Get the preset we will use to derive each imported light-node from
//
PresetClass *preset = PresetMgrClass::Find_Preset ("Lightscape Imported");
ASSERT (preset != NULL);
CString base_name = ::Asset_Name_From_Filename (filename_list[0]);
//
// Add the lights to the level
//
for (index = 0; index < light_list.Count (); index ++) {
LightClass *light = light_list[index];
if (light != NULL) {
//
// Create an editor 'node' for this light and configure it from the
// light render-object.
//
if (light->Get_Type () != LightClass::DIRECTIONAL) {
Matrix3D tm = light->Get_Transform ();
LightNodeClass *light_node = (LightNodeClass *)Create_Node (preset, &tm);
light_node->Initialize_From_Light (light);
light_node->Set_Group_ID ((int)light->Get_User_Data ());
CString light_name;
light_name.Format ("%s%04d", (LPCTSTR)base_name, index + 1);
light_node->Peek_Light_Phys ()->Set_Name (light_name);
//
// Add this light to the list the caller supplied us with (if necessary)
//
if (node_list != NULL) {
node_list->Add (light_node);
light_node->Add_Ref ();
}
}
//
// Free our hold on the light
//
MEMBER_RELEASE (light);
}
}
::Get_Main_View ()->Allow_Repaint (true);
return ;
}
////////////////////////////////////////////////////////////////
//
// Build_Light_List
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Build_Light_List
(
ChunkLoadClass & cload,
DynamicVectorClass & light_list,
int group_id
)
{
while (cload.Open_Chunk ()) {
switch (cload.Cur_Chunk_ID ()) {
case W3D_CHUNK_LIGHTSCAPE_LIGHT:
{
//
// Load the light and add it to the list
//
cload.Open_Chunk ();
LightClass *light = new LightClass;
light->Load_W3D (cload);
light->Set_User_Data ((void *)group_id);
light_list.Add (light);
cload.Close_Chunk ();
//
// Read the light's transform from the file
//
cload.Open_Chunk ();
ASSERT (cload.Cur_Chunk_ID () == W3D_CHUNK_LIGHT_TRANSFORM);
if (cload.Cur_Chunk_ID () == W3D_CHUNK_LIGHT_TRANSFORM) {
//
// Read the transform
//
W3dLightTransformStruct w3d_tm = { 0 };
cload.Read (&w3d_tm, sizeof (w3d_tm));
//
// Convert the persistent-safe transform to a
// render-obj friendly transform;
//
Matrix3D tm ( w3d_tm.Transform [0][0], w3d_tm.Transform [0][1], w3d_tm.Transform [0][2], w3d_tm.Transform [0][3],
w3d_tm.Transform [1][0], w3d_tm.Transform [1][1], w3d_tm.Transform [1][2], w3d_tm.Transform [1][3],
w3d_tm.Transform [2][0], w3d_tm.Transform [2][1], w3d_tm.Transform [2][2], w3d_tm.Transform [2][3]);
light->Set_Transform (tm);
}
cload.Close_Chunk ();
}
break;
default:
::Output_Message ("Found invalid chunk in light importer.\r\n");
break;
}
cload.Close_Chunk ();
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Filter_Lights
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Filter_Lights (DynamicVectorClass &light_list)
{
//
// Loop over every light
//
for (int index1 = 0; index1 < light_list.Count (); index1 ++) {
LightClass *light1 = light_list[index1];
bool is_unique = true;
//
// Compare this light against every other light
//
for (int index2 = 0; index2 < light_list.Count () && is_unique; index2 ++) {
//
// Don't check against itself
//
if (index2 != index1) {
LightClass *light2 = light_list[index2];
is_unique = (Compare_Lights (light1, light2) == false);
}
}
//
// Remove this light from the list if it is not unique
//
if (is_unique == false) {
MEMBER_RELEASE (light1);
light_list.Delete (index1);
index1 --;
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Display_Sound_Spheres
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Display_Sound_Spheres (bool onoff)
{
if (m_DisplaySoundSpheres != onoff) {
m_DisplaySoundSpheres = onoff;
//
// Loop over all the sounds and tell them to turn the spheres
// on or off.
//
for ( NodeClass *node = NodeMgrClass::Get_First (NODE_TYPE_SOUND);
node != NULL;
node = NodeMgrClass::Get_Next (node, NODE_TYPE_SOUND))
{
node->Show_Attenuation_Spheres (m_DisplaySoundSpheres);
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Display_Light_Spheres
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Display_Light_Spheres (bool onoff)
{
if (m_DisplayLightSpheres != onoff) {
m_DisplayLightSpheres = onoff;
//
// Loop over all the lights and tell them to turn the spheres
// on or off.
//
for ( NodeClass *node = NodeMgrClass::Get_First (NODE_TYPE_LIGHT);
node != NULL;
node = NodeMgrClass::Get_Next (node, NODE_TYPE_LIGHT))
{
node->Show_Attenuation_Spheres (m_DisplayLightSpheres);
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Import_Sunlight
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Import_Sunlight (LPCTSTR filename)
{
DynamicVectorClass light_list;
//
// Open the file
//
FileClass *file = _TheFileFactory->Get_File (filename);
if (file != NULL && file->Open ()) {
//
// Read the lights from this file
//
ChunkLoadClass cload (file);
cload.Open_Chunk ();
ASSERT (cload.Cur_Chunk_ID () == W3D_CHUNK_LIGHTSCAPE);
Build_Light_List (cload, light_list);
cload.Close_Chunk ();
file->Close ();
_TheFileFactory->Return_File (file);
}
//
// Try to find all the directional lights
//
LightClass *sunlight = NULL;
bool more_than_one = false;
for (int index = 0; index < light_list.Count () && !more_than_one; index ++) {
LightClass *light = light_list[index];
if (light != NULL) {
//
// We assume that every directional light is the 'sunlight'.
//
if (light->Get_Type () == LightClass::DIRECTIONAL) {
if (sunlight == NULL) {
sunlight = light;
} else {
//
// Check to make sure all directional lights are the same
//
if (Compare_Lights (sunlight, light) == false) {
more_than_one = true;
}
MEMBER_RELEASE (light);
}
}
}
}
bool apply_changes = (sunlight != NULL);
if (more_than_one) {
//
// Ask the user if they wish to make these changes
//
if (::MessageBox ( ::AfxGetMainWnd ()->m_hWnd,
"There are multiple sunlight definitions in this file which have different settings. Do you wish to continue?",
"Ambiguous Lights",
MB_ICONQUESTION | MB_YESNO) == IDNO)
{
apply_changes = false;
}
}
//
// Reconfigure the sunlight (if necessary)
//
if (apply_changes) {
LightClass *global_sunlight_obj = Get_Sun_Light ();
Vector3 diffuse;
sunlight->Get_Diffuse (&diffuse);
global_sunlight_obj->Set_Diffuse (diffuse);
global_sunlight_obj->Set_Intensity (sunlight->Get_Intensity ());
global_sunlight_obj->Set_Transform (sunlight->Get_Transform ());
MEMBER_RELEASE (global_sunlight_obj);
//
// Convert the sun's 3x3 roational matrix to a
// 'rotation' and 'elevation'.
//
Matrix3D tm = sunlight->Get_Transform ();
Vector3 test_vector (0, 0, -1);
test_vector = tm.Rotate_Vector (test_vector);
test_vector.Normalize ();
float rotation = ::atan2 (test_vector.Y, test_vector.X);
float elevation = ::asin (test_vector.Z);
Set_Sun_Light_Orientation (rotation, elevation);
Update_Lighting ();
}
MEMBER_RELEASE (sunlight);
return ;
}
////////////////////////////////////////////////////////////////
//
// Compare_Lights
//
////////////////////////////////////////////////////////////////
bool
SceneEditorClass::Compare_Lights (LightClass *light1, LightClass *light2)
{
bool retval = false;
//
// Are the positions and orientations approximately the same?
// Are they both the same type of light?
//
const Matrix3D &tm1 = light1->Get_Transform ();
const Matrix3D &tm2 = light2->Get_Transform ();
if ( tm1 == tm2 &&
light1->Get_Type () == light2->Get_Type ())
{
//
// Are their color's and intensities approx the same?
//
Vector3 ambient1;
Vector3 ambient2;
Vector3 specular1;
Vector3 specular2;
Vector3 diffuse1;
Vector3 diffuse2;
light1->Get_Ambient (&ambient1);
light2->Get_Ambient (&ambient2);
light1->Get_Specular (&specular1);
light2->Get_Specular (&specular2);
light1->Get_Diffuse (&diffuse1);
light2->Get_Diffuse (&diffuse2);
float intensity1 = light1->Get_Intensity ();
float intensity2 = light2->Get_Intensity ();
if ( ambient1 == ambient2 &&
specular1 == specular2 &&
diffuse1 == diffuse2 &&
intensity1 == intensity2)
{
//
// Are their attenuation ranges the same?
//
double inner1 = 0;
double inner2 = 0;
double outer1 = 0;
double outer2 = 0;
light1->Get_Far_Attenuation_Range (inner1, outer1);
light2->Get_Far_Attenuation_Range (inner2, outer2);
if (inner1 == inner2 && outer1 == outer2) {
retval = true;
}
}
}
return retval;
}
////////////////////////////////////////////////////////////////
//
// Replace_Selection
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Replace_Selection (void)
{
//
// Is there a selection set to replace?
//
int count = m_SelectionMgr->Get_Count ();
if (count > 0) {
//
// Configure a dialog that will allow the user to select a preset
//
SelectPresetDialogClass dialog (::AfxGetMainWnd ());
dialog.Set_Title ("Object Replace");
dialog.Set_Message ("Select the new preset you want to replace the selected objects with.");
dialog.Allow_None_Selection (false);
//
// Let the user pick a preset
//
if (dialog.DoModal () == IDOK) {
PresetClass *preset = dialog.Get_Selection ();
DynamicVectorClass new_nodes;
CWaitCursor wait_cursor;
//
// Loop over all the selected nodes
//
for (int index = 0; index < count; index ++) {
//
// Get the transform of this selected node
//
NodeClass *node = m_SelectionMgr->Get_At (index);
Matrix3D tm = node->Get_Transform ();
//
// Create a new node with this same transform
//
NodeClass *new_node = Create_Node (preset, &tm, 0, true);
new_node->Set_ID (node->Get_ID ());
new_nodes.Add (new_node);
//
// Test to see if both node's are game objects of some sort.
// If they are, then we need to copy the scripts.
//
ObjectNodeClass *old_obj_node = node->As_ObjectNodeClass ();
ObjectNodeClass *new_obj_node = new_node->As_ObjectNodeClass ();
if (old_obj_node != NULL && new_obj_node != NULL) {
new_obj_node->Copy_Scripts (*old_obj_node);
}
//
// Delete the old node
//
Delete_Node (node, false);
}
//
// Clear the selection
//
m_SelectionMgr->Reset ();
//
// Add the new nodes to the selection set
//
for (index = 0; index < new_nodes.Count (); index ++) {
NodeClass *new_node = new_nodes[index];
m_SelectionMgr->Add_Node (new_node);
}
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Generate_Uniform_Sampled_Vis
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Generate_Uniform_Sampled_Vis
(
float granularity,
float sample_height,
bool ignore_bias,
bool selection_only,
bool farm_mode,
int farm_cpu_index,
int farm_cpu_total
)
{
GeneratingVisDialogClass dialog (granularity, ::AfxGetMainWnd ());
dialog.Set_Sample_Height (sample_height);
dialog.Set_Ignore_Bias (ignore_bias);
dialog.Do_Selection_Only (selection_only);
if (farm_mode) {
dialog.Set_Farm_Mode (farm_cpu_index,farm_cpu_total);
}
dialog.DoModal ();
return ;
}
////////////////////////////////////////////////////////////////
//
// Generate_Edge_Sampled_Vis
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Generate_Edge_Sampled_Vis
(
float granularity,
bool ignore_bias,
bool farm_mode,
int farm_cpu_index,
int farm_cpu_total
)
{
//
// Build a list of nodes that should be vis-sampled
//
DynamicVectorClass node_list;
VisMgrClass::Build_Node_List (node_list);
//
// Determine the first and last node that this cpu is to process. In farm
// mode, the processing is split up amongst several computers...
//
int first_node = 0;
int last_node = node_list.Count();
if (farm_mode) {
int node_count = node_list.Count();
float nodes_per_processor = (float)node_count / (float)farm_cpu_total;
first_node = (int)::floor (nodes_per_processor * (float)farm_cpu_index);
last_node = (int)::ceil (nodes_per_processor * (float)(farm_cpu_index+1));
}
VisGenProgressClass progress_obj;
progress_obj.Set_Node_Count (last_node - first_node);
GeneratingEdgeSampledVisDialogClass *dialog = GeneratingEdgeSampledVisDialogClass::Display ();
dialog->Set_Progress_Obj (&progress_obj);
dialog->Enable_Farm_Mode (farm_mode);
//
// Perform the per-node vis sampling
//
VisSectorSamplerClass sampler (this, &progress_obj, granularity, MOUSE_CLICK_COLLISION_GROUP);
for ( int index = first_node;
index < last_node && !progress_obj.Is_Cancel_Requested ();
index ++)
{
NodeClass *node = node_list[index];
if (node != NULL) {
//
// Simply pass off the render object onto the sampler class
// for point generation
//
RenderObjClass *render_obj = node->Peek_Render_Obj ();
if (render_obj != NULL) {
sampler.Process (render_obj);
}
}
::General_Pump_Messages ();
}
//
// Now render any manual vis points
//
VisMgrClass::Render_Manual_Vis_Points ();
dialog->Set_Progress_Obj (NULL);
dialog->Set_Finished (true);
return ;
}
////////////////////////////////////////////////////////////////
//
// Generate_Light_Vis
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Generate_Light_Vis
(
bool farm_mode,
int farm_cpu_index,
int farm_cpu_total
)
{
GeneratingLightVisDialogClass dialog (::AfxGetMainWnd ());
if (farm_mode) {
dialog.Set_Farm_Mode (farm_cpu_index,farm_cpu_total);
}
dialog.DoModal ();
return ;
}
////////////////////////////////////////////////////////////////
//
// Generate_Manual_Vis
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Generate_Manual_Vis
(
bool farm_mode,
int farm_cpu_index,
int farm_cpu_total
)
{
GeneratingManualVisDialogClass dialog (::AfxGetMainWnd ());
if (farm_mode) {
dialog.Set_Farm_Mode (farm_cpu_index, farm_cpu_total);
}
dialog.DoModal ();
return ;
}
////////////////////////////////////////////////////////////////
//
// Display_Editor_Objects
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Display_Editor_Objects (bool onoff)
{
m_ShowEditorObjects = onoff;
//
// Loop over all the nodes, picking out the editor-only
// nodes to show or hide.
//
DynamicVectorClass node_list;
NodeMgrClass::Build_Full_Node_List (node_list);
for (int index = 0; index < node_list.Count (); index ++) {
NodeClass *node = node_list[index];
if (node != NULL) {
int type = node->Get_Type ();
//
// Does this node have an editor-only display object?
//
if ( type == NODE_TYPE_ZONE ||
type == NODE_TYPE_WAYPATH ||
type == NODE_TYPE_WAYPOINT ||
type == NODE_TYPE_LIGHT ||
type == NODE_TYPE_TRANSITION ||
type == NODE_TYPE_TRANSITION_CHARACTER ||
type == NODE_TYPE_SOUND ||
type == NODE_TYPE_VIS ||
type == NODE_TYPE_VIS_POINT ||
type == NODE_TYPE_PATHFIND_START ||
type == NODE_TYPE_DUMMY_OBJECT ||
type == NODE_TYPE_COVER_SPOT ||
type == NODE_TYPE_COVER_ATTACK_POINT ||
type == NODE_TYPE_DAMAGE_ZONE ||
type == NODE_TYPE_BUILDING ||
type == NODE_TYPE_EDITOR_ONLY_OBJ)
{
node->Hide (!onoff);
}
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Display_Static_Anim_Phys
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Display_Static_Anim_Phys (bool onoff)
{
m_ShowStaticAnimPhys = onoff;
//
// Get the list of all static objects from the physics scene
//
RefPhysListIterator iterator = ::Get_Scene_Editor ()->Get_Static_Object_Iterator ();
for (iterator.First (); !iterator.Is_Done (); iterator.Next ()) {
//
// Is this object a static anim phys?
//
PhysClass *phys_obj = iterator.Peek_Obj ();
StaticAnimPhysClass *static_phys_obj = phys_obj->As_StaticAnimPhysClass ();
if (static_phys_obj != NULL && static_phys_obj->Peek_Model () != NULL) {
//
// Hide the static anim phys object and turn off its collision
//
static_phys_obj->Peek_Model ()->Set_Hidden (!onoff);
if (onoff == false) {
phys_obj->Inc_Ignore_Counter ();
} else if (phys_obj->Is_Ignore_Me ()) {
phys_obj->Dec_Ignore_Counter ();
}
}
}
/*for ( NodeClass *node = NodeMgrClass::Get_First ();
node != NULL;
node = NodeMgrClass::Get_Next (node))
{
PhysClass *phys_obj = node->Peek_Physics_Obj ();
if (phys_obj != NULL && phys_obj->As_StaticAnimPhysClass () != NULL) {
node->Hide (!onoff);
}
}*/
return ;
}
////////////////////////////////////////////////////////////////
//
// Enable_Building_Power
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Enable_Building_Power (bool onoff)
{
//
// Make sure the buildings are in a good state
//
GameObjManager::Update_Building_Collection_Spheres ();
GameObjManager::Init_Buildings ();
//
// Loop over all the lights and tell them to turn the spheres
// on or off.
//
for ( NodeClass *node = NodeMgrClass::Get_First (NODE_TYPE_BUILDING);
node != NULL;
node = NodeMgrClass::Get_Next (node, NODE_TYPE_BUILDING))
{
((BuildingNodeClass *)node)->Enable_Power (onoff);
((BuildingNodeClass *)node)->Set_Normalized_Health (onoff * 1.0F);
}
m_BuildingPowerEnabled = onoff;
return ;
}
////////////////////////////////////////////////////////////////
//
// Reset_Dynamic_Object_Visibility_Status
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Reset_Dynamic_Object_Visibility_Status (void)
{
//
// Get the list of all dynamic objects from the physics scene
//
RefPhysListIterator iterator = ::Get_Scene_Editor ()->Get_Dynamic_Object_Iterator ();
for (iterator.First (); !iterator.Is_Done (); iterator.Next ()) {
//
// Make sure this phys obj is a dynamic object
//
PhysClass *phys_obj = iterator.Peek_Obj ();
DynamicPhysClass *dyn_phys_obj = phys_obj->As_DynamicPhysClass ();
if (dyn_phys_obj != NULL) {
//
// Reset this dynamic object's visibility
//
dyn_phys_obj->Update_Visibility_Status ();
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Reset_Vis_For_Node
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Reset_Vis_For_Node (NodeClass *node)
{
if (node == NULL || node->Is_Static () == false) {
return ;
}
//
// Make sure this is a static phys object
//
PhysClass *phys = node->Peek_Physics_Obj ();
if (phys != NULL && phys->As_StaticPhysClass () != NULL) {
StaticPhysClass *static_phys = phys->As_StaticPhysClass ();
//
// Get this sector's id
//
int vis_id = static_phys->Get_Vis_Sector_ID ();
if (vis_id > 0) {
//
// Get the vis table for this sector
//
VisTableClass *vis_table = VisTableManager.Get_Vis_Table(vis_id, false);
if (vis_table != NULL) {
//
// Reset the visibility data for this sector
//
vis_table->Reset_All ();
VisTableManager.Update_Vis_Table(vis_id,vis_table);
REF_PTR_RELEASE(vis_table);
}
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Update_Lighting
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Update_Lighting (void)
{
Vector3 lev_min;
Vector3 lev_max;
Vector3 sundirection;
Get_Level_Extents (lev_min, lev_max);
AABoxClass box;
box.Center = lev_min + ((lev_max - lev_min) * 0.5F);
box.Extent = ((lev_max - lev_min) * 0.5F);
Invalidate_Lighting_Caches (box);
return ;
}
////////////////////////////////////////////////////////////////
//
// Set_Sun_Light_Orientation
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Set_Sun_Light_Orientation (float yaw, float pitch)
{
PhysicsSceneClass::Set_Sun_Light_Orientation (yaw, pitch);
}
////////////////////////////////////////////////////////////////
//
// Show_Vis_Window
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::Show_Vis_Window (bool onoff)
{
if (m_VisWindow.m_hWnd == NULL) {
m_VisWindow.Create ();
}
m_VisWindow.ShowWindow (onoff ? SW_SHOW : SW_HIDE);
return ;
}
////////////////////////////////////////////////////////////////
//
// Is_Vis_Window_Visible
//
////////////////////////////////////////////////////////////////
bool
SceneEditorClass::Is_Vis_Window_Visible (void)
{
bool retval = true;
if ( m_VisWindow.m_hWnd == NULL ||
m_VisWindow.IsWindowVisible () == false)
{
retval = false;
}
return retval;
}
////////////////////////////////////////////////////////////////
//
// On_Vis_Occluders_Rendered
//
////////////////////////////////////////////////////////////////
void
SceneEditorClass::On_Vis_Occluders_Rendered
(
VisRenderContextClass & context,
VisSampleClass & sample
)
{
m_VisWindow.Update_Display (*context.VisRasterizer);
return ;
}