void drawOccluded(Window* win, Rect* baserect, List* splitrect_list) { if (!splitrect_list) return; int split_count = 0; int total_count = 1; int working_total = 0; List* out_rects; Rect* working_rects = (Rect*)0; int i, j, k; Rect *new_rect, *rect, *split_rect, *out_rect; //If there's nothing occluding us, just render the bitmap and get out of here if (!splitrect_list->count) { drawBmpRect(win, baserect); return; } out_rects = List_new(); if (!out_rects) { return; } rect = Rect_new(baserect->top, baserect->left, baserect->bottom, baserect->right); if (!rect) { List_delete(out_rects, Rect_deleter); return; } if (!List_add(out_rects, (void*)rect)) { free((void*)rect); List_delete(out_rects, Rect_deleter); return; } //For each splitting rect, split each rect in out_rects, delete the rectangle that was split, and add the resultant split rectangles List_for_each(splitrect_list, split_rect, Rect*) { List_for_each(out_rects, out_rect, Rect*) { if ((split_rect->left <= out_rect->right && split_rect->right >= out_rect->left && split_rect->top <= out_rect->bottom && split_rect->bottom >= out_rect->top)) { List* clip_list = splitRect(out_rect, split_rect); if (!clip_list) { List_delete(out_rects, Rect_deleter); return; } //If nothing was returned, we actually want to clip a rectangle in its entirety if (!clip_list->count) { List_remove(out_rects, (void*)out_rect, Rect_deleter); //If we deleted the last output rectangle, we are completely //occluded and can return early if (out_rects->count == 0) { List_delete(clip_list, Rect_deleter); List_delete(out_rects, Rect_deleter); return; } //Otherwise, go back to the top of the loop and test the next out_rect continue; } //Replace the rectangle that got split with the first result rectangle rect = (Rect*)List_get_at(clip_list, 0); out_rect->top = rect->top; out_rect->left = rect->left; out_rect->bottom = rect->bottom; out_rect->right = rect->right; //Append the rest of the result rectangles to the output collection List_for_each_skip(clip_list, rect, Rect*, 1) { new_rect = Rect_new(rect->top, rect->left, rect->bottom, rect->right); if (!new_rect) { List_delete(clip_list, Rect_deleter); List_delete(out_rects, Rect_deleter); return; } if (!List_add(out_rects, (void*)new_rect)){ free((void*)new_rect); List_delete(clip_list, Rect_deleter); List_delete(out_rects, Rect_deleter); return; } } //Free the space that was used for the split List_delete(clip_list, Rect_deleter); //Restart the list List_rewind(out_rects); } }
List* splitRect(Rect* rdest, Rect* rknife) { Rect baserect; List* outrect; Rect* new_rect; baserect.top = rdest->top; baserect.left = rdest->left; baserect.bottom = rdest->bottom; baserect.right = rdest->right; /* cons_prints("Splitting rect ("); cons_printDecimal(rdest->top); cons_prints(", "); cons_printDecimal(rdest->left); cons_prints(", "); cons_printDecimal(rdest->bottom); cons_prints(", "); cons_printDecimal(rdest->right); cons_prints(") with ("); cons_printDecimal(rknife->top); cons_prints(", "); cons_printDecimal(rknife->left); cons_prints(", "); cons_printDecimal(rknife->bottom); cons_prints(", "); cons_printDecimal(rknife->right); cons_prints(")\n"); */ #ifdef RECT_TEST //printf("splitting (%u, %u, %u, %u)", baserect.top, baserect.left, baserect.bottom, baserect.right); //printf("against (%u, %u, %u, %u)\n", rknife.top, rknife.left, rknife.bottom, rknife.right); #endif //RECT_TEST //prints("Allocating space for "); //printDecimal(sizeof(rect)*rect_count); //prints(" rect bytes\n"); outrect = List_new(); if(!outrect) { prints("Couldn't allocate rect space\n"); return outrect; } // cons_prints("Doing left edge split\n"); //Split by left edge if(rknife->left >= baserect.left && rknife->left <= baserect.right) { new_rect = Rect_new(baserect.top, baserect.left, baserect.bottom, rknife->left - 1); if(!new_rect) { List_delete(outrect, Rect_deleter); return (List*)0; } if(!List_add(outrect, new_rect)) { free((void*)new_rect); List_delete(outrect, Rect_deleter); return (List*)0; } baserect.left = rknife->left; } // cons_prints("Doing top edge split\n"); //Split by top edge if(rknife->top <= baserect.bottom && rknife->top >= baserect.top) { new_rect = Rect_new(baserect.top, baserect.left, rknife->top - 1, baserect.right); if(!new_rect) { List_delete(outrect, Rect_deleter); return (List*)0; } if(!List_add(outrect, new_rect)) { free((void*)new_rect); List_delete(outrect, Rect_deleter); return (List*)0; } baserect.top = rknife->top; } // cons_prints("Doing right edge split\n"); //Split by right edge if(rknife->right >= baserect.left && rknife->right <= baserect.right) { new_rect = Rect_new(baserect.top, rknife->right + 1, baserect.bottom, baserect.right); if(!new_rect) { List_delete(outrect, Rect_deleter); return (List*)0; } if(!List_add(outrect, new_rect)) { free((void*)new_rect); List_delete(outrect, Rect_deleter); return (List*)0; } baserect.right = rknife->right; } // cons_prints("Doing bottom edge split\n"); //Split by bottom edge if(rknife->bottom >= baserect.top && rknife->bottom <= baserect.bottom) { new_rect = Rect_new(rknife->bottom + 1, baserect.left, baserect.bottom, baserect.right); if(!new_rect) { List_delete(outrect, Rect_deleter); return (List*)0; } if(!List_add(outrect, new_rect)) { free((void*)new_rect); List_delete(outrect, Rect_deleter); return (List*)0; } baserect.bottom = rknife->bottom; } /* cons_prints("Result: \n"); List_for_each(outrect, new_rect, Rect*) { cons_prints(" "); cons_printDecimal(new_rect->top); cons_prints(", "); cons_printDecimal(new_rect->left); cons_prints(", "); cons_printDecimal(new_rect->bottom); cons_prints(", "); cons_printDecimal(new_rect->right); cons_prints("\n"); } scans(10, inbuf); */ return outrect; }
List* Rect_split(Rect subject_rect, Rect cutting_rect) { //Allocate the list of result rectangles List* output_rects; if(!(output_rects = List_new())) return output_rects; Rect subject_copy = subject_rect; //We need a rectangle to hold new rectangles before //they get pushed into the output list Rect* temp_rect; //Begin splitting //1 -Split by left edge if that edge is between the subject's left and right edges if(rect_min_x(cutting_rect) > rect_min_x(subject_copy) && rect_min_x(cutting_rect) <= rect_max_x(subject_copy)) { //Try to make a new rectangle spanning from the subject rectangle's left and stopping before //the cutting rectangle's left if(!(temp_rect = Rect_new(rect_min_y(subject_copy), rect_min_x(subject_copy), rect_max_y(subject_copy), rect_min_x(cutting_rect) - 1))) { //If the object creation failed, we need to delete the list and exit failed kfree(output_rects); return (List*)0; } //Add the new rectangle to the output list List_add(output_rects, temp_rect); //Shrink the subject rectangle to exclude the split portion int diff = rect_min_x(cutting_rect) - rect_min_x(subject_copy); rect_min_x(subject_copy) += diff; subject_copy.size.width -= diff; } //2 -Split by top edge if that edge is between the subject's top and bottom edges if(rect_min_y(cutting_rect) > rect_min_y(subject_copy) && rect_min_y(cutting_rect) <= rect_max_y(subject_copy)) { //Try to make a new rectangle spanning from the subject rectangle's top and stopping before //the cutting rectangle's top if(!(temp_rect = Rect_new(rect_min_y(subject_copy), rect_min_x(subject_copy), rect_min_y(cutting_rect) - 1, rect_max_x(subject_copy)))) { //If the object creation failed, we need to delete the list and exit failed //This time, also delete any previously allocated rectangles for(; output_rects->count; temp_rect = List_remove_at(output_rects, 0)) kfree(temp_rect); kfree(output_rects); return (List*)0; } //Add the new rectangle to the output list List_add(output_rects, temp_rect); //Shrink the subject rectangle to exclude the split portion int diff = rect_min_y(cutting_rect) - rect_min_y(subject_copy); rect_min_y(subject_copy) += diff; subject_copy.size.height -= diff; } //3 -Split by right edge if that edge is between the subject's left and right edges if(rect_max_x(cutting_rect) >= rect_min_x(subject_copy) && rect_max_x(cutting_rect) < rect_max_x(subject_copy)) { //Try to make a new rectangle spanning from the subject rectangle's right and stopping before //the cutting rectangle's right if(!(temp_rect = Rect_new(rect_min_y(subject_copy), rect_max_x(cutting_rect) + 1, rect_max_y(subject_copy), rect_max_x(subject_copy)))) { //Free on fail for(; output_rects->count; temp_rect = List_remove_at(output_rects, 0)) kfree(temp_rect); kfree(output_rects); return (List*)0; } //Add the new rectangle to the output list List_add(output_rects, temp_rect); //Shrink the subject rectangle to exclude the split portion int shrink_amount = rect_max_x(subject_copy) - rect_max_x(cutting_rect); subject_copy.size.width -= shrink_amount; } //4 -Split by bottom edge if that edge is between the subject's top and bottom edges if(rect_max_y(cutting_rect) >= rect_min_y(subject_copy) && rect_max_y(cutting_rect) < rect_max_y(subject_copy)) { //Try to make a new rectangle spanning from the subject rectangle's bottom and stopping before //the cutting rectangle's bottom if(!(temp_rect = Rect_new(rect_max_y(cutting_rect) + 1, rect_min_x(subject_copy), rect_max_y(subject_copy), rect_max_x(subject_copy)))) { //Free on fail for(; output_rects->count; temp_rect = List_remove_at(output_rects, 0)) kfree(temp_rect); kfree(output_rects); return (List*)0; } //Add the new rectangle to the output list List_add(output_rects, temp_rect); //Shrink the subject rectangle to exclude the split portion int shrink_amount = rect_max_y(subject_copy) - rect_max_y(cutting_rect); subject_copy.size.height -= shrink_amount; } //Finally, after all that, we can return the output rectangles return output_rects; }