/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see .
*
*/
/*
* Partially based on XFile parser code from Wine sources.
* Copyright 2008 Christian Costa
*/
#ifndef WINTERMUTE_XFILE_LOADER_H
#define WINTERMUTE_XFILE_LOADER_H
#include "common/str.h"
#include "common/stack.h"
namespace Wintermute {
enum XTokenType : uint16 {
XTOKEN_ERROR = 0xffff,
XTOKEN_NONE = 0,
XTOKEN_NAME = 1,
XTOKEN_STRING = 2,
XTOKEN_INTEGER = 3,
XTOKEN_GUID = 5,
XTOKEN_INTEGER_LIST = 6,
XTOKEN_FLOAT_LIST = 7,
XTOKEN_OBRACE = 10,
XTOKEN_CBRACE = 11,
XTOKEN_OPAREN = 12,
XTOKEN_CPAREN = 13,
XTOKEN_OBRACKET = 14,
XTOKEN_CBRACKET = 15,
XTOKEN_OANGLE = 16,
XTOKEN_CANGLE = 17,
XTOKEN_DOT = 18,
XTOKEN_COMMA = 19,
XTOKEN_SEMICOLON = 20,
XTOKEN_TEMPLATE = 31,
XTOKEN_WORD = 40,
XTOKEN_DWORD = 41,
XTOKEN_FLOAT = 42,
XTOKEN_DOUBLE = 43,
XTOKEN_CHAR = 44,
XTOKEN_UCHAR = 45,
XTOKEN_SWORD = 46,
XTOKEN_SDWORD = 47,
XTOKEN_VOID = 48,
XTOKEN_LPSTR = 49,
XTOKEN_UNICODE = 50,
XTOKEN_CSTRING = 51,
XTOKEN_ARRAY = 52
};
#define XMAX_NAME_LEN 120
#define XMAX_STRING_LEN 500
struct XToken {
XTokenType _type;
char _textVal[XMAX_STRING_LEN];
uint32 _integerVal;
float _floatVal;
};
struct XVector3 {
float _x;
float _y;
float _z;
};
struct XVector4 {
float _x;
float _y;
float _z;
float _w;
};
struct XCoords2d {
float _u;
float _v;
};
struct XMeshFace {
uint32 _numFaceVertexIndices;
uint32 _faceVertexIndices[4];
};
struct XTimedFloatKeys {
float _time;
uint32 _numTfkeys;
float _tfkeys[16];
};
struct XIndexedColor {
uint32 _index;
float _indexColorR;
float _indexColorG;
float _indexColorB;
float _indexColorA;
};
struct XVertexElement {
uint32 _type;
uint32 _method;
uint32 _usage;
uint32 _usageIndex;
};
struct XMeshMaterialListObject {
uint32 _nMaterials;
uint32 _numFaceIndexes;
uint32 *_faceIndexes{};
~XMeshMaterialListObject() {
delete[] _faceIndexes;
}
};
struct XVertexDuplicationIndicesObject {
uint32 _nOriginalVertices;
uint32 _numIndices;
uint32 *_indices{};
~XVertexDuplicationIndicesObject() {
delete[] _indices;
}
};
struct XSkinMeshHeaderObject{
uint32 _nMaxSkinWeightsPerVertex;
uint32 _nMaxSkinWeightsPerFace;
uint32 _nBones;
};
struct XSkinWeightsObject {
char _transformNodeName[XMAX_NAME_LEN];
uint32 _numVertexIndices;
uint32 *_vertexIndices{};
uint32 _numWeights;
float *_weights{};
float _matrixOffset[16];
~XSkinWeightsObject() {
delete[] _vertexIndices;
delete[] _weights;
}
};
struct XMeshObject {
uint32 _numVertices;
XVector3 *_vertices{};
uint32 _numFaces;
XMeshFace *_faces{};
~XMeshObject() {
delete[] _vertices;
delete[] _faces;
}
};
struct XMeshNormalsObject {
uint32 _numNormals;
XVector3 *_normals{};
uint32 _numFaceNormals;
XMeshFace *_faceNormals{};
~XMeshNormalsObject() {
delete[] _normals;
delete[] _faceNormals;
}
};
struct XMeshVertexColorsObject {
uint32 _numVertexColors;
XIndexedColor *_vertexColors{};
~XMeshVertexColorsObject() {
delete[] _vertexColors;
}
};
struct XMeshTextureCoordsObject {
uint32 _numTextureCoords;
XCoords2d *_textureCoords{};
~XMeshTextureCoordsObject() {
delete[] _textureCoords;
}
};
struct XMaterialObject {
float _colorR;
float _colorG;
float _colorB;
float _colorA;
float _power;
float _specularR;
float _specularG;
float _specularB;
float _emissiveR;
float _emissiveG;
float _emissiveB;
};
struct XTextureFilenameObject {
char _filename[XMAX_NAME_LEN];
};
struct XAnimTicksPerSecondObject {
uint32 _animTicksPerSecond;
};
struct XAnimationSetObject{
};
struct XAnimationObject{
};
struct XAnimationKeyObject {
uint32 _keyType;
uint32 _numKeys;
XTimedFloatKeys *_keys{};
~XAnimationKeyObject() {
delete[] _keys;
}
};
struct XAnimationOptionsObject {
uint32 _openclosed;
uint32 _positionquality;
};
struct XFrameObject {
};
struct XFrameTransformMatrixObject {
float _frameMatrix[16];
};
struct XDeclDataObject {
uint32 _numElements;
XVertexElement *_elements{};
uint32 _numData;
uint32 *_data{};
~XDeclDataObject() {
delete[] _elements;
delete[] _data;
}
};
struct XFVFDataObject {
uint32 _dwFVF;
uint32 _numData;
uint32 *_data{};
~XFVFDataObject() {
delete[] _data;
}
};
enum XClassType {
kXClassUnknown = 0,
kXClassAnimTicksPerSecond,
kXClassFrameTransformMatrix,
kXClassFrame,
kXClassMesh,
kXClassMeshNormals,
kXClassMeshVertexColors,
kXClassMeshTextureCoords,
kXClassMeshMaterialList,
kXClassVertexDuplicationIndices,
kXClassMaterial,
kXClassTextureFilename,
kXClassSkinMeshHeader,
kXClassSkinWeights,
kXClassAnimationSet,
kXClassAnimation,
kXClassAnimationKey,
kXClassAnimationOptions,
kXClassDeclData,
kXClassFVFData,
};
class XFileEnumObject;
class XObject {
friend class XFileLoader;
friend class XFileData;
friend class XFileEnumObject;
private:
Common::String _name;
XClassType _classType{};
void *_object{};
XObject *_targetObject{};
Common::Stack _children;
public:
void deinit() {
switch (_classType) {
case kXClassAnimTicksPerSecond:
delete (XAnimTicksPerSecondObject *)_object;
break;
case kXClassAnimationKey:
delete (XAnimationKeyObject *)_object;
break;
case kXClassAnimation:
delete (XAnimationObject *)_object;
break;
case kXClassAnimationOptions:
delete (XAnimationOptionsObject *)_object;
break;
case kXClassAnimationSet:
delete (XAnimationSetObject *)_object;
break;
case kXClassDeclData:
delete (XDeclDataObject *)_object;
break;
case kXClassFrame:
delete (XFrameObject *)_object;
break;
case kXClassFrameTransformMatrix:
delete (XFrameTransformMatrixObject *)_object;
break;
case kXClassFVFData:
delete (XFVFDataObject *)_object;
break;
case kXClassMaterial:
delete (XMaterialObject *)_object;
break;
case kXClassMesh:
delete (XMeshObject *)_object;
break;
case kXClassMeshMaterialList:
delete (XMeshMaterialListObject *)_object;
break;
case kXClassMeshNormals:
delete (XMeshNormalsObject *)_object;
break;
case kXClassMeshVertexColors:
delete (XMeshVertexColorsObject *)_object;
break;
case kXClassMeshTextureCoords:
delete (XMeshTextureCoordsObject *)_object;
break;
case kXClassSkinMeshHeader:
delete (XSkinMeshHeaderObject *)_object;
break;
case kXClassSkinWeights:
delete (XSkinWeightsObject *)_object;
break;
case kXClassVertexDuplicationIndices:
delete (XVertexDuplicationIndicesObject *)_object;
break;
case kXClassTextureFilename:
delete (XTextureFilenameObject *)_object;
break;
case kXClassUnknown:
break;
}
}
};
class XFileLoader {
friend class XFileEnumObject;
private:
const int kCabBlockSize = 0x8000;
const int kCabInputmax = kCabBlockSize + 12;
bool _initialised{};
XToken _currentToken{};
byte *_decompBuffer{};
byte *_buffer{};
uint32 _bufferLeft;
bool _isText;
uint32 _listNbElements;
bool _listTypeFloat;
bool _listSeparator;
bool _tokenPresent;
Common::Stack _xobjects;
public:
XFileLoader();
~XFileLoader();
bool load(byte *buffer, uint32 bufferSize);
bool createEnumObject(XFileEnumObject &xobj);
private:
void init();
void deinit();
FORCEINLINE bool readChar(char &c);
FORCEINLINE void rewindBytes(uint32 size);
bool readBytes(void *data, uint32 size);
bool readLE16(uint16 *data);
bool readLE32(uint32 *data);
bool readBE32(uint32 *data);
FORCEINLINE bool getInteger(uint32 &value);
FORCEINLINE bool getFloat(float &value);
FORCEINLINE bool getString(char *str, uint maxLen);
FORCEINLINE bool skipSemicolonComma();
FORCEINLINE bool isSpace(char c);
FORCEINLINE bool isOperator(char c);
FORCEINLINE bool isSeparator(char c);
FORCEINLINE bool isPrimitiveType(XTokenType token);
FORCEINLINE bool isGuid();
FORCEINLINE bool isName();
FORCEINLINE bool isFloat();
FORCEINLINE bool isInteger();
FORCEINLINE bool isString();
FORCEINLINE bool isKeyword(const char *keyword, uint len);
FORCEINLINE XTokenType getKeywordToken();
FORCEINLINE XTokenType checkToken();
XTokenType getToken();
void parseToken();
bool decompressMsZipData();
bool parseHeader();
bool parseTemplate();
bool parseTemplateParts();
bool parseTemplateOptionInfo();
bool parseTemplateMembersList();
XObject *resolveChildObject(XObject *object, const Common::String &referenceName);
bool resolveObject(XObject *referenceObject, const Common::String &referenceName);
bool parseObject(XObject *object);
bool parseChildObjects(XObject *object);
bool parseObjectParts(XObject *object);
};
class XFileData {
friend class XFileEnumObject;
private:
XObject *_xobject{};
bool _reference{};
public:
bool getChild(uint id, XFileData &child) {
if (_xobject) {
if (id < _xobject->_children.size()) {
child._xobject = _xobject->_children[id];
if (child._xobject->_targetObject) {
child._xobject = child._xobject->_targetObject;
child._reference = true;
}
return true;
}
}
return false;
}
bool getChildren(uint32 &num) {
if (_xobject) {
num = _xobject->_children.size();
return true;
}
return false;
}
bool getName(Common::String &name) {
if (_xobject) {
name = _xobject->_name;
return true;
}
return false;
}
bool getType(XClassType &classType) {
if (_xobject) {
classType = _xobject->_classType;
return true;
}
return false;
}
bool isReference() {
if (_xobject) {
return _reference;
}
return false;
}
#define GET_OBJECT_FUNC(objectName) \
objectName *get ## objectName() { \
if (_xobject) \
return static_cast(_xobject->_object); \
else \
return nullptr; \
}
GET_OBJECT_FUNC(XAnimTicksPerSecondObject)
GET_OBJECT_FUNC(XAnimationKeyObject)
GET_OBJECT_FUNC(XAnimationObject)
GET_OBJECT_FUNC(XAnimationOptionsObject)
GET_OBJECT_FUNC(XAnimationSetObject)
GET_OBJECT_FUNC(XDeclDataObject)
GET_OBJECT_FUNC(XFrameObject)
GET_OBJECT_FUNC(XFrameTransformMatrixObject)
GET_OBJECT_FUNC(XFVFDataObject)
GET_OBJECT_FUNC(XMaterialObject)
GET_OBJECT_FUNC(XMeshObject)
GET_OBJECT_FUNC(XMeshMaterialListObject)
GET_OBJECT_FUNC(XMeshNormalsObject)
GET_OBJECT_FUNC(XMeshVertexColorsObject)
GET_OBJECT_FUNC(XMeshTextureCoordsObject)
GET_OBJECT_FUNC(XSkinMeshHeaderObject)
GET_OBJECT_FUNC(XSkinWeightsObject)
GET_OBJECT_FUNC(XVertexDuplicationIndicesObject)
GET_OBJECT_FUNC(XTextureFilenameObject)
};
class XFileEnumObject {
friend class XFileLoader;
private:
XFileLoader *_file{};
public:
bool getChild(uint id, XFileData &child) {
if (_file) {
if (id < _file->_xobjects.size()) {
child._xobject = _file->_xobjects[id];
return true;
}
}
return false;
}
bool getChildren(uint32 &num) {
if (_file) {
num = _file->_xobjects.size();
return true;
}
return false;
}
};
} // namespace Wintermute
#endif