From f38724aa9230b7985266b00fd0dfd322f3947dae Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 30 Jun 2009 19:18:22 +0000 Subject: [PATCH] splash window --- direct/src/plugin/p3dFileDownload.cxx | 2 +- direct/src/plugin/p3dFileParams.cxx | 18 +++ direct/src/plugin/p3dFileParams.h | 1 + direct/src/plugin/p3dInstance.cxx | 85 ++++++++++++-- direct/src/plugin/p3dInstance.h | 13 +++ direct/src/plugin/p3dPackage.cxx | 1 - direct/src/plugin/p3dSplashWindow.cxx | 139 ++++++++++++++++++++++- direct/src/plugin/p3dSplashWindow.h | 10 +- direct/src/plugin/p3dWinSplashWindow.cxx | 103 +++-------------- direct/src/plugin/p3dWinSplashWindow.h | 7 +- 10 files changed, 276 insertions(+), 103 deletions(-) diff --git a/direct/src/plugin/p3dFileDownload.cxx b/direct/src/plugin/p3dFileDownload.cxx index e9c7801c4d..4c7e881d19 100755 --- a/direct/src/plugin/p3dFileDownload.cxx +++ b/direct/src/plugin/p3dFileDownload.cxx @@ -77,7 +77,7 @@ receive_data(const unsigned char *this_data, size_t this_data_size) { } //////////////////////////////////////////////////////////////////// -// Function: P3DDownload::download_finished +// Function: P3DFileDownload::download_finished // Access: Protected, Virtual // Description: Intended to be overloaded to generate a callback // when the download finishes, either successfully or diff --git a/direct/src/plugin/p3dFileParams.cxx b/direct/src/plugin/p3dFileParams.cxx index b41e2f39cb..df1cb1ed48 100644 --- a/direct/src/plugin/p3dFileParams.cxx +++ b/direct/src/plugin/p3dFileParams.cxx @@ -76,6 +76,24 @@ lookup_token(const string &keyword) const { return string(); } +//////////////////////////////////////////////////////////////////// +// Function: P3DFileParams::has_token +// Access: Public +// Description: Returns true if the named token appears in the list, +// false otherwise. +//////////////////////////////////////////////////////////////////// +bool P3DFileParams:: +has_token(const string &keyword) const { + Tokens::const_iterator ti; + for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { + if ((*ti)._keyword == keyword) { + return true; + } + } + + return false; +} + //////////////////////////////////////////////////////////////////// // Function: P3DFileParams::make_xml // Access: Public diff --git a/direct/src/plugin/p3dFileParams.h b/direct/src/plugin/p3dFileParams.h index 835e077cce..19fd585296 100644 --- a/direct/src/plugin/p3dFileParams.h +++ b/direct/src/plugin/p3dFileParams.h @@ -35,6 +35,7 @@ public: inline const string &get_p3d_filename() const; string lookup_token(const string &keyword) const; + bool has_token(const string &keyword) const; TiXmlElement *make_xml(); diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index 217beefccc..4c10eef8fd 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -113,16 +113,9 @@ set_fparams(const P3DFileParams &fparams) { // 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"); + make_splash_window(); } } - - /* - string splash_image_url = _fparams.lookup_token("splash_img"); - if (!splash_image_url.is_empty()) { - } - */ } //////////////////////////////////////////////////////////////////// @@ -140,8 +133,7 @@ set_wparams(const P3DWindowParams &wparams) { // Update or create the splash window. 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"); + make_splash_window(); } else { _splash_window->set_wparams(_wparams); } @@ -427,6 +419,48 @@ make_xml() { return xinstance; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::make_splash_window +// Access: Private +// Description: Creates the splash window to be displayed at startup. +// This method is called as soon as we have received +// both _fparams and _wparams. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +make_splash_window() { + assert(_splash_window == NULL); + + _splash_window = new SplashWindowType(this); + + string splash_image_url = _fparams.lookup_token("splash_img"); + if (!_fparams.has_token("splash_img")) { + // No specific splash image is specified; get the default splash + // image. + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + splash_image_url = inst_mgr->get_download_url(); + splash_image_url += "coreapi/splash.jpg"; + } + + if (splash_image_url.empty()) { + // No splash image. Never mind. + return; + } + + // Make a temporary file to receive the splash image. + char *name = tempnam(NULL, "p3d_"); + string filename = name; + free(name); + + nout << "Downloading splash image into " << filename << "\n"; + + // Start downloading the requested splash image. + SplashDownload *download = new SplashDownload(this); + download->set_url(splash_image_url); + download->set_filename(filename); + + start_download(download); +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::install_progress // Access: Private @@ -439,3 +473,34 @@ install_progress(P3DPackage *package, double progress) { _splash_window->set_install_progress(progress); } } + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::SplashDownload::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +P3DInstance::SplashDownload:: +SplashDownload(P3DInstance *inst) : + _inst(inst) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::SplashDownload::download_finished +// Access: Protected, Virtual +// Description: Intended to be overloaded to generate a callback +// when the download finishes, either successfully or +// otherwise. The bool parameter is true if the +// download was successful. +//////////////////////////////////////////////////////////////////// +void P3DInstance::SplashDownload:: +download_finished(bool success) { + P3DFileDownload::download_finished(success); + if (success) { + // We've successfully downloaded the splash image. Put it + // onscreen if our splash window still exists. + if (_inst->_splash_window != NULL) { + _inst->_splash_window->set_image_filename(get_filename(), true); + } + } +} diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index 710a688fce..6493494e87 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -74,6 +74,18 @@ public: TiXmlElement *make_xml(); private: + class SplashDownload : public P3DFileDownload { + public: + SplashDownload(P3DInstance *inst); + + protected: + virtual void download_finished(bool success); + + private: + P3DInstance *_inst; + }; + + void make_splash_window(); void install_progress(P3DPackage *package, double progress); P3D_request_ready_func *_func; @@ -105,6 +117,7 @@ private: static int _next_instance_id; friend class P3DSession; + friend class SplashDownload; }; #include "p3dInstance.I" diff --git a/direct/src/plugin/p3dPackage.cxx b/direct/src/plugin/p3dPackage.cxx index ba9f0d82d3..722c08deb8 100755 --- a/direct/src/plugin/p3dPackage.cxx +++ b/direct/src/plugin/p3dPackage.cxx @@ -22,7 +22,6 @@ #include #include -//#include // The relative breakdown of the full install process. Each phase is // worth this fraction of the total movement of the progress bar. diff --git a/direct/src/plugin/p3dSplashWindow.cxx b/direct/src/plugin/p3dSplashWindow.cxx index 9d3834f880..cf31373ebf 100755 --- a/direct/src/plugin/p3dSplashWindow.cxx +++ b/direct/src/plugin/p3dSplashWindow.cxx @@ -14,6 +14,31 @@ #include "p3dSplashWindow.h" + +// 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: P3DSplashWindow::Constructor // Access: Public @@ -54,10 +79,16 @@ set_wparams(const P3DWindowParams &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. +// displayed in the center of the splash window. If +// image_filename_temp is true, the file is immediately +// deleted after it has been read. //////////////////////////////////////////////////////////////////// void P3DSplashWindow:: -set_image_filename(const string &image_filename) { +set_image_filename(const string &image_filename, + bool image_filename_temp) { + if (image_filename_temp) { + unlink(image_filename.c_str()); + } } //////////////////////////////////////////////////////////////////// @@ -79,3 +110,107 @@ void P3DSplashWindow:: set_install_progress(double install_progress) { } + +//////////////////////////////////////////////////////////////////// +// Function: P3DSplashWindow::read_image +// Access: Protected +// Description: Reads the image filename and sets image parameters +// height, width, num_channels, row_stride, and data. +// Returns true on success, false on failure. If +// image_filename_temp is true, the file will be deleted +// after reading. +//////////////////////////////////////////////////////////////////// +bool P3DSplashWindow:: +read_image(const string &image_filename, bool image_filename_temp, + int &height, int &width, int &num_channels, int &row_stride, + string &data) { + height = 0; + width = 0; + num_channels = 0; + row_stride = 0; + data.clear(); + + // We currently only support JPEG images. Maybe that's all we'll + // ever support. + FILE *fp = fopen(image_filename.c_str(), "rb"); + if (fp == NULL) { + nout << "Couldn't open splash file image: " << image_filename << "\n" + << flush; + if (image_filename_temp) { + unlink(image_filename.c_str()); + } + return false; + } + + // 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; + + JSAMPLE *buffer = NULL; + + // 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); + + if (buffer != NULL) { + delete[] buffer; + } + + if (image_filename_temp) { + unlink(image_filename.c_str()); + } + return false; + } + + /* 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); + + width = cinfo.output_width; + height = cinfo.output_height; + num_channels = cinfo.output_components; + + row_stride = width * num_channels; + + // We'll pad row_stride out to word alignment. Windows requires this. + row_stride = 4 * ((row_stride + 3) / 4); + + size_t buffer_size = height * row_stride; + 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); + + fclose(fp); + if (image_filename_temp) { + unlink(image_filename.c_str()); + } + + data.append((const char *)buffer, buffer_size); + delete[] buffer; + + return true; +} diff --git a/direct/src/plugin/p3dSplashWindow.h b/direct/src/plugin/p3dSplashWindow.h index 8a2d49d8fe..a879b8394c 100755 --- a/direct/src/plugin/p3dSplashWindow.h +++ b/direct/src/plugin/p3dSplashWindow.h @@ -42,10 +42,18 @@ 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_image_filename(const string &image_filename, + bool image_filename_temp); virtual void set_install_label(const string &install_label); virtual void set_install_progress(double install_progress); + void setup_splash_image(); + +protected: + bool read_image(const string &image_filename, bool image_filename_temp, + int &height, int &width, int &num_channels, int &row_stride, + string &data); + protected: P3DInstance *_inst; P3DFileParams _fparams; diff --git a/direct/src/plugin/p3dWinSplashWindow.cxx b/direct/src/plugin/p3dWinSplashWindow.cxx index 817216f865..65368c796d 100755 --- a/direct/src/plugin/p3dWinSplashWindow.cxx +++ b/direct/src/plugin/p3dWinSplashWindow.cxx @@ -16,31 +16,6 @@ #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 @@ -59,6 +34,7 @@ P3DWinSplashWindow(P3DInstance *inst) : _thread_running = false; _got_install = false; _image_filename_changed = false; + _image_filename_temp = false; _install_label_changed = false; _install_progress = 0.0; @@ -82,14 +58,17 @@ P3DWinSplashWindow:: //////////////////////////////////////////////////////////////////// // 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. +// displayed in the center of the splash window. If +// image_filename_temp is true, the file is immediately +// deleted after it has been read. //////////////////////////////////////////////////////////////////// void P3DWinSplashWindow:: -set_image_filename(const string &image_filename) { +set_image_filename(const string &image_filename, + bool image_filename_temp) { ACQUIRE_LOCK(_install_lock); if (_image_filename != image_filename) { _image_filename = image_filename; + _image_filename_temp = image_filename_temp; _image_filename_changed = true; } RELEASE_LOCK(_install_lock); @@ -209,7 +188,7 @@ thread_run() { ACQUIRE_LOCK(_install_lock); double install_progress = _install_progress; if (_image_filename_changed) { - update_image_filename(_image_filename); + update_image_filename(_image_filename, _image_filename_temp); } _image_filename_changed = false; if (_install_label_changed && _progress_bar != NULL) { @@ -439,7 +418,7 @@ update_install_label(const string &install_label) { // sub-thread. //////////////////////////////////////////////////////////////////// void P3DWinSplashWindow:: -update_image_filename(const string &image_filename) { +update_image_filename(const string &image_filename, bool image_filename_temp) { // Clear the old image. if (_bitmap != NULL) { DeleteObject(_bitmap); @@ -450,70 +429,22 @@ update_image_filename(const string &image_filename) { // 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; + // Go read the image. + string data; + int num_channels, row_stride; + if (!read_image(image_filename, image_filename_temp, + _bitmap_height, _bitmap_width, num_channels, row_stride, + data)) { 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.biBitCount = 8 * num_channels; bmih.biCompression = BI_RGB; bmih.biSizeImage = 0; bmih.biXPelsPerMeter = 0; @@ -525,7 +456,7 @@ update_image_filename(const string &image_filename) { memcpy(&bmi, &bmih, sizeof(bmih)); HDC dc = GetDC(_hwnd); - _bitmap = CreateDIBitmap(dc, &bmih, CBM_INIT, buffer, &bmi, 0); + _bitmap = CreateDIBitmap(dc, &bmih, CBM_INIT, data.data(), &bmi, 0); ReleaseDC(_hwnd, dc); nout << "Loaded splash file image: " << image_filename << "\n" diff --git a/direct/src/plugin/p3dWinSplashWindow.h b/direct/src/plugin/p3dWinSplashWindow.h index 4f18873640..2692d80a36 100755 --- a/direct/src/plugin/p3dWinSplashWindow.h +++ b/direct/src/plugin/p3dWinSplashWindow.h @@ -34,7 +34,8 @@ public: P3DWinSplashWindow(P3DInstance *inst); virtual ~P3DWinSplashWindow(); - virtual void set_image_filename(const string &image_filename); + virtual void set_image_filename(const string &image_filename, + bool image_filename_temp); virtual void set_install_label(const string &install_label); virtual void set_install_progress(double install_progress); @@ -50,7 +51,8 @@ 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 update_image_filename(const string &image_filename, + bool image_filename_temp); void close_window(); LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); @@ -60,6 +62,7 @@ private: bool _got_install; bool _image_filename_changed; string _image_filename; + bool _image_filename_temp; bool _install_label_changed; string _install_label; double _install_progress;