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/W3DShellExt/propshet.cpp

430 lines
15 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/>.
*/
#include "StdAfx.h"
#include "priv.h"
#include "shellext.h"
#include "resource.h"
#include <stdio.h>
#include "wdump.h"
#include "WdumpDoc.h"
#include "W3D_File.h"
#include <commctrl.h>
//===============================================================
// *********** G L O B A L S ************************
extern UINT g_DllRefCount; // Reference count of this DLL.
extern HINSTANCE g_DllInstance; // Handle to this DLL itself.
//===============================================================
// *********** F U N C T I O N S *********************
///////////////////////////////////////
UINT CALLBACK W3DPageCallback(HWND hWnd,
UINT uMessage,
LPPROPSHEETPAGE ppsp){
switch(uMessage){
case PSPCB_CREATE:
return TRUE;
case PSPCB_RELEASE:{
if (ppsp->lParam){
((LPCSHELLEXT)(ppsp->lParam))->Release();
}
return TRUE;
}
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ShowHideControls(HWND hDlg, bool show){
HWND hControl = GetWindow(hDlg, GW_CHILD);
while(hControl != NULL){
ShowWindow(hControl,show?SW_SHOW:SW_HIDE);
hControl = GetWindow(hControl, GW_HWNDNEXT);
}
ShowWindow(GetDlgItem(hDlg, IDC_NODATA),show?SW_HIDE:SW_SHOW );
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void GetItemName(ChunkItem *pItem, int id_of_interest, void* pInfo, int sizeof_struct, int& found ){
if(pItem->ID == id_of_interest){
BYTE *byte_ptr = (BYTE*) pInfo;
byte_ptr += sizeof_struct* found;
memcpy(byte_ptr,pItem->Data,pItem->Length);
found ++;
}
//Get all Sibitems for this item
POSITION p = pItem->Chunks.GetHeadPosition();
while(p != 0) {
ChunkItem *subitem = pItem->Chunks.GetNext(p);
GetItemName(subitem, id_of_interest, pInfo, sizeof_struct,found);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK AnimPageDlgProc(HWND hDlg,UINT uMessage, WPARAM wParam, LPARAM lParam){
LPPROPSHEETPAGE psp=(LPPROPSHEETPAGE)GetWindowLong(hDlg, DWL_USER);
UINT iIndex=0;
LPCSHELLEXT lpcs;
char buf[MAX_PATH];
switch (uMessage){
case WM_INITDIALOG:{
SetWindowLong(hDlg, DWL_USER, lParam);
psp = (LPPROPSHEETPAGE)lParam;
lpcs = (LPCSHELLEXT)psp->lParam;
if(!lpcs->m_FileInMemory){
lpcs->Read_SelectedFile();
}
ChunkData* pData = &(lpcs->m_WdumpDocument.m_ChunkData);
assert(pData);
POSITION ptr = pData->Chunks.GetHeadPosition();;
ASSERT(ptr);
W3dAnimHeaderStruct* pAnim = lpcs->m_AnimInfos;
int id_of_interest = W3D_CHUNK_ANIMATION_HEADER;
int sizeof_struct = sizeof W3dAnimHeaderStruct;
int found_animations(0);
while(ptr){
ChunkItem *pItem = pData->Chunks.GetNext(ptr);
GetItemName(pItem, id_of_interest, (void*)lpcs->m_AnimInfos, sizeof_struct, found_animations );
}
if(found_animations){
//So far assuming only one animation per file
SetDlgItemText(hDlg, IDC_ANIMNAME, pAnim->Name);
SetDlgItemText(hDlg, IDC_HNAME, pAnim->HierarchyName);
SetDlgItemInt(hDlg, IDC_NUMFRAMES, pAnim->NumFrames,FALSE);
//FrameRate
sprintf(buf,"%i fps",pAnim->FrameRate,FALSE);
SetDlgItemText(hDlg, IDC_FRAMERATE, buf);
//SetDlgItemInt(hDlg, IDC_FRAMERATE, pAnim->FrameRate,FALSE);
//version
sprintf(buf,"%d.%d",W3D_GET_MAJOR_VERSION(pAnim->Version),W3D_GET_MINOR_VERSION(pAnim->Version));
SetDlgItemText(hDlg, IDC_ANIMVERSION, buf);
}
//Hierarchies
ptr = pData->Chunks.GetHeadPosition();;
ASSERT(ptr);
id_of_interest = W3D_CHUNK_HIERARCHY_HEADER;
//So far assuming only one hierarchy per file
W3dHierarchyStruct* pHInfo = lpcs->m_Hierarchies;
ASSERT(pHInfo);
sizeof_struct = sizeof W3dHierarchyStruct;
int found_hierarchies(0);
while(ptr){
ChunkItem *pItem = pData->Chunks.GetNext(ptr);
GetItemName(pItem, id_of_interest, (void*)pHInfo, sizeof_struct, found_hierarchies );
}
if(found_hierarchies){
SetDlgItemText(hDlg, IDC_HIERARCHYNAME, pHInfo->Name);
SetDlgItemInt(hDlg, IDC_NUMPIVOTS, pHInfo->NumPivots,FALSE);
sprintf(buf,"%d.%d",W3D_GET_MAJOR_VERSION(pHInfo->Version),W3D_GET_MINOR_VERSION(pHInfo->Version));
SetDlgItemText(hDlg, IDC_HIERARCHYVERSION, buf);
sprintf(buf, "(%.3f, %.3f, %.3f)", pHInfo->Center.X, pHInfo->Center.Y, pHInfo->Center.Z);
SetDlgItemText(hDlg, IDC_HCENTER, buf);
}
ShowHideControls(hDlg, (found_animations + found_hierarchies)!= 0);
break;
}
case WM_DESTROY:{
RemoveProp(hDlg, "ID");
break;
}
case WM_COMMAND:
switch (LOWORD(wParam)){
case IDC_TOP3D:
//SetProp(hDlg, "ID", (HANDLE)lParam);
break;
default:
break;
}
break;
case WM_NOTIFY:
switch (((NMHDR FAR *)lParam)->code){
case PSN_SETACTIVE:
break;
case PSN_APPLY:
//User has clicked the OK or Apply button so we'll
//update the icon information in the .W3D file
lpcs = (LPCSHELLEXT)psp->lParam;
//Ask the shell to refresh the icon list...
//SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSHNOWAIT, 0, 0);
break;
default:
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
//=====================================================================================================
void SetDlgMeshParams(HWND hDlg, W3dMeshHeader3Struct*pInfo){
SetDlgItemText(hDlg,IDC_MESHNAME,pInfo->MeshName);
SetDlgItemText(hDlg,IDC_CONTAINER,pInfo->ContainerName);
SetDlgItemInt(hDlg,IDC_NUM_MATERIALS, pInfo->NumMaterials,FALSE);
SetDlgItemInt(hDlg,IDC_NUM_POLYS, pInfo->NumTris,FALSE);
SetDlgItemInt(hDlg,IDC_NUM_VERTICES, pInfo->NumVertices, FALSE);
SetDlgItemInt(hDlg,IDC_NUM_MATERIALS, pInfo->NumMaterials,FALSE);
char msg[MAX_PATH];
sprintf(msg, "%.3f", pInfo->SphRadius);
SetDlgItemText(hDlg,IDC_SPHERERADIUS,msg);
//3D Coords
//Center
sprintf(msg, "(%.3f, %.3f, %.3f)", pInfo->SphCenter.X, pInfo->SphCenter.Y, pInfo->SphCenter.Z);
SetDlgItemText(hDlg, IDC_SPHERECENTER, msg);
//Min
sprintf(msg, "(%.3f, %.3f, %.3f)", pInfo->Min.X, pInfo->Min.Y, pInfo->Min.Z);
SetDlgItemText(hDlg, IDC_MINDIM, msg);
//Max
sprintf(msg, "(%.3f, %.3f, %.3f)", pInfo->Max.X, pInfo->Max.Y, pInfo->Max.Z);
SetDlgItemText(hDlg, IDC_MAXDIM, msg);
sprintf(msg,"%d.%d",W3D_GET_MAJOR_VERSION(pInfo->Version),W3D_GET_MINOR_VERSION(pInfo->Version));
SetDlgItemText(hDlg, IDC_VERSION, msg);
}
//==========================================================================================================
BOOL CALLBACK MeshPageDlgProc(HWND hDlg,UINT uMessage, WPARAM wParam, LPARAM lParam){
LPPROPSHEETPAGE psp=(LPPROPSHEETPAGE)GetWindowLong(hDlg, DWL_USER);
UINT iIndex=0;
LPCSHELLEXT lpcs;
switch (uMessage){
case WM_INITDIALOG:{
SetWindowLong(hDlg, DWL_USER, lParam);
psp = (LPPROPSHEETPAGE)lParam;
lpcs = (LPCSHELLEXT)psp->lParam;
if(!lpcs->m_FileInMemory){
lpcs->Read_SelectedFile();
}
ChunkData* pData = &(lpcs->m_WdumpDocument.m_ChunkData);
assert(pData);
POSITION ptr = pData->Chunks.GetHeadPosition();
ASSERT(ptr);
//Look for mesh headers
W3dMeshHeader3Struct* pInfo = lpcs->m_Meshes;
int id_of_interest = W3D_CHUNK_MESH_HEADER3;
int sizeof_struct = sizeof W3dMeshHeader3Struct;
while(ptr){
ChunkItem *pItem = pData->Chunks.GetNext(ptr);
ASSERT(lpcs->m_FoundMeshes < MAX_MESH);
GetItemName(pItem, id_of_interest, (void*)(pInfo),sizeof_struct, lpcs->m_FoundMeshes );
}
if(lpcs->m_FoundMeshes){
SetDlgItemInt(hDlg,IDC_MESHNUMBER, 0,FALSE);
//Look for Textures
char pTextureInfo[MAX_TEXUTRE_NAME_LEN * MAX_MESH];
id_of_interest = W3D_CHUNK_TEXTURE_NAME;
int found_textures(0);
int sizeof_struct = MAX_TEXUTRE_NAME_LEN;
ptr = pData->Chunks.GetHeadPosition();
while(ptr){
ChunkItem *pItem = pData->Chunks.GetNext(ptr);
GetItemName(pItem, id_of_interest, (void*)pTextureInfo, sizeof_struct, found_textures );
}
for(int t_count(0); t_count < found_textures; t_count ++){
if(lpcs->NotAdded(&(pTextureInfo[t_count*MAX_TEXUTRE_NAME_LEN]))){
char* text = lpcs->m_Textures[lpcs->m_NumAdded-1].LockBuffer();
SendDlgItemMessage(hDlg, IDC_TEXTURELIST, LB_ADDSTRING,(WPARAM) 0L, (LPARAM)text);//(pTextureInfo[t_count].name)) ;
lpcs->m_Textures[lpcs->m_NumAdded-1].ReleaseBuffer();
}
}
SetDlgItemInt(hDlg,IDC_NUM_MESHES, lpcs->m_FoundMeshes,FALSE);
SetDlgMeshParams(hDlg, pInfo);
//Set Spin range
SendDlgItemMessage(hDlg, IDC_MESHSPIN, UDM_SETRANGE, (WPARAM)0L, (LPARAM)MAKELONG(lpcs->m_FoundMeshes-1,0));
}
ShowHideControls(hDlg, lpcs->m_FoundMeshes != 0);
break;
}
case WM_DESTROY:
RemoveProp(hDlg, "ID");
break;
case WM_COMMAND:
switch (LOWORD(wParam)){
case IDC_TOP3D:
//SetProp(hDlg, "ID", (HANDLE)lParam);
break;
default:
break;
}
break;
case WM_NOTIFY:
lpcs = (LPCSHELLEXT)psp->lParam;
switch (((NMHDR FAR *)lParam)->code){
case PSN_SETACTIVE:
break;
case PSN_APPLY:
//Ask the shell to refresh the icon list...
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSHNOWAIT, 0, 0);
break;
case UDN_DELTAPOS:{
lpcs = (LPCSHELLEXT)psp->lParam;
W3dMeshHeader3Struct* pInfo = lpcs->m_Meshes;
LPNMUPDOWN lpUD = (LPNMUPDOWN) lParam;
int mesh_num = lpUD->iDelta + lpUD->iPos;
if(mesh_num >= 0 && mesh_num < lpcs->m_FoundMeshes){
SetDlgMeshParams(hDlg, pInfo+mesh_num);
}
break;
}
default:
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
/////////////////////////////////////////////////////////////
BOOL CALLBACK PreviewPageDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam){
LPPROPSHEETPAGE psp=(LPPROPSHEETPAGE)GetWindowLong(hDlg, DWL_USER);
UINT iIndex(0);
LPCSHELLEXT lpcs;
switch (uMessage){
case WM_INITDIALOG:{
SetWindowLong(hDlg, DWL_USER, lParam);
psp = (LPPROPSHEETPAGE)lParam;
lpcs = (LPCSHELLEXT)psp->lParam;
if(!lpcs->m_FileInMemory){
lpcs->Read_SelectedFile();
}
break;
}
case WM_DESTROY:{
RemoveProp(hDlg, "ID");
break;
}
case WM_COMMAND:
switch (LOWORD(wParam)){
case IDC_TOP3D:
//SetProp(hDlg, "ID", (HANDLE)lParam);
break;
default:
break;
}
break;
case WM_NOTIFY:
switch (((NMHDR FAR *)lParam)->code){
case PSN_SETACTIVE:
break;
case PSN_APPLY:
//User has clicked the OK or Apply button so we'll
//update the icon information in the .W3D file
lpcs = (LPCSHELLEXT)psp->lParam;
//Ask the shell to refresh the icon list...
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSHNOWAIT, 0, 0);
break;
default:
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
// PURPOSE: Called by the shell just before the property sheet is displayed.
STDMETHODIMP CShellExt::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, //Pointer to the Shell's AddPage function
LPARAM lParam){ //Passed as second parameter to lpfnAddPage
m_FileInMemory = false;
PROPSHEETPAGE psp;
HPROPSHEETPAGE hpage;
FORMATETC fmte = {CF_HDROP,(DVTARGETDEVICE FAR *)NULL,DVASPECT_CONTENT,-1, TYMED_HGLOBAL };
STGMEDIUM medium;
HRESULT hres = 0;
// char buf[MAX_PATH];
if (m_pDataObj){ //Paranoid check, m_pDataObj should have something by now...
hres = m_pDataObj->GetData(&fmte, &medium);
}
if (SUCCEEDED(hres)){
//Find out how many files the user has selected...
UINT cbFiles = 0;
LPCSHELLEXT lpcsext = this;
if (medium.hGlobal){
cbFiles = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, 0, 0);
}
if (cbFiles < 2){
if (cbFiles){
DragQueryFile((HDROP)medium.hGlobal,0, m_SelectedFile, sizeof(m_SelectedFile));
}
psp.dwSize = sizeof(psp); // no extra data.
psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_USECALLBACK;
psp.hInstance = g_DllInstance;
psp.pszTemplate = MAKEINTRESOURCE(IDD_MESH);
psp.hIcon = 0;
psp.pszTitle = " Meshes ";
psp.pfnDlgProc = MeshPageDlgProc;
psp.pcRefParent = &g_DllRefCount;
psp.pfnCallback = W3DPageCallback;
psp.lParam = (LPARAM)lpcsext;
AddRef();
hpage = CreatePropertySheetPage(&psp);
if(hpage){
if (!lpfnAddPage(hpage, lParam)){
DestroyPropertySheetPage(hpage);
Release();
}
}
//Animation Page
psp.pszTemplate = MAKEINTRESOURCE(IDD_ANIMPAGE);
psp.pszTitle = "Animations";
psp.pfnDlgProc = AnimPageDlgProc;
AddRef();
hpage = CreatePropertySheetPage(&psp);
if(hpage){
if (!lpfnAddPage(hpage, lParam)){
DestroyPropertySheetPage(hpage);
Release();
}
}
//Preview Page
psp.pszTemplate = MAKEINTRESOURCE(IDD_PREVIEW);
psp.pszTitle = " Preview ";
psp.pfnDlgProc = PreviewPageDlgProc;
AddRef();
hpage = CreatePropertySheetPage(&psp);
if(hpage){
if (!lpfnAddPage(hpage, lParam)){
DestroyPropertySheetPage(hpage);
Release();
}
}
}
}
return NOERROR;
}
// PURPOSE: Called by the shell only for Control Panel property sheet
STDMETHODIMP CShellExt::ReplacePage(UINT uPageID, //ID of page to be replaced
LPFNADDPROPSHEETPAGE lpfnReplaceWith, //Pointer to the Shell's Replace function
LPARAM lParam){ //Passed as second parameter to lpfnReplaceWith
return E_FAIL;//we don't support this function. It should never be
}