mayaprogs: Completely refactor the maya2egg server

The maya2egg_server utility is no longer a separate utility. To run the maya2egg_server (now Maya conversion server), use `maya2egg -server` or `egg2maya -server`.

Two new utilities have been added: `maya2egg_client` and `egg2maya_client`. Both of them are Maya version independent, and do not rely on any Maya libraries. However, they're only built with SDKs that already come with the Maya binaries, as the server makes its own assumptions about the current working directory (the client and the server are expected to be on the same machine.)

A new feature has been added to ProgramBase: an `exit_on_complete` flag, which allows you to parse the command line without exiting the program upon a failure or a help command.

In addition to this, a getopt bug has been fixed in ProgramBase: It is now possible to clear the state of the Panda implementation of getopt, making it possible once again to parse command line arguments twice in a row.

Closes #1025
This commit is contained in:
Daniel 2020-12-29 16:16:36 +01:00 committed by rdb
parent 33d688ec08
commit 74a4648965
25 changed files with 903 additions and 715 deletions

View File

@ -491,4 +491,13 @@ getopt_long_only(int argc, char *const argv[], const char *optstring,
return pgetopt->process(opterr, longindex, optarg, optind, optopt);
}
/**
* Resets the internal PandaGetopt state.
* This is a necessary step to reset getopt state in general.
*/
void
pgetopt_reset() {
pgetopt = nullptr;
}
#endif // defined(HAVE_GETOPT) && defined(HAVE_GETOPT_LONG_ONLY)

View File

@ -62,6 +62,8 @@ getopt_long(int argc, char *const argv[], const char *optstring,
extern EXPCL_DTOOL_DTOOLUTIL int
getopt_long_only(int argc, char *const argv[], const char *optstring,
const struct option *longopts, int *longindex);
extern EXPCL_DTOOL_DTOOLUTIL void
pgetopt_reset();
#ifdef __cplusplus
}

View File

@ -5769,6 +5769,8 @@ if not PkgSkip("PANDATOOL"):
# DIRECTORY: pandatool/src/mayaprogs/
#
MAYA_BUILT = False
for VER in MAYAVERSIONS:
VNUM = VER[4:]
if PkgSkip(VER) or PkgSkip("PANDATOOL") or PkgSkip("EGG"):
@ -5785,6 +5787,8 @@ for VER in MAYAVERSIONS:
else:
ARCH_OPTS = []
MAYA_BUILT = True
OPTS=['DIR:pandatool/src/mayaprogs', 'DIR:pandatool/src/maya', 'DIR:pandatool/src/mayaegg', 'BUILDING:MISC', VER] + ARCH_OPTS
TargetAdd('mayaeggimport'+VNUM+'_mayaeggimport.obj', opts=OPTS, input='mayaEggImport.cxx')
TargetAdd('mayaeggimport'+VNUM+'.mll', input='mayaegg'+VNUM+'_loader.obj')
@ -5822,30 +5826,31 @@ for VER in MAYAVERSIONS:
TargetAdd('libmayapview'+VNUM+'.mll', input='libmayaegg'+VNUM+'.lib')
TargetAdd('libmayapview'+VNUM+'.mll', input='libmaya'+VNUM+'.lib')
TargetAdd('libmayapview'+VNUM+'.mll', input='libp3framework.dll')
if GetTarget() == 'windows':
TargetAdd('libmayapview'+VNUM+'.mll', input=COMMON_EGG2X_LIBS)
else:
TargetAdd('libmayapview'+VNUM+'.mll', input=COMMON_EGG2X_LIBS)
TargetAdd('libmayapview'+VNUM+'.mll', input=COMMON_EGG2X_LIBS)
TargetAdd('libmayapview'+VNUM+'.mll', opts=['ADVAPI', VER]+ARCH_OPTS)
TargetAdd('maya2egg'+VNUM+'_mayaToEgg.obj', opts=OPTS, input='mayaToEgg.cxx')
TargetAdd('maya2egg'+VNUM+'_bin.exe', input='maya2egg'+VNUM+'_mayaToEgg.obj')
TargetAdd('mayaprogs'+VNUM+'_eggToMaya.obj', opts=OPTS, input='eggToMaya.cxx')
TargetAdd('mayaprogs'+VNUM+'_mayaToEgg.obj', opts=OPTS, input='mayaToEgg.cxx')
TargetAdd('mayaprogs_mayaConversionServer.obj', opts=OPTS, input='mayaConversionServer.cxx')
TargetAdd('maya2egg'+VNUM+'_mayaToEggBin.obj', opts=OPTS, input='mayaToEggBin.cxx')
TargetAdd('maya2egg'+VNUM+'_bin.exe', input='mayaprogs'+VNUM+'_eggToMaya.obj')
TargetAdd('maya2egg'+VNUM+'_bin.exe', input='mayaprogs'+VNUM+'_mayaToEgg.obj')
TargetAdd('maya2egg'+VNUM+'_bin.exe', input='mayaprogs_mayaConversionServer.obj')
TargetAdd('maya2egg'+VNUM+'_bin.exe', input='maya2egg'+VNUM+'_mayaToEggBin.obj')
TargetAdd('maya2egg'+VNUM+'_bin.exe', input='libmayaegg'+VNUM+'.lib')
TargetAdd('maya2egg'+VNUM+'_bin.exe', input='libmaya'+VNUM+'.lib')
if GetTarget() == 'windows':
TargetAdd('maya2egg'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS)
else:
TargetAdd('maya2egg'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS)
TargetAdd('maya2egg'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS)
TargetAdd('maya2egg'+VNUM+'_bin.exe', opts=['ADVAPI', VER]+ARCH_OPTS)
TargetAdd('egg2maya'+VNUM+'_eggToMaya.obj', opts=OPTS, input='eggToMaya.cxx')
TargetAdd('egg2maya'+VNUM+'_bin.exe', input='egg2maya'+VNUM+'_eggToMaya.obj')
TargetAdd('egg2maya'+VNUM+'_eggToMayaBin.obj', opts=OPTS, input='eggToMayaBin.cxx')
TargetAdd('egg2maya'+VNUM+'_bin.exe', input='mayaprogs'+VNUM+'_eggToMaya.obj')
TargetAdd('egg2maya'+VNUM+'_bin.exe', input='mayaprogs'+VNUM+'_mayaToEgg.obj')
TargetAdd('egg2maya'+VNUM+'_bin.exe', input='mayaprogs_mayaConversionServer.obj')
TargetAdd('egg2maya'+VNUM+'_bin.exe', input='egg2maya'+VNUM+'_eggToMayaBin.obj')
TargetAdd('egg2maya'+VNUM+'_bin.exe', input='libmayaegg'+VNUM+'.lib')
TargetAdd('egg2maya'+VNUM+'_bin.exe', input='libmaya'+VNUM+'.lib')
if GetTarget() == 'windows':
TargetAdd('egg2maya'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS)
else:
TargetAdd('egg2maya'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS)
TargetAdd('egg2maya'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS)
TargetAdd('egg2maya'+VNUM+'_bin.exe', opts=['ADVAPI', VER]+ARCH_OPTS)
TargetAdd('mayasavepview'+VNUM+'_mayaSavePview.obj', opts=OPTS, input='mayaSavePview.cxx')
@ -5864,6 +5869,19 @@ for VER in MAYAVERSIONS:
TargetAdd('egg2maya'+VNUM+'.exe', input=COMMON_DTOOL_LIBS)
TargetAdd('egg2maya'+VNUM+'.exe', opts=['ADVAPI']+ARCH_OPTS)
if MAYA_BUILT:
TargetAdd('mayaprogs_mayaConversionClient.obj', opts=OPTS, input='mayaConversionClient.cxx')
TargetAdd('maya2egg_mayaToEggClient.obj', opts=OPTS, input='mayaToEggClient.cxx')
TargetAdd('maya2egg_client.exe', input='mayaprogs_mayaConversionClient.obj')
TargetAdd('maya2egg_client.exe', input='maya2egg_mayaToEggClient.obj')
TargetAdd('maya2egg_client.exe', input=COMMON_EGG2X_LIBS)
TargetAdd('egg2maya_eggToMayaClient.obj', opts=OPTS, input='eggToMayaClient.cxx')
TargetAdd('egg2maya_client.exe', input='mayaprogs_mayaConversionClient.obj')
TargetAdd('egg2maya_client.exe', input='egg2maya_eggToMayaClient.obj')
TargetAdd('egg2maya_client.exe', input=COMMON_EGG2X_LIBS)
#
# DIRECTORY: contrib/src/ai/
#

View File

@ -55,6 +55,7 @@ EggReader() {
_got_tex_dirname = false;
_got_tex_extension = false;
_exit_on_failure = true;
}
/**
@ -124,6 +125,16 @@ add_delod_options(double default_delod) {
}
}
/**
* Sets whether the reader will quit the program upon encountering a fatal error.
*
* If true, the entire program will quit as soon as an egg loading error occurs.
*/
void EggReader::
set_exit_on_failure(bool exit_on_failure) {
_exit_on_failure = exit_on_failure;
}
/**
* Returns this object as an EggReader pointer, if it is in fact an EggReader,
* or NULL if it is not.
@ -175,18 +186,27 @@ handle_args(ProgramBase::Args &args) {
// Rather than returning false, we simply exit here, so the ProgramBase
// won't try to tell the user how to run the program just because we got
// a bad egg file.
exit(1);
if (_exit_on_failure) {
exit(1);
}
return false;
}
} else {
if (!file_data.read(std::cin)) {
exit(1);
if (_exit_on_failure) {
exit(1);
}
return false;
}
}
if (_noabs && file_data.original_had_absolute_pathnames()) {
nout << filename.get_basename()
<< " includes absolute pathnames!\n";
exit(1);
if (_exit_on_failure) {
exit(1);
}
return false;
}
DSearchPath file_path;
@ -194,7 +214,10 @@ handle_args(ProgramBase::Args &args) {
if (_force_complete) {
if (!file_data.load_externals(file_path)) {
exit(1);
if (_exit_on_failure) {
exit(1);
}
return false;
}
}

View File

@ -31,6 +31,7 @@ public:
void add_texture_options();
void add_delod_options(double default_delod = -1.0);
void set_exit_on_failure(bool exit_on_failure);
virtual EggReader *as_reader();
virtual void pre_process_egg_file();
@ -47,6 +48,7 @@ private:
protected:
bool _force_complete;
bool _exit_on_failure;
private:
Filename _tex_dirname;

View File

@ -31,7 +31,7 @@
using std::string;
MayaApi *MayaApi::_global_api = nullptr;
PT(MayaApi) MayaApi::_global_api = nullptr;
// We need this bogus object just to force the application to link with
// OpenMayaAnim.lib; otherwise, Maya will complain (when compiled on Windows)
@ -217,6 +217,15 @@ open_api(string program_name, bool view_license, bool revertdir) {
return _global_api;
}
/**
* Returns true if the global API has been successfully opened and may be used, or
* false if the API has not created yet or if there is some problem.
*/
bool MayaApi::
is_api_valid() {
return _global_api != nullptr && _global_api->is_valid();
}
/**
* Returns true if the API has been successfully opened and may be used, or
* false if there is some problem.

View File

@ -37,6 +37,7 @@ public:
~MayaApi();
static PT(MayaApi) open_api(std::string program_name = "", bool view_license = false, bool revertdir = true);
static bool is_api_valid();
bool is_valid() const;
bool read(const Filename &filename);
@ -51,7 +52,7 @@ private:
bool _is_valid;
bool _plug_in;
Filename _cwd;
static MayaApi *_global_api;
static PT(MayaApi) _global_api;
};
#endif

View File

@ -14,6 +14,7 @@
#include "eggToMaya.h"
#include "mayaEggLoader.h"
#include "mayaApi.h"
#include "mayaConversionServer.h"
// We must define this to prevent Maya from doubly-declaring its MApiVersion
// string in this file as well as in libmayaegg.
@ -56,14 +57,40 @@ EggToMaya() :
"respect vertex and polygon normals.",
&EggToMaya::dispatch_none, &_respect_normals);
add_option("server", "", 0,
"Runs the Maya model conversion server. This server can be used in tandem "
"with the egg2maya_client and maya2egg_client utilities to batch convert "
"both Maya and Panda3D model files.",
&EggToMaya::dispatch_none, &_run_server);
// Maya files always store centimeters.
_output_units = DU_centimeters;
}
/**
*
* Attempts to create the global Maya API.
* Exits the program if unsuccessful.
*/
void EggToMaya::
PT(MayaApi) EggToMaya::
open_api() {
if (!MayaApi::is_api_valid()) {
nout << "Initializing Maya...\n";
}
PT(MayaApi) api = MayaApi::open_api(_program_name, true, true);
if (!api || !api->is_valid()) {
nout << "Unable to initialize Maya.\n";
exit(1);
}
return api;
}
/**
* Returns true if the model has been successfully converted.
*/
bool EggToMaya::
run() {
if (!_convert_anim && !_convert_model) {
_convert_model = true;
@ -73,18 +100,13 @@ run() {
// since Maya now has a nasty habit of changing the current directory.
_output_filename.make_absolute();
nout << "Initializing Maya.\n";
PT(MayaApi) maya = MayaApi::open_api(_program_name);
if (!maya->is_valid()) {
nout << "Unable to initialize Maya.\n";
exit(1);
}
PT(MayaApi) maya = open_api();
MStatus status;
status = MFileIO::newFile(true);
if (!status) {
status.perror("Could not initialize file");
exit(1);
return false;
}
// [gjeon] since maya's internal unit is fixed to cm and when we can't
@ -101,12 +123,12 @@ run() {
// Now convert the data.
if (!MayaLoadEggData(_data, true, _convert_model, _convert_anim, _respect_normals)) {
nout << "Unable to convert egg file.\n";
exit(1);
return false;
}
if (!maya->write(_output_filename)) {
status.perror("Could not save file");
exit(1);
return false;
}
/*
@ -119,14 +141,29 @@ run() {
status = MFileIO::saveAs(os_specific.c_str(), file_type);
if (!status) {
status.perror("Could not save file");
exit(1);
return false;
}
*/
return true;
}
int main(int argc, char *argv[]) {
EggToMaya prog;
prog.parse_command_line(argc, argv);
prog.run();
return 0;
/**
* Processes the arguments parsed by the program.
*
* If the server flag is specified, the Maya conversion server is started
* up rather than the usual conversion utility functionality.
*/
bool EggToMaya::
handle_args(ProgramBase::Args &args) {
if (_run_server) {
open_api();
MayaConversionServer server;
server.listen();
exit(0);
return true;
}
return EggToSomething::handle_args(args);
}

View File

@ -17,6 +17,9 @@
#include "pandatoolbase.h"
#include "eggToSomething.h"
#include "mayaApi.h"
#include "programBase.h"
/**
* A program to read an egg file and write a maya file.
@ -25,12 +28,17 @@ class EggToMaya : public EggToSomething {
public:
EggToMaya();
void run();
bool run();
private:
virtual bool handle_args(ProgramBase::Args &args);
PT(MayaApi) open_api();
bool _convert_anim;
bool _convert_model;
bool _respect_normals;
bool _run_server;
};
#endif

View File

@ -0,0 +1,28 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file eggToMayaBin.cxx
* @author Derzsi Dániel
* @date 2020-10-01
*/
#include "eggToMaya.h"
/**
* Entrypoint for egg2maya.
*/
int main(int argc, char *argv[]) {
EggToMaya prog;
prog.parse_command_line(argc, argv);
if (!prog.run()) {
return 1;
}
return 0;
}

View File

@ -0,0 +1,22 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file eggToMayaClient.cxx
* @author Derzsi Dániel
* @date 2020-10-01
*/
#include "mayaConversionClient.h"
/**
* Entrypoint for egg2maya_client.
*/
int main(int argc, char *argv[]) {
MayaConversionClient client;
return client.main(argc, argv, MayaConversionServer::ConversionType::CT_egg_to_maya);
}

View File

@ -0,0 +1,192 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file mayaConversionClient.cxx
* @author Derzsi Dániel
* @date 2020-10-01
*/
#include "mayaConversionClient.h"
#include "mayaConversionServer.h"
#include "datagramIterator.h"
/**
* Initializes the Maya conversion client.
*/
MayaConversionClient::
MayaConversionClient()
{
_qManager = new QueuedConnectionManager();
_qReader = new QueuedConnectionReader(_qManager, 0);
_cWriter = new ConnectionWriter(_qManager, 0);
}
/**
* Cleans up the Maya conversison client's pending connections.
*/
MayaConversionClient::
~MayaConversionClient() {
close();
}
/**
* Attempts to connect to a Maya conversion server.
* If a connection is already active, it will be removed.
*
* Returns true if the connection was created successfully.
*/
bool MayaConversionClient::
connect(NetAddress server) {
if (_conn) {
// Remove this connection from the readers list
_qReader->remove_connection(_conn);
_conn = nullptr;
}
// Attempt to open a connection
_conn = _qManager->open_TCP_client_connection(server, 0);
if (!_conn || _conn.is_null()) {
// This connection could not be opened
return false;
}
// Add this connection to the readers list
_qReader->add_connection(_conn);
return true;
}
/**
* Sends a conversion workload to the Maya conversion server.
* It will be processed as soon as the server's queue is empty.
*
* Specify the working directory in where the models are located,
* the command line arguments, and the conversion type.
*
* Returns true if the workload has been successfully sent.
*/
bool MayaConversionClient::
queue(Filename working_directory, int argc, char *argv[], MayaConversionServer::ConversionType conversion_type) {
if (!_conn) {
return false;
}
std::string s_cwd = (std::string) working_directory.to_os_specific();
NetDatagram datagram;
// First part of the datagram is the argc
datagram.add_uint8(argc);
// Add the rest of the arguments as strings to the datagram
for (int i = 0; i < argc; i++) {
datagram.add_string(argv[i]);
}
// Add the current working dir as a string to the datagram
datagram.add_string(s_cwd);
// Lastly, add the conversion type
datagram.add_uint8(conversion_type);
// Send the conversion request
if (!_cWriter->send(datagram, _conn) || !_conn->flush()) {
nout << "Failed to send workload to server process.\n";
return false;
}
// Wait for a response
while (_conn->get_socket()->Active() && !_qReader->data_available()) {
_qReader->poll();
}
if (!_qReader->data_available()) {
// No response has been given by the server.
nout << "No response has been given by the conversion server.\n";
return false;
}
NetDatagram response;
// Let's read the response now!
if (!_qReader->get_data(response)) {
nout << "The conversion response could not be read.\n";
return false;
}
// Iterate through the response.
DatagramIterator response_data(response);
// Read the first and only argument.
// Did our conversion request succeed?
bool converted = response_data.get_bool();
if (!converted) {
nout << "The server reported that the conversion has failed.\n"
<< "Please check the server logs for further information.\n";
return false;
}
return true;
}
/**
* Closes the current connection to the Maya conversion server,
* waiting for all currently queued requests to finish.
*
* Does nothing if the connection has not been made yet.
*/
void MayaConversionClient::
close() {
if (!_conn) {
return;
}
while (true) {
_qReader->data_available();
if (_qManager->reset_connection_available()) {
PT(Connection) connection;
if (_qManager->get_reset_connection(connection)) {
_qManager->close_connection(_conn);
_conn = nullptr;
return;
}
}
Thread::sleep(0.1);
}
}
/**
* The entrypoint to this Maya conversion client.
*
* Connects to the default server at port 4242, queues
* one conversion request and waits for its completion.
*/
int MayaConversionClient::
main(int argc, char *argv[], MayaConversionServer::ConversionType conversion_type) {
NetAddress server;
// We assume the server is local and on port 4242
server.set_host("localhost", 4242);
if (!connect(server)) {
nout << "Failed to open port to server process.\n"
<< "Make sure maya2egg -server or egg2maya -server is running on localhost!\n";
return 1;
}
if (!queue(ExecutionEnvironment::get_cwd(), argc, argv, conversion_type)) {
return 1;
}
nout << "Conversion successful!\n";
close();
return 0;
}

View File

@ -0,0 +1,53 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file mayaConversionClient.h
* @author Derzsi Dániel
* @date 2020-10-01
*/
#ifndef MAYACONVERSIONCLIENT_H
#define MAYACONVERSIONCLIENT_H
#include "queuedConnectionManager.h"
#include "queuedConnectionReader.h"
#include "connectionWriter.h"
#include "netAddress.h"
#include "filename.h"
#include "mayaConversionServer.h"
/**
* The Maya conversion client sends batch conversion
* requests to the Maya conversion server.
*
* These utilities rely on the Maya conversion server.
* Use egg2maya or maya2egg to boot up the Maya conversion server.
* Use egg2maya_client and maya2egg_client as a replacement for
*
* Very useful in case you need to batch convert models.
* The regular utilities can only convert one model at a time.
*/
class MayaConversionClient {
public:
MayaConversionClient();
~MayaConversionClient();
bool connect(NetAddress server);
bool queue(Filename working_directory, int argc, char *argv[], MayaConversionServer::ConversionType conversion_type);
void close();
int main(int argc, char *argv[], MayaConversionServer::ConversionType conversion_type);
private:
QueuedConnectionManager *_qManager;
QueuedConnectionReader *_qReader;
ConnectionWriter *_cWriter;
PT(Connection) _conn;
};
#endif

View File

@ -0,0 +1,234 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file mayaConversionServer.cxx
* @author cbrunner
* @author Derzsi Dániel
* @date 2020-10-01
*/
#ifdef _WIN32
#include <direct.h> // for chdir
#endif
#include "mayaConversionServer.h"
#include "mayaToEgg.h"
#include "eggToMaya.h"
#include "virtualFileSystem.h"
#include "filename.h"
/**
* Initializes the Maya conversion server.
*/
MayaConversionServer::
MayaConversionServer() {
_qManager = new QueuedConnectionManager();
_qListener = new QueuedConnectionListener(_qManager, 0);
_qReader = new QueuedConnectionReader(_qManager, 0);
_cWriter = new ConnectionWriter(_qManager, 0);
}
/**
* Cleans up the connection managers for the Maya conversion server.
*/
MayaConversionServer::
~MayaConversionServer() {
delete _qManager;
delete _qReader;
delete _qListener;
delete _cWriter;
}
/**
* Checks for any network activity and handles it, if appropriate, and then
* returns. This must be called periodically
*/
void MayaConversionServer::
poll() {
// Listen for new connections
_qListener->poll();
// If we have a new connection from a client create a new connection pointer
// and add it to the reader list
if (_qListener->new_connection_available()) {
PT(Connection) rendezvous;
PT(Connection) connection;
NetAddress address;
if (_qListener->get_new_connection(rendezvous, address, connection)) {
_qReader->add_connection(connection);
_clients.insert(connection);
}
}
// Check for reset clients
if (_qManager->reset_connection_available()) {
PT(Connection) connection;
if (_qManager->get_reset_connection(connection)) {
_clients.erase(connection);
_qManager->close_connection(connection);
}
}
// Poll the readers (created above) and if they have data process it
_qReader->poll();
if (_qReader->data_available()) {
// Grab the incoming data and unpack it
NetDatagram datagram;
if (_qReader->get_data(datagram)) {
DatagramIterator data(datagram);
// First data should be the "argc" (argument count) from the client
int argc = data.get_uint8();
// Now we have to get clever because the rest of the data comes as
// strings and parse_command_line() expects arguments of the standard
// argc, argv*[] variety. First, we need a string vector to hold all
// the strings from the datagram. We also need a char * array to keep
// track of all the pointers we're gonna malloc. Needed later for
// cleanup.
vector_string vargv;
std::vector<char *> buffers;
// Get the strings from the datagram and put them into the string vector
for (int i = 0; i < argc; i++) {
vargv.push_back(data.get_string().c_str());
}
// Last string is the current directory the client was run from. Not
// part of the argument list, but we still need it
std::string cwd = data.get_string();
// We allocate some memory to hold the pointers to the pointers we're
// going to pass in to parse_command_line().
char **cargv = (char**) malloc(sizeof(char**) * argc);
// Loop through the string arguments we got from the datagram and
// convert them to const char *'s. parse_command_line() expects char
// *'s, so we have to copy these const versions into fresh char *, since
// there is no casting from const char * to char *.
for (int i = 0; i < argc; i++) {
// string to const char *
const char *cptr = vargv[i].c_str();
// memory allocated for a new char * of size of the string
char *buffer = (char *) malloc(vargv[i].capacity() + 1);
// Copy the const char * to the char *
strcpy(buffer, cptr);
// put this into the arry we defined above. This is what will
// eventually be passed to parse_command_line()
cargv[i] = buffer;
// keep track of the pointers to the allocated memory for cleanup
// later
buffers.push_back(buffer);
}
// Change to the client's current dir
#ifdef _WIN64
_chdir(cwd.c_str());
#else
chdir(cwd.c_str());
#endif
// Change the VirtualFileSystem's current dir as well
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
vfs->chdir(Filename::from_os_specific(cwd));
// Next, we'll need to read the conversion type.
// Are we converting from egg to maya or from maya to egg?
int conversion_type = data.get_uint8();
bool converted = false;
switch (conversion_type) {
case ConversionType::CT_maya_to_egg:
{
MayaToEgg egg;
// Pass in the 'new' argc and argv we got from the client
if (egg.parse_command_line(argc, cargv, false) == ProgramBase::ExitCode::EC_not_exited) {
// Actually run the damn thing
converted = egg.run();
}
break;
}
case ConversionType::CT_egg_to_maya:
{
EggToMaya maya;
maya.set_exit_on_failure(false);
// Pass in the 'new' argc and argv we got from the client
if (maya.parse_command_line(argc, cargv, false) == ProgramBase::ExitCode::EC_not_exited) {
// Actually run the damn thing
converted = maya.run();
}
break;
}
}
// Let's send the result back to the client
NetDatagram response;
// The first and only part of the response is the success value
response.add_bool(converted);
// Send the response
if (!_cWriter->send(response, datagram.get_connection())) {
// Looks like we couldn't send the response
nout << "Could not send response to the client.\n";
}
std::cout.flush();
// Cleanup first, release the string vector
vargv.clear();
// No, iterate through the char * vector and cleanup the malloc'd
// pointers
std::vector<char *>::iterator vi;
for ( vi = buffers.begin() ; vi != buffers.end(); vi++) {
free(*vi);
}
// Clean up the malloc'd pointer pointer
free(cargv);
} // qReader->get_data
Clients::iterator ci;
for (ci = _clients.begin(); ci != _clients.end(); ++ci) {
_qManager->close_connection(*ci);
}
} // qReader->data_available
} // poll
/**
* Blocks the current thread and listens to conversion requests.
*/
void MayaConversionServer::
listen() {
// Open a rendezvous port for receiving new connections from the client
PT(Connection) rend = _qManager->open_TCP_server_rendezvous(4242, 100);
if (rend.is_null()) {
nout << "Port opening failed!\n";
return;
}
nout << "Server opened on port 4242, waiting for requests...\n";
// Add this connection to the listeners list
_qListener->add_connection(rend);
// Main loop. Keep polling for connections, but don't eat up all the CPU.
while (true) {
this->poll();
Thread::force_yield();
}
}

View File

@ -0,0 +1,58 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file mayaConversionServer.h
* @author Derzsi Dániel
* @date 2020-10-01
*/
#ifndef MAYACONVERSIONSERVER_H
#define MAYACONVERSIONSERVER_H
#include "queuedConnectionManager.h"
#include "queuedConnectionListener.h"
#include "queuedConnectionReader.h"
#include "connectionWriter.h"
/**
* The Maya conversion server listens for incoming requests to
* handle maya-to-egg and egg-to-maya model conversions.
*
* This server listens to port 4242 after being started with
* egg2maya -server or maya2egg -server.
*
* Use egg2maya_client and maya2egg_client as a replacement for
* the egg2maya and maya2egg utilities after starting the server.
*
* Very useful in case you need to batch convert models.
* The regular utilities can only convert one model at a time.
*/
class MayaConversionServer {
public:
enum ConversionType {
CT_maya_to_egg = 0,
CT_egg_to_maya = 1
};
MayaConversionServer();
~MayaConversionServer();
void listen();
void poll();
protected:
typedef pset< PT(Connection) > Clients;
Clients _clients;
QueuedConnectionManager *_qManager;
QueuedConnectionListener *_qListener;
QueuedConnectionReader *_qReader;
ConnectionWriter *_cWriter;
};
#endif

View File

@ -43,6 +43,7 @@
#include "config_mayaegg.h"
#include "config_maya.h" // for maya_cat
#include "globPattern.h"
#include "mayaConversionServer.h"
/**
*
@ -124,6 +125,12 @@ MayaToEgg() :
"Legacy option. Same as -pc.",
&MayaToEgg::dispatch_filename, &_legacy_copytex, &_legacy_copytex_dir);
add_option("server", "", 0,
"Runs the Maya model conversion server. This server can be used in tandem "
"with the egg2maya_client and maya2egg_client utilities to batch convert "
"both Maya and Panda3D model files.",
&MayaToEgg::dispatch_none, &_run_server);
add_option
("trans", "type", 0,
"Specifies which transforms in the Maya file should be converted to "
@ -203,7 +210,34 @@ MayaToEgg() :
/**
*
*/
void MayaToEgg::
MayaToEgg::
~MayaToEgg() {
}
/**
* Attempts to create the global Maya API.
* Exits the program if unsuccessful.
*/
PT(MayaApi) MayaToEgg::
open_api() {
if (!MayaApi::is_api_valid()) {
nout << "Initializing Maya...\n";
}
PT(MayaApi) api = MayaApi::open_api(_program_name, true, true);
if (!api || !api->is_valid()) {
nout << "Unable to initialize Maya.\n";
exit(1);
}
return api;
}
/**
* Returns true if the model has been successfully converted.
*/
bool MayaToEgg::
run() {
// Set the verbose level by using Notify.
if (_verbose >= 3) {
@ -229,14 +263,8 @@ run() {
_path_replace->_path_directory.make_absolute();
}
nout << "Initializing Maya.\n";
open_api();
MayaToEggConverter converter(_program_name);
// reverting directories is really not needed for maya2egg. It's more
// needed for mayaeggloader and such
if (!converter.open_api(false)) {
nout << "Unable to initialize Maya.\n";
exit(1);
}
// Copy in the command-line parameters.
converter._polygon_output = _polygon_output;
@ -299,7 +327,7 @@ run() {
if (!converter.convert_file(_input_filename)) {
nout << "Errors in conversion.\n";
exit(1);
return false;
}
// Use the standard Maya units, if the user didn't specify otherwise. This
@ -310,8 +338,10 @@ run() {
_input_units = converter.get_input_units();
}
// Write output file
write_egg_file();
nout << "\n";
close_output();
return true;
}
/**
@ -332,9 +362,22 @@ dispatch_transform_type(const std::string &opt, const std::string &arg, void *va
return true;
}
int main(int argc, char *argv[]) {
MayaToEgg prog;
prog.parse_command_line(argc, argv);
prog.run();
return 0;
/**
* Processes the arguments parsed by the program.
*
* If the server flag is specified, the Maya conversion server is started
* up rather than the usual conversion utility functionality.
*/
bool MayaToEgg::
handle_args(ProgramBase::Args &args) {
if (_run_server) {
open_api();
MayaConversionServer server;
server.listen();
exit(0);
return true;
}
return SomethingToEgg::handle_args(args);
}

View File

@ -17,6 +17,9 @@
#include "pandatoolbase.h"
#include "somethingToEgg.h"
#include "mayaToEggConverter.h"
#include "mayaApi.h"
#include "programBase.h"
/**
*
@ -24,11 +27,15 @@
class MayaToEgg : public SomethingToEgg {
public:
MayaToEgg();
~MayaToEgg();
void run();
bool run();
protected:
static bool dispatch_transform_type(const std::string &opt, const std::string &arg, void *var);
virtual bool handle_args(ProgramBase::Args &args);
PT(MayaApi) open_api();
int _verbose;
bool _polygon_output;
@ -49,6 +56,9 @@ protected:
vector_string _excludes;
vector_string _ignore_sliders;
vector_string _force_joints;
public:
bool _run_server;
};
#endif

View File

@ -0,0 +1,28 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file mayaToEggBin.cxx
* @author Derzsi Dániel
* @date 2020-10-01
*/
#include "mayaToEgg.h"
/**
* Entrypoint for maya2egg.
*/
int main(int argc, char *argv[]) {
MayaToEgg prog;
prog.parse_command_line(argc, argv);
if (!prog.run()) {
return 1;
}
return 0;
}

View File

@ -0,0 +1,22 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file mayaToEggClient.cxx
* @author Derzsi Dániel
* @date 2020-10-01
*/
#include "mayaConversionClient.h"
/**
* Entrypoint for maya2egg_client.
*/
int main(int argc, char *argv[]) {
MayaConversionClient client;
return client.main(argc, argv, MayaConversionServer::ConversionType::CT_maya_to_egg);
}

View File

@ -1,73 +0,0 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file mayaToEgg_client.cxx
* @author cbrunner
* @date 2009-11-09
*/
#include "mayaToEgg_client.h"
/**
*
*/
MayaToEggClient::
MayaToEggClient() :
SomethingToEgg("Maya", ".mb")
{
qManager = new QueuedConnectionManager();
qReader = new QueuedConnectionReader(qManager, 0);
cWriter = new ConnectionWriter(qManager, 0);
// We assume the server is local and on port 4242
server.set_host("localhost", 4242);
}
int main(int argc, char *argv[]) {
MayaToEggClient prog;
// Open a connection to the server process
PT(Connection) con = prog.qManager->open_TCP_client_connection(prog.server,0);
if (con.is_null()) {
nout << "Failed to open port to server process.\nMake sure maya2egg_server is running on localhost\n";
exit(1);
}
// Add this connection to the readers list
prog.qReader->add_connection(con);
// Get the current working directory and make sure it's a string
Filename cwd = ExecutionEnvironment::get_cwd();
std::string s_cwd = (std::string)cwd.to_os_specific();
NetDatagram datagram;
// First part of the datagram is the argc
datagram.add_uint8(argc);
// Add the rest of the arguments as strings to the datagram
int i;
for (i = 0; i < argc; i++) {
datagram.add_string(argv[i]);
}
// Lastly, add the current working dir as a string to the datagram
datagram.add_string(s_cwd);
// Send it and close the connection
prog.cWriter->send(datagram, con);
con->flush();
while (true) {
prog.qReader->data_available();
if (prog.qManager->reset_connection_available()) {
PT(Connection) connection;
if (prog.qManager->get_reset_connection(connection)) {
prog.qManager->close_connection(con);
return 0;
}
}
Thread::sleep(0.1);
}
}

View File

@ -1,35 +0,0 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file mayaToEgg_client.h
* @author cbrunner
* @date 2009-11-09
*/
#ifndef MAYATOEGGCLIENT_H
#define MAYATOEGGCLIENT_H
#include "somethingToEgg.h"
#include "queuedConnectionManager.h"
#include "queuedConnectionReader.h"
#include "connectionWriter.h"
/**
*
*/
class MayaToEggClient : public SomethingToEgg {
public:
MayaToEggClient();
QueuedConnectionManager *qManager;
QueuedConnectionReader *qReader;
ConnectionWriter *cWriter;
NetAddress server;
};
#endif

View File

@ -1,474 +0,0 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file mayaToEgg_server.cxx
* @author cbrunner
* @date 2009-11-09
*/
#ifdef _WIN32
#include <direct.h> // for chdir
#endif
#include "mayaToEgg_server.h"
#include "mayaToEggConverter.h"
#include "config_mayaegg.h"
#include "config_maya.h" // for maya_cat
#include "globPattern.h"
/**
*
*/
MayaToEggServer::
MayaToEggServer() :
SomethingToEgg("Maya", ".mb")
{
add_path_replace_options();
add_path_store_options();
add_animation_options();
add_units_options();
add_normals_options();
add_transform_options();
set_program_brief("convert Maya model files to .egg");
set_program_description
("This program converts Maya model files to egg. Static and animatable "
"models can be converted, with polygon or NURBS output. Animation tables "
"can also be generated to apply to an animatable model.");
add_option
("p", "", 0,
"Generate polygon output only. Tesselate all NURBS surfaces to "
"polygons via the built-in Maya tesselator. The tesselation will "
"be based on the tolerance factor given by -ptol.",
&MayaToEggServer::dispatch_none, &_polygon_output);
add_option
("ptol", "tolerance", 0,
"Specify the fit tolerance for Maya polygon tesselation. The smaller "
"the number, the more polygons will be generated. The default is "
"0.01.",
&MayaToEggServer::dispatch_double, nullptr, &_polygon_tolerance);
add_option
("bface", "", 0,
"Respect the Maya \"double sided\" rendering flag to indicate whether "
"polygons should be double-sided or single-sided. Since this flag "
"is set to double-sided by default in Maya, it is often better to "
"ignore this flag (unless your modelers are diligent in turning it "
"off where it is not desired). If this flag is not specified, the "
"default is to treat all polygons as single-sided, unless an "
"egg object type of \"double-sided\" is set.",
&MayaToEggServer::dispatch_none, &_respect_maya_double_sided);
add_option
("suppress-vcolor", "", 0,
"Ignore vertex color for geometry that has a texture applied. "
"(This is the way Maya normally renders internally.) The egg flag "
"'vertex-color' may be applied to a particular model to override "
"this setting locally.",
&MayaToEggServer::dispatch_none, &_suppress_vertex_color);
add_option
("keep-uvs", "", 0,
"Convert all UV sets on all vertices, even those that do not appear "
"to be referenced by any textures.",
&MayaToEggServer::dispatch_none, &_keep_all_uvsets);
add_option
("round-uvs", "", 0,
"round up uv coordinates to the nearest 1/100th. i.e. -0.001 becomes"
"0.0; 0.444 becomes 0.44; 0.778 becomes 0.78.",
&MayaToEggServer::dispatch_none, &_round_uvs);
add_option
("trans", "type", 0,
"Specifies which transforms in the Maya file should be converted to "
"transforms in the egg file. The option may be one of all, model, "
"dcs, or none. The default is model, which means only transforms on "
"nodes that have the model flag or the dcs flag are preserved.",
&MayaToEggServer::dispatch_transform_type, nullptr, &_transform_type);
add_option
("subroot", "name", 0,
"Specifies that only a subroot of the geometry in the Maya file should "
"be converted; specifically, the geometry under the node or nodes whose "
"name matches the parameter (which may include globbing characters "
"like * or ?). This parameter may be repeated multiple times to name "
"multiple roots. If it is omitted altogether, the entire file is "
"converted.",
&MayaToEggServer::dispatch_vector_string, nullptr, &_subroots);
add_option
("subset", "name", 0,
"Specifies that only a subset of the geometry in the Maya file should "
"be converted; specifically, the geometry under the node or nodes whose "
"name matches the parameter (which may include globbing characters "
"like * or ?). This parameter may be repeated multiple times to name "
"multiple roots. If it is omitted altogether, the entire file is "
"converted.",
&MayaToEggServer::dispatch_vector_string, nullptr, &_subsets);
add_option
("exclude", "name", 0,
"Specifies that a subset of the geometry in the Maya file should "
"not be converted; specifically, the geometry under the node or nodes whose "
"name matches the parameter (which may include globbing characters "
"like * or ?). This parameter may be repeated multiple times to name "
"multiple roots.",
&MayaToEggServer::dispatch_vector_string, nullptr, &_excludes);
add_option
("ignore-slider", "name", 0,
"Specifies the name of a slider (blend shape deformer) that maya2egg "
"should not process. The slider will not be touched during conversion "
"and it will not become a part of the animation. This "
"parameter may including globbing characters, and it may be repeated "
"as needed.",
&MayaToEggServer::dispatch_vector_string, nullptr, &_ignore_sliders);
add_option
("force-joint", "name", 0,
"Specifies the name of a DAG node that maya2egg "
"should treat as a joint, even if it does not appear to be a Maya joint "
"and does not appear to be animated.",
&MayaToEggServer::dispatch_vector_string, nullptr, &_force_joints);
add_option
("v", "", 0,
"Increase verbosity. More v's means more verbose.",
&MayaToEggServer::dispatch_count, nullptr, &_verbose);
add_option
("legacy-shaders", "", 0,
"Use this flag to turn off modern (Phong) shader generation"
"and treat all shaders as if they were Lamberts (legacy).",
&MayaToEggServer::dispatch_none, &_legacy_shader);
// Unfortunately, the Maya API doesn't allow us to differentiate between
// relative and absolute pathnames--everything comes out as an absolute
// pathname, even if it is stored in the Maya file as a relative path. So
// we can't support -noabs.
remove_option("noabs");
_verbose = 0;
_polygon_tolerance = 0.01;
_transform_type = MayaToEggConverter::TT_model;
_got_tbnauto = true;
qManager = new QueuedConnectionManager();
qListener = new QueuedConnectionListener(qManager, 0);
qReader = new QueuedConnectionReader(qManager, 0);
cWriter = new ConnectionWriter(qManager, 0);
dummy = new MayaToEggConverter();
nout << "Initializing Maya...\n";
if (!dummy->open_api()) {
nout << "Unable to initialize Maya.\n";
exit(1);
}
}
/**
*
*/
MayaToEggServer::
~MayaToEggServer() {
delete qManager;
delete qReader;
delete qListener;
delete cWriter;
delete dummy;
}
/**
*
*/
void MayaToEggServer::
run() {
// Make sure we have good clean data to start with
_data = new EggData();
// Set the verbose level by using Notify.
if (_verbose >= 3) {
maya_cat->set_severity(NS_spam);
mayaegg_cat->set_severity(NS_spam);
} else if (_verbose >= 2) {
maya_cat->set_severity(NS_debug);
mayaegg_cat->set_severity(NS_debug);
} else if (_verbose >= 1) {
maya_cat->set_severity(NS_info);
mayaegg_cat->set_severity(NS_info);
}
// Let's convert the output file to a full path before we initialize Maya,
// since Maya now has a nasty habit of changing the current directory.
if (_got_output_filename) {
_output_filename.make_absolute();
_path_replace->_path_directory.make_absolute();
}
MayaToEggConverter converter(_program_name);
// Copy in the command-line parameters.
converter._polygon_output = _polygon_output;
converter._polygon_tolerance = _polygon_tolerance;
converter._respect_maya_double_sided = _respect_maya_double_sided;
converter._always_show_vertex_color = !_suppress_vertex_color;
converter._keep_all_uvsets = _keep_all_uvsets;
converter._round_uvs = _round_uvs;
converter._transform_type = _transform_type;
converter._legacy_shader = _legacy_shader;
vector_string::const_iterator si;
if (!_subroots.empty()) {
converter.clear_subroots();
for (si = _subroots.begin(); si != _subroots.end(); ++si) {
converter.add_subroot(GlobPattern(*si));
}
}
if (!_subsets.empty()) {
converter.clear_subsets();
for (si = _subsets.begin(); si != _subsets.end(); ++si) {
converter.add_subset(GlobPattern(*si));
}
}
if (!_excludes.empty()) {
converter.clear_excludes();
for (si = _excludes.begin(); si != _excludes.end(); ++si) {
converter.add_exclude(GlobPattern(*si));
}
}
if (!_ignore_sliders.empty()) {
converter.clear_ignore_sliders();
for (si = _ignore_sliders.begin(); si != _ignore_sliders.end(); ++si) {
converter.add_ignore_slider(GlobPattern(*si));
}
}
if (!_force_joints.empty()) {
converter.clear_force_joints();
for (si = _force_joints.begin(); si != _force_joints.end(); ++si) {
converter.add_force_joint(GlobPattern(*si));
}
}
// Copy in the path and animation parameters.
apply_parameters(converter);
// Set the coordinate system to match Maya's.
if (!_got_coordinate_system) {
_coordinate_system = converter._maya->get_coordinate_system();
}
_data->set_coordinate_system(_coordinate_system);
converter.set_egg_data(_data);
if (!converter.convert_file(_input_filename)) {
nout << "Errors in conversion.\n";
exit(1);
}
// Use the standard Maya units, if the user didn't specify otherwise. This
// always returns centimeters, which is the way all Maya files are stored
// internally (and is the units returned by all of the API functions called
// here).
if (_input_units == DU_invalid) {
_input_units = converter.get_input_units();
}
// Add the command line comment at the top of the egg file
append_command_comment(_data);
write_egg_file();
// Clean and out
close_output();
_verbose = 0;
_polygon_tolerance = 0.01;
_polygon_output = 0;
_transform_type = MayaToEggConverter::TT_model;
_subsets.clear();
_subroots.clear();
_input_units = DU_invalid;
_output_units = DU_invalid;
_excludes.clear();
_ignore_sliders.clear();
_force_joints.clear();
_got_transform = false;
_transform = LMatrix4d::ident_mat();
_normals_mode = NM_preserve;
_normals_threshold = 0.0;
_got_start_frame = false;
_got_end_frame = false;
_got_frame_inc = false;
_got_neutral_frame = false;
_got_input_frame_rate = false;
_got_output_frame_rate = false;
_got_output_filename = false;
_merge_externals = false;
_got_tbnall = false;
_got_tbnauto = false;
_got_transform = false;
_coordinate_system = CS_yup_right;
_noabs = false;
_program_args.clear();
_data->clear();
_animation_convert = AC_none;
_character_name = "";
dummy->clear();
}
/**
* Dispatches a parameter that expects a MayaToEggConverter::TransformType
* option.
*/
bool MayaToEggServer::
dispatch_transform_type(const std::string &opt, const std::string &arg, void *var) {
MayaToEggConverter::TransformType *ip = (MayaToEggConverter::TransformType *)var;
(*ip) = MayaToEggConverter::string_transform_type(arg);
if ((*ip) == MayaToEggConverter::TT_invalid) {
nout << "Invalid type for -" << opt << ": " << arg << "\n"
<< "Valid types are all, model, dcs, and none.\n";
return false;
}
return true;
}
/**
* Checks for any network activity and handles it, if appropriate, and then
* returns. This must be called periodically
*/
void MayaToEggServer::
poll() {
// Listen for new connections
qListener->poll();
// If we have a new connection from a client create a new connection pointer
// and add it to the reader list
if (qListener->new_connection_available()) {
PT(Connection) con;
PT(Connection) rv;
NetAddress address;
if (qListener->get_new_connection(rv, address, con)) {
qReader->add_connection(con);
_clients.insert(con);
}
}
// Check for reset clients
if (qManager->reset_connection_available()) {
PT(Connection) connection;
if (qManager->get_reset_connection(connection)) {
_clients.erase(connection);
qManager->close_connection(connection);
}
}
// Poll the readers (created above) and if they have data process it
qReader->poll();
if (qReader->data_available()) {
// Grab the incomming data and unpack it
NetDatagram datagram;
if (qReader->get_data(datagram)) {
DatagramIterator data(datagram);
// First data should be the "argc" (argument count) from the client
int argc = data.get_uint8();
// Now we have to get clever because the rest of the data comes as
// strings and parse_command_line() expects arguments of the standard
// argc, argv*[] variety. First, we need a string vector to hold all
// the strings from the datagram. We also need a char * array to keep
// track of all the pointers we're gonna malloc. Needed later for
// cleanup.
vector_string vargv;
std::vector<char *> buffers;
// Get the strings from the datagram and put them into the string vector
int i;
for ( i = 0; i < argc; i++ ) {
vargv.push_back(data.get_string());
}
// Last string is the current directory the client was run from. Not
// part of the argument list, but we still need it
std::string cwd = data.get_string();
// We allocate some memory to hold the pointers to the pointers we're
// going to pass in to parse_command_line().
char ** cargv = (char**) malloc(sizeof(char**) * argc);
// Loop through the string arguments we got from the datagram and
// convert them to const char *'s. parse_command_line() expects char
// *'s, so we have to copy these const versions into fresh char *, since
// there is no casting from const char * to char *.
for ( i = 0; i < argc; i++) {
// string to const char *
const char * cptr = vargv[i].c_str();
// memory allocated for a new char * of size of the string
char * buffer = (char*) malloc(vargv[i].capacity()+1);
// Copy the const char * to the char *
strcpy(buffer, cptr);
// put this into the arry we defined above. This is what will
// eventually be passed to parse_command_line()
cargv[i] = buffer;
// keep track of the pointers to the allocated memory for cleanup
// later
buffers.push_back(buffer);
}
// Change to the client's current dir
#ifdef _WIN64
_chdir(cwd.c_str());
#else
chdir(cwd.c_str());
#endif
// Pass in the 'new' argc and argv we got from the client
this->parse_command_line(argc, cargv);
// Actually run the damn thing
this->run();
// Cleanup First, release the string vector
vargv.clear();
// No, iterate through the char * vector and cleanup the malloc'd
// pointers
std::vector<char *>::iterator vi;
for ( vi = buffers.begin() ; vi != buffers.end(); vi++) {
free(*vi);
}
// Clean up the malloc'd pointer pointer
free(cargv);
} // qReader->get_data
Clients::iterator ci;
for (ci = _clients.begin(); ci != _clients.end(); ++ci) {
qManager->close_connection(*ci);
}
} // qReader->data_available
} // poll
int main(int argc, char *argv[]) {
MayaToEggServer prog;
// Open a rendezvous port for receiving new connections from the client
PT(Connection) rend = prog.qManager->open_TCP_server_rendezvous(4242, 50);
if (rend.is_null()) {
nout << "port opened fail";
}
// Add this connection to the listeners list
prog.qListener->add_connection(rend);
// Main loop. Keep polling for connections, but don't eat up all the CPU.
while (true) {
prog.poll();
Thread::force_yield();
}
return 0;
}

View File

@ -1,67 +0,0 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file mayaToEgg_server.h
* @author cbrunner
* @date 2009-11-09
*/
#ifndef MAYATOEGGSERVER_H
#define MAYATOEGGSERVER_H
#include "pandatoolbase.h"
#include "somethingToEgg.h"
#include "mayaToEggConverter.h"
#include "queuedConnectionManager.h"
#include "queuedConnectionListener.h"
#include "queuedConnectionReader.h"
#include "connectionWriter.h"
/**
*
*/
class MayaToEggServer : public SomethingToEgg {
public:
MayaToEggServer();
~MayaToEggServer();
void run();
void poll();
void add_reader(Connection *connection, QueuedConnectionReader *reader);
void remove_reader(Connection *connection, QueuedConnectionReader *reader);
QueuedConnectionManager *qManager;
QueuedConnectionListener *qListener;
QueuedConnectionReader *qReader;
ConnectionWriter *cWriter;
MayaToEggConverter *dummy;
protected:
static bool dispatch_transform_type(const std::string &opt, const std::string &arg, void *var);
typedef pset< PT(Connection) > Clients;
Clients _clients;
int _verbose;
bool _polygon_output;
double _polygon_tolerance;
bool _respect_maya_double_sided;
bool _suppress_vertex_color;
bool _keep_all_uvsets;
bool _round_uvs;
bool _legacy_shader;
MayaToEggConverter::TransformType _transform_type;
vector_string _subroots;
vector_string _subsets;
vector_string _excludes;
vector_string _ignore_sliders;
vector_string _force_joints;
};
#endif

View File

@ -268,10 +268,16 @@ write_man_page(std::ostream &out) {
/**
* Dispatches on each of the options on the command line, and passes the
* remaining parameters to handle_args(). If an error on the command line is
* detected, will automatically call show_usage() and exit(1).
* detected, will automatically call show_usage() and exit(1). If exit_on_complete
* is not set, will return the program's exit code instead of exiting.
*/
void ProgramBase::
parse_command_line(int argc, char **argv) {
ProgramBase::ExitCode ProgramBase::
parse_command_line(int argc, char **argv, bool exit_on_complete) {
if (!exit_on_complete) {
// The help option should not be available in programmatic environments.
remove_option("h");
}
preprocess_argv(argc, argv);
// Setting this variable to zero reinitializes the options parser This is
@ -280,6 +286,11 @@ parse_command_line(int argc, char **argv) {
extern int optind;
optind = 0;
#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_LONG_ONLY)
// We're using a Panda implementation of getopt. Let's reset that as well.
pgetopt_reset();
#endif
_program_name = Filename::from_os_specific(argv[0]);
int i;
for (i = 1; i < argc; i++) {
@ -310,9 +321,16 @@ parse_command_line(int argc, char **argv) {
}
} else {
cerr << "Invalid number of options for -write-man!\n";
exit(1);
if (exit_on_complete) {
exit(1);
}
return ExitCode::EC_failure;
}
exit(0);
if (exit_on_complete) {
exit(0);
}
return ExitCode::EC_clean_exit;
}
// Build up the long options list and the short options string for
@ -395,7 +413,10 @@ parse_command_line(int argc, char **argv) {
case '?':
// Invalid option or parameter.
show_usage();
exit(1);
if (exit_on_complete) {
exit(1);
}
return ExitCode::EC_failure;
case '\x1':
// A special return value from getopt() indicating a non-option
@ -427,7 +448,10 @@ parse_command_line(int argc, char **argv) {
if (!okflag) {
show_usage();
exit(1);
if (exit_on_complete) {
exit(1);
}
return ExitCode::EC_failure;
}
}
}
@ -438,13 +462,21 @@ parse_command_line(int argc, char **argv) {
if (!handle_args(remaining_args)) {
show_usage();
exit(1);
if (exit_on_complete) {
exit(1);
}
return ExitCode::EC_failure;
}
if (!post_command_line()) {
show_usage();
exit(1);
if (exit_on_complete) {
exit(1);
}
return ExitCode::EC_failure;
}
return ExitCode::EC_not_exited;
}
/**

View File

@ -33,6 +33,12 @@
*/
class ProgramBase {
public:
enum ExitCode {
EC_not_exited = -1,
EC_clean_exit = 0,
EC_failure = 1
};
ProgramBase(const std::string &name = std::string());
virtual ~ProgramBase();
@ -45,7 +51,7 @@ public:
void write_man_page(std::ostream &out);
virtual void parse_command_line(int argc, char **argv);
virtual ExitCode parse_command_line(int argc, char **argv, bool exit_on_complete = true);
std::string get_exec_command() const;