UFO: Alien Invasion
r_geoscape.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 1997-2001 Id Software, Inc.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 */
24 
25 #include "r_local.h"
26 #include "r_error.h"
27 #include "r_sphere.h"
28 #include "r_geoscape.h"
29 
30 #include "r_mesh.h"
31 #include "r_draw.h"
32 
33 #include "../DateTime.h"
34 
35 #define MARKER_SIZE 60.0
36 
50 void R_DrawFlatGeoscape (const vec2_t nodePos, const vec2_t nodeSize, float p, float cx, float cy, float iz, const char* map, bool overlayNation, bool overlayXVI, bool overlayRadar, image_t* r_dayandnightTexture, image_t* r_xviTexture, image_t* r_radarTexture)
51 {
52  image_t* gl;
53  float geoscape_texcoords[4 * 2];
54  short geoscape_verts[4 * 2];
55 
56  /* normalize */
57  const float nx = nodePos[0] * viddef.rx;
58  const float ny = nodePos[1] * viddef.ry;
59  const float nw = nodeSize[0] * viddef.rx;
60  const float nh = nodeSize[1] * viddef.ry;
61 
62  /* load day image */
63  gl = R_FindImage(va("pics/geoscape/%s_day", map), it_wrappic);
64  if (gl == r_noTexture)
65  Com_Error(ERR_FATAL, "Could not load geoscape day image");
66 
67  /* alter the array pointers */
68  glVertexPointer(2, GL_SHORT, 0, geoscape_verts);
69  R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, geoscape_texcoords);
70 
71  geoscape_texcoords[0] = cx - iz;
72  geoscape_texcoords[1] = cy - iz;
73  geoscape_texcoords[2] = cx + iz;
74  geoscape_texcoords[3] = cy - iz;
75  geoscape_texcoords[4] = cx + iz;
76  geoscape_texcoords[5] = cy + iz;
77  geoscape_texcoords[6] = cx - iz;
78  geoscape_texcoords[7] = cy + iz;
79 
80  geoscape_verts[0] = nx;
81  geoscape_verts[1] = ny;
82  geoscape_verts[2] = nx + nw;
83  geoscape_verts[3] = ny;
84  geoscape_verts[4] = nx + nw;
85  geoscape_verts[5] = ny + nh;
86  geoscape_verts[6] = nx;
87  geoscape_verts[7] = ny + nh;
88 
89  /* draw day image */
90  R_BindTexture(gl->texnum);
91  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
92 
94 
95  /* draw night map */
96  gl = R_FindImage(va("pics/geoscape/%s_night", map), it_wrappic);
97  /* maybe the campaign map doesn't have a night image */
98  if (gl != r_noTexture) {
99  float geoscape_nighttexcoords[4 * 2];
100 
101  R_BindTexture(gl->texnum);
104 
105  geoscape_nighttexcoords[0] = geoscape_texcoords[0] + p;
106  geoscape_nighttexcoords[1] = geoscape_texcoords[1];
107  geoscape_nighttexcoords[2] = geoscape_texcoords[2] + p;
108  geoscape_nighttexcoords[3] = geoscape_texcoords[3];
109  geoscape_nighttexcoords[4] = geoscape_texcoords[4] + p;
110  geoscape_nighttexcoords[5] = geoscape_texcoords[5];
111  geoscape_nighttexcoords[6] = geoscape_texcoords[6] + p;
112  geoscape_nighttexcoords[7] = geoscape_texcoords[7];
113 
114  R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, geoscape_nighttexcoords);
115 
117 
119  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
120 
121  refdef.batchCount++;
122 
124  R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, geoscape_texcoords);
125 
127  }
128 
129  /* draw nation overlay */
130  if (overlayNation) {
131  gl = R_FindImage(va("pics/geoscape/%s_nations_overlay", map), it_wrappic);
132  if (gl == r_noTexture)
133  Com_Error(ERR_FATAL, "Could not load geoscape nation overlay image");
134 
135  /* draw day image */
136  R_BindTexture(gl->texnum);
137  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
138 
139  refdef.batchCount++;
140  }
141 
142  /* draw XVI image */
143  if (overlayXVI) {
144  gl = R_FindImage(va("pics/geoscape/%s_xvi_overlay", map), it_wrappic);
145  if (gl == r_noTexture)
146  Com_Error(ERR_FATAL, "Could not load xvi overlay image");
147 
148  R_BindTexture(gl->texnum);
149 
152 
153  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
154 
155  refdef.batchCount++;
156 
158  }
159 
160  /* draw radar image */
161  if (overlayRadar) {
163  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
164 
165  refdef.batchCount++;
166  }
167 
168  /* and restore them */
169  R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY);
170  R_BindDefaultArray(GL_VERTEX_ARRAY);
171 }
172 
180 void R_Draw2DMapMarkers (const vec2_t screenPos, float direction, const char* model, int skin)
181 {
182  modelInfo_t mi;
183  vec2_t size;
184  vec3_t scale, center, position, angles;
185  float zoom = 0.4f;
186 
187  OBJZERO(mi);
188  VectorCopy(vec3_origin, position);
189  VectorCopy(vec3_origin, angles);
190 
191  mi.model = R_FindModel(model);
192  if (!mi.model) {
193  Com_Printf("Could not find model '%s'\n", model);
194  return;
195  }
196 
197  mi.name = model;
198  mi.origin = position;
199  mi.angles = angles;
200  mi.skin = skin;
201 
202  size[0] = size[1] = MARKER_SIZE * zoom;
203  R_ModelAutoScale(size, &mi, scale, center);
204  /* reset the center, as we want to place the models onto the surface of the earth */
205  mi.center = nullptr;
206 
207  /* go to a new matrix */
208  glPushMatrix();
209 
210  /* Apply all transformation to model. Note that the transformations are applied starting
211  * from the last one and ending with the first one */
212 
213  /* move model to its location */
214  glTranslatef(screenPos[0]* viddef.rx, screenPos[1]* viddef.ry, 0);
215  /* scale model to proper resolution */
216  glScalef(viddef.rx, viddef.ry, 1.0f);
217  /* rotate model to proper direction. */
218  glRotatef(-90.f + direction, 0, 0, 1);
219 
220  R_DrawModelDirect(&mi, nullptr, nullptr);
221 
222  /* restore previous matrix */
223  glPopMatrix();
224 }
225 
237 void R_Draw3DMapMarkers (const vec2_t nodePos, const vec2_t nodeSize, const vec3_t rotate, const vec2_t pos, float direction, float earthRadius, const char* model, int skin)
238 {
239  /* normalize */
240  const float nx = nodePos[0] * viddef.rx;
241  const float ny = nodePos[1] * viddef.ry;
242  const float nw = nodeSize[0] * viddef.rx;
243  const float nh = nodeSize[1] * viddef.ry;
244 
245  /* Earth center is in the middle of node.
246  * Due to Orthographic view, this is also camera position */
247  const vec3_t earthPos = {nx + nw / 2.0f, ny + nh / 2.0f, 0.0f};
248 
249  modelInfo_t mi;
250  vec2_t size;
251  vec3_t scale, center, position, angles;
252  float zoom = 0.4f;
253 
254  OBJZERO(mi);
255  VectorCopy(vec3_origin, position);
256  VectorCopy(vec3_origin, angles);
257 
258  mi.model = R_FindModel(model);
259  if (!mi.model) {
260  Com_Printf("Could not find model '%s'\n", model);
261  return;
262  }
263 
264  mi.name = model;
265  mi.origin = position;
266  mi.angles = angles;
267  mi.skin = skin;
268 
269  size[0] = size[1] = MARKER_SIZE * zoom;
270  R_ModelAutoScale(size, &mi, scale, center);
271  /* reset the center, as we want to place the models onto the surface of the earth */
272  mi.center = nullptr;
273 
274  /* go to a new matrix */
275  glPushMatrix();
276 
277  /* Apply all transformation to model. Note that the transformations are applied starting
278  * from the last one and ending with the first one */
279 
280  /* center model on earth. Translate also along z to avoid seeing
281  * bottom part of the model through earth (only half of earth is drawn) */
282  glTranslatef(earthPos[0], earthPos[1], 10.0f);
283  /* scale model to proper resolution */
284  glScalef(viddef.rx, viddef.ry, 1.0f);
285  /* place model on earth: make it tangent to earth surface, heading toward it if direction is used. */
286  glRotatef(-rotate[1], 1, 0, 0);
287  glRotatef(rotate[2], 0, 1, 0);
288  glRotatef(rotate[0] - pos[0], 0, 0, 1);
289  glRotatef(90.0f - pos[1], 1, 0, 0);
290  glTranslatef(0, 0, earthRadius);
291  glRotatef(90.0f + direction, 0, 0, 1);
292 
293  R_DrawModelDirect(&mi, nullptr, nullptr);
294 
295  /* restore previous matrix */
296  glPopMatrix();
297 }
298 
306 #define SKYBOX_HALFSIZE 800.0f
307 
308 static const float starFieldVerts[] = {
309  /* face 1 */
314 
315  /* face 2 */
320 
321  /* face 3 */
326 
327  /* face 4 */
332 
333  /* face 5 */
338 
339  /* face 6 */
344 };
345 
346 static const float starFieldTexCoords[] = {
347  0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
348  0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
349  0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
350  0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
351  0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
352  0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
353 };
354 
367 static void R_DrawStarfield (int texnum, const vec3_t pos, const vec3_t rotate, float timeOfDay)
368 {
369  vec3_t angle;
371  /* go to a new matrix */
372  glPushMatrix();
373 
374  /* we must center the skybox on the camera border of view, and not on the earth, in order
375  * to see only the inside of the cube */
376  glTranslatef(pos[0], pos[1], -SKYBOX_DEPTH);
377 
378  /* rotates starfield: only time and rotation of earth around itself causes starfield to rotate. */
379  VectorSet(angle, rotate[0] - timeOfDay * todeg, rotate[1], rotate[2]);
380  glRotatef(angle[YAW], 1, 0, 0);
381  glRotatef(angle[ROLL], 0, 1, 0);
382  glRotatef(angle[PITCH], 0, 0, 1);
383 
384  R_BindTexture(texnum);
385 
386  /* alter the array pointers */
387  glVertexPointer(3, GL_FLOAT, 0, starFieldVerts);
388  glTexCoordPointer(2, GL_FLOAT, 0, starFieldTexCoords);
389 
390  /* draw the cube */
391 #ifdef GL_VERSION_ES_CM_1_0
392  for( int ii = 0; ii < 6; ii++ )
393  glDrawArrays(GL_TRIANGLE_FAN, ii * 4, 4);
394 #else
395  glDrawArrays(GL_QUADS, 0, 24);
396 #endif
397 
398  refdef.batchCount++;
399 
400  /* restore previous matrix */
401  glPopMatrix();
402 }
403 
407 static inline void R_RotateCelestialBody (const vec4_t v, vec4_t r, const vec3_t rotate, const vec3_t earthPos, const float celestialDist)
408 {
409  vec4_t v1;
410  vec3_t v2;
411  vec3_t rotationAxis;
412 
413  VectorSet(v2, v[1], v[0], v[2]);
414  VectorSet(rotationAxis, 0, 0, 1);
415  RotatePointAroundVector(v1, rotationAxis, v2, -rotate[PITCH]);
416  VectorSet(rotationAxis, 0, 1, 0);
417  RotatePointAroundVector(v2, rotationAxis, v1, -rotate[YAW]);
418 
419  Vector4Set(r, earthPos[0] + celestialDist * v2[1], earthPos[1] + celestialDist * v2[0], -celestialDist * v2[2], 0);
420 }
421 
430 void R_Draw3DGlobe (const vec2_t pos, const vec2_t size, int day, int second, const vec3_t rotate, float zoom, const char* map,
431  bool disableSolarRender, float ambient, bool overlayNation, bool overlayXVI, bool overlayRadar, image_t* r_xviTexture,
432  image_t* r_radarTexture, bool renderNationGlow)
433 {
434  /* globe scaling */
435  const float fullscale = zoom / STANDARD_3D_ZOOM;
436 
437  /* lighting colors */
438  static const vec4_t diffuseLightColor = { 1.75f, 1.75f, 1.75f, 1.0f };
439  static const vec4_t specularLightColor = { 2.0f, 1.9f, 1.7f, 1.0f };
440  static const vec4_t darknessLightColor = { 0.0f, 0.0f, 0.0f, 1.0f };
441  static const vec4_t brightDiffuseLightColor = { 5.0f, 5.0f, 5.0f, 1.0f };
442  const vec4_t ambientLightColor = { ambient + 0.2f, ambient + 0.2f, ambient + 0.2f, ambient + 0.2f };
443  /* billboard textures */
444  image_t* starfield;
445  image_t* sun;
446  image_t* sunOverlay;
447 
448  /* set distance of the sun and moon to make them static on starfield when
449  * time is stoped. this distance should be used for any celestial body
450  * considered at infinite location (sun, moon) */
451  static const float celestialDist = 1.37f * SKYBOX_HALFSIZE;
452  static const float moonSize = 0.025f;
453  vec4_t sunPos;
454  vec4_t antiSunPos;
455  vec4_t moonLoc;
456  vec4_t sunLoc;
457 
458  /* normalize */
459  const float nx = pos[0] * viddef.rx;
460  const float ny = pos[1] * viddef.ry;
461  const float nw = size[0] * viddef.rx;
462  const float nh = size[1] * viddef.ry;
463 
464  /* Earth center is in the middle of node.
465  * Due to Orthographic view, this is also camera position */
466  const vec3_t earthPos = { nx + nw / 2.0f, ny + nh / 2.0f, 0.0f };
467 
468  /* estimate the progress through the current season so we can do
469  * smooth transitions between textures. Currently there are 12
470  * "seasons", because we have one image per Earth-month. */
471  const float season = (float) (day % DateTime::DAYS_PER_YEAR) / ((float) (DateTime::DAYS_PER_YEAR) / (float) (DateTime::SEASONS_PER_YEAR));
472  const int currSeason = (int) floorf(season) % DateTime::SEASONS_PER_YEAR;
473  const int nextSeason = (int) ceilf(season) % DateTime::SEASONS_PER_YEAR;
474  const float seasonProgress = season - (float) currSeason;
475 
476  /* Compute sun position in absolute frame */
477  const float q = (day % DateTime::DAYS_PER_YEAR * DateTime::SECONDS_PER_DAY + second) * (2.0f * M_PI / (DateTime::SECONDS_PER_DAY * DateTime::DAYS_PER_YEAR)); /* sun rotation (year) */
478  const float a = cos(q) * SIN_ALPHA; /* due to earth obliquity */
479  const float sqrta = sqrt(0.5f * (1 - a * a));
480 
481  /* earth rotation (day) */
482  const float p = (second - DateTime::SECONDS_PER_DAY / 4) * (2.0f * M_PI / DateTime::SECONDS_PER_DAY);
483  /* lunar orbit */
484  const float m = p + (((double)((10 * day % 249) / 10.0f) + ((double)second / (double)DateTime::SECONDS_PER_DAY)) / 24.9f) * (2.0f * M_PI);
485 
486  glPushMatrix();
487  glMatrixMode(GL_TEXTURE);
488  glLoadIdentity();
489  glMatrixMode(GL_MODELVIEW);
490  glDisable(GL_LIGHTING);
491  /* draw the starfield, rotating with the planet */
492  starfield = R_FindImage(va("pics/geoscape/%s_stars", map), it_wrappic);
493  if (starfield != r_noTexture)
494  R_DrawStarfield(starfield->texnum, earthPos, rotate, p);
495 
496  glPopMatrix();
497 
498  /* set up position vectors for celestial bodies */
499  Vector4Set(sunPos, cos(p) * sqrta, -sin(p) * sqrta, a, 0);
500  Vector4Set(antiSunPos, -cos(p) * sqrta, sin(p) * sqrta, -a, 0);
501 
502  /* Rotate the sun in the relative frame of player view, to get sun location */
503  R_RotateCelestialBody(sunPos, sunLoc, rotate, earthPos, 1.0f);
504  /* load sun texture image */
505  sun = R_FindImage(va("pics/geoscape/%s_sun", map), it_wrappic);
506  sunOverlay = R_FindImage(va("pics/geoscape/%s_sun_overlay", map), it_pic);
507  if (sun != r_noTexture && sunOverlay != r_noTexture && sunLoc[2] > 0 && !disableSolarRender) {
508  const int sunx = earthPos[0] + viddef.rx * (-128.0f + celestialDist * (sunLoc[0] - earthPos[0]));
509  const int suny = earthPos[1] + viddef.ry * (-128.0f + celestialDist * (sunLoc[1] - earthPos[1]));
510 
511  R_DrawTexture(sunOverlay->texnum, sunx, suny, 256.0f * viddef.rx, 256.0f * viddef.ry);
512  R_DrawBuffers(2);
513  R_DrawTexture(sun->texnum, sunx, suny, 256.0 * viddef.rx, 256.0 * viddef.ry);
514  R_DrawBuffers(1);
515  }
516 
517  /* calculate position of the moon (it rotates around earth with a period of
518  * about 24.9 h, and we must take day into account to avoid moon to "jump"
519  * every time the day is changing) */
520  VectorSet(moonLoc, cos(m) * sqrta, -sin(m) * sqrta, a);
521  R_RotateCelestialBody(moonLoc, moonLoc, rotate, earthPos, celestialDist);
522 
523  /* free last month's texture image */
524  if (r_globeEarth.season != currSeason) {
525  r_globeEarth.season = currSeason;
527  }
528 
529  /* load diffuse texture map (with embedded night-glow map as alpha channel) */
530  r_globeEarth.texture = R_FindImage(va("pics/geoscape/%s/%s_season_%02d", r_config.lodDir, map, currSeason), it_wrappic);
532  Com_Error(ERR_FATAL, "Could not find pics/geoscape/%s/%s_season_%02d\n", r_config.lodDir, map, currSeason);
533 
534  /* set up for advanced GLSL rendering if we have the capability */
535  if (r_programs->integer) {
537  /* load earth image for the next month so we can blend them */
538  r_globeEarth.blendTexture = R_FindImage(va("pics/geoscape/%s/%s_season_%02d", r_config.lodDir, map, nextSeason), it_wrappic);
540  Com_Error(ERR_FATAL, "Could not find pics/geoscape/%s/%s_season_%02d\n", r_config.lodDir, map, nextSeason);
541 
542  /* load normal map (with embedded gloss map as alpha channel) */
543  r_globeEarth.normalMap = R_FindImage(va("pics/geoscape/%s/%s_bump", r_config.lodDir, map), it_wrappic);
545  r_globeEarth.normalMap = nullptr;
546 
547  /* weight the blending based on how much of the month has elapsed */
548  r_globeEarth.blendScale = seasonProgress;
549  /* set up lights for nighttime city glow */
551  glLightfv(GL_LIGHT1, GL_AMBIENT, darknessLightColor);
552  glLightfv(GL_LIGHT1, GL_DIFFUSE, brightDiffuseLightColor);
553  glLightfv(GL_LIGHT1, GL_SPECULAR, darknessLightColor);
554 
555  r_globeEarth.glowScale = 0.7f;
556  }
557 
558  /* load moon texture image */
559  r_globeMoon.texture = R_FindImage(va("pics/geoscape/%s_moon", map), it_wrappic);
560 
561  /* globe texture scaling */
562  glMatrixMode(GL_TEXTURE);
563  glLoadIdentity();
564  glScalef(2.0f, 1.0f, 1.0f);
565  glMatrixMode(GL_MODELVIEW);
566 
567  /* enable the lighting */
568  glEnable(GL_LIGHTING);
569  glEnable(GL_LIGHT0);
570  glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLightColor);
571  glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLightColor);
572  glLightfv(GL_LIGHT0, GL_SPECULAR, specularLightColor);
573 
574  /* draw the moon */
575  if (r_globeMoon.texture != r_noTexture && moonLoc[2] > 0 && !disableSolarRender)
576  R_SphereRender(&r_globeMoon, moonLoc, rotate, moonSize, sunPos);
577 
578  /* activate depth to hide 3D models behind earth */
579  glEnable(GL_DEPTH_TEST);
580 
581  /* draw the earth */
582  R_DrawBuffers(2);
583 #if 0 /* old rendering code which doesn't render city lights in FFP */
584  if (r_programs->integer == 0) /* ignore alpha channel, since the city-light map is stored there */
585  glBlendFunc(GL_ONE, GL_ZERO);
586 
587  R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);
588 
589  if (r_programs->integer == 0) /* restore default blend function */
590  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
591 #else /* new which does render city lights in FFP */
592  if (r_programs->integer == 0) {
593  /* set up rendering of city lights map, which is stored in alpha channel; OpenGL 1.3 required */
594  R_SelectTexture(&texunit_diffuse); /* select texture to edit texture environment for */
595  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); /* enable color combiner */
596  /* setup texture combiner to blend between daylight diffuse map stored in the RGB channels of the diffuse texture
597  * and the monochomatic emission map (which simulates city lights) stored in the alpha channel;
598  * incoming color value is the blend factor.
599  */
600  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); /* set day color as blending target*/
601  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
602  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); /* set night color as blending source */
603  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
604  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS); /* set incoming color as blending factor */
605  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
606  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); /* set blending mode to interpolation from src1 to src0 */
607  /* copy alpha from incoming color, bypassing the value read from texture, which is not a "real" alpha anyway */
608  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
609  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
610  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
611  }
612 
613  R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);
614 
615  if (r_programs->integer == 0) { /* disable combiner */
617  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
618  }
619 #endif
620 
621  r_globeEarthAtmosphere.texture = R_FindImage(va("pics/geoscape/%s_atmosphere", map), it_wrappic);
622 
623  /* Draw earth atmosphere */
630  R_SphereRender(&r_globeEarthAtmosphere, earthPos, rotate, fullscale, sunPos);
631  } else {
632  image_t* halo = R_FindImage("pics/geoscape/map_earth_halo", it_pic);
633  if (halo != r_noTexture) {
635  const float earthSizeX = fullscale * 20500.0f * viddef.rx;
636  const float earthSizeY = fullscale * 20500.0f * viddef.ry;
637  glMatrixMode(GL_TEXTURE);
638  glPushMatrix();
639  glLoadIdentity();
640  glDisable(GL_LIGHTING);
641 
642  R_DrawTexture(halo->texnum, earthPos[0] - earthSizeX * 0.5f, earthPos[1] - earthSizeY * 0.5f, earthSizeX, earthSizeY);
643  glEnable(GL_LIGHTING);
644  glPopMatrix();
645  glMatrixMode(GL_MODELVIEW);
646  }
647  }
648 
649  R_DrawBuffers(1);
650  glDisable(GL_DEPTH_TEST);
651 
652  /* draw nation overlay */
653  if (overlayNation) {
654  r_globeEarth.overlay = R_FindImage(va("pics/geoscape/%s_nations_overlay", map), it_wrappic);
656  Com_Error(ERR_FATAL, "Could not load geoscape nation overlay image");
657 
658  R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);
659 
660  if (renderNationGlow) {
661  /* draw glowing borders */
662  r_globeEarth.overlay = R_FindImage(va("pics/geoscape/%s_nations_overlay_glow", map), it_wrappic);
664  Com_Error(ERR_FATAL, "Could not load geoscape nation overlay glow image");
665 
666  R_DrawBuffers(2);
667  glDisable(GL_LIGHTING);
668  R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);
669  glEnable(GL_LIGHTING);
670  R_DrawBuffers(1);
671  }
672 
673  r_globeEarth.overlay = nullptr;
674  }
675  /* draw XVI overlay */
676  if (overlayXVI) {
677  r_globeEarth.overlay = R_FindImage(va("pics/geoscape/%s_xvi_overlay", map), it_wrappic);
680  R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);
681  r_globeEarth.overlayAlphaMask = nullptr;
682  r_globeEarth.overlay = nullptr;
683  }
684  /* draw radar overlay */
685  if (overlayRadar) {
687  assert(r_globeEarth.overlay);
688  R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);
689  r_globeEarth.overlay = nullptr;
690  }
691 
692  /* disable 3d geoscape lighting */
693  glDisable(GL_LIGHTING);
694 
695  /* restore the previous matrix */
696  glMatrixMode(GL_TEXTURE);
697  glLoadIdentity();
698  glMatrixMode(GL_MODELVIEW);
699 }
700 
704 static inline void R_DrawQuad (void)
705 {
707  const vec2_t texcoord[] = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f } };
708  const vec2_t verts[] = { { 0.0f, 0.0f }, Vector2FromInt(fbo_render->width, 0.0f), Vector2FromInt(fbo_render->width, fbo_render->height), Vector2FromInt(0.0f, fbo_render->height) };
709 
710  glVertexPointer(2, GL_FLOAT, 0, verts);
711  R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, texcoord);
712 
713  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
714 
715  refdef.batchCount++;
716 
717  R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY);
718  R_BindDefaultArray(GL_VERTEX_ARRAY);
719 }
720 
725 static void R_Blur (r_framebuffer_t* source, r_framebuffer_t* dest, int tex, int dir)
726 {
727  R_EnableBlur(r_state.convolve_program, true, source, dest, dir);
728 
729  /* draw new texture onto a flat surface */
731  R_UseViewport(source);
732  R_DrawQuad();
733 
734  R_EnableBlur(r_state.convolve_program, false, nullptr, nullptr, 0);
735 }
736 
740 static void R_BlurStack (int levels, r_framebuffer_t** sources, r_framebuffer_t** dests)
741 {
742  for (int i = 0; i < levels; i++) {
743  const int l = levels - i - 1;
744 
746  R_UseFramebuffer(dests[l]);
747  R_BindTextureForTexUnit(sources[l]->textures[0], &texunit_0);
748  if (i != 0)
749  R_BindTextureForTexUnit(dests[l + 1]->textures[0], &texunit_1);
750 
752  R_DrawQuad();
753 
754  R_Blur(dests[l], sources[l], 0, 1);
755  R_Blur(sources[l], dests[l], 0, 0);
756  }
757 }
758 
762 void R_DrawBloom (void)
763 {
764  int i;
765  bool renderBufferState;
766 
768  return;
769 
770  /* save state, then set up for blit-style rendering to quads */
771  renderBufferState = R_RenderbufferEnabled();
772  glMatrixMode(GL_MODELVIEW);
773  glPushMatrix();
774  glLoadIdentity();
775  glMatrixMode(GL_TEXTURE);
776  glPushMatrix();
777  glLoadIdentity();
778  glMatrixMode(GL_PROJECTION);
779  glPushMatrix();
780  glLoadIdentity();
781 #ifndef GL_VERSION_ES_CM_1_0
782  glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
783 #endif
784  glOrtho(0, viddef.context.width, viddef.context.height, 0, 9999.0f, SKYBOX_DEPTH);
785 
786  glDisable(GL_LIGHTING);
787  glDisable(GL_DEPTH_TEST);
788 
789  /* downsample into image pyramid */
791  R_BindTexture(fbo_render->textures[1]);
792  qglGenerateMipmapEXT(GL_TEXTURE_2D);
793 
794  R_Blur(fbo_render, fbo_bloom0, 1, 0);
795  R_Blur(fbo_bloom0, fbo_bloom1, 0, 1);
796 
798  R_BindTexture(fbo_bloom1->textures[0]);
799  qglGenerateMipmapEXT(GL_TEXTURE_2D);
801  R_DrawQuad();
802 
803  for (i = 1; i < DOWNSAMPLE_PASSES; i++) {
804  R_Blur(r_state.buffers0[i - 1], r_state.buffers1[i - 1], 0, 0);
805  R_Blur(r_state.buffers1[i - 1], r_state.buffers2[i - 1], 0, 1);
809  R_DrawQuad();
810  }
811 
812  /* blur and combine downsampled images */
814 
815  /* re-combine the blurred version with the original "glow" image */
820 
822  R_DrawQuad();
823 
824  /* draw final result to the screenbuffer */
829 
830  R_DrawQuad();
831 
832  /* cleanup before returning */
834 
835  R_CheckError();
836 
837 #ifndef GL_VERSION_ES_CM_1_0
838  glPopAttrib();
839 #endif
840  glMatrixMode(GL_PROJECTION);
841  glPopMatrix();
842  glMatrixMode(GL_TEXTURE);
843  glPopMatrix();
844  glMatrixMode(GL_MODELVIEW);
845  glPopMatrix();
846  R_CheckError();
847 
848  /* reset renderbuffer state to what it was before */
849  R_EnableRenderbuffer(renderBufferState);
850 }
GLuint texnum
Definition: r_image.h:66
float glowScale
Definition: r_sphere.h:42
bool R_EnableRenderbuffer(bool enable)
Enable the render to the framebuffer.
void R_UseProgram(r_program_t *prog)
Definition: r_program.cpp:43
#define VectorCopy(src, dest)
Definition: vector.h:51
void R_UseFramebuffer(const r_framebuffer_t *buf)
bind specified framebuffer object so we render to it
void R_EnableTexture(gltexunit_t *texunit, bool enable)
Definition: r_state.cpp:303
#define fbo_bloom0
Definition: r_state.h:89
image_t * blendTexture
Definition: r_sphere.h:33
#define VectorSet(v, x, y, z)
Definition: vector.h:59
float * origin
Definition: cl_renderer.h:61
float blendScale
Definition: r_sphere.h:41
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don&#39;t need to have varargs versions of all text functi...
Definition: shared.cpp:410
r_program_t * combine2_program
Definition: r_state.h:137
QGL_EXTERN GLuint GLchar ** sources
Definition: r_gl.h:99
#define ROLL
Definition: mathlib.h:56
const char * name
Definition: cl_renderer.h:59
static const vec3_t scale
image_t * r_xviTexture
#define SIN_ALPHA
Definition: mathlib.h:65
image_t * r_radarTexture
void R_BindLightmapTexture(GLuint texnum)
Definition: r_state.cpp:90
unsigned int * textures
Definition: r_framebuffer.h:44
int season
Definition: r_sphere.h:44
const vec3_t vec3_origin
Definition: mathlib.cpp:35
cvar_t * r_programs
Definition: r_main.cpp:97
static const float starFieldVerts[]
Definition: r_geoscape.cpp:308
float rx
Definition: cl_video.h:71
int integer
Definition: cvar.h:81
voidpf void uLong size
Definition: ioapi.h:42
viddef_t viddef
Definition: cl_video.cpp:34
local graphics definitions
static void R_DrawQuad(void)
Draw the current texture on a quad the size of the renderbuffer.
Definition: r_geoscape.cpp:704
static void R_DrawStarfield(int texnum, const vec3_t pos, const vec3_t rotate, float timeOfDay)
Bind and draw starfield.
Definition: r_geoscape.cpp:367
void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees)
Rotate a point around a given vector.
Definition: mathlib.cpp:849
unsigned width
Definition: cl_video.h:44
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
rconfig_t r_config
Definition: r_main.cpp:47
image_t * r_noTexture
Definition: r_main.cpp:51
Definition: r_image.h:45
cvar_t * r_postprocess
Definition: r_main.cpp:100
static const int SECONDS_PER_DAY
Definition: DateTime.h:43
#define texunit_lightmap
Definition: r_state.h:69
#define ERR_FATAL
Definition: common.h:210
bool frameBufferObject
Definition: r_local.h:186
void R_DrawModelDirect(modelInfo_t *mi, modelInfo_t *pmi, const char *tagname)
Draws a model in 2d mode (for rendering model data from the ui)
Definition: r_mesh.cpp:306
#define YAW
Definition: mathlib.h:55
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
image_t * R_FindImage(const char *pname, imagetype_t type)
Finds or loads the given image.
Definition: r_image.cpp:603
vec4_t nightLightPos
Definition: r_sphere.h:43
void R_Draw3DMapMarkers(const vec2_t nodePos, const vec2_t nodeSize, const vec3_t rotate, const vec2_t pos, float direction, float earthRadius, const char *model, int skin)
Draw 3D Marker on the 3D geoscape.
Definition: r_geoscape.cpp:237
void R_Draw2DMapMarkers(const vec2_t screenPos, float direction, const char *model, int skin)
Draw 3D Marker on the 2D geoscape.
Definition: r_geoscape.cpp:180
#define todeg
Definition: mathlib.h:51
float * angles
Definition: cl_renderer.h:62
bool R_RenderbufferEnabled(void)
sphere_t r_globeEarthAtmosphere
Definition: r_sphere.cpp:35
r_program_t * geoscape_program
Definition: r_state.h:135
#define GL_SOURCE1_RGB
void R_DrawTexture(int texnum, int x, int y, int w, int h)
Bind and draw a texture.
Definition: r_draw.cpp:328
#define fbo_render
Definition: r_state.h:88
#define STANDARD_3D_ZOOM
Typical zoom to use on the 3D geoscape to use same zoom values for both 2D and 3D geoscape...
Definition: r_geoscape.h:32
float * center
Definition: cl_renderer.h:64
rendererData_t refdef
Definition: r_main.cpp:45
static void R_Blur(r_framebuffer_t *source, r_framebuffer_t *dest, int tex, int dir)
does 1D filter convolution to blur a framebuffer texture. dir=0 for horizontal, dir=1 for vertical ...
Definition: r_geoscape.cpp:725
#define OBJZERO(obj)
Definition: shared.h:178
#define DOWNSAMPLE_PASSES
Definition: r_state.h:84
#define Vector4Set(v, r, g, b, a)
Definition: vector.h:62
#define texunit_1
Definition: r_state.h:62
#define M_PI
Definition: mathlib.h:34
r_program_t * convolve_program
Definition: r_state.h:136
static void R_BlurStack(int levels, r_framebuffer_t **sources, r_framebuffer_t **dests)
blur from the source image pyramid into the dest image pyramid
Definition: r_geoscape.cpp:740
#define SKYBOX_HALFSIZE
Half size of Skybox.
Definition: r_geoscape.cpp:306
model_t * model
Definition: cl_renderer.h:58
#define GL_SOURCE2_RGB
#define GL_SOURCE0_RGB
image_t * normalMap
Definition: r_sphere.h:36
#define PITCH
Definition: mathlib.h:54
image_t * overlay
Definition: r_sphere.h:34
void R_BindDefaultArray(GLenum target)
Binds the appropriate shared vertex array to the specified target.
Definition: r_state.cpp:182
model_t * R_FindModel(const char *name)
Tries to load a model.
Definition: r_model.cpp:203
viddefContext_t context
Definition: cl_video.h:67
QGL_EXTERN GLenum GLuint * dest
Definition: r_gl.h:101
void R_ModelAutoScale(const vec2_t boxSize, modelInfo_t *mi, vec3_t scale, vec3_t center)
Compute scale and center for a model info data structure.
Definition: r_mesh.cpp:278
sphere_t r_globeEarth
Definition: r_sphere.cpp:33
static const int DAYS_PER_YEAR
Definition: DateTime.h:37
#define GL_SOURCE0_ALPHA
#define default_program
Definition: r_state.h:92
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
void R_DrawBuffers(unsigned int drawBufferNum)
Activate draw buffer(s)
image_t * overlayAlphaMask
Definition: r_sphere.h:35
char lodDir[8]
Definition: r_local.h:178
#define Vector2FromInt(x, y)
Definition: vector.h:40
#define texunit_0
Definition: r_state.h:61
#define texunit_diffuse
Definition: r_state.h:68
void R_SphereRender(const sphere_t *sphere, const vec3_t pos, const vec3_t rotate, const float scale, const vec4_t lightPos)
Draw the sphere.
Definition: r_sphere.cpp:247
static void R_RotateCelestialBody(const vec4_t v, vec4_t r, const vec3_t rotate, const vec3_t earthPos, const float celestialDist)
rotate a planet (sun or moon) with respect to the earth
Definition: r_geoscape.cpp:407
r_framebuffer_t * buffers1[DOWNSAMPLE_PASSES]
Definition: r_state.h:124
QGL_EXTERN GLint i
Definition: r_gl.h:113
#define SKYBOX_DEPTH
Center position of skybox along z-axis. This is used to make sure we see only the inside of Skybox...
Definition: r_state.h:41
void R_Draw3DGlobe(const vec2_t pos, const vec2_t size, int day, int second, const vec3_t rotate, float zoom, const char *map, bool disableSolarRender, float ambient, bool overlayNation, bool overlayXVI, bool overlayRadar, image_t *r_xviTexture, image_t *r_radarTexture, bool renderNationGlow)
responsible for drawing the 3d globe on geoscape param[in] rotate the rotate angle of the globe param...
Definition: r_geoscape.cpp:430
r_program_t * glslProgram
Definition: r_sphere.h:40
r_program_t * atmosphere_program
Definition: r_state.h:138
Error checking function.
image_t * r_dayandnightTexture
#define MARKER_SIZE
Definition: r_geoscape.cpp:35
image_t * texture
Definition: r_sphere.h:32
vec_t vec3_t[3]
Definition: ufotypes.h:39
vec_t vec2_t[2]
Definition: ufotypes.h:38
void R_EnableBlur(r_program_t *program, bool enable, r_framebuffer_t *source, r_framebuffer_t *dest, int dir)
Definition: r_state.cpp:523
void R_FreeImage(image_t *image)
Free the image and its assigned maps (roughness, normal, specular, glow - if there are any) ...
Definition: r_image.cpp:735
rstate_t r_state
Definition: r_main.cpp:48
#define fbo_bloom1
Definition: r_state.h:90
static const float starFieldTexCoords[]
Definition: r_geoscape.cpp:346
#define R_CheckError()
Definition: r_error.h:30
void R_DrawBloom(void)
handle post-processing bloom
Definition: r_geoscape.cpp:762
void R_DrawFlatGeoscape(const vec2_t nodePos, const vec2_t nodeSize, float p, float cx, float cy, float iz, const char *map, bool overlayNation, bool overlayXVI, bool overlayRadar, image_t *r_dayandnightTexture, image_t *r_xviTexture, image_t *r_radarTexture)
Draw the day and night images of a flat geoscape multitexture feature is used to blend the images...
Definition: r_geoscape.cpp:50
r_framebuffer_t * buffers2[DOWNSAMPLE_PASSES]
Definition: r_state.h:125
void R_ResolveMSAA(const r_framebuffer_t *buf)
Forces multisample antialiasing resolve on given framebuffer, if needed.
unsigned height
Definition: cl_video.h:45
float ry
Definition: cl_video.h:72
static const short SEASONS_PER_YEAR
Definition: DateTime.h:40
Functions to generate and render spheres.
void R_UseViewport(const r_framebuffer_t *buf)
Set the viewport to the dimensions of the given framebuffer.
#define fbo_screen
Definition: r_state.h:87
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
static struct mdfour * m
Definition: md4.cpp:35
r_framebuffer_t * buffers0[DOWNSAMPLE_PASSES]
Definition: r_state.h:123
void R_BindTextureForTexUnit(GLuint texnum, gltexunit_t *texunit)
Definition: r_state.cpp:77
#define R_BindTexture(tn)
Definition: r_state.h:184
sphere_t r_globeMoon
Definition: r_sphere.cpp:34
bool R_SelectTexture(gltexunit_t *texunit)
Returns false if the texunit is not supported.
Definition: r_state.cpp:40
void R_BindArray(GLenum target, GLenum type, const void *array)
Definition: r_state.cpp:148
vec_t vec4_t[4]
Definition: ufotypes.h:40