Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
9655 lines (8460 sloc) 245 KB
// This file is distributed under a BSD license. See LICENSE.txt for details.
#include "_types.hpp"
#include "_start.hpp"
#if sLINK_ENGINE
#include "_startdx.hpp"
#endif
#if sLINK_UTIL
#include "_util.hpp" // for sPerfMon->Flip()
#endif
#define WINVER 0x500
#define _WIN32_WINNT 0x0500
#define DIRECTINPUT_VERSION 0x0800
#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;}
#define DXERROR(hr) {if(FAILED(hr))sFatal("%s(%d) : directx error %08x (%d)",__FILE__,__LINE__,hr,hr&0x3fff);}
#undef DeleteFile
#undef GetCurrentDirectory
#undef LoadBitmap
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"dinput.lib")
#if !sINTRO
#pragma comment(lib,"dxguid.lib")
#endif
#define LOGGING 0 // log all create and release calls
#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;}
#define DXERROR(hr) {if(FAILED(hr))sFatal("%s(%d) : directx error %08x (%d)",__FILE__,__LINE__,hr,hr&0x3fff);}
sMAKEZONE(FlipLock,"FlipLock",0xffff0000);
/****************************************************************************/
/****************************************************************************/
/*** ***/
/*** System Initialisation ***/
/*** ***/
/****************************************************************************/
/****************************************************************************/
//#if !sINTRO
class sBroker_ *sBroker;
//#endif
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;
HWND MsgWin;
sSystem_ *sSystem;
static sU64 sPerfFrame;
static sF64 sPerfKalibFactor = 1.0f/1000;
static sU64 sPerfKalibRDTSC;
static sU64 sPerfKalibQuery;
/****************************************************************************/
/****************************************************************************/
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_SHORT4 ,0,D3DDECLUSAGE_NORMAL ,0 },
{ 0,20,D3DDECLTYPE_SHORT2 ,0,D3DDECLUSAGE_TANGENT ,0 },
{ 0,24,D3DDECLTYPE_FLOAT2 ,0,D3DDECLUSAGE_TEXCOORD ,0 },
D3DDECL_END()
};
static D3DVERTEXELEMENT9 DeclXYZW[] =
{
{ 0, 0,D3DDECLTYPE_FLOAT4 ,0,D3DDECLUSAGE_POSITION ,0 },
D3DDECL_END()
};
static FVFTableStruct FVFTable[] =
{
{ 0,0 },
{ 32,DeclDefault },
{ 32,DeclDouble },
{ 64,DeclTSpace },
{ 16,DeclCompact },
{ 16,DeclXYZW },
{ 32,DeclTSpace3 },
};
#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;
static sInt DXSLastFrameTime;
#define DXSSAMPLES 0x2000
static sInt DXSWriteSample;
static sInt DXSReadSample;
static sInt DXSLastTotalSample;
static HANDLE DXSThread;
static ULONG DXSThreadId;
static sInt volatile DXSRun;
static CRITICAL_SECTION DXSLock;
static HANDLE DXSEvent;
unsigned long __stdcall ThreadCode(void *);
#endif
/****************************************************************************/
/*** ***/
/*** 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,
};
/****************************************************************************/
/*** ***/
/*** Heap Memory Management ***/
/*** ***/
/****************************************************************************/
sInt 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) sFatal("ran out of virtual memory...");
// sSetMem(p,0x12,size);
// sDPrintF("%10d : (%d)\n",MemoryUsedCount,size);
MemoryUsedCount+=_msize(p);
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) sFatal("ran out of virtual memory...");
// sSetMem(p,0x12,size);
MemoryUsedCount+=_msize(p);
// sDPrintF("%10d : %d\n",MemoryUsedCount,size);
// if(size>1024*1024)
// sDPrintF("geht garnicht!\n");
return p;
}
void __cdecl operator delete(void *p)
{
if(p)
{
MemoryUsedCount-=_msize(p);
#if !sRELEASE
_free_dbg(p,_NORMAL_BLOCK);
#else
free(p);
#endif
}
}
#define new new(__FILE__,__LINE__)
#endif
#if sINTRO
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
/****************************************************************************/
/****************************************************************************/
/*** ***/
/*** Startup, Commandline ***/
/*** ***/
/****************************************************************************/
/****************************************************************************/
#if sCOMMANDLINE
#include <stdio.h>
void sPrint(sChar *text)
{
printf("%s",text);
sDPrint(text);
}
void __cdecl sPrintF(sChar *format,...)
{
static sChar buffer[1024];
sFormatString(buffer,sizeof(buffer),format,&format);
sPrint(buffer);
}
int main(int argc,char **argv)
{
sSystem = new sSystem_;
sSetMem(((sU8 *)sSystem)+4,0,sizeof(sSystem_)-4);
sSystem->InitX();
sAppHandler(sAPPCODE_INIT,0);
sAppHandler(sAPPCODE_EXIT,0);
}
void sSystem_::InitX()
{
timeBeginPeriod(1);
WStartTime = timeGetTime();
sSetRndSeed(timeGetTime()&0x7fffffff);
sBroker = new sBroker_;
sAppHandler(sAPPCODE_FRAME,0);
sBroker->Free();
sBroker->Dump();
delete sBroker;
sBroker = 0;
#if !sRELEASE
getchar();
#endif
}
/*
void sSystem_::Exit()
{
}
void sSystem_::Tag()
{
}
sNORETURN void sSystem_::Abort(sChar *msg)
{
WAborting = sTRUE;
_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);
}
void sSystem_::Log(sChar *s)
{
if(!sFatality && !sAppHandler(sAPPCODE_DEBUGPRINT,(sU32) s))
OutputDebugString(s);
}
*/
#endif
/****************************************************************************/
/****************************************************************************/
/*** ***/
/*** Startup, without intro ***/
/*** ***/
/****************************************************************************/
/****************************************************************************/
#if !sCOMMANDLINE
#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
__try
{
__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
}
}
__except(1)
{
return;
}
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(sSystem->CpuMask & sCPU_SSE)
{
__try
{
__asm
{
orps xmm0,xmm1
}
}
__except(1)
{
sSystem->CpuMask &= ~(sCPU_SSE|sCPU_SSE2);
}
}
}
/****************************************************************************/
static LRESULT WINAPI MainWndProc(HWND win,UINT msg,WPARAM wparam,LPARAM lparam)
{
MsgWin = win;
return sSystem->Msg(msg,wparam,lparam);
}
/****************************************************************************/
int APIENTRY WinMain(HINSTANCE inst,HINSTANCE prev,LPSTR cmdline,int show)
{
WInst = inst;
WCmdLine = cmdline;
if(!sAppHandler(sAPPCODE_CONFIG,0))
sSetConfig(sSF_DIRECT3D);
sSystem->InitX();
delete sSystem;
sDPrintF("Memory Left: %d bytes\n",MemoryUsedCount);
return 0;
}
/****************************************************************************/
void sSetConfig(sU32 flags,sInt xs,sInt ys)
{
sSystem = new sSystem_;
sSetMem(((sU8 *)sSystem)+4,0,sizeof(sSystem_)-4);
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;
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);
sSystem->ConfigX = r.right-r.left;
sSystem->ConfigY = r.bottom-r.top;
}
}
}
if(sSystem->WScreenCount<MAX_SCREEN)
{
if(sSystem->WScreenCount > 0)
pwin = (HWND)sSystem->Screen[0].Window;
else
pwin = 0;
win = CreateWindowEx(0,"kk",sAPPNAME " v" sVERSION,WS_OVERLAPPEDWINDOW|WS_VISIBLE,r.left,r.top,sSystem->ConfigX,sSystem->ConfigY,pwin,0,WInst,0);
sSystem->WWindowedStyle = WS_OVERLAPPEDWINDOW|WS_VISIBLE;
sSystem->Screen[sSystem->WScreenCount].Window = (sU32) 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();
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)|_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
sChar *test = new sChar[16];
sCopyString(test,"TestLeak",16);
// find dlls
d3dlib = ::LoadLibraryA("d3d9.dll");
if(d3dlib==0)
sFatal("you need directx 9 (or better)\nto run this program.\ntry downloading it at\nwww.microsoft.com");
Direct3DCreate9P = (Direct3DCreate9T) GetProcAddress(d3dlib,"Direct3DCreate9");
sVERIFY(Direct3DCreate9P);
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);
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(101));
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;
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,"ps13",4)==0)
{
CmdShaderLevel = sPS_13;
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
{
break;
}
}
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
ZBufXSize = ZBufYSize = 0;
ZBufFormat = 0;
ZBuffer = 0;
for(i=0;i<MAX_TEXTURE;i++)
Textures[i].Flags = 0;
InitScreens();
_control87(_PC_24|_RC_NEAR,MCW_PC|MCW_RC);
#if sUSE_DIRECTSOUND
if(!InitDS())
sFatal("could not initialize DirectSound");
#endif
// main loop
sAppHandler(sAPPCODE_INIT,0);
msg.message = WM_NULL;
PeekMessage(&msg,0,0,0,PM_NOREMOVE);
while(msg.message!=WM_QUIT)
{
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);
}
#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();
sBroker->Free();
sBroker->Dump();
delete sBroker;
sBroker = 0;
FreeLibrary(d3dlib);
FreeLibrary(dilib);
FreeLibrary(dslib);
}
/****************************************************************************/
sInt sSystem_::Msg(sU32 msg,sU32 wparam,sU32 lparam)
{
PAINTSTRUCT ps;
HDC hdc;
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;
}
win = MsgWin;
if(WAborting || nr==-1)
return DefWindowProc(win,msg,wparam,lparam);
result = 0;
switch(msg)
{
case WM_PAINT:
hdc = BeginPaint(win,&ps);
EndPaint(win,&ps);
if(/*WActiveCount!=0 &&*/ !WFullscreen)
Render();
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_SETFOCUS:
WFocus = 1;
break;
case WM_KILLFOCUS:
WFocus = 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);
#if !sUSE_DIRECTINPUT
MouseX = WMouseX;
MouseY = WMouseY;
#endif
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);
if(!DXD)
{
DXD = (*Direct3DCreate9P)(D3D_SDK_VERSION);
sVERIFY(DXD);
}
ZBufFormat=D3DFMT_D24S8;
for(nr=0;nr<WScreenCount;nr++)
{
// determine n
Screen[nr].SFormat=D3DFMT_A8R8G8B8;
Screen[nr].ZFormat=ZBufFormat;
WINZERO(d3dpp[nr]);
d3dpp[nr].BackBufferFormat = (enum _D3DFORMAT) Screen[nr].SFormat;
d3dpp[nr].EnableAutoDepthStencil = sFALSE;
d3dpp[nr].SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp[nr].BackBufferCount = 1;
d3dpp[nr].PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp[nr].Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;// | D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
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);
}
}
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))
sFatal("could not create screen");
}
for(i=1;i<FVFMax;i++)
DXDev->CreateVertexDeclaration(FVFTable[i].Info,&FVFTable[i].Decl);
}
else
{
if(DXNormalCube)
{
DXNormalCube->Release();
DXNormalCube = 0;
}
if(ZBuffer)
{
#if LOGGING
sDPrintF("Release ZBuffer\n");
#endif
ZBuffer->Release();
ZBuffer = 0;
}
for(i=0;i<MAX_GEOHANDLE;i++)
{
if(GeoHandle[i].Mode!=0)
{
if(GeoHandle[i].VertexBuffer>=3)
GeoBuffer[GeoHandle[i].VertexBuffer].Free();
if(GeoHandle[i].IndexBuffer>=3)
GeoBuffer[GeoHandle[i].IndexBuffer].Free();
}
GeoHandle[i].VertexCount = 0;
GeoHandle[i].VertexBuffer = 0;
GeoHandle[i].IndexCount = 0;
GeoHandle[i].IndexBuffer = 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
#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)
{
#if LOGGING
sDPrintF("Release Rendertarget\n");
#endif
Textures[i].Tex->Release();
Textures[i].Tex=0;
}
}
hr = DXDev->Reset(d3dpp);
if(FAILED(hr))
{
WDeviceLost = 1;
return;
}
}
// initialize gpumask
if(caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) GpuMask |= sGPU_TWOSIDESTENCIL;
// init buffer management
CreateGeoBuffer(0,1,1,MAX_DYNVBSIZE);
CreateGeoBuffer(1,1,0,MAX_DYNIBSIZE);
CreateGeoBuffer(2,0,0,2*0x8000/4*6);
DXERROR(GeoBuffer[2].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[2].IB->Unlock());
if((caps.PixelShaderVersion&0xffff)!=0x0000)
{
MakeCubeNormalizer();
// MakeSpecularLookupTex();
}
else
{
// SpecularLookupTex = sINVALID;
// NullBumpTex = sINVALID;
}
// set some defaults
DXDev->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
DXDev->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);
DXDev->SetRenderState(D3DRS_LIGHTING,0);
WDeviceLost = 0;
if(WFullscreen)
{
GetWindowRect((HWND)Screen[0].Window,&r);
ClipCursor(&r);
ShowCursor(0);
}
else
{
ClipCursor(0);
ShowCursor(1);
}
ReCreateZBuffer();
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));
}
}
}
/****************************************************************************/
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);
}
for(i=0;i<MAX_TEXTURE;i++)
{
if(Textures[i].Flags & sTIF_RENDERTARGET)
{
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));
if(ZBuffer)
{
ZBuffer->Release();
ZBuffer=0;
}
#if LOGGING
sDPrintF("Create ZBuffer %dx%d\n",xs,ys);
#endif
DXERROR(DXDev->CreateDepthStencilSurface(xs,ys,(D3DFORMAT) ZBufFormat,D3DMULTISAMPLE_NONE,0,FALSE,&ZBuffer,0));
ZBufXSize=xs;
ZBufYSize=ys;
DXERROR(DXDev->SetDepthStencilSurface(ZBuffer));
}
}
/****************************************************************************/
void sSystem_::ExitScreens()
{
sInt i;
for(i=0;i<MAX_TEXTURE;i++)
{
if(Textures[i].Tex)
{
Textures[i].Tex->Release();
Textures[i].Tex=0;
}
}
if(DXNormalCube)
{
DXNormalCube->Release();
DXNormalCube = 0;
}
// if(SpecularLookupTex != sINVALID)
// RemTexture(SpecularLookupTex);
// if(NullBumpTex != sINVALID)
// RemTexture(NullBumpTex);
if(ZBuffer)
{
ZBuffer->Release();
ZBuffer = 0;
}
if(DXReadTex)
DXReadTex->Release();
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();
}
#if sUSE_SHADERS
for(i=0;i<MAX_SHADERS;i++)
{
if(Shaders[i].ShaderData)
{
delete[] Shaders[i].ShaderData;
Shaders[i].ShaderData = 0;
}
sVERIFY(Shaders[i].VS==0);
sVERIFY(Shaders[i].PS==0);
}
#endif
// 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();
DXDev->Release();
DXDev = 0;
DXD->Release();
DXD = 0;
}
#endif
#endif
/****************************************************************************/
/*** ***/
/*** Startup, with sINTRO ***/
/*** ***/
/****************************************************************************/
#if !sCOMMANDLINE
#if sINTRO
/****************************************************************************/
static LRESULT WINAPI MainWndProc(HWND win,UINT msg,WPARAM wparam,LPARAM lparam)
{
MsgWin = win;
PAINTSTRUCT ps;
HDC hdc;
sInt i;
switch(msg)
{
case WM_PAINT:
hdc = BeginPaint(win,&ps);
EndPaint(win,&ps);
// if(/*WActiveCount!=0 &&*/ !sSystem->WFullscreen)
// sSystem->Render();
break;
case WM_SETCURSOR:
SetCursor(0);
return 0;
case WM_LBUTTONDOWN:
sSystem->MouseButtons |= 1;
// sSystem->MouseButtonsSave |= 1;
// KeyQual |= sKEYQ_MOUSEL;
if(sSystem->KeyIndex < MAX_KEYBUFFER)
sSystem->KeyBuffer[sSystem->KeyIndex++] = sKEY_MOUSEL;
break;
case WM_LBUTTONUP:
sSystem->MouseButtons &= ~1;
// sSystem->KeyQual &= ~sKEYQ_MOUSEL;
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);
}
/****************************************************************************/
#if !sINTRO || !sRELEASE
int APIENTRY WinMain(HINSTANCE inst,HINSTANCE prev,LPSTR cmdline,int show)
{
WInst = inst;
WCmdLine = cmdline;
#else
void WinMainCRTStartup()
{
WInst = GetModuleHandle(0);
#endif
sSystem = new sSystem_;
sSetMem(((sU8 *)sSystem)+4,0,sizeof(sSystem_)-4);
sSystem->InitX();
delete sSystem;
ExitProcess(0);
}
/****************************************************************************/
void sSystem_::InitX()
{
WNDCLASS wc;
MSG msg;
sBool gotmsg;
sInt i;
// init system
sSystem->ConfigFlags = sSF_DIRECT3D;
sSystem->ConfigX = 800;
sSystem->ConfigY = 600;
// find dlls
d3dlib = ::LoadLibraryA("d3d9.dll");
if(d3dlib==0)
sFatal("you need directx 9 (or better)\nto run this program.\ntry downloading it at\nwww.microsoft.com");
Direct3DCreate9P = (Direct3DCreate9T) GetProcAddress(d3dlib,"Direct3DCreate9");
sVERIFY(Direct3DCreate9P);
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 = "kk";
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;
Screen[0].Window = (sU32) CreateWindowEx(
0,
"kk",
"kk",
#if sFULLSCREEN
WS_POPUP|WS_VISIBLE,
#else
WS_OVERLAPPEDWINDOW|WS_VISIBLE,
#endif
0,0,
ConfigX,ConfigY,
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;
InitScreens();
sFloatFix();
#if sUSE_DIRECTSOUND
if(!InitDS())
sFatal("could not initialize DirectSound");
#endif
// main loop
sAppHandler(sAPPCODE_INIT,0);
msg.message = WM_NULL;
PeekMessage(&msg,0,0,0,PM_NOREMOVE);
while(msg.message!=WM_QUIT)
{
gotmsg = (PeekMessage(&msg,0,0,0,PM_REMOVE)!=0); // !=0) not needed
if(gotmsg)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
for(i=0;i<KeyIndex;i++)
sAppHandler(sAPPCODE_KEY,KeyBuffer[i]);
KeyIndex = 0;
Render();
#if sUSE_DIRECTSOUND
MarkDS();
#endif
}
}
/*
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
*/
sAppHandler(sAPPCODE_EXIT,0);
#if sUSE_DIRECTSOUND
if(DXSBuffer)
DXSBuffer->Stop();
// ExitDS();
#endif
ExitProcess(0);
}
/****************************************************************************/
void sSystem_::InitScreens()
{
HRESULT hr;
D3DPRESENT_PARAMETERS d3dpp;
RECT r;
sInt i;
sU32 create;
sU16 *iblock;
sHardTex *tex;
D3DCAPS9 caps;
sREGZONE(FlipLock);
if(!DXD)
{
DXD = (*Direct3DCreate9P)(D3D_SDK_VERSION);
sVERIFY(DXD);
}
ZBufFormat=D3DFMT_D24S8;
Screen[0].SFormat=D3DFMT_A8R8G8B8;
Screen[0].ZFormat=ZBufFormat;
WINZERO(d3dpp);
d3dpp.BackBufferFormat = (enum _D3DFORMAT) Screen[0].SFormat;
d3dpp.EnableAutoDepthStencil = sFALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferCount = 1;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;// | D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
d3dpp.hDeviceWindow = (HWND) Screen[0].Window;
#if sFULLSCREEN
d3dpp.Windowed = FALSE;
d3dpp.BackBufferWidth = ConfigX;
d3dpp.BackBufferHeight = ConfigY;
Screen[0].XSize = ConfigX;
Screen[0].YSize = ConfigY;
#else
d3dpp.Windowed = TRUE;
GetClientRect((HWND) Screen[0].Window,&r);
Screen[0].XSize = r.right-r.left;
Screen[0].YSize = r.bottom-r.top;
#endif
hr=DXD->GetDeviceCaps(0,D3DDEVTYPE_HAL,&caps);
sVERIFY(!FAILED(hr));
if(!DXDev)
{
if((caps.PixelShaderVersion&0xffff)==0x0000)
sFatal("pixel shaders required");
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))
sFatal("could not create screen");
for(i=1;i<FVFMax;i++)
DXDev->CreateVertexDeclaration(FVFTable[i].Info,&FVFTable[i].Decl);
}
else
{
if(DXNormalCube)
{
DXNormalCube->Release();
DXNormalCube = 0;
}
if(ZBuffer)
{
ZBuffer->Release();
ZBuffer = 0;
}
for(i=0;i<MAX_GEOHANDLE;i++)
{
if(GeoHandle[i].Mode!=0)
{
if(GeoHandle[i].VertexBuffer>=3)
GeoBuffer[GeoHandle[i].VertexBuffer].Free();
if(GeoHandle[i].IndexBuffer>=3)
GeoBuffer[GeoHandle[i].IndexBuffer].Free();
}
GeoHandle[i].VertexCount = 0;
GeoHandle[i].VertexBuffer = 0;
GeoHandle[i].IndexCount = 0;
GeoHandle[i].IndexBuffer = 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_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));
}
// zbuffer
DXERROR(DXDev->CreateDepthStencilSurface(1024,600,(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,1,MAX_DYNVBSIZE);
CreateGeoBuffer(1,1,0,MAX_DYNIBSIZE);
CreateGeoBuffer(2,0,0,2*0x8000/4*6);
DXERROR(GeoBuffer[2].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[2].IB->Unlock());
MakeCubeNormalizer();
// MakeSpecularLookupTex();
// set some defaults
DXDev->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
DXDev->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);
DXDev->SetRenderState(D3DRS_LIGHTING,0);
WDeviceLost = 0;
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));
}
}
}
#endif
#endif
/****************************************************************************/
/****************************************************************************/
/*** ***/
/*** System Implementation ***/
/*** ***/
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/*** ***/
/*** Init/Exit/Debug ***/
/*** ***/
/****************************************************************************/
void sSystem_::Exit()
{
PostQuitMessage(0);
}
void sSystem_::Tag()
{
}
sNORETURN void sSystem_::Abort(sChar *msg)
{
#if sINTRO
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,(sU32) s))
OutputDebugString(s);
}
/****************************************************************************/
#if !sINTRO
void sSystem_::Init(sU32 flags,sInt xs,sInt ys)
{
ConfigX = xs;
ConfigY = ys;
ConfigFlags = flags;
}
#if !sCOMMANDLINE
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;
}
#endif
sInt sSystem_::MemoryUsed()
{
return MemoryUsedCount;
}
void sSystem_::CheckMem()
{
_CrtCheckMemory();
}
/****************************************************************************/
void *sSystem_::FindFunc(sChar *name)
{
return GetProcAddress(0,name);
}
#endif
/****************************************************************************/
/*** ***/
/*** Render ***/
/*** ***/
/****************************************************************************/
#if sLINK_ENGINE
#if sPLAYER
void sSystem_::Progress(sInt done,sInt max)
{
static sInt lasttime;
const int step = 3;
sInt time;
sRect r;
sInt key;
IDirect3DSurface9 *backbuffer;
IDirect3DSwapChain9 *swapchain;
time = timeGetTime();
if(time > lasttime+450 || done==max)
{
lasttime = time;
DXDev->Clear(0,0,D3DCLEAR_TARGET,0xff000000,0,0);
sZONE(FlipLock);
DXDev->GetSwapChain(0,&swapchain);
swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&backbuffer);
r.Init(20+step*0,sSCREENY/2-20+step*0,sSCREENX-20-step*0,sSCREENY/2+20-step*0);
DXDev->ColorFill(backbuffer,(RECT *)&r,0xffffffff);
r.Init(20+step*1,sSCREENY/2-20+step*1,sSCREENX-20-step*1,sSCREENY/2+20-step*1);
DXDev->ColorFill(backbuffer,(RECT *)&r,0xff000000);
r.Init(20+step*2,sSCREENY/2-20+step*2,sSCREENX-20-step*2,sSCREENY/2+20-step*2);
r.x1 = r.x0 + 1 + sMin(max,done)*(r.x1-r.x0-1)/max;
DXDev->ColorFill(backbuffer,(RECT *)&r,0xffffffff);
swapchain->Release();
backbuffer->Release();
DXDev->Present(0,0,0,0);
key = GetAsyncKeyState(VK_ESCAPE);
if(key&0x8000)
{
DXDev->Release();
ExitProcess(0);
}
}
}
#endif
/****************************************************************************/
void sSystem_::Render()
{
static sInt LastTime=-1;
sInt time,ticks;
HRESULT hr;
sInt i;
RecalcTransform = sTRUE;
LastCamera.Init();
LastMatrix.Init();
LastTransform.Init();
StdTexTransMat.i.Init(0.5f,0.0f,0.0f,0.0f);
StdTexTransMat.j.Init(0.0f,0.5f,0.0f,0.0f);
StdTexTransMat.k.Init(0.0f,0.0f,0.5f,0.0f);
StdTexTransMat.l.Init(0.5f,0.5f,0.5f,1.0f);
StdTexTransMatSet[0] = 0;
for(i=0;i<8;i++)
StdTexTransMatSet[i] = 0;
if(WDeviceLost)
{
Sleep(100);
hr = DXDev->TestCooperativeLevel();
if(hr!=D3DERR_DEVICENOTRESET)
return;
InitScreens();
if(WDeviceLost)
return;
}
time = sSystem->GetTime();
ticks = 0;
if(LastTime==-1)
LastTime = time;
while(time>LastTime)
{
LastTime+=10;
ticks++;
}
if(ticks>10)
ticks=10;
sAppHandler(sAPPCODE_FRAME,0);
sAppHandler(sAPPCODE_TICK,ticks);
sAppHandler(sAPPCODE_PAINT,0);
#if !sPLAYER
#if sLINK_UTIL
sPerfMon->Marker(1);
#endif
#endif
#if !sINTRO
if(WResponse)
#endif
{
IDirect3DSurface9 *backbuffer;
IDirect3DSwapChain9 *swapchain;
D3DLOCKED_RECT lr;
sZONE(FlipLock);
DXERROR(DXDev->GetSwapChain(0,&swapchain));
DXERROR(swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&backbuffer));
DXERROR(backbuffer->LockRect(&lr,0,D3DLOCK_READONLY));
backbuffer->UnlockRect();
swapchain->Release();
backbuffer->Release();
}
hr = DXDev->Present(0,0,0,0);
if(hr==D3DERR_DEVICELOST)
WDeviceLost = 1;
for(i=1;i<MAX_GEOHANDLE;i++)
{
GeoHandle[i].VBDiscardCount = 0;
GeoHandle[i].IBDiscardCount = 0;
}
VBDiscardCount = 1;
IBDiscardCount = 1;
GeoBuffer[0].Used = GeoBuffer[0].Size;
GeoBuffer[1].Used = GeoBuffer[1].Size;
}
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_::BeginViewport(const sViewport &vp)
{
D3DVIEWPORT9 dview,fview;
sInt nr;
sInt xs,ys,dxs,dys;
sU32 stencilClear;
sHardTex *tex;
IDirect3DSurface9 *backbuffer;
IDirect3DSwapChain9 *swapchain;
CurrentViewport = vp;
nr = vp.Screen;
if(vp.RenderTarget==sINVALID)
{
ScreenNr = nr;
scr = &Screen[nr];
sVERIFY(nr>=0 && nr<WScreenCount);
dxs = Screen[nr].XSize;
dys = Screen[nr].YSize;
}
else
{
sVERIFY(vp.RenderTarget >= 0);
tex = &Textures[vp.RenderTarget];
sVERIFY(tex->Flags & sTIF_RENDERTARGET);
dxs = tex->XSize;
dys = tex->YSize;
}
xs = vp.Window.XSize();
ys = vp.Window.YSize();
if(xs==0 || ys==0)
{
dview.X = 0;
dview.Y = 0;
dview.Width = dxs;
dview.Height = dys;
CurrentViewport.Window.x0 = 0;
CurrentViewport.Window.y0 = 0;
CurrentViewport.Window.x1 = dxs;
CurrentViewport.Window.y1 = dys;
}
else
{
dview.X = vp.Window.x0;
dview.Y = vp.Window.y0;
dview.Width = vp.Window.x1-vp.Window.x0;
dview.Height = vp.Window.y1-vp.Window.y0;
}
ViewportX = dview.Width;
ViewportY = dview.Height;
dview.MinZ = 0.0f;
dview.MaxZ = 1.0f;
if(vp.RenderTarget!=sINVALID)
{
DXERROR(tex->Tex->GetSurfaceLevel(0,&backbuffer));
}
else
{
DXERROR(DXDev->GetSwapChain(nr,&swapchain));
DXERROR(swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&backbuffer));
swapchain->Release();
}
DXERROR(DXDev->SetRenderTarget(0,backbuffer));
backbuffer->Release();
if(nr!=-1 || (vp.ClearFlags & sVCF_PARTIAL))
DXDev->SetViewport(&dview);
else
{
fview.X = 0; // always clear full surface for textures
fview.Y = 0;
fview.Width = tex->XSize;
fview.Height = tex->YSize;
fview.MinZ = 0.0f;
fview.MaxZ = 1.0f;
DXDev->SetViewport(&fview);
}
stencilClear = (ZBufFormat==D3DFMT_D24S8 || ZBufFormat==D3DFMT_D15S1) ? D3DCLEAR_STENCIL : 0;
switch(vp.ClearFlags&3)
{
case sVCF_COLOR:
DXDev->Clear(0,0,D3DCLEAR_TARGET,vp.ClearColor.Color,1.0f,0);
break;
case sVCF_Z:
DXDev->Clear(0,0,D3DCLEAR_ZBUFFER|stencilClear,vp.ClearColor.Color,1.0f,0);
break;
case sVCF_ALL:
DXDev->Clear(0,0,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|stencilClear,vp.ClearColor.Color,1.0f,0);
break;
}
if(nr==-1)
DXDev->SetViewport(&dview);
DXERROR(DXDev->BeginScene());
}
void sSystem_::EndViewport()
{
DXERROR(DXDev->EndScene());
}
void sSystem_::GetTransform(sInt mode,sMatrix &mat)
{
switch(mode)
{
case sGT_UNIT:
mat.Init();
break;
case sGT_MODELVIEW:
mat = LastTransform;
break;
case sGT_MODEL:
mat = LastMatrix;
break;
case sGT_VIEW:
mat = LastCamera;
break;
case sGT_PROJECT:
mat = LastProjection;
break;
default:
mat.Init();
break;
}
}
/****************************************************************************/
/****************************************************************************/
/*
void sSystem_::SetTexture(sInt stage,sInt handle,sMatrix *mat)
{
sHardTex *tex;
if(handle==sINVALID)
{
DXDev->SetTexture(stage,0);
return;
}
tex = &Textures[handle];
DXDev->SetTexture(stage,tex->Tex);
if(mat)
{
DXDev->SetTransform((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0+stage),(D3DMATRIX *) mat);
StdTexTransMatSet[stage] = 0;
}
else
{
if(!StdTexTransMatSet[stage])
{
DXDev->SetTransform((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0+stage),(D3DMATRIX *) &StdTexTransMat);
StdTexTransMatSet[stage] = 1;
}
}
}
*/
/****************************************************************************/
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->TexGL = 0;
if(tex->Flags & sTIF_RENDERTARGET)
{
if(tex->XSize==0)
{
tex->XSize = Screen[0].XSize;
tex->YSize = Screen[0].YSize;
}
// sVERIFY(tex->XSize<=Screen[0].XSize);
// sVERIFY(tex->YSize<=Screen[0].YSize);
#if LOGGING
sDPrintF("Create Rendertarget %dx%d\n",tex->XSize,tex->YSize);
#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
DXERROR(DXDev->CreateTexture(tex->XSize,tex->YSize,0,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 format,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,
};
#else
static D3DFORMAT formats[] =
{
D3DFMT_UNKNOWN,
D3DFMT_A8R8G8B8,
D3DFMT_A8,
D3DFMT_A8R8G8B8,
D3DFMT_A8R8G8B8,
D3DFMT_A8R8G8B8,
D3DFMT_A8R8G8B8,
};
#endif
sVERIFY(format>0 && format<sTF_MAX);
tex = Textures;
for(i=0;i<MAX_TEXTURE;i++)
{
if(tex->Flags==0)
{
tex->RefCount = 1;
tex->XSize = xs;
tex->YSize = ys;
tex->Flags = sTIF_ALLOCATED;
tex->Format = format;
tex->Tex = 0;
tex->TexGL = 0;
if(data==0)
{
if(tex->XSize==0)
{
tex->XSize = Screen[0].XSize;
tex->YSize = Screen[0].YSize;
}
tex->Flags |= sTIF_RENDERTARGET;
// sVERIFY(tex->XSize<=Screen[0].XSize);
// sVERIFY(tex->YSize<=Screen[0].YSize);
#if LOGGING
sDPrintF("Create Rendertarget %dx%d\n",tex->XSize,tex->YSize);
#endif
DXERROR(DXDev->CreateTexture(tex->XSize,tex->YSize,1,D3DUSAGE_RENDERTARGET,formats[format],D3DPOOL_DEFAULT,&tex->Tex,0));
#if !sINTRO
ReCreateZBuffer();
#endif
}
else
{
#if LOGGING
sDPrintF("Create Texture %dx%d\n",tex->XSize,tex->YSize);
#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(tex->Tex)
tex->Tex->Release();
tex->Flags = 0;
tex->Tex = 0;
}
}
}
/****************************************************************************/
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));
}
}
/****************************************************************************/
/*
void sSystem_::MakeSpecularLookupTex()
{
sU16 lookup[256*4],*lp;
sInt i,v;
sF32 x;
lp = lookup;
for(i=0;i<256;i++)
{
x = i / 255.0f;
v = 32767 * sFPow(x,32.0f); // specular power is 32
*lp++ = v;
*lp++ = v;
*lp++ = v;
*lp++ = v;
}
SpecularLookupTex = AddTexture(256,1,sTF_A8R8G8B8,lookup);
lp = lookup;
for(i=0;i<256;i++)
{
*lp++ = 0x4000;
*lp++ = 0x4000;
*lp++ = 0x8000;
*lp++ = 0x4000;
}
NullBumpTex = AddTexture(16,16,sTF_Q8W8V8U8,lookup);
}
*/
/****************************************************************************/
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_::ReadTexture(sInt handle,sU32 *data)
{
sHardTex *tex;
IDirect3DSurface9 *rs;
IDirect3DSurface9 *ms;
D3DLOCKED_RECT lr;
sInt y;
sU8 *s;
tex = &Textures[handle];
sVERIFY(tex->Format==sTF_A8R8G8B8);
if(DXReadTexXS!=tex->XSize || DXReadTexYS!=tex->YSize)
{
if(DXReadTex)
DXReadTex->Release();
DXReadTex = 0;
DXReadTexXS = tex->XSize;
DXReadTexYS = tex->YSize;
DXERROR(DXDev->CreateOffscreenPlainSurface(tex->XSize,tex->YSize,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&DXReadTex,0));
}
ms = DXReadTex;
DXERROR(tex->Tex->GetSurfaceLevel(0,&rs));
DXERROR(DXDev->GetRenderTargetData(rs,ms));
DXERROR(ms->LockRect(&lr,0,D3DLOCK_READONLY));
s = (sU8 *)lr.pBits;
for(y=0;y<tex->YSize;y++)
{
sCopyMem(data,s,tex->XSize*4);
data+=tex->XSize;
s+=lr.Pitch;
}
DXERROR(ms->UnlockRect());
rs->Release();
}
/****************************************************************************/
/****************************************************************************/
void sSystem_::SetStates(sU32 *stream)
{
// DXDev->SetPixelShader(0);
// DXDev->SetVertexShader(0);
while(*stream!=0xffffffff)
{
SetState(stream[0],stream[1]);
stream+=2;
}
}
/****************************************************************************/
void sSystem_::SetState(sU32 token,sU32 value)
{
if(token<0x0310)
{
if(token<0x0100)
{
DXDev->SetRenderState((enum _D3DRENDERSTATETYPE)token,value);
}
else if(token<0x0200)
{
DXDev->SetTextureStageState(((token>>5)&7),(enum _D3DTEXTURESTAGESTATETYPE)(token&31),value);
}
else if(token<0x0300)
{
DXDev->SetSamplerState(((token>>4)&15),(enum _D3DSAMPLERSTATETYPE)(token&15),value);
}
else if(token<0x0310)
{
DXDev->SetSamplerState(D3DDMAPSAMPLER,(enum _D3DSAMPLERSTATETYPE)(token&15),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 vertex,sInt size)
{
sInt usage;
D3DPOOL pool;
sVERIFY(dyn==0 || dyn==1);
sVERIFY(vertex==0 || vertex==1);
GeoBuffer[i].Type = 1+vertex;
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(vertex)
{
DXERROR(DXDev->CreateVertexBuffer(size,usage,0,pool,&GeoBuffer[i].VB,0));
}
else
{
DXERROR(DXDev->CreateIndexBuffer(size,usage,D3DFMT_INDEX16,pool,&GeoBuffer[i].IB,0));
}
#if LOGGING
sDPrintF("Create %s %s-Buffer (%d bytes)\n",dyn?"dynamic":"static",vertex?"vertex":"index",size);
#endif
}
#undef GeoAdd
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;
gh->File = "";
gh->Line = 0;
return i;
}
}
sFatal("GeoAdd() ran out of handles");
return 0;
}
#if !sINTRO
sInt sSystem_::GeoAdd(sInt fvf,sInt prim,const sChar *file,sInt line)
{
sInt i;
sGeoHandle *gh;
static sInt AllocId=0;
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;
gh->File = file;
gh->Line = line;
gh->AllocId = AllocId++;
if(gh->AllocId == -1)
__asm int 3;
return i;
}
}
sFatal("GeoAdd() ran out of handles");
return 0;
}
#define GeoAdd(f,p) GeoAdd(f,p,__FILE__,__LINE__)
#endif
void sSystem_::GeoRem(sInt handle)
{
sVERIFY(handle>=1 && handle<MAX_GEOHANDLE);
sVERIFY(GeoHandle[handle].Mode!=0);
if(GeoHandle[handle].VertexBuffer>=3)
GeoBuffer[GeoHandle[handle].VertexBuffer].Free();
if(GeoHandle[handle].IndexBuffer>=3)
GeoBuffer[GeoHandle[handle].IndexBuffer].Free();
GeoHandle[handle].Mode = 0;
}
void sSystem_::GeoFlush()
{
sInt i;
for(i=1;i<MAX_GEOHANDLE;i++)
GeoHandle[i].VertexCount = 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].VBDiscardCount = 0;
if(what & sGEO_INDEX) GeoHandle[handle].IBDiscardCount = 0;
}
sInt sSystem_::GeoDraw(sInt &handle)
{
sGeoHandle *gh;
enum _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->VertexCount == 0)
update |= sGEO_VERTEX | sGEO_INDEX;
if(gh->VertexBuffer == 0 && gh->VBDiscardCount != VBDiscardCount)
update |= sGEO_VERTEX;
if(gh->IndexBuffer == 1 && gh->IBDiscardCount != IBDiscardCount)
update |= sGEO_INDEX;
if(update)
return update;
// set up buffers
DXDev->SetVertexDeclaration(FVFTable[gh->FVF].Decl);
if(gh->IndexCount)
{
sVERIFY(gh->IndexBuffer>=0 && gh->IndexBuffer<MAX_GEOBUFFER);
sVERIFY(GeoBuffer[gh->IndexBuffer].Type == 1);
sVERIFY(GeoBuffer[gh->IndexBuffer].IB);
DXDev->SetIndices(GeoBuffer[gh->IndexBuffer].IB);
}
sVERIFY(gh->VertexBuffer>=0 && gh->VertexBuffer<MAX_GEOBUFFER);
sVERIFY(GeoBuffer[gh->VertexBuffer].Type == 2);
sVERIFY(GeoBuffer[gh->VertexBuffer].VB);
DXDev->SetStreamSource(0,GeoBuffer[gh->VertexBuffer].VB,0,gh->VertexSize);
// start drawing
count = gh->IndexCount;
if(count==0)
count = gh->VertexCount;
PerfThis.Vertex += gh->VertexCount;
PerfThis.Batches++;
switch(gh->Mode&7)
{
case sGEO_POINT:
mode = D3DPT_POINTLIST;
count = count;
sVERIFY(gh->IndexCount==0);
break;
case sGEO_LINE:
mode = D3DPT_LINELIST;
count = count/2;
PerfThis.Line += count;
break;
case sGEO_LINESTRIP:
mode = D3DPT_LINESTRIP;
count = count-1;
PerfThis.Line += count;
break;
case sGEO_TRI:
mode = D3DPT_TRIANGLELIST;
count = count/3;
PerfThis.Triangle += count;
break;
case sGEO_TRISTRIP:
mode = D3DPT_TRIANGLESTRIP;
count = count-2;
PerfThis.Triangle += count;
break;
case sGEO_QUAD:
sVERIFY(gh->IndexCount==0);
PerfThis.Triangle += count/2;
DXDev->SetIndices(GeoBuffer[2].IB);
DXDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,gh->VertexStart,0,gh->VertexCount,0,count/4*2);
return sFALSE;
default:
sVERIFYFALSE;
}
if(gh->IndexCount)
DXDev->DrawIndexedPrimitive(mode,gh->VertexStart,0,gh->VertexCount,gh->IndexStart,count);
else
DXDev->DrawPrimitive(mode,gh->VertexStart,count);
return sFALSE;
}
void sSystem_::GeoBegin(sInt handle,sInt vc,sInt ic,sF32 **fp,sU16 **ip,sInt upd)
{
sGeoHandle *gh;
sInt i,lockf;
sInt ok;
sVERIFY(handle>=1 && handle<MAX_GEOHANDLE);
sVERIFY(GeoHandle[handle].Mode!=0);
sVERIFY(vc*GeoHandle[handle].VertexSize<=MAX_DYNVBSIZE);
sVERIFY(ic*2<=MAX_DYNIBSIZE);
gh = &GeoHandle[handle];
*fp = 0;
if(ip)
*ip = 0;
if(upd & sGEO_VERTEX)
{
if(gh->VertexBuffer>=3)
GeoBuffer[gh->VertexBuffer].Free();
gh->VertexBuffer = 0;
gh->VertexStart = 0;
gh->VertexCount = vc;
if(gh->Mode & sGEO_STATVB) // static vertex buffer
{
for(i=3;i<MAX_GEOBUFFER;i++)
if(GeoBuffer[i].AllocVB(vc,gh->VertexSize,gh->VertexStart))
break;
if(i == MAX_GEOBUFFER)
{
for(i=3;i<MAX_GEOBUFFER;i++)
{
if(GeoBuffer[i].Type == 0)
{
CreateGeoBuffer(i,0,1,MAX_DYNVBSIZE);
ok = GeoBuffer[i].AllocVB(vc,gh->VertexSize,gh->VertexStart);
sVERIFY(ok);
break;
}
}
if(i == MAX_GEOBUFFER)
sFatal("GeoBegin(): no free static vertex buffer");
}
gh->VertexBuffer = i;
lockf = 0;
}
else // dynamic vertex buffer
{
ok = GeoBuffer[0].AllocVB(vc,gh->VertexSize,gh->VertexStart);
gh->VertexBuffer = 0;
if(!ok)
{
GeoBuffer[0].Used = 0;
VBDiscardCount++;
ok = GeoBuffer[0].AllocVB(vc,gh->VertexSize,gh->VertexStart);
sVERIFY(ok);
}
gh->VBDiscardCount = VBDiscardCount;
lockf = gh->VertexStart ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD;
}
DXERROR(GeoBuffer[gh->VertexBuffer].VB->Lock(gh->VertexStart*gh->VertexSize,vc*gh->VertexSize,(void **)fp,lockf));
gh->Locked |= sGEO_VERTEX;
}
if(upd & sGEO_INDEX)
{
if(gh->IndexBuffer>=3)
GeoBuffer[gh->IndexBuffer].Free();
gh->IndexBuffer = 0;
gh->IndexStart = 0;
gh->IndexCount = ic;
if(ic)
{
if(gh->Mode & sGEO_STATIB) // static index buffer
{
for(i=3;i<MAX_GEOBUFFER;i++)
if(GeoBuffer[i].AllocIB(ic,gh->IndexStart))
break;
if(i == MAX_GEOBUFFER)
{
for(i=3;i<MAX_GEOBUFFER;i++)
{
if(GeoBuffer[i].Type == 0)
{
CreateGeoBuffer(i,0,0,MAX_DYNIBSIZE);
ok = GeoBuffer[i].AllocIB(ic,gh->IndexStart);
sVERIFY(ok);
break;
}
}
if(i == MAX_GEOBUFFER)
sFatal("GeoBegin(): no free static index buffer");
}
gh->IndexBuffer = i;
lockf = 0;
}
else // dynamic index buffer
{
gh->IndexBuffer = 1;
ok = GeoBuffer[1].AllocIB(ic,gh->IndexStart);
if(!ok)
{
GeoBuffer[1].Used = 0;
IBDiscardCount++;
ok = GeoBuffer[1].AllocIB(ic,gh->IndexStart);
sVERIFY(ok);
}
gh->IBDiscardCount = IBDiscardCount;
lockf = gh->IndexStart ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD;
}
DXERROR(GeoBuffer[gh->IndexBuffer].IB->Lock(gh->IndexStart*2,ic*2,(void **)ip,lockf));
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->VertexBuffer].VB->Unlock();
gh->Locked &= ~sGEO_VERTEX;
}
if(gh->Locked & sGEO_INDEX)
{
GeoBuffer[gh->IndexBuffer].IB->Unlock();
gh->Locked &= ~sGEO_INDEX;
}
if(vc!=-1)
gh->VertexCount = vc;
if(ic!=-1)
gh->IndexCount = 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.SwapVertexColor = 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.SwapVertexColor = (ConfigFlags & sSF_OPENGL)?1:0;
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);
if(tex->Tex)
{
tex->Tex->Release();
tex->Tex = 0;
}
}
void sSystem_::GetTexSize(sInt handle,sInt &xs,sInt &ys)
{
sHardTex *tex;
sVERIFY(handle>=0 && handle<MAX_TEXTURE);
tex = &Textures[handle];
sVERIFY(tex->Flags);
xs = tex->XSize;
ys = tex->YSize;
}
/****************************************************************************/
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)
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 x,y;
sInt bpr,oxs;
sU32 *d,*s,*data;
sU16 *d16,*s16;
// sU8 *d8;
mipdir = miptresh & 16;
alpha = miptresh & 32;
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;
for(y=0;y<ys;y++)
{
if(tex->Format==sTF_Q8W8V8U8)
{
s16 = (sU16 *)s;
for(x=0;x<xs;x++)
{
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);
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;
}
}
/*
switch(tex->Format+alpha)
{
case sTF_A8R8G8B8:
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;
}
break;
case sTF_A8R8G8B8+32:
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]>0x4000?0xff000000:0);
s16+=4;
}
break;
case sTF_A8:
s16 = (sU16 *)s;
d8 = (sU8 *)d;
for(x=0;x<xs;x++)
{
d8[x] = (((s16[3]>>7)&0xff) );
s16+=4;
}
break;
case sTF_A8+32:
s16 = (sU16 *)s;
d8 = (sU8 *)d;
for(x=0;x<xs;x++)
{
d8[x] = s16[3]>0x4000?0xff:0;
s16+=4;
}
break;
case sTF_Q8W8V8U8:
case sTF_Q8W8V8U8+32:
s16 = (sU16 *)s;
for(x=0;x<xs;x++)
{
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);
s16+=4;
}
break;
}
*/
d+=bpr/4;
s+=oxs*2;
}
mst->UnlockRect(level);
if(xs<=1 || ys<=1)
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;
}
}
#endif
/****************************************************************************/
/****************************************************************************/
/*** ***/
/*** 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 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 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 },
{ 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;
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);
}
/****************************************************************************/
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;
}
}
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;
}
else
{
KeyRepeat = key;
KeyRepeatTimer = time+KeyRepeatDelay;
KeyStickyMouseX = MouseX;
KeyStickyMouseY = MouseY;
KeyStickyTime = sSystem->GetTime();
KeySticky = sTRUE;
}
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;
}
}
}
}
}
#endif
/****************************************************************************/
/*** ***/
/*** Misc Input/Timing stuff ***/
/*** ***/
/****************************************************************************/
#if !sCOMMANDLINE
void sSystem_::GetInput(sInt id,sInputData &data)
{
#if sINTRO
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
}
#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;
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);
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()
{
if(GetAsyncKeyState(VK_PAUSE)&1)
WAbortKeyFlag = 1;
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;
}
sU32 sSystem_::PerfTime()
{
sU64 time;
_asm
{
push eax
push edx
rdtsc
mov DWORD PTR time,eax
mov DWORD PTR time+4,edx
pop edx
pop eax
}
return (time-sPerfFrame)*sPerfKalibFactor;
}
void sSystem_::PerfKalib()
{
sU64 query;
sU64 freq;
sU64 time;
_asm
{
push eax
push edx
rdtsc
mov DWORD PTR time,eax
mov DWORD PTR time+4,edx
pop edx
pop eax
}
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;
}
void sSystem_::SetWinMouse(sInt x,sInt y)
{
SetCursorPos(x,y);
}
void sSystem_::SetWinTitle(sChar *name)
{
SetWindowText((HWND)Screen[0].Window,name);
}
void sSystem_::HideWinMouse(sBool hide)
{
if(hide)
while(ShowCursor(0)>0);
else
ShowCursor(1);
}
/****************************************************************************/
#endif
/****************************************************************************/
/****************************************************************************/
/*** ***/
/*** Sound ***/
/*** ***/
/****************************************************************************/
#if sUSE_DIRECTSOUND
#if sINTRO
static const GUID IID_IDirectSoundBuffer8 = { 0x6825a449, 0x7524, 0x4d82, 0x92, 0x0f, 0x50, 0xe3, 0x6a, 0xb3, 0xab, 0x1e };
#endif
sBool sSystem_::InitDS()
{
DWORD count1,count2;
void *pos1,*pos2;
HRESULT hr;
DSBUFFERDESC dsbd;
WAVEFORMATEX format;
IDirectSoundBuffer *sbuffer;
hr = (*DirectSoundCreate8P)(0,&DXS,0);
if(FAILED(hr)) return sFALSE;
hr = DXS->SetCooperativeLevel((HWND)Screen[0].Window,DSSCL_PRIORITY);
if(FAILED(hr)) return sFALSE;
WINSET(dsbd);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = 0;
hr = DXS->CreateSoundBuffer(&dsbd,&DXSPrimary,0);
if(FAILED(hr)) return sFALSE;
WINZERO(format);
format.nAvgBytesPerSec = 44100*4;
format.nBlockAlign = 4;
format.nChannels = 2;
format.nSamplesPerSec = 44100;
format.wBitsPerSample = 16;
format.wFormatTag = WAVE_FORMAT_PCM;
DXSPrimary->SetFormat(&format);
WINSET(dsbd);
dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS/* | DSBCAPS_STICKYFOCUS*/;
dsbd.dwBufferBytes = DXSSAMPLES*4;
dsbd.lpwfxFormat = &format;
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);
}
// DXSBuffer->SetFrequency(44100);
// DXSBuffer->SetVolume(0);
// DXSBuffer->SetPan(0);
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;
// SetThreadPriority(DXSThread,THREAD_PRIORITY_TIME_CRITICAL);
// SetPriorityClass(DXSThread,HIGH_PRIORITY_CLASS);
return sTRUE;
}
/****************************************************************************/
void sSystem_::ExitDS()
{
if(DXSBuffer)
DXSBuffer->Stop();
if(DXSThread)
{
DXSRun = 1;
while(DXSRun==1)
Sleep(10);
CloseHandle(DXSThread);
CloseHandle(DXSEvent);
DeleteCriticalSection(&DXSLock);
}
SampleRemAll();
if(DXSBuffer)
DXSBuffer->Release();
if(DXSPrimary)
DXSPrimary->Release();
if(DXS)
DXS->Release();
}
/****************************************************************************/
void sSystem_::MarkDS()
{
DWORD play,write;
HRESULT hr;
sInt delta;
SetEvent(DXSEvent);