glbsp-2.24-source/0000755000175000017500000000000010652040361013321 5ustar aaptedaaptedglbsp-2.24-source/nodeview/0000755000175000017500000000000010652040071015137 5ustar aaptedaaptedglbsp-2.24-source/nodeview/system.cc0000644000175000017500000001552010624752045017007 0ustar aaptedaapted//------------------------------------------------------------------------ // SYSTEM : System specific code //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "defs.h" static char message_buf[1024]; // // FatalError // void FatalError(const char *str, ...) { /// strcpy(message_buf, "\nFATAL ERROR: "); /// char *msg_end = message_buf + strlen(message_buf); va_list args; va_start(args, str); vsprintf(message_buf, str, args); va_end(args); PrintDebug(">> FATAL ERROR: %s", message_buf); throw (const char *) message_buf; } // // InternalError // void InternalError(const char *str, ...) { strcpy(message_buf, "\nINTERNAL ERROR: "); char *msg_end = message_buf + strlen(message_buf); va_list args; va_start(args, str); vsprintf(msg_end, str, args); va_end(args); PrintDebug(">> %s", message_buf); throw (const char *) message_buf; } // // PrintMsg // void PrintMsg(const char *str, ...) { va_list args; va_start(args, str); vsprintf(message_buf, str, args); va_end(args); printf("%s", message_buf); PrintDebug(">> %s", message_buf); } // // PrintWarn // void PrintWarn(const char *str, ...) { va_list args; va_start(args, str); vsprintf(message_buf, str, args); va_end(args); printf("Warning: %s", message_buf); PrintDebug("Warning: %s", message_buf); } //------------------------------------------------------------------------ // ARGUMENT HANDLING //------------------------------------------------------------------------ const char **arg_list = NULL; int arg_count = 0; // // ArgvInit // // Initialise argument list. Do NOT include the program name // (usually in argv[0]). The strings (and array) are copied. // // NOTE: doesn't merge multiple uses of an option, hence // using ArgvFind() will only return the first usage. // void ArgvInit(int argc, const char **argv) { arg_count = argc; SYS_ASSERT(arg_count >= 0); if (arg_count == 0) { arg_list = NULL; return; } arg_list = new const char *[arg_count]; int dest = 0; for (int i = 0; i < arg_count; i++) { const char *cur = argv[i]; SYS_NULL_CHECK(cur); #ifdef MACOSX // ignore MacOS X rubbish if (strncmp(cur, "-psn", 4) == 0) continue; #endif // support GNU-style long options if (cur[0] == '-' && cur[1] == '-' && isalnum(cur[2])) cur++; arg_list[dest] = strdup(cur); // support DOS-style short options if (cur[0] == '/' && (isalnum(cur[1]) || cur[1] == '?') && cur[2] == 0) *(char *)(arg_list[dest]) = '-'; dest++; } arg_count = dest; } // // ArgvTerm(void) // void ArgvTerm(void) { while (arg_count-- > 0) free((void *) arg_list[arg_count]); if (arg_list) delete[] arg_list; } // // ArgvFind // // Returns index number, or -1 if not found. // int ArgvFind(char short_name, const char *long_name, int *num_params) { SYS_ASSERT(short_name || long_name); if (num_params) *num_params = 0; int p = 0; for (; p < arg_count; p++) { if (! ArgvIsOption(p)) continue; const char *str = arg_list[p]; if (short_name && (short_name == tolower(str[1])) && str[2] == 0) break; if (long_name && (UtilStrCaseCmp(long_name, str + 1) == 0)) break; } if (p >= arg_count) // NOT FOUND return -1; if (num_params) { int q = p + 1; while ((q < arg_count) && ! ArgvIsOption(q)) q++; *num_params = q - p - 1; } return p; } bool ArgvIsOption(int index) { SYS_ASSERT(index >= 0); SYS_ASSERT(index < arg_count); const char *str = arg_list[index]; SYS_NULL_CHECK(str); return (str[0] == '-'); } //------------------------------------------------------------------------ // DEBUGGING CODE //------------------------------------------------------------------------ #define DEBUGGING_FILE "nv_debug.txt" static FILE *debug_fp = NULL; // // InitDebug // void InitDebug(bool enable) { if (! enable) { debug_fp = NULL; return; } debug_fp = fopen(DEBUGGING_FILE, "w"); if (! debug_fp) PrintWarn("Unable to open DEBUG FILE: %s\n", DEBUGGING_FILE); PrintDebug("====== START OF DEBUG FILE ======\n\n"); } // // TermDebug // void TermDebug(void) { if (debug_fp) { PrintDebug("\n====== END OF DEBUG FILE ======\n"); fclose(debug_fp); debug_fp = NULL; } } // // PrintDebug // void PrintDebug(const char *str, ...) { if (debug_fp) { va_list args; va_start(args, str); vfprintf(debug_fp, str, args); va_end(args); fflush(debug_fp); } } //------------------------------------------------------------------------ // ENDIAN CODE //------------------------------------------------------------------------ static bool cpu_big_endian = false; // // InitEndian // // Parts inspired by the Yadex endian.cc code. // void InitEndian(void) { volatile union { uint8_g mem[32]; uint32_g val; } u; /* sanity-check type sizes */ if (sizeof(uint8_g) != 1) FatalError("Sanity check failed: sizeof(uint8_g) = %d", sizeof(uint8_g)); if (sizeof(uint16_g) != 2) FatalError("Sanity check failed: sizeof(uint16_g) = %d", sizeof(uint16_g)); if (sizeof(uint32_g) != 4) FatalError("Sanity check failed: sizeof(uint32_g) = %d", sizeof(uint32_g)); /* check endianness */ memset((uint32_g *) u.mem, 0, sizeof(u.mem)); u.mem[0] = 0x70; u.mem[1] = 0x71; u.mem[2] = 0x72; u.mem[3] = 0x73; PrintDebug("Endianness magic value: 0x%08x\n", u.val); if (u.val == 0x70717273) cpu_big_endian = true; else if (u.val == 0x73727170) cpu_big_endian = false; else FatalError("Sanity check failed: weird endianness (0x%08x)", u.val); PrintDebug("Endianness = %s\n", cpu_big_endian ? "BIG" : "LITTLE"); PrintDebug("Endianness check: 0x1234 --> 0x%04x\n", (int) Endian_U16(0x1234)); PrintDebug("Endianness check: 0x11223344 --> 0x%08x\n\n", Endian_U32(0x11223344)); } // // Endian_U16 // uint16_g Endian_U16(uint16_g x) { if (cpu_big_endian) return (x >> 8) | (x << 8); else return x; } // // Endian_U32 // uint32_g Endian_U32(uint32_g x) { if (cpu_big_endian) return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24); else return x; } glbsp-2.24-source/nodeview/main.cc0000644000175000017500000001047710625203212016401 0ustar aaptedaapted//------------------------------------------------------------------------ // MAIN Program //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "defs.h" #define GUI_PrintMsg printf static bool inited_FLTK = false; static int main_result = 0; static void ShowTitle(void) { GUI_PrintMsg( "\n" "**** " PROG_NAME " (C) 2007 Andrew Apted ****\n\n" ); } static void ShowInfo(void) { GUI_PrintMsg( "Info...\n\n" ); } void MainSetDefaults(void) { } void InitFLTK(void) { Fl::scheme(NULL); fl_message_font(FL_HELVETICA, 16); Fl_File_Icon::load_system_icons(); inited_FLTK = true; } static void DisplayError(const char *str, ...) { va_list args; if (inited_FLTK) { char buffer[1024]; va_start(args, str); vsprintf(buffer, str, args); va_end(args); fl_alert("%s", buffer); } else { va_start(args, str); vfprintf(stderr, str, args); va_end(args); fprintf(stderr, "\n"); } main_result = 9; } //------------------------------------------------------------------------ // MAIN PROGRAM //------------------------------------------------------------------------ int main(int argc, char **argv) { try { // skip program name argv++, argc--; ArgvInit(argc, (const char **)argv); InitDebug(ArgvFind(0, "debug") >= 0); InitEndian(); if (ArgvFind('?', NULL) >= 0 || ArgvFind('h', "help") >= 0) { ShowTitle(); ShowInfo(); exit(1); } InitFLTK(); // set defaults, also initializes the nodebuildxxxx stuff MainSetDefaults(); const char *filename = "data/doom2.wad"; if (arg_count > 0 && ! ArgvIsOption(0)) filename = arg_list[0]; else { int params; int idx = ArgvFind(0, "file", ¶ms); if (idx >= 0 && params >= 1) filename = arg_list[idx + 1]; } if (CheckExtension(filename, "gwa")) FatalError("Main file must be a normal WAD (not GWA).\n"); the_wad = wad_c::Load(filename); if (!the_wad) FatalError("Unable to read WAD file: %s\n", filename); const char *gwa_name = ReplaceExtension(filename, "gwa"); if (FileExists(gwa_name)) { the_gwa = wad_c::Load(gwa_name); if (!the_gwa) FatalError("Unable to read GWA file: %s\n", gwa_name); } const char *level_name = NULL; { int params; int idx = ArgvFind(0, "warp", ¶ms); if (idx >= 0 && params >= 1) level_name = arg_list[idx + 1]; if (! level_name) { level_name = the_wad->FirstLevelName(); if (! level_name) FatalError("Unable to find ANY level in WAD.\n"); } } path_c *path = NULL; { int params; int idx = ArgvFind(0, "path", ¶ms); if (idx >= 0 && params >= 1) path = path_c::ReadFile(arg_list[idx + 1]); } LoadLevel(level_name); guix_win = new Guix_MainWin(PROG_NAME); if (path) guix_win->grid->SetPath(path); double lx, ly, hx, hy; LevelGetBounds(&lx, &ly, &hx, &hy); guix_win->grid->FitBBox(lx, ly, hx, hy); guix_win->info->SetMap(level_name); guix_win->info->SetNodes("GL"); // FIXME: node version guix_win->info->SetNodeIndex(lev_nodes.num - 1); // run the GUI until the user quits while (! guix_win->want_quit) Fl::wait(); } catch (const char * err) { DisplayError("%s", err); } catch (assert_fail_c err) { DisplayError("Sorry, an internal error occurred:\n%s", err.GetMessage()); } catch (...) { DisplayError("An unknown problem occurred (UI code)"); } delete guix_win; delete the_wad; delete the_gwa; TermDebug(); return main_result; } glbsp-2.24-source/nodeview/grid.cc0000644000175000017500000004604210647412103016404 0ustar aaptedaapted//------------------------------------------------------------------------ // GRID : Draws the map (lines, nodes, etc) //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "defs.h" #if 0 static void foo_win_close_CB(Fl_Widget *w, void *data) { } #endif // // W_Grid Constructor // W_Grid::W_Grid(int X, int Y, int W, int H, const char *label) : Fl_Widget(X, Y, W, H, label), zoom(DEF_GRID_ZOOM), zoom_mul(1.0), mid_x(0), mid_y(0), grid_MODE(1), partition_MODE(1), bbox_MODE(1), miniseg_MODE(2), shade_MODE(1), path(NULL), route_len(0) { visit_route = new char[MAX_ROUTE]; } // // W_Grid Destructor // W_Grid::~W_Grid() { delete[] visit_route; } void W_Grid::SetZoom(int new_zoom) { if (new_zoom < MIN_GRID_ZOOM) new_zoom = MIN_GRID_ZOOM; if (new_zoom > MAX_GRID_ZOOM) new_zoom = MAX_GRID_ZOOM; if (zoom == new_zoom) return; zoom = new_zoom; zoom_mul = pow(2.0, (zoom / 2.0 - 9.0)); guix_win->info->SetZoom(zoom_mul); // fprintf(stderr, "Zoom %d Mul %1.5f\n", zoom, zoom_mul); redraw(); } void W_Grid::SetPos(double new_x, double new_y) { mid_x = new_x; mid_y = new_y; redraw(); } void W_Grid::FitBBox(double lx, double ly, double hx, double hy) { double dx = hx - lx; double dy = hy - ly; zoom = MAX_GRID_ZOOM; for (; zoom > MIN_GRID_ZOOM; zoom--) { zoom_mul = pow(2.0, (zoom / 2.0 - 9.0)); if (dx * zoom_mul < w() && dy * zoom_mul < h()) break; } zoom_mul = pow(2.0, (zoom / 2.0 - 9.0)); guix_win->info->SetZoom(zoom_mul); SetPos(lx + dx / 2.0, ly + dy / 2.0); new_node_or_sub(); // bit hackish (calling it here) } void W_Grid::MapToWin(double mx, double my, int *X, int *Y) const { double hx = x() + w() / 2.0; double hy = y() + h() / 2.0; (*X) = I_ROUND(hx + (mx - mid_x) * zoom_mul); (*Y) = I_ROUND(hy - (my - mid_y) * zoom_mul); } void W_Grid::WinToMap(int X, int Y, double *mx, double *my) const { double hx = x() + w() / 2.0; double hy = y() + h() / 2.0; (*mx) = mid_x + (X - hx) / zoom_mul; (*my) = mid_y - (Y - hy) / zoom_mul; } //------------------------------------------------------------------------ void W_Grid::resize(int X, int Y, int W, int H) { Fl_Widget::resize(X, Y, W, H); } void W_Grid::draw() { /// FIXME fl_push_clip(x(), y(), w(), h()); fl_color(FL_BLACK); fl_rectf(x(), y(), w(), h()); // 3456789012345678901234567890 //static const char *ity_2_to_N3 = "-------------------------233"; static const char *ity_2_to_0 = "-------------------334455555"; static const char *ity_2_to_3 = "-------------334455667777777"; static const char *ity_2_to_6 = "-------33445566778899999----"; static const char *ity_2_to_9 = "-33445566778899999----------"; static const char *ity_2_to_12 = "566778899999----------------"; static const char *ity_2_to_15 = "999999----------------------"; //draw_grid(0.125, ity_2_to_N3[zoom - 3]); draw_grid(1.0, ity_2_to_0 [zoom - 3]); draw_grid(8.0, ity_2_to_3 [zoom - 3]); draw_grid(64.0, ity_2_to_6 [zoom - 3]); draw_grid(512.0, ity_2_to_9 [zoom - 3]); draw_grid(4096.0, ity_2_to_12[zoom - 3]); draw_grid(32768.0, ity_2_to_15[zoom - 3]); node_c *root = lev_nodes.Get(lev_nodes.num - 1); if (partition_MODE == 1) draw_all_partitions(); draw_node(root, 0, true); if (partition_MODE == 2) draw_all_partitions(); if (path) draw_path(); fl_pop_clip(); } void W_Grid::draw_grid(double spacing, int ity) { if (grid_MODE == 0) return; if (! isdigit(ity)) return; ity = MIN(ity - '0', 9); fl_color(fl_rgb_color(0, 0, 255 * ity / 9)); double mlx = mid_x - w() * 0.5 / zoom_mul; double mly = mid_y - h() * 0.5 / zoom_mul; double mhx = mid_x + w() * 0.5 / zoom_mul; double mhy = mid_y + h() * 0.5 / zoom_mul; int gx = GRID_FIND(mid_x, spacing); int gy = GRID_FIND(mid_y, spacing); int x1 = x(); int y1 = y(); int x2 = x() + w(); int y2 = y() + h(); int dx, dy; int wx, wy; for (dx = 0; true; dx++) { double xx = gx + dx * spacing; if (xx > mhx) break; if (xx < mlx) continue; MapToWin(xx, gy, &wx, &wy); fl_yxline(wx, y1, y2); } for (dx = -1; true; dx--) { double xx = gx + dx * spacing; if (xx < mlx) break; if (xx > mhx) continue; MapToWin(xx, gy, &wx, &wy); fl_yxline(wx, y1, y2); } for (dy = 0; true; dy++) { double yy = gy + dy * spacing; if (yy > mhy) break; if (yy < mly) continue; MapToWin(gx, yy, &wy, &wy); fl_xyline(x1, wy, x2); } for (dy = -1; true; dy--) { double yy = gy + dy * spacing; if (yy < mly) break; if (yy > mhy) continue; MapToWin(gx, yy, &wy, &wy); fl_xyline(x1, wy, x2); } } void W_Grid::draw_partition(const node_c *nd, int ity) { double mlx = mid_x - w() * 0.5 / zoom_mul; double mly = mid_y - h() * 0.5 / zoom_mul; double mhx = mid_x + w() * 0.5 / zoom_mul; double mhy = mid_y + h() * 0.5 / zoom_mul; double tlx, tly; double thx, thy; // intersect the partition line (which extends to infinity) with // the sides of the screen (in map coords). Whether we use the // left/right sides to top/bottom depends on the angle of the // partition line. if (ABS(nd->dx) > ABS(nd->dy)) { tlx = mlx; thx = mhx; tly = nd->y + nd->dy * (mlx - nd->x) / double(nd->dx); thy = nd->y + nd->dy * (mhx - nd->x) / double(nd->dx); if (MAX(tly, thy) < mly || MIN(tly, thy) > mhy) return; } else { tlx = nd->x + nd->dx * (mly - nd->y) / double(nd->dy); thx = nd->x + nd->dx * (mhy - nd->y) / double(nd->dy); tly = mly; thy = mhy; if (MAX(tlx, thx) < mlx || MIN(tlx, thx) > mhx) return; } int sx, sy; int ex, ey; MapToWin(tlx, tly, &sx, &sy); MapToWin(thx, thy, &ex, &ey); if (partition_MODE < 2) { // move vertical or horizontal lines by one pixel // (to prevent being clobbered by segs) if (ABS(nd->dx) < ABS(nd->dy)) sx++, ex++; else sy++, ey++; } fl_color(fl_rgb_color(ity*80-70, 0, ity*80-70)); fl_line(sx, sy, ex, ey); // draw arrow heads along it float pd_len = sqrt(nd->dx*nd->dx + nd->dy*nd->dy); float pdx = nd->dx / pd_len; float pdy = -nd->dy / pd_len; for (float u=0.1; u <= 0.91; u += 0.16) { int ax = int(sx + (ex-sx) * u); int ay = int(sy + (ey-sy) * u); fl_line(ax, ay, ax + int((-pdy-pdx*1.0)*8), ay + int(( pdx-pdy*1.0)*8) ); fl_line(ax, ay, ax + int(( pdy-pdx*1.0)*8), ay + int((-pdx-pdy*1.0)*8) ); } } void W_Grid::draw_bbox(const bbox_t *bbox, int ity) { double mlx = mid_x - w() * 0.5 / zoom_mul; double mly = mid_y - h() * 0.5 / zoom_mul; double mhx = mid_x + w() * 0.5 / zoom_mul; double mhy = mid_y + h() * 0.5 / zoom_mul; // check if bounding box is off screen if (bbox->maxx < mlx || bbox->minx > mhx || bbox->maxy < mly || bbox->miny > mhy) { return; } int sx, sy; int ex, ey; MapToWin(bbox->minx, bbox->maxy, &sx, &sy); MapToWin(bbox->maxx, bbox->miny, &ex, &ey); if (partition_MODE < 2) { // make one pixel bigger (to prevent being clobbered by segs) sx--; sy--; ex++; ey++; } fl_color(fl_rgb_color(ity*50, 0, 0)); fl_line(sx, sy, sx, ey); fl_line(sx, sy, ex, sy); fl_line(sx, ey, ex, ey); fl_line(ex, sy, ex, ey); } void W_Grid::draw_all_partitions() { node_c * nodes[4]; bbox_t * bboxs[4]; nodes[0] = nodes[1] = nodes[2] = NULL; nodes[3] = lev_nodes.Get(lev_nodes.num - 1); bboxs[0] = bboxs[1] = bboxs[2] = bboxs[3] = NULL; for (int rt_idx = 0; rt_idx < route_len; rt_idx++) { node_c *cur = nodes[3]; child_t *next_ch = (visit_route[rt_idx] == RT_LEFT) ? &cur->l : &cur->r; nodes[0] = nodes[1]; bboxs[0] = bboxs[1]; nodes[1] = nodes[2]; bboxs[1] = bboxs[2]; nodes[2] = nodes[3]; bboxs[2] = bboxs[3]; nodes[3] = next_ch->node; bboxs[3] = &next_ch->bounds; // quit if we reach a subsector if (! nodes[3]) break; } // (Note: only displaying two of them) for (int n_idx = 2; n_idx <= 3; n_idx++) { if (bbox_MODE == 1) if (bboxs[n_idx]) draw_bbox(bboxs[n_idx], n_idx + 1); if (nodes[n_idx]) draw_partition(nodes[n_idx], n_idx + 1); } } void W_Grid::draw_node(const node_c *nd, int pos, bool on_route) { if (! on_route) { draw_child(&nd->l, pos, false); draw_child(&nd->r, pos, false); } else if (pos >= route_len) { draw_child(&nd->l, pos, true); draw_child(&nd->r, pos, true); } else if (visit_route[pos] == RT_LEFT) { // get drawing order correct, draw shaded side FIRST. draw_child(&nd->r, pos, false); draw_child(&nd->l, pos, true); } else // RT_RIGHT { draw_child(&nd->l, pos, false); draw_child(&nd->r, pos, true); } } void W_Grid::draw_child(const child_t *ch, int pos, bool on_route) { // OPTIMISATION: check the bounding box if (ch->node) { draw_node(ch->node, pos + 1, on_route); } else /* Subsector */ { draw_subsector(ch->subsec, pos + 1, on_route); } } void W_Grid::draw_subsector(const subsec_c *sub, int pos, bool on_route) { for (seg_c *seg = sub->seg_list; seg; seg = seg->next) { if (on_route && pos == route_len) fl_color(fl_color_cube(4,5,4)); else if (! set_seg_color(seg, on_route)) continue; static int foo; float dx=0, dy=0; if (on_route && pos == route_len) { foo = foo * 1103515245 + 12345; dx = (((foo >> 8) & 255) - 128) / 60.0; foo = foo * 1103515245 + 12345; dy = (((foo >> 8) & 255) - 128) / 60.0; } draw_line(seg->start->x+dx, seg->start->y+dy, seg->end->x+dx, seg->end->y+dy); } } bool W_Grid::set_seg_color(seg_c *seg, bool on) { if (shade_MODE == 0 && !on) return false; if (shade_MODE == 2) on = true; int ity = on ? 255 : 144; if (! seg->linedef) // miniseg { if (miniseg_MODE < 2) return false; fl_color(0, ity*144/255, ity*192/255); return true; } if (! seg->linedef->left || ! seg->linedef->right) // 1-sided line { fl_color(on ? FL_WHITE : fl_rgb_color(128)); return true; } sector_c *front = seg->linedef->right->sector; sector_c *back = seg->linedef->left->sector; int floor_min = MIN(front->floor_h, back->floor_h); int floor_max = MAX(front->floor_h, back->floor_h); int ceil_min = MIN(front->ceil_h, back->ceil_h); // int ceil_max = MAX(front->ceil_h, back->ceil_h); if (ceil_min <= floor_max) // closed door ? { fl_color(fl_rgb_color(ity, ity/2, 0)); return true; } if (ceil_min - floor_max < 56) // narrow vertical gap ? { fl_color(fl_rgb_color(0, ity, ity)); return true; } if (seg->linedef->flags & 1) // marked impassable ? { fl_color(fl_rgb_color(ity, ity, 0)); return true; } if (floor_max - floor_min > 24) // unclimbable dropoff ? { fl_color(fl_rgb_color(0, ity, 0)); return true; } if (miniseg_MODE < 1) return false; fl_color(fl_rgb_color(on ? 176 : 96)); // everything else return true; } void W_Grid::draw_line(double x1, double y1, double x2, double y2) { double mlx = mid_x - w() * 0.5 / zoom_mul; double mly = mid_y - h() * 0.5 / zoom_mul; double mhx = mid_x + w() * 0.5 / zoom_mul; double mhy = mid_y + h() * 0.5 / zoom_mul; // Based on Cohen-Sutherland clipping algorithm int out1 = MAP_OUTCODE(x1, y1, mlx, mly, mhx, mhy); int out2 = MAP_OUTCODE(x2, y2, mlx, mly, mhx, mhy); /// PrintDebug("LINE (%1.3f,%1.3f) --> (%1.3f,%1.3f)\n", x1, y1, x2, y2); /// PrintDebug("RECT (%1.3f,%1.3f) --> (%1.3f,%1.3f)\n", mlx, mly, mhx, mhy); /// PrintDebug(" out1 = %d out2 = %d\n", out1, out2); while ((out1 & out2) == 0 && (out1 | out2) != 0) { /// PrintDebug("> LINE (%1.3f,%1.3f) --> (%1.3f,%1.3f)\n", x1, y1, x2, y2); /// PrintDebug("> out1 = %d out2 = %d\n", out1, out2); // may be partially inside box, find an outside point int outside = (out1 ? out1 : out2); SYS_ZERO_CHECK(outside); double dx = x2 - x1; double dy = y2 - y1; if (fabs(dx) < 0.1 && fabs(dy) < 0.1) break; double tmp_x, tmp_y; // clip to each side if (outside & O_BOTTOM) { tmp_x = x1 + dx * (mly - y1) / dy; tmp_y = mly; } else if (outside & O_TOP) { tmp_x = x1 + dx * (mhy - y1) / dy; tmp_y = mhy; } else if (outside & O_LEFT) { tmp_y = y1 + dy * (mlx - x1) / dx; tmp_x = mlx; } else /* outside & O_RIGHT */ { SYS_ASSERT(outside & O_RIGHT); tmp_y = y1 + dy * (mhx - x1) / dx; tmp_x = mhx; } /// PrintDebug("> outside = %d temp = (%1.3f, %1.3f)\n", tmp_x, tmp_y); SYS_ASSERT(out1 != out2); if (outside == out1) { x1 = tmp_x; y1 = tmp_y; out1 = MAP_OUTCODE(x1, y1, mlx, mly, mhx, mhy); } else { SYS_ASSERT(outside == out2); x2 = tmp_x; y2 = tmp_y; out2 = MAP_OUTCODE(x1, y1, mlx, mly, mhx, mhy); } } if (out1 & out2) return; int sx, sy; int ex, ey; MapToWin(x1, y1, &sx, &sy); MapToWin(x2, y2, &ex, &ey); fl_line(sx, sy, ex, ey); } void W_Grid::draw_path() { int p; // first, render the lines fl_color(fl_color_cube(0,7,4)); for (p = 0; p < path->point_num - 1; p++) { int x1, y1, x2, y2; path->GetPoint(p, &x1, &y1); path->GetPoint(p+1, &x2, &y2); draw_line(x1, y1, x2, y2); } // second, render the points themselves fl_color(FL_YELLOW); for (p = 0; p < path->point_num; p++) { int mx, my; int wx, wy; path->GetPoint(p, &mx, &my); MapToWin(mx, my, &wx, &wy); fl_rect(wx-1, wy-1, 3, 3); } } void W_Grid::scroll(int dx, int dy) { dx = dx * w() / 10; dy = dy * h() / 10; double mdx = dx / zoom_mul; double mdy = dy / zoom_mul; mid_x += mdx; mid_y += mdy; // fprintf(stderr, "Scroll pix (%d,%d) map (%1.1f, %1.1f) mid (%1.1f, %1.1f)\n", dx, dy, mdx, mdy, mid_x, mid_y); redraw(); } //------------------------------------------------------------------------ int W_Grid::handle(int event) { switch (event) { case FL_FOCUS: return 1; case FL_KEYDOWN: case FL_SHORTCUT: { int result = handle_key(Fl::event_key()); handle_mouse(Fl::event_x(), Fl::event_y()); return result; } case FL_ENTER: case FL_LEAVE: return 1; case FL_MOVE: handle_mouse(Fl::event_x(), Fl::event_y()); return 1; case FL_PUSH: if (Fl::focus() != this) { Fl::focus(this); handle(FL_FOCUS); return 1; } if (Fl::event_state() & FL_CTRL) { // select new subsector route_len = 0; while (descend_by_mouse(Fl::event_x(), Fl::event_y())); { /* nothing */ } } else { descend_by_mouse(Fl::event_x(), Fl::event_y()); } redraw(); return 1; case FL_MOUSEWHEEL: if (Fl::event_dy() < 0) SetZoom(zoom + 1); else if (Fl::event_dy() > 0) SetZoom(zoom - 1); handle_mouse(Fl::event_x(), Fl::event_y()); return 1; case FL_DRAG: case FL_RELEASE: // these are currently ignored. return 1; default: break; } return 0; // unused } int W_Grid::handle_key(int key) { if (key == 0) return 0; switch (key) { case '+': case '=': SetZoom(zoom + 1); return 1; case '-': case '_': SetZoom(zoom - 1); return 1; case FL_Left: scroll(-1, 0); return 1; case FL_Right: scroll(+1, 0); return 1; case FL_Up: scroll(0, +1); return 1; case FL_Down: scroll(0, -1); return 1; case 'g': case 'G': grid_MODE = (grid_MODE + 1) % 2; redraw(); return 1; case 'p': case 'P': partition_MODE = (partition_MODE + 1) % 3; redraw(); return 1; case 'b': case 'B': bbox_MODE = (bbox_MODE + 1) % 2; redraw(); return 1; case 'm': case 'M': miniseg_MODE = (miniseg_MODE + 2) % 3; redraw(); return 1; case 's': case 'S': shade_MODE = (shade_MODE + 1) % 2; redraw(); return 1; case 'u': case 'U': if (route_len > 0) { route_len--; new_node_or_sub(); redraw(); } return 1; case 't': case 'T': route_len = 0; new_node_or_sub(); redraw(); return 1; case 'x': DialogShowAndGetChoice(ALERT_TXT, 0, "Please foo the joo."); return 1; default: break; } return 0; // unused } bool W_Grid::descend_by_mouse(int wx, int wy) { node_c *cur_nd; subsec_c *cur_sub; bbox_t *cur_bbox; lowest_node(&cur_nd, &cur_sub, &cur_bbox); if (cur_sub) return false; double mx, my; WinToMap(wx, wy, &mx, &my); // transpose coords to the origin, check side double ox = mx - cur_nd->x; double oy = my - cur_nd->y; if (oy * cur_nd->dx < ox * cur_nd->dy) return descend_tree(RT_RIGHT); else return descend_tree(RT_LEFT); } bool W_Grid::descend_tree(char side) { // safety check (should never happen under normal circumstances) if (route_len >= MAX_ROUTE) return false; node_c *cur_nd; subsec_c *cur_sub; bbox_t *cur_bbox; lowest_node(&cur_nd, &cur_sub, &cur_bbox); if (cur_sub) return false; visit_route[route_len++] = side; new_node_or_sub(); return true; } void W_Grid::lowest_node(node_c **nd, subsec_c **sub, bbox_t **bbox) { *bbox = NULL; node_c *cur = lev_nodes.Get(lev_nodes.num - 1); node_c *next; for (int rt_idx = 0; rt_idx < route_len; rt_idx++) { child_t *child = (visit_route[rt_idx] == RT_LEFT) ? &cur->l : &cur->r; next = child->node; *bbox = &child->bounds; // reached a subsector ? if (! next) { *nd = cur; *sub = child->subsec; SYS_NULL_CHECK(*sub); return; } cur = next; } *nd = cur; *sub = NULL; } void W_Grid::handle_mouse(int wx, int wy) { if (! guix_win) return; double mx, my; WinToMap(wx, wy, &mx, &my); guix_win->info->SetMouse(mx, my); } void W_Grid::new_node_or_sub(void) { node_c *cur_nd; subsec_c *cur_sub; bbox_t *cur_bbox; lowest_node(&cur_nd, &cur_sub, &cur_bbox); if (cur_sub) { guix_win->info->BeginSegList(); for (seg_c *seg = cur_sub->seg_list; seg; seg = seg->next) guix_win->info->AddSeg(seg); guix_win->info->EndSegList(); guix_win->info->SetSubsectorIndex(cur_sub->index); guix_win->info->SetPartition(NULL); } else { guix_win->info->SetNodeIndex(cur_nd->index); guix_win->info->SetPartition(cur_nd); } guix_win->info->SetCurBBox(cur_bbox); // NULL is OK } glbsp-2.24-source/nodeview/path.h0000644000175000017500000000231210624752022016247 0ustar aaptedaapted//------------------------------------------------------------------------ // PATH : storage for path points //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_PATH_H__ #define __NODEVIEW_PATH_H__ class path_c { public: path_c(); ~path_c(); int point_num; int *points; // pairs private: static const int MAX_PTS = 1024; public: static path_c * ReadFile(const char *filename); void GetPoint(int index, int *x, int *y) { *x = points[index*2 + 0]; *y = points[index*2 + 1]; } }; #endif /* __NODEVIEW_PATH_H__ */ glbsp-2.24-source/nodeview/TODO.txt0000644000175000017500000000061310650365352016457 0ustar aaptedaapted NodeView TODO list ================== + info panel: >> node type (normal | GL V2 | GL V3 | GL V5 ) # mouse coords: - sector - linedef - vertex - subsector - seg - GL vertex + File|Select_Map : to select a new level + process multiple WAD / GWA files - seg list: only need to show start and end numbers. - RSCRIPT editor / browser. - REJECT browser. glbsp-2.24-source/nodeview/lists.h0000644000175000017500000000557710624751746016505 0ustar aaptedaapted//------------------------------------------------------------------------ // LIST library //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_LIST_H__ #define __NODEVIEW_LIST_H__ // (Yes, I'm probably nuts for not using std::list) class listnode_c { friend class list_c; private: listnode_c *nd_next; listnode_c *nd_prev; public: listnode_c() : nd_next(NULL), nd_prev(NULL) { } listnode_c(const listnode_c& other) : nd_next(other.nd_next), nd_prev(other.nd_prev) { } ~listnode_c() { } inline listnode_c& operator= (const listnode_c& rhs) { if (this != &rhs) { nd_next = rhs.nd_next; nd_prev = rhs.nd_prev; } return *this; } inline listnode_c *NodeNext() const { return nd_next; } inline listnode_c *NodePrev() const { return nd_prev; } }; class list_c { private: listnode_c *head; listnode_c *tail; public: list_c() : head(NULL), tail(NULL) { } list_c(const list_c& other) : head(other.head), tail(other.tail) { } ~list_c() { } inline list_c& operator= (const list_c& rhs) { if (this != &rhs) { head = rhs.head; tail = rhs.tail; } return *this; } void clear() { head = NULL; tail = NULL; } inline listnode_c *begin() const { return head; } inline listnode_c *end() const { return tail; } // insert_before // insert_after void remove(listnode_c *cur) { SYS_NULL_CHECK(cur); if (cur->nd_next) cur->nd_next->nd_prev = cur->nd_prev; else tail = cur->nd_prev; if (cur->nd_prev) cur->nd_prev->nd_next = cur->nd_next; else head = cur->nd_next; } void push_back(listnode_c *cur) { cur->nd_next = NULL; cur->nd_prev = tail; if (tail) tail->nd_next = cur; else head = cur; tail = cur; } void push_front(listnode_c *cur) { cur->nd_next = head; cur->nd_prev = NULL; if (head) head->nd_prev = cur; else tail = cur; head = cur; } inline listnode_c *pop_back() { listnode_c *cur = tail; if (cur) remove(cur); return cur; } inline listnode_c *pop_front() { listnode_c *cur = head; if (cur) remove(cur); return cur; } }; #endif /* __NODEVIEW_LIST_H__ */ glbsp-2.24-source/nodeview/path.cc0000644000175000017500000000300510624752016016410 0ustar aaptedaapted//------------------------------------------------------------------------ // PATH : storage for path points //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "defs.h" // // Path Constructor // path_c::path_c() : point_num(0), points(NULL) { } // // Path Destructor // path_c::~path_c() { if (points) delete[] points; } // // Path Reading // path_c * path_c::ReadFile(const char *filename) { FILE *fp = fopen(filename, "r"); if (! fp) { PrintWarn("Unable to open path file: %s\n", strerror(errno)); return false; } path_c *P = new path_c(); P->points = new int[MAX_PTS * 2]; for (P->point_num = 0; P->point_num < MAX_PTS; P->point_num++) { int *cur_pt = P->points + (P->point_num * 2); if (fscanf(fp, " %d %d ", cur_pt, cur_pt+1) != 2) break; } fclose(fp); return P; } glbsp-2.24-source/nodeview/dialog.h0000644000175000017500000000253710624275612016570 0ustar aaptedaapted//------------------------------------------------------------------------ // DIALOG : Pop-up dialog boxes //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_DIALOG_H__ #define __NODEVIEW_DIALOG_H__ void DialogLoadImages(void); void DialogFreeImages(void); int DialogShowAndGetChoice(const char *title, Fl_Pixmap *pic, const char *message, const char *left = "OK", const char *middle = NULL, const char *right = NULL); int DialogQueryFilename(const char *message, const char ** name_ptr, const char *guess_name); void GUI_FatalError(const char *str, ...); #define ALERT_TXT (PROG_NAME "Alert") #define MISSING_COMMS "(Not Specified)" #endif /* __NODEVIEW_DIALOG_H__ */ glbsp-2.24-source/nodeview/Makefile.unx0000644000175000017500000000150710624315717017426 0ustar aaptedaapted# # GL-Node Viewer # # Makefile for Unix/FLTK # BIN=nodeview SRC_DIR=nodeview FLTK_CFLAGS=-I/usr/local/lib FLTK_LIBS=-lfltk_images -lfltk -lX11 -lXext -lpng -ljpeg CC=gcc CXX=g++ CFLAGS=-O -g3 -Wall -DUNIX $(FLTK_CFLAGS) CXXFLAGS=$(CFLAGS) LDFLAGS=-L/usr/X11R6/lib LIBS=-lm $(FLTK_LIBS) OBJS=./main.o \ ./asserts.o \ ./dialog.o \ ./grid.o \ ./info.o \ ./level.o \ ./lists.o \ ./menu.o \ ./path.o \ ./system.o \ ./util.o \ ./wad.o \ ./window.o # ----- TARGETS ------------------------------------------------------ all: $(BIN) clean: rm -f $(BIN) *.o core core.* ERRS nv_debug.txt $(BIN): $(OBJS) $(CXX) $(CFLAGS) $(OBJS) -o $(BIN) $(LDFLAGS) $(LIBS) bin: all strip --strip-unneeded $(BIN) .PHONY: all clean bin install glbsp-2.24-source/nodeview/lists.cc0000644000175000017500000000152710624275627016631 0ustar aaptedaapted//------------------------------------------------------------------------ // LIST library //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "defs.h" /* nothing needed... yet */ glbsp-2.24-source/nodeview/menu.h0000644000175000017500000000213010624275637016271 0ustar aaptedaapted//------------------------------------------------------------------------ // MENU : Menu handling //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_MENU_H__ #define __NODEVIEW_MENU_H__ #define MANUAL_WINDOW_MIN_W 500 #define MANUAL_WINDOW_MIN_H 200 #ifdef MACOSX Fl_Sys_Menu_Bar #else Fl_Menu_Bar #endif * MenuCreate(int x, int y, int w, int h); void GUI_PrintMsg(const char *str, ...); #endif /* __NODEVIEW_MENU_H__ */ glbsp-2.24-source/nodeview/level.h0000644000175000017500000001456110624767214016444 0ustar aaptedaapted//------------------------------------------------------------------------ // LEVEL : Level structures & read/write functions. //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_LEVEL_H__ #define __NODEVIEW_LEVEL_H__ class node_c; class sector_c; class vertex_c { public: // coordinates double x, y; // vertex index. Always valid after loading and pruning of unused // vertices has occurred. For GL vertices, bit 30 will be set. int index; vertex_c(int _idx, const raw_vertex_t *raw); vertex_c(int _idx, const raw_v2_vertex_t *raw); ~vertex_c(); }; #define IS_GL_VERTEX (1 << 30) class sector_c { public: // sector index. Always valid after loading & pruning. int index; // heights int floor_h, ceil_h; // textures char floor_tex[8]; char ceil_tex[8]; // attributes int light; int special; int tag; sector_c(int _idx, const raw_sector_t *raw); ~sector_c(); }; class sidedef_c { public: // adjacent sector. Can be NULL (invalid sidedef) sector_c *sector; // offset values int x_offset, y_offset; // texture names char upper_tex[8]; char lower_tex[8]; char mid_tex[8]; // sidedef index. Always valid after loading & pruning. int index; sidedef_c(int _idx, const raw_sidedef_t *raw); ~sidedef_c(); }; class linedef_c { public: vertex_c *start; // from this vertex... vertex_c *end; // ... to this vertex sidedef_c *right; // right sidedef sidedef_c *left; // left sidede, or NULL if none // line is marked two-sided char two_sided; // zero length (line should be totally ignored) char zero_len; int flags; int type; int tag; // Hexen support int specials[5]; // linedef index. Always valid after loading & pruning of zero // length lines has occurred. int index; linedef_c(int _idx, const raw_linedef_t *raw); linedef_c(int _idx, const raw_hexen_linedef_t *raw); ~linedef_c(); }; class thing_c { public: int x, y; int type; int options; // other info (angle, and hexen stuff) omitted. We don't need to // write the THING lump, only read it. // Always valid (thing indices never change). int index; thing_c(int _idx, const raw_thing_t *raw); thing_c(int _idx, const raw_hexen_thing_t *raw); ~thing_c(); }; class seg_c { public: // link for list struct seg_c *next; vertex_c *start; // from this vertex... vertex_c *end; // ... to this vertex // linedef that this seg goes along, or NULL if miniseg linedef_c *linedef; // adjacent sector, or NULL if invalid sidedef or miniseg sector_c *sector; // 0 for right, 1 for left int side; // seg index. Only valid once the seg has been added to a // subsector. A negative value means it is invalid -- there // shouldn't be any of these once the BSP tree has been built. int index; // precomputed data for faster calculations double psx, psy; double pex, pey; double pdx, pdy; double p_length, p_angle; double p_para, p_perp; seg_c(int _idx, const raw_gl_seg_t *raw); seg_c(int _idx, const raw_v3_seg_t *raw); ~seg_c(); void precompute_data(); }; class subsec_c { public: // list of segs seg_c *seg_list; // count of segs int seg_count; // subsector index in lump. int index; // approximate middle point double mid_x; double mid_y; subsec_c(int _idx, const raw_subsec_t *raw); subsec_c(int _idx, const raw_v3_subsec_t *raw); ~subsec_c(); void append_seg(seg_c *cur); void build_seg_list(int first, int count); // builds the list of segs, and also determines mid point. }; typedef struct bbox_s { int minx, miny; int maxx, maxy; void from_raw(const raw_bbox_t *raw); } bbox_t; typedef struct child_s { // child node or subsector (one must be NULL) node_c *node; subsec_c *subsec; // child bounding box bbox_t bounds; } child_t; class node_c { public: int x, y; // starting point int dx, dy; // offset to ending point // right & left children child_t r; child_t l; // node index in lump int index; node_c (int _idx, const raw_node_t *raw); ~node_c(); }; /* ----- Level data arrays ----------------------- */ template class container_tp { public: int num; private: TYPE ** arr; const char *const name; public: container_tp(const char *type_name) : num(0), arr(NULL), name(type_name) { } ~container_tp() { if (arr) FreeAll(); } void Allocate(int _num) { if (arr) FreeAll(); num = _num; arr = new TYPE* [num]; for (int i = 0; i < num; i++) { arr[i] = NULL; } } void FreeAll() { for (int i = 0; i < num; i++) { if (arr[i] != NULL) delete arr[i]; } delete[] arr; num = 0; arr = NULL; } void Set(int index, TYPE *cur) { if (arr[index] != NULL) delete arr[index]; arr[index] = cur; } TYPE *Get(int index) { if (index < 0 || index >= num) { FatalError("No such %s number #%d", name, index); } return arr[index]; } }; #define EXTERN_LEVELARRAY(TYPE, BASEVAR) \ extern container_tp BASEVAR; EXTERN_LEVELARRAY(vertex_c, lev_vertices) EXTERN_LEVELARRAY(vertex_c, lev_gl_verts) EXTERN_LEVELARRAY(linedef_c, lev_linedefs) EXTERN_LEVELARRAY(sidedef_c, lev_sidedefs) EXTERN_LEVELARRAY(sector_c, lev_sectors) EXTERN_LEVELARRAY(thing_c, lev_things) EXTERN_LEVELARRAY(seg_c, lev_segs) EXTERN_LEVELARRAY(subsec_c, lev_subsecs) EXTERN_LEVELARRAY(node_c, lev_nodes) /* ----- function prototypes ----------------------- */ // load all level data for the current level void LoadLevel(const char *name); // free all level data void FreeLevel(void); void LevelGetBounds(double *lx, double *ly, double *hx, double *hy); #endif /* __NODEVIEW_LEVEL_H__ */ glbsp-2.24-source/nodeview/structs.h0000644000175000017500000001354110624752032017031 0ustar aaptedaapted//------------------------------------------------------------------------ // STRUCT : Doom structures, raw on-disk layout //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_STRUCTS_H__ #define __NODEVIEW_STRUCTS_H__ /* ----- The wad structures ---------------------- */ // wad header typedef struct raw_wad_header_s { char type[4]; uint32_g num_entries; uint32_g dir_start; } raw_wad_header_t; // directory entry typedef struct raw_wad_entry_s { uint32_g start; uint32_g length; char name[8]; } raw_wad_entry_t; // blockmap typedef struct raw_blockmap_header_s { sint16_g x_origin, y_origin; sint16_g x_blocks, y_blocks; } raw_blockmap_header_t; /* ----- The level structures ---------------------- */ typedef struct raw_vertex_s { sint16_g x, y; } raw_vertex_t; typedef struct raw_v2_vertex_s { sint32_g x, y; } raw_v2_vertex_t; typedef struct raw_linedef_s { uint16_g start; // from this vertex... uint16_g end; // ... to this vertex uint16_g flags; // linedef flags (impassible, etc) uint16_g type; // linedef type (0 for none, 97 for teleporter, etc) sint16_g tag; // this linedef activates the sector with same tag uint16_g sidedef1; // right sidedef uint16_g sidedef2; // left sidedef (only if this line adjoins 2 sectors) } raw_linedef_t; typedef struct raw_hexen_linedef_s { uint16_g start; // from this vertex... uint16_g end; // ... to this vertex uint16_g flags; // linedef flags (impassible, etc) uint8_g type; // linedef type uint8_g specials[5]; // hexen specials uint16_g sidedef1; // right sidedef uint16_g sidedef2; // left sidedef } raw_hexen_linedef_t; #define LINEFLAG_TWO_SIDED 4 #define HEXTYPE_POLY_START 1 #define HEXTYPE_POLY_EXPLICIT 5 typedef struct raw_sidedef_s { sint16_g x_offset; // X offset for texture sint16_g y_offset; // Y offset for texture char upper_tex[8]; // texture name for the part above char lower_tex[8]; // texture name for the part below char mid_tex[8]; // texture name for the regular part uint16_g sector; // adjacent sector } raw_sidedef_t; typedef struct raw_sector_s { sint16_g floor_h; // floor height sint16_g ceil_h; // ceiling height char floor_tex[8]; // floor texture char ceil_tex[8]; // ceiling texture uint16_g light; // light level (0-255) uint16_g special; // special behaviour (0 = normal, 9 = secret, ...) sint16_g tag; // sector activated by a linedef with same tag } raw_sector_t; typedef struct raw_thing_s { sint16_g x, y; // position of thing sint16_g angle; // angle thing faces (degrees) uint16_g type; // type of thing uint16_g options; // when appears, deaf, etc.. } raw_thing_t; // -JL- Hexen thing definition typedef struct raw_hexen_thing_s { sint16_g tid; // thing tag id (for scripts/specials) sint16_g x, y; // position sint16_g height; // start height above floor sint16_g angle; // angle thing faces uint16_g type; // type of thing uint16_g options; // when appears, deaf, dormant, etc.. uint8_g special; // special type uint8_g arg[5]; // special arguments } raw_hexen_thing_t; // -JL- Hexen polyobj thing types #define PO_ANCHOR_TYPE 3000 #define PO_SPAWN_TYPE 3001 #define PO_SPAWNCRUSH_TYPE 3002 // -JL- ZDoom polyobj thing types #define ZDOOM_PO_ANCHOR_TYPE 9300 #define ZDOOM_PO_SPAWN_TYPE 9301 #define ZDOOM_PO_SPAWNCRUSH_TYPE 9302 /* ----- The BSP tree structures ----------------------- */ typedef struct raw_seg_s { uint16_g start; // from this vertex... uint16_g end; // ... to this vertex uint16_g angle; // angle (0 = east, 16384 = north, ...) uint16_g linedef; // linedef that this seg goes along uint16_g flip; // true if not the same direction as linedef uint16_g dist; // distance from starting point } raw_seg_t; typedef struct raw_gl_seg_s { uint16_g start; // from this vertex... uint16_g end; // ... to this vertex uint16_g linedef; // linedef that this seg goes along, or -1 uint16_g side; // 0 if on right of linedef, 1 if on left uint16_g partner; // partner seg number, or -1 } raw_gl_seg_t; typedef struct raw_v3_seg_s { uint32_g start; // from this vertex... uint32_g end; // ... to this vertex uint16_g linedef; // linedef that this seg goes along, or -1 uint16_g flags; // flags (especially: side) uint32_g partner; // partner seg number, or -1 } raw_v3_seg_t; #define V3SEG_F_LEFT 0x0001 typedef struct raw_bbox_s { sint16_g maxy, miny; sint16_g minx, maxx; } raw_bbox_t; typedef struct raw_node_s { sint16_g x, y; // starting point sint16_g dx, dy; // offset to ending point raw_bbox_t b1, b2; // bounding rectangles uint16_g right, left; // children: Node or SSector (if high bit is set) } raw_node_t; typedef struct raw_subsec_s { uint16_g num; // number of Segs in this Sub-Sector uint16_g first; // first Seg } raw_subsec_t; typedef struct raw_v3_subsec_s { uint32_g num; // number of Segs in this Sub-Sector uint32_g first; // first Seg } raw_v3_subsec_t; #endif /* __NODEVIEW_STRUCTS_H__ */ glbsp-2.24-source/nodeview/window.h0000644000175000017500000000336410624752125016636 0ustar aaptedaapted//------------------------------------------------------------------------ // WINDOW : Main application window //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_WINDOW_H__ #define __NODEVIEW_WINDOW_H__ #define MAIN_BG_COLOR fl_gray_ramp(FL_NUM_GRAY * 9 / 24) class Guix_MainWin : public Fl_Double_Window { public: Guix_MainWin(const char *title); virtual ~Guix_MainWin(); // main child widgets #ifdef MACOSX Fl_Sys_Menu_Bar *menu_bar; #else Fl_Menu_Bar *menu_bar; #endif W_Grid *grid; W_Info *info; // user closed the window bool want_quit; // routine to capture the current main window state into the // guix_preferences_t structure. // void WritePrefs(); protected: // initial window size, read after the window manager has had a // chance to move the window somewhere else. If the window is still // there when CaptureState() is called, we don't need to update the // coords in the cookie file. // int init_x, init_y, init_w, init_h; }; extern Guix_MainWin * guix_win; void WindowSmallDelay(void); #endif /* __NODEVIEW_WINDOW_H__ */ glbsp-2.24-source/nodeview/wad.cc0000644000175000017500000002456410624752074016250 0ustar aaptedaapted//------------------------------------------------------------------------ // WAD : Wad file read/write functions. //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "defs.h" #define DEBUG_DIR 1 #define DEBUG_LUMP 0 #define APPEND_BLKSIZE 256 #define LEVNAME_BUNCH 20 #define ALIGN_LEN(len) ((((len) + 3) / 4) * 4) // Global variables wad_c *the_wad; wad_c *the_gwa; wad_c::wad_c() : in_file(NULL), kind(-1), num_entries(0), dir_start(-1), dir(), current_level(NULL), level_names(NULL), num_level_names(0) { } wad_c::~wad_c() { if (in_file) fclose(in_file); /* free directory entries */ for (lump_c *cur = (lump_c *)dir.pop_front(); cur != NULL; cur = (lump_c *)dir.pop_front()) { delete cur; } /* free the level names */ if (level_names) { for (int i = 0; i < num_level_names; i++) UtilFree((void *) level_names[i]); UtilFree(level_names); } } level_c::level_c() : flags(0), children(), soft_limit(0), hard_limit(0), v3_switch(0) { } level_c::~level_c() { for (lump_c *cur = (lump_c *)children.pop_front(); cur != NULL; cur = (lump_c *)children.pop_front()) { delete cur; } } lump_c::lump_c() : name(NULL), start(-1), length(0), flags(0), data(NULL), lev_info(NULL) { } lump_c::~lump_c() { delete lev_info; if (data) UtilFree((void*)data); if (name) UtilFree((void*)name); } /* ---------------------------------------------------------------- */ #define NUM_LEVEL_LUMPS 12 #define NUM_GL_LUMPS 5 static const char *level_lumps[NUM_LEVEL_LUMPS]= { "THINGS", "LINEDEFS", "SIDEDEFS", "VERTEXES", "SEGS", "SSECTORS", "NODES", "SECTORS", "REJECT", "BLOCKMAP", "BEHAVIOR", // <-- hexen support "SCRIPTS" // -JL- Lump with script sources }; static const char *gl_lumps[NUM_GL_LUMPS]= { "GL_VERT", "GL_SEGS", "GL_SSECT", "GL_NODES", "GL_PVS" // -JL- PVS (Potentially Visible Set) lump }; // // CheckMagic // static bool CheckMagic(const char type[4]) { if ((type[0] == 'I' || type[0] == 'P') && type[1] == 'W' && type[2] == 'A' && type[3] == 'D') { return true; } return false; } // // CheckLevelName // bool wad_c::CheckLevelName(const char *name) { for (int i = 0; i < num_level_names; i++) { if (strcmp(level_names[i], name) == 0) return true; } return false; } static bool HasGLPrefix(const char *name) { return (name[0] == 'G' && name[1] == 'L' && name[2] == '_'); } ///---bool wad_c::CheckLevelNameGL(const char *name) ///---{ ///--- if (name[0] != 'G' || name[1] != 'L' || name[2] != '_') ///--- return false; ///--- ///--- return CheckLevelName(name+3); ///---} // // CheckLevelLumpName // // Tests if the entry name is one of the level lumps. // static bool CheckLevelLumpName(const char *name) { for (int i = 0; i < NUM_LEVEL_LUMPS; i++) { if (strcmp(name, level_lumps[i]) == 0) return true; } return false; } // // CheckGLLumpName // // Tests if the entry name matches one of the GL lump names. // static bool CheckGLLumpName(const char *name) { for (int i = 0; i < NUM_GL_LUMPS; i++) { if (strcmp(name, gl_lumps[i]) == 0) return true; } return false; } // // NewLevel // // Create new level information // static level_c *NewLevel(int flags) // FIXME @@@@ { level_c *cur = new level_c(); cur->flags = flags; return cur; } // // NewLump // // Create new lump. 'name' must be allocated storage. // static lump_c *NewLump(const char *name) // FIXME @@@@ { lump_c *cur = new lump_c(); cur->name = name; return cur; } // // ReadHeader // // Returns true if successful, or FALSE if there was a problem (in // which case the error message as been setup). // bool wad_c::ReadHeader() { raw_wad_header_t header; size_t len = fread(&header, sizeof(header), 1, in_file); if (len != 1) { PrintWarn("Trouble reading wad header: %s\n", strerror(errno)); return false; } if (! CheckMagic(header.type)) { PrintWarn("This file is not a WAD file : bad magic\n"); return false; } kind = (header.type[0] == 'I') ? IWAD : PWAD; num_entries = UINT32(header.num_entries); dir_start = UINT32(header.dir_start); return true; } // // ReadDirEntry // void wad_c::ReadDirEntry() { raw_wad_entry_t entry; size_t len = fread(&entry, sizeof(entry), 1, in_file); if (len != 1) FatalError("Trouble reading wad directory"); lump_c *lump = NewLump(UtilStrNDup(entry.name, 8)); lump->start = UINT32(entry.start); lump->length = UINT32(entry.length); #if DEBUG_DIR PrintDebug("Read dir... %s\n", lump->name); #endif dir.push_back(lump); } // // Level name helper // void wad_c::AddLevelName(const char *name) { if ((num_level_names % LEVNAME_BUNCH) == 0) { level_names = (const char **) UtilRealloc((void *)level_names, (num_level_names + LEVNAME_BUNCH) * sizeof(const char *)); } level_names[num_level_names++] = UtilStrDup(name); } // // DetermineLevelNames // void wad_c::DetermineLevelNames() { for (lump_c *L = (lump_c*)dir.begin(); L != NULL; L = L->LumpNext()) { // check if the next four lumps after the current lump match the // level-lump or GL-lump names. int i; lump_c *N; int normal_count = 0; int gl_count = 0; for (i = 0, N = L->LumpNext(); (i < 4) && (N != NULL); i++, N = N->LumpNext()) { if (strcmp(N->name, level_lumps[i]) == 0) normal_count++; if (strcmp(N->name, gl_lumps[i]) == 0) gl_count++; } if (normal_count != 4 && gl_count != 4) continue; #if DEBUG_DIR PrintDebug("Found level name: %s\n", L->name); #endif // check for invalid name and duplicate levels if (normal_count == 4 && strlen(L->name) > 5) PrintWarn("Bad level '%s' in wad (name too long)\n", L->name); else if (CheckLevelName(L->name)) PrintWarn("Level name '%s' found twice in wad\n", L->name); else AddLevelName(L->name); } } // // ProcessDirEntry // void wad_c::ProcessDirEntry(lump_c *lump) { // --- LEVEL MARKERS --- if (CheckLevelName(lump->name)) { lump->lev_info = NewLevel(0); current_level = lump; #if DEBUG_DIR PrintDebug("Process level... %s\n", lump->name); #endif dir.push_back(lump); return; } // --- LEVEL LUMPS --- if (current_level) { if (HasGLPrefix(current_level->name) ? CheckGLLumpName(lump->name) : CheckLevelLumpName(lump->name)) { // check for duplicates if (FindLumpInLevel(lump->name)) { PrintWarn("Duplicate entry '%s' ignored in %s\n", lump->name, current_level->name); delete lump; return; } #if DEBUG_DIR PrintDebug(" |--- %s\n", lump->name); #endif // link it in current_level->lev_info->children.push_back(lump); return; } // non-level lump -- end previous level and fall through. current_level = NULL; } // --- ORDINARY LUMPS --- #if DEBUG_DIR PrintDebug("Process dir... %s\n", lump->name); #endif if (CheckLevelLumpName(lump->name)) PrintWarn("Level lump '%s' found outside any level\n", lump->name); else if (CheckGLLumpName(lump->name)) PrintWarn("GL lump '%s' found outside any level\n", lump->name); // link it in dir.push_back(lump); } // // ReadDirectory // void wad_c::ReadDirectory() { fseek(in_file, dir_start, SEEK_SET); for (int i = 0; i < num_entries; i++) { ReadDirEntry(); } DetermineLevelNames(); // finally, unlink all lumps and process each one in turn list_c temp(dir); dir.clear(); for (lump_c *cur = (lump_c *) temp.pop_front(); cur; cur = (lump_c *) temp.pop_front()) { ProcessDirEntry(cur); } } /* ---------------------------------------------------------------- */ // // CacheLump // void wad_c::CacheLump(lump_c *lump) { size_t len; #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 (current_level) PrintWarn("Trouble reading lump '%s' in %s\n", lump->name, current_level->name); else PrintWarn("Trouble reading lump '%s'\n", lump->name); } } // // FindLevel // bool wad_c::FindLevel(const char *map_name) { lump_c *L; for (L = (lump_c*)dir.begin(); L != NULL; L = L->LumpNext()) { if (! L->lev_info) continue; if (L->lev_info->flags & LEVEL_IS_GL) // @@@@ continue; if (UtilStrCaseCmp(L->name, map_name) == 0) break; } current_level = L; return (L != NULL); } // // FirstLevelName // const char *wad_c::FirstLevelName() { lump_c *L; for (L = (lump_c*)dir.begin(); L != NULL; L = L->LumpNext()) { if (L->lev_info) return L->name; } return NULL; } // // FindLumpInLevel // lump_c *wad_c::FindLumpInLevel(const char *name) { SYS_ASSERT(current_level); for (lump_c *L = (lump_c*)current_level->lev_info->children.begin(); L != NULL; L = L->LumpNext()) { if (strcmp(L->name, name) == 0) return L; } return NULL; // not found } // // wad_c::Load // wad_c *wad_c::Load(const char *filename) { wad_c *wad = new wad_c(); // open input wad file & read header wad->in_file = fopen(filename, "rb"); if (! wad->in_file) { PrintWarn("Cannot open WAD file %s : %s", filename, strerror(errno)); return NULL; } if (! wad->ReadHeader()) return NULL; PrintDebug("Opened %cWAD file : %s\n", (wad->kind == IWAD) ? 'I' : 'P', filename); PrintDebug("Reading %d dir entries at 0x%X\n", wad->num_entries, wad->dir_start); // read directory wad->ReadDirectory(); wad->current_level = NULL; return wad; } glbsp-2.24-source/nodeview/wad.h0000644000175000017500000000626110624752104016076 0ustar aaptedaapted//------------------------------------------------------------------------ // WAD : Wad file read/write functions. //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_WAD_H__ #define __NODEVIEW_WAD_H__ class lump_c; typedef enum { IWAD, PWAD } wad_kind_e; // wad header class wad_c { public: wad_c(); ~wad_c(); FILE *in_file; // kind of wad file (-1 if not opened yet) int kind; // number of entries in directory (original) int num_entries; // offset to start of directory int dir_start; // current directory entries list_c dir; // current level lump_c *current_level; // array of level names found const char ** level_names; int num_level_names; public: // open the input wad file and read the contents into memory. static wad_c *Load(const char *filename); bool CheckLevelName(const char *name); bool CheckLevelNameGL(const char *name); // find a particular level in the wad directory, and store the // reference in 'wad.current_level'. Returns false if not // found. bool FindLevel(const char *map_name); // name of first level in the wad. Returns NULL if there // are no levels at all. const char *FirstLevelName(); // find the level lump with the given name in the current level, and // return a reference to it. Returns NULL if no such lump exists. // Level lumps are always present in memory (i.e. never marked // copyable). lump_c *FindLumpInLevel(const char *name); void CacheLump(lump_c *lump); private: bool ReadHeader(); void ReadDirEntry(); void ReadDirectory(); void ProcessDirEntry(lump_c *lump); void AddLevelName(const char *name); void DetermineLevelNames(); }; // level information class level_c { public: level_c(); ~level_c(); // various flags int flags; // the child lump list list_c children; // information on overflow int soft_limit; int hard_limit; int v3_switch; }; /* this level information holds GL lumps */ #define LEVEL_IS_GL 0x0002 // directory entry class lump_c : public listnode_c { public: lump_c(); ~lump_c(); // name of lump const char *name; // offset/length of lump in wad int start; int length; // various flags int flags; // data of lump void *data; // level information, usually NULL level_c *lev_info; public: inline lump_c *LumpNext() { return (lump_c*) NodeNext(); } inline lump_c *LumpPrev() { return (lump_c*) NodePrev(); } }; /* ------ Global variables ------ */ extern wad_c *the_wad; extern wad_c *the_gwa; #endif /* __NODEVIEW_WAD_H__ */ glbsp-2.24-source/nodeview/util.h0000644000175000017500000000552410624750650016305 0ustar aaptedaapted//------------------------------------------------------------------------ // UTILITY : general purpose functions //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_UTIL_H__ #define __NODEVIEW_UTIL_H__ /* ----- useful macros ---------------------------- */ #define DIST_EPSILON (1.0 / 128.0) #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifndef MAX #define MAX(x,y) ((x) > (y) ? (x) : (y)) #endif #ifndef MIN #define MIN(x,y) ((x) < (y) ? (x) : (y)) #endif #ifndef ABS #define ABS(x) ((x) >= 0 ? (x) : -(x)) #endif #ifndef I_ROUND #define I_ROUND(x) int(((x) < 0) ? ((x) - 0.5f) : ((x) + 0.5f)) #endif /* ----- function prototypes ---------------------------- */ // allocate and clear some memory. guaranteed not to fail. void *UtilCalloc(int size); // re-allocate some memory. guaranteed not to fail. void *UtilRealloc(void *old, int size); // duplicate a string. char *UtilStrDup(const char *str); char *UtilStrNDup(const char *str, int size); // copy the string and make it uppercase char *UtilStrUpper(const char *name); // free some memory or a string. void UtilFree(void *data); // compare two strings case insensitively. int UtilStrCaseCmp(const char *A, const char *B); // round a positive value up to the nearest power of two. int UtilRoundPOW2(int x); // compute angle & distance from (0,0) to (dx,dy) angle_g UtilComputeAngle(double dx, double dy); #define UtilComputeDist(dx,dy) sqrt((dx) * (dx) + (dy) * (dy)) // compute the parallel and perpendicular distances from a partition // line to a point. // #define UtilParallelDist(part,x,y) \ (((x) * (part)->pdx + (y) * (part)->pdy + (part)->p_para) \ / (part)->p_length) #define UtilPerpDist(part,x,y) \ (((x) * (part)->pdy - (y) * (part)->pdx + (part)->p_perp) \ / (part)->p_length) // return the millisecond counter. Note: it WILL overflow. unsigned int UtilGetMillis(); // --- file utilities --- bool FileExists(const char *filename); bool HasExtension(const char *filename); bool CheckExtension(const char *filename, const char *ext); const char *ReplaceExtension(const char *filename, const char *ext); const char *FileBaseName(const char *filename); #endif /* __NODEVIEW_UTIL_H__ */ glbsp-2.24-source/nodeview/menu.cc0000644000175000017500000001055510624752011016423 0ustar aaptedaapted//------------------------------------------------------------------------ // MENU : Menu handling //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "defs.h" static bool menu_want_to_quit; #if 0 static void menu_quit_CB(Fl_Widget *w, void *data) { menu_want_to_quit = true; } #endif #ifndef MACOSX static void menu_do_exit(Fl_Widget *w, void * data) { guix_win->want_quit = true; } #endif //------------------------------------------------------------------------ static void menu_do_prefs(Fl_Widget *w, void * data) { } //------------------------------------------------------------------------ static const char *about_Info = "By Andrew Apted (C) 2004-2007"; static void menu_do_about(Fl_Widget *w, void * data) { #if 0 menu_want_to_quit = false; Fl_Window *ab_win = new Fl_Window(600, 340, "About " PROG_NAME); ab_win->end(); // non-resizable ab_win->size_range(ab_win->w(), ab_win->h(), ab_win->w(), ab_win->h()); ab_win->position(guix_prefs.manual_x, guix_prefs.manual_y); ab_win->callback((Fl_Callback *) menu_quit_CB); // add the about image Fl_Group *group = new Fl_Group(0, 0, 230, ab_win->h()); group->box(FL_FLAT_BOX); group->color(FL_BLACK, FL_BLACK); ab_win->add(group); Fl_Box *box = new Fl_Box(20, 90, ABOUT_IMG_W+2, ABOUT_IMG_H+2); box->image(about_image); group->add(box); // nice big logo text box = new Fl_Box(240, 5, 350, 50, "glBSPX " GLBSP_VER); box->labelsize(24); ab_win->add(box); // about text box = new Fl_Box(240, 60, 350, 270, about_Info); box->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_TOP); ab_win->add(box); // finally add an "OK" button Fl_Button *button = new Fl_Button(ab_win->w()-10-60, ab_win->h()-10-30, 60, 30, "OK"); button->callback((Fl_Callback *) menu_quit_CB); ab_win->add(button); ab_win->set_modal(); ab_win->show(); // capture initial size WindowSmallDelay(); int init_x = ab_win->x(); int init_y = ab_win->y(); // run the GUI until the user closes while (! menu_want_to_quit) Fl::wait(); // check if the user moved/resized the window if (ab_win->x() != init_x || ab_win->y() != init_y) { guix_prefs.manual_x = ab_win->x(); guix_prefs.manual_y = ab_win->y(); } // this deletes all the child widgets too... delete ab_win; #endif } //------------------------------------------------------------------------ static void menu_do_manual(Fl_Widget *w, void * data) { } //------------------------------------------------------------------------ static void menu_do_license(Fl_Widget *w, void * data) { } //------------------------------------------------------------------------ static void menu_do_save_log(Fl_Widget *w, void * data) { } //------------------------------------------------------------------------ #undef FCAL #define FCAL (Fl_Callback *) static Fl_Menu_Item menu_items[] = { { "&File", 0, 0, 0, FL_SUBMENU }, { "&Preferences...", 0, FCAL menu_do_prefs }, { "&Save Log...", 0, FCAL menu_do_save_log }, #ifndef MACOSX { "E&xit", FL_ALT + 'q', FCAL menu_do_exit }, #endif { 0 }, { "&Help", 0, 0, 0, FL_SUBMENU }, { "&About...", 0, FCAL menu_do_about }, { "&License...", 0, FCAL menu_do_license }, { "&Manual...", FL_F+1, FCAL menu_do_manual }, { 0 }, { 0 } }; // // MenuCreate // #ifdef MACOSX Fl_Sys_Menu_Bar * MenuCreate(int x, int y, int w, int h) { Fl_Sys_Menu_Bar *bar = new Fl_Sys_Menu_Bar(x, y, w, h); bar->menu(menu_items); return bar; } #else Fl_Menu_Bar * MenuCreate(int x, int y, int w, int h) { Fl_Menu_Bar *bar = new Fl_Menu_Bar(x, y, w, h); bar->menu(menu_items); return bar; } #endif glbsp-2.24-source/nodeview/dialog.cc0000644000175000017500000002205510624751547016731 0ustar aaptedaapted//------------------------------------------------------------------------ // DIALOG : Pop-up dialog boxes //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "defs.h" static Fl_Window *cur_diag; static int cur_diag_result; static bool cur_diag_done; static const char *cur_diag_guess_name; static int pref_dialog_x = -1; static int pref_dialog_y = -1; static void dialog_closed_CB(Fl_Widget *w, void *data) { cur_diag_result = -1; cur_diag_done = true; } static void dialog_left_button_CB(Fl_Widget *w, void *data) { cur_diag_result = 0; cur_diag_done = true; } static void dialog_middle_button_CB(Fl_Widget *w, void *data) { cur_diag_result = 1; cur_diag_done = true; } static void dialog_right_button_CB(Fl_Widget *w, void *data) { cur_diag_result = 2; cur_diag_done = true; } static void dialog_file_browse_CB(Fl_Widget *w, void *data) { Fl_Input *inp_box = (Fl_Input *) data; const char *new_name; new_name = fl_file_chooser("Select the log file", "*.log", inp_box->value()); // cancelled ? if (! new_name) return; inp_box->value(new_name); } static void dialog_file_guess_CB(Fl_Widget *w, void *data) { Fl_Input *inp_box = (Fl_Input *) data; if (cur_diag_guess_name) { inp_box->value(cur_diag_guess_name); } } //------------------------------------------------------------------------ static void DialogRun() { cur_diag->set_modal(); cur_diag->show(); // read initial pos (same logic as in Guix_MainWin) WindowSmallDelay(); int init_x = cur_diag->x(); int init_y = cur_diag->y(); // run the GUI and let user make their choice while (! cur_diag_done) { Fl::wait(); } // check if the user moved/resized the window if (cur_diag->x() != init_x || cur_diag->y() != init_y) { pref_dialog_x = cur_diag->x(); pref_dialog_y = cur_diag->y(); } } // // DialogShowAndGetChoice // // The `pic' parameter is the picture to show on the left, or NULL for // none. The message can contain newlines. The right/middle/left // parameters allow up to three buttons. // // Returns the button number pressed (0 for right, 1 for middle, 2 for // left) or -1 if escape was pressed or window manually closed. // int DialogShowAndGetChoice(const char *title, Fl_Pixmap *pic, const char *message, const char *left, // = "OK", const char *middle, // = NULL, const char *right) // = NULL) { cur_diag_result = -1; cur_diag_done = false; int but_width = right ? (120*3) : middle ? (120*2) : (120*1); // determine required size int width = 120 * 3; int height; // set current font for fl_measure() fl_font(FL_HELVETICA, FL_NORMAL_SIZE); fl_measure(message, width, height); if (width < but_width) width = but_width; if (height < 16) height = 16; width += 60 + 20 + 16; // 16 extra, just in case height += 10 + 40 + 16; // // create window cur_diag = new Fl_Window(0, 0, width, height, title); cur_diag->end(); cur_diag->size_range(width, height, width, height); cur_diag->callback((Fl_Callback *) dialog_closed_CB); if (pref_dialog_x >= 0) cur_diag->position(pref_dialog_x, pref_dialog_y); // set the resizable Fl_Box *box = new Fl_Box(60, 0, width - 3*120, height); cur_diag->add(box); cur_diag->resizable(box); // create the image, if any if (pic) { box = new Fl_Box(5, 10, 50, 50); pic->label(box); cur_diag->add(box); } // create the message area box = new Fl_Box(60, 10, width-60 - 20, height-10 - 40, message); box->align(FL_ALIGN_LEFT | FL_ALIGN_TOP | FL_ALIGN_INSIDE | FL_ALIGN_WRAP); cur_diag->add(box); // create buttons Fl_Button *button; int CX = width - 120; int CY = height - 40; if (right) { button = new Fl_Return_Button(CX, CY, 104, 30, right); button->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); button->callback((Fl_Callback *) dialog_right_button_CB); cur_diag->add(button); CX -= 120; } if (middle) { button = new Fl_Button(CX, CY, 104, 30, middle); button->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); button->callback((Fl_Callback *) dialog_middle_button_CB); cur_diag->add(button); CX -= 120; } if (left) { button = new Fl_Button(CX, CY, 104, 30, left); button->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); button->callback((Fl_Callback *) dialog_left_button_CB); cur_diag->add(button); CX -= 120; } // show time ! DialogRun(); // delete window (automatically deletes child widgets) delete cur_diag; cur_diag = NULL; return cur_diag_result; } // // DialogQueryFilename // // Shows the current filename (name_ptr) in an input box, and provides // a browse button to choose a new filename, and an optional button to // guess the new filename (if `guess_name' is NULL, then the button is // disabled). // // This routine does NOT ensure that the filename is valid (or any // other requirement, e.g. has a certain extension). // // Returns 0 if "OK" was pressed, 1 if "Cancel" was pressed, or -1 if // escape was pressed or the window was manually closed. // int DialogQueryFilename(const char *message, const char ** name_ptr, const char *guess_name) { cur_diag_result = -1; cur_diag_done = false; cur_diag_guess_name = guess_name; // determine required size int width = 400; int height; // set current font for fl_measure() fl_font(FL_HELVETICA, FL_NORMAL_SIZE); fl_measure(message, width, height); if (width < 400) width = 400; if (height < 16) height = 16; width += 60 + 20 + 16; // 16 extra, just in case height += 60 + 50 + 16; // // create window cur_diag = new Fl_Window(0, 0, width, height, PROG_NAME " Query"); cur_diag->end(); cur_diag->size_range(width, height, width, height); cur_diag->callback((Fl_Callback *) dialog_closed_CB); if (pref_dialog_x >= 0) cur_diag->position(pref_dialog_x, pref_dialog_y); // set the resizable Fl_Box *box = new Fl_Box(0, height-1, width, 1); cur_diag->add(box); cur_diag->resizable(box); // create the message area box = new Fl_Box(14, 10, width-20 - 20, height-10 - 100, message); box->align(FL_ALIGN_LEFT | FL_ALIGN_TOP | FL_ALIGN_INSIDE | FL_ALIGN_WRAP); cur_diag->add(box); // create buttons int CX = width - 120; int CY = height - 50; Fl_Button *b_ok; Fl_Button *b_cancel; b_cancel = new Fl_Button(CX, CY, 104, 30, "Cancel"); b_cancel->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); b_cancel->callback((Fl_Callback *) dialog_middle_button_CB); cur_diag->add(b_cancel); CX -= 120; b_ok = new Fl_Return_Button(CX, CY, 104, 30, "OK"); b_ok->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); b_ok->callback((Fl_Callback *) dialog_left_button_CB); cur_diag->add(b_ok); // create input box Fl_Input *inp_box; CX = width - 120; CY = height - 100; inp_box = new Fl_Input(20, CY, CX - 20 - 90, 26); inp_box->value(*name_ptr); cur_diag->add(inp_box); // create the browse and guess button Fl_Button *b_browse; Fl_Button *b_guess; b_guess = new Fl_Button(CX, CY, 70, 26, "Guess"); b_guess->align(FL_ALIGN_INSIDE); b_guess->callback((Fl_Callback *) dialog_file_guess_CB, inp_box); cur_diag->add(b_guess); CX -= 85; b_browse = new Fl_Button(CX, CY, 80, b_guess->h(), "Browse"); b_browse->align(FL_ALIGN_INSIDE); b_browse->callback((Fl_Callback *) dialog_file_browse_CB, inp_box); cur_diag->add(b_browse); // show time ! DialogRun(); if (cur_diag_result == 0) { UtilFree((void *) *name_ptr); *name_ptr = UtilStrDup(inp_box->value()); } // delete window (automatically deletes child widgets) delete cur_diag; cur_diag = NULL; return cur_diag_result; } // // GUI_FatalError // // Terminates the program reporting an error. // void GUI_FatalError(const char *str, ...) { char buffer[2048]; char main_err[2048]; char *m_ptr; // create message va_list args; va_start(args, str); vsprintf(main_err, str, args); va_end(args); // remove leading and trailing whitespace int len = strlen(main_err); for (; len > 0 && isspace(main_err[len-1]); len--) { main_err[len-1] = 0; } for (m_ptr = main_err; isspace(*m_ptr); m_ptr++) { /* nothing else needed */ } sprintf(buffer, "The following unexpected error occurred:\n" "\n" " %s\n" "\n" PROG_NAME " will now shut down.", m_ptr); DialogShowAndGetChoice(PROG_NAME " Fatal Error", 0, buffer); // Q/ save cookies ? // A/ no, we save them before each build begins. exit(5); } glbsp-2.24-source/nodeview/window.cc0000644000175000017500000000735410625036015016771 0ustar aaptedaapted//------------------------------------------------------------------------ // WINDOW : Main application window //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "defs.h" #ifndef WIN32 #include #endif Guix_MainWin *guix_win; #define WINDOW_MIN_W 480 #define WINDOW_MIN_H 440 #define WINDOW_NORM_W 620 #define WINDOW_NORM_H 460 static void main_win_close_CB(Fl_Widget *w, void *data) { if (guix_win) guix_win->want_quit = true; } // // WindowSmallDelay // // This routine is meant to delay a short time (e.g. 1/5th of a // second) to allow the window manager to move our windows around. // // Hopefully such nonsense doesn't happen under Win32. // void WindowSmallDelay(void) { #ifndef WIN32 Fl::wait(0); usleep(100 * 1000); Fl::wait(0); usleep(100 * 1000); #endif Fl::wait(0); } // // MainWin Constructor // Guix_MainWin::Guix_MainWin(const char *title) : Fl_Double_Window(WINDOW_NORM_W, WINDOW_NORM_H, title) { // turn off auto-add-widget mode end(); size_range(WINDOW_MIN_W, WINDOW_MIN_H); // Set initial position. // // Note: this may not work properly. It seems that when my window // manager adds the titlebar/border, it moves the actual window // down and slightly to the right, causing subsequent invokations // to keep going lower and lower. /// position(guix_prefs.win_x, guix_prefs.win_y); callback((Fl_Callback *) main_win_close_CB); // set a nice darkish gray for the space between main boxes color(MAIN_BG_COLOR, MAIN_BG_COLOR); want_quit = false; // create contents int hw = (w() - 8*2 - 4) / 2; int mh = 28; #ifdef MACOSX mh = 1; #endif menu_bar = MenuCreate(0, 0, w()-200, 28); add(menu_bar); grid = new W_Grid(0, mh, w()-200, h()-mh); add(grid); resizable(grid); info = new W_Info(w()-200, mh*0, 200, h()-mh*0); add(info); #if 0 build_mode = new Guix_BuildMode(8, 4+mh, hw, 176); add(build_mode); misc_opts = new Guix_MiscOptions(8+hw+4, 4+mh, hw, 136); add(misc_opts); factor = new Guix_FactorBox(8+hw+4, 140+mh, hw, 40); add(factor); files = new Guix_FileBox(8, 184+mh, w()-8*2, 86); add(files); builder = new Guix_BuildButton(8, 274+10+mh, hw, 60); add(builder); progress = new Guix_ProgressBox(8+hw+4, 274+mh, hw, 74); add(progress); text_box = new Guix_TextBox(0, 352+mh, w(), h() - 352 - mh); add(text_box); resizable(text_box); #endif // show window (pass some dummy arguments) int argc = 1; char *argv[] = { "nodeview", NULL }; show(argc, argv); // read initial pos, giving 1/5th of a second for the WM to adjust // our window's position (naughty WM...) WindowSmallDelay(); init_x = x(); init_y = y(); init_w = w(); init_h = h(); } // // MainWin Destructor // Guix_MainWin::~Guix_MainWin() { WritePrefs(); } void Guix_MainWin::WritePrefs() { // check if moved or resized if (x() != init_x || y() != init_y) { /// guix_prefs.win_x = x(); /// guix_prefs.win_y = y(); } if (w() != init_w || h() != init_h) { /// guix_prefs.win_w = w(); /// guix_prefs.win_h = h(); } } glbsp-2.24-source/nodeview/level.cc0000644000175000017500000004304010647567712016602 0ustar aaptedaapted//------------------------------------------------------------------------ // LEVEL : Level structure read/write functions. //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "defs.h" #define DEBUG_LOAD 0 #define DEBUG_BSP 0 // per-level variables bool lev_doing_hexen; #define LEVELARRAY(TYPE, BASEVAR, NAMESTR) \ container_tp BASEVAR(NAMESTR); LEVELARRAY(vertex_c, lev_vertices, "vertex") LEVELARRAY(vertex_c, lev_gl_verts, "gl_vert") LEVELARRAY(linedef_c, lev_linedefs, "linedef") LEVELARRAY(sidedef_c, lev_sidedefs, "sidedef") LEVELARRAY(sector_c, lev_sectors, "sector") LEVELARRAY(thing_c, lev_things, "thing") LEVELARRAY(seg_c, lev_segs, "seg") LEVELARRAY(subsec_c, lev_subsecs, "subsector") LEVELARRAY(node_c, lev_nodes, "node") /* ----- reading routines ------------------------------ */ static const uint8_g *lev_v2_magic = (uint8_g *)"gNd2"; static const uint8_g *lev_v3_magic = (uint8_g *)"gNd3"; // forward decls void GetLinedefsHexen(wad_c *base); void GetThingsHexen(wad_c *base); vertex_c::vertex_c(int _idx, const raw_vertex_t *raw) { index = _idx; x = (double) SINT16(raw->x); y = (double) SINT16(raw->y); } vertex_c::vertex_c(int _idx, const raw_v2_vertex_t *raw) { index = _idx; x = (double) SINT32(raw->x) / 65536.0; y = (double) SINT32(raw->y) / 65536.0; } vertex_c::~vertex_c() { } // // GetVertices // void GetVertices(wad_c *base) { lump_c *lump = base->FindLumpInLevel("VERTEXES"); int count = -1; if (lump) { base->CacheLump(lump); count = lump->length / sizeof(raw_vertex_t); } # if DEBUG_LOAD PrintDebug("GetVertices: num = %d\n", count); # endif if (!lump || count == 0) FatalError("Couldn't find any Vertices"); lev_vertices.Allocate(count); raw_vertex_t *raw = (raw_vertex_t *) lump->data; for (int i = 0; i < count; i++, raw++) { lev_vertices.Set(i, new vertex_c(i, raw)); } } // // GetV2Verts // void GetV2Verts(const uint8_g *data, int length) { int count = length / sizeof(raw_v2_vertex_t); lev_gl_verts.Allocate(count); raw_v2_vertex_t *raw = (raw_v2_vertex_t *) data; for (int i = 0; i < count; i++, raw++) { lev_gl_verts.Set(i, new vertex_c(i, raw)); } } // // GetGLVerts // void GetGLVerts(wad_c *base) { lump_c *lump = base->FindLumpInLevel("GL_VERT"); # if DEBUG_LOAD PrintDebug("GetVertices: num = %d\n", count); # endif if (!lump) FatalError("Couldn't find any GL Vertices"); base->CacheLump(lump); if (lump->length >= 4 && memcmp(lump->data, lev_v2_magic, 4) == 0) { GetV2Verts((uint8_g *)lump->data + 4, lump->length - 4); return; } int count = lump->length / sizeof(raw_vertex_t); lev_gl_verts.Allocate(count); raw_vertex_t *raw = (raw_vertex_t *) lump->data; for (int i = 0; i < count; i++, raw++) { lev_gl_verts.Set(i, new vertex_c(i, raw)); } } sector_c::sector_c(int _idx, const raw_sector_t *raw) { index = _idx; floor_h = SINT16(raw->floor_h); ceil_h = SINT16(raw->ceil_h); memcpy(floor_tex, raw->floor_tex, sizeof(floor_tex)); memcpy(ceil_tex, raw->ceil_tex, sizeof(ceil_tex)); light = UINT16(raw->light); special = UINT16(raw->special); tag = SINT16(raw->tag); } sector_c::~sector_c() { } // // GetSectors // void GetSectors(wad_c *base) { int count = -1; lump_c *lump = base->FindLumpInLevel("SECTORS"); if (lump) { base->CacheLump(lump); count = lump->length / sizeof(raw_sector_t); } if (!lump || count == 0) FatalError("Couldn't find any Sectors"); # if DEBUG_LOAD PrintDebug("GetSectors: num = %d\n", count); # endif lev_sectors.Allocate(count); raw_sector_t *raw = (raw_sector_t *) lump->data; for (int i = 0; i < count; i++, raw++) { lev_sectors.Set(i, new sector_c(i, raw)); } } thing_c::thing_c(int _idx, const raw_thing_t *raw) { index = _idx; x = SINT16(raw->x); y = SINT16(raw->y); type = UINT16(raw->type); options = UINT16(raw->options); } thing_c::thing_c(int _idx, const raw_hexen_thing_t *raw) { index = _idx; x = SINT16(raw->x); y = SINT16(raw->y); type = UINT16(raw->type); options = UINT16(raw->options); } thing_c::~thing_c() { } // // GetThings // void GetThings(wad_c *base) { if (lev_doing_hexen) { GetThingsHexen(base); return; } int count = -1; lump_c *lump = base->FindLumpInLevel("THINGS"); if (lump) { base->CacheLump(lump); count = lump->length / sizeof(raw_thing_t); } if (!lump || count == 0) { // Note: no error if no things exist, even though technically a map // will be unplayable without the player starts. PrintWarn("Couldn't find any Things"); return; } # if DEBUG_LOAD PrintDebug("GetThings: num = %d\n", count); # endif lev_things.Allocate(count); raw_thing_t *raw = (raw_thing_t *) lump->data; for (int i = 0; i < count; i++, raw++) { lev_things.Set(i, new thing_c(i, raw)); } } // // GetThingsHexen // void GetThingsHexen(wad_c *base) { int count = -1; lump_c *lump = base->FindLumpInLevel("THINGS"); if (lump) { base->CacheLump(lump); count = lump->length / sizeof(raw_hexen_thing_t); } if (!lump || count == 0) { // Note: no error if no things exist, even though technically a map // will be unplayable without the player starts. PrintWarn("Couldn't find any Things"); return; } # if DEBUG_LOAD PrintDebug("GetThingsHexen: num = %d\n", count); # endif lev_things.Allocate(count); raw_hexen_thing_t *raw = (raw_hexen_thing_t *) lump->data; for (int i = 0; i < count; i++, raw++) { lev_things.Set(i, new thing_c(i, raw)); } } sidedef_c::sidedef_c(int _idx, const raw_sidedef_t *raw) { index = _idx; sector = (SINT16(raw->sector) == -1) ? NULL : lev_sectors.Get(UINT16(raw->sector)); x_offset = SINT16(raw->x_offset); y_offset = SINT16(raw->y_offset); memcpy(upper_tex, raw->upper_tex, sizeof(upper_tex)); memcpy(lower_tex, raw->lower_tex, sizeof(lower_tex)); memcpy(mid_tex, raw->mid_tex, sizeof(mid_tex)); } sidedef_c::~sidedef_c() { } // // GetSidedefs // void GetSidedefs(wad_c *base) { int count = -1; lump_c *lump = base->FindLumpInLevel("SIDEDEFS"); if (lump) { base->CacheLump(lump); count = lump->length / sizeof(raw_sidedef_t); } if (!lump || count == 0) FatalError("Couldn't find any Sidedefs"); # if DEBUG_LOAD PrintDebug("GetSidedefs: num = %d\n", count); # endif lev_sidedefs.Allocate(count); raw_sidedef_t *raw = (raw_sidedef_t *) lump->data; for (int i = 0; i < count; i++, raw++) { lev_sidedefs.Set(i, new sidedef_c(i, raw)); } } static sidedef_c *SafeLookupSidedef(uint16_g num) { if (num == 0xFFFF) return NULL; if ((int)num >= lev_sidedefs.num && (sint16_g)(num) < 0) return NULL; return lev_sidedefs.Get(num); } linedef_c::linedef_c(int _idx, const raw_linedef_t *raw) { index = _idx; start = lev_vertices.Get(UINT16(raw->start)); end = lev_vertices.Get(UINT16(raw->end)); /* check for zero-length line */ zero_len = (fabs(start->x - end->x) < DIST_EPSILON) && (fabs(start->y - end->y) < DIST_EPSILON); flags = UINT16(raw->flags); type = UINT16(raw->type); tag = SINT16(raw->tag); two_sided = (flags & LINEFLAG_TWO_SIDED) ? true : false; right = SafeLookupSidedef(UINT16(raw->sidedef1)); left = SafeLookupSidedef(UINT16(raw->sidedef2)); } linedef_c::linedef_c(int _idx, const raw_hexen_linedef_t *raw) { index = _idx; start = lev_vertices.Get(UINT16(raw->start)); end = lev_vertices.Get(UINT16(raw->end)); // check for zero-length line zero_len = (fabs(start->x - end->x) < DIST_EPSILON) && (fabs(start->y - end->y) < DIST_EPSILON); flags = UINT16(raw->flags); type = UINT8(raw->type); tag = 0; /* read specials */ for (int j = 0; j < 5; j++) specials[j] = UINT8(raw->specials[j]); // -JL- Added missing twosided flag handling that caused a broken reject two_sided = (flags & LINEFLAG_TWO_SIDED) ? true : false; right = SafeLookupSidedef(UINT16(raw->sidedef1)); left = SafeLookupSidedef(UINT16(raw->sidedef2)); } linedef_c::~linedef_c() { } // // GetLinedefs // void GetLinedefs(wad_c *base) { if (lev_doing_hexen) { GetLinedefsHexen(base); return; } int count = -1; lump_c *lump = base->FindLumpInLevel("LINEDEFS"); if (lump) { base->CacheLump(lump); count = lump->length / sizeof(raw_linedef_t); } if (!lump || count == 0) FatalError("Couldn't find any Linedefs"); # if DEBUG_LOAD PrintDebug("GetLinedefs: num = %d\n", count); # endif lev_linedefs.Allocate(count); raw_linedef_t *raw = (raw_linedef_t *) lump->data; for (int i = 0; i < count; i++, raw++) { lev_linedefs.Set(i, new linedef_c(i, raw)); } } // // GetLinedefsHexen // void GetLinedefsHexen(wad_c *base) { int count = -1; lump_c *lump = base->FindLumpInLevel("LINEDEFS"); if (lump) { base->CacheLump(lump); count = lump->length / sizeof(raw_hexen_linedef_t); } if (!lump || count == 0) FatalError("Couldn't find any Linedefs"); # if DEBUG_LOAD PrintDebug("GetLinedefsHexen: num = %d\n", count); # endif lev_linedefs.Allocate(count); raw_hexen_linedef_t *raw = (raw_hexen_linedef_t *) lump->data; for (int i = 0; i < count; i++, raw++) { lev_linedefs.Set(i, new linedef_c(i, raw)); } } static vertex_c *FindVertex16(uint16_g index) { if (index & 0x8000) return lev_gl_verts.Get(index & 0x7FFF); return lev_vertices.Get(index); } static vertex_c *FindVertex32(int index) { if (index & IS_GL_VERTEX) return lev_gl_verts.Get(index & ~IS_GL_VERTEX); return lev_vertices.Get(index); } seg_c::seg_c(int _idx, const raw_gl_seg_t *raw) { index = _idx; next = NULL; /// fprintf(stderr, "SEG %d V %d..%d line %d side %d\n", /// index, UINT16(raw->start), UINT16(raw->end), SINT16(raw->linedef), SINT16(raw->side)); start = FindVertex16(UINT16(raw->start)); end = FindVertex16(UINT16(raw->end)); linedef = (SINT16(raw->linedef) == -1) ? NULL : lev_linedefs.Get(UINT16(raw->linedef)); side = UINT16(raw->side); sidedef_c *sss = NULL; if (linedef) sss = side ? linedef->left : linedef->right; sector = sss ? sss->sector : NULL; // partner is currently ignored precompute_data(); } seg_c::seg_c(int _idx, const raw_v3_seg_t *raw) { index = _idx; next = NULL; start = FindVertex32(UINT32(raw->start)); end = FindVertex32(UINT32(raw->end)); linedef = (SINT16(raw->linedef) == -1) ? NULL : lev_linedefs.Get(UINT16(raw->linedef)); side = UINT16(raw->flags) & V3SEG_F_LEFT; sidedef_c *sss = NULL; if (linedef) sss = side ? linedef->left : linedef->right; sector = sss ? sss->sector : NULL; // partner is currently ignored precompute_data(); } seg_c::~seg_c() { } void seg_c::precompute_data() { psx = start->x; psy = start->y; pex = end->x; pey = end->y; pdx = pex - psx; pdy = pey - psy; p_length = UtilComputeDist(pdx, pdy); p_angle = UtilComputeAngle(pdx, pdy); /// fprintf(stderr, "| (%1.0f,%1.0f)->(%1.0f,%1.0f) Delta (%1.6f, %1.6f)\n", /// psx, psy, pex, pey, pdx, pdy); if (p_length <= 0) PrintWarn("Seg %d has zero p_length.\n", index); p_perp = psy * pdx - psx * pdy; p_para = -psx * pdx - psy * pdy; } // // GetV3Segs // void GetV3Segs(const uint8_g *data, int length) { int count = length / sizeof(raw_v3_seg_t); lev_segs.Allocate(count); raw_v3_seg_t *raw = (raw_v3_seg_t *) data; for (int i = 0; i < count; i++, raw++) { lev_segs.Set(i, new seg_c(i, raw)); } } // // GetGLSegs // void GetGLSegs(wad_c *base) { lump_c *lump = base->FindLumpInLevel("GL_SEGS"); # if DEBUG_LOAD PrintDebug("GetVertices: num = %d\n", count); # endif if (!lump) FatalError("Couldn't find any GL Segs"); base->CacheLump(lump); if (lump->length >= 4 && memcmp(lump->data, lev_v3_magic, 4) == 0) { GetV3Segs((uint8_g *)lump->data + 4, lump->length - 4); return; } int count = lump->length / sizeof(raw_gl_seg_t); lev_segs.Allocate(count); raw_gl_seg_t *raw = (raw_gl_seg_t *) lump->data; for (int i = 0; i < count; i++, raw++) { lev_segs.Set(i, new seg_c(i, raw)); } } subsec_c::subsec_c(int _idx, const raw_subsec_t *raw) { index = _idx; seg_count = UINT16(raw->num); int first = UINT16(raw->first); build_seg_list(first, seg_count); } subsec_c::subsec_c(int _idx, const raw_v3_subsec_t *raw) { index = _idx; seg_count = UINT32(raw->num); int first = UINT32(raw->first); build_seg_list(first, seg_count); } subsec_c::~subsec_c() { } void subsec_c::append_seg(seg_c *cur) { if (! cur) InternalError("Missing seg for subsector !\n"); mid_x += (cur->start->x + cur->end->x) / 2.0; mid_y += (cur->start->y + cur->end->y) / 2.0; // add it to the tail if (! seg_list) { seg_list = cur; return; } seg_c *tail = seg_list; while (tail->next) tail = tail->next; tail->next = cur; } void subsec_c::build_seg_list(int first, int count) { seg_list = NULL; mid_x = 0; mid_y = 0; for (; count > 0; first++, count--) { seg_c *seg = lev_segs.Get(first); append_seg(seg); } mid_x /= count; mid_y /= count; } // // GetV3Subsecs // void GetV3Subsecs(const uint8_g *data, int length) { int count = length / sizeof(raw_v3_subsec_t); lev_subsecs.Allocate(count); raw_v3_subsec_t *raw = (raw_v3_subsec_t *) data; for (int i = 0; i < count; i++, raw++) { lev_subsecs.Set(i, new subsec_c(i, raw)); } } // // GetGLSubsecs // void GetGLSubsecs(wad_c *base) { lump_c *lump = base->FindLumpInLevel("GL_SSECT"); # if DEBUG_LOAD PrintDebug("GetVertices: num = %d\n", count); # endif if (!lump) FatalError("Couldn't find any GL Subsectors"); base->CacheLump(lump); if (lump->length >= 4 && memcmp(lump->data, lev_v3_magic, 4) == 0) { GetV3Subsecs((uint8_g *)lump->data + 4, lump->length - 4); return; } int count = lump->length / sizeof(raw_subsec_t); lev_subsecs.Allocate(count); raw_subsec_t *raw = (raw_subsec_t *) lump->data; for (int i = 0; i < count; i++, raw++) { lev_subsecs.Set(i, new subsec_c(i, raw)); } } void bbox_t::from_raw(const raw_bbox_t *raw) { minx = SINT16(raw->minx); miny = SINT16(raw->miny); maxx = SINT16(raw->maxx); maxy = SINT16(raw->maxy); } node_c::node_c(int _idx, const raw_node_t *raw) { index = _idx; x = SINT16(raw->x); y = SINT16(raw->y); dx = SINT16(raw->dx); dy = SINT16(raw->dy); r.bounds.from_raw(&raw->b1); l.bounds.from_raw(&raw->b2); r.node = l.node = NULL; r.subsec = l.subsec = NULL; int r_idx = UINT16(raw->right); int l_idx = UINT16(raw->left); if (r_idx & 0x8000) r.subsec = lev_subsecs.Get(r_idx & 0x7FFF); else r.node = lev_nodes.Get(r_idx); if (l_idx & 0x8000) l.subsec = lev_subsecs.Get(l_idx & 0x7FFF); else l.node = lev_nodes.Get(l_idx); } node_c::~node_c() { } // // GetGLNodes // void GetGLNodes(wad_c *base) { int count = -1; lump_c *lump = base->FindLumpInLevel("GL_NODES"); if (lump) { base->CacheLump(lump); count = lump->length / sizeof(raw_node_t); } if (!lump || count < 1) return; # if DEBUG_LOAD PrintDebug("GetStaleNodes: num = %d\n", count); # endif lev_nodes.Allocate(count); raw_node_t *raw = (raw_node_t *) lump->data; for (int i = 0; i < count; i++, raw++) { lev_nodes.Set(i, new node_c(i, raw)); } } /* ----- whole-level routines --------------------------- */ // // LoadLevel // void LoadLevel(const char *level_name) { // ---- Normal stuff ---- if (! the_wad->FindLevel(level_name)) FatalError("Unable to find level: %s\n", level_name); // -JL- Identify Hexen mode by presence of BEHAVIOR lump lev_doing_hexen = (the_wad->FindLumpInLevel("BEHAVIOR") != NULL); GetVertices(the_wad); GetSectors(the_wad); GetSidedefs(the_wad); GetLinedefs(the_wad); GetThings(the_wad); // ---- GL stuff ---- char gl_name[16]; sprintf(gl_name, "GL_%s", the_wad->current_level->name); wad_c *gl_wad = the_wad; if (! gl_wad->FindLevel(gl_name)) { gl_wad = the_gwa; if (! gl_wad || ! gl_wad->FindLevel(gl_name)) FatalError("Unable to find GL info (%s lump)\n", gl_name); } GetGLVerts(gl_wad); GetGLSegs(gl_wad); GetGLSubsecs(gl_wad); GetGLNodes(gl_wad); /// PrintMsg("Loaded %d vertices, %d sectors, %d sides, %d lines, %d things\n", /// num_vertices, num_sectors, num_sidedefs, num_linedefs, num_things); } // // FreeLevel // void FreeLevel(void) { lev_vertices.FreeAll(); lev_gl_verts.FreeAll(); lev_linedefs.FreeAll(); lev_sidedefs.FreeAll(); lev_sectors.FreeAll(); lev_things.FreeAll(); lev_segs.FreeAll(); lev_subsecs.FreeAll(); lev_nodes.FreeAll(); } // // LevelGetBounds // void LevelGetBounds(double *lx, double *ly, double *hx, double *hy) { node_c *root = lev_nodes.Get(lev_nodes.num - 1); *lx = MIN(root->l.bounds.minx, root->r.bounds.minx); *ly = MIN(root->l.bounds.miny, root->r.bounds.miny); *hx = MAX(root->l.bounds.maxx, root->r.bounds.maxx); *hy = MAX(root->l.bounds.maxy, root->r.bounds.maxy); } glbsp-2.24-source/nodeview/defs.h0000644000175000017500000000431710624315365016250 0ustar aaptedaapted//------------------------------------------------------------------------ // DEFINITIONS //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_DEFS_H__ #define __NODEVIEW_DEFS_H__ #define PROG_NAME "GL-Node Viewer" // // SYSTEM INCLUDES // #include #include #include #include #include #include #include #include #ifdef WIN32 #include #else #include #endif // // FLTK INCLUDES // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MACOSX #include #endif #include #include #include #include #include #include // // LOCAL INCLUDES // #include "system.h" #include "asserts.h" #include "lists.h" #include "structs.h" #include "util.h" #include "wad.h" #include "dialog.h" #include "menu.h" #include "level.h" #include "path.h" #include "grid.h" #include "info.h" #include "window.h" #endif /* __NODEVIEW_DEFS_H__ */ glbsp-2.24-source/nodeview/asserts.h0000644000175000017500000000404510624751532017011 0ustar aaptedaapted//------------------------------------------------------------------------ // ASSERTIONS //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_ASSERT_H__ #define __NODEVIEW_ASSERT_H__ class assert_fail_c { public: assert_fail_c(const char *_msg); assert_fail_c(const assert_fail_c &other); ~assert_fail_c(); private: static const int MSG_MAX = 200; char message[MSG_MAX]; public: const char* GetMessage() const { return message; } assert_fail_c& operator=(const assert_fail_c &other); }; // -------- the macros -------- #ifdef NDEBUG #define SYS_ASSERT(cond) ((void) 0) #elif 1 // FIXME: proper test for __func__ #define SYS_ASSERT(cond) ((cond) ? (void)0 : \ AssertFail("Assertion (%s) failed\nIn function %s (%s:%d)\n", #cond , __func__, __FILE__, __LINE__)) #else #define SYS_ASSERT(cond) ((cond) ? (void)0 : \ AssertFail("Assertion (%s) failed\nIn file %s:%d\n", #cond , __FILE__, __LINE__)) #endif // NDEBUG #ifdef NDEBUG #define SYS_ASSERT_MSG(cond, arglist) ((void) 0) #else #define SYS_ASSERT_MSG(cond, arglist) ((cond) ? (void)0 : \ AssertFail arglist ) #endif #define SYS_NULL_CHECK(ptr) SYS_ASSERT((ptr) != NULL) #define SYS_ZERO_CHECK(value) SYS_ASSERT((value) != 0) // -------- the support code -------- void AssertFail(const char *msg, ...); // throw an assertion exception with the given message. #endif /* __NODEVIEW_ASSERT_H__ */ glbsp-2.24-source/nodeview/system.h0000644000175000017500000000442710624275652016661 0ustar aaptedaapted//------------------------------------------------------------------------ // SYSTEM : System specific code //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_SYSTEM_H__ #define __NODEVIEW_SYSTEM_H__ /* ----- basic types and macros ---------------------------- */ typedef char sint8_g; typedef short sint16_g; typedef int sint32_g; typedef unsigned char uint8_g; typedef unsigned short uint16_g; typedef unsigned int uint32_g; typedef double angle_g; // degrees, 0 is E, 90 is N /* ----- function prototypes ---------------------------- */ // fatal error messages (these don't return) void FatalError(const char *str, ...); void InternalError(const char *str, ...); // display normal messages & warnings to the screen void PrintMsg(const char *str, ...); void PrintWarn(const char *str, ...); // argument handling extern const char **arg_list; extern int arg_count; void ArgvInit(int argc, const char **argv); void ArgvTerm(void); int ArgvFind(char short_name, const char *long_name, int *num_params = NULL); bool ArgvIsOption(int index); // endian handling void InitEndian(void); uint16_g Endian_U16(uint16_g); uint32_g Endian_U32(uint32_g); // these are only used for debugging void InitDebug(bool enable); void TermDebug(void); void PrintDebug(const char *str, ...); /* ----- conversion macros ----------------------- */ #define UINT8(x) ((uint8_g) (x)) #define SINT8(x) ((sint8_g) (x)) #define UINT16(x) Endian_U16(x) #define UINT32(x) Endian_U32(x) #define SINT16(x) ((sint16_g) Endian_U16((uint16_g) (x))) #define SINT32(x) ((sint32_g) Endian_U32((uint32_g) (x))) #endif /* __NODEVIEW_SYSTEM_H__ */ glbsp-2.24-source/nodeview/grid.h0000644000175000017500000000740110625202155016242 0ustar aaptedaapted//------------------------------------------------------------------------ // GRID : Draws the map (lines, nodes, etc) //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_GRID_H__ #define __NODEVIEW_GRID_H__ class W_Grid : public Fl_Widget { public: W_Grid(int X, int Y, int W, int H, const char *label = 0); ~W_Grid(); void SetZoom(int new_zoom); // changes the current zoom factor. void SetPos(double new_x, double new_y); // changes the current position. void SetPath(path_c *p) { path = p; } // give a path for the grid to draw void ClearPath() { SetPath(NULL); } void FitBBox(double lx, double ly, double hx, double hy); // set zoom and position so that the bounding area fits. void MapToWin(double mx, double my, int *X, int *Y) const; // convert a map coordinate into a window coordinate, using // current grid position and zoom factor. void WinToMap(int X, int Y, double *mx, double *my) const; // convert a map coordinate into a window coordinate, using // current grid position and zoom factor. public: int handle(int event); // FLTK virtual method for handling input events. void resize(int X, int Y, int W, int H); // FLTK virtual method for resizing. private: void draw(); // FLTK virtual method for drawing. void draw_grid(double spacing, int ity); void draw_partition(const node_c *nd, int ity); void draw_bbox(const bbox_t *bbox, int ity); void draw_all_partitions(); void draw_node(const node_c *nd, int pos, bool on_route); void draw_child(const child_t *ch, int pos, bool on_route); void draw_subsector(const subsec_c *sub, int pos, bool on_route); void draw_path(); bool set_seg_color(seg_c *seg, bool on); void draw_line(double x1, double y1, double x2, double y2); void scroll(int dx, int dy); void new_node_or_sub(void); public: int handle_key(int key); void handle_mouse(int wx, int wy); private: int zoom; // zoom factor: (2 ^ (zoom/2)) pixels per 512 units on the map double zoom_mul; // derived from 'zoom'. static const int MIN_GRID_ZOOM = 3; static const int DEF_GRID_ZOOM = 18; // 1:1 ratio static const int MAX_GRID_ZOOM = 30; double mid_x; double mid_y; int grid_MODE; int partition_MODE; int bbox_MODE; int miniseg_MODE; int shade_MODE; path_c *path; static const int MAX_ROUTE = 2000; static const char RT_RIGHT = 0; static const char RT_LEFT = 1; char *visit_route; int route_len; bool descend_by_mouse(int wx, int wy); // true if OK bool descend_tree(char side); // true if OK void lowest_node(node_c **nd, subsec_c **sub, bbox_t **bbox); static inline int GRID_FIND(double x, double y) { return int(x - fmod(x,y) + (x < 0) ? y : 0); } static const int O_TOP = 1; static const int O_BOTTOM = 2; static const int O_LEFT = 4; static const int O_RIGHT = 8; static int MAP_OUTCODE(double x, double y, double lx, double ly, double hx, double hy) { return ((y < ly) ? O_BOTTOM : 0) | ((y > hy) ? O_TOP : 0) | ((x < lx) ? O_LEFT : 0) | ((x > hx) ? O_RIGHT : 0); } }; #endif /* __NODEVIEW_GRID_H__ */ glbsp-2.24-source/nodeview/util.cc0000644000175000017500000001345510624752055016446 0ustar aaptedaapted//------------------------------------------------------------------------ // UTILITY : General purpose functions //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "defs.h" // // UtilCalloc // // Allocate memory with error checking. Zeros the memory. // void *UtilCalloc(int size) { void *ret = calloc(1, size); if (!ret) FatalError("Out of memory (cannot allocate %d bytes)", size); return ret; } // // UtilRealloc // // Reallocate memory with error checking. // void *UtilRealloc(void *old, int size) { void *ret = realloc(old, size); if (!ret) FatalError("Out of memory (cannot reallocate %d bytes)", size); return ret; } // // UtilFree // // Free the memory with error checking. // void UtilFree(void *data) { if (data == NULL) InternalError("Trying to free a NULL pointer"); free(data); } // // UtilStrDup // // Duplicate a string with error checking. // char *UtilStrDup(const char *str) { char *result; int len = (int)strlen(str); result = (char *)UtilCalloc(len+1); if (len > 0) memcpy(result, str, len); result[len] = 0; return result; } // // UtilStrNDup // // Duplicate a limited length string. // char *UtilStrNDup(const char *str, int size) { char *result; int len; for (len=0; len < size && str[len]; len++) { } result = (char *)UtilCalloc(len+1); if (len > 0) memcpy(result, str, len); result[len] = 0; return result; } int UtilStrCaseCmp(const char *A, const char *B) { for (; *A || *B; A++, B++) { // this test also catches end-of-string conditions if (toupper(*A) != toupper(*B)) return (toupper(*A) - toupper(*B)); } // strings are equal return 0; } char *UtilStrUpper(const char *name) { char *copy = UtilStrDup(name); for (char *p = copy; *p; p++) *p = toupper(*p); return copy; } // // UtilRoundPOW2 // // Rounds the value _up_ to the nearest power of two. // int UtilRoundPOW2(int x) { int tmp; if (x <= 2) return x; x--; for (tmp=x / 2; tmp; tmp /= 2) x |= tmp; return (x + 1); } // // UtilComputeAngle // // Translate (dx, dy) into an angle value (degrees) // angle_g UtilComputeAngle(double dx, double dy) { double angle; if (dx == 0) return (dy > 0) ? 90.0 : 270.0; angle = atan2((double) dy, (double) dx) * 180.0 / M_PI; if (angle < 0) angle += 360.0; return angle; } // // UtilGetMillis // // Be sure to handle the result overflowing (it WILL happen !). // unsigned int UtilGetMillis() { #ifdef WIN32 unsigned long ticks = GetTickCount(); return (unsigned int) ticks; #else struct timeval tm; gettimeofday(&tm, NULL); return (unsigned int) ((tm.tv_sec * 1000) + (tm.tv_usec / 1000)); #endif } //------------------------------------------------------------------------ // FILE UTILITIES //------------------------------------------------------------------------ // // FileExists // bool FileExists(const char *filename) { FILE *fp = fopen(filename, "rb"); if (fp) { fclose(fp); return true; } return false; } // // HasExtension // bool HasExtension(const char *filename) { int A = (int)strlen(filename) - 1; if (A > 0 && filename[A] == '.') return false; for (; A >= 0; A--) { if (filename[A] == '.') return true; if (filename[A] == '/') break; #ifdef WIN32 if (filename[A] == '\\' || filename[A] == ':') break; #endif } return false; } // // CheckExtension // // When ext is NULL, checks if the file has no extension. // bool CheckExtension(const char *filename, const char *ext) { if (! ext) return ! HasExtension(filename); int A = (int)strlen(filename) - 1; int B = (int)strlen(ext) - 1; for (; B >= 0; B--, A--) { if (A < 0) return false; if (toupper(filename[A]) != toupper(ext[B])) return false; } return (A >= 1) && (filename[A] == '.'); } // // ReplaceExtension // // When ext is NULL, any existing extension is removed. // NOTE: returned string is static storage. // const char *ReplaceExtension(const char *filename, const char *ext) { char *dot_pos; static char buffer[1024]; SYS_ASSERT(strlen(filename)+(ext ? strlen(ext) : 0)+4 < sizeof(buffer)); SYS_ASSERT(filename[0] != 0); strcpy(buffer, filename); dot_pos = buffer + strlen(buffer) - 1; for (; dot_pos >= buffer && *dot_pos != '.'; dot_pos--) { if (*dot_pos == '/') break; #ifdef WIN32 if (*dot_pos == '\\' || *dot_pos == ':') break; #endif } if (dot_pos < buffer || *dot_pos != '.') dot_pos = NULL; if (! ext) { if (dot_pos) dot_pos[0] = 0; return buffer; } if (dot_pos) dot_pos[1] = 0; else strcat(buffer, "."); strcat(buffer, ext); return buffer; } // // FileBaseName // // Find the base name of the file (i.e. without any path). // The result always points within the given string. // // Example: "C:\Foo\Bar.wad" -> "Bar.wad" // const char *FileBaseName(const char *filename) { const char *pos = filename + strlen(filename) - 1; for (; pos >= filename; pos--) { if (*pos == '/') return pos + 1; #ifdef WIN32 if (*pos == '\\' || *pos == ':') return pos + 1; #endif } return filename; } glbsp-2.24-source/nodeview/asserts.cc0000644000175000017500000000320010624751513017136 0ustar aaptedaapted//------------------------------------------------------------------------ // ASSERTIONS //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "defs.h" assert_fail_c::assert_fail_c(const char *_msg) { strncpy(message, _msg, sizeof(message)); message[sizeof(message) - 1] = 0; } assert_fail_c::~assert_fail_c() { /* nothing needed */ } assert_fail_c::assert_fail_c(const assert_fail_c &other) { strcpy(message, other.message); } assert_fail_c& assert_fail_c::operator=(const assert_fail_c &other) { if (this != &other) strcpy(message, other.message); return *this; } //------------------------------------------------------------------------ void AssertFail(const char *msg, ...) { char buffer[1024]; va_list argptr; va_start(argptr, msg); vsprintf(buffer, msg, argptr); va_end(argptr); // assertion messages shouldn't overflow... (famous last words) buffer[sizeof(buffer) - 1] = 0; PrintDebug("%s\n", buffer); throw assert_fail_c(buffer); } glbsp-2.24-source/nodeview/info.cc0000644000175000017500000001635610625201054016414 0ustar aaptedaapted//------------------------------------------------------------------------ // INFO : Information Panel //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "defs.h" #define INFO_BG_COLOR fl_rgb_color(96) // // W_Info Constructor // W_Info::W_Info(int X, int Y, int W, int H, const char *label) : Fl_Group(X, Y, W, H, label), num_segs(0) { end(); // cancel begin() in Fl_Group constructor box(FL_FLAT_BOX); // color(INFO_BG_COLOR, INFO_BG_COLOR); X += 6; Y += 6; W -= 12; H -= 12; // ---- top section ---- map_name = new Fl_Output(X+88, Y, W-88, 22, "Map Name:"); map_name->align(FL_ALIGN_LEFT); add(map_name); Y += map_name->h() + 4; node_type = new Fl_Output(X+88, Y, W-88, 22, "Node Type:"); node_type->align(FL_ALIGN_LEFT); add(node_type); Y += node_type->h() + 4; // ---- middle section ---- Y += 16; ns_index = new Fl_Output(X+74, Y, 80, 22, "Node # "); ns_index->align(FL_ALIGN_LEFT); add(ns_index); Y += ns_index->h() + 4; // bounding box bb_label = new Fl_Box(FL_NO_BOX, X, Y, W, 22, "Bounding Box:"); bb_label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); add(bb_label); Y += bb_label->h() + 4; bb_x1 = new Fl_Output(X+32, Y, 64, 22, "x1"); bb_x2 = new Fl_Output(X+W-64, Y, 64, 22, "x2"); bb_x1->align(FL_ALIGN_LEFT); bb_x2->align(FL_ALIGN_LEFT); add(bb_x1); add(bb_x2); Y += bb_x1->h() + 4; bb_y1 = new Fl_Output(X+32, Y, 64, 22, "y1"); bb_y2 = new Fl_Output(X+W-64, Y, 64, 22, "y2"); bb_y1->align(FL_ALIGN_LEFT); bb_y2->align(FL_ALIGN_LEFT); add(bb_y1); add(bb_y2); Y += bb_y2->h() + 4; // partition line int save_Y = Y; pt_label = new Fl_Box(FL_NO_BOX, X, Y, W, 22, "Partition:"); pt_label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); add(pt_label); Y += pt_label->h() + 4; pt_x = new Fl_Output(X+32, Y, 64, 22, "x"); pt_dx = new Fl_Output(X+W-64, Y, 64, 22, "dx"); pt_x ->align(FL_ALIGN_LEFT); pt_dx->align(FL_ALIGN_LEFT); add(pt_x); add(pt_dx); Y += pt_x->h() + 4; pt_y = new Fl_Output(X+32, Y, 64, 22, "y"); pt_dy = new Fl_Output(X+W-64, Y, 64, 22, "dy"); pt_y ->align(FL_ALIGN_LEFT); pt_dy->align(FL_ALIGN_LEFT); add(pt_y); add(pt_dy); Y += pt_dy->h() + 4; // seg list Y = save_Y; seg_label = new Fl_Box(FL_NO_BOX, X, Y, W, 22, "Seg List:"); seg_label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); add(seg_label); Y += seg_label->h() + 4; seg_list = new Fl_Multiline_Output(X+10, Y, W-10, 96); add(seg_list); // keep 'em hidden seg_label->hide(); seg_list->hide(); Y += seg_list->h() + 4; #if 1 // resize control: Fl_Box *resize_control = new Fl_Box(FL_NO_BOX, x(), Y, w(), 4, NULL); add(resize_control); resizable(resize_control); #endif // ---- bottom section ---- Y = y() + H - 22; mouse_x = new Fl_Output(X+28, Y, 72, 22, "x"); mouse_y = new Fl_Output(X+W-72, Y, 72, 22, "y"); mouse_x->align(FL_ALIGN_LEFT); mouse_y->align(FL_ALIGN_LEFT); add(mouse_x); add(mouse_y); Y -= mouse_x->h() + 4; m_label = new Fl_Box(FL_NO_BOX, X, Y, W, 22, "Mouse Coords:"); m_label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); add(m_label); Y -= m_label->h() + 4; grid_size = new Fl_Output(X+50, Y, 80, 22, "Scale:"); grid_size->align(FL_ALIGN_LEFT); add(grid_size); Y -= grid_size->h() + 4; } // // W_Info Destructor // W_Info::~W_Info() { } int W_Info::handle(int event) { return Fl_Group::handle(event); } //------------------------------------------------------------------------ void W_Info::SetMap(const char *name) { char *upper = UtilStrUpper(name); map_name->value(upper); UtilFree(upper); } void W_Info::SetNodes(const char *type) { node_type->value(type); } void W_Info::SetZoom(float zoom_mul) { char buffer[60]; /// if (0.99 < zoom_mul && zoom_mul < 1.01) /// { /// grid_size->value("1:1"); /// return; /// } if (zoom_mul < 0.99) { sprintf(buffer, "/ %1.3f", 1.0/zoom_mul); } else // zoom_mul > 1 { sprintf(buffer, "x %1.3f", zoom_mul); } grid_size->value(buffer); } void W_Info::SetNodeIndex(int index) { char buffer[60]; sprintf(buffer, "%d", index); ns_index->label("Node # "); ns_index->value(buffer); seg_label->hide(); seg_list->hide(); pt_label->show(); pt_x ->show(); pt_y ->show(); pt_dx->show(); pt_dy->show(); redraw(); } void W_Info::SetSubsectorIndex(int index) { char buffer[60]; sprintf(buffer, "%d", index); ns_index->label("Subsec #"); ns_index->value(buffer); pt_label->hide(); pt_x ->hide(); pt_y ->hide(); pt_dx->hide(); pt_dy->hide(); seg_label->show(); seg_list->show(); redraw(); } void W_Info::SetCurBBox(const bbox_t *bbox) { if (! bbox) { bb_x1->value(""); bb_y1->value(""); bb_x2->value(""); bb_y2->value(""); return; } char buffer[60]; sprintf(buffer, "%d", bbox->minx); bb_x1->value(buffer); sprintf(buffer, "%d", bbox->miny); bb_y1->value(buffer); sprintf(buffer, "%d", bbox->maxx); bb_x2->value(buffer); sprintf(buffer, "%d", bbox->maxy); bb_y2->value(buffer); } void W_Info::SetPartition(const node_c *part) { if (! part) { pt_x ->value(""); pt_y ->value(""); pt_dx->value(""); pt_dy->value(""); return; } char buffer[60]; sprintf(buffer, "%d", part->x ); pt_x ->value(buffer); sprintf(buffer, "%d", part->y ); pt_y ->value(buffer); sprintf(buffer, "%d", part->dx); pt_dx->value(buffer); sprintf(buffer, "%d", part->dy); pt_dy->value(buffer); } void W_Info::SetMouse(double mx, double my) { if (mx < -32767.0 || mx > 32767.0 || my < -32767.0 || my > 32767.0) { mouse_x->value("off map"); mouse_y->value("off map"); return; } char x_buffer[60]; char y_buffer[60]; sprintf(x_buffer, "%1.1f", mx); sprintf(y_buffer, "%1.1f", my); mouse_x->value(x_buffer); mouse_y->value(y_buffer); } void W_Info::BeginSegList() { num_segs = 0; } void W_Info::AddSeg(const seg_c *seg) { if (num_segs < SEG_LIST_MAX) { seg_indices[num_segs++] = seg->index; } } void W_Info::EndSegList() { char buffer[SEG_LIST_MAX * 32]; char *line = buffer; buffer[0] = 0; for (int n = 0; n < num_segs; n++) { char num_buf[60]; sprintf(num_buf, "%d", seg_indices[n]); int line_len = strlen(line); int num_len = strlen(num_buf); // fits on the line? if (line_len + 1 + num_len <= 19) { if (*line != 0) strcat(buffer, " "); } else { strcat(buffer, "\n"); line = buffer + strlen(buffer); } strcat(buffer, num_buf); } seg_list->value(buffer); } glbsp-2.24-source/nodeview/Makefile.xming0000644000175000017500000000213010625227125017723 0ustar aaptedaapted# # GL-Node Viewer # # GNU Makefile for WIN32, using CROSS-COMPILER on Linux # PROGRAM=NodeView.exe SRC_DIR=nodeview LIB_LOC=/home/aapted/ebuild FLTK_DIR=$(LIB_LOC)/fltk-1.1.7 FLTK_FLAGS=-I$(FLTK_DIR) FLTK_LIBS=$(FLTK_DIR)/lib/libfltk_images.a \ $(FLTK_DIR)/lib/libfltk.a CXX=i586-mingw32msvc-g++ CXXFLAGS=-O -Wall -DWIN32 $(FLTK_FLAGS) LDFLAGS= LIBS=-lm $(FLTK_LIBS) \ -mwindows -lcomdlg32 -lole32 -luuid -lgdi32 \ -lcomctl32 -lwsock32 -lsupc++ OBJS=./main.o \ ./asserts.o \ ./dialog.o \ ./grid.o \ ./info.o \ ./level.o \ ./lists.o \ ./menu.o \ ./path.o \ ./system.o \ ./util.o \ ./wad.o \ ./window.o # ----- TARGETS ------------------------------------------------------ all: $(PROGRAM) clean: rm -f $(PROGRAM) *.o core core.* ERRS nv_debug.txt $(PROGRAM): $(OBJS) $(CXX) $(CFLAGS) $(OBJS) -o $@ $(LDFLAGS) $(LIBS) stripped: all i586-mingw32msvc-strip --strip-unneeded $(PROGRAM) .PHONY: all clean stripped #--- editor settings ------------ # vi:ts=8:sw=8:noexpandtab glbsp-2.24-source/nodeview/README.txt0000644000175000017500000000177510625174441016660 0ustar aaptedaapted NodeView README =============== by Andrew Apted. 21st May 2007 Introduction ------------ NodeView is a small node/subsector browsing tool. Currently it only works with GL-Nodes. COLORS ------ purple : partition lines pink : highlighted subsector red : bounding boxes sky blue : minisegs white : one-sided line yellow : 2S line marked impassible cyan : 2S line on a closed door orange : gap too narrow for player to pass green : dropoff too big for player to climb gray : normal (walkable) two-sided line KEYS ---- mouse click : go down one side of the BSP tree, highlight the subsector when reached CTRL+click : instantly highlight the subsector (same as t following by clicking all the way down) u : go Up the BSP tree t : go back to Top of BSP tree p : toggle Partition drawing (below/on-top/none) b : toggle Bounding-box drawing m : toggle Minisegs (on/off) s : toggle Shading mode (dark/no-draw) g : toggle Grid (on/off) +/- : zoom in / out glbsp-2.24-source/nodeview/info.h0000644000175000017500000000373410625176441016265 0ustar aaptedaapted//------------------------------------------------------------------------ // INFO : Information Panel //------------------------------------------------------------------------ // // GL-Node Viewer (C) 2004-2007 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __NODEVIEW_INFO_H__ #define __NODEVIEW_INFO_H__ #define SEG_LIST_MAX 16 class W_Info : public Fl_Group { public: W_Info(int X, int Y, int W, int H, const char *label = 0); ~W_Info(); private: Fl_Output *map_name; Fl_Output *node_type; Fl_Output *grid_size; Fl_Output *ns_index; Fl_Box *pt_label; Fl_Output *pt_x; Fl_Output *pt_y; Fl_Output *pt_dx; Fl_Output *pt_dy; Fl_Box *seg_label; Fl_Multiline_Output *seg_list; Fl_Box *bb_label; Fl_Output *bb_x1; Fl_Output *bb_y1; Fl_Output *bb_x2; Fl_Output *bb_y2; Fl_Box *m_label; Fl_Output *mouse_x; Fl_Output *mouse_y; private: int seg_indices[SEG_LIST_MAX]; int num_segs; public: int handle(int event); // FLTK virtual method for handling input events. public: void SetMap(const char *name); void SetNodes(const char *type); void SetZoom(float zoom_mul); void SetNodeIndex(int index); void SetSubsectorIndex(int index); void SetCurBBox(const bbox_t *bbox); void SetPartition(const node_c *part); void SetMouse(double mx, double my); void BeginSegList(); void EndSegList(); void AddSeg(const seg_c *seg); }; #endif /* __NODEVIEW_INFO_H__ */ glbsp-2.24-source/gui/0000755000175000017500000000000010652037721014113 5ustar aaptedaaptedglbsp-2.24-source/gui/glBSPX.app/0000755000175000017500000000000010652037671015775 5ustar aaptedaaptedglbsp-2.24-source/gui/glBSPX.app/Contents/0000755000175000017500000000000010652037671017572 5ustar aaptedaaptedglbsp-2.24-source/gui/glBSPX.app/Contents/Resources/0000755000175000017500000000000010652037671021544 5ustar aaptedaaptedglbsp-2.24-source/gui/glBSPX.app/Contents/Resources/glbspx.icns0000644000175000017500000014630610514052721023721 0ustar aaptedaaptedicnsÌÆics#H÷ÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþüø÷ÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþüøis32Ø    €&qÉrYŽn6»´ Aobe¤#r̈!™YLh©ƒKQù"¾Œ eSg¦´&I“ ðou¬wXˆ“@¥U 2+  *P  5nW( Gê¦*  ;Jç§/  /nW$  "6.‚   €  "T t6   v <€;0T1)>1ITQ6.*,E3V :5s6@&".G:&)gO6k=*$-F N<&>jo€|e03I7/CF%C3#z 6 & 6. Q^W$ 4nV%3=3zFê¦)HE ??3Iå¦- .mV$  !6- ‚   €ƒ&?2‚™ê9Öb‚ Ý4m€‚  ’a‚¹d€‚Çm€ÆÍ€U6ß9  “¬Ÿ€% CeUâO wunp\I!ƒ € €€ƒ€s8mkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿICN#?üÿÿÿÿ¾ÿÿþÿÿøÿÿø?ÿÿø?ÿÿüÿÿþÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿþ?ÿÿü?ÿÿøÿÿøÿÿðÿÿàÿÿ€ÿÿ?ü?üÿÿÿÿ¾ÿÿþÿÿøÿÿø?ÿÿø?ÿÿüÿÿþÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿþ?ÿÿü?ÿÿøÿÿøÿÿðÿÿàÿÿ€ÿÿ?üil32 yˆ…’ƒ€ €…€   …€ € †€€   …çf=uqn&q™^ utsU  ‡ÆaóeZö_ ´ sã Þs  „ÅdïK ÿ7¤yR fÙŠÉ ƒƨµ`ÄdîJÿ%¡àgÜ€Ó ‚˜ï Äeî›¶‡PþéIhدŸ ‚¥‹ö Åfîbhê tùïiøžÀ ‚L×r´ÇfîNño" SþBiØ€ #Ž4ÇfîQê{wíFjÜ uÞ§Êj ðf6þF¬A$ë"rß  îØÿw•ŠL˜–YM´¯e“ŸX  €¡Pf )0*%  €¡q˜8 !*:JB0 € €ª–h &:Li]9,  ƒ0 ,Hl¢‚Q6   !4U¤úÊf6 € %  0XÀÿèi7  €  5_±ÿÙh>& € !4Iv¾•W1  &7Yq]I,  .AOC6' ƒ %-7/(  „ "'" †  ˆ  Œ     ‡ˆ…’‚€ -+**!667…€ [pnj.bpT%…€gl[€BV†€>mng"… `,3101B* 31Alm= Y‡S*f,(g ,DL3^YjgS „S+b"jF6& -[9gn8^‚ SFL*R+d" jF^.\6hlm.ƒ:A eR,dBM<'ja$/[Hhln‚E9gS,d,/a 6hd0hDP)mmD‚ Z0LS,d% e5+i"1Znli<S,d& b::b&2[Fbln*0\F7T/d0i(M)a6] ilmW bZk4@<$EDE.1RP6BF)6OQmnC#=, *3,&b&&nm=D0A !)9IA/,i gmh€ G@- &9Lh\8,YHBmn%€[ ,Hk P6 >oE >mm] !3T úÉe62a__O8_\\]\ /W¾ÿçh6  4^¯ÿØg=& €  3Hu¼”V1  $7Xp\H,  .ANC5' ƒ %-6.'  „ !&" †  ˆ  Œ     ‡‹›—NKJK=6ebe/‰ ¤ÍÊÂV6µÏ™C‰€¼Æ¨€yž‹€ qÊʽ?†uÉo;¤‡„XÀ—:†€€Ðe­ƒ†ÍÉRƒ‰4ËÉ)ƒ ƒ,ËÇzƒ‚ƒ‚ÊÅ¿ ƒ‚w²ÆÊG‚€ À%ÆÇŸƒ€„UŽ“ÇɃ€ ´7=ÊÉo„ ;À¼Æ¾€‚  ~rÆÊ?‚€ $ [Ìu mÇǬ!€ "G&(¯ª¬Œb®©¨¬¨   ,±8Œ &]/ „€€  (€ƒ€€‚ƒ€  „ƒ„ €†„ €‰‚ ‰€‚„‡l8mkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿich#Hüÿÿ€ÿÿàÿÿûðÿÿÿøÿÿÿÿøÿÿÿÿàÿÿÿÿÀÿÿÿÿÀÿÿÿÿàÿÿÿÿðÿÿÿÿðÿÿÿÿø?ÿÿÿÿø?ÿÿÿÿüÿÿÿÿüÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿü?ÿÿÿÿü?ÿÿÿÿøÿÿÿÿøÿÿÿÿðÿÿÿÿðÿÿÿÿàÿÿÿÿÀÿÿÿÿÀÿÿÿÿ€ÿÿÿÿÿÿüÿÿøÿÿàÿÿ€üüÿÿ€ÿÿàÿÿûðÿÿÿøÿÿÿÿøÿÿÿÿàÿÿÿÿÀÿÿÿÿÀÿÿÿÿàÿÿÿÿðÿÿÿÿðÿÿÿÿø?ÿÿÿÿø?ÿÿÿÿüÿÿÿÿüÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿü?ÿÿÿÿü?ÿÿÿÿøÿÿÿÿøÿÿÿÿðÿÿÿÿðÿÿÿÿàÿÿÿÿÀÿÿÿÿÀÿÿÿÿ€ÿÿÿÿÿÿüÿÿøÿÿàÿÿ€üih32’¾ŠŸŠ‚†›ƒ€€‚Ž  ƒ ‚ Œ‚ƒ  ‹ƒ € Œ‚‚€  Œ 7]€€ €€   ŒKèÝl€“`'¢À¯D ‚”“”J  Œ ÅÝÍëB_ð§ ÆŽ n·'â×8‘ïf  ŒÃݾåÀå$@íCÙÇ êÅ  ‰#Ãݾå¢ë0\ñX b ÙÇ Ùà"  ˆ$ ¬ÇÊ·Ø)ÄÞ ¿å¿ßTðÒ" ÚÇ Øâ# ˆ%në48ï‡ÄÞ ¿ç1Véu )ãñÚU ÚÇåÏ ‡ªãå|ÄÞ ¿î¯ØÌ8 zîñëe ÚÍZðz€  ‡§ä!èvÄÞ ¿å"ä×$géñÞÚïÊÑw †Vî_bè5ÄÞ ¿å ™ðb@âñ:ÚÇ€ †¤À¨IÄÞ Àå ~ñ}e(”ñIÚÇ  †EÏÄÞ Àå ñnl^wñ9ÚÉ€ € …!qðÓǰ5Æß Ãë*×å8gÅ( Ó!ÝË  €  …Ò€ñÑYÕÜmq×ÝÉÊ¿X:ÃæÕS–ÜÚ•  …"CÊRF´ï&"$1OQ7    € …"½ª?î "*481/% €  …#­Ç PÍ %(3CIA:(  € „#:ݘb¾F *4?S]UF.&" €  „#RR %.BOh{pN;3%  „# $6Kh‡°–^Q6$   ƒ  *8RÅõʇT6&‚  „ ‚ +@^•ðÿó“U7& ƒ€  &9V–õÿø[<' €„€! *?`•àÿêŠX?,  €„( ,?Rk­Ú´zL4& „€%  '1?[~“{eG/! …'  '7N^kZNA, …& "0AHQF>4( ‡$  '49>61($ ‰# #'./+'! Š!  &&# Œ   Ž  ’  ”  €  ™     ハŸŠ‚†›ƒ€ ‚Ž Fƒe!edŒ‚ƒN€k g0 .dk[+‹‚ _kkb €\hŒ‚‚;€k'i<Œ'€€ € ikkS@d Œ `\.>+ FQJ8??Aaikjf=Œ R\ Vb*dF S>1M^Z>ehk;,fŒ R\P_ Q_b  D[S afk^VDˆ#  R\P` Fa*e) , [TZejkEjˆ$GSTLZR\P`Q]'eX [TZejkkRˆ.bd9R\P`(a5 _e[( [T _f€k-‡F^ _5R\PdJ[V 8deb/ [V (dV€kI‡&F_ `3R\Q`_Z 1ae][dUW4akki† $b(*`R\ Q` Ce0#^e [T  \€k5†DPF R\ Q` 8e;1Ce&\T 'kZ†'V R\ Q` @e6639e!\T  QUYkkj…!/eXSJS] RbZ`"6V HZ\V h*1€kH… W€e"W'Y[13Z\UVR.)VUL[0D\[BG`dkkf…"T$Kd $+75, gBG€k3…"NGd !*370/%;j €k]…#GS$V $'3BHA:(`Z  Z€k„#\A+P  )4>R\TF-&"6k;6€kH„( $$ $-ANgznM;3$]k jkkg„$ #6Jg†®•]P6#)Okk4-j€kQ‚  *7Q€ÃõdžS6&UkbM„k‚* *?]”ïÿñ‘T6%&%!‚€  &8U•ôÿö›Z;' €„€! *>_”ÞÿêˆW>,  €„( ,>QjªØ±wK3& „€% '0>Z}‘ydG.! …'  &6M]jYM@, …& !0@GPF=4( ‡$  &49=61($ ‰# "&./*'  Š!  &%" Œ   Ž  ’  ”  ™  € ‚ ïñ€¤€€€ €€ ‚$‘ƒƒ¸=&¸·2‚,Ž€Ä ¼W U·Ä¨N&‘…®Äĵ€©¾$‚i€ÄF€-Àn ‚  ¿ÄÄ—u·Œ‚€ 6{Àà ¹q ‡ `ÄkN» ‚ ¹­| ‚ §Ä}Â&‰ ¥ÄÄ•ˆ ‹¶ÄÄO‰ ‹1ÃÄĆˆ €€‡²ÄÄ¿ˆ €€€ §€Ä\ˆƒ„€€>ÀÄ¥ˆƒ€ ‘˜¡ÄÄÂ5‡€€€€‚(½EQ€Äƒ‡‚‡ z¯µÄŇ€‚  »q€Ä[†‚€€   € _À+3ÃÄĬ…€€ ®¡¤€Ä5†‚ PÄa€\€Äƒ…‚„   ¦Ä)ÂÄ (  #ƒÄÄQ L€Ä•-† 'C&‰Ä´‹„Ä&†ƒ !E‹< $#""„ †ƒ€  TÇD €‚€ &1^7 €Œ€ #." ‚ˆ‚ €‚‚ˆ‚€ ‚„ˆ‚€ƒ   €‡ˆ‚  €…Ї    ‚…‚„‚’€€–€‚™ ‚ïh8mk ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿit32]#ÿÿÿÿ¤šÝÙ¡Ö¤ÓŒ–ÑŒƒÎƒÌ€Œ€‘Ê€‹‚…ˆÇ€‚„‚€„ ‡ƒ‚Ѝ€‚‚‚€„  ‚Š  ¨ˆ„€‚  ‚Š  §‰ˆ‡€  ‚Š  ¦Š€ƒ€ˆ Š ƒ† ¦‹€‚€‡‚ˆ ˆ ‚  ¨Š„€‡† ‡ ‡  ¨‹ˆ‚†€‡ ‡‚ ©Œˆ† † €† ©„€‚„€€‡ €… ¨ˆƒ€…ƒ‡ ƒ §ˆ€€‚€€€ƒ †  €ƒ ¨"…€€€‚‚‡  € ¨*^Óð½ €€†€€…‚‡  € §À‚ñ½ €‚F€mF‚€ƒ‡ €€€  §­‚ñ½ ƒˆÂ¨w;€tä‚ñí“ĀÀÂÃÃÂñ‹Lƒ  € §6ñ½ ¤Šñð¹*©€ñÜÅà€ñè3 ‹ñÏA‚  € ¨€ã€ñ½ #­ñîžl|ÕñÙ1€  ˆðñíˆ ’€ñ_RÞñÙk´ï€ñàK  € §€Ó€ñ½ FñÖ¡ð€ñ ±5îññ­€ ¦ññ_¡€ñîgkñÙ €  §Ó€ñ½ 6ñÂãñ= “€ñV7ãñ` –€ñëZ¼ñt  €€ §Ó€ñ½ 6ñ‚Žñ„ Å€ñ) ²ñ` –€ñë[€Vî€ñ»  € §‚Ó€ñ½ €6ñ‚Vñ®>߀ñaña€ –€ñëZ-Ö€ñÚ;  € §‚Ó€ñ½ 6ñ‚=ê€ñ¿Qï€ñ.ãa€ –€ñëZ½€ñïT‚  € §ƒÓ€ñ½ 6ñ€7ã€ñÀhñ< ¿b  –€ñë[€ ´ño‚ €    7RP/BtÓ€ñ½ 7ñÂ7ã€ñ¾lñŠ €‡P  –€ñëZªñ„‚  € íñ Ýu 6µï Ó€ñ½ 7ñ‚Aï€ñ© lñÜ= ‚  –€ñë[ªñ„†  œ"Ø€ñåî€ñåîññvÓ€ñ½ 7ñ‚lñt RïñÐ €   –€ñë[ªñ€† €š±€ñ® ´‚ñîQÓ€ñ¾ 8ñµ€ñê/ ;Ü‚ñÄ5  —€ñë[€¶ñf† €šb€ñê0>ë€ñ݌Ӏñ¾ 8ñÂ?ëññð‘ ăñ êk —€ñë[€€ñëL… ‚™É€ñ ·àññêT€Ó€ñ¾ 9ñÂ=Ѐñ¿ …ñ ¶$ —€ñë[€/Ö€ñÕ5… ‚˜&߀ñ–·€ñ‹Ó€ñ¾ 9ñ â—™¼îññï† €  &â…ñ Ù; ˜€ñë\Sî€ñ°… ƒ˜@ç€ñƒ›€ñ°Ó€ñ¾ €9‡ñï¤* €  kê…ñØ< ˜€ñë[´ñ\‡ ‚—Xí€ñzŒ€ñÃÓ€ñ¾9ñâ—™¼î€ñ ë‹ ’†ñÑ ˜€ñïl€Yñ±‡ ‚—Xí€ñzŒ€ñÃÓ€ñ¾:ñÃ>Ѐñï• ˆî…ñu ˜ñÐ\Iç€ñÍ'‡  ‚—Jé€ñ‡Ÿ€ñ°Ó€ñ¾:ñà 7êñ_€ fâ„ñÃ& ˜‡ñð¯! ‡ ‚–,à€ñ  €Æ€ñŒÓ€ñ¾:ñà œñÀ€+»ƒñíI€ ˜„ñèƒ9‡ ‚–É€ñ ÏçññëX€Ó€ñ¾€:ñÀ  Kí€ñâJ€Šƒñy ™€ñë]‚ˆ ‚—gñ VfïññÐÓ€ñ¾:ñà ,Íñ sœðñ  ™€ñë]ƒ ˆ ‚–±€ñ à`kàññèOÓ€ñ¾;ñà € ¸ñ ’lH%Íñ»€™€ñë]… ˆ  —¹„ñçOÓ€ñ¾;ñà ¬ñ ©¢”vñÅ™€ñë]ƒŠ ‚˜ &ÀñíñêÃs€Ó€ñ¾;ñÀ  ¬ñª“Í5î€ñÅ™€ñë]€ƒ Š ‚•Féîr‚€€Ó€ñ¾<ñà ®ñ¡‹â>)×€ñ¯™€ñë]€‚‹  •/Þñダ€Õ€ñ¾<ñÀ  ¼ñ‹€îz'Ê€ñ›™€ñë^… €  ‡ ‚•ˆññè3‚€Õ€ñ¾;ñÄ‚ 2Ò€ñðkuñ¾,*Ñ€ñn›€ñë^ „ ‡ ‚•Ç€ñÙ‡iijjVÕ€ñ¾€<ñÄ € Xï€ñÜBoññb2èññãD›€ñë^„ €   ‡ ”LJñî˜Õ€ñ¾€<ñÝ€¸ñ´bññÌ4`€ñµ%›€ñë^‚   ‡ ”ˆ‰ñ°ã€ñË€SñêPƒï€ñêO_îñðŸ"!»€ñ_¬€ñðz € € €‡  €”/Þ‰ñh'y‚ñs.IÄ‚ñ订ÖñénFØ€ñŸ: .¡ïññ¯G†éñßu>  ‡ ”`ðˆñ¿ß…ñ§Šñð¿N€!R܆ñ¬.-‡ño € ‡ •bã‡ñØ1‹––‚—˜k˜˜€™€›€‹h6&"4ŒÜ‚ñ ×z#%€œ››œœ›J ‚ ˆ €“ zêñä™jju¼ï€ñ çG € € . '%$).Hdd^F-& ! €€ ‡ €’œññç/PñX€ € €  €)*',2+,)%(-&#$€ ƒ €‡ ’?çññ¶‚¢€ñX€8  ! *-+/6/1,(-1''& ‚  € ‡ €u€ñ‡‚bññíP€ € %#*3.3<56/,43*,& ‚ ‚   ‡ €ƒ€ñ‡€SññâA7  "((*756B:;42;5..&  ‚ €ˆ y€ñ­€_ññÌ ‚7  ""!$)-,:;;GAB87B65/'!  € ‡ ‘TëññÜ’ññ¥€ !$€&+20:DBNHI>@H::0)# €‚  ‡  ‘ÜññîmãññFƒ€2 "&)+*-47;LGUOODIM@>1*$! ‚  €€ˆ ’ˆ€ñ àL§ñ🃀€0 !&,//16??RN\WVJTPIA3,&$"$#   €€ ‡ ’¯€ñ î¶—Þññ·‚0 !&-376:EEUWba]Q`SPB6/*'((%!‚  ‚‡  ’ Šåƒñèw2  "#'-6=?@GMWailf[jYSC83../+&"‚  €‚ ‡ ’€\¨­ŒP€ €  € *!%'*-6@HHJUYnr{pjqbUE<7662,&"ƒ  €‡  ‘„‚€6 #&+.16BOSQZa{~}{ymUGA?A<5-'"‚  €ˆ ‘„€€€€2  &,276.($ ‹  € ‘ „€!  $(-5=FLOXm“­Öù€ÿúÜЦ}aUJB6/)$ ‹  € ‘ Œ„€! "'-6=HT_lt†µðþÿþÚ|hXJB6/(# €‚„Œ„€   $)08DQ_rˆ§Ãî‚ÿýÖ¤€gVH?5-'" €€„€…‚ "&,4=GRdwœÌû‚ÿþØŸ{dSF>5,'" €€„€…‚ "&,3IVh}ŸËûƒÿ빕{hVL@6-'" €€€„€‡‚  $*18COZk¦Õù‚ÿúÊŸ‡qaTK@80+&! €€‚‡†! !&,29BN\rˆŸ±Ìôÿ!ø¼–te[PG<5.)%  €‚€„‘„€B !&*19ETanwƒ“²ëýÿþú﹉u]OGC:3,'# €€€„‘„€€€€< !&,32,)%  €€€„’ƒ€€>  "%),05AQR^nd}vwgi^XTSF=5)$"  €„’„B  #&),5BLG^^[pjk^X[QJKE84,# €„“ƒ: !$&,5A@HYQTg_`WNVIFAB60,% € €€€€„•‚€:  $+5:6JQFP[VWOFNDA996-(&  € €€€ƒ–‚€  €-$+306HF?MTOQJBFA9623-&#  €‚€ƒ—€€€< $+-+6A<8IKHJE=;?33-,,&  €€€€‚€‚™€€€€ € 9 $)&*6:44FBBC>84:0.,')&  ›€€ € * $$"+43-1B9<=94-4.))$$% € ‚€‚€œ‚€€ € (" ,0,).<4664/*-.&&" ! €  ‚€€ € / !+,'&,7.22/,&(,#"! €  ‚‚€€Ÿ€‚0 "''"#+2*--,)$#("  €¡€‚ €  "%# *,&**(&"%"€  € €€‚£€‚ € )!!))$&&%#  ! €€€¥€€€ € * &% $$"   €€€€€€§€€ƒ€ €  %"!! € €©ƒ€€5  # ‚€«€‚€€ €!€€€  ®‚€€" € €  €‚±€ƒ€ € € ³ƒ   €€  €€¶‚ €  €  ¹€‚"  €  €¼€€ €  €€  À€   € ƒ Ä €  €    ƒ  €È   € €  €   ƒ Ì ‚ € €  ‚ € Ñ€  €   ‚ × €    € ÿÿÿÿ¤ÿÿÿÿ¤šÝÙ¡Ö¤ÓŒ–ÑŒƒÎƒÌ€Œ€‘Ê€Œ€†ˆÇ€‚„‚€„@C„BƒA;$ŠA< ¨€‚‚‚€„fŽka ;Škb¨ˆ€ƒ€‚fŽka ;Škb§‰ˆƒ‚€fŽka ;Škb¦Šƒ‡/Wjˆkg<)‚ (Eb„kg?!¥‹€‚€‡‚9‡ki&ˆ`‚kT¨Š„€‡†P†kf‡ Wk` ¨‹ˆ‚Š€&g†k,‡g€kh*©Œ‡†€X†kV€†-kR¨Ž„€‚„€€4‡k€„V€ki¨ˆƒ€…„€d†k8€ƒd€kI§ˆ€€‚‚E†kV €‚5jkki¨…€€€‚ƒ!h…kj!W€kU§(¦‚X€eOeR‚a€eP &d€e^,€ A€eb( Oei‚kakkd§ƒX€eOeR€^€eQ .e Q,  A€eb(€Keh‚k="jkkN "!€2X€eOeR^€eP 0e< € :&  A€eb(Geh‚k`[€k  `€eVf†kS ‚—`€e7C€eJX€eP eR ae . 0^„eS C‡edJ N†ki‚–]€eC€R€e;X€eP eR De R Pƒeb%€ C„e`R90‡kG‚–S€e V `eeb&€X€eP eR %b€e^&€?ƒe6 C€eb*€‡k_‚—+e %,deeW X€eP €eR We 6EdeF C€eb*ƒ8‡kj/‚–I€e])-^ee`#€X€eP eR € Oe C4&WeP€C€eb*…XˆkR—L„e`"X€eP eS Je KHC7eTD€eb*€ƒ+Šk‚˜ PeaeaR2 €Y€eP eS  JeKBXd€eTD€eb*€€VŠk@–`d0ƒ€Y€eP eS€  KeH@_&[€eLD€eb+€‚ gŠkZ•\e^ „€Y€eP eS  Pe@eeF‚4  $&%&+1/:CAMGG=?G:90(#Jk*.‡kT‘ [eed. ^ee ‚€3 !&(**,47;KGTNNCHM@>1)$!g€kb€€\‡k’8€e ]! FeeD ƒ€€1 !&,/.06>>QMZVUHSOHA3,&$"## @j€kH €€F‡kF’I€e dL6@\eeM €$ !&,3669DDTV`_\P_ROA5.)€' % _€kh, ‚ ‡k^’:_ƒea4 2  !#&-6<>?FLV`hkeZiXSB72--.+&"jk8 ‚e‡k$‘„€€€€3  &,26;BO[\_l‚ ‹Ž„rWJGKG>5-& &g‚k3 €€`‡kW ‘„€€€€€ / #,3:CGO^llz‰¥· ¤–r[SWUI?5,% 0_ƒkN €€;jˆkT „€€3 !'/;FOU]u€†¼Ø¼Æ¢vfgeXI>2*%!Oa†k`UF?€%F[j‹kiU<„€€€€2 !$&)-6ES_hv“µ×ùãâ®||iWF;2,'#h‹k0€F‘kE…€€€-  #(,157?Jar‚˜ÀÐõÿþô»›€fRE=6.(#h‹k0€F‘kE…!  $(-44,&" €…€…‚€ !&,3IUh{Éúƒÿé·“zgUK?6,'" €€€„€‡‚€  $*08CNYj}¥Óø‚ÿùdžp`SI?70+&  €€€‡‘‡€ !&+18AM[p†¯Êóÿ!ø»”rdZOF<5.)%  €‚…‘…< !%*08DSamv’°éýÿþúí·ˆt\NFB92,'"€  €€…‘…€€€<  %+3LSNOIAE@8623-&#  €€‚€ƒ—€€€ € #+-*6A<8IJGID<;>32€,& € €€‚€‚™€€€€@ $(&)6944FAAB>639/-+'(&  ›€€€ 7 #$!*42-0A9;<83-4.((##%  ‚€œ‚€€ ! +/,)-;3663/*,-%%!€ €  ‚€€€ €  €(!*+&&,7.11.+&'+#"  €  €ƒŸ€‚ "&&""+1*€,($#("  €¡€‚‚ € + "$# ),&))(&!$! €€‚‚£€‚  € ) !((#&&%"  ! €¥€€ + &$ ##"   €€€€§€‚€ €  %!€ € ‚©€‚%  "€ ‚€«€‚€€ !€ €  €‚®‚€€ € €  €‚±€ƒ€ ‚ €  ³€ƒ   €€€   €€¶‚"  ‚  €¹"  €  €¼€€ € € € À€  €€ ƒ Ä€   €   €È   €  €   €  € €Ì„   ‚ ƒÑ€  € × €    € ÿÿÿÿ¤ÿÿÿÿ¬ù‚‚ðƒ‚€ˆ×†„‚ˆ€Ö†„‚‡×†„‚†Ø€ƒ…‚†Ø€ƒ…‚„„ׂ…‚„„ׂ…‚„€qˆwƒvl BŠvm²‚…‚„€¹ŽÄ²lŠÄµ²‚€„€¹ŽÄ²lŠÄµ²ƒƒ‡ƒ€¹ŽÄ²lŠÄµ²ƒ‚ˆ,QžÃˆÄ»oJ"‚J}´„ļs=²„‚€‡‚d‡ÄÀB‰±‚Ä™¶Š€‡ƒ€’†Ä»/‰¡Ä°°„‰€>¼†ÄM‰ ¼€Ä¿L°„‰€‚‡€¡†Äž‰RÄ—±ƒ…‚€‚€€[‡Ä ‡ž€ÄÂ6³ƒ…‚†€‚¶†Äf†)¶€Äˆ ³‚„‚†ƒ{†Äž…`ÃÄÄÀ8´‚„‚…€„7¾…ÄÂ;…  €Ä¨€ƒ€€ƒ‚…€„­†ÄŽ…1€Ä¿=¨ƒƒ€ƒ‚€€„€…]†Ä·ƒƒ€Ä’ ¨‚€Œ‚Š‚ˆ$Ay¹‚ÄÃZ‚!­€ÄFª€Œ‚Œ€Œƒ‚ĘXÃÄÄ­«‚ƒ€ƒŒˆ zÃÄ/¦ÄÄÃUª‚‚€‚€ˆˆ ¬Ä|5€Ä¤ª‚‚€‚€ƒ‹‚SÄ­~€Äaª€‚‚‚ƒ€Š‚¯€Ä ÂP"°ÄĹª€‚‚‚ƒ€Š€ ŠÄ“a€Äq©‚‚ƒ€ƒƒ€p‚Ä$²ÄĶ,ª‚‚ƒ€ƒƒ€W‚Äm;ÂÄÄŽ¢ƒ„‚‚ˆ€€‚F‚ı¨€Ä6 ƒ€„‚‚ˆ‚€€F†Ä—ŸŠ€„‚ƒ‚ˆ€ƒI…ÄÂUž€ƒ€‚ƒ‚ƒ‚‰€‚€€_…ĸ‚‚ƒ‚•ƒ€y…Ät€‚ƒ‚—ƒ‘…Ä>€€‚ƒ‚ƒŽ†€&¶…Ĉ€œ€‚ƒˆˆ†€h†Ä¹›€‚ƒ‚„ˆ†€l†ÄÃY€š€‚‚ƒƒ€‡€ƒ€‚&»†Ä—š‚„€„€‡‰ Œ†ÄÀ0›€‚€…€…І€O‡Ä€œ€‚‚€…† ‡‚‚‡Ä®œ‚‚€…† †ƒ‚a‡ÄÀRœƒ€†ˆ …ƒ€ƒžˆÄ• …„‘ „ƒƒEŠÄ(ž‚†‘ „ƒƒœŠÄsœˆ‘ „ƒ„0»ŠÄ¥›€€‡‚ „„ƒt€Ävˆ†ÄÀI™€€‡‚‚ƒˆ€„‚€µÄÄ»'C¿†Ä•™‚Šƒƒ‡ €„ƒW€ÄŠ ¥‡Ä™‰ƒ„‚†€†‚  €ÄMp‡Äi˜Š†ƒ…€Œ @¼ÄÄ¿ )À†Äž™Š€—‚‚‰ˆ€Ä “†ÄÂ?™Š˜ˆ‰ #ÀÄĽ6S†đš‰–  „‰p€Ä™´†Ä½˜€‚‚ƒŠ€   €€¦€Äaƒ††ÄÃ^–€‚ƒ‹    €„ƒW€Äƒ8‡Ä™–€€€‚ƒ€€     ƒ‚°€ÄŽƒž‡Ä7•€„€‚‚ƒ€    ‚€>€ÄÂNƒg‡Ä„•€†€€‚‚    ‚ ˆ€Ä¬…#À†Ä²”€†€ˆ„   €€0¼€Äˆ††ÄÂX“…€ˆ€†€€     €€€~Ä@‡M‡Ä™ ”„€Š€€‚    € ¹€Ä±‡¨‡Ä2”‚‰ƒ€€€%    eÀÄ}‡}‡Ä”‚ˆƒƒ!     ¬€Ä¾Eˆ3‡Ä¬ •†‘€   €  \IJˆ©†ÄÃU•€€‚’€!     ªÄ“ˆb‡Ä¦•ˆˆ€‚&  &  \ÀÄY‰0·‡Ä?–†‰ƒ  +    &¹‚ÄN‡&°‡ÄŸ–‡‡‚  &1 '$  :©ƒÄˆ†gÀˆÄ›”‰…‚€ )8#3"  €}®…Äî•wj"‚;|§Â‹ÄÂn8“‰…€#,D,;  »‹ÄM‚{‘Ä—†…€&  ,!6SD8% »‹ÄM‚{‘Ä—‰„€$ #(.6=`T71& »‹ÄM‚{‘Ä—‹„€" &9FK„†/@/ 4€6€5…4‚ ‹3ƒ2 –…$ %,,1W¨”dB" ƒ‹¬†€ !0Ik¨äÕh3 „Ь‡ /S¥úÏe@* „Š­Œ‡€ %1Lt‰ÍÙY70(" €††¬Œ…+ ,=B9V¬‚f0 „‹¥‹„€'  (,'!,T`UF: …ˆ¥‰„€! 3:M887& ‚€„ˆ£‡… $*.C.,%) €ˆŠž‡‡  ,&0) !€ €ˆ‹šŠ‡€€ € %%&% €€€€ˆ™Š‡ € € €  ! €‰ŒšŠ‡ƒ ‚   ‘‹›‹…€€†  Ž›‹„Š    ŒŽ›‹„€   €  €€…›Š…€€    €€’›‰„Œ  €€–œ‡ˆ…€       €†•†ˆ€€€€  € € €†”†Š‰    €†‘Ÿ…—   €„„†¢ƒ—   ƒ„€‚¥˜    „„¦€˜   ‚‰¯ƒ‡„€  €ˆ°‚€€‚€ €€€‰°Ž€€€# НŽ$ „Н‘€ € €„‹°Ž€€  € €€ƒ‹±€„€„‚‚³‹€€€€„€€¶‰€ €€€‚…€½ˆ€ €€……¾†€€€†€€À„‚‹€Ä‚€‚‹€È€€ €€‹Ì€ €€‚Ñ€€ƒ€„€×€ ‚ÿÿÿÿ¤t8mk@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿglbsp-2.24-source/gui/glBSPX.app/Contents/Info.plist0000644000175000017500000000165010514052721021532 0ustar aaptedaapted CFBundleInfoDictionaryVersion 6.0 CFBundleExecutable glBSPX CFBundleIconFile glbspx.icns CFBundleIdentifier gnu.glbspx CFBundleName glBSPX CFBundleDisplayName glBSPX CFBundlePackageType APPL CFBundleSignature ???? CFBundleVersion 2.0.5e CFBundleShortVersionString 2.0.5 CFBundleGetInfoString 2.0.5 © Andrew Apted 2005 NSHumanReadableCopyright © Andrew Apted 2005 glbsp-2.24-source/gui/glBSPX.app/Contents/PkgInfo0000644000175000017500000000001010514052721021027 0ustar aaptedaaptedAPPL????glbsp-2.24-source/gui/helper.cc0000644000175000017500000001150010650405206015671 0ustar aaptedaapted//------------------------------------------------------------------------ // HELPER : Unix/FLTK Little Helpers... //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "local.h" #ifdef WIN32 #include #else #include #endif // // HelperCaseCmp // int HelperCaseCmp(const char *A, const char *B) { for (; *A && *B; A++, B++) { if (toupper(*A) != toupper(*B)) return (toupper(*A) - toupper(*B)); } return (*A) ? 1 : (*B) ? -1 : 0; } // // HelperCaseCmpLen // // Like the above routine, but compares no more than 'len' characters // at the start of each string. // int HelperCaseCmpLen(const char *A, const char *B, int len) { for (; *A && *B && (len > 0); A++, B++, len--) { if (toupper(*A) != toupper(*B)) return (toupper(*A) - toupper(*B)); } if (len == 0) return 0; return (*A) ? 1 : (*B) ? -1 : 0; } // // HelperGetMillis // // Be sure to handle the result overflowing (it WILL happen !). // unsigned int HelperGetMillis() { #ifdef WIN32 unsigned long ticks = GetTickCount(); return (unsigned int) ticks; #else struct timeval tm; gettimeofday(&tm, NULL); return (unsigned int) ((tm.tv_sec * 1000) + (tm.tv_usec / 1000)); #endif } // // HelperFilenameValid // boolean_g HelperFilenameValid(const char *filename) { if (! filename) return FALSE; int len = strlen(filename); if (len == 0) return FALSE; #ifdef WIN32 // check drive letter if (len >= 2 && filename[1] == ':') { if (! isalpha(filename[0])) return FALSE; if (len == 2) return FALSE; } #endif switch (filename[len - 1]) { case '.': case '/': case '\\': return FALSE; default: break; } return TRUE; } // // HelperHasExt // boolean_g HelperHasExt(const char *filename) { int A = strlen(filename) - 1; if (A > 0 && filename[A] == '.') return FALSE; for (; A >= 0; A--) { if (filename[A] == '.') return TRUE; if (filename[A] == '/') break; #ifdef WIN32 if (filename[A] == '\\' || filename[A] == ':') break; #endif } return FALSE; } // // HelperCheckExt // boolean_g HelperCheckExt(const char *filename, const char *ext) { int A = strlen(filename) - 1; int B = strlen(ext) - 1; for (; B >= 0; B--, A--) { if (A < 0) return FALSE; if (toupper(filename[A]) != toupper(ext[B])) return FALSE; } return (A >= 1) && (filename[A] == '.'); } // // HelperReplaceExt // // Returns NULL if the filename was NULL, otherwise returns a pointer // to a static buffer containing the new filename. // char *HelperReplaceExt(const char *filename, const char *ext) { char *dot_pos; static char buffer[512]; if (! filename || filename[0] == 0) return NULL; strcpy(buffer, filename); int len = strlen(buffer); if (HelperHasExt(filename)) { dot_pos = strrchr(buffer, '.'); if (dot_pos) dot_pos[1] = 0; } else { if (len > 0 && buffer[len-1] != '.') strcat(buffer, "."); } strcat(buffer, ext); return buffer; } // // HelperGuessOutput // // Computes an output filename given an input one. Returns NULL if // the filename was NULL, otherwise returns a pointer to a static // buffer containing the new filename. // char *HelperGuessOutput(const char *filename) { char *dot_pos; static char buffer[512]; if (! filename || filename[0] == 0) return NULL; strcpy(buffer, filename); dot_pos = strrchr(buffer, '.'); if (dot_pos) dot_pos[0] = 0; else dot_pos = buffer + strlen(buffer); // check for existing modification ("_b" etc) and update it when // found rather than getting level_b_b_b_b.wad :) dot_pos -= 2; if (dot_pos > buffer && dot_pos[0] == '_' && ('a' <= dot_pos[1] && dot_pos[1] <= 'z')) { if (dot_pos[1] == 'z') dot_pos[1] = 'a'; else dot_pos[1] += 1; } else { strcat(buffer, "_b"); } strcat(buffer, ".wad"); return buffer; } // // HelperFileExists // boolean_g HelperFileExists(const char *filename) { FILE *fp = fopen(filename, "rb"); if (fp) { fclose(fp); return TRUE; } return FALSE; } glbsp-2.24-source/gui/local.h0000644000175000017500000003426410650405206015362 0ustar aaptedaapted//------------------------------------------------------------------------ // LOCAL : Unix/FLTK local definitions //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_LOCAL_H__ #define __GLBSP_LOCAL_H__ // use this for inlining. Usually defined in the makefile. #ifndef INLINE_G #define INLINE_G /* nothing */ #endif // // INCLUDES // #include "glbsp.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MACOSX #include #endif #include #include #include #include #include #include // // MAIN // typedef struct guix_preferences_s { // main window position & size int win_x, win_y; int win_w, win_h; // positions & sizes of other windows int progress_x, progress_y; int dialog_x, dialog_y; int other_x, other_y; int manual_x, manual_y; int manual_w, manual_h; int manual_page; // warn about overwriting files boolean_g overwrite_warn; // warn about input file == output file boolean_g same_file_warn; // warn about missing extensions boolean_g lack_ext_warn; // filename for saving the log const char *save_log_file; } guix_preferences_t; extern guix_preferences_t guix_prefs; extern nodebuildinfo_t guix_info; extern volatile nodebuildcomms_t guix_comms; extern const nodebuildfuncs_t guix_funcs; void MainSetDefaults(void); // // ABOUT // extern const unsigned char about_image_pal[256 * 3]; extern const unsigned char about_image_data[]; #define ABOUT_IMG_W 190 #define ABOUT_IMG_H 190 // // BOOK // typedef struct book_page_s { // array of lines, ends with NULL. // Link lines start with '#L' and two decimal digits. // Paragraphcs start with '#P' and two digits, first digit is major // indent level, second digit is minor indent level. // const char ** text; } book_page_t; class Guix_Book : public Fl_Window { public: Guix_Book(); virtual ~Guix_Book(); // override resize method, reformat text virtual FL_EXPORT void resize(int,int,int,int); // child widgets Fl_Group *group; Fl_Button *quit; Fl_Button *contents; Fl_Button *next; Fl_Button *prev; Fl_Hold_Browser *browser; boolean_g want_quit; int cur_page; // total number of pages ? int PageCount(); // load a new page into the browser. Updates 'page_num'. This // routine should be called shortly after construction, to display // the initial page. Zero will get the contents page. Invalid // page numbers will be safely ignored. // void LoadPage(int new_num); // take the appropriate action for the given line number. void FollowLink(int line); // handle various internal "to do" items. This is here since // modifying widgets (esp. clearing and adding lines to the hold // browser) from within their callbacks seems like a risky business // to me. Should be called in the Fl::wait() loop. // void Update(); // page to change to, otherwise BOOK_NO_PAGE int want_page; protected: boolean_g want_reformat; // initial window position and size int init_x, init_y; int init_w, init_h; // -- paragraph code -- boolean_g in_paragraph; boolean_g first_line; int major_indent; int minor_indent; char para_buf[1024]; int para_width; void ParaStart(); void ParaEnd(); void ParaAddWord(const char *word); void ParaAddLine(const char *line); }; #define BOOK_NO_PAGE -50 extern const book_page_t book_pages[]; extern Guix_Book * guix_book_win; class Guix_License : public Fl_Window { public: Guix_License(); virtual ~Guix_License(); // child widgets Fl_Group *group; Fl_Button *quit; Fl_Browser *browser; boolean_g want_quit; protected: // initial window position and size int init_x, init_y; int init_w, init_h; }; extern Guix_License * guix_lic_win; // // COOKIE // typedef enum { COOKIE_E_OK = 0, COOKIE_E_NO_FILE = 1, COOKIE_E_PARSE_ERRORS = 2, COOKIE_E_CHECK_ERRORS = 3 } cookie_status_t; void CookieSetPath(const char *argv0); cookie_status_t CookieReadAll(void); cookie_status_t CookieWriteAll(void); // // DIALOG // void DialogLoadImages(void); void DialogFreeImages(void); int DialogShowAndGetChoice(const char *title, Fl_Pixmap *pic, const char *message, const char *left = "OK", const char *middle = NULL, const char *right = NULL); int DialogQueryFilename(const char *message, const char ** name_ptr, const char *guess_name); void GUI_FatalError(const char *str, ...); // // FILES // class Guix_FileBox : public Fl_Group { public: Guix_FileBox(int x, int y, int w, int h); virtual ~Guix_FileBox(); // child widgets in File area Fl_Box *in_label; Fl_Box *out_label; Fl_Input *in_file; Fl_Input *out_file; Fl_Output *out_gwa_file; Fl_Button *in_browse; Fl_Button *out_browse; Fl_Button *out_guess; // filename to produce when in GWA mode. const char *gwa_filename; // group for file boxes, to handle resizing properly. Fl_Group *file_group; // routine to set the input widgets based on the build-info. void ReadInfo(); // routine to change the build-info to match the widgets. void WriteInfo(); // routine to call when GWA mode changes state. void GWA_Changed(); // routine to call when the in_file changes. It should compute // a new value for 'gwa_filename', and update the out_gwa_file // widget. // void InFileChanged(); // locking routine (see Guix_MainWin) void LockOut(boolean_g lock_it); }; class Guix_FactorBox : public Fl_Group { public: Guix_FactorBox(int x, int y, int w, int h); virtual ~Guix_FactorBox(); // child widget Fl_Counter *factor; // routine to set the input widget based on the build-info. void ReadInfo(); // routine to change the build-info to match the input. void WriteInfo(); // locking routine (see Guix_MainWin) void LockOut(boolean_g lock_it); }; class Guix_BuildButton : public Fl_Group { public: Guix_BuildButton(int x, int y, int w, int h); virtual ~Guix_BuildButton(); // child widget Fl_Button *build; Fl_Button *stopper; // locking routine (see Guix_MainWin) void LockOut(boolean_g lock_it); }; #define ALERT_TXT "glBSP Alert" #define MISSING_COMMS "(Not Specified)" // // HELPER // int HelperCaseCmp(const char *A, const char *B); int HelperCaseCmpLen(const char *A, const char *B, int len); unsigned int HelperGetMillis(); boolean_g HelperFilenameValid(const char *filename); boolean_g HelperHasExt(const char *filename); boolean_g HelperCheckExt(const char *filename, const char *ext); char *HelperReplaceExt(const char *filename, const char *ext); char *HelperGuessOutput(const char *filename); boolean_g HelperFileExists(const char *filename); // // IMAGES // extern const char * pldie_image_data[]; extern const char * skull_image_data[]; extern Fl_Image * about_image; extern Fl_Pixmap * pldie_image; extern Fl_Pixmap * skull_image; // // LICENSE // extern const char *license_text[]; // // MENU // #define MANUAL_WINDOW_MIN_W 500 #define MANUAL_WINDOW_MIN_H 200 #ifdef MACOSX Fl_Sys_Menu_Bar #else Fl_Menu_Bar #endif * MenuCreate(int x, int y, int w, int h); // // OPTIONS // class Guix_BuildMode : public Fl_Group { public: Guix_BuildMode(int x, int y, int w, int h); virtual ~Guix_BuildMode(); // child widgets: a set of radio buttons Fl_Button *gwa; Fl_Button *maybe_normal; Fl_Button *both; Fl_Button *gl_only; // this routine sets one of the radio buttons on, based on the given // build-information. // void ReadInfo(); // this routine does the reverse, setting the 'gwa_mode', 'no_normal' // and 'force_normal' fields based on which radio button is currently // active. // void WriteInfo(); // locking routine (see Guix_MainWin) void LockOut(boolean_g lock_it); }; class Guix_MiscOptions : public Fl_Group { public: Guix_MiscOptions(int x, int y, int w, int h); virtual ~Guix_MiscOptions(); // child widgets: a set of toggle buttons Fl_Button *choose_fresh; Fl_Button *warnings; Fl_Button *no_reject; Fl_Button *pack_sides; // routine to set the buttons based on the build-info. void ReadInfo(); // routine to change the build-info to match the buttons. void WriteInfo(); // routine to call when GWA mode changes state. void GWA_Changed(); // locking routine (see Guix_MainWin) void LockOut(boolean_g lock_it); }; // // PREFS // class Guix_PrefWin : public Fl_Window { public: // constructor reads the guix_pref values. // destructor writes them. Guix_PrefWin(); virtual ~Guix_PrefWin(); boolean_g want_quit; // child widgets Fl_Group *groups[3]; Fl_Button *overwrite; Fl_Button *same_file; Fl_Button *lack_ext; // color stuff ?? Fl_Button *reset_all; Fl_Button *quit; // routine called by "reset all" button void PrefsChanged(); protected: // initial window position int init_x, init_y; }; extern Guix_PrefWin * guix_pref_win; // // PROGRESS // typedef struct guix_bar_s { // widgets Fl_Box *label; Fl_Slider *slide; Fl_Box *perc; // current string for bar const char *lab_str; // string buffer for percentage char perc_buf[16]; int perc_shown; // current percentage shown (avoid updating widget) } guix_bar_t; class Guix_ProgressBox : public Fl_Group { public: Guix_ProgressBox(int x, int y, int w, int h); virtual ~Guix_ProgressBox(); // child widgets guix_bar_t bars[2]; Fl_Group *group; // current message strings const char *title_str; // current number of bars (READ ONLY from outside) int curr_bars; // sets the number of active bars. Must be 1 or 2. void SetBars(int num); // clear the progress bars (e.g. when stopped by user) void ClearBars(void); // set the short name of the bar void SetBarName(int which, const char *label_short); protected: // initial window position int init_x, init_y; void CreateOneBar(guix_bar_t& bar, int x, int y, int w, int h); void SetupOneBar(guix_bar_t& bar, int y, const char *label_short, Fl_Color col); }; void GUI_Ticker(void); boolean_g GUI_DisplayOpen(displaytype_e type); void GUI_DisplaySetTitle(const char *str); void GUI_DisplaySetBar(int barnum, int count); void GUI_DisplaySetBarLimit(int barnum, int limit); void GUI_DisplaySetBarText(int barnum, const char *str); void GUI_DisplayClose(void); // // TEXTBOX // class Guix_TextBox : public Fl_Multi_Browser { public: Guix_TextBox(int x, int y, int w, int h); virtual ~Guix_TextBox(); // adds the message to the text box. The message may contain // newlines ('\n'). The message doesn't need a trailing '\n', i.e. // it is implied. // void AddMsg(const char *msg, Fl_Color col = FL_BLACK, boolean_g bold = FALSE); // add a horizontal dividing bar void AddHorizBar(); // routine to clear the text box void ClearLog(); // routine to save the log to a file. Will overwrite the file if // already exists. Returns TRUE if successful or FALSE on error. // boolean_g SaveLog(const char *filename); // locking routine (see Guix_MainWin) void LockOut(boolean_g lock_it); }; void GUI_PrintMsg(const char *str, ...); // // WINDOW // #define MAIN_BG_COLOR fl_gray_ramp(FL_NUM_GRAY * 9 / 24) #define MAIN_WINDOW_MIN_W 540 #define MAIN_WINDOW_MIN_H 450 class Guix_MainWin : public Fl_Window { public: Guix_MainWin(const char *title); virtual ~Guix_MainWin(); // main child widgets #ifdef MACOSX Fl_Sys_Menu_Bar *menu_bar; #else Fl_Menu_Bar *menu_bar; #endif Guix_BuildMode *build_mode; Guix_MiscOptions *misc_opts; Guix_FactorBox *factor; Guix_FileBox *files; Guix_ProgressBox *progress; Guix_BuildButton *builder; Guix_TextBox *text_box; // user closed the window boolean_g want_quit; // routine to capture the current main window state into the // guix_preferences_t structure. // void WritePrefs(); // this routine is useful if the nodebuildinfo has changed. It // causes all the widgets to update themselves using the new // parameters. // void ReadAllInfo(); // routine to capture all of the nodebuildinfo state from the // various widgets. Note: don't need to call this before // destructing everything -- the widget destructors will do it // automatically. // void WriteAllInfo(); // this routine will update the user interface to prevent the user // from modifying most of the widgets (used during building). When // 'lock_it' is FALSE, we are actually unlocking a previous lock. // void LockOut(boolean_g lock_it); protected: // initial window size, read after the window manager has had a // chance to move the window somewhere else. If the window is still // there when CaptureState() is called, we don't need to update the // coords in the cookie file. // int init_x, init_y, init_w, init_h; }; extern Guix_MainWin * guix_win; void WindowSmallDelay(void); #endif /* __GLBSP_LOCAL_H__ */ glbsp-2.24-source/gui/cookie.cc0000644000175000017500000003353210650405205015673 0ustar aaptedaapted//------------------------------------------------------------------------ // COOKIE : Unix/FLTK Persistence (INI/RC files) //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" #define DEBUG_COOKIE 0 static const char *cookie_filename; // current section parser func static boolean_g (* cookie_section_parser) (const char *name, const char *value) = NULL; static void CookieDebug(const char *str, ...) { #if DEBUG_COOKIE char buffer[2048]; va_list args; va_start(args, str); vsprintf(buffer, str, args); va_end(args); fprintf(stderr, "COOKIE: %s", buffer); #else (void) str; #endif } static boolean_g SetBooleanVar(boolean_g& var, const char *value) { if (strchr(value, '0')) { var = FALSE; return TRUE; } if (strchr(value, '1')) { var = TRUE; return TRUE; } // bad boolean value CookieDebug("Bad Boolean [%s]\n", value); return FALSE; } static boolean_g SetIntegerVar(int& var, const char *value) { var = strtol(value, NULL, 10); return TRUE; } static boolean_g SetStringVar(const char *& var, const char *value) { int len = strlen(value); char buffer[1024]; if (value[0] != '"' || len < 2 || value[len-1] != '"' || len > 1020) { CookieDebug("Bad String [%s]\n", value); return FALSE; } strncpy(buffer, value+1, len-2); buffer[len-2] = 0; GlbspFree(var); var = GlbspStrDup(buffer); return TRUE; } //------------------------------------------------------------------------ static boolean_g CookieSetBuildVar(const char *name, const char *value) { // file names and factor if (strcasecmp(name, "in_file") == 0) return SetStringVar(guix_info.input_file, value); if (strcasecmp(name, "out_file") == 0) return SetStringVar(guix_info.output_file, value); if (strcasecmp(name, "factor") == 0) return SetIntegerVar(guix_info.factor, value); // boolean values if (strcasecmp(name, "no_reject") == 0) return SetBooleanVar(guix_info.no_reject, value); if (strcasecmp(name, "mini_warnings") == 0) return SetBooleanVar(guix_info.mini_warnings, value); if (strcasecmp(name, "pack_sides") == 0) return SetBooleanVar(guix_info.pack_sides, value); // API change to main glbsp code: 'choose_fresh' --> 'fast'. if (strcasecmp(name, "choose_fresh") == 0) { if (! SetBooleanVar(guix_info.fast, value)) return FALSE; guix_info.fast = ! guix_info.fast; return TRUE; } // block limit if (strcasecmp(name, "block_limit") == 0) return SetIntegerVar(guix_info.block_limit, value); // build mode if (strcasecmp(name, "gwa_mode") == 0) return SetBooleanVar(guix_info.gwa_mode, value); if (strcasecmp(name, "no_normal") == 0) return SetBooleanVar(guix_info.no_normal, value); if (strcasecmp(name, "force_normal") == 0) return SetBooleanVar(guix_info.force_normal, value); // Unknown build variable ! CookieDebug("Unknown Build VAR [%s]\n", name); return FALSE; } static boolean_g CookieSetPrefVar(const char *name, const char *value) { // overwrite warning if (strcasecmp(name, "overwrite_warn") == 0) return SetBooleanVar(guix_prefs.overwrite_warn, value); // same file warning if (strcasecmp(name, "same_file_warn") == 0) return SetBooleanVar(guix_prefs.same_file_warn, value); // missing extension warning if (strcasecmp(name, "lack_ext_warn") == 0) return SetBooleanVar(guix_prefs.lack_ext_warn, value); // save log filename if (strcasecmp(name, "save_log_file") == 0) return SetStringVar(guix_prefs.save_log_file, value); // Unknown preference variable ! CookieDebug("Unknown Pref VAR [%s]\n", name); return FALSE; } static boolean_g CookieSetWinPosVar(const char *name, const char *value) { // main window position and size if (strcasecmp(name, "window_x") == 0) return SetIntegerVar(guix_prefs.win_x, value); if (strcasecmp(name, "window_y") == 0) return SetIntegerVar(guix_prefs.win_y, value); if (strcasecmp(name, "window_w") == 0) return SetIntegerVar(guix_prefs.win_w, value); if (strcasecmp(name, "window_h") == 0) return SetIntegerVar(guix_prefs.win_h, value); // other window positions if (strcasecmp(name, "progress_x") == 0) return SetIntegerVar(guix_prefs.progress_x, value); if (strcasecmp(name, "progress_y") == 0) return SetIntegerVar(guix_prefs.progress_y, value); if (strcasecmp(name, "dialog_x") == 0) return SetIntegerVar(guix_prefs.dialog_x, value); if (strcasecmp(name, "dialog_y") == 0) return SetIntegerVar(guix_prefs.dialog_y, value); if (strcasecmp(name, "other_x") == 0) return SetIntegerVar(guix_prefs.other_x, value); if (strcasecmp(name, "other_y") == 0) return SetIntegerVar(guix_prefs.other_y, value); // manual window positions if (strcasecmp(name, "manual_x") == 0) return SetIntegerVar(guix_prefs.manual_x, value); if (strcasecmp(name, "manual_y") == 0) return SetIntegerVar(guix_prefs.manual_y, value); if (strcasecmp(name, "manual_w") == 0) return SetIntegerVar(guix_prefs.manual_w, value); if (strcasecmp(name, "manual_h") == 0) return SetIntegerVar(guix_prefs.manual_h, value); if (strcasecmp(name, "manual_page") == 0) return SetIntegerVar(guix_prefs.manual_page, value); // Unknown window pos variable ! CookieDebug("Unknown WindowPos VAR [%s]\n", name); return FALSE; } //------------------------------------------------------------------------ // returns TRUE if line parsed OK. Note: modifies the buffer. static boolean_g CookieParseLine(char *buf) { char *name; int len; while (isspace(*buf)) buf++; // blank line ? if (*buf == 0) return TRUE; // remove trailing whitespace len = strlen(buf); while (len > 0 && isspace(buf[len-1])) buf[--len] = 0; CookieDebug("PRE-PARSE: '%s'\n", buf); // comment ? if (*buf == '#') return TRUE; // section ? if (*buf == '[') { if (strncasecmp(buf+1, "BUILD_INFO]", 11) == 0) { cookie_section_parser = CookieSetBuildVar; return TRUE; } if (strncasecmp(buf+1, "PREFERENCES]", 12) == 0) { cookie_section_parser = CookieSetPrefVar; return TRUE; } if (strncasecmp(buf+1, "WINDOW_POS]", 11) == 0) { cookie_section_parser = CookieSetWinPosVar; return TRUE; } // unknown section ! cookie_section_parser = NULL; CookieDebug("Unknown Section: %s\n", buf); return FALSE; } if (! isalpha(*buf)) return FALSE; // Righteo, line starts with an identifier. It should be of the // form "name = value". We'll terminate the identifier, and pass // the name/value strings to a section-dependent handler. name = buf; buf++; for (buf++; isalpha(*buf) || *buf == '_'; buf++) { /* nothing here */ } while (isspace(*buf)) *buf++ = 0; if (*buf != '=') return FALSE; *buf++ = 0; while (isspace(*buf)) buf++; if (*buf == 0) return FALSE; CookieDebug("Name: [%s] Value: [%s]\n", name, buf); if (cookie_section_parser) { return (* cookie_section_parser)(name, buf); } // variables were found outside of any section return FALSE; } // // CookieCheckEm // // Increments 'problems' each time something is fixed up. // void CookieCheckEm(int& problems) { // check main window size if (guix_prefs.win_w < MAIN_WINDOW_MIN_W) { guix_prefs.win_w = MAIN_WINDOW_MIN_W; problems++; } if (guix_prefs.win_h < MAIN_WINDOW_MIN_H) { guix_prefs.win_h = MAIN_WINDOW_MIN_H; problems++; } // check manual/license window size if (guix_prefs.manual_w < MANUAL_WINDOW_MIN_W) { guix_prefs.manual_w = MANUAL_WINDOW_MIN_W; problems++; } if (guix_prefs.manual_h < MANUAL_WINDOW_MIN_H) { guix_prefs.manual_h = MANUAL_WINDOW_MIN_H; problems++; } if (guix_info.factor > 32) { guix_info.factor = 32; problems++; } } // // CookieSetPath // // Determine the path and filename of the cookie file. // void CookieSetPath(const char *argv0) { if (cookie_filename) GlbspFree(cookie_filename); char buffer[1024]; buffer[0] = 0; #if defined(WIN32) if (HelperFilenameValid(argv0)) { strcpy(buffer, HelperReplaceExt(argv0, "ini")); } else strcpy(buffer, "glBSPX.ini"); #elif defined(MACOSX) if (getenv("HOME")) { strcpy(buffer, getenv("HOME")); strcat(buffer, "/Library/Preferences/"); } strcat(buffer, "glBSPX.rc"); #else // LINUX if (getenv("HOME")) { strcpy(buffer, getenv("HOME")); strcat(buffer, "/"); } // backwards compatibility (glbspX != glBSPX) strcat(buffer, ".glbspX_rc"); if (! HelperFileExists(buffer)) { char *bsp = strrchr(buffer, 'b'); if (bsp) strncpy(bsp, "BSP", 3); } #endif cookie_filename = GlbspStrDup(buffer); CookieDebug("CookieFilename: '%s'\n", cookie_filename); } // // CookieReadAll // // Reads the cookie file. // Returns one of the COOKIE_E_* values. // // All the variables that can be read here should be initialised to // default values before calling, in case we fail or the variable is // missing in the cookie file. // cookie_status_t CookieReadAll(void) { CookieDebug("CookieReadAll BEGUN.\n"); // open file for reading FILE *fp = fopen(cookie_filename, "r"); if (! fp) return COOKIE_E_NO_FILE; cookie_section_parser = NULL; // simple line-by-line parser char buffer[2048]; int parse_probs = 0; int check_probs = 0; while (fgets(buffer, sizeof(buffer) - 2, fp)) { if (! CookieParseLine(buffer)) parse_probs += 1; } CookieCheckEm(check_probs); CookieDebug("CookieReadAll DONE. %d ParseProbs %d CheckProbs\n", parse_probs, check_probs); // parsing problems take precedence if (parse_probs > 0) return COOKIE_E_PARSE_ERRORS; if (check_probs > 0) return COOKIE_E_CHECK_ERRORS; return COOKIE_E_OK; } //------------------------------------------------------------------------ static void CookieWriteHeader(FILE *fp) { fprintf(fp, "# GLBSPX %s Persistent Data\n", GLBSP_VER); fprintf(fp, "# Editing this file by hand is not recommended.\n"); fprintf(fp, "\n"); fflush(fp); } static void CookieWriteBuildInfo(FILE *fp) { // identifying section fprintf(fp, "[BUILD_INFO]\n"); // file names fprintf(fp, "in_file = \"%s\"\n", guix_info.input_file ? guix_info.input_file : ""); fprintf(fp, "out_file = \"%s\"\n", guix_info.output_file ? guix_info.output_file : ""); // factor fprintf(fp, "factor = %d\n", guix_info.factor); // boolean values fprintf(fp, "no_reject = %d\n", guix_info.no_reject ? 1 : 0); fprintf(fp, "mini_warnings = %d\n", guix_info.mini_warnings ? 1 : 0); fprintf(fp, "pack_sides = %d\n", guix_info.pack_sides ? 1 : 0); fprintf(fp, "choose_fresh = %d\n", guix_info.fast ? 0 : 1); // API change // block limit fprintf(fp, "block_limit = %d\n", guix_info.block_limit); // build-mode fprintf(fp, "gwa_mode = %d\n", guix_info.gwa_mode ? 1 : 0); fprintf(fp, "no_normal = %d\n", guix_info.no_normal ? 1 : 0); fprintf(fp, "force_normal = %d\n", guix_info.force_normal ? 1 : 0); // NOT HERE: // no_progress: not useful for GUI mode. // keep_sect, no_prune: not used in GUI mode (yet). // load_all: determined automatically. // keep a blank line between sections fprintf(fp, "\n"); fflush(fp); } static void CookieWritePrefs(FILE *fp) { // identifying section fprintf(fp, "[PREFERENCES]\n"); fprintf(fp, "overwrite_warn = %d\n", guix_prefs.overwrite_warn); fprintf(fp, "same_file_warn = %d\n", guix_prefs.same_file_warn); fprintf(fp, "lack_ext_warn = %d\n", guix_prefs.lack_ext_warn); fprintf(fp, "save_log_file = \"%s\"\n", guix_prefs.save_log_file ? guix_prefs.save_log_file : ""); fprintf(fp, "\n"); fflush(fp); } static void CookieWriteWindowPos(FILE *fp) { // identifying section fprintf(fp, "[WINDOW_POS]\n"); // main window position and size fprintf(fp, "window_x = %d\n", guix_prefs.win_x); fprintf(fp, "window_y = %d\n", guix_prefs.win_y); fprintf(fp, "window_w = %d\n", guix_prefs.win_w); fprintf(fp, "window_h = %d\n", guix_prefs.win_h); // other window positions fprintf(fp, "progress_x = %d\n", guix_prefs.progress_x); fprintf(fp, "progress_y = %d\n", guix_prefs.progress_y); fprintf(fp, "dialog_x = %d\n", guix_prefs.dialog_x); fprintf(fp, "dialog_y = %d\n", guix_prefs.dialog_y); fprintf(fp, "other_x = %d\n", guix_prefs.other_x); fprintf(fp, "other_y = %d\n", guix_prefs.other_y); fprintf(fp, "manual_x = %d\n", guix_prefs.manual_x); fprintf(fp, "manual_y = %d\n", guix_prefs.manual_y); fprintf(fp, "manual_w = %d\n", guix_prefs.manual_w); fprintf(fp, "manual_h = %d\n", guix_prefs.manual_h); fprintf(fp, "manual_page = %d\n", guix_prefs.manual_page); fprintf(fp, "\n"); fflush(fp); } // // CookieWriteAll // // Writes the cookie file. // Returns one of the COOKIE_E_* values. // cookie_status_t CookieWriteAll(void) { CookieDebug("CookieWriteAll BEGUN.\n"); // create file (overwrite if exists) FILE *fp = fopen(cookie_filename, "w"); if (! fp) return COOKIE_E_NO_FILE; CookieWriteHeader(fp); CookieWriteBuildInfo(fp); CookieWritePrefs(fp); CookieWriteWindowPos(fp); // all done fclose(fp); CookieDebug("CookieWriteAll DONE.\n"); return COOKIE_E_OK; } glbsp-2.24-source/gui/images.cc0000644000175000017500000001517110650405206015667 0ustar aaptedaapted//------------------------------------------------------------------------ // IMAGES : Unix/FLTK Image defs //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // These images are from DOOM II and are (C) id software. // //------------------------------------------------------------------------ #include "local.h" const char * pldie_image_data[] = { /* width height ncolors chars_per_pixel */ "35 43 52 1", /* colors */ " c None", "- c #6cb75f", "a c #64675b", "b c #64ad57", "c c #4b4430", "d c #1c2f14", "e c #579249", "f c #9b897b", "g c #a29885", "h c #4e833f", "i c #745f3a", "j c #81cc78", "k c #447434", "l c #ba8a5f", "m c #71706e", "n c #787878", "o c #9c744e", "p c #87e87f", "q c #687052", "r c #7fdc78", "s c #4e4e4e", "t c #c79268", "u c #3f3f3f", "v c #3f4923", "w c #343434", "x c #c72424", "y c #292929", "z c #670000", "Y c #817f66", "A c #654c30", "B c #a87f58", "C c #8a6844", "D c #6c5734", "E c #3a642f", "F c #2f5223", "G c #b6a594", "H c #b3835b", "I c #d89f73", "J c #293f1c", "K c #5f9f4e", "L c #58523e", "M c #957049", "N c #892121", "O c #575f44", "P c #d7b399", "Q c #c08e64", "R c #a87456", "S c #878a70", "T c #2f3a14", "V c #7b6449", "W c #74785b", "X c #74c368", /* pixels */ " GGGGG ", " GGPGGfaf ", " GGPPPGGmaf ", " gYfffgPGfsGg ", " ffAYVVYAGxfPf ", " YVAAAVVYYGffPx ", " AuusszxAVxVGg ", " mgfffQxxxsAVY ", " -jrr-KmmnnmNxnbjjjX-K ", " bjjjjI-rtIIKXjrrrXrpppr-K ", " bbXj--tPPIQMKjrrrrpjprjX-be ", " eKbbeelttHRMibjrrrrr-jjXXX-K ", " EkhktIItRMCih-rrrrr-hFFEkhhkh ", " CMtIPIIHMiiihKXXXXXbkFciCoCCiE ", " MllIIIIHMVkheKXKhkEEFFdcCQIloBE ", " MSBQQHoCDhKXrXrXbKehkFdcotIIBB ", " WSBRMVVDkeeNKrbRNe-KhEJdoQIIlB ", " qWCViDDkK-XrpppPXXkzhkFJiBBQQB ", " OqqDDzkeehkEEFFFEhebKkEFDCooBRS ", " OOO zhksNNNNNNNNNEhbkEFVfGGgfY ", " zzzRHRRNRNNNszEeEFOoBolBW ", " uzqYMRRRRRMszzzdEd oQIIlo ", " OqYSqRRRCicDYWOzzdd oBIIQo ", " qSSgqMRRRRRCAOqSWFcO MQQHo ", " qSqggOAAAAAAAEqOYYkOOO MlBo ", " qqOOOOqWWWWWWWkEEOOFOsssMtIV ", " qhqOOFqYYYYYYWkhehksuswwHIto ", " hhhkkkOOOqqOOWKhKaasyyskDVHt ", " eheKeKbkOOOOOOe-amnmswwFECDHH ", " eb-bKXKEFJJJJFEssmmssuhEHoMHR ", " hKb-bXhhhEFJJsaswwysubKehiHQI ", " hKb---eeeEFdsaswwwywuKbbehEii ", " Kb---KKeEFsaswwwyyuuebbbbekEJ ", " hb-bb-KekEsaswwyyssueKbbbbbKhkF ", "ebKbbbb-bJFsywyyssuwkeKbbbbb-bkFF ", "ehbbbeebFksswyysuww FFK-bbbbK-beOW ", "EEeeeEEEhamasuwwwFyw F-bKbbKehbKSYW", "OqqqOEJammasuwwJFFyw -KeeehhkhESYW", "uOOOOOsmmsswwwddwww eehqqqqOOOqWO", "TvLLLsssswwww EFOOOOOOOOqqO", " TTTssswwwy TvLLLvvTvO ", " uwwww TTTTTTcA ", " sww " }; const char * skull_image_data[] = { /* width height ncolors chars_per_pixel */ "44 47 51 1", /* colors */ " c None", "z c #000000", "Y c #d00000", "b c #d37000", "c c #8e3b0b", "d c #756853", "e c #a33f00", "f c #957f6a", "g c #745f3a", "h c #a9947c", "i c #524929", "j c #c70000", "k c #d0bdaa", "l c #ca6800", "m c #a60000", "n c #cab7a3", "o c #f7a354", "p c #c0ad99", "q c #7f6c57", "r c #7f643f", "s c #f5d88f", "t c #5f4e2f", "u c #eb0000", "v c #f70000", "w c #e08021", "x c #bd0000", "y c #3a2f1c", "Z c #9c0000", "X c #99836f", "A c #780000", "B c #8a6844", "C c #6c5734", "D c #f18e2a", "E c #e20000", "F c #493f23", "G c #b30000", "H c #ffba7b", "I c #d97814", "J c #920000", "K c #766150", "L c #ba5a00", "M c #d90000", "N c #9f8a78", "P c #a37852", "Q c #8e7864", "R c #2f2314", "S c #870000", "T c #af8153", "U c #966e44", "V c #705b3f", "W c #b59f8b", /* pixels */ " Y ", " Y ", " YYj ", " uYj ", " MMYYY ", " ZGYjI ", " jZmljwZ ", " GGZIlwIju ", " ZjZwlIwGYjj ", " EGbYblYuuYvYjj ", " MEDZbwbubuuEMGju ", " xEIGGxbvIDwuvYxGY ", " jjDZxluMwHDwMubxI Z ", " ZjxMwvwDsHDwvbMDjZ ", " EGZYxEDvDossoDvlExwGGE ", " MMGZIxxovDHssHDIwxxMjGM ", " xMYZjDYxovwHHHHwwDxYYMZYM ", " jMlxvIxhbwDkkkkDDHhIbExlM ", " GGwYgYWpnkkkkkkkknpbIbEwGG ", "QX YjZDvYhWppnkkkkkknppWhwEDZjY XQ", "KQXWhhNffXNNTYhWppnkkkkkknppWhwTNNXffNhhWXQK", " KQXXNXfQQqqQfNWWppnnnnnnppWWNfQqqQQfXNXXQK ", " KqQQQfQQqqCQfNhWWppppppWWhNfQCqqQQfQQQqK ", " qqqeLlLeeqqQfNhhWWWWhhNfQqqeeLlLeqqq ", " KiiiJJKKqQfXXNNNNXXfQqKKJJiiiK ", " xgmJtVVKKKqqqqqqKKKVVtxmglZZ ", " ZZTbjyBCCCCggggggCCCCByjlIYZ ", " ZYlZSyPVVrrggggggrrVrPyAxMxZ ", " ZZSAyPrrBrrrrrrrrBrBPyAAZZ ", " jAyiPPPUUUUUUUUUUPPPiyAj ", " ZuSgPFFFCrrPPPPrrCFFFPgSuZ ", " ZSmiUALcRRRRFFRRRRcLAUimjZ ", " SYtrAcTsYRFTBFRYsTcArtiS ", " ZYiXJZYuSBTFiCTSuYZJXiiZ ", " ZZFfhTTTBPiziiCPTTThfFi ", " ZJFBCtCtirFFBFritCtCBFi ", " ZMZBCiiFtrBTTBrtFiiCBxu ", " jMAFFiirrrUrUrriiFAGIm ", " JuGJRitrTPTPTPTtiRGuYZ ", " AjbwTBlMszzsMlBTwbZZ ", " ASBCllzzzzzzlICByy ", " ygSJszzzzzzsJSgy ", " yyUJoJsJJsJoJUyy ", " idgJmjJJjmJgdi ", " irggrrrrggri ", " iCUPTTPUCi ", " iiiiiiii " }; glbsp-2.24-source/gui/prefs.cc0000644000175000017500000001127710650405207015545 0ustar aaptedaapted//------------------------------------------------------------------------ // PREFS : Unix/FLTK Preference Window //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" Guix_PrefWin *guix_pref_win; static void prefs_quit_CB(Fl_Widget *w, void *data) { if (guix_pref_win) guix_pref_win->want_quit = TRUE; } static void prefs_reset_all_CB(Fl_Widget *w, void *data) { MainSetDefaults(); if (guix_pref_win) guix_pref_win->PrefsChanged(); guix_win->ReadAllInfo(); } //------------------------------------------------------------------------ // // PrefWin Constructor // Guix_PrefWin::Guix_PrefWin() : Fl_Window(480, 290, "glBSP Preferences") { // cancel the automatic 'begin' in Fl_Group constructor end(); // non-resizable window size_range(w(), h(), w(), h()); position(guix_prefs.other_x, guix_prefs.other_y); want_quit = FALSE; // allow manual closing of window callback((Fl_Callback *) prefs_quit_CB); // create buttons in top row groups[0] = new Fl_Group(0, 0, w(), 110, "Pop-up dialog options:"); groups[0]->box(FL_THIN_UP_BOX); groups[0]->resizable(0); groups[0]->labelfont(FL_HELVETICA | FL_BOLD); groups[0]->labeltype(FL_NORMAL_LABEL); groups[0]->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_TOP); add(groups[0]); int CX = 20; int CY = 24; overwrite = new Fl_Check_Button(CX, CY, 22, 22, "Warn before overwriting files"); overwrite->down_box(FL_DOWN_BOX); overwrite->align(FL_ALIGN_RIGHT); overwrite->value(guix_prefs.overwrite_warn ? 1 : 0); groups[0]->add(overwrite); CY += 22; same_file = new Fl_Check_Button(CX, CY, 22, 22, "Warn if Input and Output files are the same"); same_file->down_box(FL_DOWN_BOX); same_file->align(FL_ALIGN_RIGHT); same_file->value(guix_prefs.same_file_warn ? 1 : 0); groups[0]->add(same_file); CY += 22; lack_ext = new Fl_Check_Button(CX, CY, 22, 22, "Warn about missing extensions (otherwise add the default)"); lack_ext->down_box(FL_DOWN_BOX); lack_ext->align(FL_ALIGN_RIGHT); lack_ext->value(guix_prefs.lack_ext_warn ? 1 : 0); groups[0]->add(lack_ext); CY += 22; // create reset button groups[1] = new Fl_Group(0, 110, w(), 120); groups[1]->box(FL_THIN_UP_BOX); groups[1]->resizable(0); add(groups[1]); reset_all = new Fl_Button((w() - 240) / 2, 180, 240, 26, "Reset All To Defaults"); reset_all->labelfont(FL_HELVETICA | FL_BOLD); reset_all->callback((Fl_Callback *) prefs_reset_all_CB); groups[1]->add(reset_all); Fl_Box *reset_txt = new Fl_Box(FL_FLAT_BOX, 20, 130, w() - 40, 46, "This button resets all user-changeable options to default " "values, including everything in the main window."); reset_txt->align(FL_ALIGN_LEFT | FL_ALIGN_TOP | FL_ALIGN_INSIDE | FL_ALIGN_WRAP); groups[1]->add(reset_txt); // create quit button groups[2] = new Fl_Group(0, 230, w(), 60); groups[2]->box(FL_THIN_UP_BOX); groups[2]->resizable(0); add(groups[2]); quit = new Fl_Button(w() - 100, h() - 40, 80, 26, "Close"); quit->callback((Fl_Callback *) prefs_quit_CB); groups[2]->add(quit); // show the window set_modal(); show(); // read initial pos (same logic as in Guix_MainWin) WindowSmallDelay(); init_x = x(); init_y = y(); } // // PrefWin Destructor // Guix_PrefWin::~Guix_PrefWin() { // write new preferences guix_prefs.overwrite_warn = overwrite->value() ? TRUE : FALSE; guix_prefs.same_file_warn = same_file->value() ? TRUE : FALSE; guix_prefs.lack_ext_warn = lack_ext->value() ? TRUE : FALSE; // update window_pos if user moved the window if (x() != init_x || y() != init_y) { guix_prefs.other_x = x(); guix_prefs.other_y = y(); } } void Guix_PrefWin::PrefsChanged() { overwrite->value(guix_prefs.overwrite_warn ? 1 : 0); overwrite->redraw(); same_file->value(guix_prefs.same_file_warn ? 1 : 0); same_file->redraw(); lack_ext->value(guix_prefs.lack_ext_warn ? 1 : 0); lack_ext->redraw(); } glbsp-2.24-source/gui/textbox.cc0000644000175000017500000001035110650405207016113 0ustar aaptedaapted//------------------------------------------------------------------------ // TEXTBOX : Unix/FLTK Text messages //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" // // TextBox Constructor // Guix_TextBox::Guix_TextBox(int x, int y, int w, int h) : Fl_Multi_Browser(x, y, w, h) { // cancel the automatic 'begin' in Fl_Group constructor // (it's an ancestor of Fl_Browser). end(); textfont(FL_COURIER); textsize(14); #ifdef MACOSX // the resize box in the lower right corner is a pain, it ends up // covering the text box scroll button. Luckily when both scrollbars // are active, FLTK leaves a square space in that corner and it // fits in nicely. has_scrollbar(BOTH_ALWAYS); #endif } // // TextBox Destructor // Guix_TextBox::~Guix_TextBox() { // nothing to do } void Guix_TextBox::AddMsg(const char *msg, Fl_Color col, // = FL_BLACK, boolean_g bold) // = FALSE) { const char *r; char buffer[2048]; int b_idx; // setup formatting string buffer[0] = 0; if (col != FL_BLACK) sprintf(buffer, "@C%d", col); if (bold) strcat(buffer, "@b"); strcat(buffer, "@."); b_idx = strlen(buffer); while ((r = strchr(msg, '\n')) != NULL) { strncpy(buffer+b_idx, msg, r - msg); buffer[b_idx + r - msg] = 0; if (r - msg == 0) { // workaround for FLTK bug strcpy(buffer+b_idx, " "); } add(buffer); msg = r+1; } if (strlen(msg) > 0) { strcpy(buffer+b_idx, msg); add(buffer); } // move browser to last line if (size() > 0) bottomline(size()); } void Guix_TextBox::AddHorizBar() { add(" "); add(" "); add("@-"); add(" "); add(" "); // move browser to last line if (size() > 0) bottomline(size()); } void Guix_TextBox::ClearLog() { clear(); } boolean_g Guix_TextBox::SaveLog(const char *filename) { FILE *fp = fopen(filename, "w"); if (! fp) return FALSE; for (int y=1; y <= size(); y++) { const char *L_txt = text(y); if (! L_txt) { fprintf(fp, "\n"); continue; } if (L_txt[0] == '@' && L_txt[1] == '-') { fprintf(fp, "--------------------------------"); fprintf(fp, "--------------------------------\n"); continue; } // remove any '@' formatting info while (*L_txt == '@') { L_txt++; if (*L_txt == 0) break; char fmt_ch = *L_txt++; if (fmt_ch == '.') break; // uppercase formatting chars (e.g. @C) have an int argument if (isupper(fmt_ch)) { while (isdigit(*L_txt)) L_txt++; } } fprintf(fp, "%s\n", L_txt); } fclose(fp); return TRUE; } void Guix_TextBox::LockOut(boolean_g lock_it) { // Don't need to lock the text box. This routine is for // completeness, e.g. in case some aspect of the text box should // actually be locked. } //------------------------------------------------------------------------ // // GUI_PrintMsg // void GUI_PrintMsg(const char *str, ...) { char buffer[2048]; va_list args; va_start(args, str); vsprintf(buffer, str, args); va_end(args); // handle pre-windowing text (ShowOptions and friends) if (! guix_win) { printf("%s", buffer); fflush(stdout); return; } if (strncmp(buffer, "ATTENTION", 9) == 0) guix_win->text_box->AddMsg(buffer, FL_RED, TRUE); else if (strncmp(buffer, "Warning", 7) == 0) guix_win->text_box->AddMsg(buffer, FL_RED); else guix_win->text_box->AddMsg(buffer); } glbsp-2.24-source/gui/license.cc0000644000175000017500000004262110650405206016044 0ustar aaptedaapted//------------------------------------------------------------------------ // LICENSE : Unix/FLTK Formatted GPL //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" const char *license_text[] = { "", "@c@b@l GNU GENERAL PUBLIC LICENSE", "", "@c@b@m Version 2, June 1991", "", "@c Copyright (C) 1989, 1991 Free Software Foundation, Inc.", "@c 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA", "@c Everyone is permitted to copy and distribute verbatim copies", "@c of this license document, but changing it is not allowed.", "", "", "@-", "", "", "@c@b Preamble", "", "@c The licenses for most software are designed to take away your", "@c freedom to share and change it. By contrast, the GNU General Public", "@c License is intended to guarantee your freedom to share and change free", "@c software--to make sure the software is free for all its users. This", "@c General Public License applies to most of the Free Software", "@c Foundation's software and to any other program whose authors commit to", "@c using it. (Some other Free Software Foundation software is covered by", "@c the GNU Library General Public License instead.) You can apply it to", "@c your programs, too.", "", "@c When we speak of free software, we are referring to freedom, not", "@c price. Our General Public Licenses are designed to make sure that you", "@c have the freedom to distribute copies of free software (and charge for", "@c this service if you wish), that you receive source code or can get it", "@c if you want it, that you can change the software or use pieces of it", "@c in new free programs; and that you know you can do these things.", "", "@c To protect your rights, we need to make restrictions that forbid", "@c anyone to deny you these rights or to ask you to surrender the rights.", "@c These restrictions translate to certain responsibilities for you if you", "@c distribute copies of the software, or if you modify it.", "", "@c For example, if you distribute copies of such a program, whether", "@c gratis or for a fee, you must give the recipients all the rights that", "@c you have. You must make sure that they, too, receive or can get the", "@c source code. And you must show them these terms so they know their", "@c rights.", "", "@c We protect your rights with two steps: (1) copyright the software, and", "@c (2) offer you this license which gives you legal permission to copy,", "@c distribute and/or modify the software.", "", "@c Also, for each author's protection and ours, we want to make certain", "@c that everyone understands that there is no warranty for this free", "@c software. If the software is modified by someone else and passed on, we", "@c want its recipients to know that what they have is not the original, so", "@c that any problems introduced by others will not reflect on the original", "@c authors' reputations.", "", "@c Finally, any free program is threatened constantly by software", "@c patents. We wish to avoid the danger that redistributors of a free", "@c program will individually obtain patent licenses, in effect making the", "@c program proprietary. To prevent this, we have made it clear that any", "@c patent must be licensed for everyone's free use or not licensed at all.", "", "@c The precise terms and conditions for copying, distribution and", "@c modification follow.", "", "", "@-", "", "", "@c@b@l GNU GENERAL PUBLIC LICENSE", "", "@c@b TERMS AND CONDITIONS FOR COPYING,", "@c@b DISTRIBUTION AND MODIFICATION", "", "@c 0. This License applies to any program or other work which contains", "@c a notice placed by the copyright holder saying it may be distributed", "@c under the terms of this General Public License. The \"Program\", below,", "@c refers to any such program or work, and a \"work based on the Program\"", "@c means either the Program or any derivative work under copyright law:", "@c that is to say, a work containing the Program or a portion of it,", "@c either verbatim or with modifications and/or translated into another", "@c language. (Hereinafter, translation is included without limitation in", "@c the term \"modification\".) Each licensee is addressed as \"you\".", "", "@c Activities other than copying, distribution and modification are not", "@c covered by this License; they are outside its scope. The act of", "@c running the Program is not restricted, and the output from the Program", "@c is covered only if its contents constitute a work based on the", "@c Program (independent of having been made by running the Program).", "@c Whether that is true depends on what the Program does.", "", "@c 1. You may copy and distribute verbatim copies of the Program's", "@c source code as you receive it, in any medium, provided that you", "@c conspicuously and appropriately publish on each copy an appropriate", "@c copyright notice and disclaimer of warranty; keep intact all the", "@c notices that refer to this License and to the absence of any warranty;", "@c and give any other recipients of the Program a copy of this License", "@c along with the Program.", "", "@c You may charge a fee for the physical act of transferring a copy, and", "@c you may at your option offer warranty protection in exchange for a fee.", "", "@c 2. You may modify your copy or copies of the Program or any portion", "@c of it, thus forming a work based on the Program, and copy and", "@c distribute such modifications or work under the terms of Section 1", "@c above, provided that you also meet all of these conditions:", "", "@c@s a) You must cause the modified files to carry prominent notices", "@c@s stating that you changed the files and the date of any change.", "", "@c@s b) You must cause any work that you distribute or publish, that in", "@c@s whole or in part contains or is derived from the Program or any", "@c@s part thereof, to be licensed as a whole at no charge to all third", "@c@s parties under the terms of this License.", "", "@c@s c) If the modified program normally reads commands interactively", "@c@s when run, you must cause it, when started running for such", "@c@s interactive use in the most ordinary way, to print or display an", "@c@s announcement including an appropriate copyright notice and a", "@c@s notice that there is no warranty (or else, saying that you provide", "@c@s a warranty) and that users may redistribute the program under", "@c@s these conditions, and telling the user how to view a copy of this", "@c@s License. (Exception: if the Program itself is interactive but", "@c@s does not normally print such an announcement, your work based on", "@c@s the Program is not required to print an announcement.)", "", "@c These requirements apply to the modified work as a whole. If", "@c identifiable sections of that work are not derived from the Program,", "@c and can be reasonably considered independent and separate works in", "@c themselves, then this License, and its terms, do not apply to those", "@c sections when you distribute them as separate works. But when you", "@c distribute the same sections as part of a whole which is a work based", "@c on the Program, the distribution of the whole must be on the terms of", "@c this License, whose permissions for other licensees extend to the", "@c entire whole, and thus to each and every part regardless of who wrote it.", "", "@c Thus, it is not the intent of this section to claim rights or contest", "@c your rights to work written entirely by you; rather, the intent is to", "@c exercise the right to control the distribution of derivative or", "@c collective works based on the Program.", "", "@c In addition, mere aggregation of another work not based on the Program", "@c with the Program (or with a work based on the Program) on a volume of", "@c a storage or distribution medium does not bring the other work under", "@c the scope of this License.", "", "@c 3. You may copy and distribute the Program (or a work based on it,", "@c under Section 2) in object code or executable form under the terms of", "@c Sections 1 and 2 above provided that you also do one of the following:", "", "@c@s a) Accompany it with the complete corresponding machine-readable", "@c@s source code, which must be distributed under the terms of Sections", "@c@s 1 and 2 above on a medium customarily used for software interchange; or,", "", "@c@s b) Accompany it with a written offer, valid for at least three", "@c@s years, to give any third party, for a charge no more than your", "@c@s cost of physically performing source distribution, a complete", "@c@s machine-readable copy of the corresponding source code, to be", "@c@s distributed under the terms of Sections 1 and 2 above on a medium", "@c@s customarily used for software interchange; or,", "", "@c@s c) Accompany it with the information you received as to the offer", "@c@s to distribute corresponding source code. (This alternative is", "@c@s allowed only for noncommercial distribution and only if you", "@c@s received the program in object code or executable form with such", "@c@s an offer, in accord with Subsection b above.)", "", "@c The source code for a work means the preferred form of the work for", "@c making modifications to it. For an executable work, complete source", "@c code means all the source code for all modules it contains, plus any", "@c associated interface definition files, plus the scripts used to", "@c control compilation and installation of the executable. However, as a", "@c special exception, the source code distributed need not include", "@c anything that is normally distributed (in either source or binary", "@c form) with the major components (compiler, kernel, and so on) of the", "@c operating system on which the executable runs, unless that component", "@c itself accompanies the executable.", "", "@c If distribution of executable or object code is made by offering", "@c access to copy from a designated place, then offering equivalent", "@c access to copy the source code from the same place counts as", "@c distribution of the source code, even though third parties are not", "@c compelled to copy the source along with the object code.", "", "@c 4. You may not copy, modify, sublicense, or distribute the Program", "@c except as expressly provided under this License. Any attempt", "@c otherwise to copy, modify, sublicense or distribute the Program is", "@c void, and will automatically terminate your rights under this License.", "@c However, parties who have received copies, or rights, from you under", "@c this License will not have their licenses terminated so long as such", "@c parties remain in full compliance.", "", "@c 5. You are not required to accept this License, since you have not", "@c signed it. However, nothing else grants you permission to modify or", "@c distribute the Program or its derivative works. These actions are", "@c prohibited by law if you do not accept this License. Therefore, by", "@c modifying or distributing the Program (or any work based on the", "@c Program), you indicate your acceptance of this License to do so, and", "@c all its terms and conditions for copying, distributing or modifying", "@c the Program or works based on it.", "", "@c 6. Each time you redistribute the Program (or any work based on the", "@c Program), the recipient automatically receives a license from the", "@c original licensor to copy, distribute or modify the Program subject to", "@c these terms and conditions. You may not impose any further", "@c restrictions on the recipients' exercise of the rights granted herein.", "@c You are not responsible for enforcing compliance by third parties to", "@c this License.", "", "@c 7. If, as a consequence of a court judgment or allegation of patent", "@c infringement or for any other reason (not limited to patent issues),", "@c conditions are imposed on you (whether by court order, agreement or", "@c otherwise) that contradict the conditions of this License, they do not", "@c excuse you from the conditions of this License. If you cannot", "@c distribute so as to satisfy simultaneously your obligations under this", "@c License and any other pertinent obligations, then as a consequence you", "@c may not distribute the Program at all. For example, if a patent", "@c license would not permit royalty-free redistribution of the Program by", "@c all those who receive copies directly or indirectly through you, then", "@c the only way you could satisfy both it and this License would be to", "@c refrain entirely from distribution of the Program.", "", "@c If any portion of this section is held invalid or unenforceable under", "@c any particular circumstance, the balance of the section is intended to", "@c apply and the section as a whole is intended to apply in other", "@c circumstances.", "", "@c It is not the purpose of this section to induce you to infringe any", "@c patents or other property right claims or to contest validity of any", "@c such claims; this section has the sole purpose of protecting the", "@c integrity of the free software distribution system, which is", "@c implemented by public license practices. Many people have made", "@c generous contributions to the wide range of software distributed", "@c through that system in reliance on consistent application of that", "@c system; it is up to the author/donor to decide if he or she is willing", "@c to distribute software through any other system and a licensee cannot", "@c impose that choice.", "", "@c This section is intended to make thoroughly clear what is believed to", "@c be a consequence of the rest of this License.", "", "@c 8. If the distribution and/or use of the Program is restricted in", "@c certain countries either by patents or by copyrighted interfaces, the", "@c original copyright holder who places the Program under this License", "@c may add an explicit geographical distribution limitation excluding", "@c those countries, so that distribution is permitted only in or among", "@c countries not thus excluded. In such case, this License incorporates", "@c the limitation as if written in the body of this License.", "", "@c 9. The Free Software Foundation may publish revised and/or new versions", "@c of the General Public License from time to time. Such new versions will", "@c be similar in spirit to the present version, but may differ in detail to", "@c address new problems or concerns.", "", "@c Each version is given a distinguishing version number. If the Program", "@c specifies a version number of this License which applies to it and \"any", "@c later version\", you have the option of following the terms and conditions", "@c either of that version or of any later version published by the Free", "@c Software Foundation. If the Program does not specify a version number of", "@c this License, you may choose any version ever published by the Free", "@c Software Foundation.", "", "@c 10. If you wish to incorporate parts of the Program into other free", "@c programs whose distribution conditions are different, write to the author", "@c to ask for permission. For software which is copyrighted by the Free", "@c Software Foundation, write to the Free Software Foundation; we sometimes", "@c make exceptions for this. Our decision will be guided by the two goals", "@c of preserving the free status of all derivatives of our free software and", "@c of promoting the sharing and reuse of software generally.", "", "@c@m NO WARRANTY", "", "@c@s 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY", "@c@s FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN", "@c@s OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES", "@c@s PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED", "@c@s OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF", "@c@s MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS", "@c@s TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE", "@c@s PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,", "@c@s REPAIR OR CORRECTION.", "", "@c@s 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING", "@c@s WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR", "@c@s REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,", "@c@s INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING", "@c@s OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED", "@c@s TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY", "@c@s YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER", "@c@s PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE", "@c@s POSSIBILITY OF SUCH DAMAGES.", "", "@c@b END OF TERMS AND CONDITIONS", "", NULL }; glbsp-2.24-source/gui/dialog.cc0000644000175000017500000002475110650405205015664 0ustar aaptedaapted//------------------------------------------------------------------------ // DIALOG : Unix/FLTK Pop-up dialogs //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" Fl_Image *about_image; Fl_Pixmap *pldie_image; Fl_Pixmap *skull_image; static unsigned char *about_image_rgb; static Fl_Window *cur_diag; static int cur_diag_result; static boolean_g cur_diag_done; static const char *cur_diag_guess_name; static void UncompressAboutImage(unsigned char *& rgb) { int rgb_size = ABOUT_IMG_W * ABOUT_IMG_H * 3; rgb = new unsigned char [rgb_size]; assert(rgb); const unsigned char *src = about_image_data; unsigned char *dest = rgb; while (dest < (rgb + rgb_size)) { int val = *src++; *dest++ = about_image_pal[val*3 + 0]; // red *dest++ = about_image_pal[val*3 + 1]; // green *dest++ = about_image_pal[val*3 + 2]; // blue } } // // DialogLoadImages // // Should be called after WindowStartup. // void DialogLoadImages(void) { pldie_image = new Fl_Pixmap(pldie_image_data); skull_image = new Fl_Pixmap(skull_image_data); // create about image UncompressAboutImage(about_image_rgb); about_image = new Fl_RGB_Image(about_image_rgb, ABOUT_IMG_W, ABOUT_IMG_H, 3, (ABOUT_IMG_W * 3)); } // // DialogFreeImages // void DialogFreeImages(void) { if (about_image_rgb) delete[] about_image_rgb; delete about_image; delete pldie_image; delete skull_image; } //------------------------------------------------------------------------ static void dialog_closed_CB(Fl_Widget *w, void *data) { cur_diag_result = -1; cur_diag_done = TRUE; } static void dialog_left_button_CB(Fl_Widget *w, void *data) { cur_diag_result = 0; cur_diag_done = TRUE; } static void dialog_middle_button_CB(Fl_Widget *w, void *data) { cur_diag_result = 1; cur_diag_done = TRUE; } static void dialog_right_button_CB(Fl_Widget *w, void *data) { cur_diag_result = 2; cur_diag_done = TRUE; } static void dialog_file_browse_CB(Fl_Widget *w, void *data) { Fl_Input *inp_box = (Fl_Input *) data; const char *new_name; new_name = fl_file_chooser("Select the log file", "*.log", inp_box->value()); // cancelled ? if (! new_name) return; inp_box->value(new_name); } static void dialog_file_guess_CB(Fl_Widget *w, void *data) { Fl_Input *inp_box = (Fl_Input *) data; if (cur_diag_guess_name) { inp_box->value(cur_diag_guess_name); } } //------------------------------------------------------------------------ static void DialogRun() { cur_diag->set_modal(); cur_diag->show(); // read initial pos (same logic as in Guix_MainWin) WindowSmallDelay(); int init_x = cur_diag->x(); int init_y = cur_diag->y(); // run the GUI and let user make their choice while (! cur_diag_done) { Fl::wait(); } // check if the user moved/resized the window if (cur_diag->x() != init_x || cur_diag->y() != init_y) { guix_prefs.dialog_x = cur_diag->x(); guix_prefs.dialog_y = cur_diag->y(); } } // // DialogShowAndGetChoice // // The 'pic' parameter is the picture to show on the left, or NULL for // none. The message can contain newlines. The right/middle/left // parameters allow up to three buttons. // // Returns the button number pressed (0 for right, 1 for middle, 2 for // left) or -1 if escape was pressed or window manually closed. // int DialogShowAndGetChoice(const char *title, Fl_Pixmap *pic, const char *message, const char *left, // = "OK", const char *middle, // = NULL, const char *right) // = NULL) { cur_diag_result = -1; cur_diag_done = FALSE; int but_width = right ? (120*3) : middle ? (120*2) : (120*1); // determine required size int width = 120 * 3; int height; // set current font for fl_measure() fl_font(FL_HELVETICA, FL_NORMAL_SIZE); fl_measure(message, width, height); if (width < but_width) width = but_width; if (height < 16) height = 16; width += 60 + 20 + 16; // 16 extra, just in case height += 10 + 40 + 16; // // create window cur_diag = new Fl_Window(0, 0, width, height, title); cur_diag->end(); cur_diag->size_range(width, height, width, height); cur_diag->callback((Fl_Callback *) dialog_closed_CB); cur_diag->position(guix_prefs.dialog_x, guix_prefs.dialog_y); // set the resizable Fl_Box *box = new Fl_Box(60, 0, width - 3*120, height); cur_diag->add(box); cur_diag->resizable(box); // create the image, if any if (pic) { box = new Fl_Box(5, 10, 50, 50); pic->label(box); cur_diag->add(box); } // create the message area box = new Fl_Box(60, 10, width-60 - 20, height-10 - 40, message); box->align(FL_ALIGN_LEFT | FL_ALIGN_TOP | FL_ALIGN_INSIDE | FL_ALIGN_WRAP); cur_diag->add(box); // create buttons Fl_Button *button; int CX = width - 120; int CY = height - 40; if (right) { button = new Fl_Return_Button(CX, CY, 104, 30, right); button->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); button->callback((Fl_Callback *) dialog_right_button_CB); cur_diag->add(button); CX -= 120; } if (middle) { button = new Fl_Button(CX, CY, 104, 30, middle); button->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); button->callback((Fl_Callback *) dialog_middle_button_CB); cur_diag->add(button); CX -= 120; } if (left) { button = new Fl_Button(CX, CY, 104, 30, left); button->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); button->callback((Fl_Callback *) dialog_left_button_CB); cur_diag->add(button); CX -= 120; } // show time ! DialogRun(); // delete window (automatically deletes child widgets) delete cur_diag; cur_diag = NULL; return cur_diag_result; } // // DialogQueryFilename // // Shows the current filename (name_ptr) in an input box, and provides // a browse button to choose a new filename, and an optional button to // guess the new filename (if 'guess_name' is NULL, then the button is // disabled). // // This routine does NOT ensure that the filename is valid (or any // other requirement, e.g. has a certain extension). // // Returns 0 if "OK" was pressed, 1 if "Cancel" was pressed, or -1 if // escape was pressed or the window was manually closed. // int DialogQueryFilename(const char *message, const char ** name_ptr, const char *guess_name) { cur_diag_result = -1; cur_diag_done = FALSE; cur_diag_guess_name = guess_name; // determine required size int width = 400; int height; // set current font for fl_measure() fl_font(FL_HELVETICA, FL_NORMAL_SIZE); fl_measure(message, width, height); if (width < 400) width = 400; if (height < 16) height = 16; width += 60 + 20 + 16; // 16 extra, just in case height += 60 + 50 + 16; // // create window cur_diag = new Fl_Window(0, 0, width, height, "glBSP Query"); cur_diag->end(); cur_diag->size_range(width, height, width, height); cur_diag->callback((Fl_Callback *) dialog_closed_CB); cur_diag->position(guix_prefs.dialog_x, guix_prefs.dialog_y); // set the resizable Fl_Box *box = new Fl_Box(0, height-1, width, 1); cur_diag->add(box); cur_diag->resizable(box); // create the message area box = new Fl_Box(14, 10, width-20 - 20, height-10 - 100, message); box->align(FL_ALIGN_LEFT | FL_ALIGN_TOP | FL_ALIGN_INSIDE | FL_ALIGN_WRAP); cur_diag->add(box); // create buttons int CX = width - 120; int CY = height - 50; Fl_Button *b_ok; Fl_Button *b_cancel; b_cancel = new Fl_Button(CX, CY, 104, 30, "Cancel"); b_cancel->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); b_cancel->callback((Fl_Callback *) dialog_middle_button_CB); cur_diag->add(b_cancel); CX -= 120; b_ok = new Fl_Return_Button(CX, CY, 104, 30, "OK"); b_ok->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); b_ok->callback((Fl_Callback *) dialog_left_button_CB); cur_diag->add(b_ok); // create input box Fl_Input *inp_box; CX = width - 120; CY = height - 100; inp_box = new Fl_Input(20, CY, CX - 20 - 90, 26); inp_box->value(*name_ptr); cur_diag->add(inp_box); // create the browse and guess button Fl_Button *b_browse; Fl_Button *b_guess; b_guess = new Fl_Button(CX, CY, 70, 26, "Guess"); b_guess->align(FL_ALIGN_INSIDE); b_guess->callback((Fl_Callback *) dialog_file_guess_CB, inp_box); cur_diag->add(b_guess); CX -= 85; b_browse = new Fl_Button(CX, CY, 80, b_guess->h(), "Browse"); b_browse->align(FL_ALIGN_INSIDE); b_browse->callback((Fl_Callback *) dialog_file_browse_CB, inp_box); cur_diag->add(b_browse); // show time ! DialogRun(); if (cur_diag_result == 0) { GlbspFree(*name_ptr); *name_ptr = GlbspStrDup(inp_box->value()); } // delete window (automatically deletes child widgets) delete cur_diag; cur_diag = NULL; return cur_diag_result; } // // GUI_FatalError // // Terminates the program reporting an error. // void GUI_FatalError(const char *str, ...) { char buffer[2048]; char main_err[2048]; char *m_ptr; // create message va_list args; va_start(args, str); vsprintf(main_err, str, args); va_end(args); // remove leading and trailing whitespace int len = strlen(main_err); for (; len > 0 && isspace(main_err[len-1]); len--) { main_err[len-1] = 0; } for (m_ptr = main_err; isspace(*m_ptr); m_ptr++) { /* nothing else needed */ } if (HelperCaseCmpLen(m_ptr, "Error: ", 7) == 0) m_ptr += 7; sprintf(buffer, "The following unexpected error occurred:\n" "\n" " %s\n" "\n" "This may indicate a serious problem within the WAD you " "were trying to build the nodes for. Check that the WAD " "file isn't corrupt.\n" "\n" "glBSPX will now shut down.", m_ptr); DialogShowAndGetChoice("glBSP Fatal Error", pldie_image, buffer); // Q/ save cookies ? // A/ no, we save them before each build begins. exit(5); } glbsp-2.24-source/gui/icon.xpm0000644000175000017500000000264510514052721015572 0ustar aaptedaapted/* XPM */ static char * glbsp_icon[] = { "32 32 16 1", " c None", ". c #000000", "+ c #1C1C0B", "@ c #115385", "# c #313520", "$ c #27260E", "% c #1A7BC2", "& c #E77609", "* c #733C03", "= c #A85504", "- c #7D7B23", "; c #614B12", "> c #71701C", ", c #A09836", "' c #F9F875", ") c #DAD83C", " ............ ", " ................ ", " .............+@@### $@@@$ ", " ..............+%%%%@.$%%%# ", " .................%%%...@% ", " ..................@%%+..%# ", " ...+&*#&&&$..*=*+**=-%@.#%. ", " ....&*.&**&+*=.=.*&+&-%.@$.. ", " .....&*.&*.&#=*.*+*&.=&%@%.... ", " +&==*&*.&*+&$=&$..*&.=&%%@.... ", ".==+&.&*.&&==.*&&*.*&.=-%%+.....", ".==.&.&*.&**&$+*&&+*&=&#%%@.....", ".*&*=.&*.&*.&*$+*&**&..+%%%.....", ".+=$..&*.&*.&==++&**&..@%%%#....", ".*&==.&*.&*#&*=*$&$*&.+%$%%%....", ".+&&&*==*&&=*$;==;$==*@@.@%%+...", ".=*.=*...+++$##;##$+++%#.#%%@...", ".=*.=#...++$##;;;##$+#%+..%%%...", ".+==*....++$#;>->;##+%@...@%%#..", "........++$$#;-,,>;#@%@+.+@%%%+.", "........++$#;>,')-;#%%%@.@%%%%%.", ".........++$#>)''-;#$++.........", " ........+$#;>)')-;#$++........ ", " .......++$#;;-),>##$++........ ", " ......++$$#;>->;#$+++....... ", " ......+++$$#;>;;#$++....... ", " ......+++$##;###$++....... ", " ......++$#####$$++...... ", " .....+++$$$$$$+++..... ", " .....+++$$$++++.... ", " ....++++++++.... ", " ..+.+++++... "}; glbsp-2.24-source/gui/booktext.cc0000644000175000017500000003617010651355630016271 0ustar aaptedaapted//------------------------------------------------------------------------ // BOOKTEXT : Unix/FLTK Manual Text //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "local.h" #define GRN "@C61" // selection looks bad, oh well static const char *contents_text[] = { "", "@c@l@b glBSPX Manual", "", "@-", "", "@r by Andrew Apted ", "@r Updated: JULY 2007 ", "", "@c@m Table of Contents", "", "#L01@c" GRN " 1. Introduction", "#L02@c" GRN " 2. Using glBSPX", "#L03@c" GRN " 3. Interaction with other tools", "#L04@c" GRN " 4. How glBSP Works", "#L05@c" GRN " 5. Differences to BSP 2.3", "#L06@c" GRN " 6. Contact and Links", "#L07@c" GRN " 7. Acknowledgements", NULL }; //------------------------------------------------------------------------ static const char *intro_text[] = { "", "@c@l 1. Introduction", "", "@-", "", "#P00", "glBSP is a nodes builder specially designed to be used with OpenGL-based", "DOOM game engines. It adheres to the \"GL-Friendly Nodes\"", "specification, which means it adds some new special nodes to a WAD", "file that makes it very easy for an OpenGL DOOM engine to", "compute the polygons needed for drawing the levels.", "", "#P00", "There are many DOOM ports that understand the GL Nodes which glBSP", "creates, including: EDGE, the Doomsday engine (JDOOM), Doom3D, PrBoom,", "ZDoomGL, Vavoom and Doom3D.#- See the Contact and Links page.", "", "#P00", "glBSPX is the GUI (graphical user interface) version, which runs", "in a window. There is also a command-line version called simply", "'glbsp', which is designed to be run from a DOS box (Windows)", "or a text terminal (Linux etc). ", "glBSPX lets you perform all the usual node-building jobs,", "though the command-line version supports some more (rarely-useful)", "options.", "", "@m Status:", "", "#P00", "The current version is 2.24. It has been tested and", "known to work on numerous large wads, including DOOM I, DOOM II,", "TeamTNT's Eternal III, Fanatic's QDOOM, and many others.", "", "@m Legal stuff:", "", "#P00", "glBSP and glBSPX are Copyright (C) 2000-2007 Andrew Apted. It", "was originally based on 'BSP 2.3' (C) Colin Reed and Lee Killough,", "which was created from the basic theory stated in DEU5 (OBJECTS.C)", "by Raphael Quinet.", "", "#P00", "This GUI version (glBSPX) is based in part on the work of the FLTK ", "project. See http://www.fltk.org.", "", "#P00", "glBSP and glBSPX are free software, under the GNU General Public License", "(GPL). Click on the the Help > License menu to see the full ", "text. In particular, there is ABSOLUTELY NO WARRANTY. USE AT", "YOUR OWN RISK.", "", " All trademarks are the propriety of their owners.", "", NULL }; //------------------------------------------------------------------------ static const char *using_text[] = { "", "@c@l 2. Using glBSPX", "", "@-", "", "#P00", "The way glBSP operates is pretty simple: it will load the input", "wad file, build the nodes for the levels that it finds, and then", "save to the output file. All this is triggered when you press", "on the big 'BUILD' button in the main window. ", "The 'Files' box let you specify the Input and Output filenames,", "and the other boxes let you control various aspects about the way", "nodes are built.", "", "#P00", "On the bottom of the main window is the text output box, which", "shows various messages during node building (stuff that the", "command-line version normally prints in the terminal or DOS box). ", "Watch out for warning messages, which appear in a red font, they", "can indicate serious problems that were found in your levels.", "", "@m Build Modes", "", "#P00", "There are five different build modes in glBSPX, which can be", "selected in the upper left box in the main window.", "Here is a description of them:", "", "@t GWA Mode", "#P20", "Use this mode for general use, e.g you've downloaded a normal", "DOOM wad and wish to play it with an OpenGL DOOM engine", "(one which is GLBSP-aware, of course). ", "This mode will put all the GL Nodes into a separate file with", "the \".gwa\" extension. The engine should notice the GWA file", "and load it automatically.", "", "#P20", "The rest of the modes below create a new self-contained WAD file,", "which will contain any GL Nodes that are built.", "", "@t GL, Normal if missing", "#P20", "This mode builds the GL nodes, and will detect if the Normal nodes", "are missing and build them too when absent. Hence it will keep any", "pre-existing Normal nodes, so less work to do, plus the normal", "nodes may be better optimised for non-GLBSP-aware DOOM ports.", "", "@t GL and Normal nodes", "#P20", "This mode builds both the GL nodes and the Normal nodes.", "", "@t GL nodes only", "#P20", "This mode builds only the GL nodes, completely ignoring any", "pre-existing Normal nodes (even if absent). This mode is", "probably not very useful.", "", "@m Misc Options", "", "#P00", "The upper right box in the main window contain a set of", "miscellaneous options. Some of them only appear when certain", "build modes are enabled, because in other modes they would", "be ignored. The full set of misc options are:", "", "@t Extra Warnings", "#P20", "Shows extra warning messages, which detail various", "non-serious problems that glBSP discovers while building the", "nodes. Often these warnings show a real", "problem in the level (e.g a non-closed sector or", "invalid sidedef), so they are worth checking now and then.", "", "@t Don't clobber REJECT", "#P20", "Normally glBSP will create an simple REJECT map for", "each level. This options prevents any existing", "REJECT map from being clobbered, such as one built by a", "dedicated reject building tool (RMB, etc).", "", "@t Pack Sidedefs", "#P20", "Pack sidedefs, by detecting which sidedefs are", "identical and removing the duplicates, producing a", "smaller PWAD.", "", "#P20", "NOTE: this may make your level a lot", "harder to edit! Therefore this option is most useful", "when producing a final WAD for public release.", "", "@t Fresh Partition Lines", "#P20", "Normally glBSP will cheat a bit and", "re-use the original node information to create the GL", "nodes, doing it much faster. When this happens, the", "message \"Using original nodes to speed things up\" is", "shown.", "", "#P20", "This option forces glBSP to create \"fresh\" GL nodes.", "The downside to reusing the original nodes is that they", "may not be as good as the ones glBSP creates, e.g. the", "special checks to minimise slime-trails don't kick in,", "and the -factor value doesn't have any effect.", "", "@m Factor", "", "#P00", "The factor value is located just below the Misc options. ", "It specifies the cost assigned to seg splits. ", "Larger values make seg splits more costly (and thus glBSP tries", "harder to avoid them), but smaller values produce better BSP", "trees. See the section 'How glBSP Works' for more info. ", "The default factor is known to be a good compromise.", "", NULL }; //------------------------------------------------------------------------ static const char *note_tc_text[] = { "", "@c@l 3. Interaction with other tools", "", "@-", "", "#P00", "As far as I know,", "none of the various WAD tools that exist (such as DSHRINK, CLEANWAD,", "DEUTEX, etc..) are 'glBSP aware', they will rearrange or even remove", "some of the special GL entries, and everything goes pear shaped.", "", "#P00", "When using a reject building tool (such as RMB), you need to give", "the -noreject to glBSP to prevent the good REJECT data from being", "overwritten.", "", "@b *** DO NOT: ***", "", "#P13", "+ Run dshrink on your map WADs at any time!", "", "#P13", "+ Run cleanwad on your map WADs *after* you have compiled your GL", " friendly nodes! (The GL nodes will be removed).", "", "#P13", "+ Use Wintex/DEUSF to merge map WADs with GL friendly nodes in them!", " (The GL node entries will be rearranged, causing problems).", "", NULL }; //------------------------------------------------------------------------ static const char *howwork_text[] = { "", "@c@l 4. How glBSP Works", "", "@-", "", "#P00", "A node builder works like this: say you are looking at your level in", "the automap or in the level editor. The node builder needs to pick a", "line (stretching to infinity) that divides the whole map in two halves", "(can be rough). Now cover up one half with your hand, and repeat the", "process on the remaining half. The node builder keeps doing this", "until the areas that remain are convex (i.e. none of the walls can", "block the view of any other walls when you are inside that area).", "", "#P00", "Those infinite lines are called 'partition lines', and when they cross", "a linedef, the linedef has to be split. Each split piece is called a", "'seg', and every split causes more segs to be created. Having fewer", "segs is good: less to draw & smaller files, so partition lines are", "chosen so that they minimise splits. The 'Factor' value controls how", "costly these splits are. Higher values cause the node builder to try", "harder to avoid splits.", "", "#P00", "So, each 'partition' line splits an area (or 'space') of the level", "into *two* smaller spaces. This is where the term 'Binary Space", "Partition' (BSP) comes from.", "", "#P00", "Another thing: having a good BSP tree is also important, and helps for", "faster rendering & smaller files. Thus the node builder also tries to", "make the BSP tree good (by making it balanced, and keeping it small). ", "If the Factor value is too high, it will care too much about the", "splits, and probably make a bad BSP tree. How good the BSP tree is", "can be gauged by the output line that reads:", "", "@c@t Heights of left and right subtrees = (12,24)", "", "#P00", "Lower values are better (the BSP tree is smaller), and values that are", "closer together are also better (the BSP is more balanced).", "", NULL }; //------------------------------------------------------------------------ static const char *diff_text[] = { "", "@c@l 5. Differences to BSP 2.3", "", "@-", "", "#P00", "As mentioned in the readme file, glBSP was originally based on BSP 2.3. Most of", "the code has been rewritten, however, and some features of BSP were", "changed or abandoned. Features that are different:", "", "#P13", "+ This GUI version, glBSPX, is completely new !", "", "#P13", "+ When the output file is not specified (i.e. no -o option), then", " the default output file will be a GWA file with the same name. ", " Under BSP 2.3, the default output file would be \"tmp.wad\". ", " (This only applies to the command-line version).", "", "#P13", "+ All code for doing visplane checks has been removed. It was very", " complex stuff, and for OpenGL DOOM ports this checking is not", " needed. Thus glBSP does not accept the following options that", " BSP 2.3 supports: -thold, -vp, -vpmark, -vpwarn.", "", "#P13", "+ glBSP works on big-endian platforms (like the Mac).", "", "#P13", "+ The 'just for a grin' special feature where a linedef with tag", " 999 would cause an angle adjustment was removed.", "", "#P13", "+ glBSP has Hexen support.", "", "#P13", "+ glBSP compresses the blockmap, and can pack sidedefs.", "", "#P13", "+ glBSP has a much more modular architecture, and can even serve", " as a plug-in for other programs.", "", NULL }; //------------------------------------------------------------------------ static const char *contact_text[] = { "", "@c@l 6. Contact and Links", "", "@-", "", " The homepage for glBSP can be found here:", "", "@t http://glbsp.sourceforge.net/", "", " Questions, bug reports, suggestions, etc... can be made on the", " web forum at:", "", "@t https://sourceforge.net/forum/forum.php?forum_id=33133", "", "", "@m Compatible Engines", "", "@t EDGE http://edge.sourceforge.net/", "@t JDOOM http://www.doomsdayhq.com/", "@t PrBOOM http://prboom.sourceforge.net/", "@t ZDoomGL http://zdoomgl.mancubus.net/", "@t Vavoom http://www.vavoom-engine.com/", "@t Doom3D http://doomworld.com/doom3d/", "", NULL }; //------------------------------------------------------------------------ static const char *acknow_text[] = { "", "@c@l 7. Acknowledgements", "", "@-", "", "#P10", "Andy Baker, for making binaries, writing code and other help.", "", "#P10", "Marc A. Pullen, for testing and helping with the documentation.", "", "#P10", "Lee Killough and André Majorel, for giving their permission to put", "glBSP under the GNU GPL.", "", "#P10", "Janis Legzdinsh for fixing many problems with Hexen wads.", "", "#P10", "Darren Salt has sent in numerous patches.", "", "#P10", "Jaakko Keränen, who gave some useful feedback on the GL-Friendly", "Nodes specification.", "", "#P10", "The authors of FLTK (Fast Light Tool Kit), for a nice LGPL C++ GUI", "toolkit that even I can get working on both Linux and Win32.", "", "#P10", "Marc Rousseau (author of ZenNode 1.0), Robert Fenske Jr (author of", "Warm 1.6), L.M. Witek (author of Reject 1.1), and others, for", "releasing the source code to their WAD utilities, and giving me lots", "of ideas to \"borrow\" :), like blockmap packing.", "", "#P10", "Colin Reed and Lee Killough (and others), who wrote the original BSP", "2.3 which glBSP was based on.", "", "#P10", "Matt Fell, for the Doom Specs v1.666.", "", "#P10", "Raphael Quinet, for DEU and the original idea.", "", "#P10", "id Software, for not only creating such an irresistable game, but", "releasing the source code for so much of their stuff.", "", "#P10", ". . . and everyone else who deserves it ! ", "", NULL }; //------------------------------------------------------------------------ const book_page_t book_pages[] = { { contents_text }, // #00 { intro_text }, // #01 { using_text }, // #02 { note_tc_text }, // #03 { howwork_text }, // #04 { diff_text }, // #05 { contact_text }, // #06 { acknow_text }, // #07 { NULL } }; glbsp-2.24-source/gui/glBSPX.r0000644000175000017500000000212710650405207015373 0ustar aaptedaapted/*---------------------------------------------------------------------------- * glBSPX MacOS X RESOURCE FILE *---------------------------------------------------------------------------- * * GL-Friendly Node Builder (C) 2000-2007 Andrew Apted * * Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * *------------------------------------------------------------------------ */ data 'MBAR' (128) { $"0001 0080" }; data 'MENU' (128, "Apple") { $"0080 0000 0000 0000 0000 FFFF FFFB 0114" $"0A41 626F 7574 2046 4C54 4B00 0000 0001" $"2D00 0000 0000" }; data 'carb' (0) { }; glbsp-2.24-source/gui/options.cc0000644000175000017500000001571210650405207016117 0ustar aaptedaapted//------------------------------------------------------------------------ // Options : Unix/FLTK Option boxes //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" #define BM_BUTTONTYPE FL_ROUND_DOWN_BOX #define BM_BUTTONSIZE 30 static void build_mode_radio_CB(Fl_Widget *w, void *data) { boolean_g old_gwa = guix_info.gwa_mode; guix_win->build_mode->WriteInfo(); // communicate with output file widget, for GWA mode if (old_gwa != guix_info.gwa_mode) { guix_win->files->GWA_Changed(); } guix_win->misc_opts->GWA_Changed(); } // // BuildMode Constructor // Guix_BuildMode::Guix_BuildMode(int x, int y, int w, int h) : Fl_Group(x, y, w, h, "Build Mode") { // cancel the automatic 'begin' in Fl_Group constructor end(); box(FL_THIN_UP_BOX); resizable(0); // no resizing the kiddies, please labelfont(FL_HELVETICA | FL_BOLD); labeltype(FL_NORMAL_LABEL); align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_TOP); // create the children int CX = x+12; int CY = y+16; gwa = new Fl_Check_Button(CX, CY, BM_BUTTONSIZE, BM_BUTTONSIZE, "GWA Mode"); gwa->down_box(BM_BUTTONTYPE); gwa->type(FL_RADIO_BUTTON); gwa->align(FL_ALIGN_RIGHT); gwa->callback((Fl_Callback *) build_mode_radio_CB); add(gwa); CY += 24; maybe_normal = new Fl_Check_Button(CX, CY, BM_BUTTONSIZE, BM_BUTTONSIZE, "GL, Normal if missing"); maybe_normal->down_box(BM_BUTTONTYPE); maybe_normal->type(FL_RADIO_BUTTON); maybe_normal->align(FL_ALIGN_RIGHT); maybe_normal->callback((Fl_Callback *) build_mode_radio_CB); add(maybe_normal); CY += 24; both = new Fl_Check_Button(CX, CY, BM_BUTTONSIZE, BM_BUTTONSIZE, "GL and Normal nodes"); both->down_box(BM_BUTTONTYPE); both->type(FL_RADIO_BUTTON); both->align(FL_ALIGN_RIGHT); both->callback((Fl_Callback *) build_mode_radio_CB); add(both); CY += 24; gl_only = new Fl_Check_Button(CX, CY, BM_BUTTONSIZE, BM_BUTTONSIZE, "GL nodes only"); gl_only->down_box(BM_BUTTONTYPE); gl_only->type(FL_RADIO_BUTTON); gl_only->align(FL_ALIGN_RIGHT); gl_only->callback((Fl_Callback *) build_mode_radio_CB); add(gl_only); CY += 24; ReadInfo(); } // // BuildMode Destructor // Guix_BuildMode::~Guix_BuildMode() { WriteInfo(); } void Guix_BuildMode::ReadInfo() { if (guix_info.gwa_mode) gwa->setonly(); else if (guix_info.no_normal) gl_only->setonly(); else if (guix_info.force_normal) both->setonly(); else maybe_normal->setonly(); // redraw them all (just to be safe) gwa->redraw(); gl_only->redraw(); both->redraw(); maybe_normal->redraw(); } void Guix_BuildMode::WriteInfo() { // default: everything false guix_info.gwa_mode = FALSE; guix_info.no_normal = FALSE; guix_info.force_normal = FALSE; if (gwa->value()) { guix_info.gwa_mode = TRUE; } else if (gl_only->value()) { guix_info.no_normal = TRUE; } else if (both->value()) { guix_info.force_normal = TRUE; } } void Guix_BuildMode::LockOut(boolean_g lock_it) { if (lock_it) { gwa->set_output(); maybe_normal->set_output(); both->set_output(); gl_only->set_output(); } else { gwa->clear_output(); maybe_normal->clear_output(); both->clear_output(); gl_only->clear_output(); } } //------------------------------------------------------------------------ static void misc_opts_check_CB(Fl_Widget *w, void *data) { guix_win->misc_opts->WriteInfo(); } // // MiscOptions Constructor // Guix_MiscOptions::Guix_MiscOptions(int x, int y, int w, int h) : Fl_Group(x, y, w, h, "Misc Options") { // cancel the automatic 'begin' in Fl_Group constructor end(); box(FL_THIN_UP_BOX); resizable(0); // no resizing the kiddies, please labelfont(FL_HELVETICA | FL_BOLD); labeltype(FL_NORMAL_LABEL); align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_TOP); // create children int CX = x+12; int CY = y+20; warnings = new Fl_Check_Button(CX, CY, 22, 22, "Extra Warnings"); warnings->down_box(FL_DOWN_BOX); warnings->align(FL_ALIGN_RIGHT); warnings->callback((Fl_Callback *) misc_opts_check_CB); add(warnings); CY += 24; no_reject = new Fl_Check_Button(CX, CY, 22, 22, "Don't clobber REJECT"); no_reject->down_box(FL_DOWN_BOX); no_reject->align(FL_ALIGN_RIGHT); no_reject->callback((Fl_Callback *) misc_opts_check_CB); add(no_reject); CY += 24; pack_sides = new Fl_Check_Button(CX, CY, 22, 22, "Pack Sidedefs"); pack_sides->down_box(FL_DOWN_BOX); pack_sides->align(FL_ALIGN_RIGHT); pack_sides->callback((Fl_Callback *) misc_opts_check_CB); add(pack_sides); CY += 24; choose_fresh = new Fl_Check_Button(CX, CY, 22, 22, "Fresh Partition Lines"); choose_fresh->down_box(FL_DOWN_BOX); choose_fresh->align(FL_ALIGN_RIGHT); choose_fresh->callback((Fl_Callback *) misc_opts_check_CB); add(choose_fresh); CY += 24; ReadInfo(); } // // MiscOptions Destructor // Guix_MiscOptions::~Guix_MiscOptions() { WriteInfo(); } void Guix_MiscOptions::ReadInfo() { choose_fresh->value(guix_info.fast ? 0 : 1); // API change choose_fresh->redraw(); warnings->value(guix_info.mini_warnings ? 1 : 0); warnings->redraw(); no_reject->value(guix_info.no_reject ? 1 : 0); no_reject->redraw(); pack_sides->value(guix_info.pack_sides ? 1 : 0); pack_sides->redraw(); GWA_Changed(); } void Guix_MiscOptions::WriteInfo() { guix_info.fast = choose_fresh->value() ? FALSE : TRUE; // API change guix_info.no_reject = no_reject->value() ? TRUE : FALSE; guix_info.mini_warnings = warnings->value() ? TRUE : FALSE; guix_info.pack_sides = pack_sides->value() ? TRUE : FALSE; } void Guix_MiscOptions::GWA_Changed() { if (guix_info.gwa_mode) { no_reject->deactivate(); pack_sides->deactivate(); } else { no_reject->activate(); pack_sides->activate(); } if (guix_info.force_normal) choose_fresh->deactivate(); else choose_fresh->activate(); } void Guix_MiscOptions::LockOut(boolean_g lock_it) { if (lock_it) { choose_fresh->set_output(); warnings->set_output(); no_reject->set_output(); pack_sides->set_output(); } else { choose_fresh->clear_output(); warnings->clear_output(); no_reject->clear_output(); pack_sides->clear_output(); } } glbsp-2.24-source/gui/progress.cc0000644000175000017500000001631010650405207016263 0ustar aaptedaapted//------------------------------------------------------------------------ // PROGRESS : Unix/FLTK Progress display //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" #define TICKER_TIME 10 #define BAR_YELLOWY \ fl_color_cube(FL_NUM_RED-1, FL_NUM_GREEN-1, 0) #define BAR_ORANGEY \ fl_color_cube(FL_NUM_RED-1, (FL_NUM_GREEN-1)*4/7, 0) #define BAR_CYANISH \ fl_color_cube(0, (FL_NUM_GREEN-1)*2/7, FL_NUM_BLUE-1) // // ProgressBox Constructor // Guix_ProgressBox::Guix_ProgressBox(int x, int y, int w, int h) : Fl_Group(x, y, w, h, "Progress") { // cancel the automatic 'begin' in Fl_Group constructor end(); box(FL_THIN_UP_BOX); resizable(0); // no resizing the kiddies, please labelfont(FL_HELVETICA | FL_BOLD); labeltype(FL_NORMAL_LABEL); align(FL_ALIGN_LEFT | FL_ALIGN_TOP | FL_ALIGN_INSIDE); curr_bars = 0; bars[0].lab_str = bars[1].lab_str = NULL; title_str = NULL; // create the resizable int len = w - 60 - 50; group = new Fl_Group(x+60, y, len, h); group->end(); add(group); resizable(group); // create bars CreateOneBar(bars[0], x, y, w, h); CreateOneBar(bars[1], x, y, w, h); } // // ProgressBox Destructor // Guix_ProgressBox::~Guix_ProgressBox() { GlbspFree(bars[0].lab_str); GlbspFree(bars[1].lab_str); GlbspFree(title_str); } void Guix_ProgressBox::CreateOneBar(guix_bar_t& bar, int x, int y, int w, int h) { bar.label = new Fl_Box(x+6, y+4, 50, 20); bar.label->align(FL_ALIGN_RIGHT | FL_ALIGN_INSIDE); bar.label->hide(); add(bar.label); bar.slide = new Fl_Slider(group->x(), y+6, group->w(), 16); bar.slide->set_output(); bar.slide->slider(FL_FLAT_BOX); bar.slide->type(FL_HOR_FILL_SLIDER); bar.slide->hide(); group->add(bar.slide); bar.perc = new Fl_Box(x + w - 50, y+4, 40, 20); bar.perc->box(FL_FLAT_BOX); bar.perc->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); bar.perc->hide(); add(bar.perc); } void Guix_ProgressBox::SetupOneBar(guix_bar_t& bar, int y, const char *label_short, Fl_Color col) { bar.label->label(label_short); bar.label->position(bar.label->x(), y+4); bar.label->show(); bar.slide->selection_color(col); bar.slide->position(bar.slide->x(), y+6); bar.slide->value(0); bar.slide->show(); bar.perc->position(bar.perc->x(), y+4); bar.perc->show(); bar.perc_shown = -1; // invalid value, forces update. } void Guix_ProgressBox::SetBars(int num) { assert(num == 1 || num == 2); if (curr_bars != 0) ClearBars(); curr_bars = num; if (curr_bars == 1) { // FILE loading/saving SetupOneBar(bars[0], y() + 28, "File", BAR_ORANGEY); } else { // MAP building SetupOneBar(bars[0], y() + 16, "Map", BAR_YELLOWY); SetupOneBar(bars[1], y() + 40, "File", BAR_CYANISH); } } void Guix_ProgressBox::ClearBars(void) { if (guix_win->progress->curr_bars == 0) return; for (int i=0; i < 2; i++) { bars[i].label->hide(); bars[i].slide->hide(); bars[i].perc->hide(); } } void Guix_ProgressBox::SetBarName(int which, const char *label_short) { assert(0 <= which && which < 2); bars[which].label->label(label_short); redraw(); } //------------------------------------------------------------------------ // // GUI_Ticker // void GUI_Ticker(void) { // this routine was causing a massive slow-down (under MacOSX at least, // didn't have access to Win32/Linux to test). Seems that Fl::check() // is pretty expensive (and the main glbsp code calls here a lot). // // By fixing this (and a optimisation in the progress bars), build time // for DOOM2.WAD fell from 3m14s down to just 11 seconds ! static unsigned int last_millis = 0; unsigned int cur_millis = HelperGetMillis(); if (cur_millis >= last_millis && cur_millis >= TICKER_TIME && cur_millis - TICKER_TIME < last_millis) { return; } Fl::check(); last_millis = cur_millis; } // // GUI_DisplayOpen // boolean_g GUI_DisplayOpen(displaytype_e type) { // shutdown any existing display GUI_DisplayClose(); switch (type) { case DIS_BUILDPROGRESS: guix_win->progress->SetBars(2); break; case DIS_FILEPROGRESS: guix_win->progress->SetBars(1); break; default: return FALSE; // unknown display type } return TRUE; } // // GUI_DisplaySetTitle // void GUI_DisplaySetTitle(const char *str) { if (guix_win->progress->curr_bars == 0) return; // copy the string GlbspFree(guix_win->progress->title_str); guix_win->progress->title_str = GlbspStrDup(str); } // // GUI_DisplaySetBarText // void GUI_DisplaySetBarText(int barnum, const char *str) { if (guix_win->progress->curr_bars == 0) return; // select the correct bar if (barnum < 1 || barnum > guix_win->progress->curr_bars) return; guix_bar_t *bar = guix_win->progress->bars + (barnum-1); // we must copy the string, as the label() method only stores the // pointer -- not good if we've been passed an on-stack buffer. GlbspFree(bar->lab_str); bar->lab_str = GlbspStrDup(str); // for loading/saving, update short name if (guix_win->progress->curr_bars == 1) { if (HelperCaseCmpLen(str, "Read", 4) == 0) guix_win->progress->SetBarName(0, "Load"); if (HelperCaseCmpLen(str, "Writ", 4) == 0) guix_win->progress->SetBarName(0, "Save"); } // redraw window too guix_win->progress->redraw(); } // // GUI_DisplaySetBarLimit // void GUI_DisplaySetBarLimit(int barnum, int limit) { if (guix_win->progress->curr_bars == 0) return; // select the correct bar if (barnum < 1 || barnum > guix_win->progress->curr_bars) return; guix_bar_t *bar = guix_win->progress->bars + (barnum-1); bar->slide->range(0, limit); } // // GUI_DisplaySetBar // void GUI_DisplaySetBar(int barnum, int count) { if (guix_win->progress->curr_bars == 0) return; // select the correct bar if (barnum < 1 || barnum > guix_win->progress->curr_bars) return; guix_bar_t *bar = guix_win->progress->bars + (barnum-1); // work out percentage int perc = 0; if (count >= 0 && count <= bar->slide->maximum() && bar->slide->maximum() > 0) { perc = (int)(count * 100.0 / bar->slide->maximum()); } if (perc == bar->perc_shown) return; bar->perc_shown = perc; sprintf(bar->perc_buf, "%d%%", perc); bar->perc->label(bar->perc_buf); bar->perc->redraw(); bar->slide->value(count); bar->slide->redraw(); } // // GUI_DisplayClose // void GUI_DisplayClose(void) { guix_win->progress->ClearBars(); } glbsp-2.24-source/gui/glBSPX.rc0000644000175000017500000000331310651621277015544 0ustar aaptedaapted//---------------------------------------------------------------------------- // glBSPX WIN32 RESOURCE FILE //---------------------------------------------------------------------------- // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ 1 ICON DISCARDABLE "gui/glBSPX.ico" 1 VERSIONINFO FILEVERSION 4, 2, 24, 1 PRODUCTVERSION 4, 2, 24, 1 FILEFLAGSMASK 0x0 FILEOS 0x40004 // VOS_NT_WINDOWS32 FILETYPE 1 // VFT_APP FILESUBTYPE 0 // VFT_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN // 0409 means "US English"; 04B0 means "Unicode encoding" BLOCK "040904B0" BEGIN VALUE "CompanyName", "Andrew Apted\0" VALUE "FileDescription", "GL-Node Builder\0" VALUE "FileVersion", "2.24\0" VALUE "InternalName", "glBSP\0" VALUE "LegalCopyright", "\251 Andrew Apted, GNU General Public License\0" VALUE "OriginalFilename", "GLBSPX.EXE\0" VALUE "ProductName", "glBSP\0" VALUE "ProductVersion", "2.24\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 0x04B0 END END glbsp-2.24-source/gui/main.cc0000644000175000017500000001337510652027077015362 0ustar aaptedaapted//------------------------------------------------------------------------ // MAIN : Unix/FLTK Main program //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" #define MY_TITLE ("glBSP Node Builder " GLBSP_VER) // Node building info nodebuildinfo_t guix_info; volatile nodebuildcomms_t guix_comms; const nodebuildfuncs_t guix_funcs = { GUI_FatalError, GUI_PrintMsg, GUI_Ticker, GUI_DisplayOpen, GUI_DisplaySetTitle, GUI_DisplaySetBar, GUI_DisplaySetBarLimit, GUI_DisplaySetBarText, GUI_DisplayClose }; // GUI-specific Globals guix_preferences_t guix_prefs; const guix_preferences_t default_guiprefs = { #ifdef WIN32 40, 20, // win_x, win_y #else 40, 50, #endif 550, 520, // win_w, win_h; 120, 200, // progress_x, progress_y 90, 200, // dialog_x, dialog_y 80, 100, // other_x, other_y 20, 50, // manual_x, manual_y 610, 520, // manual_w, manual_h 0, // manual_page TRUE, // overwrite_warn TRUE, // same_file_warn TRUE, // lack_ext_warn NULL // save_log_file }; /* ----- user information ----------------------------- */ static void ShowTitle(void) { GUI_PrintMsg( "\n" "**** GLBSP Node Builder " GLBSP_VER " (C) 2007 Andrew Apted ****\n\n" ); } static void ShowInfo(void) { GUI_PrintMsg( "This GL node builder was originally based on BSP 2.3, which was\n" "created from the basic theory stated in DEU5 (OBJECTS.C)\n" "\n" "Credits should go to :-\n" " Andy Baker & Marc Pullen for their invaluable help\n" " Janis Legzdinsh for fixing up Hexen support\n" " Colin Reed & Lee Killough for creating the original BSP\n" " Matt Fell for the Doom Specs\n" " Raphael Quinet for DEU and the original idea\n" " ... and everyone who helped with the original BSP.\n" "\n" "This program is free software, under the terms of the GNU General\n" "Public License, and comes with ABSOLUTELY NO WARRANTY. See the\n" "accompanying documentation for more details.\n" "\n" "Note: glBSPX is the GUI (graphical user interface) version.\n" "Try plain \"glbsp\" if you want the command-line version.\n" ); } void MainSetDefaults(void) { // this is more messy than it was in C memcpy((nodebuildinfo_t *) &guix_info, &default_buildinfo, sizeof(guix_info)); memcpy((nodebuildcomms_t *) &guix_comms, &default_buildcomms, sizeof(guix_comms)); memcpy((guix_preferences_t *) &guix_prefs, &default_guiprefs, sizeof(guix_prefs)); // set default filename for saving the log guix_prefs.save_log_file = GlbspStrDup("glbsp.log"); } /* ----- main program ----------------------------- */ int main(int argc, char **argv) { if (argc > 1 && (strcmp(argv[1], "/?") == 0 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-help") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-HELP") == 0 || strcmp(argv[1], "--HELP") == 0)) { ShowTitle(); ShowInfo(); exit(1); } int first_arg = 1; #ifdef MACOSX if (first_arg < argc && (strncmp(argv[first_arg], "-psn", 4) == 0)) first_arg++; #endif // set defaults, also initializes the nodebuildxxxx stuff MainSetDefaults(); // read persistent data CookieSetPath(argv[0]); cookie_status_t cookie_ret = CookieReadAll(); // handle drag and drop: a single non-option argument // // NOTE: there is no support for giving options to glBSPX via the // command line. Plain 'glbsp' should be used if this is desired. // The difficult here lies in possible conflicts between given // options and those already set from within the GUI. Plus we may // want to handle a drag-n-drop of multiple files later on. // boolean_g unused_args = FALSE; if (first_arg < argc && argv[first_arg][0] != '-') { GlbspFree(guix_info.input_file); GlbspFree(guix_info.output_file); guix_info.input_file = GlbspStrDup(argv[first_arg]); // guess an output name too guix_info.output_file = GlbspStrDup( HelperGuessOutput(guix_info.input_file)); first_arg++; } if (first_arg < argc) unused_args = TRUE; // load icons for file chooser Fl_File_Icon::load_system_icons(); guix_win = new Guix_MainWin(MY_TITLE); DialogLoadImages(); ShowTitle(); switch (cookie_ret) { case COOKIE_E_OK: break; case COOKIE_E_NO_FILE: guix_win->text_box->AddMsg( "** Missing INI file -- Using defaults **\n\n", FL_RED, TRUE); break; case COOKIE_E_PARSE_ERRORS: case COOKIE_E_CHECK_ERRORS: guix_win->text_box->AddMsg( "** Warning: Errors found in INI file **\n\n", FL_RED, TRUE); break; } if (unused_args) guix_win->text_box->AddMsg( "** Warning: Ignoring extra arguments to glBSPX **\n\n", FL_RED, TRUE); // run the GUI until the user quits while (! guix_win->want_quit) Fl::wait(); delete guix_win; guix_win = NULL; CookieWriteAll(); DialogFreeImages(); return 0; } glbsp-2.24-source/gui/menu.cc0000644000175000017500000002021010650405311015351 0ustar aaptedaapted//------------------------------------------------------------------------ // MENU : Unix/FLTK Menu handling //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" static boolean_g menu_want_to_quit; static void menu_quit_CB(Fl_Widget *w, void *data) { menu_want_to_quit = TRUE; } static void menu_do_clear_log(Fl_Widget *w, void * data) { guix_win->text_box->ClearLog(); } #ifndef MACOSX static void menu_do_exit(Fl_Widget *w, void * data) { guix_win->want_quit = TRUE; } #endif //------------------------------------------------------------------------ static void menu_do_prefs(Fl_Widget *w, void * data) { guix_pref_win = new Guix_PrefWin(); // run the GUI until the user closes while (! guix_pref_win->want_quit) Fl::wait(); delete guix_pref_win; } //------------------------------------------------------------------------ static const char *about_Info = "By Andrew Apted (C) 2000-2007\n" "\n" "Based on BSP 2.3 (C) 1998 Colin Reed, Lee Killough\n" "\n" "Additional credits to...\n" " Andy Baker & Marc Pullen, for invaluable help\n" " Janis Legzdinsh, for fixing up Hexen support\n" " Matt Fell, for the Doom Specs\n" " Raphael Quinet, for DEU and the original idea\n" " ... and everyone else who deserves it !\n" "\n" "This program is free software, under the terms of\n" "the GNU General Public License, and comes with\n" "ABSOLUTELY NO WARRANTY.\n" "\n" "Website: http://glbsp.sourceforge.net"; static void menu_do_about(Fl_Widget *w, void * data) { menu_want_to_quit = FALSE; Fl_Window *ab_win = new Fl_Window(600, 340, "About glBSP"); ab_win->end(); // non-resizable ab_win->size_range(ab_win->w(), ab_win->h(), ab_win->w(), ab_win->h()); ab_win->position(guix_prefs.manual_x, guix_prefs.manual_y); ab_win->callback((Fl_Callback *) menu_quit_CB); // add the about image Fl_Group *group = new Fl_Group(0, 0, 230, ab_win->h()); group->box(FL_FLAT_BOX); group->color(FL_BLACK, FL_BLACK); ab_win->add(group); Fl_Box *box = new Fl_Box(20, 90, ABOUT_IMG_W+2, ABOUT_IMG_H+2); box->image(about_image); group->add(box); // nice big logo text box = new Fl_Box(240, 5, 350, 50, "glBSPX " GLBSP_VER); box->labelsize(24); ab_win->add(box); // about text box = new Fl_Box(240, 60, 350, 270, about_Info); box->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_TOP); ab_win->add(box); // finally add an "OK" button Fl_Button *button = new Fl_Button(ab_win->w()-10-60, ab_win->h()-10-30, 60, 30, "OK"); button->callback((Fl_Callback *) menu_quit_CB); ab_win->add(button); ab_win->set_modal(); ab_win->show(); // capture initial size WindowSmallDelay(); int init_x = ab_win->x(); int init_y = ab_win->y(); // run the GUI until the user closes while (! menu_want_to_quit) Fl::wait(); // check if the user moved/resized the window if (ab_win->x() != init_x || ab_win->y() != init_y) { guix_prefs.manual_x = ab_win->x(); guix_prefs.manual_y = ab_win->y(); } // this deletes all the child widgets too... delete ab_win; } //------------------------------------------------------------------------ static void menu_do_manual(Fl_Widget *w, void * data) { guix_book_win = new Guix_Book(); guix_book_win->LoadPage(guix_prefs.manual_page); // run the GUI until the user closes while (! guix_book_win->want_quit) { guix_book_win->Update(); Fl::wait(); } delete guix_book_win; } //------------------------------------------------------------------------ static void menu_do_license(Fl_Widget *w, void * data) { guix_lic_win = new Guix_License(); // run the GUI until the user closes while (! guix_lic_win->want_quit) { Fl::wait(); } delete guix_lic_win; } //------------------------------------------------------------------------ static void menu_do_save_log(Fl_Widget *w, void * data) { char guess_name[512]; // compute the "guess" filename if (! guix_info.output_file || ! HelperFilenameValid(guix_info.output_file) || strlen(guix_info.output_file) > 500) { strcpy(guess_name, "glbsp.log"); } else { strcpy(guess_name, HelperReplaceExt(guix_info.output_file, "log")); } int choice; char buffer[1024]; for (;;) { choice = DialogQueryFilename( "Please select the file to save the log into:", & guix_prefs.save_log_file, guess_name); if (choice != 0) return; if (!guix_prefs.save_log_file || guix_prefs.save_log_file[0] == 0) { DialogShowAndGetChoice(ALERT_TXT, skull_image, "Please choose a Log filename."); continue; } if (! HelperFilenameValid(guix_prefs.save_log_file)) { sprintf(buffer, "Invalid Log filename:\n" "\n" " %s\n" "\n" "Please check the filename and try again.", guix_prefs.save_log_file); DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer); continue; } // check for missing extension if (! HelperHasExt(guix_prefs.save_log_file)) { if (guix_prefs.lack_ext_warn) { sprintf(buffer, "The Log file you selected has no extension.\n" "\n" "Do you want to add \".LOG\" and continue ?"); choice = DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer, "OK", "Re-Select", "Cancel"); if (choice < 0 || choice == 2) return; if (choice == 1) continue; } // choice == 0 { char *new_log = HelperReplaceExt(guix_prefs.save_log_file, "log"); GlbspFree(guix_prefs.save_log_file); guix_prefs.save_log_file = GlbspStrDup(new_log); } } // check if file already exists... if (guix_prefs.overwrite_warn && HelperFileExists(guix_prefs.save_log_file)) { sprintf(buffer, "Warning: the chosen Log file already exists:\n" "\n" " %s\n" "\n" "Do you want to overwrite it ?", guix_prefs.save_log_file); choice = DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer, "OK", "Re-Select", "Cancel"); if (choice < 0 || choice == 2) return; if (choice == 1) continue; } guix_win->text_box->SaveLog(guix_prefs.save_log_file); return; } } //------------------------------------------------------------------------ #undef FCAL #define FCAL (Fl_Callback *) static Fl_Menu_Item menu_items[] = { { "&File", 0, 0, 0, FL_SUBMENU }, { "&Preferences...", 0, FCAL menu_do_prefs }, { "&Save Log...", 0, FCAL menu_do_save_log }, #ifdef MACOSX { "&Clear Log", 0, FCAL menu_do_clear_log }, #else { "&Clear Log", 0, FCAL menu_do_clear_log, 0, FL_MENU_DIVIDER }, { "E&xit", FL_ALT + 'q', FCAL menu_do_exit }, #endif { 0 }, { "&Help", 0, 0, 0, FL_SUBMENU }, { "&About...", 0, FCAL menu_do_about }, { "&License...", 0, FCAL menu_do_license }, { "&Manual...", FL_F+1, FCAL menu_do_manual }, { 0 }, { 0 } }; // // MenuCreate // #ifdef MACOSX Fl_Sys_Menu_Bar * MenuCreate(int x, int y, int w, int h) { Fl_Sys_Menu_Bar *bar = new Fl_Sys_Menu_Bar(x, y, w, h); bar->menu(menu_items); return bar; } #else Fl_Menu_Bar * MenuCreate(int x, int y, int w, int h) { Fl_Menu_Bar *bar = new Fl_Menu_Bar(x, y, w, h); bar->menu(menu_items); return bar; } #endif glbsp-2.24-source/gui/glBSPX.ico0000644000175000017500000002215610514052722015707 0ustar aaptedaaptedh6 ¨ž@@(F( @ÿÿÿzúã‰cîîjkpE /´´V³(I©h6!=x ņ1jÕHDŠ\#R2O“VE 126_hÀ6Z[Ð}]ƹr€O Q£D)E…î‘ ?A ((AlH35S + &HxPÖ‚bÀ @< *64g :;!2݇wI ,]êë猢eiExócÉS©:e L/ I“ & --  ;®k $%QŸ 59FGƒR"ˆX]^  ,(@{ hÒX²B„F*3 44HI ))£eEˆ uH  7] **1´µR L0  &% +,?@åŒ  Ñ~?z€P$€vH      )* @A     |WK¥·¶ œ±²xjˆRMs¹¸Ÿ®šeµ£pq‹Š¤´ž¯¬zš³†}'§•np[Ÿ…o˜˜®œ¡ˆ¦`>€&ZANV\y˜S4¡v9^OYPgi0‰XU1+B?=JfgaHc6 ]tŽQ’Cgwgg(gg*B)Œ‡g8g“gu37~!r2—FggdggG:E/‘”¨ hm#LDg<kggTg @{5%,„›‚_ƒ-l ©ª­¯°šƒ $I.;–y™ošo«b¢ "à€€€€à( @€ÿÿÿ~þÚ‚n~†Zúú:vjB 6¾¾"ŠŠZº2.¾þþ¢f:& &zÒbbFz®:F*BÞâŠ~j*R"V†*¦¦nÞJJNš.„RÀvR6rþþBb&rr6ÒÒnRJ†fÊJêî "z~’^vî& 2f4®²VV>>Z¦²nJ*:ÆÊ"6N> :V&’–vJ ^: >:.Ê~f¾ &*&F Jz2"Bn&z~rrjjzÚ   ŽVjÒ jJ...JBŠ6^B~&‚†R¢J’66FBV®Ò‚zöræ*" J6. *62V:fB*:nbbºr¬jÖ~žb ŠZ"6*NŽ 22RRJN^^bˆV`> *.nnffZ²Q2 ::BBÊz>Êʶrnæ¶nfÎ   f ^¾bºfB&V¢Z:2 &" "&6&& &2"~~F‚>zzz*J.2.b2^>rFFNNyJNžL.Ð~Èz°n®jV²‚RR¦T6 FŠ**226f6:nâfÒZ®Vª>:FJÖ~Ö‚zúzòvòvêrê¶rrâ¦fŠZ   Z¶  .*  &* ."" ""NŠJŠB† &&F†"2"zz **F~ ..>vBz..:r"rrjn6b>f6Z :ZJJFFVVÜܸÛàg¸•¸ÜÜÜÖÖÜÜàßääâß߸ÜÜÖÖÒÒÖÖܸäâçççâšß¸ÜÚÖÒÒÒÖÖÛ¸ßâëïïëæä߸ÖÖÒÒÏÒÔÙÙÜܸâŸô¼¾vñëç߸ÛÖÒÒÏÏÏÒÔÙÜܸßâïZ2…„¨ë߸ÜÖÒÒÒÏÏÏÏÒÒÙܸàäç…þþÄ„ëâ¸ÛÖÖÒÒÏÏÏÏÒÒÙܸàç»Z€WHz2ïâ߸ÜÖÒÒÏÏÏÏÏÒÒÙܸà缬z 6I…ñŸš¸ÜÙÖÒÏÏÏÏÏÒÒÖ%Üßçôý" ¦wZëä¸ÜÖÒÒÏÏÏÏÏÒÒÖ%Üßsï…÷‡ )+üRæg•ÖÒLÏ‹ÏÏÒÒÖܸࡼýI0#îüllo;lÌÌlˆ'xÏÔÙܸàçï2z£0: $Æqa—¶]]lDã ·¥ÔÙÜܸä»Z­kGöy2ôs³,ÖÖL|]]¹µê§ÒÖܸä뼄­z1…R»s8?–M²]²<µ/X¥xp”}¸äëñ„[ÃZëràKbÓ]]¶Éº·øÉÉ3Fž!@CA›ÁjQoL ]]ÞT_ÕYÒOV%ÉóSû“9d-¢&_Û?t±]´‹¯BÒÀ¥Ùɽ”-uè*äÉúð¿ÖÖб]œ‹©ê{À¥ÙÉøÜ^¤¢KùeVÒÒ`]±?’‚¯hÇ%Œ¥ÒÉòó-í}&ÇÉsVÇ\(>Æ]N‹¯Â™È׌¥ÒÉÉ{pf-Upóx‘Å]‹áÀÕ{ŒòŽÉªE7‚_cÚÙóÍxYJn]˜‹ÏŒòÏɪ%§‚éѽ•¥¿x®lÀÉ¥jÇE«\Ù{ÜìË剆ÏΰÊ¥É{“ ŽÙêÂõ•ºê]ƒ4×xxxÏŽÒÔŽŽÏŽÑ]]ݲƒÏÏÏÏÒÒÒÔÒÒÒÒLز±Š|mÏÏÏÏÏÒÒÒÒÏÏ.³Æ]±5Æm¹ÏÏÏÏÒÏÏÏÏP~~==ƒ°®®®iÏÏÏÏÏÏÏÏÏÏ‹ÏÏÏÏÏÏÏÏÿÀÿÿÿüøðàÀÀ€€€€ÀÀàðøüAÿÿÿÀÿ(@€ÿÿÿzöÎ~`þþfgbBŠ~b6ººV®&FNz¢˜`Âþþ&&>|BÚÞ'ŠŠ&zÒnz‚JKœþþ&fϦr.E*/£¤Fòò6]..R·r&vzæþþ3ÊÍV–R~&6&RB^z’vþþ>4râ :>Â~&Z[43# sF ""1zÅbºBz®O5*²²HŽ Bnªj# 2j)“•Núú†Z:R 2GNR*RjJbd4¬°ˆˆLêì0,S¡Bãå>ÊÊ?-BC0šš:rnnŠW6ÅÅÅzRR.¾¾:f&4 66F…F4&~^Â+ ">Z¶^_Ê~ vînÚ*R>&2.Zzz*?N™ &,>&b²jjzNnþþ..:JVX"‚†BuVVŸb¿vbÈ”Z&,::+ž¡23*Ž>ÖÚ 2¶¶ Zš >B vv.&& :;¥f$S:FGbcmF&LG. 6B2:rê ”`&"^>"&^®Zª :V>>BB$rv rr**:m:a jjcÁwJN2 /Uª 22JJÊzj×  Z±.U66>m)zzNNNN^¼"D *2 .A,N "6*HB}6bjцX&S¦$††2]>fNRZZfÈ# ) " "&&B .26:>u>>Ê~zòvòvêrænânÞ   &&"" && **": .. 26:v::ðl½òlò¾¾óóóòòðòòlll¢¢llðl½Eòò¾õó¾¾óòò¾òñllll¢lllðE¾óEó4Žõõôóó¾òòllllï¢ïíí¢¢¢llòòòõõóŽßŽ44ŽóõóEòòòòlïïïîííí¢¢¢¢ðlòòòõ4ŽŽ“4ß4÷Ž4óóóò½òllï¢íííííí¢¢¢¢¢ðlò¾óõ44÷¯øuø4÷4ŽŽó¾¾òll¢¢¢íííííííí¢¢¢¢ðððòõŽŽ“ø§¯ùøøø÷ŽŽõóòòl¢¢¢ííííìííí¡¢ï¢¢ðllòòŽ4Ž“ù¸¸¸áùùøø÷4õóòò𢢢¢íííììíí¡¡ïïïïÒllòòEô4øøˆû_þþ_û¸ùøø4õ¾ólð𢢢íííììììíí¡¡ïïïlllòòEóŽ4¯ùÁâþS¬ä__áù¯øÞŽòñll¢¢¢ííííiììììíííïïïlllñòòóŽŽ÷ù¸_SäÅ™¬-_¸ø4óEòòl¢¢¢íííííììììììííîïïllò½½¾óŽ÷øùâþŹÙÙ[ŬäþùÞôóòl𢢢¢ííííìììììììiííîïïllò½¾õõ4øùûþ™[Ù/ÙÄ™-¸ø÷Žóòðl𢢢îíííìììììììììííí¢¢ïÒlò½¾õ4“ùûü”Å/V‘rxÙØ¬¸ùøŽóòòllÒ¢¢¢íííìììììììììííí¢¢ïlllò¾õ4¯¸þ¬ÄbA~®²}¬_û§ŽŽóòòllïï¢ííííììììììììííí¢ïïllñòóõ4¯ˆ†SÅ/V‰K‡­€™_ûu4õóEòllïíííììììììììíííí¢ïllòò¾õ4“†g²r‹M#‘g™-¸ùø4õóòlllïï¢íííììììììììiííí¢¢¢llòóõ4uþ™gÃT\BB9?J[¬_“4õ¾òñlïï¢ííííìììììììììíííí¢¢ðlòòóŽøû_™Ù‘‡M) #A®Ù™ÁøŽóòòlð¢¢ííííìììììììììííííí¢¢ðlòòóŽøù_¬€VAP"#ÕJÄ-¸ø÷Žóòð𢢢íííiììììììììííííðlòóô4øþgÃTzYÕJÄä¸&p……ö¥W¢¢ŒÜÜ>>>>ÓÓ––=ììììíííí¢ïïllò¾õ4¯ˆ«}x‰YP~šÄä¸å¢¢µììììííí¢ïïllò½¾õ4¯¸ä[²b‡YPQLb¹þ¸‚å y¢¢R <1ììììíí¡ïïïllò½¾õÞ4ø¸SÅg‘?KrJšÅþûø'*l¢¢¢íí1ºZvìÝqqÝí¡ïïïllòòòóŽ4¯ü-™ÙšV‰Õ®€ÄþøÞCal¢¢¢íí1å´itçéƒjtÒïïïÒlllòóõø¯_SÅ€š­!®Gäþ“4…ºÑl¢¢¢íí´ºÓ@ЊíÇç`îïðlò¾õ4øùÁä¹Ùgg¹”¸¸“4õ£‚3¢¢¢íŒ ìf°ìiíÆë˜í¢¢¢lò½¾õÞ4¯¸üþ¬Ø}}Ä[™_{ùù“4õ*R¢¢îíaµìcHììì¿ç0íí¢ïlòò¾óŽ4¯¯ûüþ™Å¬ä¸ù§÷4õõ¾•X¢¢íí„‚ËììŠ+úí¢ïlllòòóõ4øøùû_-S¬þ«Á¸ø÷ŽŽõ¾EoZ3¢í>Z´ìjƒÆ jHqÖÖÖ’Ï]±É÷øù¸â%w6|øF]±±±Ê¾ —¢í>ì,ÚHm àƒç»j³ÉøŸÚ6$+éªøÂm»ÎòIïï<•ììqêÇíêñïÌt¾s ³ßDæ¨ù×ÚøŽÂæÍll¤ZWö8ììqc ÇeÒííãëð¢’ãòòOjFªèžøøÈèçFô]çàðllÑ›Zkì,ƒOììììiíãëÒ¢’ãòò×±¨“44uéÂó]çࢢïN‚‚ììÇ ç ÔŠìíãëÒï’ÂlòÂ;]4ÞÞÉæ¾]çࢢ¢ï<1ììéUƒîíýëÒï’°ll`^u4õõ©°¾]çࢢ¢¢—<Ëìë,i æœìýëÒï’°ðlÆé’ó¾õÞOæÍò]ætÎÖŠíܦììÔ³ìUìUëÒ¢’°¢Ïç:òò¾sÐÐôòÏÆçéÀ›ZŒììÔ³ìUìUëÒ¢¶ë»æ+ãEòò^ëjòlÏçà¢:éXìì»iìéç ìUëÒí¶tϳOEll· òòlÏçeí’jììéçÇœæ»ÝUëÒín°¢ÛéÎl’é³’llòlÏçeí˜ë7—ììœëçæ»:éÀUëîín°¢¢¿Úðà³EððllÒÖçeíí»5<ËÝÝì˜ÝUëîín°¢ítëñÍslïE:lïÖçeíî»5 •vììUëîín°íí·mðÌçElï0¿ÒïÖçeíŠ+ 2µ„ììUëîìݰíÒëf¢ñ»0ïïÎfïïÖçeíHæºÓk –ìýëîìHOœ·jÍ¢ïÎtïúéfïÒ`æÎÀ»5hì´¶ƒëîÀêêêêêm¿ í¢ïltçéçëÖ¢`êêêê+(.µÓºº¼0Ô»ëîìììíìíí¡íííïï¢Ý eÒííï¡ííí8‚Ë2ìì˜ììììììíí¡íííïïîíïîííí¡¡íí¡yµZ¼ììììììììiííííí¡ïíí¡íííí¡¡íídådË‚2ìììììììiííííí¡¡íííííííí¡íì´<X‚ìììììììíìííí¡¡íííííìíí¡íÜZX2 Ëììììììíìììíí¡ííííiìììí„ZÓå ìììììììììììííììííìììììå2º¼ììììììììííììiíìììììR–¼Ëììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿü?ÿÿÿÿàÿÿÿÿ€ÿÿÿþÿÿÿü?ÿÿøÿÿàÿÿÀÿÿ€ÿÿÿþÿþü?ø?øðàààÀÀÀ€€€€€€€€ÀÀÀàààðøø?ü?þþÿÿÿÿ€ÿÀ?ÿàÿøÿü ÿþÿÿÿÿ€ÿÿÿÿàÿÿÿÿü?ÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿglbsp-2.24-source/gui/files.cc0000644000175000017500000004305510650405206015526 0ustar aaptedaapted//------------------------------------------------------------------------ // FILES : Unix/FLTK File boxes //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" #define MY_GWA_COLOR \ fl_color_cube((FL_NUM_RED-1)*3/4, 0, 0) static void file_box_inout_CB(Fl_Widget *w, void *data) { guix_win->files->WriteInfo(); // update output box in GWA mode guix_win->files->InFileChanged(); } static void file_in_browse_CB(Fl_Widget *w, void *data) { const char *name = fl_file_chooser("Select an input file", "*.wad", guix_win->files->in_file->value()); // cancelled ? if (! name) return; guix_win->files->in_file->value(name); guix_win->files->in_file->redraw(); guix_win->files->WriteInfo(); guix_win->files->InFileChanged(); } static void file_out_browse_CB(Fl_Widget *w, void *data) { const char *name = fl_file_chooser("Select an output file", "*.wad", guix_win->files->out_file->value()); if (! name) return; guix_win->files->out_file->value(name); guix_win->files->out_file->redraw(); guix_win->files->WriteInfo(); } static void file_out_guess_CB(Fl_Widget *w, void *data) { guix_win->files->out_file->value( HelperGuessOutput(guix_win->files->in_file->value())); guix_win->files->out_file->redraw(); guix_win->files->WriteInfo(); } // // FileBox Constructor // Guix_FileBox::Guix_FileBox(int x, int y, int w, int h) : Fl_Group(x, y, w, h, "Files") { // cancel the automatic 'begin' in Fl_Group constructor end(); box(FL_THIN_UP_BOX); labelfont(FL_HELVETICA | FL_BOLD); labeltype(FL_NORMAL_LABEL); align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_TOP); // create the file group -- serves as the resizable int len = w - 62 - 178; file_group = new Fl_Group(x+62, y, len, h); file_group->end(); add(file_group); resizable(file_group); // create input and output file widgets int CX = x; int CY = y+18; in_label = new Fl_Box(CX, CY, 62, 26, "Input "); in_label->align(FL_ALIGN_INSIDE | FL_ALIGN_RIGHT); add(in_label); CY += 30; out_label = new Fl_Box(CX, CY, 62, 26, "Output "); out_label->align(FL_ALIGN_INSIDE | FL_ALIGN_RIGHT); add(out_label); CX = x+62; CY = y+18; in_file = new Fl_Input(CX, CY, len, 26); in_file->callback((Fl_Callback *) file_box_inout_CB); in_file->when(FL_WHEN_CHANGED); file_group->add(in_file); CY += 30; out_file = new Fl_Input(CX, CY, len, 26); out_file->callback((Fl_Callback *) file_box_inout_CB); out_file->when(FL_WHEN_CHANGED); file_group->add(out_file); // this widget is normally hidden. It occupies the same space as // the out_file widget. When GWA mode is selected, the normal // output box is hidden and this one is shown instead. gwa_filename = GlbspStrDup(""); out_gwa_file = new Fl_Output(CX, CY, len, 26); out_gwa_file->textcolor(MY_GWA_COLOR); out_gwa_file->selection_color(FL_CYAN); out_gwa_file->hide(); file_group->add(out_gwa_file); CX = x+70+len; CY = y+18; in_browse = new Fl_Button(CX, CY, 80, 26, "Browse"); in_browse->align(FL_ALIGN_INSIDE); in_browse->callback((Fl_Callback *) file_in_browse_CB, in_file); add(in_browse); CY += 30; out_browse = new Fl_Button(CX, CY, 80, 26, "Browse"); out_browse->align(FL_ALIGN_INSIDE); out_browse->callback((Fl_Callback *) file_out_browse_CB, out_file); add(out_browse); CX += 86; out_guess = new Fl_Button(CX, CY, 70, 26, "Guess"); out_guess->align(FL_ALIGN_INSIDE); out_guess->callback((Fl_Callback *) file_out_guess_CB, out_file); add(out_guess); ReadInfo(); } // // FileBox Destructor // Guix_FileBox::~Guix_FileBox() { WriteInfo(); GlbspFree(gwa_filename); } void Guix_FileBox::ReadInfo() { in_file->value(guix_info.input_file); in_file->redraw(); out_file->value(guix_info.output_file); out_file->redraw(); InFileChanged(); GWA_Changed(); } void Guix_FileBox::WriteInfo() { GlbspFree(guix_info.input_file); guix_info.input_file = NULL; GlbspFree(guix_info.output_file); guix_info.output_file = NULL; // treat "" the same as a NULL string ptr if (in_file->value() && strlen(in_file->value()) > 0) guix_info.input_file = GlbspStrDup(in_file->value()); if (out_file->value() && strlen(out_file->value()) > 0) guix_info.output_file = GlbspStrDup(out_file->value()); } void Guix_FileBox::GWA_Changed() { if (guix_info.gwa_mode) { out_file->hide(); out_gwa_file->show(); out_browse->deactivate(); out_guess->deactivate(); } else { out_gwa_file->hide(); out_file->show(); out_browse->activate(); out_guess->activate(); } } void Guix_FileBox::InFileChanged(void) { GlbspFree(gwa_filename); gwa_filename = GlbspStrDup( HelperReplaceExt(guix_info.input_file, "gwa")); out_gwa_file->value(gwa_filename); out_gwa_file->redraw(); } void Guix_FileBox::LockOut(boolean_g lock_it) { if (lock_it) { in_file->set_output(); out_file->set_output(); out_gwa_file->set_output(); in_browse->set_output(); out_browse->set_output(); out_guess->set_output(); } else { in_file->clear_output(); out_file->clear_output(); out_gwa_file->clear_output(); in_browse->clear_output(); out_browse->clear_output(); out_guess->clear_output(); } } //------------------------------------------------------------------------ // // FactorBox Constructor // Guix_FactorBox::Guix_FactorBox(int x, int y, int w, int h) : Fl_Group(x, y, w, h) { // cancel the automatic 'begin' in Fl_Group constructor end(); box(FL_THIN_UP_BOX); resizable(0); // no resizing the kiddies, please // create factor input box factor = new Fl_Counter(x+60, y+8, 100, 24, "Factor "); factor->align(FL_ALIGN_LEFT); factor->type(FL_SIMPLE_COUNTER); factor->range(1, 32); factor->step(1, 1); add(factor); ReadInfo(); } // // FactorBox Destructor // Guix_FactorBox::~Guix_FactorBox() { WriteInfo(); } void Guix_FactorBox::ReadInfo() { factor->value(guix_info.factor); } void Guix_FactorBox::WriteInfo() { guix_info.factor = (int) factor->value(); } void Guix_FactorBox::LockOut(boolean_g lock_it) { if (lock_it) factor->set_output(); else factor->clear_output(); } //------------------------------------------------------------------------ static boolean_g BuildValidateOptions(void) { // This routine checks for all manners of nasty input/output file // problems. Belt up, it's a bumpy ride !! int choice; char buffer[1024]; // a) Empty or invalid filenames if (!guix_info.input_file || guix_info.input_file[0] == 0) { DialogShowAndGetChoice(ALERT_TXT, skull_image, "Please choose an Input filename."); return FALSE; } if (!guix_info.output_file || guix_info.output_file[0] == 0) { DialogShowAndGetChoice(ALERT_TXT, skull_image, "Please choose an Output filename."); return FALSE; } if (! HelperFilenameValid(guix_info.input_file)) { sprintf(buffer, "Invalid Input filename:\n" "\n" " %s\n" "\n" "Please check the filename and try again.", guix_info.input_file); DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer); return FALSE; } if (! HelperFilenameValid(guix_info.output_file)) { sprintf(buffer, "Invalid Output filename:\n" "\n" " %s\n" "\n" "Please check the filename and try again.", guix_info.output_file); DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer); return FALSE; } // b) Missing extensions if (! HelperHasExt(guix_info.input_file)) { if (guix_prefs.lack_ext_warn) { sprintf(buffer, "The Input file you selected has no extension.\n" "\n" "Do you want to add \".WAD\" and continue ?"); choice = DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer, "OK", "Cancel"); if (choice != 0) return FALSE; } char *new_input = HelperReplaceExt(guix_info.input_file, "wad"); GlbspFree(guix_info.input_file); guix_info.input_file = GlbspStrDup(new_input); guix_win->files->ReadInfo(); } if (! HelperHasExt(guix_info.output_file)) { if (guix_prefs.lack_ext_warn) { sprintf(buffer, "The Output file you selected has no extension.\n" "\n" "Do you want to add \".%s\" and continue ?", guix_info.gwa_mode ? "GWA" : "WAD"); choice = DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer, "OK", "Cancel"); if (choice != 0) return FALSE; } char *new_output = HelperReplaceExt(guix_info.output_file, guix_info.gwa_mode ? "gwa" : "wad"); GlbspFree(guix_info.output_file); guix_info.output_file = GlbspStrDup(new_output); guix_win->files->ReadInfo(); } // c) No such input file if (! HelperFileExists(guix_info.input_file)) { sprintf(buffer, "Could not open the Input file:\n" "\n" " %s\n" "\n" "Please check the filename and try again.", guix_info.input_file); DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer); return FALSE; } // d) Use of the ".gwa" extension if (HelperCheckExt(guix_info.input_file, "gwa")) { DialogShowAndGetChoice(ALERT_TXT, skull_image, "The Input file you selected has the GWA extension, " "but GWA files do not contain any level data, so " "there wouldn't be anything to build nodes for.\n" "\n" "Please choose another Input file."); return FALSE; } if (HelperCheckExt(guix_info.output_file, "gwa") && ! guix_info.gwa_mode) { choice = DialogShowAndGetChoice(ALERT_TXT, skull_image, "The Output file you selected has the GWA extension, " "but the GWA Mode option is not enabled.\n" "\n" "Do you want to enable GWA Mode and continue ?", "OK", "Cancel"); if (choice != 0) return FALSE; guix_info.gwa_mode = TRUE; guix_info.no_normal = FALSE; guix_info.force_normal = FALSE; guix_win->build_mode->ReadInfo(); guix_win->files->GWA_Changed(); guix_win->misc_opts->GWA_Changed(); } // e) Input == Output // f) Output file already exists guix_info.load_all = FALSE; if (HelperCaseCmp(guix_info.input_file, guix_info.output_file) == 0) { if (guix_prefs.same_file_warn) { sprintf(buffer, "Warning: Input and Output files are the same.\n" "\n" "This will use a lot more memory than normal, since the " "whole input file must be loaded in. On a low memory " "machine, the node building may fail (especially if the " "wad is very large, e.g. DOOM2.WAD). There is also a " "small risk: if something goes wrong during saving, your " "wad file will be toast.\n" "\n" "Do you want to continue ?"); choice = DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer, "OK", "Cancel"); if (choice != 0) return FALSE; } guix_info.load_all = TRUE; } else if (guix_prefs.overwrite_warn && HelperFileExists(guix_info.output_file)) { sprintf(buffer, "Warning: the chosen Output file already exists:\n" "\n" " %s\n" "\n" "Do you want to overwrite it ?", guix_info.output_file); choice = DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer, "OK", "Cancel"); if (choice != 0) return FALSE; } return TRUE; } static boolean_g BuildCheckInfo(void) { char buffer[1024]; for (;;) { glbsp_ret_e ret = GlbspCheckInfo(&guix_info, &guix_comms); if (ret == GLBSP_E_OK) return TRUE; if (ret != GLBSP_E_BadInfoFixed) { sprintf(buffer, "The following problem was detected with the current " "node building options:\n" "\n" " %s\n" "\n" "Please fix the problem and try again.", guix_comms.message ? guix_comms.message : MISSING_COMMS); // user doesn't have any real choice here DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer); guix_win->ReadAllInfo(); break; } sprintf(buffer, "The following problem was detected with the current " "node building options:\n" "\n" " %s\n" "\n" "However, the option causing the problem has now been " "changed into something that should work. " "Do you want to continue ?", guix_comms.message ? guix_comms.message : MISSING_COMMS); int choice = DialogShowAndGetChoice(ALERT_TXT, skull_image, buffer, "OK", "Cancel"); if (choice != 0) break; } return FALSE; } static void BuildDoBuild(void) { glbsp_ret_e ret = GlbspBuildNodes(&guix_info, &guix_funcs, &guix_comms); if (ret == GLBSP_E_OK) return; guix_win->progress->ClearBars(); if (ret == GLBSP_E_Cancelled) { guix_win->text_box->AddMsg("\n*** Cancelled ***\n", FL_BLUE, TRUE); return; } // something went wrong :( char err_kind = '?'; switch (ret) { case GLBSP_E_ReadError: guix_win->text_box->AddMsg("\n*** Read Error ***\n", FL_BLUE, TRUE); err_kind = 'r'; break; case GLBSP_E_WriteError: guix_win->text_box->AddMsg("\n*** Write Error ***\n", FL_BLUE, TRUE); err_kind = 'w'; break; // these two shouldn't happen case GLBSP_E_BadArgs: case GLBSP_E_BadInfoFixed: guix_win->text_box->AddMsg("\n*** Option Error ***\n", FL_BLUE, TRUE); err_kind = 'o'; break; case GLBSP_E_Unknown: default: guix_win->text_box->AddMsg("\n*** Error ***\n", FL_BLUE, TRUE); break; } char buffer[1024]; sprintf(buffer, "The following problem was encountered when trying to " "build the nodes:\n" "\n" " %s\n", guix_comms.message ? guix_comms.message : MISSING_COMMS); if (err_kind == 'r') { strcat(buffer, "\nCheck that the Input file is a valid WAD " "file, and it is not corrupted."); } else if (err_kind == 'w') { strcat(buffer, "\nCheck that your hard disk (or floppy disk, etc) " "has not run out of storage space."); } DialogShowAndGetChoice(ALERT_TXT, pldie_image, buffer); } static void builder_build_CB(Fl_Widget *w, void *data) { // disable most of the interface, especially the BUILD button itself // (this routine is NOT reentrant !). guix_win->LockOut(TRUE); // make sure info is up-to-date guix_win->WriteAllInfo(); // save cookies, in case the build crashes or calls the fatal-error // function. CookieWriteAll(); // sleight of hand for GWA mode: we remember the old output name in // the nodebuildinfo and replace it with the gwa name. The memory // stuff is messy, since we can't be 100% sure that 'output_file' // field won't be freed and assigned a new value by the main code. const char *old_output = guix_info.output_file; boolean_g gwa_hack = FALSE; if (guix_info.gwa_mode) { guix_info.output_file = GlbspStrDup(guix_win->files->gwa_filename); gwa_hack = TRUE; } #if 0 // DEBUG fprintf(stderr, "BUILD\n INPUT = [%s]\n OUTPUT = [%s]\n\n", guix_info.input_file, guix_info.output_file); #endif if (BuildValidateOptions()) { if (BuildCheckInfo()) { BuildDoBuild(); guix_win->text_box->AddHorizBar(); } } if (gwa_hack) { GlbspFree(guix_info.output_file); guix_info.output_file = old_output; } // if the build info changed, make sure widgets are in sync. // This is not the ideal place, it would be better to call this as // soon as any change could've happened -- but the GWA hack // interferes with that approach. // guix_win->ReadAllInfo(); GlbspFree(guix_comms.message); guix_comms.message = NULL; // restore user interface to normal guix_win->LockOut(FALSE); guix_win->progress->ClearBars(); } static void builder_cancel_CB(Fl_Widget *w, void *data) { guix_comms.cancelled = TRUE; } // // BuildButton Constructor // Guix_BuildButton::Guix_BuildButton(int x, int y, int w, int h) : Fl_Group(x, y, w, h) { end(); // turn off auto-add-widgets resizable(0); // no resizing the kiddies, please // create button sitting in a space of its own build = new Fl_Button(x+10, y+10, 90, 30, "Build"); build->box(FL_ROUND_UP_BOX); build->align(FL_ALIGN_INSIDE); build->callback((Fl_Callback *) builder_build_CB); add(build); stopper = new Fl_Button(x+140, y+10, 90, 30, "Stop"); stopper->box(FL_ROUND_UP_BOX); stopper->align(FL_ALIGN_INSIDE); stopper->callback((Fl_Callback *) builder_cancel_CB); stopper->shortcut(FL_Escape); add(stopper); } // // BuildButton Destructor // Guix_BuildButton::~Guix_BuildButton() { // nothing to do } void Guix_BuildButton::LockOut(boolean_g lock_it) { if (lock_it) build->set_output(); else build->clear_output(); } glbsp-2.24-source/gui/about.cc0000644000175000017500000031552610650405215015543 0ustar aaptedaapted//------------------------------------------------------------------------ // ABOUT : Unix/FLTK About image //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // This image created by Andrew Apted, using the GIMP. // //------------------------------------------------------------------------ #include "local.h" const unsigned char about_image_pal[256 * 3] = { 2,2,2, 246,122,6, 22,126,206, 18,90,144, 18,65,95, 7,42,69, 179,176,44, 11,30,41, 114,113,21, 254,254,70, 151,150,28, 22,22,2, 148,76,4, 139,137,34, 18,18,2, 14,14,2, 134,132,33, 162,90,10, 20,108,175, 30,65,73, 251,250,72, 130,128,24, 10,10,2, 85,44,3, 126,63,2, 22,90,138, 246,246,81, 180,91,5, 126,126,34, 42,42,9, 6,6,2, 102,65,10, 59,30,2, 246,242,59, 230,114,6, 254,254,206, 228,226,58, 92,90,17, 83,82,17, 46,42,11, 42,30,6, 94,126,142, 54,54,6, 195,98,4, 63,62,10, 30,30,6, 199,197,48, 20,56,74, 254,254,144, 75,74,14, 20,55,70, 38,38,6, 34,24,4, 110,110,26, 126,122,32, 30,98,142, 171,169,37, 78,43,4, 226,111,6, 6,26,38, 78,126,158, 16,74,114, 254,254,130, 154,79,4, 90,86,24, 111,57,3, 34,34,6, 99,98,23, 26,110,166, 68,45,8, 218,218,38, 67,66,10, 22,114,182, 62,126,170, 181,122,63, 22,48,57, 206,102,6, 26,86,122, 50,50,6, 32,18,2, 170,122,70, 254,254,86, 16,78,124, 10,14,14, 26,26,6, 158,79,3, 14,14,6, 216,214,57, 100,52,3, 134,122,104, 6,18,25, 206,122,38, 11,55,87, 14,10,2, 162,161,37, 106,106,17, 121,120,24, 138,76,7, 119,63,4, 18,38,47, 222,110,6, 59,58,10, 51,30,3, 90,55,7, 31,50,43, 189,187,39, 75,38,2, 218,109,6, 54,126,178, 11,22,25, 4,10,15, 176,86,4, 254,254,254, 211,210,58, 142,70,3, 18,18,6, 26,14,2, 71,70,16, 122,80,14, 10,6,2, 254,254,113, 146,146,26, 14,86,138, 12,26,30, 62,44,8, 237,235,56, 83,82,25, 93,93,35, 79,78,17, 22,118,192, 10,10,6, 104,101,39, 166,86,5, 168,166,51, 234,114,6, 30,30,10, 119,118,34, 206,204,53, 22,18,6, 22,22,10, 26,26,10, 158,122,82, 239,237,79, 254,254,181, 142,140,48, 38,38,10, 42,42,14, 117,74,11, 95,94,17, 8,37,58, 34,34,10, 42,126,190, 94,49,3, 47,46,18, 12,46,70, 53,26,2, 18,14,2, 115,113,40, 99,98,31, 133,70,4, 18,102,165, 188,186,58, 150,146,45, 63,62,16, 26,22,6, 70,38,2, 66,66,16, 86,86,26, 59,58,14, 54,38,9, 75,74,18, 18,14,6, 59,37,5, 50,50,10, 107,106,28, 209,106,6, 22,102,160, 54,54,10, 130,129,35, 46,46,6, 86,66,14, 50,50,15, 154,152,39, 85,50,5, 38,34,11, 54,54,16, 34,30,10, 159,159,52, 66,66,23, 70,70,23, 26,78,106, 173,170,42, 30,26,10, 38,38,14, 254,254,98, 78,62,14, 22,122,202, 46,46,10, 79,78,25, 223,221,64, 100,58,6, 205,204,68, 53,34,5, 38,23,3, 134,132,45, 22,10,2, 95,94,26, 103,102,23, 131,66,3, 121,120,43, 66,37,3, 254,254,225, 166,82,3, 226,122,22, 34,126,194, 144,142,33, 62,62,22, 182,98,8, 115,113,31, 251,250,89, 172,90,6, 30,26,6, 199,197,61, 91,90,25, 153,151,49, 59,58,19, 173,172,56, 170,86,6, 18,86,136, 107,106,36, 18,97,156, 34,30,6, 22,22,6, 75,74,24, 46,46,14, 15,69,109, 146,146,41, 42,38,11, 254,254,161, 45,25,2, 58,54,16, 86,86,16, 103,102,32, 186,93,4, 12,35,43, 242,242,66, 13,50,73, 6,2,2, 130,129,44, 116,70,8, 226,226,82, 179,177,57, 110,110,36, 154,86,8, 238,118,6, 122,122,34 }; const unsigned char about_image_data[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30, 30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,119,30,30,30,30,30,30,30, 30,30,30,119,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,30,0,0,0,0,0,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,119,22,22,22,22,22,119,30,30,30,30,30,30, 30,30,119,22,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,30,30,30,0,0,0,0,0,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,22,22,22,22,22,22,22,30,30,30,30,30,30, 30,30,22,22,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,228,228,228,228,228,228,228,228,228,228, 228,228,228,228,228,228,228,228,122,122,122,122,122,122,122,122, 122,122,122,235,0,0,0,0,0,0,0,0,0,7,122,122, 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, 122,122,122,122,235,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,30,30,30,30,30,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,22,22,22,22,22,22,22,30,30,30,30,30,30, 30,30,22,22,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,18,0,0,0,0,0,0,0,0,0,5,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,18,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,22,22,22,130,22,22,22,30,30,30,30,22,22, 30,30,22,22,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,18,0,0,0,0,0,0,0,0,0,5,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,18,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,22,22,22,130,130,22,22,22,22,22,119,22,22, 22,22,22,22,22,22,22,119,30,30,30,30,30,30,30,30, 30,30,30,22,22,22,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,18,0,0,0,0,0,0,0,0,0,5,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,18,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,22,22,22,22,30,30,30,30,30,30,30,30,30, 22,22,22,22,22,130,130,130,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,119,30,30,30,30,30,30,30, 30,30,30,22,22,22,5,246,235,230,196,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,129,122, 235,92,5,90,0,0,0,0,0,0,0,0,0,30,149,92, 82,230,129,2,2,2,2,2,2,2,2,2,2,2,2,129, 122,4,5,244,90,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,22,22,22,22,30,30,30,30,30,30,22,22,22, 22,22,22,22,22,130,130,130,130,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,30,30,30,22,22,119,119, 30,30,22,22,22,130,22,22,22,30,109,228,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,129,90,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,30,160,2,2,2,2,2,2,2,2,2,129,92,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,22,22,22,22,22,119,30,22,22,22,22,22,22, 22,22,22,22,22,130,130,130,130,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,30,30,22,22,22,22,22, 22,22,22,22,22,130,22,22,22,30,30,30,82,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,18,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,122,2,2,2,2,2,2,2,2,18,110,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,130,130,130,130,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,130,130,130,22,22,30,30,30,30,110,230,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,59,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,129,2,2,2,2,2,2,2,18,110,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,119,22,130,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,130,130,86,130,130,22,22,22,22,22,22, 22,22,130,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,130,130,130,22,22,119,30,30,30,30,109,196,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,230,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,92,2,2,2,2,2,2,2,72,110,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,22,22,130,130,22,22,22,22,22,22,22,22,22, 22,22,22,22,130,130,86,86,86,130,22,22,22,22,22,22, 22,22,130,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,130,130,130,130,22,22,22,30,30,30,30,30,4,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,154, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,30,129,2,2,2,2,2,2,196,59,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,22,22,22,22,130,22,22,22,22,22,22,22,22,22, 22,22,22,22,130,130,86,86,86,86,22,22,22,22,22,22, 22,22,86,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,130,130,130,130,22,22,22,22,22,22,30,30,110,18, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,72, 110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,235,2,2,2,2,2,2,2,154,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,22,22,22,22,130,130,22,22,22,22,22,22,22,22, 22,22,22,22,130,86,86,86,86,86,86,22,22,22,22,22, 93,86,86,93,22,22,22,22,22,22,22,22,22,22,22,22, 22,130,130,130,130,22,22,22,22,22,22,22,22,22,119,149, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 61,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 90,196,2,2,2,2,2,2,82,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,30,30,30,30,30,30,116,32,239,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,22,22,22,22,130,130,22,22,22,22,22,22,22,22, 22,22,22,93,86,86,86,86,86,86,86,15,22,22,22,22, 15,86,86,15,22,22,22,22,22,22,22,22,22,22,22,22, 130,130,86,86,130,22,22,22,22,22,22,22,22,22,22,22, 82,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 196,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 122,2,2,2,2,2,2,160,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,203,165,88,208,212,76,254,1,1,212,30,30, 30,30,30,30,30,30,30,30,30,30,30,22,22,30,30,30, 30,30,22,22,22,22,130,130,130,130,22,22,22,22,22,22, 22,22,22,15,86,86,86,86,86,86,86,15,22,22,22,22, 15,86,86,15,22,22,22,22,22,22,22,22,22,22,22,22, 130,86,86,86,130,22,22,22,22,22,22,22,22,22,22,22, 90,129,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,230,30,30,0,0,0,0,0,0,0,0,0,0,0,149, 2,2,2,2,2,2,129,90,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,76,1,1,1,1,1,1,1,1,1,212,30,30, 30,30,30,30,30,30,30,30,30,30,22,22,22,22,30,22, 119,119,22,22,22,22,130,86,130,130,93,22,22,22,22,22, 22,22,22,15,86,86,86,86,86,86,86,15,93,156,165,88, 208,208,208,208,208,23,202,22,22,22,22,22,22,22,22,15, 86,86,86,86,130,22,22,22,22,22,22,22,22,22,22,22, 22,92,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,246,30,30,0,0,0,0,0,0,0,0,0,0,72, 2,2,2,2,2,2,5,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,30,27,1,1,1,1,1,1,1,1,1,212,30,30, 30,30,30,76,76,76,76,76,76,76,76,76,76,76,76,76, 76,76,76,76,76,76,212,12,98,210,86,15,22,22,22,22, 22,93,93,15,86,86,86,86,86,86,86,152,111,254,1,1, 1,1,1,1,1,1,1,254,27,152,156,22,22,22,15,86, 86,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, 76,76,91,74,80,89,41,151,2,2,2,2,2,2,2,2, 2,2,129,110,30,30,0,0,0,0,0,0,0,0,235,2, 2,2,2,2,2,82,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,30,30,30,93,88,1,1,1,1,1,1,1,212,30,30, 30,30,30,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,34,12,203,22,22,22, 22,15,15,15,86,86,86,86,86,202,43,1,1,1,1,1, 254,76,76,107,1,1,1,1,1,1,34,152,22,93,15,86, 86,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,74,60,2,2,2,2,2,2, 2,2,2,61,30,30,30,0,0,0,0,0,0,59,196,2, 2,2,2,2,18,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30,30,30,30,30,30,58,1,1,1,1,1,1,212,30,30, 30,30,30,30,79,106,76,1,1,1,1,1,1,1,1,76, 208,208,208,85,58,1,1,1,1,1,1,1,254,98,22,22, 15,15,15,15,86,86,86,171,57,254,1,1,1,1,34,65, 138,86,86,86,102,111,1,1,1,1,1,132,22,15,86,86, 86,86,52,57,76,1,1,1,1,1,1,1,1,76,114,208, 208,27,254,1,1,1,1,1,1,1,80,214,2,2,2,2, 2,2,2,2,7,30,30,30,0,0,0,0,0,230,2,2, 2,2,2,196,59,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30, 30,30,30,30,30,30,76,1,1,1,1,1,1,212,30,30, 30,30,30,30,30,30,106,1,1,1,1,1,1,1,34,15, 22,22,22,22,22,152,34,1,1,1,1,1,1,1,159,15, 15,15,15,15,86,86,86,210,254,1,1,1,1,254,102,86, 86,86,86,86,15,15,65,1,1,1,1,132,15,86,86,86, 86,86,86,86,57,1,1,1,1,1,1,1,58,156,22,22, 22,22,52,227,1,1,1,1,1,1,1,91,214,2,2,2, 2,2,2,2,230,30,30,30,30,0,0,0,92,2,2,2, 2,2,2,92,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,30, 30,30,30,30,30,30,76,1,1,1,1,1,1,212,30,30, 30,30,30,30,30,30,239,1,1,1,1,1,1,1,76,22, 22,22,22,22,22,22,32,254,1,1,1,1,1,1,1,210, 15,15,15,15,86,86,138,76,1,1,1,1,1,208,15,86, 86,171,86,86,15,15,15,208,1,1,1,132,15,86,86,86, 86,86,86,86,102,1,1,1,1,1,1,1,76,22,22,22, 22,22,22,22,227,1,1,1,1,1,1,1,80,2,2,2, 2,2,2,2,2,92,30,30,30,30,0,90,129,2,2,2, 2,2,122,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,30,30,30, 30,30,30,30,30,30,76,1,1,1,1,1,1,212,30,30, 30,30,30,30,30,30,239,1,1,1,1,1,1,1,76,22, 22,22,22,22,22,22,22,208,1,1,1,1,1,1,1,111, 15,15,15,15,86,86,88,1,1,1,1,1,1,102,15,86, 86,115,171,86,15,15,15,15,43,1,1,132,15,86,86,171, 171,86,86,86,102,1,1,1,1,1,1,1,76,93,22,22, 22,22,22,22,79,34,1,1,1,1,1,1,1,60,2,2, 2,2,2,2,2,129,83,30,30,30,0,230,2,2,2,2, 2,129,110,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,30,30,30, 30,30,30,30,30,30,76,1,1,1,1,1,1,212,30,30, 30,30,30,30,22,22,239,1,1,1,1,1,1,1,76,22, 22,22,22,22,22,22,22,239,1,1,1,1,1,1,1,34, 15,15,15,15,86,86,243,1,1,1,1,1,1,15,15,86, 86,115,115,86,15,15,15,15,23,1,1,132,86,86,86,115, 115,86,86,86,102,1,1,1,1,1,1,1,76,22,22,22, 22,22,22,22,22,63,1,1,1,1,1,1,1,74,2,2, 2,2,2,2,2,2,82,30,30,30,246,2,2,2,2,2, 2,149,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,30,30,30,30, 30,30,30,30,30,30,76,1,1,1,1,1,1,212,30,30, 22,22,30,22,22,22,239,1,1,1,1,1,1,1,76,22, 22,22,22,22,22,22,22,15,58,1,1,1,1,1,1,1, 40,15,15,15,86,171,254,1,1,1,1,1,1,164,86,115, 115,115,115,171,15,15,15,15,15,175,1,132,86,171,115,115, 115,86,86,15,102,1,1,1,1,1,1,1,76,22,22,22, 22,22,22,22,22,106,1,1,1,1,1,1,1,254,214,2, 2,2,2,2,2,2,2,7,30,83,129,2,2,2,2,2, 82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30, 30,30,30,30,30,30,76,1,1,1,1,1,1,212,30,22, 22,22,22,22,22,22,239,1,1,1,1,1,1,1,76,93, 15,15,22,22,22,22,22,15,76,1,1,1,1,1,1,1, 202,15,15,15,86,102,1,1,1,1,1,1,1,23,115,115, 115,115,115,115,15,15,15,15,15,159,1,227,86,115,115,115, 115,86,86,15,102,1,1,1,1,1,1,1,76,93,22,22, 22,22,22,22,22,203,1,1,1,1,1,1,1,1,73,2, 2,2,2,2,2,2,2,160,30,82,2,2,2,2,2,18, 110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 247,239,57,57,98,88,57,155,247,0,30,30,30,30,30,93, 57,85,98,30,30,30,76,1,1,1,1,1,1,212,22,22, 22,22,22,22,22,22,102,1,1,1,1,1,1,1,76,15, 15,15,15,15,15,15,22,15,76,1,1,1,1,1,1,1, 239,15,15,86,115,202,1,1,1,1,1,1,1,76,138,115, 115,115,115,115,156,15,15,15,15,210,76,97,115,115,115,115, 115,115,86,15,102,1,1,1,1,1,1,1,76,22,22,22, 22,22,22,22,22,22,1,1,1,1,1,1,1,1,41,2, 2,2,2,2,2,2,2,2,3,2,2,2,2,2,2,7, 30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,247,152,27, 254,1,1,1,1,1,1,1,1,243,65,116,119,106,85,34, 1,1,24,30,30,30,76,1,1,1,1,1,1,212,22,22, 22,22,22,22,22,22,102,1,1,1,1,1,1,1,76,15, 15,15,15,15,15,15,93,15,254,1,1,1,1,1,1,58, 15,15,156,115,115,202,1,1,1,1,1,1,1,1,27,164, 115,115,115,115,14,14,14,14,15,15,15,115,115,115,115,115, 115,86,15,15,202,1,1,1,1,1,1,1,76,15,22,22, 22,22,22,22,22,22,1,1,1,1,1,1,1,1,41,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,61,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,57,107,1,1, 1,1,1,1,58,1,1,1,1,1,1,254,34,1,1,1, 1,1,32,30,30,30,76,1,1,1,1,1,1,212,22,22, 22,22,22,22,22,22,102,1,1,1,1,1,1,1,76,15, 15,15,15,15,15,15,15,57,1,1,1,1,1,1,1,12, 115,14,14,115,115,115,254,1,1,1,1,1,1,1,1,76, 202,138,115,115,115,14,14,14,14,14,115,115,115,115,139,115, 115,86,15,15,202,1,1,1,1,1,1,1,76,15,22,22, 22,22,22,22,22,22,1,1,1,1,1,1,1,1,41,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,18,110,30, 30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,88,1,1,1,1, 1,1,76,203,0,247,65,1,1,1,1,1,1,1,1,1, 1,34,30,30,30,30,76,1,1,1,1,1,1,212,22,22, 22,22,22,22,22,22,102,1,1,1,1,1,1,1,76,15, 15,15,86,15,15,15,15,27,1,1,1,1,1,1,34,40, 115,14,115,115,115,115,220,1,1,1,1,1,1,1,1,1, 254,12,40,115,115,14,14,14,14,14,115,115,232,139,139,115, 115,115,15,15,202,1,1,1,1,1,1,1,76,15,93,22, 22,22,22,22,22,102,1,1,1,1,1,1,1,1,108,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,244,30,30, 30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,23,1,1,1,1,1, 1,34,116,0,0,0,0,114,1,1,1,1,1,1,1,175, 212,88,30,30,30,30,76,1,1,1,1,1,1,212,22,22, 22,22,22,22,22,22,102,1,1,1,1,1,1,1,76,15, 15,15,15,86,15,15,208,1,1,1,1,1,1,254,23,115, 115,115,115,115,115,115,103,1,1,1,1,1,1,1,1,1, 1,1,1,227,57,115,115,115,115,115,115,138,232,139,232,115, 115,14,156,115,202,1,1,1,1,1,1,1,76,15,15,22, 22,22,22,22,22,23,1,1,1,1,1,1,1,213,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,61,30,30,30, 30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,119,34,1,1,1,1,1, 1,24,0,0,0,0,0,93,254,1,1,1,1,1,43,30, 30,30,30,30,30,30,76,1,1,1,1,1,1,212,22,22, 22,22,22,22,22,22,102,1,1,1,1,1,1,1,76,15, 15,15,15,86,202,111,1,1,1,1,1,1,175,69,232,232, 115,115,115,115,115,115,232,243,1,1,1,1,1,1,1,1, 1,1,1,1,1,76,152,115,115,115,115,232,139,139,232,115, 115,14,14,115,202,1,1,1,1,1,1,1,76,15,15,15, 22,22,22,22,22,63,1,1,1,1,1,1,1,141,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,109,30,30,30, 30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,88,1,1,1,1,1,1, 1,32,0,0,0,0,30,30,243,1,1,1,1,1,1,210, 30,30,30,30,30,30,76,1,1,1,1,1,1,212,22,22, 22,22,15,22,22,22,102,1,1,1,1,1,1,1,34,132, 132,132,27,107,1,1,1,1,1,1,243,88,164,139,139,232, 232,115,115,115,115,232,232,40,107,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,76,23,115,232,139,139,139,232,115, 115,115,115,115,202,1,1,1,1,1,1,1,76,15,15,15, 15,22,22,22,138,34,1,1,1,1,1,1,254,73,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,3,30,30,30, 30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,85,1,1,1,1,1,1, 1,205,0,0,0,0,30,30,12,1,1,1,1,1,1,208, 30,30,30,30,30,30,76,1,1,1,1,1,1,212,22,22, 22,15,15,15,15,93,102,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,254,63,23,138,115,232,139,139, 232,232,138,232,232,232,232,232,169,175,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,132,84,139,140,139,232,115, 115,115,115,115,202,1,1,1,1,1,1,1,76,15,15,15, 15,22,22,22,85,1,1,1,1,1,1,1,89,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,149,30,30, 30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,76,1,1,1,1,1,1, 1,0,0,0,0,30,30,30,24,1,1,1,1,1,1,212, 30,30,30,30,30,30,76,1,1,1,1,1,1,212,22,22, 93,15,15,15,15,15,102,1,1,1,1,1,1,1,34,132, 132,132,27,107,1,1,1,1,1,1,1,34,12,202,139,139, 232,232,232,232,232,232,232,139,140,184,220,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,76,184,140,139,232,115, 115,115,115,115,172,1,1,1,1,1,1,1,34,156,15,15, 15,22,156,63,1,1,1,1,1,1,1,12,235,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,72,110,30, 30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,76,1,1,1,1,1,1, 1,0,0,0,0,30,30,30,24,1,1,1,1,1,1,212, 30,30,30,30,30,30,76,1,1,1,1,1,1,212,22,22, 15,15,15,15,15,86,102,1,1,1,1,1,1,1,76,15, 15,15,156,14,172,220,1,1,1,1,1,1,1,134,88,140, 139,232,232,232,232,232,232,140,140,192,192,183,175,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,43,192,139,232,115, 115,232,232,232,172,1,1,1,1,1,1,1,1,243,88,152, 88,114,107,1,1,1,1,1,1,254,65,22,83,72,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,61,30, 30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,111,1,1,1,1,1,1, 1,116,0,0,30,30,30,30,12,1,1,1,1,1,1,208, 30,30,30,30,30,22,76,1,1,1,1,1,1,212,22,15, 15,15,15,15,86,86,102,1,1,1,1,1,1,1,76,15, 15,15,14,14,115,115,98,1,1,1,1,1,1,1,1,98, 140,164,232,232,232,232,232,140,140,135,135,140,84,88,175,1, 1,1,1,1,1,1,1,1,1,1,1,1,159,232,232,115, 232,232,232,232,172,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,34,114,203,22,22,22,246,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,196,123, 30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,65,1,1,1,1,1,1, 1,57,0,30,30,30,30,30,76,1,1,1,1,1,1,210, 30,30,30,30,119,22,76,1,1,1,1,1,1,212,15,15, 15,15,15,86,86,86,202,1,1,1,1,1,1,1,76,15, 15,15,156,14,115,115,115,12,1,1,1,1,1,1,1,254, 69,140,84,232,164,84,84,140,140,135,135,135,140,84,84,183, 220,1,1,1,1,1,1,1,1,1,1,1,134,231,232,232, 232,232,232,232,172,1,1,1,1,1,1,1,1,1,1,1, 1,1,107,43,132,98,165,22,22,22,22,22,22,22,230,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,230, 30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,119,34,1,1,1,1,1, 1,111,0,30,30,30,30,239,1,1,1,1,1,1,76,30, 30,30,30,30,22,22,76,1,1,1,1,1,1,132,22,15, 15,15,86,86,86,86,202,1,1,1,1,1,1,1,76,14, 14,14,14,115,115,115,115,221,134,1,1,1,1,1,1,1, 243,140,140,84,84,84,84,84,135,135,150,135,192,84,84,192, 135,124,243,1,1,1,1,1,1,1,1,1,1,200,232,232, 232,139,139,232,172,1,1,1,1,1,1,1,76,15,15,15, 15,15,15,15,93,22,15,22,22,22,22,22,22,22,246,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 92,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,152,1,1,1,1,1, 1,1,23,30,30,30,119,43,1,1,1,1,1,254,172,30, 30,30,30,22,22,22,76,1,1,1,1,1,1,132,22,93, 15,15,86,86,86,86,202,1,1,1,1,1,1,1,76,14, 14,14,115,115,115,115,115,232,12,1,1,1,1,1,1,1, 1,169,140,84,84,84,84,140,135,186,150,150,135,84,135,135, 135,135,84,98,254,1,1,1,1,1,1,1,1,85,232,232, 84,140,140,232,172,1,1,1,1,1,1,1,76,15,15,15, 15,15,15,15,15,15,15,15,93,22,22,22,93,86,18,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 129,90,30,30,30,30,30,30,30,30,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,88,1,1,1,1, 1,1,1,12,23,88,175,1,1,1,1,1,58,106,30,30, 30,30,119,22,22,22,76,1,1,1,1,1,1,132,22,93, 15,86,86,86,86,86,202,1,1,1,1,1,1,1,76,14, 115,115,115,115,115,115,115,232,103,1,1,1,1,1,1,1, 1,31,135,192,84,200,220,69,135,150,150,150,135,45,135,135, 150,135,45,84,103,1,1,1,1,1,1,1,1,43,84,84, 140,140,84,232,172,1,1,1,1,1,1,1,76,15,15,15, 15,15,15,15,15,15,15,15,15,15,15,15,15,61,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,82,30,30,30,30,30,30,30,30,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,155,111,1,1, 1,1,1,1,1,1,1,1,1,1,254,12,79,30,30,30, 30,119,22,22,22,22,76,1,1,1,1,1,1,132,22,15, 15,15,86,86,86,86,202,1,1,1,1,1,1,1,76,115, 115,115,115,115,115,115,232,232,172,1,1,1,1,1,1,1, 1,97,135,135,45,97,1,63,135,150,193,150,150,45,135,150, 150,186,45,221,84,97,1,1,1,1,1,1,1,175,84,140, 140,140,84,232,172,1,1,1,1,1,1,1,76,15,15,15, 15,15,15,15,15,15,15,15,15,15,86,86,99,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,244,30,30,30,30,30,30,30,30,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,205,98,254, 1,1,254,1,1,1,107,43,12,23,156,30,30,30,30,30, 30,22,22,22,22,22,76,1,1,1,1,1,1,132,22,22, 15,15,86,86,86,86,202,1,1,1,1,1,1,1,76,115, 115,115,115,115,138,232,232,232,172,1,1,1,1,1,1,1, 1,97,150,135,135,98,1,134,184,150,193,193,150,45,186,150, 150,150,45,45,45,184,254,1,1,1,1,1,1,175,192,135, 135,140,84,232,172,1,1,1,1,1,1,1,76,15,15,15, 15,15,15,15,15,15,15,15,15,86,86,115,18,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,160,110,30,30,30,30,30,30,30,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,247,114,254,1,1, 76,203,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 119,22,22,22,22,22,76,1,1,1,1,1,1,132,22,15, 15,15,15,86,86,86,202,1,1,1,1,1,1,1,76,115, 138,115,115,138,232,232,232,232,124,1,1,1,1,1,1,1, 1,159,150,150,135,31,1,1,249,193,193,193,150,150,150,150, 193,150,45,45,45,45,76,1,1,1,1,1,1,27,135,135, 135,140,84,232,172,1,1,1,1,1,1,1,76,14,14,15, 15,15,15,15,15,15,15,86,86,86,86,82,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,92,30,30,30,30,30,30,30,30,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,205,76,1,1,1,1, 32,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 22,22,22,22,22,22,76,1,1,1,1,1,1,132,15,15, 15,15,15,15,86,86,202,1,1,1,1,1,1,1,76,232, 232,232,232,232,232,232,232,232,200,1,1,1,1,1,1,1, 1,103,193,184,150,103,1,1,100,39,146,146,193,150,150,145, 193,150,66,45,45,231,220,1,1,1,1,1,1,63,135,135, 135,84,84,164,172,1,1,1,1,1,1,1,76,14,14,14, 15,15,15,15,15,15,86,86,86,86,99,2,2,2,2,2, 2,61,61,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,129,90,30,30,30,30,30,30,30,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,114,1,1,1,1,1, 65,30,30,30,30,30,30,30,30,30,30,30,30,30,22,22, 22,22,22,22,22,22,76,1,1,1,1,1,1,132,15,15, 15,15,15,15,15,86,202,1,1,1,1,1,1,1,175,232, 232,232,232,232,232,232,232,232,132,1,1,1,1,1,1,1, 254,237,193,193,145,69,1,1,1,253,146,153,237,145,145,193, 146,145,150,66,150,150,217,1,1,1,1,1,1,103,150,135, 135,84,84,84,172,1,1,1,1,1,1,1,76,14,14,14, 14,14,14,14,115,115,115,115,115,115,18,2,2,2,2,2, 72,86,86,72,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,228,30,30,30,30,30,30,30,30,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,34,1,1,1,1,1, 1,43,12,24,24,24,24,24,24,24,88,210,93,22,22,22, 22,22,22,22,22,22,76,1,1,1,1,1,1,132,86,15, 15,15,15,15,15,15,202,1,1,1,1,1,1,1,175,232, 232,232,232,232,232,232,164,202,254,1,1,1,1,1,1,1, 253,45,145,146,193,124,1,1,1,1,31,153,146,145,145,146, 146,145,184,150,150,184,34,1,1,1,1,1,175,150,150,135, 45,221,84,84,172,1,1,1,1,1,1,1,76,14,14,14, 115,115,115,115,115,115,115,115,115,235,2,2,2,2,2,2, 154,15,15,154,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,149,30,30,30,30,30,30,30,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,34,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,254,212,102,22, 22,22,22,22,22,22,76,1,1,1,1,1,1,132,86,86, 86,15,15,15,15,15,202,1,1,1,1,1,1,1,254,231, 232,140,84,84,84,84,221,243,1,1,1,1,1,1,1,34, 169,45,184,146,146,146,1,1,1,1,254,31,234,29,29,234, 234,29,145,145,145,31,1,1,1,1,1,1,200,193,150,135, 45,84,84,84,124,1,1,1,1,1,1,1,76,14,14,115, 115,115,115,115,115,115,115,115,99,196,2,2,2,2,2,230, 15,15,15,22,230,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,18,110,30,30,30,30,30,30,30,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,114,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,208, 22,22,22,22,22,22,58,1,1,1,1,1,1,243,86,86, 86,86,86,86,15,15,152,1,1,1,1,1,1,1,1,63, 192,140,140,140,84,183,43,1,1,1,1,1,1,1,134,103, 231,45,150,146,153,146,254,1,1,1,1,254,147,29,39,234, 234,29,145,145,124,34,1,1,1,1,1,63,193,145,150,231, 45,221,84,84,200,1,1,1,1,1,1,1,254,52,115,138, 232,232,232,232,115,115,115,139,18,2,2,2,2,2,196,7, 15,15,93,22,7,196,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,4,30,30,30,30,30,30,30,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,205,76,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 208,22,22,102,57,212,1,1,1,1,1,1,1,1,97,23, 202,86,86,202,57,65,58,1,1,1,1,1,1,1,1,1, 34,27,220,243,100,1,1,1,1,1,1,1,1,43,69,145, 66,66,66,29,181,153,17,1,1,1,1,1,1,43,249,240, 181,197,69,97,254,1,1,1,1,1,253,146,146,145,150,66, 45,183,200,97,34,1,1,1,1,1,1,1,1,175,159,103, 69,202,232,232,232,115,115,235,2,2,2,2,2,2,61,86, 86,15,93,22,22,61,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,196,109,30,30,30,30,30,30,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,205,111,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,155,22,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,86,115,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,34,17,103,150,184,145, 145,51,66,29,181,181,234,31,175,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,175,31,146,234,146,145,150,66, 45,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,227,232,232,232,138,99,196,2,2,2,2,2,72,115,86, 15,15,15,22,22,115,72,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,230,30,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,106,76,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,12,22,212,212,212,132,132,132,132,132,132,132,132,132,227, 227,115,115,227,227,227,227,227,227,227,227,227,227,227,227,220, 220,220,220,220,220,220,12,97,31,124,45,66,66,66,145,237, 29,145,51,237,234,185,181,181,181,180,17,175,1,1,1,1, 1,1,1,1,1,34,217,249,197,234,234,234,146,145,184,66, 45,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, 220,98,232,232,232,139,18,2,2,2,2,2,2,246,86,15, 15,15,22,22,22,22,246,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,154,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,57,111,254,1,1, 1,107,212,24,24,24,24,12,243,254,1,1,1,1,1,1, 1,76,22,22,22,22,22,22,15,15,86,86,86,86,86,115, 115,115,115,115,115,115,115,115,232,232,232,232,232,232,232,84, 84,140,135,135,135,150,150,150,150,150,150,66,66,184,145,29, 39,29,29,29,197,225,225,181,181,185,225,188,216,180,147,118, 118,147,147,31,195,216,225,181,234,181,181,234,29,145,51,66, 66,45,45,45,84,84,84,84,84,84,84,84,140,140,140,140, 139,232,232,232,232,61,2,2,2,2,2,2,230,15,15,15, 15,15,22,22,22,22,22,230,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,72,110,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,247,212,1,1,1,1,1, 65,30,30,30,30,30,30,30,30,116,208,1,1,1,1,1, 1,1,22,22,22,22,22,22,15,15,86,86,86,86,115,115, 115,115,115,115,115,115,115,232,232,232,232,232,232,232,232,84, 84,192,135,135,150,150,150,184,145,184,145,145,145,145,145,29, 197,234,197,29,197,240,216,225,185,168,163,189,189,225,225,188, 163,185,185,185,216,188,225,181,181,185,181,234,29,29,51,66, 66,66,45,45,45,45,84,84,221,45,135,135,192,140,140,140, 140,139,232,232,99,196,2,2,2,2,2,2,244,15,15,15, 15,15,22,22,22,22,22,7,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,61,30,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,63,1,1,1,1,1,243, 30,30,30,30,30,30,30,30,30,30,30,208,1,1,1,1, 1,1,22,22,22,22,22,22,22,15,15,15,86,86,86,115, 115,115,115,115,115,138,232,232,232,232,232,232,232,164,84,84, 84,84,135,135,150,150,150,145,193,193,145,145,145,29,29,29, 197,181,181,197,179,185,188,216,168,163,163,233,233,166,166,189, 163,168,168,168,188,189,225,185,240,225,181,197,39,29,51,51, 66,66,66,45,45,45,45,45,135,135,135,135,135,192,140,140, 140,232,232,140,18,2,2,2,2,2,2,82,15,15,15,15, 15,93,22,22,22,22,22,22,82,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,7,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,119,1,1,1,1,1,1,24, 30,30,30,30,30,30,30,30,30,30,30,79,1,1,1,1, 1,58,22,22,22,22,22,22,22,15,15,15,15,15,86,86, 115,115,115,115,138,232,232,232,232,232,232,164,84,84,84,84, 84,84,45,135,150,150,145,193,237,146,146,146,29,29,29,39, 197,181,185,185,173,177,188,189,166,166,166,198,126,117,117,233, 166,163,163,166,233,189,168,225,216,225,181,197,197,29,51,51, 184,66,66,66,66,66,66,150,150,150,135,135,135,135,140,140, 84,232,232,190,2,2,2,2,2,2,196,123,15,15,15,15, 15,15,22,22,22,22,22,22,90,129,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,230,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,203,1,1,1,1,1,1,24, 30,30,30,30,30,30,30,30,30,30,30,30,1,1,1,1, 1,243,22,22,22,22,22,22,22,22,15,15,15,15,15,15, 115,115,115,115,232,232,232,232,232,139,140,140,140,140,140,140, 135,45,45,45,150,150,145,193,146,146,234,234,234,197,197,197, 173,173,240,225,177,177,166,198,117,117,233,126,64,233,233,126, 117,166,166,233,126,189,163,188,188,225,185,173,179,29,29,51, 51,51,66,66,66,150,184,184,150,150,150,135,135,135,140,84, 84,232,75,2,2,2,2,2,2,2,4,15,15,15,15,15, 15,15,93,22,22,22,22,22,22,92,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,92,30,30,30,30, 30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,205,1,1,1,1,1,1,27, 30,30,30,30,30,30,30,22,22,30,30,79,1,1,1,1, 1,88,22,22,22,22,22,22,22,22,15,15,15,15,15,15, 15,14,115,115,115,232,232,232,139,139,140,140,140,140,135,135, 135,135,135,45,66,150,145,145,146,234,234,181,181,181,173,173, 173,177,168,163,163,101,163,126,126,170,198,167,127,126,126,167, 128,49,170,167,167,117,117,233,188,168,177,173,179,179,29,29, 29,51,51,145,145,193,193,145,150,150,150,135,135,135,140,84, 84,135,72,2,2,2,2,2,2,72,115,15,15,15,15,15, 15,15,93,22,22,22,22,22,22,22,160,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,129,83,30,30,30, 30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,43,1,1,1,1,1,254, 203,30,30,30,30,30,119,22,22,22,22,88,1,1,1,1, 107,156,22,22,22,22,22,22,15,15,15,15,15,15,15,15, 15,14,14,115,115,115,232,232,139,140,140,140,140,135,135,135, 135,150,150,150,150,150,184,145,146,234,153,181,185,185,185,185, 185,168,168,166,117,166,71,126,223,126,126,223,131,223,223,206, 38,128,126,158,167,170,198,198,166,163,240,177,78,179,179,29, 29,29,29,146,146,146,237,193,145,150,150,150,135,135,140,84, 84,228,2,2,2,2,2,2,2,50,15,15,15,15,15,15, 15,15,15,22,22,22,22,22,22,22,244,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,122,30,30,30, 30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,106,1,1,1,1,1,1, 76,116,30,30,30,30,119,22,22,22,79,58,1,1,1,1, 57,22,22,93,15,15,15,15,15,15,15,15,15,15,15,15, 15,15,14,14,115,115,138,232,232,232,140,140,192,135,135,135, 150,150,150,150,184,145,145,145,29,234,181,181,185,225,225,163, 168,168,163,166,170,128,117,128,158,206,223,206,252,158,206,242, 64,241,206,229,167,126,167,198,117,44,101,42,78,78,179,179, 197,234,234,234,234,146,146,193,145,150,150,186,135,135,84,84, 47,2,2,2,2,2,2,2,18,14,14,14,15,15,15,15, 15,15,15,15,15,22,22,22,22,22,22,82,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,149,30,30, 30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,114,1,1,1,1,1, 1,175,57,30,30,30,22,22,93,23,58,1,1,1,254,65, 130,130,86,86,86,86,86,86,86,86,86,86,15,15,15,15, 156,14,14,14,14,115,115,232,232,232,164,84,140,135,135,135, 150,150,150,193,193,193,146,29,29,197,153,181,240,225,216,188, 166,166,166,117,170,126,38,128,158,242,206,242,209,229,242,229, 206,206,229,229,223,206,223,128,117,44,101,101,42,177,173,173, 181,185,181,181,234,234,146,193,145,150,150,135,135,45,84,99, 129,2,2,2,2,2,2,2,50,14,14,14,15,15,15,15, 15,15,15,15,15,22,22,22,22,22,22,90,129,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,18,30,30, 30,247,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,65,254,1,1,1, 1,1,1,58,212,114,63,27,58,1,1,1,1,76,172,130, 130,130,86,86,86,86,86,86,86,86,86,86,86,86,86,115, 115,14,115,115,115,115,115,115,232,232,232,84,84,192,135,186, 150,150,145,193,237,146,146,234,234,234,181,181,240,163,188,189, 233,233,170,49,128,167,223,241,206,136,174,174,28,136,252,218, 67,207,209,229,67,242,223,128,49,71,44,101,101,240,168,225, 225,185,185,181,234,234,146,193,145,150,150,45,45,221,84,176, 2,2,2,2,2,2,2,176,115,115,14,14,15,15,15,15, 15,15,15,15,22,22,22,22,22,22,22,22,92,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,235,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,30,79,208,175,1, 1,1,1,1,1,1,1,1,1,1,254,111,23,22,22,130, 130,130,86,86,86,86,86,86,86,86,86,115,115,115,115,115, 115,115,115,115,115,115,232,232,232,232,232,232,84,84,45,135, 150,150,145,193,146,146,234,234,181,181,181,185,240,163,166,233, 198,126,126,38,38,64,67,67,148,255,136,218,204,248,255,255, 174,218,204,174,252,174,223,38,49,117,71,44,44,163,188,163, 216,225,185,181,234,234,146,145,145,150,66,45,45,84,190,2, 2,2,2,2,2,2,2,246,115,115,14,14,156,15,15,15, 15,15,15,15,93,22,22,22,22,22,22,22,22,160,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,196,59, 30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,239, 88,208,212,212,43,243,212,63,65,210,116,22,22,22,22,130, 130,86,86,86,86,86,86,86,86,86,171,115,115,115,115,115, 115,115,232,232,232,232,232,232,232,232,232,164,84,84,84,45, 45,150,150,145,146,234,234,181,181,185,185,225,225,163,166,233, 126,167,223,206,223,37,67,53,207,136,204,54,144,144,16,178, 136,204,204,136,136,207,37,241,128,49,49,117,233,233,189,188, 216,225,185,181,234,234,29,145,150,150,231,45,45,50,2,2, 2,2,2,2,2,2,18,115,115,115,14,14,14,15,15,15, 15,15,15,15,93,22,22,22,22,22,22,22,22,99,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,230, 30,247,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,119,22,22,22,22,22,22,22,22,22,130, 130,86,86,86,86,86,86,86,86,86,171,115,115,115,115,115, 115,232,232,232,232,232,139,232,164,84,84,84,84,84,221,45, 45,45,66,184,145,146,234,181,185,185,225,216,188,166,117,170, 126,223,158,242,242,67,207,53,136,8,224,13,224,187,162,13, 16,187,16,204,136,95,148,64,38,38,38,167,126,198,233,188, 216,225,185,181,234,29,29,145,66,66,231,45,104,129,2,2, 2,2,2,2,2,2,4,115,115,115,14,14,14,15,15,15, 15,15,15,15,93,22,22,22,22,22,22,22,22,22,230,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 235,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,22,22,22,22,22,22,130,130, 130,86,86,86,86,86,86,86,86,86,171,115,115,115,115,115, 115,232,232,232,139,139,164,140,140,140,140,135,135,135,45,45, 45,66,66,66,145,237,29,234,181,225,216,188,189,233,233,198, 126,223,158,229,157,218,53,218,178,28,224,187,94,161,133,182, 182,226,215,215,255,95,67,148,37,206,158,206,167,126,233,189, 163,225,185,173,197,29,29,145,145,150,66,104,129,2,2,2, 2,2,2,2,2,2,50,115,115,115,115,14,14,15,15,15, 15,15,15,15,15,22,22,22,22,22,22,22,22,22,82,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,4,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,86,86,86,86,86,86,86,86,86,171,115,115,115,115,115, 115,232,232,232,139,139,140,140,140,140,135,135,135,150,150,150, 150,150,145,145,145,145,29,197,173,185,225,188,189,233,126,167, 223,206,67,174,136,28,178,28,16,10,121,161,6,201,161,56, 161,226,133,215,96,53,95,207,174,252,242,158,223,126,233,166, 163,168,173,173,197,29,29,145,145,104,77,196,2,2,2,2, 2,2,2,2,2,2,230,140,115,115,115,14,14,156,15,15, 15,15,15,15,15,22,22,22,22,22,22,22,83,154,129,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,230,149,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,93,15,15,86,86,86,86,86,86,115,115,115,115,115,115, 232,232,232,232,139,139,140,140,140,135,135,135,186,150,150,193, 193,193,146,146,146,39,197,197,197,173,177,168,166,233,126,223, 158,242,174,174,136,204,236,162,236,94,133,201,46,250,87,105, 199,105,251,121,21,96,96,28,255,157,229,158,223,198,117,166, 168,185,177,173,197,197,55,68,196,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,196,18,18,25,25,228,235,109,15, 15,15,15,15,15,22,22,246,228,230,18,196,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,196,160,122,61,92,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,22,22,15,15,15,86,86,86,86,86,86,115,115,115,115, 115,232,232,232,232,139,140,140,140,135,135,135,150,150,150,193, 193,237,146,153,153,181,181,185,185,185,168,168,163,117,128,64, 158,229,157,255,28,178,224,133,226,6,46,137,142,194,26,36, 142,199,6,182,215,215,236,13,28,218,242,206,167,128,117,166, 163,168,185,181,173,197,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,244,15, 15,15,15,15,15,22,22,228,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,18,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,22,22,22,93,15,15,15,86,86,86,86,171,115,115,115, 115,115,232,232,232,139,139,140,140,192,135,135,186,150,150,193, 193,146,146,153,153,181,185,225,225,216,188,189,189,170,128,38, 223,67,218,28,13,162,182,191,222,113,87,125,81,120,81,81, 81,125,105,56,6,226,187,144,54,53,67,37,241,128,170,117, 166,168,185,173,173,197,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,244,15, 15,15,15,15,15,22,22,228,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,18,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,119,22,22,22,22,22,22, 22,22,22,22,22,22,15,15,15,15,15,15,86,115,115,115, 115,115,115,232,232,232,232,164,84,140,140,135,135,150,150,150, 193,146,146,234,153,181,185,225,216,188,189,233,126,167,223,206, 67,207,95,8,16,182,226,161,137,245,20,9,194,62,194,120, 194,33,70,199,201,251,182,16,136,53,207,206,223,38,170,117, 166,168,240,173,173,197,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,244,15, 15,15,15,15,15,22,22,228,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,18,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,247,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,119,22,22,22,22,22,22, 22,22,22,22,22,22,15,15,15,15,15,15,15,15,156,14, 115,115,115,115,232,232,232,232,84,84,84,84,135,135,150,150, 150,145,237,146,234,181,181,185,225,188,189,233,126,64,206,131, 252,136,28,204,16,215,94,222,142,20,81,194,81,143,120,238, 9,9,194,26,46,56,10,16,54,8,174,206,223,38,170,117, 163,168,177,173,197,197,19,19,19,19,19,19,19,19,19,47, 47,47,47,47,47,50,50,50,50,50,50,50,50,50,109,15, 15,15,15,15,15,93,22,99,246,246,246,246,154,154,154,154, 154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, 154,154,154,5,5,5,5,5,149,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,247,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,119,22,22,22,22,22,22, 22,22,22,22,22,22,22,15,15,15,15,15,15,15,156,14, 14,115,115,115,232,232,232,232,232,84,84,84,221,45,45,66, 150,184,145,29,29,234,181,181,185,225,166,189,198,126,223,242, 252,136,248,144,187,226,161,201,36,9,120,62,238,143,35,48, 120,62,9,125,137,6,182,13,54,8,207,148,241,38,49,71, 44,101,177,173,197,179,29,237,51,66,66,231,45,45,84,84, 84,84,11,11,11,11,14,14,14,14,14,14,15,15,15,15, 15,15,15,15,15,93,22,22,22,22,22,22,22,22,22,119, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,247,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,119,22,22,22,22,22,22, 22,22,22,22,22,22,22,15,15,15,15,15,15,15,14,14, 14,115,115,115,232,232,232,232,232,164,84,84,221,45,45,231, 66,150,145,145,29,39,197,173,181,185,168,166,117,128,126,223, 67,174,218,28,215,94,161,87,219,120,62,238,35,211,112,35, 48,81,9,125,46,191,10,16,96,53,67,37,241,128,49,166, 44,101,177,173,197,179,29,51,51,66,66,231,45,45,84,84, 84,84,11,11,11,11,14,14,14,14,14,14,15,15,15,15, 15,15,15,15,15,93,22,22,22,22,22,22,22,22,22,119, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,247,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,119,22,22,22,22,22,22, 22,22,22,22,22,22,22,15,15,15,15,15,15,15,14,14, 14,115,115,115,232,232,232,232,232,164,84,84,221,45,45,45, 66,150,145,145,29,39,197,173,173,185,168,163,117,170,38,64, 206,207,53,255,16,10,191,46,125,9,194,48,35,112,112,35, 62,194,9,33,87,161,187,13,28,8,207,148,64,38,49,117, 44,101,177,173,197,197,29,237,51,66,66,231,45,45,84,84, 84,84,11,11,11,11,14,14,14,14,14,14,15,15,15,15, 15,15,15,15,15,93,22,22,22,22,22,22,22,22,22,119, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,247,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,119,22,22,22,22,22,22, 22,22,22,22,22,22,22,15,15,15,15,15,15,15,14,14, 14,115,115,115,115,232,232,232,232,164,84,84,221,45,45,45, 66,150,145,145,29,39,197,173,185,168,163,166,117,128,167,206, 207,53,255,16,162,133,161,87,219,120,48,238,238,211,211,211, 62,81,9,20,199,222,226,182,144,248,136,252,242,206,167,198, 117,166,163,168,185,181,197,29,29,145,184,150,66,45,45,45, 84,84,84,232,232,232,232,115,115,115,115,14,14,14,15,15, 15,15,15,15,15,93,22,22,22,22,22,22,22,22,22,22, 22,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,247,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,22,22,22,22,22,22, 22,22,22,22,22,22,22,15,15,15,15,15,15,15,156,14, 14,115,115,115,232,232,232,232,232,84,84,84,45,45,45,66, 150,184,145,29,29,234,181,181,240,163,166,189,198,126,223,158, 229,218,255,204,224,226,222,250,26,81,9,81,62,35,238,48, 48,81,9,36,105,191,187,236,16,255,218,174,158,206,167,198, 233,189,188,163,225,185,181,234,234,146,193,145,150,150,135,135, 45,84,84,84,232,232,232,232,115,115,115,115,115,14,156,15, 15,15,15,15,15,15,15,22,22,22,22,22,22,22,22,22, 22,22,119,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,119,22,22,22,22,22,22, 22,22,22,22,22,22,15,15,15,15,15,15,15,15,14,14, 115,115,115,115,232,232,232,232,84,84,84,84,135,135,186,150, 150,145,146,146,234,234,181,185,225,163,188,189,233,126,223,158, 229,157,248,144,187,226,251,105,137,199,20,81,62,120,62,194, 81,194,20,113,105,133,215,21,255,218,53,207,206,223,126,198, 189,166,163,225,185,181,181,234,39,146,237,193,145,150,150,186, 135,135,140,140,140,164,232,232,232,232,115,115,115,115,115,86, 86,86,15,15,15,15,15,22,22,22,22,22,22,22,22,22, 22,22,22,119,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,119,22,22,22,22,22,22, 22,22,22,22,22,22,15,15,15,15,15,15,15,115,115,115, 115,115,115,232,232,232,232,232,84,84,140,135,135,186,150,150, 145,193,146,146,234,234,181,185,225,163,188,189,233,126,127,131, 157,209,248,204,144,236,182,133,6,137,33,219,9,194,194,9, 9,20,245,113,6,10,215,178,8,207,148,37,223,167,198,233, 117,163,163,225,185,181,234,234,146,146,193,145,150,150,150,135, 135,135,140,140,140,164,232,232,232,232,138,115,115,115,115,115, 171,86,86,86,86,86,15,15,93,22,22,22,22,22,22,22, 22,22,22,119,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,119,22,22,22,22,22,22, 22,22,22,22,93,15,15,15,15,86,86,86,86,115,115,115, 115,115,138,232,232,232,232,84,84,140,140,135,135,150,150,150, 145,145,237,146,234,234,181,185,225,216,188,233,126,64,127,242, 229,252,157,136,255,178,13,121,191,201,137,26,36,219,81,125, 245,87,137,201,226,187,16,136,8,174,67,241,38,49,117,117, 166,163,225,185,181,181,234,39,29,145,145,150,150,150,186,135, 135,192,84,84,84,164,232,232,232,232,115,115,115,115,115,115, 171,86,86,86,86,86,86,15,15,15,15,22,22,22,22,22, 22,22,22,22,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,22,22,22,93,15,86,86,86,86,86,86,171,115,115,115, 115,115,138,232,232,232,232,84,84,140,140,135,135,135,150,150, 184,145,193,146,234,181,181,185,225,188,189,233,198,126,64,223, 206,158,207,174,8,136,28,236,226,94,113,46,87,36,36,113, 46,46,6,133,226,162,13,255,207,67,67,37,38,49,166,44, 101,168,185,181,181,234,197,29,29,145,145,150,150,186,135,135, 135,140,84,84,232,232,232,232,232,232,115,115,115,115,115,115, 86,86,86,86,86,86,86,15,15,15,15,22,22,22,22,22, 22,22,22,22,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,22,15,15,15,15,86,86,86,86,86,86,171,115,115,115, 115,115,138,232,232,232,232,164,84,84,140,135,135,135,150,150, 145,193,146,39,153,181,185,225,216,216,188,189,233,233,198,126, 167,223,206,67,207,53,28,224,13,133,161,94,201,105,222,161, 94,161,182,182,236,162,178,255,252,67,241,38,126,128,117,163, 101,177,173,197,197,197,29,29,145,145,184,150,150,135,135,135, 84,84,84,84,232,232,232,232,232,232,115,115,115,115,115,115, 86,86,86,86,86,86,15,15,15,15,15,22,22,22,22,22, 22,22,22,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,93,15,15,15,15,86,86,86,86,86,86,171,115,115,115, 115,115,115,232,232,232,232,164,84,140,140,135,135,135,150,150, 193,193,146,153,153,181,185,185,225,225,216,188,188,117,170,128, 38,241,64,37,67,218,248,28,16,133,182,215,161,94,6,133, 121,182,236,13,178,178,248,218,174,242,37,128,49,117,117,166, 168,177,173,197,29,29,51,145,145,150,150,150,150,45,45,45, 84,84,84,164,232,232,232,232,232,115,115,115,115,115,115,86, 86,86,86,86,86,86,15,15,15,15,93,22,22,22,22,22, 22,22,22,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,22,15,15,15,15,86,86,86,86,86,86,86,115,115,115, 115,115,115,232,232,232,232,139,140,140,192,135,135,150,150,193, 193,146,146,146,153,153,181,181,185,185,225,225,163,163,166,117, 170,128,38,37,207,157,218,53,144,236,178,16,226,236,182,224, 13,21,236,255,54,8,218,136,242,206,206,167,170,166,44,168, 168,240,181,197,29,29,51,184,66,66,66,45,45,45,45,84, 84,84,84,232,232,232,232,232,232,115,115,115,115,115,115,86, 86,86,86,86,86,86,15,93,22,22,22,22,22,22,22,22, 22,22,22,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,22,22,22,22,22,22, 22,22,15,15,15,15,15,86,86,86,86,86,86,115,115,115, 115,115,115,232,232,232,139,140,140,140,135,135,186,150,150,184, 193,193,146,146,146,234,234,181,181,181,185,185,168,163,163,166, 117,49,38,223,229,174,148,136,204,28,8,178,224,16,215,13, 28,8,178,136,53,53,207,229,229,206,167,126,198,117,163,177, 177,173,181,181,197,29,145,184,66,45,45,45,45,84,84,84, 84,84,164,232,232,232,232,138,115,115,115,115,115,115,115,86, 86,86,15,15,15,15,15,93,22,22,22,22,22,22,22,22, 22,22,22,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,22,22,22,22,22,22, 22,22,15,15,15,15,15,86,86,86,86,86,86,171,115,115, 115,115,232,232,232,139,140,140,140,140,135,135,135,150,150,150, 150,193,193,237,146,146,146,234,234,153,181,185,185,168,101,44, 166,170,126,206,158,241,67,136,209,174,95,204,248,255,178,28, 136,95,174,136,67,207,67,37,206,206,126,233,233,117,163,168, 173,197,197,197,29,29,29,145,150,66,45,45,84,84,84,84, 84,232,232,232,232,232,232,115,115,115,115,115,115,115,86,86, 15,15,15,15,15,15,15,93,22,22,22,22,22,22,22,22, 22,22,22,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,22,22,22,22,22,22, 22,22,93,15,15,15,15,86,86,86,86,86,115,115,115,115, 115,115,232,139,139,139,140,140,140,140,135,135,135,135,150,150, 150,150,145,145,145,145,29,29,29,197,197,173,173,177,177,101, 166,170,126,64,128,38,229,252,174,148,67,248,218,218,136,218, 53,207,148,252,67,223,206,167,126,167,167,233,117,166,163,225, 185,197,29,29,29,145,145,145,184,66,45,45,84,84,84,164, 11,232,232,232,232,138,115,115,115,115,115,115,115,15,15,15, 15,15,15,15,15,15,15,22,22,22,22,22,22,22,22,22, 22,22,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,22,22,22,22,22,22, 22,22,22,15,15,15,86,86,86,86,86,171,115,115,115,115, 115,232,232,139,139,139,140,140,140,140,140,135,135,135,135,135, 150,150,150,150,145,145,145,29,29,197,197,197,197,173,177,168, 166,233,198,170,49,223,242,242,37,64,206,209,207,174,252,174, 207,206,241,67,242,241,167,126,128,170,198,233,188,163,225,225, 185,181,197,29,51,51,66,150,150,150,186,45,45,84,84,164, 11,11,11,138,14,115,115,115,115,115,14,14,156,15,15,15, 15,15,15,15,15,15,93,22,22,22,22,22,22,22,22,22, 22,22,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,119,22,22,22,22,22, 22,22,22,15,86,86,86,86,86,86,86,171,115,115,115,115, 115,232,139,139,139,139,139,140,140,140,140,140,192,135,135,135, 135,135,150,150,150,150,145,145,237,29,29,39,197,173,185,163, 188,189,166,71,170,223,127,223,38,38,206,157,206,67,242,158, 206,223,38,38,206,126,170,198,170,71,117,189,189,163,225,185, 181,181,234,29,145,184,66,66,45,45,45,45,45,84,84,84, 232,232,11,14,14,14,14,14,14,14,14,14,15,15,15,15, 15,15,15,15,15,15,93,22,22,22,22,22,22,22,22,22, 22,22,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,22,22,22,22,22, 22,22,130,86,86,86,86,86,86,86,86,115,115,115,115,115, 115,232,232,232,139,139,139,139,164,140,140,140,140,140,192,135, 45,45,45,66,66,150,150,145,51,51,237,29,197,173,185,163, 188,163,101,163,198,167,167,128,49,128,206,131,167,223,206,206, 223,167,128,49,167,126,117,117,117,166,163,163,163,216,225,181, 181,234,234,146,29,145,66,45,45,45,45,45,84,84,84,84, 232,232,232,138,14,14,14,14,15,156,15,15,15,15,15,15, 15,15,15,15,15,22,22,22,22,22,22,22,22,22,22,22, 22,22,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,22,22,22,22,22, 22,130,130,86,86,86,86,86,86,86,115,115,115,115,115,115, 115,115,115,232,232,232,232,232,139,232,164,84,84,84,84,84, 45,45,45,45,231,66,66,66,184,51,51,29,197,181,185,225, 168,177,240,166,198,198,233,117,117,49,127,127,128,167,64,167, 126,128,49,71,170,198,117,163,163,163,168,168,225,225,225,181, 234,197,146,146,146,145,150,231,45,221,84,84,84,84,84,84, 164,232,232,232,115,115,14,14,15,15,15,15,15,15,15,15, 15,15,15,15,22,22,22,22,22,22,22,22,22,22,22,22, 22,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,130,130,86,86,86,86,86,86,86,86,115,115,115,115,115, 115,115,115,138,232,232,232,232,232,232,232,232,164,84,84,84, 84,45,45,45,45,45,231,66,66,51,145,29,234,181,185,185, 173,173,168,188,189,189,166,44,44,117,223,126,170,198,126,198, 198,170,117,44,44,233,189,168,168,168,168,185,181,185,185,185, 153,39,29,237,145,145,184,150,45,45,84,84,84,84,164,232, 232,232,232,232,115,115,115,14,14,15,15,15,15,15,15,15, 15,15,93,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,30,30,30,30, 30,30,30,30,30,30,30,30,22,22,22,22,22,22,22,22, 130,130,130,86,86,86,86,86,86,86,86,86,86,115,115,115, 115,115,115,115,115,115,138,232,232,232,232,232,232,232,84,84, 84,84,221,45,45,45,45,231,66,145,237,29,234,181,181,197, 179,173,225,188,188,163,168,101,101,189,126,233,166,233,233,233, 117,117,166,44,101,163,189,168,177,185,185,181,173,197,153,181, 153,234,146,145,145,184,150,150,135,45,84,84,84,11,232,232, 232,232,232,232,138,115,115,115,14,14,15,15,15,15,15,15, 15,15,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 119,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,30,30,30,30, 30,30,30,30,30,30,30,30,22,22,22,22,22,22,130,130, 130,130,130,130,86,86,86,86,86,86,86,86,86,171,115,115, 115,115,115,115,115,115,115,232,232,232,232,232,232,232,84,84, 84,84,84,84,84,45,45,231,150,145,145,146,234,234,29,29, 197,185,225,216,216,168,177,177,101,188,198,166,163,166,189,166, 166,163,163,101,177,240,216,225,173,173,181,181,234,197,29,234, 234,234,146,145,150,150,150,150,186,135,45,84,84,232,11,11, 232,232,232,115,115,115,115,115,14,14,15,15,15,15,15,15, 15,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,30,30,30, 30,30,30,30,30,30,30,30,22,22,22,22,22,130,130,130, 130,130,130,130,93,86,86,86,86,86,86,86,86,86,115,115, 171,115,115,115,115,115,115,115,115,232,232,232,232,232,232,164, 84,84,84,84,84,45,45,45,150,145,193,146,146,29,51,29, 234,185,240,225,185,181,173,173,185,188,189,163,168,163,163,163, 163,225,168,185,173,173,225,225,181,197,197,234,234,29,29,29, 146,146,146,193,150,150,186,135,135,135,135,84,84,232,232,11, 14,14,14,115,115,115,115,115,115,14,15,15,15,15,15,15, 15,22,22,22,22,22,22,22,22,22,22,22,22,30,22,119, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,30,30,30, 30,30,30,30,30,30,30,30,22,22,22,22,22,130,130,130, 130,130,130,130,130,86,86,86,86,86,86,86,86,86,86,86, 86,86,115,115,115,115,115,115,115,115,115,232,232,232,232,232, 232,232,84,84,84,221,45,66,150,145,237,146,145,51,51,29, 153,185,185,185,181,197,197,197,185,188,188,185,185,225,225,225, 225,225,185,173,197,179,173,240,181,197,29,29,39,29,145,145, 145,193,193,193,150,150,135,135,135,135,192,140,84,84,232,232, 138,14,14,14,14,115,14,14,14,156,15,15,15,15,15,15, 15,22,22,22,22,22,22,22,22,22,22,22,22,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,22,22,130,130,86,86,86,86,86,86,86,86,86,86,86, 86,86,86,156,14,14,115,115,115,115,115,232,232,232,232,232, 11,11,164,84,84,45,45,186,150,145,193,184,66,66,145,146, 153,181,181,181,197,29,197,197,185,216,225,181,181,185,240,185, 185,185,181,173,197,29,197,181,181,234,29,145,29,29,145,145, 150,150,145,193,184,150,135,135,221,84,140,84,84,84,232,232, 232,115,14,14,14,14,156,14,15,15,15,15,15,15,15,15, 15,22,22,22,22,22,22,22,22,22,22,119,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,22,22,130,130,130,86,86,15,15,15,86,86,86,86,15, 15,15,15,15,156,14,115,115,115,115,115,115,138,138,138,11, 11,11,232,84,84,45,135,186,150,150,150,66,45,66,145,146, 153,153,234,234,29,29,29,39,181,225,185,197,181,181,185,181, 181,181,153,197,29,29,29,234,181,234,145,51,145,145,145,150, 150,66,150,150,150,150,135,135,84,84,84,84,84,232,232,232, 232,115,115,14,14,15,15,15,15,15,15,15,15,15,15,15, 15,15,22,22,22,22,22,22,22,22,22,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,22,22,22,22,22,93,15,15,15,15,15,15,15,15,15, 15,15,15,15,15,14,14,14,115,115,115,115,14,14,14,11, 11,232,164,84,84,221,135,186,150,186,45,45,45,150,193,146, 146,234,146,29,51,51,51,29,181,225,181,197,234,181,181,181, 181,234,197,197,29,51,51,29,234,234,145,66,66,150,145,150, 66,45,45,135,150,150,186,135,140,84,84,84,232,232,232,232, 232,138,115,115,14,156,15,15,15,15,15,15,15,15,15,15, 15,15,22,22,22,22,22,22,22,22,22,22,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,30, 30,30,30,30,30,30,30,30,30,30,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,15,15,15,15,15,15, 15,15,15,15,15,15,14,14,14,115,14,14,14,14,14,138, 232,232,232,84,84,135,135,186,135,45,45,45,45,150,193,146, 146,146,145,145,184,51,51,29,181,185,234,29,39,234,234,234, 234,234,29,29,237,51,184,51,29,146,145,150,66,150,150,150, 66,45,45,45,135,135,135,135,192,84,84,232,232,232,232,232, 232,232,115,115,115,14,15,15,15,15,15,15,15,15,15,15, 22,22,22,22,22,22,22,22,22,22,22,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30, 30,30,30,30,30,30,30,30,30,30,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,93,22,15,15,15,15, 15,15,15,15,15,15,156,14,156,14,14,14,14,14,14,232, 232,232,232,84,84,135,135,135,45,84,84,45,135,184,193,193, 193,193,184,66,66,66,51,146,181,181,146,145,29,146,234,146, 146,29,29,29,145,184,66,66,145,146,193,150,66,45,45,186, 135,45,45,84,84,135,135,135,135,140,84,232,232,232,232,232, 232,115,115,115,115,14,15,15,15,15,15,15,15,15,93,22, 22,22,22,22,22,22,22,22,22,22,22,22,30,30,30,30, 30,30,30,30,30,30,30,30,30,0,0,30,30,30,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30, 30,30,30,30,30,30,30,30,30,30,30,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,15,15,15, 15,15,15,15,15,15,15,15,15,156,15,14,14,14,115,232, 232,232,232,84,140,192,140,84,84,84,84,45,150,150,193,193, 193,150,150,66,66,66,150,146,153,153,29,145,145,146,146,146, 146,29,145,145,145,66,66,45,66,145,193,150,45,45,45,45, 135,45,45,84,84,84,140,140,140,140,140,232,232,232,232,232, 115,115,115,115,115,115,15,15,15,15,15,15,15,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,30,30,30, 30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,119, 22,22,22,22,22,22,22,22,22,22,22,22,22,15,15,15, 15,15,15,15,15,15,15,15,15,15,15,14,14,115,115,115, 232,232,232,140,140,140,84,84,164,84,84,135,150,150,150,150, 150,150,45,45,45,231,150,146,153,146,145,150,145,193,193,193, 145,145,145,184,150,150,231,45,45,150,193,150,135,45,221,45, 45,45,84,84,84,84,84,84,140,140,140,139,232,232,232,115, 115,115,115,115,115,115,115,15,15,15,15,15,15,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,30,30,30, 30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,15,15, 15,15,15,15,15,15,15,15,15,15,15,14,115,115,115,138, 232,232,232,140,140,232,232,11,11,84,84,135,150,150,150,150, 135,45,45,45,45,45,150,237,146,193,150,150,150,145,145,145, 145,184,184,150,66,66,45,45,45,45,150,150,135,45,84,84, 84,84,84,84,84,232,232,232,232,140,164,139,232,232,232,115, 115,115,115,115,115,115,171,86,15,15,15,15,15,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,30,30,30,30, 30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 93,15,15,15,15,15,15,15,15,15,15,14,115,115,115,232, 232,232,139,232,232,232,11,11,232,84,140,135,135,186,150,135, 45,221,84,84,45,45,150,193,146,145,66,66,150,150,150,150, 150,150,150,150,66,45,45,45,84,45,135,150,135,45,84,84, 84,84,84,84,84,232,232,232,232,232,232,139,232,232,138,115, 115,115,115,115,115,86,86,86,86,86,15,15,15,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,30,30,30,30, 30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 93,15,15,15,15,15,15,15,15,15,14,14,115,115,115,115, 232,232,232,232,232,232,11,11,232,84,192,135,135,135,135,135, 84,84,84,84,84,45,150,193,193,150,45,45,150,150,150,150, 150,150,186,135,45,45,45,84,84,84,45,135,135,135,84,84, 84,84,84,84,232,232,232,232,232,232,232,232,232,232,232,115, 115,115,115,115,86,86,86,86,86,86,86,15,15,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,15,15,15,15,15,15,15,15,14,115,115,115,138, 232,232,232,138,115,14,14,232,232,140,140,135,135,135,135,84, 84,84,84,84,84,45,150,193,150,186,45,45,135,150,150,150, 150,135,135,135,45,45,84,84,84,84,84,135,135,135,84,164, 232,232,232,232,232,232,232,232,115,138,232,232,232,232,232,115, 115,115,115,15,15,86,86,86,86,86,86,86,15,22,22,22, 22,22,22,22,22,22,22,22,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,15,15,15,15,15,15,15,15,156,115,115,115,232, 232,115,115,115,14,14,138,232,232,140,140,140,140,140,84,84, 84,84,84,84,84,45,150,150,150,135,221,45,135,135,135,135, 135,135,135,45,45,84,84,84,84,11,84,84,135,135,84,164, 232,232,232,232,232,232,232,115,115,115,115,115,115,138,115,115, 115,115,115,86,15,15,15,15,86,86,86,86,15,15,22,22, 22,22,22,22,22,22,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,15,15,15,15,15,15,15,115,115,115,115,138, 115,115,115,14,14,14,115,232,164,140,140,140,140,140,84,232, 232,232,232,232,84,192,150,150,135,45,84,84,135,135,135,135, 135,135,135,221,84,84,84,84,164,11,232,84,140,140,140,232, 232,232,232,232,232,232,232,115,115,115,115,115,115,115,115,115, 115,115,115,86,86,15,15,15,15,15,15,15,15,15,22,22, 22,22,22,22,22,22,22,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,15,15,15,15,15,15,86,115,115,115,115,115, 115,14,14,14,14,115,138,232,139,164,140,140,140,164,232,232, 11,11,11,232,84,140,135,150,135,84,84,84,192,135,135,135, 135,135,84,84,84,84,84,164,232,11,11,232,84,140,140,232, 232,138,138,232,232,232,232,115,115,115,14,115,115,115,115,115, 115,115,115,86,86,86,15,15,15,15,15,15,93,22,22,22, 22,22,22,22,22,22,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,93,15,15,15,15,86,86,171,115,115,115,115, 14,156,15,14,115,115,232,139,139,139,139,164,232,232,232,232, 11,11,11,232,84,140,135,135,140,84,84,84,84,140,140,140, 140,140,84,84,84,84,232,232,232,11,11,232,232,84,140,232, 232,232,14,115,115,115,115,115,115,115,115,14,14,115,115,115, 115,115,115,115,86,86,86,15,15,15,15,93,22,22,22,22, 22,22,22,22,22,22,22,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,22,30,30,22,22,22,22,22,22,22,22, 22,22,22,22,22,15,15,15,15,86,86,115,115,115,115,15, 15,15,15,14,115,115,232,139,139,139,232,232,232,232,232,14, 14,138,11,232,84,140,135,135,140,164,232,84,84,84,84,84, 84,84,84,84,84,232,232,232,232,11,138,138,232,232,140,139, 232,232,115,115,115,115,115,115,115,115,14,14,15,15,15,86, 171,115,115,86,86,86,86,86,15,15,93,22,22,22,22,22, 22,22,22,22,22,22,22,22,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,22,22,22,22,22,22,22,22, 22,22,22,22,22,15,15,15,86,86,86,115,86,86,15,15, 15,15,15,14,115,115,232,232,232,232,232,232,232,115,115,14, 14,14,14,232,164,140,135,140,140,232,232,232,84,84,84,84, 84,164,232,232,232,232,232,232,232,14,14,14,138,232,232,139, 232,115,115,14,115,115,115,115,115,115,14,15,15,15,15,15, 86,86,86,86,86,86,86,86,15,93,22,22,22,22,22,22, 22,22,22,22,22,22,22,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,119,22,22,22,22,22, 22,22,22,22,22,15,15,86,86,86,86,86,86,15,15,15, 15,15,15,14,115,115,232,232,232,232,232,232,115,115,14,14, 14,14,115,232,232,140,140,140,232,232,232,232,232,84,84,232, 232,232,232,232,232,232,232,232,232,14,14,14,14,138,232,139, 232,138,115,115,14,14,14,14,115,115,15,15,15,15,15,15, 15,86,86,86,86,86,86,15,15,93,22,22,22,22,22,22, 22,22,22,22,22,22,30,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,30,30,30,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,119,22,22,22,22, 22,22,22,22,22,15,15,86,86,86,86,86,15,15,15,15, 15,15,15,115,115,115,115,115,232,232,115,115,115,115,14,14, 14,14,115,232,139,140,140,164,232,232,232,232,232,232,232,232, 232,232,232,232,232,232,232,232,115,115,14,14,14,115,115,232, 232,115,115,14,156,15,14,14,14,115,15,15,15,15,15,15, 15,15,86,86,86,86,86,86,15,15,22,22,22,22,22,22, 22,22,22,22,22,22,119,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,22,22,22,22,22, 22,22,22,22,22,93,15,86,86,86,86,15,15,15,15,15, 15,15,86,115,115,115,115,115,115,115,115,115,115,14,14,14, 14,14,115,232,139,140,140,232,232,232,232,232,232,232,232,232, 232,232,232,232,232,232,138,115,115,115,14,14,14,115,115,115, 232,138,115,14,14,15,15,15,15,15,86,15,15,15,15,15, 15,15,15,86,86,86,86,86,86,15,93,22,22,22,22,22, 22,22,22,22,22,119,30,30,30,30,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,22,22,22,22,22, 22,22,22,22,22,15,15,86,86,86,15,15,15,15,15,15, 15,15,86,115,115,115,115,115,115,115,115,115,14,14,14,14, 14,14,115,232,139,140,139,232,232,115,115,232,232,232,232,232, 232,232,232,232,232,115,115,115,115,115,14,14,14,14,115,115, 115,115,115,115,156,15,15,15,15,15,15,15,15,15,15,15, 15,15,15,15,15,86,86,86,86,86,22,22,22,22,22,22, 22,22,22,22,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,22,22,22,22, 22,22,22,22,15,15,86,86,15,15,15,22,22,22,15,15, 15,86,115,115,115,115,115,115,115,115,115,14,15,15,156,14, 14,14,115,232,139,139,139,232,115,115,115,115,232,232,232,232, 232,232,232,232,115,115,115,115,115,115,14,15,15,15,14,115, 115,115,115,115,15,15,15,15,15,15,15,15,15,15,15,15, 15,22,22,15,93,15,15,86,86,130,22,22,22,22,22,22, 22,22,22,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,22,22,22,22, 22,22,22,22,22,86,86,15,93,22,22,22,22,22,15,15, 15,86,115,115,115,115,115,115,115,115,15,15,15,15,15,15, 15,14,115,138,139,139,232,115,115,115,115,115,115,138,138,115, 115,115,115,115,115,115,115,115,115,14,156,15,15,15,15,14, 115,115,115,115,15,15,15,15,15,15,15,15,15,15,15,15, 15,22,22,22,22,22,15,15,130,130,130,22,22,22,22,22, 22,22,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,22,22,22,22,22, 22,22,22,22,22,130,15,22,22,22,22,22,22,22,93,15, 86,86,86,171,115,115,115,115,171,86,15,15,15,15,15,15, 15,14,115,115,139,139,138,115,115,115,115,115,115,115,115,115, 115,115,115,115,115,115,115,115,14,14,15,15,15,15,15,15, 115,115,115,115,86,15,15,15,15,15,15,15,15,15,15,15, 22,22,22,22,22,22,22,22,22,130,130,22,22,22,22,22, 22,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,22,22,22,22, 22,22,22,22,130,22,22,22,22,22,22,22,22,22,15,15, 86,86,86,86,86,171,115,86,86,15,15,15,15,15,15,15, 15,15,115,115,139,139,115,115,14,14,115,115,115,115,115,115, 115,115,115,115,115,115,14,14,14,14,15,15,15,15,15,15, 15,171,115,115,86,15,15,15,15,15,15,15,15,15,15,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,30,0,0,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,15,86, 86,86,86,86,86,86,86,86,15,15,15,15,15,15,15,15, 15,86,115,115,139,115,115,115,14,14,14,115,115,115,115,115, 115,115,115,115,115,115,156,156,15,15,15,15,15,15,15,15, 15,86,115,115,86,86,15,15,15,15,93,15,15,15,15,93, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 119,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,15,86, 86,86,86,86,86,86,86,86,15,15,15,15,15,15,15,15, 15,86,115,115,139,115,115,115,15,15,15,115,115,115,115,115, 115,115,115,115,115,115,15,15,15,15,15,15,15,15,15,15, 15,15,86,171,86,86,15,15,93,22,22,22,22,22,93,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,119,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,15,86, 86,86,86,86,86,86,86,15,15,15,15,15,15,15,15,15, 15,86,115,115,115,115,115,86,15,15,15,115,115,115,115,115, 115,115,115,115,86,86,15,15,15,15,15,15,15,15,15,15, 15,15,86,86,86,86,15,15,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,15,86,86, 86,86,86,86,86,86,86,15,15,15,15,15,15,15,15,15, 15,86,115,115,115,115,86,15,15,15,15,86,86,171,171,171, 86,86,86,86,86,86,15,15,15,15,15,15,15,15,15,22, 15,15,15,86,86,86,86,15,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,130,86,86, 86,86,86,86,86,15,15,15,22,22,22,22,15,15,15,15, 15,86,115,115,115,115,86,15,15,15,15,86,86,86,86,86, 86,86,86,86,86,15,15,15,15,15,15,15,15,15,15,22, 15,15,15,86,86,86,15,15,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,30,119,30,22,22, 22,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,22,22, 30,30,22,22,30,30,30,119,22,22,22,22,22,130,93,86, 86,86,86,86,86,15,93,22,22,22,22,22,22,22,15,15, 86,86,115,115,115,86,86,15,15,15,15,86,86,86,86,86, 86,86,86,86,86,15,15,15,15,15,15,15,15,15,22,22, 22,22,15,15,86,86,86,15,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,30,30,30,30,30,22, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,22,30, 30,30,30,30,30,30,30,30,22,22,22,22,130,130,130,130, 130,86,86,86,15,22,22,22,22,22,22,22,22,22,22,15, 86,86,171,115,115,86,86,15,15,15,15,86,86,86,86,86, 86,86,86,86,15,15,15,15,15,15,15,93,93,22,22,22, 22,22,22,93,15,86,86,15,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,22,22,22,22,22,130,130,130, 130,130,130,93,22,22,22,22,22,22,22,22,22,22,22,15, 86,86,86,171,86,86,86,15,15,15,15,15,86,86,86,86, 86,86,86,86,15,15,15,15,15,15,15,22,22,22,22,22, 22,22,22,22,22,86,86,86,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,22,22,22,22,22,22,22,22,130, 130,130,130,22,22,22,22,22,22,22,22,22,22,22,22,15, 86,86,86,86,86,86,15,15,15,15,15,15,86,86,86,86, 86,86,86,15,15,15,15,15,15,22,22,22,22,22,22,22, 22,22,22,22,22,15,86,130,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,22,22,22,22,22,22,22,22, 22,130,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 86,86,86,86,86,86,15,22,22,15,15,15,86,86,86,86, 86,86,15,15,15,15,15,15,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,130,130,22,22,22,22,22,22,22,22, 22,22,22,22,22,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,119,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,15, 86,86,86,86,86,15,93,22,22,22,93,15,15,15,15,15, 15,15,15,15,15,15,93,93,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,130,130,22,22,22,22,22,22,30, 22,22,22,22,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,15, 86,86,86,86,86,15,22,22,22,22,22,93,15,15,15,15, 93,93,93,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,30,30, 30,22,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 86,86,86,86,86,15,22,22,22,22,22,22,15,15,15,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 130,86,86,86,86,22,22,22,22,22,22,22,15,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,22,22,22,22,22,22,22,22, 22,22,22,22,22,30,22,22,22,22,22,22,22,22,22,130, 86,86,86,130,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,119,119,22,22,22,22,22,22,22,22,22,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,22,22,22,22,22,22,119, 119,30,22,22,30,30,30,30,30,22,22,22,22,22,22,22, 130,86,86,130,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,119,30,30,30,30,22,22,22,22,22,119,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,30,30,30,0,0,30,30, 30,30,30,30,30,30,30,30,30,30,30,22,22,22,22,30, 30,30,30,30,30,30,30,30,30,30,30,30,22,22,22,22, 130,130,130,130,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,30,30,30,30,30,22,22,119,22,22,22,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,30,0,0,0,0,0, 30,30,30,30,30,30,30,30,30,30,30,30,22,22,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,22,22,22,130, 130,130,130,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,30, 30,30,30,30,30,30,30,30,30,30,22,22,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,22,22,22,22,130, 130,130,130,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,30, 30,30,30,30,30,30,30,30,30,30,22,22,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,22,22,22,130, 130,130,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,30, 30,30,30,30,30,30,30,30,30,30,30,22,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,119,22,22, 130,130,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,119,119,119,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,22,22,130, 130,22,22,22,22,119,119,119,22,22,22,22,22,22,22,22, 22,22,22,22,22,22,22,22,22,22,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,22,22,130, 130,22,22,30,30,30,30,30,30,119,22,22,22,22,22,22, 22,22,22,22,22,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,22,22,130, 22,22,22,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,0,30,30,30,30,30,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,119,22,130, 22,22,22,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,0,30,30,30,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,22, 22,119,119,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,22, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,30,30,30,30,30,30,30, 0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30, 0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,0,0,30,30,30,30,30,30, 30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,30,30,0, 0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,0,0,0,0,0,30,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,0,0,0,0,0,0,30,30,30,30,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,0,0,0,0,0,0,0,30,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,247,30,30,30,30,30,30,30,30,30, 30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; glbsp-2.24-source/gui/book.cc0000644000175000017500000002222510650405205015351 0ustar aaptedaapted//------------------------------------------------------------------------ // BOOK : Unix/FLTK Manual Code //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" Guix_Book *guix_book_win; static void book_quit_CB(Fl_Widget *w, void *data) { if (guix_book_win) guix_book_win->want_quit = TRUE; } static void book_contents_CB(Fl_Widget *w, void *data) { if (guix_book_win) guix_book_win->want_page = 0; } static void book_prev_CB(Fl_Widget *w, void *data) { if (guix_book_win) guix_book_win->want_page = guix_book_win->cur_page - 1; } static void book_next_CB(Fl_Widget *w, void *data) { if (guix_book_win) guix_book_win->want_page = guix_book_win->cur_page + 1; } static void book_selector_CB(Fl_Widget *w, void *data) { if (guix_book_win) guix_book_win->FollowLink(guix_book_win->browser->value() - 1); } //------------------------------------------------------------------------ // // Book Constructor // Guix_Book::Guix_Book() : Fl_Window(guix_prefs.manual_w, guix_prefs.manual_h, "glBSP Manual") { // cancel the automatic 'begin' in Fl_Group constructor end(); size_range(MANUAL_WINDOW_MIN_W, MANUAL_WINDOW_MIN_H); position(guix_prefs.manual_x, guix_prefs.manual_y); color(MAIN_BG_COLOR, MAIN_BG_COLOR); // allow manual closing of window callback((Fl_Callback *) book_quit_CB); want_quit = FALSE; want_page = BOOK_NO_PAGE; want_reformat = FALSE; cur_page = 0; // create buttons in top row group = new Fl_Group(0, h() - 34, w(), 34); add(group); int CX = 10; int CY = h() - 30; contents = new Fl_Button(CX, CY, 96, 26, "&Contents"); contents->box(FL_ROUND_UP_BOX); contents->callback((Fl_Callback *) book_contents_CB); group->add(contents); CX += 126; prev = new Fl_Button(CX, CY, 96, 26, "<< &Prev"); prev->box(FL_ROUND_UP_BOX); prev->callback((Fl_Callback *) book_prev_CB); group->add(prev); CX += 106; next = new Fl_Button(CX, CY, 96, 26, "&Next >>"); next->box(FL_ROUND_UP_BOX); next->callback((Fl_Callback *) book_next_CB); group->add(next); CX += 106; quit = new Fl_Button(w() - 96 - 24, CY, 96, 26, "Close"); quit->box(FL_ROUND_UP_BOX); quit->callback((Fl_Callback *) book_quit_CB); group->add(quit); Fl_Box *invis_2 = new Fl_Box(CX, 0, w() - 96 - 10 - CX, 20); add(invis_2); group->resizable(invis_2); // create the browser browser = new Fl_Hold_Browser(0, 0, w(), h() - 34); browser->callback((Fl_Callback *) book_selector_CB); add(browser); resizable(browser); // show the window set_modal(); show(); // read initial pos (same logic as in Guix_MainWin) WindowSmallDelay(); init_x = x(); init_y = y(); init_w = w(); init_h = h(); } // // Book Destructor // Guix_Book::~Guix_Book() { // update preferences if user moved the window if (x() != init_x || y() != init_y) { guix_prefs.manual_x = x(); guix_prefs.manual_y = y(); } if (w() != init_w || h() != init_h) { guix_prefs.manual_w = w(); guix_prefs.manual_h = h(); } guix_prefs.manual_page = cur_page; } void Guix_Book::resize(int X, int Y, int W, int H) { if (W != w() || H != h()) want_reformat = TRUE; Fl_Window::resize(X, Y, W, H); } int Guix_Book::PageCount() { // we don't need anything super efficient int count; for (count=0; book_pages[count].text; count++) { /* nothing */ } return count; } void Guix_Book::LoadPage(int new_num) { if (new_num < 0 || new_num >= PageCount()) return; cur_page = new_num; want_page = BOOK_NO_PAGE; want_reformat = FALSE; if (cur_page == 0) prev->deactivate(); else prev->activate(); if (cur_page == PageCount() - 1) next->deactivate(); else next->activate(); // -- create browser text -- browser->clear(); int i; const char ** lines = book_pages[cur_page].text; ParaStart(); for (i=0; lines[i]; i++) { ParaAddLine(lines[i]); } ParaEnd(); browser->position(0); } void Guix_Book::FollowLink(int line) { if (line < 0) { browser->deselect(); return; } const char * L = book_pages[cur_page].text[line]; if (L[0] == '#' && L[1] == 'L') { want_page = (L[2] - '0') * 10 + (L[3] - '0'); } else { // for lines without links, the best we can do is just clear the // hold selection. // browser->deselect(); } } void Guix_Book::Update() { if (want_page != BOOK_NO_PAGE) LoadPage(want_page); else if (want_reformat) LoadPage(cur_page); } // // PARAGRAPH CODE // void Guix_Book::ParaStart() { in_paragraph = FALSE; } void Guix_Book::ParaEnd() { if (in_paragraph && para_buf[0] != 0) { browser->add(para_buf); } in_paragraph = FALSE; } void Guix_Book::ParaAddWord(const char *word) { // set current font for fl_width() fl_font(browser->textfont(), browser->textsize()); // need to wrap ? if (para_buf[0] != 0 && (fl_width(para_buf) + fl_width(' ') + fl_width(word) > para_width)) { browser->add(para_buf); para_buf[0] = 0; first_line = FALSE; } if (para_buf[0] == 0) { // prefix with spaces to indent paragraph int count = major_indent + (first_line ? 0 : minor_indent); para_buf[count] = 0; for (count--; count >= 0; count--) para_buf[count] = ' '; } else strcat(para_buf, " "); strcat(para_buf, word); } void Guix_Book::ParaAddLine(const char *line) { if (line[0] == 0 || line[0] == '#' || line[0] == '@') ParaEnd(); if (line[0] == '#' && line[1] == 'L') { browser->add(line + 4); return; } if (! in_paragraph) { if (! (line[0] == '#' && line[1] == 'P')) { browser->add(line); return; } major_indent = (line[2] - '0') * 6 + 1; minor_indent = (line[3] - '0'); line += 4; in_paragraph = TRUE; first_line = TRUE; para_buf[0] = 0; para_width = browser->w() - 24 - (int)fl_width(' ') * major_indent; } // OK, we must be in paragraph mode here for (;;) { while (isspace(*line)) line++; if (line[0] == 0) return; char word_buf[100]; int word_len = 0; while (*line && word_len < 98) { // handle escapes: // '#-' : non-break space. // '. ' : add a non-break space after dot if (line[0] == '#' && line[1] == '-') { word_buf[word_len++] = ' '; line += 2; continue; } else if (line[0] == '.' && line[1] == ' ') { word_buf[word_len++] = '.'; word_buf[word_len++] = ' '; word_buf[word_len++] = ' '; line += 2; continue; } if (isspace(*line)) break; word_buf[word_len++] = *line++; } word_buf[word_len] = 0; ParaAddWord(word_buf); } } //------------------------------------------------------------------------ Guix_License *guix_lic_win; static void license_quit_CB(Fl_Widget *w, void *data) { if (guix_lic_win) guix_lic_win->want_quit = TRUE; } // // License Constructor // Guix_License::Guix_License() : Fl_Window(guix_prefs.manual_w, guix_prefs.manual_h, "glBSP License") { // cancel the automatic 'begin' in Fl_Group constructor end(); size_range(MANUAL_WINDOW_MIN_W, MANUAL_WINDOW_MIN_H); position(guix_prefs.manual_x, guix_prefs.manual_y); color(MAIN_BG_COLOR, MAIN_BG_COLOR); // allow manual closing of window callback((Fl_Callback *) license_quit_CB); want_quit = FALSE; // create close button in bottom row Fl_Box *invis_1 = new Fl_Box(0, 0, 30, 30); add(invis_1); group = new Fl_Group(0, h() - 34, w(), 34); group->resizable(invis_1); add(group); quit = new Fl_Button(w() - 96 - 24, h() - 30, 96, 26, "Close"); quit->box(FL_ROUND_UP_BOX); quit->callback((Fl_Callback *) license_quit_CB); group->add(quit); // create the browser int i; browser = new Fl_Browser(0, 0, w(), h() - 34); for (i=0; license_text[i]; i++) browser->add(license_text[i]); browser->position(0); add(browser); resizable(browser); // show the window set_modal(); show(); // read initial pos (same logic as in Guix_MainWin) WindowSmallDelay(); init_x = x(); init_y = y(); init_w = w(); init_h = h(); } // // License Destructor // Guix_License::~Guix_License() { // update preferences if user moved the window if (x() != init_x || y() != init_y) { guix_prefs.manual_x = x(); guix_prefs.manual_y = y(); } if (w() != init_w || h() != init_h) { guix_prefs.manual_w = w(); guix_prefs.manual_h = h(); } } glbsp-2.24-source/gui/window.cc0000644000175000017500000001026210650405207015726 0ustar aaptedaapted//------------------------------------------------------------------------ // WINDOW : Unix/FLTK application window //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // this includes everything we need #include "local.h" #ifndef WIN32 #include #endif Guix_MainWin *guix_win; static void main_win_close_CB(Fl_Widget *w, void *data) { if (guix_win) guix_win->want_quit = TRUE; } // // WindowSmallDelay // // This routine is meant to delay a short time (e.g. 1/5th of a // second) to allow the window manager to move our windows around. // // Hopefully such nonsense doesn't happen under Win32. // void WindowSmallDelay(void) { #ifndef WIN32 Fl::wait(0); usleep(100 * 1000); Fl::wait(0); usleep(100 * 1000); #endif Fl::wait(0); } // // MainWin Constructor // Guix_MainWin::Guix_MainWin(const char *title) : Fl_Window(guix_prefs.win_w, guix_prefs.win_h, title) { // turn off auto-add-widget mode end(); size_range(MAIN_WINDOW_MIN_W, MAIN_WINDOW_MIN_H); // Set initial position. // // Note: this may not work properly. It seems that when my window // manager adds the titlebar/border, it moves the actual window // down and slightly to the right, causing subsequent invokations // to keep going lower and lower. position(guix_prefs.win_x, guix_prefs.win_y); callback((Fl_Callback *) main_win_close_CB); // set a nice darkish gray for the space between main boxes color(MAIN_BG_COLOR, MAIN_BG_COLOR); want_quit = FALSE; // create contents int hw = (w() - 8*2 - 4) / 2; int mh = 28; #ifdef MACOSX mh = 1; #endif menu_bar = MenuCreate(0, 0, w(), 28); add(menu_bar); build_mode = new Guix_BuildMode(8, 4+mh, hw, 176); add(build_mode); misc_opts = new Guix_MiscOptions(8+hw+4, 4+mh, hw, 136); add(misc_opts); factor = new Guix_FactorBox(8+hw+4, 140+mh, hw, 40); add(factor); files = new Guix_FileBox(8, 184+mh, w()-8*2, 86); add(files); builder = new Guix_BuildButton(8, 274+10+mh, hw, 60); add(builder); progress = new Guix_ProgressBox(8+hw+4, 274+mh, hw, 74); add(progress); text_box = new Guix_TextBox(0, 352+mh, w(), h() - 352 - mh); add(text_box); resizable(text_box); // show window (pass some dummy arguments) int argc = 1; char *argv[] = { "glBSPX", NULL }; show(argc, argv); // read initial pos, giving 1/5th of a second for the WM to adjust // our window's position (naughty WM...) WindowSmallDelay(); init_x = x(); init_y = y(); init_w = w(); init_h = h(); } // // MainWin Destructor // Guix_MainWin::~Guix_MainWin() { WritePrefs(); } void Guix_MainWin::WritePrefs() { // check if moved or resized if (x() != init_x || y() != init_y) { guix_prefs.win_x = x(); guix_prefs.win_y = y(); } if (w() != init_w || h() != init_h) { guix_prefs.win_w = w(); guix_prefs.win_h = h(); } } void Guix_MainWin::ReadAllInfo() { // Note: do build_mode before files build_mode->ReadInfo(); misc_opts->ReadInfo(); files->ReadInfo(); factor->ReadInfo(); } void Guix_MainWin::WriteAllInfo() { // Note: do build_mode before files build_mode->WriteInfo(); misc_opts->WriteInfo(); files->WriteInfo(); factor->WriteInfo(); } void Guix_MainWin::LockOut(boolean_g lock_it) { build_mode->LockOut(lock_it); misc_opts->LockOut(lock_it); files->LockOut(lock_it); factor->LockOut(lock_it); builder->LockOut(lock_it); text_box->LockOut(lock_it); // change the mouse cursor cursor(lock_it ? FL_CURSOR_WAIT : FL_CURSOR_DEFAULT); } glbsp-2.24-source/patches/0000755000175000017500000000000010652040163014750 5ustar aaptedaaptedglbsp-2.24-source/patches/fltk_win32/0000755000175000017500000000000010652037671016744 5ustar aaptedaaptedglbsp-2.24-source/patches/fltk_win32/devcpp/0000755000175000017500000000000010652037671020225 5ustar aaptedaaptedglbsp-2.24-source/patches/fltk_win32/devcpp/fltk.lib.dev0000755000175000017500000004031510514052725022432 0ustar aaptedaapted[Project] FileName=fltk.lib.dev Name=fltk.lib Ver=1 IsCpp=1 Type=2 Compiler=-D__GNUWIN32___@@_-fexceptions_@@_-finline-functions_@@_-DFL_STATIC_@@_-DWIN32_@@_-DNDEBUG_@@_-D_WINDOWS_@@_-DWIN32_LEAN_AND_MEAN_@@_-DVC_EXTRA_LEAN_@@_-DWIN32_EXTRA_LEAN_@@_ CppCompiler=-D__GNUWIN32___@@_-fexceptions_@@_-finline-functions_@@_-DFL_STATIC_@@_-DWIN32_@@_-DNDEBUG_@@_-D_WINDOWS_@@_-DWIN32_LEAN_AND_MEAN_@@_-DVC_EXTRA_LEAN_@@_-DWIN32_EXTRA_LEAN_@@_ Includes=.. Linker= Libs= UnitCount=126 Folders= ObjFiles= PrivateResource= ResourceIncludes= MakeIncludes= Icon= ExeOutput= ObjectOutput= OverrideOutput=0 OverrideOutputName=fltk.lib HostApplication= CommandLine= IncludeVersionInfo=0 SupportXPThemes=0 CompilerSet=0 CompilerSettings=000000000001000000 [Unit1] FileName=..\src\filename_absolute.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit2] FileName=..\src\filename_expand.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit3] FileName=..\src\filename_ext.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit4] FileName=..\src\filename_isdir.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit5] FileName=..\src\filename_list.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit6] FileName=..\src\filename_match.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit7] FileName=..\src\filename_setext.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit8] FileName=..\src\Fl.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit9] FileName=..\src\Fl_abort.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit10] FileName=..\src\Fl_add_idle.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit11] FileName=..\src\Fl_Adjuster.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit12] FileName=..\src\fl_arc.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit13] FileName=..\src\fl_arci.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit14] FileName=..\src\Fl_arg.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit15] FileName=..\src\fl_ask.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit16] FileName=..\src\Fl_Bitmap.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit17] FileName=..\src\Fl_Box.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit18] FileName=..\src\fl_boxtype.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit19] FileName=..\src\Fl_Browser.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit20] FileName=..\src\Fl_Browser_.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit21] FileName=..\src\Fl_Browser_load.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit22] FileName=..\src\Fl_Button.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit23] FileName=..\src\fl_call_main.c Folder= Compile=1 CompileCpp=0 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit24] FileName=..\src\Fl_Chart.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit25] FileName=..\src\Fl_Check_Browser.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit26] FileName=..\src\Fl_Check_Button.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit27] FileName=..\src\Fl_Choice.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit28] FileName=..\src\Fl_Clock.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit29] FileName=..\src\fl_color.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit30] FileName=..\src\Fl_Color_Chooser.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit31] FileName=..\src\Fl_compose.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit32] FileName=..\src\Fl_Counter.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit33] FileName=..\src\fl_cursor.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit34] FileName=..\src\fl_curve.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit35] FileName=..\src\Fl_Dial.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit36] FileName=..\src\fl_diamond_box.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit37] FileName=..\src\Fl_display.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit38] FileName=..\src\fl_dnd.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit39] FileName=..\src\Fl_Double_Window.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit40] FileName=..\src\fl_draw.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit41] FileName=..\src\fl_draw_image.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit42] FileName=..\src\fl_draw_pixmap.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit43] FileName=..\src\fl_engraved_label.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit44] FileName=..\src\Fl_File_Browser.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit45] FileName=..\src\Fl_File_Chooser.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit46] FileName=..\src\Fl_File_Chooser2.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit47] FileName=..\src\fl_file_dir.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit48] FileName=..\src\Fl_File_Icon.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit49] FileName=..\src\Fl_File_Input.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit50] FileName=..\src\fl_font.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit51] FileName=..\src\Fl_get_key.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit52] FileName=..\src\Fl_get_system_colors.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit53] FileName=..\src\Fl_grab.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit54] FileName=..\src\Fl_Group.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit55] FileName=..\src\Fl_Help_View.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit56] FileName=..\src\Fl_Image.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit57] FileName=..\src\Fl_Input.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit58] FileName=..\src\Fl_Input_.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit59] FileName=..\src\fl_labeltype.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit60] FileName=..\src\Fl_Light_Button.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit61] FileName=..\src\fl_line_style.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit62] FileName=..\src\Fl_lock.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit63] FileName=..\src\Fl_Menu.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit64] FileName=..\src\Fl_Menu_.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit65] FileName=..\src\Fl_Menu_add.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit66] FileName=..\src\Fl_Menu_Bar.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit67] FileName=..\src\Fl_Menu_Button.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit68] FileName=..\src\Fl_Menu_global.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit69] FileName=..\src\Fl_Menu_Window.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit70] FileName=..\src\Fl_Multi_Label.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit71] FileName=..\src\fl_oval_box.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit72] FileName=..\src\fl_overlay.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit73] FileName=..\src\fl_overlay_visual.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit74] FileName=..\src\Fl_Overlay_Window.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit75] FileName=..\src\Fl_own_colormap.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit76] FileName=..\src\Fl_Pack.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit77] FileName=..\src\Fl_Pixmap.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit78] FileName=..\src\fl_plastic.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit79] FileName=..\src\Fl_Positioner.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit80] FileName=..\src\Fl_Preferences.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit81] FileName=..\src\Fl_Progress.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit82] FileName=..\src\fl_rect.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit83] FileName=..\src\Fl_Repeat_Button.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit84] FileName=..\src\Fl_Return_Button.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit85] FileName=..\src\Fl_Roller.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit86] FileName=..\src\fl_round_box.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit87] FileName=..\src\Fl_Round_Button.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit88] FileName=..\src\fl_rounded_box.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit89] FileName=..\src\Fl_Scroll.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit90] FileName=..\src\fl_scroll_area.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit91] FileName=..\src\Fl_Scrollbar.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit92] FileName=..\src\fl_set_font.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit93] FileName=..\src\fl_set_fonts.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit94] FileName=..\src\fl_shadow_box.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit95] FileName=..\src\Fl_Shared_Image.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit96] FileName=..\src\fl_shortcut.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit97] FileName=..\src\fl_show_colormap.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit98] FileName=..\src\Fl_Single_Window.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit99] FileName=..\src\Fl_Slider.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit100] FileName=..\src\fl_symbols.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit101] FileName=..\src\Fl_Tabs.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit102] FileName=..\src\Fl_Text_Buffer.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit103] FileName=..\src\Fl_Text_Display.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit104] FileName=..\src\Fl_Text_Editor.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit105] FileName=..\src\Fl_Tile.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit106] FileName=..\src\Fl_Tiled_Image.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit107] FileName=..\src\Fl_Tooltip.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit108] FileName=..\src\Fl_Valuator.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit109] FileName=..\src\Fl_Value_Input.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit110] FileName=..\src\Fl_Value_Output.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit111] FileName=..\src\Fl_Value_Slider.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit112] FileName=..\src\fl_vertex.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit113] FileName=..\src\Fl_visual.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit114] FileName=..\src\Fl_Widget.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit115] FileName=..\src\Fl_Window.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit116] FileName=..\src\Fl_Window_fullscreen.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit117] FileName=..\src\Fl_Window_hotspot.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit118] FileName=..\src\Fl_Window_iconize.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit119] FileName=..\src\Fl_Wizard.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit120] FileName=..\src\Fl_x.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit121] FileName=..\src\Fl_XBM_Image.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit122] FileName=..\src\Fl_XPM_Image.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit123] FileName=..\src\flstring.c Folder= Compile=1 CompileCpp=0 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit124] FileName=..\src\numericsort.c Folder= Compile=1 CompileCpp=0 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit125] FileName=..\src\scandir.c Folder= Compile=1 CompileCpp=0 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit126] FileName=..\src\vsnprintf.c Folder= Compile=1 CompileCpp=0 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [VersionInfo] Major=0 Minor=1 Release=1 Build=1 LanguageID=1033 CharsetID=1252 CompanyName= FileVersion=0.1 FileDescription=Developed using the Dev-C++ IDE InternalName= LegalCopyright= LegalTrademarks= OriginalFilename=fltk.lib ProductName=fltk.lib ProductVersion=0.1 AutoIncBuildNr=0 glbsp-2.24-source/patches/fltk_win32/devcpp/fltkimages.lib.dev0000755000175000017500000000376710514052725023632 0ustar aaptedaapted[Project] FileName=fltkimages.lib.dev Name=fltkimages Ver=1 IsCpp=1 Type=2 Compiler=-D__GNUWIN32___@@_-fexceptions_@@_-finline-functions_@@_-DFL_STATIC_@@_-DWIN32_@@_-DNDEBUG_@@_-D_WINDOWS_@@_-DWIN32_LEAN_AND_MEAN_@@_-DVC_EXTRA_LEAN_@@_-DWIN32_EXTRA_LEAN_@@_ CppCompiler=-D__GNUWIN32___@@_-fexceptions_@@_-finline-functions_@@_-DFL_STATIC_@@_-DWIN32_@@_-DNDEBUG_@@_-D_WINDOWS_@@_-DWIN32_LEAN_AND_MEAN_@@_-DVC_EXTRA_LEAN_@@_-DWIN32_EXTRA_LEAN_@@_ Includes=.. Linker= Libs= UnitCount=8 Folders= ObjFiles= PrivateResource= ResourceIncludes= MakeIncludes= Icon= ExeOutput= ObjectOutput= OverrideOutput=0 OverrideOutputName=fltkimages.exe HostApplication= CommandLine= IncludeVersionInfo=0 SupportXPThemes=0 CompilerSet=0 CompilerSettings=000000000010000000 [Unit1] FileName=..\src\Fl_BMP_Image.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit2] FileName=..\src\Fl_File_Icon2.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit3] FileName=..\src\Fl_GIF_Image.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit4] FileName=..\src\Fl_Help_Dialog.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit5] FileName=..\src\fl_images_core.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit6] FileName=..\src\Fl_JPEG_Image.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit7] FileName=..\src\Fl_PNG_Image.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit8] FileName=..\src\Fl_PNM_Image.cxx Folder= Compile=1 CompileCpp=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [VersionInfo] Major=0 Minor=1 Release=1 Build=1 LanguageID=1033 CharsetID=1252 CompanyName= FileVersion=0.1 FileDescription=Developed using the Dev-C++ IDE InternalName= LegalCopyright= LegalTrademarks= OriginalFilename=fltkimages.exe ProductName=fltkimages ProductVersion=0.1 AutoIncBuildNr=0 glbsp-2.24-source/patches/fltk_win32/src/0000755000175000017500000000000010652037671017533 5ustar aaptedaaptedglbsp-2.24-source/patches/fltk_win32/src/Fl_win32.cxx0000644000175000017500000010431710514052726021643 0ustar aaptedaapted// // "$Id: Fl_win32.cxx 109 2003-12-24 10:38:34Z ajapted $" // // WIN32-specific code for the Fast Light Tool Kit (FLTK). // // Copyright 1998-2003 by Bill Spitzak and others. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA. // // Please report all bugs and problems to "fltk-bugs@fltk.org". // // This file contains win32-specific code for fltk which is always linked // in. Search other files for "WIN32" or filenames ending in _win32.cxx // for other system-specific code. #include #include #include #include "flstring.h" #include #include #include #include #ifdef __CYGWIN__ # include # include #else # include #endif #include #include // The following include files require GCC 3.x or a non-GNU compiler... #if !defined(__GNUC__) || __GNUC__ >= 3 # include # include #endif // !__GNUC__ || __GNUC__ >= 3 // // USE_ASYNC_SELECT - define it if you have WSAAsyncSelect()... // // This currently doesn't appear to work; needs to be fixed! // //#define USE_ASYNC_SELECT // // USE_TRACK_MOUSE - define it if you have TrackMouseEvent()... // // Apparently, at least some versions of Cygwin/MingW don't provide // the TrackMouseEvent() function. You can define this by hand // if you have it - this is only needed to support subwindow // enter/leave notification under Windows. // //#define USE_TRACK_MOUSE #if !defined(__GNUC__) # define USE_TRACK_MOUSE #endif // !__GNUC__ // // WM_SYNCPAINT is an "undocumented" message, which is finally defined in // VC++ 6.0. // #ifndef WM_SYNCPAINT # define WM_SYNCPAINT 0x0088 #endif #ifndef WM_MOUSELEAVE # define WM_MOUSELEAVE 0x02a3 #endif #ifndef WM_MOUSEWHEEL # define WM_MOUSEWHEEL 0x020a #endif #ifndef WHEEL_DELTA # define WHEEL_DELTA 120 // according to MSDN. #endif // // WM_FLSELECT is the user-defined message that we get when one of // the sockets has pending data, etc. // #define WM_FLSELECT (WM_USER+0x0400) //////////////////////////////////////////////////////////////// // interface to poll/select call: // fd's are only implemented for sockets. Microsoft Windows does not // have a unified IO system, so it doesn't support select() on files, // devices, or pipes... // // Microsoft provides the Berkeley select() call and an asynchronous // select function that sends a WIN32 message when the select condition // exists... static int maxfd = 0; #ifndef USE_ASYNC_SELECT static fd_set fdsets[3]; #endif // !USE_ASYNC_SELECT #define POLLIN 1 #define POLLOUT 4 #define POLLERR 8 #if !defined(__GNUC__) || __GNUC__ >= 3 extern IDropTarget *flIDropTarget; #endif // !__GNUC__ || __GNUC__ >= 3 static int nfds = 0; static int fd_array_size = 0; static struct FD { int fd; short events; void (*cb)(int, void*); void* arg; } *fd = 0; void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) { remove_fd(n,events); int i = nfds++; if (i >= fd_array_size) { fd_array_size = 2*fd_array_size+1; fd = (FD*)realloc(fd, fd_array_size*sizeof(FD)); } fd[i].fd = n; fd[i].events = (short)events; fd[i].cb = cb; fd[i].arg = v; #ifdef USE_ASYNC_SELECT int mask = 0; if (events & POLLIN) mask |= FD_READ; if (events & POLLOUT) mask |= FD_WRITE; if (events & POLLERR) mask |= FD_CLOSE; WSAAsyncSelect(n, fl_window, WM_FLSELECT, mask); #else if (events & POLLIN) FD_SET(n, &fdsets[0]); if (events & POLLOUT) FD_SET(n, &fdsets[1]); if (events & POLLERR) FD_SET(n, &fdsets[2]); if (n > maxfd) maxfd = n; #endif // USE_ASYNC_SELECT } void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) { Fl::add_fd(fd, POLLIN, cb, v); } void Fl::remove_fd(int n, int events) { int i,j; for (i=j=0; i0 if any callbacks were done. This version only // returns zero if nothing happens during a 0.0 timeout, otherwise // it returns 1. int fl_wait(double time_to_wait) { int have_message = 0; int timerid; #ifndef USE_ASYNC_SELECT if (nfds) { // For WIN32 we need to poll for socket input FIRST, since // the event queue is not something we can select() on... timeval t; t.tv_sec = 0; t.tv_usec = 0; fd_set fdt[3]; fdt[0] = fdsets[0]; fdt[1] = fdsets[1]; fdt[2] = fdsets[2]; if (::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t)) { // We got something - do the callback! for (int i = 0; i < nfds; i ++) { int f = fd[i].fd; short revents = 0; if (FD_ISSET(f,&fdt[0])) revents |= POLLIN; if (FD_ISSET(f,&fdt[1])) revents |= POLLOUT; if (FD_ISSET(f,&fdt[2])) revents |= POLLERR; if (fd[i].events & revents) fd[i].cb(f, fd[i].arg); } time_to_wait = 0.0; // just peek for any messages #ifdef __CYGWIN__ } #else } else { // we need to check them periodically, so set a short timeout: if (time_to_wait > .001) time_to_wait = .001; } #endif } #endif // USE_ASYNC_SELECT fl_unlock_function(); if (time_to_wait < 2147483.648) { // Perform the requested timeout... have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); if (!have_message) { int t = (int)(time_to_wait * 1000.0 + .5); if (t <= 0) { // too short to measure fl_lock_function(); return 0; } timerid = SetTimer(NULL, 0, t, NULL); have_message = GetMessage(&fl_msg, NULL, 0, 0); KillTimer(NULL, timerid); } } else { have_message = GetMessage(&fl_msg, NULL, 0, 0); } fl_lock_function(); // Execute the message we got, and all other pending messages: while (have_message) { #ifdef USE_ASYNC_SELECT if (fl_msg.message == WM_FLSELECT) { // Got notification for socket for (int i = 0; i < nfds; i ++) if (fd[i].fd == (int)fl_msg.wParam) { (fd[i].cb)(fd[i].fd, fd[i].arg); break; } // looks like it is best to do the dispatch-message anyway: } #endif if (fl_msg.message == fl_wake_msg) // Used for awaking wait() from another thread thread_message_ = (void*)fl_msg.wParam; TranslateMessage(&fl_msg); DispatchMessage(&fl_msg); have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); } // This should return 0 if only timer events were handled: return 1; } // fl_ready() is just like fl_wait(0.0) except no callbacks are done: int fl_ready() { if (PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE)) return 1; #ifdef USE_ASYNC_SELECT return 0; #else timeval t; t.tv_sec = 0; t.tv_usec = 0; fd_set fdt[3]; fdt[0] = fdsets[0]; fdt[1] = fdsets[1]; fdt[2] = fdsets[2]; return ::select(0,&fdt[0],&fdt[1],&fdt[2],&t); #endif // USE_ASYNC_SELECT } //////////////////////////////////////////////////////////////// int Fl::x() { RECT r; SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); return r.left; } int Fl::y() { RECT r; SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); return r.top; } int Fl::h() { RECT r; SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); return r.bottom - r.top; } int Fl::w() { RECT r; SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); return r.right - r.left; } void Fl::get_mouse(int &x, int &y) { POINT p; GetCursorPos(&p); x = p.x; y = p.y; } //////////////////////////////////////////////////////////////// // code used for selections: char *fl_selection_buffer[2]; int fl_selection_length[2]; int fl_selection_buffer_length[2]; char fl_i_own_selection[2]; // call this when you create a selection: void Fl::copy(const char *stuff, int len, int clipboard) { if (!stuff || len<0) return; if (len+1 > fl_selection_buffer_length[clipboard]) { delete[] fl_selection_buffer[clipboard]; fl_selection_buffer[clipboard] = new char[len+100]; fl_selection_buffer_length[clipboard] = len+100; } memcpy(fl_selection_buffer[clipboard], stuff, len); fl_selection_buffer[clipboard][len] = 0; // needed for direct paste fl_selection_length[clipboard] = len; if (clipboard) { // set up for "delayed rendering": if (OpenClipboard(fl_xid(Fl::first_window()))) { EmptyClipboard(); SetClipboardData(CF_TEXT, NULL); CloseClipboard(); } fl_i_own_selection[clipboard] = 1; } } // Call this when a "paste" operation happens: void Fl::paste(Fl_Widget &receiver, int clipboard) { if (!clipboard || fl_i_own_selection[clipboard]) { // We already have it, do it quickly without window server. // Notice that the text is clobbered if set_selection is // called in response to FL_PASTE! Fl::e_text = fl_selection_buffer[clipboard]; Fl::e_length = fl_selection_length[clipboard]; if (!Fl::e_text) Fl::e_text = (char *)""; receiver.handle(FL_PASTE); } else { if (!OpenClipboard(NULL)) return; HANDLE h = GetClipboardData(CF_TEXT); if (h) { Fl::e_text = (LPSTR)GlobalLock(h); LPSTR a,b; a = b = Fl::e_text; while (*a) { // strip the CRLF pairs ($%$#@^) if (*a == '\r' && a[1] == '\n') a++; else *b++ = *a++; } *b = 0; Fl::e_length = b - Fl::e_text; receiver.handle(FL_PASTE); GlobalUnlock(h); } CloseClipboard(); } } //////////////////////////////////////////////////////////////// HWND fl_capture; static int mouse_event(Fl_Window *window, int what, int button, WPARAM wParam, LPARAM lParam) { static int px, py, pmx, pmy; POINT pt; Fl::e_x = pt.x = (signed short)LOWORD(lParam); Fl::e_y = pt.y = (signed short)HIWORD(lParam); ClientToScreen(fl_xid(window), &pt); Fl::e_x_root = pt.x; Fl::e_y_root = pt.y; while (window->parent()) { Fl::e_x += window->x(); Fl::e_y += window->y(); window = window->window(); } ulong state = Fl::e_state & 0xff0000; // keep shift key states #if 0 // mouse event reports some shift flags, perhaps save them? if (wParam & MK_SHIFT) state |= FL_SHIFT; if (wParam & MK_CONTROL) state |= FL_CTRL; #endif if (wParam & MK_LBUTTON) state |= FL_BUTTON1; if (wParam & MK_MBUTTON) state |= FL_BUTTON2; if (wParam & MK_RBUTTON) state |= FL_BUTTON3; Fl::e_state = state; switch (what) { case 1: // double-click if (Fl::e_is_click) {Fl::e_clicks++; goto J1;} case 0: // single-click Fl::e_clicks = 0; J1: if (!fl_capture) SetCapture(fl_xid(window)); Fl::e_keysym = FL_Button + button; Fl::e_is_click = 1; px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root; return Fl::handle(FL_PUSH,window); case 2: // release: if (!fl_capture) ReleaseCapture(); Fl::e_keysym = FL_Button + button; return Fl::handle(FL_RELEASE,window); case 3: // move: default: // avoid compiler warning // MSWindows produces extra events even if mouse does not move, ignore em: if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) return 1; pmx = Fl::e_x_root; pmy = Fl::e_y_root; if (abs(Fl::e_x_root-px)>5 || abs(Fl::e_y_root-py)>5) Fl::e_is_click = 0; return Fl::handle(FL_MOVE,window); } } // convert a MSWindows VK_x to an Fltk (X) Keysym: // See also the inverse converter in Fl_get_key_win32.cxx // This table is in numeric order by VK: static const struct {unsigned short vk, fltk, extended;} vktab[] = { {VK_BACK, FL_BackSpace}, {VK_TAB, FL_Tab}, {VK_CLEAR, FL_KP+'5', 0xff0b/*XK_Clear*/}, {VK_RETURN, FL_Enter, FL_KP_Enter}, {VK_SHIFT, FL_Shift_L, FL_Shift_R}, {VK_CONTROL, FL_Control_L, FL_Control_R}, {VK_MENU, FL_Alt_L, FL_Alt_R}, {VK_PAUSE, FL_Pause}, {VK_CAPITAL, FL_Caps_Lock}, {VK_ESCAPE, FL_Escape}, {VK_SPACE, ' '}, {VK_PRIOR, FL_KP+'9', FL_Page_Up}, {VK_NEXT, FL_KP+'3', FL_Page_Down}, {VK_END, FL_KP+'1', FL_End}, {VK_HOME, FL_KP+'7', FL_Home}, {VK_LEFT, FL_KP+'4', FL_Left}, {VK_UP, FL_KP+'8', FL_Up}, {VK_RIGHT, FL_KP+'6', FL_Right}, {VK_DOWN, FL_KP+'2', FL_Down}, {VK_SNAPSHOT, FL_Print}, // does not work on NT {VK_INSERT, FL_KP+'0', FL_Insert}, {VK_DELETE, FL_KP+'.', FL_Delete}, {VK_LWIN, FL_Meta_L}, {VK_RWIN, FL_Meta_R}, {VK_APPS, FL_Menu}, {VK_MULTIPLY, FL_KP+'*'}, {VK_ADD, FL_KP+'+'}, {VK_SUBTRACT, FL_KP+'-'}, {VK_DECIMAL, FL_KP+'.'}, {VK_DIVIDE, FL_KP+'/'}, {VK_NUMLOCK, FL_Num_Lock}, {VK_SCROLL, FL_Scroll_Lock}, {0xba, ';'}, {0xbb, '='}, {0xbc, ','}, {0xbd, '-'}, {0xbe, '.'}, {0xbf, '/'}, {0xc0, '`'}, {0xdb, '['}, {0xdc, '\\'}, {0xdd, ']'}, {0xde, '\''} }; static int ms2fltk(int vk, int extended) { static unsigned short vklut[256]; static unsigned short extendedlut[256]; if (!vklut[1]) { // init the table unsigned int i; for (i = 0; i < 256; i++) vklut[i] = tolower(i); for (i=VK_F1; i<=VK_F16; i++) vklut[i] = i+(FL_F-(VK_F1-1)); for (i=VK_NUMPAD0; i<=VK_NUMPAD9; i++) vklut[i] = i+(FL_KP+'0'-VK_NUMPAD0); for (i = 0; i < sizeof(vktab)/sizeof(*vktab); i++) { vklut[vktab[i].vk] = vktab[i].fltk; extendedlut[vktab[i].vk] = vktab[i].extended; } for (i = 0; i < 256; i++) if (!extendedlut[i]) extendedlut[i] = vklut[i]; } return extended ? extendedlut[vk] : vklut[vk]; } #if USE_COLORMAP extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx #endif static Fl_Window* resize_bug_fix; extern void fl_save_pen(void); extern void fl_restore_pen(void); static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // Copy the message to fl_msg so add_handler code can see it, it is // already there if this is called by DispatchMessage, but not if // Windows calls this directly. fl_msg.hwnd = hWnd; fl_msg.message = uMsg; fl_msg.wParam = wParam; fl_msg.lParam = lParam; //fl_msg.time = ??? //fl_msg.pt = ??? //fl_msg.lPrivate = ??? Fl_Window *window = fl_find(hWnd); if (window) switch (uMsg) { case WM_QUIT: // this should not happen? Fl::fatal("WM_QUIT message"); case WM_CLOSE: // user clicked close box Fl::handle(FL_CLOSE, window); return 0; case WM_SYNCPAINT : case WM_NCPAINT : case WM_ERASEBKGND : // Andreas Weitl - WM_SYNCPAINT needs to be passed to DefWindowProc // so that Windows can generate the proper paint messages... // Similarly, WM_NCPAINT and WM_ERASEBKGND need this, too... break; case WM_PAINT: { Fl_Region R; Fl_X *i = Fl_X::i(window); i->wait_for_expose = 0; if (!i->region && window->damage()) { // Redraw the whole window... i->region = CreateRectRgn(0, 0, window->w(), window->h()); } else { // We need to merge WIN32's damage into FLTK's damage. R = CreateRectRgn(0,0,0,0); GetUpdateRgn(hWnd,R,0); if (i->region) { // Also tell WIN32 that we are drawing someplace else as well... InvalidateRgn(hWnd, i->region, FALSE); CombineRgn(i->region, i->region, R, RGN_OR); XDestroyRegion(R); } else { i->region = R; } } window->clear_damage((uchar)(window->damage()|FL_DAMAGE_EXPOSE)); // These next two statements should not be here, so that all update // is deferred until Fl::flush() is called during idle. However WIN32 // apparently is very unhappy if we don't obey it and draw right now. // Very annoying! fl_GetDC(hWnd); // Make sure we have a DC for this window... fl_save_pen(); i->flush(); fl_restore_pen(); if (window->type() == FL_DOUBLE_WINDOW) ValidateRgn(hWnd,0); else ValidateRgn(hWnd,i->region); window->clear_damage(); } return 0; case WM_LBUTTONDOWN: mouse_event(window, 0, 1, wParam, lParam); return 0; case WM_LBUTTONDBLCLK:mouse_event(window, 1, 1, wParam, lParam); return 0; case WM_LBUTTONUP: mouse_event(window, 2, 1, wParam, lParam); return 0; case WM_MBUTTONDOWN: mouse_event(window, 0, 2, wParam, lParam); return 0; case WM_MBUTTONDBLCLK:mouse_event(window, 1, 2, wParam, lParam); return 0; case WM_MBUTTONUP: mouse_event(window, 2, 2, wParam, lParam); return 0; case WM_RBUTTONDOWN: mouse_event(window, 0, 3, wParam, lParam); return 0; case WM_RBUTTONDBLCLK:mouse_event(window, 1, 3, wParam, lParam); return 0; case WM_RBUTTONUP: mouse_event(window, 2, 3, wParam, lParam); return 0; case WM_MOUSEMOVE: #ifdef USE_TRACK_MOUSE if (Fl::belowmouse() != window) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; tme.hwndTrack = hWnd; _TrackMouseEvent(&tme); } #endif // USE_TRACK_MOUSE mouse_event(window, 3, 0, wParam, lParam); return 0; case WM_MOUSELEAVE: Fl::belowmouse(0); if (!window->parent()) Fl::handle(FL_LEAVE, window); break; case WM_SETFOCUS: Fl::handle(FL_FOCUS, window); break; case WM_KILLFOCUS: Fl::handle(FL_UNFOCUS, window); Fl::flush(); // it never returns to main loop when deactivated... break; case WM_SHOWWINDOW: if (!window->parent()) { Fl::handle(wParam ? FL_SHOW : FL_HIDE, window); } break; case WM_ACTIVATEAPP: // From eric@vfx.sel.sony.com, we should process WM_ACTIVATEAPP // messages to restore the correct state of the shift/ctrl/alt/lock // keys... Added control, shift, alt, and meta keys, and changed // to use GetAsyncKeyState and do it when wParam is 1 // (that means we have focus...) if (wParam) { ulong state = 0; if (GetAsyncKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK; if (GetAsyncKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK; if (GetAsyncKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK; if (GetAsyncKeyState(VK_CONTROL)&~1) state |= FL_CTRL; if (GetAsyncKeyState(VK_SHIFT)&~1) state |= FL_SHIFT; if (GetAsyncKeyState(VK_MENU)) state |= FL_ALT; if ((GetAsyncKeyState(VK_LWIN)|GetAsyncKeyState(VK_RWIN))&~1) state |= FL_META; Fl::e_state = state; return 0; } break; case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: // save the keysym until we figure out the characters: Fl::e_keysym = ms2fltk(wParam,lParam&(1<<24)); // See if TranslateMessage turned it into a WM_*CHAR message: if (PeekMessage(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) { uMsg = fl_msg.message; wParam = fl_msg.wParam; lParam = fl_msg.lParam; } case WM_DEADCHAR: case WM_SYSDEADCHAR: case WM_CHAR: case WM_SYSCHAR: { ulong state = Fl::e_state & 0xff000000; // keep the mouse button state // if GetKeyState is expensive we might want to comment some of these out: if (GetKeyState(VK_SHIFT)&~1) state |= FL_SHIFT; if (GetKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK; if (GetKeyState(VK_CONTROL)&~1) state |= FL_CTRL; // Alt gets reported for the Alt-GR switch on foreign keyboards. // so we need to check the event as well to get it right: if ((lParam&(1<<29)) //same as GetKeyState(VK_MENU) && uMsg != WM_CHAR) state |= FL_ALT; if (GetKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK; if ((GetKeyState(VK_LWIN)|GetKeyState(VK_RWIN))&~1) { // WIN32 bug? GetKeyState returns garbage if the user hit the // meta key to pop up start menu. Sigh. if ((GetAsyncKeyState(VK_LWIN)|GetAsyncKeyState(VK_RWIN))&~1) state |= FL_META; } if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK; Fl::e_state = state; if (lParam & (1<<31)) { // key up events. if (Fl::handle(FL_KEYUP, window)) return 0; break; } static char buffer[2]; if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { buffer[0] = char(wParam); Fl::e_length = 1; } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { buffer[0] = Fl::e_keysym-FL_KP; Fl::e_length = 1; } else { buffer[0] = 0; Fl::e_length = 0; } Fl::e_text = buffer; // for (int i = lParam&0xff; i--;) while (window->parent()) window = window->window(); if (Fl::handle(FL_KEYBOARD,window)) return 0; break;} case WM_MOUSEWHEEL: { static int delta = 0; // running total of all motion delta += (SHORT)(HIWORD(wParam)); Fl::e_dy = -delta / WHEEL_DELTA; delta += Fl::e_dy * WHEEL_DELTA; if (Fl::e_dy) Fl::handle(FL_MOUSEWHEEL, window); return 0; } case WM_GETMINMAXINFO: Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam); break; case WM_SIZE: if (!window->parent()) { if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE) { Fl::handle(FL_HIDE, window); } else { Fl::handle(FL_SHOW, window); resize_bug_fix = window; window->size(LOWORD(lParam), HIWORD(lParam)); } } break; case WM_MOVE: resize_bug_fix = window; window->position(LOWORD(lParam), HIWORD(lParam)); break; case WM_SETCURSOR: if (LOWORD(lParam) == HTCLIENT) { while (window->parent()) window = window->window(); SetCursor(Fl_X::i(window)->cursor); return 0; } break; #if USE_COLORMAP case WM_QUERYNEWPALETTE : fl_GetDC(hWnd); if (fl_select_palette()) InvalidateRect(hWnd, NULL, FALSE); break; case WM_PALETTECHANGED: fl_GetDC(hWnd); if ((HWND)wParam != hWnd && fl_select_palette()) UpdateColors(fl_gc); break; case WM_CREATE : fl_GetDC(hWnd); fl_select_palette(); break; #endif case WM_DESTROYCLIPBOARD: fl_i_own_selection[1] = 0; return 1; case WM_RENDERALLFORMATS: fl_i_own_selection[1] = 0; // Windoze seems unhappy unless I do these two steps. Documentation // seems to vary on whether opening the clipboard is necessary or // is in fact wrong: CloseClipboard(); OpenClipboard(NULL); // fall through... case WM_RENDERFORMAT: { HANDLE h = GlobalAlloc(GHND, fl_selection_length[1]+1); if (h) { LPSTR p = (LPSTR)GlobalLock(h); memcpy(p, fl_selection_buffer[1], fl_selection_length[1]); p[fl_selection_length[1]] = 0; GlobalUnlock(h); SetClipboardData(CF_TEXT, h); } // Windoze also seems unhappy if I don't do this. Documentation very // unclear on what is correct: if (fl_msg.message == WM_RENDERALLFORMATS) CloseClipboard(); return 1;} default: if (Fl::handle(0,0)) return 0; break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } //////////////////////////////////////////////////////////////// // This function gets the dimensions of the top/left borders and // the title bar, if there is one, based on the FL_BORDER, FL_MODAL // and FL_NONMODAL flags, and on the window's size range. // It returns the following values: // // value | border | title bar // 0 | none | no // 1 | fix | yes // 2 | size | yes int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by) { int W, H, xoff, yoff, dx, dy; int ret = bx = by = bt = 0; if (w->border() && !w->parent()) { if (w->size_range_set && (w->maxw != w->minw || w->maxh != w->minh)) { ret = 2; bx = GetSystemMetrics(SM_CXSIZEFRAME); by = GetSystemMetrics(SM_CYSIZEFRAME); } else { ret = 1; bx = GetSystemMetrics(SM_CXFIXEDFRAME); by = GetSystemMetrics(SM_CYFIXEDFRAME); } bt = GetSystemMetrics(SM_CYCAPTION); } //The coordinates of the whole window, including non-client area xoff = bx; yoff = by + bt; dx = 2*bx; dy = 2*by + bt; X = w->x()-xoff; Y = w->y()-yoff; W = w->w()+dx; H = w->h()+dy; //Proceed to positioning the window fully inside the screen, if possible //Make border's lower right corner visible if (Fl::w() < X+W) X = Fl::w() - W; if (Fl::h() < Y+H) Y = Fl::h() - H; //Make border's upper left corner visible if (X<0) X = 0; if (Y<0) Y = 0; //Make client area's lower right corner visible if (Fl::w() < X+dx+ w->w()) X = Fl::w() - w->w() - dx; if (Fl::h() < Y+dy+ w->h()) Y = Fl::h() - w->h() - dy; //Make client area's upper left corner visible if (X+xoff < 0) X = -xoff; if (Y+yoff < 0) Y = -yoff; //Return the client area's top left corner in (X,Y) X+=xoff; Y+=yoff; return ret; } //////////////////////////////////////////////////////////////// void Fl_Window::resize(int X,int Y,int W,int H) { UINT flags = SWP_NOSENDCHANGING | SWP_NOZORDER; int is_a_resize = (W != w() || H != h()); int resize_from_program = (this != resize_bug_fix); if (!resize_from_program) resize_bug_fix = 0; if (X != x() || Y != y()) { set_flag(FL_FORCE_POSITION); } else { if (!is_a_resize) return; flags |= SWP_NOMOVE; } if (is_a_resize) { Fl_Group::resize(X,Y,W,H); if (shown()) {redraw(); i->wait_for_expose = 1;} } else { x(X); y(Y); flags |= SWP_NOSIZE; } if (!border()) flags |= SWP_NOACTIVATE; if (resize_from_program && shown()) { if (!resizable()) size_range(w(),h(),w(),h()); int dummy, bt, bx, by; //Ignore window managing when resizing, so that windows (and more //specifically menus) can be moved offscreen. if (Fl_X::fake_X_wm(this, dummy, dummy, bt, bx, by)) { X -= bx; Y -= by+bt; W += 2*bx; H += 2*by+bt; } SetWindowPos(i->xid, 0, X, Y, W, H, flags); } } //////////////////////////////////////////////////////////////// void fl_fix_focus(); // in Fl.cxx char fl_show_iconic; // hack for Fl_Window::iconic() // int fl_background_pixel = -1; // color to use for background HCURSOR fl_default_cursor; UINT fl_wake_msg = 0; int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR Fl_X* Fl_X::make(Fl_Window* w) { Fl_Group::current(0); // get rid of very common user bug: forgot end() const char* class_name = /*w->xclass(); if (!class_name) class_name =*/ "FLTK"; // create a "FLTK" WNDCLASS const char* message_name = "FLTK::ThreadWakeup"; WNDCLASSEX wc; // Documentation states a device context consumes about 800 bytes // of memory... so who cares? If 800 bytes per window is what it // takes to speed things up, I'm game. //wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; wc.lpfnWndProc = (WNDPROC)WndProc; wc.cbClsExtra = wc.cbWndExtra = 0; wc.hInstance = fl_display; if (!w->icon()) w->icon((void *)LoadIcon(NULL, IDI_APPLICATION)); wc.hIcon = wc.hIconSm = (HICON)w->icon(); wc.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW); //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b); //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b)); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = class_name; wc.cbSize = sizeof(WNDCLASSEX); RegisterClassEx(&wc); if (!fl_wake_msg) fl_wake_msg = RegisterWindowMessage(message_name); HWND parent; DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS; DWORD styleEx = WS_EX_LEFT; int xp = w->x(); int yp = w->y(); int wp = w->w(); int hp = w->h(); int showit = 1; if (w->parent()) { style |= WS_CHILD; styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; parent = fl_xid(w->window()); } else { if (!w->size_range_set) { if (w->resizable()) { Fl_Widget *o = w->resizable(); int minw = o->w(); if (minw > 100) minw = 100; int minh = o->h(); if (minh > 100) minh = 100; w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0); } else { w->size_range(w->w(), w->h(), w->w(), w->h()); } } styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; int xwm = xp , ywm = yp , bt, bx, by; switch (fake_X_wm(w, xwm, ywm, bt, bx, by)) { // No border (used for menus) case 0: style |= WS_POPUP; styleEx |= WS_EX_TOOLWINDOW; break; // Thin border and title bar case 1: style |= WS_DLGFRAME | WS_CAPTION; break; // Thick, resizable border and title bar, with maximize button case 2: style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_CAPTION ; break; } if (by+bt) { if (!w->modal()) style |= WS_MINIMIZEBOX; style |= WS_SYSMENU; wp += 2*bx; hp += 2*by+bt; } if (!(w->flags() & Fl_Window::FL_FORCE_POSITION)) { xp = yp = CW_USEDEFAULT; } else { if (!Fl::grab()) { xp = xwm; yp = ywm; w->x(xp);w->y(yp); } xp -= bx; yp -= by+bt; } parent = 0; if (w->non_modal() && Fl_X::first && !fl_disable_transient_for) { // find some other window to be "transient for": Fl_Window* w = Fl_X::first->w; while (w->parent()) w = w->window(); parent = fl_xid(w); if (!w->visible()) showit = 0; } else if (Fl::grab()) parent = fl_xid(Fl::grab()); } Fl_X* x = new Fl_X; x->other_xid = 0; x->setwindow(w); x->region = 0; x->private_dc = 0; x->cursor = fl_default_cursor; x->xid = CreateWindowEx( styleEx, class_name, w->label(), style, xp, yp, wp, hp, parent, NULL, // menu fl_display, NULL // creation parameters ); x->next = Fl_X::first; Fl_X::first = x; x->wait_for_expose = 1; if (fl_show_iconic) {showit = 0; fl_show_iconic = 0;} if (showit) { w->set_visible(); w->handle(FL_SHOW); // get child windows to appear w->redraw(); // force draw to happen } // If we've captured the mouse, we dont want do activate any // other windows from the code, or we loose the capture. ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE : (Fl::grab() || (style & WS_POPUP)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL); // Drag-n-drop requires GCC 3.x or a non-GNU compiler... #if !defined(__GNUC__) || __GNUC__ >= 3 // Register all windows for potential drag'n'drop operations static char oleInitialized = 0; if (!oleInitialized) { OleInitialize(0L); oleInitialized=1; } RegisterDragDrop(x->xid, flIDropTarget); #endif // !__GNUC__ || __GNUC__ >= 3 if (w->modal()) {Fl::modal_ = w; fl_fix_focus();} return x; } //////////////////////////////////////////////////////////////// HINSTANCE fl_display = GetModuleHandle(NULL); void Fl_Window::size_range_() { size_range_set = 1; } void Fl_X::set_minmax(LPMINMAXINFO minmax) { int td, wd, hd, dummy; fake_X_wm(w, dummy, dummy, td, wd, hd); wd *= 2; hd *= 2; hd += td; minmax->ptMinTrackSize.x = w->minw + wd; minmax->ptMinTrackSize.y = w->minh + hd; if (w->maxw) { minmax->ptMaxTrackSize.x = w->maxw + wd; minmax->ptMaxSize.x = w->maxw + wd; } if (w->maxh) { minmax->ptMaxTrackSize.y = w->maxh + hd; minmax->ptMaxSize.y = w->maxh + hd; } } //////////////////////////////////////////////////////////////// #include // need so FL_EXPORT fl_filename_name works // returns pointer to the filename, or null if name ends with '/' const char *fl_filename_name(const char *name) { const char *p,*q; if (!name) return (0); q = name; if (q[0] && q[1]==':') q += 2; // skip leading drive letter for (p = q; *p; p++) if (*p == '/' || *p == '\\') q = p+1; return q; } void Fl_Window::label(const char *name,const char *iname) { Fl_Widget::label(name); iconlabel_ = iname; if (shown() && !parent()) { if (!name) name = ""; SetWindowText(i->xid, name); // if (!iname) iname = fl_filename_name(name); // should do something with iname here... } } //////////////////////////////////////////////////////////////// // Implement the virtual functions for the base Fl_Window class: // If the box is a filled rectangle, we can make the redisplay *look* // faster by using X's background pixel erasing. We can make it // actually *be* faster by drawing the frame only, this is done by // setting fl_boxcheat, which is seen by code in fl_drawbox.cxx: // For WIN32 it looks like all windows share a background color, so // I use FL_GRAY for this and only do this cheat for windows that are // that color. // Actually it is totally disabled. // Fl_Widget *fl_boxcheat; //static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);} void Fl_Window::show() { image(Fl::scheme_bg_); if (Fl::scheme_bg_) { labeltype(FL_NORMAL_LABEL); align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP); } else { labeltype(FL_NO_LABEL); } if (!shown()) { // if (can_boxcheat(box())) fl_background_pixel = fl_xpixel(color()); Fl_X::make(this); } else { // Once again, we would lose the capture if we activated the window. if (IsIconic(i->xid)) OpenIcon(i->xid); if (!fl_capture) BringWindowToTop(i->xid); //ShowWindow(i->xid,fl_capture?SW_SHOWNOACTIVATE:SW_RESTORE); } } Fl_Window *Fl_Window::current_; // the current context HDC fl_gc = 0; // the current window handle, initially set to -1 so we can correctly // allocate fl_GetDC(0) HWND fl_window = (HWND)-1; // Here we ensure only one GetDC is ever in place. HDC fl_GetDC(HWND w) { if (fl_gc) { if (w == fl_window) return fl_gc; ReleaseDC(fl_window, fl_gc); } fl_gc = GetDC(w); fl_window = w; // calling GetDC seems to always reset these: (?) SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT); SetBkMode(fl_gc, TRANSPARENT); return fl_gc; } // make X drawing go into this window (called by subclass flush() impl.) void Fl_Window::make_current() { fl_GetDC(fl_xid(this)); #if USE_COLORMAP // Windows maintains a hardware and software color palette; the // SelectPalette() call updates the current soft->hard mapping // for all drawing calls, so we must select it here before any // code does any drawing... fl_select_palette(); #endif // USE_COLORMAP current_ = this; fl_clip_region(0); } // // End of "$Id: Fl_win32.cxx 109 2003-12-24 10:38:34Z ajapted $". // glbsp-2.24-source/patches/fltk_win32/config.h0000644000175000017500000001067510514052727020367 0ustar aaptedaapted/* * "$Id: config.h 109 2003-12-24 10:38:34Z ajapted $" * * Configuration file for the Fast Light Tool Kit (FLTK). * * Copyright 1998-2003 by Bill Spitzak and others. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. * * Please report all bugs and problems to "FLTK-bugs@fltk.org". */ /* * Where to find files... */ #define FLTK_DATADIR "C:/FLTK" #define FLTK_DOCDIR "C:/FLTK/DOC" /* * BORDER_WIDTH: * * Thickness of FL_UP_BOX and FL_DOWN_BOX. Current 1,2, and 3 are * supported. * * 3 is the historic FLTK look. * 2 is the default and looks like Microsoft Windows, KDE, and Qt. * 1 is a plausible future evolution... * * Note that this may be simulated at runtime by redefining the boxtypes * using Fl::set_boxtype(). */ #define BORDER_WIDTH 2 /* * HAVE_GL: * * Do you have OpenGL? Set this to 0 if you don't have or plan to use * OpenGL, and FLTK will be smaller. * * In order to set to 1 you will need to obtain the OpenGL header and * library files. Consult the README.win32 file for further details. */ #define HAVE_GL 0 /* * HAVE_GL_GLU_H: * * Do you have the OpenGL Utility Library header file? * (many broken Mesa RPMs do not...) */ #define HAVE_GL_GLU_H 0 /* * USE_COLORMAP: * * Setting this to zero will save a good deal of code (especially for * fl_draw_image), but FLTK will only work on TrueColor visuals. */ #define USE_COLORMAP 1 /* * USE_XFT * * Use the new Xft library to draw anti-aliased text. */ #define USE_XFT 0 /* * HAVE_XDBE: * * Do we have the X double-buffer extension? */ #define HAVE_XDBE 0 /* * USE_XDBE: * * Actually try to use the double-buffer extension? Set this to zero * disable use of XDBE without breaking the list_visuals program. */ #define USE_XDBE HAVE_XDBE /* * HAVE_OVERLAY: * * Use the X overlay extension? FLTK will try to use an overlay * visual for Fl_Overlay_Window, the Gl_Window overlay, and for the * menus. Setting this to zero will remove a substantial amount of * code from FLTK. Overlays have only been tested on SGI servers! */ #define HAVE_OVERLAY 0 /* * HAVE_GL_OVERLAY: * * It is possible your GL has an overlay even if X does not. If so, * set this to 1. */ #define HAVE_GL_OVERLAY HAVE_OVERLAY /* * WORDS_BIGENDIAN: * * Byte order of your machine: 1 = big-endian, 0 = little-endian. */ #define WORDS_BIGENDIAN 0 /* * U16, U32, U64: * * Types used by fl_draw_image. One of U32 or U64 must be defined. * U16 is optional but FLTK will work better with it! */ #define U16 unsigned short #define U32 unsigned /* #undef U64 */ /* * HAVE_DIRENT_H, HAVE_SYS_NDIR_H, HAVE_SYS_DIR_H, HAVE_NDIR_H, HAVE_SCANDIR: * * Where is (used only by fl_file_chooser and scandir). */ #define HAVE_DIRENT_H 1 /* #undef HAVE_SYS_NDIR_H */ /* #undef HAVE_SYS_DIR_H */ /* #undef HAVE_NDIR_H */ /* #undef HAVE_SCANDIR */ /* * Possibly missing sprintf-style functions: */ /* #undef HAVE_VSNPRINTF */ /* #undef HAVE_SNPRINTF */ /* * String functions... */ /* #undef HAVE_STRINGS_H */ #define HAVE_STRCASECMP 1 /* #undef HAVE_STRLCAT */ /* #undef HAVE_STRLCPY */ /* * HAVE_SYS_SELECT_H: * * Whether or not select() call has its own header file. */ /* #undef HAVE_SYS_SELECT_H */ /* * USE_POLL: * * Use poll() if we don't have select(). */ #define USE_POLL 0 /* * Do we have various image libraries? */ /* #undef HAVE_LIBPNG */ /* #undef HAVE_LIBZ */ /* #undef HAVE_LIBJPEG */ /* * Which header file do we include for libpng? */ /* #undef HAVE_PNG_H */ /* #undef HAVE_LIBPNG_PNG_H */ /* * Do we have the png_xyz() functions? */ /* #undef HAVE_PNG_GET_VALID */ /* #undef HAVE_PNG_SET_TRNS_TO_ALPHA */ /* * Do we have POSIX threading? */ /* #undef HAVE_PTHREAD */ /* #undef HAVE_PTHREAD_H */ /* * End of "$Id: config.h 109 2003-12-24 10:38:34Z ajapted $". */ glbsp-2.24-source/patches/FLTK_OSX.diff0000644000175000017500000000052010514052727017076 0ustar aaptedaapteddiff -u -r fltk-1.1.4-orig/src/Makefile fltk-1.1.4/src/Makefile --- fltk-1.1.4-orig/src/Makefile Sat Dec 6 21:48:58 2003 +++ fltk-1.1.4/src/Makefile Sat Dec 6 21:52:02 2003 @@ -55,6 +55,7 @@ Fl_Menu.cxx \ Fl_Menu_.cxx \ Fl_Menu_Bar.cxx \ + Fl_Sys_Menu_Bar.cxx \ Fl_Menu_Button.cxx \ Fl_Menu_Window.cxx \ Fl_Menu_add.cxx \ glbsp-2.24-source/src/0000755000175000017500000000000010652037721014116 5ustar aaptedaaptedglbsp-2.24-source/src/analyze.c0000644000175000017500000006133710650662641015742 0ustar aaptedaapted//------------------------------------------------------------------------ // ANALYZE : Analyzing level structures //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "system.h" #include #include #include #include #include #include #include #include #include "analyze.h" #include "blockmap.h" #include "level.h" #include "node.h" #include "reject.h" #include "seg.h" #include "structs.h" #include "util.h" #include "wad.h" #define DEBUG_WALLTIPS 0 #define DEBUG_POLYOBJ 0 #define DEBUG_WINDOW_FX 0 #define POLY_BOX_SZ 10 // stuff needed from level.c (this file closely related) extern vertex_t ** lev_vertices; extern linedef_t ** lev_linedefs; extern sidedef_t ** lev_sidedefs; extern sector_t ** lev_sectors; extern boolean_g lev_doing_normal; /* ----- polyobj handling ----------------------------- */ static void MarkPolyobjSector(sector_t *sector) { int i; if (! sector) return; # if DEBUG_POLYOBJ PrintDebug(" Marking SECTOR %d\n", sector->index); # endif /* already marked ? */ if (sector->has_polyobj) return; /* mark all lines of this sector as precious, to prevent the sector * from being split. */ sector->has_polyobj = TRUE; for (i = 0; i < num_linedefs; i++) { linedef_t *L = lev_linedefs[i]; if ((L->right && L->right->sector == sector) || (L->left && L->left->sector == sector)) { L->is_precious = TRUE; } } } static void MarkPolyobjPoint(float_g x, float_g y) { int i; int inside_count = 0; float_g best_dist = 999999; linedef_t *best_match = NULL; sector_t *sector = NULL; float_g x1, y1; float_g x2, y2; // -AJA- First we handle the "awkward" cases where the polyobj sits // directly on a linedef or even a vertex. We check all lines // that intersect a small box around the spawn point. int bminx = (int) (x - POLY_BOX_SZ); int bminy = (int) (y - POLY_BOX_SZ); int bmaxx = (int) (x + POLY_BOX_SZ); int bmaxy = (int) (y + POLY_BOX_SZ); for (i = 0; i < num_linedefs; i++) { linedef_t *L = lev_linedefs[i]; if (CheckLinedefInsideBox(bminx, bminy, bmaxx, bmaxy, (int) L->start->x, (int) L->start->y, (int) L->end->x, (int) L->end->y)) { # if DEBUG_POLYOBJ PrintDebug(" Touching line was %d\n", L->index); # endif if (L->left) MarkPolyobjSector(L->left->sector); if (L->right) MarkPolyobjSector(L->right->sector); inside_count++; } } if (inside_count > 0) return; // -AJA- Algorithm is just like in DEU: we cast a line horizontally // from the given (x,y) position and find all linedefs that // intersect it, choosing the one with the closest distance. // If the point is sitting directly on a (two-sided) line, // then we mark the sectors on both sides. for (i = 0; i < num_linedefs; i++) { linedef_t *L = lev_linedefs[i]; float_g x_cut; x1 = L->start->x; y1 = L->start->y; x2 = L->end->x; y2 = L->end->y; /* check vertical range */ if (fabs(y2 - y1) < DIST_EPSILON) continue; if ((y > (y1 + DIST_EPSILON) && y > (y2 + DIST_EPSILON)) || (y < (y1 - DIST_EPSILON) && y < (y2 - DIST_EPSILON))) continue; x_cut = x1 + (x2 - x1) * (y - y1) / (y2 - y1) - x; if (fabs(x_cut) < fabs(best_dist)) { /* found a closer linedef */ best_match = L; best_dist = x_cut; } } if (! best_match) { PrintWarn("Bad polyobj thing at (%1.0f,%1.0f).\n", x, y); return; } y1 = best_match->start->y; y2 = best_match->end->y; # if DEBUG_POLYOBJ PrintDebug(" Closest line was %d Y=%1.0f..%1.0f (dist=%1.1f)\n", best_match->index, y1, y2, best_dist); # endif /* sanity check: shouldn't be directly on the line */ # if DEBUG_POLYOBJ if (fabs(best_dist) < DIST_EPSILON) { PrintDebug(" Polyobj FAILURE: directly on the line (%d)\n", best_match->index); } # endif /* check orientation of line, to determine which side the polyobj is * actually on. */ if ((y1 > y2) == (best_dist > 0)) sector = best_match->right ? best_match->right->sector : NULL; else sector = best_match->left ? best_match->left->sector : NULL; # if DEBUG_POLYOBJ PrintDebug(" Sector %d contains the polyobj.\n", sector ? sector->index : -1); # endif if (! sector) { PrintWarn("Invalid Polyobj thing at (%1.0f,%1.0f).\n", x, y); return; } MarkPolyobjSector(sector); } // // DetectPolyobjSectors // // Based on code courtesy of Janis Legzdinsh. // void DetectPolyobjSectors(void) { int i; int hexen_style; // -JL- There's a conflict between Hexen polyobj thing types and Doom thing // types. In Doom type 3001 is for Imp and 3002 for Demon. To solve // this problem, first we are going through all lines to see if the // level has any polyobjs. If found, we also must detect what polyobj // thing types are used - Hexen ones or ZDoom ones. That's why we // are going through all things searching for ZDoom polyobj thing // types. If any found, we assume that ZDoom polyobj thing types are // used, otherwise Hexen polyobj thing types are used. // -JL- First go through all lines to see if level contains any polyobjs for (i = 0; i < num_linedefs; i++) { linedef_t *L = lev_linedefs[i]; if (L->type == HEXTYPE_POLY_START || L->type == HEXTYPE_POLY_EXPLICIT) break; } if (i == num_linedefs) { // -JL- No polyobjs in this level return; } // -JL- Detect what polyobj thing types are used - Hexen ones or ZDoom ones hexen_style = TRUE; for (i = 0; i < num_things; i++) { thing_t *T = LookupThing(i); if (T->type == ZDOOM_PO_SPAWN_TYPE || T->type == ZDOOM_PO_SPAWNCRUSH_TYPE) { // -JL- A ZDoom style polyobj thing found hexen_style = FALSE; break; } } # if DEBUG_POLYOBJ PrintDebug("Using %s style polyobj things\n", hexen_style ? "HEXEN" : "ZDOOM"); # endif for (i = 0; i < num_things; i++) { thing_t *T = LookupThing(i); float_g x = (float_g) T->x; float_g y = (float_g) T->y; // ignore everything except polyobj start spots if (hexen_style) { // -JL- Hexen style polyobj things if (T->type != PO_SPAWN_TYPE && T->type != PO_SPAWNCRUSH_TYPE) continue; } else { // -JL- ZDoom style polyobj things if (T->type != ZDOOM_PO_SPAWN_TYPE && T->type != ZDOOM_PO_SPAWNCRUSH_TYPE) continue; } # if DEBUG_POLYOBJ PrintDebug("Thing %d at (%1.0f,%1.0f) is a polyobj spawner.\n", i, x, y); # endif MarkPolyobjPoint(x, y); } } /* ----- analysis routines ----------------------------- */ static int VertexCompare(const void *p1, const void *p2) { int vert1 = ((const uint16_g *) p1)[0]; int vert2 = ((const uint16_g *) p2)[0]; vertex_t *A = lev_vertices[vert1]; vertex_t *B = lev_vertices[vert2]; if (vert1 == vert2) return 0; if ((int)A->x != (int)B->x) return (int)A->x - (int)B->x; return (int)A->y - (int)B->y; } static int SidedefCompare(const void *p1, const void *p2) { int comp; int side1 = ((const uint16_g *) p1)[0]; int side2 = ((const uint16_g *) p2)[0]; sidedef_t *A = lev_sidedefs[side1]; sidedef_t *B = lev_sidedefs[side2]; if (side1 == side2) return 0; // don't merge sidedefs on special lines if (A->on_special || B->on_special) return side1 - side2; if (A->sector != B->sector) { if (A->sector == NULL) return -1; if (B->sector == NULL) return +1; return (A->sector->index - B->sector->index); } if ((int)A->x_offset != (int)B->x_offset) return A->x_offset - (int)B->x_offset; if ((int)A->y_offset != B->y_offset) return (int)A->y_offset - (int)B->y_offset; // compare textures comp = memcmp(A->upper_tex, B->upper_tex, sizeof(A->upper_tex)); if (comp) return comp; comp = memcmp(A->lower_tex, B->lower_tex, sizeof(A->lower_tex)); if (comp) return comp; comp = memcmp(A->mid_tex, B->mid_tex, sizeof(A->mid_tex)); if (comp) return comp; // sidedefs must be the same return 0; } void DetectDuplicateVertices(void) { int i; uint16_g *array = UtilCalloc(num_vertices * sizeof(uint16_g)); DisplayTicker(); // sort array of indices for (i=0; i < num_vertices; i++) array[i] = i; qsort(array, num_vertices, sizeof(uint16_g), VertexCompare); // now mark them off for (i=0; i < num_vertices - 1; i++) { // duplicate ? if (VertexCompare(array + i, array + i+1) == 0) { vertex_t *A = lev_vertices[array[i]]; vertex_t *B = lev_vertices[array[i+1]]; // found a duplicate ! B->equiv = A->equiv ? A->equiv : A; } } UtilFree(array); } void DetectDuplicateSidedefs(void) { int i; uint16_g *array = UtilCalloc(num_sidedefs * sizeof(uint16_g)); DisplayTicker(); // sort array of indices for (i=0; i < num_sidedefs; i++) array[i] = i; qsort(array, num_sidedefs, sizeof(uint16_g), SidedefCompare); // now mark them off for (i=0; i < num_sidedefs - 1; i++) { // duplicate ? if (SidedefCompare(array + i, array + i+1) == 0) { sidedef_t *A = lev_sidedefs[array[i]]; sidedef_t *B = lev_sidedefs[array[i+1]]; // found a duplicate ! B->equiv = A->equiv ? A->equiv : A; } } UtilFree(array); } void PruneLinedefs(void) { int i; int new_num; DisplayTicker(); // scan all linedefs for (i=0, new_num=0; i < num_linedefs; i++) { linedef_t *L = lev_linedefs[i]; // handle duplicated vertices while (L->start->equiv) { L->start->ref_count--; L->start = L->start->equiv; L->start->ref_count++; } while (L->end->equiv) { L->end->ref_count--; L->end = L->end->equiv; L->end->ref_count++; } // handle duplicated sidedefs while (L->right && L->right->equiv) { L->right->ref_count--; L->right = L->right->equiv; L->right->ref_count++; } while (L->left && L->left->equiv) { L->left->ref_count--; L->left = L->left->equiv; L->left->ref_count++; } // remove zero length lines if (L->zero_len) { L->start->ref_count--; L->end->ref_count--; UtilFree(L); continue; } L->index = new_num; lev_linedefs[new_num++] = L; } if (new_num < num_linedefs) { PrintVerbose("Pruned %d zero-length linedefs\n", num_linedefs - new_num); num_linedefs = new_num; } if (new_num == 0) FatalError("Couldn't find any Linedefs"); } void PruneVertices(void) { int i; int new_num; int unused = 0; DisplayTicker(); // scan all vertices for (i=0, new_num=0; i < num_vertices; i++) { vertex_t *V = lev_vertices[i]; if (V->ref_count < 0) InternalError("Vertex %d ref_count is %d", i, V->ref_count); if (V->ref_count == 0) { if (V->equiv == NULL) unused++; UtilFree(V); continue; } V->index = new_num; lev_vertices[new_num++] = V; } if (new_num < num_vertices) { int dup_num = num_vertices - new_num - unused; if (unused > 0) PrintVerbose("Pruned %d unused vertices " "(this is normal if the nodes were built before)\n", unused); if (dup_num > 0) PrintVerbose("Pruned %d duplicate vertices\n", dup_num); num_vertices = new_num; } if (new_num == 0) FatalError("Couldn't find any Vertices"); num_normal_vert = num_vertices; } void PruneSidedefs(void) { int i; int new_num; int unused = 0; DisplayTicker(); // scan all sidedefs for (i=0, new_num=0; i < num_sidedefs; i++) { sidedef_t *S = lev_sidedefs[i]; if (S->ref_count < 0) InternalError("Sidedef %d ref_count is %d", i, S->ref_count); if (S->ref_count == 0) { if (S->sector) S->sector->ref_count--; if (S->equiv == NULL) unused++; UtilFree(S); continue; } S->index = new_num; lev_sidedefs[new_num++] = S; } if (new_num < num_sidedefs) { int dup_num = num_sidedefs - new_num - unused; if (unused > 0) PrintVerbose("Pruned %d unused sidedefs\n", unused); if (dup_num > 0) PrintVerbose("Pruned %d duplicate sidedefs\n", dup_num); num_sidedefs = new_num; } if (new_num == 0) FatalError("Couldn't find any Sidedefs"); } void PruneSectors(void) { int i; int new_num; DisplayTicker(); // scan all sectors for (i=0, new_num=0; i < num_sectors; i++) { sector_t *S = lev_sectors[i]; if (S->ref_count < 0) InternalError("Sector %d ref_count is %d", i, S->ref_count); if (S->ref_count == 0) { UtilFree(S); continue; } S->index = new_num; lev_sectors[new_num++] = S; } if (new_num < num_sectors) { PrintVerbose("Pruned %d unused sectors\n", num_sectors - new_num); num_sectors = new_num; } if (new_num == 0) FatalError("Couldn't find any Sectors"); } static INLINE_G int LineVertexLowest(const linedef_t *L) { // returns the "lowest" vertex (normally the left-most, but if the // line is vertical, then the bottom-most) => 0 for start, 1 for end. return ((int)L->start->x < (int)L->end->x || ((int)L->start->x == (int)L->end->x && (int)L->start->y < (int)L->end->y)) ? 0 : 1; } static int LineStartCompare(const void *p1, const void *p2) { int line1 = ((const int *) p1)[0]; int line2 = ((const int *) p2)[0]; linedef_t *A = lev_linedefs[line1]; linedef_t *B = lev_linedefs[line2]; vertex_t *C; vertex_t *D; if (line1 == line2) return 0; // determine left-most vertex of each line C = LineVertexLowest(A) ? A->end : A->start; D = LineVertexLowest(B) ? B->end : B->start; if ((int)C->x != (int)D->x) return (int)C->x - (int)D->x; return (int)C->y - (int)D->y; } static int LineEndCompare(const void *p1, const void *p2) { int line1 = ((const int *) p1)[0]; int line2 = ((const int *) p2)[0]; linedef_t *A = lev_linedefs[line1]; linedef_t *B = lev_linedefs[line2]; vertex_t *C; vertex_t *D; if (line1 == line2) return 0; // determine right-most vertex of each line C = LineVertexLowest(A) ? A->start : A->end; D = LineVertexLowest(B) ? B->start : B->end; if ((int)C->x != (int)D->x) return (int)C->x - (int)D->x; return (int)C->y - (int)D->y; } void DetectOverlappingLines(void) { // Algorithm: // Sort all lines by left-most vertex. // Overlapping lines will then be near each other in this set. // Note: does not detect partially overlapping lines. int i; int *array = UtilCalloc(num_linedefs * sizeof(int)); int count = 0; DisplayTicker(); // sort array of indices for (i=0; i < num_linedefs; i++) array[i] = i; qsort(array, num_linedefs, sizeof(int), LineStartCompare); for (i=0; i < num_linedefs - 1; i++) { int j; for (j = i+1; j < num_linedefs; j++) { if (LineStartCompare(array + i, array + j) != 0) break; if (LineEndCompare(array + i, array + j) == 0) { linedef_t *A = lev_linedefs[array[i]]; linedef_t *B = lev_linedefs[array[j]]; // found an overlap ! B->overlap = A->overlap ? A->overlap : A; count++; } } } if (count > 0) { PrintVerbose("Detected %d overlapped linedefs\n", count); } UtilFree(array); } static void CountWallTips(vertex_t *vert, int *one_sided, int *two_sided) { wall_tip_t *tip; *one_sided = 0; *two_sided = 0; for (tip=vert->tip_set; tip; tip=tip->next) { if (!tip->left || !tip->right) (*one_sided) += 1; else (*two_sided) += 1; } } void TestForWindowEffect(linedef_t *L) { // cast a line horizontally or vertically and see what we hit. // OUCH, we have to iterate over all linedefs. int i; float_g mx = (L->start->x + L->end->x) / 2.0; float_g my = (L->start->y + L->end->y) / 2.0; float_g dx = L->end->x - L->start->x; float_g dy = L->end->y - L->start->y; int cast_horiz = fabs(dx) < fabs(dy) ? 1 : 0; float_g back_dist = 999999.0; sector_t * back_open = NULL; int back_line = -1; float_g front_dist = 999999.0; sector_t * front_open = NULL; int front_line = -1; for (i=0; i < num_linedefs; i++) { linedef_t *N = lev_linedefs[i]; float_g dist; boolean_g is_front; sidedef_t *hit_side; float_g dx2, dy2; if (N == L || N->zero_len || N->overlap) continue; if (cast_horiz) { dx2 = N->end->x - N->start->x; dy2 = N->end->y - N->start->y; if (fabs(dy2) < DIST_EPSILON) continue; if ((MAX(N->start->y, N->end->y) < my - DIST_EPSILON) || (MIN(N->start->y, N->end->y) > my + DIST_EPSILON)) continue; dist = (N->start->x + (my - N->start->y) * dx2 / dy2) - mx; is_front = ((dy > 0) == (dist > 0)) ? TRUE : FALSE; dist = fabs(dist); if (dist < DIST_EPSILON) // too close (overlapping lines ?) continue; hit_side = ((dy > 0) ^ (dy2 > 0) ^ !is_front) ? N->right : N->left; } else /* vert */ { dx2 = N->end->x - N->start->x; dy2 = N->end->y - N->start->y; if (fabs(dx2) < DIST_EPSILON) continue; if ((MAX(N->start->x, N->end->x) < mx - DIST_EPSILON) || (MIN(N->start->x, N->end->x) > mx + DIST_EPSILON)) continue; dist = (N->start->y + (mx - N->start->x) * dy2 / dx2) - my; is_front = ((dx > 0) != (dist > 0)) ? TRUE : FALSE; dist = fabs(dist); hit_side = ((dx > 0) ^ (dx2 > 0) ^ !is_front) ? N->right : N->left; } if (dist < DIST_EPSILON) // too close (overlapping lines ?) continue; if (is_front) { if (dist < front_dist) { front_dist = dist; front_open = hit_side ? hit_side->sector : NULL; front_line = i; } } else { if (dist < back_dist) { back_dist = dist; back_open = hit_side ? hit_side->sector : NULL; back_line = i; } } } #if DEBUG_WINDOW_FX PrintDebug("back line: %d back dist: %1.1f back_open: %s\n", back_line, back_dist, back_open ? "OPEN" : "CLOSED"); PrintDebug("front line: %d front dist: %1.1f front_open: %s\n", front_line, front_dist, front_open ? "OPEN" : "CLOSED"); #endif if (back_open && front_open && L->right->sector == front_open) { L->window_effect = back_open; PrintMiniWarn("Linedef #%d seems to be a One-Sided Window (back faces sector #%d).\n", L->index, back_open->index); } } void DetectWindowEffects(void) { // Algorithm: // Scan the linedef list looking for possible candidates, // checking for an odd number of one-sided linedefs connected // to a single vertex. This idea courtesy of Graham Jackson. int i; int one_siders; int two_siders; for (i=0; i < num_linedefs; i++) { linedef_t *L = lev_linedefs[i]; if (L->two_sided || L->zero_len || L->overlap || !L->right) continue; CountWallTips(L->start, &one_siders, &two_siders); if ((one_siders % 2) == 1 && (one_siders + two_siders) > 1) { #if DEBUG_WINDOW_FX PrintDebug("FUNNY LINE %d : start vertex %d has odd number of one-siders\n", i, L->start->index); #endif TestForWindowEffect(L); continue; } CountWallTips(L->end, &one_siders, &two_siders); if ((one_siders % 2) == 1 && (one_siders + two_siders) > 1) { #if DEBUG_WINDOW_FX PrintDebug("FUNNY LINE %d : end vertex %d has odd number of one-siders\n", i, L->end->index); #endif TestForWindowEffect(L); } } } /* ----- vertex routines ------------------------------- */ static void VertexAddWallTip(vertex_t *vert, float_g dx, float_g dy, sector_t *left, sector_t *right) { wall_tip_t *tip = NewWallTip(); wall_tip_t *after; tip->angle = UtilComputeAngle(dx, dy); tip->left = left; tip->right = right; // find the correct place (order is increasing angle) for (after=vert->tip_set; after && after->next; after=after->next) { } while (after && tip->angle + ANG_EPSILON < after->angle) after = after->prev; // link it in tip->next = after ? after->next : vert->tip_set; tip->prev = after; if (after) { if (after->next) after->next->prev = tip; after->next = tip; } else { if (vert->tip_set) vert->tip_set->prev = tip; vert->tip_set = tip; } } void CalculateWallTips(void) { int i; DisplayTicker(); for (i=0; i < num_linedefs; i++) { linedef_t *line = lev_linedefs[i]; if (line->self_ref && cur_info->skip_self_ref) continue; float_g x1 = line->start->x; float_g y1 = line->start->y; float_g x2 = line->end->x; float_g y2 = line->end->y; sector_t *left = (line->left) ? line->left->sector : NULL; sector_t *right = (line->right) ? line->right->sector : NULL; VertexAddWallTip(line->start, x2-x1, y2-y1, left, right); VertexAddWallTip(line->end, x1-x2, y1-y2, right, left); } # if DEBUG_WALLTIPS for (i=0; i < num_vertices; i++) { vertex_t *vert = LookupVertex(i); wall_tip_t *tip; PrintDebug("WallTips for vertex %d:\n", i); for (tip=vert->tip_set; tip; tip=tip->next) { PrintDebug(" Angle=%1.1f left=%d right=%d\n", tip->angle, tip->left ? tip->left->index : -1, tip->right ? tip->right->index : -1); } } # endif } // // NewVertexFromSplitSeg // vertex_t *NewVertexFromSplitSeg(seg_t *seg, float_g x, float_g y) { vertex_t *vert = NewVertex(); vert->x = x; vert->y = y; vert->ref_count = seg->partner ? 4 : 2; if (lev_doing_normal && cur_info->spec_version == 1) { vert->index = num_normal_vert; num_normal_vert++; } else { vert->index = num_gl_vert | IS_GL_VERTEX; num_gl_vert++; } // compute wall_tip info VertexAddWallTip(vert, -seg->pdx, -seg->pdy, seg->sector, seg->partner ? seg->partner->sector : NULL); VertexAddWallTip(vert, seg->pdx, seg->pdy, seg->partner ? seg->partner->sector : NULL, seg->sector); // create a duplex vertex if needed if (lev_doing_normal && cur_info->spec_version != 1) { vert->normal_dup = NewVertex(); vert->normal_dup->x = x; vert->normal_dup->y = y; vert->normal_dup->ref_count = vert->ref_count; vert->normal_dup->index = num_normal_vert; num_normal_vert++; } return vert; } // // NewVertexDegenerate // vertex_t *NewVertexDegenerate(vertex_t *start, vertex_t *end) { float_g dx = end->x - start->x; float_g dy = end->y - start->y; float_g dlen = UtilComputeDist(dx, dy); vertex_t *vert = NewVertex(); vert->ref_count = start->ref_count; if (lev_doing_normal) { vert->index = num_normal_vert; num_normal_vert++; } else { vert->index = num_gl_vert | IS_GL_VERTEX; num_gl_vert++; } // compute new coordinates vert->x = start->x; vert->y = start->x; if (dlen == 0) InternalError("NewVertexDegenerate: bad delta !"); dx /= dlen; dy /= dlen; while (I_ROUND(vert->x) == I_ROUND(start->x) && I_ROUND(vert->y) == I_ROUND(start->y)) { vert->x += dx; vert->y += dy; } return vert; } // // VertexCheckOpen // sector_t * VertexCheckOpen(vertex_t *vert, float_g dx, float_g dy) { wall_tip_t *tip; angle_g angle = UtilComputeAngle(dx, dy); // first check whether there's a wall_tip that lies in the exact // direction of the given direction (which is relative to the // vertex). for (tip=vert->tip_set; tip; tip=tip->next) { if (fabs(tip->angle - angle) < ANG_EPSILON || fabs(tip->angle - angle) > (360.0 - ANG_EPSILON)) { // yes, found one return NULL; } } // OK, now just find the first wall_tip whose angle is greater than // the angle we're interested in. Therefore we'll be on the RIGHT // side of that wall_tip. for (tip=vert->tip_set; tip; tip=tip->next) { if (angle + ANG_EPSILON < tip->angle) { // found it return tip->right; } if (! tip->next) { // no more tips, thus we must be on the LEFT side of the tip // with the largest angle. return tip->left; } } InternalError("Vertex %d has no tips !", vert->index); return FALSE; } glbsp-2.24-source/src/level.c0000644000175000017500000012035410651311203015363 0ustar aaptedaapted//------------------------------------------------------------------------ // LEVEL : Level structure read/write functions. //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // ZDBSP format support based on code (C) 2002,2003 Randy Heit // //------------------------------------------------------------------------ #include "system.h" #include #include #include #include #include #include #include #include #include "analyze.h" #include "blockmap.h" #include "level.h" #include "node.h" #include "reject.h" #include "seg.h" #include "structs.h" #include "util.h" #include "wad.h" #define DEBUG_LOAD 0 #define DEBUG_BSP 0 #define ALLOC_BLKNUM 1024 // per-level variables boolean_g lev_doing_normal; boolean_g lev_doing_hexen; static boolean_g lev_force_v3; static boolean_g lev_force_v5; #define LEVELARRAY(TYPE, BASEVAR, NUMVAR) \ TYPE ** BASEVAR = NULL; \ int NUMVAR = 0; LEVELARRAY(vertex_t, lev_vertices, num_vertices) LEVELARRAY(linedef_t, lev_linedefs, num_linedefs) LEVELARRAY(sidedef_t, lev_sidedefs, num_sidedefs) LEVELARRAY(sector_t, lev_sectors, num_sectors) LEVELARRAY(thing_t, lev_things, num_things) static LEVELARRAY(seg_t, segs, num_segs) static LEVELARRAY(subsec_t, subsecs, num_subsecs) static LEVELARRAY(node_t, nodes, num_nodes) static LEVELARRAY(node_t, stale_nodes,num_stale_nodes) static LEVELARRAY(wall_tip_t,wall_tips, num_wall_tips) int num_normal_vert = 0; int num_gl_vert = 0; int num_complete_seg = 0; /* ----- allocation routines ---------------------------- */ #define ALLIGATOR(TYPE, BASEVAR, NUMVAR) \ { \ if ((NUMVAR % ALLOC_BLKNUM) == 0) \ { \ BASEVAR = UtilRealloc(BASEVAR, (NUMVAR + ALLOC_BLKNUM) * \ sizeof(TYPE *)); \ } \ BASEVAR[NUMVAR] = (TYPE *) UtilCalloc(sizeof(TYPE)); \ NUMVAR += 1; \ return BASEVAR[NUMVAR - 1]; \ } vertex_t *NewVertex(void) ALLIGATOR(vertex_t, lev_vertices, num_vertices) linedef_t *NewLinedef(void) ALLIGATOR(linedef_t, lev_linedefs, num_linedefs) sidedef_t *NewSidedef(void) ALLIGATOR(sidedef_t, lev_sidedefs, num_sidedefs) sector_t *NewSector(void) ALLIGATOR(sector_t, lev_sectors, num_sectors) thing_t *NewThing(void) ALLIGATOR(thing_t, lev_things, num_things) seg_t *NewSeg(void) ALLIGATOR(seg_t, segs, num_segs) subsec_t *NewSubsec(void) ALLIGATOR(subsec_t, subsecs, num_subsecs) node_t *NewNode(void) ALLIGATOR(node_t, nodes, num_nodes) node_t *NewStaleNode(void) ALLIGATOR(node_t, stale_nodes, num_stale_nodes) wall_tip_t *NewWallTip(void) ALLIGATOR(wall_tip_t, wall_tips, num_wall_tips) /* ----- free routines ---------------------------- */ #define FREEMASON(TYPE, BASEVAR, NUMVAR) \ { \ int i; \ for (i=0; i < NUMVAR; i++) \ UtilFree(BASEVAR[i]); \ if (BASEVAR) \ UtilFree(BASEVAR); \ BASEVAR = NULL; NUMVAR = 0; \ } void FreeVertices(void) FREEMASON(vertex_t, lev_vertices, num_vertices) void FreeLinedefs(void) FREEMASON(linedef_t, lev_linedefs, num_linedefs) void FreeSidedefs(void) FREEMASON(sidedef_t, lev_sidedefs, num_sidedefs) void FreeSectors(void) FREEMASON(sector_t, lev_sectors, num_sectors) void FreeThings(void) FREEMASON(thing_t, lev_things, num_things) void FreeSegs(void) FREEMASON(seg_t, segs, num_segs) void FreeSubsecs(void) FREEMASON(subsec_t, subsecs, num_subsecs) void FreeNodes(void) FREEMASON(node_t, nodes, num_nodes) void FreeStaleNodes(void) FREEMASON(node_t, stale_nodes, num_stale_nodes) void FreeWallTips(void) FREEMASON(wall_tip_t, wall_tips, num_wall_tips) /* ----- lookup routines ------------------------------ */ #define LOOKERUPPER(BASEVAR, NUMVAR, NAMESTR) \ { \ if (index < 0 || index >= NUMVAR) \ FatalError("No such %s number #%d", NAMESTR, index); \ \ return BASEVAR[index]; \ } vertex_t *LookupVertex(int index) LOOKERUPPER(lev_vertices, num_vertices, "vertex") linedef_t *LookupLinedef(int index) LOOKERUPPER(lev_linedefs, num_linedefs, "linedef") sidedef_t *LookupSidedef(int index) LOOKERUPPER(lev_sidedefs, num_sidedefs, "sidedef") sector_t *LookupSector(int index) LOOKERUPPER(lev_sectors, num_sectors, "sector") thing_t *LookupThing(int index) LOOKERUPPER(lev_things, num_things, "thing") seg_t *LookupSeg(int index) LOOKERUPPER(segs, num_segs, "seg") subsec_t *LookupSubsec(int index) LOOKERUPPER(subsecs, num_subsecs, "subsector") node_t *LookupNode(int index) LOOKERUPPER(nodes, num_nodes, "node") node_t *LookupStaleNode(int index) LOOKERUPPER(stale_nodes, num_stale_nodes, "stale_node") /* ----- reading routines ------------------------------ */ // // CheckForNormalNodes // int CheckForNormalNodes(void) { lump_t *lump; /* Note: an empty NODES lump can be valid */ if (FindLevelLump("NODES") == NULL) return FALSE; lump = FindLevelLump("SEGS"); if (! lump || lump->length == 0 || CheckLevelLumpZero(lump)) return FALSE; lump = FindLevelLump("SSECTORS"); if (! lump || lump->length == 0 || CheckLevelLumpZero(lump)) return FALSE; return TRUE; } // // GetVertices // void GetVertices(void) { int i, count=-1; raw_vertex_t *raw; lump_t *lump = FindLevelLump("VERTEXES"); if (lump) count = lump->length / sizeof(raw_vertex_t); DisplayTicker(); # if DEBUG_LOAD PrintDebug("GetVertices: num = %d\n", count); # endif if (!lump || count == 0) FatalError("Couldn't find any Vertices"); raw = (raw_vertex_t *) lump->data; for (i=0; i < count; i++, raw++) { vertex_t *vert = NewVertex(); vert->x = (float_g) SINT16(raw->x); vert->y = (float_g) SINT16(raw->y); vert->index = i; } num_normal_vert = num_vertices; num_gl_vert = 0; num_complete_seg = 0; } // // GetSectors // void GetSectors(void) { int i, count=-1; raw_sector_t *raw; lump_t *lump = FindLevelLump("SECTORS"); if (lump) count = lump->length / sizeof(raw_sector_t); if (!lump || count == 0) FatalError("Couldn't find any Sectors"); DisplayTicker(); # if DEBUG_LOAD PrintDebug("GetSectors: num = %d\n", count); # endif raw = (raw_sector_t *) lump->data; for (i=0; i < count; i++, raw++) { sector_t *sector = NewSector(); sector->floor_h = SINT16(raw->floor_h); sector->ceil_h = SINT16(raw->ceil_h); memcpy(sector->floor_tex, raw->floor_tex, sizeof(sector->floor_tex)); memcpy(sector->ceil_tex, raw->ceil_tex, sizeof(sector->ceil_tex)); sector->light = UINT16(raw->light); sector->special = UINT16(raw->special); sector->tag = SINT16(raw->tag); sector->coalesce = (sector->tag >= 900 && sector->tag < 1000) ? TRUE : FALSE; /* sector indices never change */ sector->index = i; sector->warned_facing = -1; /* Note: rej_* fields are handled completely in reject.c */ } } // // GetThings // void GetThings(void) { int i, count=-1; raw_thing_t *raw; lump_t *lump = FindLevelLump("THINGS"); if (lump) count = lump->length / sizeof(raw_thing_t); if (!lump || count == 0) { // Note: no error if no things exist, even though technically a map // will be unplayable without the player starts. PrintWarn("Couldn't find any Things!\n"); return; } DisplayTicker(); # if DEBUG_LOAD PrintDebug("GetThings: num = %d\n", count); # endif raw = (raw_thing_t *) lump->data; for (i=0; i < count; i++, raw++) { thing_t *thing = NewThing(); thing->x = SINT16(raw->x); thing->y = SINT16(raw->y); thing->type = UINT16(raw->type); thing->options = UINT16(raw->options); thing->index = i; } } // // GetThingsHexen // void GetThingsHexen(void) { int i, count=-1; raw_hexen_thing_t *raw; lump_t *lump = FindLevelLump("THINGS"); if (lump) count = lump->length / sizeof(raw_hexen_thing_t); if (!lump || count == 0) { // Note: no error if no things exist, even though technically a map // will be unplayable without the player starts. PrintWarn("Couldn't find any Things!\n"); return; } DisplayTicker(); # if DEBUG_LOAD PrintDebug("GetThingsHexen: num = %d\n", count); # endif raw = (raw_hexen_thing_t *) lump->data; for (i=0; i < count; i++, raw++) { thing_t *thing = NewThing(); thing->x = SINT16(raw->x); thing->y = SINT16(raw->y); thing->type = UINT16(raw->type); thing->options = UINT16(raw->options); thing->index = i; } } // // GetSidedefs // void GetSidedefs(void) { int i, count=-1; raw_sidedef_t *raw; lump_t *lump = FindLevelLump("SIDEDEFS"); if (lump) count = lump->length / sizeof(raw_sidedef_t); if (!lump || count == 0) FatalError("Couldn't find any Sidedefs"); DisplayTicker(); # if DEBUG_LOAD PrintDebug("GetSidedefs: num = %d\n", count); # endif raw = (raw_sidedef_t *) lump->data; for (i=0; i < count; i++, raw++) { sidedef_t *side = NewSidedef(); side->sector = (SINT16(raw->sector) == -1) ? NULL : LookupSector(UINT16(raw->sector)); if (side->sector) side->sector->ref_count++; side->x_offset = SINT16(raw->x_offset); side->y_offset = SINT16(raw->y_offset); memcpy(side->upper_tex, raw->upper_tex, sizeof(side->upper_tex)); memcpy(side->lower_tex, raw->lower_tex, sizeof(side->lower_tex)); memcpy(side->mid_tex, raw->mid_tex, sizeof(side->mid_tex)); /* sidedef indices never change */ side->index = i; } } static INLINE_G sidedef_t *SafeLookupSidedef(uint16_g num) { if (num == 0xFFFF) return NULL; if ((int)num >= num_sidedefs && (sint16_g)(num) < 0) return NULL; return LookupSidedef(num); } // // GetLinedefs // void GetLinedefs(void) { int i, count=-1; raw_linedef_t *raw; lump_t *lump = FindLevelLump("LINEDEFS"); if (lump) count = lump->length / sizeof(raw_linedef_t); if (!lump || count == 0) FatalError("Couldn't find any Linedefs"); DisplayTicker(); # if DEBUG_LOAD PrintDebug("GetLinedefs: num = %d\n", count); # endif raw = (raw_linedef_t *) lump->data; for (i=0; i < count; i++, raw++) { linedef_t *line; vertex_t *start = LookupVertex(UINT16(raw->start)); vertex_t *end = LookupVertex(UINT16(raw->end)); start->ref_count++; end->ref_count++; line = NewLinedef(); line->start = start; line->end = end; /* check for zero-length line */ line->zero_len = (fabs(start->x - end->x) < DIST_EPSILON) && (fabs(start->y - end->y) < DIST_EPSILON); line->flags = UINT16(raw->flags); line->type = UINT16(raw->type); line->tag = SINT16(raw->tag); line->two_sided = (line->flags & LINEFLAG_TWO_SIDED) ? TRUE : FALSE; line->is_precious = (line->tag >= 900 && line->tag < 1000) ? TRUE : FALSE; line->right = SafeLookupSidedef(UINT16(raw->sidedef1)); line->left = SafeLookupSidedef(UINT16(raw->sidedef2)); if (line->right) { line->right->ref_count++; line->right->on_special |= (line->type > 0) ? 1 : 0; } if (line->left) { line->left->ref_count++; line->left->on_special |= (line->type > 0) ? 1 : 0; } line->self_ref = (line->left && line->right && (line->left->sector == line->right->sector)); line->index = i; } } // // GetLinedefsHexen // void GetLinedefsHexen(void) { int i, j, count=-1; raw_hexen_linedef_t *raw; lump_t *lump = FindLevelLump("LINEDEFS"); if (lump) count = lump->length / sizeof(raw_hexen_linedef_t); if (!lump || count == 0) FatalError("Couldn't find any Linedefs"); DisplayTicker(); # if DEBUG_LOAD PrintDebug("GetLinedefsHexen: num = %d\n", count); # endif raw = (raw_hexen_linedef_t *) lump->data; for (i=0; i < count; i++, raw++) { linedef_t *line; vertex_t *start = LookupVertex(UINT16(raw->start)); vertex_t *end = LookupVertex(UINT16(raw->end)); start->ref_count++; end->ref_count++; line = NewLinedef(); line->start = start; line->end = end; // check for zero-length line line->zero_len = (fabs(start->x - end->x) < DIST_EPSILON) && (fabs(start->y - end->y) < DIST_EPSILON); line->flags = UINT16(raw->flags); line->type = UINT8(raw->type); line->tag = 0; /* read specials */ for (j=0; j < 5; j++) line->specials[j] = UINT8(raw->specials[j]); // -JL- Added missing twosided flag handling that caused a broken reject line->two_sided = (line->flags & LINEFLAG_TWO_SIDED) ? TRUE : FALSE; line->right = SafeLookupSidedef(UINT16(raw->sidedef1)); line->left = SafeLookupSidedef(UINT16(raw->sidedef2)); // -JL- Added missing sidedef handling that caused all sidedefs to be pruned if (line->right) { line->right->ref_count++; line->right->on_special |= (line->type > 0) ? 1 : 0; } if (line->left) { line->left->ref_count++; line->left->on_special |= (line->type > 0) ? 1 : 0; } line->self_ref = (line->left && line->right && (line->left->sector == line->right->sector)); line->index = i; } } // // GetStaleNodes // void GetStaleNodes(void) { int i, count=-1; raw_node_t *raw; lump_t *lump = FindLevelLump("NODES"); if (lump) count = lump->length / sizeof(raw_node_t); if (!lump || count < 5) return; DisplayTicker(); # if DEBUG_LOAD PrintDebug("GetStaleNodes: num = %d\n", count); # endif raw = (raw_node_t *) lump->data; /* must allocate all the nodes beforehand, since they contain * internal references to each other. */ for (i=0; i < count; i++) { NewStaleNode(); } for (i=0; i < count; i++, raw++) { node_t *nd = LookupStaleNode(i); nd->x = SINT16(raw->x); nd->y = SINT16(raw->y); nd->dx = SINT16(raw->dx); nd->dy = SINT16(raw->dy); nd->index = i; /* Note: we ignore the subsector references */ if ((UINT16(raw->right) & 0x8000U) == 0) { nd->r.node = LookupStaleNode(UINT16(raw->right)); } if ((UINT16(raw->left) & 0x8000U) == 0) { nd->l.node = LookupStaleNode(UINT16(raw->left)); } /* we also ignore the bounding boxes -- not needed */ } } static INLINE_G int TransformSegDist(const seg_t *seg) { float_g sx = seg->side ? seg->linedef->end->x : seg->linedef->start->x; float_g sy = seg->side ? seg->linedef->end->y : seg->linedef->start->y; return (int) ceil(UtilComputeDist(seg->start->x - sx, seg->start->y - sy)); } static INLINE_G int TransformAngle(angle_g angle) { int result; result = (int)(angle * 65536.0 / 360.0); if (result < 0) result += 65536; return (result & 0xFFFF); } static int SegCompare(const void *p1, const void *p2) { const seg_t *A = ((const seg_t **) p1)[0]; const seg_t *B = ((const seg_t **) p2)[0]; if (A->index < 0) InternalError("Seg %p never reached a subsector !", A); if (B->index < 0) InternalError("Seg %p never reached a subsector !", B); return (A->index - B->index); } /* ----- writing routines ------------------------------ */ static const uint8_g *lev_v2_magic = (uint8_g *) "gNd2"; static const uint8_g *lev_v3_magic = (uint8_g *) "gNd3"; static const uint8_g *lev_v5_magic = (uint8_g *) "gNd5"; void PutVertices(char *name, int do_gl) { int count, i; lump_t *lump; DisplayTicker(); if (do_gl) lump = CreateGLLump(name); else lump = CreateLevelLump(name); for (i=0, count=0; i < num_vertices; i++) { raw_vertex_t raw; vertex_t *vert = lev_vertices[i]; if ((do_gl ? 1 : 0) != ((vert->index & IS_GL_VERTEX) ? 1 : 0)) { continue; } raw.x = SINT16(I_ROUND(vert->x)); raw.y = SINT16(I_ROUND(vert->y)); AppendLevelLump(lump, &raw, sizeof(raw)); count++; } if (count != (do_gl ? num_gl_vert : num_normal_vert)) InternalError("PutVertices miscounted (%d != %d)", count, do_gl ? num_gl_vert : num_normal_vert); if (lev_doing_normal && ! do_gl && count > 65534) MarkHardFailure(LIMIT_VERTEXES); else if (count > 32767) MarkSoftFailure(do_gl ? LIMIT_GL_VERT : LIMIT_VERTEXES); } void PutV2Vertices(int do_v5) { int count, i; lump_t *lump; DisplayTicker(); lump = CreateGLLump("GL_VERT"); if (do_v5) AppendLevelLump(lump, lev_v5_magic, 4); else AppendLevelLump(lump, lev_v2_magic, 4); for (i=0, count=0; i < num_vertices; i++) { raw_v2_vertex_t raw; vertex_t *vert = lev_vertices[i]; if (! (vert->index & IS_GL_VERTEX)) continue; raw.x = SINT32((int)(vert->x * 65536.0)); raw.y = SINT32((int)(vert->y * 65536.0)); AppendLevelLump(lump, &raw, sizeof(raw)); count++; } if (count != num_gl_vert) InternalError("PutV2Vertices miscounted (%d != %d)", count, num_gl_vert); if (count > 32767) MarkSoftFailure(LIMIT_GL_VERT); } void PutSectors(void) { int i; lump_t *lump = CreateLevelLump("SECTORS"); DisplayTicker(); for (i=0; i < num_sectors; i++) { raw_sector_t raw; sector_t *sector = lev_sectors[i]; raw.floor_h = SINT16(sector->floor_h); raw.ceil_h = SINT16(sector->ceil_h); memcpy(raw.floor_tex, sector->floor_tex, sizeof(raw.floor_tex)); memcpy(raw.ceil_tex, sector->ceil_tex, sizeof(raw.ceil_tex)); raw.light = UINT16(sector->light); raw.special = UINT16(sector->special); raw.tag = SINT16(sector->tag); AppendLevelLump(lump, &raw, sizeof(raw)); } if (num_sectors > 65534) MarkHardFailure(LIMIT_SECTORS); else if (num_sectors > 32767) MarkSoftFailure(LIMIT_SECTORS); } void PutSidedefs(void) { int i; lump_t *lump = CreateLevelLump("SIDEDEFS"); DisplayTicker(); for (i=0; i < num_sidedefs; i++) { raw_sidedef_t raw; sidedef_t *side = lev_sidedefs[i]; raw.sector = (side->sector == NULL) ? SINT16(-1) : UINT16(side->sector->index); raw.x_offset = SINT16(side->x_offset); raw.y_offset = SINT16(side->y_offset); memcpy(raw.upper_tex, side->upper_tex, sizeof(raw.upper_tex)); memcpy(raw.lower_tex, side->lower_tex, sizeof(raw.lower_tex)); memcpy(raw.mid_tex, side->mid_tex, sizeof(raw.mid_tex)); AppendLevelLump(lump, &raw, sizeof(raw)); } if (num_sidedefs > 65534) MarkHardFailure(LIMIT_SIDEDEFS); else if (num_sidedefs > 32767) MarkSoftFailure(LIMIT_SIDEDEFS); } void PutLinedefs(void) { int i; lump_t *lump = CreateLevelLump("LINEDEFS"); DisplayTicker(); for (i=0; i < num_linedefs; i++) { raw_linedef_t raw; linedef_t *line = lev_linedefs[i]; raw.start = UINT16(line->start->index); raw.end = UINT16(line->end->index); raw.flags = UINT16(line->flags); raw.type = UINT16(line->type); raw.tag = SINT16(line->tag); raw.sidedef1 = line->right ? UINT16(line->right->index) : 0xFFFF; raw.sidedef2 = line->left ? UINT16(line->left->index) : 0xFFFF; AppendLevelLump(lump, &raw, sizeof(raw)); } if (num_linedefs > 65534) MarkHardFailure(LIMIT_LINEDEFS); else if (num_linedefs > 32767) MarkSoftFailure(LIMIT_LINEDEFS); } void PutLinedefsHexen(void) { int i, j; lump_t *lump = CreateLevelLump("LINEDEFS"); DisplayTicker(); for (i=0; i < num_linedefs; i++) { raw_hexen_linedef_t raw; linedef_t *line = lev_linedefs[i]; raw.start = UINT16(line->start->index); raw.end = UINT16(line->end->index); raw.flags = UINT16(line->flags); raw.type = UINT8(line->type); // write specials for (j=0; j < 5; j++) raw.specials[j] = UINT8(line->specials[j]); raw.sidedef1 = line->right ? UINT16(line->right->index) : 0xFFFF; raw.sidedef2 = line->left ? UINT16(line->left->index) : 0xFFFF; AppendLevelLump(lump, &raw, sizeof(raw)); } if (num_linedefs > 65534) MarkHardFailure(LIMIT_LINEDEFS); else if (num_linedefs > 32767) MarkSoftFailure(LIMIT_LINEDEFS); } static INLINE_G uint16_g VertexIndex16Bit(const vertex_t *v) { if (v->index & IS_GL_VERTEX) return (uint16_g) ((v->index & ~IS_GL_VERTEX) | 0x8000U); return (uint16_g) v->index; } static INLINE_G uint32_g VertexIndex32BitV5(const vertex_t *v) { if (v->index & IS_GL_VERTEX) return (uint32_g) ((v->index & ~IS_GL_VERTEX) | 0x80000000U); return (uint32_g) v->index; } void PutSegs(void) { int i, count; lump_t *lump = CreateLevelLump("SEGS"); DisplayTicker(); // sort segs into ascending index qsort(segs, num_segs, sizeof(seg_t *), SegCompare); for (i=0, count=0; i < num_segs; i++) { raw_seg_t raw; seg_t *seg = segs[i]; // ignore minisegs and degenerate segs if (! seg->linedef || seg->degenerate) continue; raw.start = UINT16(VertexIndex16Bit(seg->start)); raw.end = UINT16(VertexIndex16Bit(seg->end)); raw.angle = UINT16(TransformAngle(seg->p_angle)); raw.linedef = UINT16(seg->linedef->index); raw.flip = UINT16(seg->side); raw.dist = UINT16(TransformSegDist(seg)); AppendLevelLump(lump, &raw, sizeof(raw)); count++; # if DEBUG_BSP PrintDebug("PUT SEG: %04X Vert %04X->%04X Line %04X %s " "Angle %04X (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg->index, UINT16(raw.start), UINT16(raw.end), UINT16(raw.linedef), seg->side ? "L" : "R", UINT16(raw.angle), seg->start->x, seg->start->y, seg->end->x, seg->end->y); # endif } if (count != num_complete_seg) InternalError("PutSegs miscounted (%d != %d)", count, num_complete_seg); if (count > 65534) MarkHardFailure(LIMIT_SEGS); else if (count > 32767) MarkSoftFailure(LIMIT_SEGS); } void PutGLSegs(void) { int i, count; lump_t *lump = CreateGLLump("GL_SEGS"); DisplayTicker(); // sort segs into ascending index qsort(segs, num_segs, sizeof(seg_t *), SegCompare); for (i=0, count=0; i < num_segs; i++) { raw_gl_seg_t raw; seg_t *seg = segs[i]; // ignore degenerate segs if (seg->degenerate) continue; raw.start = UINT16(VertexIndex16Bit(seg->start)); raw.end = UINT16(VertexIndex16Bit(seg->end)); raw.side = UINT16(seg->side); if (seg->linedef) raw.linedef = UINT16(seg->linedef->index); else raw.linedef = UINT16(0xFFFF); if (seg->partner) raw.partner = UINT16(seg->partner->index); else raw.partner = UINT16(0xFFFF); AppendLevelLump(lump, &raw, sizeof(raw)); count++; # if DEBUG_BSP PrintDebug("PUT GL SEG: %04X Line %04X %s Partner %04X " "(%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg->index, UINT16(raw.linedef), seg->side ? "L" : "R", UINT16(raw.partner), seg->start->x, seg->start->y, seg->end->x, seg->end->y); # endif } if (count != num_complete_seg) InternalError("PutGLSegs miscounted (%d != %d)", count, num_complete_seg); if (count > 65534) InternalError("PutGLSegs with %d (> 65534) segs", count); else if (count > 32767) MarkSoftFailure(LIMIT_GL_SEGS); } void PutV3Segs(int do_v5) { int i, count; lump_t *lump = CreateGLLump("GL_SEGS"); if (! do_v5) AppendLevelLump(lump, lev_v3_magic, 4); DisplayTicker(); // sort segs into ascending index qsort(segs, num_segs, sizeof(seg_t *), SegCompare); for (i=0, count=0; i < num_segs; i++) { raw_v3_seg_t raw; seg_t *seg = segs[i]; // ignore degenerate segs if (seg->degenerate) continue; if (do_v5) { raw.start = UINT32(VertexIndex32BitV5(seg->start)); raw.end = UINT32(VertexIndex32BitV5(seg->end)); } else { raw.start = UINT32(seg->start->index); raw.end = UINT32(seg->end->index); } raw.side = UINT16(seg->side); if (seg->linedef) raw.linedef = UINT16(seg->linedef->index); else raw.linedef = UINT16(0xFFFF); if (seg->partner) raw.partner = UINT32(seg->partner->index); else raw.partner = UINT32(0xFFFFFFFF); AppendLevelLump(lump, &raw, sizeof(raw)); count++; # if DEBUG_BSP PrintDebug("PUT V3 SEG: %06X Line %04X %s Partner %06X " "(%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg->index, UINT16(raw.linedef), seg->side ? "L" : "R", UINT32(raw.partner), seg->start->x, seg->start->y, seg->end->x, seg->end->y); # endif } if (count != num_complete_seg) InternalError("PutGLSegs miscounted (%d != %d)", count, num_complete_seg); } void PutSubsecs(char *name, int do_gl) { int i; lump_t *lump; DisplayTicker(); if (do_gl) lump = CreateGLLump(name); else lump = CreateLevelLump(name); for (i=0; i < num_subsecs; i++) { raw_subsec_t raw; subsec_t *sub = subsecs[i]; raw.first = UINT16(sub->seg_list->index); raw.num = UINT16(sub->seg_count); AppendLevelLump(lump, &raw, sizeof(raw)); # if DEBUG_BSP PrintDebug("PUT SUBSEC %04X First %04X Num %04X\n", sub->index, UINT16(raw.first), UINT16(raw.num)); # endif } if (num_subsecs > 32767) MarkHardFailure(do_gl ? LIMIT_GL_SSECT : LIMIT_SSECTORS); } void PutV3Subsecs(int do_v5) { int i; lump_t *lump; DisplayTicker(); lump = CreateGLLump("GL_SSECT"); if (! do_v5) AppendLevelLump(lump, lev_v3_magic, 4); for (i=0; i < num_subsecs; i++) { raw_v3_subsec_t raw; subsec_t *sub = subsecs[i]; raw.first = UINT32(sub->seg_list->index); raw.num = UINT32(sub->seg_count); AppendLevelLump(lump, &raw, sizeof(raw)); # if DEBUG_BSP PrintDebug("PUT V3 SUBSEC %06X First %06X Num %06X\n", sub->index, UINT32(raw.first), UINT32(raw.num)); # endif } if (!do_v5 && num_subsecs > 32767) MarkHardFailure(LIMIT_GL_SSECT); } static int node_cur_index; static void PutOneNode(node_t *node, lump_t *lump) { raw_node_t raw; if (node->r.node) PutOneNode(node->r.node, lump); if (node->l.node) PutOneNode(node->l.node, lump); node->index = node_cur_index++; raw.x = SINT16(node->x); raw.y = SINT16(node->y); raw.dx = SINT16(node->dx / (node->too_long ? 2 : 1)); raw.dy = SINT16(node->dy / (node->too_long ? 2 : 1)); raw.b1.minx = SINT16(node->r.bounds.minx); raw.b1.miny = SINT16(node->r.bounds.miny); raw.b1.maxx = SINT16(node->r.bounds.maxx); raw.b1.maxy = SINT16(node->r.bounds.maxy); raw.b2.minx = SINT16(node->l.bounds.minx); raw.b2.miny = SINT16(node->l.bounds.miny); raw.b2.maxx = SINT16(node->l.bounds.maxx); raw.b2.maxy = SINT16(node->l.bounds.maxy); if (node->r.node) raw.right = UINT16(node->r.node->index); else if (node->r.subsec) raw.right = UINT16(node->r.subsec->index | 0x8000); else InternalError("Bad right child in node %d", node->index); if (node->l.node) raw.left = UINT16(node->l.node->index); else if (node->l.subsec) raw.left = UINT16(node->l.subsec->index | 0x8000); else InternalError("Bad left child in node %d", node->index); AppendLevelLump(lump, &raw, sizeof(raw)); # if DEBUG_BSP PrintDebug("PUT NODE %04X Left %04X Right %04X " "(%d,%d) -> (%d,%d)\n", node->index, UINT16(raw.left), UINT16(raw.right), node->x, node->y, node->x + node->dx, node->y + node->dy); # endif } static void PutOneV5Node(node_t *node, lump_t *lump) { raw_v5_node_t raw; if (node->r.node) PutOneV5Node(node->r.node, lump); if (node->l.node) PutOneV5Node(node->l.node, lump); node->index = node_cur_index++; raw.x = SINT16(node->x); raw.y = SINT16(node->y); raw.dx = SINT16(node->dx / (node->too_long ? 2 : 1)); raw.dy = SINT16(node->dy / (node->too_long ? 2 : 1)); raw.b1.minx = SINT16(node->r.bounds.minx); raw.b1.miny = SINT16(node->r.bounds.miny); raw.b1.maxx = SINT16(node->r.bounds.maxx); raw.b1.maxy = SINT16(node->r.bounds.maxy); raw.b2.minx = SINT16(node->l.bounds.minx); raw.b2.miny = SINT16(node->l.bounds.miny); raw.b2.maxx = SINT16(node->l.bounds.maxx); raw.b2.maxy = SINT16(node->l.bounds.maxy); if (node->r.node) raw.right = UINT32(node->r.node->index); else if (node->r.subsec) raw.right = UINT32(node->r.subsec->index | 0x80000000U); else InternalError("Bad right child in V5 node %d", node->index); if (node->l.node) raw.left = UINT32(node->l.node->index); else if (node->l.subsec) raw.left = UINT32(node->l.subsec->index | 0x80000000U); else InternalError("Bad left child in V5 node %d", node->index); AppendLevelLump(lump, &raw, sizeof(raw)); # if DEBUG_BSP PrintDebug("PUT V5 NODE %08X Left %08X Right %08X " "(%d,%d) -> (%d,%d)\n", node->index, UINT32(raw.left), UINT32(raw.right), node->x, node->y, node->x + node->dx, node->y + node->dy); # endif } void PutNodes(char *name, int do_gl, int do_v5, node_t *root) { lump_t *lump; DisplayTicker(); if (do_gl) lump = CreateGLLump(name); else lump = CreateLevelLump(name); node_cur_index = 0; if (root) { if (do_v5) PutOneV5Node(root, lump); else PutOneNode(root, lump); } if (node_cur_index != num_nodes) InternalError("PutNodes miscounted (%d != %d)", node_cur_index, num_nodes); if (!do_v5 && node_cur_index > 32767) MarkHardFailure(LIMIT_NODES); } /* ----- ZDBSP format writing --------------------------- */ static const uint8_g *lev_ZD_magic = (uint8_g *) "ZNOD"; void PutZVertices(void) { int count, i; uint32_g orgverts = UINT32(num_normal_vert); uint32_g newverts = UINT32(num_gl_vert); ZLibAppendLump(&orgverts, 4); ZLibAppendLump(&newverts, 4); DisplayTicker(); for (i=0, count=0; i < num_vertices; i++) { raw_v2_vertex_t raw; vertex_t *vert = lev_vertices[i]; if (! (vert->index & IS_GL_VERTEX)) continue; raw.x = SINT32((int)(vert->x * 65536.0)); raw.y = SINT32((int)(vert->y * 65536.0)); ZLibAppendLump(&raw, sizeof(raw)); count++; } if (count != num_gl_vert) InternalError("PutZVertices miscounted (%d != %d)", count, num_gl_vert); } void PutZSubsecs(void) { int i; int count; uint32_g raw_num = UINT32(num_subsecs); int cur_seg_index = 0; ZLibAppendLump(&raw_num, 4); DisplayTicker(); for (i=0; i < num_subsecs; i++) { subsec_t *sub = subsecs[i]; seg_t *seg; raw_num = UINT32(sub->seg_count); ZLibAppendLump(&raw_num, 4); // sanity check the seg index values count = 0; for (seg = sub->seg_list; seg; seg = seg->next, cur_seg_index++) { // ignore minisegs and degenerate segs if (! seg->linedef || seg->degenerate) continue; if (cur_seg_index != seg->index) InternalError("PutZSubsecs: seg index mismatch in sub %d (%d != %d)\n", i, cur_seg_index, seg->index); count++; } if (count != sub->seg_count) InternalError("PutZSubsecs: miscounted segs in sub %d (%d != %d)\n", i, count, sub->seg_count); } if (cur_seg_index != num_complete_seg) InternalError("PutZSubsecs miscounted segs (%d != %d)", cur_seg_index, num_complete_seg); } void PutZSegs(void) { int i, count; uint32_g raw_num = UINT32(num_complete_seg); ZLibAppendLump(&raw_num, 4); DisplayTicker(); for (i=0, count=0; i < num_segs; i++) { seg_t *seg = segs[i]; // ignore minisegs and degenerate segs if (! seg->linedef || seg->degenerate) continue; if (count != seg->index) InternalError("PutZSegs: seg index mismatch (%d != %d)\n", count, seg->index); { uint32_g v1 = UINT32(VertexIndex32BitV5(seg->start)); uint32_g v2 = UINT32(VertexIndex32BitV5(seg->end)); uint16_g line = UINT16(seg->linedef->index); uint8_g side = seg->side; ZLibAppendLump(&v1, 4); ZLibAppendLump(&v2, 4); ZLibAppendLump(&line, 2); ZLibAppendLump(&side, 1); } count++; } if (count != num_complete_seg) InternalError("PutZSegs miscounted (%d != %d)", count, num_complete_seg); } static void PutOneZNode(node_t *node) { raw_v5_node_t raw; if (node->r.node) PutOneZNode(node->r.node); if (node->l.node) PutOneZNode(node->l.node); node->index = node_cur_index++; raw.x = SINT16(node->x); raw.y = SINT16(node->y); raw.dx = SINT16(node->dx / (node->too_long ? 2 : 1)); raw.dy = SINT16(node->dy / (node->too_long ? 2 : 1)); ZLibAppendLump(&raw.x, 2); ZLibAppendLump(&raw.y, 2); ZLibAppendLump(&raw.dx, 2); ZLibAppendLump(&raw.dy, 2); raw.b1.minx = SINT16(node->r.bounds.minx); raw.b1.miny = SINT16(node->r.bounds.miny); raw.b1.maxx = SINT16(node->r.bounds.maxx); raw.b1.maxy = SINT16(node->r.bounds.maxy); raw.b2.minx = SINT16(node->l.bounds.minx); raw.b2.miny = SINT16(node->l.bounds.miny); raw.b2.maxx = SINT16(node->l.bounds.maxx); raw.b2.maxy = SINT16(node->l.bounds.maxy); ZLibAppendLump(&raw.b1, sizeof(raw.b1)); ZLibAppendLump(&raw.b2, sizeof(raw.b2)); if (node->r.node) raw.right = UINT32(node->r.node->index); else if (node->r.subsec) raw.right = UINT32(node->r.subsec->index | 0x80000000U); else InternalError("Bad right child in V5 node %d", node->index); if (node->l.node) raw.left = UINT32(node->l.node->index); else if (node->l.subsec) raw.left = UINT32(node->l.subsec->index | 0x80000000U); else InternalError("Bad left child in V5 node %d", node->index); ZLibAppendLump(&raw.right, 4); ZLibAppendLump(&raw.left, 4); # if DEBUG_BSP PrintDebug("PUT Z NODE %08X Left %08X Right %08X " "(%d,%d) -> (%d,%d)\n", node->index, UINT32(raw.left), UINT32(raw.right), node->x, node->y, node->x + node->dx, node->y + node->dy); # endif } void PutZNodes(node_t *root) { uint32_g raw_num = UINT32(num_nodes); ZLibAppendLump(&raw_num, 4); DisplayTicker(); node_cur_index = 0; if (root) PutOneZNode(root); if (node_cur_index != num_nodes) InternalError("PutZNodes miscounted (%d != %d)", node_cur_index, num_nodes); } void SaveZDFormat(node_t *root_node) { lump_t *lump; // leave SEGS and SSECTORS empty CreateLevelLump("SEGS"); CreateLevelLump("SSECTORS"); lump = CreateLevelLump("NODES"); AppendLevelLump(lump, lev_ZD_magic, 4); ZLibBeginLump(lump); PutZVertices(); PutZSubsecs(); PutZSegs(); PutZNodes(root_node); ZLibFinishLump(); } /* ----- whole-level routines --------------------------- */ // // LoadLevel // void LoadLevel(void) { char *message; const char *level_name = GetLevelName(); boolean_g normal_exists = CheckForNormalNodes(); lev_doing_normal = !cur_info->gwa_mode && (cur_info->force_normal || (!cur_info->no_normal && !normal_exists)); // -JL- Identify Hexen mode by presence of BEHAVIOR lump lev_doing_hexen = (FindLevelLump("BEHAVIOR") != NULL); if (lev_doing_normal) message = UtilFormat("Building normal and GL nodes on %s%s", level_name, lev_doing_hexen ? " (Hexen)" : ""); else message = UtilFormat("Building GL nodes on %s%s", level_name, lev_doing_hexen ? " (Hexen)" : ""); lev_doing_hexen |= cur_info->force_hexen; DisplaySetBarText(1, message); PrintVerbose("\n\n"); PrintMsg("%s\n", message); PrintVerbose("\n"); UtilFree(message); GetVertices(); GetSectors(); GetSidedefs(); if (lev_doing_hexen) { GetLinedefsHexen(); GetThingsHexen(); } else { GetLinedefs(); GetThings(); } PrintVerbose("Loaded %d vertices, %d sectors, %d sides, %d lines, %d things\n", num_vertices, num_sectors, num_sidedefs, num_linedefs, num_things); if (cur_info->fast && !lev_doing_normal && normal_exists && num_sectors > 5 && num_linedefs > 100) { PrintVerbose("Using original nodes to speed things up\n"); GetStaleNodes(); } if (lev_doing_normal) { // NOTE: order here is critical if (cur_info->pack_sides) DetectDuplicateSidedefs(); if (cur_info->merge_vert) DetectDuplicateVertices(); if (!cur_info->no_prune) PruneLinedefs(); // always prune vertices (ignore -noprune), otherwise all the // unused vertices from seg splits would keep accumulating. PruneVertices(); if (!cur_info->no_prune) PruneSidedefs(); if (cur_info->prune_sect) PruneSectors(); } CalculateWallTips(); if (lev_doing_hexen) { // -JL- Find sectors containing polyobjs DetectPolyobjSectors(); } DetectOverlappingLines(); if (cur_info->window_fx) DetectWindowEffects(); } // // FreeLevel // void FreeLevel(void) { FreeVertices(); FreeSidedefs(); FreeLinedefs(); FreeSectors(); FreeThings(); FreeSegs(); FreeSubsecs(); FreeNodes(); FreeStaleNodes(); FreeWallTips(); } // // PutGLOptions // void PutGLOptions(void) { char option_buf[128]; sprintf(option_buf, "-v%d -factor %d", cur_info->spec_version, cur_info->factor); if (cur_info->fast ) strcat(option_buf, " -f"); if (cur_info->force_normal ) strcat(option_buf, " -n"); if (cur_info->merge_vert ) strcat(option_buf, " -m"); if (cur_info->pack_sides ) strcat(option_buf, " -p"); if (cur_info->prune_sect ) strcat(option_buf, " -u"); if (cur_info->skip_self_ref) strcat(option_buf, " -s"); if (cur_info->window_fx ) strcat(option_buf, " -y"); if (cur_info->no_normal) strcat(option_buf, " -xn"); if (cur_info->no_reject) strcat(option_buf, " -xr"); if (cur_info->no_prune ) strcat(option_buf, " -xu"); AddGLTextLine("OPTIONS", option_buf); } // // PutGLChecksum // void PutGLChecksum(void) { uint32_g crc; lump_t *lump; char num_buf[64]; Adler32_Begin(&crc); lump = FindLevelLump("VERTEXES"); if (lump && lump->length > 0) Adler32_AddBlock(&crc, lump->data, lump->length); lump = FindLevelLump("LINEDEFS"); if (lump && lump->length > 0) Adler32_AddBlock(&crc, lump->data, lump->length); Adler32_Finish(&crc); sprintf(num_buf, "0x%08x", crc); AddGLTextLine("CHECKSUM", num_buf); } // // SaveLevel // void SaveLevel(node_t *root_node) { lev_force_v3 = (cur_info->spec_version == 3) ? TRUE : FALSE; lev_force_v5 = (cur_info->spec_version == 5) ? TRUE : FALSE; // Note: RoundOffBspTree will convert the GL vertices in segs to // their normal counterparts (pointer change: use normal_dup). if (cur_info->spec_version == 1) RoundOffBspTree(root_node); // GL Nodes { if (num_normal_vert > 32767 || num_gl_vert > 32767) { if (cur_info->spec_version < 3) { lev_force_v5 = TRUE; MarkV5Switch(LIMIT_VERTEXES | LIMIT_GL_SEGS); } } if (num_segs > 65534) { if (cur_info->spec_version < 3) { lev_force_v5 = TRUE; MarkV5Switch(LIMIT_GL_SSECT | LIMIT_GL_SEGS); } } if (num_nodes > 32767) { if (cur_info->spec_version < 5) { lev_force_v5 = TRUE; MarkV5Switch(LIMIT_GL_NODES); } } if (cur_info->spec_version == 1) PutVertices("GL_VERT", TRUE); else PutV2Vertices(lev_force_v5); if (lev_force_v3 || lev_force_v5) PutV3Segs(lev_force_v5); else PutGLSegs(); if (lev_force_v3 || lev_force_v5) PutV3Subsecs(lev_force_v5); else PutSubsecs("GL_SSECT", TRUE); PutNodes("GL_NODES", TRUE, lev_force_v5, root_node); // -JL- Add empty PVS lump CreateGLLump("GL_PVS"); } if (lev_doing_normal) { if (cur_info->spec_version != 1) RoundOffBspTree(root_node); NormaliseBspTree(root_node); PutVertices("VERTEXES", FALSE); PutSectors(); PutSidedefs(); if (lev_doing_hexen) PutLinedefsHexen(); else PutLinedefs(); if (lev_force_v5) { // don't report a problem when -v5 was explicitly given if (cur_info->spec_version < 5) MarkZDSwitch(); SaveZDFormat(root_node); } else { PutSegs(); PutSubsecs("SSECTORS", FALSE); PutNodes("NODES", FALSE, FALSE, root_node); } // -JL- Don't touch blockmap and reject if not doing normal nodes PutBlockmap(); if (!cur_info->no_reject || !FindLevelLump("REJECT")) PutReject(); } // keyword support (v5.0 of the specs) AddGLTextLine("BUILDER", "glBSP " GLBSP_VER); PutGLOptions(); { char *time_str = UtilTimeString(); if (time_str) { AddGLTextLine("TIME", time_str); UtilFree(time_str); } } // this must be done _after_ the normal nodes have been built, // so that we use the new VERTEXES lump in the checksum. PutGLChecksum(); } glbsp-2.24-source/src/glbsp.c0000644000175000017500000003264310651272063015400 0ustar aaptedaapted//------------------------------------------------------------------------ // MAIN : Main program for glBSP //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "system.h" #include #include #include #include #include #include #include #include #include "blockmap.h" #include "level.h" #include "node.h" #include "seg.h" #include "structs.h" #include "util.h" #include "wad.h" const nodebuildinfo_t *cur_info = NULL; const nodebuildfuncs_t *cur_funcs = NULL; volatile nodebuildcomms_t *cur_comms = NULL; const nodebuildinfo_t default_buildinfo = { NULL, // input_file NULL, // output_file NULL, // extra_files DEFAULT_FACTOR, // factor FALSE, // no_reject FALSE, // no_progress FALSE, // quiet FALSE, // mini_warnings FALSE, // force_hexen FALSE, // pack_sides FALSE, // fast 2, // spec_version FALSE, // load_all FALSE, // no_normal FALSE, // force_normal FALSE, // gwa_mode FALSE, // prune_sect FALSE, // no_prune FALSE, // merge_vert FALSE, // skip_self_ref FALSE, // window_fx DEFAULT_BLOCK_LIMIT, // block_limit FALSE, // missing_output FALSE // same_filenames }; const nodebuildcomms_t default_buildcomms = { NULL, // message FALSE, // cancelled 0, 0, // total warnings 0, 0 // build and file positions }; /* ----- option parsing ----------------------------- */ #define EXTRA_BLOCK 10 /* includes terminating NULL */ static void AddExtraFile(nodebuildinfo_t *info, const char *str) { int count = 0; int space; if (! info->extra_files) { info->extra_files = (const char **) UtilCalloc(EXTRA_BLOCK * sizeof(const char *)); info->extra_files[0] = str; info->extra_files[1] = NULL; return; } while (info->extra_files[count]) count++; space = EXTRA_BLOCK - 1 - (count % EXTRA_BLOCK); if (space == 0) { info->extra_files = (const char **) UtilRealloc((void *)info->extra_files, (count + 1 + EXTRA_BLOCK) * sizeof(const char *)); } info->extra_files[count] = str; info->extra_files[count+1] = NULL; } #define HANDLE_BOOLEAN(name, field) \ if (UtilStrCaseCmp(opt_str, name) == 0) \ { \ info->field = TRUE; \ argv++; argc--; \ continue; \ } #define HANDLE_BOOLEAN2(abbrev, name, field) \ HANDLE_BOOLEAN(abbrev, field) \ HANDLE_BOOLEAN(name, field) glbsp_ret_e GlbspParseArgs(nodebuildinfo_t *info, volatile nodebuildcomms_t *comms, const char ** argv, int argc) { const char *opt_str; int num_files = 0; int got_output = FALSE; cur_comms = comms; SetErrorMsg("(Unknown Problem)"); while (argc > 0) { if (argv[0][0] != '-') { // --- ORDINARY FILENAME --- if (got_output) { SetErrorMsg("Input filenames must precede the -o option"); cur_comms = NULL; return GLBSP_E_BadArgs; } if (CheckExtension(argv[0], "gwa")) { SetErrorMsg("Input file cannot be GWA (contains nothing to build)"); cur_comms = NULL; return GLBSP_E_BadArgs; } if (num_files >= 1) { AddExtraFile(info, GlbspStrDup(argv[0])); } else { GlbspFree(info->input_file); info->input_file = GlbspStrDup(argv[0]); } num_files++; argv++; argc--; continue; } // --- AN OPTION --- opt_str = &argv[0][1]; // handle GNU style options beginning with '--' if (opt_str[0] == '-') opt_str++; if (UtilStrCaseCmp(opt_str, "o") == 0) { if (got_output) { SetErrorMsg("The -o option cannot be used more than once"); cur_comms = NULL; return GLBSP_E_BadArgs; } if (num_files >= 2) { SetErrorMsg("Cannot use -o with multiple input files."); cur_comms = NULL; return GLBSP_E_BadArgs; } if (argc < 2 || argv[1][0] == '-') { SetErrorMsg("Missing filename for the -o option"); cur_comms = NULL; return GLBSP_E_BadArgs; } GlbspFree(info->output_file); info->output_file = GlbspStrDup(argv[1]); got_output = TRUE; argv += 2; argc -= 2; continue; } if (UtilStrCaseCmp(opt_str, "factor") == 0 || UtilStrCaseCmp(opt_str, "c") == 0) { if (argc < 2) { SetErrorMsg("Missing factor value"); cur_comms = NULL; return GLBSP_E_BadArgs; } info->factor = (int) strtol(argv[1], NULL, 10); argv += 2; argc -= 2; continue; } if (tolower(opt_str[0]) == 'v' && isdigit(opt_str[1])) { info->spec_version = (opt_str[1] - '0'); argv++; argc--; continue; } if (UtilStrCaseCmp(opt_str, "maxblock") == 0 || UtilStrCaseCmp(opt_str, "b") == 0) { if (argc < 2) { SetErrorMsg("Missing maxblock value"); cur_comms = NULL; return GLBSP_E_BadArgs; } info->block_limit = (int) strtol(argv[1], NULL, 10); argv += 2; argc -= 2; continue; } HANDLE_BOOLEAN2("q", "quiet", quiet) HANDLE_BOOLEAN2("f", "fast", fast) HANDLE_BOOLEAN2("w", "warn", mini_warnings) HANDLE_BOOLEAN2("p", "pack", pack_sides) HANDLE_BOOLEAN2("n", "normal", force_normal) HANDLE_BOOLEAN2("xr", "noreject", no_reject) HANDLE_BOOLEAN2("xp", "noprog", no_progress) HANDLE_BOOLEAN2("m", "mergevert", merge_vert) HANDLE_BOOLEAN2("u", "prunesec", prune_sect) HANDLE_BOOLEAN2("y", "windowfx", window_fx) HANDLE_BOOLEAN2("s", "skipselfref", skip_self_ref) HANDLE_BOOLEAN2("xu", "noprune", no_prune) HANDLE_BOOLEAN2("xn", "nonormal", no_normal) // to err is human... HANDLE_BOOLEAN("noprogress", no_progress) HANDLE_BOOLEAN("packsides", pack_sides) HANDLE_BOOLEAN("prunesect", prune_sect) // ignore these options for backwards compatibility if (UtilStrCaseCmp(opt_str, "fresh") == 0 || UtilStrCaseCmp(opt_str, "keepdummy") == 0 || UtilStrCaseCmp(opt_str, "keepsec") == 0 || UtilStrCaseCmp(opt_str, "keepsect") == 0) { argv++; argc--; continue; } // backwards compatibility HANDLE_BOOLEAN("forcegwa", gwa_mode) HANDLE_BOOLEAN("forcenormal", force_normal) HANDLE_BOOLEAN("loadall", load_all) // The -hexen option is only kept for backwards compatibility HANDLE_BOOLEAN("hexen", force_hexen) SetErrorMsg("Unknown option: %s", argv[0]); cur_comms = NULL; return GLBSP_E_BadArgs; } cur_comms = NULL; return GLBSP_E_OK; } glbsp_ret_e GlbspCheckInfo(nodebuildinfo_t *info, volatile nodebuildcomms_t *comms) { cur_comms = comms; SetErrorMsg("(Unknown Problem)"); info->same_filenames = FALSE; info->missing_output = FALSE; if (!info->input_file || info->input_file[0] == 0) { SetErrorMsg("Missing input filename !"); return GLBSP_E_BadArgs; } if (CheckExtension(info->input_file, "gwa")) { SetErrorMsg("Input file cannot be GWA (contains nothing to build)"); return GLBSP_E_BadArgs; } if (!info->output_file || info->output_file[0] == 0) { GlbspFree(info->output_file); info->output_file = GlbspStrDup(ReplaceExtension( info->input_file, "gwa")); info->gwa_mode = TRUE; info->missing_output = TRUE; } else /* has output filename */ { if (CheckExtension(info->output_file, "gwa")) info->gwa_mode = TRUE; } if (UtilStrCaseCmp(info->input_file, info->output_file) == 0) { info->load_all = TRUE; info->same_filenames = TRUE; } if (info->no_prune && info->pack_sides) { info->pack_sides = FALSE; SetErrorMsg("-noprune and -packsides cannot be used together"); return GLBSP_E_BadInfoFixed; } if (info->gwa_mode && info->force_normal) { info->force_normal = FALSE; SetErrorMsg("-forcenormal used, but GWA files don't have normal nodes"); return GLBSP_E_BadInfoFixed; } if (info->no_normal && info->force_normal) { info->force_normal = FALSE; SetErrorMsg("-forcenormal and -nonormal cannot be used together"); return GLBSP_E_BadInfoFixed; } if (info->factor <= 0 || info->factor > 32) { info->factor = DEFAULT_FACTOR; SetErrorMsg("Bad factor value !"); return GLBSP_E_BadInfoFixed; } if (info->spec_version <= 0 || info->spec_version > 5) { info->spec_version = 2; SetErrorMsg("Bad GL-Nodes version number !"); return GLBSP_E_BadInfoFixed; } else if (info->spec_version == 4) { info->spec_version = 5; SetErrorMsg("V4 GL-Nodes is not supported"); return GLBSP_E_BadInfoFixed; } if (info->block_limit < 1000 || info->block_limit > 64000) { info->block_limit = DEFAULT_BLOCK_LIMIT; SetErrorMsg("Bad blocklimit value !"); return GLBSP_E_BadInfoFixed; } return GLBSP_E_OK; } /* ----- memory functions --------------------------- */ const char *GlbspStrDup(const char *str) { if (! str) return NULL; return UtilStrDup(str); } void GlbspFree(const char *str) { if (! str) return; UtilFree((char *) str); } /* ----- build nodes for a single level --------------------------- */ 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; } /* ----- main routine -------------------------------------- */ 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; } glbsp-2.24-source/src/analyze.h0000644000175000017500000000422310650404665015736 0ustar aaptedaapted//------------------------------------------------------------------------ // ANALYZE : Analyzing level structures //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_ANALYZE_H__ #define __GLBSP_ANALYZE_H__ #include "structs.h" #include "level.h" // detection routines void DetectDuplicateVertices(void); void DetectDuplicateSidedefs(void); void DetectPolyobjSectors(void); void DetectOverlappingLines(void); void DetectWindowEffects(void); // pruning routines void PruneLinedefs(void); void PruneVertices(void); void PruneSidedefs(void); void PruneSectors(void); // computes the wall tips for all of the vertices void CalculateWallTips(void); // return a new vertex (with correct wall_tip info) for the split that // happens along the given seg at the given location. // vertex_t *NewVertexFromSplitSeg(seg_t *seg, float_g x, float_g y); // return a new end vertex to compensate for a seg that would end up // being zero-length (after integer rounding). Doesn't compute the // wall_tip info (thus this routine should only be used _after_ node // building). // vertex_t *NewVertexDegenerate(vertex_t *start, vertex_t *end); // check whether a line with the given delta coordinates and beginning // at this vertex is open. Returns a sector reference if it's open, // or NULL if closed (void space or directly along a linedef). // sector_t * VertexCheckOpen(vertex_t *vert, float_g dx, float_g dy); #endif /* __GLBSP_ANALYZE_H__ */ glbsp-2.24-source/src/wad.c0000644000175000017500000010000410650404712015024 0ustar aaptedaapted//------------------------------------------------------------------------ // WAD : WAD read/write functions. //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "system.h" #include #include #include #include #include #include #include #include #include #include "blockmap.h" #include "level.h" #include "node.h" #include "seg.h" #include "structs.h" #include "util.h" #include "wad.h" static FILE *in_file = NULL; static FILE *out_file = NULL; #define DEBUG_DIR 0 #define DEBUG_LUMP 0 #define DEBUG_KEYS 0 #define APPEND_BLKSIZE 256 #define LEVNAME_BUNCH 20 #define ALIGN_LEN(len) ((((len) + 3) / 4) * 4) // current wad info static wad_t wad; /* ---------------------------------------------------------------- */ #define NUM_LEVEL_LUMPS 12 #define NUM_GL_LUMPS 5 static const char *level_lumps[NUM_LEVEL_LUMPS]= { "THINGS", "LINEDEFS", "SIDEDEFS", "VERTEXES", "SEGS", "SSECTORS", "NODES", "SECTORS", "REJECT", "BLOCKMAP", "BEHAVIOR", // <-- hexen support "SCRIPTS" // -JL- Lump with script sources }; static const char *gl_lumps[NUM_GL_LUMPS]= { "GL_VERT", "GL_SEGS", "GL_SSECT", "GL_NODES", "GL_PVS" // -JL- PVS (Potentially Visible Set) lump }; static const char align_filler[4] = { 0, 0, 0, 0 }; // // CheckMagic // static int CheckMagic(const char type[4]) { if ((type[0] == 'I' || type[0] == 'P') && type[1] == 'W' && type[2] == 'A' && type[3] == 'D') { return TRUE; } return FALSE; } // // CheckLevelName // static int CheckLevelName(const char *name) { int n; for (n=0; n < wad.num_level_names; n++) { if (strcmp(wad.level_names[n], name) == 0) return TRUE; } return FALSE; } // // CheckLevelLumpName // // Tests if the entry name is one of the level lumps. // Returns index after header (1..N), or zero if no match. // static int CheckLevelLumpName(const char *name) { int i; for (i=0; i < NUM_LEVEL_LUMPS; i++) { if (strcmp(name, level_lumps[i]) == 0) return 1 + i; } return 0; } // // CheckGLLumpName // // Tests if the entry name matches GL_ExMy or GL_MAPxx, or one of the // GL lump names. // static int CheckGLLumpName(const char *name) { int i; if (name[0] != 'G' || name[1] != 'L' || name[2] != '_') return FALSE; for (i=0; i < NUM_GL_LUMPS; i++) { if (strcmp(name, gl_lumps[i]) == 0) return TRUE; } return CheckLevelName(name+3); } // // Level name helper // static INLINE_G void AddLevelName(const char *name) { if ((wad.num_level_names % LEVNAME_BUNCH) == 0) { wad.level_names = (const char **) UtilRealloc((void *)wad.level_names, (wad.num_level_names + LEVNAME_BUNCH) * sizeof(const char *)); } wad.level_names[wad.num_level_names] = UtilStrDup(name); wad.num_level_names++; } // // NewLevel // // Create new level information // static level_t *NewLevel(int flags) { level_t *cur; cur = UtilCalloc(sizeof(level_t)); cur->flags = flags; return cur; } // // NewLump // // Create new lump. 'name' must be allocated storage. // static lump_t *NewLump(char *name) { lump_t *cur; cur = UtilCalloc(sizeof(lump_t)); cur->name = name; cur->start = cur->new_start = -1; cur->flags = LUMP_NEW; cur->length = 0; cur->space = 0; cur->data = NULL; cur->lev_info = NULL; return cur; } static void FreeLump(lump_t *lump); // // FreeWadLevel // static void FreeWadLevel(level_t *level) { while (level->children) { lump_t *head = level->children; level->children = head->next; // the ol' recursion trick... :) FreeLump(head); } UtilFree(level); } // // FreeLump // static void FreeLump(lump_t *lump) { // free level lumps, if any if (lump->lev_info) { FreeWadLevel(lump->lev_info); } // check 'data' here, since it gets freed in WriteLumpData() if (lump->data) UtilFree(lump->data); UtilFree(lump->name); UtilFree(lump); } // // ReadHeader // // Returns TRUE if successful, or FALSE if there was a problem (in // which case the error message as been setup). // static int ReadHeader(const char *filename) { size_t len; raw_wad_header_t header; len = fread(&header, sizeof(header), 1, in_file); if (len != 1) { SetErrorMsg("Trouble reading wad header for %s [%s]", filename, strerror(errno)); return FALSE; } if (! CheckMagic(header.type)) { SetErrorMsg("%s does not appear to be a wad file (bad magic)", filename); return FALSE; } wad.kind = (header.type[0] == 'I') ? IWAD : PWAD; wad.num_entries = UINT32(header.num_entries); wad.dir_start = UINT32(header.dir_start); // initialise stuff wad.dir_head = NULL; wad.dir_tail = NULL; wad.current_level = NULL; wad.level_names = NULL; wad.num_level_names = 0; return TRUE; } // // ReadDirEntry // static void ReadDirEntry(void) { size_t len; raw_wad_entry_t entry; lump_t *lump; DisplayTicker(); len = fread(&entry, sizeof(entry), 1, in_file); if (len != 1) FatalError("Trouble reading wad directory"); lump = NewLump(UtilStrNDup(entry.name, 8)); lump->start = UINT32(entry.start); lump->length = UINT32(entry.length); # if DEBUG_DIR PrintDebug("Read dir... %s\n", lump->name); # endif // link it in lump->next = NULL; lump->prev = wad.dir_tail; if (wad.dir_tail) wad.dir_tail->next = lump; else wad.dir_head = lump; wad.dir_tail = lump; } // // DetermineLevelNames // static void DetermineLevelNames(void) { lump_t *L, *N; int i; for (L=wad.dir_head; L; L=L->next) { int matched = 0; // skip known lumps (these are never valid level names) if (CheckLevelLumpName(L->name)) continue; // check if the next four lumps after the current lump match the // level-lump names. Order doesn't matter, but repeats do. for (i=0, N=L->next; (i < 4) && N; i++, N=N->next) { int idx = CheckLevelLumpName(N->name); if (!idx || idx > 8 /* SECTORS */ || (matched & (1<name); # endif // check for duplicate levels (ignored) if (CheckLevelName(L->name)) { PrintWarn("Level name '%s' found twice in wad - Skipped\n", L->name); continue; } // check for long names if (strlen(L->name) > 5) PrintWarn("Long level name '%s' found in wad\n", L->name); AddLevelName(L->name); } } // // ProcessDirEntry // static void ProcessDirEntry(lump_t *lump) { DisplayTicker(); // ignore previous GL lump info if (CheckGLLumpName(lump->name)) { # if DEBUG_DIR PrintDebug("Discarding previous GL info: %s\n", lump->name); # endif FreeLump(lump); wad.num_entries--; return; } // mark the lump as 'ignorable' when in GWA mode. if (cur_info->gwa_mode) lump->flags |= LUMP_IGNORE_ME; // --- LEVEL MARKERS --- if (CheckLevelName(lump->name)) { /* NOTE ! Level marks can have data (in Hexen anyway) */ if (cur_info->load_all) lump->flags |= LUMP_READ_ME; else lump->flags |= LUMP_COPY_ME; // OK, start a new level lump->lev_info = NewLevel(0); wad.current_level = lump; # if DEBUG_DIR PrintDebug("Process dir... %s :\n", lump->name); # endif // link it in lump->next = NULL; lump->prev = wad.dir_tail; if (wad.dir_tail) wad.dir_tail->next = lump; else wad.dir_head = lump; wad.dir_tail = lump; return; } // --- LEVEL LUMPS --- if (wad.current_level) { if (CheckLevelLumpName(lump->name)) { // check for duplicates if (FindLevelLump(lump->name)) { PrintWarn("Duplicate entry '%s' ignored in %s\n", lump->name, wad.current_level->name); FreeLump(lump); wad.num_entries--; return; } # if DEBUG_DIR PrintDebug("Process dir... |--- %s\n", lump->name); # endif // mark it to be loaded lump->flags |= LUMP_READ_ME; // link it in lump->next = wad.current_level->lev_info->children; lump->prev = NULL; if (lump->next) lump->next->prev = lump; wad.current_level->lev_info->children = lump; return; } // OK, non-level lump. End the previous level. wad.current_level = NULL; } // --- ORDINARY LUMPS --- # if DEBUG_DIR PrintDebug("Process dir... %s\n", lump->name); # endif if (CheckLevelLumpName(lump->name)) PrintWarn("Level lump '%s' found outside any level\n", lump->name); // maybe load data if (cur_info->load_all) lump->flags |= LUMP_READ_ME; else lump->flags |= LUMP_COPY_ME; // link it in lump->next = NULL; lump->prev = wad.dir_tail; if (wad.dir_tail) wad.dir_tail->next = lump; else wad.dir_head = lump; wad.dir_tail = lump; } // // ReadDirectory // static void ReadDirectory(void) { int i; int total_entries = wad.num_entries; lump_t *prev_list; fseek(in_file, wad.dir_start, SEEK_SET); for (i=0; i < total_entries; i++) { ReadDirEntry(); } DetermineLevelNames(); // finally, unlink all lumps and process each one in turn prev_list = wad.dir_head; wad.dir_head = wad.dir_tail = NULL; while (prev_list) { lump_t *cur = prev_list; prev_list = cur->next; ProcessDirEntry(cur); } } // // 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; } // // ReadAllLumps // // Returns number of entries read. // static int ReadAllLumps(void) { lump_t *cur, *L; int count = 0; for (cur=wad.dir_head; cur; cur=cur->next) { count++; if (cur->flags & LUMP_READ_ME) ReadLumpData(cur); if (cur->lev_info && ! (cur->lev_info->flags & LEVEL_IS_GL)) { for (L=cur->lev_info->children; L; L=L->next) { count++; if (L->flags & LUMP_READ_ME) ReadLumpData(L); } } } return count; } // // CountLumpTypes // // Returns number of entries with matching flags. Used to predict how // many ReadLumpData() or WriteLumpData() calls will be made (for the // progress bars). // static int CountLumpTypes(int flag_mask, int flag_match) { lump_t *cur, *L; int count = 0; for (cur=wad.dir_head; cur; cur=cur->next) { if ((cur->flags & flag_mask) == flag_match) count++; if (cur->lev_info) { for (L=cur->lev_info->children; L; L=L->next) if ((L->flags & flag_mask) == flag_match) count++; } } return count; } /* ---------------------------------------------------------------- */ // // WriteHeader // static void WriteHeader(void) { size_t len; raw_wad_header_t header; switch (wad.kind) { case IWAD: strncpy(header.type, "IWAD", 4); break; case PWAD: strncpy(header.type, "PWAD", 4); break; } header.num_entries = UINT32(wad.num_entries); header.dir_start = UINT32(wad.dir_start); len = fwrite(&header, sizeof(header), 1, out_file); if (len != 1) PrintWarn("Trouble writing wad header\n"); } // // CreateGLMarker // lump_t *CreateGLMarker(void) { lump_t *level = wad.current_level; lump_t *cur; char name_buf[32]; boolean_g long_name = FALSE; if (strlen(level->name) <= 5) { sprintf(name_buf, "GL_%s", level->name); } else { // support for level names longer than 5 letters strcpy(name_buf, "GL_LEVEL"); long_name = TRUE; } cur = NewLump(UtilStrDup(name_buf)); cur->lev_info = NewLevel(LEVEL_IS_GL); // link it in cur->next = level->next; cur->prev = level; if (cur->next) cur->next->prev = cur; level->next = cur; level->lev_info->buddy = cur; if (long_name) { AddGLTextLine("LEVEL", level->name); } return cur; } // // SortLumps // // Algorithm is pretty simple: for each of the names, if such a lump // exists in the list, move it to the head of the list. By going // backwards through the names, we ensure the correct order. // static void SortLumps(lump_t ** list, const char **names, int count) { int i; lump_t *cur; for (i=count-1; i >= 0; i--) { for (cur=(*list); cur; cur=cur->next) { if (strcmp(cur->name, names[i]) != 0) continue; // unlink it if (cur->next) cur->next->prev = cur->prev; if (cur->prev) cur->prev->next = cur->next; else (*list) = cur->next; // add to head cur->next = (*list); cur->prev = NULL; if (cur->next) cur->next->prev = cur; (*list) = cur; // continue with next name (important !) break; } } } // // RecomputeDirectory // // Calculates all the lump offsets for the directory. // static void RecomputeDirectory(void) { lump_t *cur, *L; level_t *lev; wad.num_entries = 0; wad.dir_start = sizeof(raw_wad_header_t); // run through all the lumps, computing the 'new_start' fields, the // number of lumps in the directory, the directory starting pos, and // also sorting the lumps in the levels. for (cur=wad.dir_head; cur; cur=cur->next) { if (cur->flags & LUMP_IGNORE_ME) continue; cur->new_start = wad.dir_start; wad.dir_start += ALIGN_LEN(cur->length); wad.num_entries++; lev = cur->lev_info; if (lev) { if (lev->flags & LEVEL_IS_GL) SortLumps(&lev->children, gl_lumps, NUM_GL_LUMPS); else SortLumps(&lev->children, level_lumps, NUM_LEVEL_LUMPS); for (L=lev->children; L; L=L->next) { if (L->flags & LUMP_IGNORE_ME) continue; L->new_start = wad.dir_start; wad.dir_start += ALIGN_LEN(L->length); wad.num_entries++; } } } } // // 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; } // // WriteAllLumps // // Returns number of entries written. // static int WriteAllLumps(void) { lump_t *cur, *L; int count = 0; for (cur=wad.dir_head; cur; cur=cur->next) { if (cur->flags & LUMP_IGNORE_ME) continue; WriteLumpData(cur); count++; if (cur->lev_info) { for (L=cur->lev_info->children; L; L=L->next) { if (L->flags & LUMP_IGNORE_ME) continue; WriteLumpData(L); count++; } } } fflush(out_file); return count; } // // WriteDirEntry // static void WriteDirEntry(lump_t *lump) { size_t len; raw_wad_entry_t entry; DisplayTicker(); strncpy(entry.name, lump->name, 8); entry.start = UINT32(lump->new_start); entry.length = UINT32(lump->length); len = fwrite(&entry, sizeof(entry), 1, out_file); if (len != 1) PrintWarn("Trouble writing wad directory\n"); } // // WriteDirectory // // Returns number of entries written. // static int WriteDirectory(void) { lump_t *cur, *L; int count = 0; if (ftell(out_file) != wad.dir_start) PrintWarn("Consistency failure writing lump directory " "(%08lX,%08X)\n", ftell(out_file), wad.dir_start); for (cur=wad.dir_head; cur; cur=cur->next) { if (cur->flags & LUMP_IGNORE_ME) continue; WriteDirEntry(cur); count++; # if DEBUG_DIR if (cur->lev_info) PrintDebug("Write dir... %s :\n", cur->name); else PrintDebug("Write dir... %s\n", cur->name); # endif if (cur->lev_info) { for (L=cur->lev_info->children; L; L=L->next) { if (cur->flags & LUMP_IGNORE_ME) continue; # if DEBUG_DIR PrintDebug("Write dir... |--- %s\n", L->name); # endif WriteDirEntry(L); count++; } } } fflush(out_file); return count; } /* ---------------------------------------------------------------- */ // // CheckExtension // int CheckExtension(const char *filename, const char *ext) { int A = (int)strlen(filename) - 1; int B = (int)strlen(ext) - 1; for (; B >= 0; B--, A--) { if (A < 0) return FALSE; if (toupper(filename[A]) != toupper(ext[B])) return FALSE; } return (A >= 1) && (filename[A] == '.'); } // // ReplaceExtension // char *ReplaceExtension(const char *filename, const char *ext) { char *dot_pos; char buffer[512]; strcpy(buffer, filename); dot_pos = strrchr(buffer, '.'); if (dot_pos) dot_pos[1] = 0; else strcat(buffer, "."); strcat(buffer, ext); return UtilStrDup(buffer); } // // CreateLevelLump // lump_t *CreateLevelLump(const char *name) { lump_t *cur; # if DEBUG_DIR PrintDebug("Create Lump... %s\n", name); # endif // already exists ? for (cur=wad.current_level->lev_info->children; cur; cur=cur->next) { if (strcmp(name, cur->name) == 0) break; } if (cur) { if (cur->data) UtilFree(cur->data); cur->data = NULL; cur->length = 0; cur->space = 0; return cur; } // nope, allocate new one cur = NewLump(UtilStrDup(name)); // link it in cur->next = wad.current_level->lev_info->children; cur->prev = NULL; if (cur->next) cur->next->prev = cur; wad.current_level->lev_info->children = cur; return cur; } // // CreateGLLump // lump_t *CreateGLLump(const char *name) { lump_t *cur; lump_t *gl_level; # if DEBUG_DIR PrintDebug("Create GL Lump... %s\n", name); # endif // create GL level marker if necessary if (! wad.current_level->lev_info->buddy) CreateGLMarker(); gl_level = wad.current_level->lev_info->buddy; // check if already exists for (cur=gl_level->lev_info->children; cur; cur=cur->next) { if (strcmp(name, cur->name) == 0) break; } if (cur) { if (cur->data) UtilFree(cur->data); cur->data = NULL; cur->length = 0; cur->space = 0; return cur; } // nope, allocate new one cur = NewLump(UtilStrDup(name)); // link it in cur->next = gl_level->lev_info->children; cur->prev = NULL; if (cur->next) cur->next->prev = cur; gl_level->lev_info->children = cur; return cur; } // // AppendLevelLump // void AppendLevelLump(lump_t *lump, const void *data, int length) { if (length == 0) return; if (lump->length == 0) { lump->space = MAX(length, APPEND_BLKSIZE); lump->data = UtilCalloc(lump->space); } else if (lump->space < length) { lump->space = MAX(length, APPEND_BLKSIZE); lump->data = UtilRealloc(lump->data, lump->length + lump->space); } memcpy(((char *)lump->data) + lump->length, data, length); lump->length += length; lump->space -= length; } // // AddGLTextLine // void AddGLTextLine(const char *keyword, const char *value) { lump_t *gl_level; // create GL level marker if necessary if (! wad.current_level->lev_info->buddy) CreateGLMarker(); gl_level = wad.current_level->lev_info->buddy; # if DEBUG_KEYS PrintDebug("[%s] Adding: %s=%s\n", gl_level->name, keyword, value); # endif AppendLevelLump(gl_level, keyword, strlen(keyword)); AppendLevelLump(gl_level, "=", 1); AppendLevelLump(gl_level, value, strlen(value)); AppendLevelLump(gl_level, "\n", 1); } // // CountLevels // int CountLevels(void) { lump_t *cur; int result = 0; for (cur=wad.dir_head; cur; cur=cur->next) { if (cur->lev_info && ! (cur->lev_info->flags & LEVEL_IS_GL)) result++; } return result; } // // FindNextLevel // int FindNextLevel(void) { lump_t *cur; if (wad.current_level) cur = wad.current_level->next; else cur = wad.dir_head; while (cur && ! (cur->lev_info && ! (cur->lev_info->flags & LEVEL_IS_GL))) cur=cur->next; wad.current_level = cur; return (cur != NULL); } // // GetLevelName // const char *GetLevelName(void) { if (!wad.current_level) InternalError("GetLevelName: no current level"); return wad.current_level->name; } // // FindLevelLump // lump_t *FindLevelLump(const char *name) { lump_t *cur = wad.current_level->lev_info->children; while (cur && (strcmp(cur->name, name) != 0)) cur=cur->next; return cur; } // // CheckLevelLumpZero // int CheckLevelLumpZero(lump_t *lump) { int i; if (lump->length == 0) return TRUE; // ASSERT(lump->data) for (i=0; i < lump->length; i++) { if (((uint8_g *)lump->data)[i]) return FALSE; } return TRUE; } // // 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; } // // WriteWadFile // glbsp_ret_e WriteWadFile(const char *filename) { int check1, check2; char *write_msg; PrintMsg("\n"); PrintMsg("Saving WAD as %s\n", filename); if (cur_info->gwa_mode) wad.kind = PWAD; 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; } // // DeleteGwaFile // void DeleteGwaFile(const char *base_wad_name) { char *gwa_file = ReplaceExtension(base_wad_name, "gwa"); if (remove(gwa_file) == 0) PrintMsg("Deleted GWA file: %s\n", gwa_file); UtilFree(gwa_file); } // // CloseWads // void CloseWads(void) { int i; if (in_file) { fclose(in_file); in_file = NULL; } if (out_file) { fclose(out_file); out_file = NULL; } /* free directory entries */ while (wad.dir_head) { lump_t *head = wad.dir_head; wad.dir_head = head->next; FreeLump(head); } /* free the level names */ if (wad.level_names) { for (i=0; i < wad.num_level_names; i++) UtilFree((char *) wad.level_names[i]); UtilFree((void *)wad.level_names); wad.level_names = NULL; } } /* ---------------------------------------------------------------- */ static lump_t *zout_lump; static z_stream zout_stream; static Bytef zout_buffer[1024]; // // ZLibBeginLump // void ZLibBeginLump(lump_t *lump) { zout_lump = lump; zout_stream.zalloc = (alloc_func)0; zout_stream.zfree = (free_func)0; zout_stream.opaque = (voidpf)0; if (Z_OK != deflateInit(&zout_stream, Z_DEFAULT_COMPRESSION)) FatalError("Trouble setting up zlib compression"); zout_stream.next_out = zout_buffer; zout_stream.avail_out = sizeof(zout_buffer); } // // ZLibAppendLump // void ZLibAppendLump(const void *data, int length) { // ASSERT(zout_lump) // ASSERT(length > 0) zout_stream.next_in = (Bytef*)data; // const override zout_stream.avail_in = length; while (zout_stream.avail_in > 0) { int err = deflate(&zout_stream, Z_NO_FLUSH); if (err != Z_OK) FatalError("Trouble compressing %d bytes (zlib)\n", length); if (zout_stream.avail_out == 0) { AppendLevelLump(zout_lump, zout_buffer, sizeof(zout_buffer)); zout_stream.next_out = zout_buffer; zout_stream.avail_out = sizeof(zout_buffer); } } } // // ZLibFinishLump // void ZLibFinishLump(void) { int left_over; // ASSERT(zout_stream.avail_out > 0) zout_stream.next_in = Z_NULL; zout_stream.avail_in = 0; for (;;) { int err = deflate(&zout_stream, Z_FINISH); if (err == Z_STREAM_END) break; if (err != Z_OK) FatalError("Trouble finishing compression (zlib)\n"); if (zout_stream.avail_out == 0) { AppendLevelLump(zout_lump, zout_buffer, sizeof(zout_buffer)); zout_stream.next_out = zout_buffer; zout_stream.avail_out = sizeof(zout_buffer); } } left_over = sizeof(zout_buffer) - zout_stream.avail_out; if (left_over > 0) AppendLevelLump(zout_lump, zout_buffer, left_over); deflateEnd(&zout_stream); zout_lump = NULL; } /* ---------------------------------------------------------------- */ // // Mark failure routines // void MarkSoftFailure(int soft) { wad.current_level->lev_info->soft_limit |= soft; } void MarkHardFailure(int hard) { wad.current_level->lev_info->hard_limit |= hard; } void MarkV5Switch(int v5) { wad.current_level->lev_info->v5_switch |= v5; } void MarkZDSwitch(void) { level_t *lev = wad.current_level->lev_info; lev->v5_switch |= LIMIT_ZDBSP; lev->soft_limit &= ~ (LIMIT_VERTEXES); lev->hard_limit &= ~ (LIMIT_VERTEXES); } // // ReportOneOverflow( // void ReportOneOverflow(const lump_t *lump, int limit, boolean_g hard) { const char *msg = hard ? "overflowed the absolute limit" : "overflowed the original limit"; PrintMsg("%-8s: ", lump->name); switch (limit) { case LIMIT_VERTEXES: PrintMsg("Number of Vertices %s.\n", msg); break; case LIMIT_SECTORS: PrintMsg("Number of Sectors %s.\n", msg); break; case LIMIT_SIDEDEFS: PrintMsg("Number of Sidedefs %s\n", msg); break; case LIMIT_LINEDEFS: PrintMsg("Number of Linedefs %s\n", msg); break; case LIMIT_SEGS: PrintMsg("Number of Segs %s.\n", msg); break; case LIMIT_SSECTORS: PrintMsg("Number of Subsectors %s.\n", msg); break; case LIMIT_NODES: PrintMsg("Number of Nodes %s.\n", msg); break; case LIMIT_GL_VERT: PrintMsg("Number of GL vertices %s.\n", msg); break; case LIMIT_GL_SEGS: PrintMsg("Number of GL segs %s.\n", msg); break; case LIMIT_GL_SSECT: PrintMsg("Number of GL subsectors %s.\n", msg); break; case LIMIT_GL_NODES: PrintMsg("Number of GL nodes %s.\n", msg); break; case LIMIT_BAD_SIDE: PrintMsg("One or more linedefs has a bad sidedef.\n"); break; case LIMIT_BMAP_TRUNC: PrintMsg("Blockmap area was too big - truncated.\n"); break; case LIMIT_BLOCKMAP: PrintMsg("Blockmap lump %s.\n", msg); break; default: InternalError("UNKNOWN LIMIT BIT: 0x%06x", limit); } } // ReportOverflows // void ReportOverflows(boolean_g hard) { lump_t *cur; if (hard) { PrintMsg( "ERRORS. The following levels failed to be built, and won't\n" "work in any Doom port (and may even crash it).\n\n" ); } else // soft { PrintMsg( "POTENTIAL FAILURES. The following levels should work in a\n" "modern Doom port, but may fail (or even crash) in older ports.\n\n" ); } for (cur=wad.dir_head; cur; cur=cur->next) { level_t *lev = cur->lev_info; int limits, one_lim; if (! (lev && ! (lev->flags & LEVEL_IS_GL))) continue; limits = hard ? lev->hard_limit : lev->soft_limit; if (limits == 0) continue; for (one_lim = (1<<20); one_lim; one_lim >>= 1) { if (limits & one_lim) ReportOneOverflow(cur, one_lim, hard); } } } // // ReportV5Switches // void ReportV5Switches(void) { lump_t *cur; int saw_zdbsp = FALSE; PrintMsg( "V5 FORMAT UPGRADES. The following levels require a Doom port\n" "which supports V5 GL-Nodes, otherwise they will fail (or crash).\n\n" ); for (cur=wad.dir_head; cur; cur=cur->next) { level_t *lev = cur->lev_info; if (! (lev && ! (lev->flags & LEVEL_IS_GL))) continue; if (lev->v5_switch == 0) continue; if ((lev->v5_switch & LIMIT_ZDBSP) && ! saw_zdbsp) { PrintMsg("ZDBSP FORMAT has also been used for regular nodes.\n\n"); saw_zdbsp = TRUE; } if (lev->v5_switch & LIMIT_VERTEXES) { PrintMsg("%-8s: Number of Vertices overflowed the limit.\n", cur->name); } if (lev->v5_switch & LIMIT_GL_SSECT) { PrintMsg("%-8s: Number of GL segs overflowed the limit.\n", cur->name); } } } // // ReportFailedLevels // void ReportFailedLevels(void) { lump_t *cur; int lev_count = 0; int fail_soft = 0; int fail_hard = 0; int fail_v5 = 0; boolean_g need_spacer = FALSE; for (cur=wad.dir_head; cur; cur=cur->next) { if (! (cur->lev_info && ! (cur->lev_info->flags & LEVEL_IS_GL))) continue; lev_count++; if (cur->lev_info->soft_limit != 0) fail_soft++; if (cur->lev_info->hard_limit != 0) fail_hard++; if (cur->lev_info->v5_switch != 0) fail_v5++; } PrintMsg("\n"); if (fail_soft + fail_hard + fail_v5 == 0) { PrintMsg("All levels were built successfully.\n"); return; } PrintMsg("*** Problem Report ***\n\n"); if (fail_soft > 0) { ReportOverflows(FALSE); need_spacer = TRUE; } if (fail_v5 > 0) { if (need_spacer) PrintMsg("\n"); ReportV5Switches(); need_spacer = TRUE; } if (fail_hard > 0) { if (need_spacer) PrintMsg("\n"); ReportOverflows(TRUE); } PrintMsg("\nEnd of problem report.\n"); } glbsp-2.24-source/src/structs.h0000644000175000017500000001426310650404710015776 0ustar aaptedaapted//------------------------------------------------------------------------ // STRUCT : Doom structures, raw on-disk layout //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_STRUCTS_H__ #define __GLBSP_STRUCTS_H__ #include "system.h" /* ----- The wad structures ---------------------- */ // wad header typedef struct raw_wad_header_s { char type[4]; uint32_g num_entries; uint32_g dir_start; } raw_wad_header_t; // directory entry typedef struct raw_wad_entry_s { uint32_g start; uint32_g length; char name[8]; } raw_wad_entry_t; // blockmap typedef struct raw_blockmap_header_s { sint16_g x_origin, y_origin; sint16_g x_blocks, y_blocks; } raw_blockmap_header_t; /* ----- The level structures ---------------------- */ typedef struct raw_vertex_s { sint16_g x, y; } raw_vertex_t; typedef struct raw_v2_vertex_s { sint32_g x, y; } raw_v2_vertex_t; typedef struct raw_linedef_s { uint16_g start; // from this vertex... uint16_g end; // ... to this vertex uint16_g flags; // linedef flags (impassible, etc) uint16_g type; // linedef type (0 for none, 97 for teleporter, etc) sint16_g tag; // this linedef activates the sector with same tag uint16_g sidedef1; // right sidedef uint16_g sidedef2; // left sidedef (only if this line adjoins 2 sectors) } raw_linedef_t; typedef struct raw_hexen_linedef_s { uint16_g start; // from this vertex... uint16_g end; // ... to this vertex uint16_g flags; // linedef flags (impassible, etc) uint8_g type; // linedef type uint8_g specials[5]; // hexen specials uint16_g sidedef1; // right sidedef uint16_g sidedef2; // left sidedef } raw_hexen_linedef_t; #define LINEFLAG_TWO_SIDED 4 #define HEXTYPE_POLY_START 1 #define HEXTYPE_POLY_EXPLICIT 5 typedef struct raw_sidedef_s { sint16_g x_offset; // X offset for texture sint16_g y_offset; // Y offset for texture char upper_tex[8]; // texture name for the part above char lower_tex[8]; // texture name for the part below char mid_tex[8]; // texture name for the regular part uint16_g sector; // adjacent sector } raw_sidedef_t; typedef struct raw_sector_s { sint16_g floor_h; // floor height sint16_g ceil_h; // ceiling height char floor_tex[8]; // floor texture char ceil_tex[8]; // ceiling texture uint16_g light; // light level (0-255) uint16_g special; // special behaviour (0 = normal, 9 = secret, ...) sint16_g tag; // sector activated by a linedef with same tag } raw_sector_t; typedef struct raw_thing_s { sint16_g x, y; // position of thing sint16_g angle; // angle thing faces (degrees) uint16_g type; // type of thing uint16_g options; // when appears, deaf, etc.. } raw_thing_t; // -JL- Hexen thing definition typedef struct raw_hexen_thing_s { sint16_g tid; // thing tag id (for scripts/specials) sint16_g x, y; // position sint16_g height; // start height above floor sint16_g angle; // angle thing faces uint16_g type; // type of thing uint16_g options; // when appears, deaf, dormant, etc.. uint8_g special; // special type uint8_g arg[5]; // special arguments } raw_hexen_thing_t; // -JL- Hexen polyobj thing types #define PO_ANCHOR_TYPE 3000 #define PO_SPAWN_TYPE 3001 #define PO_SPAWNCRUSH_TYPE 3002 // -JL- ZDoom polyobj thing types #define ZDOOM_PO_ANCHOR_TYPE 9300 #define ZDOOM_PO_SPAWN_TYPE 9301 #define ZDOOM_PO_SPAWNCRUSH_TYPE 9302 /* ----- The BSP tree structures ----------------------- */ typedef struct raw_seg_s { uint16_g start; // from this vertex... uint16_g end; // ... to this vertex uint16_g angle; // angle (0 = east, 16384 = north, ...) uint16_g linedef; // linedef that this seg goes along uint16_g flip; // true if not the same direction as linedef uint16_g dist; // distance from starting point } raw_seg_t; typedef struct raw_gl_seg_s { uint16_g start; // from this vertex... uint16_g end; // ... to this vertex uint16_g linedef; // linedef that this seg goes along, or -1 uint16_g side; // 0 if on right of linedef, 1 if on left uint16_g partner; // partner seg number, or -1 } raw_gl_seg_t; typedef struct raw_v3_seg_s { uint32_g start; // from this vertex... uint32_g end; // ... to this vertex uint16_g linedef; // linedef that this seg goes along, or -1 uint16_g side; // 0 if on right of linedef, 1 if on left uint32_g partner; // partner seg number, or -1 } raw_v3_seg_t; typedef struct raw_bbox_s { sint16_g maxy, miny; sint16_g minx, maxx; } raw_bbox_t; typedef struct raw_node_s { sint16_g x, y; // starting point sint16_g dx, dy; // offset to ending point raw_bbox_t b1, b2; // bounding rectangles uint16_g right, left; // children: Node or SSector (if high bit is set) } raw_node_t; typedef struct raw_subsec_s { uint16_g num; // number of Segs in this Sub-Sector uint16_g first; // first Seg } raw_subsec_t; typedef struct raw_v3_subsec_s { uint32_g num; // number of Segs in this Sub-Sector uint32_g first; // first Seg } raw_v3_subsec_t; typedef struct raw_v5_node_s { sint16_g x, y; // starting point sint16_g dx, dy; // offset to ending point raw_bbox_t b1, b2; // bounding rectangles uint32_g right, left; // children: Node or SSector (if high bit is set) } raw_v5_node_t; #endif /* __GLBSP_STRUCTS_H__ */ glbsp-2.24-source/src/reject.c0000644000175000017500000001145510650404703015540 0ustar aaptedaapted//------------------------------------------------------------------------ // REJECT : Generate the reject table //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "system.h" #include #include #include #include #include #include #include #include #include "reject.h" #include "level.h" #include "node.h" #include "seg.h" #include "structs.h" #include "util.h" #include "wad.h" #define DEBUG_REJECT 0 // // InitReject // // Puts each sector into individual groups. // static void InitReject(void) { int i; for (i=0; i < num_sectors; i++) { sector_t *sec = LookupSector(i); sec->rej_group = i; sec->rej_next = sec->rej_prev = sec; } } // // GroupSectors // // Algorithm: Initially all sectors are in individual groups. Now we // scan the linedef list. For each 2-sectored line, merge the two // sector groups into one. That's it ! // static void GroupSectors(void) { int i; for (i=0; i < num_linedefs; i++) { linedef_t *line = LookupLinedef(i); sector_t *sec1, *sec2, *tmp; if (! line->right || ! line->left) continue; // the standard DOOM engine will not allow sight past lines // lacking the TWOSIDED flag, so we can skip them here too. if (! line->two_sided) continue; sec1 = line->right->sector; sec2 = line->left->sector; if (! sec1 || ! sec2 || sec1 == sec2) continue; // already in the same group ? if (sec1->rej_group == sec2->rej_group) continue; // swap sectors so that the smallest group is added to the biggest // group. This is based on the assumption that sector numbers in // wads will generally increase over the set of linedefs, and so // (by swapping) we'll tend to add small groups into larger // groups, thereby minimising the updates to 'rej_group' fields // that is required when merging. if (sec1->rej_group > sec2->rej_group) { tmp = sec1; sec1 = sec2; sec2 = tmp; } // update the group numbers in the second group sec2->rej_group = sec1->rej_group; for (tmp=sec2->rej_next; tmp != sec2; tmp=tmp->rej_next) tmp->rej_group = sec1->rej_group; // merge 'em baby... sec1->rej_next->rej_prev = sec2; sec2->rej_next->rej_prev = sec1; tmp = sec1->rej_next; sec1->rej_next = sec2->rej_next; sec2->rej_next = tmp; } } #if DEBUG_REJECT static void CountGroups(void) { // Note: this routine is destructive to the group numbers int i; for (i=0; i < num_sectors; i++) { sector_t *sec = LookupSector(i); sector_t *tmp; int group = sec->rej_group; int num = 0; if (group < 0) continue; sec->rej_group = -1; num++; for (tmp=sec->rej_next; tmp != sec; tmp=tmp->rej_next) { tmp->rej_group = -1; num++; } PrintDebug("Group %d Sectors %d\n", group, num); } } #endif // // CreateReject // static void CreateReject(uint8_g *matrix) { int view, target; for (view=0; view < num_sectors; view++) for (target=0; target < view; target++) { sector_t *view_sec = LookupSector(view); sector_t *targ_sec = LookupSector(target); int p1, p2; if (view_sec->rej_group == targ_sec->rej_group) continue; // for symmetry, do two bits at a time p1 = view * num_sectors + target; p2 = target * num_sectors + view; matrix[p1 >> 3] |= (1 << (p1 & 7)); matrix[p2 >> 3] |= (1 << (p2 & 7)); } } // // PutReject // // For now we only do very basic reject processing, limited to // determining all isolated groups of sectors (islands that are // surrounded by void space). // void PutReject(void) { int reject_size; uint8_g *matrix; lump_t *lump; DisplayTicker(); InitReject(); GroupSectors(); reject_size = (num_sectors * num_sectors + 7) / 8; matrix = UtilCalloc(reject_size); CreateReject(matrix); # if DEBUG_REJECT CountGroups(); # endif lump = CreateLevelLump("REJECT"); AppendLevelLump(lump, matrix, reject_size); PrintVerbose("Added simple reject lump\n"); UtilFree(matrix); } glbsp-2.24-source/src/level.h0000644000175000017500000002376110650661643015413 0ustar aaptedaapted//------------------------------------------------------------------------ // LEVEL : Level structures & read/write functions. //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_LEVEL_H__ #define __GLBSP_LEVEL_H__ #include "structs.h" #include "wad.h" struct node_s; struct sector_s; struct superblock_s; // a wall_tip is where a wall meets a vertex typedef struct wall_tip_s { // link in list. List is kept in ANTI-clockwise order. struct wall_tip_s *next; struct wall_tip_s *prev; // angle that line makes at vertex (degrees). angle_g angle; // sectors on each side of wall. Left is the side of increasing // angles, right is the side of decreasing angles. Either can be // NULL for one sided walls. struct sector_s *left; struct sector_s *right; } wall_tip_t; typedef struct vertex_s { // coordinates float_g x, y; // vertex index. Always valid after loading and pruning of unused // vertices has occurred. For GL vertices, bit 30 will be set. int index; // reference count. When building normal node info, unused vertices // will be pruned. int ref_count; // usually NULL, unless this vertex occupies the same location as a // previous vertex. Only used during the pruning phase. struct vertex_s *equiv; // set of wall_tips wall_tip_t *tip_set; // contains a duplicate vertex, needed when both normal and V2 GL // nodes are being built at the same time (this is the vertex used // for the normal segs). Normally NULL. Note: the wall tips on // this vertex are not created. struct vertex_s *normal_dup; } vertex_t; #define IS_GL_VERTEX (1 << 30) typedef struct sector_s { // sector index. Always valid after loading & pruning. int index; // allow segs from other sectors to coexist in a subsector. char coalesce; // -JL- non-zero if this sector contains a polyobj. int has_polyobj; // reference count. When building normal nodes, unused sectors will // be pruned. int ref_count; // heights int floor_h, ceil_h; // textures char floor_tex[8]; char ceil_tex[8]; // attributes int light; int special; int tag; // used when building REJECT table. Each set of sectors that are // isolated from other sectors will have a different group number. // Thus: on every 2-sided linedef, the sectors on both sides will be // in the same group. The rej_next, rej_prev fields are a link in a // RING, containing all sectors of the same group. int rej_group; struct sector_s *rej_next; struct sector_s *rej_prev; // suppress superfluous mini warnings int warned_facing; char warned_unclosed; } sector_t; typedef struct sidedef_s { // adjacent sector. Can be NULL (invalid sidedef) sector_t *sector; // offset values int x_offset, y_offset; // texture names char upper_tex[8]; char lower_tex[8]; char mid_tex[8]; // sidedef index. Always valid after loading & pruning. int index; // reference count. When building normal nodes, unused sidedefs will // be pruned. int ref_count; // usually NULL, unless this sidedef is exactly the same as a // previous one. Only used during the pruning phase. struct sidedef_s *equiv; // this is true if the sidedef is on a special line. We don't merge // these sidedefs together, as they might scroll, or change texture // when a switch is pressed. int on_special; } sidedef_t; typedef struct linedef_s { // link for list struct linedef_s *next; vertex_t *start; // from this vertex... vertex_t *end; // ... to this vertex sidedef_t *right; // right sidedef sidedef_t *left; // left sidede, or NULL if none // line is marked two-sided char two_sided; // prefer not to split char is_precious; // zero length (line should be totally ignored) char zero_len; // sector is the same on both sides char self_ref; // one-sided linedef used for a special effect (windows). // The value refers to the opposite sector on the back side. sector_t * window_effect; int flags; int type; int tag; // Hexen support int specials[5]; // normally NULL, except when this linedef directly overlaps an earlier // one (a rarely-used trick to create higher mid-masked textures). // No segs should be created for these overlapping linedefs. struct linedef_s *overlap; // linedef index. Always valid after loading & pruning of zero // length lines has occurred. int index; } linedef_t; typedef struct thing_s { int x, y; int type; int options; // other info (angle, and hexen stuff) omitted. We don't need to // write the THING lump, only read it. // Always valid (thing indices never change). int index; } thing_t; typedef struct seg_s { // link for list struct seg_s *next; vertex_t *start; // from this vertex... vertex_t *end; // ... to this vertex // linedef that this seg goes along, or NULL if miniseg linedef_t *linedef; // adjacent sector, or NULL if invalid sidedef or miniseg sector_t *sector; // 0 for right, 1 for left int side; // seg on other side, or NULL if one-sided. This relationship is // always one-to-one -- if one of the segs is split, the partner seg // must also be split. struct seg_s *partner; // seg index. Only valid once the seg has been added to a // subsector. A negative value means it is invalid -- there // shouldn't be any of these once the BSP tree has been built. int index; // when 1, this seg has become zero length (integer rounding of the // start and end vertices produces the same location). It should be // ignored when writing the SEGS or V1 GL_SEGS lumps. [Note: there // won't be any of these when writing the V2 GL_SEGS lump]. int degenerate; // the superblock that contains this seg, or NULL if the seg is no // longer in any superblock (e.g. now in a subsector). struct superblock_s *block; // precomputed data for faster calculations float_g psx, psy; float_g pex, pey; float_g pdx, pdy; float_g p_length; float_g p_angle; float_g p_para; float_g p_perp; // linedef that this seg initially comes from. For "real" segs, // this is just the same as the 'linedef' field above. For // "minisegs", this is the linedef of the partition line. linedef_t *source_line; } seg_t; typedef struct subsec_s { // list of segs seg_t *seg_list; // count of segs int seg_count; // subsector index. Always valid, set when the subsector is // initially created. int index; // approximate middle point float_g mid_x; float_g mid_y; } subsec_t; typedef struct bbox_s { int minx, miny; int maxx, maxy; } bbox_t; typedef struct child_s { // child node or subsector (one must be NULL) struct node_s *node; subsec_t *subsec; // child bounding box bbox_t bounds; } child_t; typedef struct node_s { int x, y; // starting point int dx, dy; // offset to ending point // right & left children child_t r; child_t l; // node index. Only valid once the NODES or GL_NODES lump has been // created. int index; // the node is too long, and the (dx,dy) values should be halved // when writing into the NODES lump. int too_long; } node_t; typedef struct superblock_s { // parent of this block, or NULL for a top-level block struct superblock_s *parent; // coordinates on map for this block, from lower-left corner to // upper-right corner. Pseudo-inclusive, i.e (x,y) is inside block // if and only if x1 <= x < x2 and y1 <= y < y2. int x1, y1; int x2, y2; // sub-blocks. NULL when empty. [0] has the lower coordinates, and // [1] has the higher coordinates. Division of a square always // occurs horizontally (e.g. 512x512 -> 256x512 -> 256x256). struct superblock_s *subs[2]; // number of real segs and minisegs contained by this block // (including all sub-blocks below it). int real_num; int mini_num; // list of segs completely contained by this block. seg_t *segs; } superblock_t; #define SUPER_IS_LEAF(s) \ ((s)->x2-(s)->x1 <= 256 && (s)->y2-(s)->y1 <= 256) /* ----- Level data arrays ----------------------- */ extern int num_vertices; extern int num_linedefs; extern int num_sidedefs; extern int num_sectors; extern int num_things; extern int num_segs; extern int num_subsecs; extern int num_nodes; extern int num_stale_nodes; extern int num_normal_vert; extern int num_gl_vert; extern int num_complete_seg; /* ----- function prototypes ----------------------- */ // allocation routines vertex_t *NewVertex(void); linedef_t *NewLinedef(void); sidedef_t *NewSidedef(void); sector_t *NewSector(void); thing_t *NewThing(void); seg_t *NewSeg(void); subsec_t *NewSubsec(void); node_t *NewNode(void); node_t *NewStaleNode(void); wall_tip_t *NewWallTip(void); // lookup routines vertex_t *LookupVertex(int index); linedef_t *LookupLinedef(int index); sidedef_t *LookupSidedef(int index); sector_t *LookupSector(int index); thing_t *LookupThing(int index); seg_t *LookupSeg(int index); subsec_t *LookupSubsec(int index); node_t *LookupNode(int index); node_t *LookupStaleNode(int index); // check whether the current level already has normal nodes int CheckForNormalNodes(void); // load all level data for the current level void LoadLevel(void); // free all level data void FreeLevel(void); // save the newly computed NODE info etc.. void SaveLevel(node_t *root_node); #endif /* __GLBSP_LEVEL_H__ */ glbsp-2.24-source/src/glbsp.h0000644000175000017500000002174510652011206015375 0ustar aaptedaapted//------------------------------------------------------------------------ // GLBSP.H : Interface to Node Builder //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_GLBSP_H__ #define __GLBSP_GLBSP_H__ #define GLBSP_VER "2.24" #define GLBSP_VER_HEX 0x224 // certain GCC attributes can be useful #undef GCCATTR #ifdef __GNUC__ #define GCCATTR(xyz) __attribute__ (xyz) #else #define GCCATTR(xyz) /* nothing */ #endif #ifdef __cplusplus extern "C" { #endif // __cplusplus /* ----- basic types --------------------------- */ typedef signed char sint8_g; typedef signed short sint16_g; typedef signed int sint32_g; typedef unsigned char uint8_g; typedef unsigned short uint16_g; typedef unsigned int uint32_g; typedef double float_g; typedef double angle_g; // degrees, 0 is E, 90 is N // boolean type typedef int boolean_g; #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif /* ----- complex types --------------------------- */ // Node Build Information Structure // // Memory note: when changing the string values here (and in // nodebuildcomms_t) they should be freed using GlbspFree() and // allocated with GlbspStrDup(). The application has the final // responsibility to free the strings in here. // typedef struct nodebuildinfo_s { const char *input_file; const char *output_file; // pointer to a NULL terminated array of strings containing extra // input filenames. Normally this field is NULL. When there are // extra filenames, 'output_file' will be NULL -- also the build // mode will be GWA. const char **extra_files; int factor; boolean_g no_reject; boolean_g no_progress; boolean_g quiet; boolean_g mini_warnings; boolean_g force_hexen; boolean_g pack_sides; boolean_g fast; int spec_version; // 1, 2, 3 or 5 boolean_g load_all; boolean_g no_normal; boolean_g force_normal; boolean_g gwa_mode; boolean_g prune_sect; boolean_g no_prune; boolean_g merge_vert; boolean_g skip_self_ref; boolean_g window_fx; int block_limit; // private stuff -- values computed in GlbspParseArgs or // GlbspCheckInfo that need to be passed to GlbspBuildNodes. boolean_g missing_output; boolean_g same_filenames; } nodebuildinfo_t; // This is for two-way communication (esp. with the GUI). // Should be flagged 'volatile' since multiple threads (real or // otherwise, e.g. signals) may read or change the values. // typedef struct nodebuildcomms_s { // if the node builder failed, this will contain the error const char *message; // the GUI can set this to tell the node builder to stop boolean_g cancelled; // from here on, various bits of internal state int total_small_warn, total_big_warn; int build_pos, file_pos; } nodebuildcomms_t; // Display Prototypes typedef enum { DIS_INVALID, // Nonsense value is always useful DIS_BUILDPROGRESS, // Build Box, has 2 bars DIS_FILEPROGRESS, // File Box, has 1 bar NUMOFGUITYPES } displaytype_e; // Callback functions typedef struct nodebuildfuncs_s { // Fatal errors are called as a last resort when something serious // goes wrong, e.g. out of memory. This routine should show the // error to the user and abort the program. // void (* fatal_error)(const char *str, ...) GCCATTR((format (printf, 1, 2))); // The print_msg routine is used to display the various messages // that occur, e.g. "Building GL nodes on MAP01" and that kind of // thing. // void (* print_msg)(const char *str, ...) GCCATTR((format (printf, 1, 2))); // This routine is called frequently whilst building the nodes, and // can be used to keep a GUI responsive to user input. Many // toolkits have a "do iteration" or "check events" type of function // that this can call. Avoid anything that sleeps though, or it'll // slow down the build process unnecessarily. // void (* ticker)(void); // These display routines is used for tasks that can show a progress // bar, namely: building nodes, loading the wad, and saving the wad. // The command line version could show a percentage value, or even // draw a bar using characters. // Display_open is called at the beginning, and 'type' holds the // type of progress (and determines how many bars to display). // Returns TRUE if all went well, or FALSE if it failed (in which // case the other routines should do nothing when called). // boolean_g (* display_open)(displaytype_e type); // For GUI versions this can be used to set the title of the // progress window. OK to ignore it (e.g. command line version). // void (* display_setTitle)(const char *str); // The next three routines control the appearance of each progress // bar. Display_setBarText is called to change the message above // the bar. Display_setBarLimit sets the integer limit of the // progress (the target value), and display_setBar sets the current // value (which will count up from 0 to the limit, inclusive). // void (* display_setBar)(int barnum, int count); void (* display_setBarLimit)(int barnum, int limit); void (* display_setBarText)(int barnum, const char *str); // The display_close routine is called when the task is finished, // and should remove the progress indicator/window from the screen. // void (* display_close)(void); } nodebuildfuncs_t; // Default build info and comms extern const nodebuildinfo_t default_buildinfo; extern const nodebuildcomms_t default_buildcomms; /* -------- engine prototypes ----------------------- */ typedef enum { // everything went peachy keen GLBSP_E_OK = 0, // an unknown error occurred (this is the catch-all value) GLBSP_E_Unknown, // the arguments were bad/inconsistent. GLBSP_E_BadArgs, // the info was bad/inconsistent, but has been fixed GLBSP_E_BadInfoFixed, // file errors GLBSP_E_ReadError, GLBSP_E_WriteError, // building was cancelled GLBSP_E_Cancelled } glbsp_ret_e; // parses the arguments, modifying the 'info' structure accordingly. // Returns GLBSP_E_OK if all went well, otherwise another error code. // Upon error, comms->message may be set to an string describing the // error. Typical errors are unrecognised options and invalid option // values. Calling this routine is not compulsory. Note that the set // of arguments does not include the program's name. // glbsp_ret_e GlbspParseArgs(nodebuildinfo_t *info, volatile nodebuildcomms_t *comms, const char ** argv, int argc); // checks the node building parameters in 'info'. If they are valid, // returns GLBSP_E_OK, otherwise an error code is returned. This // routine should always be called shortly before GlbspBuildNodes(). // Note that when 'output_file' is NULL, this routine will silently // update it to the correct GWA filename (and set the gwa_mode flag). // // If the GLBSP_E_BadInfoFixed error code is returned, the parameter // causing the problem has been changed. You could either treat it as // a fatal error, or alternatively keep calling the routine in a loop // until something different than GLBSP_E_BadInfoFixed is returned, // showing the user the returned messages (e.g. as warnings or in // pop-up dialog boxes). // // If there are multiple input files (extra_files is non-NULL), this // routine should be called once for each input file, setting the // 'output_file' field to NULL each time. // glbsp_ret_e GlbspCheckInfo(nodebuildinfo_t *info, volatile nodebuildcomms_t *comms); // main routine, this will build the nodes (GL and/or normal) for the // given input wad file out to the given output file. Returns // GLBSP_E_OK if everything went well, otherwise another error code. // Typical errors are fubar parameters (like input_file == NULL), // problems reading/writing files, or cancellation by another thread // (esp. the GUI) using the comms->cancelled flag. Upon errors, the // comms->message field usually contains a string describing it. // glbsp_ret_e GlbspBuildNodes(const nodebuildinfo_t *info, const nodebuildfuncs_t *funcs, volatile nodebuildcomms_t *comms); // string memory routines. These should be used for all strings // shared between the main glBSP code and the UI code (including code // using glBSP as a plug-in). They accept NULL pointers. // const char *GlbspStrDup(const char *str); void GlbspFree(const char *str); #ifdef __cplusplus } #endif // __cplusplus #endif /* __GLBSP_GLBSP_H__ */ glbsp-2.24-source/src/util.c0000644000175000017500000001244510650404710015237 0ustar aaptedaapted//------------------------------------------------------------------------ // UTILITY : general purpose functions //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "system.h" #include #include #include #include #include #include #include #include #include "util.h" #ifdef WIN32 #include #else #include #endif // // UtilCalloc // // Allocate memory with error checking. Zeros the memory. // void *UtilCalloc(int size) { void *ret = calloc(1, size); if (!ret) FatalError("Out of memory (cannot allocate %d bytes)", size); return ret; } // // UtilRealloc // // Reallocate memory with error checking. // void *UtilRealloc(void *old, int size) { void *ret = realloc(old, size); if (!ret) FatalError("Out of memory (cannot reallocate %d bytes)", size); return ret; } // // UtilFree // // Free the memory with error checking. // void UtilFree(void *data) { if (data == NULL) InternalError("Trying to free a NULL pointer"); free(data); } // // UtilStrDup // // Duplicate a string with error checking. // char *UtilStrDup(const char *str) { char *result; int len = (int)strlen(str); result = UtilCalloc(len+1); if (len > 0) memcpy(result, str, len); result[len] = 0; return result; } // // UtilStrNDup // // Duplicate a limited length string. // char *UtilStrNDup(const char *str, int size) { char *result; int len; for (len=0; len < size && str[len]; len++) { } result = UtilCalloc(len+1); if (len > 0) memcpy(result, str, len); result[len] = 0; return result; } char *UtilFormat(const char *str, ...) { /* Algorithm: keep doubling the allocated buffer size * until the output fits. Based on code by Darren Salt. */ char *buf = NULL; int buf_size = 128; for (;;) { va_list args; int out_len; buf_size *= 2; buf = realloc(buf, buf_size); if (!buf) FatalError("Out of memory (formatting string)"); va_start(args, str); out_len = vsnprintf(buf, buf_size, str, args); va_end(args); // old versions of vsnprintf() simply return -1 when // the output doesn't fit. if (out_len < 0 || out_len >= buf_size) continue; return buf; } } int UtilStrCaseCmp(const char *A, const char *B) { for (; *A || *B; A++, B++) { // this test also catches end-of-string conditions if (toupper(*A) != toupper(*B)) return (toupper(*A) - toupper(*B)); } // strings are equal return 0; } // // UtilRoundPOW2 // // Rounds the value _up_ to the nearest power of two. // int UtilRoundPOW2(int x) { int tmp; if (x <= 2) return x; x--; for (tmp=x / 2; tmp; tmp /= 2) x |= tmp; return (x + 1); } // // UtilComputeAngle // // Translate (dx, dy) into an angle value (degrees) // angle_g UtilComputeAngle(float_g dx, float_g dy) { double angle; if (dx == 0) return (dy > 0) ? 90.0 : 270.0; angle = atan2((double) dy, (double) dx) * 180.0 / M_PI; if (angle < 0) angle += 360.0; return angle; } // // UtilFileExists // int UtilFileExists(const char *filename) { FILE *fp = fopen(filename, "rb"); if (fp) { fclose(fp); return TRUE; } return FALSE; } // // UtilTimeString // char *UtilTimeString(void) { #ifdef WIN32 SYSTEMTIME sys_time; GetSystemTime(&sys_time); return UtilFormat("%04d-%02d-%02d %02d:%02d:%02d.%04d", sys_time.wYear, sys_time.wMonth, sys_time.wDay, sys_time.wHour, sys_time.wMinute, sys_time.wSecond, sys_time.wMilliseconds * 10); #else // LINUX or MACOSX time_t epoch_time; struct tm *calend_time; if (time(&epoch_time) == (time_t)-1) return NULL; calend_time = localtime(&epoch_time); if (! calend_time) return NULL; return UtilFormat("%04d-%02d-%02d %02d:%02d:%02d.%04d", calend_time->tm_year + 1900, calend_time->tm_mon + 1, calend_time->tm_mday, calend_time->tm_hour, calend_time->tm_min, calend_time->tm_sec, 0); #endif } //------------------------------------------------------------------------ // Adler-32 CHECKSUM Code //------------------------------------------------------------------------ void Adler32_Begin(uint32_g *crc) { *crc = 1; } void Adler32_AddBlock(uint32_g *crc, const uint8_g *data, int length) { uint32_g s1 = (*crc) & 0xFFFF; uint32_g s2 = ((*crc) >> 16) & 0xFFFF; for (; length > 0; data++, length--) { s1 = (s1 + *data) % 65521; s2 = (s2 + s1) % 65521; } *crc = (s2 << 16) | s1; } void Adler32_Finish(uint32_g *crc) { /* nothing to do */ } glbsp-2.24-source/src/seg.c0000644000175000017500000007274410650660400015050 0ustar aaptedaapted//------------------------------------------------------------------------ // SEG : Choose the best Seg to use for a node line. //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // To be able to divide the nodes down, this routine must decide which // is the best Seg to use as a nodeline. It does this by selecting the // line with least splits and has least difference of Segs on either // side of it. // // Credit to Raphael Quinet and DEU, this routine is a copy of the // nodeline picker used in DEU5beta. I am using this method because // the method I originally used was not so good. // // Rewritten by Lee Killough to significantly improve performance, // while not affecting results one bit in >99% of cases (some tiny // differences due to roundoff error may occur, but they are // insignificant). // // Rewritten again by Andrew Apted (-AJA-), 1999-2000. // #include "system.h" #include #include #include #include #include #include #include #include #include "analyze.h" #include "blockmap.h" #include "level.h" #include "node.h" #include "seg.h" #include "structs.h" #include "util.h" #include "wad.h" #define PRECIOUS_MULTIPLY 100 #define SEG_REUSE_THRESHHOLD 200 #define DEBUG_PICKNODE 0 #define DEBUG_SPLIT 0 #define DEBUG_CUTLIST 0 typedef struct eval_info_s { int cost; int splits; int iffy; int near_miss; int real_left; int real_right; int mini_left; int mini_right; } eval_info_t; static intersection_t *quick_alloc_cuts = NULL; // // NewIntersection // static intersection_t *NewIntersection(void) { intersection_t *cut; if (quick_alloc_cuts) { cut = quick_alloc_cuts; quick_alloc_cuts = cut->next; } else { cut = UtilCalloc(sizeof(intersection_t)); } return cut; } // // FreeQuickAllocCuts // void FreeQuickAllocCuts(void) { while (quick_alloc_cuts) { intersection_t *cut = quick_alloc_cuts; quick_alloc_cuts = cut->next; UtilFree(cut); } } // // RecomputeSeg // // Fill in the fields 'angle', 'len', 'pdx', 'pdy', etc... // void RecomputeSeg(seg_t *seg) { seg->psx = seg->start->x; seg->psy = seg->start->y; seg->pex = seg->end->x; seg->pey = seg->end->y; seg->pdx = seg->pex - seg->psx; seg->pdy = seg->pey - seg->psy; seg->p_length = UtilComputeDist(seg->pdx, seg->pdy); seg->p_angle = UtilComputeAngle(seg->pdx, seg->pdy); if (seg->p_length <= 0) InternalError("Seg %p has zero p_length.", seg); seg->p_perp = seg->psy * seg->pdx - seg->psx * seg->pdy; seg->p_para = -seg->psx * seg->pdx - seg->psy * seg->pdy; } // // SplitSeg // // -AJA- Splits the given seg at the point (x,y). The new seg is // returned. The old seg is shortened (the original start // vertex is unchanged), whereas the new seg becomes the cut-off // tail (keeping the original end vertex). // // If the seg has a partner, than that partner is also split. // NOTE WELL: the new piece of the partner seg is inserted into // the same list as the partner seg (and after it) -- thus ALL // segs (except the one we are currently splitting) must exist // on a singly-linked list somewhere. // // Note: we must update the count values of any superblock that // contains the seg (and/or partner), so that future processing // is not fucked up by incorrect counts. // static seg_t *SplitSeg(seg_t *old_seg, float_g x, float_g y) { seg_t *new_seg; vertex_t *new_vert; # if DEBUG_SPLIT if (old_seg->linedef) PrintDebug("Splitting Linedef %d (%p) at (%1.1f,%1.1f)\n", old_seg->linedef->index, old_seg, x, y); else PrintDebug("Splitting Miniseg %p at (%1.1f,%1.1f)\n", old_seg, x, y); # endif // update superblock, if needed if (old_seg->block) SplitSegInSuper(old_seg->block, old_seg); new_vert = NewVertexFromSplitSeg(old_seg, x, y); new_seg = NewSeg(); // copy seg info new_seg[0] = old_seg[0]; new_seg->next = NULL; old_seg->end = new_vert; RecomputeSeg(old_seg); new_seg->start = new_vert; RecomputeSeg(new_seg); # if DEBUG_SPLIT PrintDebug("Splitting Vertex is %04X at (%1.1f,%1.1f)\n", new_vert->index, new_vert->x, new_vert->y); # endif // handle partners if (old_seg->partner) { # if DEBUG_SPLIT PrintDebug("Splitting Partner %p\n", old_seg->partner); # endif // update superblock, if needed if (old_seg->partner->block) SplitSegInSuper(old_seg->partner->block, old_seg->partner); new_seg->partner = NewSeg(); // copy seg info new_seg->partner[0] = old_seg->partner[0]; // IMPORTANT: keep partner relationship valid. new_seg->partner->partner = new_seg; old_seg->partner->start = new_vert; RecomputeSeg(old_seg->partner); new_seg->partner->end = new_vert; RecomputeSeg(new_seg->partner); // link it into list old_seg->partner->next = new_seg->partner; } return new_seg; } // // ComputeIntersection // // -AJA- In the quest for slime-trail annihilation :->, this routine // calculates the intersection location between the current seg // and the partitioning seg, and takes advantage of some common // situations like horizontal/vertical lines. // static INLINE_G void ComputeIntersection(seg_t *cur, seg_t *part, float_g perp_c, float_g perp_d, float_g *x, float_g *y) { double ds; // horizontal partition against vertical seg if (part->pdy == 0 && cur->pdx == 0) { *x = cur->psx; *y = part->psy; return; } // vertical partition against horizontal seg if (part->pdx == 0 && cur->pdy == 0) { *x = part->psx; *y = cur->psy; return; } // 0 = start, 1 = end ds = perp_c / (perp_c - perp_d); if (cur->pdx == 0) *x = cur->psx; else *x = cur->psx + (cur->pdx * ds); if (cur->pdy == 0) *y = cur->psy; else *y = cur->psy + (cur->pdy * ds); } // // AddIntersection // static void AddIntersection(intersection_t ** cut_list, vertex_t *vert, seg_t *part, boolean_g self_ref) { intersection_t *cut; intersection_t *after; /* check if vertex already present */ for (cut=(*cut_list); cut; cut=cut->next) { if (vert == cut->vertex) return; } /* create new intersection */ cut = NewIntersection(); cut->vertex = vert; cut->along_dist = UtilParallelDist(part, vert->x, vert->y); cut->self_ref = self_ref; cut->before = VertexCheckOpen(vert, -part->pdx, -part->pdy); cut->after = VertexCheckOpen(vert, part->pdx, part->pdy); /* enqueue the new intersection into the list */ for (after=(*cut_list); after && after->next; after=after->next) { } while (after && cut->along_dist < after->along_dist) after = after->prev; /* link it in */ cut->next = after ? after->next : (*cut_list); cut->prev = after; if (after) { if (after->next) after->next->prev = cut; after->next = cut; } else { if (*cut_list) (*cut_list)->prev = cut; (*cut_list) = cut; } } // // EvalPartitionWorker // // Returns TRUE if a "bad seg" was found early. // static int EvalPartitionWorker(superblock_t *seg_list, seg_t *part, int best_cost, eval_info_t *info) { seg_t *check; float_g qnty; float_g a, b, fa, fb; int num; int factor = cur_info->factor; // -AJA- this is the heart of my superblock idea, it tests the // _whole_ block against the partition line to quickly handle // all the segs within it at once. Only when the partition // line intercepts the box do we need to go deeper into it. num = BoxOnLineSide(seg_list, part); if (num < 0) { // LEFT info->real_left += seg_list->real_num; info->mini_left += seg_list->mini_num; return FALSE; } else if (num > 0) { // RIGHT info->real_right += seg_list->real_num; info->mini_right += seg_list->mini_num; return FALSE; } # define ADD_LEFT() \ do { \ if (check->linedef) info->real_left += 1; \ else info->mini_left += 1; \ } while (0) # define ADD_RIGHT() \ do { \ if (check->linedef) info->real_right += 1; \ else info->mini_right += 1; \ } while (0) /* check partition against all Segs */ for (check=seg_list->segs; check; check=check->next) { // This is the heart of my pruning idea - it catches // bad segs early on. Killough if (info->cost > best_cost) return TRUE; /* get state of lines' relation to each other */ if (check->source_line == part->source_line) { a = b = fa = fb = 0; } else { a = UtilPerpDist(part, check->psx, check->psy); b = UtilPerpDist(part, check->pex, check->pey); fa = fabs(a); fb = fabs(b); } /* check for being on the same line */ if (fa <= DIST_EPSILON && fb <= DIST_EPSILON) { // this seg runs along the same line as the partition. Check // whether it goes in the same direction or the opposite. if (check->pdx*part->pdx + check->pdy*part->pdy < 0) { ADD_LEFT(); } else { ADD_RIGHT(); } continue; } // -AJA- check for passing through a vertex. Normally this is fine // (even ideal), but the vertex could on a sector that we // DONT want to split, and the normal linedef-based checks // may fail to detect the sector being cut in half. Thanks // to Janis Legzdinsh for spotting this obscure bug. if (fa <= DIST_EPSILON || fb <= DIST_EPSILON) { if (check->linedef && check->linedef->is_precious) info->cost += 40 * factor * PRECIOUS_MULTIPLY; } /* check for right side */ if (a > -DIST_EPSILON && b > -DIST_EPSILON) { ADD_RIGHT(); /* check for a near miss */ if ((a >= IFFY_LEN && b >= IFFY_LEN) || (a <= DIST_EPSILON && b >= IFFY_LEN) || (b <= DIST_EPSILON && a >= IFFY_LEN)) { continue; } info->near_miss++; // -AJA- near misses are bad, since they have the potential to // cause really short minisegs to be created in future // processing. Thus the closer the near miss, the higher // the cost. if (a <= DIST_EPSILON || b <= DIST_EPSILON) qnty = IFFY_LEN / MAX(a, b); else qnty = IFFY_LEN / MIN(a, b); info->cost += (int) (100 * factor * (qnty * qnty - 1.0)); continue; } /* check for left side */ if (a < DIST_EPSILON && b < DIST_EPSILON) { ADD_LEFT(); /* check for a near miss */ if ((a <= -IFFY_LEN && b <= -IFFY_LEN) || (a >= -DIST_EPSILON && b <= -IFFY_LEN) || (b >= -DIST_EPSILON && a <= -IFFY_LEN)) { continue; } info->near_miss++; // the closer the miss, the higher the cost (see note above) if (a >= -DIST_EPSILON || b >= -DIST_EPSILON) qnty = IFFY_LEN / -MIN(a, b); else qnty = IFFY_LEN / -MAX(a, b); info->cost += (int) (70 * factor * (qnty * qnty - 1.0)); continue; } // When we reach here, we have a and b non-zero and opposite sign, // hence this seg will be split by the partition line. info->splits++; // If the linedef associated with this seg has a tag >= 900, treat // it as precious; i.e. don't split it unless all other options // are exhausted. This is used to protect deep water and invisible // lifts/stairs from being messed up accidentally by splits. if (check->linedef && check->linedef->is_precious) info->cost += 100 * factor * PRECIOUS_MULTIPLY; else info->cost += 100 * factor; // -AJA- check if the split point is very close to one end, which // is quite an undesirable situation (producing really short // segs). This is perhaps _one_ source of those darn slime // trails. Hence the name "IFFY segs", and a rather hefty // surcharge :->. if (fa < IFFY_LEN || fb < IFFY_LEN) { info->iffy++; // the closer to the end, the higher the cost qnty = IFFY_LEN / MIN(fa, fb); info->cost += (int) (140 * factor * (qnty * qnty - 1.0)); } } /* handle sub-blocks recursively */ for (num=0; num < 2; num++) { if (! seg_list->subs[num]) continue; if (EvalPartitionWorker(seg_list->subs[num], part, best_cost, info)) return TRUE; } /* no "bad seg" was found */ return FALSE; } // // EvalPartition // // -AJA- Evaluate a partition seg & determine the cost, taking into // account the number of splits, difference between left & // right, and linedefs that are tagged 'precious'. // // Returns the computed cost, or a negative value if the seg should be // skipped altogether. // static int EvalPartition(superblock_t *seg_list, seg_t *part, int best_cost) { eval_info_t info; /* initialise info structure */ info.cost = 0; info.splits = 0; info.iffy = 0; info.near_miss = 0; info.real_left = 0; info.real_right = 0; info.mini_left = 0; info.mini_right = 0; if (EvalPartitionWorker(seg_list, part, best_cost, &info)) return -1; /* make sure there is at least one real seg on each side */ if (info.real_left == 0 || info.real_right == 0) { # if DEBUG_PICKNODE PrintDebug("Eval : No real segs on %s%sside\n", info.real_left ? "" : "left ", info.real_right ? "" : "right "); # endif return -1; } /* increase cost by the difference between left & right */ info.cost += 100 * ABS(info.real_left - info.real_right); // -AJA- allow miniseg counts to affect the outcome, but only to a // lesser degree than real segs. info.cost += 50 * ABS(info.mini_left - info.mini_right); // -AJA- Another little twist, here we show a slight preference for // partition lines that lie either purely horizontally or // purely vertically. if (part->pdx != 0 && part->pdy != 0) info.cost += 25; # if DEBUG_PICKNODE PrintDebug("Eval %p: splits=%d iffy=%d near=%d left=%d+%d right=%d+%d " "cost=%d.%02d\n", part, info.splits, info.iffy, info.near_miss, info.real_left, info.mini_left, info.real_right, info.mini_right, info.cost / 100, info.cost % 100); # endif return info.cost; } static seg_t *FindSegFromStaleNode(superblock_t *part_list, node_t *stale_nd, int *stale_opposite) { seg_t *part; int num; for (part=part_list->segs; part; part = part->next) { float_g fa, fb; /* ignore minisegs as partition candidates */ if (! part->linedef) continue; fa = fabs(UtilPerpDist(part, stale_nd->x, stale_nd->y)); fb = fabs(UtilPerpDist(part, stale_nd->x + stale_nd->dx, stale_nd->y + stale_nd->dy)); if (fa < DIST_EPSILON && fb < DIST_EPSILON) { /* OK found it. check if runs in same direction */ (*stale_opposite) = (stale_nd->dx * part->pdx + stale_nd->dy * part->pdy < 0) ? 1 : 0; return part; } } /* handle sub-blocks recursively */ for (num=0; num < 2; num++) { if (! part_list->subs[num]) continue; part = FindSegFromStaleNode(part_list->subs[num], stale_nd, stale_opposite); if (part) return part; } return NULL; } /* 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; } // // PickNode // // Find the best seg in the seg_list to use as a partition line. // seg_t *PickNode(superblock_t *seg_list, int depth, node_t ** stale_nd, int *stale_opposite) { 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 (*stale_nd && seg_list->real_num >= SEG_REUSE_THRESHHOLD) { best = FindSegFromStaleNode(seg_list, *stale_nd, stale_opposite); # if DEBUG_PICKNODE PrintDebug("PickNode: Trying stale node %p\n", best); # endif if (best && EvalPartition(seg_list, best, best_cost) < 0) { best = NULL; # if DEBUG_PICKNODE PrintDebug("PickNode: Stale node unsuitable !\n"); # endif } 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 Stale 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; } } (*stale_nd) = NULL; 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; } // // DivideOneSeg // // Apply the partition line to the given seg, taking the necessary // action (moving it into either the left list, right list, or // splitting it). // // -AJA- I have rewritten this routine based on the EvalPartition // routine above (which I've also reworked, heavily). I think // it is important that both these routines follow the exact // same logic when determining which segs should go left, right // or be split. // void DivideOneSeg(seg_t *cur, seg_t *part, superblock_t *left_list, superblock_t *right_list, intersection_t ** cut_list) { seg_t *new_seg; float_g x, y; /* get state of lines' relation to each other */ float_g a = UtilPerpDist(part, cur->psx, cur->psy); float_g b = UtilPerpDist(part, cur->pex, cur->pey); boolean_g self_ref = cur->linedef ? cur->linedef->self_ref : FALSE; if (cur->source_line == part->source_line) a = b = 0; /* check for being on the same line */ if (fabs(a) <= DIST_EPSILON && fabs(b) <= DIST_EPSILON) { AddIntersection(cut_list, cur->start, part, self_ref); AddIntersection(cut_list, cur->end, part, self_ref); // this seg runs along the same line as the partition. check // whether it goes in the same direction or the opposite. if (cur->pdx*part->pdx + cur->pdy*part->pdy < 0) { AddSegToSuper(left_list, cur); } else { AddSegToSuper(right_list, cur); } return; } /* check for right side */ if (a > -DIST_EPSILON && b > -DIST_EPSILON) { if (a < DIST_EPSILON) AddIntersection(cut_list, cur->start, part, self_ref); else if (b < DIST_EPSILON) AddIntersection(cut_list, cur->end, part, self_ref); AddSegToSuper(right_list, cur); return; } /* check for left side */ if (a < DIST_EPSILON && b < DIST_EPSILON) { if (a > -DIST_EPSILON) AddIntersection(cut_list, cur->start, part, self_ref); else if (b > -DIST_EPSILON) AddIntersection(cut_list, cur->end, part, self_ref); AddSegToSuper(left_list, cur); return; } // when we reach here, we have a and b non-zero and opposite sign, // hence this seg will be split by the partition line. ComputeIntersection(cur, part, a, b, &x, &y); new_seg = SplitSeg(cur, x, y); AddIntersection(cut_list, cur->end, part, self_ref); if (a < 0) { AddSegToSuper(left_list, cur); AddSegToSuper(right_list, new_seg); } else { AddSegToSuper(right_list, cur); AddSegToSuper(left_list, new_seg); } } // // SeparateSegs // void SeparateSegs(superblock_t *seg_list, seg_t *part, superblock_t *lefts, superblock_t *rights, intersection_t ** cut_list) { int num; while (seg_list->segs) { seg_t *cur = seg_list->segs; seg_list->segs = cur->next; cur->block = NULL; DivideOneSeg(cur, part, lefts, rights, cut_list); } // recursively handle sub-blocks for (num=0; num < 2; num++) { superblock_t *A = seg_list->subs[num]; if (A) { SeparateSegs(A, part, lefts, rights, cut_list); if (A->real_num + A->mini_num > 0) InternalError("SeparateSegs: child %d not empty !", num); FreeSuper(A); seg_list->subs[num] = NULL; } } seg_list->real_num = seg_list->mini_num = 0; } static void FindLimitWorker(superblock_t *block, bbox_t *bbox) { seg_t *cur; int num; for (cur=block->segs; cur; cur=cur->next) { float_g x1 = cur->start->x; float_g y1 = cur->start->y; float_g x2 = cur->end->x; float_g y2 = cur->end->y; int lx = (int) floor(MIN(x1, x2)); int ly = (int) floor(MIN(y1, y2)); int hx = (int) ceil(MAX(x1, x2)); int hy = (int) ceil(MAX(y1, y2)); if (lx < bbox->minx) bbox->minx = lx; if (ly < bbox->miny) bbox->miny = ly; if (hx > bbox->maxx) bbox->maxx = hx; if (hy > bbox->maxy) bbox->maxy = hy; } // recursive handle sub-blocks for (num=0; num < 2; num++) { if (block->subs[num]) FindLimitWorker(block->subs[num], bbox); } } // // FindLimits // // Find the limits from a list of segs, by stepping through the segs // and comparing the vertices at both ends. // void FindLimits(superblock_t *seg_list, bbox_t *bbox) { bbox->minx = bbox->miny = SHRT_MAX; bbox->maxx = bbox->maxy = SHRT_MIN; FindLimitWorker(seg_list, bbox); } // // AddMinisegs // void AddMinisegs(seg_t *part, superblock_t *left_list, superblock_t *right_list, intersection_t *cut_list) { intersection_t *cur, *next; seg_t *seg, *buddy; if (! cut_list) return; # if DEBUG_CUTLIST PrintDebug("CUT LIST:\n"); PrintDebug("PARTITION: (%1.1f,%1.1f) += (%1.1f,%1.1f)\n", part->psx, part->psy, part->pdx, part->pdy); for (cur=cut_list; cur; cur=cur->next) { PrintDebug(" Vertex %8X (%1.1f,%1.1f) Along %1.2f [%d/%d] %s\n", cur->vertex->index, cur->vertex->x, cur->vertex->y, cur->along_dist, cur->before ? cur->before->index : -1, cur->after ? cur->after->index : -1, cur->self_ref ? "SELFREF" : ""); } # endif // STEP 1: fix problems the intersection list... cur = cut_list; next = cur->next; while (cur && next) { float_g len = next->along_dist - cur->along_dist; if (len < -0.1) InternalError("Bad order in intersect list: %1.3f > %1.3f\n", cur->along_dist, next->along_dist); if (len > 0.2) { cur = next; next = cur->next; continue; } if (len > DIST_EPSILON) { PrintMiniWarn("Skipping very short seg (len=%1.3f) near (%1.1f,%1.1f)\n", len, cur->vertex->x, cur->vertex->y); } // merge the two intersections into one # if DEBUG_CUTLIST PrintDebug("Merging cut (%1.0f,%1.0f) [%d/%d] with %p (%1.0f,%1.0f) [%d/%d]\n", cur->vertex->x, cur->vertex->y, cur->before ? cur->before->index : -1, cur->after ? cur->after->index : -1, next->vertex, next->vertex->x, next->vertex->y, next->before ? next->before->index : -1, next->after ? next->after->index : -1); # endif if (cur->self_ref && !next->self_ref) { if (cur->before && next->before) cur->before = next->before; if (cur->after && next->after) cur->after = next->after; cur->self_ref = FALSE; } if (!cur->before && next->before) cur->before = next->before; if (!cur->after && next->after) cur->after = next->after; # if DEBUG_CUTLIST PrintDebug("---> merged (%1.0f,%1.0f) [%d/%d] %s\n", cur->vertex->x, cur->vertex->y, cur->before ? cur->before->index : -1, cur->after ? cur->after->index : -1, cur->self_ref ? "SELFREF" : ""); # endif // free the unused cut cur->next = next->next; next->next = quick_alloc_cuts; quick_alloc_cuts = next; next = cur->next; } // STEP 2: find connections in the intersection list... for (cur = cut_list; cur && cur->next; cur = cur->next) { next = cur->next; if (!cur->after && !next->before) continue; // check for some nasty OPEN/CLOSED or CLOSED/OPEN cases if (cur->after && !next->before) { if (!cur->self_ref && !cur->after->warned_unclosed) { PrintMiniWarn("Sector #%d is unclosed near (%1.1f,%1.1f)\n", cur->after->index, (cur->vertex->x + next->vertex->x) / 2.0, (cur->vertex->y + next->vertex->y) / 2.0); cur->after->warned_unclosed = 1; } continue; } else if (!cur->after && next->before) { if (!next->self_ref && !next->before->warned_unclosed) { PrintMiniWarn("Sector #%d is unclosed near (%1.1f,%1.1f)\n", next->before->index, (cur->vertex->x + next->vertex->x) / 2.0, (cur->vertex->y + next->vertex->y) / 2.0); next->before->warned_unclosed = 1; } continue; } // righteo, here we have definite open space. // do a sanity check on the sectors (just for good measure). if (cur->after != next->before) { if (!cur->self_ref && !next->self_ref) PrintMiniWarn("Sector mismatch: #%d (%1.1f,%1.1f) != #%d (%1.1f,%1.1f)\n", cur->after->index, cur->vertex->x, cur->vertex->y, next->before->index, next->vertex->x, next->vertex->y); // choose the non-self-referencing sector when we can if (cur->self_ref && !next->self_ref) { cur->after = next->before; } } // create the miniseg pair seg = NewSeg(); buddy = NewSeg(); seg->partner = buddy; buddy->partner = seg; seg->start = cur->vertex; seg->end = next->vertex; buddy->start = next->vertex; buddy->end = cur->vertex; // leave 'linedef' field as NULL. // leave 'side' as zero too (not needed for minisegs). seg->sector = buddy->sector = cur->after; seg->index = buddy->index = -1; seg->source_line = buddy->source_line = part->linedef; RecomputeSeg(seg); RecomputeSeg(buddy); // add the new segs to the appropriate lists AddSegToSuper(right_list, seg); AddSegToSuper(left_list, buddy); # if DEBUG_CUTLIST PrintDebug("AddMiniseg: %p RIGHT sector %d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg, seg->sector ? seg->sector->index : -1, seg->start->x, seg->start->y, seg->end->x, seg->end->y); PrintDebug("AddMiniseg: %p LEFT sector %d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", buddy, buddy->sector ? buddy->sector->index : -1, buddy->start->x, buddy->start->y, buddy->end->x, buddy->end->y); # endif } // free intersection structures into quick-alloc list while (cut_list) { cur = cut_list; cut_list = cur->next; cur->next = quick_alloc_cuts; quick_alloc_cuts = cur; } } glbsp-2.24-source/src/wad.h0000644000175000017500000001465210650404713015047 0ustar aaptedaapted//------------------------------------------------------------------------ // WAD : WAD read/write functions. //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_WAD_H__ #define __GLBSP_WAD_H__ #include "structs.h" #include "system.h" struct lump_s; // wad header typedef struct wad_s { // kind of wad file enum { IWAD, PWAD } kind; // number of entries in directory int num_entries; // offset to start of directory int dir_start; // current directory entries struct lump_s *dir_head; struct lump_s *dir_tail; // current level struct lump_s *current_level; // array of level names found const char ** level_names; int num_level_names; } wad_t; // level information typedef struct level_s { // various flags int flags; // the child lump list struct lump_s *children; // for normal levels, this is the associated GL level lump struct lump_s *buddy; // information on overflow int soft_limit; int hard_limit; int v5_switch; } level_t; /* this level information holds GL lumps */ #define LEVEL_IS_GL 0x0002 /* limit flags, to show what went wrong */ #define LIMIT_VERTEXES 0x000001 #define LIMIT_SECTORS 0x000002 #define LIMIT_SIDEDEFS 0x000004 #define LIMIT_LINEDEFS 0x000008 #define LIMIT_SEGS 0x000010 #define LIMIT_SSECTORS 0x000020 #define LIMIT_NODES 0x000040 #define LIMIT_GL_VERT 0x000100 #define LIMIT_GL_SEGS 0x000200 #define LIMIT_GL_SSECT 0x000400 #define LIMIT_GL_NODES 0x000800 #define LIMIT_BAD_SIDE 0x001000 #define LIMIT_BMAP_TRUNC 0x002000 #define LIMIT_BLOCKMAP 0x004000 #define LIMIT_ZDBSP 0x008000 // directory entry typedef struct lump_s { // link in list struct lump_s *next; struct lump_s *prev; // name of lump char *name; // offset to start of lump int start; int new_start; // length of lump int length; int space; // various flags int flags; // data of lump void *data; // level information, usually NULL level_t *lev_info; } lump_t; /* this lump should be copied from the input wad */ #define LUMP_COPY_ME 0x0004 /* this lump shouldn't be written to the output wad */ #define LUMP_IGNORE_ME 0x0008 /* this lump needs to be loaded */ #define LUMP_READ_ME 0x0100 /* this lump is new (didn't exist in the original) */ #define LUMP_NEW 0x0200 /* ----- function prototypes --------------------- */ // check if the filename has the given extension. Returns 1 if yes, // otherwise zero. // int CheckExtension(const char *filename, const char *ext); // remove any extension from the given filename, and add the given // extension, and return the newly creating filename. // char *ReplaceExtension(const char *filename, const char *ext); // open the input wad file and read the contents into memory. When // 'load_all' is false, lumps other than level info will be marked as // copyable instead of loaded. // // Returns GLBSP_E_OK if all went well, otherwise an error code (in // which case cur_comms->message has been set and all files/memory // have been freed). // glbsp_ret_e ReadWadFile(const char *filename); // open the output wad file and write the contents. Any lumps marked // as copyable will be copied from the input file instead of from // memory. Lumps marked as ignorable will be skipped. // // Returns GLBSP_E_OK if all went well, otherwise an error code (in // which case cur_comms->message has been set -- but no files/memory // are freed). // glbsp_ret_e WriteWadFile(const char *filename); // close all wad files and free any memory. void CloseWads(void); // delete the GWA file that is associated with the given normal // wad file. It doesn't have to exist. // void DeleteGwaFile(const char *base_wad_name); // returns the number of levels found in the wad. int CountLevels(void); // find the next level lump in the wad directory, and store the // reference in 'wad.current_level'. Call this straight after // ReadWadFile() to get the first level. Returns 1 if found, // otherwise 0 if there are no more levels in the wad. // int FindNextLevel(void); // return the current level name const char *GetLevelName(void); // find the level lump with the given name in the current level, and // return a reference to it. Returns NULL if no such lump exists. // Level lumps are always present in memory (i.e. never marked // copyable). // lump_t *FindLevelLump(const char *name); // tests if the level lump contains nothing but zeros. int CheckLevelLumpZero(lump_t *lump); // create a new lump in the current level with the given name. If // such a lump already exists, it is truncated to zero length. // lump_t *CreateLevelLump(const char *name); lump_t *CreateGLLump(const char *name); // append some raw data to the end of the given level lump (created // with the above function). // void AppendLevelLump(lump_t *lump, const void *data, int length); // for the current GL lump, add a keyword/value pair into the // level marker lump. void AddGLTextLine(const char *keyword, const char *value); // Zlib compression support void ZLibBeginLump(lump_t *lump); void ZLibAppendLump(const void *data, int length); void ZLibFinishLump(void); // mark the fact that this level failed to build. void MarkSoftFailure(int soft); void MarkHardFailure(int hard); void MarkV5Switch(int v5); void MarkZDSwitch(void); // alert the user if any levels failed to build properly. void ReportFailedLevels(void); /* ----- conversion macros ----------------------- */ #define UINT8(x) ((uint8_g) (x)) #define SINT8(x) ((sint8_g) (x)) #define UINT16(x) Endian_U16(x) #define UINT32(x) Endian_U32(x) #define SINT16(x) ((sint16_g) Endian_U16((uint16_g) (x))) #define SINT32(x) ((sint32_g) Endian_U32((uint32_g) (x))) #endif /* __GLBSP_WAD_H__ */ glbsp-2.24-source/src/reject.h0000644000175000017500000000213310650404703015536 0ustar aaptedaapted//------------------------------------------------------------------------ // REJECT : Generate the reject table //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_REJECT_H__ #define __GLBSP_REJECT_H__ #include "structs.h" #include "level.h" // build the reject table and write it into the REJECT lump void PutReject(void); #endif /* __GLBSP_REJECT_H__ */ glbsp-2.24-source/src/util.h0000644000175000017500000000570510650404710015245 0ustar aaptedaapted//------------------------------------------------------------------------ // UTILITY : general purpose functions //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_UTIL_H__ #define __GLBSP_UTIL_H__ /* ----- useful macros ---------------------------- */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifndef MAX #define MAX(x,y) ((x) > (y) ? (x) : (y)) #endif #ifndef MIN #define MIN(x,y) ((x) < (y) ? (x) : (y)) #endif #ifndef ABS #define ABS(x) ((x) >= 0 ? (x) : -(x)) #endif #ifndef I_ROUND #define I_ROUND(x) ((int) (((x) < 0.0f) ? ((x) - 0.5f) : ((x) + 0.5f))) #endif /* ----- function prototypes ---------------------------- */ // allocate and clear some memory. guaranteed not to fail. void *UtilCalloc(int size); // re-allocate some memory. guaranteed not to fail. void *UtilRealloc(void *old, int size); // duplicate a string. char *UtilStrDup(const char *str); char *UtilStrNDup(const char *str, int size); // format the string and return the allocated memory. // The memory must be freed with UtilFree. char *UtilFormat(const char *str, ...) GCCATTR((format (printf, 1, 2))); // free some memory or a string. void UtilFree(void *data); // compare two strings case insensitively. int UtilStrCaseCmp(const char *A, const char *B); // return an allocated string for the current data and time, // or NULL if an error occurred. char *UtilTimeString(void); // round a positive value up to the nearest power of two. int UtilRoundPOW2(int x); // compute angle & distance from (0,0) to (dx,dy) angle_g UtilComputeAngle(float_g dx, float_g dy); #define UtilComputeDist(dx,dy) sqrt((dx) * (dx) + (dy) * (dy)) // compute the parallel and perpendicular distances from a partition // line to a point. // #define UtilParallelDist(part,x,y) \ (((x) * (part)->pdx + (y) * (part)->pdy + (part)->p_para) \ / (part)->p_length) #define UtilPerpDist(part,x,y) \ (((x) * (part)->pdy - (y) * (part)->pdx + (part)->p_perp) \ / (part)->p_length) // check if the file exists. int UtilFileExists(const char *filename); // checksum functions void Adler32_Begin(uint32_g *crc); void Adler32_AddBlock(uint32_g *crc, const uint8_g *data, int length); void Adler32_Finish(uint32_g *crc); #endif /* __GLBSP_UTIL_H__ */ glbsp-2.24-source/src/seg.h0000644000175000017500000000776110650404703015054 0ustar aaptedaapted//------------------------------------------------------------------------ // SEG : Choose the best Seg to use for a node line. //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_SEG_H__ #define __GLBSP_SEG_H__ #include "structs.h" #define DEFAULT_FACTOR 11 #define IFFY_LEN 4.0 // smallest distance between two points before being considered equal #define DIST_EPSILON (1.0 / 128.0) // smallest degrees between two angles before being considered equal #define ANG_EPSILON (1.0 / 1024.0) // an "intersection" remembers the vertex that touches a BSP divider // line (especially a new vertex that is created at a seg split). typedef struct intersection_s { // link in list. The intersection list is kept sorted by // along_dist, in ascending order. struct intersection_s *next; struct intersection_s *prev; // vertex in question vertex_t *vertex; // how far along the partition line the vertex is. Zero is at the // partition seg's start point, positive values move in the same // direction as the partition's direction, and negative values move // in the opposite direction. float_g along_dist; // TRUE if this intersection was on a self-referencing linedef boolean_g self_ref; // sector on each side of the vertex (along the partition), // or NULL when that direction isn't OPEN. sector_t *before; sector_t *after; } intersection_t; /* -------- functions ---------------------------- */ // scan all the segs in the list, and choose the best seg to use as a // partition line, returning it. If no seg can be used, returns NULL. // The 'depth' parameter is the current depth in the tree, used for // computing the current progress. When stale_nd is not NULL, it can // be used to quickly find a matching seg -- but if none match, or it // is unsuitable, the pointer should be cleared. // seg_t *PickNode(superblock_t *seg_list, int depth, node_t ** stale_nd, int *stale_opposite); // compute the boundary of the list of segs void FindLimits(superblock_t *seg_list, bbox_t *bbox); // compute the seg private info (psx/y, pex/y, pdx/y, etc). void RecomputeSeg(seg_t *seg); // take the given seg 'cur', compare it with the partition line, and // determine it's fate: moving it into either the left or right lists // (perhaps both, when splitting it in two). Handles partners as // well. Updates the intersection list if the seg lies on or crosses // the partition line. // void DivideOneSeg(seg_t *cur, seg_t *part, superblock_t *left_list, superblock_t *right_list, intersection_t ** cut_list); // remove all the segs from the list, partitioning them into the left // or right lists based on the given partition line. Adds any // intersections onto the intersection list as it goes. // void SeparateSegs(superblock_t *seg_list, seg_t *part, superblock_t *left_list, superblock_t *right_list, intersection_t ** cut_list); // analyse the intersection list, and add any needed minisegs to the // given seg lists (one miniseg on each side). All the intersection // structures will be freed back into a quick-alloc list. // void AddMinisegs(seg_t *part, superblock_t *left_list, superblock_t *right_list, intersection_t *cut_list); // free the quick allocation cut list void FreeQuickAllocCuts(void); #endif /* __GLBSP_SEG_H__ */ glbsp-2.24-source/src/system.c0000644000175000017500000001326410650404710015606 0ustar aaptedaapted//------------------------------------------------------------------------ // SYSTEM : System specific code //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "system.h" #include #include #include #include #include #include #include #include #define DEBUG_ENABLED 0 #define DEBUGGING_FILE "gb_debug.txt" #define DEBUG_ENDIAN 0 static int cpu_big_endian = 0; #define SYS_MSG_BUFLEN 4000 static char message_buf[SYS_MSG_BUFLEN]; #if DEBUG_ENABLED static FILE *debug_fp = NULL; #endif // // FatalError // void FatalError(const char *str, ...) { va_list args; va_start(args, str); vsnprintf(message_buf, sizeof(message_buf), str, args); va_end(args); (* cur_funcs->fatal_error)("\nError: *** %s ***\n\n", message_buf); } // // InternalError // void InternalError(const char *str, ...) { va_list args; va_start(args, str); vsnprintf(message_buf, sizeof(message_buf), str, args); va_end(args); (* cur_funcs->fatal_error)("\nINTERNAL ERROR: *** %s ***\n\n", message_buf); } // // PrintMsg // void PrintMsg(const char *str, ...) { va_list args; va_start(args, str); vsnprintf(message_buf, sizeof(message_buf), str, args); va_end(args); (* cur_funcs->print_msg)("%s", message_buf); #if DEBUG_ENABLED PrintDebug(">>> %s", message_buf); #endif } // // PrintVerbose // void PrintVerbose(const char *str, ...) { va_list args; va_start(args, str); vsnprintf(message_buf, sizeof(message_buf), str, args); va_end(args); if (! cur_info->quiet) (* cur_funcs->print_msg)("%s", message_buf); #if DEBUG_ENABLED PrintDebug(">>> %s", message_buf); #endif } // // PrintWarn // void PrintWarn(const char *str, ...) { va_list args; va_start(args, str); vsnprintf(message_buf, sizeof(message_buf), str, args); va_end(args); (* cur_funcs->print_msg)("Warning: %s", message_buf); cur_comms->total_big_warn++; #if DEBUG_ENABLED PrintDebug("Warning: %s", message_buf); #endif } // // PrintMiniWarn // void PrintMiniWarn(const char *str, ...) { va_list args; va_start(args, str); vsnprintf(message_buf, sizeof(message_buf), str, args); va_end(args); if (cur_info->mini_warnings) (* cur_funcs->print_msg)("Warning: %s", message_buf); cur_comms->total_small_warn++; #if DEBUG_ENABLED PrintDebug("MiniWarn: %s", message_buf); #endif } // // SetErrorMsg // void SetErrorMsg(const char *str, ...) { va_list args; va_start(args, str); vsnprintf(message_buf, sizeof(message_buf), str, args); va_end(args); GlbspFree(cur_comms->message); cur_comms->message = GlbspStrDup(message_buf); } /* -------- debugging code ----------------------------- */ // // InitDebug // void InitDebug(void) { #if DEBUG_ENABLED debug_fp = fopen(DEBUGGING_FILE, "w"); if (! debug_fp) PrintWarn("Unable to open DEBUG FILE: %s\n", DEBUGGING_FILE); PrintDebug("=== START OF DEBUG FILE ===\n"); #endif } // // TermDebug // void TermDebug(void) { #if DEBUG_ENABLED if (debug_fp) { PrintDebug("=== END OF DEBUG FILE ===\n"); fclose(debug_fp); debug_fp = NULL; } #endif } // // PrintDebug // void PrintDebug(const char *str, ...) { #if DEBUG_ENABLED if (debug_fp) { va_list args; va_start(args, str); vfprintf(debug_fp, str, args); va_end(args); fflush(debug_fp); } #else (void) str; #endif } /* -------- endian code ----------------------------- */ // // InitEndian // // Parts inspired by the Yadex endian.cc code. // void InitEndian(void) { volatile union { uint8_g mem[32]; uint32_g val; } u; /* sanity-check type sizes */ if (sizeof(uint8_g) != 1) FatalError("Sanity check failed: sizeof(uint8_g) = %d", (int)sizeof(uint8_g)); if (sizeof(uint16_g) != 2) FatalError("Sanity check failed: sizeof(uint16_g) = %d", (int)sizeof(uint16_g)); if (sizeof(uint32_g) != 4) FatalError("Sanity check failed: sizeof(uint32_g) = %d", (int)sizeof(uint32_g)); /* check endianness */ memset((uint32_g *) u.mem, 0, sizeof(u.mem)); u.mem[0] = 0x70; u.mem[1] = 0x71; u.mem[2] = 0x72; u.mem[3] = 0x73; # if DEBUG_ENDIAN PrintDebug("Endianness magic value: 0x%08x\n", u.val); # endif if (u.val == 0x70717273) cpu_big_endian = 1; else if (u.val == 0x73727170) cpu_big_endian = 0; else FatalError("Sanity check failed: weird endianness (0x%08x)", u.val); # if DEBUG_ENDIAN PrintDebug("Endianness = %s\n", cpu_big_endian ? "BIG" : "LITTLE"); PrintDebug("Endianness check: 0x1234 --> 0x%04x\n", (int) Endian_U16(0x1234)); PrintDebug("Endianness check: 0x11223344 --> 0x%08x\n", Endian_U32(0x11223344)); # endif } // // Endian_U16 // uint16_g Endian_U16(uint16_g x) { if (cpu_big_endian) return (x >> 8) | (x << 8); else return x; } // // Endian_U32 // uint32_g Endian_U32(uint32_g x) { if (cpu_big_endian) return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24); else return x; } glbsp-2.24-source/src/node.c0000644000175000017500000007064510650662037015225 0ustar aaptedaapted//------------------------------------------------------------------------ // NODE : Recursively create nodes and return the pointers. //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Split a list of segs into two using the method described at bottom // of the file, this was taken from OBJECTS.C in the DEU5beta source. // // This is done by scanning all of the segs and finding the one that // does the least splitting and has the least difference in numbers of // segs on either side. // // If the ones on the left side make a SSector, then create another SSector // else put the segs into lefts list. // If the ones on the right side make a SSector, then create another SSector // else put the segs into rights list. // // Rewritten by Andrew Apted (-AJA-), 1999-2000. // #include "system.h" #include #include #include #include #include #include #include #include #include "analyze.h" #include "blockmap.h" #include "level.h" #include "node.h" #include "seg.h" #include "structs.h" #include "util.h" #include "wad.h" #define DEBUG_BUILDER 0 #define DEBUG_SORTER 0 #define DEBUG_SUBSEC 0 static superblock_t *quick_alloc_supers = NULL; // // PointOnLineSide // // Returns -1 for left, +1 for right, or 0 for intersect. // static int PointOnLineSide(seg_t *part, float_g x, float_g y) { float_g perp = UtilPerpDist(part, x, y); if (fabs(perp) <= DIST_EPSILON) return 0; return (perp < 0) ? -1 : +1; } // // BoxOnLineSide // int BoxOnLineSide(superblock_t *box, seg_t *part) { float_g x1 = (float_g)box->x1 - IFFY_LEN * 1.5; float_g y1 = (float_g)box->y1 - IFFY_LEN * 1.5; float_g x2 = (float_g)box->x2 + IFFY_LEN * 1.5; float_g y2 = (float_g)box->y2 + IFFY_LEN * 1.5; int p1, p2; // handle simple cases (vertical & horizontal lines) if (part->pdx == 0) { p1 = (x1 > part->psx) ? +1 : -1; p2 = (x2 > part->psx) ? +1 : -1; if (part->pdy < 0) { p1 = -p1; p2 = -p2; } } else if (part->pdy == 0) { p1 = (y1 < part->psy) ? +1 : -1; p2 = (y2 < part->psy) ? +1 : -1; if (part->pdx < 0) { p1 = -p1; p2 = -p2; } } // now handle the cases of positive and negative slope else if (part->pdx * part->pdy > 0) { p1 = PointOnLineSide(part, x1, y2); p2 = PointOnLineSide(part, x2, y1); } else // NEGATIVE { p1 = PointOnLineSide(part, x1, y1); p2 = PointOnLineSide(part, x2, y2); } if (p1 == p2) return p1; return 0; } /* ----- super block routines ------------------------------------ */ // // NewSuperBlock // static superblock_t *NewSuperBlock(void) { superblock_t *block; if (quick_alloc_supers == NULL) return UtilCalloc(sizeof(superblock_t)); block = quick_alloc_supers; quick_alloc_supers = block->subs[0]; // clear out any old rubbish memset(block, 0, sizeof(superblock_t)); return block; } // // FreeQuickAllocSupers // void FreeQuickAllocSupers(void) { while (quick_alloc_supers) { superblock_t *block = quick_alloc_supers; quick_alloc_supers = block->subs[0]; UtilFree(block); } } // // FreeSuper // void FreeSuper(superblock_t *block) { int num; if (block->segs) #if 0 // this can happen, but only under abnormal circumstances, in // particular when the node-building was cancelled by the GUI. InternalError("FreeSuper: block contains segs"); #else block->segs = NULL; #endif // recursively handle sub-blocks for (num=0; num < 2; num++) { if (block->subs[num]) FreeSuper(block->subs[num]); } // add block to quick-alloc list. Note that subs[0] is used for // linking the blocks together. block->subs[0] = quick_alloc_supers; quick_alloc_supers = block; } #if 0 // DEBUGGING CODE static void TestSuperWorker(superblock_t *block, int *real, int *mini) { seg_t *cur; int num; for (cur=block->segs; cur; cur=cur->next) { if (cur->linedef) (*real) += 1; else (*mini) += 1; } for (num=0; num < 2; num++) { if (block->subs[num]) TestSuperWorker(block->subs[num], real, mini); } } // // TestSuper // void TestSuper(superblock_t *block) { int real_num = 0; int mini_num = 0; TestSuperWorker(block, &real_num, &mini_num); if (real_num != block->real_num || mini_num != block->mini_num) InternalError("TestSuper FAILED: block=%p %d/%d != %d/%d", block, block->real_num, block->mini_num, real_num, mini_num); } #endif // // AddSegToSuper // void AddSegToSuper(superblock_t *block, seg_t *seg) { for (;;) { int p1, p2; int child; int x_mid = (block->x1 + block->x2) / 2; int y_mid = (block->y1 + block->y2) / 2; superblock_t *sub; // update seg counts if (seg->linedef) block->real_num++; else block->mini_num++; if (SUPER_IS_LEAF(block)) { // block is a leaf -- no subdivision possible seg->next = block->segs; seg->block = block; block->segs = seg; return; } if (block->x2 - block->x1 >= block->y2 - block->y1) { // block is wider than it is high, or square p1 = seg->start->x >= x_mid; p2 = seg->end->x >= x_mid; } else { // block is higher than it is wide p1 = seg->start->y >= y_mid; p2 = seg->end->y >= y_mid; } if (p1 && p2) child = 1; else if (!p1 && !p2) child = 0; else { // line crosses midpoint -- link it in and return seg->next = block->segs; seg->block = block; block->segs = seg; return; } // OK, the seg lies in one half of this block. Create the block // if it doesn't already exist, and loop back to add the seg. if (! block->subs[child]) { block->subs[child] = sub = NewSuperBlock(); sub->parent = block; if (block->x2 - block->x1 >= block->y2 - block->y1) { sub->x1 = child ? x_mid : block->x1; sub->y1 = block->y1; sub->x2 = child ? block->x2 : x_mid; sub->y2 = block->y2; } else { sub->x1 = block->x1; sub->y1 = child ? y_mid : block->y1; sub->x2 = block->x2; sub->y2 = child ? block->y2 : y_mid; } } block = block->subs[child]; } } // // SplitSegInSuper // void SplitSegInSuper(superblock_t *block, seg_t *seg) { do { // update seg counts if (seg->linedef) block->real_num++; else block->mini_num++; block = block->parent; } while (block != NULL); } static seg_t *CreateOneSeg(linedef_t *line, vertex_t *start, vertex_t *end, sidedef_t *side, int side_num) { seg_t *seg = NewSeg(); // check for bad sidedef if (! side->sector) { PrintWarn("Bad sidedef on linedef #%d (Z_CheckHeap error)\n", line->index); MarkSoftFailure(LIMIT_BAD_SIDE); } seg->start = start; seg->end = end; seg->linedef = line; seg->side = side_num; seg->sector = side->sector; seg->partner = NULL; seg->source_line = seg->linedef; seg->index = -1; RecomputeSeg(seg); return seg; } // // CreateSegs // // Initially create all segs, one for each linedef. Must be called // _after_ InitBlockmap(). // superblock_t *CreateSegs(void) { int i; int bw, bh; seg_t *left, *right; superblock_t *block; PrintVerbose("Creating Segs...\n"); block = NewSuperBlock(); GetBlockmapBounds(&block->x1, &block->y1, &bw, &bh); block->x2 = block->x1 + 128 * UtilRoundPOW2(bw); block->y2 = block->y1 + 128 * UtilRoundPOW2(bh); // step through linedefs and get side numbers DisplayTicker(); for (i=0; i < num_linedefs; i++) { linedef_t *line = LookupLinedef(i); right = NULL; // ignore zero-length lines if (line->zero_len) continue; // ignore overlapping lines if (line->overlap) continue; // ignore self-referencing lines (only when explicitly disabled) if (line->self_ref && cur_info->skip_self_ref) continue; // check for Humungously long lines if (ABS(line->start->x - line->end->x) >= 10000 || ABS(line->start->y - line->end->y) >= 10000) { if (UtilComputeDist(line->start->x - line->end->x, line->start->y - line->end->y) >= 30000) { PrintWarn("Linedef #%d is VERY long, it may cause problems\n", line->index); } } if (line->right) { right = CreateOneSeg(line, line->start, line->end, line->right, 0); AddSegToSuper(block, right); } else PrintWarn("Linedef #%d has no right sidedef!\n", line->index); if (line->left) { left = CreateOneSeg(line, line->end, line->start, line->left, 1); AddSegToSuper(block, left); if (right) { // -AJA- Partner segs. These always maintain a one-to-one // correspondence, so if one of the gets split, the // other one must be split too. left->partner = right; right->partner = left; } } else { if (line->two_sided) { PrintWarn("Linedef #%d is 2s but has no left sidedef\n", line->index); line->two_sided = 0; } // handle the 'One-Sided Window' trick if (line->window_effect) { seg_t *left = NewSeg(); left->start = line->end; left->end = line->start; left->side = 1; left->linedef = right->linedef; left->sector = line->window_effect; left->source_line = line; left->index = -1; RecomputeSeg(left); AddSegToSuper(block, left); left->partner = right; right->partner = left; } } } return block; } // // DetermineMiddle // static void DetermineMiddle(subsec_t *sub) { seg_t *cur; float_g mid_x=0, mid_y=0; int total=0; // compute middle coordinates for (cur=sub->seg_list; cur; cur=cur->next) { mid_x += cur->start->x + cur->end->x; mid_y += cur->start->y + cur->end->y; total += 2; } sub->mid_x = mid_x / total; sub->mid_y = mid_y / total; } // // ClockwiseOrder // // -AJA- Put the list of segs into clockwise order. // Uses the now famous "double bubble" sorter :). // static void ClockwiseOrder(subsec_t *sub) { seg_t *cur; seg_t ** array; seg_t *seg_buffer[32]; int i; int total = 0; int first = 0; int score = -1; # if DEBUG_SUBSEC PrintDebug("Subsec: Clockwising %d\n", sub->index); # endif // count segs and create an array to manipulate them for (cur=sub->seg_list; cur; cur=cur->next) total++; // use local array if small enough if (total <= 32) array = seg_buffer; else array = UtilCalloc(total * sizeof(seg_t *)); for (cur=sub->seg_list, i=0; cur; cur=cur->next, i++) array[i] = cur; if (i != total) InternalError("ClockwiseOrder miscounted."); // sort segs by angle (from the middle point to the start vertex). // The desired order (clockwise) means descending angles. i = 0; while (i+1 < total) { seg_t *A = array[i]; seg_t *B = array[i+1]; angle_g angle1, angle2; angle1 = UtilComputeAngle(A->start->x - sub->mid_x, A->start->y - sub->mid_y); angle2 = UtilComputeAngle(B->start->x - sub->mid_x, B->start->y - sub->mid_y); if (angle1 + ANG_EPSILON < angle2) { // swap 'em array[i] = B; array[i+1] = A; // bubble down if (i > 0) i--; } else { // bubble up i++; } } // choose the seg that will be first (the game engine will typically use // that to determine the sector). In particular, we don't like self // referencing linedefs (they are often used for deep-water effects). for (i=0; i < total; i++) { int cur_score = 3; if (! array[i]->linedef) cur_score = 0; else if (array[i]->linedef->window_effect) cur_score = 1; else if (array[i]->linedef->self_ref) cur_score = 2; if (cur_score > score) { first = i; score = cur_score; } } // transfer sorted array back into sub sub->seg_list = NULL; for (i=total-1; i >= 0; i--) { int j = (i + first) % total; array[j]->next = sub->seg_list; sub->seg_list = array[j]; } if (total > 32) UtilFree(array); # if DEBUG_SORTER PrintDebug("Sorted SEGS around (%1.1f,%1.1f)\n", sub->mid_x, sub->mid_y); for (cur=sub->seg_list; cur; cur=cur->next) { angle_g angle = UtilComputeAngle(cur->start->x - sub->mid_x, cur->start->y - sub->mid_y); PrintDebug(" Seg %p: Angle %1.6f (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", cur, angle, cur->start->x, cur->start->y, cur->end->x, cur->end->y); } # endif } // // SanityCheckClosed // static void SanityCheckClosed(subsec_t *sub) { seg_t *cur, *next; int total=0, gaps=0; for (cur=sub->seg_list; cur; cur=cur->next) { next = cur->next ? cur->next : sub->seg_list; if (cur->end->x != next->start->x || cur->end->y != next->start->y) gaps++; total++; } if (gaps > 0) { PrintMiniWarn("Subsector #%d near (%1.1f,%1.1f) is not closed " "(%d gaps, %d segs)\n", sub->index, sub->mid_x, sub->mid_y, gaps, total); # if DEBUG_SUBSEC for (cur=sub->seg_list; cur; cur=cur->next) { PrintDebug(" SEG %p (%1.1f,%1.1f) --> (%1.1f,%1.1f)\n", cur, cur->start->x, cur->start->y, cur->end->x, cur->end->y); } # endif } } // // SanityCheckSameSector // static void SanityCheckSameSector(subsec_t *sub) { seg_t *cur; seg_t *compare; // find a suitable seg for comparison for (compare=sub->seg_list; compare; compare=compare->next) { if (! compare->sector) continue; if (compare->sector->coalesce) continue; break; } if (! compare) return; for (cur=compare->next; cur; cur=cur->next) { if (! cur->sector) continue; if (cur->sector == compare->sector) continue; // All subsectors must come from same sector unless it's marked // "special" with sector tag >= 900. Original idea, Lee Killough if (cur->sector->coalesce) continue; // prevent excessive number of warnings if (compare->sector->warned_facing == cur->sector->index) continue; compare->sector->warned_facing = cur->sector->index; if (cur->linedef) PrintMiniWarn("Sector #%d has sidedef facing #%d (line #%d) " "near (%1.0f,%1.0f).\n", compare->sector->index, cur->sector->index, cur->linedef->index, sub->mid_x, sub->mid_y); else PrintMiniWarn("Sector #%d has sidedef facing #%d " "near (%1.0f,%1.0f).\n", compare->sector->index, cur->sector->index, sub->mid_x, sub->mid_y); } } // // SanityCheckHasRealSeg // static void SanityCheckHasRealSeg(subsec_t *sub) { seg_t *cur; for (cur=sub->seg_list; cur; cur=cur->next) { if (cur->linedef) return; } InternalError("Subsector #%d near (%1.1f,%1.1f) has no real seg !", sub->index, sub->mid_x, sub->mid_y); } // // RenumberSubsecSegs // static void RenumberSubsecSegs(subsec_t *sub) { seg_t *cur; # if DEBUG_SUBSEC PrintDebug("Subsec: Renumbering %d\n", sub->index); # endif sub->seg_count = 0; for (cur=sub->seg_list; cur; cur=cur->next) { cur->index = num_complete_seg; num_complete_seg++; sub->seg_count++; # if DEBUG_SUBSEC PrintDebug("Subsec: %d: Seg %p Index %d\n", sub->seg_count, cur, cur->index); # endif } } static void CreateSubsecWorker(subsec_t *sub, superblock_t *block) { int num; while (block->segs) { // unlink first seg from block seg_t *cur = block->segs; block->segs = cur->next; // link it into head of the subsector's list cur->next = sub->seg_list; cur->block = NULL; sub->seg_list = cur; } // recursively handle sub-blocks for (num=0; num < 2; num++) { superblock_t *A = block->subs[num]; if (A) { CreateSubsecWorker(sub, A); if (A->real_num + A->mini_num > 0) InternalError("CreateSubsec: child %d not empty !", num); FreeSuper(A); block->subs[num] = NULL; } } block->real_num = block->mini_num = 0; } // // CreateSubsec // // Create a subsector from a list of segs. // static subsec_t *CreateSubsec(superblock_t *seg_list) { subsec_t *sub = NewSubsec(); // compute subsector's index sub->index = num_subsecs - 1; // copy segs into subsector CreateSubsecWorker(sub, seg_list); DetermineMiddle(sub); # if DEBUG_SUBSEC PrintDebug("Subsec: Creating %d\n", sub->index); # endif return sub; } // // ComputeBspHeight // int ComputeBspHeight(node_t *node) { if (node) { int left, right; right = ComputeBspHeight(node->r.node); left = ComputeBspHeight(node->l.node); return MAX(left, right) + 1; } return 1; } #if DEBUG_BUILDER static void DebugShowSegs(superblock_t *seg_list) { seg_t *cur; int num; for (cur=seg_list->segs; cur; cur=cur->next) { PrintDebug("Build: %sSEG %p sector=%d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", cur->linedef ? "" : "MINI", cur, cur->sector->index, cur->start->x, cur->start->y, cur->end->x, cur->end->y); } for (num=0; num < 2; num++) { if (seg_list->subs[num]) DebugShowSegs(seg_list->subs[num]); } } #endif // // BuildNodes // glbsp_ret_e BuildNodes(superblock_t *seg_list, node_t ** N, subsec_t ** S, int depth, node_t *stale_nd) { node_t *node; seg_t *best; superblock_t *rights; superblock_t *lefts; intersection_t *cut_list; int stale_opposite = 0; glbsp_ret_e ret; *N = NULL; *S = NULL; if (cur_comms->cancelled) return GLBSP_E_Cancelled; # if DEBUG_BUILDER PrintDebug("Build: BEGUN @ %d\n", depth); DebugShowSegs(seg_list); # endif /* pick best node to use. None indicates convexicity */ best = PickNode(seg_list, depth, &stale_nd, &stale_opposite); if (best == NULL) { if (cur_comms->cancelled) return GLBSP_E_Cancelled; # if DEBUG_BUILDER PrintDebug("Build: CONVEX\n"); # endif *S = CreateSubsec(seg_list); return GLBSP_E_OK; } # if DEBUG_BUILDER PrintDebug("Build: PARTITION %p (%1.0f,%1.0f) -> (%1.0f,%1.0f)\n", best, best->start->x, best->start->y, best->end->x, best->end->y); # endif /* create left and right super blocks */ lefts = (superblock_t *) NewSuperBlock(); rights = (superblock_t *) NewSuperBlock(); lefts->x1 = rights->x1 = seg_list->x1; lefts->y1 = rights->y1 = seg_list->y1; lefts->x2 = rights->x2 = seg_list->x2; lefts->y2 = rights->y2 = seg_list->y2; /* divide the segs into two lists: left & right */ cut_list = NULL; SeparateSegs(seg_list, best, lefts, rights, &cut_list); /* sanity checks... */ if (rights->real_num + rights->mini_num == 0) InternalError("Separated seg-list has no RIGHT side"); if (lefts->real_num + lefts->mini_num == 0) InternalError("Separated seg-list has no LEFT side"); DisplayTicker(); AddMinisegs(best, lefts, rights, cut_list); *N = node = NewNode(); assert(best->linedef); if (best->side == 0) { node->x = best->linedef->start->x; node->y = best->linedef->start->y; node->dx = best->linedef->end->x - node->x; node->dy = best->linedef->end->y - node->y; } else /* left side */ { node->x = best->linedef->end->x; node->y = best->linedef->end->y; node->dx = best->linedef->start->x - node->x; node->dy = best->linedef->start->y - node->y; } /* check for really long partition (overflows dx,dy in NODES) */ if (best->p_length >= 30000) { if (node->dx && node->dy && ((node->dx & 1) || (node->dy & 1))) { PrintMiniWarn("Loss of accuracy on VERY long node: " "(%d,%d) -> (%d,%d)\n", node->x, node->y, node->x + node->dx, node->y + node->dy); } node->too_long = 1; } /* find limits of vertices */ FindLimits(lefts, &node->l.bounds); FindLimits(rights, &node->r.bounds); # if DEBUG_BUILDER PrintDebug("Build: Going LEFT\n"); # endif ret = BuildNodes(lefts, &node->l.node, &node->l.subsec, depth+1, stale_nd ? (stale_opposite ? stale_nd->r.node : stale_nd->l.node) : NULL); FreeSuper(lefts); if (ret != GLBSP_E_OK) { FreeSuper(rights); return ret; } # if DEBUG_BUILDER PrintDebug("Build: Going RIGHT\n"); # endif ret = BuildNodes(rights, &node->r.node, &node->r.subsec, depth+1, stale_nd ? (stale_opposite ? stale_nd->l.node : stale_nd->r.node) : NULL); FreeSuper(rights); # if DEBUG_BUILDER PrintDebug("Build: DONE\n"); # endif return ret; } // // ClockwiseBspTree // void ClockwiseBspTree(node_t *root) { int i; (void) root; DisplayTicker(); for (i=0; i < num_subsecs; i++) { subsec_t *sub = LookupSubsec(i); ClockwiseOrder(sub); RenumberSubsecSegs(sub); // do some sanity checks SanityCheckClosed(sub); SanityCheckSameSector(sub); SanityCheckHasRealSeg(sub); } } static void NormaliseSubsector(subsec_t *sub) { seg_t *new_head = NULL; seg_t *new_tail = NULL; # if DEBUG_SUBSEC PrintDebug("Subsec: Normalising %d\n", sub->index); # endif while (sub->seg_list) { // remove head seg_t *cur = sub->seg_list; sub->seg_list = cur->next; // only add non-minisegs to new list if (cur->linedef) { cur->next = NULL; if (new_tail) new_tail->next = cur; else new_head = cur; new_tail = cur; // this updated later cur->index = -1; } else { # if DEBUG_SUBSEC PrintDebug("Subsec: Removing miniseg %p\n", cur); # endif // set index to a really high value, so that SortSegs() will // move all the minisegs to the top of the seg array. cur->index = 1<<24; } } if (new_head == NULL) InternalError("Subsector %d normalised to being EMPTY", sub->index); sub->seg_list = new_head; } // // NormaliseBspTree // void NormaliseBspTree(node_t *root) { int i; (void) root; DisplayTicker(); // unlink all minisegs from each subsector: num_complete_seg = 0; for (i=0; i < num_subsecs; i++) { subsec_t *sub = LookupSubsec(i); NormaliseSubsector(sub); RenumberSubsecSegs(sub); } } static void RoundOffSubsector(subsec_t *sub) { seg_t *new_head = NULL; seg_t *new_tail = NULL; seg_t *cur; seg_t *last_real_degen = NULL; int real_total = 0; int degen_total = 0; # if DEBUG_SUBSEC PrintDebug("Subsec: Rounding off %d\n", sub->index); # endif // do an initial pass, just counting the degenerates for (cur=sub->seg_list; cur; cur=cur->next) { // handle the duplex vertices if (cur->start->normal_dup) cur->start = cur->start->normal_dup; if (cur->end->normal_dup) cur->end = cur->end->normal_dup; // is the seg degenerate ? if (I_ROUND(cur->start->x) == I_ROUND(cur->end->x) && I_ROUND(cur->start->y) == I_ROUND(cur->end->y)) { cur->degenerate = 1; if (cur->linedef) last_real_degen = cur; degen_total++; continue; } if (cur->linedef) real_total++; } # if DEBUG_SUBSEC PrintDebug("Subsec: degen=%d real=%d\n", degen_total, real_total); # endif // handle the (hopefully rare) case where all of the real segs // became degenerate. if (real_total == 0) { if (last_real_degen == NULL) InternalError("Subsector %d rounded off with NO real segs", sub->index); # if DEBUG_SUBSEC PrintDebug("Degenerate before: (%1.2f,%1.2f) -> (%1.2f,%1.2f)\n", last_real_degen->start->x, last_real_degen->start->y, last_real_degen->end->x, last_real_degen->end->y); # endif // create a new vertex for this baby last_real_degen->end = NewVertexDegenerate(last_real_degen->start, last_real_degen->end); # if DEBUG_SUBSEC PrintDebug("Degenerate after: (%d,%d) -> (%d,%d)\n", I_ROUND(last_real_degen->start->x), I_ROUND(last_real_degen->start->y), I_ROUND(last_real_degen->end->x), I_ROUND(last_real_degen->end->y)); # endif last_real_degen->degenerate = 0; } // second pass, remove the blighters... while (sub->seg_list) { // remove head cur = sub->seg_list; sub->seg_list = cur->next; if (! cur->degenerate) { cur->next = NULL; if (new_tail) new_tail->next = cur; else new_head = cur; new_tail = cur; // this updated later cur->index = -1; } else { # if DEBUG_SUBSEC PrintDebug("Subsec: Removing degenerate %p\n", cur); # endif // set index to a really high value, so that SortSegs() will // move all the minisegs to the top of the seg array. cur->index = 1<<24; } } if (new_head == NULL) InternalError("Subsector %d rounded off to being EMPTY", sub->index); sub->seg_list = new_head; } // // RoundOffBspTree // void RoundOffBspTree(node_t *root) { int i; (void) root; num_complete_seg = 0; DisplayTicker(); for (i=0; i < num_subsecs; i++) { subsec_t *sub = LookupSubsec(i); RoundOffSubsector(sub); RenumberSubsecSegs(sub); } } //--------------------------------------------------------------------------- // // This message has been taken, complete, from OBJECTS.C in DEU5beta // source. It outlines the method used here to pick the nodelines. // // IF YOU ARE WRITING A DOOM EDITOR, PLEASE READ THIS: // // I spent a lot of time writing the Nodes builder. There are some bugs in // it, but most of the code is OK. If you steal any ideas from this program, // put a prominent message in your own editor to make it CLEAR that some // original ideas were taken from DEU. Thanks. // // While everyone was talking about LineDefs, I had the idea of taking only // the Segs into account, and creating the Segs directly from the SideDefs. // Also, dividing the list of Segs in two after each call to CreateNodes makes // the algorithm faster. I use several other tricks, such as looking at the // two ends of a Seg to see on which side of the nodeline it lies or if it // should be split in two. I took me a lot of time and efforts to do this. // // I give this algorithm to whoever wants to use it, but with this condition: // if your program uses some of the ideas from DEU or the whole algorithm, you // MUST tell it to the user. And if you post a message with all or parts of // this algorithm in it, please post this notice also. I don't want to speak // legalese; I hope that you understand me... I kindly give the sources of my // program to you: please be kind with me... // // If you need more information about this, here is my E-mail address: // Raphael.Quinet@eed.ericsson.se (Raphael Quinet). // // Short description of the algorithm: // 1 - Create one Seg for each SideDef: pick each LineDef in turn. If it // has a "first" SideDef, then create a normal Seg. If it has a // "second" SideDef, then create a flipped Seg. // 2 - Call CreateNodes with the current list of Segs. The list of Segs is // the only argument to CreateNodes. // 3 - Save the Nodes, Segs and SSectors to disk. Start with the leaves of // the Nodes tree and continue up to the root (last Node). // // CreateNodes does the following: // 1 - Pick a nodeline amongst the Segs (minimize the number of splits and // keep the tree as balanced as possible). // 2 - Move all Segs on the right of the nodeline in a list (segs1) and do // the same for all Segs on the left of the nodeline (in segs2). // 3 - If the first list (segs1) contains references to more than one // Sector or if the angle between two adjacent Segs is greater than // 180 degrees, then call CreateNodes with this (smaller) list. // Else, create a SubSector with all these Segs. // 4 - Do the same for the second list (segs2). // 5 - Return the new node (its two children are already OK). // // Each time CreateSSector is called, the Segs are put in a global list. // When there is no more Seg in CreateNodes' list, then they are all in the // global list and ready to be saved to disk. // glbsp-2.24-source/src/blockmap.c0000644000175000017500000003203610651274555016065 0ustar aaptedaapted//------------------------------------------------------------------------ // BLOCKMAP : Generate the blockmap //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "system.h" #include #include #include #include #include #include #include #include #include "blockmap.h" #include "level.h" #include "node.h" #include "seg.h" #include "structs.h" #include "util.h" #include "wad.h" #define DEBUG_BLOCKMAP 0 static int block_x, block_y; static int block_w, block_h; static int block_count; static int block_mid_x = 0; static int block_mid_y = 0; static uint16_g ** block_lines; static uint16_g *block_ptrs; static uint16_g *block_dups; static int block_compression; static int block_overflowed; #define DUMMY_DUP 0xFFFF // // GetBlockmapBounds // void GetBlockmapBounds(int *x, int *y, int *w, int *h) { *x = block_x; *y = block_y; *w = block_w; *h = block_h; } // // CheckLinedefInsideBox // int CheckLinedefInsideBox(int xmin, int ymin, int xmax, int ymax, int x1, int y1, int x2, int y2) { int count = 2; int tmp; for (;;) { if (y1 > ymax) { if (y2 > ymax) return FALSE; x1 = x1 + (int) ((x2-x1) * (double)(ymax-y1) / (double)(y2-y1)); y1 = ymax; count = 2; continue; } if (y1 < ymin) { if (y2 < ymin) return FALSE; x1 = x1 + (int) ((x2-x1) * (double)(ymin-y1) / (double)(y2-y1)); y1 = ymin; count = 2; continue; } if (x1 > xmax) { if (x2 > xmax) return FALSE; y1 = y1 + (int) ((y2-y1) * (double)(xmax-x1) / (double)(x2-x1)); x1 = xmax; count = 2; continue; } if (x1 < xmin) { if (x2 < xmin) return FALSE; y1 = y1 + (int) ((y2-y1) * (double)(xmin-x1) / (double)(x2-x1)); x1 = xmin; count = 2; continue; } count--; if (count == 0) break; /* swap end points */ tmp=x1; x1=x2; x2=tmp; tmp=y1; y1=y2; y2=tmp; } /* linedef touches block */ return TRUE; } /* ----- create blockmap ------------------------------------ */ #define BK_NUM 0 #define BK_MAX 1 #define BK_XOR 2 #define BK_FIRST 3 #define BK_QUANTUM 32 static void BlockAdd(int blk_num, int line_index) { uint16_g *cur = block_lines[blk_num]; # if DEBUG_BLOCKMAP PrintDebug("Block %d has line %d\n", blk_num, line_index); # endif if (blk_num < 0 || blk_num >= block_count) InternalError("BlockAdd: bad block number %d", blk_num); if (! cur) { // create empty block block_lines[blk_num] = cur = UtilCalloc(BK_QUANTUM * sizeof(uint16_g)); cur[BK_NUM] = 0; cur[BK_MAX] = BK_QUANTUM; cur[BK_XOR] = 0x1234; } if (BK_FIRST + cur[BK_NUM] == cur[BK_MAX]) { // no more room, so allocate some more... cur[BK_MAX] += BK_QUANTUM; block_lines[blk_num] = cur = UtilRealloc(cur, cur[BK_MAX] * sizeof(uint16_g)); } // compute new checksum cur[BK_XOR] = ((cur[BK_XOR] << 4) | (cur[BK_XOR] >> 12)) ^ line_index; cur[BK_FIRST + cur[BK_NUM]] = UINT16(line_index); cur[BK_NUM]++; } static void BlockAddLine(linedef_t *L) { int x1 = (int) L->start->x; int y1 = (int) L->start->y; int x2 = (int) L->end->x; int y2 = (int) L->end->y; int bx1 = (MIN(x1,x2) - block_x) / 128; int by1 = (MIN(y1,y2) - block_y) / 128; int bx2 = (MAX(x1,x2) - block_x) / 128; int by2 = (MAX(y1,y2) - block_y) / 128; int bx, by; int line_index = L->index; # if DEBUG_BLOCKMAP PrintDebug("BlockAddLine: %d (%d,%d) -> (%d,%d)\n", line_index, x1, y1, x2, y2); # endif // handle truncated blockmaps if (bx1 < 0) bx1 = 0; if (by1 < 0) by1 = 0; if (bx2 >= block_w) bx2 = block_w - 1; if (by2 >= block_h) by2 = block_h - 1; if (bx2 < bx1 || by2 < by1) return; // handle simple case #1: completely horizontal if (by1 == by2) { for (bx=bx1; bx <= bx2; bx++) { int blk_num = by1 * block_w + bx; BlockAdd(blk_num, line_index); } return; } // handle simple case #2: completely vertical if (bx1 == bx2) { for (by=by1; by <= by2; by++) { int blk_num = by * block_w + bx1; BlockAdd(blk_num, line_index); } return; } // handle the rest (diagonals) for (by=by1; by <= by2; by++) for (bx=bx1; bx <= bx2; bx++) { int blk_num = by * block_w + bx; int minx = block_x + bx * 128; int miny = block_y + by * 128; int maxx = minx + 127; int maxy = miny + 127; if (CheckLinedefInsideBox(minx, miny, maxx, maxy, x1, y1, x2, y2)) { BlockAdd(blk_num, line_index); } } } static void CreateBlockmap(void) { int i; block_lines = UtilCalloc(block_count * sizeof(uint16_g *)); DisplayTicker(); for (i=0; i < num_linedefs; i++) { linedef_t *L = LookupLinedef(i); // ignore zero-length lines if (L->zero_len) continue; BlockAddLine(L); } } static int BlockCompare(const void *p1, const void *p2) { int blk_num1 = ((const uint16_g *) p1)[0]; int blk_num2 = ((const uint16_g *) p2)[0]; const uint16_g *A = block_lines[blk_num1]; const uint16_g *B = block_lines[blk_num2]; if (A == B) return 0; if (A == NULL) return -1; if (B == NULL) return +1; if (A[BK_NUM] != B[BK_NUM]) { return A[BK_NUM] - B[BK_NUM]; } if (A[BK_XOR] != B[BK_XOR]) { return A[BK_XOR] - B[BK_XOR]; } return memcmp(A+BK_FIRST, B+BK_FIRST, A[BK_NUM] * sizeof(uint16_g)); } static void CompressBlockmap(void) { int i; int cur_offset; int dup_count=0; int orig_size, new_size; block_ptrs = UtilCalloc(block_count * sizeof(uint16_g)); block_dups = UtilCalloc(block_count * sizeof(uint16_g)); DisplayTicker(); // sort duplicate-detecting array. After the sort, all duplicates // will be next to each other. The duplicate array gives the order // of the blocklists in the BLOCKMAP lump. for (i=0; i < block_count; i++) block_dups[i] = i; qsort(block_dups, block_count, sizeof(uint16_g), BlockCompare); // scan duplicate array and build up offset array cur_offset = 4 + block_count + 2; orig_size = 4 + block_count; new_size = cur_offset; DisplayTicker(); for (i=0; i < block_count; i++) { int blk_num = block_dups[i]; int count; // empty block ? if (block_lines[blk_num] == NULL) { block_ptrs[blk_num] = 4 + block_count; block_dups[i] = DUMMY_DUP; orig_size += 2; continue; } count = 2 + block_lines[blk_num][BK_NUM]; // duplicate ? Only the very last one of a sequence of duplicates // will update the current offset value. if (i+1 < block_count && BlockCompare(block_dups + i, block_dups + i+1) == 0) { block_ptrs[blk_num] = cur_offset; block_dups[i] = DUMMY_DUP; // free the memory of the duplicated block UtilFree(block_lines[blk_num]); block_lines[blk_num] = NULL; dup_count++; orig_size += count; continue; } // OK, this block is either the last of a series of duplicates, or // just a singleton. block_ptrs[blk_num] = cur_offset; cur_offset += count; orig_size += count; new_size += count; } if (cur_offset > 65535) { MarkSoftFailure(LIMIT_BLOCKMAP); block_overflowed = TRUE; return; } # if DEBUG_BLOCKMAP PrintDebug("Blockmap: Last ptr = %d duplicates = %d\n", cur_offset, dup_count); # endif block_compression = (orig_size - new_size) * 100 / orig_size; // there's a tiny chance of new_size > orig_size if (block_compression < 0) block_compression = 0; } static void WriteBlockmap(void) { int i; raw_blockmap_header_t header; lump_t *lump = CreateLevelLump("BLOCKMAP"); uint16_g null_block[2] = { 0x0000, 0xFFFF }; uint16_g m_zero = 0x0000; uint16_g m_neg1 = 0xFFFF; // leave empty if the blockmap overflowed if (block_overflowed) return; // fill in header header.x_origin = UINT16(block_x); header.y_origin = UINT16(block_y); header.x_blocks = UINT16(block_w); header.y_blocks = UINT16(block_h); AppendLevelLump(lump, &header, sizeof(header)); // handle pointers for (i=0; i < block_count; i++) { uint16_g ptr = UINT16(block_ptrs[i]); if (ptr == 0) InternalError("WriteBlockmap: offset %d not set.", i); AppendLevelLump(lump, &ptr, sizeof(uint16_g)); } // add the null block which _all_ empty blocks will use AppendLevelLump(lump, null_block, sizeof(null_block)); // handle each block list for (i=0; i < block_count; i++) { int blk_num = block_dups[i]; uint16_g *blk; // ignore duplicate or empty blocks if (blk_num == DUMMY_DUP) continue; blk = block_lines[blk_num]; if (blk == NULL) InternalError("WriteBlockmap: block %d is NULL !", i); AppendLevelLump(lump, &m_zero, sizeof(uint16_g)); AppendLevelLump(lump, blk + BK_FIRST, blk[BK_NUM] * sizeof(uint16_g)); AppendLevelLump(lump, &m_neg1, sizeof(uint16_g)); } } static void FreeBlockmap(void) { int i; for (i=0; i < block_count; i++) { if (block_lines[i]) UtilFree(block_lines[i]); } UtilFree(block_lines); UtilFree(block_ptrs); UtilFree(block_dups); } /* ----- top level funcs ------------------------------------ */ static void FindBlockmapLimits(bbox_t *bbox) { int i; int mid_x = 0; int mid_y = 0; bbox->minx = bbox->miny = SHRT_MAX; bbox->maxx = bbox->maxy = SHRT_MIN; for (i=0; i < num_linedefs; i++) { linedef_t *L = LookupLinedef(i); if (! L->zero_len) { float_g x1 = L->start->x; float_g y1 = L->start->y; float_g x2 = L->end->x; float_g y2 = L->end->y; int lx = (int)floor(MIN(x1, x2)); int ly = (int)floor(MIN(y1, y2)); int hx = (int)ceil(MAX(x1, x2)); int hy = (int)ceil(MAX(y1, y2)); if (lx < bbox->minx) bbox->minx = lx; if (ly < bbox->miny) bbox->miny = ly; if (hx > bbox->maxx) bbox->maxx = hx; if (hy > bbox->maxy) bbox->maxy = hy; // compute middle of cluster (roughly, so we don't overflow) mid_x += (lx + hx) / 32; mid_y += (ly + hy) / 32; } } if (num_linedefs > 0) { block_mid_x = (mid_x / num_linedefs) * 16; block_mid_y = (mid_y / num_linedefs) * 16; } # if DEBUG_BLOCKMAP PrintDebug("Blockmap lines centered at (%d,%d)\n", block_mid_x, block_mid_y); # endif } // // TruncateBlockmap // static void TruncateBlockmap(void) { while (block_w * block_h > cur_info->block_limit) { block_w -= block_w / 8; block_h -= block_h / 8; } block_count = block_w * block_h; PrintMiniWarn("Blockmap TOO LARGE! Truncated to %dx%d blocks\n", block_w, block_h); MarkSoftFailure(LIMIT_BMAP_TRUNC); /* center the truncated blockmap */ block_x = block_mid_x - block_w * 64; block_y = block_mid_y - block_h * 64; # if DEBUG_BLOCKMAP PrintDebug("New blockmap origin: (%d,%d)\n", block_x, block_y); # endif } // // InitBlockmap // void InitBlockmap(void) { bbox_t map_bbox; /* find limits of linedefs, and store as map limits */ FindBlockmapLimits(&map_bbox); PrintVerbose("Map goes from (%d,%d) to (%d,%d)\n", map_bbox.minx, map_bbox.miny, map_bbox.maxx, map_bbox.maxy); block_x = map_bbox.minx - (map_bbox.minx & 0x7); block_y = map_bbox.miny - (map_bbox.miny & 0x7); block_w = ((map_bbox.maxx - block_x) / 128) + 1; block_h = ((map_bbox.maxy - block_y) / 128) + 1; block_count = block_w * block_h; } // // PutBlockmap // void PutBlockmap(void) { block_overflowed = FALSE; // truncate blockmap if too large. We're limiting the number of // blocks to around 16000 (user changeable), this leaves about 48K // of shorts for the actual line lists. if (block_count > cur_info->block_limit) TruncateBlockmap(); // initial phase: create internal blockmap containing the index of // all lines in each block. CreateBlockmap(); // -AJA- second phase: compress the blockmap. We do this by sorting // the blocks, which is a typical way to detect duplicates in // a large list. CompressBlockmap(); // final phase: write it out in the correct format WriteBlockmap(); if (block_overflowed) PrintVerbose("Blockmap overflowed (lump will be empty)\n"); else PrintVerbose("Completed blockmap, size %dx%d (compression: %d%%)\n", block_w, block_h, block_compression); FreeBlockmap(); } glbsp-2.24-source/src/system.h0000644000175000017500000000520710650404710015611 0ustar aaptedaapted//------------------------------------------------------------------------ // SYSTEM : Bridging code //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_SYSTEM_H__ #define __GLBSP_SYSTEM_H__ #include "glbsp.h" // use this for inlining. Usually defined in the makefile. #ifndef INLINE_G #define INLINE_G /* nothing */ #endif // internal storage of node building parameters extern const nodebuildinfo_t *cur_info; extern const nodebuildfuncs_t *cur_funcs; extern volatile nodebuildcomms_t *cur_comms; /* ----- function prototypes ---------------------------- */ // fatal error messages (these don't return) void FatalError(const char *str, ...) GCCATTR((format (printf, 1, 2))); void InternalError(const char *str, ...) GCCATTR((format (printf, 1, 2))); // display normal messages & warnings to the screen void PrintMsg(const char *str, ...) GCCATTR((format (printf, 1, 2))); void PrintVerbose(const char *str, ...) GCCATTR((format (printf, 1, 2))); void PrintWarn(const char *str, ...) GCCATTR((format (printf, 1, 2))); void PrintMiniWarn(const char *str, ...) GCCATTR((format (printf, 1, 2))); // set message for certain errors void SetErrorMsg(const char *str, ...) GCCATTR((format (printf, 1, 2))); // endian handling void InitEndian(void); uint16_g Endian_U16(uint16_g); uint32_g Endian_U32(uint32_g); // these are only used for debugging void InitDebug(void); void TermDebug(void); void PrintDebug(const char *str, ...) GCCATTR((format (printf, 1, 2))); // macros for the display stuff #define DisplayOpen (* cur_funcs->display_open) #define DisplaySetTitle (* cur_funcs->display_setTitle) #define DisplaySetBar (* cur_funcs->display_setBar) #define DisplaySetBarLimit (* cur_funcs->display_setBarLimit) #define DisplaySetBarText (* cur_funcs->display_setBarText) #define DisplayClose (* cur_funcs->display_close) #define DisplayTicker (* cur_funcs->ticker) #endif /* __GLBSP_SYSTEM_H__ */ glbsp-2.24-source/src/node.h0000644000175000017500000000616110650404703015214 0ustar aaptedaapted//------------------------------------------------------------------------ // NODE : Recursively create nodes and return the pointers. //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_NODE_H__ #define __GLBSP_NODE_H__ #include "structs.h" // check the relationship between the given box and the partition // line. Returns -1 if box is on left side, +1 if box is on right // size, or 0 if the line intersects the box. // int BoxOnLineSide(superblock_t *box, seg_t *part); // add the seg to the given list void AddSegToSuper(superblock_t *block, seg_t *seg); // increase the counts within the superblock, to account for the given // seg being split. // void SplitSegInSuper(superblock_t *block, seg_t *seg); // scan all the linedef of the level and convert each sidedef into a // seg (or seg pair). Returns the list of segs. // superblock_t *CreateSegs(void); // free a super block. void FreeSuper(superblock_t *block); // takes the seg list and determines if it is convex. When it is, the // segs are converted to a subsector, and '*S' is the new subsector // (and '*N' is set to NULL). Otherwise the seg list is divided into // two halves, a node is created by calling this routine recursively, // and '*N' is the new node (and '*S' is set to NULL). Normally // returns GLBSP_E_OK, or GLBSP_E_Cancelled if user stopped it. // glbsp_ret_e BuildNodes(superblock_t *seg_list, node_t ** N, subsec_t ** S, int depth, node_t *stale_nd); // compute the height of the bsp tree, starting at 'node'. int ComputeBspHeight(node_t *node); // traverse the BSP tree and put all the segs in each subsector into // clockwise order, and renumber the seg indices. This cannot be done // DURING BuildNodes() since splitting a seg with a partner may insert // another seg into that partner's list -- usually in the wrong place // order-wise. // void ClockwiseBspTree(node_t *root); // traverse the BSP tree and do whatever is necessary to convert the // node information from GL standard to normal standard (for example, // removing minisegs). // void NormaliseBspTree(node_t *root); // traverse the BSP tree, doing whatever is necessary to round // vertices to integer coordinates (for example, removing segs whose // rounded coordinates degenerate to the same point). // void RoundOffBspTree(node_t *root); // free all the superblocks on the quick-alloc list void FreeQuickAllocSupers(void); #endif /* __GLBSP_NODE_H__ */ glbsp-2.24-source/src/blockmap.h0000644000175000017500000000270710651274541016067 0ustar aaptedaapted//------------------------------------------------------------------------ // BLOCKMAP : Generate the blockmap //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __GLBSP_BLOCKMAP_H__ #define __GLBSP_BLOCKMAP_H__ #include "structs.h" #include "level.h" #define DEFAULT_BLOCK_LIMIT 16000 // compute blockmap origin & size (the block_x/y/w/h variables) // based on the set of loaded linedefs. // void InitBlockmap(void); // build the blockmap and write the data into the BLOCKMAP lump void PutBlockmap(void); // utility routines... void GetBlockmapBounds(int *x, int *y, int *w, int *h); int CheckLinedefInsideBox(int xmin, int ymin, int xmax, int ymax, int x1, int y1, int x2, int y2); #endif /* __GLBSP_BLOCKMAP_H__ */ glbsp-2.24-source/cmdline/0000755000175000017500000000000010652037721014742 5ustar aaptedaaptedglbsp-2.24-source/cmdline/display.c0000644000175000017500000001054210650405055016552 0ustar aaptedaapted//------------------------------------------------------------------------ // DISPLAY : Command-line display routines //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "glbsp.h" #include #include #include #include #include #include #include #include #if defined(MSDOS) || defined(__MSDOS__) #include #endif #if defined(UNIX) || defined(__UNIX__) #include // Unix: isatty() #include // Unix: raise() #endif #include "display.h" #define FATAL_COREDUMP 0 static boolean_g disable_progress = FALSE; static displaytype_e curr_disp = DIS_INVALID; static int progress_target = 0; static int progress_shown; const nodebuildfuncs_t cmdline_funcs = { TextFatalError, TextPrintMsg, TextTicker, TextDisplayOpen, TextDisplaySetTitle, TextDisplaySetBar, TextDisplaySetBarLimit, TextDisplaySetBarText, TextDisplayClose }; // // TextStartup // void TextStartup(void) { setbuf(stdout, NULL); #ifdef UNIX // no whirling baton if stderr is redirected if (! isatty(2)) disable_progress = TRUE; #endif } // // TextShutdown // void TextShutdown(void) { /* nothing to do */ } // // TextDisableProgress // void TextDisableProgress(void) { disable_progress = TRUE; } // // TextPrintMsg // void TextPrintMsg(const char *str, ...) { va_list args; va_start(args, str); vprintf(str, args); va_end(args); fflush(stdout); } // // TextFatalError // // Terminates the program reporting an error. // void TextFatalError(const char *str, ...) { va_list args; va_start(args, str); vfprintf(stderr, str, args); va_end(args); #if FATAL_COREDUMP && defined(UNIX) raise(SIGSEGV); #endif exit(5); } // // TextTicker // void TextTicker(void) { /* does nothing */ } static void ClearProgress(void) { fprintf(stderr, " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); } // // TextDisplayOpen // boolean_g TextDisplayOpen(displaytype_e type) { // shutdown any existing display TextDisplayClose(); switch (type) { case DIS_BUILDPROGRESS: case DIS_FILEPROGRESS: // these are OK break; default: curr_disp = DIS_INVALID; return FALSE; } curr_disp = type; progress_target = 0; return TRUE; } // // TextDisplaySetTitle // void TextDisplaySetTitle(const char *str) { /* does nothing */ } // // TextDisplaySetBarText // void TextDisplaySetBarText(int barnum, const char *str) { /* does nothing */ } // // TextDisplaySetBarLimit // void TextDisplaySetBarLimit(int barnum, int limit) { if (curr_disp == DIS_INVALID || disable_progress) return; // select the correct bar if ((curr_disp == DIS_FILEPROGRESS && barnum != 1) || (curr_disp == DIS_BUILDPROGRESS && barnum != 1)) { return; } progress_target = limit; progress_shown = -1; } // // TextDisplaySetBar // void TextDisplaySetBar(int barnum, int count) { int perc; if (curr_disp == DIS_INVALID || disable_progress || progress_target <= 0) { return; } // select the correct bar if ((curr_disp == DIS_FILEPROGRESS && barnum != 1) || (curr_disp == DIS_BUILDPROGRESS && barnum != 1)) { return; } if (count > progress_target) TextFatalError("\nINTERNAL ERROR: Progress went past target !\n\n"); perc = count * 100 / progress_target; if (perc == progress_shown) return; if (perc == 0) ClearProgress(); else fprintf(stderr, "--%3d%%--\b\b\b\b\b\b\b\b", perc); progress_shown = perc; } // // TextDisplayClose // void TextDisplayClose(void) { if (curr_disp == DIS_INVALID || disable_progress) return; ClearProgress(); } glbsp-2.24-source/cmdline/main.c0000644000175000017500000002014010651311753016026 0ustar aaptedaapted//------------------------------------------------------------------------ // MAIN : Command-line version main program //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "glbsp.h" #include #include #include #include #include #include #include #include #include "display.h" static nodebuildinfo_t info; static volatile nodebuildcomms_t comms; /* ----- user information ----------------------------- */ static void ShowTitle(void) { TextPrintMsg( "\n" "**** GLBSP Node Builder " GLBSP_VER " (C) 2007 Andrew Apted ****\n\n" ); } static void ShowInfo(void) { TextPrintMsg( "This GL node builder was originally based on BSP 2.3, which was\n" "created from the basic theory stated in DEU5 (OBJECTS.C)\n" "\n" "Credits should go to :-\n" " Janis Legzdinsh for fixing up Hexen support\n" " Andy Baker & Marc Pullen for their invaluable help\n" " Colin Reed & Lee Killough for creating the original BSP\n" " Matt Fell for the Doom Specs\n" " Raphael Quinet for DEU and the original idea\n" " ... and everyone who helped with the original BSP.\n" "\n"); TextPrintMsg( "This program is free software, under the terms of the GNU General\n" "Public License, and comes with ABSOLUTELY NO WARRANTY. See the\n" "accompanying documentation for more details.\n" "\n" "Usage: glbsp [options] input.wad ... [-o output.wad]\n" "Or: glbsp @arg_file.rsp\n" "\n" "For a list of the available options, type: glbsp -help\n" ); } static void ShowOptions(void) { TextPrintMsg( "Usage: glbsp [options] input.wad ... [-o output.wad]\n" "\n" "General Options:\n" " -q -quiet Quieter output, no level stats\n" " -f -fast Reuse original nodes to build faster\n" " -w -warn Show extra warning messages\n" " -n -normal Forces the normal nodes to be rebuilt\n" " -c -factor ### Sets the cost assigned to SEG splits\n" " -p -pack Pack sidedefs (remove duplicates)\n" " -xr -noreject Don't clobber the REJECT map\n" "\n"); TextPrintMsg( "Advanced Options:\n" " -v1 .. -v5 Version of GL-Nodes to use (1,2,3 or 5)\n" " -m -mergevert Merge duplicate vertices\n" " -y -windowfx Handle the 'One-Sided Window' trick\n" " -u -prunesec Remove unused sectors\n" " -b -maxblock ### Sets the BLOCKMAP truncation limit\n" " -xn -nonormal Don't add (if missing) the normal nodes\n" " -xp -noprog Don't show progress indicator\n" " -xu -noprune Never prune linedefs or sidedefs\n" ); } static void ShowDivider(void) { TextPrintMsg("\n------------------------------------------------------------\n\n"); } static int FileExists(const char *filename) { FILE *fp = fopen(filename, "rb"); if (fp) { fclose(fp); return TRUE; } return FALSE; } /* ----- response files ----------------------------- */ #define RESP_MAX_ARGS 1000 #define MAX_WORD_LEN 4000 static const char *resp_argv[RESP_MAX_ARGS+4]; static int resp_argc; static char word_buffer[MAX_WORD_LEN+4]; static void AddArg(const char *str) { if (resp_argc >= RESP_MAX_ARGS) TextFatalError("Error: Too many options! (limit is %d)\n", RESP_MAX_ARGS); resp_argv[resp_argc++] = GlbspStrDup(str); #if 0 // DEBUGGING fprintf(stderr, "Arg [%s]\n", str); #endif } static void ProcessResponseFile(const char *filename) { int word_len = 0; int in_quote = 0; FILE *fp = fopen(filename, "rb"); if (! fp) TextFatalError("Error: Cannot find RESPONSE file: %s\n", filename); // the word buffer is always kept NUL-terminated word_buffer[0] = 0; for (;;) { int ch = fgetc(fp); if (ch == EOF) break; if (isspace(ch) && !in_quote) { if (word_len > 0) AddArg(word_buffer); word_len = 0; in_quote = 0; continue; } if (isspace(ch) && !in_quote) continue; if ((ch == '\n' || ch == '\r') && in_quote) break; // causes the unclosed-quotes error if (ch == '"') { in_quote = ! in_quote; continue; } if (word_len >= MAX_WORD_LEN) TextFatalError("Error: option in RESPONSE file too long (limit %d chars)\n", MAX_WORD_LEN); word_buffer[word_len++] = ch; word_buffer[word_len] = 0; } if (in_quote) TextFatalError("Error: unclosed quotes in RESPONSE file\n"); if (word_len > 0) AddArg(word_buffer); fclose(fp); } static void BuildArgumentList(int argc, char **argv) { for (; argc > 0; argv++, argc--) { if (argv[0][0] == '@') { ProcessResponseFile(argv[0] + 1); continue; } AddArg(*argv); } resp_argv[resp_argc] = NULL; } static void FreeArgumentList(void) { while (--resp_argc >= 0) { GlbspFree(resp_argv[resp_argc]); } } /* ----- main program ----------------------------- */ int main(int argc, char **argv) { int extra_idx = 0; TextStartup(); ShowTitle(); // skip program name itself argv++, argc--; if (argc <= 0) { ShowInfo(); TextShutdown(); exit(1); } if (strcmp(argv[0], "/?") == 0 || strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "-help") == 0 || strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "-HELP") == 0 || strcmp(argv[0], "--HELP") == 0) { ShowOptions(); TextShutdown(); exit(1); } BuildArgumentList(argc, argv); info = default_buildinfo; comms = default_buildcomms; if (GLBSP_E_OK != GlbspParseArgs(&info, &comms, resp_argv, resp_argc)) { TextFatalError("Error: %s\n", comms.message ? comms.message : "(Unknown error when parsing args)"); } if (info.extra_files) { int ext_j; /* catch this mistake: glbsp in.wad out.wad (forget the -o) */ if (info.input_file && info.extra_files[0] && ! info.extra_files[1] && FileExists(info.input_file) && ! FileExists(info.extra_files[0])) { TextFatalError("Error: Cannot find WAD file: %s (" "Maybe you forgot -o)\n", info.extra_files[0]); } /* balk NOW if any of the input files doesn't exist */ if (! FileExists(info.input_file)) TextFatalError("Error: Cannot find WAD file: %s\n", info.input_file); for (ext_j = 0; info.extra_files[ext_j]; ext_j++) { if (FileExists(info.extra_files[ext_j])) continue; TextFatalError("Error: Cannot find WAD file: %s\n", info.extra_files[ext_j]); } } /* process each input file */ for (;;) { if (GLBSP_E_OK != GlbspCheckInfo(&info, &comms)) { TextFatalError("Error: %s\n", comms.message ? comms.message : "(Unknown error when checking args)"); } if (info.no_progress) TextDisableProgress(); if (GLBSP_E_OK != GlbspBuildNodes(&info, &cmdline_funcs, &comms)) { TextFatalError("Error: %s\n", comms.message ? comms.message : "(Unknown error during build)"); } /* when there are extra input files, process them too */ if (! info.extra_files || ! info.extra_files[extra_idx]) break; ShowDivider(); GlbspFree(info.input_file); GlbspFree(info.output_file); info.input_file = GlbspStrDup(info.extra_files[extra_idx]); info.output_file = NULL; extra_idx++; } TextShutdown(); FreeArgumentList(); return 0; } glbsp-2.24-source/cmdline/display.h0000644000175000017500000000306110650405061016552 0ustar aaptedaapted//------------------------------------------------------------------------ // DISPLAY : Command-line display routines //------------------------------------------------------------------------ // // GL-Friendly Node Builder (C) 2000-2007 Andrew Apted // // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __CMDLINE_DISPLAY_H__ #define __CMDLINE_DISPLAY_H__ extern const nodebuildfuncs_t cmdline_funcs; void TextStartup(void); void TextShutdown(void); void TextDisableProgress(void); void TextFatalError(const char *str, ...) GCCATTR((format (printf, 1, 2))); void TextPrintMsg(const char *str, ...) GCCATTR((format (printf, 1, 2))); void TextTicker(void); boolean_g TextDisplayOpen(displaytype_e type); void TextDisplaySetTitle(const char *str); void TextDisplaySetBar(int barnum, int count); void TextDisplaySetBarLimit(int barnum, int limit); void TextDisplaySetBarText(int barnum, const char *str); void TextDisplayClose(void); #endif /* __CMDLINE_DISPLAY_H__ */ glbsp-2.24-source/Makefile.w320000644000175000017500000000351010651644224015401 0ustar aaptedaapted##################################################### # # glBSP Makefile for Win32 compiling (using MINGW32) # # Targets: # libglbsp.a # glbsp.exe # glbsp.txt # # all : makes the library, cmdline program and docs # clean : removes targets and intermediate files # LIB_NAME=libglbsp.a CMD_NAME=glbsp.exe DOC_NAME=glbsp.txt ## SHELL=bash.exe PREFIX= # PREFIX=mingw32- CC=$(PREFIX)gcc CXX=$(PREFIX)g++ AR=$(PREFIX)ar rc RANLIB=$(PREFIX)ranlib BASE_FLAGS=-Wall -O2 -I./src -DWIN32 -DINLINE_G=inline ZLIB_DIR=./zlib-1.2.3 # ZLIB_DIR=C:/Program\ Files/GnuWin32/src/zlib/1.2.3/zlib-1.2.3 # ----- GENERAL STUFF ---------------------------------------------- all: $(LIB_NAME) $(CMD_NAME) $(DOC_NAME) clean: -del $(LIB_NAME) -del $(CMD_NAME) -del $(DOC_NAME) -del src/*.o -del cmdline/*.o .PHONY: all clean # ----- LIBRARY ---------------------------------------------------- LIB_FLAGS=$(BASE_FLAGS) -I$(ZLIB_DIR) LIB_OBJS=\ src/analyze.o \ src/blockmap.o \ src/glbsp.o \ src/level.o \ src/node.o \ src/reject.o \ src/seg.o \ src/system.o \ src/util.o \ src/wad.o src/%.o: src/%.c $(CC) $(LIB_FLAGS) -c $^ -o $@ $(LIB_NAME): $(LIB_OBJS) $(AR) $@ $(LIB_OBJS) $(RANLIB) $@ # ----- CMDLINE PROGRAM --------------------------------------------- CMD_FLAGS=$(BASE_FLAGS) -I$(ZLIB_DIR) CMD_LIBS=$(ZLIB_DIR)/libz.a -lm CMD_OBJS=cmdline/main.o cmdline/display.o cmdline/%.o: cmdline/%.c $(CC) $(CMD_FLAGS) -c $^ -o $@ $(CMD_NAME): $(LIB_NAME) $(CMD_OBJS) $(CC) $(CMD_FLAGS) $(CMD_OBJS) -o $@ $(LIB_NAME) $(CMD_LIBS) # ----- DOCUMENTATION --------------------------------------------- DOC_FILES=README.txt USAGE.txt TRICKS.txt CHANGES.txt $(DOC_NAME): $(DOC_FILES) copy README.txt + USAGE.txt + TRICKS.txt + CHANGES.txt $@ #--- editor settings ------------ # vi:ts=8:sw=8:noexpandtab glbsp-2.24-source/USAGE.txt0000644000175000017500000002713110651623760014743 0ustar aaptedaapted USING glBSP =========== by Andrew Apted. JULY 2007 Running glBSP ------------- There are two versions of glBSP: normal 'glbsp' (the text version), and 'glBSPX' (offering a graphical interface). This documentation applies to the text version only. Under Windows, the text version must be run from the command shell (cmd.exe). There are two main ways of using glBSP: 1. Create the GL nodes and store them in a separate file with the GWA extension. This is called "GWA mode". 2. Create the GL nodes and store them in the WAD file itself, just like how a normal node builder works. These ways are described in more detail below. 1. GWA Mode ----------- For general use, when you just want to use some wad (e.g. FOO.WAD) with a compliant OpenGL DOOM port, then this method is the recommended way. It is also the simplest method, just type: glbsp foo.wad and then glBSP will create the file "foo.gwa". A compliant OpenGL DOOM port (such as EDGE) will notice the GWA file automatically and load it appropriately. Nothing more needs to be done. You can also specify multiple wads here, even wildcards should work. For example: glbsp foo.wad fred.wad simon*.wad Note! You should not give these GWA files to the DOOM port using the command line (i.e. with the -file option), doing so will confuse it and it'll probably crash. The port should notice the GWA file automatically. Note 2: when using GWA mode, the output file does not contain any information for things, linedefs, sidedefs, sectors, reject, or blockmap, all it contains is the GL node information. This is where the name "GWA" comes from, it is short for "GL WAD" (in case you were wondering). 2. Non-GWA Mode --------------- This method is intended for WAD authors, so they can create a single WAD file for distribution that contains all the needed information. Using this method looks like this: glbsp foo1.wad -o foo2.wad and then glBSP will build the GL nodes and output the new file "foo2.wad" containing them. It will also build the normal node information if it is absent. Response Files -------------- New in version 2.20 is support for response files. These are files containing a list of options. You specify the response file by prefixing it with '@'. For example: glbsp @arg_list.rsp The "@arg_list.rsp" on the command line will be replaced with the contents of that file. New-line characters are treated like spaces. Recursion (using '@' inside a response file) is not supported. Option Descriptions ------------------- The following is a list of all the available options. Each option has a short form and a long form. -q -quiet Quieter output. Information about each level (like the number of linedefs, blockmap size, etc) is not displayed when this option is given, and a few other messages are skipped. Important messages, like failure to build a certain level, are still shown. -f -fast Allows glBSP to cheat a bit and re-use the original node information to create the GL nodes, doing it much faster. Use this option to enable this feature. The message "Using original nodes to speed things up" will be shown. The downside to reusing the original nodes is that they may not be as good as the ones glBSP normally creates, e.g. the special checks to minimise slime-trails don't kick in, and the -factor value doesn't have any effect. -w -warn Shows extra warning messages, which detail various non-serious problems that glBSP has while analysing the level structure. Often these warnings show a real problem in the level (e.g. a non-closed sector or invalid sidedef), so they are worth checking now and then. -n -normal glBSP usually detects if the normal node info (i.e. the non-GL variety) is present: when yes, it is left untouched, otherwise glBSP creates it. This option forces glBSP to replace the normal node data with newly constructed nodes. -c -factor Sets the cost assigned to seg splits. Factor can be any number from 1 to 32, and larger values make seg splits more costly (and thus glBSP tries harder to avoid them), but smaller values produce better BSP trees. See the section below for more info. The default value is known to be a good compromise. -p -pack Pack sidedefs, by detecting which sidedefs are identical and removing the duplicates, producing a smaller PWAD. NOTE: this will make your level a lot harder to edit! Therefore this is most useful when producing your final WAD for public release. -xr -noreject Normally glBSP will create an simple REJECT map for each level. This options prevents any existing REJECT map, such as one time-consumingly built by a dedicated reject builder, from being clobbered. These options are rarely needed: -v1 .. -v5 Specify the version of the "GL Nodes" spec to use. The default is -v2. Using -v1 produces an obsolete format. Giving -v3 or -v5 will force certain lumps to use the new formats, but is only useful for testing since glBSP will automatically switch to V5 format when certain limits are exceeded. -m -mergevert Merge duplicate vertices at the same location into a single vertex. This is usually safe, but is not done by default because some engines (e.g. Risen3D) need the duplicate vertices to stay separate for special effect. -y -windowfx Lets glBSP detect and handle the "One-Sided Window" mapping trick. This can cause problems in some engines so it is disabled by default. -u -prunesec Removes any unused sectors found in the level. Only works when normal nodes are being built. This is not done by default since some scripting languages (Fragglescript, old versions of RTS) refer directly to the sector numbers and removing even one will change all the numbering. -b -maxblock Sets the limit of the number of blocks the BLOCKMAP may contain before we truncate it. Default is 16000. When the level is too large to fit, glBSP will truncate the blockmap, so it covers less area on the level. This means that in the parts it doesn't cover (at the outer edges) there is no collision detection: you can walk through walls and other objects and bullets/missiles don't hit anything. On very large but sparse levels, using a larger value (e.g. 30000) may help. A more serious problem is when the blockmap overflows. The blockmap created would be invalid, and could crash the DOOM engine when used. glBSP will create an empty blockmap instead, causing modern ports to build their own blockmap. -xp -noprog Turn off the progress indicator. -xn -nonormal Forces glBSP to not create the normal node information when it detects that it is absent. -xu -noprune Prevents glBSP from removing zero-length linedefs and unused sidedefs. ZDBSP Format Nodes ------------------ When the normal nodes overflow, older versions of glBSP would simply write out the invalid node data. glBSP 2.20 and higher will write out the node data in the ZDBSP format (originally created for the ZDoom engine). Interaction with other tools ---------------------------- As far as I know, none of the various WAD tools that exist (such as DSHRINK, CLEANWAD, DEUTEX, etc..) are "glBSP aware", they will rearrange or even remove some of the special GL entries, and everything goes pear shaped. When using a reject building tool (such as RMB), you need to give the -noreject to glBSP to prevent the good REJECT data from being overwritten. *** DO NOT: *** + Run DSHRINK on your map WADs at any time! + Run CLEANWAD on your map WADs *after* you have compiled your GL friendly nodes! (The GL nodes will be removed). + Use Wintex/DEUSF to merge map WADs with GL friendly nodes in them! (The GL node entries will be rearranged, causing problems). How glBSP works --------------- A node builder works like this: say you are looking at your level in the automap or in the level editor. The node builder needs to pick a line (stretching to infinity) that divides the whole map in two halves (can be rough). Now cover up one half with your hand, and repeat the process on the remaining half. The node builder keeps doing this until the areas that remain are convex (i.e. none of the walls can block the view of any other walls when you are inside that area). Those infinite lines are called "partition lines", and when they cross a linedef, the linedef has to be split. Each split piece is called a "seg", and every split causes more segs to be created. Having fewer segs is good: less to draw & smaller files, so partition lines are chosen so that they minimise splits. The "-factor" value controls how costly these splits are. Higher values cause the node builder to try harder to avoid splits. So, each "partition" line splits an area (or "space") of the level into *two* smaller spaces. This is where the term "Binary Space Partition" (BSP) comes from. Another thing: having a good BSP tree is also important, and helps for faster rendering & smaller files. Thus the node builder also tries to make the BSP tree good (by making it balanced, and keeping it small). If the "-factor" value is too high, it will care too much about the splits, and probably make a bad BSP tree. How good the BSP tree is can be gauged by the output line that reads: Heights of left and right subtrees = (12,24) Lower values are better (the BSP tree is smaller), and values that are closer together are also better (the BSP is more balanced). Differences to BSP 2.3 ---------------------- As mentioned in the readme file, glBSP was originally based on BSP 2.3. Most of the code has been rewritten, however, and some features of BSP were changed or abandoned. Features that are different: + When the output file is not specified (i.e. no -o option), then the default output file will be a GWA file with the same name. Under BSP 2.3, the default output file would be "tmp.wad". + All code for doing visplane checks has been removed. It was very complex stuff, and for OpenGL DOOM ports this checking is not needed. Thus glBSP does not accept the following options that BSP 2.3 supports: -thold, -vp, -vpmark, -vpwarn. + glBSP works on big-endian platforms (like MacOS X). + The "just for a grin" special feature where a linedef with tag 999 would cause an angle adjustment was removed. + glBSP has Hexen support. + glBSP compresses the blockmap, and can pack sidedefs. + glBSP has a much more modular architecture, and can even serve as a plug-in for other programs. + The GUI version, glBSPX, is completely new. --------------------------------------------------------------------------- glbsp-2.24-source/INSTALL.txt0000644000175000017500000000517110652010210015162 0ustar aaptedaapted Compiling glBSP =============== by Andrew Apted. JULY 2007 glBSP comes in three flavors: a command-line utility "glbsp", a graphical/GUI version "glBSPX", and a library for programs to use called: "libglbsp". The source code is structured so that both programs link against the library, hence libglbsp is always built. The GUI version, glBSPX, requires a graphical toolkit called FLTK (Fast Light Tool Kit) version 1.1.7. Other versions may work, but you're on your own there. See the "Links" section below if you need to download it. Sorry to say, but there is no support for compiling with an IDE (like Dev-C++ or Visual Studio) in this release. The directory layout was improved when the code moved to the SVN repository, but unfortunately this broke all the existing project files. NOTE WELL: glBSP is under the GNU General Public License (GPL), hence you cannot use the library (libglbsp) in your own program unless it is also under the GPL. The file COPYING.txt contains a copy of the GPL license, and there is a lot of useful information at this web page: http://www.gnu.org/licenses/ Linux / Unix Builds ------------------- The makefile is called "Makefile.unx". You may need to open it in an editor and edit some stuff near the top, especially if you want to use another compiler (only GNU GCC has been well tested) or to change the directory where FLTK can be found. To build the library and command-line program: > make -f Makefile.unx To build the GUI version: > make -f Makefile.unx glBSPX To install the command-line program and manual page: > sudo make -f Makefile.unx install Windows Builds -------------- The makefile is called "Makefile.w32" and uses the MinGW tools (see the link below) for compiling, and you may need MSYS too. You will also need the ZLIB library (version 1.2.3) and should compile it first. To build the library and command-line program: > mingw32-make -f Makefile.w32 There is no support yet for building the GUI binary natively under Windows (sorry). Cross-Compiling Win32 Binaries ------------------------------ The "Makefile.xming" makefile lets you compile Win32 binaries without leaving the comfort of Linux. You will need to compile FLTK and ZLIB libraries first (maybe edit the makefile to set their location). To build the library and command-line program: > make -f Makefile.xming To build the GUI version: > make -f Makefile.xming glBSPX.exe Links ----- Minimum GNU Windows compiler: http://www.mingw.org Fast Light Toolkit home page: http://www.fltk.org ZLib Compression library: http://www.zlib.net glbsp-2.24-source/Makefile.unx0000644000175000017500000000537410652010632015601 0ustar aaptedaapted#################################### # # glBSP Makefile for UNIX and GCC # # Targets: # libglbsp.a # glbsp # glBSPX # glbsp.txt # # all : makes the library, cmdline program and docs # install : installs cmdline program # clean : removes targets and intermediate files # LIB_NAME=libglbsp.a CMD_NAME=glbsp GUI_NAME=glBSPX DOC_NAME=glbsp.txt CC=gcc CXX=g++ AR=ar rc RANLIB=ranlib STRIP=strip --strip-unneeded BASE_FLAGS=-Wall -O2 -I./src -DUNIX -DINLINE_G=inline FLTK_DIR=./fltk-1.1.7 INSTALL_PREFIX=/usr/local MAN_PREFIX=$(INSTALL_PREFIX)/share/man # ----- GENERAL STUFF ---------------------------------------------- all: $(LIB_NAME) $(CMD_NAME) $(DOC_NAME) clean: rm -f $(LIB_NAME) $(CMD_NAME) $(GUI_NAME) $(DOC_NAME) rm -f src/*.o cmdline/*.o gui/*.o rm -f ./core ./ERRS ./gb_debug.txt .PHONY: all clean # ----- LIBRARY ---------------------------------------------------- LIB_FLAGS=$(BASE_FLAGS) LIB_OBJS=\ src/analyze.o \ src/blockmap.o \ src/glbsp.o \ src/level.o \ src/node.o \ src/reject.o \ src/seg.o \ src/system.o \ src/util.o \ src/wad.o src/%.o: src/%.c $(CC) $(LIB_FLAGS) -c $^ -o $@ $(LIB_NAME): $(LIB_OBJS) $(AR) $@ $(LIB_OBJS) $(RANLIB) $@ # ----- CMDLINE PROGRAM --------------------------------------------- CMD_FLAGS=$(BASE_FLAGS) CMD_LIBS=-lm -lz CMD_OBJS=cmdline/main.o cmdline/display.o cmdline/%.o: cmdline/%.c $(CC) $(CMD_FLAGS) -c $^ -o $@ $(CMD_NAME): $(LIB_NAME) $(CMD_OBJS) $(CC) $(CMD_FLAGS) $(CMD_OBJS) -o $@ $(LIB_NAME) $(CMD_LIBS) $(STRIP) $@ install: $(CMD_NAME) cp $(CMD_NAME) $(INSTALL_PREFIX)/bin/ chown root $(INSTALL_PREFIX)/bin/$(CMD_NAME) chmod 755 $(INSTALL_PREFIX)/bin/$(CMD_NAME) cp glbsp.1 $(MAN_PREFIX)/man1/ chmod 644 $(MAN_PREFIX)/man1/glbsp.1 .PHONY: install # ----- GUI PROGRAM --------------------------------------------- FLTK_FLAGS=-I$(FLTK_DIR) -I$(FLTK_DIR)/zlib FLTK_LIBS=-L$(FLTK_DIR)/lib -lfltk_images -lpng -lz -ljpeg \ -lfltk -lX11 -lXext ## may need: -L/usr/X11R6/lib GUI_FLAGS=$(BASE_FLAGS) $(FLTK_FLAGS) GUI_LIBS=$(FLTK_LIBS) -lm GUI_OBJS=\ gui/main.o \ gui/about.o \ gui/book.o \ gui/booktext.o \ gui/cookie.o \ gui/dialog.o \ gui/files.o \ gui/helper.o \ gui/images.o \ gui/license.o \ gui/menu.o \ gui/options.o \ gui/prefs.o \ gui/progress.o \ gui/textbox.o \ gui/window.o gui/%.o: gui/%.cc $(CXX) $(GUI_FLAGS) -c $^ -o $@ $(GUI_NAME): $(LIB_NAME) $(GUI_OBJS) $(CXX) $(GUI_FLAGS) $(GUI_OBJS) -o $@ $(LIB_NAME) $(GUI_LIBS) $(STRIP) $@ # ----- DOCUMENTATION --------------------------------------------- DOC_FILES=README.txt USAGE.txt TRICKS.txt CHANGES.txt $(DOC_NAME): $(DOC_FILES) cat $(DOC_FILES) > $@ #--- editor settings ------------ # vi:ts=8:sw=8:noexpandtab glbsp-2.24-source/AUTHORS.txt0000644000175000017500000000006010651651225015211 0ustar aaptedaaptedAndrew Apted glbsp-2.24-source/CHANGES.txt0000644000175000017500000002652510652027251015147 0ustar aaptedaapted CHANGELOG ========= Changes in V2.24 (26th July 2007) ---------------------------------- - level name detection: allow some variation in the order of the level lumps (thanks to Darren Salt for the patch). - fixed potential crash passing NULL to the SetErrorMsg() function (it depended on the compiler). - avoid some potential buffer overflows in printf calls. - abbreviations for most cmdline options, generally using single letters (like -f for -fast, -n for -normal). Negative options use an 'x' prefix (like -xr for -noreject, -xu for -noprune). - reduced default blockmap limit to 16000 (was 44000), since the existing limit could never be reached (they overflow at 65536, hence the absolute minimum is around 65535/3 = 21845, assuming no compression). - added TRICKS.txt document which describes various map tricks and how glBSP handles them. - added new option "-windowfx" to enable the test for the One-Sided Window trick, which is now disabled by default. The test was made more robust by checking both sides of the linedef. Most importantly, the seg added to the back side is now a REAL seg (not a MINISEG like before, as that caused many problems). - new option in nodebuildinfo_t "skip_self_ref" which means no segs are created for self-referencing linedefs. The default is FALSE (disabled). When enabled, the engine needs to find self-referencing linedefs and render their middle textures with special code (e.g. treat them similar to sprites). - improved directory layout, with main glbsp code in the 'src' directory. Unfortunately this made all of the IDE Project files invalid, so they have been removed. The existing Makefiles have been fixed and consolidated, so each type of target (lib/cmdline/gui) is handled in the same makefile. Changes in V2.20 (14th September 2005) --------------------------------------- - support for response files, which work the same as Doom: use a filename prefixed with '@' (e.g. @list.rsp) and the contents of the response file are inserted into the command line. - create an empty BLOCKMAP lump when the blockmap overflows (force the engine to generate it). - support V5 GL-Nodes (removes all limits), which is now the default format when limits overflow (e.g. too many GL segs). - support for writing ZDBSP format for regular nodes. This kicks in whenever V5 is used: either explicitly (the -v5 option), or implicitly when the limits overflow. - store keyword/value pairs in the GL level marker lump. This includes a checksum over the plain level data (CHECKSUM keyword), as well as the BUILDER and TIME keywords. - allow level names longer than 5 characters, using the special GL level marker "GL_LEVEL" and the LEVEL keyword (inside the lump). - significantly decreased number of mini warnings, firstly by not showing mismatch warnings for self-referencing linedefs, and secondly by limiting the number of certain warnings to only one per sector. - duplicate vertices are no longer merged (request from Graham Jackson), unless the new -mergevert option is given. - unused sectors are no longer removed by default (to prevent problems with sector numbers used in scripts, e.g. Doom Legacy). The old option -keepsect option is now ignored (for backwards compatibility), replaced by the new -prunesec option. - increased default -factor to 11 (advice from Jack Vermeulen, although he suggested an even higher default). - handle some cases (like Hexen MAP02) where two vertices at the same spot could suppress a miniseg where it was needed. The code for creating intersections is a lot simpler now. - added code to detect the 'One-Sided Window' effect, where a one-sided linedef can be looked through from behind (e.g. MAP07 in 10SECTO2.WAD). When found, a miniseg is added along the back side of the wall. Based on an idea by Graham Jackson. - fixed a bug with the overlapping linedef detection. - fixed the sint8_g typedef, it was missing the 'signed' qualifier (needed on some platforms where plain 'char' is unsigned). Changes in V2.10 (27th September 2004) --------------------------------------- - support V3 GL-Nodes (handle more than 65534 segs in GL_SEGS lump, and more than 32767 vertices in GL_VERT lump). - produce a much more comprehensive problem report when levels fail (or have possibly failed) to build properly (by overflowing limits, etc). - allow levels to contain more than 32767 sidedefs. - choose first seg in a subsector better, avoid self-referenced lines. - removed the ability to build plain nodes (without the GL nodes). - removed -fresh option (now the default), and added a -fast option. - removed code to detect and ignore dummy sectors (which was causing a crash under jHexen). The -keepdummy option is still accepted but ignored. - glBSP now detects overlapping linedefs (used to make higher mid-maskers) and ignores them (produces no segs from the second and subsequent ones). It's now up to the Engine to detect this old trick and emulate it. - v1 vertex coords are now rounded to integers (not truncated). - generalised the -v1 option, allowing -v2 and -v3 as well. Using -v3 will force the GL_SEGS and GL_SSECT lumps to be the new V3 format (mainly useful for testing an engine's support). - when truncating the blockmap, it is now centered on the average of all linedef vertices. - fixed potential inaccuracy in the NODES and GL_NODES lumps. - modified the "based on BSP" messages in the program output and in the documentation, so that people don't get the impression that glBSP is 100% backwards compatible with the original BSP (it isn't). - the Unix and MacOS X makefiles now have "make install" targets. Also converted the docs into a manual page for the Unix installation. - moved makefiles and project files into top-level directory. Removed the support for building with Borland C++Builder. Changes in V2.05 (31st December 2003) -------------------------------------- - ported glbsp and glBSPX to MacOS X. - fixed blockmap bug when building on big-endian CPUs. - fixed the "-noprog" option (it must have been broken for quite a while, maybe since version 1.95). - added a new option "-quiet" for less cluttered output. - fixed some C++ interfacing problems (thanks, indirectly, to Andy Baker). - added some 'near miss' names for certain command-line options. - glbsp now handles multiple input files (GWA mode). - lumps are now aligned on 4-byte boundaries within the output WAD. - improved the 'about' image in the GUI version. - fixed massive slow-down in GUI version under MacOSX (maybe others). - automatically ignores extrafloor dummy sectors. - renamed GUI version to glBSPX (was: glbspX). - split level.c into two files, new file is analyze.c. - reduced the amount of global symbols, and renamed some things for more consistency (e.g. UtilStrCaseCmp). - glBSPX: gave the manual/license windows a nicer interface. Changes in V2.00 (25th September 2002) --------------------------------------- - fixed compilation problems under Digital Unix 4.0 (thanks to André Majorel for the patch). - fixed a problem running on big-endian CPUs (thanks to Jussi Pakkanen for testing on an IRIX 6.5 machine). - made the endian checks run-time instead of compile-time, and added sanity checks on the type sizes. - made building GWA files *much* faster, by reusing the existing node information (up to a point anyway). It is now between 3 and 5 times faster than before. It comes at a price though, the original nodes may not be as good as the ones GLBSP can make. There is a new option "-fresh" to force GLBSP to build nodes from scratch. - some more Hexen / ZDoom fixes, thanks to Janis Legzdinsh. - now if any level fails to build properly (e.g. blockmap too big, or too many segs) then a large "ATTENTION" message is shown at the very end, showing which levels failed (perhaps all of them). - glBSPX: new misc option "Fresh Partition Lines". - fixed (hopefully) some rare sectors that were marked as precious but were being split anyway, because the partition line passed through the sector via vertices (not hitting any linedefs). Thanks to Janis Legzdinsh for spotting this bug. - The "-forcenormal" option is now just "-normal", and has been elevated to General Option status. Backwards compatibility has been kept. Changes in V1.96 (1st January 2002) ------------------------------------ - implemented the "SaveLog" feature in glBSPX. - improved the preference dialog in glBSPX, with a new option to automatically replace missing extensions. - a few changes to upgrade to FLTK version 1.1.0. This means an improved file browser and the new radio/check buttons. - updated various bits of documentation. - updated copyright in headers (etc) for 2002. - fixed a bug in glBSPX when changing extensions on files that contain ".." in their path. - fixed a glBSPX bug with the case-insensitive string comparison functions. - made various glBSPX dialogs a bit more user friendly. Changes in V1.95 (24th September 2001) --------------------------------------- - new GUI version using the FLTK toolkit. - many fixes for Hexen wads, thanks to Janis Legzdinsh, including auto-detection of a hexen wad (don't need -hexen option). - level names (MAP01, E2M3, etc) are detected automatically now, allowing arbitrary names (e.g. RUINS, QD05, etc). - improved wad.c to return error values instead of doing FatalError(), setting up the comms->message appropriately. - removed 'display_setText' function from nodebuildfuncs API. - fixed the memory semantics for the glbsp API, with new functions GlbspStrDup() and GlbspFree(). - documented the nodebuildfuncs in glbsp.h. - improved the semantics of the GlbspCheckInfo() function, adding a new error code GLBSP_E_BadInfoFixed to show that (a) there was a problem but (b) the parameter causing it has been reset. Changes in V1.94 (6th June 2001) --------------------------------- - shows percentage while loading and saving. - shows warnings when results overflow normal DOOM limits. - shows warnings for extremely long linedefs and nodes. - fixed serious bug with blockmap truncation code. - new -maxblock option gives control over blockmap truncation. - fixed some build problems with very narrow subsectors. - fixed warnings about 2s linedefs with no left side. - new "slightly better than nothing" reject support. - code is much more modular: UI has been separated out. - improved debugging code. Changes in V1.91 (10th September 2000) --------------------------------------- - optimised, DOOM2.WAD: 50% faster, ETERNAL.WAD: 3 times faster. - builds "V2 GL Nodes" which are more accurate. - no longer balks at bad sidedefs (with sector of #-1). - removes unused sectors & sidedefs. - packs the blockmap, and can pack identical sidedefs. - shows the percentage complete while building. - floatified: nodes are computed using high precision math. - source code is now under the GNU General Public License. Changes in V1.8 (20th June 2000) --------------------------------- - fixed major bug causing thin (but ugly looking) gaps to appear between some subsectors. - fixed some bugs with partner segs not being split properly. - fixed crashing bug when splitting very short segs. glbsp-2.24-source/COPYING.txt0000644000175000017500000004311010514052747015201 0ustar aaptedaapted GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. glbsp-2.24-source/TRICKS.txt0000644000175000017500000001014710651352716015075 0ustar aaptedaapted glBSP and Map-Tricks/Errors =========================== 1. Self-referencing Lines This trick involves linedefs with the same sector reference on both sidedefs. In the original DOOM renderer, segs from these lines are virtually ignored (though any mid-masked texture is still drawn). Hence by using a sector which is different from the surrounding sector, people could create the following special physics effects: 1. invisible walkways (self-ref sector floor is higher) 2. deep water (self-ref sector floor is lower) 3. force fields (self-ref sector blocks movement) 4. railings you can jump over. glBSP detects these lines and does two things: prevents spurious warnings about mismatched sectors, and adjusts the final subsector so that the FIRST seg is not one on a self-reference line. It does the latter because most engines use the very first seg to decide what sector to associate the subsector with. Engines should be aware of the trick and perform their own analysis to emulate it. NOTE this trick will cause some subsectors to contain segs from multiple sectors. 2. Overlapping Lines This trick is mostly used to make higher mid-masking textures. glBSP can detect perfectly overlapping linedefs (ones using the same start and end vertices, possibly swapped), and will IGNORE them (producing no segs from the second and subsequent lines). Engines should also detect overlapping lines and emulate the trick (by rendering the additional mid-masked textures). 3. One-Sided Windows This trick uses a one-sided linedef where a two-sided linedef should be, so the back of the one-sided line faces into a normal sector. In the original DOOM renderer, there was no back-facing seg in the BSP, hence you could see through the line when viewed from the back. When viewed from the front, the one-sided linedef acted normally (blocked your view). glBSP can detect many usages of this trick (although not 100% since that would require much more expensive analysis). It has to be explicitly enabled with the -windowfx option (or for libglbsp via a field in nodebuildinfo_t). When found, glBSP will add a REAL seg along the back of the one-sided linedef. This is the only time that segs are placed on a linedef with no corresponding sidedef. Engines should detect that and emulate the trick accordingly. Depending on how your renderer does occlusion culling, it may not be necessary to do anything special. 4. Missing Lowers/Uppers This trick is mentioned since it is very common, though it doesn't affect or interfere with node building in any way. When the DOOM renderer encounters a missing lower texture, and the floor on the back side is visible (z < camera.z) then the space where the lower texture should be will be filled by that floor texture. The same thing happens with missing uppers too. This effect can be used to create a deep water effect, or for drawing a dark ceiling over a bright lava sector. When the back floor is out of view (z > camera.z), then the missing lower is not drawn at all. Same for missing uppers. This is sometimes used to create "invisible" doors and platforms. 5. Map Errors PWADs often contain a few mapping errors in them, and even the IWADs contain some small errors, for example: Doom1 E3M2: Linedef #156 has a wrong sector reference. Doom2 MAP02: Sector #23 is not properly closed. Doom2 MAP14: Linedefs #964 and #966 are missing back sidedefs. Hexen MAP02: Vertex #1370 is not joined to linedef #668. glBSP is not psychic and cannot automatically fix errors in maps (and besides, sometimes they are used deliberately for special effects, as described above). When a linedef has a wrong sector reference, the usual result is that the subsector (or subsectors) near that spot will contain segs belonging to different sectors. I cannot say what best way to handle it is -- engine developers should at least be aware of the possibility. Other map errors are more serious and cause structural problems, like degenerate subsectors (which contain only one or two segs). There is nothing glBSP or the engine can do in these cases. --------------------------------------------------------------------------- glbsp-2.24-source/Makefile.xming0000644000175000017500000000561510651644211016114 0ustar aaptedaapted##################################################### # # glBSP Makefile for Cross-Compiling Win32 binaries # # Targets: # libglbsp.a # glbsp.exe # glBSPX.exe # glbsp.txt # # all : makes the library, cmdline program and docs # clean : removes targets and intermediate files # LIB_NAME=libglbsp.a CMD_NAME=glbsp.exe GUI_NAME=glBSPX.exe DOC_NAME=glbsp.txt CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ AR=i586-mingw32msvc-ar rc RANLIB=i586-mingw32msvc-ranlib STRIP=i586-mingw32msvc-strip --strip-unneeded WINDRES=i586-mingw32msvc-windres BASE_FLAGS=-Wall -O2 -I./src -DWIN32 -DINLINE_G=inline ZLIB_DIR=./zlib-1.2.3-win32 FLTK_DIR=./fltk-1.1.7-win32 # ----- GENERAL STUFF ---------------------------------------------- all: $(LIB_NAME) $(CMD_NAME) $(DOC_NAME) clean: rm -f $(LIB_NAME) $(CMD_NAME) $(GUI_NAME) $(DOC_NAME) rm -f src/*.o cmdline/*.o gui/*.o rm -f ./core ./ERRS ./gb_debug.txt .PHONY: all clean # ----- LIBRARY ---------------------------------------------------- LIB_FLAGS=$(BASE_FLAGS) -I$(ZLIB_DIR) LIB_OBJS=\ src/analyze.o \ src/blockmap.o \ src/glbsp.o \ src/level.o \ src/node.o \ src/reject.o \ src/seg.o \ src/system.o \ src/util.o \ src/wad.o src/%.o: src/%.c $(CC) $(LIB_FLAGS) -c $^ -o $@ $(LIB_NAME): $(LIB_OBJS) $(AR) $@ $(LIB_OBJS) $(RANLIB) $@ # ----- CMDLINE PROGRAM --------------------------------------------- CMD_FLAGS=$(BASE_FLAGS) -I$(ZLIB_DIR) CMD_LIBS=$(ZLIB_DIR)/libz.a -lm CMD_OBJS=cmdline/main.o cmdline/display.o cmdline/%.o: cmdline/%.c $(CC) $(CMD_FLAGS) -c $^ -o $@ $(CMD_NAME): $(LIB_NAME) $(CMD_OBJS) $(CC) $(CMD_FLAGS) $(CMD_OBJS) -o $@ $(LIB_NAME) $(CMD_LIBS) $(STRIP) $@ # ----- GUI PROGRAM --------------------------------------------- FLTK_FLAGS=-I$(FLTK_DIR) -I$(FLTK_DIR)/zlib FLTK_LIBS=-L$(FLTK_DIR)/lib \ -lfltk_images -lfltk_png -lfltk_z -lfltk_jpeg -lfltk WIN32_LIBS=-mwindows -lole32 -luuid -lgdi32 -lcomctl32 \ -lwsock32 -lsupc++ GUI_FLAGS=$(BASE_FLAGS) $(FLTK_FLAGS) GUI_LIBS=$(FLTK_LIBS) $(WIN32_LIBS) -lm GUI_OBJS=\ gui/main.o \ gui/about.o \ gui/book.o \ gui/booktext.o \ gui/cookie.o \ gui/dialog.o \ gui/files.o \ gui/helper.o \ gui/images.o \ gui/license.o \ gui/menu.o \ gui/options.o \ gui/prefs.o \ gui/progress.o \ gui/textbox.o \ gui/window.o \ gui/glbsp_res.o gui/%.o: gui/%.cc $(CXX) $(GUI_FLAGS) -c $^ -o $@ gui/glbsp_res.o: gui/glBSPX.rc $(WINDRES) -i $^ --input-format=rc -o $@ -O coff $(GUI_NAME): $(LIB_NAME) $(GUI_OBJS) $(CXX) $(GUI_FLAGS) $(GUI_OBJS) -o $@ $(LIB_NAME) $(GUI_LIBS) $(STRIP) $@ # ----- DOCUMENTATION --------------------------------------------- DOC_FILES=README.txt USAGE.txt TRICKS.txt CHANGES.txt $(DOC_NAME): $(DOC_FILES) cat $(DOC_FILES) > glbsp_doc.tmp awk 'sub("$$", "\r")' glbsp_doc.tmp > $@ rm -f glbsp_doc.tmp #--- editor settings ------------ # vi:ts=8:sw=8:noexpandtab glbsp-2.24-source/glbsp.10000644000175000017500000001451010651354573014527 0ustar aaptedaapted.\" -*-nroff-*- .TH glbsp 1 "July 2007" .\" .UC 4 .SH NAME glbsp \- GL Nodes builder for DOOM ports .SH SYNOPSIS .B glbsp .RI "[" options "] " input.wad ... [\-o output.wad] .PP .B glbsp .I @argfile.rsp .PP .SH DESCRIPTION .I glBSP is a nodes builder specially designed to be used with OpenGL-based DOOM game engines. It adheres to the "GL-Friendly Nodes" specification, which means it adds some new special nodes to a WAD file that makes it very easy for an OpenGL DOOM engine to compute the polygons needed for drawing the levels. .SH OPTIONS Options begin with a single dash (you can also use two dashes like in many GNU programs). Running glBSP without any options will show an informational screen. .TP .B \-h \-help Show a summary of all the options. .TP .B \-q \-quiet Quieter output. Information about each level (like the number of linedefs, blockmap size, etc) is not displayed when this option is given, and a few other messages are skipped. Important messages, like failure to build a certain level, are still shown. .TP .B \-f \-fast Allows glBSP to cheat a bit and re-use the original node information to create the GL nodes, doing it much faster. Use this option to enable this feature. The message "Using original nodes to speed things up" will be shown. The downside to reusing the original nodes is that they may not be as good as the ones glBSP normally creates, e.g. the special checks to minimise slime-trails don't kick in, and the \-factor value doesn't have much effect. .TP .B \-w \-warn Shows extra warning messages, which detail various non-serious problems that glBSP has while analysing the level structure. Often these warnings show a real problem in the level (e.g. a non-closed sector or invalid sidedef), so they are worth checking now and then. .TP .B \-n \-normal glBSP usually detects if the normal node info (i.e. the non-GL variety) is present: when yes, it is left untouched, otherwise glBSP creates it. This option forces glBSP to replace the normal node data with newly constructed nodes. .TP .BI "\-c \-factor" " " Sets the cost assigned to seg splits. Factor can be any number from 1 to 32, and larger values make seg splits more costly (and thus glBSP tries harder to avoid them), but smaller values produce better BSP trees. The default value is known to be a good compromise. .TP .B \-p \-pack Pack sidedefs, by detecting which sidedefs are identical and removing the duplicates, producing a smaller PWAD. NOTE: this may make your level a lot harder to edit! Therefore this is most useful when producing the final WAD for public release. .TP .B \-xr \-noreject Normally glBSP will create an simple REJECT map for each level. This options prevents any existing REJECT map, such as one time-consumingly built by a dedicated reject builder, from being clobbered. .PP The following options are rarely needed: .TP .B \-v1 .. \-v5 Specify the version of the "GL Nodes" spec to use (either 1, 2, 3 or 5). V1 is considered obsolete now. The default is V2. Giving \-v3 or \-v5 will force certain lumps to use the new formats, but is only useful for testing since glBSP will automatically switch to V5 format whenever the ordinary limits are exceeded. .TP .B \-m \-mergevert Merge duplicate vertices at the same location into a single vertex. This is usually safe, but is not done by default because some engines (e.g. Risen3D) need the duplicate vertices to stay separate for a special effect. .TP .B \-y \-windowfx Lets glBSP detect and handle the "One-Sided Window" mapping trick. This can cause problems in some engines so it is disabled by default. .TP .BI "\-b \-maxblock" " " Sets the limit of the number of blocks the BLOCKMAP may contain before we truncate it. Default is 16000. When the level is too large to fit, glBSP will truncate the blockmap, so it covers less area on the level. This means that in the parts it doesn't cover (at the outer edges) there is no collision detection: you can walk through walls and other objects and bullets/missiles don't hit anything. On very large but sparse levels, using a larger value (e.g. 30000) may help. A more serious problem is when the blockmap overflows. The blockmap created would be invalid, and could crash the DOOM engine when used. glBSP will create an empty blockmap instead, causing modern ports to build their own blockmap. .TP .B \-xp \-noprog Turn off the progress indicator. .TP .B \-xn \-nonormal Forces glBSP to not create the normal node information when it detects that it is absent. .TP .B \-xu \-prunesec Removes any unused sectors that are found in the level. This has the potential to cause problems, since in certain scripting languages (e.g. EDGE's RTS, or Doom Legacy's Fragglescript) some commands use sector numbers directly, and pruning unused sectors can cause those references to become invalid. .SH RESPONSE FILES New in version 2.20 is support for response files. These are files containing a list of options. You specify the response file by prefixing it with '@'. For example: .PP .B glbsp .I @argfile.rsp .PP The "@argfile.rsp" on the command line will be replaced with the contents of that file. New-line characters are treated like spaces. Recursion (using '@' inside a response file) is not supported. .SH ZDBSP NODES When the normal nodes overflow, older versions of glBSP would simply write out the invalid node data. glBSP 2.20 and higher now write the node data in the ZDBSP format (originally created for the ZDoom engine). .SH AUTHORS Andrew Apted created glBSP and glBSPX and continues to maintain them. .PP Andrew Baker, Janis Legzdinsh, Andr\('e Majoral and Darren Salt have contributed code, and Marc Pullen helped with the documentation. .PP glBSP was originally based on BSP 2.3 (C) Colin Reed and Lee Killough, which was created from the basic theory stated in DEU5 (OBJECTS.C) by Raphael Quinet. .SH LICENSE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. .PP This program is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. .SH "SEE ALSO" .PP The glBSP Homepage: .UR http://glbsp.sourceforge.net/ http://glbsp.sourceforge.net/ .UE glbsp-2.24-source/README.txt0000644000175000017500000000741110651623755015037 0ustar aaptedaapted README for glBSP ================ by Andrew Apted. JULY 2007 Introduction ------------ glBSP is a nodes builder specially designed to be used with OpenGL-based DOOM game engines. It adheres to the "GL-Friendly Nodes" specification, which means it adds some new special nodes to a WAD file that makes it very easy for an OpenGL DOOM engine to compute the polygons needed for drawing the levels. There are many DOOM ports that understand the GL Nodes which glBSP creates, including: EDGE, Doomsday (JDOOM), PrBoom, Vavoom, ZDoomGL, Legacy 2.0, and Doom3D. See the links below. Status ------ The current version of glBSP is 2.24. It has been tested and known to work on numerous large wads, including DOOM I, DOOM II, TeamTNT's Eternal III, Fanatic's QDOOM, and many others. Copyright --------- glBSP is Copyright (C) 2000-2007 Andrew Apted. It was originally based on "BSP 2.3" (C) Colin Reed and Lee Killough, which was created from the basic theory stated in DEU5 (OBJECTS.C) by Raphael Quinet. The GUI version (glBSPX) is based in part on the work of the FLTK project, see http://www.fltk.org. All trademarks are the propriety of their owners. License ------- Thanks to Lee Killough and André Majorel (former maintainer of BSP, and devil-may-care flying French fool, respectively), glBSP is under the GNU General Public License (GPL). See the file 'COPYING.txt' in the source package (or go to http://www.gnu.org) for the full text, but to summarise: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Links ----- The homepage for glBSP can be found here: http://glbsp.sourceforge.net/ The "GL Friendly Nodes" specifications is here: http://glbsp.sourceforge.net/glnodes.html The EDGE homepage can be found here: http://edge.sourceforge.net/ The DoomsDay (JDOOM) homepage is here: http://www.doomsdayhq.com/ Look here for PrBOOM: http://prboom.sourceforge.net/ Legacy info can be found here: http://legacy.newdoom.com/ The Vavoom site is here: http://www.vavoom-engine.com/ ZDoomGL is known to hang out around here: http://zdoomgl.mancubus.net/ The Doom3D site can be found here: http://doomworld.com/doom3d/ Acknowledgements ---------------- Andy Baker, for making binaries, writing code and other help. Marc A. Pullen, for testing and helping with the documentation. Lee Killough and André Majorel, for giving their permission to put glBSP under the GNU GPL. Janis Legzdinsh for fixing many problems with Hexen wads. Darren Salt has sent in numerous patches. Jaakko Keränen, who gave some useful feedback on the "GL Friendly Nodes" specification. The authors of FLTK (Fast Light Tool Kit), for a nice LGPL C++ GUI toolkit that even I can get working on both Linux and Win32. Marc Rousseau (author of ZenNode 1.0), Robert Fenske Jr (author of Warm 1.6), L.M. Witek (author of Reject 1.1), and others, for releasing the source code to their WAD utilities, and giving me lots of ideas to "borrow" :), like blockmap packing. Lee Killough and Colin Reed (and others), who wrote the original BSP 2.3 which glBSP was based on. Matt Fell, for the Doom Specs v1.666. Raphael Quinet, for DEU and the original idea. id Software, for not only creating such an irresistable game, but releasing the source code for so much of their stuff. ... and everyone else who deserves it ! --------------------------------------------------------------------------- glbsp-2.24-source/old_stuff/0000755000175000017500000000000010652037672015321 5ustar aaptedaaptedglbsp-2.24-source/old_stuff/Cmdline.vcproj0000644000175000017500000000765010650366135020126 0ustar aaptedaapted glbsp-2.24-source/old_stuff/Cmdline.dev0000644000175000017500000000660610650366132017376 0ustar aaptedaapted[Project] FileName=Cmdline.dev Name=glbsp UnitCount=24 Type=1 Ver=1 ObjFiles= Includes= Libs= PrivateResource= ResourceIncludes= MakeIncludes= Compiler=-DWIN32_@@_-DGLBSP_TEXT_@@_ CppCompiler= Linker= IsCpp=0 Icon= ExeOutput= ObjectOutput= OverrideOutput=1 OverrideOutputName=glbsp.exe HostApplication= Folders= CommandLine= IncludeVersionInfo=0 SupportXPThemes=0 CompilerSet=0 CompilerSettings=000000000001000000 [Unit1] FileName=cmdline\main.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit2] FileName=cmdline\display.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit3] FileName=cmdline\display.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit4] FileName=wad.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit5] FileName=blockmap.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit6] FileName=glbsp.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit7] FileName=glbsp.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit8] FileName=level.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit9] FileName=level.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit10] FileName=node.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit11] FileName=node.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit12] FileName=reject.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit13] FileName=reject.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit14] FileName=seg.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit15] FileName=seg.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit16] FileName=structs.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit17] FileName=system.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit18] FileName=system.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit19] FileName=util.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit20] FileName=util.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit21] FileName=wad.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit22] FileName=blockmap.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit23] FileName=analyze.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit24] FileName=analyze.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [VersionInfo] Major=0 Minor=1 Release=1 Build=1 LanguageID=1033 CharsetID=1252 CompanyName= FileVersion= FileDescription=Developed using the Dev-C++ IDE InternalName= LegalCopyright= LegalTrademarks= OriginalFilename= ProductName= ProductVersion= AutoIncBuildNr=0 glbsp-2.24-source/old_stuff/GUI.dev0000644000175000017500000001451210650366133016443 0ustar aaptedaapted[Project] FileName=GUI.dev Name=glBSPX UnitCount=38 Type=0 Ver=1 ObjFiles= Includes=..\fltk-1.1.6 Libs=..\fltk-1.1.6\devcpp PrivateResource=FLTK_private.rc ResourceIncludes= MakeIncludes= Compiler=-DWIN32_@@_-DGLBSP_GUI_@@_-finline-functions_@@_-fexceptions_@@_-DWIN32_@@_-DNDEBUG_@@_-D_WINDOWS_@@_-D__GNUWIN32___@@_-DWIN32_LEAN_AND_MEAN_@@_-DVC_EXTRA_LEAN_@@_-DWIN32_EXTRA_LEAN_@@_ CppCompiler=-DWIN32_@@_-DGLBSP_GUI_@@_-finline-functions_@@_-fexceptions_@@_-DWIN32_@@_-DNDEBU_@@_-D_WINDOWS_@@_-D__GNUWIN32___@@_-DWIN32_LEAN_AND_MEAN_@@_-DVC_EXTRA_LEAN_@@_-DWIN32_EXTRA_LEAN_@@_ Linker=../fltk-1.1.6/devcpp/fltkimages.lib_@@_../fltk-1.1.6/devcpp/fltk.lib_@@_-lcomctl32_@@_-lkernel32_@@_-luser32_@@_-ladvapi32_@@_-lshell32_@@_-luuid_@@_-lole32_@@_-lwsock32_@@_ IsCpp=1 Icon=glBSPX.ico ExeOutput= ObjectOutput= OverrideOutput=1 OverrideOutputName=glBSPX.exe HostApplication= Folders= CommandLine= IncludeVersionInfo=0 SupportXPThemes=0 CompilerSet=0 CompilerSettings=000000000010000000 [Unit3] FileName=glbsp.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit4] FileName=glbsp.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit5] FileName=level.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit6] FileName=level.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit7] FileName=node.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit8] FileName=node.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit9] FileName=reject.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit10] FileName=reject.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit11] FileName=seg.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit12] FileName=seg.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit13] FileName=structs.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit14] FileName=system.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit15] FileName=system.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit16] FileName=util.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit17] FileName=util.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit18] FileName=wad.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit19] FileName=blockmap.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit20] FileName=analyze.c CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit21] FileName=analyze.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit23] FileName=gui\book.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\book.cpp -o gui\book.o $(CXXFLAGS) [Unit24] FileName=gui\booktext.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\booktext.cpp -o gui\booktext.o $(CXXFLAGS) [VersionInfo] Major=0 Minor=1 Release=1 Build=1 LanguageID=1033 CharsetID=1252 CompanyName= FileVersion= FileDescription=Developed using the Dev-C++ IDE InternalName= LegalCopyright= LegalTrademarks= OriginalFilename= ProductName= ProductVersion= AutoIncBuildNr=0 [Unit1] FileName=wad.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit2] FileName=blockmap.h CompileCpp=0 Folder=cmdline Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit22] FileName=gui\window.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\window.cpp -o gui\window.o $(CXXFLAGS) [Unit25] FileName=gui\cookie.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\cookie.cpp -o gui\cookie.o $(CXXFLAGS) [Unit26] FileName=gui\dialog.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\dialog.cpp -o gui\dialog.o $(CXXFLAGS) [Unit27] FileName=gui\files.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\files.cpp -o gui\files.o $(CXXFLAGS) [Unit28] FileName=gui\helper.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\helper.cpp -o gui\helper.o $(CXXFLAGS) [Unit29] FileName=gui\images.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\images.cpp -o gui\images.o $(CXXFLAGS) [Unit30] FileName=gui\license.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\license.cpp -o gui\license.o $(CXXFLAGS) [Unit31] FileName=gui\local.h CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit32] FileName=gui\main.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\main.cpp -o gui\main.o $(CXXFLAGS) [Unit33] FileName=gui\menu.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\menu.cpp -o gui\menu.o $(CXXFLAGS) [Unit34] FileName=gui\options.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\options.cpp -o gui\options.o $(CXXFLAGS) [Unit35] FileName=gui\prefs.cpp CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit36] FileName=gui\progress.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\progress.cpp -o gui\progress.o $(CXXFLAGS) [Unit37] FileName=gui\textbox.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\textbox.cpp -o gui\textbox.o $(CXXFLAGS) [Unit38] FileName=gui\about.cpp CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd=$(CPP) -c gui\about.cpp -o gui\about.o $(CXXFLAGS) glbsp-2.24-source/old_stuff/Plugin.dev0000644000175000017500000000600710650366134017256 0ustar aaptedaapted[Project] FileName=Plugin.dev Name=glbsp UnitCount=21 Type=2 Ver=1 ObjFiles= Includes= Libs= PrivateResource= ResourceIncludes= MakeIncludes= Compiler=-DWIN32_@@_-DGLBSP_PLUGIN_@@_ CppCompiler=-DGLBSP_PLUGIN_@@_-DWIN32_@@_ Linker= IsCpp=1 Icon= ExeOutput= ObjectOutput= OverrideOutput=1 OverrideOutputName=libglbsp.a HostApplication= Folders= CommandLine= IncludeVersionInfo=0 SupportXPThemes=0 CompilerSet=0 CompilerSettings=000000000101000000 [Unit1] FileName=wad.h CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit2] FileName=blockmap.h CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit3] FileName=glbsp.c CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit4] FileName=glbsp.h CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit5] FileName=level.c CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit6] FileName=level.h CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit7] FileName=node.c CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit8] FileName=node.h CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit9] FileName=reject.c CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit10] FileName=reject.h CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit11] FileName=seg.c CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit12] FileName=seg.h CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit13] FileName=structs.h CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit14] FileName=system.c CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit15] FileName=system.h CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit16] FileName=util.c CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit17] FileName=util.h CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit18] FileName=wad.c CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit19] FileName=blockmap.c CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit20] FileName=analyze.c CompileCpp=0 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [Unit21] FileName=analyze.h CompileCpp=1 Folder=glbsp Compile=1 Link=1 Priority=1000 OverrideBuildCmd=0 BuildCmd= [VersionInfo] Major=0 Minor=1 Release=1 Build=1 LanguageID=1033 CharsetID=1252 CompanyName= FileVersion= FileDescription=Developed using the Dev-C++ IDE InternalName= LegalCopyright= LegalTrademarks= OriginalFilename= ProductName= ProductVersion= AutoIncBuildNr=0 glbsp-2.24-source/old_stuff/Plugin.vcproj0000644000175000017500000000640010650366136020002 0ustar aaptedaapted glbsp-2.24-source/old_stuff/GUI_w32.mak0000644000175000017500000000350610650370475017135 0ustar aaptedaapted# # glBSPX with FLTK < Win32 + MinGW MAKEFILE > # MAIN=src SYSDIR=gui SRC_DIR=glbsp FLTK_PREFIX=../fltk-1.1.6 FLTK_CFLAGS=-I$(FLTK_PREFIX) -I$(FLTK_PREFIX)/zlib FLTK_LIBS=-L$(FLTK_PREFIX)/lib -lfltk_images -lfltk_png -lfltk_z -lfltk_jpeg -lfltk PROGNAME=glBSPX.exe RES=glBSPX_priv.res CC=gcc.exe CXX=g++.exe CFLAGS=-O2 -Wall -DGLBSP_GUI -DWIN32 -DINLINE_G=inline $(FLTK_CFLAGS) CXXFLAGS=$(CFLAGS) LDFLAGS= LIBS=-lm $(FLTK_LIBS) -mwindows -lole32 -luuid -lgdi32 -lcomctl32 \ -lwsock32 -lsupc++ WINDRES=windres.exe OBJS=$(SYSDIR)/main.o \ $(SYSDIR)/about.o \ $(SYSDIR)/book.o \ $(SYSDIR)/booktext.o \ $(SYSDIR)/cookie.o \ $(SYSDIR)/dialog.o \ $(SYSDIR)/files.o \ $(SYSDIR)/helper.o \ $(SYSDIR)/images.o \ $(SYSDIR)/license.o \ $(SYSDIR)/menu.o \ $(SYSDIR)/options.o \ $(SYSDIR)/prefs.o \ $(SYSDIR)/progress.o \ $(SYSDIR)/textbox.o \ $(SYSDIR)/window.o \ \ $(MAIN)/analyze.o \ $(MAIN)/blockmap.o \ $(MAIN)/glbsp.o \ $(MAIN)/level.o \ $(MAIN)/node.o \ $(MAIN)/reject.o \ $(MAIN)/seg.o \ $(MAIN)/system.o \ $(MAIN)/util.o \ $(MAIN)/wad.o # ----- TARGETS ------------------------------------------------------ all: $(PROGNAME) clean: rm -f $(PROGNAME) $(RES) $(MAIN)/*.o $(SYSDIR)/*.o rm -f $(MAIN)/core $(SYSDIR)/core $(MAIN)/glbsp.txt localclean: rm -f $(PROGNAME) $(SYSDIR)/*.o $(SYSDIR)/core $(PROGNAME): $(OBJS) $(RES) $(CXX) $(CFLAGS) $(OBJS) $(RES) -o $(PROGNAME) $(LDFLAGS) $(LIBS) $(RES): fltk/glBSPX.rc $(WINDRES) -i fltk/glBSPX.rc --input-format=rc -o $@ -O coff bin: all strip --strip-unneeded $(PROGNAME) cat $(MAIN)/README.txt $(MAIN)/USAGE.txt $(MAIN)/CHANGES.txt > $(MAIN)/glbsp.txt .PHONY: all clean localclean bin glbsp-2.24-source/old_stuff/Plugin_w32.mak0000644000175000017500000000153610650370527017746 0ustar aaptedaapted# # glBSP Plugin: < Win32 + MinGW MAKEFILE > # # (Note: requires GNU make) # # SHELL=bash.exe BIN=libglbsp.a #ZLIB_DIR="C:/Program Files/GnuWin32/src/zlib/1.2.3/zlib-1.2.3" ZLIB_DIR=C:/Program\ Files/GnuWin32/src/zlib/1.2.3/zlib-1.2.3 INCS=-I$(ZLIB_DIR) CC=gcc CFLAGS=-O2 -Wall $(INCS) -DGLBSP_PLUGIN -DWIN32 -DINLINE_G=inline AR=ar r RANLIB=ranlib # ----- OBJECTS ------------------------------------------------------ OBJS= \ src/analyze.o \ src/blockmap.o \ src/glbsp.o \ src/level.o \ src/node.o \ src/reject.o \ src/seg.o \ src/system.o \ src/util.o \ src/wad.o # ----- TARGETS ------------------------------------------------------ all: $(BIN) clean: rm -f $(OBJS) $(BIN) %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c $< -o $@ $(BIN): $(OBJS) $(AR) $(BIN) $(OBJS) $(RANLIB) $(BIN) .PHONY: all clean glbsp-2.24-source/old_stuff/Makefile.w320000644000175000017500000000166110650370542017371 0ustar aaptedaapted# # glBSP Command-line: < Win32 + MinGW MAKEFILE > # # (Note: requires GNU make) # MAIN=src SYSDIR=cmdline # SHELL=bash.exe BIN=glbsp.exe # INCS=-I../DEV-CPP/include -Iinclude ZLIB_DIR=../zlib-1.2.2-lib ZLIB_CFLAGS=-I$(ZLIB_DIR)/include ZLIB_LIBS=$(ZLIB_DIR)/lib/libz.a CC=gcc.exe CFLAGS=-O2 -Wall -DGLBSP_TEXT -DWIN32 -DINLINE_G=inline $(ZLIB_CFLAGS) LIBS=-lm $(ZLIB_LIBS) # ----- OBJECTS ------------------------------------------------------ OBJS= \ $(SYSDIR)/main.o \ $(SYSDIR)/display.o \ $(MAIN)/analyze.o \ $(MAIN)/blockmap.o \ $(MAIN)/glbsp.o \ $(MAIN)/level.o \ $(MAIN)/node.o \ $(MAIN)/reject.o \ $(MAIN)/seg.o \ $(MAIN)/system.o \ $(MAIN)/util.o \ $(MAIN)/wad.o # ----- TARGETS ------------------------------------------------------ all: $(BIN) clean: rm -f $(OBJS) $(BIN) $(BIN): $(OBJS) $(CC) $(CFLAGS) $(OBJS) -o $(BIN) $(LDFLAGS) $(LIBS) .PHONY: all clean glbsp-2.24-source/old_stuff/GUI_osx.mak0000644000175000017500000000337010650371012017316 0ustar aaptedaapted# # glBSPX Makefile for FLTK under MacOS X # MAIN=src SYSDIR=gui SRC_DIR=glbsp FLTK_PREFIX=../fltk-1.1.6 FLTK_CFLAGS=-I$(FLTK_PREFIX) -I$(FLTK_PREFIX)/zlib FLTK_LIBS=-L$(FLTK_PREFIX)/lib -lfltk_images -lfltk_png -lfltk_z -lfltk_jpeg -lfltk PROGNAME=$(SYSDIR)/glBSPX.app/Contents/glBSPX CC=gcc CXX=g++ CFLAGS=-O2 -Wall -DGLBSP_GUI -DMACOSX -DINLINE_G=inline $(FLTK_CFLAGS) CXXFLAGS=$(CFLAGS) LDFLAGS=-framework Carbon -framework ApplicationServices -Wl,-x LIBS=-lm $(FLTK_LIBS) REZ=/Developer/Tools/Rez -t APPL OBJS=$(SYSDIR)/main.o \ $(SYSDIR)/about.o \ $(SYSDIR)/book.o \ $(SYSDIR)/booktext.o \ $(SYSDIR)/cookie.o \ $(SYSDIR)/dialog.o \ $(SYSDIR)/files.o \ $(SYSDIR)/helper.o \ $(SYSDIR)/images.o \ $(SYSDIR)/license.o \ $(SYSDIR)/menu.o \ $(SYSDIR)/options.o \ $(SYSDIR)/prefs.o \ $(SYSDIR)/progress.o \ $(SYSDIR)/textbox.o \ $(SYSDIR)/window.o \ \ $(MAIN)/analyze.o \ $(MAIN)/blockmap.o \ $(MAIN)/glbsp.o \ $(MAIN)/level.o \ $(MAIN)/node.o \ $(MAIN)/reject.o \ $(MAIN)/seg.o \ $(MAIN)/system.o \ $(MAIN)/util.o \ $(MAIN)/wad.o # ----- TARGETS ------------------------------------------------------ all: $(PROGNAME) clean: rm -f $(PROGNAME) $(MAIN)/*.o $(SYSDIR)/*.o rm -f $(MAIN)/core $(SYSDIR)/core $(MAIN)/glbsp.txt localclean: rm -f $(PROGNAME) $(SYSDIR)/*.o $(SYSDIR)/core $(PROGNAME): $(OBJS) $(CXX) $(CFLAGS) $(OBJS) -o $(PROGNAME) $(LDFLAGS) $(LIBS) ## ?? $(REZ) -o $(PROGNAME) glBSPX.r bin: all strip --strip-unneeded $(PROGNAME) cat $(MAIN)/README.txt $(MAIN)/USAGE.txt $(MAIN)/CHANGES.txt > $(MAIN)/glbsp.txt .PHONY: all clean localclean bin glbsp-2.24-source/old_stuff/Makefile.osx0000644000175000017500000000215210650371207017562 0ustar aaptedaapted# # glBSP Makefile for MacOS X/Cmdline # MAIN=src SYSDIR=cmdline SRC_DIR=glbsp PROGNAME=glbsp CC=gcc CFLAGS=-O2 -Wall -DGLBSP_TEXT -DMACOSX -DINLINE_G=inline LIBS=-lm -lz OBJS=$(SYSDIR)/main.o \ $(SYSDIR)/display.o \ $(MAIN)/analyze.o \ $(MAIN)/blockmap.o \ $(MAIN)/glbsp.o \ $(MAIN)/level.o \ $(MAIN)/node.o \ $(MAIN)/reject.o \ $(MAIN)/seg.o \ $(MAIN)/system.o \ $(MAIN)/util.o \ $(MAIN)/wad.o # ----- TARGETS ------------------------------------------------------ all: $(PROGNAME) clean: rm -f $(PROGNAME) $(MAIN)/*.o $(SYSDIR)/*.o rm -f $(MAIN)/core $(SYSDIR)/core $(MAIN)/glbsp.txt rm -f $(MAIN)/gb_debug.txt $(SYSDIR)/gb_debug.txt $(PROGNAME): $(OBJS) $(CC) $(CFLAGS) $(OBJS) -o $(PROGNAME) $(LIBS) backup: clean tar czf /tmp/glbsp.tgz make* *.[ch] bin: all cat $(MAIN)/README.txt $(MAIN)/USAGE.txt $(MAIN)/CHANGES.txt > $(MAIN)/glbsp.txt install: bin cp $(PROGNAME) /usr/bin/$(PROGNAME) chown root /usr/bin/$(PROGNAME) chmod 755 /usr/bin/$(PROGNAME) .PHONY: all clean backup bin tar zip install glbsp-2.24-source/old_stuff/Plugin_osx.mak0000644000175000017500000000115310650371215020132 0ustar aaptedaapted# # glBSP Plugin Makefile for MacOSX # BIN=libglbsp.a CC=gcc CFLAGS=-O2 -Wall -DGLBSP_PLUGIN -DMACOSX -DINLINE_G=inline # ----- OBJECTS ------------------------------------------------------ OBJS= \ src/analyze.o \ src/blockmap.o \ src/glbsp.o \ src/level.o \ src/node.o \ src/reject.o \ src/seg.o \ src/system.o \ src/util.o \ src/wad.o # ----- TARGETS ------------------------------------------------------ all: $(BIN) clean: rm -f $(BIN) *.o $(BIN): $(OBJS) libtool -static -o $(BIN) - $(OBJS) ranlib $(BIN) .PHONY: all clean glbsp-2.24-source/old_stuff/Makefile.dj0000644000175000017500000000140510650371336017351 0ustar aaptedaapted# # glBSP Makefile for DJGPP # (Note: hasn't been tested for a long time) # MAIN=src SYSDIR=cmdline PROGNAME=glbsp.exe CC=gcc CFLAGS=-O2 -Wall -DGLBSP_TEXT -DINLINE_G=inline LIBS=-lm -lz OBJS=$(SYSDIR)/main.o \ $(SYSDIR)/display.o \ $(MAIN)/analyze.o \ $(MAIN)/blockmap.o \ $(MAIN)/glbsp.o \ $(MAIN)/level.o \ $(MAIN)/node.o \ $(MAIN)/reject.o \ $(MAIN)/seg.o \ $(MAIN)/system.o \ $(MAIN)/util.o \ $(MAIN)/wad.o # ----- TARGETS ------------------------------------------------------ all: $(PROGNAME) clean: rm -f $(PROGNAME) $(MAIN)/*.o $(SYSDIR)/*.o core gb_debug.txt $(PROGNAME): $(OBJS) $(CC) $(CFLAGS) $(OBJS) -o $(PROGNAME) $(LIBS) .PHONY: all clean glbsp-2.24-source/old_stuff/glBSPX.desktop0000644000175000017500000000027110652022537020005 0ustar aaptedaapted[Desktop Entry] Version = 0.9.4 Encoding = UTF-8 Name = glBSPX GenericName = Doom Node Builder Icon = glBSPX.xpm Exec = glBSPX %f Terminal = false Categories = FirstPersonGame;Utility; glbsp-2.24-source/SConscript.edge0000644000175000017500000000105010517101325016230 0ustar aaptedaapted# # SConscript file, builds GLBSP for EDGE # import os Import('build_info') Import('base_env') env = base_env.Copy() env.Append(CCFLAGS = ['-DGLBSP_PLUGIN']) env.Append(CCFLAGS = ['-DINLINE_G=inline']) #FIXME: ZLIB include directory glbsp_sources = [ 'src/analyze.c', 'src/blockmap.c', 'src/glbsp.c', 'src/level.c', 'src/node.c', 'src/reject.c', 'src/seg.c', 'src/system.c', 'src/util.c', 'src/wad.c' ] env.Prepend(CPPPATH = './src') env.StaticLibrary('glbsp', glbsp_sources) ##--- editor settings --- ## vi:ts=4:sw=4:expandtab