// 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); } } }