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 minimap.cpp - The minimap source file. */
12 //
13 //      (c) Copyright 1998-2019 by Lutz Sammer and Jimmy Salmon, Pali Rohár and Andrettin
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 /*----------------------------------------------------------------------------
33 --  Includes
34 ----------------------------------------------------------------------------*/
35 
36 #include <string.h>
37 
38 #include "stratagus.h"
39 
40 #include "map/minimap.h"
41 
42 #include "editor.h"
43 #include "map/map.h"
44 #include "map/map_layer.h"
45 #include "map/terrain_type.h"
46 #include "map/tileset.h"
47 #include "plane.h"
48 #include "player.h"
49 #include "province.h"
50 #include "ui/ui.h"
51 #include "unit/unit.h"
52 #include "unit/unit_manager.h"
53 #include "unit/unittype.h"
54 #include "video.h"
55 #include "world.h"
56 
57 /*----------------------------------------------------------------------------
58 --  Defines
59 ----------------------------------------------------------------------------*/
60 
61 #define MINIMAP_FAC (16 * 3)  /// integer scale factor
62 
63 /// unit attacked are shown red for at least this amount of cycles
64 #define ATTACK_RED_DURATION (1 * CYCLES_PER_SECOND)
65 /// unit attacked are shown blinking for this amount of cycles
66 #define ATTACK_BLINK_DURATION (7 * CYCLES_PER_SECOND)
67 
68 #define SCALE_PRECISION 100
69 
70 
71 /*----------------------------------------------------------------------------
72 --  Variables
73 ----------------------------------------------------------------------------*/
74 
75 //Wyrmgus start
76 //SDL_Surface *MinimapSurface;        /// generated minimap
77 //SDL_Surface *MinimapTerrainSurface; /// generated minimap terrain
78 std::vector<SDL_Surface *> MinimapSurface;        /// generated minimap
79 std::vector<SDL_Surface *> MinimapTerrainSurface; /// generated minimap terrain
80 //Wyrmgus end
81 
82 #if defined(USE_OPENGL) || defined(USE_GLES)
83 //Wyrmgus start
84 //unsigned char *MinimapSurfaceGL;
85 //unsigned char *MinimapTerrainSurfaceGL;
86 std::vector<unsigned char *> MinimapSurfaceGL;
87 std::vector<unsigned char *> MinimapTerrainSurfaceGL;
88 //Wyrmgus end
89 
90 //Wyrmgus start
91 //static GLuint MinimapTexture;
92 //static int MinimapTextureWidth;
93 //static int MinimapTextureHeight;
94 static std::vector<GLuint> MinimapTexture;
95 static std::vector<int> MinimapTextureWidth;
96 static std::vector<int> MinimapTextureHeight;
97 //Wyrmgus end
98 #endif
99 
100 //Wyrmgus start
101 //static int *Minimap2MapX;                  /// fast conversion table
102 //static int *Minimap2MapY;                  /// fast conversion table
103 //static int Map2MinimapX[MaxMapWidth];      /// fast conversion table
104 //static int Map2MinimapY[MaxMapHeight];     /// fast conversion table
105 static std::vector<int *> Minimap2MapX;                  /// fast conversion table
106 static std::vector<int *> Minimap2MapY;                  /// fast conversion table
107 static std::vector<int *> Map2MinimapX;      /// fast conversion table
108 static std::vector<int *> Map2MinimapY;     /// fast conversion table
109 //Wyrmgus end
110 
111 // MinimapScale:
112 // 32x32 64x64 96x96 128x128 256x256 512x512 ...
113 // *4 *2 *4/3   *1 *1/2 *1/4
114 //Wyrmgus start
115 //static int MinimapScaleX;                  /// Minimap scale to fit into window
116 //static int MinimapScaleY;                  /// Minimap scale to fit into window
117 static std::vector<int> MinimapScaleX;                  /// Minimap scale to fit into window
118 static std::vector<int> MinimapScaleY;                  /// Minimap scale to fit into window
119 //Wyrmgus end
120 
121 #define MAX_MINIMAP_EVENTS 8
122 
123 struct MinimapEvent {
124 	PixelPos pos;
125 	int Size;
126 	Uint32 Color;
127 } MinimapEvents[MAX_MINIMAP_EVENTS];
128 int NumMinimapEvents;
129 
130 
131 /*----------------------------------------------------------------------------
132 -- Functions
133 ----------------------------------------------------------------------------*/
134 
135 
136 #if defined(USE_OPENGL) || defined(USE_GLES)
137 /**
138 **  Create the minimap texture
139 */
140 //Wyrmgus start
141 //static void CreateMinimapTexture()
CreateMinimapTexture(int z)142 static void CreateMinimapTexture(int z)
143 //Wyrmgus end
144 {
145 	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
146 	//Wyrmgus start
147 //	glGenTextures(1, &MinimapTexture);
148 //	glBindTexture(GL_TEXTURE_2D, MinimapTexture);
149 	glGenTextures(1, &MinimapTexture[z]);
150 	glBindTexture(GL_TEXTURE_2D, MinimapTexture[z]);
151 	//Wyrmgus end
152 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
153 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
154 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
155 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
156 	//Wyrmgus start
157 //	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MinimapTextureWidth,
158 //				 MinimapTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
159 //				 MinimapSurfaceGL);
160 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MinimapTextureWidth[z],
161 				 MinimapTextureHeight[z], 0, GL_RGBA, GL_UNSIGNED_BYTE,
162 				 MinimapSurfaceGL[z]);
163 	//Wyrmgus end
164 }
165 #endif
166 
167 /**
168 **  Create a mini-map from the tiles of the map.
169 **
170 **  @todo Scaling and scrolling the minmap is currently not supported.
171 */
Create()172 void CMinimap::Create()
173 {
174 	//Wyrmgus start
175 	/*
176 	// Scale to biggest value.
177 	const int n = std::max(std::max(Map.Info.MapWidth, Map.Info.MapHeight), 32);
178 
179 	MinimapScaleX = (W * MINIMAP_FAC + n - 1) / n;
180 	MinimapScaleY = (H * MINIMAP_FAC + n - 1) / n;
181 
182 	XOffset = (W - (Map.Info.MapWidth * MinimapScaleX) / MINIMAP_FAC + 1) / 2;
183 	YOffset = (H - (Map.Info.MapHeight * MinimapScaleY) / MINIMAP_FAC + 1) / 2;
184 
185 	DebugPrint("MinimapScale %d %d (%d %d), X off %d, Y off %d\n" _C_
186 			   MinimapScaleX / MINIMAP_FAC _C_ MinimapScaleY / MINIMAP_FAC _C_
187 			   MinimapScaleX _C_ MinimapScaleY _C_
188 			   XOffset _C_ YOffset);
189 
190 	//
191 	// Calculate minimap fast lookup tables.
192 	//
193 	Minimap2MapX = new int[W * H];
194 	memset(Minimap2MapX, 0, W * H * sizeof(int));
195 	Minimap2MapY = new int[W * H];
196 	memset(Minimap2MapY, 0, W * H * sizeof(int));
197 	for (int i = XOffset; i < W - XOffset; ++i) {
198 		Minimap2MapX[i] = ((i - XOffset) * MINIMAP_FAC) / MinimapScaleX;
199 	}
200 	for (int i = YOffset; i < H - YOffset; ++i) {
201 		Minimap2MapY[i] = (((i - YOffset) * MINIMAP_FAC) / MinimapScaleY) * Map.Info.MapWidth;
202 	}
203 	for (int i = 0; i < Map.Info.MapWidth; ++i) {
204 		Map2MinimapX[i] = (i * MinimapScaleX) / MINIMAP_FAC;
205 	}
206 	for (int i = 0; i < Map.Info.MapHeight; ++i) {
207 		Map2MinimapY[i] = (i * MinimapScaleY) / MINIMAP_FAC;
208 	}
209 
210 	// Palette updated from UpdateMinimapTerrain()
211 #if defined(USE_OPENGL) || defined(USE_GLES)
212 	if (UseOpenGL) {
213 		for (MinimapTextureWidth = 1; MinimapTextureWidth < W; MinimapTextureWidth <<= 1) {
214 		}
215 		for (MinimapTextureHeight = 1; MinimapTextureHeight < H; MinimapTextureHeight <<= 1) {
216 		}
217 		MinimapTerrainSurfaceGL = new unsigned char[MinimapTextureWidth * MinimapTextureHeight * 4];
218 		MinimapSurfaceGL = new unsigned char[MinimapTextureWidth * MinimapTextureHeight * 4];
219 		memset(MinimapSurfaceGL, 0, MinimapTextureWidth * MinimapTextureHeight * 4);
220 		CreateMinimapTexture();
221 	} else
222 #endif
223 	{
224 		SDL_PixelFormat *f = Map.TileGraphic->Surface->format;
225 		//Wyrmgus start
226 //		MinimapTerrainSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, W, H, f->BitsPerPixel, f->Rmask, f->Gmask, f->Bmask, f->Amask);
227 		MinimapTerrainSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, W, H, 32, TheScreen->format->Rmask, TheScreen->format->Gmask, TheScreen->format->Bmask, 0);
228 		//Wyrmgus end
229 		MinimapSurface = SDL_CreateRGBSurface(SDL_SWSURFACE,  W, H, 32, TheScreen->format->Rmask, TheScreen->format->Gmask, TheScreen->format->Bmask, 0);
230 	}
231 
232 	UpdateTerrain();
233 	*/
234 #if defined(USE_OPENGL) || defined(USE_GLES)
235 	MinimapTexture.resize(Map.MapLayers.size());
236 	MinimapTextureWidth.resize(Map.MapLayers.size());
237 	MinimapTextureHeight.resize(Map.MapLayers.size());
238 #endif
239 	for (size_t z = 0; z < Map.MapLayers.size(); ++z) {
240 		// Scale to biggest value.
241 		const int n = std::max(std::max(Map.Info.MapWidths[z], Map.Info.MapHeights[z]), 32);
242 
243 		MinimapScaleX.push_back((W * MINIMAP_FAC + n - 1) / n);
244 		MinimapScaleY.push_back((H * MINIMAP_FAC + n - 1) / n);
245 
246 		XOffset.push_back((W - (Map.Info.MapWidths[z] * MinimapScaleX[z]) / MINIMAP_FAC + 1) / 2);
247 		YOffset.push_back((H - (Map.Info.MapHeights[z] * MinimapScaleY[z]) / MINIMAP_FAC + 1) / 2);
248 
249 		DebugPrint("MinimapScale %d %d (%d %d), X off %d, Y off %d\n" _C_
250 				   MinimapScaleX[z] / MINIMAP_FAC _C_ MinimapScaleY[z] / MINIMAP_FAC _C_
251 				   MinimapScaleX[z] _C_ MinimapScaleY[z] _C_
252 				   XOffset[z] _C_ YOffset[z]);
253 
254 		//
255 		// Calculate minimap fast lookup tables.
256 		//
257 		Minimap2MapX.push_back(new int[W * H]);
258 		memset(Minimap2MapX[z], 0, W * H * sizeof(int));
259 		Minimap2MapY.push_back(new int[W * H]);
260 		memset(Minimap2MapY[z], 0, W * H * sizeof(int));
261 		for (int i = XOffset[z]; i < W - XOffset[z]; ++i) {
262 			Minimap2MapX[z][i] = ((i - XOffset[z]) * MINIMAP_FAC) / MinimapScaleX[z];
263 		}
264 		for (int i = YOffset[z]; i < H - YOffset[z]; ++i) {
265 			Minimap2MapY[z][i] = (((i - YOffset[z]) * MINIMAP_FAC) / MinimapScaleY[z]) * Map.Info.MapWidths[z];
266 		}
267 		Map2MinimapX.push_back(new int[Map.Info.MapWidths[z]]);
268 		memset(Map2MinimapX[z], 0, Map.Info.MapWidths[z] * sizeof(int));
269 		Map2MinimapY.push_back(new int[Map.Info.MapHeights[z]]);
270 		memset(Map2MinimapY[z], 0, Map.Info.MapHeights[z] * sizeof(int));
271 		for (int i = 0; i < Map.Info.MapWidths[z]; ++i) {
272 			Map2MinimapX[z][i] = (i * MinimapScaleX[z]) / MINIMAP_FAC;
273 		}
274 		for (int i = 0; i < Map.Info.MapHeights[z]; ++i) {
275 			Map2MinimapY[z][i] = (i * MinimapScaleY[z]) / MINIMAP_FAC;
276 		}
277 
278 		// Palette updated from UpdateMinimapTerrain()
279 	#if defined(USE_OPENGL) || defined(USE_GLES)
280 		if (UseOpenGL) {
281 			for (MinimapTextureWidth[z] = 1; MinimapTextureWidth[z] < W; MinimapTextureWidth[z] <<= 1) {
282 			}
283 			for (MinimapTextureHeight[z] = 1; MinimapTextureHeight[z] < H; MinimapTextureHeight[z] <<= 1) {
284 			}
285 			MinimapTerrainSurfaceGL.push_back(new unsigned char[MinimapTextureWidth[z] * MinimapTextureHeight[z] * 4]);
286 			MinimapSurfaceGL.push_back(new unsigned char[MinimapTextureWidth[z] * MinimapTextureHeight[z] * 4]);
287 			memset(MinimapSurfaceGL[z], 0, MinimapTextureWidth[z] * MinimapTextureHeight[z] * 4);
288 			CreateMinimapTexture(z);
289 		} else
290 	#endif
291 		{
292 			SDL_PixelFormat *f = TheScreen->format;
293 			MinimapTerrainSurface.push_back(SDL_CreateRGBSurface(SDL_SWSURFACE, W, H, 32, RMASK, GMASK, BMASK, AMASK));
294 			MinimapSurface.push_back(SDL_CreateRGBSurface(SDL_SWSURFACE,  W, H, 32, f->Rmask, f->Gmask, f->Bmask, 0));
295 		}
296 
297 		UpdateTerrain(z);
298 	}
299 	//Wyrmgus end
300 
301 	NumMinimapEvents = 0;
302 }
303 
304 #if defined(USE_OPENGL) || defined(USE_GLES)
305 /**
306 **  Free OpenGL minimap
307 */
FreeOpenGL()308 void CMinimap::FreeOpenGL()
309 {
310 	//Wyrmgus start
311 //	glDeleteTextures(1, &MinimapTexture);
312 	for (size_t z = 0; z < MinimapTexture.size(); ++z) {
313 		glDeleteTextures(1, &MinimapTexture[z]);
314 	}
315 	MinimapTexture.clear();
316 	//Wyrmgus end
317 }
318 
319 /**
320 **  Reload OpenGL minimap
321 */
Reload()322 void CMinimap::Reload()
323 {
324 	//Wyrmgus start
325 //	CreateMinimapTexture();
326 	for (size_t z = 0; z < Map.MapLayers.size(); ++z) {
327 		CreateMinimapTexture(z);
328 	}
329 	//Wyrmgus end
330 }
331 #endif
332 
333 /**
334 **  Calculate the tile graphic pixel
335 */
336 //Wyrmgus start
337 //static inline Uint8 *GetTileGraphicPixel(int xofs, int yofs, int mx, int my, int scalex, int scaley, int bpp)
GetTileGraphicPixel(int xofs,int yofs,int mx,int my,int scalex,int scaley,int bpp,int z,CTerrainType * terrain,const CSeason * season)338 static inline Uint8 *GetTileGraphicPixel(int xofs, int yofs, int mx, int my, int scalex, int scaley, int bpp, int z, CTerrainType *terrain, const CSeason *season)
339 //Wyrmgus end
340 {
341 	//Wyrmgus start
342 //	Uint8 *pixels = (Uint8 *)Map.TileGraphic->Surface->pixels;
343 	Uint8 *pixels = (Uint8 *)terrain->GetGraphics(season)->Surface->pixels;
344 	//Wyrmgus end
345 	int x = (xofs + 7 + ((mx * SCALE_PRECISION) % scalex) / SCALE_PRECISION * 8);
346 	int y = (yofs + 6 + ((my * SCALE_PRECISION) % scaley) / SCALE_PRECISION * 8);
347 	//Wyrmgus start
348 //	return &pixels[x * bpp + y * Map.TileGraphic->Surface->pitch];
349 	return &pixels[x * bpp + y * terrain->GetGraphics(season)->Surface->pitch];
350 	//Wyrmgus end
351 }
352 
353 /**
354 **  Update a mini-map from the tiles of the map.
355 */
356 //Wyrmgus start
357 //void CMinimap::UpdateTerrain()
UpdateTerrain(int z)358 void CMinimap::UpdateTerrain(int z)
359 //Wyrmgus end
360 {
361 	//Wyrmgus start
362 //	int scalex = MinimapScaleX * SCALE_PRECISION / MINIMAP_FAC;
363 	int scalex = MinimapScaleX[z] * SCALE_PRECISION / MINIMAP_FAC;
364 	//Wyrmgus end
365 	if (!scalex) {
366 		scalex = 1;
367 	}
368 	//Wyrmgus start
369 //	int scaley = MinimapScaleY * SCALE_PRECISION / MINIMAP_FAC;
370 	int scaley = MinimapScaleY[z] * SCALE_PRECISION / MINIMAP_FAC;
371 	//Wyrmgus end
372 	if (!scaley) {
373 		scaley = 1;
374 	}
375 	//Wyrmgus start
376 //	const int bpp = Map.TileGraphic->Surface->format->BytesPerPixel;
377 	//Wyrmgus end
378 
379 	const CSeason *season = Map.MapLayers[z]->GetSeason();
380 
381 #if defined(USE_OPENGL) || defined(USE_GLES)
382 	if (!UseOpenGL)
383 #endif
384 	{
385 		//Wyrmgus start
386 		/*
387 		if (bpp == 1) {
388 			SDL_SetPalette(MinimapTerrainSurface, SDL_LOGPAL,
389 						   Map.TileGraphic->Surface->format->palette->colors, 0, 256);
390 		}
391 		*/
392 		//Wyrmgus end
393 	}
394 
395 	//Wyrmgus start
396 //	const int tilepitch = Map.TileGraphic->Surface->w / Map.GetCurrentPixelTileSize().x;
397 	//Wyrmgus end
398 
399 #if defined(USE_OPENGL) || defined(USE_GLES)
400 	if (UseOpenGL) {
401 		SDL_LockSurface(Map.TileGraphic->Surface);
402 		//Wyrmgus start
403 		for (size_t i = 0; i != CTerrainType::TerrainTypes.size(); ++i) {
404 			if (CTerrainType::TerrainTypes[i]->GetGraphics(season)) {
405 				SDL_LockSurface(CTerrainType::TerrainTypes[i]->GetGraphics(season)->Surface);
406 			}
407 		}
408 		//Wyrmgus end
409 	} else
410 #endif
411 	{
412 		//Wyrmgus start
413 //		SDL_LockSurface(MinimapTerrainSurface);
414 		SDL_LockSurface(MinimapTerrainSurface[z]);
415 		//Wyrmgus end
416 	}
417 
418 	const CMapLayer *map_layer = Map.MapLayers[z];
419 
420 	//
421 	//  Pixel 7,6 7,14, 15,6 15,14 are taken for the minimap picture.
422 	//
423 	for (int my = YOffset[z]; my < H - YOffset[z]; ++my) {
424 		for (int mx = XOffset[z]; mx < W - XOffset[z]; ++mx) {
425 			//Wyrmgus start
426 //			const int tile = Map.Fields[Minimap2MapX[mx] + Minimap2MapY[my]].getGraphicTile();
427 			const CMapField &mf = *map_layer->Field(Minimap2MapX[z][mx] + Minimap2MapY[z][my]);
428 			CTerrainType *terrain = mf.playerInfo.SeenOverlayTerrain ? mf.playerInfo.SeenOverlayTerrain : mf.playerInfo.SeenTerrain;
429 			int tile = mf.playerInfo.SeenOverlayTerrain ? mf.playerInfo.SeenOverlaySolidTile : mf.playerInfo.SeenSolidTile;
430 			if (!terrain) {
431 				terrain = mf.OverlayTerrain ? mf.OverlayTerrain : mf.Terrain;
432 				tile = mf.OverlayTerrain ? mf.OverlaySolidTile : mf.SolidTile;
433 			}
434 
435 			CTerrainType *base_terrain = mf.playerInfo.SeenTerrain;
436 			int base_tile = mf.playerInfo.SeenSolidTile;
437 			if (!base_terrain) {
438 				base_terrain = mf.Terrain;
439 				base_tile = mf.SolidTile;
440 			}
441 			//Wyrmgus end
442 
443 			//Wyrmgus start
444 			int tilepitch = terrain->GetGraphics(season)->Surface->w / Map.GetCurrentPixelTileSize().x;
445 			const int bpp = terrain->GetGraphics(season)->Surface->format->BytesPerPixel;
446 
447 			int base_tilepitch = base_terrain->GetGraphics(season)->Surface->w / Map.GetCurrentPixelTileSize().x;
448 			//assumes the BPP for the base terrain is the same as for the top terrain (which may be an overlay)
449 			//Wyrmgus end
450 
451 			const int xofs = Map.GetCurrentPixelTileSize().x * (tile % tilepitch);
452 			const int yofs = Map.GetCurrentPixelTileSize().y * (tile / tilepitch);
453 
454 			//Wyrmgus start
455 			const int base_xofs = Map.GetCurrentPixelTileSize().x * (base_tile % base_tilepitch);
456 			const int base_yofs = Map.GetCurrentPixelTileSize().y * (base_tile / base_tilepitch);
457 			//Wyrmgus end
458 
459 #if defined(USE_OPENGL) || defined(USE_GLES)
460 			if (UseOpenGL) {
461 				Uint32 c;
462 
463 				if (bpp == 1) {
464 					//Wyrmgus start
465 //					SDL_Color color = Map.TileGraphic->Surface->format->palette->colors[
466 //										  *GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp)];
467 					SDL_Color color = terrain->GetGraphics(season)->Surface->format->palette->colors[
468 										  *GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp, z, terrain, season)];
469 					if (color.r == 255 && color.g == 255 && color.b == 255) { //completely white pixel, presumed to be a transparent one; use base instead
470 						color = base_terrain->GetGraphics(season)->Surface->format->palette->colors[
471 										  *GetTileGraphicPixel(base_xofs, base_yofs, mx, my, scalex, scaley, bpp, z, base_terrain, season)];
472 					}
473 					//Wyrmgus end
474 
475 					c = Video.MapRGB(0, color.r, color.g, color.b);
476 				} else {
477 					//Wyrmgus start
478 //					SDL_PixelFormat *f = Map.TileGraphic->Surface->format;
479 					SDL_PixelFormat *f = terrain->GetGraphics(season)->Surface->format;
480 					//Wyrmgus end
481 					c = *(Uint32 *)GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp, z, terrain, season);
482 					//Wyrmgus start
483 					if (((c & f->Amask) >> f->Ashift) == 0) { //transparent pixel, use base instead
484 						f = base_terrain->GetGraphics(season)->Surface->format;
485 						c = *(Uint32 *)GetTileGraphicPixel(base_xofs, base_yofs, mx, my, scalex, scaley, bpp, z, base_terrain, season);
486 					}
487 					//Wyrmgus end
488 					c = Video.MapRGB(0,
489 									 ((c & f->Rmask) >> f->Rshift),
490 									 ((c & f->Gmask) >> f->Gshift),
491 									 ((c & f->Bmask) >> f->Bshift));
492 				}
493 				//Wyrmgus start
494 //				*(Uint32 *)&(MinimapTerrainSurfaceGL[(mx + my * MinimapTextureWidth) * 4]) = c;
495 				*(Uint32 *)&(MinimapTerrainSurfaceGL[z][(mx + my * MinimapTextureWidth[z]) * 4]) = c;
496 				//Wyrmgus end
497 			} else
498 #endif
499 			{
500 				if (bpp == 1) {
501 					//Wyrmgus start
502 					/*
503 					((Uint8 *)MinimapTerrainSurface->pixels)[mx + my * MinimapTerrainSurface->pitch] =
504 						*GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp);
505 					*/
506 					SDL_Color original_color = terrain->GetGraphics(season)->Surface->format->palette->colors[
507 										  *GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp, z, terrain, season)];
508 
509 					if (original_color.r == 255 && original_color.g == 255 && original_color.b == 255) { //completely white pixel, presumed to be a transparent one; use base instead
510 						original_color = base_terrain->GetGraphics(season)->Surface->format->palette->colors[
511 										  *GetTileGraphicPixel(base_xofs, base_yofs, mx, my, scalex, scaley, bpp, z, base_terrain, season)];
512 					}
513 
514 					Uint32 color;
515 					color = Video.MapRGB(TheScreen->format, original_color.r, original_color.g, original_color.b);
516 
517 					*(Uint32 *)&((Uint8 *)MinimapTerrainSurface[z]->pixels)[mx * MinimapSurface[z]->format->BytesPerPixel + my * MinimapTerrainSurface[z]->pitch] = color;
518 					//Wyrmgus end
519 				} else if (bpp == 3) {
520 					//Wyrmgus start
521 //					Uint8 *d = &((Uint8 *)MinimapTerrainSurface->pixels)[mx * bpp + my * MinimapTerrainSurface->pitch];
522 //					Uint8 *s = GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp);
523 					Uint8 *d = &((Uint8 *)MinimapTerrainSurface[z]->pixels)[mx * bpp + my * MinimapTerrainSurface[z]->pitch];
524 					Uint8 *s = GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp, z, terrain, season);
525 					//Wyrmgus end
526 					*d++ = *s++;
527 					*d++ = *s++;
528 					*d++ = *s++;
529 				} else {
530 					//Wyrmgus start
531 //					*(Uint32 *)&((Uint8 *)MinimapTerrainSurface->pixels)[mx * bpp + my * MinimapTerrainSurface->pitch] =
532 //						*(Uint32 *)GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp);
533 					*(Uint32 *)&((Uint8 *)MinimapTerrainSurface[z]->pixels)[mx * bpp + my * MinimapTerrainSurface[z]->pitch] =
534 						*(Uint32 *)GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp, z, terrain, season);
535 					//Wyrmgus end
536 				}
537 			}
538 
539 		}
540 	}
541 #if defined(USE_OPENGL) || defined(USE_GLES)
542 	if (!UseOpenGL)
543 #endif
544 	{
545 		//Wyrmgus start
546 //		SDL_UnlockSurface(MinimapTerrainSurface);
547 		SDL_UnlockSurface(MinimapTerrainSurface[z]);
548 		//Wyrmgus end
549 	}
550 	SDL_UnlockSurface(Map.TileGraphic->Surface);
551 	//Wyrmgus start
552 	for (size_t i = 0; i != CTerrainType::TerrainTypes.size(); ++i) {
553 		if (CTerrainType::TerrainTypes[i]->GetGraphics(season)) {
554 			SDL_UnlockSurface(CTerrainType::TerrainTypes[i]->GetGraphics(season)->Surface);
555 		}
556 	}
557 	//Wyrmgus end
558 }
559 
560 /**
561 **	@brief	Update a single minimap tile after a change
562 **
563 **	@param	pos	The map position to update in the minimap
564 **	@param	z	The map layer of the tile to update
565 */
UpdateXY(const Vec2i & pos,int z)566 void CMinimap::UpdateXY(const Vec2i &pos, int z)
567 {
568 #if defined(USE_OPENGL) || defined(USE_GLES)
569 	if (UseOpenGL) {
570 		//Wyrmgus start
571 //		if (!MinimapTerrainSurfaceGL) {
572 		if (z >= (int) MinimapTerrainSurfaceGL.size() || !MinimapTerrainSurfaceGL[z]) {
573 		//Wyrmgus end
574 			return;
575 		}
576 	} else
577 #endif
578 	{
579 		//Wyrmgus start
580 //		if (!MinimapTerrainSurface) {
581 		if (z >= (int) MinimapTerrainSurface.size() || !MinimapTerrainSurface[z]) {
582 		//Wyrmgus end
583 			return;
584 		}
585 	}
586 
587 	//Wyrmgus start
588 //	int scalex = MinimapScaleX * SCALE_PRECISION / MINIMAP_FAC;
589 	int scalex = MinimapScaleX[z] * SCALE_PRECISION / MINIMAP_FAC;
590 	//Wyrmgus end
591 	if (scalex == 0) {
592 		scalex = 1;
593 	}
594 	//Wyrmgus start
595 //	int scaley = MinimapScaleY * SCALE_PRECISION / MINIMAP_FAC;
596 	int scaley = MinimapScaleY[z] * SCALE_PRECISION / MINIMAP_FAC;
597 	//Wyrmgus end
598 	if (scaley == 0) {
599 		scaley = 1;
600 	}
601 
602 	//Wyrmgus start
603 //	const int tilepitch = Map.TileGraphic->Surface->w / Map.GetCurrentPixelTileSize().x;
604 //	const int bpp = Map.TileGraphic->Surface->format->BytesPerPixel;
605 	//Wyrmgus end
606 
607 	const CSeason *season = Map.MapLayers[z]->GetSeason();
608 
609 	//
610 	//  Pixel 7,6 7,14, 15,6 15,14 are taken for the minimap picture.
611 	//
612 #if defined(USE_OPENGL) || defined(USE_GLES)
613 	if (!UseOpenGL)
614 #endif
615 	{
616 		//Wyrmgus start
617 //		SDL_LockSurface(MinimapTerrainSurface);
618 		SDL_LockSurface(MinimapTerrainSurface[z]);
619 		//Wyrmgus end
620 	}
621 	SDL_LockSurface(Map.TileGraphic->Surface);
622 	//Wyrmgus start
623 	for (size_t i = 0; i != CTerrainType::TerrainTypes.size(); ++i) {
624 		if (CTerrainType::TerrainTypes[i]->GetGraphics(season)) {
625 			SDL_LockSurface(CTerrainType::TerrainTypes[i]->GetGraphics(season)->Surface);
626 		}
627 	}
628 	//Wyrmgus end
629 
630 	//Wyrmgus start
631 //	const int ty = pos.y * Map.Info.MapWidth;
632 	const int ty = pos.y * Map.Info.MapWidths[z];
633 	//Wyrmgus end
634 	const int tx = pos.x;
635 	//Wyrmgus start
636 //	for (int my = YOffset; my < H - YOffset; ++my) {
637 	for (int my = YOffset[z]; my < H - YOffset[z]; ++my) {
638 	//Wyrmgus end
639 		//Wyrmgus start
640 //		const int y = Minimap2MapY[my];
641 		const int y = Minimap2MapY[z][my];
642 		//Wyrmgus end
643 		if (y < ty) {
644 			continue;
645 		}
646 		if (y > ty) {
647 			break;
648 		}
649 
650 		//Wyrmgus start
651 //		for (int mx = XOffset; mx < W - XOffset; ++mx) {
652 		for (int mx = XOffset[z]; mx < W - XOffset[z]; ++mx) {
653 		//Wyrmgus end
654 			//Wyrmgus start
655 //			const int x = Minimap2MapX[mx];
656 			const int x = Minimap2MapX[z][mx];
657 			//Wyrmgus end
658 
659 			if (x < tx) {
660 				continue;
661 			}
662 			if (x > tx) {
663 				break;
664 			}
665 
666 			//Wyrmgus start
667 			/*
668 			int tile = Map.Fields[x + y].playerInfo.SeenTile;
669 			if (!tile) {
670 				tile = Map.Fields[x + y].getGraphicTile();
671 			}
672 			*/
673 			const CMapField &mf = *Map.MapLayers[z]->Field(x + y);
674 			CTerrainType *terrain = mf.playerInfo.SeenOverlayTerrain ? mf.playerInfo.SeenOverlayTerrain : mf.playerInfo.SeenTerrain;
675 			int tile = mf.playerInfo.SeenOverlayTerrain ? mf.playerInfo.SeenOverlaySolidTile : mf.playerInfo.SeenSolidTile;
676 			if (!terrain) {
677 				terrain = mf.OverlayTerrain ? mf.OverlayTerrain : mf.Terrain;
678 				tile = mf.OverlayTerrain ? mf.OverlaySolidTile : mf.SolidTile;
679 			}
680 
681 			CTerrainType *base_terrain = mf.playerInfo.SeenTerrain;
682 			int base_tile = mf.playerInfo.SeenSolidTile;
683 			if (!base_terrain) {
684 				base_terrain = mf.Terrain;
685 				base_tile = mf.SolidTile;
686 			}
687 			//Wyrmgus end
688 
689 			//Wyrmgus start
690 			int tilepitch = terrain->GetGraphics(season)->Surface->w / Map.GetCurrentPixelTileSize().x;
691 			const int bpp = terrain->GetGraphics(season)->Surface->format->BytesPerPixel;
692 
693 			int base_tilepitch = base_terrain->GetGraphics(season)->Surface->w / Map.GetCurrentPixelTileSize().x;
694 			//Wyrmgus end
695 
696 			const int xofs = Map.GetCurrentPixelTileSize().x * (tile % tilepitch);
697 			const int yofs = Map.GetCurrentPixelTileSize().y * (tile / tilepitch);
698 
699 			//Wyrmgus start
700 			const int base_xofs = Map.GetCurrentPixelTileSize().x * (base_tile % base_tilepitch);
701 			const int base_yofs = Map.GetCurrentPixelTileSize().y * (base_tile / base_tilepitch);
702 			//Wyrmgus end
703 
704 #if defined(USE_OPENGL) || defined(USE_GLES)
705 			if (UseOpenGL) {
706 				Uint32 c;
707 
708 				if (bpp == 1) {
709 					//Wyrmgus start
710 //					const int colorIndex = *GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp);
711 //					const SDL_Color color = Map.TileGraphic->Surface->format->palette->colors[colorIndex];
712 					int colorIndex = *GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp, z, terrain, season);
713 					SDL_Color color = terrain->GetGraphics(season)->Surface->format->palette->colors[colorIndex];
714 					if (color.r == 255 && color.g == 255 && color.b == 255) { //completely white pixel, presumed to be a transparent one; use base instead
715 						colorIndex = *GetTileGraphicPixel(base_xofs, base_yofs, mx, my, scalex, scaley, bpp, z, base_terrain, season);
716 						color = base_terrain->GetGraphics(season)->Surface->format->palette->colors[colorIndex];
717 					}
718 					//Wyrmgus end
719 
720 					c = Video.MapRGB(0, color.r, color.g, color.b);
721 				} else {
722 					//Wyrmgus start
723 //					SDL_PixelFormat *f = Map.TileGraphic->Surface->format;
724 					SDL_PixelFormat *f = terrain->GetGraphics(season)->Surface->format;
725 					//Wyrmgus end
726 
727 					//Wyrmgus start
728 //					c = *(Uint32 *)GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp);
729 					c = *(Uint32 *)GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp, z, terrain, season);
730 
731 					if (((c & f->Amask) >> f->Ashift) == 0) { //transparent pixel, use base instead
732 						f = base_terrain->GetGraphics(season)->Surface->format;
733 						c = *(Uint32 *)GetTileGraphicPixel(base_xofs, base_yofs, mx, my, scalex, scaley, bpp, z, base_terrain, season);
734 					}
735 					//Wyrmgus end
736 					c = Video.MapRGB(0,
737 									 ((c & f->Rmask) >> f->Rshift),
738 									 ((c & f->Gmask) >> f->Gshift),
739 									 ((c & f->Bmask) >> f->Bshift));
740 				}
741 				//Wyrmgus start
742 //				*(Uint32 *)&(MinimapTerrainSurfaceGL[(mx + my * MinimapTextureWidth) * 4]) = c;
743 				*(Uint32 *)&(MinimapTerrainSurfaceGL[z][(mx + my * MinimapTextureWidth[z]) * 4]) = c;
744 				//Wyrmgus end
745 			} else
746 #endif
747 			{
748 				//Wyrmgus start
749 //				const int index = mx * bpp + my * MinimapTerrainSurface->pitch;
750 //				Uint8 *s = GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp);
751 				const int index = mx * bpp + my * MinimapTerrainSurface[z]->pitch;
752 				Uint8 *s = GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp, z, terrain, season);
753 				//Wyrmgus end
754 				if (bpp == 1) {
755 					//Wyrmgus start
756 					/*
757 					((Uint8 *)MinimapTerrainSurface->pixels)[index] = *s;
758 					*/
759 					SDL_Color original_color = terrain->GetGraphics(season)->Surface->format->palette->colors[
760 										  *GetTileGraphicPixel(xofs, yofs, mx, my, scalex, scaley, bpp, z, terrain, season)];
761 
762 					if (original_color.r == 255 && original_color.g == 255 && original_color.b == 255) { //completely white pixel, presumed to be a transparent one; use base instead
763 						original_color = base_terrain->GetGraphics(season)->Surface->format->palette->colors[
764 										  *GetTileGraphicPixel(base_xofs, base_yofs, mx, my, scalex, scaley, bpp, z, base_terrain, season)];
765 					}
766 
767 					Uint32 color;
768 					color = Video.MapRGB(TheScreen->format, original_color.r, original_color.g, original_color.b);
769 
770 					*(Uint32 *)&((Uint8 *)MinimapTerrainSurface[z]->pixels)[mx * MinimapSurface[z]->format->BytesPerPixel + my * MinimapTerrainSurface[z]->pitch] = color;
771 					//Wyrmgus end
772 				} else if (bpp == 3) {
773 					//Wyrmgus start
774 //					Uint8 *d = &((Uint8 *)MinimapTerrainSurface->pixels)[index];
775 					Uint8 *d = &((Uint8 *)MinimapTerrainSurface[z]->pixels)[index];
776 					//Wyrmgus end
777 
778 					*d++ = *s++;
779 					*d++ = *s++;
780 					*d++ = *s++;
781 				} else {
782 					//Wyrmgus start
783 //					*(Uint32 *)&((Uint8 *)MinimapTerrainSurface->pixels)[index] = *(Uint32 *)s;
784 					*(Uint32 *)&((Uint8 *)MinimapTerrainSurface[z]->pixels)[index] = *(Uint32 *)s;
785 					//Wyrmgus end
786 				}
787 			}
788 		}
789 	}
790 #if defined(USE_OPENGL) || defined(USE_GLES)
791 	if (!UseOpenGL)
792 #endif
793 	{
794 		//Wyrmgus start
795 //		SDL_UnlockSurface(MinimapTerrainSurface);
796 		SDL_UnlockSurface(MinimapTerrainSurface[z]);
797 		//Wyrmgus end
798 	}
799 	SDL_UnlockSurface(Map.TileGraphic->Surface);
800 	//Wyrmgus start
801 	for (size_t i = 0; i != CTerrainType::TerrainTypes.size(); ++i) {
802 		if (CTerrainType::TerrainTypes[i]->GetGraphics(season)) {
803 			SDL_UnlockSurface(CTerrainType::TerrainTypes[i]->GetGraphics(season)->Surface);
804 		}
805 	}
806 	//Wyrmgus end
807 }
808 
809 /**
810 **  Draw a unit on the minimap.
811 */
DrawUnitOn(CUnit & unit,int red_phase)812 static void DrawUnitOn(CUnit &unit, int red_phase)
813 {
814 	const CUnitType *type;
815 
816 	if (Editor.Running || ReplayRevealMap || unit.IsVisible(*ThisPlayer)) {
817 		type = unit.Type;
818 	} else {
819 		type = unit.Seen.Type;
820 		// This will happen for radar if the unit has not been seen and we
821 		// have it on radar.
822 		if (!type) {
823 			type = unit.Type;
824 		}
825 	}
826 
827 	//Wyrmgus start
828 	//don't draw decorations or diminutive fauna units on the minimap
829 	if (type->BoolFlag[DECORATION_INDEX].value || (type->BoolFlag[DIMINUTIVE_INDEX].value && type->BoolFlag[FAUNA_INDEX].value)) {
830 		return;
831 	}
832 	//Wyrmgus end
833 
834 	Uint32 color;
835 	//Wyrmgus start
836 //	if (unit.Player->Index == PlayerNumNeutral) {
837 	if (unit.GetDisplayPlayer() == PlayerNumNeutral) {
838 	//Wyrmgus end
839 		color = Video.MapRGB(TheScreen->format, type->NeutralMinimapColorRGB);
840 	} else if (unit.Player == ThisPlayer && !Editor.Running) {
841 		if (unit.Attacked && unit.Attacked + ATTACK_BLINK_DURATION > GameCycle &&
842 			(red_phase || unit.Attacked + ATTACK_RED_DURATION > GameCycle)) {
843 			color = ColorRed;
844 		} else if (UI.Minimap.ShowSelected && unit.Selected) {
845 			color = ColorWhite;
846 		} else {
847 			color = ColorGreen;
848 		}
849 	} else {
850 		color = unit.Player->Color;
851 	}
852 
853 	//Wyrmgus start
854 //	int mx = 1 + UI.Minimap.XOffset + Map2MinimapX[unit.tilePos.x];
855 //	int my = 1 + UI.Minimap.YOffset + Map2MinimapY[unit.tilePos.y];
856 //	int w = Map2MinimapX[type->TileSize.x];
857 	int mx = 1 + UI.Minimap.XOffset[UI.CurrentMapLayer->ID] + Map2MinimapX[UI.CurrentMapLayer->ID][unit.tilePos.x];
858 	int my = 1 + UI.Minimap.YOffset[UI.CurrentMapLayer->ID] + Map2MinimapY[UI.CurrentMapLayer->ID][unit.tilePos.y];
859 	int w = Map2MinimapX[UI.CurrentMapLayer->ID][type->TileSize.x];
860 	//Wyrmgus end
861 	if (mx + w >= UI.Minimap.W) { // clip right side
862 		w = UI.Minimap.W - mx;
863 	}
864 	//Wyrmgus start
865 //	int h0 = Map2MinimapY[type->TileSize.y];
866 	int h0 = Map2MinimapY[UI.CurrentMapLayer->ID][type->TileSize.y];
867 	//Wyrmgus end
868 	if (my + h0 >= UI.Minimap.H) { // clip bottom side
869 		h0 = UI.Minimap.H - my;
870 	}
871 	int bpp = 0;
872 #if defined(USE_OPENGL) || defined(USE_GLES)
873 	if (!UseOpenGL)
874 #endif
875 	{
876 		SDL_Color c;
877 		//Wyrmgus start
878 //		bpp = MinimapSurface->format->BytesPerPixel;
879 		bpp = MinimapSurface[UI.CurrentMapLayer->ID]->format->BytesPerPixel;
880 		//Wyrmgus end
881 		SDL_GetRGB(color, TheScreen->format, &c.r, &c.g, &c.b);
882 	}
883 	while (w-- >= 0) {
884 		int h = h0;
885 		while (h-- >= 0) {
886 #if defined(USE_OPENGL) || defined(USE_GLES)
887 			if (UseOpenGL) {
888 				//Wyrmgus start
889 //				*(Uint32 *)&(MinimapSurfaceGL[((mx + w) + (my + h) * MinimapTextureWidth) * 4]) = color;
890 				*(Uint32 *)&(MinimapSurfaceGL[UI.CurrentMapLayer->ID][((mx + w) + (my + h) * MinimapTextureWidth[UI.CurrentMapLayer->ID]) * 4]) = color;
891 				//Wyrmgus end
892 			} else
893 #endif
894 			{
895 				//Wyrmgus start
896 //				const unsigned int index = (mx + w) * bpp + (my + h) * MinimapSurface->pitch;
897 				const unsigned int index = (mx + w) * bpp + (my + h) * MinimapSurface[UI.CurrentMapLayer->ID]->pitch;
898 				//Wyrmgus end
899 				if (bpp == 2) {
900 					//Wyrmgus start
901 //					*(Uint16 *)&((Uint8 *)MinimapSurface->pixels)[index] = color;
902 					*(Uint16 *)&((Uint8 *)MinimapSurface[UI.CurrentMapLayer->ID]->pixels)[index] = color;
903 					//Wyrmgus end
904 				} else {
905 					//Wyrmgus start
906 //					*(Uint32 *)&((Uint8 *)MinimapSurface->pixels)[index] = color;
907 					*(Uint32 *)&((Uint8 *)MinimapSurface[UI.CurrentMapLayer->ID]->pixels)[index] = color;
908 					//Wyrmgus end
909 				}
910 			}
911 		}
912 	}
913 }
914 
915 /**
916 **  Update the minimap with the current game information
917 */
Update()918 void CMinimap::Update()
919 {
920 	static int red_phase;
921 
922 	int red_phase_changed = red_phase != (int)((FrameCounter / FRAMES_PER_SECOND) & 1);
923 	if (red_phase_changed) {
924 		red_phase = !red_phase;
925 	}
926 
927 	// Clear Minimap background if not transparent
928 	if (!Transparent) {
929 #if defined(USE_OPENGL) || defined(USE_GLES)
930 		if (UseOpenGL) {
931 			//Wyrmgus start
932 //			memset(MinimapSurfaceGL, 0, MinimapTextureWidth * MinimapTextureHeight * 4);
933 			memset(MinimapSurfaceGL[UI.CurrentMapLayer->ID], 0, MinimapTextureWidth[UI.CurrentMapLayer->ID] * MinimapTextureHeight[UI.CurrentMapLayer->ID] * 4);
934 			//Wyrmgus end
935 		} else
936 #endif
937 		{
938 			//Wyrmgus start
939 //			SDL_FillRect(MinimapSurface, nullptr, SDL_MapRGB(MinimapSurface->format, 0, 0, 0));
940 			SDL_FillRect(MinimapSurface[UI.CurrentMapLayer->ID], nullptr, SDL_MapRGB(MinimapSurface[UI.CurrentMapLayer->ID]->format, 0, 0, 0));
941 			//Wyrmgus end
942 		}
943 	}
944 
945 	int bpp;
946 #if defined(USE_OPENGL) || defined(USE_GLES)
947 	if (UseOpenGL) {
948 		bpp = 0;
949 	} else
950 #endif
951 	{
952 		//Wyrmgus start
953 //		bpp = MinimapSurface->format->BytesPerPixel;
954 		bpp = MinimapSurface[UI.CurrentMapLayer->ID]->format->BytesPerPixel;
955 		//Wyrmgus end
956 	}
957 
958 	//
959 	// Draw the terrain
960 	//
961 	if (WithTerrain) {
962 #if defined(USE_OPENGL) || defined(USE_GLES)
963 		if (UseOpenGL) {
964 			//Wyrmgus start
965 //			memcpy(MinimapSurfaceGL, MinimapTerrainSurfaceGL, MinimapTextureWidth * MinimapTextureHeight * 4);
966 			memcpy(MinimapSurfaceGL[UI.CurrentMapLayer->ID], MinimapTerrainSurfaceGL[UI.CurrentMapLayer->ID], MinimapTextureWidth[UI.CurrentMapLayer->ID] * MinimapTextureHeight[UI.CurrentMapLayer->ID] * 4);
967 			//Wyrmgus end
968 		} else
969 #endif
970 		{
971 			//Wyrmgus start
972 //			SDL_BlitSurface(MinimapTerrainSurface, nullptr, MinimapSurface, nullptr);
973 			SDL_BlitSurface(MinimapTerrainSurface[UI.CurrentMapLayer->ID], nullptr, MinimapSurface[UI.CurrentMapLayer->ID], nullptr);
974 			//Wyrmgus end
975 		}
976 	}
977 
978 #if defined(USE_OPENGL) || defined(USE_GLES)
979 	if (!UseOpenGL)
980 #endif
981 	{
982 		//Wyrmgus start
983 //		SDL_LockSurface(MinimapSurface);
984 //		SDL_LockSurface(MinimapTerrainSurface);
985 		SDL_LockSurface(MinimapSurface[UI.CurrentMapLayer->ID]);
986 		SDL_LockSurface(MinimapTerrainSurface[UI.CurrentMapLayer->ID]);
987 		//Wyrmgus end
988 	}
989 
990 	for (int my = 0; my < H; ++my) {
991 		for (int mx = 0; mx < W; ++mx) {
992 			//Wyrmgus start
993 			if (mx < XOffset[UI.CurrentMapLayer->ID] || mx >= W - XOffset[UI.CurrentMapLayer->ID] || my < YOffset[UI.CurrentMapLayer->ID] || my >= H - YOffset[UI.CurrentMapLayer->ID]) {
994 #if defined(USE_OPENGL) || defined(USE_GLES)
995 				if (UseOpenGL) {
996 					*(Uint32 *)&(MinimapSurfaceGL[UI.CurrentMapLayer->ID][(mx + my * MinimapTextureWidth[UI.CurrentMapLayer->ID]) * 4]) = Video.MapRGB(0, 0, 0, 0);
997 				} else
998 #endif
999 				{
1000 					//Wyrmgus start
1001 //					const int index = mx * bpp + my * MinimapSurface->pitch;
1002 					const int index = mx * bpp + my * MinimapSurface[UI.CurrentMapLayer->ID]->pitch;
1003 					//Wyrmgus end
1004 					if (bpp == 2) {
1005 						//Wyrmgus start
1006 //						*(Uint16 *)&((Uint8 *)MinimapSurface->pixels)[index] = ColorBlack;
1007 						*(Uint16 *)&((Uint8 *)MinimapSurface[UI.CurrentMapLayer->ID]->pixels)[index] = ColorBlack;
1008 						//Wyrmgus end
1009 					} else {
1010 						//Wyrmgus start
1011 //						*(Uint32 *)&((Uint8 *)MinimapSurface->pixels)[index] = ColorBlack;
1012 						*(Uint32 *)&((Uint8 *)MinimapSurface[UI.CurrentMapLayer->ID]->pixels)[index] = ColorBlack;
1013 						//Wyrmgus end
1014 					}
1015 				}
1016 				continue;
1017 			}
1018 			//Wyrmgus end
1019 
1020 			int visiontype; // 0 unexplored, 1 explored, >1 visible.
1021 
1022 			if (ReplayRevealMap) {
1023 				visiontype = 2;
1024 			} else {
1025 				//Wyrmgus start
1026 //				const Vec2i tilePos(Minimap2MapX[mx], Minimap2MapY[my] / Map.Info.MapWidth);
1027 //				visiontype = Map.Field(tilePos)->playerInfo.TeamVisibilityState(*ThisPlayer);
1028 				const Vec2i tilePos(Minimap2MapX[UI.CurrentMapLayer->ID][mx], Minimap2MapY[UI.CurrentMapLayer->ID][my] / UI.CurrentMapLayer->GetWidth());
1029 				visiontype = Map.Field(tilePos, UI.CurrentMapLayer->ID)->playerInfo.TeamVisibilityState(*ThisPlayer);
1030 				//Wyrmgus end
1031 			}
1032 
1033 			if (visiontype == 0 || (visiontype == 1 && ((mx & 1) != (my & 1)))) {
1034 #if defined(USE_OPENGL) || defined(USE_GLES)
1035 				if (UseOpenGL) {
1036 					//Wyrmgus start
1037 //					*(Uint32 *)&(MinimapSurfaceGL[(mx + my * MinimapTextureWidth) * 4]) = Video.MapRGB(0, 0, 0, 0);
1038 					*(Uint32 *)&(MinimapSurfaceGL[UI.CurrentMapLayer->ID][(mx + my * MinimapTextureWidth[UI.CurrentMapLayer->ID]) * 4]) = Video.MapRGB(0, 0, 0, 0);
1039 					//Wyrmgus end
1040 				} else
1041 #endif
1042 				{
1043 					//Wyrmgus start
1044 //					const int index = mx * bpp + my * MinimapSurface->pitch;
1045 					const int index = mx * bpp + my * MinimapSurface[UI.CurrentMapLayer->ID]->pitch;
1046 					//Wyrmgus end
1047 					if (bpp == 2) {
1048 						//Wyrmgus start
1049 //						*(Uint16 *)&((Uint8 *)MinimapSurface->pixels)[index] = ColorBlack;
1050 						*(Uint16 *)&((Uint8 *)MinimapSurface[UI.CurrentMapLayer->ID]->pixels)[index] = ColorBlack;
1051 						//Wyrmgus end
1052 					} else {
1053 						//Wyrmgus start
1054 //						*(Uint32 *)&((Uint8 *)MinimapSurface->pixels)[index] = ColorBlack;
1055 						*(Uint32 *)&((Uint8 *)MinimapSurface[UI.CurrentMapLayer->ID]->pixels)[index] = ColorBlack;
1056 						//Wyrmgus end
1057 					}
1058 				}
1059 			}
1060 		}
1061 	}
1062 
1063 #if defined(USE_OPENGL) || defined(USE_GLES)
1064 	if (!UseOpenGL)
1065 #endif
1066 	{
1067 		//Wyrmgus start
1068 //		SDL_UnlockSurface(MinimapTerrainSurface);
1069 		SDL_UnlockSurface(MinimapTerrainSurface[UI.CurrentMapLayer->ID]);
1070 		//Wyrmgus end
1071 	}
1072 
1073 	//
1074 	// Draw units on map
1075 	//
1076 	for (CUnitManager::Iterator it = UnitManager.begin(); it != UnitManager.end(); ++it) {
1077 		CUnit &unit = **it;
1078 		if (unit.IsVisibleOnMinimap()) {
1079 			DrawUnitOn(unit, red_phase);
1080 		}
1081 	}
1082 #if defined(USE_OPENGL) || defined(USE_GLES)
1083 	if (!UseOpenGL)
1084 #endif
1085 	{
1086 		//Wyrmgus start
1087 //		SDL_UnlockSurface(MinimapSurface);
1088 		SDL_UnlockSurface(MinimapSurface[UI.CurrentMapLayer->ID]);
1089 		//Wyrmgus end
1090 	}
1091 }
1092 
1093 /**
1094 **  Draw the minimap events
1095 */
DrawEvents()1096 static void DrawEvents()
1097 {
1098 	const unsigned char alpha = 192;
1099 
1100 	for (int i = 0; i < NumMinimapEvents; ++i) {
1101 		Video.DrawTransCircleClip(MinimapEvents[i].Color,
1102 								  MinimapEvents[i].pos.x, MinimapEvents[i].pos.y,
1103 								  MinimapEvents[i].Size, alpha);
1104 		MinimapEvents[i].Size -= 1;
1105 		if (MinimapEvents[i].Size < 2) {
1106 			MinimapEvents[i] = MinimapEvents[--NumMinimapEvents];
1107 			--i;
1108 		}
1109 	}
1110 }
1111 
1112 /**
1113 **  Draw the minimap on the screen
1114 */
Draw() const1115 void CMinimap::Draw() const
1116 {
1117 #if defined(USE_OPENGL) || defined(USE_GLES)
1118 	if (UseOpenGL) {
1119 		//Wyrmgus start
1120 //		glBindTexture(GL_TEXTURE_2D, MinimapTexture);
1121 		glBindTexture(GL_TEXTURE_2D, MinimapTexture[UI.CurrentMapLayer->ID]);
1122 		//Wyrmgus end
1123 		//Wyrmgus start
1124 //		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, MinimapTextureWidth, MinimapTextureHeight,
1125 //						GL_RGBA, GL_UNSIGNED_BYTE, MinimapSurfaceGL);
1126 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, MinimapTextureWidth[UI.CurrentMapLayer->ID], MinimapTextureHeight[UI.CurrentMapLayer->ID],
1127 						GL_RGBA, GL_UNSIGNED_BYTE, MinimapSurfaceGL[UI.CurrentMapLayer->ID]);
1128 		//Wyrmgus end
1129 
1130 #ifdef USE_GLES
1131 		float texCoord[] = {
1132 			0.0f, 0.0f,
1133 			//Wyrmgus start
1134 //			(float)W / MinimapTextureWidth, 0.0f,
1135 //			0.0f, (float)H / MinimapTextureHeight,
1136 //			(float)W / MinimapTextureWidth, (float)H / MinimapTextureHeight
1137 			(float)W / MinimapTextureWidth[UI.CurrentMapLayer->ID], 0.0f,
1138 			0.0f, (float)H / MinimapTextureHeight[UI.CurrentMapLayer->ID],
1139 			(float)W / MinimapTextureWidth[UI.CurrentMapLayer->ID], (float)H / MinimapTextureHeight[UI.CurrentMapLayer->ID]
1140 			//Wyrmgus end
1141 		};
1142 
1143 		float vertex[] = {
1144 			2.0f / (GLfloat)Video.Width *X - 1.0f, -2.0f / (GLfloat)Video.Height *Y + 1.0f,
1145 			2.0f / (GLfloat)Video.Width *(X + W) - 1.0f, -2.0f / (GLfloat)Video.Height *Y + 1.0f,
1146 			2.0f / (GLfloat)Video.Width *X - 1.0f, -2.0f / (GLfloat)Video.Height *(Y + H) + 1.0f,
1147 			2.0f / (GLfloat)Video.Width *(X + W) - 1.0f, -2.0f / (GLfloat)Video.Height *(Y + H) + 1.0f
1148 		};
1149 
1150 		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1151 		glEnableClientState(GL_VERTEX_ARRAY);
1152 
1153 		glTexCoordPointer(2, GL_FLOAT, 0, texCoord);
1154 		glVertexPointer(2, GL_FLOAT, 0, vertex);
1155 		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1156 
1157 		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1158 		glDisableClientState(GL_VERTEX_ARRAY);
1159 #endif
1160 #ifdef USE_OPENGL
1161 		glBegin(GL_QUADS);
1162 		glTexCoord2f(0.0f, 0.0f);
1163 		glVertex2i(X, Y);
1164 		//Wyrmgus start
1165 //		glTexCoord2f(0.0f, (float)H / MinimapTextureHeight);
1166 		glTexCoord2f(0.0f, (float)H / MinimapTextureHeight[UI.CurrentMapLayer->ID]);
1167 		//Wyrmgus end
1168 		glVertex2i(X, Y + H);
1169 		//Wyrmgus start
1170 //		glTexCoord2f((float)W / MinimapTextureWidth, (float)H / MinimapTextureHeight);
1171 		glTexCoord2f((float)W / MinimapTextureWidth[UI.CurrentMapLayer->ID], (float)H / MinimapTextureHeight[UI.CurrentMapLayer->ID]);
1172 		//Wyrmgus end
1173 		glVertex2i(X + W, Y + H);
1174 		//Wyrmgus start
1175 //		glTexCoord2f((float)W / MinimapTextureWidth, 0.0f);
1176 		glTexCoord2f((float)W / MinimapTextureWidth[UI.CurrentMapLayer->ID], 0.0f);
1177 		//Wyrmgus end
1178 		glVertex2i(X + W, Y);
1179 		glEnd();
1180 #endif
1181 	} else
1182 #endif
1183 	{
1184 		SDL_Rect drect = {Sint16(X), Sint16(Y), 0, 0};
1185 		//Wyrmgus start
1186 //		SDL_BlitSurface(MinimapSurface, nullptr, TheScreen, &drect);
1187 		SDL_BlitSurface(MinimapSurface[UI.CurrentMapLayer->ID], nullptr, TheScreen, &drect);
1188 		//Wyrmgus end
1189 	}
1190 
1191 	DrawEvents();
1192 }
1193 
1194 /**
1195 **  Convert screen position to tile map coordinate.
1196 **
1197 **  @param screenPos  Screen pixel coordinate.
1198 **
1199 **  @return   Tile coordinate.
1200 */
ScreenToTilePos(const PixelPos & screenPos) const1201 Vec2i CMinimap::ScreenToTilePos(const PixelPos &screenPos) const
1202 {
1203 	//Wyrmgus start
1204 //	Vec2i tilePos((((screenPos.x - X - XOffset) * MINIMAP_FAC) / MinimapScaleX),
1205 //				  (((screenPos.y - Y - YOffset) * MINIMAP_FAC) / MinimapScaleY));
1206 	Vec2i tilePos((((screenPos.x - X - XOffset[UI.CurrentMapLayer->ID]) * MINIMAP_FAC) / MinimapScaleX[UI.CurrentMapLayer->ID]),
1207 				  (((screenPos.y - Y - YOffset[UI.CurrentMapLayer->ID]) * MINIMAP_FAC) / MinimapScaleY[UI.CurrentMapLayer->ID]));
1208 	//Wyrmgus end
1209 
1210 	//Wyrmgus start
1211 //	Map.Clamp(tilePos);
1212 	Map.Clamp(tilePos, UI.CurrentMapLayer->ID);
1213 	//Wyrmgus end
1214 	return tilePos;
1215 }
1216 
1217 /**
1218 **  Convert tile map coordinate to screen position.
1219 **
1220 **  @param tilePos  Tile coordinate.
1221 **
1222 **  @return   Screen pixel coordinate.
1223 */
TilePosToScreenPos(const Vec2i & tilePos) const1224 PixelPos CMinimap::TilePosToScreenPos(const Vec2i &tilePos) const
1225 {
1226 	//Wyrmgus start
1227 //	const PixelPos screenPos(X + XOffset + (tilePos.x * MinimapScaleX) / MINIMAP_FAC,
1228 //							 Y + YOffset + (tilePos.y * MinimapScaleY) / MINIMAP_FAC);
1229 	const PixelPos screenPos(X + XOffset[UI.CurrentMapLayer->ID] + (tilePos.x * MinimapScaleX[UI.CurrentMapLayer->ID]) / MINIMAP_FAC,
1230 							 Y + YOffset[UI.CurrentMapLayer->ID] + (tilePos.y * MinimapScaleY[UI.CurrentMapLayer->ID]) / MINIMAP_FAC);
1231 	//Wyrmgus end
1232 	return screenPos;
1233 }
1234 
1235 /**
1236 **  Destroy mini-map.
1237 */
Destroy()1238 void CMinimap::Destroy()
1239 {
1240 #if defined(USE_OPENGL) || defined(USE_GLES)
1241 	if (UseOpenGL) {
1242 		//Wyrmgus start
1243 //		delete[] MinimapTerrainSurfaceGL;
1244 //		MinimapTerrainSurfaceGL = nullptr;
1245 //		if (MinimapSurfaceGL) {
1246 //			glDeleteTextures(1, &MinimapTexture);
1247 //			delete[] MinimapSurfaceGL;
1248 //			MinimapSurfaceGL = nullptr;
1249 //		}
1250 		for (size_t z = 0; z < MinimapTerrainSurfaceGL.size(); ++z) {
1251 			delete[] MinimapTerrainSurfaceGL[z];
1252 			MinimapTerrainSurfaceGL[z] = nullptr;
1253 		}
1254 		MinimapTerrainSurfaceGL.clear();
1255 		for (size_t z = 0; z < MinimapSurfaceGL.size(); ++z) {
1256 			if (MinimapSurfaceGL[z]) {
1257 				//Wyrmgus start
1258 //				glDeleteTextures(1, &MinimapTexture);
1259 				glDeleteTextures(1, &MinimapTexture[z]);
1260 				//Wyrmgus end
1261 				delete[] MinimapSurfaceGL[z];
1262 				MinimapSurfaceGL[z] = nullptr;
1263 			}
1264 		}
1265 		MinimapSurfaceGL.clear();
1266 		MinimapTexture.clear();
1267 		//Wyrmgus end
1268 	} else
1269 #endif
1270 	{
1271 		//Wyrmgus start
1272 //		VideoPaletteListRemove(MinimapTerrainSurface);
1273 //		SDL_FreeSurface(MinimapTerrainSurface);
1274 //		MinimapTerrainSurface = nullptr;
1275 //		if (MinimapSurface) {
1276 //			VideoPaletteListRemove(MinimapSurface);
1277 //			SDL_FreeSurface(MinimapSurface);
1278 //			MinimapSurface = nullptr;
1279 //		}
1280 		for (size_t z = 0; z < MinimapTerrainSurface.size(); ++z) {
1281 			VideoPaletteListRemove(MinimapTerrainSurface[z]);
1282 			SDL_FreeSurface(MinimapTerrainSurface[z]);
1283 			MinimapTerrainSurface[z] = nullptr;
1284 		}
1285 		MinimapTerrainSurface.clear();
1286 		for (size_t z = 0; z < MinimapSurface.size(); ++z) {
1287 			if (MinimapSurface[z]) {
1288 				VideoPaletteListRemove(MinimapSurface[z]);
1289 				SDL_FreeSurface(MinimapSurface[z]);
1290 				MinimapSurface[z] = nullptr;
1291 			}
1292 		}
1293 		MinimapSurface.clear();
1294 		//Wyrmgus end
1295 	}
1296 	//Wyrmgus start
1297 //	delete[] Minimap2MapX;
1298 //	Minimap2MapX = nullptr;
1299 //	delete[] Minimap2MapY;
1300 //	Minimap2MapY = nullptr;
1301 	for (size_t z = 0; z < Minimap2MapX.size(); ++z) {
1302 		delete[] Minimap2MapX[z];
1303 		Minimap2MapX[z] = nullptr;
1304 	}
1305 	Minimap2MapX.clear();
1306 	for (size_t z = 0; z < Minimap2MapY.size(); ++z) {
1307 		delete[] Minimap2MapY[z];
1308 		Minimap2MapY[z] = nullptr;
1309 	}
1310 	Minimap2MapY.clear();
1311 	for (size_t z = 0; z < Map2MinimapX.size(); ++z) {
1312 		delete[] Map2MinimapX[z];
1313 		Map2MinimapX[z] = nullptr;
1314 	}
1315 	Map2MinimapX.clear();
1316 	for (size_t z = 0; z < Map2MinimapY.size(); ++z) {
1317 		delete[] Map2MinimapY[z];
1318 		Map2MinimapY[z] = nullptr;
1319 	}
1320 	Map2MinimapY.clear();
1321 	MinimapScaleX.clear();
1322 	MinimapScaleY.clear();
1323 	XOffset.clear();
1324 	YOffset.clear();
1325 	//Wyrmgus end
1326 }
1327 
1328 /**
1329 **  Draw viewport area contour.
1330 */
DrawViewportArea(const CViewport & viewport) const1331 void CMinimap::DrawViewportArea(const CViewport &viewport) const
1332 {
1333 	// Determine and save region below minimap cursor
1334 	const PixelPos screenPos = TilePosToScreenPos(viewport.MapPos);
1335 	//Wyrmgus start
1336 //	int w = (viewport.MapWidth * MinimapScaleX) / MINIMAP_FAC;
1337 //	int h = (viewport.MapHeight * MinimapScaleY) / MINIMAP_FAC;
1338 	int w = (viewport.MapWidth * MinimapScaleX[UI.CurrentMapLayer->ID]) / MINIMAP_FAC;
1339 	int h = (viewport.MapHeight * MinimapScaleY[UI.CurrentMapLayer->ID]) / MINIMAP_FAC;
1340 	//Wyrmgus end
1341 
1342 	// Draw cursor as rectangle (Note: unclipped, as it is always visible)
1343 	//Wyrmgus start
1344 //	Video.DrawTransRectangle(UI.ViewportCursorColor, screenPos.x, screenPos.y, w, h, 128);
1345 	Video.DrawTransRectangle(UI.ViewportCursorColor, screenPos.x, screenPos.y, w + 1, h + 1, 128);
1346 	//Wyrmgus end
1347 }
1348 
1349 /**
1350 **  Add a minimap event
1351 **
1352 **  @param pos  Map tile position
1353 */
1354 //Wyrmgus start
1355 //void CMinimap::AddEvent(const Vec2i &pos, Uint32 color)
AddEvent(const Vec2i & pos,int z,Uint32 color)1356 void CMinimap::AddEvent(const Vec2i &pos, int z, Uint32 color)
1357 //Wyrmgus end
1358 {
1359 	if (NumMinimapEvents == MAX_MINIMAP_EVENTS) {
1360 		return;
1361 	}
1362 	if (z == UI.CurrentMapLayer->ID) {
1363 		MinimapEvents[NumMinimapEvents].pos = TilePosToScreenPos(pos);
1364 		MinimapEvents[NumMinimapEvents].Size = (W < H) ? W / 3 : H / 3;
1365 		MinimapEvents[NumMinimapEvents].Color = color;
1366 		++NumMinimapEvents;
1367 	} else {
1368 		CMapLayer *event_map_layer = Map.MapLayers[z];
1369 		if (event_map_layer->Plane != nullptr && Map.GetCurrentPlane() != event_map_layer->Plane && UI.PlaneButtons[event_map_layer->Plane->ID].X != -1) {
1370 			MinimapEvents[NumMinimapEvents].pos.x = UI.PlaneButtons[event_map_layer->Plane->ID].X + (UI.PlaneButtons[event_map_layer->Plane->ID].Style->Width / 2);
1371 			MinimapEvents[NumMinimapEvents].pos.y = UI.PlaneButtons[event_map_layer->Plane->ID].Y + (UI.PlaneButtons[event_map_layer->Plane->ID].Style->Height / 2);
1372 		} else if (event_map_layer->World != nullptr && Map.GetCurrentWorld() != event_map_layer->World && UI.WorldButtons[event_map_layer->World->ID].X != -1) {
1373 			MinimapEvents[NumMinimapEvents].pos.x = UI.WorldButtons[event_map_layer->World->ID].X + (UI.WorldButtons[event_map_layer->World->ID].Style->Width / 2);
1374 			MinimapEvents[NumMinimapEvents].pos.y = UI.WorldButtons[event_map_layer->World->ID].Y + (UI.WorldButtons[event_map_layer->World->ID].Style->Height / 2);
1375 		} else if (Map.GetCurrentSurfaceLayer() != event_map_layer->SurfaceLayer && UI.SurfaceLayerButtons[event_map_layer->SurfaceLayer].X != -1) {
1376 			MinimapEvents[NumMinimapEvents].pos.x = UI.SurfaceLayerButtons[event_map_layer->SurfaceLayer].X + (UI.SurfaceLayerButtons[event_map_layer->SurfaceLayer].Style->Width / 2);
1377 			MinimapEvents[NumMinimapEvents].pos.y = UI.SurfaceLayerButtons[event_map_layer->SurfaceLayer].Y + (UI.SurfaceLayerButtons[event_map_layer->SurfaceLayer].Style->Height / 2);
1378 		} else {
1379 			return;
1380 		}
1381 		MinimapEvents[NumMinimapEvents].Size = (W < H) ? W / 3 : H / 3;
1382 		MinimapEvents[NumMinimapEvents].Color = color;
1383 		++NumMinimapEvents;
1384 	}
1385 }
1386 
Contains(const PixelPos & screenPos) const1387 bool CMinimap::Contains(const PixelPos &screenPos) const
1388 {
1389 	return this->X <= screenPos.x && screenPos.x < this->X + this->W
1390 		   && this->Y <= screenPos.y && screenPos.y < this->Y + this->H;
1391 }
1392 
1393 //@}
1394