mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-16 14:50:17 +00:00
275 lines
6.7 KiB
C++
275 lines
6.7 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 "cryomni3d/omni3d.h"
|
|
|
|
#include "common/rect.h"
|
|
|
|
namespace CryOmni3D {
|
|
|
|
void Omni3DManager::init(double hfov) {
|
|
_alpha = 0.;
|
|
_beta = 0.;
|
|
_xSpeed = 0.;
|
|
_ySpeed = 0.;
|
|
|
|
double oppositeSide = tan(hfov / 2.) / (4. / 3.);
|
|
double vf = atan2(oppositeSide, 1.);
|
|
_vfov = (M_PI_2 - vf - (13. / 180.*M_PI)) * 10. / 9.;
|
|
|
|
double warpVfov = 155. / 180. * M_PI;
|
|
double hypV = 768. / 2. / sin(warpVfov / 2.);
|
|
double oppHTot = tan(hfov / 2.) * 16. / 320.;
|
|
_helperValue = 2048 * 65536 / (2. * M_PI);
|
|
|
|
for (int i = 0; i < 31; i++) {
|
|
double oppH = (i - 15) * oppHTot;
|
|
double angle = atan2(oppH, 1.);
|
|
|
|
_anglesH[i] = angle;
|
|
_hypothenusesH[i] = sqrt(oppH * oppH + 1);
|
|
|
|
double oppVTot = hypV * _hypothenusesH[i];
|
|
for (int j = 0; j < 21; j++) {
|
|
double oppV = (j - 20) * oppHTot;
|
|
|
|
_oppositeV[j] = oppV;
|
|
|
|
double coord = sqrt(oppV * oppV + _hypothenusesH[i] * _hypothenusesH[i]);
|
|
coord = oppVTot / coord;
|
|
coord = coord * 65536;
|
|
|
|
_squaresCoords[i][j] = coord;
|
|
}
|
|
}
|
|
|
|
_surface.create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
|
|
clearConstraints();
|
|
}
|
|
|
|
Omni3DManager::~Omni3DManager() {
|
|
_surface.free();
|
|
}
|
|
|
|
void Omni3DManager::updateCoords(int xDelta, int yDelta, bool useOldSpeed) {
|
|
double xDelta1 = xDelta * 0.00025;
|
|
double yDelta1 = yDelta * 0.0002;
|
|
|
|
if (useOldSpeed) {
|
|
_xSpeed += xDelta1;
|
|
_ySpeed += yDelta1;
|
|
} else {
|
|
_xSpeed = xDelta1;
|
|
_ySpeed = yDelta1;
|
|
}
|
|
_alpha += _xSpeed;
|
|
_beta += _ySpeed;
|
|
|
|
//debug("alpha = %lf beta = %lf xSpeed = %lf ySpeed = %lf", _alpha, _beta, _xSpeed, _ySpeed);
|
|
|
|
_xSpeed *= 0.4;
|
|
_ySpeed *= 0.6;
|
|
|
|
if (useOldSpeed) {
|
|
if (fabs(_xSpeed) < 0.001) {
|
|
_xSpeed = 0.;
|
|
}
|
|
if (fabs(_ySpeed) < 0.001) {
|
|
_ySpeed = 0.;
|
|
}
|
|
}
|
|
|
|
if (_alpha < _alphaMin) {
|
|
_alpha = _alphaMin;
|
|
_xSpeed = 0.;
|
|
} else if (_alpha > _alphaMax) {
|
|
_alpha = _alphaMax;
|
|
_xSpeed = 0.;
|
|
}
|
|
if (_beta < _betaMin) {
|
|
_beta = _betaMin;
|
|
_ySpeed = 0.;
|
|
} else if (_beta > _betaMax) {
|
|
_beta = _betaMax;
|
|
_ySpeed = 0.;
|
|
}
|
|
|
|
if (_alpha >= 2. * M_PI) {
|
|
_alpha -= 2. * M_PI;
|
|
} else if (_alpha < 0.) {
|
|
_alpha += 2. * M_PI;
|
|
}
|
|
|
|
_dirtyCoords = true;
|
|
|
|
updateImageCoords();
|
|
}
|
|
|
|
void Omni3DManager::updateImageCoords() {
|
|
if (!_dirtyCoords) {
|
|
return;
|
|
}
|
|
|
|
if (_alpha >= 2.*M_PI) {
|
|
_alpha -= 2.*M_PI;
|
|
} else if (_alpha < 0) {
|
|
_alpha += 2.*M_PI;
|
|
}
|
|
if (_beta > 0.9 * _vfov) {
|
|
_beta = 0.9 * _vfov;
|
|
} else if (_beta < -0.9 * _vfov) {
|
|
_beta = -0.9 * _vfov;
|
|
}
|
|
|
|
double tmp = (2048 * 65536) - 2048 * 65536 / (2. * M_PI) * _alpha;
|
|
|
|
uint k = 0;
|
|
for (uint i = 0; i < 31; i++) {
|
|
double v11 = _anglesH[i] + _beta;
|
|
double v26 = sin(v11);
|
|
double v25 = cos(v11) * _hypothenusesH[i];
|
|
|
|
uint offset = 80;
|
|
uint j;
|
|
for (j = 0; j < 20; j++) {
|
|
double v16 = atan2(_oppositeV[j], v25);
|
|
double v17 = v16 * _helperValue;
|
|
double v18 = (384 * 65536) - _squaresCoords[i][j] * v26;
|
|
|
|
k += 2;
|
|
_imageCoords[k + 0] = (int)(tmp + v17);
|
|
_imageCoords[k + offset + 0] = (int)(tmp - v17);
|
|
_imageCoords[k + 1] = (int) v18;
|
|
_imageCoords[k + offset + 1] = (int) v18;
|
|
|
|
offset -= 4;
|
|
}
|
|
|
|
double v19 = atan2(_oppositeV[j], v25);
|
|
|
|
k += 2;
|
|
_imageCoords[k + 0] = (int)((2048.*65536.) - (_alpha - v19) * _helperValue);
|
|
_imageCoords[k + 1] = (int)((384.*65536.) - _squaresCoords[i][j] * v26);
|
|
|
|
k += 40;
|
|
}
|
|
|
|
_dirtyCoords = false;
|
|
_dirty = true;
|
|
}
|
|
|
|
const Graphics::Surface *Omni3DManager::getSurface() {
|
|
if (!_sourceSurface) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (_dirtyCoords) {
|
|
updateImageCoords();
|
|
}
|
|
|
|
if (_dirty) {
|
|
uint off = 2;
|
|
byte *dst = (byte *)_surface.getBasePtr(0, 0);
|
|
const byte *src = (const byte *)_sourceSurface->getBasePtr(0, 0);
|
|
|
|
for (uint i = 0; i < 30; i++) {
|
|
for (uint j = 0; j < 40; j++) {
|
|
int x1 = (_imageCoords[off + 2] - _imageCoords[off + 0]) >> 4;
|
|
int y1 = (_imageCoords[off + 3] - _imageCoords[off + 1]) >> 4;
|
|
int x1_ = (_imageCoords[off + 82 + 2] - _imageCoords[off + 82 + 0]) >> 4;
|
|
int y1_ = (_imageCoords[off + 82 + 3] - _imageCoords[off + 82 + 1]) >> 4;
|
|
|
|
int dx1 = (x1_ - x1) >> 10;
|
|
int dy1 = (y1_ - y1) >> 15;
|
|
|
|
y1 >>= 5;
|
|
|
|
int dx2 = (_imageCoords[off + 82 + 0] - _imageCoords[off + 0]) >> 4;
|
|
int dy2 = (_imageCoords[off + 82 + 1] - _imageCoords[off + 1]) >> 9;
|
|
int x2 = (((_imageCoords[off + 0] >> 0) * 2) + dx2) >> 1;
|
|
int y2 = (((_imageCoords[off + 1] >> 5) * 2) + dy2) >> 1;
|
|
|
|
for (uint y = 0; y < 16; y++) {
|
|
uint px = (x2 * 2 + x1) * 16;
|
|
uint py = (y2 * 2 + y1) / 2;
|
|
uint deltaX = x1 * 32;
|
|
uint deltaY = y1;
|
|
|
|
for (uint x = 0; x < 16; x++) {
|
|
uint srcOff = (py & 0x1ff800) | (px >> 21);
|
|
dst[x] = src[srcOff];
|
|
px += deltaX;
|
|
py += deltaY;
|
|
}
|
|
dst += 640;
|
|
|
|
x1 += dx1;
|
|
y1 += dy1;
|
|
x2 += dx2;
|
|
y2 += dy2;
|
|
}
|
|
dst -= 16 * 640 - 16;
|
|
off += 2;
|
|
}
|
|
dst += 15 * 640;
|
|
off += 2;
|
|
}
|
|
|
|
_dirty = false;
|
|
}
|
|
|
|
return &_surface;
|
|
}
|
|
|
|
void Omni3DManager::clearConstraints() {
|
|
_alphaMin = -HUGE_VAL;
|
|
_alphaMax = HUGE_VAL;
|
|
_betaMin = -HUGE_VAL;
|
|
_betaMax = HUGE_VAL;
|
|
}
|
|
|
|
Common::Point Omni3DManager::mapMouseCoords(const Common::Point &mouse) {
|
|
Common::Point pt;
|
|
|
|
if (_dirtyCoords) {
|
|
updateImageCoords();
|
|
}
|
|
|
|
int smallX = mouse.x & 0xf, squareX = mouse.x >> 4;
|
|
int smallY = mouse.y & 0xf, squareY = mouse.y >> 4;
|
|
|
|
uint off = 82 * squareY + 2 * squareX;
|
|
|
|
pt.x = ((_imageCoords[off + 2] +
|
|
smallY * ((_imageCoords[off + 84] - _imageCoords[off + 2]) >> 4) +
|
|
(smallX * smallY) * ((_imageCoords[off + 86] - _imageCoords[off + 84]) >> 8) +
|
|
(smallX * (16 - smallY)) * ((_imageCoords[off + 4] - _imageCoords[off + 2]) >> 8))
|
|
& 0x07ff0000) >> 16;
|
|
pt.y = (_imageCoords[off + 3] +
|
|
smallY * ((_imageCoords[off + 85] - _imageCoords[off + 3]) >> 4) +
|
|
(smallX * smallY) * ((_imageCoords[off + 87] - _imageCoords[off + 85]) >> 8) +
|
|
(smallX * (16 - smallY)) * ((_imageCoords[off + 5] - _imageCoords[off + 3]) >> 8)) >> 16;
|
|
|
|
return pt;
|
|
}
|
|
|
|
} // End of namespace CryOmni3D
|