Panda3D
Loading...
Searching...
No Matches
mayaToEgg_server.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 mayaToEgg_server.cxx
10 * @author cbrunner
11 * @date 2009-11-09
12 */
13
14#if defined(WIN32_VC) || defined(WIN64_VC)
15#include <direct.h> // for chdir
16#endif
17#include "mayaToEgg_server.h"
18#include "mayaToEggConverter.h"
19#include "config_mayaegg.h"
20#include "config_maya.h" // for maya_cat
21#include "globPattern.h"
22
23/**
24 *
25 */
26MayaToEggServer::
27MayaToEggServer() :
28 SomethingToEgg("Maya", ".mb")
29{
30 add_path_replace_options();
31 add_path_store_options();
32 add_animation_options();
33 add_units_options();
34 add_normals_options();
35 add_transform_options();
36
37 set_program_brief("convert Maya model files to .egg");
38 set_program_description
39 ("This program converts Maya model files to egg. Static and animatable "
40 "models can be converted, with polygon or NURBS output. Animation tables "
41 "can also be generated to apply to an animatable model.");
42
43 add_option
44 ("p", "", 0,
45 "Generate polygon output only. Tesselate all NURBS surfaces to "
46 "polygons via the built-in Maya tesselator. The tesselation will "
47 "be based on the tolerance factor given by -ptol.",
48 &MayaToEggServer::dispatch_none, &_polygon_output);
49
50 add_option
51 ("ptol", "tolerance", 0,
52 "Specify the fit tolerance for Maya polygon tesselation. The smaller "
53 "the number, the more polygons will be generated. The default is "
54 "0.01.",
55 &MayaToEggServer::dispatch_double, nullptr, &_polygon_tolerance);
56
57 add_option
58 ("bface", "", 0,
59 "Respect the Maya \"double sided\" rendering flag to indicate whether "
60 "polygons should be double-sided or single-sided. Since this flag "
61 "is set to double-sided by default in Maya, it is often better to "
62 "ignore this flag (unless your modelers are diligent in turning it "
63 "off where it is not desired). If this flag is not specified, the "
64 "default is to treat all polygons as single-sided, unless an "
65 "egg object type of \"double-sided\" is set.",
66 &MayaToEggServer::dispatch_none, &_respect_maya_double_sided);
67
68 add_option
69 ("suppress-vcolor", "", 0,
70 "Ignore vertex color for geometry that has a texture applied. "
71 "(This is the way Maya normally renders internally.) The egg flag "
72 "'vertex-color' may be applied to a particular model to override "
73 "this setting locally.",
74 &MayaToEggServer::dispatch_none, &_suppress_vertex_color);
75
76 add_option
77 ("keep-uvs", "", 0,
78 "Convert all UV sets on all vertices, even those that do not appear "
79 "to be referenced by any textures.",
80 &MayaToEggServer::dispatch_none, &_keep_all_uvsets);
81
82 add_option
83 ("round-uvs", "", 0,
84 "round up uv coordinates to the nearest 1/100th. i.e. -0.001 becomes"
85 "0.0; 0.444 becomes 0.44; 0.778 becomes 0.78.",
86 &MayaToEggServer::dispatch_none, &_round_uvs);
87
88 add_option
89 ("trans", "type", 0,
90 "Specifies which transforms in the Maya file should be converted to "
91 "transforms in the egg file. The option may be one of all, model, "
92 "dcs, or none. The default is model, which means only transforms on "
93 "nodes that have the model flag or the dcs flag are preserved.",
94 &MayaToEggServer::dispatch_transform_type, nullptr, &_transform_type);
95
96 add_option
97 ("subroot", "name", 0,
98 "Specifies that only a subroot of the geometry in the Maya file should "
99 "be converted; specifically, the geometry under the node or nodes whose "
100 "name matches the parameter (which may include globbing characters "
101 "like * or ?). This parameter may be repeated multiple times to name "
102 "multiple roots. If it is omitted altogether, the entire file is "
103 "converted.",
104 &MayaToEggServer::dispatch_vector_string, nullptr, &_subroots);
105
106 add_option
107 ("subset", "name", 0,
108 "Specifies that only a subset of the geometry in the Maya file should "
109 "be converted; specifically, the geometry under the node or nodes whose "
110 "name matches the parameter (which may include globbing characters "
111 "like * or ?). This parameter may be repeated multiple times to name "
112 "multiple roots. If it is omitted altogether, the entire file is "
113 "converted.",
114 &MayaToEggServer::dispatch_vector_string, nullptr, &_subsets);
115
116 add_option
117 ("exclude", "name", 0,
118 "Specifies that a subset of the geometry in the Maya file should "
119 "not be converted; specifically, the geometry under the node or nodes whose "
120 "name matches the parameter (which may include globbing characters "
121 "like * or ?). This parameter may be repeated multiple times to name "
122 "multiple roots.",
123 &MayaToEggServer::dispatch_vector_string, nullptr, &_excludes);
124
125 add_option
126 ("ignore-slider", "name", 0,
127 "Specifies the name of a slider (blend shape deformer) that maya2egg "
128 "should not process. The slider will not be touched during conversion "
129 "and it will not become a part of the animation. This "
130 "parameter may including globbing characters, and it may be repeated "
131 "as needed.",
132 &MayaToEggServer::dispatch_vector_string, nullptr, &_ignore_sliders);
133
134 add_option
135 ("force-joint", "name", 0,
136 "Specifies the name of a DAG node that maya2egg "
137 "should treat as a joint, even if it does not appear to be a Maya joint "
138 "and does not appear to be animated.",
139 &MayaToEggServer::dispatch_vector_string, nullptr, &_force_joints);
140
141 add_option
142 ("v", "", 0,
143 "Increase verbosity. More v's means more verbose.",
144 &MayaToEggServer::dispatch_count, nullptr, &_verbose);
145
146 add_option
147 ("legacy-shaders", "", 0,
148 "Use this flag to turn off modern (Phong) shader generation"
149 "and treat all shaders as if they were Lamberts (legacy).",
150 &MayaToEggServer::dispatch_none, &_legacy_shader);
151
152 // Unfortunately, the Maya API doesn't allow us to differentiate between
153 // relative and absolute pathnames--everything comes out as an absolute
154 // pathname, even if it is stored in the Maya file as a relative path. So
155 // we can't support -noabs.
156 remove_option("noabs");
157
158 _verbose = 0;
159 _polygon_tolerance = 0.01;
160 _transform_type = MayaToEggConverter::TT_model;
161 _got_tbnauto = true;
162 qManager = new QueuedConnectionManager();
163 qListener = new QueuedConnectionListener(qManager, 0);
164 qReader = new QueuedConnectionReader(qManager, 0);
165 cWriter = new ConnectionWriter(qManager, 0);
166 dummy = new MayaToEggConverter();
167
168 nout << "Initializing Maya...\n";
169 if (!dummy->open_api()) {
170 nout << "Unable to initialize Maya.\n";
171 exit(1);
172 }
173}
174/**
175 *
176 */
177MayaToEggServer::
178~MayaToEggServer() {
179 delete qManager;
180 delete qReader;
181 delete qListener;
182 delete cWriter;
183 delete dummy;
184}
185
186/**
187 *
188 */
189void MayaToEggServer::
190run() {
191 // Make sure we have good clean data to start with
192 _data = new EggData();
193
194 // Set the verbose level by using Notify.
195 if (_verbose >= 3) {
196 maya_cat->set_severity(NS_spam);
197 mayaegg_cat->set_severity(NS_spam);
198 } else if (_verbose >= 2) {
199 maya_cat->set_severity(NS_debug);
200 mayaegg_cat->set_severity(NS_debug);
201 } else if (_verbose >= 1) {
202 maya_cat->set_severity(NS_info);
203 mayaegg_cat->set_severity(NS_info);
204 }
205
206 // Let's convert the output file to a full path before we initialize Maya,
207 // since Maya now has a nasty habit of changing the current directory.
208 if (_got_output_filename) {
209 _output_filename.make_absolute();
210 _path_replace->_path_directory.make_absolute();
211 }
212
213 MayaToEggConverter converter(_program_name);
214
215 // Copy in the command-line parameters.
216 converter._polygon_output = _polygon_output;
217 converter._polygon_tolerance = _polygon_tolerance;
218 converter._respect_maya_double_sided = _respect_maya_double_sided;
219 converter._always_show_vertex_color = !_suppress_vertex_color;
220 converter._keep_all_uvsets = _keep_all_uvsets;
221 converter._round_uvs = _round_uvs;
222 converter._transform_type = _transform_type;
223 converter._legacy_shader = _legacy_shader;
224
225 vector_string::const_iterator si;
226 if (!_subroots.empty()) {
227 converter.clear_subroots();
228 for (si = _subroots.begin(); si != _subroots.end(); ++si) {
229 converter.add_subroot(GlobPattern(*si));
230 }
231 }
232
233 if (!_subsets.empty()) {
234 converter.clear_subsets();
235 for (si = _subsets.begin(); si != _subsets.end(); ++si) {
236 converter.add_subset(GlobPattern(*si));
237 }
238 }
239
240 if (!_excludes.empty()) {
241 converter.clear_excludes();
242 for (si = _excludes.begin(); si != _excludes.end(); ++si) {
243 converter.add_exclude(GlobPattern(*si));
244 }
245 }
246
247 if (!_ignore_sliders.empty()) {
248 converter.clear_ignore_sliders();
249 for (si = _ignore_sliders.begin(); si != _ignore_sliders.end(); ++si) {
250 converter.add_ignore_slider(GlobPattern(*si));
251 }
252 }
253
254 if (!_force_joints.empty()) {
255 converter.clear_force_joints();
256 for (si = _force_joints.begin(); si != _force_joints.end(); ++si) {
257 converter.add_force_joint(GlobPattern(*si));
258 }
259 }
260
261 // Copy in the path and animation parameters.
262 apply_parameters(converter);
263
264 // Set the coordinate system to match Maya's.
265 if (!_got_coordinate_system) {
266 _coordinate_system = converter._maya->get_coordinate_system();
267 }
268 _data->set_coordinate_system(_coordinate_system);
269
270 converter.set_egg_data(_data);
271
272 if (!converter.convert_file(_input_filename)) {
273 nout << "Errors in conversion.\n";
274 exit(1);
275 }
276
277 // Use the standard Maya units, if the user didn't specify otherwise. This
278 // always returns centimeters, which is the way all Maya files are stored
279 // internally (and is the units returned by all of the API functions called
280 // here).
281 if (_input_units == DU_invalid) {
282 _input_units = converter.get_input_units();
283 }
284
285 // Add the command line comment at the top of the egg file
286 append_command_comment(_data);
287
289
290 // Clean and out
291 close_output();
292 _verbose = 0;
293 _polygon_tolerance = 0.01;
294 _polygon_output = 0;
295 _transform_type = MayaToEggConverter::TT_model;
296 _subsets.clear();
297 _subroots.clear();
298 _input_units = DU_invalid;
299 _output_units = DU_invalid;
300 _excludes.clear();
301 _ignore_sliders.clear();
302 _force_joints.clear();
303 _got_transform = false;
304 _transform = LMatrix4d::ident_mat();
305 _normals_mode = NM_preserve;
306 _normals_threshold = 0.0;
307 _got_start_frame = false;
308 _got_end_frame = false;
309 _got_frame_inc = false;
310 _got_neutral_frame = false;
311 _got_input_frame_rate = false;
312 _got_output_frame_rate = false;
313 _got_output_filename = false;
314 _merge_externals = false;
315 _got_tbnall = false;
316 _got_tbnauto = false;
317 _got_transform = false;
318 _coordinate_system = CS_yup_right;
319 _noabs = false;
320 _program_args.clear();
321 _data->clear();
322 _animation_convert = AC_none;
323 _character_name = "";
324 dummy->clear();
325}
326
327/**
328 * Dispatches a parameter that expects a MayaToEggConverter::TransformType
329 * option.
330 */
331bool MayaToEggServer::
332dispatch_transform_type(const std::string &opt, const std::string &arg, void *var) {
333 MayaToEggConverter::TransformType *ip = (MayaToEggConverter::TransformType *)var;
335
336 if ((*ip) == MayaToEggConverter::TT_invalid) {
337 nout << "Invalid type for -" << opt << ": " << arg << "\n"
338 << "Valid types are all, model, dcs, and none.\n";
339 return false;
340 }
341
342 return true;
343}
344
345/**
346 * Checks for any network activity and handles it, if appropriate, and then
347 * returns. This must be called periodically
348 */
350poll() {
351 // Listen for new connections
352 qListener->poll();
353
354 // If we have a new connection from a client create a new connection pointer
355 // and add it to the reader list
356 if (qListener->new_connection_available()) {
357 PT(Connection) con;
358 PT(Connection) rv;
359 NetAddress address;
360 if (qListener->get_new_connection(rv, address, con)) {
361 qReader->add_connection(con);
362 _clients.insert(con);
363 }
364 }
365
366 // Check for reset clients
367 if (qManager->reset_connection_available()) {
368 PT(Connection) connection;
369 if (qManager->get_reset_connection(connection)) {
370 _clients.erase(connection);
371 qManager->close_connection(connection);
372 }
373 }
374
375 // Poll the readers (created above) and if they have data process it
376 qReader->poll();
377 if (qReader->data_available()) {
378 // Grab the incomming data and unpack it
379 NetDatagram datagram;
380 if (qReader->get_data(datagram)) {
381 DatagramIterator data(datagram);
382 // First data should be the "argc" (argument count) from the client
383 int argc = data.get_uint8();
384
385 // Now we have to get clever because the rest of the data comes as
386 // strings and parse_command_line() expects arguments of the standard
387 // argc, argv*[] variety. First, we need a string vector to hold all
388 // the strings from the datagram. We also need a char * array to keep
389 // track of all the pointers we're gonna malloc. Needed later for
390 // cleanup.
391 vector_string vargv;
392 std::vector<char *> buffers;
393
394 // Get the strings from the datagram and put them into the string vector
395 int i;
396 for ( i = 0; i < argc; i++ ) {
397 vargv.push_back(data.get_string());
398 }
399
400 // Last string is the current directory the client was run from. Not
401 // part of the argument list, but we still need it
402 std::string cwd = data.get_string();
403
404 // We allocate some memory to hold the pointers to the pointers we're
405 // going to pass in to parse_command_line().
406 char ** cargv = (char**) malloc(sizeof(char**) * argc);
407
408 // Loop through the string arguments we got from the datagram and
409 // convert them to const char *'s. parse_command_line() expects char
410 // *'s, so we have to copy these const versions into fresh char *, since
411 // there is no casting from const char * to char *.
412 for ( i = 0; i < argc; i++) {
413 // string to const char *
414 const char * cptr = vargv[i].c_str();
415 // memory allocated for a new char * of size of the string
416 char * buffer = (char*) malloc(vargv[i].capacity()+1);
417 // Copy the const char * to the char *
418 strcpy(buffer, cptr);
419 // put this into the arry we defined above. This is what will
420 // eventually be passed to parse_command_line()
421 cargv[i] = buffer;
422 // keep track of the pointers to the allocated memory for cleanup
423 // later
424 buffers.push_back(buffer);
425 }
426 // Change to the client's current dir
427#ifdef WIN64_VC
428 _chdir(cwd.c_str());
429#else
430 chdir(cwd.c_str());
431#endif
432
433 // Pass in the 'new' argc and argv we got from the client
434 this->parse_command_line(argc, cargv);
435 // Actually run the damn thing
436 this->run();
437
438 // Cleanup First, release the string vector
439 vargv.clear();
440 // No, iterate through the char * vector and cleanup the malloc'd
441 // pointers
442 std::vector<char *>::iterator vi;
443 for ( vi = buffers.begin() ; vi != buffers.end(); vi++) {
444 free(*vi);
445 }
446 // Clean up the malloc'd pointer pointer
447 free(cargv);
448 } // qReader->get_data
449
450 Clients::iterator ci;
451 for (ci = _clients.begin(); ci != _clients.end(); ++ci) {
452 qManager->close_connection(*ci);
453 }
454 } // qReader->data_available
455} // poll
456
457int main(int argc, char *argv[]) {
458 MayaToEggServer prog;
459 // Open a rendezvous port for receiving new connections from the client
460 PT(Connection) rend = prog.qManager->open_TCP_server_rendezvous(4242, 50);
461 if (rend.is_null()) {
462 nout << "port opened fail";
463 }
464
465 // Add this connection to the listeners list
466 prog.qListener->add_connection(rend);
467
468 // Main loop. Keep polling for connections, but don't eat up all the CPU.
469 while (true) {
470 prog.poll();
472 }
473 return 0;
474}
PT(Connection) open_TCP_client_connection(const std bool close_connection(const PT(Connection) &connection)
Terminates a UDP or TCP socket previously opened.
void poll()
Explicitly polls the available sockets to see if any of them have any noise.
bool add_connection(Connection *connection)
Adds a new socket to the list of sockets the ConnectionReader will monitor.
This class handles threaded delivery of datagrams to various TCP or UDP sockets.
Represents a single TCP or UDP socket for input or output.
Definition connection.h:29
A class to retrieve the individual data elements previously stored in a Datagram.
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition eggData.h:37
void write_egg_file()
Writes out the egg file as the normal result of the program.
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
Definition globPattern.h:32
This class supervises the construction of an EggData structure from a single Maya file,...
static TransformType string_transform_type(const std::string &arg)
Returns the TransformType value corresponding to the indicated string, or TT_invalid.
void clear()
Frees all of the Maya pointers kept within this object, in preparation for loading a new scene or rel...
void poll()
Checks for any network activity and handles it, if appropriate, and then returns.
Represents a network address to which UDP packets may be sent or to which a TCP socket may be bound.
Definition netAddress.h:25
A specific kind of Datagram, especially for sending across or receiving from a network.
Definition netDatagram.h:40
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
This flavor of ConnectionListener will queue up all of the TCP connections it established for later d...
bool get_new_connection(PT(Connection) &rendezvous, NetAddress &address, PT(Connection) &new_connection)
If a previous call to new_connection_available() returned true, this function will return information...
bool new_connection_available()
Returns true if a new connection was recently established; the connection information may then be ret...
This flavor of ConnectionManager will queue up all of the reset-connection messages from the Connecti...
bool reset_connection_available() const
Returns true if one of the readers/writers/listeners reported a connection reset recently.
bool get_reset_connection(PT(Connection) &connection)
If a previous call to reset_connection_available() returned true, this function will return informati...
This flavor of ConnectionReader will read from its sockets and queue up all of the datagrams read for...
bool get_data(NetDatagram &result)
If a previous call to data_available() returned true, this function will return the datagram that has...
bool data_available()
Returns true if a datagram is available on the queue; call get_data() to extract the datagram.
This is the general base class for a file-converter program that reads some model file format and gen...
static void force_yield()
Suspends the current thread for the rest of the current epoch.
Definition thread.I:201
void close_output()
Closes the output stream previously opened by get_output().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.