md3view/win32_driver.cpp

524 lines
14 KiB
C++
Executable File

/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
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/>.
*/
/*
win32 specific driver file:
this include the WinMain function and all the code to initialize the win32 gui
look for comments in md3view.h to see how the viewer system independent code needs to be
initialized and used in the framwork
*/
#ifdef WIN32
#include "system.h"
#include "ndictionary.h"
#include "md3gl.h"
#include "md3view.h"
#include "resource.h"
#include "AFXRES.H"
#include "oddbits.h"
#include "bmp.h"
HINSTANCE WinhInstance;
HWND mainhWnd;
char* CmdLine = NULL;
#define WINDOW_STYLE WS_OVERLAPPEDWINDOW
// system specific event handler functions
bool SysOnCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct);
int SysOnDestroy(HWND hWnd);
void SysOnMouseMove(HWND hwnd, int x, int y, UINT keyFlags);
void SysOnRButtonUp(HWND hwnd, int x, int y, UINT flags);
void SysOnLButtonUp(HWND hwnd, int x, int y, UINT flags);
void SysOnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
void SysOnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
void SysOnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
void SysOnKeyDown(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags);
void SysOnKeyUp(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags);
void SysOnPaint( HWND hwnd, bool bFlip = true );
void SysOnSize(HWND hwnd, UINT state, int cx, int cy);
void SysOnIdle();
NodeSequenceInfo tagMenuList;
/*
add a seperator
*/
void tagMenu_seperatorAppend( char *name )
{
char newname[512];
strcpy( newname, "...");
strcat( newname, name );
strcat( newname, "...");
char *n = new char[strlen(newname)+1];
strcpy( n, newname );
HMENU subMenu = GetSubMenu( GetMenu(mdview.hwnd), TAG_MENU_ID );
AppendMenu( subMenu, MF_DISABLED|MF_STRING, ID_TAG_START+tagMenuList.size(), n );
tagMenuList.insertLast( (Object)NULL );
}
/*
remove a tag entry from the menu
*/
void tagMenu_remove( GLMODEL_DBLPTR tagid )
{
NodePosition pos;
GLMODEL_DBLPTR dblptr;
int i=1;
bool remove=false;
// get the tag menu position
for (pos=tagMenuList.first() ; pos!=NULL ; pos=tagMenuList.after(pos)) {
dblptr = (GLMODEL_DBLPTR)pos->element();
if (dblptr == tagid) break;
i++;
}
// return if not found
if (!pos) return;
// remove the menu
HMENU subMenu = GetSubMenu( GetMenu(mdview.hwnd), TAG_MENU_ID );
DeleteMenu( subMenu, i, MF_BYPOSITION );
// see if this is the last tag entry in a block
// if so remove the seperator
NodePosition b = tagMenuList.before(pos);
NodePosition a = tagMenuList.after(pos);
if (b==0) {
if (a==0) remove = true;
else if (a->element() == 0) remove = true;
}
else if (b->element() == 0) {
if (a==0) remove = true;
else if (a->element() == 0) remove = true;
}
if (remove) {
DeleteMenu( subMenu, i-1, MF_BYPOSITION );
tagMenuList.remove( b );
}
// remove the pos from list
tagMenuList.remove( pos );
}
/*
add a tag to the menu
*/
void tagMenu_append( char *name, GLMODEL_DBLPTR model )
{
char *n = new char[strlen(name)+1];
strcpy( n, name );
HMENU subMenu = GetSubMenu( GetMenu(mdview.hwnd), TAG_MENU_ID );
AppendMenu( subMenu, MF_ENABLED|MF_STRING, ID_TAG_START+tagMenuList.size(), n );
tagMenuList.insertLast( (Object)model );
}
void swap_buffers()
{
SwapBuffers( mdview.hdc );
}
char *getCmdLine()
{
return CmdLine;
}
void FreeCmdLine()
{
if (CmdLine)
{
delete [] CmdLine;
CmdLine = NULL;
}
}
bool file_exists( LPCSTR fname )
{
if (!fname) return false;
FILE *f = fopen( fname, "r" );
if (f) {
fclose(f);
return true;
}
else {
return false;
}
}
void repaint_main()
{
InvalidateRect( mdview.hwnd, NULL, FALSE );
}
void set_cursor( int x, int y )
{
SetCursorPos( x, y );
}
/*
time measuring stuff
*/
double getDoubleTime (void)
{
return (double)clock() / (double)CLOCKS_PER_SEC;
}
/*
main event handler
*/
// event handler itself
LONG WINAPI WinProcInstance(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
HANDLE_MSG( hwnd, WM_DESTROY, SysOnDestroy );
HANDLE_MSG( hwnd, WM_CLOSE, SysOnDestroy );
HANDLE_MSG( hwnd, WM_CREATE, SysOnCreate );
HANDLE_MSG( hwnd, WM_PAINT, SysOnPaint );
HANDLE_MSG( hwnd, WM_SIZE, SysOnSize );
HANDLE_MSG( hwnd, WM_COMMAND, SysOnCommand );
HANDLE_MSG( hwnd, WM_LBUTTONDOWN, SysOnLButtonDown );
HANDLE_MSG( hwnd, WM_RBUTTONDOWN, SysOnRButtonDown );
HANDLE_MSG( hwnd, WM_LBUTTONUP, SysOnLButtonUp );
HANDLE_MSG( hwnd, WM_RBUTTONUP, SysOnRButtonUp );
HANDLE_MSG( hwnd, WM_KEYDOWN, SysOnKeyDown );
HANDLE_MSG( hwnd, WM_KEYUP, SysOnKeyUp );
case WM_MOUSEMOVE:
{
SysOnMouseMove(hwnd, (int)(short)LOWORD(lParam),(int)(short)HIWORD(lParam),(UINT)(wParam));
return 0L;
}
default:
return(DefWindowProc(hwnd, message, wParam, lParam));
}
}
HMENU hMainMenu = NULL;
HMENU hMenuUpperAnims = NULL;
HMENU hMenuLowerAnims = NULL;
// clears menu, then adds items "none" and seperator...
//
void Menu_Clear(HMENU hMenu, int iBaseID)
{
if ( hMenu )
{
int iCount = GetMenuItemCount( hMenu );
for (int i=iCount-1; i>=0; i--)
{
VERIFY(DeleteMenu( hMenu, i, MF_BYPOSITION));
}
DrawMenuBar(mainhWnd);
// add default "choose seq" and "choose multi-seq", then a seperator...
//
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_STRING, // UINT uFlags, // menu-item flags
iBaseID + 0, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
"** Choose Seq **" // LPCTSTR lpNewItem // menu-item content
);
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_STRING, // UINT uFlags, // menu-item flags
iBaseID + 1, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
"** Choose Multi-Seq **" // LPCTSTR lpNewItem // menu-item content
);
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_SEPARATOR, // UINT uFlags, // menu-item flags
NULL, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
NULL // LPCTSTR lpNewItem // menu-item content
);
// now add a default "none" and a seperator...
//
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_STRING, // UINT uFlags, // menu-item flags
iBaseID + 2, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
"(none)" // LPCTSTR lpNewItem // menu-item content
);
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_SEPARATOR, // UINT uFlags, // menu-item flags
NULL, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
NULL // LPCTSTR lpNewItem // menu-item content
);
DrawMenuBar(mainhWnd);
iCount = GetMenuItemCount( hMenu );
}
}
void Menu_AddItem(HMENU hMenu, int iBaseID, LPCSTR psItem)
{
if ( hMenu )
{
int iID = GetMenuItemCount( hMenu );
iID-= 2; // compensate for 2 seperators, now this is ID of next we're about to add
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_STRING, // UINT uFlags, // menu-item flags
iBaseID + iID, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
psItem // LPCTSTR lpNewItem // menu-item content
);
DrawMenuBar(mainhWnd);
}
}
void Menu_UpperAnims_Clear(void)
{
Menu_Clear( hMenuUpperAnims, ID_MENUITEMS_UPPERANIMS );
}
void Menu_LowerAnims_Clear(void)
{
Menu_Clear( hMenuLowerAnims, ID_MENUITEMS_LOWERANIMS );
}
void Menu_UpperAnims_AddItem(LPCSTR psItem)
{
Menu_AddItem( hMenuUpperAnims, ID_MENUITEMS_UPPERANIMS, psItem );
}
void Menu_LowerAnims_AddItem(LPCSTR psItem)
{
Menu_AddItem( hMenuLowerAnims, ID_MENUITEMS_LOWERANIMS, psItem );
}
/*
creates window
*/
void WindowSystemInit( HINSTANCE hInstance )
{
WNDCLASS wc;
memset (&wc, 0, sizeof(wc));
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)WinProcInstance;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "mainWindow";
RegisterClass(&wc);
mainhWnd = CreateWindow (
"mainWindow" ,
FILENAME,
WINDOW_STYLE,
0, 0,
1000, // unfortunately I can't just #ifdef these 2 lines because CreateWindow is also a macro and C can't nest 'em... <sigh>
600, //
0,
LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENU1)),
hInstance,
NULL);
ShowWindow ( mainhWnd, SW_SHOW );
UpdateWindow ( mainhWnd );
hMainMenu = GetMenu(mainhWnd);
hMenuUpperAnims = CreateMenu();
hMenuLowerAnims = CreateMenu();
AppendMenu( hMainMenu, // HMENU hMenu, // handle to menu to be changed
MF_POPUP|MF_STRING, // UINT uFlags, // menu-item flags
(UINT_PTR) hMenuUpperAnims, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
"(Upper Anim Sequences)" // LPCTSTR lpNewItem // menu-item content
);
AppendMenu( hMainMenu, // HMENU hMenu, // handle to menu to be changed
MF_POPUP|MF_STRING, // UINT uFlags, // menu-item flags
(UINT_PTR) hMenuLowerAnims, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
"(Lower Anim Sequences)" // LPCTSTR lpNewItem // menu-item content
);
Menu_UpperAnims_Clear();
Menu_LowerAnims_Clear();
DrawMenuBar(mainhWnd);
if (getCmdLine() != NULL )
{
SysOnCommand(mainhWnd, ID_FILE_OPEN, 0, 0);
// if (!loadmdl( getCmdLine() )) {
// Debug( "could not load %s", getCmdLine() );
}
}
/*
initializes app
calls
*/
void Init( HINSTANCE hInstance )
{
WindowSystemInit( hInstance );
}
/*
main program entry point
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
if ( ( lpCmdLine != NULL ) &&
( lpCmdLine[0] != '\0' ) )
{
CmdLine = new char[strlen(lpCmdLine)+1];
strcpy(CmdLine,lpCmdLine);
// sometimes the OS puts quotes around the whole command line (duh!!!!), so get rid of them...
//
if (CmdLine[0]=='"' && CmdLine[strlen(CmdLine)-1]=='"')
{
strcpy(CmdLine,lpCmdLine+1);
CmdLine[strlen(CmdLine)-1]=0;
}
while (strchr(CmdLine,'/')) *strchr(CmdLine,'/')='\\';
}
WinhInstance = hInstance;
/* initilizes mdview data */
init_mdview(lpCmdLine);
Init( hInstance );
mdview.done = false;
// main message loop
while (!mdview.done)
{
SysOnIdle();
while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage (&msg);
TranslateAccelerator( mainhWnd, LoadAccelerators( hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1)), &msg );
DispatchMessage (&msg);
}
}
shutdown_mdviewdata();
return 1;
}
// if psFilename == NULL, takes a memory screenshot in DIB format (for copying to clipboard)
//
bool ScreenShot(LPCSTR psFilename, // else NULL = take memory snapshot (for clipboard)
LPCSTR psCopyrightMessage, // /* = NULL */
int iWidth, // /* = <screenwidth> */
int iHeight // /* = <screenheight> */
)
{
bool bReturn = false;
int iOldPack;
glGetIntegerv(GL_PACK_ALIGNMENT,&iOldPack);
glPixelStorei(GL_PACK_ALIGNMENT,1);
void *pvGLPixels = malloc (iWidth * iHeight * 3); // 3 = R,G,B
if (pvGLPixels)
{
if (psCopyrightMessage)
{
bool bOldInhibit = gbTextInhibit;
gbTextInhibit = false;
Text_DisplayFlat(psCopyrightMessage, 0, (iHeight-TEXT_DEPTH)-1,255,255,255); // y-1 = aesthetic only
gbTextInhibit = bOldInhibit;
}
glReadPixels( 0, // x
0, // y (from bottom left)
iWidth, // width
iHeight, // height
GL_RGB, // format
GL_UNSIGNED_BYTE, // type
pvGLPixels // buffer ptr
);
// save area is valid size...
//
if (BMP_Open(psFilename, iWidth, iHeight))
{
for (int y=0; y<iHeight; y++)
{
LPGLRGBBYTES
lpGLRGBBytes = (LPGLRGBBYTES) pvGLPixels;
lpGLRGBBytes+= y * iWidth;
for (int x=0; x<iWidth; x++, lpGLRGBBytes++)
{
BMP_WritePixel(lpGLRGBBytes->r,lpGLRGBBytes->g,lpGLRGBBytes->b);
}
BMP_WriteLinePadding(iWidth); // arg is # pixels per row
}
BMP_Close(psFilename,false); // false = bFlipFinal
bReturn = true;
}
free(pvGLPixels);
pvGLPixels = NULL; // yeah...yeah
}
glPixelStorei(GL_PACK_ALIGNMENT,iOldPack);
return bReturn;
}
#endif