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__