UFO: Alien Invasion
r_weather.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2013 Alexander Y. Tishin
8 Copyright (C) 2013-2020 UFO: Alien Invasion.
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 <stdint.h>
28 #include "r_local.h"
29 #include "../client.h"
30 #include "r_weather.h"
31 
32 /* wp stands for "weather particle */
33 static const uint8_t wpImage[8][8] = {
34  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,},
35  {0x00, 0x00, 0x20, 0x40, 0x40, 0x20, 0x00, 0x00,},
36  {0x00, 0x20, 0xa0, 0xc0, 0xc0, 0xa0, 0x20, 0x00,},
37  {0x00, 0x40, 0xc0, 0xff, 0xff, 0xc0, 0x40, 0x00,},
38  {0x00, 0x40, 0xc0, 0xff, 0xff, 0xc0, 0x40, 0x00,},
39  {0x00, 0x20, 0xa0, 0xc0, 0xc0, 0xa0, 0x20, 0x00,},
40  {0x00, 0x00, 0x20, 0x40, 0x40, 0x20, 0x00, 0x00,},
41  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}
42 };
43 
49 static GLuint wpTexture (void)
50 {
51  static GLuint wpTextureHandle = 0;
52 
53  if (wpTextureHandle)
54  return wpTextureHandle;
55 
57  glGenTextures(1, &wpTextureHandle);
58  glBindTexture(GL_TEXTURE_2D, wpTextureHandle);
59  glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE, wpImage);
60  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
61  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
62  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
63  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
64 
65  return wpTextureHandle;
66 }
67 
72 {
74  weatherStrength = 0;
75  windStrength = 0;
76  windDirection = frand() * M_PI_2; /* no preferred direction (arc) for the wind */
77  windTurbulence = 0;
78  fallingSpeed = 30; /* to avoid permanently levitating particles if someone decides to alter the weather but forgets to set it */
79  smearLength = 0.1f; /* 100 msec is the typical duration of the human eye motion blur */
80  particleSize = 1.0f; /* 1x scale by default */
81 
82  splashTime = 0.0f;
83  splashSize = 1.0f;
84 
85  color[0] = 1.0f; color[1] = 1.0f; color[2] = 1.0f; color[3] = 0.6f;
86 }
87 
92 {
93  setDefaults();
94 
95  weatherType = weather;
96 
97  switch (weather){
98  case WEATHER_RAIN:
99  weatherStrength = frand() * 0.8f + 0.2f;
100  windStrength = frand() * 20;
101  fallingSpeed = 500;
102  splashTime = 500;
103  splashSize = particleSize * 4.0f;
104  color[0] = 0.6f; color[1] = 0.6f; color[2] = 0.6f; color[3] = 0.6f;
105  break;
106  case WEATHER_SNOW:
107  weatherStrength = frand() * 0.8f + 0.2f;
108  windStrength = frand() * 10;
109  windTurbulence = 15;
110  fallingSpeed = 50;
111  smearLength = 0;
112  particleSize = 1.5f;
113  splashTime = 1500;
115  break;
116  case WEATHER_SANDSTORM:
117  weatherStrength = frand() * 0.1f + 0.9f;
118  windStrength = frand() * 500 + 1000;
119  windTurbulence = 23;
120  fallingSpeed = 200; /* in a sandstorm, sand is blown mostly horizontally */
121  particleSize = 5.0f;
122  color[0] = 1.0f; color[1] = 0.7f; color[2] = 0.25f; color[3] = 0.6f;
123  break;
124  default: /* clean weather */
125  break;
126  };
127 }
128 
133 {
134  for (size_t i = 0; i < Weather::MAX_PARTICLES; i++) {
135  particles[i].ttl = -1;
136  }
137 }
138 
143 {
144  setDefaults();
145  clearParticles();
146 }
147 
152 {
153  changeTo(weather);
154  clearParticles();
155 }
156 
158 {
159 }
160 
164 void Weather::update (int milliseconds)
165 {
166  /* Don't play the weather particles if the user doesn't want them */
167  if (!Cvar_GetInteger("cl_particleweather")) {
168  /* This makes weather look very weird if it is enabled mid-battle */
169  /* clearParticles(); */
170  return;
171  }
172 
173  size_t dead = 0;
174  /* physics: check for ttl and move live particles */
175  for (size_t i = 0; i < Weather::MAX_PARTICLES; i++) {
176  Weather::particle &prt = particles[i];
177  if (prt.ttl < 0) {
178  dead++;
179  continue;
180  } else {
181  int restOfLife = prt.ttl -= milliseconds;
182  if (restOfLife < 0) {
183  if (fabs(prt.vz) < 0.001f || splashTime < 1) {
184  /* either no splash or is a splash particle dying */
185  dead++;
186  continue;
187  }
188  /* convert it into splash particle */
189  /* technically, we should complete the last frame of movement, but with current particle types it looks good even without it */
190  prt.vz = 0; prt.vx = 0; prt.vy = 0;
191  prt.ttl += splashTime;
192  }
193  }
194  /* if we got so far, particle is alive and probably needs a physics update */
195  const int timeAfterUpdate = prt.timeout -= milliseconds;
196  const float moveDuration = milliseconds * 0.001f;
197 
198  prt.x += prt.vx * moveDuration; prt.y += prt.vy * moveDuration; prt.z += prt.vz * moveDuration;
199 
200  if (timeAfterUpdate > 0) {
201  /* just move linearly */
202  continue;
203  }
204  /* alter motion vector */
206  }
207  /* create new ones in place of dead */
208  if (dead) {
209  const float windX = cos(windDirection) * (windStrength + crand() * windTurbulence);
210  const float windY = sin(windDirection) * (windStrength + crand() * windTurbulence);
211 
212  AABB weatherZone;
213  weatherZone = cl.mapData->mapBox;
214  weatherZone.expandXY(256);
215  weatherZone.maxs[2] += 512;
216 
217  Line prtPath;
218 
219  if (dead > 200) dead = 200; /* avoid creating too much particles in the single frame, it could kill the low-end hardware */
220 
221  int debugCreated = 0;
222  for (size_t i = 0; dead && i < Weather::MAX_PARTICLES && i < weatherStrength * Weather::MAX_PARTICLES; i++) {
223  Weather::particle &prt = particles[i];
224  if (prt.ttl >= 0)
225  continue;
226  prt.x = (frand() * (weatherZone.getMaxX() - weatherZone.getMinX())) + weatherZone.getMinX();
227  prt.y = (frand() * (weatherZone.getMaxY() - weatherZone.getMinY())) + weatherZone.getMinY();
228  prt.z = weatherZone.getMaxZ();
229 
230  prt.vx = windX;
231  prt.vy = windY;
232  prt.vz = -fallingSpeed * (frand() * 0.2f + 0.9f);
233 
234  float lifeTime = (weatherZone.getMaxZ() - weatherZone.getMinZ()) / -prt.vz; /* default */
235 
236  VectorSet(prtPath.start, prt.x, prt.y, prt.z);
237  VectorSet(prtPath.stop, prt.x + prt.vx * lifeTime, prt.y + prt.vy * lifeTime, prt.z + prt.vz * lifeTime);
238 
239  trace_t trace = CL_Trace(prtPath, AABB::EMPTY, nullptr, nullptr, MASK_SOLID, cl.mapMaxLevel - 1); /* find the collision point */
240  lifeTime *= trace.fraction;
241 
242  prt.ttl = 1000 * lifeTime; /* convert to milliseconds */
243 
244  prt.timeout = prt.ttl + 1000000;
245  debugCreated++;
246  dead--;
247  }
248  }
249 #if 0
250  if (debugCreated) Com_Printf("created %i weather particles\n", debugCreated);
251 #endif
252 }
253 
257 void Weather::render (void)
258 {
259  /* Don't play the weather particles if the user doesn't want them */
260  if (!Cvar_GetInteger("cl_particleweather")) {
261  return;
262  }
263 
264  GLfloat prtPos[3 * 4 * Weather::MAX_PARTICLES];
265  GLfloat prtTexcoord[2 * 4 * Weather::MAX_PARTICLES];
266  GLushort prtIndex[3 * 2 * Weather::MAX_PARTICLES];
267  size_t prtCount = 0;
268  //const float splashTimeScale = 0.001f / splashTime; /* from msec to 1/sec units, so division is done only once per frame */
270 #if 0 // disabled because of bizarre colors
271  vec4_t prtColor = {color[0] * (refdef.ambientColor[0] + refdef.sunDiffuseColor[0]),
274  color[3]};
275 #else
277  vec4_t prtColor = {color[0] * prtBrightness, color[1] * prtBrightness, color[2] * prtBrightness, color[3]}; /* alpha is not to be scaled */
278 #endif
279 
280  for (size_t i = 0; i < Weather::MAX_PARTICLES; i++) {
281  Weather::particle &prt = particles[i];
282 
283  if (prt.ttl < 0)
284  continue;
285 
286  /* if particle is alive, construct a camera-facing quad */
287  GLfloat x, y, z;
288  GLfloat dx, dy, dz;
289  GLfloat thisParticleSize = particleSize;
290  if (prt.vz == 0 && splashTime > 0) {
291  /* splash particle, do zoom and other things */
293  const float splashFactor = prt.ttl / 500.0f;//1.0f - prt.ttl * splashTimeScale;
294  thisParticleSize *= (splashSize - 1.0f) * splashFactor + 1.0f;
295  dx = dy = thisParticleSize;
296  } else {
297  dx = i & 1 ? thisParticleSize* 2 : thisParticleSize; dy = i & 1 ? thisParticleSize : thisParticleSize * 2 ;
298  }
299 
300  x = prt.x; y = prt.y; z = prt.z;
301  dz = smearLength * prt.vz * 0.5;
302  /* construct a particle geometry; */
303  GLfloat *pos = &prtPos[3 * 4 * prtCount];
304  GLfloat *texcoord = &prtTexcoord[2 * 4 * prtCount];
305  GLushort *idx = &prtIndex[3 * 2 * prtCount];
306 
308  pos[0] = x - dx; pos[1] = y - dy; pos[2] = z + dz * 2;
309  pos[3] = x + dx; pos[4] = y - dy; pos[5] = z + dz *2;
310  pos[6] = x + dx; pos[7] = y + dy; pos[8] = z;
311  pos[9] = x - dx; pos[10] = y + dy; pos[11] = z;
312 
313  texcoord[0] = 0; texcoord[1] = 0; /* upper left vertex */
314  texcoord[2] = 1.0f; texcoord[3] = 0; /* upper right vertex */
315  texcoord[4] = 1.0f; texcoord[5] = 1.0f; /* bottom right vertex */
316  texcoord[6] = 0; texcoord[7] = 1.0f; /* bottom left vertex */
317 
318  idx[0] = 4 * prtCount; idx[1] = 4 * prtCount + 1; idx[2] = 4 * prtCount + 2;
319  idx[3] = 4 * prtCount + 2; idx[4] = 4 * prtCount + 3; idx[5] = 4 * prtCount;
320 
321  prtCount++;
322  }
323 
324  if (prtCount < 1)
325  return;
326 
327  /* draw the generated array */
328  R_Color(prtColor);
329  glBindTexture(GL_TEXTURE_2D, wpTexture());
330  R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, prtPos);
331  R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, prtTexcoord);
332  R_EnableBlend(true);
333  glDrawElements(GL_TRIANGLES, prtCount * 3 * 2, GL_UNSIGNED_SHORT, prtIndex);
334  R_EnableBlend(false);
336  R_Color(nullptr);
337 
338  refdef.batchCount++;
339 }
vec4_t sunDiffuseColor
Definition: cl_renderer.h:184
virtual ~Weather()
Definition: r_weather.cpp:157
vec_t VectorLength(const vec3_t v)
Calculate the length of a vector.
Definition: mathlib.cpp:434
void R_EnableTexture(gltexunit_t *texunit, bool enable)
Definition: r_state.cpp:303
#define VectorSet(v, x, y, z)
Definition: vector.h:59
void glBindTexture(GLenum target, GLuint id)
Definition: gldummy.cpp:4
static GLuint wpTexture(void)
Gives handle to (and uploads if needed) weather particle texture; also binds it to the active texture...
Definition: r_weather.cpp:49
QGL_EXTERN GLuint
Definition: r_gl.h:124
AABB mapBox
Definition: typedefs.h:351
void changeTo(weatherTypes weather)
changes to weather of given type; parameters are randomized
Definition: r_weather.cpp:91
Weather(void)
make a default (clean) weather
Definition: r_weather.cpp:142
Definition: aabb.h:42
float vec_t
Definition: ufotypes.h:37
local graphics definitions
static const size_t MAX_PARTICLES
Definition: r_weather.h:54
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
vec3_t maxs
Definition: aabb.h:258
vec4_t color
Definition: r_weather.h:58
int Cvar_GetInteger(const char *varName)
Returns the int value of a cvar.
Definition: cvar.cpp:194
void R_Color(const vec4_t rgba)
Change the color to given value.
Definition: r_state.cpp:1011
trace_t CL_Trace(const Line &traceLine, const AABB &box, const le_t *passle, le_t *passle2, int contentmask, int worldLevel)
Moves the given mins/maxs volume through the world from start to end.
float windStrength
Definition: r_weather.h:35
float getMaxX() const
Definition: aabb.h:131
weatherTypes
Definition: r_weather.h:32
float getMaxZ() const
Definition: aabb.h:137
int splashTime
Definition: r_weather.h:40
rendererData_t refdef
Definition: r_main.cpp:45
float windDirection
Definition: r_weather.h:36
void R_ResetArrayState(void)
Definition: r_array.cpp:185
static const uint8_t wpImage[8][8]
Definition: r_weather.cpp:33
clientBattleScape_t cl
void clearParticles(void)
Just a shared methods for ctors to initialize the weather.
Definition: r_weather.cpp:132
weatherTypes weatherType
Definition: r_weather.h:33
void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *texels)
Definition: gldummy.cpp:17
#define MASK_SOLID
Definition: defines.h:272
Definition: line.h:31
float windTurbulence
Definition: r_weather.h:37
vec3_t stop
Definition: line.h:55
float splashSize
Definition: r_weather.h:41
particle particles[MAX_PARTICLES]
Definition: r_weather.h:67
void expandXY(const float byVal)
expand the box in four directions, but clip them to the maximum boundaries
Definition: aabb.h:232
float getMinY() const
Definition: aabb.h:122
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
void glTexParameterf(GLenum target, GLenum pname, GLfloat param)
Definition: gldummy.cpp:13
float fraction
Definition: tracing.h:58
#define texunit_diffuse
Definition: r_state.h:68
float frand(void)
Return random values between 0 and 1.
Definition: mathlib.cpp:506
QGL_EXTERN GLint i
Definition: r_gl.h:113
void R_EnableBlend(bool enable)
Definition: r_state.cpp:261
vec3_t start
Definition: line.h:54
float weatherStrength
Definition: r_weather.h:34
float getMinX() const
Definition: aabb.h:119
float crand(void)
Return random values between -1 and 1.
Definition: mathlib.cpp:517
void glGenTextures(GLsizei n, GLuint *textures)
Definition: gldummy.cpp:22
void update(int milliseconds)
Updates weather for the time passed; handles particle creation/removal automatically.
Definition: r_weather.cpp:164
float fallingSpeed
Definition: r_weather.h:38
vec4_t ambientColor
Definition: cl_renderer.h:182
float smearLength
Definition: r_weather.h:55
void setDefaults(void)
Sets clean weather, but generate some parameters usable for easily changing it into the worse varieti...
Definition: r_weather.cpp:71
float getMaxY() const
Definition: aabb.h:134
static const AABB EMPTY
Definition: aabb.h:44
Weather effects rendering subsystem header file.
void render(void)
Draws weather effects.
Definition: r_weather.cpp:257
float getMinZ() const
Definition: aabb.h:125
#define M_PI_2
Definition: mathlib.h:37
float particleSize
Definition: r_weather.h:56
void R_BindArray(GLenum target, GLenum type, const void *array)
Definition: r_state.cpp:148
vec_t vec4_t[4]
Definition: ufotypes.h:40