Browse Source

fix scrngrab

cxgeorge 24 năm trước cách đây
mục cha
commit
e6835c614b

+ 68 - 16
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);

+ 15 - 48
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;
-    }
-
-    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;
-        }
+    dwXWindowOffset=SrcRect.left,dwYWindowOffset=SrcRect.top;
+    dwCopyWidth=RECT_XSIZE(SrcRect);
+    dwCopyHeight=RECT_YSIZE(SrcRect);
 
-        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)||

+ 1 - 1
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
 

+ 2 - 0
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;