mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 12:39:56 +00:00
50d18e054d
Also introduce proper SCUMM math functions.
265 lines
7.4 KiB
C++
265 lines
7.4 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/>.
|
|
*
|
|
*/
|
|
|
|
#ifdef ENABLE_HE
|
|
|
|
#include "common/math.h"
|
|
#include "common/system.h"
|
|
#include "scumm/he/intern_he.h"
|
|
#include "scumm/he/wiz_he.h"
|
|
|
|
namespace Scumm {
|
|
|
|
void Wiz::deleteLocalPolygons() {
|
|
for (int i = 0; i < ARRAYSIZE(_polygons); i++) {
|
|
if (_polygons[i].flag == 1)
|
|
_polygons[i].reset();
|
|
}
|
|
}
|
|
|
|
void Wiz::polygonLoad(const uint8 *polData) {
|
|
int slots = READ_LE_UINT32(polData);
|
|
polData += 4;
|
|
|
|
bool flag = 1;
|
|
int id, points, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y;
|
|
while (slots--) {
|
|
id = READ_LE_UINT32(polData);
|
|
points = READ_LE_UINT32(polData + 4);
|
|
if (points != 4)
|
|
error("Illegal polygon with %d points", points);
|
|
vert1x = READ_LE_UINT32(polData + 8);
|
|
vert1y = READ_LE_UINT32(polData + 12);
|
|
vert2x = READ_LE_UINT32(polData + 16);
|
|
vert2y = READ_LE_UINT32(polData + 20);
|
|
vert3x = READ_LE_UINT32(polData + 24);
|
|
vert3y = READ_LE_UINT32(polData + 28);
|
|
vert4x = READ_LE_UINT32(polData + 32);
|
|
vert4y = READ_LE_UINT32(polData + 36);
|
|
|
|
polData += 40;
|
|
set4Polygon(id, flag, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y);
|
|
}
|
|
}
|
|
|
|
void Wiz::set4Polygon(int id, bool localFlag, int vert1x, int vert1y, int vert2x, int vert2y, int vert3x, int vert3y, int vert4x, int vert4y) {
|
|
for (int i = 0; i < ARRAYSIZE(_polygons); ++i) {
|
|
if (_polygons[i].id == 0) {
|
|
_polygons[i].points[0].x = vert1x;
|
|
_polygons[i].points[0].y = vert1y;
|
|
_polygons[i].points[1].x = vert2x;
|
|
_polygons[i].points[1].y = vert2y;
|
|
_polygons[i].points[2].x = vert3x;
|
|
_polygons[i].points[2].y = vert3y;
|
|
_polygons[i].points[3].x = vert4x;
|
|
_polygons[i].points[3].y = vert4y;
|
|
_polygons[i].points[4].x = vert1x;
|
|
_polygons[i].points[4].y = vert1y;
|
|
_polygons[i].id = id;
|
|
_polygons[i].numPoints = 5;
|
|
_polygons[i].flag = localFlag;
|
|
|
|
polyBuildBoundingRect(_polygons[i].points, _polygons[i].numPoints, _polygons[i].boundingRect);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
error("Wiz::set4Polygon: out of polygon slot, max = %d", ARRAYSIZE(_polygons));
|
|
}
|
|
|
|
void Wiz::polyRotatePoints(Common::Point *pts, int num, int angle) {
|
|
double alpha = ((double)angle) * M_PI / 180.;
|
|
double cos_alpha = cos(alpha);
|
|
double sin_alpha = sin(alpha);
|
|
|
|
for (int i = 0; i < num; ++i) {
|
|
int16 x = pts[i].x;
|
|
int16 y = pts[i].y;
|
|
pts[i].x = (int16)(((double)x * cos_alpha) - ((double)y * sin_alpha));
|
|
pts[i].y = (int16)(((double)y * cos_alpha) + ((double)x * sin_alpha));
|
|
}
|
|
}
|
|
|
|
void Wiz::polyMovePolygonPoints(Common::Point *listOfPoints, int numverts, int deltaX, int deltaY) {
|
|
for (int i = 0; i < numverts; i++) {
|
|
listOfPoints->x += deltaX;
|
|
listOfPoints->y += deltaY;
|
|
listOfPoints++;
|
|
}
|
|
}
|
|
|
|
bool Wiz::polyIsRectangle(const Common::Point *points, int numverts) {
|
|
// assume it's not
|
|
bool bRetVal = false;
|
|
|
|
// if there aren't four points, it's not a rectangle, duh!
|
|
if (numverts == 4) {
|
|
// check if point 0 is on same x and y axis as neighbors
|
|
if (points[0].x == points[1].x) {
|
|
// point 3 must be on y axis to form a right angle
|
|
if (points[0].y == points[3].y) {
|
|
// check opposite point to make sure that its neighbors form a right angle
|
|
if ((points[2].x == points[3].x) && (points[2].y == points[1].y)) {
|
|
bRetVal = true;
|
|
}
|
|
}
|
|
} else if (points[0].x == points[3].x) { // the second of two possible orientations
|
|
// point 1 must be on y axis to form right angle
|
|
if (points[0].y == points[1].y) {
|
|
// check opposite point to make sure that its neighbors form a right angle
|
|
if ((points[2].x == points[1].x) && (points[2].y == points[3].y)) {
|
|
bRetVal = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
void Wiz::polyBuildBoundingRect(Common::Point *points, int numVerts, Common::Rect &rect) {
|
|
rect.left = 10000;
|
|
rect.top = 10000;
|
|
rect.right = -10000;
|
|
rect.bottom = -10000;
|
|
|
|
// compute bounding box
|
|
for (int j = 0; j < numVerts; j++) {
|
|
if (points[j].x < rect.left) rect.left = points[j].x;
|
|
if (points[j].y < rect.top) rect.top = points[j].y;
|
|
if (points[j].x > rect.right) rect.right = points[j].x;
|
|
if (points[j].y > rect.bottom) rect.bottom = points[j].y;
|
|
}
|
|
}
|
|
|
|
void Wiz::deletePolygon(int fromId, int toId) {
|
|
for (int i = 0; i < ARRAYSIZE(_polygons); i++) {
|
|
if (_polygons[i].id >= fromId && _polygons[i].id <= toId)
|
|
_polygons[i].reset();
|
|
}
|
|
}
|
|
|
|
int Wiz::findPolygon(int x, int y) {
|
|
Common::Point checkPoint((int16)x, (int16)y);
|
|
|
|
for (int i = 0; i < ARRAYSIZE(_polygons); i++) {
|
|
if (isPointInRect(&_polygons[i].boundingRect, &checkPoint)) {
|
|
if (polyIsPointInsidePoly(_polygons[i].points, _polygons[i].numPoints, &checkPoint)) {
|
|
return _polygons[i].id;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int Wiz::testForObjectPolygon(int object, int x, int y) {
|
|
Common::Point checkPoint((int16)x, (int16)y);
|
|
|
|
if (object == 0)
|
|
return 0;
|
|
|
|
for (int i = 0; i < ARRAYSIZE(_polygons); i++) {
|
|
if (_polygons[i].id == object) {
|
|
if (isPointInRect(&_polygons[i].boundingRect, &checkPoint)) {
|
|
if (polyIsPointInsidePoly(_polygons[i].points, _polygons[i].numPoints, &checkPoint)) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool Wiz::doesObjectHavePolygon(int object) {
|
|
if (object == 0)
|
|
return false;
|
|
|
|
for (int i = 0; i < ARRAYSIZE(_polygons); i++)
|
|
if (_polygons[i].id == object)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Wiz::polyIsPointInsidePoly(Common::Point *listOfPoints, int numverts, Common::Point *checkPoint) {
|
|
int ty, tx, yflag0, yflag1;
|
|
bool insideFlag = false;
|
|
Common::Point *vtx0, *vtx1;
|
|
|
|
tx = checkPoint->x;
|
|
ty = checkPoint->y;
|
|
vtx0 = listOfPoints + (numverts - 1);
|
|
yflag0 = (vtx0->y >= ty);
|
|
vtx1 = listOfPoints;
|
|
|
|
for (int j = numverts + 1; --j;) {
|
|
yflag1 = (vtx1->y >= ty);
|
|
|
|
if (yflag0 != yflag1) {
|
|
if (((vtx1->y - ty) * (vtx0->x - vtx1->x) >=
|
|
(vtx1->x - tx) * (vtx0->y - vtx1->y)) == yflag0) {
|
|
insideFlag = !insideFlag;
|
|
}
|
|
}
|
|
|
|
yflag0 = yflag1;
|
|
vtx0 = vtx1;
|
|
vtx1++;
|
|
}
|
|
|
|
// Special case the vert and horz edges.
|
|
if (_vm->_game.heversion >= 80) {
|
|
if (!insideFlag) {
|
|
int a, b, minX, maxX, minY, maxY;
|
|
|
|
for (int j = 0; j < numverts; j++) {
|
|
a = j % numverts;
|
|
b = (j + 1) % numverts;
|
|
|
|
if ((ty == listOfPoints[a].y) && (listOfPoints[a].y == listOfPoints[b].y)) {
|
|
|
|
minX = MIN(listOfPoints[a].x, listOfPoints[b].x);
|
|
maxX = MAX(listOfPoints[a].x, listOfPoints[b].x);
|
|
|
|
if ((tx >= minX) && (tx <= maxX)) {
|
|
return true;
|
|
}
|
|
|
|
} else if ((tx == listOfPoints[a].x) && (listOfPoints[a].x == listOfPoints[b].x)) {
|
|
minY = MIN(listOfPoints[a].y, listOfPoints[b].y);
|
|
maxY = MAX(listOfPoints[a].y, listOfPoints[b].y);
|
|
|
|
if ((ty >= minY) && (ty <= maxY)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return insideFlag;
|
|
}
|
|
|
|
} // End of namespace Scumm
|
|
|
|
#endif // ENABLE_HE
|