Files
bullet3/Extras/FCollada/FCDocument/FCDCamera.cpp
2006-05-25 19:18:29 +00:00

269 lines
11 KiB
C++

/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
/*
Based on the FS Import classes:
Copyright (C) 2005-2006 Feeling Software Inc
Copyright (C) 2005-2006 Autodesk Media Entertainment
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDCamera.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDAnimated.h"
#include "FCDocument/FCDSceneNode.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDCamera::FCDCamera(FCDocument* document) : FCDTargetedEntity(document, "Camera")
{
isPerspective = true;
isOrthographic = false;
viewY = viewX = 60.0f;
hasAperture = hasHorizontalView = hasVerticalView = false;
nearZ = 1.0f;
farZ = 1000.0f;
aspectRatio = 1.0f;
horizontalAperture = verticalAperture = lensSqueeze = 1.0f;
}
FCDCamera::~FCDCamera()
{
}
void FCDCamera::SetFovX(float _viewX)
{
viewX = _viewX;
if (hasVerticalView && !IsEquivalent(viewX, 0.0f)) aspectRatio = viewY / viewX;
hasHorizontalView = true;
}
void FCDCamera::SetFovY(float _viewY)
{
viewY = _viewY;
if (hasHorizontalView && !IsEquivalent(viewX, 0.0f)) aspectRatio = viewY / viewX;
hasVerticalView = true;
}
void FCDCamera::SetAspectRatio(float _aspectRatio)
{
aspectRatio = _aspectRatio;
}
// Load this camera from the given COLLADA document's node
FUStatus FCDCamera::LoadFromXML(xmlNode* cameraNode)
{
FUStatus status = FCDEntity::LoadFromXML(cameraNode);
if (!status) return status;
if (!IsEquivalent(cameraNode->name, DAE_CAMERA_ELEMENT))
{
return status.Warning(FS("Camera library contains unknown element."), cameraNode->line);
}
// COLLADA 1.3: Grab the techniques and their <optics><program> children
xmlNode* commonTechniqueNode1_3 = FindTechnique(cameraNode, DAE_COMMON_PROFILE);
xmlNode* commonOpticsNode1_3 = FindChildByType(commonTechniqueNode1_3, DAE_OPTICS_ELEMENT);
xmlNode* commonProgramNode1_3 = FindChildByType(commonOpticsNode1_3, DAE_PROGRAM_ELEMENT);
xmlNode* maxTechniqueNode1_3 = FindTechnique(cameraNode, DAEMAX_MAX_PROFILE);
xmlNode* maxOpticsNode1_3 = FindChildByType(maxTechniqueNode1_3, DAE_OPTICS_ELEMENT);
xmlNode* maxProgramNode1_3 = FindChildByType(maxOpticsNode1_3, DAE_PROGRAM_ELEMENT);
xmlNode* mayaTechniqueNode = FindTechnique(cameraNode, DAEMAYA_MAYA_PROFILE);
xmlNode* mayaOpticsNode = FindChildByType(mayaTechniqueNode, DAE_OPTICS_ELEMENT);
xmlNode* mayaProgramNode = FindChildByType(mayaOpticsNode, DAE_PROGRAM_ELEMENT);
bool isCollada1_3 = commonTechniqueNode1_3 != NULL;
// COLLADA 1.4: Grab the <optics> element's techniques
xmlNode* opticsNode = FindChildByType(cameraNode, DAE_OPTICS_ELEMENT);
xmlNode* commonTechniqueNode = FindChildByType(opticsNode, DAE_TECHNIQUE_COMMON_ELEMENT);
xmlNode* maxTechniqueNode = FindTechnique(opticsNode, DAEMAX_MAX_PROFILE);
xmlNode* cameraContainerNode = (isCollada1_3) ? ((maxProgramNode1_3 != NULL) ? maxProgramNode1_3 : commonProgramNode1_3) : NULL;
if (mayaProgramNode == NULL) mayaProgramNode = FindTechnique(opticsNode, DAEMAYA_MAYA_PROFILE);
// Figure out the camera type
if (isCollada1_3)
{
FUUri programType = ReadNodeUrl(maxProgramNode1_3);
if (programType.prefix.empty()) programType = ReadNodeUrl(commonProgramNode1_3);
if (programType.prefix.empty())
{
return status.Fail(FS("No standard program type for camera: ") + TO_FSTRING(GetDaeId()), cameraNode->line);
}
string cameraType = TO_STRING(programType.prefix);
isOrthographic = cameraType == DAE_ORTHOGRAPHIC_CAMERA_TYPE;
isPerspective = cameraType == DAE_PERSPECTIVE_CAMERA_TYPE;
}
else
{
// Retrieve the <perspective> or <orthographic> element
cameraContainerNode = FindChildByType(commonTechniqueNode, DAE_CAMERA_ORTHO_ELEMENT);
isOrthographic = cameraContainerNode != NULL;
if (!isOrthographic)
{
cameraContainerNode = FindChildByType(commonTechniqueNode, DAE_CAMERA_PERSP_ELEMENT);
isPerspective = cameraContainerNode != NULL;
}
else
{
isPerspective = false;
}
}
// Check the necessary camera structures
if (cameraContainerNode == NULL)
{
return status.Fail(FS("Cannot find parameter root node for camera: ") + TO_FSTRING(GetDaeId()), cameraNode->line);
}
if (!(isPerspective ^ isOrthographic))
{
return status.Fail(FS("Unknown program type for camera: ") + TO_FSTRING(GetDaeId()), cameraContainerNode->line);
}
// Setup the camera according to the type and its parameters
// Retrieve all the camera parameters
StringList parameterNames;
xmlNodeList parameterNodes;
FindParameters(cameraContainerNode, parameterNames, parameterNodes);
FindParameters(maxTechniqueNode, parameterNames, parameterNodes);
FindParameters(mayaProgramNode, parameterNames, parameterNodes);
#define CAM_PARAMETER(colladaParam, memberFunction, animatedMember) \
if (parameterName == colladaParam) { \
memberFunction(FUStringConversion::ToFloat(parameterValue)); \
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &animatedMember); } else
size_t parameterCount = parameterNodes.size();
for (size_t i = 0; i < parameterCount; ++i)
{
xmlNode* parameterNode = parameterNodes[i];
const string& parameterName = parameterNames[i];
const char* parameterValue = ReadNodeContentDirect(parameterNode);
// Process the camera parameters
CAM_PARAMETER(DAE_ZNEAR_CAMERA_PARAMETER, SetNearZ, nearZ)
CAM_PARAMETER(DAE_ZFAR_CAMERA_PARAMETER, SetFarZ, farZ)
CAM_PARAMETER(DAE_XFOV_CAMERA_PARAMETER, SetFovX, viewX)
CAM_PARAMETER(DAE_YFOV_CAMERA_PARAMETER, SetFovY, viewY)
CAM_PARAMETER(DAE_XMAG_CAMERA_PARAMETER, SetMagX, viewX)
CAM_PARAMETER(DAE_YMAG_CAMERA_PARAMETER, SetMagY, viewY)
CAM_PARAMETER(DAE_ASPECT_CAMERA_PARAMETER, SetAspectRatio, aspectRatio)
CAM_PARAMETER(DAEMAYA_VAPERTURE_PARAMETER, SetVerticalAperture, verticalAperture)
CAM_PARAMETER(DAEMAYA_HAPERTURE_PARAMETER, SetHorizontalAperture, horizontalAperture)
CAM_PARAMETER(DAEMAYA_LENSSQUEEZE_PARAMETER, SetLensSqueeze, lensSqueeze)
if (parameterName == DAEMAX_TARGET_CAMERA_PARAMETER)
SetTargetId(parameterValue);
else
// COLLADA 1.3 backward compatibility
CAM_PARAMETER(DAE_ZNEAR_CAMERA_PARAMETER1_3, SetNearZ, nearZ)
CAM_PARAMETER(DAE_ZFAR_CAMERA_PARAMETER1_3, SetFarZ, farZ)
CAM_PARAMETER(DAE_XFOV_CAMERA_PARAMETER1_3, SetFovX, viewX)
CAM_PARAMETER(DAE_YFOV_CAMERA_PARAMETER1_3, SetFovY, viewY)
CAM_PARAMETER(DAE_RIGHT_CAMERA_PARAMETER1_3, SetMagX, viewX)
CAM_PARAMETER(DAE_TOP_CAMERA_PARAMETER1_3, SetMagY, viewY)
CAM_PARAMETER(DAEMAYA_VAPERTURE_PARAMETER1_3, SetVerticalAperture, verticalAperture)
CAM_PARAMETER(DAEMAYA_HAPERTURE_PARAMETER1_3, SetHorizontalAperture, horizontalAperture)
CAM_PARAMETER(DAEMAYA_LENSSQUEEZE_PARAMETER1_3, SetLensSqueeze, lensSqueeze)
if (parameterName == DAE_LEFT_CAMERA_PARAMETER1_3) {} // Don't process
else if (parameterName == DAE_BOTTOM_CAMERA_PARAMETER1_3) {} // Don't process
// Max-specific parameter: target
else if (parameterName == DAEMAX_TARGET_CAMERA_PARAMETER
|| parameterName == DAEMAX_TARGET_CAMERA_PARAMETER1_3)
{
SetTargetId(parameterValue);
}
else
{
status.Warning(FS("Unknown parameter for camera: ") + TO_FSTRING(GetDaeId()), parameterNode->line);
}
}
return status;
}
// Write out this camera to the COLLADA XML document
xmlNode* FCDCamera::WriteToXML(xmlNode* parentNode) const
{
// Create the base camera node
xmlNode* cameraNode = WriteToEntityXML(parentNode, DAE_CAMERA_ELEMENT);
xmlNode* opticsNode = AddChild(cameraNode, DAE_OPTICS_ELEMENT);
xmlNode* baseNode = AddChild(opticsNode, DAE_TECHNIQUE_COMMON_ELEMENT);
const char* baseNodeName;
if (isPerspective) baseNodeName = DAE_CAMERA_PERSP_ELEMENT;
else if (isOrthographic) baseNodeName = DAE_CAMERA_ORTHO_ELEMENT;
else baseNodeName = DAEERR_UNKNOWN_ELEMENT;
baseNode = AddChild(baseNode, baseNodeName);
// Write out the basic camera parameters
if (isPerspective)
{
if (hasHorizontalView)
{
xmlNode* viewNode = AddChild(baseNode, DAE_XFOV_CAMERA_PARAMETER, viewX);
GetDocument()->WriteAnimatedValueToXML(&viewX, viewNode, "horizontal_fov");
}
if (!hasHorizontalView || hasVerticalView)
{
xmlNode* viewNode = AddChild(baseNode, DAE_YFOV_CAMERA_PARAMETER, viewY);
GetDocument()->WriteAnimatedValueToXML(&viewY, viewNode, "vertical_fov");
}
if (!hasHorizontalView || !hasVerticalView)
{
xmlNode* aspectNode = AddChild(baseNode, DAE_ASPECT_CAMERA_PARAMETER, aspectRatio);
GetDocument()->WriteAnimatedValueToXML(&aspectRatio, aspectNode, "aspect_ratio");
}
}
if (isOrthographic)
{
if (hasHorizontalView)
{
xmlNode* viewNode = AddChild(baseNode, DAE_XMAG_CAMERA_PARAMETER, viewX);
GetDocument()->WriteAnimatedValueToXML(&viewX, viewNode, "horizontal_zoom");
}
if (!hasHorizontalView || hasVerticalView)
{
xmlNode* viewNode = AddChild(baseNode, DAE_YMAG_CAMERA_PARAMETER, viewY);
GetDocument()->WriteAnimatedValueToXML(&viewY, viewNode, "vertical_zoom");
}
if (!hasHorizontalView || !hasVerticalView)
{
xmlNode* aspectNode = AddChild(baseNode, DAE_ASPECT_CAMERA_PARAMETER, aspectRatio);
GetDocument()->WriteAnimatedValueToXML(&aspectRatio, aspectNode, "aspect_ratio");
}
}
// Near/Far clip plane distance
xmlNode* clipNode = AddChild(baseNode, DAE_ZNEAR_CAMERA_PARAMETER, nearZ);
GetDocument()->WriteAnimatedValueToXML(&nearZ, clipNode, "near_clip");
clipNode = AddChild(baseNode, DAE_ZFAR_CAMERA_PARAMETER, farZ);
GetDocument()->WriteAnimatedValueToXML(&farZ, clipNode, "near_clip");
// Add the application-specific technique/parameters
// Maya has extra aperture information
if (hasAperture)
{
xmlNode* techniqueMayaNode = AddTechniqueChild(opticsNode, DAEMAYA_MAYA_PROFILE);
xmlNode* apertureNode = AddChild(techniqueMayaNode, DAEMAYA_VAPERTURE_PARAMETER, verticalAperture);
GetDocument()->WriteAnimatedValueToXML(&verticalAperture, apertureNode, "vertical_aperture");
apertureNode = AddChild(techniqueMayaNode, DAEMAYA_HAPERTURE_PARAMETER, horizontalAperture);
GetDocument()->WriteAnimatedValueToXML(&horizontalAperture, apertureNode, "horizontal_aperture");
apertureNode = AddChild(techniqueMayaNode, DAEMAYA_LENSSQUEEZE_PARAMETER, lensSqueeze);
GetDocument()->WriteAnimatedValueToXML(&lensSqueeze, apertureNode, "lens_squeeze");
}
// Max has target information
if (GetTargetNode() != NULL)
{
xmlNode* techniqueMaxNode = AddTechniqueChild(opticsNode, DAEMAX_MAX_PROFILE);
AddChild(techniqueMaxNode, DAEMAX_TARGET_CAMERA_PARAMETER, GetTargetNode()->GetDaeId());
}
FCDEntity::WriteToExtraXML(cameraNode);
return cameraNode;
}