diff --git a/direct/src/p3d/panda3d.pdef b/direct/src/p3d/panda3d.pdef index e1a5890e1b..b98bdf6d89 100755 --- a/direct/src/p3d/panda3d.pdef +++ b/direct/src/p3d/panda3d.pdef @@ -19,14 +19,39 @@ class coreapi(solo): # single .dll (or dylib, or whatever). file('p3d_plugin.dll') -class splash(solo): - # We also store the default splash image, as "solo". Well, it - # has to go somewhere. - splashFilename = Filename('maps/panda_splash.jpg') - if splashFilename.resolveFilename(getModelPath().getValue()): - file(splashFilename, newName = 'splash.jpg') - else: - print "Could not locate %s" % (splashFilename) +class images(package): + # The default startup images are stored as their own package. + names = ['download', 'play_click', 'play_ready', 'play_rollover', + 'auth_click', 'auth_ready', 'auth_rollover'] + configDict = {} + for name in names: + # Look for a png image first. + basename = '%s.png' % (name) + filename = Filename('plugin_images/%s' % (basename)) + found = filename.resolveFilename(getModelPath().getValue()) + if not found: + # Then try a jpeg image. + basename = '%s.jpg' % (name) + filename = Filename('plugin_images/%s' % (basename)) + found = filename.resolveFilename(getModelPath().getValue()) + + if found: + # Add the image file to the package + file(filename, newName = basename, extract = True) + + # And set the config variable to reference it. + token = '%s_img' % (name) + configDict[token] = basename + else: + print "Could not locate %s" % (filename) + + # Also make a few special cases. We use the same default image + # for both download and launch. + download = configDict.get('download_img', None) + if download: + configDict['launch_img'] = download + + config(**configDict) class panda3d(package): # The core Panda3D package. Contains Python and most of the graphics diff --git a/direct/src/plugin/Sources.pp b/direct/src/plugin/Sources.pp index 6fa5a0a76d..142fad8009 100644 --- a/direct/src/plugin/Sources.pp +++ b/direct/src/plugin/Sources.pp @@ -3,8 +3,8 @@ #define BUILD_DIRECTORY $[and $[HAVE_P3D_PLUGIN],$[HAVE_TINYXML],$[HAVE_OPENSSL],$[HAVE_ZLIB]] #begin lib_target - #define BUILD_TARGET $[HAVE_JPEG] - #define USE_PACKAGES tinyxml openssl zlib jpeg x11 + #define BUILD_TARGET $[and $[HAVE_JPEG],$[HAVE_PNG]] + #define USE_PACKAGES tinyxml openssl zlib jpeg png x11 #define TARGET p3d_plugin #define LIB_PREFIX @@ -111,7 +111,7 @@ interrogatedb:c dconfig:c dtoolconfig:m \ express:c pandaexpress:m \ prc:c pstatclient:c pandabase:c linmath:c putil:c \ - pipeline:c event:c nativenet:c net:c panda:m + pipeline:c event:c nativenet:c net:c display:c panda:m #define SOURCES \ binaryXml.cxx binaryXml.h \ @@ -138,7 +138,7 @@ interrogatedb:c dconfig:c dtoolconfig:m \ express:c pandaexpress:m \ prc:c pstatclient:c pandabase:c linmath:c putil:c \ - pipeline:c event:c nativenet:c net:c panda:m + pipeline:c event:c nativenet:c net:c display:c panda:m #define SOURCES \ binaryXml.cxx binaryXml.h \ diff --git a/direct/src/plugin/p3dInstance.I b/direct/src/plugin/p3dInstance.I index a3e629fec2..9dbf9453c6 100644 --- a/direct/src/plugin/p3dInstance.I +++ b/direct/src/plugin/p3dInstance.I @@ -94,3 +94,38 @@ inline bool P3DInstance:: is_started() const { return (_session != NULL); } + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::ImageFile::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +inline P3DInstance::ImageFile:: +ImageFile() { + _use_standard_image = true; + _temp_filename = NULL; + _image_placement = P3DSplashWindow::IP_none; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::ImageFile::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +inline P3DInstance::ImageFile:: +~ImageFile() { + cleanup(); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::ImageFile::cleanup +// Access: Public +// Description: Removes the temporary file, if any. +//////////////////////////////////////////////////////////////////// +inline void P3DInstance::ImageFile:: +cleanup() { + if (_temp_filename != NULL) { + delete _temp_filename; + _temp_filename = NULL; + } +} diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index 01e10322cd..493e8f2317 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -45,6 +45,19 @@ typedef P3DX11SplashWindow SplashWindowType; typedef P3DSplashWindow SplashWindowType; #endif +// These are the various image files we might download for use in the +// splash window. This list must match the ImageType enum. +const char *P3DInstance::_image_type_names[P3DInstance::IT_num_image_types] = { + "download", + "ready", + "failed", + "launch", + "play_ready", + "play_rollover", + "play_click", + "none", // Not really used. +}; + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::Constructor // Access: Public @@ -62,8 +75,9 @@ P3DInstance(P3D_request_ready_func *func, _user_data = user_data; _request_pending = false; _temp_p3d_filename = NULL; - _splash_package = NULL; - _temp_splash_image = NULL; + _image_package = NULL; + _current_background_image = IT_none; + _current_button_image = IT_none; _got_fparams = false; _got_wparams = false; @@ -74,12 +88,13 @@ P3DInstance(P3D_request_ready_func *func, _instance_id = inst_mgr->get_unique_id(); _hidden = false; _allow_python_dev = false; + _auto_start = false; _session = NULL; _panda3d = NULL; _splash_window = NULL; _instance_window_opened = false; _stuff_to_download = false; - + INIT_LOCK(_request_lock); _requested_stop = false; @@ -124,9 +139,9 @@ P3DInstance:: (*pi)->remove_instance(this); } _packages.clear(); - if (_splash_package != NULL) { - _splash_package->remove_instance(this); - _splash_package = NULL; + if (_image_package != NULL) { + _image_package->remove_instance(this); + _image_package = NULL; } if (_splash_window != NULL) { @@ -139,11 +154,6 @@ P3DInstance:: _temp_p3d_filename = NULL; } - if (_temp_splash_image != NULL) { - delete _temp_splash_image; - _temp_splash_image = NULL; - } - #ifdef __APPLE__ if (_frame_timer != NULL) { CFRunLoopTimerInvalidate(_frame_timer); @@ -221,7 +231,6 @@ set_p3d_url(const string &p3d_url) { //////////////////////////////////////////////////////////////////// void P3DInstance:: set_p3d_filename(const string &p3d_filename) { - _got_fparams = true; _fparams.set_p3d_filename(p3d_filename); _panda_script_object->set_float_property("instanceDownloadProgress", 1.0); @@ -238,6 +247,9 @@ set_p3d_filename(const string &p3d_filename) { sstream.seekg(0); TiXmlDocument doc; sstream >> doc; + + // This also starts required packages downloading. When all + // packages have been installed, we will start the instance. scan_app_desc_file(&doc); } @@ -248,13 +260,23 @@ set_p3d_filename(const string &p3d_filename) { strm << inst_mgr->get_unique_id(); _session_key = strm.str(); + // Until we've done all of the above processing, we haven't fully + // committed to having fparams. (Setting this flag down here + // instead of up there avoids starting the instance in + // scan_app_desc_file(), before we've had a chance to finish + // processing this method.) + _got_fparams = true; + // Generate a special notification: onpluginload, indicating the // plugin has read its parameters and is ready to be queried (even // if Python has not yet started). send_notify("onpluginload"); - // Now we're ready to start. - inst_mgr->start_instance(this); + // Now that we're all set up, start the instance if we're fully + // downloaded. + if (get_packages_ready() && _got_wparams) { + ready_to_start(); + } } //////////////////////////////////////////////////////////////////// @@ -331,6 +353,10 @@ set_wparams(const P3DWindowParams &wparams) { _session->send_command(doc); } + + if (get_packages_ready() && _got_fparams) { + ready_to_start(); + } } //////////////////////////////////////////////////////////////////// @@ -607,14 +633,14 @@ handle_event(P3D_event_data event) { // convert the mouse coordinates successfully via // GlobalToLocal(). GrafPtr out_port = _wparams.get_parent_window()._port; - GrafPtr portSave = NULL; - Boolean portChanged = QDSwapPort(out_port, &portSave); + GrafPtr port_save = NULL; + Boolean port_changed = QDSwapPort(out_port, &port_save); Point pt = er->where; GlobalToLocal(&pt); - if (portChanged) { - QDSwapPort(portSave, NULL); + if (port_changed) { + QDSwapPort(port_save, NULL); } SubprocessWindowBuffer::Event swb_event; @@ -698,12 +724,16 @@ add_package(P3DPackage *package) { return; } - _packages.push_back(package); - package->add_instance(this); - if (package->get_package_name() == "panda3d") { _panda3d = package; } + + _packages.push_back(package); + + // This call must be at the end of this method, because it might + // ultimately start the application before it returns (if this was + // the last required package). + package->add_instance(this); } //////////////////////////////////////////////////////////////////// @@ -864,6 +894,22 @@ make_xml() { return xinstance; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::splash_button_clicked +// Access: Public +// Description: Called by the P3DSplashWindow code when the user +// clicks the play button visible on the splash window. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +splash_button_clicked() { + // If we haven't launched yet, launch now. + if (_session == NULL) { + set_background_image(IT_launch); + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + inst_mgr->start_instance(this); + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::scan_app_desc_file // Access: Private @@ -872,6 +918,7 @@ make_xml() { //////////////////////////////////////////////////////////////////// void P3DInstance:: scan_app_desc_file(TiXmlDocument *doc) { + cerr << "scan_app_desc_file\n"; P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); TiXmlElement *xpackage = doc->FirstChildElement("package"); @@ -895,8 +942,23 @@ scan_app_desc_file(TiXmlDocument *doc) { if (xconfig->QueryIntAttribute("allow_python_dev", &allow_python_dev) == TIXML_SUCCESS) { _allow_python_dev = (allow_python_dev != 0); } + + int auto_start = 0; + if (xconfig->QueryIntAttribute("auto_start", &auto_start) == TIXML_SUCCESS) { + _auto_start = (auto_start != 0); + } } + // auto_start is true if it is set in the application itself, or in + // the web tokens. + if (_fparams.lookup_token_int("auto_start") != 0) { + _auto_start = true; + } + nout << "_auto_start = " << _auto_start << "\n"; + + // But auto_start will be set false if the p3d file has not been + // signed by an approved signature. TODO. + if (_hidden && _got_wparams) { _wparams.set_window_type(P3D_WT_hidden); } @@ -1069,9 +1131,8 @@ handle_notify_request(const string &message) { _splash_window = NULL; } - if (_temp_splash_image != NULL) { - delete _temp_splash_image; - _temp_splash_image = NULL; + for (int i = 0; i < (int)IT_num_image_types; ++i) { + _image_files[i].cleanup(); } _panda_script_object->set_string_property("status", "open"); @@ -1206,11 +1267,13 @@ make_splash_window() { // We're hidden, and so is the splash window. return; } + /* temp removing: hack for debugging. if (_wparams.get_window_type() != P3D_WT_embedded && !_stuff_to_download) { // If it's a toplevel or fullscreen window, then we don't want a // splash window until we have stuff to download. return; } + */ _splash_window = new SplashWindowType(this); _splash_window->set_wparams(_wparams); @@ -1218,34 +1281,117 @@ make_splash_window() { P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (!_fparams.has_token("splash_img")) { - // No specific splash image is specified; get the default splash - // image. We do this via the P3DPackage interface, so we can - // use the cached version on disk if it's good. - P3DHost *host = inst_mgr->get_host(PANDA_PACKAGE_HOST_URL); - _splash_package = host->get_package("splash", ""); - _splash_package->add_instance(this); + // Direct the "download" image to the background slot on the splash + // window for now, while we perform the download. + set_background_image(IT_download); - } else { - // We have an explicit splash image specified, so just download it - // directly. This one won't be cached locally (though the browser - // might be free to cache it). - string splash_image_url = _fparams.lookup_token("splash_img"); - if (splash_image_url.empty()) { - // No splash image. Never mind. - return; + // Go get the required images. + for (int i = 0; i < (int)IT_none; ++i) { + string token_keyword = string(_image_type_names[i]) + "_img"; + if (!_fparams.has_token(token_keyword)) { + // No specific image for this type is specified; get the default + // image. We do this via the P3DPackage interface, so we can + // use the cached version on disk if it's good. + _image_files[i]._use_standard_image = true; + if (_image_package == NULL) { + P3DHost *host = inst_mgr->get_host(PANDA_PACKAGE_HOST_URL); + _image_package = host->get_package("images", ""); + _image_package->add_instance(this); + } + + } else { + // We have an explicit image specified for this slot, so just + // download it directly. This one won't be cached locally + // (though the browser might be free to cache it). + _image_files[i]._use_standard_image = false; + string image_url = _fparams.lookup_token(token_keyword); + if (image_url.empty()) { + // No splash image. Never mind. + return; + } + + // Make a temporary file to receive the splash image. + assert(_image_files[i]._temp_filename == NULL); + _image_files[i]._temp_filename = new P3DTemporaryFile(".jpg"); + + // Start downloading the requested image. + ImageDownload *download = new ImageDownload(this, i); + download->set_url(image_url); + download->set_filename(_image_files[i]._temp_filename->get_filename()); + + start_download(download); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::set_background_image +// Access: Private +// Description: Specifies the particular image that should be +// displayed as the background image in the splash +// window. Specify IT_none to take the background image +// away. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +set_background_image(ImageType image_type) { + if (image_type != _current_background_image) { + // Remove the previous image. + _image_files[_current_background_image]._image_placement = P3DSplashWindow::IP_none; + + // Install the new image. + _current_background_image = image_type; + if (_current_background_image != IT_none) { + _image_files[_current_background_image]._image_placement = P3DSplashWindow::IP_background; + } + + // Update the splash window. + if (_splash_window != NULL) { + _splash_window->set_image_filename(_image_files[_current_background_image]._filename, P3DSplashWindow::IP_background); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::set_button_image +// Access: Private +// Description: Specifies the particular image that should be +// displayed as the button image in the splash +// window. Specify IT_none to take the button image +// away. +// +// This actually defines a trilogy of button images: +// ready, rollover, click. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +set_button_image(ImageType image_type) { + if (image_type != _current_button_image) { + // Remove the previous image. + _image_files[_current_button_image]._image_placement = P3DSplashWindow::IP_none; + if (_current_button_image != IT_none) { + _image_files[_current_button_image + 1]._image_placement = P3DSplashWindow::IP_none; + _image_files[_current_button_image + 2]._image_placement = P3DSplashWindow::IP_none; + } + + // Install the new image. + _current_button_image = image_type; + if (_current_button_image != IT_none) { + _image_files[_current_button_image]._image_placement = P3DSplashWindow::IP_button_ready; + _image_files[_current_button_image + 1]._image_placement = P3DSplashWindow::IP_button_rollover; + _image_files[_current_button_image + 2]._image_placement = P3DSplashWindow::IP_button_click; + } + + // Update the splash window. + if (_splash_window != NULL) { + if (_current_button_image != IT_none) { + _splash_window->set_image_filename(_image_files[_current_button_image]._filename, P3DSplashWindow::IP_button_ready); + _splash_window->set_image_filename(_image_files[_current_button_image + 1]._filename, P3DSplashWindow::IP_button_rollover); + _splash_window->set_image_filename(_image_files[_current_button_image + 2]._filename, P3DSplashWindow::IP_button_click); + } else { + _splash_window->set_image_filename(string(), P3DSplashWindow::IP_button_ready); + _splash_window->set_image_filename(string(), P3DSplashWindow::IP_button_rollover); + _splash_window->set_image_filename(string(), P3DSplashWindow::IP_button_click); + } } - - // Make a temporary file to receive the splash image. - assert(_temp_splash_image == NULL); - _temp_splash_image = new P3DTemporaryFile(".jpg"); - - // Start downloading the requested splash image. - SplashDownload *download = new SplashDownload(this); - download->set_url(splash_image_url); - download->set_filename(_temp_splash_image->get_filename()); - - start_download(download); } } @@ -1258,13 +1404,10 @@ make_splash_window() { //////////////////////////////////////////////////////////////////// void P3DInstance:: report_package_info_ready(P3DPackage *package) { - if (package == _splash_package) { - // A special case: we just downloaded the splash image, via the - // package interface. - if (_splash_window != NULL) { - string filename = package->get_desc_file_pathname(); - _splash_window->set_image_filename(filename, false); - } + if (package == _image_package) { + // A special case: the image package gets immediately downloaded, + // without waiting for anything else. + package->activate_download(); return; } @@ -1360,11 +1503,37 @@ start_next_download() { _panda_script_object->set_string_property("status", "starting"); send_notify("ondownloadcomplete"); } - - // Notify the session also. - if (_session != NULL) { - _session->report_packages_done(this, true); + + // Take down the download progress bar. + if (_splash_window != NULL) { + _splash_window->set_install_progress(0.0); + _splash_window->set_install_label(""); } + + if (_got_wparams && _got_fparams) { + ready_to_start(); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::ready_to_start +// Access: Private +// Description: Called internally when we have got the wparams and +// fparams and we have downloaded all required packages. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +ready_to_start() { + if (_auto_start) { + set_background_image(IT_launch); + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + inst_mgr->start_instance(this); + + } else if (_splash_window != NULL) { + // We're fully downloaded, and waiting for the user to click play. + set_background_image(IT_ready); + set_button_image(IT_play_ready); + _splash_window->set_button_active(true); } } @@ -1440,6 +1609,41 @@ void P3DInstance:: report_package_done(P3DPackage *package, bool success) { nout << "Done downloading " << package->get_package_name() << ": success = " << success << "\n"; + + if (package == _image_package) { + // A special case: we just downloaded the image package, so get + // the image files out of it and point them to the splash window. + string package_dir = package->get_package_dir(); + const TiXmlElement *xconfig = package->get_xconfig(); + if (xconfig == NULL) { + nout << "No entry in image package\n"; + return; + } + for (int i = 0; i < (int)IT_none; ++i) { + if (_image_files[i]._use_standard_image) { + // This image indexes into the package. Go get the standard + // image filename. + string token = string(_image_type_names[i]) + "_img"; + const string *basename = xconfig->Attribute(token); + if (basename == NULL) { + nout << "No entry in image package for " << token << "\n"; + } else { + string image_filename = package_dir + "/" + *basename; + _image_files[i]._filename = image_filename; + + // If the image should be on the window now, and the window + // still exists, put it up. + if (_splash_window != NULL && + _image_files[i]._image_placement != P3DSplashWindow::IP_none) { + P3DSplashWindow::ImagePlacement image_placement = _image_files[i]._image_placement; + _splash_window->set_image_filename(image_filename, image_placement); + } + } + } + } + return; + } + if (success) { report_package_progress(package, 1.0); start_next_download(); @@ -1615,8 +1819,8 @@ paint_window() { } GrafPtr out_port = _wparams.get_parent_window()._port; - GrafPtr portSave = NULL; - Boolean portChanged = QDSwapPort(out_port, &portSave); + GrafPtr port_save = NULL; + Boolean port_changed = QDSwapPort(out_port, &port_save); // Make sure the clipping rectangle isn't in the way. Is there a // better way to eliminate the cliprect from consideration? @@ -1627,8 +1831,8 @@ paint_window() { GetPortBitMapForCopyBits(out_port), &src_rect, &ddrc_rect, srcCopy, 0); - if (portChanged) { - QDSwapPort(portSave, NULL); + if (port_changed) { + QDSwapPort(port_save, NULL); } DisposeGWorld(pGWorld); @@ -1677,33 +1881,39 @@ timer_callback(CFRunLoopTimerRef timer, void *info) { #endif // __APPLE__ //////////////////////////////////////////////////////////////////// -// Function: P3DInstance::SplashDownload::Constructor +// Function: P3DInstance::ImageDownload::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -P3DInstance::SplashDownload:: -SplashDownload(P3DInstance *inst) : - _inst(inst) +P3DInstance::ImageDownload:: +ImageDownload(P3DInstance *inst, int index) : + _inst(inst), + _index(index) { } //////////////////////////////////////////////////////////////////// -// Function: P3DInstance::SplashDownload::download_finished +// Function: P3DInstance::ImageDownload::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:: +void P3DInstance::ImageDownload:: download_finished(bool success) { P3DFileDownload::download_finished(success); if (success) { - // We've successfully downloaded the splash image (directly, not - // via the package interface). Put it onscreen if our splash - // window still exists. - if (_inst->_splash_window != NULL) { - _inst->_splash_window->set_image_filename(get_filename(), true); + // We've successfully downloaded the image (directly, not via the + // package interface). + _inst->_image_files[_index]._filename = get_filename(); + + // Put it onscreen if it's supposed to be onscreen now, and our + // splash window still exists. + if (_inst->_splash_window != NULL && + _inst->_image_files[_index]._image_placement != P3DSplashWindow::IP_none) { + P3DSplashWindow::ImagePlacement image_placement = _inst->_image_files[_index]._image_placement; + _inst->_splash_window->set_image_filename(get_filename(), image_placement); } } } diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index 1ee3fc5eea..f989dfd2c1 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -20,6 +20,8 @@ #include "p3dFileParams.h" #include "p3dWindowParams.h" #include "p3dReferenceCount.h" +#include "p3dSplashWindow.h" +#include "p3dTemporaryFile.h" #include "get_tinyxml.h" #ifdef __APPLE__ @@ -98,15 +100,17 @@ public: void request_refresh(); TiXmlElement *make_xml(); + void splash_button_clicked(); private: - class SplashDownload : public P3DFileDownload { + class ImageDownload : public P3DFileDownload { public: - SplashDownload(P3DInstance *inst); + ImageDownload(P3DInstance *inst, int index); protected: virtual void download_finished(bool success); private: P3DInstance *_inst; + int _index; }; class InstanceDownload : public P3DFileDownload { public: @@ -118,6 +122,20 @@ private: P3DInstance *_inst; }; + // The different kinds of image files we download for the splash + // window. + enum ImageType { + IT_download, + IT_ready, + IT_failed, + IT_launch, + IT_play_ready, + IT_play_rollover, + IT_play_click, + IT_none, // Must be the last value + IT_num_image_types, // Not a real value + }; + void scan_app_desc_file(TiXmlDocument *doc); void send_browser_script_object(); @@ -127,8 +145,11 @@ private: const string &property_name, P3D_object *value, bool needs_response, int unique_id); void make_splash_window(); + void set_background_image(ImageType image_type); + void set_button_image(ImageType image_type); void report_package_info_ready(P3DPackage *package); void start_next_download(); + void ready_to_start(); void report_instance_progress(double progress); void report_package_progress(P3DPackage *package, double progress); void report_package_done(P3DPackage *package, bool progress); @@ -148,8 +169,25 @@ private: P3DMainObject *_panda_script_object; P3DTemporaryFile *_temp_p3d_filename; - P3DPackage *_splash_package; - P3DTemporaryFile *_temp_splash_image; + + // For downloading the various images used by the splash window. + P3DPackage *_image_package; + static const char *_image_type_names[IT_num_image_types]; + + class ImageFile { + public: + inline ImageFile(); + inline ~ImageFile(); + inline void cleanup(); + + bool _use_standard_image; + P3DTemporaryFile *_temp_filename; + string _filename; + P3DSplashWindow::ImagePlacement _image_placement; + }; + ImageFile _image_files[IT_num_image_types]; + ImageType _current_background_image; + ImageType _current_button_image; bool _got_fparams; P3DFileParams _fparams; @@ -162,6 +200,7 @@ private: string _log_basename; bool _hidden; bool _allow_python_dev; + bool _auto_start; P3DSession *_session; @@ -220,7 +259,7 @@ private: BakedRequests _baked_requests; friend class P3DSession; - friend class SplashDownload; + friend class ImageDownload; friend class P3DWindowParams; friend class P3DPackage; }; diff --git a/direct/src/plugin/p3dOsxSplashWindow.I b/direct/src/plugin/p3dOsxSplashWindow.I index 75d0726e87..f183bb36ed 100644 --- a/direct/src/plugin/p3dOsxSplashWindow.I +++ b/direct/src/plugin/p3dOsxSplashWindow.I @@ -12,3 +12,28 @@ // //////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::OsxImageData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +inline P3DOsxSplashWindow::OsxImageData:: +OsxImageData() { + _raw_data = NULL; + _image = NULL; + _color_space = NULL; + _provider = NULL; + _data = NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::OsxImageData::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +inline P3DOsxSplashWindow::OsxImageData:: +~OsxImageData() { + dump_image(); +} + diff --git a/direct/src/plugin/p3dOsxSplashWindow.cxx b/direct/src/plugin/p3dOsxSplashWindow.cxx index d0167b0d25..a8dc10f809 100644 --- a/direct/src/plugin/p3dOsxSplashWindow.cxx +++ b/direct/src/plugin/p3dOsxSplashWindow.cxx @@ -27,10 +27,9 @@ P3DOsxSplashWindow:: P3DOsxSplashWindow(P3DInstance *inst) : P3DSplashWindow(inst) { - _image = NULL; - _image_data = NULL; _install_progress = 0; _got_wparams = false; + _mouse_active = false; _toplevel_window = NULL; } @@ -47,15 +46,6 @@ P3DOsxSplashWindow:: DisposeWindow(_toplevel_window); _toplevel_window = NULL; } - - if (_image != NULL) { - DisposeGWorld(_image); - } - - if (_image_data != NULL) { - delete[] _image_data; - _image_data = NULL; - } } //////////////////////////////////////////////////////////////////// @@ -83,8 +73,8 @@ set_wparams(const P3DWindowParams &wparams) { r.left = 10; } - r.right = r.left + _wparams.get_win_width(); - r.bottom = r.top + _wparams.get_win_height(); + r.right = r.left + _win_width; + r.bottom = r.top + _win_height; WindowAttributes attrib = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute; CreateNewWindow(kDocumentWindowClass, attrib, &r, &_toplevel_window); @@ -93,6 +83,10 @@ set_wparams(const P3DWindowParams &wparams) { EventTypeSpec list1[] = { { kEventClassWindow, kEventWindowDrawContent }, //{ kEventClassWindow, kEventWindowUpdate }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged }, }; EventHandlerUPP gEvtHandler = NewEventHandlerUPP(st_event_callback); @@ -113,67 +107,27 @@ set_wparams(const P3DWindowParams &wparams) { // Function: P3DOsxSplashWindow::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. If -// image_filename_temp is true, the file is immediately -// deleted after it has been read. +// displayed in the center of the splash window. //////////////////////////////////////////////////////////////////// void P3DOsxSplashWindow:: -set_image_filename(const string &image_filename, - bool image_filename_temp) { - int num_channels; - string data; - if (!read_image(image_filename, image_filename_temp, - _image_height, _image_width, num_channels, data)) { - return; - } +set_image_filename(const string &image_filename, ImagePlacement image_placement) { + switch (image_placement) { + case IP_background: + load_image(_background_image, image_filename); + break; - QDErr err; - Rect src_rect = { 0, 0, _image_height, _image_width }; + case IP_button_ready: + load_image(_button_ready_image, image_filename); + set_button_range(_button_ready_image); + break; - if (_image != NULL) { - DisposeGWorld(_image); - _image = NULL; - } - - if (_image_data != NULL) { - delete[] _image_data; - _image_data = NULL; - } - - // Now we need to copy from the RGB source image into the BGRA target image. - int row_stride = _image_width * num_channels; - int new_row_stride = _image_width * 4; - _image_data = new char[new_row_stride * _image_height]; - for (int yi = 0; yi < _image_height; ++yi) { - char *dest = _image_data + yi * new_row_stride; - const char *source = data.data() + yi * row_stride; - for (int xi = 0; xi < _image_width; ++xi) { - char r = source[0]; - char g = source[1]; - char b = source[2]; -#ifndef __BIG_ENDIAN__ - // Little-endian. - dest[0] = b; - dest[1] = g; - dest[2] = r; - dest[3] = 0xff; -#else // __BIG_ENDIAN__ - // Big-endian. - dest[0] = 0xff; - dest[1] = r; - dest[2] = g; - dest[3] = b; -#endif // __BIG_ENDIAN__ - source += 3; - dest += 4; - } - } - - err = NewGWorldFromPtr(&_image, k32BGRAPixelFormat, &src_rect, 0, 0, 0, - _image_data, new_row_stride); - if (err != noErr) { - nout << " error in NewGWorldFromPtr, called from set_image_filename()\n"; - return; + case IP_button_rollover: + load_image(_button_rollover_image, image_filename); + break; + + case IP_button_click: + load_image(_button_click_image, image_filename); + break; } refresh(); @@ -215,24 +169,58 @@ set_install_progress(double install_progress) { bool P3DOsxSplashWindow:: handle_event(P3D_event_data event) { EventRecord *er = event._event; - if (er->what == updateEvt) { - paint_window(); + + // Need to ensure we have the correct port set, in order to + // convert the mouse coordinates successfully via + // GlobalToLocal(). + GrafPtr out_port = _wparams.get_parent_window()._port; + GrafPtr port_save = NULL; + Boolean port_changed = QDSwapPort(out_port, &port_save); + + Point pt = er->where; + GlobalToLocal(&pt); + + if (port_changed) { + QDSwapPort(port_save, NULL); } + + switch (er->what) { + case updateEvt: + paint_window(); + break; + + case mouseDown: + set_mouse_data(_mouse_x, _mouse_y, true); + break; + + case mouseUp: + set_mouse_data(_mouse_x, _mouse_y, false); + break; + + case activateEvt: + _mouse_active = ((er->modifiers & 1) != 0); + break; + + default: + break; + } + + if (_mouse_active) { + set_mouse_data(pt.h, pt.v, _mouse_down); + } + return false; } //////////////////////////////////////////////////////////////////// // Function: P3DOsxSplashWindow::refresh -// Access: Private +// Access: Protected, Virtual // Description: Requests that the window will be repainted. //////////////////////////////////////////////////////////////////// void P3DOsxSplashWindow:: refresh() { if (_toplevel_window != NULL) { - int win_width = _wparams.get_win_width(); - int win_height = _wparams.get_win_height(); - - Rect r = { 0, 0, win_height, win_width }; + Rect r = { 0, 0, _win_height, _win_width }; InvalWindowRect(_toplevel_window, &r); } else { @@ -263,60 +251,34 @@ paint_window() { portChanged = QDSwapPort(out_port, &portSave); } - int win_width = _wparams.get_win_width(); - int win_height = _wparams.get_win_height(); - - Rect r = { 0, 0, win_height, win_width }; + Rect r = { 0, 0, _win_height, _win_width }; ClipRect(&r); EraseRect(&r); - if (_image != NULL) { - Rect src_rect = { 0, 0, _image_height, _image_width }; - Rect dest_rect; - - // Determine the relative size of image and window. - int win_cx = win_width / 2; - int win_cy = win_height / 2; - - if (_image_width <= win_width && _image_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 - _image_width / 2; - int p_y = win_cy - _image_height / 2; + paint_image(out_port, _background_image); - dest_rect.left = p_x; - dest_rect.top = p_y; - dest_rect.right = p_x + _image_width; - dest_rect.bottom = p_y + _image_height; - - } else { - // The bitmap is larger than the window; scale it down. - double x_scale = (double)win_width / (double)_image_width; - double y_scale = (double)win_height / (double)_image_height; - double scale = min(x_scale, y_scale); - int sc_width = (int)(_image_width * scale); - int sc_height = (int)(_image_height * scale); - - int p_x = win_cx - sc_width / 2; - int p_y = win_cy - sc_height / 2; - - dest_rect.left = p_x; - dest_rect.top = p_y; - dest_rect.right = p_x + sc_width; - dest_rect.bottom = p_y + sc_height; + switch (_bstate) { + case BS_hidden: + break; + case BS_ready: + paint_image(out_port, _button_ready_image); + break; + case BS_rollover: + if (!paint_image(out_port, _button_rollover_image)) { + paint_image(out_port, _button_ready_image); } - - CopyBits(GetPortBitMapForCopyBits(_image), - GetPortBitMapForCopyBits(out_port), - &src_rect, &dest_rect, srcCopy, 0); + break; + case BS_click: + if (!paint_image(out_port, _button_click_image)) { + paint_image(out_port, _button_ready_image); + } + break; } // Draw the progress bar. We don't draw this bar at all unless we // have nonzero progress. int bar_x, bar_y, bar_width, bar_height; - get_bar_placement(win_width, win_height, - bar_x, bar_y, bar_width, bar_height); + get_bar_placement(bar_x, bar_y, bar_width, bar_height); if (_install_progress != 0.0) { Rect rbar = { bar_y, bar_x, bar_y + bar_height, bar_x + bar_width }; @@ -351,7 +313,7 @@ paint_window() { int descent = font_info.descent * numer.v / denom.v; int text_width = TextWidth(_install_label.data(), 0, _install_label.size()); - int text_x = (win_width - text_width) / 2; + int text_x = (_win_width - text_width) / 2; int text_y = bar_y - descent - 8; Rect rtext = { text_y - ascent - 2, text_x - 2, @@ -370,6 +332,155 @@ paint_window() { } } +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::load_image +// Access: Private +// Description: Loads the named image file into an OsxImageData object. +//////////////////////////////////////////////////////////////////// +void P3DOsxSplashWindow:: +load_image(OsxImageData &image, const string &image_filename) { + image.dump_image(); + string string_data; + if (!read_image_data(image, string_data, image_filename)) { + return; + } + + // Now we need to copy from the RGB (or RGBA) source image into the + // BGRA target image. + int row_stride = image._width * image._num_channels; + int new_row_stride = image._width * 4; + image._raw_data = new char[new_row_stride * image._height]; + for (int yi = 0; yi < image._height; ++yi) { + char *dest = image._raw_data + yi * new_row_stride; + const char *source = string_data.data() + yi * row_stride; + if (image._num_channels == 3) { + // Source is RGB. + for (int xi = 0; xi < image._width; ++xi) { + char r = source[0]; + char g = source[1]; + char b = source[2]; +#ifndef __BIG_ENDIAN__ + // Little-endian. + dest[0] = b; + dest[1] = g; + dest[2] = r; + dest[3] = 0xff; +#else // __BIG_ENDIAN__ + // Big-endian. + dest[0] = 0xff; + dest[1] = r; + dest[2] = g; + dest[3] = b; +#endif // __BIG_ENDIAN__ + source += 3; + dest += 4; + } + } else if (image._num_channels == 4) { + // Source is RGBA. + for (int xi = 0; xi < image._width; ++xi) { + char r = source[0]; + char g = source[1]; + char b = source[2]; + char a = source[3]; +#ifndef __BIG_ENDIAN__ + // Little-endian. + dest[0] = b; + dest[1] = g; + dest[2] = r; + dest[3] = a; +#else // __BIG_ENDIAN__ + // Big-endian. + dest[0] = a; + dest[1] = r; + dest[2] = g; + dest[3] = b; +#endif // __BIG_ENDIAN__ + source += 4; + dest += 4; + } + } + } + + image._data = + CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)image._raw_data, + image._height * new_row_stride, kCFAllocatorNull); + image._provider = CGDataProviderCreateWithCFData(image._data); + image._color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + + image._image = + CGImageCreate(image._width, image._height, 8, 32, + new_row_stride, image._color_space, + kCGImageAlphaFirst | kCGBitmapByteOrder32Little, + image._provider, NULL, false, kCGRenderingIntentDefault); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::paint_image +// Access: Private +// Description: Draws the indicated image, centered within the +// window. Returns true on success, false if the image +// is not defined. +//////////////////////////////////////////////////////////////////// +bool P3DOsxSplashWindow:: +paint_image(GrafPtr out_port, const OsxImageData &image) { + if (image._image == NULL) { + return false; + } + + CGContextRef context; + QDErr err = QDBeginCGContext(out_port, &context); + if (err != noErr) { + nout << "Error: QDBeginCGContext\n"; + return false; + } + + // We have to rely on the clipping rectangle having been set up + // correctly in order to get the proper location to draw the image. + // This isn't completely right, because if the image is slightly + // offscreen, the top left of the clipping rectangle will no longer + // correspond to the top left of the original image. + CGRect rect = CGContextGetClipBoundingBox(context); + + // Determine the relative size of image and window. + int win_cx = _win_width / 2; + int win_cy = _win_height / 2; + + if (image._width <= _win_width && image._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 - image._width / 2; + int p_y = win_cy - image._height / 2; + + rect.origin.x += p_x; + rect.origin.y += p_y; + rect.size.width = image._width; + rect.size.height = image._height; + + } else { + // The bitmap is larger than the window; scale it down. + double x_scale = (double)_win_width / (double)image._width; + double y_scale = (double)_win_height / (double)image._height; + double scale = min(x_scale, y_scale); + int sc_width = (int)(image._width * scale); + int sc_height = (int)(image._height * scale); + + int p_x = win_cx - sc_width / 2; + int p_y = win_cy - sc_height / 2; + + rect.origin.x += p_x; + rect.origin.y += p_y; + rect.size.width = sc_width; + rect.size.height = sc_height; + } + + CGContextDrawImage(context, rect, image._image); + + QDEndCGContext(out_port, &context); + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: P3DOsxSplashWindow::st_event_callback // Access: Private, Static @@ -402,11 +513,75 @@ event_callback(EventHandlerCallRef my_handler, EventRef event) { case kEventWindowDrawContent: paint_window(); result = noErr; + }; + break; + + case kEventClassMouse: + switch (kind) { + case kEventMouseUp: + set_mouse_data(_mouse_x, _mouse_y, false); + break; + + case kEventMouseDown: + set_mouse_data(_mouse_x, _mouse_y, true); + break; + + case kEventMouseMoved: + case kEventMouseDragged: + { + Point point; + GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, + sizeof(Point), NULL, (void *)&point); + + GrafPtr port = _wparams.get_parent_window()._port; + if (_toplevel_window != NULL) { + port = GetWindowPort(_toplevel_window); + } + GrafPtr port_save = NULL; + Boolean port_changed = QDSwapPort(port, &port_save); + GlobalToLocal(&point); + if (port_changed) { + QDSwapPort(port_save, NULL); + } + + set_mouse_data(point.h, point.v, _mouse_down); + } + break; + + break; } } return result; } +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::OsxImageData::dump_image +// Access: Public +// Description: Frees the previous image data. +//////////////////////////////////////////////////////////////////// +void P3DOsxSplashWindow::OsxImageData:: +dump_image() { + if (_image != NULL) { + CGImageRelease(_image); + _image = NULL; + } + if (_color_space != NULL) { + CGColorSpaceRelease(_color_space); + _color_space = NULL; + } + if (_provider != NULL) { + CGDataProviderRelease(_provider); + _provider = NULL; + } + if (_data != NULL) { + CFRelease(_data); + _data = NULL; + } + if (_raw_data != NULL) { + delete[] _raw_data; + _raw_data = NULL; + } +} #endif // __APPLE__ diff --git a/direct/src/plugin/p3dOsxSplashWindow.h b/direct/src/plugin/p3dOsxSplashWindow.h index abef11daa8..0d977c16c6 100644 --- a/direct/src/plugin/p3dOsxSplashWindow.h +++ b/direct/src/plugin/p3dOsxSplashWindow.h @@ -35,15 +35,21 @@ public: virtual void set_wparams(const P3DWindowParams &wparams); virtual void set_image_filename(const string &image_filename, - bool image_filename_temp); + ImagePlacement image_placement); virtual void set_install_label(const string &install_label); virtual void set_install_progress(double install_progress); virtual bool handle_event(P3D_event_data event); +protected: + virtual void refresh(); + private: - void refresh(); void paint_window(); + class OsxImageData; + + void load_image(OsxImageData &image, const string &image_filename); + bool paint_image(GrafPtr out_port, const OsxImageData &image); static pascal OSStatus st_event_callback(EventHandlerCallRef my_handler, EventRef event, @@ -52,13 +58,32 @@ private: private: bool _got_wparams; - GWorldPtr _image; - char *_image_data; - int _image_height, _image_width; + + class OsxImageData : public ImageData { + public: + inline OsxImageData(); + inline ~OsxImageData(); + void dump_image(); + + char *_raw_data; + CFDataRef _data; + CGDataProviderRef _provider; + CGColorSpaceRef _color_space; + CGImageRef _image; + }; + + OsxImageData _background_image; + OsxImageData _button_ready_image; + OsxImageData _button_rollover_image; + OsxImageData _button_click_image; string _install_label; double _install_progress; + // Used to track the mouse within the window in the embedded case. + bool _mouse_active; + + // Filled only in the non-embedded case. WindowRef _toplevel_window; }; diff --git a/direct/src/plugin/p3dPackage.I b/direct/src/plugin/p3dPackage.I index 86ce5e48b0..7bb408bfa1 100755 --- a/direct/src/plugin/p3dPackage.I +++ b/direct/src/plugin/p3dPackage.I @@ -41,23 +41,6 @@ get_download_size() const { return _download_size; } -//////////////////////////////////////////////////////////////////// -// Function: P3DPackage::activate_download -// Access: Public -// Description: Authorizes the package to begin downloading and -// unpacking the meat of its data. Until this is -// called, the package will download its file -// information only, and then wait. -//////////////////////////////////////////////////////////////////// -inline void P3DPackage:: -activate_download() { - _allow_data_download = true; - - if (_info_ready) { - begin_data_download(); - } -} - //////////////////////////////////////////////////////////////////// // Function: P3DPackage::get_ready // Access: Public @@ -140,6 +123,17 @@ get_package_display_name() const { return _package_display_name; } +//////////////////////////////////////////////////////////////////// +// Function: P3DPackage::get_xconfig +// Access: Public +// Description: Returns the entry of the package desc file, +// if any, or NULL if it was not present. +//////////////////////////////////////////////////////////////////// +inline const TiXmlElement *P3DPackage:: +get_xconfig() const { + return _xconfig; +} + //////////////////////////////////////////////////////////////////// // Function: P3DPackage::get_desc_file_pathname // Access: Public diff --git a/direct/src/plugin/p3dPackage.cxx b/direct/src/plugin/p3dPackage.cxx index 994021a463..e146ad9e3e 100755 --- a/direct/src/plugin/p3dPackage.cxx +++ b/direct/src/plugin/p3dPackage.cxx @@ -54,6 +54,7 @@ P3DPackage(P3DHost *host, const string &package_name, // file, instead of an xml file and a multifile to unpack. _package_solo = false; + _xconfig = NULL; _temp_contents_file = NULL; _info_ready = false; @@ -78,6 +79,11 @@ P3DPackage:: // Tell any pending callbacks that we're no good any more. report_done(false); + if (_xconfig != NULL) { + delete _xconfig; + _xconfig = NULL; + } + // Cancel any pending download. if (_active_download != NULL) { _active_download->cancel(); @@ -93,6 +99,38 @@ P3DPackage:: assert(_instances.empty()); } +//////////////////////////////////////////////////////////////////// +// Function: P3DPackage::activate_download +// Access: Public +// Description: Authorizes the package to begin downloading and +// unpacking the meat of its data. Until this is +// called, the package will download its file +// information only, and then wait. +//////////////////////////////////////////////////////////////////// +void P3DPackage:: +activate_download() { + if (_allow_data_download) { + // Already activated. + } + + _allow_data_download = true; + + if (_ready) { + // If we've already been downloaded, we can report that now. + Instances::iterator ii; + for (ii = _instances.begin(); ii != _instances.end(); ++ii) { + (*ii)->report_package_done(this, true); + } + + } else { + // Otherwise, if we've already got the desc file, then start the + // download. + if (_info_ready) { + begin_data_download(); + } + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DPackage::add_instance // Access: Public @@ -358,6 +396,9 @@ got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) { if (display_name_cstr != NULL) { _package_display_name = display_name_cstr; } + + // Save the config entry within this class for others to query. + _xconfig = (TiXmlElement *)xconfig->Clone(); } } diff --git a/direct/src/plugin/p3dPackage.h b/direct/src/plugin/p3dPackage.h index f269cc3f50..332b19fb09 100755 --- a/direct/src/plugin/p3dPackage.h +++ b/direct/src/plugin/p3dPackage.h @@ -48,7 +48,7 @@ public: inline bool get_info_ready() const; inline size_t get_download_size() const; - inline void activate_download(); + void activate_download(); inline bool get_ready() const; inline bool get_failed() const; inline P3DHost *get_host() const; @@ -56,6 +56,7 @@ public: inline const string &get_package_name() const; inline const string &get_package_version() const; inline const string &get_package_display_name() const; + inline const TiXmlElement *get_xconfig() const; inline const string &get_desc_file_pathname() const; inline string get_archive_file_pathname() const; @@ -119,6 +120,7 @@ private: string _package_display_name; string _package_fullname; string _package_dir; + TiXmlElement *_xconfig; P3DTemporaryFile *_temp_contents_file; diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index 9e9fd01781..1dd92e142d 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -109,6 +109,7 @@ P3DPythonRun:: // Close the write pipe, so the parent process will terminate us. _pipe_write.close(); + // Shut down Python and Panda. Py_Finalize(); join_read_thread(); diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index d42bb40151..b7b979721d 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -229,15 +229,11 @@ start_instance(P3DInstance *inst) { send_command(doc); inst->send_browser_script_object(); - if (inst->get_packages_ready()) { - // If it's ready immediately, go ahead and start. - start_p3dpython(inst); + // We shouldn't have gotten here unless the instance is fully + // downloaded and ready to start. + assert(inst->get_packages_ready()); - } else { - // Otherwise, wait for the instance to download itself. We'll - // automatically get a callback to report_packages_done() when - // it's done. - } + start_p3dpython(inst); } //////////////////////////////////////////////////////////////////// @@ -641,18 +637,6 @@ drop_p3dobj(int object_id) { } } -//////////////////////////////////////////////////////////////////// -// Function: P3DSession::report_packages_done -// Access: Private -// Description: Notified when a child instance is fully downloaded. -//////////////////////////////////////////////////////////////////// -void P3DSession:: -report_packages_done(P3DInstance *inst, bool success) { - if (success) { - start_p3dpython(inst); - } -} - //////////////////////////////////////////////////////////////////// // Function: P3DSession::start_p3dpython // Access: Private diff --git a/direct/src/plugin/p3dSession.h b/direct/src/plugin/p3dSession.h index 75006ffebd..d09631a689 100644 --- a/direct/src/plugin/p3dSession.h +++ b/direct/src/plugin/p3dSession.h @@ -61,7 +61,6 @@ public: void drop_p3dobj(int object_id); private: - void report_packages_done(P3DInstance *inst, bool success); void start_p3dpython(P3DInstance *inst); void spawn_read_thread(); diff --git a/direct/src/plugin/p3dSplashWindow.I b/direct/src/plugin/p3dSplashWindow.I index 18cdd9fb43..0859faa8e4 100755 --- a/direct/src/plugin/p3dSplashWindow.I +++ b/direct/src/plugin/p3dSplashWindow.I @@ -32,3 +32,15 @@ inline const P3DWindowParams &P3DSplashWindow:: get_wparams() const { return _wparams; } + +//////////////////////////////////////////////////////////////////// +// Function: P3DSplashWindow::ImageData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +inline P3DSplashWindow::ImageData:: +ImageData() { + _width = 0; + _height = 0; + _num_channels = 0; +} diff --git a/direct/src/plugin/p3dSplashWindow.cxx b/direct/src/plugin/p3dSplashWindow.cxx index 31fc17a987..b0f28d690e 100755 --- a/direct/src/plugin/p3dSplashWindow.cxx +++ b/direct/src/plugin/p3dSplashWindow.cxx @@ -14,6 +14,8 @@ #include "p3dSplashWindow.h" +// Stuff to use libpng. +#include // Stuff to use libjpeg. extern "C" { @@ -52,6 +54,16 @@ P3DSplashWindow(P3DInstance *inst) : _fparams(inst->get_fparams()), _wparams(inst->get_wparams()) { + _button_width = 0; + _button_height = 0; + _button_x = 0; + _button_y = 0; + _button_active = false; + _mouse_x = -1; + _mouse_y = -1; + _mouse_down = false; + _button_depressed = false; + _bstate = BS_hidden; } //////////////////////////////////////////////////////////////////// @@ -73,22 +85,23 @@ P3DSplashWindow:: void P3DSplashWindow:: set_wparams(const P3DWindowParams &wparams) { _wparams = wparams; + _win_width = _wparams.get_win_width(); + _win_height = _wparams.get_win_height(); } //////////////////////////////////////////////////////////////////// // 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. If -// image_filename_temp is true, the file is immediately -// deleted after it has been read. +// Description: Specifies the name of a JPEG or PNG image file that +// is displayed in the center of the splash window. +// +// image_placement defines the specific context in which +// this particular image is displayed. It is similar to +// the P3DInstance's image_type, but it is a more +// specific, lower-level usage. //////////////////////////////////////////////////////////////////// void P3DSplashWindow:: -set_image_filename(const string &image_filename, - bool image_filename_temp) { - if (image_filename_temp) { - unlink(image_filename.c_str()); - } +set_image_filename(const string &image_filename, ImagePlacement image_placement) { } //////////////////////////////////////////////////////////////////// @@ -122,35 +135,84 @@ handle_event(P3D_event_data event) { return false; } +//////////////////////////////////////////////////////////////////// +// Function: P3DSplashWindow::set_button_active +// Access: Public +// Description: Sets whether the button should be visible and active +// (true) or invisible and inactive (false). If active, +// the button image will be displayed in the window, and +// a click event will be generated when the user clicks +// the button. +//////////////////////////////////////////////////////////////////// +void P3DSplashWindow:: +set_button_active(bool flag) { + _button_active = flag; + + // Now light up the button according to the current mouse position. + set_mouse_data(_mouse_x, _mouse_y, _mouse_down); +} //////////////////////////////////////////////////////////////////// -// Function: P3DSplashWindow::read_image +// Function: P3DSplashWindow::read_image_data // Access: Protected // Description: Reads the image filename and sets image parameters -// height, width, num_channels, and data. Returns true -// on success, false on failure. If image_filename_temp -// is true, the file will be deleted after reading. +// width, height, num_channels, and data. Returns true +// on success, false on failure. //////////////////////////////////////////////////////////////////// bool P3DSplashWindow:: -read_image(const string &image_filename, bool image_filename_temp, - int &height, int &width, int &num_channels, - string &data) { - height = 0; - width = 0; - num_channels = 0; +read_image_data(ImageData &image, string &data, + const string &image_filename) { + image._width = 0; + image._height = 0; + image._num_channels = 0; data.clear(); - // We currently only support JPEG images. Maybe that's all we'll - // ever support. + // We only support JPEG or PNG images. FILE *fp = fopen(image_filename.c_str(), "rb"); if (fp == NULL) { nout << "Couldn't open splash file image: " << image_filename << "\n"; - if (image_filename_temp) { - unlink(image_filename.c_str()); - } return false; } + // Check the magic number to determine which image type we have. + static const size_t magic_number_len = 2; + char magic_number[magic_number_len]; + if (fread(magic_number, 1, magic_number_len, fp) != magic_number_len) { + nout << "Empty file: " << image_filename << "\n"; + return false; + } + // Rewind to re-read the magic number below. + fseek(fp, 0, SEEK_SET); + + bool result = false; + if ((char)magic_number[0] == (char)0xff && + (char)magic_number[1] == (char)0xd8) { + // It's a jpeg image. + result = read_image_data_jpeg(image, data, fp, image_filename); + + } else if (png_sig_cmp((png_bytep)magic_number, 0, magic_number_len) == 0) { + // It's a PNG image. + result = read_image_data_png(image, data, fp, image_filename); + + } else { + nout << "Neither a JPEG nor a PNG image: " << image_filename << "\n"; + result = false; + } + + fclose(fp); + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DSplashWindow::read_image_data_jpeg +// Access: Protected +// Description: Reads the image filename and sets image parameters +// width, height, num_channels, and data. Returns true +// on success, false on failure. +//////////////////////////////////////////////////////////////////// +bool P3DSplashWindow:: +read_image_data_jpeg(ImageData &image, string &data, + FILE *fp, const string &image_filename) { // We set up the normal JPEG error routines, then override error_exit. struct jpeg_decompress_struct cinfo; @@ -167,15 +229,10 @@ read_image(const string &image_filename, bool image_filename_temp, // 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; } @@ -190,13 +247,13 @@ read_image(const string &image_filename, bool image_filename_temp, jpeg_start_decompress(&cinfo); - width = cinfo.output_width; - height = cinfo.output_height; - num_channels = cinfo.output_components; + image._width = cinfo.output_width; + image._height = cinfo.output_height; + image._num_channels = cinfo.output_components; - int row_stride = width * num_channels; + int row_stride = image._width * image._num_channels; - size_t buffer_size = height * row_stride; + size_t buffer_size = image._height * row_stride; buffer = new JSAMPLE[buffer_size]; JSAMPLE *buffer_end = buffer + buffer_size; @@ -209,17 +266,99 @@ read_image(const string &image_filename, bool image_filename_temp, 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; } + +//////////////////////////////////////////////////////////////////// +// Function: P3DSplashWindow::read_image_data_png +// Access: Protected +// Description: Reads the image filename and sets image parameters +// width, height, num_channels, and data. Returns true +// on success, false on failure. +//////////////////////////////////////////////////////////////////// +bool P3DSplashWindow:: +read_image_data_png(ImageData &image, string &data, + FILE *fp, const string &image_filename) { + cerr << "read_image_data_png\n"; + png_structp png; + png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, + png_error, png_warning); + if (png == NULL) { + return false; + } + + png_infop info; + info = png_create_info_struct(png); + if (info == NULL) { + png_destroy_read_struct(&png, NULL, NULL); + return false; + } + + jmp_buf jmpbuf; + if (setjmp(jmpbuf)) { + // This is the ANSI C way to handle exceptions. If setjmp(), + // above, returns true, it means that libpng detected an exception + // while executing the code that reads the header info, below. + png_destroy_read_struct(&png, &info, NULL); + return false; + } + + png_init_io(png, fp); + int transforms = PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_SHIFT; + // transforms |= PNG_TRANSFORM_STRIP_ALPHA; + png_read_png(png, info, transforms, NULL); + + png_uint_32 width; + png_uint_32 height; + int bit_depth; + int color_type; + + png_get_IHDR(png, info, &width, &height, + &bit_depth, &color_type, NULL, NULL, NULL); + + cerr + << "width = " << width << " height = " << height << " bit_depth = " + << bit_depth << " color_type = " << color_type << "\n"; + + image._width = width; + image._height = height; + + switch (color_type) { + case PNG_COLOR_TYPE_RGB: + cerr + << "PNG_COLOR_TYPE_RGB\n"; + image._num_channels = 3; + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: + cerr + << "PNG_COLOR_TYPE_RGB_ALPHA\n"; + image._num_channels = 4; + break; + + default: + cerr + << "Unsupported color type: " << color_type << "\n"; + png_destroy_read_struct(&png, &info, NULL); + return false; + } + + int row_stride = image._width * image._num_channels; + png_bytep *row_pointers = png_get_rows(png, info); + for (int yi = 0; yi < image._height; ++yi) { + data.append((const char *)row_pointers[yi], row_stride); + } + + png_destroy_read_struct(&png, &info, NULL); + + cerr << "successfully read\n"; + return true; +} + //////////////////////////////////////////////////////////////////// // Function: P3DSplashWindow::get_bar_placement // Access: Protected @@ -227,11 +366,128 @@ read_image(const string &image_filename, bool image_filename_temp, // rectangle in which to place the progress bar. //////////////////////////////////////////////////////////////////// void P3DSplashWindow:: -get_bar_placement(int win_width, int win_height, - int &bar_x, int &bar_y, +get_bar_placement(int &bar_x, int &bar_y, int &bar_width, int &bar_height) { - bar_width = min((int)(win_width * 0.6), 400); - bar_height = min((int)(win_height * 0.1), 24); - bar_x = (win_width - bar_width) / 2; - bar_y = (win_height - bar_height * 2); + bar_width = min((int)(_win_width * 0.6), 400); + bar_height = min((int)(_win_height * 0.1), 24); + bar_x = (_win_width - bar_width) / 2; + bar_y = (_win_height - bar_height * 2); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DSplashWindow::set_button_range +// Access: Protected +// Description: Specifies the image that contains the "ready" button +// image, which in turn determines the clickable +// dimensions of the button within the window. +//////////////////////////////////////////////////////////////////// +void P3DSplashWindow:: +set_button_range(const ImageData &image) { + // The clickable area has a certain minimum size, even if it's a + // very small image. + _button_width = max(image._width, 64); + _button_height = max(image._height, 64); + + // But it can't be larger than the window itself. + _button_width = min(_button_width, _win_width); + _button_height = min(_button_height, _win_height); + + // Compute the top-left corner of the button image in window + // coordinates. + _button_x = (_win_width - _button_width) / 2; + _button_y = (_win_height - _button_height) / 2; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DSplashWindow::set_mouse_data +// Access: Protected +// Description: Intended to be called by the subclasses as the mouse +// is tracked through the window, whether the button is +// currently active or not. This updates the internal +// state of the mouse pointer, and also (if the button +// is active) updates the button state appropriately, +// and generates the click event when the mouse button +// transitions from down to up over the button area. +//////////////////////////////////////////////////////////////////// +void P3DSplashWindow:: +set_mouse_data(int mouse_x, int mouse_y, bool mouse_down) { + ButtonState orig_bstate = _bstate; + + _mouse_x = mouse_x; + _mouse_y = mouse_y; + _mouse_down = mouse_down; + + if (!_button_active) { + // The button isn't active, so it's hidden, regardless of the + // mouse position. + _bstate = BS_hidden; + } else { + // Is the mouse pointer within the button region? + bool is_within = (_mouse_x >= _button_x && _mouse_x < _button_x + _button_width && + _mouse_y >= _button_y && _mouse_y < _button_y + _button_height); + if (is_within) { + // The mouse is within the button region. This means either + // click or rollover state, according to the mouse button. + if (_mouse_down) { + // We only count it mouse-down if you've clicked down while + // over the button (or you never released the button since the + // last time you clicked down). Clicking down somewhere else + // and dragging over the button doesn't count. + if (orig_bstate == BS_rollover || _button_depressed) { + _button_depressed = true; + _bstate = BS_click; + } + } else { + _button_depressed = false; + if (orig_bstate == BS_click) { + // If we just transitioned from mouse down to mouse up, this + // means a click. And the button automatically hides itself + // after a successful click. + _bstate = BS_hidden; + _button_active = false; + button_click_detected(); + } else { + _bstate = BS_rollover; + } + } + } else { + // The mouse is not within the button region. This means ready + // state. + _bstate = BS_ready; + if (!_mouse_down) { + _button_depressed = false; + } + } + } + + if (orig_bstate != _bstate) { + // If we've changed button states, we need to refresh the window. + refresh(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DSplashWindow::button_click_detected +// Access: Protected, Virtual +// Description: Called when a button click by the user is detected in +// set_mouse_data(), this method simply turns around and +// notifies the instance. It's a virtual method to give +// subclasses a chance to redirect this message to the +// main thread or process, as necessary. +//////////////////////////////////////////////////////////////////// +void P3DSplashWindow:: +button_click_detected() { + assert(_inst != NULL); + _inst->splash_button_clicked(); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DSplashWindow::refresh +// Access: Protected, Virtual +// Description: Requests that the window will be repainted. This may +// or may not be implemented for a particular +// specialization of P3DSplashWindow. +//////////////////////////////////////////////////////////////////// +void P3DSplashWindow:: +refresh() { } diff --git a/direct/src/plugin/p3dSplashWindow.h b/direct/src/plugin/p3dSplashWindow.h index 5d169b425a..3de596289b 100755 --- a/direct/src/plugin/p3dSplashWindow.h +++ b/direct/src/plugin/p3dSplashWindow.h @@ -42,26 +42,72 @@ public: virtual void set_wparams(const P3DWindowParams &wparams); inline const P3DWindowParams &get_wparams() const; + enum ImagePlacement { + IP_background, + IP_button_ready, + IP_button_rollover, + IP_button_click, + IP_none + }; + virtual void set_image_filename(const string &image_filename, - bool image_filename_temp); + ImagePlacement image_placement); virtual void set_install_label(const string &install_label); virtual void set_install_progress(double install_progress); virtual bool handle_event(P3D_event_data event); - void setup_splash_image(); + void set_button_active(bool flag); protected: - bool read_image(const string &image_filename, bool image_filename_temp, - int &height, int &width, int &num_channels, string &data); - void get_bar_placement(int win_width, int win_height, - int &bar_x, int &bar_y, + // This ImageData base class provides minimal functionality for + // storing a loaded image. Most of the real meat of this class is + // provided by the various subclasses. + class ImageData { + public: + inline ImageData(); + int _width, _height, _num_channels; + }; + + bool read_image_data(ImageData &image, string &data, + const string &image_filename); + bool read_image_data_jpeg(ImageData &image, string &data, + FILE *fp, const string &image_filename); + bool read_image_data_png(ImageData &image, string &data, + FILE *fp, const string &image_filename); + void get_bar_placement(int &bar_x, int &bar_y, int &bar_width, int &bar_height); + void set_button_range(const ImageData &image); + void set_mouse_data(int mouse_x, int mouse_y, bool mouse_down); + + virtual void button_click_detected(); + virtual void refresh(); protected: P3DInstance *_inst; P3DFileParams _fparams; P3DWindowParams _wparams; + int _win_width, _win_height; + + // The region of the window for accepting button clicks. + int _button_width, _button_height; + int _button_x, _button_y; + bool _button_active; + + // Tracking the mouse pointer within the window, for the purposes of + // clicking the button. + int _mouse_x, _mouse_y; + bool _mouse_down; + bool _button_depressed; + + // The current visual state of the button. + enum ButtonState { + BS_hidden, + BS_ready, + BS_rollover, + BS_click, + }; + ButtonState _bstate; }; #include "p3dSplashWindow.I" diff --git a/direct/src/plugin/p3dWinSplashWindow.cxx b/direct/src/plugin/p3dWinSplashWindow.cxx index 91b1247c5d..9899f06509 100755 --- a/direct/src/plugin/p3dWinSplashWindow.cxx +++ b/direct/src/plugin/p3dWinSplashWindow.cxx @@ -35,7 +35,6 @@ P3DWinSplashWindow(P3DInstance *inst) : _text_label = NULL; _thread_running = false; _image_filename_changed = false; - _image_filename_temp = false; _install_label_changed = false; _install_progress = 0.0; @@ -74,18 +73,14 @@ set_wparams(const P3DWindowParams &wparams) { // 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. If -// image_filename_temp is true, the file is immediately -// deleted after it has been read. +// displayed in the center of the splash window. //////////////////////////////////////////////////////////////////// void P3DWinSplashWindow:: -set_image_filename(const string &image_filename, - bool image_filename_temp) { +set_image_filename(const string &image_filename, ImagePlacement image_placement) { nout << "image_filename = " << image_filename << ", thread_id = " << _thread_id << "\n"; 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); @@ -264,7 +259,7 @@ thread_run() { ACQUIRE_LOCK(_install_lock); double install_progress = _install_progress; if (_image_filename_changed) { - update_image_filename(_image_filename, _image_filename_temp); + update_image_filename(_image_filename); } _image_filename_changed = false; if (_install_label_changed && _progress_bar != NULL) { @@ -395,14 +390,8 @@ make_progress_bar() { DWORD window_style = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - RECT rect; - GetClientRect(_hwnd, &rect); - int win_width = rect.right - rect.left; - int win_height = rect.bottom - rect.top; - int bar_x, bar_y, bar_width, bar_height; - get_bar_placement(win_width, win_height, - bar_x, bar_y, bar_width, bar_height); + get_bar_placement(bar_x, bar_y, bar_width, bar_height); _progress_bar = CreateWindowEx(0, PROGRESS_CLASS, "", window_style, @@ -450,18 +439,12 @@ update_install_label(const string &install_label) { DWORD window_style = SS_OWNERDRAW | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - RECT rect; - GetClientRect(_hwnd, &rect); - int win_width = rect.right - rect.left; - int win_height = rect.bottom - rect.top; - int bar_x, bar_y, bar_width, bar_height; - get_bar_placement(win_width, win_height, - bar_x, bar_y, bar_width, bar_height); + get_bar_placement(bar_x, bar_y, bar_width, bar_height); int text_width = text_size.cx + 4; int text_height = text_size.cy + 2; - int text_x = (win_width - text_width) / 2; + int text_x = (_win_width - text_width) / 2; int text_y = bar_y - text_height - 2; _text_label = CreateWindowEx(0, "STATIC", text, window_style, @@ -478,7 +461,7 @@ update_install_label(const string &install_label) { // sub-thread. //////////////////////////////////////////////////////////////////// void P3DWinSplashWindow:: -update_image_filename(const string &image_filename, bool image_filename_temp) { +update_image_filename(const string &image_filename) { // Clear the old image. if (_bitmap != NULL) { DeleteObject(_bitmap); @@ -491,12 +474,16 @@ update_image_filename(const string &image_filename, bool image_filename_temp) { // Go read the image. string data; - int num_channels; - if (!read_image(image_filename, image_filename_temp, - _bitmap_height, _bitmap_width, num_channels, data)) { + ImageData image; + if (!read_image_data(image, data, image_filename)) { return; } + // Temp legacy support. + _bitmap_width = image._width; + _bitmap_height = image._height; + int num_channels =image._num_channels; + // Massage the data into Windows' conventions. int row_stride = _bitmap_width * num_channels; int new_row_stride = (_bitmap_width * 3); @@ -591,8 +578,8 @@ void P3DWinSplashWindow:: paint_window(HDC dc) { RECT rect; GetClientRect(_hwnd, &rect); - int win_width = rect.right - rect.left; - int win_height = rect.bottom - rect.top; + _win_width = rect.right - rect.left; + _win_height = rect.bottom - rect.top; if (_bitmap != NULL) { // Paint the background splash image. @@ -603,10 +590,10 @@ paint_window(HDC dc) { int bm_width = _bitmap_width; int bm_height = _bitmap_height; - int win_cx = win_width / 2; - int win_cy = win_height / 2; + int win_cx = _win_width / 2; + int win_cy = _win_height / 2; - if (bm_width <= win_width && bm_height <= win_height) { + 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. @@ -621,8 +608,8 @@ paint_window(HDC dc) { } 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 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); diff --git a/direct/src/plugin/p3dWinSplashWindow.h b/direct/src/plugin/p3dWinSplashWindow.h index 605f361454..6243220d86 100755 --- a/direct/src/plugin/p3dWinSplashWindow.h +++ b/direct/src/plugin/p3dWinSplashWindow.h @@ -36,7 +36,7 @@ public: virtual void set_wparams(const P3DWindowParams &wparams); virtual void set_image_filename(const string &image_filename, - bool image_filename_temp); + ImagePlacement image_placement); virtual void set_install_label(const string &install_label); virtual void set_install_progress(double install_progress); @@ -55,8 +55,7 @@ private: void make_window(); void make_progress_bar(); void update_install_label(const string &install_label); - void update_image_filename(const string &image_filename, - bool image_filename_temp); + void update_image_filename(const string &image_filename); void close_window(); void paint_window(HDC dc); @@ -67,7 +66,6 @@ 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; diff --git a/direct/src/plugin/p3dX11SplashWindow.cxx b/direct/src/plugin/p3dX11SplashWindow.cxx index 5afe9324e7..7ea334b10b 100755 --- a/direct/src/plugin/p3dX11SplashWindow.cxx +++ b/direct/src/plugin/p3dX11SplashWindow.cxx @@ -58,7 +58,6 @@ P3DX11SplashWindow(P3DInstance *inst) : _resized_height = 0; _graphics_context = None; _bar_context = None; - _image_filename_temp = false; _install_progress = 0.0; } @@ -92,13 +91,10 @@ set_wparams(const P3DWindowParams &wparams) { // Function: P3DX11SplashWindow::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. If -// image_filename_temp is true, the file is immediately -// deleted after it has been read. +// displayed in the center of the splash window. //////////////////////////////////////////////////////////////////// void P3DX11SplashWindow:: -set_image_filename(const string &image_filename, - bool image_filename_temp) { +set_image_filename(const string &image_filename, ImagePlacement image_placement) { if (_subprocess_pid == -1) { return; } @@ -107,7 +103,6 @@ set_image_filename(const string &image_filename, TiXmlElement *xcommand = new TiXmlElement("command"); xcommand->SetAttribute("cmd", "set_image_filename"); xcommand->SetAttribute("image_filename", image_filename); - xcommand->SetAttribute("image_filename_temp", (int)image_filename_temp); doc.LinkEndChild(xcommand); write_xml(_pipe_write, &doc, nout); @@ -367,7 +362,7 @@ subprocess_run() { } if (_image_filename != prev_image_filename) { - update_image_filename(_image_filename, _image_filename_temp); + update_image_filename(_image_filename); needs_redraw = true; prev_image_filename = _image_filename; } @@ -401,8 +396,7 @@ subprocess_run() { // some nonzero progress. if (_install_progress != 0.0) { int bar_x, bar_y, bar_width, bar_height; - get_bar_placement(_width, _height, - bar_x, bar_y, bar_width, bar_height); + get_bar_placement(bar_x, bar_y, bar_width, bar_height); if (needs_draw_label) { int text_width = _install_label.size() * 6; @@ -485,12 +479,9 @@ receive_command() { } else if (strcmp(cmd, "set_image_filename") == 0) { const char *str = xcommand->Attribute("image_filename"); - int image_filename_temp = 0; - xcommand->Attribute("image_filename_temp", &image_filename_temp); if (str != NULL) { if (_image_filename != string(str)) { _image_filename = str; - _image_filename_temp = image_filename_temp; } } @@ -570,11 +561,11 @@ make_window() { int x = _wparams.get_win_x(); int y = _wparams.get_win_y(); - _width = 320; - _height = 240; + _win_width = 320; + _win_height = 240; if (_wparams.get_win_width() != 0 && _wparams.get_win_height() != 0) { - _width = _wparams.get_win_width(); - _height = _wparams.get_win_height(); + _win_width = _wparams.get_win_width(); + _win_height = _wparams.get_win_height(); } Window parent = 0; @@ -602,7 +593,7 @@ make_window() { assert(_display != NULL); assert(parent != None); - _window = XCreateSimpleWindow(_display, parent, x, y, _width, _height, 0, 0, -1); + _window = XCreateSimpleWindow(_display, parent, x, y, _win_width, _win_height, 0, 0, -1); XMapWindow(_display, _window); } @@ -698,7 +689,7 @@ close_window() { // sub-thread. //////////////////////////////////////////////////////////////////// void P3DX11SplashWindow:: -update_image_filename(const string &image_filename, bool image_filename_temp) { +update_image_filename(const string &image_filename) { // Clear the old image. if (_image != NULL) { XDestroyImage(_image); @@ -711,12 +702,16 @@ update_image_filename(const string &image_filename, bool image_filename_temp) { // Go read the image. string data; - int num_channels; - if (!read_image(image_filename, image_filename_temp, - _image_height, _image_width, num_channels, data)) { + ImageData image; + if (!read_image_data(image, data, image_filename)) { return; } + // Temp legacy support. + _image_width = image._width; + _image_height = image._height; + int num_channels =image._num_channels; + Visual *dvisual = DefaultVisual(_display, _screen); double r_ratio = dvisual->red_mask / 255.0; double g_ratio = dvisual->green_mask / 255.0; diff --git a/direct/src/plugin/p3dX11SplashWindow.h b/direct/src/plugin/p3dX11SplashWindow.h index 93a4b0979e..ff05c60dc6 100755 --- a/direct/src/plugin/p3dX11SplashWindow.h +++ b/direct/src/plugin/p3dX11SplashWindow.h @@ -37,7 +37,7 @@ public: virtual void set_wparams(const P3DWindowParams &wparams); virtual void set_image_filename(const string &image_filename, - bool image_filename_temp); + ImagePlacement image_placement); virtual void set_install_label(const string &install_label); virtual void set_install_progress(double install_progress); @@ -59,19 +59,16 @@ private: void redraw(); void make_window(); void setup_gc(); - void update_image_filename(const string &image_filename, - bool image_filename_temp); + void update_image_filename(const string &image_filename); void close_window(); private: // Data members that are stored in the subprocess. bool _subprocess_continue; HandleStream _pipe_read; - int _width, _height; bool _own_display; string _image_filename; - bool _image_filename_temp; string _install_label; double _install_progress;