From 5fea6fffd7e5432e810bab48c3f61c6e4315c516 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 25 Jun 2009 01:37:26 +0000 Subject: [PATCH] jpeg splash images --- direct/src/plugin/Sources.pp | 2 +- direct/src/plugin/p3dInstance.cxx | 23 +- direct/src/plugin/p3dSplashWindow.cxx | 10 + direct/src/plugin/p3dSplashWindow.h | 1 + direct/src/plugin/p3dWinSplashWindow.cxx | 258 +++++++++++++++++++++-- direct/src/plugin/p3dWinSplashWindow.h | 9 +- 6 files changed, 282 insertions(+), 21 deletions(-) diff --git a/direct/src/plugin/Sources.pp b/direct/src/plugin/Sources.pp index 9b22815a14..b927328f67 100644 --- a/direct/src/plugin/Sources.pp +++ b/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 diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index 45f365aa21..217beefccc 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/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); } diff --git a/direct/src/plugin/p3dSplashWindow.cxx b/direct/src/plugin/p3dSplashWindow.cxx index 9049f9efed..9d3834f880 100755 --- a/direct/src/plugin/p3dSplashWindow.cxx +++ b/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 diff --git a/direct/src/plugin/p3dSplashWindow.h b/direct/src/plugin/p3dSplashWindow.h index cec6122367..8a2d49d8fe 100755 --- a/direct/src/plugin/p3dSplashWindow.h +++ b/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); diff --git a/direct/src/plugin/p3dWinSplashWindow.cxx b/direct/src/plugin/p3dWinSplashWindow.cxx index c4af338912..202b7d6e57 100755 --- a/direct/src/plugin/p3dWinSplashWindow.cxx +++ b/direct/src/plugin/p3dWinSplashWindow.cxx @@ -16,6 +16,31 @@ #ifdef _WIN32 + +// Stuff to use libjpeg. +extern "C" { +#include +#include +} + +#include + +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 diff --git a/direct/src/plugin/p3dWinSplashWindow.h b/direct/src/plugin/p3dWinSplashWindow.h index b0aa08315b..4f18873640 100755 --- a/direct/src/plugin/p3dWinSplashWindow.h +++ b/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; };