1021 lines
24 KiB
C++
1021 lines
24 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/>.
|
|
*/
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Utils.CPP
|
|
//
|
|
// Module containing usefull misc. utility functions
|
|
//
|
|
|
|
|
|
#include "StdAfx.H"
|
|
#include "W3DViewDoc.H"
|
|
#include "MainFrm.H"
|
|
#include "DataTreeView.H"
|
|
#include "Utils.H"
|
|
#include "Texture.H"
|
|
#include "AssetMgr.H"
|
|
#include "Agg_Def.H"
|
|
#include "HLod.H"
|
|
#include <VFW.H>
|
|
#include "RCFile.H"
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetCurrentDocument
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
CW3DViewDoc *
|
|
GetCurrentDocument (void)
|
|
{
|
|
// Assume failure
|
|
CW3DViewDoc *pCDoc = NULL;
|
|
|
|
// Get a pointer to the main window
|
|
CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
|
|
|
|
ASSERT (pCMainWnd);
|
|
if (pCMainWnd)
|
|
{
|
|
// Use the main window pointer to get a pointer
|
|
// to the current doc.
|
|
pCDoc = (CW3DViewDoc *)pCMainWnd->GetActiveDocument ();
|
|
ASSERT (pCDoc);
|
|
}
|
|
|
|
// Return the doc pointer
|
|
return pCDoc;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
//
|
|
// CenterDialogAroundTreeView
|
|
//
|
|
void
|
|
CenterDialogAroundTreeView (HWND hDlg)
|
|
{
|
|
// Params OK?
|
|
if (::IsWindow (hDlg))
|
|
{
|
|
// Get a pointer to the main window
|
|
CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
|
|
|
|
ASSERT (pCMainWnd);
|
|
if (pCMainWnd)
|
|
{
|
|
// Get the tree view pane so we can get its rectangle
|
|
CDataTreeView *pCDataTreeView = (CDataTreeView *)pCMainWnd->GetPane (0, 0);
|
|
|
|
ASSERT (pCDataTreeView);
|
|
if (pCDataTreeView)
|
|
{
|
|
// Get the bounding rectangle of the data tree view
|
|
RECT rect;
|
|
pCDataTreeView->GetWindowRect (&rect);
|
|
|
|
// Get the bounding rectangle of the dialog
|
|
RECT dialogRect;
|
|
::GetWindowRect (hDlg, &dialogRect);
|
|
|
|
// Move the dialog so its centered in the data tree view
|
|
::SetWindowPos (hDlg,
|
|
NULL,
|
|
rect.left + ((rect.right-rect.left) >> 1) - ((dialogRect.right-dialogRect.left) >> 1),
|
|
rect.top + ((rect.bottom-rect.top) >> 1) - ((dialogRect.bottom-dialogRect.top) >> 1),
|
|
0,
|
|
0,
|
|
SWP_NOSIZE | SWP_NOZORDER);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
//
|
|
// Paint_Gradient
|
|
//
|
|
void
|
|
Paint_Gradient
|
|
(
|
|
HWND hWnd,
|
|
BYTE baseRed,
|
|
BYTE baseGreen,
|
|
BYTE baseBlue
|
|
)
|
|
{
|
|
// Get the bounding rectangle so we know how much to paint
|
|
RECT rect;
|
|
::GetClientRect (hWnd, &rect);
|
|
|
|
// Determine the width, height, and width per each shade
|
|
int iWidth = rect.right-rect.left;
|
|
int iHeight = rect.bottom-rect.top;
|
|
float widthPerShade = ((float)iWidth) / 256.00F;
|
|
|
|
// Pull a hack to get the CDC for the window
|
|
HDC hDC = ::GetDC (hWnd);
|
|
CDC cDC;
|
|
cDC.Attach(hDC);
|
|
|
|
// Loop through each shade and paint its sliver
|
|
float posX = 0.00F;
|
|
for (int iShade = 0; iShade < 256; iShade ++)
|
|
{
|
|
// Paint this sliver
|
|
cDC.FillSolidRect ((int)posX,
|
|
0,
|
|
(widthPerShade >= 1.00F) ? ((int)widthPerShade)+1 : 1,
|
|
iHeight,
|
|
RGB (iShade*baseRed, iShade*baseGreen, iShade*baseBlue));
|
|
|
|
// Increment the current position
|
|
posX += widthPerShade;
|
|
}
|
|
|
|
// Release the DC
|
|
cDC.Detach ();
|
|
::ReleaseDC (hWnd, hDC);
|
|
|
|
// Validate the contents of the window so the control won't paint itself
|
|
::ValidateRect (hWnd, NULL);
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetDlgItemFloat
|
|
//
|
|
void
|
|
SetDlgItemFloat
|
|
(
|
|
HWND hdlg,
|
|
UINT child_id,
|
|
float value
|
|
)
|
|
{
|
|
// Convert the float to a string
|
|
CString text;
|
|
text.Format ("%.2f", value);
|
|
|
|
// Pass the string onto the dialog control
|
|
::SetDlgItemText (hdlg, child_id, text);
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetDlgItemFloat
|
|
//
|
|
float
|
|
GetDlgItemFloat
|
|
(
|
|
HWND hdlg,
|
|
UINT child_id
|
|
)
|
|
{
|
|
// Get the string from the window
|
|
TCHAR string_value[20];
|
|
::GetDlgItemText (hdlg, child_id, string_value, sizeof (string_value));
|
|
|
|
// Convert the string to a float and return the value
|
|
return ::atof (string_value);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Initialize_Spinner
|
|
//
|
|
void
|
|
Initialize_Spinner
|
|
(
|
|
CSpinButtonCtrl &ctrl,
|
|
float pos,
|
|
float min,
|
|
float max
|
|
)
|
|
{
|
|
//
|
|
// Convert the floats to ints and pass the settings onto the controls
|
|
//
|
|
ctrl.SetRange32 (int(min * 100), int(max * 100));
|
|
ctrl.SetPos (int(pos * 100));
|
|
|
|
//
|
|
// Set the buddy's text accordingly
|
|
//
|
|
CWnd *buddy = ctrl.GetBuddy ();
|
|
if (buddy != NULL) {
|
|
::SetWindowFloat (*buddy, pos);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Update_Spinner_Buddy
|
|
//
|
|
void
|
|
Update_Spinner_Buddy (CSpinButtonCtrl &ctrl, int delta)
|
|
{
|
|
//
|
|
// Only perform this service if the spinner isn't an auto buddy
|
|
//
|
|
if ((::GetWindowLong (ctrl, GWL_STYLE) & UDS_SETBUDDYINT) == 0) {
|
|
CWnd *buddy = ctrl.GetBuddy ();
|
|
if (buddy != NULL) {
|
|
|
|
// Get the current value, increment it, and put it back into the control
|
|
float value = ::GetWindowFloat (*buddy);
|
|
value += (((float)(delta)) / 100.0F);
|
|
|
|
//
|
|
// Validate the new position
|
|
//
|
|
int int_min = 0;
|
|
int int_max = 0;
|
|
ctrl.GetRange32 (int_min, int_max);
|
|
float float_min = ((float)int_min) / 100;
|
|
float float_max = ((float)int_max) / 100;
|
|
value = max (float_min, value);
|
|
value = min (float_max, value);
|
|
|
|
// Pass the value onto the buddy window
|
|
::SetWindowFloat (*buddy, value);
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Update_Spinner_Buddy
|
|
//
|
|
void
|
|
Update_Spinner_Buddy (HWND hspinner, int delta)
|
|
{
|
|
//
|
|
// Only perform this service if the spinner isn't an auto buddy
|
|
//
|
|
if ((::GetWindowLong (hspinner, GWL_STYLE) & UDS_SETBUDDYINT) == 0) {
|
|
HWND hbuddy_wnd = (HWND)SendMessage (hspinner, UDM_GETBUDDY, 0, 0L);
|
|
if (::IsWindow (hbuddy_wnd)) {
|
|
|
|
// Get the current value, increment it, and put it back into the control
|
|
float value = ::GetWindowFloat (hbuddy_wnd);
|
|
value += (((float)(delta)) / 100.0F);
|
|
|
|
//
|
|
// Validate the new position
|
|
//
|
|
int int_min = 0;
|
|
int int_max = 0;
|
|
SendMessage (hspinner, UDM_GETRANGE32, (WPARAM)&int_min, (LPARAM)&int_max);
|
|
float float_min = ((float)int_min) / 100;
|
|
float float_max = ((float)int_max) / 100;
|
|
value = max (float_min, value);
|
|
value = min (float_max, value);
|
|
|
|
// Pass the value onto the buddy window
|
|
::SetWindowFloat (hbuddy_wnd, value);
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Enable_Dialog_Controls
|
|
//
|
|
void
|
|
Enable_Dialog_Controls (HWND dlg,bool onoff)
|
|
{
|
|
//
|
|
// Loop over all sub-windows enable/disabling everything except for
|
|
// the static text controls
|
|
//
|
|
for (HWND child = ::GetWindow(dlg,GW_CHILD) ; child != NULL ; child = ::GetWindow(child,GW_HWNDNEXT)) {
|
|
char buf[64];
|
|
::GetClassName(child,buf,sizeof(buf));
|
|
if (stricmp(buf,"STATIC") != 0) {
|
|
::EnableWindow(child,onoff);
|
|
}
|
|
}
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetWindowFloat
|
|
//
|
|
void
|
|
SetWindowFloat
|
|
(
|
|
HWND hwnd,
|
|
float value
|
|
)
|
|
{
|
|
// Convert the float to a string
|
|
CString text;
|
|
text.Format ("%.3f", value);
|
|
|
|
// Pass the string onto the window
|
|
::SetWindowText (hwnd, text);
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetWindowFloat
|
|
//
|
|
float
|
|
GetWindowFloat (HWND hwnd)
|
|
{
|
|
// Get the string from the window
|
|
TCHAR string_value[20];
|
|
::GetWindowText (hwnd, string_value, sizeof (string_value));
|
|
|
|
// Convert the string to a float and return the value
|
|
return ::atof (string_value);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Asset_Name_From_Filename
|
|
//
|
|
CString
|
|
Asset_Name_From_Filename (LPCTSTR filename)
|
|
{
|
|
// Get the filename from this path
|
|
CString asset_name = ::Get_Filename_From_Path (filename);
|
|
|
|
// Find the index of the extension (if exists)
|
|
int extension = asset_name.ReverseFind ('.');
|
|
|
|
// Strip off the extension
|
|
if (extension != -1) {
|
|
asset_name = asset_name.Left (extension);
|
|
}
|
|
|
|
// Return the name of the asset
|
|
return asset_name;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Filename_From_Asset_Name
|
|
//
|
|
CString
|
|
Filename_From_Asset_Name (LPCTSTR asset_name)
|
|
{
|
|
// The filename is simply the asset name plus the .w3d extension
|
|
CString filename = asset_name + CString (".w3d");
|
|
|
|
// Return the filename
|
|
return filename;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Filename_From_Path
|
|
//
|
|
CString
|
|
Get_Filename_From_Path (LPCTSTR path)
|
|
{
|
|
// Find the last occurance of the directory deliminator
|
|
LPCTSTR filename = ::strrchr (path, '\\');
|
|
if (filename != NULL) {
|
|
// Increment past the directory deliminator
|
|
filename ++;
|
|
} else {
|
|
filename = path;
|
|
}
|
|
|
|
// Return the filename part of the path
|
|
return CString (filename);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Strip_Filename_From_Path
|
|
//
|
|
CString
|
|
Strip_Filename_From_Path (LPCTSTR path)
|
|
{
|
|
// Copy the path to a buffer we can modify
|
|
TCHAR temp_path[MAX_PATH];
|
|
::lstrcpy (temp_path, path);
|
|
|
|
// Find the last occurance of the directory deliminator
|
|
LPTSTR filename = ::strrchr (temp_path, '\\');
|
|
if (filename != NULL) {
|
|
// Strip off the filename
|
|
filename[0] = 0;
|
|
}
|
|
|
|
// Return the path only
|
|
return CString (temp_path);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Create_DIB_Section
|
|
//
|
|
HBITMAP
|
|
Create_DIB_Section
|
|
(
|
|
UCHAR **pbits,
|
|
int width,
|
|
int height
|
|
)
|
|
{
|
|
// Set-up the fields of the BITMAPINFOHEADER
|
|
BITMAPINFOHEADER bitmap_info;
|
|
bitmap_info.biSize = sizeof (BITMAPINFOHEADER);
|
|
bitmap_info.biWidth = width;
|
|
bitmap_info.biHeight = -height; // Top-down DIB uses negative height
|
|
bitmap_info.biPlanes = 1;
|
|
bitmap_info.biBitCount = 24;
|
|
bitmap_info.biCompression = BI_RGB;
|
|
bitmap_info.biSizeImage = ((width * height) * 3);
|
|
bitmap_info.biXPelsPerMeter = 0;
|
|
bitmap_info.biYPelsPerMeter = 0;
|
|
bitmap_info.biClrUsed = 0;
|
|
bitmap_info.biClrImportant = 0;
|
|
|
|
// Get a temporary screen DC
|
|
HDC hscreen_dc = ::GetDC (NULL);
|
|
|
|
// Create a bitmap that we can access the bits directly of
|
|
HBITMAP hbitmap = ::CreateDIBSection (hscreen_dc,
|
|
(const BITMAPINFO *)&bitmap_info,
|
|
DIB_RGB_COLORS,
|
|
(void **)pbits,
|
|
NULL,
|
|
0L);
|
|
|
|
// Release our temporary screen DC
|
|
::ReleaseDC (NULL, hscreen_dc);
|
|
return hbitmap;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Make_Bitmap_From_Texture
|
|
//
|
|
HBITMAP
|
|
Make_Bitmap_From_Texture (TextureClass &texture, int width, int height)
|
|
{
|
|
HBITMAP hbitmap = NULL;
|
|
#ifdef WW3D_DX8
|
|
srColorSurfaceIFace *surface = NULL;
|
|
|
|
// What type of texture is this?
|
|
switch (texture.getClassID ())
|
|
{
|
|
case srClass::ID_TEXTURE_FILE:
|
|
{
|
|
// Hopefully get the image data
|
|
srTextureIFace::MultiRequest info = { 0 };
|
|
info.levels[0] = new srColorSurface (srColorSurface::ARGB0444, width, height);
|
|
texture.getMipmapData (info);
|
|
surface = info.levels[0];
|
|
}
|
|
break;
|
|
|
|
case ID_MANUAL_ANIM_TEXTURE_INSTANCE_CLASS:
|
|
case ID_TIME_ANIM_TEXTURE_INSTANCE_CLASS:
|
|
case ID_RESIZEABLE_TEXTURE_INSTANCE_CLASS:
|
|
{
|
|
VariableTextureClass *psource = ((ResizeableTextureInstanceClass &)texture).Peek_Source();
|
|
if (psource != NULL) {
|
|
|
|
// Hopefully get the image data
|
|
srTextureIFace::MultiRequest info = { 0 };
|
|
info.levels[0] = new srColorSurface (srColorSurface::ARGB0444, width, height);
|
|
psource->Get_Mipmap_Data (0, info);
|
|
surface = info.levels[0];
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ID_INDIRECT_TEXTURE_CLASS:
|
|
{
|
|
srTextureIFace *preal_texture = ((IndirectTextureClass &)texture).Get_Texture ();
|
|
hbitmap = ::Make_Bitmap_From_Texture (*preal_texture, width, height);
|
|
SR_RELEASE (preal_texture);
|
|
}
|
|
break;
|
|
|
|
// Unknown texture type
|
|
default:
|
|
ASSERT (0);
|
|
break;
|
|
}
|
|
|
|
|
|
if (surface != NULL) {
|
|
|
|
int src_width = surface->getWidth ();
|
|
int src_height = surface->getHeight ();
|
|
|
|
// Create a DIB section for fast 'blitting'
|
|
UCHAR *pbits = NULL;
|
|
hbitmap = ::Create_DIB_Section (&pbits, width, height);
|
|
|
|
ASSERT (hbitmap != NULL);
|
|
ASSERT (pbits != NULL);
|
|
if (pbits != NULL) {
|
|
|
|
float src_bits_per_pixel = (float)src_width / (float)width;
|
|
float src_bits_per_scanline = (float)src_height / (float)height;
|
|
float curr_src_pixel = 0;
|
|
float curr_src_row = 0;
|
|
|
|
// Window's bitmaps are DWORD aligned, so make sure
|
|
// we take that into account.
|
|
int alignment_offset = (width * 3) % 4;
|
|
alignment_offset = (alignment_offset != 0) ? (4 - alignment_offset) : 0;
|
|
|
|
// Copy the bits into the windows DIB section
|
|
int index = 0;
|
|
for (int y = 0; y < height; y ++) {
|
|
for (int x = 0; x < width; x ++) {
|
|
|
|
// Grab the pixel from the source buffer and stuff it into the dest
|
|
srARGB pixel = surface->getPixel (curr_src_pixel, curr_src_row);
|
|
pbits[index++] = pixel[srARGB::B];
|
|
pbits[index++] = pixel[srARGB::G];
|
|
pbits[index++] = pixel[srARGB::R];
|
|
|
|
// Increment our source counter (the src size and dest don't have to match)
|
|
curr_src_pixel += src_bits_per_pixel;
|
|
}
|
|
|
|
// Reset our src-to-dest conversion data
|
|
curr_src_pixel = 0;
|
|
curr_src_row += src_bits_per_scanline;
|
|
|
|
// Skip past the padded bytes
|
|
index += alignment_offset;
|
|
}
|
|
}
|
|
|
|
surface->release ();
|
|
}
|
|
#endif
|
|
// Return a handle to the bitmap
|
|
return hbitmap;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Texture_Name
|
|
//
|
|
CString
|
|
Get_Texture_Name (TextureClass &texture)
|
|
{
|
|
CString name;
|
|
|
|
// What type of texture is this?
|
|
#ifdef WW3D_DX8
|
|
switch (texture.getClassID ())
|
|
{
|
|
case srClass::ID_TEXTURE_FILE:
|
|
name = texture.getName ();
|
|
break;
|
|
|
|
case ID_MANUAL_ANIM_TEXTURE_INSTANCE_CLASS:
|
|
case ID_TIME_ANIM_TEXTURE_INSTANCE_CLASS:
|
|
case ID_RESIZEABLE_TEXTURE_INSTANCE_CLASS:
|
|
{
|
|
VariableTextureClass *psource = ((ResizeableTextureInstanceClass &)texture).Peek_Source();
|
|
if (psource != NULL) {
|
|
name = psource->getName ();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ID_INDIRECT_TEXTURE_CLASS:
|
|
{
|
|
srTextureIFace *preal_texture = ((IndirectTextureClass &)texture).Get_Texture ();
|
|
if (preal_texture != NULL) {
|
|
name = ::Get_Texture_Name (*preal_texture);
|
|
SR_RELEASE (preal_texture);
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Unknown texture type
|
|
default:
|
|
ASSERT (0);
|
|
break;
|
|
}
|
|
#else
|
|
name = texture.Get_Texture_Name();
|
|
#endif
|
|
|
|
// Return the texture's name
|
|
return name;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Build_Emitter_List
|
|
//
|
|
void
|
|
Build_Emitter_List
|
|
(
|
|
RenderObjClass &render_obj,
|
|
DynamicVectorClass<CString> &list
|
|
)
|
|
{
|
|
// Loop through all this render obj's sub-obj's
|
|
for (int index = 0; index < render_obj.Get_Num_Sub_Objects (); index ++) {
|
|
RenderObjClass *psub_obj = render_obj.Get_Sub_Object (index);
|
|
if (psub_obj != NULL) {
|
|
|
|
// Is this sub-obj an emitter?
|
|
if (psub_obj->Class_ID () == RenderObjClass::CLASSID_PARTICLEEMITTER) {
|
|
|
|
// Is this emitter already in the list?
|
|
bool found = false;
|
|
for (int list_index = 0; (list_index < list.Count ()) && !found; list_index++) {
|
|
if (::lstrcmpi (list[list_index], psub_obj->Get_Name ()) == 0) {
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
// Add this emitter to the list if necessary
|
|
if (!found) {
|
|
list.Add (psub_obj->Get_Name ());
|
|
}
|
|
}
|
|
|
|
// Recursivly add emitters to the list
|
|
Build_Emitter_List (*psub_obj, list);
|
|
MEMBER_RELEASE (psub_obj);
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Is_Aggregate
|
|
//
|
|
bool
|
|
Is_Aggregate (const char *asset_name)
|
|
{
|
|
// Assume that the asset isn't an aggregate
|
|
bool retval = false;
|
|
|
|
// Check to see if this object is an aggregate
|
|
RenderObjClass *prender_obj = WW3DAssetManager::Get_Instance()->Create_Render_Obj (asset_name);
|
|
if ((prender_obj != NULL) &&
|
|
(prender_obj->Get_Base_Model_Name () != NULL))
|
|
{
|
|
retval = true;
|
|
}
|
|
|
|
// Free our hold on the temporary render object
|
|
MEMBER_RELEASE (prender_obj);
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Rename_Aggregate_Prototype
|
|
//
|
|
void
|
|
Rename_Aggregate_Prototype
|
|
(
|
|
const char *old_name,
|
|
const char *new_name
|
|
)
|
|
{
|
|
// Params valid?
|
|
if ((old_name != NULL) &&
|
|
(new_name != NULL) &&
|
|
(::lstrcmpi (old_name, new_name) != 0)) {
|
|
|
|
// Get the prototype from the asset manager
|
|
AggregatePrototypeClass *proto = NULL;
|
|
proto = (AggregatePrototypeClass *)WW3DAssetManager::Get_Instance ()->Find_Prototype (old_name);
|
|
if (proto != NULL) {
|
|
|
|
// Copy the definition from the prototype and remove the prototype
|
|
AggregateDefClass *pdefinition = proto->Get_Definition ();
|
|
AggregateDefClass *pnew_definition = pdefinition->Clone ();
|
|
WW3DAssetManager::Get_Instance ()->Remove_Prototype (old_name);
|
|
|
|
// Rename the definition, create a new prototype, and add it to the asset manager
|
|
pnew_definition->Set_Name (new_name);
|
|
proto = new AggregatePrototypeClass (pnew_definition);
|
|
WW3DAssetManager::Get_Instance ()->Add_Prototype (proto);
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Is_Real_LOD
|
|
//
|
|
bool
|
|
Is_Real_LOD (const char *asset_name)
|
|
{
|
|
// Assume that the asset isn't a true LOD (HLOD w/ more than one
|
|
bool retval = false;
|
|
|
|
// Check to see if this object is an aggregate
|
|
RenderObjClass *prender_obj = WW3DAssetManager::Get_Instance()->Create_Render_Obj (asset_name);
|
|
if ((prender_obj != NULL) &&
|
|
(prender_obj->Class_ID () == RenderObjClass::CLASSID_HLOD) &&
|
|
(((HLodClass *)prender_obj)->Get_LOD_Count () > 1)) {
|
|
retval = true;
|
|
}
|
|
|
|
// Free our hold on the temporary render object
|
|
MEMBER_RELEASE (prender_obj);
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_File_Time
|
|
//
|
|
bool
|
|
Get_File_Time
|
|
(
|
|
LPCTSTR path,
|
|
LPFILETIME pcreation_time,
|
|
LPFILETIME paccess_time,
|
|
LPFILETIME pwrite_time
|
|
)
|
|
{
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Attempt to open the file
|
|
HANDLE hfile = ::CreateFile (path,
|
|
0,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0L,
|
|
NULL);
|
|
|
|
ASSERT (hfile != INVALID_HANDLE_VALUE);
|
|
if (hfile != INVALID_HANDLE_VALUE) {
|
|
|
|
// Get the mod times for this file
|
|
retval = (::GetFileTime (hfile, pcreation_time, paccess_time, pwrite_time) == TRUE);
|
|
|
|
// Close the file
|
|
SAFE_CLOSE (hfile);
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Are_Glide_Drivers_Acceptable
|
|
//
|
|
bool
|
|
Are_Glide_Drivers_Acceptable (void)
|
|
{
|
|
// Assume success
|
|
bool retval = true;
|
|
|
|
// Is this windows NT?
|
|
OSVERSIONINFO version = { sizeof (OSVERSIONINFO), 0 };
|
|
if (::GetVersionEx (&version) && (version.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
|
|
|
|
// Now assume failure
|
|
retval = false;
|
|
|
|
// Get a path to the system directory
|
|
TCHAR path[MAX_PATH];
|
|
::GetSystemDirectory (path, sizeof (path));
|
|
::Delimit_Path (path);
|
|
|
|
// Build the full path of the 2 main drivers
|
|
CString glide2x = CString (path) + "glide2x.dll";
|
|
CString glide3x = CString (path) + "glide3x.dll";
|
|
|
|
// Get the creation time of the glide2x driver
|
|
FILETIME file_time = { 0 };
|
|
if (::Get_File_Time (glide2x, NULL, NULL, &file_time)) {
|
|
CTime time_obj (file_time);
|
|
retval = ((time_obj.GetYear () == 1998) && (time_obj.GetMonth () == 12)) || (time_obj.GetYear () > 1998);
|
|
}
|
|
|
|
// Get the creation time of the glide3x driver
|
|
if (::Get_File_Time (glide3x, NULL, NULL, &file_time)) {
|
|
CTime time_obj (file_time);
|
|
retval = ((time_obj.GetYear () == 1998) && (time_obj.GetMonth () == 12)) || (time_obj.GetYear () > 1998);
|
|
}
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Load_RC_Texture
|
|
//
|
|
TextureClass *
|
|
Load_RC_Texture (LPCTSTR resource_name)
|
|
{
|
|
TextureClass *texture = NULL;
|
|
|
|
//
|
|
// Load the cursor file image from this binaries resources
|
|
//
|
|
ResourceFileClass resource_file (::AfxGetResourceHandle (), resource_name);
|
|
unsigned char *res_data = resource_file.Peek_Data ();
|
|
unsigned int data_size = resource_file.Size ();
|
|
|
|
//
|
|
// Create a texture from the raw image data
|
|
//
|
|
#ifdef WW3D_DX8
|
|
srBinIMStream stream (res_data, data_size);
|
|
srSurfaceIOManager::SurfaceImporter *importer = srCore.getSurfaceIOManager()->getImporter (".tga");
|
|
if (importer != NULL) {
|
|
srColorSurfaceIFace *surface = importer->importSurface (stream, srSurfaceIOManager::ImportInfo());
|
|
if (surface != NULL) {
|
|
texture = new srTextureMap (surface);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Reutrn a pointer to the new texture
|
|
return texture;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Resolve_Path
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
Resolve_Path (CString &filename)
|
|
{
|
|
if (filename.Find ('\\') == -1) {
|
|
char path[MAX_PATH];
|
|
::GetCurrentDirectory (MAX_PATH, path);
|
|
::Delimit_Path (path);
|
|
filename = CString (path) + filename;
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Find_Missing_Textures
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
Find_Missing_Textures
|
|
(
|
|
DynamicVectorClass<CString> & list,
|
|
LPCTSTR name,
|
|
int frame_count
|
|
)
|
|
{
|
|
//
|
|
// If this file doesn't exist, then add it to our list
|
|
//
|
|
if (::GetFileAttributes (name) == 0xFFFFFFFF) {
|
|
CString full_path = name;
|
|
Resolve_Path (full_path);
|
|
list.Add (full_path);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copy_File
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
bool
|
|
Copy_File
|
|
(
|
|
LPCTSTR existing_filename,
|
|
LPCTSTR new_filename,
|
|
bool force_copy
|
|
)
|
|
{
|
|
SANITY_CHECK ((existing_filename != NULL && new_filename != NULL)) {
|
|
return false;
|
|
}
|
|
|
|
// Assume failure
|
|
bool retval = false;
|
|
|
|
// Make sure we aren't copying over ourselves
|
|
bool allow_copy = (::lstrcmpi (existing_filename, new_filename) != 0);
|
|
|
|
// Strip the readonly bit off if necessary
|
|
DWORD attributes = ::GetFileAttributes (new_filename);
|
|
if (allow_copy &&
|
|
(attributes != 0xFFFFFFFF) &&
|
|
((attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY))
|
|
{
|
|
if (force_copy) {
|
|
::SetFileAttributes (new_filename, attributes & (~FILE_ATTRIBUTE_READONLY));
|
|
} else {
|
|
allow_copy = false;
|
|
}
|
|
}
|
|
|
|
// Perform the copy operation!
|
|
if (allow_copy) {
|
|
retval = (::CopyFile (existing_filename, new_filename, FALSE) == TRUE);
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Graphic_View
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
CGraphicView *
|
|
Get_Graphic_View (void)
|
|
{
|
|
CGraphicView *view = NULL;
|
|
|
|
//
|
|
// Get the view from the current document
|
|
//
|
|
CW3DViewDoc *doc = GetCurrentDocument ();
|
|
if (doc != NULL) {
|
|
view = doc->GetGraphicView ();
|
|
}
|
|
|
|
return view;
|
|
}
|