1
0
forked from 0ad/0ad
0ad/source/collada/CommonConvert.h

181 lines
5.4 KiB
C++

/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_COMMONCONVERT
#define INCLUDED_COMMONCONVERT
#include <exception>
#include <string>
#include <memory>
#include <vector>
class FCDEntityInstance;
class FCDSceneNode;
class FCDSkinController;
class FMMatrix44;
class Skeleton;
class ColladaException : public std::exception
{
public:
ColladaException(const std::string& msg) : msg(msg) { }
~ColladaException() throw() { }
virtual const char* what() const throw() { return msg.c_str(); }
private:
std::string msg;
};
struct OutputCB
{
virtual ~OutputCB() { }
virtual void operator() (const char* data, unsigned int length)=0;
};
/**
* Standard error handler - logs FCollada messages using Log(), and also
* maintains a list of XML parser errors.
*/
class FColladaErrorHandler
{
public:
FColladaErrorHandler(std::string& xmlErrors);
~FColladaErrorHandler();
private:
void OnError(FUError::Level errorLevel, uint32 errorCode, uint32 lineNumber);
std::string& xmlErrors;
void operator=(FColladaErrorHandler);
};
/**
* Standard document loader. Based on FCDocument::LoadFromText, but allows
* access to \<extra\> nodes at the document level (i.e. directly in \<COLLADA\>).
*/
class FColladaDocument
{
public:
/**
* Loads the document from the given XML string. Should be the first function
* called on this object, and should only be called once.
* @throws ColladaException if unable to load.
*/
void LoadFromText(const char* text);
/** Returns the FCDocument that was loaded. */
FCDocument* GetDocument() const { return document.get(); }
/** Returns the \<extra\> data from the \<COLLADA\> element. */
FCDExtra* GetExtra() const { return extra.get(); }
private:
void ReadExtras(xmlNode* colladaNode);
std::unique_ptr<FCDocument> document;
std::unique_ptr<FCDExtra> extra;
};
/**
* Wrapper for code shared between the PMD and PSA converters. Loads the document
* and provides access to the relevant objects and values.
*/
class CommonConvert
{
public:
CommonConvert(const char* text, std::string& xmlErrors);
~CommonConvert();
const FColladaDocument& GetDocument() const { return m_Doc; }
FCDSceneNode& GetRoot() { return *m_Doc.GetDocument()->GetVisualSceneRoot(); }
FCDEntityInstance& GetInstance() { return *m_Instance; }
const FMMatrix44& GetEntityTransform() const { return m_EntityTransform; }
bool IsYUp() const { return m_YUp; }
bool IsXSI() const { return m_IsXSI; }
private:
FColladaErrorHandler m_Err;
FColladaDocument m_Doc;
FCDEntityInstance* m_Instance;
FMMatrix44 m_EntityTransform;
bool m_YUp;
bool m_IsXSI;
};
/** Throws a ColladaException unless the value is true. */
#define REQUIRE(value, message) require_(__LINE__, value, "Assertion not satisfied", "failed requirement \"" message "\"")
/** Throws a ColladaException unless the status is successful. */
#define REQUIRE_SUCCESS(status) require_(__LINE__, status, "FCollada error", "Line " STRINGIFY(__LINE__))
#define STRINGIFY(x) #x
void require_(int line, bool value, const char* type, const char* message);
/** Outputs a structure, using sizeof to get the size. */
template<typename T> void write(OutputCB& output, const T& data)
{
output((char*)&data, sizeof(T));
}
/**
* Tries to find a single suitable entity instance in the scene. Fails if there
* are none, or if there are too many and it's not clear which one should
* be converted.
*
* @param node root scene node to search under
* @param instance output - the found entity instance (if any)
* @param transform - the world-space transform of the found entity
*
* @return true if one was found
*/
bool FindSingleInstance(FCDSceneNode* node, FCDEntityInstance*& instance, FMMatrix44& transform);
/**
* Like FCDSkinController::ReduceInfluences but works correctly.
* Additionally, multiple influences for the same joint-vertex pair are
* collapsed into a single influence.
*/
void SkinReduceInfluences(FCDSkinController* skin, size_t maxInfluenceCount, float minimumWeight);
/**
* Fixes some occasional problems with the skeleton root definitions in a
* controller. (In particular, it's needed for models exported from XSI.)
* Should be called before extracting any joint information from the controller.
*/
void FixSkeletonRoots(FCDControllerInstance& controllerInstance);
/**
* Finds the skeleton definition which best matches the given controller.
* @throws ColladaException if none is found.
*/
const Skeleton& FindSkeleton(const FCDControllerInstance& controllerInstance);
/** Bone pose data */
struct BoneTransform
{
float translation[3];
float orientation[4];
};
/**
* Performs the standard transformations on bones, applying a scale matrix and
* moving them into the game's coordinate space.
*/
void TransformBones(std::vector<BoneTransform>& bones, const FMMatrix44& scaleTransform, bool yUp);
extern FMMatrix44 FMMatrix44_Identity;
#endif // INCLUDED_COMMONCONVERT