Przeglądaj źródła

jpeg splash images

David Rose 16 lat temu
rodzic
commit
5fea6fffd7

+ 1 - 1
direct/src/plugin/Sources.pp

@@ -3,7 +3,7 @@
 #define BUILD_DIRECTORY $[and $[HAVE_P3D_PLUGIN],$[HAVE_TINYXML],$[HAVE_OPENSSL],$[HAVE_ZLIB]]
 
 #begin lib_target
-  #define USE_PACKAGES tinyxml openssl zlib
+  #define USE_PACKAGES tinyxml openssl zlib jpeg
   #define TARGET p3d_plugin
   #define LIB_PREFIX
 

+ 16 - 7
direct/src/plugin/p3dInstance.cxx

@@ -98,13 +98,6 @@ set_fparams(const P3DFileParams &fparams) {
   _got_fparams = true;
   _fparams = fparams;
 
-  // Maybe create the splash window.
-  if (!_instance_window_opened && _got_wparams) {
-    if (_splash_window == NULL) {
-      _splash_window = new SplashWindowType(this);
-    }
-  }
-
   // This also sets up some internal data based on the contents of the
   // above file and the associated tokens.
 
@@ -115,6 +108,21 @@ set_fparams(const P3DFileParams &fparams) {
   _session_key = strm.str();
 
   _python_version = "python24";
+
+
+  // Maybe create the splash window.
+  if (!_instance_window_opened && _got_wparams) {
+    if (_splash_window == NULL) {
+      _splash_window = new SplashWindowType(this);
+      //      _splash_window->set_image_filename("c:/Documents and Settings/drose/Desktop/pandalogo.jpg");
+    }
+  }
+
+  /*
+  string splash_image_url = _fparams.lookup_token("splash_img");
+  if (!splash_image_url.is_empty()) {
+  }
+  */
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -133,6 +141,7 @@ set_wparams(const P3DWindowParams &wparams) {
   if (!_instance_window_opened && _got_fparams) {
     if (_splash_window == NULL) {
       _splash_window = new SplashWindowType(this);
+      //      _splash_window->set_image_filename("c:/Documents and Settings/drose/Desktop/pandalogo.jpg");
     } else {
       _splash_window->set_wparams(_wparams);
     }

+ 10 - 0
direct/src/plugin/p3dSplashWindow.cxx

@@ -50,6 +50,16 @@ set_wparams(const P3DWindowParams &wparams) {
   _wparams = wparams;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DSplashWindow::set_image_filename
+//       Access: Public, Virtual
+//  Description: Specifies the name of a JPEG image file that is
+//               displayed in the center of the splash window.
+////////////////////////////////////////////////////////////////////
+void P3DSplashWindow::
+set_image_filename(const string &image_filename) {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DSplashWindow::set_install_label
 //       Access: Public, Virtual

+ 1 - 0
direct/src/plugin/p3dSplashWindow.h

@@ -42,6 +42,7 @@ public:
   virtual void set_wparams(const P3DWindowParams &wparams);
   inline const P3DWindowParams &get_wparams() const;
 
+  virtual void set_image_filename(const string &image_filename);
   virtual void set_install_label(const string &install_label);
   virtual void set_install_progress(double install_progress);
 

+ 246 - 12
direct/src/plugin/p3dWinSplashWindow.cxx

@@ -16,6 +16,31 @@
 
 #ifdef _WIN32
 
+
+// Stuff to use libjpeg.
+extern "C" {
+#include <jpeglib.h>
+#include <jerror.h>
+}
+
+#include <setjmp.h>
+
+struct my_error_mgr {
+  struct jpeg_error_mgr pub;
+  jmp_buf setjmp_buffer;
+};
+
+typedef struct my_error_mgr *my_error_ptr;
+
+METHODDEF(void) my_error_exit (j_common_ptr cinfo) {
+  // cinfo->err really points to a my_error_mgr struct, so coerce pointer
+  my_error_ptr myerr = (my_error_ptr) cinfo->err;
+  // Return control to the setjmp point
+  longjmp(myerr->setjmp_buffer, 1);
+}
+
+
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DWinSplashWindow::Constructor
 //       Access: Public
@@ -28,12 +53,14 @@ P3DWinSplashWindow(P3DInstance *inst) :
   _thread = NULL;
   _thread_id = 0;
   _hwnd = NULL;
+  _bitmap = NULL;
   _progress_bar = NULL;
   _text_label = NULL;
   _thread_running = false;
   _got_install = false;
-  _install_progress = 0.0;
+  _image_filename_changed = false;
   _install_label_changed = false;
+  _install_progress = 0.0;
 
   INIT_LOCK(_install_lock);
 
@@ -52,6 +79,31 @@ P3DWinSplashWindow::
   DESTROY_LOCK(_install_lock);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinSplashWindow::set_image_filename
+//       Access: Public, Virtual
+//  Description: Specifies the name of a JPEG image file that is
+//               displayed in the center of the splash window.
+////////////////////////////////////////////////////////////////////
+void P3DWinSplashWindow::
+set_image_filename(const string &image_filename) {
+  ACQUIRE_LOCK(_install_lock);
+  if (_image_filename != image_filename) {
+    _image_filename = image_filename;
+    _image_filename_changed = true;
+  }
+  RELEASE_LOCK(_install_lock);
+
+  // Post a silly message to spin the message loop.
+  PostThreadMessage(_thread_id, WM_USER, 0, 0);
+
+  if (!_thread_running && _thread_continue) {
+    // The user must have closed the window.  Let's shut down the
+    // instance, too.
+    _inst->request_stop();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DWinSplashWindow::set_install_label
 //       Access: Public, Virtual
@@ -156,6 +208,10 @@ thread_run() {
     if (_got_install) {
       ACQUIRE_LOCK(_install_lock);
       double install_progress = _install_progress;
+      if (_image_filename_changed) {
+        update_image_filename(_image_filename);
+      }
+      _image_filename_changed = false;
       if (_install_label_changed && _progress_bar != NULL) {
         update_install_label(_install_label);
       }
@@ -213,7 +269,7 @@ make_window() {
   static bool registered_class = false;
   if (!registered_class) {
     ZeroMemory(&wc, sizeof(WNDCLASS));
-    wc.lpfnWndProc = window_proc;
+    wc.lpfnWndProc = st_window_proc;
     wc.hInstance = application;
     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
     wc.lpszClassName = "panda3d_splash";
@@ -241,7 +297,7 @@ make_window() {
   if (_wparams.get_window_type() == P3D_WT_embedded) {
     // Create an embedded window.
     DWORD window_style = 
-      WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+      WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
 
     HWND parent_hwnd = _wparams.get_parent_window()._hwnd;
 
@@ -270,9 +326,9 @@ make_window() {
       nout << "Could not create toplevel window!\n";
       return;
     }
-
-    ShowWindow(_hwnd, SW_SHOWNORMAL);
   }
+  SetWindowLongPtr(_hwnd, GWLP_USERDATA, (LONG_PTR)this);
+  ShowWindow(_hwnd, SW_SHOWNORMAL);
 }
 
 
@@ -308,18 +364,19 @@ make_progress_bar() {
   int bar_width = min((int)(width * 0.6), 400);
   int bar_height = min((int)(height * 0.1), 24);
   int bar_x = (width - bar_width) / 2;
-  int bar_y = (height - bar_height) / 2;
+  int bar_y = (height - bar_height * 2);
 
   _progress_bar = 
-      CreateWindowEx(0, PROGRESS_CLASS, "", window_style,
-                     bar_x, bar_y, bar_width, bar_height,
-                     _hwnd, NULL, application, 0);
+    CreateWindowEx(0, PROGRESS_CLASS, "", window_style,
+                   bar_x, bar_y, bar_width, bar_height,
+                   _hwnd, NULL, application, 0);
   SendMessage(_progress_bar, PBM_SETPOS, (int)(install_progress * 100.0), 0);
   ShowWindow(_progress_bar, SW_SHOWNORMAL);
 
   update_install_label(install_label);
 }
 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DWinSplashWindow::update_install_label
 //       Access: Private
@@ -361,7 +418,7 @@ update_install_label(const string &install_label) {
   int height = rect.bottom - rect.top;
 
   int bar_height = min((int)(height * 0.1), 24);
-  int bar_y = (height - bar_height) / 2;
+  int bar_y = (height - bar_height * 2);
 
   int text_width = text_size.cx;
   int text_height = text_size.cy;
@@ -374,6 +431,107 @@ update_install_label(const string &install_label) {
   ShowWindow(_text_label, SW_SHOWNORMAL);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinSplashWindow::update_image_filename
+//       Access: Private
+//  Description: Loads the splash image, converts to to BITMAP form,
+//               and stores it in _bitmap.  Runs only in the
+//               sub-thread.
+////////////////////////////////////////////////////////////////////
+void P3DWinSplashWindow::
+update_image_filename(const string &image_filename) {
+  // Clear the old image.
+  if (_bitmap != NULL) {
+    DeleteObject(_bitmap);
+    _bitmap = NULL;
+  }
+
+  // Since we'll be displaying a new image, we need to refresh the
+  // window.
+  InvalidateRect(_hwnd, NULL, TRUE);
+
+  FILE *fp = fopen(image_filename.c_str(), "rb");
+  if (fp == NULL) {
+    nout << "Couldn't open splash file image: " << image_filename << "\n"
+         << flush;
+    return;
+  }
+
+  // We set up the normal JPEG error routines, then override error_exit.
+  struct jpeg_decompress_struct cinfo;
+
+  struct my_error_mgr jerr;
+  cinfo.err = jpeg_std_error(&jerr.pub);
+  jerr.pub.error_exit = my_error_exit;
+  
+  // Establish the setjmp return context for my_error_exit to use
+  if (setjmp(jerr.setjmp_buffer)) {
+    // If we get here, the JPEG code has signaled an error.
+    nout << "JPEG error decoding " << image_filename << "\n"
+         << flush;
+
+    // We need to clean up the JPEG object, close the input file, and return.
+    jpeg_destroy_decompress(&cinfo);
+    fclose(fp);
+    return;
+  }
+
+  /* Now we can initialize the JPEG decompression object. */
+  jpeg_create_decompress(&cinfo);
+  jpeg_stdio_src(&cinfo, fp);
+
+  jpeg_read_header(&cinfo, true);
+
+  cinfo.scale_num = 1;
+  cinfo.scale_denom = 1;
+
+  jpeg_start_decompress(&cinfo);
+
+  _bitmap_width = cinfo.output_width;
+  _bitmap_height = cinfo.output_height;
+
+  int row_stride = _bitmap_width * cinfo.output_components;
+  // We have to pad row_stride out to DWORD alignment.
+  row_stride = 4 * ((row_stride + 3) / 4);
+
+  size_t buffer_size = _bitmap_height * row_stride;
+  JSAMPLE *buffer = new JSAMPLE[buffer_size];
+  JSAMPLE *buffer_end = buffer + buffer_size;
+
+  JSAMPLE *rowptr = buffer;
+  while (cinfo.output_scanline < cinfo.output_height) {
+    assert(rowptr + row_stride <= buffer_end);
+    jpeg_read_scanlines(&cinfo, &rowptr, 1);
+    rowptr += row_stride;
+  }
+
+  jpeg_finish_decompress(&cinfo);
+
+  // Now load the image.
+  BITMAPINFOHEADER bmih;
+  bmih.biSize = sizeof(bmih);
+  bmih.biWidth = _bitmap_width;
+  bmih.biHeight = -_bitmap_height;
+  bmih.biPlanes = 1;
+  bmih.biBitCount = 8 * cinfo.output_components;
+  bmih.biCompression = BI_RGB;
+  bmih.biSizeImage = 0;
+  bmih.biXPelsPerMeter = 0;
+  bmih.biYPelsPerMeter = 0;
+  bmih.biClrUsed = 0;
+  bmih.biClrImportant = 0;
+
+  BITMAPINFO bmi;
+  memcpy(&bmi, &bmih, sizeof(bmih));
+
+  HDC dc = GetDC(_hwnd);
+  _bitmap = CreateDIBitmap(dc, &bmih, CBM_INIT, buffer, &bmi, 0);
+  ReleaseDC(_hwnd, dc);
+
+  nout << "Loaded splash file image: " << image_filename << "\n"
+       << flush;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DWinSplashWindow::close_window
 //       Access: Private
@@ -381,16 +539,21 @@ update_install_label(const string &install_label) {
 ////////////////////////////////////////////////////////////////////
 void P3DWinSplashWindow::
 close_window() {
-  if (_hwnd) {
+  if (_hwnd != NULL) {
     ShowWindow(_hwnd, SW_HIDE);
     CloseWindow(_hwnd);
     _hwnd = NULL;
   }
+
+  if (_bitmap != NULL) {
+    DeleteObject(_bitmap);
+    _bitmap = NULL;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DWinSplashWindow::window_proc
-//       Access: Private, Static
+//       Access: Private
 //  Description: The windows event-processing handler.
 ////////////////////////////////////////////////////////////////////
 LONG P3DWinSplashWindow::
@@ -400,6 +563,62 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
     PostQuitMessage(0);
     break;
 
+  case WM_SIZE:
+    InvalidateRect(hwnd, NULL, TRUE);
+    break;
+
+  case WM_PAINT:
+    nout << "WM_PAINT, _bitmap = " << _bitmap << "\n";
+    {
+      PAINTSTRUCT ps;
+      HDC dc = BeginPaint(hwnd, &ps);
+      if (_bitmap != NULL) {
+        // Paint the background splash image.
+        HDC mem_dc = CreateCompatibleDC(dc);
+        SelectObject(mem_dc, _bitmap);
+        
+        // Determine the relative size of bitmap and window.
+        RECT rect;
+        GetClientRect(hwnd, &rect);
+        int win_width = rect.right - rect.left;
+        int win_height = rect.bottom - rect.top;
+        int bm_width = _bitmap_width;
+        int bm_height = _bitmap_height;
+        
+        int win_cx = win_width / 2;
+        int win_cy = win_height / 2;
+        
+        if (bm_width <= win_width && bm_height <= win_height) {
+          // The bitmap fits within the window; center it.
+          
+          // This is the top-left corner of the bitmap in window coordinates.
+          int p_x = win_cx - bm_width / 2;
+          int p_y = win_cy - bm_height / 2;
+          
+          BitBlt(dc, p_x, p_y, bm_width, bm_height,
+                 mem_dc, 0, 0, SRCCOPY);
+          
+        } else {
+          // The bitmap is larger than the window; scale it down.
+          double x_scale = (double)win_width / (double)bm_width;
+          double y_scale = (double)win_height / (double)bm_height;
+          double scale = min(x_scale, y_scale);
+          int sc_width = (int)(bm_width * scale);
+          int sc_height = (int)(bm_height * scale);
+          
+          int p_x = win_cx - sc_width / 2;
+          int p_y = win_cy - sc_height / 2;
+          StretchBlt(dc, p_x, p_y, sc_width, sc_height,
+                     mem_dc, 0, 0, bm_width, bm_height, SRCCOPY);
+        }
+        
+        SelectObject(mem_dc, NULL);
+        DeleteDC(mem_dc);
+      }
+      EndPaint(hwnd, &ps);
+    }
+    break;
+
   case WM_DRAWITEM:
     // Draw a text label placed within the window.
     {
@@ -422,5 +641,20 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
   return DefWindowProc(hwnd, msg, wparam, lparam);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinSplashWindow::st_window_proc
+//       Access: Private, Static
+//  Description: The windows event-processing handler, static version.
+////////////////////////////////////////////////////////////////////
+LONG P3DWinSplashWindow::
+st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+  LONG_PTR self = GetWindowLongPtr(hwnd, GWLP_USERDATA);
+  if (self == NULL) {
+    // We haven't assigned the pointer yet.
+    return DefWindowProc(hwnd, msg, wparam, lparam);
+  }
+
+  return ((P3DWinSplashWindow *)self)->window_proc(hwnd, msg, wparam, lparam);
+}
 
 #endif  // _WIN32

+ 8 - 1
direct/src/plugin/p3dWinSplashWindow.h

@@ -34,6 +34,7 @@ public:
   P3DWinSplashWindow(P3DInstance *inst);
   virtual ~P3DWinSplashWindow();
 
+  virtual void set_image_filename(const string &image_filename);
   virtual void set_install_label(const string &install_label);
   virtual void set_install_progress(double install_progress);
 
@@ -49,12 +50,16 @@ private:
   void make_window();
   void make_progress_bar();
   void update_install_label(const string &install_label);
+  void update_image_filename(const string &image_filename);
   void close_window();
 
-  static LONG WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+  LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+  static LONG WINAPI st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
 
 private:
   bool _got_install;
+  bool _image_filename_changed;
+  string _image_filename;
   bool _install_label_changed;
   string _install_label;
   double _install_progress;
@@ -67,6 +72,8 @@ private:
   HANDLE _thread;
   DWORD _thread_id;
   HWND _hwnd;
+  HBITMAP _bitmap;
+  int _bitmap_width, _bitmap_height;
   HWND _progress_bar;
   HWND _text_label;
 };