#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "weather.h"
#include "actors.h"
#include "asc.h"
#include "client_serv.h"
#ifdef NEW_WEATHER
#include "draw_scene.h"
#include "elconfig.h"
#endif // NEW_WEATHER
#include "global.h"
#include "lights.h"
#include "map.h"
#include "misc.h"
#ifdef NEW_WEATHER
#include "particles.h"
#include "textures.h"
#endif // NEW_WEATHER
#include "shadows.h"
#include "sound.h"
#ifdef NEW_WEATHER
#include <SDL_timer.h>
#include "errors.h"
#include "text.h"
#endif
#ifdef OPENGL_TRACE
#include "gl_init.h"
#endif
#ifdef SKY_FPV
#include "sky.h"
#endif // SKY_FPV

int use_fog = 1;

int wind_speed_srv = 0;	//strength of wind, as set by server. 100 is about the max
int wind_direction_srv = 0;	//wind direction, in degrees, as set by server. 0 and 360 == north
int wind_speed = 0;	//strength of wind, based on server's setting and local randomization
int wind_direction = 0;	//wind direction, based on server's setting and local randomization

#ifdef NEW_WEATHER

/* N E W   W E A T H E R *****************************************************/

#define MAX_RAIN_DROPS 10000
#define MAX_LIGHTNING_DEFS 20
#define MAX_THUNDERS 20

#define LIGHTNING_LIGHT_RADIUS 20.0
#define SOUND_SPEED 0.1 // real sound speed = 0.34029 m/ms

#define WEATHER_NONE 0
#define WEATHER_RAIN 1

typedef struct
{
	float pos1[3];
	float pos2[3];
} weather_drop;

typedef struct {
	int use_sprites;
	float density;
	float color[4];
	float size;
	float speed;
	float wind_effect;
	int texture;
} weather_def;

typedef struct
{
	float x_pos;
	float y_pos;
	float radius;
	int type;
	float intensity;
	float intensity_change_speed;
	int intensity_change_duration;
} weather_area;

typedef struct {
	int type;
	float x_pos;
	float y_pos;
	Uint32 time;
} thunder;

typedef struct {
	int texture;
	float coords[4]; // left bottom right top
} lightning_def;

weather_drop weather_drops[MAX_WEATHER_TYPES][MAX_RAIN_DROPS];
int weather_drops_count[MAX_WEATHER_TYPES];

weather_def weather_defs[MAX_WEATHER_TYPES];

weather_area weather_areas[MAX_WEATHER_AREAS];

lightning_def lightnings_defs[MAX_LIGHTNING_DEFS];
int lightnings_defs_count = 0;

thunder thunders[MAX_THUNDERS];
int thunders_count = 0;

Uint32 lightning_stop = 0;
int lightning_type;
float lightning_position[4] = {0.0, 0.0, 100.0, 1.0};
float lightning_sky_position[4] = {0.0, 0.0, 0.0, 1.0};
float lightning_color[4] = {0.9, 0.85, 1.0, 1.0};
float lightning_ambient_color[4] = {0.50, 0.45, 0.55, 1.0};
int lightning_falling = 0;

float weather_ratios[MAX_WEATHER_TYPES];

float current_weather_density;

#define RANDOM_TABLE_SIZE 100000
#define RAND_ONE (next_random_number())

float random_table[RANDOM_TABLE_SIZE];
int last_random_number = -1;

#ifdef NEW_SOUND
unsigned int rain_sound = 0;
#endif //NEW_SOUND

float weather_color[4] = {0.0, 0.0, 0.0, 1.0};
float fog_alpha;

// array used to build coordinates of quads to display particles
float weather_particles_coords[MAX_RAIN_DROPS*20];

__inline__ float next_random_number()
{
	last_random_number = (last_random_number+1)%RANDOM_TABLE_SIZE;
	return random_table[last_random_number];
}

int weather_read_defs(const char *file_name);

void weather_init()
{
	int i;

	for (i = 0; i < MAX_WEATHER_TYPES; ++i)
	{
		weather_ratios[i] = 0.0;
		weather_drops_count[i] = 0;
		weather_defs[i].use_sprites = 0;
		weather_defs[i].density = 0.0;
		weather_defs[i].color[0] = 0.0;
		weather_defs[i].color[1] = 0.0;
		weather_defs[i].color[2] = 0.0;
		weather_defs[i].color[3] = 0.0;
		weather_defs[i].size = 0.0;
		weather_defs[i].speed = 0.0;
		weather_defs[i].wind_effect = 0.0;
		weather_defs[i].texture = -1;
	}
	weather_ratios[0] = 1.0;

	for (i = 0; i < MAX_WEATHER_AREAS; ++i)
	{
		weather_areas[i].type = 0;
	}

	// init the random numbers table
	for (i = 0; i < RANDOM_TABLE_SIZE; ++i)
		random_table[i] = (float)rand() / (float)RAND_MAX;

    // init the particles texture coordinates
    for (i = 0; i < MAX_RAIN_DROPS; ++i)
    {
        const int j = i*20;
        weather_particles_coords[j   ] = 0.0f;
        weather_particles_coords[j+1 ] = 0.0f;
        weather_particles_coords[j+5 ] = 1.0f;
        weather_particles_coords[j+6 ] = 0.0f;
        weather_particles_coords[j+10] = 1.0f;
        weather_particles_coords[j+11] = 1.0f;
        weather_particles_coords[j+15] = 0.0f;
        weather_particles_coords[j+16] = 1.0f;
    }

	weather_read_defs("./weather.xml");
}

void weather_clear()
{
	int i;
	thunders_count = 0;
	lightning_stop = 0;
	lightning_falling = 0;
	weather_ratios[0] = 1.0;
	for(i = 1; i < MAX_WEATHER_TYPES; ++i)
	{
		weather_ratios[i] = 0.0;
		weather_drops_count[i] = 0;
	}

	for (i = 0; i < MAX_WEATHER_AREAS; ++i)
	{
		weather_areas[i].type = 0;
	}
}

void weather_set_area(int area, float x, float y, float radius, int type, float intensity, int change_duration)
{
	if (weather_areas[area].type == 0) weather_areas[area].intensity = 0.0;

	weather_areas[area].type = type;
	weather_areas[area].x_pos = x;
	weather_areas[area].y_pos = y;
	weather_areas[area].radius = radius;
	weather_areas[area].intensity_change_duration = change_duration * 1000;
	weather_areas[area].intensity_change_speed = (intensity - weather_areas[area].intensity) / weather_areas[area].intensity_change_duration;

#ifdef DEBUG
	printf("setting area %d at %f,%f with radius %f\n",
		   area, x, y, radius);
#endif // DEBUG
}

void weather_get_from_server(const Uint8* data)
{
/*
	//first, catch non-precipitations
	if(data[0] == weather_effect_wind){
		wind_direction_srv = (2 * data[1])%360;
		wind_speed_srv = data[2];
		return;
	} else if(data[0] == weather_effect_leaves){
		//EC_TAG
		return;
	} else if(data[0] > MAX_WEATHER_TYPES){
#ifdef DEBUG
		LOG_TO_CONSOLE(c_red1, "Server sent an unknown weather type");
#endif // DEBUG
		LOG_ERROR("Server sent unknown weather type %d", data[0]);
		return;
		//from now on, deal with the set of precipitations
	} else if(data[2] == 0 && !weather_active()){
		return;	//stop? but we're already stopped...
	} else if(data[2] != 0 && weather_active()){
		set_weather_ratio(data[0], data[2]);
		return;
	} else if(data[2] != 0 && !weather_active()){
		set_weather_ratio(data[0], data[2]);
		start_weather(data[1], ((float)(data[2]))/100.0f);
		return;
	} else {
		stop_weather(data[1], ((float)(data[2]))/100.0f);
	}
*/
}

void weather_compute_ratios(float ratios[MAX_WEATHER_TYPES], float x, float y)
{
	int i;
	float sum = 0.0;

	// we reset all the values
	for (i = 0; i < MAX_WEATHER_TYPES; ++i)
		ratios[i] = 0.0;

	// we compute the intensity for each type of weather according to the areas
	for (i = 0; i < MAX_WEATHER_AREAS; ++i)
		if (weather_areas[i].type > 0)
		{
			float dx = x - weather_areas[i].x_pos;
			float dy = y - weather_areas[i].y_pos;
			float dist = dx*dx + dy*dy;
			float r = weather_areas[i].radius*weather_areas[i].radius;
			if (dist < r)
				ratios[weather_areas[i].type] += (1.0 - dist/r) * weather_areas[i].intensity;
		}

	// we compute the sum of all the intensities
	for (i = 1; i < MAX_WEATHER_TYPES; ++i)
		sum += ratios[i];

	if (sum < 1.0)
	{
		ratios[0] = 1.0 - sum;
	}
	else
	{
		// we normalize the intensities if needed
		ratios[0] = 0.0;
		for (i = 1; i < MAX_WEATHER_TYPES; ++i)
			ratios[i] /= sum;
	}
}

void weather_get_color_from_ratios(float color[4], float ratios[MAX_WEATHER_TYPES])
{
	int i, j;
	for(i = 0; i < 4; ++i)
	{
		color[i] = 0.0;
		for(j = 0; j < MAX_WEATHER_TYPES; ++j)
		{
			color[i] += weather_defs[j].color[i] * ratios[j];
		}
	}
}

void __inline__ make_drop(int type, int i, float x, float y, float z)
{
	weather_drops[type][i].pos1[0] = x + 16.0f * RAND_ONE - 8.0f;
	weather_drops[type][i].pos1[1] = y + 16.0f * RAND_ONE - 8.0f;
	weather_drops[type][i].pos1[2] = z + 10.0f * RAND_ONE +  2.0f;
}

void update_wind(void)
{
	int dir_d = wind_direction_srv + (int)((float)(RAND_ONE * 60 - 30));
	int speed_d = wind_speed_srv + (int)((float)(RAND_ONE * ((float)wind_speed)/5.0f - ((float)wind_speed)/10.0f));
	if(dir_d < wind_direction){
		--wind_direction;
	} else if(dir_d > wind_direction){
		++wind_direction;
	}
	wind_direction %= 360;
	if(speed_d <= 0){
		speed_d = 0;
	} else if(speed_d > 1000){
		speed_d = 1000;
	}
	if(speed_d < wind_speed){
		--wind_speed;
	} else if(speed_d > wind_speed){
		++wind_speed;
	}
}

void update_weather_type(int type, float x, float y, float z, int ticks)
{
	int num_drops = weather_ratios[type] * weather_defs[type].density * particles_percentage * 0.01 * MAX_RAIN_DROPS;

	if (num_drops > MAX_RAIN_DROPS) num_drops = MAX_RAIN_DROPS;
	
	if (weather_drops_count[type] > num_drops)
		weather_drops_count[type] = num_drops;
	
	if (num_drops > 0)
	{
		int i;
		float x_move = weather_defs[type].wind_effect * sinf((float)wind_direction*M_PI/180) * wind_speed;
		float y_move = weather_defs[type].wind_effect * cosf((float)wind_direction*M_PI/180) * wind_speed;
		float z_move = -weather_defs[type].speed;
		float dt = ticks * 1E-3;
		float dx, dy, dz;
		
		for(i = 0; i < weather_drops_count[type]; ++i)
		{
			dx = x_move*(1.1-0.2*RAND_ONE);
			dy = y_move*(1.1-0.2*RAND_ONE);
			dz = z_move*(1.1-0.2*RAND_ONE);

			if (weather_drops[type][i].pos1[2] < z-1.0f)
			{
				// the drop should still exist so we recreate it
				make_drop(type, i, x, y, z);
			}
			else
			{
				// 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)
				weather_drops[type][i].pos1[0] += dx * dt;
				if (weather_drops[type][i].pos1[0] < x - 8.0f)
				{
					weather_drops[type][i].pos1[0] += 16.0f;
					weather_drops[type][i].pos2[0] += 16.0f;
				}
				else if(weather_drops[type][i].pos1[0] > x + 8.0f)
				{
					weather_drops[type][i].pos1[0] -= 16.0f;
					weather_drops[type][i].pos2[0] -= 16.0f;
				}
				
				weather_drops[type][i].pos1[1] += dy * dt;
				if (weather_drops[type][i].pos1[1] < y - 8.0f)
				{
					weather_drops[type][i].pos1[1] += 16.0f;
					weather_drops[type][i].pos2[1] += 16.0f;
				}
				else if(weather_drops[type][i].pos1[1] > y + 8.0f)
				{
					weather_drops[type][i].pos1[1] -= 16.0f;
					weather_drops[type][i].pos2[1] -= 16.0f;
				}
				
				weather_drops[type][i].pos1[2] += dz * dt;
			}

			weather_drops[type][i].pos2[0] = weather_drops[type][i].pos1[0] - dx * 0.02;
			weather_drops[type][i].pos2[1] = weather_drops[type][i].pos1[1] - dy * 0.02;
			weather_drops[type][i].pos2[2] = weather_drops[type][i].pos1[2] - dz * 0.02;
		}
		
		// if there are not enough drops, we recreate new ones
		if (weather_drops_count[type] < num_drops)
		{
			for (i = weather_drops_count[type]; i < num_drops; ++i)
			{
				make_drop(type, i, x, y, z);
				weather_drops[type][i].pos2[0] = weather_drops[type][i].pos1[0] - x_move * 0.02;
				weather_drops[type][i].pos2[1] = weather_drops[type][i].pos1[1] - y_move * 0.02;
				weather_drops[type][i].pos2[2] = weather_drops[type][i].pos1[2] - z_move * 0.02;
			}
			weather_drops_count[type] = num_drops;
		}
	}
}

void weather_update()
{
	static Uint32 last_update = 0;
	Uint32 ticks = cur_time - last_update;
	int i;

	update_wind();

	// we update the lightning
	if (lightning_falling && cur_time > lightning_stop)
	{
		lightning_falling = 0;
		calc_shadow_matrix();
		if (skybox_update_delay > 0)
			skybox_update_colors();
	}

	// we update the areas
	for (i = 0; i < MAX_WEATHER_AREAS; ++i)
		if (weather_areas[i].type > 0 && weather_areas[i].intensity_change_duration > 0)
		{
			if (weather_areas[i].intensity_change_duration <= ticks)
			{
				weather_areas[i].intensity += weather_areas[i].intensity_change_speed*weather_areas[i].intensity_change_duration;
				weather_areas[i].intensity_change_duration = 0;
			}
			else
			{
				weather_areas[i].intensity += weather_areas[i].intensity_change_speed*ticks;
				weather_areas[i].intensity_change_duration -= ticks;
			}
			if (weather_areas[i].intensity_change_speed < 0.0)
			{
				if (weather_areas[i].intensity <= 0.001)
				{
					weather_areas[i].intensity = 0.0;
					weather_areas[i].type = 0;
				}
			}
			else
			{
				if (weather_areas[i].intensity > 1.0)
					weather_areas[i].intensity = 1.0;
			}
		}
	
	// we compute the ratios at the actor position
	weather_compute_ratios(weather_ratios, -camera_x, -camera_y);
	
	current_weather_density = weather_get_density_from_ratios(weather_ratios);

	// we compute the weather color at the actor position
	weather_get_color_from_ratios(weather_color, weather_ratios);
	
	// we update the weather types
	for (i = 1; i < MAX_WEATHER_TYPES; ++i)
		update_weather_type(i, -camera_x, -camera_y, 0.0, ticks);
	
	last_update = cur_time;
}

void weather_render_fog()
{
	glEnable(GL_FOG);
	glFogi(GL_FOG_MODE, GL_EXP2);
	glFogf(GL_FOG_DENSITY, skybox_fog_density);
	glFogfv(GL_FOG_COLOR, skybox_fog_color);

#ifdef OPENGL_TRACE
	CHECK_GL_ERRORS();
#endif //OPENGL_TRACE
}

void weather_render()
{
	int type;
	int i;
	float modelview[16];
	float delta1[3], delta2[3];
	float color1[4], color2[4], light_level[3];

	skybox_get_current_color(color1, skybox_light_ambient);
	skybox_get_current_color(color2, skybox_light_diffuse);

	light_level[0] = 0.5 + (0.2 + color1[0] + color2[0]) * 0.5;
	light_level[1] = 0.5 + (0.2 + color1[1] + color2[1]) * 0.5;
	light_level[2] = 0.5 + (0.2 + color1[2] + color2[2]) * 0.5;

	if (lightning_falling)
	{
		light_level[0] += 0.5 * lightning_color[0];
		light_level[1] += 0.5 * lightning_color[1];
		light_level[2] += 0.5 * lightning_color[2];
	}

	if (light_level[0] > 1.0) light_level[0] = 1.0;
	if (light_level[1] > 1.0) light_level[1] = 1.0;
	if (light_level[2] > 1.0) light_level[2] = 1.0;

    glGetFloatv(GL_MODELVIEW_MATRIX, modelview);
          
	glPushAttrib(GL_ENABLE_BIT);
	glDisable(GL_LIGHTING);
	
	glDisable(GL_ALPHA_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	// we first render the weather that don't use particles
	glEnableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_NORMAL_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);
	glDisable(GL_TEXTURE_2D);
	
	for (type = 1; type < MAX_WEATHER_TYPES; ++type)
		if (!weather_defs[type].use_sprites && weather_drops_count[type] > 0)
		{
			glLineWidth(weather_defs[type].size);
			glColor4f(weather_defs[type].color[0]*light_level[0],
					  weather_defs[type].color[1]*light_level[1],
					  weather_defs[type].color[2]*light_level[2],
					  weather_defs[type].color[3]);
			glVertexPointer(3, GL_FLOAT, 0, weather_drops[type]);
	
			for (i = 0; i < weather_drops_count[type]; i += 1000) // to avoid long arrays
			{
				int nb = weather_drops_count[type] - i;
				if (nb > 1000) nb = 1000;
				glDrawArrays(GL_LINES, i, nb);
			}
		}
	
	glLineWidth(1.0);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_ALPHA_TEST);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	
	// we then render the other precipitations as sprites
    glTexCoordPointer(2, GL_FLOAT, 5*sizeof(float), weather_particles_coords);
    glVertexPointer(3, GL_FLOAT, 5*sizeof(float), weather_particles_coords+2);
	for (type = 2; type < MAX_WEATHER_TYPES; ++type)
		if (weather_defs[type].use_sprites && weather_drops_count[type] > 0)
		{
			delta1[0] = weather_defs[type].size*(modelview[0]+modelview[1]);
			delta1[1] = weather_defs[type].size*(modelview[4]+modelview[5]);
			delta1[2] = weather_defs[type].size*(modelview[8]+modelview[9]);
			delta2[0] = weather_defs[type].size*(modelview[0]-modelview[1]);
			delta2[1] = weather_defs[type].size*(modelview[4]-modelview[5]);
			delta2[2] = weather_defs[type].size*(modelview[8]-modelview[9]);
			
			for (i = 0; i < weather_drops_count[type]; ++i)
			{
				const weather_drop *d = &weather_drops[type][i];
                const int j = i*20;
                weather_particles_coords[j+2 ] = d->pos1[0]-delta1[0];
                weather_particles_coords[j+3 ] = d->pos1[1]-delta1[1];
                weather_particles_coords[j+4 ] = d->pos1[2]-delta1[2];
                weather_particles_coords[j+7 ] = d->pos1[0]+delta2[0];
                weather_particles_coords[j+8 ] = d->pos1[1]+delta2[1];
                weather_particles_coords[j+9 ] = d->pos1[2]+delta2[2];
                weather_particles_coords[j+12] = d->pos1[0]+delta1[0];
                weather_particles_coords[j+13] = d->pos1[1]+delta1[1];
                weather_particles_coords[j+14] = d->pos1[2]+delta1[2];
                weather_particles_coords[j+17] = d->pos1[0]-delta2[0];
                weather_particles_coords[j+18] = d->pos1[1]-delta2[1];
                weather_particles_coords[j+19] = d->pos1[2]-delta2[2];
			}

			glColor4f(weather_defs[type].color[0]*light_level[0],
					  weather_defs[type].color[1]*light_level[1],
					  weather_defs[type].color[2]*light_level[2],
					  weather_defs[type].color[3]);
			
			get_and_set_texture_id(weather_defs[type].texture);
            glDrawArrays(GL_QUADS, 0, weather_drops_count[type]);
		}

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisable(GL_BLEND);
	glPopAttrib();
#ifdef OPENGL_TRACE
	CHECK_GL_ERRORS();
#endif //OPENGL_TRACE
}

int weather_get_drops_count(int type)
{
	return weather_drops_count[type];
}

float weather_get_intensity()
{
	return (1.0 - weather_ratios[0]);
}

float weather_get_density_from_ratios(float ratios[MAX_WEATHER_TYPES])
{
	float density = 0.0;
	int i;
	for(i = 0; i < MAX_WEATHER_TYPES; ++i)
		density += weather_defs[i].density * ratios[i];
	return density;
}

float weather_get_density()
{
	return current_weather_density;
}

void weather_add_lightning(int type, float x, float y)
{
	if (thunders_count < MAX_THUNDERS && lightnings_defs_count > 0)
	{
		// store the thunder
		thunders[thunders_count].type = type;
		thunders[thunders_count].x_pos = x;
		thunders[thunders_count].y_pos = y;
		thunders[thunders_count].time = cur_time;
		++thunders_count;

        lightning_type = rand()%lightnings_defs_count;
        lightning_position[0] = x;
        lightning_position[1] = y;
        lightning_stop = cur_time + 200 + rand()%200;
        lightning_falling = 1;
        
        skybox_coords_from_ground_coords(lightning_sky_position,
                                         lightning_position[0] + camera_x,
                                         lightning_position[1] + camera_y);
        
        lightning_sky_position[0] -= camera_x;
        lightning_sky_position[1] -= camera_y;
        
		calc_shadow_matrix();

        if (skybox_update_delay > 0)
            skybox_update_colors();
	}
}

void weather_init_lightning_light()
{
	if (lightning_falling)
	{
		glLightfv(GL_LIGHT7, GL_AMBIENT, lightning_ambient_color);
		glLightfv(GL_LIGHT7, GL_DIFFUSE, lightning_color);
		glLightfv(GL_LIGHT7, GL_POSITION, lightning_position);
	}
}

void weather_render_lightning()
{
	if (lightning_falling)
	{
		const float *tex_coords = lightnings_defs[lightning_type].coords;
		float size = lightning_sky_position[2]*0.5*(tex_coords[2]-tex_coords[0])/(tex_coords[3]-tex_coords[1]);
		float dx = size*cosf(-rz*M_PI/180.0);
		float dy = size*sinf(-rz*M_PI/180.0);

		glPushAttrib(GL_ENABLE_BIT);
		glDisable(GL_LIGHTING);
		glDisable(GL_FOG);
		glEnable(GL_COLOR_MATERIAL);
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE);

		get_and_set_texture_id(lightnings_defs[lightning_type%lightnings_defs_count].texture);

		glColor4fv(lightning_color);
		glBegin(GL_QUADS);
		glTexCoord2f(tex_coords[0], tex_coords[1]);
		glVertex3f(lightning_position[0]-dx, lightning_position[1]-dy, 0.0);
		glTexCoord2f(tex_coords[2], tex_coords[1]);
		glVertex3f(lightning_position[0]+dx, lightning_position[1]+dy, 0.0);
		glTexCoord2f(tex_coords[2], tex_coords[3]);
		glVertex3f(lightning_sky_position[0]+dx, lightning_sky_position[1]+dy, lightning_sky_position[2]);
		glTexCoord2f(tex_coords[0], tex_coords[3]);
		glVertex3f(lightning_sky_position[0]-dx, lightning_sky_position[1]-dy, lightning_sky_position[2]);
		glEnd();
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glPopAttrib();
	}
}

float weather_get_lightning_intensity(float x, float y)
{
	float dx = x-lightning_position[0];
	float dy = y-lightning_position[1];
	float dist = dx*dx + dy*dy;

	if (!lightning_falling || dist > LIGHTNING_LIGHT_RADIUS*LIGHTNING_LIGHT_RADIUS)
		return 0.0;
	else
		return 1.0 - dist / (LIGHTNING_LIGHT_RADIUS*LIGHTNING_LIGHT_RADIUS);
}

void weather_sound_control()
{
	static Uint32 last_sound_update = 0;
	int i;

	if (cur_time < last_sound_update + 200) return;
	else last_sound_update = cur_time;

	if (!sound_on)
	{
		rain_sound = 0;
	}
	else
	{
		if (weather_ratios[WEATHER_RAIN] > 0.0)
		{
			// Torg: Only load sounds when we need them so we aren't wasting sources.
			// This is really only for NEW_SOUND.
			if (rain_sound == 0)
#ifdef NEW_SOUND
				rain_sound = add_server_sound(snd_rain, 0, 0, weather_ratios[WEATHER_RAIN]);
			else
				sound_source_set_gain(rain_sound, weather_ratios[WEATHER_RAIN]);
#endif	//NEW_SOUND
		}
		else
		{
			if (rain_sound > 0)
			{
				stop_sound(rain_sound);
				rain_sound = 0;
			}
		}
	}
		
	for (i = 0; i < thunders_count; )
	{
		float dx = thunders[i].x_pos + camera_x;
		float dy = thunders[i].y_pos + camera_y;
		float dist = sqrtf(dx*dx + dy*dy);
		if (cur_time >= thunders[i].time + dist/SOUND_SPEED)
		{
			if (sound_on)
			{
				int snd_thunder = 0;
			
				switch (thunders[i].type)
				{
				case 0:  snd_thunder = snd_thndr_1; break;
				case 1:  snd_thunder = snd_thndr_2; break;
				case 2:  snd_thunder = snd_thndr_3; break;
				case 3:  snd_thunder = snd_thndr_4; break;
				case 4:  snd_thunder = snd_thndr_5; break;
				default: snd_thunder = 0;
				}
			
				if (snd_thunder)
				{
#ifdef NEW_SOUND
					add_server_sound(snd_thunder, 0, 0, 1.0f);
#endif	//NEW_SOUND
				}
			}
			
			// we remove the thunder from the list
			if (i < --thunders_count)
				memcpy(&thunders[i], &thunders[thunders_count], sizeof(thunder));
		}
		else ++i;
	}
}

#ifdef NEW_SOUND
float weather_adjust_gain(float in_gain, int in_cookie)
{
	if (weather_ratios[WEATHER_RAIN] > 0.0 && in_cookie != rain_sound)
	{
		// Dim down all the sounds, except the rain
		return in_gain * (1.0f - 0.5*weather_ratios[WEATHER_RAIN]);
	}

	return in_gain;
}
#endif // NEW_SOUND

int weather_parse_effect(xmlNode *node)
{
	xmlNode *item;
	xmlAttr *attr;
	int ok = 1;
	int id = -1;

	for (attr = node->properties; attr; attr = attr->next)
	{
		if (attr->type == XML_ATTRIBUTE_NODE)
		{
			if (!xmlStrcasecmp (attr->name, (xmlChar*)"id"))
				id = atoi((char*)attr->children->content);
			else {
				LOG_ERROR("unknown attribute for effect: %s", (char*)attr->name);
				ok = 0;
			}
		}
	}

	if (id < 1)
	{
		LOG_ERROR("wrong or missing id for weather effect");
		return 0;
	}

	for(item = node->children; item; item = item->next) {
		if(item->type == XML_ELEMENT_NODE) {
			if (xmlStrcasecmp(item->name, (xmlChar*)"sprites") == 0) {
				weather_defs[id].use_sprites = get_bool_value(item);
			}
			else if (xmlStrcasecmp(item->name, (xmlChar*)"density") == 0) {
				weather_defs[id].density = get_float_value(item);
			}
			else if (xmlStrcasecmp(item->name, (xmlChar*)"color") == 0) {
				weather_defs[id].color[0] = 0.0;
				weather_defs[id].color[1] = 0.0;
				weather_defs[id].color[2] = 0.0;
				weather_defs[id].color[3] = 0.0;
				for (attr = item->properties; attr; attr = attr->next)
				{
					if (attr->type == XML_ATTRIBUTE_NODE)
					{
						if (!xmlStrcasecmp (attr->name, (xmlChar*)"r"))
							weather_defs[id].color[0] = atof((char*)attr->children->content);
						else if (!xmlStrcasecmp (attr->name, (xmlChar*)"g"))
							weather_defs[id].color[1] = atof((char*)attr->children->content);
						else if (!xmlStrcasecmp (attr->name, (xmlChar*)"b"))
							weather_defs[id].color[2] = atof((char*)attr->children->content);
						else if (!xmlStrcasecmp (attr->name, (xmlChar*)"a"))
							weather_defs[id].color[3] = atof((char*)attr->children->content);
						else {
							LOG_ERROR("unknown attribute for weather effect color: %s", (char*)attr->name);
							ok = 0;
						}
					}
				}
				weather_defs[id].color[0] /= 255.0;
				weather_defs[id].color[1] /= 255.0;
				weather_defs[id].color[2] /= 255.0;
				weather_defs[id].color[3] /= 255.0;
			}
			else if (xmlStrcasecmp(item->name, (xmlChar*)"size") == 0) {
				weather_defs[id].size = get_float_value(item);
			}
			else if (xmlStrcasecmp(item->name, (xmlChar*)"speed") == 0) {
				weather_defs[id].speed = get_float_value(item);
			}
			else if (xmlStrcasecmp(item->name, (xmlChar*)"wind_effect") == 0) {
				weather_defs[id].wind_effect = get_float_value(item);
			}
			else if (xmlStrcasecmp(item->name, (xmlChar*)"texture") == 0) {
				weather_defs[id].texture = load_texture_cache((char*)item->children->content, 0);
			}
			else {
				LOG_ERROR("unknown node for weather effect: %s", item->name);
				ok = 0;
			}
		}
		else if (item->type == XML_ENTITY_REF_NODE) {
			ok &= weather_parse_effect(item->children);
		}
	}

	return ok;
}

int weather_parse_lightning(xmlNode *node)
{
	xmlAttr *attr;
	int ok = 1;
	int id = lightnings_defs_count++;

	lightnings_defs[id].texture = -1;
	lightnings_defs[id].coords[0] = 0.0;
	lightnings_defs[id].coords[1] = 0.0;
	lightnings_defs[id].coords[2] = 0.0;
	lightnings_defs[id].coords[3] = 0.0;

	for (attr = node->properties; attr; attr = attr->next)
	{
		if (attr->type == XML_ATTRIBUTE_NODE)
		{
			if (!xmlStrcasecmp (attr->name, (xmlChar*)"texture"))
				lightnings_defs[id].texture = load_texture_cache((char*)attr->children->content, 0);
			else if (!xmlStrcasecmp (attr->name, (xmlChar*)"x1"))
				lightnings_defs[id].coords[0] = atof((char*)attr->children->content);
			else if (!xmlStrcasecmp (attr->name, (xmlChar*)"y1"))
				lightnings_defs[id].coords[1] = atof((char*)attr->children->content);
			else if (!xmlStrcasecmp (attr->name, (xmlChar*)"x2"))
				lightnings_defs[id].coords[2] = atof((char*)attr->children->content);
			else if (!xmlStrcasecmp (attr->name, (xmlChar*)"y2"))
				lightnings_defs[id].coords[3] = atof((char*)attr->children->content);
			else {
				LOG_ERROR("unknown attribute for weather effect color: %s", (char*)attr->name);
				ok = 0;
			}
		}
	}

	return ok;
}

int weather_parse_defs(xmlNode *node)
{
	xmlNode *def;
	int ok = 1;

	for (def = node->children; def; def = def->next) {
		if (def->type == XML_ELEMENT_NODE)
			if (xmlStrcasecmp(def->name, (xmlChar*)"effect") == 0) {
				ok &= weather_parse_effect(def);
			}
			else if (xmlStrcasecmp(def->name, (xmlChar*)"lightning") == 0) {
				ok &= weather_parse_lightning(def);
			}
			else {
				LOG_ERROR("unknown element for weather: %s", def->name);
				ok = 0;
			}
		else if (def->type == XML_ENTITY_REF_NODE) {
			ok &= weather_parse_defs(def->children);
		}
	}

	return ok;
}

int weather_read_defs(const char *file_name)
{
	xmlNode *root;
	xmlDoc *doc;
	int ok = 1;

	doc = xmlReadFile(file_name, NULL, 0);
	if (doc == NULL) {
		LOG_ERROR("Unable to read weather definition file %s", file_name);
		return 0;
	}

	root = xmlDocGetRootElement(doc);
	if (root == NULL) {
		LOG_ERROR("Unable to parse weather definition file %s", file_name);
		ok = 0;
	} else if (xmlStrcasecmp(root->name, (xmlChar*)"weather") != 0) {
		LOG_ERROR("Unknown key \"%s\" (\"weather\" expected).", root->name);
		ok = 0;
	} else {
		ok = weather_parse_defs(root);
	}

	xmlFreeDoc(doc);
	return ok;
}











#else // !def NEW_WEATHER

/* O L D   W E A T H E R *****************************************************/

#define MAX_RAIN_DROPS 25000

typedef struct {
	float x1[3];
	float x2[3]; // vertices
} rain_drop;

rain_drop rain_drops[MAX_RAIN_DROPS]; /*!< Defines the number of rain drops */

#ifdef DEBUG
GLfloat rain_color[4] = { 0.8f, 0.8f, 0.8f, 0.13f };
#else
static GLfloat rain_color[4] = { 0.8f, 0.8f, 0.8f, 0.13f }; // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
#endif

#define MAX_THUNDERS 5

typedef struct
{
	int in_use;
	int light_offset;
	int seconds_till_sound;
	int thunder_type;
	int time_since_started;
	int x;
	int y;
	int rot;
}thunder;

int seconds_till_rain_starts=-1;
int seconds_till_rain_stops=-1;
int is_raining=0;
int rain_sound=0;
int weather_light_offset=0;
int rain_light_offset=0;
int thunder_light_offset;
thunder thunders[MAX_THUNDERS];

Uint32 rain_control_counter=0;
Uint32 thunder_control_counter=0;
int num_rain_drops=0, max_rain_drops=0;

int rain_table_valid = 0;

#ifdef DEBUG
int rain_calls = 0;
int last_rain_calls = 0;
#endif

float rain_strength_bias = 1.0f;
GLfloat fogColor[4] = { 0.0f, 0.0f, 0.0f , 0.13f }; // use same alpha like in rain_color
float fogAlpha = 0.0f;

#ifdef SKY_FPV
float weather_rain_intensity = 0.0;
#endif // SKY_FPV

void init_weather() {
	clear_thunders();
	build_rain_table();
}

void start_weather(int seconds_till_start, float severity)
{
	seconds_till_rain_starts= seconds_till_start;
	seconds_till_rain_stops= -1;
	rain_strength_bias= severity;
}

void stop_weather(int seconds_till_stop, float severity)
{
	seconds_till_rain_stops= seconds_till_stop;
	seconds_till_rain_starts= -1;
	rain_strength_bias= severity;	// failsafe incase we never saw the start (logged in and already raining?
}

void clear_weather()
{
	seconds_till_rain_starts= -1;
	seconds_till_rain_stops= 0;
	weather_light_offset= 0;
	rain_light_offset= 0;
#ifdef SKY_FPV
	weather_rain_intensity = 0.0;
#endif // SKY_FPV
}

void get_weather_from_server(const Uint8* data){
	if(data[0] == weather_effect_wind){
		wind_direction = wind_direction_srv = (2 * data[1])%360;
		wind_speed = wind_speed_srv = data[2];
		return;
	} else if(data[0] == weather_effect_leaves){
		//EC_TAG
		return;
	} else if(data[0] != weather_effect_rain){
		return;	//old weather can only handle rain
	}
	if(is_raining){
		stop_weather(data[1], ((float)(data[2]))/100.0f);
	} else {
		start_weather(data[1], ((float)(data[2]))/100.0f);
	}
}

void render_weather()
{
	if(is_raining && num_rain_drops > 0) render_rain(num_rain_drops);
}

void build_rain_table()
{
	int i; 
	float x, y, z;
	actor *me;

	LOCK_ACTORS_LISTS();
	me = get_our_actor ();
	if (!me) {
		UNLOCK_ACTORS_LISTS();
		return;
	}
	x = me->x_pos; 
	y = me->y_pos; 
	z = me->z_pos; 
	UNLOCK_ACTORS_LISTS();

	for(i=0;i<MAX_RAIN_DROPS;i++)
		{
			rain_drops[i].x1[0] = x +  20.0f * ((float)rand() / RAND_MAX) - 10.0f;
			rain_drops[i].x1[1] = y +  20.0f * ((float)rand() / RAND_MAX) - 10.0f;
			rain_drops[i].x1[2] = z +  10.0f * ((float)rand() / RAND_MAX) + 10.0f;
			rain_drops[i].x2[0] = rain_drops[i].x1[0];
			rain_drops[i].x2[1] = rain_drops[i].x1[1];
			rain_drops[i].x2[2] = rain_drops[i].x1[2] - 0.08f;
		}
}

void update_rain()
{
	int i;
	float x, y, z;
	actor *me;

	LOCK_ACTORS_LISTS();
	me = get_our_actor ();
	if (!me) {
		UNLOCK_ACTORS_LISTS();
		return;
	}
	x = me->x_pos; 
	y = me->y_pos; 
	z = me->z_pos; 
	UNLOCK_ACTORS_LISTS();

	for(i=0;i<num_rain_drops;i++)
		{
			if(rain_drops[i].x1[2] < -1.0f)
				{
					if ((seconds_till_rain_stops < 0) || (seconds_till_rain_stops > 62) || (seconds_till_rain_stops > 62 + ((30*i)/MAX_RAIN_DROPS))) {
						rain_drops[i].x1[0] = x + 20.0f * ((float)rand() / RAND_MAX) - 10.0f;
						rain_drops[i].x1[1] = y + 20.0f * ((float)rand() / RAND_MAX) - 10.0f;
						rain_drops[i].x1[2] = z + 10.0f * ((float)rand() / RAND_MAX) +  2.0f;
						rain_drops[i].x2[0] = rain_drops[i].x1[0];
						rain_drops[i].x2[1] = rain_drops[i].x1[1];
						rain_drops[i].x2[2] = rain_drops[i].x1[2] - 0.08f;

#ifdef DEBUG
						rain_calls++;
#endif
					}
				} else {
					rain_drops[i].x1[2] -= 0.40f;
					rain_drops[i].x2[2] -= 0.40f;
				}
		}
}

void rain_control()
{
	float rain_light_bias = 0.8 + 0.2*rain_strength_bias;
	float rainParam;

#ifdef DEBUG
	last_rain_calls = rain_calls;
	rain_calls -= last_rain_calls;
#endif

	if(rain_control_counter+1000<cur_time)
		{
			rain_control_counter=cur_time;
		}
	else return;

	/* disable rain on snow maps for now */
	if (map_flags & MF_SNOW) {
		is_raining = 0;
#ifdef NEW_SOUND
		if (rain_sound) {
			stop_sound(rain_sound);
			rain_sound = 0;
		}
#endif // NEW_SOUND
		seconds_till_rain_starts = -1;
		seconds_till_rain_stops = -1;
		rain_light_offset=0;
#ifdef SKY_FPV
		weather_rain_intensity = 0.0;
#endif // SKY_FPV
		return;
	}

	//prepare to stop the rain?
	if(seconds_till_rain_stops!=-1) {
		rain_table_valid = 0;
		// gracefully stop rain
		if (seconds_till_rain_stops > 60) {
#ifdef SKY_FPV
			weather_rain_intensity = 1.0;
#endif // SKY_FPV
			is_raining=1;
			rainParam = rain_strength_bias*(min2i(60,seconds_till_rain_stops) - 60)/30.0f;
			num_rain_drops = rainParam*MAX_RAIN_DROPS;
#ifdef NEW_SOUND
			if (!rain_sound || find_sound_source_from_cookie(rain_sound) < 0)
				rain_sound = add_server_sound(snd_rain, 0, 0, rainParam);
			if (rain_sound) sound_source_set_gain(rain_sound, rainParam);
#endif	//NEW_SOUND
			seconds_till_rain_stops--;
		} else if(seconds_till_rain_stops) {
#ifdef SKY_FPV
			weather_rain_intensity = seconds_till_rain_stops/60.0;
#endif // SKY_FPV
			if (is_raining) is_raining = 0;
#ifdef NEW_SOUND
			if(rain_sound) {
				stop_sound(rain_sound);
				rain_sound=0;
			}
#endif	//NEW_SOUND
			num_rain_drops = 0;
			seconds_till_rain_stops--;
		} else {
#ifdef SKY_FPV
			weather_rain_intensity = 0.0;
#endif // SKY_FPV
			if (is_raining) is_raining = 0;
#ifdef NEW_SOUND
			if(rain_sound) {
				stop_sound(rain_sound);
				rain_sound=0;
			}
#endif	//NEW_SOUND
			num_rain_drops = 0;
			seconds_till_rain_stops = -1;
			rain_light_offset=0;
			return;
		}

		//make it lighter each 3 seconds
		rain_light_offset=rain_light_bias*seconds_till_rain_stops/3;
		if(rain_light_offset<0)rain_light_offset=0;
	//prepare to start the rain?
	} else if(seconds_till_rain_starts!=-1) {
		if (!rain_table_valid) {
			build_rain_table();
			rain_table_valid = 1;
		}
		// gracefully start rain
		if (seconds_till_rain_starts >= 60) {
#ifdef SKY_FPV
			weather_rain_intensity = 0.0;
#endif // SKY_FPV
			num_rain_drops = 0;
#ifdef NEW_SOUND
			if (rain_sound) sound_source_set_gain(rain_sound, 0.0f);
#endif	//NEW_SOUND
			seconds_till_rain_starts--;
		} else if(seconds_till_rain_starts) {
#ifdef SKY_FPV
			weather_rain_intensity = (60-seconds_till_rain_starts)/60.0;
#endif // SKY_FPV
			rainParam = rain_strength_bias*(60-seconds_till_rain_starts)/60.0f;
			if(!is_raining) {
				is_raining=1;
#ifdef NEW_SOUND
				if (!rain_sound || find_sound_source_from_cookie(rain_sound) < 0)
					rain_sound = add_server_sound(snd_rain, 0, 0, rainParam);
#endif	//NEW_SOUND
			}
			num_rain_drops = rainParam*MAX_RAIN_DROPS;
#ifdef NEW_SOUND
			if (rain_sound) sound_source_set_gain(rain_sound, rainParam);
#endif	//NEW_SOUND
			seconds_till_rain_starts--;
		} else {
#ifdef SKY_FPV
			weather_rain_intensity = 1.0;
#endif // SKY_FPV
			if(!is_raining) {
				is_raining=1;
#ifdef NEW_SOUND
				if (!rain_sound || find_sound_source_from_cookie(rain_sound) < 0)
					rain_sound = add_server_sound(snd_rain, 0, 0, rain_strength_bias);
#endif	//NEW_SOUND
			}
			num_rain_drops = rain_strength_bias*MAX_RAIN_DROPS;
			seconds_till_rain_starts=-1;
			rain_table_valid = 0;
			rain_light_offset = rain_light_bias*60;
			return;
		}
		//make it darker each 3 seconds
		rain_light_offset=rain_light_bias*(60-seconds_till_rain_starts/3);
		if(rain_light_offset<0)rain_light_offset=0;
	} else {
		// neither ==> keep status
		rain_table_valid = 0;
		if (is_raining) {
			num_rain_drops = rain_strength_bias*MAX_RAIN_DROPS;
			if (rain_sound) {
#ifdef NEW_SOUND
				sound_source_set_gain(rain_sound, rain_strength_bias);
			} else {
				rain_sound = add_server_sound(snd_rain, 0, 0, rain_strength_bias);
#endif	//NEW_SOUND
			}
		} else {
			num_rain_drops = 0;
#ifdef NEW_SOUND
			if (rain_sound) {
				stop_sound(rain_sound);
				rain_sound = 0;
			}
#endif	//NEW_SOUND
		}
	}
}

#ifdef NEW_SOUND
float weather_adjust_gain(float in_gain, int in_cookie)
{
	if (is_raining && in_cookie != rain_sound)
	{
		// Dim down all the sounds, except the rain
		in_gain *= 1.0f - (rain_strength_bias * 0.75f);
	}

	return in_gain;
}
#endif // NEW_SOUND

void thunder_control()
{
	int i;
#ifdef NEW_SOUND
	int sounds[5]={snd_thndr_1,snd_thndr_2,snd_thndr_3,snd_thndr_4,snd_thndr_5};
#endif // NEW_SOUND
	if(map_flags & MF_SNOW) return;

	if(thunder_control_counter+100<cur_time)
		{
			thunder_control_counter=cur_time;
		}
	else return;

	for(i=0;i<MAX_THUNDERS;i++)
		{
			if(thunders[i].in_use)
				{
					if(thunders[i].time_since_started<5)thunders[i].light_offset=thunders[i].time_since_started;
					else if(thunders[i].time_since_started>5 && thunders[i].time_since_started<10)thunders[i].light_offset=5;
					else if(thunders[i].time_since_started>10 &&thunders[i].time_since_started<15)thunders[i].light_offset=15-thunders[i].time_since_started;
					//should we start the sound?
					if(thunders[i].seconds_till_sound!=-1 && thunders[i].seconds_till_sound>=0)
					{
						thunders[i].seconds_till_sound--;
						if(!thunders[i].seconds_till_sound)
						{
							if(thunders[i].thunder_type >=0 && thunders[i].thunder_type <5)
							{
#ifdef NEW_SOUND
								add_server_sound(sounds[thunders[i].thunder_type], 0, 0, 1.0f);
#endif	//NEW_SOUND
							}
							thunders[i].seconds_till_sound=-1;//we are done with this sound
						}
					}
					thunders[i].time_since_started++;
					//is this thunder expired?
					if(thunders[i].time_since_started>20 && thunders[i].seconds_till_sound==-1)
						thunders[i].in_use=0;
				}
		}

}

void add_thunder(int type,int sound_delay)
{
	int i;

	if(map_flags & MF_SNOW) return;

	for(i=0;i<MAX_THUNDERS;i++)
		{
			if(!thunders[i].in_use)
				{
					thunders[i].in_use=1;
					thunders[i].light_offset=0;
					thunders[i].seconds_till_sound=sound_delay;
					thunders[i].thunder_type=type;
					thunders[i].time_since_started=0;
					thunders[i].x=rand()%500;
					thunders[i].y=rand()%500;
					thunders[i].rot=rand()%360;
					return;
				}
		}

}

void get_weather_light_level()
{
	int i;

	thunder_light_offset=0;

	for(i=0;i<MAX_THUNDERS;i++)
		{
			if(thunders[i].in_use)
				thunder_light_offset+=thunders[i].light_offset;
		}

	//thunders light is positive, while rain light is negative
	weather_light_offset=rain_light_offset;
}

void clear_thunders()
{
	int i;

	for(i=0;i<MAX_THUNDERS;i++)
		{
			thunders[i].in_use=0;
		}
}

float get_rain_strength()
{
	if (!(map_flags & MF_SNOW)) {
		return num_rain_drops / (float)MAX_RAIN_DROPS;
	}
	else {
		return rain_strength_bias;
	}
}

void render_fog() {
	int i;
	GLfloat fogDensity;
#ifndef SKY_FPV
	static GLfloat minDensity = 0.01f, maxDensity = 0.04f;
	float tmpf;
	GLfloat rainStrength, rainAlpha, diffuseBias;

	rainStrength = get_rain_strength();
	rainAlpha = 0.2f*rain_color[3]*rainStrength;

#ifdef NEW_LIGHTING
	if (use_new_lighting)
		diffuseBias = 0.2f;
	else
#endif
		// in dungeons and at night we use smaller light sources ==> less diffuse light
		diffuseBias = (dungeon || !is_day)? 0.2f : 0.5f;

	for (i=0; i<3; i++) {
		// blend ambient and diffuse light to build a base fog color
		GLfloat tmp = 0.5f*ambient_light[i] + diffuseBias*diffuse_light[i];
		if (is_raining) {
			// blend base color with rain color
			fogColor[i] = (1.0f - rainAlpha)*tmp + rainAlpha*rain_color[i];
		} else {
			fogColor[i] = tmp;
		}
	}

	// interpolate fog distance between min and max depending on rain
	// TODO: Is linear interpolation the best idea here?
	fogDensity = (is_raining)?  (rainStrength*maxDensity + (1.0f - rainStrength)*minDensity) : minDensity;

	tmpf = exp(-10.0f*fogDensity);
	fogAlpha = 1.0f - tmpf*tmpf;

#else // SKY_FPV

	if (dungeon) {
		fogDensity = 0.01;
		for (i = 3; i--; )
			fogColor[i] = skybox_fog[0][i];
		fogColor[3] = 1.0;
	}
	else {
		memcpy(fogColor, skybox_fog_color, 4*sizeof(float));
		fogDensity = skybox_fog_density;
	}
#endif // SKY_FPV
	
	glEnable(GL_FOG);
	glFogi(GL_FOG_MODE, GL_EXP2);
	glFogf(GL_FOG_DENSITY, fogDensity);
	glFogfv(GL_FOG_COLOR, fogColor);
#ifdef OPENGL_TRACE
CHECK_GL_ERRORS();
#endif //OPENGL_TRACE
}

void render_rain(int num_rain_drops)
{
	//TODO: it'd be really nifty if the points close to the camera were rendered as a particle or similar, while the rest stay points
	int idx, max;

	if(num_rain_drops <= 0) return;

	glPushAttrib(GL_LIGHTING_BIT);
	glDisable(GL_LIGHTING);
	
	glDisable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4fv(rain_color);
	glEnableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_NORMAL_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);
	
	glVertexPointer(3,GL_FLOAT,0,rain_drops);

	// ATI hack ... sometimes problems with large arrays
	idx = 0;
	max = num_rain_drops;
	while(idx < max) {
	    int num;
		   
		num= max-idx;
		if(num > 3000){
			num= 3000;
		}
	    glDrawArrays(GL_LINES, idx, num);
	    idx+= num;
	}

	glDisable(GL_BLEND);
	glEnable(GL_TEXTURE_2D);
	glPopAttrib();
#ifdef OPENGL_TRACE
	CHECK_GL_ERRORS();
#endif // OPENGL_TRACE
}

#endif // NEW_WEATHER

