/**********************************************************************
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.hh"
#include "image/image.hh"
#include "time/profile.hh"
#include "main/win_main.hh"
#include "image/context.hh"
#include "video/win32/dx5_util.hh"
#include "video/win32/dx5_error.hh"
#include "threads/threads.hh"
static i4_profile_class pf_dx5_mouse("dx5::mouse draw"),
pf_dx5_copy("dx5::copy dirty"),
pf_dx5_flip("dx5::flip"),
pf_dx5_lock("dx5::lock");
i4_dx5_display_class i4_dx5_display_class_instance;
i4_dx5_display_class *i4_dx5_display=0;
struct gr_buf_status_type
{
sw8 state; // -1 = not locked, else
// I4_FRAME_BUFFER_READ,
// or I4_FRAME_BUFFER_WRITE
i4_image_class *im;
} dx_buf[2]; // I4_FRONT_FRAME_BUFFER=0, I4_BACK_FRAME_BUFFER=1
int dx5_error_function(const char *str)
{
dx5_common.cleanup();
i4_dx5_display->error_handler.old_error_handler(str);
return 0;
}
i4_refresh_type i4_dx5_display_class::update_model()
{
if (use_page_flip)
return I4_PAGE_FLIP_REFRESH;
else
return I4_BLT_REFRESH;
}
i4_image_class *i4_dx5_display_class::lock_frame_buffer(i4_frame_buffer_type type,
i4_frame_access_type access)
{
if (access==dx_buf[type].state)
return dx_buf[type].im;
else if (dx_buf[type].state!=-1)
unlock_frame_buffer(type);
HRESULT res=0;
DDSURFACEDESC cur_dx5_lock_info;
memset(&cur_dx5_lock_info,0,sizeof(DDSURFACEDESC));
cur_dx5_lock_info.dwSize = sizeof(DDSURFACEDESC);
IDirectDrawSurface3 *surf=type==I4_FRONT_FRAME_BUFFER ?
dx5_common.front_surface : dx5_common.back_surface;
int flags=access==I4_FRAME_BUFFER_READ ? DDLOCK_READONLY :
DDLOCK_WRITEONLY;
if (!surf)
return 0;
res = surf->Lock(NULL,&cur_dx5_lock_info, flags | DDLOCK_WAIT,0);
if (res == DD_OK)
{
#ifdef DEBUG
surf->Unlock(NULL);
#endif
dx_buf[type].im->data=cur_dx5_lock_info.lpSurface;
dx_buf[type].im->bpl=cur_dx5_lock_info.lPitch;
dx_buf[type].state=access;
}
return dx_buf[type].im;
}
void i4_dx5_display_class::unlock_frame_buffer(i4_frame_buffer_type type)
{
IDirectDrawSurface3 *surf=type==I4_FRONT_FRAME_BUFFER ?
dx5_common.front_surface : dx5_common.back_surface;
#ifndef DEBUG
if (surf)
surf->Unlock(NULL);
#endif
dx_buf[type].im->data=0;
dx_buf[type].state=-1;
}
// i4_image_class *i4_dx5_display_class::grab_framebuffer()
// {
// if (!fake_screen) return 0;
// i4_image_class *im=i4_create_image(width(), height(), fake_screen->get_pal());
// void *mem=dx5_lock(DX5_LOCK_READ);
// for (int y=0; ydata + y*im->bpl);
// for (int x=0; xnext, id++)
{
IDirectDraw2 *ddraw=dx5_common.initialize_driver(d);
if (ddraw)
{
// no hardware acceleration for this demo
if (dx5_common.get_driver_hardware_info(ddraw))
{
sprintf(n, "%s : 3d Accelerated", d->DriverName);
i4_display_list_struct *s=new i4_display_list_struct;
s->add_to_list(n, id | 0x8000, this, i4_display_list);
n+=strlen(n)+1;
}
//only want software rendering stuffs for the primary display driver to be listed
if (!stricmp(d->DriverName,"display"))
{
sprintf(n, "%s : Software Rendered", d->DriverName);
i4_display_list_struct *s=new i4_display_list_struct;
s->add_to_list(n, id, this, i4_display_list);
n+=strlen(n)+1;
}
ddraw->Release();
}
}
dx5_common.free_driver_list(list);
}
// find the driver, then get it's modes and return the first one
i4_display_class::mode *i4_dx5_display_class::get_first_mode(int driver_id)
{
int find_id = driver_id & (~0x8000); // top bit indicates hardware accelerated
if (mode_list)
{
dx5_common.free_mode_list(mode_list);
mode_list=0;
}
dx5_driver *driver_list=dx5_common.get_driver_list(), *d;
for (d=driver_list; find_id && d; d=d->next, find_id--);
IDirectDraw2 *ddraw=dx5_common.initialize_driver(d);
dx5_common.free_driver_list(driver_list);
if (!ddraw) return 0;
mode_list=dx5_common.get_mode_list(ddraw);
ddraw->Release();
amode.dx5=mode_list;
amode.driver_id=driver_id;
return get_next_mode();
}
i4_dx5_display_class::~i4_dx5_display_class()
{
;
}
i4_display_class::mode *i4_dx5_display_class::get_next_mode()
{
if (!amode.dx5)
return 0;
DDSURFACEDESC *desc=&amode.dx5->desc;
sprintf(amode.name, "%d X %d 16bit", desc->dwWidth, desc->dwHeight);
amode.xres=desc->dwWidth;
amode.yres=desc->dwHeight;
amode.bits_per_pixel=16;
amode.red_mask = desc->ddpfPixelFormat.dwRBitMask;
amode.green_mask = desc->ddpfPixelFormat.dwGBitMask;
amode.blue_mask = desc->ddpfPixelFormat.dwBBitMask;
amode.flags =0;
last_mode=amode;
amode.dx5=amode.dx5->next;
return &amode;
}
i4_bool i4_dx5_display_class::initialize_mode()
{
if (!i4_win32_startup_options.fullscreen)
use_page_flip = i4_F;
if (!input.create_window(0,0,
last_mode.xres,
last_mode.yres, this, i4_win32_startup_options.fullscreen))
return i4_F;
int x,y,w,h;
if (!i4_win32_startup_options.fullscreen)
input.get_window_area(x,y,w,h);
else
{
w=last_mode.xres;
h=last_mode.yres;
}
last_mode.xres=w;
last_mode.yres=h;
// find the driver and initialize it
int find_id = last_mode.driver_id & (~0x8000);
dx5_driver *driver_list=dx5_common.get_driver_list(), *d;
for (d=driver_list; find_id && d; d=d->next, find_id--);
dx5_common.ddraw=dx5_common.initialize_driver(d);
dx5_common.free_driver_list(driver_list);
if (!dx5_common.ddraw)
return i4_F;
if (i4_win32_startup_options.fullscreen && use_exclusive_mode)
{
// change the error handling function so that the screen is restored before
// a dialog box is displayed, or they won't be able to read the message!
if (i4_dx5_check(dx5_common.ddraw->SetCooperativeLevel(input.get_window_handle(),
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN)))
{
error_handler.old_error_handler=i4_get_error_function();
error_handler.need_restore_old=i4_T;
i4_set_error_function(dx5_error_function);
}
else return i4_F;
}
else if (!i4_dx5_check(dx5_common.ddraw->SetCooperativeLevel(input.get_window_handle(),
DDSCL_NORMAL)))
return i4_F;
//win95 function to hide the mouse cursor. our display uses our own cursor
if (i4_win32_startup_options.fullscreen &&
!i4_dx5_check(dx5_common.ddraw->SetDisplayMode(last_mode.xres, last_mode.yres,16,0,0)))
return i4_F;
if (use_page_flip)
{
if (!dx5_common.create_surface(DX5_PAGE_FLIPPED_PRIMARY_SURFACE,
last_mode.xres, last_mode.yres))
return i4_F;
}
else if (!dx5_common.create_surface(DX5_BACKBUFFERED_PRIMARY_SURFACE,
last_mode.xres, last_mode.yres))
return i4_F;
// find the size of the primary surface
DDSURFACEDESC ddsd;
dx5_common.get_surface_description(dx5_common.primary_surface, ddsd);
fake_screen=new i4_dx5_image_class(last_mode.xres, last_mode.yres);
fake_screen->surface->PageLock(0);
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);
dx_buf[0].im=i4_create_image(last_mode.xres, last_mode.yres, pal, 0, 0);
dx_buf[0].state=-1;
dx_buf[1].im=i4_create_image(last_mode.xres, last_mode.yres, pal, 0, 0);
dx_buf[1].state=-1;
context = new i4_draw_context_class(0,0, last_mode.xres-1, last_mode.yres-1);
context->both_dirty = new i4_rect_list_class;
memcpy(&cur_mode, &last_mode, sizeof(last_mode));
if (1) //!i4_win32_startup_options.fullscreen)
mouse = new dx5_mouse_class(use_page_flip);
else
{
thread_mouse = new ddraw_thread_cursor_class(pal,input.get_window_handle(),
0,0,last_mode.xres,last_mode.yres);
input.set_async_mouse(thread_mouse);
}
return i4_T;
}
i4_bool i4_dx5_display_class::close()
{
if (mouse)
{
delete mouse;
mouse = 0;
}
input.set_async_mouse(0);
if (thread_mouse)
{
delete thread_mouse;
thread_mouse = 0;
}
if (error_handler.need_restore_old)
{
i4_set_error_function(error_handler.old_error_handler);
error_handler.need_restore_old=i4_F;
}
input.destroy_window();
for (int i=0; i<2; i++)
{
if (dx_buf[i].im)
{
delete dx_buf[i].im;
dx_buf[i].im=0;
}
}
if (fake_screen)
{
delete fake_screen;
fake_screen=0;
}
if (context)
{
delete context;
context=0;
}
if (mode_list)
{
dx5_common.free_mode_list(mode_list);
mode_list=0;
}
next_frame_copy.delete_list();
dx5_common.cleanup();
return i4_T;
}
i4_bool i4_dx5_display_class::set_mouse_shape(i4_cursor_class *cursor)
{
if (mouse)
{
mouse->set_cursor(cursor);
return i4_T;
}
else
if (thread_mouse)
{
thread_mouse->set_cursor(cursor);
return i4_T;
}
return i4_F;
}
void i4_dx5_display_class::flush()
{
RECT src;
if (!input.get_active())
{
context->both_dirty->delete_list();
context->both_dirty->add_area(0,0,width()-1, height()-1);
i4_thread_yield();
return ;
}
//start of copy stuff
pf_dx5_copy.start();
context->both_dirty->intersect_area(0,0,width()-1,height()-1);
// Step 1 : copy middle buffer information to the back-buffer
i4_rect_list_class::area_iter a,b;
i4_rect_list_class *use_list;
// if page flipped we need to make add the current dirty to the stuff left over from last frame
if (use_page_flip)
{
a=context->both_dirty->list.begin();
for (;a!=context->both_dirty->list.end();++a)
next_frame_copy.add_area(a->x1, a->y1, a->x2, a->y2);
use_list=&next_frame_copy;
}
else
use_list=context->both_dirty;
int wx,wy,ww,wh;
input.get_window_area(wx,wy,ww,wh);
for (a=use_list->list.begin(); a!=use_list->list.end(); ++a)
{
src.left = a->x1;
src.top = a->y1;
src.right = a->x2+1;
src.bottom = a->y2+1;
if (!i4_dx5_check(dx5_common.back_surface->BltFast(a->x1, a->y1, fake_screen->surface,
&src,DDBLTFAST_NOCOLORKEY |
DDBLTFAST_WAIT)))
i4_error("dx5 blt failed on area %d %d %d %d ", a->x1, a->y1,a->x2, a->y2);
}
pf_dx5_copy.stop();
//end of copy stuff
//start of mouse stuff
pf_dx5_mouse.start();
mouse_x = input.mouse_x;
mouse_y = input.mouse_y;
if (mouse)
mouse->save_and_draw(mouse_x, mouse_y);
pf_dx5_mouse.stop();
//start of flip stuff
pf_dx5_flip.start();
// now flip or copy the backbuffer to video memory
if (use_page_flip)
{
// if (thread_mouse)
// {
// thread_mouse->draw_lock.lock();
// thread_mouse->use_backbuffer(i4_F);
// thread_mouse->remove(); //remove from front buffer
// thread_mouse->use_backbuffer(i4_T);
// thread_mouse->display();//display on back buffer
// }
dx5_common.primary_surface->Flip(NULL,DDFLIP_WAIT);
// if (thread_mouse)
// {
// thread_mouse->use_backbuffer(i4_F);
// thread_mouse->draw_lock.unlock();
// }
}
else
{
// if (thread_mouse)
// {
// thread_mouse->draw_lock.lock();
// thread_mouse->use_backbuffer(i4_T);
// thread_mouse->display();
// }
if (!i4_dx5_check(dx5_common.primary_surface->BltFast(0,0,dx5_common.back_surface, NULL,
DDBLTFAST_NOCOLORKEY |
DDBLTFAST_WAIT)))
i4_error("dx5 blt failed");
// if (thread_mouse)
// {
// thread_mouse->remove();
// thread_mouse->set_visible(i4_T);
// thread_mouse->use_backbuffer(i4_F);
// thread_mouse->draw_lock.unlock();
// }
}
pf_dx5_flip.stop();
//end of flip stuff
pf_dx5_mouse.start();
if (mouse)
mouse->restore();
pf_dx5_mouse.stop();
if (use_page_flip)
next_frame_copy.swap(context->both_dirty);
context->both_dirty->delete_list();
}