Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 652f4f9682
Fetching contributors…

Cannot retrieve contributors at this time

7164 lines (6042 sloc) 172.321 kb
// 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
#define WINVER 0x500
#define _WIN32_WINNT 0x0500
#define DIRECTINPUT_VERSION 0x0800
#define sPLAYER_SCREENX 800
#define sPLAYER_SCREENY 600
#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-044: patient zero";
#endif
//#define D3D_DEBUG_INFO
#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 || _DEBUG
#pragma comment(lib,"dxguid.lib")
#else
#pragma comment(linker,"/nodefaultlib")
#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 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) {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;
HWND MsgWin;
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;
sBool IntroHighTexRes = sTRUE;
#else
const sInt IntroScreenX=sPLAYER_SCREENX;
const sInt IntroScreenY=sPLAYER_SCREENY;
const sInt IntroFlags = sPLAYER_FULLSCREEN ? sSF_FULLSCREEN : 0;
const sInt IntroTargetAspect = 0;
sBool IntroHighTexRes = sTRUE;
#endif
sInt IntroLoop;
sBool IntroStereo3D = sTRUE;
/****************************************************************************/
/****************************************************************************/
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 FVFTableStruct FVFTable[] =
{
{ 0,0 },
{ 32,DeclDefault },
{ 32,DeclDouble },
{ 64,DeclTSpace },
{ 16,DeclCompact },
{ 16,DeclXYZW },
{ 32,DeclTSpace3 },
{ 48,DeclTSpace3Big },
};
#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,
};
/****************************************************************************/
/*** ***/
/*** 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)
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);
//sDPrintF("%10d : %d\n",MemoryUsedCount,size);
MemoryUsedCount+=_msize(p);
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 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 ***/
/*** ***/
/****************************************************************************/
/****************************************************************************/
#if sCONFIGDIALOG
#include "resource.h"
BOOL CALLBACK sDialogProc(HWND win,UINT msg,WPARAM wparam,LPARAM lparam)
{
switch(msg)
{
case WM_INITDIALOG:
if(sWindowTitle)
SetWindowText(win,sWindowTitle);
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_ADDSTRING,0,(LPARAM)"1280x1024");
SendDlgItemMessage(win,IDC_RESOLUTION,CB_SETCURSEL,2,0);
SendDlgItemMessage(win,IDC_ASPECT,CB_ADDSTRING,0,(LPARAM)"4:3 (default)");
SendDlgItemMessage(win,IDC_ASPECT,CB_ADDSTRING,0,(LPARAM)"5:4");
SendDlgItemMessage(win,IDC_ASPECT,CB_ADDSTRING,0,(LPARAM)"16:9");
SendDlgItemMessage(win,IDC_ASPECT,CB_ADDSTRING,0,(LPARAM)"16:10");
SendDlgItemMessage(win,IDC_ASPECT,CB_ADDSTRING,0,(LPARAM)"2:1");
SendDlgItemMessage(win,IDC_ASPECT,CB_SETCURSEL,0,0);
#if sRELEASE
CheckDlgButton(win,IDC_FULLSCREEN,BST_CHECKED);
#endif
CheckDlgButton(win,IDC_VSYNC,BST_CHECKED);
// CheckDlgButton(win,IDC_STEREO3D,BST_CHECKED);
return sTRUE;
case WM_CLOSE:
EndDialog(win,102);
return sTRUE;
case WM_COMMAND:
switch(wparam&0xffff)
{
case IDOK:
{
sInt res = SendDlgItemMessage(win,IDC_RESOLUTION,CB_GETCURSEL,0,0);
res = sRange(res,2,0);
static sInt xResTab[] = { 640,800,1024,1280 };
static sInt yResTab[] = { 480,600, 768,1024 };
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,xResTab[res],yResTab[res]);
#else
IntroScreenX = xResTab[res];
IntroScreenY = yResTab[res];
IntroFlags = flags;
#endif
IntroTargetAspect = SendDlgItemMessage(win,IDC_ASPECT,CB_GETCURSEL,0,0);
IntroHighTexRes = IsDlgButtonChecked(win,IDC_HIGHTEXRES) == BST_CHECKED ? sTRUE : sFALSE;
IntroLoop = (IsDlgButtonChecked(win,IDC_LOOP)==BST_CHECKED);
IntroStereo3D = (IsDlgButtonChecked(win,IDC_STEREO3D) == BST_CHECKED);
}
EndDialog(win,wparam);
break;
case IDCANCEL:
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
__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;
sVERIFY(sSystem);
return sSystem->Msg(msg,wparam,lparam);
}
/****************************************************************************/
int APIENTRY WinMain(HINSTANCE inst,HINSTANCE prev,LPSTR cmdline,int show)
{
WInst = inst;
WCmdLine = cmdline;
#if sUSE_LEKKTOR
sLekktorInit();
#endif
if(sAppHandler(sAPPCODE_CONFIG,0))
sSystem->InitX();
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 = 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,r2;
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);
}
}
}
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;
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();
_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,"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
{
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;
for(i=0;i<MAX_TEXTURE;i++)
Textures[i].Flags = 0;
sSetMem(Setups,0,sizeof(Setups));
MtrlClearCaches();
InitScreens();
if(CmdShaderLevel>GetShaderLevel())
CmdShaderLevel = GetShaderLevel();
_control87(_PC_24|_RC_NEAR,MCW_PC|MCW_RC);
#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(d3dlib);
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;
}
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:
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);
if(!DXD)
{
DXD = (*Direct3DCreate9P)(D3D_SDK_VERSION);
if(!DXD)
sFatal("DirectX 9.0c not present.");
}
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 = (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;
#if sPLAYER
d3dpp[nr].Flags = 0;
#else
d3dpp[nr].Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
#endif
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))
{
::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
{
if(DXNormalCube)
{
DXNormalCube->Release();
DXNormalCube = 0;
}
if(DXAttenuationVolume)
{
DXAttenuationVolume->Release();
DXAttenuationVolume = 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].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)
{
#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
#ifdef _DOPE
BufferMemAlloc = 0;
#endif
ReCreateZBuffer();
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);
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));
}
}
DiscardCount[0] = DiscardCount[1] = DiscardCount[2] = 1;
LastDecl = -1;
LastVB = -1;
LastVSize = 0;
LastIB = -1;
MtrlReset = sTRUE;
MtrlClearCaches();
CurrentTarget = -1;
}
/****************************************************************************/
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->SetDepthStencilSurface(0)); // only for chaos laptop...
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;
#if !sPLAYER
VideoEnd();
#endif
for(i=0;i<MAX_SETUPS;i++)
{
if(Setups[i].RefCount)
Setups[i].Cleanup();
}
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(DXAttenuationVolume)
{
DXAttenuationVolume->Release();
DXAttenuationVolume = 0;
}
if(ZBuffer)
{
ZBuffer->Release();
ZBuffer = 0;
}
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();
DXDev->Release();
DXDev = 0;
DXD->Release();
DXD = 0;
}
#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);
#if !sCONFIGDIALOG
sSystem->InitX();
#else
if(sAppHandler(sAPPCODE_CONFIG,0))
sSystem->InitX();
#endif
delete sSystem;
ExitProcess(0);
}
#else
void WinMainCRTStartup()
{
WInst = GetModuleHandle(0);
WCmdLine = GetCommandLine();
while(*WCmdLine!=0 && *WCmdLine!=' ') WCmdLine++;
while(*WCmdLine==' ') WCmdLine++;
#if sUSE_LEKKTOR
sLekktorInit();
#endif
sSystem = new sSystem_;
sSetMem(((sU8 *)sSystem)+4,0,sizeof(sSystem_)-4);
#if !sCONFIGDIALOG
sSystem->InitX();
#else
if(sAppHandler(sAPPCODE_CONFIG,0))
sSystem->InitX();
#endif
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
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 = ".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
ExitProcess(0);
}
/****************************************************************************/
void sSystem_::InitScreens()
{
HRESULT hr;
D3DPRESENT_PARAMETERS d3dpp;
sInt i;
sU32 create;
sU16 *iblock;
D3DCAPS9 caps;
sREGZONE(FlipLock);
if(!DXD)
{
DXD = (*Direct3DCreate9P)(D3D_SDK_VERSION);
if(!DXD)
sFatal("DirectX 9.0c not present.");
}
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)==0x0000)
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("could not create screen");
#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;
}
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;
}
#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;
const int step = 3;
sInt time;
sRect r;
IDirect3DSurface9 *backbuffer;
IDirect3DSwapChain9 *swapchain;
#ifndef _DOPE
time = timeGetTime();
if(time > lasttime+450 || done==max)
{
lasttime = time;
sViewport vp;
vp.Init();
SetViewport(vp);
Clear(sVCF_COLOR);
sZONE(FlipLock);
DXDev->GetSwapChain(0,&swapchain);
swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&backbuffer);
r.Init(20+step*0,ConfigY/2-20+step*0,ConfigX-20-step*0,ConfigY/2+20-step*0);
DXDev->ColorFill(backbuffer,(RECT *)&r,0xffffffff);
r.Init(20+step*1,ConfigY/2-20+step*1,ConfigX-20-step*1,ConfigY/2+20-step*1);
DXDev->ColorFill(backbuffer,(RECT *)&r,0xff000000);
r.Init(20+step*2,ConfigY/2-20+step*2,ConfigX-20-step*2,ConfigY/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->EndScene();
DXDev->Present(0,0,0,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&0x8000)
{
DXDev->Release();
ExitProcess(0);
}
#endif
if(!MessagePump())
ExitProcess(0);
}
#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;
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
DXERROR(DXDev->BeginScene());
sAppHandler(sAPPCODE_PAINT,0);
DXERROR(DXDev->EndScene());
#if sPROFILE
sPerfMon->Marker(1);
#endif
#if !sINTRO
if(WResponse)
{
// sDPrintF("w8ing\n");
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();
}
#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;
}
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_::Clear(sU32 flags,sU32 color)
{
// NOTE: we don't support automatically clear textures fully anymore,
// because in the current rendering architecture we either set full
// texture viewports or render to the backbuffer then blit to textures.
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)
{
if(vp.RenderTarget == sINVALID)
{
IDirect3DSwapChain9 *swapchain;
DXERROR(DXDev->GetSwapChain(vp.Screen,&swapchain));
DXERROR(swapchain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&target));
swapchain->Release();
}
else
DXERROR(Textures[vp.RenderTarget].Tex->GetSurfaceLevel(0,&target));
DXDev->SetRenderTarget(0,target);
target->Release();
CurrentTarget = tgtid;
}
DXDev->SetViewport(&d3dvp);
}
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();
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;
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
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;
}
#if sPLAYER
extern sInt DebugTexMem;
#endif
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,
D3DFMT_A1R5G5B5,
};
#else
static D3DFORMAT formats[] =
{
D3DFMT_UNKNOWN,
D3DFMT_A8R8G8B8,
D3DFMT_A8,
D3DFMT_A8R8G8B8,
D3DFMT_A8R8G8B8,
D3DFMT_A8R8G8B8,
D3DFMT_A8R8G8B8,
D3DFMT_A1R5G5B5,
};
#endif
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;
if(data==0)
{
if(tex->XSize==0)
{
tex->XSize = Screen[0].XSize;
tex->YSize = Screen[0].YSize;
}
tex->Flags |= sTIF_RENDERTARGET;
#if LOGGING
sDPrintF("Create Rendertarget %dx%d\n",tex->XSize,tex->YSize);
#endif
#ifdef _DOPE
TexMemAlloc += tex->XSize * tex->YSize * 4;
#endif
#if sPLAYER
DebugTexMem += 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 !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
#if sPLAYER
DebugTexMem += tex->XSize * tex->YSize * 4 * (mipcount ? 4 : 3) / 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(tex->Tex)
tex->Tex->Release();
tex->Flags = 0;
tex->Tex = 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));
}
}
/****************************************************************************/
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)
{
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 = 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));
}
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);
if(tex->Tex)
{
tex->Tex->Release();
tex->Tex = 0;
}
}
/****************************************************************************/
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++)
{
#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;
}
}
/*
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 || (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,1,&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 },
{ 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)
{