UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cp_overlay.cpp
Go to the documentation of this file.
1 
7 /*
8 Copyright (C) 1997-2001 Id Software, Inc.
9 
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 
19 See the GNU General Public License for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 
25 */
26 
27 #include "../../cl_shared.h"
28 #include "cp_campaign.h"
29 #include "cp_overlay.h"
30 
32 static const int MAX_ALPHA_VALUE = 200;
33 static const int INITIAL_ALPHA_VALUE = 60;
34 
35 static inline byte* CP_XVIGetAlpha (int x, int y)
36 {
37  return &cgi->r_xviAlpha[y * XVI_WIDTH + x];
38 }
39 
40 static inline byte* CP_RadarGet (int x, int y, bool source)
41 {
42  if (source)
43  return &cgi->r_radarSourcePic[y * RADAR_WIDTH + x];
44  return &cgi->r_radarPic[y * RADAR_WIDTH + x];
45 }
46 
47 static inline void CP_UploadXVI (void)
48 {
49  cgi->R_UploadAlpha("***r_xvitexture***", cgi->r_xviAlpha);
50 }
51 
52 void CP_GetXVIMapDimensions (int* width, int* height)
53 {
54  *width = XVI_WIDTH;
55  *height = XVI_HEIGHT;
56 }
57 
58 void CP_SetXVILevel (int x, int y, int value)
59 {
60  assert(x >= 0);
61  assert(x < XVI_WIDTH);
62  assert(y >= 0);
63  assert(y < XVI_HEIGHT);
64 
65  if (!value)
66  *CP_XVIGetAlpha(x, y) = 0;
67  else
68  *CP_XVIGetAlpha(x, y) = std::min(MAX_ALPHA_VALUE, value + INITIAL_ALPHA_VALUE);
69 }
70 
71 int CP_GetXVILevel (int x, int y)
72 {
73  assert(x >= 0);
74  assert(x < XVI_WIDTH);
75  assert(y >= 0);
76  assert(y < XVI_HEIGHT);
77 
78  return std::max(0, *CP_XVIGetAlpha(x, y) - INITIAL_ALPHA_VALUE);
79 }
80 
91 static void CP_SetMinMaxOverlayRows (const vec2_t pos, float radius, const int height, int* yMin, int* yMax)
92 {
93  const float radarHeightPerDegree = height / 180.0f;
94 
95  if (pos[1] + radius > 90) {
96  *yMin = 0;
97  *yMax = round((90 - pos[1] + radius) * radarHeightPerDegree);
98  } else if (pos[1] - radius < -90) {
99  *yMin = ceil((90 - pos[1] - radius) * radarHeightPerDegree);
100  *yMax = height;
101  } else {
102  *yMin = ceil((90 - pos[1] - radius) * radarHeightPerDegree);
103  *yMax = round((90 - pos[1] + radius) * radarHeightPerDegree);
104  }
105 
106  /* a few assert to avoid buffer overflow */
107  assert(*yMin >= 0);
108  assert(*yMin <= *yMax);
109  assert(*yMax <= height); /* the loop will stop just BEFORE yMax, so use <= rather than < */
110 }
111 
122 static inline float CP_GetCircleDeltaLongitude (const vec2_t centerPos, float radius, const float yLat)
123 {
124  const float angle = (cos(radius * torad) - sin(centerPos[1] * torad) * sin(yLat)) / (cos(centerPos[1] * torad) * cos(yLat));
125  return fabs(angle) > 1.0f ? 180.0f : todeg * acos(angle);
126 }
127 
138 static void CP_DrawXVIOverlayPixel (int xMin, int xMax, const vec2_t centerPos, int y, const float yLat, int xviLevel, float radius)
139 {
140  int x;
141  vec2_t currentPos;
142 
143  currentPos[1] = yLat;
144 
145  for (x = xMin; x < xMax; x++) {
146  const int previousLevel = CP_GetXVILevel(x, y);
147  float distance;
148  int newLevel;
149 
150  currentPos[0] = 180.0f - 360.0f * x / ((float) XVI_WIDTH);
151  distance = GetDistanceOnGlobe(centerPos, currentPos);
152  newLevel = ceil((xviLevel * (radius - distance)) / radius);
153  if (newLevel > previousLevel)
154  CP_SetXVILevel(x, y, xviLevel);
155  }
156 }
157 
168 static void CP_DrawXVIOverlayRow (float latMin, float latMax, const vec2_t center, int y, float yLat, int xviLevel, float radius)
169 {
170  const float xviWidthPerDegree = XVI_WIDTH / 360.0f;
171 
172  assert(latMax - latMin <= 360 + EQUAL_EPSILON);
173 
174  /* if the disc we draw cross the left or right edge of the picture, we need to
175  * draw 2 part of circle on each side of the overlay */
176  if (latMin < -180.0f) {
177  int xMin = 0;
178  int xMax = ceil((latMax + 180.0f) * xviWidthPerDegree);
179  CP_DrawXVIOverlayPixel(xMin, xMax, center, y, yLat, xviLevel, radius);
180  xMin = floor((latMin + 540.0f) * xviWidthPerDegree);
181  xMax = RADAR_WIDTH;
182  CP_DrawXVIOverlayPixel(xMin, xMax, center, y, yLat, xviLevel, radius);
183  } else if (latMax > 180.0f) {
184  int xMin = 0;
185  int xMax = ceil((latMax - 180.0f) * xviWidthPerDegree);
186  CP_DrawXVIOverlayPixel(xMin, xMax, center, y, yLat, xviLevel, radius);
187  xMin = floor((latMin + 180.0f) * xviWidthPerDegree);
188  xMax = RADAR_WIDTH;
189  CP_DrawXVIOverlayPixel(xMin, xMax, center, y, yLat, xviLevel, radius);
190  } else {
191  const int xMin = floor((latMin + 180.0f) * xviWidthPerDegree);
192  const int xMax = ceil((latMax + 180.0f) * xviWidthPerDegree);
193  CP_DrawXVIOverlayPixel(xMin, xMax, center, y, yLat, xviLevel, radius);
194  }
195 }
196 
207 static void CP_IncreaseXVILevel (const vec2_t pos, int xCenter, int yCenter, float factor)
208 {
209  int xviLevel;
210  int y;
211  int yMax, yMin;
212  float radius;
214  /* Get xvi Level infection at pos */
215  xviLevel = CP_GetXVILevel(xCenter, yCenter);
216  /* Calculate radius of new spreading */
217  if (xviLevel < MAX_ALPHA_VALUE - INITIAL_ALPHA_VALUE)
218  xviLevel++;
219  radius = sqrt(factor * xviLevel);
220 
221  /* Set minimum and maximum rows value we'll have to change */
222  CP_SetMinMaxOverlayRows(pos, radius, XVI_HEIGHT, &yMin, &yMax);
223 
224  for (y = yMin; y < yMax; y++) {
225  const float yLat = 90.0f - 180.0f * y / ((float) XVI_HEIGHT);
226  const float deltaLong = CP_GetCircleDeltaLongitude(pos, radius, torad * yLat);
227 
228  CP_DrawXVIOverlayRow(-pos[0] - deltaLong, -pos[0] + deltaLong, pos, y, yLat, xviLevel, radius);
229  }
230 
231  CP_UploadXVI();
232 }
233 
238 {
240  for (int y = 0; y < XVI_HEIGHT; y++) {
241  for (int x = 0; x < XVI_WIDTH; x++) {
242  const int xviLevel = CP_GetXVILevel(x, y);
243  if (xviLevel > 0)
244  CP_SetXVILevel(x, y, xviLevel - 1);
245  }
246  }
247 
248  CP_UploadXVI();
249 }
250 
257 void CP_ChangeXVILevel (const vec2_t pos, float factor)
258 {
259  const int xCenter = round((180 - pos[0]) * XVI_WIDTH / 360.0f);
260  const int yCenter = round((90 - pos[1]) * XVI_HEIGHT / 180.0f);
261 
262  CP_IncreaseXVILevel(pos, xCenter, yCenter, factor);
263 }
264 
270 {
271  /* data Pointer to the data containing values to store in XVI map. Can be nullptr for new games.
272  * This is only the alpha channel of the xvi map */
273  memset(cgi->r_xviAlpha, 0, XVI_WIDTH * XVI_HEIGHT);
274  CP_UploadXVI();
275 }
276 
277 /*
278  * @brief Radar overlay code description
279  * The radar overlay is handled 2 times: bases radar range and aircraft radar range.
280  * Bases radar range needs to be updated only when a radar facility is built or destroyed.
281  * The base radar overlay is stored in r_radarSourcePic.
282  * Aircraft radar overlay needs to be updated every time an aircraft moves, because the position of the radar moves.
283  * this overlay is created by duplicating r_radarSourcePic, and then adding any aircraft radar coverage. It is stored in r_radarTexture
284  * @sa RADAR_UpdateWholeRadarOverlay
285  */
286 
292 void CP_InitializeRadarOverlay (bool source)
293 {
294  /* Initialize Radar */
295  if (source)
297  else
298  memcpy(cgi->r_radarPic, cgi->r_radarSourcePic, RADAR_WIDTH * RADAR_HEIGHT);
299 }
300 
309 static void CP_DrawRadarOverlayRow (float latMin, float latMax, int y, byte alpha, bool source)
310 {
311  const float radarWidthPerDegree = RADAR_WIDTH / 360.0f;
312  int x;
313 
314  assert(latMax - latMin <= 360 + EQUAL_EPSILON);
315 
316  /* if the disc we draw cross the left or right edge of the picture, we need to
317  * draw 2 part of circle on each side of the overlay */
318  if (latMin < -180.0f) {
319  int xMin = 0;
320  int xMax = ceil((latMax + 180.0f) * radarWidthPerDegree);
321  for (x = xMin; x < xMax; x++) {
322  byte* dest = CP_RadarGet(x, y, source);
323  if (alpha < dest[3])
324  dest[3] = alpha;
325  }
326  xMin = floor((latMin + 540.0f) * radarWidthPerDegree);
327  xMax = RADAR_WIDTH;
328  for (x = xMin; x < xMax; x++) {
329  byte* dest = CP_RadarGet(x, y, source);
330  if (alpha < dest[3])
331  dest[3] = alpha;
332  }
333  } else if (latMax > 180.0f) {
334  int xMin = 0;
335  int xMax = ceil((latMax - 180.0f) * radarWidthPerDegree);
336  for (x = xMin; x < xMax; x++) {
337  byte* dest = CP_RadarGet(x, y, source);
338  if (alpha < dest[3])
339  dest[3] = alpha;
340  }
341  xMin = floor((latMin + 180.0f) * radarWidthPerDegree);
342  xMax = RADAR_WIDTH;
343  for (x = xMin; x < xMax; x++) {
344  byte* dest = CP_RadarGet(x, y, source);
345  if (alpha < dest[3])
346  dest[3] = alpha;
347  }
348  } else {
349  const int xMin = floor((latMin + 180.0f) * radarWidthPerDegree);
350  const int xMax = ceil((latMax + 180.0f) * radarWidthPerDegree);
351  for (x = xMin; x < xMax; x++) {
352  byte* dest = CP_RadarGet(x, y, source);
353  if (alpha < dest[3])
354  dest[3] = alpha;
355  }
356  }
357 }
358 
367 void CP_AddRadarCoverage (const vec2_t pos, float innerRadius, float outerRadius, bool source)
368 {
369  const byte innerAlpha = 0;
370  const byte outerAlpha = 60;
371  const float radarHeightPerDegree = RADAR_HEIGHT / 180.0f;
372  int y;
373  int yMax, yMin;
374  int outeryMax, outeryMin;
377  assert(outerRadius < 180.0f);
378  assert(outerRadius > innerRadius);
379 
380  /* Set minimum and maximum rows value we'll have to change */
381  CP_SetMinMaxOverlayRows(pos, innerRadius, RADAR_HEIGHT, &yMin, &yMax);
382  CP_SetMinMaxOverlayRows(pos, outerRadius, RADAR_HEIGHT, &outeryMin, &outeryMax);
383 
384  /* Draw upper part of the radar coverage */
385  for (y = outeryMin; y < yMin; y++) {
386  /* latitude of current point, in radian */
387  const float yLat = torad * (90.0f - y / radarHeightPerDegree);
388  float outerDeltaLong = CP_GetCircleDeltaLongitude(pos, outerRadius, yLat);
389 
390  /* Only the outer radar coverage is drawn at this latitude */
391  CP_DrawRadarOverlayRow(-pos[0] - outerDeltaLong, -pos[0] + outerDeltaLong, y, outerAlpha, source);
392  }
393 
394  /* Draw middle part of the radar coverage */
395  for (y = yMin; y < yMax; y++) {
396  /* latitude of current point, in radian */
397  const float yLat = torad * (90.0f - y / radarHeightPerDegree);
398  const float deltaLong = CP_GetCircleDeltaLongitude(pos, innerRadius, yLat);
399  const float outerDeltaLong = CP_GetCircleDeltaLongitude(pos, outerRadius, yLat);
400 
401  /* At this latitude, there are 3 parts to draw: left outer radar, inner radar, and right outer radar */
402  CP_DrawRadarOverlayRow(-pos[0] - outerDeltaLong, -pos[0] - deltaLong, y, outerAlpha, source);
403  CP_DrawRadarOverlayRow(-pos[0] - deltaLong, -pos[0] + deltaLong, y, innerAlpha, source);
404  CP_DrawRadarOverlayRow(-pos[0] + deltaLong, -pos[0] + outerDeltaLong, y, outerAlpha, source);
405  }
406 
407  /* Draw lower part of the radar coverage */
408  for (y = yMax; y < outeryMax; y++) {
409  /* latitude of current point, in radian */
410  const float yLat = torad * (90.0f - y / radarHeightPerDegree);
411  const float outerDeltaLong = CP_GetCircleDeltaLongitude(pos, outerRadius, yLat);
412 
413  /* Only the outer radar coverage is drawn at this latitude */
414  CP_DrawRadarOverlayRow(-pos[0] - outerDeltaLong, -pos[0] + outerDeltaLong, y, outerAlpha, source);
415  }
416 }
417 
423 {
424  cgi->R_SoftenTexture(cgi->r_radarPic, RADAR_WIDTH, RADAR_HEIGHT, 1);
425  cgi->R_UploadAlpha("***r_radarTexture***", cgi->r_radarPic);
426 }
byte * r_xviAlpha
Definition: cgame.h:382
void CP_InitializeRadarOverlay(bool source)
Initialize radar overlay on geoscape.
Definition: cp_overlay.cpp:292
void CP_SetXVILevel(int x, int y, int value)
Definition: cp_overlay.cpp:58
void CP_DecreaseXVILevelEverywhere(void)
Definition: cp_overlay.cpp:237
void CP_UploadRadarCoverage(void)
Smooth radar coverage.
Definition: cp_overlay.cpp:422
#define XVI_WIDTH
Definition: cl_shared.h:49
Functions to generate and render overlay for geoscape.
#define todeg
Definition: mathlib.h:51
static void CP_DrawXVIOverlayPixel(int xMin, int xMax, const vec2_t centerPos, int y, const float yLat, int xviLevel, float radius)
Change the value of 1 pixel in XVI overlay, the new value is higher than old one. ...
Definition: cp_overlay.cpp:138
static byte * CP_XVIGetAlpha(int x, int y)
Definition: cp_overlay.cpp:35
static void CP_SetMinMaxOverlayRows(const vec2_t pos, float radius, const int height, int *yMin, int *yMax)
Set lower and upper value of an overlay (radar, xvi) row that can be modified when tracing a circle...
Definition: cp_overlay.cpp:91
void CP_GetXVIMapDimensions(int *width, int *height)
Definition: cp_overlay.cpp:52
static float CP_GetCircleDeltaLongitude(const vec2_t centerPos, float radius, const float yLat)
Return the half longitude affected when tracing a circle at a given latitude.
Definition: cp_overlay.cpp:122
const cgame_import_t * cgi
byte * r_radarSourcePic
Definition: cgame.h:384
static void CP_DrawRadarOverlayRow(float latMin, float latMax, int y, byte alpha, bool source)
Draw radar overlay for a given latitude between 2 longitudes.
Definition: cp_overlay.cpp:309
byte * r_radarPic
Definition: cgame.h:383
QGL_EXTERN GLenum GLuint * dest
Definition: r_gl.h:101
#define RADAR_HEIGHT
Definition: cl_shared.h:52
#define EQUAL_EPSILON
Definition: mathlib.h:40
#define RADAR_WIDTH
Definition: cl_shared.h:51
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
int CP_GetXVILevel(int x, int y)
Definition: cp_overlay.cpp:71
void CP_AddRadarCoverage(const vec2_t pos, float innerRadius, float outerRadius, bool source)
Add a radar coverage (base or aircraft) to radar overlay.
Definition: cp_overlay.cpp:367
static void CP_IncreaseXVILevel(const vec2_t pos, int xCenter, int yCenter, float factor)
Applies spreading on xvi transparency channel centered on a given pos.
Definition: cp_overlay.cpp:207
#define torad
Definition: mathlib.h:50
void CP_InitializeXVIOverlay(void)
Initialize XVI overlay on geoscape.
Definition: cp_overlay.cpp:269
vec_t vec2_t[2]
Definition: ufotypes.h:38
Header file for single player campaign control.
static void CP_DrawXVIOverlayRow(float latMin, float latMax, const vec2_t center, int y, float yLat, int xviLevel, float radius)
Draw XVI overlay for a given latitude between 2 longitudes.
Definition: cp_overlay.cpp:168
#define XVI_HEIGHT
Definition: cl_shared.h:50
static const int INITIAL_ALPHA_VALUE
Definition: cp_overlay.cpp:33
static void CP_UploadXVI(void)
Definition: cp_overlay.cpp:47
void CP_ChangeXVILevel(const vec2_t pos, float factor)
Convert the pos into degrees and increase XVI there.
Definition: cp_overlay.cpp:257
uint8_t byte
Definition: ufotypes.h:34
static byte * CP_RadarGet(int x, int y, bool source)
Definition: cp_overlay.cpp:40
static const int MAX_ALPHA_VALUE
Definition: cp_overlay.cpp:32
double GetDistanceOnGlobe(const vec2_t pos1, const vec2_t pos2)
Calculate distance on the geoscape.
Definition: mathlib.cpp:171