heretic2-sdk/Toolkit/Programming/Tools/qMView/Model.cpp
1998-11-24 00:00:00 +00:00

1640 lines
31 KiB
C++

// Model.cpp
#include "stdafx.h"
#include "ddutil.h"
#include "resource.h"
#include "Matrix.h"
#include "Model.h"
#include "FlexModel.h"
#include "QuakeModel.h"
#include "Quake2Model.h"
#include "FrameManager2.h"
extern pal_t qpal[];
extern pal_t h2pal[];
//
// CModel
//
CModel::CModel()
{
}
CModel::~CModel()
{
}
void CModel::Init()
{
m_skin_head = NULL;
m_curSkin = NULL;
m_defaultSkin = 0;
m_framesize = 0;
m_curFrame = 0;
m_filename = NULL;
m_curscale = -150;
m_playing = false;
m_num_glcmds = 0;
m_glcmds = NULL;
m_vertPath = NULL;
m_num_frames = 0;
m_frames = NULL;
m_ident = 0;
m_version = 0;
m_num_skins = 0;
m_pingPong = false;
m_curGroup = -1;
m_num_st = 0;
m_stverts = NULL;
m_num_tris = 0;
m_tris = NULL;
m_num_xyz = 0;
m_group = -1;
m_frameTick = 0;
m_curstep = 0;
m_pcurframe = 0;
m_nUseTicker = true;
m_nTickerDelay = 100;
m_playMode = ANIM_FORWARD;
m_usePunch = false;
// used by frame tree ctrl
m_numGroups = 0;
m_treeInfo = NULL;
m_frameSels.frames = NULL;
m_frameSels.numFrames = 0;
m_frameSels.info = 0;
m_genPropPage = NULL;
}
void CModel::SetPlayMode(int playmode)
{
m_playMode = playmode;
}
int CModel::GetPlayMode()
{
return m_playMode;
}
void CModel::SetTimerData(long delay, bool useTimer)
{
m_nUseTicker = useTimer;
m_nTickerDelay = delay;
}
void CModel::GetTimerData(long* delay, bool* useTimer)
{
*delay = m_nTickerDelay;
*useTimer = m_nUseTicker;
}
CBitmap* CModel::GetBitmap(LPDIRECT3DRM2 d3drm, CDC* pDC, int skinnum, int& width, int& height)
{
width = m_curSkin->GetWidth(d3drm, pDC);
height = m_curSkin->GetHeight(d3drm, pDC);
return m_curSkin->GetBitmap(d3drm, pDC);
}
void CModel::Delete()
{
if (m_skin_head != NULL)
{
delete m_skin_head;
m_skin_head = NULL;
}
if (m_frames)
{
free(m_frames);
m_frames = NULL;
}
if (m_tris != NULL)
{
free(m_tris);
m_tris = NULL;
}
if (m_stverts != NULL)
{
free(m_stverts);
m_stverts = NULL;
}
if (m_filename != NULL)
{
free(m_filename);
m_filename = NULL;
}
if (m_glcmds)
{
free(m_glcmds);
m_glcmds = NULL;
}
if (m_vertPath)
{
delete m_vertPath;
m_vertPath = NULL;
}
// used by frame tree ctrl
if (m_treeInfo != NULL)
{
delete m_treeInfo;
m_treeInfo = NULL;
}
if (m_frameSels.frames != NULL)
{
free (m_frameSels.frames);
m_frameSels.frames = NULL;
m_frameSels.numFrames = 0;
}
delete this;
}
void CModel::Drag(double delta_x, double delta_y)
{
}
void CModel::RenderTexture(LPDIRECT3DRM2 d3drm, CDC* pDC, bool useTexture)
{
LPDIRECT3DRMMESH mesh = GetMesh();
if (mesh == NULL)
{
return;
}
if ((useTexture) && (m_curSkin != NULL))
{
mesh->SetGroupTexture(m_group, m_curSkin->GetTexture(d3drm, pDC));
}
else
{
mesh->SetGroupTexture(m_group, NULL);
}
}
HRESULT CModel::SetGroupQuality(D3DRMRENDERQUALITY value)
{
LPDIRECT3DRMMESH mesh = GetMesh();
if (mesh == NULL)
{
return -1;
}
return mesh->SetGroupQuality(m_group, value);
}
D3DRMRENDERQUALITY CModel::GetGroupQuality()
{
LPDIRECT3DRMMESH mesh = GetMesh();
if (mesh == NULL)
{
return -1;
}
return mesh->GetGroupQuality(m_group);
}
void CModel::SetPingPong(bool pingPong)
{
m_pingPong = pingPong;
}
void CModel::Snap()
{
}
long CModel::GetNumGroups()
{
return m_numGroups;
}
long CModel::GetNumNodes()
{
return 0;
}
void CModel::DeSelectAll()
{
}
void CModel::ChangeVisual(LPDIRECT3DRMFRAME frame, int nodeNum)
{
}
int CModel::SelectNode(int nodeNum)
{
return -1;
}
HTREEITEM CModel::SelectMesh(LPDIRECT3DRMVISUAL selection)
{
return NULL;
}
bool CModel::ValidNode()
{
return false;
}
void CModel::SetCurGroup(long group)
{
m_curGroup = group;
}
long CModel::GetNumFrames()
{
return m_num_frames;
}
LPCTSTR CModel::GetFilename()
{
return m_filename;
}
void CModel::SetFilename(LPCTSTR filename)
{
CString fileName = filename;
while (true)
{
int destChar = fileName.Find("/");
if (destChar < 0)
{
break;
}
fileName.SetAt(destChar, '\\');
}
if (m_filename != NULL)
{
free(m_filename);
}
m_filename = (char*)malloc(fileName.GetLength() + 1);
strcpy(m_filename, fileName);
}
LPDIRECT3DRMMESH CModel::GetMesh(int i)
{
return NULL;
}
void CModel::MakeAllNodesVisible(LPDIRECT3DRMFRAME frame)
{
}
bool CModel::ToggleNodeVisibility(int node)
{
return false;
}
long CModel::GetNumTris()
{
return m_num_tris;
}
double CModel::GetCurScale()
{
return m_curscale;
}
void CModel::SetCurScale(double curscale)
{
m_curscale = curscale;
}
int CModel::GetTriCount()
{
return m_num_tris;
}
int CModel::GetCurFrame()
{
return m_curFrame;
}
void CModel::SetCurFrame(int curframe)
{
m_curFrame = curframe;
}
void CModel::ResetPlay()
{
m_playing = !m_playing;
}
void CModel::SetPlay(bool playing)
{
m_playing = playing;
}
bool CModel::Playing()
{
return m_playing;
}
CModel* CModel::Create(LPCTSTR extension)
{
CModel* retval;
if (!stricmp(extension, "md2"))
{
retval = new CQuake2Model();
}
else if (!stricmp(extension, "fm"))
{
retval = new CFlexModel();
}
else
{
retval = new CQuakeModel();
}
retval->Init();
return retval;
}
void CModel::SetBackOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene)
{
frame->SetOrientation( scene,
D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1),
D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) );
}
void CModel::SetFrontOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene)
{
frame->SetOrientation( scene,
D3DVALUE(0), D3DVALUE(0), D3DVALUE(1),
D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) );
}
void CModel::SetLeftOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene)
{
frame->SetOrientation( scene,
D3DVALUE(1), D3DVALUE(0), D3DVALUE(0),
D3DVALUE(0), D3DVALUE(0), D3DVALUE(-1) );
}
void CModel::SetRightOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene)
{
frame->SetOrientation( scene,
D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0),
D3DVALUE(0), D3DVALUE(0), D3DVALUE(1) );
}
void CModel::SetTopOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene)
{
frame->SetOrientation( scene,
D3DVALUE(0), D3DVALUE(1), D3DVALUE(0),
D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) );
}
void CModel::SetBottomOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene)
{
frame->SetOrientation( scene,
D3DVALUE(0), D3DVALUE(1), D3DVALUE(0),
D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0) );
}
void CModel::SetInitialOrientation(LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene)
{
}
long* CModel::GetCommands()
{
return m_glcmds;
}
void CModel::SetPunch(bool usePunch)
{
m_usePunch = usePunch;
}
BOOL CModel::ShowFrame(LPDIRECT3DRM2 d3drm, CDC* pDC)
{
return false;
}
void CModel::UpdateForward()
{
m_curFrame++;
int upperLimit;
int lowerLimit;
if (m_curGroup == -1)
{
upperLimit = m_num_frames - 1;
lowerLimit = 0;
}
else
{
upperLimit = m_treeInfo[m_curGroup].eFrame;
lowerLimit = m_treeInfo[m_curGroup].bFrame;
}
if (m_curFrame > upperLimit)
{
if (m_pingPong)
{
m_curFrame -= 2;
}
else
{
m_curFrame = lowerLimit;
}
}
}
void CModel::UpdateBackward()
{
m_curFrame--;
int upperLimit;
int lowerLimit;
if (m_curGroup == -1)
{
upperLimit = m_num_frames - 1;
lowerLimit = 0;
}
else
{
upperLimit = m_treeInfo[m_curGroup].eFrame;
lowerLimit = m_treeInfo[m_curGroup].bFrame;
}
if (m_curFrame < lowerLimit)
{
if (m_pingPong)
{
m_curFrame += 2;
}
else
{
m_curFrame = upperLimit;
}
}
}
BOOL CModel::UpdateFrame(LPDIRECT3DRM2 d3drm, CDC* pDC, int direction, bool interOn)
{
if (m_num_frames < 2) return TRUE;
unsigned long thisTick = GetTickCount();
if (m_nUseTicker)
{
if (thisTick < m_frameTick) return TRUE;
}
m_frameTick = thisTick + FRAME_TICK_INCR;
if (interOn && m_curstep != 0)
{
return CalcInterpolate(d3drm, pDC, m_curstep, INTERPOLATION_STEPS, 0, direction);
}
else m_curstep = 1;
if (m_usePunch)
{
if (m_pingPong)
{
if (direction == ANIM_FORWARD)
{
if (m_pcurframe > m_frameSels.numFrames-2)
direction = m_playMode = ANIM_BACKWARD;
}
else if (direction == ANIM_BACKWARD)
{
if (m_pcurframe <= 0)
direction = m_playMode = ANIM_FORWARD;
}
}
if (direction == ANIM_FORWARD)
{
if (m_pcurframe > m_frameSels.numFrames-2)
m_pcurframe = 0;
else
m_pcurframe++;
m_curFrame = m_frameSels.frames[m_pcurframe];
if (m_curFrame < 0)
{
m_curFrame = 0;
}
}
else if (direction == ANIM_BACKWARD)
{
if (m_pcurframe < 0)
m_pcurframe = m_frameSels.numFrames-1;
else
m_pcurframe--;
m_curFrame = m_frameSels.frames[m_pcurframe];
if (m_curFrame < 0)
{
m_curFrame = 0;
}
}
}
if (!m_usePunch || (m_frameSels.numFrames > 1))
{
if (direction == ANIM_FORWARD)
{
UpdateForward();
}
else
{
UpdateBackward();
}
}
return ShowFrame(d3drm, pDC);
}
BOOL CModel::CalcInterpolate(LPDIRECT3DRM2 d3drm, CDC* pDC, int step, int numsteps, int intertype, int direction)
{
return false;
}
void CModel::BuildMesh(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, LPDIRECT3DRMFRAME scene, CDC* pDC)
{
}
void CModel::DeleteMeshs(LPDIRECT3DRMFRAME frame)
{
}
void CModel::DeleteVisuals(LPDIRECT3DRMFRAME frame)
{
}
CSkin* CModel::GetSkin(int i)
{
return NULL;
}
CSkin* CModel::GetSkin(LPCTSTR skinname)
{
CSkin* skin = NULL;
if (m_num_skins > 0)
{
if (m_skin_head == NULL)
{
skin = new CSkin();
skin->SetFilename(skinname);
m_skin_head = skin;
}
else
{
skin = m_skin_head->Find(skinname);
if (skin == NULL)
{
skin = new CSkin();
skin->SetFilename(skinname);
m_skin_head->InsertSkin(skin);
}
}
}
return skin;
}
void CModel::FillMenuWithSkins(CMenu* menu)
{
}
void CModel::ChangeSkin(LPDIRECT3DRM2 d3drm, CDC* pDC, int nodenum, int skinnum)
{
}
void CModel::AddSkin(LPCTSTR skinname)
{
}
void CModel::ReplaceSkin(int i, LPCTSTR skinname)
{
}
bool CModel::LoadSkin(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame, int skinnum, CDC* pDC)
{
m_defaultSkin = skinnum;
m_curSkin = GetSkin(skinnum);
return true;
}
void CModel::CreateJointVisuals(LPDIRECT3DRM2 d3drm, LPDIRECT3DRMFRAME frame)
{
}
void CModel::Serialize(CArchive & ar)
{
}
// info window support
void CModel::AddJoints(CTreeCtrl* pCTree, HTREEITEM rootJoint)
{
}
void CModel::AddNodes(CTreeCtrl* pCTree, HTREEITEM rootNode)
{
}
void CModel::LoadSkinInfo(CTreeCtrl* pCTree, HTREEITEM rootSkin)
{
for (int i = 0; i < m_num_skins; i++)
{
CString name;
name.Format("skin%d", i);
HTREEITEM point = pCTree->InsertItem(name, rootSkin, TVI_LAST);
pCTree->SetItemImage(point, 0, 0);
pCTree->SetItemData(point, i);
}
}
// frame tree ctrl support
void CModel::LoadFrameInfo(CTreeCtrl* treeDlg, HTREEITEM rootFrame)
{
}
frameStruct* CModel::GetFrameSels()
{
return &m_frameSels;
}
void CModel::StripGroupName(char *gname)
{
int len = strlen(gname);
char newname[16];
memset(newname, 0, sizeof(newname));
for (int i = 0; i < len; i++)
{
if (isdigit((int)gname[i])) break;
else newname[i] = gname[i];
}
strcpy(gname, newname);
}
int CModel::InGroupList(char *test, CTreeGroup* groupList, int numGroups)
{
for (int i = 0; i < numGroups; i++)
{
if (!strcmp(test, groupList[i].id)) return i;
}
strcpy(groupList[numGroups].id, test);
return -1;
}
CTreeHead* CModel::GetTreeInfo(int i)
{
if (i == 0)
{
return m_treeInfo;
}
return &m_treeInfo[i];
}
// skin texturing support
//void CModel::TextureChanged()
//{
//}
void CModel::SetTransparency(LPDIRECT3DRM2 d3drm, CDC* pDC, bool trans)
{
if (m_curSkin != NULL)
{
m_curSkin->GetTexture(d3drm, pDC)->SetDecalTransparency(trans);
}
}
// joint support
void CModel::ToggleJointOn()
{
}
bool CModel::IsJointOn()
{
return false;
}
void CModel::GetModelAngles(float* x, float* y, float* z)
{
*x = 0;
*y = 0;
*z = 0;
}
void CModel::SetModelAngles(float x, float y, float z)
{
}
void CModel::GetConstraintAngleMaxs(float* x, float* y, float* z)
{
*x = 0;
*y = 0;
*z = 0;
}
void CModel::GetConstraintAngleMins(float* x, float* y, float* z)
{
*x = 0;
*y = 0;
*z = 0;
}
void CModel::SetConstraintAngleMaxs(float x, float y, float z)
{
}
void CModel::SetConstraintAngleMins(float x, float y, float z)
{
}
void CModel::SetCurJoint(long joint)
{
}
long CModel::GetCurJoint()
{
return -1;
}
// property page support
void CModel::AddPropPages(CPropertySheet* propSheet)
{
m_genPropPage = new CGeneralPropPage();
m_genPropPage->m_frames.Format("%d", m_num_frames);
m_genPropPage->m_glcommands.Format("%d", m_num_glcmds);
m_genPropPage->m_groups.Format("%d", m_numGroups);
m_genPropPage->m_skinheight.Format("%d", m_skinheight);
m_genPropPage->m_skins.Format("%d", m_num_skins);
m_genPropPage->m_skinwidth.Format("%d", m_skinwidth);
m_genPropPage->m_tris.Format("%d", m_num_tris);
m_genPropPage->m_verts.Format("%d", m_num_xyz);
m_genPropPage->m_stverts.Format("%d", m_num_st);
propSheet->AddPage(m_genPropPage);
}
void CModel::UpdateFromPropPages(CPropertySheet* propSheet)
{
}
void CModel::RemovePropPages(CPropertySheet* propSheet)
{
delete m_genPropPage;
m_genPropPage = NULL;
}
/////////////////////////////////////////////////////////////////////////////
// CGeneralPropPage property page
IMPLEMENT_DYNCREATE(CGeneralPropPage, CPropertyPage)
CGeneralPropPage::CGeneralPropPage() : CPropertyPage(CGeneralPropPage::IDD)
{
//{{AFX_DATA_INIT(CGeneralPropPage)
m_frames = _T("");
m_glcommands = _T("");
m_groups = _T("");
m_skinheight = _T("");
m_skins = _T("");
m_skinwidth = _T("");
m_tris = _T("");
m_stverts = _T("");
m_verts = _T("");
//}}AFX_DATA_INIT
}
CGeneralPropPage::~CGeneralPropPage()
{
}
void CGeneralPropPage::DoDataExchange(CDataExchange* pDX)
{
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CGeneralPropPage)
DDX_Text(pDX, IDC_PPGEN_FRAMES, m_frames);
DDX_Text(pDX, IDC_PPGEN_GLCOMMANDS, m_glcommands);
DDX_Text(pDX, IDC_PPGEN_GROUPS, m_groups);
DDX_Text(pDX, IDC_PPGEN_SKINHEIGHT, m_skinheight);
DDX_Text(pDX, IDC_PPGEN_SKINS, m_skins);
DDX_Text(pDX, IDC_PPGEN_SKINWIDTH, m_skinwidth);
DDX_Text(pDX, IDC_PPGEN_TRIS, m_tris);
DDX_Text(pDX, IDC_PPGEN_STVERTS, m_stverts);
DDX_Text(pDX, IDC_PPGEN_VERTS, m_verts);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CGeneralPropPage, CPropertyPage)
//{{AFX_MSG_MAP(CGeneralPropPage)
// NOTE: the ClassWizard will add message map macros here
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CGeneralPropPage message handlers
//
// CSkin
//
CRGB16* CSkin::s_rgb16 = NULL;
CSkin::CSkin()
{
m_parent = NULL;
m_left = NULL;
m_right = NULL;
m_filename = NULL;
m_bitmap = NULL;
m_texture = NULL;
m_bitDepth = 0;
m_skinWidth = 0;
m_skinHeight = 0;
t_skinBits = NULL;
t_textureBits = NULL;
t_lpDDSkin = NULL;
t_pitch = 0;
}
CSkin::~CSkin()
{
if (t_skinBits != NULL)
{
free(t_skinBits);
t_skinBits = NULL;
}
if (m_left != NULL)
{
delete m_left;
m_left = NULL;
}
if (m_right != NULL)
{
delete m_right;
m_right = NULL;
}
m_parent = NULL;
if (m_filename != NULL)
{
free (m_filename);
m_filename = NULL;
}
if (m_bitmap != NULL)
{
delete m_bitmap;
m_bitmap = NULL;
}
// if (m_texture != NULL)
// {
// m_texture->Release();
// m_texture = NULL;
// }
if (s_rgb16 != NULL)
{
delete s_rgb16;
s_rgb16 = NULL;
}
}
CSkin* CSkin::GetNext()
{
CSkin* retval;
if (m_left != NULL)
{
retval = m_left;
}
else if (m_right != NULL)
{
retval = m_right;
}
else
{
retval = m_parent;
CSkin* curSkin = this;
while (retval != NULL)
{
if ((retval->m_right != NULL) && (retval->m_right != curSkin))
{
break;
}
curSkin = retval;
retval = retval->m_parent;
}
}
if (retval != NULL)
{
while (retval->m_left != NULL)
{
retval = retval->m_left;
}
}
return retval;
}
CSkin* CSkin::Find(LPCTSTR filename)
{
CSkin* curSkin = this;
while (curSkin != NULL)
{
int result = stricmp(filename, curSkin->m_filename);
if (result == 0)
{
break;
}
if (result < 0)
{
curSkin = curSkin->m_left;
}
else
{
curSkin = curSkin->m_right;
}
}
return curSkin;
}
CSkin* CSkin::InsertSkin(CSkin* newSkin)
{
CSkin* parent = this;
while(parent != NULL)
{
int result = stricmp(newSkin->m_filename, parent->m_filename);
if (result == 0)
{
return parent;
}
if (result < 0)
{
if (parent->m_left == NULL)
{
parent->m_left = newSkin;
newSkin->m_parent = parent;
return NULL;
}
parent = parent->m_left;
}
else
{
if (parent->m_right == NULL)
{
parent->m_right = newSkin;
newSkin->m_parent = parent;
return NULL;
}
parent = parent->m_right;
}
}
return this; // impossible for properly constructed tree
}
void CSkin::SetFilename(LPCTSTR filename)
{
CFile* file = new CFile(filename, CFile::modeRead);
if (file == NULL)
{
CString message;
message.Format("%s not found", filename);
AfxMessageBox(message);
}
delete file;
if (m_filename != NULL)
{
free(m_filename);
m_filename = NULL;
}
m_filename = (char*)malloc(strlen(filename) + 1);
strcpy(m_filename, filename);
}
LPCTSTR CSkin::GetFilename()
{
return m_filename;
}
int CSkin::GetWidth(LPDIRECT3DRM2 d3drm, CDC* pDC)
{
Cache(d3drm, pDC);
return m_skinWidth;
}
int CSkin::GetHeight(LPDIRECT3DRM2 d3drm, CDC* pDC)
{
Cache(d3drm, pDC);
return m_skinHeight;
}
LPDIRECT3DRMTEXTURE CSkin::GetTexture(LPDIRECT3DRM2 d3drm, CDC* pDC)
{
Cache(d3drm, pDC);
return m_texture;
}
CBitmap* CSkin::GetBitmap(LPDIRECT3DRM2 d3drm, CDC* pDC)
{
Cache(d3drm, pDC);
return m_bitmap;
}
void CSkin::Cache(LPDIRECT3DRM2 d3drm, CDC* pDC)
{
if (m_bitmap != NULL)
{
return;
}
if ((d3drm == NULL) || (pDC == NULL))
{
AfxMessageBox("Fatal error trying to cache skin");
}
int bits = pDC->GetDeviceCaps(BITSPIXEL);
m_bitDepth = bits;
if (bits == 16)
{
CreateRGB16(pDC);
}
CString ext;
CString path = m_filename;
int loc = path.ReverseFind('.');
if (loc != -1)
{
ext = path.Right(path.GetLength() - loc - 1);
}
CFile* file = new CFile(m_filename, CFile::modeRead);
if (file == NULL)
{
CString message;
message.Format("%s not found", m_filename);
AfxMessageBox(message);
return;
}
if (!stricmp(ext, "pcx") )
{
if (!CacheFromPCX(file))
{
AfxMessageBox("Could not load PCX");
}
}
else if (!stricmp(ext, "m8"))
{
if (!CacheFromM8(file))
{
AfxMessageBox("Could not load M8");
}
}
else if (!stricmp(ext, "m32"))
{
if (!CacheFromM32(file))
{
AfxMessageBox("Could not load M32");
}
}
else if (!stricmp(ext, "tga"))
{
if (!CacheFromTGA(file))
{
AfxMessageBox("Could not load Targa");
}
}
else
{
AfxMessageBox("Could not load skin");
delete file;
return;
}
delete file;
if ((m_bitmap != NULL) && (t_skinBits != NULL))
{
m_bitmap->SetBitmapBits(m_skinWidth * m_skinHeight * m_bitDepth / 8, t_skinBits);
free(t_skinBits);
t_skinBits = NULL;
}
if (t_lpDDSkin != NULL)
{
t_lpDDSkin->Unlock(NULL);
d3drm->CreateTextureFromSurface(t_lpDDSkin, &m_texture);
t_lpDDSkin->Release();
t_lpDDSkin = NULL;
}
}
void CSkin::CreateRGB16(CDC* pDC)
{
if (s_rgb16 != NULL)
{
return;
}
DDSURFACEDESC ddsd;
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
IDirectDrawSurface* surface = 0;
// Create the primary surface.
HRESULT hr = CDDHelper::lpDD->CreateSurface(&ddsd, &surface, 0);
s_rgb16 = CDDHelper::CreateRGB16(surface);
surface->Release();
}
bool CSkin::CacheFromPCX(CFile* file)
{
file->Seek(8, CFile::begin);
short width;
short height;
file->Read(&width, sizeof(width));
file->Read(&height, sizeof(height));
width++;
height++;
if (!SetBitmap(width, height))
{
return false;
}
file->Seek(file->GetLength() - 768, CFile::begin);
pal_t palette[256];
file->Read(palette, sizeof(pal_t) * 256);
file->Seek(128, CFile::begin);
byte* buf = (byte*)malloc(width);
for (int y = 0; y < height; y++)
{
int x = 0;
while (x < width)
{
byte curByte;
file->Read(&curByte, 1);
if ((curByte & 0xC0) == 0xC0)
{
int runLen = curByte & 0x3F;
file->Read(&curByte, 1);
for(; (runLen > 0) && (x < width); runLen--, x++)
{
buf[x] = curByte;
}
}
else
{
buf[x] = curByte;
x++;
}
}
SetBitmapRow(y, buf, palette);
}
free(buf);
return true;
}
bool CSkin::CacheFromM8(CFile* file)
{
int ver;
file->Read(&ver, sizeof(ver));
char name[32];
file->Read(name, sizeof(name));
unsigned width[MIPLEVELS];
unsigned height[MIPLEVELS];
unsigned offsets[MIPLEVELS];
int arraySize = sizeof(unsigned) * MIPLEVELS;
if (ver <= 1)
{
arraySize /= 2;
}
file->Read(width, arraySize);
file->Read(height, arraySize);
file->Read(offsets, arraySize);
char animname[32];
pal_t palette[256];
int flags;
int contents;
int value;
file->Read(animname, sizeof(animname));
file->Read(palette, sizeof(palette));
file->Read(&flags, sizeof(flags));
file->Read(&contents, sizeof(contents));
file->Read(&value, sizeof(value));
if (!SetBitmap(width[0], height[0]))
{
return false;
}
file->Seek(offsets[0], CFile::begin);
byte* buf = (byte*)malloc(width[0]);
for (int y = 0; y < (int)height[0]; y++)
{
file->Read(buf, width[0]);
SetBitmapRow(y, buf, palette);
}
free(buf);
return true;
}
bool CSkin::CacheFromM32(CFile* file)
{
int ver;
file->Read(&ver, sizeof(ver));
char name[128];
file->Read(name, sizeof(name));
if (ver >= 3)
{
char animname[128];
char altname[128];
file->Read(&altname, sizeof(altname));
file->Read(&animname, sizeof(animname));
}
unsigned width[MIPLEVELS];
unsigned height[MIPLEVELS];
unsigned offsets[MIPLEVELS];
int arraySize = sizeof(unsigned) * MIPLEVELS;
file->Read(width, arraySize);
file->Read(height, arraySize);
file->Read(offsets, arraySize);
int flags;
int contents;
int value;
if (ver < 3)
{
char animname[32];
file->Read(animname, sizeof(animname));
}
file->Read(&flags, sizeof(flags));
file->Read(&contents, sizeof(contents));
file->Read(&value, sizeof(value));
float scale_x;
float scale_y;
file->Read(&scale_x, sizeof(scale_x));
file->Read(&scale_y, sizeof(scale_y));
if (ver >= 3)
{
int mip_scale;
int unused[20];
file->Read(&mip_scale, sizeof(mip_scale));
file->Read(&unused, sizeof(unused));
}
if (!SetBitmap(width[0], height[0]))
{
return false;
}
file->Seek(offsets[0], CFile::begin);
long* buf = (long*)malloc(width[0] * sizeof(long));
for (int y = 0; y < (int)height[0]; y++)
{
file->Read(buf, width[0] * 4);
SetBitmapRow(y, buf);
}
free(buf);
return true;
}
bool CSkin::CacheFromTGA(CFile* file)
{
// read header
byte IDLength;
file->Read(&IDLength, sizeof(IDLength));
byte ColorMapType;
file->Read(&ColorMapType, sizeof(ColorMapType));
byte ImageType;
file->Read(&ImageType, sizeof(ImageType));
short CMapStart;
file->Read(&CMapStart, sizeof(CMapStart));
short CMapLength;
file->Read(&CMapLength, sizeof(CMapLength));
byte CMapDepth;
file->Read(&CMapDepth, sizeof(CMapDepth));
short XOffset;
file->Read(&XOffset, sizeof(XOffset));
short YOffset;
file->Read(&YOffset, sizeof(YOffset));
short width;
file->Read(&width, sizeof(width));
short height;
file->Read(&height, sizeof(height));
byte PixelDepth;
file->Read(&PixelDepth, sizeof(PixelDepth));
byte ImageDescriptor;
file->Read(&ImageDescriptor, sizeof(ImageDescriptor));
if ((ImageType != 2) && (ImageType != 10))
{
AfxMessageBox ("Only type 2 and 10 targa RGB images supported");
return false;
}
if (ColorMapType || ((PixelDepth != 32) && (PixelDepth != 24)))
{
AfxMessageBox ("Only 32 or 24 bit images supported (no colormaps)");
return false;
}
if (!SetBitmap(width, height))
{
return false;
}
char* id = (char*)malloc(IDLength + 1);
id[IDLength] = '\0';
if (IDLength > 0)
{
file->Read(id, IDLength);
}
byte* buf = (byte*)malloc(width * sizeof(long));
if (ImageType == 2)
{
int srcRow;
switch (PixelDepth)
{
case 24:
srcRow = 3 * width;
break;
case 32:
srcRow = 4 * width;
break;
}
byte* src = (byte*)malloc(srcRow);
for(int y = 0; y < height; y++)
{
file->Read(src, srcRow);
byte* srcPtr = src;
byte* destPtr = buf;
for(int x = 0; x < width; x++)
{
switch (PixelDepth)
{
case 24:
*destPtr++ = srcPtr[2];
*destPtr++ = srcPtr[1];
*destPtr++ = srcPtr[0];
*destPtr++ = 255;
srcPtr += 3;
break;
case 32:
*destPtr++ = srcPtr[2];
*destPtr++ = srcPtr[1];
*destPtr++ = srcPtr[0];
*destPtr++ = srcPtr[3];
srcPtr += 4;
break;
}
}
SetBitmapRow(height - y - 1, (long*)buf);
}
free(src);
}
else if (ImageType == 10)
{
byte packetHeader;
int packetSize = 0;
byte blue = 0;
byte green = 0;
byte red = 0;
byte alpha = 255;
bool readEachByte = true;
for(int y = 0; y < height; y++)
{
byte* destPtr = buf;
for(int x = 0; x < width; )
{
while(packetSize > 0)
{
if (readEachByte)
{
file->Read(&blue, 1);
file->Read(&green, 1);
file->Read(&red, 1);
if (PixelDepth == 32)
{
file->Read(&alpha, 1);
}
else
{
alpha = 255;
}
}
*destPtr++ = red;
*destPtr++ = green;
*destPtr++ = blue;
*destPtr++ = alpha;
x++;
packetSize--;
if(x == width)
{
break;
}
}
if (x == width)
{
break;
}
file->Read(&packetHeader, 1);
packetSize = 1 + (packetHeader & 0x7f);
readEachByte = !(packetHeader & 0x80);
if (!readEachByte)
{ // run-length packet
file->Read(&blue, 1);
file->Read(&green, 1);
file->Read(&red, 1);
if (PixelDepth == 32)
{
file->Read(&alpha, 1);
}
else
{
alpha = 255;
}
}
}
SetBitmapRow(height - y - 1, (long*)buf);
}
}
free(buf);
free(id);
return true;
}
bool CSkin::SetBitmap(int width, int height)
{
if (((width != 1024) && (width != 512) && (width != 256) && (width != 128) &&
(width != 64) && (width != 32) && (width != 16) && (width != 8)) ||
((height != 1024) && (height != 512) && (height != 256) && (height != 128) &&
(height != 64) && (height != 32) && (height != 16) && (height != 8)))
{
AfxMessageBox("Improper skin dimensions");
return false;
}
// create surface and lockdown buffer
DDSURFACEDESC ddsd;
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
ddsd.dwWidth = width;
ddsd.dwHeight = height;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
ddsd.ddpfPixelFormat.dwRGBBitCount = 32;
ddsd.ddpfPixelFormat.dwRBitMask = 0xff0000;
ddsd.ddpfPixelFormat.dwGBitMask = 0xff00;
ddsd.ddpfPixelFormat.dwBBitMask = 0xff;
ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0;
if (CDDHelper::lpDD->CreateSurface(&ddsd, &t_lpDDSkin, NULL) != DD_OK)
{
AfxMessageBox("Fail on CreateSurface 1");
return false;
}
ddsd.dwSize = sizeof(ddsd);
t_lpDDSkin->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
t_textureBits = (byte*)ddsd.lpSurface;
t_pitch = ddsd.lPitch;
if (m_bitmap != NULL)
{
delete m_bitmap;
m_bitmap = NULL;
}
if (t_skinBits != NULL)
{
free(t_skinBits);
t_skinBits = NULL;
}
m_skinWidth = width;
m_skinHeight = height;
// create bitmap and buffer
m_bitmap = new CBitmap();
m_bitmap->CreateBitmap(width, height, 1, m_bitDepth, NULL);
t_skinBits = (byte*)malloc(width * height * m_bitDepth / 8);
return true;
}
void CSkin::SetBitmapRow(int row, byte* buf, pal_t* palette)
{
if (t_skinBits == NULL)
{
return;
}
byte* base = (byte*)(t_skinBits + (row * m_skinWidth * m_bitDepth / 8));
byte* src = buf;
int x;
switch (m_bitDepth)
{
case 16:
if (s_rgb16 == NULL)
{
return;
}
for (x = 0; x < m_skinWidth; x++)
{
((short*)base)[x] = (short)(((long)(palette[src[x]].r >> 3) << s_rgb16->Position.rgbRed) |
((long)(palette[src[x]].g >> 3) << s_rgb16->Position.rgbGreen) |
((long)(palette[src[x]].b >> 3) << s_rgb16->Position.rgbBlue));
}
break;
case 24:
for (x = 0; x < m_skinWidth; x++)
{
*base++ = palette[src[x]].b;
*base++ = palette[src[x]].g;
*base++ = palette[src[x]].r;
}
break;
case 32:
for (x = 0; x < m_skinWidth; x++)
{
*base++ = palette[src[x]].b;
*base++ = palette[src[x]].g;
*base++ = palette[src[x]].r;
*base++ = 0;
}
break;
}
// fill in texture
src = (byte*)buf;
base = (byte*)(t_textureBits + (row * t_pitch));
for (x = 0; x < m_skinWidth; x++)
{
base[2] = palette[src[x]].r;
base[1] = palette[src[x]].g;
base[0] = palette[src[x]].b;
base[3] = 0;
base += 4;
}
}
void CSkin::SetBitmapRow(int row, long* buf)
{
if (t_skinBits == NULL)
{
return;
}
byte* base = (byte*)(t_skinBits + (row * m_skinWidth * m_bitDepth / 8));
byte* src = (byte*)buf;
int x;
switch (m_bitDepth)
{
case 16:
if (s_rgb16 == NULL)
{
return;
}
for (x = 0; x < m_skinWidth; x++)
{
((short*)base)[x] = (short)(((long)(src[0] >> 3) << s_rgb16->Position.rgbRed) |
((long)(src[1] >> 3) << s_rgb16->Position.rgbGreen) |
((long)(src[2] >> 3) << s_rgb16->Position.rgbBlue));
src += 4;
}
break;
case 24:
for (x = 0; x < m_skinWidth; x++)
{
*base++ = src[2];
*base++ = src[1];
*base++ = src[0];
src += 4;
}
break;
case 32:
for (x = 0; x < m_skinWidth; x++)
{
*base++ = src[2];
*base++ = src[1];
*base++ = src[0];
*base++ = src[3];
src += 4;
}
break;
}
// fill in texture
src = (byte*)buf;
base = (byte*)(t_textureBits + (row * t_pitch));
for (x = 0; x < m_skinWidth; x++)
{
base[2] = *src++;
base[1] = *src++;
base[0] = *src++;
base[3] = *src++;
base += 4;
}
}