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

354 lines
14 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/FCDocument.h"
#include "FCDocument/FCDAnimated.h"
#include "FCDocument/FCDEffectParameter.h"
#include "FCDocument/FCDEffectParameterList.h"
#include "FCDocument/FCDImage.h"
#include "FCDocument/FCDTexture.h"
#include "FUtils/FUStringConversion.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDTexture::FCDTexture(FCDocument* document) : FCDEntity(document, "Texture")
{
textureChannel = FUDaeTextureChannel::DEFAULT;
image = NULL;
set = new FCDEffectParameterInt(document);
set->SetValue(-1);
multiplier = 1.0f;
blendMode = FUDaeBlendMode::DEFAULT;
ClearPlacement2D();
hasProjection3D = false;
hasPlacement2D = false;
}
FCDTexture::~FCDTexture()
{
image = NULL;
SAFE_DELETE(set);
}
void FCDTexture::ClearPlacement2D()
{
hasPlacement2D = false;
wrapU = wrapV = mirrorU = mirrorV = stagger = fast = 0.0f; // false
translateFrameU = translateFrameV = rotateFrame = 0.0f;
offsetU = offsetV = rotateUV = noiseU = noiseV = 0.0f;
coverageU = coverageV = repeatU = repeatV = 1.0f;
}
void FCDTexture::ClearProjection3D()
{
hasProjection3D = false;
projectionMatrix = FMMatrix44::Identity;
projectionType.clear();
}
// Look for the effect parameter with the correct semantic, in order to bind/set its value
FCDEffectParameter* FCDTexture::FindParameterBySemantic(const string& semantic)
{
if (set->GetSemantic() == semantic) return set;
else return NULL;
}
void FCDTexture::FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters)
{
if (set->GetSemantic() == semantic) parameters.push_back(set);
}
void FCDTexture::FindParametersByReference(const string& reference, FCDEffectParameterList& parameters)
{
if (set->GetReference() == reference) parameters.push_back(set);
}
// Returns a copy of the texture/sampler, with all the animations attached
FCDTexture* FCDTexture::Clone()
{
FCDTexture* clone = new FCDTexture(GetDocument());
FCDEntity::Clone(clone);
clone->textureChannel = textureChannel;
clone->image = image; // copy only the pointer.
SAFE_DELETE(clone->set);
clone->set = (FCDEffectParameterInt*) set->Clone();
clone->hasProjection3D = hasProjection3D;
clone->hasPlacement2D = hasPlacement2D;
clone->blendMode = blendMode;
clone->projectionMatrix = projectionMatrix;
# define CLONE_ANIMATED(flt) clone->flt = flt; FCDAnimatedFloat::Clone(GetDocument(), &flt, &clone->flt);
CLONE_ANIMATED(multiplier);
CLONE_ANIMATED(wrapU); CLONE_ANIMATED(wrapV);
CLONE_ANIMATED(mirrorU); CLONE_ANIMATED(mirrorV);
CLONE_ANIMATED(stagger); CLONE_ANIMATED(fast);
CLONE_ANIMATED(translateFrameU); CLONE_ANIMATED(translateFrameV);
CLONE_ANIMATED(offsetU); CLONE_ANIMATED(offsetV);
CLONE_ANIMATED(rotateUV);
CLONE_ANIMATED(noiseU); CLONE_ANIMATED(noiseV);
CLONE_ANIMATED(coverageU); CLONE_ANIMATED(coverageV);
CLONE_ANIMATED(repeatU); CLONE_ANIMATED(repeatV);
# undef CLONE_ANIMATED
return clone;
}
// Read in the texture element for a standard effect COLLADA texture
FUStatus FCDTexture::LoadFromTextureXML(xmlNode* textureNode)
{
FUStatus status;
// Verify that this is a sampler node
if (!IsEquivalent(textureNode->name, DAE_FXSTD_SAMPLER_ELEMENT))
{
return status.Fail(FS("Unknown texture sampler element."), textureNode->line);
}
// Read in the 'texture' attribute: points to an image
string imageId = ReadNodeProperty(textureNode, DAE_FXSTD_TEXTURE_ATTRIBUTE);
image = GetDocument()->FindImage(imageId);
if (image == NULL)
{
status.Warning(FS("Unable to find image source for sampler."), textureNode->line);
}
// Read in the 'texcoord' attribute: a texture coordinate set identifier
string semantic = ReadNodeProperty(textureNode, DAE_FXSTD_TEXTURESET_ATTRIBUTE);
if (!semantic.empty())
{
set->SetSemantic(semantic);
// [GLaforte 06-01-06] Also attempt to convert the value to a signed integer
// since that was done quite a bit in COLLADA 1.4 preview exporters.
set->SetValue(FUStringConversion::ToInt32(semantic));
}
// Look for/parse in the texture placement parameters
xmlNode* extraNode = FindChildByType(textureNode, DAE_EXTRA_ELEMENT);
xmlNode* mayaTechniqueNode = FindTechnique(extraNode, DAEMAYA_MAYA_PROFILE);
status.AppendStatus(LoadPlacementXML(mayaTechniqueNode));
xmlNode* maxTechniqueNode = FindTechnique(extraNode, DAEMAX_MAX_PROFILE);
status.AppendStatus(LoadPlacementXML(maxTechniqueNode));
return status;
}
// COLLADA 1.3 Backward compatibility: Read in a <texture> node from the COLLADA document
FUStatus FCDTexture::LoadFromXML(xmlNode* textureNode)
{
FUStatus status = FCDEntity::LoadFromXML(textureNode);
if (!status) return status;
if (!IsEquivalent(textureNode->name, DAE_TEXTURE_ELEMENT))
{
return status.Warning(FS("Texture library contains unknown element."), textureNode->line);
}
// Read the channel usage for this texture
xmlNode* usageParameterNode = FindChildByType(textureNode, DAE_PARAMETER_ELEMENT);
string channelUsage = ReadNodeName(usageParameterNode);
textureChannel = FUDaeTextureChannel::FromString(channelUsage);
if (textureChannel == FUDaeTextureChannel::UNKNOWN)
{
textureChannel = FUDaeTextureChannel::DEFAULT;
status.Warning(FS("Unknown channel usage for texture: ") + TO_FSTRING(GetDaeId()), textureNode->line);
}
// Retrieve the common technique and verify that the input node inside points to an image
xmlNode* commonTechniqueNode = FindTechnique(textureNode, DAE_COMMON_PROFILE);
xmlNode* imageInputNode = FindChildByType(commonTechniqueNode, DAE_INPUT_ELEMENT);
string inputSemantic = ReadNodeSemantic(imageInputNode);
if (inputSemantic != DAE_IMAGE_INPUT)
{
status.Warning(FS("Unknown input semantic for texture: ") + TO_FSTRING(GetDaeId()), imageInputNode->line);
}
else
{
// Link to the image input
string imageId = ReadNodeSource(imageInputNode);
if (imageId.empty() || imageId[0] != '#')
{
status.Warning(FS("Unknown or external image source for texture: ") + TO_FSTRING(GetDaeId()), imageInputNode->line);
}
else
{
image = GetDocument()->FindImage(imageId);
if (image == NULL)
{
status.Warning(FS("Unable to find image source: ") + TO_FSTRING(imageId), imageInputNode->line);
}
}
}
// Read in the Maya-specific texture placement parameters
// and look for a texture program
xmlNode* mayaTechniqueNode = FindTechnique(textureNode, DAEMAYA_MAYA_PROFILE);
status.AppendStatus(LoadPlacementXML(mayaTechniqueNode));
return status;
}
// Read in the Maya-specific texture placement parameters and look for a texture program
FUStatus FCDTexture::LoadPlacementXML(xmlNode* techniqueNode)
{
// This function loads extra functionality, so it should NEVER fail.
// It can throw all the warnings it wants, though!
FUStatus status;
if (techniqueNode == NULL) return status;
// Look for some placement 2D parameters
StringList parameterNames;
xmlNodeList parameterNodes;
FindParameters(techniqueNode, parameterNames, parameterNodes);
size_t parameterCount = parameterNames.size();
for (size_t i = 0; i < parameterCount; ++i)
{
const string& parameterName = parameterNames[i];
xmlNode* parameterNode = parameterNodes[i];
const char* content = ReadNodeContentDirect(parameterNode);
if (content == NULL || *content == 0 || parameterName.empty()) continue;
#define CHECKBOOLPARAM(memberName, paramName2) \
if (parameterName == paramName2) { \
memberName = (float) FUStringConversion::ToBoolean(content); \
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &memberName); \
hasPlacement2D = true; } else
#define CHECKFLOATPARAM(memberName, paramName2) \
if (parameterName == paramName2) { \
memberName = FUStringConversion::ToFloat(content); \
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &memberName); \
hasPlacement2D = true; } else
CHECKBOOLPARAM(wrapU, DAEMAYA_TEXTURE_WRAPU_PARAMETER)
CHECKBOOLPARAM(wrapV, DAEMAYA_TEXTURE_WRAPV_PARAMETER)
CHECKBOOLPARAM(mirrorU, DAEMAYA_TEXTURE_MIRRORU_PARAMETER)
CHECKBOOLPARAM(mirrorV, DAEMAYA_TEXTURE_MIRRORV_PARAMETER)
CHECKFLOATPARAM(coverageU, DAEMAYA_TEXTURE_COVERAGEU_PARAMETER)
CHECKFLOATPARAM(coverageV, DAEMAYA_TEXTURE_COVERAGEV_PARAMETER)
CHECKFLOATPARAM(translateFrameU, DAEMAYA_TEXTURE_TRANSFRAMEU_PARAMETER)
CHECKFLOATPARAM(translateFrameV, DAEMAYA_TEXTURE_TRANSFRAMEV_PARAMETER)
CHECKFLOATPARAM(rotateFrame, DAEMAYA_TEXTURE_ROTFRAME_PARAMETER)
CHECKBOOLPARAM(stagger, DAEMAYA_TEXTURE_STAGGER_PARAMETER)
CHECKBOOLPARAM(fast, DAEMAYA_TEXTURE_FAST_PARAMETER)
CHECKFLOATPARAM(repeatU, DAEMAYA_TEXTURE_REPEATU_PARAMETER)
CHECKFLOATPARAM(repeatV, DAEMAYA_TEXTURE_REPEATV_PARAMETER)
CHECKFLOATPARAM(offsetU, DAEMAYA_TEXTURE_OFFSETU_PARAMETER)
CHECKFLOATPARAM(offsetV, DAEMAYA_TEXTURE_OFFSETV_PARAMETER)
CHECKFLOATPARAM(rotateUV, DAEMAYA_TEXTURE_ROTATEUV_PARAMETER)
CHECKFLOATPARAM(noiseU, DAEMAYA_TEXTURE_NOISEU_PARAMETER)
CHECKFLOATPARAM(noiseV, DAEMAYA_TEXTURE_NOISEV_PARAMETER)
CHECKFLOATPARAM(multiplier, DAEMAX_AMOUNT_TEXTURE_PARAMETER)
#undef CHECKFLOATPARAM
#undef CHECKBOOLPARAM
if (parameterName == DAEMAYA_TEXTURE_BLENDMODE_PARAMETER || parameterName == DAEMAYA_TEXTURE_BLENDMODE_PARAMETER1_3)
{
blendMode = FUDaeBlendMode::FromString(content);
}
else
{
status.Warning(FS("Unknown texture parameter: ") + TO_FSTRING(parameterName) + FS(" in texture: ") + TO_FSTRING(GetDaeId()), parameterNode->line);
}
}
xmlNode* mayaProjectionNode = FindChildByType(techniqueNode, DAEMAYA_PROJECTION_ELEMENT);
// COLLADA 1.3 backward compatibility: check for a <program URL="PROJECTION">, also.
if (mayaProjectionNode == NULL) mayaProjectionNode = FindChildByType(techniqueNode, DAE_PROGRAM_ELEMENT);
if (mayaProjectionNode != NULL)
{
xmlNodeList parameters;
FindChildrenByType(mayaProjectionNode, DAE_PARAMETER_ELEMENT, parameters);
for (xmlNodeList::iterator itP = parameters.begin(); itP != parameters.end(); ++itP)
{
xmlNode* param = *itP;
string paramName = ReadNodeName(param);
const char* content = ReadNodeContentDirect(param);
if (paramName == DAEMAYA_PROJECTION_TYPE_PARAMETER || paramName == DAEMAYA_PROJECTION_TYPE_PARAMETER1_3)
{
projectionType = TO_FSTRING(content);
}
else if (paramName == DAEMAYA_PROJECTION_MATRIX_PARAMETER || paramName == DAEMAYA_PROJECTION_MATRIX_PARAMETER1_3)
{
FUStringConversion::ToMatrix(&content, projectionMatrix, GetDocument()->GetLengthUnitConversion());
}
else
{
status.Warning(FS("Unknown projection program parameter: '") + TO_FSTRING(paramName) + FS("' in texture : ") + TO_FSTRING(GetDaeId()), param->line);
}
}
hasProjection3D = true;
}
return status;
}
// Write out the texture to the COLLADA xml node tree
xmlNode* FCDTexture::WriteToXML(xmlNode* parentNode)
{
// Create the <texture> element
xmlNode* textureNode = AddChild(parentNode, DAE_TEXTURE_ELEMENT);
AddAttribute(textureNode, DAE_FXSTD_TEXTURE_ATTRIBUTE, image != NULL ? image->GetDaeId() : "");
AddAttribute(textureNode, DAE_FXSTD_TEXTURESET_ATTRIBUTE, set->GetValue());
if (hasPlacement2D || hasProjection3D)
{
// Create the <extra> element with the texture placement parameters and their animations
xmlNode* techniqueNode = AddExtraTechniqueChild(textureNode, DAEMAYA_MAYA_PROFILE);
if (hasPlacement2D)
{
#define ADD_PARAM_BOOL(memberName, paramName) { xmlNode* x = AddChild(techniqueNode, paramName, !IsEquivalent(memberName, 0.0f)); GetDocument()->WriteAnimatedValueToXML(&memberName, x, paramName); }
#define ADD_PARAM_FLOAT(memberName, paramName) { xmlNode* x = AddChild(techniqueNode, paramName, memberName); GetDocument()->WriteAnimatedValueToXML(&memberName, x, paramName); }
ADD_PARAM_BOOL(wrapU, DAEMAYA_TEXTURE_WRAPU_PARAMETER)
ADD_PARAM_BOOL(wrapV, DAEMAYA_TEXTURE_WRAPV_PARAMETER)
ADD_PARAM_BOOL(mirrorU, DAEMAYA_TEXTURE_MIRRORU_PARAMETER)
ADD_PARAM_BOOL(mirrorV, DAEMAYA_TEXTURE_MIRRORV_PARAMETER)
ADD_PARAM_FLOAT(coverageU, DAEMAYA_TEXTURE_COVERAGEU_PARAMETER)
ADD_PARAM_FLOAT(coverageV, DAEMAYA_TEXTURE_COVERAGEV_PARAMETER)
ADD_PARAM_FLOAT(translateFrameU, DAEMAYA_TEXTURE_TRANSFRAMEU_PARAMETER)
ADD_PARAM_FLOAT(translateFrameV, DAEMAYA_TEXTURE_TRANSFRAMEV_PARAMETER)
ADD_PARAM_FLOAT(rotateFrame, DAEMAYA_TEXTURE_ROTFRAME_PARAMETER)
ADD_PARAM_BOOL(stagger, DAEMAYA_TEXTURE_STAGGER_PARAMETER)
ADD_PARAM_BOOL(fast, DAEMAYA_TEXTURE_FAST_PARAMETER)
ADD_PARAM_FLOAT(repeatU, DAEMAYA_TEXTURE_REPEATU_PARAMETER)
ADD_PARAM_FLOAT(repeatV, DAEMAYA_TEXTURE_REPEATV_PARAMETER)
ADD_PARAM_FLOAT(offsetU, DAEMAYA_TEXTURE_OFFSETU_PARAMETER)
ADD_PARAM_FLOAT(offsetV, DAEMAYA_TEXTURE_OFFSETV_PARAMETER)
ADD_PARAM_FLOAT(rotateUV, DAEMAYA_TEXTURE_ROTATEUV_PARAMETER)
ADD_PARAM_FLOAT(noiseU, DAEMAYA_TEXTURE_NOISEU_PARAMETER)
ADD_PARAM_FLOAT(noiseV, DAEMAYA_TEXTURE_NOISEV_PARAMETER)
ADD_PARAM_FLOAT(multiplier, DAEMAX_AMOUNT_TEXTURE_PARAMETER)
#undef ADD_PARAM_BOOL
#undef ADD_PARAM_FLOAT
string blendModeValue = FUDaeBlendMode::ToString(blendMode);
AddChild(techniqueNode, DAEMAYA_TEXTURE_BLENDMODE_PARAMETER, blendModeValue);
}
if (hasProjection3D)
{
xmlNode* projectionNode = AddChild(techniqueNode, DAEMAYA_PROJECTION_ELEMENT);
AddChild(projectionNode, DAEMAYA_PROJECTION_TYPE_PARAMETER, projectionType);
AddChild(projectionNode, DAEMAYA_PROJECTION_MATRIX_PARAMETER, FUStringConversion::ToString(projectionMatrix, GetDocument()->GetLengthUnitConversion()));
}
}
return textureNode;
}