void RenderVisTreeClass::initialize_render_tree() { // LP change: using growable list Nodes.clear(); node_data Dummy; Dummy.flags = 0; // Fake initialization to shut up CW Nodes.push_back(Dummy); INITIALIZE_NODE(&Nodes.front(), view->origin_polygon_index, 0, NULL, NULL); }
int8_t push_front_DequeList(DequeList *deque, void *obj, size_t objsize, int flag) { Node *tmp; CHECK_VARN(deque, EINVAL); CHECK_VARN(obj, EINVAL); CHECK_OBJSIZE(deque,objsize,EINVAL); INITIALIZE_NODE(tmp,deque,obj,flag); if (!S(deque)) { H(deque) = T(deque) = tmp; S(deque)++; } else { ADD_FRONT(tmp, deque); } return SUCCESS; allocobjfail: ADD_FREE_NODE(deque,tmp); allocfail: return -EALLOCF; }
int8_t push_StackList(StackList * stack, void *obj, size_t objsize, int8_t flag) { Node *tmp; CHECK_VARN(stack, EINVAL); CHECK_VARN(obj, EINVAL); CHECK_OBJSIZE(stack,objsize,EINVAL); INITIALIZE_NODE(tmp,stack,obj,flag); if (!S(stack)) { H(stack) = T(stack) = tmp; S(stack)++; } else { ADD_BACK(tmp, stack); } return SUCCESS; allocobjfail: ADD_FREE_NODE(stack,tmp); allocfail: return EALLOCF; }
void * insert_BinaryTree(BinaryTree * tree, void *obj, size_t objsize, int flag) { Node *ptr = NULL, *tmp = NULL; int res = 0; CHECK_VARN(tree,NULL); CHECK_VARN(obj,NULL); CHECK_OBJSIZE(tree, objsize,NULL); INITIALIZE_NODE(tmp,tree,obj,flag); if(!S(tree)) { H(tree) = tmp; tmp->ptr[PARENT] = NULL; S(tree)++; } else { ptr = H(tree); TRAVERSE_TREE(ptr,tree,tmp->objptr,res,objsize); if(res < 0) { if(ptr->ptr[RIGHT] == T(tree)) { T(tree) = tmp; } INSERT_RIGHT(ptr,tmp); } else if(res > 0) { INSERT_LEFT(ptr,tmp); } else { DELETE_OBJPTR(tree,tmp); ADD_FREE_NODE(tree,tmp); } } return tmp; allocobjfail: ADD_FREE_NODE(tree,tmp); allocfail: ALLOCFAIL(object); return NULL; }
// 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); }
// 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); }