diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index 9728bdccfb..e876930628 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -276,8 +276,8 @@ void DXGraphicsStateGuardian::SetFPSMeterPosition(RECT &view_rect) { if(_fpsmeter_verts==NULL) return; - DWORD renderWid = view_rect.right - view_rect.left; - DWORD renderHt = view_rect.bottom - view_rect.top; + DWORD renderWid = RECT_XSIZE(view_rect); + DWORD renderHt = RECT_YSIZE(view_rect); // adjust these to match fontsize (these are hacks for default font, probably should get char width from win32) #define FPSMETER_NUMFONTLETTERS 11 // need 11 letters [0-9.] @@ -3927,6 +3927,7 @@ texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb, void DXGraphicsStateGuardian:: copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) { + RECT SrcCopyRect; nassertv(pb != NULL && dr != NULL); int xo, yo, w, h; @@ -3941,30 +3942,80 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) { IDirect3DSurface8 *pD3DSurf; HRESULT hr; + RECT WindRect; + GetWindowRect(scrn.hWnd,&WindRect); + // just handling front and backbuf for now, not textures yet if(_cur_read_pixel_buffer & RenderBuffer::T_back) { hr=scrn.pD3DDevice->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pD3DSurf); - } else if(_cur_read_pixel_buffer & RenderBuffer::T_front) { - // must create a X8R8G8B8 sysmem surface for GetFrontBuffer to copy to - hr=scrn.pD3DDevice->CreateImageSurface(w,h,D3DFMT_A8R8G8B8,&pD3DSurf); if(FAILED(hr)) { - dxgsg_cat.error() << "CreateImageSurface failed in copy_pixel_buffer(), hr = " << D3DERRORSTRING(hr); + dxgsg_cat.error() << "GetBackBuffer failed, hr = " << D3DERRORSTRING(hr); exit(1); } - hr=scrn.pD3DDevice->GetFrontBuffer(pD3DSurf); + D3DSURFACE_DESC SurfDesc; + hr = pD3DSurf->GetDesc(&SurfDesc); + + SrcCopyRect.top=SrcCopyRect.left=0; + SrcCopyRect.right=SurfDesc.Width; + SrcCopyRect.bottom=SurfDesc.Height; + + // note if you try to grab the backbuffer and full-screen anti-aliasing is on, + // the backbuffer might be larger than the window size. for screenshots its safer to get the front buffer. + + } else if(_cur_read_pixel_buffer & RenderBuffer::T_front) { + // must create a A8R8G8B8 sysmem surface for GetFrontBuffer to copy to + + DWORD TmpSurfXsize,TmpSurfYsize; + + if(scrn.PresParams.Windowed) { + // GetFrontBuffer retrieves the entire desktop for a monitor, so need space for that + + MONITORINFO minfo; + minfo.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(scrn.hMon, &minfo); // have to use GetMonitorInfo, since this gsg may not be for primary monitor + + TmpSurfXsize=RECT_XSIZE(minfo.rcMonitor); + TmpSurfYsize=RECT_YSIZE(minfo.rcMonitor); + + // set SrcCopyRect to client area of window in scrn coords + GetClientRect( scrn.hWnd, &SrcCopyRect); + ClientToScreen( scrn.hWnd, (POINT*)&SrcCopyRect.left ); + ClientToScreen( scrn.hWnd, (POINT*)&SrcCopyRect.right ); + } else { + TmpSurfXsize=RECT_XSIZE(WindRect); + TmpSurfYsize=RECT_YSIZE(WindRect); + + SrcCopyRect.top=SrcCopyRect.left=0; + SrcCopyRect.right=TmpSurfXsize; + SrcCopyRect.bottom=TmpSurfYsize; + } + + hr=scrn.pD3DDevice->CreateImageSurface(TmpSurfXsize,TmpSurfYsize,D3DFMT_A8R8G8B8,&pD3DSurf); + if(FAILED(hr)) { + dxgsg_cat.error() << "CreateImageSurface failed in copy_pixel_buffer(), hr = " << D3DERRORSTRING(hr); + exit(1); + } + + hr=scrn.pD3DDevice->GetFrontBuffer(pD3DSurf); + + if(hr==D3DERR_DEVICELOST) { + // dont necessary want to exit in this case + pD3DSurf->Release(); + dxgsg_cat.error() << "copy_pixel_buffer failed: device lost\n"; + return; + } } else { dxgsg_cat.error() << "copy_pixel_buffer: unhandled current_read_pixel_buffer type\n"; } - if(FAILED(hr)) { - dxgsg_cat.error() << "copy_pixel_buffer: " << ((_cur_read_pixel_buffer & RenderBuffer::T_back) ? "GetBackBuffer" : "GetFrontBuffer") - << " failed, hr = " << D3DERRORSTRING(hr); - exit(1); + if((RECT_XSIZE(SrcCopyRect)>w) || (RECT_YSIZE(SrcCopyRect)>h)) { + dxgsg_cat.error() << "copy_pixel_buffer: pixel buffer size does not match selected screen RenderBuffer size!\n"; + exit(1); } - (void) ConvertD3DSurftoPixBuf(pD3DSurf,pb); + (void) ConvertD3DSurftoPixBuf(SrcCopyRect,pD3DSurf,pb); ULONG refcnt; RELEASE(pD3DSurf,dxgsg,"pD3DSurf",RELEASE_ONCE); @@ -5797,8 +5848,8 @@ dx_resize_window(HWND mwindow, RECT viewrect) { } */ - scrn.PresParams.BackBufferWidth = viewrect.bottom-viewrect.top; - scrn.PresParams.BackBufferHeight = viewrect.right-viewrect.left; + scrn.PresParams.BackBufferWidth = RECT_XSIZE(viewrect); + scrn.PresParams.BackBufferHeight = RECT_YSIZE(viewrect); HRESULT hr=scrn.pD3DDevice->Reset(&scrn.PresParams); if(FAILED(hr)) { @@ -6133,9 +6184,10 @@ bool DXGraphicsStateGuardian::CheckCooperativeLevel(bool bDoReactivateWindow) { //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian::adjust_view_rect(int x, int y) { if (scrn.view_rect.left != x || scrn.view_rect.top != y) { - scrn.view_rect.right = x + scrn.view_rect.right - scrn.view_rect.left; + + scrn.view_rect.right = x + RECT_XSIZE(scrn.view_rect); scrn.view_rect.left = x; - scrn.view_rect.bottom = y + scrn.view_rect.bottom - scrn.view_rect.top; + scrn.view_rect.bottom = y + RECT_YSIZE(scrn.view_rect); scrn.view_rect.top = y; // set_clipper(clip_rect); diff --git a/panda/src/dxgsg8/dxTextureContext8.cxx b/panda/src/dxgsg8/dxTextureContext8.cxx index 414e85896b..3017d6a5c3 100644 --- a/panda/src/dxgsg8/dxTextureContext8.cxx +++ b/panda/src/dxgsg8/dxTextureContext8.cxx @@ -712,7 +712,8 @@ HRESULT ConvertPixBuftoDDSurf(ConversionType ConvNeeded,BYTE *pbuf,LPDIRECTDRAWS */ // still need custom conversion since d3d/d3dx has no way to convert arbitrary fmt to ARGB in-memory user buffer -HRESULT ConvertD3DSurftoPixBuf(IDirect3DSurface8 *pD3DSurf8,PixelBuffer *pixbuf) { +HRESULT ConvertD3DSurftoPixBuf(RECT &SrcRect,IDirect3DSurface8 *pD3DSurf8,PixelBuffer *pixbuf) { +// copies SrcRect in pD3DSurf to upper left of pixbuf HRESULT hr; DWORD dwNumComponents=pixbuf->get_num_components(); @@ -728,67 +729,33 @@ HRESULT ConvertD3DSurftoPixBuf(IDirect3DSurface8 *pD3DSurf8,PixelBuffer *pixbuf) exit(1); } + DWORD dwXWindowOffset,dwYWindowOffset; + DWORD dwCopyWidth,dwCopyHeight; + D3DLOCKED_RECT LockedRect; D3DSURFACE_DESC SurfDesc; hr = pD3DSurf8->GetDesc(&SurfDesc); - hr = pD3DSurf8->LockRect(&LockedRect,(CONST RECT*)NULL,(D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE /* | D3DLOCK_NOSYSLOCK */)); - if(FAILED(hr)) { - dxgsg_cat.error() << "ConvertDDSurftoPixBuf LockRect() failed! hr = " << D3DERRORSTRING(hr); - return hr; - } + dwXWindowOffset=SrcRect.left,dwYWindowOffset=SrcRect.top; + dwCopyWidth=RECT_XSIZE(SrcRect); + dwCopyHeight=RECT_YSIZE(SrcRect); - DWORD dwXWindowOffset=0,dwYWindowOffset=0; - DWORD dwCopyWidth=SurfDesc.Width,dwCopyHeight=SurfDesc.Height; - -/* - - bugbug: need to test scrngrab for windowed case. do I need to do the clientrect stuff? - - // get window offset so we know where to start grabbing pixels. note for - // fullscreen primary no clipper will be attached, that 'error' should be ignored - LPDIRECTDRAWCLIPPER pDDClipper; - hr = pDDSurf->GetClipper(&pDDClipper); - -#ifdef _DEBUG - if(FAILED(hr) && !((hr == DDERR_NOCLIPPERATTACHED) && dx_full_screen)) { - dxgsg_cat.error() << "ConvertDDSurftoPixBuf GetClipper failed! hr = " << ConvD3DErrorToString(hr) << "\n"; - return hr; - } -#endif - - if(hr==S_OK) { - HWND hWin; - - if(FAILED(hr = pDDClipper->GetHWnd(&hWin))) { - dxgsg_cat.error() << "ConvertDDSurftoPixBuf GetHwnd failed! hr = " << ConvD3DErrorToString(hr) << "\n"; - return hr; - } - - RECT view_rect; - GetClientRect( hWin, &view_rect ); - ClientToScreen( hWin, (POINT*)&view_rect.left ); - ClientToScreen( hWin, (POINT*)&view_rect.right ); - - dwXWindowOffset=view_rect.left; - dwYWindowOffset=view_rect.top; - dwCopyWidth=view_rect.right-view_rect.left; - dwCopyHeight=view_rect.bottom-view_rect.top; - - pDDClipper->Release(); // dec ref cnt - } -*/ //make sure there's enough space in the pixbuf, its size must match (especially xsize) // or scanlines will be too long if(!((dwCopyWidth==pixbuf->get_xsize()) && (dwCopyHeight<=(DWORD)pixbuf->get_ysize()))) { - pD3DSurf8->UnlockRect(); - dxgsg_cat.error() << "ConvertDDSurftoPixBuf, PixBuf size does not match display surface!\n"; + dxgsg_cat.error() << "ConvertDDSurftoPixBuf, PixBuf size too small to hold display surface!\n"; assert(0); return E_FAIL; } + hr = pD3DSurf8->LockRect(&LockedRect,(CONST RECT*)NULL,(D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE /* | D3DLOCK_NOSYSLOCK */)); + if(FAILED(hr)) { + dxgsg_cat.error() << "ConvertDDSurftoPixBuf LockRect() failed! hr = " << D3DERRORSTRING(hr); + return hr; + } + // ones not listed not handled yet assert((SurfDesc.Format==D3DFMT_A8R8G8B8)||(SurfDesc.Format==D3DFMT_X8R8G8B8)||(SurfDesc.Format==D3DFMT_R8G8B8)|| (SurfDesc.Format==D3DFMT_R5G6B5)||(SurfDesc.Format==D3DFMT_X1R5G5B5)||(SurfDesc.Format==D3DFMT_A1R5G5B5)|| diff --git a/panda/src/dxgsg8/dxTextureContext8.h b/panda/src/dxgsg8/dxTextureContext8.h index 35937b5c81..d4d58fab14 100644 --- a/panda/src/dxgsg8/dxTextureContext8.h +++ b/panda/src/dxgsg8/dxTextureContext8.h @@ -74,7 +74,7 @@ private: static TypeHandle _type_handle; }; -extern HRESULT ConvertD3DSurftoPixBuf(IDirect3DSurface8 *pD3DSurf8,PixelBuffer *pixbuf); +extern HRESULT ConvertD3DSurftoPixBuf(RECT &SrcRect,IDirect3DSurface8 *pD3DSurf8,PixelBuffer *pixbuf); #endif diff --git a/panda/src/dxgsg8/dxgsg8base.h b/panda/src/dxgsg8/dxgsg8base.h index 3955b750ce..7e5588a3e7 100644 --- a/panda/src/dxgsg8/dxgsg8base.h +++ b/panda/src/dxgsg8/dxgsg8base.h @@ -152,6 +152,8 @@ typedef enum { #define IS_16BPP_FORMAT(FMT) (((FMT)>=D3DFMT_R5G6B5)&&((FMT)<=D3DFMT_A1R5G5B5)) #define IS_STENCIL_FORMAT(FMT) (((FMT)==D3DFMT_D24S8) || ((FMT)==D3DFMT_D15S1) || ((FMT)==D3DFMT_D24X4S4)) +#define RECT_XSIZE(REC) (REC.right-REC.left) +#define RECT_YSIZE(REC) (REC.bottom-REC.top) typedef struct { LPDIRECT3DDEVICE8 pD3DDevice;