684 lines
16 KiB
C++
684 lines
16 KiB
C++
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions
|
|
// are met:
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
|
// contributors may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved.
|
|
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
|
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
|
|
|
#include <stdio.h>
|
|
#include "AcclaimLoader.h"
|
|
#include "FrameworkFoundation.h"
|
|
#include "PsMathUtils.h"
|
|
#include "PxTkFile.h"
|
|
#include "SampleAllocatorSDKClasses.h"
|
|
#include "SampleArray.h"
|
|
|
|
#define MAX_FILE_BUFFER_SIZE 4096
|
|
#define MAX_TOKEN_LENGTH 512
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static inline bool isWhiteSpace(int c)
|
|
{
|
|
return ( c == ' ') || (c == '\t');
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static inline bool isWhiteSpaceAndNewline(int c)
|
|
{
|
|
return ( c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') ;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static inline bool isNumeric(int c)
|
|
{
|
|
return ('0' <= c) && (c <= '9');
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
class SampleFileBuffer
|
|
{
|
|
SampleFramework::File* mFP;
|
|
char mBuffer[MAX_FILE_BUFFER_SIZE];
|
|
int mCurrentBufferSize;
|
|
int mCurrentCounter;
|
|
int mEOF;
|
|
|
|
public:
|
|
SampleFileBuffer(SampleFramework::File* fp) :
|
|
mFP(fp),
|
|
mCurrentBufferSize(0),
|
|
mCurrentCounter(0),
|
|
mEOF(0)
|
|
{}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
inline void rewind(int offset = 1)
|
|
{
|
|
mCurrentCounter -= offset;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
void readBuffer()
|
|
{
|
|
mCurrentBufferSize = (int)fread(mBuffer, 1, MAX_FILE_BUFFER_SIZE, mFP);
|
|
mEOF = feof(mFP);
|
|
mCurrentCounter = 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
char getCharacter()
|
|
{
|
|
if (mCurrentCounter >= mCurrentBufferSize)
|
|
{
|
|
if (mEOF) return EOF;
|
|
readBuffer();
|
|
if (mCurrentBufferSize == 0)
|
|
return EOF;
|
|
}
|
|
return mBuffer[mCurrentCounter++];
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
bool skipWhiteSpace(bool stopAtEndOfLine)
|
|
{
|
|
char c = 0;
|
|
do
|
|
{
|
|
c = getCharacter();
|
|
bool skip = (stopAtEndOfLine) ? isWhiteSpace(c) : isWhiteSpaceAndNewline(c);
|
|
if (skip == false)
|
|
{
|
|
rewind();
|
|
return true;
|
|
}
|
|
} while (c != EOF);
|
|
|
|
return false; // end of file
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool getNextToken(char* token, bool stopAtEndOfLine)
|
|
{
|
|
if (skipWhiteSpace(stopAtEndOfLine) == false)
|
|
return false;
|
|
|
|
char* str = token;
|
|
char c = 0;
|
|
do
|
|
{
|
|
c = getCharacter();
|
|
if (c == EOF)
|
|
{
|
|
*str = 0;
|
|
}
|
|
else if (isWhiteSpaceAndNewline(c) == true)
|
|
{
|
|
*str = 0;
|
|
rewind();
|
|
return (strlen(token) > 0);
|
|
}
|
|
else
|
|
*str++ = (char) c;
|
|
} while (c != EOF);
|
|
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool getNextTokenButMarker(char* token)
|
|
{
|
|
if (skipWhiteSpace(false) == false)
|
|
return 0;
|
|
|
|
char* str = token;
|
|
char c = 0;
|
|
do
|
|
{
|
|
c = getCharacter();
|
|
if (c == ':')
|
|
{
|
|
rewind();
|
|
*str = 0;
|
|
return false;
|
|
}
|
|
|
|
if (c == EOF)
|
|
{
|
|
*str = 0;
|
|
}
|
|
else if (isWhiteSpaceAndNewline(c) == true)
|
|
{
|
|
*str = 0;
|
|
rewind();
|
|
return (strlen(token) > 0);
|
|
}
|
|
else
|
|
*str++ = (char) c;
|
|
} while (c != EOF);
|
|
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool getNextTokenButNumeric(char* token)
|
|
{
|
|
if (skipWhiteSpace(false) == false)
|
|
return 0;
|
|
|
|
char* str = token;
|
|
char c = 0;
|
|
do
|
|
{
|
|
c = getCharacter();
|
|
if (isNumeric(c))
|
|
{
|
|
rewind();
|
|
*str = 0;
|
|
return false;
|
|
}
|
|
|
|
if (c == EOF)
|
|
{
|
|
*str = 0;
|
|
}
|
|
else if (isWhiteSpaceAndNewline(c) == true)
|
|
{
|
|
*str = 0;
|
|
rewind();
|
|
return (strlen(token) > 0);
|
|
}
|
|
else
|
|
*str++ = (char) c;
|
|
} while (c != EOF);
|
|
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void skipUntilNextLine()
|
|
{
|
|
char c = 0;
|
|
do
|
|
{
|
|
c = getCharacter();
|
|
} while ((c != '\n') && (c != EOF));
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void skipUntilNextBlock()
|
|
{
|
|
char dummy[MAX_TOKEN_LENGTH];
|
|
while (getNextTokenButMarker(dummy) == true)
|
|
;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool getNextFloat(float& val, bool stopAtEndOfLine = true)
|
|
{
|
|
char dummy[MAX_TOKEN_LENGTH];
|
|
if (getNextToken(dummy, stopAtEndOfLine) == false)
|
|
return false;
|
|
|
|
val = float(atof(dummy));
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool getNextInt(int& val, bool stopAtEndOfLine = true)
|
|
{
|
|
char dummy[MAX_TOKEN_LENGTH];
|
|
if (getNextToken(dummy, stopAtEndOfLine) == false)
|
|
return false;
|
|
|
|
val = int(atoi(dummy));
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool getNextString(char* val, bool stopAtEndOfLine = true)
|
|
{
|
|
char dummy[MAX_TOKEN_LENGTH];
|
|
|
|
if (getNextToken(dummy, stopAtEndOfLine) == false)
|
|
return false;
|
|
|
|
strcpy(val, dummy);
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool getNextVec3(PxVec3& val, bool stopAtEndOfLine = true)
|
|
{
|
|
if (getNextFloat(val.x, stopAtEndOfLine) == false)
|
|
return false;
|
|
|
|
if (getNextFloat(val.y, stopAtEndOfLine) == false)
|
|
return false;
|
|
|
|
if (getNextFloat(val.z, stopAtEndOfLine) == false)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static bool readHeader(SampleFileBuffer& buffer, Acclaim::ASFData& data)
|
|
{
|
|
using namespace Acclaim;
|
|
|
|
char token[MAX_TOKEN_LENGTH], value[MAX_TOKEN_LENGTH];
|
|
|
|
while (buffer.getNextTokenButMarker(token) == true)
|
|
{
|
|
|
|
if (strcmp(token, "mass") == 0)
|
|
{
|
|
if (buffer.getNextFloat(data.mHeader.mMass) == false)
|
|
return false;
|
|
}
|
|
else if (strcmp(token, "length") == 0)
|
|
{
|
|
if (buffer.getNextFloat(data.mHeader.mLengthUnit) == false)
|
|
return false;
|
|
}
|
|
else if (strcmp(token, "angle") == 0)
|
|
{
|
|
if (buffer.getNextToken(value, true) == false)
|
|
return false;
|
|
|
|
data.mHeader.mAngleInDegree = (strcmp(value, "deg") == 0);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static bool readRoot(SampleFileBuffer& buffer, Acclaim::ASFData& data)
|
|
{
|
|
using namespace Acclaim;
|
|
|
|
char token[MAX_TOKEN_LENGTH];
|
|
|
|
while (buffer.getNextTokenButMarker(token) == true)
|
|
{
|
|
if (strcmp(token, "order") == 0)
|
|
buffer.skipUntilNextLine();
|
|
else if (strcmp(token, "axis") == 0)
|
|
buffer.skipUntilNextLine();
|
|
else if (strcmp(token, "position") == 0)
|
|
{
|
|
if (buffer.getNextVec3(data.mRoot.mPosition) == false)
|
|
return false;
|
|
}
|
|
else if (strcmp(token, "orientation") == 0)
|
|
{
|
|
if (buffer.getNextVec3(data.mRoot.mOrientation) == false)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
buffer.skipUntilNextLine();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static bool readBone(SampleFileBuffer& buffer, Acclaim::Bone& bone)
|
|
{
|
|
using namespace Acclaim;
|
|
|
|
int nbDOF = 0;
|
|
char token[MAX_TOKEN_LENGTH], dummy[MAX_TOKEN_LENGTH];
|
|
|
|
if (buffer.getNextTokenButMarker(token) == false)
|
|
return false;
|
|
|
|
if (strcmp(token, "begin") != 0)
|
|
return false;
|
|
|
|
while (buffer.getNextToken(token, false) == true)
|
|
{
|
|
if (strcmp(token, "id") == 0)
|
|
{
|
|
if (buffer.getNextInt(bone.mID) == false) return false;
|
|
}
|
|
else if (strcmp(token, "name") == 0)
|
|
{
|
|
if (buffer.getNextString(bone.mName) == false) return false;
|
|
}
|
|
else if (strcmp(token, "direction") == 0)
|
|
{
|
|
if (buffer.getNextVec3(bone.mDirection) == false) return false;
|
|
}
|
|
else if (strcmp(token, "length") == 0)
|
|
{
|
|
if (buffer.getNextFloat(bone.mLength) == false) return false;
|
|
}
|
|
else if (strcmp(token, "axis") == 0)
|
|
{
|
|
if (buffer.getNextVec3(bone.mAxis) == false) return false;
|
|
buffer.getNextToken(dummy, true);
|
|
}
|
|
else if (strcmp(token, "dof") == 0)
|
|
{
|
|
while ((buffer.getNextToken(dummy, true) == true))
|
|
{
|
|
if (strcmp(dummy, "rx") == 0)
|
|
{
|
|
bone.mDOF |= BoneDOFFlag::eRX;
|
|
nbDOF++;
|
|
}
|
|
else if (strcmp(dummy, "ry") == 0)
|
|
{
|
|
bone.mDOF |= BoneDOFFlag::eRY;
|
|
nbDOF++;
|
|
}
|
|
else if (strcmp(dummy, "rz") == 0)
|
|
{
|
|
bone.mDOF |= BoneDOFFlag::eRZ;
|
|
nbDOF++;
|
|
}
|
|
else if (strcmp(dummy, "l") == 0)
|
|
{
|
|
bone.mDOF |= BoneDOFFlag::eLENGTH;
|
|
nbDOF++;
|
|
}
|
|
|
|
}
|
|
continue;
|
|
}
|
|
else if (strcmp(token, "limits") == 0)
|
|
{
|
|
int cnt = 0;
|
|
while ( cnt++ < nbDOF)
|
|
{
|
|
// we ignore limit data for now
|
|
if (buffer.getNextToken(dummy, false) == false) return false;
|
|
if (buffer.getNextToken(dummy, false) == false) return false;
|
|
}
|
|
}
|
|
else if (strcmp(token, "end") == 0)
|
|
break;
|
|
else
|
|
buffer.skipUntilNextLine();
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static bool readBoneData(SampleFileBuffer& buffer, Acclaim::ASFData& data)
|
|
{
|
|
using namespace Acclaim;
|
|
|
|
Bone tempBones[MAX_BONE_NUMBER];
|
|
PxU32 nbBones = 0;
|
|
|
|
// read all the temporary bones onto temporary buffer
|
|
bool moreBone = false;
|
|
do {
|
|
moreBone = readBone(buffer, tempBones[nbBones]);
|
|
if (moreBone)
|
|
nbBones++;
|
|
|
|
PX_ASSERT(nbBones <= MAX_BONE_NUMBER);
|
|
} while (moreBone == true);
|
|
|
|
// allocate the right size and copy the bone data
|
|
data.mBones = (Bone*)malloc(sizeof(Bone) * nbBones);
|
|
data.mNbBones = nbBones;
|
|
|
|
for (PxU32 i = 0; i < nbBones; i++)
|
|
{
|
|
data.mBones[i] = tempBones[i];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static Acclaim::Bone* getBoneFromName(Acclaim::ASFData& data, const char* name)
|
|
{
|
|
// use a simple linear search -> probably we could use hash map if performance is an issue
|
|
for (PxU32 i = 0; i < data.mNbBones; i++)
|
|
{
|
|
if (strcmp(name, data.mBones[i].mName) == 0)
|
|
return &data.mBones[i];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static bool readHierarchy(SampleFileBuffer& buffer, Acclaim::ASFData& data)
|
|
{
|
|
using namespace Acclaim;
|
|
|
|
char token[MAX_TOKEN_LENGTH];
|
|
char dummy[MAX_TOKEN_LENGTH];
|
|
|
|
while (buffer.getNextTokenButMarker(token) == true)
|
|
{
|
|
if (strcmp(token, "begin") == 0)
|
|
;
|
|
else if (strcmp(token, "end") == 0)
|
|
break;
|
|
else
|
|
{
|
|
Bone* parent = getBoneFromName(data, token);
|
|
|
|
while (buffer.getNextToken(dummy, true) == true)
|
|
{
|
|
Bone* child = getBoneFromName(data, dummy);
|
|
if (!child)
|
|
return false;
|
|
|
|
child->mParent = parent;
|
|
}
|
|
}
|
|
|
|
buffer.skipUntilNextLine();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static bool readFrameData(SampleFileBuffer& buffer, Acclaim::ASFData& asfData, Acclaim::FrameData& frameData)
|
|
{
|
|
using namespace Acclaim;
|
|
char token[MAX_TOKEN_LENGTH];
|
|
|
|
while (buffer.getNextTokenButNumeric(token) == true)
|
|
{
|
|
if (strcmp(token, "root") == 0)
|
|
{
|
|
buffer.getNextVec3(frameData.mRootPosition);
|
|
buffer.getNextVec3(frameData.mRootOrientation);
|
|
}
|
|
else
|
|
{
|
|
Bone* bone = getBoneFromName(asfData, token);
|
|
|
|
if (bone == 0)
|
|
return false;
|
|
|
|
int id = bone->mID - 1;
|
|
float val = 0;
|
|
if (bone->mDOF & BoneDOFFlag::eRX)
|
|
{
|
|
|
|
buffer.getNextFloat(val);
|
|
frameData.mBoneFrameData[id].x = val;
|
|
}
|
|
if (bone->mDOF & BoneDOFFlag::eRY)
|
|
{
|
|
|
|
buffer.getNextFloat(val);
|
|
frameData.mBoneFrameData[id].y = val;
|
|
}
|
|
if (bone->mDOF & BoneDOFFlag::eRZ)
|
|
{
|
|
|
|
buffer.getNextFloat(val);
|
|
frameData.mBoneFrameData[id].z = val;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool Acclaim::readASFData(const char* filename, Acclaim::ASFData& data)
|
|
{
|
|
using namespace Acclaim;
|
|
|
|
char token[MAX_TOKEN_LENGTH];
|
|
|
|
SampleFramework::File* fp = NULL;
|
|
PxToolkit::fopen_s(&fp, filename, "r");
|
|
|
|
if (!fp)
|
|
return false;
|
|
|
|
SampleFileBuffer buffer(fp);
|
|
|
|
while (buffer.getNextToken(token, false) == true)
|
|
{
|
|
if (token[0] == '#') // comment
|
|
{
|
|
buffer.skipUntilNextLine();
|
|
continue;
|
|
}
|
|
else if (token[0] == ':') // blocks
|
|
{
|
|
const char* str = token + 1; // remainder of the string
|
|
|
|
if (strcmp(str, "version") == 0) // ignore version number
|
|
buffer.skipUntilNextLine();
|
|
else if (strcmp(str, "name") == 0) // probably 'VICON'
|
|
buffer.skipUntilNextLine();
|
|
else if (strcmp(str, "units") == 0)
|
|
{
|
|
if ( readHeader(buffer, data) == false)
|
|
return false;
|
|
}
|
|
else if (strcmp(str, "documentation") == 0)
|
|
buffer.skipUntilNextBlock();
|
|
else if (strcmp(str, "root") == 0)
|
|
{
|
|
if (readRoot(buffer, data) == false)
|
|
return false;
|
|
}
|
|
else if (strcmp(str, "bonedata") == 0)
|
|
{
|
|
if (readBoneData(buffer, data) == false)
|
|
return false;
|
|
}
|
|
else if (strcmp(str, "hierarchy") == 0)
|
|
{
|
|
if (readHierarchy(buffer, data) == false)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// ERROR! - unrecognized block name
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ERRROR!
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
fclose(fp);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool Acclaim::readAMCData(const char* filename, Acclaim::ASFData& asfData, Acclaim::AMCData& amcData)
|
|
{
|
|
using namespace Acclaim;
|
|
|
|
char token[MAX_TOKEN_LENGTH];
|
|
|
|
SampleArray<FrameData> tempFrameData;
|
|
tempFrameData.reserve(300);
|
|
|
|
SampleFramework::File* fp = NULL;
|
|
PxToolkit::fopen_s(&fp, filename, "r");
|
|
|
|
if (!fp)
|
|
return false;
|
|
|
|
SampleFileBuffer buffer(fp);
|
|
|
|
while (buffer.getNextToken(token, false) == true)
|
|
{
|
|
if (token[0] == '#') // comment
|
|
{
|
|
buffer.skipUntilNextLine();
|
|
continue;
|
|
}
|
|
else if (token[0] == ':') // blocks
|
|
{
|
|
const char* str = token + 1; // remainder of the string
|
|
|
|
if (strcmp(str, "FULLY-SPECIFIED") == 0)
|
|
continue;
|
|
else if (strcmp(str, "DEGREES") == 0)
|
|
continue;
|
|
}
|
|
else if (isNumeric(token[0]) == true)
|
|
{
|
|
// frame number
|
|
//int frameNo = atoi(token);
|
|
|
|
FrameData frameData;
|
|
if (readFrameData(buffer, asfData, frameData) == true)
|
|
tempFrameData.pushBack(frameData);
|
|
}
|
|
}
|
|
|
|
amcData.mNbFrames = tempFrameData.size();
|
|
|
|
amcData.mFrameData = (FrameData*)malloc(sizeof(FrameData) * amcData.mNbFrames);
|
|
memcpy(amcData.mFrameData, tempFrameData.begin(), sizeof(FrameData) * amcData.mNbFrames);
|
|
|
|
fclose(fp);
|
|
|
|
return true;
|
|
}
|
|
|