forked from 0ad/0ad
# Updated COLLADA converter.
Now uses FCollada 3.02. This was SVN commit r4933.
This commit is contained in:
parent
fc111ecb08
commit
ea29a1caeb
@ -8,12 +8,6 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
/** Throws a ColladaException unless the value is true. */
|
||||
#define REQUIRE(value, message) require_(__LINE__, value, "Assertion not satisfied", message)
|
||||
|
||||
/** Throws a ColladaException unless the status is successful. */
|
||||
#define REQUIRE_SUCCESS(status) require_(__LINE__, status)
|
||||
|
||||
void require_(int line, bool value, const char* type, const char* message)
|
||||
{
|
||||
if (value) return;
|
||||
@ -22,11 +16,6 @@ void require_(int line, bool value, const char* type, const char* message)
|
||||
throw ColladaException(std::string(type) + " (line " + linestr + "): " + message);
|
||||
}
|
||||
|
||||
void require_(int line, const FUStatus& status)
|
||||
{
|
||||
require_(line, status, "FCollada error", status.GetErrorString());
|
||||
}
|
||||
|
||||
/** Error handler for libxml2 */
|
||||
void errorHandler(void* ctx, const char* msg, ...)
|
||||
{
|
||||
@ -40,8 +29,50 @@ void errorHandler(void* ctx, const char* msg, ...)
|
||||
*((std::string*)ctx) += buffer;
|
||||
}
|
||||
|
||||
FColladaErrorHandler::FColladaErrorHandler(std::string& xmlErrors_)
|
||||
: xmlErrors(xmlErrors_)
|
||||
{
|
||||
// Grab all the error output from libxml2, for useful error reporting
|
||||
xmlSetGenericErrorFunc(&xmlErrors, &errorHandler);
|
||||
|
||||
FUError::SetErrorCallback(FUError::DEBUG, new FUFunctor3<FColladaErrorHandler, FUError::Level, uint32, uint32, void>(this, &FColladaErrorHandler::OnError));
|
||||
FUError::SetErrorCallback(FUError::WARNING, new FUFunctor3<FColladaErrorHandler, FUError::Level, uint32, uint32, void>(this, &FColladaErrorHandler::OnError));
|
||||
FUError::SetErrorCallback(FUError::ERROR, new FUFunctor3<FColladaErrorHandler, FUError::Level, uint32, uint32, void>(this, &FColladaErrorHandler::OnError));
|
||||
}
|
||||
|
||||
FColladaErrorHandler::~FColladaErrorHandler()
|
||||
{
|
||||
xmlSetGenericErrorFunc(NULL, NULL);
|
||||
|
||||
FUError::SetErrorCallback(FUError::DEBUG, NULL);
|
||||
FUError::SetErrorCallback(FUError::WARNING, NULL);
|
||||
FUError::SetErrorCallback(FUError::ERROR, NULL);
|
||||
}
|
||||
|
||||
void FColladaErrorHandler::OnError(FUError::Level errorLevel, uint32 errorCode, uint32 UNUSED(lineNumber))
|
||||
{
|
||||
const char* errorString = FUError::GetErrorString((FUError::Code) errorCode);
|
||||
if (! errorString)
|
||||
errorString = "Unknown error code";
|
||||
|
||||
if (errorLevel == FUError::DEBUG)
|
||||
Log(LOG_INFO, "FCollada message %d: %s", errorCode, errorString);
|
||||
else if (errorLevel == FUError::WARNING)
|
||||
Log(LOG_WARNING, "FCollada error %d: %s", errorCode, errorString);
|
||||
else
|
||||
throw ColladaException(errorString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// These don't get exported properly from FCollada (3.02, DLL), so define them
|
||||
// here instead of fixing it correctly.
|
||||
const FMVector3 FMVector3::XAxis(1.0f, 0.0f, 0.0f);
|
||||
static float identity[] = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
|
||||
FMMatrix44 FMMatrix44::Identity(identity);
|
||||
|
||||
struct FoundInstance
|
||||
{
|
||||
FCDEntityInstance* instance;
|
||||
|
@ -35,14 +35,27 @@ struct OutputCB
|
||||
virtual void operator() (const char* data, unsigned int length)=0;
|
||||
};
|
||||
|
||||
class FColladaErrorHandler
|
||||
{
|
||||
public:
|
||||
FColladaErrorHandler(std::string& xmlErrors);
|
||||
~FColladaErrorHandler();
|
||||
|
||||
private:
|
||||
void OnError(FUError::Level errorLevel, uint32 errorCode, uint32 lineNumber);
|
||||
std::string& xmlErrors;
|
||||
|
||||
void operator=(FColladaErrorHandler);
|
||||
};
|
||||
|
||||
/** Throws a ColladaException unless the value is true. */
|
||||
#define REQUIRE(value, message) require_(__LINE__, value, "Assertion not satisfied", message)
|
||||
|
||||
/** Throws a ColladaException unless the status is successful. */
|
||||
#define REQUIRE_SUCCESS(status) require_(__LINE__, status)
|
||||
#define REQUIRE_SUCCESS(status) require_(__LINE__, status, "FCollada error", "Line " STRINGIFY(__LINE__))
|
||||
#define STRINGIFY(x) #x
|
||||
|
||||
void require_(int line, bool value, const char* type, const char* message);
|
||||
void require_(int line, const FUStatus& status);
|
||||
|
||||
/** Outputs a structure, using sizeof to get the size. */
|
||||
template<typename T> void write(OutputCB& output, const T& data)
|
||||
|
@ -88,7 +88,7 @@ int convert_dae_to_whatever(const char* dae, OutputFn writer, void* cb_data, voi
|
||||
{
|
||||
conv(dae, cb, xmlErrors);
|
||||
}
|
||||
catch (ColladaException e)
|
||||
catch (const ColladaException& e)
|
||||
{
|
||||
if (! xmlErrors.empty())
|
||||
Log(LOG_ERROR, "%s", xmlErrors.c_str());
|
||||
|
@ -50,17 +50,13 @@ public:
|
||||
*/
|
||||
static void ColladaToPMD(const char* input, OutputCB& output, std::string& xmlErrors)
|
||||
{
|
||||
FUStatus ret;
|
||||
|
||||
// Grab all the error output from libxml2. Be careful to never use
|
||||
// libxml2 outside this function without having first set/reset the
|
||||
// errorfunc (since xmlErrors won't be valid any more).
|
||||
xmlSetGenericErrorFunc(&xmlErrors, &errorHandler);
|
||||
FColladaErrorHandler err (xmlErrors);
|
||||
|
||||
std::auto_ptr<FCDocument> doc (FCollada::NewTopDocument());
|
||||
REQUIRE_SUCCESS(doc->LoadFromText("", input));
|
||||
|
||||
FCDSceneNode* root = doc->GetVisualSceneRoot();
|
||||
REQUIRE(root != NULL, "has root object");
|
||||
|
||||
// Find the instance to convert
|
||||
FCDEntityInstance* instance;
|
||||
@ -101,12 +97,26 @@ public:
|
||||
|
||||
WritePMD(output, *indicesCombined, dataPosition, dataNormal, dataTexcoord, boneWeights, boneTransforms);
|
||||
}
|
||||
else if (instance->GetEntity()->GetType() == FCDEntity::CONTROLLER)
|
||||
else if (instance->GetType() == FCDEntityInstance::CONTROLLER)
|
||||
{
|
||||
FCDControllerInstance* controllerInstance = (FCDControllerInstance*)instance;
|
||||
|
||||
// (NB: GetType is deprecated and should be replaced with HasType,
|
||||
// except that has irritating linker errors when using a DLL, so don't
|
||||
// bother)
|
||||
|
||||
assert(instance->GetEntity()->GetType() == FCDEntity::CONTROLLER); // assume this is always true?
|
||||
FCDController* controller = (FCDController*)instance->GetEntity();
|
||||
|
||||
REQUIRE(controller->HasSkinController(), "has skin controller");
|
||||
FCDSkinController* skin = controller->GetSkinController();
|
||||
REQUIRE(skin != NULL, "is skin controller");
|
||||
|
||||
// Data for joints is stored in two places - avoid overflows by limiting
|
||||
// to the minimum of the two sizes, and warn if they're different (which
|
||||
// happens in practice for slightly-broken meshes)
|
||||
size_t jointCount = std::min(skin->GetJointCount(), controllerInstance->GetJointCount());
|
||||
if (skin->GetJointCount() != controllerInstance->GetJointCount())
|
||||
Log(LOG_WARNING, "Mismatched bone counts");
|
||||
|
||||
// Get the skinned mesh for this entity
|
||||
FCDEntity* baseTarget = controller->GetBaseTarget();
|
||||
@ -135,7 +145,12 @@ public:
|
||||
{
|
||||
uint32 jointIdx = vertexInfluences[i][j].jointIndex;
|
||||
REQUIRE(jointIdx <= 0xFF, "sensible number of joints");
|
||||
FCDSceneNode* joint = skin->GetJoint(jointIdx)->joint;
|
||||
|
||||
// Find the joint on the skeleton, after checking it really exists
|
||||
FCDSceneNode* joint = NULL;
|
||||
if (jointIdx < controllerInstance->GetJointCount())
|
||||
joint = controllerInstance->GetJoint(jointIdx);
|
||||
|
||||
if (! joint)
|
||||
{
|
||||
if (! hasComplainedAboutNonexistentJoints)
|
||||
@ -159,17 +174,9 @@ public:
|
||||
|
||||
transform = skin->GetBindShapeTransform();
|
||||
|
||||
for (size_t i = 0; i < skin->GetJointCount(); ++i)
|
||||
for (size_t i = 0; i < jointCount; ++i)
|
||||
{
|
||||
FCDJointMatrixPair* joint = skin->GetJoint(i);
|
||||
|
||||
if (! joint->joint)
|
||||
{
|
||||
Log(LOG_WARNING, "Skin has nonexistent joint");
|
||||
continue;
|
||||
}
|
||||
|
||||
FMMatrix44 bindPose = joint->invertedBindPose.Inverted();
|
||||
FMMatrix44 bindPose = skin->GetBindPoses()[i].Inverted();
|
||||
|
||||
HMatrix matrix;
|
||||
memcpy(matrix, bindPose.Transposed().m, sizeof(matrix));
|
||||
@ -183,8 +190,14 @@ public:
|
||||
{ parts.q.x, parts.q.y, parts.q.z, parts.q.w }
|
||||
};
|
||||
|
||||
int boneId = StdSkeletons::FindStandardBoneID(joint->joint->GetName());
|
||||
REQUIRE(boneId >= 0, "recognised bone name");
|
||||
FCDSceneNode* joint = controllerInstance->GetJoint(i);
|
||||
int boneId = StdSkeletons::FindStandardBoneID(joint->GetName());
|
||||
if (boneId < 0)
|
||||
{
|
||||
Log(LOG_WARNING, "Unrecognised bone name '%s'", joint->GetName().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
boneTransforms[boneId] = b;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "FCDocument/FCDGeometryPolygons.h"
|
||||
#include "FCDocument/FCDGeometrySource.h"
|
||||
#include "FCDocument/FCDSceneNode.h"
|
||||
#include "FCDocument/FCDSkinController.h"
|
||||
|
||||
#include "StdSkeletons.h"
|
||||
#include "Decompose.h"
|
||||
@ -23,6 +22,7 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
struct BoneTransform
|
||||
{
|
||||
@ -44,17 +44,13 @@ public:
|
||||
*/
|
||||
static void ColladaToPSA(const char* input, OutputCB& output, std::string& xmlErrors)
|
||||
{
|
||||
FUStatus ret;
|
||||
|
||||
// Grab all the error output from libxml2. Be careful to never use
|
||||
// libxml2 outside this function without having first set/reset the
|
||||
// errorfunc (since xmlErrors won't be valid any more).
|
||||
xmlSetGenericErrorFunc(&xmlErrors, &errorHandler);
|
||||
FColladaErrorHandler err (xmlErrors);
|
||||
|
||||
std::auto_ptr<FCDocument> doc (FCollada::NewTopDocument());
|
||||
REQUIRE_SUCCESS(doc->LoadFromText("", input));
|
||||
|
||||
FCDSceneNode* root = doc->GetVisualSceneRoot();
|
||||
REQUIRE(root != NULL, "has root object");
|
||||
|
||||
// Find the instance to convert
|
||||
FCDEntityInstance* instance;
|
||||
@ -65,28 +61,33 @@ public:
|
||||
assert(instance);
|
||||
Log(LOG_INFO, "Converting '%s'", instance->GetEntity()->GetName().c_str());
|
||||
|
||||
if (instance->GetEntity()->GetType() == FCDEntity::CONTROLLER)
|
||||
if (instance->GetType() == FCDEntityInstance::CONTROLLER)
|
||||
{
|
||||
FCDController* controller = (FCDController*)instance->GetEntity();
|
||||
|
||||
REQUIRE(controller->HasSkinController(), "has skin controller");
|
||||
FCDSkinController* skin = controller->GetSkinController();
|
||||
FCDControllerInstance* controllerInstance = (FCDControllerInstance*)instance;
|
||||
|
||||
// Find the first and last times which have animations
|
||||
// TODO: use the FCOLLADA start_time/end_time where available
|
||||
float timeStart = std::numeric_limits<float>::max();
|
||||
float timeEnd = -std::numeric_limits<float>::max();
|
||||
for (size_t i = 0; i < skin->GetJointCount(); ++i)
|
||||
for (size_t i = 0; i < controllerInstance->GetJointCount(); ++i)
|
||||
{
|
||||
FCDJointMatrixPair* joint = skin->GetJoint(i);
|
||||
REQUIRE(joint->joint != NULL, "joint exists");
|
||||
FCDSceneNode* joint = controllerInstance->GetJoint(i);
|
||||
REQUIRE(joint != NULL, "joint exists");
|
||||
|
||||
int boneId = StdSkeletons::FindStandardBoneID(joint->GetName());
|
||||
if (boneId < 0)
|
||||
{
|
||||
Log(LOG_WARNING, "Unrecognised bone name '%s'", joint->GetName().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip unanimated joints
|
||||
if (joint->joint->GetTransformCount() == 0)
|
||||
if (joint->GetTransformCount() == 0)
|
||||
continue;
|
||||
|
||||
REQUIRE(joint->joint->GetTransformCount() == 1, "joint has single transform");
|
||||
REQUIRE(joint->GetTransformCount() == 1, "joint has single transform");
|
||||
|
||||
FCDTransform* transform = joint->joint->GetTransform(0);
|
||||
FCDTransform* transform = joint->GetTransform(0);
|
||||
|
||||
// Skip unanimated joints again. (TODO: Which of these happens in practice?)
|
||||
if (! transform->IsAnimated())
|
||||
@ -111,6 +112,7 @@ public:
|
||||
|
||||
// Count frames; don't include the last keyframe
|
||||
size_t frameCount = (size_t)((timeEnd - timeStart) / frameLength - 0.5f);
|
||||
// (TODO: sort out the timing/looping problems)
|
||||
|
||||
size_t boneCount = StdSkeletons::GetBoneCount();
|
||||
|
||||
@ -124,18 +126,47 @@ public:
|
||||
std::vector<BoneTransform> frameBoneTransforms (boneCount, boneDefault);
|
||||
|
||||
// Move the model into the new animated pose
|
||||
for (size_t i = 0; i < skin->GetJointCount(); ++i)
|
||||
for (size_t i = 0; i < controllerInstance->GetJointCount(); ++i)
|
||||
{
|
||||
FCDTransform* transform = skin->GetJoint(i)->joint->GetTransform(0);
|
||||
FCDSceneNode* joint = controllerInstance->GetJoint(i);
|
||||
|
||||
int boneId = StdSkeletons::FindStandardBoneID(joint->GetName());
|
||||
if (boneId < 0)
|
||||
continue; // already emitted a warning earlier
|
||||
|
||||
FCDTransform* transform = joint->GetTransform(0);
|
||||
FCDAnimated* anim = transform->GetAnimated();
|
||||
anim->Evaluate(time);
|
||||
}
|
||||
// As well as the joints, we need to update all the ancestors
|
||||
// of the skeleton (e.g. the Bip01 node, since the skeleton is
|
||||
// hanging off Bip01-Pelvis instead).
|
||||
// So choose an arbitrary joint, which is hopefully actually the
|
||||
// top-most joint but it doesn't really matter, and evaluate all
|
||||
// its ancestors;
|
||||
if (controllerInstance->GetJointCount() >= 1)
|
||||
{
|
||||
FCDSceneNode* node = controllerInstance->GetJoint(0);
|
||||
while (node->GetParentCount() == 1) // (I guess this should be true in sensible models)
|
||||
{
|
||||
node = node->GetParent();
|
||||
if (node->IsJoint() && node->GetTransformCount() == 1)
|
||||
node->GetTransform(0)->GetAnimated()->Evaluate(time);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the pose into the form require by the game
|
||||
for (size_t i = 0; i < skin->GetJointCount(); ++i)
|
||||
for (size_t i = 0; i < controllerInstance->GetJointCount(); ++i)
|
||||
{
|
||||
FCDSceneNode* jointNode = skin->GetJoint(i)->joint;
|
||||
FMMatrix44 worldTransform = jointNode->CalculateWorldTransform();
|
||||
FCDSceneNode* joint = controllerInstance->GetJoint(i);
|
||||
|
||||
int boneId = StdSkeletons::FindStandardBoneID(joint->GetName());
|
||||
if (boneId < 0)
|
||||
continue; // already emitted a warning earlier
|
||||
|
||||
FMMatrix44 worldTransform = joint->CalculateWorldTransform();
|
||||
|
||||
HMatrix matrix;
|
||||
memcpy(matrix, worldTransform.Transposed().m, sizeof(matrix));
|
||||
@ -148,13 +179,12 @@ public:
|
||||
{ parts.q.x, parts.q.y, parts.q.z, parts.q.w }
|
||||
};
|
||||
|
||||
int boneId = StdSkeletons::FindStandardBoneID(jointNode->GetName());
|
||||
REQUIRE(boneId >= 0, "recognised bone name");
|
||||
frameBoneTransforms[boneId] = b;
|
||||
}
|
||||
|
||||
// Push frameBoneTransforms onto the back of boneTransforms
|
||||
copy(frameBoneTransforms.begin(), frameBoneTransforms.end(), inserter(boneTransforms, boneTransforms.end()));
|
||||
copy(frameBoneTransforms.begin(), frameBoneTransforms.end(),
|
||||
inserter(boneTransforms, boneTransforms.end()));
|
||||
}
|
||||
|
||||
// Convert into game's coordinate space
|
||||
|
@ -5,11 +5,17 @@ import xml.etree.ElementTree as ET
|
||||
|
||||
binaries = '../../../binaries'
|
||||
|
||||
# Work out the platform-dependent library filename
|
||||
dll_filename = {
|
||||
'posix': './libCollada_dbg.so',
|
||||
'nt': 'Collada_dbg.dll',
|
||||
}[os.name]
|
||||
|
||||
# The DLL may need other DLLs which are in its directory, so set the path to that
|
||||
# (Don't care about clobbering the old PATH - it doesn't have anything important)
|
||||
os.environ['PATH'] = '%s/system/' % binaries
|
||||
|
||||
# Load the actual library
|
||||
library = cdll.LoadLibrary('%s/system/%s' % (binaries, dll_filename))
|
||||
|
||||
def log(severity, message):
|
||||
@ -19,16 +25,22 @@ clog = CFUNCTYPE(None, c_int, c_char_p)(log)
|
||||
# (the CFUNCTYPE must not be GC'd, so try to keep a reference)
|
||||
library.set_logger(clog)
|
||||
|
||||
def convert_dae_to_pmd(filename):
|
||||
def _convert_dae(func, filename, expected_status=0):
|
||||
output = []
|
||||
def cb(cbdata, str, len):
|
||||
output.append(string_at(str, len))
|
||||
|
||||
cbtype = CFUNCTYPE(None, POINTER(None), POINTER(c_char), c_uint)
|
||||
status = library.convert_dae_to_pmd(filename, cbtype(cb), None)
|
||||
assert(status == 0)
|
||||
status = func(filename, cbtype(cb), None)
|
||||
assert(status == expected_status)
|
||||
return ''.join(output)
|
||||
|
||||
def convert_dae_to_pmd(*args, **kwargs):
|
||||
return _convert_dae(library.convert_dae_to_pmd, *args, **kwargs)
|
||||
|
||||
def convert_dae_to_psa(*args, **kwargs):
|
||||
return _convert_dae(library.convert_dae_to_psa, *args, **kwargs)
|
||||
|
||||
def clean_dir(path):
|
||||
# Remove all files first
|
||||
try:
|
||||
@ -43,7 +55,7 @@ def clean_dir(path):
|
||||
except OSError:
|
||||
pass # (ignore errors if it already exists)
|
||||
|
||||
def create_actor(mesh, texture, idleanim, corpseanim, gatheranim):
|
||||
def create_actor(mesh, texture, anims):
|
||||
actor = ET.Element('actor', version='1')
|
||||
ET.SubElement(actor, 'castshadow')
|
||||
group = ET.SubElement(actor, 'group')
|
||||
@ -51,21 +63,41 @@ def create_actor(mesh, texture, idleanim, corpseanim, gatheranim):
|
||||
ET.SubElement(variant, 'mesh').text = mesh+'.pmd'
|
||||
ET.SubElement(variant, 'texture').text = texture+'.dds'
|
||||
animations = ET.SubElement(variant, 'animations')
|
||||
ET.SubElement(animations, 'animation', file=idleanim+'.psa', name='Idle', speed='100')
|
||||
ET.SubElement(animations, 'animation', file=corpseanim+'.psa', name='Corpse', speed='100')
|
||||
ET.SubElement(animations, 'animation', file=gatheranim+'.psa', name='Build', speed='100')
|
||||
for name, file in anims:
|
||||
ET.SubElement(animations, 'animation', file=file+'.psa', name=name, speed='100')
|
||||
return ET.tostring(actor)
|
||||
|
||||
def create_actor_static(mesh, texture):
|
||||
actor = ET.Element('actor', version='1')
|
||||
ET.SubElement(actor, 'castshadow')
|
||||
group = ET.SubElement(actor, 'group')
|
||||
variant = ET.SubElement(group, 'variant', frequency='100', name='Base')
|
||||
ET.SubElement(variant, 'mesh').text = mesh+'.pmd'
|
||||
ET.SubElement(variant, 'texture').text = texture+'.dds'
|
||||
return ET.tostring(actor)
|
||||
|
||||
################################
|
||||
|
||||
# Error handling
|
||||
|
||||
convert_dae_to_pmd('This is not well-formed XML', expected_status=-2)
|
||||
|
||||
convert_dae_to_pmd('<html>This is not COLLADA</html>', expected_status=-2)
|
||||
|
||||
convert_dae_to_pmd('<COLLADA>This is still not valid COLLADA</COLLADA>', expected_status=-2)
|
||||
|
||||
# Do some real conversions, so the output can be tested in the Actor Viewer
|
||||
|
||||
test_data = binaries + '/data/tests/collada'
|
||||
test_mod = binaries + '/data/mods/_test.collada'
|
||||
|
||||
clean_dir(test_mod + '/art/meshes')
|
||||
clean_dir(test_mod + '/art/actors')
|
||||
clean_dir(test_mod + '/art/animation')
|
||||
|
||||
for test_file in ['cube', 'jav2', 'jav2b', 'teapot_basic', 'teapot_skin', 'plane_skin', 'dude_skin', 'mergenonbone', 'densemesh']:
|
||||
print "* Converting PMD %s" % (test_file)
|
||||
|
||||
#for test_file in ['cube', 'jav2', 'teapot_basic', 'teapot_skin', 'plane_skin', 'dude_skin']:
|
||||
for test_file in ['sphere']:
|
||||
input_filename = '%s/%s.dae' % (test_data, test_file)
|
||||
output_filename = '%s/art/meshes/%s.pmd' % (test_mod, test_file)
|
||||
|
||||
@ -73,5 +105,19 @@ for test_file in ['sphere']:
|
||||
output = convert_dae_to_pmd(input)
|
||||
open(output_filename, 'wb').write(output)
|
||||
|
||||
xml = create_actor(test_file, 'male', 'dudeidle', 'dudecorpse', 'dudechop')
|
||||
xml = create_actor(test_file, 'male', [('Idle','dudeidle'),('Corpse','dudecorpse'),('Melee','jav2b')])
|
||||
open('%s/art/actors/%s.xml' % (test_mod, test_file), 'w').write(xml)
|
||||
|
||||
xml = create_actor_static(test_file, 'male')
|
||||
open('%s/art/actors/%s_static.xml' % (test_mod, test_file), 'w').write(xml)
|
||||
|
||||
for test_file in ['jav2b']:
|
||||
print "* Converting PSA %s" % (test_file)
|
||||
|
||||
input_filename = '%s/%s.dae' % (test_data, test_file)
|
||||
output_filename = '%s/art/animation/%s.psa' % (test_mod, test_file)
|
||||
|
||||
input = open(input_filename).read()
|
||||
output = convert_dae_to_psa(input)
|
||||
open(output_filename, 'wb').write(output)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user