// Returns NONE of it does not have valid clip info short RenderVisTreeClass::calculate_endpoint_clipping_information( short endpoint_index, uint16 clip_flags) { // If this endpoint was not transformed, then don't do anything with it, // and indicate that it's not a valid endpoint if (!TEST_RENDER_FLAG(endpoint_index, _endpoint_has_been_transformed)) { return NONE; } // LP addition: extend the endpoint-clip list endpoint_clip_data Dummy; Dummy.flags = 0; // Fake initialization to shut up CW EndpointClips.push_back(Dummy); size_t Length = EndpointClips.size(); assert(Length <= 32767); assert(Length >= 1); size_t LastIndex = Length-1; endpoint_data *endpoint= get_endpoint_data(endpoint_index); endpoint_clip_data *data= &EndpointClips[LastIndex]; int32 x; assert((clip_flags&(_clip_left|_clip_right))); /* must have a clip flag */ assert((clip_flags&(_clip_left|_clip_right))!=(_clip_left|_clip_right)); /* but canÕt have both */ assert(!TEST_RENDER_FLAG(endpoint_index, _endpoint_has_clip_data)); // 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); data->flags= clip_flags&(_clip_left|_clip_right); switch (data->flags) { case _clip_left: data->vector.i= transformed_endpoint.i; data->vector.j= transformed_endpoint.j; break; case _clip_right: /* negatives so we clip to the correct side */ data->vector.i= -transformed_endpoint.i; data->vector.j= -transformed_endpoint.j; break; } // warn(data->vector.i); // assert(TEST_RENDER_FLAG(endpoint_index, _endpoint_has_been_transformed)); x= endpoint_x_coordinates[endpoint_index]; data->x= (short)PIN(x, 0, view->screen_width); return (short)LastIndex; }
// Add a polygon to the polygon queue void RenderVisTreeClass::PUSH_POLYGON_INDEX(short polygon_index) { if (TEST_RENDER_FLAG(polygon_index, _polygon_is_visible)) return; // Grow the list only if necessary if (polygon_queue_size < PolygonQueue.size()) PolygonQueue[polygon_queue_size]= polygon_index; else PolygonQueue.push_back(polygon_index); polygon_queue_size++; SET_RENDER_FLAG(polygon_index, _polygon_is_visible); }
/* be sure to examine all of a nodeÕs parents for clipping information (gak!) */ clipping_window_data *RenderSortPolyClass::build_clipping_windows( node_data *ChainBegin) { // LP change: growable lists AccumulatedLineClips.clear(); AccumulatedEndpointClips.clear(); clipping_window_data *first_clipping_window = NULL; clipping_window_data *last_clipping_window = NULL; endpoint_clip_data *endpoint; line_clip_data *line; short x0, x1; /* ignoring what clipping parameters weÕve gotten, this is the left and right borders of this node on the screen */ short i, j; // LP: references to simplify the code vector<endpoint_clip_data>& EndpointClips = RVPtr->EndpointClips; vector<line_clip_data>& LineClips = RVPtr->LineClips; vector<clipping_window_data>& ClippingWindows = RVPtr->ClippingWindows; vector<short>& endpoint_x_coordinates = RVPtr->endpoint_x_coordinates; /* calculate x0,x1 (real left and right borders of this node) in case the left and right borders of the window are sloppy */ { // LP change: look at beginning of chain polygon_data *polygon= get_polygon_data(ChainBegin->polygon_index); /* all these nodes should be the same */ x0= SHRT_MAX, x1= SHRT_MIN; for (i= 0;i<polygon->vertex_count;++i) { short endpoint_index= polygon->endpoint_indexes[i]; if (TEST_RENDER_FLAG(endpoint_index, _endpoint_has_been_transformed)) { short x= endpoint_x_coordinates[endpoint_index]; if (x<x0) x0= x; if (x>x1) x1= x; } else { x0= SHRT_MIN, x1= SHRT_MAX; break; } } } /* add left, top and bottom of screen */ endpoint_clip_data *EndpointClipPtr = &EndpointClips[indexLEFT_SIDE_OF_SCREEN]; AccumulatedEndpointClips.push_back(EndpointClipPtr); line_clip_data *LineClipPtr = &LineClips[indexTOP_AND_BOTTOM_OF_SCREEN]; AccumulatedLineClips.push_back(LineClipPtr); /* accumulate clipping information, left to right, into local arrays */ // Move along chain for (node_data *ChainNode = ChainBegin; ChainNode; ChainNode = ChainNode->PS_Shared) { node_data *node; // LP change: use chain node as starting point for (node= ChainNode;node;node= node->parent) /* examine this node and all parents! */ { /* sort in endpoint clips (left to right) */ for (i= 0;i<node->clipping_endpoint_count;++i) { endpoint= &EndpointClips[node->clipping_endpoints[i]]; for (j= 0;j<short(AccumulatedEndpointClips.size());++j) { if (AccumulatedEndpointClips[j]==endpoint) { j= NONE; break; } /* found duplicate */ if ((AccumulatedEndpointClips[j]->x==endpoint->x&&endpoint->flags==_clip_left) || AccumulatedEndpointClips[j]->x>endpoint->x) { break; /* found sorting position if x is greater or x is equal and this is a left clip */ } } if (j!=NONE) /* if the endpoint was not a duplicate */ { /* expand the array, if necessary, and add the new endpoint */ int Length = AccumulatedEndpointClips.size(); AccumulatedEndpointClips.push_back(NULL); assert(AccumulatedEndpointClips.size() <= 32767); // Originally a short value if (j!=Length) memmove(&AccumulatedEndpointClips[j+1], &AccumulatedEndpointClips[j], (Length-j)*sizeof(endpoint_clip_data *)); AccumulatedEndpointClips[j]= endpoint; } } /* sort in line clips, avoiding redundancies; calculate_vertical_line_clip_data(), the function which deals with these, does not depend on them being sorted */ for (i= 0;i<node->clipping_line_count;++i) { line= &LineClips[node->clipping_lines[i]]; for (j= 0;j<short(AccumulatedLineClips.size());++j) if (AccumulatedLineClips[j]==line) break; /* found duplicate */ if (j==short(AccumulatedLineClips.size())) /* if the line was not a duplicate */ { AccumulatedLineClips.push_back(line); assert(AccumulatedLineClips.size() <= 32767); // Originally a short value } } } } // dprintf("#%d accumulated points @ %p", accumulated_endpoint_clip_count, accumulated_endpoint_clips); // dprintf("#%d accumulated lines @ %p", accumulated_line_clip_count, accumulated_line_clips); /* add right side of screen */ EndpointClipPtr = &EndpointClips[indexRIGHT_SIDE_OF_SCREEN]; AccumulatedEndpointClips.push_back(EndpointClipPtr); /* build the clipping windows */ { short state= _looking_for_left_clip; endpoint_clip_data *left_clip = NULL, *right_clip = NULL; for (i= 0;i<short(AccumulatedEndpointClips.size());++i) { endpoint= AccumulatedEndpointClips[i]; switch (endpoint->flags) { case _clip_left: switch (state) { case _looking_for_left_clip: left_clip= endpoint; state= _looking_for_right_clip; break; case _looking_for_right_clip: left_clip= endpoint; /* found more strict clipping point, use it instead */ break; } break; case _clip_right: switch (state) { case _looking_for_right_clip: right_clip= endpoint; state= _building_clip_window; break; /* ignore _left_clips */ } break; default: vassert(false,csprintf(temporary,"RenderSortPoly.cpp: build_clipping_windows(): bad state: %d",state)); break; } if (state==_building_clip_window) { if (left_clip->x<view->screen_width && right_clip->x>0 && left_clip->x<right_clip->x) { // LP change: clipping windows are in growable list size_t Length = ClippingWindows.size(); POINTER_DATA OldCWPointer = POINTER_CAST(&ClippingWindows.front()); // Add a dummy object and check if the pointer got changed clipping_window_data Dummy; Dummy.next_window = NULL; // Fake initialization to shut up CW ClippingWindows.push_back(Dummy); POINTER_DATA NewCWPointer = POINTER_CAST(&ClippingWindows.front()); if (NewCWPointer != OldCWPointer) { // Get the clipping windows and sorted nodes into sync; no render objects yet for (size_t k=0; k<Length; k++) { clipping_window_data &ClippingWindow = ClippingWindows[k]; if (ClippingWindow.next_window != NULL) ClippingWindow.next_window = (clipping_window_data *)(NewCWPointer + (POINTER_CAST(ClippingWindow.next_window) - OldCWPointer)); } for (size_t k=0; k<SortedNodes.size(); k++) { sorted_node_data &SortedNode = SortedNodes[k]; if (SortedNode.clipping_windows != NULL) SortedNode.clipping_windows = (clipping_window_data *)(NewCWPointer + (POINTER_CAST(SortedNode.clipping_windows) - OldCWPointer)); } } clipping_window_data *window= &ClippingWindows[Length]; /* handle maintaining the linked list of clipping windows */ if (!first_clipping_window) { first_clipping_window= last_clipping_window= window; } else { last_clipping_window->next_window= window; last_clipping_window= window; } window->x0= left_clip->x, window->x1= right_clip->x; window->left= left_clip->vector; window->right= right_clip->vector; calculate_vertical_clip_data(&AccumulatedLineClips.front(), AccumulatedLineClips.size(), window, MAX(x0, window->x0), MIN(x1, window->x1)); window->next_window= NULL; } state= _looking_for_left_clip; } } } return first_clipping_window; }
// LP change: make it better able to do long-distance views // Using parent index instead of pointer to avoid stale-pointer bug void RenderVisTreeClass::cast_render_ray(long_vector2d *_vector, int16 endpoint_index, node_data* parent, int16 bias) /* _clockwise or _counterclockwise for walking endpoints */ { auto polygon_index = parent->polygon_index; do { auto clipping_endpoint_index = endpoint_index; int16 clipping_line_index; auto clip_flags = next_polygon_along_line(&polygon_index, (world_point2d *) &view->origin, _vector, &clipping_endpoint_index, &clipping_line_index, bias); if (polygon_index == NONE) { if (clip_flags & _split_render_ray) { cast_render_ray( _vector, endpoint_index, parent, _clockwise_bias); cast_render_ray( _vector, endpoint_index, parent, _counterclockwise_bias); } continue; } node_data **node_reference, *node; /* find the old node referencing this polygon transition or build one */ for( node_reference = &parent->children; *node_reference && (*node_reference)->polygon_index != polygon_index; node_reference = &(*node_reference)->siblings) ; node = *node_reference; if (!node) { // LP change: using growable list // Contents get swapped when the length starts to exceed the capacity. // When they are not NULL, // "parent", "siblings" and "children" are pointers to members, // "reference" is a pointer to a member with an offset. // Cast the pointers to whatever size of integer the system uses. const size_t Length = Nodes.size(); node_data Dummy; Dummy.flags = 0; // Fake initialization to shut up CW Nodes.push_back(Dummy); node = &Nodes[Length]; // The length here is the "old" length *node_reference = node; INITIALIZE_NODE(node, polygon_index, 0, parent, node_reference); // Place new node in tree if it has gotten rooted if (Length > 0) { node_data *CurrNode = &Nodes.front(); while(true) { const int32 PolyDiff = int32(polygon_index) - int32(CurrNode->polygon_index); if (PolyDiff > 0) { node_data *NextNode = CurrNode->PS_Greater; if (NextNode) // Advance CurrNode = NextNode; else { // Attach to end CurrNode->PS_Greater = node; break; } } else if (PolyDiff < 0) { node_data *NextNode = CurrNode->PS_Less; if (NextNode) // Advance CurrNode = NextNode; else { // Attach to end CurrNode->PS_Less = node; break; } } else // Equal { node_data *NextNode = CurrNode->PS_Shared; if (NextNode) // Splice node into shared-polygon chain node->PS_Shared = NextNode; CurrNode->PS_Shared = node; break; } } } } /* update the line clipping information, if necessary, for this node (don't add duplicates */ if (clipping_line_index != NONE) { if (!TEST_RENDER_FLAG(clipping_line_index, _line_has_clip_data)) calculate_line_clipping_information(clipping_line_index, clip_flags); clipping_line_index = line_clip_indexes[clipping_line_index]; ix i; const auto nodeClippingLineCount = node->clipping_line_count; for( i = 0; i < nodeClippingLineCount && node->clipping_lines[i] != clipping_line_index; ++i) ; if (i == nodeClippingLineCount) { assert(node->clipping_line_count < MAXIMUM_CLIPPING_LINES_PER_NODE); node->clipping_lines[ node->clipping_line_count++ ] = clipping_line_index; } } /* update endpoint clipping information for this node if we have a valid endpoint with clip */ if( !isNONE(clipping_endpoint_index) && clip_flags & ( _clip_left | _clip_right ) ) { clipping_endpoint_index = calculate_endpoint_clipping_information( clipping_endpoint_index, clip_flags); // Be sure it's valid if (!isNONE(clipping_endpoint_index) && node->clipping_endpoint_count < MAXIMUM_CLIPPING_ENDPOINTS_PER_NODE) node->clipping_endpoints[ node->clipping_endpoint_count++ ] = clipping_endpoint_index; } parent = node; } while (polygon_index != NONE); }
// 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); } } }
// LP change: make it better able to do long-distance views // Using parent index instead of pointer to avoid stale-pointer bug void RenderVisTreeClass::cast_render_ray( long_vector2d *_vector, // world_vector2d *vector, short endpoint_index, int ParentIndex, /* 0==root */ short bias) /* _clockwise or _counterclockwise for walking endpoints */ { // LP: keep the parent-node pointer and index in sync with each other: node_data *parent = &Nodes.front() + ParentIndex; short polygon_index= parent->polygon_index; // dprintf("shooting at e#%d of p#%d", endpoint_index, polygon_index); do { short clipping_endpoint_index= endpoint_index; short clipping_line_index; uint16 clip_flags= next_polygon_along_line(&polygon_index, (world_point2d *) &view->origin, _vector, &clipping_endpoint_index, &clipping_line_index, bias); if (polygon_index==NONE) { if (clip_flags&_split_render_ray) { cast_render_ray(_vector, endpoint_index, ParentIndex, _clockwise_bias); cast_render_ray(_vector, endpoint_index, ParentIndex, _counterclockwise_bias); // LP: could have reallocated, so keep in sync! parent = &Nodes.front() + ParentIndex; } } else { node_data **node_reference, *node; /* find the old node referencing this polygon transition or build one */ for (node_reference= &parent->children; *node_reference && (*node_reference)->polygon_index!=polygon_index; node_reference= &(*node_reference)->siblings) ; node= *node_reference; if (!node) { // LP change: using growable list // Contents get swapped when the length starts to exceed the capacity. // When they are not NULL, // "parent", "siblings" and "children" are pointers to members, // "reference" is a pointer to a member with an offset. // Cast the pointers to whatever size of integer the system uses. size_t Length = Nodes.size(); POINTER_DATA OldNodePointer = POINTER_CAST(&Nodes.front()); // Add a dummy object and check if the pointer got changed node_data Dummy; Dummy.flags = 0; // Fake initialization to shut up CW Nodes.push_back(Dummy); POINTER_DATA NewNodePointer = POINTER_CAST(&Nodes.front()); if (NewNodePointer != OldNodePointer) { for (size_t k=0; k<Length; k++) { node_data &Node = Nodes[k]; // If NULL, then these pointers were already copied. if (Node.parent) Node.parent = (node_data *)(NewNodePointer + (POINTER_CAST(Node.parent) - OldNodePointer)); if (Node.reference) Node.reference = (node_data **)(NewNodePointer + (POINTER_CAST(Node.reference) - OldNodePointer)); if (Node.siblings) Node.siblings = (node_data *)(NewNodePointer + (POINTER_CAST(Node.siblings) - OldNodePointer)); if (Node.children) Node.children = (node_data *)(NewNodePointer + (POINTER_CAST(Node.children) - OldNodePointer)); if (Node.PS_Greater) Node.PS_Greater = (node_data *)(NewNodePointer + (POINTER_CAST(Node.PS_Greater) - OldNodePointer)); if (Node.PS_Less) Node.PS_Less = (node_data *)(NewNodePointer + (POINTER_CAST(Node.PS_Less) - OldNodePointer)); if (Node.PS_Shared) Node.PS_Shared = (node_data *)(NewNodePointer + (POINTER_CAST(Node.PS_Shared) - OldNodePointer)); } // Edit parent-node pointer also parent = &Nodes.front() + ParentIndex; // CB: Find the node reference again, the old one may point to stale memory for (node_reference= &parent->children; *node_reference && (*node_reference)->polygon_index!=polygon_index; node_reference= &(*node_reference)->siblings) ; } node = &Nodes[Length]; // The length here is the "old" length *node_reference= node; INITIALIZE_NODE(node, polygon_index, 0, parent, node_reference); // Place new node in tree if it has gotten rooted if (Length > 0) { node_data *CurrNode = &Nodes.front(); while(true) { long PolyDiff = long(polygon_index) - long(CurrNode->polygon_index); if (PolyDiff > 0) { node_data *NextNode = CurrNode->PS_Greater; if (NextNode) // Advance CurrNode = NextNode; else { // Attach to end CurrNode->PS_Greater = node; break; } } else if (PolyDiff < 0) { node_data *NextNode = CurrNode->PS_Less; if (NextNode) // Advance CurrNode = NextNode; else { // Attach to end CurrNode->PS_Less = node; break; } } else // Equal { node_data *NextNode = CurrNode->PS_Shared; if (NextNode) // Splice node into shared-polygon chain node->PS_Shared = NextNode; CurrNode->PS_Shared = node; break; } } } } /* update the line clipping information, if necessary, for this node (donÕt add duplicates */ if (clipping_line_index!=NONE) { short i; if (!TEST_RENDER_FLAG(clipping_line_index, _line_has_clip_data)) calculate_line_clipping_information(clipping_line_index, clip_flags); clipping_line_index= line_clip_indexes[clipping_line_index]; for (i=0; i<node->clipping_line_count&&node->clipping_lines[i]!=clipping_line_index; ++i) ; if (i==node->clipping_line_count) { assert(node->clipping_line_count<MAXIMUM_CLIPPING_LINES_PER_NODE); node->clipping_lines[node->clipping_line_count++]= clipping_line_index; } } /* update endpoint clipping information for this node if we have a valid endpoint with clip */ if (clipping_endpoint_index!=NONE && (clip_flags&(_clip_left|_clip_right))) { clipping_endpoint_index= calculate_endpoint_clipping_information(clipping_endpoint_index, clip_flags); // Be sure it's valid if (clipping_endpoint_index != NONE) { if (node->clipping_endpoint_count<MAXIMUM_CLIPPING_ENDPOINTS_PER_NODE) node->clipping_endpoints[node->clipping_endpoint_count++]= clipping_endpoint_index; } } parent= node; // LP: keep in sync! ParentIndex = static_cast<int>(parent - &Nodes.front()); } } while (polygon_index!=NONE); }