From 7e1496141f50292faeea41ed63c55474cbab38b4 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 22 Dec 2008 07:29:11 +0000 Subject: [PATCH] Added Collada converter --- pandatool/src/daeegg/Sources.pp | 27 + pandatool/src/daeegg/config_daeegg.cxx | 47 ++ pandatool/src/daeegg/config_daeegg.h | 25 + pandatool/src/daeegg/daeCharacter.cxx | 107 ++++ pandatool/src/daeegg/daeCharacter.h | 65 +++ pandatool/src/daeegg/daeMaterials.cxx | 403 +++++++++++++ pandatool/src/daeegg/daeMaterials.h | 97 ++++ pandatool/src/daeegg/daeToEggConverter.cxx | 614 ++++++++++++++++++++ pandatool/src/daeegg/daeToEggConverter.h | 84 +++ pandatool/src/daeegg/daeegg_composite1.cxx | 5 + pandatool/src/daeegg/pre_fcollada_include.h | 26 + pandatool/src/daeprogs/Sources.pp | 25 + pandatool/src/daeprogs/daeToEgg.cxx | 74 +++ pandatool/src/daeprogs/daeToEgg.h | 35 ++ pandatool/src/daeprogs/eggToDAE.cxx | 182 ++++++ pandatool/src/daeprogs/eggToDAE.h | 46 ++ 16 files changed, 1862 insertions(+) create mode 100755 pandatool/src/daeegg/Sources.pp create mode 100644 pandatool/src/daeegg/config_daeegg.cxx create mode 100644 pandatool/src/daeegg/config_daeegg.h create mode 100644 pandatool/src/daeegg/daeCharacter.cxx create mode 100644 pandatool/src/daeegg/daeCharacter.h create mode 100755 pandatool/src/daeegg/daeMaterials.cxx create mode 100755 pandatool/src/daeegg/daeMaterials.h create mode 100755 pandatool/src/daeegg/daeToEggConverter.cxx create mode 100755 pandatool/src/daeegg/daeToEggConverter.h create mode 100755 pandatool/src/daeegg/daeegg_composite1.cxx create mode 100755 pandatool/src/daeegg/pre_fcollada_include.h create mode 100755 pandatool/src/daeprogs/Sources.pp create mode 100755 pandatool/src/daeprogs/daeToEgg.cxx create mode 100755 pandatool/src/daeprogs/daeToEgg.h create mode 100755 pandatool/src/daeprogs/eggToDAE.cxx create mode 100755 pandatool/src/daeprogs/eggToDAE.h diff --git a/pandatool/src/daeegg/Sources.pp b/pandatool/src/daeegg/Sources.pp new file mode 100755 index 0000000000..a90847eefe --- /dev/null +++ b/pandatool/src/daeegg/Sources.pp @@ -0,0 +1,27 @@ +#define BUILD_DIRECTORY $[HAVE_FCOLLADA] + +#begin lib_target + #define USE_PACKAGES fcollada + #define TARGET daeegg + #define LOCAL_LIBS converter pandatoolbase + #define OTHER_LIBS \ + egg:c pandaegg:m \ + pandabase:c express:c pandaexpress:m \ + pipeline:c mathutil:c linmath:c putil:c event:c \ + panda:m \ + interrogatedb:c prc:c dconfig:c dtoolconfig:m \ + dtoolutil:c dtoolbase:c dtool:m + + #define SOURCES \ + config_daeegg.cxx config_daeegg.h \ + daeToEggConverter.cxx daeToEggConverter.h \ + daeCharacter.cxx daeCharacter.h \ + daeMaterials.cxx daeMaterials.h \ + pre_fcollada_include.h + + #define INSTALL_HEADERS \ + config_daeegg.h daeToEggConverter.h \ + daeCharacter.h daeMaterials.h \ + pre_fcollada_include.h + +#end lib_target diff --git a/pandatool/src/daeegg/config_daeegg.cxx b/pandatool/src/daeegg/config_daeegg.cxx new file mode 100644 index 0000000000..24015d8821 --- /dev/null +++ b/pandatool/src/daeegg/config_daeegg.cxx @@ -0,0 +1,47 @@ +// Filename: config_daeegg.cxx +// Created by: pro-rsoft (30Oct08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#include "config_daeegg.h" +#include "daeCharacter.h" +#include "daeMaterials.h" + +#include "dconfig.h" + +Configure(config_daeegg); +NotifyCategoryDef(daeegg, ""); + +ConfigureFn(config_daeegg) { + init_libdaeegg(); +} + +//////////////////////////////////////////////////////////////////// +// Function: init_libdaeegg +// Description: Initializes the library. This must be called at +// least once before any of the functions or classes in +// this library can be used. Normally it will be +// called by the static initializers and need not be +// called explicitly, but special cases exist. +//////////////////////////////////////////////////////////////////// +void +init_libdaeegg() { + static bool initialized = false; + if (initialized) { + return; + } + initialized = true; + + DaeCharacter::init_type(); + DaeMaterials::init_type(); +} + diff --git a/pandatool/src/daeegg/config_daeegg.h b/pandatool/src/daeegg/config_daeegg.h new file mode 100644 index 0000000000..0f13f269c6 --- /dev/null +++ b/pandatool/src/daeegg/config_daeegg.h @@ -0,0 +1,25 @@ +// Filename: config_daeegg.h +// Created by: pro-rsoft (30Oct08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#ifndef CONFIG_DAEEGG_H +#define CONFIG_DAEEGG_H + +#include "pandatoolbase.h" +#include "notifyCategoryProxy.h" + +NotifyCategoryDeclNoExport(daeegg); + +extern void init_libdaeegg(); + +#endif diff --git a/pandatool/src/daeegg/daeCharacter.cxx b/pandatool/src/daeegg/daeCharacter.cxx new file mode 100644 index 0000000000..5935057bf5 --- /dev/null +++ b/pandatool/src/daeegg/daeCharacter.cxx @@ -0,0 +1,107 @@ +// Filename: daeCharacter.cxx +// Created by: pro-rsoft (24Nov08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#include "daeCharacter.h" +#include "config_daeegg.h" +#include "pt_EggVertex.h" +#include "eggXfmSAnim.h" + +#include "FCDocument/FCDocument.h" +#include "FCDocument/FCDController.h" +#include "FCDocument/FCDSceneNodeTools.h" + +TypeHandle DaeCharacter::_type_handle; + +// Useful conversion stuff +#define TO_VEC3(v) (LVecBase3d(v[0], v[1], v[2])) +#define TO_VEC4(v) (LVecBase4d(v[0], v[1], v[2], v[3])) +#define TO_COLOR(v) (Colorf(v[0], v[1], v[2], v[3])) +#define FROM_VEC3(v) (FMVector3(v[0], v[1], v[2])) +#define FROM_VEC4(v) (FMVector4(v[0], v[1], v[2], v[3])) +#define FROM_MAT4(v) (FMMatrix44(v.getData())) +#define FROM_FSTRING(fs) (string(fs.c_str())) + +//////////////////////////////////////////////////////////////////// +// Function: DaeCharacter::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DaeCharacter:: +DaeCharacter(const string name, const FCDControllerInstance* controller_instance) { + _controller_instance = (FCDControllerInstance*) controller_instance; + _name = name; + _frame_rate = 0; + _skin_controller = NULL; + // If it's a skin controller, add the controller joints. + FCDController* controller = (FCDController*) controller_instance->GetEntity(); + if (controller == NULL) return; + if (controller->IsSkin()) { + _skin_controller = controller->GetSkinController(); + if (_skin_controller == NULL) return; + for (size_t j = 0; j < _skin_controller->GetJointCount(); ++j) { + _controller_joints[FROM_FSTRING(_skin_controller->GetJoint(j)->GetId())] = (FCDSkinControllerJoint*) _skin_controller->GetJoint(j); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeCharacter::as_egg_bundle +// Access: Public +// Description: Returns the character as a element, +// suited for the animation table. +//////////////////////////////////////////////////////////////////// +PT(EggTable) DaeCharacter:: +as_egg_bundle() { + PT(EggTable) bundle = new EggTable(_name); + bundle->set_table_type(EggTable::TT_bundle); + PT(EggTable) skeleton = new EggTable(""); + skeleton->set_table_type(EggTable::TT_table); + bundle->add_child(skeleton); + // Loop through the joint hierarchy + FCDSceneNodeList roots = _controller_instance->FindSkeletonNodes(); + for (FCDSceneNodeList::iterator it = roots.begin(); it != roots.end(); ++it) { + process_joint(skeleton, *it); + } + return bundle; +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeCharacter::process_joint +// Access: Public +// Description: Processes a joint node and its transforms. +//////////////////////////////////////////////////////////////////// +void DaeCharacter:: +process_joint(PT(EggTable) parent, FCDSceneNode* node) { + nassertv(node != NULL); + string node_id = FROM_FSTRING(node->GetDaeId()); + PT(EggTable) joint = new EggTable(node_id); + joint->set_table_type(EggTable::TT_table); + parent->add_child(joint); + PT(EggXfmSAnim) xform = new EggXfmSAnim("xform"); + joint->add_child(xform); + xform->set_fps(_frame_rate); + // Generate the sampled animation and loop through the matrices + FCDSceneNodeTools::GenerateSampledAnimation(node); + FMMatrix44List matrices = FCDSceneNodeTools::GetSampledAnimationMatrices(); + for (FMMatrix44List::const_iterator it = matrices.begin(); it != matrices.end(); ++it) { + LMatrix4d matr = DAEToEggConverter::convert_matrix(*it); + assert(xform->add_data(matr)); + } + // Loop through the children joints + for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) { + if (node->GetChild(ch)->IsJoint()) { + process_joint(joint, node->GetChild(ch)); + } + } +} diff --git a/pandatool/src/daeegg/daeCharacter.h b/pandatool/src/daeegg/daeCharacter.h new file mode 100644 index 0000000000..e7a85cbedf --- /dev/null +++ b/pandatool/src/daeegg/daeCharacter.h @@ -0,0 +1,65 @@ +// Filename: daeCharacter.h +// Created by: pro-rsoft (24Nov08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#include "pandatoolbase.h" +#include "typedReferenceCount.h" +#include "typeHandle.h" +#include "eggTable.h" +#include "daeToEggConverter.h" + +#include "pre_fcollada_include.h" +#include "FCollada.h" +#include "FCDocument/FCDSceneNode.h" +#include "FCDocument/FCDControllerInstance.h" +#include "FCDocument/FCDSkinController.h" + +#ifndef DAECHARACTER_H +#define DAECHARACTER_H + +//////////////////////////////////////////////////////////////////// +// Class : DaeCharacter +// Description : Class representing an animated character. +//////////////////////////////////////////////////////////////////// +class DaeCharacter : public TypedReferenceCount { +public: + DaeCharacter(const string name, const FCDControllerInstance* controller_instance); + PT(EggTable) as_egg_bundle(); + void process_joint(PT(EggTable) parent, FCDSceneNode* node); + +private: + int _frame_rate; + string _name; + FCDControllerInstance* _controller_instance; + FCDSkinController* _skin_controller; + pmap _controller_joints; + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedReferenceCount::init_type(); + register_type(_type_handle, "DaeCharacter", + TypedReferenceCount::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#endif diff --git a/pandatool/src/daeegg/daeMaterials.cxx b/pandatool/src/daeegg/daeMaterials.cxx new file mode 100755 index 0000000000..1453ac0abc --- /dev/null +++ b/pandatool/src/daeegg/daeMaterials.cxx @@ -0,0 +1,403 @@ +// Filename: daeMaterials.cxx +// Created by: pro-rsoft (03Oct08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#include "daeMaterials.h" +#include "config_daeegg.h" + +#include "FCDocument/FCDocument.h" +#include "FCDocument/FCDMaterial.h" +#include "FCDocument/FCDEffect.h" +#include "FCDocument/FCDTexture.h" +#include "FCDocument/FCDEffectParameterSampler.h" +#include "FCDocument/FCDImage.h" + +#include "filename.h" +#include "string_utils.h" + +TypeHandle DaeMaterials::_type_handle; + +// Useful conversion stuff +#define CONV_VEC3(v) (LVecBase3d(v[0], v[1], v[2])) +#define CONV_VEC4(v) (LVecBase4d(v[0], v[1], v[2], v[3])) +#define CONV_COLOR(v) (Colorf(v[0], v[1], v[2], v[3])) +#define FROM_FSTRING(fs) (string(fs.c_str())) + +// luminance function, based on the ISO/CIE color standards +// see ITU-R Recommendation BT.709-4 +#define luminance(c) ((c[0] * 0.212671 + c[1] * 0.715160 + c[2] * 0.072169)) + +//////////////////////////////////////////////////////////////////// +// Function: DaeMaterials::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DaeMaterials:: +DaeMaterials(const FCDGeometryInstance* geometry_instance) { + for (size_t mi = 0; mi < geometry_instance->GetMaterialInstanceCount(); ++mi) { + add_material_instance(geometry_instance->GetMaterialInstance(mi)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeMaterials::add_material_instance +// Access: Public +// Description: Adds a material instance. Normally automatically +// done by constructor. +//////////////////////////////////////////////////////////////////// +void DaeMaterials::add_material_instance(const FCDMaterialInstance* instance) { + nassertv(instance != NULL); + const string semantic (FROM_FSTRING(instance->GetSemantic())); + if (_materials.count(semantic) > 0) { + daeegg_cat.warning() << "Ignoring duplicate material with semantic" << semantic << endl; + return; + } + _materials[semantic] = new DaeMaterial(); + + // Load in the uvsets + for (size_t vib = 0; vib < instance->GetVertexInputBindingCount(); ++vib) { + const FCDMaterialInstanceBindVertexInput* mivib = instance->GetVertexInputBinding(vib); + assert(mivib != NULL); + _materials[semantic]->_uvsets[mivib->inputSet] = FROM_FSTRING(mivib->semantic); + } + + // Handle the material stuff + daeegg_cat.spam() << "Trying to process material with semantic " << semantic << endl; + PT_EggMaterial egg_material = new EggMaterial(semantic); + pvector egg_textures; + const FCDEffect* effect = instance->GetMaterial()->GetEffect(); + if (effect == NULL) { + daeegg_cat.debug() << "Ignoring material (semantic: " << semantic << ") without assigned effect" << endl; + } else { + // Grab the common profile effect + const FCDEffectStandard* effect_common = (FCDEffectStandard *)effect->FindProfile(FUDaeProfileType::COMMON); + if (effect_common == NULL) { + daeegg_cat.debug() << "Ignoring effect referenced by material with semantic " << semantic + << " because it has no common profile" << endl; + } else { + daeegg_cat.spam() << "Processing effect, material semantic is " << semantic << endl; + // Set the material parameters + egg_material->set_amb(CONV_COLOR(effect_common->GetAmbientColor())); + ////TODO: find a better way for transparency + //LVecBase4f diffuse = CONV_COLOR(effect_common->GetDiffuseColor()); + //diffuse.set_w(diffuse.get_w() * (1.0f - effect_common->GetOpacity())); + //egg_material->set_diff(diffuse); + egg_material->set_diff(CONV_COLOR(effect_common->GetDiffuseColor())); + egg_material->set_emit(CONV_COLOR(effect_common->GetEmissionColor()) * effect_common->GetEmissionFactor()); + egg_material->set_shininess(effect_common->GetShininess()); + egg_material->set_spec(CONV_COLOR(effect_common->GetSpecularColor())); + // Now try to load in the textures + process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::DIFFUSE, EggTexture::ET_modulate); + process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::BUMP, EggTexture::ET_normal); + process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::SPECULAR, EggTexture::ET_modulate_gloss); + process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::SPECULAR_LEVEL, EggTexture::ET_gloss); + process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::OPACITY, EggTexture::ET_unspecified, EggTexture::F_alpha); + process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::TRANSPARENT, EggTexture::ET_unspecified, EggTexture::F_alpha); + process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::EMISSION, EggTexture::ET_add); + // Now, calculate the color blend stuff. + _materials[semantic]->_blend = convert_blend(effect_common->GetTransparencyMode(), + CONV_COLOR(effect_common->GetTranslucencyColor()), + effect_common->GetTranslucencyFactor()); + } + // Find an tag to support some extra stuff from extensions + process_extra(semantic, effect->GetExtra()); + } + daeegg_cat.spam() << "Found " << egg_textures.size() << " textures in material" << endl; + _materials[semantic]->_egg_material = egg_material; +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeMaterials::process_texture_bucket +// Access: Private +// Description: Processes the given texture bucket and gives +// the textures in it the given envtype and format. +//////////////////////////////////////////////////////////////////// +void DaeMaterials:: +process_texture_bucket(const string semantic, const FCDEffectStandard* effect_common, FUDaeTextureChannel::Channel bucket, EggTexture::EnvType envtype, EggTexture::Format format) { + for (size_t tx = 0; tx < effect_common->GetTextureCount(bucket); ++tx) { + const FCDImage* image = effect_common->GetTexture(bucket, tx)->GetImage(); + if (image == NULL) { + daeegg_cat.warning() << "Texture references a nonexisting image!" << endl; + } else { + const FCDEffectParameterSampler* sampler = effect_common->GetTexture(bucket, tx)->GetSampler(); + // FCollada only supplies absolute paths. We need to grab the document + // location ourselves and make the image path absolute. + Filename texpath; + if (image->GetDocument()) { + Filename docpath = Filename::from_os_specific(FROM_FSTRING(image->GetDocument()->GetFileUrl())); + docpath.make_canonical(); + texpath = Filename::from_os_specific(FROM_FSTRING(image->GetFilename())); + texpath.make_canonical(); + texpath.make_relative_to(docpath.get_dirname(), true); + daeegg_cat.debug() << "Found texture with path " << texpath << endl; + } else { + // Never mind. + texpath = Filename::from_os_specific(FROM_FSTRING(image->GetFilename())); + } + PT_EggTexture egg_texture = new EggTexture(FROM_FSTRING(image->GetDaeId()), texpath.to_os_generic()); + // Find a set of UV coordinates + const FCDEffectParameterInt* uvset = effect_common->GetTexture(bucket, tx)->GetSet(); + if (uvset != NULL) { + if (_materials[semantic]->_uvsets.count(uvset->GetValue()) == 0) { + daeegg_cat.warning() << "Texture references a nonexisting UV coordinate set!" << endl; + } else { + egg_texture->set_uv_name(_materials[semantic]->_uvsets[uvset->GetValue()]); + } + } + // Apply sampler stuff + if (sampler != NULL) { + egg_texture->set_texture_type(convert_texture_type(sampler->GetSamplerType())); + egg_texture->set_wrap_u(convert_wrap_mode(sampler->GetWrapS())); + if (sampler->GetSamplerType() != FCDEffectParameterSampler::SAMPLER1D) { + egg_texture->set_wrap_v(convert_wrap_mode(sampler->GetWrapT())); + } + if (sampler->GetSamplerType() == FCDEffectParameterSampler::SAMPLER3D) { + egg_texture->set_wrap_w(convert_wrap_mode(sampler->GetWrapP())); + } + egg_texture->set_minfilter(convert_filter_type(sampler->GetMinFilter())); + egg_texture->set_magfilter(convert_filter_type(sampler->GetMagFilter())); + if (envtype != EggTexture::ET_unspecified) { + egg_texture->set_env_type(envtype); + } + if (format != EggTexture::F_unspecified) { + egg_texture->set_format(format); + } + } + _materials[semantic]->_egg_textures.push_back(egg_texture); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeMaterials::process_extra +// Access: Private +// Description: Processes the extra data in the given tag. +// If the given element is NULL, it just silently +// returns. +//////////////////////////////////////////////////////////////////// +void DaeMaterials:: +process_extra(const string semantic, const FCDExtra* extra) { + if (extra == NULL) return; + const FCDEType* etype = extra->GetDefaultType(); + if (etype == NULL) return; + for (size_t et = 0; et < etype->GetTechniqueCount(); ++et) { + const FCDENode* enode = ((const FCDENode*)(etype->GetTechnique(et)))->FindChildNode("double_sided"); + if (enode != NULL) { + if (trim(enode->GetContent()) == "1") { + _materials[semantic]->_double_sided = true; + } else if (trim(enode->GetContent()) == "0") { + _materials[semantic]->_double_sided = false; + } else { + daeegg_cat.warning() << "Expected tag to be either 1 or 0, found '" << enode->GetContent() << "' instead" << endl; + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeMaterials::apply_to +// Access: Public +// Description: Applies the stuff to the given EggPrimitive. +//////////////////////////////////////////////////////////////////// +void DaeMaterials:: +apply_to(const string semantic, const PT(EggPrimitive) to) { + if (_materials.count(semantic) > 0) { + to->set_material(_materials[semantic]->_egg_material); + for (pvector::iterator it = _materials[semantic]->_egg_textures.begin(); it != _materials[semantic]->_egg_textures.end(); ++it) { + daeegg_cat.spam() << "Applying texture " << (*it)->get_name() << " from material with semantic " << semantic << endl; + to->add_texture(*it); + } + to->set_bface_flag(_materials[semantic]->_double_sided); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeMaterials::apply_to +// Access: Public +// Description: Applies the colorblend stuff to the given EggGroup. +//////////////////////////////////////////////////////////////////// +void DaeMaterials:: +apply_to(const string semantic, const PT(EggGroup) to) { + if (_materials.count(semantic) > 0) { + PT(DaeBlendSettings) blend = _materials[semantic]->_blend; + if (blend->_enabled) { + to->set_blend_mode(EggGroup::BM_add); + to->set_blend_color(blend->_color); + to->set_blend_operand_a(blend->_operand_a); + to->set_blend_operand_b(blend->_operand_b); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeMaterials::get_uvset_name +// Access: Public +// Description: Returns the name of the uvset with the specified +// FCollada input set, or an empty string if the given +// material has no input set. +//////////////////////////////////////////////////////////////////// +const string DaeMaterials:: +get_uvset_name(const string semantic, int32 input_set) { + if (_materials.count(semantic) > 0 && _materials[semantic]->_uvsets.count(input_set)) { + return _materials[semantic]->_uvsets[input_set]; + } + return ""; +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeMaterials::convert_texture_type +// Access: Public, Static +// Description: Converts an FCollada sampler type to the EggTexture +// texture type equivalent. +//////////////////////////////////////////////////////////////////// +EggTexture::TextureType DaeMaterials:: +convert_texture_type(const FCDEffectParameterSampler::SamplerType orig_type) { + switch (orig_type) { + case FCDEffectParameterSampler::SAMPLER1D: + return EggTexture::TT_1d_texture; + case FCDEffectParameterSampler::SAMPLER2D: + return EggTexture::TT_2d_texture; + case FCDEffectParameterSampler::SAMPLER3D: + return EggTexture::TT_3d_texture; + case FCDEffectParameterSampler::SAMPLERCUBE: + return EggTexture::TT_cube_map; + default: + daeegg_cat.warning() << "Invalid sampler type found" << endl; + } + return EggTexture::TT_unspecified; +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeMaterials::convert_wrap_mode +// Access: Public, Static +// Description: Converts an FCollada wrap mode to the +// EggTexture wrap mode equivalent. +//////////////////////////////////////////////////////////////////// +EggTexture::WrapMode DaeMaterials:: +convert_wrap_mode(const FUDaeTextureWrapMode::WrapMode orig_mode) { + switch (orig_mode) { + case FUDaeTextureWrapMode::NONE: + //FIXME: this shouldnt be unspecified + return EggTexture::WM_unspecified; + case FUDaeTextureWrapMode::WRAP: + return EggTexture::WM_repeat; + case FUDaeTextureWrapMode::MIRROR: + return EggTexture::WM_mirror; + case FUDaeTextureWrapMode::CLAMP: + return EggTexture::WM_clamp; + case FUDaeTextureWrapMode::BORDER: + return EggTexture::WM_border_color; + case FUDaeTextureWrapMode::UNKNOWN: + return EggTexture::WM_unspecified; + default: + daeegg_cat.warning() << "Invalid wrap mode found: " << FUDaeTextureWrapMode::ToString(orig_mode) << endl; + } + return EggTexture::WM_unspecified; +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeMaterials::convert_filter_type +// Access: Public, Static +// Description: Converts an FCollada filter function to the +// EggTexture wrap type equivalent. +//////////////////////////////////////////////////////////////////// +EggTexture::FilterType DaeMaterials:: +convert_filter_type(const FUDaeTextureFilterFunction::FilterFunction orig_type) { + switch (orig_type) { + case FUDaeTextureFilterFunction::NONE: + //FIXME: this shouldnt be unspecified + return EggTexture::FT_unspecified; + case FUDaeTextureFilterFunction::NEAREST: + return EggTexture::FT_nearest; + case FUDaeTextureFilterFunction::LINEAR: + return EggTexture::FT_linear; + case FUDaeTextureFilterFunction::NEAREST_MIPMAP_NEAREST: + return EggTexture::FT_nearest_mipmap_nearest; + case FUDaeTextureFilterFunction::LINEAR_MIPMAP_NEAREST: + return EggTexture::FT_linear_mipmap_nearest; + case FUDaeTextureFilterFunction::NEAREST_MIPMAP_LINEAR: + return EggTexture::FT_nearest_mipmap_linear; + case FUDaeTextureFilterFunction::LINEAR_MIPMAP_LINEAR: + return EggTexture::FT_linear_mipmap_linear; + case FUDaeTextureFilterFunction::UNKNOWN: + return EggTexture::FT_unspecified; + default: + daeegg_cat.warning() << "Unknown filter type found: " << FUDaeTextureFilterFunction::ToString(orig_type) << endl; + } + return EggTexture::FT_unspecified; +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeMaterials::convert_blend +// Access: Private, Static +// Description: Converts collada blend attribs to Panda's equivalents. +//////////////////////////////////////////////////////////////////// +PT(DaeMaterials::DaeBlendSettings) DaeMaterials:: +convert_blend(FCDEffectStandard::TransparencyMode mode, Colorf transparent, double transparency) { + // Create the DaeBlendSettings and fill it with some defaults. + PT(DaeBlendSettings) blend = new DaeBlendSettings(); + blend->_enabled = true; + blend->_color = Colorf::zero(); + blend->_operand_a = EggGroup::BO_unspecified; + blend->_operand_b = EggGroup::BO_unspecified; + + // First fill in the color value. + if (mode == FCDEffectStandard::A_ONE) {// || mode == FCDEffectStandard::A_ZERO) { + double value = transparent[3] * transparency; + blend->_color = Colorf(value, value, value, value); + } else if (mode == FCDEffectStandard::RGB_ZERO) {//|| mode == FCDEffectStandard::RGB_ONE) { + blend->_color = transparent * transparency; + blend->_color[3] = luminance(blend->_color); + } else { + daeegg_cat.error() << "Unknown opaque type found!" << endl; + blend->_enabled = false; + return blend; + } + + // Now figure out the operands. + if (mode == FCDEffectStandard::RGB_ZERO) {// || mode == FCDEffectStandard::A_ZERO) { + blend->_operand_a = EggGroup::BO_constant_color; + blend->_operand_b = EggGroup::BO_one_minus_constant_color; + } else if (mode == FCDEffectStandard::A_ONE) {// || mode == FCDEffectStandard::RGB_ONE) { + blend->_operand_a = EggGroup::BO_one_minus_constant_color; + blend->_operand_b = EggGroup::BO_constant_color; + } else { + daeegg_cat.error() << "Unknown opaque type found!" << endl; + blend->_enabled = false; + return blend; + } + + // See if we can optimize out the color. + if (blend->_operand_a == EggGroup::BO_constant_color) { + if (blend->_color[0] == blend->_color[1] == blend->_color[2] == blend->_color[3] == 0) { + blend->_operand_a = EggGroup::BO_zero; + } + if (blend->_color[0] == blend->_color[1] == blend->_color[2] == blend->_color[3] == 1) { + blend->_operand_a = EggGroup::BO_one; + } + } + if (blend->_operand_b == EggGroup::BO_one_minus_constant_color) { + if (blend->_color[0] == blend->_color[1] == blend->_color[2] == blend->_color[3] == 0) { + blend->_operand_b = EggGroup::BO_one; + } + if (blend->_color[0] == blend->_color[1] == blend->_color[2] == blend->_color[3] == 1) { + blend->_operand_b = EggGroup::BO_zero; + } + } + + // See if we can entirely disable the blend. + if (blend->_operand_a == EggGroup::BO_one && blend->_operand_b == EggGroup::BO_zero) { + blend->_enabled = false; + } + return blend; +} diff --git a/pandatool/src/daeegg/daeMaterials.h b/pandatool/src/daeegg/daeMaterials.h new file mode 100755 index 0000000000..2303937762 --- /dev/null +++ b/pandatool/src/daeegg/daeMaterials.h @@ -0,0 +1,97 @@ +// Filename: daeMaterials.h +// Created by: pro-rsoft (03Oct08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#ifndef DAEMATERIALS_H +#define DAEMATERIALS_H + +#include "pandatoolbase.h" +#include "eggMaterial.h" +#include "eggTexture.h" +#include "eggPrimitive.h" +#include "eggGroup.h" +#include "pointerTo.h" +#include "pt_EggTexture.h" +#include "pt_EggMaterial.h" + +#include "pre_fcollada_include.h" +#include "FCollada.h" +#include "FCDocument/FCDGeometryInstance.h" +#include "FCDocument/FCDMaterialInstance.h" +#include "FCDocument/FCDEffectStandard.h" +#include "FCDocument/FCDEffectParameterSampler.h" +#include "FCDocument/FCDExtra.h" + +//////////////////////////////////////////////////////////////////// +// Class : DaeMaterials +// Description : This class is seperated from the converter file +// because otherwise it would get too big and +// needlessly complicated. +//////////////////////////////////////////////////////////////////// +class DaeMaterials : public TypedReferenceCount { +public: + DaeMaterials(const FCDGeometryInstance* geometry_instance); + virtual ~DaeMaterials() {}; + + void add_material_instance(const FCDMaterialInstance* instance); + void apply_to(const string semantic, const PT(EggPrimitive) to); + void apply_to(const string semantic, const PT(EggGroup) to); + const string get_uvset_name(const string semantic, int32 input_set); + + static EggTexture::TextureType convert_texture_type(const FCDEffectParameterSampler::SamplerType orig_type); + static EggTexture::WrapMode convert_wrap_mode(const FUDaeTextureWrapMode::WrapMode orig_mode); + static EggTexture::FilterType convert_filter_type(const FUDaeTextureFilterFunction::FilterFunction orig_type); + +private: + // Holds stuff for color blend attribs. + struct DaeBlendSettings : public ReferenceCount { + bool _enabled; + Colorf _color; + EggGroup::BlendOperand _operand_a; + EggGroup::BlendOperand _operand_b; + }; + + // Holds stuff for an individual material. + struct DaeMaterial : public ReferenceCount { + pvector _egg_textures; + PT_EggMaterial _egg_material; + bool _double_sided; + pmap _uvsets; + PT(DaeBlendSettings) _blend; + }; + + void process_texture_bucket(const string semantic, const FCDEffectStandard* effect_common, FUDaeTextureChannel::Channel bucket, EggTexture::EnvType envtype = EggTexture::ET_unspecified, EggTexture::Format format = EggTexture::F_unspecified); + void process_extra(const string semantic, const FCDExtra* extra); + static PT(DaeBlendSettings) convert_blend(FCDEffectStandard::TransparencyMode mode, Colorf transparent, double transparency); + + pmap _materials; + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedReferenceCount::init_type(); + register_type(_type_handle, "DaeMaterials", + TypedReferenceCount::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#endif diff --git a/pandatool/src/daeegg/daeToEggConverter.cxx b/pandatool/src/daeegg/daeToEggConverter.cxx new file mode 100755 index 0000000000..52345fb204 --- /dev/null +++ b/pandatool/src/daeegg/daeToEggConverter.cxx @@ -0,0 +1,614 @@ +// Filename: daeToEggConverter.cxx +// Created by: pro-rsoft (08May08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#include "daeToEggConverter.h" +#include "config_daeegg.h" +#include "daeCharacter.h" +#include "dcast.h" +#include "string_utils.h" +#include "eggData.h" +#include "eggPrimitive.h" +#include "eggLine.h" +#include "eggPolygon.h" +#include "eggTriangleFan.h" +#include "eggTriangleStrip.h" +#include "eggPoint.h" +#include "eggXfmSAnim.h" +#include "eggSAnimData.h" +#include "pt_EggVertex.h" + +#include "FCDocument/FCDAsset.h" +#include "FCDocument/FCDocumentTools.h" +#include "FCDocument/FCDSceneNode.h" +#include "FCDocument/FCDSceneNodeTools.h" +#include "FCDocument/FCDGeometry.h" +#include "FCDocument/FCDGeometryInstance.h" +#include "FCDocument/FCDGeometryPolygons.h" +#include "FCDocument/FCDGeometrySource.h" +#include "FCDocument/FCDSkinController.h" +#include "FCDocument/FCDController.h" +#include "FCDocument/FCDControllerInstance.h" +#include "FCDocument/FCDMorphController.h" +#include "FCDocument/FCDMaterialInstance.h" +#include "FCDocument/FCDExtra.h" +#include "FCDocument/FCDEffect.h" +#include "FCDocument/FCDEffectStandard.h" + +// Useful conversion stuff +#define TO_VEC3(v) (LVecBase3d(v[0], v[1], v[2])) +#define TO_VEC4(v) (LVecBase4d(v[0], v[1], v[2], v[3])) +#define TO_COLOR(v) (Colorf(v[0], v[1], v[2], v[3])) +#define FROM_VEC3(v) (FMVector3(v[0], v[1], v[2])) +#define FROM_VEC4(v) (FMVector4(v[0], v[1], v[2], v[3])) +#define FROM_MAT4(v) (FMMatrix44(v.getData())) +#define FROM_FSTRING(fs) (string(fs.c_str())) + +//////////////////////////////////////////////////////////////////// +// Function: DAEToEggConverter::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DAEToEggConverter:: +DAEToEggConverter() { + _document = NULL; + _table = NULL; + _frame_rate = -1; +} + +//////////////////////////////////////////////////////////////////// +// Function: DAEToEggConverter::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DAEToEggConverter:: +DAEToEggConverter(const DAEToEggConverter ©) : + SomethingToEggConverter(copy) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: DAEToEggConverter::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DAEToEggConverter:: +~DAEToEggConverter() { +} + +//////////////////////////////////////////////////////////////////// +// Function: DAEToEggConverter::make_copy +// Access: Public, Virtual +// Description: Allocates and returns a new copy of the converter. +//////////////////////////////////////////////////////////////////// +SomethingToEggConverter *DAEToEggConverter:: +make_copy() { + return new DAEToEggConverter(*this); +} + + +//////////////////////////////////////////////////////////////////// +// Function: DAEToEggConverter::get_name +// Access: Public, Virtual +// Description: Returns the English name of the file type this +// converter supports. +//////////////////////////////////////////////////////////////////// +string DAEToEggConverter:: +get_name() const { + return "COLLADA"; +} + +//////////////////////////////////////////////////////////////////// +// Function: DAEToEggConverter::get_extension +// Access: Public, Virtual +// Description: Returns the common extension of the file type this +// converter supports. +//////////////////////////////////////////////////////////////////// +string DAEToEggConverter:: +get_extension() const { + return "dae"; +} + +//////////////////////////////////////////////////////////////////// +// Function: DAEToEggConverter::convert_file +// Access: Public, Virtual +// Description: Handles the reading of the input file and converting +// it to egg. Returns true if successful, false +// otherwise. +//////////////////////////////////////////////////////////////////// +bool DAEToEggConverter:: +convert_file(const Filename &filename) { + // Reset stuff + clear_error(); + _joints.clear(); + _vertex_pools.clear(); + _skeletons.clear(); + _frame_rate = -1; + + // The default coordinate system is Y-up + if (_egg_data->get_coordinate_system() == CS_default) { + _egg_data->set_coordinate_system(CS_yup_right); + } + + // Read the file + FCollada::Initialize(); + _document = FCollada::LoadDocument(filename.to_os_specific().c_str()); + if(_document == NULL) { + daeegg_cat.error() << "Failed to load document: " << _error_handler.GetErrorString() << endl; + FCollada::Release(); + return false; + } + // Make sure the file uses consistent coordinate system and length + FCDocumentTools::StandardizeUpAxisAndLength(_document); + + _table = new EggTable(); + _table->set_table_type(EggTable::TT_table); + // Process the stuff + process_asset(); + preprocess(); + FCDSceneNode* visual_scene = _document->GetVisualSceneInstance(); + if (visual_scene != NULL) { + // First check for an tag + const FCDExtra* extra = visual_scene->GetExtra(); + //FIXME: eek this looks horrid + if (extra != NULL) { + const FCDEType* etype = extra->GetDefaultType(); + if (etype != NULL) { + const FCDENode* enode = (const FCDENode*) etype->FindTechnique("MAX3D"); + if (enode != NULL) { + enode = enode->FindChildNode("frame_rate"); + if (enode != NULL && !string_to_int(enode->GetContent(), _frame_rate)) { + daeegg_cat.warning() << "Invalid integer in tag: '" << enode->GetContent() << "'" << endl; + } } } } + // Now loop through the children + for (size_t ch = 0; ch < visual_scene->GetChildrenCount(); ++ch) { + process_node(DCAST(EggGroupNode, _egg_data), visual_scene->GetChild(ch)); + } + } + SAFE_DELETE(visual_scene); + + _egg_data->add_child(_table); + + // Clean up and return + SAFE_DELETE(_document); + FCollada::Release(); + return true; +} + +void DAEToEggConverter::process_asset() { + if (_document->GetAsset() == NULL) return; + // Read out the coordinate system + FMVector3 up_axis (_document->GetAsset()->GetUpAxis()); + if (up_axis == FMVector3(0, 1, 0)) { + _egg_data->set_coordinate_system(CS_yup_right); + } else if (up_axis == FMVector3(0, 0, 1)) { + _egg_data->set_coordinate_system(CS_zup_right); + } else { + _egg_data->set_coordinate_system(CS_invalid); + daeegg_cat.warning() << "Unrecognized coordinate system!\n"; + } +} + +// This function lists all the joints and referenced skeletons +void DAEToEggConverter::preprocess(const FCDSceneNode* node) { + // If the node is NULL, take the visual scene instance. + if (node == NULL) { + assert(_document != NULL); + _skeletons.clear(); + _joints.clear(); + node = _document->GetVisualSceneInstance(); + } + if (node == NULL) return; + if (node->IsJoint()) { + _joints[FROM_FSTRING(node->GetDaeId())] = NULL; + } + // Loop through the instances first. + for (size_t in = 0; in < node->GetInstanceCount(); ++in) { + if (node->GetInstance(in)->GetType() == FCDEntityInstance::CONTROLLER) { + // Loop through the skeleton roots now. + FCDSceneNodeList roots = ((FCDControllerInstance*) node->GetInstance(in))->FindSkeletonNodes(); + for (FCDSceneNodeList::iterator it = roots.begin(); it != roots.end(); ++it) { + daeegg_cat.spam() << "Found referenced skeleton root " << FROM_FSTRING((*it)->GetDaeId()) << endl; + _skeletons.push_back(FROM_FSTRING((*it)->GetDaeId())); + } + } + } + // Now loop through the children and recurse. + for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) { + preprocess(node->GetChild(ch)); + } +} + +// Process the node. If forced is true, it will even process it if its known to be a skeleton root. +void DAEToEggConverter::process_node(PT(EggGroupNode) parent, const FCDSceneNode* node, bool forced) { + nassertv(node != NULL); + string node_id = FROM_FSTRING(node->GetDaeId()); + daeegg_cat.spam() << "Processing node with ID '" << node_id << "'" << endl; + // Important! If it's known to be a skeleton root, ignore it for now, unless we're processing forced. + if (!forced && count(_skeletons.begin(), _skeletons.end(), node_id) > 0) { + daeegg_cat.spam() << "Ignoring skeleton root node with ID '" << node_id << "', we'll process it later" << endl; + return; + } + // Create an egg group for this node + PT(EggGroup) node_group = new EggGroup(node_id); + parent->add_child(node_group); + // Check if its a joint + if (node->IsJoint()) { + node_group->set_group_type(EggGroup::GT_joint); + _joints[node_id] = node_group; + } + // Loop through the transforms and apply them + for (size_t tr = 0; tr < node->GetTransformCount(); ++tr) { + apply_transform(node_group, node->GetTransform(tr)); + } + // Loop through the instances and process them + for (size_t in = 0; in < node->GetInstanceCount(); ++in) { + process_instance(node_group, node->GetInstance(in)); + } + // Loop through the children and recursively process them + for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) { + process_node(DCAST(EggGroupNode, node_group), node->GetChild(ch)); + } + // Loop through any possible scene node instances and process those, too. + for (size_t in = 0; in < node->GetInstanceCount(); ++in) { + if (node->GetInstance(in)->GetEntity() && node->GetInstance(in)->GetEntity()->GetType() == FCDEntity::SCENE_NODE) { + process_node(DCAST(EggGroupNode, node_group), (const FCDSceneNode*) node->GetInstance(in)->GetEntity()); + } + } +} + +void DAEToEggConverter::process_instance(PT(EggGroup) parent, const FCDEntityInstance* instance) { + nassertv(instance != NULL); + nassertv(instance->GetEntity() != NULL); + // Check what kind of instance this is + switch (instance->GetType()) { + case FCDEntityInstance::GEOMETRY: { + const FCDGeometry* geometry = (const FCDGeometry*) instance->GetEntity(); + assert(geometry != NULL); + if (geometry->IsMesh()) { + // Now, handle the mesh. + process_mesh(parent, geometry->GetMesh(), new DaeMaterials((const FCDGeometryInstance*) instance)); + } + if (geometry->IsSpline()) { + process_spline(parent, FROM_FSTRING(geometry->GetDaeId()), const_cast (geometry->GetSpline())); + } + break; } + case FCDEntityInstance::CONTROLLER: { + // Add the dart tag and process the controller instance + parent->set_dart_type(EggGroup::DT_default); + process_controller(parent, (const FCDControllerInstance*) instance); + break; } + case FCDEntityInstance::MATERIAL: + // We don't process this directly, handled per-geometry instead. + break; + case FCDEntityInstance::SIMPLE: { + // Grab the entity and check it's type. + const FCDEntity* entity = instance->GetEntity(); + if (entity->GetType() != FCDEntity::SCENE_NODE) { + daeegg_cat.warning() << "Unsupported entity type found" << endl; + } + break; } + default: + daeegg_cat.warning() << "Unsupported instance type found" << endl; + } +} + +// Processes the given mesh. +void DAEToEggConverter::process_mesh(PT(EggGroup) parent, const FCDGeometryMesh* mesh, PT(DaeMaterials) materials) { + nassertv(mesh != NULL); + // Create the egg stuff to hold this mesh + PT(EggGroup) mesh_group = new EggGroup(FROM_FSTRING(mesh->GetDaeId())); + parent->add_child(mesh_group); + PT(EggVertexPool) mesh_pool = new EggVertexPool(FROM_FSTRING(mesh->GetDaeId())); + mesh_group->add_child(mesh_pool); + _vertex_pools[FROM_FSTRING(mesh->GetDaeId())] = mesh_pool; + // First retrieve the vertex source + if (mesh->GetSourceCount() == 0) return; + const FCDGeometrySource* vsource = mesh->FindSourceByType(FUDaeGeometryInput::POSITION); + if (vsource == NULL) return; + // Stores which group holds the primitives. + PT(EggGroup) primitiveholder; + // Loop through the polygon groups and add them + for (size_t gr = 0; gr < mesh->GetPolygonsCount(); ++gr) { + const FCDGeometryPolygons* polygons = mesh->GetPolygons(gr); + primitiveholder = mesh_group; + // If we have materials, make a group for each material. Then, apply the material's per-group stuff. + if (materials != NULL && (!polygons->GetMaterialSemantic().empty()) && mesh->GetPolygonsCount() > 1) { + primitiveholder = new EggGroup(FROM_FSTRING(mesh->GetDaeId()) + FROM_FSTRING(polygons->GetMaterialSemantic())); + mesh_group->add_child(primitiveholder); + } + // Apply the per-group data of the materials, if we have it. + if (materials != NULL) { + materials->apply_to(FROM_FSTRING(polygons->GetMaterialSemantic()), primitiveholder); + } + // Find the position sources + const FCDGeometryPolygonsInput* pinput = polygons->FindInput(FUDaeGeometryInput::POSITION); + assert(pinput != NULL); + const uint32* indices = pinput->GetIndices(); + // Find the normal sources + const FCDGeometrySource* nsource = mesh->FindSourceByType(FUDaeGeometryInput::NORMAL); + const FCDGeometryPolygonsInput* ninput = polygons->FindInput(FUDaeGeometryInput::NORMAL); + const uint32* nindices; + if (ninput != NULL) nindices = ninput->GetIndices(); + // Find texcoord sources + const FCDGeometrySource* tcsource = mesh->FindSourceByType(FUDaeGeometryInput::TEXCOORD); + const FCDGeometryPolygonsInput* tcinput = polygons->FindInput(FUDaeGeometryInput::TEXCOORD); + const uint32* tcindices; + if (tcinput != NULL) tcindices = tcinput->GetIndices(); + // Find vcolor sources + const FCDGeometrySource* csource = mesh->FindSourceByType(FUDaeGeometryInput::COLOR); + const FCDGeometryPolygonsInput* cinput = polygons->FindInput(FUDaeGeometryInput::COLOR); + const uint32* cindices; + if (cinput != NULL) cindices = cinput->GetIndices(); + // Find binormal sources + const FCDGeometrySource* bsource = mesh->FindSourceByType(FUDaeGeometryInput::TEXBINORMAL); + const FCDGeometryPolygonsInput* binput = polygons->FindInput(FUDaeGeometryInput::TEXBINORMAL); + const uint32* bindices; + if (binput != NULL) bindices = binput->GetIndices(); + // Find tangent sources + const FCDGeometrySource* tsource = mesh->FindSourceByType(FUDaeGeometryInput::TEXTANGENT); + const FCDGeometryPolygonsInput* tinput = polygons->FindInput(FUDaeGeometryInput::TEXTANGENT); + const uint32* tindices; + if (tinput != NULL) tindices = tinput->GetIndices(); + // Get a name for potential texture coordinate sets + string uvsetname (""); + if (materials != NULL && tcinput != NULL) { + uvsetname = materials->get_uvset_name(FROM_FSTRING(polygons->GetMaterialSemantic()), tcinput->GetSet()); + } + // Loop through the indices and add the vertices. + for (size_t ix = 0; ix < pinput->GetIndexCount(); ++ix) { + PT_EggVertex vertex = mesh_pool->make_new_vertex(); + const float* data = &vsource->GetData()[indices[ix]*3]; + vertex->set_pos(LPoint3d(data[0], data[1], data[2])); + // Process the normal + if (nsource != NULL && ninput != NULL) { + assert(nsource->GetStride() == 3); + data = &nsource->GetData()[nindices[ix]*3]; + vertex->set_normal(LVecBase3d(data[0], data[1], data[2])); + } + // Process the texcoords + if (tcsource != NULL && tcinput != NULL) { + assert(tcsource->GetStride() == 2 || tcsource->GetStride() == 3); + data = &tcsource->GetData()[tcindices[ix]*tcsource->GetStride()]; + if (tcsource->GetStride() == 2) { + vertex->set_uv(uvsetname, LPoint2d(data[0], data[1])); + } else { + vertex->set_uvw(uvsetname, LPoint3d(data[0], data[1], data[2])); + } + } + // Process the color + if (csource != NULL && cinput != NULL) { + assert(csource->GetStride() == 4); + data = &csource->GetData()[cindices[ix]*4]; + vertex->set_color(Colorf(data[0], data[1], data[2], data[3])); + } + // Possibly add a UV object + if ((bsource != NULL && binput != NULL) || (tsource != NULL && tinput != NULL)) { + PT(EggVertexUV) vertex_uv; + if (tcsource != NULL && tcinput != NULL) { + assert(tcsource->GetStride() == 2 || tcsource->GetStride() == 3); + data = &tcsource->GetData()[tcindices[ix]*tcsource->GetStride()]; + if (tcsource->GetStride() == 2) { + vertex_uv = new EggVertexUV(uvsetname, TexCoordd(data[0], data[1])); + } else { + vertex_uv = new EggVertexUV(uvsetname, TexCoord3d(data[0], data[1], data[2])); + } + } else { + vertex_uv = new EggVertexUV(uvsetname, TexCoordd()); + } + vertex->set_uv_obj(vertex_uv); + if (bsource != NULL && binput != NULL) { + assert(bsource->GetStride() == 3); + data = &bsource->GetData()[bindices[ix]*3]; + vertex_uv->set_binormal(LVecBase3d(data[0], data[1], data[2])); + } + if (tsource != NULL && tinput != NULL) { + assert(tsource->GetStride() == 3); + data = &tsource->GetData()[tindices[ix]*3]; + vertex_uv->set_tangent(LVecBase3d(data[0], data[1], data[2])); + } + } + vertex->transform(parent->get_node_to_vertex()); + } + // Now loop through the faces + for (size_t fa = polygons->GetFaceOffset(); fa < polygons->GetFaceOffset() + polygons->GetFaceCount(); ++fa) { + PT(EggPrimitive) primitive = NULL; + // Create a primitive that matches the fcollada type + switch (polygons->GetPrimitiveType()) { + case FCDGeometryPolygons::LINES: + primitive = new EggLine(); + break; + case FCDGeometryPolygons::POLYGONS: + primitive = new EggPolygon(); + break; + case FCDGeometryPolygons::TRIANGLE_FANS: + primitive = new EggTriangleFan(); + break; + case FCDGeometryPolygons::TRIANGLE_STRIPS: + primitive = new EggTriangleStrip(); + break; + case FCDGeometryPolygons::POINTS: + primitive = new EggPoint(); + break; + case FCDGeometryPolygons::LINE_STRIPS: + daeegg_cat.warning() << "Linestrips not yet supported!" << endl; + break; + default: + daeegg_cat.warning() << "Unsupported primitive type found!\n"; + } + if (primitive != NULL) { + primitiveholder->add_child(primitive); + if (materials != NULL) { + materials->apply_to(FROM_FSTRING(polygons->GetMaterialSemantic()), primitive); + } + for (size_t ve = polygons->GetFaceVertexOffset(fa); ve < polygons->GetFaceVertexOffset(fa) + polygons->GetFaceVertexCount(fa); ++ve) { + assert(mesh_pool->has_vertex(ve)); + primitive->add_vertex(mesh_pool->get_vertex(ve)); + } + } + } + } +} + +void DAEToEggConverter::process_spline(PT(EggGroup) parent, const string group_name, FCDGeometrySpline* geometry_spline) { + assert(geometry_spline != NULL); + PT(EggGroup) result = new EggGroup(group_name); + parent->add_child(result); + //TODO: if its not a nurbs, make it convert between the types + if (geometry_spline->GetType() != FUDaeSplineType::NURBS) { + daeegg_cat.warning() << "Only NURBS curves are supported (yet)!" << endl; + } else { + // Loop through the splines + for (size_t sp = 0; sp < geometry_spline->GetSplineCount(); ++sp) { + process_spline(result, geometry_spline->GetSpline(sp)); + } + } +} + +void DAEToEggConverter::process_spline(PT(EggGroup) parent, const FCDSpline* spline) { + assert(spline != NULL); + nassertv(spline->GetSplineType() == FUDaeSplineType::NURBS); + // Now load in the nurbs curve to the egg library + PT(EggNurbsCurve) nurbs_curve = new EggNurbsCurve(FROM_FSTRING(spline->GetName())); + parent->add_child(nurbs_curve); + //TODO: what value is this? + nurbs_curve->setup(0, ((const FCDNURBSSpline*) spline)->GetKnotCount()); + for (size_t kn = 0; kn < ((const FCDNURBSSpline*) spline)->GetKnotCount(); ++kn) { + const float* knot = ((const FCDNURBSSpline*) spline)->GetKnot(kn); + assert(knot != NULL); + nurbs_curve->set_knot(kn, *knot); + } + for (size_t cv = 0; cv < spline->GetCVCount(); ++cv) { + PT_EggVertex c_vtx = new EggVertex(); + c_vtx->set_pos(TO_VEC3(*spline->GetCV(cv))); + c_vtx->transform(parent->get_node_to_vertex()); + nurbs_curve->add_vertex(c_vtx); + } +} + +void DAEToEggConverter::process_controller(PT(EggGroup) parent, const FCDControllerInstance* instance) { + assert(instance != NULL); + const FCDController* controller = (const FCDController*) instance->GetEntity(); + assert(controller != NULL); + PT(EggVertexPool) vertex_pool = NULL; + // Add the skin geometry + const FCDGeometry* geometry = controller->GetBaseGeometry(); + if (geometry != NULL) { + if (geometry->IsMesh()) { + process_mesh(parent, geometry->GetMesh(), new DaeMaterials((const FCDGeometryInstance*) instance)); + if (_vertex_pools.count(FROM_FSTRING(geometry->GetMesh()->GetDaeId()))) { + vertex_pool = _vertex_pools[FROM_FSTRING(geometry->GetMesh()->GetDaeId())]; + } + } + if (geometry->IsSpline()) { + process_spline(parent, FROM_FSTRING(geometry->GetDaeId()), const_cast (geometry->GetSpline())); + } + } + // Add the joint hierarchy + FCDSceneNodeList roots = (const_cast (instance))->FindSkeletonNodes(); + for (FCDSceneNodeList::iterator it = roots.begin(); it != roots.end(); ++it) { + process_node(DCAST(EggGroupNode, parent), *it, true); + } + if (controller->IsSkin()) { + // Load in the vertex influences first + pmap > > influences; + if (vertex_pool) { + for (size_t in = 0; in < controller->GetSkinController()->GetInfluenceCount(); ++in) { + assert(vertex_pool->has_vertex(in)); + for (size_t pa = 0; pa < controller->GetSkinController()->GetVertexInfluence(in)->GetPairCount(); ++pa) { + const FCDJointWeightPair* jwpair = controller->GetSkinController()->GetVertexInfluence(in)->GetPair(pa); + influences[jwpair->jointIndex].push_back(pair (vertex_pool->get_vertex(in), jwpair->weight)); + } + } + } + // Loop through the joints in the vertex influences + for (pmap > >::iterator it = influences.begin(); it != influences.end(); ++it) { + if (it->first == -1) { + daeegg_cat.warning() << "Ignoring vertex influence with negative joint index\n"; + //FIXME: Why are there joints with index -1 + } else { + const string joint_id = FROM_FSTRING(controller->GetSkinController()->GetJoint(it->first)->GetId()); + //TODO: what if the joints have just not been defined yet? + if (_joints.count(joint_id) > 0) { + if (_joints[joint_id]) { + for (pvector >::iterator vi = it->second.begin(); vi != it->second.end(); ++vi) { + _joints[joint_id]->ref_vertex(vi->first, vi->second); + } + } else { + daeegg_cat.warning() << "Unprocessed joint being referenced: '" << joint_id << "'" << endl; + } + } else { + daeegg_cat.warning() << "Unknown joint being referenced: '" << joint_id << "'" << endl; + } + } + } + } + if (controller->IsMorph()) { + assert(controller != NULL); + const FCDMorphController* morph_controller = controller->GetMorphController(); + assert(morph_controller != NULL); + PT(EggTable) bundle = new EggTable(parent->get_name()); + bundle->set_table_type(EggTable::TT_bundle); + PT(EggTable) morph = new EggTable("morph"); + morph->set_table_type(EggTable::TT_table); + bundle->add_child(morph); + // Loop through the morph targets. + for (size_t mt = 0; mt < morph_controller->GetTargetCount(); ++mt) { + const FCDMorphTarget* morph_target = morph_controller->GetTarget(mt); + assert(morph_target != NULL); + PT(EggSAnimData) target = new EggSAnimData(FROM_FSTRING(morph_target->GetGeometry()->GetDaeId())); + if (morph_target->IsAnimated()) { + //TODO + } else { + target->add_data(morph_target->GetWeight()); + } + morph->add_child(target); + } + } + + // Get a for the character and add it to the table + PT(DaeCharacter) character = new DaeCharacter(parent->get_name(), instance); + _table->add_child(character->as_egg_bundle()); +} + +LMatrix4d DAEToEggConverter::convert_matrix(const FMMatrix44& matrix) { + LMatrix4d result = LMatrix4d::zeros_mat(); + for (char x = 0; x < 4; ++x) { + for (char y = 0; y < 4; ++y) { + result(x, y) = matrix[x][y]; + } + } + return result; +} + +void DAEToEggConverter::apply_transform(const PT(EggGroup) to, const FCDTransform* from) { + assert(from != NULL); + assert(to != NULL); + switch (from->GetType()) { + case FCDTransform::TRANSLATION: + to->add_translate3d(TO_VEC3(((FCDTTranslation*) from)->GetTranslation())); + break; + case FCDTransform::ROTATION: + to->add_rotate3d(((FCDTRotation*) from)->GetAngle(), TO_VEC3(((FCDTRotation*) from)->GetAxis())); + break; + case FCDTransform::SCALE: + to->add_scale3d(TO_VEC3(((FCDTScale*) from)->GetScale())); + break; + case FCDTransform::MATRIX: + to->add_matrix4(convert_matrix(((FCDTMatrix*) from)->GetTransform())); + break; + default: + // We don't know this, so let FCollada convert it into a matrix + to->add_matrix4(convert_matrix(from->ToMatrix())); + } +} diff --git a/pandatool/src/daeegg/daeToEggConverter.h b/pandatool/src/daeegg/daeToEggConverter.h new file mode 100755 index 0000000000..108bdab6a7 --- /dev/null +++ b/pandatool/src/daeegg/daeToEggConverter.h @@ -0,0 +1,84 @@ +// Filename: daeToEggConverter.h +// Created by: pro-rsoft (08May08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#ifndef DAETOEGGCONVERTER_H +#define DAETOEGGCONVERTER_H + +#include "pandatoolbase.h" +#include "somethingToEggConverter.h" +#include "eggGroup.h" +#include "eggMaterial.h" +#include "eggTexture.h" +#include "eggTable.h" +#include "eggNurbsCurve.h" + +#include "pre_fcollada_include.h" +#include "FCollada.h" +#include "FCDocument/FCDocument.h" +#include "FCDocument/FCDTransform.h" +#include "FCDocument/FCDEntityInstance.h" +#include "FCDocument/FCDControllerInstance.h" +#include "FCDocument/FCDGeometryMesh.h" +#include "FCDocument/FCDGeometrySpline.h" +#include "FCDocument/FCDMaterial.h" +#include "FMath/FMMatrix44.h" + +#include "daeMaterials.h" +#include "pvector.h" // Include last + +//////////////////////////////////////////////////////////////////// +// Class : DAEToEggConverter +// Description : This class supervises the construction of an +// EggData structure from a DAE file. +//////////////////////////////////////////////////////////////////// +class DAEToEggConverter : public SomethingToEggConverter { +public: + DAEToEggConverter(); + DAEToEggConverter(const DAEToEggConverter ©); + ~DAEToEggConverter(); + + virtual SomethingToEggConverter *make_copy(); + + virtual string get_name() const; + virtual string get_extension() const; + + virtual bool convert_file(const Filename &filename); + +private: + + PT(EggTable) _table; + FCDocument* _document; + FUErrorSimpleHandler _error_handler; + pmap _joints; + pmap _vertex_pools; + pvector _skeletons; + int _frame_rate; + + void process_asset(); + void preprocess(const FCDSceneNode* node = NULL); + void process_node(PT(EggGroupNode) parent, const FCDSceneNode* node, bool forced = false); + void process_instance(PT(EggGroup) parent, const FCDEntityInstance* instance); + void process_mesh(PT(EggGroup) parent, const FCDGeometryMesh* mesh, PT(DaeMaterials) materials); + void process_spline(PT(EggGroup) parent, const string group_name, FCDGeometrySpline* geometry_spline); + void process_spline(PT(EggGroup) parent, const FCDSpline* spline); + void process_controller(PT(EggGroup) parent, const FCDControllerInstance* instance); + //void process_table_joint(PT(EggTable) parent, FCDSceneNode* node); + + static LMatrix4d convert_matrix(const FMMatrix44& matrix); + void apply_transform(const PT(EggGroup) to, const FCDTransform* from); + + friend class DaeCharacter; +}; + +#endif diff --git a/pandatool/src/daeegg/daeegg_composite1.cxx b/pandatool/src/daeegg/daeegg_composite1.cxx new file mode 100755 index 0000000000..be3f927d9c --- /dev/null +++ b/pandatool/src/daeegg/daeegg_composite1.cxx @@ -0,0 +1,5 @@ + +#include "config_daeegg.cxx" +#include "daeCharacter.cxx" +#include "daeMaterials.cxx" +#include "daeToEggConverter.cxx" diff --git a/pandatool/src/daeegg/pre_fcollada_include.h b/pandatool/src/daeegg/pre_fcollada_include.h new file mode 100755 index 0000000000..39efccfd08 --- /dev/null +++ b/pandatool/src/daeegg/pre_fcollada_include.h @@ -0,0 +1,26 @@ +// Filename: pre_fcollada_include.h +// Created by: pro-rsoft (04Oct08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +// This file defines some stuff that need to be defined before +// one includes FCollada.h + +// FCollada expects LINUX to be defined on linux +#ifdef IS_LINUX + #ifndef LINUX + #define LINUX + #endif +#endif + +#define NO_LIBXML +#define FCOLLADA_NOMINMAX diff --git a/pandatool/src/daeprogs/Sources.pp b/pandatool/src/daeprogs/Sources.pp new file mode 100755 index 0000000000..c3540ef122 --- /dev/null +++ b/pandatool/src/daeprogs/Sources.pp @@ -0,0 +1,25 @@ +#define BUILD_DIRECTORY $[HAVE_FCOLLADA] + +#define OTHER_LIBS \ + egg:c pandaegg:m \ + pipeline:c pnmimage:c putil:c event:c mathutil:c linmath:c panda:m \ + pandabase:c express:c pandaexpress:m \ + interrogatedb:c dtoolutil:c dtoolbase:c prc:c dconfig:c dtoolconfig:m dtool:m pystub + +#begin bin_target + #define TARGET dae2egg + #define LOCAL_LIBS daeegg eggbase progbase + + #define SOURCES \ + daeToEgg.cxx daeToEgg.h + +#end bin_target + +#begin bin_target + #define TARGET egg2dae + #define LOCAL_LIBS daeegg eggbase progbase + + #define SOURCES \ + eggToDAE.cxx eggToDAE.h + +#end bin_target diff --git a/pandatool/src/daeprogs/daeToEgg.cxx b/pandatool/src/daeprogs/daeToEgg.cxx new file mode 100755 index 0000000000..85ea25fbf1 --- /dev/null +++ b/pandatool/src/daeprogs/daeToEgg.cxx @@ -0,0 +1,74 @@ +// Filename: daeToEgg.cxx +// Created by: pro-rsoft (08May08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#include "daeToEgg.h" + +#include "daeToEggConverter.h" +#include "pystub.h" + +//////////////////////////////////////////////////////////////////// +// Function: DAEToEgg::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DAEToEgg:: +DAEToEgg(): + SomethingToEgg("COLLADA", ".dae") +{ + add_units_options(); + add_normals_options(); + add_transform_options(); + + set_program_description + ("This program converts .dae files (COLLADA Digital Asset Exchange) to .egg."); + + _coordinate_system = CS_yup_right; +} + +//////////////////////////////////////////////////////////////////// +// Function: DAEToEgg::run +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void DAEToEgg:: +run() { + nout << "Reading " << _input_filename << "\n"; + + _data->set_coordinate_system(_coordinate_system); + + DAEToEggConverter converter; + converter.set_egg_data(_data); + converter._allow_errors = _allow_errors; + + apply_parameters(converter); + + if (!converter.convert_file(_input_filename)) { + nout << "Errors in conversion.\n"; + exit(1); + } + + write_egg_file(); + nout << "\n"; +} + + +int main(int argc, char *argv[]) { + // A call to pystub() to force libpystub.so to be linked in. + pystub(); + + DAEToEgg prog; + prog.parse_command_line(argc, argv); + prog.run(); + return 0; +} diff --git a/pandatool/src/daeprogs/daeToEgg.h b/pandatool/src/daeprogs/daeToEgg.h new file mode 100755 index 0000000000..78c9d75704 --- /dev/null +++ b/pandatool/src/daeprogs/daeToEgg.h @@ -0,0 +1,35 @@ +// Filename: daeToEgg.h +// Created by: pro-rsoft (08May08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#ifndef DAETOEGG_H +#define DAETOEGG_H + +#include "pandatoolbase.h" + +#include "somethingToEgg.h" +#include "daeToEggConverter.h" + +//////////////////////////////////////////////////////////////////// +// Class : DAEToEgg +// Description : A program to read a DAE file and generate an egg +// file. +//////////////////////////////////////////////////////////////////// +class DAEToEgg : public SomethingToEgg { +public: + DAEToEgg(); + + void run(); +}; + +#endif diff --git a/pandatool/src/daeprogs/eggToDAE.cxx b/pandatool/src/daeprogs/eggToDAE.cxx new file mode 100755 index 0000000000..9742f426f7 --- /dev/null +++ b/pandatool/src/daeprogs/eggToDAE.cxx @@ -0,0 +1,182 @@ +// Filename: eggToDAE.cxx +// Created by: pro-rsoft (04Oct08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#include "eggToDAE.h" +#include "dcast.h" +#include "pystub.h" +#include "pandaVersion.h" + +#include "FCDocument/FCDocument.h" +#include "FCDocument/FCDAsset.h" +#include "FCDocument/FCDTransform.h" + +// Useful conversion stuff +#define TO_VEC3(v) (LVecBase3d(v[0], v[1], v[2])) +#define TO_VEC4(v) (LVecBase4d(v[0], v[1], v[2], v[3])) +#define TO_COLOR(v) (Colorf(v[0], v[1], v[2], v[3])) +#define FROM_VEC3(v) (FMVector3(v[0], v[1], v[2])) +#define FROM_VEC4(v) (FMVector4(v[0], v[1], v[2], v[3])) +#define FROM_MAT4(v) (FMMatrix44(v.get_data())) +#define FROM_FSTRING(fs) (fs.c_str()) + +//////////////////////////////////////////////////////////////////// +// Function: EggToDAE::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +EggToDAE:: +EggToDAE() : + EggToSomething("COLLADA", ".dae", true, false) +{ + set_binary_output(false); + set_program_description + ("This program converts files from the egg format to the COLLADA " + ".dae (Digital Asset Exchange) format."); + + _document = NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggToDAE::run +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void EggToDAE:: +run() { + nassertv(has_output_filename()); + nassertv(_data != NULL); + + FCollada::Initialize(); + _document = FCollada::NewTopDocument(); + + // Add the contributor part to the asset + FCDAssetContributor* contributor = _document->GetAsset()->AddContributor(); + const char* user_name = getenv("USER"); + if (user_name == NULL) user_name = getenv("USERNAME"); + if (user_name != NULL) contributor->SetAuthor(TO_FSTRING(user_name)); + //contributor->SetSourceData(); + char authoring_tool[1024]; + snprintf(authoring_tool, 1024, "Panda3D %s eggToDAE converter | FCollada v%d.%02d", PANDA_VERSION_STR, FCOLLADA_VERSION >> 16, FCOLLADA_VERSION & 0xFFFF); + authoring_tool[1023] = 0; + contributor->SetAuthoringTool(TO_FSTRING(authoring_tool)); + + // Set coordinate system + switch (_data->get_coordinate_system()) { + case CS_zup_right: + _document->GetAsset()->SetUpAxis(FMVector3::ZAxis); + break; + case CS_yup_right: + _document->GetAsset()->SetUpAxis(FMVector3::YAxis); + break; + } + + // Now actually start processing the data. + FCDSceneNode* visual_scene = _document->AddVisualScene(); + for (EggGroupNode::iterator it = _data->begin(); it != _data->end(); ++it) { + if ((*it)->is_of_type(EggGroup::get_class_type())) { + process_node(visual_scene, DCAST(EggGroup, *it)); + } + } + + // We're done here. + FCollada::SaveDocument(_document, get_output_filename().to_os_specific().c_str()); + SAFE_DELETE(_document); + FCollada::Release(); + + //if (!out) { + // nout << "An error occurred while writing.\n"; + // exit(1); + //} +} + +void EggToDAE::process_node(FCDSceneNode* parent, const PT(EggGroup) node) { + assert(node != NULL); + FCDSceneNode* scene_node = parent->AddChildNode(); + // Set the parameters + scene_node->SetDaeId(node->get_name().c_str()); + scene_node->SetJointFlag(node->is_joint()); + // Apply the transforms + apply_transform(scene_node, node); + // Recursively process sub-nodes + for (EggGroupNode::iterator it = node->begin(); it != node->end(); ++it) { + if ((*it)->is_of_type(EggGroup::get_class_type())) { + process_node(scene_node, DCAST(EggGroup, *it)); + } + } +} + +void EggToDAE::apply_transform(FCDSceneNode* to, const PT(EggGroup) from) { + assert(to != NULL); + assert(from != NULL); + for (int co = 0; co < from->get_num_components(); ++co) { + switch (from->get_component_type(co)) { + case EggTransform::CT_translate2d: + cerr << "Warning: ignoring non-supported 2d translation\n"; + break; + case EggTransform::CT_rotate2d: + cerr << "Warning: ignoring non-supported 2d rotation\n"; + break; + case EggTransform::CT_scale2d: + cerr << "Warning: ignoring non-supported 2d scaling\n"; + break; + case EggTransform::CT_matrix3: + cerr << "Warning: ignoring non-supported 2d matrix\n"; + break; + case EggTransform::CT_translate3d: { + FCDTTranslation* new_transform = (FCDTTranslation*) to->AddTransform(FCDTransform::TRANSLATION); + new_transform->SetTranslation(FROM_VEC3(from->get_component_vec3(co))); + break; } + case EggTransform::CT_rotate3d: { + FCDTRotation* new_transform = (FCDTRotation*) to->AddTransform(FCDTransform::ROTATION); + new_transform->SetRotation(FROM_VEC3(from->get_component_vec3(co)), from->get_component_number(co)); + break; } + case EggTransform::CT_scale3d: { + FCDTScale* new_transform = (FCDTScale*) to->AddTransform(FCDTransform::SCALE); + new_transform->SetScale(FROM_VEC3(from->get_component_vec3(co))); + break; } + case EggTransform::CT_matrix4: { + FCDTMatrix* new_transform = (FCDTMatrix*) to->AddTransform(FCDTransform::MATRIX); + new_transform->SetTransform(FROM_MAT4(from->get_component_mat4(co))); + break; } + case EggTransform::CT_rotx: { + FCDTRotation* new_transform = (FCDTRotation*) to->AddTransform(FCDTransform::ROTATION); + new_transform->SetRotation(FMVector3::XAxis, from->get_component_number(co)); + break; } + case EggTransform::CT_roty: { + FCDTRotation* new_transform = (FCDTRotation*) to->AddTransform(FCDTransform::ROTATION); + new_transform->SetRotation(FMVector3::YAxis, from->get_component_number(co)); + break; } + case EggTransform::CT_rotz: { + FCDTRotation* new_transform = (FCDTRotation*) to->AddTransform(FCDTransform::ROTATION); + new_transform->SetRotation(FMVector3::ZAxis, from->get_component_number(co)); + break; } + case EggTransform::CT_uniform_scale: { + FCDTScale* new_transform = (FCDTScale*) to->AddTransform(FCDTransform::SCALE); + new_transform->SetScale(from->get_component_number(co), from->get_component_number(co), from->get_component_number(co)); + break; } + default: + cerr << "Warning: ignoring invalid transform\n"; + } + } +} + +int main(int argc, char *argv[]) { + // A call to pystub() to force libpystub.so to be linked in. + pystub(); + + EggToDAE prog; + prog.parse_command_line(argc, argv); + prog.run(); + return 0; +} diff --git a/pandatool/src/daeprogs/eggToDAE.h b/pandatool/src/daeprogs/eggToDAE.h new file mode 100755 index 0000000000..f20dbf7d34 --- /dev/null +++ b/pandatool/src/daeprogs/eggToDAE.h @@ -0,0 +1,46 @@ +// Filename: eggToDAE.h +// Created by: pro-rsoft (04Oct08) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#ifndef EGGTODAE_H +#define EGGTODAE_H + +#include "pandatoolbase.h" +#include "eggToSomething.h" +#include "eggGroup.h" +#include "eggTransform.h" + +#include "pre_fcollada_include.h" +#include "FCollada.h" +#include "FCDocument/FCDSceneNode.h" + +//////////////////////////////////////////////////////////////////// +// Class : EggToDAE +// Description : A program to read an egg file and write a DAE file. +//////////////////////////////////////////////////////////////////// +class EggToDAE : public EggToSomething { +public: + EggToDAE(); + + void run(); + +private: + FCDocument* _document; + + void process_node(FCDSceneNode* parent, const PT(EggGroup) node); + void apply_transform(FCDSceneNode* to, const PT(EggGroup) from); + +}; + +#endif +