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.
720 lines
16 KiB
720 lines
16 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Implementation of the IEditorTexture interface for WAD textures. |
|
// |
|
//=============================================================================// |
|
|
|
|
|
#include "stdafx.h" |
|
#include <process.h> |
|
#include <afxtempl.h> |
|
#include <io.h> |
|
#include <sys\stat.h> |
|
#include <fcntl.h> |
|
#include "hammer.h" |
|
#include "MapDoc.h" |
|
#include "Options.h" |
|
#include "MainFrm.h" |
|
#include "GlobalFunctions.h" |
|
#include "WADTypes.h" |
|
#include "BSPFile.h" |
|
#include "bitmap/imageformat.h" // hack : don't want to include this just for ImageFormat |
|
#include "TextureSystem.h" |
|
#include "WADTexture.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
|
|
#pragma warning(disable:4244) |
|
|
|
|
|
#define _GraphicCacheAllocate(n) malloc(n) |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Stuff for loading WAD3 files. |
|
//----------------------------------------------------------------------------- |
|
typedef struct WAD3miptex_s |
|
{ |
|
char name[16]; |
|
unsigned width, height; |
|
unsigned offsets[4]; // four mip maps stored |
|
} WAD3miptex_t; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Stuff for loading WAL files. |
|
//----------------------------------------------------------------------------- |
|
typedef struct // Mip Graphic |
|
{ |
|
char name[32]; // Name of the Graphic. |
|
DWORD width; // width of picture, must be a multiple of 8 |
|
DWORD height; // height of picture, must be a multiple of 8 |
|
DWORD offset1; // offset to u_char Pix[width * height] |
|
DWORD offset2; // offset to u_char Pix[width/2 * height/2] |
|
DWORD offset4; // offset to u_char Pix[width/4 * height/4] |
|
DWORD offset8; // offset to u_char Pix[width/8 * height/8] |
|
char animname[32]; |
|
DWORD surface; |
|
DWORD contents; |
|
DWORD value; |
|
} walhdr_t; |
|
|
|
|
|
static char *g_pLoadBuf = NULL; |
|
static int g_nLoadSize = 128 * 1024; |
|
|
|
|
|
extern void ScaleBitmap(CSize sizeSrc, CSize sizeDest, char *src, char *dest); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : nSize - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
static bool AllocateLoadBuffer(int nSize) |
|
{ |
|
if (nSize > g_nLoadSize) |
|
{ |
|
g_nLoadSize = nSize; |
|
|
|
if (g_pLoadBuf != NULL) |
|
{ |
|
delete[] g_pLoadBuf; |
|
g_pLoadBuf = NULL; |
|
} |
|
} |
|
|
|
if (g_pLoadBuf == NULL) |
|
{ |
|
g_pLoadBuf = new char[g_nLoadSize]; |
|
} |
|
|
|
if (g_pLoadBuf == NULL) |
|
{ |
|
return(false); |
|
} |
|
|
|
return(true); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor. Initializes data members. |
|
//----------------------------------------------------------------------------- |
|
CWADTexture::CWADTexture(void) |
|
{ |
|
memset(m_szName, 0, sizeof(m_szName)); |
|
memset(m_szFileName, 0, sizeof(m_szFileName)); |
|
|
|
m_datawidth = 0; |
|
m_dataheight = 0; |
|
|
|
m_WALsurface = 0; |
|
m_WALvalue = 0; |
|
m_WALcontents = 0; |
|
|
|
m_ulFileOffset = 0; |
|
m_ulFileID = 0; |
|
|
|
memset(&format, 0, sizeof(format)); |
|
|
|
m_pPalette = NULL; |
|
m_bLocalPalette = false; |
|
|
|
m_nWidth = 0; |
|
m_nHeight = 0; |
|
|
|
m_pData = NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Destructor. Frees texture image data and palette. |
|
//----------------------------------------------------------------------------- |
|
CWADTexture::~CWADTexture(void) |
|
{ |
|
// |
|
// Free image data. |
|
// |
|
if (m_pData != NULL) |
|
{ |
|
free(m_pData); |
|
m_pData = NULL; |
|
} |
|
|
|
// |
|
// Free palette. |
|
// |
|
if (m_pPalette != NULL) |
|
{ |
|
free(m_pPalette); |
|
m_pPalette = NULL; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns the full path of the file (WAD, PAK, or WAL) from which this |
|
// texture was loaded. |
|
//----------------------------------------------------------------------------- |
|
const char *CWADTexture::GetFileName( void ) const |
|
{ |
|
return(m_szFileName); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : fd - |
|
// ulFileID - |
|
// bLoad - |
|
// pszName - |
|
// Output : Returns TRUE on success, FALSE on failure. |
|
//----------------------------------------------------------------------------- |
|
BOOL CWADTexture::Init(int fd, DWORD ulFileID, BOOL bLoad, LPCTSTR pszName) |
|
{ |
|
// |
|
// Load header and copy needed data into members variables. |
|
// |
|
GRAPHICSFILESTRUCT FileInfo; |
|
bool bFound = g_Textures.FindGraphicsFile(&FileInfo, ulFileID); |
|
if (!bFound) |
|
{ |
|
miptex_t hdr; |
|
_read(fd, (char *)&hdr, sizeof(hdr)); |
|
|
|
m_nWidth = hdr.width; |
|
m_nHeight = hdr.height; |
|
} |
|
else if (FileInfo.format == tfWAD3) |
|
{ |
|
WAD3miptex_t hdr; |
|
_read(fd, (char *)&hdr, sizeof(hdr)); |
|
|
|
m_nWidth = hdr.width; |
|
m_nHeight = hdr.height; |
|
|
|
if (m_nHeight < 0) |
|
{ |
|
return(FALSE); |
|
} |
|
} |
|
else |
|
{ |
|
return(FALSE); |
|
} |
|
|
|
m_ulFileID = ulFileID; |
|
|
|
strcpy(m_szName, pszName); |
|
|
|
if (bFound) |
|
{ |
|
strcpy(m_szFileName, FileInfo.filename); |
|
} |
|
|
|
if (m_nWidth * m_nHeight > MAX_TEXTURESIZE) |
|
{ |
|
return(FALSE); |
|
} |
|
|
|
if (!m_szName[0]) |
|
{ |
|
return(FALSE); |
|
} |
|
|
|
// set offset |
|
m_ulFileOffset = _tell(fd); |
|
|
|
if (bLoad) |
|
{ |
|
return(Load()); |
|
} |
|
|
|
return(TRUE); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : |
|
// Output : CPalette * |
|
//----------------------------------------------------------------------------- |
|
CPalette *CWADTexture::GetPalette(void) const |
|
{ |
|
static CPalette pal; |
|
pal.DeleteObject(); |
|
pal.CreatePalette(m_pPalette); |
|
return &pal; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns a string of comma delimited keywords associated with this |
|
// material. |
|
// Input : pszKeywords - Buffer to receive keywords, NULL to query string length. |
|
// Output : Returns the number of characters in the keyword string. |
|
//----------------------------------------------------------------------------- |
|
int CWADTexture::GetKeywords(char *pszKeywords) const |
|
{ |
|
// |
|
// Set the keywords to the WAD file name. |
|
// |
|
if (pszKeywords != NULL) |
|
{ |
|
const char *pszLastSlash = strrchr(m_szFileName, '\\'); |
|
if (pszLastSlash != NULL) |
|
{ |
|
pszLastSlash++; |
|
strcpy(pszKeywords, pszLastSlash); |
|
} |
|
else |
|
{ |
|
strcpy(pszKeywords, m_szFileName); |
|
} |
|
} |
|
|
|
return(strlen(m_szFileName)); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pszName - |
|
// Output : Returns the length of the short name in characters. |
|
//----------------------------------------------------------------------------- |
|
int CWADTexture::GetShortName(char *pszName) const |
|
{ |
|
char szBuf[MAX_PATH]; |
|
szBuf[0] = '\0'; |
|
|
|
if (pszName == NULL) |
|
{ |
|
pszName = szBuf; |
|
} |
|
|
|
if (format == tfWAL) |
|
{ |
|
const char *pszCopy = strstr(m_szName, "textures"); |
|
if (pszCopy == NULL) |
|
{ |
|
pszCopy = m_szName; |
|
} |
|
else |
|
{ |
|
pszCopy += strlen("textures\\"); |
|
} |
|
|
|
strcpy(pszName, pszCopy); |
|
|
|
// remove extension |
|
char *psz = strstr(szBuf, ".wal"); |
|
if (psz != NULL) |
|
{ |
|
*psz = 0; |
|
} |
|
} |
|
else |
|
{ |
|
strcpy(pszName, m_szName); |
|
} |
|
|
|
return(strlen(pszName)); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Resizes a texture to be even powers of 2 in width and height. |
|
// Input : pLoadBuf - |
|
// Output : Returns TRUE on success, FALSE on failure. |
|
//----------------------------------------------------------------------------- |
|
BOOL CWADTexture::AdjustTexture(char *pLoadBuf) |
|
{ |
|
// make height/width power of two |
|
int i, i2; |
|
|
|
for (i = 0; ; i++) |
|
{ |
|
i2 = 1 << i; |
|
if (i2 >= m_nWidth) |
|
{ |
|
m_datawidth = i2; |
|
break; |
|
} |
|
} |
|
|
|
for (i = 0; ; i++) |
|
{ |
|
i2 = 1 << i; |
|
if (i2 >= m_nHeight) |
|
{ |
|
m_dataheight = i2; |
|
break; |
|
} |
|
} |
|
|
|
// allocate data |
|
m_pData = _GraphicCacheAllocate(m_datawidth * m_dataheight); |
|
|
|
if (m_pData == NULL) |
|
{ |
|
CString errmsg; |
|
errmsg.Format(IDS_ERRLOADGRAPHIC, m_szName); |
|
AfxMessageBox(errmsg); |
|
return FALSE; |
|
} |
|
|
|
// scale up to data |
|
ScaleBitmap(CSize(m_nWidth, m_nHeight), CSize(m_datawidth, m_dataheight), pLoadBuf, (char *)m_pData); |
|
|
|
return TRUE; |
|
} |
|
|
|
bool CWADTexture::IsLoaded() const |
|
{ |
|
return (m_pData != NULL); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Load data from file associated with m_ulFileID. |
|
// Input : fd - |
|
// hFile - |
|
// Output : Returns TRUE on success, FALSE on failure. |
|
//----------------------------------------------------------------------------- |
|
BOOL CWADTexture::Load(int fd, HANDLE hFile) |
|
{ |
|
if (m_pData) |
|
{ |
|
return TRUE; // already loaded |
|
} |
|
|
|
// if fd is -1, get it from base file.. otherwise we've been |
|
// given an fd by caller, so use that in loading |
|
GRAPHICSFILESTRUCT fileInfo; |
|
Q_memset( &fileInfo, 0, sizeof(fileInfo)); |
|
|
|
|
|
if (fd == -1) |
|
{ |
|
// find graphics file - different loading based on wad type. |
|
if (!g_Textures.FindGraphicsFile(&fileInfo, m_ulFileID)) |
|
{ |
|
return(FALSE); |
|
} |
|
|
|
// keep fd |
|
fd = fileInfo.fd; |
|
|
|
// seek to offset |
|
_lseek(fd, m_ulFileOffset, SEEK_SET); |
|
} |
|
|
|
m_bLocalPalette = FALSE; |
|
|
|
// dvs: if fd != -1, using FileInfo without initializing it!! |
|
if (!AllocateLoadBuffer(m_nWidth * m_nHeight)) |
|
{ |
|
AfxMessageBox("Couldn't allocate a texture loading buffer."); |
|
return FALSE; |
|
} |
|
|
|
// load bitmap |
|
_read(fd, g_pLoadBuf, m_nWidth * m_nHeight); |
|
|
|
// |
|
// If WAD3, read the palette. |
|
// |
|
if (fileInfo.format == tfWAD3) |
|
{ |
|
WORD nPal; |
|
|
|
_lseek(fd, (m_nWidth / 2 * m_nHeight / 2) + (m_nWidth / 4 * m_nHeight / 4) + (m_nWidth / 8 * m_nHeight / 8), SEEK_CUR); |
|
|
|
_read(fd, &nPal, sizeof nPal); |
|
|
|
Assert(nPal <= 256); |
|
|
|
if ((nPal > 0) && (nPal < 1024)) |
|
{ |
|
m_bLocalPalette = TRUE; |
|
|
|
// setup palette |
|
m_pPalette = (LOGPALETTE *)malloc(sizeof(WORD) * 2 + sizeof(PALETTEENTRY) * nPal); |
|
|
|
// fast load - throw into buffer |
|
static unsigned char PalBuf[3 * 1024]; |
|
_read(fd, PalBuf, nPal * 3); |
|
|
|
// convert to LOGPALETTE |
|
for (int i = 0; i < nPal; i++) |
|
{ |
|
m_pPalette->palPalEntry[i].peRed = PalBuf[i*3]; |
|
m_pPalette->palPalEntry[i].peGreen = PalBuf[i*3+1]; |
|
m_pPalette->palPalEntry[i].peBlue = PalBuf[i*3+2]; |
|
m_pPalette->palPalEntry[i].peFlags = D3DRMPALETTE_READONLY | PC_NOCOLLAPSE; |
|
} |
|
|
|
m_pPalette->palVersion = 0x300; |
|
m_pPalette->palNumEntries = nPal; |
|
} |
|
} |
|
|
|
AdjustTexture(g_pLoadBuf); |
|
|
|
return TRUE; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: If the buffer pointer passed in is not NULL, copies the image data |
|
// in RGB format to the buffer |
|
// Input : pImageRGB - Pointer to buffer that receives the image data. If the |
|
// pointer is NULL, no data is copied, only the data size is returned. |
|
// Output : Returns a the size of the RGB image in bytes. |
|
//----------------------------------------------------------------------------- |
|
int CWADTexture::GetImageDataRGB( void *pImageRGB ) |
|
{ |
|
if ( pImageRGB != NULL ) |
|
{ |
|
Load(); |
|
|
|
unsigned char *puchImage = ( unsigned char * )m_pData; |
|
unsigned char *pIndex = ( unsigned char * )pImageRGB; |
|
|
|
for (int y = 0; y < m_dataheight; y++) |
|
{ |
|
for (int x = 0; x < m_datawidth; x++) |
|
{ |
|
unsigned char chPaletteEntry = puchImage[y * m_datawidth + x]; |
|
|
|
*pIndex = m_pPalette->palPalEntry[chPaletteEntry].peRed; |
|
pIndex++; |
|
|
|
*pIndex = m_pPalette->palPalEntry[chPaletteEntry].peGreen; |
|
pIndex++; |
|
|
|
*pIndex = m_pPalette->palPalEntry[chPaletteEntry].peBlue; |
|
pIndex++; |
|
} |
|
} |
|
} |
|
|
|
return( m_datawidth * m_dataheight * 3 ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: If the buffer pointer passed in is not NULL, copies the image data |
|
// in RGBA format to the buffer |
|
// Input : pImageRGBA - Pointer to buffer that receives the image data. If the |
|
// pointer is NULL, no data is copied, only the data size is returned. |
|
// Output : Returns a the size of the RGBA image in bytes. |
|
//----------------------------------------------------------------------------- |
|
int CWADTexture::GetImageDataRGBA( void *pImageRGBA ) |
|
{ |
|
if ( pImageRGBA != NULL ) |
|
{ |
|
unsigned char *puchImage = (unsigned char *)m_pData; |
|
unsigned char *pIndex = (unsigned char *)pImageRGBA; |
|
|
|
for (int y = 0; y < m_dataheight; y++) |
|
{ |
|
for (int x = 0; x < m_datawidth; x++) |
|
{ |
|
unsigned char chPaletteEntry = puchImage[y * m_datawidth + x]; |
|
|
|
*pIndex = m_pPalette->palPalEntry[chPaletteEntry].peRed; |
|
pIndex++; |
|
|
|
*pIndex = m_pPalette->palPalEntry[chPaletteEntry].peGreen; |
|
pIndex++; |
|
|
|
*pIndex = m_pPalette->palPalEntry[chPaletteEntry].peBlue; |
|
pIndex++; |
|
|
|
*pIndex = 0; |
|
pIndex++; |
|
} |
|
} |
|
} |
|
|
|
return( m_datawidth * m_dataheight * 4 ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : size - |
|
//----------------------------------------------------------------------------- |
|
void CWADTexture::GetSize(SIZE& size) |
|
{ |
|
size.cx = m_nWidth; |
|
size.cy = m_nHeight; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Draws white "No Image" text in a black rectangle. |
|
// Input : pDC - |
|
// rect - |
|
// iFontHeight - |
|
// dwFlags - |
|
//----------------------------------------------------------------------------- |
|
void CWADTexture::DrawNoImage(CDC *pDC, RECT& rect, int iFontHeight) |
|
{ |
|
// draw "no data" |
|
CFont *pOldFont = (CFont*) pDC->SelectStockObject(ANSI_VAR_FONT); |
|
COLORREF cr = pDC->SetTextColor(RGB(0xff, 0xff, 0xff)); |
|
COLORREF cr2 = pDC->SetBkColor(RGB(0, 0, 0)); |
|
|
|
// draw black rect first |
|
pDC->FillRect(&rect, CBrush::FromHandle(HBRUSH(GetStockObject(BLACK_BRUSH)))); |
|
|
|
// then text |
|
pDC->TextOut(rect.left+2, rect.top+2, "No Image", 8); |
|
pDC->SelectObject(pOldFont); |
|
pDC->SetTextColor(cr); |
|
pDC->SetBkColor(cr2); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pDC - |
|
// rect - |
|
// iFontHeight - |
|
// dwFlags - |
|
//----------------------------------------------------------------------------- |
|
void CWADTexture::Draw(CDC *pDC, RECT& rect, int iFontHeight, int iIconHeight, DrawTexData_t &DrawTexData) |
|
{ |
|
if (!m_nWidth) |
|
{ |
|
DrawNoImage(pDC, rect, iFontHeight); |
|
return; |
|
} |
|
|
|
// no data - |
|
if (!m_pData) |
|
{ |
|
// try to load - |
|
if (!Load()) |
|
{ |
|
DrawNoImage(pDC, rect, iFontHeight); |
|
return; |
|
} |
|
} |
|
|
|
static struct |
|
{ |
|
BITMAPINFOHEADER bmih; |
|
unsigned short colorindex[256]; |
|
} bmi; |
|
|
|
BITMAPINFOHEADER& bmih = bmi.bmih; |
|
memset(&bmih, 0, sizeof bmih); |
|
bmih.biSize = sizeof(bmih); |
|
bmih.biWidth = m_datawidth; |
|
bmih.biHeight = -m_dataheight; // top-down DIB |
|
bmih.biCompression = BI_RGB; |
|
bmih.biBitCount = 8; |
|
|
|
bmih.biPlanes = 1; |
|
|
|
static BOOL bInit = FALSE; |
|
if (!bInit) |
|
{ |
|
bInit = TRUE; |
|
for (int i = 0; i < 256; i++) |
|
{ |
|
bmi.colorindex[i] = i; |
|
} |
|
} |
|
|
|
int dest_width = rect.right - rect.left; |
|
int dest_height = rect.bottom - rect.top; |
|
|
|
if (DrawTexData.nFlags & drawCaption) |
|
{ |
|
dest_height -= iFontHeight + 4; |
|
} |
|
|
|
if (!(DrawTexData.nFlags & drawResizeAlways)) |
|
{ |
|
if (m_nWidth < dest_width) |
|
{ |
|
dest_width = m_nWidth; |
|
} |
|
|
|
if (m_nHeight < dest_height) |
|
{ |
|
dest_height = m_nHeight; |
|
} |
|
} |
|
|
|
SetStretchBltMode(pDC->m_hDC, COLORONCOLOR); |
|
|
|
if (StretchDIBits(pDC->m_hDC, rect.left, rect.top, dest_width, dest_height, 0, 0, m_datawidth, m_dataheight, m_pData, (BITMAPINFO*)&bmi, DIB_PAL_COLORS, SRCCOPY) == GDI_ERROR) |
|
{ |
|
Msg(mwError, "CWADTexture::Draw(): StretchDIBits failed."); |
|
} |
|
|
|
// |
|
// Caption. |
|
// |
|
if (DrawTexData.nFlags & drawCaption) |
|
{ |
|
// draw background for name |
|
CBrush brCaption(RGB(0, 0, 255)); |
|
CRect rcCaption(rect); |
|
|
|
rcCaption.top = rcCaption.bottom - (iFontHeight + 5); |
|
pDC->FillRect(rcCaption, &brCaption); |
|
|
|
// draw name |
|
char szShortName[MAX_PATH]; |
|
int iLen = GetShortName(szShortName); |
|
pDC->TextOut(rect.left, rect.bottom - (iFontHeight + 4), szShortName, iLen); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Frees the static load buffer. |
|
//----------------------------------------------------------------------------- |
|
bool CWADTexture::Initialize(void) |
|
{ |
|
return(AllocateLoadBuffer(g_nLoadSize)); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Loads this texture from disk, if it is not already loaded. |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CWADTexture::Load( void ) |
|
{ |
|
if (m_pData != NULL) |
|
{ |
|
// Already loaded. |
|
return(true); |
|
} |
|
|
|
return(Load(-1, NULL) == TRUE); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Frees the static load buffer. |
|
//----------------------------------------------------------------------------- |
|
void CWADTexture::ShutDown(void) |
|
{ |
|
if (g_pLoadBuf != NULL) |
|
{ |
|
delete[] g_pLoadBuf; |
|
g_pLoadBuf = NULL; |
|
} |
|
} |
|
|
|
|