Panda3D

mayaPview.cxx

00001 // Filename: mayaPview.cxx
00002 // Created by:  drose (10Mar03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #ifdef __MACH__
00016 #define __OPENTRANSPORTPROVIDERS__
00017 #endif
00018 
00019 #include "mayaPview.h"
00020 #include "mayaToEggConverter.h"
00021 #include "eggData.h"
00022 #include "load_egg_file.h"
00023 #include "config_util.h"
00024 #include "config_chan.h"
00025 #include "config_gobj.h"
00026 #include "textNode.h"
00027 #include "multiplexStream.h"
00028 #include "distanceUnit.h"
00029 #include "configVariableEnum.h"
00030 
00031 // We must define this to prevent Maya from doubly-declaring its
00032 // MApiVersion string in this file as well as in libmayaegg.
00033 #define _MApiVersion
00034 
00035 #include "pre_maya_include.h"
00036 #include <maya/MString.h>
00037 #include <maya/MFnPlugin.h>
00038 #include <maya/MFileIO.h>
00039 #include <maya/MArgParser.h>
00040 #include <maya/MArgList.h>
00041 #include <maya/MSyntax.h>
00042 #include <maya/MProgressWindow.h>
00043 #include "post_maya_include.h"
00044 
00045 // On Windows, we have code to fork pview as a separate process, which
00046 // seems to be better for Maya.
00047 #ifdef WIN32_VC
00048 #include <windows.h>
00049 #include <process.h>
00050 #define SEPARATE_PVIEW 1
00051 #endif  // WIN32_VC
00052 
00053 ////////////////////////////////////////////////////////////////////
00054 //     Function: MayaPview::Constructor
00055 //       Access: Public
00056 //  Description:
00057 ////////////////////////////////////////////////////////////////////
00058 MayaPview::
00059 MayaPview() {
00060 }
00061 
00062 ////////////////////////////////////////////////////////////////////
00063 //     Function: MayaPview::doIt
00064 //       Access: Public, Virtual
00065 //  Description: Called when the plugin command is invoked.
00066 ////////////////////////////////////////////////////////////////////
00067 MStatus MayaPview::
00068 doIt(const MArgList &args) {
00069   MStatus result;
00070 
00071   // First, parse the plugin arguments.
00072   MSyntax syntax;
00073   syntax.addFlag("a", "animate");
00074 
00075   MArgParser parser(syntax, args, &result);
00076   if (!result) {
00077     result.perror("arguments");
00078     return result;
00079   }
00080 
00081   bool animate = parser.isFlagSet("a", &result);
00082   if (!result) {
00083     result.perror("isFlagSet");
00084     return result;
00085   }
00086 
00087   if (!MProgressWindow::reserve()) {
00088     nout << "Couldn't reserve progress window.\n";
00089     return MS::kFailure;
00090   }
00091   MProgressWindow::setTitle("Sending to pview");
00092   MProgressWindow::setInterruptable(false);
00093   MProgressWindow::setProgressRange(0, 3);
00094   MProgressWindow::setProgressStatus("Converting scene");
00095   MProgressWindow::startProgress();
00096 
00097 #ifdef SEPARATE_PVIEW
00098   // We'll write the bam file to a temporary file first.
00099   Filename bam_filename = Filename::temporary("", "pview");
00100   bam_filename.set_extension("bam");
00101 
00102   // Since we're just writing to a bam file in this process, and
00103   // running pview in a separate process, we don't actually need to
00104   // load textures at this point.  Disable the loading of textures.
00105   textures_header_only = true;
00106 
00107   NodePath root("root");
00108   if (!convert(root, animate)) {
00109     nout << "failure in conversion.\n";
00110     MProgressWindow::endProgress();
00111     return MS::kFailure;
00112   }
00113 
00114   MProgressWindow::setProgressStatus("Writing bam file");
00115   MProgressWindow::advanceProgress(1);
00116 
00117   if (!root.write_bam_file(bam_filename)) {
00118     nout << "Couldn't write to " << bam_filename << ".\n";
00119     MProgressWindow::endProgress();
00120     return MS::kFailure;
00121   }
00122 
00123   MProgressWindow::setProgressStatus("Spawning pview");
00124   MProgressWindow::advanceProgress(1);
00125   
00126   // Now spawn a pview instance to view this temporary file.
00127   string pview_args = "-clD";
00128   if (animate) {
00129     pview_args = "-clDa";
00130   }
00131 
00132   // On Windows, we use the spawn function to run pview
00133   // asynchronously.
00134   string quoted = string("\"") + bam_filename.get_fullpath() + string("\"");
00135   nout << "pview " << pview_args << " " << quoted << "\n";
00136   int retval = _spawnlp(_P_DETACH, "pview", 
00137                         "pview", pview_args.c_str(), quoted.c_str(), NULL);
00138   if (retval == -1) {
00139     bam_filename.unlink();
00140     MProgressWindow::endProgress();
00141     return MS::kFailure;
00142   }
00143 
00144   nout << "pview running.\n"; 
00145   MProgressWindow::endProgress();
00146 
00147 #else  // SEPARATE_PVIEW
00148   // We'll run PandaFramework directly within this process.
00149 
00150   // Maya seems to run each invocation of the plugin in a separate
00151   // thread.  To minimize conflict in our
00152   // not-yet-completely-thread-safe Panda, we'll create a separate
00153   // PandaFramework for each invocation, even though in principle we
00154   // could be sharing one framework for all of them.
00155   int argc = 0;
00156   char **argv = NULL;
00157   PandaFramework framework;
00158   framework.open_framework(argc, argv);
00159   framework.set_window_title("Panda Viewer");
00160   framework.enable_default_keys();
00161 
00162   PT(WindowFramework) window;
00163   window = framework.open_window();
00164   if (window == (WindowFramework *)NULL) {
00165     // Couldn't open a window.
00166     nout << "Couldn't open a window!\n";
00167     MProgressWindow::endProgress();
00168     return MS::kFailure;
00169   }
00170 
00171   // We've successfully opened a window.
00172 
00173   // Put up a "loading" message for the user's benefit.
00174   NodePath aspect_2d = window->get_aspect_2d();
00175   PT(TextNode) loading = new TextNode("loading");
00176   NodePath loading_np = aspect_2d.attach_new_node(loading);
00177   loading_np.set_scale(0.125f);
00178   loading->set_text_color(1.0f, 1.0f, 1.0f, 1.0f);
00179   loading->set_shadow_color(0.0f, 0.0f, 0.0f, 1.0f);
00180   loading->set_shadow(0.04, 0.04);
00181   loading->set_align(TextNode::A_center);
00182   loading->set_text("Loading...");
00183 
00184   // Allow a couple of frames to go by so the window will be fully
00185   // created and the text will be visible.
00186   framework.do_frame(Thread::get_current_thread());
00187   framework.do_frame(Thread::get_current_thread());
00188 
00189   window->enable_keyboard();
00190   window->setup_trackball();
00191   framework.get_models().instance_to(window->get_render());
00192 
00193   if (!convert(framework.get_models(), animate)) {
00194     nout << "failure in conversion.\n";
00195     MProgressWindow::endProgress();
00196     return MS::kFailure;
00197   }
00198 
00199   nout << "successfully converted.\n";
00200 
00201   loading_np.remove_node();
00202   window->center_trackball(framework.get_models());
00203   window->loop_animations();
00204 
00205   if (animate) {
00206     window->set_anim_controls(true);
00207   }
00208 
00209   MProgressWindow::endProgress();
00210   framework.main_loop();
00211 #endif  // SEPARATE_PVIEW
00212 
00213   return MS::kSuccess;
00214 }
00215 
00216 ////////////////////////////////////////////////////////////////////
00217 //     Function: MayaPview::creator
00218 //       Access: Public, Static
00219 //  Description: This is used to create a new instance of the plugin.
00220 ////////////////////////////////////////////////////////////////////
00221 void *MayaPview::
00222 creator() {
00223   return new MayaPview;
00224 }
00225 
00226 ////////////////////////////////////////////////////////////////////
00227 //     Function: MayaPview::convert
00228 //       Access: Private
00229 //  Description: Actually converts the Maya selection to Panda
00230 //               geometry, and parents it to the indicated NodePath.
00231 ////////////////////////////////////////////////////////////////////
00232 bool MayaPview::
00233 convert(const NodePath &parent, bool animate) {
00234   // Now make a converter to get all the Maya structures.
00235   MayaToEggConverter converter("plug-in");
00236 
00237   // We always want polygon output since we want to be able to see the
00238   // results.
00239   converter._polygon_output = true;
00240   converter._polygon_tolerance = 0.01;
00241 
00242   if (animate) {
00243     // We also want to get the animation if there is any.
00244     converter.set_animation_convert(AC_both);
00245 
00246     // Don't compress animation channels; that can introduce confusing
00247     // artifacts.
00248     compress_channels = false;
00249   }
00250 
00251   PathReplace *path_replace = converter.get_path_replace();
00252 
00253   // Accept relative pathnames in the Maya file.
00254   Filename source_file = 
00255     Filename::from_os_specific(MFileIO::currentFile().asChar());
00256   string source_dir = source_file.get_dirname();
00257   if (!source_dir.empty()) {
00258     path_replace->_path.append_directory(source_dir);
00259   }
00260 
00261   // Also search along the model path.
00262   path_replace->_path.append_path(get_model_path());
00263 
00264   PT(EggData) egg_data = new EggData;
00265   converter.set_egg_data(egg_data);
00266   converter.set_from_selection(true);
00267   converter.set_neutral_frame(-1);
00268 
00269   if (!converter.convert_maya()) {
00270     nout << "Errors in conversion.\n";
00271     return false;
00272   }
00273 
00274   MProgressWindow::setProgressStatus("Converting to bam");
00275   MProgressWindow::advanceProgress(1);
00276 
00277   // Now the converter has filled up our egg structure with data, so
00278   // convert this egg data to Panda data for immediate viewing.
00279   DistanceUnit input_units = converter.get_input_units();
00280   ConfigVariableEnum<DistanceUnit> ptloader_units("ptloader-units", DU_invalid);
00281   if (input_units != DU_invalid && ptloader_units != DU_invalid && 
00282       input_units != ptloader_units) {
00283     // Convert the file to the units specified by the ptloader-units
00284     // Configrc variable.
00285     nout
00286       << "Converting from " << format_long_unit(input_units)
00287       << " to " << format_long_unit(ptloader_units) << "\n";
00288     double scale = convert_units(input_units, ptloader_units);
00289     egg_data->transform(LMatrix4d::scale_mat(scale));
00290   }
00291 
00292   egg_data->set_coordinate_system(CS_default);
00293   PT(PandaNode) result = load_egg_data(egg_data);
00294 
00295   if (result == (PandaNode *)NULL) {
00296     nout << "Unable to load converted egg data.\n";
00297     return false;
00298   }
00299 
00300   parent.attach_new_node(result);
00301   return true;
00302 }
00303 
00304 
00305 
00306 
00307 ////////////////////////////////////////////////////////////////////
00308 //     Function: initializePlugin
00309 //  Description: Called by Maya when the plugin is loaded.
00310 ////////////////////////////////////////////////////////////////////
00311 EXPCL_MISC MStatus 
00312 initializePlugin(MObject obj) {
00313   // This code is just for debugging, to cause Notify to write its
00314   // output to a log file we can inspect, so we can see the error
00315   // messages output by DX7 or DX8 just before it does a panic exit
00316   // (and thereby shuts down Maya and its output window).
00317   /*
00318   MultiplexStream *local_nout = new MultiplexStream();
00319   Notify::ptr()->set_ostream_ptr(local_nout, 0);
00320   local_nout->add_file(Filename::expand_from("$TEMP/libmayapview.log"));
00321   local_nout->add_standard_output();
00322   */
00323 
00324   MFnPlugin plugin(obj, "VR Studio", "1.0");
00325   MStatus status;
00326   status = plugin.registerCommand("pview", MayaPview::creator);
00327   if (!status) {
00328     status.perror("registerCommand");
00329   }
00330 
00331   return status;
00332 }
00333 
00334 ////////////////////////////////////////////////////////////////////
00335 //     Function: uninitializePlugin
00336 //  Description: Called by Maya when the plugin is unloaded.
00337 ////////////////////////////////////////////////////////////////////
00338 EXPCL_MISC MStatus
00339 uninitializePlugin(MObject obj) {
00340   MFnPlugin plugin(obj);
00341   MStatus status;
00342   status = plugin.deregisterCommand("pview");
00343 
00344   if (!status) {
00345     status.perror("deregisterCommand");
00346   }
00347   return status;
00348 }
 All Classes Functions Variables Enumerations