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/W3DView/Utils.cpp

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;
}