source: golgotha/src/i4/video/win32/dx5.cc @ 80

Last change on this file since 80 was 80, checked in by Sam Hocevar, 15 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 14.2 KB
Line 
1/********************************************************************** <BR>
2  This file is part of Crack dot Com's free source code release of
3  Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
4  information about compiling & licensing issues visit this URL</a>
5  <PRE> If that doesn't help, contact Jonathan Clark at
6  golgotha_source@usa.net (Subject should have "GOLG" in it)
7***********************************************************************/
8
9#include "video/win32/dx5.hh"
10#include "image/image.hh"
11#include "time/profile.hh"
12#include "main/win_main.hh"
13#include "image/context.hh"
14
15#include "video/win32/dx5_util.hh"
16#include "video/win32/dx5_error.hh"
17#include "threads/threads.hh"
18
19
20static i4_profile_class pf_dx5_mouse("dx5::mouse draw"),
21  pf_dx5_copy("dx5::copy dirty"),
22  pf_dx5_flip("dx5::flip"),
23  pf_dx5_lock("dx5::lock");
24
25i4_dx5_display_class i4_dx5_display_class_instance;
26
27i4_dx5_display_class *i4_dx5_display=0;
28
29struct gr_buf_status_type
30{
31  sw8            state;  // -1 = not locked, else 
32                         //    I4_FRAME_BUFFER_READ,
33                         // or I4_FRAME_BUFFER_WRITE
34  i4_image_class *im;
35
36
37} dx_buf[2];    // I4_FRONT_FRAME_BUFFER=0, I4_BACK_FRAME_BUFFER=1
38
39
40
41int dx5_error_function(const char *str)
42{
43  dx5_common.cleanup();
44  i4_dx5_display->error_handler.old_error_handler(str);
45  return 0;
46}
47
48i4_refresh_type i4_dx5_display_class::update_model()
49{
50  if (use_page_flip)
51    return I4_PAGE_FLIP_REFRESH;
52  else
53    return I4_BLT_REFRESH;
54 
55}
56
57i4_image_class *i4_dx5_display_class::lock_frame_buffer(i4_frame_buffer_type type,
58                                                  i4_frame_access_type access)
59{
60  if (access==dx_buf[type].state)
61    return dx_buf[type].im;
62  else if (dx_buf[type].state!=-1)
63    unlock_frame_buffer(type);
64
65  HRESULT res=0;
66
67  DDSURFACEDESC cur_dx5_lock_info;
68  memset(&cur_dx5_lock_info,0,sizeof(DDSURFACEDESC));
69  cur_dx5_lock_info.dwSize = sizeof(DDSURFACEDESC);
70
71  IDirectDrawSurface3 *surf=type==I4_FRONT_FRAME_BUFFER ?
72    dx5_common.front_surface : dx5_common.back_surface;
73
74  int flags=access==I4_FRAME_BUFFER_READ ? DDLOCK_READONLY :
75    DDLOCK_WRITEONLY;
76         
77  if (!surf)
78    return 0;
79
80  res = surf->Lock(NULL,&cur_dx5_lock_info, flags | DDLOCK_WAIT,0);
81
82  if (res == DD_OK)
83  {
84#ifdef DEBUG
85    surf->Unlock(NULL);
86#endif
87
88    dx_buf[type].im->data=cur_dx5_lock_info.lpSurface;
89    dx_buf[type].im->bpl=cur_dx5_lock_info.lPitch;
90    dx_buf[type].state=access;
91  }
92
93  return dx_buf[type].im;
94}
95
96
97void i4_dx5_display_class::unlock_frame_buffer(i4_frame_buffer_type type)
98{
99  IDirectDrawSurface3 *surf=type==I4_FRONT_FRAME_BUFFER ?
100    dx5_common.front_surface : dx5_common.back_surface;
101         
102#ifndef DEBUG
103  if (surf)
104    surf->Unlock(NULL);
105#endif
106
107  dx_buf[type].im->data=0;
108  dx_buf[type].state=-1;
109}
110
111
112
113// i4_image_class *i4_dx5_display_class::grab_framebuffer()
114// {
115//   if (!fake_screen) return 0;
116
117//   i4_image_class *im=i4_create_image(width(), height(), fake_screen->get_pal());
118
119//   void *mem=dx5_lock(DX5_LOCK_READ);
120
121
122//   for (int y=0; y<height(); y++)
123//   {
124//     w16 *p=(w16 *)((w8 *)im->data + y*im->bpl);
125
126//     for (int x=0; x<width(); x++)
127//     {     
128//       p[x]=*(((w16 *)mem)+x);
129//     }
130
131//     mem=(w8 *)mem + cur_dx5_lock_info.lPitch;
132//   }
133
134//   dx5_unlock();
135
136//   return im;
137// }
138
139i4_dx5_display_class::i4_dx5_display_class():input(0)
140{
141  mode_list=0;
142  i4_dx5_display=this;
143  mouse=0;
144  fake_screen=0;
145  context=0; 
146
147#ifdef DEBUG
148  use_exclusive_mode = i4_F;
149  use_page_flip      = i4_F;
150#else
151  use_exclusive_mode = i4_T;
152  use_page_flip      = i4_F;
153#endif
154}
155
156
157i4_image_class *i4_dx5_display_class::get_screen()
158{     
159  return fake_screen;
160}
161
162
163
164// this will add all the drivers that directx find into the display list
165void i4_dx5_display_class::init()
166{
167  int id=0;
168  dx5_driver *list=dx5_common.get_driver_list();
169  char *n=name_buffer;
170
171  for (dx5_driver *d=list; d; d=d->next, id++)
172  {   
173    IDirectDraw2 *ddraw=dx5_common.initialize_driver(d);
174    if (ddraw)
175    {
176
177      // no hardware acceleration for this demo
178      if (dx5_common.get_driver_hardware_info(ddraw))
179      {
180        sprintf(n, "%s : 3d Accelerated", d->DriverName);
181        i4_display_list_struct *s=new i4_display_list_struct;
182        s->add_to_list(n, id | 0x8000, this, i4_display_list);
183        n+=strlen(n)+1;
184      }
185   
186      //only want software rendering stuffs for the primary display driver to be listed
187      if (!stricmp(d->DriverName,"display"))
188      {
189        sprintf(n, "%s : Software Rendered", d->DriverName);
190        i4_display_list_struct *s=new i4_display_list_struct;
191        s->add_to_list(n, id, this, i4_display_list);
192        n+=strlen(n)+1;
193      }
194
195      ddraw->Release();
196    }
197  }
198
199  dx5_common.free_driver_list(list);
200}
201
202// find the driver, then get it's modes and return the first one
203i4_display_class::mode *i4_dx5_display_class::get_first_mode(int driver_id)
204{
205  int find_id = driver_id & (~0x8000);    // top bit indicates hardware accelerated
206
207  if (mode_list)
208  {
209    dx5_common.free_mode_list(mode_list);
210    mode_list=0;
211  }
212
213  dx5_driver *driver_list=dx5_common.get_driver_list(), *d;
214  for (d=driver_list; find_id && d; d=d->next, find_id--);
215  IDirectDraw2 *ddraw=dx5_common.initialize_driver(d);
216  dx5_common.free_driver_list(driver_list);
217
218  if (!ddraw) return 0;
219
220  mode_list=dx5_common.get_mode_list(ddraw);
221  ddraw->Release();
222 
223  amode.dx5=mode_list;
224  amode.driver_id=driver_id;
225
226
227  return get_next_mode();
228}
229
230
231i4_dx5_display_class::~i4_dx5_display_class()
232{
233  ;
234}
235
236i4_display_class::mode *i4_dx5_display_class::get_next_mode()
237{
238  if (!amode.dx5)
239    return 0;
240
241
242  DDSURFACEDESC *desc=&amode.dx5->desc;
243
244  sprintf(amode.name, "%d X %d 16bit", desc->dwWidth, desc->dwHeight);
245  amode.xres=desc->dwWidth;
246  amode.yres=desc->dwHeight;
247  amode.bits_per_pixel=16;
248  amode.red_mask    = desc->ddpfPixelFormat.dwRBitMask;
249  amode.green_mask  = desc->ddpfPixelFormat.dwGBitMask;
250  amode.blue_mask   = desc->ddpfPixelFormat.dwBBitMask; 
251  amode.flags =0;
252
253
254  last_mode=amode;
255  amode.dx5=amode.dx5->next;
256  return &amode;
257}
258
259
260i4_bool i4_dx5_display_class::initialize_mode()
261{
262  if (!i4_win32_startup_options.fullscreen)
263    use_page_flip = i4_F;
264 
265  if (!input.create_window(0,0,
266                           last_mode.xres,
267                           last_mode.yres, this, i4_win32_startup_options.fullscreen))
268    return i4_F;
269
270 
271  int x,y,w,h;
272
273  if (!i4_win32_startup_options.fullscreen)
274    input.get_window_area(x,y,w,h);
275  else
276  {
277    w=last_mode.xres;
278    h=last_mode.yres;
279  }
280
281  last_mode.xres=w;
282  last_mode.yres=h;
283
284  // find the driver and initialize it
285  int find_id = last_mode.driver_id & (~0x8000);
286
287  dx5_driver *driver_list=dx5_common.get_driver_list(), *d;
288  for (d=driver_list; find_id && d; d=d->next, find_id--);
289  dx5_common.ddraw=dx5_common.initialize_driver(d);
290  dx5_common.free_driver_list(driver_list);
291   
292  if (!dx5_common.ddraw)
293    return i4_F;
294
295
296  if (i4_win32_startup_options.fullscreen && use_exclusive_mode)
297  {
298    // change the error handling function so that the screen is restored before
299    // a dialog box is displayed, or they won't be able to read the message!
300    if (i4_dx5_check(dx5_common.ddraw->SetCooperativeLevel(input.get_window_handle(),
301                                                           DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN)))
302    {
303      error_handler.old_error_handler=i4_get_error_function();
304      error_handler.need_restore_old=i4_T;
305      i4_set_error_function(dx5_error_function);
306    }
307    else return i4_F;
308  }
309  else if (!i4_dx5_check(dx5_common.ddraw->SetCooperativeLevel(input.get_window_handle(),
310                                                               DDSCL_NORMAL)))
311    return i4_F;
312
313  //win95 function to hide the mouse cursor. our display uses our own cursor
314
315  if (i4_win32_startup_options.fullscreen &&
316      !i4_dx5_check(dx5_common.ddraw->SetDisplayMode(last_mode.xres, last_mode.yres,16,0,0)))
317      return i4_F;
318
319
320  if (use_page_flip)
321  {
322    if (!dx5_common.create_surface(DX5_PAGE_FLIPPED_PRIMARY_SURFACE,
323                                   last_mode.xres, last_mode.yres))
324      return i4_F;
325  }
326  else if (!dx5_common.create_surface(DX5_BACKBUFFERED_PRIMARY_SURFACE,
327                                      last_mode.xres, last_mode.yres))
328    return i4_F;
329 
330
331  // find the size of the primary surface
332  DDSURFACEDESC ddsd;
333  dx5_common.get_surface_description(dx5_common.primary_surface, ddsd);
334  fake_screen=new i4_dx5_image_class(last_mode.xres, last_mode.yres);
335  fake_screen->surface->PageLock(0);
336   
337 
338
339
340  i4_pixel_format fmt;
341  fmt.pixel_depth = I4_16BIT; 
342  fmt.red_mask    = ddsd.ddpfPixelFormat.dwRBitMask;
343  fmt.green_mask  = ddsd.ddpfPixelFormat.dwGBitMask;
344  fmt.blue_mask   = ddsd.ddpfPixelFormat.dwBBitMask;
345  fmt.alpha_mask  = 0;
346  fmt.calc_shift();
347
348  pal = i4_pal_man.register_pal(&fmt);
349
350  dx_buf[0].im=i4_create_image(last_mode.xres, last_mode.yres, pal, 0, 0);
351  dx_buf[0].state=-1;
352
353  dx_buf[1].im=i4_create_image(last_mode.xres, last_mode.yres, pal, 0, 0);
354  dx_buf[1].state=-1;
355
356
357  context             = new i4_draw_context_class(0,0, last_mode.xres-1, last_mode.yres-1);
358  context->both_dirty = new i4_rect_list_class;
359
360  memcpy(&cur_mode, &last_mode, sizeof(last_mode));
361
362  if (1) //!i4_win32_startup_options.fullscreen)
363    mouse = new dx5_mouse_class(use_page_flip);
364  else
365  {
366    thread_mouse = new ddraw_thread_cursor_class(pal,input.get_window_handle(),
367                                                 0,0,last_mode.xres,last_mode.yres);
368
369    input.set_async_mouse(thread_mouse);
370  }
371
372  return i4_T;
373}
374
375
376
377i4_bool i4_dx5_display_class::close()
378{
379  if (mouse)
380  {
381    delete mouse;
382    mouse = 0;
383  }
384
385  input.set_async_mouse(0);
386
387  if (thread_mouse)
388  {
389    delete thread_mouse;
390    thread_mouse = 0;
391  }
392
393  if (error_handler.need_restore_old)
394  {
395    i4_set_error_function(error_handler.old_error_handler);
396    error_handler.need_restore_old=i4_F;
397  }
398
399  input.destroy_window();
400
401  for (int i=0; i<2; i++)
402  {
403    if (dx_buf[i].im)
404    {
405      delete dx_buf[i].im;
406      dx_buf[i].im=0;
407    }
408  }
409
410  if (fake_screen)
411  {
412    delete fake_screen;
413    fake_screen=0;
414  }
415
416  if (context)
417  {
418    delete context;
419    context=0;
420  }
421
422  if (mode_list)
423  {
424    dx5_common.free_mode_list(mode_list);
425    mode_list=0;
426  }
427
428  next_frame_copy.delete_list();
429
430  dx5_common.cleanup();
431
432  return i4_T;
433}
434
435
436i4_bool i4_dx5_display_class::set_mouse_shape(i4_cursor_class *cursor)
437{
438  if (mouse)
439  {
440    mouse->set_cursor(cursor);   
441    return i4_T;
442  }
443  else
444  if (thread_mouse)
445  {
446    thread_mouse->set_cursor(cursor);
447    return i4_T;
448  }
449
450  return i4_F;
451}
452
453void i4_dx5_display_class::flush()
454{   
455  RECT src;
456
457  if (!input.get_active())
458    {
459      context->both_dirty->delete_list();
460      context->both_dirty->add_area(0,0,width()-1, height()-1);
461      i4_thread_yield();
462      return ;
463    }
464
465  //start of copy stuff
466  pf_dx5_copy.start();
467  context->both_dirty->intersect_area(0,0,width()-1,height()-1);
468
469  // Step 1 : copy middle buffer information to the back-buffer
470
471  i4_rect_list_class::area_iter a,b;
472  i4_rect_list_class *use_list;
473
474  // if page flipped we need to make add the current dirty to the stuff left over from last frame
475  if (use_page_flip)
476  {
477    a=context->both_dirty->list.begin();
478    for (;a!=context->both_dirty->list.end();++a)
479      next_frame_copy.add_area(a->x1, a->y1, a->x2, a->y2);
480    use_list=&next_frame_copy;
481  }
482  else
483    use_list=context->both_dirty;
484
485
486  int wx,wy,ww,wh;
487  input.get_window_area(wx,wy,ww,wh);
488
489  for (a=use_list->list.begin(); a!=use_list->list.end(); ++a)
490  {       
491    src.left   = a->x1;
492    src.top    = a->y1;
493    src.right  = a->x2+1;
494    src.bottom = a->y2+1;
495
496    if (!i4_dx5_check(dx5_common.back_surface->BltFast(a->x1, a->y1, fake_screen->surface,
497                                                       &src,DDBLTFAST_NOCOLORKEY |
498                                                       DDBLTFAST_WAIT)))
499      i4_error("dx5 blt failed on area %d %d %d %d ", a->x1, a->y1,a->x2, a->y2);
500
501  }   
502  pf_dx5_copy.stop();
503  //end of copy stuff
504
505  //start of mouse stuff
506  pf_dx5_mouse.start();
507
508  mouse_x = input.mouse_x;
509  mouse_y = input.mouse_y;
510
511  if (mouse)
512    mouse->save_and_draw(mouse_x, mouse_y);
513
514  pf_dx5_mouse.stop(); 
515
516
517  //start of flip stuff
518  pf_dx5_flip.start(); 
519 
520  // now flip or copy the backbuffer to video memory
521  if (use_page_flip)
522  {
523//     if (thread_mouse)
524//     {
525//       thread_mouse->draw_lock.lock();
526//       thread_mouse->use_backbuffer(i4_F);
527//       thread_mouse->remove(); //remove from front buffer
528//       thread_mouse->use_backbuffer(i4_T);     
529//       thread_mouse->display();//display on back buffer
530//     }
531
532    dx5_common.primary_surface->Flip(NULL,DDFLIP_WAIT);
533
534//     if (thread_mouse)
535//     {     
536//       thread_mouse->use_backbuffer(i4_F);
537//       thread_mouse->draw_lock.unlock();
538//     }
539  }
540  else
541  {
542//     if (thread_mouse)
543//     {
544//       thread_mouse->draw_lock.lock();     
545//       thread_mouse->use_backbuffer(i4_T);
546//       thread_mouse->display();     
547//     }
548
549    if (!i4_dx5_check(dx5_common.primary_surface->BltFast(0,0,dx5_common.back_surface, NULL,
550                                                          DDBLTFAST_NOCOLORKEY |
551                                                          DDBLTFAST_WAIT)))
552      i4_error("dx5 blt failed");
553   
554//     if (thread_mouse)
555//     {     
556//       thread_mouse->remove();
557//       thread_mouse->set_visible(i4_T);       
558//       thread_mouse->use_backbuffer(i4_F);
559//       thread_mouse->draw_lock.unlock();
560//     }
561  }
562 
563  pf_dx5_flip.stop();
564  //end of flip stuff
565
566
567  pf_dx5_mouse.start();
568  if (mouse)
569    mouse->restore();
570  pf_dx5_mouse.stop(); 
571
572
573  if (use_page_flip)
574    next_frame_copy.swap(context->both_dirty);
575
576  context->both_dirty->delete_list();
577}
578
579
Note: See TracBrowser for help on using the repository browser.