#ifndef SE_INCL_WORLDRAYCASTING_H
#define SE_INCL_WORLDRAYCASTING_H
#ifdef PRAGMA_ONCE
  #pragma once
#endif

#include <Engine/Math/Vector.h>
#include <Engine/Math/Placement.h>

/*
 * Class that describes casting of a ray.
 */
class ENGINE_API CCastRay {
public:
  // diferent types of testing
  enum TestType {
    TT_NONE,            // do not test at all
    TT_SIMPLE,          // do approximate testing
    TT_COLLISIONBOX,    // do testing by collision box
    TT_FULL,            // do full testing
    TT_FULLSEETHROUGH,  // do full testing without entities marked as see through
  };
public:
  BOOL cr_bAllowOverHit;                // set if the ray can hit behind its target
  ULONG cr_ulPassablePolygons;          // flags mask for pass-through testing
  CBrushPolygon *cr_pbpoIgnore;         // polygon that is origin of the continuted ray (is never hit by the ray)
  CEntity *cr_penIgnore;                // entity that is origin of the continuted ray (is never hit by the ray)

  /* Internal construction helper. */
  void Init(CEntity *penOrigin, const FLOAT3D &vOrigin, const FLOAT3D &vTarget);
  void ClearSectorList(void);

  /* Add a sector if needed. */
  inline void AddSector(CBrushSector *pbsc);
  /* Add all sectors of a brush. */
  void AddAllSectorsOfBrush(CBrush3D *pbr);
  /* Add all sectors around given entity. */
  void AddSectorsAroundEntity(CEntity *pen);

  /* Test against a model entity. */
  void TestModelSimple(CEntity *penModel, CModelObject &mo);
  void TestModelCollisionBox(CEntity *penModel, CModelObject &mo);
  void TestModelFull(CEntity *penModel, CModelObject &mo);
  void TestModel(CEntity *penModel);
  /* Test against a brush sector. */
  void TestBrushSector(CBrushSector *pbscSector);

  /* Test entire world against ray. */
  void TestWholeWorld(CWorld *pwoWorld);
  /* Test active sectors recusively. */
  void TestThroughSectors(void);
  

public:
// these are filled by the constructor:
  CPlacement3D cl_plRay;      // placement of the ray in absolute space
  CEntity *cr_penOrigin;      // entity that is origin of the ray (is never hit by the ray)
  FLOAT3D cr_vOrigin;         // coordinates of ray origin
  FLOAT3D cr_vTarget;         // coordinates of ray target
  FLOAT3D cr_vOriginRelative; // coordinates of ray origin relative to current entity
  FLOAT3D cr_vTargetRelative; // coordinates of ray target relative to current entity

// these can be altered afterwards for special options
  BOOL cr_bHitPortals;            // don't pass through portals (off by default)
  BOOL cr_bHitTranslucentPortals; // don't pass through translucent portals (on by default)
  enum TestType cr_ttHitModels;   // type of testing against models (simple by default)
  BOOL cr_bHitFields;             // don't pass thrugh field brushes (off by default)
  BOOL cr_bPhysical;              // pass only where physical objects can pass
  FLOAT cr_fTestR;                // additional radius of ray (default 0)

// these are filled by casting algorithm:
  CEntity *cr_penHit;         // entity hit by ray, NULL if ray was cast in void
  FLOAT3D cr_vHit;            // coordinate where the ray hit the entity
  FLOAT cr_fHitDistance;      // how far the hit was from the origin

  CBrushPolygon *cr_pbpoBrushPolygon;   // polygon that was hit (if brush entity hit)
  CBrushSector *cr_pbscBrushSector;     // sector that was hit (if brush entity hit)

  /* Constructor. */
  CCastRay(CEntity *penOrigin, const CPlacement3D &plOrigin); // target is very far away
  CCastRay(CEntity *penOrigin, const CPlacement3D &plOrigin, FLOAT fMaxTestDistance);
  CCastRay(CEntity *penOrigin, const FLOAT3D &vOrigin, const FLOAT3D &vTarget);
  ~CCastRay(void);

  /* Do the ray casting. */
  void Cast(CWorld *pwoWorld);
  /* Continue cast. */
  void ContinueCast(CWorld *pwoWorld);
};


#endif  /* include-once check. */

