diff options
author | Matthew Stewart | 2018-07-23 05:36:32 -0400 |
---|---|---|
committer | Eugene Sandulenko | 2018-08-09 08:37:30 +0200 |
commit | eff87179da0554446837a732bb6855f6c7f8a890 (patch) | |
tree | 87ace1e7847dcf6d589f60a33fb5acfcdc1d91e7 /engines | |
parent | 565bf0e96750588e8a7f6816e79683e97896f8de (diff) | |
download | scummvm-rg350-eff87179da0554446837a732bb6855f6c7f8a890.tar.gz scummvm-rg350-eff87179da0554446837a732bb6855f6c7f8a890.tar.bz2 scummvm-rg350-eff87179da0554446837a732bb6855f6c7f8a890.zip |
STARTREK: Half-done implementation of drawR3Shape
Handles drawing, scaling, probably rotating objects in space.
Diffstat (limited to 'engines')
-rw-r--r-- | engines/startrek/fixedint.h | 16 | ||||
-rw-r--r-- | engines/startrek/graphics.cpp | 15 | ||||
-rw-r--r-- | engines/startrek/graphics.h | 3 | ||||
-rw-r--r-- | engines/startrek/math.cpp | 14 | ||||
-rw-r--r-- | engines/startrek/space.cpp | 398 | ||||
-rw-r--r-- | engines/startrek/space.h | 49 | ||||
-rw-r--r-- | engines/startrek/startrek.cpp | 37 | ||||
-rw-r--r-- | engines/startrek/startrek.h | 16 |
8 files changed, 512 insertions, 36 deletions
diff --git a/engines/startrek/fixedint.h b/engines/startrek/fixedint.h index 2ea6400127..65b481201b 100644 --- a/engines/startrek/fixedint.h +++ b/engines/startrek/fixedint.h @@ -56,7 +56,7 @@ public: * Constructor from other fixed-point formats. */ template<typename T2, uint otherTB, uint otherDB> - TFixedInt<T, totalBits, decimalBits>(const TFixedInt<T2, otherTB, otherDB> &fi) { + explicit TFixedInt<T, totalBits, decimalBits>(const TFixedInt<T2, otherTB, otherDB> &fi) { int diff = otherDB - decimalBits; if (otherDB >= decimalBits) val = fi.raw() >> diff; @@ -76,12 +76,16 @@ public: return ((double)val) / (1 << decimalBits); } + TFixedInt operator-() const { + return fromRaw(-val); + } + /** * Multiplication with an int, with the result being an int. Use this if the result * might exceed the capacity of this type. */ int16 multToInt(int32 i) { - return (val * i) >> decimalBits; + return ((int32)(val * i)) >> decimalBits; } /** @@ -91,6 +95,12 @@ public: return fromRaw(val * i); } /** + * Multiplication with a FixedInt, with the result being the same type. + */ + TFixedInt operator*(const TFixedInt &f) const { + return fromRaw(((int32)(val * f.val)) >> decimalBits); + } + /** * Division with an int, with the result being the same type. */ TFixedInt operator/(int32 i) const { @@ -173,6 +183,8 @@ typedef TFixedInt<int16, 16, 8> Fixed8; // Fixed-point (16.16) number typedef TFixedInt<int32, 32, 16> Fixed16; +typedef Fixed8 Angle; + } #endif diff --git a/engines/startrek/graphics.cpp b/engines/startrek/graphics.cpp index 6fe1c8f9ba..1612dc0347 100644 --- a/engines/startrek/graphics.cpp +++ b/engines/startrek/graphics.cpp @@ -105,6 +105,10 @@ void Graphics::fillBackgroundRect(const Common::Rect &rect, byte color) { } } +byte *Graphics::getBackgroundPixels() { + return _backgroundImage->pixels; +} + void Graphics::clearScreenAndPriBuffer() { Common::fill(_priData, _priData + sizeof(_priData), 0); @@ -131,6 +135,17 @@ void Graphics::loadPalette(const Common::String &paletteName) { lutStream->read(_lutData, 256); } +void Graphics::copyRectBetweenBitmaps(Bitmap *destBitmap, int destX, int destY, Bitmap *srcBitmap, int srcX, int srcY, int width, int height) { + byte *src = srcBitmap->pixels + srcX + srcY * srcBitmap->width; + byte *dest = destBitmap->pixels + destX + destY * destBitmap->width; + + for (int y = 0; y < height; y++) { + memcpy(dest, src, width); + src += srcBitmap->width; + dest += destBitmap->width; + } +} + void Graphics::fadeinScreen() { while (_paletteFadeLevel <= 100) { TrekEvent event; diff --git a/engines/startrek/graphics.h b/engines/startrek/graphics.h index a40e1fa2f4..7d48c035e6 100644 --- a/engines/startrek/graphics.h +++ b/engines/startrek/graphics.h @@ -58,10 +58,13 @@ public: * @param drawRect The clipped rectangle to draw at (must be within the drawable space) */ void drawBitmapToBackground(const Common::Rect &origRect, const Common::Rect &drawRect, SharedPtr<Bitmap> bitmap); + void fillBackgroundRect(const Common::Rect &rect, byte color); + byte *getBackgroundPixels(); void clearScreenAndPriBuffer(); void loadPalette(const String &paletteFile); + void copyRectBetweenBitmaps(Bitmap *destBitmap, int destX, int destY, Bitmap *srcBitmap, int srcX, int srcY, int width, int height); void fadeinScreen(); void fadeoutScreen(); void setPaletteFadeLevel(byte *palData, int fadeLevel); diff --git a/engines/startrek/math.cpp b/engines/startrek/math.cpp index 80aa39ee6a..da81b1fa85 100644 --- a/engines/startrek/math.cpp +++ b/engines/startrek/math.cpp @@ -24,7 +24,7 @@ namespace StarTrek { -Fixed14 StarTrekEngine::sin(Fixed8 angle) { +Fixed14 StarTrekEngine::sin(Angle angle) { int16 i = angle.raw(); if (angle < 0) { i %= 0x400; @@ -46,14 +46,14 @@ Fixed14 StarTrekEngine::sin(Fixed8 angle) { f = -_sineTable.getTable()[i & 0xff]; else if (i < 0x400) f = -_sineTable.getTable()[256 - (i & 0xff)]; - return Fixed16(f); + return Fixed14(f); } -Fixed14 StarTrekEngine::cos(Fixed8 angle) { +Fixed14 StarTrekEngine::cos(Angle angle) { return sin(angle + 1.0); } -Fixed8 StarTrekEngine::atan2(int32 deltaX, int32 deltaY) { +Angle StarTrekEngine::atan2(int32 deltaX, int32 deltaY) { const int16 atanTable[] = { 0x0000, 0x0064, 0x00c9, 0x012d, 0x0192, 0x01f6, 0x025b, 0x02c0, 0x0324, 0x0389, 0x03ee, 0x0453, 0x04b8, 0x051d, 0x0582, 0x05e8, @@ -85,9 +85,9 @@ Fixed8 StarTrekEngine::atan2(int32 deltaX, int32 deltaY) { Fixed14 ratio; if (deltaY > deltaX) - ratio = Fixed14::fromRaw(((deltaX & 0xffff0000) >> 2) / (deltaY >> 16)); + ratio = Fixed14::fromRaw(((deltaX & 0xffff0000) >> 2) / deltaY); else - ratio = Fixed14::fromRaw(((deltaY & 0xffff0000) >> 2) / (deltaX >> 16)); + ratio = Fixed14::fromRaw(((deltaY & 0xffff0000) >> 2) / deltaX); int16 endIndex = 128; int16 index = 0; @@ -123,7 +123,7 @@ Fixed8 StarTrekEngine::atan2(int32 deltaX, int32 deltaY) { angle = -256 + angle; } - return Fixed8::fromRaw(angle); + return Angle::fromRaw(angle); } } diff --git a/engines/startrek/space.cpp b/engines/startrek/space.cpp index aeb26155a6..965290d266 100644 --- a/engines/startrek/space.cpp +++ b/engines/startrek/space.cpp @@ -31,6 +31,7 @@ void StarTrekEngine::initStarfieldPosition() { } void StarTrekEngine::initStarfield(int16 x, int16 y, int16 width, int16 height, int16 arg8) { + // TODO: finish _starfieldXVar1 = (x + width) / 2; _starfieldYVar1 = (y + height) / 2; _starfieldXVar2 = (width - x + 1) / 2; @@ -43,6 +44,7 @@ void StarTrekEngine::initStarfield(int16 x, int16 y, int16 width, int16 height, memset(_starList, 0, sizeof(_starList)); _starfieldPointDivisor = 150; + _flt_50898 = 50.0; } void StarTrekEngine::addR3(R3 *r3) { @@ -73,9 +75,6 @@ void StarTrekEngine::clearStarfieldPixels() { } void StarTrekEngine::drawStarfield() { - // TODO: make these class variables - float flt_50898 = 50.0; // ? - int16 var28 = ((_starfieldXVar2 * 3) >> 1); int16 xvar = var28 / 2; int16 var2a = ((_starfieldYVar2 * 3) >> 1); @@ -101,11 +100,11 @@ void StarTrekEngine::drawStarfield() { Point3 p = star->pos - _starfieldPosition; 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) { - int16 x = _starfieldXVar1 + (point2.x * _starfieldPointDivisor / point2.z); - int16 y = _starfieldYVar1 - (point2.y * _starfieldPointDivisor / point2.z); + int16 x = _starfieldXVar1 + scaleSpacePosition(point2.x, point2.z); + int16 y = _starfieldYVar1 - scaleSpacePosition(point2.y, point2.z); int fileOffset = file->pos(); file->readUint32(); @@ -131,13 +130,371 @@ void StarTrekEngine::drawStarfield() { } } +/** + * Compare 2 r3 objects for the purpose of sorting them by layer before drawing. + * FIXME: Original returned an int, not a bool. This may affect the stability of the sort... + */ +bool compareR3Objects(R3 *obj1, R3 *obj2) { + int32 diff = obj1->field54 - obj2->field54; + if (diff < 0) + return true; + else if (diff == 0) + return false; // original would have a distinct value for this + else + return false; +} + void StarTrekEngine::updateStarfieldAndShips(bool arg0) { + bool enterpriseDestroyed = false; + _starfieldSprite.bitmapChanged = true; _starPositionMatrix = _someMatrix.invert(); clearStarfieldPixels(); drawStarfield(); - // TODO + int numObjects = 0; + for (int i = 0; i < NUM_SPACE_OBJECTS; i++) { + R3 *r3 = _r3List[i]; + if (r3 == nullptr) + continue; + r3->field34 = 0; + + switch (r3->field1e) { // TODO + case 1: + r3 = sub_19f24(r3); + break; + case 2: // TODO (specifically for the enterprise?) + break; + case 3: + r3 = sub_19f24(r3); + break; + } + + if (r3 != nullptr) + _orderedR3List[numObjects++] = r3; + } + + if (numObjects != 0) { + Common::sort(_orderedR3List, _orderedR3List + numObjects, &compareR3Objects); + + for (int i = 0; i < numObjects; i++) { + R3 *r3 = _orderedR3List[i]; + r3->field34 = 1; + + switch (r3->field1e) { // TODO + case 1: + break; + case 2: + break; + case 3: + if (r3->field20 == 1) { + // TODO + } else + drawR3Shape(r3); + break; + } + } + } + + if (enterpriseDestroyed) { + showTextbox("", "GENE\\SPACE000#The Enterprise has been destroyed!", 20, 20, TEXTCOLOR_YELLOW, 0); + showGameOverMenu(); + // FIXME: original game manipulates stack to jump somewhere... + return; + } + + // TODO: static on enterprise viewscreen? +} + +R3 *StarTrekEngine::sub_19f24(R3 *r3) { + r3->matrix2 = r3->matrix; + r3->field36 = r3->pos; + r3->field36 -= _starfieldPosition; + r3->field54 = r3->field36.getDiagonal(); + Point3 point = matrixMult(r3->field36, _starPositionMatrix); + r3->field36 = point; + + if (sub_1c022(r3)) { + if (r3->field1e >= 1 && r3->field1e <= 3) + r3->matrix2 *= _starPositionMatrix; + r3->field58 = _starfieldXVar1 + scaleSpacePosition(r3->field36.x, r3->field36.z); + r3->field5a = _starfieldYVar1 - scaleSpacePosition(r3->field36.y, r3->field36.z); + return r3; + } else + return nullptr; +} + +void StarTrekEngine::drawR3Shape(R3 *r3) { + if (r3->field1e != 3) // TODO: remove this + return; + + if (r3->funcPtr1 != nullptr) { + // TODO: call it + } + + if (r3->shpFile != nullptr) { + r3->shpFile->seek(r3->bitmapOffset, SEEK_SET); + SharedPtr<Bitmap> bitmap(new Bitmap(r3->shpFile)); + double dbl68 = ((double)r3->field24 * _starfieldPointDivisor) / r3->field36.z; + double dbl70 = 1.0 / dbl68; + + double dbl30; + double dbl28; + double dbl20; + double dbl18; + double dbl60; + double dbl58; + double dbl50; + double dbl48; + + switch (r3->field1e) { + case 1: // TODO + break; + case 3: + dbl30 = dbl68; + dbl28 = 0.0; + dbl20 = 0.0; + dbl18 = dbl68; + dbl60 = dbl70; + dbl58 = 0.0; + dbl50 = 0.0; + dbl48 = dbl70; + break; + case 4: // TODO + break; + default: // TODO + break; + } + + r3->field80 = dbl60; + r3->field88 = dbl58; + r3->field90 = dbl50; + r3->field98 = dbl48; + + // dbl30, (bitmap->xoffset + 2), r3->field58, + double tmp = r3->field58 - (double)(bitmap->xoffset + 2) * dbl30; + // dbl20, (bitmap->yoffset + 2), tmp + double dbl10 = tmp - (double)(bitmap->yoffset + 2) * dbl20; + + // dbl28, (bitmap->xoffset + 2), r3->field5a + tmp = r3->field5a - (double)(bitmap->xoffset + 2) * dbl28; + // dbl18, (bitmap->yoffset + 2), tmp + double dbl8 = tmp - (double)(bitmap->yoffset + 2) * dbl18; + + // dbl60, r3->field58, bitmap->xoffset + 2 + tmp = (bitmap->xoffset + 2) - dbl60 * r3->field58; + double dbl40 = tmp - dbl50 * r3->field5a; + + tmp = (bitmap->yoffset + 2) - dbl58 * r3->field58; + double dbl38 = tmp - dbl48 * r3->field5a; + + double dbl3e4 = bitmap->width + 2; + double dbl3ec = bitmap->height + 2; + + double thing[8]; + tmp = 1.0 * dbl30; + thing[0] = 1.0 * dbl20 + tmp + dbl10; + + tmp = 1.0 * dbl28; + thing[1] = 1.0 * dbl18 + tmp + dbl8; + + tmp = 1.0 * dbl30; + thing[2] = dbl3ec * dbl20 + tmp + dbl10; + + tmp = 1.0 * dbl28; + thing[3] = dbl3ec * dbl18 + tmp + dbl8; + + thing[4] = dbl3ec * dbl20 + dbl3e4 * dbl30 + dbl10; + thing[5] = dbl3ec * dbl18 + dbl3e4 * dbl28 + dbl8; + + thing[6] = 1.0 * dbl20 + dbl3e4 * dbl30 + dbl10; + thing[7] = 1.0 * dbl18 + dbl3e4 * dbl28 + dbl8; + + + int16 rightBounds[SCREEN_HEIGHT]; + int16 leftBounds[SCREEN_HEIGHT]; + + for (int y = _starfieldRect.top; y < _starfieldRect.bottom; y++) { + leftBounds[y] = _starfieldRect.right; + rightBounds[y] = _starfieldRect.left - 1; + } + + int16 shpImageTop = _starfieldRect.bottom - 1; + int16 shpImageBottom = _starfieldRect.top; + + for (int i = 0; i < 4; i++) { + int16 index1 = i; + int16 index2 = (i + 1) & 3; + + if (thing[index1 + 1] > thing[index2 + 1]) { + index1 = index2; + index2 = i; + } + + int16 top = ceil(thing[index1 + 1]); + int16 bottom = floor(thing[index2 + 1]); + + if (top > bottom) + continue; + if (top > _starfieldRect.bottom - 1) // FIXME + continue; + if (bottom < _starfieldRect.top) + continue; + if (top < _starfieldRect.top) + top = _starfieldRect.top; + if (bottom > _starfieldRect.bottom - 1) + bottom = _starfieldRect.bottom - 1; + + if (top < shpImageTop) + shpImageTop = top; + if (bottom > shpImageBottom) + shpImageBottom = bottom; + + double dbl3f4; + if (thing[index2 + 1] == thing[index1 + 1]) + dbl3f4 = 0.0; + else + dbl3f4 = (thing[index2] - thing[index1]) / (thing[index2 + 1] - thing[index1 + 1]); + + int32 var3ec = (int32)(0x10000 * dbl3f4); + int32 var3e8 = (int32)(((top - thing[index1 + 1]) * dbl3f4 + thing[index1]) * 0x10000); + + for (int y = top; y <= bottom; y++) { + int16 var3f6 = var3e8 >> 16; + int16 var3f8 = (var3e8 + 0xffff) >> 16; + + if (var3f8 < _starfieldRect.left) + var3f8 = _starfieldRect.left; + if (var3f8 < leftBounds[y]) + leftBounds[y] = var3f8; + + if (var3f6 > _starfieldRect.right - 1) + var3f6 = _starfieldRect.right - 1; + if (var3f6 > rightBounds[y]) + rightBounds[y] = var3f6; + + var3e8 += var3ec; + } + } + + while (shpImageTop <= shpImageBottom) { + if (leftBounds[shpImageTop] > rightBounds[shpImageTop]) + shpImageTop++; + else + break; + } + while (shpImageTop <= shpImageBottom) { + if (leftBounds[shpImageBottom] > rightBounds[shpImageBottom]) + shpImageBottom--; + else + break; + } + + debug("Top: %d, Bot: %d", shpImageTop, shpImageBottom); + if (shpImageTop <= shpImageBottom) { + bool var3fa; + if (r3->field1e == 2) { + // TODO + } else + var3fa = (((r3->field24 * _starfieldPointDivisor) << 1) / 3 <= r3->field36.z); + + if (!var3fa) { + if (r3->field1e == 3) { + // FIXME: is this used anywhere? + uint16 var3fc = (_frameIndex << 3) ^ _frameIndex; + } else { + // TODO + } + } + + int16 xDiff = (int16)(dbl60 * 256); + int16 yDiff = (int16)(dbl58 * 256); + int16 var3f2 = (int16)(dbl50 * 256); + int16 var3f4 = (int16)(dbl48 * 256); + + int16 var3f6 = var3f2 * shpImageTop + (int16)(dbl40 * 256); + int16 var3f8 = var3f4 * shpImageTop + (int16)(dbl38 * 256); + + Bitmap tmpBitmap(256, 249); + byte otherBuffer[256 * 256]; + + int16 bitmapWidth = bitmap->width; + int16 bitmapHeight = bitmap->height; + + if (bitmapHeight > 245) + error("Shape height too big in drawR3Shape!"); + if (bitmapWidth > 252) + error("Shape width too big in drawR3Shape!"); + + for (int i = 0; i < 2; i++) + memset(otherBuffer + i * 256, 0, bitmapWidth + 4); + for (int i = 0; i < 2; i++) + memset(otherBuffer + (bitmapHeight + 2 + i) * 256, 0, bitmapWidth + 4); + + for (int i = 0; i < bitmapHeight; i++) { + otherBuffer[512 + i * 256 + 0] = 0; + otherBuffer[512 + i * 256 + 1] = 0; + otherBuffer[512 + i * 256 + bitmapWidth + 2] = 0; + otherBuffer[512 + i * 256 + bitmapWidth + 3] = 0; + } + + if (r3->field1e == 2) { + // TODO + } else + _gfx->copyRectBetweenBitmaps(&tmpBitmap, 2, 2, bitmap.get(), 0, 0, bitmapWidth, bitmapHeight); + + byte *bgPixels = _gfx->getBackgroundPixels() + shpImageTop * SCREEN_WIDTH; + + for (int y = shpImageTop; y <= shpImageBottom; y++) { + int16 leftBound = leftBounds[y]; + int16 rowWidth = rightBounds[y] - leftBound; + int16 srcX = leftBound * xDiff + var3f6; + int16 srcY = leftBound * yDiff + var3f8; + var3f6 += var3f2; + var3f8 += var3f4; + + byte *bgPixels2 = bgPixels + leftBound; + bgPixels += SCREEN_WIDTH; + + if (rowWidth == 0) + continue; + + debug("Width: %d", rowWidth); + + if (var3fa) { + srcX += 0x80; + srcY += 0x80; + + int16 cx = srcX; + int16 bx = srcY; + byte *di = bgPixels2; + + for (int a = 0; a < rowWidth; a++) { + byte b = tmpBitmap.pixels[(bx & 0xff00) + (cx >> 8)]; + cx += xDiff; + bx += yDiff; + if (b == 0) + *(di++) = 8; // FIXME: shouldn't assign anything, fix after done testing + else + *(di++) = b; + } + } else { + warning("Unimplemented branch in \"drawR3Shape\""); + } + } + } + } + + if (r3->funcPtr2 != nullptr) { + // TODO: call it + } +} + +bool StarTrekEngine::sub_1c022(R3 *r3) { + Point3 point = r3->field36; + if (point.z < _flt_50898) + return false; + return true; // TODO: finish this properly } Point3 StarTrekEngine::constructPoint3ForStarfield(int16 x, int16 y, int16 z) { @@ -153,9 +510,8 @@ Point3 StarTrekEngine::matrixMult(const Matrix &weight, const Point3 &point) { Point3 p; for (int i = 0; i < 3; i++) { p[i] = 0; - for (int j = 0; j < 3; j++) { // FIXME: what is this weird multiplication? - p[i] += (weight[i][j].raw() * (point[j] & 0xffff) << 2) >> 16; - } + for (int j = 0; j < 3; j++) + p[i] += (int16)weight[i][j].multToInt(point[j]); } return p; } @@ -164,13 +520,16 @@ Point3 StarTrekEngine::matrixMult(const Point3 &point, const Matrix &weight) { Point3 p = Point3(); for (int i = 0; i < 3; i++) { p[i] = 0; - for (int j = 0; j < 3; j++) { - p[i] += (weight[j][i].raw() * (point[j] & 0xffff) << 2) >> 16; - } + for (int j = 0; j < 3; j++) + p[i] += (int16)weight[j][i].multToInt(point[j]); } return p; } +int32 StarTrekEngine::scaleSpacePosition(int32 x, int32 z) { + return (x * _starfieldPointDivisor) / z; +} + Matrix StarTrekEngine::initMatrix() { Matrix mat; mat[0][0] = 1.0; @@ -179,4 +538,17 @@ Matrix StarTrekEngine::initMatrix() { return mat; } +Matrix StarTrekEngine::initSpeedMatrixForXZMovement(Angle angle, const Matrix &matrix) { + Fixed14 sinVal = sin(angle); + Fixed14 cosVal = cos(angle); + + Matrix matrix1 = initMatrix(); + matrix1[0].x = cosVal; + matrix1[0].z = -sinVal; + matrix1[2].x = sinVal; + matrix1[2].z = cosVal; + + return matrix * matrix1; +} + } diff --git a/engines/startrek/space.h b/engines/startrek/space.h index f4b53d17ab..0d113cfb40 100644 --- a/engines/startrek/space.h +++ b/engines/startrek/space.h @@ -38,6 +38,10 @@ struct TPoint { TPoint() : x(0), y(0), z(0) {} TPoint(T _x, T _y, T _z) : x(_x), y(_y), z(_z) {} + int32 getDiagonal() { + return sqrt(x * x + y * y + z * z); + } + TPoint<T> operator+(const TPoint<T> &p) const { TPoint<T> p2; p2.x = x + p.x; @@ -52,6 +56,16 @@ struct TPoint { p2.z = z - p.z; return p2; } + void operator+=(const TPoint &p) { + x += p.x; + y += p.y; + z += p.z; + } + void operator-=(const TPoint &p) { + x -= p.x; + y -= p.y; + z -= p.z; + } T &operator[](int i) { if (i == 0) return x; @@ -83,7 +97,11 @@ private: T m[3]; public: - TMatrix() {} + TMatrix() { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m[i][j] = 0; + } TMatrix(const TMatrix<T> &mat) { m[0] = mat.m[0]; m[1] = mat.m[1]; @@ -96,6 +114,22 @@ public: return m[i]; }; + TMatrix operator*(const TMatrix &m2) const { + TMatrix ret; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + ret[i][j] = 0; + for (int a = 0; a < 3; a++) + ret[i][j] += m[i][a] * m2[a][j]; + } + } + return ret; + } + + void operator*=(const TMatrix &m2) { + *this = *this * m2; + } + TMatrix<T> invert() { TMatrix<T> ret; for (int i = 0; i < 3; i++) { @@ -124,7 +158,20 @@ struct R3 { int16 field22; // 0x22 int16 field24; // 0x24 Point3_Short speed; // 0x26 + int32 funcPtr1; // 0x2c + int32 funcPtr2; // 0x30 + int16 field34; // 0x34 + Point3 field36; // 0x36 + Matrix matrix2; // 0x42 + int32 field54; // 0x54 (used for sorting by draw priority?) + int16 field58; // 0x58 + int16 field5a; // 0x5a SharedPtr<FileStream> shpFile; // 0x68 + int16 bitmapOffset; // 0x6a + double field80; // 0x80 + double field88; // 0x88 + double field90; // 0x90 + double field98; // 0x98 }; // Maximum number of stars visible at once in the starfields diff --git a/engines/startrek/startrek.cpp b/engines/startrek/startrek.cpp index 22d89db3ad..fbbf535601 100644 --- a/engines/startrek/startrek.cpp +++ b/engines/startrek/startrek.cpp @@ -58,6 +58,7 @@ StarTrekEngine::StarTrekEngine(OSystem *syst, const StarTrekGameDescription *gam DebugMan.addDebugChannel(kDebugSound, "sound", "Sound"); DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics"); DebugMan.addDebugChannel(kDebugSavegame, "savegame", "Savegames"); + DebugMan.addDebugChannel(kDebugSpace, "space", "Space and Pseudo-3D"); _gfx = nullptr; _sound = nullptr; @@ -89,6 +90,8 @@ StarTrekEngine::StarTrekEngine(OSystem *syst, const StarTrekGameDescription *gam _roomIndexToLoad = 0; _showSubtitles = true; // TODO: test + Common::fill(_r3List, _r3List + NUM_SPACE_OBJECTS, (R3 *)nullptr); + Common::fill(_orderedR3List, _orderedR3List + NUM_SPACE_OBJECTS, (R3 *)nullptr); for (int i = 0; i < NUM_OBJECTS; i++) _itemList[i] = g_itemList[i]; @@ -221,8 +224,11 @@ void StarTrekEngine::playIntro() { //delR3(&_enterpriseR3); // TODO: uncomment R3 planetR3 = R3(); - - // TODO: remainder of starfield initialization + planetR3.matrix = initMatrix(); + planetR3.field1e = 3; + planetR3.funcPtr1 = nullptr; + planetR3.funcPtr2 = nullptr; + planetR3.bitmapOffset = 0; _gfx->clearScreenAndPriBuffer(); _gfx->fadeoutScreen(); @@ -339,6 +345,16 @@ void StarTrekEngine::playIntro() { starfieldZoomSpeed = 0; break; + case 186: + delR3(&_enterpriseR3); + // TODO: the rest + break; + + case 366: + planetR3.shpFile.reset(); + delR3(&planetR3); + break; + case 378: _gfx->delSprite(&subtitleSprite); _byte_45b3c = 1; @@ -371,23 +387,26 @@ void StarTrekEngine::initIntroR3ObjectToMove(R3 *r3, int16 srcAngle, int16 srcDe Fixed8 a1 = Fixed8::fromRaw((srcAngle << 8) / 90); Fixed8 a2 = Fixed8::fromRaw((destAngle << 8) / 90); - r3->pos.x = (sin(a1).multToInt(srcDepth) << 16) + _starfieldPosition.x; - r3->pos.z = (cos(a1).multToInt(srcDepth) << 16) + _starfieldPosition.z; + r3->pos.x = sin(a1).multToInt(srcDepth) + _starfieldPosition.x; + r3->pos.z = cos(a1).multToInt(srcDepth) + _starfieldPosition.z; r3->pos.y = 0; - int32 deltaX = (sin(a2).multToInt(destDepth) << 16) + _starfieldPosition.x - r3->pos.x; - int32 deltaZ = (cos(a2).multToInt(destDepth) << 16) + _starfieldPosition.z - r3->pos.z; + int32 deltaX = sin(a2).multToInt(destDepth) + _starfieldPosition.x - r3->pos.x; + int32 deltaZ = cos(a2).multToInt(destDepth) + _starfieldPosition.z - r3->pos.z; + debug("Z: %d, %d", r3->pos.z - _starfieldPosition.z, cos(a2).multToInt(destDepth)); - Fixed16 angle = atan2(deltaX, deltaZ); - r3->matrix = initMatrix(); + Angle angle = atan2(deltaX, deltaZ); + r3->matrix = initSpeedMatrixForXZMovement(angle, initMatrix()); - // sub_248cc(angle, r3->matrix); + debugCN(5, kDebugSpace, "initIntroR3ObjectToMove: pos %x,%x,%x; ", r3->pos.x, r3->pos.y, r3->pos.z); if (ticks != 0) { + debugC(5, kDebugSpace, "speed %x,%x,%x\n", r3->speed.x, r3->speed.y, r3->speed.z); r3->speed.x = deltaX / ticks; r3->speed.z = deltaZ / ticks; r3->speed.y = 0; } else { + debugC(5, kDebugSpace, "speed 0\n"); r3->speed.x = 0; r3->speed.z = 0; r3->speed.y = 0; diff --git a/engines/startrek/startrek.h b/engines/startrek/startrek.h index 4f5e62dbd4..f95897da7b 100644 --- a/engines/startrek/startrek.h +++ b/engines/startrek/startrek.h @@ -112,7 +112,8 @@ enum StarTrekGameFeatures { enum kDebugLevels { kDebugSound = 1 << 0, kDebugGraphics = 1 << 1, - kDebugSavegame = 2 << 1 + kDebugSavegame = 1 << 2, + kDebugSpace = 2 << 3 }; enum GameMode { @@ -215,9 +216,9 @@ public: /** * Unit of the angle is "quadrants" (90 degrees = 1.0) */ - Fixed14 sin(Fixed8 angle); - Fixed14 cos(Fixed8 angle); - Fixed8 atan2(int32 deltaX, int32 deltaZ); + Fixed14 sin(Angle angle); + Fixed14 cos(Angle angle); + Angle atan2(int32 deltaX, int32 deltaZ); // Game modes Common::Error runGameMode(int mode); @@ -264,15 +265,20 @@ private: void clearStarfieldPixels(); void drawStarfield(); void updateStarfieldAndShips(bool arg0); + R3 *sub_19f24(R3 *r3); + void drawR3Shape(R3 *r3); + bool sub_1c022(R3 *r3); Point3 constructPoint3ForStarfield(int16 x, int16 y, int16 z); Point3 matrixMult(const Matrix &weight, const Point3 &point); Point3 matrixMult(const Point3 &point, const Matrix &weight); + int32 scaleSpacePosition(int32 x, int32 z); /** * Creates something like an "identity" matrix? (Value 0x4000 along the diagonal) */ Matrix initMatrix(); + Matrix initSpeedMatrixForXZMovement(Angle angle, const Matrix &matrix); // Transporter room void runTransportSequence(const Common::String &name); @@ -542,8 +548,10 @@ public: Common::Rect _starfieldRect; R3 _enterpriseR3; R3 *_r3List[NUM_SPACE_OBJECTS]; + R3 *_orderedR3List[NUM_SPACE_OBJECTS]; Matrix _starPositionMatrix; Matrix _someMatrix; + float _flt_50898; Graphics *_gfx; Sound *_sound; |