147 lines
4.8 KiB
C++
147 lines
4.8 KiB
C++
/*
|
|
This file is part of Warzone 2100.
|
|
Copyright (C) 1999-2004 Eidos Interactive
|
|
Copyright (C) 2005-2013 Warzone 2100 Project
|
|
|
|
Warzone 2100 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.
|
|
|
|
Warzone 2100 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 Warzone 2100; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* Geometry.c - holds trig/vector deliverance specific stuff for 3D */
|
|
/* Alex McLean, Pumpkin Studios, EIDOS Interactive */
|
|
|
|
#include "lib/framework/frame.h"
|
|
|
|
#include "lib/ivis_opengl/ivisdef.h"
|
|
#include "lib/ivis_opengl/piematrix.h"
|
|
#include "lib/gamelib/gtime.h"
|
|
|
|
#include "geometry.h"
|
|
#include "objectdef.h"
|
|
#include "map.h"
|
|
#include "display3d.h"
|
|
#include "hci.h"
|
|
#include "display.h"
|
|
|
|
uint16_t calcDirection(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
|
{
|
|
return iAtan2(x1 - x0, y1 - y0);
|
|
}
|
|
|
|
|
|
/* A useful function and one that should have been written long ago, assuming of course
|
|
that is hasn't been!!!! Alex M, 24th Sept, 1998. Returns the nearest unit
|
|
to a given world coordinate - we can choose whether we require that the unit be
|
|
selected or not... Makes sending the most logical unit to do something very easy.
|
|
|
|
NB*****THIS WON'T PICK A VTOL DROID*****
|
|
*/
|
|
|
|
DROID *getNearestDroid(UDWORD x, UDWORD y, bool bSelected)
|
|
{
|
|
DROID *psDroid,*psBestUnit;
|
|
UDWORD bestSoFar;
|
|
|
|
/* Go thru' all the droids - how often have we seen this - a MACRO maybe? */
|
|
for(psDroid = apsDroidLists[selectedPlayer],psBestUnit = NULL, bestSoFar = UDWORD_MAX;
|
|
psDroid; psDroid = psDroid->psNext)
|
|
{
|
|
if (!isVtolDroid(psDroid))
|
|
{
|
|
/* Clever (?) bit that reads whether we're interested in droids being selected or not */
|
|
if (!bSelected || psDroid->selected)
|
|
{
|
|
uint32_t dist = iHypot(psDroid->pos.x - x, psDroid->pos.y - y);
|
|
/* Is this the nearest one we got so far? */
|
|
if(dist<bestSoFar)
|
|
{
|
|
/* Yes, then keep a record of the distance for comparison... */
|
|
bestSoFar = dist;
|
|
/* ..and store away the droid responsible */
|
|
psBestUnit = psDroid;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(psBestUnit);
|
|
}
|
|
// -------------------------------------------------------------------------------------------
|
|
|
|
/* Returns non-zero if a point is in a 4 sided polygon */
|
|
/* See header file for definition of QUAD */
|
|
bool inQuad(const Vector2i *pt, const QUAD *quad)
|
|
{
|
|
// Early out.
|
|
int minX = std::min(std::min(quad->coords[0].x, quad->coords[1].x), std::min(quad->coords[2].x, quad->coords[3].x)); if (pt->x < minX) return false;
|
|
int maxX = std::max(std::max(quad->coords[0].x, quad->coords[1].x), std::max(quad->coords[2].x, quad->coords[3].x)); if (pt->x > maxX) return false;
|
|
int minY = std::min(std::min(quad->coords[0].y, quad->coords[1].y), std::min(quad->coords[2].y, quad->coords[3].y)); if (pt->y < minY) return false;
|
|
int maxY = std::max(std::max(quad->coords[0].y, quad->coords[1].y), std::max(quad->coords[2].y, quad->coords[3].y)); if (pt->y > maxY) return false;
|
|
|
|
bool c = false;
|
|
|
|
for (int i = 0, j = 3; i < 4; j = i++)
|
|
{
|
|
Vector2i edge = quad->coords[j] - quad->coords[i];
|
|
Vector2i pos = *pt - quad->coords[i];
|
|
if (( 0 <= pos.y && pos.y < edge.y && pos.x * edge.y < pos.y * edge.x) ||
|
|
(edge.y <= pos.y && pos.y < 0 && pos.x * edge.y > pos.y * edge.x))
|
|
{
|
|
c = !c;
|
|
}
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
Vector2i positionInQuad(Vector2i const &pt, QUAD const &quad)
|
|
{
|
|
int lenSq[4];
|
|
int ptDot[4];
|
|
for (int i = 0, j = 3; i < 4; j = i++)
|
|
{
|
|
Vector2i edge = quad.coords[j] - quad.coords[i];
|
|
Vector2i pos = quad.coords[j] - pt;
|
|
Vector2i posRot(pos.y, -pos.x);
|
|
lenSq[i] = edge*edge;
|
|
ptDot[i] = posRot*edge;
|
|
}
|
|
int ret[2];
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
int d1 = ptDot[i]*lenSq[i + 2];
|
|
int d2 = ptDot[i + 2]*lenSq[i];
|
|
ret[i] = d1 + d2 != 0? (int64_t)TILE_UNITS*d1 / (d1 + d2) : TILE_UNITS/2;
|
|
}
|
|
return Vector2i(ret[0], ret[1]);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
bool droidOnScreen( DROID *psDroid, SDWORD tolerance )
|
|
{
|
|
SDWORD dX,dY;
|
|
|
|
if (DrawnInLastFrame(psDroid->sDisplay.frameNumber)==true)
|
|
{
|
|
dX = psDroid->sDisplay.screenX;
|
|
dY = psDroid->sDisplay.screenY;
|
|
/* Is it on screen */
|
|
if(dX > (0-tolerance) && dY > (0-tolerance)
|
|
&& dX < (SDWORD)(pie_GetVideoBufferWidth()+tolerance)
|
|
&& dY < (SDWORD)(pie_GetVideoBufferHeight()+tolerance))
|
|
{
|
|
return(true);
|
|
}
|
|
}
|
|
return(false);
|
|
}
|