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