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/VisMgr.cpp

419 lines
12 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/VisMgr.cpp $*
* *
* Author:: Patrick Smith *
* *
* $Modtime:: 3/26/01 2:46p $*
* *
* $Revision:: 8 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "stdafx.h"
#include "vismgr.h"
#include "sceneeditor.h"
#include "matrix3d.h"
#include "w3d_file.h"
#include "chunkio.h"
#include "utils.h"
#include "staticphys.h"
#include "node.h"
#include "nodemgr.h"
#include "cameramgr.h"
#include "camera.h"
#include "vispointnode.h"
#include "groupmgr.h"
///////////////////////////////////////////////////////////////////////
// Local constants
///////////////////////////////////////////////////////////////////////
enum
{
CHUNKID_VIS_OBJECT = 0x06150222,
CHUNKID_VIS_DATA
};
///////////////////////////////////////////////////////////////////////
// Local structures
///////////////////////////////////////////////////////////////////////
typedef struct
{
char mesh_name[W3D_NAME_LEN * 2];
Matrix3D transform;
int vis_id;
}
VIS_OBJECT_INFO;
///////////////////////////////////////////////////////////////////////
//
// Export_Remap_Data
//
///////////////////////////////////////////////////////////////////////
void
VisMgrClass::Export_Remap_Data (ChunkSaveClass &csave)
{
//
// 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 ()) {
//
// Double-check to make sure this object is static
//
PhysClass *phys_obj = iterator.Peek_Obj ();
StaticPhysClass *static_phys_obj = phys_obj->As_StaticPhysClass ();
if (static_phys_obj != NULL && static_phys_obj->Peek_Model () != NULL) {
//
// Build a structure of information about this static object
//
VIS_OBJECT_INFO obj_info;
::lstrcpy (obj_info.mesh_name, static_phys_obj->Peek_Model ()->Get_Name ());
obj_info.transform = static_phys_obj->Get_Transform ();
obj_info.vis_id = static_phys_obj->Get_Vis_Object_ID ();
//
// Save the object info to its own chunk
//
csave.Begin_Chunk (CHUNKID_VIS_OBJECT);
csave.Write (&obj_info, sizeof (obj_info));
csave.End_Chunk ();
}
}
//
// Now export all the vis data
//
csave.Begin_Chunk (CHUNKID_VIS_DATA);
::Get_Scene_Editor ()->Export_Vis_Data (csave);
csave.End_Chunk ();
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Import_Remap_Data
//
///////////////////////////////////////////////////////////////////////
void
VisMgrClass::Import_Remap_Data (ChunkLoadClass &cload)
{
bool is_valid = true;
//
// Start with a clean slate
//
::Get_Scene_Editor ()->Discard_Vis ();
//
// Process all the chunks in this file
//
while (is_valid && cload.Open_Chunk ()) {
switch (cload.Cur_Chunk_ID ())
{
//
// Try to remap the vis-id of this object with the
// vis-id of the object in the level where vis was generated.
//
case CHUNKID_VIS_OBJECT:
{
VIS_OBJECT_INFO info;
cload.Read (&info, sizeof (info));
//
// Attempt to find this physics object in the scene
//
StaticPhysClass *vis_object = Find_Static_Phys_Object (info.mesh_name, info.transform);
if (vis_object != NULL) {
vis_object->Set_Vis_Object_ID (info.vis_id);
} else {
is_valid = false;
}
}
break;
//
// Import the actual vis data. If we successfully
// remapped the vis-id's of all the objects, then this
// should work seamlessly
//
case CHUNKID_VIS_DATA:
{
::Get_Scene_Editor ()->Import_Vis_Data (cload);
}
break;
}
cload.Close_Chunk ();
}
//
// Warn the user if we failed
//
if (is_valid == false) {
::MessageBox ( NULL,
"The static geometry in this level does not match the geometry of the level in which vis was generated. Unable to import vis data into this level.",
"Import Error",
MB_ICONERROR | MB_OK);
}
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Find_Static_Phys_Object
//
///////////////////////////////////////////////////////////////////////
StaticPhysClass *
VisMgrClass::Find_Static_Phys_Object (LPCTSTR mesh_name, const Matrix3D &tm)
{
StaticPhysClass *retval = NULL;
//
// Get the list of all static objects from the physics scene
//
RefPhysListIterator iterator = ::Get_Scene_Editor ()->Get_Static_Object_Iterator ();
for (iterator.First (); retval == NULL && !iterator.Is_Done (); iterator.Next ()) {
//
// Double-check to make sure this object is static
//
PhysClass *phys_obj = iterator.Peek_Obj ();
StaticPhysClass *static_phys_obj = phys_obj->As_StaticPhysClass ();
if (static_phys_obj != NULL && static_phys_obj->Peek_Model () != NULL) {
//
// Is this the object we are looking for?
//
LPCTSTR curr_name = static_phys_obj->Peek_Model ()->Get_Name ();
Matrix3D curr_tm = static_phys_obj->Get_Transform ();
if ((::lstrcmpi (curr_name, mesh_name) == 0) && (curr_tm == tm)) {
retval = static_phys_obj;
}
}
}
return retval;
}
///////////////////////////////////////////////////////////////////////
//
// Build_Node_List
//
///////////////////////////////////////////////////////////////////////
void
VisMgrClass::Build_Node_List (DynamicVectorClass<NodeClass *> &node_list, bool selection_only)
{
if (selection_only) {
SelectionMgrClass &sel_mgr = ::Get_Scene_Editor ()->Get_Selection_Mgr ();
//
// Build a list of the selected nodes that should be used to calculate
// vis renders
//
for (int index = 0; index < sel_mgr.Get_Count (); index ++) {
NodeClass *node = sel_mgr.Get_At (index);
if (node != NULL && node->Is_Static ()) {
Add_Nodes_To_List (node_list, node);
}
}
} else {
//
// Build a list of nodes that should be used to calculate
// vis renders
//
for (NodeClass *node = ::Get_Node_Mgr ().Get_First ();
node != NULL;
node = ::Get_Node_Mgr ().Get_Next (node))
{
if (node->Is_Static ()) {
Add_Nodes_To_List (node_list, node);
}
}
}
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Add_Nodes_To_List
//
///////////////////////////////////////////////////////////////////////
void
VisMgrClass::Add_Nodes_To_List
(
DynamicVectorClass<NodeClass *> &node_list,
NodeClass *node
)
{
//
// If the node is an aggregate (like a terrain), we are adding the
// sub-nodes directly into the list
//
int sub_count = node->Get_Sub_Node_Count ();
if (sub_count > 0) {
for (int index = 0; index < sub_count; index ++) {
NodeClass *sub_node = node->Get_Sub_Node (index);
//
// Recurse into this node
//
Add_Nodes_To_List (node_list, sub_node);
}
} else {
if (node->Has_Vis_Sectors ()) {
node_list.Add (node);
}
}
return ;
}
//////////////////////////////////////////////////////////////////////////////
//
// Render_Manual_Vis_Points
//
//////////////////////////////////////////////////////////////////////////////
void
VisMgrClass::Render_Manual_Vis_Points
(
bool farm_mode,
int processor_index,
int total_processors,
VIS_POINT_RENDERED_CALLBACK callback,
DWORD param
)
{
SceneEditorClass *scene_editor = ::Get_Scene_Editor ();
VisLogClass &vis_log = scene_editor->Get_Vis_Log ();
CameraClass *camera = new CameraClass (*::Get_Camera_Mgr ()->Get_Camera ());
bool keep_going = true;
//
// Bulid a list of vis points
//
DynamicVectorClass<VisPointNodeClass *> point_list;
VisPointNodeClass *vis_point = NULL;
for ( vis_point = (VisPointNodeClass *)NodeMgrClass::Get_First (NODE_TYPE_VIS_POINT);
vis_point != NULL && keep_going;
vis_point = (VisPointNodeClass *)NodeMgrClass::Get_Next (vis_point, NODE_TYPE_VIS_POINT))
{
point_list.Add (vis_point);
}
//
// Determine which nodes to process if we
// are in farm mode.
//
if (farm_mode) {
int points = point_list.Count ();
float points_per_processor = ((float)points) / ((float)total_processors);
int starting_point = (int)::floor (points_per_processor* (float)processor_index);
int ending_point = (int)::ceil (points_per_processor * (float)(processor_index + 1));
ending_point = min (ending_point, points);
//
// Copy the points from the total list into a temporary list
//
DynamicVectorClass<VisPointNodeClass *> temp_list;
for (int index = starting_point; index < ending_point; index ++) {
temp_list.Add (point_list[index]);
}
point_list.Delete_All ();
point_list = temp_list;
}
//
// Loop over all manual vis points in the level
//
for (int index = 0; index < point_list.Count (); index ++)
{
DWORD before = ::GetTickCount ();
VisPointNodeClass *vis_point = point_list[index];
// Set the camera up to use the same settings we used when
// we generated this manual vis point
//
vis_point->Setup_Camera (*camera);
//
// Get the camera's clip plane settings
//
float znear = 0;
float zfar = 0;
camera->Get_Clip_Planes (znear, zfar);
//
// Convert the object transform to a camera transform
//
Matrix3D transform = vis_point->Get_Transform ();
Matrix3D cam_transform (Vector3 (0, -1, 0), Vector3 (0, 0, 1), Vector3 (-1, 0, 0), Vector3 (0, 0, 0));
Matrix3D new_transform = transform * cam_transform;
Vector3 sample_location = (new_transform * Vector3 (0, 0, -znear));
//
//
// Render vis for this point
//
VisSampleClass vis_sample = scene_editor->Update_Vis (sample_location,
new_transform,
VisDirBitsType(VIS_FORWARD_BIT | VIS_DONT_RECENTER),
camera);
vis_log.Log_Sample (vis_sample);
scene_editor->Create_Vis_Point (transform);
//
// Notify the callback that we've renedered a point
//
if (callback != NULL) {
DWORD after = ::GetTickCount ();
keep_going = (*callback) (after - before, param);
}
}
MEMBER_RELEASE (camera);
return ;
}