You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

387 lines
12 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, 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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "HeadSpin.h"
#include "plTextureSearch.h"
#include "resource.h"
#include "hsUtils.h"
#define PB2Export __declspec( dllexport ) // Because I don't feel like including all the paramblock crap
#include "pbbitmap.h"
#include "bmmlib.h"
#include "IMtlEdit.h"
#include "plMtlCollector.h"
#include "plMaxAccelerators.h"
#include "MaxPlasmaMtls/Layers/plPlasmaMAXLayer.h"
#ifdef MAXASS_AVAILABLE
#include "../../AssetMan/PublicInterface/MaxAssInterface.h"
#endif
// Not a class member so we don't have to make everyone who uses this know about AssetMan
#ifdef MAXASS_AVAILABLE
static jvUniqueId gAssetID;
#endif
plTextureSearch::plTextureSearch() : fDlg(NULL)
{
#ifdef MAXASS_AVAILABLE
gAssetID.SetEmpty();
#endif
memset(fFileName, 0, sizeof(fFileName));
}
plTextureSearch& plTextureSearch::Instance()
{
static plTextureSearch theInstance;
return theInstance;
}
void plTextureSearch::Toggle()
{
if (!fDlg)
{
fDlg = CreateDialog(hInstance,
MAKEINTRESOURCE(IDD_FIND_TEXTURE),
GetCOREInterface()->GetMAXHWnd(),
ForwardDlgProc);
HWND hList = GetDlgItem(fDlg, IDC_TEXTURE_LIST);
LVCOLUMN lvc;
lvc.mask = LVCF_TEXT;
lvc.pszText = "Material";
ListView_InsertColumn(hList, 0, &lvc);
lvc.pszText = "Layer";
ListView_InsertColumn(hList, 1, &lvc);
lvc.pszText = "Texture";
ListView_InsertColumn(hList, 2, &lvc);
IUpdateTextures(kUpdateLoadList);
GetCOREInterface()->RegisterDlgWnd(fDlg);
ShowWindow(fDlg, SW_SHOW);
}
else
{
DestroyWindow(fDlg);
fDlg = NULL;
}
}
BOOL plTextureSearch::ForwardDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
return Instance().DlgProc(hDlg, msg, wParam, lParam);
}
BOOL plTextureSearch::DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_ACTIVATE:
if (LOWORD(wParam) == WA_INACTIVE)
plMaxAccelerators::Enable();
else
plMaxAccelerators::Disable();
return TRUE;
case WM_COMMAND:
if (HIWORD(wParam) == BN_CLICKED)
{
int id = LOWORD(wParam);
if (id == IDCANCEL)
{
Toggle();
return TRUE;
}
else if (id == IDC_UPDATE_BUTTON)
{
IUpdateTextures(kUpdateLoadList);
return TRUE;
}
else if (id == IDC_REPLACE_ALL_BUTTON)
{
if (hsMessageBox("Are you sure?", "Confirmation", hsMessageBoxYesNo) == hsMBoxYes)
{
IUpdateTextures(kUpdateReplace);
}
return TRUE;
}
else if (id == IDC_SET_ALL_BUTTON)
{
if (hsMessageBox("Are you sure?", "Confirmation", hsMessageBoxYesNo) == hsMBoxYes)
{
IUpdateTextures(kUpdateSetSize);
}
return TRUE;
}
else if (id == IDC_REPLACE_BUTTON)
{
IPickReplaceTexture();
return TRUE;
}
}
else if (HIWORD(wParam) == EN_CHANGE && LOWORD(wParam) == IDC_FIND_EDIT)
{
bool findText = (SendDlgItemMessage(hDlg, IDC_FIND_EDIT, EM_LINELENGTH, 0, 0) > 0);
bool replace = (fFileName[0] != '\0');
EnableWindow(GetDlgItem(hDlg, IDC_REPLACE_BUTTON), findText);
EnableWindow(GetDlgItem(hDlg, IDC_REPLACE_ALL_BUTTON), findText && replace);
return TRUE;
}
break;
case WM_NOTIFY:
{
NMHDR* nmhdr = (NMHDR*)lParam;
// User double-clicked a material in the texture list
if (nmhdr->idFrom == IDC_TEXTURE_LIST && nmhdr->code == NM_DBLCLK)
{
NMITEMACTIVATE* itema = (NMITEMACTIVATE*)lParam;
if (itema->iItem != -1)
{
// Get the material the user clicked on
HWND hList = GetDlgItem(fDlg, IDC_TEXTURE_LIST);
LV_ITEM item;
item.iItem = itema->iItem;
item.mask = LVIF_PARAM;
ListView_GetItem(hList, &item);
Mtl* mtl = (Mtl*)item.lParam;
// Make sure the material is still in the scene (paranoid check)
MtlSet mtls;
plMtlCollector::GetMtls(&mtls, nil, plMtlCollector::kPlasmaOnly | plMtlCollector::kNoMultiMtl);
if (mtls.find(mtl) != mtls.end())
{
// Put the material in the current slot of the material editor
IMtlEditInterface* mtlInterface = GetMtlEditInterface();
int slot = mtlInterface->GetActiveMtlSlot();
mtlInterface->PutMtlToMtlEditor(mtl, slot);
}
}
return TRUE;
}
}
break;
}
return FALSE;
}
static int FloorPow2(int value)
{
int v;
for (v = 1; v <= value; v <<= 1);
return v >> 1;
}
void plTextureSearch::IUpdateTextures(plTextureSearch::Update update)
{
MtlSet mtls;
plMtlCollector::GetMtls(&mtls, nil, plMtlCollector::kPlasmaOnly | plMtlCollector::kNoMultiMtl);
char searchStr[256];
GetDlgItemText(fDlg, IDC_FIND_EDIT, searchStr, sizeof(searchStr));
strlwr(searchStr);
HWND hList = GetDlgItem(fDlg, IDC_TEXTURE_LIST);
ListView_DeleteAllItems(hList);
int sizeX = -1, sizeY = -1;
HWND hCombo = GetDlgItem(fDlg, IDC_SIZE_COMBO);
// If we're updating the size, get whatever the user selected
if (update == kUpdateSetSize)
{
int sel = ComboBox_GetCurSel(hCombo);
UInt32 data = ComboBox_GetItemData(hCombo, sel);
sizeX = LOWORD(data);
sizeY = HIWORD(data);
}
MtlSet::iterator it = mtls.begin();
for (; it != mtls.end(); it++)
{
Mtl *mtl = (*it);
LayerSet layers;
plMtlCollector::GetMtlLayers(mtl, layers);
LayerSet::iterator layerIt = layers.begin();
for (; layerIt != layers.end(); layerIt++)
{
plPlasmaMAXLayer *layer = (*layerIt);
int numBitmaps = layer->GetNumBitmaps();
for (int i = 0; i < numBitmaps; i++)
{
PBBitmap *pbbm = layer->GetPBBitmap(i);
if (pbbm)
{
const char *name = pbbm->bi.Filename();
if (name && *name != '\0')
{
char buf[256];
strncpy(buf, name, sizeof(buf));
strlwr(buf);
// If we don't have a search string, or we do and it was
// found in the texture name, add the texture to the list.
if (searchStr[0] == '\0' || strstr(buf, searchStr))
{
if (update == kUpdateLoadList)
{
LVITEM item = {0};
item.mask = LVIF_TEXT | LVIF_PARAM;
item.pszText = mtl->GetName();
item.lParam = (LPARAM)mtl; // A little dangerous, since the user could delete this
int idx = ListView_InsertItem(hList, &item);
ListView_SetItemText(hList, idx, 1, layer->GetName());
ListView_SetItemText(hList, idx, 2, (char*)name);
// If size is uninitialized or the same as the last, keep size
if ((sizeX == -1 && sizeY == -1) || (sizeX == pbbm->bi.Width() && sizeY == pbbm->bi.Height()))
{
sizeX = pbbm->bi.Width();
sizeY = pbbm->bi.Height();
}
// Otherwise clear it
else
{
sizeX = sizeY = 0;
}
}
else if (update == kUpdateReplace)
{
#ifdef MAXASS_AVAILABLE
layer->SetBitmapAssetId(gAssetID, i);
#endif
BitmapInfo info;
info.SetName(fFileName);
layer->SetBitmap(&info, i);
}
else if (update == kUpdateSetSize)
{
layer->SetExportSize(sizeX, sizeY);
}
}
}
}
}
}
}
if (update == kUpdateLoadList)
{
HWND hButton = GetDlgItem(fDlg, IDC_SET_ALL_BUTTON);
ComboBox_ResetContent(hCombo);
// If all bitmaps are the same size, enable resizing
if (sizeX != -1 && sizeX != 0)
{
sizeX = FloorPow2(sizeX);
sizeY = FloorPow2(sizeY);
char buf[256];
while (sizeX >= 4 && sizeY >= 4)
{
sprintf(buf, "%d x %d", sizeX, sizeY);
int idx = ComboBox_AddString(hCombo, buf);
ComboBox_SetItemData(hCombo, idx, MAKELPARAM(sizeX, sizeY));
sizeX >>= 1;
sizeY >>= 1;
}
ComboBox_SetCurSel(hCombo, 0);
EnableWindow(hCombo, TRUE);
EnableWindow(hButton, TRUE);
}
else
{
EnableWindow(hCombo, FALSE);
EnableWindow(hButton, FALSE);
}
}
int autoSizeType = LVSCW_AUTOSIZE;
if (ListView_GetItemCount(hList) == 0)
autoSizeType = LVSCW_AUTOSIZE_USEHEADER;
ListView_SetColumnWidth(hList, 0, autoSizeType);
ListView_SetColumnWidth(hList, 1, autoSizeType);
ListView_SetColumnWidth(hList, 2, autoSizeType);
}
void plTextureSearch::IPickReplaceTexture()
{
fFileName[0] = '\0';
// if we have the assetman plug-in, then try to use it, unless shift is held down
#ifdef MAXASS_AVAILABLE
MaxAssInterface* maxAssInterface = GetMaxAssInterface();
if (maxAssInterface && !(GetKeyState(VK_SHIFT) & 0x8000))
{
maxAssInterface->OpenBitmapDlg(gAssetID, fFileName, sizeof(fFileName));
}
else
{
gAssetID.SetEmpty();
#endif
BitmapInfo bi;
TheManager->SelectFileInput(&bi, GetCOREInterface()->GetMAXHWnd(), _T("Select Bitmap Image File"));
strcpy(fFileName, bi.Filename());
#ifdef MAXASS_AVAILABLE
}
#endif
if (fFileName[0] == '\0')
{
SetDlgItemText(fDlg, IDC_REPLACE_BUTTON, "(none)");
EnableWindow(GetDlgItem(fDlg, IDC_REPLACE_ALL_BUTTON), FALSE);
}
else
{
char fname[_MAX_FNAME+_MAX_EXT], ext[_MAX_EXT];
_splitpath(fFileName, NULL, NULL, fname, ext);
strcat(fname, ext);
SetDlgItemText(fDlg, IDC_REPLACE_BUTTON, fname);
EnableWindow(GetDlgItem(fDlg, IDC_REPLACE_ALL_BUTTON), TRUE);
}
}