#include "std.h" #include "gxruntime.h" #include "zmouse.h" #define SPI_SETMOUSESPEED 113 struct gxRuntime::GfxMode{ DDSURFACEDESC2 desc; }; struct gxRuntime::GfxDriver{ GUID *guid; std::string name; std::vector modes; #ifdef PRO D3DDEVICEDESC7 d3d_desc; #endif }; static const int static_ws=WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX; static const int scaled_ws=WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX; static string app_title; static string app_close; static gxRuntime *runtime; static bool busy,suspended; static volatile bool run_flag; static DDSURFACEDESC2 desktop_desc; typedef int (_stdcall *LibFunc)( const void *in,int in_sz,void *out,int out_sz ); struct gxDll{ HINSTANCE hinst; map funcs; }; static map libs; static LRESULT CALLBACK windowProc( HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam ); //current gfx mode // //0=NONE //1=SCALED WINDOW //2=FIXED SIZE WINDOW //3=EXCLUSIVE // static int gfx_mode; static bool gfx_lost; static bool auto_suspend; //for modes 1 and 2 static int mod_cnt; static MMRESULT timerID; static IDirectDrawClipper *clipper; static IDirectDrawSurface7 *primSurf; static Debugger *debugger; static set timers; enum{ WM_STOP=WM_USER+1,WM_RUN,WM_END }; //////////////////// // STATIC STARTUP // //////////////////// gxRuntime *gxRuntime::openRuntime( HINSTANCE hinst,const string &cmd_line,Debugger *d ){ if( runtime ) return 0; //create debugger debugger=d; //create WNDCLASS WNDCLASS wndclass; memset(&wndclass,0,sizeof(wndclass)); wndclass.style=CS_HREDRAW|CS_VREDRAW|CS_OWNDC; wndclass.lpfnWndProc=::windowProc; wndclass.hInstance=hinst; wndclass.lpszClassName="Blitz Runtime Class"; wndclass.hCursor=(HCURSOR)LoadCursor( 0,IDC_ARROW ); wndclass.hbrBackground=(HBRUSH)GetStockObject( BLACK_BRUSH ); RegisterClass( &wndclass ); gfx_mode=0; clipper=0;primSurf=0; busy=suspended=false; run_flag=true; const char *app_t=" "; int ws=WS_CAPTION,ws_ex=0; HWND hwnd=CreateWindowEx( ws_ex,"Blitz Runtime Class",app_t,ws,0,0,0,0,0,0,0,0 ); UpdateWindow( hwnd ); runtime=d_new gxRuntime( hinst,cmd_line,hwnd ); return runtime; } void gxRuntime::closeRuntime( gxRuntime *r ){ if( !runtime || runtime!=r ) return; map::const_iterator it; for( it=libs.begin();it!=libs.end();++it ){ FreeLibrary( it->second->hinst ); } libs.clear(); delete runtime; runtime=0; } ////////////////////////// // RUNTIME CONSTRUCTION // ////////////////////////// typedef int (_stdcall *SetAppCompatDataFunc)( int x,int y ); gxRuntime::gxRuntime( HINSTANCE hi,const string &cl,HWND hw ): hinst(hi),cmd_line(cl),hwnd(hw),curr_driver(0),enum_all(false), pointer_visible(true),audio(0),input(0),graphics(0),fileSystem(0),use_di(false){ CoInitialize( 0 ); enumGfx(); TIMECAPS tc; timeGetDevCaps( &tc,sizeof(tc) ); timeBeginPeriod( tc.wPeriodMin ); memset( &osinfo,0,sizeof(osinfo) ); osinfo.dwOSVersionInfoSize=sizeof(osinfo); GetVersionEx( &osinfo ); HMODULE ddraw=LoadLibraryA( "ddraw.dll" ); if( ddraw ){ SetAppCompatDataFunc SetAppCompatData=(SetAppCompatDataFunc)GetProcAddress( ddraw,"SetAppCompatData" ); if( SetAppCompatData ) SetAppCompatData( 12,0 ); FreeLibrary( ddraw ); } } gxRuntime::~gxRuntime(){ while( timers.size() ) freeTimer( *timers.begin() ); if( audio ) closeAudio( audio ); if( graphics ) closeGraphics( graphics ); if( input ) closeInput( input ); TIMECAPS tc; timeGetDevCaps( &tc,sizeof(tc) ); timeEndPeriod( tc.wPeriodMin ); denumGfx(); DestroyWindow( hwnd ); UnregisterClass( "Blitz Runtime Class",hinst ); CoUninitialize(); } void gxRuntime::pauseAudio(){ if( audio ) audio->pause(); } void gxRuntime::resumeAudio(){ if( audio ) audio->resume(); } void gxRuntime::backupGraphics(){ if( auto_suspend ){ graphics->backup(); } } void gxRuntime::restoreGraphics(){ if( auto_suspend ){ if( !graphics->restore() ) gfx_lost=true; } } void gxRuntime::resetInput(){ if( input ) input->reset(); } void gxRuntime::acquireInput(){ if( !input ) return; if( gfx_mode==3 ){ if( use_di ){ use_di=input->acquire(); }else{ } } input->reset(); } void gxRuntime::unacquireInput(){ if( !input ) return; if( gfx_mode==3 && use_di ) input->unacquire(); input->reset(); } ///////////// // SUSPEND // ///////////// void gxRuntime::suspend(){ busy=true; pauseAudio(); backupGraphics(); unacquireInput(); suspended=true; busy=false; if( gfx_mode==3 ) ShowCursor(1); if( debugger ) debugger->debugStop(); } //////////// // RESUME // //////////// void gxRuntime::resume(){ if( gfx_mode==3 ) ShowCursor(0); busy=true; acquireInput(); restoreGraphics(); resumeAudio(); suspended=false; busy=false; if( debugger ) debugger->debugRun(); } /////////////////// // FORCE SUSPEND // /////////////////// void gxRuntime::forceSuspend(){ if( gfx_mode==3 ){ SetForegroundWindow( GetDesktopWindow() ); ShowWindow( GetDesktopWindow(),SW_SHOW ); }else{ suspend(); } } ////////////////// // FORCE RESUME // ////////////////// void gxRuntime::forceResume(){ if( gfx_mode==3 ){ SetForegroundWindow( hwnd ); ShowWindow( hwnd,SW_SHOWMAXIMIZED ); }else{ resume(); } } /////////// // PAINT // /////////// void gxRuntime::paint(){ switch( gfx_mode ){ case 0: { } break; case 1:case 2: //scaled windowed mode. { RECT src,dest; src.left=src.top=0; GetClientRect( hwnd,&dest ); src.right=gfx_mode==1 ? graphics->getWidth() : dest.right; src.bottom=gfx_mode==1 ? graphics->getHeight() : dest.bottom; POINT p;p.x=p.y=0;ClientToScreen( hwnd,&p ); dest.left+=p.x;dest.right+=p.x; dest.top+=p.y;dest.bottom+=p.y; gxCanvas *f=graphics->getFrontCanvas(); primSurf->Blt( &dest,f->getSurface(),&src,0,0 ); } break; case 3: { //exclusive mode } break; } } ////////// // FLIP // ////////// void gxRuntime::flip( bool vwait ){ gxCanvas *b=graphics->getBackCanvas(); gxCanvas *f=graphics->getFrontCanvas(); int n; switch( gfx_mode ){ case 1:case 2: if( vwait ) graphics->vwait(); f->setModify( b->getModify() ); if( f->getModify()!=mod_cnt ){ mod_cnt=f->getModify(); paint(); } break; case 3: if( vwait ){ BOOL vb; while( graphics->dirDraw->GetVerticalBlankStatus( &vb )>=0 && vb ) {} n=f->getSurface()->Flip( 0,DDFLIP_WAIT ); }else{ n=f->getSurface()->Flip( 0,DDFLIP_NOVSYNC|DDFLIP_WAIT ); } if( n>=0 ) return; string t="Flip Failed! Return code:"+itoa(n&0x7fff); debugLog( t.c_str() ); break; } } //////////////// // MOVE MOUSE // //////////////// void gxRuntime::moveMouse( int x,int y ){ POINT p; RECT rect; switch( gfx_mode ){ case 1: GetClientRect( hwnd,&rect ); x=x*(rect.right-rect.left)/graphics->getWidth(); y=y*(rect.bottom-rect.top)/graphics->getHeight(); case 2: p.x=x;p.y=y;ClientToScreen( hwnd,&p );x=p.x;y=p.y; break; case 3: if( use_di ) return; break; default: return; } SetCursorPos( x,y ); } ///////////////// // WINDOW PROC // ///////////////// LRESULT gxRuntime::windowProc( HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam ){ if( busy ){ return DefWindowProc( hwnd,msg,wparam,lparam ); } PAINTSTRUCT ps; //handle 'special' messages! switch( msg ){ case WM_PAINT: if( gfx_mode && !auto_suspend ){ if( !graphics->restore() ) gfx_lost=true; } BeginPaint( hwnd,&ps ); paint(); EndPaint( hwnd,&ps ); return DefWindowProc( hwnd,msg,wparam,lparam ); case WM_ERASEBKGND: return gfx_mode ? 1 : DefWindowProc( hwnd,msg,wparam,lparam ); case WM_CLOSE: if( app_close.size() ){ int n=MessageBox( hwnd,app_close.c_str(),app_title.c_str(),MB_OKCANCEL|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST ); if( n!=IDOK ) return 0; } asyncEnd(); return 0; case WM_SETCURSOR: if( !suspended ){ if( gfx_mode==3 ){ SetCursor( 0 ); return 1; }else if( !pointer_visible ){ POINT p; GetCursorPos( &p ); ScreenToClient( hwnd,&p ); RECT r;GetClientRect( hwnd,&r ); if( p.x>=0 && p.y>=0 && p.xacquire(); return DefWindowProc( hwnd,msg,wparam,lparam ); } static const int MK_ALLBUTTONS=MK_LBUTTON|MK_RBUTTON|MK_MBUTTON; //handle input messages switch( msg ){ case WM_LBUTTONDOWN: input->wm_mousedown(1); SetCapture(hwnd); break; case WM_LBUTTONUP: input->wm_mouseup(1); if( !(wparam&MK_ALLBUTTONS) ) ReleaseCapture(); break; case WM_RBUTTONDOWN: input->wm_mousedown(2); SetCapture( hwnd ); break; case WM_RBUTTONUP: input->wm_mouseup(2); if( !(wparam&MK_ALLBUTTONS) ) ReleaseCapture(); break; case WM_MBUTTONDOWN: input->wm_mousedown(3); SetCapture( hwnd ); break; case WM_MBUTTONUP: input->wm_mouseup(3); if( !(wparam&MK_ALLBUTTONS) ) ReleaseCapture(); break; case WM_MOUSEMOVE: if( !graphics ) break; if( gfx_mode==3 && !use_di ){ POINT p;GetCursorPos( &p ); input->wm_mousemove( p.x,p.y ); }else{ int x=(short)(lparam&0xffff),y=lparam>>16; if( gfx_mode==1 ){ RECT rect;GetClientRect( hwnd,&rect ); x=x*graphics->getWidth()/(rect.right-rect.left); y=y*graphics->getHeight()/(rect.bottom-rect.top); } if( x<0 ) x=0; else if( x>=graphics->getWidth() ) x=graphics->getWidth()-1; if( y<0 ) y=0; else if( y>=graphics->getHeight() ) y=graphics->getHeight()-1; input->wm_mousemove( x,y ); } break; case WM_MOUSEWHEEL: input->wm_mousewheel( (short)HIWORD( wparam ) ); break; case WM_KEYDOWN:case WM_SYSKEYDOWN: if( lparam & 0x40000000 ) break; if( int n=((lparam>>17)&0x80)|((lparam>>16)&0x7f) ) input->wm_keydown( n ); break; case WM_KEYUP:case WM_SYSKEYUP: if( int n=((lparam>>17)&0x80)|((lparam>>16)&0x7f) ) input->wm_keyup( n ); break; default: return DefWindowProc( hwnd,msg,wparam,lparam ); } return 0; } static LRESULT CALLBACK windowProc( HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam ){ if( runtime ) return runtime->windowProc( hwnd,msg,wparam,lparam ); return DefWindowProc( hwnd,msg,wparam,lparam ); } ////////////////////////////// //STOP FROM EXTERNAL SOURCE // ////////////////////////////// void gxRuntime::asyncStop(){ PostMessage( hwnd,WM_STOP,0,0 ); } ////////////////////////////// //RUN FROM EXTERNAL SOURCE // ////////////////////////////// void gxRuntime::asyncRun(){ PostMessage( hwnd,WM_RUN,0,0 ); } ////////////////////////////// // END FROM EXTERNAL SOURCE // ////////////////////////////// void gxRuntime::asyncEnd(){ PostMessage( hwnd,WM_END,0,0 ); } ////////// // IDLE // ////////// bool gxRuntime::idle(){ for(;;){ MSG msg; if( suspended && run_flag ){ GetMessage( &msg,0,0,0 ); }else{ if( !PeekMessage( &msg,0,0,0,PM_REMOVE ) ) return run_flag; } switch( msg.message ){ case WM_STOP: if( !suspended ) forceSuspend(); break; case WM_RUN: if( suspended ) forceResume(); break; case WM_END: debugger=0; run_flag=false; break; default: DispatchMessage( &msg ); } } return run_flag; } /////////// // DELAY // /////////// bool gxRuntime::delay( int ms ){ int t=timeGetTime()+ms; for(;;){ if( !idle() ) return false; int d=t-timeGetTime(); //how long left to wait if( d<=0 ) return true; if( d>100 ) d=100; Sleep( d ); } } /////////////// // DEBUGSTMT // /////////////// void gxRuntime::debugStmt( int pos,const char *file ){ if( debugger ) debugger->debugStmt( pos,file ); } /////////////// // DEBUGSTOP // /////////////// void gxRuntime::debugStop(){ if( !suspended ) forceSuspend(); } //////////////// // DEBUGENTER // //////////////// void gxRuntime::debugEnter( void *frame,void *env,const char *func ){ if( debugger ) debugger->debugEnter( frame,env,func ); } //////////////// // DEBUGLEAVE // //////////////// void gxRuntime::debugLeave(){ if( debugger ) debugger->debugLeave(); } //////////////// // DEBUGERROR // //////////////// void gxRuntime::debugError( const char *t ){ if( !debugger ) return; Debugger *d=debugger; asyncEnd(); if( !suspended ){ forceSuspend(); } d->debugMsg( t,true ); } /////////////// // DEBUGINFO // /////////////// void gxRuntime::debugInfo( const char *t ){ if( !debugger ) return; Debugger *d=debugger; asyncEnd(); if( !suspended ){ forceSuspend(); } d->debugMsg( t,false ); } ////////////// // DEBUGLOG // ////////////// void gxRuntime::debugLog( const char *t ){ if( debugger ) debugger->debugLog( t ); } ///////////////////////// // RETURN COMMAND LINE // ///////////////////////// string gxRuntime::commandLine(){ return cmd_line; } ///////////// // EXECUTE // ///////////// bool gxRuntime::execute( const string &cmd_line ){ if( !cmd_line.size() ) return false; //convert cmd_line to cmd and params string cmd=cmd_line,params; while( cmd.size() && cmd[0]==' ' ) cmd=cmd.substr( 1 ); if( cmd.find( '\"' )==0 ){ int n=cmd.find( '\"',1 ); if( n!=string::npos ){ params=cmd.substr( n+1 ); cmd=cmd.substr( 1,n-1 ); } }else{ int n=cmd.find( ' ' ); if( n!=string::npos ){ params=cmd.substr( n+1 ); cmd=cmd.substr( 0,n ); } } while( params.size() && params[0]==' ' ) params=params.substr( 1 ); while( params.size() && params[params.size()-1]==' ' ) params=params.substr( 0,params.size()-1 ); SetForegroundWindow( GetDesktopWindow() ); return (int)ShellExecute( GetDesktopWindow(),0,cmd.c_str(),params.size() ? params.c_str() : 0,0,SW_SHOW )>32; } /////////////// // APP TITLE // /////////////// void gxRuntime::setTitle( const string &t,const string &e ){ app_title=t; app_close=e; SetWindowText( hwnd,app_title.c_str() ); } ////////////////// // GETMILLISECS // ////////////////// int gxRuntime::getMilliSecs(){ return timeGetTime(); } ///////////////////// // POINTER VISIBLE // ///////////////////// void gxRuntime::setPointerVisible( bool vis ){ if( pointer_visible==vis ) return; pointer_visible=vis; if( gfx_mode==3 ) return; //force a WM_SETCURSOR POINT pt; GetCursorPos( &pt ); SetCursorPos( pt.x,pt.y ); } ///////////////// // AUDIO SETUP // ///////////////// gxAudio *gxRuntime::openAudio( int flags ){ if( audio ) return 0; int f_flags= FSOUND_INIT_GLOBALFOCUS| FSOUND_INIT_USEDEFAULTMIDISYNTH; FSOUND_SetHWND( hwnd ); if( !FSOUND_Init( 44100,1024,f_flags ) ){ return 0; } audio=d_new gxAudio( this ); return audio; } void gxRuntime::closeAudio( gxAudio *a ){ if( !audio || audio!=a ) return; delete audio; audio=0; } ///////////////// // INPUT SETUP // ///////////////// gxInput *gxRuntime::openInput( int flags ){ if( input ) return 0; IDirectInput7 *di; if( DirectInputCreateEx( hinst,DIRECTINPUT_VERSION,IID_IDirectInput7,(void**)&di,0 )>=0 ){ input=d_new gxInput( this,di ); acquireInput(); }else{ debugInfo( "Create DirectInput failed" ); } return input; } void gxRuntime::closeInput( gxInput *i ){ if( !input || input!=i ) return; unacquireInput(); delete input; input=0; } ///////////////////////////////////////////////////// // TIMER CALLBACK FOR AUTOREFRESH OF WINDOWED MODE // ///////////////////////////////////////////////////// static void CALLBACK timerCallback( UINT id,UINT msg,DWORD user,DWORD dw1,DWORD dw2 ){ if( gfx_mode ){ gxCanvas *f=runtime->graphics->getFrontCanvas(); if( f->getModify()!=mod_cnt ){ mod_cnt=f->getModify(); InvalidateRect( runtime->hwnd,0,false ); } } } //////////////////// // GRAPHICS SETUP // //////////////////// void gxRuntime::backupWindowState(){ GetWindowRect( hwnd,&t_rect ); t_style=GetWindowLong( hwnd,GWL_STYLE ); } void gxRuntime::restoreWindowState(){ SetWindowLong( hwnd,GWL_STYLE,t_style ); SetWindowPos( hwnd,0,t_rect.left,t_rect.top, t_rect.right-t_rect.left,t_rect.bottom-t_rect.top, SWP_NOZORDER|SWP_FRAMECHANGED ); } bool gxRuntime::setDisplayMode( int w,int h,int d,bool d3d,IDirectDraw7 *dirDraw ){ if( d ) return dirDraw->SetDisplayMode( w,h,d,0,0 )>=0; int best_d=0; if( d3d ){ #ifdef PRO int bd=curr_driver->d3d_desc.dwDeviceRenderBitDepth; if( bd & DDBD_32 ) best_d=32; else if( bd & DDBD_24 ) best_d=24; else if( bd & DDBD_16 ) best_d=16; #endif }else{ int best_n=0; for( d=16;d<=32;d+=8 ){ if( dirDraw->SetDisplayMode( w,h,d,0,0 )<0 ) continue; DDCAPS caps={ sizeof(caps) }; dirDraw->GetCaps( &caps,0 ); int n=0; if( caps.dwCaps & DDCAPS_BLT ) ++n; if( caps.dwCaps & DDCAPS_BLTCOLORFILL ) ++n; if( caps.dwCKeyCaps & DDCKEYCAPS_SRCBLT ) ++n; if( caps.dwCaps2 & DDCAPS2_WIDESURFACES ) ++n; if( n==4 ) return true; if( n>best_n ){ best_d=d; best_n=n; } dirDraw->RestoreDisplayMode(); } } return best_d ? dirDraw->SetDisplayMode( w,h,best_d,0,0 )>=0 : false; } gxGraphics *gxRuntime::openWindowedGraphics( int w,int h,int d,bool d3d ){ IDirectDraw7 *dd; if( DirectDrawCreateEx( curr_driver->guid,(void**)&dd,IID_IDirectDraw7,0 )<0 ) return 0; //set coop level if( dd->SetCooperativeLevel( hwnd,DDSCL_NORMAL )>=0 ){ //create primary surface IDirectDrawSurface7 *ps; DDSURFACEDESC2 desc={sizeof(desc)}; desc.dwFlags=DDSD_CAPS; desc.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE; if( dd->CreateSurface( &desc,&ps,0 )>=0 ){ //create clipper IDirectDrawClipper *cp; if( dd->CreateClipper( 0,&cp,0 )>=0 ){ //attach clipper if( ps->SetClipper( cp )>=0 ){ //set clipper HWND if( cp->SetHWnd( 0,hwnd )>=0 ){ //create front buffer IDirectDrawSurface7 *fs; DDSURFACEDESC2 desc={sizeof(desc)}; desc.dwFlags=DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS; desc.dwWidth=w;desc.dwHeight=h; desc.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN; if( d3d ) desc.ddsCaps.dwCaps|=DDSCAPS_3DDEVICE; if( dd->CreateSurface( &desc,&fs,0 )>=0 ){ if( timerID=timeSetEvent( 100,10,timerCallback,0,TIME_PERIODIC ) ){ //Success! clipper=cp; primSurf=ps; mod_cnt=0; fs->AddRef(); return d_new gxGraphics( this,dd,fs,fs,d3d ); } fs->Release(); } } } cp->Release(); } ps->Release(); } } dd->Release(); return 0; } gxGraphics *gxRuntime::openExclusiveGraphics( int w,int h,int d,bool d3d ){ IDirectDraw7 *dd; if( DirectDrawCreateEx( curr_driver->guid,(void**)&dd,IID_IDirectDraw7,0 )<0 ) return 0; //Set coop level if( dd->SetCooperativeLevel( hwnd,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN|DDSCL_ALLOWREBOOT )>=0 ){ //Set display mode if( setDisplayMode( w,h,d,d3d,dd ) ){ //create primary surface IDirectDrawSurface7 *ps; DDSURFACEDESC2 desc={sizeof(desc)}; desc.dwFlags=DDSD_CAPS|DDSD_BACKBUFFERCOUNT; desc.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE|DDSCAPS_COMPLEX|DDSCAPS_FLIP; desc.dwBackBufferCount=1; if( d3d ) desc.ddsCaps.dwCaps|=DDSCAPS_3DDEVICE; if( dd->CreateSurface( &desc,&ps,0 )>=0 ){ //find back surface IDirectDrawSurface7 *bs; DDSCAPS2 caps={sizeof caps}; caps.dwCaps=DDSCAPS_BACKBUFFER; if( ps->GetAttachedSurface( &caps,&bs )>=0 ){ return d_new gxGraphics( this,dd,ps,bs,d3d ); } ps->Release(); } dd->RestoreDisplayMode(); } } dd->Release(); return 0; } gxGraphics *gxRuntime::openGraphics( int w,int h,int d,int driver,int flags ){ if( graphics ) return 0; busy=true; bool d3d=flags & gxGraphics::GRAPHICS_3D ? true : false; bool windowed=flags & gxGraphics::GRAPHICS_WINDOWED ? true : false; if( windowed ) driver=0; curr_driver=drivers[driver]; if( windowed ){ if( graphics=openWindowedGraphics( w,h,d,d3d ) ){ gfx_mode=(flags & gxGraphics::GRAPHICS_SCALED) ? 1 : 2; auto_suspend=(flags & gxGraphics::GRAPHICS_AUTOSUSPEND) ? true : false; int ws,ww,hh; if( gfx_mode==1 ){ ws=scaled_ws; RECT c_r; GetClientRect( hwnd,&c_r ); ww=c_r.right-c_r.left; hh=c_r.bottom-c_r.top; }else{ ws=static_ws; ww=w; hh=h; } SetWindowLong( hwnd,GWL_STYLE,ws ); SetWindowPos( hwnd,0,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED ); RECT w_r,c_r; GetWindowRect( hwnd,&w_r ); GetClientRect( hwnd,&c_r ); int tw=(w_r.right-w_r.left)-(c_r.right-c_r.left); int th=(w_r.bottom-w_r.top)-(c_r.bottom-c_r.top ); int cx=( GetSystemMetrics( SM_CXSCREEN )-ww )/2; int cy=( GetSystemMetrics( SM_CYSCREEN )-hh )/2; POINT zz={0,0}; ClientToScreen( hwnd,&zz ); int bw=zz.x-w_r.left,bh=zz.y-w_r.top; int wx=cx-bw,wy=cy-bh;if( wy<0 ) wy=0; //not above top! MoveWindow( hwnd,wx,wy,ww+tw,hh+th,true ); } }else{ backupWindowState(); SetWindowLong( hwnd,GWL_STYLE,WS_VISIBLE|WS_POPUP ); SetWindowPos( hwnd,0,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED ); ShowCursor( 0 ); if( graphics=openExclusiveGraphics( w,h,d,d3d ) ){ gfx_mode=3; auto_suspend=true; SetCursorPos(0,0); acquireInput(); }else{ ShowCursor( 1 ); restoreWindowState(); } } if( !graphics ) curr_driver=0; gfx_lost=false; busy=false; return graphics; } void gxRuntime::closeGraphics( gxGraphics *g ){ if( !graphics || graphics!=g ) return; auto_suspend=false; busy=true; unacquireInput(); if( timerID ){ timeKillEvent( timerID );timerID=0; } if( clipper ){ clipper->Release();clipper=0; } if( primSurf ){ primSurf->Release();primSurf=0; } delete graphics;graphics=0; if( gfx_mode==3 ){ ShowCursor( 1 ); restoreWindowState(); } gfx_mode=0; gfx_lost=false; busy=false; } bool gxRuntime::graphicsLost(){ return gfx_lost; } gxFileSystem *gxRuntime::openFileSystem( int flags ){ if( fileSystem ) return 0; fileSystem=d_new gxFileSystem(); return fileSystem; } void gxRuntime::closeFileSystem( gxFileSystem *f ){ if( !fileSystem || fileSystem!=f ) return; delete fileSystem; fileSystem=0; } //////////////////// // GFX ENUM STUFF // //////////////////// static HRESULT WINAPI enumMode( DDSURFACEDESC2 *desc,void *context ){ int dp=desc->ddpfPixelFormat.dwRGBBitCount; if( dp==16 || dp==24 || dp==32 ){ gxRuntime::GfxMode *m=d_new gxRuntime::GfxMode; m->desc=*desc; gxRuntime::GfxDriver *d=(gxRuntime::GfxDriver*)context; d->modes.push_back( m ); } return DDENUMRET_OK; } #ifdef PRO static int maxDevType; static HRESULT CALLBACK enumDevice( char *desc,char *name,D3DDEVICEDESC7 *devDesc,void *context ){ int t=0; GUID guid=devDesc->deviceGUID; if( guid==IID_IDirect3DRGBDevice ) t=1; else if( guid==IID_IDirect3DHALDevice ) t=2; else if( guid==IID_IDirect3DTnLHalDevice ) t=3; if( t>1 && t>maxDevType ){ maxDevType=t; gxRuntime::GfxDriver *d=(gxRuntime::GfxDriver*)context; d->d3d_desc=*devDesc; } return D3DENUMRET_OK; } #endif static BOOL WINAPI enumDriver( GUID FAR *guid,LPSTR desc,LPSTR name,LPVOID context,HMONITOR hm ){ IDirectDraw7 *dd; if( DirectDrawCreateEx( guid,(void**)&dd,IID_IDirectDraw7,0 )<0 ) return 0; if( !guid && !desktop_desc.ddpfPixelFormat.dwRGBBitCount ){ desktop_desc.dwSize=sizeof(desktop_desc); dd->GetDisplayMode( &desktop_desc ); } gxRuntime::GfxDriver *d=d_new gxRuntime::GfxDriver; d->guid=guid ? d_new GUID( *guid ) : 0; d->name=desc;//string( name )+" "+string( desc ); #ifdef PRO memset( &d->d3d_desc,0,sizeof(d->d3d_desc) ); IDirect3D7 *dir3d; if( dd->QueryInterface( IID_IDirect3D7,(void**)&dir3d )>=0 ){ maxDevType=0; dir3d->EnumDevices( enumDevice,d ); dir3d->Release(); } #endif vector *drivers=(vector*)context; drivers->push_back( d ); dd->EnumDisplayModes( 0,0,d,enumMode ); dd->Release(); return 1; } void gxRuntime::enumGfx(){ denumGfx(); if( enum_all ){ DirectDrawEnumerateEx( enumDriver,&drivers,DDENUM_ATTACHEDSECONDARYDEVICES|DDENUM_NONDISPLAYDEVICES ); }else{ DirectDrawEnumerateEx( enumDriver,&drivers,0 ); } } void gxRuntime::denumGfx(){ for( int k=0;kmodes.size();++j ) delete d->modes[j]; delete d->guid; delete d; } drivers.clear(); } int gxRuntime::numGraphicsDrivers(){ if( !enum_all ){ enum_all=true; enumGfx(); } return drivers.size(); } void gxRuntime::graphicsDriverInfo( int driver,string *name,int *c ){ GfxDriver *g=drivers[driver]; int caps=0; #ifdef PRO if( g->d3d_desc.dwDeviceRenderBitDepth ) caps|=GFXMODECAPS_3D; #endif *name=g->name; *c=caps; } int gxRuntime::numGraphicsModes( int driver ){ return drivers[driver]->modes.size(); } void gxRuntime::graphicsModeInfo( int driver,int mode,int *w,int *h,int *d,int *c ){ GfxDriver *g=drivers[driver]; GfxMode *m=g->modes[mode]; int caps=0; #ifdef PRO int bd=0; switch( m->desc.ddpfPixelFormat.dwRGBBitCount ){ case 16:bd=DDBD_16;break; case 24:bd=DDBD_24;break; case 32:bd=DDBD_32;break; } if( g->d3d_desc.dwDeviceRenderBitDepth & bd ) caps|=GFXMODECAPS_3D; #endif *w=m->desc.dwWidth; *h=m->desc.dwHeight; *d=m->desc.ddpfPixelFormat.dwRGBBitCount; *c=caps; } void gxRuntime::windowedModeInfo( int *c ){ int caps=0; #ifdef PRO int bd=0; switch( desktop_desc.ddpfPixelFormat.dwRGBBitCount ){ case 16:bd=DDBD_16;break; case 24:bd=DDBD_24;break; case 32:bd=DDBD_32;break; } if( drivers[0]->d3d_desc.dwDeviceRenderBitDepth & bd ) caps|=GFXMODECAPS_3D; #endif *c=caps; } gxTimer *gxRuntime::createTimer( int hertz ){ gxTimer *t=d_new gxTimer( this,hertz ); timers.insert( t ); return t; } void gxRuntime::freeTimer( gxTimer *t ){ if( !timers.count( t ) ) return; timers.erase( t ); delete t; } static string toDir( string t ){ if( t.size() && t[t.size()-1]!='\\' ) t+='\\'; return t; } string gxRuntime::systemProperty( const std::string &p ){ char buff[MAX_PATH+1]; string t=tolower(p); if( t=="cpu" ){ return "Intel"; }else if( t=="os" ){ switch( osinfo.dwMajorVersion ){ case 3: switch( osinfo.dwMinorVersion ){ case 51:return "Windows NT 3.1"; } break; case 4: switch( osinfo.dwMinorVersion ){ case 0:return "Windows 95"; case 10:return "Windows 98"; case 90:return "Windows ME"; } break; case 5: switch( osinfo.dwMinorVersion ){ case 0:return "Windows 2000"; case 1:return "Windows XP"; case 2:return "Windows Server 2003"; } break; case 6: switch( osinfo.dwMinorVersion ){ case 0:return "Windows Vista"; case 1:return "Windows 7"; } break; } }else if( t=="appdir" ){ if( GetModuleFileName( 0,buff,MAX_PATH ) ){ string t=buff; int n=t.find_last_of( '\\' ); if( n!=string::npos ) t=t.substr( 0,n ); return toDir( t ); } }else if( t=="apphwnd" ){ return itoa( (int)hwnd ); }else if( t=="apphinstance" ){ return itoa( (int)hinst ); }else if( t=="windowsdir" ){ if( GetWindowsDirectory( buff,MAX_PATH ) ) return toDir( buff ); }else if( t=="systemdir" ){ if( GetSystemDirectory( buff,MAX_PATH ) ) return toDir( buff ); }else if( t=="tempdir" ){ if( GetTempPath( MAX_PATH,buff ) ) return toDir( buff ); }else if( t=="direct3d7" ){ if( graphics ) return itoa( (int)graphics->dir3d ); }else if( t=="direct3ddevice7" ){ if( graphics ) return itoa( (int)graphics->dir3dDev ); }else if( t=="directdraw7" ){ if( graphics ) return itoa( (int)graphics->dirDraw ); }else if( t=="directinput7" ){ if( input ) return itoa( (int)input->dirInput ); } return ""; } void gxRuntime::enableDirectInput( bool enable ){ if( use_di=enable ){ acquireInput(); }else{ unacquireInput(); } } int gxRuntime::callDll( const std::string &dll,const std::string &func,const void *in,int in_sz,void *out,int out_sz ){ map::const_iterator lib_it=libs.find( dll ); if( lib_it==libs.end() ){ HINSTANCE h=LoadLibrary( dll.c_str() ); if( !h ) return 0; gxDll *t=d_new gxDll; t->hinst=h; lib_it=libs.insert( make_pair( dll,t ) ).first; } gxDll *t=lib_it->second; map::const_iterator fun_it=t->funcs.find( func ); if( fun_it==t->funcs.end() ){ LibFunc f=(LibFunc)GetProcAddress( t->hinst,func.c_str() ); if( !f ) return 0; fun_it=t->funcs.insert( make_pair( func,f ) ).first; } static void *save_esp; _asm{ mov [save_esp],esp }; int n=fun_it->second( in,in_sz,out,out_sz ); _asm{ mov esp,[save_esp] }; return n; }