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 fow.h - The fog of war headerfile. */
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 #ifndef __FOW_H__
31 #define __FOW_H__
32
33 #include <cstdint>
34 #include <vector>
35 #include "fow_utils.h"
36 #include "map.h"
37 #include "player.h"
38 #include "settings.h"
39 #include "video.h"
40
41 //@{
42
43
44 /*----------------------------------------------------------------------------
45 -- Declarations
46 ----------------------------------------------------------------------------*/
47 enum class FogOfWarTypes { cTiled, cEnhanced, cTiledLegacy, cNumOfTypes }; /// Types of the fog of war
48 class CFogOfWar
49 {
50 public:
CFogOfWar()51 CFogOfWar()
52 {
53 SetOpacityLevels(this->Settings.ExploredOpacity, this->Settings.RevealedOpacity, this->Settings.UnseenOpacity);
54 }
55
56 enum VisionType { cUnseen = 0, cExplored = 0b001, cVisible = 0b010 };
57 enum States { cFirstEntry = 0, cGenerateFog, cGenerateTexture, cBlurTexture, cReady };
58 enum UpscaleTypes { cSimple = 0, cBilinear };
59
60 static void SetTiledFogGraphic(const std::string &fogGraphicFile);
61
62 void Init();
63 void Clean(const bool isHardClean = false);
64 bool SetType(const FogOfWarTypes fowType);
65 void SetOpacityLevels(const uint8_t explored, const uint8_t revealed, const uint8_t unseen);
66
GetType()67 FogOfWarTypes GetType() const { return Settings.Type; }
68
GetFogColor()69 CColor GetFogColor() const { return Settings.FogColor; }
GetFogColorSDL()70 uint32_t GetFogColorSDL() const { return Settings.FogColorSDL; }
GetExploredOpacity()71 uint8_t GetExploredOpacity() const { return Settings.ExploredOpacity; }
GetRevealedOpacity()72 uint8_t GetRevealedOpacity() const { return Settings.RevealedOpacity; }
GetUnseenOpacity()73 uint8_t GetUnseenOpacity() const { return Settings.UnseenOpacity; }
74
ShowVisionFor(const CPlayer & player)75 void ShowVisionFor(const CPlayer &player) { VisionFor.insert(player.Index); }
HideVisionFor(const CPlayer & player)76 void HideVisionFor(const CPlayer &player) { VisionFor.erase(player.Index); }
77
78 void SetFogColor(const uint8_t r, const uint8_t g, const uint8_t b);
79 void SetFogColor(const CColor color);
80
81 void EnableBilinearUpscale(const bool enable);
IsBilinearUpscaleEnabled()82 bool IsBilinearUpscaleEnabled() const { return Settings.UpscaleType == UpscaleTypes::cBilinear; }
83 void InitBlurer(const float radius1, const float radius2, const uint16_t numOfIterations);
84
85 void Update(bool doAtOnce = false);
86 void Draw(CViewport &viewport);
87
88 uint8_t GetVisibilityForTile(const Vec2i tilePos) const;
89
90 private:
91 void InitEnhanced();
92 void DrawEnhanced(CViewport &viewport);
93
94 void GenerateUpscaleTables(uint32_t (*table)[4], const uint8_t alphaFrom, const uint8_t alphaTo);
95
96 void GenerateFog();
97 void FogUpscale4x4();
98
99 uint8_t DeterminePattern(const size_t index, const uint8_t visFlag) const;
100 void FillUpscaledRec(uint32_t *texture, const uint16_t textureWidth, size_t index,
101 const uint8_t patternVisible, const uint8_t patternExplored) const;
102
103 void UpscaleBilinear(const uint8_t *const src, const SDL_Rect &srcRect, const int16_t srcWidth,
104 SDL_Surface *const trgSurface, const SDL_Rect &trgRect) const;
105
106 void UpscaleSimple(const uint8_t *src, const SDL_Rect &srcRect, const int16_t srcWidth,
107 SDL_Surface *const trgSurface, const SDL_Rect &trgRect) const;
108
109 void InitTiled();
110 void CleanTiled(const bool isHardClean = false);
111
112 void DrawFullShroudOfFog(const int16_t x, const int16_t y, const uint8_t alpha,
113 SDL_Surface *const vpFogSurface);
114 void GetFogTile(const size_t visIndex, const size_t mapIndex, const size_t mapIndexBase,
115 int *fogTile, int *blackFogTile) const;
IsMapFieldExplored(const size_t index)116 bool IsMapFieldExplored(const size_t index) const { return (VisTable[index] != 0); }
IsMapFieldVisible(const size_t index)117 bool IsMapFieldVisible(const size_t index) const { return (VisTable[index] > 1); }
118 void DrawFogTile(const size_t visIndex, const size_t mapIndex, const size_t mapIndexBase,
119 const int16_t dx, const int16_t dy, SDL_Surface *const vpFogSurface);
120 void DrawTiled(CViewport &viewport);
121 void DrawTiledLegacy(CViewport &viewport);
122
123 public:
124
125 private:
126 struct FogOfWarSettings
127 {
128 FogOfWarTypes Type {FogOfWarTypes::cEnhanced}; /// Type of fog of war - tiled or enhanced(smooth)
129 uint8_t NumOfEasingSteps {8}; /// Number of the texture easing steps
130 float BlurRadius[2] {2.0, 1.5}; /// Radiuses or standard deviation
131 uint8_t BlurIterations {3}; /// Number of blur iterations
132 uint8_t UpscaleType {UpscaleTypes::cSimple}; /// Rendering zoom type
133 CColor FogColor {0, 0, 0, 0}; /// Fog of war color
134 uint32_t FogColorSDL {0}; /// Fog of war color in the SDL format
135 uint8_t ExploredOpacity {0x7F};
136 uint8_t RevealedOpacity {0xBE};
137 uint8_t UnseenOpacity {0xFE};
138 } Settings; /// Fog of war settings
139
140 uint8_t State { States::cFirstEntry }; /// State of the fog of war calculation process
141
142 std::set<uint8_t> VisionFor; /// Visibilty through the fog is generated for this players
143 /// ThisPlayer and his allies in normal games
144 /// Any set of players for observers and in the replays
145
146 static CGraphic *TiledFogSrc; /// Graphic for tiled fog of war
147 CGraphic *TiledAlphaFog {nullptr}; /// Working set of graphic for tiled fog of war with alpha channel
148 SDL_Surface *TileOfFogOnly {nullptr}; /// Tile contains only fog. Used for legacy rendering of tiled fog
149
150 /**
151 ** Mapping for fog of war tiles.
152 */
153 const int TiledFogTable[16] = {0, 11, 10, 2, 13, 6, 14, 3, 12, 15, 4, 1, 8, 9, 7, 0};
154
155 std::vector<uint8_t> VisTable; /// vision table for whole map + 1 tile around (for simplification of upscale algorithm purposes)
156 size_t VisTable_Index0 {0}; /// index in the vision table for [0:0] map tile
157 size_t VisTableWidth {0}; /// width of the vision table
158 CEasedTexture FogTexture; /// Upscaled fog texture (alpha-channel values only) for whole map
159 /// + 1 tile to the left and up (for simplification of upscale algorithm purposes).
160 std::vector<uint8_t> RenderedFog; /// Back buffer for bilinear upscaling in to viewports
161 CBlurer Blurer; /// Blurer for fog of war texture
162
163 /// Tables with patterns to generate fog of war texture from vision table
164 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
165 const uint32_t UpscaleTable_4x4[16][4] { {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, // 0 00:00
166 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x007FFFFF}, // 1 00:01
167 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFF7F, 0xFFFF7F00}, // 2 00:10
168 {0xFFFFFFFF, 0xFFFFFFFF, 0x7F7F7F7F, 0x00000000}, // 3 00:11
169 {0x007FFFFF, 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, // 4 01:00
170 {0x007FFFFF, 0x007FFFFF, 0x007FFFFF, 0x007FFFFF}, // 5 01:01
171 {0x007FFFFF, 0x7FFFFFFF, 0xFFFFFF7F, 0xFFFF7F00}, // 6 01:10
172 {0x00007FFF, 0x0000007F, 0x00000000, 0x00000000}, // 7 01:11
173 {0xFFFF7F00, 0xFFFFFF7F, 0xFFFFFFFF, 0xFFFFFFFF}, // 8 10:00
174 {0xFFFF7F00, 0xFFFFFF7F, 0x7FFFFFFF, 0x007FFFFF}, // 9 10:01
175 {0xFFFF7F00, 0xFFFF7F00, 0xFFFF7F00, 0xFFFF7F00}, // A 10:10
176 {0xFF7F0000, 0x7F000000, 0x00000000, 0x00000000}, // B 10:11
177 {0x00000000, 0x7F7F7F7F, 0xFFFFFFFF, 0xFFFFFFFF}, // C 11:00
178 {0x00000000, 0x00000000, 0x0000007F, 0x00007FFF}, // D 11:01
179 {0x00000000, 0x00000000, 0x7F000000, 0xFF7F0000}, // E 11:10
180 {0x00000000, 0x00000000, 0x00000000, 0x00000000} }; // F 11:11
181
182 #else // big endian
183 const uint32_t UpscaleTable_4x4[16][4] { {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, // 0 00:00
184 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFF7F, 0xFFFF7F00}, // 1 00:01
185 {0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0x007FFFFF}, // 2 00:10
186 {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000}, // 3 00:11
187 {0xFFFF7F00, 0xFFFFFF7F, 0xFFFFFFFF, 0xFFFFFFFF}, // 4 01:00
188 {0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000}, // 5 01:01
189 {0xFFFF7F00, 0xFFFFFF7F, 0x7FFFFFFF, 0x007FFFFF}, // 6 01:10
190 {0xFF7F0000, 0x7F000000, 0x00000000, 0x00000000}, // 7 01:11
191 {0x007FFFFF, 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, // 8 10:00
192 {0x007FFFFF, 0x7FFFFFFF, 0xFFFFFF7F, 0xFFFF7F00}, // 9 10:01
193 {0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF}, // A 10:10
194 {0x00007FFF, 0x0000007F, 0x00000000, 0x00000000}, // B 10:11
195 {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}, // C 11:00
196 {0x00000000, 0x00000000, 0x7F000000, 0xFF7F0000}, // D 11:01
197 {0x00000000, 0x00000000, 0x0000007F, 0x00007FFF}, // E 11:10
198 {0x00000000, 0x00000000, 0x00000000, 0x00000000} }; // F 11:11
199 #endif
200
201 uint32_t UpscaleTableVisible[16][4] = {}; /// It will be generated from UpscaleTable_4x4
202 uint32_t UpscaleTableExplored[16][4] = {}; /// It will be generated from UpscaleTable_4x4
203 uint32_t UpscaleTableRevealed[16][4] = {}; /// It will be generated from UpscaleTable_4x4
204 const uint32_t (*CurrUpscaleTableExplored)[4] = UpscaleTableVisible;
205 };
206
207 extern CFogOfWar FogOfWar;
208
209
210 /**
211 ** Determine upscale patterns (index in the upscale table) for Visible and Explored layers
212 **
213 ** @param index tile in the vision table
214 ** @param visFlag layer to determine pattern for
215 **
216 */
DeterminePattern(const size_t index,const uint8_t visFlag)217 inline uint8_t CFogOfWar::DeterminePattern(const size_t index, const uint8_t visFlag) const
218 {
219 Assert(visFlag == VisionType::cVisible || visFlag == (VisionType::cExplored | VisionType::cVisible));
220
221 uint8_t n1, n2, n3, n4;
222 size_t offset = index;
223
224 n1 = (visFlag & VisTable[offset]);
225 n2 = (visFlag & VisTable[offset + 1]);
226 offset += VisTableWidth;
227 n3 = (visFlag & VisTable[offset]);
228 n4 = (visFlag & VisTable[offset + 1]);
229
230 n1 >>= n1 - VisionType::cExplored;
231 n2 >>= n2 - VisionType::cExplored;
232 n3 >>= n3 - VisionType::cExplored;
233 n4 >>= n4 - VisionType::cExplored;
234
235 return ( (n1 << 3) | (n2 << 2) | (n3 << 1) | n4 );
236 }
237
238 /**
239 ** Fill 4x4 sized tile in the fog texture according to the patterns
240 **
241 ** @param texture pointer to the texture to fill
242 ** @param textureWidth width of the texture
243 ** @param index index of the tile to fill
244 ** @param patternVisible index int the upscale table for Visible layer
245 ** @param patternExplored index int the upscale table for Explored layer
246 **
247 */
FillUpscaledRec(uint32_t * texture,const uint16_t textureWidth,size_t index,const uint8_t patternVisible,const uint8_t patternExplored)248 inline void CFogOfWar::FillUpscaledRec(uint32_t *texture, const uint16_t textureWidth, size_t index,
249 const uint8_t patternVisible, const uint8_t patternExplored) const
250 {
251 for (uint8_t scan_line = 0; scan_line < 4; scan_line++) {
252 texture[index] = UpscaleTableVisible[patternVisible][scan_line] + CurrUpscaleTableExplored[patternExplored][scan_line];
253 index += textureWidth;
254 }
255 }
256
GetVisibilityForTile(const Vec2i tilePos)257 inline uint8_t CFogOfWar::GetVisibilityForTile(const Vec2i tilePos) const
258 {
259 return VisTable[VisTable_Index0 + tilePos.x + VisTableWidth * tilePos.y];
260 }
261 #endif // !__FOW_H__
262