diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index 8f221de4c..e16de713f 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -136,6 +136,8 @@ public: std::for_each(meshes.begin(),meshes.end(),Util::delete_fun()); std::for_each(materials.begin(),materials.end(),Util::delete_fun()); std::for_each(animations.begin(),animations.end(),Util::delete_fun()); + std::for_each(lights.begin(),lights.end(),Util::delete_fun()); + std::for_each(cameras.begin(),cameras.end(),Util::delete_fun()); } @@ -234,6 +236,9 @@ private: // attach sub-nodes ConvertNodes(model->ID(), *nodes_chain.back(), new_abs_transform); + ConvertLights(*model); + ConvertCameras(*model); + nodes.push_back(nodes_chain.front()); nodes_chain.clear(); } @@ -254,6 +259,117 @@ private: } + // ------------------------------------------------------------------------------------------------ + void ConvertLights(const Model& model) + { + const std::vector& node_attrs = model.GetAttributes(); + BOOST_FOREACH(const NodeAttribute* attr, node_attrs) { + const Light* const light = dynamic_cast(attr); + if(light) { + ConvertLight(model, *light); + } + } + } + + + // ------------------------------------------------------------------------------------------------ + void ConvertCameras(const Model& model) + { + const std::vector& node_attrs = model.GetAttributes(); + BOOST_FOREACH(const NodeAttribute* attr, node_attrs) { + const Camera* const cam = dynamic_cast(attr); + if(cam) { + ConvertCamera(model, *cam); + } + } + } + + + // ------------------------------------------------------------------------------------------------ + void ConvertLight(const Model& model, const Light& light) + { + lights.push_back(new aiLight()); + aiLight* const out_light = lights.back(); + + out_light->mName.Set(FixNodeName(model.Name())); + + const float intensity = light.Intensity(); + const aiVector3D& col = light.Color(); + + out_light->mColorDiffuse = aiColor3D(col.x,col.y,col.z); + out_light->mColorDiffuse.r *= intensity; + out_light->mColorDiffuse.g *= intensity; + out_light->mColorDiffuse.b *= intensity; + + out_light->mColorSpecular = out_light->mColorDiffuse; + + switch(light.LightType()) + { + case Light::Type_Point: + out_light->mType = aiLightSource_POINT; + break; + + case Light::Type_Directional: + out_light->mType = aiLightSource_DIRECTIONAL; + break; + + case Light::Type_Spot: + out_light->mType = aiLightSource_SPOT; + out_light->mAngleOuterCone = AI_DEG_TO_RAD(light.OuterAngle()); + out_light->mAngleInnerCone = AI_DEG_TO_RAD(light.InnerAngle()); + break; + + case Light::Type_Area: + FBXImporter::LogWarn("cannot represent area light, set to UNDEFINED"); + out_light->mType = aiLightSource_UNDEFINED; + break; + + case Light::Type_Volume: + FBXImporter::LogWarn("cannot represent volume light, set to UNDEFINED"); + out_light->mType = aiLightSource_UNDEFINED; + break; + default: + ai_assert(false); + } + + // XXX: how to best convert the near and far decay ranges? + switch(light.DecayType()) + { + case Light::Decay_None: + out_light->mAttenuationConstant = 1.0f; + break; + case Light::Decay_Linear: + out_light->mAttenuationLinear = 1.0f; + break; + case Light::Decay_Quadratic: + out_light->mAttenuationQuadratic = 1.0f; + break; + case Light::Decay_Cubic: + FBXImporter::LogWarn("cannot represent cubic attenuation, set to Quadratic"); + out_light->mAttenuationQuadratic = 1.0f; + break; + default: + ai_assert(false); + } + } + + + // ------------------------------------------------------------------------------------------------ + void ConvertCamera(const Model& model, const Camera& cam) + { + cameras.push_back(new aiCamera()); + aiCamera* const out_camera = cameras.back(); + + out_camera->mName.Set(FixNodeName(model.Name())); + + out_camera->mAspect = cam.AspectWidth(); + out_camera->mPosition = cam.Position(); + out_camera->mLookAt = cam.InterestPosition() - out_camera->mPosition; + + out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); + } + + // ------------------------------------------------------------------------------------------------ // this returns unified names usable within assimp identifiers (i.e. no space characters - // while these would be allowed, they are a potential trouble spot so better not use them). @@ -2207,6 +2323,20 @@ private: std::swap_ranges(animations.begin(),animations.end(),out->mAnimations); } + + if(lights.size()) { + out->mLights = new aiLight*[lights.size()](); + out->mNumLights = static_cast(lights.size()); + + std::swap_ranges(lights.begin(),lights.end(),out->mLights); + } + + if(cameras.size()) { + out->mCameras = new aiCamera*[cameras.size()](); + out->mNumCameras = static_cast(cameras.size()); + + std::swap_ranges(cameras.begin(),cameras.end(),out->mCameras); + } } @@ -2218,6 +2348,8 @@ private: std::vector meshes; std::vector materials; std::vector animations; + std::vector lights; + std::vector cameras; typedef std::map MaterialMap; MaterialMap materials_converted; diff --git a/code/FBXDocument.h b/code/FBXDocument.h index 32e86be67..4d717b62f 100644 --- a/code/FBXDocument.h +++ b/code/FBXDocument.h @@ -216,9 +216,21 @@ private: #define fbx_simple_property(name, type, default_value) \ type name() const { \ - return PropertyGet(Props(), fbx_stringize(name), (default_value)); \ + return PropertyGet(Props(), fbx_stringize(name), (default_value)); \ } +// XXX improve logging +#define fbx_simple_enum_property(name, type, default_value) \ + type name() const { \ + const int ival = PropertyGet(Props(), fbx_stringize(name), static_cast(default_value)); \ + if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \ + ai_assert(static_cast(default_value) >= 0 && static_cast(default_value) < AI_CONCAT(type, _MAX)); \ + return static_cast(default_value); \ + } \ + return static_cast(ival); \ +} + + /** DOM base class for FBX cameras attached to a node */ class Camera : public NodeAttribute @@ -257,10 +269,63 @@ public: Light(uint64_t id, const Element& element, const Document& doc, const std::string& name); ~Light(); +public: + + enum Type + { + Type_Point, + Type_Directional, + Type_Spot, + Type_Area, + Type_Volume, + + Type_MAX // end-of-enum sentinel + }; + + enum Decay + { + Decay_None, + Decay_Linear, + Decay_Quadratic, + Decay_Cubic, + + Decay_MAX // end-of-enum sentinel + }; + public: fbx_simple_property(Color, aiVector3D, aiVector3D(1,1,1)); + fbx_simple_enum_property(LightType, Type, 0); + fbx_simple_property(CastLightOnObject, bool, false); + fbx_simple_property(DrawVolumetricLight, bool, true); + fbx_simple_property(DrawGroundProjection, bool, true); + fbx_simple_property(DrawFrontFacingVolumetricLight, bool, false); fbx_simple_property(Intensity, float, 1.0f); + fbx_simple_property(InnerAngle, float, 0.0f); + fbx_simple_property(OuterAngle, float, 45.0f); + fbx_simple_property(Fog, int, 50); + fbx_simple_enum_property(DecayType, Decay, 0); + fbx_simple_property(DecayStart, int, 0); + fbx_simple_property(FileName, std::string, ""); + + fbx_simple_property(EnableNearAttenuation, bool, false); + fbx_simple_property(NearAttenuationStart, float, 0.0f); + fbx_simple_property(NearAttenuationEnd, float, 0.0f); + fbx_simple_property(EnableFarAttenuation, bool, false); + fbx_simple_property(FarAttenuationStart, float, 0.0f); + fbx_simple_property(FarAttenuationEnd, float, 0.0f); + + fbx_simple_property(CastShadows, bool, true); + fbx_simple_property(ShadowColor, aiVector3D, aiVector3D(0,0,0)); + + fbx_simple_property(AreaLightShape, int, 0); + + fbx_simple_property(LeftBarnDoor, float, 20.0f); + fbx_simple_property(RightBarnDoor, float, 20.0f); + fbx_simple_property(TopBarnDoor, float, 20.0f); + fbx_simple_property(BottomBarnDoor, float, 20.0f); + fbx_simple_property(EnableBarnDoor, bool, true); + private: }; diff --git a/code/FBXModel.cpp b/code/FBXModel.cpp index 196e44a53..9e2d1eb77 100644 --- a/code/FBXModel.cpp +++ b/code/FBXModel.cpp @@ -92,7 +92,7 @@ void Model::ResolveLinks(const Element& element, const Document& doc) const char* const arr[] = {"Geometry","Material","NodeAttribute"}; // resolve material - const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID(),arr, 2); + const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID(),arr, 3); materials.reserve(conns.size()); geometry.reserve(conns.size());