00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "Core/precomp.h"
00016 #include "displaycard_directdraw.h"
00017 #include "API/Display/Display/mousecursor.h"
00018 #include "API/Display/Display/vidmode.h"
00019 #include "blit_dx.h"
00020 #include "API/Core/System/error.h"
00021 #include "../Generic/colormap.h"
00022 #include "../Generic/blitters.h"
00023 #include "API/Core/Math/rect.h"
00024
00025 CL_DisplayCard_DirectDraw::CL_DisplayCard_DirectDraw(
00026 int card_no,
00027 LPGUID card_guid,
00028 std::string card_name)
00029 : CL_DisplayCard_Win32Compatible(card_no)
00030 {
00031 this->card_no = card_no;
00032 this->card_guid = card_guid;
00033 this->card_name = card_name;
00034
00035 init_palette();
00036
00037 back_buffer = NULL;
00038 front_buffer = NULL;
00039 directdraw = NULL;
00040 use_software_surfaces = false;
00041
00042 enumerate_displaymodes();
00043
00044 slot_resize = get_sig_resize().connect(CL_CreateSlot(this, &CL_DisplayCard_DirectDraw::on_resize));
00045 }
00046
00047 CL_DisplayCard_DirectDraw::~CL_DisplayCard_DirectDraw()
00048 {
00049 deinit();
00050 destroy_displaymodes();
00051 }
00052
00053 void CL_DisplayCard_DirectDraw::deinit()
00054 {
00055 if (directdraw == NULL) return;
00056 cl_assert(get_hwnd() != NULL);
00057
00058 CL_MouseCursor::hide();
00059
00060 directdraw->FlipToGDISurface();
00061
00062
00063 if (is_fullscreen())
00064 {
00065 HRESULT err = directdraw->RestoreDisplayMode();
00066 cl_assert(err == DD_OK);
00067 }
00068
00069
00070
00071
00072
00073 CL_Blit_DX::release_all_surfaces();
00074 delete back_buffer;
00075 delete front_buffer;
00076 back_buffer = NULL;
00077 front_buffer = NULL;
00078
00079 cl_assert(directdraw->Release()==0);
00080 directdraw = NULL;
00081
00082 destroy_window();
00083 }
00084
00085
00086
00087
00088 void CL_DisplayCard_DirectDraw::set_palette(CL_Palette *palette)
00089 {
00090
00091
00092 delete[] pal.palette;
00093
00094 pal.num_colors = palette->num_colors;
00095 pal.palette = new unsigned char[pal.num_colors*3];
00096
00097 memcpy(
00098 pal.palette,
00099 palette->palette,
00100 pal.num_colors*3);
00101 }
00102
00103 CL_Palette *CL_DisplayCard_DirectDraw::get_palette()
00104 {
00105 return &pal;
00106 }
00107
00108 void CL_DisplayCard_DirectDraw::flip_display(bool sync)
00109 {
00110
00111
00112 if (front_buffer->get_surface()->IsLost())
00113 {
00114 if (front_buffer->get_surface()->Restore() == DD_OK)
00115 {
00116 CL_Blit_DX::reload_all_surfaces();
00117 }
00118 }
00119 signal_preflip();
00120
00121 if (can_flip)
00122 {
00123 front_buffer->get_surface()->Flip(
00124 NULL,
00125 DDFLIP_WAIT);
00126 }
00127 else
00128 {
00129
00130
00131
00132
00133 DDBLTFX ddbltfx;
00134 ddbltfx.dwSize = sizeof(ddbltfx);
00135
00136 DWORD flags = DDBLT_WAIT;
00137
00138
00139
00140 RECT client_rect;
00141 GetClientRect(get_hwnd(), &client_rect);
00142
00143 RECT dest_rect;
00144 GetWindowRect(get_hwnd(), &dest_rect);
00145
00146 POINT Pt;
00147 Pt.x=0;
00148 Pt.y=0;
00149 ClientToScreen(get_hwnd(),&Pt);
00150
00151 dest_rect.top += Pt.y-dest_rect.top;
00152 dest_rect.right = dest_rect.left + back_buffer->get_width()+(Pt.x-dest_rect.left);
00153 dest_rect.left += (Pt.x-dest_rect.left);
00154 dest_rect.bottom = dest_rect.top + back_buffer->get_height();
00155
00156 front_buffer->get_surface()->Blt(
00157 &dest_rect,
00158 back_buffer->get_surface(),
00159 NULL,
00160 flags,
00161 &ddbltfx);
00162 }
00163 signal_postflip();
00164 }
00165
00166 void CL_DisplayCard_DirectDraw::put_display(const CL_Rect &rect)
00167 {
00168
00169
00170
00171
00172 DDBLTFX ddbltfx;
00173 ddbltfx.dwSize = sizeof(ddbltfx);
00174
00175 DWORD flags = DDBLT_WAIT;
00176
00177
00178
00179 RECT src_rect;
00180 if (can_flip)
00181 {
00182 src_rect.left = rect.x1;
00183 src_rect.top = rect.y1;
00184 src_rect.right = rect.x2;
00185 src_rect.bottom = rect.y2;
00186 }
00187 else
00188 {
00189 GetWindowRect(get_hwnd(), &src_rect);
00190
00191 RECT client_rect;
00192 GetClientRect(get_hwnd(), &client_rect);
00193
00194 POINT Pt;
00195 Pt.x=0;
00196 Pt.y=0;
00197 ClientToScreen(get_hwnd(),&Pt);
00198
00199 src_rect.top += (Pt.y-src_rect.top);
00200 src_rect.left += (Pt.x-src_rect.left);
00201
00202 src_rect.right = src_rect.left + rect.x2;
00203 src_rect.bottom = src_rect.top + rect.y2;
00204 src_rect.left += rect.x1;
00205 src_rect.top += rect.y1;
00206 }
00207
00208 front_buffer->get_surface()->Blt(
00209 NULL,
00210 back_buffer->get_surface(),
00211 &src_rect,
00212 flags,
00213 &ddbltfx);
00214 }
00215
00216 void CL_DisplayCard_DirectDraw::sync_buffers()
00217 {
00218
00219
00220
00221
00222 DDBLTFX ddbltfx;
00223 ddbltfx.dwSize = sizeof(ddbltfx);
00224
00225 DWORD flags = DDBLT_WAIT;
00226
00227
00228
00229 RECT src_rect;
00230 if (can_flip)
00231 {
00232 src_rect.left = 0;
00233 src_rect.top = 0;
00234 src_rect.right = front_buffer->get_width();
00235 src_rect.bottom = front_buffer->get_height();
00236 }
00237 else
00238 {
00239 GetWindowRect(get_hwnd(), &src_rect);
00240
00241 RECT client_rect;
00242 GetClientRect(get_hwnd(), &client_rect);
00243
00244 POINT Pt;
00245 Pt.x=0;
00246 Pt.y=0;
00247 ClientToScreen(get_hwnd(),&Pt);
00248
00249 src_rect.top += (Pt.y-src_rect.top);
00250 src_rect.right = src_rect.left + back_buffer->get_width()+(Pt.x-src_rect.left);
00251 src_rect.left += (Pt.x-src_rect.left);
00252 src_rect.bottom = src_rect.top + back_buffer->get_height();
00253 }
00254
00255 back_buffer->get_surface()->Blt(
00256 NULL,
00257 front_buffer->get_surface(),
00258 &src_rect,
00259 flags,
00260 &ddbltfx);
00261 }
00262
00263 void CL_DisplayCard_DirectDraw::set_videomode(
00264 int width,
00265 int height,
00266 int bpp,
00267 bool fullscreen,
00268 bool allow_resize,
00269 bool video_memory)
00270 {
00271 HRESULT err;
00272
00273 deinit();
00274
00275 err = DirectDrawCreate(card_guid, &directdraw, NULL);
00276 cl_assert(err == DD_OK);
00277
00278 if (video_memory == false)
00279 {
00280 use_software_surfaces = true;
00281 }
00282 create_window(width, height, bpp, fullscreen, allow_resize);
00283
00284
00285
00286 int flags = DDSCL_NORMAL;
00287
00288 if (fullscreen)
00289 {
00290 flags =
00291 DDSCL_EXCLUSIVE |
00292 DDSCL_FULLSCREEN |
00293 DDSCL_ALLOWREBOOT|
00294 DDSCL_ALLOWMODEX;
00295 }
00296
00297 err = directdraw->SetCooperativeLevel(
00298 get_hwnd(),
00299 flags);
00300
00301 cl_assert(err == DD_OK);
00302
00303
00304 if (fullscreen)
00305 {
00306 err = directdraw->SetDisplayMode(width, height, bpp);
00307 cl_assert(err == DD_OK);
00308
00309 create_fullscreen_targets(video_memory);
00310 }
00311 else
00312 {
00313 create_windowed_targets(video_memory);
00314 }
00315
00316
00317
00318 CL_Blit_DX::create_all_surfaces();
00319
00320
00321 CL_DisplayCard_Generic::set_gfxmode(
00322 width,
00323 height,
00324 bpp,
00325 fullscreen,
00326 allow_resize);
00327 }
00328
00329 void CL_DisplayCard_DirectDraw::clear_display(
00330 float red,
00331 float green,
00332 float blue,
00333 float alpha)
00334 {
00335 fill_rect(
00336 0,
00337 0,
00338 get_width(),
00339 get_height(),
00340 red,
00341 green,
00342 blue,
00343 alpha);
00344 }
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 void CL_DisplayCard_DirectDraw::fill_rect(
00362 int x1,
00363 int y1,
00364 int x2,
00365 int y2,
00366 float r,
00367 float g,
00368 float b,
00369 float a)
00370 {
00371
00372
00373
00374 if (a <= 0.01) return;
00375 if (a <= 0.99)
00376 {
00377 CL_DisplayCard_Generic::fill_rect(x1, y1, x2, y2, r, g, b, a);
00378 return;
00379 }
00380
00381
00382 int trans_x = get_translate_offset_x();
00383 int trans_y = get_translate_offset_y();
00384 x1 += trans_x;
00385 x2 += trans_x;
00386 y1 += trans_y;
00387 y2 += trans_y;
00388
00389 CL_ClipRect rect(x1, y1, x2, y2);
00390
00391 CL_ClipRect cur_clip = get_clip_rect();
00392 if (cur_clip.test_all_clipped(rect))
00393 {
00394 return;
00395 }
00396
00397 CL_ClipRect crect = cur_clip.clip(rect);
00398 CL_ColorMap cmap(get_back_buffer());
00399 unsigned int fill_color = cmap.calc_color(r, g, b, a);
00400
00401 DDBLTFX ddbltfx;
00402 ddbltfx.dwSize=sizeof(ddbltfx);
00403 ddbltfx.dwFillColor = fill_color;
00404
00405 RECT dest;
00406 dest.left = crect.m_x1;
00407 dest.top = crect.m_y1;
00408 dest.right = crect.m_x2;
00409 dest.bottom = crect.m_y2;
00410
00411 back_buffer->get_surface()->Blt(
00412 &dest,
00413 NULL,
00414 NULL,
00415 DDBLT_COLORFILL|DDBLT_WAIT,
00416 &ddbltfx);
00417 }
00418
00419 std::string CL_DisplayCard_DirectDraw::get_name()
00420 {
00421 return card_name;
00422 }
00423
00424 const std::list<CL_VidMode*> &CL_DisplayCard_DirectDraw::get_videomodes()
00425 {
00426 return videomodes;
00427 }
00428
00429
00430
00431
00432 CL_Blitters CL_DisplayCard_DirectDraw::create_hw_blitters(
00433 CL_SurfaceProvider *provider)
00434 {
00435
00436
00437 CL_Blitters ret;
00438
00439
00440 if (use_software_surfaces)
00441 {
00442 return ret;
00443 }
00444
00445 CL_Blit_DX *blitter = new CL_Blit_DX(this, provider);
00446 bool res = blitter->init_surface(&ret);
00447 if (!res)
00448 {
00449 delete blitter;
00450 }
00451
00452 return ret;
00453 }
00454
00455
00456
00457
00458 void CL_DisplayCard_DirectDraw::init_palette()
00459 {
00460
00461
00462 delete[] pal.palette;
00463
00464 pal.num_colors = 256;
00465 pal.palette = new unsigned char[pal.num_colors*3];
00466
00467 for (int i=0; i<pal.num_colors; i++)
00468 {
00469 pal.palette[i*3 + 0] = i;
00470 pal.palette[i*3 + 1] = i;
00471 pal.palette[i*3 + 2] = i;
00472 }
00473 }
00474
00475 void CL_DisplayCard_DirectDraw::enumerate_displaymodes()
00476 {
00477 HRESULT err;
00478 LPDIRECTDRAW directdraw;
00479
00480 err = DirectDrawCreate(card_guid, &directdraw, NULL);
00481 cl_assert(err == DD_OK);
00482
00483 err = directdraw->EnumDisplayModes(
00484 DDEDM_STANDARDVGAMODES,
00485 NULL,
00486 (void *) &videomodes,
00487 enumerate_callback);
00488
00489
00490
00491
00492
00493 directdraw->Release();
00494 }
00495
00496 HRESULT CALLBACK CL_DisplayCard_DirectDraw::enumerate_callback(
00497 LPDDSURFACEDESC lpDDSurfaceDesc,
00498 LPVOID lpContext)
00499 {
00500 std::list<CL_VidMode*> *v_list=(std::list<CL_VidMode*> *) lpContext;
00501
00502 DDSURFACEDESC surf_desc = *lpDDSurfaceDesc;
00503
00504 bool modex = false;
00505 if ((surf_desc.ddsCaps.dwCaps & DDSCAPS_MODEX) == DDSCAPS_MODEX) modex = true;
00506
00507 v_list->push_back(
00508 new CL_VidMode(
00509 surf_desc.dwWidth,
00510 surf_desc.dwHeight,
00511 surf_desc.ddpfPixelFormat.dwRGBBitCount,
00512 modex));
00513
00514 return DDENUMRET_OK;
00515 }
00516
00517 void CL_DisplayCard_DirectDraw::destroy_displaymodes()
00518 {
00519 while (videomodes.empty() == false)
00520 {
00521 delete *videomodes.begin();
00522 videomodes.erase(videomodes.begin());
00523 }
00524 }
00525
00526 void CL_DisplayCard_DirectDraw::create_fullscreen_targets(bool video_memory)
00527 {
00528 try
00529 {
00530
00531 HRESULT err;
00532
00533 DDSURFACEDESC surf_desc;
00534 memset(&surf_desc, 0, sizeof(surf_desc));
00535 surf_desc.dwSize = sizeof(DDSURFACEDESC);
00536
00537 surf_desc.dwFlags =
00538 DDSD_CAPS |
00539 DDSD_BACKBUFFERCOUNT;
00540
00541 surf_desc.ddsCaps.dwCaps =
00542 DDSCAPS_PRIMARYSURFACE |
00543 DDSCAPS_FLIP |
00544 DDSCAPS_COMPLEX;
00545
00546 if (video_memory) surf_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
00547 else surf_desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
00548
00549
00550
00551
00552 surf_desc.dwBackBufferCount = 2;
00553
00554 LPDIRECTDRAWSURFACE primary_surface;
00555 directdraw->SetCooperativeLevel(hwnd,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN|DDSCL_ALLOWREBOOT|DDSCL_ALLOWMODEX);
00556 err = directdraw->CreateSurface(&surf_desc, &primary_surface, NULL);
00557 if (err != DD_OK) throw CL_Error("Couldn't create flipping system.");
00558
00559
00560 DDSCAPS backbuffer_desc;
00561 backbuffer_desc.dwCaps = DDSCAPS_BACKBUFFER;
00562
00563 LPDIRECTDRAWSURFACE backbuffer_surface;
00564 err = primary_surface->GetAttachedSurface(
00565 &backbuffer_desc,
00566 &backbuffer_surface);
00567
00568 if (err != DD_OK)
00569 {
00570 primary_surface->Release();
00571 throw CL_Error("Couldn't create flipping system.");
00572 }
00573
00574
00575 front_buffer = new CL_Target_DX(primary_surface);
00576 back_buffer = new CL_Target_DX(backbuffer_surface);
00577
00578 can_flip = true;
00579 }
00580 catch (CL_Error err)
00581 {
00582 create_windowed_targets(video_memory);
00583 }
00584 }
00585
00586 void CL_DisplayCard_DirectDraw::create_windowed_targets(bool video_memory)
00587 {
00588
00589 HRESULT err;
00590
00591 DDSURFACEDESC surf_desc;
00592 memset(&surf_desc, 0, sizeof(surf_desc));
00593 surf_desc.dwSize = sizeof(DDSURFACEDESC);
00594 surf_desc.dwFlags = DDSD_CAPS;
00595 surf_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
00596
00597 LPDIRECTDRAWSURFACE primary_surface;
00598 err = directdraw->CreateSurface(&surf_desc, &primary_surface, NULL);
00599 if (err != DD_OK) throw CL_Error("Couldn't create front buffer.");
00600
00601
00602 RECT client_rect;
00603 GetClientRect(get_hwnd(), &client_rect);
00604
00605 RECT dest_rect;
00606 GetWindowRect(get_hwnd(), &dest_rect);
00607
00608 POINT Pt;
00609 Pt.x=0;
00610 Pt.y=0;
00611 ClientToScreen(get_hwnd(),&Pt);
00612
00613 dest_rect.top += (Pt.y-dest_rect.top);
00614 dest_rect.left += (Pt.x-dest_rect.left);
00615 front_buffer = new CL_FrontbufferTarget_DX(
00616 primary_surface,
00617 this
00618
00619 );
00620
00621 backbuffer_in_video_memory = video_memory;
00622 create_windowed_backbuffer(
00623 dest_rect.right-dest_rect.left,
00624 dest_rect.bottom-dest_rect.top);
00625
00626
00627 LPDIRECTDRAWCLIPPER clipper;
00628 err = directdraw->CreateClipper(0, &clipper, NULL);
00629 cl_assert(err == DD_OK);
00630 clipper->SetHWnd(0, get_hwnd());
00631
00632
00633 front_buffer->get_surface()->SetClipper(clipper);
00634 clipper->Release();
00635
00636 can_flip = false;
00637 }
00638
00639 void CL_DisplayCard_DirectDraw::create_windowed_backbuffer(int width, int height)
00640 {
00641 if (width == 0 || height == 0) return;
00642
00643 HRESULT err = 0;
00644
00645
00646 delete back_buffer;
00647 back_buffer = NULL;
00648
00649
00650
00651 DDSURFACEDESC surf_desc;
00652 memset(&surf_desc, 0, sizeof(surf_desc));
00653 surf_desc.dwSize = sizeof(DDSURFACEDESC);
00654 surf_desc.dwFlags=DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH;
00655 surf_desc.dwWidth = width;
00656 surf_desc.dwHeight = height;
00657 surf_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
00658 if (backbuffer_in_video_memory) surf_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
00659 else surf_desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
00660
00661 LPDIRECTDRAWSURFACE backbuffer_surface;
00662
00663
00664 directdraw->SetCooperativeLevel(hwnd,DDSCL_NORMAL);
00665 err = directdraw->CreateSurface(&surf_desc, &backbuffer_surface, NULL);
00666
00667 if (err != DD_OK)
00668 {
00669 surf_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY;
00670
00671 err = directdraw->CreateSurface(&surf_desc, &backbuffer_surface, NULL);
00672 cl_assert(err == DD_OK);
00673 }
00674
00675
00676 back_buffer = new CL_Target_DX(backbuffer_surface);
00677 }
00678
00679
00680
00681
00682 DDCAPS CL_DisplayCard_DirectDraw::get_hel_caps()
00683 {
00684 HRESULT err;
00685 DDCAPS hel_caps;
00686 hel_caps.dwSize = sizeof(DDCAPS);
00687
00688 err = directdraw->GetCaps(NULL, &hel_caps);
00689 cl_assert(err == DD_OK);
00690
00691 return hel_caps;
00692 }
00693
00694 DDCAPS CL_DisplayCard_DirectDraw::get_hal_caps()
00695 {
00696 HRESULT err;
00697 DDCAPS hal_caps;
00698 hal_caps.dwSize = sizeof(DDCAPS);
00699
00700 err = directdraw->GetCaps(&hal_caps, NULL);
00701 cl_assert(err == DD_OK);
00702
00703 return hal_caps;
00704 }
00705
00706 CL_DisplayCard_DirectDraw::CL_FrontbufferTarget_DX::CL_FrontbufferTarget_DX(
00707 LPDIRECTDRAWSURFACE surf,
00708 CL_DisplayCard_DirectDraw *parent)
00709 : CL_Target_DX(surf), m_parent(parent)
00710 {
00711 }
00712
00713 void *CL_DisplayCard_DirectDraw::CL_FrontbufferTarget_DX::get_data() const
00714 {
00715 RECT client_rect;
00716 GetClientRect(m_parent->get_hwnd(), &client_rect);
00717
00718 RECT dest_rect;
00719 GetWindowRect(m_parent->get_hwnd(), &dest_rect);
00720
00721 POINT Pt;
00722 Pt.x=0;
00723 Pt.y=0;
00724 ClientToScreen(m_parent->get_hwnd(),&Pt);
00725
00726 dest_rect.top += (Pt.y-dest_rect.top);
00727 dest_rect.left += (Pt.x-dest_rect.left);
00728 return (void *) &((unsigned char *) m_data)[dest_rect.left*(m_depth/8)+dest_rect.top*m_pitch];
00729 }
00730
00731 void CL_DisplayCard_DirectDraw::on_resize(int x, int y)
00732 {
00733 if (is_fullscreen() == false)
00734 {
00735 create_windowed_backbuffer(x, y);
00736 }
00737 }