/*
* This file is part of Physics 2D Library.
* 
* Physics 2D Library 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.
* 
* Physics 2D Library 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 Physics 2D Library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef Phys2D
#define Phys2D

#include <windows.h>
#include <math.h>

#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else 
# define DLLIMPORT __declspec (dllimport)
#endif

#define MAXOBJECTS 10
#define MAXEFFECTS 10

#define sqr(x) ((x)*(x))
#define sign(x) ( (x)<0 ? -1 : 1 )

// точка-линия
typedef enum { ptlLeft,  ptlRight,  ptlBeyond,  ptlBehind, ptlBetween, ptlOrigin, ptlDestination } PTL;
// точка-полигон
typedef enum { ptpInside, ptpOutside, ptpBoundary } PTP;      
// ребро-луч (при трассировке)
typedef enum { etrTouching, etrCrossing, etrInessential } ETR;

class DLLIMPORT P2DPhysics;

struct DLLIMPORT P2DPoint
 {
 double x, y;
 };

struct DLLIMPORT P2DObject
 {
 // v(x,y) - speed, c(x,y) - center of mass
 double x, y, vx, vy, vr, cx, cy;
 double rotation;
 double mass;
 bool unyielding;
 //    /4--1\
 //   /      \
 //  3--------2
 P2DPoint* splinePoints;
 P2DPoint* splinePointsSrc;
 P2DPoint* massPoints;
 double* massPointMass;
 bool* triangulated;
 int pointCount;
 int massPointCount;
 };
 
class DLLIMPORT P2DEffect
 {
 public:
 P2DEffect() { disabled = false; };
 virtual void ApplyEffect(P2DPhysics* ph, P2DObject* obj, double step) = 0;
 bool disabled;
 };

class DLLIMPORT P2DGravity : public P2DEffect
 {
 public:
 P2DGravity(double strength);
 void ApplyEffect(P2DPhysics* ph, P2DObject* obj, double step);
 
 private:
 double strength;
 };

class DLLIMPORT P2DEnvResistance : public P2DEffect
 {
 public:
 P2DEnvResistance(double strength);
 void ApplyEffect(P2DPhysics* ph, P2DObject* obj, double step);
 
 private:
 double strength;
 };
 
class DLLIMPORT P2DPhysics
 {
 public:
 P2DPhysics();
 ~P2DPhysics();
 void CalcStep(double step);
 void ApplyForce(P2DObject* obj, double direction, double strength);
 int AddObject(P2DObject* obj);
 int AddEffect(P2DEffect* obj);
 void InitObject(P2DObject* obj, int pointCount, int massPointCount, double mass, bool unyielding = false);
       
 private:
 P2DObject* object[MAXOBJECTS];
 int maxObjects;
 P2DEffect* effect[MAXEFFECTS];
 int maxEffects;
 double gravity;
 void ApplyTransform(P2DObject* obj);
 int FindNextTri(P2DObject* obj, int v, bool next);
 bool LinesCrossing(P2DPoint p1, P2DPoint p2, P2DPoint p3, P2DPoint p4, bool includeBorder);
 PTL PointToLine(P2DPoint p, P2DPoint ls, P2DPoint le);
 PTP PointInPolygon(P2DPoint a, P2DObject p);
 ETR EdgeToRay (P2DPoint a, P2DPoint v, P2DPoint w);
 bool PointInTriangle (P2DPoint p, P2DPoint a, P2DPoint b, P2DPoint c);
 void FindCenterOfMass(P2DObject* obj);
 };
#endif
