STARTREK: Implement fixed-point decimal class

This commit is contained in:
Matthew Stewart 2018-07-18 23:53:21 -04:00 committed by Eugene Sandulenko
parent a024a3fd45
commit ac9cd1f00a
11 changed files with 417 additions and 111 deletions

View file

@ -105,9 +105,9 @@ void StarTrekEngine::loadRoom(const Common::String &missionName, int roomIndex)
actorFunc1(); actorFunc1();
initActors(); initActors();
double num = _room->getVar0c() - _room->getVar0a(); Fixed16 num = _room->getMaxScale() - _room->getMinScale();
double den = _room->getVar06() - _room->getVar08() + 1; int16 den = _room->getMaxY() - _room->getMinY() + 1;
_playerActorScale = (int32)(num * 256 / den); _playerActorScale = Fixed32(num) / den;
// TODO: RDF vars 1e/1f and 20/21; relates to BAN files? // TODO: RDF vars 1e/1f and 20/21; relates to BAN files?
@ -446,21 +446,21 @@ void StarTrekEngine::unloadRoom() {
* further up (away) the object is, the smaller it is. * further up (away) the object is, the smaller it is.
*/ */
int StarTrekEngine::loadActorAnimWithRoomScaling(int actorIndex, const Common::String &animName, int16 x, int16 y) { int StarTrekEngine::loadActorAnimWithRoomScaling(int actorIndex, const Common::String &animName, int16 x, int16 y) {
uint16 scale = getActorScaleAtPosition(y); Fixed16 scale = getActorScaleAtPosition(y);
return loadActorAnim(actorIndex, animName, x, y, scale); return loadActorAnim(actorIndex, animName, x, y, scale);
} }
uint16 StarTrekEngine::getActorScaleAtPosition(int16 y) { Fixed16 StarTrekEngine::getActorScaleAtPosition(int16 y) {
int16 var06 = _room->getVar06(); int16 maxY = _room->getMaxY();
int16 var08 = _room->getVar08(); int16 minY = _room->getMinY();
int16 var0a = _room->getVar0a(); Fixed16 minScale = _room->getMinScale();
if (var06 < y) if (y > maxY)
y = var06; y = maxY;
if (var08 > y) if (y < minY)
y = var08; y = minY;
return ((_playerActorScale * (y - var08)) >> 8) + var0a; return Fixed16(_playerActorScale * (y - minY)) + minScale;
} }
SharedPtr<Room> StarTrekEngine::getRoom() { SharedPtr<Room> StarTrekEngine::getRoom() {

View file

@ -23,6 +23,7 @@
#define STARTREK_COMMON_H #define STARTREK_COMMON_H
#include "common/scummsys.h" #include "common/scummsys.h"
#include "common/textconsole.h"
namespace Common { namespace Common {
struct Rect; struct Rect;
@ -41,12 +42,6 @@ Common::Rect getRectEncompassing(Common::Rect r1, Common::Rect r2);
void serializeRect(Common::Rect rect, Common::Serializer &ser); void serializeRect(Common::Rect rect, Common::Serializer &ser);
// Fixed-point (16.16) number
typedef int32 Fixed32;
// Fixed-point (8.8) number
typedef int16 Fixed16;
} }
#endif #endif

152
engines/startrek/fixedint.h Normal file
View file

@ -0,0 +1,152 @@
/* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef STARTREK_FIXEDINT_H
#define STARTREK_FIXEDINT_H
#include "common/serializer.h"
#include "startrek/common.h"
namespace StarTrek {
/**
* Signed fixed-point number.
*/
template<typename T, uint totalBits, uint decimalBits>
class TFixedInt : Common::Serializable {
const static int max = (1 << (totalBits - decimalBits - 1)) - 1;
const static int min = -max - 1;
T val;
public:
static TFixedInt fromRaw(T raw) {
TFixedInt ret;
ret.val = raw;
return ret;
}
TFixedInt() : val(0) {}
TFixedInt(double d) {
assert(d >= min && d <= max); // FIXME: downgrade this to a warning?
val = (T)(d * (1 << decimalBits));
}
/**
* Constructor from other fixed-point formats.
*/
template<typename T2, uint otherTB, uint otherDB>
TFixedInt<T, totalBits, decimalBits>(const TFixedInt<T2, otherTB, otherDB> &fi) {
int diff = otherDB - decimalBits;
if (otherDB >= decimalBits)
val = fi.raw() >> diff;
else
val = fi.raw() << (-diff);
}
T raw() const {
return val;
}
int16 toInt() const {
return val >> decimalBits;
}
double toDouble() const {
return ((double)val) / (1 << decimalBits);
}
/**
* Multiplication with an int, with the result being an int.
*/
int32 multToInt(int32 i) {
return ((val * i) << (totalBits - decimalBits)) >> totalBits;
}
/**
* Multiplication with an int, with the result being the same type.
*/
TFixedInt operator*(int32 i) const {
return fromRaw(val * i);
}
/**
* Division with an int, with the result being the same type.
*/
TFixedInt operator/(int32 i) const {
return fromRaw(val / i);
}
TFixedInt operator+(const TFixedInt &f) const {
return fromRaw(val + f.val);
}
TFixedInt operator-(const TFixedInt &f) const {
return fromRaw(val - f.val);
}
void operator+=(const TFixedInt &f) {
val += f.val;
}
void operator-=(const TFixedInt &f) {
val -= f.val;
}
bool operator==(double d) const {
return toDouble() == d;
}
bool operator!=(double d) const {
return toDouble() != d;
}
bool operator<(double d) const {
return toDouble() < d;
}
bool operator<=(double d) const {
return toDouble() <= d;
}
void saveLoadWithSerializer(Common::Serializer &ser) {
if (totalBits == 16)
ser.syncAsSint16LE(val);
else if (totalBits == 32)
ser.syncAsSint32LE(val);
else
error("Unsupported bit size for TFixedInt");
}
};
template<typename T, uint totalBits, uint decimalBits>
int32 operator*(const int16 lhs, const TFixedInt<T, totalBits, decimalBits> &rhs) {
return rhs * lhs;
}
// Fixed-point (2.14) number (between -1 and 1)
typedef TFixedInt<int16, 16, 14> Fixed14;
// Fixed-point (8.8) number
typedef TFixedInt<int16, 16, 8> Fixed16;
// Fixed-point (16.16) number
typedef TFixedInt<int32, 32, 16> Fixed32;
}
#endif

View file

@ -24,6 +24,7 @@
#define STARTREK_OBJECT_H #define STARTREK_OBJECT_H
#include "startrek/common.h" #include "startrek/common.h"
#include "startrek/fixedint.h"
#include "startrek/items.h" #include "startrek/items.h"
#include "startrek/sprite.h" #include "startrek/sprite.h"

View file

@ -210,7 +210,7 @@ void Room::loadActorAnim(int actorIndex, Common::String anim, int16 x, int16 y,
if (actorIndex >= 0 && actorIndex < SCALED_ACTORS_END) if (actorIndex >= 0 && actorIndex < SCALED_ACTORS_END)
_vm->loadActorAnimWithRoomScaling(actorIndex, anim, x, y); _vm->loadActorAnimWithRoomScaling(actorIndex, anim, x, y);
else else
_vm->loadActorAnim(actorIndex, anim, x, y, 256); _vm->loadActorAnim(actorIndex, anim, x, y, 1.0);
if (finishedAnimActionParam != 0) { if (finishedAnimActionParam != 0) {
actor->triggerActionWhenAnimFinished = true; actor->triggerActionWhenAnimFinished = true;
@ -231,7 +231,7 @@ void Room::loadActorAnimC(int actorIndex, Common::String anim, int16 x, int16 y,
if (actorIndex >= 0 && actorIndex < SCALED_ACTORS_END) if (actorIndex >= 0 && actorIndex < SCALED_ACTORS_END)
_vm->loadActorAnimWithRoomScaling(actorIndex, anim, x, y); _vm->loadActorAnimWithRoomScaling(actorIndex, anim, x, y);
else else
_vm->loadActorAnim(actorIndex, anim, x, y, 256); _vm->loadActorAnim(actorIndex, anim, x, y, 1.0);
if (funcPtr != nullptr) { if (funcPtr != nullptr) {
actor->triggerActionWhenAnimFinished = true; actor->triggerActionWhenAnimFinished = true;

View file

@ -27,6 +27,7 @@
#include "common/ptr.h" #include "common/ptr.h"
#include "common/str.h" #include "common/str.h"
#include "startrek/fixedint.h"
#include "startrek/startrek.h" #include "startrek/startrek.h"
#include "startrek/text.h" #include "startrek/text.h"
@ -60,11 +61,13 @@ public:
// Helper stuff for RDF access // Helper stuff for RDF access
uint16 readRdfWord(int offset); uint16 readRdfWord(int offset);
// Scale-related stuff (rename these later) // Scale-related stuff; at the "min Y" position or below, the crewmembers have
uint16 getVar06() { return readRdfWord(0x06); } // "minimum" scale; that value rises to the "max scale" value by the time they reach
uint16 getVar08() { return readRdfWord(0x08); } // the "max Y" value.
uint16 getVar0a() { return readRdfWord(0x0a); } uint16 getMaxY() { return readRdfWord(0x06); }
uint16 getVar0c() { return readRdfWord(0x0c); } uint16 getMinY() { return readRdfWord(0x08); }
Fixed16 getMinScale() { return Fixed16::fromRaw(readRdfWord(0x0a)); }
Fixed16 getMaxScale() { return Fixed16::fromRaw(readRdfWord(0x0c)); }
// words 0x0e and 0x10 in RDF file are pointers to start and end of event code. // words 0x0e and 0x10 in RDF file are pointers to start and end of event code.
// That code is instead rewritten on a per-room basis. // That code is instead rewritten on a per-room basis.

View file

@ -256,7 +256,7 @@ bool StarTrekEngine::saveOrLoadGameData(Common::SeekableReadStream *in, Common::
a->sprite.saveLoadWithSerializer(ser); a->sprite.saveLoadWithSerializer(ser);
ser.syncBytes((byte *)a->bitmapFilename, 10); ser.syncBytes((byte *)a->bitmapFilename, 10);
ser.syncAsUint16LE(a->scale); a->scale.saveLoadWithSerializer(ser);
// Can't save "animFile" (will be reloaded) // Can't save "animFile" (will be reloaded)
ser.syncAsUint16LE(a->numAnimFrames); ser.syncAsUint16LE(a->numAnimFrames);
ser.syncAsUint16LE(a->animFrame); ser.syncAsUint16LE(a->animFrame);
@ -274,10 +274,10 @@ bool StarTrekEngine::saveOrLoadGameData(Common::SeekableReadStream *in, Common::
ser.syncAsUint16LE(a->field76); ser.syncAsUint16LE(a->field76);
ser.syncAsSint16LE(a->iwSrcPosition); ser.syncAsSint16LE(a->iwSrcPosition);
ser.syncAsSint16LE(a->iwDestPosition); ser.syncAsSint16LE(a->iwDestPosition);
ser.syncAsSint32LE(a->granularPosX); a->granularPosX.saveLoadWithSerializer(ser);
ser.syncAsSint32LE(a->granularPosY); a->granularPosY.saveLoadWithSerializer(ser);
ser.syncAsSint32LE(a->speedX); a->speedX.saveLoadWithSerializer(ser);
ser.syncAsSint32LE(a->speedY); a->speedY.saveLoadWithSerializer(ser);
ser.syncAsSint16LE(a->dest.x); ser.syncAsSint16LE(a->dest.x);
ser.syncAsSint16LE(a->dest.y); ser.syncAsSint16LE(a->dest.y);
ser.syncAsUint16LE(a->field90); ser.syncAsUint16LE(a->field90);

View file

@ -26,8 +26,8 @@
namespace StarTrek { namespace StarTrek {
void StarTrekEngine::initStarfieldPosition() { void StarTrekEngine::initStarfieldPosition() {
memset(&_starfieldPosition, 0, sizeof(_starfieldPosition)); _starfieldPosition = Point3(0, 0, 0);
// TODO: matrix initialization _someMatrix = initMatrix();
} }
void StarTrekEngine::initStarfield(int16 x, int16 y, int16 width, int16 height, int16 arg8) { void StarTrekEngine::initStarfield(int16 x, int16 y, int16 width, int16 height, int16 arg8) {
@ -45,13 +45,35 @@ void StarTrekEngine::initStarfield(int16 x, int16 y, int16 width, int16 height,
_starfieldPointDivisor = 150; _starfieldPointDivisor = 150;
} }
void StarTrekEngine::addR3(R3 *r3) {
for (int i = 0; i < NUM_SPACE_OBJECTS; i++) {
if (_r3List[i] == nullptr) {
_r3List[i] = r3;
return;
}
}
error("addR3: out of shapes.");
}
void StarTrekEngine::delR3(R3 *r3) {
for (int i = 0; i < NUM_SPACE_OBJECTS; i++) {
if (_r3List[i] == r3) {
_r3List[i] = nullptr;
r3->field1e = 0;
return;
}
}
error("delR3: shape not found.");
}
void StarTrekEngine::clearStarfieldPixels() { void StarTrekEngine::clearStarfieldPixels() {
_gfx->fillBackgroundRect(_starfieldRect, 0); _gfx->fillBackgroundRect(_starfieldRect, 0);
} }
void StarTrekEngine::drawStarfield() { void StarTrekEngine::drawStarfield() {
// TODO: make these class variables // TODO: make these class variables
Point3W starPositionWeightings[] = {{0x4000, 0, 0}, {0, 0x4000, 0}, {0, 0, 0x4000}};
float flt_50898 = 50.0; // ? float flt_50898 = 50.0; // ?
int16 var28 = ((_starfieldXVar2 * 3) >> 1); int16 var28 = ((_starfieldXVar2 * 3) >> 1);
@ -72,12 +94,12 @@ void StarTrekEngine::drawStarfield() {
int16 var4 = getRandomWord() / var28 - xvar; int16 var4 = getRandomWord() / var28 - xvar;
int16 var6 = getRandomWord() / var2a - yvar; int16 var6 = getRandomWord() / var2a - yvar;
Point3 point = constructPoint3ForStarfield(var4, var6, var8); Point3 point = constructPoint3ForStarfield(var4, var6, var8);
star->pos = applyPointWeightings(starPositionWeightings, point) + _starfieldPosition; star->pos = matrixMult(_starPositionMatrix, point) + _starfieldPosition;
star->active = true; star->active = true;
} }
Point3 p = star->pos - _starfieldPosition; Point3 p = star->pos - _starfieldPosition;
Point3 point2 = applyPointWeightings2(p, starPositionWeightings); Point3 point2 = matrixMult(p, _starPositionMatrix);
if (point2.z > flt_50898 && point2.z < 0x3fff if (point2.z > flt_50898 && point2.z < 0x3fff
&& abs(point2.x) < point2.z && abs(point2.y) < point2.z) { && abs(point2.x) < point2.z && abs(point2.y) < point2.z) {
@ -111,7 +133,7 @@ void StarTrekEngine::drawStarfield() {
void StarTrekEngine::updateStarfieldAndShips(bool arg0) { void StarTrekEngine::updateStarfieldAndShips(bool arg0) {
_starfieldSprite.bitmapChanged = true; _starfieldSprite.bitmapChanged = true;
// sub_24b74(...); _starPositionMatrix = _someMatrix.invert();
clearStarfieldPixels(); clearStarfieldPixels();
drawStarfield(); drawStarfield();
@ -127,28 +149,32 @@ Point3 StarTrekEngine::constructPoint3ForStarfield(int16 x, int16 y, int16 z) {
return point; return point;
} }
Point3 StarTrekEngine::applyPointWeightings(Point3W *weight, const Point3 &point) { Point3 StarTrekEngine::matrixMult(const Matrix &weight, const Point3 &point) {
int32 ret[3]; int32 ret[3];
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
ret[i] = weight[i].x * (point.x & 0xffff) + weight[i].y * (point.y & 0xffff) + weight[i].z * (point.z & 0xffff); ret[i] = weight[i][0].multToInt(point.x & 0xffff) + weight[i][1].multToInt(point.y & 0xffff) + weight[i][2].multToInt(point.z & 0xffff);
ret[i] <<= 2;
} }
Point3 p; Point3 p;
p.x = ret[0] >> 16; p.x = ret[0];
p.y = ret[1] >> 16; p.y = ret[1];
p.z = ret[2] >> 16; p.z = ret[2];
return p; return p;
} }
Point3 StarTrekEngine::applyPointWeightings2(const Point3 &point, Point3W *weight) { Point3 StarTrekEngine::matrixMult(const Point3 &point, const Matrix &weight) {
Point3 p = Point3(); Point3 p = Point3();
p.x = (weight[0].x * (point.x & 0xffff) + weight[1].x * (point.y & 0xffff) + weight[2].x * (point.z & 0xffff)) << 2; p.x = (weight[0][0].multToInt(point.x & 0xffff) + weight[1][0].multToInt(point.y & 0xffff) + weight[2][0].multToInt(point.z & 0xffff));
p.y = (weight[0].y * (point.x & 0xffff) + weight[1].y * (point.y & 0xffff) + weight[2].y * (point.z & 0xffff)) << 2; p.y = (weight[0][1].multToInt(point.x & 0xffff) + weight[1][1].multToInt(point.y & 0xffff) + weight[2][1].multToInt(point.z & 0xffff));
p.z = (weight[0].z * (point.x & 0xffff) + weight[1].z * (point.y & 0xffff) + weight[2].z * (point.z & 0xffff)) << 2; p.z = (weight[0][2].multToInt(point.x & 0xffff) + weight[1][2].multToInt(point.y & 0xffff) + weight[2][2].multToInt(point.z & 0xffff));
p.x >>= 16;
p.y >>= 16;
p.z >>= 16;
return p; return p;
} }
Matrix StarTrekEngine::initMatrix() {
Matrix mat;
mat[0][0] = 1;
mat[1][1] = 1;
mat[2][2] = 1;
return mat;
}
} }

View file

@ -1,32 +1,113 @@
// Pseudo-3D structs /* 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 2
* of the License, or (at your option) any later version.
struct Point3 { * This program is distributed in the hope that it will be useful,
int32 x; * but WITHOUT ANY WARRANTY; without even the implied warranty of
int32 y; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
int32 z; * GNU General Public License for more details.
Point3 operator+(const Point3 &p) const { * You should have received a copy of the GNU General Public License
Point3 p2; * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef STARTREK_SPACE_H
#define STARTREK_SPACE_H
#include "fixedint.h"
namespace StarTrek {
class FileStream;
template<typename T>
struct TPoint {
T x;
T y;
T z;
TPoint() : x(0), y(0), z(0) {}
TPoint(T _x, T _y, T _z) : x(_x), y(_y), z(_z) {}
TPoint<T> operator+(const TPoint<T> &p) const {
TPoint<T> p2;
p2.x = x + p.x; p2.x = x + p.x;
p2.y = y + p.y; p2.y = y + p.y;
p2.z = z + p.z; p2.z = z + p.z;
return p2; return p2;
} }
Point3 operator-(const Point3 &p) const { TPoint<T> operator-(const TPoint<T> &p) const {
Point3 p2; TPoint<T> p2;
p2.x = x - p.x; p2.x = x - p.x;
p2.y = y - p.y; p2.y = y - p.y;
p2.z = z - p.z; p2.z = z - p.z;
return p2; return p2;
} }
T &operator[](int i) {
if (i == 0)
return x;
else if (i == 1)
return y;
else if (i == 2)
return z;
assert(false);
}
T operator[](int i) const {
if (i == 0)
return x;
else if (i == 1)
return y;
else if (i == 2)
return z;
assert(false);
}
}; };
struct Point3W { typedef TPoint<int32> Point3;
int16 x; typedef TPoint<Fixed14> Point3W;
int16 y;
int16 z;
template<typename T>
struct TMatrix {
private:
T m[3];
public:
TMatrix() {}
TMatrix(const TMatrix<T> &mat) {
m[0] = mat.m[0];
m[1] = mat.m[1];
m[2] = mat.m[2];
}
T &operator[](int i) {
return m[i];
};
T operator[](int i) const {
return m[i];
};
TMatrix<T> invert() {
TMatrix<T> ret;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
ret[i][j] = m[j][i];
}
}
return ret;
}
}; };
typedef TMatrix<Point3W> Matrix;
struct Star { struct Star {
bool active; bool active;
Point3 pos; Point3 pos;
@ -37,6 +118,10 @@ struct Star {
struct R3 { struct R3 {
Point3 pos; // 0x0 Point3 pos; // 0x0
int16 field1e; // 0x1e int16 field1e; // 0x1e
int16 field20; // 0x20
int16 field22; // 0x22
int16 field24; // 0x24
SharedPtr<FileStream> shpFile; // 0x68
}; };
// Maximum number of stars visible at once in the starfields // Maximum number of stars visible at once in the starfields
@ -44,3 +129,7 @@ struct R3 {
// Maximum number of R3 objects in space at once // Maximum number of R3 objects in space at once
#define NUM_SPACE_OBJECTS 0x30 #define NUM_SPACE_OBJECTS 0x30
}
#endif

View file

@ -217,6 +217,10 @@ void StarTrekEngine::playIntro() {
_starfieldSprite.bitmap = fakeStarfieldBitmap; _starfieldSprite.bitmap = fakeStarfieldBitmap;
initStarfieldSprite(&_starfieldSprite, fakeStarfieldBitmap, _starfieldRect); initStarfieldSprite(&_starfieldSprite, fakeStarfieldBitmap, _starfieldRect);
//delR3(&_enterpriseR3); // TODO: uncomment
R3 planetR3 = R3();
// TODO: remainder of starfield initialization // TODO: remainder of starfield initialization
_gfx->clearScreenAndPriBuffer(); _gfx->clearScreenAndPriBuffer();
@ -312,8 +316,26 @@ void StarTrekEngine::playIntro() {
loadSubtitleSprite(1, &subtitleSprite); loadSubtitleSprite(1, &subtitleSprite);
break; break;
case 42: case 42: // Enterprise moves toward camera
loadSubtitleSprite(-1, &subtitleSprite); loadSubtitleSprite(-1, &subtitleSprite);
addR3(&_enterpriseR3);
_enterpriseR3.field1e = 2;
initIntroR3ObjectToMove(&_enterpriseR3, 330, 5000, 0, 0, 18);
break;
case 60: // Enterprise moves away from camera
initIntroR3ObjectToMove(&_enterpriseR3, 0, 0, 30, 5000, 6);
break;
case 66: // Cut to scene with planet
loadSubtitleSprite(2, &subtitleSprite);
planetR3.field22 = 2000;
planetR3.field24 = 10000 / _starfieldPointDivisor;
planetR3.shpFile = loadFile("planet.shp");
initIntroR3ObjectToMove(&planetR3, 6, 10000, 6, 10000, 0);
addR3(&planetR3);
initIntroR3ObjectToMove(&_enterpriseR3, -15, 250, 15, 500, 18);
starfieldZoomSpeed = 0;
break; break;
case 378: case 378:
@ -344,6 +366,11 @@ void StarTrekEngine::playIntro() {
// TODO: the rest // TODO: the rest
} }
void StarTrekEngine::initIntroR3ObjectToMove(R3 *r3, int16 srcAngle, int16 srcDepth, int16 destAngle, int16 destDepth, int16 ticks) {
srcAngle = (srcAngle << 9) / 180;
destAngle = (destAngle << 9) / 180;
}
void StarTrekEngine::loadSubtitleSprite(int index, Sprite *sprite) { void StarTrekEngine::loadSubtitleSprite(int index, Sprite *sprite) {
if (_showSubtitles) { if (_showSubtitles) {
if (index == -1) if (index == -1)
@ -379,25 +406,25 @@ void StarTrekEngine::runTransportSequence(const Common::String &name) {
Common::String filename = getCrewmanAnimFilename(i, name); Common::String filename = getCrewmanAnimFilename(i, name);
int x = crewmanTransportPositions[i][0]; int x = crewmanTransportPositions[i][0];
int y = crewmanTransportPositions[i][1]; int y = crewmanTransportPositions[i][1];
loadActorAnim(i, filename, x, y, 256); loadActorAnim(i, filename, x, y, 1.0);
_actorList[i].animationString[0] = '\0'; _actorList[i].animationString[0] = '\0';
} }
if (_missionToLoad.equalsIgnoreCase("feather") && name[4] == 'b') { if (_missionToLoad.equalsIgnoreCase("feather") && name[4] == 'b') {
loadActorAnim(9, "qteleb", 0x61, 0x79, 0x100); loadActorAnim(9, "qteleb", 0x61, 0x79, 1.0);
} }
else if (_missionToLoad.equalsIgnoreCase("trial")) { else if (_missionToLoad.equalsIgnoreCase("trial")) {
if (name[4] == 'd') { if (name[4] == 'd') {
loadActorAnim(9, "qteled", 0x61, 0x79, 0x100); loadActorAnim(9, "qteled", 0x61, 0x79, 1.0);
} }
/* TODO /* TODO
else if (word_51156 >= 3) { else if (word_51156 >= 3) {
loadActorAnim(9, "qteleb", 0x61, 0x79, 0x100); loadActorAnim(9, "qteleb", 0x61, 0x79, 1.0);
} }
*/ */
} }
loadActorAnim(8, "transc", 0, 0, 0x100); loadActorAnim(8, "transc", 0, 0, 1.0);
// TODO: redraw mouse and sprite_52c4e? // TODO: redraw mouse and sprite_52c4e?
@ -570,7 +597,7 @@ bool StarTrekEngine::actorWalkToPosition(int actorIndex, const Common::String &a
if (directPathExists(srcX, srcY, destX, destY)) { if (directPathExists(srcX, srcY, destX, destY)) {
chooseActorDirectionForWalking(actor, srcX, srcY, destX, destY); chooseActorDirectionForWalking(actor, srcX, srcY, destX, destY);
updateActorPositionWhileWalking(actor, (actor->granularPosX + 0x8000) >> 16, (actor->granularPosY + 0x8000) >> 16); updateActorPositionWhileWalking(actor, (actor->granularPosX + 0.5).toInt(), (actor->granularPosY + 0.5).toInt());
return true; return true;
} }
else { else {
@ -590,7 +617,7 @@ bool StarTrekEngine::actorWalkToPosition(int actorIndex, const Common::String &a
else { else {
Common::Point iwSrc = _iwFile->_keyPositions[actor->iwSrcPosition]; Common::Point iwSrc = _iwFile->_keyPositions[actor->iwSrcPosition];
chooseActorDirectionForWalking(actor, srcX, srcY, iwSrc.x, iwSrc.y); chooseActorDirectionForWalking(actor, srcX, srcY, iwSrc.x, iwSrc.y);
updateActorPositionWhileWalking(actor, (actor->granularPosX + 0x8000) >> 16, (actor->granularPosY + 0x8000) >> 16); updateActorPositionWhileWalking(actor, (actor->granularPosX + 0.5).toInt(), (actor->granularPosY + 0.5).toInt());
return true; return true;
} }
} }
@ -660,7 +687,7 @@ void StarTrekEngine::updateActorAnimations() {
if (actor->field90 != 0) { if (actor->field90 != 0) {
Sprite *sprite = &actor->sprite; Sprite *sprite = &actor->sprite;
int loops; int loops;
if (getActorScaleAtPosition((actor->granularPosY + 0x8000) >> 16) < 0xa0) if (getActorScaleAtPosition((actor->granularPosY + 0.5).toInt()) < 0.625)
loops = 1; loops = 1;
else else
loops = 2; loops = 2;
@ -668,11 +695,11 @@ void StarTrekEngine::updateActorAnimations() {
if (actor->field90 == 0) if (actor->field90 == 0)
break; break;
actor->field90--; actor->field90--;
uint32 newX = actor->granularPosX + actor->speedX; Fixed32 newX = actor->granularPosX + actor->speedX;
uint32 newY = actor->granularPosY + actor->speedY; Fixed32 newY = actor->granularPosY + actor->speedY;
if ((actor->field90 & 3) == 0) { if ((actor->field90 & 3) == 0) {
sprite->bitmap.reset(); sprite->bitmap.reset();
updateActorPositionWhileWalking(actor, (newX + 0x8000) >> 16, (newY + 0x8000) >> 16); updateActorPositionWhileWalking(actor, (newX + 0.5).toInt(), (newY + 0.5).toInt());
actor->field92++; actor->field92++;
} }
@ -689,7 +716,7 @@ void StarTrekEngine::updateActorAnimations() {
} }
actor->sprite.bitmap.reset(); actor->sprite.bitmap.reset();
updateActorPositionWhileWalking(actor, (actor->granularPosX + 0x8000) >> 16, (actor->granularPosY + 0x8000) >> 16); updateActorPositionWhileWalking(actor, (actor->granularPosX + 0.5).toInt(), (actor->granularPosY + 0.5).toInt());
initStandAnim(i); initStandAnim(i);
} }
else { // actor->iwSrcPosition != -1 else { // actor->iwSrcPosition != -1
@ -834,7 +861,7 @@ void StarTrekEngine::initStandAnim(int actorIndex) {
else // Default to facing south else // Default to facing south
animName = Common::String(actor->animationString) + 's'; animName = Common::String(actor->animationString) + 's';
uint16 scale = getActorScaleAtPosition(actor->pos.y); Fixed16 scale = getActorScaleAtPosition(actor->pos.y);
loadActorAnim(actorIndex, animName, actor->pos.x, actor->pos.y, scale); loadActorAnim(actorIndex, animName, actor->pos.x, actor->pos.y, scale);
actor->animType = 0; actor->animType = 0;
} }
@ -863,8 +890,8 @@ void StarTrekEngine::updateActorPositionWhileWalking(Actor *actor, int16 x, int1
* a destination position it's walking to. * a destination position it's walking to.
*/ */
void StarTrekEngine::chooseActorDirectionForWalking(Actor *actor, int16 srcX, int16 srcY, int16 destX, int16 destY) { void StarTrekEngine::chooseActorDirectionForWalking(Actor *actor, int16 srcX, int16 srcY, int16 destX, int16 destY) {
actor->granularPosX = srcX << 16; actor->granularPosX = srcX;
actor->granularPosY = srcY << 16; actor->granularPosY = srcY;
int16 distX = destX - srcX; int16 distX = destX - srcX;
int16 distY = destY - srcY; int16 distY = destY - srcY;
@ -887,11 +914,11 @@ void StarTrekEngine::chooseActorDirectionForWalking(Actor *actor, int16 srcX, in
if (distX != 0) { if (distX != 0) {
if (distX > 0) if (distX > 0)
actor->speedX = 1 << 16; actor->speedX = 1.0;
else else
actor->speedX = -1 << 16; // 0xffff0000 actor->speedX = -1.0;
actor->speedY = (distY << 16) / absDistX; actor->speedY = Fixed32(distY) / absDistX;
} }
} }
else { else {
@ -910,11 +937,11 @@ void StarTrekEngine::chooseActorDirectionForWalking(Actor *actor, int16 srcX, in
if (distY != 0) { if (distY != 0) {
if (distY > 0) if (distY > 0)
actor->speedY = 1 << 16; actor->speedY = 1.0;
else else
actor->speedY = -1 << 16; // 0xffff0000 actor->speedY = -1.0;
actor->speedX = (distX << 16) / absDistY; actor->speedX = Fixed32(distX) / absDistY;
} }
} }
} }
@ -939,12 +966,12 @@ bool StarTrekEngine::directPathExists(int16 srcX, int16 srcY, int16 destX, int16
if (distCounter == 0) if (distCounter == 0)
return true; return true;
speedY = (distY << 16) / absDistX; speedY = Fixed32(distY) / absDistX;
if (distX > 0) if (distX > 0)
speedX = 1 << 16; speedX = 1.0;
else else
speedX = -1 << 16; speedX = -1.0;
} }
else { // absDistX <= absDistY else { // absDistX <= absDistY
distCounter = absDistY; distCounter = absDistY;
@ -952,25 +979,25 @@ bool StarTrekEngine::directPathExists(int16 srcX, int16 srcY, int16 destX, int16
if (distCounter == 0) if (distCounter == 0)
return true; return true;
speedX = (distX << 16) / absDistY; speedX = Fixed32(distX) / absDistY;
if (distY > 0) if (distY > 0)
speedY = 1 << 16; speedY = 1.0;
else else
speedY = -1 << 16; speedY = -1.0;
} }
Fixed32 fixedX = srcX << 16; Fixed32 fixedX = srcX;
Fixed32 fixedY = srcY << 16; Fixed32 fixedY = srcY;
if (isPositionSolid((fixedX + 0x8000) >> 16, (fixedY + 0x8000) >> 16)) if (isPositionSolid((fixedX + 0.5).toInt(), (fixedY + 0.5).toInt()))
return false; return false;
while (distCounter-- > 0) { while (distCounter-- > 0) {
fixedX += speedX; fixedX += speedX;
fixedY += speedY; fixedY += speedY;
if (isPositionSolid((fixedX + 0x8000) >> 16, (fixedY + 0x8000) >> 16)) if (isPositionSolid((fixedX + 0.5).toInt(), (fixedY + 0.5).toInt()))
return false; return false;
} }
@ -1119,7 +1146,7 @@ SharedPtr<Bitmap> StarTrekEngine::loadAnimationFrame(const Common::String &filen
bitmapToReturn = _gfx->loadBitmap(filename); bitmapToReturn = _gfx->loadBitmap(filename);
} }
if (scale != 256) { if (scale != 1.0) {
bitmapToReturn = scaleBitmap(bitmapToReturn, scale); bitmapToReturn = scaleBitmap(bitmapToReturn, scale);
} }
@ -1454,7 +1481,7 @@ void StarTrekEngine::updateCrewmanGetupTimers() {
} }
else { else {
const char *dirs = "nsew"; const char *dirs = "nsew";
uint16 scale = getActorScaleAtPosition(actor->sprite.pos.y); Fixed16 scale = getActorScaleAtPosition(actor->sprite.pos.y);
d = dirs[dir]; d = dirs[dir];
int16 xOffset = 0, yOffset = 0; int16 xOffset = 0, yOffset = 0;
@ -1466,8 +1493,8 @@ void StarTrekEngine::updateCrewmanGetupTimers() {
xOffset = -35; xOffset = -35;
yOffset = -12; yOffset = -12;
} }
actor->sprite.pos.x += (scale * xOffset) >> 8; actor->sprite.pos.x += scale.multToInt(xOffset);
actor->sprite.pos.y += (scale * yOffset) >> 8; actor->sprite.pos.y += scale.multToInt(yOffset);
} }
anim += (char)d; anim += (char)d;
@ -1652,12 +1679,9 @@ void StarTrekEngine::initStarfieldSprite(Sprite *sprite, SharedPtr<Bitmap> bitma
sprite->drawMode = 1; sprite->drawMode = 1;
} }
/**
* A scale of 256 is the baseline.
*/
SharedPtr<Bitmap> StarTrekEngine::scaleBitmap(SharedPtr<Bitmap> bitmap, Fixed16 scale) { SharedPtr<Bitmap> StarTrekEngine::scaleBitmap(SharedPtr<Bitmap> bitmap, Fixed16 scale) {
int scaledWidth = (bitmap->width * scale) >> 8; int scaledWidth = scale.multToInt(bitmap->width);
int scaledHeight = (bitmap->height * scale) >> 8; int scaledHeight = scale.multToInt(bitmap->height);
int origWidth = bitmap->width; int origWidth = bitmap->width;
int origHeight = bitmap->height; int origHeight = bitmap->height;
@ -1667,8 +1691,8 @@ SharedPtr<Bitmap> StarTrekEngine::scaleBitmap(SharedPtr<Bitmap> bitmap, Fixed16
scaledHeight = 1; scaledHeight = 1;
SharedPtr<Bitmap> scaledBitmap(new Bitmap(scaledWidth, scaledHeight)); SharedPtr<Bitmap> scaledBitmap(new Bitmap(scaledWidth, scaledHeight));
scaledBitmap->xoffset = (bitmap->xoffset * scale) >> 8; scaledBitmap->xoffset = scale.multToInt(bitmap->xoffset);
scaledBitmap->yoffset = (bitmap->yoffset * scale) >> 8; scaledBitmap->yoffset = scale.multToInt(bitmap->yoffset);
// sub_344a5(scaledWidth, origWidth); // sub_344a5(scaledWidth, origWidth);
@ -1678,7 +1702,7 @@ SharedPtr<Bitmap> StarTrekEngine::scaleBitmap(SharedPtr<Bitmap> bitmap, Fixed16
byte *src = bitmap->pixels; byte *src = bitmap->pixels;
byte *dest = scaledBitmap->pixels; byte *dest = scaledBitmap->pixels;
if (scale <= 256) { if (scale <= 1.0) {
int16 var2e = 0; int16 var2e = 0;
uint16 var30 = scaledHeight << 1; uint16 var30 = scaledHeight << 1;
uint16 var32 = (scaledHeight - origHeight) << 1; uint16 var32 = (scaledHeight - origHeight) << 1;

View file

@ -222,7 +222,7 @@ public:
void handleAwayMissionEvents(); void handleAwayMissionEvents();
void unloadRoom(); void unloadRoom();
int loadActorAnimWithRoomScaling(int actorIndex, const Common::String &animName, int16 x, int16 y); int loadActorAnimWithRoomScaling(int actorIndex, const Common::String &animName, int16 x, int16 y);
uint16 getActorScaleAtPosition(int16 y); Fixed16 getActorScaleAtPosition(int16 y);
void addAction(const Action &action); void addAction(const Action &action);
void addAction(byte type, byte b1, byte b2, byte b3); void addAction(byte type, byte b1, byte b2, byte b3);
bool checkItemInteractionExists(int action, int activeItem, int passiveItem, int16 arg6); bool checkItemInteractionExists(int action, int activeItem, int passiveItem, int16 arg6);
@ -240,18 +240,30 @@ public:
private: private:
// Intro // Intro
void playIntro(); void playIntro();
/**
* Initializes an object to spawn at one position and move toward another position.
* @param ticks The number of ticks it should take for the object to reach the destination
*/
void initIntroR3ObjectToMove(R3 *r3, int16 srcAngle, int16 srcDepth, int16 destAngle, int16 destDepth, int16 ticks);
void loadSubtitleSprite(int index, Sprite *sprite); void loadSubtitleSprite(int index, Sprite *sprite);
// Space, pseudo-3D (space.cpp) // Space, pseudo-3D (space.cpp)
void initStarfieldPosition(); void initStarfieldPosition();
void initStarfield(int16 x, int16 y, int16 width, int16 height, int16 arg8); void initStarfield(int16 x, int16 y, int16 width, int16 height, int16 arg8);
void addR3(R3 *r3);
void delR3(R3 *r3);
void clearStarfieldPixels(); void clearStarfieldPixels();
void drawStarfield(); void drawStarfield();
void updateStarfieldAndShips(bool arg0); void updateStarfieldAndShips(bool arg0);
Point3 constructPoint3ForStarfield(int16 x, int16 y, int16 z); Point3 constructPoint3ForStarfield(int16 x, int16 y, int16 z);
Point3 applyPointWeightings(Point3W *weight, const Point3 &point); Point3 matrixMult(const Matrix &weight, const Point3 &point);
Point3 applyPointWeightings2(const Point3 &point, Point3W *weight); Point3 matrixMult(const Point3 &point, const Matrix &weight);
/**
* Creates something like an "identity" matrix? (Value 0x4000 along the diagonal)
*/
Matrix initMatrix();
// Transporter room // Transporter room
void runTransportSequence(const Common::String &name); void runTransportSequence(const Common::String &name);
@ -447,7 +459,7 @@ public:
Common::String _screenName; // _screenName = _missionName + _roomIndex Common::String _screenName; // _screenName = _missionName + _roomIndex
Common::String _mapFilename; // Similar to _screenName, but used for .map files? Common::String _mapFilename; // Similar to _screenName, but used for .map files?
SharedPtr<FileStream> _mapFile; SharedPtr<FileStream> _mapFile;
int32 _playerActorScale; Fixed32 _playerActorScale;
Common::String _txtFilename; Common::String _txtFilename;
Common::String _loadedText; // TODO: might be OK to delete this Common::String _loadedText; // TODO: might be OK to delete this
@ -519,6 +531,10 @@ public:
int16 _starfieldXVar1, _starfieldYVar1; int16 _starfieldXVar1, _starfieldYVar1;
int16 _starfieldXVar2, _starfieldYVar2; int16 _starfieldXVar2, _starfieldYVar2;
Common::Rect _starfieldRect; Common::Rect _starfieldRect;
R3 _enterpriseR3;
R3 *_r3List[NUM_SPACE_OBJECTS];
Matrix _starPositionMatrix;
Matrix _someMatrix;
Graphics *_gfx; Graphics *_gfx;
Sound *_sound; Sound *_sound;