scummvm/engines/titanic/star_control/star_closeup.cpp
2021-12-26 18:48:43 +01:00

561 lines
16 KiB
C++

/* 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 "titanic/star_control/star_closeup.h"
#include "titanic/star_control/error_code.h"
#include "titanic/star_control/camera.h"
#include "titanic/star_control/surface_area.h"
#include "titanic/titanic.h"
#include "common/math.h"
namespace Titanic {
#define MKTAG_BE(a3,a2,a1,a0) ((uint32)((a3) | ((a2) << 8) | ((a1) << 16) | ((a0) << 24)))
void CStarCloseup::SubEntry::clear() {
_data1.clear();
_data2.clear();
}
/*------------------------------------------------------------------------*/
bool CStarCloseup::SineTable::setup() {
if (_data.empty()) {
_data.resize(1024);
for (int idx = 0; idx < 1024; ++idx)
_data[idx] = sin((float)idx * 2 * M_PI / 512.0);
}
return true;
}
/*------------------------------------------------------------------------*/
CStarCloseup::CStarCloseup() : _flag(true), _multiplier(0) {
}
bool CStarCloseup::setup() {
bool success = setupEntry(5, 5, 4, 1024.0)
&& setupEntry(7, 7, 3, 1024.0)
&& setupEntry(8, 8, 2, 1024.0)
&& setupEntry(16, 16, 1, 1024.0)
&& setupEntry(24, 24, 0, 1024.0);
if (success)
success = setup2(24, 24);
return success;
}
bool CStarCloseup::setup2(int val1, int val2) {
const int VALUES1[] = { 0x800, 0xC00, 0x1000, 0x1400, 0x1800 };
const int VALUES2[] = {
0xF95BCD, 0xA505A0, 0xFFAD43, 0x98F4EB, 0xF3EFA5, 0,
0xFFFFFF, 0x81EEF5, 0x5FFD3, 0x4EE4FA, 0x11C3FF, 0x28F3F4,
0x36FCF2, 0x29F1FD, 0x29BCFD, 0x98E3F4, 0xBBF3D9, 0x8198F5,
0x5BE4F9, 0x0D6E2, 0x74EEF6, 0x68DEF8
};
Entry *e = &_entries[0];
for (int idx = 0; idx < 256; ++idx) {
if (idx == 0) {
e->_field0 = 0x4C8;
e->_pixel1 = 0x40;
e->_pixel2 = 0x40;
e->_pixel3 = 0x40;
e->_field8 = g_vm->getRandomNumber(3) + 3;
e->_fieldC = g_vm->getRandomNumber(255);
e->_field10 = Common::deg2rad<double>(7.0);
e->_field14 = 0.0084687499;
++e;
e->_field0 = 0x574;
e->_pixel1 = 0x7f;
e->_pixel2 = 0;
e->_pixel3 = 0;
e->_field8 = g_vm->getRandomNumber(3) + 3;
e->_fieldC = g_vm->getRandomNumber(255);
e->_field10 = Common::deg2rad<double>(3.0);
e->_field14 = 0.021011719;
++e;
e->_field0 = 0x603;
e->_pixel1 = 0;
e->_pixel2 = 0;
e->_pixel3 = 0xff;
e->_field8 = g_vm->getRandomNumber(3) + 3;
e->_fieldC = g_vm->getRandomNumber(255);
e->_field10 = 0;
e->_field14 = 0.022144532;
++e;
e->_field0 = 0x712;
e->_pixel1 = 0xff;
e->_pixel2 = 0;
e->_pixel3 = 0;
e->_field8 = g_vm->getRandomNumber(3) + 3;
e->_fieldC = g_vm->getRandomNumber(255);
e->_field10 = Common::deg2rad<double>(2.0);
e->_field14 = 0.01178125;
++e;
e->_field0 = 0xe7f;
e->_pixel1 = 0xe6;
e->_pixel2 = 0xbe;
e->_pixel3 = 0;
e->_field8 = g_vm->getRandomNumber(3) + 3;
e->_fieldC = g_vm->getRandomNumber(255);
e->_field10 = Common::deg2rad<double>(1.0);
e->_field14 = 0.24791406;
++e;
e->_field0 = 0x173f;
e->_pixel1 = 0xf0;
e->_pixel2 = 0xf0;
e->_pixel3 = 0xe6;
e->_field8 = g_vm->getRandomNumber(3) + 3;
e->_fieldC = g_vm->getRandomNumber(255);
e->_field10 = Common::deg2rad<double>(3.0);
e->_field14 = 0.20832032;
++e;
e->_field0 = 0x2ab8;
e->_pixel1 = 0x28;
e->_pixel2 = 0x32;
e->_pixel3 = 0x28;
e->_field8 = g_vm->getRandomNumber(3) + 3;
e->_fieldC = g_vm->getRandomNumber(255);
e->_field10 = Common::deg2rad<double>(1.0);
e->_field14 = 0.088164061;
++e;
e->_field0 = 0x40ac;
e->_pixel1 = 0x0;
e->_pixel2 = 0xbe;
e->_pixel3 = 0xf0;
e->_field8 = g_vm->getRandomNumber(3) + 3;
e->_fieldC = g_vm->getRandomNumber(255);
e->_field10 = Common::deg2rad<double>(2.0);
e->_field14 = 0.084375001;
++e;
e->_field0 = 0x539c;
e->_pixel1 = 0x20;
e->_pixel2 = 0x20;
e->_pixel3 = 0x20;
e->_field8 = g_vm->getRandomNumber(3) + 3;
e->_fieldC = g_vm->getRandomNumber(255);
e->_field10 = Common::deg2rad<double>(17.0);
e->_field14 = 1 / 256.0;
} else {
for (int ctr = 0; ctr < 5; ++ctr) {
e->_field0 = static_cast<int>(g_vm->getRandomFloat() * 1350.0
- 675.0) + VALUES1[ctr];
int val = VALUES2[g_vm->getRandomNumber(15)];
e->_pixel1 = val & 0xff;
e->_pixel2 = (val >> 8) & 0xff;
e->_pixel3 = (val >> 16) & 0xff;
e->_field8 = g_vm->getRandomNumber(3) + 3;
e->_fieldC = g_vm->getRandomNumber(255);
e->_field10 = Common::deg2rad<double>((double)g_vm->getRandomNumber(15));
e->_field14 = ((float)g_vm->getRandomNumber(0xfffffffe)
* 50.0 / 65536.0) / 256.0;
}
}
}
if (_sineTable.setup()) {
_grid.resize((val2 - 2) * val1 + 2);
return true;
}
return false;
}
void CStarCloseup::draw(const FPose &pose, const FVector &vector, const FVector &vector2,
CSurfaceArea *surfaceArea, CCamera *camera) {
const int VALUES[] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4 };
float val1 = camera->getFrontClip();
StarColor starColor = camera->getStarColor();
if (!_flag)
return;
int f1, f3, size2, size1;
float f2, f4, f5, f6, f7, f8, f9;
float f10, incr, f12, f13, f14, f15, f16, f17, f18, f19;
float f20, f21, f22;
FVector tempV;
if (vector2._z < 6.0e9) {
int count, start;
if (vector._x != 0.0 && (vector._y != 0.0 || vector._z != 0.0)) {
// WORKAROUND: Ignoring non-sensical randSeed((int)vector._x);
count = VALUES[g_vm->getRandomNumber(15)];
start = 5 * g_vm->getRandomNumber(255);
} else {
count = 9;
start = 0;
}
Entry *entryP = &_entries[start];
for (; count > 0; --count, ++entryP) {
f1 = _multiplier * entryP->_field8;
f2 = entryP->_field14;
f3 = (f1 + entryP->_fieldC) & 0x1FF;
f4 = _sineTable[f1 & 0x1FF] * entryP->_field10;
f5 = _sineTable[f3];
f6 = cos(f4);
f7 = sin(f4);
f8 = _sineTable[f3 + 128];
f9 = f7;
f10 = f6 * f8;
incr = f6;
f12 = f6 * f5;
f13 = f2 * f10;
f14 = f8 * f2;
f15 = f9 * f2;
f16 = f2 * f12;
f17 = -(f7 * f8 * f2);
f18 = incr * f2;
f19 = -(f9 * f5 * f2);
f20 = -(f5 * f2);
f21 = f14;
_sub1._row1._x = f13;
_sub1._row1._y = f15;
_sub1._row1._z = f16;
_sub1._row2._x = f17;
_sub1._row2._y = f18;
_sub1._row2._z = f19;
_sub1._row3._x = f20;
_sub1._row3._z = f14;
f22 = (float)entryP->_field0;
_sub1._vector._x = f22 * f10 + vector._x;
_sub1._vector._y = f9 * f22 + vector._y;
_sub1._vector._z = f22 * f12 + vector._z;
_sub2._row1._x = pose._row1._x * f13 + f16 * pose._row3._x + f15 * pose._row2._x;
_sub2._row1._y = f15 * pose._row2._y + f16 * pose._row3._y + f13 * pose._row1._y;
_sub2._row1._z = f16 * pose._row3._z + f13 * pose._row1._z + f15 * pose._row2._z;
_sub2._row2._x = pose._row1._x * f17 + f19 * pose._row3._x + f18 * pose._row2._x;
_sub2._row2._y = f18 * pose._row2._y + f17 * pose._row1._y + f19 * pose._row3._y;
_sub2._row2._z = f18 * pose._row2._z + f19 * pose._row3._z + f17 * pose._row1._z;
_sub2._row3._x = pose._row1._x * f20 + f21 * pose._row3._x;
_sub2._row3._y = f20 * pose._row1._y + f21 * pose._row3._y;
_sub2._row3._z = f20 * pose._row1._z + f21 * pose._row3._z;
_sub2._vector._x = pose._row1._x * _sub1._vector._x
+ pose._row3._x * _sub1._vector._z
+ pose._row2._x * _sub1._vector._y + pose._vector._x;
_sub2._vector._y = pose._row2._y * _sub1._vector._y
+ pose._row3._y * _sub1._vector._z
+ pose._row1._y * _sub1._vector._x + pose._vector._y;
_sub2._vector._z = pose._row3._z * _sub1._vector._z
+ pose._row1._z * _sub1._vector._x
+ pose._row2._z * _sub1._vector._y + pose._vector._z;
size2 = (int)_array[1]._data2.size();
size1 = (int)_array[1]._data1.size();
if (size2 > 0) {
for (int ctr2 = 0; ctr2 < size2; ++ctr2) {
FVector &currVector = _array[1]._data2[ctr2];
GridEntry &gridEntry = _grid[ctr2];
gridEntry._x = currVector._z * _sub2._row3._x
+ currVector._y * _sub2._row2._x
+ currVector._x * _sub2._row1._x + _sub2._vector._x;
gridEntry._y = currVector._z * _sub2._row3._y
+ currVector._y * _sub2._row2._y
+ currVector._x * _sub2._row1._y + _sub2._vector._y;
gridEntry._z = currVector._z * _sub2._row3._z
+ currVector._y * _sub2._row2._z
+ currVector._x * _sub2._row1._z + _sub2._vector._z;
}
}
switch (starColor) {
case WHITE:
surfaceArea->setMode(SA_SOLID);
surfaceArea->_pixel = MKTAG_BE(entryP->_pixel1, entryP->_pixel2,
entryP->_pixel3, 0);
surfaceArea->setColorFromPixel();
for (int ctr2 = 0; ctr2 < size2; ++ctr2) {
GridEntry &gridEntry = _grid[ctr2];
tempV = camera->getRelativePos(2, gridEntry);
gridEntry._position._x = tempV._x;
gridEntry._position._y = tempV._y + vector2._y;
}
for (int ctr2 = 0; ctr2 < size1; ++ctr2) {
Data1 &d1 = _array[1]._data1[ctr2];
GridEntry &grid1 = _grid[d1._index1];
GridEntry &grid2 = _grid[d1._index2];
if (grid1._z > val1 && grid2._z > val1) {
surfaceArea->drawLine(FRect(grid1._position._x, grid1._position._y,
grid2._position._x, grid2._position._y));
}
}
break;
case PINK:
surfaceArea->setMode(SA_SOLID);
surfaceArea->_pixel = entryP->_pixel1;
surfaceArea->setColorFromPixel();
for (int ctr2 = 0; ctr2 < size2; ++ctr2) {
GridEntry &gridEntry = _grid[ctr2];
tempV = camera->getRelativePos(0, gridEntry);
gridEntry._position._x = tempV._x + vector2._x;
gridEntry._position._y = tempV._y + vector2._y;
}
for (int ctr2 = 0; ctr2 < size1; ++ctr2) {
Data1 &d1 = _array[1]._data1[ctr2];
GridEntry &grid1 = _grid[d1._index1];
GridEntry &grid2 = _grid[d1._index2];
if (grid1._z > val1 && grid2._z > val1) {
surfaceArea->drawLine(FRect(grid1._position._x, grid1._position._y,
grid2._position._x, grid2._position._y));
}
}
surfaceArea->_pixel = entryP->_pixel3;
surfaceArea->setColorFromPixel();
surfaceArea->setMode(SA_MODE2);
for (int ctr2 = 0; ctr2 < size2; ++ctr2) {
GridEntry &gridEntry = _grid[ctr2];
tempV = camera->getRelativePos(1, gridEntry);
gridEntry._position._x = tempV._x + vector2._x;
gridEntry._position._y = tempV._y + vector2._y;
}
for (int ctr2 = 0; ctr2 < size1; ++ctr2) {
Data1 &d1 = _array[1]._data1[ctr2];
GridEntry &grid1 = _grid[d1._index1];
GridEntry &grid2 = _grid[d1._index2];
if (grid1._z > val1 && grid2._z > val1) {
surfaceArea->drawLine(FRect(grid1._position._x, grid1._position._y,
grid2._position._x, grid2._position._y));
}
}
break;
default:
assert(0);
}
}
}
uint pixel1 = 0x81EEF5, pixel2 = 0xF5, pixel3 = 0x810000;
int arrIndex = 0;
if (vector2._z >= 200000000.0) {
if (vector2._z >= 900000000.0) {
if (vector2._z >= 6000000000.0) {
arrIndex = 3;
if (vector2._z >= 1.0e10)
arrIndex = 4;
} else {
arrIndex = 2;
}
} else {
arrIndex = 1;
}
} else {
arrIndex = 0;
}
SubEntry &entry = _array[arrIndex];
for (uint ctr = 0; ctr < entry._data2.size(); ++ctr) {
GridEntry &gridEntry = _grid[ctr];
const FVector &d2v = entry._data2[ctr];
FVector newV = d2v + vector;
gridEntry._x = pose._row1._x * newV._x + pose._row3._x * newV._z
+ pose._row2._x * newV._y + pose._vector._x;
gridEntry._y = newV._y * pose._row2._y + newV._z * pose._row3._y
+ newV._x * pose._row1._y + pose._vector._y;
gridEntry._z = newV._z * pose._row3._z + newV._y * pose._row2._z
+ newV._x * pose._row1._z + pose._vector._z;
}
switch(starColor) {
case WHITE:
surfaceArea->setMode(SA_SOLID);
surfaceArea->_pixel = pixel1;
surfaceArea->setColorFromPixel();
for (uint ctr = 0; ctr < entry._data2.size(); ++ctr) {
GridEntry &gridEntry = _grid[ctr];
tempV = camera->getRelativePos(2, gridEntry);
gridEntry._position._x = tempV._x + vector2._x;
gridEntry._position._y = tempV._y + vector2._y;
}
for (uint ctr = 0; ctr < entry._data1.size(); ++ctr) {
Data1 &d1 = entry._data1[ctr];
GridEntry &grid1 = _grid[d1._index1];
GridEntry &grid2 = _grid[d1._index2];
if (grid2._z > val1 && grid1._z > val1) {
surfaceArea->drawLine(FRect(grid1._position._x, grid1._position._y,
grid2._position._x, grid2._position._y));
}
}
break;
case PINK:
surfaceArea->setMode(SA_SOLID);
surfaceArea->_pixel = pixel2;
surfaceArea->setColorFromPixel();
for (uint ctr = 0; ctr < entry._data2.size(); ++ctr) {
GridEntry &gridEntry = _grid[ctr];
tempV = camera->getRelativePos(2, gridEntry);
gridEntry._position._x = tempV._x + vector2._x;
gridEntry._position._y = tempV._y + vector2._y;
}
for (uint ctr = 0; ctr < entry._data1.size(); ++ctr) {
Data1 &d1 = entry._data1[ctr];
GridEntry &grid1 = _grid[d1._index1];
GridEntry &grid2 = _grid[d1._index2];
if (grid2._z > val1 && grid1._z > val1) {
surfaceArea->drawLine(FRect(grid1._position._x, grid1._position._y,
grid2._position._x, grid2._position._y));
}
}
surfaceArea->_pixel = pixel3;
surfaceArea->setColorFromPixel();
surfaceArea->setMode(SA_MODE2);
for (uint ctr = 0; ctr < entry._data2.size(); ++ctr) {
GridEntry &gridEntry = _grid[ctr];
tempV = camera->getRelativePos(2, gridEntry);
gridEntry._position._x = tempV._x + vector2._x;
gridEntry._position._y = tempV._y + vector2._y;
}
for (uint ctr = 0; ctr < entry._data1.size(); ++ctr) {
Data1 &d1 = entry._data1[ctr];
GridEntry &grid1 = _grid[d1._index1];
GridEntry &grid2 = _grid[d1._index2];
if (grid2._z > val1 && grid1._z > val1) {
surfaceArea->drawLine(FRect(grid1._position._x, grid1._position._y,
grid2._position._x, grid2._position._y));
}
}
break;
default:
assert(0);
}
}
void CStarCloseup::proc3(CErrorCode *errorCode) {
++_multiplier;
errorCode->set();
}
void CStarCloseup::fn1() {
_flag = !_flag;
}
bool CStarCloseup::setupEntry(int width, int height, int index, float val) {
if (width < 2 || height < 3)
return false;
SubEntry &entry = _array[index];
entry.clear();
int d1Count, d2Count, size3, height1;
int ctr, ctr2, idx, incr;
float vx, vy, yVal, degrees, cosVal, sinVal, angle;
d1Count = width * (2 * height - 3);
d2Count = (height - 2) * width + 2;
entry._data1.resize(d1Count);
entry._data2.resize(d2Count);
height1 = height - 1;
vy = 180.0 / (float)height1;
vx = 360.0 / (float)width;
// Build up the vector list
entry._data2[0]._y = val;
for (ctr = height - 2, idx = 1, yVal = vy; ctr > 0; --ctr, yVal += vy) {
degrees = 0.0;
cosVal = cos(Common::deg2rad<float>(yVal));
sinVal = sin(Common::deg2rad<float>(yVal));
if (width > 0) {
for (int xCtr = 0; xCtr < width; ++xCtr, ++idx, degrees += vx) {
angle = Common::deg2rad<float>(degrees);
FVector &tempV = entry._data2[idx];
tempV._x = sin(angle) * sinVal * val;
tempV._y = cosVal * val;
tempV._z = cos(angle) * sinVal * val;
}
}
}
entry._data2[idx] = FVector(0.0, -1.0 * val, 0.0);
size3 = width * (height - 3) + 1;
Data1 *data1P = &entry._data1[0];
for (ctr = 0; ctr < width; ++ctr, ++size3) {
data1P->_index1 = 0;
data1P->_index2 = size3 - width * (height - 3);
++data1P;
data1P->_index1 = d2Count - 1;
data1P->_index2 = size3;
++data1P;
}
incr = 1;
for (ctr = 1; ctr < height1; ++ctr, incr += width) {
for (ctr2 = 0; ctr2 < width; ++ctr2, ++data1P) {
data1P->_index1 = ctr2 + incr;
if (ctr2 == width - 1)
data1P->_index2 = incr;
else
data1P->_index2 = ctr2 + incr + 1;
if (ctr < height - 2) {
++data1P;
data1P->_index1 = ctr2 + incr;
data1P->_index2 = width + ctr2 + incr;
}
}
}
return true;
}
} // End of namespace Titanic