Pārlūkot izejas kodu

fix screenshots on dx9; robustify Panda screenshot interface

David Rose 22 gadi atpakaļ
vecāks
revīzija
429fbba758

+ 3 - 0
panda/src/display/config_display.cxx

@@ -81,6 +81,9 @@ const bool yield_timeslice = config_display.GetBool("yield-timeslice", false);
 // This variable may be repeated several times.
 
 
+const string screenshot_filename = config_display.GetString("screenshot-filename", "%~p-%a-%b-%d-%H-%M-%S-%Y-%~f.%~e");
+const string screenshot_extension = config_display.GetString("screenshot-extension", "jpg");
+
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libdisplay
 //  Description: Initializes the library.  This must be called at

+ 3 - 0
panda/src/display/config_display.h

@@ -37,6 +37,9 @@ extern const string threading_model;
 extern const bool auto_flip;
 extern const bool yield_timeslice;
 
+extern const string screenshot_filename;
+extern const string screenshot_extension;
+
 extern EXPCL_PANDA const bool multiple_windows;
 
 extern EXPCL_PANDA void init_libdisplay();

+ 116 - 0
panda/src/display/graphicsWindow.cxx

@@ -385,6 +385,122 @@ get_display_region(int n) const {
   return result;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::take_screenshot
+//       Access: Published
+//  Description: Saves a screenshot of the window to a default
+//               filename, and returns the filename, or empty string
+//               if the screenshot failed.  The default filename is
+//               generated from the supplied prefix and from the
+//               Configrc variable screenshot-filename, which contains
+//               the following strings:
+//
+//                 %~p - the supplied prefix
+//                 %~f - the frame count
+//                 %~e - the value of screenshot-extension
+//                 All other % strings in strftime().
+////////////////////////////////////////////////////////////////////
+Filename GraphicsWindow::
+take_screenshot(const string &prefix) {
+  time_t now = time(NULL);
+  struct tm *ttm = localtime(&now);
+  int frame_count = ClockObject::get_global_clock()->get_frame_count();
+
+  static const int buffer_size = 1024;
+  char buffer[buffer_size];
+
+  ostringstream filename_strm;
+
+  size_t i = 0;
+  while (i < screenshot_filename.length()) {
+    char ch1 = screenshot_filename[i++];
+    if (ch1 == '%' && i < screenshot_filename.length()) {
+      char ch2 = screenshot_filename[i++];
+      if (ch2 == '~' && i < screenshot_filename.length()) {
+        char ch3 = screenshot_filename[i++];
+        switch (ch3) {
+        case 'p':
+          filename_strm << prefix;
+          break;
+
+        case 'f':
+          filename_strm << frame_count;
+          break;
+
+        case 'e':
+          filename_strm << screenshot_extension;
+          break;
+        }
+
+      } else {
+        // Use strftime() to decode the percent code.
+        char format[3] = {'%', ch2, '\0'};
+        if (strftime(buffer, buffer_size, format, ttm)) {
+          for (char *b = buffer; *b != '\0'; b++) {
+            switch (*b) {
+            case ' ':
+            case ':':
+            case '/':
+              filename_strm << '-';
+              break;
+
+            case '\n':
+              break;
+
+            default:
+              filename_strm << *b;
+            }
+          }
+        }
+      }
+    } else {
+      filename_strm << ch1;
+    }
+  }
+
+  Filename filename = filename_strm.str();
+  if (take_screenshot(filename)) {
+    return filename;
+  }
+  return Filename();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::take_screenshot
+//       Access: Published
+//  Description: Saves a screenshot of the window to the indicated
+//               filename.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool GraphicsWindow::
+take_screenshot(const Filename &filename) {
+  if (_gsg == (GraphicsStateGuardian *)NULL) {
+    return false;
+  }
+
+  WindowProperties props = get_properties();
+  if (!props.has_size()) {
+    return false;
+  }
+
+  int x_size = props.get_x_size();
+  int y_size = props.get_y_size();
+
+  PixelBuffer p(x_size, y_size, 3, 1, PixelBuffer::T_unsigned_byte,
+                PixelBuffer::F_rgb);
+
+  DisplayRegion dr(x_size, y_size);
+  RenderBuffer rb = _gsg->get_render_buffer(RenderBuffer::T_front);
+  if (!p.copy(_gsg, &dr, rb)) {
+    return false;
+  }
+
+  if (!p.write(filename)) {
+    return false;
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::get_num_input_devices
 //       Access: Published

+ 4 - 0
panda/src/display/graphicsWindow.h

@@ -36,6 +36,7 @@
 #include "iterator_types.h"
 #include "notify.h"
 #include "pmutex.h"
+#include "filename.h"
 
 #include "pvector.h"
 #include "pdeque.h"
@@ -97,6 +98,9 @@ PUBLISHED:
   int get_num_display_regions() const;
   DisplayRegion *get_display_region(int n) const;
 
+  Filename take_screenshot(const string &prefix = "screenshot");
+  bool take_screenshot(const Filename &filename);
+
   // Mouse and keyboard routines
   int get_num_input_devices() const;
   string get_input_device_name(int device) const;

+ 7 - 9
panda/src/dxgsg7/dxGraphicsStateGuardian7.cxx

@@ -3641,21 +3641,18 @@ texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian7::
+bool DXGraphicsStateGuardian7::
 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 
     extern HRESULT ConvertDDSurftoPixBuf(PixelBuffer *pixbuf,LPDIRECTDRAWSURFACE7 pDDSurf);
 
-    nassertv(pb != NULL && dr != NULL);
+    nassertr(pb != NULL && dr != NULL, false);
 
     int xo, yo, w, h;
     dr->get_region_pixels(xo, yo, w, h);
 
     // only handled simple case
-    nassertv(xo==0);
-    nassertv(yo==0);
-    nassertv(w==pb->get_xsize());
-    nassertv(h==pb->get_ysize());
+    nassertr(xo == 0 && yo==0 && w == pb->get_xsize() && h == pb->get_ysize(), false);
 
 /*
     set_pack_alignment(1);
@@ -3669,7 +3666,8 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 
     (void) ConvertDDSurftoPixBuf(pb,((_cur_read_pixel_buffer & RenderBuffer::T_back) ? _pScrn->pddsBack : _pScrn->pddsPrimary));
 
-    nassertv(!pb->_image.empty());
+    nassertr(!pb->_image.empty(), false);
+    return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -3677,11 +3675,11 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian7::
+bool DXGraphicsStateGuardian7::
 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
                   const RenderBuffer &rb) {
     set_read_buffer(rb);
-    copy_pixel_buffer(pb, dr);
+    return copy_pixel_buffer(pb, dr);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/dxgsg7/dxGraphicsStateGuardian7.h

@@ -106,8 +106,8 @@ public:
   virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
                 const DisplayRegion *dr);
 
-  virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr);
-  virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
+  virtual bool copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr);
+  virtual bool copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
                                  const RenderBuffer &rb);
 
   virtual void apply_material(const Material *material);

+ 12 - 14
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -3318,20 +3318,17 @@ texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian8::
+bool DXGraphicsStateGuardian8::
 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 
     RECT SrcCopyRect;
-    nassertv(pb != NULL && dr != NULL);
+    nassertr(pb != NULL && dr != NULL, false);
 
     int xo, yo, w, h;
     dr->get_region_pixels(xo, yo, w, h);
 
     // only handled simple case
-    nassertv(xo==0);
-    nassertv(yo==0);
-    nassertv(w==pb->get_xsize());
-    nassertv(h==pb->get_ysize());
+    nassertr(xo == 0 && yo==0 && w == pb->get_xsize() && h == pb->get_ysize(), false);
 
     IDirect3DSurface8 *pD3DSurf;
     HRESULT hr;
@@ -3345,7 +3342,7 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 
        if(FAILED(hr)) {
            dxgsg8_cat.error() << "GetBackBuffer failed" << D3DERRORSTRING(hr);
-           exit(1);
+           return false;
        }
 
        D3DSURFACE_DESC SurfDesc;
@@ -3389,31 +3386,32 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
         hr=_pD3DDevice->CreateImageSurface(TmpSurfXsize,TmpSurfYsize,D3DFMT_A8R8G8B8,&pD3DSurf);
         if(FAILED(hr)) {
            dxgsg8_cat.error() << "CreateImageSurface failed in copy_pixel_buffer()" << D3DERRORSTRING(hr);
-           exit(1);
+           return false;
         }
 
         hr=_pD3DDevice->GetFrontBuffer(pD3DSurf);
 
         if(hr==D3DERR_DEVICELOST) {
-           // dont necessary want to exit in this case
            pD3DSurf->Release();
            dxgsg8_cat.error() << "copy_pixel_buffer failed: device lost\n";
-           return;
+           return false;
         }
     } else {
         dxgsg8_cat.error() << "copy_pixel_buffer: unhandled current_read_pixel_buffer type\n";
+        return false;
     }
 
     if((RECT_XSIZE(SrcCopyRect)>w) || (RECT_YSIZE(SrcCopyRect)>h)) {
      dxgsg8_cat.error() << "copy_pixel_buffer: pixel buffer size does not match selected screen RenderBuffer size!\n";
-     exit(1);
+     return false;
     }
 
     (void) ConvertD3DSurftoPixBuf(SrcCopyRect,pD3DSurf,pb);
 
     RELEASE(pD3DSurf,dxgsg8,"pD3DSurf",RELEASE_ONCE);
 
-    nassertv(!pb->_image.empty());
+    nassertr(!pb->_image.empty(), false);
+    return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -3421,11 +3419,11 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian8::
+bool DXGraphicsStateGuardian8::
 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
                   const RenderBuffer &rb) {
     set_read_buffer(rb);
-    copy_pixel_buffer(pb, dr);
+    return copy_pixel_buffer(pb, dr);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -110,8 +110,8 @@ public:
   virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
                 const DisplayRegion *dr);
 
-  virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr);
-  virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
+  virtual bool copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr);
+  virtual bool copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
                                  const RenderBuffer &rb);
 
   virtual void apply_material(const Material *material);

+ 13 - 15
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -3337,20 +3337,17 @@ texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian9::
+bool DXGraphicsStateGuardian9::
 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 
     RECT SrcCopyRect;
-    nassertv(pb != NULL && dr != NULL);
+    nassertr(pb != NULL && dr != NULL, false);
 
     int xo, yo, w, h;
     dr->get_region_pixels(xo, yo, w, h);
 
     // only handled simple case
-    nassertv(xo==0);
-    nassertv(yo==0);
-    nassertv(w==pb->get_xsize());
-    nassertv(h==pb->get_ysize());
+    nassertr(xo == 0 && yo==0 && w == pb->get_xsize() && h == pb->get_ysize(), false);
 
     IDirect3DSurface9 *pD3DSurf;
     HRESULT hr;
@@ -3364,7 +3361,7 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 
        if(FAILED(hr)) {
            dxgsg9_cat.error() << "GetBackBuffer failed" << D3DERRORSTRING(hr);
-           exit(1);
+           return false;
        }
 
        D3DSURFACE_DESC SurfDesc;
@@ -3405,34 +3402,35 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
            SrcCopyRect.bottom=TmpSurfYsize;
         }
 
-        hr=_pD3DDevice->CreateOffscreenPlainSurface(TmpSurfXsize,TmpSurfYsize,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED, &pD3DSurf, NULL);
+        hr=_pD3DDevice->CreateOffscreenPlainSurface(TmpSurfXsize,TmpSurfYsize,D3DFMT_A8R8G8B8,D3DPOOL_SCRATCH, &pD3DSurf, NULL);
         if(FAILED(hr)) {
            dxgsg9_cat.error() << "CreateImageSurface failed in copy_pixel_buffer()" << D3DERRORSTRING(hr);
-           exit(1);
+           return false;
         }
 
         hr=_pD3DDevice->GetFrontBufferData(0, pD3DSurf);
 
         if(hr==D3DERR_DEVICELOST) {
-           // dont necessary want to exit in this case
            pD3DSurf->Release();
            dxgsg9_cat.error() << "copy_pixel_buffer failed: device lost\n";
-           return;
+           return false;
         }
     } else {
         dxgsg9_cat.error() << "copy_pixel_buffer: unhandled current_read_pixel_buffer type\n";
+        return false;
     }
 
     if((RECT_XSIZE(SrcCopyRect)>w) || (RECT_YSIZE(SrcCopyRect)>h)) {
      dxgsg9_cat.error() << "copy_pixel_buffer: pixel buffer size does not match selected screen RenderBuffer size!\n";
-     exit(1);
+     return false;
     }
 
     (void) ConvertD3DSurftoPixBuf(SrcCopyRect,pD3DSurf,pb);
 
     RELEASE(pD3DSurf,dxgsg9,"pD3DSurf",RELEASE_ONCE);
 
-    nassertv(!pb->_image.empty());
+    nassertr(!pb->_image.empty(), false);
+    return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -3440,11 +3438,11 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian9::
+bool DXGraphicsStateGuardian9::
 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
                   const RenderBuffer &rb) {
     set_read_buffer(rb);
-    copy_pixel_buffer(pb, dr);
+    return copy_pixel_buffer(pb, dr);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -110,8 +110,8 @@ public:
   virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
                 const DisplayRegion *dr);
 
-  virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr);
-  virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
+  virtual bool copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr);
+  virtual bool copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
                                  const RenderBuffer &rb);
 
   virtual void apply_material(const Material *material);

+ 1 - 0
panda/src/framework/config_framework.cxx

@@ -45,3 +45,4 @@ const float win_background_b = config_framework.GetFloat("win-background-b", 0.4
 const string record_session = config_framework.GetString("record-session", "");
 const string playback_session = config_framework.GetString("playback-session", "");
 
+

+ 80 - 4
panda/src/framework/pandaFramework.cxx

@@ -618,6 +618,14 @@ do_frame() {
   DataGraphTraverser dg_trav;
   dg_trav.traverse(_data_root.node());
   _event_handler.process_events();
+
+  if (!_screenshot_text.is_empty()) {
+    double now = ClockObject::get_global_clock()->get_frame_time();
+    if (now >= _screenshot_clear_time) {
+      _screenshot_text.remove_node();
+    }
+  }
+
   if (_recorder != (RecorderController *)NULL) {
     _recorder->record_frame();
   }
@@ -701,6 +709,7 @@ do_enable_default_keys() {
   define_key("arrow_left", "move highlight to sibling", event_arrow_left, this);
   define_key("arrow_right", "move highlight to sibling", event_arrow_right, this);
   define_key("shift-s", "activate PStats", event_S, this);
+  define_key("f9", "Take screenshot", event_f9, this);
   define_key(",", "change background color", event_comma, this);
   define_key("?", "", event_question, this);
   define_key("shift-/", "", event_question, this);
@@ -708,6 +717,29 @@ do_enable_default_keys() {
   _event_handler.add_hook("window-event", event_window_event, this);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PandaFramework::clear_text
+//       Access: Protected
+//  Description: Removes any onscreen text (like help text or
+//               screenshot filename).  Returns true if there was any
+//               text in the first place, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool PandaFramework::
+clear_text() {
+  bool any_text = false;
+  if (!_screenshot_text.is_empty()) {
+    _screenshot_text.remove_node();
+    any_text = true;
+  }
+
+  if (!_help_text.is_empty()) {
+    _help_text.remove_node();
+    any_text = true;
+  }
+
+  return any_text;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaFramework::event_esc
 //       Access: Protected, Static
@@ -1031,7 +1063,7 @@ event_arrow_right(CPT_Event, void *data) {
 //  Description: Default handler for shift-S key: activate stats.
 ////////////////////////////////////////////////////////////////////
 void PandaFramework::
-event_S(CPT_Event, void *data) {
+event_S(CPT_Event, void *) {
 #ifdef DO_PSTATS
   nout << "Connecting to stats host" << endl;
   PStatClient::connect();
@@ -1040,6 +1072,48 @@ event_S(CPT_Event, void *data) {
 #endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PandaFramework::event_f9
+//       Access: Protected, Static
+//  Description: Default handler for f9 key: take screenshot.
+////////////////////////////////////////////////////////////////////
+void PandaFramework::
+event_f9(CPT_Event event, void *data) {
+  PandaFramework *self = (PandaFramework *)data;
+
+  if (event->get_num_parameters() == 1) {
+    EventParameter param = event->get_parameter(0);
+    WindowFramework *wf;
+    DCAST_INTO_V(wf, param.get_ptr());
+
+    if (self->clear_text()) {
+      // Render one more frame to remove the text.
+      self->_engine.render_frame();
+    }
+
+    Filename filename = wf->get_graphics_window()->take_screenshot();
+    string text;
+    if (filename.empty()) {
+      text = "Screenshot failed";
+    } else {
+      text = filename;
+    }
+
+    TextNode *text_node = new TextNode("screenshot");
+    self->_screenshot_text = NodePath(text_node);
+    text_node->set_align(TextNode::A_center);
+    text_node->set_shadow_color(0.0f, 0.0f, 0.0f, 1.0f);
+    text_node->set_shadow(0.04f, 0.04f);
+    text_node->set_text(text);
+    self->_screenshot_text.set_scale(0.06);
+    self->_screenshot_text.set_pos(0.0, 0.0, -0.7);
+    self->_screenshot_text.reparent_to(wf->get_aspect_2d());
+
+    double now = ClockObject::get_global_clock()->get_frame_time();
+    self->_screenshot_clear_time = now + 2.0;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaFramework::event_comma
 //       Access: Protected, Static
@@ -1073,15 +1147,17 @@ event_comma(CPT_Event event, void *) {
 ////////////////////////////////////////////////////////////////////
 void PandaFramework::
 event_question(CPT_Event event, void *data) {
-  cerr << "got question\n";
   PandaFramework *self = (PandaFramework *)data;
   if (event->get_num_parameters() == 1) {
     EventParameter param = event->get_parameter(0);
     WindowFramework *wf;
     DCAST_INTO_V(wf, param.get_ptr());
 
+    self->_screenshot_text.remove_node();
+
     if (!self->_help_text.is_empty()) {
       self->_help_text.remove_node();
+      // This key is a toggle; remove the help text and do nothing else.
 
     } else {
       // Build up a string to display.
@@ -1096,12 +1172,12 @@ event_question(CPT_Event event, void *data) {
 
       string help_text = help.str();
 
-      TextNode *text_node = new TextNode("text");
+      TextNode *text_node = new TextNode("help");
       self->_help_text = NodePath(text_node);
-      text_node->set_text(help_text);
       text_node->set_align(TextNode::A_left);
       text_node->set_shadow_color(0.0f, 0.0f, 0.0f, 1.0f);
       text_node->set_shadow(0.04f, 0.04f);
+      text_node->set_text(help_text);
 
       LVecBase4f frame = text_node->get_frame_actual();
 

+ 4 - 0
panda/src/framework/pandaFramework.h

@@ -115,6 +115,7 @@ protected:
   virtual PT(WindowFramework) make_window_framework();
   virtual void make_default_pipe();
   virtual void do_enable_default_keys();
+  bool clear_text();
 
   static void event_esc(CPT_Event, void *data);
   static void event_f(CPT_Event, void *data);
@@ -133,6 +134,7 @@ protected:
   static void event_arrow_left(CPT_Event, void *data);
   static void event_arrow_right(CPT_Event, void *data);
   static void event_S(CPT_Event, void *data);
+  static void event_f9(CPT_Event, void *data);
   static void event_comma(CPT_Event, void *data);
   static void event_question(CPT_Event event, void *data);
   static void event_window_event(CPT_Event, void *data);
@@ -181,6 +183,8 @@ private:
   KeyDefinitions _key_definitions;
 
   NodePath _help_text;
+  NodePath _screenshot_text;
+  double _screenshot_clear_time;
 
   PT(RecorderController) _recorder;
 };

+ 1 - 1
panda/src/framework/windowFramework.h

@@ -100,7 +100,7 @@ public:
   INLINE bool get_one_sided_reverse() const;
   INLINE bool get_lighting() const;
   INLINE BackgroundType get_background_type() const;
-
+  
 protected:
   PT(Camera) make_camera();
   void setup_lights();

+ 6 - 5
panda/src/glgsg/glGraphicsStateGuardian.cxx

@@ -1954,9 +1954,9 @@ texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void GLGraphicsStateGuardian::
+bool GLGraphicsStateGuardian::
 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
-  nassertv(pb != NULL && dr != NULL);
+  nassertr(pb != NULL && dr != NULL, false);
   set_pack_alignment(1);
 
   // Bug fix for RE, RE2, and VTX - need to disable texturing in order
@@ -2014,7 +2014,7 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 
   // pixelbuffer "origin" represents upper left screen point at which
   // pixelbuffer should be drawn using draw_pixel_buffer
-  nassertv(!pb->_image.empty());
+  nassertr(!pb->_image.empty(), false);
   glReadPixels(pb->get_xorg() + xo, pb->get_yorg() + yo,
                pb->get_xsize(), pb->get_ysize(),
                external_format,
@@ -2035,6 +2035,7 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
   }
 
   report_gl_errors();
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2042,11 +2043,11 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void GLGraphicsStateGuardian::
+bool GLGraphicsStateGuardian::
 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
                   const RenderBuffer &rb) {
   set_read_buffer(rb);
-  copy_pixel_buffer(pb, dr);
+  return copy_pixel_buffer(pb, dr);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/glgsg/glGraphicsStateGuardian.h

@@ -104,8 +104,8 @@ public:
   virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
                                        const DisplayRegion *dr);
 
-  virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr);
-  virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
+  virtual bool copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr);
+  virtual bool copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
                                  const RenderBuffer &rb);
 
   virtual void apply_material(const Material *material);

+ 2 - 2
panda/src/gobj/imageBuffer.h

@@ -43,8 +43,8 @@ PUBLISHED:
 public:
   virtual void config( void ) { WritableConfigurable::config(); }
 
-  virtual void copy(GraphicsStateGuardianBase *, const DisplayRegion *)=0;
-  virtual void copy(GraphicsStateGuardianBase *, const DisplayRegion *,
+  virtual bool copy(GraphicsStateGuardianBase *, const DisplayRegion *)=0;
+  virtual bool copy(GraphicsStateGuardianBase *, const DisplayRegion *,
                     const RenderBuffer &rb)=0;
 
 PUBLISHED:

+ 4 - 4
panda/src/gobj/pixelBuffer.cxx

@@ -422,12 +422,12 @@ copy(const PixelBuffer *pb) {
     _image.v() = pb->_image.v();
 }
 
-void PixelBuffer::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr) {
-  gsg->copy_pixel_buffer(this, dr);
+bool PixelBuffer::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr) {
+  return gsg->copy_pixel_buffer(this, dr);
 }
 
-void PixelBuffer::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr,
+bool PixelBuffer::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr,
                        const RenderBuffer &rb) {
-  gsg->copy_pixel_buffer(this, dr, rb);
+  return gsg->copy_pixel_buffer(this, dr, rb);
 }
 

+ 4 - 4
panda/src/gobj/pixelBuffer.h

@@ -105,10 +105,10 @@ public:
   bool store( PNMImage& pnmimage ) const;
 
   void copy(const PixelBuffer *pb);
-
-  virtual void copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr);
-  virtual void copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr,
-            const RenderBuffer &rb);
+  
+  virtual bool copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr);
+  virtual bool copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr,
+                    const RenderBuffer &rb);
 
   INLINE void set_xsize(int size);
   INLINE void set_ysize(int size);

+ 4 - 2
panda/src/gobj/texture.cxx

@@ -606,13 +606,15 @@ get_ram_image() {
   }
 }
 
-void Texture::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr) {
+bool Texture::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr) {
   gsg->copy_texture(prepare(gsg), dr);
+  return true;
 }
 
-void Texture::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr,
+bool Texture::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr,
                    const RenderBuffer &rb) {
   gsg->copy_texture(prepare(gsg), dr, rb);
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/gobj/texture.h

@@ -116,8 +116,8 @@ public:
 
   INLINE void apply(GraphicsStateGuardianBase *gsg);
 
-  virtual void copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr);
-  virtual void copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr,
+  virtual bool copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr);
+  virtual bool copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr,
                     const RenderBuffer &rb);
 
   // These bits are used as parameters to Texture::mark_dirty() and

+ 2 - 2
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -164,8 +164,8 @@ public:
   virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
                                 const DisplayRegion *dr)=0;
 
-  virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr)=0;
-  virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
+  virtual bool copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr)=0;
+  virtual bool copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
                                  const RenderBuffer &rb)=0;
 
   virtual void apply_material(const Material *material)=0;