// Main routine
void RenderVisTreeClass::build_render_tree()
{
	assert(view);	// Idiot-proofing

	/* initialize the queue where we remember polygons we need to fire at */
	initialize_polygon_queue();

	/* initialize our node list to contain the root, etc. */
	initialize_render_tree();
	
	/* reset clipping buffers */
	initialize_clip_data();
	
	// LP change:
	// Adjusted for long-vector handling
	// Using start index of list of nodes: 0
	long_vector2d view_edge;
	
	short_to_long_2d( view->left_edge, view_edge );
	cast_render_ray( &view_edge, NONE, &Nodes.front(), _counterclockwise_bias );
	
	short_to_long_2d( view->right_edge, view_edge );
	cast_render_ray( &view_edge, NONE, &Nodes.front(), _clockwise_bias );
	
	/* 
		pull polygons off the queue, fire at all their new endpoints, building the tree as we go 
	*/
	while (polygon_queue_size)
	{
		auto polygon_index 	= PolygonQueue[ --polygon_queue_size ];
		polygon_data *polygon 	= get_polygon_data(polygon_index);
		
		assert( !POLYGON_IS_DETACHED(polygon) );
		
		const ix vertex_count = polygon->vertex_count;
		for( ix vertex_index = 0; vertex_index < vertex_count; ++vertex_index )
		{
			const auto endpoint_index	= polygon->endpoint_indexes[vertex_index];
			endpoint_data *endpoint		= get_endpoint_data(endpoint_index);
			
			if (TEST_RENDER_FLAG(endpoint_index, _endpoint_has_been_visited))
				continue;
			// LP change: move toward correct handling of long distances
			long_vector2d _vector;
			
			/* transform all visited endpoints */
			endpoint->transformed = endpoint->vertex;
			transform_overflow_point2d( &endpoint->transformed, 
						(world_point2d *) &view->origin, 
						view->yaw, 
						&endpoint->flags );
						
			/* calculate an outbound vector to this endpoint */
			// LP: changed to do long distance correctly.	
			_vector.i 	= int32( endpoint->vertex.x ) - int32( view->origin.x );
			_vector.j	= int32( endpoint->vertex.y ) - int32( view->origin.y );
			
			// LP change: compose a true transformed point to replace endpoint->transformed,
			// and use it in the upcoming code
			long_vector2d transformed_endpoint;
			overflow_short_to_long_2d( 	endpoint->transformed, 
							endpoint->flags, 
							transformed_endpoint );
			if (transformed_endpoint.i > 0)
			{
				const int32 x = view->half_screen_width + 
				( transformed_endpoint.j * view->world_to_screen_x ) / transformed_endpoint.i;
				
				endpoint_x_coordinates[ endpoint_index ] = 
					static_cast< int16 >( PIN(x, INT16_MIN, INT16_MAX) );
					
				SET_RENDER_FLAG(endpoint_index, _endpoint_has_been_transformed);
			}
			
			/* 
				do two cross products to determine whether this endpoint is in our view cone or not
				(we don't have to cast at points outside the cone) 
			*/
			const auto ri = view->right_edge.i;
			const auto rj = view->right_edge.j;
			const int32 crossprod_right = ( ri * _vector.j ) - ( rj * _vector.i );
			
			const auto li = view->left_edge.i;
			const auto lj = view->left_edge.j;
			const int32 crossprod_left = ( li * _vector.j ) - ( lj * _vector.i );
			
			if( crossprod_right <= 0 && crossprod_left >= 0 )
			{
				//it's in our view, cast at it
				int16 endpoint_;
				
				if( ENDPOINT_IS_TRANSPARENT(endpoint) )
					endpoint_ = NONE;
				else
					endpoint_ = endpoint_index;
					
				cast_render_ray(&_vector, endpoint_, &Nodes.front(), _no_bias);
			}
			SET_RENDER_FLAG(endpoint_index, _endpoint_has_been_visited);
		
		}
	}
}
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);
		}
	}
}