UFO: Alien Invasion
Loading...
Searching...
No Matches
r_weather.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 2013 Alexander Y. Tishin
8Copyright (C) 2013-2020 UFO: Alien Invasion.
9
10This program is free software; you can redistribute it and/or
11modify it under the terms of the GNU General Public License
12as published by the Free Software Foundation; either version 2
13of the License, or (at your option) any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
19See the GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software
23Foundation, 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 */
33static 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
49static 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{
75 windStrength = 0;
76 windDirection = frand() * M_PI_2; /* no preferred direction (arc) for the wind */
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{
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;
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();
146}
147
152{
153 changeTo(weather);
155}
156
158{
159}
160
164void 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++) {
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++) {
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
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]),
272 color[1] * (refdef.ambientColor[1] + refdef.sunDiffuseColor[1]),
273 color[2] * (refdef.ambientColor[2] + refdef.sunDiffuseColor[2]),
274 color[3]};
275#else
276 vec_t prtBrightness = VectorLength(refdef.ambientColor) + VectorLength(refdef.sunDiffuseColor);
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++) {
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}
clientBattleScape_t cl
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.
rendererData_t refdef
Definition r_main.cpp:45
void R_Color(const vec4_t rgba)
Change the color to given value.
Definition r_state.cpp:1011
Definition aabb.h:42
void expandXY(const float byVal)
expand the box in four directions, but clip them to the maximum boundaries
Definition aabb.h:232
float getMaxZ() const
Definition aabb.h:137
vec3_t maxs
Definition aabb.h:258
float getMaxY() const
Definition aabb.h:134
static const AABB EMPTY
Definition aabb.h:44
float getMinX() const
Definition aabb.h:119
float getMinZ() const
Definition aabb.h:125
float getMaxX() const
Definition aabb.h:131
float getMinY() const
Definition aabb.h:122
Definition line.h:31
vec3_t start
Definition line.h:54
vec3_t stop
Definition line.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 fallingSpeed
Definition r_weather.h:38
int splashTime
Definition r_weather.h:40
Weather(void)
make a default (clean) weather
float windTurbulence
Definition r_weather.h:37
virtual ~Weather()
void render(void)
Draws weather effects.
float weatherStrength
Definition r_weather.h:34
float particleSize
Definition r_weather.h:56
void clearParticles(void)
Just a shared methods for ctors to initialize the weather.
void update(int milliseconds)
Updates weather for the time passed; handles particle creation/removal automatically.
float smearLength
Definition r_weather.h:55
@ WEATHER_SNOW
Definition r_weather.h:32
@ WEATHER_SANDSTORM
Definition r_weather.h:32
@ WEATHER_CLEAN
Definition r_weather.h:32
@ WEATHER_RAIN
Definition r_weather.h:32
float windStrength
Definition r_weather.h:35
void changeTo(weatherTypes weather)
changes to weather of given type; parameters are randomized
Definition r_weather.cpp:91
static const size_t MAX_PARTICLES
Definition r_weather.h:54
float windDirection
Definition r_weather.h:36
particle particles[MAX_PARTICLES]
Definition r_weather.h:67
float splashSize
Definition r_weather.h:41
vec4_t color
Definition r_weather.h:58
weatherTypes weatherType
Definition r_weather.h:33
Primary header for client.
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
int Cvar_GetInteger(const char *varName)
Returns the int value of a cvar.
Definition cvar.cpp:194
#define MASK_SOLID
Definition defines.h:272
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
void glTexParameterf(GLenum target, GLenum pname, GLfloat param)
Definition gldummy.cpp:13
void glGenTextures(GLsizei n, GLuint *textures)
Definition gldummy.cpp:22
void glBindTexture(GLenum target, GLuint id)
Definition gldummy.cpp:4
vec_t VectorLength(const vec3_t v)
Calculate the length of a vector.
Definition mathlib.cpp:434
float crand(void)
Return random values between -1 and 1.
Definition mathlib.cpp:517
float frand(void)
Return random values between 0 and 1.
Definition mathlib.cpp:506
#define M_PI_2
Definition mathlib.h:37
void R_ResetArrayState(void)
Definition r_array.cpp:185
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint
Definition r_gl.h:124
local graphics definitions
void R_EnableTexture(gltexunit_t *texunit, bool enable)
Definition r_state.cpp:303
void R_EnableBlend(bool enable)
Definition r_state.cpp:261
void R_BindArray(GLenum target, GLenum type, const void *array)
Definition r_state.cpp:148
#define texunit_diffuse
Definition r_state.h:68
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
static const uint8_t wpImage[8][8]
Definition r_weather.cpp:33
Weather effects rendering subsystem header file.
float fraction
Definition tracing.h:58
float vec_t
Definition ufotypes.h:37
vec_t vec4_t[4]
Definition ufotypes.h:40
#define VectorSet(v, x, y, z)
Definition vector.h:59