1 // _________ __ __
2 // / _____// |_____________ _/ |______ ____ __ __ ______
3 // \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
4 // / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
5 // /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
6 // \/ \/ \//_____/ \/
7 // ______________________ ______________________
8 // T H E W A R B E G I N S
9 // Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name fov.h - The field of view header file. */
12 //
13 // (c) Copyright 2020-2021 by Alyokhin
14 //
15 // This program is free software; you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation; only version 2 of the License.
18 //
19 // This program is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 // GNU General Public License for more details.
23 //
24 // You should have received a copy of the GNU General Public License
25 // along with this program; if not, write to the Free Software
26 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 // 02111-1307, USA.
28 //
29
30 //@{
31
32 #ifndef __FOV_H__
33 #define __FOV_H__
34
35 #include <functional>
36 #include <queue>
37 #include <set>
38 #include "vec2i.h"
39 #include "map.h"
40 #include "tileset.h"
41
42
43 /// Select algorithm for field of view
44 enum class FieldOfViewTypes { cShadowCasting, cSimpleRadial, NumOfTypes };
45
46 class CFieldOfView
47 {
48 public:
Clean()49 void Clean()
50 {
51 MarkedTilesCache.clear();
52 }
53
54 /// Refresh field of view
55 void Refresh(const CPlayer &player, const CUnit &unit, const Vec2i &pos, const uint16_t width,
56 const uint16_t height, const uint16_t range, MapMarkerFunc *marker);
57
58 bool SetType(const FieldOfViewTypes fov_type);
59 FieldOfViewTypes GetType() const;
60
61 /// Set opaque map field flags (which fields will be opaque)
62 void SetOpaqueFields(const uint16_t flags);
63 uint16_t GetOpaqueFields() const;
64 /// Reset opaque flags to default (MapFieldOpaque)
65 void ResetAdditionalOpaqueFields();
66
67 protected:
68 private:
69 /// Struct for portion of column. Used in FoV calculations
70 struct SColumnPiece {
SColumnPieceSColumnPiece71 SColumnPiece(int16_t xValue, Vec2i top, Vec2i bottom) : col(xValue), TopVector(top), BottomVector(bottom) {}
72 int16_t col;
73 Vec2i TopVector;
74 Vec2i BottomVector;
75 };
76
77 /// Calc whole simple radial field of view
78 void ProceedSimpleRadial(const CPlayer &player, const Vec2i &pos, const int16_t w, const int16_t h,
79 int16_t range, MapMarkerFunc *marker) const;
80 /// Calc whole chadow casting field of view
81 void ProceedShadowCasting(const Vec2i &spectatorPos, const uint16_t width, const uint16_t height, const uint16_t range);
82 /// Calc field of view for set of lines along x or y.
83 /// Used for calc part of FoV for assymetric (widht != height) spectators.
84 void ProceedRaysCast(const uint8_t octant, const Vec2i &origin, const uint16_t width, const uint16_t range);
85 /// Calc shadow casting field of view for single octant
86 void RefreshOctant(const uint8_t octant, const Vec2i &origin, const uint16_t range);
87 /// Calc shadow casting for portion of column
88 void CalcFoVForColumnPiece(const int16_t col, Vec2i &topVector, Vec2i &bottomVector,
89 const uint16_t range, std::queue<SColumnPiece> &wrkQueue);
90 /// Recalculate top or bottom direction vectors
91 int16_t CalcRow_ByVector(const bool isTop, const int16_t x, const Vec2i &vector) const;
92
93 /// Recalculate coordinates and set current MapTile for [col, row]
94 bool SetCurrentTile(const int16_t col, const int16_t row);
95 /// Check if current MapTile opaque
96 bool IsTileOpaque() const;
97 /// Mark current MapTile
98 void MarkTile();
99
100 /// Setup ShadowCaster for current refreshing of FoV
101 void PrepareShadowCaster(const CPlayer &player, const CUnit &unit, const Vec2i &pos, MapMarkerFunc *marker);
102 void ResetShadowCaster();
103 void PrepareCache(const Vec2i pos, const uint16_t width, const uint16_t height, const uint16_t range);
104
105 /// Update values of Octant and Origin for current working set
106 void SetEnvironment(const uint8_t octant, const Vec2i &origin);
107 void ResetEnvironment();
108 /// Project [col,row] coordinates from current octant to global (Map) coordinate system and accordingly update position of current MapTile
109 void ProjectCurrentTile(const int16_t col, const int16_t row);
110
111 private:
112 struct FieldOfViewSettings
113 {
114 FieldOfViewTypes Type {FieldOfViewTypes::cSimpleRadial}; /// Type of field of view - Shadowcasting or Simple Radial
115 uint16_t OpaqueFields {MapFieldOpaque}; /// Flags for opaque MapFields
116 } Settings;
117
118 Vec2i currTilePos {0, 0}; /// Current work tile pos in global (Map) system coordinates
119 uint8_t currOctant {0}; /// Current octant
120 Vec2i Origin {0, 0}; /// Position of the spectator in the global (Map) coordinate system
121 uint16_t OpaqueFields {0}; /// Flags for opaque MapTiles for current calculation
122
123 const CPlayer *Player {nullptr}; /// Pointer to player to set FoV for
124 const CUnit *Unit {nullptr}; /// Pointer to unit to calculate FoV for
125 MapMarkerFunc *map_setFoV {nullptr}; /// Pointer to external function for setting tiles visibilty
126
127 std::vector<uint8_t> MarkedTilesCache; /// To prevent multiple calls of map_setFoV for single tile (for tiles on the vertical,
128 /// horizontal and diagonal lines it calls twise) we use cache table to
129 /// count already marked tiles
130 };
131
132 /*----------------------------------------------------------------------------
133 -- Variables
134 ----------------------------------------------------------------------------*/
135
136 extern CFieldOfView FieldOfView;
137
138 /*----------------------------------------------------------------------------
139 -- Functions
140 ----------------------------------------------------------------------------*/
141
SetCurrentTile(const int16_t col,const int16_t row)142 inline bool CFieldOfView::SetCurrentTile(const int16_t col, const int16_t row)
143 {
144 ProjectCurrentTile(col, row);
145 if (Map.Info.IsPointOnMap(currTilePos.x, currTilePos.y)) {
146 return true;
147 } else {
148 currTilePos = {0, 0};
149 return false;
150 }
151 }
152
IsTileOpaque()153 inline bool CFieldOfView::IsTileOpaque() const
154 {
155 /// FIXME: add high-/lowground
156 return (Map.Field(currTilePos.x, currTilePos.y)->Flags & OpaqueFields);
157 }
158
MarkTile()159 inline void CFieldOfView::MarkTile()
160 {
161 const size_t index = Map.getIndex(currTilePos.x, currTilePos.y);
162 if (!MarkedTilesCache[index]) {
163 map_setFoV(*Player, index);
164 MarkedTilesCache[index] = 1;
165 }
166 }
167
ProjectCurrentTile(const int16_t col,const int16_t row)168 inline void CFieldOfView::ProjectCurrentTile(const int16_t col, const int16_t row)
169 {
170 switch (currOctant) {
171 case 1: currTilePos.x = row; currTilePos.y = col; break;
172 case 2: currTilePos.x = -row; currTilePos.y = col; break;
173 case 3: currTilePos.x = -col; currTilePos.y = row; break;
174 case 4: currTilePos.x = -col; currTilePos.y = -row; break;
175 case 5: currTilePos.x = -row; currTilePos.y = -col; break;
176 case 6: currTilePos.x = row; currTilePos.y = -col; break;
177 case 7: currTilePos.x = col; currTilePos.y = -row; break;
178 default: currTilePos.x = col; currTilePos.y = row;
179 }
180 currTilePos += Origin;
181 }
182 //@}
183
184 #endif // !__FOV_H__