1 #include <math.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "weather.h"
5 #include "actors.h"
6 #include "asc.h"
7 #include "client_serv.h"
8 #include "draw_scene.h"
9 #include "elconfig.h"
10 #include "interface.h"
11 #include "map.h"
12 #include "misc.h"
13 #include "particles.h"
14 #include "textures.h"
15 #include "shadows.h"
16 #include "sound.h"
17 #include <SDL_timer.h>
18 #include "errors.h"
19 #include "text.h"
20 #ifdef OPENGL_TRACE
21 #include "gl_init.h"
22 #endif
23 #include "sky.h"
24 
25 int use_fog = 1;
26 int show_weather = 1;
27 
28 int wind_speed_srv = 0;	//strength of wind, as set by server. 100 is about the max
29 int wind_direction_srv = 0;	//wind direction, in degrees, as set by server. 0 and 360 == north
30 int wind_speed = 0;	//strength of wind, based on server's setting and local randomization
31 int wind_direction = 0;	//wind direction, based on server's setting and local randomization
32 
33 
34 /* N E W   W E A T H E R *****************************************************/
35 
36 #define MAX_RAIN_DROPS 10000
37 #define MAX_LIGHTNING_DEFS 20
38 #define MAX_THUNDERS 20
39 
40 #define LIGHTNING_LIGHT_RADIUS 20.0
41 #define SOUND_SPEED 0.1 // real sound speed = 0.34029 m/ms
42 
43 #define WEATHER_NONE 0
44 #define WEATHER_RAIN 1
45 
46 typedef struct
47 {
48 	float pos1[3];
49 	float pos2[3];
50 } weather_drop;
51 
52 typedef struct {
53 	int use_sprites;
54 	float density;
55 	float color[4];
56 	float size;
57 	float speed;
58 	float wind_effect;
59 	int texture;
60 } weather_def;
61 
62 typedef struct
63 {
64 	float x_pos;
65 	float y_pos;
66 	float radius;
67 	int type;
68 	float intensity;
69 	float intensity_change_speed;
70 	int intensity_change_duration;
71 } weather_area;
72 
73 typedef struct {
74 	int type;
75 	float x_pos;
76 	float y_pos;
77 	Uint32 time;
78 } thunder;
79 
80 typedef struct {
81 	int texture;
82 	float coords[4]; // left bottom right top
83 } lightning_def;
84 
85 weather_drop weather_drops[MAX_WEATHER_TYPES][MAX_RAIN_DROPS];
86 int weather_drops_count[MAX_WEATHER_TYPES];
87 
88 weather_def weather_defs[MAX_WEATHER_TYPES];
89 
90 weather_area weather_areas[MAX_WEATHER_AREAS];
91 
92 lightning_def lightnings_defs[MAX_LIGHTNING_DEFS];
93 int lightnings_defs_count = 0;
94 
95 thunder thunders[MAX_THUNDERS];
96 int thunders_count = 0;
97 
98 Uint32 lightning_stop = 0;
99 int lightning_type;
100 float lightning_position[4] = {0.0, 0.0, 100.0, 1.0};
101 float lightning_sky_position[4] = {0.0, 0.0, 0.0, 1.0};
102 float lightning_color[4] = {0.9, 0.85, 1.0, 1.0};
103 float lightning_ambient_color[4] = {0.50, 0.45, 0.55, 1.0};
104 int lightning_falling = 0;
105 
106 float weather_ratios[MAX_WEATHER_TYPES];
107 
108 float current_weather_density;
109 
110 #define RANDOM_TABLE_SIZE 100000
111 #define RAND_ONE (next_random_number())
112 
113 float random_table[RANDOM_TABLE_SIZE];
114 int last_random_number = -1;
115 
116 #ifdef NEW_SOUND
117 unsigned int rain_sound = 0;
118 #endif //NEW_SOUND
119 
120 float weather_color[4] = {0.0, 0.0, 0.0, 1.0};
121 float fog_alpha;
122 
123 // array used to build coordinates of quads to display particles
124 float weather_particles_coords[MAX_RAIN_DROPS*20];
125 
next_random_number()126 static __inline__ float next_random_number()
127 {
128 	last_random_number = (last_random_number+1)%RANDOM_TABLE_SIZE;
129 	return random_table[last_random_number];
130 }
131 
132 int weather_read_defs(const char *file_name);
133 
get_weather_type_for_map(void)134 weather_type get_weather_type_for_map(void)
135 {
136 	if ((cur_map < 0) || (continent_maps[cur_map].weather == 0))
137 		return weather_effect_rain;
138 	return continent_maps[cur_map].weather;
139 }
140 
get_weather_type_from_string(const char * weather_name)141 weather_type get_weather_type_from_string(const char *weather_name)
142 {
143 	size_t i;
144 	const weather_type w_types[] = {weather_effect_rain, weather_effect_snow, weather_effect_hail,
145 		weather_effect_sand, weather_effect_dust, weather_effect_lava };
146 	const char* const w_names[] = { "rain", "snow", "hail", "sand", "dust", "lava" };
147 	if (strlen(weather_name) > 0)
148 		for (i=0; i<6; i++)
149 			if (strcasecmp(w_names[i], weather_name) == 0)
150 				return w_types[i];
151 	return 0;
152 }
153 
weather_init()154 void weather_init()
155 {
156 	int i;
157 
158 	for (i = 0; i < MAX_WEATHER_TYPES; ++i)
159 	{
160 		weather_ratios[i] = 0.0;
161 		weather_drops_count[i] = 0;
162 		weather_defs[i].use_sprites = 0;
163 		weather_defs[i].density = 0.0;
164 		weather_defs[i].color[0] = 0.0;
165 		weather_defs[i].color[1] = 0.0;
166 		weather_defs[i].color[2] = 0.0;
167 		weather_defs[i].color[3] = 0.0;
168 		weather_defs[i].size = 0.0;
169 		weather_defs[i].speed = 0.0;
170 		weather_defs[i].wind_effect = 0.0;
171 		weather_defs[i].texture = -1;
172 	}
173 	weather_ratios[0] = 1.0;
174 
175 	for (i = 0; i < MAX_WEATHER_AREAS; ++i)
176 	{
177 		weather_areas[i].type = 0;
178 	}
179 
180 	// init the random numbers table
181 	for (i = 0; i < RANDOM_TABLE_SIZE; ++i)
182 		random_table[i] = (float)rand() / (float)RAND_MAX;
183 
184     // init the particles texture coordinates
185     for (i = 0; i < MAX_RAIN_DROPS; ++i)
186     {
187         const int j = i*20;
188         weather_particles_coords[j   ] = 0.0f;
189         weather_particles_coords[j+1 ] = 0.0f;
190         weather_particles_coords[j+5 ] = 1.0f;
191         weather_particles_coords[j+6 ] = 0.0f;
192         weather_particles_coords[j+10] = 1.0f;
193         weather_particles_coords[j+11] = 1.0f;
194         weather_particles_coords[j+15] = 0.0f;
195         weather_particles_coords[j+16] = 1.0f;
196     }
197 
198 	weather_read_defs("./weather.xml");
199 }
200 
weather_clear()201 void weather_clear()
202 {
203 	int i;
204 	thunders_count = 0;
205 	lightning_stop = 0;
206 	lightning_falling = 0;
207 	weather_ratios[0] = 1.0;
208 	for(i = 1; i < MAX_WEATHER_TYPES; ++i)
209 	{
210 		weather_ratios[i] = 0.0;
211 		weather_drops_count[i] = 0;
212 	}
213 
214 	for (i = 0; i < MAX_WEATHER_AREAS; ++i)
215 	{
216 		weather_areas[i].type = 0;
217 	}
218 }
219 
weather_set_area(int area,float x,float y,float radius,int type,float intensity,int change_duration)220 void weather_set_area(int area, float x, float y, float radius, int type, float intensity, int change_duration)
221 {
222 	if (weather_areas[area].type == 0) weather_areas[area].intensity = 0.0;
223 
224 	weather_areas[area].type = type;
225 	weather_areas[area].x_pos = x;
226 	weather_areas[area].y_pos = y;
227 	weather_areas[area].radius = radius;
228 	weather_areas[area].intensity_change_duration = 1 + change_duration * 1000;
229 	weather_areas[area].intensity_change_speed = (intensity - weather_areas[area].intensity) / weather_areas[area].intensity_change_duration;
230 
231 #ifdef DEBUG
232 	printf("setting area %d at %f,%f with radius %f\n",
233 		   area, x, y, radius);
234 #endif // DEBUG
235 }
236 
weather_get_from_server(const Uint8 * data)237 void weather_get_from_server(const Uint8* data)
238 {
239 /*
240 	//first, catch non-precipitations
241 	if(data[0] == weather_effect_wind){
242 		wind_direction_srv = (2 * data[1])%360;
243 		wind_speed_srv = data[2];
244 		return;
245 	} else if(data[0] == weather_effect_leaves){
246 		//EC_TAG
247 		return;
248 	} else if(data[0] > MAX_WEATHER_TYPES){
249 #ifdef DEBUG
250 		LOG_TO_CONSOLE(c_red1, "Server sent an unknown weather type");
251 #endif // DEBUG
252 		LOG_ERROR("Server sent unknown weather type %d", data[0]);
253 		return;
254 		//from now on, deal with the set of precipitations
255 	} else if(data[2] == 0 && !weather_active()){
256 		return;	//stop? but we're already stopped...
257 	} else if(data[2] != 0 && weather_active()){
258 		set_weather_ratio(data[0], data[2]);
259 		return;
260 	} else if(data[2] != 0 && !weather_active()){
261 		set_weather_ratio(data[0], data[2]);
262 		start_weather(data[1], ((float)(data[2]))/100.0f);
263 		return;
264 	} else {
265 		stop_weather(data[1], ((float)(data[2]))/100.0f);
266 	}
267 */
268 }
269 
weather_compute_ratios(float ratios[MAX_WEATHER_TYPES],float x,float y)270 void weather_compute_ratios(float ratios[MAX_WEATHER_TYPES], float x, float y)
271 {
272 	int i;
273 	float sum = 0.0;
274 
275 	// we reset all the values
276 	for (i = 0; i < MAX_WEATHER_TYPES; ++i)
277 		ratios[i] = 0.0;
278 
279 	// we compute the intensity for each type of weather according to the areas
280 	for (i = 0; i < MAX_WEATHER_AREAS; ++i)
281 		if (weather_areas[i].type > 0)
282 		{
283 			float dx = x - weather_areas[i].x_pos;
284 			float dy = y - weather_areas[i].y_pos;
285 			float dist = dx*dx + dy*dy;
286 			float r = weather_areas[i].radius*weather_areas[i].radius;
287 			if (dist < r)
288 				ratios[weather_areas[i].type] += (1.0 - dist/r) * weather_areas[i].intensity;
289 		}
290 
291 	// we compute the sum of all the intensities
292 	for (i = 1; i < MAX_WEATHER_TYPES; ++i)
293 		sum += ratios[i];
294 
295 	if (sum < 1.0)
296 	{
297 		ratios[0] = 1.0 - sum;
298 	}
299 	else
300 	{
301 		// we normalize the intensities if needed
302 		ratios[0] = 0.0;
303 		for (i = 1; i < MAX_WEATHER_TYPES; ++i)
304 			ratios[i] /= sum;
305 	}
306 }
307 
weather_get_color_from_ratios(float color[4],float ratios[MAX_WEATHER_TYPES])308 void weather_get_color_from_ratios(float color[4], float ratios[MAX_WEATHER_TYPES])
309 {
310 	int i, j;
311 	for(i = 0; i < 4; ++i)
312 	{
313 		color[i] = 0.0;
314 		for(j = 0; j < MAX_WEATHER_TYPES; ++j)
315 		{
316 			color[i] += weather_defs[j].color[i] * ratios[j];
317 		}
318 	}
319 }
320 
make_drop(int type,int i,float x,float y,float z)321 static __inline__ void make_drop(int type, int i, float x, float y, float z)
322 {
323 	weather_drops[type][i].pos1[0] = x + 16.0f * RAND_ONE - 8.0f;
324 	weather_drops[type][i].pos1[1] = y + 16.0f * RAND_ONE - 8.0f;
325 	weather_drops[type][i].pos1[2] = z + 10.0f * RAND_ONE +  2.0f;
326 }
327 
update_wind(void)328 void update_wind(void)
329 {
330 	int dir_d = wind_direction_srv + (int)((float)(RAND_ONE * 60 - 30));
331 	int speed_d = wind_speed_srv + (int)((float)(RAND_ONE * ((float)wind_speed)/5.0f - ((float)wind_speed)/10.0f));
332 	if(dir_d < wind_direction){
333 		--wind_direction;
334 	} else if(dir_d > wind_direction){
335 		++wind_direction;
336 	}
337 	wind_direction %= 360;
338 	if(speed_d <= 0){
339 		speed_d = 0;
340 	} else if(speed_d > 1000){
341 		speed_d = 1000;
342 	}
343 	if(speed_d < wind_speed){
344 		--wind_speed;
345 	} else if(speed_d > wind_speed){
346 		++wind_speed;
347 	}
348 }
349 
update_weather_type(int type,float x,float y,float z,int ticks)350 void update_weather_type(int type, float x, float y, float z, int ticks)
351 {
352 	int num_drops = weather_ratios[type] * weather_defs[type].density * particles_percentage * 0.01 * MAX_RAIN_DROPS;
353 
354 	if (num_drops > MAX_RAIN_DROPS) num_drops = MAX_RAIN_DROPS;
355 
356 	if (weather_drops_count[type] > num_drops)
357 		weather_drops_count[type] = num_drops;
358 
359 	if (num_drops > 0)
360 	{
361 		int i;
362 		float x_move = weather_defs[type].wind_effect * sinf((float)wind_direction*M_PI/180) * wind_speed;
363 		float y_move = weather_defs[type].wind_effect * cosf((float)wind_direction*M_PI/180) * wind_speed;
364 		float z_move = -weather_defs[type].speed;
365 		float dt = ticks * 1E-3;
366 		float dx, dy, dz;
367 
368 		for(i = 0; i < weather_drops_count[type]; ++i)
369 		{
370 			dx = x_move*(1.1-0.2*RAND_ONE);
371 			dy = y_move*(1.1-0.2*RAND_ONE);
372 			dz = z_move*(1.1-0.2*RAND_ONE);
373 
374 			if (weather_drops[type][i].pos1[2] < z-1.0f)
375 			{
376 				// the drop should still exist so we recreate it
377 				make_drop(type, i, x, y, z);
378 			}
379 			else
380 			{
381 				// it's moving. so find out how much by, and wrap around the X/Y if it's too far away (as wind can cause)
382 				weather_drops[type][i].pos1[0] += dx * dt;
383 				if (weather_drops[type][i].pos1[0] < x - 8.0f)
384 				{
385 					weather_drops[type][i].pos1[0] += 16.0f;
386 					weather_drops[type][i].pos2[0] += 16.0f;
387 				}
388 				else if(weather_drops[type][i].pos1[0] > x + 8.0f)
389 				{
390 					weather_drops[type][i].pos1[0] -= 16.0f;
391 					weather_drops[type][i].pos2[0] -= 16.0f;
392 				}
393 
394 				weather_drops[type][i].pos1[1] += dy * dt;
395 				if (weather_drops[type][i].pos1[1] < y - 8.0f)
396 				{
397 					weather_drops[type][i].pos1[1] += 16.0f;
398 					weather_drops[type][i].pos2[1] += 16.0f;
399 				}
400 				else if(weather_drops[type][i].pos1[1] > y + 8.0f)
401 				{
402 					weather_drops[type][i].pos1[1] -= 16.0f;
403 					weather_drops[type][i].pos2[1] -= 16.0f;
404 				}
405 
406 				weather_drops[type][i].pos1[2] += dz * dt;
407 			}
408 
409 			weather_drops[type][i].pos2[0] = weather_drops[type][i].pos1[0] - dx * 0.02;
410 			weather_drops[type][i].pos2[1] = weather_drops[type][i].pos1[1] - dy * 0.02;
411 			weather_drops[type][i].pos2[2] = weather_drops[type][i].pos1[2] - dz * 0.02;
412 		}
413 
414 		// if there are not enough drops, we recreate new ones
415 		if (weather_drops_count[type] < num_drops)
416 		{
417 			for (i = weather_drops_count[type]; i < num_drops; ++i)
418 			{
419 				make_drop(type, i, x, y, z);
420 				weather_drops[type][i].pos2[0] = weather_drops[type][i].pos1[0] - x_move * 0.02;
421 				weather_drops[type][i].pos2[1] = weather_drops[type][i].pos1[1] - y_move * 0.02;
422 				weather_drops[type][i].pos2[2] = weather_drops[type][i].pos1[2] - z_move * 0.02;
423 			}
424 			weather_drops_count[type] = num_drops;
425 		}
426 	}
427 }
428 
weather_update()429 void weather_update()
430 {
431 	static Uint32 last_update = 0;
432 	Uint32 ticks = cur_time - last_update;
433 	int i;
434 
435 	update_wind();
436 
437 	// we update the lightning
438 	if (lightning_falling && cur_time > lightning_stop)
439 	{
440 		lightning_falling = 0;
441 		calc_shadow_matrix();
442 		if (skybox_update_delay > 0)
443 			skybox_update_colors();
444 	}
445 
446 	// we update the areas
447 	for (i = 0; i < MAX_WEATHER_AREAS; ++i)
448 		if (weather_areas[i].type > 0 && weather_areas[i].intensity_change_duration > 0)
449 		{
450 			if (weather_areas[i].intensity_change_duration <= ticks)
451 			{
452 				weather_areas[i].intensity += weather_areas[i].intensity_change_speed*weather_areas[i].intensity_change_duration;
453 				weather_areas[i].intensity_change_duration = 0;
454 			}
455 			else
456 			{
457 				weather_areas[i].intensity += weather_areas[i].intensity_change_speed*ticks;
458 				weather_areas[i].intensity_change_duration -= ticks;
459 			}
460 			if (weather_areas[i].intensity_change_speed < 0.0)
461 			{
462 				if (weather_areas[i].intensity <= 0.001)
463 				{
464 					weather_areas[i].intensity = 0.0;
465 					weather_areas[i].type = 0;
466 				}
467 			}
468 			else
469 			{
470 				if (weather_areas[i].intensity > 1.0)
471 					weather_areas[i].intensity = 1.0;
472 			}
473 		}
474 
475 	// we compute the ratios at the actor position
476 	weather_compute_ratios(weather_ratios, -camera_x, -camera_y);
477 
478 	current_weather_density = weather_get_density_from_ratios(weather_ratios);
479 
480 	// we compute the weather color at the actor position
481 	weather_get_color_from_ratios(weather_color, weather_ratios);
482 
483 	// we update the weather types
484 	for (i = 1; i < MAX_WEATHER_TYPES; ++i)
485 		update_weather_type(i, -camera_x, -camera_y, 0.0, ticks);
486 
487 	last_update = cur_time;
488 }
489 
weather_render_fog()490 void weather_render_fog()
491 {
492 	glEnable(GL_FOG);
493 	glFogi(GL_FOG_MODE, GL_EXP2);
494 	glFogf(GL_FOG_DENSITY, skybox_fog_density);
495 	glFogfv(GL_FOG_COLOR, skybox_fog_color);
496 
497 #ifdef OPENGL_TRACE
498 	CHECK_GL_ERRORS();
499 #endif //OPENGL_TRACE
500 }
501 
weather_render()502 void weather_render()
503 {
504 	int type;
505 	int i;
506 	float modelview[16];
507 	float delta1[3], delta2[3];
508 	float color1[4], color2[4], light_level[3];
509 
510 	skybox_get_current_color(color1, skybox_light_ambient);
511 	skybox_get_current_color(color2, skybox_light_diffuse);
512 
513 	light_level[0] = 0.5 + (0.2 + color1[0] + color2[0]) * 0.5;
514 	light_level[1] = 0.5 + (0.2 + color1[1] + color2[1]) * 0.5;
515 	light_level[2] = 0.5 + (0.2 + color1[2] + color2[2]) * 0.5;
516 
517 	if (lightning_falling)
518 	{
519 		light_level[0] += 0.5 * lightning_color[0];
520 		light_level[1] += 0.5 * lightning_color[1];
521 		light_level[2] += 0.5 * lightning_color[2];
522 	}
523 
524 	if (light_level[0] > 1.0) light_level[0] = 1.0;
525 	if (light_level[1] > 1.0) light_level[1] = 1.0;
526 	if (light_level[2] > 1.0) light_level[2] = 1.0;
527 
528     glGetFloatv(GL_MODELVIEW_MATRIX, modelview);
529 
530 	glPushAttrib(GL_ENABLE_BIT);
531 	glDisable(GL_LIGHTING);
532 
533 	glDisable(GL_ALPHA_TEST);
534 	glEnable(GL_BLEND);
535 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
536 
537 	// we first render the weather that don't use particles
538 	glEnableClientState(GL_VERTEX_ARRAY);
539 	glDisableClientState(GL_NORMAL_ARRAY);
540 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
541 	glDisableClientState(GL_COLOR_ARRAY);
542 	glDisable(GL_TEXTURE_2D);
543 
544 	for (type = 1; type < MAX_WEATHER_TYPES; ++type)
545 		if (!weather_defs[type].use_sprites && weather_drops_count[type] > 0)
546 		{
547 			glLineWidth(weather_defs[type].size);
548 			glColor4f(weather_defs[type].color[0]*light_level[0],
549 					  weather_defs[type].color[1]*light_level[1],
550 					  weather_defs[type].color[2]*light_level[2],
551 					  weather_defs[type].color[3]);
552 			glVertexPointer(3, GL_FLOAT, 0, weather_drops[type]);
553 
554 			for (i = 0; i < weather_drops_count[type]; i += 1000) // to avoid long arrays
555 			{
556 				int nb = weather_drops_count[type] - i;
557 				if (nb > 1000) nb = 1000;
558 				glDrawArrays(GL_LINES, i, nb);
559 			}
560 		}
561 
562 	glLineWidth(1.0);
563 	glEnable(GL_TEXTURE_2D);
564 	glEnable(GL_ALPHA_TEST);
565 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
566 
567 	// we then render the other precipitations as sprites
568     glTexCoordPointer(2, GL_FLOAT, 5*sizeof(float), weather_particles_coords);
569     glVertexPointer(3, GL_FLOAT, 5*sizeof(float), weather_particles_coords+2);
570 	for (type = 2; type < MAX_WEATHER_TYPES; ++type)
571 		if (weather_defs[type].use_sprites && weather_drops_count[type] > 0)
572 		{
573 			delta1[0] = weather_defs[type].size*(modelview[0]+modelview[1]);
574 			delta1[1] = weather_defs[type].size*(modelview[4]+modelview[5]);
575 			delta1[2] = weather_defs[type].size*(modelview[8]+modelview[9]);
576 			delta2[0] = weather_defs[type].size*(modelview[0]-modelview[1]);
577 			delta2[1] = weather_defs[type].size*(modelview[4]-modelview[5]);
578 			delta2[2] = weather_defs[type].size*(modelview[8]-modelview[9]);
579 
580 			for (i = 0; i < weather_drops_count[type]; ++i)
581 			{
582 				const weather_drop *d = &weather_drops[type][i];
583                 const int j = i*20;
584                 weather_particles_coords[j+2 ] = d->pos1[0]-delta1[0];
585                 weather_particles_coords[j+3 ] = d->pos1[1]-delta1[1];
586                 weather_particles_coords[j+4 ] = d->pos1[2]-delta1[2];
587                 weather_particles_coords[j+7 ] = d->pos1[0]+delta2[0];
588                 weather_particles_coords[j+8 ] = d->pos1[1]+delta2[1];
589                 weather_particles_coords[j+9 ] = d->pos1[2]+delta2[2];
590                 weather_particles_coords[j+12] = d->pos1[0]+delta1[0];
591                 weather_particles_coords[j+13] = d->pos1[1]+delta1[1];
592                 weather_particles_coords[j+14] = d->pos1[2]+delta1[2];
593                 weather_particles_coords[j+17] = d->pos1[0]-delta2[0];
594                 weather_particles_coords[j+18] = d->pos1[1]-delta2[1];
595                 weather_particles_coords[j+19] = d->pos1[2]-delta2[2];
596 			}
597 
598 			glColor4f(weather_defs[type].color[0]*light_level[0],
599 					  weather_defs[type].color[1]*light_level[1],
600 					  weather_defs[type].color[2]*light_level[2],
601 					  weather_defs[type].color[3]);
602 
603 			bind_texture(weather_defs[type].texture);
604             glDrawArrays(GL_QUADS, 0, weather_drops_count[type]);
605 		}
606 
607 	glDisableClientState(GL_VERTEX_ARRAY);
608 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
609 	glDisable(GL_BLEND);
610 	glPopAttrib();
611 #ifdef OPENGL_TRACE
612 	CHECK_GL_ERRORS();
613 #endif //OPENGL_TRACE
614 }
615 
weather_get_drops_count(int type)616 int weather_get_drops_count(int type)
617 {
618 	return weather_drops_count[type];
619 }
620 
weather_get_intensity()621 float weather_get_intensity()
622 {
623 	return (1.0 - weather_ratios[0]);
624 }
625 
weather_get_density_from_ratios(float ratios[MAX_WEATHER_TYPES])626 float weather_get_density_from_ratios(float ratios[MAX_WEATHER_TYPES])
627 {
628 	float density = 0.0;
629 	int i;
630 	for(i = 0; i < MAX_WEATHER_TYPES; ++i)
631 		density += weather_defs[i].density * ratios[i];
632 	return density;
633 }
634 
weather_get_density()635 float weather_get_density()
636 {
637 	return current_weather_density;
638 }
639 
weather_add_lightning(int type,float x,float y)640 void weather_add_lightning(int type, float x, float y)
641 {
642 	weather_type map_weather_type = get_weather_type_for_map();
643 	if (thunders_count < MAX_THUNDERS && lightnings_defs_count > 0 &&
644 		((map_weather_type == weather_effect_rain) || (map_weather_type == weather_effect_hail)))
645 	{
646 		// store the thunder
647 		thunders[thunders_count].type = type;
648 		thunders[thunders_count].x_pos = x;
649 		thunders[thunders_count].y_pos = y;
650 		thunders[thunders_count].time = cur_time;
651 		++thunders_count;
652 
653         lightning_type = rand()%lightnings_defs_count;
654         lightning_position[0] = x;
655         lightning_position[1] = y;
656         lightning_stop = cur_time + 200 + rand()%200;
657         lightning_falling = 1;
658 
659         skybox_coords_from_ground_coords(lightning_sky_position,
660                                          lightning_position[0] + camera_x,
661                                          lightning_position[1] + camera_y);
662 
663         lightning_sky_position[0] -= camera_x;
664         lightning_sky_position[1] -= camera_y;
665 
666 		calc_shadow_matrix();
667 
668         if (skybox_update_delay > 0)
669             skybox_update_colors();
670 	}
671 }
672 
weather_init_lightning_light()673 void weather_init_lightning_light()
674 {
675 	if (lightning_falling)
676 	{
677 		glLightfv(GL_LIGHT7, GL_AMBIENT, lightning_ambient_color);
678 		glLightfv(GL_LIGHT7, GL_DIFFUSE, lightning_color);
679 		glLightfv(GL_LIGHT7, GL_POSITION, lightning_position);
680 	}
681 }
682 
weather_render_lightning()683 void weather_render_lightning()
684 {
685 	if (lightning_falling)
686 	{
687 		const float *tex_coords = lightnings_defs[lightning_type].coords;
688 		float size = lightning_sky_position[2]*0.5*(tex_coords[2]-tex_coords[0])/(tex_coords[3]-tex_coords[1]);
689 		float dx = size*cosf(-rz*M_PI/180.0);
690 		float dy = size*sinf(-rz*M_PI/180.0);
691 
692 		glPushAttrib(GL_ENABLE_BIT);
693 		glDisable(GL_LIGHTING);
694 		glDisable(GL_FOG);
695 		glEnable(GL_COLOR_MATERIAL);
696 		glEnable(GL_TEXTURE_2D);
697 		glEnable(GL_BLEND);
698 		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
699 
700 		bind_texture(lightnings_defs[lightning_type%lightnings_defs_count].texture);
701 
702 		glColor4fv(lightning_color);
703 		glBegin(GL_QUADS);
704 		glTexCoord2f(tex_coords[0], tex_coords[1]);
705 		glVertex3f(lightning_position[0]-dx, lightning_position[1]-dy, 0.0);
706 		glTexCoord2f(tex_coords[2], tex_coords[1]);
707 		glVertex3f(lightning_position[0]+dx, lightning_position[1]+dy, 0.0);
708 		glTexCoord2f(tex_coords[2], tex_coords[3]);
709 		glVertex3f(lightning_sky_position[0]+dx, lightning_sky_position[1]+dy, lightning_sky_position[2]);
710 		glTexCoord2f(tex_coords[0], tex_coords[3]);
711 		glVertex3f(lightning_sky_position[0]-dx, lightning_sky_position[1]-dy, lightning_sky_position[2]);
712 		glEnd();
713 		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
714 		glPopAttrib();
715 	}
716 }
717 
weather_get_lightning_intensity(float x,float y)718 float weather_get_lightning_intensity(float x, float y)
719 {
720 	float dx = x-lightning_position[0];
721 	float dy = y-lightning_position[1];
722 	float dist = dx*dx + dy*dy;
723 
724 	if (!lightning_falling || dist > LIGHTNING_LIGHT_RADIUS*LIGHTNING_LIGHT_RADIUS)
725 		return 0.0;
726 	else
727 		return 1.0 - dist / (LIGHTNING_LIGHT_RADIUS*LIGHTNING_LIGHT_RADIUS);
728 }
729 
730 #ifdef NEW_SOUND
weather_sound_control()731 void weather_sound_control()
732 {
733 	static Uint32 last_sound_update = 0;
734 	int i;
735 
736 	if (cur_time < last_sound_update + 200) return;
737 	else last_sound_update = cur_time;
738 
739 	if (!sound_on)
740 	{
741 		rain_sound = 0;
742 	}
743 	else
744 	{
745 		if (weather_ratios[WEATHER_RAIN] > 0.0)
746 		{
747 			// Torg: Only load sounds when we need them so we aren't wasting sources.
748 			// This is really only for NEW_SOUND.
749 			if (rain_sound == 0)
750 #ifdef NEW_SOUND
751 				rain_sound = add_server_sound(snd_rain, 0, 0, weather_ratios[WEATHER_RAIN]);
752 			else
753 				sound_source_set_gain(rain_sound, weather_ratios[WEATHER_RAIN]);
754 #endif	//NEW_SOUND
755 		}
756 		else
757 		{
758 			if (rain_sound > 0)
759 			{
760 				stop_sound(rain_sound);
761 				rain_sound = 0;
762 			}
763 		}
764 	}
765 
766 	for (i = 0; i < thunders_count; )
767 	{
768 		float dx = thunders[i].x_pos + camera_x;
769 		float dy = thunders[i].y_pos + camera_y;
770 		float dist = sqrtf(dx*dx + dy*dy);
771 		if (cur_time >= thunders[i].time + dist/SOUND_SPEED)
772 		{
773 			if (sound_on)
774 			{
775 				int snd_thunder = 0;
776 
777 				switch (thunders[i].type)
778 				{
779 				case 0:  snd_thunder = snd_thndr_1; break;
780 				case 1:  snd_thunder = snd_thndr_2; break;
781 				case 2:  snd_thunder = snd_thndr_3; break;
782 				case 3:  snd_thunder = snd_thndr_4; break;
783 				case 4:  snd_thunder = snd_thndr_5; break;
784 				default: snd_thunder = 0;
785 				}
786 
787 				if (snd_thunder)
788 				{
789 #ifdef NEW_SOUND
790 					add_server_sound(snd_thunder, 0, 0, 1.0f);
791 #endif	//NEW_SOUND
792 				}
793 			}
794 
795 			// we remove the thunder from the list
796 			if (i < --thunders_count)
797 				memcpy(&thunders[i], &thunders[thunders_count], sizeof(thunder));
798 		}
799 		else ++i;
800 	}
801 }
802 #endif	//NEW_SOUND
803 
804 #ifdef NEW_SOUND
weather_adjust_gain(float in_gain,int in_cookie)805 float weather_adjust_gain(float in_gain, int in_cookie)
806 {
807 	if (weather_ratios[WEATHER_RAIN] > 0.0 && in_cookie != rain_sound)
808 	{
809 		// Dim down all the sounds, except the rain
810 		return in_gain * (1.0f - 0.5*weather_ratios[WEATHER_RAIN]);
811 	}
812 
813 	return in_gain;
814 }
815 #endif // NEW_SOUND
816 
weather_parse_effect(xmlNode * node)817 int weather_parse_effect(xmlNode *node)
818 {
819 	xmlNode *item;
820 	xmlAttr *attr;
821 	int ok = 1;
822 	int id = -1;
823 
824 	for (attr = node->properties; attr; attr = attr->next)
825 	{
826 		if (attr->type == XML_ATTRIBUTE_NODE)
827 		{
828 			if (!xmlStrcasecmp (attr->name, (xmlChar*)"id"))
829 				id = atoi((char*)attr->children->content);
830 			else {
831 				LOG_ERROR("unknown attribute for effect: %s", (char*)attr->name);
832 				ok = 0;
833 			}
834 		}
835 	}
836 
837 	if (id < 1)
838 	{
839 		LOG_ERROR("wrong or missing id for weather effect");
840 		return 0;
841 	}
842 
843 	for(item = node->children; item; item = item->next) {
844 		if(item->type == XML_ELEMENT_NODE) {
845 			if (xmlStrcasecmp(item->name, (xmlChar*)"sprites") == 0) {
846 				weather_defs[id].use_sprites = get_bool_value(item);
847 			}
848 			else if (xmlStrcasecmp(item->name, (xmlChar*)"density") == 0) {
849 				weather_defs[id].density = get_float_value(item);
850 			}
851 			else if (xmlStrcasecmp(item->name, (xmlChar*)"color") == 0) {
852 				weather_defs[id].color[0] = 0.0;
853 				weather_defs[id].color[1] = 0.0;
854 				weather_defs[id].color[2] = 0.0;
855 				weather_defs[id].color[3] = 0.0;
856 				for (attr = item->properties; attr; attr = attr->next)
857 				{
858 					if (attr->type == XML_ATTRIBUTE_NODE)
859 					{
860 						if (!xmlStrcasecmp (attr->name, (xmlChar*)"r"))
861 							weather_defs[id].color[0] = atof((char*)attr->children->content);
862 						else if (!xmlStrcasecmp (attr->name, (xmlChar*)"g"))
863 							weather_defs[id].color[1] = atof((char*)attr->children->content);
864 						else if (!xmlStrcasecmp (attr->name, (xmlChar*)"b"))
865 							weather_defs[id].color[2] = atof((char*)attr->children->content);
866 						else if (!xmlStrcasecmp (attr->name, (xmlChar*)"a"))
867 							weather_defs[id].color[3] = atof((char*)attr->children->content);
868 						else {
869 							LOG_ERROR("unknown attribute for weather effect color: %s", (char*)attr->name);
870 							ok = 0;
871 						}
872 					}
873 				}
874 				weather_defs[id].color[0] /= 255.0;
875 				weather_defs[id].color[1] /= 255.0;
876 				weather_defs[id].color[2] /= 255.0;
877 				weather_defs[id].color[3] /= 255.0;
878 			}
879 			else if (xmlStrcasecmp(item->name, (xmlChar*)"size") == 0) {
880 				weather_defs[id].size = get_float_value(item);
881 			}
882 			else if (xmlStrcasecmp(item->name, (xmlChar*)"speed") == 0) {
883 				weather_defs[id].speed = get_float_value(item);
884 			}
885 			else if (xmlStrcasecmp(item->name, (xmlChar*)"wind_effect") == 0) {
886 				weather_defs[id].wind_effect = get_float_value(item);
887 			}
888 			else if (xmlStrcasecmp(item->name, (xmlChar*)"texture") == 0) {
889 				weather_defs[id].texture = load_texture_cached((char*)item->children->content, tt_mesh);
890 			}
891 			else {
892 				LOG_ERROR("unknown node for weather effect: %s", item->name);
893 				ok = 0;
894 			}
895 		}
896 		else if (item->type == XML_ENTITY_REF_NODE) {
897 			ok &= weather_parse_effect(item->children);
898 		}
899 	}
900 
901 	return ok;
902 }
903 
weather_parse_lightning(xmlNode * node)904 int weather_parse_lightning(xmlNode *node)
905 {
906 	xmlAttr *attr;
907 	int ok = 1;
908 	int id = lightnings_defs_count++;
909 
910 	lightnings_defs[id].texture = -1;
911 	lightnings_defs[id].coords[0] = 0.0;
912 	lightnings_defs[id].coords[1] = 0.0;
913 	lightnings_defs[id].coords[2] = 0.0;
914 	lightnings_defs[id].coords[3] = 0.0;
915 
916 	for (attr = node->properties; attr; attr = attr->next)
917 	{
918 		if (attr->type == XML_ATTRIBUTE_NODE)
919 		{
920 			if (!xmlStrcasecmp (attr->name, (xmlChar*)"texture"))
921 				lightnings_defs[id].texture = load_texture_cached((char*)attr->children->content, tt_mesh);
922 			else if (!xmlStrcasecmp (attr->name, (xmlChar*)"x1"))
923 				lightnings_defs[id].coords[0] = atof((char*)attr->children->content);
924 			else if (!xmlStrcasecmp (attr->name, (xmlChar*)"y1"))
925 				lightnings_defs[id].coords[1] = atof((char*)attr->children->content);
926 			else if (!xmlStrcasecmp (attr->name, (xmlChar*)"x2"))
927 				lightnings_defs[id].coords[2] = atof((char*)attr->children->content);
928 			else if (!xmlStrcasecmp (attr->name, (xmlChar*)"y2"))
929 				lightnings_defs[id].coords[3] = atof((char*)attr->children->content);
930 			else {
931 				LOG_ERROR("unknown attribute for weather effect color: %s", (char*)attr->name);
932 				ok = 0;
933 			}
934 		}
935 	}
936 
937 	return ok;
938 }
939 
weather_parse_defs(xmlNode * node)940 int weather_parse_defs(xmlNode *node)
941 {
942 	xmlNode *def;
943 	int ok = 1;
944 
945 	for (def = node->children; def; def = def->next) {
946 		if (def->type == XML_ELEMENT_NODE)
947 			if (xmlStrcasecmp(def->name, (xmlChar*)"effect") == 0) {
948 				ok &= weather_parse_effect(def);
949 			}
950 			else if (xmlStrcasecmp(def->name, (xmlChar*)"lightning") == 0) {
951 				ok &= weather_parse_lightning(def);
952 			}
953 			else {
954 				LOG_ERROR("unknown element for weather: %s", def->name);
955 				ok = 0;
956 			}
957 		else if (def->type == XML_ENTITY_REF_NODE) {
958 			ok &= weather_parse_defs(def->children);
959 		}
960 	}
961 
962 	return ok;
963 }
964 
weather_read_defs(const char * file_name)965 int weather_read_defs(const char *file_name)
966 {
967 	xmlNode *root;
968 	xmlDoc *doc;
969 	int ok = 1;
970 
971 	doc = xmlReadFile(file_name, NULL, 0);
972 	if (doc == NULL) {
973 		LOG_ERROR("Unable to read weather definition file %s", file_name);
974 		return 0;
975 	}
976 
977 	root = xmlDocGetRootElement(doc);
978 	if (root == NULL) {
979 		LOG_ERROR("Unable to parse weather definition file %s", file_name);
980 		ok = 0;
981 	} else if (xmlStrcasecmp(root->name, (xmlChar*)"weather") != 0) {
982 		LOG_ERROR("Unknown key \"%s\" (\"weather\" expected).", root->name);
983 		ok = 0;
984 	} else {
985 		ok = weather_parse_defs(root);
986 	}
987 
988 	xmlFreeDoc(doc);
989 	return ok;
990 }
991