/**********************************************************************
This file is part of Crack dot Com's free source code release of
Golgotha.
for
information about compiling & licensing issues visit this URL
If that doesn't help, contact Jonathan Clark at
golgotha_source@usa.net (Subject should have "GOLG" in it)
***********************************************************************/
#include "video/win32/dx5_util.hh"
#include "video/win32/dx5_error.hh"
#include "threads/threads.hh"
#include "error/error.hh"
#define DEPTH 16
dx5_common_class dx5_common;
IDirectDraw2 *dx5_common_class::ddraw;
IDirectDrawSurface3 *dx5_common_class::primary_surface, *dx5_common_class::back_surface,
*dx5_common_class::front_surface;
DDPIXELFORMAT dx5_common_class::dd_fmt_565, dx5_common_class::dd_fmt_1555;
i4_pixel_format dx5_common_class::i4_fmt_565, dx5_common_class::i4_fmt_1555;
IDirectDrawSurface3 *dx5_common_class::create_surface(dx5_surface_type type,
int width, int height,
int flags,
DDPIXELFORMAT *format)
{
HRESULT result;
DDSURFACEDESC ddsd;
IDirectDrawSurface *surface;
IDirectDrawSurface3 *surface3;
memset(&ddsd,0,sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
if (type==DX5_PAGE_FLIPPED_PRIMARY_SURFACE)
{
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_FLIP |
DDSCAPS_COMPLEX |
DDSCAPS_3DDEVICE |
DDSCAPS_VIDEOMEMORY;
ddsd.dwBackBufferCount = 1;
}
else if (type==DX5_BACKBUFFERED_PRIMARY_SURFACE)
{
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY;
}
else
{
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = 0;
if (format)
{
ddsd.dwFlags |= DDSD_PIXELFORMAT;
ddsd.ddpfPixelFormat = *format;
}
ddsd.dwWidth = width;
ddsd.dwHeight = height;
if (flags & DX5_SYSTEM_RAM)
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
if (flags & DX5_VRAM)
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
if (flags & DX5_RENDERING_SURFACE)
ddsd.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE;
if (type==DX5_TEXTURE)
ddsd.ddsCaps.dwCaps |= DDSCAPS_TEXTURE;
}
result = ddraw->CreateSurface(&ddsd, &surface, NULL);
if (!i4_dx5_check(result))
surface=0;
if (surface)
{
surface->QueryInterface(IID_IDirectDrawSurface3,(void **)&surface3);
surface->Release();
if (flags & DX5_CLEAR)
{
DDBLTFX fx;
memset(&fx,0,sizeof(DDBLTFX));
fx.dwSize = sizeof(DDBLTFX);
RECT r;
r.left = 0;
r.top = 0;
r.right = width;
r.bottom = height;
surface3->Blt(&r, 0, 0, DDBLT_COLORFILL,&fx);
}
if (type==DX5_PAGE_FLIPPED_PRIMARY_SURFACE)
{
primary_surface = surface3;
// get the back buffer surface
DDSCAPS caps;
caps.dwCaps = DDSCAPS_BACKBUFFER;
result = primary_surface->GetAttachedSurface(&caps, &back_surface);
if (!i4_dx5_check(result))
{
primary_surface->Release(); primary_surface=0;
surface3=0;
}
caps.dwCaps = DDSCAPS_FRONTBUFFER;
result = primary_surface->GetAttachedSurface(&caps, &front_surface);
if (!i4_dx5_check(result))
{
back_surface->Release(); back_surface=0;
primary_surface->Release(); primary_surface=0;
surface3=0;
}
}
else if (type==DX5_BACKBUFFERED_PRIMARY_SURFACE)
{
DDSURFACEDESC desc;
get_desc(surface3, desc);
primary_surface = surface3;
back_surface = create_surface(DX5_SURFACE, width, height,
DX5_RENDERING_SURFACE | DX5_VRAM | DX5_CLEAR);
if (!back_surface)
{
primary_surface->Release();
surface3=0;
}
}
}
else if (flags & DX5_VRAM) // try to create it in system ram
{
i4_warning("failed to create surface in video memory");
surface3=create_surface(DX5_SURFACE, width, height,
(flags & (~DX5_VRAM)) | DX5_SYSTEM_RAM, format);
}
return surface3;
}
void dx5_common_class::cleanup()
{
if (back_surface)
{
back_surface->Release();
back_surface=0;
}
if (front_surface)
{
front_surface->Release();
front_surface=0;
}
if (primary_surface)
{
primary_surface->Release();
primary_surface=0;
}
if (ddraw)
{
ddraw->Release();
ddraw=0;
}
}
dx5_common_class::dx5_common_class()
{
ddraw=0;
primary_surface=back_surface=front_surface=0;
i4_fmt_565.pixel_depth = I4_16BIT;
i4_fmt_565.red_mask = 31 << 11;
i4_fmt_565.green_mask = 63 << 5;
i4_fmt_565.blue_mask = 31;
i4_fmt_565.alpha_mask = 0;
i4_fmt_565.lookup = 0;
i4_fmt_565.calc_shift();
i4_fmt_1555.pixel_depth = I4_16BIT;
i4_fmt_1555.red_mask = 31 << 10;
i4_fmt_1555.green_mask = 31 << 5;
i4_fmt_1555.blue_mask = 31;
i4_fmt_1555.alpha_mask = 0;
i4_fmt_1555.lookup = 0;
i4_fmt_1555.calc_shift();
memset(&dd_fmt_565,0,sizeof(DDPIXELFORMAT));
dd_fmt_565.dwSize = sizeof(DDPIXELFORMAT);
dd_fmt_565.dwFlags = DDPF_RGB;
dd_fmt_565.dwRGBBitCount = 16;
dd_fmt_565.dwRBitMask = 31 << 11;
dd_fmt_565.dwGBitMask = 63 << 5;
dd_fmt_565.dwBBitMask = 31;
memset(&dd_fmt_1555,0,sizeof(DDPIXELFORMAT));
dd_fmt_1555.dwSize = sizeof(DDPIXELFORMAT);
dd_fmt_1555.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
dd_fmt_1555.dwRGBBitCount = 16;
dd_fmt_1555.dwRBitMask = 31 << 10;
dd_fmt_1555.dwGBitMask = 31 << 5;
dd_fmt_1555.dwBBitMask = 31;
dd_fmt_1555.dwRGBAlphaBitMask = 1 << 15;
}
//******************************* VIDEO MODE ENUMERATION ***************************
static dx5_mode *dx_mode_list;
HRESULT WINAPI dx5_vidmode_callback(LPDDSURFACEDESC lpDDSurfaceDesc,LPVOID lpContext)
{
dx5_mode *m=new dx5_mode(dx_mode_list);
dx_mode_list=m;
m->desc=*lpDDSurfaceDesc;
return DDENUMRET_OK;
}
dx5_mode *dx5_common_class::get_mode_list(IDirectDraw2 *dd)
{
dx_mode_list=0;
DDSURFACEDESC ddsd;
DDPIXELFORMAT p_format;
memset(&ddsd,0,sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_PIXELFORMAT;
memset(&p_format,0,sizeof(DDPIXELFORMAT));
p_format.dwSize = sizeof(DDPIXELFORMAT);
p_format.dwFlags = DDPF_RGB;
p_format.dwRGBBitCount = DEPTH;
ddsd.ddpfPixelFormat = p_format;
if (!i4_dx5_check(dd->EnumDisplayModes(0,&ddsd,0,(LPDDENUMMODESCALLBACK)dx5_vidmode_callback)))
{
free_mode_list(dx_mode_list);
dx_mode_list=0;
}
return dx_mode_list;
}
void dx5_common_class::free_mode_list(dx5_mode *list)
{
while (list)
{
dx5_mode *p=list;
list=list->next;
delete p;
}
}
//************************** DRIVER ENUMERATION AND CREATION ************************
static dx5_driver *dx_driver_list;
BOOL WINAPI dd_device_callback(LPGUID lpGuid, LPSTR lpDeviceDesc,
LPSTR lpDriverName, LPVOID lpUserArg)
{
dx5_driver *d=new dx5_driver(dx_driver_list);
dx_driver_list=d;
d->lpGuid = lpGuid;
strcpy(d->DriverName, lpDriverName);
strcpy(d->DeviceDesc, lpDeviceDesc);
return DDENUMRET_OK;
}
dx5_driver *dx5_common_class::get_driver_list()
{
dx_driver_list=0;
if (!i4_dx5_check(DirectDrawEnumerate(dd_device_callback,0)))
{
free_driver_list(dx_driver_list);
dx_driver_list=0;
}
return dx_driver_list;
}
void dx5_common_class::free_driver_list(dx5_driver *list)
{
while (list)
{
dx5_driver *n=list;
list=list->next;
delete n;
}
}
static IDirectDraw *dx5_ddraw;
BOOL WINAPI dd_create_callback(LPGUID lpGuid, LPSTR lpDeviceDescription,
LPSTR lpDriverName, LPVOID lpUserArg)
{
char *desired_driver = (char *)lpUserArg;
if (!stricmp(desired_driver,lpDriverName))
{
HRESULT res = DirectDrawCreate(lpGuid, &dx5_ddraw, 0);
return DDENUMRET_CANCEL;
}
return DDENUMRET_OK;
}
IDirectDraw2 *dx5_common_class::initialize_driver(dx5_driver *driver)
{
if (!driver) return 0;
dx5_ddraw=0;
if (!i4_dx5_check(DirectDrawEnumerate(dd_create_callback,(void *)driver->DriverName)))
return 0;
if (!dx5_ddraw)
return 0;
IDirectDraw2 *dd=0;
if (!i4_dx5_check(dx5_ddraw->QueryInterface(IID_IDirectDraw2,(void **)&dd)))
{
dx5_ddraw->Release();
return 0;
}
dx5_ddraw->Release(); // we are only using DirectDraw2 interface, free this one
return dd;
}
static LPGUID dx5_hardware_guid;
static dx5_d3d_info dx5_d3d;
HRESULT __stdcall d3d_device_callback(LPGUID lpGuid, LPSTR lpDeviceDescription,
LPSTR lpDeviceName, LPD3DDEVICEDESC lpD3DHWDeviceDesc,
LPD3DDEVICEDESC lpD3DHELDeviceDesc, LPVOID lpUserArg)
{
if (strcmp(lpDeviceName, "Direct3D HAL")==0 && lpD3DHWDeviceDesc->dwDeviceZBufferBitDepth!=0)
{
dx5_d3d.lpGuid = lpGuid;
dx5_d3d.lpDeviceName = lpDeviceName;
dx5_d3d.hw_desc = *lpD3DHWDeviceDesc;
dx5_d3d.sw_desc = *lpD3DHELDeviceDesc;
}
return D3DENUMRET_OK;
}
dx5_d3d_info *dx5_common_class::get_driver_hardware_info(IDirectDraw2 *dd)
{
dx5_d3d.lpGuid=0;
IDirect3D2 *d3d;
if (!i4_dx5_check(dd->QueryInterface(IID_IDirect3D2,(void **)&d3d)))
return 0;
d3d->EnumDevices(d3d_device_callback,0);
d3d->Release();
if (dx5_d3d.lpGuid)
return &dx5_d3d;
return 0;
}
i4_dx5_image_class::i4_dx5_image_class(w16 _w, w16 _h, w32 flags)
{
w=_w;
h=_h;
DDSURFACEDESC ddsd;
dx5_common.get_surface_description(dx5_common.primary_surface,ddsd);
i4_pixel_format fmt;
fmt.pixel_depth = I4_16BIT;
fmt.red_mask = ddsd.ddpfPixelFormat.dwRBitMask;
fmt.green_mask = ddsd.ddpfPixelFormat.dwGBitMask;
fmt.blue_mask = ddsd.ddpfPixelFormat.dwBBitMask;
fmt.alpha_mask = 0;
fmt.calc_shift();
pal = i4_pal_man.register_pal(&fmt);
//we want to create the surface w/the same pixel format as the primary surface
surface = dx5_common.create_surface(DX5_SURFACE, w,h, flags, &ddsd.ddpfPixelFormat);
if (!surface)
i4_warning("i4_dx5_image_class::create_surface failed");
else
{
lock();
unlock();
}
}
void i4_dx5_image_class::lock()
{
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize=sizeof(ddsd);
if (!i4_dx5_check(surface->Lock(0, &ddsd,DDLOCK_WRITEONLY | DDLOCK_WAIT | DDLOCK_NOSYSLOCK,0)))
i4_error("couldn't lock surface");
data = (w8 *)ddsd.lpSurface;
bpl = ddsd.lPitch;
}
void i4_dx5_image_class::unlock()
{
surface->Unlock(0);
}
IDirectDrawSurface3 *dx5_common_class::get_surface(i4_image_class *im)
{
return ((i4_dx5_image_class *)im)->surface;
}
i4_image_class *dx5_common_class::create_image(int w, int h, w32 surface_flags)
{
return new i4_dx5_image_class(w,h,surface_flags);
}