/*
** 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 : wwphys *
* *
* $Archive:: /Commando/Code/wwphys/umbrasupport.cpp $*
* *
* Original Author:: Greg Hjelstrom *
* *
* $Author:: Greg_h $*
* *
* $Modtime:: 11/29/00 4:46p $*
* *
* $Revision:: 1 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "umbrasupport.h"
#if (UMBRASUPPORT)
#include
#include "mesh.h"
#include "meshmdl.h"
#include "camera.h"
#include "phys.h"
class UmbraCommanderClass;
/*
** Static Variables
*/
static Umbra::Model * _DummySphere = NULL;
static Umbra::Cell * _TheCell = NULL;
static Umbra::Camera * _TheCamera = NULL;
static UmbraCommanderClass * _TheCommander = NULL;
static bool _UmbraEnabled = true;
static Umbra::Vector3 _umbra_box_verts[8];
static Umbra::Vector3i _umbra_box_faces[12];
static int _umbra_box_vert_count = 8;
static int _umbra_box_face_count = 12;
/*
**
** Local utility functions
**
*/
static void _convert_matrix_westwood_to_umbra(const Matrix3D & in,Umbra::Matrix4x4 & out)
{
#if 0
for (int j=0;j<3;j++) {
for (int i=0;i<4;i++) {
out.m[j][i] = in[j][i];
}
}
out.m[3][0] = 0.0;
out.m[3][1] = 0.0;
out.m[3][2] = 0.0;
out.m[3][3] = 1.0;
#endif
#if 0
for (int j=0;j<3;j++) {
for (int i=0; i<3; i++) {
out.m[i][j] = in[j][i];
}
}
out.m[0][3] = in[0][3];
out.m[1][3] = in[1][3];
out.m[2][3] = in[2][3];
out.m[3][0] = 0.0;
out.m[3][1] = 0.0;
out.m[3][2] = 0.0;
out.m[3][3] = 1.0;
#endif
#if 1
for (int j=0;j<3;j++) {
for (int i=0;i<4;i++) {
out.m[i][j] = in[j][i];
}
}
out.m[0][3] = 0.0;
out.m[1][3] = 0.0;
out.m[2][3] = 0.0;
out.m[3][3] = 1.0;
#endif
}
static void _convert_frustum_westwood_to_umbra(const CameraClass & camera,Umbra::Frustum & out)
{
camera.Get_Clip_Planes(out.zNear,out.zFar);
Vector2 vmin,vmax;
camera.Get_View_Plane(vmin,vmax);
out.left = vmin.X;
out.right = vmax.X;
out.top = vmax.Y;
out.bottom = vmin.Y;
// out.zFar = 1500.0;
}
static void _init_umbra_box(const AABoxClass & obj_bound_box)
{
_umbra_box_verts[0].v[0] = obj_bound_box.Center.X + obj_bound_box.Extent.X;
_umbra_box_verts[0].v[1] = obj_bound_box.Center.Y + obj_bound_box.Extent.Y;
_umbra_box_verts[0].v[2] = obj_bound_box.Center.Z - obj_bound_box.Extent.Z;
_umbra_box_verts[1].v[0] = obj_bound_box.Center.X - obj_bound_box.Extent.X;
_umbra_box_verts[1].v[1] = obj_bound_box.Center.Y + obj_bound_box.Extent.Y;
_umbra_box_verts[1].v[2] = obj_bound_box.Center.Z - obj_bound_box.Extent.Z;
_umbra_box_verts[2].v[0] = obj_bound_box.Center.X - obj_bound_box.Extent.X;
_umbra_box_verts[2].v[1] = obj_bound_box.Center.Y - obj_bound_box.Extent.Y;
_umbra_box_verts[2].v[2] = obj_bound_box.Center.Z - obj_bound_box.Extent.Z;
_umbra_box_verts[3].v[0] = obj_bound_box.Center.X + obj_bound_box.Extent.X;
_umbra_box_verts[3].v[1] = obj_bound_box.Center.Y - obj_bound_box.Extent.Y;
_umbra_box_verts[3].v[2] = obj_bound_box.Center.Z - obj_bound_box.Extent.Z;
_umbra_box_verts[4].v[0] = obj_bound_box.Center.X + obj_bound_box.Extent.X;
_umbra_box_verts[4].v[1] = obj_bound_box.Center.Y + obj_bound_box.Extent.Y;
_umbra_box_verts[4].v[2] = obj_bound_box.Center.Z + obj_bound_box.Extent.Z;
_umbra_box_verts[5].v[0] = obj_bound_box.Center.X - obj_bound_box.Extent.X;
_umbra_box_verts[5].v[1] = obj_bound_box.Center.Y + obj_bound_box.Extent.Y;
_umbra_box_verts[5].v[2] = obj_bound_box.Center.Z + obj_bound_box.Extent.Z;
_umbra_box_verts[6].v[0] = obj_bound_box.Center.X - obj_bound_box.Extent.X;
_umbra_box_verts[6].v[1] = obj_bound_box.Center.Y - obj_bound_box.Extent.Y;
_umbra_box_verts[6].v[2] = obj_bound_box.Center.Z + obj_bound_box.Extent.Z;
_umbra_box_verts[7].v[0] = obj_bound_box.Center.X + obj_bound_box.Extent.X;
_umbra_box_verts[7].v[1] = obj_bound_box.Center.Y - obj_bound_box.Extent.Y;
_umbra_box_verts[7].v[2] = obj_bound_box.Center.Z + obj_bound_box.Extent.Z;
// -z face
_umbra_box_faces[0].i = 2; _umbra_box_faces[0].j = 0; _umbra_box_faces[0].k = 3;
_umbra_box_faces[1].i = 2; _umbra_box_faces[1].j = 1; _umbra_box_faces[1].k = 0;
// +z face
_umbra_box_faces[2].i = 6; _umbra_box_faces[2].j = 7; _umbra_box_faces[2].k = 4;
_umbra_box_faces[3].i = 6; _umbra_box_faces[3].j = 4; _umbra_box_faces[3].k = 5;
// +x face
_umbra_box_faces[4].i = 7; _umbra_box_faces[4].j = 0; _umbra_box_faces[4].k = 4;
_umbra_box_faces[5].i = 7; _umbra_box_faces[5].j = 3; _umbra_box_faces[5].k = 0;
// -x face
_umbra_box_faces[6].i = 6; _umbra_box_faces[6].j = 5; _umbra_box_faces[6].k = 1;
_umbra_box_faces[7].i = 6; _umbra_box_faces[7].j = 1; _umbra_box_faces[7].k = 2;
// +y face
_umbra_box_faces[8].i = 5; _umbra_box_faces[8].j = 4; _umbra_box_faces[8].k = 0;
_umbra_box_faces[9].i = 5; _umbra_box_faces[9].j = 0; _umbra_box_faces[9].k = 1;
// -y face
_umbra_box_faces[10].i = 2; _umbra_box_faces[10].j = 7; _umbra_box_faces[10].k = 6;
_umbra_box_faces[11].i = 2; _umbra_box_faces[11].j = 3; _umbra_box_faces[11].k = 7;
}
/**
** UmbraCommanderClass
** This is our commander for recording the results of a visibility query to Umbra
*/
class UmbraCommanderClass : public Umbra::Commander
{
public:
UmbraCommanderClass(void) : VisObjList(NULL)
{
}
void Set_List(RefPhysListClass & visible_obj_list)
{
VisObjList = &visible_obj_list;
}
virtual void command(Command cmd)
{
WWASSERT(VisObjList != NULL);
if (cmd == Umbra::Commander::INSTANCE_VISIBLE)
{
const Umbra::Object * obj = getInstance()->getObject();
if (obj != NULL) {
VisObjList->Add((PhysClass *)(obj->getUserPointer()));
}
}
}
protected:
RefPhysListClass * VisObjList;
};
/*
** UmbraSupport implementation
*/
void UmbraSupport::Init(void)
{
/*
** Initialize UMBRA
*/
Umbra::Library::init(Umbra::LibraryDefs::COLUMN_MAJOR);
/*
** Create the dummy sphere model
*/
Umbra::Vector3 center;
center.v[0] = 0.0; center.v[1] = 0.0; center.v[2] = 0.0;
_DummySphere = new Umbra::SphereModel(center,1.0);
/*
** Create a Cell to put everything (we don't have portals so everything is in one cell)
*/
_TheCell = new Umbra::Cell;
/*
** Create the camera
*/
_TheCamera = new Umbra::Camera;
_TheCamera->setCell(_TheCell);
// _TheCamera->setParameters( 640,480,0);
// _TheCamera->setParameters( 640,480,Umbra::Camera::VIEWFRUSTUM_CULLING);
_TheCamera->setParameters( 640,480,Umbra::Camera::VIEWFRUSTUM_CULLING | Umbra::Camera::OCCLUSION_CULLING);
/*
** Create the commander
*/
_TheCommander = new UmbraCommanderClass;
}
void UmbraSupport::Shutdown(void)
{
/*
** Release everything
*/
delete _TheCommander;
_TheCommander = NULL;
_TheCamera->release();
_TheCamera = NULL;
_TheCell->release();
_TheCell = NULL;
_DummySphere->release();
_DummySphere = NULL;
/*
** UMBRA shutdown
*/
Umbra::Library::exit();
}
void UmbraSupport::Enable_Umbra(bool onoff)
{
_UmbraEnabled = onoff;
}
bool UmbraSupport::Is_Umbra_Enabled(void)
{
return _UmbraEnabled;
}
float UmbraSupport::Get_Umbra_Memory_Consumption(void)
{
return Umbra::Library::getStatistic(Umbra::Library::STAT_MEMORYUSED);
}
Umbra::Model * UmbraSupport::Peek_Dummy_Sphere(void)
{
return _DummySphere;
}
Umbra::Cell * UmbraSupport::Peek_Umbra_Cell(void)
{
return _TheCell;
}
Umbra::Camera * UmbraSupport::Peek_Umbra_Camera(void)
{
return _TheCamera;
}
Umbra::Model * UmbraSupport::Create_Box_Model(const AABoxClass & inputbox)
{
AABoxClass objbox(inputbox);
if (objbox.Extent.Length2() < 0.001f) {
objbox.Extent.Set(1,1,1);
}
_init_umbra_box(objbox);
Umbra::Model * test_model = new Umbra::MeshModel(_umbra_box_verts,_umbra_box_faces,_umbra_box_vert_count,_umbra_box_face_count);
test_model->autoRelease();
return test_model;
}
Umbra::Model * UmbraSupport::Create_Mesh_Model(MeshClass & mesh)
{
MeshModelClass * mdl = mesh.Get_Model();
Umbra::Model * new_model = NULL;
if (mdl != NULL) {
int vcount = mdl->Get_Vertex_Count();
int fcount = mdl->Get_Polygon_Count();
if ((vcount > 0) && (fcount > 0)) {
Umbra::Vector3 * uverts = new Umbra::Vector3[vcount];
Umbra::Vector3i * ufaces = new Umbra::Vector3i[fcount];
const Vector3 * wverts = mdl->Get_Vertex_Array();
const Vector3i * wfaces = mdl->Get_Polygon_Array();
for (int vi = 0; viautoRelease();
}
REF_PTR_RELEASE(mdl);
}
if (new_model != NULL) {
return new_model;
} else {
return Peek_Dummy_Sphere();
}
}
void UmbraSupport::Collect_Visible_Objects(const CameraClass & camera,RefPhysListClass & visible_obj_list)
{
Umbra::Matrix4x4 camtocell;
Matrix3D camtm;
camtm = camera.Get_Transform();
camtm.Rotate_X(DEG_TO_RAD(180.0f));
_convert_matrix_westwood_to_umbra(camtm,camtocell);
// _convert_matrix_westwood_to_umbra(camera.Get_Transform(),camtocell);
_TheCamera->setCameraToCellMatrix(camtocell);
Umbra::Frustum frustum;
_convert_frustum_westwood_to_umbra(camera,frustum);
_TheCamera->setFrustum(frustum);
_TheCommander->Set_List(visible_obj_list);
_TheCamera->resolveVisibility(_TheCommander,1,0.0);
}
void UmbraSupport::Update_Umbra_Object(PhysClass * obj)
{
Umbra::Matrix4x4 objtm;
_convert_matrix_westwood_to_umbra(obj->Get_Transform(),objtm);
obj->Peek_Umbra_Object()->setObjectToCellMatrix(objtm);
}
void UmbraSupport::Install_Umbra_Object(PhysClass * obj)
{
obj->Peek_Umbra_Object()->setCell(_TheCell);
}
void UmbraSupport::Remove_Umbra_Object(PhysClass * obj)
{
obj->Peek_Umbra_Object()->setCell(NULL);
}
#endif //UMBRASUPPORT