Expack3 wrote:Would you know where they tend to be active these days?
Sorry for the late reply. With my upgrade to Debian "Stretch" some time ago, VMware Player stopped working and all Windows related projects are on hold.
However, IDA is running fine with Wine... and here is the analysis as pseudo code:
cpp code// MASK.EXE 1.0.0.3 DE/ES/FR/IT has been built with DXSDK6
#define DIRECTDRAW_VERSION 0x0600 /* DDCAPS, D3DDEVICEDESC */
// template<typename T, short Grow = 5>
// struct KQArray {
// int count;
// int capacity;
// short grow;
// short flags;
// T *array;
// };
// template<typename T, short Grow = 5>
// struct KQPtrArray : public KQArray<T*, Grow> {
// };
////////////////////////////////////////////////////////////////////////////////
// Direct Draw
////////////////////////////////////////////////////////////////////////////////
HMODULE dd_module = NULL;
HWND dd_window = NULL;
LPDIRECTDRAW dd = NULL;
DDCAPS dd_hal_caps;
DDCAPS dd_hel_caps;
BOOL dd_write_only = FALSE;
BOOL dd_create(HWND a_window)
{
dd_module = LoadLibraryA("DDRAW.DLL");
LPDIRECTDRAWCREATE DirectDrawCreate = GetProcAddress(dd_module, "DirectDrawCreate");
if (NULL == DirectDrawCreate) {
if (dd_module != NULL) {
FreeLibrary(dd_module);
// yes, dd_module isn't reset
}
return (FALSE);
}
dd_window = a_window;
if (DirectDrawCreate(NULL, &dd, NULL) != DD_OK) {
return (FALSE);
}
dd_hal_caps.dwSize = sizeof(dd_hal_caps);
dd_hel_caps.dwSize = sizeof(dd_hel_caps);
if (IDirectDraw_GetCaps(dd, &dd_hal_caps, &dd_hel_caps) != DD_OK) {
return (FALSE);
}
if (DDSCAPS_WRITEONLY & dd_hal_caps.ddsCaps.dwCaps) {
dd_write_only = TRUE;
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////////
// Direct 3D
////////////////////////////////////////////////////////////////////////////////
struct KQD3DDeviceInfo {
BOOL valid;
GUID guid;
D3DDEVICEDESC desc;
char *driver_name;
BOOL filter_mip;
BOOL filter_mode;
BOOL blend_color;
BOOL blend_inv;
BOOL blend_mode;
BOOL unknown;
BOOL filter_linear;
BOOL texture_transparency;
BOOL alpha_src;
BOOL alpha_cmp;
};
struct KQD3DDisplayMode {
int width;
int height;
int bpp;
DDSURFACEDESC desc;
};
BOOL d3d_created = FALSE;
HWND d3d_window = NULL;
LPDIRECTDRAWCREATE d3d_DirectDrawCreate = NULL;
LPDIRECTDRAWENUMERATEA d3d_DirectDrawEnumerateA = NULL;
KQArray<LPDIRECTDRAW2> d3d_driver_dd;
KQPtrArray<char> d3d_driver_name;
KQArray<LPDIRECT3D2> d3d_driver_d3d;
KQArray<KQD3DDeviceInfo> d3d_device_info;
KQArray<LPDIRECT3DDEVICE2> d3d_device_intf;
KQPtrArray<KQArray<KQD3DDisplayMode>> d3d_display_modes;
BOOL d3d_driver_add(GUID *a_guid, LPSTR a_desc, LPSTR a_name)
{
LPDIRECTDRAW dd = NULL;
LPDIRECTDRAW2 dd2 = NULL;
if (DD_OK == d3d_DirectDrawCreate(a_guid, &dd, NULL)) {
if (S_OK == IDirectDraw_QueryInterface(dd, &IID_IDirectDraw2, &dd2)) {
DDCAPS hal_caps;
DDCAPS hel_caps;
hal_caps.dwSize = sizeof(hal_caps);
hel_caps.dwSize = sizeof(hel_caps);
IDirectDraw2_GetCaps(dd2, &hal_caps, &hel_caps);
if ((DDCAPS_3D & hal_caps.dwCaps) != 0) {
char *name = new char[strlen("D3D-") + strlen(a_name) + 2];
strcpy(name, "D3D-");
strcat(name, a_name);
d3d_driver_dd.push_back(dd2);
d3d_driver_name.push_back(name);
} else {
IDirectDraw2_Release(dd2);
}
}
IDirectDraw_Release(dd);
}
return (TRUE);
}
BOOL PASCAL d3d_driver_enum(GUID *a_guid, LPSTR a_desc, LPSTR a_name, LPVOID a_info)
{
return (d3d_driver_add(a_guid, a_desc, a_name));
}
HRESULT d3d_device_find(GUID *a_guid, LPSTR a_desc, LPSTR a_name, D3DDEVICEDESC *a_hal, D3DDEVICEDESC *a_hel, KQD3DDeviceInfo *a_info)
{
if (0 == (D3DCOLOR_RGB & a_hal->dcmColorModel)) {
return (DDENUMRET_OK);
}
BOOL valid = TRUE;
if (0 == (D3DDD_DEVICEZBUFFERBITDEPTH & a_hal->dwFlags)) {
valid = FALSE;
}
if (0 == ((DDBD_16 | DDBD_24 | DDBD_32) & a_hal->dwDeviceZBufferBitDepth)) {
valid = FALSE;
}
if (0 == (D3DPCMPCAPS_LESSEQUAL & a_hal->dpcTriCaps.dwZCmpCaps)) {
valid = FALSE;
}
if (0 == (D3DPRASTERCAPS_FOGVERTEX & a_hal->dpcTriCaps.dwRasterCaps)) {
valid = FALSE;
}
if (0 == (D3DPSHADECAPS_FOGGOURAUD & a_hal->dpcTriCaps.dwShadeCaps)) {
valid = FALSE;
}
if (((D3DPBLENDCAPS_SRCALPHA & a_hal->dpcTriCaps.dwSrcBlendCaps) != 0) &&
((D3DPBLENDCAPS_INVSRCALPHA & a_hal->dpcTriCaps.dwDestBlendCaps) != 0)) {
a_info->alpha_src = FALSE;
} else if (
((D3DPBLENDCAPS_INVSRCALPHA & a_hal->dpcTriCaps.dwSrcBlendCaps) != 0) &&
((D3DPBLENDCAPS_SRCALPHA & a_hal->dpcTriCaps.dwDestBlendCaps) != 0)) {
valid = FALSE;
} else {
a_info->alpha_src = TRUE;
}
a_info->alpha_cmp = TRUE;
if (a_info->alpha_src != FALSE) {
if (0 == (D3DPCMPCAPS_ALWAYS & a_hal->dpcTriCaps.dwAlphaCmpCaps)) {
a_info->alpha_cmp = FALSE;
}
} else {
if (0 == (D3DPCMPCAPS_LESSEQUAL & a_hal->dpcTriCaps.dwAlphaCmpCaps)) {
a_info->alpha_cmp = FALSE;
}
}
if (0 == (D3DPSHADECAPS_COLORGOURAUDRGB & a_hal->dpcTriCaps.dwShadeCaps)) {
valid = FALSE;
}
a_info->filter_mip = (((
D3DPTFILTERCAPS_MIPNEAREST |
D3DPTFILTERCAPS_MIPLINEAR |
D3DPTFILTERCAPS_LINEARMIPNEAREST |
D3DPTFILTERCAPS_LINEARMIPLINEAR) &
a_hal->dpcTriCaps.dwTextureFilterCaps) != 0) ? TRUE : FALSE;
a_info->filter_mode = 2;
if ((D3DPTEXTURECAPS_PERSPECTIVE | D3DPTEXTURECAPS_ALPHA) != (
(D3DPTEXTURECAPS_PERSPECTIVE | D3DPTEXTURECAPS_ALPHA) & a_hal->dpcTriCaps.dwTextureCaps)) {
valid = FALSE;
}
a_info->texture_transparency = TRUE;
if (0 == (D3DPTEXTURECAPS_TRANSPARENCY & a_hal->dpcTriCaps.dwTextureCaps)) {
a_info->texture_transparency = FALSE;
}
if (0 == (D3DPTBLENDCAPS_MODULATE & a_hal->dpcTriCaps.dwTextureBlendCaps)) {
valid = FALSE;
}
if ((((D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR) & a_hal->dpcTriCaps.dwDestBlendCaps) != 0) &&
((D3DPTFILTERCAPS_LINEAR & a_hal->dpcTriCaps.dwTextureFilterCaps) != 0)) {
a_info->filter_linear = TRUE;
a_info->blend_color = TRUE;
if ((D3DPBLENDCAPS_SRCCOLOR & a_hal->dpcTriCaps.dwDestBlendCaps) != 0) {
a_info->blend_inv = FALSE;
a_info->blend_mode = 3;
} else {
a_info->blend_inv = TRUE;
a_info->blend_mode = 4;
}
} else if (
(((D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA) & a_hal->dpcTriCaps.dwDestBlendCaps) != 0) &&
((D3DPTFILTERCAPS_LINEAR & a_hal->dpcTriCaps.dwTextureFilterCaps) != 0)) {
a_info->filter_linear = TRUE;
a_info->blend_color = FALSE;
if ((D3DPBLENDCAPS_SRCCOLOR & a_hal->dpcTriCaps.dwDestBlendCaps) != 0) {
a_info->blend_inv = FALSE;
a_info->blend_mode = 5;
} else {
a_info->blend_inv = TRUE;
a_info->blend_mode = 6;
}
} else {
a_info->filter_linear = FALSE;
valid = FALSE;
}
if (0 == (D3DPSHADECAPS_SPECULARGOURAUDRGB & a_hal->dpcTriCaps.dwShadeCaps)) {
valid = FALSE;
}
if (valid != FALSE) {
a_info->valid = TRUE;
a_info->guid = *a_guid;
memcpy(&a_info->desc, a_hal, sizeof(a_info->desc));
int n = strlen(a_info->driver_name) + 1;
for (int i = 0; i < n; ++i) {
char *c = &a_info->driver_name;
if (' ' == *c) {
*c = '-';
}
}
return (DDENUMRET_CANCEL);
}
a_info->driver_name = NULL;
return (DDENUMRET_OK);
}
HRESULT CALLBACK d3d_device_enum(GUID *a_guid, LPSTR a_desc, LPSTR a_name, LPD3DDEVICEDESC a_hal, LPD3DDEVICEDESC a_hel, LPVOID a_info)
{
return (d3d_device_find(a_guid, a_desc, a_name, a_hal, a_hel, a_info);
}
BOOL d3d_create(HWND a_window)
{
if (TRUE == d3d_created) {
return (TRUE);
}
d3d_window = window;
d3d_module = LoadLibraryA("DDRAW.DLL");
d3d_DirectDrawCreate = GetProcAddress(d3d_module, "DirectDrawCreate");
d3d_DirectDrawEnumerateA = GetProcAddress(d3d_module, "DirectDrawEnumerateA");
if ((NULL == d3d_DirectDrawCreate) ||
(NULL == d3d_DirectDrawEnumerateA ||
(d3d_DirectDrawEnumerateA(d3d_driver_enum, NULL) != DD_OK)) {
if (d3d_DirectDrawEnumerateA != NULL) {
for (int i = 0; i < d3d_driver_dd.count; ++i) {
LPDIRECTDRAW2 dd = d3d_driver_dd.array;
if (dd != NULL) {
IDirectDraw2_Release(dd);
}
d3d_driver_dd.array = NULL;
}
d3d_driver_dd.clear();
}
if (d3d_module != NULL) {
FreeLibrary(d3d_module);
}
d3d_window = NULL;
return (FALSE);
}
d3d_driver_d3d.resize(d3d_driver_dd.count);
d3d_device_info.resize(d3d_driver_dd.count);
for (int i = 0; i < d3d_driver_dd.count; ++i) {
LPDIRECT3D2 d3d = NULL;
IDirectDraw2_QueryInterface(d3d_driver_dd.array, &IID_IDirect3D2, &d3d);
d3d_driver_d3d.array = d3d;
d3d_device_info.array.valid = FALSE;
d3d_device_info.array.name = d3d_driver_name.array;
if (d3d2 != NULL) {
IDirect3D2_EnumDevices(d3d2, d3d_device_enum, &d3d_device_info.array);
}
if (TRUE == d3d_device_info.array.valid) {
d3d_driver_name.array[i] = NULL;
}
}
d3d_device_intf.resize(d3d_driver_dd.count);
for (int i = 0; i < d3d_device_intf.count; ++i) {
d3d_device_intf.array[i] = NULL;
}
d3d_display_modes.resize(d3d_driver_dd.count);
for (int i = 0; i < d3d_display_modes.count; ++i) {
d3d_display_modes.array[i] = new KQArray<KQD3DDisplayMode>;
}
d3d_created = TRUE;
return (TRUE);
}
HRESULT PASCAL d3d_display_modes_add(LPDDSURFACEDESC a_desc, LPVOID a_info)
{
KQArray<KQD3DDisplayMode> *modes = a_info;
if (16 == a_desc->ddpfPixelFormat.dwRGBBitCount) {
KQD3DDisplayMode mode;
mode.height = a_desc->dwHeight;
mode.width = a_desc->dwWidth;
mode.bpp = 16;
memcpy(&mode.desc, a_desc, sizeof(mode.desc));
modes->push_back(mode);
}
return (DDENUMRET_OK);
}
HRESULT d3d_display_modes_enum(int a_driver, KQArray<KQD3DDisplayMode> *a_modes)
{
DDSURFACEDESC ddsd;
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_BACKBUFFERCOUNT | DDSD_CAPS;
ddsd.dwBackBufferCount = 2;
ddsd.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | DDSCAPS_FLIP;
a_modes->clear();
return (IDirectDraw2_EnumDisplayModes(d3d_driver_dd.array[a_driver], 0, &ddsd, a_modes, d3d_display_modes_add);
}
This is the base DD and D3D initialization. I included the display mode enumeration to document the 16-bit filter.
All structures and member names are pure guesswork, but the "code" should be sufficient to answer the topic.