📄 dx_viewport.cpp
字号:
// This file is part of Ambulant Player, www.ambulantplayer.org.//// Copyright (C) 2003-2007 Stichting CWI, // Kruislaan 413, 1098 SJ Amsterdam, The Netherlands.//// Ambulant Player is free software; you can redistribute it and/or modify// it under the terms of the GNU Lesser General Public License as published by// the Free Software Foundation; either version 2.1 of the License, or// (at your option) any later version.//// Ambulant Player is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU Lesser General Public License for more details.//// You should have received a copy of the GNU Lesser General Public License// along with Ambulant Player; if not, write to the Free Software// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA/* * @$Id: dx_viewport.cpp,v 1.44 2007/02/15 12:25:22 jackjansen Exp $ */#define INITGUID#include <objbase.h>#include <ddrawex.h>#include <uuids.h>#include <windows.h>#include <mmsystem.h>#include "ambulant/gui/dx/dx_viewport.h"#pragma comment (lib,"winmm.lib")#pragma comment (lib,"ddraw.lib")#pragma comment (lib,"dxguid.lib")#include "ambulant/lib/logger.h"#include "ambulant/lib/colors.h"#include "ambulant/lib/gtypes.h"#include "ambulant/lib/win32/win32_error.h"#include "ambulant/gui/dx/dx_transition.h"#include <algorithm>#include <cassert>using namespace ambulant;#ifndef AM_DBG#define AM_DBG if(0)#endifusing lib::uint16;using lib::uint32;using lib::uchar;using ambulant::lib::win32::win_report_error;using ambulant::lib::win32::win_report_last_error;static struct error { HRESULT hr; char *name;} errorlist [] = { {DDERR_ALREADYINITIALIZED, "DDERR_ALREADYINITIALIZED"}, {DDERR_CANNOTATTACHSURFACE,"DDERR_CANNOTATTACHSURFACE"}, {DDERR_CANNOTDETACHSURFACE,"DDERR_CANNOTDETACHSURFACE"}, {DDERR_CURRENTLYNOTAVAIL,"DDERR_CURRENTLYNOTAVAIL"}, {DDERR_EXCEPTION,"DDERR_EXCEPTION"}, {DDERR_GENERIC,"DDERR_GENERIC"}, {DDERR_HEIGHTALIGN,"DDERR_HEIGHTALIGN"}, {DDERR_INCOMPATIBLEPRIMARY, "DDERR_INCOMPATIBLEPRIMARY"}, {DDERR_INVALIDCAPS, "DDERR_INVALIDCAPS"}, {DDERR_INVALIDCLIPLIST, "DDERR_INVALIDCLIPLIST"}, {DDERR_INVALIDMODE, "DDERR_INVALIDMODE"}, {DDERR_INVALIDOBJECT, "DDERR_INVALIDOBJECT"}, {DDERR_INVALIDPARAMS, "DDERR_INVALIDPARAMS"}, {DDERR_INVALIDPIXELFORMAT, "DDERR_INVALIDPIXELFORMAT"}, {DDERR_INVALIDRECT, "DDERR_INVALIDRECT"}, {DDERR_LOCKEDSURFACES, "DDERR_LOCKEDSURFACES"}, {DDERR_NO3D, "DDERR_NO3D"}, {DDERR_NOALPHAHW, "DDERR_NOALPHAHW"},#ifdef DDERR_NOSTEREOHARDWARE {DDERR_NOSTEREOHARDWARE, "DDERR_NOSTEREOHARDWARE"},#endif#ifdef DDERR_NOSURFACELEFT {DDERR_NOSURFACELEFT, "DDERR_NOSURFACELEFT"},#endif {DDERR_NOCLIPLIST, "DDERR_NOCLIPLIST"}, {DDERR_NOCOLORCONVHW, "DDERR_NOCOLORCONVHW"}, {DDERR_NOCOOPERATIVELEVELSET, "DDERR_NOCOOPERATIVELEVELSET"}, {DDERR_NOCOLORKEY, "DDERR_NOCOLORKEY"}, {DDERR_NOCOLORKEYHW, "DDERR_NOCOLORKEYHW"}, {DDERR_NODIRECTDRAWSUPPORT, "DDERR_NODIRECTDRAWSUPPORT"}, {DDERR_NOEXCLUSIVEMODE, "DDERR_NOEXCLUSIVEMODE"}, {DDERR_NOFLIPHW, "DDERR_NOFLIPHW"}, {DDERR_NOGDI, "DDERR_NOGDI"}, {DDERR_NOMIRRORHW, "DDERR_NOMIRRORHW"}, {DDERR_NOTFOUND, "DDERR_NOTFOUND"}, {DDERR_NOOVERLAYHW, "DDERR_NOOVERLAYHW"},#ifdef DDERR_OVERLAPPINGRECTS {DDERR_OVERLAPPINGRECTS, "DDERR_OVERLAPPINGRECTS"},#endif {DDERR_NORASTEROPHW, "DDERR_NORASTEROPHW"}, {DDERR_NOROTATIONHW, "DDERR_NOROTATIONHW"}, {DDERR_NOSTRETCHHW, "DDERR_NOSTRETCHHW"}, {DDERR_NOT4BITCOLOR, "DDERR_NOT4BITCOLOR"}, {DDERR_NOT4BITCOLORINDEX, "DDERR_NOT4BITCOLORINDEX"}, {DDERR_NOT8BITCOLOR, "DDERR_NOT8BITCOLOR"}, {DDERR_NOTEXTUREHW, "DDERR_NOTEXTUREHW"}, {DDERR_NOVSYNCHW, "DDERR_NOVSYNCHW"}, {DDERR_NOZBUFFERHW, "DDERR_NOZBUFFERHW"}, {DDERR_NOZOVERLAYHW, "DDERR_NOZOVERLAYHW"}, {DDERR_OUTOFCAPS, "DDERR_OUTOFCAPS"}, {DDERR_OUTOFMEMORY, "DDERR_OUTOFMEMORY"}, {DDERR_OUTOFVIDEOMEMORY, "DDERR_OUTOFVIDEOMEMORY"}, {DDERR_OVERLAYCANTCLIP, "DDERR_OVERLAYCANTCLIP"}, {DDERR_OVERLAYCOLORKEYONLYONEACTIVE, "DDERR_OVERLAYCOLORKEYONLYONEACTIVE"}, {DDERR_PALETTEBUSY, "DDERR_PALETTEBUSY"}, {DDERR_COLORKEYNOTSET, "DDERR_COLORKEYNOTSET"}, {DDERR_SURFACEALREADYATTACHED, "DDERR_SURFACEALREADYATTACHED"}, {DDERR_SURFACEALREADYDEPENDENT, "DDERR_SURFACEALREADYDEPENDENT"}, {DDERR_SURFACEBUSY, "DDERR_SURFACEBUSY"}, {DDERR_CANTLOCKSURFACE, "DDERR_CANTLOCKSURFACE"}, {DDERR_SURFACEISOBSCURED, "DDERR_SURFACEISOBSCURED"}, {DDERR_SURFACELOST, "DDERR_SURFACELOST"}, {DDERR_SURFACENOTATTACHED, "DDERR_SURFACENOTATTACHED"}, {DDERR_TOOBIGHEIGHT, "DDERR_TOOBIGHEIGHT"}, {DDERR_TOOBIGSIZE, "DDERR_TOOBIGSIZE"}, {DDERR_TOOBIGWIDTH, "DDERR_TOOBIGWIDTH"}, {DDERR_UNSUPPORTED, "DDERR_UNSUPPORTED"}, {DDERR_UNSUPPORTEDFORMAT, "DDERR_UNSUPPORTEDFORMAT"}, {DDERR_UNSUPPORTEDMASK, "DDERR_UNSUPPORTEDMASK"},#ifdef DDERR_INVALIDSTREAM {DDERR_INVALIDSTREAM, "DDERR_INVALIDSTREAM"},#endif {DDERR_VERTICALBLANKINPROGRESS, "DDERR_VERTICALBLANKINPROGRESS"}, {DDERR_WASSTILLDRAWING, "DDERR_WASSTILLDRAWING"},#ifdef DDERR_DDSCAPSCOMPLEXREQUIRED {DDERR_DDSCAPSCOMPLEXREQUIRED, "DDERR_DDSCAPSCOMPLEXREQUIRED"},#endif {DDERR_XALIGN, "DDERR_XALIGN"}, {DDERR_INVALIDDIRECTDRAWGUID, "DDERR_INVALIDDIRECTDRAWGUID"}, {DDERR_DIRECTDRAWALREADYCREATED, "DDERR_DIRECTDRAWALREADYCREATED"}, {DDERR_NODIRECTDRAWHW, "DDERR_NODIRECTDRAWHW"}, {DDERR_PRIMARYSURFACEALREADYEXISTS, "DDERR_PRIMARYSURFACEALREADYEXISTS"}, {DDERR_NOEMULATION, "DDERR_NOEMULATION"}, {DDERR_REGIONTOOSMALL, "DDERR_REGIONTOOSMALL"}, {DDERR_CLIPPERISUSINGHWND, "DDERR_CLIPPERISUSINGHWND"}, {DDERR_NOCLIPPERATTACHED, "DDERR_NOCLIPPERATTACHED"}, {DDERR_NOHWND, "DDERR_NOHWND"}, {DDERR_HWNDSUBCLASSED, "DDERR_HWNDSUBCLASSED"}, {DDERR_HWNDALREADYSET, "DDERR_HWNDALREADYSET"}, {DDERR_NOPALETTEATTACHED, "DDERR_NOPALETTEATTACHED"}, {DDERR_NOPALETTEHW, "DDERR_NOPALETTEHW"}, {DDERR_BLTFASTCANTCLIP, "DDERR_BLTFASTCANTCLIP"}, {DDERR_NOBLTHW, "DDERR_NOBLTHW"}, {DDERR_NODDROPSHW, "DDERR_NODDROPSHW"}, {DDERR_OVERLAYNOTVISIBLE, "DDERR_OVERLAYNOTVISIBLE"}, {DDERR_NOOVERLAYDEST, "DDERR_NOOVERLAYDEST"}, {DDERR_INVALIDPOSITION, "DDERR_INVALIDPOSITION"}, {DDERR_NOTAOVERLAYSURFACE, "DDERR_NOTAOVERLAYSURFACE"}, {DDERR_EXCLUSIVEMODEALREADYSET, "DDERR_EXCLUSIVEMODEALREADYSET"}, {DDERR_NOTFLIPPABLE, "DDERR_NOTFLIPPABLE"}, {DDERR_CANTDUPLICATE, "DDERR_CANTDUPLICATE"}, {DDERR_NOTLOCKED, "DDERR_NOTLOCKED"}, {DDERR_CANTCREATEDC, "DDERR_CANTCREATEDC"}, {DDERR_NODC, "DDERR_NODC"}, {DDERR_WRONGMODE, "DDERR_WRONGMODE"}, {DDERR_IMPLICITLYCREATED, "DDERR_IMPLICITLYCREATED"}, {DDERR_NOTPALETTIZED, "DDERR_NOTPALETTIZED"}, {DDERR_UNSUPPORTEDMODE, "DDERR_UNSUPPORTEDMODE"}, {DDERR_NOMIPMAPHW, "DDERR_NOMIPMAPHW"}, {DDERR_INVALIDSURFACETYPE, "DDERR_INVALIDSURFACETYPE"}, {DDERR_NOOPTIMIZEHW, "DDERR_NOOPTIMIZEHW"}, {DDERR_NOTLOADED, "DDERR_NOTLOADED"}, {DDERR_NOFOCUSWINDOW, "DDERR_NOFOCUSWINDOW"},#ifdef DDERR_NOTONMIPMAPSUBLEVEL {DDERR_NOTONMIPMAPSUBLEVEL, "DDERR_NOTONMIPMAPSUBLEVEL"},#endif {DDERR_DCALREADYCREATED, "DDERR_DCALREADYCREATED"}, {DDERR_NONONLOCALVIDMEM, "DDERR_NONONLOCALVIDMEM"}, {DDERR_CANTPAGELOCK, "DDERR_CANTPAGELOCK"}, {DDERR_CANTPAGEUNLOCK, "DDERR_CANTPAGEUNLOCK"}, {DDERR_NOTPAGELOCKED, "DDERR_NOTPAGELOCKED"}, {DDERR_MOREDATA, "DDERR_MOREDATA"},#ifdef DDERR_EXPIRED {DDERR_EXPIRED, "DDERR_EXPIRED"},#endif#ifdef DDERR_TESTFINISHED {DDERR_TESTFINISHED, "DDERR_TESTFINISHED"},#endif#ifdef DDERR_NEWMODE {DDERR_NEWMODE, "DDERR_NEWMODE"},#endif#ifdef DDERR_D3DNOTINITIALIZED {DDERR_D3DNOTINITIALIZED, "DDERR_D3DNOTINITIALIZED"},#endif {DDERR_VIDEONOTACTIVE, "DDERR_VIDEONOTACTIVE"},#ifdef DDERR_NOMONITORINFORMATION {DDERR_NOMONITORINFORMATION, "DDERR_NOMONITORINFORMATION"},#endif#ifdef DDERR_NODRIVERSUPPORT {DDERR_NODRIVERSUPPORT, "DDERR_NODRIVERSUPPORT"},#endif {DDERR_DEVICEDOESNTOWNSURFACE, "DDERR_DEVICEDOESNTOWNSURFACE"}, {DDERR_NOTINITIALIZED, "DDERR_NOTINITIALIZED"},};#define RELEASE(x) if(x) x->Release();x=NULL;static lib::logger* viewport_logger = NULL;static voidseterror(const char *funcname, HRESULT hr){ char* pszmsg; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &pszmsg, 0, NULL ); for(error *p = errorlist; p->name; p++) if (p->hr == hr){ viewport_logger->error("%s failed, error = %s (0x%x), %s", funcname, p->name, hr, pszmsg); LocalFree(pszmsg); return; } viewport_logger->error( "%s failed, error = %x, %s", funcname, hr, pszmsg); LocalFree(pszmsg);}// wrapper for Blt on primary surface to check for recoverable errors#define MAX_RETRIES 1static void primary_Blt(IDirectDrawSurface* primary_surface, LPRECT lpDestRect, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags, LPDDBLTFX lpDDBltFX){ HRESULT hr = DD_OK; int retries = MAX_RETRIES; while (retries--) { hr = primary_surface->Blt(lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFX); if (hr == DDERR_SURFACELOST && retries >= 0) { viewport_logger->trace("primary_Blt recovering from DDERR_LOSTSURFACE retry=%d", MAX_RETRIES-retries); hr = primary_surface->Restore(); if (FAILED(hr)) { seterror("primary_Blt/DirectDrawSurface::Restore()", hr); return; } } else break; } if (FAILED(hr)) seterror("primary_Blt/DirectDrawSurface::Blt()", hr);}const lib::color_t CLR_DEFAULT = RGB(255, 255, 255);gui::dx::viewport::viewport(int width, int height, HWND hwnd) : m_width(width), m_height(height), m_direct_draw(NULL), m_primary_surface(NULL), m_surface(NULL), m_fstr_surface(NULL), m_fstransition(NULL), m_hwnd(hwnd?hwnd:GetDesktopWindow()), bits_size(24), red_bits(8), green_bits(8), blue_bits(8), lo_red_bit(16), lo_green_bit(8), lo_blue_bit(0), palette_entries(0), m_bgd(CLR_DEFAULT) { viewport_logger = lib::logger::get_logger(); IDirectDrawFactory *pDDF = NULL; HRESULT hr = CoCreateInstance(CLSID_DirectDrawFactory, NULL, CLSCTX_INPROC_SERVER, IID_IDirectDrawFactory, (void **)&pDDF); if (FAILED(hr)){ seterror("CoCreateInstance(CLSID_DirectDrawFactory, ...)", hr); return; } IDirectDraw *pDD1=NULL; hr = pDDF->CreateDirectDraw(NULL, m_hwnd, DDSCL_NORMAL , 0, NULL, &pDD1); pDDF->Release(); if (FAILED(hr)){ seterror("CreateDirectDraw()", hr); return; } hr = pDD1->QueryInterface(IID_IDirectDraw2, (void**)&m_direct_draw); if (FAILED(hr)){ seterror("QueryInterface(IID_IDirectDraw2,...)", hr); pDD1->Release(); return; } pDD1->Release(); DWORD flags = DDSCL_NORMAL; hr = m_direct_draw->SetCooperativeLevel(m_hwnd, flags); if (FAILED(hr)) { seterror("SetCooperativeLevel()", hr); return; } // create primary surface DDSURFACEDESC sd; memset(&sd, 0, sizeof(DDSURFACEDESC)); sd.dwSize = sizeof(DDSURFACEDESC); sd.dwFlags = DDSD_CAPS; sd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; hr = m_direct_draw->CreateSurface(&sd, &m_primary_surface, NULL); if (FAILED(hr)) { seterror("DirectDraw::CreateSurface()", hr); return; } get_pixel_format(); // Clip output to the provided window if(m_hwnd) { IDirectDrawClipper *clipper = NULL; hr = m_direct_draw->CreateClipper(0, &clipper, NULL); if (FAILED(hr)) seterror("DirectDraw::CreateClipper()", hr); clipper->SetHWnd(0, m_hwnd); hr = m_primary_surface->SetClipper(clipper); if (FAILED(hr)) seterror("DirectDrawSurface::SetClipper()", hr); clipper->Release(); } // create drawing surface memset(&sd, 0, sizeof(DDSURFACEDESC)); sd.dwSize = sizeof(DDSURFACEDESC); sd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; sd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; sd.dwWidth = m_width; sd.dwHeight = m_height; hr = m_direct_draw->CreateSurface(&sd, &m_surface, NULL); if (FAILED(hr)){ seterror("DirectDraw::CreateSurface()", hr); return; } m_ddbgd = convert(m_bgd); // clear the back buffer clear(); // create shared transition surface IDirectDrawSurface* surf; memset(&sd, 0, sizeof(DDSURFACEDESC)); sd.dwSize = sizeof(DDSURFACEDESC); sd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; sd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; sd.dwWidth = m_width; sd.dwHeight = m_height; hr = m_direct_draw->CreateSurface(&sd, &surf, NULL); if (FAILED(hr)){ seterror("DirectDraw::CreateSurface()", hr); return; } m_surfaces.push_back(surf); memset(&sd, 0, sizeof(DDSURFACEDESC)); sd.dwSize = sizeof(DDSURFACEDESC); sd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; sd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; sd.dwWidth = m_width; sd.dwHeight = m_height; hr = m_direct_draw->CreateSurface(&sd, &m_fstr_surface, NULL); if (FAILED(hr)){ seterror("DirectDraw::CreateSurface()", hr); return; }}gui::dx::viewport::~viewport() { std::list<IDirectDrawSurface*>::iterator it; for(it=m_surfaces.begin();it!=m_surfaces.end();it++) (*it)->Release(); RELEASE(m_surface); RELEASE(m_primary_surface); RELEASE(m_direct_draw); RELEASE(m_fstr_surface); if(palette_entries != 0) delete[] palette_entries; RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);}// Sets the background color of this viewportvoid gui::dx::viewport::set_background(lib::color_t color) { m_bgd = (color == CLR_INVALID)?CLR_DEFAULT:color; m_ddbgd = convert(m_bgd);}// Creates a DD surface with the provided size.// The surface is cleared using the specified colorIDirectDrawSurface* gui::dx::viewport::create_surface(DWORD w, DWORD h) { IDirectDrawSurface* surface = 0; DDSURFACEDESC sd; memset(&sd, 0, sizeof(DDSURFACEDESC)); sd.dwSize = sizeof(DDSURFACEDESC); sd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; sd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; sd.dwWidth = w; sd.dwHeight = h; HRESULT hr = m_direct_draw->CreateSurface(&sd, &surface, NULL); if (FAILED(hr)){ seterror("DirectDraw::CreateSurface()", hr); return 0; } return surface;}IDirectDrawSurface* gui::dx::viewport::create_surface() { IDirectDrawSurface* surf = 0; if(m_surfaces.empty()) { return create_surface(m_width, m_height); } std::list<IDirectDrawSurface*>::iterator it = m_surfaces.begin(); surf = *it; m_surfaces.erase(it); return surf;}void gui::dx::viewport::release_surface(IDirectDrawSurface* surf) { m_surfaces.push_back(surf);}// Blt back buffer to primary surfacevoid gui::dx::viewport::redraw() { if(!m_primary_surface || !m_surface) return; RECT src_rc = {0, 0, m_width, m_height}; RECT dst_rc = {0, 0, m_width, m_height}; lib::rect ourrect(lib::point(0,0), lib::size(m_width, m_height)); DWORD flags = DDBLT_WAIT; if (m_fstransition) { AM_DBG lib::logger::get_logger()->debug("viewport::redraw: Applying fullscreen transition"); // Create a temp surface, determine bg/fg surfaces and copy the background
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -