Initial commit
This commit is contained in:
94
engines/twine/parser/anim.cpp
Normal file
94
engines/twine/parser/anim.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "twine/parser/anim.h"
|
||||
#include "common/memstream.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
void AnimData::loadBoneFrame(KeyFrame &keyframe, Common::SeekableReadStream &stream) {
|
||||
BoneFrame boneframe;
|
||||
boneframe.type = (BoneType)stream.readSint16LE();
|
||||
boneframe.x = stream.readSint16LE();
|
||||
boneframe.y = stream.readSint16LE();
|
||||
boneframe.z = stream.readSint16LE();
|
||||
keyframe.boneframes.push_back(boneframe);
|
||||
}
|
||||
|
||||
void AnimData::loadKeyFrames(Common::SeekableReadStream &stream) {
|
||||
for (uint16 i = 0U; i < _numKeyframes; ++i) {
|
||||
KeyFrame keyframe;
|
||||
keyframe.length = stream.readUint16LE();
|
||||
keyframe.x = stream.readSint16LE();
|
||||
keyframe.y = stream.readSint16LE();
|
||||
keyframe.z = stream.readSint16LE();
|
||||
|
||||
keyframe.animMasterRot = stream.readSint16LE();
|
||||
keyframe.animStepAlpha = stream.readSint16LE();
|
||||
keyframe.animStepBeta = stream.readSint16LE();
|
||||
keyframe.animStepGamma = stream.readSint16LE();
|
||||
stream.seek(-8, SEEK_CUR);
|
||||
|
||||
for (uint16 j = 0U; j < _numBoneframes; ++j) {
|
||||
loadBoneFrame(keyframe, stream);
|
||||
}
|
||||
|
||||
_keyframes.push_back(keyframe);
|
||||
assert(keyframe.boneframes.size() == (uint)_numBoneframes);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimData::reset() {
|
||||
_keyframes.clear();
|
||||
}
|
||||
|
||||
bool AnimData::loadFromStream(Common::SeekableReadStream &stream, bool lba1) {
|
||||
reset();
|
||||
_numKeyframes = stream.readUint16LE();
|
||||
_numBoneframes = stream.readUint16LE();
|
||||
_loopFrame = stream.readUint16LE();
|
||||
stream.readUint16LE();
|
||||
|
||||
loadKeyFrames(stream);
|
||||
|
||||
return !stream.err();
|
||||
}
|
||||
|
||||
const Common::Array<KeyFrame>& AnimData::getKeyframes() const {
|
||||
return _keyframes;
|
||||
}
|
||||
|
||||
const KeyFrame* AnimData::getKeyframe(uint index) const {
|
||||
if (index >= _numKeyframes) {
|
||||
return nullptr;
|
||||
}
|
||||
return &_keyframes[index];
|
||||
}
|
||||
|
||||
uint16 AnimData::getLoopFrame() const { // GetBouclageAnim
|
||||
return _loopFrame;
|
||||
}
|
||||
|
||||
uint16 AnimData::getNumBoneframes() const {
|
||||
return _numBoneframes;
|
||||
}
|
||||
|
||||
} // namespace TwinE
|
||||
88
engines/twine/parser/anim.h
Normal file
88
engines/twine/parser/anim.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWINE_PARSER_ANIM_H
|
||||
#define TWINE_PARSER_ANIM_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/stream.h"
|
||||
#include "twine/parser/parser.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
enum BoneType : uint16 {
|
||||
TYPE_ROTATE = 0,
|
||||
TYPE_TRANSLATE = 1,
|
||||
TYPE_ZOOM = 2,
|
||||
};
|
||||
|
||||
struct BoneFrame { // T_GROUP_INFO
|
||||
BoneType type = BoneType::TYPE_ROTATE;
|
||||
int16 x = 0; // alpha
|
||||
int16 y = 0; // beta
|
||||
int16 z = 0; // gamma
|
||||
};
|
||||
using T_GROUP_INFO = BoneFrame; // (lba2)
|
||||
|
||||
struct KeyFrame {
|
||||
uint16 length = 0;
|
||||
int16 x = 0;
|
||||
int16 y = 0;
|
||||
int16 z = 0;
|
||||
int16 animMasterRot = 0;
|
||||
int16 animStepAlpha = 0;
|
||||
int16 animStepBeta = 0;
|
||||
int16 animStepGamma = 0;
|
||||
Common::Array<BoneFrame> boneframes;
|
||||
};
|
||||
|
||||
class AnimData : public Parser {
|
||||
private:
|
||||
Common::Array<KeyFrame> _keyframes;
|
||||
|
||||
void loadBoneFrame(KeyFrame &keyframe, Common::SeekableReadStream &stream);
|
||||
void loadKeyFrames(Common::SeekableReadStream &stream);
|
||||
|
||||
uint16 _numKeyframes;
|
||||
uint16 _numBoneframes;
|
||||
uint16 _loopFrame;
|
||||
|
||||
protected:
|
||||
void reset() override;
|
||||
|
||||
public:
|
||||
bool loadFromStream(Common::SeekableReadStream &stream, bool lba1) override;
|
||||
|
||||
const KeyFrame *getKeyframe(uint index) const;
|
||||
const Common::Array<KeyFrame> &getKeyframes() const;
|
||||
uint getNbFramesAnim() const;
|
||||
uint16 getLoopFrame() const;
|
||||
uint16 getNumBoneframes() const;
|
||||
};
|
||||
|
||||
inline uint AnimData::getNbFramesAnim() const {
|
||||
return getKeyframes().size();
|
||||
}
|
||||
|
||||
} // End of namespace TwinE
|
||||
|
||||
#endif
|
||||
42
engines/twine/parser/anim3ds.cpp
Normal file
42
engines/twine/parser/anim3ds.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "twine/parser/anim3ds.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
bool Anim3DSData::loadFromStream(Common::SeekableReadStream &stream, bool lba1) {
|
||||
assert(!lba1);
|
||||
|
||||
const int n = (int)stream.size() / 8;
|
||||
debug("preload %i anim3ds entries", n);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
T_ANIM_3DS anim;
|
||||
stream.read(anim.Name, sizeof(anim.Name));
|
||||
anim.Deb = stream.readSint16LE();
|
||||
anim.Fin = stream.readSint16LE();
|
||||
_anims.push_back(anim);
|
||||
}
|
||||
return !stream.err();
|
||||
}
|
||||
|
||||
} // namespace TwinE
|
||||
48
engines/twine/parser/anim3ds.h
Normal file
48
engines/twine/parser/anim3ds.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWINE_PARSER_ANIM3DS_H
|
||||
#define TWINE_PARSER_ANIM3DS_H
|
||||
|
||||
#include "twine/parser/parser.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
struct T_ANIM_3DS {
|
||||
char Name[4]; // Name of the animation
|
||||
int16 Deb; // Start frame in the HQR
|
||||
int16 Fin; // End frame in the HQR
|
||||
};
|
||||
|
||||
class Anim3DSData : public Parser {
|
||||
private:
|
||||
Common::Array<T_ANIM_3DS> _anims; // ListAnim3DS
|
||||
|
||||
public:
|
||||
bool loadFromStream(Common::SeekableReadStream &stream, bool lba1) override;
|
||||
|
||||
const Common::Array<T_ANIM_3DS> &getAnims() const { return _anims; }
|
||||
};
|
||||
|
||||
} // End of namespace TwinE
|
||||
|
||||
#endif
|
||||
74
engines/twine/parser/blocklibrary.cpp
Normal file
74
engines/twine/parser/blocklibrary.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "twine/parser/blocklibrary.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
void BlockLibraryData::reset() {
|
||||
_layouts.clear();
|
||||
}
|
||||
|
||||
bool BlockLibraryData::loadFromStream(Common::SeekableReadStream &stream, bool lba1) {
|
||||
reset();
|
||||
const uint32 numLayouts = stream.readUint32LE() / 4;
|
||||
_layouts.resize(numLayouts);
|
||||
stream.seek(0);
|
||||
for (uint32 i = 0; i < numLayouts; ++i) {
|
||||
BlockData &blockData = _layouts[i];
|
||||
const uint32 offset = stream.readUint32LE();
|
||||
const uint32 nextOffset = stream.pos();
|
||||
if (!stream.seek(offset)) {
|
||||
return false;
|
||||
}
|
||||
if (!parseLayout(blockData, stream, lba1)) {
|
||||
return false;
|
||||
}
|
||||
stream.seek(nextOffset);
|
||||
}
|
||||
return !stream.err();
|
||||
}
|
||||
|
||||
bool BlockLibraryData::parseLayout(BlockData &blockData, Common::SeekableReadStream &stream, bool lba1) {
|
||||
const uint8 x = stream.readByte();
|
||||
const uint8 y = stream.readByte();
|
||||
const uint8 z = stream.readByte();
|
||||
const int32 numBricks = x * y * z;
|
||||
blockData.entries.resize(numBricks);
|
||||
for (int32 i = 0; i < numBricks; ++i) {
|
||||
BlockDataEntry &blockEntry = blockData.entries[i];
|
||||
blockEntry.brickShape = stream.readByte();
|
||||
blockEntry.brickType = stream.readByte();
|
||||
blockEntry.brickIdx = stream.readUint16LE();
|
||||
blockEntry.sound = bits(blockEntry.brickType, 0, 4);
|
||||
}
|
||||
return !stream.err();
|
||||
}
|
||||
|
||||
const BlockData *BlockLibraryData::getLayout(int index) const {
|
||||
if (index < 0 || index >= (int)_layouts.size()) {
|
||||
error("Block library index out of range: %i", index);
|
||||
}
|
||||
return &_layouts[index];
|
||||
}
|
||||
|
||||
} // End of namespace TwinE
|
||||
59
engines/twine/parser/blocklibrary.h
Normal file
59
engines/twine/parser/blocklibrary.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWINE_PARSER_BLOCKLIBRARY_H
|
||||
#define TWINE_PARSER_BLOCKLIBRARY_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/stream.h"
|
||||
#include "twine/parser/parser.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
struct BlockDataEntry {
|
||||
uint8 brickShape;
|
||||
uint8 brickType;
|
||||
/**
|
||||
* Index is not starting at 0 - but at 1. A 0 indicates an empty brick
|
||||
*/
|
||||
uint16 brickIdx;
|
||||
uint8 sound;
|
||||
};
|
||||
|
||||
struct BlockData {
|
||||
Common::Array<BlockDataEntry> entries;
|
||||
};
|
||||
|
||||
class BlockLibraryData : public Parser {
|
||||
private:
|
||||
Common::Array<BlockData> _layouts;
|
||||
bool parseLayout(BlockData &blockData, Common::SeekableReadStream &stream, bool lba1);
|
||||
protected:
|
||||
void reset() override;
|
||||
public:
|
||||
bool loadFromStream(Common::SeekableReadStream &stream, bool lba1) override;
|
||||
const BlockData *getLayout(int index) const;
|
||||
};
|
||||
|
||||
} // End of namespace TwinE
|
||||
|
||||
#endif
|
||||
241
engines/twine/parser/body.cpp
Normal file
241
engines/twine/parser/body.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "twine/parser/body.h"
|
||||
#include "twine/renderer/renderer.h"
|
||||
#include "common/memstream.h"
|
||||
|
||||
#define INFO_TRI 1
|
||||
#define INFO_ANIM 2
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
void BodyData::reset() {
|
||||
_vertices.clear();
|
||||
_bones.clear();
|
||||
_normals.clear();
|
||||
_polygons.clear();
|
||||
_spheres.clear();
|
||||
_lines.clear();
|
||||
}
|
||||
|
||||
void BodyData::loadVertices(Common::SeekableReadStream &stream) {
|
||||
const uint16 numVertices = stream.readUint16LE();
|
||||
if (stream.eos())
|
||||
return;
|
||||
|
||||
_vertices.reserve(numVertices);
|
||||
for (uint16 i = 0U; i < numVertices; ++i) {
|
||||
const int16 x = stream.readSint16LE();
|
||||
const int16 y = stream.readSint16LE();
|
||||
const int16 z = stream.readSint16LE();
|
||||
const uint16 bone = 0;
|
||||
_vertices.push_back({x, y, z, bone});
|
||||
}
|
||||
}
|
||||
|
||||
void BodyData::loadBones(Common::SeekableReadStream &stream) {
|
||||
const uint16 numBones = stream.readUint16LE();
|
||||
if (stream.eos())
|
||||
return;
|
||||
|
||||
_bones.reserve(numBones);
|
||||
for (uint16 i = 0; i < numBones; ++i) {
|
||||
const int16 firstPoint = stream.readSint16LE() / 6;
|
||||
const int16 numPoints = stream.readSint16LE();
|
||||
const int16 basePoint = stream.readSint16LE() / 6;
|
||||
const int16 baseElementOffset = stream.readSint16LE();
|
||||
BoneFrame boneframe;
|
||||
boneframe.type = (BoneType)stream.readSint16LE();
|
||||
boneframe.x = stream.readSint16LE();
|
||||
boneframe.y = stream.readSint16LE();
|
||||
boneframe.z = stream.readSint16LE();
|
||||
/*int16 unk1 =*/ stream.readSint16LE();
|
||||
const int16 numNormals = stream.readSint16LE();
|
||||
/*int16 unk2 =*/ stream.readSint16LE();
|
||||
/*int32 field_18 =*/ stream.readSint32LE();
|
||||
/*int32 y =*/ stream.readSint32LE();
|
||||
/*int32 field_20 =*/ stream.readSint32LE();
|
||||
/*int32 field_24 =*/ stream.readSint32LE();
|
||||
|
||||
// PatchObjet in original sources
|
||||
BodyBone bone;
|
||||
bone.parent = baseElementOffset == -1 ? 0xffff : baseElementOffset / 38;
|
||||
bone.vertex = basePoint;
|
||||
bone.firstVertex = firstPoint;
|
||||
bone.numVertices = numPoints;
|
||||
bone.initalBoneState = boneframe;
|
||||
bone.numNormals = numNormals;
|
||||
|
||||
// assign the bone index to the vertices
|
||||
for (int j = 0; j < numPoints; ++j) {
|
||||
_vertices[firstPoint + j].bone = i;
|
||||
}
|
||||
|
||||
_bones.push_back(bone);
|
||||
_boneStates[i] = bone.initalBoneState;
|
||||
}
|
||||
}
|
||||
|
||||
void BodyData::loadNormals(Common::SeekableReadStream &stream) {
|
||||
const uint16 numNormals = stream.readUint16LE();
|
||||
if (stream.eos())
|
||||
return;
|
||||
|
||||
_normals.reserve(numNormals);
|
||||
for (uint16 i = 0; i < numNormals; ++i) {
|
||||
BodyNormal shape;
|
||||
shape.x = stream.readSint16LE();
|
||||
shape.y = stream.readSint16LE();
|
||||
shape.z = stream.readSint16LE();
|
||||
shape.prenormalizedRange = stream.readUint16LE();
|
||||
_normals.push_back(shape);
|
||||
}
|
||||
}
|
||||
|
||||
void BodyData::loadPolygons(Common::SeekableReadStream &stream) {
|
||||
const uint16 numPolygons = stream.readUint16LE();
|
||||
if (stream.eos())
|
||||
return;
|
||||
|
||||
_polygons.reserve(numPolygons);
|
||||
for (uint16 i = 0; i < numPolygons; ++i) {
|
||||
BodyPolygon poly;
|
||||
poly.materialType = stream.readByte();
|
||||
const uint8 numVertices = stream.readByte();
|
||||
|
||||
poly.intensity = stream.readSint16LE();
|
||||
int16 normal = -1;
|
||||
if (poly.materialType == MAT_FLAT || poly.materialType == MAT_GRANIT) {
|
||||
// only one shade value is used
|
||||
normal = stream.readSint16LE();
|
||||
}
|
||||
|
||||
poly.indices.reserve(numVertices);
|
||||
poly.normals.reserve(numVertices);
|
||||
for (int k = 0; k < numVertices; ++k) {
|
||||
if (poly.materialType >= MAT_GOURAUD) {
|
||||
normal = stream.readSint16LE();
|
||||
}
|
||||
// numPoint is point index precomupted * 6
|
||||
const uint16 vertexIndex = stream.readUint16LE() / 6;
|
||||
poly.indices.push_back(vertexIndex);
|
||||
poly.normals.push_back(normal);
|
||||
}
|
||||
|
||||
_polygons.push_back(poly);
|
||||
}
|
||||
}
|
||||
|
||||
void BodyData::loadLines(Common::SeekableReadStream &stream) {
|
||||
const uint16 numLines = stream.readUint16LE();
|
||||
if (stream.eos())
|
||||
return;
|
||||
|
||||
_lines.reserve(numLines);
|
||||
for (uint16 i = 0; i < numLines; ++i) {
|
||||
BodyLine line;
|
||||
stream.skip(1);
|
||||
line.color = stream.readByte();
|
||||
stream.skip(2);
|
||||
// indexPoint is point index precomupted * 6
|
||||
line.vertex1 = stream.readUint16LE() / 6;
|
||||
line.vertex2 = stream.readUint16LE() / 6;
|
||||
_lines.push_back(line);
|
||||
}
|
||||
}
|
||||
|
||||
void BodyData::loadSpheres(Common::SeekableReadStream &stream) {
|
||||
const uint16 numSpheres = stream.readUint16LE();
|
||||
if (stream.eos())
|
||||
return;
|
||||
|
||||
_spheres.reserve(numSpheres);
|
||||
for (uint16 i = 0; i < numSpheres; ++i) {
|
||||
BodySphere sphere;
|
||||
sphere.fillType = stream.readByte();
|
||||
sphere.color = stream.readUint16LE();
|
||||
stream.readByte();
|
||||
sphere.radius = stream.readUint16LE();
|
||||
sphere.vertex = stream.readUint16LE() / 6;
|
||||
_spheres.push_back(sphere);
|
||||
}
|
||||
}
|
||||
|
||||
bool BodyData::loadFromStream(Common::SeekableReadStream &stream, bool lba1) {
|
||||
reset();
|
||||
if (lba1) {
|
||||
const uint16 flags = stream.readUint16LE();
|
||||
animated = (flags & INFO_ANIM) != 0;
|
||||
bbox.mins.x = stream.readSint16LE();
|
||||
bbox.maxs.x = stream.readSint16LE();
|
||||
bbox.mins.y = stream.readSint16LE();
|
||||
bbox.maxs.y = stream.readSint16LE();
|
||||
bbox.mins.z = stream.readSint16LE();
|
||||
bbox.maxs.z = stream.readSint16LE();
|
||||
offsetToData = stream.readSint16LE();
|
||||
|
||||
// using this value as the offset crashes the demo of lba1 - see https://bugs.scummvm.org/ticket/14294
|
||||
// stream.seek(offsetToData);
|
||||
stream.seek(0x1A);
|
||||
|
||||
loadVertices(stream);
|
||||
loadBones(stream);
|
||||
loadNormals(stream);
|
||||
loadPolygons(stream);
|
||||
loadLines(stream);
|
||||
loadSpheres(stream);
|
||||
} else {
|
||||
// T_BODY_HEADER (lba2)
|
||||
const uint32 flags = stream.readUint32LE();
|
||||
animated = (flags & INFO_ANIM) != 0;
|
||||
stream.skip(4); // int16 size of header and int16 dummy
|
||||
bbox.mins.x = stream.readSint32LE();
|
||||
bbox.maxs.x = stream.readSint32LE();
|
||||
bbox.mins.y = stream.readSint32LE();
|
||||
bbox.maxs.y = stream.readSint32LE();
|
||||
bbox.mins.z = stream.readSint32LE();
|
||||
bbox.maxs.z = stream.readSint32LE();
|
||||
stream.seek(0x20);
|
||||
#if 0
|
||||
const uint32 bonesSize = stream.readUint32LE();
|
||||
const uint32 bonesOffset = stream.readUint32LE();
|
||||
const uint32 verticesSize = stream.readUint32LE();
|
||||
const uint32 verticesOffset = stream.readUint32LE();
|
||||
const uint32 normalsSize = stream.readUint32LE();
|
||||
const uint32 normalsOffset = stream.readUint32LE();
|
||||
const uint32 unk1Size = stream.readUint32LE();
|
||||
const uint32 unk1Offset = stream.readUint32LE();
|
||||
const uint32 polygonsSize = stream.readUint32LE();
|
||||
const uint32 polygonsOffset = stream.readUint32LE();
|
||||
const uint32 linesSize = stream.readUint32LE();
|
||||
const uint32 linesOffset = stream.readUint32LE();
|
||||
const uint32 spheresSize = stream.readUint32LE();
|
||||
const uint32 spheresOffset = stream.readUint32LE();
|
||||
const uint32 uvGroupsSize = stream.readUint32LE();
|
||||
const uint32 uvGroupsOffset = stream.readUint32LE();
|
||||
#endif
|
||||
}
|
||||
|
||||
return !stream.err();
|
||||
}
|
||||
|
||||
} // namespace TwinE
|
||||
126
engines/twine/parser/body.h
Normal file
126
engines/twine/parser/body.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWINE_PARSER_BODY_H
|
||||
#define TWINE_PARSER_BODY_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/stream.h"
|
||||
#include "twine/parser/anim.h"
|
||||
#include "twine/parser/bodytypes.h"
|
||||
#include "twine/parser/parser.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
/** Actors animation timer structure */
|
||||
struct AnimTimerDataStruct {
|
||||
const KeyFrame *ptr = nullptr;
|
||||
int32 time = 0; // keyframe time
|
||||
};
|
||||
|
||||
class BodyData : public Parser {
|
||||
private:
|
||||
void loadVertices(Common::SeekableReadStream &stream);
|
||||
void loadBones(Common::SeekableReadStream &stream);
|
||||
void loadNormals(Common::SeekableReadStream &stream);
|
||||
void loadPolygons(Common::SeekableReadStream &stream);
|
||||
void loadLines(Common::SeekableReadStream &stream);
|
||||
void loadSpheres(Common::SeekableReadStream &stream);
|
||||
|
||||
Common::Array<BodyPolygon> _polygons;
|
||||
Common::Array<BodyVertex> _vertices;
|
||||
Common::Array<BodySphere> _spheres;
|
||||
Common::Array<BodyNormal> _normals;
|
||||
Common::Array<BodyLine> _lines;
|
||||
Common::Array<BodyBone> _bones;
|
||||
|
||||
BoneFrame _boneStates[560];
|
||||
|
||||
protected:
|
||||
void reset() override;
|
||||
|
||||
public:
|
||||
bool animated = false;
|
||||
AnimTimerDataStruct _animTimerData;
|
||||
|
||||
BoundingBox bbox;
|
||||
int16 offsetToData = 0;
|
||||
|
||||
inline bool isAnimated() const {
|
||||
return animated;
|
||||
}
|
||||
|
||||
inline uint getNumBones() const {
|
||||
return _bones.size();
|
||||
}
|
||||
|
||||
inline uint getNumVertices() const {
|
||||
return _vertices.size();
|
||||
}
|
||||
|
||||
BoneFrame *getBoneState(int16 boneIdx) {
|
||||
return &_boneStates[boneIdx];
|
||||
}
|
||||
|
||||
const BoneFrame *getBoneState(int16 boneIdx) const {
|
||||
return &_boneStates[boneIdx];
|
||||
}
|
||||
|
||||
const Common::Array<BodyPolygon> &getPolygons() const {
|
||||
return _polygons;
|
||||
}
|
||||
|
||||
const Common::Array<BodyVertex> &getVertices() const {
|
||||
return _vertices;
|
||||
}
|
||||
|
||||
const Common::Array<BodySphere> &getSpheres() const {
|
||||
return _spheres;
|
||||
}
|
||||
|
||||
const Common::Array<BodyNormal> &getNormals() const {
|
||||
return _normals;
|
||||
}
|
||||
|
||||
const BodyNormal &getNormal(int16 normalIdx) const {
|
||||
return _normals[normalIdx];
|
||||
}
|
||||
|
||||
const Common::Array<BodyLine> &getLines() const {
|
||||
return _lines;
|
||||
}
|
||||
|
||||
const Common::Array<BodyBone> &getBones() const {
|
||||
return _bones;
|
||||
}
|
||||
|
||||
const BodyBone &getBone(int16 boneIdx) const {
|
||||
return _bones[boneIdx];
|
||||
}
|
||||
|
||||
bool loadFromStream(Common::SeekableReadStream &stream, bool lba1) override;
|
||||
};
|
||||
|
||||
} // End of namespace TwinE
|
||||
|
||||
#endif
|
||||
83
engines/twine/parser/bodytypes.h
Normal file
83
engines/twine/parser/bodytypes.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWINE_PARSER_BODYTYPES_H
|
||||
#define TWINE_PARSER_BODYTYPES_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "twine/shared.h"
|
||||
#include "twine/parser/anim.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
struct BodyVertex {
|
||||
int16 x;
|
||||
int16 y;
|
||||
int16 z;
|
||||
uint16 bone;
|
||||
};
|
||||
|
||||
struct BodyLine {
|
||||
// fill byte here
|
||||
uint8 color;
|
||||
// 2 fill bytes here
|
||||
uint16 vertex1;
|
||||
uint16 vertex2;
|
||||
};
|
||||
|
||||
struct BodySphere {
|
||||
uint8 fillType;
|
||||
uint16 color; // start and end color index
|
||||
// fill byte here
|
||||
uint16 radius;
|
||||
uint16 vertex;
|
||||
};
|
||||
|
||||
struct BodyBone {
|
||||
uint16 parent;
|
||||
uint16 vertex;
|
||||
int16 firstVertex;
|
||||
int16 numVertices;
|
||||
int32 numNormals;
|
||||
BoneFrame initalBoneState;
|
||||
|
||||
inline bool isRoot() const {
|
||||
return parent == 0xffff;
|
||||
}
|
||||
};
|
||||
|
||||
struct BodyNormal {
|
||||
int16 x;
|
||||
int16 y;
|
||||
int16 z;
|
||||
uint16 prenormalizedRange;
|
||||
};
|
||||
|
||||
struct BodyPolygon {
|
||||
Common::Array<uint16> indices;
|
||||
Common::Array<uint16> normals;
|
||||
int8 materialType = 0;
|
||||
int16 intensity = 0; // color1 / color2
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
341
engines/twine/parser/entity.cpp
Normal file
341
engines/twine/parser/entity.cpp
Normal file
@@ -0,0 +1,341 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "twine/parser/entity.h"
|
||||
#include "common/stream.h"
|
||||
#include "twine/resources/resources.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
bool EntityData::loadBody(Common::SeekableReadStream &stream, bool lba1) {
|
||||
EntityBody body;
|
||||
body.index = stream.readByte();
|
||||
const int64 pos = stream.pos();
|
||||
uint8 size = stream.readByte();
|
||||
body.hqrBodyIndex = (int16)stream.readUint16LE();
|
||||
if (!body.body.loadFromHQR(TwineResource(Resources::HQR_BODY_FILE, body.hqrBodyIndex), lba1)) {
|
||||
error("Failed to load body with index: %i", body.hqrBodyIndex);
|
||||
}
|
||||
const uint8 numActions = stream.readByte();
|
||||
for (uint8 i = 0U; i < numActions; ++i) {
|
||||
if ((ActionType)stream.readByte() == ActionType::ACTION_ZV) {
|
||||
body.actorBoundingBox.hasBoundingBox = true;
|
||||
body.actorBoundingBox.bbox.mins.x = stream.readSint16LE();
|
||||
body.actorBoundingBox.bbox.mins.y = stream.readSint16LE();
|
||||
body.actorBoundingBox.bbox.mins.z = stream.readSint16LE();
|
||||
body.actorBoundingBox.bbox.maxs.x = stream.readSint16LE();
|
||||
body.actorBoundingBox.bbox.maxs.y = stream.readSint16LE();
|
||||
body.actorBoundingBox.bbox.maxs.z = stream.readSint16LE();
|
||||
}
|
||||
}
|
||||
_bodies.push_back(body);
|
||||
stream.seek(pos + size);
|
||||
return !stream.err();
|
||||
}
|
||||
|
||||
bool EntityData::loadAnim(Common::SeekableReadStream &stream, bool lba1) {
|
||||
EntityAnim anim;
|
||||
if (lba1) {
|
||||
anim.animation = (AnimationTypes)stream.readByte();
|
||||
} else {
|
||||
anim.animation = (AnimationTypes)stream.readUint16LE();
|
||||
}
|
||||
const int64 pos = stream.pos();
|
||||
uint8 size = stream.readByte();
|
||||
anim.animIndex = stream.readSint16LE();
|
||||
const uint8 numActions = stream.readByte();
|
||||
for (uint8 i = 0U; i < numActions; ++i) {
|
||||
EntityAnim::Action action;
|
||||
action.type = (ActionType)stream.readByte();
|
||||
switch (action.type) {
|
||||
case ActionType::ACTION_HITTING:
|
||||
action.animFrame = stream.readByte();
|
||||
action.strength = stream.readByte();
|
||||
break;
|
||||
case ActionType::ACTION_SAMPLE:
|
||||
action.animFrame = stream.readByte();
|
||||
action.sampleIndex = stream.readSint16LE();
|
||||
break;
|
||||
case ActionType::ACTION_SAMPLE_FREQ:
|
||||
action.animFrame = stream.readByte();
|
||||
action.sampleIndex = stream.readSint16LE();
|
||||
action.frequency = stream.readSint16LE();
|
||||
break;
|
||||
case ActionType::ACTION_THROW_MAGIC_BALL:
|
||||
action.animFrame = stream.readByte();
|
||||
action.yHeight = stream.readSint16LE();
|
||||
action.xAngle = ToAngle(stream.readSint16LE());
|
||||
action.xRotPoint = stream.readSint16LE();
|
||||
action.extraAngle = stream.readByte();
|
||||
break;
|
||||
case ActionType::ACTION_SAMPLE_REPEAT:
|
||||
action.animFrame = stream.readByte();
|
||||
action.sampleIndex = stream.readSint16LE();
|
||||
action.repeat = stream.readSint16LE();
|
||||
if (!lba1) {
|
||||
action.decal = stream.readSint16LE();
|
||||
action.sampleVolume = stream.readByte();
|
||||
action.frequency = stream.readSint16LE();
|
||||
}
|
||||
break;
|
||||
case ActionType::ACTION_THROW_SEARCH:
|
||||
action.animFrame = stream.readByte();
|
||||
action.yHeight = stream.readSint16LE();
|
||||
action.spriteIndex = stream.readByte();
|
||||
action.targetActor = stream.readByte();
|
||||
action.finalAngle = stream.readSint16LE();
|
||||
action.strength = stream.readByte();
|
||||
break;
|
||||
case ActionType::ACTION_THROW_EXTRA_BONUS:
|
||||
case ActionType::ACTION_THROW_ALPHA:
|
||||
action.animFrame = stream.readByte();
|
||||
action.yHeight = stream.readSint16LE();
|
||||
action.spriteIndex = stream.readByte();
|
||||
action.xAngle = ToAngle(stream.readSint16LE());
|
||||
action.yAngle = ToAngle(stream.readSint16LE());
|
||||
action.xRotPoint = stream.readSint16LE();
|
||||
// TODO: does lba2 need a scaling here for xRotPoint?
|
||||
action.extraAngle = ToAngle(stream.readByte());
|
||||
action.strength = stream.readByte();
|
||||
break;
|
||||
case ActionType::ACTION_LEFT_STEP:
|
||||
case ActionType::ACTION_RIGHT_STEP:
|
||||
case ActionType::ACTION_HERO_HITTING:
|
||||
action.animFrame = stream.readByte();
|
||||
break;
|
||||
case ActionType::ACTION_SAMPLE_STOP:
|
||||
action.animFrame = stream.readByte();
|
||||
if (lba1) {
|
||||
action.sampleIndex = stream.readByte();
|
||||
stream.skip(1);
|
||||
} else {
|
||||
action.sampleIndex = stream.readUint16LE();
|
||||
}
|
||||
break;
|
||||
case ActionType::ACTION_THROW_3D:
|
||||
case ActionType::ACTION_THROW_3D_ALPHA:
|
||||
action.animFrame = stream.readByte();
|
||||
action.distanceX = stream.readSint16LE();
|
||||
action.distanceY = stream.readSint16LE();
|
||||
action.distanceZ = stream.readSint16LE();
|
||||
action.spriteIndex = stream.readByte();
|
||||
action.xAngle = ToAngle(stream.readSint16LE());
|
||||
action.yAngle = ToAngle(stream.readSint16LE());
|
||||
action.xRotPoint = stream.readSint16LE();
|
||||
action.extraAngle = ToAngle(stream.readByte());
|
||||
action.strength = stream.readByte();
|
||||
break;
|
||||
case ActionType::ACTION_THROW_3D_SEARCH:
|
||||
action.animFrame = stream.readByte();
|
||||
action.distanceX = stream.readSint16LE();
|
||||
action.distanceY = stream.readSint16LE();
|
||||
action.distanceZ = stream.readSint16LE();
|
||||
action.spriteIndex = stream.readByte();
|
||||
action.targetActor = stream.readByte();
|
||||
action.finalAngle = ToAngle(stream.readSint16LE());
|
||||
action.strength = stream.readByte();
|
||||
break;
|
||||
case ActionType::ACTION_THROW_3D_MAGIC:
|
||||
action.animFrame = stream.readByte();
|
||||
action.distanceX = stream.readSint16LE();
|
||||
action.distanceY = stream.readSint16LE();
|
||||
action.distanceZ = stream.readSint16LE();
|
||||
action.xAngle = stream.readSint16LE();
|
||||
action.yAngle = stream.readSint16LE();
|
||||
action.finalAngle = stream.readByte();
|
||||
break;
|
||||
case ActionType::ACTION_ZV:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!lba1) {
|
||||
switch (action.type) {
|
||||
case ActionType::ACTION_ZV:
|
||||
action.animFrame = stream.readByte();
|
||||
action.bbox.mins.x = stream.readSint16LE();
|
||||
action.bbox.mins.y = stream.readSint16LE();
|
||||
action.bbox.mins.z = stream.readSint16LE();
|
||||
action.bbox.maxs.x = stream.readSint16LE();
|
||||
action.bbox.maxs.y = stream.readSint16LE();
|
||||
action.bbox.maxs.z = stream.readSint16LE();
|
||||
break;
|
||||
case ActionType::ACTION_SUPER_HIT:
|
||||
action.animFrame = stream.readByte();
|
||||
action.strength = stream.readByte();
|
||||
action.superHitX = stream.readSint16LE();
|
||||
action.superHitY = stream.readSint16LE();
|
||||
action.superHitZ = stream.readSint16LE();
|
||||
action.sizeSuperHit = stream.readSint16LE();
|
||||
break;
|
||||
case ActionType::ACTION_THROW_OBJ_3D:
|
||||
action.animFrame = stream.readByte();
|
||||
action.distanceX = stream.readSint16LE();
|
||||
action.distanceY = stream.readSint16LE();
|
||||
action.distanceZ = stream.readSint16LE();
|
||||
action.spriteIndex = stream.readByte();
|
||||
action.xAngle = ToAngle(stream.readSint16LE());
|
||||
action.yAngle = ToAngle(stream.readSint16LE());
|
||||
action.xRotPoint = stream.readSint16LE();
|
||||
action.extraAngle = ToAngle(stream.readByte());
|
||||
action.strength = stream.readByte();
|
||||
break;
|
||||
case ActionType::ACTION_NEW_SAMPLE:
|
||||
action.animFrame = stream.readByte();
|
||||
action.sampleIndex = stream.readSint16LE();
|
||||
action.decal = stream.readSint16LE();
|
||||
action.sampleVolume = stream.readByte();
|
||||
action.frequency = stream.readSint16LE();
|
||||
break;
|
||||
case ActionType::ACTION_THROW_DART:
|
||||
action.animFrame = stream.readByte();
|
||||
action.distanceY = stream.readSint16LE();
|
||||
action.xAngle = ToAngle(stream.readSint16LE());
|
||||
action.speed = stream.readSint16LE();
|
||||
action.weight = stream.readSByte();
|
||||
break;
|
||||
case ActionType::ACTION_SHIELD:
|
||||
action.animFrame = stream.readByte();
|
||||
action.lastAnimFrame = stream.readByte();
|
||||
break;
|
||||
case ActionType::ACTION_FLOW_3D:
|
||||
case ActionType::ACTION_THROW_3D_CONQUE:
|
||||
action.animFrame = stream.readByte();
|
||||
action.xAngle = ToAngle(stream.readSint16LE());
|
||||
action.yHeight = stream.readSint16LE();
|
||||
action.yAngle = ToAngle(stream.readSint16LE());
|
||||
action.spriteIndex = stream.readByte();
|
||||
break;
|
||||
case ActionType::ACTION_IMPACT:
|
||||
case ActionType::ACTION_RENVOYABLE:
|
||||
action.animFrame = stream.readByte();
|
||||
action.strength = stream.readSint16LE();
|
||||
break;
|
||||
case ActionType::ACTION_SCALE:
|
||||
action.animFrame = stream.readByte();
|
||||
action.scale = stream.readSint32LE();
|
||||
break;
|
||||
case ActionType::ACTION_IMPACT_3D:
|
||||
action.animFrame = stream.readByte();
|
||||
action.xAngle = ToAngle(stream.readSint16LE());
|
||||
action.yHeight = stream.readSint16LE();
|
||||
action.yAngle = ToAngle(stream.readSint16LE());
|
||||
action.spriteIndex = stream.readSint16LE();
|
||||
break;
|
||||
case ActionType::ACTION_THROW_MAGIC_EXTRA:
|
||||
action.animFrame = stream.readByte();
|
||||
action.pointIndex = stream.readSint16LE();
|
||||
action.spriteIndex = stream.readByte();
|
||||
action.xAngle = ToAngle(stream.readSint16LE());
|
||||
action.speed = stream.readSint16LE();
|
||||
action.weight = stream.readSByte();
|
||||
break;
|
||||
case ActionType::ACTION_ZV_ANIMIT:
|
||||
case ActionType::ACTION_RENVOIE:
|
||||
case ActionType::ACTION_TRANSPARENT:
|
||||
case ActionType::ACTION_SAMPLE_MAGIC:
|
||||
case ActionType::ACTION_LEFT_JUMP:
|
||||
case ActionType::ACTION_RIGHT_JUMP:
|
||||
case ActionType::ACTION_THROW_FOUDRE:
|
||||
action.animFrame = stream.readByte();
|
||||
/* empty */
|
||||
break;
|
||||
case ActionType::ACTION_PATH:
|
||||
case ActionType::ACTION_FLOW:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (action.type > ActionType::ACTION_THROW_FOUDRE) {
|
||||
error("Unknown action type %d", (int)action.type);
|
||||
}
|
||||
anim._actions.push_back(action);
|
||||
}
|
||||
_animations.push_back(anim);
|
||||
stream.seek(pos + size);
|
||||
return !stream.err();
|
||||
}
|
||||
|
||||
void EntityData::reset() {
|
||||
_animations.clear();
|
||||
_bodies.clear();
|
||||
}
|
||||
|
||||
bool EntityData::loadFromStream(Common::SeekableReadStream &stream, bool lba1) {
|
||||
reset();
|
||||
do {
|
||||
const uint8 opcode = stream.readByte();
|
||||
if (opcode == 1) {
|
||||
if (!loadBody(stream, lba1)) {
|
||||
return false;
|
||||
}
|
||||
} else if (opcode == 3) {
|
||||
if (!loadAnim(stream, lba1)) {
|
||||
return false;
|
||||
}
|
||||
} else if (opcode == 0xFF) {
|
||||
break;
|
||||
}
|
||||
} while (!stream.eos() && !stream.err());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const Common::Array<EntityAnim::Action> *EntityData::getActions(AnimationTypes animation) const {
|
||||
for (const EntityAnim &anim : _animations) {
|
||||
if (anim.animation == animation) {
|
||||
if (anim._actions.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &anim._actions;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BodyData &EntityData::getBody(int index) {
|
||||
for (EntityBody &body : _bodies) {
|
||||
if (body.index == index) {
|
||||
return body.body;
|
||||
}
|
||||
}
|
||||
error("Could not find body for index: %i", index);
|
||||
}
|
||||
|
||||
const EntityBody *EntityData::getEntityBody(const int index) const {
|
||||
for (const EntityBody &body : _bodies) {
|
||||
if (body.index == index) {
|
||||
return &body;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int32 EntityData::getAnimIndex(AnimationTypes animation) const {
|
||||
for (const EntityAnim &anim : _animations) {
|
||||
if (anim.animation == animation) {
|
||||
return anim.animIndex;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // End of namespace TwinE
|
||||
119
engines/twine/parser/entity.h
Normal file
119
engines/twine/parser/entity.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWINE_PARSER_ENTITY_H
|
||||
#define TWINE_PARSER_ENTITY_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/stream.h"
|
||||
#include "twine/parser/body.h"
|
||||
#include "twine/parser/parser.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
struct EntityBody {
|
||||
int index; /**< index in file3d.hqr */
|
||||
ActorBoundingBox actorBoundingBox;
|
||||
int hqrBodyIndex; /**< index in body.hqr */
|
||||
BodyData body;
|
||||
};
|
||||
|
||||
struct EntityAnim {
|
||||
AnimationTypes animation;
|
||||
int animIndex;
|
||||
|
||||
struct Action {
|
||||
ActionType type = ActionType::ACTION_NOP;
|
||||
uint8 animFrame = 0;
|
||||
uint8 lastAnimFrame = 0;
|
||||
int8 weight = 0;
|
||||
byte sampleVolume = 0;
|
||||
int16 pointIndex = 0;
|
||||
int16 spriteIndex = 0;
|
||||
uint8 targetActor = 0;
|
||||
int16 sampleIndex = 0;
|
||||
int16 frequency = 0;
|
||||
int16 xAngle = 0;
|
||||
int16 yAngle = 0;
|
||||
int16 xRotPoint = 0;
|
||||
int16 extraAngle = 0;
|
||||
int16 finalAngle = 0;
|
||||
int16 strength = 0;
|
||||
int16 distanceX = 0;
|
||||
int16 distanceY = 0;
|
||||
int16 distanceZ = 0;
|
||||
int16 yHeight = 0;
|
||||
int16 repeat = 0;
|
||||
int16 speed = 0;
|
||||
int16 superHitX = 0;
|
||||
int16 superHitY = 0;
|
||||
int16 superHitZ = 0;
|
||||
int16 sizeSuperHit = 0;
|
||||
int16 decal = 0;
|
||||
int32 scale = 0;
|
||||
BoundingBox bbox;
|
||||
};
|
||||
|
||||
Common::Array<Action> _actions;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Associate 3d models from body hqr with animations from anim.hqr for the game characters
|
||||
*/
|
||||
class EntityData : public Parser {
|
||||
private:
|
||||
Common::Array<EntityBody> _bodies;
|
||||
Common::Array<EntityAnim> _animations;
|
||||
|
||||
bool loadBody(Common::SeekableReadStream &stream, bool lba1);
|
||||
bool loadAnim(Common::SeekableReadStream &stream, bool lba1);
|
||||
|
||||
protected:
|
||||
void reset() override;
|
||||
|
||||
public:
|
||||
bool loadFromStream(Common::SeekableReadStream &stream, bool lba1) override;
|
||||
|
||||
const Common::Array<EntityAnim::Action> *getActions(AnimationTypes animation) const;
|
||||
const EntityBody *getEntityBody(const int index) const;
|
||||
BodyData &getBody(int index);
|
||||
int32 getAnimIndex(AnimationTypes animation) const;
|
||||
|
||||
const Common::Array<EntityBody> &getBodies() const {
|
||||
return _bodies;
|
||||
}
|
||||
const Common::Array<EntityAnim> &getAnimations() const {
|
||||
return _animations;
|
||||
}
|
||||
|
||||
Common::Array<EntityBody> &getBodies() {
|
||||
return _bodies;
|
||||
}
|
||||
Common::Array<EntityAnim> &getAnimations() {
|
||||
return _animations;
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace TwinE
|
||||
|
||||
#endif
|
||||
54
engines/twine/parser/holomap.cpp
Normal file
54
engines/twine/parser/holomap.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "twine/parser/holomap.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
void TrajectoryData::reset() {
|
||||
_trajectories.clear();
|
||||
}
|
||||
|
||||
bool TrajectoryData::loadFromStream(Common::SeekableReadStream &stream, bool lba1) {
|
||||
reset();
|
||||
_trajectories.reserve(100); // this is the lba1 amount of trajectories
|
||||
while (stream.pos() < stream.size()) {
|
||||
Trajectory data;
|
||||
data.locationIdx = stream.readSint16LE();
|
||||
data.trajLocationIdx = stream.readSint16LE();
|
||||
data.vehicleIdx = stream.readSint16LE();
|
||||
data.angle.x = stream.readSint16LE();
|
||||
data.angle.y = stream.readSint16LE();
|
||||
data.angle.z = stream.readSint16LE();
|
||||
data.numAnimFrames = stream.readSint16LE();
|
||||
assert(data.numAnimFrames < ARRAYSIZE(data.positions));
|
||||
for (int32 i = 0; i < data.numAnimFrames; ++i) {
|
||||
data.positions[i].x = stream.readSint16LE();
|
||||
data.positions[i].y = stream.readSint16LE();
|
||||
}
|
||||
_trajectories.push_back(data);
|
||||
}
|
||||
return !stream.err();
|
||||
}
|
||||
|
||||
} // End of namespace TwinE
|
||||
94
engines/twine/parser/holomap.h
Normal file
94
engines/twine/parser/holomap.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWINE_PARSER_HOLOMAP_H
|
||||
#define TWINE_PARSER_HOLOMAP_H
|
||||
|
||||
#include "common/memstream.h"
|
||||
#include "twine/parser/parser.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
enum HolomapVehicle {
|
||||
FerryBoat = 31,
|
||||
Motorbike = 33,
|
||||
Car = 35,
|
||||
FishingBoat = 37,
|
||||
Catamaran = 39,
|
||||
Hovercraft = 41,
|
||||
Dino = 43,
|
||||
ArmyBoat = 45,
|
||||
HamalayiTransporter = 47
|
||||
};
|
||||
|
||||
struct TrajectoryPos {
|
||||
int16 x = 0;
|
||||
int16 y = 0;
|
||||
};
|
||||
|
||||
struct Trajectory {
|
||||
int16 locationIdx = -1;
|
||||
int16 trajLocationIdx = -1;
|
||||
int16 vehicleIdx = -1;
|
||||
IVec3 angle;
|
||||
int16 numAnimFrames = 0;
|
||||
TrajectoryPos positions[512];
|
||||
|
||||
bool isValid() const {
|
||||
return locationIdx != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The HQR index of the vehicle model for the holomap
|
||||
* @note Multiplied by 2 because the model index is always followed by the corresponding animation index for that model
|
||||
*/
|
||||
int32 getModel() const {
|
||||
return 2 * vehicleIdx + HolomapVehicle::FerryBoat;
|
||||
}
|
||||
|
||||
int32 getAnimation() const {
|
||||
return getModel() + 1;
|
||||
}
|
||||
};
|
||||
|
||||
class TrajectoryData : public Parser {
|
||||
private:
|
||||
Common::Array<Trajectory> _trajectories;
|
||||
protected:
|
||||
void reset() override;
|
||||
public:
|
||||
bool loadFromStream(Common::SeekableReadStream &stream, bool lba1) override;
|
||||
|
||||
const Trajectory *getTrajectory(uint index) const {
|
||||
if (index >= _trajectories.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &_trajectories[index];
|
||||
}
|
||||
|
||||
const Common::Array<Trajectory> &getTrajectories() const {
|
||||
return _trajectories;
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace TwinE
|
||||
|
||||
#endif
|
||||
52
engines/twine/parser/parser.cpp
Normal file
52
engines/twine/parser/parser.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "twine/parser/parser.h"
|
||||
#include "common/stream.h"
|
||||
#include "twine/resources/hqr.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
bool Parser::loadFromBuffer(const uint8 *buf, uint32 size, bool lba1) {
|
||||
if (size == 0) {
|
||||
return false;
|
||||
}
|
||||
Common::MemoryReadStream stream(buf, size);
|
||||
return loadFromStream(stream, lba1);
|
||||
}
|
||||
|
||||
bool Parser::loadFromHQR(const char *name, int index, bool lba1) {
|
||||
Common::SeekableReadStream *stream = HQR::makeReadStream(name, index);
|
||||
if (stream == nullptr) {
|
||||
warning("Failed to load %s with index %i", name, index);
|
||||
return false;
|
||||
}
|
||||
if (!loadFromStream(*stream, lba1)) {
|
||||
delete stream;
|
||||
return false;
|
||||
}
|
||||
_hqrIndex = index;
|
||||
delete stream;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace TwinE
|
||||
56
engines/twine/parser/parser.h
Normal file
56
engines/twine/parser/parser.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWINE_PARSER_PARSER_H
|
||||
#define TWINE_PARSER_PARSER_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/stream.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
class Parser {
|
||||
protected:
|
||||
int _hqrIndex = -1;
|
||||
virtual void reset() {}
|
||||
public:
|
||||
virtual ~Parser() {
|
||||
reset();
|
||||
}
|
||||
virtual bool loadFromStream(Common::SeekableReadStream &stream, bool lba1) = 0;
|
||||
|
||||
bool loadFromBuffer(const uint8 *buf, uint32 size, bool lba1);
|
||||
bool loadFromHQR(const char *name, int index, bool lba1);
|
||||
|
||||
int hqrIndex() const {
|
||||
return _hqrIndex;
|
||||
}
|
||||
|
||||
inline bool loadFromHQR(const TwineResource &resource, bool lba1) {
|
||||
return loadFromHQR(resource.hqr, resource.index, lba1);
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace TwinE
|
||||
|
||||
#endif
|
||||
118
engines/twine/parser/sprite.cpp
Normal file
118
engines/twine/parser/sprite.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "twine/parser/sprite.h"
|
||||
#include "common/stream.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
bool SpriteBoundingBoxData::loadFromStream(Common::SeekableReadStream &stream, bool lba1) {
|
||||
const int32 size = stream.size();
|
||||
const int32 amount = size / 16;
|
||||
for (int32 i = 0; i < amount; ++i) {
|
||||
SpriteDim spriteDim;
|
||||
spriteDim.x = stream.readSint16LE();
|
||||
spriteDim.y = stream.readSint16LE();
|
||||
BoundingBox boundingBox;
|
||||
boundingBox.mins.x = stream.readSint16LE();
|
||||
boundingBox.maxs.x = stream.readSint16LE();
|
||||
boundingBox.mins.y = stream.readSint16LE();
|
||||
boundingBox.maxs.y = stream.readSint16LE();
|
||||
boundingBox.mins.z = stream.readSint16LE();
|
||||
boundingBox.maxs.z = stream.readSint16LE();
|
||||
_boundingBoxes.push_back(boundingBox);
|
||||
_dimensions.push_back(spriteDim);
|
||||
}
|
||||
return !stream.err();
|
||||
}
|
||||
|
||||
void SpriteData::reset() {
|
||||
for (int i = 0; i < _sprites; ++i) {
|
||||
_surfaces[i].free();
|
||||
}
|
||||
_sprites = 0;
|
||||
}
|
||||
|
||||
bool SpriteData::loadFromStream(Common::SeekableReadStream &stream, bool lba1) {
|
||||
reset();
|
||||
if (_bricks) {
|
||||
// brick sprites don't have the offsets
|
||||
return loadSprite(stream, 0);
|
||||
}
|
||||
const uint32 offset1 = stream.readUint32LE();
|
||||
const uint32 offset2 = stream.readUint32LE();
|
||||
const uint32 offsetData = stream.pos();
|
||||
if (!loadSprite(stream, offset1)) {
|
||||
return false;
|
||||
}
|
||||
// for most sprites the second offset is just the end of the stream - but
|
||||
// some sprites (like shadow in lba1) have a second sprite following the
|
||||
// first one.
|
||||
if (offset2 + offsetData >= stream.size()) {
|
||||
return true;
|
||||
}
|
||||
return loadSprite(stream, offset2);
|
||||
}
|
||||
|
||||
bool SpriteData::loadSprite(Common::SeekableReadStream &stream, uint32 offset) {
|
||||
stream.seek(offset);
|
||||
int width = stream.readByte();
|
||||
int height = stream.readByte();
|
||||
_offsetX[_sprites] = stream.readByte();
|
||||
_offsetY[_sprites] = stream.readByte();
|
||||
const Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8();
|
||||
_surfaces[_sprites].create(width, height, format);
|
||||
const uint8 *last = (const uint8 *)_surfaces[_sprites].getBasePtr(width, height - 1);
|
||||
for (int y = 0; y < height; ++y) {
|
||||
const uint8 numRuns = stream.readByte();
|
||||
int x = 0;
|
||||
for (uint8 run = 0; run < numRuns; ++run) {
|
||||
const uint8 runSpec = stream.readByte();
|
||||
const uint8 runLength = bits(runSpec, 0, 6) + 1;
|
||||
const uint8 type = bits(runSpec, 6, 2);
|
||||
if (type == 1) {
|
||||
uint8 *start = (uint8 *)_surfaces[_sprites].getBasePtr(x, y);
|
||||
for (uint8 i = 0; i < runLength; ++i) {
|
||||
if (start > last) {
|
||||
return false;
|
||||
}
|
||||
*start++ = stream.readByte();
|
||||
}
|
||||
} else if (type != 0) {
|
||||
uint8 *start = (uint8 *)_surfaces[_sprites].getBasePtr(x, y);
|
||||
uint8 *end = (uint8 *)_surfaces[_sprites].getBasePtr(x + runLength, y);
|
||||
if (end > last) {
|
||||
return false;
|
||||
}
|
||||
Common::fill(start, end, stream.readByte());
|
||||
}
|
||||
x += runLength;
|
||||
}
|
||||
}
|
||||
if (stream.err()) {
|
||||
return false;
|
||||
}
|
||||
++_sprites;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace TwinE
|
||||
116
engines/twine/parser/sprite.h
Normal file
116
engines/twine/parser/sprite.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWINE_PARSER_SPRITE_H
|
||||
#define TWINE_PARSER_SPRITE_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/stream.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "twine/parser/parser.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
struct SpriteDim {
|
||||
int16 x = 0;
|
||||
int16 y = 0;
|
||||
int16 w = 0;
|
||||
int16 h = 0;
|
||||
};
|
||||
|
||||
// PtrZvExtra
|
||||
class SpriteBoundingBoxData : public Parser {
|
||||
private:
|
||||
Common::Array<BoundingBox> _boundingBoxes;
|
||||
Common::Array<SpriteDim> _dimensions;
|
||||
|
||||
public:
|
||||
bool loadFromStream(Common::SeekableReadStream &stream, bool lba1) override;
|
||||
|
||||
const BoundingBox *bbox(int index) const; // PtrZvAnim3DS, PtrZvExtra, PtrZvExtraRaw
|
||||
const SpriteDim *dim(int index) const;
|
||||
};
|
||||
|
||||
inline const BoundingBox *SpriteBoundingBoxData::bbox(int index) const {
|
||||
if (index < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return &_boundingBoxes[index];
|
||||
}
|
||||
|
||||
inline const SpriteDim *SpriteBoundingBoxData::dim(int index) const {
|
||||
if (index < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return &_dimensions[index];
|
||||
}
|
||||
|
||||
class SpriteData : public Parser {
|
||||
protected:
|
||||
Graphics::ManagedSurface _surfaces[2];
|
||||
int _offsetX[2] {0};
|
||||
int _offsetY[2] {0};
|
||||
int _sprites = 0;
|
||||
bool _bricks = false;
|
||||
|
||||
bool loadSprite(Common::SeekableReadStream &stream, uint32 offset);
|
||||
void reset() override;
|
||||
public:
|
||||
bool loadFromStream(Common::SeekableReadStream &stream, bool lba1) override;
|
||||
|
||||
inline const Graphics::ManagedSurface &surface(int index = 0) const {
|
||||
if (index < 0 || index >= _sprites) {
|
||||
error("Sprite surface index out of range: %i (max: %i)", index, _sprites);
|
||||
}
|
||||
return _surfaces[index];
|
||||
}
|
||||
|
||||
inline int sprites() const {
|
||||
return _sprites;
|
||||
}
|
||||
|
||||
inline int offsetX(int index = 0) const {
|
||||
if (index < 0 || index >= _sprites) {
|
||||
error("Sprite offset index out of range: %i (max: %i)", index, _sprites);
|
||||
}
|
||||
return _offsetX[index];
|
||||
}
|
||||
|
||||
inline int offsetY(int index = 0) const {
|
||||
if (index < 0 || index >= _sprites) {
|
||||
error("Sprite offset index out of range: %i (max: %i)", index, _sprites);
|
||||
}
|
||||
return _offsetY[index];
|
||||
}
|
||||
};
|
||||
|
||||
class BrickData : public SpriteData {
|
||||
public:
|
||||
BrickData() {
|
||||
_bricks = true;
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace TwinE
|
||||
|
||||
#endif
|
||||
107
engines/twine/parser/text.cpp
Normal file
107
engines/twine/parser/text.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "twine/parser/text.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/str-enc.h"
|
||||
#include "common/util.h"
|
||||
#include "common/translation.h"
|
||||
#include "twine/resources/hqr.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
void TextData::initCustomTexts(TextBankId textBankId) {
|
||||
if (textBankId == TextBankId::Options_and_menus) {
|
||||
// TODO: add resource file for these custom strings to support other languages
|
||||
add(textBankId, TextEntry{Common::U32String("High resolution on").encode(Common::CodePage::kDos850), -1, TextId::kCustomHighResOptionOn});
|
||||
add(textBankId, TextEntry{Common::U32String("High resolution off").encode(Common::CodePage::kDos850), -1, TextId::kCustomHighResOptionOff});
|
||||
add(textBankId, TextEntry{Common::U32String("Wall collision on").encode(Common::CodePage::kDos850), -1, TextId::kCustomWallCollisionOn});
|
||||
add(textBankId, TextEntry{Common::U32String("Wall collision off").encode(Common::CodePage::kDos850), -1, TextId::kCustomWallCollisionOff});
|
||||
add(textBankId, TextEntry{Common::U32String("Language selection").encode(Common::CodePage::kDos850), -1, TextId::kCustomLanguageOption});
|
||||
add(textBankId, TextEntry{Common::U32String("Voices: None").encode(Common::CodePage::kDos850), -1, TextId::kCustomVoicesNone});
|
||||
add(textBankId, TextEntry{Common::U32String("Voices: English").encode(Common::CodePage::kDos850), -1, TextId::kCustomVoicesEnglish});
|
||||
add(textBankId, TextEntry{Common::U32String("Voices: French").encode(Common::CodePage::kDos850), -1, TextId::kCustomVoicesFrench});
|
||||
add(textBankId, TextEntry{Common::U32String("Voices: German").encode(Common::CodePage::kDos850), -1, TextId::kCustomVoicesGerman});
|
||||
}
|
||||
}
|
||||
|
||||
bool TextData::loadFromHQR(const char *name, TextBankId textBankId, int language, bool lba1, int entryCount) {
|
||||
const int langIdx = (int)textBankId * 2 + (entryCount * language);
|
||||
Common::SeekableReadStream *indexStream = HQR::makeReadStream(name, langIdx + 0);
|
||||
Common::SeekableReadStream *offsetStream = HQR::makeReadStream(name, langIdx + 1);
|
||||
if (indexStream == nullptr || offsetStream == nullptr) {
|
||||
warning("Failed to load %s with index %i", name, langIdx);
|
||||
delete indexStream;
|
||||
delete offsetStream;
|
||||
return false;
|
||||
}
|
||||
|
||||
_texts[(int)textBankId].clear();
|
||||
initCustomTexts(textBankId);
|
||||
|
||||
const int numIdxEntries = (int)indexStream->size() / 2;
|
||||
_texts[(int)textBankId].reserve(numIdxEntries + _texts[(int)textBankId].size());
|
||||
|
||||
for (int entry = 0; entry < numIdxEntries; ++entry) {
|
||||
const TextId textIdx = (TextId)indexStream->readUint16LE();
|
||||
uint16 start = offsetStream->readUint16LE();
|
||||
const int32 offsetPos = offsetStream->pos();
|
||||
const uint16 end = offsetStream->readUint16LE();
|
||||
|
||||
if (!lba1) {
|
||||
++start;
|
||||
}
|
||||
offsetStream->seek(start);
|
||||
Common::String result;
|
||||
for (int16 i = start; i < end - 1; ++i) {
|
||||
const char c = (char)offsetStream->readByte();
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
result += c;
|
||||
}
|
||||
add(textBankId, TextEntry{result, entry, textIdx});
|
||||
debugC(2, TwinE::kDebugResources, "index: %i (bank %i), text: %s", (int)textIdx, (int)textBankId, result.c_str());
|
||||
offsetStream->seek(offsetPos);
|
||||
if (end >= offsetStream->size()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete indexStream;
|
||||
delete offsetStream;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const TextEntry *TextData::getText(TextBankId textBankId, TextId textIndex) const {
|
||||
const Common::Array<TextEntry> &entries = _texts[(int)textBankId];
|
||||
const int32 size = entries.size();
|
||||
for (int32 i = 0; i < size; ++i) {
|
||||
if (entries[i].textIndex == textIndex) {
|
||||
return &entries[i];
|
||||
}
|
||||
}
|
||||
debugC(1, TwinE::kDebugResources, "Failed to find text entry for bank id %i with text index %i", (int)textBankId, (int)textIndex);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace TwinE
|
||||
58
engines/twine/parser/text.h
Normal file
58
engines/twine/parser/text.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWINE_PARSER_TEXT_H
|
||||
#define TWINE_PARSER_TEXT_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/stream.h"
|
||||
#include "twine/parser/parser.h"
|
||||
#include "twine/shared.h"
|
||||
|
||||
namespace TwinE {
|
||||
|
||||
class TextEntry {
|
||||
public:
|
||||
Common::String string; /**< The real string behind the text id */
|
||||
int index; /**< The index in the text index hqr file. This is also the index in the corresponding vox hqr file */
|
||||
TextId textIndex; /**< The text identifier */
|
||||
};
|
||||
|
||||
class TextData {
|
||||
private:
|
||||
// 30 is the max for lba2, lba1 uses 28
|
||||
Common::Array<TextEntry> _texts[30];
|
||||
void add(TextBankId textBankId, const TextEntry &entry) {
|
||||
_texts[(int)textBankId].push_back(entry);
|
||||
}
|
||||
|
||||
// custom texts that are not included in the original game
|
||||
void initCustomTexts(TextBankId textBankId);
|
||||
public:
|
||||
bool loadFromHQR(const char *name, TextBankId textBankId, int language, bool lba1, int entryCount);
|
||||
|
||||
const TextEntry *getText(TextBankId textBankId, TextId textIndex) const;
|
||||
};
|
||||
|
||||
} // End of namespace TwinE
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user