Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
fr_public/werkkzeug3/_start.cpp
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
8075 lines (6810 sloc)
190 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // This file is distributed under a BSD license. See LICENSE.txt for details. | |
| #include "_types.hpp" | |
| #include "_start.hpp" | |
| #include "_startdx.hpp" | |
| #include "material11.hpp" | |
| #if sLINK_UTIL | |
| #include "_util.hpp" // for sPerfMon->Flip() | |
| #endif | |
| #if sLINK_RYGDXT | |
| #include "_rygdxt.hpp" | |
| #endif | |
| #define WINVER 0x500 | |
| #define _WIN32_WINNT 0x0500 | |
| #define DIRECTINPUT_VERSION 0x0800 | |
| #define DIRECTSOUND_VERSION 0x0800 | |
| #define sPLAYER_SCREENX 1024 | |
| #define sPLAYER_SCREENY 768 | |
| #define sPLAYER_FULLSCREEN !sDEBUG | |
| #define sPLAYER_DIALOG 1 | |
| #define sINTRO_NO_ALT_TAB 0 // setting this to 1 saves ~190 bytes | |
| #if !sINTRO | |
| const sChar *sWindowTitle=".theprodukkt"; | |
| #else | |
| const sChar *sWindowTitle="fr-052: platinum"; | |
| #endif | |
| #define D3D_DEBUG_INFO | |
| #define INITGUID // to get rid of dxguid.lib | |
| #include <windows.h> | |
| #include <d3d9.h> | |
| #include <dinput.h> | |
| #include <olectl.h> | |
| #include <dsound.h> | |
| #include <crtdbg.h> | |
| #include <malloc.h> | |
| #include <float.h> | |
| #define WINZERO(x) {sSetMem(&x,0,sizeof(x));} | |
| #define WINSET(x) {sSetMem(&x,0,sizeof(x));x.dwSize = sizeof(x);} | |
| #define RELEASE(x) {if(x)x->Release();x=0;} | |
| #if sINTRO | |
| #define DXERROR(hr) {if(FAILED(hr))sFatal("%s(%d) : directx error %08x (%d)",__FILE__,__LINE__,hr,hr&0x3fff);} | |
| #else | |
| #define DXERROR(hr) {HRESULT res=hr;if(FAILED(res)) ReportDXError(__FILE__,__LINE__,hr);} | |
| #endif | |
| #undef DeleteFile | |
| #undef GetCurrentDirectory | |
| #undef LoadBitmap | |
| #undef GetCommandLine | |
| #pragma comment(lib,"kernel32.lib") | |
| #pragma comment(lib,"gdi32.lib") | |
| #pragma comment(lib,"user32.lib") | |
| #pragma comment(lib,"comdlg32.lib") | |
| #pragma comment(lib,"ole32.lib") | |
| #pragma comment(lib,"olepro32.lib") | |
| #pragma comment(lib,"oleaut32.lib") | |
| #pragma comment(lib,"winmm.lib") | |
| #pragma comment(lib,"opengl32.lib") | |
| #pragma comment(lib,"dinput8.lib") | |
| #if sINTRO && !defined(_DEBUG) | |
| #pragma comment(linker,"/nodefaultlib") | |
| #endif | |
| #if !sPLAYER | |
| #pragma comment(lib,"shell32.lib") | |
| #endif | |
| #if !sPLAYER | |
| #include <mmsystem.h> | |
| #include <vfw.h> | |
| #pragma comment(lib,"vfw32.lib") | |
| #endif | |
| #define LOGGING 1 // log all create and release calls | |
| //#define DXERROR(hr) {OutputDebugString(#hr "\n");if(FAILED(hr))sFatal("%s(%d) : directx error %08x (%d)",__FILE__,__LINE__,hr,hr&0x3fff);} | |
| sMAKEZONE(FlipLock,"FlipLock",0xffff0000); | |
| sMAKEZONE(MtrlSet,"MtrlSet",0xff404040); | |
| sMAKEZONE(MtrlSetSetup,"MtrlSetSetup",0xff203040); | |
| sMAKEZONE(Sound3D,"Sound3D",0xff804040); | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** System Initialisation ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| class sBroker_ *sBroker; | |
| HMODULE d3dlib; | |
| HMODULE dilib; | |
| HMODULE dslib; | |
| typedef HRESULT (WINAPI * DirectInput8CreateT)(HINSTANCE hinst,DWORD dwVersion,REFIID riidltf,LPVOID* ppvOut,LPUNKNOWN punkOuter); | |
| typedef IDirect3D9* (WINAPI * Direct3DCreate9T)(UINT SDKVersion); | |
| typedef HRESULT (WINAPI * DirectSoundCreate8T)(LPCGUID lpcGuidDevice,LPDIRECTSOUND8 * ppDS8,LPUNKNOWN pUnkOuter); | |
| DirectInput8CreateT DirectInput8CreateP; | |
| Direct3DCreate9T Direct3DCreate9P; | |
| DirectSoundCreate8T DirectSoundCreate8P; | |
| HINSTANCE WInst; | |
| sChar *WCmdLine; | |
| sChar WFilename[2048]; | |
| HWND MsgWin; | |
| static sBool SingleCore; | |
| sSystem_ *sSystem; | |
| static sU64 sPerfFrame; | |
| static sF64 sPerfKalibFactor = 1.0f/1000; | |
| static sU64 sPerfKalibRDTSC; | |
| static sU64 sPerfKalibQuery; | |
| // dies sollten meistens konstanten sein, damit ein paar if's wegoptimieren | |
| // (auch ohne lekktor) | |
| // aber manche builds haben einen konfigurationsdialog... | |
| #if sCONFIGDIALOG | |
| sInt IntroScreenX=sPLAYER_SCREENX; | |
| sInt IntroScreenY=sPLAYER_SCREENY; | |
| sInt IntroFlags = sPLAYER_FULLSCREEN ? sSF_FULLSCREEN : 0; | |
| sInt IntroTargetAspect = 0; | |
| sInt IntroTexQuality = 1; | |
| sBool IntroShadows = sTRUE; | |
| #else | |
| const sInt IntroScreenX=sPLAYER_SCREENX; | |
| const sInt IntroScreenY=sPLAYER_SCREENY; | |
| const sInt IntroFlags = sPLAYER_FULLSCREEN ? sSF_FULLSCREEN : 0; | |
| sInt IntroTargetAspect = 0; | |
| sInt IntroTexQuality = 1; | |
| sBool IntroShadows = sTRUE; | |
| #endif | |
| sInt IntroLoop; | |
| sBool IntroStereo3D = sTRUE; | |
| static D3DMULTISAMPLE_TYPE MultiSampleType = D3DMULTISAMPLE_NONE; | |
| static sInt MultiSampleQuality = 0; | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| sInt WShow; | |
| HDC GDIScreenDC; | |
| HDC GDIDC; | |
| HBITMAP GDIHBM; | |
| BITMAPINFO FontBMI; | |
| HBITMAP FontHBM; | |
| HFONT FontHandle; | |
| sBool InitGDI(); | |
| void ExitGDI(); | |
| /****************************************************************************/ | |
| /* | |
| #define MAX_KEYQUEUE 16 | |
| #define MAX_MOUSEQUEUE 64 | |
| static sU32 KeyBuffer[MAX_KEYBUFFER]; | |
| static sInt KeyIndex; | |
| static sU32 KeyQual; | |
| static sU32 MouseX; | |
| static sU32 MouseY; | |
| static sU32 MouseZ; | |
| static sU32 MouseButtons; | |
| static sU32 MouseButtonsSave; | |
| */ | |
| sInt sFatality; | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** FVF Codes ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| struct FVFTableStruct | |
| { | |
| sInt Size; // size in bytes! | |
| D3DVERTEXELEMENT9 *Info; // dx declaration | |
| IDirect3DVertexDeclaration9 *Decl; // declaration object | |
| }; | |
| static D3DVERTEXELEMENT9 DeclDefault[] = | |
| { | |
| { 0, 0,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_POSITION ,0 }, | |
| { 0,12,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_NORMAL ,0 }, | |
| { 0,24,D3DDECLTYPE_FLOAT2 ,0,D3DDECLUSAGE_TEXCOORD ,0 }, | |
| D3DDECL_END() | |
| }; | |
| static D3DVERTEXELEMENT9 DeclDouble[] = | |
| { | |
| { 0, 0,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_POSITION ,0 }, | |
| { 0,12,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_COLOR ,0 }, | |
| { 0,16,D3DDECLTYPE_FLOAT2 ,0,D3DDECLUSAGE_TEXCOORD ,0 }, | |
| { 0,24,D3DDECLTYPE_FLOAT2 ,0,D3DDECLUSAGE_TEXCOORD ,1 }, | |
| D3DDECL_END() | |
| }; | |
| static D3DVERTEXELEMENT9 DeclTSpace[] = | |
| { | |
| { 0, 0,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_POSITION ,0 }, | |
| { 0,12,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_NORMAL ,0 }, | |
| { 0,24,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_COLOR ,0 }, | |
| { 0,28,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_COLOR ,1 }, | |
| { 0,32,D3DDECLTYPE_FLOAT2 ,0,D3DDECLUSAGE_TEXCOORD ,0 }, | |
| { 0,40,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_TANGENT ,0 }, | |
| { 0,52,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_BINORMAL ,0 }, | |
| D3DDECL_END() | |
| }; | |
| static D3DVERTEXELEMENT9 DeclCompact[] = | |
| { | |
| { 0, 0,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_POSITION ,0 }, | |
| { 0,12,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_COLOR ,0 }, | |
| D3DDECL_END() | |
| }; | |
| static D3DVERTEXELEMENT9 DeclTSpace3[] = | |
| { | |
| { 0, 0,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_POSITION ,0 }, | |
| { 0,12,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_NORMAL ,0 }, | |
| { 0,16,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_TANGENT ,0 }, | |
| { 0,20,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_COLOR ,0 }, | |
| { 0,24,D3DDECLTYPE_FLOAT2 ,0,D3DDECLUSAGE_TEXCOORD ,0 }, | |
| D3DDECL_END() | |
| }; | |
| static D3DVERTEXELEMENT9 DeclTSpace3Big[] = | |
| { | |
| { 0, 0,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_POSITION ,0 }, | |
| /*{ 0,12,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_NORMAL ,0 }, | |
| { 0,16,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_TANGENT ,0 }, | |
| { 0,20,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_COLOR ,0 }, | |
| { 0,24,D3DDECLTYPE_FLOAT2 ,0,D3DDECLUSAGE_TEXCOORD ,0 },*/ | |
| { 0,12,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_NORMAL ,0 }, | |
| { 0,24,D3DDECLTYPE_FLOAT3 ,0,D3DDECLUSAGE_TANGENT ,0 }, | |
| { 0,36,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_COLOR ,0 }, | |
| { 0,40,D3DDECLTYPE_FLOAT2 ,0,D3DDECLUSAGE_TEXCOORD ,0 }, | |
| D3DDECL_END() | |
| }; | |
| static D3DVERTEXELEMENT9 DeclXYZW[] = | |
| { | |
| { 0, 0,D3DDECLTYPE_FLOAT4 ,0,D3DDECLUSAGE_POSITION ,0 }, | |
| D3DDECL_END() | |
| }; | |
| static D3DVERTEXELEMENT9 DeclCubeSpecial[] = | |
| { | |
| { 0, 0,D3DDECLTYPE_UBYTE4 ,0,D3DDECLUSAGE_POSITION ,0 }, | |
| { 0, 4,D3DDECLTYPE_D3DCOLOR ,0,D3DDECLUSAGE_COLOR ,0 }, | |
| D3DDECL_END() | |
| }; | |
| static FVFTableStruct FVFTable[] = | |
| { | |
| { 0,0 }, | |
| { 32,DeclDefault }, | |
| { 32,DeclDouble }, | |
| { 64,DeclTSpace }, | |
| { 16,DeclCompact }, | |
| { 16,DeclXYZW }, | |
| { 32,DeclTSpace3 }, | |
| { 48,DeclTSpace3Big }, | |
| { 8,DeclCubeSpecial }, | |
| }; | |
| #define FVFMax (sizeof(FVFTable)/sizeof(FVFTableStruct)) | |
| /****************************************************************************/ | |
| #if sUSE_DIRECTSOUND | |
| static IDirectSound8 *DXS; | |
| static IDirectSoundBuffer8 *DXSBuffer; | |
| static IDirectSoundBuffer *DXSPrimary; | |
| static volatile sSoundHandler DXSHandler; | |
| static sInt DXSHandlerAlign; | |
| static sInt DXSHandlerSample; | |
| static volatile void *DXSHandlerUser; | |
| #if sPLAYER | |
| #define DXSSAMPLES 0x20000 | |
| #else | |
| #define DXSSAMPLES 0x2000 | |
| #endif | |
| static volatile sInt DXSLastTotalSample; | |
| static volatile sInt DXSReadStart; | |
| static volatile sInt DXSReadOffset; | |
| static volatile sInt DXSTime; | |
| static volatile sInt DXSIndex; | |
| static HANDLE DXSThread; | |
| static ULONG DXSThreadId; | |
| static sInt volatile DXSRun; | |
| static CRITICAL_SECTION DXSLock; | |
| static HANDLE DXSEvent; | |
| unsigned long __stdcall ThreadCode(void *); | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Keyboard table for non-DI ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| sInt VKTable[256] = | |
| { | |
| 0,0,0,0,0,0,0,0, // 0x00 | |
| 0,0,0,0,0,sKEY_ENTER,0,0, | |
| 0,0,0,0,0,0,0,0, // 0x10 | |
| 0,0,0,sKEY_ESCAPE,0,0,0,0, | |
| sKEY_SPACE,0,0,0,0,sKEY_LEFT,sKEY_UP,sKEY_RIGHT, // 0x20 | |
| sKEY_DOWN,0,0,0,0,0,0,0, | |
| 1,1,1,1,1,1,1,1, // 0x30 | |
| 1,1,0,0,0,0,0,0, | |
| 1,1,1,1,1,1,1,1, // 0x40 | |
| 1,1,1,1,1,1,1,1, | |
| 1,1,1,1,1,1,1,1, // 0x50 | |
| 1,1,1,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0, // 0x60 | |
| 0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0, // 0x70 | |
| 0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0, // 0x80 | |
| 0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0, // 0x90 | |
| 0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0, // 0xa0 | |
| 0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0, // 0xb0 | |
| 0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0, // 0xc0 | |
| 0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0, // 0xd0 | |
| 0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0, // 0xe0 | |
| 0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0, // 0xf0 | |
| 0,0,0,0,0,0,0,0, | |
| }; | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** DX Error reporting ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| static void ReportDXError(const sChar *file,sInt line,HRESULT hr) | |
| { | |
| #if !sRELEASE | |
| __asm int 3; | |
| #endif | |
| #if sUSE_DIRECTSOUND | |
| sSystem->ExitDS(); | |
| #endif | |
| #if sUSE_DIRECTINPUT | |
| sSystem->ExitDI(); | |
| #endif | |
| sSystem->ExitScreens(); | |
| switch(hr) | |
| { | |
| case D3DERR_OUTOFVIDEOMEMORY: | |
| sFatal("Out of video memory (in %s:%d).\n\n" | |
| "Try using a lower resolution or lower antialiasing settings.", | |
| file,line); | |
| break; | |
| case E_OUTOFMEMORY: | |
| sFatal("DirectX ran out of memory (in %s:%d).",file,line); | |
| break; | |
| default: | |
| sFatal("DirectX error %08x occured in %s:%d.",hr,file,line); | |
| break; | |
| } | |
| } | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Heap Memory Management ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| sDInt MemoryUsedCount; | |
| #if !sINTRO | |
| #undef new | |
| void * __cdecl operator new(unsigned int size) | |
| { | |
| void *p; | |
| #if !sRELEASE | |
| p = _malloc_dbg(size,_NORMAL_BLOCK,"unknown",1); | |
| #else | |
| p = malloc(size); | |
| #endif | |
| if(p==0) | |
| { | |
| #if sDEBUG | |
| //_CrtDumpMemoryLeaks(); | |
| #endif | |
| sFatal("ran out of virtual memory..."); | |
| } | |
| //sSetMem(p,0x12,size); | |
| //sDPrintF("%10d : (%d)\n",MemoryUsedCount,size); | |
| #if !sPLAYER | |
| MemoryUsedCount+=_msize(p); | |
| #endif | |
| return p; | |
| } | |
| void * __cdecl operator new(unsigned int size,const char *file,int line) | |
| { | |
| void *p; | |
| #if !sRELEASE | |
| p = _malloc_dbg(size,_NORMAL_BLOCK,file,line); | |
| #else | |
| p = malloc(size); | |
| #endif | |
| if(p==0) | |
| { | |
| #if sDEBUG | |
| //_CrtDumpMemoryLeaks(); | |
| #endif | |
| sFatal("ran out of virtual memory..."); | |
| } | |
| //sSetMem(p,0x12,size); | |
| //sDPrintF("%10d : %d\n",MemoryUsedCount,size); | |
| #if !sPLAYER | |
| MemoryUsedCount+=_msize(p); | |
| #endif | |
| return p; | |
| } | |
| void __cdecl operator delete(void *p) | |
| { | |
| if(p) | |
| { | |
| #if !sPLAYER | |
| MemoryUsedCount-=_msize(p); | |
| #endif | |
| #if !sRELEASE | |
| _free_dbg(p,_NORMAL_BLOCK); | |
| #else | |
| free(p); | |
| #endif | |
| } | |
| } | |
| #define new new(__FILE__,__LINE__) | |
| #endif | |
| #if sINTRO | |
| void checkHeap() | |
| { | |
| HeapValidate(GetProcessHeap(),0,0); | |
| } | |
| void * __cdecl operator new(unsigned int size) | |
| { | |
| return HeapAlloc(GetProcessHeap(),HEAP_NO_SERIALIZE,size); | |
| } | |
| void * __cdecl operator new[](unsigned int size) | |
| { | |
| return HeapAlloc(GetProcessHeap(),HEAP_NO_SERIALIZE,size); | |
| } | |
| void __cdecl operator delete(void *ptr) | |
| { | |
| if(ptr) | |
| HeapFree(GetProcessHeap(),HEAP_NO_SERIALIZE,ptr); | |
| } | |
| void __cdecl operator delete[](void *ptr) | |
| { | |
| if(ptr) | |
| HeapFree(GetProcessHeap(),HEAP_NO_SERIALIZE,ptr); | |
| } | |
| int __cdecl _purecall() | |
| { | |
| return 0; | |
| } | |
| #if sRELEASE | |
| extern "C" int _fltused; | |
| int _fltused; | |
| #endif | |
| #endif | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Dialog ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| sInt AspectRatioList[][2] = { | |
| { 4,3 }, { 5,4 }, { 16,9 }, { 16,10 }, { 2,1 }, { 3,2 }, | |
| { 3,4 }, { 4,5 }, { 9,16 }, { 10,16 }, { 1,2 }, { 2,3 }, // <-- hochkant | |
| }; | |
| #if sCONFIGDIALOG | |
| #include "resource.h" | |
| struct DisplayMode | |
| { | |
| sInt XRes; | |
| sInt YRes; | |
| bool operator == (const DisplayMode &b) const | |
| { | |
| return XRes == b.XRes && YRes == b.YRes; | |
| } | |
| bool operator < (const DisplayMode &b) const | |
| { | |
| return XRes < b.XRes || (XRes == b.XRes && YRes < b.YRes); | |
| } | |
| }; | |
| static sInt MatchAspectRatio(const DisplayMode &mode) | |
| { | |
| sF32 ratio = 1.0f * mode.XRes / mode.YRes; | |
| sInt bestMatch = 0; | |
| sF32 bestDist = 1e+20f; | |
| for(sInt i=0;i<sCOUNTOF(AspectRatioList);i++) | |
| { | |
| sF32 targetRatio = 1.0f*AspectRatioList[i][0]/AspectRatioList[i][1]; | |
| sF32 dist = sFAbs(ratio - targetRatio); | |
| if(dist < bestDist) | |
| { | |
| bestDist = dist; | |
| bestMatch = i; | |
| } | |
| } | |
| return bestMatch; | |
| } | |
| BOOL CALLBACK sDialogProc(HWND win,UINT msg,WPARAM wparam,LPARAM lparam) | |
| { | |
| static const sInt defaultXRes = 1024; | |
| static const sInt defaultYRes = 768; | |
| static DisplayMode *Modes=0; | |
| static sInt ModeCount; | |
| static D3DMULTISAMPLE_TYPE MultiTypes[17]; | |
| static sInt MultiCount; | |
| switch(msg) | |
| { | |
| case WM_INITDIALOG: | |
| { | |
| if(sWindowTitle) | |
| SetWindowText(win,sWindowTitle); | |
| // enumerate video modes | |
| IDirect3D9 *d3d9 = sSystem->DXD; | |
| D3DFORMAT fmt = D3DFMT_X8R8G8B8; | |
| sInt numModes = d3d9->GetAdapterModeCount(D3DADAPTER_DEFAULT,fmt); | |
| Modes = new DisplayMode[numModes]; | |
| ModeCount = 0; | |
| for(sInt i=0;i<numModes;i++) | |
| { | |
| D3DDISPLAYMODE mode; | |
| if(d3d9->EnumAdapterModes(D3DADAPTER_DEFAULT,fmt,i,&mode) == D3D_OK) | |
| { | |
| DisplayMode newm; | |
| newm.XRes = mode.Width; | |
| newm.YRes = mode.Height; | |
| // find insertion point | |
| sInt i; | |
| for(i=ModeCount;i>0 && !(Modes[i-1] < newm);i--); | |
| // check for dupes | |
| if(i<ModeCount && Modes[i] == newm) | |
| continue; | |
| // insert | |
| for(sInt j=ModeCount;j>i;j--) | |
| Modes[j] = Modes[j-1]; | |
| Modes[i] = newm; | |
| ModeCount++; | |
| } | |
| } | |
| // add video mode list to dialog | |
| sInt bestMatch = 0; | |
| sInt bestDist = 0x7fffffff; | |
| for(sInt i=0;i<ModeCount;i++) | |
| { | |
| sChar buffer[32]; | |
| sInt dist = sAbs(Modes[i].XRes - defaultXRes) + sAbs(Modes[i].YRes - defaultYRes); | |
| if(dist<bestDist) | |
| { | |
| bestDist = dist; | |
| bestMatch=i; | |
| } | |
| sSPrintF(buffer,sizeof(buffer),"%dx%d",Modes[i].XRes,Modes[i].YRes); | |
| SendDlgItemMessage(win,IDC_RESOLUTION,CB_ADDSTRING,0,(LPARAM) buffer); | |
| } | |
| SendDlgItemMessage(win,IDC_RESOLUTION,CB_SETCURSEL,bestMatch,0); | |
| /*SendDlgItemMessage(win,IDC_RESOLUTION,CB_ADDSTRING,0,(LPARAM)"640x480"); | |
| SendDlgItemMessage(win,IDC_RESOLUTION,CB_ADDSTRING,0,(LPARAM)"800x600"); | |
| SendDlgItemMessage(win,IDC_RESOLUTION,CB_ADDSTRING,0,(LPARAM)"1024x768"); | |
| SendDlgItemMessage(win,IDC_RESOLUTION,CB_SETCURSEL,1,0);*/ | |
| // aspect ratios | |
| for(sInt i=0;i<sCOUNTOF(AspectRatioList);i++) | |
| { | |
| sChar buffer[32]; | |
| sSPrintF(buffer,sizeof(buffer),"%d:%d",AspectRatioList[i][0],AspectRatioList[i][1]); | |
| SendDlgItemMessage(win,IDC_ASPECT,CB_ADDSTRING,0,(LPARAM) buffer); | |
| } | |
| SendDlgItemMessage(win,IDC_ASPECT,CB_SETCURSEL, | |
| MatchAspectRatio(Modes[bestMatch]),0); | |
| // multisampling quality | |
| MultiCount = 0; | |
| for(sInt i=0;i<17;i++) | |
| { | |
| D3DMULTISAMPLE_TYPE mst = (D3DMULTISAMPLE_TYPE) i; | |
| if(mst == D3DMULTISAMPLE_NONMASKABLE) | |
| continue; | |
| if(SUCCEEDED(d3d9->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, | |
| D3DDEVTYPE_HAL,fmt,FALSE,mst,0))) | |
| { | |
| sChar buffer[32]; | |
| MultiTypes[MultiCount++] = mst; | |
| if(i == 0) | |
| SendDlgItemMessage(win,IDC_MULTISAMPLE,CB_ADDSTRING,0,(LPARAM) "None"); | |
| else | |
| { | |
| sSPrintF(buffer,sizeof(buffer),"%dx",i); | |
| SendDlgItemMessage(win,IDC_MULTISAMPLE,CB_ADDSTRING,0,(LPARAM) buffer); | |
| } | |
| } | |
| } | |
| SendDlgItemMessage(win,IDC_MULTISAMPLE,CB_SETCURSEL,0,0); | |
| /*SendDlgItemMessage(win,IDC_TEXQUAL,CB_ADDSTRING,0,(LPARAM)"Normal"); | |
| SendDlgItemMessage(win,IDC_TEXQUAL,CB_ADDSTRING,0,(LPARAM)"High"); | |
| SendDlgItemMessage(win,IDC_TEXQUAL,CB_ADDSTRING,0,(LPARAM)"Ultra"); | |
| SendDlgItemMessage(win,IDC_TEXQUAL,CB_SETCURSEL,1,0);*/ | |
| #if sRELEASE | |
| CheckDlgButton(win,IDC_FULLSCREEN,BST_CHECKED); | |
| #endif | |
| //CheckDlgButton(win,IDC_SHADOWS,BST_CHECKED); | |
| CheckDlgButton(win,IDC_VSYNC,BST_CHECKED); | |
| //CheckDlgButton(win,IDC_STEREO3D,BST_CHECKED); | |
| } | |
| return sTRUE; | |
| case WM_CLOSE: | |
| delete[] Modes; | |
| EndDialog(win,102); | |
| return sTRUE; | |
| case WM_COMMAND: | |
| switch(wparam&0xffff) | |
| { | |
| case IDC_RESOLUTION: | |
| // update aspect ratio on resolution change | |
| if((wparam >> 16) == CBN_SELCHANGE) | |
| { | |
| sInt item = SendDlgItemMessage(win,IDC_RESOLUTION,CB_GETCURSEL,0,0); | |
| if(item != CB_ERR) | |
| SendDlgItemMessage(win,IDC_ASPECT,CB_SETCURSEL,MatchAspectRatio(Modes[item]),0); | |
| } | |
| break; | |
| case IDOK: | |
| { | |
| sInt res = SendDlgItemMessage(win,IDC_RESOLUTION,CB_GETCURSEL,0,0); | |
| res = sRange(res,ModeCount-1,0); | |
| sU32 flags = sSF_DIRECT3D; | |
| if(IsDlgButtonChecked(win,IDC_FULLSCREEN) == BST_CHECKED) | |
| flags |= sSF_FULLSCREEN; | |
| if(IsDlgButtonChecked(win,IDC_VSYNC) == BST_CHECKED) | |
| flags |= sSF_WAITVSYNC; | |
| #if !sINTRO | |
| sSetConfig(flags,Modes[res].XRes,Modes[res].YRes); | |
| #else | |
| IntroScreenX = Modes[res].XRes; | |
| IntroScreenY = Modes[res].YRes; | |
| IntroFlags = flags; | |
| #endif | |
| IntroTargetAspect = SendDlgItemMessage(win,IDC_ASPECT,CB_GETCURSEL,0,0); | |
| //IntroTexQuality = SendDlgItemMessage(win,IDC_TEXQUAL,CB_GETCURSEL,0,0); | |
| IntroTexQuality = 2; | |
| IntroLoop = (IsDlgButtonChecked(win,IDC_LOOP)==BST_CHECKED); | |
| IntroStereo3D = sFALSE; | |
| IntroShadows = sFALSE; | |
| /*IntroStereo3D = (IsDlgButtonChecked(win,IDC_STEREO3D) == BST_CHECKED); | |
| IntroShadows = (IsDlgButtonChecked(win,IDC_SHADOWS) == BST_CHECKED) ? sTRUE : sFALSE;*/ | |
| MultiSampleType = MultiTypes[SendDlgItemMessage(win,IDC_MULTISAMPLE,CB_GETCURSEL,0,0)]; | |
| } | |
| delete[] Modes; | |
| EndDialog(win,wparam); | |
| break; | |
| case IDCANCEL: | |
| delete[] Modes; | |
| EndDialog(win,wparam); | |
| break; | |
| } | |
| return sTRUE; | |
| } | |
| return sFALSE; | |
| } | |
| // please note that the resource-file is excluded from build | |
| // you have to compile the resource manually, and then this | |
| // code is used to extract the dialog from the resource file. | |
| sBool ConfigDialog(sInt nr,const sChar *title) | |
| { | |
| if(title) | |
| sWindowTitle = title; | |
| sInt ret = DialogBox(WInst,MAKEINTRESOURCE(nr),0,(DLGPROC) sDialogProc); | |
| return ret == -1 ? 0 : ret; | |
| } | |
| #endif | |
| static sBool MessagePump() | |
| { | |
| MSG msg; | |
| sBool ok = sTRUE; | |
| while(PeekMessage(&msg,0,0,0,PM_NOREMOVE)) | |
| { | |
| if(!GetMessage(&msg,0,0,0)) | |
| ok = sFALSE; | |
| TranslateMessage(&msg); | |
| DispatchMessage(&msg); | |
| } | |
| return ok; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Startup, without intro ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| #if !sINTRO | |
| static void MakeCpuMask() | |
| { | |
| sU32 result; | |
| sU32 vendor[4]; | |
| // start with nothing supportet | |
| sSystem->CpuMask = 0; | |
| // check cpuid command, and check avaiability of standard function #1 | |
| #if !sNOCRT | |
| __try | |
| { | |
| #endif | |
| __asm | |
| { | |
| pushad | |
| xor eax,eax | |
| CPUID | |
| mov result,eax | |
| mov vendor,ebx | |
| mov vendor+4,edx | |
| mov vendor+8,ecx | |
| xor eax,eax | |
| mov vendor+12,eax | |
| popad | |
| } | |
| #if !sNOCRT | |
| } | |
| __except(1) | |
| { | |
| return; | |
| } | |
| #endif | |
| if(result==0) | |
| return; | |
| // check standard features | |
| __asm | |
| { | |
| pushad | |
| mov eax,1 | |
| CPUID | |
| mov result,edx | |
| popad | |
| } | |
| if(result&(1<< 4)) sSystem->CpuMask |= sCPU_RDTSC; | |
| if(result&(1<<15)) sSystem->CpuMask |= sCPU_CMOVE; | |
| if(result&(1<<23)) sSystem->CpuMask |= sCPU_MMX; | |
| if(result&(1<<25)) sSystem->CpuMask |= sCPU_SSE|sCPU_MMX2; | |
| if(result&(1<<26)) sSystem->CpuMask |= sCPU_SSE2; | |
| // check extended features | |
| __asm | |
| { | |
| pushad | |
| mov eax,0x80000000 | |
| CPUID | |
| mov result,eax | |
| popad | |
| } | |
| if(result>=0x80000001) | |
| { | |
| __asm | |
| { | |
| pushad | |
| mov eax,0x80000001 | |
| CPUID | |
| mov result,edx | |
| popad | |
| } | |
| if(result&(1<<31)) sSystem->CpuMask |= sCPU_3DNOW; | |
| // check AMD specific features | |
| if(sCmpMem(vendor,"AuthenticAMD",12)==0) | |
| { | |
| if(result&(1<<22)) sSystem->CpuMask |= sCPU_MMX2; | |
| if(result&(1<<30)) sSystem->CpuMask |= sCPU_3DNOW2; | |
| } | |
| } | |
| // is the SSE support complete and supported by the operating system? | |
| #if !sNOCRT | |
| if(sSystem->CpuMask & sCPU_SSE) | |
| { | |
| __try | |
| { | |
| __asm | |
| { | |
| orps xmm0,xmm1 | |
| } | |
| } | |
| __except(1) | |
| { | |
| sSystem->CpuMask &= ~(sCPU_SSE|sCPU_SSE2); | |
| } | |
| } | |
| #endif | |
| } | |
| /****************************************************************************/ | |
| static LRESULT WINAPI MainWndProc(HWND win,UINT msg,WPARAM wparam,LPARAM lparam) | |
| { | |
| MsgWin = win; | |
| sVERIFY(sSystem); | |
| return sSystem->Msg(msg,wparam,lparam); | |
| } | |
| /****************************************************************************/ | |
| int APIENTRY WinMain(HINSTANCE inst,HINSTANCE prev,LPSTR cmdline,int show) | |
| { | |
| WInst = GetModuleHandle(0); | |
| WCmdLine = GetCommandLineA(); | |
| if(*WCmdLine=='/"') | |
| { | |
| WCmdLine++; | |
| while(*WCmdLine && *WCmdLine!='/"') | |
| WCmdLine++; | |
| if(*WCmdLine=='/"') | |
| WCmdLine++; | |
| } | |
| else | |
| { | |
| while(*WCmdLine && *WCmdLine!=' ') | |
| WCmdLine++; | |
| } | |
| while(*WCmdLine==' ') | |
| WCmdLine++; | |
| #if sUSE_LEKKTOR | |
| sLekktorInit(); | |
| #endif | |
| sSystem = new sSystem_; | |
| sSetMem(((sU8 *)sSystem)+4,0,sizeof(sSystem_)-4); // argh | |
| // load d3d dll | |
| d3dlib = ::LoadLibraryA("d3d9.dll"); | |
| if(d3dlib==0) | |
| sFatal("You need DirectX 9 (or better) to run this program."); | |
| Direct3DCreate9P = (Direct3DCreate9T) GetProcAddress(d3dlib,"Direct3DCreate9"); | |
| sVERIFY(Direct3DCreate9P); | |
| // initialize d3d | |
| sSystem->DXD = (*Direct3DCreate9P)(D3D_SDK_VERSION); | |
| if(!sSystem->DXD) | |
| sFatal("DirectX 9.0c not present."); | |
| // config | |
| if(sAppHandler(sAPPCODE_CONFIG,0)) | |
| sSystem->InitX(); | |
| sRelease(sSystem->DXD); | |
| FreeLibrary(d3dlib); | |
| delete sSystem; | |
| sDPrintF("Memory Left: %d bytes\n",MemoryUsedCount); | |
| if(MemoryUsedCount!=16) | |
| { | |
| sDPrintF("************************************************\n"); | |
| sDPrintF("\n MEMORY LEAK\n\n"); | |
| sDPrintF("************************************************\n"); | |
| } | |
| return 0; | |
| } | |
| /****************************************************************************/ | |
| void sSetConfig(sU32 flags,sInt xs,sInt ys) | |
| { | |
| sSystem->ConfigFlags = flags; | |
| sSystem->ConfigX = xs; | |
| sSystem->ConfigY = ys; | |
| } | |
| /****************************************************************************/ | |
| BOOL CALLBACK MonitorEnumProc(HMONITOR handle,HDC hdc,LPRECT rect,LPARAM user) | |
| { | |
| HWND win; | |
| HWND pwin; | |
| RECT r,r2; | |
| sBool createMaximized=sFALSE; | |
| sDPrintF("found monitor <%s> at %d %d %d %d\n","xx",rect->left,rect->top,rect->right,rect->bottom); | |
| sSetMem(&r,0,sizeof(RECT)); | |
| if(sSystem->WScreenCount==0) | |
| { | |
| if(sSystem->ConfigX==0 && sSystem->ConfigY==0) | |
| { | |
| if(sSystem->ConfigFlags & sSF_FULLSCREEN) | |
| { | |
| sSystem->ConfigX = rect->right - rect->left; | |
| sSystem->ConfigY = rect->bottom - rect->top; | |
| } | |
| else | |
| { | |
| SystemParametersInfo(SPI_GETWORKAREA,0,&r,0); | |
| r2.left = r2.top = 0; | |
| r2.right = r2.bottom = 1; | |
| AdjustWindowRect(&r2,WS_OVERLAPPEDWINDOW,FALSE); | |
| sSystem->ConfigX = r.right-r.left-(r2.right-r2.left); | |
| sSystem->ConfigY = r.bottom-r.top-(r2.bottom-r2.top); | |
| createMaximized = sTRUE; | |
| } | |
| } | |
| } | |
| if(sSystem->WScreenCount<MAX_SCREEN) | |
| { | |
| if(sSystem->WScreenCount > 0) | |
| pwin = (HWND)sSystem->Screen[0].Window; | |
| else | |
| pwin = 0; | |
| r2.left = r2.top = 0; | |
| r2.right = sSystem->ConfigX; | |
| r2.bottom = sSystem->ConfigY; | |
| AdjustWindowRect(&r2,WS_OVERLAPPEDWINDOW,FALSE); | |
| sInt style = WS_OVERLAPPEDWINDOW; | |
| if(sSystem->ConfigFlags & sSF_MINIMAL) | |
| style = WS_POPUP|WS_THICKFRAME; | |
| if(createMaximized) | |
| style |= WS_MAXIMIZE; | |
| style |= WS_VISIBLE; | |
| win = CreateWindowEx(0,"kk",sWindowTitle,style,r.left,r.top,r2.right-r2.left,r2.bottom-r2.top,pwin,0,WInst,0); | |
| sSystem->WWindowedStyle = style; | |
| sSystem->Screen[sSystem->WScreenCount].Window = (sDInt) win; | |
| sSystem->WScreenCount++; | |
| if(sSystem->ConfigFlags & sSF_MULTISCREEN) | |
| return sTRUE; | |
| } | |
| return sFALSE; | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::InitX() | |
| { | |
| WNDCLASS wc; | |
| MSG msg; | |
| sBool gotmsg; | |
| sInt i; | |
| // set up memory checking | |
| MakeCpuMask(); | |
| sInitTypes(); | |
| #if sLINK_RYGDXT | |
| sInitDXT(); | |
| #endif | |
| _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)|_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF); | |
| sChar *test = new sChar[16]; | |
| sCopyString(test,"TestLeak",16); | |
| // find dlls | |
| dslib = ::LoadLibraryA("dsound.dll"); | |
| DirectSoundCreate8P = (DirectSoundCreate8T) GetProcAddress(dslib,"DirectSoundCreate8"); | |
| sVERIFY(DirectSoundCreate8P); | |
| #if sUSE_DIRECTINPUT | |
| dilib = ::LoadLibraryA("dinput8.dll"); | |
| DirectInput8CreateP = (DirectInput8CreateT) GetProcAddress(dilib,"DirectInput8Create"); | |
| sVERIFY(DirectInput8CreateP); | |
| #endif | |
| // set up some more stuff | |
| DWORD procAffinity,sysAffinity; | |
| if(GetProcessAffinityMask(GetCurrentProcess(),&procAffinity,&sysAffinity)) | |
| SingleCore = sysAffinity == 1; | |
| else | |
| SingleCore = sTRUE; | |
| sDPrintF("*** configuring system for %s-core operation.\n",SingleCore ? "single" : "multi"); | |
| timeBeginPeriod(1); | |
| WStartTime = timeGetTime(); | |
| sSetRndSeed(timeGetTime()&0x7fffffff); | |
| if(!InitGDI()) | |
| sFatal("could not initialise GDI for Font conversions!"); | |
| sBroker = new sBroker_; | |
| #if sLINK_UTIL | |
| sPerfMon = new sPerfMon_; | |
| sBroker->AddRoot(sPerfMon); | |
| #endif | |
| // sInitTypes(); | |
| // create window class | |
| wc.lpszClassName = "kk"; | |
| wc.lpfnWndProc = MainWndProc; | |
| wc.style = CS_CLASSDC;///*CS_OWNDC|*/CS_VREDRAW|CS_HREDRAW; | |
| wc.hInstance = WInst; | |
| wc.hIcon = LoadIcon(WInst,MAKEINTRESOURCE(23)); | |
| wc.hCursor = LoadCursor(0,IDC_ARROW); | |
| wc.hbrBackground = 0; | |
| wc.lpszMenuName = 0; | |
| wc.cbClsExtra = 0; | |
| wc.cbWndExtra = 0; | |
| RegisterClass(&wc); | |
| // init | |
| WDeviceLost = 0; | |
| WActiveCount = 0; | |
| WActiveMsg = 1; | |
| WContinuous = 1; | |
| WSinglestep = 0; | |
| WFullscreen = 0; | |
| WWindowedStyle = 0; | |
| WMinimized = 0; | |
| WMaximized = 0; | |
| WAborting = sFALSE; | |
| WResponse = 0; | |
| WConstantUpdate = sTRUE; | |
| WAbortKeyFlag = 0; | |
| WFocus = 1; | |
| CmdLowQuality = 0; | |
| CmdLowRes = 0; | |
| CmdShaderLevel = sPS_20; | |
| CmdNoRt = sFALSE; | |
| CmdWindowed = 0; | |
| CmdFullscreen = 0; | |
| sChar *cmdline = WCmdLine; | |
| while(*cmdline) | |
| { | |
| while(*cmdline==' ') | |
| cmdline++; | |
| if(sCmpMem(cmdline,"low",3)==0) | |
| { | |
| CmdLowQuality = 1; | |
| cmdline+=3; | |
| } | |
| else if(sCmpMem(cmdline,"lowres",6)==0) | |
| { | |
| CmdLowRes = 1; | |
| cmdline+=6; | |
| } | |
| else if(sCmpMem(cmdline,"full",4)==0) | |
| { | |
| ConfigFlags |= sSF_FULLSCREEN; | |
| if(ConfigX==0) ConfigX = 1024; | |
| if(ConfigY==0) ConfigY = 768; | |
| cmdline+=4; | |
| } | |
| else if(sCmpMem(cmdline,"win",4)==0) | |
| { | |
| ConfigFlags &= ~sSF_FULLSCREEN; | |
| cmdline+=3; | |
| } | |
| else if(sCmpMem(cmdline,"ps00",4)==0) | |
| { | |
| CmdShaderLevel = sPS_00; | |
| cmdline+=4; | |
| } | |
| else if(sCmpMem(cmdline,"ps11",4)==0) | |
| { | |
| CmdShaderLevel = sPS_11; | |
| cmdline+=4; | |
| } | |
| else if(sCmpMem(cmdline,"ps14",4)==0) | |
| { | |
| CmdShaderLevel = sPS_14; | |
| cmdline+=4; | |
| } | |
| else if(sCmpMem(cmdline,"ps20",4)==0) | |
| { | |
| CmdShaderLevel = sPS_20; | |
| cmdline+=4; | |
| } | |
| else if(sCmpMem(cmdline,"nort",4)==0) | |
| { | |
| CmdNoRt = sTRUE; | |
| cmdline += 4; | |
| } | |
| else if(cmdline[0]=='"') | |
| { | |
| cmdline++; | |
| sChar *ptr = WFilename; | |
| sInt left = sCOUNTOF(WFilename); | |
| while(*cmdline!='"' && *cmdline && left>0) | |
| { | |
| *ptr++ = *cmdline++; | |
| } | |
| *ptr++ = 0; | |
| if(*cmdline=='"') | |
| cmdline++; | |
| } | |
| else | |
| { | |
| break; | |
| } | |
| } | |
| WCmdLine = cmdline; | |
| EnumDisplayMonitors(0,0,MonitorEnumProc,0); | |
| if(WScreenCount<2) | |
| ConfigFlags &= ~sSF_MULTISCREEN; | |
| if(ConfigFlags & sSF_MULTISCREEN) | |
| ConfigFlags |= sSF_FULLSCREEN; | |
| sVERIFY(WScreenCount>0); | |
| sSetMem(GeoBuffer,0,sizeof(GeoBuffer)); | |
| sSetMem(GeoHandle,0,sizeof(GeoHandle)); | |
| sSetMem(&PerfThis,0,sizeof(PerfThis)); | |
| sSetMem(&PerfLast,0,sizeof(PerfLast)); | |
| PerfThis.Time = sSystem->PerfTime(); | |
| #if sUSE_DIRECTINPUT | |
| if(!InitDI()) | |
| sFatal("could not initialise Direct Input!"); | |
| #endif | |
| #ifdef _DOPE | |
| TexMemAlloc = 0; | |
| #endif | |
| ZBufXSize = ZBufYSize = 0; | |
| ZBufFormat = 0; | |
| ZBuffer = 0; | |
| RTBuffer = 0; | |
| CurrentRT = 0; | |
| SyncQuery = 0; | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| Textures[i].Flags = 0; | |
| sSetMem(Setups,0,sizeof(Setups)); | |
| sSetMem(Shaders,0,sizeof(Shaders)); | |
| MtrlClearCaches(); | |
| InitScreens(); | |
| if(CmdShaderLevel>GetShaderLevel()) | |
| CmdShaderLevel = GetShaderLevel(); | |
| #if !sNOCRT | |
| _control87(_PC_24|_RC_NEAR,MCW_PC|MCW_RC); | |
| #endif | |
| #if sUSE_DIRECTSOUND | |
| if(!InitDS()) | |
| sFatal("could not initialize DirectSound"); | |
| #endif | |
| // main loop | |
| DXDev->BeginScene(); | |
| sAppHandler(sAPPCODE_INIT,0); | |
| DXDev->EndScene(); | |
| WShow = -1; | |
| msg.message = WM_NULL; | |
| PeekMessage(&msg,0,0,0,PM_NOREMOVE); | |
| while(msg.message!=WM_QUIT) | |
| { | |
| if(WShow!=-1) | |
| { | |
| ::ShowWindow((HWND)sSystem->Screen[0].Window,WShow); | |
| WShow = -1; | |
| } | |
| if(WActiveCount==0) | |
| gotmsg = (PeekMessage(&msg,0,0,0,PM_REMOVE)!=0); // !=0) not needed | |
| else | |
| gotmsg = (GetMessage(&msg,0,0,0)!=0); | |
| if(gotmsg) | |
| { | |
| TranslateMessage(&msg); | |
| DispatchMessage(&msg); | |
| } | |
| else | |
| { | |
| if(WActiveCount==0 && WFocus) | |
| { | |
| #if sUSE_DIRECTINPUT | |
| PollDI(); | |
| #endif | |
| for(i=0;i<KeyIndex;i++) | |
| sAppHandler(sAPPCODE_KEY,KeyBuffer[i]); | |
| KeyIndex = 0; | |
| Render(); | |
| PerfLast.TimeFiltered = (PerfLast.TimeFiltered*7+PerfLast.Time)/8; | |
| PerfLast.Line = PerfThis.Line; | |
| PerfLast.Triangle = PerfThis.Triangle; | |
| PerfLast.Vertex = PerfThis.Vertex; | |
| PerfLast.Material = PerfThis.Material; | |
| PerfThis.Line = 0; | |
| PerfThis.Triangle = 0; | |
| PerfThis.Vertex = 0; | |
| PerfThis.Material = 0; | |
| #if sLINK_UTIL | |
| sPerfMon->Flip(); | |
| #elif !sINTRO | |
| sSystem->PerfKalib(); | |
| #endif | |
| Sleep(0); | |
| } | |
| else | |
| Sleep(20); | |
| #if sUSE_DIRECTSOUND | |
| MarkDS(); | |
| #endif | |
| } | |
| } | |
| /* | |
| while(GetMessage(&msg,NULL,0,0)) | |
| { | |
| TranslateMessage(&msg); | |
| DispatchMessage(&msg); | |
| } | |
| */ | |
| sAppHandler(sAPPCODE_EXIT,0); | |
| // cleanup | |
| #if sLINK_UTIL | |
| sBroker->RemRoot(sPerfMon); | |
| #endif | |
| #if sUSE_DIRECTSOUND | |
| ExitDS(); | |
| #endif | |
| sBroker->Free(); // some objects may still hold resources, like Geometries | |
| sBroker->Dump(); | |
| ExitScreens(); | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| Textures[i].Flags=0; | |
| #if sUSE_DIRECTINPUT | |
| ExitDI(); | |
| #endif | |
| ExitGDI(); | |
| sExitTypes(); | |
| sBroker->Free(); | |
| sBroker->Dump(); | |
| delete sBroker; | |
| sBroker = 0; | |
| FreeLibrary(dilib); | |
| FreeLibrary(dslib); | |
| } | |
| /****************************************************************************/ | |
| sInt sSystem_::Msg(sU32 msg,sU32 wparam,sU32 lparam) | |
| { | |
| HWND win; | |
| sInt result; | |
| sInt nr; | |
| sInt i; | |
| nr = -1; | |
| for(i=0;i<WScreenCount && nr==-1;i++) | |
| { | |
| if(MsgWin==(HWND) Screen[i].Window) | |
| nr = i; | |
| } | |
| // sDPrintF("%04x %08x %08x\n",msg,wparam,lparam); | |
| win = MsgWin; | |
| if(WAborting || nr==-1) | |
| return DefWindowProc(win,msg,wparam,lparam); | |
| result = 0; | |
| switch(msg) | |
| { | |
| case WM_DESTROY: | |
| PostQuitMessage(0); | |
| return 0; | |
| case WM_PAINT: | |
| #if !sPLAYER | |
| if(!WFullscreen) | |
| Render(); | |
| #endif | |
| ValidateRect(win,0); | |
| #if 0 | |
| if(/*WActiveCount!=0 &&*/ !WFullscreen) | |
| Render(); | |
| #endif | |
| break; | |
| case WM_ENTERSIZEMOVE: | |
| WActiveCount++; | |
| break; | |
| case WM_SIZE: | |
| if(!WFullscreen) | |
| WWindowedStyle = GetWindowLong(win,GWL_STYLE); | |
| if(wparam == SIZE_MINIMIZED) | |
| { | |
| WActiveCount++; | |
| WMinimized = 1; | |
| WMaximized = 0; | |
| } | |
| else if(wparam == SIZE_MAXIMIZED) | |
| { | |
| if(WMinimized) | |
| WActiveCount--; | |
| WMinimized = 0; | |
| WMaximized = 1; | |
| } | |
| else if(wparam == SIZE_RESTORED) | |
| { | |
| if(WMinimized) | |
| WActiveCount--; | |
| WMinimized = 0; | |
| WMaximized = 0; | |
| } | |
| if((wparam==SIZE_MAXIMIZED || wparam==SIZE_RESTORED) && WActiveCount==0) | |
| { | |
| InitScreens(); | |
| if(KeyIndex < MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = sKEY_MODECHANGE; | |
| } | |
| break; | |
| case WM_EXITSIZEMOVE: | |
| WActiveCount--; | |
| if(WActiveCount==0) | |
| { | |
| InitScreens(); | |
| if(KeyIndex < MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = sKEY_MODECHANGE; | |
| } | |
| break; | |
| case WM_SETCURSOR: | |
| if(WFullscreen) | |
| { | |
| SetCursor(0); | |
| return 0; | |
| } | |
| break; | |
| case WM_ENTERMENULOOP: | |
| WActiveCount++; | |
| break; | |
| case WM_EXITMENULOOP: | |
| WActiveCount--; | |
| break; | |
| case WM_NCHITTEST: | |
| if(WFullscreen) | |
| return HTCLIENT; | |
| break; | |
| case WM_SYSCOMMAND: | |
| switch(wparam) | |
| { | |
| case SC_MOVE: | |
| case SC_SIZE: | |
| case SC_MAXIMIZE: | |
| case SC_KEYMENU: | |
| case SC_MONITORPOWER: | |
| if(WFullscreen) | |
| return 1; | |
| } | |
| break; | |
| case WM_SYSKEYUP: | |
| case WM_SYSKEYDOWN: | |
| //if(WFullscreen) | |
| return 0; | |
| break; | |
| case WM_ACTIVATE: | |
| WFocus = wparam != WA_INACTIVE; | |
| break; | |
| case WM_ACTIVATEAPP: | |
| WFocus = wparam != 0; | |
| break; | |
| case WM_CLOSE: | |
| if(KeyIndex<MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = sKEY_CLOSE; | |
| else | |
| KeyBuffer[KeyIndex-1] = sKEY_CLOSE; | |
| return 0; | |
| case WM_LBUTTONDOWN: | |
| MouseButtons |= 1; | |
| MouseButtonsSave |= 1; | |
| KeyQual |= sKEYQ_MOUSEL; | |
| if(KeyIndex < MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = (sKEY_MOUSEL)|KeyQual; | |
| SetCapture(win); | |
| break; | |
| case WM_LBUTTONUP: | |
| MouseButtons &= ~1; | |
| KeyQual &= ~sKEYQ_MOUSEL; | |
| if(KeyIndex < MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = (sKEY_MOUSEL)|sKEYQ_BREAK|KeyQual; | |
| ReleaseCapture(); | |
| break; | |
| case WM_RBUTTONDOWN: | |
| MouseButtons |= 2; | |
| MouseButtonsSave |= 2; | |
| KeyQual |= sKEYQ_MOUSER; | |
| if(KeyIndex < MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = (sKEY_MOUSER)|KeyQual; | |
| SetCapture(win); | |
| break; | |
| case WM_MBUTTONDOWN: | |
| MouseButtons |= 4; | |
| MouseButtonsSave |= 4; | |
| KeyQual |= sKEYQ_MOUSEM; | |
| if(KeyIndex < MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = (sKEY_MOUSEM)|KeyQual; | |
| SetCapture(win); | |
| break; | |
| case WM_RBUTTONUP: | |
| MouseButtons &= ~2; | |
| KeyQual &= ~sKEYQ_MOUSER; | |
| if(KeyIndex < MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = (sKEY_MOUSER)|sKEYQ_BREAK|KeyQual; | |
| ReleaseCapture(); | |
| break; | |
| case WM_MBUTTONUP: | |
| MouseButtons &= ~4; | |
| KeyQual &= ~sKEYQ_MOUSEM; | |
| if(KeyIndex < MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = (sKEY_MOUSEM)|sKEYQ_BREAK|KeyQual; | |
| ReleaseCapture(); | |
| break; | |
| case WM_MOUSEMOVE: | |
| WMouseX = (sS16)LOWORD(lparam); | |
| WMouseY = (sS16)HIWORD(lparam); | |
| break; | |
| case WM_MOUSEWHEEL: | |
| i = (sS16)(wparam>>16); | |
| while(i>=WHEEL_DELTA && KeyIndex < MAX_KEYBUFFER) | |
| { | |
| KeyBuffer[KeyIndex++] = sKEY_WHEELUP; | |
| i -= WHEEL_DELTA; | |
| } | |
| while(i<=-WHEEL_DELTA && KeyIndex < MAX_KEYBUFFER) | |
| { | |
| KeyBuffer[KeyIndex++] = sKEY_WHEELDOWN; | |
| i += WHEEL_DELTA; | |
| } | |
| break; | |
| #if !sUSE_DIRECTINPUT | |
| case WM_KEYDOWN: | |
| if(KeyIndex < MAX_KEYBUFFER-1 && wparam<256) | |
| { | |
| i = VKTable[wparam]; | |
| if(i==1) i=wparam; | |
| KeyBuffer[KeyIndex++] = i; | |
| } | |
| break; | |
| case WM_KEYUP: | |
| if(KeyIndex < MAX_KEYBUFFER-1 && wparam<256) | |
| { | |
| i = VKTable[wparam]; | |
| if(i==1) i=wparam; | |
| KeyBuffer[KeyIndex++] = i|sKEYQ_BREAK; | |
| } | |
| break; | |
| #endif | |
| } | |
| return DefWindowProc(win,msg,wparam,lparam); | |
| } | |
| void sSystem_::InitScreens() | |
| { | |
| HRESULT hr; | |
| D3DPRESENT_PARAMETERS d3dpp[8]; | |
| RECT r; | |
| sInt nr,i; | |
| sU32 create; | |
| sU16 *iblock; | |
| sHardTex *tex; | |
| D3DCAPS9 caps; | |
| sVERIFY(WScreenCount<8); | |
| sREGZONE(FlipLock); | |
| sREGZONE(MtrlSet); | |
| sREGZONE(MtrlSetSetup); | |
| sREGZONE(Sound3D); | |
| ScreenFormat=CmdNoRt ? D3DFMT_R5G6B5 : D3DFMT_A8R8G8B8; | |
| ZBufFormat=CmdNoRt ? D3DFMT_D16 : D3DFMT_D24S8; | |
| for(nr=0;nr<WScreenCount;nr++) | |
| { | |
| // determine n | |
| Screen[nr].SFormat=ScreenFormat; | |
| Screen[nr].ZFormat=ZBufFormat; | |
| WINZERO(d3dpp[nr]); | |
| d3dpp[nr].BackBufferFormat = (D3DFORMAT) Screen[nr].SFormat; | |
| d3dpp[nr].EnableAutoDepthStencil = sFALSE; | |
| d3dpp[nr].SwapEffect = D3DSWAPEFFECT_DISCARD; | |
| if((ConfigFlags & (sSF_FULLSCREEN | sSF_WAITVSYNC)) == (sSF_FULLSCREEN | sSF_WAITVSYNC)) | |
| d3dpp[nr].BackBufferCount = 2; | |
| else | |
| d3dpp[nr].BackBufferCount = 1; | |
| d3dpp[nr].PresentationInterval = (ConfigFlags & sSF_WAITVSYNC) ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; | |
| d3dpp[nr].Flags = 0; | |
| d3dpp[nr].hDeviceWindow = (HWND) Screen[nr].Window; | |
| if(ConfigFlags & sSF_FULLSCREEN) | |
| { | |
| d3dpp[nr].BackBufferWidth = ConfigX; | |
| d3dpp[nr].BackBufferHeight = ConfigY; | |
| Screen[nr].XSize = ConfigX; | |
| Screen[nr].YSize = ConfigY; | |
| WFullscreen = sTRUE; | |
| SetWindowLong((HWND)Screen[nr].Window,GWL_STYLE,WS_POPUP|WS_VISIBLE); | |
| } | |
| else | |
| { | |
| d3dpp[nr].Windowed = TRUE; | |
| GetClientRect((HWND) Screen[nr].Window,&r); | |
| Screen[nr].XSize = r.right-r.left; | |
| Screen[nr].YSize = r.bottom-r.top; | |
| WFullscreen = sFALSE; | |
| SetWindowLong((HWND)Screen[nr].Window,GWL_STYLE,WWindowedStyle); | |
| } | |
| d3dpp[nr].MultiSampleType = MultiSampleType; | |
| d3dpp[nr].MultiSampleQuality = MultiSampleQuality; | |
| } | |
| hr=DXD->GetDeviceCaps(0,D3DDEVTYPE_HAL,&caps); | |
| sVERIFY(!FAILED(hr)); | |
| if(!DXDev) | |
| { | |
| #if LOGGING | |
| sDPrintF("Create Device\n"); | |
| #endif | |
| if((caps.PixelShaderVersion&0xffff)==0x0000) | |
| goto dxdevfailed; | |
| create = D3DCREATE_HARDWARE_VERTEXPROCESSING; | |
| if(ConfigFlags & sSF_MULTISCREEN) create |= D3DCREATE_ADAPTERGROUP_DEVICE; | |
| hr = DXD->CreateDevice(0,D3DDEVTYPE_HAL,(HWND) Screen[0].Window,create,d3dpp,&DXDev); | |
| if(FAILED(hr)) | |
| { | |
| dxdevfailed:; | |
| create = D3DCREATE_SOFTWARE_VERTEXPROCESSING; | |
| if(ConfigFlags & sSF_MULTISCREEN) create |= D3DCREATE_ADAPTERGROUP_DEVICE; | |
| hr = DXD->CreateDevice(0,D3DDEVTYPE_HAL,(HWND) Screen[0].Window,create,d3dpp,&DXDev); | |
| if(FAILED(hr)) | |
| { | |
| ::MoveWindow((HWND)Screen[0].Window,0,0,2,2,1); | |
| sFatal("could not create screen"); | |
| } | |
| } | |
| for(i=1;i<FVFMax;i++) | |
| DXDev->CreateVertexDeclaration(FVFTable[i].Info,&FVFTable[i].Decl); | |
| // create dummy texture | |
| sU16 bmp[4*4*4]; | |
| sSetMem(bmp,0,sizeof(bmp)); | |
| AddTexture(4,4,sTF_A8R8G8B8,bmp,1); | |
| } | |
| else | |
| { | |
| sRelease(DXNormalCube); | |
| sRelease(DXTinyNormalCube); | |
| sRelease(DXAttenuationVolume); | |
| sRelease(ZBuffer); | |
| sRelease(RTBuffer); | |
| sRelease(SyncQuery); | |
| /*for(i=0;i<MAX_GEOHANDLE;i++) | |
| { | |
| if(GeoHandle[i].Mode!=0) | |
| { | |
| if(GeoHandle[i].Vertex.Buffer>=3) | |
| GeoBuffer[GeoHandle[i].Vertex.Buffer].Free(); | |
| if(GeoHandle[i].Index.Buffer>=3) | |
| GeoBuffer[GeoHandle[i].Index.Buffer].Free(); | |
| } | |
| GeoHandle[i].Vertex.Count = 0; | |
| GeoHandle[i].Vertex.Buffer = 0; | |
| GeoHandle[i].Index.Count = 0; | |
| GeoHandle[i].Index.Buffer = 0; | |
| }*/ | |
| for(i=0;i</*MAX_GEOBUFFER*/3;i++) | |
| { | |
| if(i>=3) | |
| sVERIFY(GeoBuffer[i].UserCount==0); | |
| if(GeoBuffer[i].VB) | |
| { | |
| GeoBuffer[i].VB->Release(); // VB & IB are the same | |
| #if LOGGING | |
| sDPrintF("Release vertex/indexbuffer %d bytes\n",GeoBuffer[i].Size); | |
| #endif | |
| } | |
| GeoBuffer[i].Init(); | |
| } | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| { | |
| if(Textures[i].Flags & sTIF_RENDERTARGET) | |
| { | |
| sRelease(Textures[i].Tex); | |
| sRelease(Textures[i].Shadow); | |
| } | |
| } | |
| hr = DXDev->Reset(d3dpp); | |
| if(FAILED(hr)) | |
| { | |
| WDeviceLost = 1; | |
| return; | |
| } | |
| } | |
| // initialize gpumask | |
| if(caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) GpuMask |= sGPU_TWOSIDESTENCIL; | |
| // init buffer management | |
| #ifdef _DOPE | |
| BufferMemAlloc = 0; | |
| #endif | |
| ReCreateZBuffer(); | |
| SyncQuery = 0; | |
| /*DXERROR*/(DXDev->CreateQuery(D3DQUERYTYPE_EVENT,&SyncQuery)); // allow this to fail | |
| CreateGeoBuffer(0,1,0,MAX_DYNVBSIZE); | |
| CreateGeoBuffer(1,1,1,MAX_DYNIBSIZE); | |
| CreateGeoBuffer(2,1,2,MAX_DYNIBSIZE*2); | |
| CreateGeoBuffer(3,0,1,2*0x8000/4*6); | |
| DXERROR(GeoBuffer[3].IB->Lock(0,2*0x8000/4*6,(void **) &iblock,0)); | |
| for(i=0;i<0x8000/6;i++) | |
| sQuad(iblock,i*4+0,i*4+1,i*4+2,i*4+3); | |
| DXERROR(GeoBuffer[3].IB->Unlock()); | |
| HardwareShaderLevel = sPS_00; | |
| if((caps.PixelShaderVersion&0xffff)!=0x0000) | |
| { | |
| MakeCubeNormalizer(); | |
| MakeAttenuationVolume(); | |
| HardwareShaderLevel = sPS_11; | |
| if((caps.PixelShaderVersion&0xffff)>=0x0104) | |
| { | |
| HardwareShaderLevel = sPS_14; | |
| if((caps.PixelShaderVersion&0xffff)>=0x0200) | |
| { | |
| HardwareShaderLevel = sPS_20; | |
| } | |
| } | |
| } | |
| // set some defaults | |
| DXDev->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1); | |
| DXDev->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE); | |
| DXDev->SetRenderState(D3DRS_LIGHTING,0); | |
| if(CmdNoRt) | |
| DXDev->SetRenderState(D3DRS_DITHERENABLE,1); | |
| WDeviceLost = 0; | |
| if(WFullscreen) | |
| { | |
| GetWindowRect((HWND)Screen[0].Window,&r); | |
| ClipCursor(&r); | |
| ShowCursor(0); | |
| } | |
| else | |
| { | |
| ClipCursor(0); | |
| ShowCursor(1); | |
| } | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| { | |
| if(Textures[i].Flags & sTIF_RENDERTARGET) | |
| { | |
| tex = &Textures[i]; | |
| DXERROR(DXDev->CreateTexture(tex->XSize,tex->YSize,1,D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&tex->Tex,0)); | |
| if(Textures[i].Flags & sTIF_NEEDEXTRAZ) | |
| DXERROR(DXDev->CreateDepthStencilSurface(tex->XSize,tex->YSize,D3DFMT_D24S8,D3DMULTISAMPLE_NONE,0,TRUE,&tex->Shadow,0)); | |
| /*if(MultiSampleType) | |
| { | |
| DXERROR(DXDev->CreateRenderTarget(tex->XSize,tex->YSize,D3DFMT_A8R8G8B8,MultiSampleType,MultiSampleQuality,FALSE,&tex->Shadow,0)); | |
| }*/ | |
| } | |
| } | |
| DiscardCount[0] = DiscardCount[1] = DiscardCount[2] = 1; | |
| LastDecl = -1; | |
| LastVB = -1; | |
| LastVSize = 0; | |
| LastIB = -1; | |
| MtrlReset = sTRUE; | |
| MtrlClearCaches(); | |
| CurrentTarget = -1; | |
| NeedFinishBlit = sFALSE; | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::ReCreateZBuffer() | |
| { | |
| sInt i,xs,ys; | |
| // determine required size | |
| xs=ys=0; | |
| for(i=0;i<WScreenCount;i++) | |
| { | |
| xs=sMax<sInt>(xs,Screen[i].XSize); | |
| ys=sMax<sInt>(ys,Screen[i].YSize); | |
| } | |
| // handle default rendertarget texture sizes | |
| xs=sMax<sInt>(xs,1024); | |
| ys=sMax<sInt>(ys,1024/*512*/); | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| { | |
| sInt flags = Textures[i].Flags; | |
| if((flags & sTIF_RENDERTARGET) && !(flags & sTIF_NEEDEXTRAZ)) | |
| { | |
| xs=sMax<sInt>(xs,Textures[i].XSize); | |
| ys=sMax<sInt>(ys,Textures[i].YSize); | |
| } | |
| } | |
| // create the zbuffer | |
| if(xs!=ZBufXSize || ys!=ZBufYSize || !ZBuffer) | |
| { | |
| DXERROR(DXDev->SetDepthStencilSurface(0)); | |
| sRelease(ZBuffer); | |
| sRelease(RTBuffer); | |
| #if LOGGING | |
| sDPrintF("Create ZBuffer %dx%d\n",xs,ys); | |
| #endif | |
| DXERROR(DXDev->SetDepthStencilSurface(0)); // only for chaos laptop... | |
| DXERROR(DXDev->CreateDepthStencilSurface(xs,ys,(D3DFORMAT) ZBufFormat,MultiSampleType,MultiSampleQuality,FALSE,&ZBuffer,0)); | |
| #if !sPLAYER || 1 | |
| if(MultiSampleType) | |
| { | |
| DXERROR(DXDev->CreateRenderTarget(xs,ys,(D3DFORMAT) ScreenFormat,MultiSampleType,MultiSampleQuality,FALSE,&RTBuffer,0)); | |
| } | |
| #endif | |
| ZBufXSize=xs; | |
| ZBufYSize=ys; | |
| DXERROR(DXDev->SetDepthStencilSurface(ZBuffer)); | |
| } | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::ExitScreens() | |
| { | |
| sInt i; | |
| #if !sPLAYER | |
| VideoEnd(); | |
| #endif | |
| for(i=0;i<MAX_SETUPS;i++) | |
| { | |
| if(Setups[i].RefCount) | |
| Setups[i].Cleanup(); | |
| } | |
| for(i=0;i<MAX_SHADERS;i++) | |
| { | |
| if(Shaders[i].RefCount) | |
| Shaders[i].Cleanup(); | |
| } | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| { | |
| sRelease(Textures[i].Tex); | |
| sRelease(Textures[i].Shadow); | |
| } | |
| sRelease(DXNormalCube); | |
| sRelease(DXTinyNormalCube); | |
| sRelease(DXAttenuationVolume); | |
| sRelease(SyncQuery); | |
| sRelease(ZBuffer); | |
| sRelease(RTBuffer); | |
| for(i=1;i<MAX_GEOHANDLE;i++) | |
| { | |
| /*if(GeoHandle[i].Mode != 0) | |
| sFatal("GeoHandle leak in %s(%d) #%d",GeoHandle[i].File,GeoHandle[i].Line,GeoHandle[i].AllocId);*/ | |
| //sVERIFY(GeoHandle[i].Mode==0); | |
| } | |
| for(i=0;i<MAX_GEOBUFFER;i++) | |
| { | |
| /*if(i>=3) | |
| sVERIFY(GeoBuffer[i].UserCount==0);*/ | |
| if(GeoBuffer[i].VB) | |
| GeoBuffer[i].VB->Release(); // VB & IB are the same | |
| GeoBuffer[i].Init(); | |
| } | |
| // for(i=0;i<MAX_MATERIALS;i++) | |
| // sVERIFY(Materials[i].RefCount==0); | |
| for(i=1;i<FVFMax;i++) | |
| if(FVFTable[i].Decl) | |
| FVFTable[i].Decl->Release(); | |
| sRelease(DXDev); | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Startup, with sINTRO ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| #if sINTRO | |
| /****************************************************************************/ | |
| static LRESULT WINAPI MainWndProc(HWND win,UINT msg,WPARAM wparam,LPARAM lparam) | |
| { | |
| MsgWin = win; | |
| sInt i; | |
| switch(msg) | |
| { | |
| case WM_DESTROY: | |
| PostQuitMessage(0); | |
| return 0; | |
| case WM_PAINT: | |
| ValidateRect(win,0); | |
| break; | |
| case WM_SETCURSOR: | |
| if(IntroFlags & sSF_FULLSCREEN) | |
| { | |
| SetCursor(0); | |
| return 0; | |
| } | |
| break; | |
| case WM_LBUTTONDOWN: | |
| sSystem->MouseButtons |= 1; | |
| if(sSystem->KeyIndex < MAX_KEYBUFFER) | |
| sSystem->KeyBuffer[sSystem->KeyIndex++] = sKEY_MOUSEL; | |
| break; | |
| case WM_LBUTTONUP: | |
| sSystem->MouseButtons &= ~1; | |
| if(sSystem->KeyIndex < MAX_KEYBUFFER) | |
| sSystem->KeyBuffer[sSystem->KeyIndex++] = (sKEY_MOUSEL)|sKEYQ_BREAK; | |
| break; | |
| case WM_CLOSE: | |
| sSystem->Exit(); | |
| break; | |
| #if !sUSE_DIRECTINPUT | |
| case WM_KEYDOWN: | |
| if(sSystem->KeyIndex < MAX_KEYBUFFER-1 && wparam<256) | |
| { | |
| i = VKTable[wparam]; | |
| if(i==1) i=wparam; | |
| sSystem->KeyBuffer[sSystem->KeyIndex++] = i; | |
| } | |
| break; | |
| case WM_KEYUP: | |
| if(sSystem->KeyIndex < MAX_KEYBUFFER-1 && wparam<256) | |
| { | |
| i = VKTable[wparam]; | |
| if(i==1) i=wparam; | |
| sSystem->KeyBuffer[sSystem->KeyIndex++] = i|sKEYQ_BREAK; | |
| } | |
| break; | |
| #endif | |
| } | |
| return DefWindowProc(win,msg,wparam,lparam); | |
| } | |
| /****************************************************************************/ | |
| #pragma lekktor(off) | |
| #if !sINTRO || !sRELEASE | |
| int APIENTRY WinMain(HINSTANCE inst,HINSTANCE prev,LPSTR cmdline,int show) | |
| { | |
| WInst = inst; | |
| WCmdLine = cmdline; | |
| #if sUSE_LEKKTOR | |
| sLekktorInit(); | |
| #endif | |
| sSystem = new sSystem_; | |
| sSetMem(((sU8 *)sSystem)+4,0,sizeof(sSystem_)-4); | |
| // load d3d dll | |
| d3dlib = ::LoadLibraryA("d3d9.dll"); | |
| if(d3dlib==0) | |
| sFatal("You need DirectX 9 (or better) to run this program."); | |
| Direct3DCreate9P = (Direct3DCreate9T) GetProcAddress(d3dlib,"Direct3DCreate9"); | |
| sVERIFY(Direct3DCreate9P); | |
| // initialize d3d | |
| sSystem->DXD = (*Direct3DCreate9P)(D3D_SDK_VERSION); | |
| if(!sSystem->DXD) | |
| sFatal("DirectX 9.0c not present."); | |
| #if !sCONFIGDIALOG | |
| sSystem->InitX(); | |
| #else | |
| if(sAppHandler(sAPPCODE_CONFIG,0)) | |
| sSystem->InitX(); | |
| #endif | |
| sRelease(sSystem->DXD); | |
| FreeLibrary(d3dlib); | |
| delete sSystem; | |
| ExitProcess(0); | |
| } | |
| #else | |
| void WinMainCRTStartup() | |
| { | |
| WInst = GetModuleHandle(0); | |
| WCmdLine = GetCommandLineA(); | |
| while(*WCmdLine!=0 && *WCmdLine!=' ') WCmdLine++; | |
| while(*WCmdLine==' ') WCmdLine++; | |
| #if sUSE_LEKKTOR | |
| sLekktorInit(); | |
| #endif | |
| sSystem = new sSystem_; | |
| sSetMem(((sU8 *)sSystem)+4,0,sizeof(sSystem_)-4); | |
| // load d3d dll | |
| d3dlib = ::LoadLibraryA("d3d9.dll"); | |
| if(d3dlib==0) | |
| sFatal("You need DirectX 9 (or better) to run this program."); | |
| Direct3DCreate9P = (Direct3DCreate9T) GetProcAddress(d3dlib,"Direct3DCreate9"); | |
| sVERIFY(Direct3DCreate9P); | |
| // initialize d3d | |
| sSystem->DXD = (*Direct3DCreate9P)(D3D_SDK_VERSION); | |
| if(!sSystem->DXD) | |
| sFatal("DirectX 9.0c not present."); | |
| #if !sCONFIGDIALOG | |
| sSystem->InitX(); | |
| #else | |
| if(sAppHandler(sAPPCODE_CONFIG,0)) | |
| sSystem->InitX(); | |
| #endif | |
| sRelease(sSystem->DXD); | |
| FreeLibrary(d3dlib); | |
| delete sSystem; | |
| ExitProcess(0); | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| void sSystem_::InitX() | |
| { | |
| WNDCLASS wc; | |
| MSG msg; | |
| sBool quitmsg; | |
| sInt i; | |
| // init system | |
| sSystem->ConfigFlags = sSF_DIRECT3D; | |
| sSystem->ConfigX = IntroScreenX; | |
| sSystem->ConfigY = IntroScreenY; | |
| // find dlls | |
| dslib = ::LoadLibraryA("dsound.dll"); | |
| DirectSoundCreate8P = (DirectSoundCreate8T) GetProcAddress(dslib,"DirectSoundCreate8"); | |
| sVERIFY(DirectSoundCreate8P); | |
| #if sUSE_DIRECTINPUT | |
| dilib = ::LoadLibraryA("dinput8.dll"); | |
| DirectInput8CreateP = (DirectInput8CreateT) GetProcAddress(dilib,"DirectInput8Create"); | |
| sVERIFY(DirectInput8CreateP); | |
| #endif | |
| // set up some more stuff | |
| timeBeginPeriod(1); | |
| WStartTime = timeGetTime(); | |
| sSetRndSeed(timeGetTime()&0x7fffffff); | |
| GDIScreenDC = GetDC(0); | |
| GDIDC = CreateCompatibleDC(GDIScreenDC); | |
| GDIHBM = CreateCompatibleBitmap(GDIScreenDC,16,16); | |
| SelectObject(GDIDC,GDIHBM); | |
| // sBroker = new sBroker_; | |
| // create window class | |
| wc.lpszClassName = ".thepd00"; | |
| wc.lpfnWndProc = MainWndProc; | |
| wc.style = CS_CLASSDC;///*CS_OWNDC|*/CS_VREDRAW|CS_HREDRAW; | |
| wc.hInstance = WInst; | |
| wc.hIcon = LoadIcon(WInst,MAKEINTRESOURCE(101)); | |
| wc.hCursor = LoadCursor(0,IDC_ARROW); | |
| wc.hbrBackground = 0; | |
| wc.lpszMenuName = 0; | |
| wc.cbClsExtra = 0; | |
| wc.cbWndExtra = 0; | |
| RegisterClass(&wc); | |
| // init | |
| // WActiveMsg = 1; | |
| // WContinuous = 1; | |
| // WConstantUpdate = sTRUE; | |
| // WFocus = 1; | |
| sU32 windowstyle; | |
| sInt windowx; | |
| sInt windowy; | |
| if(IntroFlags & sSF_FULLSCREEN) // IntroFullscreen ist normalerweise eine konstante! | |
| { | |
| windowstyle = WS_POPUP|WS_VISIBLE; | |
| windowx = IntroScreenX; | |
| windowy = IntroScreenY; | |
| } | |
| else | |
| { | |
| windowstyle = WS_OVERLAPPEDWINDOW|WS_VISIBLE; | |
| RECT rc; | |
| rc.left = rc.top = 0; | |
| rc.right = IntroScreenX; | |
| rc.bottom = IntroScreenY; | |
| AdjustWindowRect(&rc,windowstyle,FALSE); | |
| windowx = rc.right - rc.left; | |
| windowy = rc.bottom - rc.top; | |
| } | |
| Screen[0].Window = (sU32) CreateWindowEx( | |
| 0, | |
| ".thepd00", | |
| sWindowTitle, | |
| windowstyle, | |
| 0,0, | |
| windowx,windowy, | |
| 0,0, | |
| WInst,0); | |
| sSystem->WScreenCount = 1; | |
| sSetMem(GeoBuffer,0,sizeof(GeoBuffer)); | |
| sSetMem(GeoHandle,0,sizeof(GeoHandle)); | |
| #if sUSE_DIRECTINPUT | |
| if(!InitDI()) | |
| sFatal("could not initialise Direct Input!"); | |
| #endif | |
| ZBufFormat = 0; | |
| ZBuffer = 0; | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| Textures[i].Flags = 0; | |
| sSetMem(Setups,0,sizeof(Setups)); | |
| MtrlClearCaches(); | |
| InitScreens(); | |
| // ShowWindow((HWND)Screen[0].Window,SW_SHOW); | |
| sFloatFix(); | |
| #if sUSE_DIRECTSOUND | |
| if(!InitDS()) | |
| sFatal("could not initialize DirectSound"); | |
| #endif | |
| // main loop | |
| DXDev->BeginScene(); | |
| sAppHandler(sAPPCODE_INIT,0); | |
| DXDev->EndScene(); | |
| msg.message = WM_NULL; | |
| PeekMessage(&msg,0,0,0,PM_NOREMOVE); | |
| quitmsg = 0; | |
| do | |
| { | |
| if(!MessagePump()) | |
| quitmsg = 1; | |
| for(i=0;i<KeyIndex;i++) | |
| sAppHandler(sAPPCODE_KEY,KeyBuffer[i]); | |
| KeyIndex = 0; | |
| Render(); | |
| #if sUSE_DIRECTSOUND | |
| MarkDS(); | |
| #endif | |
| } | |
| while(!quitmsg); | |
| sAppHandler(sAPPCODE_EXIT,0); | |
| #if sUSE_DIRECTSOUND | |
| if(DXSBuffer) | |
| DXSBuffer->Stop(); | |
| ExitDS(); | |
| #endif | |
| ExitScreens(); | |
| sExitTypes(); | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::InitScreens() | |
| { | |
| HRESULT hr; | |
| D3DPRESENT_PARAMETERS d3dpp; | |
| sInt i; | |
| sU32 create; | |
| sU16 *iblock; | |
| D3DCAPS9 caps; | |
| sREGZONE(FlipLock); | |
| ZBufFormat=D3DFMT_D24S8; | |
| Screen[0].SFormat=D3DFMT_A8R8G8B8; | |
| Screen[0].ZFormat=ZBufFormat; | |
| WINZERO(d3dpp); | |
| d3dpp.BackBufferFormat = (D3DFORMAT) Screen[0].SFormat; | |
| d3dpp.EnableAutoDepthStencil = sFALSE; | |
| d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; | |
| if(IntroFlags & sSF_WAITVSYNC) | |
| { | |
| d3dpp.BackBufferCount = 2; | |
| d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; | |
| } | |
| else | |
| { | |
| d3dpp.BackBufferCount = 1; | |
| d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; | |
| } | |
| d3dpp.Flags = 0; | |
| d3dpp.hDeviceWindow = (HWND) Screen[0].Window; | |
| if(IntroFlags & sSF_FULLSCREEN) | |
| { | |
| d3dpp.Windowed = FALSE; | |
| d3dpp.BackBufferWidth = ConfigX; | |
| d3dpp.BackBufferHeight = ConfigY; | |
| Screen[0].XSize = ConfigX; | |
| Screen[0].YSize = ConfigY; | |
| } | |
| else | |
| { | |
| RECT r; | |
| d3dpp.Windowed = TRUE; | |
| GetClientRect((HWND) Screen[0].Window,&r); | |
| Screen[0].XSize = r.right-r.left; | |
| Screen[0].YSize = r.bottom-r.top; | |
| } | |
| hr=DXD->GetDeviceCaps(0,D3DDEVTYPE_HAL,&caps); | |
| sVERIFY(!FAILED(hr)); | |
| if(!DXDev) | |
| { | |
| if((caps.PixelShaderVersion&0xffff)<0x0100) | |
| sFatal("Pixel shaders required."); | |
| create = D3DCREATE_HARDWARE_VERTEXPROCESSING; | |
| hr = DXD->CreateDevice(0,D3DDEVTYPE_HAL,(HWND) Screen[0].Window,create,&d3dpp,&DXDev); | |
| if(FAILED(hr)) | |
| { | |
| create = D3DCREATE_SOFTWARE_VERTEXPROCESSING; | |
| hr = DXD->CreateDevice(0,D3DDEVTYPE_HAL,(HWND) Screen[0].Window,create,&d3dpp,&DXDev); | |
| if(FAILED(hr)) | |
| { | |
| #if sPLAYER && !sINTRO | |
| ::MoveWindow((HWND)Screen[0].Window,0,0,2,2,1); | |
| ConfigDialog(IDD_DIALOG3,0); | |
| ExitProcess(0); | |
| #else | |
| sFatal("CreateDevice failed"); | |
| #endif | |
| } | |
| } | |
| for(i=1;i<FVFMax;i++) | |
| DXDev->CreateVertexDeclaration(FVFTable[i].Info,&FVFTable[i].Decl); | |
| // create dummy texture | |
| sU16 bmp[4*4*4]; | |
| sSetMem(bmp,0,sizeof(bmp)); | |
| AddTexture(4,4,sTF_A8R8G8B8,bmp,1); | |
| } | |
| else | |
| { | |
| #if !sINTRO_NO_ALT_TAB | |
| if(DXNormalCube) | |
| { | |
| DXNormalCube->Release(); | |
| DXNormalCube = 0; | |
| } | |
| sRelease(DXTinyNormalCube); | |
| if(ZBuffer) | |
| { | |
| ZBuffer->Release(); | |
| ZBuffer = 0; | |
| } | |
| for(i=0;i<2;i++) | |
| { | |
| DXBlockSurface[i]->Release(); | |
| DXBlockSurface[i] = 0; | |
| } | |
| for(i=0;i<3;i++) | |
| { | |
| if(GeoBuffer[i].VB) | |
| GeoBuffer[i].VB->Release(); | |
| GeoBuffer[i].Init(); | |
| } | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| { | |
| if(Textures[i].Flags & sTIF_RENDERTARGET) | |
| { | |
| #if LOGGING | |
| sDPrintF("Release Rendertarget\n"); | |
| #endif | |
| Textures[i].Tex->Release(); | |
| Textures[i].Tex=0; | |
| } | |
| } | |
| DXERROR(DXDev->Reset(&d3dpp)); | |
| #endif | |
| } | |
| // zbuffer | |
| sInt zBufX = sMax(ConfigX,1024); | |
| sInt zBufY = sMax(ConfigY, 512); | |
| DXERROR(DXDev->CreateDepthStencilSurface(zBufX,zBufY,(D3DFORMAT) ZBufFormat,D3DMULTISAMPLE_NONE,0,FALSE,&ZBuffer,0)); | |
| DXERROR(DXDev->SetDepthStencilSurface(ZBuffer)); | |
| // initialize gpumask | |
| if(caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) GpuMask |= sGPU_TWOSIDESTENCIL; | |
| // init buffer management | |
| CreateGeoBuffer(0,1,0,MAX_DYNVBSIZE); | |
| CreateGeoBuffer(1,1,1,MAX_DYNIBSIZE); | |
| CreateGeoBuffer(2,1,2,MAX_DYNIBSIZE*2); | |
| // set some defaults | |
| WDeviceLost = 0; | |
| #if !sINTRO_NO_ALT_TAB | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| { | |
| if(Textures[i].Flags & sTIF_RENDERTARGET) | |
| { | |
| sHardTex *tex = &Textures[i]; | |
| DXERROR(DXDev->CreateTexture(tex->XSize,tex->YSize,1,D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&tex->Tex,0)); | |
| } | |
| } | |
| #endif | |
| for(i=0;i<2;i++) | |
| DXDev->CreateOffscreenPlainSurface(16,16,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&DXBlockSurface[i],0); | |
| // create managed resources | |
| CreateGeoBuffer(3,0,1,2*0x8000/4*6); | |
| DXERROR(GeoBuffer[3].IB->Lock(0,2*0x8000/4*6,(void **) &iblock,0)); | |
| for(i=0;i<0x8000/6;i++) | |
| sQuad(iblock,i*4+0,i*4+1,i*4+2,i*4+3); | |
| DXERROR(GeoBuffer[3].IB->Unlock()); | |
| MakeCubeNormalizer(); | |
| MakeAttenuationVolume(); | |
| DiscardCount[0] = DiscardCount[1] = DiscardCount[2] = 1; | |
| LastDecl = -1; | |
| LastVB = -1; | |
| LastVSize = 0; | |
| LastIB = -1; | |
| MtrlReset = sTRUE; | |
| CurrentTarget = -1; | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::ExitScreens() | |
| { | |
| sInt i; | |
| for(i=0;i<MAX_SETUPS;i++) | |
| { | |
| if(Setups[i].RefCount) | |
| Setups[i].Cleanup(); | |
| } | |
| for(i=0;i<MAX_SHADERS;i++) | |
| { | |
| if(Shaders[i].RefCount) | |
| Shaders[i].Cleanup(); | |
| } | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| { | |
| sRelease(Textures[i].Tex); | |
| sRelease(Textures[i].Shadow); | |
| } | |
| sRelease(DXNormalCube); | |
| sRelease(DXTinyNormalCube); | |
| sRelease(DXAttenuationVolume); | |
| sRelease(SyncQuery); | |
| sRelease(ZBuffer); | |
| sRelease(RTBuffer); | |
| for(i=1;i<MAX_GEOHANDLE;i++) | |
| { | |
| /*if(GeoHandle[i].Mode != 0) | |
| sFatal("GeoHandle leak in %s(%d) #%d",GeoHandle[i].File,GeoHandle[i].Line,GeoHandle[i].AllocId);*/ | |
| //sVERIFY(GeoHandle[i].Mode==0); | |
| } | |
| for(i=0;i<MAX_GEOBUFFER;i++) | |
| { | |
| /*if(i>=3) | |
| sVERIFY(GeoBuffer[i].UserCount==0);*/ | |
| if(GeoBuffer[i].VB) | |
| GeoBuffer[i].VB->Release(); // VB & IB are the same | |
| GeoBuffer[i].Init(); | |
| } | |
| // for(i=0;i<MAX_MATERIALS;i++) | |
| // sVERIFY(Materials[i].RefCount==0); | |
| for(i=1;i<FVFMax;i++) | |
| if(FVFTable[i].Decl) | |
| FVFTable[i].Decl->Release(); | |
| sRelease(DXDev); | |
| } | |
| #endif | |
| #pragma lekktor(on) | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** System Implementation ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Init/Exit/Debug ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| #pragma lekktor(off) | |
| void sSystem_::Exit() | |
| { | |
| #if sUSE_LEKKTOR | |
| sLekktorExit(); | |
| #endif | |
| DestroyWindow ((HWND)Screen[0].Window); | |
| // PostQuitMessage(0); | |
| } | |
| void sSystem_::Tag() | |
| { | |
| } | |
| /*sNORETURN*/ void sSystem_::Abort(sChar *msg) | |
| { | |
| #if sINTRO | |
| if(DXD) | |
| DXD->Release(); | |
| if(msg) | |
| MessageBox(0,msg,"Fatal Error",MB_OK|MB_TASKMODAL|MB_SETFOREGROUND|MB_TOPMOST|MB_ICONERROR); | |
| ExitProcess(0); | |
| #else | |
| WAborting = sTRUE; | |
| if(DXD) | |
| DXD->Release(); | |
| _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)&~(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF)); | |
| if(msg) | |
| MessageBox(0,msg,"Fatal Error",MB_OK|MB_TASKMODAL|MB_SETFOREGROUND|MB_TOPMOST|MB_ICONERROR); | |
| ExitProcess(0); | |
| // exit(0); | |
| #endif | |
| } | |
| void sSystem_::Log(sChar *s) | |
| { | |
| if(!sFatality && !sAppHandler(sAPPCODE_DEBUGPRINT,(sDInt) s)) | |
| { | |
| OutputDebugString(s); | |
| } | |
| } | |
| #pragma lekktor(on) | |
| /****************************************************************************/ | |
| #if !sINTRO | |
| void sSystem_::Init(sU32 flags,sInt xs,sInt ys) | |
| { | |
| ConfigX = xs; | |
| ConfigY = ys; | |
| ConfigFlags = flags; | |
| } | |
| void sSystem_::Reset(sU32 flags,sInt x,sInt y,sInt x2,sInt y2) | |
| { | |
| ConfigFlags = flags; | |
| ConfigX = x; | |
| ConfigY = y; | |
| // ConfigX2 = x2; | |
| // CondifY2 = y2; | |
| InitScreens(); | |
| if(!(flags & (sSF_FULLSCREEN|sSF_MULTISCREEN))) | |
| { | |
| ::MoveWindow((HWND)Screen[0].Window,0,0,x,y,TRUE); | |
| ShowWindow((HWND)Screen[0].Window,SW_RESTORE); | |
| InitScreens(); | |
| } | |
| if(KeyIndex < MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = sKEY_MODECHANGE; | |
| } | |
| sInt sSystem_::MemoryUsed() | |
| { | |
| return MemoryUsedCount; | |
| } | |
| void sSystem_::CheckMem() | |
| { | |
| _CrtCheckMemory(); | |
| } | |
| #endif | |
| sChar *sSystem_::GetCmdLine() | |
| { | |
| return WCmdLine; | |
| } | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Render ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| #if sPLAYER | |
| #pragma lekktor(off) | |
| #ifdef _DOPE | |
| extern void DopeProgress(sInt done,sInt max); | |
| #endif | |
| void sSystem_::Progress(sInt done,sInt max) | |
| { | |
| static sInt lasttime = 0; | |
| const int step = 3; | |
| sInt time; | |
| sRect r[3]; | |
| #ifndef _DOPE | |
| if(lasttime==0) | |
| GetAsyncKeyState(VK_ESCAPE); | |
| time = timeGetTime(); | |
| if(time > lasttime+450 || done==max) | |
| { | |
| lasttime = time; | |
| sViewport vp; | |
| vp.Init(); | |
| SetViewport(vp); | |
| Clear(sVCF_COLOR); | |
| sZONE(FlipLock); | |
| static const sU32 colors[3] = { 0xffffffff,0xff000000,0xffffffff }; | |
| r[0].Init(20+step*0,ConfigY/2-20+step*0,ConfigX-20-step*0,ConfigY/2+20-step*0); | |
| r[1].Init(20+step*1,ConfigY/2-20+step*1,ConfigX-20-step*1,ConfigY/2+20-step*1); | |
| r[2].Init(20+step*2,ConfigY/2-20+step*2,ConfigX-20-step*2,ConfigY/2+20-step*2); | |
| r[2].x1 = r[2].x0 + 1 + sMin(max,done)*(r[2].x1-r[2].x0-1)/max; | |
| ColorFill(3,r,colors); | |
| DXDev->EndScene(); | |
| DXDev->Present(0,0,0,0); | |
| if(!MessagePump()) | |
| ExitProcess(0); | |
| DXDev->BeginScene(); | |
| #if !sLINK_KKRIEGER | |
| // ganz schlechte idee, den progress-bar mit escape abzubrechen | |
| // wenn man den 2. progressbar mit escape startet. | |
| sInt key; | |
| key = GetAsyncKeyState(VK_ESCAPE); | |
| if(key&0x0001) | |
| { | |
| DXDev->Release(); | |
| ExitProcess(0); | |
| } | |
| #endif | |
| } | |
| #else | |
| time = timeGetTime(); | |
| if(time > lasttime+80 || done==max) | |
| { | |
| lasttime = time; | |
| #if sUSE_DIRECTINPUT | |
| PollDI(); | |
| #endif | |
| for(sInt i=0;i<KeyIndex;i++) | |
| sAppHandler(sAPPCODE_KEY,KeyBuffer[i]); | |
| KeyIndex = 0; | |
| MessagePump(); | |
| DopeProgress(done,max); | |
| DXDev->Present(0,0,0,0); | |
| } | |
| #endif | |
| } | |
| void sSystem_::WaitForKey() | |
| { | |
| // static sInt lasttime; | |
| // const int step = 3; | |
| // sInt time; | |
| while(1) | |
| { | |
| sViewport vp; | |
| vp.Init(); | |
| SetViewport(vp); | |
| Clear(sVCF_COLOR,0xff000000); | |
| sZONE(FlipLock); | |
| DXDev->EndScene(); | |
| DXDev->Present(0,0,0,0); | |
| DXDev->BeginScene(); | |
| sInt key; | |
| key = GetAsyncKeyState(VK_SPACE); | |
| if(key&0x8000) | |
| break; | |
| if(!MessagePump()) | |
| ExitProcess(0); | |
| } | |
| } | |
| #pragma lekktor(on) | |
| #endif | |
| /****************************************************************************/ | |
| void sSystem_::Render() | |
| { | |
| static sInt LastTime=-1; | |
| static sInt Reentrant = 0; | |
| sInt time,ticks; | |
| HRESULT hr; | |
| LastCamera.Init(); | |
| LastMatrix.Init(); | |
| LastViewProject.Init(); | |
| #pragma lekktor(off) | |
| if(WDeviceLost) | |
| { | |
| #if !sINTRO_NO_ALT_TAB | |
| Sleep(100); | |
| hr = DXDev->TestCooperativeLevel(); | |
| if(hr!=D3DERR_DEVICENOTRESET) | |
| return; | |
| InitScreens(); | |
| if(WDeviceLost) | |
| return; | |
| #else | |
| ExitProcess(0); | |
| #endif | |
| } | |
| #pragma lekktor(on) | |
| time = sSystem->GetTime(); | |
| ticks = 0; | |
| if(LastTime==-1) | |
| LastTime = time; | |
| sAppHandler(sAPPCODE_FRAME,0); | |
| #if !sINTRO | |
| while(time>LastTime) | |
| { | |
| LastTime+=10; | |
| ticks++; | |
| } | |
| if(ticks>10) | |
| ticks=10; | |
| sAppHandler(sAPPCODE_TICK,ticks); | |
| #endif | |
| if(Reentrant) | |
| DXERROR(DXDev->EndScene()); | |
| Reentrant++; | |
| DXERROR(DXDev->BeginScene()); | |
| sAppHandler(sAPPCODE_PAINT,0); | |
| DXERROR(DXDev->EndScene()); | |
| Reentrant--; | |
| #if sPROFILE | |
| sPerfMon->Marker(1); | |
| #endif | |
| #if !sINTRO | |
| if(WResponse) | |
| { | |
| sZONE(FlipLock); | |
| if(SyncQuery) | |
| { | |
| SyncQuery->Issue(D3DISSUE_END); | |
| while(S_FALSE == SyncQuery->GetData(0,0,D3DGETDATA_FLUSH)); | |
| } | |
| } | |
| #else | |
| { | |
| static sInt dblock = 0; | |
| D3DLOCKED_RECT lr; | |
| DXDev->ColorFill(DXBlockSurface[dblock],0,0); | |
| dblock = 1-dblock; | |
| DXERROR(DXBlockSurface[dblock]->LockRect(&lr,0,D3DLOCK_READONLY)); | |
| DXBlockSurface[dblock]->UnlockRect(); | |
| } | |
| #endif | |
| hr = DXDev->Present(0,0,0,0); | |
| if(hr==D3DERR_DEVICELOST) | |
| WDeviceLost = 1; | |
| DiscardCount[0]++; DiscardCount[1]++; DiscardCount[2]++; | |
| if(Reentrant) | |
| DXERROR(DXDev->BeginScene()); | |
| } | |
| void sSystem_::SetGamma(sF32 gamma) | |
| { | |
| D3DGAMMARAMP ramp; | |
| sInt i; | |
| for(i=0;i<256;i++) | |
| ramp.red[i] = ramp.green[i] = ramp.blue[i] = sFPow(i/255.0f,1.0f/gamma)*0xffff; | |
| DXDev->SetGammaRamp(0,D3DSGR_NO_CALIBRATION,&ramp); | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::ColorFill(sInt nRects,const sRect *rects,const sU32 *colors) | |
| { | |
| IDirect3DSurface9 *backbuffer=0; | |
| IDirect3DSwapChain9 *swapchain=0; | |
| if(nRects && SUCCEEDED(DXDev->GetSwapChain(0,&swapchain)) | |
| && SUCCEEDED(swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&backbuffer))) | |
| { | |
| for(sInt i=0;i<nRects;i++) | |
| DXDev->ColorFill(backbuffer,(RECT *) &rects[i],colors[i]); | |
| } | |
| sRelease(swapchain); | |
| sRelease(backbuffer); | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::Clear(sU32 flags,sU32 color) | |
| { | |
| sU32 d3dClear = 0; | |
| if(flags & sVCF_COLOR) d3dClear |= D3DCLEAR_TARGET; | |
| if(flags & sVCF_Z) d3dClear |= D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL; | |
| if(flags & sVCF_STENCIL) d3dClear |= D3DCLEAR_STENCIL; | |
| if(d3dClear) | |
| DXDev->Clear(0,0,d3dClear,color,1.0f,0); | |
| } | |
| void sSystem_::SetViewport(const sViewport &vp) | |
| { | |
| IDirect3DSurface9 *target; | |
| sInt txs,tys,tgtid; | |
| CurrentViewport = vp; | |
| // get target surface and its extents | |
| if(vp.RenderTarget == sINVALID) | |
| { | |
| // get screen extents and target surface | |
| sInt nr = vp.Screen; | |
| sVERIFY(nr >= 0 && nr < WScreenCount); | |
| txs = Screen[nr].XSize; | |
| tys = Screen[nr].YSize; | |
| tgtid = -nr - 1; | |
| } | |
| else | |
| { | |
| // get the target texture and verify that it's a rendertarget | |
| sVERIFY(vp.RenderTarget >= 0); | |
| sHardTex *tex = &Textures[vp.RenderTarget]; | |
| sVERIFY(tex->Flags & sTIF_RENDERTARGET); | |
| // get extents and surface | |
| txs = tex->XSize; | |
| tys = tex->YSize; | |
| tgtid = vp.RenderTarget; | |
| } | |
| // if the given window has zero extents, use full surface | |
| if(!vp.Window.XSize() || !vp.Window.YSize()) | |
| { | |
| CurrentViewport.Window.x0 = 0; | |
| CurrentViewport.Window.y0 = 0; | |
| CurrentViewport.Window.x1 = txs; | |
| CurrentViewport.Window.y1 = tys; | |
| } | |
| ViewportX = CurrentViewport.Window.XSize(); | |
| ViewportY = CurrentViewport.Window.YSize(); | |
| // prepare d3d viewport | |
| D3DVIEWPORT9 d3dvp; | |
| d3dvp.X = CurrentViewport.Window.x0; | |
| d3dvp.Y = CurrentViewport.Window.y0; | |
| d3dvp.Width = ViewportX; | |
| d3dvp.Height = ViewportY; | |
| d3dvp.MinZ = 0.0f; | |
| d3dvp.MaxZ = 1.0f; | |
| // set render target and viewport | |
| if(CurrentTarget != tgtid) | |
| { | |
| // finishing blit if multisampling is on | |
| FinishMSBlit(); | |
| IDirect3DSurface9 *zbuf = ZBuffer; | |
| if(vp.RenderTarget == sINVALID) | |
| { | |
| IDirect3DSwapChain9 *swapchain; | |
| DXERROR(DXDev->GetSwapChain(vp.Screen,&swapchain)); | |
| DXERROR(swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&target)); | |
| swapchain->Release(); | |
| } | |
| else if(vp.Screen == -2 && MultiSampleType) | |
| { | |
| #if sPLAYER || 1 | |
| sHardTex *tex = &Textures[vp.RenderTarget]; | |
| if(tex->XSize <= Screen[0].XSize && tex->YSize <= Screen[0].YSize) | |
| { | |
| IDirect3DSwapChain9 *swapchain; | |
| DXERROR(DXDev->GetSwapChain(0,&swapchain)); | |
| DXERROR(swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&target)); | |
| swapchain->Release(); | |
| } | |
| else | |
| { | |
| target = RTBuffer; | |
| target->AddRef(); | |
| } | |
| NeedFinishBlit = sTRUE; | |
| #else | |
| target=RTBuffer; | |
| target->AddRef(); | |
| #endif | |
| } | |
| else | |
| { | |
| DXERROR(Textures[vp.RenderTarget].Tex->GetSurfaceLevel(0,&target)); | |
| NeedFinishBlit = sFALSE; | |
| if(Textures[vp.RenderTarget].Flags & sTIF_NEEDEXTRAZ) | |
| zbuf = Textures[vp.RenderTarget].Shadow; | |
| } | |
| DXDev->SetRenderTarget(0,target); | |
| DXDev->SetDepthStencilSurface(zbuf); | |
| target->Release(); | |
| CurrentTarget = tgtid; | |
| } | |
| DXDev->SetViewport(&d3dvp); | |
| } | |
| void sSystem_::FinishMSBlit() | |
| { | |
| if(!NeedFinishBlit) | |
| return; | |
| if(CurrentTarget >= 0 && MultiSampleType) | |
| { | |
| RECT rc; | |
| sHardTex *tex = &Textures[CurrentTarget]; | |
| IDirect3DSurface9 *source,*target; | |
| rc.left = 0; | |
| rc.top = 0; | |
| #if sPLAYER || 1 | |
| if(tex->XSize <= Screen[0].XSize && tex->YSize <= Screen[0].YSize) | |
| { | |
| IDirect3DSwapChain9 *swapchain; | |
| DXERROR(DXDev->GetSwapChain(0,&swapchain)); | |
| DXERROR(swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&source)); | |
| swapchain->Release(); | |
| } | |
| else | |
| { | |
| source = RTBuffer; | |
| source->AddRef(); | |
| } | |
| rc.right = tex->XSize; | |
| rc.bottom = tex->YSize; | |
| #else | |
| source = RTBuffer; | |
| source->AddRef(); | |
| rc.right = tex->XSize; | |
| rc.bottom = tex->YSize; | |
| #endif | |
| DXERROR(tex->Tex->GetSurfaceLevel(0,&target)); | |
| DXERROR(DXDev->StretchRect(source,&rc,target,0,D3DTEXF_NONE)); | |
| target->Release(); | |
| source->Release(); | |
| } | |
| //NeedFinishBlit = sFALSE; | |
| } | |
| void sSystem_::CopyRT(sInt dest,const sRect *destRect,sInt source,const sRect *srcRect) | |
| { | |
| IDirect3DSurface9 *srcsurf,*dstsurf; | |
| sVERIFY(dest > -1 && Textures[dest].Tex); | |
| sVERIFY(source > -1 && Textures[source].Tex); | |
| DXERROR(Textures[dest].Tex->GetSurfaceLevel(0,&dstsurf)); | |
| DXERROR(Textures[source].Tex->GetSurfaceLevel(0,&srcsurf)); | |
| DXERROR(DXDev->StretchRect(srcsurf,(const RECT *) srcRect,dstsurf,(const RECT *) destRect,D3DTEXF_NONE)); | |
| dstsurf->Release(); | |
| srcsurf->Release(); | |
| } | |
| void sSystem_::ClearTarget(sInt rt,sU32 color) | |
| { | |
| IDirect3DSurface9 *texbuffer; | |
| DXERROR(Textures[rt].Tex->GetSurfaceLevel(0,&texbuffer)); | |
| DXERROR(DXDev->ColorFill(texbuffer,0,color)); | |
| texbuffer->Release(); | |
| } | |
| void sSystem_::GrabScreen(sInt sourceRT,const sRect &win,sInt tex,sBool stretch) | |
| { | |
| IDirect3DSurface9 *backbuffer; | |
| IDirect3DSwapChain9 *swapchain; | |
| IDirect3DSurface9 *texbuffer; | |
| sHardTex *ht; | |
| ht = &Textures[tex]; | |
| if(sourceRT == -1) | |
| { | |
| DXERROR(DXDev->GetSwapChain(0,&swapchain)); | |
| DXERROR(swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&backbuffer)); | |
| } | |
| else | |
| { | |
| DXERROR(Textures[sourceRT].Tex->GetSurfaceLevel(0,&backbuffer)); | |
| } | |
| DXERROR(ht->Tex->GetSurfaceLevel(0,&texbuffer)); | |
| RECT tgtRect; | |
| tgtRect.left = 0; | |
| tgtRect.top = 0; | |
| tgtRect.right = win.XSize(); | |
| tgtRect.bottom = win.YSize(); | |
| // if(!sRELEASE) | |
| // DXERROR(DXDev->ColorFill(texbuffer,0,0xffff0000)); | |
| DXERROR(DXDev->StretchRect(backbuffer,(const RECT *)&win,texbuffer,stretch ? 0 : &tgtRect,D3DTEXF_NONE)); | |
| if(sourceRT == -1) | |
| swapchain->Release(); | |
| backbuffer->Release(); | |
| texbuffer->Release(); | |
| } | |
| void sSystem_::Begin2D(sU32 **buffer,sInt &stride) | |
| { | |
| IDirect3DSurface9 *backbuffer; | |
| IDirect3DSwapChain9 *swapchain; | |
| D3DLOCKED_RECT lr; | |
| DXERROR(DXDev->GetSwapChain(0,&swapchain)); | |
| DXERROR(swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&backbuffer)); | |
| DXERROR(backbuffer->LockRect(&lr,0,0)); | |
| swapchain->Release(); | |
| backbuffer->Release(); | |
| *buffer = (sU32 *) lr.pBits; | |
| stride = lr.Pitch; | |
| } | |
| void sSystem_::End2D() | |
| { | |
| IDirect3DSurface9 *backbuffer; | |
| IDirect3DSwapChain9 *swapchain; | |
| DXERROR(DXDev->GetSwapChain(0,&swapchain)); | |
| DXERROR(swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&backbuffer)); | |
| DXERROR(backbuffer->UnlockRect()); | |
| swapchain->Release(); | |
| backbuffer->Release(); | |
| } | |
| void sSystem_::GetTransform(sInt mode,sMatrix &mat) | |
| { | |
| switch(mode) | |
| { | |
| case sGT_VIEW: | |
| mat = LastCamera; | |
| break; | |
| case sGT_MODELVIEW: | |
| mat = LastMatrix; | |
| mat.TransR(); | |
| mat.MulA(mat,LastCamera); | |
| break; | |
| case sGT_MODEL: | |
| mat = LastMatrix; | |
| break; | |
| case sGT_PROJECT: | |
| mat = LastProjection; | |
| break; | |
| default: | |
| mat.Init(); | |
| break; | |
| } | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| sInt sSystem_::AddTexture(const sTexInfo &ti) | |
| { | |
| sInt i; | |
| sHardTex *tex; | |
| tex = Textures; | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| { | |
| if(tex->Flags==0) | |
| { | |
| tex->RefCount = 1; | |
| tex->XSize = ti.XSize; | |
| tex->YSize = ti.YSize; | |
| tex->Flags = ti.Flags|sTIF_ALLOCATED; | |
| tex->Format = sTF_A8R8G8B8; | |
| tex->Tex = 0; | |
| tex->Shadow = 0; | |
| if(tex->Flags & sTIF_RENDERTARGET) | |
| { | |
| if(tex->XSize==0) | |
| { | |
| tex->XSize = Screen[0].XSize; | |
| tex->YSize = Screen[0].YSize; | |
| } | |
| #if LOGGING | |
| sDPrintF("Create Rendertarget %dx%d\n",tex->XSize,tex->YSize); | |
| #endif | |
| #ifdef _DOPE | |
| TexMemAlloc += tex->XSize * tex->YSize * 4; | |
| #endif | |
| DXERROR(DXDev->CreateTexture(tex->XSize,tex->YSize,1,D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&tex->Tex,0)); | |
| #if !sINTRO | |
| ReCreateZBuffer(); | |
| #endif | |
| } | |
| else | |
| { | |
| #if LOGGING | |
| sDPrintF("Create Texture %dx%d\n",tex->XSize,tex->YSize); | |
| #endif | |
| #ifdef _DOPE | |
| TexMemAlloc += tex->XSize * tex->YSize * 4 * 4 / 3; | |
| #endif | |
| sInt mipCount = 0; | |
| // non-power-of-2 | |
| if((tex->XSize & (tex->XSize-1)) || (tex->YSize & (tex->YSize-1))) | |
| mipCount = 1; | |
| DXERROR(DXDev->CreateTexture(tex->XSize,tex->YSize,mipCount,0,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,&tex->Tex,0)); | |
| UpdateTexture(i,ti.Bitmap); | |
| } | |
| return i; | |
| } | |
| tex++; | |
| } | |
| return sINVALID; | |
| } | |
| sInt sSystem_::AddTexture(sInt xs,sInt ys,sInt formatParm,sU16 *data,sInt mipcount,sInt miptresh) | |
| { | |
| sInt i; | |
| sHardTex *tex; | |
| #if sUSE_SHADERS | |
| static D3DFORMAT formats[] = | |
| { | |
| D3DFMT_UNKNOWN, | |
| D3DFMT_A8R8G8B8, | |
| D3DFMT_A8, | |
| D3DFMT_R16F, | |
| D3DFMT_A2R10G10B10, | |
| D3DFMT_Q8W8V8U8, | |
| D3DFMT_A2W10V10U10, | |
| D3DFMT_A1R5G5B5, | |
| D3DFMT_DXT1, | |
| D3DFMT_DXT5, | |
| D3DFMT_R32F, | |
| D3DFMT_L8, | |
| D3DFMT_A8L8, | |
| }; | |
| #else | |
| static D3DFORMAT formats[] = | |
| { | |
| D3DFMT_UNKNOWN, | |
| D3DFMT_A8R8G8B8, | |
| D3DFMT_A8, | |
| D3DFMT_A8R8G8B8, | |
| D3DFMT_A8R8G8B8, | |
| D3DFMT_A8R8G8B8, | |
| D3DFMT_A8R8G8B8, | |
| D3DFMT_A1R5G5B5, | |
| D3DFMT_DXT1, | |
| D3DFMT_DXT5, | |
| D3DFMT_R32F, | |
| D3DFMT_L8, | |
| D3DFMT_A8L8, | |
| }; | |
| #endif | |
| sInt format = formatParm & 0xff; | |
| sVERIFY(format>0 && format<sTF_MAX); | |
| tex = Textures; | |
| for(i=0;i<MAX_TEXTURE;i++) | |
| { | |
| if(tex->Flags==0) | |
| { | |
| mipcount = sMin(mipcount,sGetPower2(xs)); | |
| mipcount = sMin(mipcount,sGetPower2(ys)); | |
| if(xs & (xs-1) || ys & (ys-1)) // xs/ys not a power of 2? no mips. | |
| mipcount = 1; | |
| tex->RefCount = 1; | |
| tex->XSize = xs; | |
| tex->YSize = ys; | |
| tex->Flags = sTIF_ALLOCATED; | |
| tex->Format = format; | |
| tex->MipLevels = mipcount; | |
| tex->Tex = 0; | |
| tex->Shadow = 0; | |
| if(formatParm & sTF_NEEDEXTRAZ) | |
| tex->Flags |= sTIF_NEEDEXTRAZ; | |
| if(data==0) | |
| { | |
| if(tex->XSize==0) | |
| { | |
| tex->XSize = Screen[0].XSize; | |
| tex->YSize = Screen[0].YSize; | |
| } | |
| if(CmdNoRt) | |
| tex->XSize = tex->YSize = 4; | |
| tex->Flags |= sTIF_RENDERTARGET; | |
| #if LOGGINGT | |
| sDPrintF("Create Rendertarget %dx%d\n",tex->XSize,tex->YSize); | |
| #endif | |
| #ifdef _DOPE | |
| TexMemAlloc += tex->XSize * tex->YSize * 4; | |
| #endif | |
| DXDev->EvictManagedResources(); | |
| DXERROR(DXDev->CreateTexture(tex->XSize,tex->YSize,1,D3DUSAGE_RENDERTARGET,formats[format],D3DPOOL_DEFAULT,&tex->Tex,0)); | |
| if(tex->Flags & sTIF_NEEDEXTRAZ) | |
| DXERROR(DXDev->CreateDepthStencilSurface(tex->XSize,tex->YSize,D3DFMT_D24S8,D3DMULTISAMPLE_NONE,0,TRUE,&tex->Shadow,0)); | |
| /*if(MultiSampleType) | |
| { | |
| DXERROR(DXDev->CreateRenderTarget(tex->XSize,tex->YSize,formats[format],MultiSampleType,MultiSampleQuality,FALSE,&tex->Shadow,0)); | |
| }*/ | |
| #if !sINTRO | |
| ReCreateZBuffer(); | |
| #endif | |
| } | |
| else | |
| { | |
| #if LOGGING | |
| sDPrintF("Create Texture %dx%d\n",tex->XSize,tex->YSize); | |
| #endif | |
| #ifdef _DOPE | |
| TexMemAlloc += tex->XSize * tex->YSize * 4 * 4 / 3; | |
| #endif | |
| DXERROR(DXDev->CreateTexture(tex->XSize,tex->YSize,mipcount,0,formats[format],D3DPOOL_MANAGED,&tex->Tex,0)); | |
| UpdateTexture(i,data,miptresh); | |
| } | |
| return i; | |
| } | |
| tex++; | |
| } | |
| return sINVALID; | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::AddRefTexture(sInt handle) | |
| { | |
| // sHardTex *tex; | |
| if(handle!=sINVALID) | |
| { | |
| sVERIFY(handle>=0 && handle<MAX_TEXTURE); | |
| sVERIFY(Textures[handle].RefCount>0); | |
| Textures[handle].RefCount++; | |
| } | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::RemTexture(sInt handle) | |
| { | |
| sHardTex *tex; | |
| if(handle!=sINVALID) | |
| { | |
| sVERIFY(handle>=0 && handle<MAX_TEXTURE); | |
| tex = &Textures[handle]; | |
| sVERIFY(tex->RefCount>=1); | |
| tex->RefCount--; | |
| if(tex->RefCount==0) | |
| { | |
| // if we delete a texture that was the current rendertarget, | |
| // make sure we reset the viewport | |
| if(CurrentTarget == handle) | |
| { | |
| sViewport vp; | |
| vp.Init(); | |
| SetViewport(vp); | |
| } | |
| sRelease(tex->Tex); | |
| sRelease(tex->Shadow); | |
| tex->Flags = 0; | |
| } | |
| } | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::GetTextureSize(sInt handle,sInt &w,sInt &h) | |
| { | |
| if(handle != sINVALID) | |
| { | |
| sVERIFY(handle>=0 && handle<MAX_TEXTURE); | |
| sHardTex *tex = &Textures[handle]; | |
| sVERIFY(tex->RefCount >= 1); | |
| w = tex->XSize; | |
| h = tex->YSize; | |
| } | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::MakeCubeNormalizer() | |
| { | |
| const sInt size = 64; | |
| sInt i,x,y; | |
| D3DLOCKED_RECT lr; | |
| sU8 *p; | |
| sVector v; | |
| static sVector faces[6][2] = | |
| { | |
| {{ 0, 0,-1},{ 0, 1, 0}}, | |
| {{ 0, 0, 1},{ 0, 1, 0}}, | |
| {{ 1, 0, 0},{ 0, 0,-1}}, | |
| {{ 1, 0, 0},{ 0, 0, 1}}, | |
| {{ 1, 0, 0},{ 0, 1, 0}}, | |
| {{-1, 0, 0},{ 0, 1, 0}} | |
| }; | |
| DXERROR(DXDev->CreateCubeTexture(size,1,0,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,&DXNormalCube,0)); | |
| for(i=0;i<6;i++) | |
| { | |
| DXERROR(DXNormalCube->LockRect((D3DCUBEMAP_FACES)i,0,&lr,0,0)); | |
| for(y=0;y<size;y++) | |
| { | |
| p = ((sU8*)lr.pBits)+y*lr.Pitch; | |
| for(x=0;x<size;x++) | |
| { | |
| v.Cross3(faces[i][0],faces[i][1]); | |
| v.Scale3((size-1)*0.5f); | |
| v.AddScale3(faces[i][0],(x-(size-1)*0.5f)); | |
| v.AddScale3(faces[i][1],(-y+(size-1)*0.5f)); | |
| v.Unit3(); | |
| p[0] = sFtol(128.0f+v.z*127); | |
| p[1] = sFtol(128.0f+v.y*127); | |
| p[2] = sFtol(128.0f+v.x*127); | |
| p[3] = 0; | |
| p+=4; | |
| } | |
| } | |
| DXERROR(DXNormalCube->UnlockRect((D3DCUBEMAP_FACES)i,0)); | |
| } | |
| DXERROR(DXDev->CreateCubeTexture(1,1,0,D3DFMT_Q8W8V8U8,D3DPOOL_MANAGED,&DXTinyNormalCube,0)); | |
| for(i=0;i<6;i++) | |
| { | |
| DXERROR(DXTinyNormalCube->LockRect((D3DCUBEMAP_FACES)i,0,&lr,0,0)); | |
| p = (sU8 *) lr.pBits; | |
| p[0] = p[1] = p[2] = 0; | |
| p[3] = 127; | |
| p[i/2] = (i&1) ? 127 : -128; | |
| DXERROR(DXTinyNormalCube->UnlockRect((D3DCUBEMAP_FACES)i,0)); | |
| } | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::MakeAttenuationVolume() | |
| { | |
| const sInt size = 32; | |
| const sF32 scale = 2.0f / (size - 2.0f); | |
| const sF32 mid = size / 2.0f; | |
| D3DLOCKED_BOX lb; | |
| sInt x,y,z; | |
| sVector v; | |
| sF32 attn; | |
| sU8 *p; | |
| DXERROR(DXDev->CreateVolumeTexture(size,size,size,1,0,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,&DXAttenuationVolume,0)); | |
| DXERROR(DXAttenuationVolume->LockBox(0,&lb,0,0)); | |
| for(z=0;z<size;z++) | |
| { | |
| v.z = (z - mid) * scale; | |
| for(y=0;y<size;y++) | |
| { | |
| v.y = (y - mid) * scale; | |
| p = ((sU8 *)lb.pBits)+z*lb.SlicePitch+y*lb.RowPitch; | |
| for(x=0;x<size;x++) | |
| { | |
| v.x = (x - mid) * scale; | |
| attn = sMax(1.0f - v.Dot3(v),0.0f); | |
| p[0] = p[1] = p[2] = p[3] = sFtol(attn * 255); | |
| p += 4; | |
| } | |
| } | |
| } | |
| DXERROR(DXAttenuationVolume->UnlockBox(0)); | |
| } | |
| /****************************************************************************/ | |
| sBool sSystem_::StreamTextureStart(sInt handle,sInt level,sBitmapLock &lock) | |
| { | |
| sHardTex *tex; | |
| IDirect3DTexture9 *mst; | |
| D3DLOCKED_RECT dxlock; | |
| tex = &Textures[handle]; | |
| mst = tex->Tex; | |
| sVERIFY(!DXStreamTexture); | |
| DXStreamTexture = mst; | |
| DXStreamLevel = level; | |
| if(FAILED(mst->LockRect(level,&dxlock,0,0))) | |
| return sFALSE; | |
| lock.Data = (sU8 *)dxlock.pBits; | |
| lock.XSize = tex->XSize>>level; | |
| lock.YSize = tex->YSize>>level; | |
| lock.Kind = tex->Format; | |
| lock.BPR = dxlock.Pitch; | |
| return sTRUE; | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::StreamTextureEnd() | |
| { | |
| sVERIFY(DXStreamTexture); | |
| DXStreamTexture->UnlockRect(DXStreamLevel); | |
| DXStreamTexture=0; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| void sSystem_::SetStates(sU32 *stream) | |
| { | |
| // DXDev->SetPixelShader(0); | |
| // DXDev->SetVertexShader(0); | |
| while(*stream!=0xffffffff) | |
| { | |
| if(CurrentStates[stream[0]] != stream[1]) | |
| { | |
| SetState(stream[0],stream[1]); | |
| CurrentStates[stream[0]] = stream[1]; | |
| } | |
| stream+=2; | |
| } | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::SetState(sU32 token,sU32 value) | |
| { | |
| if(CurrentStates[token] == value) | |
| return; | |
| if(token<0x0310) | |
| { | |
| if(token<0x0100) | |
| { | |
| DXDev->SetRenderState((D3DRENDERSTATETYPE)token,value); | |
| } | |
| else if(token<0x0200) | |
| { | |
| DXDev->SetTextureStageState(((token>>5)&7),(D3DTEXTURESTAGESTATETYPE)(token&31),value); | |
| } | |
| else if(token<0x0300) | |
| { | |
| DXDev->SetSamplerState(((token>>4)&15),(D3DSAMPLERSTATETYPE)(token&15),value); | |
| } | |
| else if(token<0x0310) | |
| { | |
| DXDev->SetSamplerState(D3DDMAPSAMPLER,(D3DSAMPLERSTATETYPE)(token&15),value); | |
| } | |
| } | |
| CurrentStates[token] = value; | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::SetScissor(const sFRect *scissor) | |
| { | |
| RECT rc; | |
| if(!scissor) | |
| SetState(sD3DRS_SCISSORTESTENABLE,0); | |
| else | |
| { | |
| rc.left = CurrentViewport.Window.x0 + (CurrentViewport.Window.x1 - CurrentViewport.Window.x0) * (1.0f + scissor->x0) * 0.5f; | |
| rc.right = CurrentViewport.Window.x0 + (CurrentViewport.Window.x1 - CurrentViewport.Window.x0) * (1.0f + scissor->x1) * 0.5f; | |
| rc.top = CurrentViewport.Window.y0 + (CurrentViewport.Window.y1 - CurrentViewport.Window.y0) * (1.0f - scissor->y1) * 0.5f; | |
| rc.bottom = CurrentViewport.Window.y0 + (CurrentViewport.Window.y1 - CurrentViewport.Window.y0) * (1.0f - scissor->y0) * 0.5f; | |
| DXDev->SetScissorRect(&rc); | |
| SetState(sD3DRS_SCISSORTESTENABLE,1); | |
| } | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| void sSystem_::CreateGeoBuffer(sInt i,sInt dyn,sInt index,sInt size) | |
| { | |
| sInt usage; | |
| D3DPOOL pool; | |
| sVERIFY(dyn==0 || dyn==1); | |
| sVERIFY(index>=0 || index<=2); | |
| GeoBuffer[i].Type = 1+index; | |
| GeoBuffer[i].Size = size; | |
| GeoBuffer[i].Used = 0; | |
| GeoBuffer[i].UserCount = 0; | |
| GeoBuffer[i].VB = 0; | |
| usage = D3DUSAGE_WRITEONLY; | |
| pool = D3DPOOL_MANAGED; | |
| if(dyn) | |
| { | |
| usage |= D3DUSAGE_DYNAMIC; | |
| pool = D3DPOOL_DEFAULT; | |
| } | |
| if(!index) | |
| { | |
| DXERROR(DXDev->CreateVertexBuffer(size,usage,0,pool,&GeoBuffer[i].VB,0)); | |
| } | |
| else | |
| { | |
| DXERROR(DXDev->CreateIndexBuffer(size,usage,index == 1 ? D3DFMT_INDEX16 : D3DFMT_INDEX32,pool,&GeoBuffer[i].IB,0)); | |
| } | |
| #if LOGGING | |
| sDPrintF("Create %s %s-Buffer (%d bytes) id %d\n",dyn?"dynamic":"static",index?"index":"vertex",size,i); | |
| #endif | |
| #ifdef _DOPE | |
| BufferMemAlloc += size; | |
| #endif | |
| } | |
| sInt sSystem_::GeoAdd(sInt fvf,sInt prim) | |
| { | |
| sInt i; | |
| sGeoHandle *gh; | |
| sVERIFY(fvf>=1 && fvf<FVFMax); | |
| for(i=1;i<MAX_GEOHANDLE;i++) | |
| { | |
| gh = &GeoHandle[i]; | |
| if(gh->Mode==0) | |
| { | |
| sSetMem(gh,0,sizeof(*gh)); | |
| gh->VertexSize = FVFTable[fvf].Size; | |
| gh->FVF = fvf; | |
| gh->Mode = prim; | |
| gh->Locked = 0; | |
| return i; | |
| } | |
| } | |
| sFatal("GeoAdd() ran out of handles"); | |
| return 0; | |
| } | |
| void sSystem_::GeoRem(sInt handle) | |
| { | |
| sVERIFY(handle>=1 && handle<MAX_GEOHANDLE); | |
| sVERIFY(GeoHandle[handle].Mode!=0); | |
| if(GeoHandle[handle].Vertex.Buffer>=4) | |
| GeoBuffer[GeoHandle[handle].Vertex.Buffer].Free(); | |
| if(GeoHandle[handle].Index.Buffer>=4) | |
| GeoBuffer[GeoHandle[handle].Index.Buffer].Free(); | |
| GeoHandle[handle].Mode = 0; | |
| } | |
| void sSystem_::GeoFlush() | |
| { | |
| sInt i; | |
| for(i=1;i<MAX_GEOHANDLE;i++) | |
| GeoHandle[i].Vertex.Count = 0; | |
| for(i=3;i<MAX_GEOBUFFER;i++) | |
| { | |
| if(GeoBuffer[i].VB) | |
| GeoBuffer[i].VB->Release(); | |
| GeoBuffer[i].Init(); | |
| } | |
| } | |
| void sSystem_::GeoFlush(sInt handle,sInt what) | |
| { | |
| sVERIFY(handle>=1 && handle<MAX_GEOHANDLE); | |
| if(what & sGEO_VERTEX) GeoHandle[handle].Vertex.DiscardCount = 0; | |
| if(what & sGEO_INDEX) GeoHandle[handle].Index.DiscardCount = 0; | |
| } | |
| sInt sSystem_::GeoDraw(sInt &handle,sInt drawCount) | |
| { | |
| sGeoHandle *gh; | |
| D3DPRIMITIVETYPE mode; | |
| sInt count; | |
| sInt update; | |
| // buffer correctly loaded? | |
| sVERIFY(handle>=1 && handle<MAX_GEOHANDLE); | |
| sVERIFY(GeoHandle[handle].Mode!=0); | |
| gh = &GeoHandle[handle]; | |
| update = 0; | |
| if(gh->Vertex.Count == 0) | |
| update |= sGEO_VERTEX | sGEO_INDEX; | |
| if(gh->Vertex.Buffer == 0 && gh->Vertex.DiscardCount != DiscardCount[0]) | |
| update |= sGEO_VERTEX; | |
| if(gh->Index.Buffer == 1 && gh->Index.DiscardCount != DiscardCount[1]) | |
| update |= sGEO_INDEX; | |
| if(gh->Index.Buffer == 2 && gh->Index.DiscardCount != DiscardCount[2]) | |
| update |= sGEO_INDEX; | |
| if(update) | |
| return update; | |
| // set up buffers | |
| if(gh->FVF != LastDecl) | |
| { | |
| DXDev->SetVertexDeclaration(FVFTable[gh->FVF].Decl); | |
| LastDecl = gh->FVF; | |
| } | |
| if(gh->Index.Count && LastIB != gh->Index.Buffer) | |
| { | |
| sInt ib = gh->Index.Buffer; | |
| sVERIFY(ib>=0 && ib<MAX_GEOBUFFER); | |
| sVERIFY(GeoBuffer[ib].Type >= 2 && GeoBuffer[ib].Type <= 3); | |
| sVERIFY(GeoBuffer[ib].IB); | |
| DXDev->SetIndices(GeoBuffer[ib].IB); | |
| LastIB = ib; | |
| } | |
| if(LastVB != gh->Vertex.Buffer || LastVSize != gh->VertexSize) | |
| { | |
| sInt vb = gh->Vertex.Buffer; | |
| sVERIFY(vb>=0 && vb<MAX_GEOBUFFER); | |
| sVERIFY(GeoBuffer[vb].Type == 1); | |
| sVERIFY(GeoBuffer[vb].VB); | |
| DXDev->SetStreamSource(0,GeoBuffer[vb].VB,0,gh->VertexSize); | |
| LastVB = vb; | |
| LastVSize = gh->VertexSize; | |
| } | |
| // start drawing | |
| count = drawCount ? drawCount : gh->Index.Count; | |
| if(count == 0) | |
| count = gh->Vertex.Count; | |
| #if !sINTRO | |
| PerfThis.Vertex += gh->Vertex.Count; | |
| PerfThis.Batches++; | |
| #endif | |
| switch(gh->Mode&7) | |
| { | |
| case sGEO_POINT: | |
| mode = D3DPT_POINTLIST; | |
| count = count; | |
| sVERIFY(gh->Index.Count==0); | |
| break; | |
| case sGEO_LINE: | |
| mode = D3DPT_LINELIST; | |
| count = count/2; | |
| #if !sINTRO | |
| PerfThis.Line += count; | |
| #endif | |
| break; | |
| case sGEO_LINESTRIP: | |
| mode = D3DPT_LINESTRIP; | |
| count = count-1; | |
| #if !sINTRO | |
| PerfThis.Line += count; | |
| #endif | |
| break; | |
| case sGEO_TRI: | |
| mode = D3DPT_TRIANGLELIST; | |
| count = count/3; | |
| #if !sINTRO | |
| PerfThis.Triangle += count; | |
| #endif | |
| break; | |
| case sGEO_TRISTRIP: | |
| mode = D3DPT_TRIANGLESTRIP; | |
| count = count-2; | |
| #if !sINTRO | |
| PerfThis.Triangle += count; | |
| #endif | |
| break; | |
| case sGEO_QUAD: | |
| sVERIFY(gh->Index.Count==0); | |
| #if !sINTRO | |
| PerfThis.Triangle += count/2; | |
| #endif | |
| LastIB = 3; | |
| DXDev->SetIndices(GeoBuffer[3].IB); | |
| DXDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,gh->Vertex.Start,0,gh->Vertex.Count,0,count/4*2); | |
| return sFALSE; | |
| default: | |
| sVERIFYFALSE; | |
| } | |
| if(gh->Index.Count) | |
| DXDev->DrawIndexedPrimitive(mode,gh->Vertex.Start,0,gh->Vertex.Count,gh->Index.Start,count); | |
| else if(count) | |
| DXDev->DrawPrimitive(mode,gh->Vertex.Start,count); | |
| return sFALSE; | |
| } | |
| void sSystem_::AllocBufferInternal(sGeoBufferRef &ref,sInt size,sBool stat,sInt index,void **ptr) | |
| { | |
| sInt i,lockf; | |
| sBool ok; | |
| if(stat) // static buffer | |
| { | |
| for(i=4;i<MAX_GEOBUFFER;i++) | |
| if(GeoBuffer[i].Alloc(ref.Count,size,ref.Start,index+1)) | |
| break; | |
| if(i == MAX_GEOBUFFER) | |
| { | |
| for(i=4;i<MAX_GEOBUFFER;i++) | |
| { | |
| #pragma lekktor(off) | |
| if(GeoBuffer[i].Type == 0) | |
| { | |
| sInt bufSize = index ? MAX_DYNIBSIZE * index : MAX_DYNVBSIZE; | |
| if(bufSize < ref.Count * size) | |
| bufSize = ref.Count * size; | |
| CreateGeoBuffer(i,0,index,bufSize); | |
| ok = GeoBuffer[i].Alloc(ref.Count,size,ref.Start,index+1); | |
| sVERIFY(ok); | |
| break; | |
| #pragma lekktor(on) | |
| } | |
| } | |
| if(i == MAX_GEOBUFFER) | |
| sFatal("AllocInternal(): out of static geobuffers"); | |
| } | |
| ref.Buffer = i; | |
| lockf = 0; | |
| } | |
| else // dynamic buffer | |
| { | |
| ok = GeoBuffer[index].Alloc(ref.Count,size,ref.Start,index+1); | |
| ref.Buffer = index; | |
| if(!ok) | |
| { | |
| #pragma lekktor(off) | |
| GeoBuffer[index].Used = 0; | |
| DiscardCount[index]++; | |
| ok = GeoBuffer[index].Alloc(ref.Count,size,ref.Start,index+1); | |
| sVERIFY(ok); | |
| #pragma lekktor(on) | |
| } | |
| ref.DiscardCount = DiscardCount[index]; | |
| lockf = ref.Start ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD; | |
| } | |
| DXERROR(GeoBuffer[ref.Buffer].VB->Lock(ref.Start*size,ref.Count*size,(void **)ptr,lockf)); | |
| } | |
| // Compare two shaders, return length if equal. | |
| static sInt checkShadersEqual(const sU32 *sh1,const sU32 *sh2) | |
| { | |
| if(!sh1 && !sh2) | |
| return 1; | |
| if(!sh1 || !sh2) | |
| return 0; | |
| sInt i; | |
| for(i=0;sh1[i] == sh2[i] && sh1[i] != XO_END;i++); | |
| return sh1[i] == sh2[i] ? i + 1 : 0; | |
| } | |
| sInt sSystem_::GetShader(const sU32 *bytecode) | |
| { | |
| // search for matching shader | |
| sInt holePos = -1; | |
| for(sInt i=0;i<MAX_SHADERS;i++) | |
| { | |
| if(Shaders[i].RefCount) | |
| { | |
| if(checkShadersEqual(bytecode,Shaders[i].Code)) | |
| { | |
| Shaders[i].AddRef(); | |
| return i; | |
| } | |
| } | |
| else if(holePos == -1) | |
| holePos = i; | |
| } | |
| // need to add a new one | |
| sVERIFY(holePos != -1); | |
| sInt i = holePos; | |
| sInt len = checkShadersEqual(bytecode,bytecode); | |
| Shaders[i].RefCount = 1; | |
| if(bytecode) | |
| { | |
| Shaders[i].Code = new sU32[len]; | |
| sCopyMem(Shaders[i].Code,bytecode,len*4); | |
| } | |
| else | |
| Shaders[i].Code = 0; | |
| Shaders[i].Shader = 0; | |
| if(bytecode) | |
| { | |
| HRESULT hr; | |
| sU32 type = bytecode[0] >> 16; | |
| if(type == 0xfffe) // vertex shader | |
| hr = DXDev->CreateVertexShader((DWORD *) bytecode,(IDirect3DVertexShader9 **) &Shaders[i].Shader); | |
| else if(type == 0xffff) // pixel shader | |
| hr = DXDev->CreatePixelShader((DWORD *) bytecode,(IDirect3DPixelShader9 **) &Shaders[i].Shader); | |
| else | |
| sVERIFYFALSE; // invalid shader bytecode! | |
| #if !sPLAYER | |
| if(FAILED(hr)) | |
| PrintShader(bytecode); | |
| #endif | |
| } | |
| return i; | |
| } | |
| void sSystem_::GeoBegin(sInt handle,sInt vc,sInt ic,sF32 **fp,void **ip,sInt upd) | |
| { | |
| sGeoHandle *gh; | |
| sVERIFY(handle>=1 && handle<MAX_GEOHANDLE); | |
| sVERIFY(GeoHandle[handle].Mode!=0); | |
| sVERIFY(ic*2<=MAX_DYNIBSIZE); | |
| gh = &GeoHandle[handle]; | |
| if(fp) | |
| *fp = 0; | |
| if(ip) | |
| *ip = 0; | |
| if(upd & sGEO_VERTEX) | |
| { | |
| if(gh->Vertex.Buffer>=4) | |
| GeoBuffer[gh->Vertex.Buffer].Free(); | |
| gh->Vertex.Buffer = 0; | |
| gh->Vertex.Start = 0; | |
| gh->Vertex.Count = vc; | |
| AllocBufferInternal(gh->Vertex,gh->VertexSize,gh->Mode & sGEO_STATVB,0,(void **)fp); | |
| gh->Locked |= sGEO_VERTEX; | |
| sVERIFY(vc*GeoHandle[handle].VertexSize <= GeoBuffer[gh->Vertex.Buffer].Size); | |
| } | |
| if(upd & sGEO_INDEX) | |
| { | |
| if(gh->Index.Buffer>=4) | |
| GeoBuffer[gh->Index.Buffer].Free(); | |
| gh->Index.Buffer = 0; | |
| gh->Index.Start = 0; | |
| gh->Index.Count = ic; | |
| if(ic) | |
| { | |
| sBool is32b = (gh->Mode & sGEO_IND32B); | |
| AllocBufferInternal(gh->Index,is32b ? 4 : 2,gh->Mode & sGEO_STATIB,is32b ? 2 : 1,(void **)ip); | |
| gh->Locked |= sGEO_INDEX; | |
| } | |
| } | |
| } | |
| void sSystem_::GeoEnd(sInt handle,sInt vc,sInt ic) | |
| { | |
| sGeoHandle *gh; | |
| // sBool load; | |
| sVERIFY(handle>=1 && handle<MAX_GEOHANDLE); | |
| sVERIFY(GeoHandle[handle].Mode!=0); | |
| gh = &GeoHandle[handle]; | |
| if(gh->Locked & sGEO_VERTEX) | |
| { | |
| GeoBuffer[gh->Vertex.Buffer].VB->Unlock(); | |
| gh->Locked &= ~sGEO_VERTEX; | |
| } | |
| if(gh->Locked & sGEO_INDEX) | |
| { | |
| GeoBuffer[gh->Index.Buffer].IB->Unlock(); | |
| gh->Locked &= ~sGEO_INDEX; | |
| } | |
| if(vc!=-1) | |
| gh->Vertex.Count = vc; | |
| if(ic!=-1) | |
| gh->Index.Count = ic; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| #if !sINTRO | |
| sBool sSystem_::GetScreenInfo(sInt i,sScreenInfo &info) | |
| { | |
| if(i<0||i>=WScreenCount) | |
| { | |
| info.XSize = 0; | |
| info.YSize = 0; | |
| info.FullScreen = 0; | |
| info.ShaderLevel = sPS_00; | |
| info.LowQuality = 0; | |
| info.PixelRatio = 1; | |
| return sFALSE; | |
| } | |
| else | |
| { | |
| info.XSize = Screen[i].XSize; | |
| info.YSize = Screen[i].YSize; | |
| info.FullScreen = WFullscreen; | |
| info.ShaderLevel = CmdShaderLevel; | |
| info.LowQuality = CmdLowQuality; | |
| info.PixelRatio = 1.0f*Screen[i].XSize/Screen[i].YSize; | |
| return sTRUE; | |
| } | |
| } | |
| sInt sSystem_::GetScreenCount() | |
| { | |
| return WScreenCount; | |
| } | |
| sBool sSystem_::GetFullscreen() | |
| { | |
| return WFullscreen; | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| void sSystem_::FlushTexture(sInt handle) | |
| { | |
| sHardTex *tex; | |
| sVERIFY(handle>=0 && handle<MAX_TEXTURE); | |
| tex = &Textures[handle]; | |
| sVERIFY(tex->Flags); | |
| sRelease(tex->Tex); | |
| sRelease(tex->Shadow); | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::UpdateTexture(sInt handle,sBitmap *bm) | |
| { | |
| sHardTex *tex; | |
| sInt xs,ys,level; | |
| sInt miptresh; | |
| sInt mipdir; | |
| sInt filter; | |
| IDirect3DTexture9 *mst; | |
| D3DLOCKED_RECT dxlock; | |
| sInt x,y; | |
| sInt bpr,oxs; | |
| sU32 *d,*s,*data; | |
| sU8 *db,*sb; | |
| miptresh = 0; | |
| tex = &Textures[handle]; | |
| mst = tex->Tex; | |
| mipdir = miptresh & 16; | |
| miptresh = miptresh & 15; | |
| sVERIFY(bm->XSize == tex->XSize); | |
| sVERIFY(bm->YSize == tex->YSize); | |
| if(!(tex->Flags & sTIF_RENDERTARGET)) | |
| { | |
| xs = tex->XSize; | |
| ys = tex->YSize; | |
| oxs = xs; | |
| level = 0; | |
| data = new sU32[xs*ys]; | |
| sCopyMem4(data,bm->Data,xs*ys); | |
| { | |
| for(;;) | |
| { | |
| if(FAILED(mst->LockRect(level,&dxlock,0,0))) | |
| break; | |
| bpr = dxlock.Pitch; | |
| d = (sU32 *)dxlock.pBits; | |
| s = data; | |
| for(y=0;y<ys;y++) | |
| { | |
| sCopyMem4(d,s,xs); | |
| d+=bpr/4; | |
| s+=oxs; | |
| } | |
| mst->UnlockRect(level); | |
| if(xs<=1 || ys<=1 || (xs&(xs-1)) || (ys&(ys-1))) | |
| break; | |
| filter = (miptresh <= level); | |
| if(mipdir) filter = !filter; | |
| s = data; | |
| d = data; | |
| for(y=0;y<ys/2;y++) | |
| { | |
| sb = (sU8 *) s; | |
| db = (sU8 *) d; | |
| s+=oxs*2; | |
| d+=oxs; | |
| for(x=0;x<xs/2;x++) | |
| { | |
| if(filter) | |
| { | |
| db[0] = (sb[0]+sb[4]+sb[oxs*4+0]+sb[oxs*4+4]+2)>>2; | |
| db[1] = (sb[1]+sb[5]+sb[oxs*4+1]+sb[oxs*4+5]+2)>>2; | |
| db[2] = (sb[2]+sb[6]+sb[oxs*4+2]+sb[oxs*4+6]+2)>>2; | |
| db[3] = (sb[3]+sb[7]+sb[oxs*4+3]+sb[oxs*4+7]+2)>>2; | |
| } | |
| else | |
| { | |
| db[0] = sb[0]; | |
| db[1] = sb[1]; | |
| db[2] = sb[2]; | |
| db[3] = sb[3]; | |
| } | |
| db+=4; | |
| sb+=8; | |
| } | |
| } | |
| xs=xs>>1; | |
| ys=ys>>1; | |
| level++; | |
| } | |
| } | |
| delete[] data; | |
| } | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::UpdateTexture(sInt handle,sU16 *source,sInt miptresh) | |
| { | |
| sHardTex *tex; | |
| IDirect3DTexture9 *mst; | |
| D3DLOCKED_RECT dxlock; | |
| sInt xs,ys,level; | |
| sInt mipdir; | |
| sInt filter; | |
| sInt alpha; | |
| sInt dxtquality; | |
| sInt x,y; | |
| sInt bpr,oxs; | |
| sU32 *d,*s,*data; | |
| sU16 *d16,*s16; | |
| // sU8 *d8; | |
| mipdir = miptresh & 16; | |
| alpha = miptresh & 32; | |
| dxtquality = miptresh >> 6; | |
| miptresh = miptresh & 15; | |
| tex = &Textures[handle]; | |
| mst = tex->Tex; | |
| if(!(tex->Flags & sTIF_RENDERTARGET)) | |
| { | |
| xs = tex->XSize; | |
| ys = tex->YSize; | |
| oxs = xs; | |
| level = 0; | |
| data = new sU32[xs*ys*2]; | |
| sCopyMem4(data,(sU32 *)source,xs*ys*2); | |
| { | |
| for(;;) | |
| { | |
| if(FAILED(mst->LockRect(level,&dxlock,0,0))) | |
| break; | |
| bpr = dxlock.Pitch; | |
| d = (sU32 *)dxlock.pBits; | |
| s = data; | |
| #if sLINK_RYGDXT | |
| if(tex->Format==sTF_DXT1 || tex->Format==sTF_DXT5) | |
| { | |
| sU8 pixels[16*4]; | |
| sU32 block[4]; | |
| sInt shiftX = sGetPower2(oxs*4); | |
| s16 = (sU16 *) s; | |
| for(y=0;y<ys;y+=4) | |
| { | |
| for(x=0;x<xs;x+=4) | |
| { | |
| sU8 *dp = pixels; | |
| for(sInt yb=0;yb<4;yb++) | |
| { | |
| sU16 *sp = s16 + (((y+yb) & (ys-1))<<shiftX); | |
| for(sInt xb=0;xb<4;xb++) | |
| { | |
| sU16 *sr = sp + ((x+xb) & (xs-1))*4; | |
| dp[0] = (sr[0]>>7) & 0xff; | |
| dp[1] = (sr[1]>>7) & 0xff; | |
| dp[2] = (sr[2]>>7) & 0xff; | |
| dp[3] = (sr[3]>>7) & 0xff; | |
| dp += 4; | |
| } | |
| } | |
| sCompressDXTBlock((sU8 *) block,(sU32 *) pixels,tex->Format==sTF_DXT5,dxtquality); | |
| d[0] = block[0]; | |
| d[1] = block[1]; | |
| if(tex->Format == sTF_DXT1) | |
| d += 2; | |
| else | |
| { | |
| d[2] = block[2]; | |
| d[3] = block[3]; | |
| d += 4; | |
| } | |
| } | |
| } | |
| } | |
| else | |
| #endif | |
| if(tex->Format==sTF_A8) | |
| { | |
| sU8 *d8 = (sU8 *)d; | |
| for(y=0;y<ys;y++) | |
| { | |
| s16 = (sU16 *)s; | |
| for(x=0;x<xs;x++) | |
| { | |
| d8[x] = (s16[x*4+3]>>7)&0xff; | |
| } | |
| d8+=bpr; | |
| s+=oxs*2; | |
| } | |
| } | |
| else if(tex->Format==sTF_I8) | |
| { | |
| sU8 *d8 = (sU8 *)d; | |
| for(y=0;y<ys;y++) | |
| { | |
| s16 = (sU16 *)s; | |
| for(x=0;x<xs;x++) | |
| { | |
| d8[x] = (s16[x*4+1]>>7)&0xff; | |
| } | |
| d8+=bpr; | |
| s+=oxs*2; | |
| } | |
| } | |
| else if(tex->Format==sTF_A8I8) | |
| { | |
| sU8 *d8 = (sU8 *)d; | |
| for(y=0;y<ys;y++) | |
| { | |
| s16 = (sU16 *)s; | |
| for(x=0;x<xs;x++) | |
| { | |
| d8[x*2+0] = (s16[x*4+1]>>7)&0xff; | |
| d8[x*2+1] = (s16[x*4+3]>>7)&0xff; | |
| } | |
| d8+=bpr; | |
| s+=oxs*2; | |
| } | |
| } | |
| else | |
| { | |
| for(y=0;y<ys;y++) | |
| { | |
| if(tex->Format==sTF_Q8W8V8U8) | |
| { | |
| s16 = (sU16 *)s; | |
| for(x=0;x<xs;x++) | |
| { | |
| #if sINTRO | |
| d[x] = (((((sInt)s16[2]-0x4000)>>7)&0xff) ) | | |
| (((((sInt)s16[1]-0x4000)>>7)&0xff)<< 8) | | |
| (((((sInt)s16[0]-0x4000)>>7)&0xff)<<16) | | |
| (((((sInt)s16[3]-0x4000)>>7)&0xff)<<24); | |
| #else // more exact but bigger (and slower) version | |
| sVector v; | |
| v.x = s16[2] - 0x4000; | |
| v.y = s16[1] - 0x4000; | |
| v.z = s16[0] - 0x4000; | |
| v.UnitSafe3(); | |
| d[x] = ((sInt(v.x * 127.0f) & 0xff)<< 0) | | |
| ((sInt(v.y * 127.0f) & 0xff)<< 8) | | |
| ((sInt(v.z * 127.0f) & 0xff)<<16) | | |
| (((((sInt)s16[3]-0x4000)>>7)&0xff)<<24); | |
| #endif | |
| s16+=4; | |
| } | |
| } | |
| else | |
| { | |
| s16 = (sU16 *)s; | |
| for(x=0;x<xs;x++) | |
| { | |
| d[x] = (((s16[0]>>7)&0xff) ) | | |
| (((s16[1]>>7)&0xff)<< 8) | | |
| (((s16[2]>>7)&0xff)<<16) | | |
| (((s16[3]>>7)&0xff)<<24); | |
| s16+=4; | |
| } | |
| } | |
| d+=bpr/4; | |
| s+=oxs*2; | |
| } | |
| } | |
| mst->UnlockRect(level); | |
| if(xs<=1 || ys<=1 || (tex->MipLevels && level+1>=tex->MipLevels)) | |
| break; | |
| filter = (miptresh <= level); | |
| if(mipdir) filter = !filter; | |
| s = data; | |
| d = data; | |
| for(y=0;y<ys/2;y++) | |
| { | |
| s16 = (sU16 *) s; | |
| d16 = (sU16 *) d; | |
| s+=oxs*4; | |
| d+=oxs*2; | |
| for(x=0;x<xs/2;x++) | |
| { | |
| if(filter) | |
| { | |
| d16[0] = (s16[0]+s16[4]+s16[oxs*4+0]+s16[oxs*4+4]+2)>>2; | |
| d16[1] = (s16[1]+s16[5]+s16[oxs*4+1]+s16[oxs*4+5]+2)>>2; | |
| d16[2] = (s16[2]+s16[6]+s16[oxs*4+2]+s16[oxs*4+6]+2)>>2; | |
| d16[3] = (s16[3]+s16[7]+s16[oxs*4+3]+s16[oxs*4+7]+2)>>2; | |
| } | |
| else | |
| { | |
| d16[0] = s16[0]; | |
| d16[1] = s16[1]; | |
| d16[2] = s16[2]; | |
| d16[3] = s16[3]; | |
| } | |
| d16+=4; | |
| s16+=8; | |
| } | |
| } | |
| xs=xs>>1; | |
| ys=ys>>1; | |
| level++; | |
| } | |
| } | |
| delete[] data; | |
| } | |
| } | |
| void sSystem_::ReadTexture(sInt handle,sU16 *dest) | |
| { | |
| sHardTex *tex; | |
| IDirect3DTexture9 *mst; | |
| IDirect3DSurface9 *surf; | |
| IDirect3DSurface9 *rsurf; | |
| IDirect3DSurface9 *tsurf; | |
| D3DLOCKED_RECT dxlock; | |
| sInt xs,ys; | |
| sInt x,y; | |
| sInt bpr; | |
| sU32 *s; | |
| tex = &Textures[handle]; | |
| mst = tex->Tex; | |
| DXERROR(mst->GetSurfaceLevel(0,&tsurf)); | |
| DXERROR(DXDev->CreateRenderTarget(tex->XSize,tex->YSize,D3DFMT_A8R8G8B8,D3DMULTISAMPLE_NONE,0,0,&rsurf,0)); | |
| DXERROR(DXDev->CreateOffscreenPlainSurface(tex->XSize,tex->YSize,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&surf,0)); | |
| DXERROR(DXDev->StretchRect(tsurf,0,rsurf,0,D3DTEXF_NONE)); | |
| DXERROR(DXDev->GetRenderTargetData(rsurf,surf)); | |
| xs = tex->XSize; | |
| ys = tex->YSize; | |
| DXERROR(surf->LockRect(&dxlock,0,0)); | |
| bpr = dxlock.Pitch; | |
| s = (sU32 *)dxlock.pBits; | |
| for(y=0;y<ys;y++) | |
| { | |
| for(x=0;x<xs;x++) | |
| { | |
| sU32 val = s[x]; | |
| for(sInt i=0;i<4;i++) | |
| { | |
| sU32 bits = ((val>>(i*8))&255); | |
| dest[i] = (bits<<7) | (bits>>1); | |
| } | |
| dest+=4; | |
| } | |
| s+=bpr/4; | |
| } | |
| surf->UnlockRect(); | |
| sRelease(surf); | |
| sRelease(rsurf); | |
| sRelease(tsurf); | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Input ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| #if sUSE_DIRECTINPUT | |
| static IDirectInput8 *DXI; | |
| static IDirectInputDevice8 *DXIKey; | |
| static IDirectInputDevice8 *DXIMouse; | |
| static sInt WMouseX; | |
| static sInt WMouseY; | |
| static sInt DXIKeyFocus; | |
| static sInt DXIMouseFocus; | |
| #define MAX_KEYQUEUE 16 | |
| #define MAX_MOUSEQUEUE 64 | |
| //static sU32 KeyBuffer[MAX_KEYBUFFER]; | |
| //static sInt KeyIndex; | |
| //static sU32 KeyQual; | |
| static sU32 KeyDown[MAX_KEYQUEUE]; | |
| static sInt KeyDownIndex; | |
| static sU32 KeyMaps[3][256]; | |
| static sU32 KeyRepeat; | |
| static sU32 KeyRepeatTimer; | |
| static sU32 KeyRepeatDelay; | |
| static sU32 KeyRepeatRate; | |
| static sU32 KeyStickyMouseX; | |
| static sU32 KeyStickyMouseY; | |
| static sBool KeySticky; | |
| static sInt KeyStickyTime; | |
| static sU32 MouseX; | |
| static sU32 MouseY; | |
| static sU32 MouseZ; | |
| //static sU32 MouseButtons; | |
| //static sU32 MouseButtonsSave; | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| void sSystem_::AddAKey(sU32 *Scans,sInt ascii) | |
| { | |
| sInt j; | |
| sU32 scan,vkey; | |
| vkey = VkKeyScan(ascii); | |
| if(vkey!=-1) | |
| { | |
| scan = MapVirtualKey(vkey&0xff,0); | |
| for(j=0;j<256;j++) | |
| { | |
| if(Scans[j]==scan) | |
| { | |
| // sDPrintF("ASCII '%c' %02x -> VKey %04x -> Scan %02x -> DX %02x\n",ascii,ascii,vkey,scan,j); | |
| switch(vkey&0xff00) | |
| { | |
| case 0x0000: | |
| KeyMaps[0][j] = ascii; // normal | |
| break; | |
| case 0x0100: | |
| KeyMaps[1][j] = ascii; // shift | |
| break; | |
| case 0x0600: | |
| KeyMaps[2][j] = ascii; // alt-gr | |
| break; | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| /****************************************************************************/ | |
| sBool sSystem_::InitDI() | |
| { | |
| HRESULT hr; | |
| DIPROPDWORD prop; | |
| sU32 Scans[256]; | |
| sInt i; | |
| static sInt dkeys[][2] = | |
| { | |
| { DIK_BACK ,sKEY_BACKSPACE }, | |
| { DIK_TAB ,sKEY_TAB }, | |
| { DIK_RETURN ,sKEY_ENTER }, | |
| { DIK_ESCAPE ,sKEY_ESCAPE }, | |
| { DIK_UP ,sKEY_UP }, | |
| { DIK_DOWN ,sKEY_DOWN }, | |
| { DIK_LEFT ,sKEY_LEFT }, | |
| { DIK_RIGHT ,sKEY_RIGHT }, | |
| { DIK_PRIOR ,sKEY_PAGEUP }, | |
| { DIK_NEXT ,sKEY_PAGEDOWN }, | |
| { DIK_HOME ,sKEY_HOME }, | |
| { DIK_END ,sKEY_END }, | |
| { DIK_INSERT ,sKEY_INSERT }, | |
| { DIK_DELETE ,sKEY_DELETE }, | |
| { DIK_PAUSE ,sKEY_PAUSE }, | |
| { DIK_SCROLL ,sKEY_SCROLL }, | |
| { DIK_LWIN ,sKEY_WINL }, | |
| { DIK_RWIN ,sKEY_WINR }, | |
| { DIK_APPS ,sKEY_APPPOPUP }, | |
| { DIK_LSHIFT ,sKEY_SHIFTL }, | |
| { DIK_RSHIFT ,sKEY_SHIFTR }, | |
| { DIK_CAPITAL ,sKEY_CAPS }, | |
| { DIK_NUMLOCK ,sKEY_NUMLOCK }, | |
| { DIK_LCONTROL,sKEY_CTRLL }, | |
| { DIK_RCONTROL,sKEY_CTRLR }, | |
| { DIK_LMENU ,sKEY_ALT }, | |
| { DIK_RMENU ,sKEY_ALTGR }, | |
| { DIK_F1 ,sKEY_F1 }, | |
| { DIK_F2 ,sKEY_F2 }, | |
| { DIK_F3 ,sKEY_F3 }, | |
| { DIK_F4 ,sKEY_F4 }, | |
| { DIK_F5 ,sKEY_F5 }, | |
| { DIK_F6 ,sKEY_F6 }, | |
| { DIK_F7 ,sKEY_F7 }, | |
| { DIK_F8 ,sKEY_F8 }, | |
| { DIK_F9 ,sKEY_F9 }, | |
| { DIK_F10 ,sKEY_F10 }, | |
| { DIK_F11 ,sKEY_F11 }, | |
| { DIK_F12 ,sKEY_F12 }, | |
| { DIK_NUMPAD0 ,'0' }, | |
| { DIK_NUMPAD1 ,'1' }, | |
| { DIK_NUMPAD2 ,'2' }, | |
| { DIK_NUMPAD3 ,'3' }, | |
| { DIK_NUMPAD4 ,'4' }, | |
| { DIK_NUMPAD5 ,'5' }, | |
| { DIK_NUMPAD6 ,'6' }, | |
| { DIK_NUMPAD7 ,'7' }, | |
| { DIK_NUMPAD8 ,'8' }, | |
| { DIK_NUMPAD9 ,'9' }, | |
| { DIK_NUMPADENTER ,sKEY_ENTER }, | |
| { DIK_DECIMAL ,'.' }, | |
| { DIK_NUMPADCOMMA ,',' }, | |
| { DIK_DIVIDE ,'/' }, | |
| { DIK_MULTIPLY ,'*' }, | |
| { DIK_SUBTRACT ,'-' }, | |
| { DIK_ADD ,'+' }, | |
| { DIK_NUMPADEQUALS ,'=' }, | |
| { 0,0 } | |
| }; | |
| // set up direct input | |
| hr = (*DirectInput8CreateP)(WInst,DIRECTINPUT_VERSION,IID_IDirectInput8,(void**)&DXI,0); | |
| if(FAILED(hr)) return sFALSE; | |
| // set up keyboard | |
| hr = DXI->CreateDevice(GUID_SysKeyboard,&DXIKey,0); | |
| if(FAILED(hr)) return sFALSE; | |
| hr = DXIKey->SetDataFormat(&c_dfDIKeyboard); | |
| if(FAILED(hr)) return sFALSE; | |
| hr = DXIKey->SetCooperativeLevel((HWND)Screen[0].Window,DISCL_FOREGROUND|DISCL_NONEXCLUSIVE); | |
| if(FAILED(hr)) return sFALSE; | |
| prop.diph.dwSize = sizeof(DIPROPDWORD); | |
| prop.diph.dwHeaderSize = sizeof(DIPROPHEADER); | |
| prop.diph.dwObj = 0; | |
| prop.diph.dwHow = DIPH_DEVICE; | |
| prop.dwData = MAX_KEYQUEUE; | |
| hr = DXIKey->SetProperty(DIPROP_BUFFERSIZE,&prop.diph); | |
| if(FAILED(hr)) return sFALSE; | |
| // load keyboard mapping | |
| for(i=0;i<256;i++) | |
| { | |
| prop.diph.dwSize = sizeof(DIPROPDWORD); | |
| prop.diph.dwHeaderSize = sizeof(DIPROPHEADER); | |
| prop.diph.dwObj = i; | |
| prop.diph.dwHow = DIPH_BYOFFSET; | |
| prop.dwData = 0; | |
| DXIKey->GetProperty(DIPROP_SCANCODE,&prop.diph); | |
| Scans[i] = prop.dwData; | |
| } | |
| for(i=0;dkeys[i][0];i++) | |
| KeyMaps[0][dkeys[i][0]] = dkeys[i][1]; | |
| for(i=32;i<127;i++) | |
| AddAKey(Scans,i); | |
| for(i=160;i<256;i++) | |
| AddAKey(Scans,i); | |
| // init key tables | |
| KeyIndex = 0; | |
| KeyDownIndex = 0; | |
| KeyQual = 0; | |
| KeyRepeat = 0; | |
| KeyRepeatTimer = 0; | |
| KeyRepeatDelay = 200; | |
| KeyRepeatRate = 20; | |
| // start the keyboard | |
| hr = DXIKey->Acquire(); | |
| DXIKeyFocus = 1; | |
| // if(FAILED(hr)) return sFALSE; | |
| // create mouse | |
| hr = DXI->CreateDevice(GUID_SysMouse,&DXIMouse,0); | |
| if(FAILED(hr)) return sFALSE; | |
| hr = DXIMouse->SetDataFormat(&c_dfDIMouse); | |
| if(FAILED(hr)) return sFALSE; | |
| hr = DXIMouse->SetCooperativeLevel((HWND)Screen[0].Window,DISCL_FOREGROUND|DISCL_NONEXCLUSIVE); | |
| if(FAILED(hr)) return sFALSE; | |
| prop.diph.dwSize = sizeof(DIPROPDWORD); | |
| prop.diph.dwHeaderSize = sizeof(DIPROPHEADER); | |
| prop.diph.dwObj = 0; | |
| prop.diph.dwHow = DIPH_DEVICE; | |
| prop.dwData = MAX_MOUSEQUEUE; | |
| hr = DXIMouse->SetProperty(DIPROP_BUFFERSIZE,&prop.diph); | |
| if(FAILED(hr)) return sFALSE; | |
| // init mouse tables | |
| MouseX = 0; | |
| MouseY = 0; | |
| MouseZ = 0; | |
| MouseButtons = 0; | |
| MouseButtonsSave = 0; | |
| // start mouse | |
| hr = DXIMouse->Acquire(); | |
| DXIMouseFocus = 1; | |
| // if(FAILED(hr)) return sFALSE; | |
| return TRUE; | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::ExitDI() | |
| { | |
| if(DXIKey) | |
| { | |
| DXIKey->Unacquire(); | |
| DXIKey->Release(); | |
| DXIKey = 0; | |
| } | |
| if(DXIMouse) | |
| { | |
| DXIMouse->Unacquire(); | |
| DXIMouse->Release(); | |
| DXIMouse = 0; | |
| } | |
| RELEASE(DXI); | |
| } | |
| /****************************************************************************/ | |
| #pragma lekktor(off) | |
| void sSystem_::PollDI() | |
| { | |
| DIDEVICEOBJECTDATA data[MAX_MOUSEQUEUE]; | |
| DWORD count; | |
| HRESULT hr; | |
| sInt i; | |
| sU32 code; | |
| sU32 key; | |
| sU32 qual; | |
| sInt time; | |
| // check for window | |
| if(WActiveCount!=0) | |
| return; | |
| // get keys | |
| if(!DXIKeyFocus) | |
| { | |
| hr = DXIKey->Acquire(); | |
| if(!FAILED(hr)) | |
| DXIKeyFocus = 1; | |
| } | |
| if(DXIKeyFocus) | |
| { | |
| count = MAX_KEYQUEUE; | |
| hr = DXIKey->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),data,&count,0); | |
| if(hr==DIERR_INPUTLOST || hr==DIERR_NOTACQUIRED) | |
| { | |
| DXIKeyFocus = 0; | |
| for(i=0;i<KeyDownIndex;i++) | |
| { | |
| if(KeyIndex<MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = KeyDown[i] | sKEYQ_BREAK; | |
| } | |
| KeyDownIndex = 0; | |
| KeyQual = 0; | |
| KeyRepeat = 0; | |
| KeyRepeatTimer = 0; | |
| } | |
| } | |
| time = sSystem->GetTime(); | |
| if(DXIKeyFocus) | |
| { | |
| if(hr==DI_BUFFEROVERFLOW) | |
| { | |
| KeyQual=0; | |
| sDPrintF("Direct Input Buffer Overflow\n"); | |
| } | |
| if(!FAILED(hr)) | |
| { | |
| // done | |
| for(i=0;i<(sInt)count;i++) | |
| { | |
| if(i<(sInt)count-1) // direct input bugs | |
| { | |
| if((data[i].dwData&0x80) && (data[i+1].dwData&0x80)) | |
| { | |
| if(data[i].dwOfs==0x1d && data[i+1].dwOfs==0xb8) // altgr always comes with control | |
| continue; | |
| } | |
| /* | |
| if(!(data[i].dwData&0x80) && (data[i+1].dwData&0x80) && (data[i].dwOfs==0x36)) | |
| { | |
| if(data[i+1].dwOfs==0xc7 || data[i+1].dwOfs==0xc8 || data[i+1].dwOfs==0xc9 || data[i+1].dwOfs==0xcb || | |
| data[i+1].dwOfs==0xcd || data[i+1].dwOfs==0xcf || data[i+1].dwOfs==0xd0 || data[i+1].dwOfs==0xd1 || | |
| data[i+1].dwOfs==0xd2 || data[i+1].dwOfs==0xd3) | |
| { | |
| continue; | |
| } | |
| } | |
| */ | |
| } | |
| code = data[i].dwOfs&0xff; | |
| qual = sKEYQ_BREAK; | |
| if(data[i].dwData&0x80) | |
| qual = 0; | |
| key = KeyMaps[0][code]; | |
| if(key>=sKEY_SHIFTL && key<=sKEY_ALTGR) | |
| { | |
| if(qual&sKEYQ_BREAK) | |
| KeyQual &= ~(sKEYQ_SHIFTL<<(key-sKEY_SHIFTL)); | |
| else | |
| KeyQual |= (sKEYQ_SHIFTL<<(key-sKEY_SHIFTL)); | |
| } | |
| // sDPrintF("%02x %02x -> %08x\n",data[i].dwOfs,data[i].dwData,KeyQual); | |
| key = 0; | |
| if(KeyQual & sKEYQ_ALTGR) | |
| key = KeyMaps[2][code]; | |
| if(key == 0 && (KeyQual & sKEYQ_SHIFT)) | |
| key = KeyMaps[1][code]; | |
| if(key == 0) | |
| key = KeyMaps[0][code]; | |
| key |= KeyQual; | |
| key |= qual; | |
| if(key&sKEYQ_BREAK) | |
| { | |
| KeyRepeat = 0; | |
| KeyRepeatTimer = 0; | |
| if(sSystem->GetTime() - KeyStickyTime > 250) | |
| key |= sKEYQ_STICKYBREAK; | |
| for(sInt j=0;j<KeyDownIndex;j++) | |
| { | |
| if(KeyDown[j] == (key & ~(sKEYQ_BREAK | sKEYQ_STICKYBREAK))) | |
| { | |
| KeyDown[j] = KeyDown[--KeyDownIndex]; | |
| break; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| KeyRepeat = key; | |
| KeyRepeatTimer = time+KeyRepeatDelay; | |
| KeyStickyMouseX = MouseX; | |
| KeyStickyMouseY = MouseY; | |
| KeyStickyTime = sSystem->GetTime(); | |
| KeySticky = sTRUE; | |
| if(KeyDownIndex<MAX_KEYQUEUE) | |
| KeyDown[KeyDownIndex++] = key; | |
| } | |
| if(KeyIndex<MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = key; | |
| // sDPrintF("key %02x -> %08x '%c'\n",code,key,(key&0xff)>=32 ? key&0xff : '?'); | |
| } | |
| } | |
| } | |
| if(sAbs(KeyStickyMouseX-MouseX)+sAbs(KeyStickyMouseY-MouseY)>4) | |
| KeySticky = sFALSE; | |
| if(KeyRepeat!=0 && time>=(sInt)KeyRepeatTimer && KeyIndex<MAX_KEYBUFFER) | |
| { | |
| KeyBuffer[KeyIndex++] = KeyRepeat|sKEYQ_REPEAT; | |
| KeyRepeatTimer += KeyRepeatRate; | |
| if((sInt)KeyRepeatTimer<time) | |
| KeyRepeatTimer=time; | |
| } | |
| // get mouse | |
| if(!DXIMouseFocus) | |
| { | |
| hr = DXIMouse->Acquire(); | |
| if(!FAILED(hr)) | |
| DXIMouseFocus = 1; | |
| } | |
| if(DXIMouseFocus) | |
| { | |
| count = MAX_MOUSEQUEUE; | |
| hr = DXIMouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),data,&count,0); | |
| if(hr==DIERR_INPUTLOST || hr==DIERR_NOTACQUIRED) | |
| DXIMouseFocus = 0; | |
| } | |
| if(DXIMouseFocus) | |
| { | |
| if(!FAILED(hr)) | |
| { | |
| for(i=0;i<(sInt)count;i++) | |
| { | |
| switch(data[i].dwOfs) | |
| { | |
| case DIMOFS_X: | |
| MouseX += data[i].dwData; | |
| break; | |
| case DIMOFS_Y: | |
| MouseY += data[i].dwData; | |
| break; | |
| case DIMOFS_Z: | |
| MouseZ += data[i].dwData; | |
| break; | |
| /* | |
| case DIMOFS_BUTTON0: | |
| case DIMOFS_BUTTON1: | |
| case DIMOFS_BUTTON2: | |
| */ | |
| case DIMOFS_BUTTON3: | |
| case DIMOFS_BUTTON4: | |
| case DIMOFS_BUTTON5: | |
| case DIMOFS_BUTTON6: | |
| case DIMOFS_BUTTON7: | |
| key = (data[i].dwOfs-DIMOFS_BUTTON0); | |
| if(data[i].dwData&0x80) | |
| { | |
| MouseButtons |= (1<<key); | |
| MouseButtonsSave |= (1<<key); | |
| KeyQual |= (sKEYQ_MOUSEL<<key); | |
| if(KeyIndex < MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = (sKEY_MOUSEL+key)|KeyQual; | |
| } | |
| else | |
| { | |
| MouseButtons &= ~( (1<<key) | ((MouseButtons&8)?4:0) ); // buggy mouse driver fix | |
| KeyQual &= ~(sKEYQ_MOUSEL<<key); | |
| if(KeyIndex < MAX_KEYBUFFER) | |
| KeyBuffer[KeyIndex++] = (sKEY_MOUSEL+key)|KeyQual|sKEYQ_BREAK; | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| #pragma lekktor(on) | |
| #endif | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Windows User Interface Access ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| #if !sPLAYER | |
| const sChar *sSystem_::GetCommandLine() | |
| { | |
| return WFilename[0] ? WFilename : 0; | |
| } | |
| sBool sSystem_::FileRequester(sChar *buffer,sInt size,sU32 flags,const sChar *ext) | |
| { | |
| sChar oldpath[2048]; | |
| sChar extstring[2048]; | |
| OPENFILENAME ofn; | |
| sInt result=0; | |
| if(ext==0) | |
| { | |
| sCopyString(extstring,"All\0*.*\0",sCOUNTOF(extstring)); | |
| } | |
| else | |
| { | |
| sChar *d = extstring; | |
| const sChar *s = ext; | |
| while(*s) | |
| { | |
| while(*s && *s!=':') | |
| *d++ = *s++; | |
| *d++ = 0; | |
| if(*s==':') | |
| { | |
| sBool comma = 0; | |
| while(*s==':' || *s==',') | |
| { | |
| s++; | |
| if(comma) | |
| *d++ = ';'; | |
| *d++ = '*'; | |
| *d++ = '.'; | |
| while(*s && *s!=',' && *s!=';') | |
| *d++ = *s++; | |
| comma = 1; | |
| } | |
| if(*s==';') | |
| s++; | |
| } | |
| else | |
| { | |
| *d++ = '*'; | |
| *d++ = '.'; | |
| *d++ = '*'; | |
| } | |
| *d++ = 0; | |
| } | |
| *d++ = 0; | |
| } | |
| sSetMem(&ofn,0,sizeof(ofn)); | |
| ofn.lStructSize = sizeof(ofn); | |
| ofn.hwndOwner = (HWND) Screen[0].Window; | |
| ofn.lpstrFile = buffer; | |
| ofn.nMaxFile = size; | |
| ofn.lpstrFilter = extstring; | |
| ofn.nFilterIndex = 1; | |
| ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; | |
| if(!CheckFile(buffer) && !CheckDir(buffer)) | |
| buffer[0] = 0; | |
| GetCurrentDirectoryA(sCOUNTOF(oldpath),oldpath); | |
| switch(flags & sFRF_MODEMASK) | |
| { | |
| case sFRF_OPEN: | |
| result = GetOpenFileName(&ofn); | |
| break; | |
| case sFRF_SAVE: | |
| result = GetSaveFileName(&ofn); | |
| break; | |
| case sFRF_PATH: | |
| sVERIFYFALSE; | |
| break; | |
| } | |
| SetCurrentDirectoryA(oldpath); | |
| if(result) | |
| { | |
| sInt len = sGetStringLen(oldpath); | |
| if(sCmpMemI(oldpath,buffer,len)==0) | |
| { | |
| sChar b[2048]; | |
| sCopyString(b,".\\",2048); | |
| if(buffer[len]=='/' || buffer[len]=='\\') | |
| len++; | |
| sAppendString(b,buffer+len,2048); | |
| sCopyString(buffer,b,2048); | |
| } | |
| } | |
| return result; | |
| } | |
| sBool sSystem_::ExecuteShell(sChar *verb,sChar *file) | |
| { | |
| HINSTANCE inst = ShellExecute(0,verb,file,0,0,SW_SHOWNORMAL); | |
| return sDInt(inst)>32; | |
| } | |
| void sSystem_::SetClipboard(const sChar *text,sInt len) | |
| { | |
| OpenClipboard((HWND)Screen[0].Window); | |
| EmptyClipboard(); | |
| if(len==-1) | |
| len = sGetStringLen(text); | |
| sInt size = len+1; | |
| for(sInt i=0;text[i];i++) | |
| if(text[i]=='\n') | |
| size++; | |
| HANDLE hmem = GlobalAlloc(GMEM_MOVEABLE,size); | |
| sChar *d = (sChar *) GlobalLock(hmem); | |
| for(sInt i=0;i<len;i++) | |
| { | |
| if(text[i]=='\n') | |
| *d++ = '\r'; | |
| *d++ = text[i]; | |
| } | |
| *d++ = 0; | |
| GlobalUnlock(hmem); | |
| SetClipboardData(CF_TEXT,hmem); | |
| CloseClipboard(); | |
| } | |
| sChar *sSystem_::GetClipboard() | |
| { | |
| sChar *result=0; | |
| OpenClipboard((HWND)Screen[0].Window); | |
| HANDLE hmem = GetClipboardData(CF_TEXT); | |
| if(hmem) | |
| { | |
| sChar *s = (sChar *)GlobalLock(hmem); | |
| sInt size = sGetStringLen(s)+1; | |
| result = new sChar[size]; | |
| sInt i = 0; | |
| while(*s) | |
| { | |
| if(*s!='\r') | |
| result[i++] = *s; | |
| s++; | |
| } | |
| result[i++] = 0; | |
| GlobalUnlock(hmem); | |
| } | |
| else | |
| { | |
| result = new sChar[1]; | |
| result[0] = 0; | |
| } | |
| CloseClipboard(); | |
| return result; | |
| } | |
| void sSystem_::SetClipboard(sBitmap *bm) | |
| { | |
| OpenClipboard((HWND)Screen[0].Window); | |
| EmptyClipboard(); | |
| HBITMAP hbm = CreateBitmap(bm->XSize,bm->YSize,1,32,bm->Data); | |
| SetClipboardData(CF_BITMAP,hbm); | |
| CloseClipboard(); | |
| } | |
| static sInt ProgressGDIMax; | |
| static sInt ProgressGDITime; | |
| static sInt ProgressGDIValue; | |
| static sInt ProgressGDIActive; | |
| static sInt ProgressGDIAbort; | |
| void sSystem_::ProgressGDIStart(sInt max) | |
| { | |
| ProgressGDIMax = max; | |
| ProgressGDITime = GetTime()+500; | |
| ProgressGDIValue = 0; | |
| ProgressGDIActive = 0; | |
| ProgressGDIAbort = 0; | |
| ClearAbortKey(); | |
| } | |
| void sSystem_::ProgressGDIStop() | |
| { | |
| /*if(ProgressGDIValue!=0 || ProgressGDIMax!=0) | |
| sDPrintF("progress %d/%d\n",ProgressGDIValue,ProgressGDIMax);*/ | |
| if(ProgressGDIActive) | |
| { | |
| ProgressGDIValue = ProgressGDIMax; | |
| ProgressGDI(0); | |
| } | |
| ProgressGDIMax = 0; | |
| } | |
| sBool sSystem_::ProgressGDI(sInt increment) | |
| { | |
| ProgressGDIValue += increment; | |
| sInt max = ProgressGDIMax; | |
| if(max>3) | |
| { | |
| sInt value = ProgressGDIValue; | |
| sInt time = GetTime(); | |
| if(time>ProgressGDITime) | |
| { | |
| ProgressGDIAbort |= GetAbortKey(); | |
| HDC dc = GetDC((HWND)Screen[0].Window); | |
| HBRUSH br0 = CreateSolidBrush(RGB(0,0,0)); | |
| HBRUSH br1 = CreateSolidBrush(RGB(255,255,255)); | |
| sScreenInfo si; | |
| ProgressGDITime = time+500; | |
| ProgressGDIActive = 1; | |
| GetScreenInfo(0,si); | |
| sRect r,rr; | |
| sInt h; | |
| sInt w = 500; if(si.XSize<500) w = si.XSize; | |
| r.x0 = si.XSize/2-w/2; | |
| r.y0 = si.YSize/2-14; | |
| r.x1 = si.XSize/2+w/2; | |
| r.y1 = si.YSize/2+14; | |
| h = 2; | |
| rr.Init(r.x0,r.y0,r.x1,r.y0+h); | |
| FillRect(dc,(const RECT *)&rr,br0); | |
| rr.Init(r.x0,r.y1-h,r.x1,r.y1); | |
| FillRect(dc,(const RECT *)&rr,br0); | |
| rr.Init(r.x0,r.y0+h,r.x0+h,r.y1-h); | |
| FillRect(dc,(const RECT *)&rr,br0); | |
| rr.Init(r.x1-h,r.y0+h,r.x1,r.y1-h); | |
| FillRect(dc,(const RECT *)&rr,br0); | |
| r.Extend(-h); | |
| h = 2; | |
| rr.Init(r.x0,r.y0,r.x1,r.y0+h); | |
| FillRect(dc,(const RECT *)&rr,br1); | |
| rr.Init(r.x0,r.y1-h,r.x1,r.y1); | |
| FillRect(dc,(const RECT *)&rr,br1); | |
| rr.Init(r.x0,r.y0+h,r.x0+h,r.y1-h); | |
| FillRect(dc,(const RECT *)&rr,br1); | |
| rr.Init(r.x1-h,r.y0+h,r.x1,r.y1-h); | |
| FillRect(dc,(const RECT *)&rr,br1); | |
| r.Extend(-h); | |
| h = 2; | |
| rr.Init(r.x0,r.y0,r.x1,r.y0+h); | |
| FillRect(dc,(const RECT *)&rr,br0); | |
| rr.Init(r.x0,r.y1-h,r.x1,r.y1); | |
| FillRect(dc,(const RECT *)&rr,br0); | |
| rr.Init(r.x0,r.y0+h,r.x0+h,r.y1-h); | |
| FillRect(dc,(const RECT *)&rr,br0); | |
| rr.Init(r.x1-h,r.y0+h,r.x1,r.y1-h); | |
| FillRect(dc,(const RECT *)&rr,br0); | |
| r.Extend(-h); | |
| sInt x = r.x0 + sMulDiv(r.XSize(),value,max); | |
| rr = r; rr.x0 = x; | |
| FillRect(dc,(const RECT *)&rr,br0); | |
| rr = r; rr.x1 = x; | |
| FillRect(dc,(const RECT *)&rr,br1); | |
| DeleteObject(br0); | |
| DeleteObject(br1); | |
| ReleaseDC((HWND)Screen[0].Window,dc); | |
| } | |
| } | |
| return ProgressGDIAbort; | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Misc Input/Timing stuff ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| void sSystem_::GetInput(sInt id,sInputData &data) | |
| { | |
| #if !sUSE_DIRECTINPUT | |
| POINT pt; | |
| static sInt x,y; | |
| GetCursorPos(&pt); | |
| x += pt.x-400; | |
| y += pt.y-300; | |
| data.Analog[0]=x; | |
| data.Analog[1]=y; | |
| SetCursorPos(400,300); | |
| #else | |
| data.Type = sIDT_NONE; | |
| data.AnalogCount = 0; | |
| data.DigitalCount = 0; | |
| data.pad = 0; | |
| data.Analog[0] = 0; | |
| data.Analog[1] = 0; | |
| data.Analog[2] = 0; | |
| data.Analog[3] = 0; | |
| data.Digital = 0; | |
| if(id==0) | |
| { | |
| data.Type = sIDT_MOUSE; | |
| data.AnalogCount = 3; | |
| data.DigitalCount = 3; | |
| data.Analog[0] += MouseX; | |
| data.Analog[1] += MouseY; | |
| data.Analog[2] += MouseZ; | |
| data.Analog[3] = 0; | |
| data.Digital = MouseButtons | MouseButtonsSave; | |
| MouseButtonsSave = 0; | |
| } | |
| #endif | |
| } | |
| sInt sSystem_::GetTime() | |
| { | |
| return timeGetTime()-WStartTime; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| #if !sINTRO | |
| sU32 sSystem_::GetKeyboardShiftState() | |
| { | |
| return (KeyQual&0x7ffe0000); | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::GetKeyName(sChar *buffer,sInt size,sU32 key) | |
| { | |
| sU32 pure; | |
| sChar c2[2]; | |
| static sChar *names[] = | |
| { | |
| "UP","DOWN","LEFT","RIGHT", | |
| "PAGEUP","PAGEDOWN","HOME","END", | |
| "INSERT","DELETE",0,0, | |
| 0,0,0,0, | |
| "PAUSE","SCROLL","NUMLOCK","WINL", | |
| "WINR","APPS","CLOSE","SIZE", | |
| 0,0,0,0, | |
| 0,0,0,0, | |
| 0,"SHIFTL","SHIFTR","CAPS", | |
| "CTRLL","CTRLR","ALT","ALTGR", | |
| "MOUSEL","MOUSER","MOUSEM",0, | |
| 0,0,0,0, | |
| "F1","F2","F3","F4", | |
| "F5","F6","F7","F8", | |
| "F9","F10","F11","F12", | |
| 0,0,0,0, | |
| }; | |
| pure = key & 0x0001ffff; | |
| buffer[0] = 0; | |
| #pragma lekktor(off) | |
| if(key & sKEYQ_SHIFT) | |
| sAppendString(buffer,"SHIFT+",size); | |
| if(key & sKEYQ_CTRL) | |
| sAppendString(buffer,"CTRL+",size); | |
| if(key & sKEYQ_ALTGR) | |
| sAppendString(buffer,"ALTGR+",size); | |
| if(key & sKEYQ_ALT) | |
| sAppendString(buffer,"ALT+",size); | |
| #pragma lekktor(on) | |
| if((pure>=0x20 && pure<=0x7f) || (pure>=0xa0 && pure<0xff)) | |
| { | |
| c2[0] = pure; | |
| c2[1] = 0; | |
| sAppendString(buffer,c2,size); | |
| } | |
| else if(pure>=0x00010000 && pure<0x00010040 && names[pure&0x3f]) | |
| sAppendString(buffer,names[pure&0x3f],size); | |
| else if(pure==sKEY_BACKSPACE) | |
| sAppendString(buffer,"BACKSPACE",size); | |
| else if(pure==sKEY_TAB) | |
| sAppendString(buffer,"TAB",size); | |
| else if(pure==sKEY_ENTER) | |
| sAppendString(buffer,"ENTER",size); | |
| else if(pure==sKEY_ESCAPE) | |
| sAppendString(buffer,"ESCAPE",size); | |
| else | |
| sAppendString(buffer,"???",size); | |
| } | |
| /****************************************************************************/ | |
| sBool sSystem_::GetAbortKey() | |
| { | |
| #pragma lekktor(off) | |
| if(GetAsyncKeyState(VK_PAUSE)&1) | |
| WAbortKeyFlag = 1; | |
| #pragma lekktor(on) | |
| return WAbortKeyFlag; | |
| } | |
| void sSystem_::ClearAbortKey() | |
| { | |
| GetAbortKey(); | |
| WAbortKeyFlag = 0; | |
| } | |
| /****************************************************************************/ | |
| sInt sSystem_::GetTimeOfDay() | |
| { | |
| static SYSTEMTIME st; | |
| static sInt cache; | |
| sInt time; | |
| time = GetTime(); | |
| if(time>cache+500) | |
| { | |
| GetLocalTime(&st); | |
| cache = time; | |
| } | |
| return st.wSecond+st.wMinute*60+st.wHour*60*60; | |
| } | |
| static sU64 GetPreciseTimer() | |
| { | |
| sU64 time; | |
| if(SingleCore) | |
| { | |
| __asm | |
| { | |
| rdtsc; | |
| mov dword ptr [time], eax; | |
| mov dword ptr [time+4], edx; | |
| } | |
| } | |
| else | |
| QueryPerformanceCounter((LARGE_INTEGER *) &time); | |
| return time; | |
| } | |
| sU32 sSystem_::PerfTime() | |
| { | |
| return (GetPreciseTimer()-sPerfFrame)*sPerfKalibFactor; | |
| } | |
| void sSystem_::PerfKalib() | |
| { | |
| sU64 query; | |
| sU64 freq; | |
| sU64 time = GetPreciseTimer(); | |
| PerfLast.Time = (time-sPerfFrame)*sPerfKalibFactor; | |
| sPerfFrame = time; | |
| if(time-sPerfKalibRDTSC>1000*1000*1000) | |
| { | |
| QueryPerformanceCounter((LARGE_INTEGER *)&query); | |
| QueryPerformanceFrequency((LARGE_INTEGER *)&freq); | |
| sPerfKalibFactor = (((sF64)(query-sPerfKalibQuery))/freq) / ((sF64)(time-sPerfKalibRDTSC)) * 1000000; | |
| sPerfKalibRDTSC=0; | |
| } | |
| if(sPerfKalibRDTSC==0) | |
| { | |
| sPerfKalibRDTSC = time; | |
| QueryPerformanceCounter((LARGE_INTEGER *)&query); | |
| sPerfKalibQuery = query; | |
| } | |
| } | |
| void sSystem_::GetPerf(sPerfInfo &info,sInt mode) | |
| { | |
| switch(mode) | |
| { | |
| case sPIM_LAST: | |
| info = PerfLast; | |
| break; | |
| case sPIM_BEGIN: | |
| info = PerfThis; | |
| info.Time = PerfLast.Time; | |
| info.TimeFiltered = PerfLast.TimeFiltered; | |
| break; | |
| case sPIM_END: | |
| info.Line = PerfThis.Line - info.Line; | |
| info.Triangle = PerfThis.Triangle - info.Triangle; | |
| info.Vertex = PerfThis.Vertex - info.Vertex; | |
| info.Material = PerfThis.Material - info.Material; | |
| info.Batches = PerfThis.Batches - info.Batches; | |
| info.Time = PerfLast.Time; | |
| info.TimeFiltered = PerfLast.TimeFiltered; | |
| break; | |
| case sPIM_PAUSE: | |
| info.Line -= PerfThis.Line; | |
| info.Triangle -= PerfThis.Triangle; | |
| info.Vertex -= PerfThis.Vertex; | |
| info.Material -= PerfThis.Material; | |
| info.Batches -= PerfThis.Batches; | |
| break; | |
| case sPIM_CONTINUE: | |
| info.Line += PerfThis.Line; | |
| info.Triangle += PerfThis.Triangle; | |
| info.Vertex += PerfThis.Vertex; | |
| info.Material += PerfThis.Material; | |
| info.Batches += PerfThis.Batches; | |
| break; | |
| default: | |
| sFatal("sSystem_::GetPerf() unknown mode"); | |
| break; | |
| } | |
| } | |
| /****************************************************************************/ | |
| sBool sSystem_::GetWinMouse(sInt &x,sInt &y) | |
| { | |
| x = WMouseX; | |
| y = WMouseY; | |
| return sTRUE; | |
| } | |
| sBool sSystem_::GetWinMouseAbs(sInt &x,sInt &y) | |
| { | |
| POINT pt; | |
| GetCursorPos(&pt); | |
| x = pt.x; | |
| y = pt.y; | |
| return sTRUE; | |
| } | |
| void sSystem_::SetWinMouse(sInt x,sInt y) | |
| { | |
| RECT rc; | |
| GetWindowRect((HWND)Screen[0].Window,&rc); | |
| SetCursorPos(x+rc.left,y+rc.top); | |
| } | |
| void sSystem_::SetWinTitle(sChar *name) | |
| { | |
| SetWindowText((HWND)Screen[0].Window,name); | |
| } | |
| void sSystem_::MoveWindow(sInt dx,sInt dy) | |
| { | |
| RECT r; | |
| GetWindowRect((HWND)Screen[0].Window,&r); | |
| ::MoveWindow((HWND)Screen[0].Window,r.left+dx,r.top+dy,r.right-r.left,r.bottom-r.top,1); | |
| } | |
| void sSystem_::SetWinMode(sInt mode) | |
| { | |
| switch(mode) | |
| { | |
| case 0: | |
| WShow = SW_RESTORE; | |
| // ShowWindow((HWND)Screen[0].Window,SW_RESTORE); | |
| break; | |
| case 1: | |
| WShow = SW_MAXIMIZE; | |
| // ShowWindow((HWND)Screen[0].Window,SW_MAXIMIZE); | |
| break; | |
| case 2: | |
| WShow = SW_MINIMIZE; | |
| // ShowWindow((HWND)Screen[0].Window,SW_MINIMIZE); | |
| break; | |
| } | |
| } | |
| sInt sSystem_::GetWinMode() | |
| { | |
| if(IsIconic((HWND)Screen[0].Window)) return 2; | |
| if(IsZoomed((HWND)Screen[0].Window)) return 1; | |
| return 0; | |
| } | |
| void sSystem_::HideWinMouse(sBool hide) | |
| { | |
| if(hide) | |
| while(ShowCursor(0)>0); | |
| else | |
| ShowCursor(1); | |
| } | |
| /****************************************************************************/ | |
| #endif | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Sound ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| #pragma lekktor(off) | |
| static WAVEFORMATEX soundFormat = { | |
| WAVE_FORMAT_PCM, | |
| 2, | |
| 44100, | |
| 44100*4, | |
| 4, | |
| 16, | |
| 0 | |
| }; | |
| sBool sSystem_::InitDS() | |
| { | |
| DWORD count1,count2; | |
| void *pos1,*pos2; | |
| HRESULT hr; | |
| DSBUFFERDESC dsbd; | |
| IDirectSoundBuffer *sbuffer; | |
| timeBeginPeriod(1); | |
| hr = (*DirectSoundCreate8P)(0,&DXS,0); | |
| if(FAILED(hr)) return sFALSE; | |
| hr = DXS->SetCooperativeLevel((HWND)Screen[0].Window,DSSCL_PRIORITY); | |
| if(FAILED(hr)) return sFALSE; | |
| #if !sINTRO | |
| WINSET(dsbd); | |
| dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D; | |
| dsbd.dwBufferBytes = 0; | |
| dsbd.lpwfxFormat = 0; | |
| hr = DXS->CreateSoundBuffer(&dsbd,&DXSPrimary,0); | |
| if(FAILED(hr)) return sFALSE; | |
| hr = DXSPrimary->QueryInterface(IID_IDirectSound3DListener,(void **)&Listener); | |
| if(FAILED(hr)) return sFALSE; | |
| #else // no dsound3d support | |
| WINSET(dsbd); | |
| dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; | |
| dsbd.dwBufferBytes = 0; | |
| dsbd.lpwfxFormat = 0; | |
| hr = DXS->CreateSoundBuffer(&dsbd,&DXSPrimary,0); | |
| if(FAILED(hr)) return sFALSE; | |
| #endif | |
| DXSPrimary->SetFormat(&soundFormat); | |
| WINSET(dsbd); | |
| dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS; | |
| dsbd.dwBufferBytes = DXSSAMPLES*4; | |
| dsbd.lpwfxFormat = &soundFormat; | |
| hr = DXS->CreateSoundBuffer(&dsbd,&sbuffer,0); | |
| if(FAILED(hr)) return sFALSE; | |
| hr = sbuffer->QueryInterface(IID_IDirectSoundBuffer8,(void**)&DXSBuffer); | |
| sbuffer->Release(); | |
| if(FAILED(hr)) return sFALSE; | |
| hr = DXSBuffer->Lock(0,DXSSAMPLES*4,&pos1,&count1,&pos2,&count2,0); | |
| if(!FAILED(hr)) | |
| { | |
| sSetMem(pos1,0,count1); | |
| sSetMem(pos2,0,count2); | |
| DXSBuffer->Unlock(pos1,count1,pos2,count2); | |
| } | |
| DXSEvent = CreateEvent(0,0,0,0); | |
| if(!DXSEvent) | |
| return sFALSE; | |
| InitializeCriticalSection(&DXSLock); | |
| DXSBuffer->Play(0,0,DSBPLAY_LOOPING); | |
| DXSRun = 0; | |
| DXSThread = CreateThread(0,16384,ThreadCode,0,0,&DXSThreadId); | |
| if(!DXSThread) | |
| return sFALSE; | |
| SoundTime = 1; | |
| DXSTime = timeGetTime(); | |
| return sTRUE; | |
| } | |
| #pragma lekktor(on) | |
| /****************************************************************************/ | |
| void sSystem_::ExitDS() | |
| { | |
| if(Listener) | |
| Listener->Release(); | |
| if(DXSBuffer) | |
| DXSBuffer->Stop(); | |
| if(DXSThread) | |
| { | |
| DXSRun = 1; | |
| while(DXSRun==1) | |
| Sleep(10); | |
| CloseHandle(DXSThread); | |
| CloseHandle(DXSEvent); | |
| DeleteCriticalSection(&DXSLock); | |
| } | |
| #if sLINK_KKRIEGER | |
| SampleRemAll(); | |
| #endif | |
| if(DXSBuffer) | |
| DXSBuffer->Release(); | |
| if(DXSPrimary) | |
| DXSPrimary->Release(); | |
| if(DXS) | |
| DXS->Release(); | |
| } | |
| /****************************************************************************/ | |
| #pragma lekktor(off) | |
| void sSystem_::MarkDS() | |
| { | |
| SetEvent(DXSEvent); | |
| EnterCriticalSection(&DXSLock); | |
| DXSLastTotalSample = DXSReadStart + DXSReadOffset + sMulDiv(timeGetTime()-DXSTime,44100,1000); | |
| LeaveCriticalSection(&DXSLock); | |
| } | |
| #pragma lekktor(on) | |
| /****************************************************************************/ | |
| #pragma lekktor(off) | |
| unsigned long __stdcall ThreadCode(void *) | |
| { | |
| HRESULT hr; | |
| sInt play,dummy; | |
| DWORD count1,count2; | |
| void *pos1,*pos2; | |
| const sInt SAMPLESIZE = 4; | |
| sInt size,pplay; | |
| while(DXSRun==0) | |
| { | |
| WaitForSingleObject(DXSEvent,20/*(DXSSAMPLES*1000/44100)/(SAMPLESIZE*2)*/); | |
| EnterCriticalSection(&DXSLock); | |
| hr = DXSBuffer->GetCurrentPosition((DWORD*)&play,(DWORD*)&dummy); | |
| if(!FAILED(hr)) | |
| { | |
| pplay = play; | |
| play = play/SAMPLESIZE; | |
| DXSReadOffset = play; | |
| DXSTime = timeGetTime(); | |
| if(DXSIndex>play) | |
| play+=DXSSAMPLES; | |
| size = play-DXSIndex; | |
| size = (size)&(~(DXSHandlerAlign-1)); | |
| if(size>0) | |
| { | |
| count1 = 0; | |
| count2 = 0; | |
| hr = DXSBuffer->Lock(DXSIndex*SAMPLESIZE,size*SAMPLESIZE,&pos1,&count1,&pos2,&count2,0); | |
| if(!FAILED(hr)) | |
| { | |
| DXSIndex += size; | |
| if(DXSIndex>=DXSSAMPLES) | |
| { | |
| DXSIndex-=DXSSAMPLES; | |
| DXSReadStart += DXSSAMPLES; | |
| } | |
| sVERIFY((sInt)(count1+count2)==(size*4)); | |
| #if sLINK_UTIL | |
| if(sPerfMon && sPerfMon->IndexSound<0xfc) | |
| { | |
| sPerfMon->SoundRec[sPerfMon->DBuffer][sPerfMon->IndexSound] = sSystem->PerfTime(); | |
| } | |
| #endif | |
| if(DXSHandler) | |
| { | |
| if(count1>0) | |
| (*DXSHandler)((sS16 *)pos1,count1/SAMPLESIZE,(void *)DXSHandlerUser); | |
| if(count2>0) | |
| (*DXSHandler)((sS16 *)pos2,count2/SAMPLESIZE,(void *)DXSHandlerUser); | |
| } | |
| DXSBuffer->Unlock(pos1,count1,pos2,count2); | |
| #if sLINK_UTIL | |
| if(sPerfMon && sPerfMon->IndexSound<0xfc) | |
| { | |
| sPerfMon->SoundRec[sPerfMon->DBuffer][sPerfMon->IndexSound+1] = sSystem->PerfTime(); | |
| sPerfMon->IndexSound += 2; | |
| } | |
| #endif | |
| } | |
| } | |
| } | |
| LeaveCriticalSection(&DXSLock); | |
| } | |
| DXSRun = sFALSE; | |
| return 0; | |
| } | |
| #pragma lekktor(on) | |
| #endif | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| static void DSNullHandler(sS16 *data,sInt samples,void *user) | |
| { | |
| static sInt p0,p1; | |
| sSetMem4((sU32 *)data,0x00000000,samples); | |
| } | |
| extern void DSNullHandler(sS16 *data,sInt samples,void *user); | |
| /****************************************************************************/ | |
| void sSystem_::SetSoundHandler(sSoundHandler hnd,sInt align,void *user) | |
| { | |
| #if sUSE_DIRECTSOUND | |
| EnterCriticalSection(&DXSLock); | |
| if(hnd) | |
| { | |
| DXSHandler = hnd; | |
| DXSBuffer->Play(0,0,DSBPLAY_LOOPING); | |
| } | |
| else | |
| { | |
| DXSHandler = DSNullHandler; | |
| DXSBuffer->Stop(); | |
| #if !sINTRO | |
| HRESULT hr; | |
| DWORD count1,count2; | |
| void *pos1,*pos2; | |
| hr = DXSBuffer->Lock(0,DXSSAMPLES*4,&pos1,&count1,&pos2,&count2,0); // clear buffer, so that replay stops | |
| if(!FAILED(hr)) | |
| { | |
| sSetMem(pos1,0,count1); | |
| sSetMem(pos2,0,count2); | |
| DXSBuffer->Unlock(pos1,count1,pos2,count2); | |
| } | |
| #endif | |
| } | |
| if(align<0) | |
| align=64; | |
| DXSHandlerAlign = align; | |
| DXSHandlerSample = 0; | |
| DXSHandlerUser = user; | |
| DXSLastTotalSample = 0; | |
| DXSIndex = 0; | |
| DXSReadStart = -DXSSAMPLES; | |
| DXSReadOffset = 0; | |
| DXSTime = timeGetTime(); | |
| LeaveCriticalSection(&DXSLock); | |
| #endif | |
| } | |
| /****************************************************************************/ | |
| sInt sSystem_::GetCurrentSample() | |
| { | |
| #if sUSE_DIRECTSOUND | |
| return DXSLastTotalSample; | |
| #else | |
| return 0; | |
| #endif | |
| } | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Sample Player ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| #if sLINK_KKRIEGER | |
| sInt sSystem_::SampleAdd(sS16 *data,sInt size,sInt buffers,sInt handle,sBool is3d) | |
| { | |
| sInt i; | |
| IDirectSoundBuffer *dsb; | |
| DSBUFFERDESC dsbd; | |
| WAVEFORMATEX format; | |
| HRESULT hr; | |
| DWORD len; | |
| sSample *sam; | |
| sS16 *ptr; | |
| sVERIFY(buffers>=1); | |
| if(handle==sINVALID) | |
| { | |
| for(i=0;i<sMAXSAMPLEHANDLE;i++) | |
| { | |
| if(Sample[i].Count==0) | |
| { | |
| handle = i; | |
| break; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| sVERIFY(handle>=0 && handle<sMAXSAMPLEHANDLE); | |
| if(Sample[handle].Count!=0) | |
| handle = sINVALID; | |
| } | |
| if(handle!=sINVALID) | |
| { | |
| WINZERO(format); | |
| WINSET(dsbd); | |
| format.wFormatTag = WAVE_FORMAT_PCM; | |
| format.nChannels = is3d ? 1 : 2; | |
| format.nSamplesPerSec = 44100; | |
| format.nBlockAlign = is3d ? 2 : 4; | |
| format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; | |
| format.wBitsPerSample = 16; | |
| dsbd.dwFlags = (is3d ? DSBCAPS_CTRL3D : DSBCAPS_CTRLPAN) | DSBCAPS_CTRLVOLUME/* | DSBCAPS_CTRLFREQUENCY*/; | |
| dsbd.dwBufferBytes = size * format.nBlockAlign; | |
| dsbd.lpwfxFormat = &format; | |
| #pragma lekktor(off) | |
| hr = DXS->CreateSoundBuffer(&dsbd,&dsb,0); | |
| if(FAILED(hr)) return sINVALID; | |
| hr = dsb->Lock(0,0,(void **)&ptr,&len,0,0,DSBLOCK_ENTIREBUFFER); | |
| if(FAILED(hr)) return sINVALID; | |
| sVERIFY(len==size*format.nBlockAlign); | |
| if(!is3d) // we can upload stereo samples | |
| sCopyMem(ptr,data,size*format.nBlockAlign); | |
| else // do mono downmix | |
| for(i=0;i<size;i++) | |
| ptr[i] = (data[i*2+0] + data[i*2+1]) >> 1; | |
| hr = dsb->Unlock(ptr,len,0,0); | |
| if(FAILED(hr)) return sINVALID; | |
| sam = &Sample[handle]; | |
| sam->Buffers[0].Buffer = dsb; | |
| for(i=0;i<buffers;i++) | |
| { | |
| sam->Buffers[i].Buf3D = 0; | |
| sam->Buffers[i].PlayTime = 0; | |
| } | |
| for(i=1;i<buffers;i++) | |
| { | |
| hr = DXS->DuplicateSoundBuffer(dsb,&sam->Buffers[i].Buffer); | |
| if(FAILED(hr)) return sINVALID; | |
| } | |
| if(is3d) | |
| { | |
| for(i=0;i<buffers;i++) | |
| { | |
| if(!FAILED(sam->Buffers[i].Buffer->QueryInterface(IID_IDirectSound3DBuffer,(void **)&sam->Buffers[i].Buf3D))) | |
| sam->Buffers[i].Buf3D->SetMode(DS3DMODE_DISABLE,DS3D_DEFERRED); | |
| } | |
| } | |
| sam->LRU = 0; | |
| sam->Count = buffers; | |
| sam->Uses = 0; | |
| sam->Is3D = is3d; | |
| sam->LenMs = sMulDiv(len,1000,format.nAvgBytesPerSec) + 10; | |
| #pragma lekktor(on) | |
| } | |
| return handle; | |
| } | |
| void sSystem_::SampleRem(sInt handle) | |
| { | |
| sInt i; | |
| sSample *sam; | |
| sVERIFY(handle>=0 && handle<sMAXSAMPLEHANDLE); | |
| sam = &Sample[handle]; | |
| for(i=0;i<sam->Count;i++) | |
| { | |
| sam->Buffers[i].Buffer->Release(); | |
| if(sam->Buffers[i].Buf3D) | |
| sam->Buffers[i].Buf3D->Release(); | |
| } | |
| sam->Count = 0; | |
| sam->LRU = 0; | |
| } | |
| void sSystem_::SampleRemAll() | |
| { | |
| sInt i; | |
| for(i=0;i<sMAXSAMPLEHANDLE;i++) | |
| SampleRem(i); | |
| } | |
| static sInt lin2d3d(sF32 volume) | |
| { | |
| volume = sRange(volume,1.0f,1e-20f); | |
| return sFLog(volume)*20*100; | |
| } | |
| sInt sSystem_::SamplePlay(sInt handle,sF32 volume,sF32 pan,sInt freq) | |
| { | |
| sSample *sam; | |
| sSampleBuffer *buf; | |
| HRESULT hr; | |
| sInt d3dvol,d3dpan; | |
| sVERIFY(handle>=0 && handle<sMAXSAMPLEHANDLE); | |
| sam = &Sample[handle]; | |
| if(sam->Count>0) | |
| { | |
| d3dvol = lin2d3d(volume); | |
| d3dpan = sRange<sInt>(pan*100,10000,-10000); | |
| sam->LRU = (sam->LRU+1)%sam->Count; | |
| buf = &sam->Buffers[sam->LRU]; | |
| buf->Buffer->Stop(); | |
| buf->Buffer->SetCurrentPosition(0); | |
| buf->Buffer->SetVolume(d3dvol); | |
| if(!sam->Is3D) | |
| buf->Buffer->SetPan(d3dpan); | |
| hr = buf->Buffer->Play(0,0,0); | |
| buf->PlayTime = SoundTime; | |
| return ++sam->Uses; | |
| } | |
| else | |
| return -1; | |
| } | |
| void sSystem_::Sample3DParam(sInt handle,sInt bufnum,const sVector &pos,const sVector &vel,sF32 minDist,sF32 maxDist) | |
| { | |
| sSample *sam; | |
| DS3DBUFFER params; | |
| sVERIFY(handle>=0 && handle<sMAXSAMPLEHANDLE); | |
| sam = &Sample[handle]; | |
| // get 3d buffer | |
| if(sam->Is3D && sam->Uses - bufnum < sam->Count) // if buffer has not been reallocated yet | |
| { | |
| bufnum %= sam->Count; | |
| if(sam->Buffers[bufnum].PlayTime) // if buffer hasn't been stopped yet | |
| { | |
| // set up parameters | |
| WINSET(params); | |
| params.vPosition.x = pos.x; | |
| params.vPosition.y = pos.y; | |
| params.vPosition.z = pos.z; | |
| params.vVelocity.x = vel.x; | |
| params.vVelocity.y = vel.y; | |
| params.vVelocity.z = vel.z; | |
| params.dwInsideConeAngle = 360; // in degrees... right. | |
| params.dwOutsideConeAngle = 360; | |
| params.vConeOrientation.z = 1.0f; | |
| params.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME; | |
| params.flMinDistance = minDist; | |
| params.flMaxDistance = maxDist; | |
| params.dwMode = DS3DMODE_NORMAL; | |
| // set the parameters | |
| sam->Buffers[bufnum].Buf3D->SetAllParameters(¶ms,DS3D_IMMEDIATE); | |
| } | |
| } | |
| } | |
| void sSystem_::Sample3DListener(const sVector &pos,const sVector &vel,const sVector &up,const sVector &fwd,sF32 doppler,sF32 rolloff) | |
| { | |
| DS3DLISTENER params; | |
| WINSET(params); | |
| params.vPosition.x = pos.x; | |
| params.vPosition.y = pos.y; | |
| params.vPosition.z = pos.z; | |
| params.vVelocity.x = vel.x; | |
| params.vVelocity.y = vel.y; | |
| params.vVelocity.z = vel.z; | |
| params.vOrientFront.x = fwd.x; | |
| params.vOrientFront.y = fwd.y; | |
| params.vOrientFront.z = fwd.z; | |
| params.vOrientTop.x = up.x; | |
| params.vOrientTop.y = up.y; | |
| params.vOrientTop.z = up.z; | |
| params.flDistanceFactor = 1.0f; | |
| params.flRolloffFactor = rolloff; | |
| params.flDopplerFactor = doppler; | |
| Listener->SetAllParameters(¶ms,DS3D_DEFERRED); | |
| } | |
| void sSystem_::Sample3DCommit() | |
| { | |
| sInt i,j; | |
| sSample *sam; | |
| sSampleBuffer *buf; | |
| sZONE(Sound3D); | |
| // disable hanging 3d sounds | |
| for(i=0;i<sMAXSAMPLEHANDLE;i++) | |
| { | |
| sam = &Sample[i]; | |
| if(sam->Is3D) | |
| { | |
| for(j=0;j<sam->Count;j++) | |
| { | |
| buf = &sam->Buffers[j]; | |
| if(buf->PlayTime && buf->PlayTime + sam->LenMs < SoundTime) | |
| { | |
| buf->PlayTime = 0; | |
| buf->Buf3D->SetMode(DS3DMODE_DISABLE,DS3D_DEFERRED); | |
| } | |
| } | |
| } | |
| } | |
| // commit settings | |
| Listener->CommitDeferredSettings(); | |
| SoundTime = sSystem->GetTime(); | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** File ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| sU8 *sSystem_::LoadFile(const sChar *name,sInt &size) | |
| { | |
| sInt result; | |
| HANDLE handle; | |
| DWORD test; | |
| sU8 *mem; | |
| mem = 0; | |
| result = sFALSE; | |
| handle = CreateFile(name,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); | |
| if(handle != INVALID_HANDLE_VALUE) | |
| { | |
| size = GetFileSize(handle,&test); | |
| if(test==0) | |
| { | |
| mem = new sU8[size]; | |
| if(ReadFile(handle,mem,size,&test,0)) | |
| result = sTRUE; | |
| if(size!=(sInt)test) | |
| result = sFALSE; | |
| } | |
| CloseHandle(handle); | |
| } | |
| if(!result) | |
| { | |
| if(mem) | |
| delete[] mem; | |
| mem = 0; | |
| sDPrintF("*** Loading <%s> failed\n",name); | |
| } | |
| else | |
| { | |
| sDPrintF("*** Loading <%s> (%d bytes)\n",name,size); | |
| } | |
| return mem; | |
| } | |
| /****************************************************************************/ | |
| sU8 *sSystem_::LoadFile(const sChar *name) | |
| { | |
| sInt dummy; | |
| return LoadFile(name,dummy); | |
| } | |
| /****************************************************************************/ | |
| #if !sINTRO | |
| //---------------------------------------------------------------------------- | |
| // get base name of current exe | |
| //---------------------------------------------------------------------------- | |
| void sSystem_::GetModuleBaseName(sChar *buffer,sInt size) | |
| { | |
| // Retrieves the full path for the file that contains the specified module | |
| char str[MAX_PATH]; | |
| GetModuleFileName(NULL, str, MAX_PATH); | |
| // strip path | |
| sCopyString(buffer,sFileFromPathString(str),size); | |
| // remove extension (if present) to just keep base name | |
| sChar *ext = sFileExtensionString(buffer); | |
| if (ext) | |
| *ext = 0; | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| sU8 *sSystem_::LoadFileIfNewerThan(const sChar *name,const sChar *other,sInt &size) | |
| { | |
| WIN32_FILE_ATTRIBUTE_DATA fa1,fa2; | |
| if(GetFileAttributesEx(name,GetFileExInfoStandard,&fa1) && | |
| GetFileAttributesEx(other,GetFileExInfoStandard,&fa2) && | |
| CompareFileTime(&fa1.ftLastWriteTime,&fa2.ftLastWriteTime) > 0) | |
| return LoadFile(name,size); | |
| else | |
| return 0; | |
| } | |
| /****************************************************************************/ | |
| sChar *sSystem_::LoadText(const sChar *name) | |
| { | |
| sInt result; | |
| HANDLE handle; | |
| DWORD test; | |
| sU8 *mem; | |
| sInt size; | |
| mem = 0; | |
| result = sFALSE; | |
| handle = CreateFile(name,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); | |
| if(handle != INVALID_HANDLE_VALUE) | |
| { | |
| size = GetFileSize(handle,&test); | |
| if(test==0) | |
| { | |
| mem = new sU8[size+1]; | |
| if(ReadFile(handle,mem,size,&test,0)) | |
| result = sTRUE; | |
| if(size!=(sInt)test) | |
| result = sFALSE; | |
| mem[size]=0; | |
| } | |
| CloseHandle(handle); | |
| } | |
| if(!result) | |
| { | |
| delete[] mem; | |
| mem = 0; | |
| } | |
| return (sChar *)mem;} | |
| /****************************************************************************/ | |
| sBool sSystem_::SaveFile(const sChar *name,const sU8 *data,sInt size) | |
| { | |
| sInt result; | |
| HANDLE handle; | |
| DWORD test; | |
| result = sFALSE; | |
| handle = CreateFile(name,GENERIC_WRITE,FILE_SHARE_WRITE,0,CREATE_NEW,0,0); | |
| if(handle == INVALID_HANDLE_VALUE) | |
| handle = CreateFile(name,GENERIC_WRITE,FILE_SHARE_WRITE,0,TRUNCATE_EXISTING,0,0); | |
| if(handle != INVALID_HANDLE_VALUE) | |
| { | |
| if(WriteFile(handle,data,size,&test,0)) | |
| result = sTRUE; | |
| if(size!=(sInt)test) | |
| result = sFALSE; | |
| CloseHandle(handle); | |
| } | |
| if(result) | |
| sDPrintF("*** Saving <%s> (%d bytes)\n",name,size); | |
| else | |
| sDPrintF("*** Saving <%s> failed\n",name); | |
| return result; | |
| } | |
| /****************************************************************************/ | |
| sU64 sSystem_::GetFileStamp(const sChar *name) | |
| { | |
| WIN32_FILE_ATTRIBUTE_DATA data; | |
| if(GetFileAttributesEx(name,GetFileExInfoStandard,&data)) | |
| { | |
| return *(sU64 *)&data.ftLastWriteTime; | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| #define sMAX_PATHNAME 4096 | |
| sDirEntry *sSystem_::LoadDir(const sChar *name) | |
| { | |
| static sChar buffer[sMAX_PATHNAME]; | |
| HANDLE handle; | |
| sInt len; | |
| sInt i,j; | |
| WIN32_FIND_DATA dir; | |
| sDirEntry *de,*nde; | |
| sInt max; | |
| de = 0; | |
| sCopyString(buffer,name,sMAX_PATHNAME); | |
| len = sGetStringLen(buffer); | |
| if(name[len-1]!='/' && name[len-1]!='\\') | |
| sAppendString(buffer,"/",sMAX_PATHNAME); | |
| sAppendString(buffer,"*.*",sMAX_PATHNAME); | |
| handle = FindFirstFile(buffer,&dir); | |
| if(handle!=INVALID_HANDLE_VALUE) | |
| { | |
| max = 256; | |
| i=0; | |
| de = new sDirEntry[max]; | |
| do | |
| { | |
| if(i == max-1) | |
| { | |
| max *= 2; | |
| nde = new sDirEntry[max]; | |
| sCopyMem(nde,de,sizeof(sDirEntry)*i); | |
| delete[] de; | |
| de = nde; | |
| } | |
| if(sCmpString(dir.cFileName,".")==0) | |
| continue; | |
| if(sCmpString(dir.cFileName,"..")==0) | |
| continue; | |
| de[i].IsDir = (dir.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; | |
| de[i].Size = dir.nFileSizeLow; | |
| sCopyString(de[i].Name,dir.cFileName,sizeof(de[i].Name)); | |
| de[i].pad[0]=0; | |
| de[i].pad[1]=0; | |
| de[i].pad[2]=0; | |
| i++; | |
| } | |
| while(FindNextFile(handle,&dir)); | |
| FindClose(handle); | |
| sSetMem(&de[i],0,sizeof(sDirEntry)); | |
| max = i; | |
| for(i=0;i<max-1;i++) | |
| for(j=i+1;j<max;j++) | |
| if(de[i].IsDir<de[j].IsDir || (de[i].IsDir==de[j].IsDir && sCmpStringI(de[i].Name,de[j].Name)>0)) | |
| sSwap(de[i],de[j]); | |
| } | |
| return de; | |
| } | |
| /****************************************************************************/ | |
| sBool sSystem_::MakeDir(const sChar *name) | |
| { | |
| return CreateDirectory(name,0) != 0; | |
| } | |
| /****************************************************************************/ | |
| sBool sSystem_::CheckDir(const sChar *name) | |
| { | |
| sBool result; | |
| static sChar buffer[sMAX_PATHNAME]; | |
| HANDLE handle; | |
| sInt len; | |
| WIN32_FIND_DATA dir; | |
| sCopyString(buffer,name,sMAX_PATHNAME); | |
| len = sGetStringLen(buffer); | |
| if(name[len-1]!='/' && name[len-1]!='\\') | |
| sAppendString(buffer,"/",sMAX_PATHNAME); | |
| sAppendString(buffer,"*.*",sMAX_PATHNAME); | |
| handle = FindFirstFile(buffer,&dir); | |
| result = (handle!=INVALID_HANDLE_VALUE); | |
| FindClose(handle); | |
| return result; | |
| } | |
| sBool sSystem_::CheckFile(const sChar *name) | |
| { | |
| HANDLE handle; | |
| handle = CreateFile(name,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); | |
| if(handle != INVALID_HANDLE_VALUE) | |
| { | |
| CloseHandle(handle); | |
| return sTRUE; | |
| } | |
| return sFALSE; | |
| } | |
| #undef sMAX_PATHNAME | |
| /****************************************************************************/ | |
| sBool sSystem_::RenameFile(const sChar *oldname,const sChar *newname) | |
| { | |
| sBool result; | |
| result = sFALSE; | |
| // if(CheckFileName(name)) | |
| { | |
| result = MoveFile(oldname,newname); | |
| } | |
| return result; | |
| } | |
| /****************************************************************************/ | |
| sBool sSystem_::DeleteFile(const sChar *name) | |
| { | |
| return ::DeleteFileA(name); | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::GetCurrentDir(sChar *buffer,sInt size) | |
| { | |
| sChar *s; | |
| if(::GetCurrentDirectoryA(size,buffer)) | |
| { | |
| s = buffer; | |
| while(*s) | |
| { | |
| if(*s=='\\') | |
| *s = '/'; | |
| s++; | |
| } | |
| } | |
| else | |
| { | |
| sCopyString(buffer,"c:/",size); | |
| } | |
| } | |
| /****************************************************************************/ | |
| sU32 sSystem_::GetDriveMask() | |
| { | |
| return GetLogicalDrives(); | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| #if sLINK_PNG | |
| #include "pngloader/loadpng.hpp" | |
| #endif | |
| /****************************************************************************/ | |
| #define HIMETRIC_PER_INCH 2540 | |
| #define MAP_PIX_TO_LOGHIM(x,ppli) ((HIMETRIC_PER_INCH*(x)+((ppli)>>1))/(ppli)) | |
| #define MAP_LOGHIM_TO_PIX(x,ppli) (((ppli)*(x)+HIMETRIC_PER_INCH/2)/HIMETRIC_PER_INCH) | |
| sBitmap *sSystem_::LoadBitmap(const sU8 *data,sInt size) | |
| { | |
| sInt x,y; | |
| sU8 *pic; | |
| sBitmap *bm; | |
| if(LoadBitmapCore(data,size,x,y,pic)) | |
| { | |
| bm = new sBitmap; | |
| bm->Init(x,y); | |
| sCopyMem(bm->Data,pic,x*y*4); | |
| delete[] pic; | |
| return bm; | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| } | |
| sBool sSystem_::LoadBitmapCore(const sU8 *data,sInt size,sInt &xout,sInt &yout,sU8 *&dataout) | |
| { | |
| HDC screendc; | |
| HDC hdc; | |
| HDC hdc2,hdcold; | |
| HBITMAP hbm,hbm2; | |
| BITMAPINFO bmi; | |
| sInt i; | |
| HRESULT hr; | |
| IPicture *pic; | |
| IStream *str; | |
| DWORD dummy; | |
| POINT wpl,wpp; | |
| sInt xs,ys; | |
| // sBitmap *bm; | |
| union _ULARGE_INTEGER usize; | |
| union _LARGE_INTEGER useek; | |
| union _ULARGE_INTEGER udummy; | |
| xout = 0; | |
| yout = 0; | |
| dataout = 0; | |
| #if sLINK_PNG | |
| if(LoadPNG(data,size,xout,yout,dataout)) | |
| return sTRUE; | |
| #endif | |
| #if sTEXTUREONLY | |
| return sFALSE; | |
| #else | |
| screendc = GetDC(0); | |
| hr = CreateStreamOnHGlobal(0,TRUE,&str); | |
| if(!FAILED(hr)) | |
| { | |
| usize.QuadPart = size; | |
| str->SetSize(usize); | |
| str->Write(data,size,&dummy); | |
| useek.QuadPart = 0; | |
| str->Seek(useek,STREAM_SEEK_SET,&udummy); | |
| hr = OleLoadPicture(str,size,TRUE,IID_IPicture,(void**)&pic); | |
| if(!FAILED(hr)) | |
| { | |
| pic->get_Width(&wpl.x); | |
| pic->get_Height(&wpl.y); | |
| wpp = wpl; | |
| sInt px=GetDeviceCaps(screendc,LOGPIXELSX); | |
| sInt py=GetDeviceCaps(screendc,LOGPIXELSY); | |
| wpp.x=MAP_LOGHIM_TO_PIX(wpl.x,px); | |
| wpp.y=MAP_LOGHIM_TO_PIX(-wpl.y,py); | |
| hdc = CreateCompatibleDC(screendc); | |
| hdc2 = CreateCompatibleDC(screendc); | |
| xout = xs = sMakePower2(wpp.x); | |
| yout = ys = sMakePower2(-wpp.y); | |
| dataout = new sU8[xs*ys*4]; | |
| hbm = CreateCompatibleBitmap(screendc,xs,ys); | |
| SelectObject(hdc,hbm); | |
| sSetMem4((sU32 *)dataout,0xffff0000,xs*ys); | |
| bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); | |
| bmi.bmiHeader.biWidth = xs; | |
| bmi.bmiHeader.biHeight = -ys; | |
| bmi.bmiHeader.biPlanes = 1; | |
| bmi.bmiHeader.biBitCount = 32; | |
| bmi.bmiHeader.biCompression = BI_RGB; | |
| hr = pic->SelectPicture(hdc2,&hdcold,(unsigned int *)&hbm2); | |
| if(!FAILED(hr)) | |
| { | |
| SetMapMode(hdc2,MM_TEXT); | |
| StretchBlt(hdc,0,0,xs,ys,hdc2,0,0,wpp.x,-wpp.y,SRCCOPY); | |
| GetDIBits(hdc,hbm,0,ys,dataout,&bmi,DIB_RGB_COLORS); | |
| pic->SelectPicture(hdcold,0,(unsigned int *)&hbm2); | |
| } | |
| pic->Release(); | |
| DeleteDC(hdc2); | |
| DeleteDC(hdc); | |
| DeleteObject(hbm); | |
| for(i=0;i<xs*ys;i++) | |
| ((sU32 *)dataout)[i] |= 0xff000000; | |
| } | |
| str->Release(); | |
| } | |
| ReleaseDC(0,screendc); | |
| return dataout!=0; | |
| #endif | |
| } | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Host Font Interface ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| sInt sSystem_::FontBegin(sInt pagex,sInt pagey,const sChar *name,sInt xs,sInt ys,sInt style) | |
| { | |
| //LOGFONT lf; | |
| TEXTMETRIC met; | |
| FontBMI.bmiHeader.biSize = sizeof(FontBMI.bmiHeader); | |
| FontBMI.bmiHeader.biWidth = pagex; | |
| FontBMI.bmiHeader.biHeight = -pagey; | |
| FontBMI.bmiHeader.biPlanes = 1; | |
| FontBMI.bmiHeader.biBitCount = 32; | |
| FontBMI.bmiHeader.biCompression = BI_RGB; | |
| FontHBM = CreateDIBSection(GDIScreenDC,&FontBMI,DIB_RGB_COLORS, | |
| (void **) &FontMem,0,0); | |
| SelectObject(GDIDC,FontHBM); | |
| if(name[0]==0) name = "arial"; | |
| /*lf.lfHeight = -ys; | |
| lf.lfWidth = xs; | |
| lf.lfEscapement = 0; | |
| lf.lfOrientation = 0; | |
| lf.lfWeight = (style&2) ? FW_BOLD : FW_NORMAL; | |
| lf.lfItalic = (style&1) ? 1 : 0; | |
| lf.lfUnderline = 0; | |
| lf.lfStrikeOut = 0; | |
| lf.lfCharSet = DEFAULT_CHARSET; | |
| lf.lfOutPrecision = OUT_TT_PRECIS; | |
| lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; | |
| lf.lfQuality = (style&4) ? ANTIALIASED_QUALITY : NONANTIALIASED_QUALITY; | |
| lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; | |
| sCopyMem(lf.lfFaceName,name,32); | |
| FontHandle = CreateFontIndirect(&lf);*/ | |
| FontHandle = CreateFont(-ys,xs,0,0,(style&2) ? FW_BOLD : FW_NORMAL, | |
| (style&1) ? 1 : 0,0,0,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS, | |
| PROOF_QUALITY, | |
| //(style&4) ? ANTIALIASED_QUALITY : NONANTIALIASED_QUALITY, | |
| DEFAULT_PITCH|FF_DONTCARE,name); | |
| SetBkMode(GDIDC,TRANSPARENT); | |
| SelectObject(GDIScreenDC,FontHandle); // win98: first select font into screen dc | |
| SelectObject(GDIDC,FontHandle); | |
| SelectObject(GDIDC,FontHBM); | |
| SetTextColor(GDIDC,0xffffff); | |
| GetTextMetrics(GDIDC,&met); | |
| return met.tmHeight; | |
| // Advance = met.tmHeight+met.tmExternalLeading; | |
| // Baseline = met.tmHeight-met.tmDescent; | |
| } | |
| sInt sSystem_::FontWidth(const sChar *string,sInt len) | |
| { | |
| SIZE p; | |
| if(len==-1) | |
| { | |
| len++; | |
| while(string[len]) len++; | |
| } | |
| GetTextExtentPoint32(GDIDC,string,len,&p); | |
| return p.cx; | |
| } | |
| void sSystem_::FontCharWidth(sInt ch,sInt *widths) | |
| { | |
| ABC abc; | |
| GetCharABCWidths(GDIDC,ch,ch,&abc); | |
| widths[0] = abc.abcA; | |
| widths[1] = abc.abcB; | |
| widths[2] = abc.abcC; | |
| } | |
| void sSystem_::FontPrint(sInt x,sInt y,const sChar *string,sInt len) | |
| { | |
| if(len==-1) | |
| { | |
| len++; | |
| while(string[len]) len++; | |
| } | |
| ExtTextOut(GDIDC,x,y,0,0,string,len,0); | |
| } | |
| void sSystem_::FontPrint(sInt x,sInt y,const sWChar *string,sInt len) | |
| { | |
| if(len==-1) | |
| { | |
| len++; | |
| while(string[len]) len++; | |
| } | |
| ExtTextOutW(GDIDC,x,y,0,0,string,len,0); | |
| } | |
| void sSystem_::FontEnd() | |
| { | |
| SelectObject(GDIDC,GDIHBM); | |
| DeleteObject(FontHBM); | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Helper Structures ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| void sGeoBuffer::Init() | |
| { | |
| Type = 0; | |
| Size = 0; | |
| Used = 0; | |
| VB = 0; | |
| UserCount = 0; | |
| } | |
| sBool sGeoBuffer::Alloc(sInt count,sInt size,sInt &firstp,sInt type) | |
| { | |
| sInt pos,first; | |
| if(Type!=type) | |
| return sFALSE; | |
| first = (Used+size-1)/size; | |
| pos = (first+count)*size; | |
| if(pos>Size) | |
| return sFALSE; | |
| Used = pos; | |
| firstp = first; | |
| UserCount++; | |
| return sTRUE; | |
| } | |
| void sGeoBuffer::Free() | |
| { | |
| sVERIFY(UserCount>0); | |
| UserCount--; | |
| if(UserCount==0) | |
| Used = 0; | |
| } | |
| void sTexInfo::Init(sBitmap *bm,sInt format,sU32 flags) | |
| { | |
| XSize = bm->XSize; | |
| YSize = bm->YSize; | |
| Bitmap = bm; | |
| Flags = flags; | |
| Format = format; | |
| } | |
| void sTexInfo::InitRT(sInt xs,sInt ys) | |
| { | |
| XSize = xs; | |
| YSize = ys; | |
| Flags = sTIF_RENDERTARGET; | |
| Format = 0; | |
| } | |
| void sMaterialEnv::Init() | |
| { | |
| sSetMem(this,0,sizeof(*this)); | |
| ModelSpace.Init(); | |
| CameraSpace.Init(); | |
| NearClip = 0.125f; | |
| FarClip = 4096.0f; | |
| ZoomX = 1.0f; | |
| ZoomY = 1.0f; | |
| CenterX = 0.0f; | |
| CenterY = 0.0f; | |
| FogStart = 0; | |
| FogEnd = FarClip; | |
| FogColor = 0xff808080; | |
| } | |
| void sMaterialEnv::MakeProjectionMatrix(sMatrix &pmat) const | |
| { | |
| sF32 q; | |
| sF32 shiftX = 1.0f / sSystem->ViewportX; | |
| sF32 shiftY = 1.0f / sSystem->ViewportY; | |
| switch(Orthogonal) | |
| { | |
| #if !sINTRO | |
| case sMEO_PIXELS: // 0 .. screen_max | |
| pmat.i.Init(2.0f/sSystem->ViewportX,0 ,0 ,0); | |
| pmat.j.Init(0 ,-2.0f/sSystem->ViewportY,0 ,0); | |
| pmat.k.Init(0 ,0 ,1 ,0); | |
| pmat.l.Init(-1 - (2*CenterX+1)*shiftX,1 + (2*CenterY+1)*shiftY,0 ,1); | |
| break; | |
| #endif | |
| case sMEO_NORMALISED: // -1 .. 1 | |
| pmat.i.Init(ZoomX ,0 ,0 ,0); | |
| pmat.j.Init(0 ,ZoomY ,0 ,0); | |
| pmat.k.Init(0 ,0 ,1.0f/FarClip,0); | |
| pmat.l.Init(-shiftX ,shiftY ,0 ,1); | |
| break; | |
| case sMEO_PERSPECTIVE: | |
| //q = FarClip/(FarClip-NearClip); | |
| q = 1.0f; | |
| pmat.i.Init(ZoomX ,0 , 0 ,0); | |
| pmat.j.Init(0 ,ZoomY , 0 ,0); | |
| pmat.k.Init(CenterX ,CenterY , q ,1); | |
| pmat.l.Init(-shiftX ,shiftY ,-q*NearClip ,0); | |
| break; | |
| } | |
| } | |
| /****************************************************************************/ | |
| sMaterial::~sMaterial() | |
| { | |
| } | |
| /****************************************************************************/ | |
| void sShader::Cleanup() | |
| { | |
| delete[] Code; | |
| Code = 0; | |
| sRelease(Shader); | |
| } | |
| /****************************************************************************/ | |
| void sMaterialSetup::Cleanup() | |
| { | |
| delete[] States; | |
| States = 0; | |
| sSystem->Shaders[VSId].Release(); | |
| sSystem->Shaders[PSId].Release(); | |
| VSId = PSId = sINVALID; | |
| VS = 0; | |
| PS = 0; | |
| } | |
| sMaterialInstance sMaterialInstance::Null = { 0 }; | |
| /****************************************************************************/ | |
| sSimpleMaterial::sSimpleMaterial(sInt tex,sU32 flags,sU32 flags2,sU32 color) | |
| { | |
| sU32 states[64],*st = states; | |
| static const sU32 vShaderTex[] = | |
| { | |
| 0xfffe0101, // vs.1.1 | |
| 0x0000001f, 0x80000000, 0x900f0000, // dcl_position v0 | |
| 0x0000001f, 0x80000005, 0x900f0001, // dcl_texcoord v1 | |
| 0x0000001f, 0x8000000a, 0x900f0002, // dcl_color v2 | |
| 0x00000014, 0xc00f0000, 0x90e40000, 0xa0e40000, // m4x4 oPos,v0,c0 | |
| 0x00000001, 0xe00f0000, 0x90e40001, // mov oT0,v1 | |
| 0x00000001, 0xd00f0000, 0x90e40002, // mov oD0,v2 | |
| 0x0000ffff, // end | |
| }; | |
| static const sU32 vShaderNoTex[] = | |
| { | |
| 0xfffe0101, // vs.1.1 | |
| 0x0000001f, 0x80000000, 0x900f0000, // dcl_position v0 | |
| 0x0000001f, 0x8000000a, 0x900f0001, // dcl_color v1 | |
| 0x00000014, 0xc00f0000, 0x90e40000, 0xa0e40000, // m4x4 oPos,v0,c0 | |
| 0x00000001, 0xd00f0000, 0x90e40001, // mov oD0,v1 | |
| 0x0000ffff, // end | |
| }; | |
| sInt blendMode = flags & sMBF_BLENDMASK; | |
| // zbias calc | |
| sF32 zBias = 0.0f; | |
| if(flags & sMBF_ZBIASBACK) zBias = 1.0f / 65536.0f; | |
| if(flags & sMBF_ZBIASFORE) zBias = -1.0f / 65536.0f; | |
| // render state setup | |
| *st++ = sD3DRS_ALPHATESTENABLE; *st++ = 0; | |
| *st++ = sD3DRS_ZENABLE; *st++ = sD3DZB_TRUE; | |
| *st++ = sD3DRS_ZWRITEENABLE; *st++ = (flags & sMBF_ZWRITE) ? 1 : 0; | |
| *st++ = sD3DRS_ZFUNC; *st++ = (flags & sMBF_ZREAD) ? sD3DCMP_LESS : sD3DCMP_ALWAYS; | |
| *st++ = sD3DRS_CULLMODE; *st++ = (flags & sMBF_DOUBLESIDED) ? sD3DCULL_NONE : (flags & sMBF_INVERTCULL ? sD3DCULL_CW : sD3DCULL_CCW); | |
| *st++ = sD3DRS_COLORWRITEENABLE; *st++ = 15; | |
| *st++ = sD3DRS_SLOPESCALEDEPTHBIAS; *st++ = *(sU32 *) &zBias; | |
| *st++ = sD3DRS_DEPTHBIAS; *st++ = *(sU32 *) &zBias; | |
| *st++ = sD3DRS_FOGENABLE; *st++ = 0; | |
| *st++ = sD3DRS_STENCILENABLE; *st++ = 0; | |
| switch(flags & sMBF_BLENDMASK) | |
| { | |
| case sMBF_BLENDADD: | |
| *st++ = sD3DRS_ALPHABLENDENABLE; *st++ = 1; | |
| *st++ = sD3DRS_SRCBLEND; *st++ = sD3DBLEND_ONE; | |
| *st++ = sD3DRS_DESTBLEND; *st++ = sD3DBLEND_ONE; | |
| *st++ = sD3DRS_BLENDOP; *st++ = sD3DBLENDOP_ADD; | |
| break; | |
| case sMBF_BLENDALPHA: | |
| *st++ = sD3DRS_ALPHABLENDENABLE; *st++ = 1; | |
| *st++ = sD3DRS_SRCBLEND; *st++ = sD3DBLEND_SRCALPHA; | |
| *st++ = sD3DRS_DESTBLEND; *st++ = sD3DBLEND_INVSRCALPHA; | |
| *st++ = sD3DRS_BLENDOP; *st++ = sD3DBLENDOP_ADD; | |
| break; | |
| default: | |
| *st++ = sD3DRS_ALPHABLENDENABLE; *st++ = 0; | |
| break; | |
| } | |
| // texture stages | |
| *st++ = sD3DTSS_0|sD3DTSS_TEXCOORDINDEX; *st++ = 0; | |
| *st++ = sD3DTSS_0|sD3DTSS_TEXTURETRANSFORMFLAGS; *st++ = 0; | |
| sU32 colorSource = (flags2 & 1) ? sD3DTA_TFACTOR : sD3DTA_DIFFUSE; | |
| if(tex != sINVALID) | |
| { | |
| *st++ = sD3DTSS_0|sD3DTSS_COLORARG1; *st++ = sD3DTA_TEXTURE; | |
| *st++ = sD3DTSS_0|sD3DTSS_COLORARG2; *st++ = colorSource; | |
| *st++ = sD3DTSS_0|sD3DTSS_COLOROP; *st++ = sD3DTOP_MODULATE; | |
| *st++ = sD3DTSS_0|sD3DTSS_ALPHAARG1; *st++ = sD3DTA_TEXTURE; | |
| *st++ = sD3DTSS_0|sD3DTSS_ALPHAOP; *st++ = sD3DTOP_SELECTARG1; | |
| } | |
| else | |
| { | |
| *st++ = sD3DTSS_0|sD3DTSS_COLORARG2; *st++ = colorSource; | |
| *st++ = sD3DTSS_0|sD3DTSS_COLOROP; *st++ = sD3DTOP_SELECTARG2; | |
| *st++ = sD3DTSS_0|sD3DTSS_ALPHAARG2; *st++ = colorSource; | |
| *st++ = sD3DTSS_0|sD3DTSS_ALPHAOP; *st++ = sD3DTOP_SELECTARG2; | |
| } | |
| *st++ = sD3DTSS_1|sD3DTSS_COLOROP; *st++ = sD3DTOP_DISABLE; | |
| *st++ = sD3DTSS_1|sD3DTSS_ALPHAOP; *st++ = sD3DTOP_DISABLE; | |
| // sampler | |
| sU32 addressMode = (flags2 & 2) ? sD3DTADDRESS_CLAMP : sD3DTADDRESS_WRAP; | |
| *st++ = sD3DSAMP_0|sD3DSAMP_MAGFILTER; *st++ = sD3DTEXF_LINEAR; | |
| *st++ = sD3DSAMP_0|sD3DSAMP_MINFILTER; *st++ = sD3DTEXF_LINEAR; | |
| *st++ = sD3DSAMP_0|sD3DSAMP_MIPFILTER; *st++ = (flags2 & 4) ? sD3DTEXF_NONE : sD3DTEXF_LINEAR; | |
| *st++ = sD3DSAMP_0|sD3DSAMP_ADDRESSU; *st++ = addressMode; | |
| *st++ = sD3DSAMP_0|sD3DSAMP_ADDRESSV; *st++ = addressMode; | |
| // terminator | |
| *st++ = ~0U; *st++ = ~0U; | |
| // other stuff | |
| Color = color; | |
| Tex = sINVALID; | |
| SetTex(tex); | |
| // create setup | |
| Setup = sSystem->MtrlAddSetup(states,(tex == sINVALID) ? vShaderNoTex : vShaderTex,0); | |
| } | |
| sSimpleMaterial::~sSimpleMaterial() | |
| { | |
| SetTex(sINVALID); | |
| sSystem->MtrlRemSetup(Setup); | |
| } | |
| void sSimpleMaterial::SetTex(sInt tex) | |
| { | |
| if(tex != sINVALID) | |
| sSystem->AddRefTexture(tex); | |
| if(Tex != sINVALID) | |
| sSystem->RemTexture(Tex); | |
| Tex = tex; | |
| } | |
| void sSimpleMaterial::Set(const sMaterialEnv &env) | |
| { | |
| sMaterialInstance inst; | |
| sMatrix mat; | |
| inst.NumTextures = 1; | |
| inst.Textures[0] = Tex; | |
| inst.NumVSConstants = 4; | |
| inst.VSConstants = &mat.i; | |
| inst.NumPSConstants = 0; | |
| mat.Mul4(env.ModelSpace,sSystem->LastViewProject); | |
| mat.Trans4(); | |
| sSystem->MtrlSetSetup(Setup); | |
| sSystem->MtrlSetInstance(inst); | |
| sSystem->SetState(sD3DRS_TEXTUREFACTOR,Color); | |
| } | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Viewport ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| void sViewport::Init(sInt screen) | |
| { | |
| Screen = screen; | |
| RenderTarget = -1; | |
| Window.Init(0,0,sSystem->Screen[screen].XSize,sSystem->Screen[screen].YSize); | |
| } | |
| /****************************************************************************/ | |
| void sViewport::InitTex(sInt handle) | |
| { | |
| Screen = -1; | |
| RenderTarget = handle; | |
| Window.x0 = 0; | |
| Window.y0 = 0; | |
| sSystem->GetTextureSize(handle,Window.x1,Window.y1); | |
| } | |
| /****************************************************************************/ | |
| void sViewport::InitTexMS(sInt handle) | |
| { | |
| Screen = -2; | |
| RenderTarget = handle; | |
| Window.x0 = 0; | |
| Window.y0 = 0; | |
| sSystem->GetTextureSize(handle,Window.x1,Window.y1); | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Host Font ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| struct sHostFontPrivate | |
| { | |
| // HDC screendc; | |
| BITMAPINFO bmi; | |
| // HDC hdc; | |
| HBITMAP hbm; | |
| LOGFONT lf; | |
| HFONT font; | |
| }; | |
| /****************************************************************************/ | |
| sBool InitGDI() | |
| { | |
| GDIScreenDC = GetDC(0); | |
| GDIDC = CreateCompatibleDC(GDIScreenDC); | |
| GDIHBM = CreateCompatibleBitmap(GDIScreenDC,16,16); | |
| SelectObject(GDIDC,GDIHBM); | |
| return sTRUE; | |
| } | |
| /****************************************************************************/ | |
| void ExitGDI() | |
| { | |
| DeleteDC(GDIDC); | |
| DeleteObject(GDIHBM); | |
| ReleaseDC(0,GDIScreenDC); | |
| } | |
| /****************************************************************************/ | |
| sHostFont::sHostFont() | |
| { | |
| prv = new sHostFontPrivate; | |
| prv->font = 0; | |
| } | |
| /****************************************************************************/ | |
| sHostFont::~sHostFont() | |
| { | |
| if(prv->font) | |
| DeleteObject(prv->font); | |
| delete[] prv; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| void sHostFont::Begin(sBitmap *bm) | |
| { | |
| prv->hbm = CreateCompatibleBitmap(GDIScreenDC,bm->XSize,bm->YSize); | |
| SelectObject(GDIDC,prv->hbm); | |
| prv->bmi.bmiHeader.biSize = sizeof(prv->bmi.bmiHeader); | |
| prv->bmi.bmiHeader.biWidth = bm->XSize; | |
| prv->bmi.bmiHeader.biHeight = -bm->YSize; | |
| prv->bmi.bmiHeader.biPlanes = 1; | |
| prv->bmi.bmiHeader.biBitCount = 32; | |
| prv->bmi.bmiHeader.biCompression = BI_RGB; | |
| SetDIBits(GDIDC,prv->hbm,0,bm->YSize,bm->Data,&prv->bmi,DIB_RGB_COLORS); | |
| } | |
| /****************************************************************************/ | |
| sInt sHostFont::GetWidth(sChar *text,sInt len) | |
| { | |
| SIZE p; | |
| if(len==-1) | |
| len = sGetStringLen(text); | |
| GetTextExtentPoint32(GDIDC,text,len,&p); | |
| return p.cx; | |
| } | |
| /****************************************************************************/ | |
| void sHostFont::Print(sChar *text,sInt x,sInt y,sU32 c0,sInt len) | |
| { | |
| sInt i; | |
| c0 = ((c0&0xff0000)>>16)|(c0&0x00ff00)|((c0&0x0000ff)<<16); | |
| SetTextColor(GDIDC,c0); | |
| // if(len==-1) | |
| // len = 0x7fffffff; | |
| len &= 0x7fffffff; | |
| for(i=0;text[i]!=0 && i<len;i++); | |
| ExtTextOut(GDIDC,x,y,0,0,text,i,0); | |
| } | |
| /****************************************************************************/ | |
| void sHostFont::End(sBitmap *bm) | |
| { | |
| sInt i; | |
| prv->bmi.bmiHeader.biSize = sizeof(prv->bmi.bmiHeader); | |
| prv->bmi.bmiHeader.biWidth = bm->XSize; | |
| prv->bmi.bmiHeader.biHeight = -bm->YSize; | |
| prv->bmi.bmiHeader.biPlanes = 1; | |
| prv->bmi.bmiHeader.biBitCount = 32; | |
| prv->bmi.bmiHeader.biCompression = BI_RGB; | |
| GetDIBits(GDIDC,prv->hbm,0,bm->YSize,bm->Data,&prv->bmi,DIB_RGB_COLORS); | |
| SelectObject(GDIDC,GDIHBM); | |
| DeleteObject(prv->hbm); | |
| for(i=0;i<bm->XSize*bm->YSize;i++) | |
| bm->Data[i] |= 0xff000000; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| void sHostFont::Init(sChar *name,sInt height,sInt width,sInt style) | |
| { | |
| LOGFONT lf; | |
| TEXTMETRIC met; | |
| sVERIFY(prv->font==0); | |
| if(name[0]==0) | |
| name = "arial"; | |
| lf.lfHeight = -height; | |
| lf.lfWidth = width; | |
| lf.lfEscapement = 0; | |
| lf.lfOrientation = 0; | |
| lf.lfWeight = (style&2) ? FW_BOLD : FW_NORMAL; | |
| lf.lfItalic = (style&1) ? 1 : 0; | |
| lf.lfUnderline = 0; | |
| lf.lfStrikeOut = 0; | |
| lf.lfCharSet = DEFAULT_CHARSET; | |
| lf.lfOutPrecision = OUT_TT_PRECIS; | |
| lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; | |
| lf.lfQuality = (style&4) ? ANTIALIASED_QUALITY : NONANTIALIASED_QUALITY; | |
| lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; | |
| sCopyMem(lf.lfFaceName,name,32); | |
| prv->font = CreateFontIndirect(&lf); | |
| SetBkMode(GDIDC,TRANSPARENT); | |
| SelectObject(GDIScreenDC,prv->font); // win98: first select font into screen dc | |
| SelectObject(GDIDC,prv->font); | |
| SelectObject(GDIDC,GDIHBM); | |
| GetTextMetrics(GDIDC,&met); | |
| Height = met.tmHeight; | |
| Advance = met.tmHeight+met.tmExternalLeading; | |
| Baseline = met.tmHeight-met.tmDescent; | |
| } | |
| /****************************************************************************/ | |
| void sHostFont::Print(sBitmap *bm,sChar *text,sInt x,sInt y,sU32 color,sInt len) | |
| { | |
| Begin(bm); | |
| Print(text,x,y,color,len); | |
| End(bm); | |
| } | |
| /****************************************************************************/ | |
| sBool sHostFont::Prepare(sBitmap *bm,sChar *letters,sHostFontLetter *met) | |
| { | |
| sInt letter; | |
| sInt border; | |
| sInt x,y,xs,ys,h,w,a; | |
| SIZE size; | |
| sChar buffer[2]; | |
| sBool result; | |
| ABC abc; | |
| Begin(bm); | |
| h = Height; | |
| border = 2; | |
| x = border; | |
| y = border; | |
| xs = bm->XSize; | |
| ys = bm->YSize; | |
| sSetMem(met,0,sizeof(sHostFontLetter)*256); | |
| result = sTRUE; | |
| while(*letters) | |
| { | |
| letter = (*letters++)&0xff; | |
| buffer[0]=letter; | |
| buffer[1]=0; | |
| if(GetCharABCWidths(GDIDC,letter,letter,&abc)) | |
| { | |
| w = abc.abcB; | |
| a = 0; | |
| if(abc.abcA>0) | |
| w += abc.abcA; | |
| else | |
| a = -abc.abcA; | |
| if(abc.abcC>0) | |
| w += abc.abcC; | |
| } | |
| else | |
| { | |
| GetTextExtentPoint32(GDIDC,buffer,1,&size); | |
| w = size.cx; | |
| a = 0; | |
| } | |
| if(x+w>xs-border) | |
| { | |
| y+=h+border; | |
| x=border; | |
| if(y+h>ys-border) | |
| { | |
| result = sFALSE; | |
| break; | |
| } | |
| } | |
| Print(buffer,x+a,y,0xffffffff); | |
| met[letter].Location.x0 = x; | |
| met[letter].Location.y0 = y; | |
| met[letter].Location.x1 = x+w; | |
| met[letter].Location.y1 = y+h; | |
| met[letter].Pre = 0; | |
| met[letter].Post = 0; | |
| met[letter].Top = 0; | |
| x = x + w + border; | |
| } | |
| End(bm); | |
| return result; | |
| } | |
| /****************************************************************************/ | |
| sBool sHostFont::PrepareCheck(sInt xs,sInt ys,sChar *letters) | |
| { | |
| sInt letter; | |
| sInt border; | |
| sInt x,y,h,w; | |
| SIZE size; | |
| sChar buffer[2]; | |
| sBool result; | |
| h = Height; | |
| border = 2; | |
| x = border; | |
| y = border; | |
| result = sTRUE; | |
| while(*letters) | |
| { | |
| letter = (*letters++)&0xff; | |
| buffer[0]=letter; | |
| buffer[1]=0; | |
| GetTextExtentPoint32(GDIDC,buffer,1,&size); | |
| w = size.cx; | |
| if(x+w>xs-border) | |
| { | |
| y+=h+border; | |
| x=border; | |
| if(y+h>ys-border) | |
| { | |
| result = sFALSE; | |
| break; | |
| } | |
| } | |
| x = x + w + border; | |
| } | |
| // sDPrintF("letter %d\n",letter); | |
| return result; | |
| } | |
| /****************************************************************************/ | |
| void sSystem_::SetViewProject(const sMaterialEnv *env) | |
| { | |
| sVERIFY(env); | |
| sFloatDouble(); | |
| env->MakeProjectionMatrix(LastProjection); | |
| LastCamera = env->CameraSpace; | |
| LastCamera.TransR(); | |
| LastViewProject.Mul4(LastCamera,LastProjection); | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /*** ***/ | |
| /*** Shader ***/ | |
| /*** ***/ | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| #if !sPLAYER | |
| static void PrintReg(sU32 reg,sInt version) | |
| { | |
| sInt type,num; | |
| const sChar *name; | |
| static const sChar *psnames[32] = | |
| { | |
| "r","v","c","t", | |
| "?","?","?","?", | |
| "oC","oDepth","s","?", | |
| "?","?","?","?", | |
| "?","?","?","?", | |
| "?","?","?","?", | |
| "?","?","?","?", | |
| "?","?","?","?", | |
| }; | |
| static const sChar *vsnames[32] = | |
| { | |
| "r","v","c","a", | |
| "?","oD","oT","?", | |
| "?","?","?","?", | |
| "?","?","?","?", | |
| "?","?","?","?", | |
| "?","?","?","?", | |
| "?","?","?","?", | |
| "?","?","?","?", | |
| }; | |
| static const sChar *rastout[4] = | |
| { | |
| "oPos","oFog","oPsize","???" | |
| }; | |
| type = ((reg>>28)&7) + ((reg>>11)&3)*8; | |
| num = reg&0x7ff; | |
| if(version<0xffff0000) | |
| { | |
| name = vsnames[type]; | |
| if(type==4) | |
| name = rastout[sMin(num,3)]; | |
| } | |
| else | |
| { | |
| name = psnames[type]; | |
| } | |
| sDPrintF("%s%d",name,num); | |
| } | |
| void sSystem_::PrintShader(const sU32 *data) | |
| { | |
| static const sChar *opcodes[0x100] = | |
| { | |
| "nop" ,"mov" ,"add" ,"sub" ,"mad" ,"mul" ,"rcp" ,"rsq" , | |
| "dp3" ,"dp4" ,"min" ,"max" ,"slt" ,"sge" ,"exp" ,"log" , | |
| "lit" ,"dst" ,"lrp" ,"frc" ,"m4x4" ,"m4x3" ,"m3x4" ,"m3x3" , | |
| "m3x2" ,"call" ,"callnz","loop" ,"ret" ,"endloop","label","dcl" , | |
| "pow" ,"crs" ,"sgn" ,"abs" ,"nrm" ,"sincos","rep" ,"endrep", | |
| "if" ,"ifc" ,"else" ,"endif" ,"break" ,"breakc","mova" ,"defb" , | |
| "defi" ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| "texcoord","texkill","tex","texbem" ,"texbeml","texreg2ar","texreg2bg","texm3x2pad", | |
| "texm3x2tex","texm3x3pad","texm3x3tex",0,"texm3x3spec","texm3x3vspec","expp","logp", | |
| "cnd" ,"def" ,"texreg2rgb","texdp3tex","texm3x2depth","texdp3","texm3x3","texdepth", | |
| "cmp" ,"bem" ,"dp2add","dsx" ,"dsy" ,"texldd" ,"setp" ,"texldl", | |
| "breaklp",0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , | |
| "vs" ,"ps" ,0 ,0 ,0 ,"phase" ,"comment","end" , | |
| }; | |
| static const sU8 outin[0x100]= | |
| { | |
| 0x00,0x11,0x12,0x12 ,0x13,0x12,0x11,0x11, | |
| 0x12,0x12,0x12,0x12 ,0x12,0x12,0x11,0x11, // 0x80 = label | |
| 0x11,0x12,0x13,0x11 ,0x12,0x12,0x12,0x12, // 0x90 = dcl | |
| 0x12,0x80,0x80,0x80 ,0x00,0x00,0x80,0x90, // 0xb0 = def | |
| 0x12,0x12,0x11,0x11 ,0x11,0x20,0x00,0x00, | |
| 0x01,0x02,0x01,0x01 ,0x00,0x02,0x11,0x90, | |
| 0x90,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x10,0x01,0x10,0x11 ,0x11,0x11,0x11,0x12, | |
| 0x12,0x12,0x12,0x00 ,0x13,0x12,0x11,0x11, | |
| 0x13,0xb0,0x13,0x11 ,0x11,0x14,0x12,0x12, | |
| 0x13,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00, | |
| 0xa0,0xa0,0x00,0x00 ,0x00,0x00,0x00,0x00, // 0xa0 = version (faked!) | |
| }; | |
| static const sChar *usage[16] = | |
| { | |
| "position","blendweights","blendindices","normal", | |
| "psize","texcoord","tangent","binormal", | |
| "tessfactor","positiont","color","fog", | |
| "depth","sample","???","???", | |
| }; | |
| static const sChar *texkind[8] = | |
| { | |
| "(reg)","???","2d","cube","volume","???","???","???" | |
| }; | |
| static const sChar rz[] = "xyzw"; | |
| static const sChar *sourcepre[16] = | |
| { | |
| "" ,"-" ,"b_" ,"-b_" , | |
| "~" ,"~-" ,"?" ,"2*" , | |
| "-2*" ,"dz_" ,"dw_" ,"abs_" , | |
| "-abs_","!" ,"?" ,"?" | |
| }; | |
| sInt code,in,out,def,dcl,label; | |
| sInt i,len,j; | |
| sInt version; | |
| sU32 val; | |
| sInt komma; | |
| sInt line; | |
| sBool end = sFALSE; | |
| line = 1; | |
| while(!end) | |
| { | |
| val = *data; | |
| switch(val&0xffff0000) | |
| { | |
| case 0xffff0000: | |
| code = 0xf9; | |
| version = val; | |
| break; | |
| case 0xfffe0000: | |
| code = 0xf8; | |
| version = val; | |
| break; | |
| default: | |
| code = val&0x00ff; | |
| break; | |
| } | |
| if(val == 0xffff) | |
| end = sTRUE; | |
| in = out = def = dcl = label = komma = 0; | |
| switch(outin[code]&0xf0) | |
| { | |
| case 0x80: | |
| label = 1; | |
| break; | |
| case 0x90: | |
| dcl = 1; | |
| out = 1; | |
| break; | |
| case 0xa0: | |
| break; | |
| case 0xb0: | |
| def = 4; | |
| out = 1; | |
| break; | |
| default: | |
| in = outin[code]&0x0f; | |
| out = (outin[code]&0x70)>>4; | |
| break; | |
| } | |
| if(code==0x42 && version==0xffff0200) | |
| in = 2, out =1; | |
| len = 1+in+out+dcl+label; | |
| sDPrintF("%04d ",line++); | |
| for(i=0;i<5;i++) | |
| { | |
| if(i<len) | |
| sDPrintF("%08x ",data[i]); | |
| else | |
| sDPrintF(" "); | |
| } | |
| data++; | |
| if((val & 0x40000000) && ((val >> 16) != 0xffff)) | |
| sDPrintF("+"); | |
| else | |
| sDPrintF(" "); | |
| sDPrintF("%-08s",opcodes[code]); | |
| if((outin[code]&0xf0)==0xa0) | |
| sDPrintF("%04x",version); | |
| for(i=0;i<label;i++) | |
| { | |
| if(komma) sDPrintF(","); komma=1; | |
| sDPrintF("label"); | |
| data++; | |
| } | |
| for(i=0;i<dcl;i++) | |
| { | |
| if(komma) sDPrintF(","); komma=1; | |
| val = *data++; | |
| if(version<0xffff0000) | |
| sDPrintF("%s%d",usage[val&0x0f],(val&0xf0000)>>16); | |
| else | |
| sDPrintF("%s",texkind[(val>>27)&7]); | |
| } | |
| for(i=0;i<out;i++) | |
| { | |
| if(komma) sDPrintF(","); komma=1; | |
| val = *data++; | |
| PrintReg(val,version); | |
| if(val&0x00100000) sDPrintF("_sat"); | |
| if(val&0x00200000) sDPrintF("_pp"); | |
| if(val&0x00400000) sDPrintF("_msamp"); | |
| j = (val&0xf0000)>>16; | |
| if(j!=15) | |
| { | |
| sDPrintF("."); | |
| if(j&1) sDPrintF("x"); | |
| if(j&2) sDPrintF("y"); | |
| if(j&4) sDPrintF("z"); | |
| if(j&8) sDPrintF("w"); | |
| } | |
| } | |
| for(i=0;i<in;i++) | |
| { | |
| if(komma) sDPrintF(","); komma=1; | |
| val = *data++; | |
| sDPrintF("%s",sourcepre[(val>>24)&15]); | |
| PrintReg(val,version); | |
| if(val&0x00002000) sDPrintF("[a]"); | |
| j = (val&0x00ff0000)>>16; | |
| if(j!=0xe4) | |
| sDPrintF(".%c%c%c%c",rz[(j>>0)&3],rz[(j>>2)&3],rz[(j>>4)&3],rz[(j>>6)&3]); | |
| } | |
| for(i=0;i<def;i++) | |
| { | |
| if(komma) sDPrintF(","); komma=1; | |
| val = *data++; | |
| sF32 valf = *((sF32 *) &val); | |
| sDPrintF("%7.3f",valf); | |
| } | |
| sDPrintF("\n"); | |
| } | |
| sDPrintF(".\n"); | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| // Compare two state lists. | |
| static sBool checkStatesEqual(const sU32 *st1,const sU32 *st2) | |
| { | |
| sInt i; | |
| for(i=0;st1[i] == st2[i] && ((i&1) || st1[i] != ~0U);i++); | |
| return st1[i] == st2[i]; | |
| } | |
| sInt sSystem_::MtrlAddSetup(const sU32 *states,const sU32 *vs,const sU32 *ps) | |
| { | |
| // calculate length of state array | |
| sInt stateLen; | |
| for(stateLen=0;states[stateLen] != ~0U;stateLen+=2); | |
| stateLen += 2; | |
| #if !sINTRO // full-featured version | |
| // create copy of state array + insertion sort by state index | |
| sU32 *stateCopy = new sU32[stateLen]; | |
| for(sInt i=0;i<stateLen;i+=2) | |
| { | |
| sInt j; | |
| sU32 key = states[i]; | |
| for(j=i-2;j>=0 && stateCopy[j] > key;j-=2) | |
| { | |
| stateCopy[j+2] = stateCopy[j+0]; | |
| stateCopy[j+3] = stateCopy[j+1]; | |
| } | |
| stateCopy[j+2] = states[i+0]; | |
| stateCopy[j+3] = states[i+1]; | |
| } | |
| // check whether this shader is unique | |
| sInt firstFree = -1; | |
| sInt vsId = GetShader(vs); | |
| sInt psId = GetShader(ps); | |
| for(sInt i=0;i<MAX_SETUPS;i++) | |
| { | |
| if(!Setups[i].RefCount) | |
| { | |
| if(firstFree == -1) | |
| firstFree = i; | |
| continue; | |
| } | |
| else if(checkStatesEqual(stateCopy,Setups[i].States) // identical with this shader? | |
| && vsId == Setups[i].VSId && psId == Setups[i].PSId) | |
| { | |
| Shaders[vsId].Release(); | |
| Shaders[psId].Release(); | |
| Setups[i].AddRef(); | |
| delete[] stateCopy; | |
| return i; | |
| } | |
| } | |
| if(firstFree == -1) // no more setup slots left | |
| { | |
| #if !sINTRO | |
| sDPrintF("out of material setup slots!\n"); | |
| #endif | |
| return sINVALID; | |
| } | |
| // create new shader setup | |
| sMaterialSetup *setup = &Setups[firstFree]; | |
| // copy source data and we're set | |
| setup->RefCount = 1; | |
| setup->States = stateCopy; | |
| setup->VSId = vsId; | |
| setup->PSId = psId; | |
| setup->VS = (IDirect3DVertexShader9 *) Shaders[vsId].Shader; | |
| setup->PS = (IDirect3DPixelShader9 *) Shaders[psId].Shader; | |
| #else // bare-bone version for intros without equality check or anything | |
| sInt firstFree; | |
| HRESULT hr; | |
| for(firstFree=0;firstFree<MAX_SETUPS;firstFree++) | |
| { | |
| if(!Setups[firstFree].RefCount) | |
| break; | |
| } | |
| if(firstFree == MAX_SETUPS) | |
| return sINVALID; | |
| sMaterialSetup *setup = &Setups[firstFree]; | |
| hr = DXDev->CreateVertexShader((DWORD *) vs,&setup->VS); | |
| if(FAILED(hr)) | |
| return sINVALID; | |
| hr = DXDev->CreatePixelShader((DWORD *) ps,&setup->PS); | |
| if(FAILED(hr)) | |
| return sINVALID; | |
| setup->RefCount = 1; | |
| setup->States = new sU32[stateLen]; | |
| setup->VSId = setup->PSId = sINVALID; | |
| sCopyMem4(setup->States,states,stateLen); | |
| #endif | |
| return firstFree; | |
| } | |
| void sSystem_::MtrlAddRefSetup(sInt sid) | |
| { | |
| // sanity checks | |
| sVERIFY(sid >= 0 && sid < MAX_SETUPS); | |
| sVERIFY(Setups[sid].RefCount); | |
| Setups[sid].AddRef(); | |
| } | |
| void sSystem_::MtrlRemSetup(sInt sid) | |
| { | |
| // sanity checks | |
| sVERIFY(sid >= 0 && sid < MAX_SETUPS); | |
| sVERIFY(Setups[sid].RefCount); | |
| Setups[sid].Release(); | |
| } | |
| void sSystem_::MtrlClearCaches() | |
| { | |
| CurrentSetupId = sINVALID; | |
| CurrentVS = 0; | |
| CurrentPS = 0; | |
| for(sInt i=0;i<MAX_TEXSTAGE;i++) | |
| CurrentTextures[i] = sINVALID; | |
| for(sInt i=0;i<0x310;i++) | |
| CurrentStates[i] = 0xfefefefe; // let's hope we never actually want this value | |
| } | |
| void sSystem_::MtrlSetSetup(sInt sid) | |
| { | |
| if(sid == CurrentSetupId) | |
| return; | |
| sZONE(MtrlSetSetup); | |
| // sanity checks | |
| sVERIFY(sid >= 0 && sid < MAX_SETUPS); | |
| sMaterialSetup *setup = &Setups[sid]; | |
| sVERIFY(setup->RefCount > 0); | |
| if(CurrentSetupId != sINVALID) | |
| Setups[CurrentSetupId].Release(); | |
| setup->AddRef(); | |
| // set states | |
| for(sU32 *st = setup->States;st[0] != ~0U;st += 2) | |
| { | |
| sU32 state = st[0]; | |
| sVERIFY(state < 0x310); | |
| if(st[1] != CurrentStates[state]) | |
| { | |
| SetState(state,st[1]); | |
| CurrentStates[state] = st[1]; | |
| } | |
| } | |
| // set vertex shader | |
| if(setup->VS != CurrentVS) | |
| { | |
| HRESULT hr = DXDev->SetVertexShader(setup->VS); | |
| sVERIFY(SUCCEEDED(hr)); | |
| CurrentVS = setup->VS; | |
| } | |
| // set pixel shader | |
| if(setup->PS != CurrentPS) | |
| { | |
| HRESULT hr = DXDev->SetPixelShader(setup->PS); | |
| sVERIFY(SUCCEEDED(hr)); | |
| CurrentPS = setup->PS; | |
| } | |
| CurrentSetupId = sid; | |
| } | |
| void sSystem_::MtrlSetInstance(const sMaterialInstance &inst) | |
| { | |
| // set textures | |
| for(sInt i=0;i<inst.NumTextures;i++) | |
| { | |
| sInt texIndex = inst.Textures[i]; | |
| if(texIndex != CurrentTextures[i]) | |
| { | |
| IDirect3DBaseTexture9 *tex = 0; | |
| if(texIndex >= 0 && texIndex < MAX_TEXTURE) | |
| tex = Textures[texIndex].Tex; | |
| else if(texIndex == -2) | |
| tex = DXNormalCube; | |
| else if(texIndex == -3) | |
| tex = DXAttenuationVolume; | |
| else if(texIndex == -4) | |
| tex = DXTinyNormalCube; | |
| HRESULT hr = DXDev->SetTexture(i,tex); | |
| sVERIFY(SUCCEEDED(hr)); | |
| CurrentTextures[i] = texIndex; | |
| } | |
| } | |
| // vertex+pixel shader constants (no special caching) | |
| if(inst.NumVSConstants) | |
| DXDev->SetVertexShaderConstantF(0,(sF32 *) inst.VSConstants,inst.NumVSConstants); | |
| if(inst.NumPSConstants) | |
| DXDev->SetPixelShaderConstantF(0,(sF32 *) inst.PSConstants,inst.NumPSConstants); | |
| } | |
| void sSystem_::MtrlSetVSConstants(sInt first,const sVector *constants,sInt count) | |
| { | |
| if(count) | |
| DXDev->SetVertexShaderConstantF(first,&constants->x,count); | |
| } | |
| void sSystem_::MtrlSetPSConstants(sInt first,const sVector *constants,sInt count) | |
| { | |
| if(count) | |
| DXDev->SetPixelShaderConstantF(first,&constants->x,count); | |
| } | |
| /****************************************************************************/ | |
| #if !sPLAYER | |
| static PAVIFILE aviFile = 0; | |
| static PAVISTREAM aviVid = 0,aviVidC = 0; | |
| static sInt aviXRes,aviYRes; | |
| static IDirect3DSurface9 *aviSurface = 0; | |
| static sInt aviTarget = sINVALID; | |
| static sU8 *aviBuffer = 0; | |
| static sInt aviFrameCount; | |
| sBool sSystem_::VideoStart(sChar *filename,sF32 fpsrate,sInt xRes,sInt yRes) | |
| { | |
| AVISTREAMINFO asi; | |
| AVICOMPRESSOPTIONS aco; | |
| AVICOMPRESSOPTIONS FAR *optlist[1]; | |
| BITMAPINFOHEADER bmi; | |
| sBool gotOptions = sFALSE; | |
| sBool error = sTRUE; | |
| VideoEnd(); | |
| // clamp resolution | |
| if(xRes > 1024) | |
| { | |
| xRes = 1024; | |
| yRes = sMulDiv(yRes,1024,xRes); | |
| } | |
| if(yRes > 512) | |
| { | |
| yRes = 512; | |
| xRes = sMulDiv(xRes,512,yRes); | |
| } | |
| AVIFileInit(); | |
| // create avi file | |
| if(AVIFileOpen(&aviFile,filename,OF_WRITE|OF_CREATE,NULL) != AVIERR_OK) | |
| { | |
| sDPrintF("AVIFileOpen failed\n"); | |
| goto cleanup; | |
| } | |
| // initialize video stream header | |
| WINZERO(asi); | |
| asi.fccType = streamtypeVIDEO; | |
| asi.dwScale = 10000; | |
| asi.dwRate = 10000*fpsrate + 0.5f; | |
| asi.dwSuggestedBufferSize = xRes * yRes * 3; | |
| SetRect(&asi.rcFrame,0,0,xRes,yRes); | |
| sCopyString(asi.szName,"Video",sizeof(asi.szName)); | |
| // create video stream | |
| if(AVIFileCreateStream(aviFile,&aviVid,&asi) != AVIERR_OK) | |
| { | |
| sDPrintF("AVIFileCreateStream failed\n"); | |
| goto cleanup; | |
| } | |
| // get coding options | |
| WINZERO(aco); | |
| optlist[0] = &aco; | |
| gotOptions = sTRUE; | |
| if(!AVISaveOptions((HWND) Screen[0].Window,0,1,&aviVid,optlist)) | |
| { | |
| sDPrintF("AVISaveOptions failed\n"); | |
| goto cleanup; | |
| } | |
| // create compressed stream | |
| if(AVIMakeCompressedStream(&aviVidC,aviVid,&aco,0) != AVIERR_OK) | |
| { | |
| sDPrintF("AVIMakeCompressedStream failed\n"); | |
| goto cleanup; | |
| } | |
| // set stream format | |
| WINZERO(bmi); | |
| bmi.biSize = sizeof(bmi); | |
| bmi.biWidth = xRes; | |
| bmi.biHeight = yRes; | |
| bmi.biPlanes = 1; | |
| bmi.biBitCount = 24; | |
| bmi.biCompression = BI_RGB; | |
| AVIStreamSetFormat(aviVidC,0,&bmi,sizeof(bmi)); | |
| if(FAILED(DXDev->CreateOffscreenPlainSurface(1024,512,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&aviSurface,0))) | |
| { | |
| sDPrintF("CreateOffscreenPlainSurface failed\n"); | |
| goto cleanup; | |
| } | |
| aviTarget = AddTexture(1024,512,sTF_A8R8G8B8,0); | |
| if(aviTarget == sINVALID) | |
| { | |
| sDPrintF("Couldn't create AVI rendertarget\n"); | |
| goto cleanup; | |
| } | |
| error = sFALSE; | |
| sDPrintF("Video recording started.\n"); | |
| aviXRes = xRes; | |
| aviYRes = yRes; | |
| aviBuffer = new sU8[xRes * yRes * 3]; | |
| aviFrameCount = 0; | |
| cleanup: | |
| if(gotOptions) | |
| AVISaveOptionsFree(1,optlist); | |
| if(error) | |
| VideoEnd(); | |
| return !error; | |
| } | |
| void sSystem_::VideoViewport(sViewport &vp) | |
| { | |
| vp.InitTex(aviTarget); | |
| vp.Window.Init(0,0,aviXRes,aviYRes); | |
| } | |
| sInt sSystem_::VideoWriteFrame(sF32 &u1,sF32 &v1) | |
| { | |
| D3DLOCKED_RECT lr; | |
| IDirect3DSurface9 *surface = 0; | |
| sBool error = sTRUE; | |
| if(aviTarget == sINVALID) | |
| return sINVALID; | |
| u1 = 0.0f; | |
| v1 = 0.0f; | |
| // first, get rendertarget surface | |
| if(FAILED(Textures[aviTarget].Tex->GetSurfaceLevel(0,&surface))) | |
| { | |
| sDPrintF("couldn't get surface level!\n"); | |
| goto cleanup; | |
| } | |
| // copy rendertarget data | |
| if(FAILED(DXDev->GetRenderTargetData(surface,aviSurface))) | |
| { | |
| sDPrintF("couldn't get render target data!\n"); | |
| goto cleanup; | |
| } | |
| // lock | |
| if(FAILED(aviSurface->LockRect(&lr,0,D3DLOCK_READONLY))) | |
| { | |
| sDPrintF("couldn't lock.\n"); | |
| goto cleanup; | |
| } | |
| // read data and convert in the process | |
| for(sInt y=0;y<aviYRes;y++) | |
| { | |
| sU32 *src = (sU32 *) ((sU8 *) lr.pBits + lr.Pitch * y); | |
| sU8 *dst = aviBuffer + (aviYRes - 1 - y) * aviXRes * 3; | |
| for(sInt x=0;x<aviXRes;x++) | |
| { | |
| sU32 srcv = *src++; | |
| *dst++ = (srcv >> 0) & 0xff; // blue | |
| *dst++ = (srcv >> 8) & 0xff; // green | |
| *dst++ = (srcv >> 16) & 0xff; // red | |
| } | |
| } | |
| // unlock + encode | |
| aviSurface->UnlockRect(); | |
| AVIStreamWrite(aviVidC,aviFrameCount,1,aviBuffer,3*aviXRes*aviYRes,0,0,0); | |
| error = sFALSE; | |
| aviFrameCount++; | |
| u1 = aviXRes / 1024.0f; | |
| v1 = aviYRes / 512.0f; | |
| cleanup: | |
| if(surface) | |
| surface->Release(); | |
| if(error) | |
| return sINVALID; | |
| else | |
| return aviTarget; | |
| } | |
| void sSystem_::VideoEnd() | |
| { | |
| delete[] aviBuffer; | |
| aviBuffer = 0; | |
| if(aviTarget != sINVALID) | |
| { | |
| RemTexture(aviTarget); | |
| aviTarget = sINVALID; | |
| } | |
| if(aviSurface) | |
| { | |
| aviSurface->Release(); | |
| aviSurface = 0; | |
| } | |
| if(aviVidC) | |
| { | |
| AVIStreamRelease(aviVidC); | |
| aviVidC = 0; | |
| } | |
| if(aviVid) | |
| { | |
| AVIStreamRelease(aviVid); | |
| aviVid = 0; | |
| } | |
| if(aviFile) | |
| { | |
| AVIFileRelease(aviFile); | |
| aviFile = 0; | |
| } | |
| AVIFileExit(); | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| /****************************************************************************/ |