// // ReadLumpData // static void ReadLumpData(lump_t *lump) { size_t len; cur_comms->file_pos++; DisplaySetBar(1, cur_comms->file_pos); DisplayTicker(); # if DEBUG_LUMP PrintDebug("Reading... %s (%d)\n", lump->name, lump->length); # endif if (lump->length == 0) return; lump->data = UtilCalloc(lump->length); fseek(in_file, lump->start, SEEK_SET); len = fread(lump->data, lump->length, 1, in_file); if (len != 1) { if (wad.current_level) PrintWarn("Trouble reading lump '%s' in %s\n", lump->name, wad.current_level->name); else PrintWarn("Trouble reading lump '%s'\n", lump->name); } lump->flags &= ~LUMP_READ_ME; }
// // ReadWadFile // glbsp_ret_e ReadWadFile(const char *filename) { int check; char *read_msg; // open input wad file & read header in_file = fopen(filename, "rb"); if (! in_file) { if (errno == ENOENT) SetErrorMsg("Cannot open WAD file: %s", filename); else SetErrorMsg("Cannot open WAD file: %s [%s]", filename, strerror(errno)); return GLBSP_E_ReadError; } if (! ReadHeader(filename)) { fclose(in_file); return GLBSP_E_ReadError; } PrintMsg("Opened %cWAD file : %s\n", (wad.kind == IWAD) ? 'I' : 'P', filename); PrintVerbose("Reading %d dir entries at 0x%X\n", wad.num_entries, wad.dir_start); // read directory ReadDirectory(); DisplayOpen(DIS_FILEPROGRESS); DisplaySetTitle("glBSP Reading Wad"); read_msg = UtilFormat("Reading: %s", filename); DisplaySetBarText(1, read_msg); DisplaySetBarLimit(1, CountLumpTypes(LUMP_READ_ME, LUMP_READ_ME)); DisplaySetBar(1, 0); UtilFree(read_msg); cur_comms->file_pos = 0; // now read lumps check = ReadAllLumps(); if (check != wad.num_entries) InternalError("Read directory count consistency failure (%d,%d)", check, wad.num_entries); wad.current_level = NULL; DisplayClose(); return GLBSP_E_OK; }
static glbsp_ret_e HandleLevel(void) { superblock_t *seg_list; node_t *root_node; node_t *root_stale_node; subsec_t *root_sub; glbsp_ret_e ret; if (cur_comms->cancelled) return GLBSP_E_Cancelled; DisplaySetBarLimit(1, 1000); DisplaySetBar(1, 0); cur_comms->build_pos = 0; LoadLevel(); InitBlockmap(); // create initial segs seg_list = CreateSegs(); root_stale_node = (num_stale_nodes == 0) ? NULL : LookupStaleNode(num_stale_nodes - 1); // recursively create nodes ret = BuildNodes(seg_list, &root_node, &root_sub, 0, root_stale_node); FreeSuper(seg_list); if (ret == GLBSP_E_OK) { ClockwiseBspTree(root_node); PrintVerbose("Built %d NODES, %d SSECTORS, %d SEGS, %d VERTEXES\n", num_nodes, num_subsecs, num_segs, num_normal_vert + num_gl_vert); if (root_node) PrintVerbose("Heights of left and right subtrees = (%d,%d)\n", ComputeBspHeight(root_node->r.node), ComputeBspHeight(root_node->l.node)); SaveLevel(root_node); } FreeLevel(); FreeQuickAllocCuts(); FreeQuickAllocSupers(); return ret; }
// // WriteWadFile // glbsp_ret_e WriteWadFile(const char *filename) { int check1, check2; char *write_msg; PrintMsg("\n"); PrintMsg("Saving WAD as %s\n", filename); RecomputeDirectory(); // create output wad file & write the header out_file = fopen(filename, "wb"); if (! out_file) { SetErrorMsg("Cannot create WAD file: %s [%s]", filename, strerror(errno)); return GLBSP_E_WriteError; } WriteHeader(); DisplayOpen(DIS_FILEPROGRESS); DisplaySetTitle("glBSP Writing Wad"); write_msg = UtilFormat("Writing: %s", filename); DisplaySetBarText(1, write_msg); DisplaySetBarLimit(1, CountLumpTypes(LUMP_IGNORE_ME, 0)); DisplaySetBar(1, 0); UtilFree(write_msg); cur_comms->file_pos = 0; // now write all the lumps to the output wad check1 = WriteAllLumps(); DisplayClose(); // finally, write out the directory check2 = WriteDirectory(); if (check1 != wad.num_entries || check2 != wad.num_entries) InternalError("Write directory count consistency failure (%d,%d,%d)", check1, check2, wad.num_entries); return GLBSP_E_OK; }
// // WriteLumpData // static void WriteLumpData(lump_t *lump) { size_t len; int align_size; cur_comms->file_pos++; DisplaySetBar(1, cur_comms->file_pos); DisplayTicker(); # if DEBUG_LUMP if (lump->flags & LUMP_COPY_ME) PrintDebug("Copying... %s (%d)\n", lump->name, lump->length); else PrintDebug("Writing... %s (%d)\n", lump->name, lump->length); # endif if (ftell(out_file) != lump->new_start) PrintWarn("Consistency failure writing %s (%08lX, %08X\n", lump->name, ftell(out_file), lump->new_start); if (lump->length == 0) return; if (lump->flags & LUMP_COPY_ME) { lump->data = UtilCalloc(lump->length); fseek(in_file, lump->start, SEEK_SET); len = fread(lump->data, lump->length, 1, in_file); if (len != 1) PrintWarn("Trouble reading lump %s to copy\n", lump->name); } len = fwrite(lump->data, lump->length, 1, out_file); if (len != 1) PrintWarn("Trouble writing lump %s\n", lump->name); align_size = ALIGN_LEN(lump->length) - lump->length; if (align_size > 0) fwrite(align_filler, align_size, 1, out_file); UtilFree(lump->data); lump->data = NULL; }
// // PickNode // // Find the best seg in the seg_list to use as a partition line. // seg_t *PickNode(superblock_t *seg_list, int depth, const bbox_t *bbox) { seg_t *best=NULL; int best_cost=INT_MAX; int progress=0; int prog_step=1<<24; int build_step=0; # if DEBUG_PICKNODE PrintDebug("PickNode: BEGUN (depth %d)\n", depth); # endif /* compute info for showing progress */ if (depth <= 6) { static int depth_counts[7] = { 248, 100, 30, 10, 6, 4, 2 }; int total = seg_list->real_num + seg_list->mini_num; build_step = depth_counts[depth]; prog_step = 1 + ((total - 1) / build_step); if (total / prog_step < build_step) { cur_comms->build_pos += build_step - total / prog_step; build_step = total / prog_step; DisplaySetBar(1, cur_comms->build_pos); DisplaySetBar(2, cur_comms->file_pos + cur_comms->build_pos / 100); } } DisplayTicker(); /* -AJA- another (optional) optimisation, when building just the GL * nodes. We assume that the original nodes are reasonably * good choices, and re-use them as much as possible, saving * *heaps* of time on really large levels. */ if (cur_info->fast && seg_list->real_num >= SEG_FAST_THRESHHOLD) { # if DEBUG_PICKNODE PrintDebug("PickNode: Looking for Fast node...\n"); # endif best = FindFastSeg(seg_list, bbox); if (best) { /* update progress */ cur_comms->build_pos += build_step; DisplaySetBar(1, cur_comms->build_pos); DisplaySetBar(2, cur_comms->file_pos + cur_comms->build_pos / 100); # if DEBUG_PICKNODE PrintDebug("PickNode: Using Fast node (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", best->start->x, best->start->y, best->end->x, best->end->y); # endif return best; } } if (FALSE == PickNodeWorker(seg_list, seg_list, &best, &best_cost, &progress, prog_step)) { /* hack here : BuildNodes will detect the cancellation */ return NULL; } # if DEBUG_PICKNODE if (! best) { PrintDebug("PickNode: NO BEST FOUND !\n"); } else { PrintDebug("PickNode: Best has score %d.%02d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", best_cost / 100, best_cost % 100, best->start->x, best->start->y, best->end->x, best->end->y); } # endif /* all finished, return best Seg */ return best; }
/* returns FALSE if cancelled */ static int PickNodeWorker(superblock_t *part_list, superblock_t *seg_list, seg_t ** best, int *best_cost, int *progress, int prog_step) { seg_t *part; int num; int cost; /* use each Seg as partition */ for (part=part_list->segs; part; part = part->next) { if (cur_comms->cancelled) return FALSE; # if DEBUG_PICKNODE PrintDebug("PickNode: %sSEG %p sector=%d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", part->linedef ? "" : "MINI", part, part->sector ? part->sector->index : -1, part->start->x, part->start->y, part->end->x, part->end->y); # endif /* something for the user to look at */ (*progress) += 1; if ((*progress % prog_step) == 0) { cur_comms->build_pos++; DisplaySetBar(1, cur_comms->build_pos); DisplaySetBar(2, cur_comms->file_pos + cur_comms->build_pos / 100); } /* ignore minisegs as partition candidates */ if (! part->linedef) continue; cost = EvalPartition(seg_list, part, *best_cost); /* seg unsuitable or too costly ? */ if (cost < 0 || cost >= *best_cost) continue; /* we have a new better choice */ (*best_cost) = cost; /* remember which Seg */ (*best) = part; } DisplayTicker(); /* recursively handle sub-blocks */ for (num=0; num < 2; num++) { if (part_list->subs[num]) PickNodeWorker(part_list->subs[num], seg_list, best, best_cost, progress, prog_step); } return TRUE; }
glbsp_ret_e GlbspBuildNodes(const nodebuildinfo_t *info, const nodebuildfuncs_t *funcs, volatile nodebuildcomms_t *comms) { char *file_msg; glbsp_ret_e ret = GLBSP_E_OK; cur_info = info; cur_funcs = funcs; cur_comms = comms; cur_comms->total_big_warn = 0; cur_comms->total_small_warn = 0; // clear cancelled flag comms->cancelled = FALSE; // sanity check if (!cur_info->input_file || cur_info->input_file[0] == 0 || !cur_info->output_file || cur_info->output_file[0] == 0) { SetErrorMsg("INTERNAL ERROR: Missing in/out filename !"); return GLBSP_E_BadArgs; } InitDebug(); InitEndian(); if (info->missing_output) PrintMsg("* No output file specified. Using: %s\n\n", info->output_file); if (info->same_filenames) PrintMsg("* Output file is same as input file. Using -loadall\n\n"); // opens and reads directory from the input wad ret = ReadWadFile(cur_info->input_file); if (ret != GLBSP_E_OK) { TermDebug(); return ret; } if (CountLevels() <= 0) { CloseWads(); TermDebug(); SetErrorMsg("No levels found in wad !"); return GLBSP_E_Unknown; } PrintMsg("\n"); PrintVerbose("Creating nodes using tunable factor of %d\n", info->factor); DisplayOpen(DIS_BUILDPROGRESS); DisplaySetTitle("glBSP Build Progress"); file_msg = UtilFormat("File: %s", cur_info->input_file); DisplaySetBarText(2, file_msg); DisplaySetBarLimit(2, CountLevels() * 10); DisplaySetBar(2, 0); UtilFree(file_msg); cur_comms->file_pos = 0; // loop over each level in the wad while (FindNextLevel()) { ret = HandleLevel(); if (ret != GLBSP_E_OK) break; cur_comms->file_pos += 10; DisplaySetBar(2, cur_comms->file_pos); } DisplayClose(); // writes all the lumps to the output wad if (ret == GLBSP_E_OK) { ret = WriteWadFile(cur_info->output_file); // when modifying the original wad, any GWA companion must be deleted if (ret == GLBSP_E_OK && cur_info->same_filenames) DeleteGwaFile(cur_info->output_file); PrintMsg("\n"); PrintMsg("Total serious warnings: %d\n", cur_comms->total_big_warn); PrintMsg("Total minor warnings: %d\n", cur_comms->total_small_warn); ReportFailedLevels(); } // close wads and free memory CloseWads(); TermDebug(); cur_info = NULL; cur_comms = NULL; cur_funcs = NULL; return ret; }