示例#1
0
文件: devices.c 项目: DrItanium/moo
void try_and_toggle_control_panel(
	short polygon_index,
	short line_index)
{
	struct polygon_data *polygon= get_polygon_data(polygon_index);
	struct line_data *line= get_line_data(line_index);
	short side_index= find_adjacent_side(polygon_index, line_index);
	
	if (side_index!=NONE)
	{
		struct side_data *side= get_side_data(side_index);

		if (SIDE_IS_CONTROL_PANEL(side))
		{
			if (switch_can_be_toggled(side_index, FALSE))
			{
				boolean make_sound, state= GET_CONTROL_PANEL_STATUS(side);
				struct control_panel_definition *definition= get_control_panel_definition(side->control_panel_type);
				
				switch (definition->panel_class)
				{
					case _panel_is_tag_switch:
						state= !state;
						make_sound= set_tagged_light_statuses(side->control_panel_permutation, state);
						if (try_and_change_tagged_platform_states(side->control_panel_permutation, state)) make_sound= TRUE;
						if (!side->control_panel_permutation) make_sound= TRUE;
						if (make_sound)
						{
							SET_CONTROL_PANEL_STATUS(side, state);
							set_control_panel_texture(side);
						}
						break;
					case _panel_is_light_switch:
						state= !state;
						make_sound= set_light_status(side->control_panel_permutation, state);
						break;
					case _panel_is_platform_switch:
						state= !state;
						make_sound= try_and_change_platform_state(get_polygon_data(side->control_panel_permutation)->permutation, state);
						break;
				}
				
				if (make_sound)
				{
					play_control_panel_sound(side_index, state ? _activating_sound : _deactivating_sound);
				}
			}
		}
	}
	
	return;
}
示例#2
0
static bool test_item_retrieval(short polygon_index1, world_point3d *location1, world_point3d *location2)
{
	bool valid_retrieval= true;
	auto polygon_index = polygon_index1;

	do
	{
		auto line_index= find_line_crossed_leaving_polygon(polygon_index, (world_point2d *) location1,
			(world_point2d *) location2);
		
		if (line_index!=NONE)
		{
			polygon_index= find_adjacent_polygon(polygon_index, line_index);
			if (LINE_IS_SOLID(get_line_data(line_index))) 
				valid_retrieval= false;
			if (polygon_index!=NONE)
			{
				polygon_data *polygon= get_polygon_data(polygon_index);
				
				if (polygon->type==_polygon_is_platform)
				{
					platform_data *platform= get_platform_data(polygon->permutation);
					
					if (PLATFORM_IS_MOVING(platform)) valid_retrieval= false;
				}
			}
		}
		else
		{
			polygon_index= NONE;
		}
	}
	while (polygon_index!=NONE && valid_retrieval);
	
	return valid_retrieval;
}
示例#3
0
文件: devices.c 项目: DrItanium/moo
static boolean line_side_has_control_panel(
	short line_index, 
	short polygon_index,
	short *side_index_with_panel)
{
	short             side_index = NONE;
	boolean           has_panel = FALSE;
	struct line_data  *line = get_line_data(line_index);
	struct side_data  *side = NULL;
	
	if (line->clockwise_polygon_owner==polygon_index)
	{
		side_index = line->clockwise_polygon_side_index;
		if (side_index != NONE)
		{
			side = get_side_data(side_index);
		}
	} 
	else
	{
		assert(line->counterclockwise_polygon_owner==polygon_index);
		side_index = line->counterclockwise_polygon_side_index;
		if (side_index != NONE)
		{
			side= get_side_data(side_index);
		}
	}

	if (side != NULL && SIDE_IS_CONTROL_PANEL(side))
	{
		*side_index_with_panel = side_index;
		has_panel = TRUE;
	}
	
	return has_panel;
}
示例#4
0
// LP change: make it better able to do long-distance views
uint16 RenderVisTreeClass::next_polygon_along_line(int16 * polygon_index,
	world_point2d *origin, /* not necessairly in polygon_index */
	long_vector2d *_vector, // world_vector2d *vector,
	int16 *clipping_endpoint_index, /* if non-NONE on entry this is the solid endpoint weÕre shooting for */
	int16 *clipping_line_index, /* NONE on exit if this polygon transition wasnÕt accross an elevation line */
	int16 bias)
{
	polygon_data *polygon	= get_polygon_data(*polygon_index);
	int16 next_polygon_index, crossed_line_index, crossed_side_index;
	bool passed_through_solid_vertex = false;
	uint16 clip_flags = 0;


	ADD_POLYGON_TO_AUTOMAP(*polygon_index);
	PUSH_POLYGON_INDEX(*polygon_index);

	int16 state = _looking_for_first_nonzero_vertex;
	int16 vertex_index = 0;
	int16 vertex_delta = 1; /* start searching clockwise from vertex zero */
	
	// LP change: added test for looping around:
	// will remember the first vertex examined when the state has changed
	auto initial_vertex_index = vertex_index;
	
	bool changed_state = true;
	
	do
	{
		// Jump out of loop?
		if (changed_state)
			changed_state = false;
		else if (vertex_index == initial_vertex_index)
		{
			// Attempt to idiot-proof it by returning nothing
			next_polygon_index = NONE;
			crossed_line_index = NONE;
			crossed_side_index = NONE;
			break;
		}
			
		auto endpoint_index = polygon->endpoint_indexes[vertex_index];
		world_point2d *vertex = &get_endpoint_data(endpoint_index)->vertex;
		// LP change to make it more long-distance-friendly
		
		//urghhhhhhhhhhh
		CROSSPROD_TYPE cross_product	= 
			CROSSPROD_TYPE(int32(vertex->x)-int32(origin->x))*_vector->j 
			- 
			CROSSPROD_TYPE(int32(vertex->y)-int32(origin->y))*_vector->i;
		
		if (cross_product < 0)
		{
		    switch (state)
		    {
			case _looking_for_first_nonzero_vertex:
			    /* search counterclockwise for transition (right to left) */
			    state = _looking_counterclockwise_for_left_vertex;
			    vertex_delta = -1;
			    // LP change: resetting loop test
			    initial_vertex_index = vertex_index;
			    changed_state = true;
			    break;

			case _looking_clockwise_for_right_vertex: /* found the transition we were looking for */
			{
			    ix i = WRAP_LOW(vertex_index, polygon->vertex_count-1);
			    next_polygon_index = polygon->adjacent_polygon_indexes[i];
			    crossed_line_index = polygon->line_indexes[i];
			    crossed_side_index = polygon->side_indexes[i];
			}
			case _looking_for_next_nonzero_vertex: /* next_polygon_index already set */
			    state = NONE;
			    break;
		    }
		} 
		else if (cross_product > 0)
		{
		    switch (state)
		    {
			case _looking_for_first_nonzero_vertex:
			    /* search clockwise for transition (left to right) */
			    state= _looking_clockwise_for_right_vertex;
			    // LP change: resetting loop test
			    initial_vertex_index = vertex_index;
			    changed_state = true;
			    break;

			case _looking_counterclockwise_for_left_vertex: /* found the transition we were looking for */
			    next_polygon_index = polygon->adjacent_polygon_indexes[vertex_index];
			    crossed_line_index = polygon->line_indexes[vertex_index];
			    crossed_side_index = polygon->side_indexes[vertex_index];
			case _looking_for_next_nonzero_vertex: /* next_polygon_index already set */
			    state = NONE;
			    break;
		    }
		} 
		else
		{
		    if (state!=_looking_for_first_nonzero_vertex)
		    {
			if (endpoint_index==*clipping_endpoint_index) 
				passed_through_solid_vertex = true;

			/* 
				if we think we know what's on the other side of this zero (these zeros)
				change the state: if we don't find what we're looking for then the polygon
				is entirely on one side of the line or the other (except for this vertex),
				in any case we need to call decide_where_vertex_leads() to find out what's
				on the other side of this vertex 
			*/
			switch (state)
			{
			    case _looking_clockwise_for_right_vertex:
			    case _looking_counterclockwise_for_left_vertex:
				next_polygon_index= *polygon_index;
				clip_flags|= decide_where_vertex_leads(&next_polygon_index, &crossed_line_index, &crossed_side_index,
					   vertex_index, origin, _vector, clip_flags, bias);
				state = _looking_for_next_nonzero_vertex;
				// LP change: resetting loop test
				initial_vertex_index = vertex_index;
				changed_state = true;
				break;
			}
		    }
		}
		/* adjust vertex_index (clockwise or counterclockwise, depending on vertex_delta) */
		vertex_index = vertex_delta < 0 ? WRAP_LOW(vertex_index, polygon->vertex_count - 1) :
			WRAP_HIGH(vertex_index, polygon->vertex_count - 1);
	}
	while (state!=NONE);


	/* 
		if we didn't pass through the solid vertex we were aiming for, set clipping_endpoint_index to NONE,
		we assume the line we passed through doesn't clip, and set clipping_line_index to NONE
		(this will be corrected in a few moments if we chose poorly) 
	*/
	if (!passed_through_solid_vertex) 
		*clipping_endpoint_index = NONE;
		
	*clipping_line_index = NONE;
	
	if (crossed_line_index==NONE)
	{
		*polygon_index = next_polygon_index;
		return clip_flags;
	}

	const line_data *restrict line = get_line_data(crossed_line_index);

	/* add the line we crossed to the automap */
	ADD_LINE_TO_AUTOMAP(crossed_line_index);

	/* if the line has a side facing this polygon, mark the side as visible */
	if (crossed_side_index!=NONE) 
		SET_RENDER_FLAG(crossed_side_index, _side_is_visible);

	/* if this line is transparent we need to check for a change in elevation for clipping,
		if itÕs not transparent then we canÕt pass through it */
	// LP change: added test for there being a polygon on the other side
	if (LINE_IS_TRANSPARENT(line) && next_polygon_index != NONE)
	{
		const polygon_data *restrict next_polygon = get_polygon_data(next_polygon_index);
		
		if (line->highest_adjacent_floor > next_polygon->floor_height ||
			line->highest_adjacent_floor > polygon->floor_height) 
				clip_flags |= _clip_down; /* next polygon floor is lower */
				
		if (line->lowest_adjacent_ceiling < next_polygon->ceiling_height ||
			line->lowest_adjacent_ceiling < polygon->ceiling_height) 
				clip_flags |= _clip_up; /* next polygon ceiling is higher */
				
		if ( clip_flags&(_clip_up|_clip_down) ) 
			*clipping_line_index = crossed_line_index;
	}
	else
void RenderVisTreeClass::calculate_line_clipping_information(
	short line_index,
	uint16 clip_flags)
{
	// LP addition: extend the line-clip list
	line_clip_data Dummy;
	Dummy.flags = 0;			// Fake initialization to shut up CW
	LineClips.push_back(Dummy);
	size_t Length = LineClips.size();
	assert(Length <= 32767);
	assert(Length >= 1);
	size_t LastIndex = Length-1;
	
	line_data *line= get_line_data(line_index);
	// LP change: relabeling p0 and p1 so as not to conflict with later use
	world_point2d p0_orig= get_endpoint_data(line->endpoint_indexes[0])->vertex;
	world_point2d p1_orig= get_endpoint_data(line->endpoint_indexes[1])->vertex;
	// LP addition: place for new line data
	line_clip_data *data= &LineClips[LastIndex];

	/* itÕs possible (in fact, likely) that this lineÕs endpoints have not been transformed yet,
		so we have to do it ourselves */
	// LP change: making the operation long-distance friendly
	uint16 p0_flags = 0, p1_flags = 0;
	transform_overflow_point2d(&p0_orig, (world_point2d *) &view->origin, view->yaw, &p0_flags);
	transform_overflow_point2d(&p1_orig, (world_point2d *) &view->origin, view->yaw, &p1_flags);
	
	// Defining long versions here and copying over
	long_point2d p0, p1;
	long_vector2d *pv0ptr = (long_vector2d*)(&p0), *pv1ptr = (long_vector2d*)(&p1);
	overflow_short_to_long_2d(p0_orig,p0_flags,*pv0ptr);
	overflow_short_to_long_2d(p1_orig,p1_flags,*pv1ptr);
	
	clip_flags&= _clip_up|_clip_down;	
	assert(clip_flags&(_clip_up|_clip_down));
	assert(!TEST_RENDER_FLAG(line_index, _line_has_clip_data));

	SET_RENDER_FLAG(line_index, _line_has_clip_data);
	line_clip_indexes[line_index]= static_cast<vector<size_t>::value_type>(LastIndex);
	
	data->flags= 0;

	if (p0.x>0 && p1.x>0)
	{
		// LP change:
		long_point2d *p;
		world_distance z;
		long transformed_z;
		long y, y0, y1;
		long x0= view->half_screen_width + (p0.y*view->world_to_screen_x)/p0.x;
		long x1= view->half_screen_width + (p1.y*view->world_to_screen_x)/p1.x;
	
		data->x0= (short)PIN(x0, 0, view->screen_width);
		data->x1= (short)PIN(x1, 0, view->screen_width);
		if (data->x1<data->x0) SWAP(data->x0, data->x1);
		if (data->x1>data->x0)
		{
			if (clip_flags&_clip_up)
			{
				/* precalculate z and transformed_z */
				z= line->lowest_adjacent_ceiling-view->origin.z;
				transformed_z= z*view->world_to_screen_y;
				
				/* calculate and clip y0 and y1 (screen y-coordinates of each side of the line) */
				y0= (p0.x>0) ? (view->half_screen_height - transformed_z/p0.x + view->dtanpitch) : 0;
				y1= (p1.x>0) ? (view->half_screen_height - transformed_z/p1.x + view->dtanpitch) : 0;
		
				/* pick the highest (closest to zero) and pin it to the screen */
				if (y0<y1) y= y0, p= &p0; else y= y1, p= &p1;
				y= PIN(y, 0, view->screen_height);
				
				/* if weÕre not useless (clipping up off the top of the screen) set up top-clip information) */
				if (y<=0)
				{
					clip_flags&= ~_clip_up;
				}
				else
				{
					data->top_vector.i= - p->x, data->top_vector.j= - z;
					data->top_y= y;
				}
			}
			
			if (clip_flags&_clip_down)
			{
				z= line->highest_adjacent_floor - view->origin.z;
				transformed_z= z*view->world_to_screen_y;
				
				/* calculate and clip y0 and y1 (screen y-coordinates of each side of the line) */
				y0= (p0.x>0) ? (view->half_screen_height - transformed_z/p0.x + view->dtanpitch) : view->screen_height;
				y1= (p1.x>0) ? (view->half_screen_height - transformed_z/p1.x + view->dtanpitch) : view->screen_height;
				
				/* pick the highest (closest to zero screen_height) and pin it to the screen */
				if (y0>y1) y= y0, p= &p0; else y= y1, p= &p1;
				y= PIN(y, 0, view->screen_height);
				
				/* if weÕre not useless (clipping up off the bottom of the screen) set up top-clip information) */
				if (y>=view->screen_height)
				{
					clip_flags&= ~_clip_down;
				}
				else
				{
					data->bottom_vector.i= p->x,  data->bottom_vector.j= z;
					data->bottom_y= y;
				}
			}
	
			data->flags= clip_flags;
//			dprintf("line #%d clips %x @ %p", line_index, clip_flags, data);
		}
	}
}
// LP change: make it better able to do long-distance views
uint16 RenderVisTreeClass::decide_where_vertex_leads(
	short *polygon_index,
	short *line_index,
	short *side_index,
	short endpoint_index_in_polygon_list,
	world_point2d *origin,
	long_vector2d *_vector, // world_vector2d *vector,
	uint16 clip_flags,
	short bias)
{
	polygon_data *polygon= get_polygon_data(*polygon_index);
	short endpoint_index= polygon->endpoint_indexes[endpoint_index_in_polygon_list];
	short index;
	
	switch (bias)
	{
		case _no_bias:
//			dprintf("splitting at endpoint #%d", endpoint_index);
			clip_flags|= _split_render_ray;
			*polygon_index= *line_index= *side_index= NONE;
			index= NONE;
			break;
		
		case _clockwise_bias:
			index= endpoint_index_in_polygon_list;
			break;
		
		case _counterclockwise_bias:
			index= WRAP_LOW(endpoint_index_in_polygon_list, polygon->vertex_count-1);
			break;
		
		default:
			// LP change:
			assert(false);
			// halt();
	}
	
	if (index!=NONE)
	{
		line_data *line;
		world_point2d *vertex;
		CROSSPROD_TYPE cross_product;

		*line_index= polygon->line_indexes[index];
		*side_index= polygon->side_indexes[index];
		*polygon_index= polygon->adjacent_polygon_indexes[index];
		
		line= get_line_data(*line_index);
		if (*polygon_index!=NONE && LINE_IS_TRANSPARENT(line))
		{
			polygon= get_polygon_data(*polygon_index);
			
			/* locate our endpoint in this polygon */
			for (index=0;
					index<polygon->vertex_count && polygon->endpoint_indexes[index]!=endpoint_index;
					++index)
				;
			vassert(index!=polygon->vertex_count, csprintf(temporary, "endpoint #%d not in polygon #%d", endpoint_index, *polygon_index));
	
			switch (bias)
			{
				case _clockwise_bias: index= WRAP_HIGH(index, polygon->vertex_count-1); break;
				case _counterclockwise_bias: index= WRAP_LOW(index, polygon->vertex_count-1); break;
				default:
					assert(false);
					break;
			}
			
			vertex= &get_endpoint_data(polygon->endpoint_indexes[index])->vertex;
			// LP change: made more long-distance-friendly
			cross_product= CROSSPROD_TYPE(long(vertex->x)-long(origin->x))*_vector->j - CROSSPROD_TYPE(long(vertex->y)-long(origin->y))*_vector->i;
			
			if ((bias==_clockwise_bias&&cross_product>=0) || (bias==_counterclockwise_bias&&cross_product<=0))
			{
				/* weÕre leaving this endpoint, set clip flag in case itÕs solid */
				clip_flags|= (bias==_clockwise_bias) ? _clip_left : _clip_right;
			}
		}

//		dprintf("left endpoint #%d via line #%d to polygon #%d (bias==#%d)", endpoint_index, *line_index, *polygon_index, bias);
	}

	return clip_flags;
}
示例#7
0
文件: devices.c 项目: DrItanium/moo
static short find_action_key_target(
	short player_index,
	world_distance range,
	short *target_type)
{
	struct player_data *player= get_player_data(player_index);
	short current_polygon= player->camera_polygon_index;
	world_point2d destination;
	boolean done= FALSE;
	short itemhit, line_index;
	struct polygon_data *polygon;

	/* Should we use this one, the physics one, or the object one? */
	ray_to_line_segment((world_point2d *) &player->location, &destination, player->facing, range);

//	dprintf("#%d(#%d,#%d) --> (#%d,#%d) (#%d along #%d)", current_polygon, player->location.x, player->location.y, destination.x, destination.y, range, player->facing);

	itemhit= NONE;
	while (!done)
	{
		line_index= find_line_crossed_leaving_polygon(current_polygon, (world_point2d *) &player->location, &destination);
			
		if (line_index==NONE)
		{
			done= TRUE;
		} 
		else 
		{
			struct line_data *line;
			short original_polygon;

			line= get_line_data(line_index);
			original_polygon= current_polygon;
			current_polygon= find_adjacent_polygon(current_polygon, line_index);
			
//			dprintf("leaving polygon #%d through line #%d to polygon #%d", original_polygon, line_index, current_polygon);
			
			if (current_polygon!=NONE)
			{
				polygon= get_polygon_data(current_polygon);

				/* We hit a platform */				
				if (polygon->type==_polygon_is_platform && line_is_within_range(player->monster_index, line_index, MAXIMUM_PLATFORM_ACTIVATION_RANGE) &&
					platform_is_legal_player_target(polygon->permutation))
				{
//					dprintf("found platform #%d in %p", polygon->permutation, polygon);
					itemhit= polygon->permutation;
					*target_type= _target_is_platform;
					done= TRUE;
				} 
			} 
			else 
			{
				done= TRUE;
			}

			/* Slammed a wall */
			if (line_is_within_range(player->monster_index, line_index, MAXIMUM_CONTROL_ACTIVATION_RANGE))
			{
				if (line_side_has_control_panel(line_index, original_polygon, &itemhit))
				{
					if (switch_can_be_toggled(itemhit, TRUE))
					{
						*target_type= _target_is_control_panel;
						done= TRUE;
					}
					else
					{
						itemhit= NONE;
					}
				}
			}
		}
	}
	
	return itemhit;
}