Panda3D

mayaPview.cxx
Go to the documentation of this file.
1 /**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file mayaPview.cxx
10 * @author drose
11 * @date 2003-03-10
12 */
13
14 #ifdef __MACH__
15 #define __OPENTRANSPORTPROVIDERS__
16 #endif
17
18 #include "mayaPview.h"
19 #include "mayaToEggConverter.h"
20 #include "eggData.h"
21 #include "load_egg_file.h"
22 #include "config_putil.h"
23 #include "config_chan.h"
24 #include "config_gobj.h"
25 #include "textNode.h"
26 #include "multiplexStream.h"
27 #include "distanceUnit.h"
28 #include "configVariableEnum.h"
29
30 // We must define this to prevent Maya from doubly-declaring its MApiVersion
31 // string in this file as well as in libmayaegg.
32 #define _MApiVersion
33
34 #include "pre_maya_include.h"
35 #include <maya/MString.h>
36 #include <maya/MFnPlugin.h>
37 #include <maya/MFileIO.h>
38 #include <maya/MArgParser.h>
39 #include <maya/MArgList.h>
40 #include <maya/MSyntax.h>
41 #include <maya/MProgressWindow.h>
42 #include "post_maya_include.h"
43
44 // On Windows, we have code to fork pview as a separate process, which seems
45 // to be better for Maya.
46 #ifdef WIN32_VC
47 #include <windows.h>
48 #include <process.h>
49 #define SEPARATE_PVIEW 1
50 #endif // WIN32_VC
51
52 /**
53 *
54 */
55 MayaPview::
56 MayaPview() {
57 }
58
59 /**
60 * Called when the plugin command is invoked.
61 */
62 MStatus MayaPview::
63 doIt(const MArgList &args) {
64 MStatus result;
65
66 // First, parse the plugin arguments.
67 MSyntax syntax;
68 syntax.addFlag("a", "animate");
69
70 MArgParser parser(syntax, args, &result);
71 if (!result) {
72 result.perror("arguments");
73 return result;
74 }
75
76 bool animate = parser.isFlagSet("a", &result);
77 if (!result) {
78 result.perror("isFlagSet");
79 return result;
80 }
81
82 if (!MProgressWindow::reserve()) {
83 nout << "Couldn't reserve progress window.\n";
84 return MS::kFailure;
85 }
86 MProgressWindow::setTitle("Sending to pview");
87 MProgressWindow::setInterruptable(false);
88 MProgressWindow::setProgressRange(0, 3);
89 MProgressWindow::setProgressStatus("Converting scene");
90 MProgressWindow::startProgress();
91
92 #ifdef SEPARATE_PVIEW
93 // We'll write the bam file to a temporary file first.
94 Filename bam_filename = Filename::temporary("", "pview");
95 bam_filename.set_extension("bam");
96
97 // Since we're just writing to a bam file in this process, and running pview
98 // in a separate process, we don't actually need to load textures at this
99 // point. Disable the loading of textures.
100 textures_header_only = true;
101
102 NodePath root("root");
103 if (!convert(root, animate)) {
104 nout << "failure in conversion.\n";
105 MProgressWindow::endProgress();
106 return MS::kFailure;
107 }
108
109 MProgressWindow::setProgressStatus("Writing bam file");
110 MProgressWindow::advanceProgress(1);
111
112 if (!root.write_bam_file(bam_filename)) {
113 nout << "Couldn't write to " << bam_filename << ".\n";
114 MProgressWindow::endProgress();
115 return MS::kFailure;
116 }
117
118 MProgressWindow::setProgressStatus("Spawning pview");
119 MProgressWindow::advanceProgress(1);
120
121 // Now spawn a pview instance to view this temporary file.
122 std::string pview_args = "-clD";
123 if (animate) {
124 pview_args = "-clDa";
125 }
126
127 // On Windows, we use the spawn function to run pview asynchronously.
128 std::string quoted = std::string("\"") + bam_filename.get_fullpath() + std::string("\"");
129 nout << "pview " << pview_args << " " << quoted << "\n";
130 int retval = _spawnlp(_P_DETACH, "pview",
131 "pview", pview_args.c_str(), quoted.c_str(), nullptr);
132 if (retval == -1) {
133 bam_filename.unlink();
134 MProgressWindow::endProgress();
135 return MS::kFailure;
136 }
137
138 nout << "pview running.\n";
139 MProgressWindow::endProgress();
140
141 #else // SEPARATE_PVIEW
142 // We'll run PandaFramework directly within this process.
143
144 // Maya seems to run each invocation of the plugin in a separate thread. To
145 // minimize conflict in our not-yet-completely-thread-safe Panda, we'll
146 // create a separate PandaFramework for each invocation, even though in
147 // principle we could be sharing one framework for all of them.
148 int argc = 0;
149 char **argv = nullptr;
150 PandaFramework framework;
151 framework.open_framework(argc, argv);
152 framework.set_window_title("Panda Viewer");
153 framework.enable_default_keys();
154
155 PT(WindowFramework) window;
156 window = framework.open_window();
157 if (window == nullptr) {
158 // Couldn't open a window.
159 nout << "Couldn't open a window!\n";
160 MProgressWindow::endProgress();
161 return MS::kFailure;
162 }
163
164 // We've successfully opened a window.
165
166 // Put up a "loading" message for the user's benefit.
167 NodePath aspect_2d = window->get_aspect_2d();
168 PT(TextNode) loading = new TextNode("loading");
169 NodePath loading_np = aspect_2d.attach_new_node(loading);
170 loading_np.set_scale(0.125f);
171 loading->set_text_color(1.0f, 1.0f, 1.0f, 1.0f);
172 loading->set_shadow_color(0.0f, 0.0f, 0.0f, 1.0f);
173 loading->set_shadow(0.04, 0.04);
174 loading->set_align(TextNode::A_center);
175 loading->set_text("Loading...");
176
177 // Allow a couple of frames to go by so the window will be fully created and
178 // the text will be visible.
179 framework.do_frame(Thread::get_current_thread());
180 framework.do_frame(Thread::get_current_thread());
181
182 window->enable_keyboard();
183 window->setup_trackball();
184 framework.get_models().instance_to(window->get_render());
185
186 if (!convert(framework.get_models(), animate)) {
187 nout << "failure in conversion.\n";
188 MProgressWindow::endProgress();
189 return MS::kFailure;
190 }
191
192 nout << "successfully converted.\n";
193
194 loading_np.remove_node();
195 window->center_trackball(framework.get_models());
196 window->loop_animations();
197
198 if (animate) {
199 window->set_anim_controls(true);
200 }
201
202 MProgressWindow::endProgress();
203 framework.main_loop();
204 #endif // SEPARATE_PVIEW
205
206 return MS::kSuccess;
207 }
208
209 /**
210 * This is used to create a new instance of the plugin.
211 */
212 void *MayaPview::
213 creator() {
214 return new MayaPview;
215 }
216
217 /**
218 * Actually converts the Maya selection to Panda geometry, and parents it to
219 * the indicated NodePath.
220 */
221 bool MayaPview::
222 convert(const NodePath &parent, bool animate) {
223 // Now make a converter to get all the Maya structures.
224 MayaToEggConverter converter("plug-in");
225
226 // We always want polygon output since we want to be able to see the
227 // results.
228 converter._polygon_output = true;
229 converter._polygon_tolerance = 0.01;
230
231 if (animate) {
232 // We also want to get the animation if there is any.
233 converter.set_animation_convert(AC_both);
234
235 // Don't compress animation channels; that can introduce confusing
236 // artifacts.
237 compress_channels = false;
238 }
239
240 PathReplace *path_replace = converter.get_path_replace();
241
242 // Accept relative pathnames in the Maya file.
243 Filename source_file =
244 Filename::from_os_specific(MFileIO::currentFile().asChar());
245 std::string source_dir = source_file.get_dirname();
246 if (!source_dir.empty()) {
247 path_replace->_path.append_directory(source_dir);
248 }
249
250 // Also search along the model path.
251 path_replace->_path.append_path(get_model_path());
252
253 PT(EggData) egg_data = new EggData;
254 converter.set_egg_data(egg_data);
255 converter.set_from_selection(true);
256 converter.set_neutral_frame(-1);
257
258 if (!converter.convert_maya()) {
259 nout << "Errors in conversion.\n";
260 return false;
261 }
262
263 MProgressWindow::setProgressStatus("Converting to bam");
264 MProgressWindow::advanceProgress(1);
265
266 // Now the converter has filled up our egg structure with data, so convert
267 // this egg data to Panda data for immediate viewing.
268 DistanceUnit input_units = converter.get_input_units();
269 ConfigVariableEnum<DistanceUnit> ptloader_units("ptloader-units", DU_invalid);
270 if (input_units != DU_invalid && ptloader_units != DU_invalid &&
271 input_units != ptloader_units) {
272 // Convert the file to the units specified by the ptloader-units Configrc
273 // variable.
274 nout
275 << "Converting from " << format_long_unit(input_units)
276 << " to " << format_long_unit(ptloader_units) << "\n";
277 double scale = convert_units(input_units, ptloader_units);
278 egg_data->transform(LMatrix4d::scale_mat(scale));
279 }
280
281 egg_data->set_coordinate_system(CS_default);
282 PT(PandaNode) result = load_egg_data(egg_data);
283
284 if (result == nullptr) {
285 nout << "Unable to load converted egg data.\n";
286 return false;
287 }
288
289 parent.attach_new_node(result);
290 return true;
291 }
292
293
294
295
296 /**
297 * Called by Maya when the plugin is loaded.
298 */
299 EXPCL_MISC MStatus
300 initializePlugin(MObject obj) {
301 // This code is just for debugging, to cause Notify to write its output to a
302 // log file we can inspect, so we can see the error messages output by DX7
303 // or DX8 just before it does a panic exit (and thereby shuts down Maya and
304 // its output window).
305 /*
306 MultiplexStream *local_nout = new MultiplexStream();
307 Notify::ptr()->set_ostream_ptr(local_nout, 0);
308 local_nout->add_file(Filename::expand_from("$TEMP/libmayapview.log"));
309 local_nout->add_standard_output();
310 */
311
312 MFnPlugin plugin(obj, "VR Studio", "1.0");
313 MStatus status;
314 status = plugin.registerCommand("pview", MayaPview::creator);
315 if (!status) {
316 status.perror("registerCommand");
317 }
318
319 return status;
320 }
321
322 /**
323 * Called by Maya when the plugin is unloaded.
324 */
325 EXPCL_MISC MStatus
326 uninitializePlugin(MObject obj) {
327 MFnPlugin plugin(obj);
328 MStatus status;
329 status = plugin.deregisterCommand("pview");
330
331 if (!status) {
332 status.perror("deregisterCommand");
333 }
334 return status;
335 }
ConfigVariableEnum
This class specializes ConfigVariable as an enumerated type.
Definition: configVariableEnum.h:31
DSearchPath::append_path
void append_path(const std::string &path, const std::string &separator=std::string())
Adds all of the directories listed in the search path to the end of the search list.
Definition: dSearchPath.cxx:164
DSearchPath::append_directory
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
Definition: dSearchPath.cxx:147
EggData
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition: eggData.h:37
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
Filename::unlink
bool unlink() const
Permanently deletes the file associated with the filename, if possible.
Definition: filename.cxx:2319
Filename::get_fullpath
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
Definition: filename.I:338
Filename::temporary
static Filename temporary(const std::string &dirname, const std::string &prefix, const std::string &suffix=std::string(), Type type=T_general)
Generates a temporary filename within the indicated directory, using the indicated prefix.
Definition: filename.cxx:424
Filename::from_os_specific
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...
Definition: filename.cxx:328
Filename::set_extension
void set_extension(const std::string &s)
Replaces the file extension.
Definition: filename.cxx:804
Filename::get_dirname
std::string get_dirname() const
Returns the directory part of the filename.
Definition: filename.I:358
MayaPview
This class serves as a plug-in to Maya to allow viewing the current Maya selection as it will be conv...
Definition: mayaPview.h:30
MayaPview::creator
static void * creator()
This is used to create a new instance of the plugin.
Definition: mayaPview.cxx:213
MayaPview::doIt
virtual MStatus doIt(const MArgList &args)
Called when the plugin command is invoked.
Definition: mayaPview.cxx:63
MayaToEggConverter
This class supervises the construction of an EggData structure from a single Maya file,...
Definition: mayaToEggConverter.h:52
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
NodePath::remove_node
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:624
NodePath::write_bam_file
bool write_bam_file(const Filename &filename) const
Writes the contents of this node and below out to a bam file with the indicated filename.
Definition: nodePath.cxx:5689
NodePath::attach_new_node
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
Definition: nodePath.cxx:596
NodePath::set_scale
void set_scale(PN_stdfloat scale)
Sets the scale component of the transform, leaving translation and rotation untouched.
Definition: nodePath.I:675
NodePath::instance_to
NodePath instance_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Adds the referenced node of the NodePath as a child of the referenced node of the indicated other Nod...
Definition: nodePath.cxx:471
PandaFramework
This class serves to provide a high-level framework for basic applications that use Panda in simple w...
Definition: pandaFramework.h:38
PandaFramework::open_window
WindowFramework * open_window()
Opens a window on the default graphics pipe.
Definition: pandaFramework.cxx:335
PandaFramework::enable_default_keys
void enable_default_keys()
Sets callbacks on the event handler to handle all of the normal viewer keys, like t to toggle texture...
Definition: pandaFramework.cxx:735
PandaFramework::open_framework
void open_framework()
Should be called once at the beginning of the application to initialize Panda (and the framework) for...
Definition: pandaFramework.cxx:85
PandaFramework::set_window_title
void set_window_title(const std::string &title)
Specifies the title that is set for all subsequently created windows.
Definition: pandaFramework.I:60
PandaFramework::get_models
NodePath & get_models()
Returns the root of the scene graph normally reserved for parenting models and such.
Definition: pandaFramework.cxx:537
PandaFramework::main_loop
void main_loop()
Called to yield control to the panda framework.
Definition: pandaFramework.cxx:761
PandaFramework::do_frame
virtual bool do_frame(Thread *current_thread)
Renders one frame and performs all associated processing.
Definition: pandaFramework.cxx:748
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
PathReplace
This encapsulates the user's command-line request to replace existing, incorrect pathnames to models ...
Definition: pathReplace.h:36
TextNode
The primary interface to this module.
Definition: textNode.h:48
Thread::get_current_thread
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
WindowFramework
This encapsulates the data that is normally associated with a single window, or with a single display...
Definition: windowFramework.h:51
configVariableEnum.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_chan.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_gobj.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_putil.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
format_long_unit
string format_long_unit(DistanceUnit unit)
Returns the string representing the full name (plural) for the given unit.
Definition: distanceUnit.cxx:67
convert_units
double convert_units(DistanceUnit from, DistanceUnit to)
Returns the scaling factor that must be applied to convert from units of "from" to "to".
Definition: distanceUnit.cxx:213
distanceUnit.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DistanceUnit
DistanceUnit
This enumerated type lists all the kinds of units we're likely to come across in model conversion pro...
Definition: distanceUnit.h:23
eggData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
load_egg_file.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
uninitializePlugin
EXPCL_MISC MStatus uninitializePlugin(MObject obj)
Called by Maya when the plugin is unloaded.
Definition: mayaPview.cxx:326
initializePlugin
EXPCL_MISC MStatus initializePlugin(MObject obj)
Called by Maya when the plugin is loaded.
Definition: mayaPview.cxx:300
mayaPview.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
mayaToEggConverter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
multiplexStream.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
post_maya_include.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pre_maya_include.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
textNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.