|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "stdafx.h"
#pragma warning(push, 1)
#pragma warning(disable:4701 4702 4530)
#include <fstream>
#pragma warning(pop)
#include "hammer.h"
#include "TextureWindow.h"
#include "TextureBrowser.h"
#include "CustomMessages.h"
#include "IEditorTexture.h"
#include "GameConfig.h"
#include "GlobalFunctions.h"
#include "TextureSystem.h"
#include "materialsystem/imaterial.h"
#include "materialsystem/imaterialsystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
const DWORD NO_FILE_FILTER = 0xFFFFFFF0L; const int iPadding = 4; const int iTexNameFontHeight = 7; const int iTexIconHeight = 12;
BEGIN_MESSAGE_MAP(CTextureWindow, CWnd) //{{AFX_MSG_MAP(CTextureWindow)
ON_WM_PAINT() ON_WM_SIZE() ON_WM_HSCROLL() ON_WM_VSCROLL() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONDBLCLK() ON_WM_KEYDOWN() ON_WM_MOUSEWHEEL() ON_WM_CHAR() //}}AFX_MSG_MAP
END_MESSAGE_MAP()
//-----------------------------------------------------------------------------
// Purpose: Constructor. Initializes data members.
//-----------------------------------------------------------------------------
CTextureWindow::CTextureWindow(void) { bFirstPaint = TRUE;
m_szFilter[0] = '\0'; m_nFilters = 0;
m_szKeywords[0] = '\0'; m_nKeywords = 0;
m_pSpecificList = NULL; szCurTexture[0] = '\0';
m_eTextureFormat = g_pGameConfig->GetTextureFormat();
m_bEnableUpdate = true; m_nTypeFilter = ~0; m_bShowErrors = true; }
//-----------------------------------------------------------------------------
// Purpose: Destructor.
//-----------------------------------------------------------------------------
CTextureWindow::~CTextureWindow(void) { }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pParentWnd -
// rect -
//-----------------------------------------------------------------------------
void CTextureWindow::Create(CWnd *pParentWnd, RECT& rect) { static CString TextureWndClassName;
iDisplaySize = 64;
if(TextureWndClassName.IsEmpty()) { // create class
TextureWndClassName = AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, LoadCursor(NULL, IDC_ARROW), (HBRUSH) GetStockObject(BLACK_BRUSH), AfxGetApp()->LoadIcon(IDI_TEXTUREWINDOW)); }
CWnd::Create(TextureWndClassName, "TextureBrowserWindow", SS_SUNKEN | WS_TABSTOP | WS_CHILD | WS_VSCROLL | WS_HSCROLL, rect, pParentWnd, IDC_TEXTUREWINDOW);
UpdateScrollSizes();
// create font
if(!TexFont.m_hObject) TexFont.CreatePointFont(iTexNameFontHeight * 10, "Courier New");
CDC *pDC = GetDC(); pDC->SelectObject(&TexFont); pDC->GetCharWidth('A', 'A', &iTexNameCharWidth); ReleaseDC(pDC); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : bEnable -
//-----------------------------------------------------------------------------
void CTextureWindow::EnableUpdate(bool bEnable) { m_bEnableUpdate = bEnable; }
//-----------------------------------------------------------------------------
// Purpose: Searches for all of the keywords in an array of keywords within
// a given search string, case-insensitive.
// Input : pszSearch - String to search for keywords within.
// pszKeyword - Array of pointers to keywords.
// nKeywords - Number of keywords in the array.
// Output : Returns true if all keywords were found, false otherwise.
//-----------------------------------------------------------------------------
bool CTextureWindow::MatchKeywords(const char *pszSearch, char **pszKeyword, int nKeywords) { if (nKeywords != 0) { for (int i = 0; i < nKeywords; i++) { if (Q_stristr(pszSearch, pszKeyword[i]) == NULL) { return(false); } } }
return(true); }
//-----------------------------------------------------------------------------
// Changes type filter bits
//-----------------------------------------------------------------------------
void CTextureWindow::SetTypeFilter( int filter, bool enable ) { if (enable) m_nTypeFilter |= filter; else m_nTypeFilter &= ~filter;
if (m_bEnableUpdate) { UpdateScrollSizes(); SelectTexture(szCurTexture, false); if (IsWindow(m_hWnd)) { Invalidate(); UpdateWindow(); } } }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pTE -
// bStart -
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL CTextureWindow::EnumTexturePositions(TWENUMPOS *pTE, BOOL bStart) { RECT &texrect = pTE->texrect;
if (bStart) { pTE->cur_x = iPadding; pTE->cur_y = iPadding; pTE->largest_y = 0; pTE->iTexIndex = 0;
if (IsWindow(m_hWnd)) { GetClientRect(&pTE->clientrect); }
SetRect(&texrect, 0, 0, 0, 0); } bool bFound = false; do { pTE->pTex = g_Textures.EnumActiveTextures(&pTE->iTexIndex, m_eTextureFormat);
if (pTE->pTex == NULL) continue;
bFound = false;
// If we are iterating a specific list of textures, make sure it is in the list.
// dvs: inefficient, the specific list should control the loop, not act as a filter
if (m_pSpecificList != NULL) { int nIndex = m_pSpecificList->Find(pTE->pTex); if (nIndex == -1) continue; pTE->nUsageCount = m_pSpecificList->Element(nIndex).nUsageCount; }
// Filter by texture name.
char szTemp[MAX_PATH]; pTE->pTex->GetShortName(szTemp); if (MatchKeywords(szTemp, m_Filters, m_nFilters)) { //
// Filter by keywords.
//
// NOTE: Try not to access the material here when finding the position
// because it causes the materials to be cached (slow!!)
if (m_nKeywords) { pTE->pTex->GetKeywords(szTemp); if (MatchKeywords(szTemp, m_Keyword, m_nKeywords)) { bFound = true; } } else { bFound = true; } }
// Filter based on opacity, etc.
// NOTE: Try not to access the material here when finding the position
// because it causes the materials to be cached (slow!!)
if (bFound && ((m_nTypeFilter & TYPEFILTER_ALL) != TYPEFILTER_ALL)) { IMaterial* pMaterial = pTE->pTex->GetMaterial(); if (pMaterial) { bFound = false; if ( pMaterial->GetMaterialVarFlag( MATERIAL_VAR_SELFILLUM ) ) { if (m_nTypeFilter & TYPEFILTER_SELFILLUM) bFound = true; } if ( pMaterial->GetMaterialVarFlag( MATERIAL_VAR_BASEALPHAENVMAPMASK ) ) { if (m_nTypeFilter & TYPEFILTER_ENVMASK) bFound = true; }
if ( pMaterial->GetMaterialVarFlag( MATERIAL_VAR_TRANSLUCENT ) ) { if (m_nTypeFilter & TYPEFILTER_TRANSLUCENT) bFound = true; } else { if (m_nTypeFilter & TYPEFILTER_OPAQUE) bFound = true; } } }
// Blow off zero-size materials, but only if they've been loaded...
// Otherwise we have to cache everything which will take forever...
if ( bFound && pTE->pTex->IsLoaded() ) { if ((pTE->pTex->GetWidth() == 0) || (pTE->pTex->GetHeight() == 0)) { bFound = false; } } } while ((pTE->pTex != NULL) && (!bFound));
if ((!bFound) || (pTE->pTex == NULL)) { return(FALSE); }
doresize:
SetRect( &texrect, pTE->cur_x, pTE->cur_y, pTE->cur_x + iDisplaySize, pTE->cur_y + iDisplaySize );
// if we've got one texture on this row already, and this one goes out of
// the client area, jump to the next row. we want to have at least one texture on
// each row, or we will sit in an infinite loop.
if(pTE->cur_x > iPadding && texrect.right > pTE->clientrect.right) { pTE->cur_x = iPadding; pTE->cur_y = pTE->largest_y + iPadding; goto doresize; }
texrect.bottom += (8 + iTexNameFontHeight + iTexIconHeight);
if(texrect.bottom > pTE->largest_y) pTE->largest_y = texrect.bottom;
// update cur_x
pTE->cur_x = texrect.right + iPadding;
return TRUE; }
//-----------------------------------------------------------------------------
// Purpose: Sets the dimensions of each texture within the texture window.
// Input : iSize - 32 to display as 32 x 32 textures.
// 64 to display as 64 x 64 textures.
// 128 to display as 128 x 128 textures.
// 512 to display as 512 x 512 textures
//-----------------------------------------------------------------------------
void CTextureWindow::SetDisplaySize(int iSize) { iDisplaySize = iSize; UpdateScrollSizes(); SelectTexture(szCurTexture, FALSE); RedrawWindow(); }
//-----------------------------------------------------------------------------
// Purpose: Sets the name filter that is used to filter the texture window contents.
// Input : pszFilter - Space, comma, or semicolon delimited names to filter against.
//-----------------------------------------------------------------------------
void CTextureWindow::SetNameFilter(LPCTSTR pszFilter) { if (m_bEnableUpdate) { // kill highlight
HighlightCurTexture(); }
// set filter
strcpy(m_szFilter, pszFilter); strupr(m_szFilter);
// delimit the filter
m_nFilters = 0; char *p = strtok(m_szFilter, " ,;"); while (p != NULL) { m_Filters[m_nFilters++] = p; p = strtok(NULL, " ,;"); }
if (m_bEnableUpdate) { UpdateScrollSizes(); SelectTexture(szCurTexture, false); if (IsWindow(m_hWnd)) { Invalidate(); UpdateWindow(); } } }
//-----------------------------------------------------------------------------
// Purpose: Sets the keywords that are used to filter the texture window contents.
// Input : pszFilter - Space, comma, or semicolon delimited keywords to filter against.
//-----------------------------------------------------------------------------
void CTextureWindow::SetKeywords(LPCTSTR pszKeywords) { if (m_bEnableUpdate) { // kill highlight
HighlightCurTexture(); }
// set keyword filter
strcpy(m_szKeywords, pszKeywords); strupr(m_szKeywords);
// delimit the filter
m_nKeywords = 0; char *p = strtok(m_szKeywords, " ,;"); while (p != NULL) { m_Keyword[m_nKeywords++] = p; p = strtok(NULL, " ,;"); }
if (m_bEnableUpdate) { UpdateScrollSizes(); SelectTexture(szCurTexture, false); if (IsWindow(m_hWnd)) { Invalidate(); UpdateWindow(); } } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTextureWindow::UpdateScrollSizes(void) { TWENUMPOS TE;
total_x = total_y = 0;
if(EnumTexturePositions(&TE, TRUE)) do { if(TE.texrect.right > total_x) total_x = TE.texrect.right; if(TE.texrect.bottom > total_y) total_y = TE.texrect.bottom; } while(EnumTexturePositions(&TE));
// update total_x and total_y
total_x += iPadding; total_y += iPadding;
SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; si.nMin = 0; si.nPos = 0; si.nMax = total_x; si.nPage = TE.clientrect.right; SetScrollInfo(SB_HORZ, &si, TRUE);
si.nMax = total_y; si.nPage = TE.clientrect.bottom; SetScrollInfo(SB_VERT, &si, TRUE);
char szbuf[100]; sprintf(szbuf, "Size = %d %d\n", total_y, TE.clientrect.bottom); TRACE0(szbuf); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTextureWindow::OnPaint(void) { CPaintDC dc(this); // device context for painting
// setup font
dc.SelectObject(&TexFont); dc.SetTextColor(RGB(255, 255, 255)); //dc.SetBkColor(RGB(0,0,0));
dc.SetBkMode(TRANSPARENT);
CRect clientrect; GetClientRect(clientrect);
dc.SetWindowOrg(GetScrollPos(SB_HORZ), GetScrollPos(SB_VERT));
TWENUMPOS TE; BOOL bNotDone = EnumTexturePositions(&TE, TRUE); BOOL bFoundHighlight = FALSE; rectHighlight.left = -1; BOOL bFirst = TRUE; char szDrawTexture[128]; char szFirstDrawnTexture[128];
while (bNotDone) { TE.pTex->GetShortName(szDrawTexture);
if (!strcmpi(szCurTexture, szDrawTexture)) { rectHighlight = TE.texrect; rectHighlight.InflateRect(2, 4); bFoundHighlight = TRUE; }
if (dc.RectVisible(&TE.texrect)) { // ensure loaded
TE.pTex->Load();
CPalette *pOld = dc.SelectPalette(TE.pTex->HasPalette() ? TE.pTex->GetPalette() : g_pGameConfig->Palette, FALSE); dc.RealizePalette();
int flags = drawCaption | drawIcons; if (m_bShowErrors) flags |= drawErrors;
DrawTexData_t DrawTexData; DrawTexData.nFlags = flags | (m_pSpecificList ? drawUsageCount : 0); DrawTexData.nUsageCount = TE.nUsageCount; TE.pTex->Draw(&dc, TE.texrect, iTexNameFontHeight, iTexIconHeight, DrawTexData);
dc.SelectPalette(pOld, FALSE); }
//
// Save the name of the first drawn texture in case we need to highlight it.
//
if (bFirst) { bFirst = FALSE; strcpy(szFirstDrawnTexture, szDrawTexture); }
// next texture & position
bNotDone = EnumTexturePositions(&TE); }
if(bFoundHighlight) { HighlightCurTexture(&dc); } else { // select first texture
SelectTexture(szFirstDrawnTexture); } }
//-----------------------------------------------------------------------------
// Purpose:
// Input : nType -
// cx -
// cy -
//-----------------------------------------------------------------------------
void CTextureWindow::OnSize(UINT nType, int cx, int cy) { CWnd::OnSize(nType, cx, cy); UpdateScrollSizes(); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : nSBCode -
// nPos -
// pScrollBar -
//-----------------------------------------------------------------------------
void CTextureWindow::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int iPos = int(nPos); SCROLLINFO si;
GetScrollInfo(SB_HORZ, &si); int iCurPos = GetScrollPos(SB_HORZ); int iLimit = GetScrollLimit(SB_HORZ);
switch(nSBCode) { case SB_LINELEFT: iPos = -int(si.nPage / 4); break; case SB_LINERIGHT: iPos = int(si.nPage / 4); break; case SB_PAGELEFT: iPos = -int(si.nPage / 2); break; case SB_PAGERIGHT: iPos = int(si.nPage / 2); break; case SB_THUMBTRACK: case SB_THUMBPOSITION: iPos -= iCurPos; break; }
if(iCurPos + iPos < 0) iPos = -iCurPos; if(iCurPos + iPos > iLimit) iPos = iLimit - iCurPos; if(iPos) { SetScrollPos(SB_HORZ, iCurPos + iPos); ScrollWindow(-iPos, 0); UpdateWindow(); } CWnd::OnHScroll(nSBCode, nPos, pScrollBar); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : nSBCode -
// nPos -
// pScrollBar -
//-----------------------------------------------------------------------------
void CTextureWindow::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { SCROLLINFO si;
GetScrollInfo(SB_VERT, &si); int iCurPos = GetScrollPos(SB_VERT); int iLimit = GetScrollLimit(SB_VERT); int iPos = int(si.nPos); switch(nSBCode) { case SB_LINEUP: iPos = -int(si.nPage / 4); break; case SB_LINEDOWN: iPos = int(si.nPage / 4); break; case SB_PAGEUP: iPos = -int(si.nPage / 2); break; case SB_PAGEDOWN: iPos = int(si.nPage / 2); break; case SB_THUMBTRACK: case SB_THUMBPOSITION: iPos = si.nTrackPos - iCurPos; break; case SB_ENDSCROLL: iPos = 0; break; }
if(iCurPos + iPos < 0) iPos = -iCurPos; if(iCurPos + iPos > iLimit) iPos = iLimit - iCurPos; if(iPos) { SetScrollPos(SB_VERT, iCurPos + iPos); ScrollWindow(0, -iPos); UpdateWindow(); }
CWnd::OnVScroll(nSBCode, nPos, pScrollBar); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pDC -
//-----------------------------------------------------------------------------
void CTextureWindow::HighlightCurTexture(CDC *pDC) { CDC dc; BOOL bMadeDC = FALSE;
// nothing to draw
if(rectHighlight.left < 0) return;
if(!pDC) { dc.Attach(::GetDC(m_hWnd)); dc.SetWindowOrg(GetScrollPos(SB_HORZ), GetScrollPos(SB_VERT)); bMadeDC = TRUE; pDC = &dc; }
pDC->SelectStockObject(WHITE_PEN); pDC->SelectStockObject(NULL_BRUSH); pDC->SetROP2(R2_XORPEN); pDC->Rectangle(rectHighlight);
if(bMadeDC) ::ReleaseDC(m_hWnd, dc.Detach()); }
//-----------------------------------------------------------------------------
// Purpose: Selects a given texture by name, scrolling the window if necessary
// to make the selected texture visible.
// Input : pszTexture - Texture to select.
//-----------------------------------------------------------------------------
void CTextureWindow::SelectTexture(LPCTSTR pszTexture, BOOL bAllowRedraw) { TWENUMPOS TE; BOOL bNotDone = EnumTexturePositions(&TE, TRUE); int iTextureIndex = 0;
IEditorTexture *pTex = g_Textures.FindActiveTexture(pszTexture);
CRect r(100, 100, 500, 500); if (IsWindow(m_hWnd)) { GetClientRect(r); } int iClientHeight = r.Height();
if (pTex == NULL) { return; }
while (bNotDone) { if (pTex == TE.pTex) { // found it - make sure it's visible
if (IsWindow(m_hWnd)) { int iScrollPos = GetScrollPos(SB_VERT); if (iScrollPos + iClientHeight < TE.texrect.top || TE.texrect.bottom < iScrollPos) { SetScrollPos(SB_VERT, TE.texrect.top); ScrollWindow(0, iScrollPos - TE.texrect.top);
if (bAllowRedraw) { RedrawWindow(); } }
// first remove current highlight
HighlightCurTexture(); }
pTex->GetShortName(szCurTexture);
// highlight new texture
if (IsWindow(m_hWnd)) { rectHighlight = CRect(&TE.texrect); rectHighlight.InflateRect(2, 4); HighlightCurTexture(); }
GetParent()->PostMessage(TWN_SELCHANGED);
return; }
// next texture & position
bNotDone = EnumTexturePositions(&TE); ++iTextureIndex; } }
//-----------------------------------------------------------------------------
// Purpose:
// Input : nFlags -
// point -
//-----------------------------------------------------------------------------
void CTextureWindow::OnLButtonDown(UINT nFlags, CPoint point) { // find clicked texture
TWENUMPOS TE; BOOL bNotDone = EnumTexturePositions(&TE, TRUE); int iTextureIndex = 0;
int iHorzPos = GetScrollPos(SB_HORZ); int iVertPos = GetScrollPos(SB_VERT);
char szNewTexture[128];
point += CPoint(iHorzPos, iVertPos);
while (bNotDone) { if (PtInRect(&TE.texrect, point)) { TE.pTex->GetShortName(szNewTexture); break; }
// next texture & position
bNotDone = EnumTexturePositions(&TE); ++iTextureIndex; }
if(!bNotDone) { // no texture was hit
return; }
// first remove current highlight
HighlightCurTexture();
// highlight new texture
strcpy(szCurTexture, szNewTexture); rectHighlight = CRect(&TE.texrect); rectHighlight.InflateRect(2, 4); HighlightCurTexture();
// tell parent we changed selection
GetParent()->PostMessage(TWN_SELCHANGED);
SetFocus();
CWnd::OnLButtonDown(nFlags, point); }
//-----------------------------------------------------------------------------
// Purpose: Notifies our parent window of a double-click event.
// Input : nFlags -
// point -
//-----------------------------------------------------------------------------
void CTextureWindow::OnLButtonDblClk(UINT nFlags, CPoint point) { GetParent()->PostMessage(TWN_LBUTTONDBLCLK); CWnd::OnLButtonDblClk(nFlags, point); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : nChar -
// nRepCnt -
// nFlags -
//-----------------------------------------------------------------------------
void CTextureWindow::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { CWnd::OnKeyDown(nChar, nRepCnt, nFlags); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : nFlags -
// zDelta -
// point -
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL CTextureWindow::OnMouseWheel(UINT nFlags, short zDelta, CPoint point) { int nScrollCode;
if (zDelta > 0) { nScrollCode = SB_LINEUP; } else { nScrollCode = SB_LINEDOWN; }
SCROLLINFO si; GetScrollInfo(SB_VERT, &si); int iCurPos = GetScrollPos(SB_VERT); int iLimit = GetScrollLimit(SB_VERT); int iPos = int(si.nPos); switch (nScrollCode) { case SB_LINEUP: { iPos = -(int)si.nPage / 4; break; }
case SB_LINEDOWN: { iPos = si.nPage / 4; break; } }
if (iCurPos + iPos < 0) { iPos = -iCurPos; }
if (iCurPos + iPos > iLimit) { iPos = iLimit - iCurPos; }
if (iPos) { SetScrollPos(SB_VERT, iCurPos + iPos); ScrollWindow(0, -iPos); UpdateWindow(); }
return(TRUE); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : nChar -
// nRepCnt -
// nFlags -
//-----------------------------------------------------------------------------
void CTextureWindow::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { CWnd::OnChar(nChar, nRepCnt, nFlags); }
//-----------------------------------------------------------------------------
// Purpose: Sets the contents of the texture window to a specific list of textures.
// Input : pList - Textures with which to populate the texture window.
//-----------------------------------------------------------------------------
void CTextureWindow::SetSpecificList(TextureWindowTexList *pList) { m_pSpecificList = pList;
if (m_hWnd != NULL) { UpdateScrollSizes(); SelectTexture(szCurTexture, FALSE); RedrawWindow(); } }
//-----------------------------------------------------------------------------
// Purpose:
// Input : eTextureFormat -
//-----------------------------------------------------------------------------
void CTextureWindow::SetTextureFormat(TEXTUREFORMAT eTextureFormat) { m_eTextureFormat = eTextureFormat; }
|