www.pudn.com > map_editor.rar > shadows.c


#include "global.h"
#include 

GLuint depth_map_id = 0;
int is_day = 1;

void SetShadowMatrix()
{
	float dot;
	// dot product of plane and light position
	dot = fPlane[0] * fLightPos[0]
		+ fPlane[1] * fLightPos[1]
		+ fPlane[2] * fLightPos[2]
		+ fPlane[3] * fLightPos[3];

	// first column
	fDestMat[0] = dot - fLightPos[0] * fPlane[0];
	fDestMat[4] = 0.0f - fLightPos[0] * fPlane[1];
	fDestMat[8] = 0.0f - fLightPos[0] * fPlane[2];
	fDestMat[12] = 0.0f - fLightPos[0] * fPlane[3];

	// second column
	fDestMat[1] = 0.0f - fLightPos[1] * fPlane[0];
	fDestMat[5] = dot - fLightPos[1] * fPlane[1];
	fDestMat[9] = 0.0f - fLightPos[1] * fPlane[2];
	fDestMat[13] = 0.0f - fLightPos[1] * fPlane[3];

	// third column
	fDestMat[2] = 0.0f - fLightPos[2] * fPlane[0];
	fDestMat[6] = 0.0f - fLightPos[2] * fPlane[1];
	fDestMat[10] = dot - fLightPos[2] * fPlane[2];
	fDestMat[14] = 0.0f - fLightPos[2] * fPlane[3];

	// fourth column
	fDestMat[3] = 0.0f - fLightPos[3] * fPlane[0];
	fDestMat[7] = 0.0f - fLightPos[3] * fPlane[1];
	fDestMat[11] = 0.0f - fLightPos[3] * fPlane[2];
	fDestMat[15] = dot - fLightPos[3] * fPlane[3];
}

#ifdef NEW_E3D_FORMAT
#include "../elc/e3d_object.h"

void draw_3d_object_shadow(object3d * object_id)
{
	int texture_id, i;
	float x_pos,y_pos,z_pos;
	float x_rot,y_rot,z_rot;
	void* data_ptr;
	int vertex_size;

	//also, update the last time this object was used
	object_id->last_acessed_time=cur_time;

	if(object_id->blended)
	{
		glEnable(GL_BLEND);
		glBlendFunc(GL_ONE,GL_ONE);
	}

	if(object_id->self_lit && (night_shadows_on || dungeon))
	{
		glDisable(GL_LIGHTING);
		//set_material(object_id->r,object_id->g,object_id->b);
		glColor3f(object_id->r,object_id->g,object_id->b);
	}

	CHECK_GL_ERRORS();

	glPushMatrix();//we don't want to affect the rest of the scene
	x_pos = object_id->x_pos;
	y_pos = object_id->y_pos;
	z_pos = object_id->z_pos;
	glTranslatef (x_pos, y_pos, z_pos);

	x_rot = object_id->x_rot;
	y_rot = object_id->y_rot;
	z_rot = object_id->z_rot;
	glRotatef(z_rot, 0.0f, 0.0f, 1.0f);
	glRotatef(x_rot, 1.0f, 0.0f, 0.0f);
	glRotatef(y_rot, 0.0f, 1.0f, 0.0f);

	CHECK_GL_ERRORS();

	if (have_vertex_buffers)
	{
		ELglBindBufferARB(GL_ARRAY_BUFFER_ARB, object_id->e3d_data->vertex_vbo);
		data_ptr = 0;
	}
	else
	{
		data_ptr = object_id->e3d_data->vertex_data;
	}
	vertex_size = get_vertex_size(object_id->e3d_data->vertex_options);
	glTexCoordPointer(TEXTURE_FLOAT_COUNT, GL_FLOAT, vertex_size,
		data_ptr + get_texture_offset(object_id->e3d_data->vertex_options));
	glVertexPointer(VERTEX_FLOAT_COUNT, GL_FLOAT, vertex_size,
		data_ptr + get_vertex_offset(object_id->e3d_data->vertex_options));
	if (have_vertex_buffers)
	{
		ELglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object_id->e3d_data->indicies_vbo);
	}
		
	CHECK_GL_ERRORS();

	for (i = 0; i < object_id->e3d_data->material_no; i++)
	{
		if (material_is_transparent(object_id->e3d_data->materials[i].options))
		{
			//enable alpha filtering, so we have some alpha key
			glEnable(GL_ALPHA_TEST);
			if (is_ground(object_id->e3d_data->vertex_options)) glAlphaFunc(GL_GREATER, 0.23f);
			else glAlphaFunc(GL_GREATER, 0.06f);
			glDisable(GL_CULL_FACE);
			glEnable(GL_TEXTURE_2D);
			texture_id = get_texture_id(object_id->e3d_data->materials[i].diffuse_map);
			if (last_texture != texture_id)
			{
				glBindTexture(GL_TEXTURE_2D, texture_id);
				last_texture = texture_id;
			}
		}
		else
		{
			glDisable(GL_ALPHA_TEST);
			glEnable(GL_CULL_FACE);
			glDisable(GL_TEXTURE_2D);
		}

		ELglDrawRangeElementsEXT(GL_TRIANGLES,
			object_id->e3d_data->materials[i].triangles_indicies_min,
			object_id->e3d_data->materials[i].triangles_indicies_max,
			object_id->e3d_data->materials[i].triangles_indicies_count,
			object_id->e3d_data->index_type,
			object_id->e3d_data->materials[i].triangles_indicies_index);
	}

	glPopMatrix();//restore the scene
	CHECK_GL_ERRORS();

	if (material_is_transparent(object_id->e3d_data->materials[object_id->e3d_data->material_no-1].options))
	{
		glDisable(GL_ALPHA_TEST);
		glEnable(GL_CULL_FACE);
	}
	else
	{
		glEnable(GL_TEXTURE_2D);
	}
	CHECK_GL_ERRORS();
}

#else	//NEW_E3D_FORMAT

void draw_3d_object_shadow(object3d * object_id)
{
	float x_pos,y_pos,z_pos;
	float x_rot,y_rot,z_rot;

	int materials_no,texture_id;
	int i;
	char is_transparent;

	e3d_array_vertex *array_vertex;
	e3d_array_uv_main *array_uv_main;
	e3d_array_order *array_order;

    if(object_id->blended)return;//blended objects can't have shadows
    if(object_id->self_lit)return;//light sources can't have shadows
    if(!(object_id->e3d_data->min_z-object_id->e3d_data->max_z))return;//we have a flat object

	array_vertex=object_id->e3d_data->array_vertex;
	array_uv_main=object_id->e3d_data->array_uv_main;
	array_order=object_id->e3d_data->array_order;

	is_transparent=object_id->e3d_data->is_transparent;
	materials_no=object_id->e3d_data->materials_no;

	if(is_transparent)
		{
			glEnable(GL_ALPHA_TEST);//enable alpha filtering, so we have some alpha key
			glAlphaFunc(GL_GREATER,0.05f);
		}
	else glDisable(GL_TEXTURE_2D);//we don't need textures for non transparent objects

	glPushMatrix();//we don't want to affect the rest of the scene
	glMultMatrixf(fDestMat);
	x_pos=object_id->x_pos;
	y_pos=object_id->y_pos;
	z_pos=object_id->z_pos;
	glTranslatef (x_pos, y_pos, z_pos);

	x_rot=object_id->x_rot;
	y_rot=object_id->y_rot;
	z_rot=object_id->z_rot;
	glRotatef(z_rot, 0.0f, 0.0f, 1.0f);
	glRotatef(x_rot, 1.0f, 0.0f, 0.0f);
	glRotatef(y_rot, 0.0f, 1.0f, 0.0f);

	glEnableClientState(GL_VERTEX_ARRAY);
	glVertexPointer(3,GL_FLOAT,0,array_vertex);
	if(is_transparent)
		{
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glTexCoordPointer(2,GL_FLOAT,0,array_uv_main);
		}

	for(i=0;iblended!=20)
				 {
#ifndef	NEW_E3D_FORMAT
				if(!objects_list[i]->e3d_data->is_ground && objects_list[i]->z_pos>-0.20f)
#else	//NEW_E3D_FORMAT
				if (!is_ground(objects_list[i]->e3d_data->vertex_options)
					&& objects_list[i]->z_pos>-0.20f)
#endif	//NEW_E3D_FORMAT
					{
						 int dist1;
						 int dist2;

						 dist1=x-(int)objects_list[i]->x_pos;
						 dist2=y-(int)objects_list[i]->y_pos;
						 if(dist1*dist1+dist2*dist2<=20*20)
							draw_3d_object_shadow(objects_list[i]);
					 }
                 }
		}
	glDisable(GL_CULL_FACE);
}

void display_night_shadows(int phase)
{
	int i,j;
	int x,y;
	int closest_light=-1;
	int next_closest_light=-1;
	float closest_light_dist=100.0f;
	float next_closest_light_dist=100.0f;

	x=(int)-camera_x;
	y=(int)-camera_y;
	glEnable(GL_CULL_FACE);
	for (i = 0; i < MAX_OBJ_3D; i++)
		{
			closest_light=-1;
			next_closest_light=-1;
			closest_light_dist=100.0f;
			next_closest_light_dist=100.0f;

			if(objects_list[i] && objects_list[i]->blended!=20)
				 {
#ifndef	NEW_E3D_FORMAT
				if(!objects_list[i]->e3d_data->is_ground && objects_list[i]->z_pos>-0.20f)
#else	//NEW_E3D_FORMAT
				if (!is_ground(objects_list[i]->e3d_data->vertex_options)
					&& objects_list[i]->z_pos>-0.20f)
#endif	//NEW_E3D_FORMAT
					{
					 float dist1;
					 float dist2;
					 float x_pos,y_pos;

					 x_pos=objects_list[i]->x_pos;
					 y_pos=objects_list[i]->y_pos;
					 dist1=x-(int)x_pos;
					 dist2=y-(int)y_pos;
					 if(dist1*dist1+dist2*dist2<=20*20)
						{
							//now, find the closest, or next closest light source, according to
							//the phase value
							for (j = 0; j < MAX_LIGHTS; j++)
							 {
							  if(lights_list[j])
							   {
								 float dist1;
								 float dist2;
								 float light_dist;

								 dist1=x_pos-lights_list[j]->pos_x;
								 dist2=y_pos-lights_list[j]->pos_y;
								 light_dist=sqrt(dist1*dist1+dist2*dist2);
								 if(light_dist<=8)
									{
										if(light_distpos_x;
									fLightPos[1]=lights_list[closest_light]->pos_y;
									fLightPos[2]=lights_list[closest_light]->pos_z;
									fLightPos[3]=1.0f;
									SetShadowMatrix();
									draw_3d_object_shadow(objects_list[i]);
								}
							if(phase==2)if(next_closest_light!=-1)
								{
									fLightPos[0]=lights_list[next_closest_light]->pos_x;
									fLightPos[1]=lights_list[next_closest_light]->pos_y;
									fLightPos[2]=lights_list[next_closest_light]->pos_z;
									fLightPos[3]=1.0f;
									SetShadowMatrix();
									draw_3d_object_shadow(objects_list[i]);
								}
						}//object in range
                 }//object nonground
			 }//object exist
		}//main for
	glDisable(GL_CULL_FACE);
}

void display_3d_ground_objects()
{
	int i;
	int x,y;

	x=(int)-camera_x;
	y=(int)-camera_y;
	glEnable(GL_CULL_FACE);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	if(have_multitexture && clouds_shadows)
		{
			//bind the detail texture
			glActiveTextureARB(GL_TEXTURE1_ARB);
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, texture_cache[ground_detail_text].texture_id);
			glActiveTextureARB(GL_TEXTURE0_ARB);
			glEnable(GL_TEXTURE_2D);

		}
	for (i = 0; i < MAX_OBJ_3D; i++)
		{
			if(objects_list[i] && objects_list[i]->blended!=20)
				 {
#ifndef	NEW_E3D_FORMAT
					 if(objects_list[i]->e3d_data->is_ground)
#else	//NEW_E3D_FORMAT
					if (!is_ground(objects_list[i]->e3d_data->vertex_options))
#endif	//NEW_E3D_FORMAT
						{
					 		int dist1;
					 		int dist2;

							dist1=x-(int)objects_list[i]->x_pos;
							dist2=y-(int)objects_list[i]->y_pos;
							if(dist1*dist1+dist2*dist2<=25*25)
								{
									/*
									float x_len;
									float y_len;
									float z_len;
									float radius;

									z_len=objects_list[i]->e3d_data->max_z-objects_list[i]->e3d_data->min_z;
									x_len=objects_list[i]->e3d_data->max_x-objects_list[i]->e3d_data->min_x;
									y_len=objects_list[i]->e3d_data->max_y-objects_list[i]->e3d_data->min_y;

									radius=x_len/2;
									if(radiusx_pos,objects_list[i]->y_pos,
													   objects_list[i]->z_pos,radius))
										*/
										draw_3d_object(objects_list[i]);
								}
						}
                 }
		}
	if(have_multitexture && clouds_shadows)
		{
			//disable the second texture unit
			glActiveTextureARB(GL_TEXTURE1_ARB);
			glDisable(GL_TEXTURE_2D);
			glActiveTextureARB(GL_TEXTURE0_ARB);
		}
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisable(GL_CULL_FACE);
}

void display_3d_non_ground_objects()
{
	int i;
	int x,y;

	x=(int)-camera_x;
	y=(int)-camera_y;
	glEnable(GL_CULL_FACE);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	if(have_multitexture && clouds_shadows)
		{
			//bind the detail texture
			glActiveTextureARB(GL_TEXTURE1_ARB);
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, texture_cache[ground_detail_text].texture_id);
			glActiveTextureARB(GL_TEXTURE0_ARB);
			glEnable(GL_TEXTURE_2D);

		}
	for (i = 0; i < MAX_OBJ_3D; i++)
		{
			if(objects_list[i] && objects_list[i]->blended!=20)
				 {
#ifndef	NEW_E3D_FORMAT
					 if(!objects_list[i]->e3d_data->is_ground)
#else	//NEW_E3D_FORMAT
					if (!is_ground(objects_list[i]->e3d_data->vertex_options))
#endif	//NEW_E3D_FORMAT
						{
							int dist1;
							int dist2;

							dist1=x-(int)objects_list[i]->x_pos;
							dist2=y-(int)objects_list[i]->y_pos;
							if(dist1*dist1+dist2*dist2<=25*25)
								{
									/*
									float x_len, y_len, z_len;
									float radius;

									z_len=objects_list[i]->e3d_data->max_z-objects_list[i]->e3d_data->min_z;
									x_len=objects_list[i]->e3d_data->max_x-objects_list[i]->e3d_data->min_x;
									y_len=objects_list[i]->e3d_data->max_y-objects_list[i]->e3d_data->min_y;

									radius=x_len/2;
									if(radius %f == %d\n", objects_list[i]->x_pos,objects_list[i]->y_pos, objects_list[i]->z_pos, radius,SphereInFrustum(objects_list[i]->x_pos,objects_list[i]->y_pos, objects_list[i]->z_pos,radius));
									//not in the middle of the air
									if(SphereInFrustum(objects_list[i]->x_pos,objects_list[i]->y_pos,
													   objects_list[i]->z_pos,radius))
										{*/
											draw_3d_object(objects_list[i]);
										//}
								}
						}
                 }
		}
	if(have_multitexture && clouds_shadows)
		{
			//disable the second texture unit
			glActiveTextureARB(GL_TEXTURE1_ARB);
			glDisable(GL_TEXTURE_2D);
			glActiveTextureARB(GL_TEXTURE0_ARB);
		}
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisable(GL_CULL_FACE);
}

void draw_sun_shadowed_scene()
{
	int	abs_light;

	display_3d_ground_objects();
	// turning off writing to the color buffer and depth buffer
	glDisable(GL_DEPTH_TEST);

	glDisable(GL_LIGHTING);
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

	glEnable(GL_STENCIL_TEST);
	// write a one to the stencil buffer everywhere we are about to draw
	glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
	// this is to always pass a one to the stencil buffer where we draw
	glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

	display_shadows();

	glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
	// don't modify the contents of the stencil buffer
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	//go to the 2d mode, and draw a black rectangle...
	Enter2DMode();
	glDisable(GL_TEXTURE_2D);

	//if(light_level<60)glColor4f(0.0f,0.0f,0.0f,0.73f+(float)light_level*0.008f);
	//if(light_level>60)glColor4f(0.0f,0.0f,0.0f,0.73f+(float)(119-light_level)*0.008f);
	abs_light=light_level;
	if(light_level>59)abs_light=119-light_level;
	//abs_light+=weather_light_offset;
	if(abs_light<0)abs_light=0;
	if(abs_light>59)abs_light=59;

	glColor4f(0.0f,0.0f,0.0f,0.73f+(float)abs_light*0.008f);
	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE,GL_SRC_ALPHA);
	glBegin(GL_QUADS);
	glVertex3i(0,window_height,0);
	glVertex3i(0,0,0);
	glVertex3i(window_width,0,0);
	glVertex3i(window_width,window_height,0);
	glEnd();
	glDisable(GL_BLEND);
	glEnable(GL_TEXTURE_2D);

	Leave2DMode();
	glEnable(GL_DEPTH_TEST);
	glColor4f(1.0f,1.0f,1.0f,1.0f);
	glEnable(GL_LIGHTING);
	glDisable(GL_STENCIL_TEST);

	display_3d_non_ground_objects();
}

void draw_night_shadowed_scene()
{
	display_3d_ground_objects();
	// turning off writing to the color buffer and depth buffer
	glDisable(GL_DEPTH_TEST);

	glDisable(GL_LIGHTING);
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

	glEnable(GL_STENCIL_TEST);
	// write a one to the stencil buffer everywhere we are about to draw
	glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
	// this is to always pass a one to the stencil buffer where we draw
	glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

	//display the first (closest light)
	display_night_shadows(1);
	//now, change the value of the stencil to 2, to have two distinct shadows
	glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
	glStencilOp(GL_INCR, GL_INCR, GL_INCR);
	//draw the next closest light
	display_night_shadows(2);

	glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
	//glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
	// don't modify the contents of the stencil buffer
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	//go to the 2d mode, and draw a black rectangle...
	Enter2DMode();
	glDisable(GL_TEXTURE_2D);
	//source 1
	glColor4f(0.0f,0.0f,0.0f,0.63f);
	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE,GL_SRC_ALPHA);
	glBegin(GL_QUADS);
	glVertex3i(0,window_height,0);
	glVertex3i(0,0,0);
	glVertex3i(window_width,0,0);
	glVertex3i(window_width,window_height,0);
	glEnd();

	//source 2
	glStencilFunc(GL_LEQUAL, 2, 0xFFFFFFFF);
	glBegin(GL_QUADS);
	glColor4f(0.0f,0.0f,0.0f,0.33f);
	glVertex3i(0,window_height,0);
	glVertex3i(0,0,0);
	glVertex3i(window_width,0,0);
	glVertex3i(window_width,window_height,0);
	glEnd();

	glDisable(GL_BLEND);
	glEnable(GL_TEXTURE_2D);

	Leave2DMode();
	glEnable(GL_DEPTH_TEST);
	glColor4f(1.0f,1.0f,1.0f,1.0f);
	glEnable(GL_LIGHTING);
	glDisable(GL_STENCIL_TEST);

	display_3d_non_ground_objects();
}