eureka-1.11-source/0000755000175100017510000000000012651564503013475 5ustar aaptedaaptedeureka-1.11-source/bindings.cfg0000644000175100017510000000670312651023621015750 0ustar aaptedaapted# Eureka key bindings (installed) # vi:ts=16:noexpandtab browser CMD-k BR_ClearSearch browser PGUP BR_Scroll -3 browser PGDN BR_Scroll +3 render w 3D_Forward 16 render W 3D_Forward 4 render s 3D_Backward 16 render S 3D_Backward 4 render a 3D_Left 16 render A 3D_Left 4 render d 3D_Right 16 render D 3D_Right 4 render UP 3D_Forward 16 render SHIFT-UP 3D_Forward 4 render CMD-UP 3D_Forward 64 render DOWN 3D_Backward 16 render SHIFT-DOWN 3D_Backward 4 render CMD-DOWN 3D_Backward 64 render LEFT 3D_Turn 22.5 render SHIFT-LEFT 3D_Turn 6 render CMD-LEFT 3D_Turn 90 render RIGHT 3D_Turn -22.5 render SHIFT-RIGHT 3D_Turn -6 render CMD-RIGHT 3D_Turn -90 render ALT-LEFT 3D_Left 16 render ALT-RIGHT 3D_Right 16 render PGUP 3D_Up 16 render SHIFT-PGUP 3D_Up 4 render CMD-PGUP 3D_Up 64 render PGDN 3D_Down 16 render SHIFT-PGDN 3D_Down 4 render CMD-PGDN 3D_Down 64 render v 3D_DropToFloor render t 3D_Toggle tex render o 3D_Toggle obj render l 3D_Toggle light render g 3D_Toggle grav render x 3D_Align x render y 3D_Align y render z 3D_Align xy render X 3D_Align x /right render Y 3D_Align y /right render Z 3D_Align xy /right render c 3D_Align xy /clear thing w TH_Spin +45 thing x TH_Spin -45 thing K Toggle skills line e LIN_SelectPath /add line E LIN_SelectPath /add /sametex line k LIN_SplitHalf line w LIN_Flip sector M Merge /keep sector e SEC_SelectGroup /add /floor_h sector E SEC_SelectGroup /add /floor_tex sector w SEC_SwapFlats sector , SEC_Floor -8 sector . SEC_Floor +8 sector < SEC_Floor -1 sector > SEC_Floor +1 sector CMD-, SEC_Floor -64 sector CMD-. SEC_Floor +64 sector [ SEC_Ceil -8 sector ] SEC_Ceil +8 sector { SEC_Ceil -1 sector } SEC_Ceil +1 sector CMD-[ SEC_Ceil -64 sector CMD-] SEC_Ceil +64 vertex I VT_ShapeLine vertex O VT_ShapeArc 360 vertex Q VT_ShapeArc 240 vertex D VT_ShapeArc 180 vertex C VT_ShapeArc 120 general TAB Toggle 3d general b Toggle browser general ; MetaKey general META-; Nothing general T BrowserMode obj general X BrowserMode tex general F BrowserMode flat general L BrowserMode line general S BrowserMode sec general \ Toggle recent general | BR_CycleCategory general + Zoom +1 general = Zoom +1 general - Zoom -1 general _ Zoom -1 general HOME ZoomWholeMap general 0 ZoomWholeMap general END GoToCamera general ' PlaceCamera general ` UnselectAll general UP Scroll 0 +10 general DOWN Scroll 0 -10 general LEFT Scroll -10 0 general RIGHT Scroll +10 0 general SHIFT-UP Scroll 0 +40 general SHIFT-DOWN Scroll 0 -40 general SHIFT-LEFT Scroll -40 0 general SHIFT-RIGHT Scroll +40 0 general g GRID_Step -1 general G GRID_Step +1 general h Toggle grid general f Toggle snap general l EditMode line general s EditMode sector general v EditMode vertex general t EditMode thing general r EditMode rts general N FlipMap next general P FlipMap prev general META-n GivenFile next general META-p GivenFile prev general SPACE Insert general INS Insert general SHIFT-SPACE Insert /continue general SHIFT-INS Insert /continue general CMD-SPACE Insert /new /nofill general CMD-INS Insert /new /nofill general DEL Delete general BS Delete general SHIFT-DEL Delete /keep_unused general SHIFT-BS Delete /keep_unused general d Disconnect general m Merge general q Quantize general j JumpToObject general o CopyAndPaste general p PruneUnused general H Mirror horiz general V Mirror vert general W Rotate90 acw general R Rotate90 cw general c CopyProperties general J Toggle obj_nums general F11 Gamma +1 general META-f ApplyTag fresh general META-l ApplyTag last eureka-1.11-source/AUTHORS.txt0000644000175100017510000000134712651344432015365 0ustar aaptedaapted EUREKA AUTHORS ============== DEVELOPER: Andrew Apted  I created Eureka (based on an existing program) and continue to develop it. CONTRIBUTORS: Ioan Chera * MacOS X port Fabian Greffrath * Debian packager Jason R. Johnston (fiftyoars.com) * Eureka Logo Wesley Johnson * Doom Legacy definition file EARLIER WORK: André Majorel created the Yadex editor. Eureka began as a fork of this editor, version 1.7.0 to be precise. Raphael Quinet and Brendon Wyber created DEU 5.21, which Yadex was derived from. Both Yadex and DEU had many contributors, a comprehensive list of them can be found in the Yadex documentation. ACKNOWLEDGEMENTS: Eureka uses the FLTK widget library (http://www.fltk.org) eureka-1.11-source/src/0000755000175100017510000000000012651564411014262 5ustar aaptedaaptedeureka-1.11-source/src/ui_browser.cc0000644000175100017510000007454512651124306016763 0ustar aaptedaapted//------------------------------------------------------------------------ // BROWSER for TEXTURES / FLATS / THINGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 "main.h" #include #include #include "ui_window.h" #include "ui_browser.h" #include "im_img.h" #include "im_color.h" #include "m_config.h" #include "m_game.h" #include "e_things.h" #include "w_rawdef.h" #include "w_flats.h" #include "w_texture.h" #include "levels.h" extern std::map flats; extern std::map textures; extern std::map line_groups; extern std::map thing_groups; extern std::map line_types; extern std::map sector_types; extern std::map thing_types; #define BROWBACK_COL (gui_scheme == 2 ? FL_DARK3 : FL_DARK2) // config items bool browser_small_tex = false; // sort methods typedef enum { SOM_Numeric = 0, SOM_Alpha, SOM_AlphaSkip, // skip the S1, WR (etc) of linedef descriptions SOM_Recent } sort_method_e; /* text item */ Browser_Item::Browser_Item(int X, int Y, int W, int H, const char *_desc, const char *_realname, int _num, char _category) : Fl_Group(X, Y, W, H, ""), desc(_desc), real_name(_realname), number(_num), category(_category), recent_idx(-2), button(NULL), pic(NULL) { end(); button = new Fl_Repeat_Button(X + 4, Y + 1, W - 8, H - 2, desc.c_str()); button->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); button->labelfont(FL_COURIER); button->labelsize(12 + KF * 2); button->when(FL_WHEN_CHANGED); add(button); } /* image item */ Browser_Item::Browser_Item(int X, int Y, int W, int H, const char *_desc, const char *_realname, int _num, char _category, int pic_w, int pic_h, UI_Pic *_pic) : Fl_Group(X, Y, W, H, ""), desc(_desc), real_name(_realname), number(_num), category(_category), recent_idx(-2), button(NULL), pic(_pic) { end(); add(pic); Fl_Box *box = new Fl_Box(FL_NO_BOX, X + 4, Y + H - 28, W - 4, 24, desc.c_str()); box->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER); box->labelcolor(FL_WHITE); box->labelsize(12); add(box); resizable(NULL); } Browser_Item::~Browser_Item() { // TODO } void Browser_Item::texture_callback(Fl_Widget *w, void *data) { const char *tex_name = (const char *)data; SYS_ASSERT(tex_name); main_win->BrowsedItem('T', 0, tex_name, Fl::event_state()); } void Browser_Item::flat_callback(Fl_Widget *w, void *data) { const char *flat_name = (const char *)data; SYS_ASSERT(flat_name); main_win->BrowsedItem('F', 0, flat_name, Fl::event_state()); } void Browser_Item::thing_callback(Fl_Widget *w, void *data) { Browser_Item * item = (Browser_Item *) data; main_win->BrowsedItem('O', item->number, "", Fl::event_state()); } void Browser_Item::line_callback(Fl_Widget *w, void *data) { Browser_Item * item = (Browser_Item *) data; main_win->BrowsedItem('L', item->number, "", Fl::event_state()); } void Browser_Item::sector_callback(Fl_Widget *w, void *data) { Browser_Item * item = (Browser_Item *) data; main_win->BrowsedItem('S', item->number, "", Fl::event_state()); } //------------------------------------------------------------------------ UI_Browser_Box::UI_Browser_Box(int X, int Y, int W, int H, const char *label, char _kind) : Fl_Group(X, Y, W, H, NULL), kind(_kind), pic_mode(false) { end(); // cancel begin() in Fl_Group constructor box(FL_FLAT_BOX); color(BROWBACK_COL, BROWBACK_COL); strcpy(cat_letters, "*"); int cx = X + 80 + KF * 8; int cy = Y + 4; Fl_Box *title = new Fl_Box(X + 34, cy, W - 90, 22+KF*4, label); title->labelsize(20+KF*4); add(title); Fl_Button *hide_button = new Fl_Button(X + 8, cy+2, 22, 22, "X"); hide_button->callback(hide_callback, this); hide_button->labelsize(14); add(hide_button); cy += title->h() + 6; category = new Fl_Choice(cx, cy, 160, 22, "Category:"); category->align(FL_ALIGN_LEFT); category->add("ALL"); category->value(0); category->labelsize(KF_fonth); category->textsize(KF_fonth); category->callback(filter_callback, this); add(category); cy += category->h() + 9; search = new Fl_Input(cx, cy, 120, 22, "Match:"); search->align(FL_ALIGN_LEFT); search->callback(filter_callback, this); search->when(FL_WHEN_CHANGED); add(search); cy += search->h() + 6; alpha = NULL; if (strchr("OSL", kind)) { alpha = new Fl_Check_Button(cx, cy, 75, 22, " Alpha"); // things need to repopulate (in picture mode anyway) if (kind == 'O') alpha->callback(repop_callback, this); else alpha->callback(sort_callback, this); // things usually show pics (with sprite name), so want alpha if (kind == 'O') alpha->value(1); add(alpha); } pics = NULL; if (strchr("O", kind)) { pics = new Fl_Check_Button(X+172, cy, 64, 22, " Pics"); pics->value(1); pics->callback(repop_callback, this); add(pics); } if (strchr("OSL", kind)) { cy += 30; } int top_H = cy - Y; scroll = new UI_Scroll(X, cy, W, H-3 - top_H); scroll->box(FL_FLAT_BOX); add(scroll); // resize box Fl_Box * rs_box = new Fl_Box(FL_NO_BOX, X + W - 10, Y + top_H, 8, H - top_H, NULL); resizable(rs_box); } UI_Browser_Box::~UI_Browser_Box() { // nothing needed } void UI_Browser_Box::resize(int X, int Y, int W, int H) { Fl_Group::resize(X, Y, W, H); Fl_Widget * rs_box = resizable(); rs_box->resize(X + W - 10, Y + rs_box->h(), 8, H - rs_box->h()); // rearrange images if (pic_mode) { Filter(); } } void UI_Browser_Box::filter_callback(Fl_Widget *w, void *data) { UI_Browser_Box *that = (UI_Browser_Box *)data; that->Filter(); } void UI_Browser_Box::hide_callback(Fl_Widget *w, void *data) { main_win->ShowBrowser(0); } void UI_Browser_Box::repop_callback(Fl_Widget *w, void *data) { UI_Browser_Box *that = (UI_Browser_Box *)data; that->Populate(); } void UI_Browser_Box::sort_callback(Fl_Widget *w, void *data) { UI_Browser_Box *that = (UI_Browser_Box *)data; that->Sort(); } bool UI_Browser_Box::Filter(bool force_update) { bool changes = false; int left_X = scroll->x() + SBAR_W; int right_X = left_X + scroll->w() - SBAR_W; // current position int cx = left_X; int cy = scroll->y(); // the highest visible widget on the current line int highest = 0; for (int i = 0 ; i < scroll->Children() ; i++) { Browser_Item *item = (Browser_Item *)scroll->Child(i); item->redraw(); bool keep = SearchMatch(item); if (keep != (item->visible() ? true : false)) { if (keep) item->show(); else item->hide(); changes = true; } if (! keep) { item->position(cx, cy); continue; } // can it fit on the current row? if (pic_mode && (cx <= left_X || (cx + item->w()) <= right_X)) { // Yes } else { // No, move down to the next row cx = left_X; cy += highest; highest = 0; } // update position item->position(cx, cy); cx += item->w(); highest = MAX(highest, item->h()); } scroll->Init_sizes(); scroll->redraw(); return changes; } bool UI_Browser_Box::SearchMatch(Browser_Item *item) const { if (category->value() > 0) { char cat = cat_letters[category->value()]; // special logic for RECENT category [ignore search box] if (cat == '^') return (item->recent_idx >= 0); if (! (cat == tolower(item->category) || (cat == 'X' && isupper(item->category)))) return false; } // here an empty pattern matches EVERYTHING // [ different to Texture_MatchPattern semantics ] if (search->size() == 0) return true; const char *pattern = search->value(); if (kind == 'T' || kind == 'F') return Texture_MatchPattern(item->real_name.c_str(), pattern); return Texture_MatchPattern(item->desc.c_str(), pattern); } bool UI_Browser_Box::Recent_UpdateItem(Browser_Item *item) { // returns true if the index changed int new_idx = -1; switch (kind) { case 'T': new_idx = recent_textures.find(item->real_name.c_str()); break; case 'F': new_idx = recent_flats.find(item->real_name.c_str()); break; case 'O': new_idx = recent_things.find_number(item->number); break; default: return false; } if (item->recent_idx == new_idx) return false; item->recent_idx = new_idx; return true; } static int SortCmp(const Browser_Item *A, const Browser_Item *B, sort_method_e method) { const char *sa = A->desc.c_str(); const char *sb = B->desc.c_str(); if (method == SOM_Numeric) { return (A->number - B->number); } else if (method == SOM_Recent) { return (A->recent_idx - B->recent_idx); } if (strchr(sa, '/')) sa = strchr(sa, '/') + 1; if (strchr(sb, '/')) sb = strchr(sb, '/') + 1; // Alphabetical in LINEDEF mode, skip trigger type (SR etc) if (method == SOM_AlphaSkip) { while (isspace(*sa)) sa++; while (isspace(*sb)) sb++; if (sa[0] && sa[1] && sa[2] == ' ') while (! isspace(*sa)) sa++; if (sb[0] && sb[1] && sb[2] == ' ') while (! isspace(*sb)) sb++; } return strcmp(sa, sb); } static void SortPass(std::vector< Browser_Item * >& ARR, int gap, int total, sort_method_e method) { int i, k; for (i = gap ; i < total ; i++) { Browser_Item * temp = ARR[i]; for (k = i ; k >= gap && SortCmp(ARR[k - gap], temp, method) > 0 ; k -= gap) ARR[k] = ARR[k - gap]; ARR[k] = temp; } } void UI_Browser_Box::Sort() { int total = scroll->Children(); // transfer widgets to a local vector std::vector< Browser_Item * > ARR; for (int i = 0 ; i < total ; i++) { ARR.push_back( (Browser_Item *) scroll->Child(0)); scroll->Remove_first(); } char cat = cat_letters[category->value()]; sort_method_e method = SOM_Alpha; if (cat == '^') method = SOM_Recent; else if (alpha && ! alpha->value()) method = SOM_Numeric; else if (kind == 'L') method = SOM_AlphaSkip; // shell sort SortPass(ARR, 9, total, method); SortPass(ARR, 4, total, method); SortPass(ARR, 1, total, method); // transfer them back to the scroll widget for (int i = 0 ; i < total ; i++) scroll->Add(ARR[i]); // reposition them all Filter(true); } const char * TidyLineDesc(const char *name) { // escapes any '&' characters for FLTK if (! strchr(name, '&')) return name; static char buffer[FL_PATH_MAX]; char *dest = buffer; for (const char *src = name ; *src ; src++) { if (*src == '&') { *dest++ = '&'; *dest++ = '&'; continue; } *dest++ = *src; } *dest = 0; return buffer; } void UI_Browser_Box::Populate_Images(std::map & img_list) { /* Note: the side-by-side packing is done in Filter() method */ pic_mode = true; scroll->color(FL_BLACK, FL_BLACK); scroll->resize_horiz(false); scroll->Line_size(98); std::map::iterator TI; int cx = scroll->x() + SBAR_W; int cy = scroll->y(); char full_desc[256]; for (TI = img_list.begin() ; TI != img_list.end() ; TI++) { const char *name = TI->first.c_str(); Img_c *image = TI->second; if (false) /* NO PICS */ snprintf(full_desc, sizeof(full_desc), "%-8s : %3dx%d", name, image->width(), image->height()); else snprintf(full_desc, sizeof(full_desc), "%-8s", name); int pic_w = (kind == 'F' || image->width() <= 64) ? 64 : 128; // MIN(128, MAX(4, image->width())); int pic_h = (kind == 'F') ? 64 : MIN(128, MAX(4, image->height())); if (browser_small_tex && kind == 'T') { pic_w = 64; pic_h = MIN(64, MAX(4, image->height())); } if (image->width() >= 256 && image->height() == 128) { pic_w = 128; pic_h = 64; } int item_w = 8 + MAX(pic_w, 64) + 2; int item_h = 4 + MAX(pic_h, 16) + 2 + 24 + 4; char category = 0; UI_Pic *pic = new UI_Pic(cx + 8, cy + 4, pic_w, pic_h); if (kind == 'F') { pic->GetFlat(name); pic->callback(Browser_Item::flat_callback, (void *)name); category = M_GetFlatType(name); } else if (kind == 'T') { pic->GetTex(name); pic->callback(Browser_Item::texture_callback, (void *)name); category = M_GetTextureType(name); } Browser_Item *item = new Browser_Item(cx, cy, item_w, item_h, full_desc, name, 0 /* num */, category, pic_w, pic_h, pic); scroll->Add(item); } } void UI_Browser_Box::Populate_Sprites() { /* Note: the side-by-side packing is done in Filter() method */ pic_mode = true; scroll->color(FL_BLACK, FL_BLACK); scroll->resize_horiz(false); scroll->Line_size(98); std::map::iterator TI; int cx = scroll->x() + SBAR_W; int cy = scroll->y(); char full_desc[256]; for (TI = thing_types.begin() ; TI != thing_types.end() ; TI++) { thingtype_t *info = TI->second; // ignore sprite-less things if (y_stricmp(info->sprite, "NULL") == 0) continue; if (alpha->value() == 0) sprintf(full_desc, "%d", TI->first); else snprintf(full_desc, sizeof(full_desc), "%s", info->sprite); int pic_w = 64; int pic_h = 72; int item_w = 8 + MAX(pic_w, 64) + 2; int item_h = 4 + MAX(pic_h, 16) + 2 + 24 + 4; UI_Pic *pic = new UI_Pic(cx + 8, cy + 4, pic_w, pic_h); pic->GetSprite(TI->first, FL_BLACK); Browser_Item *item = new Browser_Item(cx, cy, item_w, item_h, full_desc, "", TI->first, info->group, pic_w, pic_h, pic); pic->callback(Browser_Item::thing_callback, item); scroll->Add(item); } } void UI_Browser_Box::Populate_ThingTypes() { std::map::iterator TI; int y = scroll->y(); int mx = scroll->x() + SBAR_W; int mw = scroll->w() - SBAR_W; char full_desc[256]; for (TI = thing_types.begin() ; TI != thing_types.end() ; TI++) { thingtype_t *info = TI->second; snprintf(full_desc, sizeof(full_desc), "%4d/ %s", TI->first, info->desc); Browser_Item *item = new Browser_Item(mx, y, mw, 24, full_desc, "", TI->first, info->group); item->button->callback(Browser_Item::thing_callback, item); scroll->Add(item); } } void UI_Browser_Box::Populate_LineTypes() { std::map::iterator TI; int y = scroll->y(); int mx = scroll->x() + SBAR_W; int mw = scroll->w() - SBAR_W; char full_desc[256]; for (TI = line_types.begin() ; TI != line_types.end() ; TI++) { linetype_t *info = TI->second; snprintf(full_desc, sizeof(full_desc), "%3d/ %s", TI->first, TidyLineDesc(info->desc)); Browser_Item *item = new Browser_Item(mx, y, mw, 24, full_desc, "", TI->first, info->group); item->button->callback(Browser_Item::line_callback, item); scroll->Add(item); } } void UI_Browser_Box::Populate_SectorTypes() { std::map::iterator TI; int y = scroll->y(); int mx = scroll->x() + SBAR_W; int mw = scroll->w() - SBAR_W; char full_desc[256]; for (TI = sector_types.begin() ; TI != sector_types.end() ; TI++) { sectortype_t *info = TI->second; snprintf(full_desc, sizeof(full_desc), "%3d/ %s", TI->first, info->desc); Browser_Item *item = new Browser_Item(mx, y, mw, 24, full_desc, "", TI->first, 0 /* cat */); item->button->callback(Browser_Item::sector_callback, item); scroll->Add(item); } } void UI_Browser_Box::Populate() { // delete existing ones scroll->Remove_all(); // default background and scroll rate scroll->color(WINDOW_BG, WINDOW_BG); scroll->resize_horiz(true); scroll->Line_size(24 * 2); pic_mode = false; switch (kind) { case 'T': Populate_Images(textures); break; case 'F': Populate_Images(flats); break; case 'O': if (pics->value()) Populate_Sprites(); else Populate_ThingTypes(); break; case 'L': Populate_LineTypes(); break; case 'S': Populate_SectorTypes(); break; default: break; } RecentUpdate(); // this calls Filter to reposition the widgets Sort(); } void UI_Browser_Box::SetCategories(const char *cats, const char *letters) { strncpy(cat_letters, letters, sizeof(cat_letters)); cat_letters[sizeof(cat_letters) - 1] = 0; category->clear(); category->add(cats); category->value(0); redraw(); } void UI_Browser_Box::CycleCategory(int dir) { // need '- 1' since the size() includes the empty terminator int total_cats = category->size() - 1; if (total_cats <= 1) return; int new_cat = category->value(); for (int loop = 0 ; loop < 2 ; loop++) { if (dir > 0) { new_cat = (new_cat + 1) % total_cats; } else if (dir < 0) { new_cat = (new_cat + total_cats - 1) % total_cats; } // skip the RECENT category if (new_cat != 1) break; } if (category->value(new_cat)) { Filter(); } } bool UI_Browser_Box::CategoryByLetter(char letter) { // need '- 1' since the size() includes the empty terminator int total_cats = category->size() - 1; for (int i = 0 ; i < total_cats ; i++) { if (cat_letters[i] == letter) { category->value(i); Filter(); return true; } } return false; } void UI_Browser_Box::ClearSearchBox() { if (search->size() > 0) { search->value(""); Filter(); } } void UI_Browser_Box::Scroll(int delta) { scroll->Scroll(delta); } void UI_Browser_Box::RecentUpdate() { bool changes = false; for (int i = 0 ; i < scroll->Children() ; i++) { Browser_Item *item = (Browser_Item *)scroll->Child(i); if (Recent_UpdateItem(item)) changes = true; } char cat = cat_letters[category->value()]; if (changes && cat == '^') Sort(); } void UI_Browser_Box::ToggleRecent(bool force_recent) { char cat = cat_letters[category->value()]; if (cat == '^' && force_recent) { Filter(); return; } // this logic assumes first category is ALL, second is RECENT if (cat_letters[1] != '^') return; int new_cat = (cat == '^') ? 0 : 1; category->value(new_cat); Sort(); } //------------------------------------------------------------------------ class UI_Generalized_Item : public Fl_Choice { public: const generalized_field_t * field; public: UI_Generalized_Item(int X, int Y, int W, int H, const generalized_field_t *_field) : Fl_Choice(X, Y, W, H, ""), field(_field) { char label_buf[256]; snprintf(label_buf, sizeof(label_buf), "%s: ", field->name); copy_label(label_buf); for (int i = 0 ; i < field->num_keywords ; i++) { add(field->keywords[i]); } Reset(); } ~UI_Generalized_Item() { } int Compute() const { return (value() << field->shift) & field->mask; } void Decode(int line_type) { value((line_type & field->mask) >> field->shift); } void Reset() { int def_val = CLAMP(0, field->default_val, field->num_keywords - 1); value(def_val); } }; class UI_Generalized_Page : public Fl_Group { public: int t_base; int t_length; UI_Generalized_Item * items[MAX_GEN_NUM_FIELDS]; int num_items; // index for the "Change", "Model", "Monster" triplet, usually -1 int change_index; UI_Generalized_Item *change_widget; private: static void item_callback(Fl_Widget *w, void *data) { UI_Generalized_Page *page = (UI_Generalized_Page *)data; if (w == page->change_widget) page->UpdateChange(); page->do_callback(); } public: UI_Generalized_Page(int X, int Y, int W, int H, const generalized_linetype_t *info) : Fl_Group(X, Y, W, H), t_base(info->base), t_length(info->length), num_items(0), change_index(-1), change_widget(NULL) { #if 0 box(FL_FLAT_BOX); color(FL_BLUE, FL_BLUE); #endif memset(items, 0, sizeof(items)); num_items = info->num_fields; Y += 5; for (int i = 0 ; i < num_items ; i++) { bool is_change = (y_stricmp(info->fields[i].name, "Change") == 0); if (is_change) Y += 10; items[i] = new UI_Generalized_Item(X + 100, Y, 120, 22, &info->fields[i]); items[i]->callback(item_callback, this); if (is_change && (i+2) < num_items) { change_index = i; change_widget = items[i]; } if (change_index >= 0 && i == change_index+1) items[i]->deactivate(); Y += 30; } end(); } ~UI_Generalized_Page() { } void UpdateChange() { if (change_index < 0) return; if (items[change_index]->value() == 0) { items[change_index+1]->deactivate(); items[change_index+2]-> activate(); } else { items[change_index+1]-> activate(); items[change_index+2]->deactivate(); } } int ComputeType() const { int value = 0; for (int i = 0 ; i < num_items ; i++) { if (items[i]->active()) value = value | items[i]->Compute(); } return t_base + value; } void DecodeType(int line_type) { line_type -= t_base; for (int i = 0 ; i < num_items ; i++) { items[i]->Decode(line_type); } UpdateChange(); } void ResetFields() { for (int i = 0 ; i < num_items ; i++) { items[i]->Reset(); } } }; UI_Generalized_Box::UI_Generalized_Box(int X, int Y, int W, int H, const char *label) : Fl_Group(X, Y, W, H, NULL), num_pages(0), in_update(false) { box(FL_FLAT_BOX); color(BROWBACK_COL, BROWBACK_COL); memset(pages, 0, sizeof(pages)); int orig_X = X; /// X = X + (W - MIN_BROWSER_W); Y += 10; Fl_Box *title = new Fl_Box(X + 30, Y, W - 114, 22+KF*4, label); title->labelsize(20+KF*4); Fl_Button *hide_button = new Fl_Button(X + 8, Y+2, 22, 22, "X"); hide_button->callback(hide_callback, this); hide_button->labelsize(14); Y += title->h() + 6; no_boom = new Fl_Box(FL_NO_BOX, X + 2, Y + 40, W - 60, 60, "This requires BOOM\n(or a compatible port)"); no_boom->labelsize(18); no_boom->labelcolor(FL_BLUE); no_boom->align(FL_ALIGN_INSIDE); Y += 10; category = new Fl_Choice(X + 40, Y, 170, 30); category->callback(cat_callback, this); category->textsize(16); end(); // resize box Fl_Box * rs_box = new Fl_Box(FL_NO_BOX, orig_X + W - 10, Y + H - 10, 8, 8, NULL); resizable(rs_box); } UI_Generalized_Box::~UI_Generalized_Box() { // nothing needed } void UI_Generalized_Box::Populate() { if (! game_info.gen_types) { no_boom->show(); category->hide(); for (int i = 0 ; i < num_pages ; i++) pages[i]->hide(); } else { // we only create the pages once // [ not strictly correct, but the generalized types never change ] if (! pages[0]) CreatePages(); no_boom->hide(); category->show(); for (int i = 0 ; i < num_pages ; i++) { if (i == category->value() - 1) pages[i]->show(); else pages[i]->hide(); } } redraw(); } void UI_Generalized_Box::CreatePages() { memset(pages, 0, sizeof(pages)); num_pages = 0; category->clear(); category->add("NONE"); int X = x(); /// + (w() - MIN_BROWSER_W); for (int i = 0 ; i < num_gen_linetypes ; i++) { const generalized_linetype_t *info = &gen_linetypes[i]; category->add(info->name); pages[i] = new UI_Generalized_Page(X + 10, y() + 100, 230, 300, info); pages[i]->callback(edit_callback, this); add(pages[i]); num_pages += 1; } category->value(0); } int UI_Generalized_Box::ComputeType() const { int cur_page = category->value(); if (cur_page == 0) return 0; return pages[cur_page - 1]->ComputeType(); } void UI_Generalized_Box::UpdateGenType(int line_type) { if (in_update) return; if (no_boom->visible() || num_pages == 0) return; int new_page = -1; for (int i = 0 ; i < num_pages ; i++) { if (pages[i]->t_base <= line_type && line_type < pages[i]->t_base + pages[i]->t_length) { new_page = i; break; } } if (new_page < 0) { for (int k = 0 ; k < num_pages ; k++) pages[k]->ResetFields(); if (category->value() != 0) { category->value(0); Populate(); } return; } if (category->value() != new_page + 1) { category->value(new_page + 1); Populate(); } pages[new_page]->DecodeType(line_type); } void UI_Generalized_Box::hide_callback(Fl_Widget *w, void *data) { main_win->ShowBrowser(0); } void UI_Generalized_Box::cat_callback(Fl_Widget *w, void *data) { UI_Generalized_Box *box = (UI_Generalized_Box *)data; int new_page = box->category->value() - 1; for (int i = 0 ; i < box->num_pages ; i++) { if (i == new_page) box->pages[i]->show(); else box->pages[i]->hide(); } edit_callback(w, (void *)box); box->redraw(); } void UI_Generalized_Box::edit_callback(Fl_Widget *w, void *data) { UI_Generalized_Box *box = (UI_Generalized_Box *)data; if (box->no_boom->visible() || box->num_pages == 0) return; box->in_update = true; // prevent some useless work { int line_type = box->ComputeType(); main_win->BrowsedItem('L', line_type, "", 0); } box->in_update = false; } //------------------------------------------------------------------------ UI_Browser::UI_Browser(int X, int Y, int W, int H, const char *label) : Fl_Group(X, Y, W, H, label), active(2) { // create each browser box const char *mode_letters = "TFOLS"; const char *mode_titles[5] = { "Textures", "Flats", "Things", "Line Types", "Sector Types" }; for (int i = 0 ; i < 5 ; i++) { browsers[i] = new UI_Browser_Box(X, Y, W, H, mode_titles[i], mode_letters[i]); if (i != active) browsers[i]->hide(); } gen_box = new UI_Generalized_Box(X, Y, W, H, "Generalized"); gen_box->hide(); end(); } UI_Browser::~UI_Browser() { // nothing needed } void UI_Browser::Populate() { for (int i = 0 ; i < 5 ; i++) { browsers[i]->Populate(); } gen_box->Populate(); // setup the categories char letters[64]; const char *tex_cats = M_TextureCategoryString(letters, false); browsers[0]->SetCategories(tex_cats, letters); const char *flat_cats = M_TextureCategoryString(letters, true); browsers[1]->SetCategories(flat_cats, letters); const char *thing_cats = M_ThingCategoryString(letters); browsers[2]->SetCategories(thing_cats, letters); const char *line_cats = M_LineCategoryString(letters); browsers[3]->SetCategories(line_cats, letters); // TODO: sector_cats // no ceiling_cats, fortunately :) } void UI_Browser::SetActive(int new_active) { if (new_active == active) return; if (active < ACTIVE_GENERALIZED) browsers[active]->hide(); else gen_box->hide(); active = new_active; if (active < ACTIVE_GENERALIZED) { browsers[active]->show(); browsers[active]->RecentUpdate(); } else { gen_box->show(); } if (new_active == ACTIVE_GENERALIZED) main_win->tile->MinimiseRight(); } void UI_Browser::ChangeMode(char new_mode) { switch (new_mode) { case 'T': SetActive(0); break; // TEXTURES case 'F': SetActive(1); break; // FLATS case 'O': SetActive(2); break; // THINGS (Objects) case 'L': SetActive(3); break; // LINE TYPES case 'S': SetActive(4); break; // SECTOR TYPES case 'G': SetActive(ACTIVE_GENERALIZED); break; default: break; } } void UI_Browser::NewEditMode(obj_type_e edit_mode) { switch (edit_mode) { case OBJ_LINEDEFS: // if on LINE TYPES, stay there // otherwise go to TEXTURES if (! (active == 3 || active == ACTIVE_GENERALIZED)) SetActive(0); break; case OBJ_SECTORS: // if on SECTOR TYPES, stay there // otherwise go to FLATS if (active != 4) SetActive(1); break; case OBJ_THINGS: SetActive(2); break; default: /* no change */ break; } } void UI_Browser::CycleCategory(int dir) { if (active < ACTIVE_GENERALIZED) { browsers[active]->CycleCategory(dir); } } void UI_Browser::ClearSearchBox() { if (active < ACTIVE_GENERALIZED) { browsers[active]->ClearSearchBox(); } // idea : reset generalized info } void UI_Browser::Scroll(int delta) { if (active < ACTIVE_GENERALIZED) { browsers[active]->Scroll(delta); } } void UI_Browser::RecentUpdate() { if (active < ACTIVE_GENERALIZED) { UI_Browser_Box *box = browsers[active]; box->RecentUpdate(); } } void UI_Browser::ToggleRecent(bool force_recent) { // show browser if hidden [ and then force the RECENT category ] if (! visible()) { main_win->ShowBrowser('/'); force_recent = true; } if (active < ACTIVE_GENERALIZED) { browsers[active]->ToggleRecent(force_recent); } } void UI_Browser::UpdateGenType(int line_type) { gen_box->UpdateGenType(line_type); } //------------------------------------------------------------------------ bool UI_Browser_Box::ParseUser(const char ** tokens, int num_tok) { // syntax is: browser if (num_tok < 3) return false; if (strcmp(tokens[0], "browser") != 0) return false; if (tokens[1][0] != kind) return false; tokens += 2; num_tok -= 2; if (strcmp(tokens[0], "cat") == 0 && num_tok >= 2) { CategoryByLetter(tokens[1][0]); return true; } if (strcmp(tokens[0], "sort") == 0 && num_tok >= 2 && alpha) { alpha->value(atoi(tokens[1]) ? 0 : 1); Sort(); return true; } if (strcmp(tokens[0], "search") == 0 && num_tok >= 2) { search->value(tokens[1]); Filter(); return true; } if (strcmp(tokens[0], "pics") == 0 && num_tok >= 2 && pics) { pics->value(atoi(tokens[1]) ? 1 : 0); // pics_callback(); return true; } return true; } void UI_Browser_Box::WriteUser(FILE *fp) { char cat = cat_letters[category->value()]; if (isprint(cat)) fprintf(fp, "browser %c cat %c\n", kind, cat); if (alpha) fprintf(fp, "browser %c sort %d\n", kind, 1 - alpha->value()); fprintf(fp, "browser %c search \"%s\"\n", kind, StringTidy(search->value(), "\"")); if (pics) fprintf(fp, "browser %c pics %d\n", kind, pics->value()); } bool UI_Browser::ParseUser(const char ** tokens, int num_tok) { if (strcmp(tokens[0], "open_browser") == 0 && num_tok >= 2) { main_win->ShowBrowser(tokens[1][0]); return true; } for (int i = 0 ; i < 5 ; i++) { if (browsers[i]->ParseUser(tokens, num_tok)) return true; } return false; } void UI_Browser::WriteUser(FILE *fp) { fprintf(fp, "\n"); fprintf(fp, "open_browser %c\n", (! visible()) ? '-' : (active >= ACTIVE_GENERALIZED) ? 'G' : browsers[active]->GetKind()); for (int i = 0 ; i < 5 ; i++) { browsers[i]->WriteUser(fp); } // generalized box is not saved (not needed) } bool Browser_ParseUser(const char ** tokens, int num_tok) { if (main_win) { if (main_win->tile->ParseUser(tokens, num_tok)) return true; if (main_win->browser->ParseUser(tokens, num_tok)) return true; } return false; } void Browser_WriteUser(FILE *fp) { if (main_win) { main_win->tile ->WriteUser(fp); main_win->browser->WriteUser(fp); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_nombre.cc0000644000175100017510000000464412647061302016554 0ustar aaptedaapted//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2009 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 "main.h" #include "m_config.h" #include "ui_window.h" #include "ui_nombre.h" #define NOMBRBACK_COL (gui_scheme == 2 ? FL_GRAY0+1 : FL_GRAY0+3) // // UI_Nombre Constructor // UI_Nombre::UI_Nombre(int X, int Y, int W, int H, const char *what) : Fl_Box(FL_FLAT_BOX, X, Y, W, H, ""), index(-1), total(0), selected(0) { type_name = strdup(what); // FIXME: consistent string handling align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); color(NOMBRBACK_COL); labelfont(FL_COURIER_BOLD); labelsize(16 + KF*3); Update(); } // // UI_Nombre Destructor // UI_Nombre::~UI_Nombre() { } void UI_Nombre::Update() { char buffer[256]; /// if (index < 0 && total <= 0) /// sprintf(buffer, "%s: NONE\n", type_name); /// else if (index < 0) sprintf(buffer, "No %s / %d\n", type_name, total); else if (selected > 1) sprintf(buffer, "%s #%-4d + %d more\n", type_name, index, selected-1); else sprintf(buffer, "%s #%-4d / %d\n", type_name, index, total); if (index < 0 || total == 0) labelcolor(FL_DARK1); else labelcolor(FL_YELLOW); if (index < 0 || total == 0) color(NOMBRBACK_COL); else if (selected == 0) color(NOMBRBACK_COL); // same as above else if (selected == 1) color(FL_BLUE); else color(FL_RED); copy_label(buffer); } void UI_Nombre::SetIndex(int _idx) { if (index != _idx) { index = _idx; Update(); } } void UI_Nombre::SetTotal(int _tot) { if (total != _tot) { total = _tot; Update(); } } void UI_Nombre::SetSelected(int _sel) { if (selected != _sel) { selected = _sel; Update(); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_basis.h0000644000175100017510000002145012647061302016036 0ustar aaptedaapted//------------------------------------------------------------------------ // BASIC OBJECT HANDLING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_BASIS_H__ #define __EUREKA_E_BASIS_H__ class crc32_c; // // DESIGN NOTES // // Every field in these structures are a plain 'int'. This is a // design decision aiming to simplify the logic and code for undo // and redo. // // Strings are represented as offsets into a string table, where // fetching the actual (read-only) string is fast, but adding new // strings is slow (with the current code). // // These structures are always ensured to have valid fields, e.g. // the LineDef vertex numbers are OK, the SideDef sector number is // valid, etc. For LineDefs, the left and right fields can contain // -1 to mean "no sidedef", but note that a missing right sidedef // can cause problems when playing the map in DOOM. // typedef enum { SIDE_RIGHT = +1, SIDE_LEFT = -1 } side_ref_e; // See objid.h for obj_type_e (OBJ_THINGS etc) class Thing { public: int x; int y; int angle; int type; int options; // Hexen stuff int z; int tid; int special; int arg1, arg2, arg3, arg4, arg5; enum { F_X, F_Y, F_ANGLE, F_TYPE, F_OPTIONS, F_Z, F_TID, F_SPECIAL, F_ARG1, F_ARG2, F_ARG3, F_ARG4, F_ARG5 }; public: Thing() : x(0), y(0), angle(0), type(0), options(7), z(0), tid(0), special(0), arg1(0), arg2(0), arg3(0), arg4(0), arg5(0) { } void RawCopy(const Thing *other) { x = other->x; y = other->y; angle = other->angle; type = other->type; options = other->options; z = other->z; tid = other->tid; special = other->special; arg1 = other->arg1; arg2 = other->arg2; arg3 = other->arg3; arg4 = other->arg4; arg5 = other->arg5; } }; class Vertex { public: int x; int y; enum { F_X, F_Y }; public: Vertex() : x(0), y(0) { } void RawCopy(const Vertex *other) { x = other->x; y = other->y; } bool Matches(int ox, int oy) const { return (x == ox) && (y == oy); } bool Matches(const Vertex *other) const { return (x == other->x) && (y == other->y); } }; class Sector { public: int floorh; int ceilh; int floor_tex; int ceil_tex; int light; int type; int tag; enum { F_FLOORH, F_CEILH, F_FLOOR_TEX, F_CEIL_TEX, F_LIGHT, F_TYPE, F_TAG }; public: Sector() : floorh(0), ceilh(0), floor_tex(0), ceil_tex(0), light(0), type(0), tag(0) { } void RawCopy(const Sector *other) { floorh = other->floorh; ceilh = other->ceilh; floor_tex = other->floor_tex; ceil_tex = other->ceil_tex; light = other->light; type = other->type; tag = other->tag; } const char *FloorTex() const; const char *CeilTex() const; int HeadRoom() const { return ceilh - floorh; } void SetDefaults(); }; class SideDef { public: int x_offset; int y_offset; int upper_tex; int mid_tex; int lower_tex; int sector; enum { F_X_OFFSET, F_Y_OFFSET, F_UPPER_TEX, F_MID_TEX, F_LOWER_TEX, F_SECTOR }; public: SideDef() : x_offset(0), y_offset(0), upper_tex(0), mid_tex(0), lower_tex(0), sector(0) { } void RawCopy(const SideDef *other) { x_offset = other->x_offset; y_offset = other->y_offset; upper_tex = other->upper_tex; mid_tex = other->mid_tex; lower_tex = other->lower_tex; sector = other->sector; } const char *UpperTex() const; const char *MidTex() const; const char *LowerTex() const; Sector *SecRef() const; void SetDefaults(bool two_sided); }; class LineDef { public: int start; int end; int right; int left; int flags; int type; int tag; // Hexen stuff [NOTE: tag is 'arg1'] int arg2; int arg3; int arg4; int arg5; enum { F_START, F_END, F_RIGHT, F_LEFT, F_FLAGS, F_TYPE, F_TAG, F_ARG2, F_ARG3, F_ARG4, F_ARG5 }; public: LineDef() : start(0), end(0), right(-1), left(-1), flags(0), type(0), tag(0), arg2(0), arg3(0), arg4(0), arg5(0) { } void RawCopy(const LineDef *other) { start = other->start; end = other->end; right = other->right; left = other->left; flags = other->flags; type = other->type; tag = other->tag; // arg1 arg2 = other->arg2; arg3 = other->arg3; arg4 = other->arg4; arg5 = other->arg5; } Vertex *Start() const; Vertex *End() const; // remember: these two can return NULL! SideDef *Right() const; SideDef *Left() const; bool TouchesVertex(int v_num) const { return (start == v_num) || (end == v_num); } bool TouchesSector(int sec_num) const; bool OneSided() const { return (right >= 0) && (left < 0); } bool TwoSided() const { return (right >= 0) && (left >= 0); } // side is either SIDE_LEFT or SIDE_RIGHT int WhatSector(int side) const; int WhatSideDef(int side) const; double CalcLength() const; bool isZeroLength() const { return (Start()->x == End()->x) && (Start()->y == End()->y); } }; typedef struct Vertex *VPtr; typedef struct Thing *TPtr; typedef struct LineDef *LDPtr; typedef struct SideDef *SDPtr; typedef struct Sector *SPtr; extern std::vector Things; extern std::vector Vertices; extern std::vector Sectors; extern std::vector SideDefs; extern std::vector LineDefs; extern std::vector HeaderData; extern std::vector BehaviorData; #define NumThings ((int)Things.size()) #define NumVertices ((int)Vertices.size()) #define NumSectors ((int)Sectors.size()) #define NumSideDefs ((int)SideDefs.size()) #define NumLineDefs ((int)LineDefs.size()) extern int NumObjects(obj_type_e type); #define is_thing(n) ((n) >= 0 && (n) < NumThings ) #define is_vertex(n) ((n) >= 0 && (n) < NumVertices) #define is_sector(n) ((n) >= 0 && (n) < NumSectors ) #define is_sidedef(n) ((n) >= 0 && (n) < NumSideDefs) #define is_linedef(n) ((n) >= 0 && (n) < NumLineDefs) /* BASIS API */ // begin a group of operations that will become a single undo/redo // step. All stored _redo_ steps will be removed. The BA_New, // BA_Delete and BA_Change calls must only be called between // BA_Begin() and BA_End() pairs. void BA_Begin(); // finish a group of operations. void BA_End(); // abort the group of operations -- the undo/redo history is not // modified and any changes since BA_Begin() are undone except // when 'keep_changes' is true. void BA_Abort(bool keep_changes = false); // create a new object, returning its objnum. It is safe to // directly set the new object's fields after calling BA_New(). int BA_New(obj_type_e type); // deletes the given object, and in certain cases other types of // objects bound to it (e.g. deleting a vertex will cause all // bound linedefs to also be deleted). void BA_Delete(obj_type_e type, int objnum); // change a field of an existing object. If the value was the // same as before, nothing happens and false is returned. // Otherwise returns true. bool BA_Change(obj_type_e type, int objnum, byte field, int value); // attempt to undo the last normal or redo operation. Returns // false if the undo history is empty. bool BA_Undo(); // attempt to re-do the last undo operation. Returns false if // there is no stored redo steps. bool BA_Redo(); // add this string to the basis string table (if it doesn't // already exist) and return its integer offset. int BA_InternaliseString(const char *str); int BA_InternaliseShortStr(const char *str, int max_len); // get the string from the basis string table. const char * BA_GetString(int offset); // clear everything (before loading a new level). void BA_ClearAll(); // compute a checksum for the current level void BA_LevelChecksum(crc32_c& crc); /* HELPERS */ bool BA_ChangeTH(int thing, byte field, int value); bool BA_ChangeVT(int vert, byte field, int value); bool BA_ChangeSEC(int sec, byte field, int value); bool BA_ChangeSD(int side, byte field, int value); bool BA_ChangeLD(int line, byte field, int value); bool BA_ChangeRAD(int rad, byte field, int value); #endif /* __EUREKA_E_BASIS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/lib_file.h0000644000175100017510000000536112647061302016201 0ustar aaptedaapted//------------------------------------------------------------------------ // File Utilities //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2012 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 __LIB_FILE_H__ #define __LIB_FILE_H__ #ifdef WIN32 #define DIR_SEP_CH '\\' #define DIR_SEP_STR "\\" #else #define DIR_SEP_CH '/' #define DIR_SEP_STR "/" #endif // filename functions bool HasExtension(const char *filename); bool MatchExtension(const char *filename, const char *ext); char *ReplaceExtension(const char *filename, const char *ext); const char *FindBaseName(const char *filename); bool FilenameIsBare(const char *filename); const char *FilenameReposition(const char *filename, const char *othername); // file utilities bool FileExists(const char *filename); bool FileCopy(const char *src_name, const char *dest_name); bool FileRename(const char *old_name, const char *new_name); bool FileDelete(const char *filename); bool FileChangeDir(const char *dir_name); bool FileMakeDir(const char *dir_name); u8_t *FileLoad(const char *filename, int *length); void FileFree(u8_t *mem); const char * FileFindInPath(const char *paths, const char *base_name); // miscellanous const char *GetExecutablePath(const char *argv0); //------------------------------------------------------------------------ // directory functions bool PathIsDirectory(const char *path); typedef enum { SCAN_F_IsDir = (1 << 0), SCAN_F_Hidden = (1 << 1), SCAN_F_ReadOnly = (1 << 2), } scan_flags_e; typedef enum { SCAN_ERROR = -1, // general catch-all SCAN_ERR_NoExist = -2, // could not find given path SCAN_ERR_NotDir = -3, // path was not a directory } scan_error_e; typedef void (* directory_iter_f)(const char *name, int flags, void *priv_dat); int ScanDirectory(const char *path, directory_iter_f func, void *priv_dat); // scan the directory with the given path and call the given // function (passing the private data pointer to it) for each // entry in the directory. Returns the total number of entries, // or a negative value on error (SCAN_ERR_xx value). #endif /* __LIB_FILE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_linedef.cc0000644000175100017510000005421712651124405016507 0ustar aaptedaapted//------------------------------------------------------------------------ // LINEDEFS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "e_cutpaste.h" #include "e_linedef.h" #include "editloop.h" #include "im_img.h" #include "levels.h" #include "m_game.h" #include "objects.h" #include "w_rawdef.h" #include "w_texture.h" // config items bool leave_offsets_alone = true; bool LineDefAlreadyExists(int v1, int v2) { for (int n = 0 ; n < NumLineDefs ; n++) { LineDef *L = LineDefs[n]; if (L->start == v1 && L->end == v2) return true; if (L->start == v2 && L->end == v1) return true; } return false; } /* return true if adding a line between v1 and v2 would overlap an existing line. By "overlap" I mean parallel and sitting on top (this does NOT test for lines crossing each other). */ bool LineDefWouldOverlap(int v1, int x2, int y2) { int x1 = Vertices[v1]->x; int y1 = Vertices[v1]->y; for (int n = 0 ; n < NumLineDefs ; n++) { LineDef *L = LineDefs[n]; // zero-length lines should not exist, but don't get stroppy if they do if (L->isZeroLength()) continue; double a, b; a = PerpDist(x1, y1, L->Start()->x, L->Start()->y, L->End()->x, L->End()->y); b = PerpDist(x2, y2, L->Start()->x, L->Start()->y, L->End()->x, L->End()->y); if (fabs(a) >= 2.0 || fabs(b) >= 2.0) continue; a = AlongDist(x1, y1, L->Start()->x, L->Start()->y, L->End()->x, L->End()->y); b = AlongDist(x2, y2, L->Start()->x, L->Start()->y, L->End()->x, L->End()->y); double len = L->CalcLength(); if (a > b) std::swap(a, b); if (b < 0.5 || a > len - 0.5) continue; return true; } return false; } /* deletes all the linedefs AND unused vertices AND unused sidedefs */ void DeleteLineDefs(selection_c *lines) { selection_c verts(OBJ_VERTICES); selection_c sides(OBJ_SIDEDEFS); UnusedVertices(lines, &verts); UnusedSideDefs(lines, &sides); DeleteObjects(lines); DeleteObjects(&verts); DeleteObjects(&sides); } /* get the absolute height from which the textures are drawn */ int GetTextureRefHeight (int sidedef) { int l, sector; int otherside = NIL_OBJ; /* find the sidedef on the other side of the LineDef, if any */ for (l = 0 ; l < NumLineDefs ; l++) { if (LineDefs[l]->right == sidedef) { otherside = LineDefs[l]->left; break; } if (LineDefs[l]->left == sidedef) { otherside = LineDefs[l]->right; break; } } /* get the Sector number */ sector = SideDefs[sidedef]->sector; /* if the upper texture is displayed, then the reference is taken from the other Sector */ if (otherside >= 0) { l = SideDefs[otherside]->sector; if (l > 0) { if (Sectors[l]->ceilh < Sectors[sector]->ceilh && Sectors[l]->ceilh > Sectors[sector]->floorh) sector = l; } } /* return the altitude of the ceiling */ if (sector >= 0) return Sectors[sector]->ceilh; /* textures are drawn from the ceiling down */ else return 0; /* yuck! */ } // this type represents one side of a linedef typedef int side_on_a_line_t; static inline side_on_a_line_t soal_make(int ld, int side) { return (ld << 1) | (side < 0 ? 1 : 0); } static inline int soal_ld(side_on_a_line_t zz) { return (zz >> 1); } static inline const LineDef * soal_LD_ptr(side_on_a_line_t zz) { return LineDefs[soal_ld(zz)]; } static inline int soal_side(side_on_a_line_t zz) { return (zz & 1) ? SIDE_LEFT : SIDE_RIGHT; } static inline int soal_sd(side_on_a_line_t zz) { return soal_LD_ptr(zz)->WhatSideDef(soal_side(zz)); } static inline const SideDef * soal_SD_ptr(side_on_a_line_t zz) { int sd = soal_sd(zz); return (sd >= 0) ? SideDefs[sd] : NULL; } static int PartialTexCmp(const char *A, const char *B) { // only compare the first 6 characters char A2[64]; char B2[64]; strcpy(A2, A); strcpy(B2, B); A2[6] = B2[6] = 0; return y_stricmp(A2, B2); } static int ScoreAdjoiner(side_on_a_line_t zz, side_on_a_line_t adj, char part, int align_flags) { const LineDef *L = soal_LD_ptr(zz); const LineDef *N = soal_LD_ptr(adj); const SideDef *LS = soal_SD_ptr(zz); const SideDef *NS = soal_SD_ptr(adj); SYS_ASSERT(LS); // no sidedef on adjoining line? if (! NS) return -2; // wrong side? if (soal_side(zz) == soal_side(adj)) { if (N->start == L->start) return -1; if (N->end == L->end) return -1; } else { if (N->start == L->end) return -1; if (N->end == L->start) return -1; } // require adjoiner is "to the left" of this sidedef // [or "to the right" if the 'r' flag is present] bool on_left = N->TouchesVertex(soal_side(zz) < 0 ? L->end : L->start); if (align_flags & LINALIGN_Right) { if (on_left) return -2; } else { if (! on_left) return -2; } int score = 1; // FIXME : take 'part' into account !! // Main requirement is a matching texture. // There are three cases depending on number of sides: // // (a) single <-> single : easy // // (b) double <-> double : compare lower/lower and upper/upper // [only need one to match] // // (c) single <-> double : compare mid/lower and mid/upper // bool matched = false; for (int what = 0 ; what < 2 ; what++) { //??? if (what == 0 && only_U) continue; //??? if (what == 1 && only_L) continue; const char *L_tex = (! L->TwoSided()) ? LS->MidTex() : (what & 1) ? LS->UpperTex() : LS->LowerTex(); const char *N_tex = (! N->TwoSided()) ? NS->MidTex() : (what & 1) ? NS->UpperTex() : NS->LowerTex(); if (L_tex[0] == '-') continue; if (N_tex[0] == '-') continue; if (PartialTexCmp(L_tex, N_tex) == 0) matched = true; } ///--- // require a texture match? ///--- if (/* strchr(flags, 't') && */ ! matched) ///--- return -1; if (matched) score = score + 20; // preference for same sector if (LS->sector == NS->sector) score = score + 1; // prefer both lines to have same sided-ness if (L->OneSided() == N->OneSided()) score = score + 5; return score; } static side_on_a_line_t DetermineAdjoiner(side_on_a_line_t cur, char part, int align_flags) { // returns -1 for none int best_adj = -1; int best_score = -1; const LineDef *L = soal_LD_ptr(cur); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *N = LineDefs[n]; if (N == L) continue; if (! (N->TouchesVertex(L->start) || N->TouchesVertex(L->end))) continue; for (int pass = 0 ; pass < 2 ; pass++) { int adj_side = pass ? SIDE_LEFT : SIDE_RIGHT; int adjoiner = soal_make(n, adj_side); int score = ScoreAdjoiner(cur, adjoiner, part, align_flags); // fprintf(stderr, "Score for %d:%d --> %d\n", n, adj_side, score); if (score > 0 && score > best_score) { best_adj = adjoiner; best_score = score; } } } return best_adj; } static int GetTextureHeight(const char *name) { if (name[0] == '-') return 128; Img_c *img = W_GetTexture(name); if (! img) return 128; return img->height(); } static bool PartIsVisible(side_on_a_line_t zz, char part) { const LineDef *L = soal_LD_ptr(zz); const SideDef *SD = soal_SD_ptr(zz); if (! L->TwoSided()) return (part == 'l'); const Sector *front = L->Right()->SecRef(); const Sector *back = L->Left ()->SecRef(); if (soal_side(zz) == SIDE_LEFT) std::swap(front, back); // ignore sky walls if (part == 'u' && is_sky(front->CeilTex()) && is_sky(back->CeilTex())) return false; if (part == 'l') { if (SD->LowerTex()[0] == '-') return false; return back->floorh > front->floorh; } else { if (SD->UpperTex()[0] == '-') return false; return back->ceilh < front->ceilh; } } static char PickAdjoinerPart(side_on_a_line_t cur, char part, side_on_a_line_t adj, int align_flags) { const LineDef *L = soal_LD_ptr(cur); const SideDef *SD = soal_SD_ptr(cur); const LineDef *adj_L = soal_LD_ptr(adj); const SideDef *adj_SD = soal_SD_ptr(adj); if (! adj_L->TwoSided()) return 'l'; // the adjoiner part (upper or lower) should be visible bool lower_vis = PartIsVisible(adj, 'l'); bool upper_vis = PartIsVisible(adj, 'u'); if (lower_vis != upper_vis) return upper_vis ? 'u' : 'l'; else if (! lower_vis) return 'l'; // check for a matching texture if (L->TwoSided()) { // TODO: this logic would mean sometimes aligning an upper with // a lower (or vice versa). This should only be done when // those parts are actually adjacent (on the Y axis). #if 0 bool lower_match = (PartialTexCmp(SD->LowerTex(), adj_SD->LowerTex()) == 0); bool upper_match = (PartialTexCmp(SD->UpperTex(), adj_SD->UpperTex()) == 0); if (lower_match != upper_match) return upper_match ? 'u' : 'l'; #endif return part; } else { bool lower_match = (PartialTexCmp(SD->MidTex(), adj_SD->LowerTex()) == 0); bool upper_match = (PartialTexCmp(SD->MidTex(), adj_SD->UpperTex()) == 0); if (lower_match != upper_match) return upper_match ? 'u' : 'l'; } return part; } static int CalcReferenceH(side_on_a_line_t zz, char part) { const LineDef *L = soal_LD_ptr(zz); const SideDef *SD = soal_SD_ptr(zz); if (! L->TwoSided()) { if (! L->Right()) return 256; const Sector *front = L->Right()->SecRef(); if (L->flags & MLF_LowerUnpegged) return front->floorh + GetTextureHeight(SD->MidTex()); return front->ceilh; } const Sector *front = L->Right()->SecRef(); const Sector *back = L->Left ()->SecRef(); if (soal_side(zz) == SIDE_LEFT) std::swap(front, back); if (part == 'l') { if (! (L->flags & MLF_LowerUnpegged)) return back->floorh; return front->ceilh; } else { if (! (L->flags & MLF_UpperUnpegged)) return back->ceilh + GetTextureHeight(SD->UpperTex()); return front->ceilh; } } static void DoAlignX(side_on_a_line_t cur, char part, side_on_a_line_t adj, int align_flags) { const LineDef *L = soal_LD_ptr(cur); const LineDef *adj_L = soal_LD_ptr(adj); const SideDef *adj_SD = soal_SD_ptr(adj); bool on_left = adj_L->TouchesVertex(soal_side(cur) < 0 ? L->end : L->start); int new_offset; if (on_left) { int adj_length = I_ROUND(adj_L->CalcLength()); new_offset = adj_SD->x_offset + adj_length; if (new_offset > 0) new_offset &= 1023; } else { int length = I_ROUND(L->CalcLength()); new_offset = adj_SD->x_offset - length; if (new_offset < 0) new_offset = - (-new_offset & 1023); } BA_ChangeSD(soal_sd(cur), SideDef::F_X_OFFSET, new_offset); } static void DoAlignY(side_on_a_line_t cur, char part, side_on_a_line_t adj, int align_flags) { const LineDef *L = soal_LD_ptr(cur); const SideDef *SD = soal_SD_ptr(cur); // const LineDef *adj_L = soal_LD_ptr(adj); const SideDef *adj_SD = soal_SD_ptr(adj); bool lower_vis = PartIsVisible(cur, 'l'); bool upper_vis = PartIsVisible(cur, 'u'); // handle unpeg flags : check for windows if (L->TwoSided() && (lower_vis && upper_vis) && ((L->flags & MLF_LowerUnpegged) == 0) && ((L->flags & MLF_UpperUnpegged) == 0) && PartialTexCmp(SD->LowerTex(), SD->UpperTex()) == 0 && SD->MidTex()[0] == '-' /* no rail */) { int new_flags = L->flags; if (lower_vis) new_flags |= MLF_LowerUnpegged; if (upper_vis) new_flags |= MLF_UpperUnpegged; BA_ChangeLD(soal_ld(cur), LineDef::F_FLAGS, new_flags); } // determine which parts (upper or lower) we will use for alignment char cur_part = part; char adj_part = PickAdjoinerPart(cur, part, adj, align_flags); // requirement: adj_tex_h + adj_y_off = cur_tex_h + cur_y_off int cur_texh = CalcReferenceH(cur, cur_part); int adj_texh = CalcReferenceH(adj, adj_part); int new_offset = adj_texh + adj_SD->y_offset - cur_texh; // normalize value [TODO: handle BOOM non-power-of-two heights] if (new_offset < 0) new_offset = - (-new_offset & 255); else new_offset &= 255; BA_ChangeSD(soal_sd(cur), SideDef::F_Y_OFFSET, new_offset); } void LineDefs_Align(int ld, int side, int sd, char part, int align_flags) { side_on_a_line_t cur = soal_make(ld, side); side_on_a_line_t adj = DetermineAdjoiner(cur, part, align_flags); if (adj < 0) { Beep("No nearby wall to align with"); return; } BA_Begin(); if (align_flags & LINALIGN_X) DoAlignX(cur, part, adj, align_flags); if (align_flags & LINALIGN_Y) DoAlignY(cur, part, adj, align_flags); BA_End(); } //------------------------------------------------------------------------ static void FlipLine_verts(int ld) { int old_start = LineDefs[ld]->start; int old_end = LineDefs[ld]->end; BA_ChangeLD(ld, LineDef::F_START, old_end); BA_ChangeLD(ld, LineDef::F_END, old_start); } static void FlipLine_sides(int ld) { int old_right = LineDefs[ld]->right; int old_left = LineDefs[ld]->left; BA_ChangeLD(ld, LineDef::F_RIGHT, old_left); BA_ChangeLD(ld, LineDef::F_LEFT, old_right); } void FlipLineDef(int ld) { FlipLine_verts(ld); FlipLine_sides(ld); } void FlipLineDef_safe(int ld) { // this avoids creating a linedef with only a left side (no right) FlipLine_verts(ld); if (! LineDefs[ld]->OneSided()) FlipLine_sides(ld); } void FlipLineDefGroup(selection_c& flip) { selection_iterator_c it; for (flip.begin(&it) ; !it.at_end() ; ++it) { FlipLineDef(*it); } } /* flip one or several LineDefs */ void LIN_Flip(void) { selection_c list; if (! GetCurrentObjects(&list)) { Beep("No lines to flip"); return; } BA_Begin(); bool do_verts = Exec_HasFlag("/verts"); bool do_sides = Exec_HasFlag("/sides"); selection_iterator_c it; for (list.begin(&it) ; !it.at_end() ; ++it) { if (! do_verts && ! do_sides) { FlipLineDef_safe(*it); } else { if (do_verts) FlipLine_verts(*it); if (do_sides) FlipLine_sides(*it); } } BA_End(); } int SplitLineDefAtVertex(int ld, int new_v) { LineDef * L = LineDefs[ld]; Vertex * V = Vertices[new_v]; // create new linedef int new_l = BA_New(OBJ_LINEDEFS); LineDef * L2 = LineDefs[new_l]; // it is OK to directly set fields of newly created objects L2->RawCopy(L); L2->start = new_v; L2->end = L->end; // update vertex on original line BA_ChangeLD(ld, LineDef::F_END, new_v); // compute lengths (to update sidedef X offsets) int orig_length = (int)ComputeDist( L->Start()->x - L->End()->x, L->Start()->y - L->End()->y); int new_length = (int)ComputeDist( L->Start()->x - V->x, L->Start()->y - V->y); // update sidedefs if (L->Right()) { L2->right = BA_New(OBJ_SIDEDEFS); L2->Right()->RawCopy(L->Right()); if (! leave_offsets_alone) L2->Right()->x_offset += new_length; } if (L->Left()) { L2->left = BA_New(OBJ_SIDEDEFS); L2->Left()->RawCopy(L->Left()); if (! leave_offsets_alone) { int new_x_ofs = L->Left()->x_offset + orig_length - new_length; BA_ChangeSD(L->left, SideDef::F_X_OFFSET, new_x_ofs); } } return new_l; } static bool DoSplitLineDef(int ld) { LineDef * L = LineDefs[ld]; int new_x = (L->Start()->x + L->End()->x) / 2; int new_y = (L->Start()->y + L->End()->y) / 2; // prevent creating tiny lines (especially zero-length) if (abs(L->Start()->x - L->End()->x) < 4 && abs(L->Start()->y - L->End()->y) < 4) return false; int new_v = BA_New(OBJ_VERTICES); Vertex * V = Vertices[new_v]; V->x = new_x; V->y = new_y; SplitLineDefAtVertex(ld, new_v); return true; } /* split one or more LineDefs in two, adding new Vertices in the middle */ void LIN_SplitHalf(void) { selection_c list; selection_iterator_c it; if (! GetCurrentObjects(&list)) { Beep("No lines to split"); return; } bool was_selected = edit.Selected->notempty(); // clear current selection, since the size needs to grow due to // new linedefs being added to the map. Selection_Clear(true); int new_first = NumLineDefs; int new_count = 0; BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { if (DoSplitLineDef(*it)) new_count++; } BA_End(); // Hmmmmm -- should abort early if some lines are too short?? if (new_count < list.count_obj()) Beep("Some lines were too short!"); if (was_selected && new_count > 0) { // reselect the old _and_ new linedefs for (list.begin(&it) ; !it.at_end() ; ++it) edit.Selected->set(*it); edit.Selected->frob_range(new_first, new_first + new_count - 1, BOP_ADD); } } void LD_MergedSecondSideDef(int ld) { // similar to above, but with existing sidedefs LineDef * L = LineDefs[ld]; SYS_ASSERT(L->TwoSided()); int new_flags = L->flags; new_flags |= MLF_TwoSided; new_flags &= ~MLF_Blocking; BA_ChangeLD(ld, LineDef::F_FLAGS, new_flags); // TODO: make this a global pseudo-constant int null_tex = BA_InternaliseString("-"); // determine textures for each side int left_tex = 0; int right_tex = 0; if (isalnum(L->Left()->MidTex()[0])) left_tex = L->Left()->mid_tex; if (isalnum(L->Right()->MidTex()[0])) right_tex = L->Right()->mid_tex; if (! left_tex) left_tex = right_tex; if (! right_tex) right_tex = left_tex; // use default texture if both sides are empty if (! left_tex) { left_tex = BA_InternaliseString(default_mid_tex); right_tex = left_tex; } BA_ChangeSD(L->left, SideDef::F_MID_TEX, null_tex); BA_ChangeSD(L->right, SideDef::F_MID_TEX, null_tex); BA_ChangeSD(L->left, SideDef::F_LOWER_TEX, left_tex); BA_ChangeSD(L->left, SideDef::F_UPPER_TEX, left_tex); BA_ChangeSD(L->right, SideDef::F_LOWER_TEX, right_tex); BA_ChangeSD(L->right, SideDef::F_UPPER_TEX, right_tex); } void LIN_MergeTwo(void) { if (edit.Selected->count_obj() == 1 && edit.highlight.valid()) { edit.Selected->set(edit.highlight.num); } if (edit.Selected->count_obj() != 2) { Beep("Need 2 linedefs to merge (got %d)", edit.Selected->count_obj()); return; } // we will merge the second into the first int ld2 = edit.Selected->find_first(); int ld1 = edit.Selected->find_second(); const LineDef * L1 = LineDefs[ld1]; const LineDef * L2 = LineDefs[ld2]; if (! (L1->OneSided() && L2->OneSided())) { Beep("Linedefs to merge must be single sided."); return; } Selection_Clear(true); BA_Begin(); // ld2 steals the sidedef from ld1 BA_ChangeLD(ld2, LineDef::F_LEFT, L1->right); BA_ChangeLD(ld1, LineDef::F_RIGHT, -1); LD_MergedSecondSideDef(ld2); // fix existing lines connected to ld1 : reconnect to ld2 for (int n = 0 ; n < NumLineDefs ; n++) { if (n == ld1 || n == ld2) continue; const LineDef * L = LineDefs[n]; if (L->start == L1->start) BA_ChangeLD(n, LineDef::F_START, L2->end); else if (L->start == L1->end) BA_ChangeLD(n, LineDef::F_START, L2->start); if (L->end == L1->start) BA_ChangeLD(n, LineDef::F_END, L2->end); else if (L->end == L1->end) BA_ChangeLD(n, LineDef::F_END, L2->start); } // delete ld1 and any unused vertices selection_c del_line(OBJ_LINEDEFS); del_line.set(ld1); DeleteLineDefs(&del_line); BA_End(); } void MoveCoordOntoLineDef(int ld, int *x, int *y) { const LineDef *L = LineDefs[ld]; double x1 = L->Start()->x; double y1 = L->Start()->y; double x2 = L->End()->x; double y2 = L->End()->y; double dx = x2 - x1; double dy = y2 - y1; double len_squared = dx*dx + dy*dy; SYS_ASSERT(len_squared > 0); // compute along distance double along = (*x - x1) * dx + (*y - y1) * dy; // result = start + along * line unit vector double new_x = x1 + along * dx / len_squared; double new_y = y1 + along * dy / len_squared; *x = I_ROUND(new_x); *y = I_ROUND(new_y); } static bool LineDefStartWillBeMoved(int ld, selection_c& list) { int start = LineDefs[ld]->start; selection_iterator_c it; for (list.begin(&it) ; !it.at_end() ; ++it) { if (*it == ld) continue; const LineDef *L = LineDefs[*it]; if (L->end == start) return true; } return false; } static int PickLineDefToExtend(selection_c& list) { // we want a line whose start is not going to be moved in the future // (otherwise the length will be wrecked by the later change). // however there could be loops, so need to always pick something. selection_iterator_c it; for (list.begin(&it) ; !it.at_end() ; ++it) if (! LineDefStartWillBeMoved(*it, list)) return *it; return list.find_first(); } static void LD_SetLength(int ld, int new_len, int angle) { const LineDef *L = LineDefs[ld]; double dx = new_len * cos(angle * M_PI / 32768.0); double dy = new_len * sin(angle * M_PI / 32768.0); int idx = I_ROUND(dx); int idy = I_ROUND(dy); if (idx == 0 && idy == 0) { if (dx < 0) idx = (int)floor(dx); else idx = (int)ceil(dx); if (dy < 0) idy = (int)floor(dy); else idy = (int)ceil(dy); } if (idx == 0 && idy == 0) idx = 1; BA_ChangeVT(L->end, Vertex::F_X, L->Start()->x + idx); BA_ChangeVT(L->end, Vertex::F_Y, L->Start()->y + idy); } void LineDefs_SetLength(int new_len) { selection_c list; if (! GetCurrentObjects(&list)) { Beep("No lines to extend"); return; } // remember angles std::vector angles(NumLineDefs); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; angles[n] = ComputeAngle(L->End()->x - L->Start()->x, L->End()->y - L->Start()->y); } BA_Begin(); while (! list.empty()) { int ld = PickLineDefToExtend(list); list.clear(ld); LD_SetLength(ld, new_len, angles[ld]); } BA_End(); } void LD_FixForLostSide(int ld) { LineDef * L = LineDefs[ld]; SYS_ASSERT(L->Right()); int tex; if (L->Right()->LowerTex()[0] != '-') tex = L->Right()->lower_tex; else if (L->Right()->UpperTex()[0] != '-') tex = L->Right()->upper_tex; else tex = BA_InternaliseString(default_mid_tex); BA_ChangeSD(L->right, SideDef::F_MID_TEX, tex); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_nombre.h0000644000175100017510000000251012647061302016404 0ustar aaptedaapted//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2009 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 __EUREKA_UI_NOMBRE_H__ #define __EUREKA_UI_NOMBRE_H__ class UI_Nombre : public Fl_Box { private: int index; int total; int selected; const char *type_name; void Update(); public: UI_Nombre(int X, int Y, int W, int H, const char *what = NULL); virtual ~UI_Nombre(); public: void SetIndex(int _idx); // _idx < 0 means "no index" void SetTotal(int _tot); void SetSelected(int _sel); }; #endif /* __EUREKA_UI_NOMBRE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_config.h0000644000175100017510000000706212651520477016225 0ustar aaptedaapted//------------------------------------------------------------------------ // CONFIG FILE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_CONFIG_H__ #define __EUREKA_M_CONFIG_H__ #include "im_color.h" /* ==== CONFIG VARIABLES ==================== */ extern const char *default_port; extern int default_edit_mode; extern bool auto_load_recent; extern bool begin_maximized; extern bool map_scroll_bars; extern bool digits_set_zoom; extern bool leave_offsets_alone; extern bool mouse_wheel_scrolls_map; extern bool new_islands_are_void; extern bool same_mode_clears_selection; extern bool swap_sidedefs; extern bool show_full_one_sided; extern int gui_scheme; extern int gui_color_set; extern rgb_color_t gui_custom_bg; extern rgb_color_t gui_custom_ig; extern rgb_color_t gui_custom_fg; extern int multi_select_modifier; extern int minimum_drag_pixels; extern int new_sector_size; extern bool easier_drawing_mode; extern int sector_render_default; extern int default_grid_size; extern bool default_grid_snap; extern int default_grid_mode; extern bool grid_hide_in_free_mode; extern int grid_toggle_type; extern rgb_color_t dotty_axis_col; extern rgb_color_t dotty_major_col; extern rgb_color_t dotty_minor_col; extern rgb_color_t dotty_point_col; extern rgb_color_t normal_axis_col; extern rgb_color_t normal_main_col; extern rgb_color_t normal_flat_col; extern rgb_color_t normal_small_col; extern int backup_max_files; extern int backup_max_space; extern bool browser_small_tex; extern int floor_bump_small; extern int floor_bump_medium; extern int floor_bump_large; extern int light_bump_small; extern int light_bump_medium; extern int light_bump_large; extern int render_pixel_aspect; extern bool render_high_detail; extern bool render_lock_gravity; extern bool render_missing_bright; extern bool render_unknown_bright; extern bool glbsp_fast; extern bool glbsp_verbose; extern bool glbsp_warn; /* ==== FUNCTIONS ==================== */ int M_ParseConfigFile(); int M_WriteConfigFile(); int M_ParseEnvironmentVars(); int M_ParseCommandLine(int argc, const char *const *argv, int pass); void dump_parameters (FILE *fp); void dump_command_line_options (FILE *fp); // returns number of tokens, zero for comment, negative on error int M_ParseLine(const char *line, const char ** tokens, int max_tok, bool do_strings); void M_FreeLine(const char ** tokens, int num_tok); // user state persistence (stuff like camera pos, grid settings, ...) bool M_LoadUserState(); bool M_SaveUserState(); void M_DefaultUserState(); #endif /* __EUREKA_M_CONFIG_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_hyper.cc0000644000175100017510000000705612647061302016421 0ustar aaptedaapted//------------------------------------------------------------------------ // Hyperlinks //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2011 Andrew Apted // Copyright (C) 2002 Jason Bryan // // 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. // //------------------------------------------------------------------------ // // Used some code from Jason Bryan's FLU (FLTK Utility Widgets), // which is under the the GNU LGPL license (same as FLTK itself). // //------------------------------------------------------------------------ #include "main.h" #include "ui_window.h" #define LINK_BLUE FL_BLUE // fl_rgb_color(0,0,192) UI_HyperLink::UI_HyperLink(int x, int y, int w, int h, const char *label, const char *_url) : Fl_Button(x, y, w, h, label), hover(false), label_X(0), label_Y(0), label_W(0), label_H(0) { // copy the URL string url = strdup(_url); box(FL_FLAT_BOX); color(FL_GRAY); labelcolor(LINK_BLUE); // setup the callback callback(callback_Link, NULL); } UI_HyperLink::~UI_HyperLink() { free((void *)url); } void UI_HyperLink::checkLink() { // change the cursor if the mouse is over the link. // the 'hover' variable reduces the number of times fl_cursor() // needs to be called (since it can be expensive). if (Fl::event_inside(x()+label_X, y()+label_Y, label_W, label_H)) { if (! hover) fl_cursor(FL_CURSOR_HAND); hover = true; } else { if (hover) fl_cursor(FL_CURSOR_DEFAULT); hover = false; } } int UI_HyperLink::handle(int event) { if (!active_r()) return Fl_Button::handle(event); switch (event) { case FL_MOVE: { checkLink(); return 1; } case FL_ENTER: { checkLink(); redraw(); return 1; } break; case FL_LEAVE: { checkLink(); redraw(); return 1; } default: break; } return Fl_Button::handle(event); } void UI_HyperLink::draw() { if (type() == FL_HIDDEN_BUTTON) return; // determine where to draw the label label_X = label_Y = label_W = label_H = 0; fl_font(labelfont(), labelsize()); fl_measure(label(), label_W, label_H, 1); if (align() & FL_ALIGN_LEFT) label_X = 2; else if (align() & FL_ALIGN_RIGHT) label_X = w() - label_W - 2; else label_X = (w() - label_W) / 2; label_Y += h() / 2 - labelsize() / 2 - 2; // draw the link text fl_draw_box(box(), x(), y(), w(), h(), color()); fl_color(labelcolor()); fl_draw(label(), x() + label_X, y() + label_Y, label_W, label_H, FL_ALIGN_LEFT); // draw the underline if (! value()) { int yy = y() + label_Y + label_H-2; fl_line_style(FL_SOLID); fl_line(x() + label_X, yy, x() + label_X + label_W, yy); fl_line_style(0); } /* if (Fl::focus() == this) draw_focus(); */ } void UI_HyperLink::callback_Link(Fl_Widget *w, void *data) { UI_HyperLink *link = (UI_HyperLink *)w; if (! fl_open_uri(link->url)) { LogPrintf("\n"); LogPrintf("Open URL failed: %s\n", link->url); LogPrintf("\n"); } } eureka-1.11-source/src/e_vertex.cc0000644000175100017510000006130712651124163016415 0ustar aaptedaapted//------------------------------------------------------------------------ // VERTEX OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "editloop.h" #include "e_linedef.h" #include "e_vertex.h" #include "m_bitvec.h" #include "r_grid.h" #include "levels.h" #include "objects.h" #include "w_rawdef.h" #include "x_hover.h" #include "x_mirror.h" #include int Vertex_FindExact(int x, int y) { for (int i = 0 ; i < NumVertices ; i++) { if (Vertices[i]->x == x && Vertices[i]->y == y) return i; } return -1; // not found } // TODO: InsertPolygonVertices #if 0 /* insert the vertices of a new polygon */ void InsertPolygonVertices (int centerx, int centery, int sides, int radius) { for (int n = 0 ; n < sides ; n++) { DoInsertObject (OBJ_VERTICES, -1, centerx + (int) ((double)radius * cos (2*M_PI * (double)n / (double)sides)), centery + (int) ((double)radius * sin (2*M_PI * (double)n / (double)sides))); } } #endif /* we merge ld1 into ld2 -- v is the common vertex */ static void MergeConnectedLines(int ld1, int ld2, int v) { LineDef *L1 = LineDefs[ld1]; LineDef *L2 = LineDefs[ld2]; bool ld1_onesided = L1->OneSided(); bool ld2_onesided = L2->OneSided(); int new_mid_tex = (ld1_onesided) ? L1->Right()->mid_tex : (ld2_onesided) ? L2->Right()->mid_tex : 0; // flip ld1 so it would be parallel (after merging the other endpoints) // with ld2 but going the opposite direction. if ((L2->end == v) == (L1->end == v)) { FlipLineDef(ld1); } bool same_left = (L2->WhatSector(SIDE_LEFT) == L1->WhatSector(SIDE_LEFT)); bool same_right = (L2->WhatSector(SIDE_RIGHT) == L1->WhatSector(SIDE_RIGHT)); if (same_left && same_right) { // delete other line too // [ MUST do the highest numbered first ] if (ld2 < ld1) std::swap(ld1, ld2); BA_Delete(OBJ_LINEDEFS, ld2); BA_Delete(OBJ_LINEDEFS, ld1); return; } if (same_left) { BA_ChangeLD(ld2, LineDef::F_LEFT, L1->right); } else if (same_right) { BA_ChangeLD(ld2, LineDef::F_RIGHT, L1->left); } else { // geometry was broken / unclosed sector(s) } // fix orientation of remaining linedef if needed if (L2->Left() && ! L2->Right()) { FlipLineDef(ld2); } if (L2->OneSided() && new_mid_tex > 0) { BA_ChangeSD(L2->right, SideDef::F_MID_TEX, new_mid_tex); } BA_Delete(OBJ_LINEDEFS, ld1); } void MergeVertex(int v1, int v2, bool v1_will_be_deleted) { /* merge v1 into v2 */ SYS_ASSERT(v1 >= 0 && v2 >= 0); SYS_ASSERT(v1 != v2); // first check if two linedefs would overlap after the merge for (int n = NumLineDefs - 1 ; n >= 0 ; n--) { const LineDef *L = LineDefs[n]; if (! (L->start == v1 || L->end == v1)) continue; int v3 = (L->start == v1) ? L->end : L->start; int found = -1; for (int k = NumLineDefs - 1 ; k >= 0 ; k--) { if (k == n) continue; const LineDef *K = LineDefs[k]; if ((K->start == v3 && K->end == v2) || (K->start == v2 && K->end == v3)) { found = k; break; } } if (found >= 0) { // this deletes linedef [n], and maybe the other too MergeConnectedLines(n, found, v3); break; } } // update any linedefs which use V1 to use V2 instead for (int n = NumLineDefs - 1 ; n >= 0 ; n--) { const LineDef *L = LineDefs[n]; // handle a line that exists between the two vertices if ((L->start == v1 && L->end == v2) || (L->start == v2 && L->end == v1)) { if (v1_will_be_deleted) { // we simply skip it, hence when V1 is deleted this line // will automatically be deleted too (as it refers to V1). // Clever huh? } else { BA_Delete(OBJ_LINEDEFS, n); } continue; } if (L->start == v1) BA_ChangeLD(n, LineDef::F_START, v2); if (L->end == v1) BA_ChangeLD(n, LineDef::F_END, v2); } } int VertexHowManyLineDefs(int v_num) { int count = 0; for (int n = 0 ; n < NumLineDefs ; n++) { LineDef *L = LineDefs[n]; if (L->start == v_num || L->end == v_num) count++; } return count; } static void CalcDisconnectCoord(const LineDef *L, int v_num, int *x, int *y) { const Vertex * V = Vertices[v_num]; int dx = L->End()->x - L->Start()->x; int dy = L->End()->y - L->Start()->y; if (L->end == v_num) { dx = -dx; dy = -dy; } if (abs(dx) < 4 && abs(dy) < 4) { dx = dx / 2; dy = dy / 2; } else if (abs(dx) < 16 && abs(dy) < 16) { dx = dx / 4; dy = dy / 4; } else if (abs(dx) >= abs(dy)) { dy = dy * 8 / abs(dx); dx = (dx < 0) ? -8 : 8; } else { dx = dx * 8 / abs(dy); dy = (dy < 0) ? -8 : 8; } *x = V->x + dx; *y = V->y + dy; } static void DoDisconnectVertex(int v_num, int num_lines) { int which = 0; for (int n = 0 ; n < NumLineDefs ; n++) { LineDef *L = LineDefs[n]; if (L->start == v_num || L->end == v_num) { int new_x, new_y; CalcDisconnectCoord(L, v_num, &new_x, &new_y); // the _LAST_ linedef keeps the current vertex, the rest // need a new one. if (which != num_lines-1) { int new_v = BA_New(OBJ_VERTICES); Vertices[new_v]->x = new_x; Vertices[new_v]->y = new_y; if (L->start == v_num) BA_ChangeLD(n, LineDef::F_START, new_v); else BA_ChangeLD(n, LineDef::F_END, new_v); } else { BA_ChangeVT(v_num, Vertex::F_X, new_x); BA_ChangeVT(v_num, Vertex::F_Y, new_y); } which++; } } } void Vertex_MergeList(selection_c *list) { if (list->count_obj() < 2) return; // the first vertex is kept, all the other vertices are removed. int v = list->find_first(); int new_x, new_y; #if 0 Objs_CalcMiddle(list, &new_x, &new_y); #else new_x = Vertices[v]->x; new_y = Vertices[v]->y; #endif list->clear(v); BA_Begin(); BA_ChangeVT(v, Vertex::F_X, new_x); BA_ChangeVT(v, Vertex::F_Y, new_y); selection_iterator_c it; for (list->begin(&it) ; !it.at_end() ; ++it) { MergeVertex(*it, v, true /* v1_will_be_deleted */); } DeleteObjects(list); BA_End(); list->clear_all(); } void VT_Merge() { if (edit.Selected->count_obj() == 1 && edit.highlight.valid()) { edit.Selected->set(edit.highlight.num); } if (edit.Selected->count_obj() < 2) { Beep("Need 2 or more vertices to merge"); return; } Vertex_MergeList(edit.Selected); Editor_ClearAction(); } void VT_Disconnect(void) { if (edit.Selected->empty()) { if (edit.highlight.is_nil()) { Beep("Nothing to disconnect"); return; } edit.Selected->set(edit.highlight.num); } bool seen_one = false; BA_Begin(); selection_iterator_c it; for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { int v_num = *it; // nothing to do unless vertex has 2 or more linedefs int num_lines = VertexHowManyLineDefs(*it); if (num_lines < 2) continue; DoDisconnectVertex(v_num, num_lines); seen_one = true; } if (! seen_one) Beep("Nothing was disconnected"); BA_End(); Selection_Clear(true); } bool Vertex_TryFixDangler(int v_num) { // see if this vertex is sitting on another one (or very close to it) int v_other = -1; int max_dist = 2; for (int i = 0 ; i < NumVertices ; i++) { if (i == v_num) continue; int dx = Vertices[v_num]->x - Vertices[i]->x; int dy = Vertices[v_num]->y - Vertices[i]->y; if (abs(dx) <= max_dist && abs(dy) <= max_dist && ! LineDefAlreadyExists(v_num, v_other)) { v_other = i; break; } } // check for a dangling vertex if (VertexHowManyLineDefs(v_num) != 1) { if (v_other >= 0 && VertexHowManyLineDefs(v_other) == 1) std::swap(v_num, v_other); else return false; } if (v_other >= 0) { Selection_Clear(true /* no_save */); // delete highest numbered one [ so the other index remains valid ] if (v_num < v_other) std::swap(v_num, v_other); fprintf(stderr, "Vertex_TryFixDangler : merge vert %d onto %d\n", v_num, v_other); BA_Begin(); MergeVertex(v_num, v_other, true /* v1_will_be_deleted */); selection_c list(OBJ_VERTICES); list.set(v_num); DeleteObjects(&list); BA_End(); edit.Selected->set(v_other); Beep("Merged a dangling vertex"); return true; } #if 0 // find the line joined to this vertex int joined_ld = -1; for (int n = 0 ; n < NumLineDefs ; n++) { if (LineDefs[n]->TouchesVertex(v_num)) { joined_ld = n; break; } } SYS_ASSERT(joined_ld >= 0); #endif // see if vertex is sitting on a line Objid line_ob; GetSplitLineForDangler(line_ob, v_num); if (! line_ob.valid()) return false; fprintf(stderr, "Vertex_TryFixDangler : split linedef %d with vert %d\n", line_ob.num, v_num); BA_Begin(); SplitLineDefAtVertex(line_ob.num, v_num); BA_End(); // no vertices were added or removed, hence can continue Insert_Vertex return false; } static void DoDisconnectLineDef(int ld, int which_vert, bool *seen_one) { LineDef *L = LineDefs[ld]; int v_num = which_vert ? L->end : L->start; // see if there are any linedefs NOT in the selection which are // connected to this vertex. bool touches_non_sel = false; for (int n = 0 ; n < NumLineDefs ; n++) { if (edit.Selected->get(n)) continue; LineDef *N = LineDefs[n]; if (N->start == v_num || N->end == v_num) { touches_non_sel = true; break; } } if (! touches_non_sel) return; int new_x, new_y; CalcDisconnectCoord(LineDefs[ld], v_num, &new_x, &new_y); int new_v = BA_New(OBJ_VERTICES); Vertices[new_v]->x = new_x; Vertices[new_v]->y = new_y; // fix all linedefs in the selection to use this new vertex selection_iterator_c it; for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { LineDef *L2 = LineDefs[*it]; if (L2->start == v_num) BA_ChangeLD(*it, LineDef::F_START, new_v); if (L2->end == v_num) BA_ChangeLD(*it, LineDef::F_END, new_v); } *seen_one = true; } void LIN_Disconnect(void) { // Note: the logic here is significantly different than the logic // in VT_Disconnect, since we want to keep linedefs in the // selection connected, and only disconnect from linedefs // NOT in the selection. // // Hence need separate code for this. bool unselect = false; if (edit.Selected->empty()) { if (edit.highlight.is_nil()) { Beep("Nothing to disconnect"); return; } edit.Selected->set(edit.highlight.num); unselect = true; } bool seen_one = false; BA_Begin(); selection_iterator_c it; for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { DoDisconnectLineDef(*it, 0, &seen_one); DoDisconnectLineDef(*it, 1, &seen_one); } BA_End(); if (! seen_one) Beep("Nothing was disconnected"); if (unselect) Selection_Clear(true /* no save */); } static void VerticesOfDetachableSectors(selection_c &verts) { SYS_ASSERT(NumVertices > 0); bitvec_c in_verts(NumVertices); bitvec_c out_verts(NumVertices); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef * L = LineDefs[n]; bool innie = false; bool outie = false; // TODO: what about no-sided lines?? if (L->Right()) { if (edit.Selected->get(L->Right()->sector)) innie = true; else outie = true; } if (L->Left()) { if (edit.Selected->get(L->Left()->sector)) innie = true; else outie = true; } if (innie) { in_verts.set(L->start); in_verts.set(L->end); } if (outie) { out_verts.set(L->start); out_verts.set(L->end); } } for (int k = 0 ; k < NumVertices ; k++) { if (in_verts.get(k) && out_verts.get(k)) verts.set(k); } } static void DETSEC_SeparateLine(int ld_num, int start2, int end2, int in_side) { const LineDef * L1 = LineDefs[ld_num]; int new_ld = BA_New(OBJ_LINEDEFS); int lost_sd; LineDef * L2 = LineDefs[new_ld]; if (in_side == SIDE_LEFT) { L2->start = end2; L2->end = start2; L2->right = L1->left; lost_sd = L1->left; } else { L2->start = start2; L2->end = end2; L2->right = L1->right; lost_sd = L1->right; FlipLineDef(ld_num); } BA_ChangeLD(ld_num, LineDef::F_LEFT, -1); // determine new flags int new_flags = L1->flags; new_flags &= ~MLF_TwoSided; new_flags |= MLF_Blocking; BA_ChangeLD(ld_num, LineDef::F_FLAGS, new_flags); L2->flags = L1->flags; // fix the first line's textures int tex = BA_InternaliseString(default_mid_tex); const SideDef * SD = SideDefs[L1->right]; if (isalnum(SD->LowerTex()[0])) tex = SD->lower_tex; else if (isalnum(SD->UpperTex()[0])) tex = SD->upper_tex; BA_ChangeSD(L1->right, SideDef::F_MID_TEX, tex); // now fix the second line's textures SD = SideDefs[lost_sd]; if (isalnum(SD->LowerTex()[0])) tex = SD->lower_tex; else if (isalnum(SD->UpperTex()[0])) tex = SD->upper_tex; BA_ChangeSD(lost_sd, SideDef::F_MID_TEX, tex); } static void DETSEC_CalcMoveVector(selection_c * detach_verts, int * dx, int * dy) { int det_mid_x, sec_mid_x; int det_mid_y, sec_mid_y; Objs_CalcMiddle(detach_verts, &det_mid_x, &det_mid_y); Objs_CalcMiddle(edit.Selected, &sec_mid_x, &sec_mid_y); *dx = sec_mid_x - det_mid_x; *dy = sec_mid_y - det_mid_y; // avoid moving perfectly horizontal or vertical // (also handes the case of dx == dy == 0) if (abs(*dx) > abs(*dy)) { *dx = (*dx < 0) ? -9 : +9; *dy = (*dy < 0) ? -5 : +5; } else { *dx = (*dx < 0) ? -5 : +5; *dy = (*dy < 0) ? -9 : +9; } if (abs(*dx) < 2) *dx = (*dx < 0) ? -2 : +2; if (abs(*dy) < 4) *dy = (*dy < 0) ? -4 : +4; int mul = 1.0 / CLAMP(0.25, grid.Scale, 1.0); *dx = (*dx) * mul; *dy = (*dy) * mul; } void SEC_Disconnect(void) { if (NumVertices == 0) { Beep("No sectors to disconnect"); return; } int n; bool unselect = false; if (edit.Selected->empty()) { if (edit.highlight.is_nil()) { Beep("No sectors to disconnect"); return; } edit.Selected->set(edit.highlight.num); unselect = true; } // collect all vertices which need to be detached selection_c detach_verts(OBJ_VERTICES); selection_iterator_c it; VerticesOfDetachableSectors(detach_verts); if (detach_verts.empty()) { Beep("Already disconnected"); return; } // determine vector to move the detach coords int move_dx, move_dy; DETSEC_CalcMoveVector(&detach_verts, &move_dx, &move_dy); BA_Begin(); // create new vertices, and a mapping from old --> new int * mapping = new int[NumVertices]; for (n = 0 ; n < NumVertices ; n++) mapping[n] = -1; for (detach_verts.begin(&it) ; !it.at_end() ; ++it) { int new_v = BA_New(OBJ_VERTICES); mapping[*it] = new_v; Vertex *newbie = Vertices[new_v]; newbie->RawCopy(Vertices[*it]); } // update linedefs, creating new ones where necessary // (go backwards so we don't visit newly created lines) for (n = NumLineDefs-1 ; n >= 0 ; n--) { const LineDef * L = LineDefs[n]; // only process lines which touch a selected sector bool left_in = L->Left() && edit.Selected->get(L->Left()->sector); bool right_in = L->Right() && edit.Selected->get(L->Right()->sector); if (! (left_in || right_in)) continue; bool between_two = (left_in && right_in); int start2 = mapping[L->start]; int end2 = mapping[L->end]; if (start2 >= 0 && end2 >= 0 && L->TwoSided() && ! between_two) { DETSEC_SeparateLine(n, start2, end2, left_in ? SIDE_LEFT : SIDE_RIGHT); } else { if (start2 >= 0) BA_ChangeLD(n, LineDef::F_START, start2); if (end2 >= 0) BA_ChangeLD(n, LineDef::F_END, end2); } } // finally move all vertices of selected sectors selection_c all_verts(OBJ_VERTICES); ConvertSelection(edit.Selected, &all_verts); for (all_verts.begin(&it) ; !it.at_end() ; ++it) { const Vertex * V = Vertices[*it]; BA_ChangeVT(*it, Vertex::F_X, V->x + move_dx); BA_ChangeVT(*it, Vertex::F_Y, V->y + move_dy); } BA_End(); if (unselect) Selection_Clear(true); } //------------------------------------------------------------------------ // RESHAPING STUFF //------------------------------------------------------------------------ static double WeightForVertex(const Vertex *V, /* bbox: */ int x1, int y1, int x2, int y2, int width, int height, int side) { double dist; double extent; if (width >= height) { dist = (side < 0) ? (V->x - x1) : (x2 - V->x); extent = width; } else { dist = (side < 0) ? (V->y - y1) : (y2 - V->y); extent = height; } if (dist > extent * 0.66) return 0; if (dist > extent * 0.33) return 0.25; return 1.0; } struct vert_along_t { int vert_num; double along; public: vert_along_t(int num, double _along) : vert_num(num), along(_along) { } struct CMP { inline bool operator() (const vert_along_t &A, const vert_along_t& B) const { return A.along < B.along; } }; }; void VT_ShapeLine(void) { if (edit.Selected->count_obj() < 3) { Beep("Need 3 or more vertices to shape"); return; } // determine orientation and position of the line int x1, y1, x2, y2; Objs_CalcBBox(edit.Selected, &x1, &y1, &x2, &y2); int width = x2 - x1; int height = y2 - y1; if (width < 4 && height < 4) { Beep("Too small"); return; } // The method here is where split the vertices into two groups and // use the center of each group to form the infinite line. I have // modified that a bit, the vertices in a band near the middle all // participate in the sum but at 0.25 weighting. -AJA- double ax = 0; double ay = 0; double a_total = 0; double bx = 0; double by = 0; double b_total = 0; selection_iterator_c it; for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { const Vertex *V = Vertices[*it]; double weight = WeightForVertex(V, x1,y1, x2,y2, width,height, -1); if (weight > 0) { ax += V->x * weight; ay += V->y * weight; a_total += weight; } weight = WeightForVertex(V, x1,y1, x2,y2, width,height, +1); if (weight > 0) { bx += V->x * weight; by += V->y * weight; b_total += weight; } } SYS_ASSERT(a_total > 0); SYS_ASSERT(b_total > 0); ax /= a_total; ay /= a_total; bx /= b_total; by /= b_total; // check the two end points are not too close double unit_x = (bx - ax); double unit_y = (by - ay); double unit_len = hypot(unit_x, unit_y); if (unit_len < 2) { Beep("Cannot determine line"); return; } unit_x /= unit_len; unit_y /= unit_len; // collect all vertices and determine where along the line they are, // then sort them based on their along value. std::vector< vert_along_t > along_list; for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { const Vertex *V = Vertices[*it]; vert_along_t ALONG(*it, AlongDist(V->x, V->y, ax,ay, bx,by)); along_list.push_back(ALONG); } std::sort(along_list.begin(), along_list.end(), vert_along_t::CMP()); // compute proper positions for start and end of the line const Vertex *V1 = Vertices[along_list.front().vert_num]; const Vertex *V2 = Vertices[along_list. back().vert_num]; double along1 = along_list.front().along; double along2 = along_list. back().along; if (true /* don't move first and last vertices */) { ax = V1->x; ay = V1->y; bx = V2->x; by = V2->y; } else { bx = ax + along2 * unit_x; by = ay + along2 * unit_y; ax = ax + along1 * unit_x; ay = ay + along1 * unit_y; } BA_Begin(); for (unsigned int i = 0 ; i < along_list.size() ; i++) { double frac; if (true /* regular spacing */) frac = i / (double)(along_list.size() - 1); else frac = (along_list[i].along - along1) / (along2 - along1); // ANOTHER OPTION: use distances between neighbor verts... double nx = ax + (bx - ax) * frac; double ny = ay + (by - ay) * frac; BA_ChangeVT(along_list[i].vert_num, Thing::F_X, I_ROUND(nx)); BA_ChangeVT(along_list[i].vert_num, Thing::F_Y, I_ROUND(ny)); } BA_End(); } static double BiggestGapAngle(std::vector< vert_along_t > &along_list, unsigned int *start_idx) { double best_diff = 0; double best_low = 0; *start_idx = 0; for (unsigned int i = 0 ; i < along_list.size() ; i++) { unsigned int k = i + 1; if (k >= along_list.size()) k = 0; double low = along_list[i].along; double high = along_list[k].along; if (high < low) high = high + M_PI * 2.0; double ang_diff = high - low; if (ang_diff > best_diff) { best_diff = ang_diff; best_low = low; *start_idx = k; } } double best = best_low + best_diff * 0.5; return best; } static double EvaluateCircle(double mid_x, double mid_y, double r, std::vector< vert_along_t > &along_list, unsigned int start_idx, double arc_rad, double ang_offset /* radians */, bool move_vertices = false) { double cost = 0; bool partial_circle = (arc_rad < M_PI * 1.9); for (unsigned int i = 0 ; i < along_list.size() ; i++) { unsigned int k = (start_idx + i) % along_list.size(); const Vertex *V = Vertices[along_list[k].vert_num]; double frac = i / (double)(along_list.size() - (partial_circle ? 1 : 0)); double ang = arc_rad * frac + ang_offset; double new_x = mid_x + cos(ang) * r; double new_y = mid_y + sin(ang) * r; if (move_vertices) { BA_ChangeVT(along_list[k].vert_num, Thing::F_X, I_ROUND(new_x)); BA_ChangeVT(along_list[k].vert_num, Thing::F_Y, I_ROUND(new_y)); } else { double dx = new_x - V->x; double dy = new_y - V->y; cost = cost + (dx*dx + dy*dy); } } return cost; } void VT_ShapeArc(void) { if (! EXEC_Param[0][0]) { Beep("VT_ShapeArc: missing angle parameter"); return; } int arc_deg = atoi(EXEC_Param[0]); if (arc_deg < 30 || arc_deg > 360) { Beep("VT_ShapeArc: bad angle: %s", EXEC_Param[0]); return; } double arc_rad = arc_deg * M_PI / 180.0; // determine middle point for circle int x1, y1, x2, y2; Objs_CalcBBox(edit.Selected, &x1, &y1, &x2, &y2); int width = x2 - x1; int height = y2 - y1; if (width < 4 && height < 4) { Beep("Too small"); return; } double mid_x = (x1 + x2) * 0.5; double mid_y = (y1 + y2) * 0.5; // collect all vertices and determine their angle (in radians), // and sort them. // // also determine radius of circle -- average of distances between // the computed mid-point and each vertex. double r = 0; std::vector< vert_along_t > along_list; selection_iterator_c it; for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { const Vertex *V = Vertices[*it]; double dx = V->x - mid_x; double dy = V->y - mid_y; double dist = hypot(dx, dy); if (dist < 4) { Beep("Strange shape"); return; } r += dist; double angle = atan2(dy, dx); vert_along_t ALONG(*it, angle); along_list.push_back(ALONG); } r /= (double)along_list.size(); std::sort(along_list.begin(), along_list.end(), vert_along_t::CMP()); // where is the biggest gap? unsigned int start_idx; unsigned int end_idx; double gap_angle = BiggestGapAngle(along_list, &start_idx); double gap_dx = cos(gap_angle); double gap_dy = sin(gap_angle); if (start_idx > 0) end_idx = start_idx - 1; else end_idx = along_list.size() - 1; const Vertex * start_V = Vertices[along_list[start_idx].vert_num]; const Vertex * end_V = Vertices[along_list[ end_idx].vert_num]; double start_end_dist = hypot(end_V->x - start_V->x, end_V->y - start_V->y); // compute new mid-point and radius (except for a full circle) // and also compute starting angle. double best_offset = 0; double best_cost = 1e30; if (arc_deg < 360) { mid_x = (start_V->x + end_V->x) * 0.5; mid_y = (start_V->y + end_V->y) * 0.5; r = start_end_dist * 0.5; double dx = gap_dx; double dy = gap_dy; if (arc_deg > 180) { dx = -dx; dy = -dy; } double theta = fabs(arc_rad - M_PI) / 2.0; double away = r * tan(theta); mid_x += dx * away; mid_y += dy * away; r = hypot(r, away); best_offset = atan2(start_V->y - mid_y, start_V->x - mid_x); } else { // find the best orientation, the one that minimises the distances // which vertices move. We try 1000 possibilities. for (int pos = 0 ; pos < 1000 ; pos++) { double ang_offset = pos * M_PI * 2.0 / 1000.0; double cost = EvaluateCircle(mid_x, mid_y, r, along_list, start_idx, arc_rad, ang_offset, false); if (cost < best_cost) { best_offset = ang_offset; best_cost = cost; } } } // actually move stuff now BA_Begin(); EvaluateCircle(mid_x, mid_y, r, along_list, start_idx, arc_rad, best_offset, true); BA_End(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_things.h0000644000175100017510000000345312647061302016234 0ustar aaptedaapted//------------------------------------------------------------------------ // THING OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_THINGS_H__ #define __EUREKA_E_THINGS_H__ #include "im_color.h" /* starting areas */ #define THING_PLAYER1 1 #define THING_PLAYER2 2 #define THING_PLAYER3 3 #define THING_PLAYER4 4 #define THING_DEATHMATCH 11 #define MAX_RADIUS 128 /* * angle_to_direction - convert angle to direction (0-7) * * Return a value that is guaranteed to be within [0-7]. */ inline int angle_to_direction (int angle) { return ((unsigned) angle / 45) % 8; } int calc_new_angle(int angle, int diff); /* commands */ void TH_SpinThings(void); void TH_Disconnect(void); void TH_Merge(void); #endif /* __EUREKA_E_THINGS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_vertex.h0000644000175100017510000000320612650314533016252 0ustar aaptedaapted//------------------------------------------------------------------------ // VERTEX STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_VERTEX_H__ #define __EUREKA_E_VERTEX_H__ void MergeVertex(int v1, int v2, bool v1_will_be_deleted); void InsertPolygonVertices (int, int, int, int); int Vertex_FindExact(int x, int y); int VertexHowManyLineDefs(int v_num); void Vertex_MergeList(selection_c *list); bool Vertex_TryFixDangler(int v_num); void VT_Merge(void); void VT_Disconnect(void); void LIN_Disconnect(void); void SEC_Disconnect(void); void VT_ShapeLine(void); void VT_ShapeArc (void); #endif /* __EUREKA_E_VERTEX_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/w_wad.cc0000644000175100017510000006152312647061302015675 0ustar aaptedaapted//------------------------------------------------------------------------ // WAD Reading / Writing //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2015 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include "lib_adler.h" #include "w_rawdef.h" #include "w_wad.h" Wad_file * game_wad; Wad_file * edit_wad; std::vector master_dir; //------------------------------------------------------------------------ // LUMP Handling //------------------------------------------------------------------------ Lump_c::Lump_c(Wad_file *_par, const char *_nam, int _start, int _len) : parent(_par), l_start(_start), l_length(_len) { name = strdup(_nam); SYS_ASSERT(name); // ensure lump name is uppercase y_strupr((char *)name); } Lump_c::Lump_c(Wad_file *_par, const struct raw_wad_entry_s *entry) : parent(_par) { // handle the entry name, which can lack a terminating NUL char buffer[10]; strncpy(buffer, entry->name, 8); buffer[8] = 0; name = strdup(buffer); l_start = LE_U32(entry->pos); l_length = LE_U32(entry->size); // DebugPrintf("new lump '%s' @ %d len:%d\n", name, l_start, l_length); } Lump_c::~Lump_c() { free((void*)name); } void Lump_c::MakeEntry(struct raw_wad_entry_s *entry) { strncpy(entry->name, name, 8); entry->pos = LE_U32(l_start); entry->size = LE_U32(l_length); } void Lump_c::Rename(const char *new_name) { free((void*)name); name = strdup(new_name); SYS_ASSERT(name); // ensure lump name is uppercase y_strupr((char *)name); } bool Lump_c::Seek(int offset) { SYS_ASSERT(offset >= 0); return (fseek(parent->fp, l_start + offset, SEEK_SET) == 0); } bool Lump_c::Read(void *data, int len) { SYS_ASSERT(data && len > 0); return (fread(data, len, 1, parent->fp) == 1); } bool Lump_c::GetLine(char *buffer, size_t buf_size) { int cur_pos = (int)ftell(parent->fp); if (cur_pos < 0) return false; cur_pos -= l_start; if (cur_pos >= l_length) return false; // EOF char *dest = buffer; char *dest_end = buffer + buf_size - 1; for (; cur_pos < l_length && dest < dest_end ; cur_pos++) { *dest++ = fgetc(parent->fp); if (dest[-1] == '\n') break; if (ferror(parent->fp)) return false; if (feof(parent->fp)) break; } *dest = 0; return true; // OK } bool Lump_c::Write(void *data, int len) { SYS_ASSERT(data && len > 0); l_length += len; return (fwrite(data, len, 1, parent->fp) == 1); } void Lump_c::Printf(const char *msg, ...) { static char buffer[FL_PATH_MAX]; va_list args; va_start(args, msg); vsnprintf(buffer, sizeof(buffer), msg, args); va_end(args); buffer[sizeof(buffer) - 1] = 0; Write(buffer, (int)strlen(buffer)); } bool Lump_c::Finish() { if (l_length == 0) l_start = 0; return parent->FinishLump(l_length); } //------------------------------------------------------------------------ // WAD Reading Interface //------------------------------------------------------------------------ Wad_file::Wad_file(const char *_name, char _mode, FILE * _fp) : mode(_mode), fp(_fp), kind('P'), total_size(0), directory(), dir_start(0), dir_count(0), dir_crc(0), levels(), patches(), sprites(), flats(), tex_info(NULL), begun_write(false), insert_point(-1) { filename = strdup(_name); } Wad_file::~Wad_file() { LogPrintf("Closing WAD file: %s\n", filename); fclose(fp); // free the directory for (short k = 0 ; k < NumLumps() ; k++) delete directory[k]; directory.clear(); free((char *)filename); } Wad_file * Wad_file::Open(const char *filename, char mode) { SYS_ASSERT(mode == 'r' || mode == 'w' || mode == 'a'); if (mode == 'w') return Create(filename, mode); LogPrintf("Opening WAD file: %s\n", filename); FILE *fp = NULL; retry: fp = fopen(filename, (mode == 'r' ? "rb" : "r+b")); if (! fp) { // mimic the fopen() semantics if (mode == 'a' && errno == ENOENT) return Create(filename, mode); // if file is read-only, open in 'r' mode instead if (mode == 'a' && (errno == EACCES || errno == EROFS)) { LogPrintf("Open r/w failed, trying again in read mode...\n"); mode = 'r'; goto retry; } int what = errno; LogPrintf("Open failed: %s\n", what, strerror(what)); return NULL; } Wad_file *w = new Wad_file(filename, mode, fp); // determine total size (seek to end) if (fseek(fp, 0, SEEK_END) != 0) FatalError("Error determining WAD size.\n"); w->total_size = (int)ftell(fp); DebugPrintf("total_size = %d\n", w->total_size); if (w->total_size < 0) FatalError("Error determining WAD size.\n"); w->ReadDirectory(); w->DetectLevels(); w->ProcessNamespaces(); return w; } Wad_file * Wad_file::Create(const char *filename, char mode) { LogPrintf("Creating new WAD file: %s\n", filename); FILE *fp = fopen(filename, "w+b"); if (! fp) return NULL; Wad_file *w = new Wad_file(filename, mode, fp); // write out base header raw_wad_header_t header; memset(&header, 0, sizeof(header)); memcpy(header.ident, "PWAD", 4); fwrite(&header, sizeof(header), 1, fp); fflush(fp); w->total_size = (int)sizeof(header); return w; } bool Wad_file::Validate(const char *filename) { FILE *fp = fopen(filename, "rb"); if (! fp) return false; raw_wad_header_t header; if (fread(&header, sizeof(header), 1, fp) != 1) { fclose(fp); return false; } if (! ( header.ident[1] == 'W' && header.ident[2] == 'A' && header.ident[3] == 'D')) { fclose(fp); return false; } fclose(fp); return true; // OK } static int WhatLevelPart(const char *name) { if (y_stricmp(name, "THINGS") == 0) return 1; if (y_stricmp(name, "LINEDEFS") == 0) return 2; if (y_stricmp(name, "SIDEDEFS") == 0) return 3; if (y_stricmp(name, "VERTEXES") == 0) return 4; if (y_stricmp(name, "SECTORS") == 0) return 5; return 0; } static bool IsLevelLump(const char *name) { if (y_stricmp(name, "SEGS") == 0) return true; if (y_stricmp(name, "SSECTORS") == 0) return true; if (y_stricmp(name, "NODES") == 0) return true; if (y_stricmp(name, "REJECT") == 0) return true; if (y_stricmp(name, "BLOCKMAP") == 0) return true; if (y_stricmp(name, "BEHAVIOR") == 0) return true; if (y_stricmp(name, "SCRIPTS") == 0) return true; return WhatLevelPart(name) != 0; } static bool IsGLNodeLump(const char *name) { if (y_strnicmp(name, "GL_", 3) == 0 ) return true; return false; } Lump_c * Wad_file::GetLump(short index) { SYS_ASSERT(0 <= index && index < NumLumps()); SYS_ASSERT(directory[index]); return directory[index]; } Lump_c * Wad_file::FindLump(const char *name) { for (short k = 0 ; k < NumLumps() ; k++) if (y_stricmp(directory[k]->name, name) == 0) return directory[k]; return NULL; // not found } short Wad_file::FindLumpNum(const char *name) { for (short k = 0 ; k < NumLumps() ; k++) if (y_stricmp(directory[k]->name, name) == 0) return k; return -1; // not found } Lump_c * Wad_file::FindLumpInLevel(const char *name, short level) { SYS_ASSERT(0 <= level && level < NumLumps()); // determine how far past the level marker (MAP01 etc) to search short last = level + 14; if (last >= NumLumps()) last = NumLumps() - 1; for (short k = level+1 ; k <= last ; k++) { SYS_ASSERT(0 <= k && k < NumLumps()); if (! IsLevelLump(directory[k]->name)) break; if (y_stricmp(directory[k]->name, name) == 0) return directory[k]; } return NULL; // not found } short Wad_file::FindLevel_Raw(const char *name) { for (short k = 0 ; k < (int)levels.size() ; k++) { short index = levels[k]; SYS_ASSERT(0 <= index && index < NumLumps()); SYS_ASSERT(directory[index]); if (y_stricmp(directory[index]->name, name) == 0) return k; } return -1; // not found } short Wad_file::FindLevel(const char *name) { short k = FindLevel_Raw(name); if (k >= 0) return levels[k]; return -1; // not found } short Wad_file::FindLevelByNumber(int number) { // sanity check if (number <= 0 || number > 99) return -1; char buffer[10]; short index; // try MAP## first sprintf(buffer, "MAP%02d", number); index = FindLevel(buffer); if (index >= 0) return index; // otherwise try E#M# sprintf(buffer, "E%dM%d", MAX(1, number / 10), number % 10); index = FindLevel(buffer); if (index >= 0) return index; return -1; // not found } short Wad_file::FindFirstLevel() { if (levels.size() > 0) return levels[0]; else return -1; // none } short Wad_file::GetLevel(short index) { SYS_ASSERT(0 <= index && index < NumLevels()); return levels[index]; } map_format_e Wad_file::LevelFormat(short lump_index) { int start = lump_index; if (start + LL_BEHAVIOR < (int)NumLumps()) { const char *name = GetLump(start + LL_BEHAVIOR)->Name(); if (y_stricmp(name, "BEHAVIOR") == 0) return MAPF_Hexen; } return MAPF_Doom; } Lump_c * Wad_file::FindLumpInNamespace(const char *name, char group) { short k; switch (group) { case 'P': for (k = 0 ; k < (short)patches.size() ; k++) if (y_stricmp(directory[patches[k]]->name, name) == 0) return directory[patches[k]]; break; case 'S': for (k = 0 ; k < (short)sprites.size() ; k++) if (y_stricmp(directory[sprites[k]]->name, name) == 0) return directory[sprites[k]]; break; case 'F': for (k = 0 ; k < (short)flats.size() ; k++) if (y_stricmp(directory[flats[k]]->name, name) == 0) return directory[flats[k]]; break; default: BugError("FindLumpInNamespace: bad group '%c'\n", group); } return NULL; // not found! } void Wad_file::ReadDirectory() { // TODO: no fatal errors rewind(fp); raw_wad_header_t header; if (fread(&header, sizeof(header), 1, fp) != 1) FatalError("Error reading WAD header.\n"); // TODO: check ident for PWAD or IWAD kind = header.ident[0]; dir_start = LE_S32(header.dir_start); dir_count = LE_S32(header.num_entries); if (dir_count < 0 || dir_count > 32000) FatalError("Bad WAD header, too many entries (%d)\n", dir_count); crc32_c checksum; if (fseek(fp, dir_start, SEEK_SET) != 0) FatalError("Error seeking to WAD directory.\n"); for (short i = 0 ; i < dir_count ; i++) { raw_wad_entry_t entry; if (fread(&entry, sizeof(entry), 1, fp) != 1) FatalError("Error reading WAD directory.\n"); // update the checksum with each _RAW_ entry checksum.AddBlock((u8_t *) &entry, sizeof(entry)); Lump_c *lump = new Lump_c(this, &entry); // TODO: check if entry is valid directory.push_back(lump); } dir_crc = checksum.raw; DebugPrintf("Loaded directory. crc = %08x\n", dir_crc); } void Wad_file::DetectLevels() { // Determine what lumps in the wad are level markers, based on // the lumps which follow it. Store the result in the 'levels' // vector. The test here is rather lax, as I'm told certain // wads exist with a non-standard ordering of level lumps. for (short k = 0 ; k+5 < NumLumps() ; k++) { int part_mask = 0; int part_count = 0; // check whether the next four lumps are level lumps for (short i = 1 ; i <= 4 ; i++) { int part = WhatLevelPart(directory[k+i]->name); if (part == 0) break; // do not allow duplicates if (part_mask & (1 << part)) break; part_mask |= (1 << part); part_count++; } if (part_count == 4) { levels.push_back(k); DebugPrintf("Detected level : %s\n", directory[k]->name); } } // sort levels into alphabetical order // (mainly for the 'N' next map and 'P' prev map commands) std::sort(levels.begin(), levels.end(), level_name_CMP_pred(this)); } static bool IsDummyMarker(const char *name) { // matches P1_START, F3_END etc... if (strlen(name) < 3) return false; if (! strchr("PSF", toupper(name[0]))) return false; if (! isdigit(name[1])) return false; if (y_stricmp(name+2, "_START") == 0 || y_stricmp(name+2, "_END") == 0) return true; return false; } void Wad_file::ProcessNamespaces() { char active = 0; for (short k = 0 ; k < NumLumps() ; k++) { const char *name = directory[k]->name; // skip the sub-namespace markers if (IsDummyMarker(name)) continue; if (y_stricmp(name, "P_START") == 0 || y_stricmp(name, "PP_START") == 0) { if (active && active != 'P') LogPrintf("WARNING: missing %c_END marker.\n", active); active = 'P'; continue; } else if (y_stricmp(name, "P_END") == 0 || y_stricmp(name, "PP_END") == 0) { if (active != 'P') LogPrintf("WARNING: stray P_END marker found.\n"); active = 0; continue; } if (y_stricmp(name, "S_START") == 0 || y_stricmp(name, "SS_START") == 0) { if (active && active != 'S') LogPrintf("WARNING: missing %c_END marker.\n", active); active = 'S'; continue; } else if (y_stricmp(name, "S_END") == 0 || y_stricmp(name, "SS_END") == 0) { if (active != 'S') LogPrintf("WARNING: stray S_END marker found.\n"); active = 0; continue; } if (y_stricmp(name, "F_START") == 0 || y_stricmp(name, "FF_START") == 0) { if (active && active != 'F') LogPrintf("WARNING: missing %c_END marker.\n", active); active = 'F'; continue; } else if (y_stricmp(name, "F_END") == 0 || y_stricmp(name, "FF_END") == 0) { if (active != 'F') LogPrintf("WARNING: stray F_END marker found.\n"); active = 0; continue; } if (active) { if (directory[k]->Length() == 0) { LogPrintf("WARNING: skipping empty lump %s in %c_START\n", name, active); continue; } // DebugPrintf("Namespace %c lump : %s\n", active, name); switch (active) { case 'P': patches.push_back(k); break; case 'S': sprites.push_back(k); break; case 'F': flats. push_back(k); break; default: BugError("ProcessNamespaces: active = 0x%02x\n", (int)active); } } } if (active) LogPrintf("WARNING: Missing %c_END marker (at EOF)\n", active); } bool Wad_file::WasExternallyModified() { if (fseek(fp, 0, SEEK_END) != 0) FatalError("Error determining WAD size.\n"); if (total_size != (int)ftell(fp)) return true; rewind(fp); raw_wad_header_t header; if (fread(&header, sizeof(header), 1, fp) != 1) FatalError("Error reading WAD header.\n"); if (dir_start != LE_S32(header.dir_start) || dir_count != LE_S32(header.num_entries)) return true; fseek(fp, dir_start, SEEK_SET); crc32_c checksum; for (short i = 0 ; i < dir_count ; i++) { raw_wad_entry_t entry; if (fread(&entry, sizeof(entry), 1, fp) != 1) FatalError("Error reading WAD directory.\n"); checksum.AddBlock((u8_t *) &entry, sizeof(entry)); } DebugPrintf("New CRC : %08x\n", checksum.raw); return (dir_crc != checksum.raw); } //------------------------------------------------------------------------ // WAD Writing Interface //------------------------------------------------------------------------ void Wad_file::BeginWrite() { if (mode == 'r') BugError("Wad_file::BeginWrite() called on read-only file\n"); if (begun_write) BugError("Wad_file::BeginWrite() called again without EndWrite()\n"); // put the size into a quantum state total_size = 0; begun_write = true; } void Wad_file::EndWrite() { if (! begun_write) BugError("Wad_file::EndWrite() called without BeginWrite()\n"); begun_write = false; WriteDirectory(); // reset the insertion point insert_point = -1; } void Wad_file::RenameLump(short index, const char *new_name) { SYS_ASSERT(begun_write); SYS_ASSERT(0 <= index && index < NumLumps()); Lump_c *lump = directory[index]; SYS_ASSERT(lump); lump->Rename(new_name); } void Wad_file::RemoveLumps(short index, short count) { SYS_ASSERT(begun_write); SYS_ASSERT(0 <= index && index < NumLumps()); SYS_ASSERT(directory[index]); short i; for (i = 0 ; i < count ; i++) { delete directory[index + i]; } for (i = index ; i+count < NumLumps() ; i++) directory[i] = directory[i+count]; directory.resize(directory.size() - (size_t)count); // fix various arrays containing lump indices FixGroup(levels, index, 0, count); FixGroup(patches, index, 0, count); FixGroup(sprites, index, 0, count); FixGroup(flats, index, 0, count); // reset the insertion point insert_point = -1; } void Wad_file::RemoveLevel(short index) { SYS_ASSERT(begun_write); SYS_ASSERT(0 <= index && index < NumLumps()); short count = 1; // collect associated lumps (THINGS, VERTEXES etc) // this will stop when it hits a non-level lump while (count < 21 && index+count < NumLumps() && (IsLevelLump(directory[index+count]->name) || IsGLNodeLump(directory[index+count]->name)) ) { count++; } // Note: FixGroup() will remove the entry in levels[] RemoveLumps(index, count); } void Wad_file::FixGroup(std::vector& group, short index, short num_added, short num_removed) { bool did_remove = false; for (short k = 0 ; k < (short)group.size() ; k++) { if (group[k] < index) continue; if (group[k] < index + num_removed) { group[k] = -1; did_remove = true; continue; } group[k] += num_added; group[k] -= num_removed; } if (did_remove) { std::vector::iterator ENDP; ENDP = std::remove(group.begin(), group.end(), (short)-1); group.erase(ENDP, group.end()); } } Lump_c * Wad_file::AddLump(const char *name, int max_size) { SYS_ASSERT(begun_write); begun_max_size = max_size; int start = PositionForWrite(max_size); Lump_c *lump = new Lump_c(this, name, start, 0); // check if the insert_point is still valid if (insert_point >= NumLumps()) insert_point = -1; if (insert_point >= 0) { // fix various arrays containing lump indices FixGroup(levels, insert_point, 1, 0); FixGroup(patches, insert_point, 1, 0); FixGroup(sprites, insert_point, 1, 0); FixGroup(flats, insert_point, 1, 0); directory.insert(directory.begin() + insert_point, lump); insert_point++; } else // add to end { directory.push_back(lump); } return lump; } Lump_c * Wad_file::AddLevel(const char *name, int max_size) { int actual_point = insert_point; if (actual_point < 0 || actual_point > NumLumps()) actual_point = NumLumps(); Lump_c * lump = AddLump(name, max_size); levels.push_back(actual_point); std::sort(levels.begin(), levels.end(), level_name_CMP_pred(this)); return lump; } void Wad_file::InsertPoint(short index) { // this is validated on usage insert_point = index; } int Wad_file::HighWaterMark() { int offset = (int)sizeof(raw_wad_header_t); for (short k = 0 ; k < NumLumps() ; k++) { Lump_c *lump = directory[k]; // ignore zero-length lumps (their offset could be anything) if (lump->Length() <= 0) continue; int l_end = lump->l_start + lump->l_length; l_end = ((l_end + 3) / 4) * 4; if (offset < l_end) offset = l_end; } return offset; } int Wad_file::FindFreeSpace(int length) { length = ((length + 3) / 4) * 4; // collect non-zero length lumps and sort by their offset std::vector sorted_dir; for (short k = 0 ; k < NumLumps() ; k++) { Lump_c *lump = directory[k]; if (lump->Length() > 0) sorted_dir.push_back(lump); } std::sort(sorted_dir.begin(), sorted_dir.end(), Lump_c::offset_CMP_pred()); int offset = (int)sizeof(raw_wad_header_t); for (unsigned int k = 0 ; k < sorted_dir.size() ; k++) { Lump_c *lump = sorted_dir[k]; int l_start = lump->l_start; int l_end = lump->l_start + lump->l_length; l_end = ((l_end + 3) / 4) * 4; if (l_end <= offset) continue; if (l_start >= offset + length) continue; // the lump overlapped the current gap, so bump offset offset = l_end; } return offset; } int Wad_file::PositionForWrite(int max_size) { int want_pos; if (max_size <= 0) want_pos = HighWaterMark(); else want_pos = FindFreeSpace(max_size); // determine if position is past end of file // (difference should only be a few bytes) // // Note: doing this for every new lump may be a little expensive, // but trying to optimise it away will just make the code // needlessly complex and hard to follow. if (fseek(fp, 0, SEEK_END) < 0) FatalError("Error seeking to new write position.\n"); total_size = (int)ftell(fp); if (total_size < 0) FatalError("Error seeking to new write position.\n"); if (want_pos > total_size) { SYS_ASSERT(want_pos < total_size + 8); WritePadding(want_pos - total_size); } else if (want_pos == total_size) { /* ready to write */ } else { if (fseek(fp, want_pos, SEEK_SET) < 0) FatalError("Error seeking to new write position.\n"); } DebugPrintf("POSITION FOR WRITE: %d (total_size %d)\n", want_pos, total_size); return want_pos; } bool Wad_file::FinishLump(int final_size) { fflush(fp); // sanity check if (begun_max_size >= 0) if (final_size > begun_max_size) BugError("Internal Error: wrote too much in lump (%d > %d)\n", final_size, begun_max_size); int pos = (int)ftell(fp); if (pos & 3) { WritePadding(4 - (pos & 3)); } fflush(fp); return true; } int Wad_file::WritePadding(int count) { static byte zeros[8] = { 0,0,0,0,0,0,0,0 }; SYS_ASSERT(1 <= count && count <= 8); fwrite(zeros, count, 1, fp); return count; } void Wad_file::WriteDirectory() { dir_start = PositionForWrite(); dir_count = NumLumps(); DebugPrintf("WriteDirectory...\n"); DebugPrintf("dir_start:%d dir_count:%d\n", dir_start, dir_count); crc32_c checksum; for (short k = 0 ; k < dir_count ; k++) { Lump_c *lump = directory[k]; SYS_ASSERT(lump); raw_wad_entry_t entry; lump->MakeEntry(&entry); // update the CRC checksum.AddBlock((u8_t *) &entry, sizeof(entry)); if (fwrite(&entry, sizeof(entry), 1, fp) != 1) FatalError("Error writing WAD directory.\n"); } dir_crc = checksum.raw; DebugPrintf("dir_crc: %08x\n", dir_crc); fflush(fp); total_size = (int)ftell(fp); DebugPrintf("total_size: %d\n", total_size); if (total_size < 0) FatalError("Error determining WAD size.\n"); // update header at start of file rewind(fp); raw_wad_header_t header; strncpy(header.ident, (kind == 'I') ? "IWAD" : "PWAD", 4); header.dir_start = LE_U32(dir_start); header.num_entries = LE_U32(dir_count); if (fwrite(&header, sizeof(header), 1, fp) != 1) FatalError("Error writing WAD header.\n"); fflush(fp); } bool Wad_file::Backup(const char *filename) { fflush(fp); return FileCopy(PathName(), filename); } //------------------------------------------------------------------------ // GLOBAL API //------------------------------------------------------------------------ Lump_c * W_FindLump(const char *name) { for (short i = (int)master_dir.size()-1 ; i >= 0 ; i--) { Lump_c *L = master_dir[i]->FindLump(name); if (L) return L; } return NULL; // not found } Lump_c * W_FindSpriteLump(const char *name) { for (short i = (int)master_dir.size()-1 ; i >= 0 ; i--) { Lump_c *L = master_dir[i]->FindLumpInNamespace(name, 'S'); if (L) return L; } return NULL; // not found } Lump_c * W_FindPatchLump(const char *name) { for (short i = (int)master_dir.size()-1 ; i >= 0 ; i--) { Lump_c *L = master_dir[i]->FindLumpInNamespace(name, 'P'); if (L) return L; } // Fallback: try free-standing lumps for (short i = (int)master_dir.size()-1 ; i >= 0 ; i--) { Lump_c *L = master_dir[i]->FindLump(name); // FIXME: do basic test (size etc) if (L) return L; } return NULL; // not found } int W_LoadLumpData(Lump_c *lump, byte ** buf_ptr) { // include an extra byte, used to NUL-terminate a text buffer *buf_ptr = new byte[lump->Length() + 1]; if (lump->Length() > 0) { if (! lump->Seek() || ! lump->Read(*buf_ptr, lump->Length())) FatalError("W_LoadLumpData: read error loading lump.\n"); } (*buf_ptr)[lump->Length()] = 0; return lump->Length(); } void W_FreeLumpData(byte ** buf_ptr) { if (*buf_ptr) { delete[] *buf_ptr; *buf_ptr = NULL; } } //------------------------------------------------------------------------ void MasterDir_Add(Wad_file *wad) { DebugPrintf("MasterDir: adding '%s'\n", wad->PathName()); master_dir.push_back(wad); } void MasterDir_Remove(Wad_file *wad) { DebugPrintf("MasterDir: removing '%s'\n", wad->PathName()); std::vector::iterator ENDP; ENDP = std::remove(master_dir.begin(), master_dir.end(), wad); master_dir.erase(ENDP, master_dir.end()); } void MasterDir_CloseAll() { while (master_dir.size() > 0) { Wad_file *wad = master_dir.back(); master_dir.pop_back(); delete wad; } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/im_color.cc0000644000175100017510000001076012647061302016374 0ustar aaptedaapted//------------------------------------------------------------------------ // COLORS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "im_color.h" #include "im_img.h" // TRANS_PIXEL #include "w_wad.h" rgb_color_t palette[256]; int trans_replace; byte raw_palette[256][3]; byte raw_colormap[32][256]; // config item int usegamma = 2; extern int gammatable[5][256]; byte bright_map[256]; void W_UpdateGamma() { for (int c = 0 ; c < 256 ; c++) { byte r = raw_palette[c][0]; byte g = raw_palette[c][1]; byte b = raw_palette[c][2]; r = gammatable[usegamma][r]; g = gammatable[usegamma][g]; b = gammatable[usegamma][b]; palette[c] = fl_rgb_color(r, g, b); } } void W_LoadPalette() { Lump_c *lump = W_FindLump("PLAYPAL"); if (! lump) { FatalError("PLAYPAL lump not found.\n"); return; } if (! lump->Seek() || ! lump->Read(raw_palette, sizeof(raw_palette))) { LogPrintf("PLAYPAL: read error\n"); return; } // find the colour closest to TRANS_PIXEL byte tr = raw_palette[TRANS_PIXEL][0]; byte tg = raw_palette[TRANS_PIXEL][1]; byte tb = raw_palette[TRANS_PIXEL][2]; trans_replace = W_FindPaletteColor(tr, tg, tb); W_UpdateGamma(); W_CreateBrightMap(); IM_ResetDummyTextures(); } void W_LoadColormap() { Lump_c *lump = W_FindLump("COLORMAP"); if (! lump) { FatalError("COLORMAP lump not found.\n"); return; } if (! lump->Seek() || ! lump->Read(raw_colormap, sizeof(raw_colormap))) { LogPrintf("COLORMAP: read error\n"); return; } // ensure colormap does not transparent pixel for (int i = 0 ; i < 32 ; i++) for (int c = 0 ; c < 256 ; c++) { if (raw_colormap[i][c] == TRANS_PIXEL) raw_colormap[i][c] = trans_replace; } } rgb_color_t DarkerColor(rgb_color_t col) { int r = RGB_RED(col); int g = RGB_GREEN(col); int b = RGB_BLUE(col); return fl_rgb_color(r*2/3, g*2/3, b*2/3); } rgb_color_t LighterColor(rgb_color_t col) { int r = RGB_RED(col); int g = RGB_GREEN(col); int b = RGB_BLUE(col); r = r * 13 / 16 + 48; g = g * 13 / 16 + 48; b = b * 13 / 16 + 48; return fl_rgb_color(r, g, b); } byte W_FindPaletteColor(int r, int g, int b) { int best = 0; int best_dist = (1 << 30); for (int c = 0 ; c < 256 ; c++) { if (c == TRANS_PIXEL) continue; int dr = r - (int)raw_palette[c][0]; int dg = g - (int)raw_palette[c][1]; int db = b - (int)raw_palette[c][2]; int dist = dr*dr + dg*dg + db*db; if (dist < best_dist) { best = c; best_dist = dist; } } return best; } void W_CreateBrightMap() { for (int c = 0 ; c < 256 ; c++) { byte r = raw_palette[c][0]; byte g = raw_palette[c][1]; byte b = raw_palette[c][2]; rgb_color_t col = LighterColor(fl_rgb_color(r, g, b)); r = RGB_RED(col); g = RGB_GREEN(col); b = RGB_BLUE(col); bright_map[c] = W_FindPaletteColor(r, g, b); } } rgb_color_t ParseColor(const char *str) { if (*str == '#') str++; if (strlen(str) >= 6) // long form #rrggbb { int number = (int)strtol(str, NULL, 16); int r = (number & 0xFF0000) >> 16; int g = (number & 0x00FF00) >> 8; int b = (number & 0x0000FF); return fl_rgb_color(r, g, b); } else // short form: #rgb { int number = (int)strtol(str, NULL, 16); int r = (number & 0xF00) >> 8; int g = (number & 0x0F0) >> 4; int b = (number & 0x00F); return fl_rgb_color(r*17, g*17, b*17); } } rgb_color_t SectorLightColor(int light) { float lt = CLAMP(0, (light | 15), 256) / 256.0; lt = pow(lt, 1.5); light = CLAMP(48, (int)(lt * 256), 255); return RGB_MAKE(light, light, light); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/r_grid.h0000644000175100017510000000702612651123123015675 0ustar aaptedaapted//------------------------------------------------------------------------ // GRID STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 __EUREKA_R_GRID_H__ #define __EUREKA_R_GRID_H__ class Grid_State_c { public: // the actual grid step (64, 128, etc) int step; // if true, new and moved objects are forced to be on the grid bool snap; // whether the grid is being displayed or not. bool shown; // the mode / style of grid : 0 is dotty, 1 is normal. int mode; // map coordinates for centre of canvas double orig_x; double orig_y; // scale for drawing map float Scale; public: Grid_State_c(); virtual ~Grid_State_c(); public: void Init(); inline bool isShown() const { return shown; } void MoveTo(double new_x, double new_y); void Scroll(double delta_x, double delta_y); // change the view so that the map coordinates (x, y) // appear at the centre of the window void CenterMapAt(int x, int y) { MoveTo(x, y); } // return X/Y coordinate snapped to grid // (or unchanged is the 'snap' flag is off) int SnapX(int map_x) const; int SnapY(int map_y) const; // return X/Y coordinate snapped to grid (always) int ForceSnapX(int map_x) const; int ForceSnapY(int map_y) const; // quantization snap, can pick coordinate on other side int QuantSnapX(int map_x, bool want_furthest, int *dir = NULL) const; int QuantSnapY(int map_y, bool want_furthest, int *dir = NULL) const; // check if the X/Y coordinate is on a grid point bool OnGridX(int map_x) const; bool OnGridY(int map_y) const; bool OnGrid(int map_x, int map_y) const; // interface with UI_Infobar widget... static const char *scale_options(); static const char *grid_options(); void ScaleFromWidget(int i); void StepFromWidget(int i); // compute new grid step from current scale void StepFromScale(); // increase or decrease the grid size. The 'delta' parameter // is positive to increase it, negative to decrease it. void AdjustStep(int delta); void AdjustScale(int delta); void SetShown(bool enable); void SetSnap (bool enable); void SetMode (int new_mode); void ToggleShown(); void ToggleMode(); void ToggleSnap(); // choose the scale nearest to (and less than) the wanted one void NearestScale(double want_scale); void ScaleFromDigit(int digit); void StepFromDigit(int digit); // move the origin so that the focus point of the last zoom // operation (scale change) is map_x/y. void RefocusZoom(int map_x, int map_y, float before_Scale); // these are really private, but needed by Grid_ParseUser() void DoSetGrid(); void DoSetScale(); private: static const double scale_values[]; static const int digit_scales[]; static const int grid_values[]; }; extern Grid_State_c grid; bool Grid_ParseUser(const char ** tokens, int num_tok); void Grid_WriteUser(FILE *fp); #endif /* __EUREKA_R_GRID_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_sector.cc0000644000175100017510000003633012651405403016565 0ustar aaptedaapted//------------------------------------------------------------------------ // SECTOR PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 "main.h" #include "ui_window.h" #include "levels.h" #include "e_checks.h" #include "e_sector.h" #include "e_things.h" #include "m_game.h" #include "w_rawdef.h" // config items int floor_bump_small = 1; int floor_bump_medium = 8; int floor_bump_large = 64; int light_bump_small = 4; int light_bump_medium = 16; int light_bump_large = 64; //TODO make these configurable int headroom_presets[UI_SectorBox::HEADROOM_BUTTONS] = { 0, 72, 96, 128, 192, 256 }; // // UI_SectorBox Constructor // UI_SectorBox::UI_SectorBox(int X, int Y, int W, int H, const char *label) : Fl_Group(X, Y, W, H, label), obj(-1), count(0) { box(FL_FLAT_BOX); // (FL_THIN_UP_BOX); X += 6; Y += 6; W -= 12; H -= 10; which = new UI_Nombre(X+6, Y, W-12, 28, "Sector"); Y += which->h() + 4; type = new Fl_Int_Input(X+70, Y, 64, 24, "Type: "); type->align(FL_ALIGN_LEFT); type->callback(type_callback, this); type->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); choose = new Fl_Button(X+W/2+24, Y, 80, 24, "Choose"); choose->callback(button_callback, this); Y += type->h() + 4; desc = new Fl_Output(X+70, Y, W-78, 24, "Desc: "); desc->align(FL_ALIGN_LEFT); Y += desc->h() + 12; tag = new Fl_Int_Input(X+70, Y, 64, 24, "Tag: "); tag->align(FL_ALIGN_LEFT); tag->callback(tag_callback, this); tag->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += tag->h() + 4; light = new Fl_Int_Input(X+70, Y, 64, 24, "Light: "); light->align(FL_ALIGN_LEFT); light->callback(light_callback, this); light->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); lt_down = new Fl_Button(light->x() + light->w() + 20, Y+1, 30, 22, "-"); lt_up = new Fl_Button(light->x() + light->w() + 60, Y+1, 30, 22, "+"); lt_down->labelfont(FL_HELVETICA_BOLD); lt_up ->labelfont(FL_HELVETICA_BOLD); lt_down->labelsize(16); lt_up ->labelsize(16); lt_down->callback(button_callback, this); lt_up ->callback(button_callback, this); Y += light->h() + 20; c_pic = new UI_Pic(X+W-82, Y-2, 64, 64, "Ceil"); f_pic = new UI_Pic(X+W-82, Y+74, 64, 64, "Floor"); c_pic->callback(tex_callback, this); f_pic->callback(tex_callback, this); Y += 10; c_tex = new Fl_Input(X+70, Y, 108, 24, "Ceiling: "); c_tex->align(FL_ALIGN_LEFT); c_tex->callback(tex_callback, this); c_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += c_tex->h() + 3; ceil_h = new Fl_Int_Input(X+70, Y, 64, 24, ""); ceil_h->align(FL_ALIGN_LEFT); ceil_h->callback(height_callback, this); ceil_h->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); ce_down = new Fl_Button(X+28, Y+1, 30, 22, "-"); ce_up = new Fl_Button(X+145, Y+1, 30, 22, "+"); ce_down->labelfont(FL_HELVETICA_BOLD); ce_up ->labelfont(FL_HELVETICA_BOLD); ce_down->labelsize(16); ce_up ->labelsize(16); ce_down->callback(button_callback, this); ce_up ->callback(button_callback, this); Y += ceil_h->h() + 10; floor_h = new Fl_Int_Input(X+70, Y, 64, 24, ""); floor_h->align(FL_ALIGN_LEFT); floor_h->callback(height_callback, this); floor_h->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); fl_down = new Fl_Button(X+28, Y+1, 30, 22, "-"); fl_up = new Fl_Button(X+145, Y+1, 30, 22, "+"); fl_down->labelfont(FL_HELVETICA_BOLD); fl_up ->labelfont(FL_HELVETICA_BOLD); fl_down->labelsize(16); fl_up ->labelsize(16); fl_down->callback(button_callback, this); fl_up ->callback(button_callback, this); Y += floor_h->h() + 3; f_tex = new Fl_Input(X+70, Y, 108, 24, "Floor: "); f_tex->align(FL_ALIGN_LEFT); f_tex->callback(tex_callback, this); f_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += f_tex->h() + 28; headroom = new Fl_Int_Input(X+100, Y, 56, 24, "Headroom: "); headroom->align(FL_ALIGN_LEFT); headroom->callback(room_callback, this); headroom->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); for (int i = 0 ; i < HEADROOM_BUTTONS ; i++) { int hx = (i < 2) ? (X + 170 + i * 60) : (X + 50 + (i-2) * 60); int hy = Y + 28 * ((i < 2) ? 0 : 1); hd_buttons[i] = new Fl_Button(hx, hy+1, 45, 22); hd_buttons[i]->copy_label(Int_TmpStr(headroom_presets[i])); hd_buttons[i]->callback(room_callback, this); } Y += headroom->h() + 50; // generalized sector stuff bm_title = new Fl_Box(FL_NO_BOX, X+10, Y, 100, 24, "Boom flags:"); bm_title->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); Y += 28; bm_damage = new Fl_Choice(X+W - 95, Y, 80, 24, "Damage: "); bm_damage->add("NONE|5 hp|10 hp|20 hp"); bm_damage->value(0); bm_damage->callback(type_callback, this); bm_secret = new Fl_Check_Button(X+28, Y, 94, 20, "Secret"); bm_secret->labelsize(12); bm_secret->callback(type_callback, this); bm_friction = new Fl_Check_Button(X+28, Y+20, 94, 20, "Friction"); bm_friction->labelsize(12); bm_friction->callback(type_callback, this); bm_wind = new Fl_Check_Button(X+28, Y+40, 94, 20, "Wind"); bm_wind->labelsize(12); bm_wind->callback(type_callback, this); end(); resizable(NULL); } // // UI_SectorBox Destructor // UI_SectorBox::~UI_SectorBox() { } //------------------------------------------------------------------------ void UI_SectorBox::height_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; int f_h = atoi(box->floor_h->value()); int c_h = atoi(box->ceil_h->value()); f_h = CLAMP(-32767, f_h, 32767); c_h = CLAMP(-32767, c_h, 32767); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { if (w == box->floor_h) BA_ChangeSEC(*it, Sector::F_FLOORH, f_h); else BA_ChangeSEC(*it, Sector::F_CEILH, c_h); } BA_End(); box-> floor_h->value(Int_TmpStr(f_h)); box-> ceil_h->value(Int_TmpStr(c_h)); box->headroom->value(Int_TmpStr(c_h - f_h)); } } void UI_SectorBox::room_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; int room = atoi(box->headroom->value()); // handle the shortcut buttons for (int i = 0 ; i < HEADROOM_BUTTONS ; i++) { if (w == box->hd_buttons[i]) { room = atoi(w->label()); } } selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { int new_h = Sectors[*it]->floorh + room; new_h = CLAMP(-32767, new_h, 32767); BA_ChangeSEC(*it, Sector::F_CEILH, new_h); } BA_End(); box->UpdateField(); } } void UI_SectorBox::tex_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; if (box->obj < 0) return; bool is_pic = (w == box->f_pic || w == box->c_pic); bool is_floor = (w == box->f_pic || w == box->f_tex); int new_tex; // MMB on ceiling flat image sets to sky if (w == box->c_pic && Fl::event_button() == 2) { new_tex = BA_InternaliseString(game_info.sky_flat); goto change_it; } // LMB on the flat image just selects/unselects it (red border) if (is_pic && Fl::event_button() != 3) { UI_Pic * pic = (UI_Pic *) w; pic->Selected(! pic->Selected()); pic->redraw(); if (pic->Selected()) main_win->ShowBrowser('F'); return; } // right click sets to default value // [ Note the 'is_pic' check prevents a bug when using RMB in browser ] if (is_pic && Fl::event_button() == 3) { new_tex = BA_InternaliseString(is_floor ? default_floor_tex : default_ceil_tex); } else { new_tex = FlatFromWidget(is_floor ? box->f_tex : box->c_tex); } change_it: selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { if (is_floor) BA_ChangeSEC(*it, Sector::F_FLOOR_TEX, new_tex); else BA_ChangeSEC(*it, Sector::F_CEIL_TEX, new_tex); } BA_End(); box->UpdateField(); } } void UI_SectorBox::SetFlat(const char *name, int e_state) { if (obj < 0) return; int sel_pics = GetSelectedPics(); if (sel_pics == 0) sel_pics = (e_state & FL_BUTTON3) ? 2 : 1; if (sel_pics & 1) { f_tex->value(name); f_tex->do_callback(); } if (sel_pics & 2) { c_tex->value(name); c_tex->do_callback(); } } void UI_SectorBox::type_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; int mask = 65535; int value = atoi(box->type->value()); if (w == box->type && value >= 32) { // when user enters a large value into type box, store it as-is // in sectors. The panel will show the Boom interpretation. } else if (game_info.gen_types) { // Boom generalized sectors mask = BoomSF_TypeMask; if (w == box->bm_damage) { mask = BoomSF_DamageMask; value = box->bm_damage->value() << 5; } else if (w == box->bm_secret) { mask = BoomSF_Secret; value = box->bm_secret->value() << 7; } else if (w == box->bm_friction) { mask = BoomSF_Friction; value = box->bm_friction->value() << 8; } else if (w == box->bm_wind) { mask = BoomSF_Wind; value = box->bm_wind->value() << 9; } } value &= mask; selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { int old_type = Sectors[*it]->type; BA_ChangeSEC(*it, Sector::F_TYPE, (old_type & ~mask) | value); } BA_End(); } // update the description box->UpdateField(Sector::F_TYPE); } void UI_SectorBox::SetSectorType(int new_type) { if (obj < 0) return; char buffer[64]; sprintf(buffer, "%d", new_type); type->value(buffer); type->do_callback(); } void UI_SectorBox::light_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; int new_lt = atoi(box->light->value()); // we allow 256 if explicitly typed, otherwise limit to 255 if (new_lt > 256) new_lt = 255; if (new_lt < 0) new_lt = 0; selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { BA_ChangeSEC(*it, Sector::F_LIGHT, new_lt); } BA_End(); } } void UI_SectorBox::tag_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; int new_tag = atoi(box->tag->value()); new_tag = CLAMP(-32767, new_tag, 32767); Tags_ApplyNewValue(new_tag); } void UI_SectorBox::button_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; if (w == box->choose) { main_win->ShowBrowser('S'); return; } int lt_step; if (Fl::event_shift()) lt_step = light_bump_small; else if (Fl::event_ctrl()) lt_step = light_bump_large; else lt_step = light_bump_medium; if (w == box->lt_up) { CMD_AdjustLight(+lt_step); return; } else if (w == box->lt_down) { CMD_AdjustLight(-lt_step); return; } int mv_step; if (Fl::event_shift()) mv_step = floor_bump_small; else if (Fl::event_ctrl()) mv_step = floor_bump_large; else mv_step = floor_bump_medium; if (w == box->ce_up) { EXEC_Param[0] = Int_TmpStr(+mv_step); SEC_Ceil(); return; } else if (w == box->ce_down) { EXEC_Param[0] = Int_TmpStr(-mv_step); SEC_Ceil(); return; } if (w == box->fl_up) { EXEC_Param[0] = Int_TmpStr(+mv_step); SEC_Floor(); return; } else if (w == box->fl_down) { EXEC_Param[0] = Int_TmpStr(-mv_step); SEC_Floor(); return; } } //------------------------------------------------------------------------ void UI_SectorBox::SetObj(int _index, int _count) { if (obj == _index && count == _count) return; obj = _index; count = _count; which->SetIndex(obj); which->SetSelected(count); UpdateField(); if (obj < 0) UnselectPics(); redraw(); } void UI_SectorBox::UpdateField(int field) { if (field < 0 || field == Sector::F_FLOORH || field == Sector::F_CEILH) { if (is_sector(obj)) { floor_h->value(Int_TmpStr(Sectors[obj]->floorh)); ceil_h->value(Int_TmpStr(Sectors[obj]->ceilh)); headroom->value(Int_TmpStr(Sectors[obj]->HeadRoom())); } else { floor_h->value(""); ceil_h->value(""); headroom->value(""); } } if (field < 0 || field == Sector::F_FLOOR_TEX || field == Sector::F_CEIL_TEX) { if (is_sector(obj)) { f_tex->value(Sectors[obj]->FloorTex()); c_tex->value(Sectors[obj]->CeilTex()); f_pic->GetFlat(Sectors[obj]->FloorTex()); c_pic->GetFlat(Sectors[obj]->CeilTex()); } else { f_tex->value(""); c_tex->value(""); f_pic->Clear(); c_pic->Clear(); } } if (field < 0 || field == Sector::F_TYPE) { bm_damage->value(0); bm_secret->value(0); bm_friction->value(0); bm_wind->value(0); if (is_sector(obj)) { int value = Sectors[obj]->type; int mask = game_info.gen_types ? 31 : 65535; type->value(Int_TmpStr(value & mask)); const sectortype_t *info = M_GetSectorType(value & mask); desc->value(info->desc); if (game_info.gen_types) { bm_damage->value((value >> 5) & 3); bm_secret->value((value >> 7) & 1); bm_friction->value((value >> 8) & 1); bm_wind ->value((value >> 9) & 1); } } else { type->value(""); desc->value(""); } } if (field < 0 || field == Sector::F_LIGHT || field == Sector::F_TAG) { if (is_sector(obj)) { light->value(Int_TmpStr(Sectors[obj]->light)); tag->value(Int_TmpStr(Sectors[obj]->tag)); } else { light->value(""); tag->value(""); } } } int UI_SectorBox::GetSelectedPics() const { return (f_pic->Selected() ? 1 : 0) | (c_pic->Selected() ? 2 : 0); } void UI_SectorBox::UnselectPics() { f_pic->Selected(false); c_pic->Selected(false); } // FIXME: make a method of Sector class void UI_SectorBox::AdjustHeight(s16_t *h, int delta) { // prevent overflow if (delta > 0 && (int(*h) + delta) > 32767) { *h = 32767; return; } else if (delta < 0 && (int(*h) + delta) < -32767) { *h = -32767; return; } *h = *h + delta; } // FIXME: make a method of Sector class void UI_SectorBox::AdjustLight(s16_t *L, int delta) { if (abs(delta) > 16) { *L = (delta > 0) ? 255 : 0; return; } if (abs(delta) < 4) *L += delta; else { if (delta > 0) *L = (*L | 15) + 1; else *L = (*L - 1) & ~15; } if (*L < 0) *L = 0; else if (*L > 255) *L = 255; } int UI_SectorBox::FlatFromWidget(Fl_Input *w) { char name[WAD_FLAT_NAME+1]; memset(name, 0, sizeof(name)); strncpy(name, w->value(), WAD_FLAT_NAME); for (int i = 0 ; i < WAD_FLAT_NAME ; i++) name[i] = toupper(name[i]); return BA_InternaliseString(name); } void UI_SectorBox::UpdateTotal() { which->SetTotal(NumSectors); } void UI_SectorBox::UpdateGameInfo() { if (game_info.gen_types) { bm_title->show(); bm_damage->show(); bm_secret->show(); bm_friction->show(); bm_wind->show(); } else { bm_title->hide(); bm_damage->hide(); bm_secret->hide(); bm_friction->hide(); bm_wind->hide(); } UpdateField(); redraw(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_select.h0000644000175100017510000000627112647575615016251 0ustar aaptedaapted//------------------------------------------------------------------------ // SELECTION SET //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_SELECT_H__ #define __EUREKA_M_SELECT_H__ #include "m_bitvec.h" class selection_iterator_c; #define MAX_STORE_SEL 24 class selection_c { friend class selection_iterator_c; private: obj_type_e type; int objs[MAX_STORE_SEL]; int count; bitvec_c * bv; // NULL unless needed int b_count; int maxobj; // the very first object selected, or -1 int first_obj; public: selection_c(obj_type_e _type = OBJ_THINGS); ~selection_c(); obj_type_e what_type() const { return type; } // this also clears the selection void change_type(obj_type_e new_type); void clear_all(); bool empty() const; bool notempty() const { return ! empty(); } // return the number of selected objects int count_obj() const; // return the highest selected object, or -1 if none int max_obj() const { return maxobj; } bool get(int n) const; void set(int n); void clear(int n); void toggle(int n); void frob(int n, sel_op_e op); void frob_range(int n1, int n2, sel_op_e op); // set all the objects from the other selection void merge(const selection_c& other); // clear all the objects from the other selection void unmerge(const selection_c& other); // only keep values that are in both selections void intersect(const selection_c& other); bool test_equal(const selection_c& other); // these return -1 if there is no first or second int find_first() const; int find_second() const; // sets up the passed iterator for iterating over all the // object numbers contained in this selection. // Modifying the set is NOT ALLOWED during a traversal. void begin(selection_iterator_c * it) const; private: void ConvertToBitvec(); void RecomputeMaxObj(); }; class selection_iterator_c { friend class selection_c; private: const selection_c *sel; // this is position in the objs[] array when there is no // bit vector, otherwise it is the object number itself // (and the corresponding bit will be one). int pos; public: bool at_end() const; int operator* () const; selection_iterator_c& operator++ (); }; #endif /* __EUREKA_M_SELECT_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/objects.h0000644000175100017510000000347712651045635016101 0ustar aaptedaapted//------------------------------------------------------------------------ // OBJECT STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_OBJECTS_H__ #define __EUREKA_OBJECTS_H__ void SelectObjectsInBox (selection_c *list, int, int, int, int, int); void HighlightObject (int, int, int); void DeleteObjects (selection_c * list); bool LineTouchesBox (int, int, int, int, int); void GetDragFocus(int *x, int *y, int map_x, int map_y); bool Texture_MatchPattern(const char *tex, const char *pattern); void Insert_Vertex(bool force_continue, bool no_fill, bool is_button = false); void Insert_Vertex_split(int split_ld, int new_x, int new_y); /* commands */ void CMD_Insert(void); void CMD_MoveObjects(int delta_x, int delta_y, int delta_z = 0); void CMD_CopyProperties(void); #endif /* __EUREKA_OBJECTS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/w_sprite.h0000644000175100017510000000246212647061302016267 0ustar aaptedaapted//------------------------------------------------------------------------ // SPRITE LOADING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_W_SPRITE_H__ #define __EUREKA_W_SPRITE_H__ #include "im_img.h" void W_ClearSprites(); Img_c * W_GetSprite(int type); #endif /* __EUREKA_W_SPRITE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_tile.h0000644000175100017510000000331012647337011016061 0ustar aaptedaapted//------------------------------------------------------------------------ // Adjustable border (variation of Fl_Tile) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012 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 __EUREKA_UI_TILE_H__ #define __EUREKA_UI_TILE_H__ class UI_Tile : public Fl_Tile { private: Fl_Widget * left; Fl_Widget * right; Fl_Box * limiter; // when the right widget (the browser) is hidden, this remembers // how much of the available width it was using, so can restore it // where the user expects. // // NOTE: not set or used while right widget is visible. int right_W; public: UI_Tile(int X, int Y, int W, int H, const char *what, Fl_Widget *_left, Fl_Widget *_right); virtual ~UI_Tile(); /* FLTK method */ void resize(int, int, int, int); public: void ShowRight(); void HideRight(); void MinimiseRight(); void MaximiseRight(); bool ParseUser(const char ** tokens, int num_tok); void WriteUser(FILE *fp); private: void ResizeBoth(); }; #endif /* __EUREKA_UI_TILE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/sys_endian.h0000644000175100017510000000715112647061302016567 0ustar aaptedaapted//------------------------------------------------------------------------ // EDGE Endian handling //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2008 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. // //------------------------------------------------------------------------ // // Using code from SDL_byteorder.h and SDL_endian.h. // Copyright (C) 1997-2004 Sam Lantinga. // //------------------------------------------------------------------------ #ifndef __SYS_ENDIAN_H__ #define __SYS_ENDIAN_H__ // ---- determine byte order ---- #define UT_LIL_ENDIAN 1234 #define UT_BIG_ENDIAN 4321 #if defined(__LITTLE_ENDIAN__) || defined(WIN32) || \ defined(__i386__) || defined(__i386) || \ defined(__ia64__) || defined(__x86_64__) || \ defined(__alpha__) || defined(__alpha) || \ defined(__arm__) || defined(__SYMBIAN32__) || \ (defined(__mips__) && defined(__MIPSEL__)) #define UT_BYTEORDER UT_LIL_ENDIAN #else #define UT_BYTEORDER UT_BIG_ENDIAN #endif // ---- the gruntwork of swapping ---- #if defined(__GNUC__) && defined(__i386__) static inline u16_t UT_Swap16(u16_t x) { __asm__("xchgb %b0,%h0" : "=q" (x) : "0" (x)); return x; } #elif defined(__GNUC__) && defined(__x86_64__) static inline u16_t UT_Swap16(u16_t x) { __asm__("xchgb %b0,%h0" : "=Q" (x) : "0" (x)); return x; } #elif defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__)) static inline u16_t UT_Swap16(u16_t x) { u16_t result; __asm__("rlwimi %0,%2,8,16,23" : "=&r" (result) : "0" (x >> 8), "r" (x)); return result; } #else static inline u16_t UT_Swap16(u16_t x) { return((x<<8)|(x>>8)); } #endif #if defined(__GNUC__) && defined(__i386__) static inline u32_t UT_Swap32(u32_t x) { __asm__("bswap %0" : "=r" (x) : "0" (x)); return x; } #elif defined(__GNUC__) && defined(__x86_64__) static inline u32_t UT_Swap32(u32_t x) { __asm__("bswapl %0" : "=r" (x) : "0" (x)); return x; } #elif defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__)) static inline u32_t UT_Swap32(u32_t x) { u32_t result; __asm__("rlwimi %0,%2,24,16,23" : "=&r" (result) : "0" (x>>24), "r" (x)); __asm__("rlwimi %0,%2,8,8,15" : "=&r" (result) : "0" (result), "r" (x)); __asm__("rlwimi %0,%2,24,0,7" : "=&r" (result) : "0" (result), "r" (x)); return result; } #else static inline u32_t UT_Swap32(u32_t x) { return ((x<<24)|((x<<8)&0x00FF0000)|((x>>8)&0x0000FF00)|(x>>24)); } #endif // ---- byte swap from specified endianness to native ---- #if (UT_BYTEORDER == UT_LIL_ENDIAN) #define LE_U16(X) ((u16_t)(X)) #define LE_U32(X) ((u32_t)(X)) #define BE_U16(X) UT_Swap16(X) #define BE_U32(X) UT_Swap32(X) #else #define LE_U16(X) UT_Swap16(X) #define LE_U32(X) UT_Swap32(X) #define BE_U16(X) ((u16_t)(X)) #define BE_U32(X) ((u32_t)(X)) #endif // signed versions of the above #define LE_S16(X) ((s16_t) LE_U16((u16_t) (X))) #define LE_S32(X) ((s32_t) LE_U32((u32_t) (X))) #define BE_S16(X) ((s16_t) BE_U16((u16_t) (X))) #define BE_S32(X) ((s32_t) BE_U32((u32_t) (X))) #endif // __SYS_ENDIAN_H__ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_keys.cc0000644000175100017510000005560312651060166016067 0ustar aaptedaapted//------------------------------------------------------------------------ // KEY BINDINGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2013-2015 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 "main.h" #include "m_config.h" #include const char * EXEC_Param[MAX_EXEC_PARAM]; const char * EXEC_Flags[MAX_EXEC_PARAM]; int EXEC_Errno; static std::vector< editor_command_t * > all_commands; static key_context_e ContextFromName(const char *name) { if (strncmp(name, "LIN_", 4) == 0) return KCTX_Line; if (strncmp(name, "SEC_", 4) == 0) return KCTX_Sector; if (strncmp(name, "TH_", 3) == 0) return KCTX_Thing; if (strncmp(name, "VT_", 3) == 0) return KCTX_Vertex; if (strncmp(name, "3D_", 3) == 0) return KCTX_Render; // we don't need anything for KCTX_Browser return KCTX_NONE; } /* this should only be called during startup */ void M_RegisterCommand(const char *name, command_func_t func) { editor_command_t *cmd = new editor_command_t; cmd->name = name; cmd->func = func; cmd->flag_list = NULL; cmd->keyword_list = NULL; cmd->req_context = ContextFromName(name); all_commands.push_back(cmd); } /* this should only be called during startup */ void M_RegisterCommandList(editor_command_t * list) { // the structures are used directly for ( ; list->name ; list++) { list->req_context = ContextFromName(list->name); all_commands.push_back(list); } } const editor_command_t * FindEditorCommand(const char *name) { for (unsigned int i = 0 ; i < all_commands.size() ; i++) if (y_stricmp(all_commands[i]->name, name) == 0) return all_commands[i]; return NULL; } const editor_command_t * LookupEditorCommand(int idx) { if (idx >= (int)all_commands.size()) return NULL; return all_commands[idx]; } //------------------------------------------------------------------------ typedef struct { keycode_t key; const char * name; } key_mapping_t; static key_mapping_t key_map[] = { { ' ', "SPACE" }, { FL_BackSpace, "BS" }, { FL_Tab, "TAB" }, { FL_Enter, "ENTER" }, { FL_Pause, "PAUSE" }, { FL_Escape, "ESC" }, { FL_Left, "LEFT" }, { FL_Up, "UP" }, { FL_Right, "RIGHT" }, { FL_Down, "DOWN" }, { FL_Page_Up, "PGUP" }, { FL_Page_Down, "PGDN" }, { FL_Home, "HOME" }, { FL_End, "END" }, { FL_Print, "PRINT" }, { FL_Insert, "INS" }, { FL_Delete, "DEL" }, { FL_Menu, "MENU" }, { FL_Help, "HELP" }, { FL_KP_Enter, "KP_Enter"}, { FL_Volume_Down, "VOL_DOWN" }, { FL_Volume_Mute, "VOL_MUTE" }, { FL_Volume_Up, "VOL_UP" }, { FL_Media_Play, "CD_PLAY" }, { FL_Media_Stop, "CD_STOP" }, { FL_Media_Prev, "CD_PREV" }, { FL_Media_Next, "CD_NEXT" }, { FL_Home_Page, "HOME_PAGE" }, { FL_Mail, "MAIL" }, { FL_Search, "SEARCH" }, { FL_Back, "BACK" }, { FL_Forward, "FORWARD" }, { FL_Stop, "STOP" }, { FL_Refresh, "REFRESH" }, { FL_Sleep, "SLEEP" }, { FL_Favorites, "FAVORITES" }, // special stuff (not in FLTK) { FL_WheelUp, "WHEEL_UP" }, { FL_WheelDn, "WHEEL_DN" }, // some synonyms for user input { ' ', "SPC" }, { FL_BackSpace, "BACKSPACE" }, { FL_Enter, "RETURN" }, { FL_Escape, "ESCAPE" }, { FL_Insert, "INSERT" }, { FL_Delete, "DELETE" }, { FL_Page_Up, "PAGEUP" }, { FL_Page_Down, "PAGEDOWN" }, { 0, NULL } // the end }; /* returns zero (an invalid key) if parsing fails */ keycode_t M_ParseKeyString(const char *str) { int key = 0; if (y_strnicmp(str, "CMD-", 4) == 0) { key |= MOD_COMMAND; str += 4; } else if (y_strnicmp(str, "META-", 5) == 0) { key |= MOD_META; str += 5; } else if (y_strnicmp(str, "ALT-", 4) == 0) { key |= MOD_ALT; str += 4; } else if (y_strnicmp(str, "SHIFT-", 6) == 0) { key |= MOD_SHIFT; str += 6; } if (strlen(str) == 1 && str[0] > 32 && str[0] < 127 && isprint(str[0])) return key | (unsigned char) str[0]; if (y_strnicmp(str, "F", 1) == 0 && isdigit(str[1])) return key | (FL_F + atoi(str + 1)); if (y_strnicmp(str, "MOUSE", 5) == 0 && isdigit(str[5])) return key | (FL_Button + atoi(str + 5)); // find name in mapping table for (int k = 0 ; key_map[k].name ; k++) if (y_stricmp(str, key_map[k].name) == 0) return key | key_map[k].key; if (y_strnicmp(str, "KP_", 3) == 0 && 33 < str[3] && (FL_KP + str[3]) <= FL_KP_Last) return key | (FL_KP + str[3]); if (str[0] == '0' && str[1] == 'x') return key | (int)strtol(str, NULL, 0); return 0; } static const char * BareKeyName(keycode_t key) { static char buffer[200]; if (key < 127 && key > 32 && isprint(key)) { buffer[0] = (char) key; buffer[1] = 0; return buffer; } if (FL_F < key && key <= FL_F_Last) { sprintf(buffer, "F%d", key - FL_F); return buffer; } if (FL_Button < key && key <= FL_Button + 20) { sprintf(buffer, "MOUSE%d", key - FL_Button); return buffer; } // find key in mapping table for (int k = 0 ; key_map[k].name ; k++) if (key == key_map[k].key) return key_map[k].name; if (FL_KP + 33 <= key && key <= FL_KP_Last) { sprintf(buffer, "KP_%c", (char)(key & 127)); return buffer; } // fallback : hex code sprintf(buffer, "0x%04x", key); return buffer; } static const char *ModName(keycode_t mod) { if (mod & MOD_COMMAND) return "CMD-"; if (mod & MOD_META) return "META-"; if (mod & MOD_ALT) return "ALT-"; if (mod & MOD_SHIFT) return "SHIFT-"; return ""; } const char * M_KeyToString(keycode_t key) { static char buffer[200]; strcpy(buffer, ModName(key)); strcat(buffer, BareKeyName(key & FL_KEY_MASK)); return buffer; } int M_KeyCmp(keycode_t A, keycode_t B) { keycode_t A_mod = A & MOD_ALL_MASK; keycode_t B_mod = B & MOD_ALL_MASK; A &= FL_KEY_MASK; B &= FL_KEY_MASK; // make mouse buttons separate from everything else if ((A >= FL_Button && A <= FL_Button + 20) || A == FL_WheelUp || A == FL_WheelDn) A += 0x10000; if ((B >= FL_Button && B <= FL_Button + 20) || B == FL_WheelUp || B == FL_WheelDn) B += 0x10000; // we want lower- and uppercase of a key together (e.g. a + A) if (A < 256 && isupper(A)) { A = tolower(A); A_mod |= MOD_SHIFT; } if (B < 256 && isupper(B)) { B = tolower(B); B_mod |= MOD_SHIFT; } // base key is most important if (A != B) return (int)A - (int)B; // modifiers are the least important return (int)A_mod - (int)B_mod; } //------------------------------------------------------------------------ key_context_e M_ParseKeyContext(const char *str) { if (y_stricmp(str, "browser") == 0) return KCTX_Browser; if (y_stricmp(str, "render") == 0) return KCTX_Render; if (y_stricmp(str, "general") == 0) return KCTX_General; if (y_stricmp(str, "line") == 0) return KCTX_Line; if (y_stricmp(str, "sector") == 0) return KCTX_Sector; if (y_stricmp(str, "thing") == 0) return KCTX_Thing; if (y_stricmp(str, "vertex") == 0) return KCTX_Vertex; // TEMPORARY for compatibility if (y_stricmp(str, "global") == 0) return KCTX_General; return KCTX_NONE; } const char * M_KeyContextString(key_context_e context) { switch (context) { case KCTX_Browser: return "browser"; case KCTX_Render: return "render"; case KCTX_General: return "general"; case KCTX_Line: return "line"; case KCTX_Sector: return "sector"; case KCTX_Thing: return "thing"; case KCTX_Vertex: return "vertex"; default: break; } return "INVALID"; } //------------------------------------------------------------------------ #define MAX_BIND_LENGTH 32 typedef struct { keycode_t key; key_context_e context; const editor_command_t *cmd; char param[MAX_EXEC_PARAM][MAX_BIND_LENGTH]; // this field ONLY used by M_DetectConflictingBinds() bool is_duplicate; } key_binding_t; static std::vector all_bindings; static std::vector install_binds; void M_RemoveBinding(keycode_t key, key_context_e context) { std::vector::iterator IT; for (IT = all_bindings.begin() ; IT != all_bindings.end() ; IT++) { if (IT->key == key && IT->context == context) { // found it all_bindings.erase(IT); // there should never be more than one // (besides, our iterator is now invalid) return; } } } static void ParseKeyBinding(const char ** tokens, int num_tok) { key_binding_t temp; // this ensures all parameters are NUL terminated memset(&temp, 0, sizeof(temp)); temp.key = M_ParseKeyString(tokens[1]); if (! temp.key) { LogPrintf("bindings.cfg: cannot parse key name: %s\n", tokens[1]); return; } temp.context = M_ParseKeyContext(tokens[0]); if (temp.context == KCTX_NONE) { LogPrintf("bindings.cfg: unknown context: %s\n", tokens[0]); return; } // handle un-bound keys if (y_stricmp(tokens[2], "UNBOUND") == 0) { #if 0 fprintf(stderr, "REMOVED BINDING key:%04x (%s)\n", temp.key, tokens[0]); #endif M_RemoveBinding(temp.key, temp.context); return; } temp.cmd = FindEditorCommand(tokens[2]); if (! temp.cmd) { LogPrintf("bindings.cfg: unknown function: %s\n", tokens[2]); return; } if (temp.cmd->req_context != KCTX_NONE && temp.context != temp.cmd->req_context) { LogPrintf("bindings.cfg: function '%s' in wrong context '%s'\n", tokens[2], tokens[0]); return; } for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) if (num_tok >= 4 + p) strncpy(temp.param[p], tokens[3 + p], MAX_BIND_LENGTH-1); #if 0 // DEBUG fprintf(stderr, "ADDED BINDING key:%04x --> %s\n", temp.key, tokens[2]); #endif M_RemoveBinding(temp.key, temp.context); all_bindings.push_back(temp); } #define MAX_TOKENS (MAX_EXEC_PARAM + 8) static bool LoadBindingsFromPath(const char *path, bool required) { static char filename[FL_PATH_MAX]; sprintf(filename, "%s/bindings.cfg", path); FILE *fp = fopen(filename, "r"); if (! fp) { if (! required) return false; FatalError("Missing key bindings file:\n\n%s\n", filename); } LogPrintf("Reading key bindings from: %s\n", filename); static char line_buf[FL_PATH_MAX]; const char * tokens[MAX_TOKENS]; while (! feof(fp)) { char *line = fgets(line_buf, FL_PATH_MAX, fp); if (! line) break; StringRemoveCRLF(line); int num_tok = M_ParseLine(line, tokens, MAX_TOKENS, false /* do_strings */); if (num_tok == 0) continue; if (num_tok < 3) { LogPrintf("Syntax error in bindings: %s\n", line); continue; } ParseKeyBinding(tokens, num_tok); } fclose(fp); return true; } static void CopyInstallBindings() { install_binds.clear(); for (unsigned int i = 0 ; i < all_bindings.size() ; i++) { install_binds.push_back(all_bindings[i]); } } static bool BindingExists(std::vector& list, key_binding_t& bind, bool full_match) { for (unsigned int i = 0 ; i < list.size() ; i++) { key_binding_t& other = list[i]; if (bind.key != other.key) continue; if (bind.context != other.context) continue; if (! full_match) return true; if (bind.cmd != other.cmd) continue; bool same_params = true; for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { if (strcmp(bind.param[p], other.param[p]) != 0) { same_params = false; break; } } if (same_params) return true; } return false; } void M_LoadBindings() { all_bindings.clear(); LoadBindingsFromPath(install_dir, true /* required */); // keep a copy of the install_dir bindings CopyInstallBindings(); LoadBindingsFromPath(home_dir, false); } void M_SaveBindings() { static char filename[FL_PATH_MAX]; sprintf(filename, "%s/bindings.cfg", home_dir); FILE *fp = fopen(filename, "w"); if (! fp) { LogPrintf("Failed to save key bindings to: %s\n", filename); DLG_Notify("Warning: failed to save key bindings\n" "(filename: %s)", filename); return; } LogPrintf("Writing key bindings to: %s\n", filename); fprintf(fp, "# Eureka key bindings (local)\n"); fprintf(fp, "# vi:ts=16:noexpandtab\n\n"); for (int ctx = KCTX_Browser ; ctx <= KCTX_General ; ctx++) { int count = 0; for (unsigned int i = 0 ; i < all_bindings.size() ; i++) { key_binding_t& bind = all_bindings[i]; if (bind.context != (key_context_e)ctx) continue; // no need to write it if unchanged from install_dir if (BindingExists(install_binds, bind, true /* full match */)) continue; fprintf(fp, "%s\t%s\t%s", M_KeyContextString(bind.context), M_KeyToString(bind.key), bind.cmd->name); for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { if (bind.param[p][0]) fprintf(fp, "\t%s", bind.param[p]); } fprintf(fp, "\n"); count++; } // find un-bound keys (relative to installation) for (unsigned int i = 0 ; i < install_binds.size() ; i++) { key_binding_t& bind = install_binds[i]; if (bind.context != ctx) continue; if (! BindingExists(all_bindings, bind, false /* full match */)) { fprintf(fp, "%s\t%s\t%s\n", M_KeyContextString(bind.context), M_KeyToString(bind.key), "UNBOUND"); count++; } } if (count > 0) fprintf(fp, "\n"); } fclose(fp); } //------------------------------------------------------------------------ // PREFERENCE DIALOG STUFF //------------------------------------------------------------------------ // local copy of the bindings // these only become live after M_ApplyBindings() static std::vector pref_binds; void M_CopyBindings(bool from_defaults) { // returns # of bindings pref_binds.clear(); if (from_defaults) { for (unsigned int i = 0 ; i < install_binds.size() ; i++) pref_binds.push_back(install_binds[i]); } else { for (unsigned int i = 0 ; i < all_bindings.size() ; i++) pref_binds.push_back(all_bindings[i]); } } void M_ApplyBindings() { all_bindings.clear(); for (unsigned int i = 0 ; i < pref_binds.size() ; i++) all_bindings.push_back(pref_binds[i]); } int M_NumBindings() { return (int)pref_binds.size(); } struct KeyBind_CMP_pred { private: char column; public: KeyBind_CMP_pred(char _col) : column(_col) { } inline bool operator() (const key_binding_t& k1, const key_binding_t& k2) const { if (column == 'c' && k1.context != k2.context) return k1.context > k2.context; if (column != 'f' && k1.key != k2.key) return M_KeyCmp(k1.key, k2.key) < 0; /// if (column == 'k' && k1.context != k2.context) /// return k1.context > k2.context; if (k1.cmd != k2.cmd) return y_stricmp(k1.cmd->name, k2.cmd->name) < 0; for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { int cmp = y_stricmp(k1.param[p], k2.param[p]); if (cmp != 0) return cmp < 0; } if (column == 'f' && k1.key != k2.key) return M_KeyCmp(k1.key, k2.key) < 0; return k1.context < k2.context; } }; void M_SortBindings(char column, bool reverse) { std::sort(pref_binds.begin(), pref_binds.end(), KeyBind_CMP_pred(column)); if (reverse) std::reverse(pref_binds.begin(), pref_binds.end()); } void M_DetectConflictingBinds() { // copy the local bindings and sort them. // duplicate bindings will be contiguous in the list. std::vector list; for (unsigned int i = 0 ; i < pref_binds.size() ; i++) { pref_binds[i].is_duplicate = false; list.push_back(pref_binds[i]); } std::sort(list.begin(), list.end(), KeyBind_CMP_pred('c')); for (unsigned int k = 0 ; k + 1 < list.size() ; k++) { if (! (list[k].key == list[k+1].key && list[k].context == list[k+1].context)) continue; // mark these in the local bindings for (unsigned int n = 0 ; n < pref_binds.size() ; n++) { if (pref_binds[n].key == list[k].key && pref_binds[n].context == list[k].context) { pref_binds[n].is_duplicate = true; } } } } const char * M_StringForFunc(int index) { static char buffer[300]; key_binding_t& bind = pref_binds[index]; strcpy(buffer, bind.cmd->name); // add the parameters char *pos = buffer; for (int k = 0 ; k < MAX_EXEC_PARAM ; k++) { const char *param = bind.param[k]; if (! param[0]) break; pos = buffer + strlen(buffer); if (k == 0) *pos++ = ':'; *pos++ = ' '; sprintf(pos, "%.30s", param); } return buffer; } const char * M_StringForBinding(int index, bool changing_key) { SYS_ASSERT(index < (int)pref_binds.size()); key_binding_t& bind = pref_binds[index]; static char buffer[600]; sprintf(buffer, "%s%6.6s%-9.9s %-10.10s %.30s", bind.is_duplicate ? "@C1" : "", changing_key ? "" : BareKeyName(bind.key & FL_KEY_MASK), M_KeyContextString(bind.context), M_StringForFunc(index) ); return buffer; } void M_GetBindingInfo(int index, keycode_t *key, key_context_e *context) { // hmmm... exposing key_binding_t may have been easier... *key = pref_binds[index].key; *context = pref_binds[index].context; } void M_ChangeBindingKey(int index, keycode_t key) { SYS_ASSERT(0 <= index && index < (int)pref_binds.size()); SYS_ASSERT(key != 0); pref_binds[index].key = key; } static const char * DoParseBindingFunc(key_binding_t& bind, const char * func_str) { static char error_msg[1024]; // convert the brackets and commas into spaces and use the // line tokeniser. static char buffer[600]; strncpy(buffer, func_str, sizeof(buffer)); buffer[sizeof(buffer) - 1] = 0; for (unsigned int k = 0 ; buffer[k] ; k++) if (buffer[k] == ',' || buffer[k] == ':') buffer[k] = ' '; const char * tokens[MAX_TOKENS]; int num_tok = M_ParseLine(buffer, tokens, MAX_TOKENS, false /* do_strings */); if (num_tok == 0) return "Missing function name"; const editor_command_t * cmd = FindEditorCommand(tokens[0]); if (! cmd) { sprintf(error_msg, "Unknown function name: %s", tokens[0]); return error_msg; } // check context is suitable if (cmd->req_context != KCTX_NONE && bind.context != cmd->req_context) { char *mode = StringUpper(M_KeyContextString(cmd->req_context)); sprintf(error_msg, "%s can only be used in %s mode", tokens[0], mode); StringFree(mode); return error_msg; } /* OK : change the binding function */ bind.cmd = cmd; memset(&bind.param, 0, sizeof(bind.param)); for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) if (num_tok >= 2 + p) strncpy(bind.param[p], tokens[1 + p], MAX_BIND_LENGTH-1); return NULL; } bool M_IsBindingFuncValid(key_context_e context, const char * func_str) { key_binding_t temp; temp.key = 'a'; // dummy key temp.context = context; return (DoParseBindingFunc(temp, func_str) == NULL); } // returns an error message, or NULL if OK const char * M_SetLocalBinding(int index, keycode_t key, key_context_e context, const char *func_str) { SYS_ASSERT(0 <= index && index < (int)pref_binds.size()); pref_binds[index].key = key; pref_binds[index].context = context; const char *err_msg = DoParseBindingFunc(pref_binds[index], func_str); return err_msg; } const char * M_AddLocalBinding(int after, keycode_t key, key_context_e context, const char *func_str) { key_binding_t temp; // this ensures the parameters are NUL terminated memset(&temp, 0, sizeof(temp)); temp.key = key; temp.context = context; const char *err_msg = DoParseBindingFunc(temp, func_str); if (err_msg) return err_msg; if (after < 0) pref_binds.push_back(temp); else pref_binds.insert(pref_binds.begin() + (1 + after), temp); return NULL; // OK } void M_DeleteLocalBinding(int index) { SYS_ASSERT(0 <= index && index < (int)pref_binds.size()); pref_binds.erase(pref_binds.begin() + index); } //------------------------------------------------------------------------ // COMMAND EXECUTION STUFF //------------------------------------------------------------------------ keycode_t M_TranslateKey(int key, int state) { // ignore modifier keys themselves switch (key) { case FL_Num_Lock: case FL_Caps_Lock: case FL_Shift_L: case FL_Control_L: case FL_Shift_R: case FL_Control_R: case FL_Meta_L: case FL_Alt_L: case FL_Meta_R: case FL_Alt_R: return 0; } if (key == '\t') key = FL_Tab; if (key == '\b') key = FL_BackSpace; // modifier logic -- only allow a single one if (state & MOD_COMMAND) key |= MOD_COMMAND; else if (state & MOD_META) key |= MOD_META; else if (state & MOD_ALT) key |= MOD_ALT; else if (state & MOD_SHIFT) { // Note: SHIFT + digit is kept that way (rather than get '!', '@' etc) if (key < 127 && isalpha(key)) key = toupper(key); else if (key < 127 && ispunct(key) && strlen(Fl::event_text()) == 1) key = Fl::event_text()[0]; else key |= MOD_SHIFT; } return key; } key_context_e M_ModeToKeyContext(obj_type_e mode) { switch (mode) { case OBJ_THINGS: return KCTX_Thing; case OBJ_LINEDEFS: return KCTX_Line; case OBJ_SECTORS: return KCTX_Sector; case OBJ_VERTICES: return KCTX_Vertex; default: break; } return KCTX_NONE; /* shouldn't happen */ } bool Exec_HasFlag(const char *flag) { // the parameter should include a leading '/' for (int i = 0 ; i < MAX_EXEC_PARAM ; i++) { if (! EXEC_Flags[i][0]) break; if (y_stricmp(EXEC_Flags[i], flag) == 0) return true; } return false; } static void DoExecuteCommand(const editor_command_t *cmd) { (* cmd->func)(); } bool ExecuteKey(keycode_t key, key_context_e context) { Status_Clear(); for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { EXEC_Param[p] = ""; EXEC_Flags[p] = ""; } EXEC_Errno = 0; for (unsigned int i = 0 ; i < all_bindings.size() ; i++) { key_binding_t& bind = all_bindings[i]; if (bind.key == key && bind.context == context) { int p_idx = 0; int f_idx = 0; for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { if (! bind.param[p][0]) break; // separate flags from normal parameters if (bind.param[p][0] == '/') EXEC_Flags[f_idx++] = bind.param[p]; else EXEC_Param[p_idx++] = bind.param[p]; } DoExecuteCommand(bind.cmd); return true; } } return false; } bool ExecuteCommand(const char *name, const char *param1, const char *param2, const char *param3) { const editor_command_t * cmd = FindEditorCommand(name); if (! cmd) return false; Status_Clear(); for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { EXEC_Param[p] = ""; EXEC_Flags[p] = ""; } EXEC_Param[0] = param1; EXEC_Param[1] = param2; EXEC_Param[2] = param3; EXEC_Errno = 0; DoExecuteCommand(cmd); return true; } /* * play a fascinating tune */ void Beep(const char *fmt, ...) { va_list arg_ptr; static char buffer[MSG_BUF_LEN]; va_start(arg_ptr, fmt); vsnprintf(buffer, MSG_BUF_LEN-1, fmt, arg_ptr); va_end(arg_ptr); buffer[MSG_BUF_LEN-1] = 0; if (buffer[0]) { Status_Set("%s", buffer); LogPrintf("BEEP: %s\n", buffer); } else Status_Set("Problem occurred"); EXEC_Errno = 1; fl_beep(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_canvas.cc0000644000175100017510000011165312651540406016546 0ustar aaptedaapted//------------------------------------------------------------------------ // EDITING CANVAS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2016 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 "main.h" #include "ui_window.h" #include "editloop.h" #include "e_sector.h" #include "e_things.h" #include "m_game.h" #include "r_grid.h" #include "im_color.h" #include "im_img.h" #include "levels.h" #include "r_render.h" #include "w_flats.h" #include #define CAMERA_COLOR fl_rgb_color(255, 192, 255) extern int active_when; extern int active_wmask; // config items rgb_color_t dotty_axis_col = RGB_MAKE(0, 128, 255); rgb_color_t dotty_major_col = RGB_MAKE(0, 0, 238); rgb_color_t dotty_minor_col = RGB_MAKE(0, 0, 187); rgb_color_t dotty_point_col = RGB_MAKE(0, 0, 255); rgb_color_t normal_axis_col = RGB_MAKE(0, 128, 255); rgb_color_t normal_main_col = RGB_MAKE(0, 0, 238); rgb_color_t normal_flat_col = RGB_MAKE(84, 96, 48); rgb_color_t normal_small_col = RGB_MAKE(60, 60, 120); int vertex_radius(double scale); // // UI_Canvas Constructor // UI_Canvas::UI_Canvas(int X, int Y, int W, int H, const char *label) : Fl_Widget(X, Y, W, H, label), highlight(), split_ld(-1), drag_lines(), scale_lines(), seen_sectors() { } // // UI_Canvas Destructor // UI_Canvas::~UI_Canvas() { } void UI_Canvas::resize(int X, int Y, int W, int H) { Fl_Widget::resize(X, Y, W, H); } void UI_Canvas::draw() { fl_push_clip(x(), y(), w(), h()); fl_color(FL_WHITE); // default font (for showing object numbers) int font_size = (grid.Scale < 0.4) ? 10 : (grid.Scale < 1.9) ? 14 : 18; fl_font(FL_COURIER, font_size); DrawEverything(); fl_pop_clip(); } int UI_Canvas::handle(int event) { //// fprintf(stderr, "HANDLE EVENT %d\n", event); switch (event) { case FL_FOCUS: return 1; case FL_ENTER: // we greedily grab the focus if (Fl::focus() != this) take_focus(); return 1; case FL_LEAVE: Editor_LeaveWindow(); redraw(); return 1; case FL_KEYDOWN: case FL_KEYUP: case FL_SHORTCUT: return Editor_RawKey(event); case FL_PUSH: case FL_RELEASE: return Editor_RawButton(event); case FL_MOUSEWHEEL: return Editor_RawWheel(event); case FL_DRAG: case FL_MOVE: return Editor_RawMouse(event); default: break; } return Fl_Widget::handle(event); } void UI_Canvas::PointerPos(int *map_x, int *map_y) { *map_x = MAPX(Fl::event_x()); *map_y = MAPY(Fl::event_y()); } int UI_Canvas::ApproxBoxSize(int mx1, int my1, int mx2, int my2) { if (mx2 < mx1) std::swap(mx1, mx2); if (my2 < my1) std::swap(my1, my2); int x1 = SCREENX(mx1); int x2 = SCREENX(mx2); int y1 = SCREENY(my2); int y2 = SCREENY(my1); if (x1 < 8 || x2 > w() - 8 || y1 < 8 || y2 > h() - 8) return 1; // too big float x_ratio = MAX(4, x2 - x1) / (float) MAX(4, w()); float y_ratio = MAX(4, y2 - y1) / (float) MAX(4, h()); if (MAX(x_ratio, y_ratio) < 0.25) return -1; // too small return 0; } //------------------------------------------------------------------------ void UI_Canvas::DrawEverything() { map_lx = MAPX(x()); map_ly = MAPY(y()+h()); map_hx = MAPX(x()+w()); map_hy = MAPY(y()); // setup for drawing sector numbers if (edit.show_object_numbers && edit.mode == OBJ_SECTORS) { seen_sectors.clear_all(); } DrawMap(); DrawSelection(edit.Selected); if (edit.action == ACT_DRAG && ! drag_lines.empty()) DrawSelection(&drag_lines); else if (edit.action == ACT_SCALE && ! scale_lines.empty()) DrawSelection(&scale_lines); if (highlight.valid()) { Fl_Color hi_color = HI_COL; if (edit.Selected->get(highlight.num)) hi_color = HI_AND_SEL_COL; DrawHighlight(highlight.type, highlight.num, hi_color, ! edit.error_mode /* do_tagged */); } if (edit.action == ACT_SELBOX) SelboxDraw(); if (edit.action == ACT_DRAW_LINE) DrawCurrentLine(); } /* draw the actual game map */ void UI_Canvas::DrawMap() { fl_color(FL_BLACK); fl_rectf(x(), y(), w(), h()); if (edit.sector_render_mode && (! grid.shown || grid.mode == 0)) { for (int n = 0 ; n < NumSectors ; n++) RenderSector(n); } // draw the grid first since it's in the background if (grid.shown) { if (grid.mode == 0) DrawGrid_Dotty(); else DrawGrid_Normal(); } if (Debugging) DrawMapBounds(); DrawCamera(); if (edit.mode != OBJ_THINGS) DrawThings(); DrawLinedefs(); if (edit.mode == OBJ_VERTICES) DrawVertices(); if (edit.mode == OBJ_THINGS) { DrawThingBodies(); DrawThings(); } } /* * draw_grid - draw the grid in the background of the edit window */ void UI_Canvas::DrawGrid_Normal() { float pixels_1 = grid.step * grid.Scale; if (pixels_1 < 1.6) { fl_color(DarkerColor(DarkerColor(normal_main_col))); fl_rectf(x(), y(), w(), h()); DrawAxes(normal_axis_col); return; } int flat_step = 64; float pixels_2 = flat_step * grid.Scale; Fl_Color flat_col = (grid.step < 64) ? normal_main_col : normal_flat_col; if (pixels_2 < 2.2) flat_col = DarkerColor(flat_col); fl_color(flat_col); if (pixels_2 < 1.6) { fl_rectf(x(), y(), w(), h()); } else { int gx = (map_lx / flat_step) * flat_step; for (; gx <= map_hx; gx += flat_step) DrawMapLine(gx, map_ly, gx, map_hy); int gy = (map_ly / flat_step) * flat_step; for (; gy <= map_hy; gy += flat_step) DrawMapLine(map_lx, gy, map_hx, gy); } Fl_Color main_col = (grid.step < 64) ? normal_small_col : normal_main_col; float pixels_3 = grid.step * grid.Scale; if (pixels_3 < 4.2) main_col = DarkerColor(main_col); fl_color(main_col); { int gx = (map_lx / grid.step) * grid.step; for (; gx <= map_hx; gx += grid.step) if ((grid.step >= 64 || (gx & 63) != 0) && (gx != 0)) DrawMapLine(gx, map_ly, gx, map_hy); int gy = (map_ly / grid.step) * grid.step; for (; gy <= map_hy; gy += grid.step) if ((grid.step >= 64 || (gy & 63) != 0) && (gy != 0)) DrawMapLine(map_lx, gy, map_hx, gy); } DrawAxes(normal_axis_col); } void UI_Canvas::DrawGrid_Dotty() { int grid_step_1 = 1 * grid.step; // Map units between dots int grid_step_2 = 8 * grid_step_1; // Map units between dim lines int grid_step_3 = 8 * grid_step_2; // Map units between bright lines float pixels_1 = grid.step * grid.Scale; if (pixels_1 < 1.6) { fl_color(DarkerColor(DarkerColor(dotty_point_col))); fl_rectf(x(), y(), w(), h()); DrawAxes(dotty_axis_col); return; } fl_color(dotty_major_col); { int gx = (map_lx / grid_step_3) * grid_step_3; for (; gx <= map_hx; gx += grid_step_3) DrawMapLine(gx, map_ly-2, gx, map_hy+2); int gy = (map_ly / grid_step_3) * grid_step_3; for (; gy <= map_hy; gy += grid_step_3) DrawMapLine(map_lx, gy, map_hx, gy); } DrawAxes(dotty_axis_col); fl_color(dotty_minor_col); { int gx = (map_lx / grid_step_2) * grid_step_2; for (; gx <= map_hx; gx += grid_step_2) if (gx % grid_step_3 != 0) DrawMapLine(gx, map_ly, gx, map_hy); int gy = (map_ly / grid_step_2) * grid_step_2; for (; gy <= map_hy; gy += grid_step_2) if (gy % grid_step_3 != 0) DrawMapLine(map_lx, gy, map_hx, gy); } if (pixels_1 < 4.02) fl_color(DarkerColor(dotty_point_col)); else fl_color(dotty_point_col); { int gx = (map_lx / grid_step_1) * grid_step_1; int gy = (map_ly / grid_step_1) * grid_step_1; for (int ny = gy; ny <= map_hy; ny += grid_step_1) for (int nx = gx; nx <= map_hx; nx += grid_step_1) { int sx = SCREENX(nx); int sy = SCREENY(ny); if (pixels_1 < 24.1) fl_point(sx, sy); else { fl_rectf(sx, sy, 2, 2); // fl_line(sx-0, sy, sx+1, sy); // fl_line(sx, sy-0, sx, sy+1); } } } } void UI_Canvas::DrawAxes(Fl_Color col) { fl_color(col); DrawMapLine(0, map_ly, 0, map_hy); DrawMapLine(map_lx, 0, map_hx, 0); } void UI_Canvas::DrawMapBounds() { fl_color(FL_RED); DrawMapLine(Map_bound_x1, Map_bound_y1, Map_bound_x2, Map_bound_y1); DrawMapLine(Map_bound_x1, Map_bound_y2, Map_bound_x2, Map_bound_y2); DrawMapLine(Map_bound_x1, Map_bound_y1, Map_bound_x1, Map_bound_y2); DrawMapLine(Map_bound_x2, Map_bound_y1, Map_bound_x2, Map_bound_y2); } /* * vertex_radius - apparent radius of a vertex, in pixels */ int vertex_radius(double scale) { int r = 6 * (0.26 + scale / 2); if (r > 12) r = 12; return r; } /* * draw_vertices - draw the vertices, and possibly their numbers */ void UI_Canvas::DrawVertex(int map_x, int map_y, int r) { int scrx = SCREENX(map_x); int scry = SCREENY(map_y); // BLOBBY TEST #if 0 fl_line(scrx - 1, scry - 2, scrx + 1, scry - 2); fl_line(scrx - 2, scry - 1, scrx + 2, scry - 1); fl_line(scrx - 2, scry + 0, scrx + 2, scry + 0); fl_line(scrx - 2, scry + 1, scrx + 2, scry + 1); fl_line(scrx - 1, scry + 2, scrx + 1, scry + 2); #else fl_line(scrx - r, scry - r, scrx + r, scry + r); fl_line(scrx + r, scry - r, scrx - r, scry + r); fl_line(scrx - 1, scry, scrx + 1, scry); fl_line(scrx, scry - 1, scrx, scry + 1); #endif } void UI_Canvas::DrawVertices() { const int r = vertex_radius(grid.Scale); fl_color(FL_GREEN); for (int n = 0 ; n < NumVertices ; n++) { int x = Vertices[n]->x; int y = Vertices[n]->y; if (Vis(x, y, r)) { DrawVertex(x, y, r); } } if (edit.show_object_numbers) { for (int n = 0 ; n < NumVertices ; n++) { int x = Vertices[n]->x; int y = Vertices[n]->y; if (! Vis(x, y, r)) continue; int sx = SCREENX(x) + r; int sy = SCREENY(y) - r - 2; DrawObjNum(sx, sy, n); } } } /* * draw_linedefs - draw the linedefs */ void UI_Canvas::DrawLinedefs() { for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; int x1 = L->Start()->x; int y1 = L->Start()->y; int x2 = L->End ()->x; int y2 = L->End ()->y; if (! Vis(MIN(x1,x2), MIN(y1,y2), MAX(x1,x2), MAX(y1,y2))) continue; bool one_sided = (! L->Left()); switch (edit.mode) { case OBJ_VERTICES: { if (n == split_ld) fl_color(HI_AND_SEL_COL); else if (edit.error_mode) fl_color(LIGHTGREY); else if (L->right < 0) fl_color(RED); else if (one_sided) fl_color(WHITE); else fl_color(LIGHTGREY); if (n == split_ld) DrawSplitLine(x1, y1, x2, y2); else DrawKnobbyLine(x1, y1, x2, y2); if (n >= (NumLineDefs - 3) && ! edit.show_object_numbers) { DrawLineNumber(x1, y1, x2, y2, 0, I_ROUND(L->CalcLength())); } } break; case OBJ_LINEDEFS: { if (edit.error_mode) fl_color(LIGHTGREY); // no first sidedef? else if (! L->Right()) fl_color(RED); else if (L->type != 0) { if (L->tag != 0) fl_color(LIGHTMAGENTA); else fl_color(LIGHTGREEN); } else if (one_sided) fl_color(WHITE); else if (L->flags & 1) fl_color(FL_CYAN); else fl_color(LIGHTGREY); DrawKnobbyLine(x1, y1, x2, y2); } break; case OBJ_SECTORS: { int sd1 = L->right; int sd2 = L->left; int s1 = (sd1 < 0) ? NIL_OBJ : SideDefs[sd1]->sector; int s2 = (sd2 < 0) ? NIL_OBJ : SideDefs[sd2]->sector; if (edit.error_mode) fl_color(LIGHTGREY); else if (sd1 < 0) fl_color(RED); else { bool have_tag = false; bool have_type = false; if (Sectors[s1]->tag != 0) have_tag = true; if (Sectors[s1]->type != 0) have_type = true; if (s2 >= 0) { if (Sectors[s2]->tag != 0) have_tag = true; if (Sectors[s2]->type != 0) have_type = true; } if (have_tag && have_type) fl_color(SECTOR_TAGTYPE); else if (have_tag) fl_color(SECTOR_TAG); else if (have_type) fl_color(SECTOR_TYPE); else if (one_sided) fl_color(WHITE); else fl_color(LIGHTGREY); } DrawMapLine(x1, y1, x2, y2); if (edit.show_object_numbers) { if (s1 != NIL_OBJ) DrawSectorNum(x1, y1, x2, y2, SIDE_RIGHT, s1); if (s2 != NIL_OBJ) DrawSectorNum(x1, y1, x2, y2, SIDE_LEFT, s2); } } break; // OBJ_THINGS default: { if (one_sided && ! edit.error_mode) fl_color(WHITE); else fl_color(LIGHTGREY); DrawMapLine(x1, y1, x2, y2); } break; } } // draw the linedef numbers if (edit.mode == OBJ_LINEDEFS && edit.show_object_numbers) { for (int n = 0 ; n < NumLineDefs ; n++) { int x1 = LineDefs[n]->Start()->x; int y1 = LineDefs[n]->Start()->y; int x2 = LineDefs[n]->End ()->x; int y2 = LineDefs[n]->End ()->y; if (! Vis(MIN(x1,x2), MIN(y1,y2), MAX(x1,x2), MAX(y1,y2))) continue; DrawLineNumber(x1, y1, x2, y2, 0, n); } } } void UI_Canvas::DrawThing(int x, int y, int r, int angle, bool big_arrow) { DrawMapLine(x-r, y-r, x-r, y+r); DrawMapLine(x-r, y+r, x+r, y+r); DrawMapLine(x+r, y+r, x+r, y-r); DrawMapLine(x+r, y-r, x-r, y-r); if (big_arrow) { DrawMapArrow(x, y, r * 2, angle); } else { int dir = angle_to_direction(angle); static const short xsign[] = { 1, 1, 0, -1, -1, -1, 0, 1, 0 }; static const short ysign[] = { 0, 1, 1, 1, 0, -1, -1, -1, 0 }; int corner_x = r * xsign[dir]; int corner_y = r * ysign[dir]; DrawMapLine(x, y, x + corner_x, y + corner_y); } } /* * draw_things_squares - the obvious */ void UI_Canvas::DrawThings() { fl_color(DARKGREY); for (int n = 0 ; n < NumThings ; n++) { int x = Things[n]->x; int y = Things[n]->y; if (! Vis(x, y, MAX_RADIUS)) continue; const thingtype_t *info = M_GetThingType(Things[n]->type); if (edit.mode == OBJ_THINGS) { if (edit.error_mode) { fl_color(LIGHTGREY); } else if (active_wmask) { if (Things[n]->options & 1) fl_color (YELLOW); else if (Things[n]->options & 2) fl_color (LIGHTGREEN); else if (Things[n]->options & 4) fl_color (LIGHTRED); else fl_color (DARKGREY); } else fl_color((Fl_Color) info->color); } int r = info->radius; DrawThing(x, y, r, Things[n]->angle, false); } // draw the thing numbers if (edit.mode == OBJ_THINGS && edit.show_object_numbers) { for (int n = 0 ; n < NumThings ; n++) { int x = Things[n]->x; int y = Things[n]->y; if (! Vis(x, y, MAX_RADIUS)) continue; const thingtype_t *info = M_GetThingType(Things[n]->type); x += info->radius; y += info->radius; DrawObjNum(SCREENX(x), SCREENY(y) - 2, n); } } } void UI_Canvas::DrawThingBodies() { if (edit.error_mode) return; for (int n = 0 ; n < NumThings ; n++) { int x = Things[n]->x; int y = Things[n]->y; if (! Vis(x, y, MAX_RADIUS)) continue; const thingtype_t *info = M_GetThingType(Things[n]->type); int r = info->radius; fl_color(DarkerColor(DarkerColor(info->color))); int sx1 = SCREENX(x - r); int sy1 = SCREENY(y + r); int sx2 = SCREENX(x + r); int sy2 = SCREENY(y - r); fl_rectf(sx1, sy1, sx2 - sx1 + 1, sy2 - sy1 + 1); } } void UI_Canvas::DrawSectorNum(int mx1, int my1, int mx2, int my2, int side, int n) { // only draw a number for the first linedef actually visible if (seen_sectors.get(n)) return; seen_sectors.set(n); DrawLineNumber(mx1, my1, mx2, my2, side, n); } void UI_Canvas::DrawLineNumber(int mx1, int my1, int mx2, int my2, int side, int n) { int x1 = SCREENX(mx1); int y1 = SCREENY(my1); int x2 = SCREENX(mx2); int y2 = SCREENY(my2); int mx = (x1 + x2) / 2; int my = (y1 + y2) / 2 - 1; int dx = (y1 - y2); int dy = (x2 - x1); if (side == SIDE_LEFT) { dx = -dx; dy = -dy; } if (side) { int len = MAX(4, MAX(abs(dx), abs(dy))); int want_len = 4 + 10 * CLAMP(0.25, grid.Scale, 1.0); mx += dx * want_len / len; my += dy * want_len / len; if (abs(dx) > abs(dy)) { want_len = 2 + want_len / 2; if (dx > 0) mx += want_len; else mx -= want_len; } } DrawObjNum(mx, my + fl_descent(), n, true /* center */); } /* * draw_obj_no - draw a number at screen coordinates (x, y) */ void UI_Canvas::DrawObjNum(int x, int y, int num, bool center) { char buffer[64]; sprintf(buffer, "%d", num); if (center) { #if 0 /* DEBUG */ fl_color(FL_RED); fl_rectf(x - 1, y - 1, 3, 3); return; #endif x -= fl_width(buffer) / 2; y += fl_descent(); } fl_color(FL_BLACK); fl_draw(buffer, x - 2, y); fl_draw(buffer, x - 1, y); fl_draw(buffer, x + 1, y); fl_draw(buffer, x + 2, y); fl_draw(buffer, x, y + 1); fl_draw(buffer, x, y - 1); fl_color(OBJECT_NUM_COL); fl_draw(buffer, x, y); } void UI_Canvas::HighlightSet(Objid& obj) { if (highlight == obj) return; highlight = obj; redraw(); } void UI_Canvas::HighlightForget() { if (highlight.is_nil()) return; highlight.clear(); redraw(); } void UI_Canvas::SplitLineSet(int ld, int new_x, int new_y) { if (split_ld == ld && split_x == new_x && split_y == new_y) return; split_ld = ld; split_x = new_x; split_y = new_y; redraw(); } void UI_Canvas::SplitLineForget() { if (split_ld < 0) return; split_ld = -1; redraw(); } /* highlight the selected object */ void UI_Canvas::DrawHighlight(int objtype, int objnum, Fl_Color col, bool do_tagged, bool skip_lines, int dx, int dy) { fl_color(col); // fprintf(stderr, "DrawHighlight: %d\n", objnum); int vert_r = vertex_radius(grid.Scale); switch (objtype) { case OBJ_THINGS: { int x = dx + Things[objnum]->x; int y = dy + Things[objnum]->y; if (! Vis(x, y, MAX_RADIUS)) return; const thingtype_t *info = M_GetThingType(Things[objnum]->type); int r = info->radius; if (edit.error_mode) DrawThing(x, y, r, Things[objnum]->angle, false /* big_arrow */); r += r / 10 + 4; DrawThing(x, y, r, Things[objnum]->angle, true); } break; case OBJ_LINEDEFS: { // handle tagged linedefs : show matching sector(s) if (do_tagged && (dx==0 && dy==0) && LineDefs[objnum]->tag > 0) { for (int m = 0 ; m < NumSectors ; m++) if (Sectors[m]->tag == LineDefs[objnum]->tag) DrawHighlight(OBJ_SECTORS, m, LIGHTRED, false); fl_color(col); } int x1 = dx + LineDefs[objnum]->Start()->x; int y1 = dy + LineDefs[objnum]->Start()->y; int x2 = dx + LineDefs[objnum]->End ()->x; int y2 = dy + LineDefs[objnum]->End ()->y; if (! Vis(MIN(x1,x2), MIN(y1,y2), MAX(x1,x2), MAX(y1,y2))) return; int mx = (x1 + x2) / 2; int my = (y1 + y2) / 2; DrawMapLine(mx, my, mx + (y2 - y1) / 5, my + (x1 - x2) / 5); fl_line_style(FL_SOLID, 2); DrawMapVector(x1, y1, x2, y2); fl_line_style(FL_SOLID); } break; case OBJ_VERTICES: { int x = dx + Vertices[objnum]->x; int y = dy + Vertices[objnum]->y; if (! Vis(x, y, vert_r)) return; DrawVertex(x, y, vert_r); int r = vert_r * 3 / 2; int sx1 = SCREENX(x) - r; int sy1 = SCREENY(y) - r; int sx2 = SCREENX(x) + r; int sy2 = SCREENY(y) + r; fl_line(sx1, sy1, sx2, sy1); fl_line(sx2, sy1, sx2, sy2); fl_line(sx2, sy2, sx1, sy2); fl_line(sx1, sy2, sx1, sy1); } break; case OBJ_SECTORS: { // handle tagged sectors : show matching line(s) if (do_tagged && (dx==0 && dy==0) && Sectors[objnum]->tag > 0) { for (int m = 0 ; m < NumLineDefs ; m++) if (LineDefs[m]->tag == Sectors[objnum]->tag) DrawHighlight(OBJ_LINEDEFS, m, LIGHTRED, false); fl_color(col); } fl_line_style(FL_SOLID, 2); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (! L->TouchesSector(objnum)) continue; bool reverse = false; // skip lines if both sides are in the selection if (skip_lines && L->TwoSided()) { int sec1 = L->Right()->sector; int sec2 = L->Left ()->sector; if ((sec1 == objnum || edit.Selected->get(sec1)) && (sec2 == objnum || edit.Selected->get(sec2))) continue; if (sec1 != objnum) reverse = true; } int x1 = dx + L->Start()->x; int y1 = dy + L->Start()->y; int x2 = dx + L->End ()->x; int y2 = dy + L->End ()->y; if (! Vis(MIN(x1,x2), MIN(y1,y2), MAX(x1,x2), MAX(y1,y2))) continue; if (skip_lines) DrawKnobbyLine(x1, y1, x2, y2, reverse); else DrawMapLine(x1, y1, x2, y2); } fl_line_style(FL_SOLID); } break; } } void UI_Canvas::DrawHighlightScaled(int objtype, int objnum, Fl_Color col) { fl_color(col); int vert_r = vertex_radius(grid.Scale); switch (objtype) { case OBJ_THINGS: { int x = Things[objnum]->x; int y = Things[objnum]->y; scale_param.Apply(&x, &y); if (! Vis(x, y, MAX_RADIUS)) return; const thingtype_t *info = M_GetThingType(Things[objnum]->type); int r = info->radius; DrawThing(x, y, r * 3 / 2, Things[objnum]->angle, true); } break; case OBJ_VERTICES: { int x = Vertices[objnum]->x; int y = Vertices[objnum]->y; scale_param.Apply(&x, &y); if (! Vis(x, y, vert_r)) return; DrawVertex(x, y, vert_r); int r = vert_r * 3 / 2; int sx1 = SCREENX(x) - r; int sy1 = SCREENY(y) - r; int sx2 = SCREENX(x) + r; int sy2 = SCREENY(y) + r; fl_line(sx1, sy1, sx2, sy1); fl_line(sx2, sy1, sx2, sy2); fl_line(sx2, sy2, sx1, sy2); fl_line(sx1, sy2, sx1, sy1); } break; case OBJ_LINEDEFS: { int x1 = LineDefs[objnum]->Start()->x; int y1 = LineDefs[objnum]->Start()->y; int x2 = LineDefs[objnum]->End ()->x; int y2 = LineDefs[objnum]->End ()->y; scale_param.Apply(&x1, &y1); scale_param.Apply(&x2, &y2); if (! Vis(MIN(x1,x2), MIN(y1,y2), MAX(x1,x2), MAX(y1,y2))) return; int mx = (x1 + x2) / 2; int my = (y1 + y2) / 2; DrawMapLine(mx, my, mx + (y2 - y1) / 5, my + (x1 - x2) / 5); fl_line_style(FL_SOLID, 2); DrawMapVector(x1, y1, x2, y2); fl_line_style(FL_SOLID); } break; case OBJ_SECTORS: { fl_line_style(FL_SOLID, 2); for (int n = 0 ; n < NumLineDefs ; n++) { if (! LineDefs[n]->TouchesSector(objnum)) continue; int x1 = LineDefs[n]->Start()->x; int y1 = LineDefs[n]->Start()->y; int x2 = LineDefs[n]->End ()->x; int y2 = LineDefs[n]->End ()->y; scale_param.Apply(&x1, &y1); scale_param.Apply(&x2, &y2); if (! Vis(MIN(x1,x2), MIN(y1,y2), MAX(x1,x2), MAX(y1,y2))) continue; DrawMapLine(x1, y1, x2, y2); } fl_line_style(FL_SOLID); } break; } } /* highlight the selected objects */ void UI_Canvas::DrawSelection(selection_c * list) { if (! list || list->empty()) return; selection_iterator_c it; if (edit.action == ACT_SCALE) { for (list->begin(&it) ; !it.at_end() ; ++it) { DrawHighlightScaled(list->what_type(), *it, SEL_COL); } return; } int dx = 0; int dy = 0; if (edit.action == ACT_DRAG) { DragDelta(&dx, &dy); } for (list->begin(&it) ; !it.at_end() ; ++it) { DrawHighlight(list->what_type(), *it, edit.error_mode ? FL_RED : SEL_COL, ! edit.error_mode /* do_tagged */, true /* skip_lines */, dx, dy); } } /* * draw_map_point - draw a point at map coordinates * * The point is drawn at map coordinates (, ) */ void UI_Canvas::DrawMapPoint(int map_x, int map_y) { fl_point(SCREENX(map_x), SCREENY(map_y)); } /* * DrawMapLine - draw a line on the screen from map coords */ void UI_Canvas::DrawMapLine(int map_x1, int map_y1, int map_x2, int map_y2) { fl_line(SCREENX(map_x1), SCREENY(map_y1), SCREENX(map_x2), SCREENY(map_y2)); } void UI_Canvas::DrawKnobbyLine(int map_x1, int map_y1, int map_x2, int map_y2, bool reverse) { int x1 = SCREENX(map_x1); int y1 = SCREENY(map_y1); int x2 = SCREENX(map_x2); int y2 = SCREENY(map_y2); if (reverse) { std::swap(x1, x2); std::swap(y1, y2); } fl_line(x1, y1, x2, y2); // indicate direction of line int mx = (x1 + x2) / 2; int my = (y1 + y2) / 2; int dx = (y1 - y2); int dy = (x2 - x1); int len = MAX(4, MAX(abs(dx), abs(dy))); int want_len = MIN(12, len / 5); dx = dx * want_len / len; dy = dy * want_len / len; if (! (dx == 0 && dy == 0)) { fl_line(mx, my, mx + dx, my + dy); } } void UI_Canvas::DrawSplitLine(int map_x1, int map_y1, int map_x2, int map_y2) { // show how and where the line will be split int scr_x1 = SCREENX(map_x1); int scr_y1 = SCREENY(map_y1); int scr_x2 = SCREENX(map_x2); int scr_y2 = SCREENY(map_y2); int scr_mx = SCREENX(split_x); int scr_my = SCREENY(split_y); fl_line(scr_x1, scr_y1, scr_mx, scr_my); fl_line(scr_x2, scr_y2, scr_mx, scr_my); int size = (grid.Scale >= 5.0) ? 11 : (grid.Scale >= 1.0) ? 9 : 7; fl_pie(scr_mx - size/2, scr_my - size/2, size, size, 0, 360); } /* * DrawMapVector - draw an arrow on the screen from map coords */ void UI_Canvas::DrawMapVector (int map_x1, int map_y1, int map_x2, int map_y2) { int x1 = SCREENX(map_x1); int y1 = SCREENY(map_y1); int x2 = SCREENX(map_x2); int y2 = SCREENY(map_y2); fl_line(x1, y1, x2, y2); double r2 = hypot((double) (x1 - x2), (double) (y1 - y2)); if (r2 < 1.0) return; double scale = (grid.Scale > 1.0) ? sqrt(grid.Scale) : grid.Scale; int dx = (int) ((x1 - x2) * 8.0 / r2 * scale); int dy = (int) ((y1 - y2) * 8.0 / r2 * scale); x1 = x2 + 2 * dx; y1 = y2 + 2 * dy; fl_line(x1 - dy, y1 + dx, x2, y2); fl_line(x1 + dy, y1 - dx, x2, y2); } /* * DrawMapArrow - draw an arrow on the screen from map coords and angle (0 - 65535) */ void UI_Canvas::DrawMapArrow(int map_x1, int map_y1, int r, int angle) { int map_x2 = map_x1 + r * cos(angle * M_PI / 180.0); int map_y2 = map_y1 + r * sin(angle * M_PI / 180.0); int x1 = SCREENX(map_x1); int y1 = SCREENY(map_y1); int x2 = SCREENX(map_x2); int y2 = SCREENY(map_y2); fl_line(x1, y1, x2, y2); double r2 = hypot((double) (x1 - x2), (double) (y1 - y2)); if (r2 < 1.0) return; int dx = (int) ((x1 - x2) * 12.0 / (double)r2 * (grid.Scale / 2)); int dy = (int) ((y1 - y2) * 12.0 / (double)r2 * (grid.Scale / 2)); x1 = x2 + 2 * dx; y1 = y2 + 2 * dy; fl_line(x1 - dy, y1 + dx, x2, y2); fl_line(x1 + dy, y1 - dx, x2, y2); } void UI_Canvas::DrawCamera() { int map_x, map_y; float angle; Render3D_GetCameraPos(&map_x, &map_y, &angle); int scr_x = SCREENX(map_x); int scr_y = SCREENY(map_y); float size = sqrt(grid.Scale) * 40; if (size < 8) size = 8; int dx = size * cos(angle * M_PI / 180.0); int dy = size * -sin(angle * M_PI / 180.0); fl_color(CAMERA_COLOR); // arrow body fl_line(scr_x - dx, scr_y - dy, scr_x + dx, scr_y + dy); int ex = dy/3; int ey = -dx/3; fl_line(scr_x + dx/8 + ex, scr_y + dy/8 + ey, scr_x + dx/8 - ex, scr_y + dy/8 - ey); fl_line(scr_x - dx/8 + ex, scr_y - dy/8 + ey, scr_x - dx/8 - ex, scr_y - dy/8 - ey); // arrow head scr_x += dx; scr_y += dy; int hx = dx/2; int hy = dy/2; fl_line(scr_x, scr_y, scr_x + hy - hx, scr_y - hx - hy); fl_line(scr_x, scr_y, scr_x - hy - hx, scr_y + hx - hy); } void UI_Canvas::DrawCurrentLine() { if (edit.drawing_from < 0) return; int new_x = grid.SnapX(edit.map_x); int new_y = grid.SnapY(edit.map_y); // should draw a vertex? if (highlight.valid()) { SYS_ASSERT(highlight.type == OBJ_VERTICES); new_x = Vertices[highlight.num]->x; new_y = Vertices[highlight.num]->y; } else if (split_ld < 0) { fl_color(FL_GREEN); DrawVertex(new_x, new_y, vertex_radius(grid.Scale)); } fl_color(RED); const Vertex * v = Vertices[edit.drawing_from]; DrawKnobbyLine(v->x, v->y, new_x, new_y); } void UI_Canvas::SelboxBegin(int map_x, int map_y) { selbox_x1 = selbox_x2 = map_x; selbox_y1 = selbox_y2 = map_y; } void UI_Canvas::SelboxUpdate(int map_x, int map_y) { selbox_x2 = map_x; selbox_y2 = map_y; redraw(); } void UI_Canvas::SelboxFinish(int *x1, int *y1, int *x2, int *y2) { *x1 = MIN(selbox_x1, selbox_x2); *y1 = MIN(selbox_y1, selbox_y2); *x2 = MAX(selbox_x1, selbox_x2); *y2 = MAX(selbox_y1, selbox_y2); int scr_dx = SCREENX(*x2) - SCREENX(*x1); int scr_dy = SCREENY(*y1) - SCREENY(*y2); // small boxes should be treated as a click/release if (scr_dx < 10 && scr_dy < 10) // TODO: CONFIG ITEM { *x2 = *x1; *y2 = *y1; } } void UI_Canvas::SelboxDraw() { int x1 = MIN(selbox_x1, selbox_x2); int x2 = MAX(selbox_x1, selbox_x2); int y1 = MIN(selbox_y1, selbox_y2); int y2 = MAX(selbox_y1, selbox_y2); fl_color(FL_CYAN); DrawMapLine(x1, y1, x2, y1); DrawMapLine(x2, y1, x2, y2); DrawMapLine(x2, y2, x1, y2); DrawMapLine(x1, y2, x1, y1); } void UI_Canvas::DragBegin(int focus_x, int focus_y, int map_x, int map_y) { drag_start_x = map_x; drag_start_y = map_y; drag_focus_x = focus_x; drag_focus_y = focus_y; drag_cur_x = drag_start_x; drag_cur_y = drag_start_y; if (edit.mode == OBJ_VERTICES) { drag_lines.change_type(OBJ_LINEDEFS); ConvertSelection(edit.Selected, &drag_lines); } } void UI_Canvas::DragFinish(int *dx, int *dy) { drag_lines.clear_all(); DragDelta(dx, dy); } void UI_Canvas::DragUpdate(int map_x, int map_y) { drag_cur_x = map_x; drag_cur_y = map_y; redraw(); } void UI_Canvas::DragDelta(int *dx, int *dy) { *dx = drag_cur_x - drag_start_x; *dy = drag_cur_y - drag_start_y; if (grid.snap) { int focus_x = drag_focus_x + *dx; int focus_y = drag_focus_y + *dy; *dx = grid.SnapX(focus_x) - drag_focus_x; *dy = grid.SnapY(focus_y) - drag_focus_y; } } void UI_Canvas::ScaleBegin(int map_x, int map_y, int middle_x, int middle_y) { scale_start_x = map_x; scale_start_y = map_y; scale_param.Clear(); scale_param.mid_x = middle_x; scale_param.mid_y = middle_y; if (edit.mode == OBJ_VERTICES) { scale_lines.change_type(OBJ_LINEDEFS); ConvertSelection(edit.Selected, &scale_lines); } } void UI_Canvas::ScaleFinish(scale_param_t& param) { scale_lines.clear_all(); param = scale_param; } void UI_Canvas::ScaleUpdate(int map_x, int map_y, keycode_t mod) { int dx1 = map_x - scale_param.mid_x; int dy1 = map_y - scale_param.mid_y; int dx2 = scale_start_x - scale_param.mid_x; int dy2 = scale_start_y - scale_param.mid_y; bool any_aspect = (mod & MOD_SHIFT) ? true : false; bool rotate = (mod & MOD_COMMAND) ? true : false; scale_param.rotate = 0; if (rotate) { int angle1 = (int)ComputeAngle(dx1, dy1); int angle2 = (int)ComputeAngle(dx2, dy2); scale_param.rotate = angle1 - angle2; // fprintf(stderr, "angle diff : %1.2f\n", scale_rotate * 360.0 / 65536.0); } if (rotate) // TODO: CONFIG ITEM: rotate_with_scale { // no scaling dx1 = dx2 = 10; dy1 = dy2 = 10; } else if (rotate || !any_aspect) { dx1 = MAX(abs(dx1), abs(dy1)); dx2 = MAX(abs(dx2), abs(dy2)); dy1 = dx1; dy2 = dx2; } scale_param.scale_x = dx2 ? (dx1 / (float)dx2) : 1.0; scale_param.scale_y = dy2 ? (dy1 / (float)dy2) : 1.0; redraw(); } //------------------------------------------------------------------------ // this represents a segment of a linedef bounding a sector. struct sector_edge_t { const LineDef * line; // coordinates mapped to screen space, not clipped int scr_x1, scr_y1; int scr_x2, scr_y2; // has the line been flipped (coordinates were swapped) ? short flipped; // what side this edge faces (SIDE_LEFT or SIDE_RIGHT) short side; // clipped vertical range, inclusive short y1, y2; // computed X value float x; void CalcX(short y) { x = scr_x1 + (scr_x2 - scr_x1) * (float)(y - scr_y1) / (float)(scr_y2 - scr_y1); } struct CMP_Y { inline bool operator() (const sector_edge_t &A, const sector_edge_t& B) const { return A.scr_y1 < B.scr_y1; } }; struct CMP_X { inline bool operator() (const sector_edge_t *A, const sector_edge_t *B) const { // NULL is always > than a valid pointer if (A == NULL) return false; if (B == NULL) return true; return A->x < B->x; } }; }; void UI_Canvas::RenderSector(int num) { /// fprintf(stderr, "RenderSector %d\n", num); rgb_color_t light_col = SectorLightColor(Sectors[num]->light); const char * tex_name = NULL; Img_c * img = NULL; if (edit.sector_render_mode == SREND_Lighting) { fl_color(light_col); } else { if (edit.sector_render_mode == SREND_Ceiling) tex_name = Sectors[num]->CeilTex(); else tex_name = Sectors[num]->FloorTex(); if (is_sky(tex_name)) { fl_color(palette[game_info.sky_color]); } else { img = W_GetFlat(tex_name); if (! img) { img = IM_UnknownTex(); } } } img_pixel_t *wbuf = img ? img->wbuf() : NULL; int tw = img ? img->width() : 1; int th = img ? img->height() : 1; // verify size is at least 64x64 if (img && (tw < 64 || th < 64)) { fl_color(palette[game_info.missing_color]); img = NULL; } /*** Part 1 : visit linedefs and create edges ***/ std::vector edgelist; short min_y = 32767; short max_y = 0; for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (! L->TouchesSector(num)) continue; // ignore 2S lines with same sector on both sides if (L->WhatSector(SIDE_LEFT) == L->WhatSector(SIDE_RIGHT)) continue; sector_edge_t edge; edge.scr_x1 = SCREENX(L->Start()->x); edge.scr_y1 = SCREENY(L->Start()->y); edge.scr_x2 = SCREENX(L->End()->x); edge.scr_y2 = SCREENY(L->End()->y); // completely above or below the screen? if (MAX(edge.scr_y1, edge.scr_y2) < y()) continue; if (MIN(edge.scr_y1, edge.scr_y2) >= y() + h()) continue; // skip horizontal lines if (edge.scr_y1 == edge.scr_y2) continue; edge.flipped = 0; if (edge.scr_y1 > edge.scr_y2) { std::swap(edge.scr_x1, edge.scr_x2); std::swap(edge.scr_y1, edge.scr_y2); edge.flipped = 1; } // compute usable range, clipping to screen edge.y1 = MAX(edge.scr_y1, y()); edge.y2 = MIN(edge.scr_y2, y() + h() - 1); // this probably cannot happen.... if (edge.y2 < edge.y1) continue; min_y = MIN(min_y, edge.y1); max_y = MAX(max_y, edge.y2); // compute side bool is_right = (L->WhatSector(SIDE_LEFT) == num); if (edge.flipped) is_right = !is_right; edge.side = is_right ? SIDE_RIGHT : SIDE_LEFT; /* fprintf(stderr, "Line %d mapped coords (%d %d) .. (%d %d) flipped:%d sec:%d/%d\n", n, edge.scr_x1, edge.scr_y1, edge.scr_x2, edge.scr_y2, edge.flipped, L->WhatSector(SIDE_RIGHT), L->WhatSector(SIDE_LEFT)); */ // add the edge edge.line = L; edgelist.push_back(edge); } if (edgelist.empty()) return; // sort edges into vertical order (i.e. by scr_y1) std::sort(edgelist.begin(), edgelist.end(), sector_edge_t::CMP_Y()); /*** Part 2 : traverse edge list and render spans ***/ unsigned int next_edge = 0; u8_t * line_rgb = new u8_t[3 * (w() + 4)]; std::vector active_edges; unsigned int i; // visit each screen row for (short y = min_y ; y <= max_y ; y++) { // remove old edges from active list for (i = 0 ; i < active_edges.size() ; i++) { if (y > active_edges[i]->y2) active_edges[i] = NULL; } // add new edges from active list for ( ; next_edge < edgelist.size() && y == edgelist[next_edge].y1 ; next_edge++) { active_edges.push_back(&edgelist[next_edge]); } /// fprintf(stderr, " active @ y=%d --> %d\n", y, (int)active_edges.size()); if (active_edges.empty()) continue; // sort active edges by X value // [ also puts NULL entries at end, making easy to remove them ] for (i = 0 ; i < active_edges.size() ; i++) { if (active_edges[i]) active_edges[i]->CalcX(y); } std::sort(active_edges.begin(), active_edges.end(), sector_edge_t::CMP_X()); while (active_edges.size() > 0 && active_edges.back() == NULL) active_edges.pop_back(); // compute spans for (unsigned int i = 1 ; i < active_edges.size() ; i++) { const sector_edge_t * E1 = active_edges[i - 1]; const sector_edge_t * E2 = active_edges[i]; #if 1 if (E1 == NULL || E2 == NULL) BugError("RenderSector: did not delete NULLs properly!"); #endif /// fprintf(stderr, "E1 @ x=%1.2f side=%d | E2 @ x=%1.2f side=%d\n", /// E1->x, E1->side, E2->x, E2->side); if (! (E1->side == SIDE_RIGHT && E2->side == SIDE_LEFT)) continue; // treat lines without a right side as dead if (E1->line->right < 0) continue; if (E2->line->right < 0) continue; int x1 = floor(E1->x); int x2 = floor(E2->x); // completely off the screen? if (x2 < x() || x1 >= x() + w()) continue; // clip span to screen x1 = MAX(x1, x()); x2 = MIN(x2, x() + w() - 1); // this probably cannot happen.... if (x2 < x1) continue; /// fprintf(stderr, " span : y=%d x=%d..%d\n", y, x1, x2); // solid color? if (! img) { fl_rectf(x1, y, x2 - x1 + 1, 1); continue; } int x = x1; int span_w = x2 - x1 + 1; u8_t *dest = line_rgb; u8_t *dest_end = line_rgb + span_w * 3; int ty = (0 - MAPY(y)) & 63; for (; dest < dest_end ; dest += 3, x++) { // TODO : be nice to optimize the next line int tx = MAPX(x) & 63; rgb_color_t col = palette[wbuf[ty * tw + tx]]; dest[0] = RGB_RED(col); dest[1] = RGB_GREEN(col); dest[2] = RGB_BLUE(col); } fl_draw_image(line_rgb, x1, y, span_w, 1); } } delete[] line_rgb; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_game.cc0000644000175100017510000005474512647352405016040 0ustar aaptedaapted//------------------------------------------------------------------------ // GAME DEFINITION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include #include "im_color.h" #include "m_game.h" #include "levels.h" #include "e_things.h" #define UNKNOWN_THING_RADIUS 16 #define UNKNOWN_THING_COLOR fl_rgb_color(0,255,255) std::map line_groups; std::map thing_groups; std::map texture_groups; std::map line_types; std::map sector_types; std::map thing_types; std::map texture_assigns; std::map flat_assigns; game_info_t game_info; // contains sky_color (etc) generalized_linetype_t gen_linetypes[MAX_GEN_NUM_TYPES]; int num_gen_linetypes; /* * Create empty lists for game definitions */ void M_InitDefinitions() { // FIXME: delete the contents line_groups.clear(); line_types.clear(); sector_types.clear(); thing_groups.clear(); thing_types.clear(); texture_groups.clear(); texture_assigns.clear(); flat_assigns.clear(); // reset game information memset(&game_info, 0, sizeof(game_info)); // FIXME: ability to parse from a game definition file game_info.player_h = 56; game_info.min_dm_starts = 4; game_info.max_dm_starts = 10; // reset generalized types memset(&gen_linetypes, 0, sizeof(gen_linetypes)); num_gen_linetypes = 0; } static short ParseThingdefFlags(const char *s) { short flags = 0; if (strchr(s, 'i')) flags |= THINGDEF_INVIS; if (strchr(s, 'c')) flags |= THINGDEF_CEIL; if (strchr(s, 'l')) flags |= THINGDEF_LIT; if (strchr(s, 'n')) flags |= THINGDEF_PASS; if (strchr(s, 'v')) flags |= THINGDEF_VOID; if (strchr(s, 't')) flags |= THINGDEF_TELEPT; return flags; } static void ParseColorDef(char ** argv, int argc) { if (y_stricmp(argv[0], "sky") == 0) { game_info.sky_color = atoi(argv[1]); } else if (y_stricmp(argv[0], "wall") == 0) { game_info.wall_colors[0] = atoi(argv[1]); if (argc < 2) game_info.wall_colors[1] = game_info.wall_colors[0]; else game_info.wall_colors[1] = atoi(argv[2]); } else if (y_stricmp(argv[0], "floor") == 0) { game_info.floor_colors[0] = atoi(argv[1]); if (argc < 2) game_info.floor_colors[1] = game_info.floor_colors[0]; else game_info.floor_colors[1] = atoi(argv[2]); } else if (y_stricmp(argv[0], "missing") == 0) { game_info.missing_color = atoi(argv[1]); } else if (y_stricmp(argv[0], "unknown_tex") == 0) { game_info.unknown_tex = atoi(argv[1]); } else if (y_stricmp(argv[0], "unknown_flat") == 0) { game_info.unknown_flat = atoi(argv[1]); } else { LogPrintf("unknown color keyword: '%s'\n", argv[0]); } } static void ParseFeatureDef(char ** argv, int argc) { if (y_stricmp(argv[0], "gen_types") == 0) { game_info.gen_types = atoi(argv[1]); } else if (y_stricmp(argv[0], "img_png") == 0) { game_info.img_png = atoi(argv[1]); } else if (y_stricmp(argv[0], "tx_start") == 0) { game_info.tx_start = atoi(argv[1]); } else if (y_stricmp(argv[0], "coop_dm_flags") == 0) { game_info.coop_dm_flags = atoi(argv[1]); } else if (y_stricmp(argv[0], "friend_flag") == 0) { game_info.friend_flag = atoi(argv[1]); } else if (y_stricmp(argv[0], "pass_through") == 0) { game_info.pass_through = atoi(argv[1]); } else if (y_stricmp(argv[0], "3d_midtex") == 0) { game_info.midtex_3d = atoi(argv[1]); } else if (y_stricmp(argv[0], "medusa_bug") == 0) { game_info.medusa_bug = atoi(argv[1]); } else { LogPrintf("unknown feature keyword: '%s'\n", argv[0]); } } static const char * FindDefinitionFile( const char *base_dir, const char *folder, const char *name) { static char filename[FL_PATH_MAX]; if (! base_dir) return NULL; sprintf(filename, "%s/%s/%s.ugh", base_dir, folder, name); DebugPrintf(" trying: %s\n", filename); if (FileExists(filename)) return filename; return NULL; } bool M_CanLoadDefinitions(const char *folder, const char *name) { const char * filename; filename = FindDefinitionFile(home_dir, folder, name); if (! filename) filename = FindDefinitionFile(install_dir, folder, name); return (filename != NULL); } /* * Loads a definition file. The ".ugh" extension is added. * Will try the "common" folder if not found in the given one. * * Examples: "games" + "doom2" * "ports" + "edge" * "mods" + "qdoom" */ void M_LoadDefinitions(const char *folder, const char *name, int include_level) { // this is for error messages & debugging char basename[256]; sprintf(basename, "%s/%s.ugh", folder, name); LogPrintf("Loading Definitions : %s\n", basename); const char * filename; filename = FindDefinitionFile(home_dir, folder, name); if (! filename) filename = FindDefinitionFile(install_dir, folder, name); // look in common/ folder as last resort if (! filename && strcmp(folder, "common") != 0) { folder = "common"; filename = FindDefinitionFile(home_dir, folder, name); if (! filename) filename = FindDefinitionFile(install_dir, folder, name); } if (! filename) FatalError("Cannot find definition file: %s\n", basename); DebugPrintf(" found at: %s\n", filename); M_ParseDefinitionFile(filename, folder, basename, include_level); } void M_ParseDefinitionFile(const char *filename, const char *folder, const char *basename, int include_level) { if (! folder) folder = "common"; if (! basename) basename = fl_filename_name(filename); #define YGD_BUF 512 /* max. line length + 2 */ char readbuf[YGD_BUF]; /* buffer the line is read into */ #define MAX_TOKENS 30 /* tokens per line */ int lineno; /* current line of file */ #define MAX_INCLUDE_LEVEL 10 int current_gen_line = -1; FILE *fp = fopen(filename, "r"); if (! fp) FatalError("Cannot open %s: %s\n", filename, strerror(errno)); /* Read the game definition file, line by line. */ for (lineno = 2 ; fgets(readbuf, sizeof readbuf, fp) ; lineno++) { int ntoks; char *token[MAX_TOKENS]; int quoted; int in_token; const char *iptr; char *optr; char *buf; const char *const bad_arg_count = "%s(%d): directive \"%s\" takes %d parameters\n"; // create a buffer to contain the tokens [Note: never freed] buf = StringNew((int)strlen(readbuf) + 1); /* break the line into whitespace-separated tokens. whitespace can be enclosed in double quotes. */ for (in_token = 0, quoted = 0, iptr = readbuf, optr = buf, ntoks = 0 ; ; iptr++) { if (*iptr == '\n' || *iptr == '\0') { if (in_token) *optr = '\0'; break; } else if (*iptr == '"') quoted ^= 1; // "#" at the beginning of a token else if (! in_token && ! quoted && *iptr == '#') break; // First character of token else if (! in_token && (quoted || ! isspace(*iptr))) { if (ntoks >= (int) (sizeof token / sizeof *token)) FatalError("%s(%d): more than %d tokens\n", basename, lineno, sizeof token / sizeof *token); token[ntoks] = optr; ntoks++; in_token = 1; *optr++ = *iptr; } // First space between two tokens else if (in_token && ! quoted && isspace(*iptr)) { *optr++ = '\0'; in_token = 0; } // Character in the middle of a token else if (in_token) *optr++ = *iptr; } if (quoted) FatalError("%s(%d): unmatched double quote\n", basename, lineno); /* process the line */ int nargs = ntoks - 1; if (ntoks == 0) { continue; } else if (y_stricmp(token[0], "include") == 0) { if (nargs != 1) FatalError(bad_arg_count, basename, lineno, token[0], 1); if (include_level >= MAX_INCLUDE_LEVEL) FatalError("%s(%d): Too many includes (check for a loop)\n", basename, lineno); M_LoadDefinitions(folder, token[1], include_level + 1); } else if (y_stricmp(token[0], "level_name") == 0) { /* ignored for backwards compability */ } else if (y_stricmp(token[0], "sky_color") == 0) // back compat { if (nargs != 1) FatalError(bad_arg_count, basename, lineno, token[0], 1); game_info.sky_color = atoi(token[1]); } else if (y_stricmp(token[0], "sky_flat") == 0) { if (nargs != 1) FatalError(bad_arg_count, basename, lineno, token[0], 1); if (strlen(token[1]) >= sizeof(game_info.sky_flat)) FatalError("%s(%d): sky_flat name is too long\n", basename, lineno); strcpy(game_info.sky_flat, token[1]); } else if (y_stricmp(token[0], "color") == 0) { if (nargs < 2) FatalError(bad_arg_count, basename, lineno, token[0], 2); ParseColorDef(token + 1, nargs); } else if (y_stricmp(token[0], "feature") == 0) { if (nargs < 2) FatalError(bad_arg_count, basename, lineno, token[0], 2); ParseFeatureDef(token + 1, nargs); } else if (y_stricmp(token[0], "default_port") == 0) { /* ignored for backwards compability */ } else if (y_stricmp(token[0], "default_textures") == 0) { if (nargs != 3) FatalError(bad_arg_count, basename, lineno, token[0], 3); default_mid_tex = token[1]; default_floor_tex = token[2]; default_ceil_tex = token[3]; default_upper_tex = default_mid_tex; default_lower_tex = default_mid_tex; } else if (y_stricmp(token[0], "default_thing") == 0) { if (nargs != 1) FatalError(bad_arg_count, basename, lineno, token[0], 1); default_thing = atoi(token[1]); } else if (y_stricmp(token[0], "linegroup") == 0) { if (nargs != 2) FatalError(bad_arg_count, basename, lineno, token[0], 2); linegroup_t * lg = new linegroup_t; lg->group = token[1][0]; lg->desc = token[2]; line_groups[lg->group] = lg; } else if (y_stricmp(token[0], "line") == 0 || y_stricmp(token[0], "special") == 0) { if (nargs < 3) FatalError(bad_arg_count, basename, lineno, token[0], 3); linetype_t * info = new linetype_t; memset(info->args, 0, sizeof(info->args)); int number = atoi(token[1]); info->group = token[2][0]; info->desc = token[3]; int arg_count = MIN(nargs - 3, 5); for (int i = 0 ; i < arg_count ; i++) { if (token[4 + i][0] != '-') info->args[i] = token[4 + i]; } // FIXME : have separate tables for "special" if (line_groups.find( info->group) == line_groups.end()) { LogPrintf("%s(%d): unknown line group '%c'\n", basename, lineno, info->group); } else line_types[number] = info; } else if (y_stricmp(token[0], "sector") == 0) { if (nargs != 2) FatalError(bad_arg_count, basename, lineno, token[0], 2); int number = atoi(token[1]); sectortype_t *info = new sectortype_t; info->desc = token[2]; sector_types[number] = info; } else if (y_stricmp(token[0], "thinggroup") == 0) { if (nargs != 3) FatalError(bad_arg_count, basename, lineno, token[0], 3); thinggroup_t * tg = new thinggroup_t; tg->group = token[1][0]; tg->color = ParseColor(token[2]); tg->desc = token[3]; thing_groups[tg->group] = tg; } else if (y_stricmp(token[0], "thing") == 0) { if (nargs != 6) FatalError(bad_arg_count, basename, lineno, token[0], 6); thingtype_t * info = new thingtype_t; int number = atoi(token[1]); info->group = token[2][0]; info->flags = ParseThingdefFlags(token[3]); info->radius = atoi(token[4]); info->sprite = token[5]; info->desc = token[6]; if (thing_groups.find(info->group) == thing_groups.end()) { LogPrintf("%s(%d): unknown thing group '%c'\n", basename, lineno, info->group); } else { info->color = thing_groups[info->group]->color; thing_types[number] = info; } } else if (y_stricmp(token[0], "texturegroup") == 0) { if (nargs != 2) FatalError(bad_arg_count, basename, lineno, token[0], 2); texturegroup_t * tg = new texturegroup_t; tg->group = token[1][0]; tg->desc = token[2]; texture_groups[tg->group] = tg; } else if (y_stricmp(token[0], "texture") == 0) { if (nargs != 2) FatalError(bad_arg_count, basename, lineno, token[0], 2); char group = token[1][0]; std::string name = std::string(token[2]); if (texture_groups.find(tolower(group)) == texture_groups.end()) { LogPrintf("%s(%d): unknown texture group '%c'\n", basename, lineno, group); } else texture_assigns[name] = group; } else if (y_stricmp(token[0], "flat") == 0) { if (nargs != 2) FatalError(bad_arg_count, basename, lineno, token[0], 2); char group = token[1][0]; std::string name = std::string(token[2]); if (texture_groups.find(tolower(group)) == texture_groups.end()) { LogPrintf("%s(%d): unknown texture group '%c'\n", basename, lineno, group); } else flat_assigns[name] = group; } else if (y_stricmp(token[0], "gen_line") == 0) { if (nargs != 4) FatalError(bad_arg_count, basename, lineno, token[0], 4); current_gen_line = num_gen_linetypes; num_gen_linetypes++; if (num_gen_linetypes > MAX_GEN_NUM_TYPES) FatalError("%s(%d): too many gen_line definitions\n", basename, lineno); generalized_linetype_t *def = &gen_linetypes[current_gen_line]; def->key = token[1][0]; // use strtol() to support "0x" notation def->base = strtol(token[2], NULL, 0); def->length = strtol(token[3], NULL, 0); def->name = token[4]; def->num_fields = 0; } else if (y_stricmp(token[0], "gen_field") == 0) { if (nargs < 5) FatalError(bad_arg_count, basename, lineno, token[0], 5); if (current_gen_line < 0) FatalError("%s(%d): gen_field used outside of a gen_line definition\n", basename, lineno); generalized_linetype_t *def = &gen_linetypes[current_gen_line]; generalized_field_t *field = &def->fields[def->num_fields]; def->num_fields++; if (def->num_fields > MAX_GEN_NUM_FIELDS) FatalError("%s(%d): too many fields in gen_line definition\n", basename, lineno); field->bits = atoi(token[1]); field->shift = atoi(token[2]); field->mask = ((1 << field->bits) - 1) << field->shift; field->default_val = atoi(token[3]); field->name = token[4]; // grab the keywords field->num_keywords = MIN(nargs - 4, MAX_GEN_FIELD_KEYWORDS); for (int i = 0 ; i < field->num_keywords ; i++) { field->keywords[i] = token[5 + i]; } } else if (y_stricmp(token[0], "exclude_game") == 0) { if (nargs != 1) FatalError(bad_arg_count, basename, lineno, token[0], 1); if (Game_name && y_stricmp(token[1], Game_name) == 0) { LogPrintf("WARNING: skipping %s -- not compatible with %s\n", basename, Game_name); // do not process any more of the file fclose(fp); return; } } else { FatalError("%s(%d): unknown directive: %.32s\n", basename, lineno, token[0]); } } fclose(fp); } /* * Free all memory allocated to game definitions */ void M_FreeDefinitions() { } static void scanner_add_file(const char *name, int flags, void *priv_dat) { std::vector * list = (std::vector *) priv_dat; // DebugPrintf(" file [%s] flags:%d\n", name, flags); if (flags & (SCAN_F_IsDir | SCAN_F_Hidden)) return; if (! MatchExtension(name, "ugh")) return; list->push_back(ReplaceExtension(name, NULL)); } struct DefName_CMP_pred { inline bool operator() (const char *A, const char *B) const { return y_stricmp(A, B) < 0; } }; void M_CollectKnownDefs(const char *folder, std::vector & list) { std::vector temp_list; static char path[FL_PATH_MAX]; // DebugPrintf("M_CollectKnownDefs for: %d\n", folder); sprintf(path, "%s/%s", install_dir, folder); ScanDirectory(path, scanner_add_file, & temp_list); sprintf(path, "%s/%s", home_dir, folder); ScanDirectory(path, scanner_add_file, & temp_list); std::sort(temp_list.begin(), temp_list.end(), DefName_CMP_pred()); // transfer to passed list, removing duplicates as we go unsigned int pos; for (pos = 0 ; pos < temp_list.size() ; pos++) { if (pos + 1 < temp_list.size() && y_stricmp(temp_list[pos], temp_list[pos + 1]) == 0) { StringFree(temp_list[pos]); continue; } list.push_back(temp_list[pos]); } } // result will be '|' separated (ready for Fl_Choice::add) // returns the empty string when nothing found. // The result should be freed with StringFree(). // // will also find an existing name, storing its index in 'exist_val' // (when not found, the value in 'exist_val' is not changed at all) const char * M_CollectDefsForMenu(const char *folder, int *exist_val, const char *exist_name) { std::vector list; M_CollectKnownDefs(folder, list); if (list.empty()) return StringDup(""); // determine final length int length = 2 + (int)list.size(); unsigned int i; for (i = 0 ; i < list.size() ; i++) length += strlen(list[i]); char * result = StringNew(length); result[0] = 0; for (i = 0 ; i < list.size() ; i++) { strcat(result, list[i]); if (i + 1 < list.size()) strcat(result, "|"); if (y_stricmp(list[i], exist_name) == 0) *exist_val = i; } // DebugPrintf( "RESULT = '%s'\n", result); return result; } //------------------------------------------------------------------------ bool is_sky(const char *flat) { return (y_stricmp(game_info.sky_flat, flat) == 0); } const sectortype_t * M_GetSectorType(int type) { std::map::iterator SI; SI = sector_types.find(type); if (SI != sector_types.end()) return SI->second; static sectortype_t dummy_type = { "UNKNOWN TYPE" }; return &dummy_type; } const linetype_t * M_GetLineType(int type) { std::map::iterator LI; LI = line_types.find(type); if (LI != line_types.end()) return LI->second; static linetype_t dummy_type = { 0, "UNKNOWN TYPE" }; return &dummy_type; } const thingtype_t * M_GetThingType(int type) { std::map::iterator TI; TI = thing_types.find(type); if (TI != thing_types.end()) return TI->second; static thingtype_t dummy_type = { 0, 0, UNKNOWN_THING_RADIUS, "UNKNOWN TYPE", "NULL", UNKNOWN_THING_COLOR }; return &dummy_type; } char M_GetTextureType(const char *name) { std::map::iterator TI; TI = texture_assigns.find(name); if (TI != texture_assigns.end()) return TI->second; return '-'; // the OTHER category } char M_GetFlatType(const char *name) { std::map::iterator TI; TI = flat_assigns.find(name); if (TI != flat_assigns.end()) return TI->second; return '-'; // the OTHER category } static bool LineCategory_IsUsed(char group) { std::map::iterator IT; for (IT = line_types.begin() ; IT != line_types.end() ; IT++) { linetype_t *info = IT->second; if (info->group == group) return true; } return false; } static bool ThingCategory_IsUsed(char group) { std::map::iterator IT; for (IT = thing_types.begin() ; IT != thing_types.end() ; IT++) { thingtype_t *info = IT->second; if (info->group == group) return true; } return false; } static bool TextureCategory_IsUsed(char group) { std::map::iterator IT; for (IT = texture_assigns.begin() ; IT != texture_assigns.end() ; IT++) if (IT->second == group) return true; return false; } static bool FlatCategory_IsUsed(char group) { std::map::iterator IT; for (IT = flat_assigns.begin() ; IT != flat_assigns.end() ; IT++) if (IT->second == group) return true; return false; } const char *M_LineCategoryString(char *letters) { static char buffer[2000]; int L_index = 0; // the "ALL" category is always first strcpy(buffer, "ALL"); letters[L_index++] = '*'; std::map::iterator IT; for (IT = line_groups.begin() ; IT != line_groups.end() ; IT++) { linegroup_t *G = IT->second; // the "Other" category is always at the end if (G->group == '-') continue; if (! LineCategory_IsUsed(G->group)) continue; // FIXME: potential for buffer overflow here strcat(buffer, "|"); strcat(buffer, G->desc); letters[L_index++] = IT->first; } strcat(buffer, "|Other"); letters[L_index++] = '-'; letters[L_index++] = 0; return buffer; } const char *M_ThingCategoryString(char *letters) { static char buffer[2000]; int L_index = 0; // these common categories are always first strcpy(buffer, "ALL|RECENT"); letters[L_index++] = '*'; letters[L_index++] = '^'; std::map::iterator IT; for (IT = thing_groups.begin() ; IT != thing_groups.end() ; IT++) { thinggroup_t *G = IT->second; // the "Other" category is always at the end if (G->group == '-') continue; if (! ThingCategory_IsUsed(G->group)) continue; // FIXME: potential for buffer overflow here strcat(buffer, "|"); strcat(buffer, G->desc); letters[L_index++] = IT->first; } strcat(buffer, "|Other"); letters[L_index++] = '-'; letters[L_index++] = 0; return buffer; } const char *M_TextureCategoryString(char *letters, bool do_flats) { static char buffer[2000]; int L_index = 0; // these common categories are always first strcpy(buffer, "ALL|RECENT"); letters[L_index++] = '*'; letters[L_index++] = '^'; std::map::iterator IT; for (IT = texture_groups.begin() ; IT != texture_groups.end() ; IT++) { texturegroup_t *G = IT->second; // the "Other" category is always at the end if (G->group == '-') continue; if (do_flats && !FlatCategory_IsUsed(G->group)) continue; if (!do_flats && !TextureCategory_IsUsed(G->group)) continue; // FIXME: potential for buffer overflow here strcat(buffer, "|"); strcat(buffer, G->desc); letters[L_index++] = IT->first; } strcat(buffer, "|Other"); letters[L_index++] = '-'; letters[L_index++] = 0; return buffer; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/main.cc0000644000175100017510000004566712647614076015547 0ustar aaptedaapted//------------------------------------------------------------------------ // MAIN PROGRAM //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include "e_loadsave.h" #include "im_color.h" #include "m_config.h" #include "editloop.h" #include "m_game.h" #include "m_files.h" #include "levels.h" /* Because of "viewtex" */ #include "w_flats.h" #include "w_rawdef.h" #include "w_sprite.h" #include "w_texture.h" #include "w_wad.h" #include "ui_window.h" #include "ui_file.h" #include "r_render.h" #ifndef WIN32 #include #endif // IOANCH: be able to call OSX specific routines (needed for ~/Library) #ifdef __APPLE__ #include "OSXCalls.h" #endif /* * Global variables */ // progress during initialisation: // 0 = nothing yet // 1 = read early options, set up logging // 2 = read all options, and possibly a config file // 3 = inited FLTK, opened main window int init_progress; bool want_quit = false; const char *config_file = NULL; const char *log_file; const char *install_dir; const char *home_dir; const char *cache_dir; const char *Iwad_name = NULL; const char *Pwad_name = NULL; std::vector< const char * > Pwad_list; std::vector< const char * > Resource_list; const char *Game_name; const char *Port_name; const char *Level_name; map_format_e Level_format; int show_help = 0; int show_version = 0; int KF; int KF_fonth; // config items bool auto_load_recent = false; bool begin_maximized = false; bool map_scroll_bars = true; #define DEFAULT_PORT_NAME "vanilla" const char *default_port = DEFAULT_PORT_NAME; int scroll_less = 10; int scroll_more = 90; int gui_scheme = 2; // plastic int gui_color_set = 1; // bright rgb_color_t gui_custom_bg = RGB_MAKE(0xCC, 0xD5, 0xDD); rgb_color_t gui_custom_ig = RGB_MAKE(255, 255, 255); rgb_color_t gui_custom_fg = RGB_MAKE(0, 0, 0); /* * Prototypes of private functions */ static void TermFLTK(); static void RemoveSingleNewlines(char *buffer) { for (char *p = buffer ; *p ; p++) { if (*p == '\n' && p[1] == '\n') while (*p == '\n') p++; if (*p == '\n') *p = ' '; } } /* * Show an error message and terminate the program */ void FatalError(const char *fmt, ...) { va_list arg_ptr; static char buffer[MSG_BUF_LEN]; va_start(arg_ptr, fmt); vsnprintf(buffer, MSG_BUF_LEN-1, fmt, arg_ptr); va_end(arg_ptr); buffer[MSG_BUF_LEN-1] = 0; if (init_progress < 1 || Quiet || log_file) { fprintf(stderr, "\nFATAL ERROR: %s", buffer); } if (init_progress >= 1) { LogPrintf("\nFATAL ERROR: %s", buffer); } if (init_progress >= 3) { RemoveSingleNewlines(buffer); DLG_ShowError("%s", buffer); init_progress = 2; TermFLTK(); } #ifdef WIN32 else { MessageBox(NULL, buffer, "Eureka : Error", MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL | MB_SETFOREGROUND); } #endif init_progress = 0; MasterDir_CloseAll(); LogClose(); exit(2); } static void CreateHomeDirs() { SYS_ASSERT(home_dir); static char dir_name[FL_PATH_MAX]; #ifdef __APPLE__ // IOANCH 20130825: modified to use name-independent calls fl_filename_expand(dir_name, OSX_UserDomainDirectory(osx_LibDir, NULL)); FileMakeDir(dir_name); fl_filename_expand(dir_name, OSX_UserDomainDirectory(osx_LibAppSupportDir, NULL)); FileMakeDir(dir_name); fl_filename_expand(dir_name, OSX_UserDomainDirectory(osx_LibCacheDir, NULL)); FileMakeDir(dir_name); #endif // try to create home_dir (doesn't matter if it already exists) FileMakeDir(home_dir); FileMakeDir(cache_dir); static const char *const subdirs[] = { // these under $cache_dir "cache", "backups", // these under $home_dir "iwads", "games", "ports", "mods", NULL }; for (int i = 0 ; subdirs[i] ; i++) { snprintf(dir_name, FL_PATH_MAX, "%s/%s", (i < 2) ? cache_dir : home_dir, subdirs[i]); dir_name[FL_PATH_MAX-1] = 0; FileMakeDir(dir_name); } } static void Determine_HomeDir(const char *argv0) { // already set by cmd-line option? if (! home_dir) { #if defined(WIN32) // get the %APPDATA% location // if that fails, use a folder at the EXE location TCHAR * path = StringNew(MAX_PATH); if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, path))) { strcat(path, "\\EurekaEditor"); home_dir = StringDup(path); } else { SYS_ASSERT(install_dir); home_dir = StringPrintf("%s\\app_data", install_dir); } if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path))) { strcat(path, "\\EurekaEditor"); cache_dir = StringDup(path); } StringFree(path); #elif defined(__APPLE__) char * path = StringNew(FL_PATH_MAX + 4); fl_filename_expand(path, OSX_UserDomainDirectory(osx_LibAppSupportDir, "eureka-editor")); home_dir = StringDup(path); fl_filename_expand(path, OSX_UserDomainDirectory(osx_LibCacheDir, "eureka-editor")); cache_dir = StringDup(path); StringFree(path); #else // UNIX char * path = StringNew(FL_PATH_MAX + 4); if (fl_filename_expand(path, "$HOME/.eureka")) home_dir = path; #endif } if (! home_dir) FatalError("Unable to find home directory!\n"); if (! cache_dir) cache_dir = home_dir; LogPrintf("Home dir: %s\n", home_dir); LogPrintf("Cache dir: %s\n", cache_dir); // create cache directory (etc) CreateHomeDirs(); // determine log filename log_file = StringPrintf("%s/logs.txt", home_dir); } static void Determine_InstallPath(const char *argv0) { // already set by cmd-line option? if (! install_dir) { #ifdef WIN32 install_dir = GetExecutablePath(argv0); #else static const char *prefixes[] = { "/usr/local", "/usr", "/opt", NULL }; for (int i = 0 ; prefixes[i] ; i++) { install_dir = StringPrintf("%s/share/eureka", prefixes[i]); const char *filename = StringPrintf("%s/games/doom2.ugh", install_dir); DebugPrintf("Trying install path: %s\n", install_dir); DebugPrintf(" looking for file: %s\n", filename); bool exists = FileExists(filename); StringFree(filename); if (exists) break; StringFree(install_dir); install_dir = NULL; } #endif } // fallback : look in current directory if (! install_dir) { if (FileExists("./games/doom2.ugh")) install_dir = "."; } if (! install_dir) FatalError("Unable to find install directory!\n"); LogPrintf("Install dir: %s\n", install_dir); } const char * DetermineGame(const char *iwad_name) { static char game_name[FL_PATH_MAX]; strcpy(game_name, fl_filename_name(iwad_name)); fl_filename_setext(game_name, ""); y_strlowr(game_name); return StringDup(game_name); } static bool DetermineIWAD() { if (Iwad_name && FilenameIsBare(Iwad_name)) { // a bare name (e.g. "heretic") is treated as a game name // make lowercase Iwad_name = StringDup(Iwad_name); y_strlowr((char *)Iwad_name); if (! M_CanLoadDefinitions("games", Iwad_name)) FatalError("Unsupported game: %s (no definition file)\n", Iwad_name); const char * path = M_QueryKnownIWAD(Iwad_name); if (! path) FatalError("Cannot find IWAD for game: %s\n", Iwad_name); Iwad_name = StringDup(path); } else if (Iwad_name) { // if extension is missing, add ".wad" if (! HasExtension(Iwad_name)) Iwad_name = ReplaceExtension(Iwad_name, "wad"); if (! Wad_file::Validate(Iwad_name)) FatalError("IWAD does not exist or is invalid: %s\n", Iwad_name); const char *game = DetermineGame(Iwad_name); if (! M_CanLoadDefinitions("games", game)) FatalError("Unsupported game: %s (no definition file)\n", Iwad_name); M_AddKnownIWAD(Iwad_name); M_SaveRecent(); } else { Iwad_name = M_PickDefaultIWAD(); if (Iwad_name) Iwad_name = StringDup(Iwad_name); else { if (! ProjectSetup(false /* new_project */, true /* is_startup */)) return false; } } return true; } static void DeterminePort() { // user supplied value? // an unknown name will error out during Main_LoadResources. if (Port_name) return; SYS_ASSERT(default_port); // ensure the 'default_port' value is OK if (! default_port[0]) { LogPrintf("WARNING: Default port is empty, resetting...\n"); default_port = DEFAULT_PORT_NAME; } if (! M_CanLoadDefinitions("ports", default_port)) { LogPrintf("WARNING: Default port '%s' is unknown, resetting...\n"); default_port = DEFAULT_PORT_NAME; } Port_name = default_port; } static const char * DetermineMod(const char *res_name) { static char mod_name[FL_PATH_MAX]; strcpy(mod_name, fl_filename_name(res_name)); fl_filename_setext(mod_name, ""); y_strlowr(mod_name); return StringDup(mod_name); } static const char * DetermineLevel() { // most of the logic here is to handle a numeric level number // e.g. -warp 15 // // DOOM 1 level number is 10 * episode + map, e.g. 23 --> E2M3 // (there is logic in command-line parsing to handle two numbers after -warp) int level_number = 0; if (Level_name && Level_name[0]) { if (! isdigit(Level_name[0])) return StringUpper(Level_name); level_number = atoi(Level_name); } for (int pass = 0 ; pass < 2 ; pass++) { Wad_file *wad = (pass == 0) ? edit_wad : game_wad; if (! wad) continue; short lev_idx; if (level_number > 0) { lev_idx = wad->FindLevelByNumber(level_number); if (lev_idx < 0) FatalError("Level '%d' not found (no matches)\n", level_number); } else { lev_idx = wad->FindFirstLevel(); if (lev_idx < 0) FatalError("No levels found in the %s!\n", (pass == 0) ? "PWAD" : "IWAD"); } Lump_c *lump = wad->GetLump(lev_idx); SYS_ASSERT(lump); return StringDup(lump->Name()); } // cannot get here return "XXX"; } /* this is only to prevent ESCAPE key from quitting */ int Main_key_handler(int event) { if (event != FL_SHORTCUT) return 0; if (Fl::event_key() == FL_Escape) { fl_beep(); return 1; } return 0; } static void Main_OpenWindow() { /* * Create the window */ Fl::visual(FL_DOUBLE | FL_RGB); if (gui_color_set == 0) { // use default colors } else if (gui_color_set == 1) { Fl::background(236, 232, 228); Fl::background2(255, 255, 255); Fl::foreground(0, 0, 0); } else { // custom colors Fl::background (RGB_RED(gui_custom_bg), RGB_GREEN(gui_custom_bg), RGB_BLUE(gui_custom_bg)); Fl::background2(RGB_RED(gui_custom_ig), RGB_GREEN(gui_custom_ig), RGB_BLUE(gui_custom_ig)); Fl::foreground (RGB_RED(gui_custom_fg), RGB_GREEN(gui_custom_fg), RGB_BLUE(gui_custom_fg)); } if (gui_scheme == 0) { // use default scheme } else if (gui_scheme == 1) { Fl::scheme("gtk+"); } else { Fl::scheme("plastic"); } #ifdef UNIX Fl_File_Icon::load_system_icons(); #endif int screen_w = Fl::w(); int screen_h = Fl::h(); LogPrintf("Detected Screen Size: %dx%d\n", screen_w, screen_h); KF = 1; #if 0 // TODO KF = 0; if (screen_w >= 1000) KF = 1; if (screen_w >= 1180) KF = 2; #endif KF_fonth = (14 + KF * 2); main_win = new UI_MainWin(); main_win->label("Eureka v" EUREKA_VERSION); // show window (pass some dummy arguments) { int argc = 1; char *argv[2]; argv[0] = StringDup("Eureka.exe"); argv[1] = NULL; main_win->show(argc, argv); } // kill the stupid bright background of the "plastic" scheme if (gui_scheme == 2) { delete Fl::scheme_bg_; Fl::scheme_bg_ = NULL; main_win->image(NULL); } Fl::check(); if (begin_maximized) main_win->Maximize(); log_viewer = new UI_LogViewer(); LogOpenWindow(); Fl::add_handler(Main_key_handler); main_win->ShowBrowser(0); main_win->NewEditMode(edit.mode); Fl::check(); } static void TermFLTK() { } // used for 'New Map' / 'Open Map' functions too bool Main_ConfirmQuit(const char *action) { if (! MadeChanges) return true; char buttons[200]; sprintf(buttons, "Cancel|&%s", action); // convert action string like "open a new map" to a simple "Open" // string for the yes choice. buttons[8] = toupper(buttons[8]); char *p = strchr(buttons, ' '); if (p) *p = 0; if (DLG_Confirm(buttons, "You have unsaved changes. " "Do you really want to %s?", action) == 1) { return true; } return false; } void Main_Loop() { UpdateHighlight(); for (;;) { Fl::wait(0.2); if (want_quit) { if (Main_ConfirmQuit("quit")) break; want_quit = false; } // TODO: handle these in a better way main_win->UpdateTitle(MadeChanges ? '*' : 0); main_win->scroll->UpdateRenderMode(); main_win->scroll->UpdateBounds(); if (edit.Selected->empty()) edit.error_mode = false; } } static void LoadResourceFile(const char *filename) { // support loading "ugh" definitions if (MatchExtension(filename, "ugh")) { M_ParseDefinitionFile(filename); return; } if (! Wad_file::Validate(filename)) FatalError("Resource does not exist: %s\n", filename); Wad_file *wad = Wad_file::Open(filename, 'r'); if (! wad) FatalError("Cannot load resource: %s\n", filename); MasterDir_Add(wad); // load corresponding mod file (if it exists) const char *mod_name = DetermineMod(filename); if (M_CanLoadDefinitions("mods", mod_name)) { M_LoadDefinitions("mods", mod_name); } } void Main_LoadResources() { LogPrintf("\n"); LogPrintf("----- Loading Resources -----\n"); // Load game definitions (*.ugh) M_InitDefinitions(); Game_name = DetermineGame(Iwad_name); LogPrintf("IWAD name: '%s'\n", Iwad_name); LogPrintf("Game name: '%s'\n", Game_name); M_LoadDefinitions("games", Game_name); SYS_ASSERT(Port_name); LogPrintf("Port name: '%s'\n", Port_name); M_LoadDefinitions("ports", Port_name); // reset the master directory if (edit_wad) MasterDir_Remove(edit_wad); MasterDir_CloseAll(); // Load the IWAD (read only) game_wad = Wad_file::Open(Iwad_name, 'r'); if (! game_wad) FatalError("Failed to open game IWAD: %s\n", Iwad_name); MasterDir_Add(game_wad); // Load all resource wads for (int i = 0 ; i < (int)Resource_list.size() ; i++) { LoadResourceFile(Resource_list[i]); } if (edit_wad) MasterDir_Add(edit_wad); // finally, load textures and stuff... W_LoadPalette(); W_LoadColormap(); W_LoadFlats(); W_LoadTextures(); W_ClearSprites(); LogPrintf("--- DONE ---\n"); LogPrintf("\n"); if (main_win) { main_win->UpdateGameInfo(); main_win->browser->Populate(); // TODO: only call this when the IWAD has changed Props_LoadValues(); } } /* ----- user information ----------------------------- */ static void ShowHelp() { printf( "\n" "*** " EUREKA_TITLE " v" EUREKA_VERSION " (C) 2016 Andrew Apted, et al ***\n" "\n"); printf( "Eureka is free software, under the terms of the GNU General\n" "Public License (GPL), and comes with ABSOLUTELY NO WARRANTY.\n" "Home page: http://eureka-editor.sf.net/\n" "\n"); printf( "USAGE: eureka [options...] [FILE...]\n" "\n" "Available options are:\n"); dump_command_line_options(stdout); fflush(stdout); } static void ShowVersion() { printf("Eureka version " EUREKA_VERSION " (" __DATE__ ")\n"); fflush(stdout); } static void ShowTime() { #ifdef WIN32 SYSTEMTIME sys_time; GetSystemTime(&sys_time); LogPrintf("Current time: %02d:%02d on %04d/%02d/%02d\n", sys_time.wHour, sys_time.wMinute, sys_time.wYear, sys_time.wMonth, sys_time.wDay); #else // LINUX or MACOSX time_t epoch_time; struct tm *calend_time; if (time(&epoch_time) == (time_t)-1) return; calend_time = localtime(&epoch_time); if (! calend_time) return; LogPrintf("Current time: %02d:%02d on %04d/%02d/%02d\n", calend_time->tm_hour, calend_time->tm_min, calend_time->tm_year + 1900, calend_time->tm_mon + 1, calend_time->tm_mday); #endif } /* * the driving program */ int main(int argc, char *argv[]) { init_progress = 0; int r; // a quick pass through the command line arguments // to handle special options, like --help, --install, --config r = M_ParseCommandLine(argc - 1, argv + 1, 1); if (r) exit(3); if (show_help) { ShowHelp(); return 0; } else if (show_version) { ShowVersion(); return 0; } //printf ("%s\n", what ()); init_progress = 1; LogPrintf("\n"); LogPrintf("*** " EUREKA_TITLE " v" EUREKA_VERSION " (C) 2016 Andrew Apted, et al ***\n"); LogPrintf("\n"); // Sanity checks (useful when porting). check_types(); ShowTime(); Determine_InstallPath(argv[0]); Determine_HomeDir(argv[0]); LogOpenFile(log_file); // a config file can provides some values M_ParseConfigFile(); if (r == 0) { // environment variables can override them r = M_ParseEnvironmentVars(); } if (r == 0) { // and command line arguments will override both r = M_ParseCommandLine(argc - 1, argv + 1, 2); } if (r != 0) { // FIXME fprintf(stderr, "Error parsing config or cmd-line options.\n"); exit(1); } init_progress = 2; M_LoadRecent(); M_LookForIWADs(); Editor_Init(); Main_OpenWindow(); init_progress = 3; M_LoadBindings(); // open a specified PWAD now // [ the map is loaded later.... ] if (Pwad_list.size() > 0) { M_ValidateGivenFiles(); Pwad_name = Pwad_list[0]; edit_wad = Wad_file::Open(Pwad_name, 'a'); if (! edit_wad) FatalError("Cannot load pwad: %s\n", Pwad_name); // Note: the Main_LoadResources() call will ensure this gets // placed at the correct spot (at the end) MasterDir_Add(edit_wad); } else if (auto_load_recent && ! (Iwad_name || Level_name)) { M_TryOpenMostRecent(); } // Handle the '__EUREKA' lump. It is almost equivalent to using the // -iwad, -merge and -port command line options, but with extra // checks (to allow editing a wad containing dud information). // // Note: there is logic in M_ParseEurekaLump() to ensure that command // line arguments can override the EUREKA_LUMP values. if (edit_wad) { if (! M_ParseEurekaLump(edit_wad, true /* keep_cmd_line_args */)) { // user cancelled the load RemoveEditWad(); } } DeterminePort(); // determine which IWAD to use if (! DetermineIWAD()) goto quit; Main_LoadResources(); // load the initial level Level_name = DetermineLevel(); LogPrintf("Loading initial map : %s\n", Level_name); LoadLevel(edit_wad ? edit_wad : game_wad, Level_name); Main_Loop(); quit: /* that's all folks! */ LogPrintf("Quit\n"); init_progress = 2; TermFLTK(); init_progress = 0; MasterDir_CloseAll(); LogClose(); return 0; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_vertex.cc0000644000175100017510000000571612647061302016610 0ustar aaptedaapted//------------------------------------------------------------------------ // VERTEX PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2015 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 "main.h" #include "ui_window.h" #include "levels.h" #include "m_game.h" #include "w_rawdef.h" // // UI_VertexBox Constructor // UI_VertexBox::UI_VertexBox(int X, int Y, int W, int H, const char *label) : Fl_Group(X, Y, W, H, label), obj(-1), count(0) { box(FL_FLAT_BOX); X += 6; Y += 6; W -= 12; H -= 10; int MX = X + W/2; which = new UI_Nombre(X+6, Y, W-12, 28, "Vertex"); Y += which->h() + 4; pos_x = new Fl_Int_Input(X + 44, Y, 75, 24, "x: "); pos_y = new Fl_Int_Input(MX + 14, Y, 75, 24, "y: "); pos_x->align(FL_ALIGN_LEFT); pos_y->align(FL_ALIGN_LEFT); pos_x->callback(x_callback, this); pos_y->callback(y_callback, this); Y += pos_y->h() + 4; resizable(NULL); end(); } // // UI_VertexBox Destructor // UI_VertexBox::~UI_VertexBox() { } int UI_VertexBox::handle(int event) { return Fl_Group::handle(event); } void UI_VertexBox::x_callback(Fl_Widget *w, void *data) { UI_VertexBox *box = (UI_VertexBox *)data; int new_x = atoi(box->pos_x->value()); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) BA_ChangeVT(*it, Vertex::F_X, new_x); BA_End(); } } void UI_VertexBox::y_callback(Fl_Widget *w, void *data) { UI_VertexBox *box = (UI_VertexBox *)data; int new_y = atoi(box->pos_y->value()); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) BA_ChangeVT(*it, Vertex::F_Y, new_y); BA_End(); } } //------------------------------------------------------------------------ void UI_VertexBox::SetObj(int _index, int _count) { if (obj == _index && count == _count) return; obj = _index; count = _count; which->SetIndex(obj); which->SetSelected(count); UpdateField(); redraw(); } void UI_VertexBox::UpdateField() { if (is_vertex(obj)) { pos_x->value(Int_TmpStr(Vertices[obj]->x)); pos_y->value(Int_TmpStr(Vertices[obj]->y)); } else { pos_x->value(""); pos_y->value(""); } } void UI_VertexBox::UpdateTotal() { which->SetTotal(NumVertices); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_scroll.h0000644000175100017510000000520612647061302016425 0ustar aaptedaapted//------------------------------------------------------------------------ // A decent scrolling widget //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2013 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 __EUREKA_UI_SCROLL_H__ #define __EUREKA_UI_SCROLL_H__ #define SBAR_W 16 class UI_Scroll : public Fl_Group { private: Fl_Scrollbar * scrollbar; bool resize_horiz_; int top_y, bottom_y; public: UI_Scroll(int X, int Y, int W, int H); virtual ~UI_Scroll(); /* FLTK methods */ void resize(int X, int Y, int W, int H); int handle(int event); public: void resize_horiz(bool r) { resize_horiz_ = r; } void Add(Fl_Widget *w); void Remove(Fl_Widget *w); void Remove_first(); void Remove_all(); int Children() const; Fl_Widget * Child(int i) const; void Init_sizes(); void Line_size(int pixels); // delta is positive to move further down the list, negative to // move further up. Its absolute value can be: // 1 : scroll by a small amount // 2 : scroll by one "line" // 3 : scroll to next/previous page // 4 : scroll to end void Scroll(int delta); private: void do_scroll(); void calc_extents(); void reposition_all(int start_y); static void bar_callback(Fl_Widget *, void *); }; //------------------------------------------------------------------------ class UI_Canvas; class UI_Render3D; class UI_CanvasScroll : public Fl_Group { public: UI_Canvas * canvas; UI_Render3D * render; private: Fl_Scrollbar * horiz; Fl_Scrollbar * vert; bool enable_bars; int bound_x1, bound_x2; int bound_y1, bound_y2; int last_bounds[4]; public: UI_CanvasScroll(int X, int Y, int W, int H); virtual ~UI_CanvasScroll(); public: void UpdateRenderMode(); void UpdateBounds(); void AdjustPos(); private: void Adjust_X(); void Adjust_Y(); void UpdateBounds_X(); void UpdateBounds_Y(); void Scroll_X(); // callback helpers void Scroll_Y(); static void bar_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_SCROLL_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_loadsave.cc0000644000175100017510000010222712651521054016673 0ustar aaptedaapted//------------------------------------------------------------------------ // LEVEL LOAD / SAVE / NEW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 2015 Ioan Chera // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "e_basis.h" #include "e_loadsave.h" #include "e_checks.h" #include "levels.h" // CalculateLevelBounds() #include "lib_adler.h" #include "m_config.h" #include "m_files.h" #include "w_rawdef.h" #include "w_wad.h" #include "ui_window.h" #include "ui_file.h" int last_given_file; static void SaveLevel(Wad_file *wad, const char *level); static const char * overwrite_message = "The %s PWAD already contains this map. " "This operation will destroy that map (overwrite it)." "\n\n" "Are you sure you want to continue?"; static void FreshLevel() { BA_ClearAll(); Sector *sec = new Sector; Sectors.push_back(sec); sec->SetDefaults(); for (int i = 0 ; i < 4 ; i++) { Vertex *v = new Vertex; Vertices.push_back(v); v->x = (i >= 2) ? 256 : -256; v->y = (i==1 || i==2) ? 256 :-256; SideDef *sd = new SideDef; SideDefs.push_back(sd); sd->SetDefaults(false); LineDef *ld = new LineDef; LineDefs.push_back(ld); ld->start = i; ld->end = (i+1) % 4; ld->flags = MLF_Blocking; ld->right = i; } for (int pl = 1 ; pl <= 4 ; pl++) { Thing *th = new Thing; Things.push_back(th); th->type = pl; th->angle = 90; th->x = (pl == 1) ? 0 : (pl - 3) * 48; th->y = (pl == 1) ? 48 : (pl == 3) ? -48 : 0; } CalculateLevelBounds(); } extern void CMD_ZoomWholeMap(); void RemoveEditWad(); static bool Project_New() { SYS_ASSERT(! edit_wad); // determine map name (same as first level in the IWAD) const char *map_name = "MAP01"; short idx = game_wad->FindFirstLevel(); if (idx >= 0) { Lump_c * lump = game_wad->GetLump(idx); map_name = lump->Name(); } Fl_Native_File_Chooser chooser; chooser.title("Pick file to create"); chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); chooser.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM); chooser.filter("Wads\t*.wad"); //?? chooser.directory("xxx"); // Show native chooser switch (chooser.show()) { case -1: LogPrintf("New Project: error choosing file:\n"); LogPrintf(" %s\n", chooser.errmsg()); DLG_Notify("Unable to create a new project:\n\n%s", chooser.errmsg()); return false; case 1: LogPrintf("New Project: cancelled by user\n"); return false; default: break; // OK } // if extension is missing then add ".wad" char filename[FL_PATH_MAX]; strcpy(filename, chooser.filename()); char *pos = (char *)fl_filename_ext(filename); if (! *pos) strcat(filename, ".wad"); // delete the file if it already exists // (the file chooser should have asked the user for confirmation) if (FileExists(filename)) { // TODO M_BackupWad(wad); if (! FileDelete(filename)) { DLG_Notify("Unable to delete the existing file."); return false; } } LogPrintf("Creating New File : %s of %s\n", map_name, filename); Wad_file * wad = Wad_file::Open(filename, 'w'); if (! wad) { DLG_Notify("Unable to create the new WAD file."); return false; } edit_wad = wad; Pwad_name = edit_wad->PathName(); MasterDir_Add(edit_wad); FreshLevel(); CMD_ZoomWholeMap(); SaveLevel(edit_wad, map_name); M_AddRecent(edit_wad->PathName(), Level_name); MadeChanges = 0; return true; } bool ProjectSetup(bool new_project, bool is_startup) { if (new_project) { if (! Main_ConfirmQuit("create a new project")) return false; } UI_ProjectSetup * dialog = new UI_ProjectSetup(new_project, is_startup); bool ok = dialog->Run(); if (ok) { // grab new information Iwad_name = StringDup(dialog->iwad); Port_name = StringDup(dialog->port); Resource_list.clear(); for (int i = 0 ; i < UI_ProjectSetup::RES_NUM ; i++) { if (dialog->res[i]) Resource_list.push_back(StringDup(dialog->res[i])); } } delete dialog; Fl::wait(0.1); Fl::wait(0.1); if (! ok) return false; if (is_startup) return true; if (! new_project) { Main_LoadResources(); return true; } RemoveEditWad(); Main_LoadResources(); return Project_New(); } void CMD_NewMap() { if (! Main_ConfirmQuit("create a new map")) return; if (! edit_wad || edit_wad->IsReadOnly()) { ProjectSetup(true /* new_project */); return; } UI_ChooseMap * dialog = new UI_ChooseMap(Level_name); dialog->PopulateButtons(toupper(Level_name[0]), edit_wad); const char *map_name = dialog->Run(); delete dialog; // cancelled? if (! map_name) return; // would this replace an existing map? if (edit_wad->FindLevel(map_name) >= 0) { if (DLG_Confirm("Cancel|&Overwrite", overwrite_message, "current") <= 0) { return; } } M_BackupWad(edit_wad); LogPrintf("Created NEW map : %s\n", map_name); FreshLevel(); CMD_ZoomWholeMap(); // save it now : sets Level_name and window title SaveLevel(edit_wad, map_name); M_AddRecent(edit_wad->PathName(), Level_name); MadeChanges = 0; } //------------------------------------------------------------------------ // LOADING CODE //------------------------------------------------------------------------ static Wad_file * load_wad; static short loading_level; static int bad_linedef_count; static int bad_sector_refs; static int bad_sidedef_refs; static void UpperCaseShortStr(char *buf, int max_len) { for (int i = 0 ; (i < max_len) && buf[i] ; i++) { buf[i] = toupper(buf[i]); } } static void LoadVertices() { Lump_c *lump = load_wad->FindLumpInLevel("VERTEXES", loading_level); if (! lump) FatalError("No vertex lump!\n"); if (! lump->Seek()) FatalError("Error seeking to vertex lump!\n"); int count = lump->Length() / sizeof(raw_vertex_t); # if DEBUG_LOAD PrintDebug("GetVertices: num = %d\n", count); # endif Vertices.reserve(count); for (int i = 0 ; i < count ; i++) { raw_vertex_t raw; if (! lump->Read(&raw, sizeof(raw))) FatalError("Error reading vertices.\n"); Vertex *vert = new Vertex; vert->x = LE_S16(raw.x); vert->y = LE_S16(raw.y); Vertices.push_back(vert); } } static void LoadSectors() { Lump_c *lump = load_wad->FindLumpInLevel("SECTORS", loading_level); if (! lump) FatalError("No sector lump!\n"); if (! lump->Seek()) FatalError("Error seeking to sector lump!\n"); int count = lump->Length() / sizeof(raw_sector_t); # if DEBUG_LOAD PrintDebug("GetSectors: num = %d\n", count); # endif Sectors.reserve(count); for (int i = 0 ; i < count ; i++) { raw_sector_t raw; if (! lump->Read(&raw, sizeof(raw))) FatalError("Error reading sectors.\n"); Sector *sec = new Sector; sec->floorh = LE_S16(raw.floorh); sec->ceilh = LE_S16(raw.ceilh); UpperCaseShortStr(raw.floor_tex, 8); UpperCaseShortStr(raw. ceil_tex, 8); sec->floor_tex = BA_InternaliseShortStr(raw.floor_tex, 8); sec->ceil_tex = BA_InternaliseShortStr(raw.ceil_tex, 8); sec->light = LE_U16(raw.light); sec->type = LE_U16(raw.type); sec->tag = LE_S16(raw.tag); Sectors.push_back(sec); } } static void CreateFallbackSector() { LogPrintf("Creating a fallback sector.\n"); Sector *sec = new Sector; sec->SetDefaults(); Sectors.push_back(sec); } static void LoadHeader() { Lump_c *lump = load_wad->GetLump(loading_level); int length = lump->Length(); if (length == 0) return; HeaderData.resize(length); if (! lump->Seek()) FatalError("Error seeking to header lump!\n"); if (! lump->Read(& HeaderData[0], length)) FatalError("Error reading header lump.\n"); } static void LoadBehavior() { // IOANCH 9/2015: support Hexen maps Lump_c *lump = load_wad->FindLumpInLevel("BEHAVIOR", loading_level); if (! lump) FatalError("No BEHAVIOR lump!\n"); if (! lump->Seek()) FatalError("Error seeking to BEHAVIOR lump!\n"); int length = lump->Length(); BehaviorData.resize(length); if (length == 0) return; if (! lump->Read(& BehaviorData[0], length)) FatalError("Error reading BEHAVIOR.\n"); } static void LoadThings() { Lump_c *lump = load_wad->FindLumpInLevel("THINGS", loading_level); if (! lump) FatalError("No things lump!\n"); if (! lump->Seek()) FatalError("Error seeking to things lump!\n"); int count = lump->Length() / sizeof(raw_thing_t); # if DEBUG_LOAD PrintDebug("GetThings: num = %d\n", count); # endif for (int i = 0 ; i < count ; i++) { raw_thing_t raw; if (! lump->Read(&raw, sizeof(raw))) FatalError("Error reading things.\n"); Thing *th = new Thing; th->x = LE_S16(raw.x); th->y = LE_S16(raw.y); th->angle = LE_U16(raw.angle); th->type = LE_U16(raw.type); th->options = LE_U16(raw.options); Things.push_back(th); } } // IOANCH 9/2015 static void LoadThings_Hexen() { Lump_c *lump = load_wad->FindLumpInLevel("THINGS", loading_level); if (! lump) FatalError("No things lump!\n"); if (! lump->Seek()) FatalError("Error seeking to things lump!\n"); int count = lump->Length() / sizeof(raw_hexen_thing_t); # if DEBUG_LOAD PrintDebug("GetThings: num = %d\n", count); # endif for (int i = 0; i < count; ++i) { raw_hexen_thing_t raw; if (! lump->Read(&raw, sizeof(raw))) FatalError("Error reading things.\n"); Thing *th = new Thing; th->tid = LE_S16(raw.tid); th->x = LE_S16(raw.x); th->y = LE_S16(raw.y); th->z = LE_S16(raw.height); th->angle = LE_U16(raw.angle); th->type = LE_U16(raw.type); th->options = LE_U16(raw.options); th->special = raw.special; th->arg1 = raw.args[0]; th->arg2 = raw.args[1]; th->arg3 = raw.args[2]; th->arg4 = raw.args[3]; th->arg5 = raw.args[4]; Things.push_back(th); } } static void LoadSideDefs() { Lump_c *lump = load_wad->FindLumpInLevel("SIDEDEFS", loading_level); if (! lump) FatalError("No sidedefs lump!\n"); if (! lump->Seek()) FatalError("Error seeking to sidedefs lump!\n"); int count = lump->Length() / sizeof(raw_sidedef_t); # if DEBUG_LOAD PrintDebug("GetSidedefs: num = %d\n", count); # endif for (int i = 0 ; i < count ; i++) { raw_sidedef_t raw; if (! lump->Read(&raw, sizeof(raw))) FatalError("Error reading sidedefs.\n"); SideDef *sd = new SideDef; sd->x_offset = LE_S16(raw.x_offset); sd->y_offset = LE_S16(raw.y_offset); UpperCaseShortStr(raw.upper_tex, 8); UpperCaseShortStr(raw.lower_tex, 8); UpperCaseShortStr(raw. mid_tex, 8); sd->upper_tex = BA_InternaliseShortStr(raw.upper_tex, 8); sd->lower_tex = BA_InternaliseShortStr(raw.lower_tex, 8); sd-> mid_tex = BA_InternaliseShortStr(raw. mid_tex, 8); sd->sector = LE_U16(raw.sector); if (sd->sector >= NumSectors) { LogPrintf("WARNING: sidedef #%d has bad sector ref (%d)\n", i, sd->sector); bad_sector_refs++; // ensure we have a valid sector if (NumSectors == 0) CreateFallbackSector(); sd->sector = 0; } SideDefs.push_back(sd); } } static void CreateFallbackSideDef() { LogPrintf("Creating a fallback sidedef.\n"); SideDef *sd = new SideDef; sd->SetDefaults(false); SideDefs.push_back(sd); } static void ValidateSidedefs(LineDef * ld) { if (ld->right == 0xFFFF) ld->right = -1; if (ld-> left == 0xFFFF) ld-> left = -1; // validate sidedefs if (ld->right >= NumSideDefs || ld->left >= NumSideDefs) { LogPrintf("WARNING: linedef #%d has bad sidedef ref (%d, %d)\n", ld->right, ld->left); bad_sidedef_refs++; if (ld->right >= NumSideDefs) ld->right = (ld->left == 0) ? 1 : 0; if (ld->left >= NumSideDefs) ld->left = (ld->right == 1) ? 0 : 1; } } static void LoadLineDefs() { Lump_c *lump = load_wad->FindLumpInLevel("LINEDEFS", loading_level); if (! lump) FatalError("No linedefs lump!\n"); if (! lump->Seek()) FatalError("Error seeking to linedefs lump!\n"); int count = lump->Length() / sizeof(raw_linedef_t); # if DEBUG_LOAD PrintDebug("GetLinedefs: num = %d\n", count); # endif if (count == 0) return; if (NumSideDefs < 2) CreateFallbackSideDef(); if (NumSideDefs < 2) CreateFallbackSideDef(); for (int i = 0 ; i < count ; i++) { raw_linedef_t raw; if (! lump->Read(&raw, sizeof(raw))) FatalError("Error reading linedefs.\n"); LineDef *ld = new LineDef; ld->start = LE_U16(raw.start); ld->end = LE_U16(raw.end); // validate vertices if (ld->start >= NumVertices || ld->end >= NumVertices || ld->start == ld->end) { LogPrintf("WARNING: linedef #%d has bad vertex ref (%d, %d)\n", ld->start, ld->end); bad_linedef_count++; // forget it delete ld; continue; } ld->flags = LE_U16(raw.flags); ld->type = LE_U16(raw.type); ld->tag = LE_S16(raw.tag); ld->right = LE_U16(raw.right); ld->left = LE_U16(raw.left); ValidateSidedefs(ld); LineDefs.push_back(ld); } } // IOANCH 9/2015 static void LoadLineDefs_Hexen() { Lump_c *lump = load_wad->FindLumpInLevel("LINEDEFS", loading_level); if (! lump) FatalError("No linedefs lump!\n"); if (! lump->Seek()) FatalError("Error seeking to linedefs lump!\n"); int count = lump->Length() / sizeof(raw_hexen_linedef_t); # if DEBUG_LOAD PrintDebug("GetLinedefs: num = %d\n", count); # endif if (count == 0) return; if (NumSideDefs < 2) CreateFallbackSideDef(); if (NumSideDefs < 2) CreateFallbackSideDef(); for (int i = 0 ; i < count ; i++) { raw_hexen_linedef_t raw; if (! lump->Read(&raw, sizeof(raw))) FatalError("Error reading linedefs.\n"); LineDef *ld = new LineDef; ld->start = LE_U16(raw.start); ld->end = LE_U16(raw.end); // validate vertices if (ld->start >= NumVertices || ld->end >= NumVertices || ld->start == ld->end) { LogPrintf("WARNING: linedef #%d has bad vertex ref (%d, %d)\n", ld->start, ld->end); bad_linedef_count++; // forget it delete ld; continue; } ld->flags = LE_U16(raw.flags); ld->type = raw.type; ld->tag = raw.args[0]; ld->arg2 = raw.args[1]; ld->arg3 = raw.args[2]; ld->arg4 = raw.args[3]; ld->arg5 = raw.args[4]; ld->right = LE_U16(raw.right); ld->left = LE_U16(raw.left); ValidateSidedefs(ld); LineDefs.push_back(ld); } } static void RemoveUnusedVerticesAtEnd() { if (NumVertices == 0) return; bitvec_c used_verts(NumVertices); for (int i = 0 ; i < NumLineDefs ; i++) { used_verts.set(LineDefs[i]->start); used_verts.set(LineDefs[i]->end); } int new_count = NumVertices; while (new_count > 2 && !used_verts.get(new_count-1)) new_count--; // we directly modify the vertex array here (which is not // normally kosher, but level loading is a special case). if (new_count < NumVertices) { LogPrintf("Removing %d unused vertices at end\n", new_count); for (int i = new_count ; i < NumVertices ; i++) delete Vertices[i]; Vertices.resize(new_count); } } static void ShowLoadProblem() { LogPrintf("Map load problems:\n"); LogPrintf(" %d linedefs with bad vertex refs (removed)\n", bad_linedef_count); LogPrintf(" %d linedefs with bad sidedef refs\n", bad_sidedef_refs); LogPrintf(" %d sidedefs with bad sector refs\n", bad_sector_refs); static char message[MSG_BUF_LEN]; if (bad_linedef_count > 0) { sprintf(message, "Found %d linedefs with bad vertex references.\n" "These linedefs have been removed.", bad_linedef_count); } else { sprintf(message, "Found %d bad sector refs, %d bad sidedef refs.\n" "These references have been replaced.", bad_sector_refs, bad_sidedef_refs); } DLG_Notify("Map validation report:\n\n%s", message); } /* read in the level data */ void LoadLevel(Wad_file *wad, const char *level) { load_wad = wad; loading_level = load_wad->FindLevel(level); if (loading_level < 0) FatalError("No such map: %s\n", level); Level_format = load_wad->LevelFormat(loading_level); BA_ClearAll(); bad_linedef_count = 0; bad_sector_refs = 0; bad_sidedef_refs = 0; LoadHeader(); if (Level_format == MAPF_Hexen) LoadThings_Hexen(); else LoadThings(); LoadVertices(); LoadSectors(); LoadSideDefs(); if (Level_format == MAPF_Hexen) { LoadLineDefs_Hexen(); LoadBehavior(); } else { LoadLineDefs(); } if (bad_linedef_count || bad_sector_refs || bad_sidedef_refs) { ShowLoadProblem(); } // Node builders create a lot of new vertices for segs. // However they just get in the way for editing, so remove them. RemoveUnusedVerticesAtEnd(); SideDefs_Unpack(true); // TODO: CONFIG ITEM? SideDefs_NormalizeMiddles(); CalculateLevelBounds(); // reset various editor state Editor_ClearAction(); Selection_InvalidateLast(); edit.Selected->clear_all(); edit.highlight.clear(); RedrawMap(); main_win->UpdateTotals(); main_win->UpdateGameInfo(); main_win->InvalidatePanelObj(); main_win->redraw(); MadeChanges = 0; Level_name = StringUpper(level); Status_Set("Loaded %s", Level_name); if (main_win) { main_win->SetTitle(wad->PathName(), level, load_wad->IsReadOnly()); // load the user state associated with this map crc32_c adler_crc; BA_LevelChecksum(adler_crc); if (! M_LoadUserState()) { M_DefaultUserState(); } } } void RemoveEditWad() { if (! edit_wad) return; MasterDir_Remove(edit_wad); delete edit_wad; edit_wad = NULL; Pwad_name = NULL; } bool CMD_OpenMap() { if (! Main_ConfirmQuit("open another map")) return false; Wad_file *wad = NULL; const char *map_name = NULL; bool is_new_pwad = false; UI_OpenMap * dialog = new UI_OpenMap(); dialog->Run(&wad, &is_new_pwad, &map_name); delete dialog; // cancelled? if (! wad) return false; // this shouldn't happen -- but just in case... if (wad->FindLevel(map_name) < 0) { DLG_Notify("Hmmmm, cannot find that map !?!"); return false; } if (is_new_pwad && wad->FindLump(EUREKA_LUMP)) { if (! M_ParseEurekaLump(wad)) return false; } // has this removed or replaced the currently edited wad? if (edit_wad && (wad != edit_wad)) { RemoveEditWad(); } if (is_new_pwad) { edit_wad = wad; Pwad_name = edit_wad->PathName(); MasterDir_Add(edit_wad); Main_LoadResources(); } LogPrintf("Loading Map : %s of %s\n", map_name, wad->PathName()); LoadLevel(wad, map_name); return true; } void CMD_OpenFileMap(const char *filename, const char *map_name) { if (! Main_ConfirmQuit("open another map")) return; Wad_file *wad = NULL; // make sure the file exists [Open with 'a' would create it] // TODO: perhaps check this when building the Pwad_list // [however, 'eureka foo.wad' should fatal error if no foo.wad] if (FileExists(filename)) { wad = Wad_file::Open(filename, 'a'); } if (! wad) { // FIXME: get an error message, add it here DLG_Notify("Unable to open that WAD file."); return; } int lev_idx = -1; if (map_name) { lev_idx = wad->FindLevel(map_name); if (lev_idx < 0) { // FIXME: WARN ?? ERROR ?? } } if (lev_idx < 0) { map_name = NULL; lev_idx = wad->FindFirstLevel(); } if (lev_idx < 0) { delete wad; DLG_Notify("No levels found in that WAD."); return; } // IOANCH 9/2015: support Hexen, too if (wad->FindLump(EUREKA_LUMP)) { if (! M_ParseEurekaLump(wad)) return; } // OK, open it // this wad replaces the current PWAD RemoveEditWad(); edit_wad = wad; Pwad_name = edit_wad->PathName(); MasterDir_Add(edit_wad); Main_LoadResources(); if (! map_name) { Lump_c *lump = wad->GetLump(lev_idx); map_name = lump->Name(); } LogPrintf("Loading Map : %s of %s\n", map_name, wad->PathName()); LoadLevel(wad, map_name); } void CMD_GivenFile() { const char *mode = EXEC_Param[0]; int index = last_given_file; if (! mode[0] || y_stricmp(mode, "current") == 0) { // index = index + 0; } else if (y_stricmp(mode, "next") == 0) { index = index + 1; } else if (y_stricmp(mode, "prev") == 0) { index = index - 1; } else if (y_stricmp(mode, "first") == 0) { index = 0; } else if (y_stricmp(mode, "last") == 0) { index = (int)Pwad_list.size() - 1; } else { Beep("GivenFile: unknown keyword: %s", mode); return; } if (index < 0 || index >= (int)Pwad_list.size()) { Beep("No more files"); return; } last_given_file = index; // TODO: remember last map visited in this wad CMD_OpenFileMap(Pwad_list[index], NULL); } void CMD_FlipMap() { const char *mode = EXEC_Param[0]; if (! mode[0]) { Beep("FlipMap: missing keyword"); return; } if (! Main_ConfirmQuit("open another map")) return; Wad_file *wad = edit_wad ? edit_wad : game_wad; // the level might not be found (lev_idx < 0) -- that is OK int lev_idx = wad->FindLevel_Raw(Level_name); int max_idx = wad->NumLevels() - 1; if (max_idx < 0) { Beep("No maps ?!?"); return; } SYS_ASSERT(lev_idx <= max_idx); if (y_stricmp(mode, "next") == 0) { if (lev_idx < 0) lev_idx = 0; else if (lev_idx < max_idx) lev_idx++; else { Beep("No more maps"); return; } } else if (y_stricmp(mode, "prev") == 0) { if (lev_idx < 0) lev_idx = max_idx; else if (lev_idx > 0) lev_idx--; else { Beep("No more maps"); return; } } else if (y_stricmp(mode, "first") == 0) { lev_idx = 0; } else if (y_stricmp(mode, "last") == 0) { lev_idx = max_idx; } else { Beep("FlipMap: unknown keyword: %s", mode); return; } SYS_ASSERT(lev_idx >= 0); SYS_ASSERT(lev_idx <= max_idx); short lump_idx = wad->GetLevel(lev_idx); Lump_c * lump = wad->GetLump(lump_idx); const char *map_name = lump->Name(); LogPrintf("Flipping Map to : %s\n", map_name); LoadLevel(wad, map_name); } //------------------------------------------------------------------------ // SAVING CODE //------------------------------------------------------------------------ static Wad_file *save_wad; static void SaveHeader(const char *level) { int size = (int)HeaderData.size(); Lump_c *lump = save_wad->AddLevel(level, size); if (size > 0) { lump->Write(& HeaderData[0], size); } lump->Finish(); } static void SaveBehavior() { int size = (int)BehaviorData.size(); Lump_c *lump = save_wad->AddLump("BEHAVIOR", size); if (size > 0) { lump->Write(& BehaviorData[0], size); } lump->Finish(); } static void SaveVertices() { int size = NumVertices * (int)sizeof(raw_vertex_t); Lump_c *lump = save_wad->AddLump("VERTEXES", size); for (int i = 0 ; i < NumVertices ; i++) { Vertex *vert = Vertices[i]; raw_vertex_t raw; raw.x = LE_S16(vert->x); raw.y = LE_S16(vert->y); lump->Write(&raw, sizeof(raw)); } lump->Finish(); } static void SaveSectors() { int size = NumSectors * (int)sizeof(raw_sector_t); Lump_c *lump = save_wad->AddLump("SECTORS", size); for (int i = 0 ; i < NumSectors ; i++) { Sector *sec = Sectors[i]; raw_sector_t raw; raw.floorh = LE_S16(sec->floorh); raw.ceilh = LE_S16(sec->ceilh); strncpy(raw.floor_tex, sec->FloorTex(), sizeof(raw.floor_tex)); strncpy(raw.ceil_tex, sec->CeilTex(), sizeof(raw.ceil_tex)); raw.light = LE_U16(sec->light); raw.type = LE_U16(sec->type); raw.tag = LE_U16(sec->tag); lump->Write(&raw, sizeof(raw)); } lump->Finish(); } static void SaveThings() { int size = NumThings * (int)sizeof(raw_thing_t); Lump_c *lump = save_wad->AddLump("THINGS", size); for (int i = 0 ; i < NumThings ; i++) { Thing *th = Things[i]; raw_thing_t raw; raw.x = LE_S16(th->x); raw.y = LE_S16(th->y); raw.angle = LE_U16(th->angle); raw.type = LE_U16(th->type); raw.options = LE_U16(th->options); lump->Write(&raw, sizeof(raw)); } lump->Finish(); } // IOANCH 9/2015 static void SaveThings_Hexen() { int size = NumThings * (int)sizeof(raw_hexen_thing_t); Lump_c *lump = save_wad->AddLump("THINGS", size); for (int i = 0 ; i < NumThings ; i++) { Thing *th = Things[i]; raw_hexen_thing_t raw; raw.tid = LE_S16(th->tid); raw.x = LE_S16(th->x); raw.y = LE_S16(th->y); raw.height = LE_S16(th->z); raw.angle = LE_U16(th->angle); raw.type = LE_U16(th->type); raw.options = LE_U16(th->options); raw.special = th->special; raw.args[0] = th->arg1; raw.args[1] = th->arg2; raw.args[2] = th->arg3; raw.args[3] = th->arg4; raw.args[4] = th->arg5; lump->Write(&raw, sizeof(raw)); } lump->Finish(); } static void SaveSideDefs() { int size = NumSideDefs * (int)sizeof(raw_sidedef_t); Lump_c *lump = save_wad->AddLump("SIDEDEFS", size); for (int i = 0 ; i < NumSideDefs ; i++) { SideDef *side = SideDefs[i]; raw_sidedef_t raw; raw.x_offset = LE_S16(side->x_offset); raw.y_offset = LE_S16(side->y_offset); strncpy(raw.upper_tex, side->UpperTex(), sizeof(raw.upper_tex)); strncpy(raw.lower_tex, side->LowerTex(), sizeof(raw.lower_tex)); strncpy(raw.mid_tex, side->MidTex(), sizeof(raw.mid_tex)); raw.sector = LE_U16(side->sector); lump->Write(&raw, sizeof(raw)); } lump->Finish(); } static void SaveLineDefs() { int size = NumLineDefs * (int)sizeof(raw_linedef_t); Lump_c *lump = save_wad->AddLump("LINEDEFS", size); for (int i = 0 ; i < NumLineDefs ; i++) { LineDef *ld = LineDefs[i]; raw_linedef_t raw; raw.start = LE_U16(ld->start); raw.end = LE_U16(ld->end); raw.flags = LE_U16(ld->flags); raw.type = LE_U16(ld->type); raw.tag = LE_S16(ld->tag); raw.right = (ld->right >= 0) ? LE_U16(ld->right) : 0xFFFF; raw.left = (ld->left >= 0) ? LE_U16(ld->left) : 0xFFFF; lump->Write(&raw, sizeof(raw)); } lump->Finish(); } // IOANCH 9/2015 static void SaveLineDefs_Hexen() { int size = NumLineDefs * (int)sizeof(raw_hexen_linedef_t); Lump_c *lump = save_wad->AddLump("LINEDEFS", size); for (int i = 0 ; i < NumLineDefs ; i++) { LineDef *ld = LineDefs[i]; raw_hexen_linedef_t raw; raw.start = LE_U16(ld->start); raw.end = LE_U16(ld->end); raw.flags = LE_U16(ld->flags); raw.type = ld->type; raw.args[0] = ld->tag; raw.args[1] = ld->arg2; raw.args[2] = ld->arg3; raw.args[3] = ld->arg4; raw.args[4] = ld->arg5; raw.right = (ld->right >= 0) ? LE_U16(ld->right) : 0xFFFF; raw.left = (ld->left >= 0) ? LE_U16(ld->left) : 0xFFFF; lump->Write(&raw, sizeof(raw)); } lump->Finish(); } static void EmptyLump(const char *name) { save_wad->AddLump(name)->Finish(); } static void SaveLevel(Wad_file *wad, const char *level) { save_wad = wad; save_wad->BeginWrite(); // remove previous version of level (if it exists) int level_lump = save_wad->FindLevel(level); if (level_lump >= 0) save_wad->RemoveLevel(level_lump); save_wad->InsertPoint(level_lump); SaveHeader(level); // IOANCH 9/2015: save Hexen format maps if (Level_format == MAPF_Hexen) { SaveThings_Hexen(); SaveLineDefs_Hexen(); } else { SaveThings(); SaveLineDefs(); } SaveSideDefs(); SaveVertices(); EmptyLump("SEGS"); EmptyLump("SSECTORS"); EmptyLump("NODES"); SaveSectors(); EmptyLump("REJECT"); EmptyLump("BLOCKMAP"); if (Level_format == MAPF_Hexen) SaveBehavior(); // write out the new directory save_wad->EndWrite(); M_WriteEurekaLump(save_wad); Level_name = StringUpper(level); Status_Set("Saved %s -- NO NODES", Level_name); if (main_win) { main_win->SetTitle(wad->PathName(), level, false); // save the user state associated with this map M_SaveUserState(); } } bool CMD_SaveMap() { // we require a wad file to save into. // if there is none, then need to create one via Export function. if (! edit_wad) { return CMD_ExportMap(); } if (edit_wad->IsReadOnly()) { if (DLG_Confirm("Cancel|&Export", "The current pwad is a READ-ONLY file. " "Do you want to export this map into a new file?") <= 0) { return false; } else return CMD_ExportMap(); } M_BackupWad(edit_wad); LogPrintf("Saving Map : %s of %s\n", Level_name, edit_wad->PathName()); SaveLevel(edit_wad, Level_name); M_AddRecent(edit_wad->PathName(), Level_name); MadeChanges = 0; return true; } bool CMD_ExportMap() { Fl_Native_File_Chooser chooser; chooser.title("Pick file to export to"); chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); chooser.filter("Wads\t*.wad"); //?? chooser.directory("xxx"); // Show native chooser switch (chooser.show()) { case -1: LogPrintf("Export Map: error choosing file:\n"); LogPrintf(" %s\n", chooser.errmsg()); DLG_Notify("Unable to export the map:\n\n%s", chooser.errmsg()); return false; case 1: LogPrintf("Export Map: cancelled by user\n"); return false; default: break; // OK } // if extension is missing then add ".wad" char filename[FL_PATH_MAX]; strcpy(filename, chooser.filename()); char *pos = (char *)fl_filename_ext(filename); if (! *pos) strcat(filename, ".wad"); // does the file already exist? if not, create it... bool exists = FileExists(filename); Wad_file *wad; if (exists) { wad = Wad_file::Open(filename, 'a'); if (wad && wad->IsReadOnly()) { DLG_Notify("Cannot export the map into a READ-ONLY file."); delete wad; return false; } } else { wad = Wad_file::Open(filename, 'w'); } if (! wad) { DLG_Notify("Unable to export the map:\n\n%s", "Error creating output file"); return false; } // ask user for map name UI_ChooseMap * dialog = new UI_ChooseMap(Level_name); dialog->PopulateButtons(toupper(Level_name[0]), wad); const char *map_name = dialog->Run(); delete dialog; // cancelled? if (! map_name) { delete wad; return false; } // we will write into the chosen wad. // however if the level already exists, get confirmation first if (exists && wad->FindLevel(map_name) >= 0) { if (DLG_Confirm("Cancel|&Overwrite", overwrite_message, "selected") <= 0) { delete wad; return false; } } // back-up an existing wad if (exists) { M_BackupWad(wad); } LogPrintf("Exporting Map : %s of %s\n", map_name, wad->PathName()); SaveLevel(wad, map_name); M_AddRecent(wad->PathName(), map_name); // the new wad replaces the current PWAD if (edit_wad) { MasterDir_Remove(edit_wad); delete edit_wad; } edit_wad = wad; Pwad_name = edit_wad->PathName(); MasterDir_Add(edit_wad); MadeChanges = 0; return true; } //------------------------------------------------------------------------ // RENAME and DELETE //------------------------------------------------------------------------ void CMD_RenameMap() { if (! edit_wad) { DLG_Notify("Cannot rename a map unless editing a PWAD."); return; } if (edit_wad->IsReadOnly()) { DLG_Notify("Cannot rename map : file is read-only."); return; } // ask user for map name UI_ChooseMap * dialog = new UI_ChooseMap(Level_name, edit_wad /* rename_wad */); // pick level format from the IWAD // [ user may be trying to rename map after changing the IWAD ] char format = 'M'; { short idx = game_wad->FindFirstLevel(); if (idx >= 0) { Lump_c * lump = game_wad->GetLump(idx); const char *name = lump->Name(); format = toupper(name[0]); } } dialog->PopulateButtons(format, edit_wad); const char *new_name = dialog->Run(); delete dialog; // cancelled? if (! new_name) return; // sanity check that the name is different // (should be prevented by the choose-map dialog) if (y_stricmp(new_name, Level_name) == 0) { Beep("Name is same!?!"); return; } // perform the rename short level_lump = edit_wad->FindLevel(Level_name); if (level_lump >= 0) { edit_wad->BeginWrite(); edit_wad->RenameLump(level_lump, new_name); edit_wad->EndWrite(); } Level_name = StringUpper(new_name); main_win->SetTitle(edit_wad->PathName(), Level_name, false); Status_Set("Renamed to %s", Level_name); } void CMD_DeleteMap() { if (! edit_wad) { DLG_Notify("Cannot delete a map unless editing a PWAD."); return; } if (edit_wad->IsReadOnly()) { DLG_Notify("Cannot delete map : file is read-only."); return; } if (edit_wad->NumLevels() < 2) { // perhaps ask either to Rename map, or Delete the file (and Eureka will shut down) DLG_Notify("Cannot delete the last map in a PWAD."); return; } if (DLG_Confirm("Cancel|&Delete", "Are you sure you want to delete this map? " "It will be permanently removed from the current PWAD.") <= 0) { return; } LogPrintf("Deleting Map : %s...\n", Level_name); short level_lump = edit_wad->FindLevel(Level_name); short level_idx = edit_wad->FindLevel_Raw(Level_name); if (level_lump < 0 || level_idx < 0) { Beep("No such map ?!?"); return; } edit_wad->BeginWrite(); edit_wad->RemoveLevel(level_lump); edit_wad->EndWrite(); // choose a new level to load { if (level_idx >= edit_wad->NumLevels()) level_idx = edit_wad->NumLevels() - 1; short lump_idx = edit_wad->GetLevel(level_idx); Lump_c * lump = edit_wad->GetLump(lump_idx); const char *map_name = lump->Name(); LogPrintf("OK. Loading : %s....\n", map_name); LoadLevel(edit_wad, map_name); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_game.h0000644000175100017510000001217612647352316015673 0ustar aaptedaapted//------------------------------------------------------------------------ // GAME DEFINITION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_GAME_H__ #define __EUREKA_M_GAME_H__ #include "im_color.h" #include /* * Data structures for game definition data */ // linegroup typedef struct { char group; const char *desc; } linegroup_t; // line [ arg1 .. arg5 ] typedef struct { char group; const char *desc; const char *args[5]; } linetype_t; // sector typedef struct { const char *desc; } sectortype_t; // thinggroup typedef struct { char group; // group letter rgb_color_t color; // RGB colour const char *desc; // Description of thing group } thinggroup_t; // thing [] typedef struct { char group; // Thing group short flags; // Flags short radius; // Radius of thing const char *desc; // Short description of thing const char *sprite; // Root of name of sprite for thing rgb_color_t color; // RGB color (from group) } thingtype_t; typedef enum { THINGDEF_INVIS = (1 << 0), // partially invisible THINGDEF_CEIL = (1 << 1), // hangs from ceiling THINGDEF_LIT = (1 << 2), // always bright THINGDEF_PASS = (1 << 3), // non-blocking THINGDEF_VOID = (1 << 4), // can exist in the void THINGDEF_TELEPT = (1 << 5), // teleport dest, can overlap certain things } thingdef_flags_e; // texturegroup typedef struct { char group; const char *desc; } texturegroup_t; /* * Global variables that contain game definition data */ typedef struct { int sky_color; char sky_flat[16]; int wall_colors[2]; int floor_colors[2]; int missing_color; int unknown_tex; int unknown_flat; int player_h; int min_dm_starts; int max_dm_starts; /* port features */ int gen_types; // BOOM generalized linedefs and sectors int img_png; // PNG format for various graphics int tx_start; // textures in TX_START .. TX_END int coop_dm_flags; // MTF_NOT_COOP and MTF_NOT_DM for things int friend_flag; // MTF_FRIEND thing flag from MBF int pass_through; // Boom's MTF_PASSTHRU line flag int midtex_3d; // Eternity's ML_3DMIDTEX line flag int medusa_bug; // used for Vanilla, prone to the Medusa Effect } game_info_t; extern game_info_t game_info; /* Boom generalized types */ #define MAX_GEN_FIELD_BITS 4 #define MAX_GEN_FIELD_KEYWORDS (1 << MAX_GEN_FIELD_BITS) #define MAX_GEN_NUM_FIELDS 16 #define MAX_GEN_NUM_TYPES 16 typedef struct { int bits; // int mask; // the bit-field info int shift; // int default_val; const char *name; const char *keywords[MAX_GEN_FIELD_KEYWORDS]; int num_keywords; } generalized_field_t; typedef struct { char key; int base; int length; const char *name; generalized_field_t fields[MAX_GEN_NUM_FIELDS]; int num_fields; } generalized_linetype_t; extern generalized_linetype_t gen_linetypes[MAX_GEN_NUM_TYPES]; extern int num_gen_linetypes; //------------------------------------------------------------------------ void M_InitDefinitions(); void M_LoadDefinitions(const char *folder, const char *name, int include_level = 0); bool M_CanLoadDefinitions(const char *folder, const char *name); void M_ParseDefinitionFile(const char *filename, const char *folder = NULL, const char *basename = NULL, int include_level = 0); void M_FreeDefinitions(); void M_CollectKnownDefs(const char *folder, std::vector & list); const char * M_CollectDefsForMenu(const char *folder, int *exist_val, const char *exist_name); // is this flat a sky? bool is_sky(const char *flat); const sectortype_t * M_GetSectorType(int type); const linetype_t * M_GetLineType(int type); const thingtype_t * M_GetThingType(int type); char M_GetTextureType(const char *name); char M_GetFlatType(const char *name); const char *M_LineCategoryString(char *letters); const char *M_ThingCategoryString(char *letters); const char *M_TextureCategoryString(char *letters, bool do_flats); #endif /* __EUREKA_M_GAME_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_checks.h0000644000175100017510000000535712647061302016205 0ustar aaptedaapted//------------------------------------------------------------------------ // INTEGRITY CHECKS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_CHECKS_H__ #define __EUREKA_E_CHECKS_H__ #include "ui_window.h" void SideDefs_Unpack(bool no_history = false); void SideDefs_NormalizeMiddles(); void Tags_ApplyNewValue(int new_tag); void CMD_CheckMap(); void CMD_ApplyTag(); //------------------------------------------------------------------------ // the CHECK_xxx functions return the following values: typedef enum { CKR_OK = 0, // no issues at all CKR_MinorProblem, // only minor issues CKR_MajorProblem, // some major problems CKR_Highlight, // need to highlight stuff (skip further checks) CKR_TookAction // [internal use : user took some action] } check_result_e; class UI_Check_base : public UI_Escapable_Window { protected: bool want_close; check_result_e user_action; Fl_Group * line_group; int cy; int worst_severity; private: static void close_callback(Fl_Widget *, void *); public: UI_Check_base(int W, int H, bool all_mode, const char *L, const char *header_txt); virtual ~UI_Check_base(); void Reset(); void AddGap(int H); void AddLine(const char *msg, int severity = 0, int W = -1, const char *button1 = NULL, Fl_Callback *cb1 = NULL, const char *button2 = NULL, Fl_Callback *cb2 = NULL, const char *button3 = NULL, Fl_Callback *cb3 = NULL); check_result_e Run(); int WorstSeverity() const { return worst_severity; } }; check_result_e CHECK_LineDefs(int min_severity = 0); check_result_e CHECK_Textures(int min_severity = 0); check_result_e CHECK_Tags (int min_severity = 0); #endif /* __EUREKA_E_CHECKS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/w_loadpic.h0000644000175100017510000000323412647061302016372 0ustar aaptedaapted//------------------------------------------------------------------------ // WAD PIC LOADER //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_W_LOADPIC_H__ #define __EUREKA_W_LOADPIC_H__ #include "im_img.h" #include "w_wad.h" bool LoadPicture(Img_c& img, Lump_c *lump, /* Lump containing picture */ const char *pic_name, /* Picture name, for messages */ int pic_x_offset, /* Coordinates of top left corner of picture */ int pic_y_offset, /* relative to top left corner of buffer. */ int *pic_width = NULL, /* To return the size of the picture */ int *pic_height = NULL); /* (can be NULL) */ #endif /* __EUREKA_W_LOADPIC_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_default.h0000644000175100017510000000442212647061302016552 0ustar aaptedaapted//------------------------------------------------------------------------ // DEFAULT PROPERTIES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2015 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 __EUREKA_UI_DEFAULT_H__ #define __EUREKA_UI_DEFAULT_H__ class UI_DefaultProps : public Fl_Group { private: UI_Pic *w_pic; Fl_Input *w_tex; Fl_Int_Input *ceil_h; Fl_Int_Input *light; Fl_Int_Input *floor_h; Fl_Button *ce_down, *ce_up; Fl_Button *fl_down, *fl_up; Fl_Input *c_tex; UI_Pic *c_pic; Fl_Input *f_tex; UI_Pic *f_pic; Fl_Int_Input *thing; Fl_Output *th_desc; UI_Pic *th_sprite; public: UI_DefaultProps(int X, int Y, int W, int H); virtual ~UI_DefaultProps(); void BrowsedItem(char kind, int number, const char *name, int e_state); void UnselectPics(); void LoadValues(); private: void SetIntVal(Fl_Int_Input *w, int value); void UpdateThingDesc(); void SetTexture(const char *name, int e_state); void SetFlat(const char *name, int e_state); void SetThing(int number); void UnselectPicSet(char what /* 'f' or 't' */); static const char * NormalizeTex_and_Dup(Fl_Input *w); static void hide_callback(Fl_Widget *w, void *data); static void tex_callback(Fl_Widget *w, void *data); static void flat_callback(Fl_Widget *w, void *data); static void button_callback(Fl_Widget *w, void *data); static void height_callback(Fl_Widget *w, void *data); static void thing_callback(Fl_Widget *w, void *data); }; bool Props_ParseUser(const char ** tokens, int num_tok); void Props_WriteUser(FILE *fp); void Props_LoadValues(); #endif /* __EUREKA_UI_DEFAULT_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/main.h0000644000175100017510000001025312651120414015347 0ustar aaptedaapted//------------------------------------------------------------------------ // MAIN DEFINITIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_MAIN_H__ #define __EUREKA_MAIN_H__ #define EUREKA_TITLE "Eureka DOOM Editor" #define EUREKA_VERSION "1.11" #define EUREKA_LUMP "__EUREKA" /* * Standard headers */ #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include #endif #include #include #include #include #include #include #include #include #include #ifndef WIN32 #include #endif #include /* * Additional libraries */ #include "hdr_fltk.h" /* * Commonly-used headers */ #include "sys_type.h" #include "sys_macro.h" #include "sys_endian.h" #include "sys_debug.h" #include "objid.h" #include "m_bitvec.h" #include "m_select.h" #include "lib_util.h" #include "lib_file.h" #include "e_basis.h" #include "m_keys.h" #include "objects.h" /* * Miscellaneous */ typedef std::vector< const char * > string_list_t; typedef enum { MAPF_INVALID = 0, MAPF_Doom, MAPF_Hexen } map_format_e; /* * Interfile global variables */ extern int init_progress; extern bool want_quit; extern const char *install_dir; // install dir (e.g. /usr/share/eureka) extern const char *home_dir; // home dir (e.g. $HOME/.eureka) extern const char *cache_dir; // for caches and backups, can be same as home_dir extern const char *Game_name; // Name of game "doom", "doom2", "heretic", ... extern const char *Port_name; // Name of source port "vanilla", "boom", ... extern const char *Level_name; // Name of map lump we are editing extern map_format_e Level_format; // format of current map extern const char *config_file; // Name of the configuration file, or NULL extern const char *log_file; // Name of log file, or NULL extern const char *Iwad_name; // Name of the iwad extern const char *Pwad_name; extern std::vector< const char * > Pwad_list; extern std::vector< const char * > Resource_list; extern int default_floor_h; extern int default_ceil_h; extern int default_light_level; extern int default_thing; extern const char * default_floor_tex; extern const char * default_ceil_tex; extern const char * default_lower_tex; extern const char * default_mid_tex; extern const char * default_upper_tex; extern int show_help; // Print usage message and exit. extern int show_version; // Print version info and exit. extern int scroll_less;// %s of screenful to scroll by extern int scroll_more;// %s of screenful to scroll by extern int KF; // Kromulent Factor extern int KF_fonth; // default font size /* * Various global functions */ bool Main_ConfirmQuit(const char *action); void Main_LoadResources(); #ifdef __GNUC__ __attribute__((noreturn)) #endif void FatalError(const char *fmt, ...); #define BugError FatalError void DLG_ShowError(const char *msg, ...); void DLG_Notify(const char *msg, ...); int DLG_Confirm(const char *buttons, const char *msg, ...); const char * DetermineGame(const char *iwad_name); void Beep(const char *msg, ...); void Status_Set(const char *fmt, ...); void Status_Clear(); #endif /* __EUREKA_MAIN_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/x_loop.cc0000644000175100017510000003776512651054135016110 0ustar aaptedaapted//------------------------------------------------------------------------ // LINE LOOP HANDLING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include "levels.h" #include "objects.h" #include "m_bitvec.h" #include "e_linedef.h" #include "w_rawdef.h" #include "x_loop.h" #include "x_hover.h" // #define DEBUG_PATH 1 lineloop_c::lineloop_c() : lines(), sides(), faces_outward(false), islands() { } lineloop_c::~lineloop_c() { clear(); } void lineloop_c::clear() { lines.clear(); sides.clear(); faces_outward = false; for (unsigned int i = 0 ; i < islands.size() ; i++) delete islands[i]; islands.clear(); } void lineloop_c::push_back(int ld, int side) { lines.push_back(ld); sides.push_back(side); } bool lineloop_c::get(int ld, int side) const { for (unsigned int k = 0 ; k < lines.size() ; k++) if (lines[k] == ld && sides[k] == side) return true; for (unsigned int i = 0 ; i < islands.size() ; i++) if (islands[i]->get(ld, side)) return true; return false; } bool lineloop_c::get_just_line(int ld) const { for (unsigned int k = 0 ; k < lines.size() ; k++) if (lines[k] == ld) return true; for (unsigned int i = 0 ; i < islands.size() ; i++) if (islands[i]->get_just_line(ld)) return true; return false; } double lineloop_c::TotalLength() const { // NOTE: does NOT include islands double result = 0; for (unsigned int k = 0 ; k < lines.size() ; k++) { const LineDef *L = LineDefs[lines[k]]; result += L->CalcLength(); } return result; } bool lineloop_c::SameSector(int *sec_num) const { // NOTE: does NOT include islands SYS_ASSERT(lines.size() > 0); int sec = LineDefs[lines[0]]->WhatSector(sides[0]); for (unsigned int k = 1 ; k < lines.size() ; k++) { if (sec != LineDefs[lines[k]]->WhatSector(sides[k])) return false; } if (sec_num) *sec_num = sec; return true; } bool lineloop_c::AllNew() const { int sec_num; if (! SameSector(&sec_num)) return false; return (sec_num < 0); } int lineloop_c::NeighboringSector() const { // pick the longest linedef with a sector on the other side // NOTE: it does not make sense to handle islands here. int best = -1; int best_len = -1; for (unsigned int i = 0 ; i < lines.size() ; i++) { const LineDef *L = LineDefs[lines[i]]; // we assume here that SIDE_RIGHT == 0 - SIDE_LEFT int sec = LineDefs[lines[i]]->WhatSector(- sides[i]); if (sec < 0) continue; int dx = L->Start()->x - L->End()->x; int dy = L->Start()->y - L->End()->y; int len = ComputeDist(dx, dy); if (len > best_len) { best = sec; best_len = len; } } return best; } int lineloop_c::FacesSector() const { // test is only valid for islands if (! faces_outward) return -1; // we might need to check multiple lines, as the first line could // be facing a linedef which is ALSO part of the island. for (unsigned int i = 0 ; i < lines.size() ; i++) { int opp_side; int opp = OppositeLineDef(lines[i], sides[i], &opp_side); // can see "the void" : outside of map if (opp < 0) return -1; // part of the island? if (get_just_line(opp)) continue; return LineDefs[opp]->WhatSector(opp_side); } return -1; } /* compute the angle between lines AB and BC, going anticlockwise. result is in degrees in the range [0, 360). A, B and C are vertex indices. -AJA- 2001-05-09 FIXME: move to e_linedef (or so) */ double AngleBetweenLines(int A, int B, int C) { int a_dx = Vertices[B]->x - Vertices[A]->x; int a_dy = Vertices[B]->y - Vertices[A]->y; int c_dx = Vertices[B]->x - Vertices[C]->x; int c_dy = Vertices[B]->y - Vertices[C]->y; double AB_angle = (a_dx == 0) ? (a_dy >= 0 ? 90 : -90) : atan2(a_dy, a_dx) * 180 / M_PI; double CB_angle = (c_dx == 0) ? (c_dy >= 0 ? 90 : -90) : atan2(c_dy, c_dx) * 180 / M_PI; double result = CB_angle - AB_angle; while (result >= 360.0) result -= 360.0; while (result < 0) result += 360.0; #if 0 // DEBUGGING DebugPrintf("ANGLE %1.6f (%d,%d) -> (%d,%d) -> (%d,%d)\n", result, Vertices[A].x, Vertices[A].y, Vertices[B].x, Vertices[B].y, Vertices[C].x, Vertices[C].y); #endif return result; } void lineloop_c::CalcBounds(int *x1, int *y1, int *x2, int *y2) const { SYS_ASSERT(lines.size() > 0); *x1 = +99999; *y1 = +99999; *x2 = -99999; *y2 = -99999; for (unsigned int i = 0 ; i < lines.size() ; i++) { const LineDef *L = LineDefs[lines[i]]; *x1 = MIN(*x1, MIN(L->Start()->x, L->End()->x)); *y1 = MIN(*y1, MIN(L->Start()->y, L->End()->y)); *x2 = MAX(*x2, MAX(L->Start()->x, L->End()->x)); *y2 = MAX(*y2, MAX(L->Start()->y, L->End()->y)); } } /* Follows the path clockwise from the given start line, adding each line into the appropriate set. Returns true if the path was closed, or false for failure (in which case the lineloop_c object will not be in a valid state). side is either SIDE_LEFT or SIDE_RIGHT. -AJA- 2001-05-09 */ bool TraceLineLoop(int ld, int side, lineloop_c& loop, bool ignore_new) { loop.clear(); int cur_vert; int prev_vert; if (side == SIDE_RIGHT) { cur_vert = LineDefs[ld]->end; prev_vert = LineDefs[ld]->start; } else { cur_vert = LineDefs[ld]->start; prev_vert = LineDefs[ld]->end; } int final_vert = prev_vert; #ifdef DEBUG_PATH DebugPrintf("TRACE PATH: line:%d side:%d cur:%d final:%d\n", ld, side, cur_vert, final_vert); #endif // compute the average angle double average_angle = 0; // add the starting line loop.push_back(ld, side); while (cur_vert != final_vert) { int next_line = -1; int next_vert = -1; int next_side = 0; double best_angle = 9999; // Look for the next linedef in the path. It's the linedef which // uses the current vertex, not the same as the current line, and // has the smallest interior angle. for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef * N = LineDefs[n]; if (N->start != cur_vert && N->end != cur_vert) continue; if (n == ld) continue; if (ignore_new && !N->Left() && !N->Right()) continue; int other_vert; int which_side; if (N->start == cur_vert) { other_vert = N->end; which_side = SIDE_RIGHT; } else // (N->end == cur_vert) { other_vert = N->start; which_side = SIDE_LEFT; } // found adjoining linedef double angle = AngleBetweenLines(prev_vert, cur_vert, other_vert); if (next_line < 0 || angle < best_angle) { next_line = n; next_vert = other_vert; next_side = which_side; best_angle = angle; } // continue the search... } #ifdef DEBUG_PATH DebugPrintf("PATH NEXT: line:%d side:%d vert:%d angle:%1.6f\n", next_line, next_side, next_vert, best_angle); #endif // No next line? Path cannot be closed if (next_line < 0) return false; // Line already seen? Under normal circumstances this won't // happen, but it _can_ happen and indicates a non-closed // structure if (loop.get_just_line(next_line)) return false; ld = next_line; side = next_side; prev_vert = cur_vert; cur_vert = next_vert; average_angle += best_angle; // add the next line loop.push_back(ld, side); } // this might happen if there are overlapping linedefs if (loop.lines.size() < 3) return false; average_angle = average_angle / (double)loop.lines.size(); loop.faces_outward = (average_angle >= 180.0); #ifdef DEBUG_PATH DebugPrintf("PATH CLOSED! average_angle:%1.2f\n", average_angle); #endif return true; } bool lineloop_c::LookForIsland() { // ALGORITHM: // Iterate over all lines which lie within the bounding box of // the current path (but not _in_ the current path). // // Use OppositeLineDef() to find starting lines, and trace them // (tracing is necessary because in certain shapes, the opposite // lines will be part of the island too). // // Returns: true if found one, false otherwise. // // calc bounding box int bb_x1, bb_y1, bb_x2, bb_y2; CalcBounds(&bb_x1, &bb_y1, &bb_x2, &bb_y2); // cut me some slack, dude bb_x1--; bb_y1--; bb_x2++; bb_y2++; int count = 0; for (int ld = 0 ; ld < NumLineDefs ; ld++) { const LineDef * L = LineDefs[ld]; int x1 = L->Start()->x; int y1 = L->Start()->y; int x2 = L->End()->x; int y2 = L->End()->y; if (MAX(x1, x2) < bb_x1 || MIN(x1, x2) > bb_x2 || MAX(y1, y2) < bb_y1 || MIN(y1, y2) > bb_y2) continue; // ouch, this is gonna be SLOW : O(n^2) on # lines for (int where = 0 ; where < 2 ; where++) { int ld_side = where ? SIDE_RIGHT : SIDE_LEFT; int opp_side; int opp = OppositeLineDef(ld, ld_side, &opp_side); if (opp < 0) continue; bool ld_in_path = get(ld, ld_side); bool opp_in_path = get(opp, opp_side); // nothing to do when both (or neither) are in path if (ld_in_path == opp_in_path) continue; #ifdef DEBUG_PATH DebugPrintf("Found line:%d side:%d <--> opp:%d opp_side:%d us:%d them:%d\n", ld, ld_side, opp, opp_side, ld_in_path?1:0, opp_in_path?1:0); #endif lineloop_c *island = new lineloop_c; bool ok; if (ld_in_path) ok = TraceLineLoop(opp, opp_side, *island); else ok = TraceLineLoop(ld, ld_side, *island); if (ok && island->faces_outward) { islands.push_back(island); count++; } else { delete island; } } } return (count > 0); } void lineloop_c::FindIslands() { // Look for "islands", closed linedef paths that lie completely // inside the area, i.e. not connected to the main path. // // Repeat these steps until no more islands are found. // (This is needed to handle e.g. a big room full of pillars, // since the pillars in the middle won't "see" the outer sector // until the neighboring pillars are added). // // Example: the two pillars at the start of MAP01 of DOOM 2. // use a counter for safety for (int loop = 200 ; loop >= 0 ; loop--) { if (loop == 0) BugError("Infinite loop in FindIslands!\n"); if (! LookForIsland()) break; } } void lineloop_c::Dump() const { DebugPrintf("Lineloop %p : %u lines, %u islands\n", this, lines.size(), islands.size()); for (unsigned int i = 0 ; i < lines.size() ; i++) { const LineDef *L = LineDefs[lines[i]]; DebugPrintf(" %s of line #%d : (%d %d) --> (%d %d)\n", sides[i] == SIDE_LEFT ? " LEFT" : "RIGHT", lines[i], L->Start()->x, L->Start()->y, L->End ()->x, L->End ()->y); } } // FIXME: move to e_linedef void LD_AddSecondSideDef(int ld, int new_sd, int other_sd) { LineDef * L = LineDefs[ld]; SideDef * SD = SideDefs[new_sd]; int new_flags = L->flags; new_flags |= MLF_TwoSided; new_flags &= ~MLF_Blocking; BA_ChangeLD(ld, LineDef::F_FLAGS, new_flags); // TODO: make this a global pseudo-constant int null_tex = BA_InternaliseString("-"); const SideDef *other = SideDefs[other_sd]; if (isalnum(other->MidTex()[0])) { SD->lower_tex = other->mid_tex; SD->upper_tex = other->mid_tex; BA_ChangeSD(other_sd, SideDef::F_LOWER_TEX, other->mid_tex); BA_ChangeSD(other_sd, SideDef::F_UPPER_TEX, other->mid_tex); BA_ChangeSD(other_sd, SideDef::F_MID_TEX, null_tex); } else { SD->lower_tex = other->lower_tex; SD->upper_tex = other->upper_tex; } } void LD_RemoveSideDef(int ld, int ld_side) { const LineDef *L = LineDefs[ld]; int gone_sd = (ld_side > 0) ? L->right : L->left; int other_sd = (ld_side > 0) ? L->left : L->right; if (ld_side > 0) BA_ChangeLD(ld, LineDef::F_RIGHT, -1); else BA_ChangeLD(ld, LineDef::F_LEFT, -1); if (other_sd < 0) return; // The line is changing from TWO SIDED --> ONE SIDED. // Hence we need to: // (1) clear the Two-Sided flag // (2) set the Impassible flag // (3) flip the linedef if right side was removed // (4) set the middle texture int new_flags = L->flags; new_flags &= ~MLF_TwoSided; new_flags |= MLF_Blocking; BA_ChangeLD(ld, LineDef::F_FLAGS, new_flags); // FIXME: if sidedef is shared, either don't modify it _OR_ duplicate it const SideDef *SD = SideDefs[other_sd]; int new_tex = BA_InternaliseString(default_mid_tex); // grab new texture from lower or upper if possible if (isalnum(SD->LowerTex()[0])) new_tex = SD->lower_tex; else if (isalnum(SD->UpperTex()[0])) new_tex = SD->upper_tex; else if (gone_sd >= 0) { SD = SideDefs[gone_sd]; if (isalnum(SD->LowerTex()[0])) new_tex = SD->lower_tex; else if (isalnum(SD->UpperTex()[0])) new_tex = SD->upper_tex; } BA_ChangeSD(other_sd, SideDef::F_MID_TEX, new_tex); } /* update the side on a single linedef, using the given sector reference. Will create a new sidedef if necessary. */ static void DoAssignSector(int ld, int side, int new_sec, selection_c& flip) { // DebugPrintf("DoAssignSector %d ---> line #%d, side %d\n", new_sec, ld, side); const LineDef * L = LineDefs[ld]; int sd_num = (side > 0) ? L->right : L->left; int other_sd = (side > 0) ? L->left : L->right; if (sd_num >= 0) { BA_ChangeSD(sd_num, SideDef::F_SECTOR, new_sec); return; } // if we're adding a sidedef to a line that has no sides, and // the sidedef would be the 2nd one, then flip the linedef. // Thus we don't end up with invalid lines -- i.e. ones with a // left side but no right side. if (side < 0 && other_sd < 0) { flip.set(ld); } // create new sidedef int new_sd = BA_New(OBJ_SIDEDEFS); SideDef * SD = SideDefs[new_sd]; SD->SetDefaults(other_sd >= 0); SD->sector = new_sec; if (side > 0) BA_ChangeLD(ld, LineDef::F_RIGHT, new_sd); else BA_ChangeLD(ld, LineDef::F_LEFT, new_sd); // if we're adding a second side to the linedef, clear out some // of the properties that aren't needed anymore: middle texture, // two-sided flag, and impassible flag. if (other_sd >= 0) LD_AddSecondSideDef(ld, new_sd, other_sd); } void AssignSectorToLoop(lineloop_c& loop, int new_sec, selection_c& flip) { for (unsigned int k = 0 ; k < loop.lines.size() ; k++) { int ld = loop.lines[k]; int side = loop.sides[k]; DoAssignSector(ld, side, new_sec, flip); } for (unsigned int i = 0 ; i < loop.islands.size() ; i++) { AssignSectorToLoop(* loop.islands[i], new_sec, flip); } } // // Change the closed sector at the pointer // // "sector" here really means a bunch of sidedefs that all face // inward to the current area under the mouse cursor. // void AssignSectorToSpace(int map_x, int map_y, int new_sec, bool model_from_neighbor) { int ld, side; ld = ClosestLine_CastingHoriz(map_x, map_y, &side); if (ld < 0) { Beep("Area is not closed"); DebugPrintf("Area is not closed (can see infinity)\n"); return; } lineloop_c loop; if (! TraceLineLoop(ld, side, loop)) { Beep("Area is not closed"); DebugPrintf("Area is not closed (tracing a loop failed)\n"); return; } // FIXME: should look in other directions for an inward line loop if (loop.faces_outward) { Beep("Line loop faces outward"); DebugPrintf("Line loop faces outward\n"); return; } loop.FindIslands(); if (model_from_neighbor) { int model = loop.NeighboringSector(); if (model >= 0) Sectors[new_sec]->RawCopy(Sectors[model]); else Sectors[new_sec]->SetDefaults(); } selection_c flip(OBJ_LINEDEFS); AssignSectorToLoop(loop, new_sec, flip); FlipLineDefGroup(flip); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_sector.h0000644000175100017510000000536212647117245016441 0ustar aaptedaapted//------------------------------------------------------------------------ // SECTOR PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 __EUREKA_UI_SECTOR_H__ #define __EUREKA_UI_SECTOR_H__ class UI_SectorBox : public Fl_Group { private: int obj; int count; public: UI_Nombre *which; Fl_Int_Input *type; Fl_Output *desc; Fl_Button *choose; Fl_Int_Input *light; Fl_Int_Input *tag; Fl_Button *lt_down, *lt_up; Fl_Int_Input *ceil_h; Fl_Int_Input *floor_h; Fl_Button *ce_down, *ce_up; Fl_Button *fl_down, *fl_up; Fl_Input *c_tex; UI_Pic *c_pic; Fl_Input *f_tex; UI_Pic *f_pic; Fl_Int_Input *headroom; enum { HEADROOM_BUTTONS = 6 }; Fl_Button * hd_buttons[HEADROOM_BUTTONS]; // Boom generalized sectors Fl_Box * bm_title; Fl_Choice * bm_damage; Fl_Check_Button * bm_secret; Fl_Check_Button * bm_friction; Fl_Check_Button * bm_wind; public: UI_SectorBox(int X, int Y, int W, int H, const char *label = NULL); virtual ~UI_SectorBox(); public: void SetObj(int _index, int _count); int GetObj() const { return obj; } // call this if the thing was externally changed. // -1 means "all fields" void UpdateField(int field = -1); void UpdateTotal(); void UpdateGameInfo(); void SetFlat(const char *name, int e_state); void SetSectorType(int new_type); // returns a bitmask: 1 for floor, 2 for ceiling int GetSelectedPics() const; void UnselectPics(); // this truncates the name and makes it uppercase, then returns // the internalised string. static int FlatFromWidget(Fl_Input *w); private: void AdjustHeight(s16_t *h, int delta); void AdjustLight (s16_t *L, int delta); static void height_callback(Fl_Widget *, void *); static void room_callback(Fl_Widget *, void *); static void tex_callback(Fl_Widget *, void *); static void type_callback(Fl_Widget *, void *); static void light_callback(Fl_Widget *, void *); static void tag_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_SECTOR_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_pic.cc0000644000175100017510000001263712647061302016046 0ustar aaptedaapted//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2013 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 "main.h" #include "ui_pic.h" #include "ui_window.h" #include "im_img.h" #include "im_color.h" #include "m_config.h" #include "m_game.h" #include "e_things.h" #include "w_rawdef.h" #include "w_flats.h" #include "w_sprite.h" #include "w_texture.h" // // UI_Pic Constructor // UI_Pic::UI_Pic(int X, int Y, int W, int H, const char *L) : Fl_Box(FL_BORDER_BOX, X, Y, W, H, ""), rgb(NULL), special(SP_None), selected(false) { color(FL_DARK2); what_text = StringDup(L); what_color = (gui_color_set == 1) ? (FL_GRAY0 + 4) : FL_BACKGROUND_COLOR; label(what_text); labelcolor(what_color); labelsize(16); align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER); } // // UI_Pic Destructor // UI_Pic::~UI_Pic() { StringFree(what_text); what_text = NULL; } void UI_Pic::Clear() { special = SP_None; color(FL_DARK2); labelcolor(what_color); labelsize(16); label(what_text); if (rgb) { delete rgb; rgb = NULL; } redraw(); } void UI_Pic::MarkUnknown() { Clear(); special = SP_Unknown; color(FL_CYAN); labelcolor(FL_BLACK); labelsize(40); label("?"); redraw(); } void UI_Pic::MarkMissing() { Clear(); special = SP_Missing; color(fl_rgb_color(255, 128, 0)); labelcolor(FL_BLACK); labelsize(40); label("!"); redraw(); } void UI_Pic::GetFlat(const char * fname) { TiledImg(W_GetFlat(fname), false /* has_trans */); } void UI_Pic::GetTex(const char * tname) { if (tname[0] == '-') { Clear(); return; } TiledImg(W_GetTexture(tname), true /* has_trans */); } void UI_Pic::GetSprite(int type, Fl_Color back_color) { // color(FL_GRAY0 + 2); Clear(); Img_c *img = W_GetSprite(type); if (! img || img->width() < 1 || img->height() < 1) { MarkUnknown(); return; } const thingtype_t *info = M_GetThingType(type); bool new_img = false; if (info->flags & THINGDEF_INVIS) { img = img->spectrify(); new_img = true; } u32_t back = Fl::get_color(back_color); int iw = img->width(); int ih = img->height(); int nw = w(); int nh = h(); int scale = 1; if (iw*3 < nw && ih*3 < nh) scale = 2; uchar *buf = new uchar[nw * nh * 3]; for (int y = 0 ; y < nh ; y++) for (int x = 0 ; x < nw ; x++) { int ix = x / scale - (nw / scale - iw) / 2; // int iy = (ih-1) - (nh-4 - y); int iy = y / scale - (nh / scale - ih) / 2; u32_t col = back; if (ix >= 0 && ix < iw && iy >= 0 && iy < ih) { img_pixel_t pix = img->buf() [iy*iw+ix]; if (pix != TRANS_PIXEL) col = palette[pix]; } // Black border if (x == 0 || x == nw-1 || y == 0 || y == nh-1) col = 0; byte *dest = buf + ((y*nw+x) * 3); dest[0] = RGB_RED(col); dest[1] = RGB_GREEN(col); dest[2] = RGB_BLUE(col); } UploadRGB(buf, 3); if (new_img) delete img; } void UI_Pic::TiledImg(Img_c *img, bool has_trans) { color(FL_DARK2); Clear(); if (! img || img->width() < 1 || img->height() < 1) { MarkUnknown(); return; } int iw = img->width(); int ih = img->height(); int nw = w(); int nh = h(); int scale = 1; while (nw*scale < iw || nh*scale < ih) scale = scale * 2; const u32_t back_col = 0x00FFFF00; // CYAN uchar *buf = new uchar[nw * nh * 3]; for (int y = 0 ; y < nh ; y++) for (int x = 0 ; x < nw ; x++) { int ix = (x * scale) % iw; int iy = (y * scale) % ih; img_pixel_t pix = img->buf() [iy*iw+ix]; u32_t col = back_col; if (! (has_trans && pix == TRANS_PIXEL)) col = palette[pix]; byte *dest = buf + ((y*nw+x) * 3); dest[0] = RGB_RED(col); dest[1] = RGB_GREEN(col); dest[2] = RGB_BLUE(col); } UploadRGB(buf, 3); } void UI_Pic::UploadRGB(const byte *buf, int depth) { rgb = new Fl_RGB_Image(buf, w(), h(), depth, 0); // HACK ALERT: make the Fl_RGB_Image class think it allocated // the buffer, so that it will get freed properly // by the Fl_RGB_Image destructor. rgb->alloc_array = true; // remove label label(""); special = SP_None; redraw(); } //------------------------------------------------------------------------ int UI_Pic::handle(int event) { switch (event) { case FL_ENTER: main_win->SetCursor(FL_CURSOR_HAND); return 1; case FL_LEAVE: main_win->SetCursor(FL_CURSOR_DEFAULT); return 1; case FL_PUSH: do_callback(); return 1; default: break; } return 0; // unused } void UI_Pic::draw() { if (rgb) rgb->draw(x(), y()); else Fl_Box::draw(); if (selected) draw_selected(); } void UI_Pic::draw_selected() { int X = x(); int Y = y(); int W = w(); int H = h(); fl_rect(X+0, Y+0, W-0, H-0, FL_RED); fl_rect(X+1, Y+1, W-2, H-2, FL_RED); fl_rect(X+2, Y+2, W-4, H-4, FL_BLACK); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_files.cc0000644000175100017510000005050612647061302016211 0ustar aaptedaapted//------------------------------------------------------------------------ // RECENT FILES / KNOWN IWADS / BACKUPS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2015 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 "main.h" #include "levels.h" #include "e_loadsave.h" #include "m_game.h" #include "w_wad.h" #include "ui_window.h" // list of known iwads (mapping GAME name --> PATH) static std::map known_iwads; void M_AddKnownIWAD(const char *path) { char absolute_name[FL_PATH_MAX]; fl_filename_absolute(absolute_name, path); const char *game = DetermineGame(path); known_iwads[game] = std::string(absolute_name); } const char * M_QueryKnownIWAD(const char *game) { std::map::iterator KI; KI = known_iwads.find(game); if (KI != known_iwads.end()) return KI->second.c_str(); else return NULL; } const char * M_KnownIWADsForMenu(int *exist_val, const char *exist_name) { exist_name = fl_filename_name(exist_name); std::map::iterator KI; static char result[2000]; result[0] = 0; int index = 0; for (KI = known_iwads.begin() ; KI != known_iwads.end() ; KI++, index++) { const char *name = KI->first.c_str(); strcat(result, "|"); strcat(result, name); /// strcat(result, ".wad"); if (y_stricmp(fl_filename_name(KI->second.c_str()), exist_name) == 0) *exist_val = index; } return StringDup(result + 1); } void M_ValidateGivenFiles() { for (int i = 0 ; i < (int)Pwad_list.size() ; i++) { if (! Wad_file::Validate(Pwad_list[i])) FatalError("Given pwad does not exist or is invalid: %s\n", Pwad_list[i]); } } int M_FindGivenFile(const char *filename) { for (int i = 0 ; i < (int)Pwad_list.size() ; i++) if (strcmp(Pwad_list[i], filename) == 0) return i; return -1; // Not Found } //------------------------------------------------------------------------ // RECENT FILE HANDLING //------------------------------------------------------------------------ #define MAX_RECENT 12 // this is for the 'File/Recent' menu class recent_file_data_c { public: const char *file; const char *map; public: recent_file_data_c(const char *_file, const char *_map) : file(_file), map(_map) { } recent_file_data_c() { } }; // recent filenames are never freed (atm), since they need to stay // around for the 'File/Recent' menu. #undef FREE_RECENT_FILES class RecentFiles_c { private: int size; // newest is at index [0] const char * filenames[MAX_RECENT]; const char * map_names[MAX_RECENT]; public: RecentFiles_c() : size(0) { memset(filenames, 0, sizeof(filenames)); memset(filenames, 0, sizeof(map_names)); } ~RecentFiles_c() { } int getSize() const { return size; } recent_file_data_c *getData(int index) const { SYS_ASSERT(0 <= index && index < size); return new recent_file_data_c(filenames[index], map_names[index]); } void clear() { for (int k = 0 ; k < size ; k++) { #ifdef FREE_RECENT_FILES StringFree(filenames[k]); StringFree(map_names[k]); #endif filenames[k] = NULL; map_names[k] = NULL; } size = 0; } int find(const char *file, const char *map = NULL) { // ignore the path when matching filenames const char *A = fl_filename_name(file); for (int k = 0 ; k < size ; k++) { const char *B = fl_filename_name(filenames[k]); if (y_stricmp(A, B) != 0) continue; if (! map || y_stricmp(map_names[k], map) == 0) return k; } return -1; // not found } void erase(int index) { SYS_ASSERT(0 <= index && index < MAX_RECENT); #ifdef FREE_RECENT_FILES StringFree(filenames[index]); StringFree(map_names[index]); #endif size--; SYS_ASSERT(size < MAX_RECENT); for ( ; index < size ; index++) { filenames[index] = filenames[index + 1]; map_names[index] = map_names[index + 1]; } filenames[index] = NULL; map_names[index] = NULL; } void push_front(const char *file, const char *map) { if (size >= MAX_RECENT) { erase(MAX_RECENT - 1); } // shift elements up for (int k = size - 1 ; k >= 0 ; k--) { filenames[k + 1] = filenames[k]; map_names[k + 1] = map_names[k]; } filenames[0] = StringDup(file); map_names[0] = StringDup(map); size++; } void insert(const char *file, const char *map) { // ensure filename (without any path) is unique int f = find(file); if (f >= 0) erase(f); push_front(file, map); } void WriteFile(FILE * fp) { // file is in opposite order, newest at the end // (this allows the parser to merely insert() items in the // order they are read). for (int k = size - 1 ; k >= 0 ; k--) { fprintf(fp, "recent %s %s\n", map_names[k], filenames[k]); } } void Format(char *buffer, int index) const { SYS_ASSERT(index < size); const char *name = fl_filename_name(filenames[index]); // const char *map = map_names[index]; sprintf(buffer, "%s%d. %-.42s", (index < 9) ? "&" : "", 1+index, name); } void Lookup(int index, const char ** file_v, const char ** map_v) { SYS_ASSERT(index >= 0); SYS_ASSERT(index < size); *file_v = filenames[index]; *map_v = map_names[index]; } }; static RecentFiles_c recent_files; static void ParseMiscConfig(FILE * fp) { static char line[FL_PATH_MAX]; static char * map; while (fgets(line, sizeof(line), fp) != NULL) { // comment? if (line[0] == '#') continue; StringRemoveCRLF(line); char *pos = strchr(line, ' '); if (! pos) { // FIXME warning continue; } *pos++ = 0; map = pos; pos = strchr(map, ' '); if (! pos) { // FIXME warning continue; } *pos++ = 0; if (strcmp(line, "recent") == 0) { if (Wad_file::Validate(pos)) recent_files.insert(pos, map); else LogPrintf(" no longer exists: %s\n", pos); } else if (strcmp(line, "known_iwad") == 0) { // ignore plain freedoom.wad (backwards compatibility) if (y_stricmp(map, "freedoom") == 0) LogPrintf(" ignoring for compatibility: %s\n", pos); else if (Wad_file::Validate(pos)) known_iwads[map] = std::string(pos); else LogPrintf(" no longer exists: %s\n", pos); } else { // FIXME: warning continue; } } } void M_LoadRecent() { static char filename[FL_PATH_MAX]; sprintf(filename, "%s/misc.cfg", home_dir); FILE *fp = fopen(filename, "r"); if (! fp) { LogPrintf("No recent list at: %s\n", filename); return; } LogPrintf("Reading recent list from: %s\n", filename); recent_files.clear(); known_iwads.clear(); ParseMiscConfig(fp); fclose(fp); } void M_SaveRecent() { static char filename[FL_PATH_MAX]; sprintf(filename, "%s/misc.cfg", home_dir); FILE *fp = fopen(filename, "w"); if (! fp) { LogPrintf("Failed to save recent list to: %s\n", filename); return; } LogPrintf("Writing recent list to: %s\n", filename); fprintf(fp, "# Eureka miscellaneous stuff\n"); recent_files.WriteFile(fp); // known iwad files std::map::iterator KI; for (KI = known_iwads.begin() ; KI != known_iwads.end() ; KI++) { fprintf(fp, "known_iwad %s %s\n", KI->first.c_str(), KI->second.c_str()); } fclose(fp); } int M_RecentCount() { return recent_files.getSize(); } void M_RecentShortName(int index, char *name_buf) { recent_files.Format(name_buf, index); } void * M_RecentData(int index) { return recent_files.getData(index); } void M_OpenRecentFromMenu(void *priv_data) { SYS_ASSERT(priv_data); recent_file_data_c *data = (recent_file_data_c *)priv_data; CMD_OpenFileMap(data->file, data->map); } void M_AddRecent(const char *filename, const char *map_name) { char absolute_name[FL_PATH_MAX]; fl_filename_absolute(absolute_name, filename); recent_files.insert(absolute_name, map_name); M_SaveRecent(); // why wait? } bool M_TryOpenMostRecent() { if (recent_files.getSize() == 0) return false; const char *filename; const char *map_name; recent_files.Lookup(0, &filename, &map_name); // M_LoadRecent has already validated the filename, so this should // normally work. Wad_file *wad = Wad_file::Open(filename, 'a'); if (! wad) { LogPrintf("Failed to load most recent pwad: %s\n", filename); return false; } // make sure at least one level can be loaded if (wad->NumLevels() == 0) { LogPrintf("No levels in most recent pwad: %s\n", filename); delete wad; return false; } // -- OK -- if (wad->FindLevel(map_name) >= 0) Level_name = map_name; else Level_name = NULL; Pwad_name = filename; edit_wad = wad; MasterDir_Add(edit_wad); return true; } //------------------------------------------------------------------------ // EUREKA LUMP HANDLING //------------------------------------------------------------------------ #ifdef WIN32 #define PATH_SEPARATOR ';' #else #define PATH_SEPARATOR ':' #endif static bool ExtractOnePath(const char *paths, char *dir, int index) { for (; index > 0 ; index--) { paths = strchr(paths, PATH_SEPARATOR); if (! paths) return false; paths++; } // handle a trailing separator if (! paths[0]) return NULL; int len; const char * sep_pos = strchr(paths, PATH_SEPARATOR); if (sep_pos) len = (int)(sep_pos - paths); else len = (int)strlen(paths); if (len > FL_PATH_MAX - 2) len = FL_PATH_MAX - 2; if (len == 0) // ouch return "."; // remove trailing slash while (len > 1 && paths[len - 1] == DIR_SEP_CH) len--; memcpy(dir, paths, len); dir[len] = 0; return dir; } static const char * SearchDirForIWAD(const char *dir_name, const char *game) { char name_buf[FL_PATH_MAX]; sprintf(name_buf, "%s/%s.wad", dir_name, game); DebugPrintf(" trying: %s\n", name_buf); if (Wad_file::Validate(name_buf)) return StringDup(name_buf); // try uppercasing the name, to find e.g. DOOM2.WAD y_strupr(name_buf + strlen(dir_name) + 1); DebugPrintf(" trying: %s\n", name_buf); if (Wad_file::Validate(name_buf)) return StringDup(name_buf); return NULL; } static const char * SearchForIWAD(const char *game) { DebugPrintf("Searching for '%s' IWAD\n", game); static char dir_name[FL_PATH_MAX]; // 1. look in ~/.eureka/iwads first snprintf(dir_name, FL_PATH_MAX, "%s/iwads", home_dir); dir_name[FL_PATH_MAX-1] = 0; const char * path = SearchDirForIWAD(dir_name, game); if (path) return path; // 2. look in $DOOMWADPATH const char *doomwadpath = getenv("DOOMWADPATH"); if (doomwadpath) { for (int i = 0 ; i < 999 ; i++) { if (! ExtractOnePath(doomwadpath, dir_name, i)) break; path = SearchDirForIWAD(dir_name, game); if (path) return path; } } // 3. look in $DOOMWADDIR const char *doomwaddir = getenv("DOOMWADDIR"); if (doomwaddir) { path = SearchDirForIWAD(StringDup(doomwaddir), game); if (path) return path; } // 4. look in various standard places /* WISH: check the Steam folder(s) for WIN32 */ static const char *standard_iwad_places[] = { #ifdef WIN32 "c:/doom", "c:/doom2", "c:/doom95", #else "/usr/share/games/doom", "/usr/share/doom", "/usr/local/share/games/doom", "/usr/local/games/doom", #endif NULL }; for (int i = 0 ; standard_iwad_places[i] ; i++) { path = SearchDirForIWAD(standard_iwad_places[i], game); if (path) return path; } // 5. last resort : the current directory path = SearchDirForIWAD(".", game); if (path) return path; return NULL; // not found } /* * search for iwads in various places */ void M_LookForIWADs() { LogPrintf("Looking for IWADs....\n"); string_list_t game_list; M_CollectKnownDefs("games", game_list); for (unsigned int i = 0 ; i < game_list.size() ; i++) { const char *game = game_list[i]; // already have it? if (M_QueryKnownIWAD(game)) continue; const char *path = SearchForIWAD(game); if (path) { LogPrintf("Found '%s' IWAD file: %s\n", game, path); M_AddKnownIWAD(path); } } M_SaveRecent(); } const char * M_PickDefaultIWAD() { // guess either DOOM or DOOM 2 based on level names const char *default_game = "doom2"; if (Level_name && toupper(Level_name[0]) == 'E') { default_game = "doom"; } else if (edit_wad) { int lev = edit_wad->FindFirstLevel(); const char *lev_name = ""; if (lev >= 0) { lev_name = edit_wad->GetLump(lev)->Name(); if (toupper(lev_name[0]) == 'E') default_game = "doom"; } } DebugPrintf("pick default iwad, trying: '%s'\n", default_game); const char *result; result = StringDup(M_QueryKnownIWAD(default_game)); if (result) return result; // try FreeDoom if (strcmp(default_game, "doom") == 0) default_game = "freedoom1"; else default_game = "freedoom2"; DebugPrintf("pick default iwad, trying: '%s'\n", default_game); result = StringDup(M_QueryKnownIWAD(default_game)); if (result) return result; // try any known iwad DebugPrintf("pick default iwad, trying first known iwad...\n"); std::map::iterator KI; KI = known_iwads.begin(); if (KI != known_iwads.end()) return StringDup(KI->second.c_str()); // nothing left to try DebugPrintf("pick default iwad failed.\n"); return NULL; } static void M_AddResource_Unique(const char * filename) { // check if base filename (without path) already exists for (unsigned int k = 0 ; k < Resource_list.size() ; k++) { const char *A = fl_filename_name(filename); const char *B = fl_filename_name(Resource_list[k]); if (y_stricmp(A, B) == 0) return; // found it } Resource_list.push_back(filename); } /* returns false if user wanted to cancel the load */ bool M_ParseEurekaLump(Wad_file *wad, bool keep_cmd_line_args) { LogPrintf("Parsing '%s' lump\n", EUREKA_LUMP); Lump_c * lump = wad->FindLump(EUREKA_LUMP); if (! lump) { LogPrintf("--> does not exist.\n"); return true; } if (! lump->Seek()) { LogPrintf("--> error seeking.\n"); return true; } const char * new_iwad = NULL; const char * new_port = NULL; std::vector< const char * > new_resources; static char line[FL_PATH_MAX]; while (lump->GetLine(line, sizeof(line))) { // comment? if (line[0] == '#') continue; StringRemoveCRLF(line); char *pos = strchr(line, ' '); if (! pos || pos == line) { LogPrintf("WARNING: bad syntax in %s lump\n", EUREKA_LUMP); continue; } *pos++ = 0; if (strcmp(line, "game") == 0) { if (! M_CanLoadDefinitions("games", pos)) { LogPrintf(" unknown game: %s\n", pos /* show full path */); int res = DLG_Confirm("&Ignore|&Cancel Load", "Warning: the pwad specifies an unsupported " "game:\n\n %s", pos); if (res == 1) return false; } else { new_iwad = StringDup(M_QueryKnownIWAD(pos)); if (! new_iwad) { int res = DLG_Confirm("&Ignore|&Cancel Load", "Warning: the pwad specifies an IWAD " "which cannot be found:\n\n %s.wad", pos); if (res == 1) return false; } } } else if (strcmp(line, "resource") == 0) { const char *res = pos; // if not found at absolute location, try same place as PWAD if (! FileExists(res)) { LogPrintf(" file not found: %s\n", pos); res = FilenameReposition(pos, wad->PathName()); LogPrintf(" trying: %s\n", res); } if (! FileExists(res) && new_iwad) { res = FilenameReposition(pos, new_iwad); LogPrintf(" trying: %s\n", res); } if (FileExists(res)) new_resources.push_back(StringDup(res)); else { DLG_Notify("Warning: the pwad specifies a resource " "which cannot be found:\n\n%s", pos); } } else if (strcmp(line, "port") == 0) { if (M_CanLoadDefinitions("ports", pos)) new_port = StringDup(pos); else { LogPrintf(" unknown port: %s\n", pos); DLG_Notify("Warning: the pwad specifies an unknown port:\n\n%s", pos); } } else { LogPrintf("WARNING: unknown keyword '%s' in %s lump\n", line, EUREKA_LUMP); continue; } } /* OK */ // When 'keep_cmd_line_args' is true, we do not override any value which // has been set via command line arguments. In other words, cmd line // arguments will override the EUREKA_LUMP. // // Resources are trickier, we merge the EUREKA_LUMP resources into the ones // supplied on the command line, ensuring that we don't get any duplicates. if (new_iwad) { if (! (keep_cmd_line_args && Iwad_name)) Iwad_name = new_iwad; } if (new_port) { if (! (keep_cmd_line_args && Port_name)) Port_name = new_port; } if (! keep_cmd_line_args) Resource_list.clear(); for (unsigned int i = 0 ; i < new_resources.size() ; i++) { M_AddResource_Unique(new_resources[i]); } return true; } void M_WriteEurekaLump(Wad_file *wad) { LogPrintf("Writing '%s' lump\n", EUREKA_LUMP); wad->BeginWrite(); int oldie = wad->FindLumpNum(EUREKA_LUMP); if (oldie >= 0) wad->RemoveLumps(oldie, 1); Lump_c *lump = wad->AddLump(EUREKA_LUMP); lump->Printf("# Eureka project info\n"); if (Game_name) lump->Printf("game %s\n", Game_name); if (Port_name) lump->Printf("port %s\n", Port_name); for (unsigned int i = 0 ; i < Resource_list.size() ; i++) { char absolute_name[FL_PATH_MAX]; fl_filename_absolute(absolute_name, Resource_list[i]); lump->Printf("resource %s\n", absolute_name); } lump->Finish(); wad->EndWrite(); } //------------------------------------------------------------------------ // BACKUP SYSTEM //------------------------------------------------------------------------ // config variables int backup_max_files = 30; int backup_max_space = 60; // MB typedef struct { int low; int high; } backup_scan_data_t; static void backup_scan_file(const char *name, int flags, void *priv_dat) { backup_scan_data_t * data = (backup_scan_data_t *)priv_dat; if (flags & SCAN_F_Hidden) return; if (flags & SCAN_F_IsDir) return; if (! isdigit(name[0])) return; int num = atoi(name); data->low = MIN(data->low, num); data->high = MAX(data->high, num); } static const char *Backup_Name(const char *dir_name, int slot) { static char filename[FL_PATH_MAX]; sprintf(filename, "%s/%d.wad", dir_name, slot); return filename; } static void Backup_Prune(const char *dir_name, int b_low, int b_high, int wad_size) { // Note: the logic here for checking space is very crude, it assumes // all existing backups have the same size as the currrent wad. // do calculations in KB units wad_size = wad_size / 1024 + 1; int backup_num = 2 + backup_max_space * 1024 / wad_size; if (backup_num > backup_max_files) backup_num = backup_max_files; for ( ; b_low <= b_high - backup_num + 1 ; b_low++) { FileDelete(Backup_Name(dir_name, b_low)); } } void M_BackupWad(Wad_file *wad) { // disabled ? if (backup_max_files <= 0 || backup_max_space <= 0) return; // convert wad filename to a directory name in $cache_dir/backups static char filename[FL_PATH_MAX]; sprintf(filename, "%s/backups/%s", cache_dir, fl_filename_name(wad->PathName())); char * dir_name = ReplaceExtension(filename, NULL); DebugPrintf("dir_name for backup: '%s'\n", dir_name); // create the directory if it doesn't already exist // (this will fail if it DOES already exist, but that's OK) FileMakeDir(dir_name); // scan directory to determine lowest and highest numbers in use backup_scan_data_t scan_data; scan_data.low = (1 << 30); scan_data.high = 0; if (ScanDirectory(dir_name, backup_scan_file, &scan_data) < 0) { // Hmmm, show a dialog ?? LogPrintf("WARNING: backup failed (cannot scan dir)\n"); StringFree(dir_name); return; } int b_low = scan_data.low; int b_high = scan_data.high; if (b_low < b_high) { int wad_size = wad->TotalSize(); Backup_Prune(dir_name, b_low, b_high, wad_size); } // actually back-up the file const char * dest_name = Backup_Name(dir_name, b_high + 1); StringFree(dir_name); if (! wad->Backup(dest_name)) { // Hmmm, show a dialog ?? LogPrintf("WARNING: backup failed (cannot copy file)\n"); return; } LogPrintf("Backed up wad to: %s\n", dest_name); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_nodes.h0000644000175100017510000000201112647061302016035 0ustar aaptedaapted//------------------------------------------------------------------------ // BUILDING NODES / PLAY THE MAP //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012 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 __EUREKA_E_NODES_H__ #define __EUREKA_E_NODES_H__ bool CMD_BuildNodes(); void CMD_TestMap(); #endif /* __EUREKA_E_NODES_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_path.cc0000644000175100017510000002605012647602047016037 0ustar aaptedaapted//------------------------------------------------------------------------ // LINEDEF PATHS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "m_bitvec.h" #include "editloop.h" #include "e_path.h" #include "levels.h" #include "m_game.h" #include "r_grid.h" #include "w_rawdef.h" #include "x_mirror.h" #include "ui_window.h" typedef enum { SLP_Normal = 0, SLP_SameTex = (1 << 1), // require lines have same textures SLP_OneSided = (1 << 2), // only handle one-sided lines } select_lines_in_path_flag_e; static bool MatchingTextures(int index1, int index2) { LineDef *L1 = LineDefs[index1]; LineDef *L2 = LineDefs[index2]; // lines with no sidedefs only match each other if (! L1->Right() || ! L2->Right()) return L1->Right() == L2->Right(); // determine texture to match from first line int texture = 0; if (! L1->TwoSided()) { texture = L1->Right()->mid_tex; } else { int f_diff = L1->Left()->SecRef()->floorh - L1->Right()->SecRef()->floorh; int c_diff = L1->Left()->SecRef()->ceilh - L1->Right()->SecRef()->ceilh; if (f_diff == 0 && c_diff != 0) texture = (c_diff > 0) ? L1->Left()->upper_tex : L1->Right()->upper_tex; else texture = (f_diff < 0) ? L1->Left()->lower_tex : L1->Right()->lower_tex; } // match texture with other line if (! L2->TwoSided()) { return (L2->Right()->mid_tex == texture); } else { int f_diff = L2->Left()->SecRef()->floorh - L2->Right()->SecRef()->floorh; int c_diff = L2->Left()->SecRef()->ceilh - L2->Right()->SecRef()->ceilh; if (c_diff != 0) if (texture == ((c_diff > 0) ? L2->Left()->upper_tex : L2->Right()->upper_tex)) return true; if (f_diff != 0) if (texture == ((f_diff < 0) ? L2->Left()->lower_tex : L2->Right()->lower_tex)) return true; return false; } } bool OtherLineDef(int L, int V, int *L_other, int *V_other, int match, int start_L) { *L_other = -1; *V_other = -1; for (int n = 0 ; n < NumLineDefs ; n++) { if (n == L) continue; if ((match & SLP_OneSided) && ! LineDefs[n]->OneSided()) continue; for (int k = 0 ; k < 2 ; k++) { int v1 = LineDefs[n]->start; int v2 = LineDefs[n]->end; if (k == 1) std::swap(v1, v2); if (v1 != V) continue; if ((match & SLP_SameTex) && ! MatchingTextures(start_L, n)) continue; if (*L_other >= 0) // There is a fork in the path. Stop here. return false; *L_other = n; *V_other = v2; } } return (*L_other >= 0); } // This routine looks for all linedefs other than 'L' which use // the vertex 'V'. If there are none or more than one, the search // stops there and nothing else happens. If there is exactly one, // then it is added to the selection and we continue from the new // linedef and vertex. static void SelectLinesInHalfPath(int L, int V, selection_c& seen, int match) { int start_L = L; for (;;) { int L_other, V_other; // does not exist or is forky if (! OtherLineDef(L, V, &L_other, &V_other, match, start_L)) break; // already seen? if (seen.get(L_other)) break; seen.set(L_other); L = L_other; V = V_other; } } /* Select/unselect all linedefs in non-forked path. */ void LIN_SelectPath(void) { // determine starting linedef if (edit.highlight.is_nil()) { Beep("No highlighted line"); return; } bool additive = Exec_HasFlag("/add"); int match = 0; if (Exec_HasFlag("/onesided")) match |= SLP_OneSided; if (Exec_HasFlag("/sametex")) match |= SLP_SameTex; if (edit.did_a_move) { edit.did_a_move = false; additive = false; } int start_L = edit.highlight.num; if ((match & SLP_OneSided) && ! LineDefs[start_L]->OneSided()) return; bool unset_them = false; if (additive && edit.Selected->get(start_L)) unset_them = true; selection_c seen(OBJ_LINEDEFS); seen.set(start_L); SelectLinesInHalfPath(start_L, LineDefs[start_L]->start, seen, match); SelectLinesInHalfPath(start_L, LineDefs[start_L]->end, seen, match); Editor_ClearErrorMode(); if (! additive) Selection_Clear(); if (unset_them) edit.Selected->unmerge(seen); else edit.Selected->merge(seen); RedrawMap(); } //------------------------------------------------------------------------ #define PLAYER_STEP_H 24 static bool GrowContiguousSectors(selection_c &seen, bool additive) { // returns TRUE when some new sectors got added bool changed = false; bool can_walk = Exec_HasFlag("/can_walk"); bool allow_doors = Exec_HasFlag("/doors"); bool do_floor_h = Exec_HasFlag("/floor_h"); bool do_floor_tex = Exec_HasFlag("/floor_tex"); bool do_ceil_h = Exec_HasFlag("/ceil_h"); bool do_ceil_tex = Exec_HasFlag("/ceil_tex"); bool do_light = Exec_HasFlag("/light"); bool do_tag = Exec_HasFlag("/tag"); bool do_special = Exec_HasFlag("/special"); for (int n = 0 ; n < NumLineDefs ; n++) { LineDef *L = LineDefs[n]; if (! L->TwoSided()) continue; int sec1 = L->Right()->sector; int sec2 = L-> Left()->sector; if (sec1 == sec2) continue; Sector *S1 = Sectors[sec1]; Sector *S2 = Sectors[sec2]; // skip closed doors if (! allow_doors && (S1->floorh >= S1->ceilh || S2->floorh >= S2->ceilh)) continue; if (can_walk) { if (L->flags & MLF_Blocking) continue; // too big a step? if (abs(S1->floorh - S2->floorh) > PLAYER_STEP_H) continue; // player wouldn't fit vertically? int f_max = MAX(S1->floorh, S2->floorh); int c_min = MIN(S1-> ceilh, S2-> ceilh); if (c_min - f_max < game_info.player_h) { // ... but allow doors if (! (allow_doors && (S1->floorh == S1->ceilh || S2->floorh == S2->ceilh))) continue; } } /* perform match */ if (do_floor_h && (S1->floorh != S2->floorh)) continue; if (do_ceil_h && (S1->ceilh != S2->ceilh)) continue; if (do_floor_tex && (S1->floor_tex != S2->floor_tex)) continue; if (do_ceil_tex && (S1->ceil_tex != S2->ceil_tex)) continue; if (do_light && (S1->light != S2->light)) continue; if (do_tag && (S1->tag != S2->tag )) continue; if (do_special && (S1->type != S2->type)) continue; // check if only one of the sectors is part of current set // (doing this _AFTER_ the matches since this can be a bit slow) bool got1 = seen.get(sec1); bool got2 = seen.get(sec2); if (got1 == got2) continue; seen.set(got1 ? sec2 : sec1); changed = true; } return changed; } /* Select/unselect a contiguous group of sectors. */ void SEC_SelectGroup(void) { // determine starting sector if (edit.highlight.is_nil()) { Beep("No highlighted sector"); return; } bool additive = Exec_HasFlag("/add"); if (edit.did_a_move) { edit.did_a_move = false; additive = false; } int start_sec = edit.highlight.num; bool unset_them = false; if (additive && edit.Selected->get(start_sec)) unset_them = true; selection_c seen(OBJ_SECTORS); seen.set(start_sec); while (GrowContiguousSectors(seen, additive)) { } Editor_ClearErrorMode(); if (! additive) Selection_Clear(); if (unset_them) edit.Selected->unmerge(seen); else edit.Selected->merge(seen); RedrawMap(); } //------------------------------------------------------------------------ void GoToSelection() { int x1, y1, x2, y2; Objs_CalcBBox(edit.Selected, &x1, &y1, &x2, &y2); int mid_x = (x1 + x2) / 2; int mid_y = (y1 + y2) / 2; grid.CenterMapAt(mid_x, mid_y); // zoom out until selected objects fit on screen for (int loop = 0 ; loop < 30 ; loop++) { int eval = main_win->canvas->ApproxBoxSize(x1, y1, x2, y2); if (eval <= 0) break; grid.AdjustScale(-1); } // zoom in when bbox is very small (say < 20% of window) for (int loop = 0 ; loop < 30 ; loop++) { if (grid.Scale >= 1.0) break; int eval = main_win->canvas->ApproxBoxSize(x1, y1, x2, y2); if (eval >= 0) break; grid.AdjustScale(+1); } // FIXME: this is not completely right, we should check where mouse pointer is // and use the following as the fallback (when not pointer_in_window). edit.map_x = mid_x; edit.map_y = mid_y; RedrawMap(); } void GoToErrors() { edit.error_mode = true; GoToSelection(); } /* centre the map around the object and zoom in if necessary */ void GoToObject(const Objid& objid) { Selection_Clear(); edit.Selected->set(objid.num); GoToSelection(); } void CMD_JumpToObject(void) { const char *buf = fl_input("Enter index number", ""); if (! buf) // cancelled return; // TODO: validate it is a number int num = atoi(buf); if (num < 0 || num >= NumObjects(edit.mode)) { Beep("No such object: #%d", num); return; } GoToObject(Objid(edit.mode, num)); } void CMD_NextObject() { if (edit.Selected->count_obj() != 1) { Beep("Next: need a single object"); return; } int num = edit.Selected->find_first(); if (num >= NumObjects(edit.mode)) { Beep("Next: no more objects"); return; } num += 1; GoToObject(Objid(edit.mode, num)); } void CMD_PrevObject() { if (edit.Selected->count_obj() != 1) { Beep("Prev: need a single object"); return; } int num = edit.Selected->find_first(); if (num <= 0) { Beep("Prev: no more objects"); return; } num -= 1; GoToObject(Objid(edit.mode, num)); } void CMD_PruneUnused(void) { selection_c used_secs (OBJ_SECTORS); selection_c used_sides(OBJ_SIDEDEFS); selection_c used_verts(OBJ_VERTICES); for (int i = 0 ; i < NumLineDefs ; i++) { const LineDef * L = LineDefs[i]; used_verts.set(L->start); used_verts.set(L->end); if (L->left >= 0) { used_sides.set(L->left); used_secs.set(L->Left()->sector); } if (L->right >= 0) { used_sides.set(L->right); used_secs.set(L->Right()->sector); } } used_secs .frob_range(0, NumSectors -1, BOP_TOGGLE); used_sides.frob_range(0, NumSideDefs-1, BOP_TOGGLE); used_verts.frob_range(0, NumVertices-1, BOP_TOGGLE); int num_secs = used_secs .count_obj(); int num_sides = used_sides.count_obj(); int num_verts = used_verts.count_obj(); if (num_verts == 0 && num_sides == 0 && num_secs == 0) { Beep("Nothing to prune"); return; } BA_Begin(); DeleteObjects(&used_sides); DeleteObjects(&used_secs); DeleteObjects(&used_verts); Status_Set("Pruned %d SEC - %d Side - %d Vert", num_secs, num_sides, num_verts); BA_End(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_linedef.h0000644000175100017510000000406312647061302016344 0ustar aaptedaapted//------------------------------------------------------------------------ // LINEDEF OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_LINEDEF_H__ #define __EUREKA_E_LINEDEF_H__ void FlipLineDef(int ld); void FlipLineDefGroup(selection_c& flip); void LineDefs_SetLength(int new_len); bool LineDefAlreadyExists(int v1, int v2); bool LineDefWouldOverlap(int v1, int x2, int y2); void DeleteLineDefs(selection_c *lines); int SplitLineDefAtVertex(int ld, int v_idx); void MoveCoordOntoLineDef(int ld, int *x, int *y); void LD_FixForLostSide(int ld); typedef enum { LINALIGN_X = (1 << 0), // align the X offset LINALIGN_Y = (1 << 1), // align the Y offset LINALIGN_Left = 0, // align with line to the left of this one LINALIGN_Right = (1 << 4) // align with line to the right of this one } linedef_align_flag_e; void LineDefs_Align(int ld, int side, int sd, char part, int align_flags); /* commands */ void LIN_Flip(void); void LIN_Align(void); void LIN_MergeTwo(void); void LIN_SplitHalf(void); #endif /* __EUREKA_E_LINEDEF_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_nodes.cc0000644000175100017510000000716612651121326016402 0ustar aaptedaapted//------------------------------------------------------------------------ // Node Building Window //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2012 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 "main.h" #include "ui_window.h" #include "ui_nodes.h" #define NODE_PROGRESS_COLOR fl_color_cube(2,6,2) // // Callbacks // void UI_NodeDialog::close_callback(Fl_Widget *w, void *data) { UI_NodeDialog * that = (UI_NodeDialog *)data; that->want_close = true; if (! that->finished) that->want_cancel = true; } void UI_NodeDialog::button_callback(Fl_Widget *w, void *data) { UI_NodeDialog * that = (UI_NodeDialog *)data; if (that->finished) that->want_close = true; else that->want_cancel = true; } // // Constructor // UI_NodeDialog::UI_NodeDialog() : Fl_Double_Window(400, 400, "Building Nodes"), cur_prog(-1), finished(false), want_cancel(false), want_close(false) { size_range(w(), h()); callback((Fl_Callback *) close_callback, this); color(WINDOW_BG, WINDOW_BG); browser = new Fl_Browser(0, 0, w(), h() - 100); Fl_Box * ptext = new Fl_Box(FL_NO_BOX, 10, h() - 80, 80, 20, "Progress:"); (void) ptext; progress = new Fl_Progress(100, h() - 80, w() - 120, 20); progress->align(FL_ALIGN_INSIDE); progress->box(FL_FLAT_BOX); progress->color(FL_LIGHT2, NODE_PROGRESS_COLOR); progress->minimum(0.0); progress->maximum(100.0); progress->value(0.0); button = new Fl_Button(w() - 100, h() - 46, 80, 30, "Cancel"); button->callback(button_callback, this); end(); resizable(browser); } // // Destructor // UI_NodeDialog::~UI_NodeDialog() { } int UI_NodeDialog::handle(int event) { if (event == FL_KEYDOWN && Fl::event_key() == FL_Escape) { if (finished) want_close = true; else want_cancel = true; return 1; } return Fl_Double_Window::handle(event); } void UI_NodeDialog::SetStatus(const char *str) { /* not used */ } void UI_NodeDialog::SetProg(int perc) { if (perc == cur_prog) return; cur_prog = perc; sprintf(prog_label, "%d%%", perc); progress->value(perc); progress->label(prog_label); Fl::check(); } void UI_NodeDialog::Print(const char *str) { // split lines static char buffer[256]; snprintf(buffer, sizeof(buffer), "%s", str); buffer[sizeof(buffer) - 1] = 0; char * pos = buffer; char * next; while (pos && *pos) { next = strchr(pos, '\n'); if (next) *next++ = 0; browser->add(pos); pos = next; } browser->bottomline(browser->size()); Fl::check(); } void UI_NodeDialog::Finish_OK() { finished = true; button->label("Close"); progress->value(100); progress->label("Success"); progress->color(FL_BLUE, FL_BLUE); } void UI_NodeDialog::Finish_Cancel() { finished = true; button->label("Close"); progress->value(0); progress->label("Cancelled"); progress->color(FL_RED, FL_RED); } void UI_NodeDialog::Finish_Error() { finished = true; button->label("Close"); progress->value(100); progress->label("ERROR"); progress->color(FL_RED, FL_RED); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_pic.h0000644000175100017510000000353512647061302015705 0ustar aaptedaapted//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2013 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 __EUREKA_UI_PIC_H__ #define __EUREKA_UI_PIC_H__ class Img_c; class UI_Pic : public Fl_Box { private: Fl_RGB_Image *rgb; enum { SP_None = 0, SP_Unknown, // texture name is not found SP_Missing, // texture is '-' but should be present }; int special; bool selected; const char *what_text; Fl_Color what_color; public: UI_Pic(int X, int Y, int W, int H, const char *L = ""); virtual ~UI_Pic(); // FLTK virtual method for drawing. int handle(int event); public: void Clear(); void MarkUnknown(); void MarkMissing(); void GetFlat(const char * fname); void GetTex (const char * tname); void GetSprite(int type, Fl_Color back_color); bool Selected() { return selected; } void Selected(bool _val) { selected = _val; } private: // FLTK virtual method for drawing. void draw(); void draw_selected(); void UploadRGB(const byte *buf, int depth); void TiledImg(Img_c *img, bool has_trans); }; #endif /* __EUREKA_UI_PIC_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_checks.cc0000644000175100017510000011502012651541365016337 0ustar aaptedaapted//------------------------------------------------------------------------ // INTEGRITY CHECKS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include "e_checks.h" #include "e_path.h" #include "e_vertex.h" #include "editloop.h" #include "m_game.h" #include "levels.h" #include "objects.h" #include "w_rawdef.h" #include "ui_window.h" #include "x_hover.h" #define ERROR_MSG_COLOR FL_RED #define WARNING_MSG_COLOR FL_BLUE static char check_message[MSG_BUF_LEN]; //------------------------------------------------------------------------ // BASE CLASS //------------------------------------------------------------------------ void UI_Check_base::close_callback(Fl_Widget *w, void *data) { UI_Check_base *dialog = (UI_Check_base *)data; dialog->want_close = true; } UI_Check_base::UI_Check_base(int W, int H, bool all_mode, const char *L, const char *header_txt) : UI_Escapable_Window(W, H, L), want_close(false), user_action(CKR_OK), worst_severity(0) { cy = 10; callback(close_callback, this); int ey = h() - 66; Fl_Box *title = new Fl_Box(FL_NO_BOX, 10, cy, w() - 20, 30, header_txt); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); title->labelfont(FL_HELVETICA_BOLD); title->labelsize(FL_NORMAL_SIZE + 2); cy = 45; line_group = new Fl_Group(0, 0, w(), ey); line_group->end(); { Fl_Group *o = new Fl_Group(0, ey, w(), 66); o->box(FL_FLAT_BOX); o->color(WINDOW_BG, WINDOW_BG); int but_W = all_mode ? 110 : 70; { Fl_Button *ok_but; ok_but = new Fl_Button(w()/2 - but_W/2, ey + 18, but_W, 34, all_mode ? "Continue" : "OK"); ok_but->labelfont(1); ok_but->callback(close_callback, this); } o->end(); } end(); } UI_Check_base::~UI_Check_base() { } void UI_Check_base::Reset() { want_close = false; user_action = CKR_OK; cy = 45; line_group->clear(); redraw(); } void UI_Check_base::AddGap(int H) { cy += H; } void UI_Check_base::AddLine( const char *msg, int severity, int W, const char *button1, Fl_Callback *cb1, const char *button2, Fl_Callback *cb2, const char *button3, Fl_Callback *cb3) { int cx = 30; if (W < 0) W = w() - 40; Fl_Box *box = new Fl_Box(FL_NO_BOX, cx, cy, W, 25, NULL); box->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); box->copy_label(msg); if (severity == 2) { box->labelcolor(ERROR_MSG_COLOR); box->labelfont(FL_HELVETICA_BOLD); } else if (severity == 1) { box->labelcolor(WARNING_MSG_COLOR); box->labelfont(FL_HELVETICA_BOLD); } line_group->add(box); cx += W; if (button1) { Fl_Button *but = new Fl_Button(cx, cy, 80, 25, button1); but->callback(cb1, this); line_group->add(but); cx += but->w() + 10; } if (button2) { Fl_Button *but = new Fl_Button(cx, cy, 80, 25, button2); but->callback(cb2, this); line_group->add(but); cx += but->w() + 10; } if (button3) { Fl_Button *but = new Fl_Button(cx, cy, 80, 25, button3); but->callback(cb3, this); line_group->add(but); } cy = cy + 30; if (severity > worst_severity) worst_severity = severity; } check_result_e UI_Check_base::Run() { set_modal(); show(); while (! (want_close || user_action != CKR_OK)) Fl::wait(0.2); if (user_action != CKR_OK) return user_action; switch (worst_severity) { case 0: return CKR_OK; case 1: return CKR_MinorProblem; default: return CKR_MajorProblem; } } //------------------------------------------------------------------------ void Vertex_FindDanglers(selection_c& sel) { sel.change_type(OBJ_VERTICES); if (NumVertices == 0 || NumLineDefs == 0) return; byte * line_counts = new byte[NumVertices]; memset(line_counts, 0, NumVertices); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; int v1 = L->start; int v2 = L->end; // dangling vertices are fine for lines setting inside a sector // (i.e. with same sector on both sides) if (L->TwoSided() && (L->WhatSector(SIDE_LEFT) == L->WhatSector(SIDE_RIGHT))) { line_counts[v1] = line_counts[v2] = 2; continue; } if (line_counts[v1] < 2) line_counts[v1] += 1; if (line_counts[v2] < 2) line_counts[v2] += 1; } for (int k = 0 ; k < NumVertices ; k++) { if (line_counts[k] == 1) sel.set(k); } delete[] line_counts; } void Vertex_ShowDanglers() { if (edit.mode != OBJ_VERTICES) Editor_ChangeMode('v'); Vertex_FindDanglers(*edit.Selected); GoToErrors(); } struct vertex_X_CMP_pred { inline bool operator() (int A, int B) const { const Vertex *V1 = Vertices[A]; const Vertex *V2 = Vertices[B]; return V1->x < V2->x; } }; void Vertex_FindOverlaps(selection_c& sel, bool one_coord = false) { // the 'one_coord' parameter limits the selection to a single // vertex coordinate. sel.change_type(OBJ_VERTICES); if (NumVertices < 2) return; // sort the vertices into order of the 'X' value. // hence any overlapping vertices will be near each other. std::vector sorted_list(NumVertices, 0); for (int i = 0 ; i < NumVertices ; i++) sorted_list[i] = i; std::sort(sorted_list.begin(), sorted_list.end(), vertex_X_CMP_pred()); bool seen_one = false; int last_y = 0; #define VERT_K Vertices[sorted_list[k]] #define VERT_N Vertices[sorted_list[n]] for (int k = 0 ; k < NumVertices ; k++) { for (int n = k + 1 ; n < NumVertices && VERT_N->x == VERT_K->x ; n++) { if (VERT_N->y == VERT_K->y) { if (one_coord && seen_one && VERT_K->y != last_y) continue; sel.set(sorted_list[k]); sel.set(sorted_list[n]); seen_one = true; last_y = VERT_K->y; } } } #undef VERT_K #undef VERT_N } void Vertex_MergeOverlaps() { for (;;) { selection_c sel; Vertex_FindOverlaps(sel, true /* one_coord */); if (sel.empty()) break; Vertex_MergeList(&sel); } } void Vertex_ShowOverlaps() { if (edit.mode != OBJ_VERTICES) Editor_ChangeMode('v'); Vertex_FindOverlaps(*edit.Selected); GoToErrors(); } void Vertex_FindUnused(selection_c& sel) { sel.change_type(OBJ_VERTICES); if (NumVertices == 0) return; for (int i = 0 ; i < NumLineDefs ; i++) { sel.set(LineDefs[i]->start); sel.set(LineDefs[i]->end); } sel.frob_range(0, NumVertices - 1, BOP_TOGGLE); } void Vertex_RemoveUnused() { selection_c sel; Vertex_FindUnused(sel); BA_Begin(); DeleteObjects(&sel); BA_End(); } void Vertex_ShowUnused() { if (edit.mode != OBJ_VERTICES) Editor_ChangeMode('v'); Vertex_FindUnused(*edit.Selected); GoToErrors(); } //------------------------------------------------------------------------ class UI_Check_Vertices : public UI_Check_base { public: UI_Check_Vertices(bool all_mode) : UI_Check_base(520, 224, all_mode, "Check : Vertices", "Vertex test results") { } public: static void action_merge(Fl_Widget *w, void *data) { UI_Check_Vertices *dialog = (UI_Check_Vertices *)data; Vertex_MergeOverlaps(); dialog->user_action = CKR_TookAction; } static void action_highlight(Fl_Widget *w, void *data) { UI_Check_Vertices *dialog = (UI_Check_Vertices *)data; Vertex_ShowOverlaps(); dialog->user_action = CKR_Highlight; } static void action_show_unused(Fl_Widget *w, void *data) { UI_Check_Vertices *dialog = (UI_Check_Vertices *)data; Vertex_ShowUnused(); dialog->user_action = CKR_Highlight; } static void action_remove(Fl_Widget *w, void *data) { UI_Check_Vertices *dialog = (UI_Check_Vertices *)data; Vertex_RemoveUnused(); dialog->user_action = CKR_TookAction; } static void action_show_danglers(Fl_Widget *w, void *data) { UI_Check_Vertices *dialog = (UI_Check_Vertices *)data; Vertex_ShowDanglers(); dialog->user_action = CKR_Highlight; } }; check_result_e CHECK_Vertices(int min_severity = 0) { UI_Check_Vertices *dialog = new UI_Check_Vertices(min_severity > 0); selection_c sel; for (;;) { Vertex_FindDanglers(sel); if (sel.empty()) dialog->AddLine("No dangling vertices"); else { sprintf(check_message, "%d dangling vertices", sel.count_obj()); dialog->AddLine(check_message, 2, 210, "Show", &UI_Check_Vertices::action_show_danglers); } Vertex_FindOverlaps(sel); if (sel.empty()) dialog->AddLine("No overlapping vertices"); else { int approx_num = sel.count_obj() / 2; sprintf(check_message, "%d overlapping vertices", approx_num); dialog->AddLine(check_message, 2, 210, "Show", &UI_Check_Vertices::action_highlight, "Merge", &UI_Check_Vertices::action_merge); } Vertex_FindUnused(sel); if (sel.empty()) dialog->AddLine("No unused vertices"); else { sprintf(check_message, "%d unused vertices", sel.count_obj()); dialog->AddLine(check_message, 1, 210, "Show", &UI_Check_Vertices::action_show_unused, "Remove", &UI_Check_Vertices::action_remove); } // in "ALL" mode, just continue if not too severe if (dialog->WorstSeverity() < min_severity) { delete dialog; return CKR_OK; } check_result_e result = dialog->Run(); if (result == CKR_TookAction) { // repeat the tests dialog->Reset(); continue; } delete dialog; return result; } } //------------------------------------------------------------------------ void Sectors_FindUnclosed(selection_c& secs, selection_c& verts) { secs.change_type(OBJ_SECTORS); verts.change_type(OBJ_VERTICES); if (NumVertices == 0 || NumSectors == 0) return; byte *ends = new byte[NumVertices]; int v; for (int s = 0 ; s < NumSectors ; s++) { // clear the "ends" array for (v = 0 ; v < NumVertices ; v++) ends[v] = 0; // for each sidedef bound to the Sector, store a "1" in the "ends" // array for its starting vertex, and a "2" for its ending vertex. for (int i = 0 ; i < NumLineDefs ; i++) { const LineDef *L = LineDefs[i]; if (! L->TouchesSector(s)) continue; // ignore lines with same sector on both sides if (L->left >= 0 && L->right >= 0 && L->Left()->sector == L->Right()->sector) continue; if (L->right >= 0 && L->Right()->sector == s) { ends[L->start] |= 1; ends[L->end] |= 2; } if (L->left >= 0 && L->Left()->sector == s) { ends[L->start] |= 2; ends[L->end] |= 1; } } // every entry in the "ends" array should be 0 or 3 for (v = 0 ; v < NumVertices ; v++) { if (ends[v] == 1 || ends[v] == 2) { secs.set(s); verts.set(v); } } } delete[] ends; } void Sectors_ShowUnclosed(obj_type_e what) { if (edit.mode != what) Editor_ChangeMode((what == OBJ_SECTORS) ? 's' : 'v'); selection_c other; if (what == OBJ_SECTORS) Sectors_FindUnclosed(*edit.Selected, other); else Sectors_FindUnclosed(other, *edit.Selected); GoToErrors(); } void Sectors_FindMismatches(selection_c& secs, selection_c& lines) { /* Note from RQ: This is a very simple idea, but it works! The first test (above) checks that all Sectors are closed. But if a closed set of LineDefs is moved out of a Sector and has all its "external" SideDefs pointing to that Sector instead of the new one, then we need a second test. That's why I check if the SideDefs facing each other are bound to the same Sector. Other note from RQ: Nowadays, what makes the power of a good editor is its automatic tests. So, if you are writing another Doom editor, you will probably want to do the same kind of tests in your program. Fine, but if you use these ideas, don't forget to credit DEU... Just a reminder... :-) */ secs.change_type(OBJ_SECTORS); lines.change_type(OBJ_LINEDEFS); if (NumLineDefs == 0 || NumSectors == 0) return; FastOpposite_Begin(); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->right >= 0) { int s = OppositeSector(n, SIDE_RIGHT); if (s < 0 || L->Right()->sector != s) { secs.set(L->Right()->sector); lines.set(n); } } if (L->left >= 0) { int s = OppositeSector(n, SIDE_LEFT); if (s < 0 || L->Left()->sector != s) { secs.set(L->Left()->sector); lines.set(n); } } } FastOpposite_Finish(); } void Sectors_ShowMismatches(obj_type_e what) { if (edit.mode != what) Editor_ChangeMode((what == OBJ_SECTORS) ? 's' : 'l'); selection_c other; if (what == OBJ_SECTORS) Sectors_FindMismatches(*edit.Selected, other); else Sectors_FindMismatches(other, *edit.Selected); GoToErrors(); } static void bump_unknown_type(std::map& t_map, int type) { int count = 0; if (t_map.find(type) != t_map.end()) count = t_map[type]; t_map[type] = count + 1; } void Sectors_FindUnknown(selection_c& list, std::map& types) { types.clear(); list.change_type(OBJ_SECTORS); for (int n = 0 ; n < NumSectors ; n++) { int type_num = Sectors[n]->type; if (type_num < 0 || type_num >= 2048) { bump_unknown_type(types, type_num); list.set(n); continue; } // Boom generalized sectors if (game_info.gen_types) type_num &= 31; const sectortype_t *info = M_GetSectorType(type_num); if (strncmp(info->desc, "UNKNOWN", 7) == 0) { bump_unknown_type(types, type_num); list.set(n); } } } void Sectors_ShowUnknown() { if (edit.mode != OBJ_SECTORS) Editor_ChangeMode('s'); std::map types; Sectors_FindUnknown(*edit.Selected, types); GoToErrors(); } void Sectors_LogUnknown() { selection_c sel; std::map types; std::map::iterator IT; Sectors_FindUnknown(sel, types); LogPrintf("\n"); LogPrintf("Unknown Sector Types:\n"); LogPrintf("{\n"); for (IT = types.begin() ; IT != types.end() ; IT++) LogPrintf(" %5d x %d\n", IT->first, IT->second); LogPrintf("}\n"); LogViewer_Open(); } void Sectors_ClearUnknown() { selection_c sel; std::map types; Sectors_FindUnknown(sel, types); selection_iterator_c it; BA_Begin(); for (sel.begin(&it) ; !it.at_end() ; ++it) BA_ChangeSEC(*it, Sector::F_TYPE, 0); BA_End(); } void Sectors_FindUnused(selection_c& sel) { sel.change_type(OBJ_SECTORS); if (NumSectors == 0) return; for (int i = 0 ; i < NumLineDefs ; i++) { const LineDef *L = LineDefs[i]; if (L->left >= 0) sel.set(L->Left()->sector); if (L->right >= 0) sel.set(L->Right()->sector); } sel.frob_range(0, NumSectors - 1, BOP_TOGGLE); } void Sectors_RemoveUnused() { selection_c sel; Sectors_FindUnused(sel); BA_Begin(); DeleteObjects(&sel); BA_End(); //?? Status_Set("Removed %d vertices", sel.count_obj()); } void Sectors_FindBadCeil(selection_c& sel) { sel.change_type(OBJ_SECTORS); if (NumSectors == 0) return; for (int i = 0 ; i < NumSectors ; i++) { if (Sectors[i]->ceilh < Sectors[i]->floorh) sel.set(i); } } void Sectors_FixBadCeil() { selection_c sel; Sectors_FindBadCeil(sel); BA_Begin(); for (int i = 0 ; i < NumSectors ; i++) { if (Sectors[i]->ceilh < Sectors[i]->floorh) { BA_ChangeSEC(i, Sector::F_CEILH, Sectors[i]->floorh); } } BA_End(); } void Sectors_ShowBadCeil() { if (edit.mode != OBJ_SECTORS) Editor_ChangeMode('s'); Sectors_FindBadCeil(*edit.Selected); GoToErrors(); } void SideDefs_FindUnused(selection_c& sel) { sel.change_type(OBJ_SIDEDEFS); if (NumSideDefs == 0) return; for (int i = 0 ; i < NumLineDefs ; i++) { const LineDef *L = LineDefs[i]; if (L->left >= 0) sel.set(L->left); if (L->right >= 0) sel.set(L->right); } sel.frob_range(0, NumSideDefs - 1, BOP_TOGGLE); } void SideDefs_RemoveUnused() { selection_c sel; SideDefs_FindUnused(sel); BA_Begin(); DeleteObjects(&sel); BA_End(); //?? Status_Set("Removed %d vertices", sel.count_obj()); } void SideDefs_FindPacking(selection_c& sides, selection_c& lines) { sides.change_type(OBJ_SIDEDEFS); lines.change_type(OBJ_LINEDEFS); for (int i = 0 ; i < NumLineDefs ; i++) for (int k = 0 ; k < i ; k++) { const LineDef * A = LineDefs[i]; const LineDef * B = LineDefs[k]; bool AA = (A->left >= 0 && A->left == A->right); bool AL = (A->left >= 0 && (A->left == B->left || A->left == B->right)); bool AR = (A->right >= 0 && (A->right == B->left || A->right == B->right)); if (AL || AA) sides.set(A->left); if (AR) sides.set(A->right); if (AL || AR) { lines.set(i); lines.set(k); } else if (AA) { lines.set(i); } } } void SideDefs_ShowPacked() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); selection_c sides; SideDefs_FindPacking(sides, *edit.Selected); GoToErrors(); } static int Copy_SideDef(int num) { int sd = BA_New(OBJ_SIDEDEFS); SideDefs[sd]->RawCopy(SideDefs[num]); return sd; } static const char *unpack_confirm_message = "This map contains shared sidedefs. It it recommended to unpack " "them, otherwise it may cause unexpected behavior during editing " "(such as random walls changing their texture).\n\n" "Unpack the sidedefs now?"; void SideDefs_Unpack(bool no_history) { selection_c sides; selection_c lines; SideDefs_FindPacking(sides, lines); if (sides.empty()) return; if (false /* confirm_it */) { if (DLG_Confirm("&No Change|&Unpack", unpack_confirm_message) <= 0) return; } BA_Begin(); for (int sd = 0 ; sd < NumSideDefs ; sd++) { if (! sides.get(sd)) continue; // find the first linedef which uses this sidedef int first; for (first = 0 ; first < NumLineDefs ; first++) { const LineDef *F = LineDefs[first]; if (F->left == sd || F->right == sd) break; } if (first >= NumLineDefs) continue; // handle it when first linedef uses sidedef on both sides if (LineDefs[first]->left == LineDefs[first]->right) { BA_ChangeLD(first, LineDef::F_LEFT, Copy_SideDef(sd)); } // duplicate any remaining references for (int ld = first + 1 ; ld < NumLineDefs ; ld++) { if (LineDefs[ld]->left == sd) BA_ChangeLD(ld, LineDef::F_LEFT, Copy_SideDef(sd)); if (LineDefs[ld]->right == sd) BA_ChangeLD(ld, LineDef::F_RIGHT, Copy_SideDef(sd)); } } if (no_history) BA_Abort(true /* keep changes */); else BA_End(); LogPrintf("Unpacked %d shared sidedefs --> %d\n", sides.count_obj(), NumSideDefs); } void SideDefs_NormalizeMiddles() { // ensure each one-sided linedef has no texture in upper and lower. // must only be called directly after level load, and after sidedefs // are unpacked. It is mainly to prevent one-sided lines seeming to // have a "rail" texture. selection_c sides(OBJ_SIDEDEFS); selection_iterator_c it; for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (! L->OneSided()) continue; sides.set(L->right); } int null_tex = BA_InternaliseString("-"); for (sides.begin(&it) ; !it.at_end() ; ++it) { SideDef * SD = SideDefs[*it]; // ensure it has a middle texture if (SD->MidTex()[0] == '-') continue; SD->lower_tex = null_tex; SD->upper_tex = null_tex; } } //------------------------------------------------------------------------ class UI_Check_Sectors : public UI_Check_base { public: UI_Check_Sectors(bool all_mode) : UI_Check_base(530, 346, all_mode, "Check : Sectors", "Sector test results") { } public: static void action_remove(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_RemoveUnused(); dialog->user_action = CKR_TookAction; } static void action_remove_sidedefs(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; SideDefs_RemoveUnused(); dialog->user_action = CKR_TookAction; } static void action_fix_ceil(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_FixBadCeil(); dialog->user_action = CKR_TookAction; } static void action_show_ceil(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowBadCeil(); dialog->user_action = CKR_Highlight; } static void action_unpack(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; SideDefs_Unpack(); dialog->user_action = CKR_Highlight; } static void action_show_packed(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; SideDefs_ShowPacked(); dialog->user_action = CKR_Highlight; } static void action_show_unclosed(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowUnclosed(OBJ_SECTORS); dialog->user_action = CKR_Highlight; } static void action_show_un_verts(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowUnclosed(OBJ_VERTICES); dialog->user_action = CKR_Highlight; } static void action_show_mismatch(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowMismatches(OBJ_SECTORS); dialog->user_action = CKR_Highlight; } static void action_show_mis_lines(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowMismatches(OBJ_LINEDEFS); dialog->user_action = CKR_Highlight; } static void action_show_unknown(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowUnknown(); dialog->user_action = CKR_Highlight; } static void action_log_unknown(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_LogUnknown(); dialog->user_action = CKR_Highlight; } static void action_clear_unknown(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ClearUnknown(); dialog->user_action = CKR_TookAction; } }; check_result_e CHECK_Sectors(int min_severity = 0) { UI_Check_Sectors *dialog = new UI_Check_Sectors(min_severity > 0); selection_c sel, other; std::map types; for (;;) { Sectors_FindUnclosed(sel, other); if (sel.empty()) dialog->AddLine("No unclosed sectors"); else { sprintf(check_message, "%d unclosed sectors", sel.count_obj()); dialog->AddLine(check_message, 2, 210, "Show", &UI_Check_Sectors::action_show_unclosed, "Verts", &UI_Check_Sectors::action_show_un_verts); } Sectors_FindMismatches(sel, other); if (sel.empty()) dialog->AddLine("No mismatched sectors"); else { sprintf(check_message, "%d mismatched sectors", sel.count_obj()); dialog->AddLine(check_message, 2, 210, "Show", &UI_Check_Sectors::action_show_mismatch, "Lines", &UI_Check_Sectors::action_show_mis_lines); } Sectors_FindBadCeil(sel); if (sel.empty()) dialog->AddLine("No sectors with ceil < floor"); else { sprintf(check_message, "%d sectors with ceil < floor", sel.count_obj()); dialog->AddLine(check_message, 2, 220, "Show", &UI_Check_Sectors::action_show_ceil, "Fix", &UI_Check_Sectors::action_fix_ceil); } dialog->AddGap(10); Sectors_FindUnknown(sel, types); if (sel.empty()) dialog->AddLine("No unknown sector types"); else { sprintf(check_message, "%d unknown sector types", (int)types.size()); dialog->AddLine(check_message, 2, 220, "Show", &UI_Check_Sectors::action_show_unknown, "Log", &UI_Check_Sectors::action_log_unknown, "Clear", &UI_Check_Sectors::action_clear_unknown); } SideDefs_FindPacking(sel, other); if (sel.empty()) dialog->AddLine("No shared sidedefs"); else { int approx_num = sel.count_obj(); sprintf(check_message, "%d shared sidedefs", approx_num); dialog->AddLine(check_message, 1, 200, "Show", &UI_Check_Sectors::action_show_packed, "Unpack", &UI_Check_Sectors::action_unpack); } Sectors_FindUnused(sel); if (sel.empty()) dialog->AddLine("No unused sectors"); else { sprintf(check_message, "%d unused sectors", sel.count_obj()); dialog->AddLine(check_message, 1, 170, "Remove", &UI_Check_Sectors::action_remove); } SideDefs_FindUnused(sel); if (sel.empty()) dialog->AddLine("No unused sidedefs"); else { sprintf(check_message, "%d unused sidedefs", sel.count_obj()); dialog->AddLine(check_message, 1, 170, "Remove", &UI_Check_Sectors::action_remove_sidedefs); } // in "ALL" mode, just continue if not too severe if (dialog->WorstSeverity() < min_severity) { delete dialog; return CKR_OK; } check_result_e result = dialog->Run(); if (result == CKR_TookAction) { // repeat the tests dialog->Reset(); continue; } delete dialog; return result; } } //------------------------------------------------------------------------ void Things_FindUnknown(selection_c& list, std::map& types) { types.clear(); list.change_type(OBJ_THINGS); for (int n = 0 ; n < NumThings ; n++) { const thingtype_t *info = M_GetThingType(Things[n]->type); if (strncmp(info->desc, "UNKNOWN", 7) == 0) { bump_unknown_type(types, Things[n]->type); list.set(n); } } } void Things_ShowUnknown() { if (edit.mode != OBJ_THINGS) Editor_ChangeMode('t'); std::map types; Things_FindUnknown(*edit.Selected, types); GoToErrors(); } void Things_LogUnknown() { selection_c sel; std::map types; std::map::iterator IT; Things_FindUnknown(sel, types); LogPrintf("\n"); LogPrintf("Unknown Things:\n"); LogPrintf("{\n"); for (IT = types.begin() ; IT != types.end() ; IT++) LogPrintf(" %5d x %d\n", IT->first, IT->second); LogPrintf("}\n"); LogViewer_Open(); } void Things_RemoveUnknown() { selection_c sel; std::map types; Things_FindUnknown(sel, types); BA_Begin(); DeleteObjects(&sel); BA_End(); } // this returns a bitmask : bits 0..3 for players 1..4 int Things_FindStarts(int *dm_num) { *dm_num = 0; int mask = 0; for (int n = 0 ; n < NumThings ; n++) { const Thing * T = Things[n]; // ideally, these type numbers would not be hard-coded.... switch (T->type) { case 1: mask |= (1 << 0); break; case 2: mask |= (1 << 1); break; case 3: mask |= (1 << 2); break; case 4: mask |= (1 << 3); break; case 11: *dm_num += 1; break; } } return mask; } void Things_FindInVoid(selection_c& list) { list.change_type(OBJ_THINGS); for (int n = 0 ; n < NumThings ; n++) { int x = Things[n]->x; int y = Things[n]->y; Objid obj; GetNearObject(obj, OBJ_SECTORS, x, y); if (! obj.is_nil()) continue; // allow certain things in the void (Heretic sounds) const thingtype_t *info = M_GetThingType(Things[n]->type); if (info->flags & THINGDEF_VOID) continue; // check more coords around the thing's centre, to be sure int out_count = 0; for (int corner = 0 ; corner < 4 ; corner++) { int x2 = x + ((corner & 1) ? -4 : +4); int y2 = y + ((corner & 2) ? -4 : +4); GetNearObject(obj, OBJ_SECTORS, x2, y2); if (obj.is_nil()) out_count++; } if (out_count == 4) list.set(n); } } void Things_ShowInVoid() { if (edit.mode != OBJ_THINGS) Editor_ChangeMode('t'); Things_FindInVoid(*edit.Selected); GoToErrors(); } void Things_RemoveInVoid() { selection_c sel; Things_FindInVoid(sel); BA_Begin(); DeleteObjects(&sel); BA_End(); } //------------------------------------------------------------------------ static void CollectBlockingThings(std::vector& list, std::vector& sizes) { for (int n = 0 ; n < NumThings ; n++) { const Thing *T = Things[n]; const thingtype_t *info = M_GetThingType(T->type); if (info->flags & THINGDEF_PASS) continue; // ignore unknown things if (strncmp(info->desc, "UNKNOWN", 7) == 0) continue; // TODO: config option: treat ceiling things as non-blocking list.push_back(n); sizes.push_back(info->radius); } } /* andrewj: the DOOM movement code for monsters works by moving the actor by a stepping distance which is based on its 'speed' value. The move is allowed when the *new position* has no blocking things or walls, which means that things can overlap a short distance and won't be stuck. Properly taking this into account requires knowing the speed of each individual monster, but we don't have that information here. Hence I've chosen a conservative value based on the speed of the slowest monster (8 units). TODO: make it either game config or user preference. */ #define MONSTER_STEP_DIST 8 static bool ThingStuckInThing(const Thing *T1, const thingtype_t *info1, const Thing *T2, const thingtype_t *info2) { SYS_ASSERT(T1 != T2); // require one thing to be a monster or player bool is_actor1 = (info1->group == 'm' || info1->group == 'p'); bool is_actor2 = (info2->group == 'm' || info2->group == 'p'); if (! (is_actor1 || is_actor2)) return false; // check if T1 is stuck in T2 int r1 = info1->radius; int r2 = info2->radius; if (info1->group == 'm' && info2->group != 'p') r1 = MAX(4, r1 - MONSTER_STEP_DIST); else if (info2->group == 'm' && info1->group != 'p') r2 = MAX(4, r2 - MONSTER_STEP_DIST); if (T1->x - r1 >= T2->x + r2) return false; if (T1->y - r1 >= T2->y + r2) return false; if (T1->x + r1 <= T2->x - r2) return false; if (T1->y + r1 <= T2->y - r2) return false; // teleporters and DM starts can safely overlap moving actors if ((info1->flags & THINGDEF_TELEPT) && is_actor2) return false; if ((info2->flags & THINGDEF_TELEPT) && is_actor1) return false; // check skill bits, except for players int opt1 = T1->options; int opt2 = T2->options; if (Level_format == MAPF_Hexen) { if (info1->group == 'p') opt1 |= 0x7E7; if (info2->group == 'p') opt2 |= 0x7E7; // check skill bits if ((opt1 & opt2 & 0x07) == 0) return false; // check class bits if ((opt1 & opt2 & 0xE0) == 0) return false; // check game mode if ((opt1 & opt2 & 0x700) == 0) return false; } else { // invert game-mode bits (MTF_Not_COOP etc) opt1 ^= 0x70; opt2 ^= 0x70; if (info1->group == 'p') opt1 |= 0x77; if (info2->group == 'p') opt2 |= 0x77; // check skill bits if ((opt1 & opt2 & 0x07) == 0) return false; // check game mode if ((opt1 & opt2 & 0x70) == 0) return false; } return true; } static inline bool LD_is_blocking(const LineDef *L) { #define MONSTER_HEIGHT 36 // ignore virtual linedefs if (L->right < 0 && L->left < 0) return false; if (L->right < 0 || L->left < 0) return true; const Sector *S1 = L->Right()->SecRef(); const Sector *S2 = L-> Left()->SecRef(); int f_max = MAX(S1->floorh, S2->floorh); int c_min = MIN(S1-> ceilh, S2-> ceilh); return (c_min < f_max + MONSTER_HEIGHT); } static bool ThingStuckInWall(const Thing *T, int r, char group) { // only check players and monsters if (! (group == 'p' || group == 'm')) return false; if (group == 'm') r = MAX(4, r - MONSTER_STEP_DIST); // shrink a tiny bit, because we need to find lines which CROSS the // bounding box, not just touch it. r = r - 1; int x1 = T->x - r; int y1 = T->y - r; int x2 = T->x + r; int y2 = T->y + r; for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (! LD_is_blocking(L)) continue; if (LineTouchesBox(n, x1, y1, x2, y2)) return true; } return false; } void Things_FindStuckies(selection_c& list) { list.change_type(OBJ_THINGS); std::vector blockers; std::vector sizes; CollectBlockingThings(blockers, sizes); for (int n = 0 ; n < (int)blockers.size() ; n++) { const Thing *T = Things[blockers[n]]; const thingtype_t *info = M_GetThingType(T->type); if (ThingStuckInWall(T, info->radius, info->group)) list.set(blockers[n]); for (int n2 = n + 1 ; n2 < (int)blockers.size() ; n2++) { const Thing *T2 = Things[blockers[n2]]; const thingtype_t *info2 = M_GetThingType(T2->type); if (ThingStuckInThing(T, info, T2, info2)) list.set(blockers[n]); } } } void Things_ShowStuckies() { if (edit.mode != OBJ_THINGS) Editor_ChangeMode('t'); Things_FindStuckies(*edit.Selected); GoToErrors(); } //------------------------------------------------------------------------ class UI_Check_Things : public UI_Check_base { public: UI_Check_Things(bool all_mode) : UI_Check_base(520, 286, all_mode, "Check : Things", "Thing test results") { } public: static void action_show_unknown(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_ShowUnknown(); dialog->user_action = CKR_Highlight; } static void action_log_unknown(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_LogUnknown(); dialog->user_action = CKR_Highlight; } static void action_remove_unknown(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_RemoveUnknown(); dialog->user_action = CKR_TookAction; } static void action_show_void(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_ShowInVoid(); dialog->user_action = CKR_Highlight; } static void action_remove_void(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_RemoveInVoid(); dialog->user_action = CKR_TookAction; } static void action_show_stuck(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_ShowStuckies(); dialog->user_action = CKR_Highlight; } }; check_result_e CHECK_Things(int min_severity = 0) { UI_Check_Things *dialog = new UI_Check_Things(min_severity > 0); selection_c sel; std::map types; for (;;) { Things_FindUnknown(sel, types); if (sel.empty()) dialog->AddLine("No unknown thing types"); else { sprintf(check_message, "%d unknown things", (int)types.size()); dialog->AddLine(check_message, 2, 200, "Show", &UI_Check_Things::action_show_unknown, "Log", &UI_Check_Things::action_log_unknown, "Remove", &UI_Check_Things::action_remove_unknown); } Things_FindStuckies(sel); if (sel.empty()) dialog->AddLine("No stuck actors"); else { sprintf(check_message, "%d stuck actors", sel.count_obj()); dialog->AddLine(check_message, 2, 200, "Show", &UI_Check_Things::action_show_stuck); } Things_FindInVoid(sel); if (sel.empty()) dialog->AddLine("No things in the void"); else { sprintf(check_message, "%d things in the void", sel.count_obj()); dialog->AddLine(check_message, 1, 200, "Show", &UI_Check_Things::action_show_void, "Remove", &UI_Check_Things::action_remove_void); } dialog->AddGap(10); int dm_num, mask; mask = Things_FindStarts(&dm_num); if (! (mask & 1)) dialog->AddLine("Player 1 start is missing!", 2); else if (! (mask & 2)) dialog->AddLine("Player 2 start is missing", 1); else if (! (mask & 4)) dialog->AddLine("Player 3 start is missing", 1); else if (! (mask & 8)) dialog->AddLine("Player 4 start is missing", 1); else dialog->AddLine("Found all 4 player starts"); if (dm_num == 0) dialog->AddLine("Map is missing deathmatch starts", 1); else if (dm_num < game_info.min_dm_starts) { sprintf(check_message, "Found %d deathmatch starts -- need at least %d", dm_num, game_info.min_dm_starts); dialog->AddLine(check_message, 1); } else if (dm_num > game_info.max_dm_starts) { sprintf(check_message, "Found %d deathmatch starts -- maximum is %d", dm_num, game_info.max_dm_starts); dialog->AddLine(check_message, 2); } else { sprintf(check_message, "Found %d deathmatch starts -- OK", dm_num); dialog->AddLine(check_message); } // in "ALL" mode, just continue if not too severe if (dialog->WorstSeverity() < min_severity) { delete dialog; return CKR_OK; } check_result_e result = dialog->Run(); if (result == CKR_TookAction) { // repeat the tests dialog->Reset(); continue; } delete dialog; return result; } } //------------------------------------------------------------------------ void CHECK_All(bool major_stuff) { bool no_worries = true; int min_severity = major_stuff ? 2 : 1; check_result_e result; result = CHECK_Vertices(min_severity); if (result == CKR_Highlight) return; if (result != CKR_OK) no_worries = false; result = CHECK_Sectors(min_severity); if (result == CKR_Highlight) return; if (result != CKR_OK) no_worries = false; result = CHECK_LineDefs(min_severity); if (result == CKR_Highlight) return; if (result != CKR_OK) no_worries = false; result = CHECK_Things(min_severity); if (result == CKR_Highlight) return; if (result != CKR_OK) no_worries = false; result = CHECK_Textures(min_severity); if (result == CKR_Highlight) return; if (result != CKR_OK) no_worries = false; result = CHECK_Tags(min_severity); if (result == CKR_Highlight) return; if (result != CKR_OK) no_worries = false; if (no_worries) { DLG_Notify(major_stuff ? "No major problems." : "All tests were successful."); } } //------------------------------------------------------------------------ void CMD_CheckMap() { const char *what = EXEC_Param[0]; if (! what[0]) { Beep("Check: missing keyword"); return; } else if (y_stricmp(what, "all") == 0) { CHECK_All(false); } else if (y_stricmp(what, "major") == 0) { CHECK_All(true); } else if (y_stricmp(what, "vertices") == 0) { CHECK_Vertices(); } else if (y_stricmp(what, "sectors") == 0) { CHECK_Sectors(); } else if (y_stricmp(what, "linedefs") == 0) { CHECK_LineDefs(); } else if (y_stricmp(what, "things") == 0) { CHECK_Things(); } else if (y_stricmp(what, "current") == 0) // current editing mode { switch (edit.mode) { case OBJ_VERTICES: CHECK_Vertices(); break; case OBJ_SECTORS: CHECK_Sectors(); break; case OBJ_LINEDEFS: CHECK_LineDefs(); break; case OBJ_THINGS: CHECK_Things(); break; default: Beep("Nothing to check"); break; } } else if (y_stricmp(what, "textures") == 0) { CHECK_Textures(); } else if (y_stricmp(what, "tags") == 0) { CHECK_Tags(); } else { Beep("Check: unknown keyword: %s\n", what); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_prefs.cc0000644000175100017510000010745512650275364016426 0ustar aaptedaapted//------------------------------------------------------------------------ // PREFERENCES DIALOG //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2016 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 "main.h" #include "m_config.h" #include #include "ui_window.h" #include "ui_prefs.h" #include #define PREF_WINDOW_W 600 #define PREF_WINDOW_H 500 #define PREF_WINDOW_TITLE "Eureka Preferences" static int last_active_tab = 0; class UI_EditKey : public UI_Escapable_Window { private: bool want_close; bool cancelled; bool grab_active; keycode_t key; Fl_Input *key_name; Fl_Choice *context; Fl_Choice *func; Fl_Input *params; const editor_command_t *cur_cmd; Fl_Menu_Button *keyword_menu; Fl_Menu_Button *flag_menu; Fl_Button *cancel; Fl_Button *ok_but; private: struct name_CMP_pred { inline bool operator() (const char * A, const char * B) const { return (strcmp(A, B) < 0); } }; int PopulateFuncMenu(key_context_e ctx, const char *find_name = NULL) { if (ctx == KCTX_Browser || ctx == KCTX_General) ctx = KCTX_NONE; func->clear(); // collect all names so we can sort them alphabetically std::vector< const char * > name_list; for (int i = 0 ; ; i++) { const editor_command_t *cmd = LookupEditorCommand(i); if (! cmd) break; if (cmd->req_context == ctx) name_list.push_back(cmd->name); } std::sort(name_list.begin(), name_list.end(), name_CMP_pred()); // add sorted names to menu, and find the current function int result = 0; cur_cmd = NULL; for (unsigned int k = 0 ; k < name_list.size() ; k++) { func->add(name_list[k]); if (find_name && strcmp(name_list[k], find_name) == 0) { result = (int)k; cur_cmd = FindEditorCommand(find_name); } } return result; } void Decode(key_context_e ctx, const char *str) { while (isspace(*str)) str++; char func_buf[100]; unsigned int pos = 0; while (*str && ! (isspace(*str) || *str == ':' || *str == '/') && pos + 4 < sizeof(func_buf)) { func_buf[pos++] = *str++; } func_buf[pos] = 0; func->value(PopulateFuncMenu(ctx, func_buf)); PopulateMenus(); if (*str == ':') str++; while (isspace(*str)) str++; params->value(str); } const char * Encode() { static char buffer[1024]; // should not happen if (! cur_cmd) return "ERROR"; strcpy(buffer, cur_cmd->name); if (strlen(buffer) + strlen(params->value()) + 10 >= sizeof(buffer)) return "OVERFLOW"; strcat(buffer, ": "); strcat(buffer, params->value()); return buffer; } void PopulateMenuList(Fl_Menu_Button *menu, const char *list) { menu->clear(); if (! list || ! list[0]) { menu->deactivate(); return; } const char * tokens[32]; int num_tok = M_ParseLine(list, tokens, 32, false); if (num_tok < 1) // shouldn't happen { menu->deactivate(); return; } for (int i = 0 ; i < num_tok ; i++) menu->add(tokens[i]); M_FreeLine(tokens, num_tok); menu->activate(); } void PopulateMenus() { PopulateMenuList(keyword_menu, cur_cmd ? cur_cmd->keyword_list : NULL); PopulateMenuList( flag_menu, cur_cmd ? cur_cmd-> flag_list : NULL); } bool ValidateKey() { keycode_t new_key = M_ParseKeyString(key_name->value()); if (new_key > 0) { key = new_key; return true; } return false; } static void validate_callback(Fl_Widget *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; bool valid_key = dialog->ValidateKey(); dialog->key_name->textcolor(valid_key ? FL_FOREGROUND_COLOR : FL_RED); // need to redraw the input box (otherwise get a mix of colors) dialog->key_name->redraw(); if (valid_key) dialog->ok_but->activate(); else dialog->ok_but->deactivate(); } static void grab_key_callback(Fl_Button *w, void *data) { // FIXME } static void close_callback(Fl_Widget *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; dialog->want_close = true; dialog->cancelled = true; } static void ok_callback(Fl_Button *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; dialog->want_close = true; } static void context_callback(Fl_Choice *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; key_context_e ctx = (key_context_e)(1 + w->value()); const char *cur_func = dialog->cur_cmd ? dialog->cur_cmd->name : NULL; dialog->func->value(dialog->PopulateFuncMenu(ctx, cur_func)); dialog->func->do_callback(); } static void func_callback(Fl_Choice *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; const char * name = w->mvalue()->text; SYS_ASSERT(name); dialog->cur_cmd = FindEditorCommand(name); dialog->PopulateMenus(); } void ReplaceKeyword(const char *new_word) { // delete existing keyword, if any if (isalnum(params->value()[0])) { const char *str = params->value(); int len = 0; while (str[len] && (isalnum(str[len]) || str[len] == '_')) len++; while (str[len] && isspace(str[len])) len++; params->replace(0, len, NULL); } if (params->size() > 0) params->replace(0, 0, " "); params->replace(0, 0, new_word); } void ReplaceFlag(const char *new_flag) { const char *str = params->value(); // if flag is already present, remove it const char *pos = strstr(str, new_flag); if (pos) { int a = (int)(pos - str); int b = a + (int)strlen(new_flag); while (str[b] && isspace(str[b])) b++; params->replace(a, b, NULL); return; } // append the flag, adding a space if necessary int a = params->size(); if (a > 0 && !isspace(str[a-1])) { params->replace(a, a, " "); a += 1; } params->replace(a, a, new_flag); } static void keyword_callback(Fl_Menu_Button *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; dialog->ReplaceKeyword(w->text()); } static void flag_callback(Fl_Menu_Button *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; dialog->ReplaceFlag(w->text()); } public: UI_EditKey(keycode_t _key, key_context_e ctx, const char *_func) : UI_Escapable_Window(400, 306, "Edit Key Binding"), want_close(false), cancelled(false), grab_active(false), key(_key) { if (ctx == KCTX_NONE) ctx = KCTX_General; callback(close_callback, this); { key_name = new Fl_Input(85, 25, 150, 25, "Key:"); if (key) key_name->value(M_KeyToString(key)); key_name->when(FL_WHEN_CHANGED); key_name->callback((Fl_Callback*)validate_callback, this); } { Fl_Button *o = new Fl_Button(250, 25, 85, 25, "Grab"); o->callback((Fl_Callback*)grab_key_callback, this); o->hide(); // TODO: IMPLEMENT THIS } { context = new Fl_Choice(85, 65, 150, 25, "Mode:"); context->add("Browser|Render|Vertex|Thing|Sector|Linedef|General"); context->value((int)ctx - 1); context->callback((Fl_Callback*)context_callback, this); } { func = new Fl_Choice(85, 105, 150, 25, "Function:"); func->callback((Fl_Callback*) func_callback, this); } { params = new Fl_Input(85, 145, 300, 25, "Params:"); params->value(""); params->when(FL_WHEN_CHANGED); // params->callback((Fl_Callback*)validate_callback, this); } { keyword_menu = new Fl_Menu_Button( 85, 180, 135, 25, "Keywords..."); keyword_menu->callback((Fl_Callback*) keyword_callback, this); } { flag_menu = new Fl_Menu_Button(250, 180, 135, 25, "Flags..."); flag_menu->callback((Fl_Callback*) flag_callback, this); } { Fl_Group *o = new Fl_Group(0, 240, 400, 66); o->box(FL_FLAT_BOX); o->color(WINDOW_BG, WINDOW_BG); { cancel = new Fl_Button(170, 254, 80, 35, "Cancel"); cancel->callback((Fl_Callback*)close_callback, this); } { ok_but = new Fl_Button(295, 254, 80, 35, "OK"); ok_but->labelfont(1); ok_but->callback((Fl_Callback*)ok_callback, this); ok_but->deactivate(); } o->end(); } end(); // parse line into function name and parameters Decode(ctx, _func); } bool Run(keycode_t *key_v, key_context_e *ctx_v, const char **func_v) { *key_v = 0; *ctx_v = KCTX_NONE; *func_v = NULL; // check the initial state validate_callback(this, this); set_modal(); show(); Fl::focus(params); while (! want_close) Fl::wait(0.2); if (cancelled) return false; *key_v = key; *ctx_v = (key_context_e)(1 + context->value()); *func_v = Encode(); return true; } }; //------------------------------------------------------------------------ class UI_Preferences : public Fl_Double_Window { private: bool want_quit; bool want_discard; char key_sort_mode; bool key_sort_rev; // normally zero (not waiting for a key) int awaiting_line; static void close_callback(Fl_Widget *w, void *data); static void color_callback(Fl_Button *w, void *data); static void sort_key_callback(Fl_Button *w, void *data); static void bind_key_callback(Fl_Button *w, void *data); static void edit_key_callback(Fl_Button *w, void *data); static void copy_key_callback(Fl_Button *w, void *data); static void del_key_callback(Fl_Button *w, void *data); static void reset_callback(Fl_Button *w, void *data); public: UI_Preferences(); void Run(); void LoadValues(); void SaveValues(); void LoadKeys(); void ReloadKeys(); int GridSizeToChoice(int size); /* FLTK override */ int handle(int event); void ClearWaiting(); void SetBinding(keycode_t key); void EnsureKeyVisible(int line); public: Fl_Tabs *tabs; Fl_Button *apply_but; Fl_Button *discard_but; /* General Tab */ Fl_Round_Button *theme_FLTK; Fl_Round_Button *theme_GTK; Fl_Round_Button *theme_plastic; Fl_Round_Button *cols_default; Fl_Round_Button *cols_bright; Fl_Round_Button *cols_custom; Fl_Button *bg_colorbox; Fl_Button *ig_colorbox; Fl_Button *fg_colorbox; Fl_Check_Button *gen_autoload; Fl_Check_Button *gen_maximized; Fl_Check_Button *gen_swapsides; /* Edit Tab */ Fl_Input *edit_def_port; Fl_Choice *edit_def_mode; Fl_Check_Button *edit_newislands; Fl_Check_Button *edit_samemode; Fl_Check_Button *edit_autoadjustX; Fl_Check_Button *edit_multiselect; Fl_Choice *edit_modkey; Fl_Int_Input *edit_sectorsize; Fl_Check_Button *edit_drawingmode; Fl_Check_Button *brow_smalltex; /* Grid Tab */ Fl_Check_Button *gen_scrollbars; Fl_Check_Button *grid_snap; Fl_Choice *grid_mode; Fl_Choice *grid_toggle; Fl_Choice *grid_size; Fl_Check_Button *gen_digitzoom; Fl_Choice *gen_smallscroll; Fl_Choice *gen_largescroll; Fl_Check_Button *gen_wheelscroll; Fl_Check_Button *grid_hide_free; Fl_Button *dotty_axis; Fl_Button *dotty_major; Fl_Button *dotty_minor; Fl_Button *dotty_point; Fl_Button *normal_axis; Fl_Button *normal_main; Fl_Button *normal_flat; Fl_Button *normal_small; /* Keys Tab */ Fl_Hold_Browser *key_list; Fl_Button *key_group; Fl_Button *key_key; Fl_Button *key_func; Fl_Button *key_bind; Fl_Button *key_copy; Fl_Button *key_edit; Fl_Button *key_delete; Fl_Button *key_reset; /* Mouse Tab */ /* Other Tab */ Fl_Float_Input *rend_aspect;; Fl_Check_Button *rend_high_detail; Fl_Check_Button *rend_lock_grav; Fl_Check_Button *bsp_warn; Fl_Check_Button *bsp_verbose; Fl_Check_Button *bsp_fast; }; #define R_SPACES " " UI_Preferences::UI_Preferences() : Fl_Double_Window(PREF_WINDOW_W, PREF_WINDOW_H, PREF_WINDOW_TITLE), want_quit(false), want_discard(false), key_sort_mode('c'), key_sort_rev(false), awaiting_line(0) { if (gui_color_set == 2) color(fl_gray_ramp(4)); else color(WINDOW_BG); callback(close_callback, this); { tabs = new Fl_Tabs(0, 0, 585, 435); /* ---- General Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 405, " General" R_SPACES); o->labelsize(16); // o->hide(); { Fl_Box* o = new Fl_Box(25, 45, 145, 30, "GUI Appearance"); o->labelfont(1); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { Fl_Group* o = new Fl_Group(45, 90, 250, 115); { theme_FLTK = new Fl_Round_Button(50, 90, 150, 25, " FLTK theme"); theme_FLTK->type(102); theme_FLTK->down_box(FL_ROUND_DOWN_BOX); } { theme_GTK = new Fl_Round_Button(50, 120, 150, 25, " GTK+ theme "); theme_GTK->type(102); theme_GTK->down_box(FL_ROUND_DOWN_BOX); } { theme_plastic = new Fl_Round_Button(50, 150, 165, 25, " plastic theme "); theme_plastic->type(102); theme_plastic->down_box(FL_ROUND_DOWN_BOX); } o->end(); } { Fl_Group* o = new Fl_Group(220, 90, 190, 90); { cols_default = new Fl_Round_Button(245, 90, 135, 25, "default colors"); cols_default->type(102); cols_default->down_box(FL_ROUND_DOWN_BOX); } { cols_bright = new Fl_Round_Button(245, 120, 140, 25, "bright colors"); cols_bright->type(102); cols_bright->down_box(FL_ROUND_DOWN_BOX); } { cols_custom = new Fl_Round_Button(245, 150, 165, 25, "custom colors ---->"); cols_custom->type(102); cols_custom->down_box(FL_ROUND_DOWN_BOX); } o->end(); } { Fl_Group* o = new Fl_Group(385, 80, 205, 100); o->color(FL_LIGHT1); o->align(Fl_Align(FL_ALIGN_BOTTOM_LEFT|FL_ALIGN_INSIDE)); { bg_colorbox = new Fl_Button(430, 90, 45, 25, "background"); bg_colorbox->box(FL_BORDER_BOX); bg_colorbox->align(Fl_Align(FL_ALIGN_RIGHT)); bg_colorbox->callback((Fl_Callback*)color_callback, this); } { ig_colorbox = new Fl_Button(430, 120, 45, 25, "input bg"); ig_colorbox->box(FL_BORDER_BOX); ig_colorbox->color(FL_BACKGROUND2_COLOR); ig_colorbox->align(Fl_Align(FL_ALIGN_RIGHT)); ig_colorbox->callback((Fl_Callback*)color_callback, this); } { fg_colorbox = new Fl_Button(430, 150, 45, 25, "text color"); fg_colorbox->box(FL_BORDER_BOX); fg_colorbox->color(FL_GRAY0); fg_colorbox->align(Fl_Align(FL_ALIGN_RIGHT)); fg_colorbox->callback((Fl_Callback*)color_callback, this); } o->end(); } { Fl_Box* o = new Fl_Box(30, 240, 280, 35, "Miscellaneous"); o->labelfont(1); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { gen_autoload = new Fl_Check_Button(50, 280, 380, 25, " automatically open the most recent pwad"); gen_autoload->down_box(FL_DOWN_BOX); } { gen_swapsides = new Fl_Check_Button(50, 310, 380, 25, " swap upper and lower sidedefs in Linedef panel"); gen_swapsides->down_box(FL_DOWN_BOX); } { gen_maximized = new Fl_Check_Button(50, 340, 380, 25, " maximize the window when Eureka starts"); gen_maximized->down_box(FL_DOWN_BOX); // not supported on MacOS X // (on that platform we should restore last window position, but I don't // know how to code that) #ifdef __APPLE__ gen_maximized->hide(); #endif } o->end(); } /* ---- Editing Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 410, " Editing" R_SPACES); o->labelsize(16); o->hide(); { Fl_Box* o = new Fl_Box(25, 45, 355, 30, "Editing Options"); o->labelfont(1); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { edit_def_port = new Fl_Input(150, 85, 95, 25, "default port: "); edit_def_port->align(FL_ALIGN_LEFT); } { edit_def_mode = new Fl_Choice(440, 85, 105, 25, "default edit mode: "); edit_def_mode->align(FL_ALIGN_LEFT); edit_def_mode->add("Things|Linedefs|Sectors|Vertices"); } { edit_newislands = new Fl_Check_Button(50, 120, 265, 30, " new islands have void interior"); edit_newislands->down_box(FL_DOWN_BOX); } { edit_autoadjustX = new Fl_Check_Button(50, 150, 260, 30, " auto-adjust X offsets"); edit_autoadjustX->down_box(FL_DOWN_BOX); } { edit_samemode = new Fl_Check_Button(50, 180, 270, 30, " same mode key will clear selection"); edit_samemode->down_box(FL_DOWN_BOX); } { edit_multiselect = new Fl_Check_Button(50, 210, 275, 30, " multi-select requires a modifier key"); edit_multiselect->down_box(FL_DOWN_BOX); } { edit_modkey = new Fl_Choice(370, 210, 95, 30, "----> "); edit_modkey->down_box(FL_BORDER_BOX); edit_modkey->add("CTRL"); edit_modkey->value(0); } { edit_sectorsize = new Fl_Int_Input(440, 120, 105, 25, "new sector size:"); } { edit_drawingmode = new Fl_Check_Button(50, 240, 270, 30, " easier line drawing using the LMB"); edit_drawingmode->down_box(FL_DOWN_BOX); } { Fl_Box* o = new Fl_Box(25, 295, 355, 30, "Browser Options"); o->labelfont(1); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { brow_smalltex = new Fl_Check_Button(50, 330, 265, 30, " smaller textures"); brow_smalltex->down_box(FL_DOWN_BOX); } o->end(); } /* ---- Grid Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 410, " Grid" R_SPACES); o->labelsize(16); o->hide(); { Fl_Box* o = new Fl_Box(25, 45, 355, 30, "Map Grid and Scrolling"); o->labelfont(1); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { gen_scrollbars = new Fl_Check_Button(50, 80, 245, 25, " enable scroll-bars for map view"); gen_scrollbars->down_box(FL_DOWN_BOX); } { grid_snap = new Fl_Check_Button(50, 110, 235, 25, " default SNAP mode"); grid_snap->down_box(FL_DOWN_BOX); } { grid_size = new Fl_Choice(435, 110, 95, 25, "default grid size "); grid_size->down_box(FL_BORDER_BOX); grid_size->add("1024|512|256|192|128|64|32|16|8|4|2"); } { grid_mode = new Fl_Choice(435, 145, 95, 25, "default grid type "); grid_mode->down_box(FL_BORDER_BOX); grid_mode->add("OFF|Dotty|Normal"); } { grid_toggle = new Fl_Choice(435, 180, 95, 25, "grid toggle types "); grid_toggle->down_box(FL_BORDER_BOX); grid_toggle->add("BOTH|Dotty|Normal"); } { gen_digitzoom = new Fl_Check_Button(50, 140, 240, 25, " digit keys zoom the map"); gen_digitzoom->down_box(FL_DOWN_BOX); } { gen_smallscroll = new Fl_Choice(435, 140, 95, 25, "small scroll step "); gen_smallscroll->down_box(FL_BORDER_BOX); gen_smallscroll->hide(); } { gen_largescroll = new Fl_Choice(435, 170, 95, 25, "large scroll step "); gen_largescroll->down_box(FL_BORDER_BOX); gen_largescroll->hide(); } { gen_wheelscroll = new Fl_Check_Button(50, 170, 245, 25, " mouse wheel scrolls the map"); gen_wheelscroll->down_box(FL_DOWN_BOX); } { grid_hide_free = new Fl_Check_Button(50, 200, 245, 25, " hide grid in FREE mode"); grid_hide_free->down_box(FL_DOWN_BOX); } { Fl_Box* o = new Fl_Box(25, 270, 355, 30, "Grid Colors"); o->labelfont(1); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { normal_axis = new Fl_Button(150 + 0*55, 300, 45, 25, "Normal Grid : "); normal_axis->box(FL_BORDER_BOX); normal_axis->align(FL_ALIGN_LEFT); normal_axis->callback((Fl_Callback*)color_callback, this); } { normal_main = new Fl_Button(150 + 1*55, 300, 45, 25, ""); normal_main->box(FL_BORDER_BOX); normal_main->align(FL_ALIGN_RIGHT); normal_main->callback((Fl_Callback*)color_callback, this); } { normal_flat = new Fl_Button(150 + 2*55, 300, 45, 25, ""); normal_flat->box(FL_BORDER_BOX); normal_flat->align(FL_ALIGN_RIGHT); normal_flat->callback((Fl_Callback*)color_callback, this); } { normal_small = new Fl_Button(150 + 3*55, 300, 45, 25, ""); normal_small->box(FL_BORDER_BOX); normal_small->align(FL_ALIGN_RIGHT); normal_small->callback((Fl_Callback*)color_callback, this); } { dotty_axis = new Fl_Button(150 + 0*55, 340, 45, 25, "Dotty Grid : "); dotty_axis->box(FL_BORDER_BOX); dotty_axis->align(FL_ALIGN_LEFT); dotty_axis->callback((Fl_Callback*)color_callback, this); } { dotty_major = new Fl_Button(150 + 1*55, 340, 45, 25, ""); dotty_major->box(FL_BORDER_BOX); dotty_major->align(FL_ALIGN_RIGHT); dotty_major->callback((Fl_Callback*)color_callback, this); } { dotty_minor = new Fl_Button(150 + 2*55, 340, 45, 25, ""); dotty_minor->box(FL_BORDER_BOX); dotty_minor->align(FL_ALIGN_RIGHT); dotty_minor->callback((Fl_Callback*)color_callback, this); } { dotty_point = new Fl_Button(150 + 3*55, 340, 45, 25, ""); dotty_point->box(FL_BORDER_BOX); dotty_point->align(FL_ALIGN_RIGHT); dotty_point->callback((Fl_Callback*)color_callback, this); } o->end(); } /* ---- Key bindings Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 410, " Keys" R_SPACES); o->labelsize(16); o->hide(); { Fl_Box* o = new Fl_Box(25, 45, 355, 30, "Key Bindings"); o->labelfont(1); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { key_key = new Fl_Button(30, 90, 120, 25, "KEY"); key_key->color((Fl_Color)231); key_key->align(Fl_Align(FL_ALIGN_INSIDE)); key_key->callback((Fl_Callback*)sort_key_callback, this); } { key_group = new Fl_Button(155, 90, 90, 25, "MODE"); key_group->color((Fl_Color)231); key_group->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); key_group->callback((Fl_Callback*)sort_key_callback, this); } { key_func = new Fl_Button(250, 90, 190, 25, "FUNCTION"); key_func->color((Fl_Color)231); key_func->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); key_func->callback((Fl_Callback*)sort_key_callback, this); } { key_list = new Fl_Hold_Browser(30, 115, 430, 295); key_list->textfont(FL_COURIER); } { key_bind = new Fl_Button(470, 140, 90, 30, "Bind"); key_bind->callback((Fl_Callback*)bind_key_callback, this); key_bind->shortcut(FL_Enter); } { key_copy = new Fl_Button(470, 185, 90, 30, "&Copy"); key_copy->callback((Fl_Callback*)copy_key_callback, this); } { key_edit = new Fl_Button(470, 230, 90, 30, "&Edit"); key_edit->callback((Fl_Callback*)edit_key_callback, this); } { key_delete = new Fl_Button(470, 275, 90, 30, "Delete"); key_delete->callback((Fl_Callback*)del_key_callback, this); key_delete->shortcut(FL_Delete); } { key_reset = new Fl_Button(470, 335, 90, 50, "Reset\nDefaults"); key_reset->callback((Fl_Callback*)reset_callback, this); } o->end(); } /* ---- Mouse Tab ---- */ #if 0 { Fl_Group* o = new Fl_Group(0, 25, 585, 410, " Mouse" R_SPACES); o->labelsize(16); o->hide(); o->end(); } #endif /* ---- Other Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 410, " Other" R_SPACES); o->selection_color(FL_LIGHT1); o->labelsize(16); o->hide(); { Fl_Box* o = new Fl_Box(25, 45, 280, 30, "3D Preview Options"); o->labelfont(1); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { rend_aspect = new Fl_Float_Input(190, 90, 95, 25, "Pixel aspect ratio: "); } { rend_high_detail = new Fl_Check_Button(50, 125, 360, 30, " High detail -- slower but looks better"); rend_high_detail->down_box(FL_DOWN_BOX); } { rend_lock_grav = new Fl_Check_Button(50, 155, 360, 30, " Locked gravity -- cannot move up or down"); rend_lock_grav->down_box(FL_DOWN_BOX); } { Fl_Box* o = new Fl_Box(25, 250, 280, 30, "glBSP Node Building"); o->labelfont(1); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { bsp_warn = new Fl_Check_Button(50, 290, 220, 30, " Show all warning messages"); bsp_warn->down_box(FL_DOWN_BOX); } { bsp_verbose = new Fl_Check_Button(50, 320, 350, 30, " Verbose -- show information about each level"); bsp_verbose->down_box(FL_DOWN_BOX); } { bsp_fast = new Fl_Check_Button(50, 350, 440, 30, " Fast -- build the fastest way, but nodes may not be as good"); bsp_fast->down_box(FL_DOWN_BOX); } o->end(); } tabs->end(); } { apply_but = new Fl_Button(480, 450, 95, 35, "Apply"); apply_but->labelfont(1); apply_but->callback(close_callback, this); } { discard_but = new Fl_Button(350, 450, 95, 35, "Discard"); discard_but->callback(close_callback, this); } end(); } //------------------------------------------------------------------------ void UI_Preferences::close_callback(Fl_Widget *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; prefs->want_quit = true; if (w == prefs->discard_but) prefs->want_discard = true; } void UI_Preferences::color_callback(Fl_Button *w, void *data) { // UI_Preferences *dialog = (UI_Preferences *)data; uchar r, g, b; Fl::get_color(w->color(), r, g, b); if (! fl_color_chooser("New color:", r, g, b, 3)) return; w->color(fl_rgb_color(r, g, b)); w->redraw(); } void UI_Preferences::bind_key_callback(Fl_Button *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; int line = prefs->key_list->value(); if (line < 1) { fl_beep(); return; } prefs->EnsureKeyVisible(line); int bind_idx = line - 1; // show we're ready to accept a new key const char *str = M_StringForBinding(bind_idx, true /* changing_key */); SYS_ASSERT(str); prefs->key_list->text(line, str); prefs->key_list->selection_color(FL_YELLOW); Fl::focus(prefs); prefs->awaiting_line = line; } void UI_Preferences::sort_key_callback(Fl_Button *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; if (w == prefs->key_group) { if (prefs->key_sort_mode != 'c') { prefs->key_sort_mode = 'c'; prefs->key_sort_rev = false; } else prefs->key_sort_rev = !prefs->key_sort_rev; } else if (w == prefs->key_key) { if (prefs->key_sort_mode != 'k') { prefs->key_sort_mode = 'k'; prefs->key_sort_rev = false; } else prefs->key_sort_rev = !prefs->key_sort_rev; } else if (w == prefs->key_func) { if (prefs->key_sort_mode != 'f') { prefs->key_sort_mode = 'f'; prefs->key_sort_rev = false; } else prefs->key_sort_rev = !prefs->key_sort_rev; } prefs->LoadKeys(); } void UI_Preferences::copy_key_callback(Fl_Button *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; int line = prefs->key_list->value(); if (line < 1) { fl_beep(); return; } int bind_idx = line - 1; keycode_t new_key; key_context_e new_context; M_GetBindingInfo(bind_idx, &new_key, &new_context); const char *new_func = M_StringForFunc(bind_idx); M_AddLocalBinding(bind_idx, new_key, new_context, new_func); // we will reload the lines, so use a dummy one here prefs->key_list->insert(line + 1, ""); prefs->key_list->select(line + 1); prefs->ReloadKeys(); bind_key_callback(w, data); } void UI_Preferences::edit_key_callback(Fl_Button *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; int line = prefs->key_list->value(); if (line < 1) { fl_beep(); return; } prefs->EnsureKeyVisible(line); int bind_idx = line - 1; keycode_t new_key; key_context_e new_context; M_GetBindingInfo(bind_idx, &new_key, &new_context); const char *new_func = M_StringForFunc(bind_idx); UI_EditKey *dialog = new UI_EditKey(new_key, new_context, new_func); if (dialog->Run(&new_key, &new_context, &new_func)) { // assume it works (since we validated it) M_SetLocalBinding(bind_idx, new_key, new_context, new_func); } delete dialog; prefs->ReloadKeys(); Fl::focus(prefs->key_list); } void UI_Preferences::del_key_callback(Fl_Button *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; int line = prefs->key_list->value(); if (line < 1) { fl_beep(); return; } M_DeleteLocalBinding(line - 1); prefs->key_list->remove(line); prefs->ReloadKeys(); if (line <= prefs->key_list->size()) { prefs->key_list->select(line); Fl::focus(prefs->key_list); } } void UI_Preferences::reset_callback(Fl_Button *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; if (true) { int res = DLG_Confirm("Cancel|Reset", "You are about to reset all key bindings to their default " "values. Pressing the preference window's \"Apply\" button " "will cause any changes you have made to be lost." "\n\n" "Are you sure you want to continue?"); if (res <= 0) return; } M_CopyBindings(true /* from_defaults */); prefs->LoadKeys(); } void UI_Preferences::Run() { if (last_active_tab < tabs->children()) tabs->value(tabs->child(last_active_tab)); M_CopyBindings(); LoadValues(); LoadKeys(); set_modal(); show(); while (! want_quit) { Fl::wait(0.2); } last_active_tab = tabs->find(tabs->value()); if (want_discard) { LogPrintf("Preferences: discarded changes\n"); return; } SaveValues(); M_WriteConfigFile(); M_ApplyBindings(); M_SaveBindings(); } int UI_Preferences::GridSizeToChoice(int size) { if (size > 512) return 0; if (size > 256) return 1; if (size > 128) return 2; if (size > 64) return 3; if (size > 32) return 4; if (size > 16) return 5; if (size > 8) return 6; if (size > 4) return 7; if (size > 2) return 8; return 9; } void UI_Preferences::LoadValues() { /* Theme stuff */ switch (gui_scheme) { case 0: theme_FLTK->value(1); break; case 1: theme_GTK->value(1); break; case 2: theme_plastic->value(1); break; } switch (gui_color_set) { case 0: cols_default->value(1); break; case 1: cols_bright->value(1); break; case 2: cols_custom->value(1); break; } bg_colorbox->color(gui_custom_bg); ig_colorbox->color(gui_custom_ig); fg_colorbox->color(gui_custom_fg); /* General Tab */ gen_autoload ->value(auto_load_recent ? 1 : 0); gen_maximized ->value(begin_maximized ? 1 : 0); gen_swapsides ->value(swap_sidedefs ? 1 : 0); /* Edit Tab */ edit_def_port->value(default_port); edit_def_mode->value(CLAMP(0, default_edit_mode, 3)); edit_sectorsize->value(Int_TmpStr(new_sector_size)); edit_newislands->value(new_islands_are_void ? 1 : 0); edit_samemode->value(same_mode_clears_selection ? 1 : 0); edit_autoadjustX->value(leave_offsets_alone ? 0 : 1); edit_multiselect->value(multi_select_modifier ? 2 : 0); edit_drawingmode->value(easier_drawing_mode ? 1 : 0); brow_smalltex->value(browser_small_tex ? 1 : 0); /* Grid Tab */ if (default_grid_mode < 0 || default_grid_mode > 2) default_grid_mode = 2; if (grid_toggle_type < 0 || grid_toggle_type > 2) grid_toggle_type = 0; grid_snap->value(default_grid_snap ? 1 : 0); grid_size->value(GridSizeToChoice(default_grid_size)); grid_mode->value(default_grid_mode); grid_toggle->value(grid_toggle_type); gen_digitzoom ->value(digits_set_zoom ? 1 : 0); grid_hide_free ->value(grid_hide_in_free_mode ? 1 : 0); gen_wheelscroll->value(mouse_wheel_scrolls_map ? 1 : 0); gen_scrollbars ->value(map_scroll_bars ? 1 : 0); dotty_axis ->color(dotty_axis_col); dotty_major->color(dotty_major_col); dotty_minor->color(dotty_minor_col); dotty_point->color(dotty_point_col); normal_axis ->color(normal_axis_col); normal_main ->color(normal_main_col); normal_flat ->color(normal_flat_col); normal_small->color(normal_small_col); // TODO: smallscroll, largescroll /* Other Tab */ render_pixel_aspect = CLAMP(25, render_pixel_aspect, 400); char aspect_buf[64]; sprintf(aspect_buf, "%1.2f", render_pixel_aspect / 100.0); rend_aspect->value(aspect_buf); rend_high_detail->value(render_high_detail ? 1 : 0); rend_lock_grav->value(render_lock_gravity ? 1 : 0); bsp_fast->value(glbsp_fast ? 1 : 0); bsp_verbose->value(glbsp_verbose ? 1 : 0); bsp_warn->value(glbsp_warn ? 1 : 0); } void UI_Preferences::SaveValues() { /* Theme stuff */ if (theme_FLTK->value()) gui_scheme = 0; else if (theme_GTK->value()) gui_scheme = 1; else gui_scheme = 2; if (cols_default->value()) gui_color_set = 0; else if (cols_bright->value()) gui_color_set = 1; else gui_color_set = 2; gui_custom_bg = (rgb_color_t) bg_colorbox->color(); gui_custom_ig = (rgb_color_t) ig_colorbox->color(); gui_custom_fg = (rgb_color_t) fg_colorbox->color(); // update the colors // FIXME: how to reset the "default" colors?? if (gui_color_set == 1) { Fl::background(236, 232, 228); Fl::background2(255, 255, 255); Fl::foreground(0, 0, 0); main_win->redraw(); } else if (gui_color_set == 2) { Fl::background (RGB_RED(gui_custom_bg), RGB_GREEN(gui_custom_bg), RGB_BLUE(gui_custom_bg)); Fl::background2(RGB_RED(gui_custom_ig), RGB_GREEN(gui_custom_ig), RGB_BLUE(gui_custom_ig)); Fl::foreground (RGB_RED(gui_custom_fg), RGB_GREEN(gui_custom_fg), RGB_BLUE(gui_custom_fg)); main_win->redraw(); } /* General Tab */ auto_load_recent = gen_autoload ->value() ? true : false; begin_maximized = gen_maximized ->value() ? true : false; swap_sidedefs = gen_swapsides ->value() ? true : false; /* Edit Tab */ default_port = StringDup(edit_def_port->value()); default_edit_mode = edit_def_mode->value(); new_sector_size = atoi(edit_sectorsize->value()); new_sector_size = CLAMP(4, new_sector_size, 8192); new_islands_are_void = edit_newislands->value() ? true : false; same_mode_clears_selection = edit_samemode->value() ? true : false; leave_offsets_alone = edit_autoadjustX->value() ? false : true; multi_select_modifier = edit_multiselect->value() ? 2 : 0; easier_drawing_mode = edit_drawingmode->value() ? true : false; // changing this requires re-populating the browser bool new_small_tex = brow_smalltex->value() ? true : false; if (new_small_tex != browser_small_tex) { browser_small_tex = new_small_tex; main_win->browser->Populate(); } /* Grid Tab */ default_grid_snap = grid_snap->value() ? true : false; default_grid_size = atoi(grid_size->mvalue()->text); default_grid_mode = grid_mode->value(); grid_toggle_type = grid_toggle->value(); digits_set_zoom = gen_digitzoom ->value() ? true : false; grid_hide_in_free_mode = grid_hide_free ->value() ? true : false; mouse_wheel_scrolls_map = gen_wheelscroll->value() ? true : false; map_scroll_bars = gen_scrollbars ->value() ? true : false; dotty_axis_col = (rgb_color_t) dotty_axis ->color(); dotty_major_col = (rgb_color_t) dotty_major->color(); dotty_minor_col = (rgb_color_t) dotty_minor->color(); dotty_point_col = (rgb_color_t) dotty_point->color(); normal_axis_col = (rgb_color_t) normal_axis ->color(); normal_main_col = (rgb_color_t) normal_main ->color(); normal_flat_col = (rgb_color_t) normal_flat ->color(); normal_small_col = (rgb_color_t) normal_small->color(); // TODO: smallscroll, largescroll /* Other Tab */ render_pixel_aspect = (int)(100 * atof(rend_aspect->value()) + 0.2); render_pixel_aspect = CLAMP(25, render_pixel_aspect, 400); render_high_detail = rend_high_detail->value() ? true : false; render_lock_gravity = rend_lock_grav->value() ? true : false; glbsp_fast = bsp_fast->value() ? true : false; glbsp_verbose = bsp_verbose->value() ? true : false; glbsp_warn = bsp_warn->value() ? true : false; } void UI_Preferences::LoadKeys() { M_SortBindings(key_sort_mode, key_sort_rev); M_DetectConflictingBinds(); key_list->clear(); for (int i = 0 ; i < M_NumBindings() ; i++) { const char *str = M_StringForBinding(i); SYS_ASSERT(str); key_list->add(str); } key_list->select(1); } void UI_Preferences::ReloadKeys() { M_DetectConflictingBinds(); for (int i = 0 ; i < M_NumBindings() ; i++) { const char *str = M_StringForBinding(i); key_list->text(i + 1, str); } } void UI_Preferences::EnsureKeyVisible(int line) { if (! key_list->displayed(line)) { key_list->middleline(line); } } void UI_Preferences::ClearWaiting() { if (awaiting_line > 0) { // restore the text line ReloadKeys(); Fl::focus(key_list); } awaiting_line = 0; key_list->selection_color(FL_SELECTION_COLOR); } void UI_Preferences::SetBinding(keycode_t key) { int bind_idx = awaiting_line - 1; M_ChangeBindingKey(bind_idx, key); ClearWaiting(); } int UI_Preferences::handle(int event) { if (awaiting_line > 0) { if (event == FL_KEYDOWN) { if (Fl::event_key() == FL_Escape) { ClearWaiting(); return 1; } keycode_t key = M_TranslateKey(Fl::event_key(), Fl::event_state()); if (key != 0) { SetBinding(key); return 1; } } if (event == FL_PUSH) ClearWaiting(); } return Fl_Double_Window::handle(event); } //------------------------------------------------------------------------ void CMD_Preferences() { UI_Preferences * dialog = new UI_Preferences(); dialog->Run(); delete dialog; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/w_flats.cc0000644000175100017510000000507312647061302016231 0ustar aaptedaapted//------------------------------------------------------------------------ // FLAT LOADING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include #include #include "m_game.h" /* yg_picture_format */ #include "levels.h" #include "w_loadpic.h" #include "w_rawdef.h" #include "w_flats.h" #include "w_wad.h" std::map flats; static void DeleteFlat(const std::map::value_type& P) { delete P.second; } static void W_ClearFlats() { std::for_each(flats.begin(), flats.end(), DeleteFlat); flats.clear(); } void W_LoadFlats() { W_ClearFlats(); for (int i = 0 ; i < (int)master_dir.size() ; i++) { LogPrintf("Loading Flats from WAD #%d\n", i+1); Wad_file *wf = master_dir[i]; for (int k = 0 ; k < (int)wf->flats.size() ; k++) { Lump_c *lump = wf->GetLump(wf->flats[k]); DebugPrintf(" Flat %d : '%s'\n", k, lump->Name()); // TODO: check size == 64*64 Img_c *img = new Img_c(64, 64, false); if (! lump->Seek() || ! lump->Read(img->wbuf(), 64*64)) FatalError("Error reading flat from WAD.\n"); // FIXME: free any existing one with same name flats[std::string(lump->Name())] = img; } } } Img_c * W_GetFlat(const char *name) { std::string f_str = name; std::map::iterator P = flats.find(f_str); if (P != flats.end()) return P->second; return NULL; } bool W_FlatExists(const char *name) { std::string f_str = name; std::map::iterator P = flats.find(f_str); return (P != flats.end()); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_sector.h0000644000175100017510000000261612651123650016237 0ustar aaptedaapted//------------------------------------------------------------------------ // SECTOR OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_SECTOR_H__ #define __EUREKA_E_SECTOR_H__ /* commands */ void SEC_Floor(void); void SEC_Ceil(void); void CMD_AdjustLight(int delta); void SEC_Light(void); void SEC_Merge(void); void SEC_SwapFlats(void); #endif /* __EUREKA_E_SECTOR_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/w_texture.h0000644000175100017510000000262712647061302016464 0ustar aaptedaapted//------------------------------------------------------------------------ // TEXTURE LOADING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2015 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_W_TEXTURE_H__ #define __EUREKA_W_TEXTURE_H__ #include "im_img.h" void W_LoadTextures(); bool W_TextureExists(const char *name); Img_c * W_GetTexture(const char *name); bool W_TextureCausesMedusa(const char *name); #endif /* __EUREKA_W_TEXTURE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/lib_util.cc0000644000175100017510000001470412647061302016376 0ustar aaptedaapted//------------------------------------------------------------------------ // UTILITIES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include #include "w_rawdef.h" /* * y_stricmp * A case-insensitive strcmp() * (same thing as DOS stricmp() or GNU strcasecmp()) */ int y_stricmp (const char *s1, const char *s2) { for (;;) { if (tolower (*s1) != tolower (*s2)) return (unsigned char) *s1 - (unsigned char) *s2; if (! *s1) { if (! *s2) return 0; else return -1; } if (! *s2) return 1; s1++; s2++; } } /* * y_strnicmp * A case-insensitive strncmp() * (same thing as DOS strnicmp() or GNU strncasecmp()) */ int y_strnicmp (const char *s1, const char *s2, size_t len) { while (len-- > 0) { if (tolower (*s1) != tolower (*s2)) return (unsigned char) *s1 - (unsigned char) *s2; if (! *s1) { if (! *s2) return 0; else return -1; } if (! *s2) return 1; s1++; s2++; } return 0; } /* * y_strupr * Upper-case a string */ void y_strupr (char *str) { for (; *str; str++) { *str = toupper(*str); } } /* * y_strlowr * Lower-case a string */ void y_strlowr (char *str) { for (; *str; str++) { *str = tolower(*str); } } char *StringNew(int length) { // length does not include the trailing NUL. char *s = (char *) calloc(length + 1, 1); if (! s) FatalError("Out of memory (%d bytes for string)\n", length); return s; } char *StringDup(const char *orig, int limit) { if (! orig) return NULL; if (limit < 0) { char *s = strdup(orig); if (! s) FatalError("Out of memory (copy string)\n"); return s; } char * s = StringNew(limit+1); strncpy(s, orig, limit); s[limit] = 0; return s; } char *StringUpper(const char *name) { char *copy = StringDup(name); for (char *p = copy; *p; p++) *p = toupper(*p); return copy; } char *StringPrintf(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 = (char*)realloc(buf, buf_size); if (!buf) FatalError("Out of memory (formatting string)\n"); 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; } } void StringFree(const char *str) { if (str) { free((void*) str); } } void StringRemoveCRLF(char *str) { size_t len = strlen(str); if (len > 0 && str[len - 1] == '\n') str[--len] = 0; if (len > 0 && str[len - 1] == '\r') str[--len] = 0; } char * StringTidy(const char *str, const char *bad_chars) { static char buffer[FL_PATH_MAX]; char *dest = buffer; char *d_end = &buffer[FL_PATH_MAX-2]; for ( ; *str && dest < d_end ; str++) if (isprint(*str) && ! strchr(bad_chars, *str)) *dest++ = *str; *dest = 0; return buffer; } void TimeDelay(unsigned int millies) { SYS_ASSERT(millies < 300000); #ifdef WIN32 ::Sleep(millies); #else // LINUX or MacOSX usleep(millies * 1000); #endif } unsigned int TimeGetMillies() { // Note: you *MUST* handle overflow (it *WILL* happen) #ifdef WIN32 return GetTickCount(); #else struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); return ((int)tv.tv_sec * 1000 + (int)tv.tv_usec / 1000); #endif } /* * check_types * * Sanity checks about the sizes and properties of certain types. * Useful when porting. */ #define assert_size(type,size) \ do \ { \ if (sizeof (type) != size) \ FatalError("sizeof " #type " is %d (should be " #size ")\n", \ (int) sizeof (type)); \ } \ while (0) #define assert_wrap(type,high,low) \ do \ { \ type n = high; \ if (++n != low) \ FatalError("Type " #type " wraps around to %lu (should be " #low ")\n",\ (unsigned long) n); \ } \ while (0) void check_types () { assert_size (u8_t, 1); assert_size (s8_t, 1); assert_size (u16_t, 2); assert_size (s16_t, 2); assert_size (u32_t, 4); assert_size (s32_t, 4); assert_size (raw_linedef_t, 14); assert_size (raw_sector_s, 26); assert_size (raw_sidedef_t, 30); assert_size (raw_thing_t, 10); assert_size (raw_vertex_t, 4); } /* translate (dx, dy) into an integer angle value (0-65535) */ unsigned ComputeAngle(int dx, int dy) { return (unsigned) (atan2 ((double) dy, (double) dx) * 10430.37835 + 0.5); } /* compute the distance from (0, 0) to (dx, dy) */ unsigned ComputeDist(int dx, int dy) { return (unsigned) (hypot ((double) dx, (double) dy) + 0.5); } double PerpDist(double x, double y, double x1, double y1, double x2, double y2) { x -= x1; y -= y1; x2 -= x1; y2 -= y1; double len = sqrt(x2*x2 + y2*y2); SYS_ASSERT(len > 0); return (x * y2 - y * x2) / len; } double AlongDist(double x, double y, double x1, double y1, double x2, double y2) { x -= x1; y -= y1; x2 -= x1; y2 -= y1; double len = sqrt(x2*x2 + y2*y2); SYS_ASSERT(len > 0); return (x * x2 + y * y2) / len; } const char *Int_TmpStr(int value) { static char buffer[200]; sprintf(buffer, "%d", value); return buffer; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_keys.h0000644000175100017510000001063512647061302015723 0ustar aaptedaapted//------------------------------------------------------------------------ // KEY BINDINGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2013-2015 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 __EUREKA_M_KEYS_H__ #define __EUREKA_M_KEYS_H__ /* key value: * - can be a printable ASCII character, e.g. 'a', 'A', '2', ';' * - spacebar is ' ' * - all other keys use the FLTK code (e.g. FL_Enter, FL_Up, etc) * - control keys (like CTRL-A) use MOD_COMMAND flag (never '\001') * * modifier (MOD_XXXX value) is or-ed with the bare key. * - uppercase letters (etc) do _not_ have the MOD_SHIFT flag * - digits, however, _do_ have MOD_SHIFT * - can extract bare key with FL_KEY_MASK * - can extract modifier with MOD_ALL_MASK * - currently only a single modifier will be present: * MOD_COMMAND > MOD_META > MOD_ALT > MOD_SHIFT * - using my own names since "FL_CONTROL" is fucking confusing */ typedef unsigned int keycode_t; #define MOD_none 0 #undef MOD_ALT // these clash with Windows defines #undef MOD_SHIFT // #define MOD_COMMAND FL_COMMAND #define MOD_META FL_CONTROL #define MOD_ALT FL_ALT #define MOD_SHIFT FL_SHIFT #define MOD_ALL_MASK (MOD_COMMAND | MOD_META | MOD_ALT | MOD_SHIFT) // values to represent the mouse wheel #define FL_WheelUp 0xEF91 #define FL_WheelDn 0xEF92 typedef enum { KCTX_NONE = 0, /* INVALID */ KCTX_Browser, KCTX_Render, KCTX_Vertex, KCTX_Thing, KCTX_Sector, KCTX_Line, KCTX_General } key_context_e; /* --- general manipulation --- */ int M_KeyCmp(keycode_t A, keycode_t B); key_context_e M_ParseKeyContext(const char *str); const char * M_KeyContextString(key_context_e context); keycode_t M_ParseKeyString(const char *str); const char * M_KeyToString(keycode_t key); keycode_t M_TranslateKey(int key, int state); key_context_e M_ModeToKeyContext(obj_type_e mode); /* --- preferences dialog stuff --- */ void M_CopyBindings(bool from_defaults = false); void M_SortBindings(char column, bool reverse); void M_ApplyBindings(); int M_NumBindings(); void M_DetectConflictingBinds(); const char * M_StringForFunc(int index); const char * M_StringForBinding(int index, bool changing_key = false); void M_GetBindingInfo(int index, keycode_t *key, key_context_e *context); bool M_IsBindingFuncValid(key_context_e context, const char * func_str); void M_ChangeBindingKey(int index, keycode_t key); const char * M_SetLocalBinding(int index, keycode_t key, key_context_e context, const char *func_str); const char * M_AddLocalBinding(int after, keycode_t key, key_context_e context, const char *func_str); void M_DeleteLocalBinding(int index); void M_LoadBindings(); void M_SaveBindings(); void M_RemoveBinding(keycode_t key, key_context_e context); /* --- command execution stuff --- */ typedef void (* command_func_t)(void); typedef struct { const char *name; command_func_t func; const char *flag_list; const char *keyword_list; // this value is computed when registering key_context_e req_context; } editor_command_t; void M_RegisterCommandList(editor_command_t * list); const editor_command_t * FindEditorCommand(const char *name); const editor_command_t * LookupEditorCommand(int index); // parameter(s) for command function -- must be valid strings #define MAX_EXEC_PARAM 16 extern const char * EXEC_Param[MAX_EXEC_PARAM]; extern const char * EXEC_Flags[MAX_EXEC_PARAM]; // result from command function, 0 is OK extern int EXEC_Errno; bool Exec_HasFlag(const char *flag); bool ExecuteKey(keycode_t key, key_context_e context); bool ExecuteCommand(const char *name, const char *param1 = "", const char *param2 = "", const char *param3 = ""); #endif /* __EUREKA_M_KEYS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/im_img.h0000644000175100017510000000456512647061302015702 0ustar aaptedaapted//------------------------------------------------------------------------ // IMAGES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_IM_IMG_H__ #define __EUREKA_IM_IMG_H__ #include "im_color.h" typedef byte img_pixel_t; // the color number used to represent transparent pixels in an Img_c. const img_pixel_t TRANS_PIXEL = 255; class Img_c { private: img_pixel_t *pixels; int w; // Width int h; // Height public: Img_c(); Img_c(int width, int height, bool _dummy = false); ~Img_c(); bool is_null() const { return (! pixels); } int width() const { return w; } int height() const { return h; } // read access const img_pixel_t *buf() const; // read/write access img_pixel_t *wbuf(); public: // set all pixels to TRANS_PIXEL void clear(); void resize(int new_width, int new_height); Img_c * spectrify() const; Img_c * scale_img(double scale) const; Img_c * color_remap(int src1, int src2, int targ1, int targ2) const; bool has_transparent() const; private: Img_c (const Img_c&); // Too lazy to implement it Img_c& operator= (const Img_c&); // Too lazy to implement it }; void IM_ResetDummyTextures(); Img_c * IM_MissingTex(); Img_c * IM_UnknownTex(); Img_c * IM_UnknownFlat(); Img_c * IM_CreateFromText(int W, int H, const char **text, const rgb_color_t *palette, int pal_size); #endif /* __EUREKA_IM_IMG_H__*/ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_cutpaste.cc0000644000175100017510000005370212647601401016730 0ustar aaptedaapted//------------------------------------------------------------------------ // LEVEL CUT 'N' PASTE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2009-2016 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 "main.h" #include #include "e_basis.h" #include "e_cutpaste.h" #include "e_linedef.h" #include "e_vertex.h" #include "editloop.h" #include "levels.h" #include "objects.h" #include "r_grid.h" #include "w_rawdef.h" #include "x_hover.h" #include "x_loop.h" #define INVALID_SECTOR (-999999) class clipboard_data_c { public: // the mode used when the objects were Copied obj_type_e mode; // NOTE: // // The references here normally refer to other objects in here // (as though this was a little self-contained map). For example, // the LineDef::right field is an index into sides[]. // // The exception is sector references in the SideDefs. These // values refer to the real map when >= 0, and refer to local // sectors when < 0 (negate and add 1). // // That's because we generally want a copy'n'pasted piece of the // map (linedefs or sectors) to "fit in" with nearby sections of // the map. bool uses_real_sectors; std::vector things; std::vector verts; std::vector sectors; std::vector sides; std::vector lines; public: clipboard_data_c(obj_type_e _mode) : mode(_mode), uses_real_sectors(false), things(), verts(), sectors(), sides(), lines() { if (mode == OBJ_LINEDEFS || mode == OBJ_SECTORS) uses_real_sectors = true; } ~clipboard_data_c() { unsigned int i; for (i = 0 ; i < things.size() ; i++) delete things[i]; for (i = 0 ; i < verts.size() ; i++) delete verts[i]; for (i = 0 ; i < sectors.size() ; i++) delete sectors[i]; for (i = 0 ; i < sides.size() ; i++) delete sides[i]; for (i = 0 ; i < lines.size() ; i++) delete lines[i]; } void CentreOfThings(int *cx, int *cy) { *cx = *cy = 0; if (things.empty()) return; double sum_x = 0; double sum_y = 0; for (unsigned int i = 0 ; i < things.size() ; i++) { sum_x += things[i]->x; sum_y += things[i]->y; } sum_x /= (double)things.size(); sum_y /= (double)things.size(); *cx = I_ROUND(sum_x); *cy = I_ROUND(sum_y); #if 0 // find closest thing to this point double best_dist = 9e9; for (unsigned int k = 0 ; k < things.size() ; k++) { double dx = things[k]->x - sum_x; double dy = things[k]->y - sum_y; double dist = dx*dx + dy*dy; if (dist < best_dist) { *cx = things[k]->x; *cy = things[k]->y; best_dist = dist; } } #endif } void CentreOfVertices(int *cx, int *cy) { *cx = *cy = 0; if (verts.empty()) return; double sum_x = 0; double sum_y = 0; for (unsigned int i = 0 ; i < verts.size() ; i++) { sum_x += verts[i]->x; sum_y += verts[i]->y; } sum_x /= (double)verts.size(); sum_y /= (double)verts.size(); *cx = I_ROUND(sum_x); *cy = I_ROUND(sum_y); #if 0 // find closest vertex to this point double best_dist = 9e9; for (unsigned int k = 0 ; k < verts.size() ; k++) { double dx = verts[k]->x - sum_x; double dy = verts[k]->y - sum_y; double dist = dx*dx + dy*dy; if (dist < best_dist) { *cx = verts[k]->x; *cy = verts[k]->y; best_dist = dist; } } #endif } bool HasSectorRefs(int s1, int s2) { if (! uses_real_sectors) return false; for (unsigned int i = 0 ; i < sides.size() ; i++) { if (s1 <= sides[i]->sector && sides[i]->sector <= s2) return true; } return false; } void InsertRealSector(int snum) { if (! uses_real_sectors) return; for (unsigned int i = 0 ; i < sides.size() ; i++) { if (sides[i]->sector >= snum) sides[i]->sector++; } } void DeleteRealSector(int snum) { if (! uses_real_sectors) return; for (unsigned int i = 0 ; i < sides.size() ; i++) { if (sides[i]->sector == snum) sides[i]->sector = INVALID_SECTOR; else if (sides[i]->sector > snum) sides[i]->sector--; } } void RemoveSectorRefs() { if (! uses_real_sectors) return; for (unsigned int i = 0 ; i < sides.size() ; i++) { if (sides[i]->sector >= 0) sides[i]->sector = INVALID_SECTOR; } } }; static clipboard_data_c * clip_board; static bool clip_doing_paste; void Clipboard_Clear() { if (clip_board) { delete clip_board; clip_board = NULL; } } /* this remove sidedefs which refer to local sectors, allowing the clipboard geometry to persist when changing maps. */ void Clipboard_ClearLocals() { if (clip_board) clip_board->RemoveSectorRefs(); } bool Clipboard_HasStuff() { return clip_board ? true : false; } void Clipboard_NotifyBegin() { } void Clipboard_NotifyEnd() { } void Clipboard_NotifyInsert(obj_type_e type, int objnum) { // this function notifies us that a new sector is about to be // inserted in the map (causing other sectors to be moved). if (type != OBJ_SECTORS) return; if (! clip_board) return; // paste operations should only insert new sectors at the end if (objnum < NumSectors) { SYS_ASSERT(! clip_doing_paste); } #if 0 // OLD WAY if (clip_board->HasSectorRefs(objnum, NumSectors-1)) { Clipboard_Clear(); } #else clip_board->InsertRealSector(objnum); #endif } void Clipboard_NotifyDelete(obj_type_e type, int objnum) { // this function notifies us that a sector is about to be deleted // (causing other sectors to be moved). if (type != OBJ_SECTORS) return; if (! clip_board) return; SYS_ASSERT(! clip_doing_paste); clip_board->DeleteRealSector(objnum); } void Clipboard_NotifyChange(obj_type_e type, int objnum, int field) { // field changes never affect the clipboard } //------------------------------------------------------------------------ static void CopyGroupOfObjects(selection_c *list) { // this is used for LineDefs and Sectors, where we need to copy // groups of objects and create internal references between them. bool is_sectors = (list->what_type() == OBJ_SECTORS) ? true : false; selection_iterator_c it; selection_c vert_sel(OBJ_VERTICES); selection_c side_sel(OBJ_SIDEDEFS); selection_c line_sel(OBJ_LINEDEFS); ConvertSelection(list, &line_sel); ConvertSelection(&line_sel, &vert_sel); // determine needed sidedefs for (line_sel.begin(&it) ; !it.at_end() ; ++it) { LineDef *L = LineDefs[*it]; if (L->right >= 0) side_sel.set(L->right); if (L->left >= 0) side_sel.set(L->left); } // these hold the mapping from real index --> clipboard index std::map vert_map; std::map sector_map; std::map side_map; for (vert_sel.begin(&it) ; !it.at_end() ; ++it) { vert_map[*it] = (int)clip_board->verts.size(); Vertex * SD = new Vertex; SD->RawCopy(Vertices[*it]); clip_board->verts.push_back(SD); } if (is_sectors) { for (list->begin(&it) ; !it.at_end() ; ++it) { sector_map[*it] = (int)clip_board->sectors.size(); Sector * S = new Sector; S->RawCopy(Sectors[*it]); clip_board->sectors.push_back(S); } } for (side_sel.begin(&it) ; !it.at_end() ; ++it) { side_map[*it] = (int)clip_board->sides.size(); SideDef * SD = new SideDef; SD->RawCopy(SideDefs[*it]); clip_board->sides.push_back(SD); // adjust sector references, if needed if (is_sectors && list->get(SD->sector)) { SYS_ASSERT(sector_map.find(SD->sector) != sector_map.end()); SD->sector = -1 - sector_map[SD->sector]; } } for (line_sel.begin(&it) ; !it.at_end() ; ++it) { LineDef * L = new LineDef; L->RawCopy(LineDefs[*it]); clip_board->lines.push_back(L); // adjust vertex references SYS_ASSERT(vert_map.find(L->start) != vert_map.end()); SYS_ASSERT(vert_map.find(L->end) != vert_map.end()); L->start = vert_map[L->start]; L->end = vert_map[L->end ]; // adjust sidedef references if (L->right >= 0) { SYS_ASSERT(side_map.find(L->right) != side_map.end()); L->right = side_map[L->right]; } if (L->left >= 0) { SYS_ASSERT(side_map.find(L->left) != side_map.end()); L->left = side_map[L->left]; } } // in sectors mode, copy things too if (is_sectors) { selection_c thing_sel(OBJ_THINGS); ConvertSelection(list, &thing_sel); for (thing_sel.begin(&it) ; !it.at_end() ; ++it) { Thing * T = new Thing; T->RawCopy(Things[*it]); clip_board->things.push_back(T); } } } bool CMD_Copy() { selection_c list; selection_iterator_c it; if (! GetCurrentObjects(&list)) return false; // create storage for the copied objects if (clip_board) delete clip_board; clip_board = new clipboard_data_c(edit.mode); switch (edit.mode) { case OBJ_THINGS: for (list.begin(&it) ; !it.at_end() ; ++it) { Thing * T = new Thing; T->RawCopy(Things[*it]); clip_board->things.push_back(T); } break; case OBJ_VERTICES: for (list.begin(&it) ; !it.at_end() ; ++it) { Vertex * V = new Vertex; V->RawCopy(Vertices[*it]); clip_board->verts.push_back(V); } break; case OBJ_LINEDEFS: case OBJ_SECTORS: CopyGroupOfObjects(&list); break; default: return false; } return true; } //------------------------------------------------------------------------ static void PasteGroupOfObjects(int pos_x, int pos_y) { int cx, cy; clip_board->CentreOfVertices(&cx, &cy); // these hold the mapping from clipboard index --> real index std::map vert_map; std::map sector_map; std::map side_map; unsigned int i; for (i = 0 ; i < clip_board->verts.size() ; i++) { int new_v = BA_New(OBJ_VERTICES); Vertex * V = Vertices[new_v]; vert_map[i] = new_v; V->RawCopy(clip_board->verts[i]); V->x += pos_x - cx; V->y += pos_y - cy; } for (i = 0 ; i < clip_board->sectors.size() ; i++) { int new_s = BA_New(OBJ_SECTORS); Sector * S = Sectors[new_s]; sector_map[i] = new_s; S->RawCopy(clip_board->sectors[i]); } for (i = 0 ; i < clip_board->sides.size() ; i++) { // handle invalidated sectors (as if sidedef had been deleted) if (clip_board->sides[i]->sector == INVALID_SECTOR) { side_map[i] = -1; continue; } int new_sd = BA_New(OBJ_SIDEDEFS); SideDef * SD = SideDefs[new_sd]; side_map[i] = new_sd; SD->RawCopy(clip_board->sides[i]); if (SD->sector < 0) { int local = -1 - SD->sector; SYS_ASSERT(sector_map.find(local) != sector_map.end()); SD->sector = sector_map[local]; } } for (i = 0 ; i < clip_board->lines.size() ; i++) { int new_l = BA_New(OBJ_LINEDEFS); LineDef * L = LineDefs[new_l]; L->RawCopy(clip_board->lines[i]); // adjust vertex references SYS_ASSERT(vert_map.find(L->start) != vert_map.end()); SYS_ASSERT(vert_map.find(L->end) != vert_map.end()); L->start = vert_map[L->start]; L->end = vert_map[L->end ]; // adjust sidedef references if (L->Right()) { SYS_ASSERT(side_map.find(L->right) != side_map.end()); L->right = side_map[L->right]; } if (L->Left()) { SYS_ASSERT(side_map.find(L->left) != side_map.end()); L->left = side_map[L->left]; } // flip linedef if necessary if (L->Left() && ! L->Right()) { FlipLineDef(new_l); } // if the linedef lost a side, fix texturing if (L->OneSided() && L->Right()->MidTex()[0] == '-') LD_FixForLostSide(new_l); } for (i = 0 ; i < clip_board->things.size() ; i++) { int new_t = BA_New(OBJ_THINGS); Thing * T = Things[new_t]; T->RawCopy(clip_board->things[i]); T->x += pos_x - cx; T->y += pos_y - cy; } } static void ReselectGroup() { // this assumes all the new objects are at the end of their // array (currently true, but not a guarantee of BA_New). if (edit.mode == OBJ_THINGS) { if (clip_board->mode == OBJ_THINGS || clip_board->mode == OBJ_SECTORS) { int count = (int)clip_board->things.size(); Selection_Clear(); edit.Selected->frob_range(NumThings - count, NumThings-1, BOP_ADD); } return; } bool was_mappy = (clip_board->mode == OBJ_VERTICES || clip_board->mode == OBJ_LINEDEFS || clip_board->mode == OBJ_SECTORS); bool is_mappy = (edit.mode == OBJ_VERTICES || edit.mode == OBJ_LINEDEFS || edit.mode == OBJ_SECTORS); if (! (was_mappy && is_mappy)) return; selection_c new_sel(clip_board->mode); if (clip_board->mode == OBJ_VERTICES) { int count = (int)clip_board->verts.size(); new_sel.frob_range(NumVertices - count, NumVertices-1, BOP_ADD); } else if (clip_board->mode == OBJ_LINEDEFS) { // Note: this doesn't behave as expected if the editing mode is // SECTORS, because the pasted lines do not completely surround // the sectors (non-pasted lines refer to them too). int count = (int)clip_board->lines.size(); new_sel.frob_range(NumLineDefs - count, NumLineDefs-1, BOP_ADD); } else { SYS_ASSERT(clip_board->mode == OBJ_SECTORS); int count = (int)clip_board->sectors.size(); new_sel.frob_range(NumSectors - count, NumSectors-1, BOP_ADD); } Selection_Clear(); ConvertSelection(&new_sel, edit.Selected); } bool CMD_Paste() { bool reselect = true; // CONFIG TODO unsigned int i; if (! Clipboard_HasStuff()) return false; // figure out where to put stuff int pos_x = edit.map_x; int pos_y = edit.map_y; if (! edit.pointer_in_window) { pos_x = I_ROUND(grid.orig_x); pos_y = I_ROUND(grid.orig_y); } // honor the grid snapping setting pos_x = grid.SnapX(pos_x); pos_y = grid.SnapY(pos_y); BA_Begin(); clip_doing_paste = true; switch (clip_board->mode) { case OBJ_THINGS: { int cx, cy; clip_board->CentreOfThings(&cx, &cy); for (unsigned int i = 0 ; i < clip_board->things.size() ; i++) { int new_t = BA_New(OBJ_THINGS); Thing * T = Things[new_t]; T->RawCopy(clip_board->things[i]); T->x += pos_x - cx; T->y += pos_y - cy; recent_things.insert_number(T->type); } break; } case OBJ_VERTICES: { int cx, cy; clip_board->CentreOfVertices(&cx, &cy); for (i = 0 ; i < clip_board->verts.size() ; i++) { int new_v = BA_New(OBJ_VERTICES); Vertex * V = Vertices[new_v]; V->RawCopy(clip_board->verts[i]); V->x += pos_x - cx; V->y += pos_y - cy; } break; } case OBJ_LINEDEFS: case OBJ_SECTORS: { PasteGroupOfObjects(pos_x, pos_y); break; } default: break; } clip_doing_paste = false; BA_End(); edit.error_mode = false; if (reselect) ReselectGroup(); return true; } //------------------------------------------------------------------------ void UnusedVertices(selection_c *lines, selection_c *result) { SYS_ASSERT(lines->what_type() == OBJ_LINEDEFS); ConvertSelection(lines, result); for (int n = 0 ; n < NumLineDefs ; n++) { // we are interested in the lines we are NOT deleting if (lines->get(n)) continue; const LineDef *L = LineDefs[n]; result->clear(L->start); result->clear(L->end); } } void UnusedSideDefs(selection_c *lines, selection_c *result) { SYS_ASSERT(lines->what_type() == OBJ_LINEDEFS); ConvertSelection(lines, result); for (int n = 0 ; n < NumLineDefs ; n++) { // we are interested in the lines we are NOT deleting if (lines->get(n)) continue; const LineDef *L = LineDefs[n]; if (L->Right()) result->clear(L->right); if (L->Left()) result->clear(L->left); } } void UnusedLineDefs(selection_c *sectors, selection_c *result) { SYS_ASSERT(sectors->what_type() == OBJ_SECTORS); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; // check if touches a to-be-deleted sector // -1 : no side // 0 : deleted side // +1 : kept side int right_m = (L->right < 0) ? -1 : sectors->get(L->Right()->sector) ? 0 : 1; int left_m = (L->left < 0) ? -1 : sectors->get(L->Left() ->sector) ? 0 : 1; if (MAX(right_m, left_m) == 0) { result->set(n); } } } void UnusedSectors(selection_c *verts, selection_c *lines, selection_c *result) { SYS_ASSERT(verts->what_type() == OBJ_VERTICES); SYS_ASSERT(lines->what_type() == OBJ_LINEDEFS); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (lines->get(n) || verts->get(L->start) || verts->get(L->end)) { if (L->WhatSector(SIDE_LEFT ) >= 0) result->set(L->WhatSector(SIDE_LEFT )); if (L->WhatSector(SIDE_RIGHT) >= 0) result->set(L->WhatSector(SIDE_RIGHT)); } } for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (lines->get(n) || verts->get(L->start) || verts->get(L->end)) continue; for (int pass = 0 ; pass < 2 ; pass++) { int what_side = pass ? SIDE_LEFT : SIDE_RIGHT; int sec_num = L->WhatSector(what_side); if (sec_num < 0) continue; // if already clear, skip it (prevent expensive tests below) if (! result->get(sec_num)) continue; // check if the linedef opposite this is being deleted, which // means this linedef will get mucked up. When all remaining // lines are like this, we should consider the sector "unused" // and let it be removed. int opp_side; int opp_ld = OppositeLineDef(n, what_side, &opp_side); if (opp_ld >= 0) { const LineDef *L2 = LineDefs[opp_ld]; if ((L2->WhatSector(opp_side) == sec_num) && (L2->WhatSector(SIDE_LEFT) != L2->WhatSector(SIDE_RIGHT)) && (lines->get(opp_ld) || verts->get(L2->start) || verts->get(L2->end))) continue; } result->clear(sec_num); } } } static void FixupLineDefs(selection_c *lines, selection_c *sectors) { selection_iterator_c it; for (lines->begin(&it) ; !it.at_end() ; ++it) { const LineDef *L = LineDefs[*it]; // the logic is ugly here mainly to handle flipping (in particular, // not to flip the line when _both_ sides are unlinked). bool do_right = L->Right() ? sectors->get(L->Right()->sector) : false; bool do_left = L->Left() ? sectors->get(L->Left() ->sector) : false; // line shouldn't be in list unless it touches the sector SYS_ASSERT(do_right || do_left); if (do_right && do_left) { LD_RemoveSideDef(*it, SIDE_RIGHT); LD_RemoveSideDef(*it, SIDE_LEFT); } else if (do_right) { LD_RemoveSideDef(*it, SIDE_RIGHT); FlipLineDef(*it); } else // do_left { LD_RemoveSideDef(*it, SIDE_LEFT); } } } static bool DeleteVertex_MergeLineDefs(int v_num) { // returns true if OK, false if would create an overlapping linedef // [ meaning the vertex should be deleted normally ] // find the linedefs int ld1 = -1; int ld2 = -1; for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->start == v_num || L->end == v_num) { SYS_ASSERT(ld2 < 0); if (ld1 < 0) ld1 = n; else ld2 = n; } } SYS_ASSERT(ld1 >= 0); SYS_ASSERT(ld2 >= 0); LineDef *L1 = LineDefs[ld1]; LineDef *L2 = LineDefs[ld2]; // we merge L2 into L1, unless L1 is significantly shorter if (L1->CalcLength() < L2->CalcLength() * 0.7) { std::swap(ld1, ld2); std::swap(L1, L2); } // determine the remaining vertices int v1 = (L1->start == v_num) ? L1->end : L1->start; int v2 = (L2->start == v_num) ? L2->end : L2->start; // ensure we don't create two directly overlapping linedefs if (LineDefAlreadyExists(v1, v2)) return false; BA_Begin(); if (L1->start == v_num) BA_ChangeLD(ld1, LineDef::F_START, v2); else BA_ChangeLD(ld1, LineDef::F_END, v2); // NOT-DO: update X offsets on existing linedef BA_Delete(OBJ_LINEDEFS, ld2); BA_Delete(OBJ_VERTICES, v_num); BA_End(); return true; } void CMD_Delete(void) { selection_c list; if (! GetCurrentObjects(&list)) { Beep("Nothing to delete"); return; } bool keep_things = Exec_HasFlag("/keep_things"); bool keep_unused = Exec_HasFlag("/keep_unused"); selection_c vert_sel(OBJ_VERTICES); selection_c side_sel(OBJ_SIDEDEFS); selection_c line_sel(OBJ_LINEDEFS); selection_c sec_sel(OBJ_SECTORS); switch (edit.mode) { case OBJ_VERTICES: vert_sel.merge(list); break; case OBJ_LINEDEFS: line_sel.merge(list); break; case OBJ_SECTORS: sec_sel.merge(list); break; default: /* OBJ_THINGS */ BA_Begin(); DeleteObjects(&list); BA_End(); goto success; } // special case for a single vertex connected to two linedef, // we delete the vertex but merge the two linedefs. if (edit.mode == OBJ_VERTICES && vert_sel.count_obj() == 1) { int v_num = vert_sel.find_first(); SYS_ASSERT(v_num >= 0); if (VertexHowManyLineDefs(v_num) == 2) { if (DeleteVertex_MergeLineDefs(v_num)) goto success; // delete vertex normally } } if (!keep_unused && edit.mode == OBJ_SECTORS) { UnusedLineDefs(&sec_sel, &line_sel); if (line_sel.notempty()) { UnusedVertices(&line_sel, &vert_sel); UnusedSideDefs(&line_sel, &side_sel); } } if (!keep_unused && edit.mode == OBJ_LINEDEFS) { UnusedVertices(&line_sel, &vert_sel); } if (edit.mode == OBJ_VERTICES || edit.mode == OBJ_LINEDEFS) { UnusedSideDefs(&line_sel, &side_sel); UnusedSectors(&vert_sel, &line_sel, &sec_sel); } BA_Begin(); // delete things from each deleted sector if (!keep_things && sec_sel.notempty()) { selection_c thing_sel(OBJ_THINGS); ConvertSelection(&sec_sel, &thing_sel); DeleteObjects(&thing_sel); } // perform linedef fixups here (when sectors get removed) if (sec_sel.notempty()) { selection_c fixups(OBJ_LINEDEFS); ConvertSelection(&sec_sel, &fixups); // skip lines which will get deleted fixups.unmerge(line_sel); FixupLineDefs(&fixups, &sec_sel); } // actually delete stuff, in the correct order DeleteObjects(&line_sel); DeleteObjects(&side_sel); DeleteObjects(&vert_sel); DeleteObjects( &sec_sel); BA_End(); success: Editor_ClearAction(); Selection_Clear(); edit.highlight.clear(); edit.split_line.clear(); UpdateHighlight(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/w_sprite.cc0000644000175100017510000001243712651122067016431 0ustar aaptedaapted//------------------------------------------------------------------------ // SPRITE LOADING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2015 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include #include #include "m_game.h" /* yg_picture_format */ #include "levels.h" #include "w_loadpic.h" #include "w_rawdef.h" #include "w_sprite.h" // maps type number to an image typedef std::map sprite_map_t; static sprite_map_t sprites; static Img_c * CreateDogSprite(); static void DeleteSprite(const sprite_map_t::value_type& P) { delete P.second; } void W_ClearSprites() { std::for_each(sprites.begin(), sprites.end(), DeleteSprite); sprites.clear(); } // find sprite by prefix Lump_c * Sprite_loc_by_root (const char *name) { char buffer[16]; strcpy(buffer, name); if (strlen(buffer) == 4) strcat(buffer, "A"); if (strlen(buffer) == 5) strcat(buffer, "0"); Lump_c *lump = W_FindSpriteLump(buffer); if (! lump) { buffer[5] = '1'; lump = W_FindSpriteLump(buffer); } if (! lump) { strcat(buffer, "D1"); lump = W_FindSpriteLump(buffer); } return lump; } Img_c * W_GetSprite(int type) { sprite_map_t::iterator P = sprites.find(type); if (P != sprites.end ()) return P->second; // sprite not in the list yet. Add it. const thingtype_t *info = M_GetThingType(type); Img_c *result = NULL; if (y_stricmp(info->sprite, "NULL") != 0) { Lump_c *lump = Sprite_loc_by_root(info->sprite); if (! lump) { LogPrintf("Sprite not found: '%s'\n", info->sprite); // for the MBF dog, create our own sprite for it, since // it is defined in the Boom definition file and the // missing sprite looks ugly in the thing browser. if (y_stricmp(info->sprite, "DOGS") == 0) result = CreateDogSprite(); } else { result = new Img_c (); if (! LoadPicture(*result, lump, info->sprite, 0, 0)) { delete result; result = NULL; } } } // player color remapping // [ FIXME : put colors into game definition file ] // [ TODO : support types 4001..4004 ] if (result && type >= 2 && type <= 4) { Img_c *old_img = result; switch (type) { case 2: result = old_img->color_remap(0x70, 0x7f, 0x60, 0x6f); break; case 3: result = old_img->color_remap(0x70, 0x7f, 0x40, 0x4f); break; case 4: default: result = old_img->color_remap(0x70, 0x7f, 0x20, 0x2f); break; } delete old_img; } // note that a NULL image is OK. Our renderer will just ignore the // missing sprite. sprites[type] = result; return result; } //------------------------------------------------------------------------ // // This dog sprite was sourced from OpenGameArt.org // Authors are 'Benalene' and 'qudobup' (users on the OGA site). // License is CC-BY 3.0 (Creative Commons Attribution license). // static const rgb_color_t dog_palette[] = { 0x302020ff, 0x944921ff, 0x000000ff, 0x844119ff, 0x311800ff, 0x4A2400ff, 0x633119ff, }; static const char *dog_image_text[] = { " aaaa ", " abbbba ", " abbbbbba ", " aaaabcbbbbbda ", "aeedbbbfbbbbda ", "aegdddbbdbbdbbaaaaaaaaaaaaaaaaa a ", "affggddbgddgbccceeeeeeeeeeeeeeeaa aba", " affgggdfggfccceeeeeeeeeeeeeefffgaaa aaba ", " afffaafgecccefffffffffffffffggggddaaabbba ", " aaa aeeccggggffffffffffffggddddbbbbbaa ", " accbdddggfffffffffffggdbbbbbbba ", " aabbdbddgfffffffffggddbaaaaaa ", " abbbbdddfffffffggdbbba ", " abbbbbbdddddddddddbbba ", " aeebbbbbbbbaaaabbbbbbbba ", " aeebbbbbaaa aeebbbbbba ", " afebbbbaa affeebbbba ", " agfbbbaa aggffabbbba ", " agfebba aggggaabbba ", " aadgfabba addda abba ", " abbddaabbbaa adddaabba ", " abbbba abbbba adbbaabba ", " aaaa abbba abbba abba ", " aaa abbba abba ", " abbba abbba ", " aaa aaa " }; static Img_c * CreateDogSprite() { return IM_CreateFromText(44, 26, dog_image_text, dog_palette, 7); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_path.h0000644000175100017510000000277512647061302015702 0ustar aaptedaapted//------------------------------------------------------------------------ // LINEDEF PATHS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_PATH_H__ #define __EUREKA_E_PATH_H__ /* find/next/prev stuff */ void GoToObject(const Objid& objid); void GoToSelection(); void GoToErrors(); /* commands */ void LIN_SelectPath(void); void SEC_SelectGroup(void); void CMD_JumpToObject(void); void CMD_NextObject(); void CMD_PrevObject(); void CMD_PruneUnused(void); #endif /* __EUREKA_E_PATH_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_cutpaste.h0000644000175100017510000000274112647061302016567 0ustar aaptedaapted//------------------------------------------------------------------------ // LEVEL CUT 'N' PASTE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2009-2012 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 __EUREKA_E_CUTPASTE_H__ #define __EUREKA_E_CUTPASTE_H__ void Clipboard_Clear(); void Clipboard_ClearLocals(); bool Clipboard_HasStuff(); void Clipboard_NotifyBegin(); void Clipboard_NotifyInsert(obj_type_e type, int objnum); void Clipboard_NotifyDelete(obj_type_e type, int objnum); void Clipboard_NotifyChange(obj_type_e type, int objnum, int field); void Clipboard_NotifyEnd(); void UnusedVertices(selection_c *lines, selection_c *result); void UnusedSideDefs(selection_c *lines, selection_c *result); void CMD_Delete(void); bool CMD_Copy(); bool CMD_Paste(); #endif /* __EUREKA_E_CUTPASTE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_infobar.h0000644000175100017510000000356612647613341016564 0ustar aaptedaapted//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2012 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 __EUREKA_UI_INFOBAR_H__ #define __EUREKA_UI_INFOBAR_H__ class UI_InfoBar : public Fl_Group { public: UI_InfoBar(int X, int Y, int W, int H, const char *label = NULL); virtual ~UI_InfoBar(); public: Fl_Choice *mode; Fl_Choice *scale; Fl_Choice *grid_size; Fl_Toggle_Button *grid_snap; Fl_Output *mouse_x; Fl_Output *mouse_y; Fl_Box *status; public: int handle(int event); // FLTK virtual method for handling input events. public: void SetStatus(const char *str); void NewEditMode(obj_type_e new_mode); void SetMouse(double mx, double my); void SetScale(int i); // called from Grid_State_c ONLY! void SetGrid(int i); // called from Grid_State_c void UpdateSnap(); private: void UpdateModeColor(); void UpdateSnapText(); static void mode_callback(Fl_Widget *, void *); static void scale_callback(Fl_Widget *, void *); static void grid_callback(Fl_Widget *, void *); static void snap_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_INFOBAR_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/lib_util.h0000644000175100017510000001006512647061302016234 0ustar aaptedaapted//------------------------------------------------------------------------ // UTILITIES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_LIB_UTIL_H__ #define __EUREKA_LIB_UTIL_H__ int y_stricmp (const char *s1, const char *s2); int y_strnicmp (const char *s1, const char *s2, size_t len); void y_strupr (char *str); void y_strlowr (char *str); char *StringNew(int length); char *StringDup(const char *orig, int limit = -1); char *StringUpper(const char *name); char *StringPrintf(const char *str, ...); // GCCATTR((format (printf, 1, 2))); void StringFree(const char *str); void StringRemoveCRLF(char *str); char *StringTidy(const char *str, const char *bad_chars = ""); void check_types (); void TimeDelay(unsigned int millies); unsigned int TimeGetMillies(); unsigned ComputeAngle (int, int); unsigned ComputeDist (int, int); double PerpDist(double x, double y, /* coord to test */ double x1, double y1, double x2, double y2 /* line */); double AlongDist(double x, double y, /* coord to test */ double x1, double y1, double x2, double y2 /* line */); const char * Int_TmpStr(int value); /* * dectoi * If is a decimal digit ("[0-9]"), return its value. * Else, return a negative number. */ inline int dectoi (char c) { if (isdigit ((unsigned char) c)) return c - '0'; else return -1; } /* * hextoi * If is a hexadecimal digit ("[0-9A-Fa-f]"), return its value. * Else, return a negative number. */ inline int hextoi (char c) { if (isdigit ((unsigned char) c)) return c - '0'; else if (c >= 'a' && c <= 'f') return c - 'a' + 10; else if (c >= 'A' && c <= 'F') return c - 'A' + 10; else return -1; } /* * y_isident - return true iff is one of a-z, A-Z, 0-9 or "_". * * Intentionally not using isalpha() and co. because I * don't want the results to depend on the locale. */ inline bool y_isident (char c) { switch (c) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '_': return true; default: return false; } } /* * round_up * Round a value up to the next multiple of quantum. * * Both the value and the quantum are supposed to be positive. */ inline void round_up (int& value, int quantum) { value = ((value + quantum - 1) / quantum) * quantum; } /* * y_isprint * Is a printable character in ISO-8859-1 ? */ inline bool y_isprint (char c) { return (c & 0x60) && (c != 0x7f); } #endif /* __EUREKA_YUTIL_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/objects.cc0000644000175100017510000010221512651123311016211 0ustar aaptedaapted//------------------------------------------------------------------------ // OBJECT OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include "e_linedef.h" #include "e_sector.h" #include "e_things.h" #include "e_vertex.h" #include "editloop.h" #include "levels.h" #include "objects.h" #include "r_grid.h" #include "w_rawdef.h" #include "x_hover.h" #include "x_loop.h" #include "ui_window.h" // config items bool new_islands_are_void = false; int new_sector_size = 128; bool easier_drawing_mode = true; /* delete a group of objects. The selection is no longer valid after this! */ void DeleteObjects(selection_c *list) { // we need to process the object numbers from highest to lowest, // because each deletion invalidates all higher-numbered refs // in the selection. Our selection iterator cannot give us // what we need, hence put them into a vector for sorting. if (list->empty()) return; std::vector objnums; selection_iterator_c it; for (list->begin(&it) ; !it.at_end() ; ++it) objnums.push_back(*it); std::sort(objnums.begin(), objnums.end()); for (int i = (int)objnums.size()-1 ; i >= 0 ; i--) { BA_Delete(list->what_type(), objnums[i]); } } static void CreateSquare(int model) { int new_sec = BA_New(OBJ_SECTORS); if (model >= 0) Sectors[new_sec]->RawCopy(Sectors[model]); else Sectors[new_sec]->SetDefaults(); int x1 = grid.QuantSnapX(edit.map_x, false); int y1 = grid.QuantSnapX(edit.map_y, false); int x2 = x1 + new_sector_size; int y2 = y1 + new_sector_size; for (int i = 0 ; i < 4 ; i++) { int new_v = BA_New(OBJ_VERTICES); Vertices[new_v]->x = (i >= 2) ? x2 : x1; Vertices[new_v]->y = (i==1 || i==2) ? y2 : y1; int new_sd = BA_New(OBJ_SIDEDEFS); SideDefs[new_sd]->SetDefaults(false); SideDefs[new_sd]->sector = new_sec; int new_ld = BA_New(OBJ_LINEDEFS); LineDef * L = LineDefs[new_ld]; L->start = new_v; L->end = (i == 3) ? (new_v - 3) : new_v + 1; L->flags = MLF_Blocking; L->right = new_sd; } // select it Selection_Clear(); edit.Selected->set(new_sec); } static void Insert_Thing() { int model = -1; if (edit.Selected->notempty()) model = edit.Selected->find_first(); BA_Begin(); int new_t = BA_New(OBJ_THINGS); Thing *T = Things[new_t]; T->type = default_thing; if (model >= 0) T->RawCopy(Things[model]); T->x = grid.SnapX(edit.map_x); T->y = grid.SnapY(edit.map_y); recent_things.insert_number(T->type); BA_End(); // select it Selection_Clear(); edit.Selected->set(new_t); } static void ClosedLoop_Simple(int new_ld, int v2, selection_c& flip) { lineloop_c right_loop; lineloop_c left_loop; bool right_ok = TraceLineLoop(new_ld, SIDE_RIGHT, right_loop); bool left_ok = TraceLineLoop(new_ld, SIDE_LEFT, left_loop); // require all lines to be "new" (no sidedefs) right_ok = right_ok && right_loop.AllNew(); left_ok = left_ok && left_loop.AllNew(); // check if one of the loops is OK and faces outward. // in that case, we just make the island part of the surrounding // sector (i.e. we DON'T put a new sector in the inside area). // [[ Except when new island contains an island ! ]] bool did_outer = false; for (int pass = 0 ; pass < 2 ; pass++) { lineloop_c& loop = (pass == 0) ? right_loop : left_loop; bool ok = (pass == 0) ? right_ok : left_ok; if (ok && loop.faces_outward) { int sec_num = loop.FacesSector(); if (sec_num >= 0) { AssignSectorToLoop(loop, sec_num, flip); did_outer = true; } } } // otherwise try to create new sector in the inside area // TODO: CONFIG ITEM 'auto_insert_sector' for (int pass = 0 ; pass < 2 ; pass++) { lineloop_c& loop = (pass == 0) ? right_loop : left_loop; bool ok = (pass == 0) ? right_ok : left_ok; if (ok && ! loop.faces_outward) { loop.FindIslands(); // if the loop is inside a sector, only _have_ to create // the inner sector if we surrounded something. if (new_islands_are_void && did_outer && loop.islands.empty()) return; int new_sec = BA_New(OBJ_SECTORS); int model = loop.NeighboringSector(); if (model >= 0) Sectors[new_sec]->RawCopy(Sectors[model]); else Sectors[new_sec]->SetDefaults(); AssignSectorToLoop(loop, new_sec, flip); } } } static bool TwoNeighboringLineDefs(int new_ld, int v1, int v2, int *ld1, int *side1, int *ld2, int *side2) { // find the two linedefs that are neighbors to the new line at // the second vertex (v2). The first one (ld1) is on new_ld's // right side, and the second one (ld2) is on new_ld's left side. *ld1 = -1; *ld2 = -1; double best_angle1 = 9999; double best_angle2 = -9999; for (int n = 0 ; n < NumLineDefs ; n++) { if (n == new_ld) continue; const LineDef *L = LineDefs[n]; int other_v; if (L->start == v2) other_v = L->end; else if (L->end == v2) other_v = L->start; else continue; double angle = AngleBetweenLines(v1, v2, other_v); // overlapping lines if (fabs(angle) < 0.0001) return false; if (angle < best_angle1) { *ld1 = n; *side1 = (other_v == L->start) ? SIDE_LEFT : SIDE_RIGHT; best_angle1 = angle; } if (angle > best_angle2) { *ld2 = n; *side2 = (other_v == L->start) ? SIDE_RIGHT : SIDE_LEFT; best_angle2 = angle; } } #if 0 DebugPrintf("best right: line:#%d side:%d angle:%1.2f\n", *ld1, *side1, best_angle1); DebugPrintf("best left: line:#%d side:%d angle:%1.2f\n", *ld2, *side2, best_angle2); #endif if (*ld1 < 0 || *ld2 < 0 || *ld1 == *ld2) return false; return true; } static void ClosedLoop_Complex(int new_ld, int v1, int v2, selection_c& flip) { DebugPrintf("COMPLEX LOOP : LINE #%d : %d --> %d\n", new_ld, v1, v2); // find the two linedefs which are nearest to the new line int left_ld = 0, right_ld = 0; int left_side = 0, right_side = 0; if (! TwoNeighboringLineDefs(new_ld, v1, v2, &right_ld, &right_side, &left_ld, &left_side)) { // Beep(); return; } int right_front = LineDefs[right_ld]->WhatSector(right_side); int left_front = LineDefs[ left_ld]->WhatSector( left_side); int right_back = LineDefs[right_ld]->WhatSector(- right_side); int left_back = LineDefs[ left_ld]->WhatSector(- left_side); bool right_new = (right_front < 0) && (right_back < 0); bool left_new = ( left_front < 0) && ( left_back < 0); DebugPrintf("RIGHT LINE #%d : front=%d back=%d\n", right_ld, right_front, right_back); DebugPrintf(" LEFT LINE #%d : front=%d back=%d\n", left_ld, left_front, left_back); if (right_new || left_new) { // OK } else if (right_front != left_front) { // geometry is broken : disable auto-split or auto-sectoring. // Beep(); return; } // do nothing if touching a "self-referencing linedef" // TODO: REVIEW THIS if ((right_front >= 0 && right_back == right_front) || ( left_front >= 0 && left_back == left_front)) { // Beep(); return; } // AT HERE : either splitting a sector or extending one lineloop_c right_loop; lineloop_c left_loop; // trace the loops on either side of the new line bool right_ok = TraceLineLoop(new_ld, SIDE_RIGHT, right_loop); bool left_ok = TraceLineLoop(new_ld, SIDE_LEFT, left_loop); DebugPrintf("right_ok : %s\n", right_ok ? "yes" : "NO!"); DebugPrintf(" left_ok : %s\n", left_ok ? "yes" : "NO!"); if (right_ok) DebugPrintf("right faces outward : %s\n", right_loop.faces_outward ? "YES!" : "no"); if ( left_ok) DebugPrintf(" left faces outward : %s\n", left_loop.faces_outward ? "YES!" : "no"); if (right_front >= 0 && right_front == left_front && (right_ok && !right_loop.faces_outward) && ( left_ok && ! left_loop.faces_outward)) { // the SPLITTING case.... DebugPrintf("SPLITTING sector #%d\n", right_front); // TODO: CONFIG ITEM 'auto_split' // ensure original sector is OK lineloop_c orig_loop; if (! TraceLineLoop(right_ld, right_side, orig_loop, true /* ignore_new */)) { DebugPrintf("Traced original : failed\n"); return; } if (! orig_loop.SameSector()) { DebugPrintf("Original not all same\n"); return; } // OK WE ARE SPLITTING IT : pick which side will stay the same double right_total = right_loop.TotalLength(); double left_total = left_loop.TotalLength(); DebugPrintf("Left total: %1.1f Right total: %1.1f\n", left_total, right_total); lineloop_c& mod_loop = (left_total < right_total) ? left_loop : right_loop; lineloop_c& keep_loop = (left_total < right_total) ? right_loop : left_loop; // we'll need the islands too mod_loop.FindIslands(); int new_sec = BA_New(OBJ_SECTORS); Sectors[new_sec]->RawCopy(Sectors[right_front]); // ensure the new linedef usually ends at v2 (the final vertex) if (left_total < right_total) { AssignSectorToLoop(keep_loop, right_front, flip); AssignSectorToLoop( mod_loop, new_sec, flip); } else { AssignSectorToLoop( mod_loop, new_sec, flip); AssignSectorToLoop(keep_loop, right_front, flip); } return; } // the SPLIT-VOID case.... if (right_ok && right_front < 0 && !right_loop.faces_outward && left_ok && left_front < 0 && ! left_loop.faces_outward) { DebugPrintf("SPLITTING VOID...\n"); // pick which side gets the new sector double right_total = right_loop.TotalLength(); double left_total = left_loop.TotalLength(); DebugPrintf("Left total: %1.1f Right total: %1.1f\n", left_total, right_total); lineloop_c& loop = (left_total < right_total) ? left_loop : right_loop; loop.FindIslands(); int model = (left_total < right_total) ? left_back : right_back; int new_sec = BA_New(OBJ_SECTORS); if (model < 0) Sectors[new_sec]->SetDefaults(); else Sectors[new_sec]->RawCopy(Sectors[model]); AssignSectorToLoop(loop, new_sec, flip); return; } // the EXTENDING case.... DebugPrintf("EXTENDING....\n"); // TODO: CONFIG ITEM 'auto_extend' for (int pass = 0 ; pass < 2 ; pass++) { lineloop_c& loop = (pass == 0) ? right_loop : left_loop; int front = (pass == 0) ? right_front : left_front; bool ok = (pass == 0) ? right_ok : left_ok; // bad geometry? if (! ok) continue; if (! loop.faces_outward) { loop.FindIslands(); DebugPrintf("ISLANDS = %u\n", loop.islands.size()); int model = loop.NeighboringSector(); int new_sec = BA_New(OBJ_SECTORS); if (model < 0) Sectors[new_sec]->SetDefaults(); else Sectors[new_sec]->RawCopy(Sectors[model]); AssignSectorToLoop(loop, new_sec, flip); } else { // when front >= 0, we can be certain we are extending an // island within an existing sector. When < 0, we check // whether the loop can see an outer sector. int sec_num = (front >= 0) ? front : loop.FacesSector(); if (sec_num >= 0) { AssignSectorToLoop(loop, sec_num, flip); } } } } void Insert_LineDef(int v1, int v2, bool no_fill = false) { int new_ld = BA_New(OBJ_LINEDEFS); LineDef * L = LineDefs[new_ld]; L->start = v1; L->end = v2; L->flags = MLF_Blocking; if (no_fill) return; selection_c flip(OBJ_LINEDEFS); switch (VertexHowManyLineDefs(v2)) { case 0: // this should not happen! case 1: // joined onto an isolated vertex : nothing to do return; case 2: ClosedLoop_Simple(new_ld, v2, flip); break; default: // 3 or more ClosedLoop_Complex(new_ld, v1, v2, flip); break; } FlipLineDefGroup(flip); } void Insert_LineDef_autosplit(int v1, int v2, bool no_fill = false) { if (LineDefAlreadyExists(v1, v2)) return; fprintf(stderr, "Insert_LineDef_autosplit %d..%d\n", v1, v2); // Find a linedef which this new line would cross, and if it exists // add a vertex there and create TWO lines. Also handle a vertex // that this line crosses (sits on) similarly. cross_state_t cross; if (! FindClosestCrossPoint(v1, v2, &cross)) { Insert_LineDef(v1, v2, no_fill); return; } if (cross.line >= 0) { cross.vert = BA_New(OBJ_VERTICES); Vertex *V = Vertices[cross.vert]; V->x = cross.x; V->y = cross.y; SplitLineDefAtVertex(cross.line, cross.vert); } // recursively handle both sides Insert_LineDef_autosplit(v1, cross.vert, no_fill); Insert_LineDef_autosplit(cross.vert, v2, no_fill); } void Insert_Vertex(bool force_continue, bool no_fill, bool is_button) { bool do_continue = true; int from_vert = -1; int to_vert = -1; // the "nearby" vertex is usually the highlighted one. int near_vert = -1; if (edit.highlight.valid()) near_vert = edit.highlight.num; int new_x = grid.SnapX(edit.map_x); int new_y = grid.SnapY(edit.map_y); // a linedef which we are splitting (usually none) int split_ld = edit.split_line.valid() ? edit.split_line.num : -1; if (easier_drawing_mode) { if (edit.action == ACT_DRAW_LINE) from_vert = edit.drawing_from; } else { if (edit.Selected->count_obj() > 2) { Beep("Too many vertices to add a linedef"); return; } from_vert = edit.Selected->find_first(); to_vert = edit.Selected->find_second(); if (from_vert >= 0 && to_vert >= 0 && split_ld >= 0) { Beep("Too many vertices to split a linedef"); return; } } // if no highlight, look for a vertex at snapped coord if (! (edit.action == ACT_DRAW_LINE) && near_vert < 0 && grid.snap) { near_vert = Vertex_FindExact(new_x, new_y); } // // handle a highlighted vertex // [ an explicit destination overrides any highlight ] // [ a splittable line also overrides ] // if (near_vert >= 0 && to_vert < 0 && split_ld < 0) { // the simple "select it" case, as we have no explicit source if (from_vert < 0) { // a plain INSERT will attempt to fix a dangling vertex if (!is_button && edit.action == ACT_NOTHING) { if (Vertex_TryFixDangler(near_vert)) { // a vertex was deleted, selection/highlight is now invalid return; } } edit.Selected->set(near_vert); if (easier_drawing_mode) { Editor_SetAction(ACT_DRAW_LINE); edit.drawing_from = near_vert; } return; } // the simple "unselect it" case if (near_vert == from_vert) { edit.Selected->clear(from_vert); Editor_ClearAction(); return; } // we have no explicit destination, so use the highlight // [ in drawing mode we never have an explicit destination ] to_vert = near_vert; // 'near_vert' is no longer used... } if (from_vert >= 0 && to_vert >= 0) { /* ------ adding a linedef, no new vertex ------ */ if (LineDefAlreadyExists(from_vert, to_vert)) { edit.Selected->set(from_vert); edit.Selected->set(to_vert); Editor_ClearAction(); return; } if (!force_continue && VertexHowManyLineDefs(to_vert) > 0) do_continue = false; BA_Begin(); Insert_LineDef_autosplit(from_vert, to_vert, no_fill); BA_End(); } else { /* ------ creating a new vertex ------ */ // do not create a new line when we are splitting a line and // the source vertex is an endpoint of that line (otherwise // we would get two overlapping lines). if (from_vert >= 0 && split_ld >= 0 && LineDefs[split_ld]->TouchesVertex(from_vert)) { from_vert = -1; } // the following should not happen, but just in case... if (from_vert >= 0 && split_ld < 0 && Vertices[from_vert]->x == new_x && Vertices[from_vert]->y == new_y) { Beep("Bug detected (creation of zero-length line)"); return; } BA_Begin(); to_vert = BA_New(OBJ_VERTICES); Vertex *V = Vertices[to_vert]; V->x = new_x; V->y = new_y; // split an existing linedef? if (split_ld >= 0) { V->x = edit.split_x; V->y = edit.split_y; SplitLineDefAtVertex(split_ld, to_vert); if (!force_continue && from_vert >= 0) do_continue = false; } // add a new linedef? if (from_vert >= 0) { Insert_LineDef_autosplit(from_vert, to_vert, no_fill); } BA_End(); } Selection_Clear(); Editor_ClearAction(); // continue drawing / select new vertex if (do_continue) { edit.Selected->set(to_vert); if (easier_drawing_mode) { Editor_SetAction(ACT_DRAW_LINE); edit.drawing_from = to_vert; } } RedrawMap(); } static void Correct_Sector(int sec_num) { BA_Begin(); AssignSectorToSpace(edit.map_x, edit.map_y, sec_num); BA_End(); } static void Insert_Sector(bool force_new) { int sel_count = edit.Selected->count_obj(); if (sel_count > 1) { Beep("Too many sectors to copy from"); return; } // if outside of the map, create a square if (PointOutsideOfMap(edit.map_x, edit.map_y)) { BA_Begin(); int model = -1; if (sel_count > 0) model = edit.Selected->find_first(); CreateSquare(model); BA_End(); return; } // if a sector is highlighted, merely correct it (unless CTRL is pressed) if (edit.highlight.valid() && ! force_new) { // must not be any selection if (sel_count > 0) { Beep("Correct sector not supported on selection"); return; } Correct_Sector(edit.highlight.num); return; } // --- adding a NEW sector to the area --- // determine a model sector to copy properties from int model; if (sel_count > 0) model = edit.Selected->find_first(); else if (edit.highlight.valid()) model = edit.highlight.num; else model = -1; // look for a neighbor to copy BA_Begin(); int new_sec = BA_New(OBJ_SECTORS); if (model >= 0) { Sectors[new_sec]->RawCopy(Sectors[model]); } AssignSectorToSpace(edit.map_x, edit.map_y, new_sec, model < 0); BA_End(); Selection_Clear(); edit.Selected->set(new_sec); } void Insert_Vertex_split(int split_ld, int new_x, int new_y) { BA_Begin(); int new_vert = BA_New(OBJ_VERTICES); Vertex *V = Vertices[new_vert]; V->x = new_x; V->y = new_y; SplitLineDefAtVertex(split_ld, new_vert); BA_End(); Selection_Clear(); Editor_ClearAction(); edit.clicked = Objid(OBJ_VERTICES, new_vert); RedrawMap(); } void CMD_Insert(void) { bool force_new; bool force_cont; bool no_fill; switch (edit.mode) { case OBJ_THINGS: Insert_Thing(); break; case OBJ_VERTICES: force_cont = Exec_HasFlag("/continue"); no_fill = Exec_HasFlag("/nofill"); Insert_Vertex(force_cont, no_fill); break; case OBJ_SECTORS: force_new = Exec_HasFlag("/new"); Insert_Sector(force_new); break; default: Beep("Cannot insert in this mode"); break; } RedrawMap(); } /* check if a (part of a) LineDef is inside a given box */ bool LineTouchesBox (int ld, int x0, int y0, int x1, int y1) { int lx0 = LineDefs[ld]->Start()->x; int ly0 = LineDefs[ld]->Start()->y; int lx1 = LineDefs[ld]->End()->x; int ly1 = LineDefs[ld]->End()->y; int i; // start is entirely inside the square? if (lx0 >= x0 && lx0 <= x1 && ly0 >= y0 && ly0 <= y1) return true; // end is entirely inside the square? if (lx1 >= x0 && lx1 <= x1 && ly1 >= y0 && ly1 <= y1) return true; if ((ly0 > y0) != (ly1 > y0)) { i = lx0 + (int) ((double) (y0 - ly0) * (double) (lx1 - lx0) / (double) (ly1 - ly0)); if (i >= x0 && i <= x1) return true; /* the linedef crosses the left side */ } if ((ly0 > y1) != (ly1 > y1)) { i = lx0 + (int) ((double) (y1 - ly0) * (double) (lx1 - lx0) / (double) (ly1 - ly0)); if (i >= x0 && i <= x1) return true; /* the linedef crosses the right side */ } if ((lx0 > x0) != (lx1 > x0)) { i = ly0 + (int) ((double) (x0 - lx0) * (double) (ly1 - ly0) / (double) (lx1 - lx0)); if (i >= y0 && i <= y1) return true; /* the linedef crosses the bottom side */ } if ((lx0 > x1) != (lx1 > x1)) { i = ly0 + (int) ((double) (x1 - lx0) * (double) (ly1 - ly0) / (double) (lx1 - lx0)); if (i >= y0 && i <= y1) return true; /* the linedef crosses the top side */ } return false; } static void DoMoveObjects(selection_c *list, int delta_x, int delta_y, int delta_z) { selection_iterator_c it; switch (list->what_type()) { case OBJ_THINGS: for (list->begin(&it) ; !it.at_end() ; ++it) { const Thing * T = Things[*it]; BA_ChangeTH(*it, Thing::F_X, T->x + delta_x); BA_ChangeTH(*it, Thing::F_Y, T->y + delta_y); } break; case OBJ_VERTICES: for (list->begin(&it) ; !it.at_end() ; ++it) { const Vertex * V = Vertices[*it]; BA_ChangeVT(*it, Vertex::F_X, V->x + delta_x); BA_ChangeVT(*it, Vertex::F_Y, V->y + delta_y); } break; case OBJ_SECTORS: // apply the Z delta first for (list->begin(&it) ; !it.at_end() ; ++it) { const Sector * S = Sectors[*it]; BA_ChangeSEC(*it, Sector::F_FLOORH, S->floorh + delta_z); BA_ChangeSEC(*it, Sector::F_CEILH, S->ceilh + delta_z); } /* FALL-THROUGH !! */ case OBJ_LINEDEFS: { selection_c verts(OBJ_VERTICES); ConvertSelection(list, &verts); DoMoveObjects(&verts, delta_x, delta_y, delta_z); } break; default: break; } } void CMD_MoveObjects(int delta_x, int delta_y, int delta_z) { if (edit.Selected->empty()) return; BA_Begin(); // handle a single vertex merging onto an existing one if (edit.mode == OBJ_VERTICES && edit.drag_single_vertex >= 0 && edit.highlight.valid()) { MergeVertex(edit.drag_single_vertex, edit.highlight.num, true /* v1_will_be_deleted */); BA_Delete(OBJ_VERTICES, edit.drag_single_vertex); edit.drag_single_vertex = -1; goto success; } // handle a single vertex splitting a linedef if (edit.mode == OBJ_VERTICES && edit.drag_single_vertex >= 0 && edit.split_line.valid()) { SplitLineDefAtVertex(edit.split_line.num, edit.drag_single_vertex); // now move the vertex! } // move things in sectors too (must do it _before_ moving the // sectors, otherwise we fail trying to determine which sectors // each thing is in). if (edit.mode == OBJ_SECTORS) { selection_c thing_sel(OBJ_THINGS); ConvertSelection(edit.Selected, &thing_sel); DoMoveObjects(&thing_sel, delta_x, delta_y, delta_z); } DoMoveObjects(edit.Selected, delta_x, delta_y, delta_z); success: BA_End(); } static void TransferThingProperties(int src_thing, int dest_thing) { const Thing * T = Things[src_thing]; BA_ChangeTH(dest_thing, Thing::F_TYPE, T->type); BA_ChangeTH(dest_thing, Thing::F_OPTIONS, T->options); // BA_ChangeTH(dest_thing, Thing::F_ANGLE, T->angle); BA_ChangeTH(dest_thing, Thing::F_TID, T->tid); BA_ChangeTH(dest_thing, Thing::F_SPECIAL, T->special); BA_ChangeTH(dest_thing, Thing::F_ARG1, T->arg1); BA_ChangeTH(dest_thing, Thing::F_ARG2, T->arg2); BA_ChangeTH(dest_thing, Thing::F_ARG3, T->arg3); BA_ChangeTH(dest_thing, Thing::F_ARG4, T->arg4); BA_ChangeTH(dest_thing, Thing::F_ARG5, T->arg5); } static void TransferSectorProperties(int src_sec, int dest_sec) { const Sector * SEC = Sectors[src_sec]; BA_ChangeSEC(dest_sec, Sector::F_FLOORH, SEC->floorh); BA_ChangeSEC(dest_sec, Sector::F_FLOOR_TEX, SEC->floor_tex); BA_ChangeSEC(dest_sec, Sector::F_CEILH, SEC->ceilh); BA_ChangeSEC(dest_sec, Sector::F_CEIL_TEX, SEC->ceil_tex); BA_ChangeSEC(dest_sec, Sector::F_LIGHT, SEC->light); BA_ChangeSEC(dest_sec, Sector::F_TYPE, SEC->type); BA_ChangeSEC(dest_sec, Sector::F_TAG, SEC->tag); } #define LINEDEF_FLAG_KEEP (MLF_Blocking + MLF_TwoSided) static void TransferLinedefProperties(int src_line, int dest_line, bool do_tex) { const LineDef * L1 = LineDefs[src_line]; const LineDef * L2 = LineDefs[dest_line]; // don't transfer certain flags int flags = LineDefs[dest_line]->flags; flags = (flags & LINEDEF_FLAG_KEEP) | (L1->flags & ~LINEDEF_FLAG_KEEP); // handle textures if (do_tex && L1->Right() && L2->Right()) { /* There are four cases, depending on number of sides: * * (a) single --> single : easy * * (b) single --> double : copy mid_tex to both sides upper and lower * [alternate idea: copy mid_tex to VISIBLE sides] * * (c) double --> single : pick a texture (e.g. visible lower) to copy * * (d) double --> double : copy each side, but possibly flip the * second linedef based on floor or ceil diff. */ if (! L1->Left()) { int tex = L1->Right()->mid_tex; if (! L2->Left()) { BA_ChangeSD(L2->right, SideDef::F_MID_TEX, tex); } else { BA_ChangeSD(L2->right, SideDef::F_LOWER_TEX, tex); BA_ChangeSD(L2->right, SideDef::F_UPPER_TEX, tex); BA_ChangeSD(L2->left, SideDef::F_LOWER_TEX, tex); BA_ChangeSD(L2->left, SideDef::F_UPPER_TEX, tex); // this is debatable.... CONFIG ITEM? flags |= MLF_LowerUnpegged; flags |= MLF_UpperUnpegged; } } else if (! L2->Left()) { /* pick which texture to copy */ const Sector *front = L1->Right()->SecRef(); const Sector *back = L1-> Left()->SecRef(); int f_l = L1->Right()->lower_tex; int f_u = L1->Right()->upper_tex; int b_l = L1-> Left()->lower_tex; int b_u = L1-> Left()->upper_tex; // ignore missing textures if (BA_GetString(f_l)[0] == '-') f_l = 0; if (BA_GetString(f_u)[0] == '-') f_u = 0; if (BA_GetString(b_l)[0] == '-') b_l = 0; if (BA_GetString(b_u)[0] == '-') b_u = 0; // try hard to find a usable texture int tex = -1; if (front->floorh < back->floorh && f_l > 0) tex = f_l; else if (front->floorh > back->floorh && b_l > 0) tex = b_l; else if (front-> ceilh > back-> ceilh && f_u > 0) tex = f_u; else if (front-> ceilh < back-> ceilh && b_u > 0) tex = b_u; else if (f_l > 0) tex = f_l; else if (b_l > 0) tex = b_l; else if (f_u > 0) tex = f_u; else if (b_u > 0) tex = b_u; if (tex > 0) { BA_ChangeSD(L2->right, SideDef::F_MID_TEX, tex); } } else { const SideDef *RS = L1->Right(); const SideDef *LS = L1->Left(); const Sector *F1 = L1->Right()->SecRef(); const Sector *B1 = L1-> Left()->SecRef(); const Sector *F2 = L2->Right()->SecRef(); const Sector *B2 = L2-> Left()->SecRef(); // logic to determine which sides we copy int f_diff1 = B1->floorh - F1->floorh; int f_diff2 = B2->floorh - F2->floorh; int c_diff1 = B1->ceilh - F1->ceilh; int c_diff2 = B2->ceilh - F2->ceilh; if (f_diff1 * f_diff2 > 0) { /* no change */ } else if (f_diff1 * f_diff2 < 0) std::swap(LS, RS); else if (c_diff1 * c_diff2 > 0) { /* no change */ } else if (c_diff1 * c_diff2 < 0) std::swap(LS, RS); else if (L1->start == L2->end || L1->end == L2->start) { /* no change */ } else if (L1->start == L2->start || L1->end == L2->end) std::swap(LS, RS); else if (F1 == F2 || B1 == B2) { /* no change */ } else if (F1 == B1 || F1 == B2 || F2 == B1 || F2 == B2) std::swap(LS, RS); // TODO; review if we should copy '-' into lowers or uppers BA_ChangeSD(L2->right, SideDef::F_LOWER_TEX, RS->lower_tex); BA_ChangeSD(L2->right, SideDef::F_MID_TEX, RS->mid_tex); BA_ChangeSD(L2->right, SideDef::F_UPPER_TEX, RS->upper_tex); BA_ChangeSD(L2->left, SideDef::F_LOWER_TEX, LS->lower_tex); BA_ChangeSD(L2->left, SideDef::F_MID_TEX, LS->mid_tex); BA_ChangeSD(L2->left, SideDef::F_UPPER_TEX, LS->upper_tex); } } BA_ChangeLD(dest_line, LineDef::F_FLAGS, flags); BA_ChangeLD(dest_line, LineDef::F_TYPE, L1->type); BA_ChangeLD(dest_line, LineDef::F_TAG, L1->tag); BA_ChangeLD(dest_line, LineDef::F_ARG2, L1->arg2); BA_ChangeLD(dest_line, LineDef::F_ARG3, L1->arg3); BA_ChangeLD(dest_line, LineDef::F_ARG4, L1->arg4); BA_ChangeLD(dest_line, LineDef::F_ARG5, L1->arg5); } void CMD_CopyProperties(void) { if (edit.highlight.is_nil()) { Beep("No target for CopyProperties"); return; } else if (edit.Selected->empty()) { Beep("No source for CopyProperties"); return; } else if (edit.mode == OBJ_VERTICES) { Beep("No properties to copy"); return; } /* normal mode, SEL --> HILITE */ if (! Exec_HasFlag("/reverse")) { if (edit.Selected->count_obj() != 1) { Beep("Too many sources for CopyProperties"); return; } int source = edit.Selected->find_first(); int target = edit.highlight.num; // silently allow copying onto self if (source == target) return; BA_Begin(); switch (edit.mode) { case OBJ_SECTORS: TransferSectorProperties(source, target); break; case OBJ_THINGS: TransferThingProperties(source, target); break; case OBJ_LINEDEFS: TransferLinedefProperties(source, target, true /* do_tex */); break; default: break; } BA_End(); } else /* reverse mode, HILITE --> SEL */ { if (edit.Selected->count_obj() == 1 && edit.Selected->find_first() == edit.highlight.num) { Beep("No selection for CopyProperties"); return; } int source = edit.highlight.num; selection_iterator_c it; BA_Begin(); for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { if (*it == source) continue; switch (edit.mode) { case OBJ_SECTORS: TransferSectorProperties(source, *it); break; case OBJ_THINGS: TransferThingProperties(source, *it); break; case OBJ_LINEDEFS: TransferLinedefProperties(source, *it, true /* do_tex */); break; default: break; // fuck you, compiler } } BA_End(); } } static void Drag_CountOnGrid_Worker(int obj_type, int objnum, int *count, int *total) { switch (obj_type) { case OBJ_THINGS: *total += 1; if (grid.OnGrid(Things[objnum]->x, Things[objnum]->y)) *count += 1; break; case OBJ_VERTICES: *total += 1; if (grid.OnGrid(Vertices[objnum]->x, Vertices[objnum]->y)) *count += 1; break; case OBJ_LINEDEFS: Drag_CountOnGrid_Worker(OBJ_VERTICES, LineDefs[objnum]->start, count, total); Drag_CountOnGrid_Worker(OBJ_VERTICES, LineDefs[objnum]->end, count, total); break; case OBJ_SECTORS: for (int n = 0 ; n < NumLineDefs ; n++) { LineDef *L = LineDefs[n]; if (! L->TouchesSector(objnum)) continue; Drag_CountOnGrid_Worker(OBJ_LINEDEFS, n, count, total); } break; default: break; } } static void Drag_CountOnGrid(int *count, int *total) { // Note: the results are approximate, vertices can be counted two // or more times. selection_iterator_c it; for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { Drag_CountOnGrid_Worker(edit.mode, *it, count, total); } } static void Drag_UpdateObjectDist(int obj_type, int objnum, int *x, int *y, int *best_dist, int map_x, int map_y, bool only_grid) { int x2, y2; switch (obj_type) { case OBJ_THINGS: x2 = Things[objnum]->x; y2 = Things[objnum]->y; break; case OBJ_VERTICES: x2 = Vertices[objnum]->x; y2 = Vertices[objnum]->y; break; case OBJ_LINEDEFS: { LineDef *L = LineDefs[objnum]; Drag_UpdateObjectDist(OBJ_VERTICES, L->start, x, y, best_dist, map_x, map_y, only_grid); Drag_UpdateObjectDist(OBJ_VERTICES, L->end, x, y, best_dist, map_x, map_y, only_grid); } return; case OBJ_SECTORS: // recursively handle all vertices belonging to the sector // (some vertices can be processed two or more times, that // won't matter though). for (int n = 0 ; n < NumLineDefs ; n++) { LineDef *L = LineDefs[n]; if (! L->TouchesSector(objnum)) continue; Drag_UpdateObjectDist(OBJ_LINEDEFS, n, x, y, best_dist, map_x, map_y, only_grid); } return; default: return; } // handle OBJ_THINGS and OBJ_VERTICES if (only_grid && ! grid.OnGrid(x2, y2)) return; int dist = ComputeDist(x2 - map_x, y2 - map_y); if (dist < *best_dist) { *x = x2; *y = y2; *best_dist = dist; } } void GetDragFocus(int *x, int *y, int map_x, int map_y) { *x = 0; *y = 0; // determine whether a majority of the object(s) are already on // the grid. If they are, then pick a coordinate that also lies // on the grid. bool only_grid = false; int count = 0; int total = 0; if (grid.snap) { Drag_CountOnGrid(&count, &total); if (total > 0 && count > total / 2) only_grid = true; } int best_dist = 99999; selection_iterator_c it; for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { Drag_UpdateObjectDist(edit.mode, *it, x, y, &best_dist, map_x, map_y, only_grid); } } bool Texture_MatchPattern(const char *tex, const char *pattern) { // Note: an empty pattern matches NOTHING char local_pat[256]; local_pat[0] = 0; // add '*' to the start and end of the pattern // (unless it uses the ^ or $ anchors) bool negated = false; if (pattern[0] == '!') { pattern++; negated = true; } if (pattern[0] == '^') pattern++; else strcpy(local_pat, "*"); strcat(local_pat, pattern); size_t len = strlen(local_pat); if (len == 0) return false; if (local_pat[len-1] == '$') local_pat[len-1] = 0; else strcat(local_pat, "*"); bool result = fl_filename_match(tex, local_pat) ? true : false; return negated ? !result : result; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/editloop.h0000644000175100017510000001043312650662322016252 0ustar aaptedaapted//------------------------------------------------------------------------ // EDIT LOOP //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_EDITLOOP_H__ #define __EUREKA_EDITLOOP_H__ typedef enum { ACT_NOTHING = 0, ACT_WAIT_META, // user pressed ';' -- waiting for next key ACT_SELBOX, // user is outlining a selection box ACT_DRAG, // user is dragging some objects ACT_SCALE, // user is scaling (etc) some objects ACT_ADJUST_OFS, // user is adjusting the offsets on a sidedef ACT_DRAW_LINE, // user is drawing a new line } editor_action_e; typedef enum { SREND_Nothing = 0, SREND_Floor, SREND_Ceiling, SREND_Lighting } sector_rendering_mode_e; /* this holds some important editor state */ typedef struct { obj_type_e mode; // current mode (OBJ_LINEDEFS, OBJ_SECTORS, etc...) editor_action_e action; // an in-progress action, usually ACT_NOTHING bool is_scrolling; // user is scrolling the map (or moving in 3D view) bool render3d; // 3D preview is active bool error_mode; // draw selection in red int sector_render_mode; // one of the SREND_XXX values bool show_object_numbers; // Whether the object numbers are shown bool show_things_squares; // Whether the things squares are shown bool show_things_sprites; // Whether the things sprites are shown int map_x; // Map coordinates of pointer int map_y; int pointer_in_window; // If false, pointer_[xy] are not meaningful. int button_down; // mouse button 1 to 3, or 0 for none, keycode_t button_mod; // modifier(s) used when button was pressed Objid clicked; // The object that was under the pointer when // the left click occurred. bool did_a_move; // just moved stuff, clear the next selection selection_c *Selected; // all selected objects (usually empty) Objid highlight; // The highlighted object Objid split_line; // linedef which would be split by a new vertex int split_x; int split_y; int drawing_from; // for ACT_DRAW_LINE, the vertex we are drawing a line from int drag_single_vertex; // -1, or vertex number when dragging one vertex } Editor_State_t; extern Editor_State_t edit; void Editor_Init(); void Editor_DigitKey(keycode_t key); void Editor_Wheel(int dx, int dy, keycode_t mod); void Editor_MousePress(keycode_t mod); void Editor_MouseRelease(); void Editor_MiddlePress(keycode_t mod); void Editor_MiddleRelease(); void Editor_LeaveWindow(); void Editor_ClearAction(); void Editor_SetAction(editor_action_e new_action); bool Editor_ParseUser(const char ** tokens, int num_tok); void Editor_WriteUser(FILE *fp); void Editor_ClearErrorMode(); void Editor_ChangeMode(char mode); void Editor_ChangeMode_Raw(obj_type_e new_mode); void Editor_Zoom(int delta, int mid_x, int mid_y); bool GetCurrentObjects(selection_c *list); void UpdateHighlight(); void RedrawMap(); /* raw input handling */ extern int wheel_dx; extern int wheel_dy; int Editor_RawKey(int event); int Editor_RawButton(int event); int Editor_RawWheel(int event); int Editor_RawMouse(int event); /* commands */ void CMD_SelectAll(void); void CMD_UnselectAll(void); void CMD_InvertSelection(void); void CMD_LastSelection(void); void CMD_Quit(void); void CMD_ZoomWholeMap(void); void CMD_ZoomSelection(void); void CMD_GoToCamera(void); void CMD_ToggleVar(void); #endif /* __EUREKA_EDITLOOP_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/w_texture.cc0000644000175100017510000001513212651121246016614 0ustar aaptedaapted//------------------------------------------------------------------------ // TEXTURE LOADING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2015 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include #include #include "m_game.h" /* yg_picture_format */ #include "levels.h" #include "w_loadpic.h" #include "w_rawdef.h" #include "w_texture.h" std::map textures; // textures which can cause the Medusa Effect in vanilla/chocolate DOOM static std::map medusa_textures; static void DeleteTex(const std::map::value_type& P) { delete P.second; } static void W_ClearTextures() { std::for_each(textures.begin(), textures.end(), DeleteTex); textures.clear(); medusa_textures.clear(); } static void LoadTextureLump(Lump_c *lump, byte *pnames, int pname_size, bool skip_first) { // skip size word at front of PNAMES pnames += 4; pname_size /= 8; // load TEXTUREx data into memory for easier processing byte *tex_data; int tex_length = W_LoadLumpData(lump, &tex_data); // shut the fuck up, compiler (void) tex_length; // at the front of the TEXTUREx lump are some 4-byte integers s32_t *tex_data_s32 = (s32_t *)tex_data; int num_tex = LE_S32(tex_data_s32[0]); // FIXME validate num_tex // Note: we skip the first entry (e.g. AASHITTY) which is not really // usable (in the DOOM engine the #0 texture is not drawn). for (int n = skip_first ? 1 : 0 ; n < num_tex ; n++) { int offset = LE_S32(tex_data_s32[1+n]); // FIXME: validate offset const raw_texture_t *raw = (const raw_texture_t *)(tex_data + offset); // create the new Img int width = LE_U16(raw->width); int height = LE_U16(raw->height); DebugPrintf("Texture [%.8s] : %dx%d\n", raw->name, width, height); if (width == 0 || height == 0) FatalError("W_InitTextures: Texture '%.8s' has zero size\n", raw->name); Img_c *img = new Img_c(width, height, false); bool is_medusa = false; // apply all the patches int num_patches = LE_S16(raw->patch_count); if (! num_patches) FatalError("W_InitTextures: Texture '%.8s' has no patches\n", raw->name); const raw_patchdef_t *patdef = (const raw_patchdef_t *) & raw->patches[0]; // andrewj: this is not strictly correct, the Medusa Effect is only // triggered when multiple patches occupy a single column of // the texture. But checking for that is a major pain since // we don't know the width of each patch here.... if (num_patches >= 2) is_medusa = true; for (int j = 0 ; j < num_patches ; j++, patdef++) { int xofs = LE_S16(patdef->x_origin); int yofs = LE_S16(patdef->y_origin); int pname_idx = LE_U16(patdef->pname); // AYM 1998-08-08: Yes, that's weird but that's what Doom // does. Without these two lines, the few textures that have // patches with negative y-offsets (BIGDOOR7, SKY1, TEKWALL1, // TEKWALL5 and a few others) would not look in the texture // viewer quite like in Doom. This should be mentioned in // the UDS, by the way. if (yofs < 0) yofs = 0; if (pname_idx >= pname_size) { LogPrintf("Invalid pname in texture '%.8s'\n", raw->name); continue; } char picname[16]; memcpy(picname, pnames + 8*pname_idx, 8); picname[8] = 0; //DebugPrintf("-- %d patch [%s]\n", j, picname); Lump_c *lump = W_FindPatchLump(picname); if (! lump || ! LoadPicture(*img, lump, picname, xofs, yofs, 0, 0)) { LogPrintf("texture '%.8s': patch '%.8s' not found.\n", raw->name, picname); } } // store the new texture char namebuf[16]; memcpy(namebuf, raw->name, 8); namebuf[8] = 0; std::string t_str(namebuf); // FIXME: free any existing one with same name textures[t_str] = img; if (is_medusa) medusa_textures[t_str] = 1; } W_FreeLumpData(&tex_data); } #if 0 static void LoadTexture_SinglePatch(const char *name, Lump_c *lump) { Img_c *img = new Img_c(); if (! LoadPicture(*img, lump, name, 0, 0)) { delete img; return; } std::string t_str(name); // FIXME: free any existing one with same name textures[t_str] = img; } #endif void W_LoadTextures() { W_ClearTextures(); for (int i = 0 ; i < (int)master_dir.size() ; i++) { LogPrintf("Loading Textures from WAD #%d\n", i+1); Lump_c *pnames = master_dir[i]->FindLump("PNAMES"); Lump_c *texture1 = master_dir[i]->FindLump("TEXTURE1"); Lump_c *texture2 = master_dir[i]->FindLump("TEXTURE2"); // Note that we _require_ the PNAMES lump to exist along // with the TEXTURE1/2 lump which uses it. Probably a // few wads exist which lack the PNAMES lump (relying on // the one in the IWAD), however this practice is too // error-prone (using the wrong IWAD will break it), // so I think supporting it is a bad idea. -- AJA if (!pnames) continue; byte *pname_data; int pname_size = W_LoadLumpData(pnames, &pname_data); if (texture1) LoadTextureLump(texture1, pname_data, pname_size, true); if (texture2) LoadTextureLump(texture2, pname_data, pname_size, false); } } Img_c * W_GetTexture(const char *name) { if (name[0] == 0 || name[0] == '-') return NULL; std::string t_str = name; std::map::iterator P = textures.find(t_str); if (P != textures.end()) return P->second; return NULL; } bool W_TextureExists(const char *name) { std::string t_str = name; std::map::iterator P = textures.find(t_str); return (P != textures.end()); } bool W_TextureCausesMedusa(const char *name) { std::string t_str = name; std::map::iterator P = medusa_textures.find(t_str); return (P != medusa_textures.end()); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_replace.cc0000644000175100017510000007341512647603045016715 0ustar aaptedaapted//------------------------------------------------------------------------ // FIND AND REPLACE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2015-2016 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 "main.h" #include "ui_window.h" #include "e_path.h" // GoToObject #include "levels.h" // Selection_Clear #include "m_config.h" // gui_scheme #include "m_game.h" #include "w_rawdef.h" class number_group_c { // This represents a small group of numbers and number ranges, // which the user can type into the Match input box. #define NUMBER_GROUP_MAX 40 private: int size; int ranges[NUMBER_GROUP_MAX][2]; bool everything; public: number_group_c() : size(0), everything(false) { } ~number_group_c() { } void clear() { size = 0; everything = false; } bool is_single() const { return (size == 1) && (ranges[0][0] == ranges[0][1]); } bool is_everything() const { return everything; } int grab_first() const { if (size == 0) return 0; return ranges[0][0]; } void insert(int low, int high) { // overflow is silently ignored if (size >= NUMBER_GROUP_MAX) return; // TODO : try to merge with existing range ranges[size][0] = low; ranges[size][1] = high; size++; } bool get(int num) const { for (int i = 0 ; i < size ; i++) { if (ranges[i][0] <= num && num <= ranges[i][1]) return true; } return false; } // // Parse a string like "1,3-5,9" and add the numbers (or ranges) // to this group. Returns false for malformed strings. // An empty string is considered invalid. // bool ParseString(const char *str) { char *endptr; for (;;) { // support an asterix to mean everything // (useful when using filters) if (*str == '*') { insert(INT_MIN, INT_MAX); everything = true; return true; } int low = (int)strtol(str, &endptr, 0 /* allow hex */); int high = low; if (endptr == str) return false; str = endptr; while (isspace(*str)) str++; // check for range if (*str == '-' || (str[0] == '.' && str[1] == '.')) { str += (*str == '-') ? 1 : 2; while (isspace(*str)) str++; high = (int)strtol(str, &endptr, 0 /* allow hex */); if (endptr == str) return false; str = endptr; // valid range? if (high < low) return false; while (isspace(*str)) str++; } insert(low, high); if (*str == 0) return true; // OK // // valid separator? if (*str == ',' || *str == '/' || *str == '|') str++; else return false; } } }; //------------------------------------------------------------------------ class UI_TripleCheckButton : public Fl_Group { /* this button has three states to represent how a search should check against a boolean value: 1. want value to be FALSE (show with red 'X') 2. want value to be TRUE (show with green tick) 3. don't care about value (show with black '?') */ private: int _value; // -1, 0, +1 Fl_Button * false_but; Fl_Button * true_but; Fl_Button * other_but; void Update() { false_but->hide(); true_but->hide(); other_but->hide(); if (_value < 0) false_but->show(); else if (_value > 0) true_but->show(); else other_but->show(); redraw(); } void BumpValue() { _value = (_value < 0) ? 0 : (_value == 0) ? 1 : -1; Update(); } static void button_callback(Fl_Widget *w, void *data) { UI_TripleCheckButton *G = (UI_TripleCheckButton *)data; G->BumpValue(); G->do_callback(); } public: UI_TripleCheckButton(int X, int Y, int W, int H, const char *label = NULL) : Fl_Group(X, Y, W, H), _value(0) { if (label) { Fl_Box *box = new Fl_Box(FL_NO_BOX, X, Y, W, H, label); box->align(FL_ALIGN_LEFT); } false_but = new Fl_Button(X, Y, W, H, "N"); false_but->labelcolor(FL_RED); false_but->labelsize(H*2/3); false_but->callback(button_callback, this); true_but = new Fl_Button(X, Y, W, H, "Y"); true_but->labelfont(FL_HELVETICA_BOLD); true_but->labelcolor(fl_rgb_color(0, 176, 0)); true_but->labelsize(H*2/3); true_but->callback(button_callback, this); other_but = new Fl_Button(X, Y, W, H, "-"); other_but->labelsize(H*3/4); other_but->callback(button_callback, this); end(); resizable(NULL); Update(); } virtual ~UI_TripleCheckButton() { } public: int value() const { return _value; } void value(int new_value) { _value = new_value; Update(); } }; //------------------------------------------------------------------------ #define HIDE_BG (gui_scheme == 2 ? FL_DARK3 : FL_DARK1) UI_FindAndReplace::UI_FindAndReplace(int X, int Y, int W, int H) : Fl_Group(X, Y, W, H, NULL), find_numbers(new number_group_c), tag_numbers(new number_group_c), cur_obj(OBJ_THINGS, -1) { box(FL_FLAT_BOX); color(WINDOW_BG, WINDOW_BG); /* ---- FIND AREA ---- */ Fl_Group *grp1 = new Fl_Group(X, Y, W, 210); grp1->box(FL_UP_BOX); { Fl_Button *hide_button = new Fl_Button(X + 8, Y + 12, 22, 22, "X"); hide_button->color(HIDE_BG, HIDE_BG); hide_button->labelsize(14); hide_button->callback(hide_callback, this); Fl_Box *title = new Fl_Box(X + 60, Y + 10, W - 70, 30, "Find and Replace"); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); title->labelsize(18+KF*4); what = new Fl_Choice(X+60, Y+46, W - 120, 33); what->textsize(17); what->add("Things|Line Textures|Sector Flats|Lines by Type|Sectors by Type"); what->value(0); what->callback(what_kind_callback, this); UpdateWhatColor(); find_match = new Fl_Input(X+70, Y+95, 125, 25, "Match: "); find_match->when(FL_WHEN_CHANGED); find_match->callback(find_match_callback, this); find_choose = new Fl_Button(X+210, Y+95, 70, 25, "Choose"); find_choose->callback(find_choose_callback, this); find_desc = new Fl_Output(X+70, Y+125, 210, 25, "Desc: "); find_but = new Fl_Button(X+50, Y+165, 80, 30, "Find"); find_but->labelfont(FL_HELVETICA_BOLD); find_but->callback(find_but_callback, this); select_all_but = new Fl_Button(X+165, Y+165, 93, 30, "Select All"); select_all_but->callback(select_all_callback, this); } grp1->end(); /* ---- REPLACE AREA ---- */ Fl_Group *grp2 = new Fl_Group(X, Y + 214, W, 132); grp2->box(FL_UP_BOX); { rep_value = new Fl_Input(X+80, Y+230, 115, 25, "New val: "); rep_value->when(FL_WHEN_CHANGED); rep_value->callback(rep_value_callback, this); rep_choose = new Fl_Button(X+210, Y+230, 70, 25, "Choose"); rep_choose->callback(rep_choose_callback, this); rep_desc = new Fl_Output(X+80, Y+260, 200, 25, "Desc: "); apply_but = new Fl_Button(X+45, Y+300, 90, 30, "Replace"); apply_but->labelfont(FL_HELVETICA_BOLD); apply_but->callback(apply_but_callback, this); replace_all_but = new Fl_Button(X+160, Y+300, 105, 30, "Replace All"); replace_all_but->callback(replace_all_callback, this); } grp2->end(); /* ---- FILTER AREA ---- */ Fl_Group *grp3 = new Fl_Group(X, Y + 350, W, H - 350); grp3->box(FL_UP_BOX); { filter_toggle = new Fl_Toggle_Button(X+15, Y+356, 30, 30, "v"); filter_toggle->labelsize(16); filter_toggle->color(FL_DARK3, FL_DARK3); filter_toggle->callback(filter_toggle_callback, this); filter_toggle->clear_visible_focus(); Fl_Box *f_text = new Fl_Box(X+60, Y+356, 200, 30, "Search Filters"); f_text->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); f_text->labelsize(16); filter_group = new Fl_Group(X, Y+391, W, H-391); { // common stuff tag_input = new Fl_Input(X+105, Y+390, 130, 24, "Tag match:"); tag_input->when(FL_WHEN_CHANGED); tag_input->callback(tag_input_callback, this); // thing stuff o_easy = new UI_TripleCheckButton(X+105, Y+414, 28, 26, "easy: "); o_medium = new UI_TripleCheckButton(X+105, Y+444, 28, 26, "medium: "); o_hard = new UI_TripleCheckButton(X+105, Y+474, 28, 26, "hard: "); o_sp = new UI_TripleCheckButton(X+220, Y+414, 28, 26, "sp: "); o_coop = new UI_TripleCheckButton(X+220, Y+444, 28, 26, "coop: "); o_dm = new UI_TripleCheckButton(X+220, Y+474, 28, 26, "dm: "); // sector stuff o_floors = new Fl_Check_Button(X+45, Y+418, 80, 22, " floors"); o_ceilings = new Fl_Check_Button(X+45, Y+440, 80, 22, " ceilings"); o_skies = new Fl_Check_Button(X+45, Y+462, 80, 22, " skies"); // linedef stuff o_lowers = new Fl_Check_Button(X+45, Y+418, 80, 22, " lowers"); o_uppers = new Fl_Check_Button(X+45, Y+440, 80, 22, " uppers"); o_rails = new Fl_Check_Button(X+45, Y+462, 80, 22, " rail"); o_one_sided = new Fl_Check_Button(X+155, Y+418, 80, 22, " one-sided"); o_two_sided = new Fl_Check_Button(X+155, Y+440, 80, 22, " two-sided"); } filter_group->end(); filter_group->hide(); UpdateWhatFilters(); } grp3->end(); grp3->resizable(NULL); resizable(grp3); end(); Clear(); } UI_FindAndReplace::~UI_FindAndReplace() { } void UI_FindAndReplace::hide_callback(Fl_Widget *w, void *data) { main_win->HideSpecialPanel(); } void UI_FindAndReplace::UpdateWhatColor() { switch (what->value()) { case 0: /* Things */ what->color(FL_MAGENTA); break; case 1: /* Line Tex */ what->color(fl_rgb_color(0,128,255)); break; case 2: /* Sector Flat */ what->color(FL_YELLOW); break; case 3: /* Line Type */ what->color(FL_GREEN); break; case 4: /* Sector Type */ what->color(fl_rgb_color(255,144,0)); break; } } void UI_FindAndReplace::UpdateWhatFilters() { int x = what->value(); #define SHOW_WIDGET_IF(w, test) \ if (test) (w)->show(); else (w)->hide(); // common stuff if (x == 0 && Level_format != MAPF_Hexen) { tag_input->deactivate(); tag_input->value(""); } else { tag_input->activate(); } // thing stuff SHOW_WIDGET_IF(o_easy, x == 0); SHOW_WIDGET_IF(o_medium, x == 0); SHOW_WIDGET_IF(o_hard, x == 0); SHOW_WIDGET_IF(o_sp, x == 0); SHOW_WIDGET_IF(o_coop, x == 0); SHOW_WIDGET_IF(o_dm, x == 0); // sector stuff SHOW_WIDGET_IF(o_floors, x == 2); SHOW_WIDGET_IF(o_ceilings, x == 2); SHOW_WIDGET_IF(o_skies, x == 2); // linedef stuff SHOW_WIDGET_IF(o_lowers, x == 1); SHOW_WIDGET_IF(o_uppers, x == 1); SHOW_WIDGET_IF(o_rails, x == 1); SHOW_WIDGET_IF(o_one_sided, x == 1 || x == 3); SHOW_WIDGET_IF(o_two_sided, x == 1 || x == 3); #undef SHOW_WIDGET_IF // vanilla DOOM : always hide SP and COOP flags if (x == 0 && ! game_info.coop_dm_flags && Level_format != MAPF_Hexen) { o_sp->hide(); o_coop->hide(); } } void UI_FindAndReplace::rawShowFilter(int value) { if (value) { filter_toggle->label("^"); filter_group->show(); } else { filter_toggle->label("v"); filter_group->hide(); } } void UI_FindAndReplace::filter_toggle_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; Fl_Toggle_Button *toggle = (Fl_Toggle_Button *)w; box->rawShowFilter(toggle->value()); } void UI_FindAndReplace::what_kind_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; obj_type_e prev_type = box->cur_obj.type; bool want_descs = true; switch (box->what->value()) { case 0: box->cur_obj.type = OBJ_THINGS; break; case 1: box->cur_obj.type = OBJ_LINEDEFS; want_descs = false; break; case 2: box->cur_obj.type = OBJ_SECTORS; want_descs = false; break; case 3: box->cur_obj.type = OBJ_LINEDEFS; break; case 4: box->cur_obj.type = OBJ_SECTORS; break; default: break; } // only clear everything when type changes if (prev_type != box->cur_obj.type) { box->Clear(); } box->UpdateWhatColor(); box->UpdateWhatFilters(); if (want_descs) { box->find_desc->activate(); box-> rep_desc->activate(); } else { box->find_desc->deactivate(); box-> rep_desc->deactivate(); } } void UI_FindAndReplace::Open() { show(); WhatFromEditMode(); // this will do a Clear() for us what->do_callback(); Fl::focus(find_match); } void UI_FindAndReplace::Clear() { cur_obj.clear(); find_match->value(""); find_desc->value(""); find_but->label("Find"); rep_value->value(""); rep_desc->value(""); find_but->deactivate(); select_all_but->deactivate(); apply_but->deactivate(); replace_all_but->deactivate(); filter_toggle->value(0); filter_toggle->do_callback(); ResetFilters(); } void UI_FindAndReplace::ResetFilters() { tag_input->value(""); tag_numbers->clear(); // thing filters o_easy ->value(0); o_medium->value(0); o_hard ->value(0); o_sp ->value(0); o_coop->value(0); o_dm ->value(0); ComputeFlagMask(); // sector filters o_floors ->value(1); o_ceilings->value(1); o_skies ->value(1); // linedef filters o_lowers->value(1); o_uppers->value(1); o_rails ->value(1); o_one_sided->value(1); o_two_sided->value(1); } bool UI_FindAndReplace::WhatFromEditMode() { switch (edit.mode) { case OBJ_THINGS: what->value(0); return true; case OBJ_LINEDEFS: what->value(1); return true; case OBJ_SECTORS: what->value(2); return true; default: return false; } } void UI_FindAndReplace::find_but_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; box->FindNext(); } void UI_FindAndReplace::select_all_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; box->DoAll(false /* replace */); } void UI_FindAndReplace::apply_but_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; box->DoReplace(); } void UI_FindAndReplace::replace_all_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; box->DoAll(true /* replace */); } void UI_FindAndReplace::find_match_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; bool is_valid = box->CheckInput(box->find_match, box->find_desc, box->find_numbers); if (is_valid) { box->find_but->activate(); box->select_all_but->activate(); box->find_match->textcolor(FL_FOREGROUND_COLOR); box->find_match->redraw(); } else { box->find_but->deactivate(); box->select_all_but->deactivate(); box->find_match->textcolor(FL_RED); box->find_match->redraw(); } // update Replace section too box->rep_value->do_callback(); } void UI_FindAndReplace::rep_value_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; bool is_valid = box->CheckInput(box->rep_value, box->rep_desc); if (is_valid) { box->rep_value->textcolor(FL_FOREGROUND_COLOR); box->rep_value->redraw(); } else { box->rep_value->textcolor(FL_RED); box->rep_value->redraw(); } bool is_usable = (is_valid && box->find_but->active()); if (is_usable) box->replace_all_but->activate(); else box->replace_all_but->deactivate(); // require an found object too before 'Replace' button can be used if (box->cur_obj.is_nil()) is_usable = false; if (is_usable) box->apply_but->activate(); else box->apply_but->deactivate(); } bool UI_FindAndReplace::CheckInput(Fl_Input *w, Fl_Output *desc, number_group_c *num_grp) { if (strlen(w->value()) == 0) { desc->value(""); return false; } if (what->value() == 1 || what->value() == 2) return true; // for numeric types, parse the number(s) and/or ranges int type_num; if (! num_grp) { // just check the number is valid char *endptr; type_num = strtol(w->value(), &endptr, 0 /* allow hex */); if (*endptr != 0) { desc->value("(parse error)"); return false; } } else { num_grp->clear(); if (! num_grp->ParseString(w->value())) { desc->value("(parse error)"); return false; } if (num_grp->is_everything()) { desc->value("(everything)"); return true; } else if (! num_grp->is_single()) { desc->value("(multi-match)"); return true; } type_num = num_grp->grab_first(); } switch (what->value()) { case 0: // Things { const thingtype_t *info = M_GetThingType(type_num); desc->value(info->desc); break; } case 3: // Lines by Type { const linetype_t *info = M_GetLineType(type_num); desc->value(info->desc); break; } case 4: // Lines by Type { const sectortype_t * info = M_GetSectorType(type_num); desc->value(info->desc); break; } default: break; } return true; } void UI_FindAndReplace::tag_input_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; bool is_valid = box->CheckNumberInput(box->tag_input, box->tag_numbers); if (is_valid) { box->tag_input->textcolor(FL_FOREGROUND_COLOR); box->tag_input->redraw(); } else { // uhhh, cannot disable all the search buttons [ too hard ] // so..... showing red is the all we can do.... box->tag_input->textcolor(FL_RED); box->tag_input->redraw(); } } bool UI_FindAndReplace::CheckNumberInput(Fl_Input *w, number_group_c *num_grp) { num_grp->clear(); // an empty string will mean match everything if (w->size() == 0) return true; if (num_grp->ParseString(w->value())) return true; return false; } //------------------------------------------------------------------------ char UI_FindAndReplace::GetKind() { // these letters are same as the Browser uses int v = what->value(); if (v < 0 || v >= 5) return '?'; const char *kinds = "OTFLS"; return kinds[v]; } void UI_FindAndReplace::BrowsedItem(char kind, int number, const char *name, int e_state) { if (kind != GetKind()) { fl_beep(); return; } bool is_replace = false; if (Fl::focus() == rep_value || Fl::focus() == rep_desc) is_replace = true; char append = 0; // never append if user has selected some/all of the input if (! is_replace && find_match->position() == find_match->mark()) { append = ','; } // insert the chosen item Fl_Input *inp = is_replace ? rep_value : find_match; if (kind == 'T' || kind == 'F') InsertName(inp, append, name); else { // already present? if (! is_replace && find_numbers->get(number)) return; InsertNumber(inp, append, number); } } void UI_FindAndReplace::InsertName(Fl_Input *inp, char append, const char *name) { if (append) { int len = inp->size(); // insert a separator, unless user has already put one there if (NeedSeparator(inp)) { char buf[4]; buf[0] = append; buf[1] = 0; inp->replace(len, len, buf); len += 1; } inp->replace(len, len, name); } else { inp->value(name); } inp->do_callback(); Fl::focus(inp); inp->redraw(); } void UI_FindAndReplace::InsertNumber(Fl_Input *inp, char append, int number) { char buf[256]; sprintf(buf, "%d", number); InsertName(inp, append, buf); } bool UI_FindAndReplace::NeedSeparator(Fl_Input *inp) const { const char *str = inp->value(); // nothing but whitespace? --> no need while (isspace(*str)) str++; if (str[0] == 0) return false; // ends with a punctuation symbol? --> no need int p = (int)strlen(str) - 1; while (p >= 0 && isspace(str[p])) p--; if (p >= 0) { if (str[p] == '_') return true; if (str[p] == '*') return true; if (ispunct(str[p])) return false; } return true; } void UI_FindAndReplace::find_choose_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; main_win->ShowBrowser(box->GetKind()); // ensure Match input widget has the focus Fl::focus(box->find_match); box->find_match->redraw(); } void UI_FindAndReplace::rep_choose_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; main_win->ShowBrowser(box->GetKind()); // ensure 'New val' input widget has the focus Fl::focus(box->rep_value); box->rep_value->redraw(); } //------------------------------------------------------------------------ bool UI_FindAndReplace::FindNext() { // this can happen via CTRL-G shortcut (View / Go to next) if (strlen(find_match->value()) == 0) { Beep("No find active!"); return false; } ComputeFlagMask(); if (cur_obj.type != edit.mode) { Editor_ChangeMode_Raw(cur_obj.type); } Selection_Clear(); bool is_first = cur_obj.is_nil(); int start_at = cur_obj.is_nil() ? 0 : (cur_obj.num + 1); int total = NumObjects(cur_obj.type); for (int idx = start_at ; idx < total ; idx++) { if (MatchesObject(idx)) { cur_obj.num = idx; if (is_first) { find_but->label("Next"); rep_value->do_callback(); } GoToObject(cur_obj); Status_Set("Found #%d", idx); return true; } } // nothing (else) was found cur_obj.clear(); find_but->label("Find"); rep_value->do_callback(); if (is_first) Beep("Nothing found"); else Beep("No more found"); return false; } void UI_FindAndReplace::DoReplace() { // sanity check [ should never happen ] if (strlen(find_match->value()) == 0 || strlen( rep_value->value()) == 0) { Beep("Bad replace"); return; } // this generally can't happen either if (cur_obj.is_nil()) { Beep("No object to replace"); return; } int replace_tex_id = UI_SideBox::TexFromWidget(rep_value); BA_Begin(); ApplyReplace(cur_obj.num, replace_tex_id); BA_End(); // move onto next object FindNext(); } bool UI_FindAndReplace::MatchesObject(int idx) { switch (what->value()) { case 0: // Things return Match_Thing(idx); case 1: // LineDefs (texturing) return Match_LineDef(idx); case 2: // Sectors (texturing) return Match_Sector(idx); case 3: // Lines by Type return Match_LineType(idx); case 4: // Sectors by Type return Match_SectorType(idx); default: return false; } } void UI_FindAndReplace::ApplyReplace(int idx, int new_tex) { SYS_ASSERT(idx >= 0); switch (what->value()) { case 0: // Things Replace_Thing(idx); break; case 1: // LineDefs (texturing) Replace_LineDef(idx, new_tex); break; case 2: // Sectors (texturing) Replace_Sector(idx, new_tex); break; case 3: // Lines by Type Replace_LineType(idx); break; case 4: // Sectors by Type Replace_SectorType(idx); break; default: break; } } void UI_FindAndReplace::DoAll(bool replace) { if (strlen(find_match->value()) == 0) { Beep("No find active!"); return; } ComputeFlagMask(); if (cur_obj.type != edit.mode) Editor_ChangeMode_Raw(cur_obj.type); int replace_tex_id = 0; if (replace) { replace_tex_id = UI_SideBox::TexFromWidget(rep_value); BA_Begin(); } // we select objects even in REPLACE mode // (gives the user a visual indication that stuff was done) // this clears the selection edit.Selected->change_type(edit.mode); int total = NumObjects(cur_obj.type); int count = 0; for (int idx = 0 ; idx < total ; idx++) { if (! MatchesObject(idx)) continue; count++; if (replace) ApplyReplace(idx, replace_tex_id); edit.Selected->set(idx); } if (count == 0) Beep("Nothing found"); else Status_Set("Found %d objects", count); if (replace) { BA_End(); } if (count > 0) { GoToSelection(); edit.error_mode = true; } if (replace) { cur_obj.clear(); rep_value->do_callback(); } RedrawMap(); } //------------------------------------------------------------------------ // MATCHING METHODS //------------------------------------------------------------------------ bool UI_FindAndReplace::Match_Thing(int idx) { const Thing *T = Things[idx]; if (! find_numbers->get(T->type)) return false; // skill/mode flag filter if ((T->options & options_mask) != options_value) return false; if (Level_format == MAPF_Hexen && ! Filter_Tag(T->tid)) return false; return true; } bool UI_FindAndReplace::Match_LineDef(int idx) { const LineDef *L = LineDefs[idx]; if (! Filter_Tag(L->tag) || ! Filter_Sides(L)) return false; const char *pattern = find_match->value(); for (int pass = 0 ; pass < 2 ; pass++) { const SideDef *SD = (pass == 0) ? L->Right() : L->Left(); if (! SD) continue; const char *L_tex = SD->LowerTex(); const char *U_tex = SD->UpperTex(); const char *R_tex = SD->MidTex(); if (! L->TwoSided()) { L_tex = R_tex; R_tex = U_tex = NULL; } if (!filter_toggle->value() || o_lowers->value()) if (L_tex && Pattern_Match(L_tex, pattern)) return true; if (!filter_toggle->value() || o_uppers->value()) if (U_tex && Pattern_Match(U_tex, pattern)) return true; if (!filter_toggle->value() || o_rails->value()) if (R_tex && Pattern_Match(R_tex, pattern, true /* is_rail */)) return true; } return false; } bool UI_FindAndReplace::Match_Sector(int idx) { const Sector *SEC = Sectors[idx]; if (! Filter_Tag(SEC->tag)) return false; const char *pattern = find_match->value(); if (!filter_toggle->value() || o_floors->value()) if (Pattern_Match(SEC->FloorTex(), pattern)) return true; const char *ceil_tex = SEC->CeilTex(); if (!filter_toggle->value() || (!is_sky(ceil_tex) && o_ceilings->value()) || ( is_sky(ceil_tex) && o_skies->value()) ) if (Pattern_Match(ceil_tex, pattern)) return true; return false; } bool UI_FindAndReplace::Match_LineType(int idx) { const LineDef *L = LineDefs[idx]; if (! find_numbers->get(L->type)) return false; if (! Filter_Tag(L->tag) || ! Filter_Sides(L)) return false; return true; } bool UI_FindAndReplace::Match_SectorType(int idx) { const Sector *SEC = Sectors[idx]; if (! find_numbers->get(SEC->type)) return false; if (! Filter_Tag(SEC->tag)) return false; return true; } bool UI_FindAndReplace::Filter_Tag(int tag) { if (! filter_toggle->value()) return true; // an empty string means everything (same as '*') if (tag_input->size() == 0) return true; return tag_numbers->get(tag); } bool UI_FindAndReplace::Filter_Sides(const LineDef *L) { if (filter_toggle->value()) { if (! o_one_sided->value() && L->OneSided()) return false; if (! o_two_sided->value() && L->TwoSided()) return false; } return true; } void UI_FindAndReplace::ComputeFlagMask() { options_mask = 0; options_value = 0; if (! filter_toggle->value()) { // this will always succeed return; } #define FLAG_FROM_WIDGET(w, mul, flag) \ if ((w)->value() != 0) \ { \ options_mask |= (flag); \ if ((w)->value() * (mul) > 0) \ options_value |= (flag); \ } FLAG_FROM_WIDGET( o_easy, 1, MTF_Easy); FLAG_FROM_WIDGET(o_medium, 1, MTF_Medium); FLAG_FROM_WIDGET( o_hard, 1, MTF_Hard); if (game_info.coop_dm_flags) { FLAG_FROM_WIDGET( o_sp, -1, MTF_Not_SP); FLAG_FROM_WIDGET(o_coop, -1, MTF_Not_COOP); FLAG_FROM_WIDGET( o_dm, -1, MTF_Not_DM); } else // vanilla DOOM { FLAG_FROM_WIDGET(o_dm, 1, MTF_Not_SP); } #undef FLAG_FROM_WIDGET } bool UI_FindAndReplace::Pattern_Match(const char *tex, const char *pattern, bool is_rail) { // allow multiple names (simple patterns) separated by commas. // they can include '*' as a wildcard. char local_pat[256]; int ofs = 0; for (;;) { if (*pattern == 0 || *pattern == ',' || *pattern == '/' || *pattern == '|') { local_pat[ofs] = 0; // do not match the empty rail texture against the "*" wildcard. // [ this is debatable, but I think this prevents making changes // which the user really didn't want or expect ] if (is_rail && tex[0] == '-' && local_pat[0] == '*') { // no match } else { if (fl_filename_match(tex, local_pat)) return true; } if (*pattern == 0) return false; // begin new part, skip comma ofs = 0; pattern++; } // prevent overflow of the local buffer if (ofs + 4 > (int)sizeof(local_pat)) return false; local_pat[ofs++] = *pattern++; } } //------------------------------------------------------------------------ // REPLACE METHODS //------------------------------------------------------------------------ void UI_FindAndReplace::Replace_Thing(int idx) { int new_type = atoi(rep_value->value()); BA_ChangeTH(idx, Thing::F_TYPE, new_type); } void UI_FindAndReplace::Replace_LineDef(int idx, int new_tex) { const LineDef *L = LineDefs[idx]; const char *pattern = find_match->value(); for (int pass = 0 ; pass < 2 ; pass++) { int sd_num = (pass == 0) ? L->right : L->left; const SideDef *SD = (pass == 0) ? L->Right() : L->Left(); if (! SD) continue; const char *L_tex = SD->LowerTex(); const char *U_tex = SD->UpperTex(); const char *R_tex = SD->MidTex(); if (! L->TwoSided()) { if (!filter_toggle->value() || o_lowers->value()) if (R_tex && Pattern_Match(R_tex, pattern)) BA_ChangeSD(sd_num, SideDef::F_MID_TEX, new_tex); continue; } if (!filter_toggle->value() || o_lowers->value()) if (L_tex && Pattern_Match(L_tex, pattern)) BA_ChangeSD(sd_num, SideDef::F_LOWER_TEX, new_tex); if (!filter_toggle->value() || o_uppers->value()) if (U_tex && Pattern_Match(U_tex, pattern)) BA_ChangeSD(sd_num, SideDef::F_UPPER_TEX, new_tex); if (!filter_toggle->value() || o_rails->value()) if (R_tex && Pattern_Match(R_tex, pattern, true /* is_rail */)) BA_ChangeSD(sd_num, SideDef::F_MID_TEX, new_tex); } } void UI_FindAndReplace::Replace_Sector(int idx, int new_tex) { const Sector *SEC = Sectors[idx]; const char *pattern = find_match->value(); if (!filter_toggle->value() || o_floors->value()) if (Pattern_Match(SEC->FloorTex(), pattern)) BA_ChangeSEC(idx, Sector::F_FLOOR_TEX, new_tex); const char *ceil_tex = SEC->CeilTex(); if (!filter_toggle->value() || (!is_sky(ceil_tex) && o_ceilings->value()) || ( is_sky(ceil_tex) && o_skies->value()) ) if (Pattern_Match(ceil_tex, pattern)) BA_ChangeSEC(idx, Sector::F_CEIL_TEX, new_tex); } void UI_FindAndReplace::Replace_LineType(int idx) { int new_type = atoi(rep_value->value()); BA_ChangeLD(idx, LineDef::F_TYPE, new_type); } void UI_FindAndReplace::Replace_SectorType(int idx) { int new_type = atoi(rep_value->value()); BA_ChangeSEC(idx, Sector::F_TYPE, new_type); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_replace.h0000644000175100017510000001064712651122324016544 0ustar aaptedaapted//------------------------------------------------------------------------ // FIND AND REPLACE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2015 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 __EUREKA_UI_REPLACE_H__ #define __EUREKA_UI_REPLACE_H__ class number_group_c; class UI_TripleCheckButton; class UI_FindAndReplace : public Fl_Group { private: // main thing we are finding / replacing Fl_Choice *what; // --- FIND AREA --- Fl_Input *find_match; Fl_Button *find_choose; Fl_Output *find_desc; Fl_Button *find_but; Fl_Button *select_all_but; // for numeric types, this contains the number(s) to match number_group_c *find_numbers; // --- REPLACE AREA --- Fl_Input *rep_value; Fl_Button *rep_choose; Fl_Output *rep_desc; Fl_Button *apply_but; Fl_Button *replace_all_but; // --- FILTER AREA --- Fl_Toggle_Button *filter_toggle; Fl_Group *filter_group; // common stuff Fl_Input * tag_input; number_group_c * tag_numbers; // thing stuff UI_TripleCheckButton *o_easy; UI_TripleCheckButton *o_medium; UI_TripleCheckButton *o_hard; UI_TripleCheckButton *o_sp; UI_TripleCheckButton *o_coop; UI_TripleCheckButton *o_dm; int options_mask; int options_value; // sector filters Fl_Check_Button *o_floors; Fl_Check_Button *o_ceilings; Fl_Check_Button *o_skies; // linedef filters Fl_Check_Button *o_lowers; Fl_Check_Button *o_uppers; Fl_Check_Button *o_rails; Fl_Check_Button *o_one_sided; Fl_Check_Button *o_two_sided; // current (found) object Objid cur_obj; public: UI_FindAndReplace(int X, int Y, int W, int H); virtual ~UI_FindAndReplace(); void Open(); char GetKind(); // same as browser : 'O' 'T' 'F' 'L' 'S' // called by "Find" button in here, or CTRL-G shortcut bool FindNext(); void BrowsedItem(char kind, int number, const char *name, int e_state); private: void Clear(); void ResetFilters(); bool WhatFromEditMode(); void UpdateWhatColor(); void UpdateWhatFilters(); void ComputeFlagMask(); void InsertName (Fl_Input *inp, char append, const char *name); void InsertNumber(Fl_Input *inp, char append, int number); bool NeedSeparator(Fl_Input *inp) const; void rawShowFilter(int value); bool MatchesObject(int idx); void ApplyReplace (int idx, int new_tex); void DoReplace(); void DoAll(bool replace); bool CheckInput(Fl_Input *w, Fl_Output *desc, number_group_c *num_grp = NULL); bool CheckNumberInput(Fl_Input *w, number_group_c *num_grp); bool Pattern_Match(const char *tex, const char *pattern, bool is_rail = false); // specialized functions for each search modality bool Match_Thing(int idx); bool Match_LineDef(int idx); bool Match_LineType(int idx); bool Match_Sector(int idx); bool Match_SectorType(int idx); // return 'true' for pass, 'false' to reject bool Filter_Tag(int tag); bool Filter_Sides(const LineDef *L); void Replace_Thing(int idx); void Replace_LineDef(int idx, int new_tex); void Replace_LineType(int idx); void Replace_Sector(int idx, int new_tex); void Replace_SectorType(int idx); private: static void hide_callback(Fl_Widget *w, void *data); static void what_kind_callback(Fl_Widget *w, void *data); static void find_match_callback(Fl_Widget *w, void *data); static void find_choose_callback(Fl_Widget *w, void *data); static void find_but_callback(Fl_Widget *w, void *data); static void select_all_callback(Fl_Widget *w, void *data); static void rep_value_callback(Fl_Widget *w, void *data); static void rep_choose_callback(Fl_Widget *w, void *data); static void apply_but_callback(Fl_Widget *w, void *data); static void replace_all_callback(Fl_Widget *w, void *data); static void filter_toggle_callback(Fl_Widget *w, void *data); static void tag_input_callback(Fl_Widget *w, void *data); }; #endif /* __EUREKA_UI_REPLACE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_canvas.h0000644000175100017510000001142512650305174016404 0ustar aaptedaapted//------------------------------------------------------------------------ // EDITING CANVAS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2008-2016 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 __EUREKA_UI_CANVAS_H__ #define __EUREKA_UI_CANVAS_H__ #include "editloop.h" #include "m_select.h" #include "objects.h" #include "r_grid.h" #include "x_mirror.h" class UI_Canvas : public Fl_Widget { private: Objid highlight; // split-able line state int split_ld; int split_x; int split_y; // sel-box state int selbox_x1, selbox_y1; // map coords int selbox_x2, selbox_y2; // dragging state int drag_start_x, drag_start_y; int drag_focus_x, drag_focus_y; int drag_cur_x, drag_cur_y; selection_c drag_lines; // scaling state int scale_start_x, scale_start_y; scale_param_t scale_param; selection_c scale_lines; // drawing state only int map_lx, map_ly; int map_hx, map_hy; bitvec_c seen_sectors; public: UI_Canvas(int X, int Y, int W, int H, const char *label = NULL); virtual ~UI_Canvas(); public: // FLTK virtual method for handling input events. int handle(int event); // FLTK virtual method for resizing. void resize(int X, int Y, int W, int H); void DrawEverything(); void HighlightSet(Objid& obj); void HighlightForget(); void SplitLineSet(int ld, int new_x, int new_y); void SplitLineForget(); void DrawSelection(selection_c *list); void DrawHighlight(int objtype, int objnum, Fl_Color col, bool do_tagged=true, bool skip_lines = false, int dx=0, int dy=0); void DrawHighlightScaled(int objtype, int objnum, Fl_Color col); void SelboxBegin(int map_x, int map_y); void SelboxUpdate(int map_x, int map_y); void SelboxFinish(int *x1, int *y1, int *x2, int *y2); void DragBegin(int focus_x, int focus_y, int map_x, int map_y); void DragUpdate(int map_x, int map_y); void DragFinish(int *dx, int *dy); void ScaleBegin(int map_x, int map_y, int middle_x, int middle_y); void ScaleUpdate(int map_x, int map_y, keycode_t mod); void ScaleFinish(scale_param_t& param); void PointerPos(int *map_x, int *map_y); // return -1 if too small, 0 is OK, 1 is too big to fit int ApproxBoxSize(int mx1, int my1, int mx2, int my2); private: // FLTK virtual method for drawing void draw(); void DrawMap(); void DrawGrid_Dotty(); void DrawGrid_Normal(); void DrawAxes(Fl_Color col); void DrawMapBounds(); void DrawVertices(); void DrawLinedefs(); void DrawThings(); void DrawThingBodies(); void DrawMapPoint(int map_x, int map_y); void DrawMapLine(int map_x1, int map_y1, int map_x2, int map_y2); void DrawMapVector(int map_x1, int map_y1, int map_x2, int map_y2); void DrawMapArrow(int map_x1, int map_y1, int r, int angle); void DrawKnobbyLine(int map_x1, int map_y1, int map_x2, int map_y2, bool reverse = false); void DrawSplitLine(int map_x1, int map_y1, int map_x2, int map_y2); void DrawVertex(int map_x, int map_y, int r); void DrawThing(int map_x, int map_y, int r, int angle, bool big_arrow); void DrawCamera(); void DrawLineNumber(int mx1, int my1, int mx2, int my2, int side, int n); void DrawSectorNum(int mx1, int my1, int mx2, int my2, int side, int n); void DrawObjNum(int x, int y, int num, bool center = false); void DrawCurrentLine(); void RenderSector(int num); void SelboxDraw(); void DragDelta(int *dx, int *dy); // convert screen coordinates to map coordinates inline int MAPX(int sx) const { return I_ROUND(grid.orig_x + (sx - w()/2 - x()) / grid.Scale); } inline int MAPY(int sy) const { return I_ROUND(grid.orig_y + (h()/2 - sy + y()) / grid.Scale); } // convert map coordinates to screen coordinates inline int SCREENX(int mx) const { return (x() + w()/2 + I_ROUND((mx - grid.orig_x) * grid.Scale)); } inline int SCREENY(int my) const { return (y() + h()/2 + I_ROUND((grid.orig_y - my) * grid.Scale)); } inline bool Vis(int x, int y, int r) const { return (x+r >= map_lx) && (x-r <= map_hx) && (y+r >= map_ly) && (y-r <= map_hy); } inline bool Vis(int x1, int y1, int x2, int y2) const { return (x2 >= map_lx) && (x1 <= map_hx) && (y2 >= map_ly) && (y1 <= map_hy); } }; #endif /* __EUREKA_UI_CANVAS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_infobar.cc0000644000175100017510000001510012647614427016713 0ustar aaptedaapted//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 "main.h" #include "ui_window.h" #include "editloop.h" #include "r_grid.h" #define SNAP_COLOR fl_rgb_color(255, 128, 128) #define FREE_COLOR fl_rgb_color(128, 255, 128) // // UI_InfoBar Constructor // UI_InfoBar::UI_InfoBar(int X, int Y, int W, int H, const char *label) : Fl_Group(X, Y, W, H, label) { box(FL_FLAT_BOX); // Fitts' law : keep buttons flush with bottom of window Y += 4; H -= 4; mode = new Fl_Choice(X+58, Y, 88, H, "Mode:"); mode->align(FL_ALIGN_LEFT); mode->add("Things|Linedefs|Sectors|Vertices"); mode->value(0); mode->callback(mode_callback, this); mode->labelsize(KF_fonth); mode->textsize(KF_fonth - 2); X = mode->x() + mode->w() + 10; scale = new Fl_Choice(X+52, Y, 78, H, "Scale:"); scale->align(FL_ALIGN_LEFT); scale->add(Grid_State_c::scale_options()); scale->value(8); scale->callback(scale_callback, this); scale->labelsize(KF_fonth); scale->textsize(KF_fonth); X = scale->x() + scale->w() + 10; grid_size = new Fl_Choice(X+44, Y, 72, H, "Grid:"); grid_size->align(FL_ALIGN_LEFT); grid_size->add(Grid_State_c::grid_options()); grid_size->value(1); grid_size->callback(grid_callback, this); grid_size->labelsize(KF_fonth); grid_size->textsize(KF_fonth); X = grid_size->x() + grid_size->w() + 10; grid_snap = new Fl_Toggle_Button(X+4, Y, 72, H); grid_snap->value(grid.snap ? 1 : 0); grid_snap->color(FREE_COLOR); grid_snap->selection_color(SNAP_COLOR); grid_snap->callback(snap_callback, this); grid_snap->labelsize(KF_fonth); UpdateSnapText(); X = grid_snap->x() + grid_snap->w() + 4; mouse_x = new Fl_Output(X+28, Y, 64, H, "x"); mouse_y = new Fl_Output(X+28+72+10, Y, 64, H, "y"); mouse_x->align(FL_ALIGN_LEFT); mouse_y->align(FL_ALIGN_LEFT); mouse_x->labelsize(KF_fonth); mouse_y->labelsize(KF_fonth); mouse_x->textsize(KF_fonth); mouse_y->textsize(KF_fonth); X = mouse_y->x() + mouse_y->w() + 10; Fl_Box *div = new Fl_Box(FL_FLAT_BOX, X, Y-4, 3, H+4, NULL); div->color(WINDOW_BG, WINDOW_BG); X += 6; status = new Fl_Box(FL_FLAT_BOX, X, Y-4, W - 4 - X, H+4, "Ready"); status->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_CLIP); status->labelfont(FL_HELVETICA_BOLD); // ---- resizable ---- resizable(status); end(); } // // UI_InfoBar Destructor // UI_InfoBar::~UI_InfoBar() { } int UI_InfoBar::handle(int event) { return Fl_Group::handle(event); } void UI_InfoBar::mode_callback(Fl_Widget *w, void *data) { Fl_Choice *mode = (Fl_Choice *)w; static const char *mode_keys = "tlsvr"; Editor_ChangeMode(mode_keys[mode->value()]); } void UI_InfoBar::scale_callback(Fl_Widget *w, void *data) { Fl_Choice *choice = (Fl_Choice *)w; grid.ScaleFromWidget(choice->value()); } void UI_InfoBar::grid_callback(Fl_Widget *w, void *data) { Fl_Choice *choice = (Fl_Choice *)w; grid.StepFromWidget(choice->value()); } void UI_InfoBar::snap_callback(Fl_Widget *w, void *data) { Fl_Toggle_Button *grid_snap = (Fl_Toggle_Button *)w; // update editor state grid.SetSnap(grid_snap->value() ? true : false); } //------------------------------------------------------------------------ void UI_InfoBar::NewEditMode(obj_type_e new_mode) { switch (new_mode) { case OBJ_THINGS: mode->value(0); break; case OBJ_LINEDEFS: mode->value(1); break; case OBJ_SECTORS: mode->value(2); break; case OBJ_VERTICES: mode->value(3); break; default: break; } UpdateModeColor(); } void UI_InfoBar::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, "%d", I_ROUND(mx)); sprintf(y_buffer, "%d", I_ROUND(my)); mouse_x->value(x_buffer); mouse_y->value(y_buffer); } void UI_InfoBar::SetStatus(const char *str) { status->copy_label(str); if (!str || !str[0]) status->tooltip(NULL); else status->copy_tooltip(str); } void UI_InfoBar::SetScale(int i) { scale->value(i); } void UI_InfoBar::SetGrid(int i) { grid_size->value(i); } #if 0 void UI_InfoBar::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 UI_InfoBar::SetNodeIndex(int index) { #if 0 char buffer[60]; sprintf(buffer, "%d", index); ns_index->label("Node #"); ns_index->value(buffer); redraw(); #endif } void UI_InfoBar::SetWhich(int index, int total) { if (index < 0) { which->label(INDEX_NONE_STR); } else { char buffer[200]; sprintf(buffer, "Index: #%d of %d", index, total); which->copy_label(buffer); } redraw(); } #endif void UI_InfoBar::UpdateSnap() { grid_snap->value(grid.snap ? 1 : 0); UpdateSnapText(); } void UI_InfoBar::UpdateModeColor() { switch (mode->value()) { case 0: /* Things */ mode->color(FL_MAGENTA); break; case 1: /* Linedefs */ mode->color(fl_rgb_color(0,128,255)); break; case 2: /* Sectors */ mode->color(FL_YELLOW); break; case 3: /* Vertices */ mode->color(fl_rgb_color(0,192,96)); break; } } void UI_InfoBar::UpdateSnapText() { if (grid_snap->value()) { grid_snap->label("SNAP"); } else { grid_snap->label("Free"); } grid_snap->redraw(); } void Status_Set(const char *fmt, ...) { if (! main_win) return; va_list arg_ptr; static char buffer[MSG_BUF_LEN]; va_start(arg_ptr, fmt); vsnprintf(buffer, MSG_BUF_LEN-1, fmt, arg_ptr); va_end(arg_ptr); buffer[MSG_BUF_LEN-1] = 0; main_win->info_bar->SetStatus(buffer); } void Status_Clear() { if (! main_win) return; main_win->info_bar->SetStatus(""); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_scroll.cc0000644000175100017510000002017212647061302016562 0ustar aaptedaapted//------------------------------------------------------------------------ // A decent scrolling widget //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2013 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 "main.h" #include "m_config.h" #include "levels.h" #include "ui_scroll.h" #include "ui_canvas.h" #include "r_render.h" #define HUGE_DIST (1 << 24) #define SCRBAR_BACK (gui_scheme == 2 ? FL_DARK3 : FL_DARK2) #define SCRBAR_COL (gui_scheme == 2 ? FL_DARK1 : FL_BACKGROUND_COLOR) // // UI_Scroll Constructor // UI_Scroll::UI_Scroll(int X, int Y, int W, int H) : Fl_Group(X, Y, W, H, NULL), resize_horiz_(false), top_y(0), bottom_y(0) { end(); scrollbar = new Fl_Scrollbar(X, Y, SBAR_W, H, NULL); scrollbar->align(FL_ALIGN_LEFT); scrollbar->color(SCRBAR_BACK, SCRBAR_BACK); scrollbar->selection_color(SCRBAR_COL); scrollbar->callback(bar_callback, this); add(scrollbar); clip_children(1); resizable(NULL); } // // UI_Scroll Destructor // UI_Scroll::~UI_Scroll() { } void UI_Scroll::resize(int X, int Y, int W, int H) { // int ox = x(); // int oy = y(); // int oh = h(); int ow = w(); Fl_Group::resize(X, Y, W, H); scrollbar->resize(X, Y, SBAR_W, H); int total_h = bottom_y - top_y; scrollbar->value(0, h(), 0, MAX(h(), total_h)); if (ow != W && resize_horiz_) { for (int i = 0 ; i < Children() ; i++) { Fl_Widget * w = Child(i); w->resize(X + SBAR_W, w->y(), W - SBAR_W, w->h()); } } } int UI_Scroll::handle(int event) { return Fl_Group::handle(event); } void UI_Scroll::bar_callback(Fl_Widget *w, void *data) { UI_Scroll * that = (UI_Scroll *)data; that->do_scroll(); } void UI_Scroll::do_scroll() { int pos = scrollbar->value(); int total_h = bottom_y - top_y; scrollbar->value(pos, h(), 0, MAX(h(), total_h)); reposition_all(y() - pos); redraw(); } void UI_Scroll::calc_extents() { if (Children() == 0) { top_y = bottom_y = 0; return; } top_y = HUGE_DIST; bottom_y = -HUGE_DIST; for (int i = 0 ; i < Children() ; i++) { Fl_Widget * w = Child(i); if (! w->visible()) continue; top_y = MIN(top_y, w->y()); bottom_y = MAX(bottom_y, w->y() + w->h()); } } void UI_Scroll::reposition_all(int start_y) { for (int i = 0 ; i < Children() ; i++) { Fl_Widget * w = Child(i); int y = start_y + (w->y() - top_y); w->position(w->x(), y); } calc_extents(); init_sizes(); } void UI_Scroll::Scroll(int delta) { int pixels; int line_size = scrollbar->linesize(); if (abs(delta) <= 1) pixels = MAX(1, line_size / 4); else if (abs(delta) == 2) pixels = line_size; else if (abs(delta) == 3) pixels = MAX(h() - line_size / 2, h() * 2 / 3); else pixels = HUGE_DIST; if (delta < 0) pixels = -pixels; int pos = scrollbar->value() + pixels; int total_h = bottom_y - top_y; if (pos > total_h - h()) pos = total_h - h(); if (pos < 0) pos = 0; scrollbar->value(pos, h(), 0, MAX(h(), total_h)); reposition_all(y() - pos); redraw(); } //------------------------------------------------------------------------ // // PASS-THROUGHS // void UI_Scroll::Add(Fl_Widget *w) { add(w); } void UI_Scroll::Remove(Fl_Widget *w) { remove(w); } void UI_Scroll::Remove_first() { // skip scrollbar remove(1); } void UI_Scroll::Remove_all() { remove(scrollbar); clear(); resizable(NULL); add(scrollbar); } int UI_Scroll::Children() const { // ignore scrollbar return children() - 1; } Fl_Widget * UI_Scroll::Child(int i) const { SYS_ASSERT(child(0) == scrollbar); // skip scrollbar return child(1 + i); } void UI_Scroll::Init_sizes() { calc_extents(); init_sizes(); int total_h = bottom_y - top_y; scrollbar->value(0, h(), 0, MAX(h(), total_h)); } void UI_Scroll::Line_size(int pixels) { scrollbar->linesize(pixels); } //------------------------------------------------------------------------ UI_CanvasScroll::UI_CanvasScroll(int X, int Y, int W, int H) : Fl_Group(X, Y, W, H), enable_bars(true), bound_x1(0), bound_x2(100), bound_y1(0), bound_y2(100) { for (int i = 0 ; i < 4 ; i++) last_bounds[i] = 12345678; box(FL_NO_BOX); vert = new Fl_Scrollbar(X, Y, SBAR_W, H - SBAR_W, NULL); vert->type(FL_VERTICAL); vert->align(FL_ALIGN_LEFT); vert->color(SCRBAR_BACK, SCRBAR_BACK); vert->selection_color(SCRBAR_COL); vert->callback(bar_callback, this); horiz = new Fl_Scrollbar(X + SBAR_W, Y + H - SBAR_W, W - SBAR_W, SBAR_W, NULL); horiz->type(FL_HORIZONTAL); horiz->align(FL_ALIGN_LEFT); horiz->color(SCRBAR_BACK, SCRBAR_BACK); horiz->selection_color(SCRBAR_COL); horiz->callback(bar_callback, this); canvas = new UI_Canvas(X + SBAR_W, Y, W - SBAR_W, H - SBAR_W); resizable(canvas); render = new UI_Render3D(X, Y, W, H); render->hide(); } UI_CanvasScroll::~UI_CanvasScroll() { } void UI_CanvasScroll::UpdateRenderMode() { int old_3d = render->visible() ? 1 : 0; int new_3d = edit.render3d ? 1 : 0; int old_bars = enable_bars ? 1 : 0; int new_bars = map_scroll_bars ? 1 : 0; // nothing changed? if (old_3d == new_3d && old_bars == new_bars) return; if (old_bars != new_bars) { int b = new_bars ? SBAR_W : 0; canvas->resize(x() + b, y(), w() - b, h() - b); init_sizes(); enable_bars = map_scroll_bars; } if (edit.render3d) { render->show(); canvas->hide(); } else { canvas->show(); render->hide(); } if (edit.render3d || ! enable_bars) { vert->hide(); horiz->hide(); } else { vert->show(); horiz->show(); } } void UI_CanvasScroll::UpdateBounds() { UpdateBounds_X(); UpdateBounds_Y(); } void UI_CanvasScroll::UpdateBounds_X() { if (last_bounds[0] == Map_bound_x1 && last_bounds[1] == Map_bound_x2) { return; } last_bounds[0] = Map_bound_x1; last_bounds[1] = Map_bound_x2; int expand = 512 + (Map_bound_x2 - Map_bound_x1) / 8; bound_x1 = Map_bound_x1 - expand; bound_x2 = Map_bound_x2 + expand; Adjust_X(); } void UI_CanvasScroll::UpdateBounds_Y() { if (last_bounds[2] == Map_bound_y1 && last_bounds[3] == Map_bound_y2) { return; } last_bounds[2] = Map_bound_y1; last_bounds[3] = Map_bound_y2; int expand = 512 + (Map_bound_y2 - Map_bound_y1) / 8; bound_y1 = Map_bound_y1 - expand; bound_y2 = Map_bound_y2 + expand; Adjust_Y(); } void UI_CanvasScroll::AdjustPos() { Adjust_X(); Adjust_Y(); } void UI_CanvasScroll::Adjust_X() { int cw = canvas->w(); int map_w = I_ROUND(cw / grid.Scale); int map_x = grid.orig_x - map_w / 2; if (map_x > bound_x2 - map_w) map_x = bound_x2 - map_w; if (map_x < bound_x1) map_x = bound_x1; horiz->value(map_x, map_w, bound_x1, bound_x2 - bound_x1); } void UI_CanvasScroll::Adjust_Y() { int ch = canvas->h(); int map_h = I_ROUND(ch / grid.Scale); int map_y = grid.orig_y - map_h / 2; // invert, since screen coords are the reverse of map coords map_y = bound_y2 - map_h - (map_y - bound_y1); if (map_y > bound_y2 - map_h) map_y = bound_y2 - map_h; if (map_y < bound_y1) map_y = bound_y1; vert->value(map_y, map_h, bound_y1, bound_y2 - bound_y1); } void UI_CanvasScroll::Scroll_X() { int pos = horiz->value(); double map_w = canvas->w() / grid.Scale; double new_x = pos + map_w / 2.0; grid.MoveTo(new_x, grid.orig_y); } void UI_CanvasScroll::Scroll_Y() { int pos = vert->value(); double map_h = canvas->h() / grid.Scale; double new_y = bound_y2 - map_h / 2.0 - (pos - bound_y1); grid.MoveTo(grid.orig_x, new_y); } void UI_CanvasScroll::bar_callback(Fl_Widget *w, void *data) { UI_CanvasScroll * that = (UI_CanvasScroll *)data; if (w == that->horiz) that->Scroll_X(); if (w == that->vert) that->Scroll_Y(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_about.h0000644000175100017510000000175612647061302016247 0ustar aaptedaapted//------------------------------------------------------------------------ // ABOUT WINDOW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2011 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 __EUREKA_UI_ABOUT_H__ #define __EUREKA_UI_ABOUT_H__ void DLG_AboutText(void); #endif /* __EUREKA_UI_ABOUT_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/sys_debug.cc0000644000175100017510000000635112647061302016556 0ustar aaptedaapted//------------------------------------------------------------------------ // Debugging support //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2013 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 "main.h" bool Quiet = false; bool Debugging = false; static FILE * log_fp; // need to keep an in-memory copy of logs until the log viewer is open static bool log_window_open; static std::vector kept_messages; // hack here to avoid bringing in ui_window.h and FLTK headers extern void LogViewer_AddLine(const char *str); void LogOpenFile(const char *filename) { log_fp = fopen(filename, "w+"); if (! log_fp) FatalError("Cannot open log file: %s\n", filename); fprintf(log_fp, "======= START OF LOGS =======\n\n"); // add all messages saved so far for (unsigned int i = 0 ; i < kept_messages.size() ; i++) fputs(kept_messages[i], log_fp); } void LogOpenWindow() { log_window_open = true; // retrieve all messages saved so far for (unsigned int i = 0 ; i < kept_messages.size() ; i++) LogViewer_AddLine(kept_messages[i]); } void LogClose() { if (log_fp) { fprintf(log_fp, "\n\n======== END OF LOGS ========\n"); fclose(log_fp); log_fp = NULL; } log_window_open = false; } void LogPrintf(const char *str, ...) { static char buffer[MSG_BUF_LEN]; va_list args; va_start(args, str); vsnprintf(buffer, MSG_BUF_LEN, str, args); va_end(args); buffer[MSG_BUF_LEN-1] = 0; if (log_fp) { fputs(buffer, log_fp); fflush(log_fp); } if (log_window_open) LogViewer_AddLine(buffer); else kept_messages.push_back(StringDup(buffer)); if (! Quiet) { fputs(buffer, stdout); fflush(stdout); } } void DebugPrintf(const char *str, ...) { if (Debugging && log_fp) { static char buffer[MSG_BUF_LEN]; va_list args; va_start(args, str); vsnprintf(buffer, MSG_BUF_LEN-1, str, args); va_end(args); buffer[MSG_BUF_LEN-2] = 0; // prefix each debugging line with a special symbol char *pos = buffer; char *next; while (pos && *pos) { next = strchr(pos, '\n'); if (next) *next++ = 0; fprintf(log_fp, "# %s\n", pos); fflush(log_fp); if (! Quiet) { fprintf(stderr, "# %s\n", pos); } pos = next; } } } void LogSaveTo(FILE *dest_fp) { byte buffer[256]; if (! log_fp) { fprintf(dest_fp, "No logs.\n"); return; } // copy the log file rewind(log_fp); while (true) { size_t rlen = fread(buffer, 1, sizeof(buffer), log_fp); if (rlen <= 0) break; fwrite(buffer, 1, rlen, dest_fp); } // restore write position for the log file fseek(log_fp, 0L, SEEK_END); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_vertex.h0000644000175100017510000000310212647061302016435 0ustar aaptedaapted//------------------------------------------------------------------------ // VERTEX PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2015 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 __EUREKA_UI_VERTEX_H__ #define __EUREKA_UI_VERTEX_H__ class UI_VertexBox : public Fl_Group { private: int obj; int count; public: UI_Nombre *which; Fl_Int_Input *pos_x; Fl_Int_Input *pos_y; public: UI_VertexBox(int X, int Y, int W, int H, const char *label = NULL); virtual ~UI_VertexBox(); public: int handle(int event); // FLTK virtual method for handling input events. public: void SetObj(int _index, int _count); int GetObj() const { return obj; } // call this if the vertex was externally changed. void UpdateField(); void UpdateTotal(); private: static void x_callback(Fl_Widget *, void *); static void y_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_VERTEX_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/x_hover.h0000644000175100017510000000432012650361331016077 0ustar aaptedaapted//------------------------------------------------------------------------ // HIGHLIGHT HELPER //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_X_HOVER_H__ #define __EUREKA_X_HOVER_H__ class Objid; void GetNearObject(Objid& o, obj_type_e objtype, int x, int y); void GetSplitLineDef(Objid& o, int x, int y, int drag_vert = -1); void GetSplitLineForDangler(Objid& o, int v_num); float ApproxDistToLineDef(const LineDef * L, int x, int y); int ClosestLine_CastingHoriz(int x, int y, int *side); int ClosestLine_CastingVert (int x, int y, int *side); int ClosestLine_CastAtAngle (int x, int y, float radians); int OppositeLineDef(int ld, int ld_side, int *result_side); int OppositeSector(int ld, int ld_side); void FastOpposite_Begin(); void FastOpposite_Finish(); bool PointOutsideOfMap(int x, int y); // result: -1 for back, +1 for front, 0 for _exactly_on_ the line int PointOnLineSide(int x, int y, int lx1, int ly1, int lx2, int ly2); typedef struct { int vert; // >= 0 when we hit a vertex int line; // >= 0 when we hit a linedef instead int x, y; // coordinate of line split point } cross_state_t; bool FindClosestCrossPoint(int v1, int v2, cross_state_t *cross); #endif /* __EUREKA_X_HOVER_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/w_flats.h0000644000175100017510000000252612647061302016073 0ustar aaptedaapted//------------------------------------------------------------------------ // FLAT LOADING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_W_FLATS_H__ #define __EUREKA_W_FLATS_H__ #include "im_img.h" void W_LoadFlats(); bool W_FlatExists(const char *name); Img_c * W_GetFlat(const char *name); #endif /* __EUREKA_W_FLATS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_bitvec.h0000644000175100017510000000465712647061302016233 0ustar aaptedaapted//------------------------------------------------------------------------ // BIT VECTORS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2015 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_BITVEC_H__ #define __EUREKA_M_BITVEC_H__ typedef enum { BOP_ADD = 0, // Add to selection BOP_REMOVE, // Remove from selection BOP_TOGGLE // If not in selection, add it, else remove it } sel_op_e; class bitvec_c { // // Although this bit-vector has a current size, it acts as though it // was infinitely sized and all bits past the end are zero. When // setting a bit past the end, it will automatically resize itself. // private: int num_elem; byte *d; public: bitvec_c(int n_elements = 64); ~bitvec_c(); inline int size() const { return num_elem; } // this preserves existing elements void resize(int n_elements); bool get(int n) const; // Get bit void set(int n); // Set bit to 1 void clear(int n); // Set bit to 0 void toggle(int n); // Toggle bit void frob(int n, sel_op_e op); void set_all(); void clear_all(); void toggle_all(); private: /* NOTE : these functions do no range checking! */ inline bool raw_get(int n) const { return (d[n >> 3] & (1 << (n & 7))) ? true : false; } inline void raw_set(int n) { d[n >> 3] |= (1 << (n & 7)); } inline void raw_clear(int n) { d[n >> 3] &= ~(1 << (n & 7)); } inline void raw_toggle(int n) { d[n >> 3] ^= (1 << (n & 7)); } }; #endif /* __EUREKA_M_BITVEC_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/w_rawdef.h0000644000175100017510000002065412650264111016231 0ustar aaptedaapted//------------------------------------------------------------------------ // RAWDEF : Doom structures, raw on-disk layout //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 __EUREKA_W_RAWDEF_H__ #define __EUREKA_W_RAWDEF_H__ /* ----- The wad structures ---------------------- */ #define WAD_TEX_NAME 8 #define WAD_FLAT_NAME 8 // wad header typedef struct raw_wad_header_s { char ident[4]; u32_t num_entries; u32_t dir_start; } PACKEDATTR raw_wad_header_t; // directory entry typedef struct raw_wad_entry_s { u32_t pos; u32_t size; char name[8]; } PACKEDATTR raw_wad_entry_t; // Lump order in a map WAD: each map needs a couple of lumps // to provide a complete scene geometry description. typedef enum { LL_LABEL=0, // A separator name, ExMx or MAPxx LL_THINGS, // Monsters, items.. LL_LINEDEFS, // LineDefs, from editing LL_SIDEDEFS, // SideDefs, from editing LL_VERTEXES, // Vertices, edited and BSP splits generated LL_SEGS, // LineSegs, from LineDefs split by BSP LL_SSECTORS, // SubSectors, list of LineSegs LL_NODES, // BSP nodes LL_SECTORS, // Sectors, from editing LL_REJECT, // LUT, sector-sector visibility LL_BLOCKMAP, // LUT, motion clipping, walls/grid element LL_BEHAVIOR // Hexen scripting stuff } lump_order_e; /* ----- The level structures ---------------------- */ typedef struct raw_vertex_s { s16_t x, y; } PACKEDATTR raw_vertex_t; typedef struct raw_v2_vertex_s { s32_t x, y; } PACKEDATTR raw_v2_vertex_t; typedef struct raw_linedef_s { u16_t start; // from this vertex... u16_t end; // ... to this vertex u16_t flags; // linedef flags (impassible, etc) u16_t type; // special type (0 for none, 97 for teleporter, etc) s16_t tag; // this linedef activates the sector with same tag u16_t right; // right sidedef u16_t left; // left sidedef (only if this line adjoins 2 sectors) } PACKEDATTR raw_linedef_t; typedef struct raw_hexen_linedef_s { u16_t start; // from this vertex... u16_t end; // ... to this vertex u16_t flags; // linedef flags (impassible, etc) u8_t type; // special type u8_t args[5]; // special arguments u16_t right; // right sidedef u16_t left; // left sidedef } PACKEDATTR raw_hexen_linedef_t; typedef struct raw_sidedef_s { s16_t x_offset; // X offset for texture s16_t 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 u16_t sector; // adjacent sector } PACKEDATTR raw_sidedef_t; typedef struct raw_sector_s { s16_t floorh; // floor height s16_t ceilh; // ceiling height char floor_tex[8]; // floor texture char ceil_tex[8]; // ceiling texture u16_t light; // light level (0-255) u16_t type; // special type (0 = normal, 9 = secret, ...) s16_t tag; // sector activated by a linedef with same tag } PACKEDATTR raw_sector_t; typedef struct raw_thing_s { s16_t x, y; // position of thing s16_t angle; // angle thing faces (degrees) u16_t type; // type of thing u16_t options; // when appears, deaf, etc.. } PACKEDATTR raw_thing_t; // -JL- Hexen thing definition typedef struct raw_hexen_thing_s { s16_t tid; // tag id (for scripts/specials) s16_t x, y; // position s16_t height; // start height above floor s16_t angle; // angle thing faces u16_t type; // type of thing u16_t options; // when appears, deaf, dormant, etc.. u8_t special; // special type u8_t args[5]; // special arguments } PACKEDATTR raw_hexen_thing_t; /* ----- Graphical structures ---------------------- */ typedef struct { s16_t x_origin; s16_t y_origin; u16_t pname; // index into PNAMES u16_t stepdir; // NOT USED u16_t colormap; // NOT USED } PACKEDATTR raw_patchdef_t; // Texture definition. // // Each texture is composed of one or more patches, // with patches being lumps stored in the WAD. // typedef struct { char name[8]; u32_t masked; // NOT USED u16_t width; u16_t height; u32_t column_dir; // NOT USED u16_t patch_count; raw_patchdef_t patches[1]; } PACKEDATTR raw_texture_t; // Patches. // // A patch holds one or more columns. // Patches are used for sprites and all masked pictures, // and we compose textures from the TEXTURE1/2 lists // of patches. // typedef struct patch_s { // bounding box size s16_t width; s16_t height; // pixels to the left of origin s16_t leftoffset; // pixels below the origin s16_t topoffset; u32_t columnofs[1]; // only [width] used } PACKEDATTR patch_t; // // LineDef attributes. // typedef enum { // solid, is an obstacle MLF_Blocking = 0x0001, // blocks monsters only MLF_BlockMonsters = 0x0002, // backside will not be present at all if not two sided MLF_TwoSided = 0x0004, // If a texture is pegged, the texture will have // the end exposed to air held constant at the // top or bottom of the texture (stairs or pulled // down things) and will move with a height change // of one of the neighbor sectors. // // Unpegged textures allways have the first row of // the texture at the top pixel of the line for both // top and bottom textures (use next to windows). // upper texture unpegged MLF_UpperUnpegged = 0x0008, // lower texture unpegged MLF_LowerUnpegged = 0x0010, // in AutoMap: don't map as two sided: IT'S A SECRET! MLF_Secret = 0x0020, // sound rendering: don't let sound cross two of these MLF_SoundBlock = 0x0040, // don't draw on the automap at all MLF_DontDraw = 0x0080, // set as if already seen, thus drawn in automap MLF_Mapped = 0x0100, // -AJA- this one is from Boom. Allows multiple lines to // be pushed simultaneously. MLF_Boom_PassThru = 0x0200, } lineflag_e; typedef enum { MLF_Eternity_3DMidTex = 0x0400, } eternity_lineflag_e; typedef enum { // -AJA- these three are from XDoom MLF_XDoom_Translucent = 0x0400, MLF_XDoom_ShootBlock = 0x0800, MLF_XDoom_SightBlock = 0x1000, } xdoom_lineflag_e; typedef enum { // flags 0x001 .. 0x200 are same as DOOM above MLF_Repeatable = 0x0200, MLF_Activation = 0x1c00, } hexen_lineflag_e; typedef enum { // these are supported by ZDoom (and derived ports) MLF_ZDoom_MonCanActivate = 0x2000, MLF_ZDoom_BlockPlayers = 0x4000, MLF_ZDoom_BlockEverything = 0x8000, } zdoom_lineflag_e; #define BOOM_GENLINE_FIRST 0x2f80 #define BOOM_GENLINE_LAST 0x7fff #define is_genline(tp) ((tp) >= BOOM_GENLINE_FIRST && (tp) <= BOOM_GENLINE_LAST) typedef enum { SPAC_Cross = 0, // when line is crossed (W1 / WR) SPAC_Use = 1, // when line is used (S1 / SR) SPAC_Monster = 2, // when monster walks over line SPAC_Impact = 3, // when bullet/projectile hits line (G1 / GR) SPAC_Push = 4, // when line is bumped (player is stopped) SPAC_PCross = 5, // when projectile crosses the line } hexen_activation_e; // // Sector attributes. // typedef enum { BoomSF_TypeMask = 0x001F, BoomSF_DamageMask = 0x0060, BoomSF_Secret = 0x0080, BoomSF_Friction = 0x0100, BoomSF_Wind = 0x0200, BoomSF_NoSounds = 0x0400, BoomSF_QuietPlane = 0x0800 } boom_sectorflag_e; #define MSF_BoomFlags 0x0FE0 // // Thing attributes. // typedef enum { // these four used in Hexen too MTF_Easy = 1, MTF_Medium = 2, MTF_Hard = 4, MTF_Ambush = 8, MTF_Not_SP = 16, MTF_Not_DM = 32, MTF_Not_COOP = 64, MTF_Friend = 128, MTF_Reserved = 256, } thing_option_e; #define MTF_EXFLOOR_MASK 0x3C00 #define MTF_EXFLOOR_SHIFT 10 typedef enum { MTF_Hexen_Dormant = 16, MTF_Hexen_Fighter = 32, MTF_Hexen_Cleric = 64, MTF_Hexen_Mage = 128, MTF_Hexen_SP = 256, MTF_Hexen_COOP = 512, MTF_Hexen_DM = 1024, } hexen_option_e; #endif /* __EUREKA_W_RAWDEF_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/hdr_fltk.h0000644000175100017510000000411712647061302016227 0ustar aaptedaapted//------------------------------------------------------------------------ // FLTK INCLUDES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2008 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 __EUREKA_HDR_FLTK__ #define __EUREKA_HDR_FLTK__ /* FLTK - Widget Library */ #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 #include #include #include #include #include #include #include #include #include #include #include #endif /* __EUREKA_HDR_FLTK__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_thing.h0000644000175100017510000000575312647061302016247 0ustar aaptedaapted//------------------------------------------------------------------------ // THING PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2015 Andrew Apted // Copyright (C) 2015 Ioan Chera // // 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 __EUREKA_UI_THING_H__ #define __EUREKA_UI_THING_H__ class Sticker; class UI_ThingBox : public Fl_Group { private: int obj; int count; UI_Nombre *which; Fl_Int_Input *type; Fl_Output *desc; Fl_Button *choose; Fl_Int_Input *angle; Fl_Button *ang_buts[8]; Fl_Int_Input *tid; Fl_Int_Input *exfloor; Fl_Button *efl_down; Fl_Button *efl_up; Fl_Int_Input *pos_x; Fl_Int_Input *pos_y; Fl_Int_Input *pos_z; // Options Fl_Check_Button *o_easy; Fl_Check_Button *o_medium; Fl_Check_Button *o_hard; Fl_Check_Button *o_sp; Fl_Check_Button *o_coop; Fl_Check_Button *o_dm; Fl_Check_Button *o_vanilla_dm; Fl_Check_Button *o_fight; // Fl_Check_Button *o_cleric; // Hexen Fl_Check_Button *o_mage; // Fl_Check_Button *o_ambush; Fl_Check_Button *o_friend; // Boom / MBF Fl_Check_Button *o_dormant; // Hexen UI_Pic *sprite; // more Hexen stuff Fl_Int_Input *spec_type; Fl_Button *spec_choose; Fl_Output *spec_desc; Fl_Int_Input *args[5]; public: UI_ThingBox(int X, int Y, int W, int H, const char *label = NULL); virtual ~UI_ThingBox(); public: void SetObj(int _index, int _count); int GetObj() const { return obj; } // call this if the thing was externally changed. // -1 means "all fields" void UpdateField(int field = -1); void UpdateTotal(); void SetThingType(int new_type); void SetSpecialType(int new_type); void UpdateGameInfo(); private: static void x_callback(Fl_Widget *w, void *data); static void y_callback(Fl_Widget *w, void *data); static void z_callback(Fl_Widget *w, void *data); static void type_callback(Fl_Widget *w, void *data); static void angle_callback(Fl_Widget *w, void *data); static void tid_callback(Fl_Widget *w, void *data); static void option_callback(Fl_Widget *w, void *data); static void button_callback(Fl_Widget *w, void *data); static void spec_callback(Fl_Widget *w, void *data); static void args_callback(Fl_Widget *w, void *data); void AdjustExtraFloor(int dir); int CalcOptions() const; void OptionsFromInt(int options); }; #endif /* __EUREKA_UI_THING_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_prefs.h0000644000175100017510000000175612647061302016254 0ustar aaptedaapted//------------------------------------------------------------------------ // PREFERENCES DIALOG //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012 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 __EUREKA_UI_PREFS_H__ #define __EUREKA_UI_PREFS_H__ void CMD_Preferences(); #endif /* __EUREKA_UI_PREFS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_file.cc0000644000175100017510000004657612650662336016233 0ustar aaptedaapted//------------------------------------------------------------------------ // FILE-RELATED DIALOGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2015 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 "main.h" #include "m_config.h" #include "m_files.h" #include "m_game.h" #include "w_wad.h" #include "ui_window.h" #include "ui_file.h" #define FREE_COL fl_rgb_color(0x33, 0xFF, 0xAA) #define USED_COL (gui_scheme == 2 ? fl_rgb_color(0xFF, 0x11, 0x11) : fl_rgb_color(0xFF, 0x88, 0x88)) // TODO: find a better home for this bool ValidateMapName(const char *p) { size_t len = strlen(p); if (len == 0 || len > 8) return false; if (! isalpha(*p)) return false; for ( ; *p ; p++) if (! (isalnum(*p) || *p == '_')) return false; return true; } UI_ChooseMap::UI_ChooseMap(const char *initial_name, Wad_file *_rename_wad) : UI_Escapable_Window(420, 385, "Choose Map"), rename_wad(_rename_wad), action(ACT_none) { resizable(NULL); callback(close_callback, this); { map_name = new Fl_Input(120, 35, 120, 25, "Map slot: "); map_name->labelfont(FL_HELVETICA_BOLD); } map_name->when(FL_WHEN_CHANGED); map_name->callback(input_callback, this); map_name->value(initial_name); Fl::focus(map_name); map_buttons = new Fl_Group(x(), y() + 60, w(), y() + 320); map_buttons->end(); { int bottom_y = 320; Fl_Group* o = new Fl_Group(0, bottom_y, 420, 65); o->box(FL_FLAT_BOX); o->color(WINDOW_BG, WINDOW_BG); ok_but = new Fl_Return_Button(270, bottom_y + 17, 95, 35, "OK"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); Fl_Button *cancel = new Fl_Button(130, bottom_y + 17, 95, 35, "Cancel"); cancel->callback(close_callback, this); o->end(); } end(); CheckMapName(); } UI_ChooseMap::~UI_ChooseMap() { } void UI_ChooseMap::PopulateButtons(char format, Wad_file *test_wad) { int but_W = 60; for (int col = 0 ; col < 5 ; col++) for (int row = 0 ; row < 8 ; row++) { int cx = x() + 30 + col * (but_W + but_W / 5); int cy = y() + 80 + row * 24 + (row / 2) * 10; char name_buf[20]; if (format == 'E') { int epi = 1 + row / 2; int map = 1 + col + (row & 1) * 5; if (map > 9) continue; sprintf(name_buf, "E%dM%d", epi, map); } else { int map = 1 + col + row * 5; // this logic matches UI_OpenMap on the IWAD if (row >= 2) map--; else if (row == 1 && col == 4) continue; if (map < 1 || map > 32) continue; sprintf(name_buf, "MAP%02d", map); } Fl_Button * but = new Fl_Button(cx, cy, 60, 20); but->copy_label(name_buf); but->callback(button_callback, this); if (test_wad && test_wad->FindLevel(name_buf) >= 0) { if (rename_wad) but->deactivate(); else but->color(USED_COL); } else but->color(FREE_COL); map_buttons->add(but); } } const char * UI_ChooseMap::Run() { set_modal(); show(); while (action == ACT_none) { Fl::wait(0.2); } if (action == ACT_CANCEL) return NULL; return StringUpper(map_name->value()); } void UI_ChooseMap::close_callback(Fl_Widget *w, void *data) { UI_ChooseMap * that = (UI_ChooseMap *)data; that->action = ACT_CANCEL; } void UI_ChooseMap::ok_callback(Fl_Widget *w, void *data) { UI_ChooseMap * that = (UI_ChooseMap *)data; // santify check if (ValidateMapName(that->map_name->value())) that->action = ACT_ACCEPT; else fl_beep(); } void UI_ChooseMap::button_callback(Fl_Widget *w, void *data) { UI_ChooseMap * that = (UI_ChooseMap *)data; that->map_name->value(w->label()); that->action = ACT_ACCEPT; } void UI_ChooseMap::input_callback(Fl_Widget *w, void *data) { UI_ChooseMap * that = (UI_ChooseMap *)data; that->CheckMapName(); } void UI_ChooseMap::CheckMapName() { bool was_valid = ok_but->active(); bool is_valid = ValidateMapName(map_name->value()); if (rename_wad && is_valid) { if (rename_wad->FindLevel(map_name->value()) >= 0) is_valid = false; } if (was_valid == is_valid) return; if (is_valid) { ok_but->activate(); map_name->textcolor(FL_FOREGROUND_COLOR); } else { ok_but->deactivate(); map_name->textcolor(FL_RED); } map_name->redraw(); } //------------------------------------------------------------------------ UI_OpenMap::UI_OpenMap() : UI_Escapable_Window(420, 530, "Open Map"), action(ACT_none), result_wad(NULL), new_pwad(NULL) { resizable(NULL); callback(close_callback, this); { Fl_Box *o = new Fl_Box(10, 10, 300, 37, "Look for the map in which file:"); o->labelfont(FL_HELVETICA_BOLD); o->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); } { Fl_Group *o = new Fl_Group(50, 50, 235, 85); look_iwad = new Fl_Round_Button(50, 50, 215, 25, " the Game (IWAD) file"); look_iwad->down_box(FL_ROUND_DOWN_BOX); look_iwad->type(FL_RADIO_BUTTON); look_iwad->callback(look_callback, this); look_res = new Fl_Round_Button(50, 75, 215, 25, " the Resource wads"); look_res->down_box(FL_ROUND_DOWN_BOX); look_res->type(FL_RADIO_BUTTON); look_res->callback(look_callback, this); look_pwad = new Fl_Round_Button(50, 100, 235, 25, " the currently edited PWAD"); look_pwad->down_box(FL_ROUND_DOWN_BOX); look_pwad->type(FL_RADIO_BUTTON); look_pwad->callback(look_callback, this); if (edit_wad) look_pwad->value(1); else look_iwad->value(1); o->end(); } { Fl_Box* o = new Fl_Box(10, 140, 300, 20, "Current PWAD file:"); o->labelfont(FL_HELVETICA_BOLD); o->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); } pwad_name = new Fl_Output(25, 165, 265, 26); Fl_Button *load_but = new Fl_Button(305, 164, 70, 28, "Load"); load_but->callback(load_callback, this); map_name = new Fl_Input(94, 205, 100, 26, "Map slot: "); map_name->labelfont(FL_HELVETICA_BOLD); map_name->when(FL_WHEN_CHANGED); map_name->callback(input_callback, this); { Fl_Box *o = new Fl_Box(205, 205, 180, 26, "Available maps:"); // o->labelfont(FL_HELVETICA_BOLD); o->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); } // all the map buttons go into this group button_grp = new Fl_Group(0, 235, w(), 230, "\n\nNone Found"); button_grp->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); button_grp->end(); { int bottom_y = 470; Fl_Group* o = new Fl_Group(0, bottom_y, w(), 60); o->box(FL_FLAT_BOX); o->color(WINDOW_BG, WINDOW_BG); ok_but = new Fl_Return_Button(280, bottom_y + 15, 89, 34, "OK"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); Fl_Button * cancel = new Fl_Button(140, bottom_y + 15, 95, 35, "Cancel"); cancel->callback(close_callback, this); o->end(); } end(); CheckMapName(); } UI_OpenMap::~UI_OpenMap() { } void UI_OpenMap::Run(Wad_file ** wad_v, bool * is_new_pwad, const char ** map_v) { *wad_v = NULL; *map_v = NULL; *is_new_pwad = false; if (edit_wad) SetPWAD(edit_wad->PathName()); Populate(); set_modal(); show(); while (action == ACT_none) { Fl::wait(0.2); } if (action == ACT_ACCEPT) { SYS_ASSERT(result_wad); *wad_v = result_wad; *map_v = StringUpper(map_name->value()); if (result_wad == new_pwad) { *is_new_pwad = true; new_pwad = NULL; } } if (new_pwad) { delete new_pwad; } } void UI_OpenMap::CheckMapName() { bool was_valid = ok_but->active(); bool is_valid = (result_wad != NULL) && ValidateMapName(map_name->value()) && (result_wad->FindLevel(map_name->value()) >= 0); if (was_valid == is_valid) return; if (is_valid) { ok_but->activate(); map_name->textcolor(FL_FOREGROUND_COLOR); } else { ok_but->deactivate(); map_name->textcolor(FL_RED); } map_name->redraw(); } void UI_OpenMap::Populate() { button_grp->label("\n\nNone Found"); button_grp->clear(); result_wad = NULL; if (look_iwad->value()) { PopulateButtons(game_wad); } else if (look_res->value()) { int first = 1; int last = (int)master_dir.size() - 1; if (edit_wad) last--; // we simply use the last resource which contains levels // TODO: should grab list from each of them and merge into one big list for (int r = last ; r >= first ; r--) { if (master_dir[r]->FindFirstLevel() >= 0) { PopulateButtons(master_dir[r]); break; } } } else { if (new_pwad) PopulateButtons(new_pwad); else if (edit_wad) PopulateButtons(edit_wad); } } static bool DifferentEpisode(const char *A, const char *B) { if (A[0] != B[0]) return true; // handle ExMx if (toupper(A[0]) == 'E') { return A[1] != B[1]; } // handle MAPxx if (strlen(A) < 4 && strlen(B) < 4) return false; return A[3] != B[3]; } void UI_OpenMap::PopulateButtons(Wad_file *wad) { result_wad = wad; int num_levels = wad->NumLevels(); if (num_levels == 0) return; button_grp->label(""); // limit the number based on available space /* int max_rows = 8; int max_cols = 5; num_levels = MIN(num_levels, max_rows * max_cols); */ std::map level_names; std::map::iterator IT; for (int lev = 0 ; lev < num_levels ; lev++) { Lump_c *lump = wad->GetLump(wad->GetLevel(lev)); level_names[std::string(lump->Name())] = 1; } // determine how many rows and columns, and adjust layout #if 0 if (num_levels <= 24) max_rows = 6; /* if (num_levels <= 9) max_rows = 3; if (num_levels <= 4) max_rows = 2; if (num_levels <= 2) max_rows = 1; */ max_cols = (num_levels + (max_rows - 1)) / max_rows; #endif int cx_base = button_grp->x() + 30; int cy_base = button_grp->y() + 5; int but_W = 60; /* if (max_cols <= 4) { cx_base += 20; but_W += 12; } if (max_cols <= 2) { cx_base += 40; but_W += 12; } if (max_cols <= 1) { cx_base += 40; but_W += 12; } */ // create them buttons!! int row = 0; int col = 0; const char *last_name = NULL; for (IT = level_names.begin() ; IT != level_names.end() ; IT++) { const char *name = IT->first.c_str(); if (col > 0 && last_name && DifferentEpisode(last_name, name)) { col = 0; row++; if (row >= 8) break; } int cx = cx_base + col * (but_W + but_W / 5); int cy = cy_base + row * 24 + (row / 2) * 8; Fl_Button * but = new Fl_Button(cx, cy, but_W, 20); but->copy_label(name); but->color(FREE_COL); but->callback(button_callback, this); button_grp->add(but); col++; if (col >= 5) { col = 0; row++; if (row >= 8) break; } last_name = name; } redraw(); } void UI_OpenMap::SetPWAD(const char *name) { pwad_name->value(fl_filename_name(name)); } void UI_OpenMap::close_callback(Fl_Widget *w, void *data) { UI_OpenMap * that = (UI_OpenMap *)data; that->action = ACT_CANCEL; } void UI_OpenMap::ok_callback(Fl_Widget *w, void *data) { UI_OpenMap * that = (UI_OpenMap *)data; // santify check if (that->result_wad && ValidateMapName(that->map_name->value())) that->action = ACT_ACCEPT; else fl_beep(); } void UI_OpenMap::button_callback(Fl_Widget *w, void *data) { UI_OpenMap * that = (UI_OpenMap *)data; // sanity check if (! that->result_wad) return; that->map_name->value(w->label()); that->action = ACT_ACCEPT; } void UI_OpenMap::input_callback(Fl_Widget *w, void *data) { UI_OpenMap * that = (UI_OpenMap *)data; that->CheckMapName(); } void UI_OpenMap::look_callback(Fl_Widget *w, void *data) { UI_OpenMap * that = (UI_OpenMap *)data; that->Populate(); that->CheckMapName(); } void UI_OpenMap::load_callback(Fl_Widget *w, void *data) { UI_OpenMap * that = (UI_OpenMap *)data; that->LoadFile(); that->CheckMapName(); } void UI_OpenMap::LoadFile() { Fl_Native_File_Chooser chooser; chooser.title("Pick file to open"); chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); chooser.filter("Wads\t*.wad"); //?? chooser.directory("xxx"); // Show native chooser switch (chooser.show()) { case -1: LogPrintf("Open Map: error choosing file:\n"); LogPrintf(" %s\n", chooser.errmsg()); DLG_Notify("Unable to open the map:\n\n%s", chooser.errmsg()); return; case 1: LogPrintf("Open Map: cancelled by user\n"); return; default: break; // OK } Wad_file * wad = Wad_file::Open(chooser.filename(), 'a'); if (! wad) { // FIXME: get an error message, add it here DLG_Notify("Unable to open the chosen WAD file.\n\n" "Please try again."); return; } if (wad->FindFirstLevel() < 0) { DLG_Notify("The chosen WAD contains no levels.\n\n" "Please try again."); return; } if (new_pwad) { delete new_pwad; } new_pwad = wad; SetPWAD(new_pwad->PathName()); // change the "Look in ..." setting to be the current pwad look_iwad->value(0); look_res ->value(0); look_pwad->value(1); Populate(); } //------------------------------------------------------------------------ UI_ProjectSetup * UI_ProjectSetup::_instance = NULL; #define STARTUP_MSG "No IWADs could be found." UI_ProjectSetup::UI_ProjectSetup(bool new_project, bool is_startup) : UI_Escapable_Window(400, is_startup ? 412 : 372, new_project ? "New Project" : "Manage Project"), action(ACT_none), iwad(NULL), port(NULL) { callback(close_callback, this); resizable(NULL); _instance = this; // meh, hacky int by = 0; if (is_startup) { Fl_Box * message = new Fl_Box(FL_FLAT_BOX, 15, 10, 370, 46, STARTUP_MSG); message->align(FL_ALIGN_INSIDE); message->color(FL_RED, FL_RED); message->labelcolor(FL_YELLOW); message->labelsize(18); by += 40; } iwad_choice = new Fl_Choice(120, by+25, 170, 29, "Game IWAD: "); iwad_choice->labelfont(FL_HELVETICA_BOLD); iwad_choice->down_box(FL_BORDER_BOX); iwad_choice->callback((Fl_Callback*)iwad_callback, this); port_choice = new Fl_Choice(120, by+60, 170, 29, "Port: "); port_choice->labelfont(FL_HELVETICA_BOLD); port_choice->down_box(FL_BORDER_BOX); port_choice->callback((Fl_Callback*)port_callback, this); { Fl_Button* o = new Fl_Button(305, by+27, 75, 25, "Find"); o->callback((Fl_Callback*)browse_callback, this); } // Resource section Fl_Box *res_title = new Fl_Box(15, by+110, 185, 35, "Resource Files:"); res_title->labelfont(FL_HELVETICA_BOLD); res_title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); for (int r = 0 ; r < RES_NUM ; r++) { res[r] = NULL; int cy = by + 145 + r * 35; char res_label[64]; sprintf(res_label, "%d. ", 1 + r); res_name[r] = new Fl_Output(55, cy, 205, 25); res_name[r]->copy_label(res_label); Fl_Button *kill = new Fl_Button(270, cy, 30, 25, "x"); kill->labelsize(20); kill->callback((Fl_Callback*)kill_callback, (void *)(long)r); Fl_Button *load = new Fl_Button(315, cy, 75, 25, "Load"); load->callback((Fl_Callback*)load_callback, (void *)(long)r); } // bottom buttons { Fl_Group *o = new Fl_Group(0, by+312, 400, 60); o->box(FL_FLAT_BOX); o->color(WINDOW_BG, WINDOW_BG); cancel = new Fl_Button(165, o->y() + 14, 80, 35, is_startup ? "Quit" : "Cancel"); cancel->callback((Fl_Callback*)close_callback, this); ok_but = new Fl_Button(290, o->y() + 14, 80, 35, "Use"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback((Fl_Callback*)use_callback, this); o->end(); } end(); } UI_ProjectSetup::~UI_ProjectSetup() { _instance = NULL; } bool UI_ProjectSetup::Run() { Populate(); set_modal(); show(); while (action == ACT_none) { Fl::wait(0.2); } return (action == ACT_ACCEPT); } void UI_ProjectSetup::PopulateIWADs(const char *curr_iwad) { const char *iwad_string; int iwad_val = 0; iwad_string = M_KnownIWADsForMenu(&iwad_val, curr_iwad ? curr_iwad : "xxx"); iwad_choice->clear(); if (iwad_string[0]) { iwad_choice->add(iwad_string); iwad_choice->value(iwad_val); iwad = M_QueryKnownIWAD(iwad_choice->mvalue()->text); } } void UI_ProjectSetup::Populate() { iwad = NULL; PopulateIWADs(Iwad_name); if (! iwad) ok_but->deactivate(); port = NULL; const char *port_string; int port_val = 0; port_string = M_CollectDefsForMenu("ports", &port_val, Port_name ? Port_name : "xxx"); if (port_string[0]) { port_choice->add (port_string); port_choice->value(port_val); port = port_choice->mvalue()->text; } // Note: these resource wads may be invalid (not exist) during startup. // This is probably NOT the place to validate them... for (int r = 0 ; r < RES_NUM ; r++) { if (r < (int)Resource_list.size()) { res[r] = StringDup(Resource_list[r]); res_name[r]->value(fl_filename_name(res[r])); } } } void UI_ProjectSetup::close_callback(Fl_Widget *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; that->action = ACT_CANCEL; } void UI_ProjectSetup::use_callback(Fl_Button *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; that->action = ACT_ACCEPT; } void UI_ProjectSetup::iwad_callback(Fl_Choice *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; const char * name = w->mvalue()->text; that->iwad = StringDup(M_QueryKnownIWAD(name)); if (that->iwad) that->ok_but->activate(); else { that->ok_but->deactivate(); fl_beep(); } } void UI_ProjectSetup::port_callback(Fl_Choice *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; const char * name = w->mvalue()->text; that->port = StringDup(name); } void UI_ProjectSetup::browse_callback(Fl_Button *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; Fl_Native_File_Chooser chooser; chooser.title("Pick file to open"); chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); chooser.filter("Wads\t*.wad"); //?? chooser.directory("xxx"); switch (chooser.show()) { case -1: // error DLG_Notify("Unable to open that wad:\n\n%s", chooser.errmsg()); return; case 1: // cancelled return; default: break; // OK } // check that a game definition exists const char *game = DetermineGame(chooser.filename()); if (! M_CanLoadDefinitions("games", game)) { DLG_Notify("That game is not supported (no definition file).\n\n" "Please try again."); return; } M_AddKnownIWAD(chooser.filename()); M_SaveRecent(); that->iwad = StringDup(chooser.filename()); that->PopulateIWADs(that->iwad); that->ok_but->activate(); } void UI_ProjectSetup::load_callback(Fl_Button *w, void *data) { int r = (int)(long)data; SYS_ASSERT(0 <= r && r < RES_NUM); UI_ProjectSetup * that = _instance; SYS_ASSERT(that); Fl_Native_File_Chooser chooser; chooser.title("Pick file to open"); chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); chooser.filter("Wads\t*.wad\nEureka defs\t*.ugh"); //?? chooser.directory("xxx"); switch (chooser.show()) { case -1: // error DLG_Notify("Unable to open that wad:\n\n%s", chooser.errmsg()); return; case 1: // cancelled return; default: break; // OK } if (that->res[r]) StringFree(that->res[r]); that->res[r] = StringDup(chooser.filename()); that->res_name[r]->value(fl_filename_name(that->res[r])); } void UI_ProjectSetup::kill_callback(Fl_Button *w, void *data) { int r = (int)(long)data; SYS_ASSERT(0 <= r && r < RES_NUM); UI_ProjectSetup * that = _instance; SYS_ASSERT(that); if (that->res[r]) { StringFree(that->res[r]); that->res[r] = NULL; that->res_name[r]->value(""); } else fl_beep(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/x_hover.cc0000644000175100017510000005737112651053235016255 0ustar aaptedaapted//------------------------------------------------------------------------ // HIGHLIGHT HELPER //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include "r_grid.h" #include "levels.h" #include "m_game.h" #include "x_hover.h" extern int vertex_radius(double scale); float ApproxDistToLineDef(const LineDef * L, int x, int y) { int x1 = L->Start()->x; int y1 = L->Start()->y; int x2 = L->End()->x; int y2 = L->End()->y; int dx = x2 - x1; int dy = y2 - y1; if (abs(dx) > abs(dy)) { // The linedef is rather horizontal // case 1: x is to the left of the linedef // hence return distance to the left-most vertex if (x < (dx > 0 ? x1 : x2)) return hypot(x - (dx > 0 ? x1 : x2), y - (dx > 0 ? y1 : y2)); // case 2: x is to the right of the linedef // hence return distance to the right-most vertex if (x > (dx > 0 ? x2 : x1)) return hypot(x - (dx > 0 ? x2 : x1), y - (dx > 0 ? y2 : y1)); // case 3: x is in-between (and not equal to) both vertices // hence use slope formula to get intersection point float y3 = y1 + (x - x1) * (float)dy / (float)dx; return fabs(y3 - y); } else { // The linedef is rather vertical if (y < (dy > 0 ? y1 : y2)) return hypot(x - (dy > 0 ? x1 : x2), y - (dy > 0 ? y1 : y2)); if (y > (dy > 0 ? y2 : y1)) return hypot(x - (dy > 0 ? x2 : x1), y - (dy > 0 ? y2 : y1)); float x3 = x1 + (y - y1) * (float)dx / (float)dy; return fabs(x3 - x); } } int ClosestLine_CastingHoriz(int x, int y, int *side) { int best_match = -1; float best_dist = 9e9; for (int n = 0 ; n < NumLineDefs ; n++) { int ly1 = LineDefs[n]->Start()->y; int ly2 = LineDefs[n]->End()->y; // ignore purely horizontal lines if (ly1 == ly2) continue; // does the linedef cross the horizontal ray? if (MIN(ly1, ly2) >= y + 1 || MAX(ly1, ly2) <= y) continue; int lx1 = LineDefs[n]->Start()->x; int lx2 = LineDefs[n]->End()->x; float dist = lx1 - (x + 0.5) + (lx2 - lx1) * (y + 0.5 - ly1) / (float)(ly2 - ly1); if (fabs(dist) < best_dist) { best_match = n; best_dist = fabs(dist); if (side) { if (best_dist < 0.2) *side = 0; // on the line else if ( (ly1 > ly2) == (dist > 0)) *side = 1; // right side else *side = -1; // left side } } } return best_match; } int ClosestLine_CastingVert(int x, int y, int *side) { int best_match = -1; float best_dist = 9e9; for (int n = 0 ; n < NumLineDefs ; n++) { int lx1 = LineDefs[n]->Start()->x; int lx2 = LineDefs[n]->End()->x; // ignore purely vertical lines if (lx1 == lx2) continue; // does the linedef cross the vertical ray? if (MIN(lx1, lx2) >= x + 1 || MAX(lx1, lx2) <= x) continue; int ly1 = LineDefs[n]->Start()->y; int ly2 = LineDefs[n]->End()->y; float dist = ly1 - (y + 0.5) + (ly2 - ly1) * (x + 0.5 - lx1) / (float)(lx2 - lx1); if (fabs(dist) < best_dist) { best_match = n; best_dist = fabs(dist); if (side) { if (best_dist < 0.2) *side = 0; // on the line else if ( (lx1 > lx2) == (dist < 0)) *side = 1; // right side else *side = -1; // left side } } } return best_match; } int ClosestLine_CastAtAngle(int x, int y, float radians) { int best_match = -1; float best_dist = 9e9; double x2 = x + 256 * cos(radians); double y2 = y + 256 * sin(radians); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; float a = PerpDist(L->Start()->x, L->Start()->y, x, y, x2, y2); float b = PerpDist(L-> End()->x, L-> End()->y, x, y, x2, y2); // completely on one side of the vector? if (a > 0 && b > 0) continue; if (a < 0 && b < 0) continue; float c = AlongDist(L->Start()->x, L->Start()->y, x, y, x2, y2); float d = AlongDist(L-> End()->x, L-> End()->y, x, y, x2, y2); float dist; if (fabs(a) < 1 && fabs(b) < 1) dist = MIN(c, d); else if (fabs(a) < 1) dist = c; else if (fabs(b) < 1) dist = d; else { float factor = a / (a - b); dist = c * (1 - factor) + d * factor; } // behind or touching the vector? if (dist < 1) continue; if (dist < best_dist) { best_match = n; best_dist = dist; } } return best_match; } bool PointOutsideOfMap(int x, int y) { // this keeps track of directions tested int dirs = 0; for (int n = 0 ; n < NumLineDefs ; n++) { int lx1 = LineDefs[n]->Start()->x; int ly1 = LineDefs[n]->Start()->y; int lx2 = LineDefs[n]->End()->x; int ly2 = LineDefs[n]->End()->y; // does the linedef cross the horizontal ray? if (MIN(ly1, ly2) <= y && MAX(ly1, ly2) >= y + 1) { float dist = lx1 - (x + 0.5) + (lx2 - lx1) * (y + 0.5 - ly1) / (float)(ly2 - ly1); dirs |= (dist < 0) ? 1 : 2; if (dirs == 15) return false; } // does the linedef cross the vertical ray? if (MIN(lx1, lx2) <= x && MAX(lx1, lx2) >= x + 1) { float dist = ly1 - (y - 0.5) + (ly2 - ly1) * (x + 0.5 - lx1) / (float)(lx2 - lx1); dirs |= (dist < 0) ? 4 : 8; if (dirs == 15) return false; } } return true; } //------------------------------------------------------------------------ #define FASTOPP_DIST 320 typedef struct { int ld; int ld_side; // a SIDE_XXX value int * result_side; int dx, dy; // origin of casting line float x, y; bool is_horizontal; int best_match; float best_dist; public: void ComputeCastOrigin() { // choose a coordinate on the source line near the middle, but make // sure the casting line is not integral (i.e. lies between two lines // on the unit grid) so that we never directly hit a vertex. const LineDef * L = LineDefs[ld]; dx = L->End()->x - L->Start()->x; dy = L->End()->y - L->Start()->y; is_horizontal = abs(dy) >= abs(dx); x = L->Start()->x + dx * 0.5; y = L->Start()->y + dy * 0.5; if (is_horizontal && (dy & 1) == 0 && abs(dy) > 0) { y = y + 0.5; x = x + 0.5 * dx / (float)dy; } if (!is_horizontal && (dx & 1) == 0 && abs(dx) > 0) { x = x + 0.5; y = y + 0.5 * dy / (float)dx; } } void ProcessLine(int n) { if (ld == n) // ignore input line return; int nx1 = LineDefs[n]->Start()->x; int ny1 = LineDefs[n]->Start()->y; int nx2 = LineDefs[n]->End()->x; int ny2 = LineDefs[n]->End()->y; if (is_horizontal) { if (ny1 == ny2) return; if (MIN(ny1, ny2) > y || MAX(ny1, ny2) < y) return; float dist = nx1 + (nx2 - nx1) * (y - ny1) / (float)(ny2 - ny1) - x; if ( (dy < 0) == (ld_side > 0) ) dist = -dist; if (dist > 0.2 && dist < best_dist) { best_match = n; best_dist = dist; if (result_side) { if ( (dy > 0) != (ny2 > ny1) ) *result_side = ld_side; else *result_side = -ld_side; } } } else // casting a vertical ray { if (nx1 == nx2) return; if (MIN(nx1, nx2) > x || MAX(nx1, nx2) < x) return; float dist = ny1 + (ny2 - ny1) * (x - nx1) / (float)(nx2 - nx1) - y; if ( (dx > 0) == (ld_side > 0) ) dist = -dist; if (dist > 0.2 && dist < best_dist) { best_match = n; best_dist = dist; if (result_side) { if ( (dx > 0) != (nx2 > nx1) ) *result_side = ld_side; else *result_side = -ld_side; } } } } } opp_test_state_t; class fastopp_node_c { public: int lo, hi; // coordinate range int mid; fastopp_node_c * lo_child; fastopp_node_c * hi_child; std::vector lines; public: fastopp_node_c(int _low, int _high) : lo(_low), hi(_high), lo_child(NULL), hi_child(NULL), lines() { mid = (lo + hi) / 2; Subdivide(); } ~fastopp_node_c() { delete lo_child; delete hi_child; } /* horizontal tree */ void AddLine_X(int ld, int x1, int x2) { if (lo_child && (x1 > lo_child->lo) && (x2 < lo_child->hi)) { lo_child->AddLine_X(ld, x1, x2); return; } if (hi_child && (x1 > hi_child->lo) && (x2 < hi_child->hi)) { hi_child->AddLine_X(ld, x1, x2); return; } lines.push_back(ld); } void AddLine_X(int ld) { const LineDef *L = LineDefs[ld]; int x1 = MIN(L->Start()->x, L->End()->x); int x2 = MAX(L->Start()->x, L->End()->x); // can ignore purely vertical lines if (x1 == x2) return; AddLine_X(ld, x1, x2); } /* vertical tree */ void AddLine_Y(int ld, int y1, int y2) { if (lo_child && (y1 > lo_child->lo) && (y2 < lo_child->hi)) { lo_child->AddLine_Y(ld, y1, y2); return; } if (hi_child && (y1 > hi_child->lo) && (y2 < hi_child->hi)) { hi_child->AddLine_Y(ld, y1, y2); return; } lines.push_back(ld); } void AddLine_Y(int ld) { const LineDef *L = LineDefs[ld]; int y1 = MIN(L->Start()->y, L->End()->y); int y2 = MAX(L->Start()->y, L->End()->y); // can ignore purely horizonal lines if (y1 == y2) return; AddLine_Y(ld, y1, y2); } void Process(opp_test_state_t& test, float coord) { for (unsigned int k = 0 ; k < lines.size() ; k++) test.ProcessLine(lines[k]); if (! lo_child) return; // the AddLine() methods ensure that lines are not added // into a child bucket unless the end points are completely // inside it -- and one unit away from the extremes. // // hence we never need to recurse down BOTH sides here. if (coord < mid) lo_child->Process(test, coord); else hi_child->Process(test, coord); } private: void Subdivide() { if (hi - lo <= FASTOPP_DIST) return; lo_child = new fastopp_node_c(lo, mid); hi_child = new fastopp_node_c(mid, hi); } }; static fastopp_node_c * fastopp_X_tree; static fastopp_node_c * fastopp_Y_tree; void FastOpposite_Begin() { CalculateLevelBounds(); fastopp_X_tree = new fastopp_node_c(Map_bound_x1 - 8, Map_bound_x2 + 8); fastopp_Y_tree = new fastopp_node_c(Map_bound_y1 - 8, Map_bound_y2 + 8); for (int n = 0 ; n < NumLineDefs ; n++) { fastopp_X_tree->AddLine_X(n); fastopp_Y_tree->AddLine_Y(n); } } void FastOpposite_Finish() { delete fastopp_X_tree; fastopp_X_tree = NULL; delete fastopp_Y_tree; fastopp_Y_tree = NULL; } int OppositeLineDef(int ld, int ld_side, int *result_side) { // ld_side is either SIDE_LEFT or SIDE_RIGHT. // result_side uses the same values (never 0). opp_test_state_t test; test.ld = ld; test.ld_side = ld_side; test.result_side = result_side; test.ComputeCastOrigin(); if (test.dx == 0 && test.dy == 0) return -1; test.best_match = -1; test.best_dist = 9e9; if (fastopp_X_tree) { // fast way : use the binary tree if (test.is_horizontal) fastopp_Y_tree->Process(test, test.y); else fastopp_X_tree->Process(test, test.x); } else { // normal way : test all linedefs for (int n = 0 ; n < NumLineDefs ; n++) test.ProcessLine(n); } return test.best_match; } int OppositeSector(int ld, int ld_side) { int opp_side; int opp = OppositeLineDef(ld, ld_side, &opp_side); // can see the void? if (opp < 0) return -1; return LineDefs[opp]->WhatSector(opp_side); } // result: -1 for back, +1 for front, 0 for _exactly_on_ the line int PointOnLineSide(int x, int y, int lx1, int ly1, int lx2, int ly2) { x -= lx1; y -= ly1; lx2 -= lx1; ly2 -= ly1; int tmp = (x * ly2 - y * lx2); return (tmp < 0) ? -1 : (tmp > 0) ? +1 : 0; } //------------------------------------------------------------------------ class Close_obj { public : Objid obj; double distance; bool inside; int radius; Close_obj() { clear(); } void clear() { obj.clear(); distance = 9e9; radius = (1 << 30); inside = false; } bool operator== (const Close_obj& other) const { return (inside == other.inside && radius == other.radius && distance == other.distance) ? true : false; } bool operator< (const Close_obj& other) const { if (inside && ! other.inside) return true; if (! inside && other.inside) return false; // Small objects should "mask" large objects if (radius < other.radius) return true; if (radius > other.radius) return false; if (distance < other.distance) return true; if (distance > other.distance) return false; return radius < other.radius; } bool operator<= (const Close_obj& other) const { return *this == other || *this < other; } }; extern int TestAdjoinerLineDef(int ld); /* * get_cur_linedef - determine which linedef is under the pointer */ static void get_cur_linedef(Close_obj& closest, int x, int y) { // slack in map units int mapslack = 2 + (int)ceil(16.0f / grid.Scale); int lx = x - mapslack; int ly = y - mapslack; int hx = x + mapslack; int hy = y + mapslack; for (int n = 0 ; n < NumLineDefs ; n++) { int x1 = LineDefs[n]->Start()->x; int y1 = LineDefs[n]->Start()->y; int x2 = LineDefs[n]->End()->x; int y2 = LineDefs[n]->End()->y; // Skip all lines of which all points are more than // units away from (x,y). In a typical level, this test will // filter out all the linedefs but a handful. if (MAX(x1,x2) < lx || MIN(x1,x2) > hx || MAX(y1,y2) < ly || MIN(y1,y2) > hy) continue; float dist = ApproxDistToLineDef(LineDefs[n], x, y); if (dist > mapslack) continue; // "<=" because if there are superimposed vertices, we want to // return the highest-numbered one. if (dist > closest.distance) continue; closest.obj.type = OBJ_LINEDEFS; closest.obj.num = n; closest.distance = dist; } #if 0 // TESTING CRUD if (closest.obj.type == OBJ_LINEDEFS) { closest.obj.num = TestAdjoinerLineDef(closest.obj.num); if (closest.obj.num < 0) closest.clear(); } else if (closest.obj.type == OBJ_LINEDEFS) { closest.obj.num = OppositeLineDef(closest.obj.num, +1, NULL); if (closest.obj.num < 0) closest.clear(); } #endif } /* * get_split_linedef - determine which linedef would be split if a * new vertex was added to the given point. */ static void get_split_linedef(Close_obj& closest, int x, int y, int ignore_vert) { // slack in map units int mapslack = 1 + (int)ceil(8.0f / grid.Scale); int lx = x - mapslack; int ly = y - mapslack; int hx = x + mapslack; int hy = y + mapslack; for (int n = 0 ; n < NumLineDefs ; n++) { LineDef *L = LineDefs[n]; if (L->start == ignore_vert || L->end == ignore_vert) continue; int x1 = L->Start()->x; int y1 = L->Start()->y; int x2 = L->End()->x; int y2 = L->End()->y; if (MAX(x1,x2) < lx || MIN(x1,x2) > hx || MAX(y1,y2) < ly || MIN(y1,y2) > hy) continue; // skip linedef if point matches a vertex if (x == x1 && y == y1) continue; if (x == x2 && y == y2) continue; // skip linedef if too small to split if (abs(L->Start()->x - L->End()->x) < 4 && abs(L->Start()->y - L->End()->y) < 4) continue; float dist = ApproxDistToLineDef(L, x, y); if (dist > mapslack) continue; if (dist > closest.distance) continue; closest.obj.type = OBJ_LINEDEFS; closest.obj.num = n; closest.distance = dist; } } /* * get_cur_sector - determine which sector is under the pointer */ static void get_cur_sector(Close_obj& closest,int x, int y) { /* hack, hack... I look for the first LineDef crossing an horizontal half-line drawn from the cursor */ // -AJA- updated this to look in four directions (N/S/E/W) and // grab the closest linedef. Now it is possible to access // self-referencing lines, even purely horizontal ones. int side1, side2; int line1 = ClosestLine_CastingHoriz(x, y, &side1); int line2 = ClosestLine_CastingVert (x, y, &side2); if (line2 < 0) { /* nothing needed */ } else if (line1 < 0 || ApproxDistToLineDef(LineDefs[line2], x, y) < ApproxDistToLineDef(LineDefs[line1], x, y)) { line1 = line2; side1 = side2; } // grab the sector reference from the appropriate side // (Note that side1 = +1 for right, -1 for left, 0 for "on"). if (line1 >= 0) { int sd_num = (side1 < 0) ? LineDefs[line1]->left : LineDefs[line1]->right; if (sd_num >= 0) { closest.obj.type = OBJ_SECTORS; closest.obj.num = SideDefs[sd_num]->sector; } } } /* * get_cur_thing - determine which thing is under the pointer */ static void get_cur_thing(Close_obj& closest, int x, int y) { int mapslack = 1 + (int)ceil(16.0f / grid.Scale); int max_radius = MAX_RADIUS + mapslack; int lx = x - max_radius; int ly = y - max_radius; int hx = x + max_radius; int hy = y + max_radius; for (int n = 0 ; n < NumThings ; n++) { int tx = Things[n]->x; int ty = Things[n]->y; // Filter out things that are farther than units away. if (tx < lx || tx > hx || ty < ly || ty > hy) continue; const thingtype_t *info = M_GetThingType(Things[n]->type); // So how far is that thing exactly ? int thing_radius = info->radius + mapslack; if (x < tx - thing_radius || x > tx + thing_radius || y < ty - thing_radius || y > ty + thing_radius) continue; Close_obj current; current.obj.type = OBJ_THINGS; current.obj.num = n; current.distance = hypot(x - tx, y - ty); current.radius = info->radius; current.inside = x > tx - current.radius && x < tx + current.radius && y > ty - current.radius && y < ty + current.radius; // "<=" because if there are superimposed vertices, we want to // return the highest-numbered one. if (current <= closest) closest = current; } } /* * get_cur_vertex - determine which vertex is under the pointer */ static void get_cur_vertex(Close_obj& closest, int x, int y) { const int screen_pix = vertex_radius(grid.Scale); int mapslack = 1 + (int)ceil((4 + screen_pix) / grid.Scale); int lx = x - mapslack; int ly = y - mapslack; int hx = x + mapslack; int hy = y + mapslack; for (int n = 0 ; n < NumVertices ; n++) { int vx = Vertices[n]->x; int vy = Vertices[n]->y; /* Filter out objects that are farther than units away. */ if (vx < lx || vx > hx || vy < ly || vy > hy) continue; double dist = hypot(x - vx, y - vy); // "<=" because if there are superimposed vertices, we want to // return the highest-numbered one. if (dist > closest.distance) continue; closest.obj.type = OBJ_VERTICES; closest.obj.num = n; closest.distance = dist; } } /* * GetNearObject - determine which object is under the pointer * * Set to point to the object under the pointer (map * coordinates (, ). If several objects are close * enough to the pointer, the smallest object is chosen. */ void GetNearObject(Objid& o, obj_type_e objtype, int x, int y) { Close_obj closest; switch (objtype) { case OBJ_THINGS: { get_cur_thing(closest, x, y); o = closest.obj; break; } case OBJ_VERTICES: { get_cur_vertex(closest, x, y); o = closest.obj; break; } case OBJ_LINEDEFS: { get_cur_linedef(closest, x, y); o = closest.obj; break; } case OBJ_SECTORS: { get_cur_sector(closest, x, y); o = closest.obj; break; } default: BugError("GetNearObject: bad objtype %d", (int) objtype); break; /* NOT REACHED */ } } void GetSplitLineDef(Objid& o, int x, int y, int drag_vert) { Close_obj closest; get_split_linedef(closest, x, y, drag_vert); o = closest.obj; // don't highlight the line if the new vertex would snap onto // the same coordinate as the start or end of the linedef. // [ I tried a bbox test here, but it's bad for axis-aligned lines ] if (o.valid() && grid.snap) { int snap_x = grid.SnapX(x); int snap_y = grid.SnapY(y); const LineDef * L = LineDefs[o.num]; if ( (L->Start()->x == snap_x && L->Start()->y == snap_y) || (L-> End()->x == snap_x && L-> End()->y == snap_y) ) { o.clear(); } // also require snap coordinate be not TOO FAR from the line double len = L->CalcLength(); double along = AlongDist(snap_x, snap_y, L->Start()->x, L->Start()->y, L->End()->x, L->End()->y); double perp = PerpDist(snap_x, snap_y, L->Start()->x, L->Start()->y, L->End()->x, L->End()->y); if (along < len * 0.1 || along > len * 0.9 || fabs(perp) > len * 0.2) { o.clear(); } } } void GetSplitLineForDangler(Objid& o, int v_num) { Close_obj closest; get_split_linedef(closest, Vertices[v_num]->x, Vertices[v_num]->y, v_num); o = closest.obj; } bool FindClosestCrossPoint(int v1, int v2, cross_state_t *cross) { SYS_ASSERT(v1 != v2); cross->vert = -1; cross->line = -1; const Vertex *VA = Vertices[v1]; const Vertex *VB = Vertices[v2]; int x1 = VA->x; int y1 = VA->y; int x2 = VB->x; int y2 = VB->y; int dx = x2 - x1; int dy = y2 - y1; // same coords? (generally should not happen, handle it anyway) if (dx == 0 && dy == 0) return false; double length = sqrt(dx*dx + dy*dy); double epsilon = 0.4; // when zooming out, make it easier to hit a vertex double sk = 1.0 / grid.Scale; double close_dist = 8 * sqrt(sk); close_dist = CLAMP(1.2, close_dist, 24.0); double best_dist = 9e9; /* try all vertices */ for (int v = 0 ; v < NumVertices ; v++) { if (v == v1 || v == v2) continue; const Vertex * VC = Vertices[v]; // ignore vertices ar same coordinates as v1 or v2 if (VC->x == VA->x && VC->y == VA->y) continue; if (VC->x == VB->x && VC->y == VB->y) continue; // is this vertex sitting on the line? #if 0 if (x1 == x2) { if (VC->x != x1) continue; } else if (y1 == y2) { if (VC->y != y1) continue; } else #endif { double perp = PerpDist(VC->x, VC->y, x1,y1, x2,y2); if (fabs(perp) > close_dist) continue; } double along = AlongDist(VC->x, VC->y, x1,y1, x2,y2); if (along < epsilon || along > length - epsilon) continue; // yes it is if (along < best_dist) { best_dist = along; cross->vert = v; cross->line = -1; cross->x = VC->x; cross->y = VC->y; } } /* try all linedefs */ for (int ld = 0 ; ld < NumLineDefs ; ld++) { const LineDef * L = LineDefs[ld]; // only need to handle cases where this linedef distinctly crosses // the new line (i.e. start and end are clearly on opposite sides). double lx1 = L->Start()->x; double ly1 = L->Start()->y; double lx2 = L->End()->x; double ly2 = L->End()->y; double a = PerpDist(lx1,ly1, x1,y1, x2,y2); double b = PerpDist(lx2,ly2, x1,y1, x2,y2); if (! ((a < -epsilon && b > epsilon) || (a > epsilon && b < -epsilon))) continue; // compute intersection point double l_along = a / (a - b); double ix = lx1 + l_along * (lx2 - lx1); double iy = ly1 + l_along * (ly2 - ly1); int new_x = I_ROUND(ix); int new_y = I_ROUND(iy); // ensure new vertex does not match the start or end points if (new_x == x1 && new_y == y1) continue; if (new_x == x2 && new_y == y2) continue; double along = AlongDist(new_x, new_y, x1,y1, x2,y2); if (along < epsilon || along > length - epsilon) continue; // OK, this linedef crosses it fprintf(stderr, "linedef #%d crosses at (%1.3f %1.3f) along=%1.3f\n", ld, ix, iy, along); // allow vertices to win over a nearby linedef along += close_dist * 2; if (along < best_dist) { best_dist = along; cross->vert = -1; cross->line = ld; cross->x = new_x; cross->y = new_y; } } return (cross->vert >= 0) || (cross->line >= 0); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/levels.h0000644000175100017510000000634112647602763015741 0ustar aaptedaapted//------------------------------------------------------------------------ // LEVEL MISC STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_LEVELS_H__ #define __EUREKA_LEVELS_H__ #include #include "e_things.h" extern int Map_bound_x1; /* minimum X value of map */ extern int Map_bound_y1; /* minimum Y value of map */ extern int Map_bound_x2; /* maximum X value of map */ extern int Map_bound_y2; /* maximum Y value of map */ extern int MadeChanges; void MarkChanges(); void CalculateLevelBounds(); void MapStuff_NotifyBegin(); void MapStuff_NotifyInsert(obj_type_e type, int objnum); void MapStuff_NotifyDelete(obj_type_e type, int objnum); void MapStuff_NotifyChange(obj_type_e type, int objnum, int field); void MapStuff_NotifyEnd(); void ObjectBox_NotifyBegin(); void ObjectBox_NotifyInsert(obj_type_e type, int objnum); void ObjectBox_NotifyDelete(obj_type_e type, int objnum); void ObjectBox_NotifyChange(obj_type_e type, int objnum, int field); void ObjectBox_NotifyEnd(); void Selection_NotifyBegin(); void Selection_NotifyInsert(obj_type_e type, int objnum); void Selection_NotifyDelete(obj_type_e type, int objnum); void Selection_NotifyChange(obj_type_e type, int objnum, int field); void Selection_NotifyEnd(); void DumpSelection (selection_c * list); void ConvertSelection(selection_c * src, selection_c * dest); int Selection_FirstLine(selection_c *list); void Selection_Clear(bool no_save = false); void Selection_Push(); void Selection_InvalidateLast(); // handling of recently used textures, flats and things #define RECENTLY_USED_MAX 32 class Recently_used { private: int size; int keep_num; const char *name_set[RECENTLY_USED_MAX]; public: Recently_used(); ~Recently_used(); int find(const char *name); int find_number(int val); void insert(const char *name); void insert_number(int val); void clear(); void WriteUser(FILE *fp, char letter); private: void erase(int index); void push_front(const char *name); }; extern Recently_used recent_textures; extern Recently_used recent_flats; extern Recently_used recent_things; void RecUsed_ClearAll(); void RecUsed_WriteUser(FILE *fp); bool RecUsed_ParseUser(const char ** tokens, int num_tok); #endif /* __EUREKA_LEVELS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_file.h0000644000175100017510000000777112647061302016057 0ustar aaptedaapted//------------------------------------------------------------------------ // FILE-RELATED DIALOGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012 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 __EUREKA_UI_FILE_H__ #define __EUREKA_UI_FILE_H__ class UI_ChooseMap : public UI_Escapable_Window { private: Fl_Input *map_name; Fl_Group *map_buttons; Fl_Return_Button *ok_but; // normally NULL, when present will prevent using an existing level name Wad_file *rename_wad; enum { ACT_none = 0, ACT_CANCEL, ACT_ACCEPT }; int action; void CheckMapName(); public: UI_ChooseMap(const char *initial_name = "", Wad_file *_rename_wad = NULL); virtual ~UI_ChooseMap(); // format is 'E' for ExMx, or 'M' for MAPxx void PopulateButtons(char format, Wad_file *test_wad = NULL); // returns map name on success, NULL on cancel const char * Run(); private: static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); static void input_callback(Fl_Widget *, void *); static void new_callback(Fl_Widget *, void *); }; //------------------------------------------------------------------------ class UI_OpenMap : public UI_Escapable_Window { private: Fl_Round_Button *look_iwad; Fl_Round_Button *look_res; Fl_Round_Button *look_pwad; Fl_Output *pwad_name; Fl_Input *map_name; Fl_Group *button_grp; Fl_Return_Button *ok_but; enum { ACT_none = 0, ACT_CANCEL, ACT_ACCEPT }; int action; Wad_file * result_wad; Wad_file * new_pwad; void Populate(); void PopulateButtons(Wad_file *wad); void LoadFile(); void SetPWAD(const char *name); void CheckMapName(); public: UI_OpenMap(); virtual ~UI_OpenMap(); // the 'wad' result will be NULL when cancelled. // when OK and 'is_new_pwad' is set, the wad should become the edit_wad void Run(Wad_file ** wad_v, bool * is_new_pwad, const char ** map_v); private: static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); static void look_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); static void input_callback(Fl_Widget *, void *); static void load_callback(Fl_Widget *, void *); }; //------------------------------------------------------------------------ class UI_ProjectSetup : public UI_Escapable_Window { public: enum { RES_NUM = 4 }; private: Fl_Choice *iwad_choice; Fl_Choice *port_choice; Fl_Output *res_name[RES_NUM]; Fl_Button *ok_but; Fl_Button *cancel; enum { ACT_none = 0, ACT_CANCEL, ACT_ACCEPT }; int action; static UI_ProjectSetup * _instance; // meh! static void iwad_callback(Fl_Choice*, void*); static void port_callback(Fl_Choice*, void*); static void browse_callback(Fl_Button*, void*); static void kill_callback(Fl_Button*, void*); static void load_callback(Fl_Button*, void*); static void close_callback(Fl_Widget*, void*); static void use_callback(Fl_Button*, void*); void Populate(); void PopulateIWADs(const char *curr_iwad); public: /* * current state */ const char * iwad; const char * port; const char * res[RES_NUM]; public: UI_ProjectSetup(bool new_project = false, bool is_startup = false); virtual ~UI_ProjectSetup(); // returns true if something changed bool Run(); }; #endif /* __EUREKA_UI_FILE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/sys_type.h0000644000175100017510000000220112647061302016301 0ustar aaptedaapted//------------------------------------------------------------------------ // Type definitions //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2008 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 __SYS_TYPE_H__ #define __SYS_TYPE_H__ // basic types typedef char s8_t; typedef short s16_t; typedef int s32_t; typedef unsigned char u8_t; typedef unsigned short u16_t; typedef unsigned int u32_t; typedef u8_t byte; #endif /* __SYS_TYPE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/x_mirror.h0000644000175100017510000000377712651124650016307 0ustar aaptedaapted//------------------------------------------------------------------------ // MIRROR / ROTATE / ETC OPS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_X_MIRROR_H__ #define __EUREKA_X_MIRROR_H__ struct scale_param_t { public: int mid_x, mid_y; float scale_x, scale_y; int rotate; // 16 bits (65536 = 360 degrees) public: void Clear(); void Apply(int *x, int *y) const; }; void Objs_CalcMiddle(selection_c * list, int *x, int *y); void Objs_CalcBBox(selection_c * list, int *x1, int *y1, int *x2, int *y2); /* commands */ void CMD_Mirror (void); void CMD_Rotate90(void); void CMD_Enlarge (void); void CMD_Shrink (void); void CMD_Quantize(void); void CMD_ScaleObjects2(scale_param_t& param); void CMD_ScaleObjects3(double scale_x, double scale_y, int pos_x, int pos_y); void CMD_ScaleObjects3(double scale_x, double scale_y, double scale_z, int pos_x, int pos_y, int pos_z); void CMD_RotateObjects3(double deg, int pos_x, int pos_y); #endif /* __EUREKA_X_MIRROR_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/r_grid.cc0000644000175100017510000002443312651123275016044 0ustar aaptedaapted//------------------------------------------------------------------------ // GRID STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "r_grid.h" #include "ui_window.h" Grid_State_c grid; // config items int default_grid_size = 64; bool default_grid_snap = true; int default_grid_mode = 2; // normal int grid_toggle_type = 0; // both bool grid_hide_in_free_mode = false; Grid_State_c::Grid_State_c() : step(16 /* dummy */), snap(true), shown(true), mode(0), orig_x(0.0), orig_y(0.0), Scale(1.0) { } Grid_State_c::~Grid_State_c() { } void Grid_State_c::Init() { step = default_grid_size - 1; if (step < 1) step = 1; if (step >= grid_values[1]) step = grid_values[1] - 1; shown = true; // prevent a beep in AdjustStep AdjustStep(+1); if (default_grid_mode == 0) { shown = false; if (main_win) main_win->info_bar->SetGrid(0); } else { shown = true; mode = default_grid_mode - 1; } snap = default_grid_snap; if (main_win) main_win->info_bar->UpdateSnap(); } void Grid_State_c::MoveTo(double x, double y) { // no change? if (fabs(x - orig_x) < 0.01 && fabs(y - orig_y) < 0.01) return; orig_x = x; orig_y = y; if (main_win) { main_win->canvas->redraw(); main_win->scroll->AdjustPos(); } } void Grid_State_c::Scroll(double delta_x, double delta_y) { MoveTo(orig_x + delta_x, orig_y + delta_y); } int Grid_State_c::ForceSnapX(int map_x) const { if (map_x >= 0) return grid.step * ((map_x + grid.step / 2) / grid.step); else return grid.step * ((map_x - grid.step / 2) / grid.step); } int Grid_State_c::ForceSnapY(int map_y) const { if (map_y >= 0) return grid.step * ((map_y + grid.step / 2) / grid.step); else return grid.step * ((map_y - grid.step / 2) / grid.step); } int Grid_State_c::SnapX(int map_x) const { if (! snap || grid.step == 0) return map_x; return ForceSnapX(map_x); } int Grid_State_c::SnapY(int map_y) const { if (! snap || grid.step == 0) return map_y; return ForceSnapY(map_y); } int Grid_State_c::QuantSnapX(int map_x, bool want_furthest, int *dir) const { if (OnGridX(map_x)) { if (dir) *dir = 0; return map_x; } int new_x = ForceSnapX(map_x); if (dir) { if (new_x < map_x) *dir = -1; else *dir = +1; } if (! want_furthest) return new_x; if (new_x < map_x) return ForceSnapX(map_x + (step - 1)); else return ForceSnapX(map_x - (step - 1)); } int Grid_State_c::QuantSnapY(int map_y, bool want_furthest, int *dir) const { // this is sufficient since the grid is always square return QuantSnapX(map_y, want_furthest, dir); } bool Grid_State_c::OnGridX(int map_x) const { if (map_x < 0) map_x = -map_x; return (map_x % step) == 0; } bool Grid_State_c::OnGridY(int map_y) const { if (map_y < 0) map_y = -map_y; return (map_y % step) == 0; } bool Grid_State_c::OnGrid(int map_x, int map_y) const { return OnGridX(map_x) && OnGridY(map_y); } void Grid_State_c::RefocusZoom(int map_x, int map_y, float before_Scale) { float dist_factor = (1.0 - before_Scale / Scale); orig_x += (map_x - orig_x) * dist_factor; orig_y += (map_y - orig_y) * dist_factor; if (main_win) main_win->canvas->redraw(); } const double Grid_State_c::scale_values[] = { 16.0, 8.0, 6.0, 4.0, 3.0, 2.0, 1.5, 1.0, 1.0 / 1.5, 1.0 / 2.0, 1.0 / 3.0, 1.0 / 4.0, 1.0 / 6.0, 1.0 / 8.0, 1.0 / 16.0, 1.0 / 32.0, 1.0 / 64.0 }; const int Grid_State_c::digit_scales[] = { 1, 3, 5, 7, 9, 11, 13, 14, 15 /* index into scale_values[] */ }; const int Grid_State_c::grid_values[] = { -1 /* OFF */, 1024, 512, 256, 192, 128, 64, 32, 16, 8, 4, 2 }; #define NUM_SCALE_VALUES 17 #define NUM_GRID_VALUES 12 const char *Grid_State_c::scale_options() { return "x 16|x 8|x 6|x 4|x 3|x 2|x 1.5|" " 100% |" "/ 1.5|/ 2|/ 3|/ 4|/ 6|/ 8|/ 16|/ 32|/ 64"; } const char *Grid_State_c::grid_options() { return "OFF|1024|512|256|192|128| 64| 32| 16| 8| 4| 2"; } void Grid_State_c::ScaleFromWidget(int i) { SYS_ASSERT(0 <= i && i < NUM_SCALE_VALUES); Scale = scale_values[i]; if (main_win) main_win->scroll->AdjustPos(); RedrawMap(); } void Grid_State_c::StepFromWidget(int i) { SYS_ASSERT(0 <= i && i < NUM_GRID_VALUES); if (i == 0) /* OFF */ { shown = false; } else { shown = true; step = grid_values[i]; } if (grid_hide_in_free_mode && snap != shown) SetSnap(shown); RedrawMap(); } void Grid_State_c::StepFromScale() { int pixels_min = 16; int result = 1; for (int i = 1 ; i < NUM_GRID_VALUES ; i++) { result = i; if (grid_values[i] * Scale / 2 < pixels_min) break; } if (step == grid_values[result]) return; // no change step = grid_values[result]; if (main_win) { main_win->canvas->redraw(); } } void Grid_State_c::AdjustStep(int delta) { if (! shown) { Beep("Grid is off (cannot change step)"); return; } int result = -1; if (delta > 0) { for (int i = NUM_GRID_VALUES-1 ; i >= 1 ; i--) { if (grid_values[i] > step) { result = i; break; } } } else // (delta < 0) { for (int i = 1 ; i < NUM_GRID_VALUES ; i++) { if (grid_values[i] < step) { result = i; break; } } } // already at the extreme end? if (result < 0) return; StepFromWidget(result); if (main_win) main_win->info_bar->SetGrid(result); } void Grid_State_c::AdjustScale(int delta) { int result = -1; if (delta > 0) { for (int i = NUM_SCALE_VALUES-1 ; i >= 0 ; i--) { if (scale_values[i] > Scale*1.01) { result = i; break; } } } else // (delta < 0) { for (int i = 0 ; i < NUM_SCALE_VALUES ; i++) { if (scale_values[i] < Scale*0.99) { result = i; break; } } } // already at the extreme end? if (result < 0) return; ScaleFromWidget(result); if (main_win) { main_win->info_bar->SetScale(result); main_win->scroll->AdjustPos(); } } void Grid_State_c::DoSetScale() { if (! main_win) return; for (int i = NUM_SCALE_VALUES-1 ; i >= 0 ; i--) { float ratio = scale_values[i] / Scale; if (ratio > 0.99 && ratio < 1.01) { main_win->info_bar->SetScale(i); main_win->scroll->AdjustPos(); return; } } int index = 10; //meh Scale = scale_values[index]; main_win->info_bar->SetScale(index); main_win->scroll->AdjustPos(); } void Grid_State_c::DoSetGrid() { if (! main_win) return; if (! shown) { main_win->info_bar->SetGrid(0); return; } // find the step for (int i = 1 ; i < NUM_GRID_VALUES ; i++) { if (grid_values[i] == step) { main_win->info_bar->SetGrid(i); return; } } // bad step? Init(); } void Grid_State_c::SetShown(bool enable) { if (grid_toggle_type > 0) mode = grid_toggle_type - 1; shown = enable; if (grid_hide_in_free_mode && shown != snap) SetSnap(shown); DoSetGrid(); RedrawMap(); } void Grid_State_c::ToggleShown() { if (grid_toggle_type > 0) mode = grid_toggle_type - 1; if (! shown) { shown = true; } else if (grid_toggle_type > 0) { shown = false; } else if (mode == 1) { shown = false; mode = 0; } else { mode = 1; } if (grid_hide_in_free_mode && shown != snap) SetSnap(shown); DoSetGrid(); RedrawMap(); } void Grid_State_c::SetMode(int new_mode) { mode = new_mode; DoSetGrid(); RedrawMap(); } void Grid_State_c::ToggleMode() { if (! shown) { shown = true; } SetMode(1 - mode); } void Grid_State_c::SetSnap(bool enable) { snap = enable; if (grid_hide_in_free_mode && snap != shown) SetShown(snap); if (main_win) main_win->info_bar->UpdateSnap(); UpdateHighlight(); } void Grid_State_c::ToggleSnap() { SetSnap(! snap); } void Grid_State_c::NearestScale(double want_scale) { int result = 0; for (int i = 0 ; i < NUM_SCALE_VALUES ; i++) { result = i; if (scale_values[i] < want_scale) break; } ScaleFromWidget(result); if (main_win) { main_win->info_bar->SetScale(result); main_win->scroll->AdjustPos(); } } void Grid_State_c::ScaleFromDigit(int digit) { // digit must be 1 to 9 SYS_ASSERT(1 <= digit && digit <= 9); int result = digit_scales[digit - 1]; ScaleFromWidget(result); if (main_win) { main_win->info_bar->SetScale(result); main_win->scroll->AdjustPos(); } } void Grid_State_c::StepFromDigit(int digit) { // digit must be 1 to 9 SYS_ASSERT(1 <= digit && digit <= 9); int result = NUM_GRID_VALUES - digit; StepFromWidget(result); if (main_win) main_win->info_bar->SetGrid(result); } bool Grid_ParseUser(const char ** tokens, int num_tok) { if (strcmp(tokens[0], "map_pos") == 0 && num_tok >= 4) { double x = atof(tokens[1]); double y = atof(tokens[2]); grid.MoveTo(x, y); grid.Scale = atof(tokens[3]); grid.DoSetScale(); RedrawMap(); return true; } if (strcmp(tokens[0], "grid") == 0 && num_tok >= 4) { grid.shown = atoi(tokens[1]) ? true : false; grid.mode = atoi(tokens[2]); grid.step = atoi(tokens[3]); if (grid.mode < 0 || grid.mode > 1) grid.mode = 1; grid.DoSetGrid(); RedrawMap(); return true; } if (strcmp(tokens[0], "snap") == 0 && num_tok >= 2) { grid.snap = atoi(tokens[1]) ? true : false; if (main_win) main_win->info_bar->UpdateSnap(); return true; } return false; } void Grid_WriteUser(FILE *fp) { fprintf(fp, "map_pos %1.0f %1.0f %1.6f\n", grid.orig_x, grid.orig_y, grid.Scale); fprintf(fp, "grid %d %d %d\n", grid.shown ? 1 : 0, grid.mode, grid.step); fprintf(fp, "snap %d\n", grid.snap ? 1 : 0); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_sidedef.h0000644000175100017510000000457212647061302016537 0ustar aaptedaapted//------------------------------------------------------------------------ // SIDEDEF INFORMATION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2015 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 __EUREKA_UI_SIDEDEF_H__ #define __EUREKA_UI_SIDEDEF_H__ #define SETOBJ_NO_LINE -2 // solid_mask bits : when set, that part requires a texture enum { SOLID_LOWER = (1 << 0), SOLID_MID = (1 << 1), SOLID_UPPER = (1 << 2) }; class UI_SideBox : public Fl_Group { private: int obj; bool is_front; int what_is_solid; bool on_2S_line; public: Fl_Int_Input *x_ofs; Fl_Int_Input *y_ofs; Fl_Int_Input *sec; UI_Pic *l_pic; UI_Pic *u_pic; UI_Pic *r_pic; Fl_Input *l_tex; Fl_Input *u_tex; Fl_Input *r_tex; Fl_Button *add_button; Fl_Button *del_button; public: UI_SideBox(int X, int Y, int W, int H, int _side); virtual ~UI_SideBox(); public: // this can be a sidedef number or -1 for none, or the special // value SETOBJ_NO_LINE when there is no linedef at all. // solid_mask is a bit field of parts which require a texture. // two_sided is from the linedef, will show all parts if true. void SetObj(int index, int solid_mask, bool two_sided); void UpdateField(); // returns a bitmask: 1 for lower, 2 for upper, 4 for rail int GetSelectedPics() const; void UnselectPics(); static int TexFromWidget(Fl_Input *w); private: void UpdateLabel(); void UpdateHiding(); void UpdateAddDel(); static void tex_callback(Fl_Widget *, void *); static void offset_callback(Fl_Widget *, void *); static void sector_callback(Fl_Widget *, void *); static void add_callback(Fl_Widget *, void *); static void delete_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_SIDEDEF_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_sector.cc0000644000175100017510000001233312651123632016372 0ustar aaptedaapted//------------------------------------------------------------------------ // SECTOR STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "levels.h" #include "e_linedef.h" #include "e_sector.h" #include "editloop.h" #include "m_bitvec.h" #include "objects.h" #include "x_loop.h" #include "ui_window.h" void SEC_Floor(void) { int diff = atoi(EXEC_Param[0]); if (diff == 0) { Beep("SEC_Floor: bad parameter '%s'", EXEC_Param[0]); return; } selection_c list; selection_iterator_c it; if (! GetCurrentObjects(&list)) { Beep("No sectors to move"); return; } BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { const Sector *S = Sectors[*it]; int new_h = CLAMP(-32767, S->floorh + diff, S->ceilh); BA_ChangeSEC(*it, Sector::F_FLOORH, new_h); } BA_End(); main_win->sec_box->UpdateField(Sector::F_FLOORH); } void SEC_Ceil(void) { int diff = atoi(EXEC_Param[0]); if (diff == 0) { Beep("SEC_Ceil: bad parameter '%s'", EXEC_Param[0]); return; } selection_c list; selection_iterator_c it; if (! GetCurrentObjects(&list)) { Beep("No sectors to move"); return; } BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { const Sector *S = Sectors[*it]; int new_h = CLAMP(S->floorh, S->ceilh + diff, 32767); BA_ChangeSEC(*it, Sector::F_CEILH, new_h); } BA_End(); main_win->sec_box->UpdateField(Sector::F_CEILH); } static int light_add_delta(int level, int delta) { // NOTE: delta is assumed to be a power of two if (abs(delta) <= 1) { level += delta; } else if (delta > 0) { level = (level | (delta-1)) + 1; } else { level = (level - 1) & ~(abs(delta)-1); } return CLAMP(0, level, 255); } void CMD_AdjustLight(int delta) { selection_c list; selection_iterator_c it; if (! GetCurrentObjects(&list)) { Beep("No sectors to adjust light"); return; } BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { const Sector *S = Sectors[*it]; int new_lt = light_add_delta(S->light, delta); BA_ChangeSEC(*it, Sector::F_LIGHT, new_lt); } BA_End(); main_win->sec_box->UpdateField(Sector::F_LIGHT); } void SEC_Light(void) { int diff = atoi(EXEC_Param[0]); if (diff == 0) { Beep("SEC_Light: bad parameter '%s'", EXEC_Param[0]); return; } CMD_AdjustLight(diff); } void SEC_SwapFlats() { selection_c list; selection_iterator_c it; if (! GetCurrentObjects(&list)) { Beep("No sectors to swap"); return; } BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { const Sector *S = Sectors[*it]; int floor_tex = S->floor_tex; int ceil_tex = S->ceil_tex; BA_ChangeSEC(*it, Sector::F_FLOOR_TEX, ceil_tex); BA_ChangeSEC(*it, Sector::F_CEIL_TEX, floor_tex); } BA_End(); main_win->sec_box->UpdateField(Sector::F_FLOOR_TEX); main_win->sec_box->UpdateField(Sector::F_CEIL_TEX); } static void LineDefsBetweenSectors(selection_c *list, int sec1, int sec2) { for (int i = 0 ; i < NumLineDefs ; i++) { const LineDef * L = LineDefs[i]; if (! (L->Left() && L->Right())) continue; if ((L->Left()->sector == sec1 && L->Right()->sector == sec2) || (L->Left()->sector == sec2 && L->Right()->sector == sec1)) { list->set(i); } } } static void ReplaceSectorRefs(int old_sec, int new_sec) { for (int i = 0 ; i < NumSideDefs ; i++) { SideDef * sd = SideDefs[i]; if (sd->sector == old_sec) { BA_ChangeSD(i, SideDef::F_SECTOR, new_sec); } } } void SEC_Merge(void) { // need a selection if (edit.Selected->count_obj() == 1 && edit.highlight.valid()) { edit.Selected->set(edit.highlight.num); } if (edit.Selected->count_obj() < 2) { Beep("Need 2 or more sectors to merge"); return; } bool keep_common_lines = Exec_HasFlag("/keep"); int source = edit.Selected->find_first(); selection_c common_lines(OBJ_LINEDEFS); selection_iterator_c it; BA_Begin(); for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { int target = *it; if (target == source) continue; LineDefsBetweenSectors(&common_lines, target, source); ReplaceSectorRefs(target, source); } if (! keep_common_lines) { // this deletes any unused vertices/sidedefs too DeleteLineDefs(&common_lines); } BA_End(); // re-select the final sector Selection_Clear(true); edit.Selected->set(source); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/sys_debug.h0000644000175100017510000000337212647061302016420 0ustar aaptedaapted//------------------------------------------------------------------------ // Debugging support //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2013 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 __SYS_DEBUG_H__ #define __SYS_DEBUG_H__ #define MSG_BUF_LEN 1024 extern bool Quiet; extern bool Debugging; void LogOpenFile(const char *filename); void LogOpenWindow(void); void LogClose(void); void LogSaveTo(FILE *dest_fp); void LogPrintf(const char *str, ...); void DebugPrintf(const char *str, ...); // -------- assertion macros -------- #ifdef NDEBUG #define SYS_ASSERT(cond) ((void) 0) #elif defined(__GNUC__) #define SYS_ASSERT(cond) ((cond) ? (void)0 : \ BugError("Assertion (%s) failed\nIn function %s (%s:%d)\n", #cond , __func__, __FILE__, __LINE__)) #else #define SYS_ASSERT(cond) ((cond) ? (void)0 : \ BugError("Assertion (%s) failed\nIn file %s:%d\n", #cond , __FILE__, __LINE__)) #endif // NDEBUG #define SYS_NULL_CHECK(ptr) SYS_ASSERT((ptr) != NULL) #define SYS_ZERO_CHECK(value) SYS_ASSERT((value) != 0) #endif /* __SYS_DEBUG_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_about.cc0000644000175100017510000001055112651564411016402 0ustar aaptedaapted//------------------------------------------------------------------------ // ABOUT WINDOW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 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 "main.h" #include "ui_window.h" #include "ui_about.h" #define ABOUT_W (440) // matches logo image #define ABOUT_H (230 + 290) class UI_About : public UI_Escapable_Window { private: static UI_About * _instance; static Fl_RGB_Image *about_img; UI_About(int W, int H, const char *label = NULL); virtual ~UI_About() { // nothing needed } static void LoadImage() { static char filename[FL_PATH_MAX]; snprintf(filename, sizeof(filename), "%s/about_logo.png", install_dir); filename[FL_PATH_MAX-1] = 0; if (FileExists(filename)) { about_img = new Fl_PNG_Image(filename); } } public: static void Open() { if (_instance) // already up? return; if (! about_img) LoadImage(); _instance = new UI_About(ABOUT_W, ABOUT_H, "About Eureka v" EUREKA_VERSION); _instance->show(); } private: static void close_callback(Fl_Widget *w, void *data) { if (_instance) { _instance->default_callback(_instance, data); _instance = NULL; } } static const char *Text1; static const char *Text2; static const char *URL; }; UI_About * UI_About::_instance; Fl_RGB_Image * UI_About::about_img; const char *UI_About::Text1 = "EUREKA is a map editor for classic DOOM\n" "It uses code from the Yadex editor"; const char *UI_About::Text2 = "Copyright (C) 2001-2016 Andrew Apted, et al\n" "Copyright (C) 2014-2015 Ioan Chera \n" "Copyright (C) 1997-2003 André Majorel, et al\n" "\n" "This program is free software, and may be\n" "distributed and modified under the terms of\n" "the GNU General Public License\n" "\n" "There is ABSOLUTELY NO WARRANTY\n" "Use at your OWN RISK"; const char *UI_About::URL = "http://awwports.sf.net/eureka"; // // Constructor // UI_About::UI_About(int W, int H, const char *label) : UI_Escapable_Window(W, H, label) { // non-resizable size_range(W, H, W, H); callback(close_callback, this); // nice big logo image Fl_Box *box = new Fl_Box(FL_NO_BOX, 0, 0, W, 230, NULL); box->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER); box->color(FL_BLACK, FL_BLACK); if (about_img) { box->image(about_img); // overlay a small version number in bottom right corner Fl_Box *v_box = new Fl_Box(FL_NO_BOX, 0, 0, W - 2, 230, ""); v_box->label("v" EUREKA_VERSION); v_box->labelsize(20); v_box->labelcolor(fl_rgb_color(160, 255, 128)); v_box->align(FL_ALIGN_INSIDE | FL_ALIGN_RIGHT | FL_ALIGN_BOTTOM); } else { box->box(FL_FLAT_BOX); box->label("EUREKA\nDoom Editor\nv" EUREKA_VERSION); box->labelsize(40); box->labelcolor(fl_rgb_color(255, 200, 100)); } int cy = 240; // the very informative text int pad = 20 + KF * 6; box = new Fl_Box(FL_NO_BOX, pad, cy, W-pad-pad, 44, Text1); box->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER); box->labelfont(FL_HELVETICA_BOLD); cy += box->h(); box = new Fl_Box(FL_NO_BOX, pad, cy, W-pad-pad, 186, Text2); box->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER); box->labelfont(FL_HELVETICA); cy += box->h(); #if 0 // website address UI_HyperLink *link = new UI_HyperLink(10, cy, W-20, 30, URL, URL); link->align(FL_ALIGN_CENTER); link->labelsize(20); link->color(color()); cy += link->h() + 16; #endif // finally add an "OK" button int bw = 60 + KF * 10; int bh = 30 + KF * 3; cy += (H - cy - bh) / 2 - 6; Fl_Color but_color = fl_rgb_color(128, 128, 255); Fl_Button *button = new Fl_Button((W-10-bw)/2, cy, bw, bh, "OK!"); button->color(but_color, but_color); button->callback(close_callback, this); end(); } void DLG_AboutText(void) { UI_About::Open(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_nodes.cc0000644000175100017510000002144012647061302016202 0ustar aaptedaapted//------------------------------------------------------------------------ // BUILDING NODES / PLAY THE MAP //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2013 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 "main.h" #include "levels.h" #include "e_loadsave.h" #include "w_wad.h" #include "ui_window.h" #include "ui_nodes.h" #include "glbsp.h" // config items bool glbsp_fast = false; bool glbsp_verbose = false; bool glbsp_warn = false; static glbsp::nodebuildinfo_t nb_info; static volatile glbsp::nodebuildcomms_t nb_comms; static int display_mode = glbsp::DIS_INVALID; static int progress_limit; static char message_buf[MSG_BUF_LEN]; static UI_NodeDialog * dialog; static const char *glbsp_ErrorString(glbsp::glbsp_ret_e ret) { switch (ret) { case glbsp::GLBSP_E_OK: return "OK"; // the arguments were bad/inconsistent. case glbsp::GLBSP_E_BadArgs: return "Bad Arguments"; // the info was bad/inconsistent, but has been fixed case glbsp::GLBSP_E_BadInfoFixed: return "Bad Args (fixed)"; // file errors case glbsp::GLBSP_E_ReadError: return "Read Error"; case glbsp::GLBSP_E_WriteError: return "Write Error"; // building was cancelled case glbsp::GLBSP_E_Cancelled: return "Cancelled by User"; // an unknown error occurred (this is the catch-all value) case glbsp::GLBSP_E_Unknown: default: return "Unknown Error"; } } static void GB_PrintMsg(const char *str, ...) { va_list args; va_start(args, str); vsnprintf(message_buf, MSG_BUF_LEN, str, args); va_end(args); message_buf[MSG_BUF_LEN-1] = 0; dialog->Print(message_buf); LogPrintf("GLBSP: %s", message_buf); } static void GB_FatalError(const char *str, ...) { va_list args; va_start(args, str); vsnprintf(message_buf, MSG_BUF_LEN, str, args); va_end(args); message_buf[MSG_BUF_LEN-1] = 0; FatalError("glBSP Failure:\n\n%s", message_buf); /* NOT REACHED */ } static void GB_Ticker(void) { if (dialog->WantCancel()) { nb_comms.cancelled = TRUE; } } static glbsp::boolean_g GB_DisplayOpen(glbsp::displaytype_e type) { display_mode = type; return TRUE; } static void GB_DisplaySetTitle(const char *str) { /* does nothing */ } static void GB_DisplaySetBarText(int barnum, const char *str) { if (display_mode == glbsp::DIS_BUILDPROGRESS && barnum == 1) { dialog->SetStatus(str); /* UNUSED: // extract map name const char * map_name = str + strlen(str); if (map_name > str) map_name--; // handle the (Hexen) suffix if (*map_name == ')') { while (map_name > str && map_name[1] != '(') map_name--; while (map_name > str && isspace(*map_name)) map_name--; // map_name[1] = 0; } while (map_name > str && !isspace(*map_name)) map_name--; */ } } static void GB_DisplaySetBarLimit(int barnum, int limit) { if (display_mode == glbsp::DIS_BUILDPROGRESS && barnum == 2) { progress_limit = MAX(1, limit); } } static void GB_DisplaySetBar(int barnum, int count) { if (display_mode == glbsp::DIS_BUILDPROGRESS && barnum == 2) { int perc = count * 100.0 / progress_limit; dialog->SetProg(perc); } } static void GB_DisplayClose(void) { /* does nothing */ } static const glbsp::nodebuildfuncs_t build_funcs = { GB_FatalError, GB_PrintMsg, GB_Ticker, GB_DisplayOpen, GB_DisplaySetTitle, GB_DisplaySetBar, GB_DisplaySetBarLimit, GB_DisplaySetBarText, GB_DisplayClose }; static bool DM_BuildNodes(const char *in_name, const char *out_name) { LogPrintf("\n"); display_mode = glbsp::DIS_INVALID; memcpy(&nb_info, &glbsp::default_buildinfo, sizeof(glbsp::default_buildinfo)); memcpy((void*)&nb_comms, &glbsp::default_buildcomms, sizeof(glbsp::nodebuildcomms_t)); nb_info.input_file = glbsp::GlbspStrDup(in_name); nb_info.output_file = glbsp::GlbspStrDup(out_name); nb_info.fast = glbsp_fast ? TRUE : FALSE; nb_info.quiet = glbsp_verbose ? FALSE : TRUE; nb_info.mini_warnings = glbsp_warn ? TRUE : FALSE; nb_info.pack_sides = FALSE; nb_info.force_normal = TRUE; glbsp::glbsp_ret_e ret; ret = glbsp::CheckInfo(&nb_info, &nb_comms); if (ret != glbsp::GLBSP_E_OK) { // check info failure (unlikely to happen) GB_PrintMsg("\n"); GB_PrintMsg("Param Check FAILED: %s\n", glbsp_ErrorString(ret)); GB_PrintMsg("Reason: %s\n\n", nb_comms.message); return false; } ret = glbsp::BuildNodes(&nb_info, &build_funcs, &nb_comms); if (ret == glbsp::GLBSP_E_Cancelled) { GB_PrintMsg("\n"); GB_PrintMsg("Building CANCELLED.\n\n"); return false; } if (ret != glbsp::GLBSP_E_OK) { // build nodes failed GB_PrintMsg("\n"); GB_PrintMsg("Building FAILED: %s\n", glbsp_ErrorString(ret)); GB_PrintMsg("Reason: %s\n\n", nb_comms.message); return false; } return true; } bool CMD_BuildNodes() { if (MadeChanges) { if (DLG_Confirm("Cancel|&Save", "You have unsaved changes, do you want to save them now " "and then build the nodes?") <= 0) { return false; } if (! CMD_SaveMap()) return false; } if (! edit_wad) { DLG_Notify("Cannot build nodes unless you are editing a PWAD."); return false; } if (edit_wad->IsReadOnly()) { DLG_Notify("Cannot build nodes on a read-only file."); return false; } SYS_ASSERT(edit_wad); const char *old_name = StringDup(edit_wad->PathName()); const char *new_name = ReplaceExtension(old_name, "new"); if (MatchExtension(old_name, "new")) { DLG_Notify("Cannot build nodes on a pwad with .NEW extension."); return false; } dialog = new UI_NodeDialog(); dialog->set_modal(); dialog->show(); Fl::check(); bool was_ok = DM_BuildNodes(old_name, new_name); if (was_ok) { MasterDir_Remove(edit_wad); delete edit_wad; edit_wad = NULL; Pwad_name = NULL; // delete the old file, rename the new file if (! FileDelete(old_name)) { #if 0 fprintf(stderr, "DELETE ERROR: %s\n", strerror(errno)); fprintf(stderr, "old_name : %s\n", old_name); #endif FatalError("Unable to replace the pwad with the new version\n" "containing the freshly built nodes, as the original\n" "could not be deleted.\n"); } if (! FileRename(new_name, old_name)) { #if 0 fprintf(stderr, "RENAME ERROR: %s\n", strerror(errno)); fprintf(stderr, "old_name : %s\n", old_name); fprintf(stderr, "new_name : %s\n", new_name); #endif FatalError("Unable to replace the pwad with the new version\n" "containing the freshly built nodes, as a problem\n" "occurred trying to rename the new file.\n" "\n" "Your wad has been left with the .NEW extension.\n"); } GB_PrintMsg("\n"); GB_PrintMsg("Replaced the old file with the new file.\n"); } else { FileDelete(new_name); } if (was_ok) { dialog->Finish_OK(); } else if (nb_comms.cancelled) { dialog->Finish_Cancel(); Status_Set("Cancelled"); } else { dialog->Finish_Error(); Status_Set("Error building nodes"); } while (! dialog->WantClose()) { Fl::wait(0.2); } delete dialog; dialog = NULL; if (was_ok) { // re-open the PWAD LogPrintf("Re-opening the PWAD...\n"); edit_wad = Wad_file::Open(old_name, 'a'); Pwad_name = old_name; if (! edit_wad) FatalError("Unable to re-open the PWAD.\n"); MasterDir_Add(edit_wad); LogPrintf("Re-opening the map (%s)\n", Level_name); LoadLevel(edit_wad, Level_name); Status_Set("Built nodes OK"); } return was_ok; } //------------------------------------------------------------------------ void CMD_TestMap() { if (MadeChanges) { if (DLG_Confirm("Cancel|&Save", "You have unsaved changes, do you want to save them now " "and build the nodes?") <= 0) { return; } if (! CMD_BuildNodes()) return; } if (! edit_wad) { DLG_Notify("Cannot test the map unless you are editing a PWAD."); return; } // FIXME: // if (missing nodes) // DLG_Confirm( "build the nodes now?") char cmd_buffer[FL_PATH_MAX * 2]; // FIXME: use fl_filename_absolute() to get absolute paths snprintf(cmd_buffer, sizeof(cmd_buffer), "cd /home/aapted/doom; ./edge135 -iwad %s -file %s -warp %s", game_wad->PathName(), edit_wad->PathName(), Level_name); LogPrintf("Playing map using the following command:\n"); LogPrintf(" %s\n", cmd_buffer); system(cmd_buffer); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_tile.cc0000644000175100017510000000643412647337106016236 0ustar aaptedaapted//------------------------------------------------------------------------ // Adjustable border (variation of Fl_Tile) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2013 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 "main.h" #include "ui_tile.h" #include "ui_window.h" // // UI_Tile Constructor // UI_Tile::UI_Tile(int X, int Y, int W, int H, const char *what, Fl_Widget * _left, Fl_Widget * _right) : Fl_Tile(X, Y, W, H, what), left(_left), right(_right) { end(); add(left); add(right); right_W = right->w(); limiter = new Fl_Box(FL_NO_BOX, X + 32, Y, W - 32 - MIN_BROWSER_W, H, NULL); limiter->clear_visible(); // prevent this fucker from stealing events add(limiter); resizable(limiter); } // // UI_Tile Destructor // UI_Tile::~UI_Tile() { } void UI_Tile::resize(int X, int Y, int W, int H) { // resize ourself (skip the Fl_Group resize) Fl_Widget::resize(X, Y, W, H); // update limiter limiter->resize(X+32, Y, W - 32 - MIN_BROWSER_W, H); if (find(right) >= children()) { left->resize(X, Y, W, H); return; } // determine the width of the browser right_W = right->w(); if (right_W > w() - 32) right_W = w() - 32; if (right_W < MIN_BROWSER_W) right_W = MIN_BROWSER_W; left->resize(X, Y, W - right_W, H); right->resize(X + W - right_W, Y, right_W, H); } void UI_Tile::ResizeBoth() { right->resize(x() + w() - right_W, y(), right_W, h()); right->show(); right->redraw(); left->resize(x(), y(), w() - right_W, h()); left->redraw(); init_sizes(); } void UI_Tile::ShowRight() { if (find(right) < children()) return; // determine the width of the browser right_W = CLAMP(MIN_BROWSER_W, right_W, w() - 32); add(right); ResizeBoth(); } void UI_Tile::HideRight() { if (find(right) >= children()) return; // remember old width right_W = right->w(); right->hide(); remove(right); left->size(w(), h()); left->redraw(); // widgets in our group (the window) got rearranged, tell FLTK init_sizes(); } void UI_Tile::MinimiseRight() { if (find(right) >= children()) return; right_W = MIN_BROWSER_W; ResizeBoth(); } void UI_Tile::MaximiseRight() { if (find(right) >= children()) return; right_W = w() - 32; ResizeBoth(); } bool UI_Tile::ParseUser(const char ** tokens, int num_tok) { if (strcmp(tokens[0], "br_width") == 0 && num_tok >= 2) { bool was_visible = right->visible(); if (was_visible) HideRight(); right_W = atoi(tokens[1]); if (was_visible) ShowRight(); return true; } return false; } void UI_Tile::WriteUser(FILE *fp) { fprintf(fp, "br_width %d\n", right->visible() ? right->w() : right_W); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/r_render.cc0000644000175100017510000013364512651115736016407 0ustar aaptedaapted//------------------------------------------------------------------------ // 3D RENDERING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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 "main.h" #include #include #include "im_color.h" #include "im_img.h" #include "e_linedef.h" #include "e_things.h" #include "editloop.h" #include "m_game.h" #include "objects.h" #include "x_hover.h" #include "w_loadpic.h" #include "w_rawdef.h" #include "r_render.h" #include "w_flats.h" #include "w_sprite.h" #include "w_texture.h" #include "editloop.h" #include "ui_window.h" #define INFO_BAR_H 30 #define INFO_TEXT_COL fl_rgb_color(192, 192, 192) #define INFO_DIM_COL fl_rgb_color(128, 128, 128) // config items int render_pixel_aspect = 100; // 100 * width / height bool render_high_detail = false; bool render_lock_gravity = false; bool render_missing_bright = true; bool render_unknown_bright = true; struct highlight_3D_info_t { public: int line; // -1 for none int sector; // -1 for none int side; // SIDE_XXX, or -1=floor +1=ceiling query_part_e part; public: highlight_3D_info_t() : line(-1), sector(-1), side(0), part(QRP_Lower) { } highlight_3D_info_t(const highlight_3D_info_t& other) : line(other.line), sector(other.sector), side(other.side), part(other.part) { } void Clear() { line = sector = -1; side = 0; part = QRP_Lower; } bool isSame(const highlight_3D_info_t& other) const { return (line == other.line) && (sector == other.sector) && (side == other.side) && (part == other.part); } }; struct Y_View { public: // player type and position. int p_type, px, py; // view position. float x, y; int z; // standard height above the floor. #define EYE_HEIGHT 41 // view direction. angle is in radians float angle; float Sin, Cos; // screen image. int sw, sh; byte *screen; float aspect_sh; float aspect_sw; // sw * aspect_ratio bool texturing; bool sprites; bool lighting; bool gravity; // when true, walk on ground std::vector thing_sectors; int thsec_sector_num; bool thsec_invalidated; // state for adjusting offsets via the mouse int adjust_ld; int adjust_sd; float adjust_dx, adjust_dx_factor; float adjust_dy, adjust_dy_factor; // current highlighted wotsit highlight_3D_info_t hl; public: Y_View() : p_type(0), screen(NULL), texturing(false), sprites(false), lighting(false), gravity(true), thing_sectors(), thsec_sector_num(0), thsec_invalidated(false), adjust_ld(-1), adjust_sd(-1), hl() { } void SetAngle(float new_ang) { angle = new_ang; if (angle >= 2*M_PI) angle -= 2*M_PI; else if (angle < 0) angle += 2*M_PI; Sin = sin(angle); Cos = cos(angle); } void CalcViewZ() { Objid o; GetNearObject(o, OBJ_SECTORS, int(x), int(y)); int secnum = o.num; if (secnum >= 0) z = Sectors[secnum]->floorh + EYE_HEIGHT; } void CalcAspect() { float window_aspect = float(sw) / float(sh); aspect_sh = sh * window_aspect * (render_pixel_aspect / 133.0); aspect_sw = sw; // things break if these are different } void UpdateScreen(int ow, int oh) { // in low detail mode, setup size so that expansion always covers // our window (i.e. we draw a bit more than we need). int new_sw = render_high_detail ? ow : (ow + 1) / 2; int new_sh = render_high_detail ? oh : (oh + 1) / 2; if (!screen || sw != new_sw || sh != new_sh) { sw = new_sw; sh = new_sh; if (screen) delete[] screen; screen = new byte [sw * sh]; } CalcAspect(); } void ClearScreen() { // color #0 is black (DOOM, Heretic, Hexen) memset(screen, 0, sw * sh); } void FindThingSectors() { thing_sectors.resize(NumThings); for (int i = 0 ; i < NumThings ; i++) { Objid obj; GetNearObject(obj, OBJ_SECTORS, Things[i]->x, Things[i]->y); thing_sectors[i] = obj.num; } thsec_sector_num = NumSectors; thsec_invalidated = false; } inline int R_DoomLightingEquation(int L, float dist) { /* L in the range 0 to 63 */ int min_L = CLAMP(0, 36 - L, 31); int index = (59 - L) - int(1280 / MAX(1, dist)); /* result is colormap index (0 bright .. 31 dark) */ return CLAMP(min_L, index, 31); } byte DoomLightRemap(int light, float dist, byte pixel) { int map = R_DoomLightingEquation(light >> 2, dist); return raw_colormap[map][pixel]; } void PrepareToRender(int ow, int oh) { if (thsec_invalidated || !screen || NumThings != (int)thing_sectors.size() || NumSectors != thsec_sector_num) { FindThingSectors(); } UpdateScreen(ow, oh); if (gravity) CalcViewZ(); } void ClearHighlight() { hl.Clear(); } void FindHighlight() { hl.sector = -1; hl.line = main_win->render->query(&hl.side, &hl.part); if (hl.part == QRP_Floor || hl.part == QRP_Ceil) { // FIXME: get sector hl.line = -1; } } }; static Y_View view; struct DrawSurf { public: enum { K_INVIS = 0, K_FLAT, K_TEXTURE }; int kind; // heights for the surface (h1 is below h2) int h1, h2, tex_h; Img_c *img; img_pixel_t col; /* used when no image */ enum { SOLID_ABOVE = 1, SOLID_BELOW = 2 }; int y_clip; bool fullbright; public: DrawSurf() : kind(K_INVIS), img(NULL), fullbright(false) { } ~DrawSurf() { } int hashed_color(const char *name, const int *cols) { int hash = name[0]*17 + name[2]*7 + name[4]*3 + name[5]*13 + name[6]*47 + name[7]; hash ^= (hash >> 5); int c1 = cols[0]; int c2 = cols[1]; if (c1 > c2) std::swap(c1, c2); if (c1 == c2) return c1; return c1 + hash % (c2 - c1 + 1); } void FindFlat(const char * fname, Sector *sec) { fullbright = false; if (is_sky(fname)) { col = game_info.sky_color; fullbright = true; return; } if (view.texturing) { img = W_GetFlat(fname); if (! img) { img = IM_UnknownFlat(); fullbright = render_unknown_bright; } return; } col = hashed_color(fname, game_info.floor_colors); } void FindTex(const char * tname, LineDef *ld) { fullbright = false; if (view.texturing) { if (tname[0] == '-') { img = IM_MissingTex(); fullbright = render_missing_bright; return; } img = W_GetTexture(tname); if (! img) { img = IM_UnknownTex(); fullbright = render_unknown_bright; } return; } col = hashed_color(tname, game_info.wall_colors); } }; struct DrawWall { public: typedef std::vector vec_t; // when 'th' is >= 0, this is actually a sprite, and 'ld' and // 'sd' will be NULL. Sprites use the info in the 'ceil' surface. int th; LineDef *ld; SideDef *sd; Sector *sec; // which side this wall faces (SIDE_LEFT or SIDE_RIGHT) // for sprites: a copy of the thinginfo flags int side; // lighting for wall, adjusted for N/S and E/W walls int wall_light; // clipped angles float ang1; float delta_ang; // line constants float dist, t_dist; float normal; // distance values (inverted, so they can be lerped) double iz1, iz2; double diz, cur_iz; double mid_iz; // translate coord, for sprite float spr_tx1; // screen X coordinates int sx1, sx2; // for sprites, the remembered open space to clip to int oy1, oy2; /* surfaces */ DrawSurf ceil; DrawSurf upper; DrawSurf lower; DrawSurf floor; DrawSurf rail; #define IZ_EPSILON 1e-6 /* PREDICATES */ struct MidDistCmp { inline bool operator() (const DrawWall * A, const DrawWall * B) const { return A->mid_iz > B->mid_iz; } }; struct DistCmp { inline bool operator() (const DrawWall * A, const DrawWall * B) const { if (fabs(A->cur_iz - B->cur_iz) >= IZ_EPSILON) { // this is the normal case return A->cur_iz > B->cur_iz; } // this case usually occurs at a column where two walls share a vertex. // // hence we check if they actually share a vertex, and if so then // we test whether A is behind B or not -- by checking which side // of B the camera and the other vertex of A are on. if (A->ld && B->ld) { // find the vertex of A _not_ shared with B int A_other = -1; if (B->ld->TouchesVertex(A->ld->start)) A_other = A->ld->end; if (B->ld->TouchesVertex(A->ld->end)) A_other = A->ld->start; if (A_other >= 0) { int ax = Vertices[A_other]->x; int ay = Vertices[A_other]->y; int bx1 = B->ld->Start()->x; int by1 = B->ld->Start()->y; int bx2 = B->ld->End()->x; int by2 = B->ld->End()->y; int cx = (int)view.x; // camera int cy = (int)view.y; int A_side = PointOnLineSide(ax, ay, bx1, by1, bx2, by2); int C_side = PointOnLineSide(cx, cy, bx1, by1, bx2, by2); return (A_side * C_side >= 0); } } // a pretty good fallback: return A->mid_iz > B->mid_iz; } }; struct SX1Cmp { inline bool operator() (const DrawWall * A, const DrawWall * B) const { return A->sx1 < B->sx1; } inline bool operator() (const DrawWall * A, int x) const { return A->sx1 < x; } inline bool operator() (int x, const DrawWall * A) const { return x < A->sx1; } }; struct SX2Less { int x; SX2Less(int _x) : x(_x) { } inline bool operator() (const DrawWall * A) const { return A->sx2 < x; } }; /* methods */ void ComputeWallSurface() { Sector *front = sec; Sector *back = NULL; SideDef *back_sd = (side == SIDE_LEFT) ? ld->Right() : ld->Left(); if (back_sd) back = Sectors[back_sd->sector]; bool sky_upper = back && is_sky(front->CeilTex()) && is_sky(back->CeilTex()); bool self_ref = (front == back) ? true : false; if ((front->ceilh > view.z || is_sky(front->CeilTex())) && ! sky_upper && ! self_ref) { ceil.kind = DrawSurf::K_FLAT; ceil.h1 = front->ceilh; ceil.h2 = +99999; ceil.tex_h = ceil.h1; ceil.y_clip = DrawSurf::SOLID_ABOVE; ceil.FindFlat(front->CeilTex(), front); } if (front->floorh < view.z && ! self_ref) { floor.kind = DrawSurf::K_FLAT; floor.h1 = -99999; floor.h2 = front->floorh; floor.tex_h = floor.h2; floor.y_clip = DrawSurf::SOLID_BELOW; floor.FindFlat(front->FloorTex(), front); } if (! back) { /* ONE-sided line */ lower.kind = DrawSurf::K_TEXTURE; lower.h1 = front->floorh; lower.h2 = front->ceilh; lower.y_clip = DrawSurf::SOLID_ABOVE | DrawSurf::SOLID_BELOW; lower.FindTex(sd->MidTex(), ld); if (lower.img && (ld->flags & MLF_LowerUnpegged)) lower.tex_h = lower.h1 + lower.img->height(); else lower.tex_h = lower.h2; lower.tex_h += sd->y_offset; return; } /* TWO-sided line */ if (back->ceilh < front->ceilh && ! sky_upper && ! self_ref) { upper.kind = DrawSurf::K_TEXTURE; upper.h1 = back->ceilh; upper.h2 = front->ceilh; upper.y_clip = DrawSurf::SOLID_ABOVE; upper.FindTex(sd->UpperTex(), ld); if (upper.img && ! (ld->flags & MLF_UpperUnpegged)) upper.tex_h = upper.h1 + upper.img->height(); else upper.tex_h = upper.h2; upper.tex_h += sd->y_offset; } if (back->floorh > front->floorh && ! self_ref) { lower.kind = DrawSurf::K_TEXTURE; lower.h1 = front->floorh; lower.h2 = back->floorh; lower.y_clip = DrawSurf::SOLID_BELOW; lower.FindTex(sd->LowerTex(), ld); if (ld->flags & MLF_LowerUnpegged) lower.tex_h = front->ceilh; else lower.tex_h = lower.h2; lower.tex_h += sd->y_offset; } /* Mid-Masked texture */ if (! view.texturing) return; if (! isalnum(sd->MidTex()[0])) return; rail.FindTex(sd->MidTex(), ld); if (! rail.img) return; int c_h = MIN(front->ceilh, back->ceilh); int f_h = MAX(front->floorh, back->floorh); int r_h = rail.img->height(); if (f_h >= c_h) return; if (ld->flags & MLF_LowerUnpegged) { rail.h1 = f_h + sd->y_offset; rail.h2 = rail.h1 + r_h; } else { rail.h2 = c_h + sd->y_offset; rail.h1 = rail.h2 - r_h; } rail.kind = DrawSurf::K_TEXTURE; rail.y_clip = 0; rail.tex_h = rail.h2; // clip railing, unless sectors on both sides are identical or // we have a sky upper if (! (sky_upper || (back->ceilh == front->ceilh && back->ceil_tex == front->ceil_tex && back->light == front->light))) { rail.h2 = MIN(c_h, rail.h2); } if (! (back->floorh == front->floorh && back->floor_tex == front->floor_tex && back->light == front->light)) { rail.h1 = MAX(f_h, rail.h1); } } }; struct RenderLine { short sx1, sy1, sx2, sy2; Fl_Color color; }; struct RendInfo { public: // complete set of walls/sprites to draw. DrawWall::vec_t walls; // the active list. Pointers here are always duplicates of ones in // the walls list (no need to 'delete' any of them). DrawWall::vec_t active; // query state int query_mode; // 0 for normal render int query_sx; int query_sy; DrawWall *query_wall; // the hit wall query_part_e query_part; // the part of the hit wall // inverse distances over X range, 0 when empty. std::vector depth_x; int open_y1; int open_y2; #define Y_SLOPE 1.70 // remembered lines for drawing highlight (etc) std::vector hl_lines; // saved offsets for mouse adjustment mode int saved_x_offset; int saved_y_offset; private: static void DeleteWall(DrawWall *P) { delete P; } public: RendInfo() : walls(), active(), query_mode(0), depth_x(), hl_lines() { } ~RendInfo() { std::for_each(walls.begin(), walls.end(), DeleteWall); walls.clear (); active.clear (); } void InitDepthBuf (int width) { depth_x.resize(width); std::fill_n(depth_x.begin(), width, 0); } void AddRenderLine(int sx1, int sy1, int sx2, int sy2, Fl_Color color) { if (! render_high_detail) { sx1 *= 2; sy1 *= 2; sx2 *= 2; sy2 *= 2; } RenderLine new_line; new_line.sx1 = sx1; new_line.sy1 = sy1; new_line.sx2 = sx2; new_line.sy2 = sy2; new_line.color = color; hl_lines.push_back(new_line); } void SaveOffsets() { if (view.adjust_ld < 0) return; SideDef *SD = SideDefs[view.adjust_sd]; saved_x_offset = SD->x_offset; saved_y_offset = SD->y_offset; // change it temporarily (just for the render) SD->x_offset += (int)view.adjust_dx; SD->y_offset += (int)view.adjust_dy; } void RestoreOffsets() { if (view.adjust_ld < 0) return; SideDef *SD = SideDefs[view.adjust_sd]; SD->x_offset = saved_x_offset; SD->y_offset = saved_y_offset; } static inline float PointToAngle(float x, float y) { if (-0.01 < x && x < 0.01) return (y > 0) ? M_PI/2 : (3 * M_PI/2); float angle = atan2(y, x); if (angle < 0) angle += 2*M_PI; return angle; } static inline int AngleToX(float ang) { float t = tan(M_PI/2 - ang); int x = int(view.aspect_sw * t); x = (view.sw + x) / 2; if (x < 0) x = 0; else if (x > view.sw) x = view.sw; return x; } static inline float XToAngle(int x) { x = x * 2 - view.sw; float ang = M_PI/2 + atan(x / view.aspect_sw); if (ang < 0) ang = 0; else if (ang > M_PI) ang = M_PI; return ang; } static inline int DeltaToX(double iz, float tx) { int x = int(view.aspect_sw * tx * iz); x = (x + view.sw) / 2; return x; } static inline float XToDelta(int x, double iz) { x = x * 2 - view.sw; float tx = x / iz / view.aspect_sw; return tx; } static inline int DistToY(double iz, int sec_h) { if (sec_h > 32770) return -9999; if (sec_h < -32770) return +9999; sec_h -= view.z; int y = int(view.aspect_sh * sec_h * iz * Y_SLOPE); y = (view.sh - y) / 2; return y; } static inline float YToDist(int y, int sec_h) { sec_h -= view.z; y = view.sh - y * 2; if (y == 0) return 999999; return view.aspect_sh * sec_h * Y_SLOPE / y; } static inline float YToSecH(int y, double iz) { y = y * 2 - view.sh; return view.z - (float(y) / view.aspect_sh / iz / Y_SLOPE); } void AddLine(int ld_index) { LineDef *ld = LineDefs[ld_index]; if (! is_vertex(ld->start) || ! is_vertex(ld->end)) return; if (! ld->Right()) return; float x1 = ld->Start()->x - view.x; float y1 = ld->Start()->y - view.y; float x2 = ld->End()->x - view.x; float y2 = ld->End()->y - view.y; float tx1 = x1 * view.Sin - y1 * view.Cos; float ty1 = x1 * view.Cos + y1 * view.Sin; float tx2 = x2 * view.Sin - y2 * view.Cos; float ty2 = x2 * view.Cos + y2 * view.Sin; // reject line if complete behind viewplane if (ty1 <= 0 && ty2 <= 0) return; float angle1 = PointToAngle(tx1, ty1); float angle2 = PointToAngle(tx2, ty2); float span = angle1 - angle2; if (span < 0) span += 2*M_PI; int side = SIDE_RIGHT; if (span >= M_PI) side = SIDE_LEFT; // ignore the line when there is no facing sidedef SideDef *sd = (side == SIDE_LEFT) ? ld->Left() : ld->Right(); if (! sd) return; if (side == SIDE_LEFT) { float tmp = angle1; angle1 = angle2; angle2 = tmp; } // clip angles to view volume float base_ang = angle1; float leftclip = (3 * M_PI / 4); float rightclip = M_PI / 4; float tspan1 = angle1 - rightclip; float tspan2 = leftclip - angle2; if (tspan1 < 0) tspan1 += 2*M_PI; if (tspan2 < 0) tspan2 += 2*M_PI; if (tspan1 > M_PI/2) { // Totally off the left edge? if (tspan2 >= M_PI) return; angle1 = leftclip; } if (tspan2 > M_PI/2) { // Totally off the left edge? if (tspan1 >= M_PI) return; angle2 = rightclip; } // convert angles to on-screen X positions int sx1 = AngleToX(angle1); int sx2 = AngleToX(angle2) - 1; if (sx1 > sx2) return; // optimisation for query mode if (query_mode && (sx2 < query_sx || sx1 > query_sx)) return; // compute distance from eye to wall float wdx = x2 - x1; float wdy = y2 - y1; float wlen = sqrt(wdx * wdx + wdy * wdy); float dist = fabs((y1 * wdx / wlen) - (x1 * wdy / wlen)); if (dist < 0.01) return; // compute normal of wall (translated coords) float normal; if (side == SIDE_LEFT) normal = PointToAngle(ty2 - ty1, tx1 - tx2); else normal = PointToAngle(ty1 - ty2, tx2 - tx1); // compute inverse distances double iz1 = cos(normal - angle1) / dist / cos(M_PI/2 - angle1); double iz2 = cos(normal - angle2) / dist / cos(M_PI/2 - angle2); double diz = (iz2 - iz1) / MAX(1, sx2 - sx1); // create drawwall structure DrawWall *dw = new DrawWall; dw->th = -1; dw->ld = ld; dw->sd = sd; dw->sec = sd->SecRef(); dw->side = side; dw->wall_light = dw->sec->light; if (ld->Start()->x == ld->End()->x) dw->wall_light += 16; else if (ld->Start()->y == ld->End()->y) dw->wall_light -= 16; dw->ang1 = angle1; dw->delta_ang = angle1 + XToAngle(sx1) - normal; dw->dist = dist; dw->normal = normal; dw->t_dist = tan(base_ang - normal) * dist; dw->iz1 = iz1; dw->iz2 = iz2; dw->diz = diz; dw->mid_iz = iz1 + (sx2 - sx1 + 1) * diz / 2; dw->sx1 = sx1; dw->sx2 = sx2; walls.push_back(dw); } void AddThing(int th_index) { Thing *th = Things[th_index]; const thingtype_t *info = M_GetThingType(th->type); float x = th->x - view.x; float y = th->y - view.y; float tx = x * view.Sin - y * view.Cos; float ty = x * view.Cos + y * view.Sin; // reject sprite if complete behind viewplane if (ty < 4) return; Img_c *sprite = W_GetSprite(th->type); if (! sprite) // TODO: show a question mark (same color as on 2D map) return; float tx1 = tx - sprite->width() / 2.0; float tx2 = tx + sprite->width() / 2.0; double iz = 1 / ty; int sx1 = DeltaToX(iz, tx1); int sx2 = DeltaToX(iz, tx2) - 1; if (sx1 < 0) sx1 = 0; if (sx2 >= view.sw) sx2 = view.sw - 1; if (sx1 > sx2) return; int thsec = view.thing_sectors[th_index]; int h1, h2; if (info && (info->flags & THINGDEF_CEIL)) { // IOANCH 9/2015: also add z h2 = (is_sector(thsec) ? Sectors[thsec]->ceilh : 192) - th->z; h1 = h2 - sprite->height(); } else { h1 = (is_sector(thsec) ? Sectors[thsec]->floorh : 0) + th->z; h2 = h1 + sprite->height(); } // create drawwall structure DrawWall *dw = new DrawWall; dw->th = th_index; dw->ld = NULL; dw->sd = NULL; dw->sec = NULL; dw->side = info ? info->flags : 0; dw->spr_tx1 = tx1; dw->ang1 = 0; dw->iz1 = dw->mid_iz = iz; dw->diz = 0; dw->sx1 = sx1; dw->sx2 = sx2; dw->ceil.img = sprite; dw->ceil.h1 = h1; dw->ceil.h2 = h2; walls.push_back(dw); } void HighlightWall(DrawWall *dw) { if (dw->side != view.hl.side) return; int h1, h2; if (! dw->ld->TwoSided()) { h1 = dw->sd->SecRef()->floorh; h2 = dw->sd->SecRef()->ceilh; } else { const Sector *front = dw->ld->Right()->SecRef(); const Sector *back = dw->ld-> Left()->SecRef(); if (view.hl.part == QRP_Lower) { h1 = MIN(front->floorh, back->floorh); h2 = MAX(front->floorh, back->floorh); } else /* part == QRP_Upper */ { h1 = MIN(front->ceilh, back->ceilh); h2 = MAX(front->ceilh, back->ceilh); } } int x1 = dw->sx1 - 1; int x2 = dw->sx2 + 1; int ly1 = DistToY(dw->iz1, h2); int ly2 = DistToY(dw->iz1, h1); int ry1 = DistToY(dw->iz2, h2); int ry2 = DistToY(dw->iz2, h1); AddRenderLine(x1, ly1, x1, ly2, HI_COL); AddRenderLine(x2, ry1, x2, ry2, HI_COL); AddRenderLine(x1, ly1, x2, ry1, HI_COL); AddRenderLine(x1, ly2, x2, ry2, HI_COL); } void ComputeSurfaces() { const LineDef *hl_linedef = is_linedef(view.hl.line) ? LineDefs[view.hl.line] : NULL; DrawWall::vec_t::iterator S; for (S = walls.begin() ; S != walls.end() ; S++) { if ((*S)->ld) { (*S)->ComputeWallSurface(); if ((*S)->ld == hl_linedef) HighlightWall(*S); } } } void ClipSolids() { // perform a rough depth sort of the walls and sprites. std::sort(walls.begin(), walls.end(), DrawWall::MidDistCmp()); // go forwards, from closest to furthest away DrawWall::vec_t::iterator S; for (S = walls.begin() ; S != walls.end() ; S++) { DrawWall *dw = (*S); if (! dw) continue; int one_sided = dw->ld && ! dw->ld->Left(); int vis_count = dw->sx2 - dw->sx1 + 1; for (int x = dw->sx1 ; x <= dw->sx2 ; x++) { double iz = dw->iz1 + (dw->diz * (x - dw->sx1)); if (iz < depth_x[x]) vis_count--; else if (one_sided) depth_x[x] = iz; } if (vis_count == 0) { delete dw; (*S) = NULL; } } // remove null pointers S = std::remove(walls.begin(), walls.end(), (DrawWall *) NULL); walls.erase(S, walls.end()); } void RenderFlatColumn(DrawWall *dw, DrawSurf& surf, int x, int y1, int y2) { img_pixel_t *buf = view.screen; img_pixel_t *wbuf = surf.img->wbuf (); int tw = surf.img->width(); int th = surf.img->height(); float ang = XToAngle(x); float modv = cos(ang - M_PI/2); float t_cos = cos(M_PI + -view.angle + ang) / modv; float t_sin = sin(M_PI + -view.angle + ang) / modv; buf += x + y1 * view.sw; int light = dw->sec->light; for ( ; y1 <= y2 ; y1++, buf += view.sw) { float dist = YToDist(y1, surf.tex_h); int tx = int( view.x - t_sin * dist) & (tw - 1); int ty = int(-view.y + t_cos * dist) & (th - 1); *buf = wbuf[ty * tw + tx]; if (view.lighting && ! surf.fullbright) *buf = view.DoomLightRemap(light, dist, *buf); } } void RenderTexColumn(DrawWall *dw, DrawSurf& surf, int x, int y1, int y2) { img_pixel_t *buf = view.screen; img_pixel_t *wbuf = surf.img->wbuf (); int tw = surf.img->width(); int th = surf.img->height(); int light = dw->wall_light; float dist = 1.0 / dw->cur_iz; /* compute texture X coord */ float cur_ang = dw->delta_ang - XToAngle(x); int tx = int(dw->t_dist - tan(cur_ang) * dw->dist); tx = (dw->sd->x_offset + tx) & (tw - 1); /* compute texture Y coords */ float hh = surf.tex_h - YToSecH(y1, dw->cur_iz); float dh = surf.tex_h - YToSecH(y2, dw->cur_iz); dh = (dh - hh) / MAX(1, y2 - y1); hh += 0.2; buf += x + y1 * view.sw; wbuf += tx; for ( ; y1 <= y2 ; y1++, hh += dh, buf += view.sw) { int ty = int(floor(hh)) % th; // handle negative values (use % twice) ty = (ty + th) % th; img_pixel_t pix = wbuf[ty * tw]; if (pix == TRANS_PIXEL) continue; if (view.lighting && ! surf.fullbright) *buf = view.DoomLightRemap(light, dist, pix); else *buf = pix; } } void SolidFlatColumn(DrawWall *dw, DrawSurf& surf, int x, int y1, int y2) { img_pixel_t *buf = view.screen; buf += x + y1 * view.sw; int light = dw->sec->light; for ( ; y1 <= y2 ; y1++, buf += view.sw) { float dist = YToDist(y1, surf.tex_h); if (view.lighting && ! surf.fullbright) *buf = view.DoomLightRemap(light, dist, game_info.floor_colors[1]); else *buf = surf.col; } } void SolidTexColumn(DrawWall *dw, DrawSurf& surf, int x, int y1, int y2) { int light = dw->wall_light; float dist = 1.0 / dw->cur_iz; img_pixel_t *buf = view.screen; buf += x + y1 * view.sw; for ( ; y1 <= y2 ; y1++, buf += view.sw) { if (view.lighting && ! surf.fullbright) *buf = view.DoomLightRemap(light, dist, game_info.wall_colors[1]); else *buf = surf.col; } } void HighlightColumn(int x, int y1, int y2, byte col) { img_pixel_t *buf = view.screen; buf += x + y1 * view.sw; for ( ; y1 <= y2 ; y1++, buf += view.sw) *buf = col; } inline void RenderWallSurface(DrawWall *dw, DrawSurf& surf, int x, query_part_e part) { if (surf.kind == DrawSurf::K_INVIS) return; int y1 = DistToY(dw->cur_iz, surf.h2); int y2 = DistToY(dw->cur_iz, surf.h1) - 1; if (y1 < open_y1) y1 = open_y1; if (y2 > open_y2) y2 = open_y2; if (y1 > y2) return; /* clip the open region */ if (surf.y_clip & DrawSurf::SOLID_ABOVE) if (open_y1 < y2) open_y1 = y2; if (surf.y_clip & DrawSurf::SOLID_BELOW) if (open_y2 > y1) open_y2 = y1; /* query mode : is mouse over this wall part? */ if (query_mode) { if (y1 <= query_sy && query_sy <= y2) { query_wall = dw; query_part = part; } return; } /* fill pixels */ if (! surf.img) { if (surf.kind == DrawSurf::K_FLAT) SolidFlatColumn(dw, surf, x, y1, y2); else SolidTexColumn(dw, surf, x, y1, y2); } else switch (surf.kind) { case DrawSurf::K_FLAT: RenderFlatColumn(dw, surf, x, y1, y2); break; case DrawSurf::K_TEXTURE: RenderTexColumn(dw, surf, x, y1, y2); break; } } inline void RenderSprite(DrawWall *dw, int x) { int y1 = DistToY(dw->cur_iz, dw->ceil.h2); int y2 = DistToY(dw->cur_iz, dw->ceil.h1) - 1; if (y1 < dw->oy1) y1 = dw->oy1; if (y2 > dw->oy2) y2 = dw->oy2; if (y1 > y2) return; /* fill pixels */ img_pixel_t *buf = view.screen; img_pixel_t *wbuf = dw->ceil.img->wbuf (); int tw = dw->ceil.img->width(); int th = dw->ceil.img->height(); int tx = int(XToDelta(x, dw->cur_iz) - dw->spr_tx1); if (tx < 0 || tx >= tw) return; float hh = dw->ceil.h2 - YToSecH(y1, dw->cur_iz); float dh = dw->ceil.h2 - YToSecH(y2, dw->cur_iz); dh = (dh - hh) / MAX(1, y2 - y1); buf += x + y1 * view.sw; wbuf += tx; int thsec = view.thing_sectors[dw->th]; int light = is_sector(thsec) ? Sectors[thsec]->light : 255; float dist = 1.0 / dw->cur_iz; for ( ; y1 <= y2 ; y1++, hh += dh, buf += view.sw) { int ty = int(hh); if (ty < 0 || ty >= th) continue; img_pixel_t pix = wbuf[ty * tw]; if (pix == TRANS_PIXEL) continue; if (dw->side & THINGDEF_INVIS) { *buf = raw_colormap[14][*buf]; continue; } *buf = pix; if (view.lighting && ! (dw->side & THINGDEF_LIT)) *buf = view.DoomLightRemap(light, dist, *buf); } } inline void RenderMidMasker(DrawWall *dw, DrawSurf& surf, int x) { if (surf.kind == DrawSurf::K_INVIS) return; if (! surf.img) return; int y1 = DistToY(dw->cur_iz, surf.h2); int y2 = DistToY(dw->cur_iz, surf.h1) - 1; if (y1 < dw->oy1) y1 = dw->oy1; if (y2 > dw->oy2) y2 = dw->oy2; if (y1 > y2) return; /* fill pixels */ RenderTexColumn(dw, surf, x, y1, y2); } void UpdateActiveList(int x) { DrawWall::vec_t::iterator S, E, P; bool changes = false; // remove walls that have finished. S = active.begin(); E = active.end(); S = std::remove_if (S, E, DrawWall::SX2Less(x)); if (S != E) { active.erase(S, E); changes = true; } // add new walls that start in this column. S = walls.begin(); E = walls.end(); S = std::lower_bound(S, E, x, DrawWall::SX1Cmp()); E = std::upper_bound(S, E, x, DrawWall::SX1Cmp()); if (S != E) changes = true; for ( ; S != E ; S++) { active.push_back(*S); } // calculate new depth values S = active.begin(); E = active.end(); for (P=S ; (P != E) ; P++) { DrawWall *dw = (*P); dw->cur_iz = dw->iz1 + dw->diz * (x - dw->sx1); if (P != S && (*(P-1))->cur_iz < dw->cur_iz + IZ_EPSILON) changes = true; } // if there are changes, re-sort the active list... if (changes) { std::sort(active.begin(), active.end(), DrawWall::DistCmp()); } } void RenderWalls() { // sort walls by their starting column, to allow binary search. std::sort(walls.begin(), walls.end(), DrawWall::SX1Cmp()); active.clear (); for (int x=0 ; x < view.sw ; x++) { // clear vertical depth buffer open_y1 = 0; open_y2 = view.sh - 1; UpdateActiveList(x); // in query mode, only care about a single column if (query_mode && x != query_sx) continue; // render, front to back DrawWall::vec_t::iterator S, E, P; S = active.begin(); E = active.end(); for (P=S ; P != E ; P++) { DrawWall *dw = (*P); // for things, just remember the open space { dw->oy1 = open_y1; dw->oy2 = open_y2; } if (dw->th >= 0) continue; RenderWallSurface(dw, dw->ceil, x, QRP_Ceil); RenderWallSurface(dw, dw->floor, x, QRP_Floor); RenderWallSurface(dw, dw->upper, x, QRP_Upper); RenderWallSurface(dw, dw->lower, x, QRP_Lower); if (open_y1 >= open_y2) break; } // now render things, back to front // (mid-masked textures are done here too) if (P == E) P--; for ( ; P != (S-1) ; P--) { DrawWall *dw = (*P); if (dw->th >= 0) RenderSprite(dw, x); else RenderMidMasker(dw, dw->rail, x); } } } void DoRender3D() { view.ClearScreen(); InitDepthBuf(view.sw); SaveOffsets(); for (int i=0 ; i < NumLineDefs ; i++) AddLine(i); if (view.sprites && ! query_mode) for (int k=0 ; k < NumThings ; k++) AddThing(k); ClipSolids(); ComputeSurfaces(); RenderWalls(); RestoreOffsets(); } void DoQuery(int sx, int sy) { query_mode = 1; query_sx = sx; query_sy = sy; query_wall = NULL; DoRender3D(); query_mode = 0; } }; static Thing *FindPlayer(int typenum) { // need to search backwards (to handle Voodoo dolls properly) for (int i = NumThings-1 ; i >= 0 ; i--) if (Things[i]->type == typenum) return Things[i]; return NULL; // not found } //------------------------------------------------------------------------ static Thing *player; UI_Render3D::UI_Render3D(int X, int Y, int W, int H) : Fl_Widget(X, Y, W, H) { } UI_Render3D::~UI_Render3D() { } void UI_Render3D::draw() { int ox = x(); int oy = y() + INFO_BAR_H; int ow = w(); int oh = h() - INFO_BAR_H; view.PrepareToRender(ow, oh); RendInfo rend; rend.DoRender3D(); if (render_high_detail) BlitHires(ox, oy, ow, oh); else BlitLores(ox, oy, ow, oh); // draw the highlight (etc) for (unsigned int k = 0 ; k < rend.hl_lines.size() ; k++) { RenderLine& line = rend.hl_lines[k]; fl_color(line.color); fl_line(ox + line.sx1, oy + line.sy1, ox + line.sx2, oy + line.sy2); } DrawInfoBar(); } int UI_Render3D::query(int *side, query_part_e *part) { int ow = w(); int oh = h(); view.PrepareToRender(ow, oh); int sx = Fl::event_x() - x(); int sy = Fl::event_y() - y(); if (! render_high_detail) { sx = sx / 2; sy = sy / 2; } RendInfo rend; rend.DoQuery(sx, sy); if (rend.query_wall) { *side = rend.query_wall->side; *part = rend.query_part; // ouch -- fix? for (int n = 0 ; n < NumLineDefs ; n++) if (rend.query_wall->ld == LineDefs[n]) return n; } // nothing was hit return -1; } void UI_Render3D::BlitHires(int ox, int oy, int ow, int oh) { for (int ry = 0 ; ry < view.sh ; ry++) { u8_t line_rgb[view.sw * 3]; u8_t *dest = line_rgb; u8_t *dest_end = line_rgb + view.sw * 3; const byte *src = view.screen + ry * view.sw; for ( ; dest < dest_end ; dest += 3, src++) { u32_t col = palette[*src]; dest[0] = RGB_RED(col); dest[1] = RGB_GREEN(col); dest[2] = RGB_BLUE(col); } fl_draw_image(line_rgb, ox, oy+ry, view.sw, 1); } } void UI_Render3D::BlitLores(int ox, int oy, int ow, int oh) { for (int ry = 0 ; ry < view.sh ; ry++) { const byte *src = view.screen + ry * view.sw; // if destination width is odd, we store an extra pixel here u8_t line_rgb[(ow + 1) * 3]; u8_t *dest = line_rgb; u8_t *dest_end = line_rgb + ow * 3; for (; dest < dest_end ; dest += 6, src++) { u32_t col = palette[*src]; dest[0] = RGB_RED(col); dest[1] = RGB_GREEN(col); dest[2] = RGB_BLUE(col); dest[3] = dest[0]; dest[4] = dest[1]; dest[5] = dest[2]; } fl_draw_image(line_rgb, ox, oy + ry*2, ow, 1); if (ry * 2 + 1 < oh) { fl_draw_image(line_rgb, ox, oy + ry*2 + 1, ow, 1); } } } void UI_Render3D::DrawInfoBar() { int cx = x(); int cy = y(); fl_push_clip(x(), cy, w(), INFO_BAR_H); fl_color(FL_BLACK); fl_rectf(x(), cy, w(), INFO_BAR_H); fl_color(INFO_TEXT_COL); cx += 10; cy += 20; fl_font(FL_COURIER, 16); DrawNumber(cx, cy, "x", I_ROUND(view.x), -5); DrawNumber(cx, cy, "y", I_ROUND(view.y), -5); DrawNumber(cx, cy, "z", view.z, -4); int ang = I_ROUND(view.angle * 180 / M_PI); if (ang < 0) ang += 360; DrawNumber(cx, cy, "ang", ang, 3); cx += 12; DrawFlag(cx, cy, view.gravity, "GRAVITY", "gravity"); fl_color(INFO_TEXT_COL); DrawNumber(cx, cy, "gam", usegamma, 1); cx += 10; DrawFlag(cx, cy, !view.texturing, "!Tx", "tex"); DrawFlag(cx, cy, !view.lighting, "!Lt", "lit"); DrawFlag(cx, cy, !view.sprites, "!Ob", "obj"); fl_pop_clip(); } void UI_Render3D::DrawNumber(int& cx, int& cy, const char *label, int value, int size) { char buffer[256]; // negative size means we require a sign if (size < 0) sprintf(buffer, "%s:%-+*d ", label, -size + 1, value); else sprintf(buffer, "%s:%-*d ", label, size, value); fl_draw(buffer, cx, cy); cx = cx + fl_width(buffer); } void UI_Render3D::DrawFlag(int& cx, int& cy, bool value, const char *label_on, const char *label_off) { const char *label = value ? label_on : label_off; fl_color(value ? INFO_TEXT_COL : INFO_DIM_COL); fl_draw(label, cx, cy); cx = cx + fl_width(label) + 20; } int UI_Render3D::handle(int event) { switch (event) { case FL_FOCUS: return 1; case FL_ENTER: // we greedily grab the focus if (Fl::focus() != this) take_focus(); return 1; case FL_KEYDOWN: case FL_KEYUP: case FL_SHORTCUT: return Editor_RawKey(event); case FL_PUSH: case FL_RELEASE: return Editor_RawButton(event); case FL_MOUSEWHEEL: return Editor_RawWheel(event); case FL_DRAG: case FL_MOVE: return Editor_RawMouse(event); default: break; // pass it on } return Fl_Widget::handle(event); } void Render3D_Setup() { if (! view.p_type) { view.p_type = THING_PLAYER1; view.px = 99999; } player = FindPlayer(view.p_type); if (! player) { if (view.p_type != THING_DEATHMATCH) view.p_type = THING_DEATHMATCH; player = FindPlayer(view.p_type); } if (player && (view.px != player->x || view.py != player->y)) { // if player moved, re-create view parameters view.x = view.px = player->x; view.y = view.py = player->y; view.CalcViewZ(); view.SetAngle(player->angle * M_PI / 180.0); } else { view.x = 0; view.y = 0; view.z = 64; view.SetAngle(0); } /* create image */ view.sw = -1; view.sh = -1; view.texturing = true; view.sprites = true; view.lighting = true; } void Render3D_MouseMotion(int x, int y, keycode_t mod) { highlight_3D_info_t old(view.hl); view.FindHighlight(); if (old.isSame(view.hl)) return; main_win->render->redraw(); } void Render3D_Wheel(int dx, int dy, keycode_t mod) { float speed = 48; // TODO: CONFIG ITEM if (mod == MOD_SHIFT) speed = MAX(1, speed / 8); else if (mod == MOD_COMMAND) speed *= 4; view.x += speed * (view.Cos * dy + view.Sin * dx); view.y += speed * (view.Sin * dy - view.Cos * dx); RedrawMap(); } void Render3D_RBScroll(int dx, int dy, keycode_t mod) { // we separate the movement into either turning or moving up/down // (never both at the same time : CONFIG IT THOUGH). bool force_one_dir = true; if (force_one_dir) { if (abs(dx) >= abs(dy)) dy = 0; else dx = 0; } if (mod == MOD_ALT) // strafing { if (dx) { view.x += view.Sin * dx * 2; view.y -= view.Cos * dx * 2; dx = 0; } /* dy = -dy; // CONFIG OPT if (dy) { view.x += view.Cos * dy * 2; view.y += view.Sin * dy * 2; dy = 0; } */ } if (dx) { int speed = 12; // TODO: CONFIG ITEM [also: reverse] if (mod == MOD_SHIFT) speed = MAX(1, speed / 4); else if (mod == MOD_COMMAND) speed *= 3; double d_ang = dx * M_PI * speed / (1440.0*4.0); view.SetAngle(view.angle - d_ang); } if (dy && ! (render_lock_gravity && view.gravity)) { int speed = 12; // TODO: CONFIG ITEM [also: reverse] if (mod == MOD_SHIFT) speed = MAX(1, speed / 4); else if (mod == MOD_COMMAND) speed *= 3; view.z -= dy * speed / 16; view.gravity = false; } RedrawMap(); } void Render3D_AdjustOffsets(int mode, int dx, int dy) { // started? if (mode < 0) { // find the line / side to adjust if (! is_linedef(view.hl.line)) return; if (view.hl.part == QRP_Floor || view.hl.part == QRP_Ceil) return; const LineDef *L = LineDefs[view.hl.line]; int sd = (view.hl.side < 0) ? L->left : L->right; if (sd < 0) // WTF? return; // OK view.adjust_ld = view.hl.line; view.adjust_sd = sd; // reset offset deltas to 0 view.adjust_dx = 0; view.adjust_dy = 0; float dist = ApproxDistToLineDef(L, view.x, view.y); if (dist < 20) dist = 20; // TODO: take perspective into account (angled wall --> reduce dx_factor) view.adjust_dx_factor = dist / view.aspect_sw; view.adjust_dy_factor = dist / view.aspect_sh / Y_SLOPE; Editor_SetAction(ACT_ADJUST_OFS); return; } if (edit.action != ACT_ADJUST_OFS) return; SYS_ASSERT(view.adjust_ld >= 0); // finished? if (mode > 0) { // apply the offset deltas now dx = (int)view.adjust_dx; dy = (int)view.adjust_dy; if (dx || dy) { const SideDef * SD = SideDefs[view.adjust_sd]; BA_Begin(); BA_ChangeSD(view.adjust_sd, SideDef::F_X_OFFSET, SD->x_offset + dx); BA_ChangeSD(view.adjust_sd, SideDef::F_Y_OFFSET, SD->y_offset + dy); BA_End(); } view.adjust_ld = -1; view.adjust_sd = -1; Editor_ClearAction(); return; } if (dx == 0 && dy == 0) return; bool force_one_dir = true; if (force_one_dir) { if (abs(dx) >= abs(dy)) dy = 0; else dx = 0; } keycode_t mod = Fl::event_state() & MOD_ALL_MASK; float factor = (mod == MOD_SHIFT) ? 0.25 : 1.0; if (render_high_detail) factor = factor * 2.0; view.adjust_dx -= dx * factor * view.adjust_dx_factor; view.adjust_dy -= dy * factor * view.adjust_dy_factor; RedrawMap(); } void Render3D_Term() { /* all done */ delete view.screen; view.screen = NULL; } void Render3D_SetCameraPos(int new_x, int new_y) { view.x = new_x; view.y = new_y; view.CalcViewZ(); } void Render3D_GetCameraPos(int *x, int *y, float *angle) { *x = view.x; *y = view.y; // convert angle from radians to degrees *angle = view.angle * 180.0 / M_PI; } bool Render3D_ParseUser(const char ** tokens, int num_tok) { if (strcmp(tokens[0], "camera") == 0 && num_tok >= 5) { view.x = atof(tokens[1]); view.y = atof(tokens[2]); view.z = atoi(tokens[3]); view.SetAngle(atof(tokens[4])); return true; } if (strcmp(tokens[0], "r_modes") == 0 && num_tok >= 4) { view.texturing = atoi(tokens[1]) ? true : false; view.sprites = atoi(tokens[2]) ? true : false; view.lighting = atoi(tokens[3]) ? true : false; return true; } if (strcmp(tokens[0], "low_detail") == 0 && num_tok >= 2) { // ignored for compatibility return true; } if (strcmp(tokens[0], "gamma") == 0 && num_tok >= 2) { usegamma = MAX(0, atoi(tokens[1])) % 5; W_UpdateGamma(); return true; } return false; } void Render3D_WriteUser(FILE *fp) { fprintf(fp, "camera %1.2f %1.2f %d %1.2f\n", view.x, view.y, view.z, view.angle); fprintf(fp, "r_modes %d %d %d\n", view.texturing ? 1 : 0, view.sprites ? 1 : 0, view.lighting ? 1 : 0); fprintf(fp, "gamma %d\n", usegamma); } //------------------------------------------------------------------------ // COMMAND FUNCTIONS //------------------------------------------------------------------------ void R3D_Forward(void) { int dist = atoi(EXEC_Param[0]); view.x += view.Cos * dist; view.y += view.Sin * dist; RedrawMap(); } void R3D_Backward(void) { int dist = atoi(EXEC_Param[0]); view.x -= view.Cos * dist; view.y -= view.Sin * dist; RedrawMap(); } void R3D_Left(void) { int dist = atoi(EXEC_Param[0]); view.x -= view.Sin * dist; view.y += view.Cos * dist; RedrawMap(); } void R3D_Right(void) { int dist = atoi(EXEC_Param[0]); view.x += view.Sin * dist; view.y -= view.Cos * dist; RedrawMap(); } void R3D_Up(void) { if (view.gravity && render_lock_gravity) { Beep("Gravity is on"); return; } int dist = atoi(EXEC_Param[0]); view.z += dist; view.gravity = false; RedrawMap(); } void R3D_Down(void) { if (view.gravity && render_lock_gravity) { Beep("Gravity is on"); return; } int dist = atoi(EXEC_Param[0]); view.z -= dist; view.gravity = false; RedrawMap(); } void R3D_Turn(void) { float angle = atof(EXEC_Param[0]); // convert to radians angle = angle * M_PI / 180.0; view.SetAngle(view.angle + angle); RedrawMap(); } void R3D_DropToFloor(void) { view.CalcViewZ(); RedrawMap(); } void R3D_Set(void) { const char *var_name = EXEC_Param[0]; const char *value = EXEC_Param[1]; if (! var_name[0]) { Beep("3D_Set: missing var name"); return; } if (! value[0]) { Beep("3D_Set: missing value"); return; } int int_val = atoi(value); bool bool_val = (int_val > 0); if (y_stricmp(var_name, "gamma") == 0) { usegamma = int_val % 5; if (usegamma < 0) usegamma = 0; W_UpdateGamma(); Status_Set("Gamma level %d", usegamma); } else if (y_stricmp(var_name, "tex") == 0) { view.texturing = bool_val; } else if (y_stricmp(var_name, "obj") == 0) { view.sprites = bool_val; view.thsec_invalidated = true; } else if (y_stricmp(var_name, "light") == 0) { view.lighting = bool_val; } else if (y_stricmp(var_name, "grav") == 0) { view.gravity = bool_val; } else { Beep("3D_Set: unknown var: %s", var_name); return; } RedrawMap(); } void R3D_Toggle(void) { const char *var_name = EXEC_Param[0]; if (! var_name[0]) { Beep("3D_Toggle: missing var name"); return; } if (y_stricmp(var_name, "tex") == 0) { view.texturing = ! view.texturing; } else if (y_stricmp(var_name, "obj") == 0) { view.sprites = ! view.sprites; view.thsec_invalidated = true; } else if (y_stricmp(var_name, "light") == 0) { view.lighting = ! view.lighting; } else if (y_stricmp(var_name, "grav") == 0) { view.gravity = ! view.gravity; } else { Beep("3D_Toggle: unknown var: %s", var_name); return; } RedrawMap(); } /* Align texture on a sidedef * * Parameter: * x : align X offset * y : align Y offset * xy : align both X and Y * * Flags: * /clear : clear offset(s) instead of aligning * /right : align to line on the right of this one (instead of left) */ void R3D_Align(void) { if (! edit.render3d) { Beep("3D mode required"); return; } // parse parameter const char *param = EXEC_Param[0]; bool do_X = strchr(param, 'x') ? true : false; bool do_Y = strchr(param, 'y') ? true : false; if (! (do_X || do_Y)) { Beep("3D_Align: need x or y flag"); return; } bool do_clear = Exec_HasFlag("/clear"); // find the line / side to align if (! is_linedef(view.hl.line) || view.hl.part == QRP_Floor || view.hl.part == QRP_Ceil) { Beep("No sidedef there!"); return; } const LineDef *L = LineDefs[view.hl.line]; int sd = (view.hl.side < 0) ? L->left : L->right; if (sd < 0) // should NOT happen { Beep("No sidedef there!"); return; } if (do_clear) { BA_Begin(); if (do_X) BA_ChangeSD(sd, SideDef::F_X_OFFSET, 0); if (do_Y) BA_ChangeSD(sd, SideDef::F_Y_OFFSET, 0); BA_End(); return; } char part_c = (view.hl.part == QRP_Upper) ? 'u' : 'l'; int align_flags = 0; if (do_X) align_flags = align_flags | LINALIGN_X; if (do_Y) align_flags = align_flags | LINALIGN_Y; if (Exec_HasFlag("/right")) align_flags |= LINALIGN_Right; LineDefs_Align(view.hl.line, view.hl.side, sd, part_c, align_flags); } //------------------------------------------------------------------------ static editor_command_t render_commands[] = { { "3D_Forward", &R3D_Forward }, { "3D_Backward", &R3D_Backward }, { "3D_Left", &R3D_Left }, { "3D_Right", &R3D_Right }, { "3D_Up", &R3D_Up }, { "3D_Down", &R3D_Down }, { "3D_Turn", &R3D_Turn }, { "3D_DropToFloor", &R3D_DropToFloor }, { "3D_Set", &R3D_Set, /* flags */ NULL, /* keywords */ "gamma tex obj light grav" }, { "3D_Toggle", &R3D_Toggle, /* flags */ NULL, /* keywords */ "tex obj light grav" }, { "3D_Align", &R3D_Align, /* flags */ "/right /clear" }, // end of command list { NULL, NULL } }; void Render3D_RegisterCommands() { M_RegisterCommandList(render_commands); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_files.h0000644000175100017510000000336412647061302016053 0ustar aaptedaapted//------------------------------------------------------------------------ // RECENT FILES / KNOWN IWADS / BACKUPS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2013 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 __EUREKA_M_FILES_H__ #define __EUREKA_M_FILES_H__ class Wad_file; void M_LoadRecent(); void M_SaveRecent(); void M_AddRecent(const char *filename, const char *map_name); void M_OpenRecentFromMenu(void *priv_data); bool M_TryOpenMostRecent(); // these three only for menu code int M_RecentCount(); void M_RecentShortName(int index, char *name_buf); void * M_RecentData(int index); void M_LookForIWADs(); void M_AddKnownIWAD(const char *path); const char * M_QueryKnownIWAD(const char *game); const char * M_KnownIWADsForMenu(int *exist_val, const char *exist_name); const char * M_PickDefaultIWAD(); void M_ValidateGivenFiles(); int M_FindGivenFile(const char *filename); bool M_ParseEurekaLump(Wad_file *wad, bool keep_cmd_line_args = false); void M_WriteEurekaLump(Wad_file *wad); void M_BackupWad(Wad_file *wad); #endif /* __EUREKA_M_FILES_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/im_arrows.cc0000644000175100017510000000433412647061302016573 0ustar aaptedaapted/* basic arrow sprites, made by Andrew Apted, public domain */ /* XPM */ const char * arrow_0_xpm[] = { "12 12 2 1", " c None", ". c #000000", " . ", " .. ", " ... ", " .... ", " ..... ", "............", "............", " ..... ", " .... ", " ... ", " .. ", " . "}; /* XPM */ const char * arrow_45_xpm[] = { "12 12 2 1", " c None", ". c #000000", " ", " ........ ", " ....... ", " ...... ", " ..... ", " ...... ", " ... ... ", " ... .. ", " ... . ", " ... ", " .. ", " "}; /* XPM */ const char * arrow_90_xpm[] = { "12 12 2 1", " c None", ". c #000000", " .. ", " .... ", " ...... ", " ........ ", " .......... ", "............", " .. ", " .. ", " .. ", " .. ", " .. ", " .. "}; /* XPM */ const char * arrow_135_xpm[] = { "12 12 2 1", " c None", ". c #000000", " ", " ........ ", " ....... ", " ...... ", " ..... ", " ...... ", " ... ... ", " .. ... ", " . ... ", " ... ", " .. ", " "}; /* XPM */ const char * arrow_180_xpm[] = { "12 12 2 1", " c None", ". c #000000", " . ", " .. ", " ... ", " .... ", " ..... ", "............", "............", " ..... ", " .... ", " ... ", " .. ", " . "}; /* XPM */ const char * arrow_225_xpm[] = { "12 12 2 1", " c None", ". c #000000", " ", " .. ", " ... ", " . ... ", " .. ... ", " ... ... ", " ...... ", " ..... ", " ...... ", " ....... ", " ........ ", " "}; /* XPM */ const char * arrow_270_xpm[] = { "12 12 2 1", " c None", ". c #000000", " .. ", " .. ", " .. ", " .. ", " .. ", " .. ", "............", " .......... ", " ........ ", " ...... ", " .... ", " .. "}; /* XPM */ const char * arrow_315_xpm[] = { "12 12 2 1", " c None", ". c #000000", " ", " .. ", " ... ", " ... . ", " ... .. ", " ... ... ", " ...... ", " ..... ", " ...... ", " ....... ", " ........ ", " "}; eureka-1.11-source/src/e_things.cc0000644000175100017510000001056612647061302016375 0ustar aaptedaapted//------------------------------------------------------------------------ // THING OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "m_game.h" #include "e_things.h" #include "editloop.h" #include "levels.h" #include "m_bitvec.h" #include "w_rawdef.h" #include "ui_window.h" int calc_new_angle(int angle, int diff) { angle += diff; while (angle < 0) angle += 360000000; return angle % 360; } /* * spin_thing - change the angle of things */ void TH_SpinThings(void) { int degrees = atoi(EXEC_Param[0]); if (! degrees) degrees = +45; selection_c list; selection_iterator_c it; if (! GetCurrentObjects(&list)) { Beep("No things to spin"); return; } BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { const Thing *T = Things[*it]; BA_ChangeTH(*it, Thing::F_ANGLE, calc_new_angle(T->angle, degrees)); } BA_End(); main_win->thing_box->UpdateField(Thing::F_ANGLE); } bool ThingsOverlap(int th1, int th2) { const Thing *T1 = Things[th1]; const Thing *T2 = Things[th2]; int r1 = M_GetThingType(T1->type)->radius; int r2 = M_GetThingType(T2->type)->radius; int dx = abs(T1->x - T2->x); int dy = abs(T1->y - T2->y); return (MAX(dx, dy) < r1 + r2); } bool ThingsAtSameLoc(int th1, int th2) { const Thing *T1 = Things[th1]; const Thing *T2 = Things[th2]; int dx = abs(T1->x - T2->x); int dy = abs(T1->y - T2->y); return (dx < 8 && dy < 8); } static void CollectOverlapGroup(selection_c& list) { int first = edit.Selected->find_first(); list.set(first); for (int k = 0 ; k < NumThings ; k++) if (k != first && ThingsAtSameLoc(k, first)) list.set(k); } static void MoveOverlapThing(int th, int mid_x, int mid_y, int n, int total) { float angle = n * 360 / total; float vec_x = cos(angle * M_PI / 180.0); float vec_y = sin(angle * M_PI / 180.0); float dist = 8 + 6 * MIN(100, total); const Thing *T = Things[th]; BA_ChangeTH(th, Thing::F_X, T->x + vec_x * dist); BA_ChangeTH(th, Thing::F_Y, T->y + vec_y * dist); } /* all things lying at same location (or very near) to the selected * things are moved so they are more distinct -- about 8 units away * from that location. */ void TH_Disconnect(void) { if (edit.Selected->empty()) { if (edit.highlight.is_nil()) { Beep("No vertices to disconnect"); return; } edit.Selected->set(edit.highlight.num); } BA_Begin(); while (! edit.Selected->empty()) { selection_c overlaps(OBJ_THINGS); CollectOverlapGroup(overlaps); // remove these from the selection edit.Selected->unmerge(overlaps); int total = overlaps.count_obj(); int n; if (total < 2) continue; int mid_x, mid_y; Objs_CalcMiddle(&overlaps, &mid_x, &mid_y); selection_iterator_c it; for (n = 0, overlaps.begin(&it) ; !it.at_end() ; ++it, ++n) { MoveOverlapThing(*it, mid_x, mid_y, n, total); } } BA_End(); } /* place all selected things at same location */ void TH_Merge(void) { if (edit.Selected->count_obj() == 1 && edit.highlight.valid()) { edit.Selected->set(edit.highlight.num); } if (edit.Selected->count_obj() < 2) { Beep("Need 2 or more things to merge"); return; } int mid_x, mid_y; Objs_CalcMiddle(edit.Selected, &mid_x, &mid_y); BA_Begin(); selection_iterator_c it; for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { BA_ChangeTH(*it, Thing::F_X, mid_x); BA_ChangeTH(*it, Thing::F_Y, mid_y); } BA_End(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_menu.cc0000644000175100017510000004306412651415434016241 0ustar aaptedaapted//------------------------------------------------------------------------ // MENUS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 "main.h" #include "ui_window.h" #include "ui_about.h" #include "ui_misc.h" #include "ui_prefs.h" #include "editloop.h" #include "e_basis.h" #include "e_loadsave.h" #include "e_nodes.h" #include "e_cutpaste.h" #include "e_path.h" #include "levels.h" #include "m_files.h" #include "r_grid.h" #include "x_mirror.h" //------------------------------------------------------------------------ // FILE MENU //------------------------------------------------------------------------ static void file_do_quit(Fl_Widget *w, void * data) { CMD_Quit(); } static void file_do_new(Fl_Widget *w, void * data) { CMD_NewMap(); } static void file_do_open(Fl_Widget *w, void * data) { CMD_OpenMap(); } static void file_do_save(Fl_Widget *w, void * data) { CMD_SaveMap(); } static void file_do_export(Fl_Widget *w, void * data) { CMD_ExportMap(); } static void file_do_rename(Fl_Widget *w, void * data) { CMD_RenameMap(); } static void file_do_delete(Fl_Widget *w, void * data) { CMD_DeleteMap(); } static void file_do_new_project(Fl_Widget *w, void * data) { ProjectSetup(true /* new_project */); } static void file_do_manage_project(Fl_Widget *w, void * data) { ProjectSetup(); } static void file_do_default_props(Fl_Widget *w, void * data) { main_win->ShowDefaultProps(); } static void file_do_prefs(Fl_Widget *w, void * data) { CMD_Preferences(); } static void file_do_build_nodes(Fl_Widget *w, void * data) { CMD_BuildNodes(); } #if 0 static void file_do_test_map(Fl_Widget *w, void * data) { CMD_TestMap(); } #endif static void file_do_load_given(Fl_Widget *w, void *data) { const char *filename = (const char *) data; int given_idx = M_FindGivenFile(filename); if (given_idx >= 0) last_given_file = given_idx; CMD_OpenFileMap(filename); } static void file_do_load_recent(Fl_Widget *w, void *data) { M_OpenRecentFromMenu(data); } //------------------------------------------------------------------------ // EDIT MENU //------------------------------------------------------------------------ static void edit_do_undo(Fl_Widget *w, void * data) { if (BA_Undo()) RedrawMap(); else Beep("No operation to undo"); } static void edit_do_redo(Fl_Widget *w, void * data) { if (BA_Redo()) RedrawMap(); else Beep("No operation to redo"); } static void edit_do_cut(Fl_Widget *w, void * data) { if (! CMD_Copy()) { Beep("Nothing to cut"); return; } ExecuteCommand("Delete"); } static void edit_do_copy(Fl_Widget *w, void * data) { if (! CMD_Copy()) { Beep("Nothing to copy"); return; } } static void edit_do_paste(Fl_Widget *w, void * data) { if (! CMD_Paste()) { Beep("Clipboard is empty"); return; } } static void edit_do_delete(Fl_Widget *w, void * data) { ExecuteCommand("Delete"); } static void edit_do_select_all(Fl_Widget *w, void * data) { CMD_SelectAll(); } static void edit_do_unselect_all(Fl_Widget *w, void * data) { CMD_UnselectAll(); } static void edit_do_invert_sel(Fl_Widget *w, void * data) { CMD_InvertSelection(); } static void edit_do_last_sel(Fl_Widget *w, void * data) { CMD_LastSelection(); } static void edit_do_move(Fl_Widget *w, void * data) { if (edit.Selected->empty()) { Beep("Nothing to move"); return; } UI_MoveDialog * dialog = new UI_MoveDialog(); dialog->Run(); delete dialog; } static void edit_do_scale(Fl_Widget *w, void * data) { if (edit.Selected->empty()) { Beep("Nothing to scale"); return; } UI_ScaleDialog * dialog = new UI_ScaleDialog(); dialog->Run(); delete dialog; } static void edit_do_rotate(Fl_Widget *w, void * data) { if (edit.Selected->empty()) { Beep("Nothing to rotate"); return; } UI_RotateDialog * dialog = new UI_RotateDialog(); dialog->Run(); delete dialog; } static void edit_do_prune_unused(Fl_Widget *w, void * data) { CMD_PruneUnused(); } static void edit_do_mirror_horiz(Fl_Widget *w, void * data) { ExecuteCommand("Mirror", "horiz"); } static void edit_do_mirror_vert(Fl_Widget *w, void * data) { ExecuteCommand("Mirror", "vert"); } //------------------------------------------------------------------------ // VIEW MENU //------------------------------------------------------------------------ static void view_do_logs(Fl_Widget *w, void * data) { LogViewer_Open(); } static void view_do_zoom_in(Fl_Widget *w, void * data) { Editor_Zoom(+1, I_ROUND(grid.orig_x), I_ROUND(grid.orig_y)); } static void view_do_zoom_out(Fl_Widget *w, void * data) { Editor_Zoom(-1, I_ROUND(grid.orig_x), I_ROUND(grid.orig_y)); } static void view_do_whole_map(Fl_Widget *w, void * data) { CMD_ZoomWholeMap(); } static void view_do_whole_selection(Fl_Widget *w, void * data) { CMD_ZoomSelection(); } static void view_do_camera_pos(Fl_Widget *w, void * data) { CMD_GoToCamera(); } static void view_do_toggle_3d(Fl_Widget *w, void * data) { Editor_ClearAction(); edit.render3d = ! edit.render3d; main_win->redraw(); } static void view_do_object_nums(Fl_Widget *w, void * data) { ExecuteCommand("Toggle", "obj_nums"); } static void view_do_grid_type(Fl_Widget *w, void * data) { grid.ToggleMode(); } static void view_do_sector_render(Fl_Widget *w, void * data) { const Fl_Menu_Item *item = ((Fl_Menu_*)w)->mvalue(); if (strcmp(item->text, "Floors") == 0) edit.sector_render_mode = SREND_Floor; else if (strcmp(item->text, "Ceilings") == 0) edit.sector_render_mode = SREND_Ceiling; else if (strcmp(item->text, "Lighting") == 0) edit.sector_render_mode = SREND_Lighting; else edit.sector_render_mode = SREND_Nothing; main_win->redraw(); } static void view_do_find(Fl_Widget *w, void * data) { main_win->ShowFindAndReplace(); } static void view_do_next(Fl_Widget *w, void * data) { main_win->find_box->FindNext(); } static void view_do_jump(Fl_Widget *w, void * data) { CMD_JumpToObject(); } //------------------------------------------------------------------------ // BROWSER MENU //------------------------------------------------------------------------ static void browser_do_textures(Fl_Widget *w, void * data) { main_win->ShowBrowser('T'); } static void browser_do_flats(Fl_Widget *w, void * data) { main_win->ShowBrowser('F'); } static void browser_do_things(Fl_Widget *w, void * data) { main_win->ShowBrowser('O'); } static void browser_do_lines(Fl_Widget *w, void * data) { main_win->ShowBrowser('L'); } static void browser_do_sectors(Fl_Widget *w, void * data) { main_win->ShowBrowser('S'); } static void browser_do_gen_types(Fl_Widget *w, void * data) { main_win->ShowBrowser('G'); } static void browser_do_recent_things(Fl_Widget *w, void * data) { main_win->ShowBrowser('O'); main_win->browser->ToggleRecent(true /* force */); } static void browser_do_recent_tex(Fl_Widget *w, void * data) { main_win->ShowBrowser('T'); main_win->browser->ToggleRecent(true /* force */); } static void browser_do_recent_flats(Fl_Widget *w, void * data) { main_win->ShowBrowser('F'); main_win->browser->ToggleRecent(true /* force */); } #if 0 static void browser_go_wide(Fl_Widget *w, void * data) { // TODO } static void browser_go_narrow(Fl_Widget *w, void * data) { // TODO } #endif static void browser_hide(Fl_Widget *w, void * data) { main_win->ShowBrowser(0); } //------------------------------------------------------------------------ // CHECK MENU //------------------------------------------------------------------------ static void checks_do_all(Fl_Widget *w, void * data) { ExecuteCommand("Check", "all"); } static void checks_do_major(Fl_Widget *w, void * data) { ExecuteCommand("Check", "major"); } static void checks_do_vertices(Fl_Widget *w, void * data) { ExecuteCommand("Check", "vertices"); } static void checks_do_sectors(Fl_Widget *w, void * data) { ExecuteCommand("Check", "sectors"); } static void checks_do_linedefs(Fl_Widget *w, void * data) { ExecuteCommand("Check", "linedefs"); } static void checks_do_things(Fl_Widget *w, void * data) { ExecuteCommand("Check", "things"); } static void checks_do_textures(Fl_Widget *w, void * data) { ExecuteCommand("Check", "textures"); } static void checks_do_tags(Fl_Widget *w, void * data) { ExecuteCommand("Check", "tags"); } //------------------------------------------------------------------------ // HELP MENU //------------------------------------------------------------------------ void help_do_online_docs(Fl_Widget *w, void * data) { fl_open_uri("http://eureka-editor.sourceforge.net/?n=Docs.Index"); } void help_do_about(Fl_Widget *w, void * data) { DLG_AboutText(); } //------------------------------------------------------------------------ #define M_GIVEN_FILES "&Given Files" #define M_RECENT_FILES "&Recent Files" #undef FCAL #define FCAL (Fl_Callback *) static Fl_Menu_Item menu_items[] = { { "&File", 0, 0, 0, FL_SUBMENU }, { "&New Project ", FL_COMMAND + 'n', FCAL file_do_new_project }, { "New Map", FL_COMMAND + FL_SHIFT + 'n', FCAL file_do_new }, { "&Manage Project ", FL_COMMAND + 'm', FCAL file_do_manage_project }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Open Map", FL_COMMAND + 'o', FCAL file_do_open }, { M_GIVEN_FILES, 0, 0, 0, FL_SUBMENU|FL_MENU_INACTIVE }, { 0 }, { M_RECENT_FILES, 0, 0, 0, FL_SUBMENU|FL_MENU_INACTIVE }, { 0 }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Save Map", FL_COMMAND + 's', FCAL file_do_save }, { "&Export Map", FL_COMMAND + 'e', FCAL file_do_export }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Rename Map", 0, FCAL file_do_rename }, { "Delete Map", 0, FCAL file_do_delete }, { "&Build Nodes ", FL_COMMAND + 'b', FCAL file_do_build_nodes }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, #if 0 { "&Test Map", FL_COMMAND + 't', FCAL file_do_test_map }, #endif { "&Preferences", FL_COMMAND + 'p', FCAL file_do_prefs }, { "&Quit", FL_COMMAND + 'q', FCAL file_do_quit }, { 0 }, { "&Edit", 0, 0, 0, FL_SUBMENU }, { "&Undo", FL_COMMAND + 'z', FCAL edit_do_undo }, { "&Redo", FL_COMMAND + 'y', FCAL edit_do_redo }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Cu&t", FL_COMMAND + 'x', FCAL edit_do_cut }, { "&Copy", FL_COMMAND + 'c', FCAL edit_do_copy }, { "&Paste", FL_COMMAND + 'v', FCAL edit_do_paste }, { "&Delete", FL_Delete, FCAL edit_do_delete }, { "Prune Unused", 0, FCAL edit_do_prune_unused }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Select &All", FL_COMMAND + 'a', FCAL edit_do_select_all }, { "Unselect All", FL_COMMAND + 'u', FCAL edit_do_unselect_all }, { "&Invert Selection", FL_COMMAND + 'i', FCAL edit_do_invert_sel }, { "&Last Selection", FL_COMMAND + 'l', FCAL edit_do_last_sel }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Move Objects...", 0, FCAL edit_do_move }, { "&Scale Objects...", 0, FCAL edit_do_scale }, { "Rotate Objects...", 0, FCAL edit_do_rotate }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Mirror &Horizontally", 0, FCAL edit_do_mirror_horiz }, { "Mirror &Vertically", 0, FCAL edit_do_mirror_vert }, //?? "~Exchange object numbers", 24, 0, { 0 }, { "&View", 0, 0, 0, FL_SUBMENU }, { "&Logs....", 0, FCAL view_do_logs }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Toggle &3D View", 0, FCAL view_do_toggle_3d }, { "Toggle Object &Nums", 0, FCAL view_do_object_nums }, { "&Toggle Grid Type", 0, FCAL view_do_grid_type }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Sector Rendering", 0, 0, 0, FL_SUBMENU }, { "Nothing", 0, FCAL view_do_sector_render }, { "Floors", 0, FCAL view_do_sector_render }, { "Ceilings", 0, FCAL view_do_sector_render }, { "Lighting", 0, FCAL view_do_sector_render }, { 0 }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Zoom &In", 0, FCAL view_do_zoom_in }, { "Zoom &Out", 0, FCAL view_do_zoom_out }, { "&Whole Map", 0, FCAL view_do_whole_map }, { "Whole &Selection", 0, FCAL view_do_whole_selection }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Default Props ", FL_COMMAND + 'd', FCAL file_do_default_props }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Find / Replace", FL_COMMAND + 'f', FCAL view_do_find }, { "&Go to next", FL_COMMAND + 'g', FCAL view_do_next }, { "Go to &Camera", 0, FCAL view_do_camera_pos }, { "&Jump to Object", 0, FCAL view_do_jump }, { 0 }, { "&Browser", 0, 0, 0, FL_SUBMENU }, { "&Things", 0, FCAL browser_do_things }, { "Te&xtures", 0, FCAL browser_do_textures }, { "&Flats", 0, FCAL browser_do_flats }, { "&Line Types", 0, FCAL browser_do_lines }, { "&Sector Types", 0, FCAL browser_do_sectors }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Generalized Types", 0, FCAL browser_do_gen_types }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Recent Textures", 0, FCAL browser_do_recent_tex }, { "Recent Flats", 0, FCAL browser_do_recent_flats }, { "Recent Things", 0, FCAL browser_do_recent_things }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Hide", 0, FCAL browser_hide }, { 0 }, { "&Check", 0, 0, 0, FL_SUBMENU }, { "&ALL", 0, FCAL checks_do_all }, { "&Major stuff", 0, FCAL checks_do_major }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Vertices", 0, FCAL checks_do_vertices }, { "&Sectors", 0, FCAL checks_do_sectors }, { "&LineDefs", 0, FCAL checks_do_linedefs }, { "&Things", 0, FCAL checks_do_things }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Te&xtures", 0, FCAL checks_do_textures }, { "Ta&gs", 0, FCAL checks_do_tags }, { 0 }, { "&Help", 0, 0, 0, FL_SUBMENU }, { "&Online Docs...", 0, FCAL help_do_online_docs }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&About Eureka...", 0, FCAL help_do_about }, { 0 }, { 0 } }; //------------------------------------------------------------------------ #define MAX_PWAD_LIST 20 static int Menu_FindItem(const Fl_Menu_Item *items, const char *text) { int total = items[0].size(); // includes {0} at end for (int i = 0 ; i < total ; i++) if (items[i].text && y_stricmp(items[i].text, text) == 0) return i; return -1; // not found } static void Menu_CopyItem(Fl_Menu_Item* &pos, const Fl_Menu_Item &orig) { memcpy(pos, &orig, sizeof(orig)); pos++; } static void Menu_AddItem(Fl_Menu_Item* &pos, const char *text, Fl_Callback *cb, void *data, int flags) { Fl_Menu_Item item; memset(&item, 0, sizeof(item)); item.text = text; item.flags = flags; item.callback_ = cb; item.user_data_ = data; Menu_CopyItem(pos, item); } static Fl_Menu_Item * Menu_PopulateGivenFiles(Fl_Menu_Item *items) { int count = (int)Pwad_list.size(); if (count < 2) return items; // silently ignore excess pwads if (count > MAX_PWAD_LIST) count = MAX_PWAD_LIST; // find Given Files sub-menu and activate it int menu_pos = Menu_FindItem(items, M_GIVEN_FILES); if (menu_pos < 0) // [should not happen] return items; items[menu_pos++].activate(); // create new array int total = items[0].size(); // includes {0} at end Fl_Menu_Item * new_array = new Fl_Menu_Item[total + count]; Fl_Menu_Item * pos = new_array; for (int i = 0 ; i < menu_pos ; i++) Menu_CopyItem(pos, items[i]); for (int k = 0 ; k < count ; k++) { const char *short_name = fl_filename_name(Pwad_list[k]); short_name = StringPrintf("%s%d. %s", (k < 9) ? "&" : "", 1+k, short_name); Menu_AddItem(pos, short_name, FCAL file_do_load_given, (void *) Pwad_list[k], 0); } for ( ; menu_pos < total ; menu_pos++) Menu_CopyItem(pos, items[menu_pos]); return new_array; } static Fl_Menu_Item * Menu_PopulateRecentFiles(Fl_Menu_Item *items, Fl_Callback *cb) { int count = M_RecentCount(); if (count < 1) return items; // find Recent Files sub-menu and activate it int menu_pos = Menu_FindItem(items, M_RECENT_FILES); if (menu_pos < 0) // [should not happen] return items; items[menu_pos++].activate(); // create new array int total = items[0].size(); // includes {0} at end Fl_Menu_Item * new_array = new Fl_Menu_Item[total + count]; Fl_Menu_Item * pos = new_array; for (int i = 0 ; i < menu_pos ; i++) Menu_CopyItem(pos, items[i]); for (int k = 0 ; k < count ; k++) { char name_buf[256]; M_RecentShortName(k, name_buf); void *data = M_RecentData(k); Menu_AddItem(pos, StringDup(name_buf), cb, data, 0); } for ( ; menu_pos < total ; menu_pos++) Menu_CopyItem(pos, items[menu_pos]); return new_array; } Fl_Sys_Menu_Bar * Menu_Create(int x, int y, int w, int h) { Fl_Sys_Menu_Bar *bar = new Fl_Sys_Menu_Bar(x, y, w, h); #ifndef __APPLE__ bar->textsize(KF_fonth); #endif Fl_Menu_Item *items = menu_items; items = Menu_PopulateGivenFiles(items); items = Menu_PopulateRecentFiles(items, FCAL file_do_load_recent); bar->menu(items); return bar; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_browser.h0000644000175100017510000001234612651124264016617 0ustar aaptedaapted//------------------------------------------------------------------------ // BROWSER for TEXTURES / FLATS / THINGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 __EUREKA_UI_BROWSER_H__ #define __EUREKA_UI_BROWSER_H__ #include #include class Browser_Item : public Fl_Group { private: public: std::string desc; std::string real_name; // for textures and flats only int number; char category; int recent_idx; Fl_Repeat_Button * button; UI_Pic *pic; public: // this constructor makes a simple text button Browser_Item(int X, int Y, int W, int H, const char *_desc, const char *_realname, int _num, char _category); // this constructor makes a picture with a text label below it Browser_Item(int X, int Y, int W, int H, const char * _desc, const char *_realname, int _num, char _category, int pic_w, int pic_h, UI_Pic *_pic); virtual ~Browser_Item(); public: static void texture_callback(Fl_Widget *w, void *data); static void flat_callback(Fl_Widget *w, void *data); static void thing_callback(Fl_Widget *w, void *data); static void line_callback(Fl_Widget *w, void *data); static void sector_callback(Fl_Widget *w, void *data); private: }; class UI_Browser_Box : public Fl_Group { private: char kind; Fl_Choice *category; Fl_Input *search; Fl_Check_Button *alpha; Fl_Check_Button *pics; UI_Scroll *scroll; bool pic_mode; char cat_letters[64]; public: UI_Browser_Box(int X, int Y, int W, int H, const char *label, char _kind); virtual ~UI_Browser_Box(); /* FLTK method */ void resize(int X, int Y, int W, int H); public: void Populate(); void SetCategories(const char *cats, const char *letters); void CycleCategory(int dir); void ToggleRecent(bool force_recent); void ClearSearchBox(); void Scroll(int delta); char GetKind() const { return kind; } void RecentUpdate(); bool ParseUser(const char ** tokens, int num_tok); void WriteUser(FILE *fp); private: // adjust the widgets in the Fl_Scroll based on current search // parameters. Returns true if something changed. bool Filter(bool force_update = false); void Sort(); bool SearchMatch(Browser_Item *item) const; void Populate_Images(std::map & img_list); void Populate_Sprites(); void Populate_ThingTypes(); void Populate_LineTypes(); void Populate_SectorTypes(); bool Recent_UpdateItem(Browser_Item *item); bool CategoryByLetter(char letter); static void filter_callback(Fl_Widget *w, void *data); static void hide_callback(Fl_Widget *w, void *data); static void repop_callback(Fl_Widget *w, void *data); static void sort_callback(Fl_Widget *w, void *data); }; class UI_Generalized_Page; class UI_Generalized_Box : public Fl_Group { private: // overall kind of line (DOOR, LIFT, etc...) Fl_Choice * category; // this is shown when not in Boom mode Fl_Box * no_boom; enum { MAX_PAGES = 16 }; UI_Generalized_Page * pages[MAX_PAGES]; int num_pages; int in_update; public: UI_Generalized_Box(int X, int Y, int W, int H, const char *label); virtual ~UI_Generalized_Box(); void Populate(); void UpdateGenType(int line_type); private: void CreatePages(); int ComputeType() const; static void hide_callback(Fl_Widget *w, void *data); static void cat_callback(Fl_Widget *w, void *data); static void edit_callback(Fl_Widget *w, void *data); }; class UI_Browser : public Fl_Group { /* this widget basically just contains all the browser boxes, * and controls which one is visible at any time. */ private: UI_Browser_Box *browsers[5]; UI_Generalized_Box *gen_box; enum { ACTIVE_GENERALIZED = 5 }; // currently active browser box (may be hidden though) int active; public: UI_Browser(int X, int Y, int W, int H, const char *label = NULL); virtual ~UI_Browser(); public: void Populate(); void SetActive(int new_active); void ChangeMode(char new_mode); void NewEditMode(obj_type_e edit_mode); // dir is +1 or -1, or 0 to set the category to "ALL" void CycleCategory(int dir); void ToggleRecent(bool force_recent = false); void ClearSearchBox(); void Scroll(int delta); // recently used textures (etc) has changed void RecentUpdate(); // for the generalized box void UpdateGenType(int line_type); bool ParseUser(const char ** tokens, int num_tok); void WriteUser(FILE *fp); private: // static void mode_callback(Fl_Widget *w, void *data); }; bool Browser_ParseUser(const char ** tokens, int num_tok); void Browser_WriteUser(FILE *fp); #endif /* __EUREKA_UI_BROWSER_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/sys_macro.h0000644000175100017510000000411212647061302016424 0ustar aaptedaapted//------------------------------------------------------------------------ // Macros //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2008 Andrew Apted // Copyright (C) 2005 Simon Howard // // 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 __SYS_MACRO_H__ #define __SYS_MACRO_H__ // basic macros #ifndef NULL #define NULL ((void*) 0) #endif #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifndef M_SQRT2 #define M_SQRT2 1.41421356237309504880 #endif #ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef ABS #define ABS(a) ((a) < 0 ? -(a) : (a)) #endif #ifndef SGN #define SGN(a) ((a) < 0 ? -1 : (a) > 0 ? +1 : 0) #endif #ifndef I_ROUND #define I_ROUND(x) ((int) (((x) < 0.0f) ? ((x) - 0.5f) : ((x) + 0.5f))) #endif #ifndef CLAMP #define CLAMP(low,x,high) \ ((x) < (low) ? (low) : (x) > (high) ? (high) : (x)) #endif // // The packed attribute forces structures to be packed into the minimum // space necessary. If this is not done, the compiler may align structure // fields differently to optimize memory access, inflating the overall // structure size. It is important to use the packed attribute on certain // structures where alignment is important, particularly data read/written // to disk. // #ifdef __GNUC__ #define PACKEDATTR __attribute__((packed)) #else #define PACKEDATTR #endif #endif /* __SYS_MACRO_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_window.h0000644000175100017510000001060212647613230016435 0ustar aaptedaapted//------------------------------------------------------------------------ // MAIN WINDOW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2015 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 __EUREKA_UI_WINDOW_H__ #define __EUREKA_UI_WINDOW_H__ #include "ui_menu.h" #include "ui_canvas.h" #include "ui_infobar.h" #include "ui_hyper.h" #include "ui_nombre.h" #include "ui_pic.h" #include "ui_scroll.h" #include "ui_tile.h" #include "ui_browser.h" #include "ui_default.h" #include "ui_replace.h" #include "ui_thing.h" #include "ui_sector.h" #include "ui_sidedef.h" #include "ui_linedef.h" #include "ui_vertex.h" #define WINDOW_BG FL_DARK3 #define MIN_BROWSER_W 250 class Wad_file; class UI_Render3D; class UI_MainWin : public Fl_Double_Window { public: // main child widgets Fl_Sys_Menu_Bar *menu_bar; int panel_W; UI_Tile * tile; UI_CanvasScroll *scroll; UI_Canvas *canvas; UI_Render3D *render; UI_Browser *browser; UI_InfoBar *info_bar; UI_ThingBox *thing_box; UI_LineBox *line_box; UI_SectorBox *sec_box; UI_VertexBox *vert_box; UI_DefaultProps *props_box; UI_FindAndReplace *find_box; private: Fl_Cursor cursor_shape; // remember window size/position after going fullscreen. // the 'last_w' and 'last_h' fields are zero when not fullscreen int last_x, last_y, last_w, last_h; public: UI_MainWin(); virtual ~UI_MainWin(); public: void SetTitle(const char *wad_name, const char *map_name, bool read_only); // add or remove the '*' (etc) in the title void UpdateTitle(char want_prefix = 0); void Maximize(); void NewEditMode(obj_type_e mode); // this is a wrapper around the FLTK cursor() method which // prevents the possibly expensive call when the shape hasn't // changed. void SetCursor(Fl_Cursor shape); // show or hide the Browser panel. // kind is NUL or '-' to hide, '/' to toggle, 'T' for textures, 'F' flats, // 'O' for thing types, 'L' line types, 'S' sector types. void ShowBrowser(char kind); void ShowDefaultProps(); void ShowFindAndReplace(); void UpdateTotals(); int GetPanelObjNum() const; void InvalidatePanelObj(); void UpdatePanelObj(); void UnselectPics(); void HideSpecialPanel(); bool isSpecialPanelShown() { return props_box->visible() || find_box->visible(); } void Delay(int steps); // each step is 1/10th second // this is used by the browser when user clicks on an entry. // kind == 'T' for textures (etc... as above) void BrowsedItem(char kind, int number, const char *name, int e_state); // this is called when game_info changes (in Main_LoadResources) // and can enable / disable stuff in the panels. void UpdateGameInfo(); }; extern UI_MainWin * main_win; //------------------------------------------------------------------------ class UI_Escapable_Window : public Fl_Double_Window { public: UI_Escapable_Window(int W, int H, const char *L = NULL); virtual ~UI_Escapable_Window(); public: // FLTK event handling method int handle(int event); }; //------------------------------------------------------------------------ class UI_LogViewer : public UI_Escapable_Window { private: Fl_Multi_Browser * browser; Fl_Button * copy_but; public: UI_LogViewer(); virtual ~UI_LogViewer(); void Add(const char *line); void Deselect(); // ensure the very last line is visible void JumpEnd(); private: int CountSelectedLines() const; char * GetSelectedText() const; static void ok_callback(Fl_Widget *, void *); static void clear_callback(Fl_Widget *, void *); static void save_callback(Fl_Widget *, void *); static void select_callback(Fl_Widget *, void *); static void copy_callback(Fl_Widget *, void *); }; extern UI_LogViewer * log_viewer; void LogViewer_Open(); #endif /* __EUREKA_UI_WINDOW_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_linedef.cc0000644000175100017510000004342612650266074016710 0ustar aaptedaapted//------------------------------------------------------------------------ // LINEDEF PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 "main.h" #include "ui_window.h" #include "levels.h" #include "e_checks.h" #include "e_linedef.h" #include "e_things.h" #include "m_game.h" #include "w_rawdef.h" #include "w_rawdef.h" #define MLF_ALL_AUTOMAP \ MLF_Secret | MLF_Mapped | MLF_DontDraw | MLF_XDoom_Translucent class line_flag_CB_data_c { public: UI_LineBox *parent; int mask; public: line_flag_CB_data_c(UI_LineBox *_parent, int _mask) : parent(_parent), mask(_mask) { } ~line_flag_CB_data_c() { } }; // // UI_LineBox Constructor // UI_LineBox::UI_LineBox(int X, int Y, int W, int H, const char *label) : Fl_Group(X, Y, W, H, label), obj(-1), count(0) { box(FL_FLAT_BOX); // (FL_THIN_UP_BOX); X += 6; Y += 6; W -= 12; H -= 10; which = new UI_Nombre(X+6, Y, W-12, 28, "Linedef"); Y += which->h() + 4; type = new Fl_Int_Input(X+58, Y, 65, 24, "Type: "); type->align(FL_ALIGN_LEFT); type->callback(type_callback, this); type->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); choose = new Fl_Button(X+W/2+15, Y, 80, 24, "Choose"); choose->callback(button_callback, this); gen = new Fl_Button(X+W-60, Y, 50, 24, "Gen"); gen->callback(button_callback, this); Y += type->h() + 2; new Fl_Box(FL_NO_BOX, X+10, Y, 48, 24, "Desc: "); desc = new Fl_Output(type->x(), Y, W-66, 24); desc->align(FL_ALIGN_LEFT); actkind = new Fl_Choice(X+58, Y, 57, 24); // this order must match the SPAC_XXX constants actkind->add("W1|WR|S1|SR|M1|MR|G1|GR|P1|PR|X1|XR|??"); actkind->value(12); actkind->callback(flags_callback, new line_flag_CB_data_c(this, MLF_Activation | MLF_Repeatable)); actkind->deactivate(); actkind->hide(); Y += desc->h() + 2; tag = new Fl_Int_Input(X+58, Y, 64, 24, "Tag: "); tag->align(FL_ALIGN_LEFT); tag->callback(tag_callback, this); tag->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); length = new Fl_Int_Input(X+W/2+58, Y, 64, 24, "Length: "); length->align(FL_ALIGN_LEFT); length->callback(length_callback, this); length->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); for (int a = 0 ; a < 5 ; a++) { args[a] = new Fl_Int_Input(X+58+47*a, Y, 42, 24); args[a]->callback(args_callback, new line_flag_CB_data_c(this, a)); args[a]->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); args[a]->hide(); } args[0]->label("Args: "); Y += tag->h() + 10; Fl_Box *flags = new Fl_Box(FL_FLAT_BOX, X+10, Y, 64, 24, "Flags: "); flags->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); f_automap = new Fl_Choice(X+W-118, Y, 104, 22, "Vis: "); f_automap->add("Normal|Invisible|Mapped|Secret"); f_automap->value(0); f_automap->callback(flags_callback, new line_flag_CB_data_c(this, MLF_ALL_AUTOMAP)); Y += flags->h() - 1; int FW = 110; f_upper = new Fl_Check_Button(X+28, Y+2, FW, 20, "upper unpeg"); f_upper->labelsize(12); f_upper->callback(flags_callback, new line_flag_CB_data_c(this, MLF_UpperUnpegged)); f_walk = new Fl_Check_Button(X+W-120, Y+2, FW, 20, "block walk"); f_walk->labelsize(12); f_walk->callback(flags_callback, new line_flag_CB_data_c(this, MLF_Blocking)); Y += 19; f_lower = new Fl_Check_Button(X+28, Y+2, FW, 20, "lower unpeg"); f_lower->labelsize(12); f_lower->callback(flags_callback, new line_flag_CB_data_c(this, MLF_LowerUnpegged)); f_mons = new Fl_Check_Button(X+W-120, Y+2, FW, 20, "block mons"); f_mons->labelsize(12); f_mons->callback(flags_callback, new line_flag_CB_data_c(this, MLF_BlockMonsters)); Y += 19; f_passthru = new Fl_Check_Button(X+28, Y+2, FW, 20, "pass thru"); f_passthru->labelsize(12); f_passthru->callback(flags_callback, new line_flag_CB_data_c(this, MLF_Boom_PassThru)); f_passthru->hide(); f_sound = new Fl_Check_Button(X+W-120, Y+2, FW, 20, "sound block"); f_sound->labelsize(12); f_sound->callback(flags_callback, new line_flag_CB_data_c(this, MLF_SoundBlock)); Y += 19; f_3dmidtex = new Fl_Check_Button(X+W-120, Y+2, FW, 20, "3D MidTex"); f_3dmidtex->labelsize(12); f_3dmidtex->callback(flags_callback, new line_flag_CB_data_c(this, MLF_Eternity_3DMidTex)); f_3dmidtex->hide(); Y += 24; front = new UI_SideBox(x(), Y, w(), 140, 0); Y += front->h() + 16; back = new UI_SideBox(x(), Y, w(), 140, 1); Y += back->h(); end(); resizable(NULL); } // // UI_LineBox Destructor // UI_LineBox::~UI_LineBox() { } void UI_LineBox::type_callback(Fl_Widget *w, void *data) { UI_LineBox *box = (UI_LineBox *)data; int new_type = atoi(box->type->value()); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { BA_ChangeLD(*it, LineDef::F_TYPE, new_type); } BA_End(); } // update description box->UpdateField(LineDef::F_TYPE); } void UI_LineBox::SetTexOnLine(int ld, int new_tex, int e_state, int front_pics, int back_pics) { bool opposite = (e_state & FL_SHIFT); LineDef *L = LineDefs[ld]; // handle the selected texture boxes if (front_pics || back_pics) { if (L->OneSided()) { if (front_pics & 1) BA_ChangeSD(L->right, SideDef::F_MID_TEX, new_tex); if (front_pics & 2) BA_ChangeSD(L->right, SideDef::F_UPPER_TEX, new_tex); return; } if (L->Right()) { if (front_pics & 1) BA_ChangeSD(L->right, SideDef::F_LOWER_TEX, new_tex); if (front_pics & 2) BA_ChangeSD(L->right, SideDef::F_UPPER_TEX, new_tex); if (front_pics & 4) BA_ChangeSD(L->right, SideDef::F_MID_TEX, new_tex); } if (L->Left()) { if (back_pics & 1) BA_ChangeSD(L->left, SideDef::F_LOWER_TEX, new_tex); if (back_pics & 2) BA_ChangeSD(L->left, SideDef::F_UPPER_TEX, new_tex); if (back_pics & 4) BA_ChangeSD(L->left, SideDef::F_MID_TEX, new_tex); } return; } // middle click : set mid-masked texture on both sides if (e_state & FL_BUTTON2) { if (! L->TwoSided()) return; // convenience: set lower unpeg on first change if (! (L->flags & MLF_LowerUnpegged) && L->Right()->MidTex()[0] == '-' && L-> Left()->MidTex()[0] == '-') { BA_ChangeLD(ld, LineDef::F_FLAGS, L->flags | MLF_LowerUnpegged); } BA_ChangeSD(L->left, SideDef::F_MID_TEX, new_tex); BA_ChangeSD(L->right, SideDef::F_MID_TEX, new_tex); return; } // one-sided case: set the middle texture only if (! L->TwoSided()) { int sd = (L->right >= 0) ? L->right : L->left; if (sd < 0) return; BA_ChangeSD(sd, SideDef::F_MID_TEX, new_tex); return; } // modify an upper texture int sd1 = L->right; int sd2 = L->left; if (e_state & FL_BUTTON3) { // back ceiling is higher? if (L->Left()->SecRef()->ceilh > L->Right()->SecRef()->ceilh) std::swap(sd1, sd2); if (opposite) std::swap(sd1, sd2); BA_ChangeSD(sd1, SideDef::F_UPPER_TEX, new_tex); } // modify a lower texture else { // back floor is lower? if (L->Left()->SecRef()->floorh < L->Right()->SecRef()->floorh) std::swap(sd1, sd2); if (opposite) std::swap(sd1, sd2); SideDef *S = SideDefs[sd1]; // change BOTH upper and lower when they are the same // (which is great for windows). // // Note: we only do this for LOWERS (otherwise it'd be // impossible to set them to different textures). if (S->lower_tex == S->upper_tex) BA_ChangeSD(sd1, SideDef::F_UPPER_TEX, new_tex); BA_ChangeSD(sd1, SideDef::F_LOWER_TEX, new_tex); } } void UI_LineBox::SetTexture(const char *tex_name, int e_state) { int new_tex = BA_InternaliseString(tex_name); int front_pics = front->GetSelectedPics(); int back_pics = back->GetSelectedPics(); // this works a bit differently than other ways, we don't modify a // widget and let it update the map, instead we update the map and // let the widget(s) get updated. That's because we do different // things depending on whether the line is one-sided or two-sided. selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { SetTexOnLine(*it, new_tex, e_state, front_pics, back_pics); } BA_End(); } UpdateField(); UpdateSides(); redraw(); } void UI_LineBox::SetLineType(int new_type) { if (obj < 0) { /// Beep("No lines selected"); return; } char buffer[64]; sprintf(buffer, "%d", new_type); type->value(buffer); type->do_callback(); } void UI_LineBox::tag_callback(Fl_Widget *w, void *data) { UI_LineBox *box = (UI_LineBox *)data; int new_tag = atoi(box->tag->value()); Tags_ApplyNewValue(new_tag); } void UI_LineBox::flags_callback(Fl_Widget *w, void *data) { line_flag_CB_data_c *l_f_c = (line_flag_CB_data_c *)data; UI_LineBox *box = l_f_c->parent; int mask = l_f_c->mask; int new_flags = box->CalcFlags(); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { const LineDef *L = LineDefs[*it]; // only change the bits specified in 'mask'. // this is important when multiple linedefs are selected. BA_ChangeLD(*it, LineDef::F_FLAGS, (L->flags & ~mask) | (new_flags & mask)); } BA_End(); } } void UI_LineBox::args_callback(Fl_Widget *w, void *data) { line_flag_CB_data_c *l_f_c = (line_flag_CB_data_c *)data; UI_LineBox *box = l_f_c->parent; int arg_idx = l_f_c->mask; int new_value = atoi(box->args[arg_idx]->value()); new_value = CLAMP(0, new_value, 255); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { BA_ChangeLD(*it, LineDef::F_TAG + arg_idx, new_value); } BA_End(); } } void UI_LineBox::length_callback(Fl_Widget *w, void *data) { UI_LineBox *box = (UI_LineBox *)data; int new_len = atoi(box->length->value()); new_len = CLAMP(1, new_len, 32768); LineDefs_SetLength(new_len); } void UI_LineBox::button_callback(Fl_Widget *w, void *data) { UI_LineBox *box = (UI_LineBox *)data; if (w == box->choose) { int cur_type = atoi(box->type->value()); if ((game_info.gen_types && is_genline(cur_type)) || Fl::event_button() == 3) { main_win->ShowBrowser('G'); return; } main_win->ShowBrowser('L'); return; } if (w == box->gen) { main_win->ShowBrowser('G'); return; } } //------------------------------------------------------------------------ void UI_LineBox::SetObj(int _index, int _count) { if (obj == _index && count == _count) return; obj = _index; count = _count; which->SetIndex(obj); which->SetSelected(count); UpdateField(); if (obj < 0) UnselectPics(); redraw(); } void UI_LineBox::UpdateField(int field) { if (field < 0 || field == LineDef::F_START || field == LineDef::F_END) { if (is_linedef(obj)) CalcLength(); else length->value(""); } if (field < 0 || (field >= LineDef::F_TAG && field <= LineDef::F_ARG5)) { for (int a = 0 ; a < 5 ; a++) { args[a]->value(""); args[a]->tooltip(NULL); } if (is_linedef(obj)) { const LineDef *L = LineDefs[obj]; tag->value(Int_TmpStr(LineDefs[obj]->tag)); const linetype_t *info = M_GetLineType(L->type); if (Level_format == MAPF_Hexen) { if (L->tag || info->args[0]) args[0]->value(Int_TmpStr(L->tag)); if (L->arg2 || info->args[1]) args[1]->value(Int_TmpStr(L->arg2)); if (L->arg3 || info->args[2]) args[2]->value(Int_TmpStr(L->arg3)); if (L->arg4 || info->args[3]) args[3]->value(Int_TmpStr(L->arg4)); if (L->arg5 || info->args[4]) args[4]->value(Int_TmpStr(L->arg5)); // set tooltips for (int a = 0 ; a < 5 ; a++) if (info->args[a]) args[a]->copy_tooltip(info->args[a]); } } else { length->value(""); tag->value(""); } } if (field < 0 || field == LineDef::F_RIGHT || field == LineDef::F_LEFT) { if (is_linedef(obj)) { const LineDef *L = LineDefs[obj]; front->SetObj(L->right, SolidMask(SIDE_RIGHT), L->TwoSided()); back->SetObj(L->left, SolidMask(SIDE_LEFT), L->TwoSided()); } else { front->SetObj(SETOBJ_NO_LINE, 0, false); back->SetObj(SETOBJ_NO_LINE, 0, false); } } if (field < 0 || field == LineDef::F_TYPE) { if (is_linedef(obj)) { int type_num = LineDefs[obj]->type; type->value(Int_TmpStr(type_num)); const char *gen_desc = GeneralizedDesc(type_num); if (gen_desc) { desc->value(gen_desc); choose->label("Edit"); } else { const linetype_t *info = M_GetLineType(type_num); desc->value(info->desc); choose->label("Choose"); } main_win->browser->UpdateGenType(type_num); } else { type->value(""); desc->value(""); choose->label("Choose"); main_win->browser->UpdateGenType(0); } } if (field < 0 || field == LineDef::F_FLAGS) { if (is_linedef(obj)) { actkind->activate(); FlagsFromInt(LineDefs[obj]->flags); } else { FlagsFromInt(0); actkind->value(12); // show as "??" actkind->deactivate(); } } } void UI_LineBox::UpdateSides() { front->UpdateField(); back->UpdateField(); } void UI_LineBox::UnselectPics() { front->UnselectPics(); back->UnselectPics(); } void UI_LineBox::CalcLength() { // ASSERT(obj >= 0); int n = obj; float len_f = LineDefs[n]->CalcLength(); char buffer[300]; if (int(len_f) >= 10000) sprintf(buffer, "%1.0f", len_f); else if (int(len_f) >= 100) sprintf(buffer, "%1.1f", len_f); else sprintf(buffer, "%1.2f", len_f); length->value(buffer); } void UI_LineBox::FlagsFromInt(int lineflags) { // compute activation if (Level_format == MAPF_Hexen) { int new_act = (lineflags & MLF_Activation) >> 9; new_act |= (lineflags & MLF_Repeatable) ? 1 : 0; // show "??" for unknown values if (new_act > 12) new_act = 12; actkind->value(new_act); } if (lineflags & MLF_Secret) f_automap->value(3); else if (lineflags & MLF_DontDraw) f_automap->value(1); else if (lineflags & MLF_Mapped) f_automap->value(2); else f_automap->value(0); f_upper ->value((lineflags & MLF_UpperUnpegged) ? 1 : 0); f_lower ->value((lineflags & MLF_LowerUnpegged) ? 1 : 0); f_passthru->value((lineflags & MLF_Boom_PassThru) ? 1 : 0); f_3dmidtex->value((lineflags & MLF_Eternity_3DMidTex) ? 1 : 0); f_walk ->value((lineflags & MLF_Blocking) ? 1 : 0); f_mons ->value((lineflags & MLF_BlockMonsters) ? 1 : 0); f_sound->value((lineflags & MLF_SoundBlock) ? 1 : 0); } int UI_LineBox::CalcFlags() const { int lineflags = 0; switch (f_automap->value()) { case 0: /* Normal */; break; case 1: /* Invisible */ lineflags |= MLF_DontDraw; break; case 2: /* Mapped */ lineflags |= MLF_Mapped; break; case 3: /* Secret */ lineflags |= MLF_Secret; break; } if (f_upper->value()) lineflags |= MLF_UpperUnpegged; if (f_lower->value()) lineflags |= MLF_LowerUnpegged; if (f_walk->value()) lineflags |= MLF_Blocking; if (f_mons->value()) lineflags |= MLF_BlockMonsters; if (f_sound->value()) lineflags |= MLF_SoundBlock; if (Level_format == MAPF_Hexen) { int actval = actkind->value(); if (actval >= 12) actval = 0; lineflags |= (actval << 9); } else { if (game_info.pass_through && f_passthru->value()) lineflags |= MLF_Boom_PassThru; if (game_info.midtex_3d && f_3dmidtex->value()) lineflags |= MLF_Eternity_3DMidTex; } return lineflags; } void UI_LineBox::UpdateTotal() { which->SetTotal(NumLineDefs); } int UI_LineBox::SolidMask(int side) { SYS_ASSERT(is_linedef(obj)); const LineDef *L = LineDefs[obj]; if (L->left < 0 && L->right < 0) return 0; if (L->left < 0 || L->right < 0) return SOLID_MID; Sector *right = L->Right()->SecRef(); Sector * left = L->Left ()->SecRef(); if (side == SIDE_LEFT) std::swap(left, right); int mask = 0; if (right->floorh < left->floorh) mask |= SOLID_LOWER; // upper texture of '-' is OK between two skies bool two_skies = is_sky(right->CeilTex()) && is_sky(left->CeilTex()); if (right-> ceilh > left-> ceilh && ! two_skies) mask |= SOLID_UPPER; return mask; } void UI_LineBox::UpdateGameInfo() { choose->label("Choose"); if (Level_format == MAPF_Hexen) { tag->hide(); length->hide(); gen->hide(); actkind->show(); desc->resize(type->x() + 65, desc->y(), w()-78-65, desc->h()); f_passthru->hide(); f_3dmidtex->hide(); } else { tag->show(); length->show(); actkind->hide(); desc->resize(type->x(), desc->y(), w()-78, desc->h()); if (game_info.pass_through) f_passthru->show(); else f_passthru->hide(); if (game_info.midtex_3d) f_3dmidtex->show(); else f_3dmidtex->hide(); #if 0 if (game_info.gen_types) gen->show(); else #endif gen->hide(); } for (int a = 0 ; a < 5 ; a++) { if (Level_format == MAPF_Hexen) args[a]->show(); else args[a]->hide(); } redraw(); } const char * UI_LineBox::GeneralizedDesc(int type_num) { if (! game_info.gen_types) return NULL; static char desc_buffer[256]; for (int i = 0 ; i < num_gen_linetypes ; i++) { const generalized_linetype_t *info = &gen_linetypes[i]; if (type_num >= info->base && type_num < (info->base + info->length)) { // grab trigger name (we assume it is first field) if (info->num_fields < 1 || info->fields[0].num_keywords < 8) return NULL; const char *trigger = info->fields[0].keywords[type_num & 7]; sprintf(desc_buffer, "%s GENTYPE: %s", trigger, info->name); return desc_buffer; } } return NULL; // not a generalized linetype } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_misc.h0000644000175100017510000000463212647061302016064 0ustar aaptedaapted//------------------------------------------------------------------------ // Miscellaneous UI Dialogs //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2013 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 __EUREKA_UI_MISC_H__ #define __EUREKA_UI_MISC_H__ class UI_MoveDialog : public UI_Escapable_Window { private: Fl_Int_Input *delta_x; Fl_Int_Input *delta_y; Fl_Int_Input *delta_z; Fl_Button *ok_but; Fl_Button *cancel_but; bool want_close; public: UI_MoveDialog(); virtual ~UI_MoveDialog(); void Run(); bool WantClose() { return want_close; } private: static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); }; //------------------------------------------------------------------------ class UI_ScaleDialog : public UI_Escapable_Window { private: Fl_Input *scale_x; Fl_Input *scale_y; Fl_Input *scale_z; Fl_Choice *origin_x; Fl_Choice *origin_y; Fl_Choice *origin_z; Fl_Button *ok_but; Fl_Button *cancel_but; bool want_close; public: UI_ScaleDialog(); virtual ~UI_ScaleDialog(); void Run(); bool WantClose() { return want_close; } private: static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); }; //------------------------------------------------------------------------ class UI_RotateDialog : public UI_Escapable_Window { private: Fl_Float_Input *angle; Fl_Choice *dir; Fl_Choice *origin; Fl_Button *ok_but; Fl_Button *cancel_but; bool want_close; public: UI_RotateDialog(); virtual ~UI_RotateDialog(); void Run(); bool WantClose() { return want_close; } private: static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_MISC_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_misc.cc0000644000175100017510000001655112647061302016225 0ustar aaptedaapted//------------------------------------------------------------------------ // Miscellaneous UI Dialogs //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2013 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 "main.h" #include "ui_window.h" #include "ui_misc.h" #include "x_mirror.h" UI_MoveDialog::UI_MoveDialog() : UI_Escapable_Window(360, 205, "Move Objects"), want_close(false) { Fl_Box *title = new Fl_Box(10, 11, w() - 20, 32, "Enter the offset to move objects:"); title->labelsize(KF_fonth); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); delta_x = new Fl_Int_Input(95, 55, 65, 25, "delta x:"); delta_y = new Fl_Int_Input(95, 85, 65, 25, "delta y:"); delta_z = new Fl_Int_Input(240, 85, 65, 25, "delta z:"); delta_x->value("0"); delta_y->value("0"); delta_z->value("0"); Fl_Group * grp = new Fl_Group(0, h() - 70, w(), 70); grp->box(FL_FLAT_BOX); grp->color(WINDOW_BG, WINDOW_BG); { cancel_but = new Fl_Button(30, grp->y() + 20, 95, 30, "Cancel"); cancel_but->callback(close_callback, this); ok_but = new Fl_Button(245, grp->y() + 20, 95, 30, "Move"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); grp->end(); } end(); resizable(NULL); callback(close_callback, this); } UI_MoveDialog::~UI_MoveDialog() { } void UI_MoveDialog::Run() { if (edit.mode != OBJ_SECTORS) { delta_z->hide(); } set_modal(); show(); while (! WantClose()) { Fl::wait(0.2); } } void UI_MoveDialog::close_callback(Fl_Widget *w, void *data) { UI_MoveDialog * that = (UI_MoveDialog *)data; that->want_close = true; } void UI_MoveDialog::ok_callback(Fl_Widget *w, void *data) { UI_MoveDialog * that = (UI_MoveDialog *)data; int delta_x = atoi(that->delta_x->value()); int delta_y = atoi(that->delta_y->value()); int delta_z = atoi(that->delta_z->value()); CMD_MoveObjects(delta_x, delta_y, delta_z); that->want_close = true; } //------------------------------------------------------------------------ UI_ScaleDialog::UI_ScaleDialog() : UI_Escapable_Window(360, 270, "Scale Objects"), want_close(false) { Fl_Box *title = new Fl_Box(10, 11, w() - 20, 32, "Enter the scale amount:"); title->labelsize(KF_fonth); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); scale_x = new Fl_Input( 95, 55, 85, 25, "scale x:"); scale_y = new Fl_Input( 95, 85, 85, 25, "scale y:"); scale_z = new Fl_Input( 95, 115, 85, 25, "scale z:"); scale_x->value("1"); scale_y->value("1"); scale_z->value("1"); origin_x = new Fl_Choice(234, 55, 100, 25, "from:"); origin_y = new Fl_Choice(234, 85, 100, 25, "from:"); origin_z = new Fl_Choice(234, 115, 100, 25, "from:"); origin_x->add("Left|Centre|Right"); origin_x->value(1); origin_y->add("Bottom|Centre|Top"); origin_y->value(1); origin_z->add("Bottom|Middle|Top"); origin_z->value(0); Fl_Group * grp = new Fl_Group(0, 160, w(), h() - 160); grp->box(FL_FLAT_BOX); grp->color(WINDOW_BG, WINDOW_BG); { Fl_Box * help = new Fl_Box(10, 175, w() - 20, 40); help->label("Scale Values:\n" " can be real: 0.25 or 3.7\n" " or percentages: 25%\n" " or fractions: 3 / 4"); help->align(FL_ALIGN_LEFT | FL_ALIGN_TOP | FL_ALIGN_INSIDE); cancel_but = new Fl_Button(245, 180, 95, 30, "Cancel"); cancel_but->callback(close_callback, this); ok_but = new Fl_Button(245, 225, 95, 30, "Scale"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); grp->end(); } end(); resizable(NULL); callback(close_callback, this); } UI_ScaleDialog::~UI_ScaleDialog() { } void UI_ScaleDialog::Run() { if (edit.mode != OBJ_SECTORS) { scale_z->hide(); origin_z->hide(); } set_modal(); show(); while (! WantClose()) { Fl::wait(0.2); } } static double ParseScaleStr(const char * s) { // handle percentages if (strchr(s, '%')) { double val; if (sscanf(s, " %lf %% ", &val) != 1) return -1; return val / 100.0; } // handle fractions if (strchr(s, '/')) { double num, denom; if (sscanf(s, " %lf / %lf ", &num, &denom) != 2) return -1; if (denom <= 0) return -1; return num / denom; } return atof(s); } void UI_ScaleDialog::close_callback(Fl_Widget *w, void *data) { UI_ScaleDialog * that = (UI_ScaleDialog *)data; that->want_close = true; } void UI_ScaleDialog::ok_callback(Fl_Widget *w, void *data) { UI_ScaleDialog * that = (UI_ScaleDialog *)data; double scale_x = ParseScaleStr(that->scale_x->value()); double scale_y = ParseScaleStr(that->scale_y->value()); double scale_z = ParseScaleStr(that->scale_z->value()); if (scale_x <= 0 || scale_y <= 0 || scale_z <= 0) { fl_beep(); return; } int pos_x = that->origin_x->value() - 1; int pos_y = that->origin_y->value() - 1; int pos_z = that->origin_z->value() - 1; if (edit.mode == OBJ_SECTORS) CMD_ScaleObjects3(scale_x, scale_y, scale_z, pos_x, pos_y, pos_z); else CMD_ScaleObjects3(scale_x, scale_y, pos_x, pos_y); that->want_close = true; } //------------------------------------------------------------------------ UI_RotateDialog::UI_RotateDialog() : UI_Escapable_Window(360, 200, "Rotate Objects"), want_close(false) { Fl_Box *title = new Fl_Box(10, 11, w() - 20, 32, "Enter # of degrees to rotate objects:"); title->labelsize(KF_fonth); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); angle = new Fl_Float_Input(95, 55, 65, 25, "angle:"); angle->value("0"); dir = new Fl_Choice(170, 55, 140, 25); dir->add("Clockwise|Anti-clockwise"); dir->value(0); origin = new Fl_Choice(95, 90, 140, 25, "origin:"); origin->add("Bottom Left|Bottom|Bottom Right|" "Left|Centre|Right|" "Top Left|Top|Top Right"); origin->value(4); Fl_Group * grp = new Fl_Group(0, h() - 70, w(), 70); grp->box(FL_FLAT_BOX); grp->color(WINDOW_BG, WINDOW_BG); { cancel_but = new Fl_Button(30, grp->y() + 20, 95, 30, "Cancel"); cancel_but->callback(close_callback, this); ok_but = new Fl_Button(245, grp->y() + 20, 95, 30, "Rotate"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); grp->end(); } end(); resizable(NULL); callback(close_callback, this); } UI_RotateDialog::~UI_RotateDialog() { } void UI_RotateDialog::Run() { set_modal(); show(); while (! WantClose()) { Fl::wait(0.2); } } void UI_RotateDialog::close_callback(Fl_Widget *w, void *data) { UI_RotateDialog * that = (UI_RotateDialog *)data; that->want_close = true; } void UI_RotateDialog::ok_callback(Fl_Widget *w, void *data) { UI_RotateDialog * that = (UI_RotateDialog *)data; float angle = atof(that->angle->value()); if (that->dir->value() == 0) angle = -angle; int pos_x = (that->origin->value() % 3) - 1; int pos_y = (that->origin->value() / 3) - 1; CMD_RotateObjects3(angle, pos_x, pos_y); that->want_close = true; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_thing.cc0000644000175100017510000004626012651124057016405 0ustar aaptedaapted//------------------------------------------------------------------------ // THING PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 Andrew Apted // Copyright (C) 2015 Ioan Chera // // 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 "main.h" #include "ui_window.h" #include "editloop.h" #include "levels.h" #include "m_game.h" #include "w_rawdef.h" class thing_opt_CB_data_c { public: UI_ThingBox *parent; int mask; public: thing_opt_CB_data_c(UI_ThingBox *_parent, int _mask) : parent(_parent), mask(_mask) { } ~thing_opt_CB_data_c() { } }; extern const char * arrow_0_xpm[]; extern const char * arrow_45_xpm[]; extern const char * arrow_90_xpm[]; extern const char * arrow_135_xpm[]; extern const char * arrow_180_xpm[]; extern const char * arrow_225_xpm[]; extern const char * arrow_270_xpm[]; extern const char * arrow_315_xpm[]; static const char ** arrow_pixmaps[8] = { arrow_0_xpm, arrow_45_xpm, arrow_90_xpm, arrow_135_xpm, arrow_180_xpm, arrow_225_xpm, arrow_270_xpm, arrow_315_xpm }; // // UI_ThingBox Constructor // UI_ThingBox::UI_ThingBox(int X, int Y, int W, int H, const char *label) : Fl_Group(X, Y, W, H, label), obj(-1), count(0) { box(FL_FLAT_BOX); X += 6; Y += 6; W -= 12; H -= 10; which = new UI_Nombre(X+6, Y, W-12, 28, "Thing"); Y = Y + which->h() + 4; type = new Fl_Int_Input(X+70, Y, 64, 24, "Type: "); type->align(FL_ALIGN_LEFT); type->callback(type_callback, this); type->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); choose = new Fl_Button(X+W/2+24, Y, 80, 24, "Choose"); choose->callback(button_callback, this); Y = Y + type->h() + 4; desc = new Fl_Output(X+70, Y, W-78, 24, "Desc: "); desc->align(FL_ALIGN_LEFT); Y = Y + desc->h() + 4; sprite = new UI_Pic(X + W - 120, Y + 10, 100,100, "Sprite"); sprite->callback(button_callback, this); Y = Y + 10; pos_x = new Fl_Int_Input(X+70, Y, 70, 24, "x: "); pos_y = new Fl_Int_Input(X+70, Y + 28, 70, 24, "y: "); pos_z = new Fl_Int_Input(X+70, Y + 28*2, 70, 24, "z: "); pos_z->hide(); pos_x->align(FL_ALIGN_LEFT); pos_y->align(FL_ALIGN_LEFT); pos_z->align(FL_ALIGN_LEFT); pos_x->callback(x_callback, this); pos_y->callback(y_callback, this); pos_z->callback(z_callback, this); pos_x->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); pos_y->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); pos_z->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y = Y + 105; // IOANCH 9/2015: TID tid = new Fl_Int_Input(X+70, Y, 64, 24, "TID: "); tid->align(FL_ALIGN_LEFT); tid->callback(tid_callback, this); tid->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y = Y + tid->h() + 4; angle = new Fl_Int_Input(X+70, Y, 64, 24, "Angle: "); angle->align(FL_ALIGN_LEFT); angle->callback(angle_callback, this); angle->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); int ang_mx = X + W - 75; int ang_my = Y + 15; for (int i = 0 ; i < 8 ; i++) { int x = ang_mx + 30 * cos(i * 45 * M_PI / 180.0); int y = ang_my - 30 * sin(i * 45 * M_PI / 180.0); ang_buts[i] = new Fl_Button(x - 9, y - 9, 24, 24, 0); ang_buts[i]->image(new Fl_Pixmap(arrow_pixmaps[i])); ang_buts[i]->align(FL_ALIGN_CENTER); ang_buts[i]->clear_visible_focus(); ang_buts[i]->callback(button_callback, this); } Y = Y + 50; Fl_Box *opt_lab = new Fl_Box(X+10, Y, W, 22, "Options Flags:"); opt_lab->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); Y = Y + opt_lab->h() + 2; // when appear: two rows of three on/off buttons int AX = X+W/3+4; int BX = X+2*W/3-20; int FW = W/3 - 12; int AY = Y+22; int BY = Y+22*2; o_easy = new Fl_Check_Button( X+28, Y, FW, 22, "easy"); o_medium = new Fl_Check_Button( X+28, AY, FW, 22, "medium"); o_hard = new Fl_Check_Button( X+28, BY, FW, 22, "hard"); o_sp = new Fl_Check_Button(AX+28, Y, FW, 22, "sp"); o_coop = new Fl_Check_Button(AX+28, AY, FW, 22, "coop"); o_dm = new Fl_Check_Button(AX+28, BY, FW, 22, "dm"); // this is shown only for Vanilla DOOM (instead of the above three). // it is also works differently, no negated like the above. o_vanilla_dm = new Fl_Check_Button(AX+28, BY, FW, 22, "dm"); o_easy ->value(1); o_sp ->value(1); o_medium->value(1); o_coop->value(1); o_hard ->value(1); o_dm ->value(1); o_vanilla_dm->value(0); o_easy ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Easy)); o_medium->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Medium)); o_hard ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Hard)); o_sp ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Not_SP)); o_coop ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Not_COOP)); o_dm ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Not_DM)); o_vanilla_dm->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Not_SP)); // Hexen class flags o_fight = new Fl_Check_Button(BX+28, Y, FW, 22, "Fighter"); o_cleric = new Fl_Check_Button(BX+28, AY, FW, 22, "Cleric"); o_mage = new Fl_Check_Button(BX+28, BY, FW, 22, "Mage"); o_fight ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Hexen_Fighter)); o_cleric->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Hexen_Cleric)); o_mage ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Hexen_Mage)); o_fight ->hide(); o_cleric->hide(); o_mage ->hide(); Y = BY + 35; o_ambush = new Fl_Check_Button( X+28, Y, FW, 22, "ambush"); o_friend = new Fl_Check_Button(AX+28, Y, FW, 22, "friend"); o_dormant = new Fl_Check_Button(BX+28, Y, FW, 22, "dormant"); o_ambush ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Ambush)); o_friend ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Friend)); o_dormant->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Hexen_Dormant)); o_dormant->hide(); Y = Y + 45; exfloor = new Fl_Int_Input(X+84, Y, 64, 24, "3D Floor: "); exfloor->align(FL_ALIGN_LEFT); exfloor->callback(option_callback, new thing_opt_CB_data_c(this, MTF_EXFLOOR_MASK)); exfloor->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); efl_down = new Fl_Button(X+165, Y+1, 30, 22, "-"); efl_up = new Fl_Button(X+210, Y+1, 30, 22, "+"); efl_down->labelfont(FL_HELVETICA_BOLD); efl_up ->labelfont(FL_HELVETICA_BOLD); efl_down->labelsize(16); efl_up ->labelsize(16); efl_down->callback(button_callback, this); efl_up ->callback(button_callback, this); #if 0 Y = Y + exfloor->h() + 10; #else exfloor->hide(); efl_down->hide(); efl_up->hide(); #endif // Hexen thing specials spec_type = new Fl_Int_Input(X+74, Y, 64, 24, "Special: "); spec_type->align(FL_ALIGN_LEFT); spec_type->callback(spec_callback, this); spec_type->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); spec_type->hide(); spec_choose = new Fl_Button(X+W/2+24, Y, 80, 24, "Choose"); spec_choose->callback(button_callback, this); spec_choose->hide(); Y = Y + spec_type->h() + 2; spec_desc = new Fl_Output(X+74, Y, W-86, 24, "Desc: "); spec_desc->align(FL_ALIGN_LEFT); spec_desc->hide(); Y = Y + spec_desc->h() + 2; for (int a = 0 ; a < 5 ; a++) { args[a] = new Fl_Int_Input(X+74+43*a, Y, 39, 24); args[a]->callback(args_callback, new thing_opt_CB_data_c(this, a)); args[a]->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); args[a]->hide(); } args[0]->label("Args: "); end(); resizable(NULL); } // // UI_ThingBox Destructor // UI_ThingBox::~UI_ThingBox() { } void UI_ThingBox::SetObj(int _index, int _count) { if (obj == _index && count == _count) return; obj = _index; count = _count; which->SetIndex(obj); which->SetSelected(count); UpdateField(); redraw(); } void UI_ThingBox::type_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_type = atoi(box->type->value()); const thingtype_t *info = M_GetThingType(new_type); box->desc->value(info->desc); box->sprite->GetSprite(new_type, FL_DARK2); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { BA_ChangeTH(*it, Thing::F_TYPE, new_type); } BA_End(); } } void UI_ThingBox::spec_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_type = atoi(box->spec_type->value()); const linetype_t *info = M_GetLineType(new_type); if (new_type == 0) box->spec_desc->value(""); else box->spec_desc->value(info->desc); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { BA_ChangeTH(*it, Thing::F_SPECIAL, new_type); } BA_End(); } } void UI_ThingBox::SetThingType(int new_type) { if (obj < 0) return; char buffer[64]; sprintf(buffer, "%d", new_type); type->value(buffer); type->do_callback(); } void UI_ThingBox::SetSpecialType(int new_type) { if (obj < 0) return; char buffer[64]; sprintf(buffer, "%d", new_type); spec_type->value(buffer); spec_type->do_callback(); } void UI_ThingBox::angle_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_ang = atoi(box->angle->value()); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { BA_ChangeTH(*it, Thing::F_ANGLE, new_ang); } BA_End(); } } // IOANCH 9/2015 void UI_ThingBox::tid_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_tid = atoi(box->tid->value()); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { BA_ChangeTH(*it, Thing::F_TID, new_tid); } BA_End(); } } void UI_ThingBox::x_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_x = atoi(box->pos_x->value()); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) BA_ChangeTH(*it, Thing::F_X, new_x); BA_End(); } } void UI_ThingBox::y_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_y = atoi(box->pos_y->value()); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) BA_ChangeTH(*it, Thing::F_Y, new_y); BA_End(); } } void UI_ThingBox::z_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_z = atoi(box->pos_z->value()); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) BA_ChangeTH(*it, Thing::F_Z, new_z); BA_End(); } } void UI_ThingBox::option_callback(Fl_Widget *w, void *data) { thing_opt_CB_data_c *ocb = (thing_opt_CB_data_c *)data; UI_ThingBox *box = ocb->parent; int mask = ocb->mask; int new_opts = box->CalcOptions(); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { const Thing *T = Things[*it]; // only change the bits specified in 'mask'. // this is important when multiple things are selected. BA_ChangeTH(*it, Thing::F_OPTIONS, (T->options & ~mask) | (new_opts & mask)); } BA_End(); } } void UI_ThingBox::button_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; if (w == box->efl_down) box->AdjustExtraFloor(-1); if (w == box->efl_up) box->AdjustExtraFloor(+1); if (w == box->choose || w == box->sprite) main_win->ShowBrowser('O'); if (w == box->spec_choose) main_win->ShowBrowser('L'); // check for the angle buttons for (int i = 0 ; i < 8 ; i++) { if (w == box->ang_buts[i]) { char buffer[20]; sprintf(buffer, "%d", i * 45); box->angle->value(buffer); angle_callback(box->angle, box); } } } void UI_ThingBox::args_callback(Fl_Widget *w, void *data) { thing_opt_CB_data_c *ocb = (thing_opt_CB_data_c *)data; UI_ThingBox *box = ocb->parent; int arg_idx = ocb->mask; int new_value = atoi(box->args[arg_idx]->value()); new_value = CLAMP(0, new_value, 255); selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { BA_ChangeTH(*it, Thing::F_ARG1 + arg_idx, new_value); } BA_End(); } } void UI_ThingBox::AdjustExtraFloor(int dir) { if (! is_thing(obj)) return; int old_fl = atoi(exfloor->value()); int new_fl = (old_fl + dir) & 15; if (new_fl) exfloor->value(Int_TmpStr(new_fl)); else exfloor->value(""); thing_opt_CB_data_c ocb(this, MTF_EXFLOOR_MASK); option_callback(this, &ocb); } void UI_ThingBox::OptionsFromInt(int options) { o_easy ->value((options & MTF_Easy) ? 1 : 0); o_medium->value((options & MTF_Medium) ? 1 : 0); o_hard ->value((options & MTF_Hard) ? 1 : 0); o_ambush->value((options & MTF_Ambush) ? 1 : 0); if (Level_format == MAPF_Hexen) { o_sp ->value((options & MTF_Hexen_SP) ? 1 : 0); o_coop->value((options & MTF_Hexen_COOP) ? 1 : 0); o_dm ->value((options & MTF_Hexen_DM) ? 1 : 0); o_fight ->value((options & MTF_Hexen_Fighter) ? 1 : 0); o_cleric->value((options & MTF_Hexen_Cleric) ? 1 : 0); o_mage ->value((options & MTF_Hexen_Mage) ? 1 : 0); o_dormant->value((options & MTF_Hexen_Dormant) ? 1 : 0); } else { o_sp ->value((options & MTF_Not_SP) ? 0 : 1); o_coop->value((options & MTF_Not_COOP) ? 0 : 1); o_dm ->value((options & MTF_Not_DM) ? 0 : 1); o_vanilla_dm->value((options & MTF_Not_SP) ? 1 : 0); } if (Level_format != MAPF_Hexen) { o_friend->value((options & MTF_Friend) ? 1 : 0); if (options & MTF_EXFLOOR_MASK) exfloor->value(Int_TmpStr((options & MTF_EXFLOOR_MASK) >> MTF_EXFLOOR_SHIFT)); else exfloor->value(""); } } int UI_ThingBox::CalcOptions() const { int options = 0; if (o_easy ->value()) options |= MTF_Easy; if (o_medium->value()) options |= MTF_Medium; if (o_hard ->value()) options |= MTF_Hard; if (o_ambush->value()) options |= MTF_Ambush; if (Level_format == MAPF_Hexen) { if (o_sp ->value()) options |= MTF_Hexen_SP; if (o_coop->value()) options |= MTF_Hexen_COOP; if (o_dm ->value()) options |= MTF_Hexen_DM; if (o_fight ->value()) options |= MTF_Hexen_Fighter; if (o_cleric->value()) options |= MTF_Hexen_Cleric; if (o_mage ->value()) options |= MTF_Hexen_Mage; if (o_dormant->value()) options |= MTF_Hexen_Dormant; } else if (game_info.coop_dm_flags) { if (0 == o_sp ->value()) options |= MTF_Not_SP; if (0 == o_coop->value()) options |= MTF_Not_COOP; if (0 == o_dm ->value()) options |= MTF_Not_DM; } else { if (o_vanilla_dm->value()) options |= MTF_Not_SP; } if (Level_format != MAPF_Hexen) { if (game_info.friend_flag && o_friend->value()) options |= MTF_Friend; #if 0 int exfl_num = atoi(exfloor->value()); if (exfl_num > 0) { options |= (exfl_num << MTF_EXFLOOR_SHIFT) & MTF_EXFLOOR_MASK; } #endif } return options; } void UI_ThingBox::UpdateField(int field) { if (field < 0 || field == Thing::F_X || field == Thing::F_Y || field == Thing::F_Z) { if (is_thing(obj)) { const Thing *T = Things[obj]; pos_x->value(Int_TmpStr(T->x)); pos_y->value(Int_TmpStr(T->y)); pos_z->value(Int_TmpStr(T->z)); } else { pos_x->value(""); pos_y->value(""); pos_z->value(""); } } if (field < 0 || field == Thing::F_ANGLE) { if (is_thing(obj)) angle->value(Int_TmpStr(Things[obj]->angle)); else angle->value(""); } // IOANCH 9/2015 if (field < 0 || field == Thing::F_TID) { if (is_thing(obj)) tid->value(Int_TmpStr(Things[obj]->tid)); else tid->value(""); } if (field < 0 || field == Thing::F_TYPE) { if (is_thing(obj)) { const thingtype_t *info = M_GetThingType(Things[obj]->type); desc->value(info->desc); type->value(Int_TmpStr(Things[obj]->type)); sprite->GetSprite(Things[obj]->type, FL_DARK2); } else { type ->value(""); desc ->value(""); sprite->Clear(); } } if (field < 0 || field == Thing::F_OPTIONS) { if (is_thing(obj)) OptionsFromInt(Things[obj]->options); else OptionsFromInt(0); } if (Level_format != MAPF_Hexen) return; if (field < 0 || field == Thing::F_SPECIAL) { if (is_thing(obj) && Things[obj]->special) { const linetype_t *info = M_GetLineType(Things[obj]->special); spec_desc->value(info->desc); spec_type->value(Int_TmpStr(Things[obj]->special)); } else { spec_type->value(""); spec_desc->value(""); } } if (field < 0 || (field >= Thing::F_ARG1 && field <= Thing::F_ARG5)) { for (int a = 0 ; a < 5 ; a++) { args[a]->value(""); args[a]->tooltip(NULL); } if (is_thing(obj)) { const Thing *T = Things[obj]; const linetype_t *info = M_GetLineType(T->special); if (T->arg1 || info->args[0]) args[0]->value(Int_TmpStr(T->arg1)); if (T->arg2 || info->args[1]) args[1]->value(Int_TmpStr(T->arg2)); if (T->arg3 || info->args[2]) args[2]->value(Int_TmpStr(T->arg3)); if (T->arg4 || info->args[3]) args[3]->value(Int_TmpStr(T->arg4)); if (T->arg5 || info->args[4]) args[4]->value(Int_TmpStr(T->arg5)); // set tooltips for (int a = 0 ; a < 5 ; a++) if (info->args[a]) args[a]->copy_tooltip(info->args[a]); } } } void UI_ThingBox::UpdateTotal() { which->SetTotal(NumThings); } void UI_ThingBox::UpdateGameInfo() { if (game_info.coop_dm_flags || Level_format == MAPF_Hexen) { o_sp ->show(); o_coop->show(); o_dm ->show(); o_vanilla_dm->hide(); } else { o_vanilla_dm->show(); o_sp ->hide(); o_coop->hide(); o_dm ->hide(); } if (game_info.friend_flag) o_friend->show(); else o_friend->hide(); /* map format stuff */ thing_opt_CB_data_c *ocb; if (Level_format == MAPF_Hexen) { pos_z->show(); tid->show(); o_fight ->show(); o_cleric->show(); o_mage ->show(); o_dormant->show(); spec_type ->show(); spec_choose->show(); spec_desc ->show(); for (int a = 0 ; a < 5 ; a++) args[a]->show(); // fix the masks for SP/COOP/DM ocb = (thing_opt_CB_data_c *) o_sp ->user_data(); ocb->mask = MTF_Hexen_SP; ocb = (thing_opt_CB_data_c *) o_coop->user_data(); ocb->mask = MTF_Hexen_COOP; ocb = (thing_opt_CB_data_c *) o_dm ->user_data(); ocb->mask = MTF_Hexen_DM; } else { pos_z->hide(); tid->hide(); o_fight ->hide(); o_cleric->hide(); o_mage ->hide(); o_dormant->hide(); spec_type ->hide(); spec_choose->hide(); spec_desc ->hide(); for (int a = 0 ; a < 5 ; a++) args[a]->hide(); // fix the masks for SP/COOP/DM ocb = (thing_opt_CB_data_c *) o_sp ->user_data(); ocb->mask = MTF_Not_SP; ocb = (thing_opt_CB_data_c *) o_coop->user_data(); ocb->mask = MTF_Not_COOP; ocb = (thing_opt_CB_data_c *) o_dm ->user_data(); ocb->mask = MTF_Not_DM; } redraw(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_basis.cc0000644000175100017510000005051712647061302016202 0ustar aaptedaapted//------------------------------------------------------------------------ // BASIC OBJECT HANDLING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2015 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include #include #include "e_basis.h" #include "levels.h" #include "lib_adler.h" #include "m_strings.h" #include "m_game.h" // g_default_xxx // need these for the XXX_Notify() prototypes #include "e_cutpaste.h" #include "objects.h" std::vector Things; std::vector Vertices; std::vector Sectors; std::vector SideDefs; std::vector LineDefs; std::vector HeaderData; std::vector BehaviorData; int default_floor_h = 0; int default_ceil_h = 128; int default_light_level = 176; int default_thing = 2001; const char * default_floor_tex = "FLAT1"; const char * default_ceil_tex = "FLAT1"; const char * default_lower_tex = "STARTAN3"; const char * default_mid_tex = "STARTAN3"; const char * default_upper_tex = "STARTAN3"; static bool did_make_changes; string_table_c basis_strtab; int NumObjects(obj_type_e type) { switch (type) { case OBJ_THINGS: return NumThings; case OBJ_LINEDEFS: return NumLineDefs; case OBJ_SIDEDEFS: return NumSideDefs; case OBJ_VERTICES: return NumVertices; case OBJ_SECTORS: return NumSectors; default: BugError("NumObjects: bad type: %d\n", (int)type); return 0; /* NOT REACHED */ } } static void DoClearChangeStatus() { did_make_changes = false; Clipboard_NotifyBegin(); Selection_NotifyBegin(); MapStuff_NotifyBegin(); ObjectBox_NotifyBegin(); } static void DoProcessChangeStatus() { if (did_make_changes) MarkChanges(); Clipboard_NotifyEnd(); Selection_NotifyEnd(); MapStuff_NotifyEnd(); ObjectBox_NotifyEnd(); } int BA_InternaliseString(const char *str) { return basis_strtab.add(str); } int BA_InternaliseShortStr(const char *str, int max_len) { std::string goodie(str, max_len); int result = BA_InternaliseString(goodie.c_str()); return result; } const char *BA_GetString(int offset) { return basis_strtab.get(offset); } const char * Sector::FloorTex() const { return basis_strtab.get(floor_tex); } const char * Sector::CeilTex() const { return basis_strtab.get(ceil_tex); } void Sector::SetDefaults() { floorh = default_floor_h; ceilh = default_ceil_h; floor_tex = BA_InternaliseString(default_floor_tex); ceil_tex = BA_InternaliseString(default_ceil_tex); light = default_light_level; } const char * SideDef::UpperTex() const { return basis_strtab.get(upper_tex); } const char * SideDef::MidTex() const { return basis_strtab.get(mid_tex); } const char * SideDef::LowerTex() const { return basis_strtab.get(lower_tex); } void SideDef::SetDefaults(bool two_sided) { lower_tex = BA_InternaliseString(default_lower_tex); upper_tex = BA_InternaliseString(default_upper_tex); if (two_sided) mid_tex = BA_InternaliseString("-"); else mid_tex = BA_InternaliseString(default_mid_tex); } Sector * SideDef::SecRef() const { return Sectors[sector]; } Vertex * LineDef::Start() const { return Vertices[start]; } Vertex * LineDef::End() const { return Vertices[end]; } SideDef * LineDef::Right() const { return (right >= 0) ? SideDefs[right] : NULL; } SideDef * LineDef::Left() const { return (left >= 0) ? SideDefs[left] : NULL; } bool LineDef::TouchesSector(int sec_num) const { if (right >= 0 && SideDefs[right]->sector == sec_num) return true; if (left >= 0 && SideDefs[left]->sector == sec_num) return true; return false; } int LineDef::WhatSector(int side) const { switch (side) { case SIDE_LEFT: return Left() ? Left()->sector : -1; case SIDE_RIGHT: return Right() ? Right()->sector : -1; default: BugError("bad side : %d\n", side); return -1; } } int LineDef::WhatSideDef(int side) const { switch (side) { case SIDE_LEFT: return left; case SIDE_RIGHT: return right; default: BugError("bad side : %d\n", side); return -1; } } double LineDef::CalcLength() const { int dx = Start()->x - End()->x; int dy = Start()->y - End()->y; return sqrt(dx * dx + dy * dy); } //------------------------------------------------------------------------ static void RawInsertThing(int objnum, int *ptr) { SYS_ASSERT(0 <= objnum && objnum <= NumThings); Things.push_back(NULL); for (int n = NumThings-1 ; n > objnum ; n--) Things[n] = Things[n - 1]; Things[objnum] = (Thing*) ptr; } static void RawInsertLineDef(int objnum, int *ptr) { SYS_ASSERT(0 <= objnum && objnum <= NumLineDefs); LineDefs.push_back(NULL); for (int n = NumLineDefs-1 ; n > objnum ; n--) LineDefs[n] = LineDefs[n - 1]; LineDefs[objnum] = (LineDef*) ptr; } static void RawInsertVertex(int objnum, int *ptr) { SYS_ASSERT(0 <= objnum && objnum <= NumVertices); Vertices.push_back(NULL); for (int n = NumVertices-1 ; n > objnum ; n--) Vertices[n] = Vertices[n - 1]; Vertices[objnum] = (Vertex*) ptr; // fix references in linedefs if (objnum+1 < NumVertices) { for (int n = NumLineDefs-1 ; n >= 0 ; n--) { LineDef *L = LineDefs[n]; if (L->start >= objnum) L->start++; if (L->end >= objnum) L->end++; } } } static void RawInsertSideDef(int objnum, int *ptr) { SYS_ASSERT(0 <= objnum && objnum <= NumSideDefs); SideDefs.push_back(NULL); for (int n = NumSideDefs-1 ; n > objnum ; n--) SideDefs[n] = SideDefs[n - 1]; SideDefs[objnum] = (SideDef*) ptr; // fix the linedefs references if (objnum+1 < NumSideDefs) { for (int n = NumLineDefs-1 ; n >= 0 ; n--) { LineDef *L = LineDefs[n]; if (L->right >= objnum) L->right++; if (L->left >= objnum) L->left++; } } } static void RawInsertSector(int objnum, int *ptr) { SYS_ASSERT(0 <= objnum && objnum <= NumSectors); Sectors.push_back(NULL); for (int n = NumSectors-1 ; n > objnum ; n--) Sectors[n] = Sectors[n - 1]; Sectors[objnum] = (Sector*) ptr; // fix all sidedef references if (objnum+1 < NumSectors) { for (int n = NumSideDefs-1 ; n >= 0 ; n--) { SideDef *S = SideDefs[n]; if (S->sector >= objnum) S->sector++; } } } static int * RawDeleteThing(int objnum) { SYS_ASSERT(0 <= objnum && objnum < NumThings); int * result = (int*) Things[objnum]; for (int n = objnum ; n < NumThings-1 ; n++) Things[n] = Things[n + 1]; Things.pop_back(); return result; } static void RawInsert(obj_type_e objtype, int objnum, int *ptr) { did_make_changes = true; Clipboard_NotifyInsert(objtype, objnum); Selection_NotifyInsert(objtype, objnum); MapStuff_NotifyInsert(objtype, objnum); ObjectBox_NotifyInsert(objtype, objnum); switch (objtype) { case OBJ_THINGS: RawInsertThing(objnum, ptr); break; case OBJ_VERTICES: RawInsertVertex(objnum, ptr); break; case OBJ_SIDEDEFS: RawInsertSideDef(objnum, ptr); break; case OBJ_SECTORS: RawInsertSector(objnum, ptr); break; case OBJ_LINEDEFS: RawInsertLineDef(objnum, ptr); break; default: BugError("RawInsert: bad objtype %d", (int) objtype); } } static int * RawDeleteLineDef(int objnum) { SYS_ASSERT(0 <= objnum && objnum < NumLineDefs); int * result = (int*) LineDefs[objnum]; for (int n = objnum ; n < NumLineDefs-1 ; n++) LineDefs[n] = LineDefs[n + 1]; LineDefs.pop_back(); return result; } static int * RawDeleteVertex(int objnum) { SYS_ASSERT(0 <= objnum && objnum < NumVertices); int * result = (int*) Vertices[objnum]; for (int n = objnum ; n < NumVertices-1 ; n++) Vertices[n] = Vertices[n + 1]; Vertices.pop_back(); // fix the linedef references if (objnum < NumVertices) { for (int n = NumLineDefs-1 ; n >= 0 ; n--) { LineDef *L = LineDefs[n]; if (L->start > objnum) L->start--; if (L->end > objnum) L->end--; } } return result; } static int * RawDeleteSideDef(int objnum) { SYS_ASSERT(0 <= objnum && objnum < NumSideDefs); int * result = (int*) SideDefs[objnum]; for (int n = objnum ; n < NumSideDefs-1 ; n++) SideDefs[n] = SideDefs[n + 1]; SideDefs.pop_back(); // fix the linedefs references if (objnum < NumSideDefs) { for (int n = NumLineDefs-1 ; n >= 0 ; n--) { LineDef *L = LineDefs[n]; if (L->right > objnum) L->right--; if (L->left > objnum) L->left--; } } return result; } static int * RawDeleteSector(int objnum) { SYS_ASSERT(0 <= objnum && objnum < NumSectors); int * result = (int*) Sectors[objnum]; for (int n = objnum ; n < NumSectors-1 ; n++) Sectors[n] = Sectors[n + 1]; Sectors.pop_back(); // fix sidedef references if (objnum < NumSectors) { for (int n = NumSideDefs-1 ; n >= 0 ; n--) { SideDef *S = SideDefs[n]; if (S->sector > objnum) S->sector--; } } return result; } static int * RawDelete(obj_type_e objtype, int objnum) { did_make_changes = true; Clipboard_NotifyDelete(objtype, objnum); Selection_NotifyDelete(objtype, objnum); MapStuff_NotifyDelete(objtype, objnum); ObjectBox_NotifyDelete(objtype, objnum); switch (objtype) { case OBJ_THINGS: return RawDeleteThing(objnum); case OBJ_VERTICES: return RawDeleteVertex(objnum); case OBJ_SECTORS: return RawDeleteSector(objnum); case OBJ_SIDEDEFS: return RawDeleteSideDef(objnum); case OBJ_LINEDEFS: return RawDeleteLineDef(objnum); default: BugError("RawDelete: bad objtype %d", (int) objtype); return NULL; /* NOT REACHED */ } } static void DeleteFinally(obj_type_e objtype, int *ptr) { // fprintf(stderr, "DeleteFinally: %p\n", ptr); switch (objtype) { case OBJ_THINGS: delete (Thing *) ptr; break; case OBJ_VERTICES: delete (Vertex *) ptr; break; case OBJ_SECTORS: delete (Sector *) ptr; break; case OBJ_SIDEDEFS: delete (SideDef *) ptr; break; case OBJ_LINEDEFS: delete (LineDef *) ptr; break; default: BugError("DeleteFinally: bad objtype %d", (int) objtype); } } static void RawChange(obj_type_e objtype, int objnum, int field, int *value) { int * pos = NULL; switch (objtype) { case OBJ_THINGS: pos = (int*) Things[objnum]; break; case OBJ_VERTICES: pos = (int*) Vertices[objnum]; break; case OBJ_SECTORS: pos = (int*) Sectors[objnum]; break; case OBJ_SIDEDEFS: pos = (int*) SideDefs[objnum]; break; case OBJ_LINEDEFS: pos = (int*) LineDefs[objnum]; break; default: BugError("RawGetBase: bad objtype %d", (int) objtype); return; /* NOT REACHED */ } std::swap(pos[field], *value); did_make_changes = true; Clipboard_NotifyChange(objtype, objnum, field); Selection_NotifyChange(objtype, objnum, field); MapStuff_NotifyChange(objtype, objnum, field); ObjectBox_NotifyChange(objtype, objnum, field); } //------------------------------------------------------------------------ // BASIS API IMPLEMENTATION //------------------------------------------------------------------------ enum { OP_CHANGE = 'c', OP_INSERT = 'i', OP_DELETE = 'd', }; class edit_op_c { public: char action; byte objtype; byte field; byte _pad; int objnum; int *ptr; int value; public: edit_op_c() : action(0), objtype(0), field(0), objnum(0), ptr(NULL), value(0) { } ~edit_op_c() { } void Apply() { switch (action) { case OP_CHANGE: RawChange((obj_type_e)objtype, objnum, (int)field, &value); return; case OP_DELETE: ptr = RawDelete((obj_type_e)objtype, objnum); action = OP_INSERT; // reverse the operation return; case OP_INSERT: RawInsert((obj_type_e)objtype, objnum, ptr); ptr = NULL; action = OP_DELETE; // reverse the operation return; default: BugError("edit_op_c::Apply"); } } void Destroy() { // fprintf(stderr, "edit_op_c::Destroy %p action = '%c'\n", this, (action == 0) ? ' ' : action); if (action == OP_INSERT) { SYS_ASSERT(ptr); DeleteFinally((obj_type_e) objtype, ptr); } else if (action == OP_DELETE) { SYS_ASSERT(! ptr); } } }; class undo_group_c { private: std::vector ops; int dir; public: undo_group_c() : ops(), dir(+1) { } ~undo_group_c() { for (int i = (int)ops.size() - 1 ; i >= 0 ; i--) { ops[i].Destroy(); } } bool Empty() const { return ops.empty(); } void Add_Apply(edit_op_c& op) { ops.push_back(op); ops.back().Apply(); } void End() { dir = -1; } void ReApply() { int total = (int)ops.size(); if (dir > 0) for (int i = 0; i < total; i++) ops[i].Apply(); else for (int i = total-1; i >= 0; i--) ops[i].Apply(); // reverse the order for next time dir = -dir; } }; static undo_group_c *cur_group; static std::list undo_history; static std::list redo_future; static void ClearUndoHistory() { std::list::iterator LI; for (LI = undo_history.begin(); LI != undo_history.end(); LI++) delete *LI; undo_history.clear(); } static void ClearRedoFuture() { std::list::iterator LI; for (LI = redo_future.begin(); LI != redo_future.end(); LI++) delete *LI; redo_future.clear(); } void BA_Begin() { if (cur_group) BugError("BA_Begin called twice without BA_End\n"); ClearRedoFuture(); cur_group = new undo_group_c(); DoClearChangeStatus(); } void BA_End() { if (! cur_group) BugError("BA_End called without a previous BA_Begin\n"); cur_group->End(); if (! cur_group->Empty()) { undo_history.push_front(cur_group); } cur_group = NULL; DoProcessChangeStatus(); } void BA_Abort(bool keep_changes) { if (! cur_group) BugError("BA_Abort called without a previous BA_Begin\n"); cur_group->End(); if (! keep_changes && ! cur_group->Empty()) { cur_group->ReApply(); } delete cur_group; cur_group = NULL; did_make_changes = false; DoProcessChangeStatus(); } int BA_New(obj_type_e type) { SYS_ASSERT(cur_group); edit_op_c op; op.action = OP_INSERT; op.objtype = type; switch (type) { case OBJ_THINGS: op.objnum = NumThings; op.ptr = (int*) new Thing; break; case OBJ_VERTICES: op.objnum = NumVertices; op.ptr = (int*) new Vertex; break; case OBJ_SIDEDEFS: op.objnum = NumSideDefs; op.ptr = (int*) new SideDef; break; case OBJ_LINEDEFS: op.objnum = NumLineDefs; op.ptr = (int*) new LineDef; break; case OBJ_SECTORS: op.objnum = NumSectors; op.ptr = (int*) new Sector; break; default: BugError("BA_New"); } SYS_ASSERT(cur_group); cur_group->Add_Apply(op); return op.objnum; } void BA_Delete(obj_type_e type, int objnum) { SYS_ASSERT(cur_group); edit_op_c op; op.action = OP_DELETE; op.objtype = type; op.objnum = objnum; // this must happen _before_ doing the deletion (otherwise // when we undo, the insertion will mess up the references). if (type == OBJ_SIDEDEFS) { // unbind sidedef from any linedefs using it for (int n = NumLineDefs-1 ; n >= 0 ; n--) { LineDef *L = LineDefs[n]; if (L->right == objnum) BA_ChangeLD(n, LineDef::F_RIGHT, -1); if (L->left == objnum) BA_ChangeLD(n, LineDef::F_LEFT, -1); } } else if (type == OBJ_VERTICES) { // delete any linedefs bound to this vertex for (int n = NumLineDefs-1 ; n >= 0 ; n--) { LineDef *L = LineDefs[n]; if (L->start == objnum || L->end == objnum) { BA_Delete(OBJ_LINEDEFS, n); } } } else if (type == OBJ_SECTORS) { // delete the sidedefs bound to this sector for (int n = NumSideDefs-1 ; n >= 0 ; n--) { if (SideDefs[n]->sector == objnum) { BA_Delete(OBJ_SIDEDEFS, n); } } } SYS_ASSERT(cur_group); cur_group->Add_Apply(op); } bool BA_Change(obj_type_e type, int objnum, byte field, int value) { // TODO: optimise, check whether value actually changes edit_op_c op; op.action = OP_CHANGE; op.objtype = type; op.field = field; op.objnum = objnum; op.value = value; SYS_ASSERT(cur_group); cur_group->Add_Apply(op); return true; } bool BA_Undo() { if (undo_history.empty()) return false; DoClearChangeStatus(); undo_group_c * grp = undo_history.front(); undo_history.pop_front(); grp->ReApply(); redo_future.push_front(grp); DoProcessChangeStatus(); return true; } bool BA_Redo() { if (redo_future.empty()) return false; DoClearChangeStatus(); undo_group_c * grp = redo_future.front(); redo_future.pop_front(); grp->ReApply(); undo_history.push_front(grp); DoProcessChangeStatus(); return true; } void BA_ClearAll() { int i; for (i = 0 ; i < NumThings ; i++) delete Things[i]; for (i = 0 ; i < NumVertices ; i++) delete Vertices[i]; for (i = 0 ; i < NumSectors ; i++) delete Sectors[i]; for (i = 0 ; i < NumSideDefs ; i++) delete SideDefs[i]; for (i = 0 ; i < NumLineDefs ; i++) delete LineDefs[i]; Things.clear(); Vertices.clear(); Sectors.clear(); SideDefs.clear(); LineDefs.clear(); HeaderData.clear(); BehaviorData.clear(); ClearUndoHistory(); ClearRedoFuture(); // Note: we don't clear the string table, since there can be // string references in the clipboard. Clipboard_ClearLocals(); } /* HELPERS */ bool BA_ChangeTH(int thing, byte field, int value) { SYS_ASSERT(is_thing(thing)); SYS_ASSERT(field <= Thing::F_ARG5); if (field == Thing::F_TYPE) recent_things.insert_number(value); return BA_Change(OBJ_THINGS, thing, field, value); } bool BA_ChangeVT(int vert, byte field, int value) { SYS_ASSERT(is_vertex(vert)); SYS_ASSERT(field <= Vertex::F_Y); return BA_Change(OBJ_VERTICES, vert, field, value); } bool BA_ChangeSEC(int sec, byte field, int value) { SYS_ASSERT(is_sector(sec)); SYS_ASSERT(field <= Sector::F_TAG); if (field == Sector::F_FLOOR_TEX || field == Sector::F_CEIL_TEX) { recent_flats.insert(BA_GetString(value)); } return BA_Change(OBJ_SECTORS, sec, field, value); } bool BA_ChangeSD(int side, byte field, int value) { SYS_ASSERT(is_sidedef(side)); SYS_ASSERT(field <= SideDef::F_SECTOR); if (field == SideDef::F_LOWER_TEX || field == SideDef::F_UPPER_TEX || field == SideDef::F_MID_TEX) { recent_textures.insert(BA_GetString(value)); } return BA_Change(OBJ_SIDEDEFS, side, field, value); } bool BA_ChangeLD(int line, byte field, int value) { SYS_ASSERT(is_linedef(line)); SYS_ASSERT(field <= LineDef::F_ARG5); return BA_Change(OBJ_LINEDEFS, line, field, value); } //------------------------------------------------------------------------ // CHECKSUM LOGIC //------------------------------------------------------------------------ static void ChecksumThing(crc32_c& crc, const Thing * T) { crc += T->x; crc += T->y; crc += T->angle; crc += T->type; crc += T->options; } static void ChecksumVertex(crc32_c& crc, const Vertex * V) { crc += V->x; crc += V->y; } static void ChecksumSector(crc32_c& crc, const Sector * SEC) { crc += SEC->floorh; crc += SEC->ceilh; crc += SEC->light; crc += SEC->type; crc += SEC->tag; crc += SEC->FloorTex(); crc += SEC->CeilTex(); } static void ChecksumSideDef(crc32_c& crc, const SideDef * S) { crc += S->x_offset; crc += S->y_offset; crc += S->LowerTex(); crc += S->MidTex(); crc += S->UpperTex(); ChecksumSector(crc, S->SecRef()); } static void ChecksumLineDef(crc32_c& crc, const LineDef * L) { crc += L->flags; crc += L->type; crc += L->tag; ChecksumVertex(crc, L->Start()); ChecksumVertex(crc, L->End()); if (L->Right()) ChecksumSideDef(crc, L->Right()); if (L->Left()) ChecksumSideDef(crc, L->Left()); } void BA_LevelChecksum(crc32_c& crc) { // the following method conveniently skips any unused vertices, // sidedefs and sectors. It also adds each sector umpteen times // (for each line in the sector), but that should not affect the // validity of the final checksum. int i; for (i = 0 ; i < NumThings ; i++) ChecksumThing(crc, Things[i]); for (i = 0 ; i < NumLineDefs ; i++) ChecksumLineDef(crc, LineDefs[i]); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_hyper.h0000644000175100017510000000277312647061302016264 0ustar aaptedaapted//------------------------------------------------------------------------ // Hyperlinks //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2011 Andrew Apted // Copyright (C) 2002 Jason Bryan // // 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 __EUREKA_UI_HYPER_H__ #define __EUREKA_UI_HYPER_H__ class UI_HyperLink : public Fl_Button { private: // true when mouse is over this widget bool hover; // area containing the label int label_X, label_Y, label_W, label_H; // the URL to visit when clicked const char *url; public: UI_HyperLink(int x, int y, int w, int h, const char *label, const char *_url); virtual ~UI_HyperLink(); public: // FLTK overrides int handle(int event); void draw(); private: void checkLink(); static void callback_Link(Fl_Widget *w, void *data); }; #endif /* __EUREKA_UI_HYPER_H__ */ //--- editor settings --- // vi:ts=2:sw=2:expandtab eureka-1.11-source/src/m_strings.h0000644000175100017510000000346012647061302016437 0ustar aaptedaapted//------------------------------------------------------------------------ // STRING TABLE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 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 __EUREKA_M_STRINGS_H__ #define __EUREKA_M_STRINGS_H__ class string_block_c; class string_table_c { private: std::vector blocks; std::vector huge_ones; public: string_table_c(); ~string_table_c(); int add(const char *str); // find the given string in the string table, returning the // offset if it exists, otherwise adds the string and returns // the new offset. The empty string and NULL are always 0. const char * get(int offset); // get the string from an offset. Zero always returns an // empty string. NULL is never returned. void clear(); // remove all strings. private: int find_normal(const char *str, int len); // returns an offset value, zero when not found. int find_huge(const char *str, int len); // returns an offset value, zero when not found. int add_normal(const char *str, int len); int add_huge(const char *str, int len); }; #endif /* __EUREKA_M_STRINGS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_menu.h0000644000175100017510000000200612647061302016066 0ustar aaptedaapted//------------------------------------------------------------------------ // MENUS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2009 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 __EUREKA_UI_MENU_H__ #define __EUREKA_UI_MENU_H__ Fl_Sys_Menu_Bar * Menu_Create(int x, int y, int w, int h); #endif /* __EUREKA_UI_MENU_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/editloop.cc0000644000175100017510000010100112651520702016374 0ustar aaptedaapted//------------------------------------------------------------------------ // EDIT LOOP //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "e_checks.h" #include "editloop.h" #include "e_cutpaste.h" #include "r_grid.h" #include "e_linedef.h" #include "e_loadsave.h" #include "e_sector.h" #include "e_path.h" #include "e_vertex.h" #include "levels.h" #include "objects.h" #include "x_mirror.h" #include "x_hover.h" #include "r_render.h" #include "ui_window.h" Editor_State_t edit; int active_when = 0; // FIXME MOVE THESE into Editor_State int active_wmask = 0; // config items int default_edit_mode = 0; // Things bool digits_set_zoom = false; bool mouse_wheel_scrolls_map = false; bool same_mode_clears_selection = false; int multi_select_modifier = 0; int minimum_drag_pixels = 5; int sector_render_default = (int)SREND_Floor; extern bool easier_drawing_mode; void Editor_MouseMotion(int x, int y, keycode_t mod); /* * zoom_fit - adjust zoom factor to make level fit in window * * Return 0 on success, non-zero on failure. */ static void zoom_fit() { if (NumVertices == 0) return; double xzoom = 1; double yzoom = 1; int ScrMaxX = main_win->canvas->w(); int ScrMaxY = main_win->canvas->h(); if (Map_bound_x1 < Map_bound_x2) xzoom = ScrMaxX / (double)(Map_bound_x2 - Map_bound_x1); if (Map_bound_y1 < Map_bound_y2) yzoom = ScrMaxY / (double)(Map_bound_y2 - Map_bound_y1); grid.NearestScale(MIN(xzoom, yzoom)); grid.CenterMapAt((Map_bound_x1 + Map_bound_x2) / 2, (Map_bound_y1 + Map_bound_y2) / 2); } void RedrawMap() { if (! main_win) return; if (edit.render3d) main_win->render->redraw(); else main_win->canvas->redraw(); } static void UpdatePanel() { // -AJA- I think the highlighted object is always the same type as // the current editing mode. But do this check for safety. if (edit.highlight.valid() && edit.highlight.type != edit.mode) return; // Choose object to show in right-hand panel: // - the highlighted object takes priority // - otherwise show the selection (first + count) // // It's a little more complicated since highlight may or may not // be part of the selection. int obj_idx = edit.highlight.num; int obj_count = edit.Selected->count_obj(); if (obj_idx >= 0) { if (! edit.Selected->get(obj_idx)) obj_count = 0; } else if (obj_count > 0) { // in linedef mode, we want a two-sided linedef to show if (edit.mode == OBJ_LINEDEFS && obj_count > 1) obj_idx = Selection_FirstLine(edit.Selected); else obj_idx = edit.Selected->find_first(); } switch (edit.mode) { case OBJ_THINGS: main_win->thing_box->SetObj(obj_idx, obj_count); break; case OBJ_LINEDEFS: main_win->line_box->SetObj(obj_idx, obj_count); break; case OBJ_SECTORS: main_win->sec_box->SetObj(obj_idx, obj_count); break; case OBJ_VERTICES: main_win->vert_box->SetObj(obj_idx, obj_count); break; default: break; } } static void UpdateSplitLine(int map_x, int map_y) { edit.split_line.clear(); // usually disabled while dragging stuff if (edit.action == ACT_DRAG && edit.drag_single_vertex < 0) return; // in vertex mode, see if there is a linedef which would be split by // adding a new vertex if (edit.mode == OBJ_VERTICES && edit.pointer_in_window && edit.highlight.is_nil()) { GetSplitLineDef(edit.split_line, map_x, map_y, edit.drag_single_vertex); // NOTE: OK if the split line has one of its vertices selected // (that case is handled by Insert_Vertex) } if (edit.split_line.valid()) { edit.split_x = grid.SnapX(map_x); edit.split_y = grid.SnapY(map_y); // in FREE mode, ensure the new vertex is directly on the linedef if (! grid.snap) MoveCoordOntoLineDef(edit.split_line.num, &edit.split_x, &edit.split_y); main_win->canvas->SplitLineSet(edit.split_line.num, edit.split_x, edit.split_y); } else main_win->canvas->SplitLineForget(); } void UpdateHighlight() { bool dragging = (edit.action == ACT_DRAG); // find the object to highlight edit.highlight.clear(); if (edit.pointer_in_window && (!dragging || edit.drag_single_vertex >= 0)) { GetNearObject(edit.highlight, edit.mode, edit.map_x, edit.map_y); // guarantee that we cannot drag a vertex onto itself if (edit.drag_single_vertex >= 0 && edit.highlight.valid() && edit.drag_single_vertex == edit.highlight.num) { edit.highlight.clear(); } } UpdateSplitLine(edit.map_x, edit.map_y); // in drawing mode, highlight extends to a vertex at the snap position if (edit.mode == OBJ_VERTICES && grid.snap && edit.action == ACT_DRAW_LINE && edit.highlight.is_nil() && edit.split_line.is_nil()) { int new_x = grid.SnapX(edit.map_x); int new_y = grid.SnapY(edit.map_y); int near_vert = Vertex_FindExact(new_x, new_y); if (near_vert >= 0) { edit.highlight = Objid(OBJ_VERTICES, near_vert); } else { UpdateSplitLine(new_x, new_y); } } if (edit.highlight.valid()) main_win->canvas->HighlightSet(edit.highlight); else main_win->canvas->HighlightForget(); UpdatePanel(); } bool GetCurrentObjects(selection_c *list) { // returns false when there are no objects at all list->change_type(edit.mode); // this also clears it if (edit.Selected->notempty()) { list->merge(*edit.Selected); return true; } if (edit.highlight.valid()) { list->set(edit.highlight.num); return true; } return false; } void Editor_ClearErrorMode() { if (edit.error_mode) { Selection_Clear(); } } void Editor_ChangeMode_Raw(obj_type_e new_mode) { // keep selection after a "Find All" and user dismisses panel if (new_mode == edit.mode && main_win->isSpecialPanelShown()) edit.error_mode = false; edit.mode = new_mode; Editor_ClearAction(); Editor_ClearErrorMode(); edit.highlight.clear(); edit.split_line.clear(); edit.did_a_move = false; } void Editor_ChangeMode(char mode_char) { obj_type_e prev_type = edit.mode; // Set the object type according to the new mode. switch (mode_char) { case 't': Editor_ChangeMode_Raw(OBJ_THINGS); break; case 'l': Editor_ChangeMode_Raw(OBJ_LINEDEFS); break; case 's': Editor_ChangeMode_Raw(OBJ_SECTORS); break; case 'v': Editor_ChangeMode_Raw(OBJ_VERTICES); break; default: LogPrintf("INTERNAL ERROR: unknown mode %d\n", mode_char); return; } if (prev_type != edit.mode) { Selection_Push(); main_win->NewEditMode(edit.mode); // convert the selection selection_c *prev_sel = edit.Selected; edit.Selected = new selection_c(edit.mode); ConvertSelection(prev_sel, edit.Selected); delete prev_sel; } else if (main_win->isSpecialPanelShown()) { // same mode, but this removes the special panel main_win->NewEditMode(edit.mode); } // -AJA- Yadex (DEU?) would clear the selection if the mode didn't // change. We optionally emulate that behavior here. else if (same_mode_clears_selection) { Selection_Clear(); } UpdateHighlight(); RedrawMap(); } void CMD_Nothing(void) { /* hey jude, don't make it bad */ } void CMD_EditMode(void) { char mode = tolower(EXEC_Param[0][0]); if (! mode || ! strchr("lstvr", mode)) { Beep("Bad parameter for EditMode: '%s'", EXEC_Param[0]); return; } Editor_ChangeMode(mode); } void CMD_SelectAll(void) { Editor_ClearErrorMode(); int total = NumObjects(edit.mode); Selection_Push(); edit.Selected->change_type(edit.mode); edit.Selected->frob_range(0, total-1, BOP_ADD); UpdateHighlight(); RedrawMap(); } void CMD_UnselectAll(void) { Editor_ClearErrorMode(); if (edit.action == ACT_DRAW_LINE || edit.action == ACT_SCALE) { Editor_ClearAction(); } Selection_Clear(); UpdateHighlight(); RedrawMap(); } void CMD_InvertSelection(void) { // do not clear selection when in error mode edit.error_mode = false; int total = NumObjects(edit.mode); if (edit.Selected->what_type() != edit.mode) { // convert the selection selection_c *prev_sel = edit.Selected; edit.Selected = new selection_c(edit.mode); ConvertSelection(prev_sel, edit.Selected); delete prev_sel; } edit.Selected->frob_range(0, total-1, BOP_TOGGLE); UpdateHighlight(); RedrawMap(); } void CMD_Quit(void) { want_quit = true; } void CMD_SetVar(void) { const char *var_name = EXEC_Param[0]; const char *value = EXEC_Param[0]; if (! var_name[0]) { Beep("Set: missing var name"); return; } if (! value[0]) { Beep("Set: missing value"); return; } int int_val = atoi(value); bool bool_val = (int_val > 0); if (y_stricmp(var_name, "3d") == 0) { Editor_ClearAction(); edit.render3d = bool_val; main_win->redraw(); } else if (y_stricmp(var_name, "browser") == 0) { Editor_ClearAction(); int want_vis = bool_val ? 1 : 0; int is_visible = main_win->browser->visible() ? 1 : 0; if (want_vis != is_visible) main_win->ShowBrowser('/'); } else if (y_stricmp(var_name, "grid") == 0) { grid.SetShown(bool_val); } else if (y_stricmp(var_name, "snap") == 0) { grid.SetSnap(bool_val); } else if (y_stricmp(var_name, "obj_nums") == 0) { edit.show_object_numbers = bool_val; RedrawMap(); } else // TODO: "skills" { Beep("Set: unknown var: %s", var_name); } } void CMD_ToggleVar(void) { const char *var_name = EXEC_Param[0]; if (! var_name[0]) { Beep("Toggle: missing var name"); return; } if (y_stricmp(var_name, "3d") == 0) { Editor_ClearAction(); edit.render3d = ! edit.render3d; main_win->redraw(); } else if (y_stricmp(var_name, "browser") == 0) { Editor_ClearAction(); main_win->ShowBrowser('/'); } else if (y_stricmp(var_name, "recent") == 0) { main_win->browser->ToggleRecent(); } else if (y_stricmp(var_name, "grid") == 0) { grid.ToggleShown(); } else if (y_stricmp(var_name, "snap") == 0) { grid.ToggleSnap(); } else if (y_stricmp(var_name, "obj_nums") == 0) { edit.show_object_numbers = ! edit.show_object_numbers; RedrawMap(); } else if (y_stricmp(var_name, "skills") == 0) { active_wmask ^= 1; active_when = active_wmask; RedrawMap(); } else { Beep("Toggle: unknown var: %s", var_name); } } static int mouse_last_x; static int mouse_last_y; // screen position when LMB was pressed static int mouse_button1_x; static int mouse_button1_y; // map location when LMB was pressed static int button1_map_x; static int button1_map_y; void Editor_ClearAction() { switch (edit.action) { case ACT_NOTHING: return; case ACT_WAIT_META: Status_Clear(); break; case ACT_ADJUST_OFS: main_win->SetCursor(FL_CURSOR_DEFAULT); break; default: /* no special for the rest */ break; } edit.action = ACT_NOTHING; } void Editor_SetAction(editor_action_e new_action) { Editor_ClearAction(); edit.action = new_action; switch (edit.action) { case ACT_NOTHING: return; case ACT_WAIT_META: Status_Set("META..."); break; case ACT_ADJUST_OFS: mouse_last_x = Fl::event_x(); mouse_last_y = Fl::event_y(); main_win->SetCursor(FL_CURSOR_HAND); break; default: /* no special for the rest */ break; } } void CMD_MetaKey(void) { Editor_SetAction(ACT_WAIT_META); } void CMD_BrowserMode(void) { if (! EXEC_Param[0][0]) { Beep("Missing parameter to CMD_BrowserMode"); return; } char mode = toupper(EXEC_Param[0][0]); if (! (mode == 'L' || mode == 'S' || mode == 'O' || mode == 'T' || mode == 'F' || mode == 'G')) { Beep("Unknown browser mode: %s", EXEC_Param[0]); return; } main_win->ShowBrowser(mode); } void BR_CycleCategory(void) { if (! main_win->browser->visible()) { Beep("Browser not open"); return; } int dir = (atoi(EXEC_Param[0]) >= 0) ? +1 : -1; main_win->browser->CycleCategory(dir); } void BR_ClearSearch(void) { if (! main_win->browser->visible()) { Beep("Browser not open"); return; } main_win->browser->ClearSearchBox(); } void BR_Scroll(void) { if (! main_win->browser->visible()) { Beep("Browser not open"); return; } if (! EXEC_Param[0][0]) { Beep("Missing parameter to BR_Scroll"); return; } int delta = atoi(EXEC_Param[0]); main_win->browser->Scroll(delta); } void CMD_Scroll(void) { // these are percentages int delta_x = atoi(EXEC_Param[0]); int delta_y = atoi(EXEC_Param[1]); if (delta_x == 0 && delta_y == 0) { Beep("Bad parameter to Scroll: '%s' %s'", EXEC_Param[0], EXEC_Param[1]); return; } delta_x = delta_x * main_win->canvas->w() / 100.0 / grid.Scale; delta_y = delta_y * main_win->canvas->h() / 100.0 / grid.Scale; grid.Scroll(delta_x, delta_y); // certain actions need to be updated if (edit.action == ACT_SELBOX || edit.action == ACT_DRAW_LINE || edit.action == ACT_DRAG) { int mod = Fl::event_state() & MOD_ALL_MASK; Editor_MouseMotion(Fl::event_x(), Fl::event_y(), mod); } } void CMD_Merge(void) { switch (edit.mode) { case OBJ_VERTICES: VT_Merge(); break; case OBJ_LINEDEFS: LIN_MergeTwo(); break; case OBJ_SECTORS: SEC_Merge(); break; case OBJ_THINGS: TH_Merge(); break; default: Beep("Cannot merge that"); break; } } void CMD_Disconnect(void) { switch (edit.mode) { case OBJ_VERTICES: VT_Disconnect(); break; case OBJ_LINEDEFS: LIN_Disconnect(); break; case OBJ_SECTORS: SEC_Disconnect(); break; case OBJ_THINGS: TH_Disconnect(); break; default: Beep("Cannot disconnect that"); break; } } void GRID_Step(void) { int delta = atoi(EXEC_Param[0]); delta = (delta >= 0) ? +1 : -1; grid.AdjustStep(delta); } void Editor_DigitKey(keycode_t key) { // [1] - [9]: set the grid size int digit = (key & 127) - '0'; bool do_zoom = digits_set_zoom; if (key & MOD_SHIFT) do_zoom = !do_zoom; if (do_zoom) { float S1 = grid.Scale; grid.ScaleFromDigit(digit); grid.RefocusZoom(edit.map_x, edit.map_y, S1); } else { grid.StepFromDigit(digit); } } void Editor_Zoom(int delta, int mid_x, int mid_y) { float S1 = grid.Scale; grid.AdjustScale(delta); grid.RefocusZoom(mid_x, mid_y, S1); } void CMD_Zoom(void) { int delta = atoi(EXEC_Param[0]); if (delta == 0) { Beep("Bad parameter to CMD_Zoom"); return; } Editor_Zoom(delta, edit.map_x, edit.map_y); } void CMD_ZoomWholeMap(void) { if (MadeChanges) CalculateLevelBounds(); zoom_fit(); RedrawMap(); } void CMD_ZoomSelection(void) { if (edit.Selected->empty()) { Beep("No selection to zoom"); return; } GoToSelection(); } void CMD_GoToCamera(void) { int x, y; float angle; Render3D_GetCameraPos(&x, &y, &angle); grid.CenterMapAt(x, y); // FIXME: this is not right, we want to recompute where mouse pointer is edit.map_x = x; edit.map_y = y; RedrawMap(); } void CMD_PlaceCamera(void) { if (edit.render3d) { Beep("Not supported in 3D view"); return; } if (! edit.pointer_in_window) { // IDEA: turn cursor into cross, wait for click in map window Beep("Mouse is not over map"); return; } int x = edit.map_x; int y = edit.map_y; Render3D_SetCameraPos(x, y); if (Exec_HasFlag("/open3d")) { edit.render3d = 1; main_win->redraw(); } RedrawMap(); } void CMD_Gamma(void) { int delta = (atoi(EXEC_Param[0]) >= 0) ? +1 : -1; usegamma = (usegamma + delta + 5) % 5; W_UpdateGamma(); Status_Set("Gamma level %d", usegamma); RedrawMap(); } void CMD_CopyAndPaste(void) { if (edit.Selected->empty() && edit.highlight.is_nil()) { Beep("Nothing to copy and paste"); return; } if (CMD_Copy()) { CMD_Paste(); } } //------------------------------------------------------------------------ static void Editor_ScrollMap(int mode, int dx = 0, int dy = 0) { // started? if (mode < 0) { edit.is_scrolling = true; main_win->SetCursor(FL_CURSOR_HAND); return; } // finished? if (mode > 0) { edit.is_scrolling = false; main_win->SetCursor(FL_CURSOR_DEFAULT); return; } keycode_t mod = Fl::event_state() & MOD_ALL_MASK; if (edit.render3d) { Render3D_RBScroll(dx, dy, mod); } else { int speed = 8; // FIXME: CONFIG OPTION if (mod == MOD_SHIFT) speed /= 2; else if (mod == MOD_COMMAND) speed *= 2; double delta_x = ((double) -dx * speed / 8.0 / grid.Scale); double delta_y = ((double) dy * speed / 8.0 / grid.Scale); grid.Scroll(delta_x, delta_y); } } //------------------------------------------------------------------------ int wheel_dx; int wheel_dy; int Editor_RawKey(int event) { if (event == FL_KEYUP) return 0; bool convert_meta = (edit.action == ACT_WAIT_META); if (edit.action == ACT_WAIT_META) Editor_ClearAction(); int raw_key = Fl::event_key(); int raw_state = Fl::event_state(); if (convert_meta) raw_state = MOD_META; keycode_t key = M_TranslateKey(raw_key, raw_state); if (key == 0) return convert_meta ? 1 : 0; wheel_dx = wheel_dy = 0; #if 0 // DEBUG fprintf(stderr, "Key code: 0x%08x : %s\n", key, M_KeyToString(key)); #endif // keyboard propagation logic // handle digits specially if ('1' <= (key & FL_KEY_MASK) && (key & FL_KEY_MASK) <= '9') { Editor_DigitKey(key); return 1; } if (main_win->browser->visible() && ExecuteKey(key, KCTX_Browser)) return 1; if (edit.render3d && ExecuteKey(key, KCTX_Render)) return 1; if (ExecuteKey(key, M_ModeToKeyContext(edit.mode))) return 1; if (ExecuteKey(key, KCTX_General)) return 1; // NOTE: the key may still get handled by something (e.g. Menus) // fprintf(stderr, "Unknown key %d (0x%04x)\n", key, key); // prevent a META-fied key from being sent elsewhere, because it // won't really be META-fied anywhere else -- including the case // of it being sent back to this function as a SHORTCUT event. return convert_meta ? 1 : 0; } int Editor_RawWheel(int event) { if (edit.action == ACT_WAIT_META) Editor_ClearAction(); // ensure we zoom from correct place main_win->canvas->PointerPos(&edit.map_x, &edit.map_y); wheel_dx = Fl::event_dx(); wheel_dy = Fl::event_dy(); keycode_t mod = Fl::event_state() & MOD_ALL_MASK; // TODO: DistributeKey(EU_Wheel | mod) if (edit.render3d) Render3D_Wheel(wheel_dx, 0 - wheel_dy, mod); else Editor_Wheel(wheel_dx, wheel_dy, mod); return 1; } int Editor_RawButton(int event) { if (edit.action == ACT_WAIT_META) Editor_ClearAction(); int button = Fl::event_button(); bool down = (event == FL_PUSH); // Hack Alert : this is required to support pressing two buttons at the // same time. Without this, FLTK does not send us the second button // release event, because when the first button is released the "pushed" // widget becomes NULL. if (Fl::event_buttons() != 0) Fl::pushed(main_win->canvas); // start scrolling the map? [or moving in 3D view] if (button == 3) { Editor_ScrollMap(down ? -1 : +1); return 1; } // adjust offsets on a sidedef? if (edit.render3d && button == 2) { Render3D_AdjustOffsets(down ? -1 : +1); return 1; } if (! down) { if (button == 2) Editor_MiddleRelease(); else if (! edit.render3d) Editor_MouseRelease(); return 1; } int mod = Fl::event_state() & MOD_ALL_MASK; if (button == 2) { Editor_MiddlePress(mod); } else if (! edit.render3d) { Editor_MousePress(mod); } return 1; } int Editor_RawMouse(int event) { int mod = Fl::event_state() & MOD_ALL_MASK; int dx = Fl::event_x() - mouse_last_x; int dy = Fl::event_y() - mouse_last_y; if (edit.is_scrolling) { Editor_ScrollMap(0, dx, dy); } else if (edit.action == ACT_ADJUST_OFS) { Render3D_AdjustOffsets(0, dx, dy); } else if (edit.render3d) { Render3D_MouseMotion(Fl::event_x(), Fl::event_y(), mod); } else { Editor_MouseMotion(Fl::event_x(), Fl::event_y(), mod); } mouse_last_x = Fl::event_x(); mouse_last_y = Fl::event_y(); return 1; } //------------------------------------------------------------------------ void Editor_Wheel(int dx, int dy, keycode_t mod) { if (mouse_wheel_scrolls_map && mod != #ifdef __APPLE__ MOD_ALT) #else MOD_COMMAND) #endif { int speed = 12; // FIXME: CONFIG OPTION if (mod == MOD_SHIFT) speed = MAX(1, speed / 3); grid.Scroll( dx * (double) speed / grid.Scale, - dy * (double) speed / grid.Scale); } else { dy = (dy > 0) ? +1 : -1; Editor_Zoom(- dy, edit.map_x, edit.map_y); } } void Editor_MousePress(keycode_t mod) { if (edit.button_down >= 2) return; edit.button_down = 1; edit.button_mod = mod; // remember some state (for dragging) mouse_button1_x = Fl::event_x(); mouse_button1_y = Fl::event_y(); button1_map_x = edit.map_x; button1_map_y = edit.map_y; // this is a special case, since we want to allow the new vertex // from a split-line (when in in drawing mode) to be draggable. // [ that is achieved by setting edit.clicked ] if (easier_drawing_mode && edit.split_line.valid() && edit.action != ACT_DRAW_LINE) { Insert_Vertex_split(edit.split_line.num, edit.split_x, edit.split_y); return; } if (edit.action == ACT_DRAW_LINE) { bool force_cont = (mod == MOD_SHIFT); bool no_fill = (mod == MOD_COMMAND); Insert_Vertex(force_cont, no_fill, true /* is_button */); return; } // find the object under the pointer. GetNearObject(edit.clicked, edit.mode, edit.map_x, edit.map_y); // inhibit in sector/linedef mode when SHIFT is pressed, to allow // opening a selection box in places which are otherwise impossible. if (mod == MOD_SHIFT && (edit.mode == OBJ_SECTORS || edit.mode == OBJ_LINEDEFS)) { edit.clicked.clear(); } // clicking on an empty space starts a new selection box. if (edit.clicked.is_nil()) { if (edit.did_a_move) Selection_Clear(); Editor_SetAction(ACT_SELBOX); main_win->canvas->SelboxBegin(edit.map_x, edit.map_y); return; } // Note: drawing mode is activated on RELEASE... // (as the user may be trying to drag the vertex) } void Editor_MouseRelease() { edit.button_down = 0; Objid click_obj(edit.clicked); edit.clicked.clear(); bool was_did_move = edit.did_a_move; edit.did_a_move = false; // releasing the button while dragging : drop the selection. if (edit.action == ACT_DRAG) { Editor_ClearAction(); int dx, dy; main_win->canvas->DragFinish(&dx, &dy); if (! (dx==0 && dy==0)) { CMD_MoveObjects(dx, dy); // next select action will clear the selection edit.did_a_move = true; } edit.drag_single_vertex = -1; RedrawMap(); return; } // releasing the button while there was a selection box // causes all the objects within the box to be selected. if (edit.action == ACT_SELBOX) { Editor_ClearAction(); Editor_ClearErrorMode(); int x1, y1, x2, y2; main_win->canvas->SelboxFinish(&x1, &y1, &x2, &y2); // a mere click and release will unselect everything if (x1 == x2 && y1 == y2) CMD_UnselectAll(); else SelectObjectsInBox(edit.Selected, edit.mode, x1, y1, x2, y2); UpdateHighlight(); RedrawMap(); return; } // nothing needed while in drawing mode if (edit.action == ACT_DRAW_LINE) return; // optional multi-select : require a certain modifier key if (multi_select_modifier && edit.button_mod != (multi_select_modifier == 1 ? MOD_SHIFT : MOD_COMMAND)) { was_did_move = true; } // handle a clicked-on object // e.g. select the object if unselected, and vice versa. if (click_obj.valid()) { bool was_empty = edit.Selected->empty(); Editor_ClearErrorMode(); if (was_did_move) Selection_Clear(); // check if pointing at the same object as before Objid near_obj; GetNearObject(near_obj, edit.mode, edit.map_x, edit.map_y); if (near_obj != click_obj) return; // begin drawing mode (unless a modifier was pressed) if (easier_drawing_mode && edit.mode == OBJ_VERTICES && was_empty && edit.button_mod == 0) { Editor_SetAction(ACT_DRAW_LINE); edit.drawing_from = click_obj.num; edit.Selected->set(click_obj.num); RedrawMap(); return; } edit.Selected->toggle(click_obj.num); RedrawMap(); return; } } void Editor_MiddlePress(keycode_t mod) { if (edit.button_down & 1) // allow 0 or 2 return; #if 0 // ability to insert stuff via the mouse if (mod == 0) { EXEC_Param[0] = ""; EXEC_Flags[0] = ""; CMD_Insert(); return; } #endif if (edit.Selected->empty()) { Beep("Nothing to scale"); return; } int middle_x, middle_y; Objs_CalcMiddle(edit.Selected, &middle_x, &middle_y); Editor_SetAction(ACT_SCALE); edit.button_mod = mod; main_win->canvas->ScaleBegin(edit.map_x, edit.map_y, middle_x, middle_y); } void Editor_MiddleRelease() { edit.button_down = 0; if (edit.action == ACT_SCALE) { Editor_ClearAction(); scale_param_t param; main_win->canvas->ScaleFinish(param); CMD_ScaleObjects2(param); RedrawMap(); } } void Editor_LeaveWindow() { edit.pointer_in_window = false; // this offers a handy way to get out of drawing mode if (edit.action == ACT_DRAW_LINE) Editor_ClearAction(); UpdateHighlight(); } void Editor_MouseMotion(int x, int y, keycode_t mod) { int map_x, map_y; main_win->canvas->PointerPos(&map_x, &map_y); edit.map_x = map_x; edit.map_y = map_y; edit.pointer_in_window = true; // FIXME if (edit.pointer_in_window) main_win->info_bar->SetMouse(edit.map_x, edit.map_y); // fprintf(stderr, "MOUSE MOTION: %d,%d map: %d,%d\n", x, y, edit.map_x, edit.map_y); if (edit.action == ACT_SCALE) { main_win->canvas->ScaleUpdate(edit.map_x, edit.map_y, mod); return; } if (edit.action == ACT_DRAW_LINE) { UpdateHighlight(); main_win->canvas->redraw(); return; } if (edit.action == ACT_SELBOX) { main_win->canvas->SelboxUpdate(edit.map_x, edit.map_y); return; } if (edit.action == ACT_DRAG) { main_win->canvas->DragUpdate(edit.map_x, edit.map_y); // if dragging a single vertex, update the possible split_line UpdateHighlight(); return; } // // begin dragging? // int pixel_dx = Fl::event_x() - mouse_button1_x; int pixel_dy = Fl::event_y() - mouse_button1_y; if (edit.button_down == 1 && edit.clicked.valid() && MAX(abs(pixel_dx), abs(pixel_dy)) >= minimum_drag_pixels) { if (! edit.Selected->get(edit.clicked.num)) { if (edit.did_a_move) Selection_Clear(); edit.Selected->set(edit.clicked.num); edit.did_a_move = false; } int focus_x, focus_y; GetDragFocus(&focus_x, &focus_y, button1_map_x, button1_map_y); Editor_SetAction(ACT_DRAG); main_win->canvas->DragBegin(focus_x, focus_y, button1_map_x, button1_map_y); // check for a single vertex edit.drag_single_vertex = -1; if (edit.mode == OBJ_VERTICES && edit.Selected->find_second() < 0) { edit.drag_single_vertex = edit.Selected->find_first(); SYS_ASSERT(edit.drag_single_vertex >= 0); } UpdateHighlight(); return; } // in general, just update the highlight, split-line (etc) UpdateHighlight(); } void Editor_Resize(int is_width, int is_height) { RedrawMap(); } //------------------------------------------------------------------------ static editor_command_t command_table[] = { /* ------ interface stuff ------ */ { "Nothing", &CMD_Nothing }, { "Quit", &CMD_Quit }, { "EditMode", &CMD_EditMode, /* flags */ NULL, /* keywords */ "thing line sector vertex" }, { "BrowserMode", &CMD_BrowserMode, /* flags */ NULL, /* keywords */ "obj tex flat line sec genline" }, { "Set", &CMD_SetVar, /* flags */ NULL, /* keywords */ "3d browser grid obj_nums snap" }, { "Toggle", &CMD_ToggleVar, /* flags */ NULL, /* keywords */ "3d browser grid obj_nums snap recent" }, { "Check", &CMD_CheckMap, /* flags */ NULL, /* keywords */ "all major vertices sectors linedefs things textures tags current" }, { "MetaKey", &CMD_MetaKey }, { "GivenFile", &CMD_GivenFile, /* flags */ NULL, /* keywords */ "next prev first last current" }, { "FlipMap", &CMD_FlipMap, /* flags */ NULL, /* keywords */ "next prev first last" }, { "SelectAll", &CMD_SelectAll }, { "UnselectAll", &CMD_UnselectAll }, { "InvertSelection", &CMD_InvertSelection }, { "LastSelection", &CMD_LastSelection }, { "Scroll", &CMD_Scroll }, { "GoToCamera", &CMD_GoToCamera }, { "PlaceCamera", &CMD_PlaceCamera, /* flags */ "/open3d" }, { "JumpToObject", &CMD_JumpToObject }, { "Zoom", &CMD_Zoom }, { "ZoomWholeMap", &CMD_ZoomWholeMap }, { "ZoomSelection", &CMD_ZoomSelection }, { "GRID_Step", &GRID_Step }, /* ----- general map stuff ----- */ { "Insert", &CMD_Insert, /* flags */ "/new /continue /nofill" }, { "Delete", &CMD_Delete, /* flags */ "/keep_things /keep_unused" }, { "Mirror", &CMD_Mirror, /* flags */ NULL, /* keywords */ "horiz vert" }, { "Rotate90", &CMD_Rotate90, /* flags */ NULL, /* keywords */ "cw acw" }, { "Enlarge", &CMD_Enlarge }, { "Shrink", &CMD_Shrink }, { "Disconnect", &CMD_Disconnect }, { "Merge", &CMD_Merge, /* flags */ "/keep" }, { "Quantize", &CMD_Quantize }, { "Gamma", &CMD_Gamma }, { "CopyAndPaste", &CMD_CopyAndPaste }, { "CopyProperties", &CMD_CopyProperties, /* flags */ "/reverse" }, { "ApplyTag", &CMD_ApplyTag, /* flags */ NULL, /* keywords */ "fresh last" }, { "PruneUnused", &CMD_PruneUnused }, /* -------- linedef -------- */ { "LIN_Flip", &LIN_Flip, /* flags */ "/verts /sides" }, { "LIN_SplitHalf", &LIN_SplitHalf }, { "LIN_SelectPath", &LIN_SelectPath, /* flags */ "/add /onesided /sametex" }, /* -------- sector -------- */ { "SEC_Floor", &SEC_Floor }, { "SEC_Ceil", &SEC_Ceil }, { "SEC_Light", &SEC_Light }, { "SEC_SelectGroup", &SEC_SelectGroup, /* flags */ "/add /can_walk /doors /floor_h /floor_tex /ceil_h /ceil_tex /light /tag /special" }, { "SEC_SwapFlats", &SEC_SwapFlats }, /* -------- thing -------- */ { "TH_Spin", &TH_SpinThings }, /* -------- vertex -------- */ { "VT_ShapeLine", &VT_ShapeLine }, { "VT_ShapeArc", &VT_ShapeArc }, /* -------- browser -------- */ { "BR_CycleCategory", &BR_CycleCategory }, { "BR_ClearSearch", &BR_ClearSearch }, { "BR_Scroll", &BR_Scroll }, // end of command list { NULL, NULL } }; void Editor_RegisterCommands() { M_RegisterCommandList(command_table); } void Editor_Init() { memset(&edit, 0, sizeof(edit)); /* Catch-all */ switch (default_edit_mode) { case 1: edit.mode = OBJ_LINEDEFS; break; case 2: edit.mode = OBJ_SECTORS; break; case 3: edit.mode = OBJ_VERTICES; break; default: edit.mode = OBJ_THINGS; break; } edit.action = ACT_NOTHING; edit.is_scrolling = false; edit.render3d = false; edit.error_mode = false; edit.sector_render_mode = sector_render_default; edit.show_object_numbers = false; edit.show_things_squares = false; edit.show_things_sprites = true; edit.button_down = 0; edit.button_mod = 0; edit.clicked.clear(); edit.highlight.clear(); edit.split_line.clear(); edit.drawing_from = -1; edit.drag_single_vertex = -1; edit.Selected = new selection_c(edit.mode); edit.did_a_move = false; grid.Init(); MadeChanges = 0; Editor_RegisterCommands(); Render3D_RegisterCommands(); } bool Editor_ParseUser(const char ** tokens, int num_tok) { if (strcmp(tokens[0], "edit_mode") == 0 && num_tok >= 2) { Editor_ChangeMode(tokens[1][0]); return true; } if (strcmp(tokens[0], "render_mode") == 0 && num_tok >= 2) { edit.render3d = atoi(tokens[1]); RedrawMap(); return true; } if (strcmp(tokens[0], "sector_render_mode") == 0 && num_tok >= 2) { edit.sector_render_mode = atoi(tokens[1]); RedrawMap(); return true; } if (strcmp(tokens[0], "show_object_numbers") == 0 && num_tok >= 2) { edit.show_object_numbers = atoi(tokens[1]); RedrawMap(); return true; } return false; } void Editor_WriteUser(FILE *fp) { switch (edit.mode) { case OBJ_THINGS: fprintf(fp, "edit_mode t\n"); break; case OBJ_LINEDEFS: fprintf(fp, "edit_mode l\n"); break; case OBJ_SECTORS: fprintf(fp, "edit_mode s\n"); break; case OBJ_VERTICES: fprintf(fp, "edit_mode v\n"); break; default: break; } fprintf(fp, "render_mode %d\n", edit.render3d ? 1 : 0); fprintf(fp, "sector_render_mode %d\n", edit.sector_render_mode); fprintf(fp, "show_object_numbers %d\n", edit.show_object_numbers ? 1 : 0); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_bitvec.cc0000644000175100017510000000613412647061302016361 0ustar aaptedaapted//------------------------------------------------------------------------ // BIT VECTORS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2015 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "m_bitvec.h" bitvec_c::bitvec_c(int n_elements) : num_elem(n_elements) { SYS_ASSERT(n_elements > 0); int total = (num_elem / 8) + 1; d = new byte[total]; clear_all(); } bitvec_c::~bitvec_c() { delete[] d; } void bitvec_c::resize(int n_elements) { SYS_ASSERT(n_elements > 0); int old_elem = num_elem; int old_total = (num_elem / 8) + 1; int new_total = (n_elements / 8) + 1; byte * old_d = d; // don't bother re-allocating unless shrinking by a large amount if (num_elem/2 < n_elements && n_elements < num_elem) { num_elem = n_elements; return; } num_elem = n_elements; d = new byte[new_total]; // copy existing values memcpy(d, old_d, MIN(old_total, new_total)); delete[] old_d; if (new_total > old_total) memset(d+old_total, 0, new_total - old_total); // make sure the bits near the old top are clear for (int i = 0 ; i < 8 ; i++) { if (old_elem + i < num_elem) raw_clear(old_elem + i); } } bool bitvec_c::get(int n) const { SYS_ASSERT(n >= 0); if (n >= num_elem) return 0; return raw_get(n); } void bitvec_c::set(int n) { SYS_ASSERT(n >= 0); while (n >= num_elem) { resize(num_elem * 3 / 2 + 16); } raw_set(n); } void bitvec_c::clear(int n) { SYS_ASSERT(n >= 0); if (n >= num_elem) return; raw_clear(n); } void bitvec_c::toggle(int n) { if (get(n)) clear(n); else set(n); } void bitvec_c::frob(int n, sel_op_e op) { switch (op) { case BOP_ADD: set(n); break; case BOP_REMOVE: clear(n); break; default: toggle(n); break; } } void bitvec_c::set_all() { int total = (num_elem / 8) + 1; // Note: this will set some extra bits (over num_elem). // the get() functions (etc) make sure to never use them. memset(d, 0xFF, total); } void bitvec_c::clear_all() { int total = (num_elem / 8) + 1; memset(d, 0, total); } void bitvec_c::toggle_all() { int total = (num_elem / 8) + 1; byte *pos = d; byte *p_end = d + total; while (pos < p_end) *pos++ ^= 0xFF; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/x_mirror.cc0000644000175100017510000004646012651124723016442 0ustar aaptedaapted//------------------------------------------------------------------------ // MIRROR / ROTATE / ETC OPS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include "m_bitvec.h" #include "e_linedef.h" #include "e_sector.h" #include "e_things.h" #include "e_vertex.h" #include "editloop.h" #include "levels.h" #include "m_game.h" #include "m_select.h" #include "r_grid.h" #include "x_mirror.h" void scale_param_t::Clear() { mid_x = mid_y = 0; scale_x = scale_y = 1; rotate = 0; } void scale_param_t::Apply(int *x, int *y) const { *x = *x - mid_x; *y = *y - mid_y; if (rotate) { float s = sin(rotate * M_PI / 32768.0); float c = cos(rotate * M_PI / 32768.0); int x1 = *x; int y1 = *y; *x = x1 * c - y1 * s; *y = y1 * c + x1 * s; } *x = mid_x + I_ROUND( (*x) * scale_x ); *y = mid_y + I_ROUND( (*y) * scale_y ); } // // Return the coordinate of the centre of a group of objects. // // This is computed using an average of all the coordinates, which can // often give a different result than using the middle of the bounding // box. // void Objs_CalcMiddle(selection_c * list, int *x, int *y) { *x = *y = 0; if (list->empty()) return; selection_iterator_c it; double sum_x = 0; double sum_y = 0; int count = 0; switch (list->what_type()) { case OBJ_THINGS: { for (list->begin(&it) ; !it.at_end() ; ++it, ++count) { sum_x += Things[*it]->x; sum_y += Things[*it]->y; } break; } case OBJ_VERTICES: { for (list->begin(&it) ; !it.at_end() ; ++it, ++count) { sum_x += Vertices[*it]->x; sum_y += Vertices[*it]->y; } break; } // everything else: just use the vertices default: { selection_c verts(OBJ_VERTICES); ConvertSelection(list, &verts); Objs_CalcMiddle(&verts, x, y); return; } } SYS_ASSERT(count > 0); *x = I_ROUND(sum_x / count); *y = I_ROUND(sum_y / count); } /* * Returns a bounding box that completely includes a group of objects */ void Objs_CalcBBox(selection_c * list, int *x1, int *y1, int *x2, int *y2) { if (list->empty()) { *x1 = *y1 = 0; *x2 = *y2 = 0; return; } *x1 = *y1 = +777777; *x2 = *y2 = -777777; selection_iterator_c it; switch (list->what_type()) { case OBJ_THINGS: { for (list->begin(&it) ; !it.at_end() ; ++it) { const Thing *T = Things[*it]; const thingtype_t *info = M_GetThingType(T->type); int r = info->radius; if (T->x - r < *x1) *x1 = T->x - r; if (T->y - r < *y1) *y1 = T->y - r; if (T->x + r > *x2) *x2 = T->x + r; if (T->y + r > *y2) *y2 = T->y + r; } break; } case OBJ_VERTICES: { for (list->begin(&it) ; !it.at_end() ; ++it) { const Vertex *V = Vertices[*it]; if (V->x < *x1) *x1 = V->x; if (V->y < *y1) *y1 = V->y; if (V->x > *x2) *x2 = V->x; if (V->y > *y2) *y2 = V->y; } break; } // everything else: just use the vertices default: { selection_c verts(OBJ_VERTICES); ConvertSelection(list, &verts); Objs_CalcBBox(&verts, x1, y1, x2, y2); return; } } SYS_ASSERT(*x1 <= *x2); SYS_ASSERT(*y1 <= *y2); } static void DoMirrorThings(selection_c& list, bool is_vert, int mid_x, int mid_y) { selection_iterator_c it; for (list.begin(&it) ; !it.at_end() ; ++it) { const Thing * T = Things[*it]; if (is_vert) { BA_ChangeTH(*it, Thing::F_Y, 2*mid_y - T->y); if (T->angle != 0) BA_ChangeTH(*it, Thing::F_ANGLE, 360 - T->angle); } else { BA_ChangeTH(*it, Thing::F_X, 2*mid_x - T->x); if (T->angle > 180) BA_ChangeTH(*it, Thing::F_ANGLE, 540 - T->angle); else BA_ChangeTH(*it, Thing::F_ANGLE, 180 - T->angle); } } } static void DoMirrorVertices(selection_c& list, bool is_vert, int mid_x, int mid_y) { selection_c verts(OBJ_VERTICES); ConvertSelection(&list, &verts); selection_iterator_c it; for (verts.begin(&it) ; !it.at_end() ; ++it) { const Vertex * V = Vertices[*it]; if (is_vert) BA_ChangeVT(*it, Vertex::F_Y, 2*mid_y - V->y); else BA_ChangeVT(*it, Vertex::F_X, 2*mid_x - V->x); } // flip linedefs too !! selection_c lines(OBJ_LINEDEFS); ConvertSelection(&verts, &lines); for (lines.begin(&it) ; !it.at_end() ; ++it) { LineDef * L = LineDefs[*it]; int start = L->start; int end = L->end; BA_ChangeLD(*it, LineDef::F_START, end); BA_ChangeLD(*it, LineDef::F_END, start); } } static void DoMirrorStuff(selection_c& list, bool is_vert, int mid_x, int mid_y) { if (edit.mode == OBJ_THINGS) { DoMirrorThings(list, is_vert, mid_x, mid_y); return; } // everything else just modifies the vertices if (edit.mode == OBJ_SECTORS) { // handle things in Sectors mode too selection_c things(OBJ_THINGS); ConvertSelection(&list, &things); DoMirrorThings(things, is_vert, mid_x, mid_y); } DoMirrorVertices(list, is_vert, mid_x, mid_y); } void CMD_Mirror(void) { selection_c list; if (! GetCurrentObjects(&list)) { Beep("No objects to mirror"); return; } bool is_vert = false; if (tolower(EXEC_Param[0][0]) == 'v') is_vert = true; int mid_x, mid_y; Objs_CalcMiddle(&list, &mid_x, &mid_y); BA_Begin(); DoMirrorStuff(list, is_vert, mid_x, mid_y); BA_End(); } static void DoRotate90Things(selection_c& list, bool anti_clockwise, int mid_x, int mid_y) { selection_iterator_c it; for (list.begin(&it) ; !it.at_end() ; ++it) { const Thing * T = Things[*it]; int old_x = T->x; int old_y = T->y; if (anti_clockwise) { BA_ChangeTH(*it, Thing::F_X, mid_x - old_y + mid_y); BA_ChangeTH(*it, Thing::F_Y, mid_y + old_x - mid_x); BA_ChangeTH(*it, Thing::F_ANGLE, calc_new_angle(T->angle, +90)); } else { BA_ChangeTH(*it, Thing::F_X, mid_x + old_y - mid_y); BA_ChangeTH(*it, Thing::F_Y, mid_y - old_x + mid_x); BA_ChangeTH(*it, Thing::F_ANGLE, calc_new_angle(T->angle, -90)); } } } void CMD_Rotate90(void) { if (EXEC_Param[0] == 0) { Beep("Rotate90: missing keyword"); return; } bool anti_clockwise = (tolower(EXEC_Param[0][0]) == 'a'); selection_c list; selection_iterator_c it; if (! GetCurrentObjects(&list)) { Beep("No objects to rotate"); return; } int mid_x, mid_y; Objs_CalcMiddle(&list, &mid_x, &mid_y); BA_Begin(); if (edit.mode == OBJ_THINGS) { DoRotate90Things(list, anti_clockwise, mid_x, mid_y); } else { // handle things inside sectors if (edit.mode == OBJ_SECTORS) { selection_c things(OBJ_THINGS); ConvertSelection(&list, &things); DoRotate90Things(things, anti_clockwise, mid_x, mid_y); } // everything else just rotates the vertices selection_c verts(OBJ_VERTICES); ConvertSelection(&list, &verts); for (verts.begin(&it) ; !it.at_end() ; ++it) { const Vertex * V = Vertices[*it]; int old_x = V->x; int old_y = V->y; if (anti_clockwise) { BA_ChangeVT(*it, Vertex::F_X, mid_x - old_y + mid_y); BA_ChangeVT(*it, Vertex::F_Y, mid_y + old_x - mid_x); } else { BA_ChangeVT(*it, Vertex::F_X, mid_x + old_y - mid_y); BA_ChangeVT(*it, Vertex::F_Y, mid_y - old_x + mid_x); } } } BA_End(); } static void DoEnlargeThings(selection_c& list, int mul, int mid_x, int mid_y) { selection_iterator_c it; for (list.begin(&it) ; !it.at_end() ; ++it) { const Thing * T = Things[*it]; int dx = T->x - mid_x; int dy = T->y - mid_y; BA_ChangeTH(*it, Thing::F_X, mid_x + dx * mul); BA_ChangeTH(*it, Thing::F_Y, mid_y + dy * mul); } } void CMD_Enlarge(void) { selection_c list; selection_iterator_c it; if (! GetCurrentObjects(&list)) { Beep("No objects to enlarge"); return; } int mul = 2; if (EXEC_Param[0][0]) mul = atoi(EXEC_Param[0]); if (mul < 1 || mul > 64) { Beep("Bad parameter for enlarge: '%s'", EXEC_Param[0]); return; } int mid_x, mid_y, hx, hy; // TODO: CONFIG ITEM if (true) Objs_CalcMiddle(&list, &mid_x, &mid_y); else { Objs_CalcBBox(&list, &mid_x, &mid_y, &hx, &hy); mid_x = mid_x + (hx - mid_x) / 2; mid_y = mid_y + (hy - mid_y) / 2; } BA_Begin(); if (edit.mode == OBJ_THINGS) { DoEnlargeThings(list, mul, mid_x, mid_y); } else { // handle things inside sectors if (edit.mode == OBJ_SECTORS) { selection_c things(OBJ_THINGS); ConvertSelection(&list, &things); DoEnlargeThings(things, mul, mid_x, mid_y); } // everything else just scales the vertices selection_c verts(OBJ_VERTICES); ConvertSelection(&list, &verts); for (verts.begin(&it) ; !it.at_end() ; ++it) { const Vertex * V = Vertices[*it]; int dx = V->x - mid_x; int dy = V->y - mid_y; BA_ChangeVT(*it, Vertex::F_X, mid_x + dx * mul); BA_ChangeVT(*it, Vertex::F_Y, mid_y + dy * mul); } } BA_End(); } static void DoShrinkThings(selection_c& list, int div, int mid_x, int mid_y) { selection_iterator_c it; for (list.begin(&it) ; !it.at_end() ; ++it) { const Thing * T = Things[*it]; int dx = T->x - mid_x; int dy = T->y - mid_y; BA_ChangeTH(*it, Thing::F_X, mid_x + dx / div); BA_ChangeTH(*it, Thing::F_Y, mid_y + dy / div); } } void CMD_Shrink(void) { selection_c list; selection_iterator_c it; if (! GetCurrentObjects(&list)) { Beep("No objects to shrink"); return; } int div = 2; if (EXEC_Param[0][0]) div = atoi(EXEC_Param[0]); if (div < 1 || div > 64) { Beep("Bad parameter for shrink: '%s'", EXEC_Param[0]); return; } int mid_x, mid_y, hx, hy; // TODO: CONFIG ITEM if (true) Objs_CalcMiddle(&list, &mid_x, &mid_y); else { Objs_CalcBBox(&list, &mid_x, &mid_y, &hx, &hy); mid_x = mid_x + (hx - mid_x) / 2; mid_y = mid_y + (hy - mid_y) / 2; } BA_Begin(); if (edit.mode == OBJ_THINGS) { DoShrinkThings(list, div, mid_x, mid_y); } else { // handle things inside sectors if (edit.mode == OBJ_SECTORS) { selection_c things(OBJ_THINGS); ConvertSelection(&list, &things); DoShrinkThings(things, div, mid_x, mid_y); } // everything else just scales the vertices selection_c verts(OBJ_VERTICES); ConvertSelection(&list, &verts); for (verts.begin(&it) ; !it.at_end() ; ++it) { const Vertex * V = Vertices[*it]; int dx = V->x - mid_x; int dy = V->y - mid_y; BA_ChangeVT(*it, Vertex::F_X, mid_x + dx / div); BA_ChangeVT(*it, Vertex::F_Y, mid_y + dy / div); } } BA_End(); } static void DoScaleTwoThings(selection_c& list, scale_param_t& param) { selection_iterator_c it; for (list.begin(&it) ; !it.at_end() ; ++it) { const Thing * T = Things[*it]; int new_x = T->x; int new_y = T->y; param.Apply(&new_x, &new_y); BA_ChangeTH(*it, Thing::F_X, new_x); BA_ChangeTH(*it, Thing::F_Y, new_y); float rot1 = param.rotate / 8192.0; int ang_diff = I_ROUND(rot1) * 45.0; if (ang_diff) { BA_ChangeTH(*it, Thing::F_ANGLE, calc_new_angle(T->angle, ang_diff)); } } } static void DoScaleTwoVertices(selection_c& list, scale_param_t& param) { selection_c verts(OBJ_VERTICES); ConvertSelection(&list, &verts); selection_iterator_c it; for (verts.begin(&it) ; !it.at_end() ; ++it) { const Vertex * V = Vertices[*it]; int new_x = V->x; int new_y = V->y; param.Apply(&new_x, &new_y); BA_ChangeVT(*it, Vertex::F_X, new_x); BA_ChangeVT(*it, Vertex::F_Y, new_y); } } static void DoScaleTwoStuff(selection_c& list, scale_param_t& param) { if (edit.mode == OBJ_THINGS) { DoScaleTwoThings(list, param); return; } // everything else just modifies the vertices if (edit.mode == OBJ_SECTORS) { // handle things in Sectors mode too selection_c things(OBJ_THINGS); ConvertSelection(&list, &things); DoScaleTwoThings(things, param); } DoScaleTwoVertices(list, param); } void CMD_ScaleObjects2(scale_param_t& param) { // this is called by the MOUSE2 dynamic scaling code SYS_ASSERT(edit.Selected->notempty()); BA_Begin(); if (param.scale_x < 0) { param.scale_x = -param.scale_x; DoMirrorStuff(*edit.Selected, false /* is_vert */, param.mid_x, param.mid_y); } if (param.scale_y < 0) { param.scale_y = -param.scale_y; DoMirrorStuff(*edit.Selected, true /* is_vert */, param.mid_x, param.mid_y); } DoScaleTwoStuff(*edit.Selected, param); BA_End(); } static void DetermineOrigin(scale_param_t& param, int pos_x, int pos_y) { if (pos_x == 0 && pos_y == 0) { Objs_CalcMiddle(edit.Selected, ¶m.mid_x, ¶m.mid_y); return; } int lx, ly, hx, hy; Objs_CalcBBox(edit.Selected, &lx, &ly, &hx, &hy); if (pos_x < 0) param.mid_x = lx; else if (pos_x > 0) param.mid_x = hx; else param.mid_x = lx + (hx - lx) / 2; if (pos_y < 0) param.mid_y = ly; else if (pos_y > 0) param.mid_y = hy; else param.mid_y = ly + (hy - ly) / 2; } void CMD_ScaleObjects3(double scale_x, double scale_y, int pos_x, int pos_y) { SYS_ASSERT(scale_x > 0); SYS_ASSERT(scale_y > 0); scale_param_t param; param.Clear(); param.scale_x = scale_x; param.scale_y = scale_y; DetermineOrigin(param, pos_x, pos_y); BA_Begin(); { DoScaleTwoStuff(*edit.Selected, param); } BA_End(); } static void DoScaleSectorHeights(selection_c& list, double scale_z, int pos_z) { SYS_ASSERT(! list.empty()); selection_iterator_c it; // determine Z range and origin int lz = +99999; int hz = -99999; for (list.begin(&it) ; !it.at_end() ; ++it) { const Sector * S = Sectors[*it]; lz = MIN(lz, S->floorh); hz = MAX(hz, S->ceilh); } int mid_z; if (pos_z < 0) mid_z = lz; else if (pos_z > 0) mid_z = hz; else mid_z = lz + (hz - lz) / 2; // apply the scaling for (list.begin(&it) ; !it.at_end() ; ++it) { const Sector * S = Sectors[*it]; int new_f = mid_z + I_ROUND((S->floorh - mid_z) * scale_z); int new_c = mid_z + I_ROUND((S-> ceilh - mid_z) * scale_z); BA_ChangeSEC(*it, Sector::F_FLOORH, new_f); BA_ChangeSEC(*it, Sector::F_CEILH, new_c); } } void CMD_ScaleObjects3(double scale_x, double scale_y, double scale_z, int pos_x, int pos_y, int pos_z) { SYS_ASSERT(edit.mode == OBJ_SECTORS); scale_param_t param; param.Clear(); param.scale_x = scale_x; param.scale_y = scale_y; DetermineOrigin(param, pos_x, pos_y); BA_Begin(); { DoScaleTwoStuff(*edit.Selected, param); DoScaleSectorHeights(*edit.Selected, scale_z, pos_z); } BA_End(); } void CMD_RotateObjects3(double deg, int pos_x, int pos_y) { scale_param_t param; param.Clear(); param.rotate = I_ROUND(deg * 65536.0 / 360.0); DetermineOrigin(param, pos_x, pos_y); BA_Begin(); { DoScaleTwoStuff(*edit.Selected, param); } BA_End(); } bool SpotInUse(obj_type_e obj_type, int map_x, int map_y) { // FIXME: FindObjectAt(obj_type, map_x, map_y) switch (obj_type) { case OBJ_THINGS: for (int n = 0 ; n < NumThings ; n++) if (Things[n]->x == map_x && Things[n]->y == map_y) return true; return false; case OBJ_VERTICES: for (int n = 0 ; n < NumVertices ; n++) if (Vertices[n]->x == map_x && Vertices[n]->y == map_y) return true; return false; default: BugError("IsSpotVacant: bad object type\n"); return false; } } static void Quantize_Things(selection_c& list) { // remember the things which we moved // (since we cannot modify the selection while we iterate over it) selection_c moved(list.what_type()); selection_iterator_c it; for (list.begin(&it) ; !it.at_end() ; ++it) { const Thing * T = Things[*it]; if (grid.OnGrid(T->x, T->y)) { moved.set(*it); continue; } for (int pass = 0 ; pass < 4 ; pass++) { int new_x = grid.QuantSnapX(T->x, pass & 1); int new_y = grid.QuantSnapY(T->y, pass & 2); if (! SpotInUse(OBJ_THINGS, new_x, new_y)) { BA_ChangeTH(*it, Thing::F_X, new_x); BA_ChangeTH(*it, Thing::F_Y, new_y); moved.set(*it); break; } } } list.unmerge(moved); if (list.notempty()) Beep("Quantize: could not move %d things", list.count_obj()); } static void Quantize_Vertices(selection_c& list) { // first : do an analysis pass, remember vertices that are part // of a horizontal or vertical line (and both in the selection) // and limit the movement of those vertices to ensure the lines // stay horizontal or vertical. enum { V_HORIZ = (1 << 0), V_VERT = (1 << 1), V_DIAG_NE = (1 << 2), V_DIAG_SE = (1 << 3) }; byte * vert_modes = new byte[NumVertices]; for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; // require both vertices of the linedef to be in the selection if (! (list.get(L->start) && list.get(L->end))) continue; // IDEA: make this a method of LineDef int x1 = L->Start()->x; int y1 = L->Start()->y; int x2 = L->End()->x; int y2 = L->End()->y; if (y1 == y2) { vert_modes[L->start] |= V_HORIZ; vert_modes[L->end] |= V_HORIZ; } else if (x1 == x2) { vert_modes[L->start] |= V_VERT; vert_modes[L->end] |= V_VERT; } else if ((x1 < x2 && y1 < y2) || (x1 > x2 && y1 > y2)) { vert_modes[L->start] |= V_DIAG_NE; vert_modes[L->end] |= V_DIAG_NE; } else { vert_modes[L->start] |= V_DIAG_SE; vert_modes[L->end] |= V_DIAG_SE; } } // remember the vertices which we moved // (since we cannot modify the selection while we iterate over it) selection_c moved(list.what_type()); selection_iterator_c it; for (list.begin(&it) ; !it.at_end() ; ++it) { const Vertex * V = Vertices[*it]; if (grid.OnGrid(V->x, V->y)) { moved.set(*it); continue; } byte mode = vert_modes[*it]; for (int pass = 0 ; pass < 4 ; pass++) { int x_dir, y_dir; int new_x = grid.QuantSnapX(V->x, pass & 1, &x_dir); int new_y = grid.QuantSnapY(V->y, pass & 2, &y_dir); // keep horizontal lines horizontal if ((mode & V_HORIZ) && (pass & 2)) continue; // keep vertical lines vertical if ((mode & V_VERT) && (pass & 1)) continue; // TODO: keep diagonal lines diagonal... if (! SpotInUse(OBJ_VERTICES, new_x, new_y)) { BA_ChangeVT(*it, Vertex::F_X, new_x); BA_ChangeVT(*it, Vertex::F_Y, new_y); moved.set(*it); break; } } } delete[] vert_modes; list.unmerge(moved); if (list.notempty()) Beep("Quantize: could not move %d vertices", list.count_obj()); } void CMD_Quantize(void) { if (edit.Selected->empty()) { if (edit.highlight.is_nil()) { Beep("Nothing to quantize"); return; } edit.Selected->set(edit.highlight.num); } BA_Begin(); switch (edit.mode) { case OBJ_THINGS: Quantize_Things(*edit.Selected); break; case OBJ_VERTICES: Quantize_Vertices(*edit.Selected); break; // everything else merely quantizes vertices default: { selection_c verts(OBJ_VERTICES); ConvertSelection(edit.Selected, &verts); Quantize_Vertices(verts); Selection_Clear(); break; } } BA_End(); edit.error_mode = true; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_loadsave.h0000644000175100017510000000325212647061302016533 0ustar aaptedaapted//------------------------------------------------------------------------ // LEVEL LOAD / SAVE / NEW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2015 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_LOADSAVE_H__ #define __EUREKA_E_LOADSAVE_H__ #include "w_wad.h" void LoadLevel(Wad_file *wad, const char *level); void RemoveEditWad(); bool ProjectSetup(bool new_project = false, bool is_startup = false); void CMD_NewMap(); bool CMD_OpenMap(); void CMD_OpenFileMap(const char *filename, const char *map_name = NULL); extern int last_given_file; void CMD_GivenFile(); void CMD_FlipMap(); bool CMD_SaveMap(); bool CMD_ExportMap(); void CMD_RenameMap(); void CMD_DeleteMap(); #endif /* __EUREKA_E_LOADSAVE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_nodes.h0000644000175100017510000000322612647061302016237 0ustar aaptedaapted//------------------------------------------------------------------------ // Node Building Window //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2012 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 __EUREKA_UI_NODES_H__ #define __EUREKA_UI_NODES_H__ class UI_NodeDialog : public Fl_Double_Window { public: Fl_Browser *browser; Fl_Progress *progress; Fl_Button * button; int cur_prog; char prog_label[64]; bool finished; bool want_cancel; bool want_close; public: UI_NodeDialog(); virtual ~UI_NodeDialog(); /* FLTK method */ int handle(int event); public: void SetStatus(const char *str); void SetProg(int perc); void Print(const char *str); void Finish_OK(); void Finish_Cancel(); void Finish_Error(); bool WantCancel() const { return want_cancel; } bool WantClose() const { return want_close; } private: static void close_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_NODES_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_strings.cc0000644000175100017510000001011312647061302016566 0ustar aaptedaapted//------------------------------------------------------------------------ // STRING TABLE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 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 "main.h" #include "m_strings.h" #define CHARS_PER_BLOCK 4096 class string_block_c { public: char data[CHARS_PER_BLOCK]; int used; public: string_block_c() : used(0) { } ~string_block_c() { } bool fits(int len) const { return (used + len + 1) < CHARS_PER_BLOCK; } int add(const char *str, int len) { SYS_ASSERT(fits(len)); int offset = used; used += (len+1); memcpy(data + offset, str, len+1); return offset; } int find(const char *str, int len) const { int pos = 0; while (pos < used) { int p_len = (int)strlen(data + pos); // we allow matching the end of existing strings if (len <= p_len) { if (memcmp(data + pos + (p_len-len), str, len) == 0) return pos + (p_len-len); } pos += (p_len+1); } return -1; // NOT FOUND } }; //------------------------------------------------------------------------ string_table_c::string_table_c() : blocks(), huge_ones() { // nothing needed } string_table_c::~string_table_c() { clear(); } int string_table_c::add(const char *str) { if (!str || !str[0]) return 0; int len = (int)strlen(str); if (len > CHARS_PER_BLOCK/5) { int offset = find_huge(str, len); return offset ? offset : add_huge(str, len); } int offset = find_normal(str, len); return offset ? offset : add_normal(str, len); } const char * string_table_c::get(int offset) { if (offset == 0) return ""; if (offset < 0) { offset = -(offset + 1); SYS_ASSERT(offset < (int)huge_ones.size()); return huge_ones[offset]; } offset--; int blk_num = offset / CHARS_PER_BLOCK; offset = offset % CHARS_PER_BLOCK; SYS_ASSERT(blk_num < (int)blocks.size()); return & blocks[blk_num]->data[offset]; } void string_table_c::clear() { for (int i = 0; i < (int)blocks.size(); i++) delete blocks[i]; for (int i = 0; i < (int)huge_ones.size(); i++) delete[] huge_ones[i]; blocks.clear(); huge_ones.clear(); } int string_table_c::find_normal(const char *str, int len) { for (int blk_num = 0; blk_num < (int)blocks.size(); blk_num++) { int offset = blocks[blk_num]->find(str, len); if (offset != -1) return (blk_num * CHARS_PER_BLOCK) + offset + 1; } return 0; // not found } int string_table_c::add_normal(const char *str, int len) { if (blocks.empty()) blocks.push_back(new string_block_c); int blk_num = (int)blocks.size() - 1; if (! blocks[blk_num]->fits(len)) { // try some earlier blocks if (blk_num >= 1 && blocks[blk_num-1]->fits(len)) blk_num -= 1; else if (blk_num >= 2 && blocks[blk_num-2]->fits(len)) blk_num -= 2; else if (blk_num >= 3 && blocks[blk_num-3]->fits(len)) blk_num -= 3; else if (blk_num >= 4 && blocks[blk_num-4]->fits(len)) blk_num -= 4; else { // need a new block blocks.push_back(new string_block_c); blk_num++; } } int offset = blocks[blk_num]->add(str, len); return (blk_num * CHARS_PER_BLOCK) + offset + 1; } int string_table_c::find_huge(const char *str, int len) { for (int i = 0; i < (int)huge_ones.size(); i++) { if (strcmp(huge_ones[i], str) == 0) return -(i+1); } return 0; } int string_table_c::add_huge(const char *str, int len) { char *buf = new char[len+2]; strcpy(buf, str); huge_ones.push_back(buf); return -(int)huge_ones.size(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_select.cc0000644000175100017510000001430612647575606016405 0ustar aaptedaapted//------------------------------------------------------------------------ // SELECTION SET //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "m_select.h" #include "objects.h" //#define NEED_SLOW_CLEAR #define INITIAL_BITVEC_SIZE 1024 selection_c::selection_c(obj_type_e _type) : type(_type), count(0), bv(NULL), b_count(0), maxobj(-1), first_obj(-1) { } selection_c::~selection_c() { if (bv) delete bv; } void selection_c::change_type(obj_type_e new_type) { type = new_type; clear_all(); } bool selection_c::empty() const { if (bv) return b_count == 0; return count == 0; } int selection_c::count_obj() const { if (! bv) return count; return b_count; // hmmm, not so slow after all } bool selection_c::get(int n) const { if (bv) return bv->get(n); for (int i = 0 ; i < count ; i++) if (objs[i] == n) return true; return false; } void selection_c::set(int n) { if (get(n)) return; if (maxobj < n) maxobj = n; if (first_obj < 0 && empty()) first_obj = n; if (!bv && count >= MAX_STORE_SEL) { ConvertToBitvec(); } if (bv) { bv->set(n); b_count++; return; } objs[count++] = n; } void selection_c::clear(int n) { if (bv) { if (! get(n)) return; bv->clear(n); b_count--; } else { int i; for (i = 0 ; i < count ; i++) if (objs[i] == n) break; if (i >= count) return; // not present count--; #ifdef NEED_SLOW_CLEAR for ( ; i < count ; i++) objs[i] = objs[i+1]; #else if (i < count) objs[i] = objs[count]; #endif } if (maxobj == n) RecomputeMaxObj(); if (first_obj == n) first_obj = -1; } void selection_c::toggle(int n) { if (get(n)) clear(n); else set(n); } void selection_c::clear_all() { count = 0; maxobj = -1; first_obj = -1; if (bv) { delete bv; } bv = NULL; b_count = 0; } void selection_c::frob(int n, sel_op_e op) { switch (op) { case BOP_ADD: set(n); break; case BOP_REMOVE: clear(n); break; default: toggle(n); break; } } void selection_c::frob_range(int n1, int n2, sel_op_e op) { for ( ; n1 <= n2 ; n1++) { frob(n1, op); } } void selection_c::merge(const selection_c& other) { if (! other.bv) { for (int i = 0 ; i < other.count ; i++) set(other.objs[i]); return; } if (! bv) ConvertToBitvec(); for (int i = 0 ; i < other.bv->size() ; i++) if (other.bv->get(i)) set(i); } void selection_c::unmerge(const selection_c& other) { if (! other.bv) { for (int i = 0 ; i < other.count ; i++) clear(other.objs[i]); } else { for (int i = 0 ; i < other.bv->size() ; i++) if (other.bv->get(i)) clear(i); } } void selection_c::intersect(const selection_c& other) { if (! bv) ConvertToBitvec(); int cur_size = bv->size(); for (int i = 0 ; i < cur_size ; i++) if (get(i) != other.get(i)) clear(i); } bool selection_c::test_equal(const selection_c& other) { if (type != other.type) return false; if (maxobj != other.maxobj) return false; if (count_obj() != other.count_obj()) return false; // the quick tests have passed, now perform the expensive one selection_iterator_c it; for (begin(&it) ; !it.at_end() ; ++it) if (! other.get(*it)) return false; return true; } void selection_c::ConvertToBitvec() { SYS_ASSERT(! bv); int size = INITIAL_BITVEC_SIZE; if (size < maxobj+1) size = maxobj+1; bv = new bitvec_c(size); for (int i = 0 ; i < count ; i++) { bv->set(objs[i]); } b_count = count; count = 0; } void selection_c::RecomputeMaxObj() { maxobj = -1; if (bv) { // search backwards so we can early out for (int i = bv->size()-1 ; i >= 0 ; i--) { if (bv->get(i)) { maxobj = i; break; } } } else { // cannot optimise here, values are not sorted for (int i = 0 ; i < count ; i++) { maxobj = MAX(maxobj, objs[i]); } } } int selection_c::find_first() const { if (first_obj >= 0) { SYS_ASSERT(get(first_obj)); return first_obj; } selection_iterator_c it; begin(&it); return it.at_end() ? -1 : *it; } int selection_c::find_second() const { selection_iterator_c it; begin(&it); if (it.at_end()) return -1; // the logic here is trickier than it looks. // // When first_obj exists AND is the same as the very first object // in the group, then this test fails and we move onto the next // object in the group. if (first_obj >= 0 && *it != first_obj) return *it; ++it; return it.at_end() ? -1 : *it; } //------------------------------------------------------------------------ // ITERATOR STUFF //------------------------------------------------------------------------ void selection_c::begin(selection_iterator_c *it) const { it->sel = this; it->pos = 0; if (bv) { // for bit vector, need to find the first one bit // Note: this logic is rather hacky it->pos = -1; ++ (*it); } } bool selection_iterator_c::at_end() const { if (sel->bv) return (pos >= sel->bv->size()); else return (pos >= sel->count); } int selection_iterator_c::operator* () const { if (sel->bv) return pos; else return sel->objs[pos]; } selection_iterator_c& selection_iterator_c::operator++ () { pos++; if (sel->bv) { // this could be optimised.... while (pos < sel->bv->size() && ! sel->bv->get(pos)) pos++; } return *this; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/e_checks2.cc0000644000175100017510000012160012650264246016421 0ustar aaptedaapted//------------------------------------------------------------------------ // INTEGRITY CHECKS II //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include "e_checks.h" #include "e_path.h" #include "e_vertex.h" #include "e_cutpaste.h" #include "editloop.h" #include "m_game.h" #include "levels.h" #include "objects.h" #include "w_rawdef.h" #include "w_flats.h" #include "w_texture.h" #include "ui_window.h" #include "x_hover.h" #define ERROR_MSG_COLOR FL_RED #define WARNING_MSG_COLOR FL_BLUE static char check_buffer[MSG_BUF_LEN]; void LineDefs_FindZeroLen(selection_c& lines) { lines.change_type(OBJ_LINEDEFS); for (int n = 0 ; n < NumLineDefs ; n++) if (LineDefs[n]->isZeroLength()) lines.set(n); } void LineDefs_RemoveZeroLen() { selection_c sel; BA_Begin(); for (int n = NumLineDefs-1 ; n >= 0 ; n--) { const LineDef *L = LineDefs[n]; if (! L->isZeroLength()) continue; // merge the vertices if possible if (L->start == L->end) { BA_Delete(OBJ_LINEDEFS, n); } else { MergeVertex(L->start, L->end, true); BA_Delete(OBJ_VERTICES, L->start); } } BA_End(); } void LineDefs_ShowZeroLen() { if (edit.mode != OBJ_VERTICES) Editor_ChangeMode('v'); selection_c sel; LineDefs_FindZeroLen(sel); ConvertSelection(&sel, edit.Selected); GoToErrors(); } void LineDefs_FindMissingRight(selection_c& lines) { lines.change_type(OBJ_LINEDEFS); for (int n = 0 ; n < NumLineDefs ; n++) if (LineDefs[n]->right < 0) lines.set(n); } void LineDefs_ShowMissingRight() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); LineDefs_FindMissingRight(*edit.Selected); GoToErrors(); } void LineDefs_FindManualDoors(selection_c& lines) { // find D1/DR manual doors on one-sided linedefs lines.change_type(OBJ_LINEDEFS); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->type <= 0) continue; if (L->left >= 0) continue; const linetype_t *info = M_GetLineType(L->type); if (info->desc[0] == 'D' && (info->desc[1] == '1' || info->desc[1] == 'R')) { lines.set(n); } } } void LineDefs_ShowManualDoors() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); LineDefs_FindManualDoors(*edit.Selected); GoToErrors(); } void LineDefs_FixManualDoors() { BA_Begin(); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->type <= 0 || L->left >= 0) continue; const linetype_t *info = M_GetLineType(L->type); if (info->desc[0] == 'D' && (info->desc[1] == '1' || info->desc[1] == 'R')) { BA_ChangeLD(n, LineDef::F_TYPE, 0); } } BA_End(); } void LineDefs_FindLackImpass(selection_c& lines) { lines.change_type(OBJ_LINEDEFS); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->OneSided() && (L->flags & MLF_Blocking) == 0) lines.set(n); } } void LineDefs_ShowLackImpass() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); LineDefs_FindLackImpass(*edit.Selected); GoToErrors(); } void LineDefs_FixLackImpass() { BA_Begin(); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->OneSided() && (L->flags & MLF_Blocking) == 0) { int new_flags = L->flags | MLF_Blocking; BA_ChangeLD(n, LineDef::F_FLAGS, new_flags); } } BA_End(); } void LineDefs_FindBad2SFlag(selection_c& lines) { lines.change_type(OBJ_LINEDEFS); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->OneSided() && (L->flags & MLF_TwoSided)) lines.set(n); if (L->TwoSided() && ! (L->flags & MLF_TwoSided)) lines.set(n); } } void LineDefs_ShowBad2SFlag() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); LineDefs_FindBad2SFlag(*edit.Selected); GoToErrors(); } void LineDefs_FixBad2SFlag() { BA_Begin(); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->OneSided() && (L->flags & MLF_TwoSided)) BA_ChangeLD(n, LineDef::F_FLAGS, L->flags & ~MLF_TwoSided); if (L->TwoSided() && ! (L->flags & MLF_TwoSided)) BA_ChangeLD(n, LineDef::F_FLAGS, L->flags | MLF_TwoSided); } BA_End(); } static void bung_unknown_type(std::map& t_map, int type) { int count = 0; if (t_map.find(type) != t_map.end()) count = t_map[type]; t_map[type] = count + 1; } void LineDefs_FindUnknown(selection_c& list, std::map& types) { types.clear(); list.change_type(OBJ_LINEDEFS); for (int n = 0 ; n < NumLineDefs ; n++) { int type_num = LineDefs[n]->type; const linetype_t *info = M_GetLineType(type_num); // Boom generalized line type? if (game_info.gen_types && is_genline(type_num)) continue; if (strncmp(info->desc, "UNKNOWN", 7) == 0) { bung_unknown_type(types, type_num); list.set(n); } } } void LineDefs_ShowUnknown() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); std::map types; LineDefs_FindUnknown(*edit.Selected, types); GoToErrors(); } void LineDefs_LogUnknown() { selection_c sel; std::map types; std::map::iterator IT; LineDefs_FindUnknown(sel, types); LogPrintf("\n"); LogPrintf("Unknown Line Types:\n"); LogPrintf("{\n"); for (IT = types.begin() ; IT != types.end() ; IT++) LogPrintf(" %5d x %d\n", IT->first, IT->second); LogPrintf("}\n"); LogViewer_Open(); } void LineDefs_ClearUnknown() { selection_c sel; std::map types; LineDefs_FindUnknown(sel, types); selection_iterator_c it; BA_Begin(); for (sel.begin(&it) ; !it.at_end() ; ++it) BA_ChangeLD(*it, LineDef::F_TYPE, 0); BA_End(); } //------------------------------------------------------------------------ static int linedef_pos_cmp(int A, int B) { const LineDef *AL = LineDefs[A]; const LineDef *BL = LineDefs[B]; int A_x1 = AL->Start()->x; int A_y1 = AL->Start()->y; int A_x2 = AL->End()->x; int A_y2 = AL->End()->y; int B_x1 = BL->Start()->x; int B_y1 = BL->Start()->y; int B_x2 = BL->End()->x; int B_y2 = BL->End()->y; if (A_x1 > A_x2 || (A_x1 == A_x2 && A_y1 > A_y2)) { std::swap(A_x1, A_x2); std::swap(A_y1, A_y2); } if (B_x1 > B_x2 || (B_x1 == B_x2 && B_y1 > B_y2)) { std::swap(B_x1, B_x2); std::swap(B_y1, B_y2); } // the "normalized" X1 coordinates is the most significant thing in // this comparison function. if (A_x1 != B_x1) return A_x1 - B_x1; if (A_y1 != B_y1) return A_y1 - B_y1; if (A_x2 != B_x2) return A_x2 - B_x2; if (A_y2 != B_y2) return A_y2 - B_y2; return 0; // equal : lines are overlapping } struct linedef_pos_CMP_pred { inline bool operator() (int A, int B) const { return linedef_pos_cmp(A, B) < 0; } }; struct linedef_minx_CMP_pred { inline bool operator() (int A, int B) const { const LineDef *AL = LineDefs[A]; const LineDef *BL = LineDefs[B]; int A_x1 = MIN(AL->Start()->x, AL->End()->x); int B_x1 = MIN(BL->Start()->x, BL->End()->x); return A_x1 < B_x1; } }; void LineDefs_FindOverlaps(selection_c& lines) { // we only find directly overlapping linedefs here lines.change_type(OBJ_LINEDEFS); if (NumLineDefs < 2) return; int n; // sort linedefs by their position. overlapping lines will end up // adjacent to each other after the sort. std::vector sorted_list(NumLineDefs, 0); for (n = 0 ; n < NumLineDefs ; n++) sorted_list[n] = n; std::sort(sorted_list.begin(), sorted_list.end(), linedef_pos_CMP_pred()); for (n = 0 ; n < NumLineDefs - 1 ; n++) { int ld1 = sorted_list[n]; int ld2 = sorted_list[n + 1]; // only the second (or third, etc) linedef is stored if (linedef_pos_cmp(ld1, ld2) == 0) lines.set(ld2); } } void LineDefs_ShowOverlaps() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); LineDefs_FindOverlaps(*edit.Selected); GoToErrors(); } void LineDefs_RemoveOverlaps() { selection_c lines, unused_verts; LineDefs_FindOverlaps(lines); UnusedVertices(&lines, &unused_verts); BA_Begin(); DeleteObjects(&lines); DeleteObjects(&unused_verts); BA_End(); } static bool CheckLinesCross(int A, int B) { SYS_ASSERT(A != B); const LineDef *AL = LineDefs[A]; const LineDef *BL = LineDefs[B]; // ignore zero-length lines if (AL->isZeroLength() || BL->isZeroLength()) return false; // ignore lines connected at a vertex // TODO: check for sitting on top if (AL->start == BL->start || AL->start == BL->end) return false; if (AL->end == BL->start || AL->end == BL->end) return false; // bbox test // // the algorithm in LineDefs_FindCrossings() ensures that A and B // already overlap on the X axis. hence only check Y axis here. if (MIN(AL->Start()->y, AL->End()->y) > MAX(BL->Start()->y, BL->End()->y)) { return false; } if (MIN(BL->Start()->y, BL->End()->y) > MAX(AL->Start()->y, AL->End()->y)) { return false; } // precise (but slower) intersection test int ax1 = AL->Start()->x; int ay1 = AL->Start()->y; int ax2 = AL->End()->x; int ay2 = AL->End()->y; int bx1 = BL->Start()->x; int by1 = BL->Start()->y; int bx2 = BL->End()->x; int by2 = BL->End()->y; const double DIST = 0.6; double c = PerpDist(bx1, by1, ax1, ay1, ax2, ay2); double d = PerpDist(bx2, by2, ax1, ay1, ax2, ay2); if (c < -DIST && d < -DIST) return false; if (c > DIST && d > DIST) return false; double e = PerpDist(ax1, ay1, bx1, by1, bx2, by2); double f = PerpDist(ax2, ay2, bx1, by1, bx2, by2); if (e < -DIST && f < -DIST) return false; if (e > DIST && f > DIST) return false; // TODO: lines are (roughly) co-linear, check for separation return true; } void LineDefs_FindCrossings(selection_c& lines) { lines.change_type(OBJ_LINEDEFS); if (NumLineDefs < 2) return; int n; // sort linedefs by their position. linedefs which cross will be // near each other in this list. std::vector sorted_list(NumLineDefs, 0); for (n = 0 ; n < NumLineDefs ; n++) sorted_list[n] = n; std::sort(sorted_list.begin(), sorted_list.end(), linedef_minx_CMP_pred()); for (n = 0 ; n < NumLineDefs ; n++) { int n2 = sorted_list[n]; const LineDef *L1 = LineDefs[n2]; int max_x = MAX(L1->Start()->x, L1->End()->x); for (int k = n + 1 ; k < NumLineDefs ; k++) { int k2 = sorted_list[k]; const LineDef *L2 = LineDefs[k2]; int min_x = MIN(L2->Start()->x, L2->End()->x); // stop when all remaining linedefs are to the right of L1 if (min_x > max_x) break; // ignore direct overlapping here if (linedef_pos_cmp(n2, k2) == 0) continue; if (CheckLinesCross(n2, k2)) { // only the second (or third, etc) linedef is stored lines.set(k2); lines.set(n2); } } } } void LineDefs_ShowCrossings() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); LineDefs_FindCrossings(*edit.Selected); GoToErrors(); } //------------------------------------------------------------------------ class UI_Check_LineDefs : public UI_Check_base { public: UI_Check_LineDefs(bool all_mode) : UI_Check_base(530, 370, all_mode, "Check : LineDefs", "LineDef test results") { } public: static void action_show_zero(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowZeroLen(); dialog->user_action = CKR_Highlight; } static void action_remove_zero(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_RemoveZeroLen(); dialog->user_action = CKR_TookAction; } static void action_show_mis_right(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowMissingRight(); dialog->user_action = CKR_Highlight; } static void action_show_manual_doors(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowManualDoors(); dialog->user_action = CKR_Highlight; } static void action_fix_manual_doors(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_FixManualDoors(); dialog->user_action = CKR_TookAction; } static void action_show_lack_impass(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowLackImpass(); dialog->user_action = CKR_Highlight; } static void action_fix_lack_impass(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_FixLackImpass(); dialog->user_action = CKR_TookAction; } static void action_show_bad_2s_flag(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowBad2SFlag(); dialog->user_action = CKR_Highlight; } static void action_fix_bad_2s_flag(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_FixBad2SFlag(); dialog->user_action = CKR_TookAction; } static void action_show_unknown(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowUnknown(); dialog->user_action = CKR_Highlight; } static void action_log_unknown(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_LogUnknown(); dialog->user_action = CKR_Highlight; } static void action_clear_unknown(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ClearUnknown(); dialog->user_action = CKR_TookAction; } static void action_remove_overlap(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_RemoveOverlaps(); dialog->user_action = CKR_TookAction; } static void action_show_overlap(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowOverlaps(); dialog->user_action = CKR_Highlight; } static void action_show_crossing(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowCrossings(); dialog->user_action = CKR_Highlight; } }; check_result_e CHECK_LineDefs(int min_severity) { UI_Check_LineDefs *dialog = new UI_Check_LineDefs(min_severity > 0); selection_c sel, other; std::map types; for (;;) { LineDefs_FindZeroLen(sel); if (sel.empty()) dialog->AddLine("No zero-length linedefs"); else { sprintf(check_buffer, "%d zero-length linedefs", sel.count_obj()); dialog->AddLine(check_buffer, 2, 220, "Show", &UI_Check_LineDefs::action_show_zero, "Remove", &UI_Check_LineDefs::action_remove_zero); } LineDefs_FindOverlaps(sel); if (sel.empty()) dialog->AddLine("No overlapping linedefs"); else { sprintf(check_buffer, "%d overlapping linedefs", sel.count_obj()); dialog->AddLine(check_buffer, 2, 220, "Show", &UI_Check_LineDefs::action_show_overlap, "Remove", &UI_Check_LineDefs::action_remove_overlap); } LineDefs_FindCrossings(sel); if (sel.empty()) dialog->AddLine("No criss-crossing linedefs"); else { sprintf(check_buffer, "%d criss-crossing linedefs", sel.count_obj()); dialog->AddLine(check_buffer, 2, 220, "Show", &UI_Check_LineDefs::action_show_crossing); } dialog->AddGap(10); LineDefs_FindUnknown(sel, types); if (sel.empty()) dialog->AddLine("No unknown line types"); else { sprintf(check_buffer, "%d unknown line types", (int)types.size()); dialog->AddLine(check_buffer, 1, 210, "Show", &UI_Check_LineDefs::action_show_unknown, "Log", &UI_Check_LineDefs::action_log_unknown, "Clear", &UI_Check_LineDefs::action_clear_unknown); } LineDefs_FindMissingRight(sel); if (sel.empty()) dialog->AddLine("No linedefs without a right side"); else { sprintf(check_buffer, "%d linedefs without right side", sel.count_obj()); dialog->AddLine(check_buffer, 2, 250, "Show", &UI_Check_LineDefs::action_show_mis_right); } LineDefs_FindManualDoors(sel); if (sel.empty()) dialog->AddLine("No manual doors on 1S linedefs"); else { sprintf(check_buffer, "%d manual doors on 1S linedefs", sel.count_obj()); dialog->AddLine(check_buffer, 2, 250, "Show", &UI_Check_LineDefs::action_show_manual_doors, "Fix", &UI_Check_LineDefs::action_fix_manual_doors); } LineDefs_FindLackImpass(sel); if (sel.empty()) dialog->AddLine("No non-blocking one-sided linedefs"); else { sprintf(check_buffer, "%d non-blocking one-sided linedefs", sel.count_obj()); dialog->AddLine(check_buffer, 1, 300, "Show", &UI_Check_LineDefs::action_show_lack_impass, "Fix", &UI_Check_LineDefs::action_fix_lack_impass); } LineDefs_FindBad2SFlag(sel); if (sel.empty()) dialog->AddLine("No linedefs with wrong 2S flag"); else { sprintf(check_buffer, "%d linedefs with wrong 2S flag", sel.count_obj()); dialog->AddLine(check_buffer, 1, 285, "Show", &UI_Check_LineDefs::action_show_bad_2s_flag, "Fix", &UI_Check_LineDefs::action_fix_bad_2s_flag); } // in "ALL" mode, just continue if not too severe if (dialog->WorstSeverity() < min_severity) { delete dialog; return CKR_OK; } check_result_e result = dialog->Run(); if (result == CKR_TookAction) { // repeat the tests dialog->Reset(); continue; } delete dialog; return result; } } //------------------------------------------------------------------------ void Tags_UsedRange(int *min_tag, int *max_tag) { int i; *min_tag = +999999; *max_tag = -999999; for (i = 0 ; i < NumLineDefs ; i++) { int tag = LineDefs[i]->tag; if (tag > 0) { *min_tag = MIN(*min_tag, tag); *max_tag = MAX(*max_tag, tag); } } for (i = 0 ; i < NumSectors ; i++) { int tag = Sectors[i]->tag; if (tag > 0) { *min_tag = MIN(*min_tag, tag); *max_tag = MAX(*max_tag, tag); } } // none at all? if (*min_tag > *max_tag) { *min_tag = *max_tag = 0; } } void Tags_ApplyNewValue(int new_tag) { selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { if (edit.mode == OBJ_LINEDEFS) BA_ChangeLD(*it, LineDef::F_TAG, new_tag); else if (edit.mode == OBJ_SECTORS) BA_ChangeSEC(*it, Sector::F_TAG, new_tag); } BA_End(); } } void CMD_ApplyTag() { if (! (edit.mode == OBJ_SECTORS || edit.mode == OBJ_LINEDEFS)) { Beep("ApplyTag: wrong mode"); return; } bool do_last = false; const char *mode = EXEC_Param[0]; if (mode[0] == 0 || y_stricmp(mode, "fresh") == 0) { // fresh tag } else if (y_stricmp(mode, "last") == 0) { do_last = true; } else { Beep("ApplyTag: unknown keyword: %s\n", mode); return; } bool unselect = false; if (edit.Selected->empty()) { if (edit.highlight.is_nil()) { Beep("ApplyTag: nothing selected"); return; } edit.Selected->set(edit.highlight.num); unselect = true; } int min_tag, max_tag; Tags_UsedRange(&min_tag, &max_tag); int new_tag = max_tag + (do_last ? 0 : 1); if (new_tag <= 0) { Beep("No last tag"); return; } else if (new_tag > 32767) { Beep("Out of tag numbers"); return; } Tags_ApplyNewValue(new_tag); if (unselect) Selection_Clear(true); } static bool LD_tag_exists(int tag) { for (int n = 0 ; n < NumLineDefs ; n++) if (LineDefs[n]->tag == tag) return true; return false; } static bool SEC_tag_exists(int tag) { for (int s = 0 ; s < NumSectors ; s++) if (Sectors[s]->tag == tag) return true; return false; } void Tags_FindUnmatchedSectors(selection_c& secs) { secs.change_type(OBJ_SECTORS); for (int s = 0 ; s < NumSectors ; s++) { int tag = Sectors[s]->tag; if (tag <= 0) continue; if (! LD_tag_exists(tag)) secs.set(s); } } void Tags_FindUnmatchedLineDefs(selection_c& lines) { lines.change_type(OBJ_LINEDEFS); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->tag <= 0) continue; // TODO: handle special BOOM types (e.g. line-to-line teleporter) if (L->type <= 0) continue; if (! SEC_tag_exists(L->tag)) lines.set(n); } } void Tags_ShowUnmatchedSectors() { if (edit.mode != OBJ_SECTORS) Editor_ChangeMode('s'); Tags_FindUnmatchedSectors(*edit.Selected); GoToErrors(); } void Tags_ShowUnmatchedLineDefs() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); Tags_FindUnmatchedLineDefs(*edit.Selected); GoToErrors(); } void Tags_FindMissingTags(selection_c& lines) { lines.change_type(OBJ_LINEDEFS); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->type <= 0) continue; if (L->tag > 0) continue; // use type description to determine if a tag is needed // e.g. D1, DR, --, and lowercase first letter all mean "no tag". // TODO: boom generalized manual doors (etc??) const linetype_t *info = M_GetLineType(L->type); char first = info->desc[0]; if (first == 'D' || first == '-' || ('a' <= first && first <= 'z')) continue; lines.set(n); } } void Tags_ShowMissingTags() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); Tags_FindMissingTags(*edit.Selected); GoToErrors(); } //------------------------------------------------------------------------ class UI_Check_Tags : public UI_Check_base { public: int fresh_tag; public: UI_Check_Tags(bool all_mode) : UI_Check_base(520, 286, all_mode, "Check : Tags", "Tag test results") { } public: static void action_fresh_tag(Fl_Widget *w, void *data) { UI_Check_Tags *dialog = (UI_Check_Tags *)data; // fresh_tag is set externally Tags_ApplyNewValue(dialog->fresh_tag); dialog->want_close = true; } static void action_show_unmatch_sec(Fl_Widget *w, void *data) { UI_Check_Tags *dialog = (UI_Check_Tags *)data; Tags_ShowUnmatchedSectors(); dialog->user_action = CKR_Highlight; } static void action_show_unmatch_line(Fl_Widget *w, void *data) { UI_Check_Tags *dialog = (UI_Check_Tags *)data; Tags_ShowUnmatchedLineDefs(); dialog->user_action = CKR_Highlight; } static void action_show_missing_tag(Fl_Widget *w, void *data) { UI_Check_Tags *dialog = (UI_Check_Tags *)data; Tags_ShowMissingTags(); dialog->user_action = CKR_Highlight; } }; check_result_e CHECK_Tags(int min_severity) { UI_Check_Tags *dialog = new UI_Check_Tags(min_severity > 0); selection_c sel; for (;;) { Tags_FindMissingTags(sel); if (sel.empty()) dialog->AddLine("No linedefs missing a needed tag"); else { sprintf(check_buffer, "%d linedefs missing a needed tag", sel.count_obj()); dialog->AddLine(check_buffer, 2, 320, "Show", &UI_Check_Tags::action_show_missing_tag); } Tags_FindUnmatchedLineDefs(sel); if (sel.empty()) dialog->AddLine("No tagged linedefs w/o a matching sector"); else { sprintf(check_buffer, "%d tagged linedefs w/o a matching sector", sel.count_obj()); dialog->AddLine(check_buffer, 2, 350, "Show", &UI_Check_Tags::action_show_unmatch_line); } Tags_FindUnmatchedSectors(sel); if (sel.empty()) dialog->AddLine("No tagged sectors w/o a matching linedef"); else { sprintf(check_buffer, "%d tagged sectors w/o a matching linedef", sel.count_obj()); dialog->AddLine(check_buffer, 1, 350, "Show", &UI_Check_Tags::action_show_unmatch_sec); } int min_tag, max_tag; Tags_UsedRange(&min_tag, &max_tag); if (max_tag <= 0) dialog->AddLine("No tags are in use"); else { sprintf(check_buffer, "Lowest tag: %d Highest tag: %d", min_tag, max_tag); dialog->AddLine(check_buffer); } if ((edit.mode == OBJ_LINEDEFS || edit.mode == OBJ_SECTORS) && edit.Selected->notempty()) { dialog->fresh_tag = max_tag + 1; dialog->AddGap(10); dialog->AddLine("Apply fresh tag to selection :", 0, 215, "Apply", &UI_Check_Tags::action_fresh_tag); } if (dialog->WorstSeverity() < min_severity) { delete dialog; return CKR_OK; } check_result_e result = dialog->Run(); if (result == CKR_TookAction) { // repeat the tests dialog->Reset(); continue; } delete dialog; return result; } } //------------------------------------------------------------------------ static void bump_unknown_name(std::map& list, const char *name) { std::string t_name = name; int count = 0; if (list.find(t_name) != list.end()) count = list[t_name]; list[t_name] = count + 1; } static inline bool is_missing(const char *tex) { return (tex[0] == 0 || tex[0] == '-'); } void Textures_FindMissing(selection_c& lines) { lines.change_type(OBJ_LINEDEFS); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->right < 0) continue; if (L->OneSided()) { if (is_missing(L->Right()->MidTex())) lines.set(n); } else // Two Sided { const Sector *front = L->Right()->SecRef(); const Sector *back = L->Left() ->SecRef(); if (front->floorh < back->floorh && is_missing(L->Right()->LowerTex())) lines.set(n); if (back->floorh < front->floorh && is_missing(L->Left()->LowerTex())) lines.set(n); // missing uppers are OK when between two sky ceilings if (is_sky(front->CeilTex()) && is_sky(back->CeilTex())) continue; if (front->ceilh > back->ceilh && is_missing(L->Right()->UpperTex())) lines.set(n); if (back->ceilh > front->ceilh && is_missing(L->Left()->UpperTex())) lines.set(n); } } } void Textures_ShowMissing() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); Textures_FindMissing(*edit.Selected); GoToErrors(); } void Textures_FixMissing() { int new_upper = BA_InternaliseString(default_upper_tex); int new_mid = BA_InternaliseString(default_mid_tex); int new_lower = BA_InternaliseString(default_lower_tex); BA_Begin(); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->right < 0) continue; if (L->OneSided()) { if (is_missing(L->Right()->MidTex())) BA_ChangeSD(L->right, SideDef::F_MID_TEX, new_mid); } else // Two Sided { const Sector *front = L->Right()->SecRef(); const Sector *back = L->Left() ->SecRef(); if (front->floorh < back->floorh && is_missing(L->Right()->LowerTex())) BA_ChangeSD(L->right, SideDef::F_LOWER_TEX, new_lower); if (back->floorh < front->floorh && is_missing(L->Left()->LowerTex())) BA_ChangeSD(L->left, SideDef::F_LOWER_TEX, new_lower); // missing uppers are OK when between two sky ceilings if (is_sky(front->CeilTex()) && is_sky(back->CeilTex())) continue; if (front->ceilh > back->ceilh && is_missing(L->Right()->UpperTex())) BA_ChangeSD(L->right, SideDef::F_UPPER_TEX, new_upper); if (back->ceilh > front->ceilh && is_missing(L->Left()->UpperTex())) BA_ChangeSD(L->left, SideDef::F_UPPER_TEX, new_upper); } } BA_End(); } static bool is_transparent(const char *tex) { // ignore lack of texture here if (tex[0] == 0 || tex[0] == '-') return false; Img_c *img = W_GetTexture(tex); if (! img) return false; // note : this is slow return img->has_transparent(); } static int check_transparent(const char *tex, std::map& names) { if (is_transparent(tex)) { bump_unknown_name(names, tex); return 1; } return 0; } void Textures_FindTransparent(selection_c& lines, std::map& names) { lines.change_type(OBJ_LINEDEFS); names.clear(); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->right < 0) continue; if (L->OneSided()) { if (check_transparent(L->Right()->MidTex(), names)) lines.set(n); } else // Two Sided { // note : plain OR operator here to check all parts (do NOT want short-circuit) if (check_transparent(L->Right()->LowerTex(), names) | check_transparent(L->Right()->UpperTex(), names) | check_transparent(L-> Left()->LowerTex(), names) | check_transparent(L-> Left()->UpperTex(), names)) { lines.set(n); } } } } void Textures_ShowTransparent() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); std::map names; Textures_FindTransparent(*edit.Selected, names); GoToErrors(); } void Textures_FixTransparent() { int new_upper = BA_InternaliseString(default_upper_tex); int new_mid = BA_InternaliseString(default_mid_tex); int new_lower = BA_InternaliseString(default_lower_tex); BA_Begin(); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->right < 0) continue; if (L->OneSided()) { if (is_transparent(L->Right()->MidTex())) BA_ChangeSD(L->right, SideDef::F_MID_TEX, new_mid); } else // Two Sided { if (is_transparent(L->Left()->LowerTex())) BA_ChangeSD(L->left, SideDef::F_LOWER_TEX, new_lower); if (is_transparent(L->Left()->UpperTex())) BA_ChangeSD(L->left, SideDef::F_UPPER_TEX, new_upper); if (is_transparent(L->Right()->LowerTex())) BA_ChangeSD(L->right, SideDef::F_LOWER_TEX, new_lower); if (is_transparent(L->Right()->UpperTex())) BA_ChangeSD(L->right, SideDef::F_UPPER_TEX, new_upper); } } BA_End(); } void Textures_LogTransparent() { selection_c sel; std::map names; std::map::iterator IT; Textures_FindTransparent(sel, names); LogPrintf("\n"); LogPrintf("Transparent textures on solid walls:\n"); LogPrintf("{\n"); for (IT = names.begin() ; IT != names.end() ; IT++) LogPrintf(" %-9s x %d\n", IT->first.c_str(), IT->second); LogPrintf("}\n"); LogViewer_Open(); } static bool is_medusa(const char *tex) { // ignore lack of texture here if (tex[0] == 0 || tex[0] == '-') return false; return W_TextureCausesMedusa(tex); } static int check_medusa(const char *tex, std::map& names) { if (is_medusa(tex)) { bump_unknown_name(names, tex); return 1; } return 0; } void Textures_FindMedusa(selection_c& lines, std::map& names) { lines.change_type(OBJ_LINEDEFS); names.clear(); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->right < 0 || L->left < 0) continue; if (check_medusa(L->Right()->MidTex(), names) | /* plain OR */ check_medusa(L-> Left()->MidTex(), names)) { lines.set(n); } } } void Textures_ShowMedusa() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); std::map names; Textures_FindMedusa(*edit.Selected, names); GoToErrors(); } void Textures_RemoveMedusa() { int null_tex = BA_InternaliseString("-"); std::map names; BA_Begin(); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; if (L->right < 0 || L->left < 0) continue; if (check_medusa(L->Right()->MidTex(), names)) { BA_ChangeSD(L->right, SideDef::F_MID_TEX, null_tex); } if (check_medusa(L-> Left()->MidTex(), names)) { BA_ChangeSD(L->left, SideDef::F_MID_TEX, null_tex); } } BA_End(); } void Textures_LogMedusa() { selection_c sel; std::map names; std::map::iterator IT; Textures_FindMedusa(sel, names); LogPrintf("\n"); LogPrintf("Medusa effect textures:\n"); LogPrintf("{\n"); for (IT = names.begin() ; IT != names.end() ; IT++) LogPrintf(" %-9s x %d\n", IT->first.c_str(), IT->second); LogPrintf("}\n"); LogViewer_Open(); } // FIXME: is_unknown_tex (allow '-' and '#....') void Textures_FindUnknownTex(selection_c& lines, std::map& names) { lines.change_type(OBJ_LINEDEFS); names.clear(); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; for (int side = 0 ; side < 2 ; side++) { const SideDef *SD = side ? L->Left() : L->Right(); if (! SD) continue; for (int part = 0 ; part < 3 ; part++) { const char *tex = (part == 0) ? SD->LowerTex() : (part == 1) ? SD->UpperTex() : SD->MidTex(); if (strcmp(tex, "-") == 0) continue; // textures beginning with '#' are special if (tex[0] == '#') continue; if (! W_TextureExists(tex)) { bump_unknown_name(names, tex); lines.set(n); } } } } } void Textures_FindUnknownFlat(selection_c& secs, std::map& names) { secs.change_type(OBJ_SECTORS); names.clear(); for (int s = 0 ; s < NumSectors ; s++) { const Sector *S = Sectors[s]; for (int part = 0 ; part < 2 ; part++) { const char *flat = part ? S->CeilTex() : S->FloorTex(); if (! W_FlatExists(flat)) { bump_unknown_name(names, flat); secs.set(s); } } } } void Textures_ShowUnknownTex() { if (edit.mode != OBJ_LINEDEFS) Editor_ChangeMode('l'); std::map names; Textures_FindUnknownTex(*edit.Selected, names); GoToErrors(); } void Textures_ShowUnknownFlat() { if (edit.mode != OBJ_SECTORS) Editor_ChangeMode('s'); std::map names; Textures_FindUnknownFlat(*edit.Selected, names); GoToErrors(); } void Textures_LogUnknown(bool do_flat) { selection_c sel; std::map names; std::map::iterator IT; if (do_flat) Textures_FindUnknownFlat(sel, names); else Textures_FindUnknownTex(sel, names); LogPrintf("\n"); LogPrintf("Unknown %s:\n", do_flat ? "Flats" : "Textures"); LogPrintf("{\n"); for (IT = names.begin() ; IT != names.end() ; IT++) LogPrintf(" %-9s x %d\n", IT->first.c_str(), IT->second); LogPrintf("}\n"); LogViewer_Open(); } void Textures_FixUnknownTex() { int new_upper = BA_InternaliseString(default_upper_tex); int new_mid = BA_InternaliseString(default_mid_tex); int new_lower = BA_InternaliseString(default_lower_tex); int null_tex = BA_InternaliseString("-"); BA_Begin(); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; bool two_sided = L->TwoSided(); for (int side = 0 ; side < 2 ; side++) { int sd_num = side ? L->left : L->right; if (sd_num < 0) continue; const SideDef *SD = SideDefs[sd_num]; if (! W_TextureExists(SD->LowerTex())) BA_ChangeSD(sd_num, SideDef::F_LOWER_TEX, new_lower); if (! W_TextureExists(SD->UpperTex())) BA_ChangeSD(sd_num, SideDef::F_UPPER_TEX, new_upper); if (! W_TextureExists(SD->MidTex())) BA_ChangeSD(sd_num, SideDef::F_MID_TEX, two_sided ? null_tex : new_mid); } } BA_End(); } void Textures_FixUnknownFlat() { int new_floor = BA_InternaliseString(default_floor_tex); int new_ceil = BA_InternaliseString(default_ceil_tex); BA_Begin(); for (int s = 0 ; s < NumSectors ; s++) { const Sector *S = Sectors[s]; if (! W_FlatExists(S->FloorTex())) BA_ChangeSEC(s, Sector::F_FLOOR_TEX, new_floor); if (! W_FlatExists(S->CeilTex())) BA_ChangeSEC(s, Sector::F_CEIL_TEX, new_ceil); } BA_End(); } //------------------------------------------------------------------------ class UI_Check_Textures : public UI_Check_base { public: UI_Check_Textures(bool all_mode) : UI_Check_base(565, 286, all_mode, "Check : Textures", "Texture test results") { } public: static void action_show_unk_tex(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_ShowUnknownTex(); dialog->user_action = CKR_Highlight; } static void action_log_unk_tex(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_LogUnknown(false); dialog->user_action = CKR_Highlight; } static void action_fix_unk_tex(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_FixUnknownTex(); dialog->user_action = CKR_TookAction; } static void action_show_unk_flat(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_ShowUnknownFlat(); dialog->user_action = CKR_Highlight; } static void action_log_unk_flat(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_LogUnknown(true); dialog->user_action = CKR_Highlight; } static void action_fix_unk_flat(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_FixUnknownFlat(); dialog->user_action = CKR_TookAction; } static void action_show_missing(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_ShowMissing(); dialog->user_action = CKR_Highlight; } static void action_fix_missing(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_FixMissing(); dialog->user_action = CKR_TookAction; } static void action_show_transparent(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_ShowTransparent(); dialog->user_action = CKR_Highlight; } static void action_fix_transparent(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_FixTransparent(); dialog->user_action = CKR_TookAction; } static void action_log_transparent(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_LogTransparent(); dialog->user_action = CKR_Highlight; } static void action_show_medusa(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_ShowMedusa(); dialog->user_action = CKR_Highlight; } static void action_remove_medusa(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_RemoveMedusa(); dialog->user_action = CKR_TookAction; } static void action_log_medusa(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_LogMedusa(); dialog->user_action = CKR_Highlight; } }; check_result_e CHECK_Textures(int min_severity) { UI_Check_Textures *dialog = new UI_Check_Textures(min_severity > 0); selection_c sel; std::map names; for (;;) { Textures_FindUnknownTex(sel, names); if (sel.empty()) dialog->AddLine("No unknown textures"); else { sprintf(check_buffer, "%d unknown textures", (int)names.size()); dialog->AddLine(check_buffer, 2, 200, "Show", &UI_Check_Textures::action_show_unk_tex, "Log", &UI_Check_Textures::action_log_unk_tex, "Fix", &UI_Check_Textures::action_fix_unk_tex); } Textures_FindUnknownFlat(sel, names); if (sel.empty()) dialog->AddLine("No unknown flats"); else { sprintf(check_buffer, "%d unknown flats", (int)names.size()); dialog->AddLine(check_buffer, 2, 200, "Show", &UI_Check_Textures::action_show_unk_flat, "Log", &UI_Check_Textures::action_log_unk_flat, "Fix", &UI_Check_Textures::action_fix_unk_flat); } if (game_info.medusa_bug) { Textures_FindMedusa(sel, names); if (sel.empty()) dialog->AddLine("No textures causing Medusa Effect"); else { sprintf(check_buffer, "%d Medusa textures", (int)names.size()); dialog->AddLine(check_buffer, 2, 200, "Show", &UI_Check_Textures::action_show_medusa, "Log", &UI_Check_Textures::action_log_medusa, "Fix", &UI_Check_Textures::action_remove_medusa); } } dialog->AddGap(10); Textures_FindMissing(sel); if (sel.empty()) dialog->AddLine("No missing textures on walls"); else { sprintf(check_buffer, "%d missing textures on walls", sel.count_obj()); dialog->AddLine(check_buffer, 1, 270, "Show", &UI_Check_Textures::action_show_missing, "Fix", &UI_Check_Textures::action_fix_missing); } Textures_FindTransparent(sel, names); if (sel.empty()) dialog->AddLine("No transparent textures on solids"); else { sprintf(check_buffer, "%d transparent textures on solids", sel.count_obj()); dialog->AddLine(check_buffer, 1, 270, "Show", &UI_Check_Textures::action_show_transparent, "Fix", &UI_Check_Textures::action_fix_transparent, "Log", &UI_Check_Textures::action_log_transparent); } if (dialog->WorstSeverity() < min_severity) { delete dialog; return CKR_OK; } check_result_e result = dialog->Run(); if (result == CKR_TookAction) { // repeat the tests dialog->Reset(); continue; } delete dialog; return result; } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/lib_adler.cc0000644000175100017510000000511412647061302016503 0ustar aaptedaapted//------------------------------------------------------------------------ // ADLER-32 CHECKSUM //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2012 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 is the Adler-32 algorithm as described in RFC-1950. // // The 'extra' field is my own adaptation to provide an extra 32 bits // of checksum. This should make collisions a lot less likely (though // how much remains to be seen -- definitely not the full 32 bits!). // //------------------------------------------------------------------------ #include "main.h" #include "lib_adler.h" // ---- Primitive routines ---- crc32_c& crc32_c::operator+= (u8_t data) { u32_t s1 = raw & 0xFFFF; u32_t s2 = (raw >> 16) & 0xFFFF; s1 = (s1 + data) % 65521; s2 = (s2 + s1) % 65521; raw = (s2 << 16) | s1; extra += s2; // modulo the extra value by a large prime number if (extra >= 0xFFFEFFF9) extra -= 0xFFFEFFF9; return *this; } crc32_c& crc32_c::AddBlock(const u8_t *data, int len) { u32_t s1 = raw & 0xFFFF; u32_t s2 = (raw >> 16) & 0xFFFF; for (; len > 0; data++, len--) { s1 = (s1 + *data) % 65521; s2 = (s2 + s1) % 65521; extra += s2; if (extra >= 0xFFFEFFF9) extra -= 0xFFFEFFF9; } raw = (s2 << 16) | s1; return *this; } // ---- Non-primitive routines ---- crc32_c& crc32_c::operator+= (u16_t value) { *this += (u8_t) (value >> 8); *this += (u8_t) (value); return *this; } crc32_c& crc32_c::operator+= (u32_t value) { *this += (u8_t) (value >> 24); *this += (u8_t) (value >> 16); *this += (u8_t) (value >> 8); *this += (u8_t) (value); return *this; } crc32_c& crc32_c::operator+= (float value) { bool neg = (value < 0.0f); value = (float)fabs(value); int exp; u32_t mant = (u32_t) (ldexp(frexp(value, &exp), 30)); *this += (u8_t) (neg ? '-' : '+'); *this += (u32_t) exp; *this += mant; return *this; } crc32_c& crc32_c::AddCStr(const char *str) { return AddBlock((const u8_t *) str, (int)strlen(str)); } eureka-1.11-source/src/levels.cc0000644000175100017510000004032112651015755016065 0ustar aaptedaapted//------------------------------------------------------------------------ // LEVEL MISC STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "m_bitvec.h" #include "m_game.h" #include "editloop.h" #include "levels.h" #include "e_path.h" #include "e_things.h" #include "w_rawdef.h" #include "x_hover.h" #include "ui_window.h" int Map_bound_x1 = 32767; /* minimum X value of map */ int Map_bound_y1 = 32767; /* minimum Y value of map */ int Map_bound_x2 = -32767; /* maximum X value of map */ int Map_bound_y2 = -32767; /* maximum Y value of map */ int MadeChanges; static bool recalc_map_bounds; static int new_vertex_minimum; static int moved_vertex_count; static selection_c * last_Sel; void MarkChanges() { MadeChanges = 1; UpdateHighlight(); RedrawMap(); } void UpdateLevelBounds(int start_vert) { for (int i = start_vert ; i < NumVertices ; i++) { const Vertex * V = Vertices[i]; if (V->x < Map_bound_x1) Map_bound_x1 = V->x; if (V->y < Map_bound_y1) Map_bound_y1 = V->y; if (V->x > Map_bound_x2) Map_bound_x2 = V->x; if (V->y > Map_bound_y2) Map_bound_y2 = V->y; } } void CalculateLevelBounds() { if (NumVertices == 0) { Map_bound_x1 = Map_bound_x2 = 0; Map_bound_y1 = Map_bound_y2 = 0; return; } Map_bound_x1 = 999999; Map_bound_x2 = -999999; Map_bound_y1 = 999999; Map_bound_y2 = -999999; UpdateLevelBounds(0); } void MapStuff_NotifyBegin() { recalc_map_bounds = false; new_vertex_minimum = -1; moved_vertex_count = 0; } void MapStuff_NotifyInsert(obj_type_e type, int objnum) { if (type == OBJ_VERTICES) { if (new_vertex_minimum < 0 || objnum < new_vertex_minimum) new_vertex_minimum = objnum; } } void MapStuff_NotifyDelete(obj_type_e type, int objnum) { if (type == OBJ_VERTICES) { recalc_map_bounds = true; if (edit.action == ACT_DRAW_LINE && edit.drawing_from == objnum) { Editor_ClearAction(); } } } void MapStuff_NotifyChange(obj_type_e type, int objnum, int field) { if (type == OBJ_VERTICES) { // NOTE: for performance reasons we don't recalculate the // map bounds when only moving a few vertices. moved_vertex_count++; const Vertex * V = Vertices[objnum]; if (V->x < Map_bound_x1) Map_bound_x1 = V->x; if (V->y < Map_bound_y1) Map_bound_y1 = V->y; if (V->x > Map_bound_x2) Map_bound_x2 = V->x; if (V->y > Map_bound_y2) Map_bound_y2 = V->y; } } void MapStuff_NotifyEnd() { if (recalc_map_bounds || moved_vertex_count > 10) // TODO: CONFIG { CalculateLevelBounds(); } else if (new_vertex_minimum >= 0) { UpdateLevelBounds(new_vertex_minimum); } } //------------------------------------------------------------------------ // ObjectBox Notification handling //------------------------------------------------------------------------ static bool invalidated_totals; static bool invalidated_panel_obj; static bool changed_panel_obj; static bool changed_recent_list; void ObjectBox_NotifyBegin() { invalidated_totals = false; invalidated_panel_obj = false; changed_panel_obj = false; changed_recent_list = false; } void ObjectBox_NotifyInsert(obj_type_e type, int objnum) { invalidated_totals = true; if (type != edit.mode) return; if (objnum > main_win->GetPanelObjNum()) return; invalidated_panel_obj = true; } void ObjectBox_NotifyDelete(obj_type_e type, int objnum) { invalidated_totals = true; if (type != edit.mode) return; if (objnum > main_win->GetPanelObjNum()) return; invalidated_panel_obj = true; } void ObjectBox_NotifyChange(obj_type_e type, int objnum, int field) { if (type != edit.mode) return; if (objnum != main_win->GetPanelObjNum()) return; changed_panel_obj = true; } void ObjectBox_NotifyEnd() { if (invalidated_totals) main_win->UpdateTotals(); if (invalidated_panel_obj) { main_win->InvalidatePanelObj(); } else if (changed_panel_obj) { main_win->UpdatePanelObj(); } if (changed_recent_list) main_win->browser->RecentUpdate(); } //------------------------------------------------------------------------ // Selection Notification, ETC //------------------------------------------------------------------------ static bool invalidated_selection; static bool invalidated_last_sel; void Selection_NotifyBegin() { invalidated_selection = false; invalidated_last_sel = false; } void Selection_NotifyInsert(obj_type_e type, int objnum) { if (type == edit.Selected->what_type() && objnum <= edit.Selected->max_obj()) { invalidated_selection = true; } if (last_Sel && type == last_Sel->what_type() && objnum <= last_Sel->max_obj()) { invalidated_last_sel = true; } } void Selection_NotifyDelete(obj_type_e type, int objnum) { if (objnum <= edit.Selected->max_obj()) { invalidated_selection = true; } if (last_Sel && type == last_Sel->what_type() && objnum <= last_Sel->max_obj()) { invalidated_last_sel = true; } } void Selection_NotifyChange(obj_type_e type, int objnum, int field) { // field changes never affect the current selection } void Selection_NotifyEnd() { if (invalidated_selection) { // this clears AND RESIZES the selection_c object edit.Selected->change_type(edit.mode); } if (invalidated_last_sel) Selection_InvalidateLast(); } // // list the contents of a selection (for debugging) // void DumpSelection(selection_c * list) { SYS_ASSERT(list); printf("Selection:"); selection_iterator_c it; for (list->begin(&it); ! it.at_end(); ++it) printf(" %d", *it); printf("\n"); } void ConvertSelection(selection_c * src, selection_c * dest) { if (src->what_type() == dest->what_type()) { dest->merge(*src); return; } if (src->what_type() == OBJ_SECTORS && dest->what_type() == OBJ_THINGS) { // FIXME: get bbox of selection, skip things outside it for (int t = 0 ; t < NumThings ; t++) { const Thing *T = Things[t]; // if (! thing_touches_bbox(T->x, T->y, 128, bbox)) // continue; Objid obj; GetNearObject(obj, OBJ_SECTORS, T->x, T->y); if (! obj.is_nil() && src->get(obj.num)) { dest->set(t); } } return; } if (src->what_type() == OBJ_SECTORS && dest->what_type() == OBJ_LINEDEFS) { for (int l = 0 ; l < NumLineDefs ; l++) { const LineDef *L = LineDefs[l]; if ( (L->Right() && src->get(L->Right()->sector)) || (L->Left() && src->get(L->Left()->sector)) ) { dest->set(l); } } return; } if (src->what_type() == OBJ_SECTORS && dest->what_type() == OBJ_VERTICES) { for (int l = 0 ; l < NumLineDefs ; l++) { const LineDef *L = LineDefs[l]; if ( (L->Right() && src->get(L->Right()->sector)) || (L->Left() && src->get(L->Left()->sector)) ) { dest->set(L->start); dest->set(L->end); } } return; } if (src->what_type() == OBJ_LINEDEFS && dest->what_type() == OBJ_SIDEDEFS) { selection_iterator_c it; for (src->begin(&it); ! it.at_end(); ++it) { const LineDef *L = LineDefs[*it]; if (L->Right()) dest->set(L->right); if (L->Left()) dest->set(L->left); } return; } if (src->what_type() == OBJ_SECTORS && dest->what_type() == OBJ_SIDEDEFS) { for (int n = 0 ; n < NumSideDefs ; n++) { const SideDef * SD = SideDefs[n]; if (src->get(SD->sector)) dest->set(n); } return; } if (src->what_type() == OBJ_LINEDEFS && dest->what_type() == OBJ_VERTICES) { selection_iterator_c it; for (src->begin(&it); ! it.at_end(); ++it) { const LineDef *L = LineDefs[*it]; dest->set(L->start); dest->set(L->end); } return; } if (src->what_type() == OBJ_VERTICES && dest->what_type() == OBJ_LINEDEFS) { // select all linedefs that have both ends selected for (int l = 0 ; l < NumLineDefs ; l++) { const LineDef *L = LineDefs[l]; if (src->get(L->start) && src->get(L->end)) { dest->set(l); } } } // remaining conversions are L->S and V->S if (dest->what_type() != OBJ_SECTORS) return; if (src->what_type() != OBJ_LINEDEFS && src->what_type() != OBJ_VERTICES) return; // step 1: select all sectors (except empty ones) int l; for (l = 0 ; l < NumLineDefs ; l++) { const LineDef *L = LineDefs[l]; if (L->Right()) dest->set(L->Right()->sector); if (L->Left()) dest->set(L->Left()->sector); } // step 2: unselect any sectors if a component is not selected for (l = 0 ; l < NumLineDefs ; l++) { const LineDef *L = LineDefs[l]; if (src->what_type() == OBJ_VERTICES) { if (src->get(L->start) && src->get(L->end)) continue; } else { if (src->get(l)) continue; } if (L->Right()) dest->clear(L->Right()->sector); if (L->Left()) dest->clear(L->Left()->sector); } } // // Return the line to show in the LineDef panel from the selection. // When the selection is a mix of one-sided and two-sided lines, then // we want the first TWO-SIDED line. // // NOTE: this is slow, as it may need to search the whole list. // int Selection_FirstLine(selection_c *list) { selection_iterator_c it; for (list->begin(&it); ! it.at_end(); ++it) { const LineDef *L = LineDefs[*it]; if (L->TwoSided()) return *it; } // return first entry (a one-sided line) return list->find_first(); } /* select all objects inside a given box */ void SelectObjectsInBox(selection_c *list, int objtype, int x1, int y1, int x2, int y2) { if (x2 < x1) { int tmp = x1; x1 = x2; x2 = tmp; } if (y2 < y1) { int tmp = y1; y1 = y2; y2 = tmp; } switch (objtype) { case OBJ_THINGS: for (int n = 0 ; n < NumThings ; n++) { const Thing *T = Things[n]; if (x1 <= T->x && T->x <= x2 && y1 <= T->y && T->y <= y2) { list->toggle(n); } } break; case OBJ_VERTICES: for (int n = 0 ; n < NumVertices ; n++) { const Vertex *V = Vertices[n]; if (x1 <= V->x && V->x <= x2 && y1 <= V->y && V->y <= y2) { list->toggle(n); } } break; case OBJ_LINEDEFS: for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; /* the two ends of the line must be in the box */ if (x1 <= L->Start()->x && L->Start()->x <= x2 && y1 <= L->Start()->y && L->Start()->y <= y2 && x1 <= L->End()->x && L->End()->x <= x2 && y1 <= L->End()->y && L->End()->y <= y2) { list->toggle(n); } } break; case OBJ_SECTORS: { selection_c in_sectors(OBJ_SECTORS); selection_c out_sectors(OBJ_SECTORS); for (int n = 0 ; n < NumLineDefs ; n++) { const LineDef *L = LineDefs[n]; // Get the numbers of the sectors on both sides of the linedef int s1 = L->Right() ? L->Right()->sector : -1; int s2 = L->Left( ) ? L->Left() ->sector : -1; if (x1 <= L->Start()->x && L->Start()->x <= x2 && y1 <= L->Start()->y && L->Start()->y <= y2 && x1 <= L->End()->x && L->End()->x <= x2 && y1 <= L->End()->y && L->End()->y <= y2) { if (s1 >= 0) in_sectors.set(s1); if (s2 >= 0) in_sectors.set(s2); } else { if (s1 >= 0) out_sectors.set(s1); if (s2 >= 0) out_sectors.set(s2); } } for (int i = 0 ; i < NumSectors ; i++) if (in_sectors.get(i) && ! out_sectors.get(i)) list->toggle(i); break; } } } void Selection_InvalidateLast() { delete last_Sel; last_Sel = NULL; } void Selection_Push() { if (edit.Selected->empty()) return; if (last_Sel && last_Sel->test_equal(*edit.Selected)) return; // OK copy it if (last_Sel) delete last_Sel; last_Sel = new selection_c(edit.Selected->what_type()); last_Sel->merge(*edit.Selected); } void Selection_Clear(bool no_save) { if (! no_save) Selection_Push(); // this always clear it edit.Selected->change_type(edit.mode); edit.error_mode = false; RedrawMap(); } void Selection_Validate() { int num_obj = NumObjects(edit.mode); if (edit.Selected->max_obj() >= num_obj) { edit.Selected->frob_range(num_obj, edit.Selected->max_obj(), BOP_REMOVE); Beep("BUG: invalid selection"); } } void CMD_LastSelection(void) { if (! last_Sel) { Beep("No last selection (or was invalidated)"); return; } bool changed_mode = false; if (last_Sel->what_type() != edit.mode) { changed_mode = true; Editor_ChangeMode_Raw(last_Sel->what_type()); main_win->NewEditMode(edit.mode); } std::swap(last_Sel, edit.Selected); // ensure everything is kosher Selection_Validate(); if (changed_mode) GoToSelection(); UpdateHighlight(); RedrawMap(); } //------------------------------------------------------------------------ // RECENTLY USED TEXTURES (etc) //------------------------------------------------------------------------ // the containers for the textures (etc) Recently_used recent_textures; Recently_used recent_flats; Recently_used recent_things; Recently_used::Recently_used() : size(0), keep_num(RECENTLY_USED_MAX - 2) { memset(&name_set, 0, sizeof(name_set)); } Recently_used::~Recently_used() { for (int i = 0 ; i < size ; i++) { StringFree(name_set[i]); name_set[i] = NULL; } } int Recently_used::find(const char *name) { for (int k = 0 ; k < size ; k++) if (y_stricmp(name_set[k], name) == 0) return k; return -1; // not found } int Recently_used::find_number(int val) { char buffer[64]; sprintf(buffer, "%d", val); return find(buffer); } void Recently_used::insert(const char *name) { // ignore '-' texture if (name[0] == '-') return; int idx = find(name); // optimisation if (idx >= 0 && idx < 4) return; if (idx >= 0) erase(idx); push_front(name); // mark browser for later update // [ this method may be called very often by basis, too expensive to // update the browser here ] changed_recent_list = true; } void Recently_used::insert_number(int val) { char buffer[64]; sprintf(buffer, "%d", val); insert(buffer); } void Recently_used::erase(int index) { SYS_ASSERT(0 <= index && index < size); StringFree(name_set[index]); size--; for ( ; index < size ; index++) { name_set[index] = name_set[index + 1]; } name_set[index] = NULL; } void Recently_used::push_front(const char *name) { if (size >= keep_num) { erase(keep_num - 1); } // shift elements up for (int k = size - 1 ; k >= 0 ; k--) { name_set[k + 1] = name_set[k]; } name_set[0] = StringDup(name); size++; } void Recently_used::clear() { size = 0; memset(&name_set, 0, sizeof(name_set)); } void RecUsed_ClearAll() { recent_textures.clear(); recent_flats .clear(); recent_things .clear(); if (main_win) main_win->browser->RecentUpdate(); } /* --- Save and Restore --- */ void Recently_used::WriteUser(FILE *fp, char letter) { for (int i = 0 ; i < size ; i++) { fprintf(fp, "recent_used %c \"%s\"\n", letter, StringTidy(name_set[i])); } } void RecUsed_WriteUser(FILE *fp) { fprintf(fp, "\n"); fprintf(fp, "recent_used clear\n"); recent_textures.WriteUser(fp, 'T'); recent_flats .WriteUser(fp, 'F'); recent_things .WriteUser(fp, 'O'); } bool RecUsed_ParseUser(const char ** tokens, int num_tok) { if (strcmp(tokens[0], "recent_used") != 0 || num_tok < 2) return false; if (strcmp(tokens[1], "clear") == 0) { RecUsed_ClearAll(); return true; } // syntax is: recent_used if (num_tok < 3) return false; switch (tokens[1][0]) { case 'T': recent_textures.insert(tokens[2]); break; case 'F': recent_flats.insert(tokens[2]); break; case 'O': recent_things.insert(tokens[2]); break; default: // ignore it break; } if (main_win) main_win->browser->RecentUpdate(); return true; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/w_wad.h0000644000175100017510000002206212647061302015532 0ustar aaptedaapted//------------------------------------------------------------------------ // WAD Reading / Writing //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2015 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_W_WAD_H__ #define __EUREKA_W_WAD_H__ class Wad_file; class Texture_info; class Lump_c { friend class Wad_file; private: Wad_file *parent; const char *name; int l_start; int l_length; // constructor is private Lump_c(Wad_file *_par, const char *_nam, int _start, int _len); Lump_c(Wad_file *_par, const struct raw_wad_entry_s *entry); void MakeEntry(struct raw_wad_entry_s *entry); public: ~Lump_c(); const char *Name() const { return name; } int Length() const { return l_length; } // do not call this directly, use Wad_file::RenameLump() void Rename(const char *new_name); // attempt to seek to a position within the lump (default is // the beginning). Returns true if OK, false on error. bool Seek(int offset = 0); // read some data from the lump, returning true if OK. bool Read(void *data, int len); // read a line of text, returns true if OK, false on EOF bool GetLine(char *buffer, size_t buf_size); // write some data to the lump. Only the lump which had just // been created with Wad_file::AddLump() can be written to. bool Write(void *data, int len); // write some text to the lump void Printf(const char *msg, ...); // mark the lump as finished (after writing it). bool Finish(); // predicate for std::sort() struct offset_CMP_pred { inline bool operator() (const Lump_c * A, const Lump_c * B) const { return A->l_start < B->l_start; } }; private: // deliberately don't implement these Lump_c(const Lump_c& other); Lump_c& operator= (const Lump_c& other); }; //------------------------------------------------------------------------ class Wad_file { friend class Lump_c; friend void W_LoadFlats(); private: const char *filename; char mode; // mode value passed to ::Open() FILE * fp; char kind; // 'P' for PWAD, 'I' for IWAD // zero means "currently unknown", which only occurs after a // call to BeginWrite() and before any call to AddLump() or // the finalizing EndWrite(). int total_size; std::vector directory; int dir_start; int dir_count; u32_t dir_crc; // these are lump indices (into 'directory' vector) std::vector levels; std::vector patches; std::vector sprites; std::vector flats; Texture_info *tex_info; bool begun_write; int begun_max_size; // when >= 0, the next added lump is placed _before_ this int insert_point; // constructor is private Wad_file(const char *_name, char _mode, FILE * _fp); public: ~Wad_file(); // open a wad file. // // mode is similar to the fopen() function: // 'r' opens the wad for reading ONLY // 'a' opens the wad for appending (read and write) // 'w' opens the wad for writing (i.e. create it) // // Note: if 'a' is used and the file is read-only, it will be // silently opened in 'r' mode instead. // static Wad_file * Open(const char *filename, char mode = 'a'); // check the given wad file exists and is a WAD file static bool Validate(const char *filename); const char *PathName() const { return filename; } bool IsReadOnly() const { return mode == 'r'; } int TotalSize() const { return total_size; } short NumLumps() const { return (short)directory.size(); } Lump_c * GetLump(short index); Lump_c * FindLump(const char *name); Lump_c * FindLumpInLevel(const char *name, short level); short FindLumpNum(const char *name); // these all return a lump index short FindLevel(const char *name); short FindLevelByNumber(int number); short FindFirstLevel(); Lump_c * FindLumpInNamespace(const char *name, char group); short NumLevels() const { return (short)levels.size(); } short GetLevel(short index); short FindLevel_Raw(const char *name); // returns level index map_format_e LevelFormat(short lump_index); // check whether another program has modified this WAD, and return // either true or false. We test for change in file size, change // in directory size or location, and directory contents (CRC). bool WasExternallyModified(); // backup the current wad into the given filename. // returns true if successful, false on error. bool Backup(const char *filename); // all changes to the wad must occur between calls to BeginWrite() // and EndWrite() methods. void BeginWrite(); void EndWrite(); // change name of a lump (can be a level marker too) void RenameLump(short index, const char *new_name); // remove the given lump(s) // this will change index numbers on existing lumps // (previous results of FindLumpNum or GetLevel are invalidated). void RemoveLumps(short index, short count = 1); // this removes the level marker PLUS all associated level lumps // which follow it. 'index' is a lump number (e.g. from FindLevel) void RemoveLevel(short index); // insert a new lump. // The second form is for a level marker. // The 'max_size' parameter (if >= 0) specifies the most data // you will write into the lump -- writing more will corrupt // something else in the WAD. Lump_c * AddLump (const char *name, int max_size = -1); Lump_c * AddLevel(const char *name, int max_size = -1); // set the insertion point -- the next lump will be added _before_ // this index, and it will be incremented so that a sequence of // AddLump() calls produces lumps in the same order. // // passing a negative value or invalid index will reset the // insertion point -- future lumps get added at the END. // RemoveLumps(), RemoveLevel() and EndWrite() also reset it. void InsertPoint(short index = -1); private: static Wad_file * Create(const char *filename, char mode); // read the existing directory. void ReadDirectory(); void DetectLevels(); void ProcessNamespaces(); // look at all the lumps and determine the lowest offset from // start of file where we can write new data. The directory itself // is ignored for this. int HighWaterMark(); // look at all lumps in directory and determine the lowest offset // where a lump of the given length will fit. Returns same as // HighWaterMark() when no largest gaps exist. The directory itself // is ignored since it will be re-written at EndWrite(). int FindFreeSpace(int length); // find a place (possibly at end of WAD) where we can write some // data of max_size (-1 means unlimited), and seek to that spot // (possibly writing some padding zeros -- the difference should // be no more than a few bytes). Returns new position. int PositionForWrite(int max_size = -1); bool FinishLump(int final_size); int WritePadding(int count); // write the new directory, updating the dir_xxx variables // (including the CRC). void WriteDirectory(); void FixGroup(std::vector& group, short index, short num_added, short num_removed); private: // deliberately don't implement these Wad_file(const Wad_file& other); Wad_file& operator= (const Wad_file& other); private: // predicate for sorting the levels[] vector struct level_name_CMP_pred { private: Wad_file *wad; public: level_name_CMP_pred(Wad_file * _w) : wad(_w) { } inline bool operator() (const short A, const short B) const { const Lump_c *L1 = wad->directory[A]; const Lump_c *L2 = wad->directory[B]; return (strcmp(L1->Name(), L2->Name()) < 0); } }; }; // the IWAD, never NULL, always at master_dir.front() extern Wad_file * game_wad; // the current PWAD, or NULL for none. // when present it is also at master_dir.back() extern Wad_file * edit_wad; extern std::vector master_dir; // find a lump in any loaded wad (later ones tried first), // returning NULL if not found. Lump_c * W_FindLump(const char *name); // find a lump that only exists in a certain namespace (sprite, // or patch) of a loaded wad (later ones tried first). Lump_c * W_FindSpriteLump(const char *name); Lump_c * W_FindPatchLump(const char *name); // load the lump into memory, returning the size int W_LoadLumpData(Lump_c *lump, byte ** buf_ptr); void W_FreeLumpData(byte ** buf_ptr); void MasterDir_Add (Wad_file *wad); void MasterDir_Remove(Wad_file *wad); void MasterDir_CloseAll(); #endif /* __EUREKA_W_WAD_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/m_config.cc0000644000175100017510000006374312651520612016362 0ustar aaptedaapted//------------------------------------------------------------------------ // CONFIG FILE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include #include #include "lib_adler.h" #include "editloop.h" #include "e_loadsave.h" #include "im_color.h" #include "m_config.h" #include "r_grid.h" #include "r_render.h" #include "levels.h" #include "ui_window.h" // meh! //------------------------------------------------------------------------ /* * Description of the command line arguments and config file keywords */ typedef enum { // End of the options description OPT_END = 0, // Boolean (toggle) // Receptacle is of type: bool OPT_BOOLEAN, // Integer number, // Receptacle is of type: int OPT_INTEGER, // A color value // Receptacle is of type: rgb_color_t OPT_COLOR, // String // Receptacle is of type: const char * OPT_STRING, // List of strings // Receptacle is of type: std::vector< const char * > OPT_STRING_LIST } opt_type_t; typedef struct { const char *long_name; // Command line arg. or keyword const char *short_name; // Abbreviated command line argument opt_type_t opt_type; // Type of this option const char *flags; // Flags for this option : // '1' : process only on pass 1 of parse_command_line_options() // 'f' : string is a filename // '<' : print extra newline after this option (when dumping) // 'v' : a real variable (preference setting) // 'w' : warp hack -- accept two numeric args const char *desc; // Description of the option const char *arg_desc; // Description of the argument (NULL --> none or default) void *data_ptr; // Pointer to the data } opt_desc_t; static const opt_desc_t options[] = { // // A few options must be handled in an early pass // { "home", 0, OPT_STRING, "1", "Home directory", "", &home_dir }, { "install", 0, OPT_STRING, "1", "Installation directory", "", &install_dir }, { "log", 0, OPT_STRING, "1", "Log messages to specified file", "", &log_file }, { "config", 0, OPT_STRING, "1<", "Config file to load / save", "", &config_file }, { "help", "h", OPT_BOOLEAN, "1", "Show usage summary", NULL, &show_help }, { "version", "v", OPT_BOOLEAN, "1", "Show the version", NULL, &show_version }, { "debug", "d", OPT_BOOLEAN, "1", "Enable debugging messages", NULL, &Debugging }, { "quiet", "q", OPT_BOOLEAN, "1", "Quiet mode (no messages on stdout)", NULL, &Quiet }, // // Normal options from here on.... // { "file", "f", OPT_STRING_LIST, "", "Wad file(s) to edit", "...", &Pwad_list }, { "merge", "m", OPT_STRING_LIST, "", "Resource file(s) to load", "...", &Resource_list }, { "iwad", "i", OPT_STRING, "", "The name of the IWAD (game data)", "", &Iwad_name }, { "port", "p", OPT_STRING, "", "Port (engine) name", "", &Port_name }, { "warp", "w", OPT_STRING, "w<", "Select level to edit", "", &Level_name }, /* ------------ Preferences ------------ */ { "auto_load_recent", 0, OPT_BOOLEAN, "v", "When no given files, load the most recent one saved", NULL, &auto_load_recent }, { "begin_maximized", 0, OPT_BOOLEAN, "v", "Maximize the window when Eureka starts", NULL, &begin_maximized }, { "backup_max_files", 0, OPT_INTEGER, "v", "Maximum copies to make when backing up a wad", NULL, &backup_max_files }, { "backup_max_space", 0, OPT_INTEGER, "v", "Maximum space to use (in MB) when backing up a wad", NULL, &backup_max_space }, { "easier_drawing_mode", 0, OPT_BOOLEAN, "v", "Easier line drawing using the LMB", NULL, &easier_drawing_mode }, { "browser_small_tex", 0, OPT_BOOLEAN, "v", "Show smaller (more compact) textures in the browser", NULL, &browser_small_tex }, { "default_gamma", 0, OPT_INTEGER, "v", "Default gamma for images and 3D view (0..4)", NULL, &usegamma }, { "default_grid_mode", 0, OPT_INTEGER, "v", "Default grid mode: 0 = OFF, 1 = dotty, 2 = normal", NULL, &default_grid_mode }, { "default_grid_size", 0, OPT_INTEGER, "v", "Default grid size", NULL, &default_grid_size }, { "default_grid_snap", 0, OPT_BOOLEAN, "v", "Default grid snapping", NULL, &default_grid_snap }, { "default_edit_mode", 0, OPT_INTEGER, "v", "Default editing mode: 0..3 = Th / Lin / Sec / Vt", NULL, &default_edit_mode }, { "default_port", 0, OPT_STRING, "v", "Default port (engine) name", NULL, &default_port }, { "digits_set_zoom", 0, OPT_BOOLEAN, "v", "Digit keys set zoom factor (rather than grid size)", NULL, &digits_set_zoom }, { "dotty_axis_col", 0, OPT_COLOR, "v", "axis color for the dotty style grid", NULL, &dotty_axis_col }, { "dotty_major_col", 0, OPT_COLOR, "v", "major color for the dotty style grid", NULL, &dotty_major_col }, { "dotty_minor_col", 0, OPT_COLOR, "v", "minor color for the dotty style grid", NULL, &dotty_minor_col }, { "dotty_point_col", 0, OPT_COLOR, "v", "point color for the dotty style grid", NULL, &dotty_point_col }, { "floor_bump_small", 0, OPT_INTEGER, "v", "distance for '+' and '-' buttons in sector panel while SHIFT is pressed", NULL, &floor_bump_small }, { "floor_bump_medium", 0, OPT_INTEGER, "v", "distance for '+' and '-' buttons in sector panel without any modifier keys", NULL, &floor_bump_medium }, { "floor_bump_large", 0, OPT_INTEGER, "v", "distance for '+' and '-' buttons in sector panel while CTRL is pressed", NULL, &floor_bump_large }, { "glbsp_fast", 0, OPT_BOOLEAN, "v", "Node building: enable fast mode (may be lower quality)", NULL, &glbsp_fast }, { "glbsp_verbose", 0, OPT_BOOLEAN, "v", "Node building: be verbose, show level information", NULL, &glbsp_verbose }, { "glbsp_warn", 0, OPT_BOOLEAN, "v", "Node building: show all warning messages", NULL, &glbsp_warn }, { "grid_hide_in_free_mode", 0, OPT_BOOLEAN, "v", "hide the grid in FREE mode", NULL, &grid_hide_in_free_mode }, { "grid_toggle_type", 0, OPT_INTEGER, "v", "grid toggle type : 0 = BOTH, 1 = dotty, 2 = normal", NULL, &grid_toggle_type }, { "gui_scheme", 0, OPT_INTEGER, "v", "GUI widget theme: 0 = fltk, 1 = gtk+, 2 = plastic", NULL, &gui_scheme }, { "gui_color_set", 0, OPT_INTEGER, "v", "GUI color set: 0 = fltk default, 1 = bright, 2 = custom", NULL, &gui_color_set }, { "gui_custom_bg", 0, OPT_COLOR, "v", "GUI custom background color", NULL, &gui_custom_bg }, { "gui_custom_ig", 0, OPT_COLOR, "v", "GUI custom input color", NULL, &gui_custom_ig }, { "gui_custom_fg", 0, OPT_COLOR, "v", "GUI custom foreground (text) color", NULL, &gui_custom_fg }, { "leave_offsets_alone", 0, OPT_BOOLEAN, "v", "Do not adjust offsets when splitting lines (etc)", NULL, &leave_offsets_alone }, { "light_bump_small", 0, OPT_INTEGER, "v", "light step for '+' and '-' buttons in sector panel while SHIFT is pressed", NULL, &light_bump_small }, { "light_bump_medium", 0, OPT_INTEGER, "v", "light step for '+' and '-' buttons in sector panel without any modifier keys", NULL, &light_bump_medium }, { "light_bump_large", 0, OPT_INTEGER, "v", "light step for '+' and '-' buttons in sector panel while CTRL is pressed", NULL, &light_bump_large }, { "map_scroll_bars", 0, OPT_BOOLEAN, "v", "Enable scroll-bars for the map view", NULL, &map_scroll_bars }, { "minimum_drag_pixels", 0, OPT_INTEGER, "v", "Minimum distance to move mouse to drag an object (in pixels)", NULL, &minimum_drag_pixels }, { "mouse_wheel_scrolls_map", 0, OPT_BOOLEAN, "v", "Use the mouse wheel events for scrolling, not zooming", NULL, &mouse_wheel_scrolls_map }, { "multi_select_modifier", 0, OPT_INTEGER, "v", "Require a modifier key for multi-select (0 = none, 1 = SHIFT, 2 = CTRL)", NULL, &multi_select_modifier }, { "new_islands_are_void", 0, OPT_BOOLEAN, "v", "Islands created inside a sector will get a void interior", NULL, &new_islands_are_void }, { "new_sector_size", 0, OPT_INTEGER, "v", "Size of sector rectangles created outside of the map", NULL, &new_sector_size }, { "normal_axis_col", 0, OPT_COLOR, "v", "axis color for the normal grid", NULL, &normal_axis_col }, { "normal_main_col", 0, OPT_COLOR, "v", "main color for the normal grid", NULL, &normal_main_col }, { "normal_flat_col", 0, OPT_COLOR, "v", "flat color for the normal grid", NULL, &normal_flat_col }, { "normal_small_col", 0, OPT_COLOR, "v", "small color for the normal grid", NULL, &normal_small_col }, { "render_pixel_aspect", 0, OPT_INTEGER, "v", "Pixel aspect ratio for 3D view (100 * width / height)", NULL, &render_pixel_aspect }, { "render_high_detail", 0, OPT_BOOLEAN, "v", "Use highest detail when rendering the 3D view", NULL, &render_high_detail }, { "render_lock_gravity", 0, OPT_BOOLEAN, "v", "Locked gravity in 3D view -- cannot move up or down", NULL, &render_lock_gravity }, { "render_missing_bright", 0, OPT_BOOLEAN, "v", "Render the missing texture as fullbright", NULL, &render_missing_bright }, { "render_unknown_bright", 0, OPT_BOOLEAN, "v", "Render the unknown texture as fullbright", NULL, &render_unknown_bright }, { "same_mode_clears_selection", 0, OPT_BOOLEAN, "v", "Clear the selection when entering the same mode", NULL, &same_mode_clears_selection }, { "scroll_less", 0, OPT_INTEGER, "v", "Amplitude of scrolling (% of screen size)", NULL, &scroll_less }, { "scroll_more", 0, OPT_INTEGER, "v", "Amplitude of scrolling (% of screen size)", NULL, &scroll_more }, { "sector_render_default", 0, OPT_INTEGER, "v", "Default sector rendering mode: 0 = NONE, 1 = floor, 2 = ceiling", NULL, §or_render_default }, { "show_full_one_sided", 0, OPT_BOOLEAN, "v", "Show all textures on one-sided lines in the Linedef panel", NULL, &show_full_one_sided }, { "swap_sidedefs", 0, OPT_BOOLEAN, "v", "Swap upper and lower sidedefs in the Linedef panel", NULL, &swap_sidedefs }, // // That's all there is // { 0, 0, OPT_END, 0, 0, 0, 0 } }; //------------------------------------------------------------------------ static int parse_config_line_from_file(char *p, const char *basename, int lnum) { char *name = NULL; char *value = NULL; // skip leading whitespace while (isspace (*p)) p++; // skip comments if (*p == '#') return 0; // remove trailing newline and whitespace { int len = (int)strlen(p); while (len > 0 && isspace(p[len - 1])) { p[len - 1] = 0; len--; } } // skip empty lines if (*p == 0) return 0; // grab the name name = p; while (y_isident (*p)) p++; if (! isspace(*p)) { LogPrintf("WARNING: %s(%u): bad line, no space after keyword.\n", basename, lnum); return 0; } *p++ = 0; // find the option value (occupies rest of the line) while (isspace(*p)) p++; if (*p == 0) { LogPrintf("WARNING: %s(%u): bad line, missing option value.\n", basename, lnum); return 0; } value = p; // find the option keyword const opt_desc_t * opt; for (opt = options ; ; opt++) { if (opt->opt_type == OPT_END) { LogPrintf("WARNING: %s(%u): invalid option '%s', skipping\n", basename, lnum, name); return 0; } if (! opt->long_name || strcmp(name, opt->long_name) != 0) continue; // pre-pass options (like --help) don't make sense in a config file if (strchr(opt->flags, '1')) { LogPrintf("WARNING: %s(%u): cannot use option '%s' in config files.\n", basename, lnum, name); return 0; } // found it break; } switch (opt->opt_type) { case OPT_BOOLEAN: if (y_stricmp(value, "no") == 0 || y_stricmp(value, "false") == 0 || y_stricmp(value, "off") == 0 || y_stricmp(value, "0") == 0) { *((bool *) (opt->data_ptr)) = false; } else // anything else is TRUE { *((bool *) (opt->data_ptr)) = true; } break; case OPT_INTEGER: *((int *) opt->data_ptr) = atoi(value); break; case OPT_COLOR: *((rgb_color_t *) opt->data_ptr) = ParseColor(value); break; case OPT_STRING: // handle empty string if (strcmp(value, "''") == 0) *value = 0; *((char **) opt->data_ptr) = StringDup(value); break; case OPT_STRING_LIST: while (*value != 0) { char *v = value; while (*v != 0 && ! isspace ((unsigned char) *v)) v++; string_list_t * list = (string_list_t *)opt->data_ptr; list->push_back(StringDup(value, (int)(v - value))); while (isspace (*v)) v++; value = v; } break; default: BugError("INTERNAL ERROR: unknown option type %d", (int) opt->opt_type); return -1; } return 0; // OK } /* * try to parse a config file by pathname. * * Return 0 on success, negative value on failure. */ static int parse_a_config_file(FILE *fp, const char *filename) { static char line[1024]; const char *basename = FindBaseName(filename); // Execute one line on each iteration for (int lnum = 1 ; fgets(line, sizeof(line), fp) != NULL ; lnum++) { int ret = parse_config_line_from_file(line, basename, lnum); if (ret != 0) return ret; } return 0; // OK } static const char * default_config_file() { static char filename[FL_PATH_MAX]; SYS_ASSERT(home_dir); sprintf(filename, "%s/config.cfg", home_dir); return StringDup(filename); } /* * parses the config file (either a user-specific one or the default one). * * return 0 on success, negative value on error. */ int M_ParseConfigFile() { if (! config_file) { config_file = default_config_file(); } FILE * fp = fopen(config_file, "r"); LogPrintf("Reading config file: %s\n", config_file); if (fp == NULL) { LogPrintf("--> %s\n", strerror(errno)); return -1; } int rc = parse_a_config_file(fp, config_file); fclose(fp); return rc; } /* * parse_environment_vars * Check certain environment variables. * Returns 0 on success, <>0 on error. */ int M_ParseEnvironmentVars() { #if 0 char *value; value = getenv ("EUREKA_GAME"); if (value != NULL) Game = value; #endif return 0; } void M_AddPwadName(const char *filename) { Pwad_list.push_back(StringDup(filename)); } /* * parses the command line options * * If is set to 1, ignores all options except those * that have the "1" flag. * Else, ignores all options that have the "1" flag. * If an error occurs, report it with LogPrintf(). * and returns non-zero. Else, returns 0. */ int M_ParseCommandLine(int argc, const char *const *argv, int pass) { const opt_desc_t *o; while (argc > 0) { bool ignore; // is it actually an option? if (argv[0][0] != '-') { // this is a loose file, handle it now if (pass != 1) M_AddPwadName(argv[0]); argv++; argc--; continue; } // Which option is this? for (o = options; ; o++) { if (o->opt_type == OPT_END) { FatalError("unknown option: '%s'\n", argv[0]); return 1; } if ( (o->short_name && strcmp (argv[0]+1, o->short_name) == 0) || (o->long_name && strcmp (argv[0]+1, o->long_name ) == 0) || (o->long_name && argv[0][1] == '-' && strcmp (argv[0]+2, o->long_name ) == 0) ) break; } // ignore options which are not meant for this pass ignore = (strchr(o->flags, '1') != NULL) != (pass == 1); switch (o->opt_type) { case OPT_BOOLEAN: // -AJA- permit a following value if (argc >= 2 && argv[1][0] != '-') { argv++; argc--; if (ignore) break; if (y_stricmp(argv[0], "no") == 0 || y_stricmp(argv[0], "false") == 0 || y_stricmp(argv[0], "off") == 0 || y_stricmp(argv[0], "0") == 0) { *((bool *) (o->data_ptr)) = false; } else // anything else is TRUE { *((bool *) (o->data_ptr)) = true; } } else if (! ignore) { *((bool *) o->data_ptr) = true; } break; case OPT_INTEGER: if (argc < 2) { FatalError("missing argument after '%s'\n", argv[0]); return 1; } argv++; argc--; if (! ignore) { *((int *) o->data_ptr) = atoi(argv[0]); } break; case OPT_COLOR: if (argc < 2) { FatalError("missing argument after '%s'\n", argv[0]); return 1; } argv++; argc--; if (! ignore) { *((rgb_color_t *) o->data_ptr) = ParseColor(argv[0]); } break; case OPT_STRING: if (argc < 2) { FatalError("missing argument after '%s'\n", argv[0]); return 1; } argv++; argc--; if (! ignore) { *((const char **) o->data_ptr) = StringDup(argv[0]); } // support two numeric values after -warp if (strchr(o->flags, 'w') && isdigit(argv[0][0]) && argc > 1 && isdigit(argv[1][0])) { if (! ignore) { *((const char **) o->data_ptr) = StringPrintf("%s%s", argv[0], argv[1]); } argv++; argc--; } break; case OPT_STRING_LIST: if (argc < 2) { FatalError("missing argument after '%s'\n", argv[0]); return 1; } while (argc > 1 && argv[1][0] != '-' && argv[1][0] != '+') { argv++; argc--; if (! ignore) { string_list_t * list = (string_list_t *) o->data_ptr; list->push_back(StringDup(argv[0])); } } break; default: { BugError("INTERNAL ERROR: unknown option type (%d)", (int) o->opt_type); return 1; } } argv++; argc--; } return 0; } /* * Print a list of the parameters with their current value. */ void dump_parameters(FILE *fp) { const opt_desc_t *o; int desc_maxlen = 0; int name_maxlen = 0; for (o = options; o->opt_type != OPT_END; o++) { int len = (int)strlen (o->desc); desc_maxlen = MAX(desc_maxlen, len); if (o->long_name) { len = (int)strlen (o->long_name); name_maxlen = MAX(name_maxlen, len); } } for (o = options; o->opt_type != OPT_END; o++) { if (! o->long_name) continue; fprintf (fp, "%-*s %-*s ", name_maxlen, o->long_name, desc_maxlen, o->desc); if (o->opt_type == OPT_BOOLEAN) fprintf (fp, "%s", *((bool *) o->data_ptr) ? "true" : "false"); else if (o->opt_type == OPT_INTEGER) fprintf (fp, "%d", *((int *) o->data_ptr)); else if (o->opt_type == OPT_COLOR) fprintf (fp, "%06x", *((rgb_color_t *) o->data_ptr) >> 8); else if (o->opt_type == OPT_STRING) { const char *str = *((const char **) o->data_ptr); fprintf(fp, "'%s'", str ? str : "--none--"); } else if (o->opt_type == OPT_STRING_LIST) { string_list_t *list = (string_list_t *)o->data_ptr; if (list->empty()) fprintf(fp, "--none--"); else for (unsigned int i = 0 ; i < list->size() ; i++) fprintf(fp, "'%s' ", list->at(i)); } fputc ('\n', fp); } } /* * Print a list of all command line options (usage message). */ void dump_command_line_options(FILE *fp) { const opt_desc_t *o; int name_maxlen = 0; int arg_maxlen = 0; for (o = options; o->opt_type != OPT_END; o++) { int len; if (strchr(o->flags, 'v')) continue; if (o->long_name) { len = (int)strlen (o->long_name); name_maxlen = MAX(name_maxlen, len); } if (o->arg_desc) { len = (int)strlen (o->arg_desc); arg_maxlen = MAX(arg_maxlen, len); } } for (int pass = 0 ; pass < 2 ; pass++) for (o = options; o->opt_type != OPT_END; o++) { if (strchr(o->flags, 'v')) continue; if ((strchr(o->flags, '1') ? 1 : 0) != pass) continue; if (o->short_name) fprintf (fp, " -%-3s ", o->short_name); else fprintf (fp, " "); if (o->long_name) fprintf (fp, "--%-*s ", name_maxlen, o->long_name); else fprintf (fp, "%*s ", name_maxlen + 2, ""); if (o->arg_desc) fprintf (fp, "%-12s", o->arg_desc); else switch (o->opt_type) { case OPT_BOOLEAN: fprintf (fp, " "); break; case OPT_INTEGER: fprintf (fp, " "); break; case OPT_COLOR: fprintf (fp, " "); break; case OPT_STRING: fprintf (fp, " "); break; case OPT_STRING_LIST: fprintf (fp, " ..."); break; case OPT_END: ; // This line is here only to silence a GCC warning. } fprintf (fp, " %s\n", o->desc); if (strchr(o->flags, '<')) fprintf (fp, "\n"); } } int M_WriteConfigFile() { SYS_ASSERT(config_file); LogPrintf("Writing config file: %s\n", config_file); FILE * fp = fopen(config_file, "w"); if (! fp) { LogPrintf("--> %s\n", strerror(errno)); return -1; } const opt_desc_t *o; for (o = options; o->opt_type != OPT_END; o++) { if (! strchr(o->flags, 'v')) continue; if (! o->long_name) continue; fprintf(fp, "%s ", o->long_name); switch (o->opt_type) { case OPT_BOOLEAN: fprintf(fp, "%s", *((bool *) o->data_ptr) ? "1" : "0"); break; case OPT_STRING: { const char *str = *((const char **) o->data_ptr); fprintf(fp, "%s", (str && str[0]) ? str : "''"); break; } case OPT_INTEGER: fprintf(fp, "%d", *((int *) o->data_ptr)); break; case OPT_COLOR: fprintf(fp, "%06x", *((rgb_color_t *) o->data_ptr) >> 8); break; case OPT_STRING_LIST: { string_list_t *list = (string_list_t *)o->data_ptr; if (list->empty()) fprintf(fp, "{}"); else for (unsigned int i = 0 ; i < list->size() ; i++) fprintf(fp, "%s ", list->at(i)); } default: break; } fprintf(fp, "\n"); } fflush(fp); fclose(fp); return 0; // OK } //------------------------------------------------------------------------ // USER STATE HANDLING //------------------------------------------------------------------------ int M_ParseLine(const char *line, const char ** tokens, int max_tok, bool do_strings) { int num_tok = 0; char tokenbuf[256]; int tokenlen = -1; bool in_string = false; // skip leading whitespace while (isspace(*line)) line++; // blank line or comment line? if (*line == 0 || *line == '\n' || *line == '#') return 0; for (;;) { if (tokenlen > 250) // ERROR: token too long return -1; int ch = *line++; if (tokenlen < 0) // looking for a new token { SYS_ASSERT(!in_string); // end of line? if yes, break out of for loop if (ch == 0 || ch == '\n') break; if (isspace(ch)) continue; tokenlen = 0; // begin a string? if (ch == '"' && do_strings) { in_string = true; continue; } // begin a normal token tokenbuf[tokenlen++] = ch; continue; } if (ch == '"' && in_string) { // end of string in_string = false; } else if (ch == 0 || ch == '\n' || isspace(ch)) { // end of token } else { tokenbuf[tokenlen++] = ch; continue; } if (num_tok >= max_tok) // ERROR: too many tokens return -2; if (in_string) // ERROR: non-terminated string return -3; tokenbuf[tokenlen] = 0; tokenlen = -1; tokens[num_tok++] = strdup(tokenbuf); // end of line? if yes, break out of for loop if (ch == 0 || ch == '\n') break; } return num_tok; } void M_FreeLine(const char ** tokens, int num_tok) { for (int i = 0 ; i < num_tok ; i++) { free((void *) tokens[i]); tokens[i] = NULL; } } char * PersistFilename(const crc32_c& crc) { static char filename[FL_PATH_MAX]; sprintf(filename, "%s/cache/%08X%08X.dat", cache_dir, crc.extra, crc.raw); return filename; } #define MAX_TOKENS 10 bool M_LoadUserState() { crc32_c crc; BA_LevelChecksum(crc); char *filename = PersistFilename(crc); LogPrintf("Load user state from: %s\n", filename); FILE *fp = fopen(filename, "r"); if (! fp) { LogPrintf("--> %s\n", strerror(errno)); return false; } static char line_buf[FL_PATH_MAX]; const char * tokens[MAX_TOKENS]; while (! feof(fp)) { char *line = fgets(line_buf, FL_PATH_MAX, fp); if (! line) break; StringRemoveCRLF(line); int num_tok = M_ParseLine(line, tokens, MAX_TOKENS, true /* do_strings */); if (num_tok == 0) continue; if (num_tok < 0) { LogPrintf("Error in persistent data: %s\n", line); continue; } if ( Editor_ParseUser(tokens, num_tok) || Grid_ParseUser(tokens, num_tok) || Render3D_ParseUser(tokens, num_tok) || Browser_ParseUser(tokens, num_tok) || Props_ParseUser(tokens, num_tok) || RecUsed_ParseUser(tokens, num_tok)) { // Ok } else { LogPrintf("Unknown persistent data: %s\n", line); } } fclose(fp); Props_LoadValues(); return true; } bool M_SaveUserState() { crc32_c crc; BA_LevelChecksum(crc); char *filename = PersistFilename(crc); LogPrintf("Save user state to: %s\n", filename); FILE *fp = fopen(filename, "w"); if (! fp) { LogPrintf("--> FAILED! (%s)\n", strerror(errno)); return false; } Editor_WriteUser(fp); Grid_WriteUser(fp); Render3D_WriteUser(fp); Browser_WriteUser(fp); Props_WriteUser(fp); RecUsed_WriteUser(fp); fclose(fp); return true; } void M_DefaultUserState() { grid.Init(); CMD_ZoomWholeMap(); Render3D_Setup(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_linedef.h0000644000175100017510000000513012647127122016534 0ustar aaptedaapted//------------------------------------------------------------------------ // LINEDEF PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 __EUREKA_UI_LINEDEF_H__ #define __EUREKA_UI_LINEDEF_H__ class UI_LineBox : public Fl_Group { private: int obj; int count; public: UI_Nombre *which; Fl_Int_Input *type; Fl_Button *choose; Fl_Button *gen; Fl_Output *desc; Fl_Choice *actkind; Fl_Int_Input *length; Fl_Int_Input *tag; Fl_Int_Input *args[5]; UI_SideBox *front; UI_SideBox *back; // Flags Fl_Choice *f_automap; Fl_Check_Button *f_upper; Fl_Check_Button *f_lower; Fl_Check_Button *f_passthru; Fl_Check_Button *f_3dmidtex; Fl_Check_Button *f_walk; Fl_Check_Button *f_mons; Fl_Check_Button *f_sound; public: UI_LineBox(int X, int Y, int W, int H, const char *label = NULL); virtual ~UI_LineBox(); public: void SetObj(int _index, int _count); int GetObj() const { return obj; } // call this if the linedef was externally changed. // -1 means "all fields" void UpdateField(int field = -1); // call this is the linedef's sides were externally modified. void UpdateSides(); void UpdateTotal(); void SetTexture(const char *tex_name, int e_state); void SetLineType(int new_type); void UnselectPics(); void UpdateGameInfo(); private: void CalcLength(); int CalcFlags() const; void FlagsFromInt(int flags); void SetTexOnLine(int ld, int new_tex, int e_state, int front_pics, int back_pics); int SolidMask(int side); const char *GeneralizedDesc(int type_num); static void type_callback(Fl_Widget *, void *); static void tag_callback(Fl_Widget *, void *); static void flags_callback(Fl_Widget *, void *); static void args_callback(Fl_Widget *, void *); static void length_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_LINEDEF_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/lib_file.cc0000644000175100017510000002670712647061302016346 0ustar aaptedaapted//------------------------------------------------------------------------ // File Utilities //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2012 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 "main.h" #ifdef WIN32 #include #endif #ifdef UNIX #include #include #include #include #endif #ifdef __APPLE__ #include #include // _NSGetExecutablePath #endif #ifndef PATH_MAX #define PATH_MAX 2048 #endif bool FileExists(const char *filename) { FILE *fp = fopen(filename, "rb"); if (fp) { fclose(fp); return true; } return false; } 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; } // // MatchExtension // // When ext is NULL, checks if the file has no extension. // bool MatchExtension(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. // // Returned string is a COPY. // char *ReplaceExtension(const char *filename, const char *ext) { SYS_ASSERT(filename[0] != 0); size_t total_len = strlen(filename) + (ext ? strlen(ext) : 0); char *buffer = StringNew((int)total_len + 10); strcpy(buffer, filename); char *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; } const char *FindBaseName(const char *filename) { // 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 *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; } bool FilenameIsBare(const char *filename) { if (strchr(filename, '.')) return false; if (strchr(filename, '/')) return false; if (strchr(filename, '\\')) return false; if (strchr(filename, ':')) return false; return true; } void FilenameStripBase(char *buffer) { char *pos = buffer + strlen(buffer) - 1; for (; pos > buffer ; pos--) { if (*pos == '/') break; #ifdef WIN32 if (*pos == '\\') break; if (*pos == ':') { pos[1] = 0; return; } #endif } if (pos > buffer) *pos = 0; else strcpy(buffer, "."); } /* takes the basename in 'filename' and prepends the path from 'othername'. * returns a newly allocated string. */ const char *FilenameReposition(const char *filename, const char *othername) { filename = fl_filename_name(filename); const char *op = fl_filename_name(othername); if (op <= othername) return StringDup(filename); size_t dir_len = op - othername; size_t len = strlen(filename) + dir_len; char *result = StringNew((int)len + 10); memcpy(result, othername, dir_len); result[dir_len] = 0; strcat(result, filename); return result; } bool FileCopy(const char *src_name, const char *dest_name) { char buffer[1024]; FILE *src = fopen(src_name, "rb"); if (! src) return false; FILE *dest = fopen(dest_name, "wb"); if (! dest) { fclose(src); return false; } while (true) { size_t rlen = fread(buffer, 1, sizeof(buffer), src); if (rlen <= 0) break; size_t wlen = fwrite(buffer, 1, rlen, dest); if (wlen != rlen) break; } bool was_OK = !ferror(src) && !ferror(dest); fclose(dest); fclose(src); return was_OK; } bool FileRename(const char *old_name, const char *new_name) { #ifdef WIN32 return (::MoveFile(old_name, new_name) != 0); #else // UNIX or MACOSX return (rename(old_name, new_name) == 0); #endif } bool FileDelete(const char *filename) { #ifdef WIN32 return (::DeleteFile(filename) != 0); #else // UNIX or MACOSX return (remove(filename) == 0); #endif } bool FileChangeDir(const char *dir_name) { #ifdef WIN32 return (::SetCurrentDirectory(dir_name) != 0); #else // UNIX or MACOSX return (chdir(dir_name) == 0); #endif } bool FileMakeDir(const char *dir_name) { #ifdef WIN32 return (::CreateDirectory(dir_name, NULL) != 0); #else // UNIX or MACOSX return (mkdir(dir_name, 0775) == 0); #endif } u8_t * FileLoad(const char *filename, int *length) { *length = 0; FILE *fp = fopen(filename, "rb"); if (! fp) return NULL; // determine size of file (via seeking) fseek(fp, 0, SEEK_END); { (*length) = (int)ftell(fp); } fseek(fp, 0, SEEK_SET); if (ferror(fp) || *length < 0) { fclose(fp); return NULL; } u8_t *data = (u8_t *) malloc(*length + 1); if (! data) FatalError("Out of memory (%d bytes for FileLoad)\n", *length); // ensure buffer is NUL-terminated data[*length] = 0; if (1 != fread(data, *length, 1, fp)) { FileFree(data); fclose(fp); return NULL; } fclose(fp); return data; } void FileFree(u8_t *mem) { free((void*) mem); } // // Note: returns false when the path doesn't exist. // bool PathIsDirectory(const char *path) { #ifdef WIN32 char old_dir[MAX_PATH+1]; if (GetCurrentDirectory(MAX_PATH, (LPSTR)old_dir) == FALSE) return false; bool result = SetCurrentDirectory(path); SetCurrentDirectory(old_dir); return result; #else // UNIX or MACOSX struct stat finfo; if (stat(path, &finfo) != 0) return false; return (S_ISDIR(finfo.st_mode)) ? true : false; #endif } const char * FileFindInPath(const char *paths, const char *base_name) { // search through the path list (separated by ';') to find the file. // If found, the complete filename is returned (which must be freed // using StringFree). If not found, NULL is returned. for (;;) { const char *sep = strchr(paths, ';'); size_t len = sep ? (sep - paths) : strlen(paths); SYS_ASSERT(len > 0); const char *filename = StringPrintf("%.*s/%s", (int)len, paths, base_name); // fprintf(stderr, "Trying data file: [%s]\n", filename); if (FileExists(filename)) return filename; StringFree(filename); if (! sep) return NULL; // not found paths = sep + 1; } } //------------------------------------------------------------------------ int ScanDirectory(const char *path, directory_iter_f func, void *priv_dat) { int count = 0; #ifdef WIN32 // this is a bit clunky. We set the current directory to the // target and use FindFirstFile with "*.*" as the pattern. // Afterwards we restore the current directory. char old_dir[MAX_PATH+1]; if (GetCurrentDirectory(MAX_PATH, (LPSTR)old_dir) == FALSE) return SCAN_ERROR; if (SetCurrentDirectory(path) == FALSE) return SCAN_ERR_NoExist; WIN32_FIND_DATA fdata; HANDLE handle = FindFirstFile("*.*", &fdata); if (handle == INVALID_HANDLE_VALUE) { SetCurrentDirectory(old_dir); return 0; //??? (GetLastError() == ERROR_FILE_NOT_FOUND) ? 0 : SCAN_ERROR; } do { int flags = 0; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) flags |= SCAN_F_IsDir; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY) flags |= SCAN_F_ReadOnly; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) flags |= SCAN_F_Hidden; // minor kludge for consistency with Unix if (fdata.cFileName[0] == '.' && isalpha(fdata.cFileName[1])) flags |= SCAN_F_Hidden; if (strcmp(fdata.cFileName, ".") == 0 || strcmp(fdata.cFileName, "..") == 0) { // skip the funky "." and ".." dirs } else { (* func)(fdata.cFileName, flags, priv_dat); count++; } } while (FindNextFile(handle, &fdata) != FALSE); FindClose(handle); SetCurrentDirectory(old_dir); #else // ---- UNIX ------------------------------------------------ DIR *handle = opendir(path); if (handle == NULL) return SCAN_ERR_NoExist; for (;;) { const struct dirent *fdata = readdir(handle); if (fdata == NULL) break; if (strlen(fdata->d_name) == 0) continue; // skip the funky "." and ".." dirs if (strcmp(fdata->d_name, ".") == 0 || strcmp(fdata->d_name, "..") == 0) continue; const char *full_name = StringPrintf("%s/%s", path, fdata->d_name); struct stat finfo; if (stat(full_name, &finfo) != 0) { DebugPrintf(".... stat failed: %s\n", strerror(errno)); StringFree(full_name); continue; } StringFree(full_name); int flags = 0; if (S_ISDIR(finfo.st_mode)) flags |= SCAN_F_IsDir; if ((finfo.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0) flags |= SCAN_F_ReadOnly; if (fdata->d_name[0] == '.' && isalpha(fdata->d_name[1])) flags |= SCAN_F_Hidden; (* func)(fdata->d_name, flags, priv_dat); count++; } closedir(handle); #endif return count; } //------------------------------------------------------------------------ const char *GetExecutablePath(const char *argv0) { char *path; #ifdef WIN32 path = StringNew(PATH_MAX+2); int length = GetModuleFileName(GetModuleHandle(NULL), path, PATH_MAX); if (length > 0 && length < PATH_MAX) { if (access(path, 0) == 0) // sanity check { FilenameStripBase(path); return path; } } // didn't work, free the memory StringFree(path); #endif #ifdef UNIX path = StringNew(PATH_MAX+2); int length = readlink("/proc/self/exe", path, PATH_MAX); if (length > 0) { path[length] = 0; // add the missing NUL if (access(path, 0) == 0) // sanity check { FilenameStripBase(path); return path; } } // didn't work, free the memory StringFree(path); #endif #ifdef __APPLE__ /* from http://www.hmug.org/man/3/NSModule.html extern int _NSGetExecutablePath(char *buf, uint32_t *bufsize); _NSGetExecutablePath copies the path of the executable into the buffer and returns 0 if the path was successfully copied in the provided buffer. If the buffer is not large enough, -1 is returned and the expected buffer size is copied in *bufsize. */ uint32_t pathlen = PATH_MAX * 2; path = StringNew(pathlen+2); if (0 == _NSGetExecutablePath(path, &pathlen)) { // FIXME: will this be _inside_ the .app folder??? FilenameStripBase(path); return path; } // didn't work, free the memory StringFree(path); #endif // fallback method: use argv[0] path = StringDup(argv0); #ifdef __APPLE__ // FIXME: check if _inside_ the .app folder #endif FilenameStripBase(path); return path; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_sidedef.cc0000644000175100017510000002601412651122253016666 0ustar aaptedaapted//------------------------------------------------------------------------ // SIDEDEF INFORMATION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 "main.h" #include "ui_window.h" #include "levels.h" #include "w_rawdef.h" #include "x_hover.h" #include "x_loop.h" // config item bool swap_sidedefs; bool show_full_one_sided; // // Constructor // UI_SideBox::UI_SideBox(int X, int Y, int W, int H, int _side) : Fl_Group(X, Y, W, H), obj(SETOBJ_NO_LINE), is_front(_side == 0), on_2S_line(false) { box(FL_FLAT_BOX); // FL_UP_BOX align(FL_ALIGN_INSIDE | FL_ALIGN_TOP | FL_ALIGN_LEFT); if (is_front) labelcolor(FL_BLUE); else labelcolor(fl_rgb_color(224,64,0)); add_button = new Fl_Button(X + W - 120, Y, 50, 20, "ADD"); add_button->labelcolor(labelcolor()); add_button->callback(add_callback, this); del_button = new Fl_Button(X + W - 65, Y, 50, 20, "DEL"); del_button->labelcolor(labelcolor()); del_button->callback(delete_callback, this); X += 6; Y += 6 + 16; // space for label W -= 12; H -= 12; int MX = X + W/2; x_ofs = new Fl_Int_Input(X+28, Y, 52, 24, "x:"); y_ofs = new Fl_Int_Input(MX-20, Y, 52, 24, "y:"); sec = new Fl_Int_Input(X+W-59, Y, 52, 24, "sec:"); x_ofs->align(FL_ALIGN_LEFT); y_ofs->align(FL_ALIGN_LEFT); sec ->align(FL_ALIGN_LEFT); x_ofs->callback(offset_callback, this); y_ofs->callback(offset_callback, this); sec ->callback(sector_callback, this); x_ofs->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); y_ofs->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); sec ->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += x_ofs->h() + 6; int LX = X+16; int UX = X+W-64-16; MX = MX-32; if (swap_sidedefs) { std::swap(UX, LX); } l_pic = new UI_Pic(LX, Y, 64, 64, "Lower"); u_pic = new UI_Pic(UX, Y, 64, 64, "Upper"); r_pic = new UI_Pic(MX, Y, 64, 64, "Rail"); l_pic->callback(tex_callback, this); u_pic->callback(tex_callback, this); r_pic->callback(tex_callback, this); Y += 65; l_tex = new Fl_Input(LX-8, Y, 80, 20); u_tex = new Fl_Input(UX-8, Y, 80, 20); r_tex = new Fl_Input(MX-8, Y, 80, 20); l_tex->textsize(12); u_tex->textsize(12); r_tex->textsize(12); l_tex->callback(tex_callback, this); u_tex->callback(tex_callback, this); r_tex->callback(tex_callback, this); l_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); u_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); r_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); end(); UpdateHiding(); UpdateLabel(); UpdateAddDel(); } // // Destructor // UI_SideBox::~UI_SideBox() { } void UI_SideBox::tex_callback(Fl_Widget *w, void *data) { UI_SideBox *box = (UI_SideBox *)data; if (box->obj < 0) return; if (Fl::event_button() != 3 && (w == box->l_pic || w == box->u_pic || w == box->r_pic)) { UI_Pic * pic = (UI_Pic *)w; pic->Selected(! pic->Selected()); pic->redraw(); if (pic->Selected()) main_win->ShowBrowser('T'); return; } int new_tex; // right click sets to default value, "-" for rail if (Fl::event_button() == 3) { if (w == box->r_pic) new_tex = BA_InternaliseString("-"); else new_tex = BA_InternaliseString(default_lower_tex); } else { if (w == box->l_tex) new_tex = TexFromWidget(box->l_tex); else if (w == box->u_tex) new_tex = TexFromWidget(box->u_tex); else new_tex = TexFromWidget(box->r_tex); } // iterate over selected linedefs selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it) ; !it.at_end() ; ++it) { const LineDef *L = LineDefs[*it]; int sd = box->is_front ? L->right : L->left; if (is_sidedef(sd)) { bool lower = (w == box->l_tex || w == box->l_pic); bool upper = (w == box->u_tex || w == box->u_pic); bool rail = (w == box->r_tex || w == box->r_pic); if (L->OneSided()) std::swap(lower, rail); if (lower) { BA_ChangeSD(sd, SideDef::F_LOWER_TEX, new_tex); } if (upper) { BA_ChangeSD(sd, SideDef::F_UPPER_TEX, new_tex); } if (rail) { BA_ChangeSD(sd, SideDef::F_MID_TEX, new_tex); } } } BA_End(); box->UpdateField(); } } void UI_SideBox::add_callback(Fl_Widget *w, void *data) { UI_SideBox *box = (UI_SideBox *)data; if (box->obj >= 0) return; if (edit.Selected->empty()) return; // iterate over selected linedefs selection_iterator_c it; int field = box->is_front ? LineDef::F_RIGHT : LineDef::F_LEFT; BA_Begin(); // iterate through all lines, if this sidedef exists on one of them // then use the same sector. // DISABLED -- NOT INTUITIVE #if 0 int new_sec = -1; for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { const LineDef *L = LineDefs[*it]; int sd = box->is_front ? L->right : L->left; if (sd >= 0) { new_sec = SideDefs[sd]->sector; break; } } #endif // make sure we have a fallback sector to use if (NumSectors == 0) { int new_sec = BA_New(OBJ_SECTORS); Sectors[new_sec]->SetDefaults(); } for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { const LineDef *L = LineDefs[*it]; int sd = box->is_front ? L->right : L->left; int other = box->is_front ? L->left : L->right; if (is_sidedef(sd)) continue; // determine what sector to use int new_sec = OppositeSector(*it, box->is_front ? SIDE_RIGHT : SIDE_LEFT); if (new_sec < 0) new_sec = NumSectors - 1; // create the new sidedef sd = BA_New(OBJ_SIDEDEFS); SideDefs[sd]->SetDefaults(other >= 0); SideDefs[sd]->sector = new_sec; BA_ChangeLD(*it, field, sd); if (other >= 0) LD_AddSecondSideDef(*it, sd, other); } BA_End(); main_win->line_box->UpdateField(); main_win->line_box->UpdateSides(); } void UI_SideBox::delete_callback(Fl_Widget *w, void *data) { UI_SideBox *box = (UI_SideBox *)data; if (box->obj < 0) return; if (edit.Selected->empty()) return; // iterate over selected linedefs selection_iterator_c it; BA_Begin(); for (edit.Selected->begin(&it) ; !it.at_end() ; ++it) { const LineDef *L = LineDefs[*it]; int sd = box->is_front ? L->right : L->left; if (sd < 0) continue; // NOTE WELL: the actual sidedef is not deleted (it might be shared) LD_RemoveSideDef(*it, box->is_front ? SIDE_RIGHT : SIDE_LEFT); } BA_End(); main_win->line_box->UpdateField(); main_win->line_box->UpdateSides(); } void UI_SideBox::offset_callback(Fl_Widget *w, void *data) { UI_SideBox *box = (UI_SideBox *)data; int new_x_ofs = atoi(box->x_ofs->value()); int new_y_ofs = atoi(box->y_ofs->value()); // iterate over selected linedefs selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { const LineDef *L = LineDefs[*it]; int sd = box->is_front ? L->right : L->left; if (is_sidedef(sd)) { if (w == box->x_ofs) BA_ChangeSD(sd, SideDef::F_X_OFFSET, new_x_ofs); else BA_ChangeSD(sd, SideDef::F_Y_OFFSET, new_y_ofs); } } BA_End(); } } void UI_SideBox::sector_callback(Fl_Widget *w, void *data) { UI_SideBox *box = (UI_SideBox *)data; int new_sec = atoi(box->sec->value()); new_sec = CLAMP(0, new_sec, NumSectors-1); // iterate over selected linedefs selection_c list; selection_iterator_c it; if (GetCurrentObjects(&list)) { BA_Begin(); for (list.begin(&it); !it.at_end(); ++it) { const LineDef *L = LineDefs[*it]; int sd = box->is_front ? L->right : L->left; if (is_sidedef(sd)) BA_ChangeSD(sd, SideDef::F_SECTOR, new_sec); } BA_End(); } } //------------------------------------------------------------------------ void UI_SideBox::SetObj(int index, int solid_mask, bool two_sided) { if (obj == index && what_is_solid == solid_mask && on_2S_line == two_sided) return; bool hide_change = !(obj == index && on_2S_line == two_sided); obj = index; what_is_solid = solid_mask; on_2S_line = two_sided; if (hide_change) UpdateHiding(); UpdateLabel(); UpdateAddDel(); UpdateField(); if (obj < 0) UnselectPics(); redraw(); } void UI_SideBox::UpdateField() { if (is_sidedef(obj)) { const SideDef *sd = SideDefs[obj]; x_ofs->value(Int_TmpStr(sd->x_offset)); y_ofs->value(Int_TmpStr(sd->y_offset)); sec->value(Int_TmpStr(sd->sector)); const char *lower = sd->LowerTex(); const char *rail = sd->MidTex(); const char *upper = sd->UpperTex(); if (what_is_solid & SOLID_MID) std::swap(lower, rail); l_tex->value(lower); u_tex->value(upper); r_tex->value(rail); l_pic->GetTex(lower); u_pic->GetTex(upper); r_pic->GetTex(rail); if ((what_is_solid & (SOLID_LOWER | SOLID_MID)) && (lower[0] == '-')) l_pic->MarkMissing(); if ((what_is_solid & SOLID_UPPER) && (upper[0] == '-')) u_pic->MarkMissing(); } else { x_ofs->value(""); y_ofs->value(""); sec->value(""); l_tex->value(""); u_tex->value(""); r_tex->value(""); l_pic->Clear(); u_pic->Clear(); r_pic->Clear(); } } void UI_SideBox::UpdateLabel() { if (! is_sidedef(obj)) { label(is_front ? " No Front Sidedef" : " No Back Sidedef"); return; } char buffer[200]; sprintf(buffer, " %s Sidedef: #%d\n", is_front ? "Front" : "Back", obj); copy_label(buffer); } void UI_SideBox::UpdateAddDel() { if (obj == SETOBJ_NO_LINE) { add_button->hide(); del_button->hide(); } else if (! is_sidedef(obj)) { add_button->show(); del_button->hide(); } else { add_button->hide(); del_button->show(); } } void UI_SideBox::UpdateHiding() { if (obj < 0) { x_ofs->hide(); y_ofs->hide(); sec->hide(); l_tex->hide(); u_tex->hide(); r_tex->hide(); l_pic->hide(); u_pic->hide(); r_pic->hide(); } else { x_ofs->show(); y_ofs->show(); sec->show(); l_tex->show(); l_pic->show(); if (on_2S_line || show_full_one_sided) { u_tex->show(); r_tex->show(); u_pic->show(); r_pic->show(); } else { u_tex->hide(); r_tex->hide(); u_pic->hide(); r_pic->hide(); } } } int UI_SideBox::GetSelectedPics() const { return (l_pic->Selected() ? 1 : 0) | (u_pic->Selected() ? 2 : 0) | (r_pic->Selected() ? 4 : 0); } void UI_SideBox::UnselectPics() { l_pic->Selected(false); u_pic->Selected(false); r_pic->Selected(false); } int UI_SideBox::TexFromWidget(Fl_Input *w) { char name[WAD_TEX_NAME+1]; memset(name, 0, sizeof(name)); strncpy(name, w->value(), WAD_TEX_NAME); for (int i = 0 ; i < WAD_TEX_NAME ; i++) name[i] = toupper(name[i]); return BA_InternaliseString(name); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/im_img.cc0000644000175100017510000003631212647061302016033 0ustar aaptedaapted//------------------------------------------------------------------------ // IMAGES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "im_img.h" #include "m_game.h" // Now where did these came from? int gammatable[5][256] = { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 }, { 2, 4, 5, 7, 8, 10, 11, 12, 14, 15, 16, 18, 19, 20, 21, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, 225, 226, 227, 228, 229, 230, 230, 231, 232, 233, 234, 235, 236, 237, 237, 238, 239, 240, 241, 242, 243, 244, 245, 245, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 255 }, { 4, 7, 9, 11, 13, 15, 17, 19, 21, 22, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 40, 42, 43, 45, 46, 47, 48, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 153, 154, 155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 172, 172, 173, 174, 175, 176, 177, 178, 178, 179, 180, 181, 182, 183, 183, 184, 185, 186, 187, 188, 188, 189, 190, 191, 192, 193, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 201, 202, 203, 204, 205, 206, 206, 207, 208, 209, 210, 210, 211, 212, 213, 213, 214, 215, 216, 217, 217, 218, 219, 220, 221, 221, 222, 223, 224, 224, 225, 226, 227, 228, 228, 229, 230, 231, 231, 232, 233, 234, 235, 235, 236, 237, 238, 238, 239, 240, 241, 241, 242, 243, 244, 244, 245, 246, 247, 247, 248, 249, 250, 251, 251, 252, 253, 254, 254, 255 }, { 8, 12, 16, 19, 22, 24, 27, 29, 31, 34, 36, 38, 40, 41, 43, 45, 47, 49, 50, 52, 53, 55, 57, 58, 60, 61, 63, 64, 65, 67, 68, 70, 71, 72, 74, 75, 76, 77, 79, 80, 81, 82, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140, 141, 142, 143, 143, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 165, 165, 166, 167, 168, 169, 169, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 185, 186, 186, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 195, 195, 196, 197, 197, 198, 199, 200, 200, 201, 202, 202, 203, 204, 205, 205, 206, 207, 207, 208, 209, 210, 210, 211, 212, 212, 213, 214, 214, 215, 216, 216, 217, 218, 219, 219, 220, 221, 221, 222, 223, 223, 224, 225, 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, 235, 236, 237, 237, 238, 238, 239, 240, 240, 241, 242, 242, 243, 244, 244, 245, 246, 246, 247, 247, 248, 249, 249, 250, 251, 251, 252, 253, 253, 254, 254, 255 }, { 16, 23, 28, 32, 36, 39, 42, 45, 48, 50, 53, 55, 57, 60, 62, 64, 66, 68, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 93, 94, 96, 97, 98, 100, 101, 102, 103, 105, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 143, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 163, 164, 165, 166, 166, 167, 168, 169, 169, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 177, 178, 179, 180, 180, 181, 182, 182, 183, 184, 184, 185, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194, 195, 195, 196, 196, 197, 198, 198, 199, 200, 200, 201, 202, 202, 203, 203, 204, 205, 205, 206, 207, 207, 208, 208, 209, 210, 210, 211, 211, 212, 213, 213, 214, 214, 215, 216, 216, 217, 217, 218, 219, 219, 220, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 254, 254, 255, 255 } }; //------------------------------------------------------------------------ /* * Img_c::Img_c - default constructor * * The new image is a null image. */ Img_c::Img_c() : pixels(NULL), w(0), h(0) { } /* * Img_c::Img_c - constructor with dimensions * * The new image is set to the specified dimensions. */ Img_c::Img_c(int width, int height, bool _dummy) : pixels(NULL), w(0), h(0) { resize(width, height); } /* * Img_c::~Img_c - destructor */ Img_c::~Img_c() { delete pixels; } /* * Img_c::buf - return a const pointer on the buffer * * If the image is null, return a null pointer. */ const img_pixel_t *Img_c::buf() const { return pixels; } /* * Img_c::wbuf - return a writable pointer on the buffer * * If the image is null, return a null pointer. */ img_pixel_t *Img_c::wbuf() { return pixels; } /* * Img_c::clear - clear the image */ void Img_c::clear() { if (pixels) { memset(pixels, TRANS_PIXEL, w * h); } } /* * Img_c::resize - resize the image * * If either dimension is zero, the image becomes a null * image. */ void Img_c::resize(int new_width, int new_height) { if (new_width == w && new_height == h) return; // Unallocate old buffer if (pixels) { delete[] pixels; pixels = NULL; } // Is it a null image ? if (new_width == 0 || new_height == 0) { w = h = 0; return; } // Allocate new buffer w = new_width; h = new_height; pixels = new img_pixel_t[w * h + 10]; // Some slack clear(); } /* * spectrify_img - make a game image look vaguely like a spectre */ Img_c * Img_c::spectrify() const { Img_c *omg = new Img_c(width(), height()); byte grey = 104; // FIXME GAME CONFIG ITEM if (strcmp(Game_name, "heretic") == 0) grey = 8; int W = width(); int H = height(); const img_pixel_t *src = buf(); img_pixel_t *dest = omg->wbuf(); for (int y = 0 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { img_pixel_t pix = src[y * W + x]; if (pix != TRANS_PIXEL) pix = grey + (rand () >> 6) % 7; // FIXME more kludgery dest[y * W + x] = pix; } return omg; } /* * scale_img - scale a game image * * is the source image, is the destination * image. is the scaling factor (> 1.0 to magnify). * A scaled copy of is put in . is not * modified. Any previous data in is lost. * * Example: * * Img_c raw; * Img_c scaled; * LoadPicture (raw, ...); * scale_img (raw, 2, scaled); * display_img (scaled, ...); * * The implementation is mediocre in the case of scale * factors < 1 because it uses only one source pixel per * destination pixel. On certain patterns, it's likely to * cause a visible loss of quality. * * In the case of scale factors > 1, the algorithm is * suboptimal. * * andrewj: turned into a method, but untested... */ Img_c * Img_c::scale_img(double scale) const { int iwidth = width(); int owidth = (int) (width() * scale + 0.5); int oheight = (int) (height() * scale + 0.5); Img_c *omg = new Img_c(owidth, oheight); const img_pixel_t *const ibuf = buf(); img_pixel_t *const obuf = omg->wbuf(); if (true) { img_pixel_t *orow = obuf; int *ix = new int[owidth]; for (int ox = 0; ox < owidth; ox++) ix[ox] = (int) (ox / scale); const int *const ix_end = ix + owidth; for (int oy = 0; oy < oheight; oy++) { int iy = (int) (oy / scale); const img_pixel_t *const irow = ibuf + iwidth * iy; for (const int *i = ix; i < ix_end; i++) *orow++ = irow[*i]; } delete[] ix; } return omg; } /* * Copy the image, but remap pixels in the range 'src1..src2' to the * range 'targ1..targ2'. */ Img_c * Img_c::color_remap(int src1, int src2, int targ1, int targ2) const { SYS_ASSERT( src1 <= src2); SYS_ASSERT(targ1 <= targ2); Img_c *omg = new Img_c(width(), height()); int W = width(); int H = height(); const img_pixel_t *src = buf(); img_pixel_t *dest = omg->wbuf(); for (int y = 0 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { img_pixel_t pix = src[y * W + x]; if (src1 <= pix && pix <= src2) { int diff = pix - src1; pix = targ1 + diff * (targ2 - targ1 + 1) / (src2 - src1 + 1); } dest[y * W + x] = pix; } return omg; } bool Img_c::has_transparent() const { int W = width(); int H = height(); const img_pixel_t *src = buf(); for (int y = 0 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { if (src[y * W + x] == TRANS_PIXEL) return true; } return false; } //------------------------------------------------------------------------ static int missing_tex_color; static int unknown_tex_color; static int unknown_flat_color; static Img_c * missing_tex_image; static Img_c * unknown_tex_image; static Img_c * unknown_flat_image; void IM_ResetDummyTextures() { missing_tex_color = -1; unknown_tex_color = -1; unknown_flat_color = -1; } static const byte unknown_graphic[16 * 16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,1,1,1,1,0,0,0,0,0,1,1,1,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0, 0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static const byte missing_graphic[16 * 16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static Img_c * IM_CreateDummyTex(const byte *data, int bg, int fg) { Img_c *omg = new Img_c(64, 64, true); img_pixel_t *obuf = omg->wbuf(); for (int y = 0 ; y < 64 ; y++) for (int x = 0 ; x < 64 ; x++) { obuf[y * 64 + x] = data[((y/2) & 15 ) * 16 + ((x/2) & 15)] ? fg : bg; } return omg; } Img_c * IM_MissingTex() { if (! missing_tex_image || missing_tex_color != game_info.missing_color) { missing_tex_color = game_info.missing_color; if (missing_tex_image) delete missing_tex_image; missing_tex_image = IM_CreateDummyTex(missing_graphic, missing_tex_color, 0); } return missing_tex_image; } Img_c * IM_UnknownTex() { if (! unknown_tex_image || unknown_tex_color != game_info.unknown_tex) { unknown_tex_color = game_info.unknown_tex; if (unknown_tex_image) delete unknown_tex_image; unknown_tex_image = IM_CreateDummyTex(unknown_graphic, unknown_tex_color, 0); } return unknown_tex_image; } Img_c * IM_UnknownFlat() { if (! unknown_flat_image || unknown_flat_color != game_info.unknown_flat) { unknown_flat_color = game_info.unknown_flat; if (unknown_flat_image) delete unknown_flat_image; unknown_flat_image = IM_CreateDummyTex(unknown_graphic, unknown_flat_color, 0); } return unknown_flat_image; } Img_c * IM_CreateFromText(int W, int H, const char **text, const rgb_color_t *palette, int pal_size) { Img_c *result = new Img_c(W, H); result->clear(); // translate colors to current palette byte *conv_palette = new byte[pal_size]; for (int c = 0 ; c < pal_size ; c++) conv_palette[c] = W_FindPaletteColor(RGB_RED(palette[c]), RGB_GREEN(palette[c]), RGB_BLUE(palette[c])); for (int y = 0 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { int ch = text[y][x] & 0x7f; if (ch == ' ') continue; // leave transparent if (ch < 'a' || ch >= 'a' + pal_size) BugError("Bad character (dec #%d) in built-in image.\n", ch); result->wbuf() [y * W + x] = conv_palette[ch - 'a']; } delete[] conv_palette; return result; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/w_loadpic.cc0000644000175100017510000001074612647061302016536 0ustar aaptedaapted//------------------------------------------------------------------------ // WAD PIC LOADER //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "im_color.h" /* trans_replace */ #include "im_img.h" #include "w_loadpic.h" #include "w_rawdef.h" #include "w_wad.h" // posts are runs of non masked source pixels typedef struct { // offset down from top. P_SENTINEL terminates the list. byte topdelta; // length data bytes follows byte length; /* byte pixels[length+2] */ } post_t; #define P_SENTINEL 0xFF static void DrawColumn(Img_c& img, const post_t *column, int x, int y) { SYS_ASSERT(column); int W = img.width(); int H = img.height(); // clip horizontally if (x < 0 || x >= W) return; while (column->topdelta != P_SENTINEL) { int top = y + (int) column->topdelta; int count = column->length; byte *src = (byte *) column + 3; byte *dest = img.wbuf() + x; if (top < 0) { count += top; top = 0; } if (top + count > H) count = H - top; // copy the pixels, remapping any TRANS_PIXEL values for (; count > 0; count--, top++) { byte pix = *src++; if (pix == TRANS_PIXEL) pix = trans_replace; dest[top * W] = pix; } column = (const post_t *) ((const byte *) column + column->length + 4); } } /* * LoadPicture - read a picture from a wad file into an Img_c object * * If img->is_null() is false, LoadPicture() does not allocate the * buffer itself. The buffer and the picture don't have to have the * same dimensions. Thanks to this, it can also be used to compose * textures : you allocate a single buffer for the whole texture * and then you call LoadPicture() on it once for each patch. * LoadPicture() takes care of all the necessary clipping. * * If img->is_null() is true, LoadPicture() sets the size of img * to match that of the picture. This is useful in display_pic(). * * Return true on success, false on failure. * * If pic_x_offset == INT_MIN, the picture is centred horizontally. * If pic_y_offset == INT_MIN, the picture is centred vertically. */ bool LoadPicture(Img_c& img, // image to load picture into Lump_c *lump, const char *pic_name, // Picture name (for messages) int pic_x_offset, // Coordinates of top left corner of picture int pic_y_offset, // relative to top left corner of buffer int *pic_width, // To return the size of the picture int *pic_height) // (can be NULL) { byte *raw_data; W_LoadLumpData(lump, &raw_data); const patch_t *pat = (patch_t *) raw_data; int width = LE_S16(pat->width); int height = LE_S16(pat->height); // int offset_x = LE_S16(pat->leftoffset); // int offset_y = LE_S16(pat->topoffset); // FIXME: validate values (in case we got flat data or so) if (pic_width) *pic_width = width; if (pic_height) *pic_height = height; if (img.is_null()) { // our new image will be completely transparent img.resize (width, height); } // Centre the picture? if (pic_x_offset == INT_MIN) pic_x_offset = (img.width() - width) / 2; if (pic_y_offset == INT_MIN) pic_y_offset = (img.height() - height) / 2; for (int x = 0 ; x < width ; x++) { int offset = LE_S32(pat->columnofs[x]); if (offset < 0 || offset >= lump->Length()) { LogPrintf("WARNING: bad image offset 0x%08x in patch [%s]\n", offset, pic_name); return false; } const post_t *column = (const post_t *) ((const byte *)pat + offset); DrawColumn(img, column, pic_x_offset + x, pic_y_offset); } W_FreeLumpData(&raw_data); return true; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/lib_adler.h0000644000175100017510000000507012647061302016346 0ustar aaptedaapted//------------------------------------------------------------------------ // ADLER-32 CHECKSUM //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2012 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 is the Adler-32 algorithm as described in RFC-1950. // // The 'extra' field is my own adaptation to provide an extra 32 bits // of checksum. This should make collisions a lot less likely (though // how much remains to be seen -- definitely not the full 32 bits!). // //------------------------------------------------------------------------ #ifndef __LIB_CRC_H__ #define __LIB_CRC_H__ class crc32_c { public: u32_t raw; u32_t extra; private: static const u32_t INIT_VALUE = 1; public: crc32_c() : raw(INIT_VALUE), extra(0) { } crc32_c(const crc32_c &rhs) { raw = rhs.raw; extra = rhs.extra; } ~crc32_c() { } void Reset(void) { raw = INIT_VALUE; extra = 0; } crc32_c& operator= (const crc32_c &rhs) { raw = rhs.raw; extra = rhs.extra; return *this; } crc32_c& operator+= (u8_t value); crc32_c& operator+= (s8_t value); crc32_c& operator+= (u16_t value); crc32_c& operator+= (s16_t value); crc32_c& operator+= (u32_t value); crc32_c& operator+= (s32_t value); crc32_c& operator+= (float value); crc32_c& operator+= (bool value); crc32_c& AddBlock(const u8_t *data, int len); crc32_c& AddCStr(const char *str); // TODO: operator== and operator!= }; //------------------------------------------------------------------------ // IMPLEMENTATION //------------------------------------------------------------------------ inline crc32_c& crc32_c::operator+= (s8_t value) { *this += (u8_t) value; return *this; } inline crc32_c& crc32_c::operator+= (s16_t value) { *this += (u16_t) value; return *this; } inline crc32_c& crc32_c::operator+= (s32_t value) { *this += (u32_t) value; return *this; } inline crc32_c& crc32_c::operator+= (bool value) { *this += (value ? (u8_t)1 : (u8_t)0); return *this; } #endif // __LIB_CRC_H__ eureka-1.11-source/src/ui_default.cc0000644000175100017510000002461512647061302016716 0ustar aaptedaapted//------------------------------------------------------------------------ // DEFAULT PROPERTIES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 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 "main.h" #include "ui_window.h" #include "levels.h" #include "m_config.h" // gui_scheme #include "m_game.h" #include "w_rawdef.h" #define HIDE_BG (gui_scheme == 2 ? FL_DARK3 : FL_DARK1) UI_DefaultProps::UI_DefaultProps(int X, int Y, int W, int H) : Fl_Group(X, Y, W, H, NULL) { box(FL_FLAT_BOX); Fl_Button *hide_button = new Fl_Button(X + 14, Y + 14, 22, 22, "X"); hide_button->color(HIDE_BG, HIDE_BG); hide_button->labelsize(14); hide_button->callback(hide_callback, this); Fl_Box *title = new Fl_Box(X + 60, Y + 10, W - 70, 30, "Default Properties"); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); title->labelsize(18+KF*4); Y += 35; H -= 35; X += 6; W -= 12; // ---- LINEDEF TEXTURES ------------ Y += 32; w_pic = new UI_Pic(X+W-76, Y, 64, 64); w_pic->callback(tex_callback, this); Y += 20; w_tex = new Fl_Input(X+68, Y, 108, 24, "Wall: "); w_tex->callback(tex_callback, this); w_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += w_tex->h() + 50; // ---- SECTOR PROPS -------------- c_pic = new UI_Pic(X+W-76, Y+2, 64, 64); f_pic = new UI_Pic(X+W-76, Y+78, 64, 64); c_pic->callback(flat_callback, this); f_pic->callback(flat_callback, this); c_tex = new Fl_Input(X+68, Y, 108, 24, "Ceiling: "); c_tex->align(FL_ALIGN_LEFT); c_tex->callback(flat_callback, this); c_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += c_tex->h() + 3; ceil_h = new Fl_Int_Input(X+68, Y, 64, 24, ""); ceil_h->align(FL_ALIGN_LEFT); ceil_h->callback(height_callback, this); ceil_h->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); ce_down = new Fl_Button(X+24, Y+1, 30, 22, "-"); ce_up = new Fl_Button(X+68+68, Y+1, 30, 22, "+"); ce_down->labelfont(FL_HELVETICA_BOLD); ce_up ->labelfont(FL_HELVETICA_BOLD); ce_down->labelsize(16); ce_up ->labelsize(16); ce_down->callback(button_callback, this); ce_up ->callback(button_callback, this); Y += ceil_h->h() + 8; floor_h = new Fl_Int_Input(X+68, Y, 64, 24, ""); floor_h->align(FL_ALIGN_LEFT); floor_h->callback(height_callback, this); floor_h->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); fl_down = new Fl_Button(X+24, Y+1, 30, 22, "-"); fl_up = new Fl_Button(X+68+68, Y+1, 30, 22, "+"); fl_down->labelfont(FL_HELVETICA_BOLD); fl_up ->labelfont(FL_HELVETICA_BOLD); fl_down->labelsize(16); fl_up ->labelsize(16); fl_down->callback(button_callback, this); fl_up ->callback(button_callback, this); Y += floor_h->h() + 3; f_tex = new Fl_Input(X+68, Y, 108, 24, "Floor: "); f_tex->align(FL_ALIGN_LEFT); f_tex->callback(flat_callback, this); f_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += f_tex->h() + 8; light = new Fl_Int_Input(X+68, Y, 64, 24, "Light: "); light->align(FL_ALIGN_LEFT); light->callback(height_callback, this); light->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += light->h() + 40; // ---- THING PROPS -------------- thing = new Fl_Int_Input(X+60, Y+20, 64, 24, "Thing: "); thing->align(FL_ALIGN_LEFT); thing->callback(thing_callback, this); thing->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); th_desc = new Fl_Output(X+60, Y+80-26, 122, 24); th_sprite = new UI_Pic(X+W-90, Y, 80,80, "Sprite"); th_sprite->callback(thing_callback, this); resizable(NULL); end(); } UI_DefaultProps::~UI_DefaultProps() { } void UI_DefaultProps::hide_callback(Fl_Widget *w, void *data) { main_win->HideSpecialPanel(); } void UI_DefaultProps::SetIntVal(Fl_Int_Input *w, int value) { char buffer[64]; sprintf(buffer, "%d", value); w->value(buffer); } void UI_DefaultProps::UpdateThingDesc() { const thingtype_t *info = M_GetThingType(default_thing); th_desc->value(info->desc); th_sprite->GetSprite(default_thing, FL_DARK2); } void UI_DefaultProps::SetTexture(const char *name, int e_state) { w_tex->value(name); w_tex->do_callback(); } void UI_DefaultProps::SetFlat(const char *name, int e_state) { // same logic as in UI_SectorBox::SetFlat() int sel_pics = (f_pic->Selected() ? 1 : 0) | (c_pic->Selected() ? 2 : 0); if (sel_pics == 0) sel_pics = (e_state & FL_BUTTON3) ? 2 : 1; if (sel_pics & 1) { f_tex->value(name); f_tex->do_callback(); } if (sel_pics & 2) { c_tex->value(name); c_tex->do_callback(); } } void UI_DefaultProps::SetThing(int number) { default_thing = number; SetIntVal(thing, default_thing); UpdateThingDesc(); } void UI_DefaultProps::UnselectPicSet(char what /* 'f' or 't' */) { if (what == 'f') { f_pic->Selected(false); c_pic->Selected(false); } if (what == 't') { w_pic->Selected(false); } } const char * UI_DefaultProps::NormalizeTex_and_Dup(Fl_Input *w) { char name[WAD_TEX_NAME + 1]; memset(name, 0, sizeof(name)); strncpy(name, w->value(), WAD_TEX_NAME); for (int i = 0 ; i < WAD_TEX_NAME ; i++) name[i] = toupper(name[i]); w->value(name); return StringDup(name); } void UI_DefaultProps::tex_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; if (w == box->w_pic) { UI_Pic * pic = (UI_Pic *) w; pic->Selected(! pic->Selected()); pic->redraw(); if (pic->Selected()) { box->UnselectPicSet('f'); main_win->ShowBrowser('T'); } return; } if (w == box->w_tex) { default_lower_tex = NormalizeTex_and_Dup(box->w_tex); default_mid_tex = default_lower_tex; default_upper_tex = default_lower_tex; } box->w_pic->GetTex(box->w_tex->value()); } void UI_DefaultProps::flat_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; if (w == box->f_pic || w == box->c_pic) { UI_Pic * pic = (UI_Pic *) w; pic->Selected(! pic->Selected()); pic->redraw(); if (pic->Selected()) { box->UnselectPicSet('t'); main_win->ShowBrowser('F'); } return; } if (w == box->f_tex) default_floor_tex = NormalizeTex_and_Dup(box->f_tex); if (w == box->c_tex) default_ceil_tex = NormalizeTex_and_Dup(box->c_tex); box->f_pic->GetFlat(box->f_tex->value()); box->c_pic->GetFlat(box->c_tex->value()); } void UI_DefaultProps::button_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; int diff = 8; if (Fl::event_shift()) diff = 1; else if (Fl::event_ctrl()) diff = 64; if (w == box->fl_up) default_floor_h += diff; if (w == box->fl_down) default_floor_h -= diff; if (w == box->ce_up) default_ceil_h += diff; if (w == box->ce_down) default_ceil_h -= diff; box->SetIntVal(box->floor_h, default_floor_h); box->SetIntVal(box-> ceil_h, default_ceil_h); } void UI_DefaultProps::height_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; default_floor_h = atoi(box->floor_h->value()); default_ceil_h = atoi(box-> ceil_h->value()); default_light_level = atoi(box->light->value()); } void UI_DefaultProps::thing_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; if (w == box->th_sprite) { main_win->ShowBrowser('O'); return; } default_thing = atoi(box->thing->value()); box->UpdateThingDesc(); } void UI_DefaultProps::LoadValues() { w_tex->value(default_lower_tex); f_tex->value(default_floor_tex); c_tex->value(default_ceil_tex); w_pic->GetTex (w_tex->value()); f_pic->GetFlat(f_tex->value()); c_pic->GetFlat(c_tex->value()); SetIntVal(floor_h, default_floor_h); SetIntVal( ceil_h, default_ceil_h); SetIntVal( light, default_light_level); SetIntVal( thing, default_thing); UpdateThingDesc(); } void UI_DefaultProps::BrowsedItem(char kind, int number, const char *name, int e_state) { if (! visible()) { fl_beep(); return; } switch (kind) { case 'T': SetTexture(name, e_state); break; case 'F': SetFlat (name, e_state); break; case 'O': SetThing(number); break; default: fl_beep(); break; } } void UI_DefaultProps::UnselectPics() { UnselectPicSet('f'); UnselectPicSet('t'); } //------------------------------------------------------------------------ bool Props_ParseUser(const char ** tokens, int num_tok) { // syntax is: default if (num_tok < 3) return false; if (strcmp(tokens[0], "default") != 0) return false; if (strcmp(tokens[1], "is_shown") == 0) { /* ignored for backwards compat */ } if (strcmp(tokens[1], "floor_h") == 0) default_floor_h = atoi(tokens[2]); if (strcmp(tokens[1], "ceil_h") == 0) default_ceil_h = atoi(tokens[2]); if (strcmp(tokens[1], "light_level") == 0) default_light_level = atoi(tokens[2]); if (strcmp(tokens[1], "thing") == 0) default_thing = atoi(tokens[2]); if (strcmp(tokens[1], "floor_tex") == 0) default_floor_tex = StringDup(tokens[2]); if (strcmp(tokens[1], "ceil_tex") == 0) default_ceil_tex = StringDup(tokens[2]); if (strcmp(tokens[1], "lower_tex") == 0) default_lower_tex = StringDup(tokens[2]); if (strcmp(tokens[1], "mid_tex") == 0) default_mid_tex = StringDup(tokens[2]); if (strcmp(tokens[1], "upper_tex") == 0) default_upper_tex = StringDup(tokens[2]); return true; } void Props_WriteUser(FILE *fp) { fprintf(fp, "\n"); fprintf(fp, "default floor_h %d\n", default_floor_h); fprintf(fp, "default ceil_h %d\n", default_ceil_h); fprintf(fp, "default light_level %d\n", default_light_level); fprintf(fp, "default thing %d\n", default_thing); fprintf(fp, "default floor_tex \"%s\"\n", StringTidy(default_floor_tex, "\"")); fprintf(fp, "default ceil_tex \"%s\"\n", StringTidy(default_ceil_tex, "\"")); fprintf(fp, "default lower_tex \"%s\"\n", StringTidy(default_lower_tex, "\"")); fprintf(fp, "default mid_tex \"%s\"\n", StringTidy(default_mid_tex, "\"")); fprintf(fp, "default upper_tex \"%s\"\n", StringTidy(default_upper_tex, "\"")); } void Props_LoadValues() { if (main_win) main_win->props_box->LoadValues(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_window.cc0000644000175100017510000003427312647613317016613 0ustar aaptedaapted//------------------------------------------------------------------------ // MAIN WINDOW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2015 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 "main.h" #include "m_config.h" #include "ui_window.h" #include "w_wad.h" #ifndef WIN32 #include #endif #if (FL_MAJOR_VERSION != 1 || \ FL_MINOR_VERSION != 3 || \ FL_PATCH_VERSION < 0) #error "Require FLTK version 1.3.0 or later" #endif UI_MainWin *main_win; #define MAIN_WINDOW_W (800 - 32) #define MAIN_WINDOW_H (600 - 40) static void main_win_close_CB(Fl_Widget *w, void *data) { CMD_Quit(); } // // MainWin Constructor // UI_MainWin::UI_MainWin() : Fl_Double_Window(MAIN_WINDOW_W, MAIN_WINDOW_H, EUREKA_TITLE), cursor_shape(FL_CURSOR_DEFAULT), last_x(0), last_y(0), last_w(0), last_h(0) { end(); // cancel begin() in Fl_Group constructor size_range(MAIN_WINDOW_W, MAIN_WINDOW_H); callback((Fl_Callback *) main_win_close_CB); color(WINDOW_BG, WINDOW_BG); int cy = 0; int ey = h(); panel_W = 276 + KF * 32; /* ---- Menu bar ---- */ { menu_bar = Menu_Create(0, 0, w()-3 - panel_W, 28+KF*3); add(menu_bar); #ifndef __APPLE__ cy += menu_bar->h(); #endif } info_bar = new UI_InfoBar(0, ey - (28+KF*3), w(), 28+KF*3); add(info_bar); ey = ey - info_bar->h(); int browser_W = MIN_BROWSER_W + 66; int cw = w() - panel_W - browser_W; int ch = ey - cy; scroll = new UI_CanvasScroll(0, cy, cw, ch); canvas = scroll->canvas; render = scroll->render; browser = new UI_Browser(w() - panel_W - browser_W, cy, browser_W, ey - cy); tile = new UI_Tile(0, cy, w() - panel_W, ey - cy, NULL, scroll, browser); add(tile); resizable(tile); int BY = 0; // cy+2 int BH = ey-4; // ey-BY-2 thing_box = new UI_ThingBox(w() - panel_W, BY, panel_W, BH); add(thing_box); line_box = new UI_LineBox(w() - panel_W, BY, panel_W, BH); line_box->hide(); add(line_box); sec_box = new UI_SectorBox(w() - panel_W, BY, panel_W, BH); sec_box->hide(); add(sec_box); vert_box = new UI_VertexBox(w() - panel_W, BY, panel_W, BH); vert_box->hide(); add(vert_box); props_box = new UI_DefaultProps(w() - panel_W, BY, panel_W, BH); props_box->hide(); add(props_box); find_box = new UI_FindAndReplace(w() - panel_W, BY, panel_W, BH); find_box->hide(); add(find_box); } // // MainWin Destructor // UI_MainWin::~UI_MainWin() { } void UI_MainWin::NewEditMode(obj_type_e mode) { UnselectPics(); thing_box->hide(); line_box->hide(); sec_box->hide(); vert_box->hide(); props_box->hide(); find_box->hide(); switch (mode) { case OBJ_THINGS: thing_box->show(); break; case OBJ_LINEDEFS: line_box->show(); break; case OBJ_SECTORS: sec_box->show(); break; case OBJ_VERTICES: vert_box->show(); break; default: break; } info_bar->NewEditMode(mode); browser ->NewEditMode(mode); redraw(); } void UI_MainWin::SetCursor(Fl_Cursor shape) { if (shape == cursor_shape) return; cursor_shape = shape; cursor(shape); } void UI_MainWin::ShowBrowser(char kind) { bool is_visible = browser->visible() ? true : false; if (kind == '-' || (is_visible && kind == '/')) kind = 0; bool want_visible = (kind != 0) ? true : false; if (is_visible != want_visible) { if (want_visible) tile->ShowRight(); else tile->HideRight(); // hiding the browser also clears any pic selection if (! want_visible) UnselectPics(); } if (kind != 0 && kind != '/') { browser->ChangeMode(kind); } } void UI_MainWin::HideSpecialPanel() { props_box->hide(); find_box->hide(); switch (edit.mode) { case OBJ_THINGS: thing_box->show(); break; case OBJ_LINEDEFS: line_box->show(); break; case OBJ_VERTICES: vert_box->show(); break; case OBJ_SECTORS: sec_box->show(); break; default: break; } redraw(); } void UI_MainWin::ShowDefaultProps() { // already shown? if (props_box->visible()) { HideSpecialPanel(); return; } thing_box->hide(); line_box->hide(); sec_box->hide(); vert_box->hide(); find_box->hide(); props_box->show(); redraw(); } void UI_MainWin::ShowFindAndReplace() { // already shown? if (find_box->visible()) { HideSpecialPanel(); return; } thing_box->hide(); line_box->hide(); sec_box->hide(); vert_box->hide(); props_box->hide(); find_box->Open(); redraw(); } void UI_MainWin::UpdateTotals() { thing_box->UpdateTotal(); line_box->UpdateTotal(); sec_box->UpdateTotal(); vert_box->UpdateTotal(); } int UI_MainWin::GetPanelObjNum() const { // FIXME: using 'edit' here feels like a hack or mis-design switch (edit.mode) { case OBJ_THINGS: return thing_box->GetObj(); case OBJ_VERTICES: return vert_box->GetObj(); case OBJ_SECTORS: return sec_box->GetObj(); case OBJ_LINEDEFS: return line_box->GetObj(); default: return -1; } } void UI_MainWin::InvalidatePanelObj() { if (thing_box->visible()) thing_box->SetObj(-1, 0); if (line_box->visible()) line_box->SetObj(-1, 0); if (sec_box->visible()) sec_box->SetObj(-1, 0); if (vert_box->visible()) vert_box->SetObj(-1, 0); } void UI_MainWin::UpdatePanelObj() { if (thing_box->visible()) thing_box->UpdateField(); if (line_box->visible()) { line_box->UpdateField(); line_box->UpdateSides(); } if (sec_box->visible()) sec_box->UpdateField(); if (vert_box->visible()) vert_box->UpdateField(); } void UI_MainWin::UnselectPics() { line_box->UnselectPics(); sec_box->UnselectPics(); props_box->UnselectPics(); } void UI_MainWin::SetTitle(const char *wad_name, const char *map_name, bool read_only) { static char title_buf[FL_PATH_MAX]; if (wad_name) { wad_name = fl_filename_name(wad_name); sprintf(title_buf, "%s (%s)%s", wad_name, Level_name, read_only ? " [Read-Only]" : ""); } else { sprintf(title_buf, "Unsaved %s", Level_name); } // this just seems like visual noise, disabled for now #if 0 strcat(title_buf, " - Eureka"); #endif copy_label(title_buf); } void UI_MainWin::UpdateTitle(char want_prefix) { if (! label()) return; char got_prefix = label()[0]; if (! ispunct(got_prefix)) got_prefix = 0; if (got_prefix == want_prefix) return; static char title_buf[FL_PATH_MAX]; const char *src = label() + (got_prefix ? 1 : 0); char *dest = title_buf; if (want_prefix) { *dest++ = want_prefix; } strcpy(dest, src); copy_label(title_buf); } /* DISABLED, since it fails miserably on every platform void UI_MainWin::ToggleFullscreen() { if (last_w) { fullscreen_off(last_x, last_y, last_w, last_h); last_w = last_h = 0; } else { last_x = x(); last_y = y(); last_w = w(); last_h = h(); fullscreen(); } } */ void UI_MainWin::BrowsedItem(char kind, int number, const char *name, int e_state) { // fprintf(stderr, "BrowsedItem: kind '%c' --> %d / \"%s\"\n", kind, number, name); if (props_box->visible()) { props_box->BrowsedItem(kind, number, name, e_state); return; } if (find_box->visible()) { find_box->BrowsedItem(kind, number, name, e_state); return; } switch (edit.mode) { case OBJ_LINEDEFS: if (kind == 'T') { line_box->SetTexture(name, e_state); return; } if (kind == 'L') { line_box->SetLineType(number); return; } break; case OBJ_SECTORS: if (kind == 'F') { sec_box->SetFlat(name, e_state); return; } if (kind == 'S') { sec_box->SetSectorType(number); return; } break; case OBJ_THINGS: if (kind == 'O') { thing_box->SetThingType(number); return; } if (kind == 'L' && Level_format == MAPF_Hexen) { thing_box->SetSpecialType(number); return; } break; default: break; } fl_beep(); } void UI_MainWin::Maximize() { #if defined(WIN32) HWND hWnd = fl_xid(this); ShowWindow(hWnd, SW_MAXIMIZE); #elif defined(__APPLE__) // FIXME : something like this... (AFAIK) // // Window handle = fl_xid(this); // really an NSWindow * // // if (! [handle isZoomed]) // [handle zoom:nil]; #else /* Linux + X11 */ Window xid = fl_xid(this); Atom wm_state = XInternAtom(fl_display, "_NET_WM_STATE", False); Atom vmax = XInternAtom(fl_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); Atom hmax = XInternAtom(fl_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); XEvent xev; memset(&xev, 0, sizeof(xev)); xev.type = ClientMessage; xev.xclient.window = xid; xev.xclient.message_type = wm_state; xev.xclient.format = 32; xev.xclient.data.l[0] = 2; xev.xclient.data.l[1] = hmax; xev.xclient.data.l[2] = vmax; XSendEvent(fl_display, DefaultRootWindow(fl_display), False, SubstructureNotifyMask, &xev); Delay(3); #endif } void UI_MainWin::Delay(int steps) { for (; steps > 0 ; steps--) { TimeDelay(100); Fl::check(); } } void UI_MainWin::UpdateGameInfo() { thing_box->UpdateGameInfo(); line_box->UpdateGameInfo(); sec_box->UpdateGameInfo(); } //------------------------------------------------------------------------ UI_Escapable_Window::UI_Escapable_Window(int W, int H, const char *L) : Fl_Double_Window(W, H, L) { } UI_Escapable_Window::~UI_Escapable_Window() { } int UI_Escapable_Window::handle(int event) { if (event == FL_KEYDOWN && Fl::event_key() == FL_Escape) { do_callback(); return 1; } return Fl_Double_Window::handle(event); } //------------------------------------------------------------------------ #define MAX_LOG_LINES 1000 UI_LogViewer * log_viewer; UI_LogViewer::UI_LogViewer() : UI_Escapable_Window(580, 400, "Eureka Log Viewer") { box(FL_NO_BOX); size_range(480, 200); int ey = h() - 65; browser = new Fl_Multi_Browser(0, 0, w(), ey); browser->textsize(16); browser->callback(select_callback, this); resizable(browser); { Fl_Group *o = new Fl_Group(0, ey, w(), h() - ey); o->box(FL_FLAT_BOX); if (gui_color_set == 2) o->color(fl_gray_ramp(4)); else o->color(WINDOW_BG); int bx = w() - 110; int bx2 = bx; { Fl_Button * but = new Fl_Button(bx, ey + 15, 80, 35, "Close"); but->labelfont(1); but->callback(ok_callback, this); } bx = 30; { Fl_Button * but = new Fl_Button(bx, ey + 15, 80, 35, "Save..."); but->callback(save_callback, this); } bx += 105; { Fl_Button * but = new Fl_Button(bx, ey + 15, 80, 35, "Clear"); but->callback(clear_callback, this); } bx += 105; { copy_but = new Fl_Button(bx, ey + 15, 80, 35, "Copy"); copy_but->callback(copy_callback, this); copy_but->shortcut(FL_CTRL + 'c'); copy_but->deactivate(); } bx += 80; Fl_Group *resize_box = new Fl_Group(bx + 10, ey + 2, bx2 - bx - 20, h() - ey - 4); resize_box->box(FL_NO_BOX); o->resizable(resize_box); o->end(); } end(); } UI_LogViewer::~UI_LogViewer() { } void UI_LogViewer::Deselect() { browser->deselect(); copy_but->deactivate(); } void UI_LogViewer::JumpEnd() { if (browser->size() > 0) { browser->bottomline(browser->size()); } } int UI_LogViewer::CountSelectedLines() const { int count = 0; for (int i = 1 ; i <= browser->size() ; i++) if (browser->selected(i)) count++; return count; } char * UI_LogViewer::GetSelectedText() const { char *buf = StringDup(""); for (int i = 1 ; i <= browser->size() ; i++) { if (! browser->selected(i)) continue; const char *line_text = browser->text(i); if (! line_text) continue; // append current line onto previous ones int new_len = (int)strlen(buf) + (int)strlen(line_text); char *new_buf = StringNew(new_len + 1 /* newline */ ); strcpy(new_buf, buf); strcat(new_buf, line_text); if (new_len > 0 && new_buf[new_len - 1] != '\n') { new_buf[new_len++] = '\n'; new_buf[new_len] = 0; } StringFree(buf); buf = new_buf; } return buf; } void UI_LogViewer::Add(const char *line) { browser->add(line); if (browser->size() > MAX_LOG_LINES) browser->remove(1); if (shown()) browser->bottomline(browser->size()); } void LogViewer_AddLine(const char *str) { if (log_viewer) log_viewer->Add(str); } void UI_LogViewer::ok_callback(Fl_Widget *w, void *data) { UI_LogViewer *that = (UI_LogViewer *)data; that->do_callback(); } void UI_LogViewer::clear_callback(Fl_Widget *w, void *data) { UI_LogViewer *that = (UI_LogViewer *)data; that->browser->clear(); that->copy_but->deactivate(); that->Add(""); } void UI_LogViewer::select_callback(Fl_Widget *w, void *data) { UI_LogViewer *that = (UI_LogViewer *)data; // require 2 or more lines to activate Copy button if (that->CountSelectedLines() >= 2) that->copy_but->activate(); else that->copy_but->deactivate(); } void UI_LogViewer::copy_callback(Fl_Widget *w, void *data) { UI_LogViewer *that = (UI_LogViewer *)data; const char *text = that->GetSelectedText(); if (text[0]) { Fl::copy(text, (int)strlen(text), 1); } StringFree(text); } void UI_LogViewer::save_callback(Fl_Widget *w, void *data) { Fl_Native_File_Chooser chooser; chooser.title("Pick file to save to"); chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); chooser.filter("Text files\t*.txt"); switch (chooser.show()) { case -1: DLG_Notify("Unable to save the log file:\n\n%s", chooser.errmsg()); return; case 1: // cancelled return; default: break; // OK } // add an extension if missing static char filename[FL_PATH_MAX]; strcpy(filename, chooser.filename()); if (! HasExtension(filename)) strcat(filename, ".txt"); FILE *fp = fopen(filename, "w"); if (! fp) { sprintf(filename, "%s", strerror(errno)); DLG_Notify("Unable to save the log file:\n\n%s", filename); return; } LogSaveTo(fp); fclose(fp); } void LogViewer_Open() { if (! log_viewer) return; if (! log_viewer->shown()) { log_viewer->show(); log_viewer->Deselect(); } log_viewer->JumpEnd(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/ui_dialog.cc0000644000175100017510000001512012647061302016520 0ustar aaptedaapted//------------------------------------------------------------------------ // DIALOG when all fucked up //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2013 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 "main.h" #include "ui_window.h" #define BUT_W 100 #define BUT_H 26 #define ICON_W 40 #define ICON_H 40 #define FONT_SIZE 16 static int dialog_result; static void dialog_close_callback(Fl_Widget *w, void *data) { dialog_result = 0; } static void dialog_button_callback(Fl_Widget *w, void *data) { dialog_result = (int)(long)data; } static int DialogShowAndRun(char icon_type, const char *message, const char *title, const char *link_title = NULL, const char *link_url = NULL, std::vector *labels = NULL) { dialog_result = -1; // determine required size int mesg_W = 480; // NOTE: fl_measure will wrap to this! int mesg_H = 0; fl_font(FL_HELVETICA, FONT_SIZE); fl_measure(message, mesg_W, mesg_H); if (mesg_W < 200) mesg_W = 200; if (mesg_H < 60) mesg_H = 60; // add a little wiggle room mesg_W += 16; mesg_H += 8; int total_W = 10 + ICON_W + 10 + mesg_W + 10; int total_H = 10 + mesg_H + 10; if (link_title) total_H += FONT_SIZE + 8; total_H += 12 + BUT_H + 12; // create window... UI_Escapable_Window *dialog = new UI_Escapable_Window(total_W, total_H, title); dialog->size_range(total_W, total_H, total_W, total_H); dialog->callback((Fl_Callback *) dialog_close_callback); // create the error icon... Fl_Box *icon = new Fl_Box(10, 10 + (10 + mesg_H - ICON_H) / 2, ICON_W, ICON_H, ""); icon->box(FL_OVAL_BOX); icon->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); icon->labelfont(FL_HELVETICA_BOLD); icon->labelsize(26); if (icon_type == '!') { icon->label("!"); icon->color(FL_RED, FL_RED); icon->labelcolor(FL_WHITE); } else if (icon_type == '?') { icon->label("?"); icon->color(FL_GREEN, FL_GREEN); icon->labelcolor(FL_BLACK); } else { icon->label("i"); icon->color(FL_BLUE, FL_BLUE); icon->labelcolor(FL_WHITE); } // create the message area... Fl_Box *box = new Fl_Box(ICON_W + 20, 10, mesg_W, mesg_H, message); box->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_WRAP); box->labelfont(FL_HELVETICA); box->labelsize(FONT_SIZE); // create the hyperlink... if (link_title) { SYS_ASSERT(link_url); UI_HyperLink *link = new UI_HyperLink(ICON_W + 20, 10 + mesg_H, mesg_W, 24, link_title, link_url); link->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); link->labelfont(FL_HELVETICA); link->labelsize(FONT_SIZE); } // create buttons... int GROUP_H = BUT_H + 12 * 2; Fl_Button *focus_button = NULL; Fl_Group *b_group = new Fl_Group(0, total_H - GROUP_H, total_W, GROUP_H); b_group->box(FL_FLAT_BOX); b_group->color(WINDOW_BG, WINDOW_BG); b_group->end(); int but_count = labels ? (int)labels->size() : 1; int but_x = total_W - 40; int but_y = b_group->y() + 12; for (int b = but_count - 1 ; b >= 0 ; b--) { const char *text = labels ? (*labels)[b].c_str() : (icon_type == '?') ? "OK" : "Close"; int b_width = fl_width(text) + 20; Fl_Button *button = new Fl_Button(but_x - b_width, but_y, b_width, BUT_H, text); button->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); button->callback((Fl_Callback *) dialog_button_callback, (void *)(long)b); b_group->insert(*button, 0); but_x = but_x - b_width - 40; // left-most button should get the focus focus_button = button; } dialog->end(); // show time! if (focus_button) dialog->hotspot(focus_button); dialog->set_modal(); dialog->show(); if (icon_type == '!') fl_beep(); if (focus_button) Fl::focus(focus_button); // run the GUI and let user make their choice while (dialog_result < 0) { Fl::wait(); } // delete window (automatically deletes child widgets) delete dialog; return dialog_result; } static void ParseHyperLink(char *buffer, unsigned int buf_len, const char ** link_title, const char ** link_url) { // the syntax for a hyperlink is similar to HTML :- // Title char *pos = strstr(buffer, ""); if (! pos) // malformed : oh well return; // terminate the URL here pos[0] = 0; pos++; *link_title = pos; pos = strstr(pos, "<"); if (pos) pos[0] = 0; } static void ParseButtons(const char *buttons, std::vector& labels) { for (;;) { const char *p = strchr(buttons, '|'); if (! p) { labels.push_back(buttons); return; } int len = (int)(p - buttons); SYS_ASSERT(len > 0); labels.push_back(std::string(buttons, len)); buttons = p + 1; } } //------------------------------------------------------------------------ static char dialog_buffer[MSG_BUF_LEN]; void DLG_ShowError(const char *msg, ...) { va_list arg_pt; va_start (arg_pt, msg); vsnprintf (dialog_buffer, MSG_BUF_LEN, msg, arg_pt); va_end (arg_pt); dialog_buffer[MSG_BUF_LEN-1] = 0; const char *link_title = NULL; const char *link_url = NULL; // handle error messages with a hyperlink at the end ParseHyperLink(dialog_buffer, sizeof(dialog_buffer), &link_title, &link_url); DialogShowAndRun('!', dialog_buffer, "Eureka - Fatal Error", link_title, link_url); } void DLG_Notify(const char *msg, ...) { va_list arg_pt; va_start (arg_pt, msg); vsnprintf (dialog_buffer, MSG_BUF_LEN, msg, arg_pt); va_end (arg_pt); dialog_buffer[MSG_BUF_LEN-1] = 0; DialogShowAndRun('i', dialog_buffer, "Eureka - Notification"); } int DLG_Confirm(const char *buttons, const char *msg, ...) { va_list arg_pt; va_start (arg_pt, msg); vsnprintf (dialog_buffer, MSG_BUF_LEN, msg, arg_pt); va_end (arg_pt); dialog_buffer[MSG_BUF_LEN-1] = 0; std::vector labels; ParseButtons(buttons, labels); return DialogShowAndRun('?', dialog_buffer, "Eureka - Confirmation", NULL, NULL, &labels); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/im_color.h0000644000175100017510000000615612647061302016242 0ustar aaptedaapted//------------------------------------------------------------------------ // COLORS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_IM_COLOR_H__ #define __EUREKA_IM_COLOR_H__ typedef u32_t rgb_color_t; #define RGB_RED(col) ((col >> 24) & 255) #define RGB_GREEN(col) ((col >> 16) & 255) #define RGB_BLUE(col) ((col >> 8) & 255) #define RGB_MAKE(r, g, b) (((r) << 24) | ((g) << 16) | ((b) << 8)) extern int usegamma; extern rgb_color_t palette[256]; // palette color closest to palette[TRANS_PIXEL] extern int trans_replace; extern byte raw_colormap[32][256]; extern byte bright_map[256]; void W_UpdateGamma(); void W_LoadPalette(); void W_LoadColormap(); byte W_FindPaletteColor(int r, int g, int b); void W_CreateBrightMap(); // make the color darker rgb_color_t DarkerColor(rgb_color_t col); rgb_color_t ParseColor(const char *str); rgb_color_t SectorLightColor(int light); //------------------------------------------------------------// #define BLACK FL_BLACK #define BLUE FL_BLUE #define GREEN FL_GREEN #define CYAN FL_CYAN #define RED FL_RED #define MAGENTA FL_MAGENTA #define BROWN FL_DARK_RED #define YELLOW fl_rgb_color(255,255,0) #define WHITE FL_WHITE #define LIGHTGREY fl_rgb_color(160,160,160) #define DARKGREY fl_rgb_color(96,96,96) #define LIGHTBLUE fl_rgb_color(128,128,255) #define LIGHTGREEN fl_rgb_color(128,255,128) #define LIGHTCYAN fl_rgb_color(128,255,255) #define LIGHTRED fl_rgb_color(255,128,128) #define LIGHTMAGENTA fl_rgb_color(255,128,255) #define OBJECT_NUM_COL fl_rgb_color(0x44, 0xdd, 0xff) #define CLR_ERROR fl_rgb_color(0xff, 0, 0) #define SECTOR_TAG fl_rgb_color(0x00, 0xff, 0x00) #define SECTOR_TAGTYPE fl_rgb_color(0x00, 0xe0, 0xe0) #define SECTOR_TYPE fl_rgb_color(0x00, 0x80, 0xff) #define SEL_COL fl_rgb_color(128,192,255) #define HI_COL fl_rgb_color(255,255,0) #define HI_AND_SEL_COL fl_rgb_color(255,192,128) #define WINTITLE fl_rgb_color(0xff, 0xff, 0x00) #endif /* __EUREKA_IM_COLOR_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/objid.h0000644000175100017510000000371312651036166015527 0ustar aaptedaapted//------------------------------------------------------------------------ // OBJECT IDENTIFICATION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_OBJ_ID_H__ #define __EUREKA_OBJ_ID_H__ // main kinds of objects typedef enum { OBJ_THINGS, OBJ_LINEDEFS, OBJ_SIDEDEFS, OBJ_VERTICES, OBJ_SECTORS, } obj_type_e; // special object number for "NONE" #define NIL_OBJ -1 class Objid { public: obj_type_e type; int num; public: Objid() : type(OBJ_THINGS), num(NIL_OBJ) { } Objid(obj_type_e t, int n) : type(t), num(n) { } Objid(const Objid& other) : type(other.type), num(other.num) { } void clear() { num = NIL_OBJ; } bool operator== (const Objid& other) const { return (other.type == type) && (other.num == num); } bool operator!= (const Objid& other) const { return (other.type != type) || (other.num != num); } bool valid() const { return num >= 0; } bool is_nil() const { return num < 0; } }; #endif /* __EUREKA_OBJ_ID_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/x_loop.h0000644000175100017510000000644212647061302015735 0ustar aaptedaapted//------------------------------------------------------------------------ // LINE LOOP HANDLING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_X_LOOP_H__ #define __EUREKA_X_LOOP_H__ class lineloop_c { public: // This contains the linedefs in the line loop, beginning with // the first line and going in order until the last line. There // will be at least 3 lines in the loop, and the same linedef // cannot occur more than once. std::vector< int > lines; // This contains which side of the linedefs in 'lines'. // Guaranteed to be the same size as 'lines'. // Each value is either SIDE_LEFT or SIDE_RIGHT. std::vector< int > sides; // true if the lines face outward (average angle > 180 degrees) // false if the lines face inward (average angle < 180 degrees) bool faces_outward; // Islands are outward facing line-loops which lie inside this one // (which must be inward facing). This list is only created by // calling FindIslands() method, which can be very expensive. std::vector< lineloop_c * > islands; public: lineloop_c(); ~lineloop_c(); void clear(); void push_back(int ld, int side); // test if the given line/side combo is in the loop bool get(int ld, int side) const; bool get_just_line(int ld) const; void FindIslands(); double TotalLength() const; bool SameSector(int *sec_num = NULL) const; bool AllNew() const; // find a sector that neighbors this line loop, i.e. is on the other // side of one of the lines. If there are multiple neighbors, then // only one of them is returned. If there are none, returns -1. int NeighboringSector() const; // check if an island (faces_outward is true) lies inside a sector. // sector, returning the sector number if true, otherwise -1. int FacesSector() const; void Dump() const; public: bool LookForIsland(); void CalcBounds(int *x1, int *y1, int *x2, int *y2) const; }; bool TraceLineLoop(int ld, int side, lineloop_c& loop, bool ignore_new = false); void AssignSectorToSpace(int map_x, int map_y, int new_sec, bool model_from_neighbor = false); void AssignSectorToLoop(lineloop_c& loop, int new_sec, selection_c& flip); double AngleBetweenLines(int A, int B, int C); void LD_AddSecondSideDef(int ld, int new_sd, int other_sd); void LD_RemoveSideDef(int ld, int ld_side); #endif /* __EUREKA_X_LOOP_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/src/r_render.h0000644000175100017510000000515512650665034016243 0ustar aaptedaapted//------------------------------------------------------------------------ // 3D RENDERING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_R_RENDER__ #define __EUREKA_R_RENDER__ typedef enum { QRP_Floor = -2, QRP_Lower = -1, // used for middle of 1S lines too QRP_Rail = 0, QRP_Upper = +1, QRP_Ceil = +2, } query_part_e; class UI_Render3D : public Fl_Widget { public: UI_Render3D(int X, int Y, int W, int H); virtual ~UI_Render3D(); // FLTK virtual methods for drawing / event handling void draw(); int handle(int event); // perform a query to see what the mouse pointer is over. // returns the linedef hit, or -1 if none found. // side will be either SIDE_LEFT or SIDE_RIGHT. // part will distinguish between floor, lower, upper, ceiling. int query(int *side, query_part_e *part); private: void BlitLores(int ox, int oy, int ow, int oh); void BlitHires(int ox, int oy, int ow, int oh); void DrawInfoBar(); void DrawNumber(int& cx, int& cy, const char *label, int value, int size); void DrawFlag (int& cx, int& cy, bool value, const char *label_on, const char *label_off); }; void Render3D_Setup(); void Render3D_RegisterCommands(); void Render3D_MouseMotion(int x, int y, keycode_t mod); void Render3D_Wheel(int dx, int dy, keycode_t mod); void Render3D_RBScroll(int dx, int dy, keycode_t mod); void Render3D_AdjustOffsets(int mode, int dx = 0, int dy = 0); void Render3D_SetCameraPos(int new_x, int new_y); void Render3D_GetCameraPos(int *x, int *y, float *angle); bool Render3D_ParseUser(const char ** tokens, int num_tok); void Render3D_WriteUser(FILE *fp); #endif /* __EUREKA_R_RENDER__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-1.11-source/obj_linux/0000755000175100017510000000000012651564503015466 5ustar aaptedaaptedeureka-1.11-source/obj_linux/glbsp/0000755000175100017510000000000012651564503016575 5ustar aaptedaaptedeureka-1.11-source/games/0000755000175100017510000000000012651542123014563 5ustar aaptedaaptedeureka-1.11-source/games/doom2.ugh0000644000175100017510000001423212647314347016324 0ustar aaptedaapted#------------------------------------------------------------------------ # DOOM 2 definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2013 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ sky_flat F_SKY1 default_textures STARTAN3 FLOOR4_8 CEIL3_5 default_thing 2014 include "doom_colors" include "doom_things" include "doom_specials" include "doom_tex" #---- DOOM 2 THINGS ---------------- thing 82 w n- 20 SGN2 "Super shotgun" thing 83 h nl 20 MEGA "Megasphere" thing 84 m - 20 SSWV "Wolf-SS" thing 65 m - 20 CPOS "Chaingunner" thing 69 m - 24 BOS2A1C1 "Hell knight" thing 68 m - 64 BSPI "Arachnotron" thing 71 m - 31 PAIN "Pain elemental" thing 66 m - 20 SKEL "Revenant" thing 67 m - 48 FATT "Mancubus" thing 64 m - 20 VILE "Archvile" thing 73 g c 16 HDB1 "Hanging no guts" thing 74 g c 16 HDB2 "Hanging no brain" thing 75 g c 16 HDB3 "Hang torso looking down" thing 76 g c 16 HDB4 "Hang torso open skull" thing 77 g c 16 HDB5 "Hang torso looking up" thing 78 g c 16 HDB6 "Hang torso w/o brain" thing 79 g n 16 POB1 "Pool of blood 2" thing 80 g n 16 POB2 "Pool of blood 3" thing 81 g n 16 BRS1 "Pool of brains" thing 85 l l 16 TLMP "Tall mercury lamp" thing 86 l l 16 TLP2 "Short mercury lamp" thing 87 - nl 16 FIREF "Spawn spot" thing 88 - - 16 BBRN "Boss brain" thing 89 - - 16 BOSFB "Boss shooter" thing 72 - c 16 KEEN "Commander Keen" #---- DOOM 2 TEXTURES ---------------- texturegroup w "Wolfenstein" texture w ZDOORB1 texture w ZDOORF1 texture w ZELDOOR texture w ZZWOLF1 texture w ZZWOLF10 texture w ZZWOLF11 texture w ZZWOLF12 texture w ZZWOLF13 texture w ZZWOLF2 texture w ZZWOLF3 texture w ZZWOLF4 texture w ZZWOLF5 texture w ZZWOLF6 texture w ZZWOLF7 texture w ZZWOLF9 texture u BIGBRIK1 texture u BIGBRIK2 texture u BIGBRIK3 texture u BRICK1 texture u BRICK10 texture u BRICK11 texture u BRICK12 texture u BRICK2 texture u BRICK3 texture u BRICK4 texture u BRICK5 texture u BRICK6 texture u BRICK7 texture u BRICK8 texture u BRICK9 texture u BRICKLIT texture u BRWINDOW texture u BSTONE1 texture u BSTONE2 texture u BSTONE3 texture u CEMENT7 texture u CEMENT8 texture u CEMENT9 texture h BFALL1 texture h BFALL2 texture h BFALL3 texture h BFALL4 texture h CRACKLE2 texture h CRACKLE4 texture h DBRAIN1 texture h DBRAIN2 texture h DBRAIN3 texture h DBRAIN4 texture h MARBFAC4 texture h MARBGRAY texture h SW1SKULL texture h SW2SKULL texture h ZZZFACE1 texture h ZZZFACE2 texture h ZZZFACE3 texture h ZZZFACE4 texture h ZZZFACE5 texture h ZZZFACE6 texture h ZZZFACE7 texture h ZZZFACE8 texture h ZZZFACE9 texture t BRONZE1 texture t BRONZE2 texture t BRONZE3 texture t BRONZE4 texture t CRATE3 texture t MIDBARS1 texture t MIDBARS3 texture t MIDBRONZ texture t MIDSPACE texture t METAL2 texture t METAL3 texture t METAL4 texture t METAL5 texture t METAL6 texture t METAL7 texture t SFALL1 texture t SFALL2 texture t SFALL3 texture t SFALL4 texture t SW1TEK texture t SW2TEK texture t TEKBRON1 texture t TEKBRON2 texture t TEKGREN1 texture t TEKGREN2 texture t TEKGREN3 texture t TEKGREN4 texture t TEKGREN5 texture t TEKLITE texture t TEKLITE2 texture t TEKWALL6 texture n ASHWALL2 texture n ASHWALL3 texture n ASHWALL4 texture n ASHWALL6 texture n ASHWALL7 texture n ROCK1 texture n ROCK2 texture n ROCK3 texture n ROCK4 texture n ROCK5 texture n STONE4 texture n STONE5 texture n STONE6 texture n STONE7 texture n SW1ROCK texture n SW2ROCK texture n SW1ZIM texture n SW2ZIM texture n TANROCK2 texture n TANROCK3 texture n TANROCK4 texture n TANROCK5 texture n TANROCK7 texture n TANROCK8 texture n ZIMMER1 texture n ZIMMER2 texture n ZIMMER3 texture n ZIMMER4 texture n ZIMMER5 texture n ZIMMER7 texture n ZIMMER8 texture t MODWALL1 texture t MODWALL2 texture t MODWALL3 texture t MODWALL4 texture t PIPES texture t PIPEWAL1 texture t PIPEWAL2 texture t SILVER1 texture t SILVER2 texture t SILVER3 texture t SPACEW2 texture t SPACEW3 texture t SPACEW4 texture t SPCDOOR1 texture t SPCDOOR2 texture t SPCDOOR3 texture t SPCDOOR4 texture u PANBLACK texture u PANBLUE texture u PANBOOK texture u PANBORD1 texture u PANBORD2 texture u PANCASE1 texture u PANCASE2 texture u PANEL1 texture u PANEL2 texture u PANEL3 texture u PANEL4 texture u PANEL5 texture u PANEL6 texture u PANEL7 texture u PANEL8 texture u PANEL9 texture u PANRED texture u SP_DUDE7 texture u SP_DUDE8 texture u STUCCO texture u STUCCO1 texture u STUCCO2 texture u STUCCO3 texture u SW1PANEL texture u SW2PANEL texture u SW1WDMET texture u SW2WDMET texture u WOOD10 texture u WOOD12 texture u WOOD6 texture u WOOD7 texture u WOOD8 texture u WOOD9 texture u WOODMET1 texture u WOODMET2 texture u WOODMET3 texture u WOODMET4 texture u WOODVERT #---- DOOM 2 FLATS ---------------- flat n GRASS1 flat n GRASS2 flat t GRNLITE1 flat n GRNROCK flat n RROCK01 flat n RROCK02 flat n RROCK03 flat n RROCK04 flat n RROCK05 flat n RROCK06 flat n RROCK07 flat n RROCK08 flat n RROCK09 flat n RROCK10 flat n RROCK11 flat n RROCK12 flat n RROCK13 flat n RROCK14 flat n RROCK15 flat n RROCK16 flat n RROCK17 flat n RROCK18 flat n RROCK19 flat n RROCK20 flat u SLIME01 flat u SLIME02 flat u SLIME03 flat u SLIME04 flat u SLIME05 flat u SLIME06 flat u SLIME07 flat u SLIME08 flat h SLIME09 flat h SLIME10 flat h SLIME11 flat h SLIME12 flat u SLIME13 flat t SLIME14 flat t SLIME15 flat t SLIME16 eureka-1.11-source/games/doom.ugh0000644000175100017510000000436512647061302016236 0ustar aaptedaapted#------------------------------------------------------------------------ # DOOM 1 definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2013 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ sky_flat F_SKY1 default_textures STARTAN3 FLOOR4_8 CEIL3_5 default_thing 2014 include "doom_colors" include "doom_things" include "doom_specials" include "doom_tex" #---- DOOM 1 TEXTURES ---------------- texture h REDWALL1 texture h SKINBORD texture h SKINTEK1 texture h SKINTEK2 texture h SKULWAL3 texture h SKULWALL texture h SP_DUDE3 texture h SP_DUDE6 texture n ASHWALL texture n MIDVINE1 texture n MIDVINE2 texture n SP_ROCK2 texture n SKY4 texture t BLODGR1 texture t BLODGR2 texture t BLODGR3 texture t BLODGR4 texture t BRNBIGC texture t BRNBIGL texture t BRNBIGR texture t BRNPOIS2 texture t BROVINE texture t BROWNWEL texture t COMP2 texture t COMPOHSO texture t COMPTILE texture t COMPUTE1 texture t COMPUTE2 texture t COMPUTE3 texture t DOORHI texture t GRAYDANG texture t ICKDOOR1 texture t ICKWALL6 texture t LITE2 texture t LITE4 texture t LITE96 texture t LITEBLU2 texture t LITEBLU3 texture t LITEMET texture t LITERED texture t NUKESLAD texture t PLANET1 texture t SLADRIP1 texture t SLADRIP2 texture t SLADRIP3 texture t STARTAN1 texture t TEKWALL2 texture t TEKWALL3 texture t TEKWALL5 texture u CEMPOIS texture u LITESTON texture u STONGARG texture u STONPOIS texture u WOODSKUL eureka-1.11-source/games/freedoom1.ugh0000644000175100017510000000153512647061302017155 0ustar aaptedaapted#------------------------------------------------------------------------ # FREEDOOM PHASE 1 #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2015 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 "doom" # TODO : new FreeDoom textures eureka-1.11-source/games/heretic.ugh0000644000175100017510000003316312647331142016723 0ustar aaptedaapted#------------------------------------------------------------------------ # HERETIC definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2012-2016 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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 game definition is derived partially from the Unofficial # Heretic Specs by John "DrSleep" Anderson, partially from the # Heretic source code, and partially from YADEX (which probably # used the other two sources anyway). # #------------------------------------------------------------------------ sky_flat F_SKY1 default_textures SANDSQ2 FLOOR00 FLAT508 # 10 = wand crystal default_thing 10 #---- COLORS -------------------- color sky 199 color wall 6 35 color floor 68 94 color missing 244 color unknown_tex 205 color unknown_flat 222 #---- THING TYPES --------------- thinggroup p 4F4 "Player" thinggroup m F00 "Monster" thinggroup w FA0 "Weapon" thinggroup a 850 "Ammunition" thinggroup h 280 "Health && Armor" thinggroup b 280 "Bonus" thinggroup k F0F "Key" thinggroup d 66C "Decoration" thinggroup l 66C "Light Source" thinggroup s DAD "Sounds" thinggroup - 0BD "OTHER" thing 1 p - 16 PLAY "Player 1" thing 2 p - 16 PLAY "Player 2" thing 3 p - 16 PLAY "Player 3" thing 4 p - 16 PLAY "Player 4" thing 11 p t 16 PLAYF1 "Deathmatch start" thing 14 p t 20 TELE "Teleport Spot" thing 2005 w n 20 WGNT "Gauntlets" thing 2001 w n 20 WBOW "Ethereal Crossbow" thing 53 w n 20 WBLS "Dragon Claw" thing 2004 w n 20 WSKL "Hellstaff" thing 2003 w n 20 WPHX "Phoenix Rod" thing 2002 w n 20 WMCE "Mace" thing 10 a n 20 AMG1 "Wand Crystal" thing 12 a n 20 AMG2 "Wand Geode" thing 18 a n 20 AMC1 "Ethereal Arrows" thing 19 a n 20 AMC2 "Ethereal Quiver" thing 54 a n 20 AMB1 "Claw Orb" thing 55 a n 20 AMB2 "Energy Orb" thing 20 a n 20 AMS1 "Lesser Runes" thing 21 a n 20 AMS2 "Greater Runes" thing 22 a n 20 AMP1 "Flame Orb" thing 23 a n 20 AMP2 "Inferno Orb" thing 13 a n 20 AMM1 "Mace Spheres" thing 16 a n 20 AMM2 "Pile of Mace Spheres" thing 81 h n 20 PTN1 "Crystal Vial" thing 82 h n 20 PTN2 "Quartz Flask" thing 32 h n 20 SPHL "Mystic Urn" thing 85 h n 20 SHLD "Shield (Silver)" thing 31 h n 20 SHD2 "Shield (Enchanted)" thing 8 b n 20 BAGH "Bag of Holding" thing 30 b n 20 EGGC "Morph Ovum" thing 34 b n 20 FBMB "Time Bomb" thing 83 b n 20 SOAR "Wings of Wrath" thing 75 b n 20 INVS "Shadowsphere" thing 84 b nl 20 INVU "Ring of Invulnerability" thing 35 b n 20 SPMP "Map Scroll" thing 36 b n 20 ATLP "Chaos Device" thing 86 b n 20 PWBK "Tome of Power" thing 33 b nl 20 TRCH "Torch" thing 73 k nl 20 AKYY "Green Key" thing 79 k nl 20 BKYY "Blue Key" thing 80 k nl 20 CKYY "Yellow Key" thing 94 k -l 16 KGZB "Blue Key Statue" thing 95 k -l 16 KGZG "Green Key Statue" thing 96 k -l 16 KGZY "Yellow Key Statue" thing 44 d - 12 BARL "Barrel" thing 47 d - 14 BRPL "Brown Pillar" thing 48 d nc 20 MOS1 "Moss 1" thing 49 d nc 20 MOS2 "Moss 2" thing 51 d -c 8 HCOR "Hanging Corpse" thing 26 d nc 20 SKH4 "Hanging Skull 35" thing 25 d nc 20 SKH3 "Hanging Skull 45" thing 24 d nc 20 SKH2 "Hanging Skull 60" thing 17 d nc 20 SKH1 "Hanging Skull 70" thing 29 d - 16 SMPL "Small Pillar" thing 37 d - 8 STGS "Stalagmite (small)" thing 38 d - 12 STGL "Stalagmite (large)" thing 39 d c 8 STCS "Stalactite (small)" thing 40 d c 12 STCL "Stalactite (large)" thing 87 d n- 12 VLCO "Volcano" thing 74 d nl 20 TGLT "Teleport Glitter" thing 52 d nl 20 TGLTF0 "Teleport Glitter (exit)" thing 28 l nlc 20 CHDL "Chandelier" thing 76 l -l 20 KFR1 "Fire Brazier" thing 27 l -l 20 SRTC "Serpent Torch" thing 50 l nl 20 WRTH "Wall Torch" thing 2035 - - 16 PPOD "Pod" thing 43 - n 20 NULL "Pod Generator" thing 66 m - 20 IMPX "Gargoyle" thing 5 m - 20 IMPX "Fire Gargoyle" thing 68 m - 20 MUMM "Golem" thing 69 m i 20 MUMM "Golem Ghost" thing 45 m - 20 MUMMY1 "Nitro Golem" thing 46 m i 20 MUMMY1 "Nitro Golem Ghost" thing 64 m - 20 KNIG "Undead Warrior" thing 65 m i 20 KNIG "Undead Warrior Ghost" thing 15 m - 20 WZRD "Disciple" thing 70 m - 20 BEAS "Weredragon" thing 90 m - 20 CLNK "Sabreclaw" thing 6 m - 20 HEAD "Ironlich" thing 9 m - 20 MNTR "Maulotaur" thing 92 m - 20 SNKE "Ophidian" thing 7 m - 20 SRCR "D'Sparil" thing 56 m t 20 SOR2H0 "D'Sparil Spot" thing 1202 s nv 16 NULL "Sound: Waterdrip" thing 1203 s nv 16 NULL "Sound: Slow Footsteps" thing 1204 s nv 16 NULL "Sound: Heartbeat" thing 1205 s nv 16 NULL "Sound: Bells" thing 1208 s nv 16 NULL "Sound: Laughter" thing 1209 s nv 16 NULL "Sound: Fast Footsteps" thing 1200 s nv 16 NULL "Sound: Scream" thing 1201 s nv 16 NULL "Sound: Squish" thing 1206 s nv 16 NULL "Sound: Growl" thing 1207 s nv 16 NULL "Sound: Magic" thing 42 s nv 20 NULL "Env: Wind" thing 41 s nv 20 NULL "Env: Waterfall" #---- LINE TYPES ---------------- linegroup d "Door" linegroup k "Keyed Door" linegroup p "Lift" linegroup f "Floor (lower)" linegroup g "Floor (raise)" linegroup c "Ceiling" linegroup h "Crusher" linegroup l "Light" linegroup e "Exit level" linegroup m "Moving floor" linegroup u "Stairs" linegroup s "Sounds" linegroup - "OTHER" line 0 - "-- NOTHING" line 48 - "-- Scroll Left" line 99 - "-- Scroll Right" line 31 d "D1 Open door (stays open)" line 1 d "DR Open door" line 46 d "GR Open door (stays open)" line 50 d "S1 Close door" line 103 d "S1 Open door (stays open)" line 29 d "S1 Open door" line 42 d "SR Close door" line 61 d "SR Open door (stays open)" line 63 d "SR Open door" line 3 d "W1 Close door" line 16 d "W1 Close door for 30 seconds" line 2 d "W1 Open door (stays open)" line 4 d "W1 Open door" line 75 d "WR Close door" line 76 d "WR Close door for 30 seconds" line 86 d "WR Open door (stays open)" line 90 d "WR Open door" line 100 d "WR Open door (turbo)" line 32 k "D1 Open blue door (stays open)" line 26 k "DR Open blue door" line 34 k "D1 Open yellow door (stays open)" line 27 k "DR Open yellow door" line 33 k "D1 Open green door (stays open)" line 28 k "DR Open green door" line 11 e "s1 Exit level" line 51 e "s1 Secret exit" line 52 e "w1 Exit level" line 105 e "w1 Secret exit" line 71 f "S1 Lower turbo floor to HEF + 8" line 102 f "S1 Lower floor to HEF" line 23 f "S1 Lower floor to LEF" line 70 f "SR Lower turbo floor to HEF + 8" line 45 f "SR Lower floor to HEF" line 60 f "SR Lower floor to LEF" line 36 f "W1 Lower turbo floor to HEF + 8" line 37 f "W1 Lower floor to LEF (NXP)" line 19 f "W1 Lower floor to HEF" line 38 f "W1 Lower floor to LEF" line 98 f "WR Lower turbo floor to HEF + 8" line 84 f "WR Lower floor to LEF (NXP)" line 83 f "WR Lower floor to HEF" line 82 f "WR Lower floor to LEF" line 21 p "S1 Lower lift" line 62 p "SR Lower lift" line 10 p "W1 Lower lift" line 88 p "WR Lower lift" line 53 m "W1 Start moving floor" line 54 m "W1 Stop moving floor" line 87 m "WR& Start moving floor" line 89 m "WR& Stop moving floor" line 7 u "S1 Raise stairs by 8" line 107 u "S1 Raise stairs by 16" line 8 u "W1 Raise stairs by 8" line 106 u "W1 Raise stairs by 16" line 39 - "W1 Teleport" line 97 - "WR Teleport" line 6 h "W1 Start fast crushing, fast hurt" line 25 h "W1 Start fast crushing, slow hurt" line 57 h "W1& Stop crushing" line 77 h "WR& Start fast crushing, fast hurt" line 73 h "WR& Start slow crushing, slow hurt" line 74 h "WR& Stop crushing" line 47 g "G1 Raise floor to nhEF (TX)" line 24 g "G1 Raise floor to LIC" line 55 g "S1 Raise floor to LIC - 8, crush" line 101 g "S1 Raise floor to LIC" line 18 g "S1 Raise floor to nhEF" line 20 g "S1& Raise floor to nhEF (TX)" line 15 g "S1& Raise floor by 24 (TX)" line 14 g "S1& Raise floor by 32 (TX)" line 65 g "SR Raise floor to LIC - 8, crush" line 69 g "SR Raise floor to nhEF" line 64 g "SR Raise floor to LIC" line 66 g "SR& Raise floor by 24 (TX)" line 67 g "SR& Raise floor by 32 (TX)" line 68 g "SR& Raise floor to nhEF (TX)" line 59 g "W1 Raise floor by 24 (TXP)" line 58 g "W1 Raise floor by 24" line 5 g "W1 Raise floor to LIC" line 30 g "W1 Raise floor by ShortestLowerTexture" line 22 g "W1& Raise floor to nhEF (TX)" line 56 g "W1& Raise floor to LIC - 8, crush" line 93 g "WR Raise floor by 24 (TXP)" line 94 g "WR Raise floor to LIC - 8, crush" line 95 g "WR Raise floor to nhEF (TX)" line 92 g "WR Raise floor by 24" line 91 g "WR Raise floor to LIC" line 96 g "WR Raise floor by ShortestLowerTexture" line 13 l "W1 Light level goes to 255" line 35 l "W1 Light level goes to 35" line 12 l "W1 Light level goes to HE" line 104 l "W1 Light level goes to LE" line 17 l "W1 Start blinking lights" line 81 l "WR Light level goes to 255" line 79 l "WR Light level goes to 35" line 80 l "WR Light level goes to HE" line 49 c "S1 Lower ceiling to floor + 8" line 41 c "S1 Lower ceiling to floor" line 43 c "SR Lower ceiling to floor" line 44 c "W1 Lower ceiling to floor + 8" line 40 c "W1 Raise ceiling to HEC, floor to LEF" line 72 c "WR Lower ceiling to floor + 8" line 9 - "S1 Donut (lower outer, raise inner)" #---- SECTOR TYPES ----------- sector 0 "NOTHING" sector 1 "Light: Flickering" sector 2 "Light: Fast Strobe" sector 3 "Light: Slow Strobe" sector 8 "Light: Glowing" sector 12 "Light: Synch (Slow)" sector 13 "Light: Synch (Fast)" sector 6 "Ceiling Crush & Raise" sector 14 "Door: Raise in 5 min" sector 10 "Door: Close in 30 sec" sector 15 "Low Friction" sector 9 "Secret Area" sector 7 "Damage: Sludge" sector 4 "Damage: Lava Flow" sector 5 "Damage: Lava (Light)" sector 16 "Damage: Lava (Heavy)" sector 21 "Scroll: East (slow)" sector 22 "Scroll: East (normal)" sector 23 "Scroll: East (fast)" sector 26 "Scroll: North (slow)" sector 27 "Scroll: North (normal)" sector 28 "Scroll: North (fast)" sector 31 "Scroll: South (slow)" sector 32 "Scroll: South (normal)" sector 33 "Scroll: South (fast)" sector 36 "Scroll: West (slow)" sector 37 "Scroll: West (normal)" sector 38 "Scroll: West (fast)" sector 40 "Wind: East (weak)" sector 41 "Wind: East (normal)" sector 42 "Wind: East (strong)" sector 43 "Wind: North (weak)" sector 44 "Wind: North (normal)" sector 45 "Wind: North (strong)" sector 46 "Wind: South (weak)" sector 47 "Wind: South (normal)" sector 48 "Wind: South (strong)" sector 49 "Wind: West (weak)" sector 50 "Wind: West (normal)" sector 51 "Wind: West (strong)" #---- TEXTURE CATEGORIES ----------- texturegroup c "Castle" texturegroup d "Door && Metal" texturegroup g "Grating" texturegroup l "Liquid" texturegroup v "Village" texturegroup - "OTHER" texture c BANNER1 texture c BANNER2 texture c BANNER3 texture c BANNER4 texture c BANNER5 texture c BANNER6 texture c BANNER7 texture c BANNER8 texture c CHAINSD texture c CSTLMOSS texture c CSTLRCK texture c GRNBLOK1 texture c GRNBLOK2 texture c GRNBLOK3 texture c GRNBLOK4 texture c GRSTNPB texture c GRSTNPBV texture c GRSTNPBW texture c LOOSERCK texture c MOSSRCK1 texture c ORNGRAY texture c REDWALL texture c SANDSQ2 texture c SNDBLCKS texture c SNDCHNKS texture c SNDPLAIN texture c SPINE1 texture c SPINE2 texture c SQPEB1 texture c SQPEB2 texture c TRISTON1 texture c TRISTON2 texture c WOODWL texture d CHAINMAN texture d DMNMSK texture d DOORWOOD texture d DOOREXIT texture d DOORSTON texture d GRSKULL1 texture d GRSKULL2 texture d GRSKULL3 texture d HORSES1 texture d SKULLSB1 texture d SKULLSB2 texture d SAINT1 texture d METL1 texture d METL2 texture d SW1OFF texture d SW1ON texture d SW2OFF texture d SW2ON texture g GATMETL texture g GATMETL2 texture g GATMETL3 texture g GATMETL4 texture g GATMETL5 texture g WDGAT64 texture g WEB1_B texture g WEB1_F texture g WEB2_B texture g WEB2_F texture g WEB3_M texture g STNGLS1 texture g STNGLS2 texture g STNGLS3 texture l LAVA1 texture l LAVAFL1 texture l LAVAFL2 texture l LAVAFL3 texture l WATRWAL1 texture l WATRWAL2 texture l WATRWAL3 texture v BRWNRCKS texture v CELTIC texture v CTYSTCI1 texture v CTYSTCI2 texture v CTYSTCI4 texture v CTYSTUC1 texture v CTYSTUC2 texture v CTYSTUC3 texture v CTYSTUC4 texture v CTYSTUC5 texture v DRIPWALL texture v RCKSNMUD texture v ROOTWALL texture v TMBSTON1 texture v TMBSTON2 texture v BLUEFRAG texture v MOSAIC1 texture v MOSAIC2 texture v MOSAIC3 texture v MOSAIC4 texture v MOSAIC5 texture - OLDSKY2 texture - OLDSKY3 texture - SKY1 texture - SKY2 texture - SKY3 texture - SKY5 flat c FLAT500 flat c FLAT503 flat c FLAT504 flat c FLAT520 flat c FLAT521 flat c FLAT522 flat c FLAT523 flat c FLOOR00 flat c FLOOR01 flat c FLOOR03 flat c FLOOR06 flat c FLOOR07 flat c FLOOR09 flat c FLOOR18 flat c FLOOR19 flat c FLOOR20 flat l FLATHUH1 flat l FLATHUH2 flat l FLATHUH3 flat l FLATHUH4 flat l FLTFLWW1 flat l FLTFLWW2 flat l FLTFLWW3 flat l FLTLAVA1 flat l FLTLAVA2 flat l FLTLAVA3 flat l FLTLAVA4 flat l FLTSLUD1 flat l FLTSLUD2 flat l FLTSLUD3 flat l FLTWAWA1 flat l FLTWAWA2 flat l FLTWAWA3 flat l FLAT517 flat v FLAT502 flat v FLAT506 flat v FLAT507 flat v FLAT508 flat v FLAT509 flat v FLAT510 flat v FLAT512 flat v FLAT513 flat v FLAT516 flat v FLOOR04 flat v FLOOR05 flat v FLOOR10 flat v FLOOR11 flat v FLOOR12 flat v FLOOR16 flat v FLOOR17 flat v FLOOR25 flat v FLOOR27 flat m FLTTELE1 flat m FLTTELE2 flat m FLTTELE3 flat m FLTTELE4 flat - F_SKY1 flat - FLOOR08 flat - FLOOR21 flat - FLOOR22 flat - FLOOR23 flat - FLOOR24 flat - FLOOR26 flat - FLOOR28 flat - FLOOR29 flat - FLOOR30 eureka-1.11-source/games/freedoom2.ugh0000644000175100017510000000153612647061302017157 0ustar aaptedaapted#------------------------------------------------------------------------ # FREEDOOM PHASE 2 #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2015 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 "doom2" # TODO : new FreeDoom textures eureka-1.11-source/games/plutonia.ugh0000644000175100017510000000441112647061302017123 0ustar aaptedaapted#------------------------------------------------------------------------ # FINAL DOOM : Plutonia Experiment #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2012 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 "doom2" texture h A-ASKIN1 texture h A-ASKIN2 texture h A-ASKIN3 texture h A-ASKIN4 texture h A-ASKIN5 texture u A-BRBRK texture u A-BRBRK2 texture u A-BRICK1 texture u A-BRICK2 texture u A-BRICK3 texture u A-BROCK2 texture u A-BROWN1 texture u A-BROWN2 texture u A-BROWN3 texture u A-BROWN4 texture u A-BROWN5 texture u A-CONCTE texture u A-DBRI1 texture u A-DBRI2 texture u A-GRATE texture u A-MARBLE texture u A-MOSBRI texture u A-MYWOOD texture u A-TILE texture u A-VINE3 texture u A-WOOD1 texture u SLIME1 texture u SLIME2 texture u SLIME3 texture u SLIME4 texture u SLIME5 texture u SLIME8 texture n A-CAMO1 texture n A-CAMO2 texture n A-CAMO3 texture n A-CAMO4 texture n A-CAMO5 texture n A-DROCK1 texture n A-DROCK2 texture n A-MOSRK2 texture n A-MOSROK texture n A-MOULD texture n A-MUD texture n A-REDROK texture n A-ROCK texture n A-VINE1 texture n A-VINE2 texture n A-VINE4 texture n A-VINES texture n AROCK2 texture n AROCK3 texture n AROCK4 texture n AROCK5 texture n MC2 texture n MC3 texture n MC4 texture n MC5 texture n MC6 texture n MC7 texture n MC8 texture n MC10 texture n MC11 texture n MC12 texture n MC13 texture n MC14 texture n MC15 texture n MC16 texture n MC17 texture n MC18 texture n MC19 texture n WFALL1 texture n WFALL2 texture n WFALL3 texture n WFALL4 texture t A-POIS texture t A-RAIL1 texture t A-YELLOW eureka-1.11-source/games/tnt.ugh0000644000175100017510000000646112647061302016104 0ustar aaptedaapted#------------------------------------------------------------------------ # FINAL DOOM : TNT Evilution #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2012 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 "doom2" texturegroup c "Crates" texturegroup e "Egypt" texture c CR128HGB texture c CR128LB texture c CR128LG texture c CR64HBB texture c CR64HBBP texture c CR64HBG texture c CR64HBRM texture c CR64HGB texture c CR64HGBP texture c CR64HGG texture c CR64LB texture c CR64LG texture c CR64SLGB texture c CRAWHBP texture c CRAWLBP texture c CRBLWDH6 texture c CRBWDH64 texture c CRBWDL12 texture c CRBWHBP texture c CRBWLBP texture c CRLWDH6 texture c CRLWDH6B texture c CRLWDL12 texture c CRLWDL6 texture c CRLWDL6B texture c CRLWDL6C texture c CRLWDL6D texture c CRLWDL6E texture c CRLWDS6 texture c CRLWDT3 texture c CRLWDVS texture c CRSMB texture c CRTINYB texture c CRWDH64 texture c CRWDH64B texture c CRWDL128 texture c CRWDL64A texture c CRWDL64B texture c CRWDL64C texture c CRWDS64 texture c CRWDT32 texture e BIGMURAL texture e BIGWALL texture e DRFRONT texture e DRSIDE1 texture e DRSIDE2 texture e DRTOPFR texture e DRTOPSID texture e LONGWALL texture e MURAL1 texture e MURAL2 texture e PILLAR texture e SKIRTING texture h MTNT1 texture n ALTAQUA texture n ASPHALT texture n CARLLF1 texture n CARLLF2 texture n CARLRT1 texture n CARLRT2 texture n CAVERN1 texture n CAVERN4 texture n CAVERN5 texture n CAVERN6 texture n CAVERN7 texture n GRNOPEN texture n FALL3 texture n REDOPEN texture n WFALL1 texture n WFALL4 texture u BRNOPEN texture u CUBICLE texture u DISASTER texture u DOBWIRE texture u DOBWIRE2 texture u DOGLDIR texture u DOGLPANL texture u DOGRID texture u DOGRMSC texture u DOKGRIR texture u DOKODO1B texture u DOKODO2B texture u DOPUNK4 texture u DORED texture u DOWINDOW texture u GRNMEN texture u PNK4EXIT texture u SMGLASS1 texture u SMSTONE6 texture u STONEW1 texture u STONEW5 texture u STWALL texture u TYIRONLG texture u TYIRONSM texture u TYUNDER1 texture u TYWHEEL1 texture u WEBL texture u WEBR texture t BTNTMETL texture t BTNTSLVR texture t DOC1 texture t EGGREENI texture t EGREDI texture t EGSUPRT3 texture t LITEGRN1 texture t LITERED1 texture t LITERED2 texture t LITEYEL1 texture t LITEYEL2 texture t LITEYEL3 texture t METAL-BD texture t METAL-RM texture t METAL2BD texture t METALDR texture t M_RDOOR texture t M_TEC texture t M_YDOOR texture t SLAD2 texture t SLAD3 texture t SLAD4 texture t SLAD5 texture t SLAD6 texture t SLAD7 texture t SLAD8 texture t SLAD9 texture t SLAD10 texture t SLAD11 texture t SLADRIP1 texture t SLADRIP3 texture t TNTDOOR texture t YELMETAL eureka-1.11-source/games/hacx.ugh0000644000175100017510000004063312647061302016221 0ustar aaptedaapted#------------------------------------------------------------------------ # HACX definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2012-2013 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. # #------------------------------------------------------------------------ sky_flat F_SKY1 default_textures MODWALL3 FLAT14 FLAT5_1 default_thing 2014 include "doom_colors" include "doom_specials" #---- THINGS ---------------- thinggroup p 4F4 "Player" thinggroup m F00 "Monster" thinggroup w FA0 "Weapon" thinggroup a 850 "Ammunition" thinggroup h 280 "Health && Armor" thinggroup b 280 "Bonus" thinggroup k F0F "Key" thinggroup d 66C "Decoration" thinggroup g 850 "Gore" thinggroup l 66C "Light Source" thinggroup n 66C "Natural" thinggroup - 0BD "OTHER" thing 1 p - 16 PLAY "Player 1 start" thing 2 p - 16 PLAY "Player 2 start" thing 3 p - 16 PLAY "Player 3 start" thing 4 p - 16 PLAY "Player 4 start" thing 11 p t 16 PLAYF1 "Deathmatch start" thing 14 p t 16 TFOG "Teleport exit" thing 2001 w n 20 SHOT "Tazer" thing 82 w n 20 SGN2 "Cyrogun" thing 2002 w n 20 MGUN "Uzi" thing 2003 w n 20 LAUN "Photon Zooka" thing 2004 w n 20 PLAS "Anti-gun" thing 2005 w n 20 CSAW "Reznator" thing 2006 w n 20 BFUG "Nuker" thing 2007 a n 20 CLIP "Clip" thing 2048 a n 20 AMMO "Box of bullets" thing 2008 a n 20 SHEL "Shells" thing 2049 a n 20 SBOX "Box of shells" thing 2010 a n 20 ROCK "Torpedo" thing 2046 a n 20 BROK "Box of torpedoes" thing 2047 a n 20 CELL "Molecules" thing 17 a n 20 CELP "Box of molecules" thing 8 b n 20 BPAK "Valise w/ ammo" thing 2022 b nl 20 PINV "Force field" thing 2023 b nl 20 PSTR "007-Microtel" thing 2024 b nl 20 PINS "Enk blinder" thing 2025 b nl 20 SUIT "Vulcan rubber boots" thing 2026 b n 20 PMAP "SI Array mapping" thing 2045 b nl 20 PVIS "Infrared visor" thing 83 b nl 20 MEGA "Super kevlar vest" thing 2011 h n 20 STIM "Microkit" thing 2012 h n 20 MEDI "Hypo" thing 2013 h n 20 SOUL "Smart drug" thing 2014 h n 20 BON1 "Dampener" thing 2015 h n 20 BON2 "Inhaler" thing 2018 h n 20 ARM1 "Kevlar Armor" thing 2019 h n 20 ARM2 "Super Armor" thing 5 k nl 20 BKEY "Password" thing 6 k nl 20 YKEY "C-key" thing 13 k nl 20 RKEY "Keycard" thing 40 k nl 20 BSKU "Blue Z-key" thing 39 k nl 20 YSKU "Yellow Z-key" thing 38 k nl 20 RSKU "Red Z-key" # TODO: there may a few missing decorations thing 15 g n 16 PLAYN "Dead player" thing 21 g n 16 SARGN "Destroyed bot" thing 18 g n 20 POSSL "Dead trooper" thing 19 g n 20 SPOSL "Dead sergeant" thing 20 g n 20 TROOM "Dead imp" thing 23 g n 16 SKULK "Dead lost soul" thing 50 g n 16 GOR2 "Corpse 1" thing 51 g n 16 GOR3 "Corpse 2" thing 52 g n 16 GOR4 "Corpse 3" thing 24 g n 16 POL5 "Corpse 4" thing 3004 m - 20 POSS "Thug" thing 9 m - 20 SPOS "Android" thing 3001 m - 20 TROO "I_C_E" thing 3002 m - 30 SARG "Buzzer" thing 3003 m - 24 BOSS "Terminatrix" thing 58 m i 30 SARG "Stealth" thing 3006 m - 16 SKUL "D-Man" thing 84 m - 20 SSWV "Roaming mine" thing 65 m - 20 CPOS "Monstruct" thing 69 m - 24 BOS2A1C1 "Mechamaniac" thing 68 m - 64 BSPI "Thorn Thing" thing 71 m - 31 PAIN "Majong 7" thing 67 m - 48 FATT "Phage" thing 45 l lcn 16 TBLU "Ceiling light" thing 46 l lc 16 TRED "Chandelier" thing 56 l l 16 SMGT "Torch" thing 55 l l 16 SMBT "Desk lamp" thing 57 l l 16 SMRT "Office lamp" thing 2028 d - 16 COLU "Monitor" thing 2035 d - 10 BAR1 "Nitro canister" thing 30 d - 16 COL1 "Robot torso" thing 31 d - 16 COL2 "Robot legs" thing 35 d - 16 CBRA "Chair" thing 80 d - 16 POB2 "Skeleton" thing 81 d - 16 BRS1 "Mummy" thing 44 d - 16 TGRN "Shiny ball" thing 3005 d n 32 HEADC1 "Breakable glass" thing 25 d - 16 POL1 "Laser pole" thing 48 d - 16 ELEC "Metal blades" thing 49 d - 16 GOR1 "Tall robot" thing 26 d - 16 POL6 "Clay jug" thing 28 d - 16 POL2 "Dinghy" thing 34 d - 16 CAND "Warrior statue" thing 41 d l 16 CEYE "Evil eye" thing 42 d l 16 FSKU "Floating galaxy" thing 43 n - 16 TRE1 "Tall tree" thing 54 n - 32 TRE2 "Big tree" thing 47 n - 16 SMIT "Shrub" thing 27 n - 16 POL4 "Bonzai" thing 32 n - 16 COL3 "Pink flowers" thing 33 n - 16 COL4 "Blob" thing 85 n n 16 TLMP "Dots" thing 86 n n 16 TLP2 "Dot" thing 73 n nc 16 HDB1 "Hanging moss 1" thing 74 n nc 16 HDB2 "Hanging moss 2" thing 75 n - 16 HDB3 "Stalagmite 2" thing 76 n - 16 HDB4 "Stalagmite 3" thing 77 n nc 16 HDB5 "Stalactite 1" thing 78 n nc 16 HDB6 "Stalactite 2" thing 79 n - 16 POB1 "Stalagmite 1" #---- TEXTURES ---------------- ## FIXME: more categories texturegroup n "Natural" texturegroup u "Urban" texturegroup c "Cyberspace" texturegroup - "OTHER" ## FIXME: assign to categories texture - AASHITTY texture - ASHWALL2 texture - ASHWALL3 texture - ASHWALL4 texture - ASHWALL6 texture - ASHWALL7 texture - BFALL1 texture - BFALL2 texture - BFALL3 texture - BFALL4 texture - BIGBRIK1 texture - BIGBRIK2 texture - BIGBRIK3 texture - BIGDOOR1 texture - BIGDOOR2 texture - BIGDOOR4 texture - BLAKWAL1 texture - BLAKWAL2 texture - BLODGR1 texture - BLODGR2 texture - BLODGR3 texture - BLODGR4 texture - BLODRIP1 texture - BLODRIP2 texture - BLODRIP3 texture - BLODRIP4 texture - BRICK1 texture - BRICK10 texture - BRICK11 texture - BRICK12 texture - BRICK2 texture - BRICK3 texture - BRICK4 texture - BRICK5 texture - BRICK6 texture - BRICK7 texture - BRICK8 texture - BRICK9 texture - BRICKLIT texture - BRNBIGC texture - BRNBIGL texture - BRNBIGR texture - BRNPOIS texture - BRNPOIS2 texture - BRNSMAL1 texture - BRNSMAL2 texture - BRNSMALC texture - BRNSMALL texture - BRNSMALR texture - BRONZE1 texture - BRONZE2 texture - BRONZE3 texture - BRONZE4 texture - BROWN1 texture - BROWN144 texture - BROWN96 texture - BROWNGRN texture - BROWNHUG texture - BROWNPIP texture - BRWINDOW texture - BSTONE1 texture - BSTONE2 texture - BSTONE3 texture - CEMENT7 texture - CEMENT8 texture - CEMENT9 texture - COMP2 texture - COMPSPAN texture - COMPSTA1 texture - COMPSTA2 texture - COMPTALL texture - COMPTILE texture - COMPUTE1 texture - COMPUTE2 texture - COMPUTE3 texture - CRACKLE2 texture - CRACKLE4 texture - CRATE3 texture - DBRAIN1 texture - DBRAIN2 texture - DBRAIN3 texture - DBRAIN4 texture - DOOR1 texture - DOOR3 texture - DOORBLU texture - DOORRED texture - DOORSTOP texture - DOORTRAK texture - DOORYEL texture - EXITDOOR texture - EXITSIGN texture - FIREWALA texture - FIREWALB texture - FIREWALC texture - FIREWALD texture - FIREWALL texture - GRAY4 texture - GRAY5 texture - GRAY7 texture - GRAYTALL texture - GSTFONT1 texture - GSTFONT2 texture - GSTFONT3 texture - HD1 texture - HD2 texture - HD3 texture - HD4 texture - HD5 texture - HD6 texture - HD7 texture - HD8 texture - HD9 texture - HW162 texture - HW163 texture - HW164 texture - HW165 texture - HW166 texture - HW167 texture - HW168 texture - HW169 texture - HW170 texture - HW171 texture - HW172 texture - HW173 texture - HW174 texture - HW175 texture - HW176 texture - HW177 texture - HW178 texture - HW179 texture - HW180 texture - HW181 texture - HW182 texture - HW183 texture - HW184 texture - HW185 texture - HW186 texture - HW187 texture - HW188 texture - HW189 texture - HW190 texture - HW191 texture - HW192 texture - HW193 texture - HW194 texture - HW195 texture - HW196 texture - HW197 texture - HW198 texture - HW199 texture - HW200 texture - HW201 texture - HW202 texture - HW203 texture - HW204 texture - HW205 texture - HW206 texture - HW207 texture - HW208 texture - HW209 texture - HW210 texture - HW211 texture - HW212 texture - HW213 texture - HW214 texture - HW215 texture - HW216 texture - HW217 texture - HW218 texture - HW219 texture - HW221 texture - HW222 texture - HW223 texture - HW224 texture - HW225 texture - HW226 texture - HW227 texture - HW228 texture - HW229 texture - HW24 texture - HW300 texture - HW301 texture - HW302 texture - HW303 texture - HW304 texture - HW305 texture - HW306 texture - HW307 texture - HW308 texture - HW309 texture - HW310 texture - HW311 texture - HW312 texture - HW313 texture - HW314 texture - HW315 texture - HW316 texture - HW317 texture - HW318 texture - HW319 texture - HW320 texture - HW321 texture - HW322 texture - HW323 texture - HW324 texture - HW325 texture - HW326 texture - HW327 texture - HW328 texture - HW329 texture - HW330 texture - HW331 texture - HW332 texture - HW333 texture - HW334 texture - HW335 texture - HW336 texture - HW337 texture - HW338 texture - HW339 texture - HW340 texture - HW341 texture - HW343 texture - HW344 texture - HW345 texture - HW347 texture - HW348 texture - HW349 texture - HW350 texture - HW351 texture - HW352 texture - HW353 texture - HW354 texture - HW355 texture - HW356 texture - HW357 texture - HW358 texture - HW361 texture - HW363 texture - HW364 texture - HW365 texture - HW366 texture - HW367 texture - HW500 texture - HW501 texture - HW502 texture - HW503 texture - HW504 texture - HW505 texture - HW506 texture - HW507 texture - HW508 texture - HW509 texture - HW510 texture - HW511 texture - HW512 texture - HW513 texture - HW600 texture - HW601 texture - LITE2 texture - LITE3 texture - LITE4 texture - LITE5 texture - LITEBLU1 texture - LITEBLU2 texture - LITEBLU3 texture - LITEBLU4 texture - MARBFAC4 texture - MARBGRAY texture - METAL1 texture - METAL2 texture - METAL3 texture - METAL4 texture - METAL5 texture - METAL6 texture - METAL7 texture - MIDBARS1 texture - MIDBARS3 texture - MIDBRONZ texture - MIDSPACE texture - MODWALL1 texture - MODWALL2 texture - MODWALL3 texture - MODWALL4 texture - NUKE24 texture - NUKEDGE1 texture - NUKESLAD texture - PANBLACK texture - PANBLUE texture - PANBOOK texture - PANBORD1 texture - PANBORD2 texture - PANCASE1 texture - PANCASE2 texture - PANEL1 texture - PANEL2 texture - PANEL3 texture - PANEL4 texture - PANEL5 texture - PANEL6 texture - PANEL7 texture - PANEL8 texture - PANEL9 texture - PANRED texture - PIPE2 texture - PIPES texture - PIPEWAL1 texture - PIPEWAL2 texture - PLANET1 texture - PLAT1 texture - REDWALL1 texture - ROCK1 texture - ROCK2 texture - ROCK3 texture - ROCK4 texture - ROCK5 texture - SAILBOTA texture - SAILBOTB texture - SAILTOPA texture - SAILTOPB texture - SFALL1 texture - SFALL2 texture - SFALL3 texture - SFALL4 texture - SHAWN2 texture - SILVER1 texture - SILVER2 texture - SILVER3 texture - SK_LEFT texture - SK_RIGHT texture - SKY1 texture - SKY2 texture - SKY3 texture - SLADPOIS texture - SLADRIP1 texture - SLADRIP2 texture - SLADRIP3 texture - SLADWALL texture - SLOPPY1 texture - SLOPPY2 texture - SPACEW2 texture - SPACEW3 texture - SPACEW4 texture - SPCDOOR1 texture - SPCDOOR2 texture - SPCDOOR3 texture - SPCDOOR4 texture - SP_DUDE7 texture - SP_DUDE8 texture - SP_FACE2 texture - STARG1 texture - STARG3 texture - STARGR1 texture - STARTAN1 texture - STARTAN2 texture - STARTAN3 texture - STEP1 texture - STEP2 texture - STEP3 texture - STEP4 texture - STEP5 texture - STEP6 texture - STONE texture - STONE2 texture - STONE3 texture - STONE4 texture - STONE5 texture - STONE6 texture - STONE7 texture - STONPOIS texture - STUCCO texture - STUCCO1 texture - STUCCO2 texture - STUCCO3 texture - SUPPORT2 texture - SW1BLUE texture - SW1BRCOM texture - SW1BRIK texture - SW1BRN1 texture - SW1BRN2 texture - SW1BRNGN texture - SW1BROWN texture - SW1CMT texture - SW1COMM texture - SW1COMP texture - SW1DIRT texture - SW1EXIT texture - SW1GARG texture - SW1GRAY texture - SW1GRAY1 texture - SW1GSTON texture - SW1HOT texture - SW1LION texture - SW1MARB texture - SW1MET2 texture - SW1METAL texture - SW1MOD1 texture - SW1PANEL texture - SW1PIPE texture - SW1ROCK texture - SW1SATYR texture - SW1SKIN texture - SW1SKULL texture - SW1SLAD texture - SW1STARG texture - SW1STON1 texture - SW1STON2 texture - SW1STON6 texture - SW1STONE texture - SW1STRTN texture - SW1TEK texture - SW1VINE texture - SW1WDMET texture - SW1WOOD texture - SW1ZIM texture - SW2BLUE texture - SW2BRCOM texture - SW2BRIK texture - SW2BRN1 texture - SW2BRN2 texture - SW2BRNGN texture - SW2BROWN texture - SW2CMT texture - SW2COMM texture - SW2COMP texture - SW2DIRT texture - SW2EXIT texture - SW2GARG texture - SW2GRAY texture - SW2GRAY1 texture - SW2GSTON texture - SW2HOT texture - SW2LION texture - SW2MARB texture - SW2MET2 texture - SW2METAL texture - SW2MOD1 texture - SW2PANEL texture - SW2PIPE texture - SW2ROCK texture - SW2SATYR texture - SW2SKIN texture - SW2SKULL texture - SW2SLAD texture - SW2STARG texture - SW2STON1 texture - SW2STON2 texture - SW2STON6 texture - SW2STONE texture - SW2STRTN texture - SW2TEK texture - SW2VINE texture - SW2WDMET texture - SW2WOOD texture - SW2ZIM texture - TANROCK2 texture - TANROCK3 texture - TANROCK4 texture - TANROCK5 texture - TANROCK7 texture - TANROCK8 texture - TEKBRON1 texture - TEKBRON2 texture - TEKGREN1 texture - TEKGREN2 texture - TEKGREN3 texture - TEKGREN4 texture - TEKGREN5 texture - TEKLITE texture - TEKLITE2 texture - TEKWALL1 texture - TEKWALL2 texture - TEKWALL3 texture - TEKWALL4 texture - TEKWALL5 texture - TEKWALL6 texture - WFALL1 texture - WFALL2 texture - WFALL3 texture - WFALL4 texture - WOOD10 texture - WOOD12 texture - WOOD6 texture - WOOD7 texture - WOOD8 texture - WOOD9 texture - WOODMET1 texture - WOODMET2 texture - WOODMET3 texture - WOODMET4 texture - WOODVERT texture - ZDOORB1 texture - ZDOORF1 texture - ZELDOOR texture - ZIMMER1 texture - ZIMMER2 texture - ZIMMER3 texture - ZIMMER4 texture - ZIMMER5 texture - ZIMMER7 texture - ZIMMER8 texture - ZZWOLF1 texture - ZZWOLF10 texture - ZZWOLF11 texture - ZZWOLF12 texture - ZZWOLF13 texture - ZZWOLF2 texture - ZZWOLF3 texture - ZZWOLF4 texture - ZZWOLF5 texture - ZZWOLF6 texture - ZZWOLF7 texture - ZZWOLF9 texture - ZZZFACE1 texture - ZZZFACE2 texture - ZZZFACE3 texture - ZZZFACE4 texture - ZZZFACE5 texture - ZZZFACE6 texture - ZZZFACE7 texture - ZZZFACE8 texture - ZZZFACE9 #---- FLATS ---------------- ## FIXME: assign to categories flat - BLOOD1 flat - BLOOD2 flat - BLOOD3 flat - CEIL1_1 flat - CEIL1_2 flat - CEIL1_3 flat - CEIL3_1 flat - CEIL3_2 flat - CEIL3_3 flat - CEIL3_4 flat - CEIL3_5 flat - CEIL3_6 flat - CEIL4_1 flat - CEIL4_2 flat - CEIL4_3 flat - CEIL5_1 flat - CEIL5_2 flat - COMP01 flat - CONS1_1 flat - CONS1_5 flat - CONS1_7 flat - CRATOP1 flat - CRATOP2 flat - DEM1_1 flat - DEM1_2 flat - DEM1_3 flat - DEM1_4 flat - DEM1_5 flat - DEM1_6 flat - FLAT1 flat - FLAT10 flat - FLAT1_1 flat - FLAT1_2 flat - FLAT1_3 flat - FLAT14 flat - FLAT17 flat - FLAT18 flat - FLAT19 flat - FLAT2 flat - FLAT20 flat - FLAT22 flat - FLAT23 flat - FLAT3 flat - FLAT4 flat - FLAT5 flat - FLAT5_1 flat - FLAT5_2 flat - FLAT5_3 flat - FLAT5_4 flat - FLAT5_5 flat - FLAT5_6 flat - FLAT5_7 flat - FLAT5_8 flat - FLAT8 flat - FLAT9 flat - FLOOR0_1 flat - FLOOR0_2 flat - FLOOR0_3 flat - FLOOR0_5 flat - FLOOR0_6 flat - FLOOR0_7 flat - FLOOR1_1 flat - FLOOR1_6 flat - FLOOR1_7 flat - FLOOR3_3 flat - FLOOR4_1 flat - FLOOR4_5 flat - FLOOR4_6 flat - FLOOR4_8 flat - FLOOR5_1 flat - FLOOR5_2 flat - FLOOR5_3 flat - FLOOR5_4 flat - FLOOR6_1 flat - FLOOR6_2 flat - FLOOR7_1 flat - FLOOR7_2 flat - F_SKY1 flat - FWATER1 flat - FWATER2 flat - FWATER3 flat - FWATER4 flat - GATE1 flat - GATE2 flat - GATE3 flat - GATE4 flat - GRASS1 flat - GRASS2 flat - GRNLITE1 flat - GRNROCK flat - LAVA1 flat - LAVA2 flat - LAVA3 flat - LAVA4 flat - MFLR8_1 flat - MFLR8_2 flat - MFLR8_3 flat - MFLR8_4 flat - NUKAGE1 flat - NUKAGE2 flat - NUKAGE3 flat - RROCK01 flat - RROCK02 flat - RROCK03 flat - RROCK04 flat - RROCK05 flat - RROCK06 flat - RROCK07 flat - RROCK08 flat - RROCK09 flat - RROCK10 flat - RROCK11 flat - RROCK12 flat - RROCK13 flat - RROCK14 flat - RROCK15 flat - SFLR6_1 flat - SFLR6_4 flat - SFLR7_1 flat - SFLR7_4 flat - SLIME01 flat - SLIME02 flat - SLIME03 flat - SLIME04 flat - SLIME05 flat - SLIME06 flat - SLIME07 flat - SLIME08 flat - SLIME09 flat - SLIME10 flat - SLIME11 flat - SLIME12 flat - SLIME13 flat - SLIME14 flat - SLIME15 flat - SLIME16 flat - STEP1 flat - STEP2 flat - TLITE6_1 flat - TLITE6_4 flat - TLITE6_5 flat - TLITE6_6 eureka-1.11-source/games/hexen.ugh0000644000175100017510000006251112647324713016414 0ustar aaptedaapted#------------------------------------------------------------------------ # HEXEN DEFINITIONS #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2015 Ioan Chera # Copyright (C) 2015-2016 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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. # #------------------------------------------------------------------------ # # Thanks to the the Official Hexen Specs by Ben Morris (et al). # See http://doomlegacy.sourceforge.net/hosted/hexenspec09.txt # #------------------------------------------------------------------------ sky_flat F_SKY default_textures CASTLE07 F_009 F_020 default_thing 81 # healing vial #---- COLORS -------------------- color sky 219 color wall 6 32 color floor 81 96 color missing 227 color unknown_tex 223 color unknown_flat 213 #---- THING TYPES --------------- thinggroup p 4F4 "Player" thinggroup m F00 "Monster" thinggroup w FA0 "Weapon" thinggroup a 850 "Ammunition" thinggroup h 280 "Health && Armor" thinggroup b 280 "Bonus" thinggroup k F0F "Key" thinggroup j F0F "Puzzle Piece" thinggroup d 66C "Decoration" thinggroup n 66C "Natural" thinggroup s DAD "Sounds" thinggroup - 0BD "OTHER" thing 1 p - 16 PLAY "Player 1 start" thing 2 p - 16 CLER "Player 2 start" thing 3 p - 16 CLER "Player 3 start" thing 4 p - 16 MAGE "Player 4 start" thing 11 p t 16 MAGEF1 "Deathmatch start" thing 14 p t 16 TELE "Teleport exit" thing 9100 p - 16 PLAY "Player 5 start" thing 9101 p - 16 CLER "Player 6 start" thing 9102 p - 16 CLER "Player 7 start" thing 9103 p - 16 MAGE "Player 8 start" thing 10 w n 20 WCSS "Serpent staff" thing 8010 w n 20 WFAX "Axe" thing 53 w nl 20 WMCS "Frost shards" thing 8009 w nl 20 WCFM "Fire storm" thing 123 w n 20 WFHM "Hammer" thing 8040 w nl 20 WMLGH0 "Lightning" thing 20 w nl 20 WCH3 "Wraithverge shaft" thing 19 w nl 20 WCH2 "Wraithverge cross" thing 18 w nl 20 WCH1 "Wraithverge arc" thing 16 w nl 20 WFR3 "Quietus hilt" thing 13 w nl 20 WFR2 "Quietus crosspiece" thing 12 w nl 20 WFR1 "Quietus blade" thing 23 w nl 20 WMS3 "Bloodscourge stick" thing 22 w nl 20 WMS2 "Bloodscourge stub" thing 21 w nl 20 WMS1 "Bloodscourge skull" thing 8000 b n 20 PSBG "Flechette" thing 8003 b n 20 BMAN "Krater of might" thing 8002 b nl 20 SPEDB0 "Boots of speed" thing 8041 b nl 20 BRACC0 "Dragonskin bracers" thing 84 b n 20 INVU "Icon of the defender" thing 30 b n 20 PORK "Porkalator" thing 83 b n 20 SOARB0 "Wings of wrath" thing 32 b n 20 SPHL "Mystic urn" thing 82 b n 20 PTN2 "Quartz flask" thing 10120 b nl 20 HRAD "Mystic ambit incant" thing 10110 b nl 20 BLST "Disc of repulsion" thing 86 b n 20 SUMN "Dark servant" thing 36 b n 20 ATLP "Chaos device" thing 33 b nl 20 TRCH "Torch" thing 10040 b n 20 TELO "Banishment device" thing 8008 h n 20 ARM4 "Amulet of warding" thing 8005 h n 20 ARM1 "Mesh armor" thing 8007 h n 20 ARM3 "Platinum helm" thing 8006 h n 20 ARM2 "Falcon shield" thing 81 h n 20 PTN1 "Healing vial" thing 122 a nl 8 MAN1 "Blue mana" thing 124 a nl 8 MAN2 "Green mana" thing 8004 a nl 8 MAN3 "Combined mana" thing 114 m - 22 BISH "Dark bishop" thing 107 m - 20 CENT "Centaur" thing 115 m l 20 CENTF1 "Slaughtaur" thing 31 m - 32 DEMN "Chaos serpent" thing 8080 m - 32 DEM2 "Chaos serpent 2" thing 254 m - 20 DRAG "Death wyvern" thing 10030 m - 25 ETTN "Ettin" thing 10060 m l 20 FDMN "Afrit" thing 10080 m - 40 SORC "Heresiarch" thing 8020 m - 22 ICEY "Wendigo" thing 10200 m - 65 KORX "Korax" thing 121 m - 32 SSPTI1 "Stalker" thing 120 m - 32 SSPTK1 "Stalker leader" thing 34 m - 20 WRTH "Wraith" thing 10011 m - 20 WRTH "Buried wraith" thing 10100 m - 16 PLAYE "Zedek" thing 10101 m - 16 CLERE "Traductus" thing 10102 m - 16 MAGEE "Mage boss" thing 8032 k n 8 KEY3 "Axe key" thing 8200 k n 8 KEYB "Castle key" thing 8031 k n 8 KEY2 "Cave key" thing 8035 k n 8 KEY6 "Dungeon key" thing 8033 k n 8 KEY4 "Fire key" thing 8034 k n 8 KEY5 "Emerald key" thing 8037 k n 8 KEY8 "Rusty key" thing 8036 k n 8 KEY7 "Silver key" thing 8030 k n 8 KEY1 "Steel key" thing 8039 k n 8 KEYA "Swamp key" thing 8038 k n 8 KEY9 "Horn key" thing 9002 j n 20 ASKU "Puzzle Skull" thing 9003 j n 20 ABGM "Puzzle GemBig" thing 9004 j n 20 AGMR "Puzzle GemRed" thing 9005 j n 20 AGMG "Puzzle GemGreen1" thing 9006 j n 20 AGMB "Puzzle GemBlue1" thing 9007 j n 20 ABK1 "Puzzle Book1" thing 9008 j n 20 ABK2 "Puzzle Book2" thing 9009 j n 20 AGG2 "Puzzle GemGreen2" thing 9010 j n 20 AGB2 "Puzzle GemBlue2" thing 9014 j n 20 ASK2 "Puzzle FlameMask" thing 9015 j n 20 AFWP "Puzzle FWeapon" thing 9016 j n 20 ACWP "Puzzle CWeapon" thing 9017 j n 20 AMWP "Puzzle MWeapon" thing 9018 j nl 20 AGER "Puzzle Gear1" thing 9019 j nl 20 AGR2 "Puzzle Gear2" thing 9020 j nl 20 AGR3 "Puzzle Gear3" thing 9021 j nl 20 AGR4 "Puzzle Gear4" thing 5 d - 10 STTW "Winged Statue" thing 54 d ln 20 WLTR "Wall Torch" thing 55 d n 20 WLTRI0 "WallTorch /unlit" thing 116 d l 10 TWTR "Twined Torch" thing 117 d - 10 TWTRI0 "Twined Torch /unlit" thing 119 d ln 20 CNDL "Candle" thing 61 d - 10 CPS1 "Corpse Kabob" thing 62 d n 20 CPS2 "Corpse Sleeping" thing 72 d - 14 STT2 "Gargoyle Green" thing 73 d - 14 STT3 "Gargoyle Blue" thing 74 d - 14 STT4 "Gargoyle Green /short" thing 76 d - 14 STT5 "Gargoyle Blue /short" thing 77 d - 8 BNR1 "Tattered Banner" thing 103 d - 12 VASE "Vase Pillar" thing 104 d - 10 POT1 "Pottery 1" thing 105 d - 10 POT2 "Pottery 2" thing 106 d - 15 POT3 "Pottery 3" thing 110 d - 15 CPS6 "Corpse Sitting" thing 111 d n 20 BDPL "Blood Pool" thing 140 d n 20 TSMK "Teleport Smoke" thing 8042 d l 20 FBUL "FireBull" thing 8043 d - 20 FBULH0 "FireBull /unlit" thing 8044 d - 14 GAR1 "Gargoyle" thing 8045 d - 14 GAR2 "Gargoyle Dark" thing 8046 d - 14 GAR3 "Gargoyle Red" thing 8047 d - 14 GAR4 "Gargoyle Tan" thing 8048 d - 14 GAR5 "Gargoyle Rust" thing 8049 d - 14 GAR6 "Gargoyle Dark /short" thing 8050 d - 14 GAR7 "Gargoyle Red /short" thing 8051 d - 14 GAR8 "Gargoyle Tan /short" thing 8052 d - 14 GAR9 "Gargoyle Rust /short" thing 8060 d l 5 FSKL "Fire Thing" thing 8061 d l 6 BRTR "Brass Torch" thing 8064 d - 16 SUIT "Suit Of Armor" thing 8066 d nl 20 CAND "Candle /blue" thing 8067 d - 12 IRON "Iron Maiden" thing 8069 d l 12 CDRNB0 "Cauldron" thing 8070 d - 12 CDRNA0 "Cauldron /unlit" thing 8100 d - 15 BARL "Barrel" thing 9011 d - 10 STWN "Winged Statue 2" thing 9012 d - 10 GMPD "Gem Pedestal" thing 17 d cn 20 CDLR "Chandelier" thing 8063 d cn 20 CDLRD0 "Chandelier /unlit" thing 71 d c 6 CPS3 "Corpse Hanging" thing 108 d c 11 CPS4 "Corpse Lynched" thing 109 d c 10 CPS5 "Corpse Lynched 2" thing 8065 d c 56 BBLL "Bell" thing 8071 d cn 4 CHNSA0 "Chain" thing 8072 d cn 4 CHNSB0 "Chain Long" thing 8073 d cn 4 CHNSC0 "Chain w/ heart" thing 8074 d cn 4 CHNSD0 "Chain Hook" thing 8075 d cn 4 CHNSE0 "Chain Hook 2" thing 8076 d cn 4 CHNSF0 "Chain Mace" thing 8077 d cn 4 CHNSG0 "Chain w/ skull" thing 8103 d c 8 BCKT "Bucket" thing 8500 d n 20 TST1 "Table Item 1" thing 8501 d n 20 TST2 "Table Item 2" thing 8502 d n 20 TST3 "Table Item 3" thing 8503 d n 20 TST4 "Table Item 4" thing 8504 d n 20 TST5 "Table Item 5" thing 8505 d n 20 TST6 "Table Item 6" thing 8506 d n 20 TST7 "Table Item 7" thing 8507 d n 20 TST8 "Table Item 8" thing 8508 d n 20 TST9 "Table Item 9" thing 8509 d n 20 TST0 "Table Item 10" thing 6 n n 20 RCK1 "Rock 1" thing 7 n n 20 RCK2 "Rock 2" thing 9 n n 20 RCK3 "Rock 3" thing 15 n - 20 RCK4 "Rock 4" thing 24 n - 10 TRE1 "Tree 1 /dead" thing 25 n - 15 TRE1 "Tree 1" thing 26 n - 10 TRE2 "Tree 2" thing 27 n - 10 TRE3 "Tree 3" thing 78 n - 15 TRE4 "Tree Large 1" thing 79 n - 15 TRE5 "Tree Large 2" thing 80 n - 22 TRE6 "Tree Gnarled" thing 87 n - 22 TRE7 "Tree Gnarled 2" thing 28 n - 12 STM1 "Stump 1" thing 29 n - 12 STM2 "Stump 2" thing 37 n n 20 STM3 "Stump 3" thing 38 n n 20 STM4 "Stump 4" thing 39 n n 20 MSH1 "Mushroom Large 1" thing 40 n n 20 MSH2 "Mushroom Large 2" thing 41 n n 20 MSH3 "Mushroom Large 3" thing 42 n n 20 MSH4 "Mushroom 1" thing 44 n n 20 MSH5 "Mushroom 2" thing 45 n n 20 MSH6 "Mushroom 3" thing 46 n n 20 MSH7 "Mushroom 4" thing 47 n n 20 MSH8 "Mushroom 5" thing 48 n - 8 SGMP "Stalagmite Pillar" thing 49 n - 8 SGM1 "Stalagmite Large" thing 50 n - 6 SGM2 "Stalagmite Medium" thing 51 n - 8 SGM3 "Stalagmite Small" thing 60 n - 8 SWMV "Swamp Vine" thing 63 n - 10 TMS1 "Tombstone 1" thing 64 n - 10 TMS2 "Tombstone 2" thing 65 n - 10 TMS3 "Tombstone 3" thing 66 n - 10 TMS4 "Tombstone 4" thing 67 n - 10 TMS5 "Tombstone 5" thing 68 n - 8 TMS6 "Tombstone 6" thing 69 n - 8 TMS7 "Tombstone 7" thing 88 n - 20 LOGG "Log" thing 93 n - 8 ICM1 "Ice Stalagmite Large" thing 94 n - 5 ICM2 "Ice Stalagmite Medium" thing 95 n - 4 ICM3 "Ice Stalagmite Small" thing 96 n - 4 ICM4 "Ice Stalagmite Tiny" thing 97 n - 17 RKBL "Boulder 1" thing 98 n - 15 RKBS "Boulder 2" thing 99 n - 20 RKBK "Boulder 3" thing 100 n n 20 RBL1 "Rubble 1" thing 101 n n 20 RBL2 "Rubble 2" thing 102 n n 20 RBL3 "Rubble 3" thing 8062 n - 15 TRDT "Destructible Tree" thing 8068 n - 11 XMAS "Xmas Tree" thing 8101 n - 8 SHB1 "Shrub 1" thing 8102 n - 16 SHB2 "Shrub 2" thing 8104 n - 6 SHRM "Poison Mushroom" thing 58 n cn 20 MSS1 "Moss Ceiling 1" thing 59 n cn 20 MSS2 "Moss Ceiling 2" thing 52 n c 8 SLC1 "Stalactite Large" thing 56 n c 6 SLC2 "Stalactite Medium" thing 57 n c 8 SLC3 "Stalactite Small" thing 89 n c 8 ICT1 "Ice Stalactite Large" thing 90 n c 5 ICT2 "Ice Stalactite Medium" thing 91 n c 4 ICT3 "Ice Stalactite Small" thing 92 n c 4 ICT4 "Ice Stalactite Tiny" thing 118 - - 32 NULL "Bridge" thing 9001 - n 20 NULL "Map spot" thing 9013 - n 20 NULL "Map spot /gravity" thing 3000 - nv 8 NULL "Polyobject anchor" thing 3001 - nv 8 NULL "Polyobject spot" thing 3002 - nv 8 NULL "Polyobject spot /crush" thing 1400 s n 8 NULL "Sndtype Stone" thing 1401 s n 8 NULL "Sndtype Heavy" thing 1402 s n 8 NULL "Sndtype Metal Sfx" thing 1403 s n 8 NULL "Sndtype Creak Sfx" thing 1404 s n 8 NULL "Sndtype Silent" thing 1405 s n 8 NULL "Sndtype Lava" thing 1406 s n 8 NULL "Sndtype Water" thing 1407 s n 8 NULL "Sndtype Ice" thing 1408 s n 8 NULL "Sndtype Earth" thing 1409 s n 8 NULL "Sndtype Metal2" thing 1410 s nv 8 NULL "Wind Sound" thing 113 - n 20 LEF1 "Leaf spawner" thing 10000 - nl 20 FOGM "Fog spawner" thing 10001 - n 20 FOGS "Fog /small" thing 10002 - n 20 FOGM "Fog /medium" thing 10003 - n 20 FOGL "Fog /large" thing 10225 - n 20 ABAT "Bat spawner" thing 10500 - nl 20 FFSM "Flame Small /temp" thing 10501 - nl 20 FFSM "Flame Small" thing 10502 - nl 20 FFLG "Flame Large /temp" thing 10503 - nl 20 FFLG "Flame Large" #---- SECTOR TYPES --------------- sector 0 "NOTHING" sector 9 "Secret Area" sector 1 "Phased Light" sector 2 "Light Seq Start" sector 3 "Light Seq Next 1" sector 4 "Light Seq Next 2" sector 26 "Next Stair 1" sector 27 "Next Stair 2" sector 40 "Wind E /slow" sector 41 "Wind E /med" sector 42 "Wind E /fast" sector 43 "Wind N /slow" sector 44 "Wind N /med" sector 45 "Wind N /fast" sector 46 "Wind S /slow" sector 47 "Wind S /med" sector 48 "Wind S /fast" sector 49 "Wind W /slow" sector 50 "Wind W /med" sector 51 "Wind W /fast" sector 198 "Indoor Lightning /64" sector 199 "Indoor Lightning /32" sector 200 "Alternate Sky" sector 201 "Scroll N /slow" sector 202 "Scroll N /med" sector 203 "Scroll N /fast" sector 204 "Scroll E /slow" sector 205 "Scroll E /med" sector 206 "Scroll E /fast" sector 207 "Scroll S /slow" sector 208 "Scroll S /med" sector 209 "Scroll S /fast" sector 210 "Scroll W /slow" sector 211 "Scroll W /med" sector 212 "Scroll W /fast" sector 213 "Scroll NW /slow" sector 214 "Scroll NW /med" sector 215 "Scroll NW /fast" sector 216 "Scroll NE /slow" sector 217 "Scroll NE /med" sector 218 "Scroll NE /fast" sector 219 "Scroll SE /slow" sector 220 "Scroll SE /med" sector 221 "Scroll SE /fast" sector 222 "Scroll SW /slow" sector 223 "Scroll SW /med" sector 224 "Scroll SW /fast" #---- LINE/THING SPECIALS --------------- linegroup a "Animated" linegroup f "Floor" linegroup g "Lift" linegroup c "Ceiling" linegroup d "Door" linegroup l "Light" linegroup s "Stairs" linegroup t "Thing" linegroup p "Polyobj" linegroup - "OTHER" # Floors and lifts special 20 f "Floor_Lower" tag speed dist special 21 f "Floor_Lower /lowest" tag speed special 22 f "Floor_Lower /nearest" tag speed special 23 f "Floor_Raise" tag speed dist special 24 f "Floor_Raise /highest" tag speed special 25 f "Floor_Raise /nearest" tag speed special 28 f "Floor_Raise /crush" tag speed damage special 35 f "Floor_Raise x8" tag speed dist_x8 special 36 f "Floor_Lower x8" tag speed dist_x8 special 66 f "Floor_Lower /instant" tag - dist special 67 f "Floor_Raise /instant" tag - dist special 68 f "Floor_MoveTo x8" tag speed height_x8 negate? special 46 f "Floor_CrushStop" tag special 138 f "Floor_Waggle" tag amp speed offset time special 62 g "Plat_DownWaitUp" tag speed delay special 63 g "Plat_Down" tag speed delay dist special 64 g "Plat_UpWaitDown" tag speed delay special 65 g "Plat_Up" tag speed delay dist special 60 g "Plat_Perpetual" tag speed delay special 61 g "Plat_Stop" tag special 26 s "Stairs_Down" tag speed dist delay reset special 27 s "Stairs_Up" tag speed dist delay reset special 31 s "Stairs_Down /sync" tag speed dist reset special 32 s "Stairs_Up /sync" tag speed dist reset # Ceiling and doors special 40 c "Ceiling_Lower" tag speed dist special 41 c "Ceiling_Raise" tag speed dist special 69 c "Ceiling_MoveTo x8" tag speed height_x8 negate? special 42 c "Ceiling_Crush /perpet" tag speed damage special 43 c "Ceiling_Crush " tag speed damage special 45 c "Ceiling_CrushAndUp" tag speed damage special 44 c "Ceiling_CrushStop" tag special 10 d "Door_Close" tag speed special 11 d "Door_Open" tag speed special 12 d "Door_Raise" tag speed delay special 13 d "Door_Locked" tag speed delay lock # Lighting special 110 l "Light_Raise" tag light special 111 l "Light_Lower" tag light special 112 l "Light_Set" tag light special 113 l "Light_Fade" tag light time special 114 l "Light_Glow" tag high low time special 115 l "Light_Flicker" tag high low special 116 l "Light_Strobe" tag high low hightime lowtime special 109 l "Force Lightning" mode # Thing specials special 72 t "Push Thing" angle dist special 73 t "Damage Thing" damage special 130 t "Thing_Activate" tid special 131 t "Thing_Deactivate" tid special 132 t "Thing_Remove" tid special 133 t "Thing_Destroy" tid special 134 t "Thing_Launch" tid type angle speed vspeed special 136 t "Thing_Launch /grav" tid type angle speed vspeed special 135 t "Thing_Spawn" tid type angle special 137 t "Thing_Spawn /silent" tid type angle # Polyobj specials special 1 p "Polyobj_Start" po mirror sound special 5 p "Polyobj_Explicit" po order mirror sound special 2 p "Polyobj_RotateL" po speed angle special 3 p "Polyobj_RotateR" po speed angle special 4 p "Polyobj_Move" po speed angle dist special 6 p "Polyobj_Move x8" po speed angle dist special 7 p "Polyobj_DoorSwing" po speed angle delay special 8 p "Polyobj_DoorSlide" po speed angle dist delay special 90 p "Polyobj_RotateL /OR" po speed angle special 91 p "Polyobj_RotateR /OR" po speed angle special 92 p "Polyobj_Move /OR" po speed angle dist special 93 p "Polyobj_Move x8 /OR" po speed angle dist # Miscellaneous special 0 - "NOTHING" special 29 - "Pillar_Build" tag speed dist special 30 - "Pillar_Open" tag speed f_dist c_dist special 94 - "Pillar_Crush" tag speed dist damage special 80 - "ACS_Execute" script map param1 param2 param3 special 83 - "ACS_Execute /lock" script map param1 param2 lock special 81 - "ACS_Suspend" script map special 82 - "ACS_Terminate" script map special 95 - "Elevator_Lower" tag speed dist special 96 - "Elevator_Raise" tag speed dist special 121 - "Set Line ID" id_number special 100 a "Scroll_Left" speed special 101 a "Scroll_Right" speed special 102 a "Scroll_Up" speed special 103 a "Scroll_Down" speed special 129 - "UsePuzzleItem" item script param1 param2 param3 special 140 - "Change Sound" tag sound special 120 - "Earthquake" intensity duration damrad tremrad tid special 70 - "Teleport" tid special 71 - "Teleport /silent" tid special 74 - "Game_NewMap" map position special 75 - "Game_End" #---- TEXTURES CATEGORIES ---------------- texturegroup c "Castle" texturegroup d "Door" texturegroup g "Grating" texturegroup m "Metal" texturegroup n "Natural" texturegroup p "Puzzle" texturegroup s "Switch" texturegroup - "OTHER" texture c BOOKS01 texture c BOOKS02 texture c BOOKS03 texture c BOOKS04 texture c BOSSK1 texture c BOSSK2 texture c CASTLE01 texture c CASTLE02 texture c CASTLE03 texture c CASTLE04 texture c CASTLE05 texture c CASTLE06 texture c CASTLE07 texture c CASTLE08 texture c CASTLE09 texture c CAVE07 texture c CRATE01 texture c CRATE02 texture c CRATE03 texture c CRATE04 texture c CRATE05 texture c FIRE01 texture c FIRE02 texture c FIRE03 texture c FIRE04 texture c FIRE05 texture c FIRE06 texture c FIRE07 texture c FIRE08 texture c FIRE09 texture c FIRE10 texture c FIRE11 texture c FIRE12 texture c FIRE14 texture c FIRE15 texture c FIRE16 texture c FIRE17 texture c FOREST05 texture c ICE02 texture c ICE03 texture c ICE06 texture c MONK01 texture c MONK02 texture c MONK03 texture c MONK04 texture c MONK05 texture c MONK06 texture c MONK07 texture c MONK08 texture c MONK09 texture c MONK11 texture c MONK12 texture c MONK14 texture c MONK15 texture c MONK16 texture c MONK17 texture c MONK18 texture c MONK19 texture c MONK21 texture c MONK22 texture c MONK23 texture c MONK24 texture c PILLAR01 texture c PILLAR02 texture c POOT texture c PRTL02 texture c PRTL03 texture c PRTL04 texture c PRTL05 texture c PRTL06 texture c PRTL07 texture c SEWER01 texture c SEWER02 texture c SEWER05 texture c SEWER06 texture c SEWER07 texture c SEWER08 texture c SEWER09 texture c SEWER10 texture c SEWER11 texture c SEWER12 texture c SEWER13 texture c SEWER14 texture c S_02 texture c S_04 texture c S_05 texture c S_06 texture c S_07 texture c S_09 texture c S_12 texture c S_13 texture c T2_STEP texture c TOMB01 texture c TOMB02 texture c TOMB04 texture c TOMB05 texture c TOMB06 texture c TOMB07 texture c TOMB08 texture c TOMB09 texture c TOMB10 texture c TOMB11 texture c TOMB12 texture c TOMB13 texture c VILL01 texture c VILL04 texture c VILL05 texture c WINNOW02 texture c WOOD01 texture c WOOD02 texture c WOOD03 texture c WOOD04 flat c F_008 flat c F_009 flat c F_010 flat c F_011 flat c F_012 flat c F_013 flat c F_014 flat c F_015 flat c F_018 flat c F_021 flat c F_022 flat c F_023 flat c F_025 flat c F_027 flat c F_030 flat c F_031 flat c F_032 flat c F_037 flat c F_041 flat c F_042 flat c F_043 flat c F_044 flat c F_045 flat c F_046 flat c F_047 flat c F_048 flat c F_049 flat c F_050 flat c F_051 flat c F_052 flat c F_053 flat c F_054 flat c F_055 flat c F_057 flat c F_058 flat c F_077 flat c F_081 flat c F_082 flat c F_089 flat c F_092 flat c F_A501 texture d BRASS1 texture d BRASS3 texture d BRASS4 texture d DOOR51 texture d D_AXE texture d D_BRASS1 texture d D_BRASS2 texture d D_CAST texture d D_CAVE texture d D_CAVE2 texture d D_DUNGEO texture d D_END1 texture d D_END2 texture d D_END3 texture d D_END4 texture d D_ENDBR texture d D_ENDSLV texture d D_FIRE texture d D_RUST texture d D_SILKEY texture d D_SILVER texture d D_SLV1 texture d D_SLV2 texture d D_STEEL texture d D_SWAMP texture d D_SWAMP2 texture d D_WASTE texture d D_WD01 texture d D_WD02 texture d D_WD03 texture d D_WD04 texture d D_WD05 texture d D_WD06 texture d D_WD07 texture d D_WD08 texture d D_WD09 texture d D_WD10 texture d D_WINNOW texture g GATE01 texture g GATE02 texture g GATE03 texture g GATE04 texture g GATE51 texture g GATE52 texture g GATE53 texture g SEWER03 texture g SEWER04 texture g VILL06 texture g VILL07 texture g VILL08 texture g WEB1_L texture g WEB1_R texture g WEB2_L texture g WEB2_R texture g WEB3 texture g GLASS01 texture g GLASS02 texture g GLASS03 texture g GLASS04 texture g GLASS05 texture g GLASS06 texture g GLASS07 texture g TOMB03 texture g TOMB18 texture m FOREST10 texture m GILO1 texture m GILO2 texture m PLAT01 texture m PLAT02 texture m SPAWN01 texture m SPAWN02 texture m SPAWN03 texture m SPAWN04 texture m SPAWN05 texture m SPAWN06 texture m SPAWN07 texture m SPAWN08 texture m SPAWN09 texture m SPAWN10 texture m SPAWN11 texture m SPAWN12 texture m SPAWN13 texture m STEEL01 texture m STEEL02 texture m STEEL05 texture m STEEL06 texture m STEEL07 texture m STEEL08 texture m S_01 texture m VALVE01 texture m VALVE02 texture m VALVE1 texture m VALVE2 texture m WINN01 flat m F_061 flat m F_062 flat m F_063 flat m F_064 flat m F_065 flat m F_066 flat m F_067 flat m F_068 flat m F_069 flat m F_070 flat m F_071 flat m F_072 flat m F_073 flat m F_074 flat m F_075 flat m F_078 flat m F_083 flat m F_091 flat m F_081 flat m F_084 flat m F_085 flat m F_086 flat m F_087 flat m F_088 flat m X_012 flat m X_013 flat m X_014 flat m X_015 flat m X_016 texture n CAVE03 texture n CAVE04 texture n CAVE05 texture n CAVE06 texture n CHAP1 texture n CHAP2 texture n CHAP3 texture n FOREST06 texture n FOREST07 texture n ICE01 texture n WASTE01 texture n WASTE02 texture n WASTE03 texture n WASTE04 texture n GRAVE01 texture n GRAVE03 texture n GRAVE04 texture n GRAVE05 texture n GRAVE06 texture n GRAVE07 texture n GRAVE08 texture n CASTLE11 texture n CAVE01 texture n CAVE02 texture n CAVE11 texture n CAVE12 texture n FOREST01 texture n FOREST02 texture n FOREST03 texture n FOREST04 texture n FOREST11 texture n FOREST12 texture n SWAMP01 texture n SWAMP03 texture n SWAMP04 texture n SWAMP06 texture n SWAMP07 texture n S_11 texture n X_FIRE01 texture n X_FIRE02 texture n X_FIRE03 texture n X_FIRE04 texture n X_SWMP1 texture n X_SWMP2 texture n X_SWMP3 texture n X_SWR1 texture n X_SWR2 texture n X_SWR3 texture n X_WATER1 texture n X_WATER2 texture n X_WATER3 texture n X_WATER4 flat n F_001 flat n F_002 flat n F_003 flat n F_004 flat n F_005 flat n F_006 flat n F_007 flat n F_024 flat n F_033 flat n F_034 flat n F_038 flat n F_039 flat n F_040 flat n F_SKY flat n F_017 flat n F_019 flat n F_020 flat n F_076 flat n F_029 flat n F_028 flat n F_059 flat n X_001 flat n X_002 flat n X_003 flat n X_004 flat n X_005 flat n X_006 flat n X_007 flat n X_008 flat n X_009 flat n X_010 flat n X_011 texture p CLOCKA texture p CLOCKB texture p CLOCKC texture p CLOCK01 texture p CLOCK02 texture p CLOCK03 texture p CLOCK04 texture p CLOCK05 texture p CLOCK06 texture p CLOCK07 texture p CLOCK08 texture p CLOCK11 texture p CLOCK12 texture p CLOCK13 texture p CLOCK14 texture p CLOCK15 texture p CLOCK16 texture p CLOCK17 texture p CLOCK18 texture p FORPUZ1 texture p FORPUZ2 texture p FORPUZ3 texture p GEAR01 texture p GEAR02 texture p GEAR03 texture p GEAR04 texture p GEAR05 texture p GEAR0A texture p GEAR0B texture p GEARW texture p GEARX texture p GEARY texture p GEARZ texture p PLANET1 texture p PLANET2 texture p PUZZLE1 texture p PUZZLE2 texture p PUZZLE3 texture p PUZZLE4 texture p PUZZLE5 texture p PUZZLE6 texture p PUZZLE7 texture p PUZZLE8 texture p PUZZLE9 texture p PUZZLE10 texture p PUZZLE11 texture p PUZZLE12 texture s SW_1_DN texture s SW_1_MD texture s SW_1_UP texture s SW_2_DN texture s SW_2_MD texture s SW_2_UP texture s SW_EL1 texture s SW_EL2 texture s SW_EL3 texture s SW_EL4 texture s SW_EL5 texture s SW_OL1 texture s SW_OL2 texture s SW_OL3 texture s SW_OL4 texture s SW_OL5 texture s SW51_OFF texture s SW51_ON texture s SW52_OFF texture s SW52_ON texture s SW53_DN texture s SW53_MD texture s SW53_UP texture - BLANK texture - SKY1 texture - SKY2 texture - SKY3 texture - SKY4 texture - SKYFOG texture - SKYFOG2 texture - SKYWALL texture - SKYWALL2 texture - TPORTX texture - TPORT1 texture - TPORT2 texture - TPORT3 texture - TPORT4 texture - TPORT5 texture - TPORT6 texture - TPORT7 texture - TPORT8 texture - TPORT9 texture - X_FAC01 texture - X_FAC02 texture - X_FAC03 texture - X_FAC04 texture - X_FAC05 texture - X_FAC06 texture - X_FAC07 texture - X_FAC08 texture - X_FAC09 texture - X_FAC10 texture - X_FAC11 texture - X_FAC12 eureka-1.11-source/osx/0000755000175100017510000000000012647061302014300 5ustar aaptedaaptedeureka-1.11-source/osx/Eureka Doom Editor.xcodeproj/0000755000175100017510000000000012647061302021576 5ustar aaptedaaptedeureka-1.11-source/osx/Eureka Doom Editor.xcodeproj/project.pbxproj0000644000175100017510000023524612647061302024666 0ustar aaptedaapted// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 4F0364D81958EDA70000AE65 /* libpng16.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F0364D71958EDA70000AE65 /* libpng16.a */; }; 4F13FF231A16C1E700B64656 /* bindings.cfg in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4F13FF211A16C19700B64656 /* bindings.cfg */; }; 4F2181611755526A0053D99E /* libfltk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F2181601755526A0053D99E /* libfltk.a */; }; 4F218163175553040053D99E /* libz.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F218162175553040053D99E /* libz.a */; }; 4F288FC81A574B77000E03AD /* libfltk_forms.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F288FC61A574B77000E03AD /* libfltk_forms.a */; }; 4F288FC91A574B77000E03AD /* libfltk_gl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F288FC71A574B77000E03AD /* libfltk_gl.a */; }; 4F2D365417C96A7E003BEEE9 /* OSXCalls.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4F2D365217C96A7E003BEEE9 /* OSXCalls.mm */; }; 4F9C53A01A6CECFA001F4427 /* ui_default.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4F9C539C1A6CECFA001F4427 /* ui_default.cc */; }; 4F9C53A11A6CECFA001F4427 /* ui_replace.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4F9C539E1A6CECFA001F4427 /* ui_replace.cc */; }; 4FBD72EC179FBF9300937B50 /* e_checks2.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4FBD72EB179FBF9300937B50 /* e_checks2.cc */; }; 4FBD72FC179FC10100937B50 /* libfltk_images.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FBD72FB179FC10100937B50 /* libfltk_images.a */; }; 4FBD7300179FC18000937B50 /* libjpeg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FBD72FF179FC18000937B50 /* libjpeg.a */; }; 4FBD7302179FC5ED00937B50 /* about_logo.png in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4FBD7301179FC5ED00937B50 /* about_logo.png */; }; FA1E04EE16689A2900ED41DC /* ui_misc.cc in Sources */ = {isa = PBXBuildFile; fileRef = FA1E04EC16689A2900ED41DC /* ui_misc.cc */; }; FA244640166CAA6100C68ED8 /* common in CopyFiles */ = {isa = PBXBuildFile; fileRef = FA24463A166CAA6100C68ED8 /* common */; }; FA244642166CAA6100C68ED8 /* games in CopyFiles */ = {isa = PBXBuildFile; fileRef = FA24463C166CAA6100C68ED8 /* games */; }; FA244644166CAA6100C68ED8 /* mods in CopyFiles */ = {isa = PBXBuildFile; fileRef = FA24463E166CAA6100C68ED8 /* mods */; }; FA244645166CAA6100C68ED8 /* ports in CopyFiles */ = {isa = PBXBuildFile; fileRef = FA24463F166CAA6100C68ED8 /* ports */; }; FA4433D116AD9CB800525112 /* m_keys.cc in Sources */ = {isa = PBXBuildFile; fileRef = FA4433CF16AD9CB800525112 /* m_keys.cc */; }; FA5E2C2D165B8F860024D6A5 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA5E2C2C165B8F860024D6A5 /* Cocoa.framework */; }; FA5E2C37165B8F860024D6A5 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FA5E2C35165B8F860024D6A5 /* InfoPlist.strings */; }; FA5E2C3D165B8F860024D6A5 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = FA5E2C3B165B8F860024D6A5 /* Credits.rtf */; }; FA5E2C43165B8F860024D6A5 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = FA5E2C41165B8F860024D6A5 /* MainMenu.xib */; }; FA5E2C4B165B8F870024D6A5 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA5E2C4A165B8F870024D6A5 /* SenTestingKit.framework */; }; FA5E2C4C165B8F870024D6A5 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA5E2C2C165B8F860024D6A5 /* Cocoa.framework */; }; FA6ADC22165E75D400FB10D1 /* im_arrows.cc in Sources */ = {isa = PBXBuildFile; fileRef = FA6ADC21165E75D400FB10D1 /* im_arrows.cc */; }; FA85EEE816936A3A00CA6FC2 /* m_files.cc in Sources */ = {isa = PBXBuildFile; fileRef = FA85EEE216936A3A00CA6FC2 /* m_files.cc */; }; FA85EEE916936A3A00CA6FC2 /* ui_file.cc in Sources */ = {isa = PBXBuildFile; fileRef = FA85EEE416936A3A00CA6FC2 /* ui_file.cc */; }; FA85EEEA16936A3A00CA6FC2 /* ui_prefs.cc in Sources */ = {isa = PBXBuildFile; fileRef = FA85EEE616936A3A00CA6FC2 /* ui_prefs.cc */; }; FA8DBCFC165D293600FCFB1A /* main.cc in Sources */ = {isa = PBXBuildFile; fileRef = FA8DBCFA165D293600FCFB1A /* main.cc */; }; FA8DBD73165D435600FCFB1A /* Eureka Doom EditorIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = FA8DBD72165D435600FCFB1A /* Eureka Doom EditorIcon.icns */; }; FABBC0FA165B90280080245F /* e_basis.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC080165B90280080245F /* e_basis.cc */; }; FABBC0FB165B90280080245F /* e_checks.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC082165B90280080245F /* e_checks.cc */; }; FABBC0FC165B90280080245F /* e_cutpaste.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC084165B90280080245F /* e_cutpaste.cc */; }; FABBC0FD165B90280080245F /* e_linedef.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC086165B90280080245F /* e_linedef.cc */; }; FABBC0FE165B90280080245F /* e_loadsave.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC088165B90280080245F /* e_loadsave.cc */; }; FABBC0FF165B90280080245F /* e_nodes.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC08A165B90280080245F /* e_nodes.cc */; }; FABBC100165B90280080245F /* e_path.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC08C165B90280080245F /* e_path.cc */; }; FABBC101165B90280080245F /* e_sector.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC08E165B90280080245F /* e_sector.cc */; }; FABBC102165B90280080245F /* e_things.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC090165B90280080245F /* e_things.cc */; }; FABBC103165B90280080245F /* e_vertex.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC092165B90280080245F /* e_vertex.cc */; }; FABBC104165B90280080245F /* editloop.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC094165B90280080245F /* editloop.cc */; }; FABBC105165B90280080245F /* im_color.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC097165B90280080245F /* im_color.cc */; }; FABBC106165B90280080245F /* im_img.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC099165B90280080245F /* im_img.cc */; }; FABBC107165B90280080245F /* levels.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC09B165B90280080245F /* levels.cc */; }; FABBC108165B90280080245F /* lib_adler.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC09D165B90280080245F /* lib_adler.cc */; }; FABBC109165B90280080245F /* lib_file.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC09F165B90280080245F /* lib_file.cc */; }; FABBC10A165B90280080245F /* lib_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0A1165B90280080245F /* lib_util.cc */; }; FABBC10B165B90280080245F /* m_bitvec.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0A3165B90280080245F /* m_bitvec.cc */; }; FABBC10C165B90280080245F /* m_config.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0A5165B90280080245F /* m_config.cc */; }; FABBC10E165B90280080245F /* m_game.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0A9165B90280080245F /* m_game.cc */; }; FABBC10F165B90280080245F /* m_select.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0AB165B90280080245F /* m_select.cc */; }; FABBC110165B90280080245F /* m_strings.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0AD165B90280080245F /* m_strings.cc */; }; FABBC112165B90280080245F /* objects.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0B1165B90280080245F /* objects.cc */; }; FABBC113165B90280080245F /* r_grid.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0B4165B90280080245F /* r_grid.cc */; }; FABBC115165B90280080245F /* r_render.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0B8165B90280080245F /* r_render.cc */; }; FABBC118165B90280080245F /* sys_debug.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0BE165B90280080245F /* sys_debug.cc */; }; FABBC119165B90280080245F /* ui_about.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0C3165B90280080245F /* ui_about.cc */; }; FABBC11A165B90280080245F /* ui_browser.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0C5165B90280080245F /* ui_browser.cc */; }; FABBC11B165B90280080245F /* ui_canvas.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0C7165B90280080245F /* ui_canvas.cc */; }; FABBC11C165B90280080245F /* ui_dialog.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0C9165B90280080245F /* ui_dialog.cc */; }; FABBC11D165B90280080245F /* ui_hyper.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0CB165B90280080245F /* ui_hyper.cc */; }; FABBC11E165B90280080245F /* ui_infobar.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0CD165B90280080245F /* ui_infobar.cc */; }; FABBC11F165B90280080245F /* ui_linedef.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0CF165B90280080245F /* ui_linedef.cc */; }; FABBC120165B90280080245F /* ui_menu.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0D1165B90280080245F /* ui_menu.cc */; }; FABBC121165B90280080245F /* ui_nodes.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0D3165B90280080245F /* ui_nodes.cc */; }; FABBC122165B90280080245F /* ui_nombre.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0D5165B90280080245F /* ui_nombre.cc */; }; FABBC123165B90280080245F /* ui_pic.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0D7165B90280080245F /* ui_pic.cc */; }; FABBC125165B90280080245F /* ui_scroll.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0DB165B90280080245F /* ui_scroll.cc */; }; FABBC126165B90280080245F /* ui_sector.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0DD165B90280080245F /* ui_sector.cc */; }; FABBC127165B90280080245F /* ui_sidedef.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0DF165B90280080245F /* ui_sidedef.cc */; }; FABBC128165B90280080245F /* ui_thing.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0E1165B90280080245F /* ui_thing.cc */; }; FABBC129165B90280080245F /* ui_tile.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0E3165B90280080245F /* ui_tile.cc */; }; FABBC12A165B90280080245F /* ui_vertex.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0E5165B90280080245F /* ui_vertex.cc */; }; FABBC12B165B90280080245F /* ui_window.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0E7165B90280080245F /* ui_window.cc */; }; FABBC12C165B90280080245F /* w_flats.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0E9165B90280080245F /* w_flats.cc */; }; FABBC12D165B90280080245F /* w_loadpic.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0EB165B90280080245F /* w_loadpic.cc */; }; FABBC12E165B90280080245F /* w_sprite.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0EE165B90280080245F /* w_sprite.cc */; }; FABBC12F165B90280080245F /* w_texture.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0F0165B90280080245F /* w_texture.cc */; }; FABBC130165B90280080245F /* w_wad.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0F2165B90280080245F /* w_wad.cc */; }; FABBC131165B90280080245F /* x_hover.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0F4165B90280080245F /* x_hover.cc */; }; FABBC132165B90280080245F /* x_loop.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0F6165B90280080245F /* x_loop.cc */; }; FABBC133165B90280080245F /* x_mirror.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC0F8165B90280080245F /* x_mirror.cc */; }; FABBC255165B990C0080245F /* analyze.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC240165B990C0080245F /* analyze.cc */; }; FABBC256165B990C0080245F /* blockmap.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC242165B990C0080245F /* blockmap.cc */; }; FABBC257165B990C0080245F /* glbsp.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC244165B990C0080245F /* glbsp.cc */; }; FABBC258165B990C0080245F /* level.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC246165B990C0080245F /* level.cc */; }; FABBC259165B990C0080245F /* node.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC248165B990C0080245F /* node.cc */; }; FABBC25A165B990C0080245F /* reject.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC24A165B990C0080245F /* reject.cc */; }; FABBC25B165B990C0080245F /* seg.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC24C165B990C0080245F /* seg.cc */; }; FABBC25C165B990C0080245F /* system.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC24F165B990C0080245F /* system.cc */; }; FABBC25D165B990C0080245F /* util.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC251165B990C0080245F /* util.cc */; }; FABBC25E165B990C0080245F /* wad.cc in Sources */ = {isa = PBXBuildFile; fileRef = FABBC253165B990C0080245F /* wad.cc */; }; FADB99F316B017D600A28204 /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = FADB99F216B017D600A28204 /* AppDelegate.mm */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ FA5E2C4D165B8F870024D6A5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = FA5E2C1F165B8F860024D6A5 /* Project object */; proxyType = 1; remoteGlobalIDString = FA5E2C27165B8F860024D6A5; remoteInfo = EurekaApp; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ FA177ABD165FD56200B797F3 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; FAF8A110165C0001009B4C14 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 7; files = ( FA244640166CAA6100C68ED8 /* common in CopyFiles */, 4F13FF231A16C1E700B64656 /* bindings.cfg in CopyFiles */, FA244642166CAA6100C68ED8 /* games in CopyFiles */, 4FBD7302179FC5ED00937B50 /* about_logo.png in CopyFiles */, FA244644166CAA6100C68ED8 /* mods in CopyFiles */, FA244645166CAA6100C68ED8 /* ports in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 4F0364D71958EDA70000AE65 /* libpng16.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng16.a; path = staticlib/libpng16.a; sourceTree = ""; }; 4F13FF211A16C19700B64656 /* bindings.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = bindings.cfg; path = ../bindings.cfg; sourceTree = ""; }; 4F2181601755526A0053D99E /* libfltk.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfltk.a; path = staticlib/libfltk.a; sourceTree = ""; }; 4F218162175553040053D99E /* libz.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libz.a; path = staticlib/libz.a; sourceTree = ""; }; 4F288FC61A574B77000E03AD /* libfltk_forms.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfltk_forms.a; path = staticlib/libfltk_forms.a; sourceTree = ""; }; 4F288FC71A574B77000E03AD /* libfltk_gl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfltk_gl.a; path = staticlib/libfltk_gl.a; sourceTree = ""; }; 4F2D365217C96A7E003BEEE9 /* OSXCalls.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OSXCalls.mm; sourceTree = ""; }; 4F2D365317C96A7E003BEEE9 /* OSXCalls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSXCalls.h; sourceTree = ""; }; 4F9C539C1A6CECFA001F4427 /* ui_default.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_default.cc; path = ../../src/ui_default.cc; sourceTree = ""; }; 4F9C539D1A6CECFA001F4427 /* ui_default.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_default.h; path = ../../src/ui_default.h; sourceTree = ""; }; 4F9C539E1A6CECFA001F4427 /* ui_replace.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_replace.cc; path = ../../src/ui_replace.cc; sourceTree = ""; }; 4F9C539F1A6CECFA001F4427 /* ui_replace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_replace.h; path = ../../src/ui_replace.h; sourceTree = ""; }; 4FBD72EB179FBF9300937B50 /* e_checks2.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = e_checks2.cc; path = ../../src/e_checks2.cc; sourceTree = ""; usesTabs = 1; }; 4FBD72FB179FC10100937B50 /* libfltk_images.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfltk_images.a; path = staticlib/libfltk_images.a; sourceTree = ""; }; 4FBD72FF179FC18000937B50 /* libjpeg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjpeg.a; path = staticlib/libjpeg.a; sourceTree = ""; }; 4FBD7301179FC5ED00937B50 /* about_logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = about_logo.png; path = ../misc/about_logo.png; sourceTree = ""; }; FA1E04EC16689A2900ED41DC /* ui_misc.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_misc.cc; path = ../../src/ui_misc.cc; sourceTree = ""; usesTabs = 1; }; FA1E04ED16689A2900ED41DC /* ui_misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_misc.h; path = ../../src/ui_misc.h; sourceTree = ""; usesTabs = 1; }; FA24463A166CAA6100C68ED8 /* common */ = {isa = PBXFileReference; lastKnownFileType = folder; name = common; path = ../common; sourceTree = ""; }; FA24463B166CAA6100C68ED8 /* docs */ = {isa = PBXFileReference; lastKnownFileType = folder; name = docs; path = ../docs; sourceTree = ""; }; FA24463C166CAA6100C68ED8 /* games */ = {isa = PBXFileReference; lastKnownFileType = folder; name = games; path = ../games; sourceTree = ""; }; FA24463D166CAA6100C68ED8 /* misc */ = {isa = PBXFileReference; lastKnownFileType = folder; name = misc; path = ../misc; sourceTree = ""; }; FA24463E166CAA6100C68ED8 /* mods */ = {isa = PBXFileReference; lastKnownFileType = folder; name = mods; path = ../mods; sourceTree = ""; }; FA24463F166CAA6100C68ED8 /* ports */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ports; path = ../ports; sourceTree = ""; }; FA4433CF16AD9CB800525112 /* m_keys.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = m_keys.cc; path = ../../src/m_keys.cc; sourceTree = ""; usesTabs = 1; }; FA4433D016AD9CB800525112 /* m_keys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_keys.h; path = ../../src/m_keys.h; sourceTree = ""; usesTabs = 1; }; FA5E2C28165B8F860024D6A5 /* Eureka Doom Editor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Eureka Doom Editor.app"; sourceTree = BUILT_PRODUCTS_DIR; }; FA5E2C2C165B8F860024D6A5 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; FA5E2C2F165B8F860024D6A5 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; FA5E2C30165B8F860024D6A5 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; FA5E2C31165B8F860024D6A5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; FA5E2C34165B8F860024D6A5 /* Eureka Doom Editor-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Eureka Doom Editor-Info.plist"; sourceTree = ""; }; FA5E2C36165B8F860024D6A5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; FA5E2C3A165B8F860024D6A5 /* Eureka Doom Editor-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Eureka Doom Editor-Prefix.pch"; sourceTree = ""; }; FA5E2C3C165B8F860024D6A5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; FA5E2C3E165B8F860024D6A5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; FA5E2C42165B8F860024D6A5 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; FA5E2C49165B8F870024D6A5 /* Eureka Doom EditorTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Eureka Doom EditorTests.octest"; sourceTree = BUILT_PRODUCTS_DIR; }; FA5E2C4A165B8F870024D6A5 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; FA6ADC21165E75D400FB10D1 /* im_arrows.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = im_arrows.cc; path = ../../src/im_arrows.cc; sourceTree = ""; usesTabs = 1; }; FA85EEE216936A3A00CA6FC2 /* m_files.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = m_files.cc; path = ../../src/m_files.cc; sourceTree = ""; usesTabs = 1; }; FA85EEE316936A3A00CA6FC2 /* m_files.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_files.h; path = ../../src/m_files.h; sourceTree = ""; usesTabs = 1; }; FA85EEE416936A3A00CA6FC2 /* ui_file.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_file.cc; path = ../../src/ui_file.cc; sourceTree = ""; usesTabs = 1; }; FA85EEE516936A3A00CA6FC2 /* ui_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_file.h; path = ../../src/ui_file.h; sourceTree = ""; usesTabs = 1; }; FA85EEE616936A3A00CA6FC2 /* ui_prefs.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_prefs.cc; path = ../../src/ui_prefs.cc; sourceTree = ""; usesTabs = 1; }; FA85EEE716936A3A00CA6FC2 /* ui_prefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_prefs.h; path = ../../src/ui_prefs.h; sourceTree = ""; usesTabs = 1; }; FA8DBCFA165D293600FCFB1A /* main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cc; path = ../../src/main.cc; sourceTree = ""; usesTabs = 1; }; FA8DBCFB165D293600FCFB1A /* main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = main.h; path = ../../src/main.h; sourceTree = ""; usesTabs = 1; }; FA8DBD72165D435600FCFB1A /* Eureka Doom EditorIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = "Eureka Doom EditorIcon.icns"; sourceTree = ""; }; FABBC080165B90280080245F /* e_basis.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = e_basis.cc; path = ../../src/e_basis.cc; sourceTree = ""; usesTabs = 1; }; FABBC081165B90280080245F /* e_basis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = e_basis.h; path = ../../src/e_basis.h; sourceTree = ""; usesTabs = 1; }; FABBC082165B90280080245F /* e_checks.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = e_checks.cc; path = ../../src/e_checks.cc; sourceTree = ""; usesTabs = 1; }; FABBC083165B90280080245F /* e_checks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = e_checks.h; path = ../../src/e_checks.h; sourceTree = ""; usesTabs = 1; }; FABBC084165B90280080245F /* e_cutpaste.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = e_cutpaste.cc; path = ../../src/e_cutpaste.cc; sourceTree = ""; usesTabs = 1; }; FABBC085165B90280080245F /* e_cutpaste.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = e_cutpaste.h; path = ../../src/e_cutpaste.h; sourceTree = ""; usesTabs = 1; }; FABBC086165B90280080245F /* e_linedef.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = e_linedef.cc; path = ../../src/e_linedef.cc; sourceTree = ""; usesTabs = 1; }; FABBC087165B90280080245F /* e_linedef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = e_linedef.h; path = ../../src/e_linedef.h; sourceTree = ""; usesTabs = 1; }; FABBC088165B90280080245F /* e_loadsave.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = e_loadsave.cc; path = ../../src/e_loadsave.cc; sourceTree = ""; usesTabs = 1; }; FABBC089165B90280080245F /* e_loadsave.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = e_loadsave.h; path = ../../src/e_loadsave.h; sourceTree = ""; usesTabs = 1; }; FABBC08A165B90280080245F /* e_nodes.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = e_nodes.cc; path = ../../src/e_nodes.cc; sourceTree = ""; usesTabs = 1; }; FABBC08B165B90280080245F /* e_nodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = e_nodes.h; path = ../../src/e_nodes.h; sourceTree = ""; usesTabs = 1; }; FABBC08C165B90280080245F /* e_path.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = e_path.cc; path = ../../src/e_path.cc; sourceTree = ""; usesTabs = 1; }; FABBC08D165B90280080245F /* e_path.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = e_path.h; path = ../../src/e_path.h; sourceTree = ""; usesTabs = 1; }; FABBC08E165B90280080245F /* e_sector.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = e_sector.cc; path = ../../src/e_sector.cc; sourceTree = ""; usesTabs = 1; }; FABBC08F165B90280080245F /* e_sector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = e_sector.h; path = ../../src/e_sector.h; sourceTree = ""; usesTabs = 1; }; FABBC090165B90280080245F /* e_things.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = e_things.cc; path = ../../src/e_things.cc; sourceTree = ""; usesTabs = 1; }; FABBC091165B90280080245F /* e_things.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = e_things.h; path = ../../src/e_things.h; sourceTree = ""; usesTabs = 1; }; FABBC092165B90280080245F /* e_vertex.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = e_vertex.cc; path = ../../src/e_vertex.cc; sourceTree = ""; usesTabs = 1; }; FABBC093165B90280080245F /* e_vertex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = e_vertex.h; path = ../../src/e_vertex.h; sourceTree = ""; usesTabs = 1; }; FABBC094165B90280080245F /* editloop.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = editloop.cc; path = ../../src/editloop.cc; sourceTree = ""; usesTabs = 1; }; FABBC095165B90280080245F /* editloop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = editloop.h; path = ../../src/editloop.h; sourceTree = ""; usesTabs = 1; }; FABBC096165B90280080245F /* hdr_fltk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hdr_fltk.h; path = ../../src/hdr_fltk.h; sourceTree = ""; usesTabs = 1; }; FABBC097165B90280080245F /* im_color.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = im_color.cc; path = ../../src/im_color.cc; sourceTree = ""; usesTabs = 1; }; FABBC098165B90280080245F /* im_color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = im_color.h; path = ../../src/im_color.h; sourceTree = ""; usesTabs = 1; }; FABBC099165B90280080245F /* im_img.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = im_img.cc; path = ../../src/im_img.cc; sourceTree = ""; usesTabs = 1; }; FABBC09A165B90280080245F /* im_img.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = im_img.h; path = ../../src/im_img.h; sourceTree = ""; usesTabs = 1; }; FABBC09B165B90280080245F /* levels.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = levels.cc; path = ../../src/levels.cc; sourceTree = ""; usesTabs = 1; }; FABBC09C165B90280080245F /* levels.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = levels.h; path = ../../src/levels.h; sourceTree = ""; usesTabs = 1; }; FABBC09D165B90280080245F /* lib_adler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = lib_adler.cc; path = ../../src/lib_adler.cc; sourceTree = ""; usesTabs = 1; }; FABBC09E165B90280080245F /* lib_adler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lib_adler.h; path = ../../src/lib_adler.h; sourceTree = ""; usesTabs = 1; }; FABBC09F165B90280080245F /* lib_file.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = lib_file.cc; path = ../../src/lib_file.cc; sourceTree = ""; usesTabs = 1; }; FABBC0A0165B90280080245F /* lib_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lib_file.h; path = ../../src/lib_file.h; sourceTree = ""; usesTabs = 1; }; FABBC0A1165B90280080245F /* lib_util.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = lib_util.cc; path = ../../src/lib_util.cc; sourceTree = ""; usesTabs = 1; }; FABBC0A2165B90280080245F /* lib_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lib_util.h; path = ../../src/lib_util.h; sourceTree = ""; usesTabs = 1; }; FABBC0A3165B90280080245F /* m_bitvec.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = m_bitvec.cc; path = ../../src/m_bitvec.cc; sourceTree = ""; usesTabs = 1; }; FABBC0A4165B90280080245F /* m_bitvec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_bitvec.h; path = ../../src/m_bitvec.h; sourceTree = ""; usesTabs = 1; }; FABBC0A5165B90280080245F /* m_config.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = m_config.cc; path = ../../src/m_config.cc; sourceTree = ""; usesTabs = 1; }; FABBC0A6165B90280080245F /* m_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_config.h; path = ../../src/m_config.h; sourceTree = ""; usesTabs = 1; }; FABBC0A9165B90280080245F /* m_game.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = m_game.cc; path = ../../src/m_game.cc; sourceTree = ""; usesTabs = 1; }; FABBC0AA165B90280080245F /* m_game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_game.h; path = ../../src/m_game.h; sourceTree = ""; usesTabs = 1; }; FABBC0AB165B90280080245F /* m_select.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = m_select.cc; path = ../../src/m_select.cc; sourceTree = ""; usesTabs = 1; }; FABBC0AC165B90280080245F /* m_select.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_select.h; path = ../../src/m_select.h; sourceTree = ""; usesTabs = 1; }; FABBC0AD165B90280080245F /* m_strings.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = m_strings.cc; path = ../../src/m_strings.cc; sourceTree = ""; usesTabs = 1; }; FABBC0AE165B90280080245F /* m_strings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m_strings.h; path = ../../src/m_strings.h; sourceTree = ""; usesTabs = 1; }; FABBC0B1165B90280080245F /* objects.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = objects.cc; path = ../../src/objects.cc; sourceTree = ""; usesTabs = 1; }; FABBC0B2165B90280080245F /* objects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = objects.h; path = ../../src/objects.h; sourceTree = ""; usesTabs = 1; }; FABBC0B3165B90280080245F /* objid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = objid.h; path = ../../src/objid.h; sourceTree = ""; usesTabs = 1; }; FABBC0B4165B90280080245F /* r_grid.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = r_grid.cc; path = ../../src/r_grid.cc; sourceTree = ""; usesTabs = 1; }; FABBC0B5165B90280080245F /* r_grid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_grid.h; path = ../../src/r_grid.h; sourceTree = ""; usesTabs = 1; }; FABBC0B8165B90280080245F /* r_render.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = r_render.cc; path = ../../src/r_render.cc; sourceTree = ""; usesTabs = 1; }; FABBC0B9165B90280080245F /* r_render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = r_render.h; path = ../../src/r_render.h; sourceTree = ""; usesTabs = 1; }; FABBC0BE165B90280080245F /* sys_debug.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = sys_debug.cc; path = ../../src/sys_debug.cc; sourceTree = ""; usesTabs = 1; }; FABBC0BF165B90280080245F /* sys_debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sys_debug.h; path = ../../src/sys_debug.h; sourceTree = ""; usesTabs = 1; }; FABBC0C0165B90280080245F /* sys_endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sys_endian.h; path = ../../src/sys_endian.h; sourceTree = ""; usesTabs = 1; }; FABBC0C1165B90280080245F /* sys_macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sys_macro.h; path = ../../src/sys_macro.h; sourceTree = ""; usesTabs = 1; }; FABBC0C2165B90280080245F /* sys_type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sys_type.h; path = ../../src/sys_type.h; sourceTree = ""; usesTabs = 1; }; FABBC0C3165B90280080245F /* ui_about.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_about.cc; path = ../../src/ui_about.cc; sourceTree = ""; usesTabs = 1; }; FABBC0C4165B90280080245F /* ui_about.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_about.h; path = ../../src/ui_about.h; sourceTree = ""; usesTabs = 1; }; FABBC0C5165B90280080245F /* ui_browser.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_browser.cc; path = ../../src/ui_browser.cc; sourceTree = ""; usesTabs = 1; }; FABBC0C6165B90280080245F /* ui_browser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_browser.h; path = ../../src/ui_browser.h; sourceTree = ""; usesTabs = 1; }; FABBC0C7165B90280080245F /* ui_canvas.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_canvas.cc; path = ../../src/ui_canvas.cc; sourceTree = ""; usesTabs = 1; }; FABBC0C8165B90280080245F /* ui_canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_canvas.h; path = ../../src/ui_canvas.h; sourceTree = ""; usesTabs = 1; }; FABBC0C9165B90280080245F /* ui_dialog.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_dialog.cc; path = ../../src/ui_dialog.cc; sourceTree = ""; usesTabs = 1; }; FABBC0CB165B90280080245F /* ui_hyper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_hyper.cc; path = ../../src/ui_hyper.cc; sourceTree = ""; usesTabs = 1; }; FABBC0CC165B90280080245F /* ui_hyper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_hyper.h; path = ../../src/ui_hyper.h; sourceTree = ""; usesTabs = 1; }; FABBC0CD165B90280080245F /* ui_infobar.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_infobar.cc; path = ../../src/ui_infobar.cc; sourceTree = ""; usesTabs = 1; }; FABBC0CE165B90280080245F /* ui_infobar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_infobar.h; path = ../../src/ui_infobar.h; sourceTree = ""; usesTabs = 1; }; FABBC0CF165B90280080245F /* ui_linedef.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_linedef.cc; path = ../../src/ui_linedef.cc; sourceTree = ""; usesTabs = 1; }; FABBC0D0165B90280080245F /* ui_linedef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_linedef.h; path = ../../src/ui_linedef.h; sourceTree = ""; usesTabs = 1; }; FABBC0D1165B90280080245F /* ui_menu.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_menu.cc; path = ../../src/ui_menu.cc; sourceTree = ""; usesTabs = 1; }; FABBC0D2165B90280080245F /* ui_menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_menu.h; path = ../../src/ui_menu.h; sourceTree = ""; usesTabs = 1; }; FABBC0D3165B90280080245F /* ui_nodes.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_nodes.cc; path = ../../src/ui_nodes.cc; sourceTree = ""; usesTabs = 1; }; FABBC0D4165B90280080245F /* ui_nodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_nodes.h; path = ../../src/ui_nodes.h; sourceTree = ""; usesTabs = 1; }; FABBC0D5165B90280080245F /* ui_nombre.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_nombre.cc; path = ../../src/ui_nombre.cc; sourceTree = ""; usesTabs = 1; }; FABBC0D6165B90280080245F /* ui_nombre.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_nombre.h; path = ../../src/ui_nombre.h; sourceTree = ""; usesTabs = 1; }; FABBC0D7165B90280080245F /* ui_pic.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_pic.cc; path = ../../src/ui_pic.cc; sourceTree = ""; usesTabs = 1; }; FABBC0D8165B90280080245F /* ui_pic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_pic.h; path = ../../src/ui_pic.h; sourceTree = ""; usesTabs = 1; }; FABBC0DB165B90280080245F /* ui_scroll.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_scroll.cc; path = ../../src/ui_scroll.cc; sourceTree = ""; usesTabs = 1; }; FABBC0DC165B90280080245F /* ui_scroll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_scroll.h; path = ../../src/ui_scroll.h; sourceTree = ""; usesTabs = 1; }; FABBC0DD165B90280080245F /* ui_sector.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_sector.cc; path = ../../src/ui_sector.cc; sourceTree = ""; usesTabs = 1; }; FABBC0DE165B90280080245F /* ui_sector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_sector.h; path = ../../src/ui_sector.h; sourceTree = ""; usesTabs = 1; }; FABBC0DF165B90280080245F /* ui_sidedef.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_sidedef.cc; path = ../../src/ui_sidedef.cc; sourceTree = ""; usesTabs = 1; }; FABBC0E0165B90280080245F /* ui_sidedef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_sidedef.h; path = ../../src/ui_sidedef.h; sourceTree = ""; usesTabs = 1; }; FABBC0E1165B90280080245F /* ui_thing.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_thing.cc; path = ../../src/ui_thing.cc; sourceTree = ""; usesTabs = 1; }; FABBC0E2165B90280080245F /* ui_thing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_thing.h; path = ../../src/ui_thing.h; sourceTree = ""; usesTabs = 1; }; FABBC0E3165B90280080245F /* ui_tile.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_tile.cc; path = ../../src/ui_tile.cc; sourceTree = ""; usesTabs = 1; }; FABBC0E4165B90280080245F /* ui_tile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_tile.h; path = ../../src/ui_tile.h; sourceTree = ""; usesTabs = 1; }; FABBC0E5165B90280080245F /* ui_vertex.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_vertex.cc; path = ../../src/ui_vertex.cc; sourceTree = ""; usesTabs = 1; }; FABBC0E6165B90280080245F /* ui_vertex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_vertex.h; path = ../../src/ui_vertex.h; sourceTree = ""; usesTabs = 1; }; FABBC0E7165B90280080245F /* ui_window.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ui_window.cc; path = ../../src/ui_window.cc; sourceTree = ""; usesTabs = 1; }; FABBC0E8165B90280080245F /* ui_window.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_window.h; path = ../../src/ui_window.h; sourceTree = ""; usesTabs = 1; }; FABBC0E9165B90280080245F /* w_flats.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = w_flats.cc; path = ../../src/w_flats.cc; sourceTree = ""; usesTabs = 1; }; FABBC0EA165B90280080245F /* w_flats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = w_flats.h; path = ../../src/w_flats.h; sourceTree = ""; usesTabs = 1; }; FABBC0EB165B90280080245F /* w_loadpic.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = w_loadpic.cc; path = ../../src/w_loadpic.cc; sourceTree = ""; usesTabs = 1; }; FABBC0EC165B90280080245F /* w_loadpic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = w_loadpic.h; path = ../../src/w_loadpic.h; sourceTree = ""; usesTabs = 1; }; FABBC0ED165B90280080245F /* w_rawdef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = w_rawdef.h; path = ../../src/w_rawdef.h; sourceTree = ""; usesTabs = 1; }; FABBC0EE165B90280080245F /* w_sprite.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = w_sprite.cc; path = ../../src/w_sprite.cc; sourceTree = ""; usesTabs = 1; }; FABBC0EF165B90280080245F /* w_sprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = w_sprite.h; path = ../../src/w_sprite.h; sourceTree = ""; usesTabs = 1; }; FABBC0F0165B90280080245F /* w_texture.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = w_texture.cc; path = ../../src/w_texture.cc; sourceTree = ""; usesTabs = 1; }; FABBC0F1165B90280080245F /* w_texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = w_texture.h; path = ../../src/w_texture.h; sourceTree = ""; usesTabs = 1; }; FABBC0F2165B90280080245F /* w_wad.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = w_wad.cc; path = ../../src/w_wad.cc; sourceTree = ""; usesTabs = 1; }; FABBC0F3165B90280080245F /* w_wad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = w_wad.h; path = ../../src/w_wad.h; sourceTree = ""; usesTabs = 1; }; FABBC0F4165B90280080245F /* x_hover.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = x_hover.cc; path = ../../src/x_hover.cc; sourceTree = ""; usesTabs = 1; }; FABBC0F5165B90280080245F /* x_hover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = x_hover.h; path = ../../src/x_hover.h; sourceTree = ""; usesTabs = 1; }; FABBC0F6165B90280080245F /* x_loop.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = x_loop.cc; path = ../../src/x_loop.cc; sourceTree = ""; usesTabs = 1; }; FABBC0F7165B90280080245F /* x_loop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = x_loop.h; path = ../../src/x_loop.h; sourceTree = ""; usesTabs = 1; }; FABBC0F8165B90280080245F /* x_mirror.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = x_mirror.cc; path = ../../src/x_mirror.cc; sourceTree = ""; usesTabs = 1; }; FABBC0F9165B90280080245F /* x_mirror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = x_mirror.h; path = ../../src/x_mirror.h; sourceTree = ""; usesTabs = 1; }; FABBC240165B990C0080245F /* analyze.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = analyze.cc; sourceTree = ""; usesTabs = 1; }; FABBC241165B990C0080245F /* analyze.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = analyze.h; sourceTree = ""; usesTabs = 1; }; FABBC242165B990C0080245F /* blockmap.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blockmap.cc; sourceTree = ""; usesTabs = 1; }; FABBC243165B990C0080245F /* blockmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blockmap.h; sourceTree = ""; usesTabs = 1; }; FABBC244165B990C0080245F /* glbsp.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glbsp.cc; sourceTree = ""; usesTabs = 1; }; FABBC245165B990C0080245F /* glbsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glbsp.h; sourceTree = ""; usesTabs = 1; }; FABBC246165B990C0080245F /* level.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = level.cc; sourceTree = ""; usesTabs = 1; }; FABBC247165B990C0080245F /* level.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = level.h; sourceTree = ""; usesTabs = 1; }; FABBC248165B990C0080245F /* node.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = node.cc; sourceTree = ""; usesTabs = 1; }; FABBC249165B990C0080245F /* node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = node.h; sourceTree = ""; usesTabs = 1; }; FABBC24A165B990C0080245F /* reject.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reject.cc; sourceTree = ""; usesTabs = 1; }; FABBC24B165B990C0080245F /* reject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reject.h; sourceTree = ""; usesTabs = 1; }; FABBC24C165B990C0080245F /* seg.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = seg.cc; sourceTree = ""; usesTabs = 1; }; FABBC24D165B990C0080245F /* seg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seg.h; sourceTree = ""; usesTabs = 1; }; FABBC24E165B990C0080245F /* structs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = structs.h; sourceTree = ""; usesTabs = 1; }; FABBC24F165B990C0080245F /* system.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = system.cc; sourceTree = ""; usesTabs = 1; }; FABBC250165B990C0080245F /* system.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = system.h; sourceTree = ""; usesTabs = 1; }; FABBC251165B990C0080245F /* util.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = util.cc; sourceTree = ""; usesTabs = 1; }; FABBC252165B990C0080245F /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = ""; usesTabs = 1; }; FABBC253165B990C0080245F /* wad.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wad.cc; sourceTree = ""; usesTabs = 1; }; FABBC254165B990C0080245F /* wad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wad.h; sourceTree = ""; usesTabs = 1; }; FADB99F216B017D600A28204 /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate.mm; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ FA5E2C25165B8F860024D6A5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( FA5E2C2D165B8F860024D6A5 /* Cocoa.framework in Frameworks */, 4F2181611755526A0053D99E /* libfltk.a in Frameworks */, 4F0364D81958EDA70000AE65 /* libpng16.a in Frameworks */, 4F218163175553040053D99E /* libz.a in Frameworks */, 4FBD72FC179FC10100937B50 /* libfltk_images.a in Frameworks */, 4F288FC91A574B77000E03AD /* libfltk_gl.a in Frameworks */, 4F288FC81A574B77000E03AD /* libfltk_forms.a in Frameworks */, 4FBD7300179FC18000937B50 /* libjpeg.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; FA5E2C45165B8F870024D6A5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( FA5E2C4B165B8F870024D6A5 /* SenTestingKit.framework in Frameworks */, FA5E2C4C165B8F870024D6A5 /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ FA5E2C1D165B8F860024D6A5 = { isa = PBXGroup; children = ( 4F13FF211A16C19700B64656 /* bindings.cfg */, 4FBD7301179FC5ED00937B50 /* about_logo.png */, FA24463A166CAA6100C68ED8 /* common */, FA24463B166CAA6100C68ED8 /* docs */, FA24463C166CAA6100C68ED8 /* games */, FA24463D166CAA6100C68ED8 /* misc */, FA24463E166CAA6100C68ED8 /* mods */, FA24463F166CAA6100C68ED8 /* ports */, FA5E2C32165B8F860024D6A5 /* EurekaApp */, FA5E2C2B165B8F860024D6A5 /* Frameworks */, FA5E2C29165B8F860024D6A5 /* Products */, ); sourceTree = ""; }; FA5E2C29165B8F860024D6A5 /* Products */ = { isa = PBXGroup; children = ( FA5E2C28165B8F860024D6A5 /* Eureka Doom Editor.app */, FA5E2C49165B8F870024D6A5 /* Eureka Doom EditorTests.octest */, ); name = Products; sourceTree = ""; }; FA5E2C2B165B8F860024D6A5 /* Frameworks */ = { isa = PBXGroup; children = ( 4F288FC61A574B77000E03AD /* libfltk_forms.a */, 4F288FC71A574B77000E03AD /* libfltk_gl.a */, 4F0364D71958EDA70000AE65 /* libpng16.a */, 4FBD72FF179FC18000937B50 /* libjpeg.a */, 4FBD72FB179FC10100937B50 /* libfltk_images.a */, 4F218162175553040053D99E /* libz.a */, 4F2181601755526A0053D99E /* libfltk.a */, FA5E2C2C165B8F860024D6A5 /* Cocoa.framework */, FA5E2C4A165B8F870024D6A5 /* SenTestingKit.framework */, FA5E2C2E165B8F860024D6A5 /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; FA5E2C2E165B8F860024D6A5 /* Other Frameworks */ = { isa = PBXGroup; children = ( FA5E2C2F165B8F860024D6A5 /* AppKit.framework */, FA5E2C30165B8F860024D6A5 /* CoreData.framework */, FA5E2C31165B8F860024D6A5 /* Foundation.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; FA5E2C32165B8F860024D6A5 /* EurekaApp */ = { isa = PBXGroup; children = ( FA5E2C60165B8F950024D6A5 /* Eureka */, FAF8A0DF165BE342009B4C14 /* OSXPort */, FA5E2C33165B8F860024D6A5 /* Supporting Files */, ); path = EurekaApp; sourceTree = ""; }; FA5E2C33165B8F860024D6A5 /* Supporting Files */ = { isa = PBXGroup; children = ( FA5E2C41165B8F860024D6A5 /* MainMenu.xib */, FA8DBD72165D435600FCFB1A /* Eureka Doom EditorIcon.icns */, FA5E2C34165B8F860024D6A5 /* Eureka Doom Editor-Info.plist */, FA5E2C35165B8F860024D6A5 /* InfoPlist.strings */, FA5E2C3A165B8F860024D6A5 /* Eureka Doom Editor-Prefix.pch */, FA5E2C3B165B8F860024D6A5 /* Credits.rtf */, ); name = "Supporting Files"; sourceTree = ""; }; FA5E2C60165B8F950024D6A5 /* Eureka */ = { isa = PBXGroup; children = ( FA8DBCFA165D293600FCFB1A /* main.cc */, FA8DBCFB165D293600FCFB1A /* main.h */, FABBC23F165B990C0080245F /* glbsp_src */, FABBC13D165B90B60080245F /* x_ */, FABBC13C165B90A60080245F /* w_ */, FABBC13B165B90900080245F /* ui_ */, FABBC13A165B90860080245F /* sys_ */, FABBC139165B907A0080245F /* r_ */, FABBC138165B90690080245F /* m_ */, FABBC137165B905E0080245F /* lib_ */, FABBC136165B90500080245F /* im_ */, FABBC134165B90350080245F /* e_ */, FABBC094165B90280080245F /* editloop.cc */, FABBC095165B90280080245F /* editloop.h */, FABBC096165B90280080245F /* hdr_fltk.h */, FABBC09B165B90280080245F /* levels.cc */, FABBC09C165B90280080245F /* levels.h */, FABBC0B1165B90280080245F /* objects.cc */, FABBC0B2165B90280080245F /* objects.h */, FABBC0B3165B90280080245F /* objid.h */, ); name = Eureka; sourceTree = ""; }; FABBC134165B90350080245F /* e_ */ = { isa = PBXGroup; children = ( FABBC135165B903E0080245F /* headers */, 4FBD72EB179FBF9300937B50 /* e_checks2.cc */, FABBC080165B90280080245F /* e_basis.cc */, FABBC082165B90280080245F /* e_checks.cc */, FABBC084165B90280080245F /* e_cutpaste.cc */, FABBC086165B90280080245F /* e_linedef.cc */, FABBC088165B90280080245F /* e_loadsave.cc */, FABBC08A165B90280080245F /* e_nodes.cc */, FABBC08C165B90280080245F /* e_path.cc */, FABBC08E165B90280080245F /* e_sector.cc */, FABBC090165B90280080245F /* e_things.cc */, FABBC092165B90280080245F /* e_vertex.cc */, ); name = e_; sourceTree = ""; }; FABBC135165B903E0080245F /* headers */ = { isa = PBXGroup; children = ( FABBC081165B90280080245F /* e_basis.h */, FABBC083165B90280080245F /* e_checks.h */, FABBC085165B90280080245F /* e_cutpaste.h */, FABBC087165B90280080245F /* e_linedef.h */, FABBC089165B90280080245F /* e_loadsave.h */, FABBC08B165B90280080245F /* e_nodes.h */, FABBC08D165B90280080245F /* e_path.h */, FABBC08F165B90280080245F /* e_sector.h */, FABBC091165B90280080245F /* e_things.h */, FABBC093165B90280080245F /* e_vertex.h */, ); name = headers; sourceTree = ""; }; FABBC136165B90500080245F /* im_ */ = { isa = PBXGroup; children = ( FA6ADC21165E75D400FB10D1 /* im_arrows.cc */, FABBC097165B90280080245F /* im_color.cc */, FABBC098165B90280080245F /* im_color.h */, FABBC099165B90280080245F /* im_img.cc */, FABBC09A165B90280080245F /* im_img.h */, ); name = im_; sourceTree = ""; }; FABBC137165B905E0080245F /* lib_ */ = { isa = PBXGroup; children = ( FABBC09D165B90280080245F /* lib_adler.cc */, FABBC09E165B90280080245F /* lib_adler.h */, FABBC09F165B90280080245F /* lib_file.cc */, FABBC0A0165B90280080245F /* lib_file.h */, FABBC0A1165B90280080245F /* lib_util.cc */, FABBC0A2165B90280080245F /* lib_util.h */, ); name = lib_; sourceTree = ""; }; FABBC138165B90690080245F /* m_ */ = { isa = PBXGroup; children = ( FA4433CF16AD9CB800525112 /* m_keys.cc */, FA4433D016AD9CB800525112 /* m_keys.h */, FA85EEE216936A3A00CA6FC2 /* m_files.cc */, FA85EEE316936A3A00CA6FC2 /* m_files.h */, FABBC0A3165B90280080245F /* m_bitvec.cc */, FABBC0A4165B90280080245F /* m_bitvec.h */, FABBC0A5165B90280080245F /* m_config.cc */, FABBC0A6165B90280080245F /* m_config.h */, FABBC0A9165B90280080245F /* m_game.cc */, FABBC0AA165B90280080245F /* m_game.h */, FABBC0AB165B90280080245F /* m_select.cc */, FABBC0AC165B90280080245F /* m_select.h */, FABBC0AD165B90280080245F /* m_strings.cc */, FABBC0AE165B90280080245F /* m_strings.h */, ); name = m_; sourceTree = ""; }; FABBC139165B907A0080245F /* r_ */ = { isa = PBXGroup; children = ( FABBC0B4165B90280080245F /* r_grid.cc */, FABBC0B5165B90280080245F /* r_grid.h */, FABBC0B8165B90280080245F /* r_render.cc */, FABBC0B9165B90280080245F /* r_render.h */, ); name = r_; sourceTree = ""; }; FABBC13A165B90860080245F /* sys_ */ = { isa = PBXGroup; children = ( FABBC0BE165B90280080245F /* sys_debug.cc */, FABBC0BF165B90280080245F /* sys_debug.h */, FABBC0C0165B90280080245F /* sys_endian.h */, FABBC0C1165B90280080245F /* sys_macro.h */, FABBC0C2165B90280080245F /* sys_type.h */, ); name = sys_; sourceTree = ""; }; FABBC13B165B90900080245F /* ui_ */ = { isa = PBXGroup; children = ( 4F9C539C1A6CECFA001F4427 /* ui_default.cc */, 4F9C539D1A6CECFA001F4427 /* ui_default.h */, FA85EEE416936A3A00CA6FC2 /* ui_file.cc */, FA85EEE516936A3A00CA6FC2 /* ui_file.h */, FA85EEE616936A3A00CA6FC2 /* ui_prefs.cc */, FA85EEE716936A3A00CA6FC2 /* ui_prefs.h */, FA1E04EC16689A2900ED41DC /* ui_misc.cc */, FA1E04ED16689A2900ED41DC /* ui_misc.h */, FABBC0C3165B90280080245F /* ui_about.cc */, FABBC0C4165B90280080245F /* ui_about.h */, FABBC0C5165B90280080245F /* ui_browser.cc */, FABBC0C6165B90280080245F /* ui_browser.h */, FABBC0C7165B90280080245F /* ui_canvas.cc */, FABBC0C8165B90280080245F /* ui_canvas.h */, FABBC0C9165B90280080245F /* ui_dialog.cc */, FABBC0CB165B90280080245F /* ui_hyper.cc */, FABBC0CC165B90280080245F /* ui_hyper.h */, FABBC0CD165B90280080245F /* ui_infobar.cc */, FABBC0CE165B90280080245F /* ui_infobar.h */, FABBC0CF165B90280080245F /* ui_linedef.cc */, FABBC0D0165B90280080245F /* ui_linedef.h */, FABBC0D1165B90280080245F /* ui_menu.cc */, FABBC0D2165B90280080245F /* ui_menu.h */, FABBC0D3165B90280080245F /* ui_nodes.cc */, FABBC0D4165B90280080245F /* ui_nodes.h */, FABBC0D5165B90280080245F /* ui_nombre.cc */, FABBC0D6165B90280080245F /* ui_nombre.h */, FABBC0D7165B90280080245F /* ui_pic.cc */, FABBC0D8165B90280080245F /* ui_pic.h */, 4F9C539E1A6CECFA001F4427 /* ui_replace.cc */, 4F9C539F1A6CECFA001F4427 /* ui_replace.h */, FABBC0DB165B90280080245F /* ui_scroll.cc */, FABBC0DC165B90280080245F /* ui_scroll.h */, FABBC0DD165B90280080245F /* ui_sector.cc */, FABBC0DE165B90280080245F /* ui_sector.h */, FABBC0DF165B90280080245F /* ui_sidedef.cc */, FABBC0E0165B90280080245F /* ui_sidedef.h */, FABBC0E1165B90280080245F /* ui_thing.cc */, FABBC0E2165B90280080245F /* ui_thing.h */, FABBC0E3165B90280080245F /* ui_tile.cc */, FABBC0E4165B90280080245F /* ui_tile.h */, FABBC0E5165B90280080245F /* ui_vertex.cc */, FABBC0E6165B90280080245F /* ui_vertex.h */, FABBC0E7165B90280080245F /* ui_window.cc */, FABBC0E8165B90280080245F /* ui_window.h */, ); name = ui_; sourceTree = ""; }; FABBC13C165B90A60080245F /* w_ */ = { isa = PBXGroup; children = ( FABBC0E9165B90280080245F /* w_flats.cc */, FABBC0EA165B90280080245F /* w_flats.h */, FABBC0EB165B90280080245F /* w_loadpic.cc */, FABBC0EC165B90280080245F /* w_loadpic.h */, FABBC0ED165B90280080245F /* w_rawdef.h */, FABBC0EE165B90280080245F /* w_sprite.cc */, FABBC0EF165B90280080245F /* w_sprite.h */, FABBC0F0165B90280080245F /* w_texture.cc */, FABBC0F1165B90280080245F /* w_texture.h */, FABBC0F2165B90280080245F /* w_wad.cc */, FABBC0F3165B90280080245F /* w_wad.h */, ); name = w_; sourceTree = ""; }; FABBC13D165B90B60080245F /* x_ */ = { isa = PBXGroup; children = ( FABBC0F4165B90280080245F /* x_hover.cc */, FABBC0F5165B90280080245F /* x_hover.h */, FABBC0F6165B90280080245F /* x_loop.cc */, FABBC0F7165B90280080245F /* x_loop.h */, FABBC0F8165B90280080245F /* x_mirror.cc */, FABBC0F9165B90280080245F /* x_mirror.h */, ); name = x_; sourceTree = ""; }; FABBC23F165B990C0080245F /* glbsp_src */ = { isa = PBXGroup; children = ( FABBC240165B990C0080245F /* analyze.cc */, FABBC241165B990C0080245F /* analyze.h */, FABBC242165B990C0080245F /* blockmap.cc */, FABBC243165B990C0080245F /* blockmap.h */, FABBC244165B990C0080245F /* glbsp.cc */, FABBC245165B990C0080245F /* glbsp.h */, FABBC246165B990C0080245F /* level.cc */, FABBC247165B990C0080245F /* level.h */, FABBC248165B990C0080245F /* node.cc */, FABBC249165B990C0080245F /* node.h */, FABBC24A165B990C0080245F /* reject.cc */, FABBC24B165B990C0080245F /* reject.h */, FABBC24C165B990C0080245F /* seg.cc */, FABBC24D165B990C0080245F /* seg.h */, FABBC24E165B990C0080245F /* structs.h */, FABBC24F165B990C0080245F /* system.cc */, FABBC250165B990C0080245F /* system.h */, FABBC251165B990C0080245F /* util.cc */, FABBC252165B990C0080245F /* util.h */, FABBC253165B990C0080245F /* wad.cc */, FABBC254165B990C0080245F /* wad.h */, ); name = glbsp_src; path = ../../glbsp_src; sourceTree = ""; }; FAF8A0DF165BE342009B4C14 /* OSXPort */ = { isa = PBXGroup; children = ( FA5E2C3E165B8F860024D6A5 /* AppDelegate.h */, FADB99F216B017D600A28204 /* AppDelegate.mm */, 4F2D365217C96A7E003BEEE9 /* OSXCalls.mm */, 4F2D365317C96A7E003BEEE9 /* OSXCalls.h */, ); name = OSXPort; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ FA5E2C27165B8F860024D6A5 /* Eureka Doom Editor */ = { isa = PBXNativeTarget; buildConfigurationList = FA5E2C5A165B8F870024D6A5 /* Build configuration list for PBXNativeTarget "Eureka Doom Editor" */; buildPhases = ( FA5E2C24165B8F860024D6A5 /* Sources */, FA5E2C25165B8F860024D6A5 /* Frameworks */, FA5E2C26165B8F860024D6A5 /* Resources */, FAF8A110165C0001009B4C14 /* CopyFiles */, FA177ABD165FD56200B797F3 /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = "Eureka Doom Editor"; productName = EurekaApp; productReference = FA5E2C28165B8F860024D6A5 /* Eureka Doom Editor.app */; productType = "com.apple.product-type.application"; }; FA5E2C48165B8F870024D6A5 /* Eureka Doom EditorTests */ = { isa = PBXNativeTarget; buildConfigurationList = FA5E2C5D165B8F870024D6A5 /* Build configuration list for PBXNativeTarget "Eureka Doom EditorTests" */; buildPhases = ( FA5E2C44165B8F870024D6A5 /* Sources */, FA5E2C45165B8F870024D6A5 /* Frameworks */, FA5E2C46165B8F870024D6A5 /* Resources */, FA5E2C47165B8F870024D6A5 /* ShellScript */, ); buildRules = ( ); dependencies = ( FA5E2C4E165B8F870024D6A5 /* PBXTargetDependency */, ); name = "Eureka Doom EditorTests"; productName = EurekaAppTests; productReference = FA5E2C49165B8F870024D6A5 /* Eureka Doom EditorTests.octest */; productType = "com.apple.product-type.bundle.ocunit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ FA5E2C1F165B8F860024D6A5 /* Project object */ = { isa = PBXProject; attributes = { LastTestingUpgradeCheck = 0640; LastUpgradeCheck = 0640; ORGANIZATIONNAME = ioan; TargetAttributes = { FA5E2C27165B8F860024D6A5 = { DevelopmentTeam = 66L236F264; }; }; }; buildConfigurationList = FA5E2C22165B8F860024D6A5 /* Build configuration list for PBXProject "Eureka Doom Editor" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = FA5E2C1D165B8F860024D6A5; productRefGroup = FA5E2C29165B8F860024D6A5 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( FA5E2C27165B8F860024D6A5 /* Eureka Doom Editor */, FA5E2C48165B8F870024D6A5 /* Eureka Doom EditorTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ FA5E2C26165B8F860024D6A5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( FA5E2C37165B8F860024D6A5 /* InfoPlist.strings in Resources */, FA5E2C3D165B8F860024D6A5 /* Credits.rtf in Resources */, FA5E2C43165B8F860024D6A5 /* MainMenu.xib in Resources */, FA8DBD73165D435600FCFB1A /* Eureka Doom EditorIcon.icns in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; FA5E2C46165B8F870024D6A5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ FA5E2C47165B8F870024D6A5 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ FA5E2C24165B8F860024D6A5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( FABBC0FA165B90280080245F /* e_basis.cc in Sources */, FABBC0FB165B90280080245F /* e_checks.cc in Sources */, FABBC0FC165B90280080245F /* e_cutpaste.cc in Sources */, FABBC0FD165B90280080245F /* e_linedef.cc in Sources */, FABBC0FE165B90280080245F /* e_loadsave.cc in Sources */, FABBC0FF165B90280080245F /* e_nodes.cc in Sources */, FABBC100165B90280080245F /* e_path.cc in Sources */, FABBC101165B90280080245F /* e_sector.cc in Sources */, FABBC102165B90280080245F /* e_things.cc in Sources */, FABBC103165B90280080245F /* e_vertex.cc in Sources */, FABBC104165B90280080245F /* editloop.cc in Sources */, FABBC105165B90280080245F /* im_color.cc in Sources */, FABBC106165B90280080245F /* im_img.cc in Sources */, FABBC107165B90280080245F /* levels.cc in Sources */, FABBC108165B90280080245F /* lib_adler.cc in Sources */, FABBC109165B90280080245F /* lib_file.cc in Sources */, FABBC10A165B90280080245F /* lib_util.cc in Sources */, FABBC10B165B90280080245F /* m_bitvec.cc in Sources */, FABBC10C165B90280080245F /* m_config.cc in Sources */, FABBC10E165B90280080245F /* m_game.cc in Sources */, FABBC10F165B90280080245F /* m_select.cc in Sources */, FABBC110165B90280080245F /* m_strings.cc in Sources */, FABBC112165B90280080245F /* objects.cc in Sources */, FABBC113165B90280080245F /* r_grid.cc in Sources */, FABBC115165B90280080245F /* r_render.cc in Sources */, FABBC118165B90280080245F /* sys_debug.cc in Sources */, FABBC119165B90280080245F /* ui_about.cc in Sources */, FABBC11A165B90280080245F /* ui_browser.cc in Sources */, FABBC11B165B90280080245F /* ui_canvas.cc in Sources */, FABBC11C165B90280080245F /* ui_dialog.cc in Sources */, FABBC11D165B90280080245F /* ui_hyper.cc in Sources */, FABBC11E165B90280080245F /* ui_infobar.cc in Sources */, FABBC11F165B90280080245F /* ui_linedef.cc in Sources */, FABBC120165B90280080245F /* ui_menu.cc in Sources */, FABBC121165B90280080245F /* ui_nodes.cc in Sources */, FABBC122165B90280080245F /* ui_nombre.cc in Sources */, FABBC123165B90280080245F /* ui_pic.cc in Sources */, FABBC125165B90280080245F /* ui_scroll.cc in Sources */, FABBC126165B90280080245F /* ui_sector.cc in Sources */, FABBC127165B90280080245F /* ui_sidedef.cc in Sources */, FABBC128165B90280080245F /* ui_thing.cc in Sources */, FABBC129165B90280080245F /* ui_tile.cc in Sources */, FABBC12A165B90280080245F /* ui_vertex.cc in Sources */, FABBC12B165B90280080245F /* ui_window.cc in Sources */, FABBC12C165B90280080245F /* w_flats.cc in Sources */, FABBC12D165B90280080245F /* w_loadpic.cc in Sources */, 4F9C53A11A6CECFA001F4427 /* ui_replace.cc in Sources */, FABBC12E165B90280080245F /* w_sprite.cc in Sources */, FABBC12F165B90280080245F /* w_texture.cc in Sources */, FABBC130165B90280080245F /* w_wad.cc in Sources */, FABBC131165B90280080245F /* x_hover.cc in Sources */, FABBC132165B90280080245F /* x_loop.cc in Sources */, FABBC133165B90280080245F /* x_mirror.cc in Sources */, FABBC255165B990C0080245F /* analyze.cc in Sources */, FABBC256165B990C0080245F /* blockmap.cc in Sources */, FABBC257165B990C0080245F /* glbsp.cc in Sources */, FABBC258165B990C0080245F /* level.cc in Sources */, FABBC259165B990C0080245F /* node.cc in Sources */, FABBC25A165B990C0080245F /* reject.cc in Sources */, FABBC25B165B990C0080245F /* seg.cc in Sources */, FABBC25C165B990C0080245F /* system.cc in Sources */, FABBC25D165B990C0080245F /* util.cc in Sources */, 4F9C53A01A6CECFA001F4427 /* ui_default.cc in Sources */, FABBC25E165B990C0080245F /* wad.cc in Sources */, FA8DBCFC165D293600FCFB1A /* main.cc in Sources */, FA6ADC22165E75D400FB10D1 /* im_arrows.cc in Sources */, FA1E04EE16689A2900ED41DC /* ui_misc.cc in Sources */, FA85EEE816936A3A00CA6FC2 /* m_files.cc in Sources */, FA85EEE916936A3A00CA6FC2 /* ui_file.cc in Sources */, FA85EEEA16936A3A00CA6FC2 /* ui_prefs.cc in Sources */, FA4433D116AD9CB800525112 /* m_keys.cc in Sources */, FADB99F316B017D600A28204 /* AppDelegate.mm in Sources */, 4FBD72EC179FBF9300937B50 /* e_checks2.cc in Sources */, 4F2D365417C96A7E003BEEE9 /* OSXCalls.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; FA5E2C44165B8F870024D6A5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ FA5E2C4E165B8F870024D6A5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = FA5E2C27165B8F860024D6A5 /* Eureka Doom Editor */; targetProxy = FA5E2C4D165B8F870024D6A5 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ FA5E2C35165B8F860024D6A5 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( FA5E2C36165B8F860024D6A5 /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; FA5E2C3B165B8F860024D6A5 /* Credits.rtf */ = { isa = PBXVariantGroup; children = ( FA5E2C3C165B8F860024D6A5 /* en */, ); name = Credits.rtf; sourceTree = ""; }; FA5E2C41165B8F860024D6A5 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( FA5E2C42165B8F860024D6A5 /* en */, ); name = MainMenu.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ FA5E2C58165B8F870024D6A5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libstdc++"; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = /Library/Frameworks; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_STRICT_ALIASING = NO; GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = /opt/local/include; LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; LLVM_LTO = NO; MACOSX_DEPLOYMENT_TARGET = 10.5; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; name = Debug; }; FA5E2C59165B8F870024D6A5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libstdc++"; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = /Library/Frameworks; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_STRICT_ALIASING = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = /opt/local/include; LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.5; SDKROOT = macosx; }; name = Release; }; FA5E2C5B165B8F870024D6A5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "Developer ID Application"; COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "EurekaApp/Eureka Doom Editor-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", "main=main_ORIGINAL", _THREAD_SAFE, _REENTRANT, "INLINE_G=inline", ); INFOPLIST_FILE = "EurekaApp/Eureka Doom Editor-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)/staticlib\"", "$(PROJECT_DIR)/staticlib", ); PRODUCT_NAME = "Eureka Doom Editor"; WRAPPER_EXTENSION = app; }; name = Debug; }; FA5E2C5C165B8F870024D6A5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "Developer ID Application"; COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "EurekaApp/Eureka Doom Editor-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "main=main_ORIGINAL", _THREAD_SAFE, _REENTRANT, "INLINE_G=inline", ); INFOPLIST_FILE = "EurekaApp/Eureka Doom Editor-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)/staticlib\"", "$(PROJECT_DIR)/staticlib", ); PRODUCT_NAME = "Eureka Doom Editor"; WRAPPER_EXTENSION = app; }; name = Release; }; FA5E2C5E165B8F870024D6A5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/EurekaApp.app/Contents/MacOS/EurekaApp"; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\""; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "EurekaApp/EurekaApp-Prefix.pch"; INFOPLIST_FILE = "EurekaAppTests/Eureka Doom EditorTests-Info.plist"; PRODUCT_NAME = "Eureka Doom EditorTests"; TEST_HOST = "$(BUNDLE_LOADER)"; WRAPPER_EXTENSION = octest; }; name = Debug; }; FA5E2C5F165B8F870024D6A5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/EurekaApp.app/Contents/MacOS/EurekaApp"; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\""; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "EurekaApp/EurekaApp-Prefix.pch"; INFOPLIST_FILE = "EurekaAppTests/Eureka Doom EditorTests-Info.plist"; PRODUCT_NAME = "Eureka Doom EditorTests"; TEST_HOST = "$(BUNDLE_LOADER)"; WRAPPER_EXTENSION = octest; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ FA5E2C22165B8F860024D6A5 /* Build configuration list for PBXProject "Eureka Doom Editor" */ = { isa = XCConfigurationList; buildConfigurations = ( FA5E2C58165B8F870024D6A5 /* Debug */, FA5E2C59165B8F870024D6A5 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; FA5E2C5A165B8F870024D6A5 /* Build configuration list for PBXNativeTarget "Eureka Doom Editor" */ = { isa = XCConfigurationList; buildConfigurations = ( FA5E2C5B165B8F870024D6A5 /* Debug */, FA5E2C5C165B8F870024D6A5 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; FA5E2C5D165B8F870024D6A5 /* Build configuration list for PBXNativeTarget "Eureka Doom EditorTests" */ = { isa = XCConfigurationList; buildConfigurations = ( FA5E2C5E165B8F870024D6A5 /* Debug */, FA5E2C5F165B8F870024D6A5 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = FA5E2C1F165B8F860024D6A5 /* Project object */; } eureka-1.11-source/osx/Eureka Doom Editor.xcodeproj/project.xcworkspace/0000755000175100017510000000000012647061302025574 5ustar aaptedaaptedeureka-1.11-source/osx/Eureka Doom Editor.xcodeproj/project.xcworkspace/xcuserdata/0000755000175100017510000000000012647061302027737 5ustar aaptedaaptedeureka-1.11-source/osx/Eureka Doom Editor.xcodeproj/project.xcworkspace/xcuserdata/ioan.xcuserdatad/0000755000175100017510000000000012647061302033173 5ustar aaptedaapted././@LongLink0000644000000000000000000000020100000000000011574 Lustar rootrooteureka-1.11-source/osx/Eureka Doom Editor.xcodeproj/project.xcworkspace/xcuserdata/ioan.xcuserdatad/WorkspaceSettings.xcsettingseureka-1.11-source/osx/Eureka Doom Editor.xcodeproj/project.xcworkspace/xcuserdata/ioan.xcuserdatad/0000644000175100017510000000051512647061302033176 0ustar aaptedaapted HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges SnapshotAutomaticallyBeforeSignificantChanges eureka-1.11-source/osx/Eureka Doom Editor.xcodeproj/project.xcworkspace/contents.xcworkspacedata0000644000175100017510000000024312647061302032535 0ustar aaptedaapted eureka-1.11-source/osx/staticlib/0000755000175100017510000000000012647061302016256 5ustar aaptedaaptedeureka-1.11-source/osx/staticlib/libfltk_forms.a0000644000175100017510000007706012647061302021267 0ustar aaptedaapted! #1/20 1415124514 0 0 100644 2820 ` __.SYMDEF$H aH H H H 1H /H QH kH H H H H H H H FH H LH H CH H H H X,X,X,WX,rX,[X,zX,X,X,X,X,=X,;;;;;I;Z;k;|;;;;;;<@M@M@M%@McXUXUDXUXU^XU XUXUXUXUyXU%XUXUqeeeeeeeeeee2ee#ee&e>eXeH__Z11fl_do_formsv__Z11fl_end_formv__Z12fl_show_formP9Fl_WindowiiPKc__Z13fl_add_buttonhiiiiPKc__Z13fl_initializePiPPcPKcPvi__Z13fl_show_alertPKcS0_S0_i__Z14fl_check_formsv__Z14fl_show_choicePKcS0_S0_iS0_S0_S0___Z15fl_show_messagePKcS0_S0___Z16fl_show_questionPKcS0_S0___Z20fl_set_graphics_modeii__Z20fl_show_simple_inputPKcS0___ZN12Fl_FormsText4drawEv__ZN12Fl_FormsTextD0Ev__ZN12Fl_FormsTextD1Ev__ZN8Fl_Group9forms_endEv__ZN9Fl_Widget12as_gl_windowEv__ZN9Fl_Widget8as_groupEv__ZN9Fl_Widget9as_windowEv__ZTI12Fl_FormsText__ZTS12Fl_FormsText__ZTV12Fl_FormsText_fl_flip_fl_modal_next__ZN14Fl_FormsBitmap3setEiiPKh__ZN14Fl_FormsBitmap4drawEv__ZN14Fl_FormsBitmapC1E10Fl_BoxtypeiiiiPKc__ZN14Fl_FormsBitmapC2E10Fl_BoxtypeiiiiPKc__ZN14Fl_FormsBitmapD0Ev__ZN14Fl_FormsBitmapD1Ev__ZN9Fl_Widget12as_gl_windowEv__ZN9Fl_Widget8as_groupEv__ZN9Fl_Widget9as_windowEv__ZTI14Fl_FormsBitmap__ZTS14Fl_FormsBitmap__ZTV14Fl_FormsBitmap__ZN7Fl_Free4drawEv__ZN7Fl_Free4stepEPv__ZN7Fl_Free6handleEi__ZN7Fl_FreeC1EhiiiiPKcPFiP9Fl_WidgetiffcE__ZN7Fl_FreeC2EhiiiiPKcPFiP9Fl_WidgetiffcE__ZN7Fl_FreeD0Ev__ZN7Fl_FreeD1Ev__ZN7Fl_FreeD2Ev__ZN9Fl_Widget12as_gl_windowEv__ZN9Fl_Widget8as_groupEv__ZN9Fl_Widget9as_windowEv__ZTI7Fl_Free__ZTS7Fl_Free__ZTV7Fl_Free__Z14fl_get_patternv__Z15fl_get_filenamev__Z16fl_get_directoryv__Z21fl_show_file_selectorPKcS0_S0_S0___ZN14Fl_FormsPixmap3setEPKPc__ZN14Fl_FormsPixmap4drawEv__ZN14Fl_FormsPixmapC1E10Fl_BoxtypeiiiiPKc__ZN14Fl_FormsPixmapC2E10Fl_BoxtypeiiiiPKc__ZN14Fl_FormsPixmapD0Ev__ZN14Fl_FormsPixmapD1Ev__ZN9Fl_Widget12as_gl_windowEv__ZN9Fl_Widget8as_groupEv__ZN9Fl_Widget9as_windowEv__ZTI14Fl_FormsPixmap__ZTS14Fl_FormsPixmap__ZTV14Fl_FormsPixmap__Z10fl_gettimePlS___ZN8Fl_Timer4drawEv__ZN8Fl_Timer4stepEv__ZN8Fl_Timer5valueEd__ZN8Fl_Timer6handleEi__ZN8Fl_Timer6stepcbEPv__ZN8Fl_Timer9suspendedEc__ZN8Fl_TimerC1EhiiiiPKc__ZN8Fl_TimerC2EhiiiiPKc__ZN8Fl_TimerD0Ev__ZN8Fl_TimerD1Ev__ZN8Fl_TimerD2Ev__ZN9Fl_Widget12as_gl_windowEv__ZN9Fl_Widget8as_groupEv__ZN9Fl_Widget9as_windowEv__ZTI8Fl_Timer__ZTS8Fl_Timer__ZTV8Fl_Timer#1/28 1415124499 502 80 100644 8404 ` forms_compatability.o hy h  __text__TEXTX9__textcoal_nt__TEXT>   __data__DATAF6 __bss__DATAh __common__DATAx __cstring__TEXTG7 __const__DATA`xP 8__const__TEXT __compact_unwind__LD` __eh_frame__TEXTH 8  h@W P+3$UH HHu]ÐUHAVSIAA~(LH0DV DN$~(DD^,EEAt=D)HHQ q$D9DND9DNQ(9Mq,D9DMHuEV EN$D)A~(E)E^,=t>A~lLwLX,LAtHH+r$+r,ɉr$uL[A^]UHAWAVATSHIHHHHHAHE1Ƀ;y HHIH; |MEAL}HcȍAEI K Iċ;9}LLEuIcI=uH[A\A^A_]UHAWAVSHAAHHEuK`=uAu Ka@At 1HHAtaH}HuDEDMH}HuHUHME܋UԋK()ʉƋE؋}DC,D)ljHHP A@tHAtKD{ EyAAD+{(D{ S$xDC,DC,D)S$HK(HDP Auc`Et A@tHuH5tHH HHP(H[A^A_]UHHuu1]UH]UH]ÐUHSPHKTHH[]UHAWAVAUATSHLMDEAAAt0CwKILDDDDELMIILDDDDELMOILDDDDELMe ȃw H 5HcHAFl fuA^lLH[A\A]A^A_]AFoUHIMH LDHHDHHEH=1HL]UHIMH LDHHDHHEH=1HL]UHHIIMHLDMLDHHEH$H=H5H11H]UHHIHEMH LDHHDHHEH$H=1HLH]UHSPHHH=1HHHDH[]UH]UHSPHHH[]UH1]UH1]UH1]%s %s %sNoYes%s12Fl_FormsText ! ar  X88@RK+ .6>zRx $AC $DAC C,l^AC K$ AC I$b AC $ZAC $AAC $< AC B,dAC M$8AC $8AC $RAC $ :KAC $4]+AC B$\` AC $BAC B$6AC $AC $AC 5-6-6-xqT<4-.3-fC-JU-C7-'U-8-U-N-P-@->-V-=-w@-TNJ-F;:-;-I-s9-V?-CL-/2m2m K-1m1m<-kTMT-/A-M-O-1mGM-B-&-B-"S-H-H-pQh/`RX(P,H*@D8E0G(F "$.@ `@ `@ h p PGQTX H r  u `  V  @  0  P t n@ ( " X  x >9 -> $ +  > @ L.X f6u  '`\Fx ,]Q9~tEseXe;D__Z11fl_end_formv__ZN8Fl_Group7currentEv__ZN8Fl_Group9forms_endEv__ZNK8Fl_Group5arrayEv_fl_flip__ZNK9Fl_Widget6windowEv__ZN8Fl_Group3endEv__Z13fl_initializePiPPcPKcPvi__Znam__ZN2Fl3argEiPPcRi__Z12fl_show_formP9Fl_WindowiiPKc__ZN9Fl_Window5labelEPKc_fl_modal_next__ZN9Fl_Window7hotspotEPK9Fl_Widgeti__ZN2Fl9get_mouseERiS0___ZN2Fl11screen_xywhERiS0_S0_S0_ii__ZN9Fl_Window10fullscreenEv__ZN2Fl1wEv__ZN2Fl1hEv__ZN9Fl_Window4showEiPPc__Z11fl_do_formsv__ZN2Fl9readqueueEv__ZN2Fl4waitEv_exit__Z14fl_check_formsv__ZN2Fl5checkEv__Z20fl_set_graphics_modeii__ZN12Fl_FormsText4drawEv__ZNK9Fl_Widget8draw_boxEv__ZNK9Fl_Widget10draw_labelEv__Z13fl_add_buttonhiiiiPKc__Znwm__ZN16Fl_Return_ButtonC1EiiiiPKc__ZN16Fl_Repeat_ButtonC1EiiiiPKc__ZN9Fl_ButtonC1EiiiiPKc__Z15fl_show_messagePKcS0_S0___Z10fl_messagePKcz__Z13fl_show_alertPKcS0_S0_i__Z8fl_alertPKcz__Z16fl_show_questionPKcS0_S0___Z9fl_choicePKcS0_S0_S0_z__Z14fl_show_choicePKcS0_S0_iS0_S0_S0___Z20fl_show_simple_inputPKcS0___Z8fl_inputPKcS0_z__ZN12Fl_FormsTextD1Ev__ZN9Fl_WidgetD2Ev__ZN12Fl_FormsTextD0Ev__ZdlPv__ZN9Fl_Widget8as_groupEv__ZN9Fl_Widget9as_windowEv__ZN9Fl_Widget12as_gl_windowEv__ZTV12Fl_FormsText__ZTI12Fl_FormsText__ZN9Fl_Widget6handleEi__ZN9Fl_Widget6resizeEiiii__ZN9Fl_Widget4showEv__ZN9Fl_Widget4hideEv__ZTS12Fl_FormsText__ZTVN10__cxxabiv120__si_class_type_infoE__ZTI9Fl_Widget__Z11fl_end_formv.eh__ZN8Fl_Group9forms_endEv.eh__Z13fl_initializePiPPcPKcPvi.eh__Z12fl_show_formP9Fl_WindowiiPKc.eh__Z11fl_do_formsv.eh__Z14fl_check_formsv.eh__Z20fl_set_graphics_modeii.eh__ZN12Fl_FormsText4drawEv.eh__Z13fl_add_buttonhiiiiPKc.eh__Z15fl_show_messagePKcS0_S0_.eh__Z13fl_show_alertPKcS0_S0_i.eh__Z16fl_show_questionPKcS0_S0_.eh__Z14fl_show_choicePKcS0_S0_iS0_S0_S0_.eh__Z20fl_show_simple_inputPKcS0_.eh__ZN12Fl_FormsTextD1Ev.eh__ZN12Fl_FormsTextD0Ev.eh__ZN9Fl_Widget8as_groupEv.eh__ZN9Fl_Widget9as_windowEv.eh__ZN9Fl_Widget12as_gl_windowEv.eh__ZL8initargc__ZL8initargvL_.str1L_.strL_.str2L_.str3L_.str4EH_frame0 #1/20 1415124499 502 80 100644 3828 ` forms_bitmap.o (__text__TEXT} __textcoal_nt__TEXT~>. __const__DATAxp__const__TEXT@__compact_unwind__LDX  __eh_frame__TEXTx( h$  PUHAVSAHHE։DEIHHDsnHCxCd8CT[A^]UHAVSAHHE։DEIHHDsnHCxCd8CT[A^]UHAWAVATSIAAHH{xHtHP@D`Dx @@H HHHH(Lp(@0H@8HH @HCx[A\A^A_]ÐUHSPHsnShH{xt7sdHH8HH{xHs S$K(DC,$E1P8HH[]UH]UHSPHHH[]UH1]UH1]UH1]14Fl_FormsBitmapL!LL! a~ zRx $hLAC C$DLAC C,lAC G$aAC B$> AC $ AC B$AC $<AC $dAC y->#=--="-rk-&-"!---ph` X PH@80(   `@ x[L]P`1~48~l G@E1,J]v__ZN14Fl_FormsBitmapC1E10Fl_BoxtypeiiiiPKc__ZN9Fl_WidgetC2EiiiiPKc__ZTV14Fl_FormsBitmap__ZN14Fl_FormsBitmapC2E10Fl_BoxtypeiiiiPKc__ZN14Fl_FormsBitmap3setEiiPKh__Znwm__ZTV9Fl_Bitmap__ZN14Fl_FormsBitmap4drawEv__ZNK9Fl_Widget8draw_boxE10Fl_Boxtypej_fl_graphics_driver__ZNK9Fl_Widget10draw_labelEv__ZN14Fl_FormsBitmapD1Ev__ZN9Fl_WidgetD2Ev__ZN14Fl_FormsBitmapD0Ev__ZdlPv__ZN9Fl_Widget8as_groupEv__ZN9Fl_Widget9as_windowEv__ZN9Fl_Widget12as_gl_windowEv__ZTI14Fl_FormsBitmap__ZN9Fl_Widget6handleEi__ZN9Fl_Widget6resizeEiiii__ZN9Fl_Widget4showEv__ZN9Fl_Widget4hideEv__ZTS14Fl_FormsBitmap__ZTVN10__cxxabiv120__si_class_type_infoE__ZTI9Fl_Widget__ZN14Fl_FormsBitmapC1E10Fl_BoxtypeiiiiPKc.eh__ZN14Fl_FormsBitmapC2E10Fl_BoxtypeiiiiPKc.eh__ZN14Fl_FormsBitmap3setEiiPKh.eh__ZN14Fl_FormsBitmap4drawEv.eh__ZN14Fl_FormsBitmapD1Ev.eh__ZN14Fl_FormsBitmapD0Ev.eh__ZN9Fl_Widget8as_groupEv.eh__ZN9Fl_Widget9as_windowEv.eh__ZN9Fl_Widget12as_gl_windowEv.ehEH_frame0 #1/20 1415124498 502 80 100644 4476 ` forms_free.o xXX__text__TEXTtX __literal8__TEXTxx__textcoal_nt__TEXT __const__DATAx( __const__TEXT __compact_unwind__LD(`( __eh_frame__TEXT h )  PUHAWAVSPHL5E>AeHPE>H=?HH[A^A_]UH]UHAWAVSPAHL}HE։DEIHHDslL{xD<s!H=HH[A^A_]AuK`H[A^A_]ÐUHSPHHHH=HfWW1HSxHHH[]UHSPHHHH=HfWW1HSxHH[]UHSPHHHH=HfWW1HSxHH[]UHHGxdWW1]UHAVSHHN wE1HaHc H)H *H * HSxAtHSHHD[A^]ÊKltt{Gz?{Gz?UH1]UH1]UH1]7Fl_FreeKaL V{aKCbC!zRx $XKAC F$D| AC $l^{AC F$KAC B$CAC B$CAC B$ AC $4AC C$\AC $AC $`AC ) -===%--xn]%-<-4*(- %---|$-R -G-5=p&h`'XPH@!8"0#(   @ `@ 5NIeHLsV&@$b:h0~V(q~_@*d __ZN7Fl_Free4stepEPv__ZN2Fl8e_numberE__ZN2Fl11add_timeoutEdPFvPvES0___ZN7Fl_FreeC1EhiiiiPKcPFiP9Fl_WidgetiffcE__ZN7Fl_FreeC2EhiiiiPKcPFiP9Fl_WidgetiffcE__ZN9Fl_WidgetC2EiiiiPKc__ZTV7Fl_Free__ZN7Fl_FreeD0Ev__ZN2Fl14remove_timeoutEPFvPvES0___ZN9Fl_WidgetD2Ev__ZdlPv__ZN7Fl_FreeD1Ev__ZN7Fl_FreeD2Ev__ZN7Fl_Free4drawEv__ZN7Fl_Free6handleEi__ZN2Fl8e_keysymE__ZN2Fl3e_xE__ZN2Fl3e_yE__ZN9Fl_Widget11do_callbackEPS_Pv__ZN9Fl_Widget8as_groupEv__ZN9Fl_Widget9as_windowEv__ZN9Fl_Widget12as_gl_windowEv__ZTI7Fl_Free__ZN9Fl_Widget6resizeEiiii__ZN9Fl_Widget4showEv__ZN9Fl_Widget4hideEv__ZTS7Fl_Free__ZTVN10__cxxabiv120__si_class_type_infoE__ZTI9Fl_Widget__ZN7Fl_Free4stepEPv.eh__ZN7Fl_FreeC1EhiiiiPKcPFiP9Fl_WidgetiffcE.eh__ZN7Fl_FreeC2EhiiiiPKcPFiP9Fl_WidgetiffcE.eh__ZN7Fl_FreeD0Ev.eh__ZN7Fl_FreeD1Ev.eh__ZN7Fl_FreeD2Ev.eh__ZN7Fl_Free4drawEv.eh__ZN7Fl_Free6handleEi.eh__ZN9Fl_Widget8as_groupEv.eh__ZN9Fl_Widget9as_windowEv.eh__ZN9Fl_Widget12as_gl_windowEv.ehEH_frame0#1/20 1415124499 502 80 100644 2012 ` forms_fselect.o __text__TEXTD__bss__DATA__compact_unwind__LDHX@__eh_frame__TEXT h``h P UHAWAVSPIHIHt>tH=Ht ;tHMtA?tH=LHHH<H~|/t H|/HH)L=H5H511LLIMtNHHLHHH=HHHKH9HFLHH[A^A_]UHH]UHH]UHH]a * 7 zRx $AC F$D AC $l AC $ AC >1$- -- --i-aZ-M;*- `@ (; L ^*07Xq9X(1__Z21fl_show_file_selectorPKcS0_S0_S0__strlcpy_strlen__Z15fl_file_chooserPKcS0_S0_i__Z16fl_filename_namePKc__Z16fl_get_directoryv__Z14fl_get_patternv__Z15fl_get_filenamev__Z21fl_show_file_selectorPKcS0_S0_S0_.eh__Z16fl_get_directoryv.eh__Z14fl_get_patternv.eh__Z15fl_get_filenamev.eh__ZL12fl_directory__ZL10fl_pattern__ZL11fl_filenameEH_frame0#1/20 1415124499 502 80 100644 3948 ` forms_pixmap.o (__text__TEXT __textcoal_nt__TEXT>H  __const__DATAx8__const__TEXT`__compact_unwind__LDx ( __eh_frame__TEXTH h&P  PUHAVSAHHE։DEIHHDsnHCxCd8CT[A^]UHAVSAHHE։DEIHHDsnHCxCd8CT[A^]UHAWAVSPIIIxHtHP@HCC CCCHC HHHC(HC8HC0HLHI_xH[A^A_]UHSPHsnShH{xt7sdHH8HH{xHs S$K(DC,$E1P8HH[]UH]UHSPHHH[]UH1]UH1]UH1]14Fl_FormsPixmapL!LL!a6a zRx $HLAC C$DlLAC C$lAC F$aAC B$@ AC $"AC B$ AC $4AC $\AC -X%=G-#--!=$-rk-&-"#---p h`"X PH@80(   `@ )6J([LxgiP@}`EgQ6,I5__ZN14Fl_FormsPixmapC1E10Fl_BoxtypeiiiiPKc__ZN9Fl_WidgetC2EiiiiPKc__ZTV14Fl_FormsPixmap__ZN14Fl_FormsPixmapC2E10Fl_BoxtypeiiiiPKc__ZN14Fl_FormsPixmap3setEPKPc__Znwm__ZTV9Fl_Pixmap__ZN9Fl_Pixmap8set_dataEPKPKc__ZN9Fl_Pixmap7measureEv__ZN14Fl_FormsPixmap4drawEv__ZNK9Fl_Widget8draw_boxE10Fl_Boxtypej_fl_graphics_driver__ZNK9Fl_Widget10draw_labelEv__ZN14Fl_FormsPixmapD1Ev__ZN9Fl_WidgetD2Ev__ZN14Fl_FormsPixmapD0Ev__ZdlPv__ZN9Fl_Widget8as_groupEv__ZN9Fl_Widget9as_windowEv__ZN9Fl_Widget12as_gl_windowEv__ZTI14Fl_FormsPixmap__ZN9Fl_Widget6handleEi__ZN9Fl_Widget6resizeEiiii__ZN9Fl_Widget4showEv__ZN9Fl_Widget4hideEv__ZTS14Fl_FormsPixmap__ZTVN10__cxxabiv120__si_class_type_infoE__ZTI9Fl_Widget__ZN14Fl_FormsPixmapC1E10Fl_BoxtypeiiiiPKc.eh__ZN14Fl_FormsPixmapC2E10Fl_BoxtypeiiiiPKc.eh__ZN14Fl_FormsPixmap3setEPKPc.eh__ZN14Fl_FormsPixmap4drawEv.eh__ZN14Fl_FormsPixmapD1Ev.eh__ZN14Fl_FormsPixmapD0Ev.eh__ZN9Fl_Widget8as_groupEv.eh__ZN9Fl_Widget9as_windowEv.eh__ZN9Fl_Widget12as_gl_windowEv.ehEH_frame0#1/20 1415124499 502 80 100644 6388 ` forms_timer.o0 X PX __text__TEXTP 8__literal8__TEXT8h__textcoal_nt__TEXTP __cstring__TEXTh__const__DATAxh__const__TEXT H __compact_unwind__LDX __eh_frame__TEXTp8  hP8  P!$UHAVSH IHH}HuHEHHcEIH [A^]ÐUHAWAVSH8HL5IHE{xt%Wf.w^, HCdsnH{luHWf.v7{yt\( [f.v!H5H}BH4X^,W*Y\H5H}sHSLL=I?HsPI?Hs S$K(DC,D$H$H}E1IH;Eu H8[A^A_]HChUH]UHSH(H{xEH}HuHEHcMHH+HH+WMf.WH*H*^%X\HHvf.s2{luHH=HH([]H([]À{luCxHǃHH=HK`HSHHH([]UHuWf.rW1]UHSHHWf.CxH}HuHEHHcEH{ltHH=H{xtH=HH[]H[]ÐUHSPHHHH=HHHH[]UHSPHHHH=HHH[]UHSPHHHH=HHH[]UH]UHAVSAHHE։DEIAHHCnChXHǃCxCyDslu CT AuK`[A^]ÐUHSHH@CxttvCxH=HH[]uYWf.CxH}HuHEHHcEH{xtH=JHH[]H[]?N@?.A???UH1]UH1]UH1]%.1f%d:%04.1f8Fl_Timer5!6^a "n800 m!~PX`zRx $5AC G$D^AC I$l< AC $AC E$"AC $ AC E$ v8AC B$40AC B$\0AC B$ AC $xmAC C$AC E$hAC $$HAC $L(AC %- 6-&- :#/,- ---&- #--&- #2---&- z#b%-TL ?&-7 0*- 6- -'-%- *-`%-RJ C*-6--3-n$-*5=7-.-7-/-oI4=6-p0h"`1XPH@(8)0+(  !`@ `@ hml#6(x|eP_~x @h -\ n +@ `0 yP X ##C  F{K\28r__Z10fl_gettimePlS__gettimeofday__ZN8Fl_Timer4drawEv___stack_chk_guard__ZNK9Fl_Widget8draw_boxE10Fl_Boxtypej_sprintf__ZNK9Fl_Widget10draw_labelEv_fl_graphics_driver__Z7fl_drawPKciiiijP8Fl_Imagei___stack_chk_fail__ZN8Fl_Timer6stepcbEPv__ZN8Fl_Timer4stepEv__ZN9Fl_Widget6redrawEv__ZN2Fl11add_timeoutEdPFvPvES0___ZN9Fl_Widget11do_callbackEPS_Pv__ZN8Fl_Timer6handleEi__ZN8Fl_Timer5valueEd__ZN2Fl14remove_timeoutEPFvPvES0___ZN8Fl_TimerD0Ev__ZTV8Fl_Timer__ZN9Fl_WidgetD2Ev__ZdlPv__ZN8Fl_TimerD1Ev__ZN8Fl_TimerD2Ev__ZN8Fl_TimerC1EhiiiiPKc__ZN8Fl_TimerC2EhiiiiPKc__ZN9Fl_WidgetC2EiiiiPKc__ZN8Fl_Timer9suspendedEc__ZN9Fl_Widget8as_groupEv__ZN9Fl_Widget9as_windowEv__ZN9Fl_Widget12as_gl_windowEv__ZTI8Fl_Timer__ZN9Fl_Widget6resizeEiiii__ZN9Fl_Widget4showEv__ZN9Fl_Widget4hideEv__ZTS8Fl_Timer__ZTVN10__cxxabiv120__si_class_type_infoE__ZTI9Fl_Widget__Z10fl_gettimePlS_.eh__ZN8Fl_Timer4drawEv.eh__ZN8Fl_Timer6stepcbEPv.eh__ZN8Fl_Timer4stepEv.eh__ZN8Fl_Timer6handleEi.eh__ZN8Fl_Timer5valueEd.eh__ZN8Fl_TimerD0Ev.eh__ZN8Fl_TimerD1Ev.eh__ZN8Fl_TimerD2Ev.eh__ZN8Fl_TimerC1EhiiiiPKc.eh__ZN8Fl_TimerC2EhiiiiPKc.eh__ZN8Fl_Timer9suspendedEc.eh__ZN9Fl_Widget8as_groupEv.eh__ZN9Fl_Widget9as_windowEv.eh__ZN9Fl_Widget12as_gl_windowEv.ehL_.strL_.str1EH_frame0 eureka-1.11-source/osx/staticlib/libfltk_gl.a0000644000175100017510000047037012647061302020544 0ustar aaptedaapted! #1/20 1415124514 0 0 100644 5916 ` __.SYMDEFx````K`5`'`'`'Z`'`'*.f....H.~........D5DDDDID2DDDDDDDDD`DDyDlDRDVD3DDDyD5`o`o`o`o`o$`o;`oS`oj`o`o`o`o`o`o`o`o9`oT`oo`o`o`o`o`o`o`o%`o-`o=@RWcx v  f U ) S      F          $ - x x x   s    e G (       f N 6    +Hf   )B]m Z C ``'`>`U`m`2`M```````h```__Z16fl_no_gl_contextv__Z17fl_set_gl_contextP9Fl_WindowP15__AGLContextRec__Z20fl_create_gl_contextP9Fl_WindowPK12Fl_Gl_Choicei__Z20fl_delete_gl_contextP15__AGLContextRec__ZN12Fl_Gl_Choice4findEiPKi__ZN12Fl_Gl_Window12hide_overlayEv__ZN12Fl_Gl_Window12make_overlayEv__ZN12Fl_Gl_Window14can_do_overlayEv__ZN12Fl_Gl_Window14redraw_overlayEv__ZN12Fl_Gl_Window20make_overlay_currentEv__ZN16Fl_Device_Plugin5klassEv__ZN16Fl_Device_PluginD0Ev__ZN16Fl_Device_PluginD1Ev__ZN19Fl_Gl_Device_Plugin4nameEv__ZN19Fl_Gl_Device_Plugin5printEP9Fl_Widgetiii__ZN19Fl_Gl_Device_PluginD0Ev__ZN19Fl_Gl_Device_PluginD1Ev__ZTI16Fl_Device_Plugin__ZTI19Fl_Gl_Device_Plugin__ZTS16Fl_Device_Plugin__ZTS19Fl_Gl_Device_Plugin__ZTV16Fl_Device_Plugin__ZTV19Fl_Gl_Device_Plugin_fl_gl_load_plugin__ZN12Fl_Gl_Window10invalidateEv__ZN12Fl_Gl_Window12as_gl_windowEv__ZN12Fl_Gl_Window12draw_overlayEv__ZN12Fl_Gl_Window12make_currentEv__ZN12Fl_Gl_Window12swap_buffersEv__ZN12Fl_Gl_Window17gl_plugin_linkageEv__ZN12Fl_Gl_Window4drawEv__ZN12Fl_Gl_Window4hideEv__ZN12Fl_Gl_Window4initEv__ZN12Fl_Gl_Window4modeEiPKi__ZN12Fl_Gl_Window4showEv__ZN12Fl_Gl_Window5flushEv__ZN12Fl_Gl_Window5orthoEv__ZN12Fl_Gl_Window6can_doEiPKi__ZN12Fl_Gl_Window6handleEi__ZN12Fl_Gl_Window6resizeEiiii__ZN12Fl_Gl_Window7contextEPvi__ZN12Fl_Gl_WindowD0Ev__ZN12Fl_Gl_WindowD1Ev__ZN12Fl_Gl_WindowD2Ev__ZN8Fl_Group8as_groupEv__ZN9Fl_Window9as_windowEv__ZTI12Fl_Gl_Window__ZTS12Fl_Gl_Window__ZTV12Fl_Gl_Window__Z12glutWireConeddii__Z12glutWireCubed__Z13glutSolidConeddii__Z13glutSolidCubed__Z13glutWireTorusddii__Z14glutSolidTorusddii__Z14glutWireSpheredii__Z15glutSolidSpheredii__Z16glutWireCylinderddii__Z17glutSolidCylinderddii__Z18glutWireOctahedronv__Z19glutSolidOctahedronv__Z19glutWireIcosahedronv__Z19glutWireTetrahedronv__Z20glutSolidIcosahedronv__Z20glutSolidTetrahedronv__Z20glutWireDodecahedronv__Z21glutSolidDodecahedronv__Z24glutWireSierpinskiSpongeiPdd__Z25glutSolidSierpinskiSpongeiPdd__Z27glutWireRhombicDodecahedronv__Z28glutSolidRhombicDodecahedronv_icos_r_icos_v_rdod_n_rdod_r_rdod_v_glutStrokeMonoRoman_glutStrokeRoman__Z14glutWireTeapotd__Z15glutSolidTeapotd__Z10gl_descentv__Z10gl_measurePKcRiS1___Z13gl_draw_imagePKhiiiiii__Z16gl_texture_resetv__Z22gl_texture_pile_heighti__Z22gl_texture_pile_heightv__Z27gl_remove_displaylist_fontsv__Z7gl_drawPKc__Z7gl_drawPKcff__Z7gl_drawPKci__Z7gl_drawPKciff__Z7gl_drawPKcii__Z7gl_drawPKciii__Z7gl_drawPKciiiij__Z7gl_fontii__Z7gl_rectiiii__Z8gl_colorj__Z8gl_widthPKc__Z8gl_widthPKci__Z8gl_widthh__Z9gl_heightv__ZN15gl_texture_fifo13already_knownEPKci__ZN15gl_texture_fifo15compute_textureEPKci__ZN15gl_texture_fifo15display_textureEi__ZN15gl_texture_fifoC1Ei__ZN15gl_texture_fifoC2Ei__ZN15gl_texture_fifoD1Ev__ZN15gl_texture_fifoD2Ev__Z8gl_startv__Z9gl_finishv__ZN2Fl9gl_visualEiPi__Z12glutIdleFuncPFvvE__Z12glutLayerGetj__Z12glutMainLoopv__Z13glutDeviceGetj__Z13glutSetWindowi__Z14glutAddSubMenuPci__Z14glutCreateMenuPFviE__Z15glutDestroyMenui__Z15glutSwapBuffersv__Z16glutAddMenuEntryPci__Z16glutCreateWindowPKc__Z16glutCreateWindowPc__Z17glutDestroyWindowi__Z18glutGetProcAddressPKc__Z18glutInitWindowSizeii__Z18glutRemoveMenuItemi__Z19glutChangeToSubMenuiPci__Z19glutCreateSubWindowiiiii__Z19glutInitDisplayModej__Z21glutChangeToMenuEntryiPci__Z22glutExtensionSupportedPKc__Z22glutInitWindowPositionii__Z23glutPostWindowRedisplayi__Z7glutGetj__Z8glutInitPiPPc__ZN12Fl_Gl_Window12as_gl_windowEv__ZN14Fl_Glut_Window12draw_overlayEv__ZN14Fl_Glut_Window12make_currentEv__ZN14Fl_Glut_Window4drawEv__ZN14Fl_Glut_Window5_initEv__ZN14Fl_Glut_Window6handleEi__ZN14Fl_Glut_WindowC1EiiPKc__ZN14Fl_Glut_WindowC1EiiiiPKc__ZN14Fl_Glut_WindowC2EiiPKc__ZN14Fl_Glut_WindowC2EiiiiPKc__ZN14Fl_Glut_WindowD0Ev__ZN14Fl_Glut_WindowD1Ev__ZN14Fl_Glut_WindowD2Ev__ZN8Fl_Group8as_groupEv__ZN9Fl_Window9as_windowEv__ZTI14Fl_Glut_Window__ZTS14Fl_Glut_Window__ZTV14Fl_Glut_Window_glut_menu_glut_menustate_function_glut_menustatus_function_glut_window__Z15glutBitmapWidthPvi__Z15glutStrokeWidthPvi__Z16glutBitmapHeightPv__Z16glutBitmapLengthPvPKh__Z16glutBitmapStringPvPKh__Z16glutStrokeHeightPv__Z16glutStrokeLengthPvPKh__Z16glutStrokeStringPvPKh__Z19glutBitmapCharacterPvi__Z19glutStrokeCharacterPvi_glutBitmap8By13_glutBitmap9By15_glutBitmapHelvetica10_glutBitmapHelvetica12_glutBitmapHelvetica18_glutBitmapTimesRoman10_glutBitmapTimesRoman24#1/20 1415124499 502 80 100644 4036 ` Fl_Gl_Choice.o |P__text__TEXT`7__bss__DATAP,__compact_unwind__LD __eh_frame__TEXThx h@ "` L P UHAWAVAUATSHIL%I$HEHH[Ht9uL9suMMLtDžPDžTDžPDžT Ѓ@ֺEЉXtDž\ `tD׍pPDŽPDŽPtHDŽPDŽPЉtHcDŽPt"HcDŽP HDŽP t"HcDŽP HDŽPtHcDŽPLPHDŽPA111LIMt* HD+LsHHCHL{I$H;EuHHĈ[A\A]A^A_]UHAWAVSHIL=IHEH 1Ht tHH~HH1H ; u=uɉ H=HcHH HQHcHI~tGL@,AN MAN,)A+F$EAF(E؉MHUоHHIHHHIH;Mu H[A^A_]UHAWAVSHIHL=IHEL95u H9twL5HH{tCH@,K MЋK,)+C$EԋC(E؉MHUоLLHLHLIH;Eu H[A^A_]UHHHHt 1H1]UHSPHH9uH~PH=H9t H9ȍI2)HcHHwȉHcHHHt[][] X 6aCa6<zRx ,x AC P$LU6AC I$tcAC I$6AC $ AC B- -m]W-O-H8-0-!- -------ypgY=?-#-- ---!-thbN-;. = ----+=`@ PX` xh,p@hm#C]v $<(1]dGW__ZN12Fl_Gl_Choice4findEiPKi___stack_chk_guard__Z15fl_open_displayv_aglChoosePixelFormat__Znwm___stack_chk_fail__Z20fl_create_gl_contextP9Fl_WindowPK12Fl_Gl_Choicei_aglCreateContext_realloc__ZNK9Fl_Widget6windowEv_aglSetInteger_aglEnable__ZN4Fl_X10window_refEv_aglSetWindowRef__Z17fl_set_gl_contextP9Fl_WindowP15__AGLContextRec_aglSetCurrentContext__Z16fl_no_gl_contextv_aglGetCurrentContext__Z20fl_delete_gl_contextP15__AGLContextRec_aglDestroyContext_memmove__Z27gl_remove_displaylist_fontsv__ZN12Fl_Gl_Choice4findEiPKi.eh__Z20fl_create_gl_contextP9Fl_WindowPK12Fl_Gl_Choicei.eh__Z17fl_set_gl_contextP9Fl_WindowP15__AGLContextRec.eh__Z16fl_no_gl_contextv.eh__Z20fl_delete_gl_contextP15__AGLContextRec.eh__ZL5first__ZL12context_list__ZL8nContext__ZL8NContext__ZL14cached_context__ZL13cached_windowEH_frame0 #1/20 1415124499 502 80 100644 1660 ` Fl_Gl_Overlay.o 8__text__TEXTL__compact_unwind__LDP__eh_frame__TEXT h  P UH1]UHH]ÐUHHt H]]ÐUHH]UH] 4FzRx $AC $D AC $lAC $AC $AC A -- -`@ F&0IEX4mn__ZN12Fl_Gl_Window14can_do_overlayEv__ZN12Fl_Gl_Window12make_overlayEv__ZN12Fl_Gl_Window14redraw_overlayEv__ZN9Fl_Widget6redrawEv__ZN12Fl_Gl_Window20make_overlay_currentEv__ZN12Fl_Gl_Window12make_currentEv__ZN12Fl_Gl_Window12hide_overlayEv__ZN12Fl_Gl_Window14can_do_overlayEv.eh__ZN12Fl_Gl_Window12make_overlayEv.eh__ZN12Fl_Gl_Window14redraw_overlayEv.eh__ZN12Fl_Gl_Window20make_overlay_currentEv.eh__ZN12Fl_Gl_Window12hide_overlayEv.ehEH_frame0 #1/28 1415124500 502 80 100644 5716 ` Fl_Gl_Device_Plugin.op  __text__TEXT @ __textcoal_nt__TEXTH ! __literal8__TEXT@__StaticInit__TEXTcPP __bss__DATA__common__DATA__datacoal_nt__DATA0  __const_coal__TEXT3 __cstring__TEXT##__mod_init_func__DATAH8  __compact_unwind__LDP@ __eh_frame__TEXTP`  h 84 PUHH]UH]UHSPHHH[]UHH]ÐUHH]ÐUHAWAVAUATSHhEAωHHPHI1M]D}DuI$LPP  1 1 1E|$(El$,BAHcIL4$AAgDDIL}AD$,HcH 1LIIc|$(Ict$,LcLl$D$ D$HD$$  MIML5I>I>]*WI> *EE+]ED$,D)W*EAL$(W*EWA*EH}11I>HEHD$HEHD$HEHMHL$H$LI>LH}LHh[A\A]A^A_]ÐUH]UHSPHHH[]?UHSPHHHHH5HHHHHH=HHH[]19Fl_Gl_Device_Plugin16Fl_Device_Pluginopengl.device.fltk.orgfltk:device 4 B P7X  zRx $ AC $DAC B$lt AC $Z AC ,@7AC M$ AC $ AC $<AC B 2---*-*-a$-Y-P&-H-@'-;- (-!-"- -1=|%-5#-+- 4-6-7-3-3-3-3-5-;-"--*-*-_.-Q0=J=C8=1)-)" =//  ph`,P+H@,0(  `@  : # P  8X4 k Pn `wB P< 2  hNp60dy03NfP]J__ZN19Fl_Gl_Device_PluginD1Ev__ZN9Fl_PluginD2Ev__ZN19Fl_Gl_Device_PluginD0Ev__ZdlPv__ZN16Fl_Device_Plugin5klassEv__ZN19Fl_Gl_Device_Plugin4nameEv__ZN19Fl_Gl_Device_Plugin5printEP9Fl_Widgetiii_glPushClientAttrib_glPixelStorei_malloc_glReadPixels_glPopClientAttrib_CGColorSpaceCreateDeviceRGB_CGDataProviderCreateWithData_CGImageCreate_fl_gc_CGContextSaveGState_CGContextTranslateCTM_CGContextScaleCTM__ZN4Fl_X13q_begin_imageER6CGRectiiii_CGContextDrawImage__ZN4Fl_X11q_end_imageEv_CGContextRestoreGState_CGImageRelease_CGColorSpaceRelease_CGDataProviderRelease_free__ZN16Fl_Device_PluginD1Ev__ZN16Fl_Device_PluginD0Ev__ZTV16Fl_Device_Plugin__ZN9Fl_PluginC2EPKcS1___ZTV19Fl_Gl_Device_Plugin___dso_handle___cxa_atexit_fl_gl_load_plugin__ZTI19Fl_Gl_Device_Plugin__ZTS19Fl_Gl_Device_Plugin__ZTS16Fl_Device_Plugin__ZTI16Fl_Device_Plugin__ZTVN10__cxxabiv120__si_class_type_infoE__ZTI9Fl_Plugin___cxa_pure_virtual__ZN19Fl_Gl_Device_PluginD1Ev.eh__ZN19Fl_Gl_Device_PluginD0Ev.eh__ZN16Fl_Device_Plugin5klassEv.eh__ZN19Fl_Gl_Device_Plugin4nameEv.eh__ZN19Fl_Gl_Device_Plugin5printEP9Fl_Widgetiii.eh__ZN16Fl_Device_PluginD1Ev.eh__ZN16Fl_Device_PluginD0Ev.ehL_.str1L_.str__ZL22imgProviderReleaseDataPvPKvm__GLOBAL__I_a__ZL16Gl_Device_PluginEH_frame0__ZL22imgProviderReleaseDataPvPKvm.eh #1/20 1415124500 502 80 100644 10876 ` Fl_Gl_Window.o hP8 __text__TEXTs (t__literal8__TEXTx h __literal4__TEXT __textcoal_nt__TEXT   __cstring__TEXT __bss__DATA8__const__DATAP @__const__TEXT __compact_unwind__LD H__eh_frame__TEXT  hi P /90UHH]UHAVSHHtHc`lHuLHHHu.@uIHHHt.LsHc`It[A^]H[A^]HHH=1[A^]UH倧HHtH]UHAWAVSPIAHD9u 1L9tP11HDLHtDLHH HǃH[A^A_]UHAWAVSPAIHHHtxL%EDH[A^A_]UHAVSH0HL5IHEHHu2H1HHHHHHt&HuHUHM̉MЋH,+MȋC,)MEEC,K(M؉EHHUоHtHHIH;Eu H0[A^]UHAVSHHL5IHEHu: {(s,UM))C(K,*+E**+M*%"-"IH;Eu H[A^]UHAWAVSH(L=IHEH Dw(_,Huܿ Hu A* (^W*^DW*rY‰W*YW1111AD}EMU HIH;Eu H([A^A_]UHAWAVSPHHDHAH=IMtrH5LH5LH5LGHHPH9HHPX<H HcHH9t(Cm Cm{m u {muEu HHPL5MLuH1HHH5HMtEt H9tgq S(K,11*K(*[,%-WW11HS(K,11AHƃ TCmuEu:HHP/HHHPH9u HHPXHH9u+=t"HHPXH[A^A_]ÐEglUHAWAVAUATSPEAAAHC(D9uD9s,tD9c uD9D9{$u uD9s,t HHDDDEH[A\A]A^A_]UHSPH11HH[]UHSPHHH[]UH]UHSPHHH11HHH[]UHSPHCnǃHǃfǃHǃHǃHǃH[]UH]UHHHH=1]UHAVSAHAuHt)HHP(AuHu 11HHD[A^]UHH]??@??UHH]ÐUHH]ÐUHH]Insufficient GL supportGL_SWAP_TYPECOPYNODAMAGESWAPFl_Gl_Window::draw() *must* be overriden. Please refer to the documentation.12Fl_Gl_Window!.a|^a!!zWaa|X <X b2X W!d    zRx $8AC $D$AC C$l.AC $AC F$^AC F$JAC G$ 6AC G$4WAC I$\AC F,p|AC J$ AC B$AC B$ AC $,2AC B$TXAC B$|AC $AC $WAC C$AC $ AC $D AC $l AC k V=_ E-P *-@ K-# K- ?=@-H-C-z*-n8^0-TN-F0-8C-**-F-T-yZ-tY-aY-TmE-"A-mm-W-b-_-g-]-Y-xd-nX-bQ:-I?;-&mmyh-qbh-ZKh-C4U-/'mY--O-S-c-^-`-^-{`-vW-bY-Xd-Nb-Ef-*e-]-a-^-]-a-^-[-\-P=vO-__-ZR.g-]-\-P=O-G=d-Y-Q-R-UI-@J-8:-)9-;-P=<-[B-L=-)*->=B-D-u=-N=-,D-=-Lx7pMh` X P4H2@80((& ,.6`@ `@ `@ ?  F 8U  ]  e  m  u @ H       R   zd d  x H X5  8= s wF { 7  p (| `I< X `b      - P S (m3WoLSkAwe@%c90G*T>__ZN12Fl_Gl_Window6can_doEiPKi__ZN12Fl_Gl_Choice4findEiPKi__ZN12Fl_Gl_Window4showEv__ZN9Fl_Window4showEv__ZN9Fl_Widget6redrawEv__ZN2Fl5errorE__ZN12Fl_Gl_Window10invalidateEv__ZN12Fl_Gl_Window4modeEiPKi__ZN12Fl_Gl_Window7contextEPvi__Z20fl_delete_gl_contextP15__AGLContextRec__ZN12Fl_Gl_Window12make_currentEv___stack_chk_guard__Z20fl_create_gl_contextP9Fl_WindowPK12Fl_Gl_Choicei__Z16gl_texture_resetv__Z17fl_set_gl_contextP9Fl_WindowP15__AGLContextRec__ZNK9Fl_Widget6windowEv__ZNK9Fl_Widget17top_window_offsetERiS0__aglSetInteger_aglEnable_glDrawBuffer_glReadBuffer__ZN9Fl_Window8current_E___stack_chk_fail__ZN12Fl_Gl_Window5orthoEv_glGetIntegerv_glLoadIdentity_glViewport_glOrtho__ZN12Fl_Gl_Window12swap_buffersEv_glGetFloatv_glMatrixMode_glPushMatrix_glScalef_glTranslatef_glRasterPos2i_glCopyPixels_glPopMatrix_glRasterPos3f_aglSwapBuffers__ZN12Fl_Gl_Window5flushEv_fl_getenv_strcmp_glDisable__ZN9Fl_Widget6damageEh_glFlush__ZN12Fl_Gl_Window6resizeEiiii_aglUpdateContext__ZN9Fl_Window6resizeEiiii__ZN12Fl_Gl_Window4hideEv__ZN9Fl_Window4hideEv__ZN12Fl_Gl_WindowD0Ev__ZN12Fl_Gl_WindowD2Ev__ZdlPv__ZN12Fl_Gl_WindowD1Ev__ZTV12Fl_Gl_Window__ZN9Fl_WindowD2Ev__ZN12Fl_Gl_Window4initEv__ZN8Fl_Group3endEv__ZN12Fl_Gl_Window12draw_overlayEv__ZN12Fl_Gl_Window4drawEv__ZN2Fl5fatalE__ZN12Fl_Gl_Window6handleEi__ZNK9Fl_Widget9visible_rEv__ZN9Fl_Window6handleEi__ZN12Fl_Gl_Window17gl_plugin_linkageEv_fl_gl_load_plugin__ZN8Fl_Group8as_groupEv__ZN9Fl_Window9as_windowEv__ZN12Fl_Gl_Window12as_gl_windowEv__ZTI12Fl_Gl_Window__ZTS12Fl_Gl_Window__ZTVN10__cxxabiv120__si_class_type_infoE__ZTI9Fl_Window__ZN12Fl_Gl_Window6can_doEiPKi.eh__ZN12Fl_Gl_Window4showEv.eh__ZN12Fl_Gl_Window10invalidateEv.eh__ZN12Fl_Gl_Window4modeEiPKi.eh__ZN12Fl_Gl_Window7contextEPvi.eh__ZN12Fl_Gl_Window12make_currentEv.eh__ZN12Fl_Gl_Window5orthoEv.eh__ZN12Fl_Gl_Window12swap_buffersEv.eh__ZN12Fl_Gl_Window5flushEv.eh__ZN12Fl_Gl_Window6resizeEiiii.eh__ZN12Fl_Gl_Window4hideEv.eh__ZN12Fl_Gl_WindowD0Ev.eh__ZN12Fl_Gl_WindowD1Ev.eh__ZN12Fl_Gl_WindowD2Ev.eh__ZN12Fl_Gl_Window4initEv.eh__ZN12Fl_Gl_Window12draw_overlayEv.eh__ZN12Fl_Gl_Window4drawEv.eh__ZN12Fl_Gl_Window6handleEi.eh__ZN12Fl_Gl_Window17gl_plugin_linkageEv.eh__ZN8Fl_Group8as_groupEv.eh__ZN9Fl_Window9as_windowEv.eh__ZN12Fl_Gl_Window12as_gl_windowEv.ehL_.str__ZL9SWAP_TYPEL_.str1L_.str2L_.str3L_.str4__ZZN12Fl_Gl_Window5flushEvE13ortho_context__ZZN12Fl_Gl_Window5flushEvE12ortho_windowL_.str5EH_frame0#1/28 1415124499 502 80 100644 30116 ` freeglut_geometry.o (HH__text__TEXT:K__literal8__TEXT:<__const__TEXT;P>__data__DATA <>__compact_unwind__LDApDj__eh_frame__TEXTD8PG hhkCo P16 UHHE 9YM9WWMY 9ME(EM(E(UE((WW e9E((E(UEM(EM(WW8E((EM(E(UEM(8WWE(UEM(EM(E((WW =8E(UE((EM(EM(WW7E((EM(E(UEM(H]UHHE s7YM`7WWMY P7ME(EM(E(UE((WW 6E((E(UEM(EM(WW6E((EM(E(UEM(X6WWE(UEM(EM(E((WW 5E(UE((EM(EM(WW5E((EM(E(UEM(H]UHAWAVAUATSHAEDH}HuH}HuIHMHxEHMHpE4WWWWUEEYEEEuMcIH]LL}UYAYU]YUYAYYUAHIEALhAHEH`HEHXAETEMMEHxTUHpTUEEMYMMYMDTLXL`A$UYAYUA$]YUYAYYUA$UYAYUA$]YUYAYYUIIAMHHh9U(]( U]]Um2WW3EfWfWWEx|LeLuU(YEEA1A]YA YA]YUYA YYUUHA9uLuLeLLHpHxHĈ[A\A]A^A_]UHAWAVAUATSPIIAADL ^1t*^MAD$HcؿHIHII?HtHu,HtIHHH[A\A]A^A_]HIH?HAM|5EW*YII MHA9uIIcIH[A\A]A^A_]UHAWAVAUATSHHxH}EH}HuH}HuHEHpLuHEHhHEH`HE@\AHpBECEHExEYEED\H`LhAE MUUEYMY]YY(UIHAuIHxA9:HEL}L}HEHpH]HEHEHx@hE1HxLHDhLmHp BYEBY MAUUMI]EYMYUYLMHEHIAuHIIHEA9DLuLpHH}L}LeLuLLLHĈ[A\A]A^A_]UHAWAVAUATSHxAAE~EMA*EM-EDH}Hu-WWWWWEUx8LuH]E|$AY YWUIHAu](Y(YXQ(^M(^MAD|EHEHEHEHE1ME^pe(^hAD$dWE1((M]mEE\hEdLuLmxrAEUYAYUAEUYAYUAEUYAYUIIupXEEmANj|A9U(E(UWUEHEUYHEYUEHELpHEHXAFUYKYUWWUAUY YUAUY YUIHAuH}H}Hx[A\A]A^A_]UHAWAVAUATSHh]AMEDH}Hu~*Y*](Ye(YXQ^]^eM^MM(^UHEHxW1HEHpEMEDALpLx~QAUYAMYUAUYAMYUIIAuEXEM\MËE9EYE~mLuLmE1AUYALYUAUYALYWWWUHA9uLmLuLLHh[A\A]A^A_]UHAWAVAUATSHXADeE~EMA*EMa(EHH]H}Hu:(WWWWWx;LuH]HEDxAUY YWIHAu'WWWWUHExJHEDpLcIH]LL}UYAYUAHIEEM(^EEHEHELmHE@EWAUE9t(MHE]LILexfA$AMWA$UYAMYUA$UYAMYUIIuEMXDeE9AFA(MM7H]LmH]LHHX[A\A]A^A_]UHAWAVAUATSHHADuMEDH}Hu~*%M(^UHEHEWE1HEHEA9t(MEL}Lm~BAEAWAEUYAYUIIAuEXEA9AD$AMDuqE~oL}LeE1AA WAUYA YWAUYA YUHA9uLeL}LLHH[A\A]A^A_]UHAWAVAUATSHxlMEADNDxN؉]Dž|DÍ@LcLIǿLADIENA* #^pW* #^Ml|Oȉ|fW1HE1HMEf)MAHEH H@f(Mff)MfWE1EEHe]f(YXHH ff(]fYfA(YATUffYfA ADEXHAE9wEXpHMHHE|HEDuD9DLeL}lɸO@EE11LeED}пEED}Lu~McK<K<E;]|ED}Ax9Du|LmDLulOȉM1HE1HMM~GHEH L4@E1ALH I<HEH >(6W W((W W (WyW\ \( ]WW :   (WW(W W f((W`hW0P+ (WW (W W ((Ww7WW/2 2(W7 W (WW(Wh hWP hS C(W9AW!((W W  (Wg gW_ _b(OW /GW ((W W  (W W  p(Wv .WV &! !(W W  (W W ((W tW tD?(<]UH  CCW ;;W3 3(+WW(( W W (WnWv~Q Q(  RWW / (WW( W W x[((WU]W%E  ( WW (W W~ ~(( Wl,WL$' '(W, W ( WW(}W] ]WE ]H 8( W.6W((W W  ( W\ \WT TW(DW $<W  (( W W  (W W u e( Wk #WK  (W W  ( W W w((W iW i94(1]UH8((-WWWW WW(WWWWWW  (WWWWrWW oJ R(WW4WW 1WW  (WWWWWW  (WWWW WW|g(LWWQWW >WW((WWWW WW ]UH (( WWWW WW  r (WWd g WWWW > )  1 (WW WW WW   (WW WW WW    (WW WW^ WW K F  . (WW0 WW WW  ( WW WW WW  ((WW WW WW m ]UHAWAVATSL5f fW fWfWL=LHHHL%0L fW fW(fWLLH0 fW 8fW@fWLHLHn fW PfWf(XfWLLL[A\A^A_]UHAWAVATSL5 fW fWfWL=LHHHL%0L fW fW(fWLLH0a fW 8fW@fWLHLH fW PfWf(XfWLLL[A\A^A_]UHAWAVAUATSH(L5IHEлL%L-L}JcD#H@JcL#H IJc#HRfADfALf\AT\A\AdfAdfff\f(fYAl\f(ffYffYf\f)EfY\mLJcD#H@I|JcD#H@I|Jc#H@I|H HIH;EuH([A\A]A^A_]UHAWAVAUATSH(L5IHEпL%L-L}JcD#H@JcL#H IJc#HRfADfALf\AT\A\AdfAdfff\f(fYAl\f(ffYffYf\f)EfY\mLJcD#H@I|JcD#H@I|Jc#H@I|H HIH;EuH([A\A]A^A_]UHAWAVATSL5 L=L%LJcD;H@I<JcD;H@I<JcD;H@I<Jc;H@I<IHHu[A\A^A_]UHAWAVATSL5 L=L%LJcD;H@I<JcD;H@I<JcD;H@I<Jc;H@I<IHHu[A\A^A_]UHAWAVAUATSHXHAEHHHEtvAYf)Eff)EAL-L}ffCL,fYMfXf)MC ,f(EYXKMDLoIIpu)EL5E1L-LuKAD /f(fWALfWATfWAIcH@ADf(]YXSALYXATYXSIIuILuI IOHHH;EuHX[A\A]A^A_]UHAWAVAUATSHXHAEHHHEAY f)Ef(ff)MAL-L}ffCL,fYMfXf)MC ,YXKMDLlf(EIIpuHHH;EHX[A\A]A^A_])EL5E1L-LuKAD f(fWALfWATfWAIcH@ADf(]YXSALYXATYXSIIuILuI I^HHH;EuHX[A\A]A^A_]?????-DT!@????-DT!@-DT!-DT!@-DT!ZN ?HF 8?w?/7??/7HF 8뿁wZN ZN ?HF 8?w?/7??/7HF 8뿁wZN Ey??EyEy??Ey???=UUUUտ+}+?=UUUUտ+}+޿5 p ?=UUUUտ+}+޿5 p ?%?%?%?U m?HF 8?%?յoq'ZN ?%?յoq'ZN %?U m?HF 8%ܿ%%ܿU mѿHF 8?%ܿյoq'?ZN ?%ܿյoq'?ZN %ܿU mѿHF 8        ?Kf??Kf??Kf?Kf?Kf?Kf?Kf濸Kf?Kf濸KfKf?KfKf?Kf?࿸KfKf        nf?nf??nfֿnf??nfֿnfֿ?nf?nfֿ???nf?nf?nfֿnf?nfֿnfֿnf?nfֿUXX X OXXXVXBXEXL[#[+-&0f 1f 2PXB4PX5 /6 6XU8XzRx $@AC $DUAC ,lAC P,AC J,{AC P,OAC M,,AC M,\AC M,&AC M,BAC M,AC M$[AC $D[AC $lAC $\AC ,fAC G,fAC G,2PAC M,LRPAC M,|rAC G,AC G,KAC M, AC M:7-9<-98=9A-p9=-M969,9%9;-88=88r88=Q87-488=8<- 8A-7=-77;-|7r77668=6<-6B-6B-6B-t6B-b6>-Z64S65G63@6;-6<- 6B-5B-5B-5B-5>-5;-54555357-q5<-[5B-I5B-65B-#5>-z41s42g4;-V48=>47-4<- 4B-3B-3B-3>-3;- 313238=2<-2B-2B-2B-2=-22222B-2B-2B-|2=-s2g2[2S2K2B-C2B-;2B-32=-*222 22B-11B-11B-11=-111111;-1<-{1B-s1B-k1B-c1=-Z1J1>161.1B-&1B-1B-1=- 11000B-0B-0B-0=-00000B-00B-0~0B-v0o0=-f0Z0N0F0>070;-"0<-0A-0 0A-0/A-//=-//A-//A-//A-//=-///A-z/l/A-g/Y/A-T/F/=->/6/./A-)//A-//A-/.=-...A-..A-..A-..=-...A-.y.A-t.f.A-a.S.=-K.C.;.A-6.(.A-..A-..=----A---A---A---=---;--<--A--w-A-r-d-A-_-Q-=-F->-A-9-+-A-&--A---=--,,A-,,A-,,A-,,=-,,,A-,,A-,v,A-q,c,=-[,S,K,A-F,8,A-3,%,A- ,,=- ,,+A-++A-++A-++=-+++A-++A-++A-~+p+=-h+`+X+A-S+E+A-@+2+A-'++=-+ +;-*<-*A-***A-***A-***A-**A-***=-*x*m*;-c*<-^*A-V*N*F*A-A*9*.*A-)*!**A-**)A-)))=-)));-)<-)A-)))A-)))A-))w)A-o)g)_)A-Z)R)G)=-B):)/);-%)<- )A-) )A-))(A-(((A-(((A-(((=-(((;-(<-(A-~(v(n(A-i(a(V(A-Q(I(>(A-3(+(A-&(((=-((';-'<-'A-'''A-'''A-'''A-'''A-''t'=-o'g'\';-R'<-M'A-H'='5'A-0'(''A-'''A-&&&A-&&&=-&&&;-&<-&A-&&A-&&&A-~&v&k&A-c&[&S&A-N&F&;&=-6&.&#&;-&<-&A- &&%A-%%%A-%%%A-%%A-%%%=-%%%;-%<-z%A-u%j%b%A-]%U%J%A-E%=%2%A-*%"%%A-% %%=-$$$;-$<-$A-$$$A-$$$A-$$$A-$${$A-v$n$c$=-^$S$K$;-A$<-<$A-1$)$A-$$$$A- $$#A-###A-###=-###;-#<-#A-###A-#x#m#A-h#`#U#A-J#B#A-=#5#*#=-%###;-#<-#A-"""A-"""A-"""A-"""A-"""=-"~"s";-i"<-d"A-\"T"L"A-G"?"4"A-/"'""A-" ""A-!!!=-!!!;-!<-!A-!!A-!!!A-!!!A-}!r!j!A-e!]!R!=-M!E!:!;-0!<-+!A-#!!!A-!! A-   A-  A-   =-   ;- <- A-  y A-t l a A-\ T I A-D 9 1 A-, $  =-   ;-<-A-A-A-A-A-z=-umb;-X<-SA-H@A-;3(A-#A-A-=-;-<-A-A-A-|qA-f^A-YQF=-A9.;-$<-A-A-A-A-A-=-;-<-A-xphA-c[PA-K@8A-3( A-=-;-<-A-A-A-A-A-~vn=-f^V;-H?-5:--:-%<-B->-B->-B->-B->-7;-~6-56-@-9-9-A?-.:-&:-<-B->-;-P<-AB-8>-;-+6-6-@-x9-b9-:-:-<-A-A-=-`;-2<- A-=-;--R:-<:-<-A-A-=-y;-#<-A-A-=-;-<-A-[A-M=-B:;-0-:-:-<-A-A-l=-6;-<-A-=-;--:-:-<-A-z=-ZA-JA-=-;-<-A-^A-<=- ;-x <-. A- A- =-  ;- - } :-d :-\ :-T :- <- A- =-} ;-" <- A- =- ;-. - - 6-f :-D :-* 9- 9-:-:-:-:-<-yA-I=-A-=-;-<-A-P=-.A-=-;-#<-A-=-A-=-xp;-1-!-<-A-A-A-A-=-A-|A-jA-ZA-H=-C5A-%A-A-A-=-A-A-A-A-=-A-qA-_A-MA-==-8*A-A-A-A-=-;-<-A-A-nA-\A-L=-G9;-/<-*A-A-A-A-=-;-<-A-A-A-A-|=-qi;-_<-ZA-HA-6A-$A-=-;-<-A-A-A-A-=-;-<-A-zA-hA-VA-D7=-,$;-`@ `@ `@  <;D8EED pE<$DXFKEF VhEP;EV(FE+PG-l0G2G&0XGQB4G1GcLF~#1F6JxHU8oHl5H/6$HH7</=@>?v?nh5$>)1__Z12glutWireCubed_glBegin_glNormal3d_glVertex3d_glEnd__Z13glutSolidCubed__Z15glutSolidSpheredii_free_calloc___sincos_stret__Z14glutWireSpheredii__Z13glutSolidConeddii__Z12glutWireConeddii__Z17glutSolidCylinderddii__Z16glutWireCylinderddii__Z13glutWireTorusddii_glPushMatrix_glNormal3dv_glVertex3dv_glPopMatrix__Z14glutSolidTorusddii__Z20glutWireDodecahedronv__Z21glutSolidDodecahedronv__Z18glutWireOctahedronv__Z19glutSolidOctahedronv__Z19glutWireTetrahedronv__Z20glutSolidTetrahedronv__Z19glutWireIcosahedronv___stack_chk_guard_icos_v_icos_r___stack_chk_fail__Z20glutSolidIcosahedronv__Z27glutWireRhombicDodecahedronv_rdod_n_rdod_v_rdod_r__Z28glutSolidRhombicDodecahedronv__Z24glutWireSierpinskiSpongeiPdd__Z25glutSolidSierpinskiSpongeiPdd__Z12glutWireCubed.eh__Z13glutSolidCubed.eh__Z15glutSolidSpheredii.eh__Z14glutWireSpheredii.eh__Z13glutSolidConeddii.eh__Z12glutWireConeddii.eh__Z17glutSolidCylinderddii.eh__Z16glutWireCylinderddii.eh__Z13glutWireTorusddii.eh__Z14glutSolidTorusddii.eh__Z20glutWireDodecahedronv.eh__Z21glutSolidDodecahedronv.eh__Z18glutWireOctahedronv.eh__Z19glutSolidOctahedronv.eh__Z19glutWireTetrahedronv.eh__Z20glutSolidTetrahedronv.eh__Z19glutWireIcosahedronv.eh__Z20glutSolidIcosahedronv.eh__Z27glutWireRhombicDodecahedronv.eh__Z28glutSolidRhombicDodecahedronv.eh__Z24glutWireSierpinskiSpongeiPdd.eh__Z25glutSolidSierpinskiSpongeiPdd.eh__ZL14fghCircleTablePPdS0_i__ZL5tet_r__ZL5tet_iEH_frame0__ZL14fghCircleTablePPdS0_i.eh#1/36 1415124499 502 80 100644 29212 ` freeglut_stroke_mono_roman.o@ P9`P9__text__TEXT`__cstring__TEXT `__data__DATAp;b__const__DATA0>__const__TEXT`#PG_h P~~MonoRomanaC%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B           " qێBBMUBMUy>BZUBMUBwByA%QB|aA|aB|aAyAyA:dAMUB|a@y>B:dBqێB|a@B:dAmB:AmBm+BB%QBqێBwB:dBZUBy>BZUB|aA:A|aA|aB:dA%QByATdBMUBTdBm+B%QBwB|aBqێBMUBBMUBB|aByBy>B|aA|aB:dAy>ByA%QBMUB%QBm+By>BwBMUBqێB:AB:ABMUByBy>ByBTdB!BBHBoB0 [BJ B_nBB_nBB0 [BBHBaB4BZUB4BTdB0 [By>BHBoB0 [B%B0 [ByBHBmB4BB!BqێB!BwB4B%QBGBm+B4BMUB!ByA!B:dA4B|a@HB0 [B|a0 [B|aHB:0 [B|aB4B:A4B|aAHB|aA0 [B|a@_nB|a_nB:d0 [ByHB:!BMU%QBB%QBMUGBB0 [BoBHBJ B4BB4BBHBB0 [BaB_nBZUB_nBTdBHBy>B0 [BoBHB%BHByB0 [BmB_nBBGBqێBGBwB_nB%QB!Bm+B_nBMUBGByAGB:dA_nB|a@0 [BHB|aHB|a0 [B:HB|aB_nB:A_nB|aA0 [B|aAHB|a@4B|a4B:dHBy0 [B:GBMUœ$BZUB%A%AZUB$BZUB%A$B%AZUB0 [BBZUB0 [B4B|aqB:%AMUmAMU%AZUB$B$BZUB%A:dAZUBMUB QBZUBMUB QBZUBqێBBZUBqێByAZUB QBBZUB QB%AZUB%A|aAA|a@!B0 [BGB|a@$B|aA$BZUB$By>BBy>B|aA%QB|a@wBqێBgUBZUBZUBZUB$B%QBwBwB_nBZUB4BZUBAwB%A%QBAm+B!B|aBGBMUBwB:A$B|aA$B:dAwB|a@_nB4BA|a@%A:dAgUBZUBgUBgUB|aBaB%QBy>BwBTdBZUBqێBZUBBZUBBMU¡B%QBdێBwBjwBZUBy>BZUB|aBwB:A%QByA|aByA:A:A:dA|aB|a@y>BjwBdێB|a@B:dAyAZUByAMUyA%QBMUBwBm+BZUB:dBZUBMUBwBaB%QBB|aBB:AaB:dAMUB|a@:dBm+BMUB|a@yA:dA4BZUBqBwB%A%QBmA|aBmA:A%A:dAqB|a@4B_nB_B|a@$B:dAB:AB|aB$B%QB_BwB_nBZUB4BZUB%AZUB%A%Ay>B!BwBHBZUBGBZUBwBwB$By>B$BZUBy>B:dAwByAZUB|aBZUBy>BwB%QBy>B%QB%QBy>BZUBwBaBZUBBZUBBwB%By>B%B%QBB%QB%AB%AwBZUB%A|aA4B|aB$BTdBBwByBZUBBwB%BTdBBwBZUBwB:dTdB:y>BMU–aBMUy>BB%QByBTdBB%QB%By>BB%QBZUB%QB%AB%A%Ay>B!BwBHBZUBGBZUBwBwB$By>B$BBZUBB|aaBydێB:jwBMUy>BMU|aB:B%QBdێBwBjwBZUBy>BZUB|aBwB:A%QByA|aByA:A:A:dA|aB|a@y>BjwBdێB|a@B:dAqێBBwBB%QByBy>BBy>BgUBZUBZUBZUByA|aBB|aBBy>BaBTdBdێBwBjwBZUBy>BZUB|aBwB:A%QByA|aByA:A:A:dA|aB|a@y>BjwBdێB|a@B:dABBBB%QBdێBwBjwBZUBy>BZUB|aBwB:A%QByA|aByA:A:A:dA|aB|a@y>BjwBdێB|a@B:dAB%QBdێBwBjwBZUBy>BZUB|aBwB:A%QByA|aByA:A:A:dA|aB|a@y>BjwBdێB|a@B:dAyAByAyA%QBMUBwBm+BZUB:dBZUBMUBwBaB%QBB|aBB:AaB:dAMUB|a@:dBm+BMUB|a@yA:dABZUBBB%QBdێBwBjwBZUBy>BZUB|aBwB:A%QByA|aByA:A:A:dA|aB|a@y>BjwBdێB|a@B:dAm+BBZUBqێBm+BBaByBZUBqێBMU%BMU%B::MU QBJ B:dAm+B QBJ BBm+BGBBGBMU_BB_BMUqBB_BBqBMU_BMU|aABmB:dqBBqBMU¡!BB!BMUqBB_BBqBMU_BMU¹mBB|aA|aABmBB|aAmB:dAB QB%QB QBBB QB%QB|aABmBmBB|aA|a@B:A QBB:A QBBaBBBaB:dAB QBBB QB|aAB|aA:AyA:dAMUB|a@y>B:dBqێB|a@B:dAmB:AmBB QBB QB|aABmBBmBmBaByBjwBBm+BB:AyB|aAmB|aAaByAZUB:AwB|aBTdBMUBy>BaBm+BB|aBmB:AmB:dAaB|a@jwBm+B:A|a@|aA:dA|aAB|aA|aABjwBBaByBBBmBBmBqێBBwBaBTdBjwB%QB|aA%QB QB%QBmBm+BBMUByByAmB|aAaB:dAwB:dA|aB|aAyAyA:dAMUB|a@m+BjwBqێB|a@B:dAmByAB|aBBwBmBaBBmBqێByBjwBBm+BB:dB|aAmB|a|aAB|aA|aABjwBBaByBBBmBBmBZUBBTdBaB%QBjwBy>B|aAy>Bm+BBMUByByAmB|aAaB:dAwB:dA|aB|aAyAyA:dAMUB|a@m+BjwBqێB|a@B:dAmByAB|aBBwBmBaBBmBqێByBjwBBm+BB|aAB|aA|aABmBmBBmB:dAB:dA:dAB QBBB QBBBByAByAyAB|aAB|aAmBB|aAMUBm+BTdBmBaBBaByAqێB|aAZUB|a@TdBy>BaB|a@gUB|aAoAyAoAMUB%QBB%QB|aAB|aAmBBmB|aA%QBmB%QB0BaBBmBByBGBB4BBqByB%AmBmAaBgUAwBgUA|aBmAyA%A:dAqB|a@4BGBB|a@B:dA0ByA0B|aBGB|aB0B|aBmABmAmABBBmA%QB_nB%QBmABmAmABBBmA%QB_nB%QBmAB|aAB|aA|aAB QBBMUByBaBmBBaBmBwBmB|aBByAaB:dAMUB|a@ QB|aA0BaBBmBByBGBB4BBqByB%AmBmAaBgUAwBgUA|aBmAyA%A:dAqB|a@4BGBB|a@B:dA0ByA|aAB|aA|aABjwBBaByBBBmBBmBqێBBwBaBTdBjwB%QB|aA%QBjwB%QBaBy>BBm+BmBMUBmB|aAB|aAaB|a@jwB|aA QBB:dA QBBB:AMUBaBMUBGB%QB0 [BTdB4BTdB!By>B!Bm+B4BMUB0 [BMUBGB|aBGBTdBGB|aB_BMUB$BMUBBm+BBy>B$BwB_BqێB0 [BaBHBaBqBqێB%AwBmAy>BmAm+B%A:AqB|aAHB:dA0 [B:dA_B|aAyAaByAB:ABMUByBm+BBjwBBdێByBaBBBBBqێBaBwBdێBTdB QBy>B QBMUB QB|aAy>B|a@ QB:dB|a@ QB|aA:dAmBBm+B:dA|aATdByBTdB|aA:AyB:ABmB:dAm+BB%QBZUBy>BwB%QBTdBTdBwB%QBZUBTdB|a@%QBy>B|a@%QB|aATdB|a@TdB|a%QB:dy>B|a%QBZUBy>BwB%QBTdBTdBwB%QBZUB%QB|aAy>B|a@%QBTdB|a@%QB|aABZUB$B%QB_Bm+B0 [B|aBHB|aBqBm+B%A%QBmAZUBmAqێB%AmBqByBHBB0 [BB_ByB$BmBBZUBBm+B$B|aA_B|a@0 [B4BA|a@%A:dAm+BB:AyByAmByAaB:AZUB|aBwB:dBTdBqێB%QBBm+BmBMUBmB|aAB|aAaB|a@jwBm+B:A|a@yA|aA|aA|aA|aAMUByAm+BMUB%QBy>BTdBMUBwBaBZUBBaBBmBaByBjwBBm+BBmBB|aB|aABmBB$BmBByB_nBBHBBqByB%ABmATdBmAMUB%A:dAqB|a@HB0 [B_B|a@$B:dAB:ABMUB$By>B_BTdB0 [BwBHBwBqBTdB%Ay>BmAMUBaBB:AByATdB:AwBm+BZUB:dBZUBqێBwBB%QBmB|aBmB:AB:dAqێB|a@:dBm+B:A|a@yA|aA|aA|aAGBBgUAMUB0BMUBGBBGB:ABBB QBwBMUBwBaBTdBB%QBmB|aBmB:AB:dAqێB|a@:dBm+B:A|a@yA|aA|aA|aAyAaByAB:ABMUByBm+BBjwBBqێByBaBBBBBqێBaBwBMUBy>B|aAmB!BBHBmBGBBGBy>BBMUByByAB|aATdB|aAm+ByA|aAMUB|a@y>B:dBqێB|a@B|aAmBm+BmBTdBBBqێByB:dBBy>BB|aA:dmBB%QB|aAy>B|a@%QBTdB|a@%QB|aA|aAm+ByBm+BTdB|a@%QBy>B|a@%QB|aATdB|a@TdB|a%QB:dy>B|a QBmB QB|aAm+ByBm+B%QBqێB%QB:dAoATdBaB:AaBTdBoA:AqBB4BJ B0 [ByBGBaB_B%QB_BMUBGB|aA0 [B|a4ByqBMU_BB_nBJ BHByB!BaBqB%QBqBMUB!B|aAHB|a_nBy_BMU%QBB%QBZUBBTdBBwByBZUBBZUBmBwBB%QBqێB:AwB:dA QB|a@m+ByA:dA|a@|aA|aA|a@|aA|a@:A|aA|aB:dAm+By>BwB QBZUBTdBaBTdBmB QByBm+BBMUByB:AmB:AaBMUBwBm+By>BZUB:dAaB|a@mByBB|a@B|aAyBB|aAMUBBm+BBm+BB|aBqێB:AZUB|aAZUB|aAaB|aAmB:dAyByABMUBBm+ByB:dBBqێBBmByByBBaBMUBZUB:AwB|aAwB|aAqێBBB|a@yB:dAyByAmBMUBaBMUBm+BBm+B|ajwBBjwB|amBmBaByBjwBBm+BB:AyB|aAmB|aAaByAZUB:AwB|aBTdBMUBy>BaBm+BB|aBmB:AmB:dAaB|a@jwBm+B:A|a@|aA:dA0 [BBmAMU³BBHBMUmATdB0BTdBgUA:AB:AgUBBgUBZUBqێBBqێBZUB%QBB%QBMUB%QB|aAy>B|a@%QBTdB|a@%QB|aAa`_^]\[ZYXWVUTSRxQpPhO`NXMPLHK@J8I0H(G FEDCBA@?>=<;:98765432x1p0h/`.X-P,H+@*8)0((' &%$#"! xph`X P H @ 8 0( }|{zxyhxXwHv8u(tsrqponmlkjxihhXgHf8e(dcba`_^]\[ZxYhXXWHV8U(TSRQPONMLKJxIhHXGHF8E(DCB A @ ? > = < ; :x 9h 8X 7H 68 5( 4 3 2 1 0 / . - , + *x )h (X 'H &8 %( $ # " !       x h X H 8 (           x h X H 8 (           x h X H 8 (   xhXH8(xhXH8(xhXH8(xhXH8(xhXH8(xhXH8(xhXH8(~}|{zxyhxXwHv8u(tsrqponmlkjxihhXgHf8e(dcb(02@<PF`PpZdnx 0@P`p",6@JT^ h0r@|P`p 0@P&`0p:DNXblv 0@P`p(3 > I T0 _@ jP u` p            @9(p4@@LXdp|p`P@0  $0<`H@T0`lx`P0p`P  ,8D`P@\htpP0pP@  ( 4 A N [` h@ u     p ` @       +P 80 E R _ l yp P 0 P0   , p: H V d r  0 @ P ` p       0( @6 D R `  n |       @     $ 2  @ PN `\ pj x  `   0! @! !  " 0" " "  # 0#' P#4 #A #N #[ #h #u # # # $ $  $ 0$ @$ P$ `$ $ $ $ $+ $8 $E $R $_ %l %y `% p% %  & 0& & & @' P' `' '`(p("(/(<(I(V(c(p(}()) )p)))))P*`* p**&*3*@*M*Z*g*t@+++0,,,,,,-.0.P.`.*p.7.D.Q/^0/k`/x 01 10112220333P4`4!4.4;4H4U5b5o 5|055556777788 88%828?8L9Y9_glutStrokeMonoRomanL_.str__ZL5chars__ZL4ch32__ZL4ch33__ZL4ch34__ZL4ch35__ZL4ch36__ZL4ch37__ZL4ch38__ZL4ch39__ZL4ch40__ZL4ch41__ZL4ch42__ZL4ch43__ZL4ch44__ZL4ch45__ZL4ch46__ZL4ch47__ZL4ch48__ZL4ch49__ZL4ch50__ZL4ch51__ZL4ch52__ZL4ch53__ZL4ch54__ZL4ch55__ZL4ch56__ZL4ch57__ZL4ch58__ZL4ch59__ZL4ch60__ZL4ch61__ZL4ch62__ZL4ch63__ZL4ch64__ZL4ch65__ZL4ch66__ZL4ch67__ZL4ch68__ZL4ch69__ZL4ch70__ZL4ch71__ZL4ch72__ZL4ch73__ZL4ch74__ZL4ch75__ZL4ch76__ZL4ch77__ZL4ch78__ZL4ch79__ZL4ch80__ZL4ch81__ZL4ch82__ZL4ch83__ZL4ch84__ZL4ch85__ZL4ch86__ZL4ch87__ZL4ch88__ZL4ch89__ZL4ch90__ZL4ch91__ZL4ch92__ZL4ch93__ZL4ch94__ZL4ch95__ZL4ch96__ZL4ch97__ZL4ch98__ZL4ch99__ZL5ch100__ZL5ch101__ZL5ch102__ZL5ch103__ZL5ch104__ZL5ch105__ZL5ch106__ZL5ch107__ZL5ch108__ZL5ch109__ZL5ch110__ZL5ch111__ZL5ch112__ZL5ch113__ZL5ch114__ZL5ch115__ZL5ch116__ZL5ch117__ZL5ch118__ZL5ch119__ZL5ch120__ZL5ch121__ZL5ch122__ZL5ch123__ZL5ch124__ZL5ch125__ZL5ch126__ZL5ch127__ZL6ch32st__ZL6ch33st__ZL6ch34st__ZL6ch35st__ZL6ch36st__ZL6ch37st__ZL6ch38st__ZL6ch39st__ZL6ch40st__ZL6ch41st__ZL6ch42st__ZL6ch43st__ZL6ch44st__ZL6ch45st__ZL6ch46st__ZL6ch47st__ZL6ch48st__ZL6ch49st__ZL6ch50st__ZL6ch51st__ZL6ch52st__ZL6ch53st__ZL6ch54st__ZL6ch55st__ZL6ch56st__ZL6ch57st__ZL6ch58st__ZL6ch59st__ZL6ch60st__ZL6ch61st__ZL6ch62st__ZL6ch63st__ZL6ch64st__ZL6ch65st__ZL6ch66st__ZL6ch67st__ZL6ch68st__ZL6ch69st__ZL6ch70st__ZL6ch71st__ZL6ch72st__ZL6ch73st__ZL6ch74st__ZL6ch75st__ZL6ch76st__ZL6ch77st__ZL6ch78st__ZL6ch79st__ZL6ch80st__ZL6ch81st__ZL6ch82st__ZL6ch83st__ZL6ch84st__ZL6ch85st__ZL6ch86st__ZL6ch87st__ZL6ch88st__ZL6ch89st__ZL6ch90st__ZL6ch91st__ZL6ch92st__ZL6ch93st__ZL6ch94st__ZL6ch95st__ZL6ch96st__ZL6ch97st__ZL6ch98st__ZL6ch99st__ZL7ch100st__ZL7ch101st__ZL7ch102st__ZL7ch103st__ZL7ch104st__ZL7ch105st__ZL7ch106st__ZL7ch107st__ZL7ch108st__ZL7ch109st__ZL7ch110st__ZL7ch111st__ZL7ch112st__ZL7ch113st__ZL7ch114st__ZL7ch115st__ZL7ch116st__ZL7ch117st__ZL7ch118st__ZL7ch119st__ZL7ch120st__ZL7ch121st__ZL7ch122st__ZL7ch123st__ZL7ch124st__ZL7ch125st__ZL7ch126st__ZL7ch127st__ZL8ch127st0__ZL8ch127st1__ZL8ch126st0__ZL8ch126st1__ZL8ch125st0__ZL8ch125st1__ZL8ch125st2__ZL8ch124st0__ZL8ch123st0__ZL8ch123st1__ZL8ch123st2__ZL8ch122st0__ZL8ch122st1__ZL8ch122st2__ZL8ch121st0__ZL8ch121st1__ZL8ch120st0__ZL8ch120st1__ZL8ch119st0__ZL8ch119st1__ZL8ch119st2__ZL8ch119st3__ZL8ch118st0__ZL8ch118st1__ZL8ch117st0__ZL8ch117st1__ZL8ch116st0__ZL8ch116st1__ZL8ch115st0__ZL8ch114st0__ZL8ch114st1__ZL8ch113st0__ZL8ch113st1__ZL8ch112st0__ZL8ch112st1__ZL8ch111st0__ZL8ch110st0__ZL8ch110st1__ZL8ch109st0__ZL8ch109st1__ZL8ch109st2__ZL8ch108st0__ZL8ch107st0__ZL8ch107st1__ZL8ch107st2__ZL8ch106st0__ZL8ch106st1__ZL8ch105st0__ZL8ch105st1__ZL8ch104st0__ZL8ch104st1__ZL8ch103st0__ZL8ch103st1__ZL8ch102st0__ZL8ch102st1__ZL8ch101st0__ZL8ch100st0__ZL8ch100st1__ZL7ch99st0__ZL7ch98st0__ZL7ch98st1__ZL7ch97st0__ZL7ch97st1__ZL7ch96st0__ZL7ch96st1__ZL7ch95st0__ZL7ch94st0__ZL7ch94st1__ZL7ch93st0__ZL7ch93st1__ZL7ch93st2__ZL7ch93st3__ZL7ch92st0__ZL7ch91st0__ZL7ch91st1__ZL7ch91st2__ZL7ch91st3__ZL7ch90st0__ZL7ch90st1__ZL7ch90st2__ZL7ch89st0__ZL7ch89st1__ZL7ch88st0__ZL7ch88st1__ZL7ch87st0__ZL7ch87st1__ZL7ch87st2__ZL7ch87st3__ZL7ch86st0__ZL7ch86st1__ZL7ch85st0__ZL7ch84st0__ZL7ch84st1__ZL7ch83st0__ZL7ch82st0__ZL7ch82st1__ZL7ch82st2__ZL7ch81st0__ZL7ch81st1__ZL7ch80st0__ZL7ch80st1__ZL7ch79st0__ZL7ch78st0__ZL7ch78st1__ZL7ch78st2__ZL7ch77st0__ZL7ch77st1__ZL7ch77st2__ZL7ch77st3__ZL7ch76st0__ZL7ch76st1__ZL7ch75st0__ZL7ch75st1__ZL7ch75st2__ZL7ch74st0__ZL7ch73st0__ZL7ch72st0__ZL7ch72st1__ZL7ch72st2__ZL7ch71st0__ZL7ch71st1__ZL7ch70st0__ZL7ch70st1__ZL7ch70st2__ZL7ch69st0__ZL7ch69st1__ZL7ch69st2__ZL7ch69st3__ZL7ch68st0__ZL7ch68st1__ZL7ch67st0__ZL7ch66st0__ZL7ch66st1__ZL7ch66st2__ZL7ch65st0__ZL7ch65st1__ZL7ch65st2__ZL7ch64st0__ZL7ch64st1__ZL7ch63st0__ZL7ch63st1__ZL7ch62st0__ZL7ch61st0__ZL7ch61st1__ZL7ch60st0__ZL7ch59st0__ZL7ch59st1__ZL7ch58st0__ZL7ch58st1__ZL7ch57st0__ZL7ch56st0__ZL7ch55st0__ZL7ch55st1__ZL7ch54st0__ZL7ch53st0__ZL7ch52st0__ZL7ch52st1__ZL7ch51st0__ZL7ch50st0__ZL7ch49st0__ZL7ch48st0__ZL7ch47st0__ZL7ch46st0__ZL7ch45st0__ZL7ch44st0__ZL7ch43st0__ZL7ch43st1__ZL7ch42st0__ZL7ch42st1__ZL7ch42st2__ZL7ch41st0__ZL7ch40st0__ZL7ch39st0__ZL7ch38st0__ZL7ch37st0__ZL7ch37st1__ZL7ch37st2__ZL7ch36st0__ZL7ch36st1__ZL7ch36st2__ZL7ch35st0__ZL7ch35st1__ZL7ch35st2__ZL7ch35st3__ZL7ch34st0__ZL7ch34st1__ZL7ch33st0__ZL7ch33st1#1/28 1415124499 502 80 100644 29204 ` freeglut_stroke_roman.o@ P9`P9__text__TEXT`__cstring__TEXT`__data__DATAp;b__const__DATA0>__const__TEXT`#PG_d P~~RomanaC%BAMB*BiB &BBYAvBmB4BA BA6B'"BBKBBSVB_BBtBZUB-!BXA/nA8B4B8BIΓBǺB#B@B*BʒB^BV}BBd,BffAoBEBSBkBB7BZUBV.BBEBB1B8B7 BBMBO~Bt8BiB9BvBB$B4BB؉BB BB?B BABzBRABÍBV}BB]|BEBHyBBBoRB_irB#BaB-!BHwB&Bq=A%BqBZUB           " %QBB:dAMU:AZUB:dAwB|a@%QB|aByA|a@:dA:dA|a@:A|aB%QB|a@wB:dAZUB:AZUBm+BwB%QB%QBwB|aBZUB:AZUBH:@:AH:@|aB @%QBFATdBATdBaB%QB94]B|aBLBMUB|BMUBB|aBDBy>BH:@|aB @y>BFA%QBA%QBaBy>B94]BMUBLB:A|B:ABMUBDBy>BDBTdBHABbAoBAJ B AB ABABbAaB_AZUB_ATdBAy>BbAoBA%BAyBbAmB_ABHAqێBHAwB_A%QB?Bm+B_AMUBHAyAHA:dA_A|a@bAA|aA|abA:A|aB_A:A_A|aAbA|aAA|a@ A|a A:dAybA:HAMUף8ABף8AMUAB[SAoB:AJ B9EBAB9EBAB:AB[SAaBkAZUBkATdB:Ay>B[SAoB:A%B:AyB[SAmBkABAqێBAwBkA%QB(@m+BkAMUBAyAA:dAkA|a@[SA:A|a:A|a[SA::A|aBkA:AkA|aA[SA|aA:A|a@9EBA|a9EBA:d:Ay[SA:AMU´HcBZUB{@{@ZUBHcBZUB{@HcB@ZUB B~BZUB BBA|aA:@MUff?MUz?ZUB)XB)XBZUBz? @ZUB|aA|a"BZUB|aA|a"BZUBTnBaBZUBTnBff?ZUBAkBZUBA)\AZUB)\A|aAcA|a@2A' B8>B|a@/]wB|aA/]wBZUB/]wB6mAB6mA|aAhA|a@&ArBq= ?ZUBB~BZUBRdB%QBFQBwB"BZUBAZUBcAwBff@%QBcAm+BA|aBI.+BMUBFQB:ARdB|aARdB:dAFQB|a@"BAcA|a@ff@:dA)\AZUB)\A)\A|aBcA%QB2AwBBZUB8>BZUB}wBZUB}wBMU}wB%QBQBwB+BZUB-2AZUBoAwBbA%QBH@|aBH@:AbA:dAoA|a@-2A+BQB|a@}wB:dA)\AZUB)\AMU)\A%QBޗAwBAZUBW,+BZUBDQBwB/]wB%QB4B|aB4B:A/]wB:dADQB|a@W,+BAޗA|a@)\A:dAPAZUB' AwBA%QB)\@|aB)\@:AA:dA' A|a@PAM,B`eRB|a@}xB:dAŅB:AŅB|aB}xB%QB`eRBwBM,BZUBPAZUBHAZUBHAHAy>BAwB?BZUB=BZUB-2cBwBw>vBy>Bw>vBAZUBAAy>BAwBTBZUB>BZUBBdBwBwBy>BwBwBy>BBwBBZUB&BZUB33BwBXBy>BXBQ ABQ AABABdBZUBA|aAI.A|aBwBAB-2AyBJAB-2A%BAB-2AZUB-2A:dA:@@MUzԿMUQ ABlAyBYABlA%BQ ABlAZUBlAABAAy>BAwBTBZUB>BZUBBdBwBwBy>BwBzBZUBzB|afBySB: -BMU#[AMUe*A:zB%QBSBwB -BZUB#[AZUBe*AwBM!A%QB@|aB@:AM!A:dAe*A|a@#[A -BSB|a@zB:dABBAB ҝAyBsoABsoA{.?ZUB BZUB= @|aBs{B|aBs{By>BmghBTdB#[UBwBB/BZUBjB*IBm+BBϋB|aBZUB:AZUB:dA*IB|a@mKByA0A|a@A:dAH:ABH:AH:AB%ZBBSByBk+BBBBBqێBk+BwBSBTdB%ZB%QBH:A%QB 4B%QBBP|BBAyBI.mAmB AaB@wB@|aB AyAI.mA:dAA|a@P|BSByB|a@B:dA uByA#B|aB#BwB uBaBBmByByBSBBP|BBߠ@B|aA uB|aAABAAAAB[BB]|ByBuBBBBBZUBuBTdB]|B%QB[By>BAAy>B> BBMAyB8|AmB0AaB@wB@|aB0AyA8|A:dAMA|a@> BoWB}B|a@;БB:dASVByAjܤB|aBjܤBwBSVBaB;БBmB}ByBoWBB> BBq=2ABq=2Aq=2ABBBBB-AB-A-AB CBBB CBBBBH:ABH:AH:ASBz4ABz4ABBz4AMUB[ BTdBByHBByHByAm5B|aA|a"B|a@:A|aA|a@A|a@|a@|aA @yA @MUB-AB-AR6ABR6Ad,BBd,BR6A%QBd,B%QB*BaBtBmBgByBLZBBBB]AyBAmB&=AaB@wB@|aB&=AyAA:dA]A|a@BLZBgB|a@tB:dA*ByA*B|aBLZB|aB*B|aBR6ABR6AR6ABLBBR6A%QBFB%QBR6ABR6AR6ABLBBR6A%QBFB%QBR6ALB)\?AB)\?A)\?ABW,5BBPnByB4BmBǺBaB@BwB@B|aBǺByA4B:dAPnB|a@W,5B)\?A]-BaBEBmB+6ByBYBB BB*AyBlxAmB6AaB@wB@|aB6AyAlxA:dA*A|a@ BYB+6B|a@EB:dA]-ByAR6ABR6AR6ABYBB4 ByBLBBd,BBd,BqێBLBwB4 BTdBYB%QBR6A%QBYB%QB4 By>BLBm+Bd,BMUBd,B|aALB|aA4 B|a@YBR6A|a"BB @|a"BBaBIAMUBBπBMUBODB%QBBTdB#[ATdBBAy>BBAm+B#[AMUBBMUBODB|aBODBTdBODB|aBWBMUB~BMUBBm+BBy>B~BwBWBqێBBaB BaBe*AqێBM1AwB@y>B@m+BM1A:Ae*A|aA B:dAB:dAWB|aARAaBRABRAB猏AyBAB:BB'`ByB94sBB4 BB4 BqێB94sBwB'`BTdB2By>B2BMUB2B|aAB|a@2Ba'B|a@2B|aA1@mBBm+B1@ff@TdBԶBTdBff@:AԶB:ABBmB C@m+BBBcOAZUB33AwBcOATdBXʍAwBcOAZUBXʍA|a@cOA33A|a@cOA|aAXʍA|a@XʍA|acOA:d33A|avOaAZUBAwBvOaATdBAwBvOaAZUBvOaA|aAA|a@vOaAA|a@vOaA|aAuBZUB~B%QBBXBm+BB|aB B|aBAm+BX5A%QB33@ZUB33@qێBX5AmBAyB BBBBBXByB~BmBuBZUBuBm+B~B|aABXB|a@BFAA|a@X5A:dAFABqAyBX%AmBX%AaBqAZUBI.AwB.BTdBgB%QBuBm+BBMUBB|aAuB|aAzB|a@ABFAqA|a@X%A|aA33@|aA33@MUBX%Am+BA%QBBTdBBTBwBzBZUBuBaBuBmBzByBABBFABtBB]A@BtBB@zBmBgByBh.BB BBAyBlx%AB\@TdB\@MUBlx%A:dAA|a@ B8BTB|a@@zB:dA8B:A8BMUB@zBy>BTBTdB8BwB BwBATdBlx%Ay>B\@MUBxBB $fABMATdB $fAwB#[AZUB +BZUBdBwBB%QB B|aB B:AB:dAdB|a@ +B#[A $fA|a@MA|aA@|aAMBBQx@MUBBMUBMBBMB|ahABBυBBMUBwByRBwBTxBTdBBυB%QBZUB|aBZUB:ABυB:dA%eB|a@|a,ByA|ahA|a@0A|aA@|aA"AaB"ABoABFAyBABABB94gByBi@zBBLBBLBqێBi@zBwB'TBy>Bp@d,B=ABAmBBBB4BB' AyBAB)\@TdB)\@m+BA|aA' A|a@4BM,BqeB|a@ŅB|aAKBm+BKBTdBŅBBqeByBM,BB4BB@:d;ГBBbQA|aApA|a@bQAA|a@bQA|aA(@m+BH0Bm+B9EA|a@YXA( A|a@YXA|aA9EA|a@9EA|aYXA:d( A|a1YCBmB1YCB)\@m+B{cBm+B'AqێB'A:dAR@TdBPZB:APZBTdBR@:A@B]lAJ BAyBgBaBtB%QBtBMUBgB|aAA|a]lAy@MU8#BBAJ BAyBlxEAaB\@%QB\@MUBlxEA|aAA|aAy8#BMU{@B{@ZUBoBTdBoBwBBZUB{cBZUBdݭBwBLWB%QBKB:A}|B:dA`eVB|a@M0B8AxA|a@+A|aA)\@|aA)\@:A+A|aBxAm+B1YCBwB`eVBZUBqiBaBqiBmB`eVByBM0BB4 ByBPAmBPAaB4 BwBM0By>BŇB:dA4њB|a@dݭBBoB|a@oB|aA &BB@#[ABBBBB BqێBBAZUB $~AZUB@aB@mBM1AyBe*AB#[ABByBWBBBBByB &BB BMUB~B:AjB|aAjB|aABÓBB|a@ &B:dA &ByABMUB BMUB7 AB7 A|aZ>BBZ>B|a1BmBwByBZ>BB7 AB4eAyBq=@mBq=@aBvOAZUB4eAwBATdBQBy>BwBm+BsB|aB1B:A1B:dAwB|a@Z>B7 A4eA|a@q=@:dAI.%BB@MUBB"BMU@TdBABTdBL@:AB:Aף@Bף@ZUBu(BBu(BZUBCVABCVAMUBCVA|aA A|a@CVA&A|a@CVA|aAa`_^]\[ZYXWVUTSRxQpPhO`NXMPLHK@J8I0H(G FEDCBA@?>=<;:98765432x1p0h/`.X-P,H+@*8)0((' &%$#"! xph`X P H @ 8 0( }|{zxyhxXwHv8u(tsrqponmlkjxihhXgHf8e(dcba`_^]\[ZxYhXXWHV8U(TSRQPONMLKJxIhHXGHF8E(DCB A @ ? > = < ; :x 9h 8X 7H 68 5( 4 3 2 1 0 / . - , + *x )h (X 'H &8 %( $ # " !       x h X H 8 (           x h X H 8 (           x h X H 8 (   xhXH8(xhXH8(xhXH8(xhXH8(xhXH8(xhXH8(xhXH8(~}|{zxyhxXwHv8u(tsrqponmlkjxihhXgHf8e(dcb$0.@8PB`LpV`jt~ 0@P`p (2<FPZ d0n@xP`p 0@P"`,p6@JT^hr| 0@P`p$/ : E P0 [@ fP q` |p            @9 $p0@<HT`lxp`P@0  ,8`D@P0\ht`P0p`P (4@`L@Xdp|pP0pP@   $ 0 = J W` d@ q ~    p ` @       'P 40 A N [ h up P 0 P0  ( p6 D R ` n | 0 @ P ` p       0$ @2 @ N \  j x       @      .  < PJ `X pf t  `   0! @! !  " 0" " "  # 0## P#0 #= #J #W #d #q #~ # # $ $  $ 0$ @$ P$ `$ $ $ $ $' $4 $A $N $[ %h %u `% p% %  & 0& & & @' P' `' '`(p((+(8(E(R(_(l(y()) )p)))))P*`*p**"*/*<*I*V*c*p@+}++0,,,,,,-.0. P.`.&p.3.@.M/Z0/g`/t 01 10112220333P4`44*474D4Q5^5k 5x05555677778888!8.8;8H9U9_glutStrokeRomanL_.str__ZL5chars__ZL4ch32__ZL4ch33__ZL4ch34__ZL4ch35__ZL4ch36__ZL4ch37__ZL4ch38__ZL4ch39__ZL4ch40__ZL4ch41__ZL4ch42__ZL4ch43__ZL4ch44__ZL4ch45__ZL4ch46__ZL4ch47__ZL4ch48__ZL4ch49__ZL4ch50__ZL4ch51__ZL4ch52__ZL4ch53__ZL4ch54__ZL4ch55__ZL4ch56__ZL4ch57__ZL4ch58__ZL4ch59__ZL4ch60__ZL4ch61__ZL4ch62__ZL4ch63__ZL4ch64__ZL4ch65__ZL4ch66__ZL4ch67__ZL4ch68__ZL4ch69__ZL4ch70__ZL4ch71__ZL4ch72__ZL4ch73__ZL4ch74__ZL4ch75__ZL4ch76__ZL4ch77__ZL4ch78__ZL4ch79__ZL4ch80__ZL4ch81__ZL4ch82__ZL4ch83__ZL4ch84__ZL4ch85__ZL4ch86__ZL4ch87__ZL4ch88__ZL4ch89__ZL4ch90__ZL4ch91__ZL4ch92__ZL4ch93__ZL4ch94__ZL4ch95__ZL4ch96__ZL4ch97__ZL4ch98__ZL4ch99__ZL5ch100__ZL5ch101__ZL5ch102__ZL5ch103__ZL5ch104__ZL5ch105__ZL5ch106__ZL5ch107__ZL5ch108__ZL5ch109__ZL5ch110__ZL5ch111__ZL5ch112__ZL5ch113__ZL5ch114__ZL5ch115__ZL5ch116__ZL5ch117__ZL5ch118__ZL5ch119__ZL5ch120__ZL5ch121__ZL5ch122__ZL5ch123__ZL5ch124__ZL5ch125__ZL5ch126__ZL5ch127__ZL6ch32st__ZL6ch33st__ZL6ch34st__ZL6ch35st__ZL6ch36st__ZL6ch37st__ZL6ch38st__ZL6ch39st__ZL6ch40st__ZL6ch41st__ZL6ch42st__ZL6ch43st__ZL6ch44st__ZL6ch45st__ZL6ch46st__ZL6ch47st__ZL6ch48st__ZL6ch49st__ZL6ch50st__ZL6ch51st__ZL6ch52st__ZL6ch53st__ZL6ch54st__ZL6ch55st__ZL6ch56st__ZL6ch57st__ZL6ch58st__ZL6ch59st__ZL6ch60st__ZL6ch61st__ZL6ch62st__ZL6ch63st__ZL6ch64st__ZL6ch65st__ZL6ch66st__ZL6ch67st__ZL6ch68st__ZL6ch69st__ZL6ch70st__ZL6ch71st__ZL6ch72st__ZL6ch73st__ZL6ch74st__ZL6ch75st__ZL6ch76st__ZL6ch77st__ZL6ch78st__ZL6ch79st__ZL6ch80st__ZL6ch81st__ZL6ch82st__ZL6ch83st__ZL6ch84st__ZL6ch85st__ZL6ch86st__ZL6ch87st__ZL6ch88st__ZL6ch89st__ZL6ch90st__ZL6ch91st__ZL6ch92st__ZL6ch93st__ZL6ch94st__ZL6ch95st__ZL6ch96st__ZL6ch97st__ZL6ch98st__ZL6ch99st__ZL7ch100st__ZL7ch101st__ZL7ch102st__ZL7ch103st__ZL7ch104st__ZL7ch105st__ZL7ch106st__ZL7ch107st__ZL7ch108st__ZL7ch109st__ZL7ch110st__ZL7ch111st__ZL7ch112st__ZL7ch113st__ZL7ch114st__ZL7ch115st__ZL7ch116st__ZL7ch117st__ZL7ch118st__ZL7ch119st__ZL7ch120st__ZL7ch121st__ZL7ch122st__ZL7ch123st__ZL7ch124st__ZL7ch125st__ZL7ch126st__ZL7ch127st__ZL8ch127st0__ZL8ch127st1__ZL8ch126st0__ZL8ch126st1__ZL8ch125st0__ZL8ch125st1__ZL8ch125st2__ZL8ch124st0__ZL8ch123st0__ZL8ch123st1__ZL8ch123st2__ZL8ch122st0__ZL8ch122st1__ZL8ch122st2__ZL8ch121st0__ZL8ch121st1__ZL8ch120st0__ZL8ch120st1__ZL8ch119st0__ZL8ch119st1__ZL8ch119st2__ZL8ch119st3__ZL8ch118st0__ZL8ch118st1__ZL8ch117st0__ZL8ch117st1__ZL8ch116st0__ZL8ch116st1__ZL8ch115st0__ZL8ch114st0__ZL8ch114st1__ZL8ch113st0__ZL8ch113st1__ZL8ch112st0__ZL8ch112st1__ZL8ch111st0__ZL8ch110st0__ZL8ch110st1__ZL8ch109st0__ZL8ch109st1__ZL8ch109st2__ZL8ch108st0__ZL8ch107st0__ZL8ch107st1__ZL8ch107st2__ZL8ch106st0__ZL8ch106st1__ZL8ch105st0__ZL8ch105st1__ZL8ch104st0__ZL8ch104st1__ZL8ch103st0__ZL8ch103st1__ZL8ch102st0__ZL8ch102st1__ZL8ch101st0__ZL8ch100st0__ZL8ch100st1__ZL7ch99st0__ZL7ch98st0__ZL7ch98st1__ZL7ch97st0__ZL7ch97st1__ZL7ch96st0__ZL7ch96st1__ZL7ch95st0__ZL7ch94st0__ZL7ch94st1__ZL7ch93st0__ZL7ch93st1__ZL7ch93st2__ZL7ch93st3__ZL7ch92st0__ZL7ch91st0__ZL7ch91st1__ZL7ch91st2__ZL7ch91st3__ZL7ch90st0__ZL7ch90st1__ZL7ch90st2__ZL7ch89st0__ZL7ch89st1__ZL7ch88st0__ZL7ch88st1__ZL7ch87st0__ZL7ch87st1__ZL7ch87st2__ZL7ch87st3__ZL7ch86st0__ZL7ch86st1__ZL7ch85st0__ZL7ch84st0__ZL7ch84st1__ZL7ch83st0__ZL7ch82st0__ZL7ch82st1__ZL7ch82st2__ZL7ch81st0__ZL7ch81st1__ZL7ch80st0__ZL7ch80st1__ZL7ch79st0__ZL7ch78st0__ZL7ch78st1__ZL7ch78st2__ZL7ch77st0__ZL7ch77st1__ZL7ch77st2__ZL7ch77st3__ZL7ch76st0__ZL7ch76st1__ZL7ch75st0__ZL7ch75st1__ZL7ch75st2__ZL7ch74st0__ZL7ch73st0__ZL7ch72st0__ZL7ch72st1__ZL7ch72st2__ZL7ch71st0__ZL7ch71st1__ZL7ch70st0__ZL7ch70st1__ZL7ch70st2__ZL7ch69st0__ZL7ch69st1__ZL7ch69st2__ZL7ch69st3__ZL7ch68st0__ZL7ch68st1__ZL7ch67st0__ZL7ch66st0__ZL7ch66st1__ZL7ch66st2__ZL7ch65st0__ZL7ch65st1__ZL7ch65st2__ZL7ch64st0__ZL7ch64st1__ZL7ch63st0__ZL7ch63st1__ZL7ch62st0__ZL7ch61st0__ZL7ch61st1__ZL7ch60st0__ZL7ch59st0__ZL7ch59st1__ZL7ch58st0__ZL7ch58st1__ZL7ch57st0__ZL7ch56st0__ZL7ch55st0__ZL7ch55st1__ZL7ch54st0__ZL7ch53st0__ZL7ch52st0__ZL7ch52st1__ZL7ch51st0__ZL7ch50st0__ZL7ch49st0__ZL7ch48st0__ZL7ch47st0__ZL7ch46st0__ZL7ch45st0__ZL7ch44st0__ZL7ch43st0__ZL7ch43st1__ZL7ch42st0__ZL7ch42st1__ZL7ch42st2__ZL7ch41st0__ZL7ch40st0__ZL7ch39st0__ZL7ch38st0__ZL7ch37st0__ZL7ch37st1__ZL7ch37st2__ZL7ch36st0__ZL7ch36st1__ZL7ch36st2__ZL7ch35st0__ZL7ch35st1__ZL7ch35st2__ZL7ch35st3__ZL7ch34st0__ZL7ch34st1__ZL7ch33st0__ZL7ch33st1 #1/28 1415124499 502 80 100644 6884 ` freeglut_teapot.o (__text__TEXT)__literal8__TEXT __const__TEXT0x__data__DATA@`__compact_unwind__LD`__eh_frame__TEXTP hh` P UH ]UHAWAVAUATSHHHHEп   WfWYsf(f(ffWfWE1L-OE1NN E1K<[KRHLPKLHHHLL)Hc HcH4RITMtMtIDIDIDI1H4fWHH4IItHHH4H4f(uf(fWIKHPH4H4HufWfW HHH4lHHnIIII fWfWҹA (L fWfWҹ A (LPfWfWҋ {(11DDA fWfWҹ A /f(L11DAI fWfWҹ A (LP11DDA fWfWҹ A f(L11DAII kHHH;EuH[A\A]A^A_]UH]p@??fghi   !"#$%&'(````abcdeeeejklmnopqrstuvvvv|zwy{~}x('&%)*+,-./01234567856789:;<=>?@ABCDEFGHIJKLMNOPQRSPQRSTUVWXYZ[\]^_?@?y&1@y&1?ɿ@ɿ@ffffff?@@ffffff?+@@+?ffffff@@ffffff@@?@@?(\@@(\?@@@@?333333@?zG333333@zG?333333@333333@???\(\?\(\???@?@Q񿚙?Q???@?@Q?Q????@?@Q?Q??????zG?zG????333333??zG333333?zG?333333?333333?333333@333333ӿ333333@333333ӿ@@ffffff333333@ffffff333333ӿ333333@333333ӿ@@333333@333333ӿ333333@333333ӿ@@?333333ӿ?333333ӿ??333333?333333ӿ333333?333333ӿ???333333ӿ?333333333333ӿ?333333?333333ӿ?ffffff333333ӿ333333?ffffff333333?333333??333333?Q?333333?Q333333?333333?333333?@?@Q?@Qffffff?@ffffff?ffffff@@ffffff@п@333333@п333333@333333@333333@@333333@@п333333@ffffff @п333333@ffffff @333333@ffffff@@ffffff@п@333333 @п33333@333333 @33333@333333@@333333@333333ÿ@ @333333ÿ@ @@ffffff@333333@ffffff@333333ÿ333333@ @333333ÿ333333@ @333333@333333 @?333333 @?ܿ333333 @?333333 @333333 @@ffffff?333333@ffffff?J +333333@J +?ffffff333333@ffffff333333@?ffffff@?y&1̿ffffff@y&1?ٿffffff@ٿffffff@?ffffff@?Kffffff@K?ffffff@ffffff@?333333@?K333333@K?333333@333333@?K7?333333??K7?333333??zG333333?zG?333333?????XzRx $AC ,D|AC P$t4AC  - - =-- --g -I-: -- ---rH-C9---}-x -n -d -Z -P-? =-@ &@5>PHh7r{)AOZd__Z14glutWireTeapotd___stack_chk_guard_glPushAttrib_glEnable_glPushMatrix_glRotated_glScaled_glTranslated_glMap2d_glMapGrid2d_glEvalMesh2_glPopMatrix_glPopAttrib___stack_chk_fail__Z15glutSolidTeapotd__Z14glutWireTeapotd.eh__Z15glutSolidTeapotd.eh__ZL9fghTeapotidj__ZL6cpdata__ZL9patchdata__ZL3texEH_frame0__ZL9fghTeapotidj.eh#1/20 1415124500 502 80 100644 11828 ` gl_draw.o@ 8`(__text__TEXT `__literal4__TEXT __bss__DATA(__compact_unwind__LD __eh_frame__TEXTH ht(% P8=7UHHH8H]UHHH8H]UH]UHAHHH:HHHD]UHH H9HH]UHAVSL5I>HΉIHH[A^]UHAWAVAUATSPHH8HE111HHKHHHtbLE1HÃ0t@I;$HuI$IE0L;HHMLu HHIuIIrH[A\A]A^A_]UHAWAVAUATSPAIL%Mu@IHdID$ID$d I$L%A|$uBE1A|$~'1I4$LL%I A;\$|AD$L%LLDuLLDL%LH[A\A]A^A_]UHAVSAH׉HD[A^]UHAVSAHHD[A^]UHSPHH߉H[]UHAWAVATSAAHIDDHD[A\A^A_]UHAVSHMEHIEMHDH[A^]UHH DHH$D$HD$H ]UHAVSAHى׉HD[A^]UH]UHAWAVAUATSPAωAAy A܉؉Ey EDAǿF,#B\#G|>DDDDDDDDH[A\A]A^A_]UHHHuHUHMUu}H]UHAWAVAUATSPDDEAAAIEuAę DDЁDuMH[A\A]A^A_]UHSPHsC CCHc HH[]UHSPHsC CCHc HH[]UH]UHAWAVSPIA~~;E11IH|HtA~tI6H޿H AE;~|I>H[A^A_]UHAWAVATSHAIL%I$HEHuԿ *@(*P, ?(^^,#YYWHu EMZHH8HW*\WZpIcIH*Dx*Dh`q P I4WWI*LWhXpWZpI*D*LxXZpI*DW}I*DXEEL@ LL LH HZEZMZUHLLLLHI$H;EuHĀ[A\A^A_]UHAWAVAUATSHHAIIHHHEAG AA_ A;_~A_HcM'HI|Ht A_ M'AFHcHcHID IcG IHH|IcLHIcG IHHDIcG IHDIcG IHDIcG IHH|HtHT1LmIIc_ LuM7HADHcIctIMIDILL5IHUHc0HcLc$LMILL-IEH HHu MY,MY,YE,I}LAIcG IH\I}H)I}H1HuHUAPpIcG IH4(&(&IcG IHLDDLd$D$$E1I>HEILHIcO IHHD AG H H H;MuHH[A\A]A^A_]UHAWAVAUATSHHuDgEx\HLcHHEHALkH}LLuC|=u HEH9tAH E9|ADH[A\A]A^A_]UHSPHHu=HHdHCHCd HHCH[]UHAVSAHHtHHHDsC CCIc HH[A^]UHH=t ]]@?C0 :'a8!X}Xg%!!!: B!G4{'!XG0wxX8(8` jaaZ & X( X Y h!w zRx $AC $DAC $lx AC $Z'AC $YAC $P8AC C, `AC J,<AC J$l%AC C$!AC C$AC B,:AC G$BAC G$<4AC $d'AC C$AC ,AC J$0AC , xAC J$<h8AC B$dx8AC B$ AC $jaAC F,ZAC N, AC M,<AC M$lYAC B$/hAC C$oAC  - -~ mn d K-; H-1 G-) ;-   K- H- u q-T # I- J=  O- @- a- j- k-u k-a Q-I c-  \-  N= ?- =-h M=F K- >- A- r- p-~ O-C J=" I- e-o-]-[-[-m_-eb-`_-Vb-Qa-LY-Gm-2i-!m-i-m-i-m-i-P-}Q-mV-cX-YR-JX-@V-6c-N=\-l-umh-hQ<F-*F-%^- d-_-^- d-_-]-J=O-U-O-f;-RK-K-W-g-`-mS-\E-CY-0n-%n-n-n-n-P-A--g-qB-WC-0f-s--g-s--s--f--yg-c3-KD1-1/-#Z-K-H-HG-@D-5T-L=N=N=jN=GN=6C-N=N=`@ `@ `@ `@ (0{H$GwPw u Uh 5(PX}Mu(g` Gt(xG (50U:fa`( :& Pf 9-(VG`sajN_E{OB-8x^@/l`__Z9gl_heightv_fl_graphics_driver__Z10gl_descentv__Z8gl_widthPKc__Z8fl_widthPKc__Z8gl_widthPKci__Z8gl_widthh__Z7gl_fontii__Z27gl_remove_displaylist_fontsv_fl_fonts_glDeleteLists__ZN18Fl_Font_DescriptorD1Ev__ZdlPv__Z7gl_drawPKci__Znwm_calloc_glGenTextures__ZN15gl_texture_fifo13already_knownEPKci__ZN15gl_texture_fifo15compute_textureEPKci__ZN15gl_texture_fifo15display_textureEi__Z7gl_drawPKciii_glRasterPos2i__Z7gl_drawPKciff_glRasterPos2f__Z7gl_drawPKc_strlen__Z7gl_drawPKcii__Z7gl_drawPKcff__Z7gl_drawPKciiiij__Z7fl_drawPKciiiijPFvS0_iiiEP8Fl_Imagei__Z10gl_measurePKcRiS1___Z10fl_measurePKcRiS1_i__Z7gl_rectiiii_glBegin_glVertex2i_glEnd__Z8gl_colorj__ZN2Fl9get_colorEjRhS0_S0__glColor3ub__Z13gl_draw_imagePKhiiiiii_glPixelStorei_glDrawPixels__ZN15gl_texture_fifoC1Ei__ZN15gl_texture_fifoC2Ei__ZN15gl_texture_fifoD1Ev__ZN15gl_texture_fifoD2Ev_free_glDeleteTextures___stack_chk_guard_glGetIntegerv_glMatrixMode_glPushMatrix_glLoadIdentity__ZN9Fl_Window7currentEv_glScalef_glTranslatef_glGetFloatv_glPushAttrib_glDisable_glEnable_glBlendFunc_glBindTexture_glTexCoord2f_glVertex2f_glPopAttrib_glPopMatrix_glGetDoublev_gluUnProject_glRasterPos2d___stack_chk_fail_malloc_memcpy_CGColorSpaceCreateDeviceRGB_fl_gc_CGBitmapContextCreate_CGColorSpaceRelease_glTexParameteri_glTexImage2D_CGContextRelease_memcmp__Z22gl_texture_pile_heightv__Z22gl_texture_pile_heighti__Z16gl_texture_resetv__Z9gl_heightv.eh__Z10gl_descentv.eh__Z8gl_widthPKc.eh__Z8gl_widthPKci.eh__Z8gl_widthh.eh__Z7gl_fontii.eh__Z27gl_remove_displaylist_fontsv.eh__Z7gl_drawPKci.eh__Z7gl_drawPKciii.eh__Z7gl_drawPKciff.eh__Z7gl_drawPKc.eh__Z7gl_drawPKcii.eh__Z7gl_drawPKcff.eh__Z7gl_drawPKciiiij.eh__Z10gl_measurePKcRiS1_.eh__Z7gl_rectiiii.eh__Z8gl_colorj.eh__Z13gl_draw_imagePKhiiiiii.eh__ZN15gl_texture_fifoC1Ei.eh__ZN15gl_texture_fifoC2Ei.eh__ZN15gl_texture_fifoD1Ev.eh__ZN15gl_texture_fifoD2Ev.eh__ZN15gl_texture_fifo15display_textureEi.eh__ZN15gl_texture_fifo15compute_textureEPKci.eh__ZN15gl_texture_fifo13already_knownEPKci.eh__Z22gl_texture_pile_heightv.eh__Z22gl_texture_pile_heighti.eh__Z16gl_texture_resetv.eh__ZL11gl_fontsize__ZL7gl_fifo__ZL14gl_draw_invertPKciiiEH_frame0__ZL14gl_draw_invertPKciii.eh #1/20 1415124500 502 80 100644 2908 ` gl_start.o (X@__text__TEXT)*__literal8__TEXT0__bss__DATA@__data__DATA@__compact_unwind__LDH`@__eh_frame__TEXTX hX , P UHAWAVAUATSHXH=uH51HHH5H;X(u;X,tk@(@, 11* *%v-vWW L=Id9X(D@,I?HHMHL$HMHL$HMH $LM11҉`DmEEEEDeH ILsH}DUMEHEIFHEIFHEHMINII?H]p,M+u)΋U  HX[A\A]A^A_]UH]UHH1Ht H ]?X !zRx ,8AC M$L AC $t!AC  ------- -q-^---=----{-vm-c-^S-NH -@9-4--#-m@ @HPT@ Um^(J@d5__Z8gl_startv__ZN9Fl_Window7currentEv__Z20fl_create_gl_contextP9Fl_WindowPK12Fl_Gl_Choicei__Z17fl_set_gl_contextP9Fl_WindowP15__AGLContextRec_glLoadIdentity_glViewport_glOrtho_glDrawBuffer_fl_graphics_driver_malloc__Z19fl_cgrectmake_cocoaiiii__ZN18Fl_Graphics_Driver11clip_regionEP13flCocoaRegion_glScissor_glEnable_glDisable__Z9gl_finishv_glFlush__ZN2Fl9gl_visualEiPi__ZN12Fl_Gl_Choice4findEiPKi__Z8gl_startv.eh__Z9gl_finishv.eh__ZN2Fl9gl_visualEiPi.eh__ZL7context__ZL9gl_choice__ZL2pw__ZL2ph__ZL17clip_state_numberEH_frame0 #1/28 1415124500 502 80 100644 16732 ` glut_compatability.o h"( __text__TEXT"__textcoal_nt__TEXT __common__DATA( __bss__DATAP`__data__DATA  __const__DATA '__cstring__TEXT__const__TEXT__compact_unwind__LD`(+__eh_frame__TEXT( hX)2D PWk/UHH=Ht]]ÐUHSPHHu{(s,@0H[]UHt]H=]UHSPH=uH{(s,@H߀H[]8UHAWAVAUATSPAIL-ItLAD$ HD;L5AMH HcHIHu IxtLH1HуNHcIc HeIHHtHHt DUKdH H|3A1E1E1HtHHHtxHHt 1DUHHuq1AsIPHtDMÃuADžIhHIhH1IX(IHzIxl{I`HkDuJIHuIxFHHIHH"DUIpH1IpHHy;IPHt1DMuI`˅IPHt1DMIxHtkH BC#CDU2A IPHt1DM IXtH[A\A]A^A_]LDH[A\A]A^A_]f '@IjUHLJHH<tHQIH~HHcH<LJ(LJ$LJ HH@HH0H8LJHLJxHLJpHLJhHLJ`HLJXHLJPHLJH51]UH11ʉ]UH]UHSPHHHHHHHHH[]UHSPHHHHHHHHH[]UHSPHHHHHHHHH[]UHSPHHHHHHHHH[]UHAWAVATSHIHHHHHAHE1Ƀ;y HHIH; |MEAL}HcȍAEI K Iċ;9}LLEuIcIH[A\A^A_]UH=]UH]UH=5]UH=5]UH]UHAWAVSPID=HEtU5 DHMHHHHHHH?5HLHHHHHHHH5tHH HHP(HHtHH[A^A_]UHAWAVAUATSPEAAA}ԿHE1HDDDEHHHHHHHLcuL=K   +9 :s C! G    Xae C L  qPA'e! >   zRx $AC $DGAC B$lAC $;AC B,tAC J$hAC $(AC $<AC $d<AC B$<AC B$<AC B$0<AC B,DAC K$4 AC $\ AC $AC $AC $ AC $d AC F,$\AC J$TAC B$| AC $>AC $ AC $AC $+AC $D:AC $lCAC C,GAC G, AC G$XAC F$CAC $D8LAC $l\AC $qAC B$hAAC $'AC $ eAC J,4AC G$d>AC B$4 AC $ AC $ AC -w--f-S-F-9----=m-jgj------{ p e ZMs-F7,g!x-y-j j j j j -  g  g| l g4 -+  g -B - -  g - m gc E 3 k-# j  -   v-  j j f ^- -| ^-X k-F j( -  N- fo-=--k-jhb-ZOBN-7f0o-!=-    mN-fo-=-   - (-| v i mc ]S}-Gz--pN-_fXo-I=B-4N-#fo- =-N-fo-=-N-fo-=-z-dp-\.t-=:~==hi-izhpg?=8-|={=k-jj~l-xjkYm0m*jk-jxephH`rXFPbH`@n8q0u(P LZ\d@ `@ `@ `@ `@ `@  P  `+ hC ~Z  i hw p x |      "  (  8 `,   P  SM  L6   0  @U  9 G  hs c  re < |  c  H    `M  0p+      h  H9A  Xle  @k  XtW         t  (z   u @V h   !>  ~  ^  8  9r  xs  R  F  _  ! 40?8X@&(3'i &f+">raU74k{__ZN14Fl_Glut_Window12make_currentEv_glut_window__ZN12Fl_Gl_Window12make_currentEv__ZN14Fl_Glut_Window4drawEv__Z15glutSwapBuffersv__ZN12Fl_Gl_Window12swap_buffersEv__ZN14Fl_Glut_Window12draw_overlayEv__ZN14Fl_Glut_Window6handleEi__ZN2Fl3e_xE__ZN2Fl3e_yE__ZN2Fl5focusEP9Fl_Widget__ZN2Fl8e_keysymE_glut_menu_glut_menustate_function_glut_menustatus_function__ZNK12Fl_Menu_Item5popupEiiPKcPKS_PK8Fl_Menu___ZN2Fl6e_textE__ZN2Fl4e_dyE__ZN12Fl_Gl_Window6handleEi__ZN14Fl_Glut_Window5_initEv__ZN12Fl_Gl_Window4modeEiPKi_glViewport__ZN14Fl_Glut_WindowC1EiiPKc__ZN9Fl_WindowC2EiiPKc__ZTV12Fl_Gl_Window__ZN12Fl_Gl_Window4initEv__ZTV14Fl_Glut_Window__ZN14Fl_Glut_WindowC2EiiPKc__ZN14Fl_Glut_WindowC1EiiiiPKc__ZN9Fl_WindowC2EiiiiPKc__ZN14Fl_Glut_WindowC2EiiiiPKc__Z8glutInitPiPPc__Znam__ZN2Fl3argEiPPcRi__Z19glutInitDisplayModej__Z12glutMainLoopv__ZN2Fl3runEv__Z22glutInitWindowPositionii__Z18glutInitWindowSizeii__Z16glutCreateWindowPc__Z16glutCreateWindowPKc__Znwm__ZN9Fl_Window4showEiPPc__Z19glutCreateSubWindowiiiii__ZN8Fl_Group3addER9Fl_Widget__ZN14Fl_Glut_WindowD0Ev__ZN14Fl_Glut_WindowD2Ev__ZdlPv__ZN14Fl_Glut_WindowD1Ev__ZN12Fl_Gl_WindowD2Ev__Z17glutDestroyWindowi__Z23glutPostWindowRedisplayi__ZN9Fl_Widget6redrawEv__Z13glutSetWindowi__Z14glutCreateMenuPFviE__Z15glutDestroyMenui__ZdaPv__Z16glutAddMenuEntryPci__Z14glutAddSubMenuPci__Z21glutChangeToMenuEntryiPci__Z19glutChangeToSubMenuiPci__Z18glutRemoveMenuItemi__Z7glutGetj_glGetIntegerv__ZN2Fl1wEv__ZN2Fl1hEv__ZN12Fl_Gl_Window6can_doEiPKi__Z12glutLayerGetj__ZN12Fl_Gl_Window14can_do_overlayEv__Z13glutDeviceGetj__Z18glutGetProcAddressPKc___stack_chk_guard_snprintf_dlsym___stack_chk_fail__Z22glutExtensionSupportedPKc_strchr_strlen_glGetString_strstr__Z12glutIdleFuncPFvvE__ZN2Fl11remove_idleEPFvPvES0___ZN2Fl8add_idleEPFvPvES0___ZN8Fl_Group8as_groupEv__ZN9Fl_Window9as_windowEv__ZN12Fl_Gl_Window12as_gl_windowEv__ZTI14Fl_Glut_Window__ZN12Fl_Gl_Window6resizeEiiii__ZN12Fl_Gl_Window4showEv__ZN12Fl_Gl_Window4hideEv__ZN12Fl_Gl_Window5flushEv__ZTS14Fl_Glut_Window__ZTVN10__cxxabiv120__si_class_type_infoE__ZTI12Fl_Gl_Window__ZN14Fl_Glut_Window12make_currentEv.eh__ZN14Fl_Glut_Window4drawEv.eh__Z15glutSwapBuffersv.eh__ZN14Fl_Glut_Window12draw_overlayEv.eh__ZN14Fl_Glut_Window6handleEi.eh__ZN14Fl_Glut_Window5_initEv.eh__ZN14Fl_Glut_WindowC1EiiPKc.eh__ZN14Fl_Glut_WindowC2EiiPKc.eh__ZN14Fl_Glut_WindowC1EiiiiPKc.eh__ZN14Fl_Glut_WindowC2EiiiiPKc.eh__Z8glutInitPiPPc.eh__Z19glutInitDisplayModej.eh__Z12glutMainLoopv.eh__Z22glutInitWindowPositionii.eh__Z18glutInitWindowSizeii.eh__Z16glutCreateWindowPc.eh__Z16glutCreateWindowPKc.eh__Z19glutCreateSubWindowiiiii.eh__ZN14Fl_Glut_WindowD0Ev.eh__ZN14Fl_Glut_WindowD1Ev.eh__ZN14Fl_Glut_WindowD2Ev.eh__Z17glutDestroyWindowi.eh__Z23glutPostWindowRedisplayi.eh__Z13glutSetWindowi.eh__Z14glutCreateMenuPFviE.eh__Z15glutDestroyMenui.eh__Z16glutAddMenuEntryPci.eh__Z14glutAddSubMenuPci.eh__Z21glutChangeToMenuEntryiPci.eh__Z19glutChangeToSubMenuiPci.eh__Z18glutRemoveMenuItemi.eh__Z7glutGetj.eh__Z12glutLayerGetj.eh__Z13glutDeviceGetj.eh__Z18glutGetProcAddressPKc.eh__Z22glutExtensionSupportedPKc.eh__Z12glutIdleFuncPFvvE.eh__ZN8Fl_Group8as_groupEv.eh__ZN9Fl_Window9as_windowEv.eh__ZN12Fl_Gl_Window12as_gl_windowEv.eh__ZL6indraw__ZL5menus__ZL7windows__ZL15default_reshapeii__ZL15default_displayv__ZL9glut_mode__ZL8initargc__ZL8initargv__ZL5initx__ZL5inity__ZL7initpos__ZL5initw__ZL5inith__ZL7additemP4menuL_.str__ZL14glut_idle_funcEH_frame0__ZL15default_reshapeii.eh__ZL15default_displayv.eh__ZL7additemP4menu.eh #1/20 1415124499 502 80 100644 4116 ` glut_font.o (__text__TEXT,@ __literal8__TEXT0 __const__TEXTP__data__DATA`8__compact_unwind__LD@H __eh_frame__TEXT hP & L P UHSPw]H}H[]UHw]UHSPHwHX,H[]UHSPHwHH[]UHSPwX,H[]UHAWAVATSx~9w~yHcHOL4MtiA~~JMfE1A<$~ 1ID$LHA;$|AIE;~|AWW[A\A^A_][A\A^A_]UHAWAVAUATSHIHH]MA$WۋKI9}< tHCL!-8-!-- `@ B>u;,?bBZ@rxhq!'hV @#Z h` px+}S__Z19glutBitmapCharacterPvi__Z7gl_fontii__Z7gl_drawPKci__Z16glutBitmapHeightPv__Z9gl_heightv__Z16glutBitmapLengthPvPKh__Z8gl_widthPKc__Z16glutBitmapStringPvPKh__Z7gl_drawPKc__Z15glutBitmapWidthPvi__Z8gl_widthh__Z19glutStrokeCharacterPvi_glBegin_glVertex2f_glEnd_glTranslatef__Z16glutStrokeStringPvPKh__Z15glutStrokeWidthPvi__Z16glutStrokeLengthPvPKh__Z16glutStrokeHeightPv_glutBitmap9By15_glutBitmap8By13_glutBitmapTimesRoman10_glutBitmapTimesRoman24_glutBitmapHelvetica10_glutBitmapHelvetica12_glutBitmapHelvetica18__Z19glutBitmapCharacterPvi.eh__Z16glutBitmapHeightPv.eh__Z16glutBitmapLengthPvPKh.eh__Z16glutBitmapStringPvPKh.eh__Z15glutBitmapWidthPvi.eh__Z19glutStrokeCharacterPvi.eh__Z16glutStrokeStringPvPKh.eh__Z15glutStrokeWidthPvi.eh__Z16glutStrokeLengthPvPKh.eh__Z16glutStrokeHeightPv.ehEH_frame0 eureka-1.11-source/osx/README.rtf0000644000175100017510000000257012647061302015756 0ustar aaptedaapted{\rtf1\mac\ansicpg10000\cocoartf1187\cocoasubrtf340 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \paperw11900\paperh16840\margl1440\margr1440\vieww12600\viewh7800\viewkind0 \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural \f0\b\fs32 \cf0 Eureka Editor - Mac OS X port \b0\fs24 \ \ This is a simple port to OS X of the Eureka Doom editor, originally for Linux, made by Andrew Apted.\ \ \b\fs28 \ul Installing \b0\fs24 \ulnone \ \ Just drag the Eureka Doom Editor (or Eureka Doom Editor.app) file to the Applications folder.\ \ \b\fs28 \ul Maintaining \b0\fs24 \ulnone \ \ Do note that Eureka for Mac stores its data inside \i (home folder)/Library/Application Support \i0 . From Finder, the \i Library \i0 folder may be hidden. Inside it you may look through the various game and mod editing settings and data.\ \ To access it, you need to press COMMAND-SHIFT-G from Finder to show the "Go To\'85" dialog, and type this inside the text field:\ \ \b ~/Library/Application Support/eureka-editor \b0 \ \ Don't worry about the "Library" name being localized (translated), the folder name can be written in English, and Finder will go to the correct location. For quick access to it, you can easily drag the folder icon from the Finder window title to the side bar.\ \ Text file and Mac porting by Ioan Chera.}eureka-1.11-source/osx/TODO.txt0000644000175100017510000000010212647061302015577 0ustar aaptedaapted- add support for opening files from drag-drop even after it's runeureka-1.11-source/osx/EurekaApp/0000755000175100017510000000000012647061302016155 5ustar aaptedaaptedeureka-1.11-source/osx/EurekaApp/AppDelegate.h0000644000175100017510000000233112647061302020500 0ustar aaptedaapted//------------------------------------------------------------------------ // OS X EDITOR APP DELEGATE INTERFACE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 AndrÈ Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // // Module by Ioan Chera // #import @interface AppDelegate : NSObject @end eureka-1.11-source/osx/EurekaApp/OSXCalls.mm0000644000175100017510000000417512647061302020147 0ustar aaptedaapted//------------------------------------------------------------------------ // MAC OS X NATIVE C-STYLE CALLS TO BE ACCESSED FROM THE MAIN PROGRAM //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 AndrÈ Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by RaphaÎl Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // // Module by Ioan Chera // #ifdef __APPLE__ #import "Foundation/Foundation.h" #include "OSXCalls.h" // // OSX_UserDomainDirectory // // Returns the directory where to save configs // const char *OSX_UserDomainDirectory(osx_dirtype dirtype, const char *subdir) { NSSearchPathDirectory spd; switch (dirtype) { case osx_LibDir: spd = NSLibraryDirectory; break; case osx_LibAppSupportDir: spd = NSApplicationSupportDirectory; break; case osx_LibCacheDir: spd = NSCachesDirectory; break; } NSArray *paths = NSSearchPathForDirectoriesInDomains(spd, NSUserDomainMask, YES); if([paths count] <= 0) return "."; // shouldn't normally occur NSString *retDir = [paths objectAtIndex:0]; if(subdir) retDir = [retDir stringByAppendingPathComponent:[NSString stringWithCString:subdir encoding:NSUTF8StringEncoding]]; return [retDir cStringUsingEncoding:NSUTF8StringEncoding]; } #endif eureka-1.11-source/osx/EurekaApp/en.lproj/0000755000175100017510000000000012647061302017704 5ustar aaptedaaptedeureka-1.11-source/osx/EurekaApp/en.lproj/InfoPlist.strings0000644000175100017510000000005512647061302023226 0ustar aaptedaapted/* Localized versions of Info.plist keys */ eureka-1.11-source/osx/EurekaApp/en.lproj/Credits.rtf0000644000175100017510000000106712647061302022022 0ustar aaptedaapted{\rtf1\mac\ansicpg10000\cocoartf1187\cocoasubrtf340 \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \paperw11900\paperh16840\vieww9600\viewh8400\viewkind0 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 \f0\b\fs24 \cf0 Eureka Editor: \b0 \ Andrew Apted\ Andr\'e9 Majorel\ \ See also "About" from the "Help" menu.\ \ Released under the GNU General Public License, version 2.\ You are welcome to modify and redistribute it under certain conditions.\ See GPL.txt for details.}eureka-1.11-source/osx/EurekaApp/en.lproj/MainMenu.xib0000644000175100017510000044770312647061302022140 0ustar aaptedaapted 1050 12C3012 2844 1187.34 625.00 com.apple.InterfaceBuilder.CocoaPlugin 2844 YES NSCustomObject NSMenu NSMenuItem YES com.apple.InterfaceBuilder.CocoaPlugin PluginDependencyRecalculationVersion YES NSApplication FirstResponder NSApplication AMainMenu YES Eureka 1048576 2147483647 NSImage NSMenuCheckmark NSImage NSMenuMixedState submenuAction: Eureka YES About Eureka 2147483647 YES YES 1048576 2147483647 Toggle Full Screen f 1310720 2147483647 YES YES 1048576 2147483647 Services 1048576 2147483647 submenuAction: Services YES _NSServicesMenu YES YES 1048576 2147483647 Hide Eureka h 1048576 2147483647 Hide Others h 1572864 2147483647 Show All 1048576 2147483647 YES YES 1048576 2147483647 Quit Eureka q 1048576 2147483647 _NSAppleMenu File 1048576 2147483647 submenuAction: File YES New n 1048576 2147483647 Open… o 1048576 2147483647 Open Recent 1048576 2147483647 submenuAction: Open Recent YES Clear Menu 1048576 2147483647 _NSRecentDocumentsMenu YES YES 1048576 2147483647 Close w 1048576 2147483647 Save… s 1048576 2147483647 Revert to Saved 2147483647 YES YES 1048576 2147483647 Page Setup... P 1179648 2147483647 Print… p 1048576 2147483647 Edit 1048576 2147483647 submenuAction: Edit YES Undo z 1048576 2147483647 Redo Z 1179648 2147483647 YES YES 1048576 2147483647 Cut x 1048576 2147483647 Copy c 1048576 2147483647 Paste v 1048576 2147483647 Paste and Match Style V 1572864 2147483647 Delete 1048576 2147483647 Select All a 1048576 2147483647 YES YES 1048576 2147483647 Find 1048576 2147483647 submenuAction: Find YES Find… f 1048576 2147483647 1 Find and Replace… f 1572864 2147483647 12 Find Next g 1048576 2147483647 2 Find Previous G 1179648 2147483647 3 Use Selection for Find e 1048576 2147483647 7 Jump to Selection j 1048576 2147483647 Spelling and Grammar 1048576 2147483647 submenuAction: Spelling and Grammar YES Show Spelling and Grammar : 1048576 2147483647 Check Document Now ; 1048576 2147483647 YES YES 2147483647 Check Spelling While Typing 1048576 2147483647 Check Grammar With Spelling 1048576 2147483647 Correct Spelling Automatically 2147483647 Substitutions 1048576 2147483647 submenuAction: Substitutions YES Show Substitutions 2147483647 YES YES 2147483647 Smart Copy/Paste f 1048576 2147483647 1 Smart Quotes g 1048576 2147483647 2 Smart Dashes 2147483647 Smart Links G 1179648 2147483647 3 Text Replacement 2147483647 Transformations 2147483647 submenuAction: Transformations YES Make Upper Case 2147483647 Make Lower Case 2147483647 Capitalize 2147483647 Speech 1048576 2147483647 submenuAction: Speech YES Start Speaking 1048576 2147483647 Stop Speaking 1048576 2147483647 Format 2147483647 submenuAction: Format YES Font 2147483647 submenuAction: Font YES Show Fonts t 1048576 2147483647 Bold b 1048576 2147483647 2 Italic i 1048576 2147483647 1 Underline u 1048576 2147483647 YES YES 2147483647 Bigger + 1048576 2147483647 3 Smaller - 1048576 2147483647 4 YES YES 2147483647 Kern 2147483647 submenuAction: Kern YES Use Default 2147483647 Use None 2147483647 Tighten 2147483647 Loosen 2147483647 Ligatures 2147483647 submenuAction: Ligatures YES Use Default 2147483647 Use None 2147483647 Use All 2147483647 Baseline 2147483647 submenuAction: Baseline YES Use Default 2147483647 Superscript 2147483647 Subscript 2147483647 Raise 2147483647 Lower 2147483647 YES YES 2147483647 Show Colors C 1048576 2147483647 YES YES 2147483647 Copy Style c 1572864 2147483647 Paste Style v 1572864 2147483647 _NSFontMenu Text 2147483647 submenuAction: Text YES Align Left { 1048576 2147483647 Center | 1048576 2147483647 Justify 2147483647 Align Right } 1048576 2147483647 YES YES 2147483647 Writing Direction 2147483647 submenuAction: Writing Direction YES YES Paragraph 2147483647 CURlZmF1bHQ 2147483647 CUxlZnQgdG8gUmlnaHQ 2147483647 CVJpZ2h0IHRvIExlZnQ 2147483647 YES YES 2147483647 YES Selection 2147483647 CURlZmF1bHQ 2147483647 CUxlZnQgdG8gUmlnaHQ 2147483647 CVJpZ2h0IHRvIExlZnQ 2147483647 YES YES 2147483647 Show Ruler 2147483647 Copy Ruler c 1310720 2147483647 Paste Ruler v 1310720 2147483647 View 1048576 2147483647 submenuAction: View YES Show Toolbar t 1572864 2147483647 Customize Toolbar… 1048576 2147483647 Window 1048576 2147483647 submenuAction: Window YES Minimize m 1048576 2147483647 Zoom 1048576 2147483647 YES YES 1048576 2147483647 Bring All to Front 1048576 2147483647 _NSWindowsMenu Help 2147483647 submenuAction: Help YES Eureka Help ? 1048576 2147483647 _NSHelpMenu _NSMainMenu NSFontManager AppDelegate EUExtraInterface YES terminate: 449 orderFrontStandardAboutPanel: 142 delegate 538 performMiniaturize: 37 arrangeInFront: 39 print: 86 runPageLayout: 87 clearRecentDocuments: 127 performClose: 193 toggleContinuousSpellChecking: 222 undo: 223 copy: 224 checkSpelling: 225 paste: 226 stopSpeaking: 227 cut: 228 showGuessPanel: 230 redo: 231 selectAll: 232 startSpeaking: 233 delete: 235 performZoom: 240 performFindPanelAction: 241 centerSelectionInVisibleArea: 245 toggleGrammarChecking: 347 toggleSmartInsertDelete: 355 toggleAutomaticQuoteSubstitution: 356 toggleAutomaticLinkDetection: 357 saveDocument: 362 revertDocumentToSaved: 364 runToolbarCustomizationPalette: 365 toggleToolbarShown: 366 hide: 367 hideOtherApplications: 368 unhideAllApplications: 370 newDocument: 373 openDocument: 374 raiseBaseline: 426 lowerBaseline: 427 copyFont: 428 subscript: 429 superscript: 430 tightenKerning: 431 underline: 432 orderFrontColorPanel: 433 useAllLigatures: 434 loosenKerning: 435 pasteFont: 436 unscript: 437 useStandardKerning: 438 useStandardLigatures: 439 turnOffLigatures: 440 turnOffKerning: 441 toggleAutomaticSpellingCorrection: 456 orderFrontSubstitutionsPanel: 458 toggleAutomaticDashSubstitution: 461 toggleAutomaticTextReplacement: 463 uppercaseWord: 464 capitalizeWord: 467 lowercaseWord: 468 pasteAsPlainText: 486 performFindPanelAction: 487 performFindPanelAction: 488 performFindPanelAction: 489 showHelp: 493 alignCenter: 518 pasteRuler: 519 toggleRuler: 520 alignRight: 521 copyRuler: 522 alignJustified: 523 alignLeft: 524 makeBaseWritingDirectionNatural: 525 makeBaseWritingDirectionLeftToRight: 526 makeBaseWritingDirectionRightToLeft: 527 makeTextWritingDirectionNatural: 528 makeTextWritingDirectionLeftToRight: 529 makeTextWritingDirectionRightToLeft: 530 performFindPanelAction: 535 addFontTrait: 421 addFontTrait: 422 modifyFont: 423 orderFrontFontPanel: 424 modifyFont: 425 extraInterface 544 setFullScreen: 546 appDelegate 548 YES 0 YES -2 File's Owner -1 First Responder -3 Application 29 YES 19 YES 56 YES 217 YES 83 YES 81 YES 75 78 72 82 124 YES 77 73 79 112 74 125 YES 126 205 YES 202 198 207 214 199 203 197 206 215 218 YES 216 YES 200 YES 219 201 204 220 YES 213 210 221 208 209 57 YES 58 134 150 136 144 143 236 131 YES 149 145 130 24 YES 92 5 239 23 295 YES 296 YES 297 298 211 YES 212 YES 195 196 346 348 YES 349 YES 350 351 354 375 YES 376 YES 377 YES 388 YES 389 390 391 392 393 394 395 396 397 YES 398 YES 399 YES 400 401 402 403 404 405 YES 406 407 408 409 410 411 YES 412 413 414 415 YES 416 417 418 419 420 450 YES 451 YES 452 453 454 457 459 460 462 465 466 485 490 YES 491 YES 492 496 YES 497 YES 498 499 500 501 502 503 YES 504 505 506 507 508 YES 509 510 511 512 513 514 515 516 517 534 537 541 543 YES YES -1.IBPluginDependency -2.IBPluginDependency -3.IBPluginDependency 112.IBPluginDependency 124.IBPluginDependency 125.IBPluginDependency 126.IBPluginDependency 130.IBPluginDependency 131.IBPluginDependency 134.IBPluginDependency 136.IBPluginDependency 143.IBPluginDependency 144.IBPluginDependency 145.IBPluginDependency 149.IBPluginDependency 150.IBPluginDependency 19.IBPluginDependency 195.IBPluginDependency 196.IBPluginDependency 197.IBPluginDependency 198.IBPluginDependency 199.IBPluginDependency 200.IBPluginDependency 201.IBPluginDependency 202.IBPluginDependency 203.IBPluginDependency 204.IBPluginDependency 205.IBPluginDependency 206.IBPluginDependency 207.IBPluginDependency 208.IBPluginDependency 209.IBPluginDependency 210.IBPluginDependency 211.IBPluginDependency 212.IBPluginDependency 213.IBPluginDependency 214.IBPluginDependency 215.IBPluginDependency 216.IBPluginDependency 217.IBPluginDependency 218.IBPluginDependency 219.IBPluginDependency 220.IBPluginDependency 221.IBPluginDependency 23.IBPluginDependency 236.IBPluginDependency 239.IBPluginDependency 24.IBPluginDependency 29.IBPluginDependency 295.IBPluginDependency 296.IBPluginDependency 297.IBPluginDependency 298.IBPluginDependency 346.IBPluginDependency 348.IBPluginDependency 349.IBPluginDependency 350.IBPluginDependency 351.IBPluginDependency 354.IBPluginDependency 375.IBPluginDependency 376.IBPluginDependency 377.IBPluginDependency 388.IBPluginDependency 389.IBPluginDependency 390.IBPluginDependency 391.IBPluginDependency 392.IBPluginDependency 393.IBPluginDependency 394.IBPluginDependency 395.IBPluginDependency 396.IBPluginDependency 397.IBPluginDependency 398.IBPluginDependency 399.IBPluginDependency 400.IBPluginDependency 401.IBPluginDependency 402.IBPluginDependency 403.IBPluginDependency 404.IBPluginDependency 405.IBPluginDependency 406.IBPluginDependency 407.IBPluginDependency 408.IBPluginDependency 409.IBPluginDependency 410.IBPluginDependency 411.IBPluginDependency 412.IBPluginDependency 413.IBPluginDependency 414.IBPluginDependency 415.IBPluginDependency 416.IBPluginDependency 417.IBPluginDependency 418.IBPluginDependency 419.IBPluginDependency 420.IBPluginDependency 450.IBPluginDependency 451.IBPluginDependency 452.IBPluginDependency 453.IBPluginDependency 454.IBPluginDependency 457.IBPluginDependency 459.IBPluginDependency 460.IBPluginDependency 462.IBPluginDependency 465.IBPluginDependency 466.IBPluginDependency 485.IBPluginDependency 490.IBPluginDependency 491.IBPluginDependency 492.IBPluginDependency 496.IBPluginDependency 497.IBPluginDependency 498.IBPluginDependency 499.IBPluginDependency 5.IBPluginDependency 500.IBPluginDependency 501.IBPluginDependency 502.IBPluginDependency 503.IBPluginDependency 504.IBPluginDependency 505.IBPluginDependency 506.IBPluginDependency 507.IBPluginDependency 508.IBPluginDependency 509.IBPluginDependency 510.IBPluginDependency 511.IBPluginDependency 512.IBPluginDependency 513.IBPluginDependency 514.IBPluginDependency 515.IBPluginDependency 516.IBPluginDependency 517.IBPluginDependency 534.IBPluginDependency 537.IBPluginDependency 541.IBPluginDependency 543.IBPluginDependency 56.IBPluginDependency 57.IBPluginDependency 58.IBPluginDependency 72.IBPluginDependency 73.IBPluginDependency 74.IBPluginDependency 75.IBPluginDependency 77.IBPluginDependency 78.IBPluginDependency 79.IBPluginDependency 81.IBPluginDependency 82.IBPluginDependency 83.IBPluginDependency 92.IBPluginDependency YES com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin YES YES 549 YES AppDelegate NSObject YES YES appMenu extraInterface YES NSMenu EUExtraInterface YES YES appMenu extraInterface YES appMenu NSMenu extraInterface EUExtraInterface IBProjectSource ./Classes/AppDelegate.h EUExtraInterface NSObject YES YES setFullScreen: showPreferences: YES id id YES YES setFullScreen: showPreferences: YES setFullScreen: id showPreferences: id appDelegate AppDelegate appDelegate appDelegate AppDelegate IBProjectSource ./Classes/EUExtraInterface.h 0 IBCocoaFramework com.apple.InterfaceBuilder.CocoaPlugin.macosx com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 YES 3 YES YES NSMenuCheckmark NSMenuMixedState YES {11, 11} {10, 3} eureka-1.11-source/osx/EurekaApp/Eureka Doom EditorIcon.icns0000644000175100017510000010677412647061302023165 0ustar aaptedaaptedicnsTOC it32Mt8mk@it32M6  !!"!! !! !" ""!"#EHҹ=HrURILTJeJJ\_^R?JdJHO409TZENDF?<=CJ^M-,3;7A9VI.CCURC>%1DG0(+ +C,)2<)::ZIQhb^!<',?.((.'###M'B+4#<'!=0'$)-EA()&!-4!#*7@-!/430#PAEI,3K>(5 #F $ 1&G-BG=0$ B0#5E@1*!"&%C/ $/?(!6E ~,P995,+!,07!J  +=  A:+1231-# "%?("'+!,81A  O;P:74!.9!G B)&tkwl[\~ne.%F+4&*'0))* 3@S_C"'>@$'A'1- &<,xH0 *!25Q",$)W"1Ȱ!-&+&J5 #> 4F &.< ;'7C-,- #?E--%#(I5w[ ('@DLn7-:CM^]H5ZW92;Z85Z^0%2B7(=0(/,#+S%+',CD5%!3\eQ A^ⶒÄcmxkC $-60:G+2K#'MK+"@@?\P      -BAA 77++# *CUUR@,HADŽ  /5V. 5H U&#%P,9") TF 6WF(%O#K"$, @6& 4>$;K+gR"GS $'<3;_Y*D= !  !! UQ0') L> "KZM-20"oR$+,*VQ!V(1+]C+,561$!&.+c?&,n4!("%-) >  BbEWL,EcwG( ()'S)_3SxH43%&/5)2+8aZbuK"7:1&&!> 1RYM[U0!(  b*%)&3JSP7 033-3-&61+(%#-aaF0,3%i]> '&4\YRlY%  (eljM('#3# #/&#,K?5);2$7>7D}P%(sl_SD : '=RO&>XX[eB#$ gO?4Gi#/3/+%plD=;H"2@JAAD_|-/Mxcx:  .B5__^bM(aP'Vqe*+#../--0i4rL?GDkb]kJPSD&,1/(*,1-)2M]{gECCJNA<;. $ > +0Fe]_cQ!/+.,3-"79;LL@>KFGH3+3)#!'l^ >"-& -O_U9 !govpH" &%-2?>=CDBDA=2"+-(2+--(* "_[_>'gSQWVd2@/0i !-gw|j>#*,2;82;>HI6)$)00.2*$.71$lmm > 7%'/i3"oP5ktqvvA-'2/661-. (+ 00-/.16)'&'%rp>m!# 7G=0 A{|~oJ&02#*-,/00)*,9+!33,(()aYb> #rS"" &Szk !-,)4/20041* ':731-632**WGK>/.%Rr/%!"#&#!"+&%$Bt{k}o+!),-+4.4% ()(2)26:0# \fSW ! %!c{hLJ_q\PH=BN`e`v[> IL!!)!#' {ǀ<6:Mb`m{җCE;628<:AFHDI.' &# #  `X  -%#& !&#$7nW{&  ,#&$&&N2 1 &$$1 5f "$ %'!#  )FO@o/ ."&  %  BgL-kPF #$#)&# !$R* A t\L &#&# !40}($8ZI   *!$!1G@  r׹| "" "'DF)""&2N1!i^ " $(r_Jpe%""& ?0?  dȀ  ,!)* k8%& O:5   , !"GV6$2.(  !0򟼺Ӽ $" (&)02 f!BٝcoέmmZtvfL  !$!/,!  M>1iȀ5uv|!(:5!  '}ߪ㽉 H 1&#-*  m'Wc*g1[˺#Ѐ$tՍzƎ6X[ #઄ރP!vdʫр}  Ƭس.Cκ}!.71QYrr(hAFpԹwf~-o!˩w^-txJrئnS亴yxOvrJĽ어s܁N|xFˬŽܜtfk͋Dij<؉ȋͅK?㵮ȽЀ́(?˺쿓ǯj9ˑֽ>:č{2޶؁W3͒0+-ضºǠ·½ƷľƿZ1͜㿶%͖ݶ֘t,ãǾ갞:%ė紃(ĥK%ʛ%$ärؚRݜ̻"ƹĵwC ` ր' E#iq  f, *6)(&"  " !! # "$! ! ""!  !!# !"" ""-IϿĿü¬KH|~ngkfkmnZfijvXDNkxlocdYS_``{p>  LS05/[K#,.*=>1.5\U\\ K 91:gZ@Pn\i>Qum{D+&AfE4.30UrZLHLE@39<1x8F{D9*6f31HJGBGD_oE+"]aM`j0Q^a]@+/KL*.B[D,1* EI 1("FT32NMG=(/MS?+((39ElPUC5(%6OMMB@BBJa_55YYLJ]\k*QYPbxg&*U]4%:\ ++.3w(! !H.fG&%Q_96?wD5-);=kgd{mG? :MIHB?hf&/GmgC@]vUOg(PNO; A4!B`6-@o( "3/Ci *cB `HCTuv39<~D54*)+h2FR~?<@'5EBYZ<2BRfnUEVi_E>OZ"QNGRFgl-4Va43@y(2(.?\#0 ap0[jE$Axd91*+,+?[rhXA6DBCuZBC;YpQ@]|W, *JOPA3319S Hj*,Fq2%&)"WSJWnQEA:;BH@;=:H?5=EA:?>-=/1I8/9>Wy^JiOVNVRXVEe&-)8w\7L#P564-(,&;LZ[)0Dz//*1#x$b1.2&0)"/%"%#*%-.)2$/66<;88GYwuGSx|g}{SB`USv,5.;_&8:"100/2/*/3la0Aw !9H:DSH=279!1&7HUXkPKQmB |LQp{(;Y483>?4>/'(0-4),*X|(ByEP69UPRSpC.-$!!,$9FW{G@PPKHScv^B4srF-"Zn:+*&0:(!BuXh\2 N\AF^LMJSt}rE8HqC $#!,0-->/*$+)$)$#$)$#)-0%..(#,4(-&5 &!77tS;is,EQOF]Hcs)<!!          `tZGo|>/MS2dK@n5$>jEIGGR{qE"=s\>ueA*(1 XXA1CB2&8VJ4WaM!&)(:@V [YN1&#W}'&5;u&19IU0 V0)/V*n($*BA>AIcI  >&0EF,ФXXRI̗EPHU|CDSQBPVSI8,%:IKl(:S[87/-+2?R_C> !ׯb*oْP?L?Y 77hmSVE30@XbU`ZpҐ<3&8arf\]i:k\9?M>-. C5AHAIid4,-;Q[^Ya[Pa[TMG;4=[m[f[U>  J0dɞJ .=P̹UI=QF2(4DRQR`cL^TE0 0_|{UjԵ7CQ> (;.m|F:CCyq>'',CSYZ[Wxl71;Wy~zYIzQ[e> hp$"a×P4܌!++-%3s9FSPRTRNRVOF,l㱉rU2!&;22HFHM5ab> 4/DP060 4C7=KLUTZU3!">Wzg2$;MWMKJ92KQQ/>!H$+Gh$@ЀI>ON?*$6Ratyyx_?"7LSPXQUUPNC4K@ > _mdv5XӼu&!8NbgqhbsuqJ#(ET[]\cYS]bWE01-4D> &8;:3iWJԜ"$9/cx]XZZgohhaF&.KYMZZ\^\\^PG3),FQSSB%>:LD?9.3d{mV47$(%/@w׼Wc`H5"':U]`bb^VX`jV<01>Hbea`\][>EA=>;+/#*,/4213ABHK%+D_]]jfkhfieXF5*Pdtojdokk^\L >. [;88,,/93>>;5*F0.054)&(;9?6&11,-=:7;<;>2/3C789//,(?LKA( @pK_e:%CU!7DjC'F73<=D@8 H<:-/(4E<1.##-*FW3*n<7L? =:A<<-1>9!":@;0'+S3+ LGED><3-HA=7*-5<5+E{ 0<5 & @DBA90174138Z`V8r*68* K       "C4067,-4=>69D2;XuoH4/%-9 @ ". #;!> 44(%2-6.0/$*8C9 Sta?1650+"$84QgZA ", S47;125)7/5*8/7;:',69@,69B!  ADD=4эj4,6>7,AFP?:*) $"-9~topxq~ux=c1 OILFD&w764FT4%/>1'!+7tgha}rdhjfeo|r?g9  LD>97E|sDXB54\S  )+.$7!%,xvy~wi|W}rs{m^gubm~eo_/K; >848??B)68=5Wug5%*5'O}a/-!!:|szYexi4?hmRFc>:'<\WB4UAI@ 2EAE??=;2;_bMlHn~zXg(!$ ^29qXqlzZEd|jnkn|tvtgM~yJE*<q\Re\E.,+&*8GaTIzyP\T<'-&$3Arv7zzhUm`xodzf{VgVlfjPaJ]:-c\+069D<<>NaUt|iNV*!>:/OI{E{hpujhqw~yzjsD=MDfOqp_NQ2aL*2,;:;?^z|uY=dhz~sZ.D ,-5Q|0lks[>`}stzl_rpp_Y?l|s_Yohq|s:E1Q K=;<8:lE^rD_`VMfTYlaoh_^! % (J^Yjλ4ei~|@[PjcwtmD;5HmI.+?sjdn7~|xAMrKQAzxtqMa̞G1{ko@PG{qy/ǍvuyB`9QCgQS3 J}buLVwulżO_}5~vL{P0T%Kfewp}~s}qz~}g_~5yIK R/L{uyp}ruppcQc<|qSX OU\|x~hg~wx}CtûCr_= ?*Liu}xu{}ihMSpyF<=ckKx |{G13J 1a_e\]eP\^V^Y\RQXZ`TIQask[bdWO^Mi_VZ`[^cOVVUZYVV_cqq[aNM`]`\mhopsgX./1 H D:v|{|qU||dn}0E9AXzwumw~~w~yL}~|e}{qlu!B<.PX~z|j^|}cw|E?8.]Z}ke{n֯N=04dxyf^qg\;;/k}sqc\zta{qDHL\94*ghz]¸}'697wrmfl3"S~flsl]kzpv}z~pteoV}wr|vnxp|zwO2J5oZt{~z{rbm~~zm390HHQn}^avغP -Q;w^pazθ՟5+H0ovVrYom)jGzvb|ŒӨa$%E>w[Ӗj0$]>r{b}Ѽ@!jIZHXNtWwvgyuV!?Frsv]uvjbdXV_ddxHe F>o}x*XP[YP{K<lizz X}|Ȼ t|§ S9-&HbӷO =I5Z7)('#" ""$"#$#" & $&""$" "$""$##$%#"$" $""!!&"%&#!#%Kɿ»#Ľ½½žŤFHvjojqt{_gspyYARr~lvjibZifa}wA9IVTWL}rDQceM]]ab`ihfxǁ@I8u2ilD9@jj[J_T=hxbNfX+DBFjR= Bk@#SX033dQ&*2,==.09b_c^KA9=bV=QX<_zsH,q<A- -86310MhD4*,WP.=`d1)2[^8;4*-9p& *@xFN>4*9A[]GDMA33/A]d~|K560><8/31BCWl"6wM>45Tc7..]Z!+*t'%&.1L_pc& }|Z_:'//E]I3A18:6>Gv9;>sD0.0Ye<8"K:*%"'&[|K3(,-)&&O~YQts8AXc3*,5Gg];4.94>5=4509u~hlH645Fr31:oG.Ad~}^:5PU""00WfZcg3 "#)9?CFXmks?Qyl~J/,BjL9296Vq\PSXOK=@>.y@L~I83Aj3:@mJ@ldYYvw3NY!;;:5]<3-MsB&7:MILYmkBK\t.Qqji=T@0P`Y;578;>?>NQcEVnIkb929Wl3:@qD9S5\tw1W`.)75&:==6@EXj\JJPAAUlgV@.Hcf|,QmfY 7qD/17kL+.:56/+Cs=*&\Y5 MvX2$:;Tb@4H\`K9@P]3.(=1'$&/9GJNQLOMkwI0#*]oR^r3Q][dD70JO02FfL!-1("KJ#3-'AV77SQGC/6RXH2/.99MwWWJ<.+8ONOKJKJQf_5 4XiNV^Ph(QXKm~Y&+]f2%Fi -+. 5l*"&,M3eL2.Wb==AxH>2+;Awqh~qLE@QKMIDlk/#4JssPBYaUn+QLY> G4Oh31Ip*"3(Lz 0gI$cLHa|69=J=8..+g6LcDJA(5HDgd?2CWlt]KateH?I]QMCUJl..]f28J|+2&*Fk)-es4cjN.Hye;4-./.Dbsl]G>DDKy`DA=avWJfX.&.?TQA4ET]QX)"_e)*I.-*b{ 'WgkpjDAekI49HABB62=CDA@C99OqO0IKLGhpDdt.0LKYQ@6B9819T+Go/0L{7))'%g]OYa`ND4@EL>:=7RI4?DD@A<6C01D<5@DYeLsZcWXVbXJj--04~]3K#P9693-,+=;@M^}~S[|oZIn]Xy245GSKAORMJUcv]A.mjF7&\r7).,:2 )FscwX4,SbGIfQSR\yCDTvI# (!02+,<8b#_VMרNMO`@" LghHRYXP>4*@ONv*=Xb@A5/17DTc@> ,̥d/yZBKI`"9>h~cWG42BU`R`Yy76,?b{rfkx:kɧfBGO<16&GBKIKTrr;*4CX`a\gg]ocWVQ<4Hcngtga > G9mܬR"-=TƍYOCWK0&8J\RVgs[cS?/&9jYgï8F2tƌK  }z#,lТVC`ѺDKMJX`d^P{1+vΝՖXl{QMj> @*(-40?Ώ;H\Z[ZTRUZRL4k򿗕}b9'.A90IJMU3E^>  33FT391&6ɝJ9=QR]]hT4'&=js>$!2Q[RNKB8P\d0&H.4 Vs#>*߆KBRNB0&9VidC!&!#s|oy$@ay/*;IcjtpjzN(%+BS^a_j]Vcg[J664>R >1:FBMveIڟ-'33nֆdXjipukpgJ*1M[PccddegiTN;03JUZ[K;NAEA919lw]99$GƔYfeN;%)>Yaegjd]bis]@35FMilhdbe`>aG@?=,0&-..3359HCHT/2Ebbcqmpnmpm\H7/Xowrpm{qrgcS >.&cC>@102>8EDA9.>JHJRϗm~yty~hMP32399.,",?=B:*45.2Fbɤjlx^   nsWi   > B9:>A>A637H;<=541+COLF2 9mIPa0 3D-;iA"I>9>AFC?>4,1""56BD19!$-. ON1:AD>;58004EA85.%75u¸A RND113433FFC7-,4@6  !OA<34.8I?30&&20JY70vC7*F"(0H7>]~tH75*6K6!# -    @I@>4@\dF=?52.&#*;;Uld4"#( 2(   AHG?9ے~˻:14E=2HLYIC32 #"' I>@00>BD)/J@+7AI9339B7I=31: QORJK-B?>IW<*-'8@> %""#9=-7@"A'.F?3=7A*:+?.*.=4U0 !OJE5D4MF>9_|r>26@*-3<" $:?6CE+3!*715>%./*$ 3FEIBDBA9AflZK_E80S?/5-9 $:/68?.44**0;8*4*%8I5M1!/N01[OWtrN+87FJRM=.1.8:E ' *=:#8'/;$(:./*/,-?74+0.?,7) DcXmgT?558;AB@" A1/C04 ( 0?8"5*<0>):9@+-4,%6&8!/".')G&8xl239CSX\F3C04!%7*=5242!+  .-:)A?>$(B.1I*#,1630&6"(<8:7J1 (;x[3@CVJG35-'!0+':*%145. .  !;H',7(2?86*+70* -*('%-<3$0)/5,;4 R#OPSOJ5B#2*#1%%6-71+* '%(75-,25<292-'4,(.,5-5,10'&%"-(3!!E- R)!DUK:0/5R(C),#IJ5`-. +04F6>=740CACTZK</#3D@+:<>08+8643@8=aK)*R ~q=#(9&\!S/6+C9BHM)* %.006>09570A5;55;PM?YE4890E:@3AJM0?,<,E>9E9"!!%"5*011"1!%@<[638>`-=4-5E4A;*"!&(494(+03P:IF33:E@117-+279(D<(V1$ S =?>@+/8B')0'3>4*e@.==)4Q'2JI+98,6/38.;42NIJM'B-@A9/CAG<5-4'>F70<%<0B;  T 9;94'&N')02*73.17>3/-7)-@850CL1/?85=-<-40>,1+3;8?73.9+-FBD68/+21&/)269747/6A&.>23430'/J+.C98;4GE037+1066:"14DF@8>=81+9.=8.8 NL7%;96-5>1-@047@65?K1)0 .?90BMH$IA&8P?1,538-#5.2&+:+$2+0E*D'2*2/3.5:4+32D:470C8I4,,60/5386@307a-@#'!BD@2H5,18+.).+453= %++:+329/.+590..$=631.+;03+25250+84*IB=@  ;:+4B'*61.+'+39)9(&<.31;+5056>8@91.@.8;:H4%,4& !A?47,I6>93/;;835"/$!>8<-//433-:18/6351/546?3E;;<>4A# = $J18=*;*1A#!46,9,)6"!:5(<1.242=:/33891/"89;?A0.819$ & : "=072D<9/2/43<9,,5. 983-38/0/5/:?/=936:03:694;:A()7 -C7+-;C94;1942D+4D$)/*A,779/3//4;123<6>4=A?27,.4 -4 &*<#&-',0/0&(#- .((21*#*#5.++0,0-041.71#%3+A7=;FC8 ,,96/478;.4713AB(0!60  )%?3659+1"@60'53.,%323449143;1?=+%.' "H596C38.382++&'1-,0=28<.;4(1*( "$GG76;53";384+0284(,07889A&93 "4==>=;*@9-7A1//,0730:7A7?#! "894/94.97,887./507((+   %GB.34,.,6.% " "!((   $8.&-,*0*.,+//13:;.(=C=,2464848AA:CA #E?6>899>7=F6-2 #99E6844<8)70 155)09=3 &B=C5  L<+&  (, !t8mk@icnV C eureka-1.11-source/osx/EurekaApp/AppDelegate.mm0000644000175100017510000001105412647061302020664 0ustar aaptedaapted//------------------------------------------------------------------------ // OS X EDITOR APP DELEGATE IMPLEMENTATION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 AndrÈ Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // // Module by Ioan Chera // // Thanks to Darrell Walisser, Max Horn et al. for their SDLMain.m code - // reliable base for cross-platform apps ported to OS X. #import "AppDelegate.h" #include "main.h" static int gArgc; static char **gArgv; static BOOL gFinderLaunch; static BOOL gCalledAppMainline = FALSE; // Prototype to cross-platform main entry function int main_ORIGINAL(int argc, char *argv[]); @implementation AppDelegate // // applicationDidFinishLaunching: // // After [NSApp run] was called. // launchMainLine not called immediately because I needed application:openFile: // - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Set install_dir from here (it's dependent on project build settings) // Current value (might change): .app package root directory install_dir = StringDup([[[NSBundle mainBundle] resourcePath] cStringUsingEncoding:NSUTF8StringEncoding]); // home_dir is set inside the main program and doesn't depend on build // settings [self launchMainLine]; // start the program } // // launchMainLine // // Start the program and retrieve the exit code // - (void)launchMainLine { int exitcode = main_ORIGINAL(gArgc, gArgv); exit(exitcode); } // // application:openFile: // // Handle OS X UI's non-command-line way of opening files. // FIXME: handle files open this way at runtime. // // Note: code has been borrowed from SDLMain.m. // SDL license is compatible with GPL v2 // - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { const char *temparg; size_t arglen; char *arg; char **newargv; if (!gFinderLaunch) /* MacOS is passing command line args. */ return FALSE; if (gCalledAppMainline) /* app has started, ignore this document. */ return FALSE; temparg = [filename UTF8String]; arglen = strlen(temparg) + 1; arg = (char *) malloc(arglen); if (arg == NULL) return FALSE; newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); if (newargv == NULL) { free(arg); return FALSE; } gArgv = newargv; strlcpy(arg, temparg, arglen); gArgv[gArgc++] = arg; gArgv[gArgc] = NULL; return TRUE; } @end // // CustomApplicationMain // // Replacement for NSApplicationMain. Also borrowed from SDLMain.m // static void CustomApplicationMain (int argc, char **argv) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; AppDelegate *delegate; // Ensure the application object is initialised [NSApplication sharedApplication]; // Set up the menubar [NSApp setMainMenu:[[NSMenu alloc] init]]; // Create SDLMain and make it the app delegate delegate = [[AppDelegate alloc] init]; [[NSApplication sharedApplication] setDelegate:delegate]; // Start the main event loop [NSApp run]; [delegate release]; [pool release]; } // Undefine main from main_ORIGINAL. This will be the real entry point. #ifdef main #undef main #endif // // main // // Code borrowed from SDLMain.m // int main(int argc, char *argv[]) { if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { gArgv = (char **) malloc(sizeof (char *) * 2); gArgv[0] = argv[0]; gArgv[1] = NULL; gArgc = 1; gFinderLaunch = YES; } else { int i; gArgc = argc; gArgv = (char **) malloc(sizeof (char *) * (argc+1)); for (i = 0; i <= argc; i++) gArgv[i] = argv[i]; gFinderLaunch = NO; } CustomApplicationMain(gArgc, gArgv); } eureka-1.11-source/osx/EurekaApp/OSXCalls.h0000644000175100017510000000320612647061302017757 0ustar aaptedaapted//------------------------------------------------------------------------ // MAC OS X NATIVE C-STYLE CALLS TO BE ACCESSED FROM THE MAIN PROGRAM //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 AndrÈ Majorel et al // // 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. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by RaphaÎl Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // // Module by Ioan Chera // #ifdef __APPLE__ #ifndef __Eureka_Doom_Editor__OSXCalls__ #define __Eureka_Doom_Editor__OSXCalls__ //#ifdef __cplusplus__ //extern "C" //{ //#endif // Currently used paths enum { osx_LibDir, osx_LibAppSupportDir, osx_LibCacheDir, }; typedef unsigned osx_dirtype; const char *OSX_UserDomainDirectory(osx_dirtype dirtype, const char *subdir); //#ifdef __cplusplus__ //} //#endif #endif /* defined(__Eureka_Doom_Editor__OSXCalls__) */ #endif eureka-1.11-source/osx/EurekaApp/Eureka Doom Editor-Info.plist0000644000175100017510000000302712647061302023427 0ustar aaptedaapted CFBundleDevelopmentRegion en CFBundleDocumentTypes CFBundleTypeExtensions WAD CFBundleTypeIconFile EurekaIcon CFBundleTypeName Doom WAD File CFBundleTypeRole Editor LSHandlerRank Alternate CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile Eureka Doom EditorIcon CFBundleIdentifier com.eureka.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleShortVersionString 1.07 CFBundleSignature ???? CFBundleVersion 1720 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright Copyright © 2001-2015 Andrew Apted Copyright © 1997-2003 André Majorel et al. NSMainNibFile MainMenu NSPrincipalClass NSApplication eureka-1.11-source/osx/EurekaApp/Eureka Doom Editor-Prefix.pch0000644000175100017510000000022512647061302023405 0ustar aaptedaapted// // Prefix header for all source files of the 'EurekaApp' target in the 'EurekaApp' project // #ifdef __OBJC__ #import #endif eureka-1.11-source/osx/INSTALL.txt0000644000175100017510000000322612647061302016152 0ustar aaptedaaptedBuilding for Mac OS X --------------------- The Eureka Doom Editor.xcodeproj package has been made with Xcode 4. For info on how to build using an older version or by using another development environment or build automation, see Section "Building by other means". Xcode 4 can be downloaded from the Mac App Store for free, if you have Mac OS X 10.7 "Lion" or more. Xcode 3 comes bundled with the Mac OS X 10.6 or earlier DVD. Dependencies: - fltk.framework - fltk_zlib.framework FLTK can be downloaded from the FLTK website, http://www.fltk.org Follow the instructions in the FLTK source readme file on how to build them (at this time, you can choose between command-line, Xcode 3 and Xcode 4). Then copy them either to /Library/Frameworks (will require admin password) or to ~/Library/Frameworks (from within your home folder). Building by other means ----------------------- If you're using Xcode 4 to load the project, ignore this section. For compilation, include the *.cc and *.h files from "src" and those from "glbsp_src". For editor data, make sure to stage the "common", "games", "mods", "ports" folders for packaging into the target *.app bundle, at the base destination (i.e. sisters with "Contents", the topmost folder from inside an *.app package), by preserving the directory trees, i.e. if you need to choose between loading as groups and loading the folder references, choose the latter. By default, this has been built as 32+64 bit Intel, 10.5 minimum. Preprocessor definitions used in this project: main=main_ORIGINAL -> redefines the main() function from the base program, so that the OS X port can call its own implementation. ---- Ioan Cheraeureka-1.11-source/osx/EurekaAppTests/0000755000175100017510000000000012647061302017200 5ustar aaptedaaptedeureka-1.11-source/osx/EurekaAppTests/en.lproj/0000755000175100017510000000000012647061302020727 5ustar aaptedaaptedeureka-1.11-source/osx/EurekaAppTests/en.lproj/InfoPlist.strings0000644000175100017510000000005512647061302024251 0ustar aaptedaapted/* Localized versions of Info.plist keys */ eureka-1.11-source/osx/EurekaAppTests/EurekaAppTests.h0000644000175100017510000000031612647061302022251 0ustar aaptedaapted// // EurekaAppTests.h // EurekaAppTests // // Created by Ioan on 20.11.2012. // Copyright (c) 2012 Ioan Chera // #import @interface EurekaAppTests : SenTestCase @end eureka-1.11-source/osx/EurekaAppTests/Eureka Doom EditorTests-Info.plist0000644000175100017510000000125612647061302025477 0ustar aaptedaapted CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier eureka.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 eureka-1.11-source/osx/EurekaAppTests/EurekaAppTests.m0000644000175100017510000000064712647061302022265 0ustar aaptedaapted// // EurekaAppTests.m // EurekaAppTests // // Created by Ioan on 20.11.2012. // Copyright (c) 2012 Ioan Chera // #import "EurekaAppTests.h" @implementation EurekaAppTests - (void)setUp { [super setUp]; // Set-up code here. } - (void)tearDown { // Tear-down code here. [super tearDown]; } - (void)testExample { STFail(@"Unit tests are not implemented yet in EurekaAppTests"); } @end eureka-1.11-source/changelogs/0000755000175100017510000000000012647061302015601 5ustar aaptedaaptedeureka-1.11-source/changelogs/084.txt0000644000175100017510000000350612647061302016661 0ustar aaptedaapted CHANGES IN Eureka 0.84 (r304) ============================= (Changes since 0.81 version, r186) + multi-select : LMB toggles each object (no need for CTRL key) + can click on a texture in the LineDef or Sector panels, it becomes highlighted, the browser is opened (if not already), and only the selected parts are changed when clicking in the browser. + implemented a -merge option for resource wads + reload the wad/map after building the nodes (no longer exit) - ESC key no longer quits - plain MMB now inserts an object (like SPACE or INSERT key) - thing panel has radial arrow buttons for setting the angle - insert thing: if one already selected, copy its properties - improved line split highlighting when SNAP mode is active - limit size of drawn vertices when zooming right in - allow running locally (without a 'make install') - iwad search: check more places (like /usr/share/games/doom) - fixed possible fatal error with zero-length lines - fixed state persistence to ignore unused vertices (etc) - fixed inner sector getting defaults when closing simple loop - fixed pink-highlighted tagged sectors when line was off-screen - fixed CMD key on MacOS X to only trigger menu commands - config: can specify a boolean value on the command-line - config: new syntax for config files, no '=' required - config: added 'escape_key_quits' var - config: added 'leave_offsets_alone' var - config: added 'mouse_wheel_scrolls_map' var - config: added 'new_islands_are_void' var - Browser: faster scrolling with the mouse wheel - Heretic: fixed the default port (i.e. not BOOM) - 3D view: can use WASD keys in 3D mode to move around - 3D view: the 'g' key toggles gravity (walking on the ground) - 3D view: toggle sprites changed key to 'o' (objects) - 3D view: removed CTRL-L function, resync objects with 'o' key eureka-1.11-source/changelogs/107.txt0000644000175100017510000001047612647061302016661 0ustar aaptedaapted CHANGES IN Eureka 1.07 (r1716) ============================== (Changes since 1.00 version, r1416) + implemented Find and Replace (as a panel), with support for stepping though each item or selecting them all, and filters to control which items to visit or ignore + added 'File / New Project' command as the proper way to create a brand new WAD file. The 'New Map' command requires a current pwad, and will save the fresh map immediately into it + new 'RECENT' category for Texture/Flat/Thing browsers, and rebound the '\' key to toggle this category on/off + new 'Rename Map' and 'Delete Map' commands in FILE menu + improvement to key binding system, support for "flags" which are parameters beginning with a forward slash, such as "/new" and "/clear". The 'EditKey' dialog is now much easier to use too + Windows package no longer uses an installer + vertex reshaping commands: - 'I' moves selected vertices onto a line - 'O' moves them into a circle shape - 'D' moves them into a half-circle - 'C' moves them into a 120-degree arc - 'Q' moves them into a 240-degree arc - a preference to show smaller textures in the browser - map checker can find unknown linedef and sector types - Linedef panel: swapped the 'Tag' and 'Length' positions - Linedef panel: always show a two-sided line panel when multiple lines are selected (allowing all texture parts to be edited) - Linedef panel: don't show rail/upper tex for one-sided lines (can be disabled with the 'show_full_one_sided' config var) - when loading a wad specified on the command line, and it contains settings for the iwad, port and/or resources, then allow command line arguments to override those values (and _add_ new resources) - new preference to maximize window on start (Linux, WIN32 only) - the Default Properties now has its own panel - Default Props: only a single wall texture now, and shows a sprite for the default thing which opens the browser when clicked on - added back the '192' grid size - browser: changed two key-bindings: 'T' now opens to Things and 'X' is used to open it to Textures (matching the menu shortcuts) - browser: changed key-binding for BR_CycleCategory to '|' - browser: the 'Sort' menu has been replaced with an 'Alpha' checkbox - browser: made sprites a bit smaller, can now show three columns when the browser is at minimum width - better way to show how a linedef will be split (esp. when snapping) - co-op player starts are now colored as in DOOM - 3D view: the low/high detail flag is now a preference setting (no longer toggleable with the F5 key) - added info bar for 3D view, shows current position, angle, etc... - added 'Toggle 3D View' command to View menu - support loading a read-only wad file - support data in a map header lump (such as MAP01), make sure to save it when saving the map (instead of removing it) - node builder: added work-around for "TOO SIMPLE" levels (i.e. a single convex sector), creating a dummy node and an extra subsector and seg for the back side - wrote a Unix man page - vanilla DOOM: do not show "friend", "coop" or "sp" thing flags - support -warp option being followed by two numeric arguments (episode and map number), compatible with vanilla DOOM - when checking textures, ignore ones beginning with '#' - show version _in_ the About box (not just the window title) Bug Fixes: - fixed not loading 'ASHWALL' texture for DOOM 1 - fixed bug when saving and using the 'ExMx' buttons (an erroneous newline was added into the map's lump name) - 3D view: fixed a vertical mis-alignment of textures (one pixel) in certain circumstances - fixed occasional false positives with sector mismatch test - fixed wrong focal point when zooming immediately after the 'j' (JumpToObject) command - fixed category of linetype #68 (should be a raising floor) - fixed clipping of mid-masked textures (e.g. the cage in E1M9) - fixed not reloading textures (etc) when opening a new wad file - fixed crash when trying to build nodes on an IWAD map which has some changes made to it, but has not been saved (exported) yet - fixed key binding list so that pressing 'Bind', 'Copy' etc on a non-visible line will scroll to that line (make it visible) - browser: fixed patterns like '4$' not working properly eureka-1.11-source/changelogs/072.txt0000644000175100017510000000231512647061302016653 0ustar aaptedaapted CHANGES IN Eureka 0.72 ====================== (Main changes since 0.64 version) ++ the File menu is fully operational (albeit a bit clunky) ++ browser for textures, flats, thing types (etc) ++ can scale/rotate stuff with middle mouse button + grid snapping works again ('f' key to toggle) + quantization function ('q' key) which grid-snaps objects + disconnect function ('d' key) in vertex and linedef modes + automatic sector insertion when closing a line loop + automatic sector splitting when a line crosses a sector + the -iwad option works again - split linedefs by just inserting a vertex on a highlighted line - merge two linedefs by just deleting the vertex in-between - select linedef path function ('e' key) - correct sector function ('c' key) - new sectors get default flats/textures/etc - invert selection function (CTRL-I or Edit menu) - draw the camera on the map (a pink arrow) - move camera function (' key) and goto camera (END key) - can find an IWAD (doom2.wad only) in $DOOMWADDIR - the IWAD is opened in read-only mode - partial support for DOOM 1 and HERETIC (need -warp E1M1) - games/ directory for game definitions - ports/ directory for source port definitions eureka-1.11-source/changelogs/081.txt0000644000175100017510000000351512647061302016656 0ustar aaptedaapted CHANGES IN Eureka 0.81 (r186) ============================= (Changes since 0.74 version) + support a proper unix-style installation + made a proper web-site (using PmWiki) + command to build nodes (via glBSP) and quit + texture browser can be resized by dragging the edge - log file is only created when --log is used - the --quiet option (-q) suppresses output to stdout - new --debug option (-d) enables debug messages - allow long options to begin with '-' or '--' - handle a pwad filename given without -file - more lax finding of patch lumps for textures - when no level is given, find first one in PWAD or IWAD - support plain numbers with -warp - look for iwads in the ~/.eureka/iwads directory - when searching for iwads, look for more names (e.g. "doom.wad") - if -iwad parameter is a bare name, look in iwad search path - if -iwad parameter has no extension, add ".wad" - using SPACE on a single selected vertex will unselect it - closing a simple vertex loop always makes a new sector inside it - can now split a line when one of its vertices is selected + new 'm' command for merging sectors + new 'c' command to copy sector/thing/line properties - added 'same_mode_clears_selection' config var (emulates Yadex behavior) - 3D view: support strafing with ALT or META key - initial support for Odamex - DOOM: fixed line types 33 and 34 (red and yellow locked doors) - DOOM: restored the 'Computer Map' pickup - DOOM: fixed "SW2xxx" textures not having the right category - EDGE: added slope line types - EDGE: added some missing things (jetpack, green keys, dog, stealth mons) - EDGE: fleshed out sector types - EDGE: fleshed out line types (hub exits, sliding doors, RTS) - TNT: assigned the new textures into categories (e.g. "Crates") - PLUTONIA: assigned the new textures into categories eureka-1.11-source/changelogs/088.txt0000644000175100017510000000375412647061302016672 0ustar aaptedaapted CHANGES IN Eureka 0.88c (r605) ============================== (Changes since 0.84 version, r304) + large overhaul of file handling: - 'Manage Wads' dialog allows setting the IWAD, port and resource wads - 'Open Map' dialog, with buttons for easy map selection - 'Recent Files' dialog (CTRL-R or File menu) - the iwad/port/resource settings are saved in the PWAD - better 'Export Map' dialog - IWADs found by the user are remembered + new Default Properties panel (shown in vertex mode) + implemented picture mode for Thing browser + new Move/Scale/Rotate dialogs (via Edit menu) + support for Doom Legacy, courtesy Wesley Johnson + support for HACX (not quite finished, but usable) + 3D view: fixed the slime trails - added 'd' disconnect command for sectors - added 'm' merge command for vertices - added 'm' merge command for two linedefs ! the -iwad parameter can no longer be a directory name - shortcut key for 'File/Export Map' is now CTRL-E - swapped sector height keys: '.' ',' <---> '[' ']' - grid-snap button is easier to use (a toggle button now) - can disable multi-select ('multi_select_modifier' config var) - sectors created outside of map now have fixed size - show a '*' in window title when map has unsaved changes - got 'View/Jump to Object' command working ('j' key) - got 'View/Show Object Numbers' working (also on 'J' key) - new 'View/Whole Selection' command - new 'View/Toggle Grid Type' command - fixed rotating a group of things to update their angles too - fixed wrong color of a tagged linedef or sector - fixed zooming out on File/Open when map has persistent state - fixed middle texture when pasting and linedef lost a side - config: default grid size is now 64 (was: 128) - config: added 'default_grid_size' var - config: added 'default_grid_snap' var - config: added 'digits_set_zoom' var - config: added 'new_sector_size' var - config: added 'gui_scheme' and 'gui_color_set' vars - config: added some glBSP-related vars eureka-1.11-source/changelogs/095.txt0000644000175100017510000000256512647061302016667 0ustar aaptedaapted CHANGES IN Eureka 0.95 (r922) ============================= (Changes since 0.88 version, r605) + Preferences dialog + Key binding system, with GUI in preferences + Windows port (32-bit), with an installer + Automatically back-up edited wads (multiple times) + Status area on info bar (replaces map name) + Log viewer - new 'Prune Unused' command removes unused stuff (sectors etc) - fixed explosion of wad size when saving repeatedly - fixed crash clicking a linedef flag when nothing was selected - fixed PGUP / PGDN keys to scroll the browser - fixed jerky RMB scrolling at large zoom factors - Scale Objects: implemented Z scaling for sectors - Default Props panel is now hidden by default - copy properties command ('c') now copies linedef textures - swapped grid keys: 'g' now makes the grid smaller, 'G' bigger - key for splitting lines in half is now 'k' (was 'x') - prevent making two lines overlap when merging vertices - merge: support one selected + one highlighted - merge command for things -- place them at same location - disconnect command for things at same location - when a resource cannot be found, look in same dir as PWAD and IWAD - when saving over a map, use existing location in the wad - command line options: '-m' is shorthand for '--merge' - preference setting to swap upper and lower in Linedef panel ! removed '192' grid size eureka-1.11-source/changelogs/100.txt0000644000175100017510000000447712647061302016656 0ustar aaptedaapted CHANGES IN Eureka 1.00 (r1416) ============================== (Changes since 0.95 version, r922) + extensive map-checking functions + validate map data when loading a level + texture alignment commands for 3D view + splitting void islands now works as expected + improved grid, with configurable colors + scroll-bars for the map view (optional) - one sided linedefs show texture in the "Lower" spot - automatically unpack sidedefs when loading a map - support multiple filenames: new 'File/Given Files' menu - commands to visit the next or previous file - commands to open the next/previous map ('N' and 'P' keys) - changed 'File/Recent Files' to be a sub-menu - option to automatically open the most recent file - improved About dialog with Jason R. Johnston's logo - improved Log viewer, ability to save the logs to a file - improved dialog boxes - support Eureka config (.ugh) files as resource files - support $DOOMWADPATH for finding IWADs - implemented SEC_Light() binding command - commands for setting tags on linedefs/sectors - Edit / Move objects: implemented Z value for sectors - the ';' key waits for next key and makes it META - better drawing of selected sectors - better drawing of highlighted things and linedefs - better drawing of things (in THING mode) - show unknown/missing textures in the LineDef panel - show unknown/missing textures in the 3D preview - display the lengths of the last few linedefs - can modify the length of a line in the LineDef panel - improved behavior of vertices when grid-snap is on - option to limit grid toggle to a single kind - option to show grid in SNAP mode, hide it in FREE mode - option to set the default editing mode - option to set the default port - 3D View: option to set the aspect ratio - 3D View: option to prevent up/down moves when gravity is on - remember the browser width for a saved map - remember the 3D mode (the lack of it) for a map - fixed crash bug when loading or saving a map containing linedefs which have no right sidedef - fixed rare map saving problem (header lump in wrong position) - fixed possible crash not clearing selection after loading a map - fixed wrong linedef (etc) totals after loading another map - fixed key binding dialog: unable to remove a parameter - fixed the selection after a sector merge eureka-1.11-source/changelogs/074.txt0000644000175100017510000000335412647061302016661 0ustar aaptedaapted CHANGES IN Eureka 0.74 ====================== (Main changes since 0.72 version) + show the current WAD and map in the window title bar. + clipboard persists when changing maps, so you can copy-n-paste from one map/wad to another map/wad. + various user state (grid settings, camera, editing mode, etc..) persists when a map is saved, and is restored when the same map is loaded again. + improved SECTOR insertion: (a) copy properties from a selected sector, or try a neighboring sector if no selection. Use default value as last resort. (b) if CTRL is pressed, then new area BECOMES the same sector as the one selected. + new 'Sort' setting in Thing/Line/Sector type browsers. + new 'ADD' and 'DEL' sidedef buttons in the LineDef panel. + new -port option to select the source port. Defaults to boom. Other values currently supported are: vanilla, edge. - fixed problem where you could seemingly close a line loop, but due to grid snapping the vertex was merely placed on top of the existing one and it did not actually close the loop. - fixed bug where closing a line-loop around an existing shape did not apply the new sector to the outside of that shape. - new outside-of-map sectors now occupy a single grid square. - File/New does not ask for map slot unless there's a current PWAD, since that will be asked on the File/Save (== File/Export). - File/Export asks for the map slot _after_ the filename. - dynamic rotating (CTRL + middle button) no longer scales. - dragging/scaling/rotating vertices will draw the lines too. - fixed display of a certain flat (CEIL4_1 IIRC) which was showing bright cyan in parts that should be black (palette color #247). - better looking About box. eureka-1.11-source/CHANGES.txt0000644000175100017510000000433112651521335015303 0ustar aaptedaapted CHANGES Eureka 1.11 =================== (Changes since 1.07 version) Games and Ports: + Hexen support! (thanks to printz for doing some of the heavy lifting) + Boom generalized lines and sectors + treat Freedoom Phase 1 and Phase 2 as separate games + added Eternity port definition, thanks to printz - Heretic: categorized the textures and flats - changed default port from Boom --> Vanilla Editing: + rendering of sector flats/lighting in the 2D window + easier vertex "drawing mode" using the LMB + when adding lines, automatically split crossed lines - inserting a vertex with SHIFT continues the drawing mode - inserting a vertex with CTRL inhibits creation of sectors - SHIFT + LMB in sectors mode always opens a selection box - better merging of linedefs when dragging a vertex - prevent overlapping lines when deleting 3rd vertex of a triangle - much less chance to accidentally drag an object - when a line splits a sector, use a consistent orientation - when creating a fresh map, add all four player starts - allow loading a map with no vertices, no linedefs (etc) UI: + fixed texture warping in 3D preview - sector panel: buttons for quickly setting the headroom - sector panel: MMB on the ceiling flat sets it to sky - right-click on a sidedef or sector texture sets it to default - various layout tweaks to the editing panels - added "Recent Textures" command (etc) to Browser menu - fixed RECENT category to show most recent items at the top - status bar lets you see full message via a tooltip Commands: - new "Last Selection" command, undo an accidental clearing - added /reverse flag for CopyProperties command - extended LIN_Flip command, avoid making lines with no right side Map checking: - find "dangling" vertices - detect the Medusa Effect on 2S lines - detect transparent tex on solid walls - find manual doors on 1S lines - don't consider teleport things to be stuck in monsters - ability to SHOW unused vertices Miscellaneous: - improved eureka.desktop file, courtesy Fabian Greffrath - have a fallback sprite for the MBF dog thing (id 888) - replaced "Aspect ratio" with "Pixel aspect ratio" in prefs - use absolute paths for resource filenames in __EUREKA lump eureka-1.11-source/README.txt0000644000175100017510000001513712651344500015173 0ustar aaptedaapted Eureka 1.11 README ================== by Andrew Apted January 2016 INTRODUCTION Eureka is a map editor for the classic DOOM games, and a few related games such as Heretic and Hexen. The supported operating systems are Linux (and other Unix-likes), Windows and MacOS X. FEATURES - Undo/Redo (multiple levels) - 3D preview - Low system requirements, no 3D card needed - Editable panels for things, linedefs, sectors (etc) - Browser for textures, flats, things (etc) - Key binding system - Built-in nodes builder SUPPORTED GAMES - DOOM - DOOM 2 - Final Doom - FreeDoom - HacX - Heretic - Hexen REQUIREMENTS - 128 MB of computer memory - 800x600 or higher screen resolution - a keyboard and a two-button mouse - the data (iwad) file from a supported game COMPILATION See the INSTALL.txt document (in source code) RUNNING You can run Eureka from the command line, or it can be run from the desktop menu (if your OS handles .desktop files as per the XDG specs). Eureka will need to be able to find an IWAD to run, if it cannot find any then the "Manage Wads" dialog will open up, allowing you to "Find" one (which is remembered for next time). You can open a PWAD file using the File/Open menu command, or start a new map with File/New command. You can also specify the PWAD to edit on the command line, either on its own or with the -file option: eureka -file masterpiece.wad If that PWAD contains multiple maps, you may need to specify which one to edit using the -warp option: eureka -file masterpiece.wad -warp 14 For a summary of useful command line options, type: eureka --help KEYBOARD AND MOUSE CONTROLS All Modes --------- LMB * select an object, drag to move the object(s) * begin line drawing (in vertex mode) from selected vertex * click in an empty area to clear the selection * click in an empty area and drag to select a group of objects RMB * scroll the map around (by dragging) MMB * scale the selected objects * with SHIFT key: allow changing aspect (stretching) * with CTRL key: rotate objects wheel : zoom in or out 1..9 : select the grid size (smallest to largest) TAB : toggle the 3D preview on or off ; : make the next key pressed META t : enter Thing mode l : enter Linedef mode s : enter Sector mode v : enter Vertex mode b : toggle the Browser on or off CTRL-Z : undo (can be used multiple times) CTRL-Y : redo (i.e. undo the previous undo) CTRL-A : select all CTRL-I : invert the selection CTRL-U : unselect all ` (backquote) : unselect all HOME : move/zoom 2D viewport to show the whole map END : move 2D viewport to camera location ' (quote) : move 3D camera to position of mouse pointer META-N : load next file in given list META-P : load previous file in given list N : open next map in the current wad P : open previous map in the current wad g : grid size adjustment : smaller G : grid size adjustment : larger h : grid mode toggle : on, simple, off f : toggle grid snapping on or off J : toggle object number display j : jump to object (by its numberic id) o : copy and paste the selected objects c : copy properties from the selection to the highlighted object p : prune unused sectors, sidedefs and vertices H : mirror objects horizontally V : mirror objects vertically R : rotate objects 90 degrees clockwise W : rotate objects 90 degrees anti-clockwise \ : toggle the RECENT category in the Browser META-F : apply a fresh tag to the current objects META-L : apply the last (highest) tag to the current objects Things Mode ----------- SPACE : add a new thing d : disconnect things at the same location m : move selected things to occupy the same location w : rotate things 45 degrees anti-clockwise x : rotate things 45 degrees clockwise Vertex Mode ----------- SPACE * add a new vertex (begin drawing mode) * if a vertex is already selected, adds a new linedef too * with SHIFT key: continue in drawing mode * with CTRL key: inhibit creation of sectors d : disconnect all linedefs at the selected vertices m : merge selected vertices into a single one I : reshape selected vertices into a line O : reshape selected vertices into a circle D : reshape selected vertices into a half-circle C : reshape selected vertices into a 120-degree arc Q : reshape selected vertices into a 240-degree arc Linedef Mode ------------ e : select a chain of linedefs E : select a chain of linedefs with same textures w : flip linedefs k : split linedefs in two d : disconnect selected linedefs from the rest m : merge two one-sided linedefs into a two-sided linedef Sector Mode ----------- SPACE * add a new sector to area around the mouse pointer * fix broken sectoring in an area (use CTRL key to force a new sector) * if a sector is selected, copy that sector instead of using defaults d : disconnect sector(s) from their neighbors m : merge all selected sectors into a single one w : swap floor and ceiling textures e : select sectors with same floor height E : select sectors with same floor texture , and < : lower floor heights . and > : raise floor heights [ and { : lower ceiling heights ] and } : raise ceiling heights 3D Preview ---------- (Cursor keys will move forward and back, turn left and right) (the WASD keys can also be used to move the camera) LMB : not implemented yet RMB : turn or move the camera (by dragging the mouse) MMB : adjust sidedef offsets (drag the mouse) wheel : move camera forwards or backwards PGUP and PGDN : move camera up and down g : toggle gravity (i.e. as if the player was on the ground) l : toggle lighting on or off t : toggle texturing on or off o : toggle objects on or off F11 : increase brightness (gamma) c : clear offsets on highlighted sidedef x : align X offset with wall to the left y : align Y offset with wall to the left z : align both X + Y offsets X : align X offset with wall to the right Y : align Y offset with wall to the right Z : align both X + Y offsets COPYRIGHT and LICENSE Eureka DOOM Editor Copyright (C) 2001-2016 Andrew Apted, et al Copyright (C) 2014-2015 Ioan Chera Copyright (C) 1997-2003 Andre Majorel et al Eureka 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. Eureka 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. CONTACT DETAILS Web: http://eureka-editor.sourceforge.net/ Email: eureka-1.11-source/mods/0000755000175100017510000000000012651564503014437 5ustar aaptedaaptedeureka-1.11-source/GPL.txt0000644000175100017510000004325412647061302014662 0ustar aaptedaapted GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General Public License instead of this License. eureka-1.11-source/glbsp_src/0000755000175100017510000000000012651311507015445 5ustar aaptedaaptedeureka-1.11-source/glbsp_src/structs.h0000644000175100017510000001433512647061302017333 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" namespace glbsp { /* ----- 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; } // namespace glbsp #endif /* __GLBSP_STRUCTS_H__ */ eureka-1.11-source/glbsp_src/reject.cc0000644000175100017510000001154212647061302017233 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" namespace glbsp { #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 = (uint8_g *)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); } } // namespace glbsp eureka-1.11-source/glbsp_src/system.cc0000644000175100017510000001333612647061302017306 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 namespace glbsp { #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; } } // namespace glbsp eureka-1.11-source/glbsp_src/glbsp.cc0000644000175100017510000003260312647061302017067 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" namespace glbsp { 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 ParseArgs(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 (UtilCheckExtension(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 CheckInfo(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 (UtilCheckExtension(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(UtilReplaceExtension( info->input_file, "gwa")); info->gwa_mode = TRUE; info->missing_output = TRUE; } else /* has output filename */ { if (UtilCheckExtension(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; bbox_t seg_bbox; node_t *root_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(); FindLimits(seg_list, &seg_bbox); // recursively create nodes ret = BuildNodes(seg_list, &root_node, &root_sub, 0, &seg_bbox); 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 BuildNodes(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; } } // namespace glbsp eureka-1.11-source/glbsp_src/seg.cc0000644000175100017510000007423112647061302016541 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" namespace glbsp { #define PRECIOUS_MULTIPLY 100 #define SEG_FAST_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 = (intersection_t *) 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 void EvaluateFastWorker(superblock_t *seg_list, seg_t **best_H, seg_t **best_V, int mid_x, int mid_y) { seg_t *part; int num; for (part=seg_list->segs; part; part = part->next) { /* ignore minisegs as partition candidates */ if (! part->linedef) continue; if (part->pdy == 0) { // horizontal seg if (! *best_H) *best_H = part; else { int old_dist = abs((int)(*best_H)->psy - mid_y); int new_dist = abs((int)( part)->psy - mid_y); if (new_dist < old_dist) *best_H = part; } } else if (part->pdx == 0) { // vertical seg if (! *best_V) *best_V = part; else { int old_dist = abs((int)(*best_V)->psx - mid_x); int new_dist = abs((int)( part)->psx - mid_x); if (new_dist < old_dist) *best_V = part; } } } /* handle sub-blocks recursively */ for (num=0; num < 2; num++) { if (! seg_list->subs[num]) continue; EvaluateFastWorker(seg_list->subs[num], best_H, best_V, mid_x, mid_y); } } static seg_t *FindFastSeg(superblock_t *seg_list, const bbox_t *bbox) { seg_t *best_H = NULL; seg_t *best_V = NULL; int mid_x = (bbox->minx + bbox->maxx) / 2; int mid_y = (bbox->miny + bbox->maxy) / 2; EvaluateFastWorker(seg_list, &best_H, &best_V, mid_x, mid_y); int H_cost = -1; int V_cost = -1; if (best_H) H_cost = EvalPartition(seg_list, best_H, 99999999); if (best_V) V_cost = EvalPartition(seg_list, best_V, 99999999); # if DEBUG_PICKNODE PrintDebug("FindFastSeg: best_H=%p (cost %d) | best_V=%p (cost %d)\n", best_H, H_cost, best_V, V_cost); # endif if (H_cost < 0 && V_cost < 0) return NULL; if (H_cost < 0) return best_V; if (V_cost < 0) return best_H; return (V_cost < H_cost) ? best_V : best_H; } /* 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, const bbox_t *bbox) { seg_t *best=NULL; int best_cost=INT_MAX; int progress=0; int prog_step=1<<24; int build_step=0; # if DEBUG_PICKNODE PrintDebug("PickNode: BEGUN (depth %d)\n", depth); # endif /* compute info for showing progress */ if (depth <= 6) { static int depth_counts[7] = { 248, 100, 30, 10, 6, 4, 2 }; int total = seg_list->real_num + seg_list->mini_num; build_step = depth_counts[depth]; prog_step = 1 + ((total - 1) / build_step); if (total / prog_step < build_step) { cur_comms->build_pos += build_step - total / prog_step; build_step = total / prog_step; DisplaySetBar(1, cur_comms->build_pos); DisplaySetBar(2, cur_comms->file_pos + cur_comms->build_pos / 100); } } DisplayTicker(); /* -AJA- another (optional) optimisation, when building just the GL * nodes. We assume that the original nodes are reasonably * good choices, and re-use them as much as possible, saving * *heaps* of time on really large levels. */ if (cur_info->fast && seg_list->real_num >= SEG_FAST_THRESHHOLD) { # if DEBUG_PICKNODE PrintDebug("PickNode: Looking for Fast node...\n"); # endif best = FindFastSeg(seg_list, bbox); if (best) { /* update progress */ cur_comms->build_pos += build_step; DisplaySetBar(1, cur_comms->build_pos); DisplaySetBar(2, cur_comms->file_pos + cur_comms->build_pos / 100); # if DEBUG_PICKNODE PrintDebug("PickNode: Using Fast node (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", best->start->x, best->start->y, best->end->x, best->end->y); # endif return best; } } if (FALSE == PickNodeWorker(seg_list, seg_list, &best, &best_cost, &progress, prog_step)) { /* hack here : BuildNodes will detect the cancellation */ return NULL; } # if DEBUG_PICKNODE if (! best) { PrintDebug("PickNode: NO BEST FOUND !\n"); } else { PrintDebug("PickNode: Best has score %d.%02d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", best_cost / 100, best_cost % 100, best->start->x, best->start->y, best->end->x, best->end->y); } # endif /* all finished, return best Seg */ return best; } // // 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; } } } // namespace glbsp eureka-1.11-source/glbsp_src/blockmap.cc0000644000175100017510000003216412647061302017552 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" namespace glbsp { #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 = (uint16_g *)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 = (uint16_g *)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 = (uint16_g **) 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 = (uint16_g *)UtilCalloc(block_count * sizeof(uint16_g)); block_dups = (uint16_g *)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(); } } // namespace glbsp eureka-1.11-source/glbsp_src/level.h0000644000175100017510000002410212647061302016724 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" namespace glbsp { 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; // this is normally FALSE, only set for the "no nodes hack" // [ see comments in the BuildNodes() function. ] int is_dummy; } 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_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); 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); // 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); } // namespace glbsp #endif /* __GLBSP_LEVEL_H__ */ eureka-1.11-source/glbsp_src/util.h0000644000175100017510000000575712647061302016611 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__ namespace glbsp { /* ----- 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); } // namespace glbsp #endif /* __GLBSP_UTIL_H__ */ eureka-1.11-source/glbsp_src/seg.h0000644000175100017510000000754712647061302016411 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" namespace glbsp { #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. // seg_t *PickNode(superblock_t *seg_list, int depth, const bbox_t *bbox); // 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); } // namespace glbsp #endif /* __GLBSP_SEG_H__ */ eureka-1.11-source/glbsp_src/node.h0000644000175100017510000000623412647061302016550 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" namespace glbsp { // 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, const bbox_t *bbox); // 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); } // namespace glbsp #endif /* __GLBSP_NODE_H__ */ eureka-1.11-source/glbsp_src/analyze.h0000644000175100017510000000427512647061302017271 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" namespace glbsp { // 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); } // namespace glbsp #endif /* __GLBSP_ANALYZE_H__ */ eureka-1.11-source/glbsp_src/reject.h0000644000175100017510000000220512647061302017071 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" namespace glbsp { // build the reject table and write it into the REJECT lump void PutReject(void); } // namespace glbsp #endif /* __GLBSP_REJECT_H__ */ eureka-1.11-source/glbsp_src/glbsp.h0000644000175100017510000002204312647061302016726 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__ /** Eureka change: namespacing */ namespace glbsp { #define GLBSP_VER "2.27" #define GLBSP_VER_HEX 0x227 // certain GCC attributes can be useful #undef GCCATTR #ifdef __GNUC__ #define GCCATTR(xyz) __attribute__ (xyz) #else #define GCCATTR(xyz) /* nothing */ #endif /** OBLIGE change: assume C++ **/ // #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 ParseArgs(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 CheckInfo(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 BuildNodes(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); } // namespace glbsp #endif /* __GLBSP_GLBSP_H__ */ eureka-1.11-source/glbsp_src/blockmap.h0000644000175100017510000000276012647061302017413 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" namespace glbsp { #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); } // namespace glbsp #endif /* __GLBSP_BLOCKMAP_H__ */ eureka-1.11-source/glbsp_src/node.cc0000644000175100017510000007445312647061302016716 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" namespace glbsp { #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 (superblock_t *)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; if (sub->is_dummy) return; // 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 = (seg_t **) 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 static seg_t * CreateDummySeg(seg_t *orig) { seg_t *dummy = NewSeg(); // copy most stuff from original seg memcpy(dummy, orig, sizeof(seg_t)); dummy->next = NULL; dummy->partner = NULL; dummy->block = NULL; dummy->index = num_complete_seg; num_complete_seg++; return dummy; } static node_t * CreateDummyNode(superblock_t *seg_list) { node_t *node; seg_t *best; PrintWarn("LEVEL TOO SIMPLE, creating a dummy node...\n"); // first seg of the whole list will be our partition line // (the choice is totally arbitrary) best = seg_list->segs; node = NewNode(); 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; FindLimits(seg_list, &node->l.bounds); FindLimits(seg_list, &node->r.bounds); // the right side will have a normal subsector node->r.subsec = CreateSubsec(seg_list); // the left side gets a fake subsector node->l.subsec = NewSubsec(); node->l.subsec->seg_list = CreateDummySeg(best); node->l.subsec->seg_count = 1; node->l.subsec->index = num_subsecs - 1; node->l.subsec->is_dummy = TRUE; return node; } // // BuildNodes // glbsp_ret_e BuildNodes(superblock_t *seg_list, node_t ** N, subsec_t ** S, int depth, const bbox_t *bbox) { node_t *node; seg_t *best; superblock_t *rights; superblock_t *lefts; intersection_t *cut_list; 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, bbox); if (best == NULL) { if (cur_comms->cancelled) return GLBSP_E_Cancelled; # if DEBUG_BUILDER PrintDebug("Build: CONVEX\n"); # endif #if 0 // turns out this was bogus -- AJA nov/2015 if (depth == 0) { /* -AJA- welcome to Hack Central, hope you enjoy your stay. * * Vanilla DOOM (and some source ports) do not function when * there are no nodes at all. For this case we create a dummy * node with the real subsector on one side, and a fake-ish * subsector (containing a copy of a seg) on the other side. * * Tested in Chocolate Doom, PrBoom, Legacy and Odamex, with * no problems. * * [ P.S. no need to set *S here ] */ *N = CreateDummyNode(seg_list); } else #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, &node->l.bounds); 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, &node->r.bounds); 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); if (sub->is_dummy) continue; 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 (sub->is_dummy) return; # 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 (sub->is_dummy) return; # 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. // } // namespace glbsp eureka-1.11-source/glbsp_src/util.cc0000644000175100017510000001255212647061302016736 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 namespace glbsp { // // 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; } 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 = (char *) 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 */ } } // namespace glbsp eureka-1.11-source/glbsp_src/wad.cc0000644000175100017510000010014312647061302016526 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" namespace glbsp { 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 = (level_t *) 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 = (lump_t *) 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; } /* ---------------------------------------------------------------- */ // // UtilCheckExtension // int UtilCheckExtension(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] == '.'); } // // UtilReplaceExtension // char *UtilReplaceExtension(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, (int)strlen(keyword)); AppendLevelLump(gl_level, "=", 1); AppendLevelLump(gl_level, value, (int)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 = UtilReplaceExtension(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"); } } // namespace glbsp eureka-1.11-source/glbsp_src/wad.h0000644000175100017510000001477212647061302016404 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" namespace glbsp { struct lump_s; // wad header #define IWAD 0 #define PWAD 1 typedef struct wad_s { // kind of wad file : IWAD or PWAD int 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 UtilCheckExtension(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 *UtilReplaceExtension(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))) } // namespace glbsp #endif /* __GLBSP_WAD_H__ */ eureka-1.11-source/glbsp_src/level.cc0000644000175100017510000011534512647061302017074 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" namespace glbsp { #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(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 = (TYPE **) 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) 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 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") /* ----- 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; } } 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(const 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(const 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(const 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 (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(); 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, (uint8_g*) lump->data, lump->length); lump = FindLevelLump("LINEDEFS"); if (lump && lump->length > 0) Adler32_AddBlock(&crc, (uint8_g*) 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(); } } // namespace glbsp eureka-1.11-source/glbsp_src/system.h0000644000175100017510000000526012647061302017145 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" namespace glbsp { // 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) } // namespace glbsp #endif /* __GLBSP_SYSTEM_H__ */ eureka-1.11-source/glbsp_src/analyze.cc0000644000175100017510000006145012647061302017425 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" namespace glbsp { #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 = (uint16_g *)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 = (uint16_g *)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 = (int *)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; } } // namespace glbsp eureka-1.11-source/ports/0000755000175100017510000000000012647061302014636 5ustar aaptedaaptedeureka-1.11-source/ports/vanilla.ugh0000644000175100017510000000213112647061302016766 0ustar aaptedaapted#------------------------------------------------------------------------ # VANILLA (i.e. plain DOOM.EXE) #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2015 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ feature medusa_bug 1 eureka-1.11-source/ports/eternity.ugh0000644000175100017510000004104712647061302017214 0ustar aaptedaapted#------------------------------------------------------------------------ # Eternity Source Port #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2015 Ioan Chera # Copyright (C) 2001-2015 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ include "boom" feature 3d_midtex 1 #TODO: thing flag 512 "Dormant" - like in Hexen #---- THINGS ------------ thinggroup s DAD "Environment Sounds" thing 5003 - nv 20 NULL "EE: Camera spot" thing 5004 - nv 20 NULL "EE: ExtraData" thing 5006 - nv 20 NULL "EE: SkyBox camera" thing 5007 - nv 20 NULL "EE: Particle drip" thing 9001 - nv 20 NULL "EE: Map spot" thing 9013 - nv 20 NULL "EE: Map spot w/ gravity" thing 9027 - nv 20 NULL "EE: Red fountain" thing 9028 - nv 20 NULL "EE: Green fountain" thing 9029 - nv 20 NULL "EE: Blue fountain" thing 9030 - nv 20 NULL "EE: Yellow fountain" thing 9031 - nv 20 NULL "EE: Purple fountain" thing 9032 - nv 20 NULL "EE: Black fountain" thing 9033 - nv 20 NULL "EE: White fountain" thing 9300 - nv 16 NULL "EE: Polyobj anchor" thing 9301 - nv 16 NULL "EE: Polyobj spawnspot" thing 9302 - nv 16 NULL "EE: Polycrush spawnspot" thing 9303 - nv 16 NULL "EE: Polyburn spawnspot" thing 1200 s nv 16 NULL "EE: Enviro Sequence 00" thing 1201 s nv 16 NULL "EE: Enviro Sequence 01" thing 1202 s nv 16 NULL "EE: Enviro Sequence 02" thing 1203 s nv 16 NULL "EE: Enviro Sequence 03" thing 1204 s nv 16 NULL "EE: Enviro Sequence 04" thing 1205 s nv 16 NULL "EE: Enviro Sequence 05" thing 1206 s nv 16 NULL "EE: Enviro Sequence 06" thing 1207 s nv 16 NULL "EE: Enviro Sequence 07" thing 1208 s nv 16 NULL "EE: Enviro Sequence 08" thing 1209 s nv 16 NULL "EE: Enviro Sequence 09" thing 1210 s nv 16 NULL "EE: Enviro Sequence 10" thing 1211 s nv 16 NULL "EE: Enviro Sequence 11" thing 1212 s nv 16 NULL "EE: Enviro Sequence 12" thing 1213 s nv 16 NULL "EE: Enviro Sequence 13" thing 1214 s nv 16 NULL "EE: Enviro Sequence 14" thing 1215 s nv 16 NULL "EE: Enviro Sequence 15" thing 1216 s nv 16 NULL "EE: Enviro Sequence 16" thing 1217 s nv 16 NULL "EE: Enviro Sequence 17" thing 1218 s nv 16 NULL "EE: Enviro Sequence 18" thing 1219 s nv 16 NULL "EE: Enviro Sequence 19" thing 1220 s nv 16 NULL "EE: Enviro Sequence 20" thing 1221 s nv 16 NULL "EE: Enviro Sequence 21" thing 1222 s nv 16 NULL "EE: Enviro Sequence 22" thing 1223 s nv 16 NULL "EE: Enviro Sequence 23" thing 1224 s nv 16 NULL "EE: Enviro Sequence 24" thing 1225 s nv 16 NULL "EE: Enviro Sequence 25" thing 1226 s nv 16 NULL "EE: Enviro Sequence 26" thing 1227 s nv 16 NULL "EE: Enviro Sequence 27" thing 1228 s nv 16 NULL "EE: Enviro Sequence 28" thing 1229 s nv 16 NULL "EE: Enviro Sequence 29" thing 1230 s nv 16 NULL "EE: Enviro Sequence 30" thing 1231 s nv 16 NULL "EE: Enviro Sequence 31" thing 1232 s nv 16 NULL "EE: Enviro Sequence 32" thing 1233 s nv 16 NULL "EE: Enviro Sequence 33" thing 1234 s nv 16 NULL "EE: Enviro Sequence 34" thing 1235 s nv 16 NULL "EE: Enviro Sequence 35" thing 1236 s nv 16 NULL "EE: Enviro Sequence 36" thing 1237 s nv 16 NULL "EE: Enviro Sequence 37" thing 1238 s nv 16 NULL "EE: Enviro Sequence 38" thing 1239 s nv 16 NULL "EE: Enviro Sequence 39" thing 1240 s nv 16 NULL "EE: Enviro Sequence 40" thing 1241 s nv 16 NULL "EE: Enviro Sequence 41" thing 1242 s nv 16 NULL "EE: Enviro Sequence 42" thing 1243 s nv 16 NULL "EE: Enviro Sequence 43" thing 1244 s nv 16 NULL "EE: Enviro Sequence 44" thing 1245 s nv 16 NULL "EE: Enviro Sequence 45" thing 1246 s nv 16 NULL "EE: Enviro Sequence 46" thing 1247 s nv 16 NULL "EE: Enviro Sequence 47" thing 1248 s nv 16 NULL "EE: Enviro Sequence 48" thing 1249 s nv 16 NULL "EE: Enviro Sequence 49" thing 1250 s nv 16 NULL "EE: Enviro Sequence 50" thing 1251 s nv 16 NULL "EE: Enviro Sequence 51" thing 1252 s nv 16 NULL "EE: Enviro Sequence 52" thing 1253 s nv 16 NULL "EE: Enviro Sequence 53" thing 1254 s nv 16 NULL "EE: Enviro Sequence 54" thing 1255 s nv 16 NULL "EE: Enviro Sequence 55" thing 1256 s nv 16 NULL "EE: Enviro Sequence 56" thing 1257 s nv 16 NULL "EE: Enviro Sequence 57" thing 1258 s nv 16 NULL "EE: Enviro Sequence 58" thing 1259 s nv 16 NULL "EE: Enviro Sequence 59" thing 1260 s nv 16 NULL "EE: Enviro Sequence 60" thing 1261 s nv 16 NULL "EE: Enviro Sequence 61" thing 1262 s nv 16 NULL "EE: Enviro Sequence 62" thing 1263 s nv 16 NULL "EE: Enviro Sequence 63" thing 1264 s nv 16 NULL "EE: Enviro Sequence 64" thing 1265 s nv 16 NULL "EE: Enviro Sequence 65" thing 1266 s nv 16 NULL "EE: Enviro Sequence 66" thing 1267 s nv 16 NULL "EE: Enviro Sequence 67" thing 1268 s nv 16 NULL "EE: Enviro Sequence 68" thing 1269 s nv 16 NULL "EE: Enviro Sequence 69" thing 1270 s nv 16 NULL "EE: Enviro Sequence 70" thing 1271 s nv 16 NULL "EE: Enviro Sequence 71" thing 1272 s nv 16 NULL "EE: Enviro Sequence 72" thing 1273 s nv 16 NULL "EE: Enviro Sequence 73" thing 1274 s nv 16 NULL "EE: Enviro Sequence 74" thing 1275 s nv 16 NULL "EE: Enviro Sequence 75" thing 1276 s nv 16 NULL "EE: Enviro Sequence 76" thing 1277 s nv 16 NULL "EE: Enviro Sequence 77" thing 1278 s nv 16 NULL "EE: Enviro Sequence 78" thing 1279 s nv 16 NULL "EE: Enviro Sequence 79" thing 1280 s nv 16 NULL "EE: Enviro Sequence 80" thing 1281 s nv 16 NULL "EE: Enviro Sequence 81" thing 1282 s nv 16 NULL "EE: Enviro Sequence 82" thing 1283 s nv 16 NULL "EE: Enviro Sequence 83" thing 1284 s nv 16 NULL "EE: Enviro Sequence 84" thing 1285 s nv 16 NULL "EE: Enviro Sequence 85" thing 1286 s nv 16 NULL "EE: Enviro Sequence 86" thing 1287 s nv 16 NULL "EE: Enviro Sequence 87" thing 1288 s nv 16 NULL "EE: Enviro Sequence 88" thing 1289 s nv 16 NULL "EE: Enviro Sequence 89" thing 1290 s nv 16 NULL "EE: Enviro Sequence 90" thing 1291 s nv 16 NULL "EE: Enviro Sequence 91" thing 1292 s nv 16 NULL "EE: Enviro Sequence 92" thing 1293 s nv 16 NULL "EE: Enviro Sequence 93" thing 1294 s nv 16 NULL "EE: Enviro Sequence 94" thing 1295 s nv 16 NULL "EE: Enviro Sequence 95" thing 1296 s nv 16 NULL "EE: Enviro Sequence 96" thing 1297 s nv 16 NULL "EE: Enviro Sequence 97" thing 1298 s nv 16 NULL "EE: Enviro Sequence 98" thing 1299 s nv 16 NULL "EE: Enviro Sequence 99" thing 1300 s nv 16 NULL "EE: Enviro Sequence Ex" thing 1400 s nv 16 NULL "EE: Sector Sequence 00" thing 1401 s nv 16 NULL "EE: Sector Sequence 01" thing 1402 s nv 16 NULL "EE: Sector Sequence 02" thing 1403 s nv 16 NULL "EE: Sector Sequence 03" thing 1404 s nv 16 NULL "EE: Sector Sequence 04" thing 1405 s nv 16 NULL "EE: Sector Sequence 05" thing 1406 s nv 16 NULL "EE: Sector Sequence 06" thing 1407 s nv 16 NULL "EE: Sector Sequence 07" thing 1408 s nv 16 NULL "EE: Sector Sequence 08" thing 1409 s nv 16 NULL "EE: Sector Sequence 09" thing 1410 s nv 16 NULL "EE: Sector Sequence 10" thing 1411 s nv 16 NULL "EE: Sector Sequence 11" thing 1412 s nv 16 NULL "EE: Sector Sequence 12" thing 1413 s nv 16 NULL "EE: Sector Sequence 13" thing 1414 s nv 16 NULL "EE: Sector Sequence 14" thing 1415 s nv 16 NULL "EE: Sector Sequence 15" thing 1416 s nv 16 NULL "EE: Sector Sequence 16" thing 1417 s nv 16 NULL "EE: Sector Sequence 17" thing 1418 s nv 16 NULL "EE: Sector Sequence 18" thing 1419 s nv 16 NULL "EE: Sector Sequence 19" thing 1420 s nv 16 NULL "EE: Sector Sequence 20" thing 1421 s nv 16 NULL "EE: Sector Sequence 21" thing 1422 s nv 16 NULL "EE: Sector Sequence 22" thing 1423 s nv 16 NULL "EE: Sector Sequence 23" thing 1424 s nv 16 NULL "EE: Sector Sequence 24" thing 1425 s nv 16 NULL "EE: Sector Sequence 25" thing 1426 s nv 16 NULL "EE: Sector Sequence 26" thing 1427 s nv 16 NULL "EE: Sector Sequence 27" thing 1428 s nv 16 NULL "EE: Sector Sequence 28" thing 1429 s nv 16 NULL "EE: Sector Sequence 29" thing 1430 s nv 16 NULL "EE: Sector Sequence 30" thing 1431 s nv 16 NULL "EE: Sector Sequence 31" thing 1432 s nv 16 NULL "EE: Sector Sequence 32" thing 1433 s nv 16 NULL "EE: Sector Sequence 33" thing 1434 s nv 16 NULL "EE: Sector Sequence 34" thing 1435 s nv 16 NULL "EE: Sector Sequence 35" thing 1436 s nv 16 NULL "EE: Sector Sequence 36" thing 1437 s nv 16 NULL "EE: Sector Sequence 37" thing 1438 s nv 16 NULL "EE: Sector Sequence 38" thing 1439 s nv 16 NULL "EE: Sector Sequence 39" thing 1440 s nv 16 NULL "EE: Sector Sequence 40" thing 1441 s nv 16 NULL "EE: Sector Sequence 41" thing 1442 s nv 16 NULL "EE: Sector Sequence 42" thing 1443 s nv 16 NULL "EE: Sector Sequence 43" thing 1444 s nv 16 NULL "EE: Sector Sequence 44" thing 1445 s nv 16 NULL "EE: Sector Sequence 45" thing 1446 s nv 16 NULL "EE: Sector Sequence 46" thing 1447 s nv 16 NULL "EE: Sector Sequence 47" thing 1448 s nv 16 NULL "EE: Sector Sequence 48" thing 1449 s nv 16 NULL "EE: Sector Sequence 49" thing 1450 s nv 16 NULL "EE: Sector Sequence 50" thing 1451 s nv 16 NULL "EE: Sector Sequence 51" thing 1452 s nv 16 NULL "EE: Sector Sequence 52" thing 1453 s nv 16 NULL "EE: Sector Sequence 53" thing 1454 s nv 16 NULL "EE: Sector Sequence 54" thing 1455 s nv 16 NULL "EE: Sector Sequence 55" thing 1456 s nv 16 NULL "EE: Sector Sequence 56" thing 1457 s nv 16 NULL "EE: Sector Sequence 57" thing 1458 s nv 16 NULL "EE: Sector Sequence 58" thing 1459 s nv 16 NULL "EE: Sector Sequence 59" thing 1460 s nv 16 NULL "EE: Sector Sequence 60" thing 1461 s nv 16 NULL "EE: Sector Sequence 61" thing 1462 s nv 16 NULL "EE: Sector Sequence 62" thing 1463 s nv 16 NULL "EE: Sector Sequence 63" thing 1464 s nv 16 NULL "EE: Sector Sequence 64" thing 1465 s nv 16 NULL "EE: Sector Sequence 65" thing 1466 s nv 16 NULL "EE: Sector Sequence 66" thing 1467 s nv 16 NULL "EE: Sector Sequence 67" thing 1468 s nv 16 NULL "EE: Sector Sequence 68" thing 1469 s nv 16 NULL "EE: Sector Sequence 69" thing 1470 s nv 16 NULL "EE: Sector Sequence 70" thing 1471 s nv 16 NULL "EE: Sector Sequence 71" thing 1472 s nv 16 NULL "EE: Sector Sequence 72" thing 1473 s nv 16 NULL "EE: Sector Sequence 73" thing 1474 s nv 16 NULL "EE: Sector Sequence 74" thing 1475 s nv 16 NULL "EE: Sector Sequence 75" thing 1476 s nv 16 NULL "EE: Sector Sequence 76" thing 1477 s nv 16 NULL "EE: Sector Sequence 77" thing 1478 s nv 16 NULL "EE: Sector Sequence 78" thing 1479 s nv 16 NULL "EE: Sector Sequence 79" thing 1480 s nv 16 NULL "EE: Sector Sequence 80" thing 1481 s nv 16 NULL "EE: Sector Sequence 81" thing 1482 s nv 16 NULL "EE: Sector Sequence 82" thing 1483 s nv 16 NULL "EE: Sector Sequence 83" thing 1484 s nv 16 NULL "EE: Sector Sequence 84" thing 1485 s nv 16 NULL "EE: Sector Sequence 85" thing 1486 s nv 16 NULL "EE: Sector Sequence 86" thing 1487 s nv 16 NULL "EE: Sector Sequence 87" thing 1488 s nv 16 NULL "EE: Sector Sequence 88" thing 1489 s nv 16 NULL "EE: Sector Sequence 89" thing 1490 s nv 16 NULL "EE: Sector Sequence 90" thing 1491 s nv 16 NULL "EE: Sector Sequence 91" thing 1492 s nv 16 NULL "EE: Sector Sequence 92" thing 1493 s nv 16 NULL "EE: Sector Sequence 93" thing 1494 s nv 16 NULL "EE: Sector Sequence 94" thing 1495 s nv 16 NULL "EE: Sector Sequence 95" thing 1496 s nv 16 NULL "EE: Sector Sequence 96" thing 1497 s nv 16 NULL "EE: Sector Sequence 97" thing 1498 s nv 16 NULL "EE: Sector Sequence 98" thing 1499 s nv 16 NULL "EE: Sector Sequence 99" thing 1500 s nv 16 NULL "EE: Sector Sequence Ex" thing 14001 s nv 16 NULL "EE: Ambience 01" thing 14002 s nv 16 NULL "EE: Ambience 02" thing 14003 s nv 16 NULL "EE: Ambience 03" thing 14004 s nv 16 NULL "EE: Ambience 04" thing 14005 s nv 16 NULL "EE: Ambience 05" thing 14006 s nv 16 NULL "EE: Ambience 06" thing 14007 s nv 16 NULL "EE: Ambience 07" thing 14008 s nv 16 NULL "EE: Ambience 08" thing 14009 s nv 16 NULL "EE: Ambience 09" thing 14010 s nv 16 NULL "EE: Ambience 10" thing 14011 s nv 16 NULL "EE: Ambience 11" thing 14012 s nv 16 NULL "EE: Ambience 12" thing 14013 s nv 16 NULL "EE: Ambience 13" thing 14014 s nv 16 NULL "EE: Ambience 14" thing 14015 s nv 16 NULL "EE: Ambience 15" thing 14016 s nv 16 NULL "EE: Ambience 16" thing 14017 s nv 16 NULL "EE: Ambience 17" thing 14018 s nv 16 NULL "EE: Ambience 18" thing 14019 s nv 16 NULL "EE: Ambience 19" thing 14020 s nv 16 NULL "EE: Ambience 20" thing 14021 s nv 16 NULL "EE: Ambience 21" thing 14022 s nv 16 NULL "EE: Ambience 22" thing 14023 s nv 16 NULL "EE: Ambience 23" thing 14024 s nv 16 NULL "EE: Ambience 24" thing 14025 s nv 16 NULL "EE: Ambience 25" thing 14026 s nv 16 NULL "EE: Ambience 26" thing 14027 s nv 16 NULL "EE: Ambience 27" thing 14028 s nv 16 NULL "EE: Ambience 28" thing 14029 s nv 16 NULL "EE: Ambience 29" thing 14030 s nv 16 NULL "EE: Ambience 30" thing 14031 s nv 16 NULL "EE: Ambience 31" thing 14032 s nv 16 NULL "EE: Ambience 32" thing 14033 s nv 16 NULL "EE: Ambience 33" thing 14034 s nv 16 NULL "EE: Ambience 34" thing 14035 s nv 16 NULL "EE: Ambience 35" thing 14036 s nv 16 NULL "EE: Ambience 36" thing 14037 s nv 16 NULL "EE: Ambience 37" thing 14038 s nv 16 NULL "EE: Ambience 38" thing 14039 s nv 16 NULL "EE: Ambience 39" thing 14040 s nv 16 NULL "EE: Ambience 40" thing 14041 s nv 16 NULL "EE: Ambience 41" thing 14042 s nv 16 NULL "EE: Ambience 42" thing 14043 s nv 16 NULL "EE: Ambience 43" thing 14044 s nv 16 NULL "EE: Ambience 44" thing 14045 s nv 16 NULL "EE: Ambience 45" thing 14046 s nv 16 NULL "EE: Ambience 46" thing 14047 s nv 16 NULL "EE: Ambience 47" thing 14048 s nv 16 NULL "EE: Ambience 48" thing 14049 s nv 16 NULL "EE: Ambience 49" thing 14050 s nv 16 NULL "EE: Ambience 50" thing 14051 s nv 16 NULL "EE: Ambience 51" thing 14052 s nv 16 NULL "EE: Ambience 52" thing 14053 s nv 16 NULL "EE: Ambience 53" thing 14054 s nv 16 NULL "EE: Ambience 54" thing 14055 s nv 16 NULL "EE: Ambience 55" thing 14056 s nv 16 NULL "EE: Ambience 56" thing 14057 s nv 16 NULL "EE: Ambience 57" thing 14058 s nv 16 NULL "EE: Ambience 58" thing 14059 s nv 16 NULL "EE: Ambience 59" thing 14060 s nv 16 NULL "EE: Ambience 60" thing 14061 s nv 16 NULL "EE: Ambience 61" thing 14062 s nv 16 NULL "EE: Ambience 62" thing 14063 s nv 16 NULL "EE: Ambience 63" thing 14064 s nv 16 NULL "EE: Ambience 64" thing 14065 s nv 16 NULL "EE: Ambience Ex" #---- LINETYPES ---------- linegroup i "Slopes" linegroup o "Portals" linegroup r "Scripting" line 283 o "-- EE: Plane portal /c" line 284 o "-- EE: Plane portal /f" line 285 o "-- EE: Plane portal" line 286 o "-- EE: Horizon portal /c" line 287 o "-- EE: Horizon portal /f" line 288 o "-- EE: Horizon portal" line 290 o "-- EE: Skybox portal /c" line 291 o "-- EE: Skybox portal /f" line 292 o "-- EE: Skybox portal" line 295 o "-- EE: Anchor portal /c" line 296 o "-- EE: Anchor portal /f" line 297 o "-- EE: Anchor portal" line 298 o "-- EE: Anch line for 295,297" line 299 o "-- EE: Anch line for 296" line 344 o "-- EE: 2-way anc prt /c" line 345 o "-- EE: 2-way anc prt /f" line 346 o "-- EE: Anch line for 344" line 347 o "-- EE: Anch line for 345" line 289 o "-- EE: Portal transfer" line 358 o "-- EE: Linked portal /c" line 359 o "-- EE: Linked portal /f" line 360 o "-- EE: Link prt anch for 358" line 361 o "-- EE: Link prt anch for 359" line 376 o "-- EE: Link prt to tag lines" line 377 o "-- EE: Link prt anch for 376" line 385 o "-- EE: Link prt to front sec" line 386 i "-- EE: Slope front floor" line 387 i "-- EE: Slope front ceil" line 388 i "-- EE: Slope front f & c" line 389 i "-- EE: Slope back floor" line 390 i "-- EE: Slope back ceil" line 391 i "-- EE: Slope back f & c" line 392 i "-- EE: Slope back f & front c" line 393 i "-- EE: Slope back c & front f" line 394 i "-- EE: Front f to tag slope" line 395 i "-- EE: Front c to tag slope" line 396 i "-- EE: Front f, c to tag slp" line 280 r "WR EE: Exec Script" line 273 r "WR EE: Exec Script /1way" line 274 r "W1 EE: Exec Script" line 275 r "W1 EE: Exec Script /1way" line 276 r "SR EE: Exec Script" line 277 r "S1 EE: Exec Script" line 278 r "GR EE: Exec Script" line 279 r "G1 EE: Exec Script" line 270 - "-- EE: ExtraData" line 281 - "-- EE: 3D Midtex /f" line 282 - "-- EE: 3D Midtex /c" line 293 - "-- EE: Heretic wind" line 294 - "-- EE: Heretic current" line 379 - "-- EE: Attach set ceil ctrl" line 380 - "-- EE: Attach set floor ctrl" line 381 - "-- EE: Attach floor to ctrl" line 382 - "-- EE: Attach ceil to ctrl" line 383 - "-- EE: Mirror floor to ctrl" line 384 - "-- EE: Mirror ceil to ctrl" eureka-1.11-source/ports/boom.ugh0000644000175100017510000001512712647061302016305 0ustar aaptedaapted#------------------------------------------------------------------------ # BOOM definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2016 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ exclude_game heretic exclude_game hexen #---- BOOM FEATURES ------------- feature gen_types 1 feature coop_dm_flags 1 feature pass_through 1 # an MBF feature, but most "Boom Compatible" ports will support it feature friend_flag 1 #---- BOOM THINGS ------------- thing 5001 - nv 20 NULL "BOOM: Point pusher" thing 5002 - nv 20 NULL "BOOM: Point puller" # an MBF feature, but some "Boom Compatible" ports support it thing 888 - - 12 DOGS "Dog (MBF)" #---- BOOM LINETYPES ---------- line 85 - "-- BOOM: Scroll Wall Right" line 241 - "S1 BOOM: Floor Transfer /NXP" line 189 - "S1 BOOM: Floor Transfer /TXP" line 191 - "SR BOOM: Donut" line 190 - "SR BOOM: Floor Transfer /TXP" line 146 - "W1 BOOM: Donut" line 239 - "W1 BOOM: Floor Transfer /NXP" line 153 - "W1 BOOM: Floor Transfer /TXP" line 155 - "WR BOOM: Donut" line 240 - "WR BOOM: Floor Transfer /NXP" line 154 - "WR BOOM: Floor Transfer /TXP" line 164 h "S1 BOOM: Crusher" line 165 h "S1& BOOM: Crusher /silent" line 168 h "S1& BOOM: Stop crusher" line 183 h "SR BOOM: Crusher" line 185 h "SR& BOOM: Crusher /silent" line 184 h "SR& BOOM: Crusher /slow" line 188 h "SR& BOOM: Stop crusher" line 150 h "WR& BOOM: Crusher /silent" line 160 g "S1 BOOM: Floor up 24 /TXP" line 161 g "S1 BOOM: Floor up 24" line 158 g "S1 BOOM: Floor up lowest tex" line 179 g "SR BOOM: Floor up 24 /TXP" line 180 g "SR BOOM: Floor up 24" line 178 g "SR BOOM: Floor up 512" line 176 g "SR BOOM: Floor up lowest tex" line 142 g "W1 BOOM: Floor up 512" line 147 g "WR BOOM: Floor up 512" line 170 l "S1 BOOM: Light to 0" line 171 l "S1 BOOM: Light to 255" line 169 l "S1 BOOM: Light to highest nb" line 173 l "S1 BOOM: Light to lowest nb" line 172 l "S1 BOOM: Start Blinking" line 192 l "SR BOOM: Light to highest nb" line 194 l "SR BOOM: Light to lowest nb" line 193 l "SR BOOM: Start Blinking" line 157 l "WR BOOM: Light to lowest nb" line 156 l "WR BOOM: Start Blinking" line 167 c "S1 BOOM: Ceiling close flr+8" line 204 c "S1 BOOM: Ceiling down HEF" line 203 c "S1 BOOM: Ceiling down LEC" line 166 c "S1 BOOM: Ceiling up HEC" line 187 c "SR BOOM: Ceiling close flr+8" line 206 c "SR BOOM: Ceiling down HEF" line 205 c "SR BOOM: Ceiling down LEC" line 186 c "SR BOOM: Ceiling up HEC" line 145 c "W1 BOOM: Ceiling close" line 200 c "W1 BOOM: Ceiling down HEF" line 199 c "W1 BOOM: Ceiling down LEC" line 152 c "WR BOOM: Ceiling close" line 202 c "WR BOOM: Ceiling down HEF" line 201 c "WR BOOM: Ceiling down LEC" line 151 c "WR BOOM: Ceiling up HEC" line 175 d "S1 BOOM: Close for 30s" line 196 d "SR BOOM: Close for 30s" line 197 e "g1 BOOM: Exit level" line 198 e "g1 BOOM: Secret exit" line 159 f "S1 BOOM: Floor down LEF /NX" line 221 f "S1 BOOM: Floor down nlEF" line 177 f "SR BOOM: Floor down LEF /NX" line 222 f "SR BOOM: Floor down nlEF" line 219 f "W1 BOOM: Floor down nlEF" line 220 f "WR BOOM: Floor down nlEF" line 143 p "W1& BOOM: Floor up 24 /TX" line 144 p "W1& BOOM: Floor up 32 /TX" line 148 p "WR& BOOM: Floor up 24 /TX" line 149 p "WR& BOOM: Floor up 32 /TX" line 162 m "S1 BOOM: Start moving floor" line 163 m "S1 BOOM: Stop moving floor" line 211 m "SR BOOM: Floor Toggle" line 181 m "SR BOOM: Start moving floor" line 182 m "SR BOOM: Stop moving floor" line 212 m "WR BOOM: Floor Toggle" line 209 t "S1 BOOM: Teleport /keepdir" line 174 t "S1 BOOM: Teleport" line 210 t "SR BOOM: Teleport /keepdir" line 195 t "SR BOOM: Teleport" line 207 t "W1 BOOM: Teleport /keepdir" line 243 t "W1 BOOM: Teleport Line" line 208 t "WR BOOM: Teleport /keepdir" line 244 t "WR BOOM: Teleport Line" line 213 l "-- BOOM: Transfer floor light" line 261 l "-- BOOM: Transfer ceil light" line 223 - "-- BOOM: Friction" line 224 - "-- BOOM: Wind force" line 225 - "-- BOOM: Current force" line 226 - "-- BOOM: Point force" line 242 - "-- BOOM: Deep water" line 260 - "-- BOOM: Translucent" line 227 v "W1 BOOM: Elevator up" line 228 v "WR BOOM: Elevator up" line 229 v "S1 BOOM: Elevator up" line 230 v "SR BOOM: Elevator up" line 231 v "W1 BOOM: Elevator down" line 232 v "WR BOOM: Elevator down" line 233 v "S1 BOOM: Elevator down" line 234 v "SR BOOM: Elevator down" line 235 v "W1 BOOM: Elevator to trigger" line 236 v "WR BOOM: Elevator to trigger" line 237 v "S1 BOOM: Elevator to trigger" line 238 v "SR BOOM: Elevator to trigger" line 252 a "-- BOOM: Push floor" line 216 a "-- BOOM: Push floor /accel" line 247 a "-- BOOM: Push floor /disp" line 253 a "-- BOOM: Push/Scr floor" line 217 a "-- BOOM: Push/Scr floor /acc" line 248 a "-- BOOM: Push/Scr floor /dis" line 255 a "-- BOOM: Scroll X/Y offsets" line 254 a "-- BOOM: Scroll Wall /sync" line 214 a "-- BOOM: Scroll Ceil /accel" line 245 a "-- BOOM: Scroll Ceil /disp" line 250 a "-- BOOM: Scroll Ceil" line 215 a "-- BOOM: Scroll Floor /accel" line 246 a "-- BOOM: Scroll Floor /disp" line 251 a "-- BOOM: Scroll Floor" line 218 a "-- BOOM: Scroll Wall /accel" line 249 a "-- BOOM: Scroll Wall /disp" line 256 s "WR BOOM: Stair Raise 8" line 257 s "WR BOOM: Stair Raise 16" line 258 s "SR BOOM: Stair Raise 8" line 259 s "SR BOOM: Stair Raise 16" line 262 t "W1 BOOM: Teleport Line /r" line 263 t "WR BOOM: Teleport Line /r" line 264 t "W1 BOOM: Teleport Line /mon/r" line 265 t "WR BOOM: Teleport Line /mon/r" line 266 t "W1 BOOM: Teleport Line /mon" line 267 t "WR BOOM: Teleport Line /mon" line 268 t "W1 BOOM: Teleport /mon" line 269 t "WR BOOM: Teleport /mon" # these were not in the original BOOM, but are considered nowadays # to be features which "Boom-Compatible" source ports provide. line 271 - "-- MBF: Transfer sky" line 272 - "-- MBF: Mirror sky" #---- GENERALIZED LINETYPES ---------- include "gen_types" eureka-1.11-source/ports/legacy.ugh0000644000175100017510000001107612647061302016614 0ustar aaptedaapted#------------------------------------------------------------------------ # DOOMLEGACY 1.44 definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2012 Wesley Johnson # Copyright (C) 2001-2013 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. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ include "boom" #---- DOOMLEGACY THINGS ------------- thing 5003 - n 8 NULL "LEG: Camera" thing 5004 - n 16 NULL "LEG: Node" # JDS group player starts thing 4001 p - 16 NULL "Player 5 start" thing 4002 p - 16 NULL "Player 6 start" thing 4003 p - 16 NULL "Player 7 start" thing 4004 p - 16 NULL "Player 8 start" thing 4005 p - 16 NULL "Player 9 start" thing 4006 p - 16 NULL "Player 10 start" thing 4007 p - 16 NULL "Player 11 start" thing 4008 p - 16 NULL "Player 12 start" thing 4009 p - 16 NULL "Player 13 start" thing 4010 p - 16 NULL "Player 14 start" thing 4011 p - 16 NULL "Player 15 start" thing 4012 p - 16 NULL "Player 16 start" thing 4013 p - 16 NULL "Player 17 start" thing 4014 p - 16 NULL "Player 18 start" thing 4015 p - 16 NULL "Player 19 start" thing 4016 p - 16 NULL "Player 20 start" thing 4017 p - 16 NULL "Player 21 start" thing 4018 p - 16 NULL "Player 22 start" thing 4019 p - 16 NULL "Player 23 start" thing 4020 p - 16 NULL "Player 24 start" thing 4021 p - 16 NULL "Player 25 start" thing 4022 p - 16 NULL "Player 26 start" thing 4023 p - 16 NULL "Player 27 start" thing 4024 p - 16 NULL "Player 28 start" thing 4025 p - 16 NULL "Player 29 start" thing 4026 p - 16 NULL "Player 30 start" thing 4027 p - 16 NULL "Player 31 start" thing 4028 p - 16 NULL "Player 32 start" #---- DOOMLEGACY LINETYPES ---------- linegroup x "LEG: Extrafloor" linegroup y "LEG: Effects" linegroup z "LEG: FraggleScript" line 290 f "-- LEG: Instant lower floor" line 291 c "-- LEG: Instant raise ceil" line 284 y "-- LEG: Translucent MED" line 285 y "-- LEG: Translucent MORE" line 286 y "-- LEG: Translucent HI" line 287 y "-- LEG: Translucent FIRE" line 288 y "-- LEG: Translucent FX1 " line 280 y "-- LEG: Swim Water" line 282 y "-- LEG: Gen Colormap #UML" # side1 upper texture: #rrggbba ( or texture name ) Color # where: # rr, gg, bb= red, green, blue (hex 00..FF) # a= alpha (letter 'a'..'z') # side1 middle texture: #fssee ( or texture name ) # where: # f: (0,1) fog colormap # ss: (dec 0..32) Fade begin # ee: (dec 1..33) Fade end # side1 lower texture: #rrggbb ( or texture name ) Fade-to-color # where: # rr, gg, bb= red, green, blue (hex 00..FF) line 283 y "-- LEG: Fog sheet" line 281 x "-- LEG: Floor Solid shadow" line 289 x "-- LEG: Floor Solid" line 300 x "-- LEG: Floor Trans #U" # side1 upper texture: #aaa ( or texture name ) Alpha # where: aaa= alpha (0..255) line 301 x "-- LEG: 3d Water Translu #U" # side1 upper texture: #aaaf ( or texture name ) Alpha # where: # aaa= alpha (0..255) # f= fog effect (letter 'A'..'F') line 304 x "-- LEG: 3d Water Opaque #U" # side1 upper texture: #aaaf ( or texture name ) Alpha inside water # where: # aaa= alpha (0..255) # f= fog effect (letter 'A'..'F') line 302 x "-- LEG: 3d Fog #U" # side1 upper texture: #aaaf ( or texture name ) Alpha inside water # where: # aaa= alpha (0..255) # f= fog effect (letter 'A'..'F') # Fog effect chart # 'A'= Clear, no fog # 'B'= Cast # 'C'= Colormap # 'D'= Fog inside # 'E'= Fog lite # 'F'= Fog dust # 'G'= Fog distance # 'H'= Fog fluid line 303 x "-- LEG: 3d Ceiling Light" line 305 x "-- LEG: 3d Light Slab" line 306 x "-- LEG: Floor Invisible" # not in DoomLegacy line 271 - "-- (Unsupported)" # start the script with the tag number line 272 z "WR LEG: Script Trigger" line 273 z "WR LEG: Script 1-way" line 274 z "W1 LEG: Script Trigger" line 275 z "W1 LEG: Script 1-way" line 276 z "SR LEG: Script Trigger" line 277 z "S1 LEG: Script Trigger" line 278 z "GR LEG: Script Trigger" line 279 z "G1 LEG: Script Trigger" #linedef flags # Flag 1024 (0x400) "AllTrigger" eureka-1.11-source/ports/xdoom.ugh0000644000175100017510000000302712647061302016473 0ustar aaptedaapted#------------------------------------------------------------------------ # XDOOM (a port by Udo Monk) #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2013 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ #---- LINE TYPES ---------- linegroup x "XDoom" line 300 x "SR XDOOM: Sliding door" line 320 x "-- XDOOM: Laser barrier" line 321 x "SR XDOOM: Laser off /temp" line 322 x "G1 XDOOM: Laser off" line 333 x "S1 XDOOM: Laser off /msg" line 330 x "WR XDOOM: Message" line 331 x "W1 XDOOM: Message" line 334 x "M1 XDOOM: Message" line 332 x "S1 XDOOM: Teleport /msg" line 350 x "W1 XDOOM: Silent door" line 351 x "S1 XDOOM: Silent door" line 352 x "M1 XDOOM: Silent door" eureka-1.11-source/ports/edge.ugh0000644000175100017510000002476012647061302016260 0ustar aaptedaapted#------------------------------------------------------------------------ # EDGE 1.35 definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2013 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ include "boom" #---- EDGE THINGS ---------- thing 7000 b n 20 NVSC "EDGE: Night vision" thing 7020 b n 20 JPCK "EDGE: Jetpack" thing 7015 k nl 20 YKEY "EDGE: Green keycard" thing 7017 k nl 20 YSKU "EDGE: Green skull key" thing 7031 h nl 20 ARM2 "EDGE: Purple armor" thing 7032 h nl 20 ARM1 "EDGE: Yellow armor" thing 7033 h nl 20 ARM1 "EDGE: Red armor" thing 7010 d - 16 SMT2 "EDGE: Grey stub" thing 7011 d - 10 BEXP "EDGE: Unstable barrel" thing 7041 - n 16 NULL "EDGE: Green glow" thing 7042 - n 16 NULL "EDGE: Red glow" thing 7043 - n 16 NULL "EDGE: Blue glow" thing 888 m - 16 SARGA3A7 "EDGE: Dog" thing 4050 m i 64 BSPI "EDGE: Stealth Arachnotron" thing 4051 m i 20 VILE "EDGE: Stealth Archvile" thing 4052 m i 24 BOSS "EDGE: Stealth Baron" thing 4053 m i 31 HEAD "EDGE: Stealth Cacodemon" thing 4054 m i 20 CPOS "EDGE: Stealth Chaingunner" thing 4055 m i 30 SARG "EDGE: Stealth Demon" thing 4056 m i 24 BOS2A1C1 "EDGE: Stealth Hell Knight" thing 4057 m i 20 TROO "EDGE: Stealth Imp" thing 4058 m i 48 FATT "EDGE: Stealth Mancubus" thing 4059 m i 20 SKEL "EDGE: Stealth Revenant" thing 4060 m i 20 SPOS "EDGE: Stealth Sargeant" thing 4061 m i 20 POSS "EDGE: Stealth Trooper" thing 7100 m - 20 SKELJ "EDGE: Revenant mkII" thing 7101 m n 64 TFOGB "EDGE: Imp spawner" thing 7102 m - 64 BSPIH "EDGE: Arachnotron mkII" thing 7103 m - 48 FATTH "EDGE: Mancubus mkII" #---- EDGE LINE TYPES ---------- linegroup b "EDGE: Hubs" linegroup w "EDGE: Sliding Door" linegroup x "EDGE: Extrafloor" linegroup z "EDGE: RTS Script" line 400 x "-- EDGE: 3D Floor" line 401 x "-- EDGE: 3D Floor /upper" line 402 x "-- EDGE: 3D Floor /lower" line 403 x "-- EDGE: Liquid" line 404 x "-- EDGE: Liquid 80%" line 405 x "-- EDGE: Liquid 60%" line 406 x "-- EDGE: Liquid 40%" line 407 x "-- EDGE: Liquid 20%" line 408 x "-- EDGE: Liquid 0%" line 422 a "-- EDGE: Scroll right" line 423 a "-- EDGE: Scroll up" line 424 a "-- EDGE: Scroll down" line 425 a "-- EDGE: Scroll left/up" line 426 a "-- EDGE: Scroll left/down" line 427 a "-- EDGE: Scroll right/up" line 428 a "-- EDGE: Scroll right/down" line 567 s "-- EDGE: Slope Floor" line 568 s "-- EDGE: Slope Ceiling" line 569 s "-- EDGE: Slope F + C" line 409 a "-- EDGE: Translucency 80%" line 410 a "-- EDGE: Translucency 60%" line 411 a "-- EDGE: Translucency 40%" line 412 a "-- EDGE: Translucency 20%" line 413 x "-- EDGE: Thin 3D floor" line 414 x "-- EDGE: Thin 3D floor 80%" line 415 x "-- EDGE: Thin 3D floor 60%" line 416 x "-- EDGE: Thin 3D floor 40%" line 417 x "-- EDGE: Thin 3D floor 20%" line 442 w "DR Sliding door LEFT /mon" line 443 w "DR Sliding door LEFT" line 444 w "DR Sliding door LEFT /fast" line 445 w "D1 Sliding door LEFT" line 446 w "DR Sliding door RIGHT /mon" line 447 w "DR Sliding door RIGHT" line 448 w "DR Sliding door RIGHT /fast" line 449 w "D1 Sliding door RIGHT" line 450 w "DR Sliding door CENTER /mon" line 451 w "DR Sliding door CENTER" line 452 w "DR Sliding door CENTER /fast" line 453 w "D1 Sliding door CENTER" line 418 z "S1 EDGE: Enable RTS" line 419 z "SR EDGE: Enable RTS" line 420 z "W1 EDGE: Enable RTS" line 421 z "WR EDGE: Enable RTS" line 440 z "G1 EDGE: Enable RTS" line 441 z "GR EDGE: Enable RTS" line 454 z "W1 EDGE: Enable RTS /mon" line 455 z "WR EDGE: Enable RTS /mon" line 456 z "GR EDGE: Enable RTS /mon" line 457 z "SR EDGE: DISABLE RTS" line 458 z "WR EDGE: DISABLE RTS" line 459 z "GR EDGE: DISABLE RTS" line 460 z "WR EDGE: DISABLE RTS /mon" line 461 z "GR EDGE: DISABLE RTS /mon" line 470 s "-- EDGE: Ladder, 48 high" line 471 s "-- EDGE: Ladder, 80 high" line 472 s "-- EDGE: Ladder, 120 high" line 473 s "-- EDGE: Ladder, 160 high" line 474 s "-- EDGE: Ladder, 192 high" line 475 s "-- EDGE: Ladder, 256 high" line 476 s "-- EDGE: Ladder, 384 high" line 477 s "-- EDGE: Ladder, 512 high" line 478 s "-- EDGE: Ladder, 768 high" line 479 s "-- EDGE: Ladder, no limit" line 462 a "-- EDGE: Mirror" line 463 a "-- EDGE: Mirror /white" line 464 a "-- EDGE: Mirror /blue" line 465 a "-- EDGE: Mirror /red" line 466 a "-- EDGE: Mirror /green" line 480 a "-- EDGE: Portal /dark" line 481 a "-- EDGE: Portal /light" line 482 a "-- EDGE: Portal /light2" line 483 a "-- EDGE: Portal /blue" line 484 a "-- EDGE: Portal /green" line 485 a "-- EDGE: Camera Portal" line 486 a "-- EDGE: Camera Portal /white" line 487 a "-- EDGE: Camera Portal /cyan" line 488 a "-- EDGE: Camera Portal /rusty" line 489 a "-- EDGE: Camera Portal /green" line 501 b "WR Hub Exit to MAP01 / E1M1" line 502 b "WR Hub Exit to MAP02 / E1M2" line 503 b "WR Hub Exit to MAP03 / E1M3" line 504 b "WR Hub Exit to MAP04 / E1M4" line 505 b "WR Hub Exit to MAP05 / E1M5" line 506 b "WR Hub Exit to MAP06 / E1M6" line 507 b "WR Hub Exit to MAP07 / E1M7" line 508 b "WR Hub Exit to MAP08 / E1M8" line 509 b "WR Hub Exit to MAP09 / E1M9" line 510 b "WR Hub Exit to MAP10" line 511 b "WR Hub Exit to MAP11 / E2M1" line 512 b "WR Hub Exit to MAP12 / E2M2" line 513 b "WR Hub Exit to MAP13 / E2M3" line 514 b "WR Hub Exit to MAP14 / E2M4" line 515 b "WR Hub Exit to MAP15 / E2M5" line 516 b "WR Hub Exit to MAP16 / E2M6" line 517 b "WR Hub Exit to MAP17 / E2M7" line 518 b "WR Hub Exit to MAP18 / E2M8" line 519 b "WR Hub Exit to MAP19 / E2M9" line 520 b "WR Hub Exit to MAP20" line 521 b "WR Hub Exit to MAP21 / E3M1" line 522 b "WR Hub Exit to MAP22 / E3M2" line 523 b "WR Hub Exit to MAP23 / E3M3" line 524 b "WR Hub Exit to MAP24 / E3M4" line 525 b "WR Hub Exit to MAP25 / E3M5" line 526 b "WR Hub Exit to MAP26 / E3M6" line 527 b "WR Hub Exit to MAP27 / E3M7" line 528 b "WR Hub Exit to MAP28 / E3M8" line 529 b "WR Hub Exit to MAP29 / E3M9" line 530 b "WR Hub Exit to MAP30" line 531 b "WR Hub Exit to MAP31 / E4M1" line 532 b "WR Hub Exit to MAP32 / E4M2" line 533 b "WR Hub Exit to MAP33 / E4M3" line 534 b "WR Hub Exit to MAP34 / E4M4" line 535 b "WR Hub Exit to MAP35 / E4M5" line 536 b "WR Hub Exit to MAP36 / E4M6" line 537 b "WR Hub Exit to MAP37 / E4M7" line 538 b "WR Hub Exit to MAP38 / E4M8" line 539 b "WR Hub Exit to MAP39 / E4M9" line 490 d "DR EDGE: Green key door" line 491 d "D1 EDGE: Green key door" line 492 d "SR EDGE: Green key door" line 493 d "S1 EDGE: Green key door" line 494 d "D1 EDGE: Green key door /fast" line 580 d "DR EDGE: Gold key door" line 581 d "D1 EDGE: Gold key door" line 582 d "SR EDGE: Gold key door" line 583 d "S1 EDGE: Gold key door" line 584 d "DR EDGE: Silver key door" line 585 d "D1 EDGE: Silver key door" line 586 d "SR EDGE: Silver key door" line 587 d "S1 EDGE: Silver key door" line 588 d "DR EDGE: Brass key door" line 589 d "D1 EDGE: Brass key door" line 590 d "DR EDGE: Copper key door" line 591 d "D1 EDGE: Copper key door" line 592 d "DR EDGE: Steel key door" line 593 d "D1 EDGE: Steel key door" line 594 d "DR EDGE: Wooden key door" line 595 d "D1 EDGE: Wooden key door" line 596 d "DR EDGE: Fire key door" line 597 d "D1 EDGE: Fire key door" line 598 d "DR EDGE: Water key door" line 599 d "D1 EDGE: Water key door" line 800 a "-- EDGE: Align F1" line 801 a "-- EDGE: Align F2" line 802 a "-- EDGE: Align C1" line 803 a "-- EDGE: Align C2" line 804 a "-- EDGE: Align F1 + C1" line 805 a "-- EDGE: Align F2 + C2" line 810 a "-- EDGE: Align, scale F1" line 811 a "-- EDGE: Align, scale F2" line 812 a "-- EDGE: Align, scale C1" line 813 a "-- EDGE: Align, scale C2" line 814 a "-- EDGE: Align, scale F1 + C1" line 815 a "-- EDGE: Align, scale C2 + C2" line 820 a "-- EDGE: Scale F1" line 821 a "-- EDGE: Scale F2" line 822 a "-- EDGE: Scale C1" line 823 a "-- EDGE: Scale C2" line 824 a "-- EDGE: Scale F1 + C1" line 825 a "-- EDGE: Scale F2 + C2" # not in EDGE line 271 - "-- (Unsupported)" line 272 - "-- (Unsupported)" #---- EDGE SECTOR TYPES ---------- sector 29 "EDGE: Hub entry area" sector 4466 "EDGE Water" sector 4418 "EDGE Water + Current N" sector 4419 "EDGE Water + Current NE" sector 4420 "EDGE Water + Current E" sector 4421 "EDGE Water + Current SE" sector 4422 "EDGE Water + Current S" sector 4423 "EDGE Water + Current SW" sector 4424 "EDGE Water + Current W" sector 4425 "EDGE Water + Current NW" sector 4467 "EDGE Slime (no damage)" sector 4468 "EDGE Slime" sector 4426 "EDGE Slime + Current N" sector 4427 "EDGE Slime + Current NE" sector 4428 "EDGE Slime + Current E" sector 4429 "EDGE Slime + Current SE" sector 4430 "EDGE Slime + Current S" sector 4431 "EDGE Slime + Current SW" sector 4432 "EDGE Slime + Current W" sector 4433 "EDGE Slime + Current NW" sector 4469 "EDGE Lava (no damage)" sector 4470 "EDGE Lava" sector 4434 "EDGE Lava + Current N" sector 4435 "EDGE Lava + Current NE" sector 4436 "EDGE Lava + Current E" sector 4437 "EDGE Lava + Current SE" sector 4438 "EDGE Lava + Current S" sector 4439 "EDGE Lava + Current SW" sector 4440 "EDGE Lava + Current W" sector 4441 "EDGE Lava + Current NW" sector 4442 "EDGE Push N" sector 4443 "EDGE Push NE" sector 4444 "EDGE Push E" sector 4445 "EDGE Push SE" sector 4446 "EDGE Push S" sector 4447 "EDGE Push SW" sector 4448 "EDGE Push W" sector 4449 "EDGE Push NW" sector 4450 "EDGE Scroll Floor N" sector 4451 "EDGE Scroll Floor NE" sector 4452 "EDGE Scroll Floor E" sector 4453 "EDGE Scroll Floor SE" sector 4454 "EDGE Scroll Floor S" sector 4455 "EDGE Scroll Floor SW" sector 4456 "EDGE Scroll Floor W" sector 4457 "EDGE Scroll Floor NW" sector 4458 "EDGE Scroll + Push N" sector 4459 "EDGE Scroll + Push NE" sector 4460 "EDGE Scroll + Push E" sector 4461 "EDGE Scroll + Push SE" sector 4462 "EDGE Scroll + Push S" sector 4463 "EDGE Scroll + Push SW" sector 4464 "EDGE Scroll + Push W" sector 4465 "EDGE Scroll + Push NW" eureka-1.11-source/ports/odamex.ugh0000644000175100017510000000437212647061302016626 0ustar aaptedaapted#------------------------------------------------------------------------ # ODAMEX definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2013 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 "boom" #---- ODAMEX THINGS ---------- thing 5080 p - 16 PLAYF1 "ODAMEX: Blue start" thing 5081 p - 16 PLAYF1 "ODAMEX: Red start" thing 5130 k n 16 BFLG "ODAMEX: Blue flag" thing 5131 k n 16 RFLG "ODAMEX: Red flag" thing 9046 - n 16 NULL "ODAMEX: Secret" thing 9045 - n 16 NULL "ODAMEX: Water zone" thing 9026 d n 16 NULL "ODAMEX: Sparks" thing 9027 d n 16 NULL "ODAMEX: Fountain 1" thing 9028 d n 16 NULL "ODAMEX: Fountain 2" thing 9029 d n 16 NULL "ODAMEX: Fountain 3" thing 9030 d n 16 NULL "ODAMEX: Fountain 4" thing 9031 d n 16 NULL "ODAMEX: Fountain 5" thing 9032 d n 16 NULL "ODAMEX: Fountain 6" thing 9033 d n 16 NULL "ODAMEX: Fountain 7" # not here (require Hexen format) : # MT_CAMERA # MT_PATHNODE # MT_NODE # MT_ZDOOMBRIDGE # MT_BRIDGE8/16/32 #---- ODAMEX LINE TYPES ---------- line 333 - "-- ODAMEX: Init Gravity" line 334 - "-- ODAMEX: Init Color" line 335 - "-- ODAMEX: Init Damage" line 340 s "-- ODAMEX: Slope F1" line 341 s "-- ODAMEX: Slope C1" line 342 s "-- ODAMEX: Slope F1 + C1" line 343 s "-- ODAMEX: Slope F2" line 344 s "-- ODAMEX: Slope C2" line 345 s "-- ODAMEX: Slope C2 + F2" line 346 s "-- ODAMEX: Slope C1 + F2" line 347 s "-- ODAMEX: Slope C2 + F1" #---- ODAMEX SECTOR TYPES ---------- sector 21 "ODAMEX: Light Phased" sector 22 "ODAMEX: LightSeq Start" sector 23 "ODAMEX: LightSeq Spec 1" sector 24 "ODAMEX: LightSeq Spec 2" # hmmm, can Sky2 and Scroll types be used too ??? eureka-1.11-source/obj_win32/0000755000175100017510000000000012651564503015271 5ustar aaptedaaptedeureka-1.11-source/obj_win32/glbsp/0000755000175100017510000000000012651564503016400 5ustar aaptedaaptedeureka-1.11-source/TODO.txt0000644000175100017510000002330312651564436015011 0ustar aaptedaapted Eureka TODO / WISHLIST ====================== ______________________________________________________________________ HIGH PRIORITY ______________________________________________________________________ General ------- + Preferences: - sector_render_default - headroom button values - ability to change mouse move/turn speed in 3D view - floor_bump_xxx values + Key binding system for mouse buttons - convert MIDDLE button (insert/resize/rotate) for KEY system - convert RIGHT BUTTON (scroll) to use KEY system - convert LEFT BUTTON (select, insert-line, drag, selbox) for KEY system - convert button stuff in 3D render to use KEY system - preference for "bindable mouse wheel (disable normal behavior)" + Proper system to specify which ports can be used with each game. Perhaps it would group games into classes (e.g. most of the current games would be "doom" class). Then each port can specify which classes of games it supports. Documentation ------------- + a tutorial for the basics - describe what a wad file is, PWAD vs IWAD, how to play it, what nodes are, how wad files can contain more than maps, different games and source ports - describe basic elements of a map: Lines, Vertices, Sectors, Things, SideDefs - describe the four modes V/L/S/T, and their panels - hilighting stuff, selecting stuff, dragging stuff - drawing lines in VERTEX mode - using the browser - common pitfalls (vertices sitting on a linedef or another vertex) + information on each binding command, parameters etc.. Editing ------- + automatically build nodes on save (only for that map) (need to more tightly integrate a node builder into the code) + ENTER key pops up an "operation" menu, which provides all the commands that can be done via the keyboard (e.g. flip linedefs) (could also be bound to right mouse button) 3D View ------- Browser ------- + when opened by a click, jump to the texture/thing/etc clicked on ______________________________________________________________________ LOWER PRIORITY ______________________________________________________________________ General ------- + Large font mode, more readable on 1920x1080 monitors + sprite rendering in the 2D canvas + ability to hide the right-side panel ? a toolbar - a key to copy properties TO defaults (e.g. shift-C) - View/Place Camera command, cursor turns into + + Preferences window: + add backup_max_files / backup_max_space - implement the scrolling sizes - add more stuff (see USER CONFIG NEEDED, below) + a dialog to view / load / prune backups. IDEA: integrate Visplane Explorer IDEA: MMB on sidedef/sector tex : open RECENT browser WISH: support Windows 95/98/ME [running on Windows 98SE requires KernelEx] WISH: can import DWD (DoomEd) format maps WISH: can import UDMF format maps - File / Test Map + make filenames absolute + configurable stuff [ for each PORT ] - directory to 'cd' into - program to invoke - arguments to use (-iwad, -file, -merge, -warp) ===> PORT .UGH - support resource wads - make sure the user built the nodes (option to invoke it automatically, or not check at all) - each map (via .dat?) can specify _override_ config ? GUI buttons for NewTag / LastTag commands - vertex/linedef mode: '[' and ']' to adjust length of current line - tag checking: check for valid usage of special 666 / 667 tags. - binding functions for all menu stuff (NewMap, OpenMap, etc....) (perhaps prefix with MENU_xxx) - improve Key binding preferences: + "Grab" button in UI_EditKey - "Find" or "Match" button for function in UI_EditKey - reverse ordering of KCTX_XXX values - make sure Load/Export wad filename not already in master_dir - PRINT key to make a screenshot of map or 3D view ? config system: OPT_KEY values ? ability to view (perhaps edit) a map header lump (for FraggleScript etc...) ? ability to create / view / edit / import arbitrary lumps (e.g. MAPINFO, DECORATE, etc...) ? a way to slow down fake mouse wheels? IDEA: for generalized lines, show more info in tooltip of desc IDEA: after inserting a new object, allow moving another object (i.e. set edit.did_a_move = true). Perhaps config item. IDEA: "fix" missing coop starts, place them near player #1 WISH: support ZDoom PK3 for textures (etc) WISH: support DDF as (or in) a resource file WISH: support DECORATE as (or in) a resource file Documentation ------------- + cannot Undo after building nodes - happens because we reload the map (because the current WAD file has been replaced by a new one) + add supported OSes -- e.g. Windows >= XP - document texture browser (RIGHT click etc) - make a manpage for the debian package, list cmdline options - command line arguments page Coding ------ - replace usage(s) of fl_input [ currently just the 'JumpToObject' command ] Editing ------- + for the "Edit -> Paste" menu, turn the cursor into crosshairs and wait until the user selects a spot to paste to. + support PNG (etc?) image formats [enabled by a port definition] --> feature png - support TX_START / TX_END namespace for textures --> feature tx_start + when dragging a shape next to existing geometry, highlight vertices and linedefs which would get merged, and implement that merging. - a proper "curve" tool for making a circle arc or bezier curve, and new vertices would be constrained to that curve, and you can move existing vertices onto the curve. - assume texture names beginning with '#' are special (The texture checker ignores them -- what else is needed ??) ? quantization function: prevent linedefs from overlapping / crossing ? Multi-select : if CTRL is pressed, don't clear selection after drag - more port-specific line/thing flags Q/ how to handle self-referencing linedefs in auto create/split sector ?? Q/ disconnect sectors : include islands (perhaps with 'D') IDEA: in Find/Replace panel, can filter things by CATEGORY IDEA: for quantizing a group of objects, try about 9 delta positions (x+0, x+step/4, x-step/4 etc...) and choose the "best" quantization. 3D View ------- + draw the sky (optionally) - option to reverse mouse movement + smooth movement via keyboard - call a function in Main_Loop - if did a move, Fl::wait(0) instead of 0.2 - handle key up/down events in UI_Canvas::handle() - closed sectors have a see-through gap (gets bigger further away) + being able to select stuff to modify: - things - floors - ceilings - sidedef textures - moving up/down with RMB should not disable gravity when change is small - able to drag things around - raise floors? - move vertices? + shift textures? - rotated sprites + slopes - BOOM colormaps - BOOM deep water ? extrafloors IDEA: a key (or mouse button) to toggle "grab mouse" mode IDEA: animation mode, render continuously and show any lighting effects and animated / scrolling textures and sprites Browser ------- + ability to shrink categories, i.e. say that for things the 'b' (bonus) and 'k' categories should become a single one - can change the [max] size of the texture/flat previews - scroll speed (i.e. linesize) is configurable - search box: ',' for OR - preference for # of RECENT items ? command to clear the recent lists Game / Port Definitions ----------------------- + support Harmony + a ZDoom configuration - support Doom-in-Hexen mapping - conversion between Hexen <--> DOOM formats - game-def setting: view_height - FreeDOOM : categorize all the new textures - HacX : categorize the textures IDEA: for DOOM have "Switch", "Grating", "Door" categories WISH: conversion from Boom --> vanilla DOOM Possible user config -------------------- render_forward_speed (16) render_turn_speed (16) render_updown_speed (16) paste_reselects (true) ______________________________________________________________________ NOT-TO-DO ______________________________________________________________________ NO: Restore last window position and maximized state NO: un-hard-code menu shortcuts? NO: Scripting language NO: ability to use an external node builder NO: if a given pwad (from command line) does not exist, ask to create it perhaps: --create or --new option? NO: built-in cheat sheet for mouse buttons and common keys NO: document the config file syntax NO: when one vertex of a linedef is moved (and not the other) update the X offset on the appropriate side (right side for start, left side for end vertex). NO: support SPACE/INSERT in linedef mode (and line is highlighted or selected) split the line and put vertex where mouse is [ can do this in vertex mode easily enough ] NO: merge vertex and linedef modes NO: nicer way to select map, render a small 2D version of each map and present them in a scrolling list. NO: ability to drag the camera (on 2D viewport) NO: when moving a sector and the camera is inside it, move camera too NO: ability to edit Lua code for OBLIGE prefabs NO: 3D view: handle very tall/thin window, letter box with black NO: an auto-save feature (e.g. save every N minutes unless no changes occurred in the last N minutes). NO: no-pic mode for textures and flats NO: exchange object numbers NO: check that current pwad has been externally modified NO: when highlighting a sector, draw the things in the same color but diimer, to show sector operators will affect things too NO: support Chex Quest 1 and 2 NO: ability to "remove line 271" (etc) in port definitions NO: "USED" category for the browser NO: speed up grid drawing when step is small and zoomed out eureka-1.11-source/Makefile0000644000175100017510000001105312651545712015136 0ustar aaptedaapted# # --- Eureka Editor --- # # Makefile for Unixy system-wide install # PROGRAM=eureka # prefix choices: /usr /usr/local /opt PREFIX=/usr/local OBJ_DIR=obj_linux OPTIMISE=-O2 -fno-strict-aliasing STRIP_FLAGS=--strip-unneeded # operating system choices: UNIX WIN32 OS=UNIX #--- Internal stuff from here ----------------------------------- INSTALL_DIR=$(PREFIX)/share/eureka CXXFLAGS=$(OPTIMISE) -Wall -D$(OS) \ -Iglbsp_src \ -D_THREAD_SAFE -D_REENTRANT LDFLAGS=-L/usr/X11R6/lib LIBS= \ -lfltk_images -lfltk_gl -lfltk \ -lX11 -lXext -lXft -lfontconfig -lXinerama \ -lpng -ljpeg -lGL -lz -lm # support for a non-standard install of FLTK ifneq ($(FLTK_PREFIX),) CXXFLAGS += -I$(FLTK_PREFIX)/include LDFLAGS += -L$(FLTK_PREFIX)/lib -Wl,-rpath,$(FLTK_PREFIX)/lib endif # support for statically linking FLTK (no GL, local JPEG and PNG) ifneq ($(FLTK_STATIC),) LIBS= \ -lfltk_images -lfltk \ -lfltk_png -lfltk_jpeg \ -lX11 -lXext -lXft -lfontconfig -lXinerama \ -lz -lm endif #----- Object files ---------------------------------------------- OBJS = \ $(OBJ_DIR)/editloop.o \ $(OBJ_DIR)/e_basis.o \ $(OBJ_DIR)/e_checks.o \ $(OBJ_DIR)/e_checks2.o \ $(OBJ_DIR)/e_cutpaste.o \ $(OBJ_DIR)/e_linedef.o \ $(OBJ_DIR)/e_loadsave.o \ $(OBJ_DIR)/e_nodes.o \ $(OBJ_DIR)/e_path.o \ $(OBJ_DIR)/e_sector.o \ $(OBJ_DIR)/e_things.o \ $(OBJ_DIR)/e_vertex.o \ $(OBJ_DIR)/im_arrows.o \ $(OBJ_DIR)/im_color.o \ $(OBJ_DIR)/im_img.o \ $(OBJ_DIR)/levels.o \ $(OBJ_DIR)/lib_adler.o \ $(OBJ_DIR)/lib_file.o \ $(OBJ_DIR)/lib_util.o \ $(OBJ_DIR)/main.o \ $(OBJ_DIR)/m_bitvec.o \ $(OBJ_DIR)/m_config.o \ $(OBJ_DIR)/m_files.o \ $(OBJ_DIR)/m_game.o \ $(OBJ_DIR)/m_keys.o \ $(OBJ_DIR)/m_select.o \ $(OBJ_DIR)/m_strings.o \ $(OBJ_DIR)/objects.o \ $(OBJ_DIR)/r_grid.o \ $(OBJ_DIR)/r_render.o \ $(OBJ_DIR)/sys_debug.o \ $(OBJ_DIR)/ui_about.o \ $(OBJ_DIR)/ui_browser.o \ $(OBJ_DIR)/ui_canvas.o \ $(OBJ_DIR)/ui_default.o \ $(OBJ_DIR)/ui_dialog.o \ $(OBJ_DIR)/ui_file.o \ $(OBJ_DIR)/ui_hyper.o \ $(OBJ_DIR)/ui_infobar.o \ $(OBJ_DIR)/ui_linedef.o \ $(OBJ_DIR)/ui_menu.o \ $(OBJ_DIR)/ui_misc.o \ $(OBJ_DIR)/ui_nombre.o \ $(OBJ_DIR)/ui_nodes.o \ $(OBJ_DIR)/ui_pic.o \ $(OBJ_DIR)/ui_prefs.o \ $(OBJ_DIR)/ui_replace.o \ $(OBJ_DIR)/ui_sector.o \ $(OBJ_DIR)/ui_scroll.o \ $(OBJ_DIR)/ui_sidedef.o \ $(OBJ_DIR)/ui_thing.o \ $(OBJ_DIR)/ui_tile.o \ $(OBJ_DIR)/ui_vertex.o \ $(OBJ_DIR)/ui_window.o \ $(OBJ_DIR)/w_loadpic.o \ $(OBJ_DIR)/w_flats.o \ $(OBJ_DIR)/w_sprite.o \ $(OBJ_DIR)/w_texture.o \ $(OBJ_DIR)/w_wad.o \ $(OBJ_DIR)/x_hover.o \ $(OBJ_DIR)/x_loop.o \ $(OBJ_DIR)/x_mirror.o $(OBJ_DIR)/%.o: src/%.cc $(CXX) $(CXXFLAGS) -o $@ -c $< #----- glBSP Objects ------------------------------------------------ GLBSP_OBJS= \ $(OBJ_DIR)/glbsp/analyze.o \ $(OBJ_DIR)/glbsp/blockmap.o \ $(OBJ_DIR)/glbsp/glbsp.o \ $(OBJ_DIR)/glbsp/level.o \ $(OBJ_DIR)/glbsp/node.o \ $(OBJ_DIR)/glbsp/reject.o \ $(OBJ_DIR)/glbsp/seg.o \ $(OBJ_DIR)/glbsp/system.o \ $(OBJ_DIR)/glbsp/util.o \ $(OBJ_DIR)/glbsp/wad.o GLBSP_CXXFLAGS=$(OPTIMISE) -Wall -DINLINE_G=inline $(OBJ_DIR)/glbsp/%.o: glbsp_src/%.cc $(CXX) $(GLBSP_CXXFLAGS) -o $@ -c $< #----- Targets ----------------------------------------------- all: $(PROGRAM) clean: rm -f $(PROGRAM) $(OBJ_DIR)/*.* core core.* rm -f $(OBJ_DIR)/glbsp/*.* rm -f ERRS LOG.txt update.log $(PROGRAM): $(OBJS) $(GLBSP_OBJS) $(CXX) $^ -o $@ $(LDFLAGS) $(LIBS) stripped: $(PROGRAM) strip $(STRIP_FLAGS) $(PROGRAM) install: stripped install -o root -m 755 $(PROGRAM) $(PREFIX)/bin/ install -d $(INSTALL_DIR)/games install -d $(INSTALL_DIR)/common install -d $(INSTALL_DIR)/ports install -d $(INSTALL_DIR)/mods rm -f $(INSTALL_DIR)/games/freedoom.ugh install -o root -m 644 bindings.cfg $(INSTALL_DIR)/bindings.cfg install -o root -m 644 misc/about_logo.png $(INSTALL_DIR)/about_logo.png install -o root -m 644 games/*.* $(INSTALL_DIR)/games install -o root -m 644 common/*.* $(INSTALL_DIR)/common install -o root -m 644 ports/*.* $(INSTALL_DIR)/ports # install -o root -m 644 mods/*.* $(INSTALL_DIR)/mods xdg-desktop-menu install --novendor misc/eureka.desktop xdg-icon-resource install --novendor --size 32 misc/eureka.xpm uninstall: rm -v $(PREFIX)/bin/$(PROGRAM) rm -Rv $(INSTALL_DIR) xdg-desktop-menu uninstall --novendor misc/eureka.desktop xdg-icon-resource uninstall --novendor --size 32 eureka .PHONY: all clean stripped install uninstall #--- editor settings ------------ # vi:ts=8:sw=8:noexpandtab eureka-1.11-source/docs/0000755000175100017510000000000012651310006014410 5ustar aaptedaaptedeureka-1.11-source/docs/History.txt0000644000175100017510000246004212651310005016621 0ustar aaptedaapted__________________ REPOSITORY HISTORY __________________ This file contains commit logs from several different repositories, in reverse chronological order (from newest to oldest). When I first created Eureka (forking from Yadex), I just made all the changes on my hard-drive -- without using any source control at all. Hence there are no change logs from that period. After a while, I developed the code on the EDGE SVN repository, and later moved the code to the AwwPorts repository and continued developing it there. Eventually I made a preview version available on the DoomWorld forums to see if there was any interest, and then registered a SourceForge project for it, and the code repository got moved yet again. In January 2016 the SVN repository was converted into a GIT repository (still on SourceForge though). ==================================================== CURRENT DEVELOPMENT (GIT) ==================================================== ------------------------------------------------------------------------ fa4b5a27193e | Andrew Apted | 2016-01-24 22:31:59 +1100 README and CHANGELOG : small update. ------------------------------------------------------------------------ 283db5159c29 | Andrew Apted | 2016-01-24 22:29:09 +1100 TODO : went through and re-evaluated most items, moved several to the "NOT-TO-DO" section. ------------------------------------------------------------------------ bb89fd036ef2 | Andrew Apted | 2016-01-24 22:13:26 +1100 Editing : SHIFT + LMB in sector/linedef mode forces the opening of a selection box -- handy for places were it is otherwise impossible. ------------------------------------------------------------------------ 6f1fb5073c59 | Andrew Apted | 2016-01-24 21:44:31 +1100 Code tidying, miscellaneous stuff here and there. ------------------------------------------------------------------------ 2ef2708b2f39 | Andrew Apted | 2016-01-24 21:43:46 +1100 Browser : removed CycleCategory method from generalized line editor. ------------------------------------------------------------------------ 23fc3cf6eb24 | Andrew Apted | 2016-01-24 21:39:57 +1100 Code tidying : removed the unused exchange_object_numbers() which is legacy code that would require major surgery to get working again but has very little utility. ------------------------------------------------------------------------ df4b2b95b474 | Andrew Apted | 2016-01-24 21:30:34 +1100 Code tidying : removed some unused code in e_sector.cc ------------------------------------------------------------------------ e6214230a578 | Andrew Apted | 2016-01-24 21:03:17 +1100 Version bumped, ------------------------------------------------------------------------ bafc1cc78a17 | Andrew Apted | 2016-01-24 20:59:15 +1100 CHANGELOG : re-organized into sections like "Editing" etc. ------------------------------------------------------------------------ 595b8a63f540 | Andrew Apted | 2016-01-24 20:41:24 +1100 3D Preview : small optimisation of the texture-warp fix. ------------------------------------------------------------------------ e45cf71fb832 | Andrew Apted | 2016-01-24 19:38:31 +1100 3D Preview : fixed the texture warping issue, caused by interpolating the angles across the wall (not the correct method). ------------------------------------------------------------------------ 917fd68cb3a4 | Andrew Apted | 2016-01-24 18:15:06 +1100 TODO updated. ------------------------------------------------------------------------ 48bc72ceb2e1 | Andrew Apted | 2016-01-24 18:12:41 +1100 When scrolling via keyboard, ensure certain actions (esp. drawing mode) get updated properly. ------------------------------------------------------------------------ 502373e63c25 | Andrew Apted | 2016-01-24 17:37:43 +1100 TODO update. ------------------------------------------------------------------------ eb171c92d11c | Andrew Apted | 2016-01-24 16:28:10 +1100 LIN_Flip : 1. default behavior on 1S lines is to NOT makes lines without a right side 2. support /verts flag which only swaps the vertices 3. support /sides flag which only swaps the sidedefs ------------------------------------------------------------------------ be11e914ff48 | Andrew Apted | 2016-01-24 16:27:29 +1100 Fixed bug saving the key bindings (file handle was not closed). ------------------------------------------------------------------------ d9344de9a581 | Andrew Apted | 2016-01-24 16:22:08 +1100 Canvas sector rendering : treat lines missing a right side as broken (i.e. do not create spans even when the left side is valid). ------------------------------------------------------------------------ 4c62d990849a | Andrew Apted | 2016-01-24 15:44:18 +1100 Improved split-line detection when grid snapping -- prevent the split point from being far away from the line. ------------------------------------------------------------------------ a46432dcaa8b | Andrew Apted | 2016-01-24 14:58:32 +1100 Drawing mode : added special case for splitting a line via mouse button (and not in drawing mode) to allow the new vertex to be dragged. [ this was not possible in the normal Insert_Vertex code-path ] ------------------------------------------------------------------------ d8715a09ddfc | Andrew Apted | 2016-01-24 13:54:13 +1100 code : futher tidying in Editor_MouseRelease(). ------------------------------------------------------------------------ 12134d210757 | Andrew Apted | 2016-01-24 13:53:07 +1100 Implemented "!=" operator for the Objid class. ------------------------------------------------------------------------ ecde28798c7f | Andrew Apted | 2016-01-24 13:44:03 +1100 code : various tidying in Editor_MouseMotion(). ------------------------------------------------------------------------ ff44e9660b02 | Andrew Apted | 2016-01-24 13:35:09 +1100 code : some refactoring in Editor_MouseRelease(). ------------------------------------------------------------------------ 97b340a84f1d | Andrew Apted | 2016-01-24 13:23:16 +1100 minor code rejig in Editor_MouseRelease(). ------------------------------------------------------------------------ 6b6d6101db2e | Andrew Apted | 2016-01-24 13:09:53 +1100 Drawing mode : worked on fixing drawing mode erroneously beginning again after closing a sector via splitting a line. Still not correct, ugh... ------------------------------------------------------------------------ 7a7e8cefea7f | Andrew Apted | 2016-01-24 11:39:08 +1100 Fixed Selection_NotifyInsert() to not clear a vertex selection when a new linedef or sector is created. ------------------------------------------------------------------------ 0340593de210 | Andrew Apted | 2016-01-23 23:25:47 +1100 Added workaround in Editor_RawButton() for FLTK not sending us a button release event after another mouse button was released (i.e. when two buttons were being held down simultaneously). ------------------------------------------------------------------------ a106d2019868 | Andrew Apted | 2016-01-23 22:57:04 +1100 fix for previous commit: do not check for FL_DRAG event when calling Editor_MouseMotion, since it won't be set after scrolling via RMB. ------------------------------------------------------------------------ 701606bbb8f1 | Andrew Apted | 2016-01-23 22:49:07 +1100 Changed the way map scrolling via RMB is done, no longer an action state (ACT_XXX value) because that prevents scrolling and line drawing being used together [ a scroll would disable the current line ]. ------------------------------------------------------------------------ d1b3b2a4744e | Andrew Apted | 2016-01-23 21:12:37 +1100 For dangling vertex fixer, when merging two vertices make the final vertex selected (and nothing else). ------------------------------------------------------------------------ 025c5161c1f1 | Andrew Apted | 2016-01-23 21:01:05 +1100 Fixed the logic for fixing a dangling vertex. ------------------------------------------------------------------------ 9ad68d2fb07e | Andrew Apted | 2016-01-23 20:29:42 +1100 Insert_Vertex : added back the check preventing the creation of a zero length linedef -- it displays a "Bug detected" message as I am quite sure that it should never happen. ------------------------------------------------------------------------ f2015147a513 | Andrew Apted | 2016-01-23 20:08:29 +1100 Insert_Vertex : fixed a few cases involving a split-line. ------------------------------------------------------------------------ d96639336041 | Andrew Apted | 2016-01-22 22:49:25 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 770427e0583e | Andrew Apted | 2016-01-22 22:48:04 +1100 Insert_Vertex : bit more work, e.g. split-line handling. ------------------------------------------------------------------------ 0d24939ea117 | Andrew Apted | 2016-01-22 22:37:25 +1100 Insert_Vertex : tidied up the highlight handling code. ------------------------------------------------------------------------ ef8079ded2eb | Andrew Apted | 2016-01-22 22:27:57 +1100 Began some major surgery to Insert_Vertex() to better manage all the possible cases (e.g. easier_drawing_mode either ON or OFF). ------------------------------------------------------------------------ cb1ada9985dc | Andrew Apted | 2016-01-22 19:40:09 +1100 Drawing mode : when drawing a line AND grid snapping, allow the highlight and split-line to move onto the snapped position (when they would otherwise not show anything). This prevents creating a vertex which inadvertently sits on top of another vertex or sits on a line (due to the coordinate being snapped). ------------------------------------------------------------------------ 9b45589532ba | Andrew Apted | 2016-01-22 19:38:38 +1100 Canvas : draw the split-line orange ball larger when zoomed in (closer to the size of the vertices). ------------------------------------------------------------------------ 94e30ea2dfe2 | Andrew Apted | 2016-01-22 19:10:19 +1100 Code : merely moved some code around in editloop.cc ------------------------------------------------------------------------ 6309684a23b5 | Andrew Apted | 2016-01-22 19:07:15 +1100 Code : renamed GetCurobject --> GetNearObject, removed unused "snap" param. ------------------------------------------------------------------------ 7effd83d2359 | Andrew Apted | 2016-01-22 18:24:08 +1100 Added config file variable "minimum_drag_pixels". ------------------------------------------------------------------------ 1e410deea699 | Andrew Apted | 2016-01-22 18:12:57 +1100 Improved dragging: only begin dragging if cursor has moved a minimum # of pixels away from the click point. This prevents the problem where you only wanted to select a vertex, but instead you "dragged" it. ------------------------------------------------------------------------ 0cab70de706f | Andrew Apted | 2016-01-22 16:43:16 +1100 Drawing mode : allow a vertex created by spliting a line to be dragged. ------------------------------------------------------------------------ 7fd666632eb1 | Andrew Apted | 2016-01-22 15:14:42 +1100 When merging vertices, simply keep the coordinates of the first vertex (the one not delete). The previous way of computing the middle coord was not working well with grid-snapped vertices. ------------------------------------------------------------------------ 51c91df163bc | Andrew Apted | 2016-01-22 13:57:51 +1100 More work on dangling vert fixer, but the logic is still not right... ------------------------------------------------------------------------ 0f2b97fef84a | Andrew Apted | 2016-01-22 13:39:43 +1100 Implemented code to try to fix a dangling vertex -- if it sits on another vertex, merge into that one, or if it sits on a line then split the line with it. Also when using CMD_Insert on a vertex, try to fix it if dangling. ------------------------------------------------------------------------ e017b4dc494e | Andrew Apted | 2016-01-22 12:49:27 +1100 Code tidying : removed unused/obsolete DrawSnapMarker() method. ------------------------------------------------------------------------ fc5e6a76bf2a | Andrew Apted | 2016-01-22 11:49:32 +1100 Checks : fixed sector checker for Boom generalized types. ------------------------------------------------------------------------ f7eadbbeda47 | Andrew Apted | 2016-01-22 11:42:47 +1100 Added preference setting to disable the "easier line drawing" mode. ------------------------------------------------------------------------ ae42eb238506 | Andrew Apted | 2016-01-22 10:54:51 +1100 Generalized browser : changing fields will now update the line's type value. This commit marks the completion of BOOM generalized type support :) ------------------------------------------------------------------------ 768bea808584 | Andrew Apted | 2016-01-22 10:41:04 +1100 Generalized browser : allow "NONE" category to clear the line's type. ------------------------------------------------------------------------ cb81af656fcf | Andrew Apted | 2016-01-22 10:40:07 +1100 LineDef panel : change "Choose" button to "Edit" for generalized types. ------------------------------------------------------------------------ 2b58a571e419 | Andrew Apted | 2016-01-22 10:26:12 +1100 Checks : fixed unknown line-type checker to accept Boom generalized types when the current port is boom-compatible. ------------------------------------------------------------------------ c17e1a147d37 | Andrew Apted | 2016-01-20 22:05:13 +1100 CHANGELOG and TODO updated. ------------------------------------------------------------------------ 8e8f1884ba13 | Andrew Apted | 2016-01-20 21:51:20 +1100 Drawing mode : prevent LMB from adding linedefs when not in drawing mode (this was happening when splitting a linedef with LMB and another vertex was selected). ------------------------------------------------------------------------ 16edc3c8a418 | Andrew Apted | 2016-01-20 19:12:06 +1100 CMD_LastSelection : tweak invalidation logic. ------------------------------------------------------------------------ 5518ba839444 | Andrew Apted | 2016-01-20 18:45:10 +1100 TODO update. ------------------------------------------------------------------------ 2f83b1983fb5 | Andrew Apted | 2016-01-20 18:43:52 +1100 Checks / vertex : added new test for "dangling" vertices (one which are only connected to a single line). ------------------------------------------------------------------------ a38e3a4a24ba | Andrew Apted | 2016-01-20 17:18:04 +1100 .gitignore : added "_work" and various MacOS-X crud. ------------------------------------------------------------------------ 8da24b1c39ad | Andrew Apted | 2016-01-20 17:09:22 +1100 Browser : fixed recent bug causing the browser to jump to top of list when clicking on an entry (such as a texture). ------------------------------------------------------------------------ ac2bc6f8bbf6 | Andrew Apted | 2016-01-20 16:45:18 +1100 Code tidying : removed obsolete GetMaxObjectNum() function. ------------------------------------------------------------------------ ca58ba967f23 | Andrew Apted | 2016-01-20 16:43:35 +1100 CMD_LastSelection : validate the new selection (i.e. don't crash if there turns out to be a bug in the normal invalidation logic). ------------------------------------------------------------------------ cc93a8f9c43a | Andrew Apted | 2016-01-20 16:27:27 +1100 A few fixes for "LastSelection" command, which involved changing the "mode" parameter of the NewEditMode() methods from char --> obj_type_e (which is much more sensible). ------------------------------------------------------------------------ cc9db892869d | Andrew Apted | 2016-01-20 15:59:11 +1100 CMD_LastSelection : properly invalidate the last selection if an editing operation inserts or deletes objects in its range. ------------------------------------------------------------------------ d8a8633063ca | Andrew Apted | 22016-01-20 15:51:35 +1100 Info bar : give the status widget a tooltip with the same message, for cases when the message is too long to fit on-screen. ------------------------------------------------------------------------ 37fd31d0f80b | Andrew Apted | 2016-01-20 15:41:30 +1100 CMD_LastSelection : change editor mode if different than the last selection (and zoom into the selection, which helps make the mode change more obvious). ------------------------------------------------------------------------ 55c50ce52c87 | Andrew Apted | 2016-01-20 15:34:43 +1100 CMD_LastSelection : got the basic functionality working. ------------------------------------------------------------------------ f9f4f2cda77e | Andrew Apted | 2016-01-20 15:06:45 +1100 Drawing mode : fixed handling of SHIFT + LMB (continue drawing) when the line connected to an existing used vertex. ------------------------------------------------------------------------ cd3a8b697bfd | Andrew Apted | 2016-01-20 15:01:59 +1100 Replaced "edit.Selected->clear_all()" code --> Selection_Clear(). Also began work on ability to restore the last selection (when possible). ------------------------------------------------------------------------ 29320c1f53c2 | Andrew Apted | 2016-01-20 14:15:10 +1100 Selection class : implemented new "test_equal()" method, checks if two selections are the same. ------------------------------------------------------------------------ f40a855324eb | Andrew Apted | 2016-01-19 22:00:53 +1100 TODO update. ------------------------------------------------------------------------ 4ab4adfac0dc | Andrew Apted | 2016-01-19 22:00:14 +1100 CHANGELOG updated. ------------------------------------------------------------------------ ff1b2c5d2b6a | Andrew Apted | 2016-01-19 21:55:37 +1100 Generalized browser : made choice widgets a bit wider. ------------------------------------------------------------------------ b6b47b8ca0e5 | Andrew Apted | 2016-01-19 21:54:39 +1100 gen_types.ugh : expanded "HnF", "LnC" (etc) --> "Highest Floor", "Lowest Ceil" (etc). ------------------------------------------------------------------------ cc97e49d0309 | Andrew Apted | 2016-01-19 21:38:44 +1100 gen_types.ugh : improved various keywords, e.g. target names. ------------------------------------------------------------------------ c5bc0c49356a | Andrew Apted | 2016-01-19 21:25:02 +1100 Generalized browser : ability to reset all fields to default values, and fixed bug showing the wrong page. ------------------------------------------------------------------------ dbc53c8454c5 | Andrew Apted | 2016-01-19 21:00:42 +1100 Generalized browser : small improvement to previous commit. ------------------------------------------------------------------------ 833a5654cff6 | Andrew Apted | 2016-01-19 20:53:47 +1100 Generalized browser : removed the "Gen" button, too much clutter. Instead: clicking "Choose" when the type is in range will open the generalized browser, also by right clicking that button. Plus it can be opened via the menus. ------------------------------------------------------------------------ 5085fac14cc2 | Andrew Apted | 2016-01-19 20:45:45 +1100 Generalized browser : implemented decoding the line_type. ------------------------------------------------------------------------ 91680fa56b9c | Andrew Apted | 2016-01-19 20:18:41 +1100 Generalized browser : worked on UpdateGenType() for setting the page and all the field widgets to match the current linedef type. Also removed the "SET" button -- changes will take effect immediately (just like everything else in the LineDef panel). ------------------------------------------------------------------------ 040d3c6ebbdc | Andrew Apted | 2016-01-19 19:15:33 +1100 Generalized browser : tweaked layout for extra line in FLOOR/CEILING categories, and some other stuff for the Model/Monsters duality... ------------------------------------------------------------------------ f793fde39431 | Andrew Apted | 2016-01-19 18:19:20 +1100 gen_types.ugh : moved "Speed" field lower (underneath Target field), and for FLOOR and CEILING added a "Monsters" field (having same bit position as the "Model" field -- will need code to handle that properly). ------------------------------------------------------------------------ 1086a2117b04 | Andrew Apted | 2016-01-19 17:21:10 +1100 gen_types.ugh : added a default value in each "gen_field" line, and tweaked some more field names / keywords. ------------------------------------------------------------------------ ba4e660499b8 | Andrew Apted | 2016-01-19 17:05:12 +1100 gen_types.ugh : changed order so that "DOOR" is first, and capitalized various of the keywords and tweaked a few others. ------------------------------------------------------------------------ 603c1d5fcc36 | Andrew Apted | 2016-01-19 17:03:45 +1100 Generalized browser : layout tweak. ------------------------------------------------------------------------ df23936ec62b | Andrew Apted | 2016-01-19 16:41:48 +1100 Generalized browser : implemented creating the choice buttons in each page, and computing a type value, and fixed a few bugs. ------------------------------------------------------------------------ a30790a7fae3 | Andrew Apted | 2016-01-19 16:02:49 +1100 Generalized browser : changed resize behavior again, match what the other browsers do (everything follows the left edge). ------------------------------------------------------------------------ cc1f97a5491c | Andrew Apted | 2016-01-19 15:57:58 +1100 Generalized browser : minimise it whenever we change to the GEN browser (since it looks quite bad otherwise). ------------------------------------------------------------------------ 0dba3322afe3 | Andrew Apted | 2016-01-19 14:50:05 +1100 Heretic config : categorized all the flats and textures. ------------------------------------------------------------------------ b541f4c70e5c | Andrew Apted | 2016-01-19 14:13:46 +1100 Hexen config tweak. ------------------------------------------------------------------------ 6922aca68c73 | Andrew Apted | 2016-01-19 14:10:09 +1100 Hexen config : categorized all the textures and flats. ------------------------------------------------------------------------ e5c78e090cc6 | Andrew Apted | 2016-01-19 13:01:42 +1100 Browser : only populate the Category widget with non-empty categories. ------------------------------------------------------------------------ 419c132ca180 | Andrew Apted | 2016-01-18 23:08:47 +1100 TODO updated. ------------------------------------------------------------------------ 4372deb33d8e | Andrew Apted | 2016-01-18 23:03:35 +1100 Generalized browser : implemented apply_callback(). ------------------------------------------------------------------------ 95fad8495f84 | Andrew Apted | 2016-01-18 22:49:17 +1100 Generalized browser : implemented category callback which shows the corresponding page (hiding the rest), and support cycling through the categories. ------------------------------------------------------------------------ c89c229084a8 | Andrew Apted | 2016-01-18 22:20:37 +1100 Generalized browser : create the category and apply widgets, create all the pages (albeit just empty rects), and handle changes to game_info. ------------------------------------------------------------------------ 048c6e57bef6 | Andrew Apted | 2016-01-18 21:18:37 +1100 Generalized browser : fleshed out structure of UI_Generalized_Box class, added a message box to show when not in BOOM mode. ------------------------------------------------------------------------ 90bbb8850446 | Andrew Apted | 2016-01-18 20:54:44 +1100 Generalized browser : fixed resize behavior, tweaked title. ------------------------------------------------------------------------ 206d7e8464a1 | Andrew Apted | 2016-01-18 20:34:04 +1100 Generalized type : in LineDef panel, show a basic description for a gen line, currently it is the trigger + "GENERALIZED" + category name. ------------------------------------------------------------------------ e400500674fe | Andrew Apted | 2016-01-18 19:59:46 +1100 Sector panel : when user enters a large value into type box, store it directly in sectors -- the panel will show the Boom interpretation. ------------------------------------------------------------------------ 7d1b2dc12219 | Andrew Apted | 2016-01-18 19:38:09 +1100 Sector panel : use "BoomSF_XXX" constants for generalized masks. ------------------------------------------------------------------------ 60d57d7d9945 | Andrew Apted | 2016-01-18 19:25:57 +1100 Sector panel : the Boom flag widgets now show values for current sector, and reworked type_callback() to allow setting these values too. ------------------------------------------------------------------------ e96dc17a0625 | Andrew Apted | 2016-01-18 18:22:19 +1100 Sector panel : added widgets at bottom for Boom generalized sector types, and enable/disable them based on the game_info. They do not work yet... ------------------------------------------------------------------------ 282819b660af | Andrew Apted | 2016-01-18 16:04:35 +1100 Sector panel : got the headroom shortcut buttons working. ------------------------------------------------------------------------ 2b8bbdbc19cb | Andrew Apted | 2016-01-18 15:58:51 +1100 Sector panel : began work on buttons for setting headroom... ------------------------------------------------------------------------ bbceb92effdb | Andrew Apted | 2016-01-18 15:30:07 +1100 Generalized types : hide or show "Gen" button depending on game_info. ------------------------------------------------------------------------ fa5b620d1365 | Andrew Apted | 2016-01-18 15:08:24 +1100 Added a .gitignore file, ignore objects (*.o) and executables. ------------------------------------------------------------------------ cb6a39ba1ebb | Andrew Apted | 2016-01-18 15:03:41 +1100 Create obj_linux/ and obj_win32/ folders, which were lost after the conversion from SVN, and added .gitignore files in them. ------------------------------------------------------------------------ 0b46a7d4032f | Andrew Apted | 2016-01-17 13:11:33 +0000 TODO update. ------------------------------------------------------------------------ 9af1f2337766 | Andrew Apted | 2016-01-17 13:10:22 +0000 Generalized types : added "Gen" button to LineDef panel. ==================================================== DEVELOPMENT IN SVN REPOSITORY ==================================================== ------------------------------------------------------------------------ r1909 | ajapted | 2016-01-17 23:44:49 +1100 (Sun, 17 Jan 2016) | 3 lines Generalized types : in the Browser, support ACTIVE_GENERALIZED as the special value for "active" member, support 'G' in ChangeMode() method. ------------------------------------------------------------------------ r1908 | ajapted | 2016-01-17 23:20:25 +1100 (Sun, 17 Jan 2016) | 2 lines CMD_BrowserMode : support a "genline" keyword. ------------------------------------------------------------------------ r1907 | ajapted | 2016-01-17 23:18:21 +1100 (Sun, 17 Jan 2016) | 2 lines Menu : added "Generalized Line" command to Browser menu. ------------------------------------------------------------------------ r1906 | ajapted | 2016-01-17 23:13:56 +1100 (Sun, 17 Jan 2016) | 3 lines Generalized types : began work on a special browser box for displaying and editing a generalized type (via new UI_Generalized_Box class). ------------------------------------------------------------------------ r1905 | ajapted | 2016-01-17 23:00:16 +1100 (Sun, 17 Jan 2016) | 3 lines gen_types.ugh : removed the mask values, we simply compute it from the bits and shift values. ------------------------------------------------------------------------ r1904 | ajapted | 2016-01-17 21:51:04 +1100 (Sun, 17 Jan 2016) | 3 lines Replaced "Aspect ratio" preference with "Pixel aspect ratio", now just a simple number input box. The config variable was also renamed. ------------------------------------------------------------------------ r1903 | ajapted | 2016-01-17 21:07:11 +1100 (Sun, 17 Jan 2016) | 3 lines CMD_CopyProperties : implemented /reverse flag which copies from the highlighted object to the selected object(s). ------------------------------------------------------------------------ r1902 | ajapted | 2016-01-17 18:55:36 +1100 (Sun, 17 Jan 2016) | 2 lines TODO.txt updated. ------------------------------------------------------------------------ r1901 | ajapted | 2016-01-17 18:52:10 +1100 (Sun, 17 Jan 2016) | 9 lines CMD_Delete : allow sectors to be considered "unused" (and hence removed) if were are deleting linedefs (or verts) and the only linedefs remaining will not have a valid sector reference opposite them. This change was prompted by the case of removing the 3rd vertex in a triangle poking out from other geometry, which would delete the two linedefs but leave the one opposite the vertex with broken geometry (still two sided, with a sidedef facing the now defunct sector). ------------------------------------------------------------------------ r1900 | ajapted | 2016-01-17 18:36:56 +1100 (Sun, 17 Jan 2016) | 2 lines Check / vertices : ability to SHOW unused vertices. ------------------------------------------------------------------------ r1899 | ajapted | 2016-01-17 18:10:22 +1100 (Sun, 17 Jan 2016) | 2 lines CMD_Delete : remove unused sectors in vertex/linedef mode, fixed some bugs. ------------------------------------------------------------------------ r1898 | ajapted | 2016-01-17 17:54:25 +1100 (Sun, 17 Jan 2016) | 2 lines Improved the code in CMD_Delete(). ------------------------------------------------------------------------ r1897 | ajapted | 2016-01-17 16:00:12 +1100 (Sun, 17 Jan 2016) | 4 lines Improved FindClosestCrossPoint() to treat vertices as quite large, the exact size depending on the current zoom factor. This makes it easier for the user to draw a line through a vertex and have it autosplit. ------------------------------------------------------------------------ r1896 | ajapted | 2016-01-17 15:21:30 +1100 (Sun, 17 Jan 2016) | 2 lines Proper fix for previous commit (that commit was causing unclosed sectors). ------------------------------------------------------------------------ r1895 | ajapted | 2016-01-17 14:53:14 +1100 (Sun, 17 Jan 2016) | 4 lines When merging two connected linedefs (by dragging a vertex),fixed the handling when one of the lines is one-sided -- caused bad orientation of the merged line and/or missing middle texture. ------------------------------------------------------------------------ r1894 | ajapted | 2016-01-17 14:19:48 +1100 (Sun, 17 Jan 2016) | 2 lines Factored out a linedef utility function: LD_FixForLostSide() ------------------------------------------------------------------------ r1893 | ajapted | 2016-01-17 13:45:16 +1100 (Sun, 17 Jan 2016) | 3 lines Fixed creating overlapping lines when deleting 3rd vertex of a triangle (caused by merging the two linedefs connected at that vertex). ------------------------------------------------------------------------ r1892 | ajapted | 2016-01-17 00:45:42 +1100 (Sun, 17 Jan 2016) | 4 lines Added common/xlat_doom.cfg and common/xlat_hexen.cfg files. These are not used yet, but later will contain directives for converting between the two supported map formats (Doom and Hexen). ------------------------------------------------------------------------ r1891 | ajapted | 2016-01-17 00:13:51 +1100 (Sun, 17 Jan 2016) | 2 lines Browser : fixed things inserted by SPACE not appearing in RECENT category. ------------------------------------------------------------------------ r1890 | ajapted | 2016-01-17 00:03:49 +1100 (Sun, 17 Jan 2016) | 3 lines Browser : improved the RECENT category, properly sort items so that the most recent ones are near the top. ------------------------------------------------------------------------ r1889 | ajapted | 2016-01-16 21:42:55 +1100 (Sat, 16 Jan 2016) | 4 lines Browser : don't call RecentUpdate() directly from the insert() method of the recently used lists, since RecentUpdate() might be very expensive (e.g. needing to sort the whole texture list). ------------------------------------------------------------------------ r1888 | ajapted | 2016-01-16 20:53:28 +1100 (Sat, 16 Jan 2016) | 3 lines Disabled the MMB doing an "Insert" command, that functionality has been superceded by the new drawing mode. ------------------------------------------------------------------------ r1887 | ajapted | 2016-01-16 20:46:13 +1100 (Sat, 16 Jan 2016) | 2 lines Menu : added "Recent Textures" (etc) commands to the Browser menu. ------------------------------------------------------------------------ r1886 | ajapted | 2016-01-16 20:44:13 +1100 (Sat, 16 Jan 2016) | 2 lines Browser : increased size of RECENT category to 30 (was 11). ------------------------------------------------------------------------ r1885 | ajapted | 2016-01-16 18:45:53 +1100 (Sat, 16 Jan 2016) | 2 lines CHANGELOG and TODO update. ------------------------------------------------------------------------ r1884 | ajapted | 2016-01-16 18:34:21 +1100 (Sat, 16 Jan 2016) | 3 lines Disable a check for potential linedef overlaps -- not needed with the new autosplit logic. ------------------------------------------------------------------------ r1883 | ajapted | 2016-01-16 18:33:22 +1100 (Sat, 16 Jan 2016) | 2 lines FindClosestCrossPoint : finished the implementation. ------------------------------------------------------------------------ r1882 | ajapted | 2016-01-16 18:21:42 +1100 (Sat, 16 Jan 2016) | 3 lines FindClosestCrossPoint : tweak vertex check, worked on the linedef check (e.g. the intersection calculation, which seems to be working). ------------------------------------------------------------------------ r1881 | ajapted | 2016-01-16 15:52:16 +1100 (Sat, 16 Jan 2016) | 2 lines Detect vertex crossing in FindClosestCrossPoint(). ------------------------------------------------------------------------ r1880 | ajapted | 2016-01-16 14:11:33 +1100 (Sat, 16 Jan 2016) | 2 lines Began work on new FindClosestCrossPoint() function.... ------------------------------------------------------------------------ r1879 | ajapted | 2016-01-16 13:35:43 +1100 (Sat, 16 Jan 2016) | 4 lines Implemented high-level logic for Insert_LineDef_autosplit(), which will check if the new line crosses any existing lines or vertices and if so automatically create splits and multiple new linedefs (as needed). ------------------------------------------------------------------------ r1878 | ajapted | 2016-01-16 13:10:33 +1100 (Sat, 16 Jan 2016) | 5 lines Hexen : use "special" instead of "line" in the game definition file. In the code, temporarily made "special" synonymous with "line", though later they will need to be separate tables. ------------------------------------------------------------------------ r1877 | ajapted | 2016-01-16 12:16:33 +1100 (Sat, 16 Jan 2016) | 2 lines LineDef panel : made the Hexen arg boxes a bit wider. ------------------------------------------------------------------------ r1876 | ajapted | 2016-01-15 23:19:20 +1100 (Fri, 15 Jan 2016) | 2 lines Ports : include "gen_types" from the BOOM definition file. ------------------------------------------------------------------------ r1875 | ajapted | 2016-01-15 23:14:43 +1100 (Fri, 15 Jan 2016) | 3 lines Generalized types : implemented parsing of "gen_line" and "gen_field" commands (in the gen_types.ugh file). ------------------------------------------------------------------------ r1874 | ajapted | 2016-01-15 22:42:58 +1100 (Fri, 15 Jan 2016) | 3 lines Generalized types : define the structures that the parsing code will store the information into. ------------------------------------------------------------------------ r1873 | ajapted | 2016-01-15 22:25:14 +1100 (Fri, 15 Jan 2016) | 3 lines gen_types.ugh : fleshed out remaining types (LIFT, STAIR, CRUSHER) and tweaked a few other things. ------------------------------------------------------------------------ r1872 | ajapted | 2016-01-15 22:08:23 +1100 (Fri, 15 Jan 2016) | 2 lines gen_types.ugh : added fields for CEILING, DOOR and KEY DOOR. ------------------------------------------------------------------------ r1871 | ajapted | 2016-01-15 21:53:24 +1100 (Fri, 15 Jan 2016) | 3 lines Began work on 'common/gen_types.ugh' file which defines all the BOOM generalized line types. [ it will require new code too... ] ------------------------------------------------------------------------ r1870 | ajapted | 2016-01-15 20:54:59 +1100 (Fri, 15 Jan 2016) | 2 lines Find and Replace : added 'X' button to hide the panel. ------------------------------------------------------------------------ r1869 | ajapted | 2016-01-15 20:51:09 +1100 (Fri, 15 Jan 2016) | 2 lines Default Props : added an 'X' button to hide the panel. ------------------------------------------------------------------------ r1868 | ajapted | 2016-01-15 20:17:30 +1100 (Fri, 15 Jan 2016) | 2 lines TODO updated. ------------------------------------------------------------------------ r1867 | ajapted | 2016-01-15 20:16:54 +1100 (Fri, 15 Jan 2016) | 2 lines README : updated some key combos (e.g. SPACE + SHIFT) ------------------------------------------------------------------------ r1866 | ajapted | 2016-01-15 20:11:16 +1100 (Fri, 15 Jan 2016) | 3 lines Bindings : added /nofill flag to CMD-SPACE and CMD-INSERT, so that they behave the same as the hard-coded behavior of the LMB. ------------------------------------------------------------------------ r1865 | ajapted | 2016-01-15 20:08:30 +1100 (Fri, 15 Jan 2016) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1864 | ajapted | 2016-01-15 20:03:36 +1100 (Fri, 15 Jan 2016) | 3 lines Drawing mode : LMB + SHIFT now continues drawing mode (in cases where it normally stops) and LMB + CTRL now inhibits the creation of new sectors. ------------------------------------------------------------------------ r1863 | ajapted | 2016-01-15 19:54:09 +1100 (Fri, 15 Jan 2016) | 3 lines Implemented /nofill flag for CMD_Insert command, in vertex mode it prevents creating any new sectors. ------------------------------------------------------------------------ r1862 | ajapted | 2016-01-15 18:28:21 +1100 (Fri, 15 Jan 2016) | 2 lines Drawing mode : cancel drawing mode if the source vertex is deleted. ------------------------------------------------------------------------ r1861 | ajapted | 2016-01-15 17:47:22 +1100 (Fri, 15 Jan 2016) | 4 lines Drawing mode : if second vertex is on a line connected to first one, merely select them both. This allows to select numerous vertices even when drawing mode begins at first one. ------------------------------------------------------------------------ r1860 | ajapted | 2016-01-15 17:14:37 +1100 (Fri, 15 Jan 2016) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1859 | ajapted | 2016-01-15 17:11:33 +1100 (Fri, 15 Jan 2016) | 2 lines Sector panel : right click on floor/ceiling flat sets it to default. ------------------------------------------------------------------------ r1858 | ajapted | 2016-01-15 17:06:42 +1100 (Fri, 15 Jan 2016) | 3 lines LineDef panel : right-clicking on a texture sets it to the default, or "-" for the rail textures. ------------------------------------------------------------------------ r1857 | ajapted | 2016-01-15 00:57:18 +1100 (Fri, 15 Jan 2016) | 4 lines When inserting a linedef which splits a sector, ensure the line faces a consistent way (in other words, make the line's end vertex be the second one selected or created). ------------------------------------------------------------------------ r1856 | ajapted | 2016-01-13 20:31:44 +1100 (Wed, 13 Jan 2016) | 2 lines Drawing mode : exit drawing mode on the "Unselect All" command. ------------------------------------------------------------------------ r1855 | ajapted | 2016-01-13 20:11:04 +1100 (Wed, 13 Jan 2016) | 2 lines Drawing mode : fixed bug beginning to draw when edit mode != VERTEX. ------------------------------------------------------------------------ r1854 | ajapted | 2016-01-13 20:01:18 +1100 (Wed, 13 Jan 2016) | 2 lines Replaced "edit.RedrawMap = 1" with a function call: RedrawMap() ------------------------------------------------------------------------ r1853 | ajapted | 2016-01-13 19:47:58 +1100 (Wed, 13 Jan 2016) | 5 lines Drawing mode : begin drawing on mouse release after clicking on a vertex and not dragging it, and when no other vertices were selected. This is now working as a user would expect. ------------------------------------------------------------------------ r1852 | ajapted | 2016-01-13 19:01:08 +1100 (Wed, 13 Jan 2016) | 3 lines When showing a split-line, store X/Y coordinate in the editor state (instead of recomputing them in Vertex_Insert). ------------------------------------------------------------------------ r1851 | ajapted | 2016-01-13 18:35:55 +1100 (Wed, 13 Jan 2016) | 4 lines Drawing mode : don't draw a vertex when another vertex is highlighted, or when split-line is active. If another vertex is highlighted, "snap" the line onto it (since inserting will use it as the new endpoint). ------------------------------------------------------------------------ r1850 | ajapted | 2016-01-13 18:15:17 +1100 (Wed, 13 Jan 2016) | 2 lines Drawing mode : worked on making it a proper action: ACT_DRAW_LINE. ------------------------------------------------------------------------ r1849 | ajapted | 2016-01-12 21:42:11 +1100 (Tue, 12 Jan 2016) | 2 lines Sector rendering : use the dummy image for unknown flats. ------------------------------------------------------------------------ r1848 | ajapted | 2016-01-12 21:38:25 +1100 (Tue, 12 Jan 2016) | 4 lines Reworked code for creating dummy textures, they are now cached by functions in im_img.cc (IM_MissingTex etc) instead of r_render.cc, and increased the size from 32x32 --> 64x64. ------------------------------------------------------------------------ r1847 | ajapted | 2016-01-12 19:15:03 +1100 (Tue, 12 Jan 2016) | 4 lines Vertex drawing : draw a vertex too (as well as the red line) and handle grid-snapping properly. Fixed several issues when inserting (generally turning off the drawing mode). ------------------------------------------------------------------------ r1846 | ajapted | 2016-01-12 18:42:20 +1100 (Tue, 12 Jan 2016) | 4 lines Began work on a "drawing mode", after inserting a vertex we continuously draw a red line from it to where the next vertex will go, and allow a simple left click to insert the next vertex. Quite buggy atm... ------------------------------------------------------------------------ r1845 | ajapted | 2016-01-12 16:52:14 +1100 (Tue, 12 Jan 2016) | 2 lines Fixed mouse-wheel zooming around wrong spot after loading a new map. ------------------------------------------------------------------------ r1844 | ajapted | 2016-01-12 16:39:52 +1100 (Tue, 12 Jan 2016) | 2 lines Sector rendering : save/restore the state to the cache .dat file. ------------------------------------------------------------------------ r1843 | ajapted | 2016-01-12 16:30:30 +1100 (Tue, 12 Jan 2016) | 2 lines CHANGELOG updated. ------------------------------------------------------------------------ r1842 | ajapted | 2016-01-12 16:29:00 +1100 (Tue, 12 Jan 2016) | 3 lines Menu : added "Sector Rendering" choice to the View menu, implemented via new 'sector_render_mode' field in the editor_state structure. ------------------------------------------------------------------------ r1841 | ajapted | 2016-01-11 14:06:12 +1100 (Mon, 11 Jan 2016) | 7 lines ALL GAMES : reworked color definitions: * sky is now a fairly light blue * unknown_tex is as close to bright cyan as possible * unknown_flat is a fairly bright green * wall colors are grayscale * floor colors are a light brown ------------------------------------------------------------------------ r1840 | ajapted | 2016-01-11 13:44:02 +1100 (Mon, 11 Jan 2016) | 3 lines Replaced "R3D_Gamma" command with "Gamma" command so it can be used in general scope, and fixed the F11 key in the bindings.cfg file. ------------------------------------------------------------------------ r1839 | ajapted | 2016-01-11 13:33:50 +1100 (Mon, 11 Jan 2016) | 6 lines Changed TRANS_PIXEL from 247 --> 255, which is more friendly to Heretic and Hexen games. Also updated COLORMAP loader to replace any TRANS_PIXEL values, just in case some code uses it when creating an Img_c. ------------------------------------------------------------------------ r1838 | ajapted | 2016-01-11 11:33:58 +1100 (Mon, 11 Jan 2016) | 3 lines Canvas : fleshed out support for different modes in RenderSector(), e.g. solid rendering for an unknown texture using the game specific color. ------------------------------------------------------------------------ r1837 | ajapted | 2016-01-10 20:48:36 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas : compute proper texture coords for rendering sector flats. ------------------------------------------------------------------------ r1836 | ajapted | 2016-01-10 20:33:47 +1100 (Sun, 10 Jan 2016) | 3 lines Canvas : rendering sector flats is working, albeit not scaled or translated properly yet.... ------------------------------------------------------------------------ r1835 | ajapted | 2016-01-10 20:20:31 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas : partial work on rendering sectors with a flat texture... ------------------------------------------------------------------------ r1834 | ajapted | 2016-01-10 20:06:20 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas : ability to render sectors as solid, showing their light levels. ------------------------------------------------------------------------ r1833 | ajapted | 2016-01-10 19:34:40 +1100 (Sun, 10 Jan 2016) | 3 lines Added config file variables: light_bump_small, _medium, _large. The default for non-modifier light button is 16 units (up or down). ------------------------------------------------------------------------ r1832 | ajapted | 2016-01-10 19:26:21 +1100 (Sun, 10 Jan 2016) | 2 lines Added SectorLightColor() utility function. ------------------------------------------------------------------------ r1831 | ajapted | 2016-01-10 18:40:08 +1100 (Sun, 10 Jan 2016) | 2 lines README : some updates. ------------------------------------------------------------------------ r1830 | ajapted | 2016-01-10 18:37:36 +1100 (Sun, 10 Jan 2016) | 2 lines TODO update. ------------------------------------------------------------------------ r1829 | ajapted | 2016-01-10 18:31:57 +1100 (Sun, 10 Jan 2016) | 7 lines Added workaround for loading BOOM definitions with games that are not supported by BOOM (Heretic and Hexen) -- we skip parsing the boom.ugh config file for certain games (done via new "exclude_game" directive). A better system for specifying which game + port combinations are usable is definitely needed -- something to be tackled later on. ------------------------------------------------------------------------ r1828 | ajapted | 2016-01-10 18:10:47 +1100 (Sun, 10 Jan 2016) | 2 lines Version bump and updated printf'd copyright year for 2016. ------------------------------------------------------------------------ r1827 | ajapted | 2016-01-10 18:09:32 +1100 (Sun, 10 Jan 2016) | 2 lines About window : credit Ioan Chera in the copyright lines. ------------------------------------------------------------------------ r1826 | ajapted | 2016-01-10 17:09:59 +1100 (Sun, 10 Jan 2016) | 2 lines Eternity support : added a "3D MidTex" checkbox to the LineDef panel. ------------------------------------------------------------------------ r1825 | ajapted | 2016-01-10 16:54:23 +1100 (Sun, 10 Jan 2016) | 2 lines code : removed unused GetAngleName() and GetWhenName() functions. ------------------------------------------------------------------------ r1824 | ajapted | 2016-01-10 16:51:01 +1100 (Sun, 10 Jan 2016) | 3 lines Only show the "passthru" linedef flag when the game/port supports it. Added "feature pass_through 1" to the BOOM definition file. ------------------------------------------------------------------------ r1823 | ajapted | 2016-01-10 16:39:06 +1100 (Sun, 10 Jan 2016) | 3 lines Hexen (etc) : removed UpdateMapFormatInfo() methods, use UpdateGameInfo() for map format stuff too. ------------------------------------------------------------------------ r1822 | ajapted | 2016-01-10 16:08:23 +1100 (Sun, 10 Jan 2016) | 3 lines UI : in Sector panel, moved the "Headroom" widget below the rest, with a few other tweaks to the layout. ------------------------------------------------------------------------ r1821 | ajapted | 2016-01-10 15:25:23 +1100 (Sun, 10 Jan 2016) | 3 lines UI : code tidying -- remove explicit add() calls in UI_Sector and UI_NodeDialog constructors. ------------------------------------------------------------------------ r1820 | ajapted | 2016-01-10 15:18:30 +1100 (Sun, 10 Jan 2016) | 2 lines UI : improved layout of Sector panel, more roomy. ------------------------------------------------------------------------ r1819 | ajapted | 2016-01-10 15:09:26 +1100 (Sun, 10 Jan 2016) | 2 lines UI : tweaked position of UI_Nombre in each editing panel. ------------------------------------------------------------------------ r1818 | ajapted | 2016-01-10 14:54:23 +1100 (Sun, 10 Jan 2016) | 2 lines UI : offset the first column of flags in the LineDef panel. ------------------------------------------------------------------------ r1817 | ajapted | 2016-01-10 14:49:24 +1100 (Sun, 10 Jan 2016) | 2 lines UI : tweaked layout in the LineDef panel, bit more vertical spacing. ------------------------------------------------------------------------ r1816 | ajapted | 2016-01-10 13:27:01 +1100 (Sun, 10 Jan 2016) | 2 lines Hexen : use tooltips to show what arguments of a line/thing special do. ------------------------------------------------------------------------ r1815 | ajapted | 2016-01-10 13:16:50 +1100 (Sun, 10 Jan 2016) | 3 lines Hexen : when showing args in LineDef / Thing panels, show a zero instead of a blank when the special for the line/thing actually uses that arg. ------------------------------------------------------------------------ r1814 | ajapted | 2016-01-10 12:26:49 +1100 (Sun, 10 Jan 2016) | 3 lines Inserting vertices with SHIFT always selects the new vertex. This is achieved via new "/select" flag for the Insert key command. ------------------------------------------------------------------------ r1813 | ajapted | 2016-01-10 11:02:06 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas : fixed some bugs in 2D sector rendering (e.g. min_y/max_y calcs). ------------------------------------------------------------------------ r1812 | ajapted | 2016-01-10 01:10:37 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas / RenderSector : fixed CMP_X to place NULLs at end of list. ------------------------------------------------------------------------ r1811 | ajapted | 2016-01-10 01:01:36 +1100 (Sun, 10 Jan 2016) | 3 lines Canvas : got solid rendering of a rectangular sector working. The next step will be to render flats.... ------------------------------------------------------------------------ r1810 | ajapted | 2016-01-10 00:52:18 +1100 (Sun, 10 Jan 2016) | 4 lines Canvas : for 2D sector rendering, compute the "side" field, added "x" field for the computed X values, and implemented finding the spans. ------------------------------------------------------------------------ r1809 | ajapted | 2016-01-10 00:30:14 +1100 (Sun, 10 Jan 2016) | 2 lines TODO.txt updated. ------------------------------------------------------------------------ r1808 | ajapted | 2016-01-10 00:25:23 +1100 (Sun, 10 Jan 2016) | 2 lines CHANGELOG : minor rearrange. ------------------------------------------------------------------------ r1807 | ajapted | 2016-01-10 00:14:01 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas : more work on experimental 2D sector rendering.... ------------------------------------------------------------------------ r1806 | ajapted | 2016-01-09 21:19:26 +1100 (Sat, 09 Jan 2016) | 2 lines Hexen : fully support the special type in the Thing panel. ------------------------------------------------------------------------ r1805 | ajapted | 2016-01-09 21:04:17 +1100 (Sat, 09 Jan 2016) | 3 lines Hexen : implemented the Thing special "Choose" button, and allow a click on a browser item to set the special type. ------------------------------------------------------------------------ r1804 | ajapted | 2016-01-09 20:52:13 +1100 (Sat, 09 Jan 2016) | 2 lines Canvas : began work on experimental RenderSector() method.... ------------------------------------------------------------------------ r1803 | ajapted | 2016-01-09 20:05:36 +1100 (Sat, 09 Jan 2016) | 2 lines Hexen : support showing and editing arguments in the Thing panel. ------------------------------------------------------------------------ r1802 | ajapted | 2016-01-08 19:43:59 +1100 (Fri, 08 Jan 2016) | 6 lines Thing panel : reorganized it e.g. moved sprite above the arrow circle (closer to the Type / Desc widgets), and a few other tweaks. This was prompted by a need for all the new Hexen stuff to fit in the minimum window size (which it now does). ------------------------------------------------------------------------ r1801 | ajapted | 2016-01-08 18:45:50 +1100 (Fri, 08 Jan 2016) | 3 lines Hexen : added "Special", "Args" (etc) widgets in the Thing panel. They are not implemented yet.... ------------------------------------------------------------------------ r1800 | ajapted | 2016-01-08 18:22:52 +1100 (Fri, 08 Jan 2016) | 2 lines Hexen : implemented "dormant" flag in the Thing panel. ------------------------------------------------------------------------ r1799 | ajapted | 2016-01-08 18:11:33 +1100 (Fri, 08 Jan 2016) | 2 lines Hexen : fixed wrong "mask" values for SP/COOP/DM buttons (used by callback function). ------------------------------------------------------------------------ r1798 | ajapted | 2016-01-08 17:10:03 +1100 (Fri, 08 Jan 2016) | 2 lines Hexen : support the class flags (Fighter/Cleric/Magic) in Thing panel. ------------------------------------------------------------------------ r1797 | ajapted | 2016-01-08 16:46:35 +1100 (Fri, 08 Jan 2016) | 2 lines Hexen : support game mode flags (SP, COOP, DM) in the Things panel. ------------------------------------------------------------------------ r1796 | ajapted | 2016-01-08 16:31:15 +1100 (Fri, 08 Jan 2016) | 3 lines Check things : updated stuck-things detection to handle HEXEN flags, especially the class bits. ------------------------------------------------------------------------ r1795 | ajapted | 2016-01-08 16:24:10 +1100 (Fri, 08 Jan 2016) | 2 lines Fixed a bug recently introduced in the stuck-thing detection. ------------------------------------------------------------------------ r1794 | ajapted | 2016-01-08 16:18:24 +1100 (Fri, 08 Jan 2016) | 2 lines Added config file variable: default_gamma ------------------------------------------------------------------------ r1793 | ajapted | 2016-01-08 15:08:53 +1100 (Fri, 08 Jan 2016) | 2 lines Added config file variables: floor_bump_small, _medium, _large. ------------------------------------------------------------------------ r1792 | ajapted | 2016-01-06 14:49:05 +1100 (Wed, 06 Jan 2016) | 4 lines Makefile : the install target now deletes the old "freedoom.ugh" config, preventing it from appearing in the Manage Project dialog (along with freedoom1 and freedoom2, which is confusing). ------------------------------------------------------------------------ r1791 | ajapted | 2015-12-31 14:31:48 +1100 (Thu, 31 Dec 2015) | 3 lines CHANGELOG : brought the changelog completely up-to-date, and reorganised with most important elements at the top. ------------------------------------------------------------------------ r1790 | ajapted | 2015-12-30 12:45:23 +1100 (Wed, 30 Dec 2015) | 3 lines Hexen : in Linedef panel, support setting new Activation values via the choice button. ------------------------------------------------------------------------ r1789 | ajapted | 2015-12-30 12:35:29 +1100 (Wed, 30 Dec 2015) | 2 lines Hexen : properly update the Activation choice when selecting/hilighting lines. ------------------------------------------------------------------------ r1788 | ajapted | 2015-12-30 12:14:47 +1100 (Wed, 30 Dec 2015) | 2 lines Thing panel : moved the arrow circle (up and left) and made the buttons bigger. ------------------------------------------------------------------------ r1787 | ajapted | 2015-12-30 12:10:41 +1100 (Wed, 30 Dec 2015) | 2 lines UI : made the right panel slightly wider. ------------------------------------------------------------------------ r1786 | ajapted | 2015-12-30 12:06:21 +1100 (Wed, 30 Dec 2015) | 3 lines Hexen : in LineDef panel added a choice widget for the activation mode of the linedef -- with choices such as W1, SR, G1 (etc....) ------------------------------------------------------------------------ r1785 | ajapted | 2015-12-30 11:30:21 +1100 (Wed, 30 Dec 2015) | 3 lines Map loading : allow loading a map with no vertices, no linedefs (etc...) Also factored out some common code in linedef loaders: ValidateSidedefs() ------------------------------------------------------------------------ r1784 | ajapted | 2015-12-29 23:27:54 +1100 (Tue, 29 Dec 2015) | 2 lines Hexen : made the Linedef panel actually show the 5 arguments. ------------------------------------------------------------------------ r1783 | ajapted | 2015-12-29 23:13:56 +1100 (Tue, 29 Dec 2015) | 3 lines Hexen : in Linedef panel show the five "Args:" boxes when in Hexen mode, and implemented args_callback() which can set new values. ------------------------------------------------------------------------ r1782 | ajapted | 2015-12-29 22:51:03 +1100 (Tue, 29 Dec 2015) | 2 lines Find / Replace : support the "tag" filter for Hexen things (TID). ------------------------------------------------------------------------ r1781 | ajapted | 2015-12-29 19:43:14 +1100 (Tue, 29 Dec 2015) | 3 lines Changed DEFAULT_PORT to be "vanilla" instead of "boom", because Boom is only a DOOM engine and does not support Heretic or Hexen. ------------------------------------------------------------------------ r1780 | ajapted | 2015-12-29 19:36:23 +1100 (Tue, 29 Dec 2015) | 2 lines HEXEN conf : added four linegroups: Animated, Door, Lift, Stairs. ------------------------------------------------------------------------ r1779 | ajapted | 2015-12-29 19:20:09 +1100 (Tue, 29 Dec 2015) | 2 lines DOOM conf : minor comment fix (syntax of "line" command). ------------------------------------------------------------------------ r1778 | ajapted | 2015-12-29 19:15:57 +1100 (Tue, 29 Dec 2015) | 3 lines Browser : fixed alpha sorting of line specials for Hexen (it did not handle the lack of a S1/WR/etc action name at beginning of the description). ------------------------------------------------------------------------ r1777 | ajapted | 2015-12-29 19:05:15 +1100 (Tue, 29 Dec 2015) | 2 lines HEXEN conf : added two missing specials: 138 "Floor_Waggle" and 109 "Force_Lightning". ------------------------------------------------------------------------ r1776 | ajapted | 2015-12-29 18:58:34 +1100 (Tue, 29 Dec 2015) | 2 lines HEXEN conf : added missing line/thing special 0 ("NOTHING"). ------------------------------------------------------------------------ r1775 | ajapted | 2015-12-29 18:48:31 +1100 (Tue, 29 Dec 2015) | 2 lines Game def parser : support arg1..arg5 names in "line" commands (for Hexen). ------------------------------------------------------------------------ r1774 | ajapted | 2015-12-29 18:38:29 +1100 (Tue, 29 Dec 2015) | 2 lines HEXEN conf : finished the line/thing specials. ------------------------------------------------------------------------ r1773 | ajapted | 2015-12-29 18:20:15 +1100 (Tue, 29 Dec 2015) | 3 lines HEXEN conf : more work on line/thing specials, simplifying and/or abbreviating some names and renamed a few argument names. ------------------------------------------------------------------------ r1772 | ajapted | 2015-12-29 17:19:27 +1100 (Tue, 29 Dec 2015) | 3 lines HEXEN conf : more work on the specials, put all types into an appropriate category and renamed a few specials. ------------------------------------------------------------------------ r1771 | ajapted | 2015-12-29 17:06:36 +1100 (Tue, 29 Dec 2015) | 3 lines HEXEN config : began work to define all the line/thing specials, based on the Unofficial Hexen Specifications. ------------------------------------------------------------------------ r1770 | ajapted | 2015-12-29 14:55:02 +1100 (Tue, 29 Dec 2015) | 3 lines Use absolute paths for resource filenames in __EUREKA lump, since that is more robust (allows moving the wad to another folder). ------------------------------------------------------------------------ r1769 | ajapted | 2015-12-29 14:42:04 +1100 (Tue, 29 Dec 2015) | 8 lines Added a built-in "DOGS" sprite for when port is Boom (or compatible), as that sprite is generally not available in the IWADs and showing a missing sprite in the browser was quite ugly / distracting. This dog sprite was sourced from the OpenGameArt.org website. Authors are 'Benalene' and 'qudobup' (users on the OGA site). License is CC-BY 3.0 (Creative Commons Attribution license). ------------------------------------------------------------------------ r1768 | ajapted | 2015-12-29 14:33:02 +1100 (Tue, 29 Dec 2015) | 3 lines Image class : added IM_CreateFromText() function which can generate an Img_c from some builtin strings and palette [ not unlike XPM ]. ------------------------------------------------------------------------ r1767 | ajapted | 2015-12-29 14:04:29 +1100 (Tue, 29 Dec 2015) | 2 lines Removed RGB_INVALID constant -- not used anywhere. ------------------------------------------------------------------------ r1766 | ajapted | 2015-12-27 21:29:19 +1100 (Sun, 27 Dec 2015) | 2 lines Configs : updated comments to remove "should not exceed 24 characters" advice. ------------------------------------------------------------------------ r1765 | ajapted | 2015-12-27 21:24:32 +1100 (Sun, 27 Dec 2015) | 3 lines Hexen : define the new linedef flags (MLF_Repeatable, MLF_Activation) plus some ZDoom flags. Also define the activation values (SPAC_XXX). ------------------------------------------------------------------------ r1764 | ajapted | 2015-12-27 19:23:52 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : finished sector types. ------------------------------------------------------------------------ r1763 | ajapted | 2015-12-27 19:13:12 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN conf : worked on adding all the Sector specials... ------------------------------------------------------------------------ r1762 | ajapted | 2015-12-27 18:09:37 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : a few fixes (e.g. Cauldron sprites). ------------------------------------------------------------------------ r1761 | ajapted | 2015-12-27 18:07:25 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : finished improving the names of things. ------------------------------------------------------------------------ r1760 | ajapted | 2015-12-27 17:54:22 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN conf : worked on improving names of decorative things... ------------------------------------------------------------------------ r1759 | ajapted | 2015-12-27 17:17:35 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : split decorations by adding new "Natural" category. ------------------------------------------------------------------------ r1758 | ajapted | 2015-12-27 17:06:56 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : added all remaining thing types (though names need fixing...) ------------------------------------------------------------------------ r1757 | ajapted | 2015-12-27 16:49:46 +1100 (Sun, 27 Dec 2015) | 2 lines Hexen config : added thing types 10500-10503 and 8500-8509. ------------------------------------------------------------------------ r1756 | ajapted | 2015-12-27 16:41:03 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : added the puzzle-piece items (plus a new category for them). ------------------------------------------------------------------------ r1755 | ajapted | 2015-12-27 16:36:23 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : id numbers for 'Flechette' and 'Disc of Repulsion' were reversed, fixed. ------------------------------------------------------------------------ r1754 | ajapted | 2015-12-27 15:03:45 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : added player starts 5-8 and the soundtype markers (things 1400-1409). ------------------------------------------------------------------------ r1753 | ajapted | 2015-12-27 14:48:40 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN : added whitespace to align columns (for Things). ------------------------------------------------------------------------ r1752 | ajapted | 2015-12-27 12:09:48 +1100 (Sun, 27 Dec 2015) | 2 lines TODO : minor update ------------------------------------------------------------------------ r1751 | ajapted | 2015-12-27 12:05:35 +1100 (Sun, 27 Dec 2015) | 7 lines In game definitions support 't' flag for things like teleport destination which can safely overlap moving actors (players and monsters) but not decorative things. Reworked thing stuck checking code to handle it (and also to only check each pair of blocking things ONCE). ------------------------------------------------------------------------ r1750 | ajapted | 2015-12-20 12:42:05 +1100 (Sun, 20 Dec 2015) | 2 lines Removed top-level "ups" folder -- not used for anything. ------------------------------------------------------------------------ r1749 | ajapted | 2015-12-20 12:38:40 +1100 (Sun, 20 Dec 2015) | 2 lines TODO.txt : updated. ------------------------------------------------------------------------ r1748 | ajapted | 2015-12-20 12:35:17 +1100 (Sun, 20 Dec 2015) | 3 lines GAME definitions : removed "level_name XXX" lines, which are not used (they were simply ignored by the UGH file parser). ------------------------------------------------------------------------ r1747 | ajapted | 2015-12-19 23:48:41 +1100 (Sat, 19 Dec 2015) | 4 lines Hexen support : added "z" widget to the Thing panel (only visible when editing a hexen format map). Also apply the Z value when rendering things in the 3D preview. These changes by Ioan Chera. ------------------------------------------------------------------------ r1746 | ajapted | 2015-12-19 23:21:37 +1100 (Sat, 19 Dec 2015) | 3 lines Hexen support : added "TID" widget to the Thing panel when the current map format is Hexen (and hide it otherwise). This code by Ioan Chera. ------------------------------------------------------------------------ r1745 | ajapted | 2015-12-19 23:08:56 +1100 (Sat, 19 Dec 2015) | 4 lines Hexen support : code for reading and writing Hexen format maps, including handling the BEHAVIOR lump. This code originally by Ioan Chera (printz) with a few tweaks by me. ------------------------------------------------------------------------ r1744 | ajapted | 2015-12-19 22:13:01 +1100 (Sat, 19 Dec 2015) | 2 lines GAMES : added partial Hexen config (ugh) file -- thanks to printz. ------------------------------------------------------------------------ r1743 | ajapted | 2015-12-19 21:29:24 +1100 (Sat, 19 Dec 2015) | 6 lines Check lines : detect manual (D1,DR) doors on one-sided linedefs, with options to show or fix them (we "fix" them by clearing the special). Reason for this check is that such doors can crash vanilla DOOM. This closes ticket #16. ------------------------------------------------------------------------ r1742 | ajapted | 2015-12-19 20:58:19 +1100 (Sat, 19 Dec 2015) | 3 lines HERETIC: renamed two monsters: "Gargoyle Leader" --> "Fire Gargoyle", and "Golem Leader" --> "Nitro Golem" (more consistent with the game). ------------------------------------------------------------------------ r1741 | ajapted | 2015-11-27 12:56:56 +1100 (Fri, 27 Nov 2015) | 3 lines glBSP library : disabled the "no nodes" hack which created a dummy node and subsector -- turns out that vanilla DOOM copes with no nodes just fine. ------------------------------------------------------------------------ r1740 | ajapted | 2015-09-21 19:40:23 +1000 (Mon, 21 Sep 2015) | 9 lines Updated eureka.desktop file with: 1. %f on Exec line and a MimeType line, so can handle wad files from file-system exploring/navigation programs 2. replaced "X-DoomEditor" category with "ActionGame" 3. added Keywords line Thanks to Fabian Greffrath for the patch (ticket #17). I tweaked the set of keywords (e.g. added "heretic"). ------------------------------------------------------------------------ r1739 | ajapted | 2015-09-09 13:54:40 +1000 (Wed, 09 Sep 2015) | 4 lines Another fix for the freedoom1/freedoom2 distinction -- when loading known iwads, ignore the plain "freedoom" entry (so it won't appear as a choice in the Manage Project dialog). ------------------------------------------------------------------------ r1738 | ajapted | 2015-09-08 21:37:46 +1000 (Tue, 08 Sep 2015) | 5 lines Fixed problem when looking for 'freedoom' as an emergency IWAD to use, since there are now separate config files for Phase 1 and Phase 2, namely 'freedoom1.ugh' and 'freedoom2.ugh', hence the code should check these instead of plain 'freedoom'. ------------------------------------------------------------------------ r1737 | ajapted | 2015-09-07 22:02:51 +1000 (Mon, 07 Sep 2015) | 4 lines Ports / Eternity : added "EE:" prefix to all linetype descriptions, removed the 'x', 'w' and 'u' categories, various tweaks to the descriptions e.g. added /f and /c to designate types that use/affect a floor or ceiling. ------------------------------------------------------------------------ r1736 | ajapted | 2015-09-07 21:43:05 +1000 (Mon, 07 Sep 2015) | 3 lines Checked in definition file for the 'Eternity' source port, courtesy printz (with some editing by me). ------------------------------------------------------------------------ r1735 | ajapted | 2015-08-29 22:53:08 +1000 (Sat, 29 Aug 2015) | 2 lines Browser: increased default width by 10 pixels (show 4 columns of sprites). ------------------------------------------------------------------------ r1734 | ajapted | 2015-08-29 22:51:38 +1000 (Sat, 29 Aug 2015) | 4 lines Better handle the case when merging linedefs after dragging a vertex (check the sectors on each side and decide if need to change a sidedef on the linedef which remains, or even delete the other linedef). ------------------------------------------------------------------------ r1733 | printz | 2015-08-23 18:58:37 +1000 (Sun, 23 Aug 2015) | 3 lines Eureka for OSX is now code-signed * Also updated recommended project settings. ------------------------------------------------------------------------ r1732 | ajapted | 2015-06-13 16:43:15 +1000 (Sat, 13 Jun 2015) | 2 lines Created new CHANGES.txt after the previous release. ------------------------------------------------------------------------ r1731 | ajapted | 2015-06-13 16:40:15 +1000 (Sat, 13 Jun 2015) | 2 lines Moved CHANGES.txt --> changelogs/107.txt ------------------------------------------------------------------------ r1730 | ajapted | 2015-06-13 16:36:33 +1000 (Sat, 13 Jun 2015) | 3 lines Check / textures : implemented checking for the Medusa Effect, but only when the game or port specifies the "medusa_bug" feature. ------------------------------------------------------------------------ r1729 | ajapted | 2015-06-13 14:21:01 +1000 (Sat, 13 Jun 2015) | 2 lines Ports / vanilla : added "feature medusa_bug 1" ------------------------------------------------------------------------ r1728 | ajapted | 2015-06-13 14:20:18 +1000 (Sat, 13 Jun 2015) | 3 lines Support 'medusa_bug' feature in game definitions (mainly needed by Vanilla to indicate that it is prone to the Medusa Effect). ------------------------------------------------------------------------ r1727 | ajapted | 2015-06-13 14:14:16 +1000 (Sat, 13 Jun 2015) | 3 lines Texture loader : check for textures which potentially cause the Medusa Effect when used as a mid-masked texture on a 2S line. ------------------------------------------------------------------------ r1726 | ajapted | 2015-06-12 14:57:04 +1000 (Fri, 12 Jun 2015) | 4 lines Check / textures : implemented test for transparent textures used on solid parts of walls, including "Log" button to list them and "Fix" button to automatically set them to the default wall texture. ------------------------------------------------------------------------ r1725 | ajapted | 2015-06-12 14:34:19 +1000 (Fri, 12 Jun 2015) | 2 lines Image class : added has_transparent() method. ------------------------------------------------------------------------ r1724 | ajapted | 2015-03-03 19:47:41 +1100 (Tue, 03 Mar 2015) | 2 lines GAME DEFS : minor comment changes in freedoom2.ugh ------------------------------------------------------------------------ r1723 | ajapted | 2015-03-03 19:46:24 +1100 (Tue, 03 Mar 2015) | 4 lines GAME DEFS : better support for latest FreeDoom release: 1. renamed freedoom.ugh --> freedoom2.ugh 2. added freedoom1.ugh which simply includes "doom" ------------------------------------------------------------------------ r1722 | ajapted | 2015-02-18 18:22:05 +1100 (Wed, 18 Feb 2015) | 2 lines README.txt : removed 'F5' key description. ------------------------------------------------------------------------ r1721 | printz | 2015-02-17 18:30:38 +1100 (Tue, 17 Feb 2015) | 1 line osx: Bumped info.plist version ------------------------------------------------------------------------ r1720 | ajapted | 2015-02-16 18:24:43 +1100 (Mon, 16 Feb 2015) | 2 lines Changed default of 'render_aspect_ratio' config var --> 133. ------------------------------------------------------------------------ r1719 | ajapted | 2015-02-16 18:21:57 +1100 (Mon, 16 Feb 2015) | 2 lines Win32 package : fixed missing logo image. ------------------------------------------------------------------------ r1718 | ajapted | 2015-02-16 16:58:48 +1100 (Mon, 16 Feb 2015) | 2 lines CHANGELOG : added current revision. ------------------------------------------------------------------------ r1717 | ajapted | 2015-02-16 16:47:13 +1100 (Mon, 16 Feb 2015) | 2 lines docs/History : re-sync with SVN repository logs (ready fo release). ------------------------------------------------------------------------ r1716 | ajapted | 2015-02-16 15:41:50 +1100 (Mon, 16 Feb 2015) | 2 lines CHANGELOG and TODO updated for the release. ------------------------------------------------------------------------ r1715 | ajapted | 2015-02-16 15:41:00 +1100 (Mon, 16 Feb 2015) | 2 lines Makefile : re-enable optimisation for the upcoming release. ------------------------------------------------------------------------ r1714 | ajapted | 2015-02-16 15:31:38 +1100 (Mon, 16 Feb 2015) | 3 lines Default Props : implemented showing sprite for default thing, and clicking on it opens the Thing browser. ------------------------------------------------------------------------ r1713 | ajapted | 2015-02-16 15:06:41 +1100 (Mon, 16 Feb 2015) | 3 lines Default Properties : only show a single "wall" texture (instead of having three of them, which was rather unwieldy). ------------------------------------------------------------------------ r1712 | ajapted | 2015-02-16 12:38:52 +1100 (Mon, 16 Feb 2015) | 2 lines Makefile.xming : updated to FLTK 1.3.3 ------------------------------------------------------------------------ r1711 | ajapted | 2015-02-16 12:38:03 +1100 (Mon, 16 Feb 2015) | 2 lines FLTK tweak : add FL_DOUBLE flag to Fl::visual() call. ------------------------------------------------------------------------ r1710 | ajapted | 2015-02-16 12:35:31 +1100 (Mon, 16 Feb 2015) | 2 lines README.txt : update (c) year. ------------------------------------------------------------------------ r1709 | ajapted | 2015-02-16 00:21:28 +1100 (Mon, 16 Feb 2015) | 2 lines pack scripts : added missing "bindings.cfg" to them (Esp. the Win32 package) ------------------------------------------------------------------------ r1708 | ajapted | 2015-02-16 00:10:20 +1100 (Mon, 16 Feb 2015) | 3 lines Show error dialog when the standard "bindings.cfg" file cannot be loaded (call M_LoadBindings _after_ bumping init_progress to 3). ------------------------------------------------------------------------ r1707 | ajapted | 2015-02-15 23:14:15 +1100 (Sun, 15 Feb 2015) | 2 lines pack-win32 script : small improvements. ------------------------------------------------------------------------ r1706 | ajapted | 2015-02-15 23:10:27 +1100 (Sun, 15 Feb 2015) | 2 lines Win32 : created 'pack-win32.sh' shell script for creating a package. ------------------------------------------------------------------------ r1705 | ajapted | 2015-02-15 22:56:42 +1100 (Sun, 15 Feb 2015) | 3 lines pack-source script : rewrote it, removed "cd ..", removed "$src" variable, use "svn export" for copying directory contents. ------------------------------------------------------------------------ r1704 | ajapted | 2015-02-15 22:31:25 +1100 (Sun, 15 Feb 2015) | 7 lines Win32 : implement a fallback for $home_dir when the %APPDATA% folder cannot be determined. We also now call Determine_InstallPath() _before_ Determine_HomeDir(), needed by the above change, and I'm 99% sure that this is perfectly fine for all platforms. ------------------------------------------------------------------------ r1703 | ajapted | 2015-02-15 22:15:14 +1100 (Sun, 15 Feb 2015) | 2 lines Makefile.xming : more tidying. ------------------------------------------------------------------------ r1702 | ajapted | 2015-02-15 22:14:10 +1100 (Sun, 15 Feb 2015) | 2 lines Makefile.xming : removed obsolete NSIS stuff. ------------------------------------------------------------------------ r1701 | ajapted | 2015-02-15 22:13:05 +1100 (Sun, 15 Feb 2015) | 3 lines Win32 : as we no longer use an installer, removed code which queries the registry for the installation folder. Use GetExecutablePath() instead. ------------------------------------------------------------------------ r1700 | ajapted | 2015-02-15 22:11:05 +1100 (Sun, 15 Feb 2015) | 2 lines code tweak. ------------------------------------------------------------------------ r1699 | ajapted | 2015-02-15 22:10:04 +1100 (Sun, 15 Feb 2015) | 2 lines hdr_fltk.h : added missing #include for Fl_Menu_Button. ------------------------------------------------------------------------ r1698 | ajapted | 2015-02-15 21:36:23 +1100 (Sun, 15 Feb 2015) | 2 lines code tweak. ------------------------------------------------------------------------ r1697 | ajapted | 2015-02-15 21:28:27 +1100 (Sun, 15 Feb 2015) | 2 lines Config : tweak to description of --file option. ------------------------------------------------------------------------ r1696 | ajapted | 2015-02-15 21:20:06 +1100 (Sun, 15 Feb 2015) | 3 lines misc : removed NSIS script "eureka.nsi" -- I plan on a simpler method of packaging binaries for the Windows platform. ------------------------------------------------------------------------ r1695 | ajapted | 2015-02-15 21:17:52 +1100 (Sun, 15 Feb 2015) | 6 lines misc : removed the 'Makefile.debian' and control files in misc/debian, partly so as not to confuse that stuff with the official Debian package, but also because I plan to explore a more distribution-neutral method for packaging Linux binaries. ------------------------------------------------------------------------ r1694 | ajapted | 2015-02-15 21:10:00 +1100 (Sun, 15 Feb 2015) | 2 lines eureka.rc : updated version for next release. ------------------------------------------------------------------------ r1693 | ajapted | 2015-02-15 21:09:21 +1100 (Sun, 15 Feb 2015) | 2 lines TODO.txt tidying ------------------------------------------------------------------------ r1692 | ajapted | 2015-02-15 19:28:57 +1100 (Sun, 15 Feb 2015) | 2 lines TODO update. ------------------------------------------------------------------------ r1691 | ajapted | 2015-02-15 19:28:36 +1100 (Sun, 15 Feb 2015) | 2 lines UI_EditKey dialog : fixed wrong function name in Encode() method. ------------------------------------------------------------------------ r1690 | ajapted | 2015-02-15 18:44:17 +1100 (Sun, 15 Feb 2015) | 2 lines UI_EditKey dialog : changing the context re-populates the Function choices. ------------------------------------------------------------------------ r1689 | ajapted | 2015-02-15 18:30:38 +1100 (Sun, 15 Feb 2015) | 3 lines UI_EditKey dialog : re-populate the 'Keywords' and 'Flags' menus when the function choice has been changed. ------------------------------------------------------------------------ r1688 | ajapted | 2015-02-15 18:16:30 +1100 (Sun, 15 Feb 2015) | 2 lines UI_EditKey dialog : implemented the 'Flags...' menu. ------------------------------------------------------------------------ r1687 | ajapted | 2015-02-15 18:06:54 +1100 (Sun, 15 Feb 2015) | 2 lines UI_EditKey dialog : implemented the 'Keywords...' menu. ------------------------------------------------------------------------ r1686 | ajapted | 2015-02-15 16:59:35 +1100 (Sun, 15 Feb 2015) | 2 lines Various tidying in changelogs/*.txt ------------------------------------------------------------------------ r1685 | ajapted | 2015-02-15 16:37:02 +1100 (Sun, 15 Feb 2015) | 2 lines TODO.txt updated ------------------------------------------------------------------------ r1684 | ajapted | 2015-02-15 16:36:42 +1100 (Sun, 15 Feb 2015) | 2 lines CHANGELOG update and version bump. ------------------------------------------------------------------------ r1683 | ajapted | 2015-02-15 16:28:45 +1100 (Sun, 15 Feb 2015) | 2 lines About box : yet another tweak. ------------------------------------------------------------------------ r1682 | ajapted | 2015-02-15 16:22:00 +1100 (Sun, 15 Feb 2015) | 2 lines CMD_NewMap : backup the current pwad before saving. ------------------------------------------------------------------------ r1681 | ajapted | 2015-02-15 16:15:31 +1100 (Sun, 15 Feb 2015) | 5 lines The 'New Map' command (in File menu) now saves the fresh map into the current pwad, asking for confirmation if it already exists. Hence removed 'Replacer' global and the overwrite test in CMD_SaveMap. ------------------------------------------------------------------------ r1680 | ajapted | 2015-02-15 15:41:12 +1100 (Sun, 15 Feb 2015) | 2 lines (part of last commit) -- removed 'new_file' stuff from UI_ChooseMap. ------------------------------------------------------------------------ r1679 | ajapted | 2015-02-15 15:22:32 +1100 (Sun, 15 Feb 2015) | 2 lines UI_ChooseMap : removed the 'new_file' stuff -- obsolete now. ------------------------------------------------------------------------ r1678 | ajapted | 2015-02-15 15:03:25 +1100 (Sun, 15 Feb 2015) | 2 lines Finished implementing the 'New Project' command (in File menu). ------------------------------------------------------------------------ r1677 | ajapted | 2015-02-15 14:44:24 +1100 (Sun, 15 Feb 2015) | 3 lines More work on 'File / New Project' command, implemented the file chooser and logic to determine the initial map name. ------------------------------------------------------------------------ r1676 | ajapted | 2015-02-15 14:02:28 +1100 (Sun, 15 Feb 2015) | 4 lines Partial work on a 'File / New Project' command, which feels like a better way of handling create new files from scratch (rather than a radio button in the New Map dialog). ------------------------------------------------------------------------ r1675 | ajapted | 2015-02-15 11:41:53 +1100 (Sun, 15 Feb 2015) | 4 lines For the File / Recent and File / Given-files menus, add a number to the beginning of each entry and make it the shortcut key (e.g. pressing '4' can be used to select the fourth entry while the menu is shown). ------------------------------------------------------------------------ r1674 | ajapted | 2015-02-14 22:57:35 +1100 (Sat, 14 Feb 2015) | 3 lines About box : overlay a small version number on top of the logo (in bottom right corner), and tweaked a few things. ------------------------------------------------------------------------ r1673 | ajapted | 2015-02-14 21:16:13 +1100 (Sat, 14 Feb 2015) | 3 lines Renamed prefix for vertex commands from 'VERT_' --> 'VT_', and renamed vertex reshaping commands to 'VT_ShapeArc' and 'VT_ShapeLine'. ------------------------------------------------------------------------ r1672 | ajapted | 2015-02-14 21:01:42 +1100 (Sat, 14 Feb 2015) | 3 lines Key bind dialog : fixed wrong context strings (seems to have gotten out of sync with the KCTX_xxx values). ------------------------------------------------------------------------ r1671 | ajapted | 2015-02-14 20:31:49 +1100 (Sat, 14 Feb 2015) | 2 lines README.txt : minor updates. ------------------------------------------------------------------------ r1670 | ajapted | 2015-02-14 19:11:37 +1100 (Sat, 14 Feb 2015) | 4 lines Fixed the key binding list so that pressing 'Bind', 'Copy' etc on a non-visible line will scroll to that line (make it visible). ------------------------------------------------------------------------ r1669 | ajapted | 2015-02-14 16:49:06 +1100 (Sat, 14 Feb 2015) | 2 lines Reworked SEC_SelectGroup command to use the new flag system. ------------------------------------------------------------------------ r1668 | ajapted | 2015-02-14 16:07:01 +1100 (Sat, 14 Feb 2015) | 2 lines Updated LIN_SelectPath command to use new flag system. ------------------------------------------------------------------------ r1667 | ajapted | 2015-02-14 15:43:31 +1100 (Sat, 14 Feb 2015) | 3 lines Fixed damn silly bug in ExecuteKey() not storing flag parameters, which begin with a slash '/', into the EXEC_Flags[] array. ------------------------------------------------------------------------ r1666 | ajapted | 2015-02-14 15:17:42 +1100 (Sat, 14 Feb 2015) | 3 lines For "Delete" command support two flags: /keep_unused and /keep_things (the latter only useful in sectors mode). ------------------------------------------------------------------------ r1665 | ajapted | 2015-02-14 14:50:13 +1100 (Sat, 14 Feb 2015) | 3 lines 1. updated CMD_Rotate90 to take a keyword ("cw" for clockwise, "acw" for anti-clockwise) 2. split VERT_Reshape into two commands : VERT_ReshapeLine and VERT_ReshapeArc ------------------------------------------------------------------------ r1664 | ajapted | 2015-02-13 22:11:54 +1100 (Fri, 13 Feb 2015) | 3 lines Added 'flag_list' and 'keyword_list' to every editor_command_t that needs them. [ Note that most commands do not support their flags yet.... ] ------------------------------------------------------------------------ r1663 | ajapted | 2015-02-13 19:59:42 +1100 (Fri, 13 Feb 2015) | 4 lines Reworked LineDef_Align() function to take 'flags' as a integer bitmask instead of a string. Updated the 3D_Align implementation for this, and to use the new Exec_HasFlag() mechanism to check for "/clear" and "/right". ------------------------------------------------------------------------ r1662 | ajapted | 2015-02-13 19:39:23 +1100 (Fri, 13 Feb 2015) | 4 lines Added EXEC_Flags[] global which is similar to EXEC_Param[] but stores "flags" (paremeters beginning with '/'). Implemented adding such flags into that array (from a key binding), and added Exec_HasFlag() utility function. ------------------------------------------------------------------------ r1661 | ajapted | 2015-02-13 16:50:31 +1100 (Fri, 13 Feb 2015) | 2 lines TODO update. ------------------------------------------------------------------------ r1660 | ajapted | 2015-02-13 16:42:23 +1100 (Fri, 13 Feb 2015) | 5 lines Added 'flag_list' and 'keyword_list' fields to editor_command_t. Use these in the UI_EditKey dialog to populate a 'Keywords' and/or 'Flags' menus. These menus don't actually do anything yet.... ------------------------------------------------------------------------ r1659 | ajapted | 2015-02-13 13:51:28 +1100 (Fri, 13 Feb 2015) | 4 lines Began work on some improvements to key binding system. This commit works on the UI_EditKey dialog, the 'Function' widget is now a choice menu that contains all the possible functions for the current context. ------------------------------------------------------------------------ r1658 | ajapted | 2015-02-10 15:35:17 +1100 (Tue, 10 Feb 2015) | 4 lines Fixed crash when trying to build nodes (via File menu) on an IWAD map which has had some changes made to it, but has not been saved yet (and hence 'edit_wad' was NULL). ------------------------------------------------------------------------ r1657 | ajapted | 2015-02-10 15:15:44 +1100 (Tue, 10 Feb 2015) | 2 lines TODO update. ------------------------------------------------------------------------ r1656 | ajapted | 2015-02-10 15:14:59 +1100 (Tue, 10 Feb 2015) | 3 lines Key bindings : changed vertex reshapers 'C' to be 120 degrees and 'Q' to 240 degrees -- I think these will be more useful than 90/270 in practice. ------------------------------------------------------------------------ r1655 | ajapted | 2015-02-10 15:13:17 +1100 (Tue, 10 Feb 2015) | 2 lines Version bump, in honor of Find/Replace feature fully implemented. ------------------------------------------------------------------------ r1654 | ajapted | 2015-02-10 15:07:37 +1100 (Tue, 10 Feb 2015) | 3 lines Find/Replace : added 'skies' checkbox to the Sector filters. This can be used to prevent matches from affecting sky ceilings. ------------------------------------------------------------------------ r1653 | ajapted | 2015-02-10 14:52:20 +1100 (Tue, 10 Feb 2015) | 3 lines Find/Replace : prevent matching the empty rail texture ('-') against a "*" wildcard pattern -- especially pertinent when doing a Replace All operation. ------------------------------------------------------------------------ r1652 | ajapted | 2015-02-10 13:22:11 +1100 (Tue, 10 Feb 2015) | 2 lines Find/Replace : fixed the filter toggle button being out-of-sync. ------------------------------------------------------------------------ r1651 | ajapted | 2015-02-10 13:15:58 +1100 (Tue, 10 Feb 2015) | 3 lines Find/Replace : only clear everything when the type changes (i.e. keep the existing match text, filters, etc... while edit mode stays the same). ------------------------------------------------------------------------ r1650 | ajapted | 2015-02-10 13:00:58 +1100 (Tue, 10 Feb 2015) | 2 lines Find/Replace : code to reset the filters section. ------------------------------------------------------------------------ r1649 | ajapted | 2015-02-09 22:22:33 +1100 (Mon, 09 Feb 2015) | 2 lines Find/Replace : implemented replacement for LineDef textures. ------------------------------------------------------------------------ r1648 | ajapted | 2015-02-09 22:11:55 +1100 (Mon, 09 Feb 2015) | 8 lines Find/Replace : decided to remove handling of negative matches ('!' prefix) for textures and flats -- primarily because the semantics of find is quite different for semantics of replace (with find, user wants to see all sectors where BOTH flats match the negative pattern, but with replace user wants to visit sectors where EITHER flat match the negative pattern). Hence opting for K.I.S.S. ------------------------------------------------------------------------ r1647 | ajapted | 2015-02-09 21:48:58 +1100 (Mon, 09 Feb 2015) | 4 lines Invert selection command : do not clear the selection when 'error_mode' is active -- firstly because it all we get is the same as Select All command, and using CTRL-I (twice) to keep the error selection can be useful. ------------------------------------------------------------------------ r1646 | ajapted | 2015-02-09 21:32:37 +1100 (Mon, 09 Feb 2015) | 2 lines Find/Replace : implemented replacement for sector flats. ------------------------------------------------------------------------ r1645 | ajapted | 2015-02-09 21:30:23 +1100 (Mon, 09 Feb 2015) | 3 lines UI : made TexFromWidget() and FlatFromWidget() be static functions since they do not use or require any fields or methods of their class. ------------------------------------------------------------------------ r1644 | ajapted | 2015-02-09 20:54:06 +1100 (Mon, 09 Feb 2015) | 4 lines Find/Replace : Allow user to dismiss the Find/Replace panel without losing the current selection (it was being cleared because it now uses the error mode). ------------------------------------------------------------------------ r1643 | ajapted | 2015-02-09 20:18:48 +1100 (Mon, 09 Feb 2015) | 3 lines Find/Replace : implemented Match_LineDef(), logic for matching textures on the sidedefs. ------------------------------------------------------------------------ r1642 | ajapted | 2015-02-09 19:35:46 +1100 (Mon, 09 Feb 2015) | 4 lines Find/Replace : allow '/' and '|' as separators for textures (consistent with numeric searches), and when adding a texture from the browser add a comma separator if current match ends with '*'. ------------------------------------------------------------------------ r1641 | ajapted | 2015-02-09 19:19:22 +1100 (Mon, 09 Feb 2015) | 6 lines Find/Replace : implemented Pattern_Match() method for matching texture names, supporting a list of names (simple patterns) separated by commas. Use this to implement Match_Sector() logic, and support initial '!' character in the pattern to negate the results. ------------------------------------------------------------------------ r1640 | ajapted | 2015-02-09 18:25:34 +1100 (Mon, 09 Feb 2015) | 6 lines Factored out code to match texture names (etc) --> Texture_MatchPattern(), now in the objects.cc/h file. Also fixed bug in browser where patterns like '4$' would not match some flats or textures, like 'CEIL3_4', due to spaces (padding) on the end. ------------------------------------------------------------------------ r1639 | ajapted | 2015-02-09 17:09:22 +1100 (Mon, 09 Feb 2015) | 2 lines TODO update. ------------------------------------------------------------------------ r1638 | ajapted | 2015-02-09 17:02:57 +1100 (Mon, 09 Feb 2015) | 4 lines Vertex Reshaping : finished logic for arbitrary arc angles, updating the key bindings for O/C/D/Q to specify the angle directly. Document new 'Q' binding (270 degrees) in the README. ------------------------------------------------------------------------ r1637 | ajapted | 2015-02-09 16:43:05 +1100 (Mon, 09 Feb 2015) | 3 lines Vertex Reshaping : worked to support arbitrary arc sizes (angles), and to keep the start and end vertices of the arc in the same location.... ------------------------------------------------------------------------ r1636 | ajapted | 2015-02-09 15:55:17 +1100 (Mon, 09 Feb 2015) | 2 lines sys_macro.h : #define M_SQRT2 if not already defined. ------------------------------------------------------------------------ r1635 | ajapted | 2015-02-09 15:19:40 +1100 (Mon, 09 Feb 2015) | 2 lines Fixed not reloading textures (etc) when opening a new wad file. ------------------------------------------------------------------------ r1634 | ajapted | 2015-02-09 14:37:11 +1100 (Mon, 09 Feb 2015) | 2 lines TODO.txt : update and tidy up. ------------------------------------------------------------------------ r1633 | ajapted | 2015-02-09 14:33:55 +1100 (Mon, 09 Feb 2015) | 5 lines When loading a wad specified on the command line, and it contains settings for the iwad, port and/or resources in an EUREKA_LUMP, then allow command line arguments to override those values (and _add_ new resources). ------------------------------------------------------------------------ r1632 | ajapted | 2015-02-09 13:01:55 +1100 (Mon, 09 Feb 2015) | 4 lines Makefile.xming : link with -static-libgcc and -static-libstdc++ so that the Windows executable actually works on Windows (and not complain about a missing DLL). ------------------------------------------------------------------------ r1631 | ajapted | 2015-01-24 16:29:41 +1100 (Sat, 24 Jan 2015) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1630 | ajapted | 2015-01-24 16:28:30 +1100 (Sat, 24 Jan 2015) | 3 lines Config : added 'show_full_one_sided' config variable, enables showing the rail / upper textures for one-sided lines in the LineDef panel. ------------------------------------------------------------------------ r1629 | ajapted | 2015-01-24 15:45:39 +1100 (Sat, 24 Jan 2015) | 3 lines Linedef panel : for one-sided lines, don't show upper and rail texture (since editing them generally does nothing). ------------------------------------------------------------------------ r1628 | ajapted | 2015-01-24 15:15:15 +1100 (Sat, 24 Jan 2015) | 3 lines Canvas : tweak to error mode, when active don't highlight the tagged sector(s) of the currently highlighted linedef. ------------------------------------------------------------------------ r1627 | ajapted | 2015-01-24 15:11:43 +1100 (Sat, 24 Jan 2015) | 3 lines Canvas : in the error mode, draw most linedefs as LIGHTGREY so the selected objects stand out more. ------------------------------------------------------------------------ r1626 | ajapted | 2015-01-24 14:57:17 +1100 (Sat, 24 Jan 2015) | 2 lines Linedef checker : implemented detection of unknown line types. ------------------------------------------------------------------------ r1625 | ajapted | 2015-01-24 14:18:05 +1100 (Sat, 24 Jan 2015) | 3 lines Sector checker : detect unknown sector types. They are shown in red since in vanilla DOOM they will cause a fatal error. ------------------------------------------------------------------------ r1624 | printz | 2015-01-19 18:43:48 +1100 (Mon, 19 Jan 2015) | 1 line osx: updated Xcode project ------------------------------------------------------------------------ r1623 | ajapted | 2015-01-18 22:40:46 +1100 (Sun, 18 Jan 2015) | 6 lines Game definitions : 1. fixed category of linetype #68 (should be a raising floor) 2. changed category letter of raising floors to 'g', so they appear near the lowering floors in the Browser. ------------------------------------------------------------------------ r1622 | ajapted | 2015-01-17 22:10:09 +1100 (Sat, 17 Jan 2015) | 3 lines Find/Replace : make 'Select All' button use the error mode, i.e. show all matches in bright red and everything else in a rather dim gray. ------------------------------------------------------------------------ r1621 | ajapted | 2015-01-17 21:30:21 +1100 (Sat, 17 Jan 2015) | 2 lines tweak the --help text ------------------------------------------------------------------------ r1620 | ajapted | 2015-01-17 21:29:41 +1100 (Sat, 17 Jan 2015) | 2 lines Man page : bit more fleshing out + lots of polishing. ------------------------------------------------------------------------ r1619 | ajapted | 2015-01-17 17:30:54 +1100 (Sat, 17 Jan 2015) | 2 lines Man page : fixed long options to have two dashes, plus some tweaks. ------------------------------------------------------------------------ r1618 | ajapted | 2015-01-17 17:26:21 +1100 (Sat, 17 Jan 2015) | 2 lines Man page : finished describing the remaining options. ------------------------------------------------------------------------ r1617 | ajapted | 2015-01-17 16:14:03 +1100 (Sat, 17 Jan 2015) | 3 lines Browser : tidied up some code with 'sort_method_e' typedef (instead of using 0/1/2 with special meanings). ------------------------------------------------------------------------ r1616 | ajapted | 2015-01-17 15:56:21 +1100 (Sat, 17 Jan 2015) | 4 lines Menus : the 'Default Properties' command did not belong in FILE menu, so moved it into the VIEW menu (the EDIT menu might make more sense, but is rather full right now). ------------------------------------------------------------------------ r1615 | ajapted | 2015-01-16 22:19:49 +1100 (Fri, 16 Jan 2015) | 4 lines DOOM defs : moved 'SKY1/2/3' textures from NATURAL --> OTHER category, since they looked out of place there (they have little utility when used on walls, so "Other" category seems the most appropiate). ------------------------------------------------------------------------ r1614 | ajapted | 2015-01-16 22:16:27 +1100 (Fri, 16 Jan 2015) | 4 lines Game defs : moved the MBF dog thing --> Boom definition (ports/boom.ugh), which at least prevents it appearing in "vanilla" mode. Also changed its category from Player --> Other. ------------------------------------------------------------------------ r1613 | ajapted | 2015-01-16 22:13:53 +1100 (Fri, 16 Jan 2015) | 2 lines Renamed 'Manage Wads' command --> 'Manage Project' ------------------------------------------------------------------------ r1612 | ajapted | 2015-01-16 21:35:14 +1100 (Fri, 16 Jan 2015) | 3 lines Recolor the co-op player starts to match DOOM, i.e. type 2 start is gray, type 3 start is brown, type 4 start is red. ------------------------------------------------------------------------ r1611 | ajapted | 2015-01-16 20:50:00 +1100 (Fri, 16 Jan 2015) | 2 lines Code : minor rename, Img class --> Img_c ------------------------------------------------------------------------ r1610 | ajapted | 2015-01-16 20:40:03 +1100 (Fri, 16 Jan 2015) | 4 lines Img class : removed the Img_priv class, just have the fields in the private area of 'Img' class (renamed since they clashed with access methods). Also reformatted code to use tabs, plus various tidying. ------------------------------------------------------------------------ r1609 | ajapted | 2015-01-16 20:14:12 +1100 (Fri, 16 Jan 2015) | 3 lines Img class : implemented color_remap() method, like spectrify() but remaps a source color range into a target color range. ------------------------------------------------------------------------ r1608 | ajapted | 2015-01-16 19:59:08 +1100 (Fri, 16 Jan 2015) | 6 lines Browser : the BR_CycleCategory command now skips the 'RECENT' category. Rationale is that another key toggles between RECENT category and the ALL category, so when the user uses this function they are probably not after the special RECENT category. ------------------------------------------------------------------------ r1607 | ajapted | 2015-01-16 17:17:54 +1100 (Fri, 16 Jan 2015) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1606 | ajapted | 2015-01-16 15:47:39 +1100 (Fri, 16 Jan 2015) | 2 lines Man page : describe '$PREFIX/share/eureka' in FILES section. ------------------------------------------------------------------------ r1605 | ajapted | 2015-01-16 15:27:59 +1100 (Fri, 16 Jan 2015) | 2 lines Man page : added "FILES", "ENVIRONMENT" and "SEE ALSO" sections ------------------------------------------------------------------------ r1604 | ajapted | 2015-01-16 15:15:54 +1100 (Fri, 16 Jan 2015) | 2 lines Removed "ups" from the directories created in the $home_dir. ------------------------------------------------------------------------ r1603 | ajapted | 2015-01-16 14:22:20 +1100 (Fri, 16 Jan 2015) | 2 lines Man page : documented the main options, --file, --warp, --iwad, etc.... ------------------------------------------------------------------------ r1602 | ajapted | 2015-01-16 12:48:03 +1100 (Fri, 16 Jan 2015) | 3 lines Manual page : created a DESCRIPTION section, listing some of Eureka's features, and reworked other parts at top of file (SYNOPSIS, etc). ------------------------------------------------------------------------ r1601 | ajapted | 2015-01-16 12:45:54 +1100 (Fri, 16 Jan 2015) | 2 lines Added 'misc/eureka.6' -- a skeletal manual page, courtesy Fabian Greffrath. ------------------------------------------------------------------------ r1600 | ajapted | 2015-01-16 12:26:12 +1100 (Fri, 16 Jan 2015) | 3 lines For --help text, change order of command-line options to show the most important ones first (like --file and --iwad). ------------------------------------------------------------------------ r1599 | ajapted | 2015-01-16 11:38:10 +1100 (Fri, 16 Jan 2015) | 3 lines For the --help text, show long options with two dashes ('--') since I will use double dashes in the manpage. ------------------------------------------------------------------------ r1598 | ajapted | 2015-01-16 11:26:56 +1100 (Fri, 16 Jan 2015) | 2 lines Updated AUTHORS.txt ------------------------------------------------------------------------ r1597 | ajapted | 2015-01-16 10:59:37 +1100 (Fri, 16 Jan 2015) | 2 lines Code : fixed previous commit (SYS_ASSERT in the wrong place) ------------------------------------------------------------------------ r1596 | ajapted | 2015-01-16 10:50:33 +1100 (Fri, 16 Jan 2015) | 4 lines Code : added some SYS_ASSERT() checks to erase() method of RecentFiles_c. Perhaps this will silence the bogus warnings about out-of-bounds access which older GNU compilers generate. ------------------------------------------------------------------------ r1595 | ajapted | 2015-01-16 10:43:54 +1100 (Fri, 16 Jan 2015) | 2 lines Code : added __attribute((noreturn)) to the FatalError() prototype. ------------------------------------------------------------------------ r1594 | ajapted | 2015-01-16 00:03:40 +1100 (Fri, 16 Jan 2015) | 4 lines Browser : reduced size of sprites in Thing browser --> 64x72 (from 80x80) which works better horizontally (three columns at minimum size) and can generally see more things, albeit a few more things are cut off now. ------------------------------------------------------------------------ r1593 | ajapted | 2015-01-15 23:57:33 +1100 (Thu, 15 Jan 2015) | 2 lines Browser : tweaked name of "Other" category. ------------------------------------------------------------------------ r1592 | ajapted | 2015-01-15 23:56:49 +1100 (Thu, 15 Jan 2015) | 4 lines Browser : replaced the "Sort" choice widget with a "Alpha" checkbox, and moved the "Match" widget up. This makes the Things (etc) browsers more consistent looking with Flats and Textures, and a bit easier to use. ------------------------------------------------------------------------ r1591 | ajapted | 2015-01-15 23:44:44 +1100 (Thu, 15 Jan 2015) | 2 lines Browser : made the minimum width a bit narrower (10 units). ------------------------------------------------------------------------ r1590 | ajapted | 2015-01-15 23:28:43 +1100 (Thu, 15 Jan 2015) | 4 lines In main window's title, disabled the program name "Eureka" tacked on the end -- just seems like visual noise, especially with a [Read-Only] in the title. ------------------------------------------------------------------------ r1589 | ajapted | 2015-01-15 23:06:42 +1100 (Thu, 15 Jan 2015) | 2 lines Bindings : added '|' (SHIFT + '\') as the BR_CycleCategory function. ------------------------------------------------------------------------ r1588 | ajapted | 2015-01-15 22:50:15 +1100 (Thu, 15 Jan 2015) | 2 lines Game defs : tweaked name of "Health & Ammo" category. ------------------------------------------------------------------------ r1587 | ajapted | 2015-01-15 22:23:38 +1100 (Thu, 15 Jan 2015) | 4 lines Bindings : make 'T' (shift + t) open the browser to things, and 'X' (shift + x) open the browser to textures -- for consistency with the shortcuts in the BROWSER menu. ------------------------------------------------------------------------ r1586 | ajapted | 2015-01-15 22:12:10 +1100 (Thu, 15 Jan 2015) | 3 lines Menus : in Browser menu, moved 'Things' to first position, matching the order in the MODE choice on info-bar and the Find/Replace dialog. ------------------------------------------------------------------------ r1585 | ajapted | 2015-01-15 21:54:33 +1100 (Thu, 15 Jan 2015) | 2 lines Browser : tweaked title names and positioning. ------------------------------------------------------------------------ r1584 | ajapted | 2015-01-15 21:30:55 +1100 (Thu, 15 Jan 2015) | 2 lines Version bump. ------------------------------------------------------------------------ r1583 | ajapted | 2015-01-15 21:18:32 +1100 (Thu, 15 Jan 2015) | 3 lines 3D View : changed the low_detail/high_detail flag into a preference setting (instead of being toggleable with the F5 key). ------------------------------------------------------------------------ r1582 | ajapted | 2015-01-15 20:42:32 +1100 (Thu, 15 Jan 2015) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1581 | ajapted | 2015-01-15 20:41:12 +1100 (Thu, 15 Jan 2015) | 4 lines 3D View : tweaked the info bar, move gamma to just after gravity, and made the Tex/Lit/Obj indicators be highlighted when NOT in effect (so under normal circumstances they remain dim). ------------------------------------------------------------------------ r1580 | ajapted | 2015-01-15 20:34:56 +1100 (Thu, 15 Jan 2015) | 2 lines 3D View : finished the info-bar implementation. ------------------------------------------------------------------------ r1579 | ajapted | 2015-01-15 19:54:14 +1100 (Thu, 15 Jan 2015) | 3 lines 3D View : began work on an Information bar at top of render, showing the camera position, angle and various state. ------------------------------------------------------------------------ r1578 | ajapted | 2015-01-15 19:15:15 +1100 (Thu, 15 Jan 2015) | 3 lines Canvas : when drawing the "split line", show how and where the line will be split, with two new lines in orange and a small disc at new vertex. ------------------------------------------------------------------------ r1577 | ajapted | 2015-01-15 18:29:03 +1100 (Thu, 15 Jan 2015) | 4 lines Canvas : experimented with drawing a solid circle where the closest snap position to the mouse is (when SNAP is enabled), with a line going to the current mouse position.... Seems too weird to be useful. ------------------------------------------------------------------------ r1576 | ajapted | 2015-01-15 17:55:03 +1100 (Thu, 15 Jan 2015) | 5 lines Command system : registering commands is now done by passing a list of structures (instead of calling a function for each command). This will allow extra fields in the future, e.g. description of the command and what parameters it takes. ------------------------------------------------------------------------ r1575 | ajapted | 2015-01-15 16:52:49 +1100 (Thu, 15 Jan 2015) | 2 lines The 'CopyAndPaste' command broke recently -- fixed it. ------------------------------------------------------------------------ r1574 | ajapted | 2015-01-15 12:22:50 +1100 (Thu, 15 Jan 2015) | 2 lines Simplified some code using the bit-vector class. ------------------------------------------------------------------------ r1573 | ajapted | 2015-01-15 12:22:03 +1100 (Thu, 15 Jan 2015) | 2 lines Selection class : no need to check/grow the bit-vector, as it grows itself now. ------------------------------------------------------------------------ r1572 | ajapted | 2015-01-15 12:14:52 +1100 (Thu, 15 Jan 2015) | 2 lines Bitvec class : improved way vector is grown in set() method. ------------------------------------------------------------------------ r1571 | ajapted | 2015-01-15 11:58:20 +1100 (Thu, 15 Jan 2015) | 7 lines Bitvec class : added raw_get(), raw_set(), etc... as inline methods which do no range checking, and the normal get(), set(), etc... methods now check the position and will automatically resize the vector when needed. Also made resize() allow shrinking the vector when reduced by a large amount. ------------------------------------------------------------------------ r1570 | ajapted | 2015-01-15 11:33:58 +1100 (Thu, 15 Jan 2015) | 2 lines Bitvec class : removed unused 'merge()' method. ------------------------------------------------------------------------ r1569 | ajapted | 2015-01-14 23:25:36 +1100 (Wed, 14 Jan 2015) | 7 lines Menus : 1. added shortcuts to numerous menu items that lacked them (especially the Browser menu) 2. moved 'Prune unused' to below Delete, and removed its shortcut since the 'P' shortcut is already used by Paste. ------------------------------------------------------------------------ r1568 | ajapted | 2015-01-14 22:39:16 +1100 (Wed, 14 Jan 2015) | 3 lines Find/Replace : implemented linedef filtering based on sidedness, and fixed some issues with the tag filtering logic. ------------------------------------------------------------------------ r1567 | ajapted | 2015-01-14 22:18:41 +1100 (Wed, 14 Jan 2015) | 4 lines Find/Replace : 1. got the skill and mode filters for Things working 2. got the tag-number filter for Line/Sector searches working ------------------------------------------------------------------------ r1566 | ajapted | 2015-01-14 21:30:02 +1100 (Wed, 14 Jan 2015) | 4 lines Find/Replace : got the UI_TripleCheckButton working quite well, for both the skill flags and the mode flags, and implemented logic to compute the mask and compare value from those widgets. ------------------------------------------------------------------------ r1565 | ajapted | 2015-01-14 20:37:40 +1100 (Wed, 14 Jan 2015) | 3 lines Find/Replace : created a UI_TripleCheckButton() which is used to represent the search state for a boolean flag (YES, NO, DontCare). ------------------------------------------------------------------------ r1564 | ajapted | 2015-01-14 19:21:04 +1100 (Wed, 14 Jan 2015) | 2 lines CHANGELOG : yet another reorganisation... ------------------------------------------------------------------------ r1563 | ajapted | 2015-01-14 19:17:05 +1100 (Wed, 14 Jan 2015) | 3 lines Find/Replace : added code to show/hide the filter widgets based on the current mode (Things, LineDefs, etc). Also improved widget positions. ------------------------------------------------------------------------ r1562 | ajapted | 2015-01-14 18:50:42 +1100 (Wed, 14 Jan 2015) | 3 lines Find/Replace : began work on Filters -- this commit merely creates all the widgets we will need. ------------------------------------------------------------------------ r1561 | ajapted | 2015-01-14 16:53:11 +1100 (Wed, 14 Jan 2015) | 2 lines Find/Replace : finished 'Choose' button and browser interaction logic. ------------------------------------------------------------------------ r1560 | ajapted | 2015-01-14 15:29:34 +1100 (Wed, 14 Jan 2015) | 2 lines Find/Replace : worked on 'Choose' button and interaction with the Browser... ------------------------------------------------------------------------ r1559 | ajapted | 2015-01-14 15:01:19 +1100 (Wed, 14 Jan 2015) | 2 lines Find/Replace : when '*' is used, show "(everything)" as the description. ------------------------------------------------------------------------ r1558 | ajapted | 2015-01-14 14:51:58 +1100 (Wed, 14 Jan 2015) | 3 lines Find/Replace : when 'Replace All', select all the objects which were modified and goto this selection at the end -- lets the user see what was affected. ------------------------------------------------------------------------ r1557 | ajapted | 2015-01-14 14:47:43 +1100 (Wed, 14 Jan 2015) | 2 lines Find/Replace : support for finding and replacing Line-Types and Sector-Types. ------------------------------------------------------------------------ r1556 | ajapted | 2015-01-14 14:46:43 +1100 (Wed, 14 Jan 2015) | 2 lines Objid : the clear() method now only changes the 'num', leaves 'type' alone. ------------------------------------------------------------------------ r1555 | ajapted | 2015-01-13 21:59:34 +1100 (Tue, 13 Jan 2015) | 2 lines README.txt : document the '\' key (toggle RECENT category). ------------------------------------------------------------------------ r1554 | ajapted | 2015-01-13 21:51:24 +1100 (Tue, 13 Jan 2015) | 5 lines Find/Replace : 1. renamed 'Apply' button --> 'Replace' 2. only activate 'Replace' button when something has been found 3. implemented Replace_Thing() method ------------------------------------------------------------------------ r1553 | ajapted | 2015-01-13 21:30:53 +1100 (Tue, 13 Jan 2015) | 3 lines Texture checker : assume textures beginning with '#' are special, do not treat them as unknown textures. ------------------------------------------------------------------------ r1552 | ajapted | 2015-01-13 21:15:14 +1100 (Tue, 13 Jan 2015) | 3 lines Vertex Reshaping : added bindings for them, and document them in the README and CHANGELOG. ------------------------------------------------------------------------ r1551 | ajapted | 2015-01-13 21:13:20 +1100 (Tue, 13 Jan 2015) | 3 lines Vertex Reshaping : register its command, and properly check the parameter to call the correct function (e.g. "line" vs "circle" vs "arc180"). ------------------------------------------------------------------------ r1550 | ajapted | 2015-01-13 20:48:05 +1100 (Tue, 13 Jan 2015) | 3 lines Vertices : support for shaping vertices into a half-circle (180 degrees) or a quarter circle (90 degrees). ------------------------------------------------------------------------ r1549 | ajapted | 2015-01-13 18:54:52 +1100 (Tue, 13 Jan 2015) | 3 lines Vertices : implemented the EvalCircle() function -- the circle reshaping code is working now. ------------------------------------------------------------------------ r1548 | ajapted | 2015-01-13 18:27:27 +1100 (Tue, 13 Jan 2015) | 2 lines Vertices : partial work on command to reshape vertices into a pure circle. ------------------------------------------------------------------------ r1547 | ajapted | 2015-01-13 17:44:12 +1100 (Tue, 13 Jan 2015) | 2 lines Vertices : got the Reshape_Line() code working. ------------------------------------------------------------------------ r1546 | ajapted | 2015-01-13 17:07:24 +1100 (Tue, 13 Jan 2015) | 3 lines Vertices : further work on straight line reshaper, collect all vertices and sort them along the line, and then determine the end-points we need. ------------------------------------------------------------------------ r1545 | ajapted | 2015-01-13 16:30:52 +1100 (Tue, 13 Jan 2015) | 3 lines Vertices : worked on code to move all selected vertices onto a straight line (some experimental stuff...) ------------------------------------------------------------------------ r1544 | ajapted | 2015-01-13 16:29:12 +1100 (Tue, 13 Jan 2015) | 2 lines Basis : ensure BA_Begin() has been called for BA_New() and BA_Delete() functions. ------------------------------------------------------------------------ r1543 | ajapted | 2015-01-13 15:19:59 +1100 (Tue, 13 Jan 2015) | 3 lines Key bindings : increased maximum parameters of a binding from 4 --> 16, and increased the maximum length of a parameter from 16 --> 32. ------------------------------------------------------------------------ r1542 | ajapted | 2015-01-13 14:56:52 +1100 (Tue, 13 Jan 2015) | 2 lines Code : moved prototypes for Status_xxx() and Beep() functions --> main.h ------------------------------------------------------------------------ r1541 | ajapted | 2015-01-13 12:22:42 +1100 (Tue, 13 Jan 2015) | 4 lines Find/Replace : implemented rep_value_callback(), ensuring the 'Apply' and 'Replace All' buttons are only active when both the rep_value is valid and the find_match is valid. ------------------------------------------------------------------------ r1540 | ajapted | 2015-01-13 11:58:40 +1100 (Tue, 13 Jan 2015) | 2 lines Find/Replace : support '*' wildcard in number_group_c ------------------------------------------------------------------------ r1539 | ajapted | 2015-01-12 23:17:13 +1100 (Mon, 12 Jan 2015) | 2 lines Code tweak : consistent capitalization for top-of-file descriptions. ------------------------------------------------------------------------ r1538 | ajapted | 2015-01-12 23:04:23 +1100 (Mon, 12 Jan 2015) | 3 lines Code : removed commented-out code for CMD_FindObjectByType() -- the new Find/Replace panel implements equivalent functionality. ------------------------------------------------------------------------ r1537 | ajapted | 2015-01-12 23:01:48 +1100 (Mon, 12 Jan 2015) | 9 lines Objid rework: 1. moved obj_type_e definition --> objid.h 2. removed 'OBJ_NONE' as a member of obj_type_e enumeration 3. renamed 'OBJ_NO_NONE' constant --> 'NIL_OBJ' 4. in Objid class, replaced '()' operator with 'valid()' method 5. removed the barely used is_obj() macro 6. renamed 'edit.highlighted' --> 'edit.highlight' ------------------------------------------------------------------------ r1536 | ajapted | 2015-01-12 21:00:51 +1100 (Mon, 12 Jan 2015) | 2 lines Find/Replace : tweaked size of 'what' choice widget. ------------------------------------------------------------------------ r1535 | ajapted | 2015-01-12 20:58:23 +1100 (Mon, 12 Jan 2015) | 7 lines Find/Replace : 1. remove the toggle button for the Replace section, was rather unnecessary, and now there is more room for the Filters section. 2. made the 'what' choice (Things, Line Textures, etc) be colored, using colors that match the mode colors in infobar widget. ------------------------------------------------------------------------ r1534 | ajapted | 2015-01-12 19:50:23 +1100 (Mon, 12 Jan 2015) | 4 lines Find/Replace : better handling of 'Select All' button, e.g. beep with "nothing found" message if nothing was found, and if some stuff _was_ found then use GoToSelection() to move/zoom in to it. ------------------------------------------------------------------------ r1533 | ajapted | 2015-01-12 19:38:54 +1100 (Mon, 12 Jan 2015) | 4 lines Find/Replace : 1. Got the 'number_group_c' class working, can find things with it now. 2. Make sure selection is cleared after nothing is found ------------------------------------------------------------------------ r1532 | ajapted | 2015-01-12 18:55:59 +1100 (Mon, 12 Jan 2015) | 3 lines Find/Replace : created a 'number_group_c' class for storing a small group of numbers or number ranges. Also implemented its ParseString() method. ------------------------------------------------------------------------ r1531 | ajapted | 2015-01-12 18:19:44 +1100 (Mon, 12 Jan 2015) | 4 lines Removed the 'selectn.cc/h' code files -- merged the code into levels.cc/h Also moved some code from objects.cc/h --> levels.cc/h (notification stuff) ------------------------------------------------------------------------ r1530 | ajapted | 2015-01-12 18:09:13 +1100 (Mon, 12 Jan 2015) | 2 lines Find/Replace : bit more work, got basic Thing matching working. ------------------------------------------------------------------------ r1529 | ajapted | 2015-01-12 16:53:31 +1100 (Mon, 12 Jan 2015) | 2 lines Find/Replace : properly set the description for a thing type (etc). ------------------------------------------------------------------------ r1528 | ajapted | 2015-01-12 16:46:27 +1100 (Mon, 12 Jan 2015) | 3 lines Find/Replace : implemented find_match callback, e.g. validate that the string is numeric (for Things or for line/sector types). ------------------------------------------------------------------------ r1527 | ajapted | 2015-01-12 15:57:04 +1100 (Mon, 12 Jan 2015) | 2 lines Added Editor_ChangeMode_Raw() function. ------------------------------------------------------------------------ r1526 | ajapted | 2015-01-12 15:18:32 +1100 (Mon, 12 Jan 2015) | 4 lines Find/Replace : worked on outer logic for finding the first/next object, and for selecting everything or doing a replace on all matches. The inner logic (MatchObject or ApplyReplace methods) are not started yet.... ------------------------------------------------------------------------ r1525 | ajapted | 2015-01-12 15:10:04 +1100 (Mon, 12 Jan 2015) | 2 lines minor rename ------------------------------------------------------------------------ r1524 | ajapted | 2015-01-12 14:57:11 +1100 (Mon, 12 Jan 2015) | 2 lines Coding : removed unused macros (IsSelected, SelectObject, etc) from selectn.h ------------------------------------------------------------------------ r1523 | ajapted | 2015-01-12 14:24:54 +1100 (Mon, 12 Jan 2015) | 3 lines Find/Replace : bit more work, added Clear() method, added several more callback functions (skeletal atm), call BrowsedItem() from UI_MainWin. ------------------------------------------------------------------------ r1522 | ajapted | 2015-01-12 12:13:05 +1100 (Mon, 12 Jan 2015) | 4 lines Preferences : enabled the 'Maximize on start-up' option, except for MacOS X platform. This is instead of restoring the last window position and maximized state, which is non-trivial (especially on Linux), but better than nothing. ------------------------------------------------------------------------ r1521 | ajapted | 2015-01-12 11:56:19 +1100 (Mon, 12 Jan 2015) | 2 lines Added 'Toggle 3D View' command to the VIEW menu. ------------------------------------------------------------------------ r1520 | ajapted | 2015-01-12 11:45:49 +1100 (Mon, 12 Jan 2015) | 2 lines Default probs : layout tweak. ------------------------------------------------------------------------ r1519 | ajapted | 2015-01-12 11:42:16 +1100 (Mon, 12 Jan 2015) | 3 lines Default props : added labels above the textures, and spaced the three groups out some more. ------------------------------------------------------------------------ r1518 | ajapted | 2015-01-12 11:13:05 +1100 (Mon, 12 Jan 2015) | 3 lines Preferences : when the 'browser_small_tex' value is changed, re-populate the browser (to show the resized textures). ------------------------------------------------------------------------ r1517 | ajapted | 2015-01-11 23:16:17 +1100 (Sun, 11 Jan 2015) | 2 lines TODO.txt updated (lots of WIP stuff...) ------------------------------------------------------------------------ r1516 | ajapted | 2015-01-11 22:56:55 +1100 (Sun, 11 Jan 2015) | 3 lines Implemented new 'browser_small_tex' option to show smaller textures in the texture browser. Includes addition to the Preferences dialog. ------------------------------------------------------------------------ r1515 | ajapted | 2015-01-11 21:35:26 +1100 (Sun, 11 Jan 2015) | 2 lines Find/Replace : implemented the toggle buttons showing/hiding their group. ------------------------------------------------------------------------ r1514 | ajapted | 2015-01-11 21:02:47 +1100 (Sun, 11 Jan 2015) | 3 lines Find/Replace : fixed dismissing the panel by pressing the key for the current mode, e.g. 'v' for vertices. ------------------------------------------------------------------------ r1513 | ajapted | 2015-01-11 20:51:35 +1100 (Sun, 11 Jan 2015) | 4 lines Find/Replace : worked on layout some more, grouping the three sub-panels into their own group (leaving a think BG_COLOR border between each panel). Also tidied up the code (the output from fluid). ------------------------------------------------------------------------ r1512 | ajapted | 2015-01-11 20:21:21 +1100 (Sun, 11 Jan 2015) | 3 lines Find/Replace : created main UI for this (done in Fluid, code reformatted and pasted here). Nothing works yet.... ------------------------------------------------------------------------ r1511 | ajapted | 2015-01-11 17:13:10 +1100 (Sun, 11 Jan 2015) | 2 lines Find/Replace : added 'Go to next' to View menu (not implemented yet....) ------------------------------------------------------------------------ r1510 | ajapted | 2015-01-11 17:03:54 +1100 (Sun, 11 Jan 2015) | 2 lines Find/Replace : add widget to main window, and added menu item for it. ------------------------------------------------------------------------ r1509 | ajapted | 2015-01-11 17:02:31 +1100 (Sun, 11 Jan 2015) | 2 lines Makefiles : added 'ui_replace.o' into the build. ------------------------------------------------------------------------ r1508 | ajapted | 2015-01-11 15:53:41 +1100 (Sun, 11 Jan 2015) | 3 lines Added new files 'ui_replace.cc/h' -- will contain the Find and Replace panel (only contains minimal code at the moment). ------------------------------------------------------------------------ r1507 | ajapted | 2015-01-11 15:45:16 +1100 (Sun, 11 Jan 2015) | 2 lines Default props : fixed using the Browser to set stuff (textures etc). ------------------------------------------------------------------------ r1506 | ajapted | 2015-01-11 15:28:07 +1100 (Sun, 11 Jan 2015) | 2 lines Default props : hide it when press CTRL-D and already shown. ------------------------------------------------------------------------ r1505 | ajapted | 2015-01-11 15:15:27 +1100 (Sun, 11 Jan 2015) | 2 lines Default props : added command in File/ menu to show it, and various fixes. ------------------------------------------------------------------------ r1504 | ajapted | 2015-01-11 14:52:55 +1100 (Sun, 11 Jan 2015) | 2 lines Default props : removed toggle button and related code. ------------------------------------------------------------------------ r1503 | ajapted | 2015-01-11 14:45:51 +1100 (Sun, 11 Jan 2015) | 2 lines Default props : added "Lower" (etc) names to the wall texture pics. ------------------------------------------------------------------------ r1502 | ajapted | 2015-01-11 14:07:15 +1100 (Sun, 11 Jan 2015) | 3 lines Finished separating UI_DefaultProps code, splitting the implementation into header file + code file definitions. ------------------------------------------------------------------------ r1501 | ajapted | 2015-01-11 13:57:04 +1100 (Sun, 11 Jan 2015) | 2 lines (forgot 'Makefile' in previous commit) ------------------------------------------------------------------------ r1500 | ajapted | 2015-01-11 13:45:05 +1100 (Sun, 11 Jan 2015) | 3 lines More work to separate UI_DefaultProps code -- mainly deleting the relevant parts from ui_vertex.* and ui_default.* -- but also updated the Makefiles. ------------------------------------------------------------------------ r1499 | ajapted | 2015-01-11 13:35:17 +1100 (Sun, 11 Jan 2015) | 3 lines Began work to separate code for the 'Default Properties' panel into its own code files --> ui_default.cc/h. This commit merely copies the new files. ------------------------------------------------------------------------ r1498 | ajapted | 2015-01-11 13:31:07 +1100 (Sun, 11 Jan 2015) | 3 lines Always show a two-sided line in LineDef panel when multiple lines are selected (and are a mix of one-sided and two-sided lines). ------------------------------------------------------------------------ r1497 | ajapted | 2015-01-09 14:30:00 +1100 (Fri, 09 Jan 2015) | 2 lines Wad code : re-sort the levels[] array after adding a new level. ------------------------------------------------------------------------ r1496 | ajapted | 2015-01-07 13:32:52 +1100 (Wed, 07 Jan 2015) | 3 lines Keys : convert FL_Button+n values <--> "MOUSE##" string, and FL_WheelUp/Dn values <--> "WHEEL_UP/DN" strings. ------------------------------------------------------------------------ r1495 | ajapted | 2015-01-06 16:01:31 +1100 (Tue, 06 Jan 2015) | 2 lines TODO.txt : moved the 'NO:' stuff to a separate NOT-TO-DO section. ------------------------------------------------------------------------ r1494 | ajapted | 2015-01-06 15:55:59 +1100 (Tue, 06 Jan 2015) | 3 lines Finished support for RECENT browser category, with new binding for '\' key which toggles between the ALL and RECENT categories. ------------------------------------------------------------------------ r1493 | ajapted | 2015-01-06 13:57:11 +1100 (Tue, 06 Jan 2015) | 4 lines More work on new "RECENT" category for Texture (etc) browsers. Implemented ability to save/restore them from the .dat cache file, and fixed a few issues. ------------------------------------------------------------------------ r1492 | ajapted | 2015-01-06 13:55:15 +1100 (Tue, 06 Jan 2015) | 3 lines Menu : removed short-cut from 'File/Delete Map' command, as it likely will be used rarely and it's not something you want to hit accidentally. ------------------------------------------------------------------------ r1491 | ajapted | 2015-01-06 11:05:17 +1100 (Tue, 06 Jan 2015) | 2 lines Partial work on a "RECENT" category for the Texture, Flat and Thing browsers. ------------------------------------------------------------------------ r1490 | ajapted | 2015-01-05 19:31:27 +1100 (Mon, 05 Jan 2015) | 2 lines Updated some copyright messages (e.g. About box) for 2015. ------------------------------------------------------------------------ r1489 | ajapted | 2015-01-05 19:30:50 +1100 (Mon, 05 Jan 2015) | 2 lines Version bump. ------------------------------------------------------------------------ r1488 | ajapted | 2015-01-05 19:14:57 +1100 (Mon, 05 Jan 2015) | 2 lines Render : fixed clipping of mid-masked textures (e.g. the cage in E1M9) ------------------------------------------------------------------------ r1487 | ajapted | 2015-01-05 11:55:34 +1100 (Mon, 05 Jan 2015) | 2 lines Moved the BA_LevelChecksum() code from e_loadsave --> e_basis ------------------------------------------------------------------------ r1486 | ajapted | 2015-01-05 11:54:31 +1100 (Mon, 05 Jan 2015) | 3 lines Wad code : sort the levels alphabetically in the levels[] vector (mainly for the next-map and prev-map commands). ------------------------------------------------------------------------ r1485 | ajapted | 2015-01-05 11:10:08 +1100 (Mon, 05 Jan 2015) | 2 lines Implemented the 'File / Rename Map' command (no shortcut key). ------------------------------------------------------------------------ r1484 | ajapted | 2015-01-05 10:21:10 +1100 (Mon, 05 Jan 2015) | 2 lines Wad code : implemented 'RenameLump()' method. ------------------------------------------------------------------------ r1483 | ajapted | 2015-01-05 10:07:04 +1100 (Mon, 05 Jan 2015) | 2 lines Implemented new 'File / Delete Map' command (bound to CTRL-d key). ------------------------------------------------------------------------ r1482 | ajapted | 2015-01-04 20:50:46 +1100 (Sun, 04 Jan 2015) | 5 lines Reworked the way "New WAD File" button in the 'New Map' command works, it is now a radio button with another choice "Current WAD File", and when chosen then we immediately try to save (export) the new map -- which feels more like what the user would expect. ------------------------------------------------------------------------ r1481 | ajapted | 2015-01-04 20:10:14 +1100 (Sun, 04 Jan 2015) | 2 lines TODO update. ------------------------------------------------------------------------ r1480 | ajapted | 2015-01-04 20:06:35 +1100 (Sun, 04 Jan 2015) | 3 lines Fixed the occasional false positives with the sector mismatch test (caused by poor logic in OppositeLineDef and OppositeSector functions). ------------------------------------------------------------------------ r1479 | ajapted | 2015-01-04 20:04:46 +1100 (Sun, 04 Jan 2015) | 3 lines Fixed zooming after doing a command, like 'j' JumpToObject, which moves the map origin to focus on some selected object(s). ------------------------------------------------------------------------ r1478 | ajapted | 2015-01-04 16:48:05 +1100 (Sun, 04 Jan 2015) | 2 lines Makefile.xming : updated to use 'mingw-w64' cross compiler and zlib 1.2.8 ------------------------------------------------------------------------ r1477 | ajapted | 2015-01-04 16:34:56 +1100 (Sun, 04 Jan 2015) | 2 lines Removed 'slurp' directory from obj_linux/ and obj_win32/ ------------------------------------------------------------------------ r1476 | ajapted | 2015-01-04 16:32:14 +1100 (Sun, 04 Jan 2015) | 2 lines Makefiles : added 'STRIP_FLAGS' variable (for "stripped" target). ------------------------------------------------------------------------ r1475 | ajapted | 2015-01-04 16:01:35 +1100 (Sun, 04 Jan 2015) | 4 lines For 'New Map' dialog, added a "New File" check button which means the wad will be saved into a new file (disables the map selection, since that is done by the export map dialog). ------------------------------------------------------------------------ r1474 | ajapted | 2015-01-04 11:55:08 +1100 (Sun, 04 Jan 2015) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1473 | ajapted | 2015-01-04 11:54:26 +1100 (Sun, 04 Jan 2015) | 2 lines Support two numeric values after -warp, compatible with vanilla DOOM. ------------------------------------------------------------------------ r1472 | ajapted | 2015-01-04 11:30:20 +1100 (Sun, 04 Jan 2015) | 3 lines Linedef panel : swapped 'Tag' and 'Length' widgets(so Tag is now on left (like the Sector panel). ------------------------------------------------------------------------ r1471 | ajapted | 2015-01-04 11:25:27 +1100 (Sun, 04 Jan 2015) | 2 lines Code : silence some compiler warnings about integer conversions. ------------------------------------------------------------------------ r1470 | printz | 2015-01-03 09:01:20 +1100 (Sat, 03 Jan 2015) | 3 lines osx: * Fixed type warnings on the app delegate because I didn't set it to conform to the NSApplicationDelegate protocol * Added other .a files to the dependency list, because I was getting linker errors. ------------------------------------------------------------------------ r1469 | printz | 2014-11-15 10:06:48 +1100 (Sat, 15 Nov 2014) | 2 lines * Updated Xcode project to work * Removed a personal file ------------------------------------------------------------------------ r1468 | ajapted | 2014-10-25 22:34:34 +1100 (Sat, 25 Oct 2014) | 4 lines Support 'coop_dm_flags' feature in game definitions, and when not enabled then show a vanilla DOOM compatible "dm" thing flag (instead of the normal three sp/coop/dm flags). ------------------------------------------------------------------------ r1467 | ajapted | 2014-10-25 22:00:21 +1100 (Sat, 25 Oct 2014) | 2 lines Fixed makefile "install" targets for r1459 (moved "bindings.cfg" to top level) ------------------------------------------------------------------------ r1466 | ajapted | 2014-10-25 21:54:50 +1100 (Sat, 25 Oct 2014) | 3 lines UI_Window : added UpdateGameInfo() method, and use it for THING panel to show or hide the "friend" checkbox depending on game_info.friend_flag ------------------------------------------------------------------------ r1465 | ajapted | 2014-10-25 21:53:26 +1100 (Sat, 25 Oct 2014) | 2 lines Added 'friend_flag' field to game_info_t and parse it from definition files. ------------------------------------------------------------------------ r1464 | ajapted | 2014-10-25 21:52:16 +1100 (Sat, 25 Oct 2014) | 2 lines Ports / BOOM : added "feature friend_flag 1" ------------------------------------------------------------------------ r1463 | ajapted | 2014-10-25 21:27:26 +1100 (Sat, 25 Oct 2014) | 3 lines Use simple char[] for 'sky_flat' member of game_info, so we can memset() the whole structure to zero in M_InitDefinitions(). ------------------------------------------------------------------------ r1462 | ajapted | 2014-10-25 20:11:57 +1100 (Sat, 25 Oct 2014) | 4 lines (part of VM removal) : removed 'misc/core_defs.up' script file, which was never used and barely had anything in it. Updated 'make install' targets in the Makefiles too. ------------------------------------------------------------------------ r1461 | ajapted | 2014-10-25 20:07:13 +1100 (Sat, 25 Oct 2014) | 3 lines Removed all the VM code (vm.h + vm_*.cc) -- this was never used and was a long way from becoming usable. Lua would be a better choice anyway. ------------------------------------------------------------------------ r1460 | ajapted | 2014-10-25 19:52:30 +1100 (Sat, 25 Oct 2014) | 2 lines Preferences : added '192' to list of possible default grid sizes. ------------------------------------------------------------------------ r1459 | ajapted | 2014-09-12 20:29:11 +1000 (Fri, 12 Sep 2014) | 3 lines Moved 'bindings.cfg' to top level in repository, so that running Eureka after a compilation (without installing it) works. ------------------------------------------------------------------------ r1458 | ajapted | 2014-09-12 20:22:51 +1000 (Fri, 12 Sep 2014) | 2 lines silence a compiler warning. ------------------------------------------------------------------------ r1457 | ajapted | 2014-08-15 15:28:58 +1000 (Fri, 15 Aug 2014) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1456 | ajapted | 2014-08-15 13:45:35 +1000 (Fri, 15 Aug 2014) | 5 lines 3D View : fixed texturing issue, textures could be vertically off by a pixel (due to the way casting float --> int will round towards zero). This closes ticket #3. Bug reported by 'umbrakun'. ------------------------------------------------------------------------ r1455 | ajapted | 2014-08-06 16:14:06 +1000 (Wed, 06 Aug 2014) | 2 lines README.txt : added contact details at the end. ------------------------------------------------------------------------ r1454 | ajapted | 2014-08-06 15:49:34 +1000 (Wed, 06 Aug 2014) | 2 lines TODO update. ------------------------------------------------------------------------ r1453 | ajapted | 2014-06-25 22:05:45 +1000 (Wed, 25 Jun 2014) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1452 | ajapted | 2014-06-25 22:04:01 +1000 (Wed, 25 Jun 2014) | 8 lines glBSP library : improved method of creating a dummy node, we now create a real subsector and a real seg for the back side of the partition line (though the seg is a carbon copy of an existing one). This method should be more robust, since the created structures are all real (instead of re-using an index number). Tested in various software rendered ports without any problem. ------------------------------------------------------------------------ r1451 | ajapted | 2014-06-25 21:32:11 +1000 (Wed, 25 Jun 2014) | 3 lines Removed misc/slurp -- (a) it does not belong here, and (b) I do not plan to finish or release it. ------------------------------------------------------------------------ r1450 | ajapted | 2014-06-25 21:15:11 +1000 (Wed, 25 Jun 2014) | 2 lines Comment the NSIS makefile and 'nsi' file as OLD / OBSOLETE. ------------------------------------------------------------------------ r1449 | ajapted | 2014-06-25 19:53:59 +1000 (Wed, 25 Jun 2014) | 3 lines Ports / BOOM : added "feature gen_types 1" -- this will (in the future) enable support for generalized linedefs and sectors. ------------------------------------------------------------------------ r1448 | ajapted | 2014-06-25 19:51:55 +1000 (Wed, 25 Jun 2014) | 6 lines Game definition parser : support "feature" keyword which is used to activate (or de-activate) certain game- or port-related features. So far three feature names are _parsed_, but there is no actual support for those features yet. ------------------------------------------------------------------------ r1447 | printz | 2014-06-25 17:27:19 +1000 (Wed, 25 Jun 2014) | 3 lines Xcode project: * Updated library references * Made it so all source files (at least from the C++ group) will have real tabs instead of groups of spaces ------------------------------------------------------------------------ r1446 | ajapted | 2014-06-19 22:31:53 +1000 (Thu, 19 Jun 2014) | 2 lines glBSP library : more dramatic warning when creating a dummy node. ------------------------------------------------------------------------ r1445 | ajapted | 2014-06-19 22:14:18 +1000 (Thu, 19 Jun 2014) | 6 lines glBSP library : implemented a hack for the case when no nodes are generated (i.e. when the whole level is a single convex sector). This hack involves creating a dummy node with the real subsector on one side, and a dummy one on the other. ------------------------------------------------------------------------ r1444 | ajapted | 2014-06-19 20:38:08 +1000 (Thu, 19 Jun 2014) | 2 lines TODO.txt : moved more stuff --> doc/MiscNotes.txt ------------------------------------------------------------------------ r1443 | ajapted | 2014-06-19 19:20:55 +1000 (Thu, 19 Jun 2014) | 3 lines TODO.txt : updated various entries, and moved some of the notes to a new file --> docs/MiscNotes.txt ------------------------------------------------------------------------ r1442 | ajapted | 2014-06-19 19:05:47 +1000 (Thu, 19 Jun 2014) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1441 | ajapted | 2014-06-19 19:01:17 +1000 (Thu, 19 Jun 2014) | 2 lines About box : show version number _in_ the text (not just window title). ------------------------------------------------------------------------ r1440 | ajapted | 2014-06-19 18:47:45 +1000 (Thu, 19 Jun 2014) | 2 lines When saving the map, save any header data too (for FraggleScript etc). ------------------------------------------------------------------------ r1439 | ajapted | 2014-06-19 18:27:28 +1000 (Thu, 19 Jun 2014) | 3 lines When loading a map, load any data in the header lump, especially the FraggleScript and level-info data used by DOOM Legacy. ------------------------------------------------------------------------ r1438 | ajapted | 2014-06-19 17:45:39 +1000 (Thu, 19 Jun 2014) | 2 lines Makefile.xming (WIN32) : update to FLTK 1.3.2 and zlib 1.2.6 ------------------------------------------------------------------------ r1437 | ajapted | 2014-06-19 13:07:06 +1000 (Thu, 19 Jun 2014) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1436 | ajapted | 2014-06-19 13:05:54 +1000 (Thu, 19 Jun 2014) | 8 lines Support loading a pwad which is READ-ONLY. This will cause the 'Save' action to ask whether to export to a file, and the 'Build Nodes' action will show a fail message. The window title will also show the read-only state of the current file. This closes bug ticket #2. ------------------------------------------------------------------------ r1435 | ajapted | 2014-05-18 16:59:56 +1000 (Sun, 18 May 2014) | 2 lines File menu : tweaked position of Build Nodes entry. ------------------------------------------------------------------------ r1434 | ajapted | 2014-05-18 16:54:44 +1000 (Sun, 18 May 2014) | 4 lines Fixed bug when saving a map and using the "ExMx" buttons -- there was an erroneous newline added to the lump name, preventing the game from accessing the map. Thanks to ettingrinder for the bug report. ------------------------------------------------------------------------ r1433 | ajapted | 2014-01-26 00:16:36 +1100 (Sun, 26 Jan 2014) | 3 lines Fixed bug not loading 'ASHWALL' texture for DOOM 1, which occurred because we erroneously skipped the first entry of TEXTURE2 lump. ------------------------------------------------------------------------ r1432 | ajapted | 2014-01-26 00:14:51 +1100 (Sun, 26 Jan 2014) | 2 lines Began fresh CHANGES.txt document (after 1.00 release) ------------------------------------------------------------------------ r1431 | ajapted | 2014-01-26 00:13:52 +1100 (Sun, 26 Jan 2014) | 2 lines Moved version 1.00 CHANGELOG --> changelogs/100.txt ------------------------------------------------------------------------ r1430 | ajapted | 2014-01-09 10:26:25 +1100 (Thu, 09 Jan 2014) | 2 lines Post-release version bump. ------------------------------------------------------------------------ r1429 | ajapted | 2014-01-05 22:31:54 +1100 (Sun, 05 Jan 2014) | 2 lines Updated some copyright years (e.g. in About box) for 2014. ------------------------------------------------------------------------ r1428 | ajapted | 2014-01-05 21:26:00 +1100 (Sun, 05 Jan 2014) | 2 lines Re-instated the '192' grid size (reverted revision 628). ------------------------------------------------------------------------ r1427 | ajapted | 2013-12-27 10:22:24 +1100 (Fri, 27 Dec 2013) | 2 lines Updated GPL.txt -- the GNU General Public License (version 2). ------------------------------------------------------------------------ r1426 | ajapted | 2013-10-27 14:21:34 +1100 (Sun, 27 Oct 2013) | 2 lines Makefile : renamed INSTALL_PREFIX --> PREFIX ------------------------------------------------------------------------ r1425 | ajapted | 2013-10-27 13:49:10 +1100 (Sun, 27 Oct 2013) | 2 lines Use I_ROUND() macro instead of round() standard library call. ------------------------------------------------------------------------ r1424 | ajapted | 2013-09-09 20:02:55 +1000 (Mon, 09 Sep 2013) | 2 lines Workaround a compiler warning. ------------------------------------------------------------------------ r1423 | ajapted | 2013-08-25 15:26:16 +1000 (Sun, 25 Aug 2013) | 2 lines History.txt : resync for the 1.00 release. ------------------------------------------------------------------------ r1422 | ajapted | 2013-08-25 15:20:46 +1000 (Sun, 25 Aug 2013) | 2 lines Pack-source script: handle the 'ups' folder (as per 'mods' etc). ------------------------------------------------------------------------ r1421 | ajapted | 2013-08-25 14:58:40 +1000 (Sun, 25 Aug 2013) | 2 lines README.txt : more updates to the keys list. ------------------------------------------------------------------------ r1420 | ajapted | 2013-08-25 14:48:04 +1000 (Sun, 25 Aug 2013) | 2 lines README.txt : updated key list for ';' and 3D view offset commands. ------------------------------------------------------------------------ r1419 | ajapted | 2013-08-25 14:36:09 +1000 (Sun, 25 Aug 2013) | 2 lines README.txt : simplified the INTRODUCTION section. ------------------------------------------------------------------------ r1418 | printz | 2013-08-25 09:18:26 +1000 (Sun, 25 Aug 2013) | 7 lines osx: * Added a new generic OSX call module, for interfacing OSX system calls with the main application C++ code * Prepared Xcode project for release * Corrected copyright in my modules to actually refer to the author(s) of Eureka in whole, not to the author of the module. * Removed dead code from AppDelegate.mm * Updated OSX icon * Fixed main.cc to use system-proof application data directories. ------------------------------------------------------------------------ r1417 | ajapted | 2013-08-23 21:52:21 +1000 (Fri, 23 Aug 2013) | 2 lines INSTALL.txt tweak. ------------------------------------------------------------------------ r1416 | ajapted | 2013-08-23 21:44:10 +1000 (Fri, 23 Aug 2013) | 2 lines CHANGELOG tweak for 1.00 release. ------------------------------------------------------------------------ r1415 | ajapted | 2013-08-23 21:34:00 +1000 (Fri, 23 Aug 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1414 | ajapted | 2013-08-23 15:33:43 +1000 (Fri, 23 Aug 2013) | 2 lines NSIS install script : updated to use the Modern UI (MUI2.nsh). ------------------------------------------------------------------------ r1413 | ajapted | 2013-08-23 15:30:07 +1000 (Fri, 23 Aug 2013) | 3 lines Makefile.xming : updated 'nsis_build' target to add "ups" folder and to copy the "about_logo.png" and "core_defs.up" files. ------------------------------------------------------------------------ r1412 | ajapted | 2013-08-23 15:05:08 +1000 (Fri, 23 Aug 2013) | 2 lines Makefile.xming : properly include the Win32 resource stuff in the build. ------------------------------------------------------------------------ r1411 | ajapted | 2013-08-23 14:51:50 +1000 (Fri, 23 Aug 2013) | 2 lines Updated WIN32 "rc" file to include the ICON resource. ------------------------------------------------------------------------ r1410 | ajapted | 2013-08-23 14:51:17 +1000 (Fri, 23 Aug 2013) | 3 lines Fixed WIN32 icon file (eureka.ico) -- I accidentally committed the XCF version before. ------------------------------------------------------------------------ r1409 | ajapted | 2013-08-23 14:42:56 +1000 (Fri, 23 Aug 2013) | 2 lines Makefile.xming : added 'fltk_png.a' library to the build. ------------------------------------------------------------------------ r1408 | ajapted | 2013-08-23 14:39:37 +1000 (Fri, 23 Aug 2013) | 2 lines Fixed bug in WIN32-specific code. ------------------------------------------------------------------------ r1407 | ajapted | 2013-08-23 14:37:11 +1000 (Fri, 23 Aug 2013) | 2 lines Quieten some compiler warnings. ------------------------------------------------------------------------ r1406 | ajapted | 2013-08-23 14:24:38 +1000 (Fri, 23 Aug 2013) | 2 lines Created a 128x128 win32 icon and a 32x32 linux xpm from Jason's logo. ------------------------------------------------------------------------ r1405 | ajapted | 2013-08-22 22:32:34 +1000 (Thu, 22 Aug 2013) | 2 lines TODO updated. ------------------------------------------------------------------------ r1404 | ajapted | 2013-08-22 21:48:25 +1000 (Thu, 22 Aug 2013) | 2 lines Version bump to 1.00, heading towards a release... ------------------------------------------------------------------------ r1403 | ajapted | 2013-08-22 21:42:42 +1000 (Thu, 22 Aug 2013) | 2 lines CHANGELOG: more tweakage. ------------------------------------------------------------------------ r1402 | ajapted | 2013-08-22 21:35:06 +1000 (Thu, 22 Aug 2013) | 6 lines 3D View: 1. implemented logic to determine coordinates for a highlighted wall and then create the lines to draw. 2. removed some old, non-working highlight code. ------------------------------------------------------------------------ r1401 | ajapted | 2013-08-22 16:30:35 +1000 (Thu, 22 Aug 2013) | 2 lines 3D View: more work on logic to highlight walls.... ------------------------------------------------------------------------ r1400 | ajapted | 2013-08-22 15:37:20 +1000 (Thu, 22 Aug 2013) | 3 lines 3D View: use current highlight info for offset adjustment and alignment commands (rather than perform a redundant query). ------------------------------------------------------------------------ r1399 | ajapted | 2013-08-22 14:40:03 +1000 (Thu, 22 Aug 2013) | 3 lines 3D View: added logic to keep track of a "highlighted" wotsit, and to only redraw the view when it changes. ------------------------------------------------------------------------ r1398 | ajapted | 2013-08-22 14:12:53 +1000 (Thu, 22 Aug 2013) | 4 lines 3D View: 1. began work on ability to highlight sidedef under the mouse 2. moved some code around ------------------------------------------------------------------------ r1397 | ajapted | 2013-08-21 22:50:28 +1000 (Wed, 21 Aug 2013) | 2 lines CHANGELOG : update and tweakage. ------------------------------------------------------------------------ r1396 | ajapted | 2013-08-21 22:49:36 +1000 (Wed, 21 Aug 2013) | 2 lines Texture alignment: added 'X', 'Y', 'Z' key bindings. ------------------------------------------------------------------------ r1395 | ajapted | 2013-08-21 22:29:00 +1000 (Wed, 21 Aug 2013) | 5 lines Texture alignment: 1. support for 'r' flag : align with wall "to the right" 2. PartialTexCmp() now compares 6 letters, not 4 3. tweaked scoring function for adjoiners ------------------------------------------------------------------------ r1394 | ajapted | 2013-08-21 19:02:58 +1000 (Wed, 21 Aug 2013) | 3 lines Texture alignment: dead code removal: (1) old DEU alignment stuff, and (2) my linedef-mode alignment logic. ------------------------------------------------------------------------ r1393 | ajapted | 2013-08-21 18:58:45 +1000 (Wed, 21 Aug 2013) | 3 lines Texture alignment: implemented PickAdjoinerPart(), tweaked some code, and removed some dead code. ------------------------------------------------------------------------ r1392 | ajapted | 2013-08-20 22:17:31 +1000 (Tue, 20 Aug 2013) | 4 lines Texture alignment: still banging away on this, e.g. pass the particular part (upper or lower) which the user clicked on to LineDefs_Align(), and wrote some logic for picking which adjoiner part of align with. ------------------------------------------------------------------------ r1391 | ajapted | 2013-08-20 15:20:57 +1000 (Tue, 20 Aug 2013) | 3 lines Texture alignment: fleshed out the logic for Y alignment, though it is not 100% finished yet.... ------------------------------------------------------------------------ r1390 | ajapted | 2013-08-17 16:22:13 +1000 (Sat, 17 Aug 2013) | 5 lines 3D_Align: more work on texture alignment: 1. the chosen adjoiner is always on the LEFT to the chosen sidedef 2. implemented DoAlignX() 3. started work on DoAlignY(), but it needs proper calculation ------------------------------------------------------------------------ r1389 | ajapted | 2013-08-17 15:51:07 +1000 (Sat, 17 Aug 2013) | 3 lines 3D_Align: for 'c' clear flag, properly handle different combinations of the 'x' and 'y' flags. ------------------------------------------------------------------------ r1388 | ajapted | 2013-08-17 14:55:19 +1000 (Sat, 17 Aug 2013) | 2 lines Texture alignment: implemented the 'c' (clear offsets) flag. ------------------------------------------------------------------------ r1387 | ajapted | 2013-08-17 14:37:07 +1000 (Sat, 17 Aug 2013) | 8 lines Texture aligning: began work on new method which is done in 3D Mode. This commit disables the 'LIN_Align' binding command, replacing it with '3D_Align' binding command (which does nothing yet). Updated the default bindings too, with 'x', 'y', 'z' and 'c' keys. The 'c' key will clear the offsets, and 'z' aligns both X and Y (I would preferred 'a' do both, but it is used for WASD movement). ------------------------------------------------------------------------ r1386 | ajapted | 2013-08-17 14:31:30 +1000 (Sat, 17 Aug 2013) | 2 lines Disabled the Adjoiner test code.... ------------------------------------------------------------------------ r1385 | ajapted | 2013-08-02 22:46:35 +1000 (Fri, 02 Aug 2013) | 2 lines minor update. ------------------------------------------------------------------------ r1384 | ajapted | 2013-08-02 21:23:52 +1000 (Fri, 02 Aug 2013) | 3 lines Texture alignment: try to pick the next sidedef a bit more intelligently, however I don't think this approach is really cutting the mustard.... ------------------------------------------------------------------------ r1383 | ajapted | 2013-08-02 19:54:42 +1000 (Fri, 02 Aug 2013) | 4 lines Texture alignment: 1. adjoiner scoring function: preference for same sided-ness of lines 2. added testing code -- highlight the best adjoiner of a line ------------------------------------------------------------------------ r1382 | ajapted | 2013-08-02 19:32:03 +1000 (Fri, 02 Aug 2013) | 4 lines Texture alignment: implemented scoring logic for adjoiners, firstly making sure that the sidedefs are actually next to each other, and secondly giving a score based on texture matching (etc). ------------------------------------------------------------------------ r1381 | ajapted | 2013-08-02 17:22:04 +1000 (Fri, 02 Aug 2013) | 3 lines Texture alignment: updated remaining code for 'side_on_a_line_t' typedef and access functions. ------------------------------------------------------------------------ r1380 | ajapted | 2013-08-02 14:42:51 +1000 (Fri, 02 Aug 2013) | 4 lines Texture alignment: introduced a 'side_on_a_line_t' typedef to simplify passing around the LINE+SIDE references. Partial work on the logic to determine the adjoiner for a side. ------------------------------------------------------------------------ r1379 | ajapted | 2013-08-02 14:18:53 +1000 (Fri, 02 Aug 2013) | 2 lines Basis : added LineDef::WhatSideDef() method. ------------------------------------------------------------------------ r1378 | ajapted | 2013-08-02 13:42:17 +1000 (Fri, 02 Aug 2013) | 3 lines Texture alignment: a bit more work, e.g. logic for handling the unpeg linedef flags, and added PartialTexCmp() function. ------------------------------------------------------------------------ r1377 | ajapted | 2013-08-02 12:33:09 +1000 (Fri, 02 Aug 2013) | 4 lines LineDef panel: reverted layout of sidedef textures to match previous versions (i.e. LOWER / RAIL / UPPER) -- although single-sided lines still use the LOWER spot for its texture. ------------------------------------------------------------------------ r1376 | ajapted | 2013-08-02 12:26:58 +1000 (Fri, 02 Aug 2013) | 5 lines Texture alignment: fleshed out more of the code, e.g. the logic for collecting which sidedefs to align, and logic to pick which sidedef to align next (ensuring we do an adjoiner _before_ that sidedef, if possible). ------------------------------------------------------------------------ r1375 | ajapted | 2013-08-01 22:54:29 +1000 (Thu, 01 Aug 2013) | 2 lines History.txt : added a preface about the different repositories. ------------------------------------------------------------------------ r1374 | ajapted | 2013-08-01 21:25:14 +1000 (Thu, 01 Aug 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1373 | ajapted | 2013-08-01 21:12:07 +1000 (Thu, 01 Aug 2013) | 2 lines TODO updated. ------------------------------------------------------------------------ r1372 | ajapted | 2013-08-01 21:10:45 +1000 (Thu, 01 Aug 2013) | 3 lines Renderer: got the query() method working, and use it to determine which linedef / sidedef to adjust the offsets on. ------------------------------------------------------------------------ r1371 | ajapted | 2013-08-01 17:16:49 +1000 (Thu, 01 Aug 2013) | 2 lines Renderer: use SIDE_LEFT / SIDE_RIGHT rather than 0/1. ------------------------------------------------------------------------ r1370 | ajapted | 2013-08-01 17:11:04 +1000 (Thu, 01 Aug 2013) | 2 lines Renderer: more work on query() method.... ------------------------------------------------------------------------ r1369 | ajapted | 2013-08-01 16:49:41 +1000 (Thu, 01 Aug 2013) | 4 lines Renderer: began work on a query() method which will determine what the mouse pointer is pointing at. It will perform a limited rendering to determine which wall / floor under the pointer. ------------------------------------------------------------------------ r1368 | ajapted | 2013-08-01 16:47:17 +1000 (Thu, 01 Aug 2013) | 2 lines Texture alignment: comment defining flags to LIN_Align(). ------------------------------------------------------------------------ r1367 | ajapted | 2013-08-01 15:33:29 +1000 (Thu, 01 Aug 2013) | 2 lines Preferences: tweaked layout in each panel for better consistency. ------------------------------------------------------------------------ r1366 | ajapted | 2013-08-01 13:55:28 +1000 (Thu, 01 Aug 2013) | 2 lines Improved normal grid drawing, darken colors when lines get close together. ------------------------------------------------------------------------ r1365 | ajapted | 2013-07-31 22:31:53 +1000 (Wed, 31 Jul 2013) | 4 lines Began work on texture alignment commands. This commit merely replaces the two LIN_AlignX/Y functions into a single one 'LIN_Align', with updated key bindings file. ------------------------------------------------------------------------ r1364 | ajapted | 2013-07-31 22:22:00 +1000 (Wed, 31 Jul 2013) | 2 lines Version bump to 0.99 ------------------------------------------------------------------------ r1363 | ajapted | 2013-07-31 21:07:37 +1000 (Wed, 31 Jul 2013) | 2 lines Preferences: fixed the 'render_lock_gravity' option. ------------------------------------------------------------------------ r1362 | ajapted | 2013-07-31 21:01:38 +1000 (Wed, 31 Jul 2013) | 2 lines Render3D_Wheel: added 'dx' parameter, use it to move left/right. ------------------------------------------------------------------------ r1361 | ajapted | 2013-07-31 20:40:43 +1000 (Wed, 31 Jul 2013) | 2 lines Removed obj_no_t typedef -- just use 'int' instead. ------------------------------------------------------------------------ r1360 | ajapted | 2013-07-31 20:12:29 +1000 (Wed, 31 Jul 2013) | 6 lines Improved highlight behavior of vertices when grid-snap is enabled. The previous method merely expanded the search range to find a vertex to highlight (get_cur_vertex) -- this made it too easy to accidently drag the wrong vertex. ------------------------------------------------------------------------ r1359 | ajapted | 2013-07-31 20:07:54 +1000 (Wed, 31 Jul 2013) | 2 lines Objid class: added a copy constructor. ------------------------------------------------------------------------ r1358 | ajapted | 2013-07-31 20:05:16 +1000 (Wed, 31 Jul 2013) | 2 lines Added Vertex_FindExact() utility function. ------------------------------------------------------------------------ r1357 | ajapted | 2013-07-31 16:03:40 +1000 (Wed, 31 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1356 | ajapted | 2013-07-31 16:01:16 +1000 (Wed, 31 Jul 2013) | 3 lines Implemented 'render_lock_gravity' config option, when enabled and gravity is ON then you cannot move up or down in the 3D view. ------------------------------------------------------------------------ r1355 | ajapted | 2013-07-31 14:34:17 +1000 (Wed, 31 Jul 2013) | 5 lines LineDef panel: the 'Length' widget is now an input box, and implemented ability to enter a new length value and change all selected linedefs. Doing this with all linedefs selected is a great way to wreck a map! ------------------------------------------------------------------------ r1354 | ajapted | 2013-07-31 14:22:11 +1000 (Wed, 31 Jul 2013) | 2 lines Check / linedefs: layout tweak. ------------------------------------------------------------------------ r1353 | ajapted | 2013-07-31 13:38:09 +1000 (Wed, 31 Jul 2013) | 2 lines Dead code removal : frob_things_flags(). ------------------------------------------------------------------------ r1352 | ajapted | 2013-07-31 13:36:16 +1000 (Wed, 31 Jul 2013) | 2 lines Dead code removal : frob_linedefs_flags() etc... ------------------------------------------------------------------------ r1351 | ajapted | 2013-07-31 13:13:01 +1000 (Wed, 31 Jul 2013) | 3 lines In vertex mode, display length of last three linedefs (typically ones which the user just added). ------------------------------------------------------------------------ r1350 | ajapted | 2013-07-30 22:23:42 +1000 (Tue, 30 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1349 | ajapted | 2013-07-30 22:21:24 +1000 (Tue, 30 Jul 2013) | 3 lines Better drawing of things (in THINGS mode) -- fill in their body with a darker version of their color. ------------------------------------------------------------------------ r1348 | ajapted | 2013-07-30 21:59:08 +1000 (Tue, 30 Jul 2013) | 2 lines Implemented mouse scaling using new 'edit.action' mechanism. ------------------------------------------------------------------------ r1347 | ajapted | 2013-07-30 16:58:21 +1000 (Tue, 30 Jul 2013) | 2 lines Use the edit.action mechanism for dragging and the selection box. ------------------------------------------------------------------------ r1346 | ajapted | 2013-07-30 14:45:22 +1000 (Tue, 30 Jul 2013) | 3 lines Implemented ClosestLine_CastAtAngle() utility function which finds the closest linedef to a point casting at an arbitrary angle. ------------------------------------------------------------------------ r1345 | ajapted | 2013-07-30 14:34:26 +1000 (Tue, 30 Jul 2013) | 2 lines Print a log message after unpacking sidedefs. ------------------------------------------------------------------------ r1344 | ajapted | 2013-07-30 14:33:53 +1000 (Tue, 30 Jul 2013) | 2 lines LoadLevel: reset editor state _before_ loading the user state. ------------------------------------------------------------------------ r1343 | ajapted | 2013-07-29 22:38:52 +1000 (Mon, 29 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1342 | ajapted | 2013-07-29 22:38:00 +1000 (Mon, 29 Jul 2013) | 4 lines Adjust offsets: properly compute 'dx_factor' and 'dy_factor' values based on the distance of the linedef to the camera. This makes it look like you are really dragging the texture around the wall. ------------------------------------------------------------------------ r1341 | ajapted | 2013-07-29 21:54:34 +1000 (Mon, 29 Jul 2013) | 2 lines Adjust offsets: the SHIFT key makes the adjustment finer (slower). ------------------------------------------------------------------------ r1340 | ajapted | 2013-07-29 21:47:59 +1000 (Mon, 29 Jul 2013) | 4 lines Removed unnecessary MarkChanges() and 'edit.RedrawMap = 1' statements. Also fixed recent bug of texture changes not redrawing the 3D view. ------------------------------------------------------------------------ r1339 | ajapted | 2013-07-29 21:35:40 +1000 (Mon, 29 Jul 2013) | 2 lines Dead code removal. ------------------------------------------------------------------------ r1338 | ajapted | 2013-07-29 21:29:02 +1000 (Mon, 29 Jul 2013) | 2 lines Added GoToErrors() convenience function. ------------------------------------------------------------------------ r1337 | ajapted | 2013-07-29 21:18:08 +1000 (Mon, 29 Jul 2013) | 2 lines Simplified handling of 'MadeChanges' global var. ------------------------------------------------------------------------ r1336 | ajapted | 2013-07-29 15:58:13 +1000 (Mon, 29 Jul 2013) | 2 lines Disabled '!' prefix in the window title -- was not useful after all. ------------------------------------------------------------------------ r1335 | ajapted | 2013-07-29 12:28:46 +1000 (Mon, 29 Jul 2013) | 4 lines Implemented SideDefs_NormalizeMiddles(), which is used after level load and ensures that one-sided linedefs do not have an "Upper" or "Rail" texture (as shown by the LineDef panel). ------------------------------------------------------------------------ r1334 | ajapted | 2013-07-28 20:05:32 +1000 (Sun, 28 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1333 | ajapted | 2013-07-28 20:01:41 +1000 (Sun, 28 Jul 2013) | 4 lines After loading a map, reset various editor state, especially clearing the selection and highlight (prevent a possible crash), and update the map totals (# of linedefs, etc) for the side panel. ------------------------------------------------------------------------ r1332 | ajapted | 2013-07-28 19:44:00 +1000 (Sun, 28 Jul 2013) | 2 lines CHANGELOG: added the new sidedef layout. ------------------------------------------------------------------------ r1331 | ajapted | 2013-07-28 19:43:25 +1000 (Sun, 28 Jul 2013) | 4 lines Adjust offsets: force mouse deltas to be either vertical or horizontal, which makes it easier to make large horizontal adjustments without it going up or down, and vice versa. ------------------------------------------------------------------------ r1330 | ajapted | 2013-07-28 19:27:02 +1000 (Sun, 28 Jul 2013) | 11 lines LideDef panel: changed layout of textures in each SideDef section. The default order is now LOWER / UPPER / RAIL. Also, single-sided linedefs show the texture in the "LOWER" position, since there is no longer a spot for a "middle" texture. The main benefit of this is when multiple linedefs are selected which is a mix of one-sided and two-sided lines, the user can safely change the "LOWER" (or LOWER + UPPER) on all the linedefs without ending up with unwanted railing textures. ------------------------------------------------------------------------ r1329 | ajapted | 2013-07-28 19:17:59 +1000 (Sun, 28 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1328 | ajapted | 2013-07-28 19:00:52 +1000 (Sun, 28 Jul 2013) | 3 lines Automatically unpack sidedefs when loading a map, since the previous confirmation dialog was probably more of a nuisance than a help. ------------------------------------------------------------------------ r1327 | ajapted | 2013-07-28 18:45:49 +1000 (Sun, 28 Jul 2013) | 3 lines Basis: added BA_Abort() function which discards the current group of operations and (optionally) undoes the changes since BA_Begin(). ------------------------------------------------------------------------ r1326 | ajapted | 2013-07-28 18:10:50 +1000 (Sun, 28 Jul 2013) | 3 lines 3D View: changing the aspect ratio preference setting did not update the rendered view (unless user changed window size) -- fixed. ------------------------------------------------------------------------ r1325 | ajapted | 2013-07-28 15:43:51 +1000 (Sun, 28 Jul 2013) | 3 lines Checks: updated missing texture detection to count "" (empty string) as a missing texture. ------------------------------------------------------------------------ r1324 | ajapted | 2013-07-28 15:27:49 +1000 (Sun, 28 Jul 2013) | 2 lines Dead code removal : UI_SideDef::SetTexture() method. ------------------------------------------------------------------------ r1323 | ajapted | 2013-07-28 14:12:49 +1000 (Sun, 28 Jul 2013) | 3 lines Preferences: implemented setting for Aspect ratio in 3D view, supporting a "CUSTOM" choice allowing the user to enter arbitrary values. ------------------------------------------------------------------------ r1322 | ajapted | 2013-07-28 13:58:19 +1000 (Sun, 28 Jul 2013) | 3 lines 3D View: added 'render_aspect_ratio' config variable, and use it when rendering a scene. No preference setting yet.... ------------------------------------------------------------------------ r1321 | ajapted | 2013-07-28 13:56:49 +1000 (Sun, 28 Jul 2013) | 2 lines Fixed recent bug of highlighting map stuff when 3D view is active. ------------------------------------------------------------------------ r1320 | ajapted | 2013-07-27 21:06:44 +1000 (Sat, 27 Jul 2013) | 3 lines Render3D: moved code around, namely UpdateScreen() method of 'view' and draw(), BlitLores() and BlitHires() methods in UI_Render3D class. ------------------------------------------------------------------------ r1319 | ajapted | 2013-07-27 17:41:55 +1000 (Sat, 27 Jul 2013) | 2 lines Adjusting offsets: apply the offsets when mouse button is released. ------------------------------------------------------------------------ r1318 | ajapted | 2013-07-27 17:29:21 +1000 (Sat, 27 Jul 2013) | 6 lines More work on adjusting X/Y offsets via the mouse. Implemented the logic to save/change/restore the current offsets in the renderer (the real change only occurs when the user releases the button -- NYI). It does NOT pick the linedef/sidedef properly yet.... ------------------------------------------------------------------------ r1317 | ajapted | 2013-07-26 22:23:11 +1000 (Fri, 26 Jul 2013) | 4 lines 1. added Editor_ClearAction() and Editor_SetAction() functions 2. re-implemented RMB map scrolling using the action system 3. began implementation of sidedef adjustment via MMB ------------------------------------------------------------------------ r1316 | ajapted | 2013-07-26 11:08:17 +1000 (Fri, 26 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1315 | ajapted | 2013-07-26 11:07:54 +1000 (Fri, 26 Jul 2013) | 2 lines CHANGELOG : yet another rejig. ------------------------------------------------------------------------ r1314 | ajapted | 2013-07-26 11:01:26 +1000 (Fri, 26 Jul 2013) | 4 lines Preferences: disabled the "maximize on startup" option. It is planned to replace it in a future release with code to remember the window position and maximized state. ------------------------------------------------------------------------ r1313 | ajapted | 2013-07-25 20:44:14 +1000 (Thu, 25 Jul 2013) | 3 lines Menu: rewrote code to populate the "Recent Files" sub-menu, using same basic method as for "Given Files" (recreating the Fl_Menu_Item array). ------------------------------------------------------------------------ r1312 | ajapted | 2013-07-25 20:30:26 +1000 (Thu, 25 Jul 2013) | 6 lines Menu: worked on reimplementing the way the "Given Files" and "Recent Files" sub-menus are populated, since previous way did not work under MacOS X. Instead of fiddling with the menu bar _after_ creating it, we fiddle with arrays of raw Fl_Menu_Items _before_ creating it. ------------------------------------------------------------------------ r1311 | ajapted | 2013-07-25 18:52:38 +1000 (Thu, 25 Jul 2013) | 12 lines 1. removed unused 'move_speed', 'extra_zoom' fields from Editor_State_t 2. added 'edit.action' field and a set of ACT_XXXXX enumerated values which will bring some sanity to the handling of temporal actions like dragging objects, drawing a sel box, scrolling the map, etc... 3. handle the META-fier command using the 'edit.action' mechanism 4. fixed bug with META-fying logic where an unrecogized META-fied key would be sent on to other widgets, even coming back to be handled as a normal key instead of being ignored. ------------------------------------------------------------------------ r1310 | ajapted | 2013-07-25 13:53:12 +1000 (Thu, 25 Jul 2013) | 2 lines M_ParseEurekaLump: use DLG_Confirm() instead of fl_choice. ------------------------------------------------------------------------ r1309 | ajapted | 2013-07-25 13:52:17 +1000 (Thu, 25 Jul 2013) | 3 lines Don't quit the program when the user cancels loading a wad during parsing of the EUREKA lump. ------------------------------------------------------------------------ r1308 | ajapted | 2013-07-25 13:37:56 +1000 (Thu, 25 Jul 2013) | 5 lines Preferences / Keys: renamed last button to "Reset Defaults" and _always_ show the confirmation dialog, since it erases ALL the user's changes. Code-wise: use DLG_Confirm() instead of fl_choice() there. ------------------------------------------------------------------------ r1307 | ajapted | 2013-07-25 13:18:51 +1000 (Thu, 25 Jul 2013) | 6 lines Fixed "venetian blind" issue when drawing large dots for the grid. The real problem is with FLTK and how it clips non-filled rectangles. To workaround the FLTK bug, use filled rectangles instead -- it might even be faster. ------------------------------------------------------------------------ r1306 | ajapted | 2013-07-25 13:08:23 +1000 (Thu, 25 Jul 2013) | 2 lines Edit / Move objects: implemented 'Z' delta for sectors. ------------------------------------------------------------------------ r1305 | ajapted | 2013-07-24 23:05:57 +1000 (Wed, 24 Jul 2013) | 2 lines Tweaked the single-line title + copyright message. ------------------------------------------------------------------------ r1304 | ajapted | 2013-07-24 22:35:40 +1000 (Wed, 24 Jul 2013) | 3 lines Dead code removal : MakeDoorFromSector and MakeLiftFromSector. (that functionality may return one day, in the form of a script). ------------------------------------------------------------------------ r1303 | ajapted | 2013-07-24 22:31:04 +1000 (Wed, 24 Jul 2013) | 2 lines Dead code removal : bv_vertices_of_xxx and linedefs_of_sector(s). ------------------------------------------------------------------------ r1302 | ajapted | 2013-07-24 22:27:18 +1000 (Wed, 24 Jul 2013) | 2 lines Dead code removal : Superimposed_ld class. ------------------------------------------------------------------------ r1301 | printz | 2013-07-24 19:22:04 +1000 (Wed, 24 Jul 2013) | 4 lines osx: * Updated Xcode project to Makefile's new specifications * Updated the info plist to the current version * Updated the icns file to the new logo. File is a bit too large now, especially after I used a free tool called "Retina Icon Binder". Thus the total package size is even bigger than the previous OSX Eureka release, even if now I merely linked FLTK statically. Might be the redundant lower-scale icons adding to the size. I need a better ICNS tool that can safely delete the smaller icons. ------------------------------------------------------------------------ r1300 | ajapted | 2013-07-23 19:32:51 +1000 (Tue, 23 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1299 | ajapted | 2013-07-23 19:22:14 +1000 (Tue, 23 Jul 2013) | 2 lines M_WriteEurekaLump : it handles the BeginWrite/EndWrite itself now. ------------------------------------------------------------------------ r1298 | ajapted | 2013-07-23 19:21:18 +1000 (Tue, 23 Jul 2013) | 3 lines Wad code: fixed potential issue with 'insert_point' handling which was probably responsible for the rare level-lumps-in-wrong-order problem. ------------------------------------------------------------------------ r1297 | ajapted | 2013-07-23 16:20:47 +1000 (Tue, 23 Jul 2013) | 3 lines File / Test map: if changes have been made, ask user if they want to save the map and build the nodes. ------------------------------------------------------------------------ r1296 | ajapted | 2013-07-23 16:09:50 +1000 (Tue, 23 Jul 2013) | 2 lines Tweaks. ------------------------------------------------------------------------ r1295 | ajapted | 2013-07-23 16:06:33 +1000 (Tue, 23 Jul 2013) | 2 lines FatalError: replace single newlines with spaces for DLG_ShowError(). ------------------------------------------------------------------------ r1294 | ajapted | 2013-07-23 14:59:54 +1000 (Tue, 23 Jul 2013) | 5 lines Dialogs: added keyboard shortcuts (via '&') for all buttons except Cancel. We don't do Cancel since "Create" button (from File / New Map) would conflict, plus the ESCAPE key already serves that function. ------------------------------------------------------------------------ r1293 | ajapted | 2013-07-23 14:44:30 +1000 (Tue, 23 Jul 2013) | 3 lines Wad code: no need to LogPrintf() updates to the master directory or when reading/writing a directory from a wad -- they are now debug messages. ------------------------------------------------------------------------ r1292 | ajapted | 2013-07-23 14:43:03 +1000 (Tue, 23 Jul 2013) | 3 lines File / Build nodes: better handle the case when there is no current pwad, but the user has made changes (e.g. an edited IWAD map, or a fresh map). ------------------------------------------------------------------------ r1291 | ajapted | 2013-07-23 14:35:28 +1000 (Tue, 23 Jul 2013) | 3 lines Dialogs: use UI_Escapable_Window so that dialogs can be dismissed with the ESCAPE key. ------------------------------------------------------------------------ r1290 | ajapted | 2013-07-23 14:31:56 +1000 (Tue, 23 Jul 2013) | 4 lines File / Build nodes: when the map has unsaved changes, we now ask the user whether they want to save the map and then build the nodes. (Previously it was just a notification dialog.) ------------------------------------------------------------------------ r1289 | ajapted | 2013-07-23 14:28:15 +1000 (Tue, 23 Jul 2013) | 10 lines Fixed bug causing a FatalError() when editing a pwad, creating a new map which is fresh (does not replace any existing map), and then attempting to build the nodes. Since the new map was not saved, Eureka was unable to re-load the map from the node-enhanced wad. Hence creating a new map (CTRL-N) always sets the "Made Changes" flag. This commit also makes CMD_SaveMap() and CMD_ExportMap() return a bool indicating success or failure. ------------------------------------------------------------------------ r1288 | ajapted | 2013-07-23 14:01:08 +1000 (Tue, 23 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1287 | ajapted | 2013-07-23 13:55:44 +1000 (Tue, 23 Jul 2013) | 3 lines Show an '!' symbol in the window title when a new map would replace an existing map in the current wad. ------------------------------------------------------------------------ r1286 | ajapted | 2013-07-23 13:41:28 +1000 (Tue, 23 Jul 2013) | 3 lines File / Save: if a new map would replace (overwrite) an existing map, give the user a third option: "Export" the map. ------------------------------------------------------------------------ r1285 | ajapted | 2013-07-22 22:20:54 +1000 (Mon, 22 Jul 2013) | 3 lines Improved look of Preferences and Log-viewer windows when not using the "Bright" color scheme -- the background at the bottom was too dark. ------------------------------------------------------------------------ r1284 | ajapted | 2013-07-22 21:38:47 +1000 (Mon, 22 Jul 2013) | 3 lines Dialogs: copy the fl_ask (etc) behavior and make the window's position dependent on where the mouse pointer is. ------------------------------------------------------------------------ r1283 | ajapted | 2013-07-22 21:15:40 +1000 (Mon, 22 Jul 2013) | 5 lines Dialogs: 1. support the 'icon_type' to make different colored icons 2. ensure the left-most button gets the focus 3. fixed navigation problem (LEFT and RIGHT cursor keys) ------------------------------------------------------------------------ r1282 | ajapted | 2013-07-22 20:54:20 +1000 (Mon, 22 Jul 2013) | 4 lines Dialogs: worked to parse and create the buttons for DLG_Confirm(), and properly handle the var-args for DLG_Notify() and DLG_Confirm(), plus a few other tweaks. ------------------------------------------------------------------------ r1281 | ajapted | 2013-07-22 20:19:31 +1000 (Mon, 22 Jul 2013) | 5 lines 1. Thing checker now detects if too many DM starts are present 2. moved the DOOM_PLAYER_HEIGHT and DOOM_MIN/MAX_DEATHMATCH_STARTS to be fields of the game_info_t structure. ------------------------------------------------------------------------ r1280 | ajapted | 2013-07-22 20:05:23 +1000 (Mon, 22 Jul 2013) | 3 lines Removed unused confirm_t type, and the OPT_CONFIRM stuff in the config loading and saving code. ------------------------------------------------------------------------ r1279 | ajapted | 2013-07-22 20:01:49 +1000 (Mon, 22 Jul 2013) | 2 lines Tidied up main.h ------------------------------------------------------------------------ r1278 | ajapted | 2013-07-22 16:40:24 +1000 (Mon, 22 Jul 2013) | 2 lines Removed code file: m_dialog.cc ------------------------------------------------------------------------ r1277 | ajapted | 2013-07-22 16:36:37 +1000 (Mon, 22 Jul 2013) | 5 lines Dialogs: renamed Confirm() --> DLG_Confirm(), and changed the parameters to take button names and use var-arg message. Note that the new DLG_Confirm() is not implemented yet. ------------------------------------------------------------------------ r1276 | ajapted | 2013-07-22 16:12:32 +1000 (Mon, 22 Jul 2013) | 2 lines Removed header files: m_dialog.h and ui_dialog.h ------------------------------------------------------------------------ r1275 | ajapted | 2013-07-22 16:05:23 +1000 (Mon, 22 Jul 2013) | 3 lines Began work on better dialog boxes. This commit mainly renames 'Notify' function to 'DLG_Notify' and simplifies its parameters. ------------------------------------------------------------------------ r1274 | ajapted | 2013-07-22 15:17:27 +1000 (Mon, 22 Jul 2013) | 2 lines Dead code removal : NotImplemented() and Confirm2() functions. ------------------------------------------------------------------------ r1273 | ajapted | 2013-07-21 16:02:13 +1000 (Sun, 21 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1272 | ajapted | 2013-07-21 16:01:15 +1000 (Sun, 21 Jul 2013) | 2 lines Improved scroll-bar colors. ------------------------------------------------------------------------ r1271 | ajapted | 2013-07-21 14:42:44 +1000 (Sun, 21 Jul 2013) | 2 lines Check / textures: allow "-" on uppers when between two sky ceilings. ------------------------------------------------------------------------ r1270 | ajapted | 2013-07-21 14:29:51 +1000 (Sun, 21 Jul 2013) | 2 lines CHANGELOG: minor rejig. ------------------------------------------------------------------------ r1269 | ajapted | 2013-07-21 14:23:17 +1000 (Sun, 21 Jul 2013) | 2 lines Check / textures: wrote logic to detect and fix missing textures. ------------------------------------------------------------------------ r1268 | ajapted | 2013-07-21 14:00:38 +1000 (Sun, 21 Jul 2013) | 3 lines Check / things: fixed "Remove" button for things in void to not close the thing check dialog. ------------------------------------------------------------------------ r1267 | ajapted | 2013-07-21 13:59:29 +1000 (Sun, 21 Jul 2013) | 3 lines Check / textures: implemented "Fix" buttons for unknown textures and unknown flats. ------------------------------------------------------------------------ r1266 | ajapted | 2013-07-21 13:43:59 +1000 (Sun, 21 Jul 2013) | 2 lines HERETIC: changed default floor to FLOOR00 (was FLOOR01). ------------------------------------------------------------------------ r1265 | ajapted | 2013-07-21 13:07:42 +1000 (Sun, 21 Jul 2013) | 2 lines Ports / BOOM: added 'v' flag to point push/pull things. ------------------------------------------------------------------------ r1264 | ajapted | 2013-07-21 13:05:32 +1000 (Sun, 21 Jul 2013) | 3 lines Check / things: improved VOID testing to ignore things with the 'v' flag (such as Heretic's sound emitters). ------------------------------------------------------------------------ r1263 | ajapted | 2013-07-21 13:04:31 +1000 (Sun, 21 Jul 2013) | 3 lines Game defs: implemented new 'v' thing flag for things which may exist in the VOID, and use this flag for Heretic's sound emitters. ------------------------------------------------------------------------ r1262 | ajapted | 2013-07-21 12:39:40 +1000 (Sun, 21 Jul 2013) | 5 lines Check / things: 1. implemented 'Remove' button for unknown things 2. more accurate testing for "in the void" things 3. added 'Remove' button for things in the void ------------------------------------------------------------------------ r1261 | ajapted | 2013-07-21 12:20:05 +1000 (Sun, 21 Jul 2013) | 2 lines foo ------------------------------------------------------------------------ r1260 | ajapted | 2013-07-21 12:13:33 +1000 (Sun, 21 Jul 2013) | 6 lines Check / things: 1. implemented "Log" button for unknown things, which dumps all the unknown id numbers to the log file (and opens the log viewer) 2. moved the unknown thing results to the top. ------------------------------------------------------------------------ r1259 | ajapted | 2013-07-20 23:22:20 +1000 (Sat, 20 Jul 2013) | 4 lines Check / textures: implemented a "Log" button for unknown flats and textures, which prints the names (and usage count) into the log file, then opens up the log viewer. ------------------------------------------------------------------------ r1258 | ajapted | 2013-07-20 22:59:48 +1000 (Sat, 20 Jul 2013) | 3 lines Log viewer: have a function to open it, which now jumps to the end (i.e. ensures the last line is visible). ------------------------------------------------------------------------ r1257 | ajapted | 2013-07-20 22:25:26 +1000 (Sat, 20 Jul 2013) | 3 lines Check / textures: implemented detecting unknown flats and textures, and ability to show the sectors / lines (in the ERROR mode). ------------------------------------------------------------------------ r1256 | ajapted | 2013-07-20 22:01:19 +1000 (Sat, 20 Jul 2013) | 2 lines Added W_TextureExists() and W_FlatExists() functions. ------------------------------------------------------------------------ r1255 | ajapted | 2013-07-20 21:49:28 +1000 (Sat, 20 Jul 2013) | 2 lines Checks: began work on Texture checking functions.... ------------------------------------------------------------------------ r1254 | ajapted | 2013-07-20 21:47:14 +1000 (Sat, 20 Jul 2013) | 3 lines Check / things: made unknown things a serious error, since vanilla DOOM will produce a fatal error for them. ------------------------------------------------------------------------ r1253 | ajapted | 2013-07-20 17:51:25 +1000 (Sat, 20 Jul 2013) | 2 lines TODO: updated. ------------------------------------------------------------------------ r1252 | ajapted | 2013-07-20 17:38:10 +1000 (Sat, 20 Jul 2013) | 6 lines Clear the ERROR mode when necessary, such as when changing the edit mode or trying to select a new object, or certain operations that leave a certain object selected. For the Quantize command, we now _set_ the ERROR mode. ------------------------------------------------------------------------ r1251 | ajapted | 2013-07-20 14:33:28 +1000 (Sat, 20 Jul 2013) | 3 lines Preferences: reserve an area in 'Other' tab for "3D Preview Options". Nothing is there yet.... ------------------------------------------------------------------------ r1250 | ajapted | 2013-07-20 14:24:50 +1000 (Sat, 20 Jul 2013) | 4 lines Fixed assertion when the 'FlipMap' command was used and the current level name cannot be found in the current wad (e.g. the IWAD was changed from DOOM 2 --> DOOM 1). ------------------------------------------------------------------------ r1249 | ajapted | 2013-07-20 14:17:15 +1000 (Sat, 20 Jul 2013) | 2 lines DOOM 1: categorized the DOOM1-specific textures. ------------------------------------------------------------------------ r1248 | ajapted | 2013-07-20 14:06:27 +1000 (Sat, 20 Jul 2013) | 2 lines DOOM: moved the DOOM2-only textures out of common/doom_tex.ugh ------------------------------------------------------------------------ r1247 | ajapted | 2013-07-20 13:41:59 +1000 (Sat, 20 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1246 | ajapted | 2013-07-20 13:31:55 +1000 (Sat, 20 Jul 2013) | 4 lines Map view: better drawing of selected sectors, draw knobbly lines where the knobs point inside the sectors, and skip lines that exist between two selected sectors. ------------------------------------------------------------------------ r1245 | ajapted | 2013-07-20 11:36:26 +1000 (Sat, 20 Jul 2013) | 5 lines Map view: 1. smaller surrounding box for highlighted things 2. improved arrow drawing for large highlighted things 3. improved arrow drawing for highlighted linedefs ------------------------------------------------------------------------ r1244 | ajapted | 2013-07-19 20:36:21 +1000 (Fri, 19 Jul 2013) | 2 lines HERETIC: apply same fix for exit-level linetypes. ------------------------------------------------------------------------ r1243 | ajapted | 2013-07-19 20:28:36 +1000 (Fri, 19 Jul 2013) | 3 lines DOOM: updated exit specials to use "s1" instead of "S1", to prevent those lines showing up in the "linedefs missing a needed tag" check. ------------------------------------------------------------------------ r1242 | ajapted | 2013-07-19 20:24:54 +1000 (Fri, 19 Jul 2013) | 4 lines Check / tags: added new test for linedefs missing a needed tag. Needs some game definition changes to work properly, especially the exit level types to use "s1" instead of "S1". ------------------------------------------------------------------------ r1241 | ajapted | 2013-07-19 20:00:25 +1000 (Fri, 19 Jul 2013) | 3 lines Check / tags: finished GUI parts of detecting unmatched tagged stuff. Also moved the Lowest/Highest values to occupy a single line. ------------------------------------------------------------------------ r1240 | ajapted | 2013-07-19 19:15:11 +1000 (Fri, 19 Jul 2013) | 3 lines Check / tags: worked on detecting sectors with no tagged linedef and vice versa. This commit has the detection logic. ------------------------------------------------------------------------ r1239 | ajapted | 2013-07-19 15:59:19 +1000 (Fri, 19 Jul 2013) | 2 lines Check / tags: fixed the "all_mode" handling. ------------------------------------------------------------------------ r1238 | ajapted | 2013-07-19 15:56:48 +1000 (Fri, 19 Jul 2013) | 2 lines Checks.txt : a few more tag-testing ideas... ------------------------------------------------------------------------ r1237 | ajapted | 2013-07-19 15:52:49 +1000 (Fri, 19 Jul 2013) | 3 lines Check / things: implemented ThingStuckInWall() -- finishing the support for stuck thing detection. ------------------------------------------------------------------------ r1236 | ajapted | 2013-07-19 15:51:55 +1000 (Fri, 19 Jul 2013) | 2 lines Renamed LineCrossesBox() --> LineTouchesBox(), and removed some unused code. ------------------------------------------------------------------------ r1235 | ajapted | 2013-07-19 14:29:09 +1000 (Fri, 19 Jul 2013) | 5 lines Check / things: for monsters, allow a small (8 unit) leeway to overlap a solid thing before considering it as stuck. That's because the monster movement code allows a monster to move a certain distance from its starting position. ------------------------------------------------------------------------ r1234 | ajapted | 2013-07-19 13:53:02 +1000 (Fri, 19 Jul 2013) | 2 lines Check / things: implemented detecting actors stuck in solid things. ------------------------------------------------------------------------ r1233 | ajapted | 2013-07-19 13:09:33 +1000 (Fri, 19 Jul 2013) | 3 lines Check / things: began work on detecting players and monsters stuck in walls or other things. ------------------------------------------------------------------------ r1232 | ajapted | 2013-07-19 11:56:33 +1000 (Fri, 19 Jul 2013) | 3 lines Checks: removed the previous checking code -- it was not used as-is, but some of that code or algorithms were used in the new functions. ------------------------------------------------------------------------ r1231 | ajapted | 2013-07-19 11:53:40 +1000 (Fri, 19 Jul 2013) | 2 lines Checks: just moved code around. ------------------------------------------------------------------------ r1230 | ajapted | 2013-07-19 11:37:36 +1000 (Fri, 19 Jul 2013) | 2 lines Port definitions: updated with 'n' (non-blocking) thing flag. ------------------------------------------------------------------------ r1229 | ajapted | 2013-07-19 11:35:31 +1000 (Fri, 19 Jul 2013) | 2 lines HACX: updated thing defs with new 'n' (non-blocking) flag. ------------------------------------------------------------------------ r1228 | ajapted | 2013-07-19 11:31:05 +1000 (Fri, 19 Jul 2013) | 3 lines HERETIC: updated things, added missing 'l' (lit) and 'c' (ceiling) flags as well as the new 'n' (non-blocking) flag. ------------------------------------------------------------------------ r1227 | ajapted | 2013-07-18 22:47:55 +1000 (Thu, 18 Jul 2013) | 3 lines Game defs: updated DOOM 1 and 2 definitions to add the 'n' non-solid flag to all the things which need it. ------------------------------------------------------------------------ r1226 | ajapted | 2013-07-18 22:45:42 +1000 (Thu, 18 Jul 2013) | 3 lines Game defs: support a new thing flag 'n' : Non-Solid. This will be used later for detecting things stuck in walls or other things. ------------------------------------------------------------------------ r1225 | ajapted | 2013-07-18 22:19:24 +1000 (Thu, 18 Jul 2013) | 2 lines TODO and CHANGELOG update. ------------------------------------------------------------------------ r1224 | ajapted | 2013-07-18 22:15:06 +1000 (Thu, 18 Jul 2013) | 3 lines Log viewer: finished the ability to "Save" the full logs to a file. The grunt-work is done by new LogSaveTo(FILE *) function. ------------------------------------------------------------------------ r1223 | ajapted | 2013-07-18 21:51:41 +1000 (Thu, 18 Jul 2013) | 5 lines Log viewer: 1. implemented copying the selected lines to the clipboard 2. made CTRL-C be a shortcut for the "Copy" button 3. renamed the "OK" button to "Close" ------------------------------------------------------------------------ r1222 | ajapted | 2013-07-18 21:01:04 +1000 (Thu, 18 Jul 2013) | 3 lines Opposite finder: when building the binary trees, skip purely horizontal lines in the Y tree, similarly purely vertical lines in the X tree. ------------------------------------------------------------------------ r1221 | ajapted | 2013-07-18 20:45:30 +1000 (Thu, 18 Jul 2013) | 3 lines Log viewer: added logic to activate the "Copy" button when the user has selected two or more lines -- otherwise it stays deactivated. ------------------------------------------------------------------------ r1220 | ajapted | 2013-07-18 19:57:30 +1000 (Thu, 18 Jul 2013) | 6 lines Log viewer: 1. partial work to implement "Save" button 2. use a Fl_Multi_Browser, so user can select areas to copy/save 3. added a "Copy" button to bottom area (not yet functional) 4. in bottom area, place resizable gap between "OK" and other buttons ------------------------------------------------------------------------ r1219 | ajapted | 2013-07-18 19:08:16 +1000 (Thu, 18 Jul 2013) | 2 lines Log viewer: implemented the "OK" button (to close) and "Clear" button. ------------------------------------------------------------------------ r1218 | ajapted | 2013-07-18 18:55:33 +1000 (Thu, 18 Jul 2013) | 3 lines Log viewer: began work improving it, with a button area at the bottom which will contain three buttons: "Save", "Clear" and "OK". ------------------------------------------------------------------------ r1217 | ajapted | 2013-07-18 17:21:19 +1000 (Thu, 18 Jul 2013) | 3 lines Opposite finder: fixed some bugs, and actually use it to speed up the sector mismatch test. The new logic is roughly 4-5 times faster. ------------------------------------------------------------------------ r1216 | ajapted | 2013-07-18 16:36:24 +1000 (Thu, 18 Jul 2013) | 2 lines Opposite finder: implemented the binary-tree testing logic. ------------------------------------------------------------------------ r1215 | ajapted | 2013-07-18 16:20:35 +1000 (Thu, 18 Jul 2013) | 3 lines Opposite finder: in fastopp nodes, store linedefs as integers rather than pointers. ------------------------------------------------------------------------ r1214 | ajapted | 2013-07-18 16:16:09 +1000 (Thu, 18 Jul 2013) | 3 lines Opposite finder: moved state into a 'opp_test_state_t' structure, and also moved the code to handle a single linedef there. ------------------------------------------------------------------------ r1213 | ajapted | 2013-07-18 15:58:10 +1000 (Thu, 18 Jul 2013) | 7 lines Began work on a faster version of OppositeLineDef() and OppositeSector(), mainly for the sector mismatch test. So far: written the logic for creating a quadtree-like structure and storing linedefs in it. Unlike a quadtree, this is one-dimensional and there are two of them (for X and Y dimensions). ------------------------------------------------------------------------ r1212 | ajapted | 2013-07-18 15:20:36 +1000 (Thu, 18 Jul 2013) | 3 lines Checks / linedefs: added test for linedefs with wrong 2S (TwoSided) flag, as well as actions to show and fix them. ------------------------------------------------------------------------ r1211 | ajapted | 2013-07-18 15:10:49 +1000 (Thu, 18 Jul 2013) | 3 lines Checks / linedefs: implemented test for one-sided lines without blocking flag, and actions to show and fix them. ------------------------------------------------------------------------ r1210 | ajapted | 2013-07-18 13:46:32 +1000 (Thu, 18 Jul 2013) | 3 lines Checks: use UI_Check_base as the base for remaining dialog classes, namely UI_Check_Sectors, UI_Check_Things and UI_Check_Tags. ------------------------------------------------------------------------ r1209 | ajapted | 2013-07-16 22:30:09 +1000 (Tue, 16 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1208 | ajapted | 2013-07-16 22:29:18 +1000 (Tue, 16 Jul 2013) | 3 lines Checks: converted UI_Check_Vertices and UI_Check_LineDefs classes to use the new base class. ------------------------------------------------------------------------ r1207 | ajapted | 2013-07-16 22:19:21 +1000 (Tue, 16 Jul 2013) | 3 lines Checks: created a base class for all the dialogs : UI_Check_base. Nothing uses it yet.... ------------------------------------------------------------------------ r1206 | ajapted | 2013-07-16 21:16:28 +1000 (Tue, 16 Jul 2013) | 7 lines Use UI_Escapable_Window for most other dialogs with a "Cancel" button. Not used for UI_NodeDialog since it has special behavior (first ESC press cancels the build but keeps the window open). Not used with UI_Check_XXX yet, pending a superclass for them. ------------------------------------------------------------------------ r1205 | ajapted | 2013-07-16 21:02:26 +1000 (Tue, 16 Jul 2013) | 3 lines About dialog: subclass from UI_Escapable_Window, simplifying the code e.g. no longer need our own handle() method. ------------------------------------------------------------------------ r1204 | ajapted | 2013-07-16 21:01:08 +1000 (Tue, 16 Jul 2013) | 2 lines Added UI_Escapable_Window class -- a subclass of Fl_Double_Window. ------------------------------------------------------------------------ r1203 | ajapted | 2013-07-16 20:38:33 +1000 (Tue, 16 Jul 2013) | 2 lines Code: re-whitespaced ui_about.cc/h to be consistent. ------------------------------------------------------------------------ r1202 | ajapted | 2013-07-16 20:11:27 +1000 (Tue, 16 Jul 2013) | 2 lines misc/Checks.txt : more twiddling... ------------------------------------------------------------------------ r1201 | ajapted | 2013-07-16 20:10:56 +1000 (Tue, 16 Jul 2013) | 2 lines Made some Beep() error messages more consistent. ------------------------------------------------------------------------ r1200 | ajapted | 2013-07-16 19:52:43 +1000 (Tue, 16 Jul 2013) | 2 lines Checks: moved code around, namely TAG stuff --> e_checks2.cc ------------------------------------------------------------------------ r1199 | ajapted | 2013-07-16 19:49:37 +1000 (Tue, 16 Jul 2013) | 10 lines Checks: 1. rearranged 'Check' menu, added 'Major stuff' item which does all the checks but ignores minor problems. 2. made the 'Check / ALL' menu item perform the Texture and Tags tests too (not just the Vert/Lin/Sec/Thing tests). 3. Code-wise, pass 'min_severity' to each CHECK_xxx function, instead of 'all_mode' boolean. ------------------------------------------------------------------------ r1198 | ajapted | 2013-07-16 19:06:16 +1000 (Tue, 16 Jul 2013) | 2 lines Check / linedefs: implemented test for criss-crossing linedefs. ------------------------------------------------------------------------ r1197 | ajapted | 2013-07-16 18:08:59 +1000 (Tue, 16 Jul 2013) | 2 lines Check / linedefs: moved code around, added linedef_minx_CMP_pred. ------------------------------------------------------------------------ r1196 | ajapted | 2013-07-16 17:10:27 +1000 (Tue, 16 Jul 2013) | 6 lines Checks: for tests which have a "Show" button and a map-modifying button, place the "Show" button on the left and other button on the right. That's because the first button is navigated to by FLTK, and hence it should ideally be a non-destructive action. ------------------------------------------------------------------------ r1195 | ajapted | 2013-07-16 17:06:58 +1000 (Tue, 16 Jul 2013) | 2 lines Check / linedefs: added 'Remove' feature for overlapping linedefs. ------------------------------------------------------------------------ r1194 | ajapted | 2013-07-16 16:46:27 +1000 (Tue, 16 Jul 2013) | 2 lines Checks: layout tweak. ------------------------------------------------------------------------ r1193 | ajapted | 2013-07-16 16:43:27 +1000 (Tue, 16 Jul 2013) | 2 lines Check / linedefs: detection logic for directly overlapping linedefs. ------------------------------------------------------------------------ r1192 | ajapted | 2013-07-16 14:53:14 +1000 (Tue, 16 Jul 2013) | 2 lines Check / linedefs: added test for linedefs without a right side. ------------------------------------------------------------------------ r1191 | ajapted | 2013-07-16 14:43:41 +1000 (Tue, 16 Jul 2013) | 3 lines Check / linedefs: implemented zero-length linedef test, with a button to show them (in vertex mode) and a button to remove them. ------------------------------------------------------------------------ r1190 | ajapted | 2013-07-16 13:58:52 +1000 (Tue, 16 Jul 2013) | 2 lines New code file 'e_checks2.cc' -- it will contain linedef checking code. ------------------------------------------------------------------------ r1189 | ajapted | 2013-07-16 13:38:22 +1000 (Tue, 16 Jul 2013) | 4 lines Check / sectors: re-implemented the mismatched sectors test, based on the existing DEU code. However it is quite slow, O(n^2) with number of linedefs. ------------------------------------------------------------------------ r1188 | ajapted | 2013-07-16 13:04:51 +1000 (Tue, 16 Jul 2013) | 2 lines Removed the now redundant GetOppositeSector() code. ------------------------------------------------------------------------ r1187 | ajapted | 2013-07-16 13:03:32 +1000 (Tue, 16 Jul 2013) | 2 lines Added OppositeSector() function which uses OppositeLineDef(). ------------------------------------------------------------------------ r1186 | ajapted | 2013-07-16 12:45:28 +1000 (Tue, 16 Jul 2013) | 2 lines Check / things: tweaked player start messages. ------------------------------------------------------------------------ r1185 | ajapted | 2013-07-16 12:38:32 +1000 (Tue, 16 Jul 2013) | 2 lines misc/Checks.txt updated. ------------------------------------------------------------------------ r1184 | ajapted | 2013-07-16 12:38:07 +1000 (Tue, 16 Jul 2013) | 5 lines Check / sectors: implemented detection of unclosed sectors (mismatches at vertices), with buttons to show the sectors and show the vertices. Renamed XXX_Highlight --> XXX_Show, and removed a bit of dead code. ------------------------------------------------------------------------ r1183 | ajapted | 2013-07-16 10:59:25 +1000 (Tue, 16 Jul 2013) | 4 lines Key bindings: 1. renamed binding command: AwaitMeta --> MetaKey 2. allow ';' to toggle the await_meta state on and off ------------------------------------------------------------------------ r1182 | ajapted | 2013-07-15 21:50:17 +1000 (Mon, 15 Jul 2013) | 3 lines When loading a level, check for shared sidedefs and if exist ask user whether to unpack them or not. ------------------------------------------------------------------------ r1181 | ajapted | 2013-07-15 21:40:06 +1000 (Mon, 15 Jul 2013) | 2 lines Check / sectors: finished the sidedef unpacking algorithm. ------------------------------------------------------------------------ r1180 | ajapted | 2013-07-15 21:19:04 +1000 (Mon, 15 Jul 2013) | 2 lines Check / sectors: worked on algorithm to unpack sidedefs... ------------------------------------------------------------------------ r1179 | ajapted | 2013-07-15 20:49:59 +1000 (Mon, 15 Jul 2013) | 3 lines Check / sectors: implemented detection of shared sidedefs, and ability to show them in the error mode. To-Do: ability to unpack them. ------------------------------------------------------------------------ r1178 | ajapted | 2013-07-15 20:08:11 +1000 (Mon, 15 Jul 2013) | 4 lines Check / sectors: added test for ceiling < floor height, with two action buttons: "Fix" will set ceiling same as floor, and "Show" to highlight them in the error_mode. ------------------------------------------------------------------------ r1177 | ajapted | 2013-07-15 19:56:46 +1000 (Mon, 15 Jul 2013) | 2 lines Check / sectors: count unused sidedefs, and ability to remove them. ------------------------------------------------------------------------ r1176 | ajapted | 2013-07-15 19:41:24 +1000 (Mon, 15 Jul 2013) | 3 lines Checks: began work on SECTOR checks... So far only have unused count (with button to remove those unused sectors). ------------------------------------------------------------------------ r1175 | ajapted | 2013-07-15 19:40:15 +1000 (Mon, 15 Jul 2013) | 2 lines tweaked Prune message. ------------------------------------------------------------------------ r1174 | ajapted | 2013-07-15 19:26:55 +1000 (Mon, 15 Jul 2013) | 2 lines Checks.txt : updated for current plans. ------------------------------------------------------------------------ r1173 | ajapted | 2013-07-15 19:11:54 +1000 (Mon, 15 Jul 2013) | 3 lines Checks: when highlighting error objects, ensure we change the editor mode when necessary. ------------------------------------------------------------------------ r1172 | ajapted | 2013-07-15 19:01:23 +1000 (Mon, 15 Jul 2013) | 2 lines Checks: tweakage. ------------------------------------------------------------------------ r1171 | ajapted | 2013-07-15 18:53:32 +1000 (Mon, 15 Jul 2013) | 2 lines Checks / things: added detection of things in void-space. ------------------------------------------------------------------------ r1170 | ajapted | 2013-07-15 18:41:25 +1000 (Mon, 15 Jul 2013) | 2 lines Dead code removal : CheckStartingPos() ------------------------------------------------------------------------ r1169 | ajapted | 2013-07-15 18:40:20 +1000 (Mon, 15 Jul 2013) | 2 lines Checks / things: added checks for missing player starts. ------------------------------------------------------------------------ r1168 | ajapted | 2013-07-15 16:59:05 +1000 (Mon, 15 Jul 2013) | 3 lines Checks: when highlighting error objects, use GoToSelection() to ensure the user will see them. ------------------------------------------------------------------------ r1167 | ajapted | 2013-07-15 16:56:07 +1000 (Mon, 15 Jul 2013) | 3 lines Checks: began work on THING checking. So far: can count the number of unknown things, and highlight them in the error mode. ------------------------------------------------------------------------ r1166 | ajapted | 2013-07-15 16:31:55 +1000 (Mon, 15 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1165 | ajapted | 2013-07-15 16:22:19 +1000 (Mon, 15 Jul 2013) | 2 lines Prefs: layout tweaks. ------------------------------------------------------------------------ r1164 | ajapted | 2013-07-15 16:19:22 +1000 (Mon, 15 Jul 2013) | 2 lines Preferences: implemented a 'Default editing mode' setting. ------------------------------------------------------------------------ r1163 | ajapted | 2013-07-15 14:22:11 +1000 (Mon, 15 Jul 2013) | 2 lines UI_Sector and UI_LineDef: use Tags_ApplyNewValue() in tag_callback. ------------------------------------------------------------------------ r1162 | ajapted | 2013-07-15 14:19:28 +1000 (Mon, 15 Jul 2013) | 6 lines Implemented new 'ApplyTag' key-binding command. With the "fresh" param it sets the tags on selected objects to a fresh tag (max + 1), and with the "last" parameter it sets the tag to the last one (maximum). Current bindings are META-F and META-L. ------------------------------------------------------------------------ r1161 | ajapted | 2013-07-15 14:08:52 +1000 (Mon, 15 Jul 2013) | 2 lines Main loop: disable error_mode whenever selection becomes empty. ------------------------------------------------------------------------ r1160 | ajapted | 2013-07-15 13:35:16 +1000 (Mon, 15 Jul 2013) | 3 lines Checks / tags: added feature to assign a fresh tag value to the current selected linedefs or sectors. ------------------------------------------------------------------------ r1159 | ajapted | 2013-07-15 13:18:26 +1000 (Mon, 15 Jul 2013) | 3 lines Checks: implemented "TAG" dialog, which for now just shows the lowest and highest used tag numbers. ------------------------------------------------------------------------ r1158 | ajapted | 2013-07-15 13:02:04 +1000 (Mon, 15 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1157 | ajapted | 2013-07-15 12:27:08 +1000 (Mon, 15 Jul 2013) | 3 lines Save message : added "NO NODES" so the user knows that nodes have not been built. ------------------------------------------------------------------------ r1156 | ajapted | 2013-07-15 11:58:03 +1000 (Mon, 15 Jul 2013) | 2 lines Minor rename: edit.obj_type --> edit.mode ------------------------------------------------------------------------ r1155 | ajapted | 2013-07-14 22:57:21 +1000 (Sun, 14 Jul 2013) | 3 lines Check / vertices: implemented ability to merge overlapping vertices, or highlight them in the error selection [that part is not complete]. ------------------------------------------------------------------------ r1154 | ajapted | 2013-07-14 22:19:41 +1000 (Sun, 14 Jul 2013) | 4 lines Checks / vertices: 1. fixed some bugs in Reset() method [one was quite nasty] 2. implemented Vertex_RemoveUnused() function ------------------------------------------------------------------------ r1153 | ajapted | 2013-07-14 22:05:20 +1000 (Sun, 14 Jul 2013) | 3 lines Checks / vertices: implemented Vertex_FindOverlaps() and FindUnused(), fixed AddLine() to copy the label, and tweaked a few things. ------------------------------------------------------------------------ r1152 | ajapted | 2013-07-14 21:29:21 +1000 (Sun, 14 Jul 2013) | 3 lines Checks / vertices: worked on performing proper tests, and improved the size and layout of the dialog window. ------------------------------------------------------------------------ r1151 | ajapted | 2013-07-14 20:32:35 +1000 (Sun, 14 Jul 2013) | 11 lines Check: 1. use an enumeration for the result of CHECK_xxx functions 2. support CHECK_xxx functions returning a value to indicate skipping the rest of the checks in CHECK_All() 3. ability to Reset() the UI dialog, so checks can be re-performed on an existing dialog window 4. fixed not passing 'this' to the callback functions. ------------------------------------------------------------------------ r1150 | ajapted | 2013-07-14 19:57:20 +1000 (Sun, 14 Jul 2013) | 6 lines Checks: 1. the CHECK_xxx functions now return a "severity" value (an int) 2. keep track of 'worst_severity' in the UI_CheckXXX classes 3. fixed logic in CHECK_All() -- it needs to keep going when one of the CHECK_xxx() functions returns a non-zero severity ------------------------------------------------------------------------ r1149 | ajapted | 2013-07-14 19:40:29 +1000 (Sun, 14 Jul 2013) | 3 lines Checks: implemented an 'AddLine' method for the Vertex dialog, which supports upto three buttons for actions to take. ------------------------------------------------------------------------ r1148 | ajapted | 2013-07-14 19:03:33 +1000 (Sun, 14 Jul 2013) | 2 lines Check Menu: fixed shortcuts. ------------------------------------------------------------------------ r1147 | ajapted | 2013-07-14 18:57:38 +1000 (Sun, 14 Jul 2013) | 4 lines Checks: 1. added a bare-bones UI_CheckVertices dialog class 2. removed some obsolete code ------------------------------------------------------------------------ r1146 | ajapted | 2013-07-14 18:55:03 +1000 (Sun, 14 Jul 2013) | 3 lines Preferences: fixed potential problem with UI_EditKey and the close button of the window manager. ------------------------------------------------------------------------ r1145 | ajapted | 2013-07-14 18:20:19 +1000 (Sun, 14 Jul 2013) | 6 lines Began work on map-checking functions. Firstly have a 'Check' menu with various choices (like "Vertices", "Sectors", etc). These are routed through a new 'CheckMap' binding command whose first parameter is the area to check. Some special keywords are "current" for the current enditing mode, and "all" to check all the major stuff. ------------------------------------------------------------------------ r1144 | ajapted | 2013-07-14 18:10:59 +1000 (Sun, 14 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1143 | ajapted | 2013-07-14 15:20:28 +1000 (Sun, 14 Jul 2013) | 3 lines VM: disabled the testing stuff in main.cc -- all the scripting stuff is very much on the back-burner now.... ------------------------------------------------------------------------ r1142 | ajapted | 2013-07-14 15:15:08 +1000 (Sun, 14 Jul 2013) | 4 lines The ';' key waits for the next key, and makes it META (as if it had been pressed with the META modifier key). This could be handy on computers with limited keyboards -- especially laptops. ------------------------------------------------------------------------ r1141 | ajapted | 2013-07-14 14:42:43 +1000 (Sun, 14 Jul 2013) | 2 lines Prefs: tweak. ------------------------------------------------------------------------ r1140 | ajapted | 2013-07-14 14:36:15 +1000 (Sun, 14 Jul 2013) | 4 lines Config file: 1. handle empty strings, write and parse as '' (two single quotes) 2. moved the glbsp_xxx entries down ------------------------------------------------------------------------ r1139 | ajapted | 2013-07-14 14:23:06 +1000 (Sun, 14 Jul 2013) | 2 lines Game defs: removed obsolete 'default_port' command. ------------------------------------------------------------------------ r1138 | ajapted | 2013-07-14 14:11:07 +1000 (Sun, 14 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1137 | ajapted | 2013-07-14 14:07:40 +1000 (Sun, 14 Jul 2013) | 6 lines Preferences: added 'Default Port' setting to the Editing tab. This affects general startup too, as previously the default port was a game definition setting. Hence added DeterminePort() whose main job is to ensure the default_port value is valid [and reset it if not]. ------------------------------------------------------------------------ r1136 | ajapted | 2013-07-14 14:03:11 +1000 (Sun, 14 Jul 2013) | 2 lines Game (UGH) parser: disabled the 'default_port' command. ------------------------------------------------------------------------ r1135 | ajapted | 2013-07-14 13:24:22 +1000 (Sun, 14 Jul 2013) | 3 lines the X11 UI_Window::Maximize() implementation now does a short delay, to allow the X message to get to the X server and back. ------------------------------------------------------------------------ r1134 | ajapted | 2013-07-14 13:11:41 +1000 (Sun, 14 Jul 2013) | 2 lines Utils: added TimeDelay() function. ------------------------------------------------------------------------ r1133 | ajapted | 2013-07-14 13:03:49 +1000 (Sun, 14 Jul 2013) | 3 lines Made patch image loading fail more gracefully: a bad offset now prints a warning to the log file instead of inducing a fatal error. ------------------------------------------------------------------------ r1132 | ajapted | 2013-07-11 19:08:38 +1000 (Thu, 11 Jul 2013) | 2 lines Version bump. ------------------------------------------------------------------------ r1131 | ajapted | 2013-07-11 18:58:15 +1000 (Thu, 11 Jul 2013) | 3 lines Key bindings: shifted 'N' and 'P' keys now have the FlipMap function, and moved the GivenFile functions to META-N and META-P. ------------------------------------------------------------------------ r1130 | ajapted | 2013-07-11 18:55:30 +1000 (Thu, 11 Jul 2013) | 4 lines Implemented new binding command 'FlipMap' which loads another map in the current wad. The first param must be "next", "prev", "first" or "last". Very useful for browsing through a pwad with multiple maps. ------------------------------------------------------------------------ r1129 | ajapted | 2013-07-11 18:43:32 +1000 (Thu, 11 Jul 2013) | 3 lines Wad code: added FindLevel_Raw() method which returns a level index instead of a _lump_ index. ------------------------------------------------------------------------ r1128 | ajapted | 2013-07-05 21:34:57 +1000 (Fri, 05 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1127 | ajapted | 2013-07-05 20:28:47 +1000 (Fri, 05 Jul 2013) | 2 lines Removed obsolete GRID_XXX color defines. ------------------------------------------------------------------------ r1126 | ajapted | 2013-07-05 20:13:27 +1000 (Fri, 05 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1125 | ajapted | 2013-07-05 20:11:11 +1000 (Fri, 05 Jul 2013) | 2 lines Grid: implemented preference colors for the Normal grid. ------------------------------------------------------------------------ r1124 | ajapted | 2013-07-05 19:03:30 +1000 (Fri, 05 Jul 2013) | 4 lines Grid: 1. added preference settings for the Dotty grid colors 2. slightly better rendering of the Dotty grid ------------------------------------------------------------------------ r1123 | ajapted | 2013-07-05 16:33:33 +1000 (Fri, 05 Jul 2013) | 5 lines Grid: 1. implemented option to limit grid toggle to a single kind 2. added option to hide grid in FREE mode, show it in SNAP mode 3. nomenclature: old grid is called "dotty", new grid "normal" ------------------------------------------------------------------------ r1122 | ajapted | 2013-07-05 16:28:36 +1000 (Fri, 05 Jul 2013) | 2 lines UI_Canvas: split DrawGrid() into two separate methods. ------------------------------------------------------------------------ r1121 | ajapted | 2013-07-04 20:19:47 +1000 (Thu, 04 Jul 2013) | 2 lines Preferences: a few more tweaks ------------------------------------------------------------------------ r1120 | ajapted | 2013-07-04 18:24:04 +1000 (Thu, 04 Jul 2013) | 4 lines Preferences: 1. added a 'Mouse' tab, nothing in it yet 2. renamed 'glBSP' tab --> 'Other', ready for some other stuff ------------------------------------------------------------------------ r1119 | ajapted | 2013-07-04 16:54:11 +1000 (Thu, 04 Jul 2013) | 4 lines Fixed recent bug with mousewheel zooming -- Editor_RawWheel() was not returning 1 and hence FLTK was sending the mousewheel event to the scrollbars which used it to scroll. ------------------------------------------------------------------------ r1118 | ajapted | 2013-07-04 16:28:06 +1000 (Thu, 04 Jul 2013) | 2 lines CHANGELOG rejigged. ------------------------------------------------------------------------ r1117 | ajapted | 2013-07-04 14:45:46 +1000 (Thu, 04 Jul 2013) | 2 lines Implemented new preference setting : maximize the window on start. ------------------------------------------------------------------------ r1116 | ajapted | 2013-07-04 14:36:43 +1000 (Thu, 04 Jul 2013) | 5 lines UI_Window: added Maximize() method, using OS-native code since FLTK does not provide the required functionality. Only implemented for Win32 and Linux/X11 : the OSX implemented is commented out since it requires some Objective-C logic. ------------------------------------------------------------------------ r1115 | ajapted | 2013-07-01 15:49:13 +1000 (Mon, 01 Jul 2013) | 2 lines event handling tweaks. ------------------------------------------------------------------------ r1114 | ajapted | 2013-07-01 13:11:44 +1000 (Mon, 01 Jul 2013) | 6 lines Moved the mouse button and movement logic out of UI_Canvas class and into Editor_RawButton() and Editor_RawMouse() functions. This fixes the hack in UI_Render3D class [calling the handle method of UI_Canvas, even though the widget was hidden]. ------------------------------------------------------------------------ r1113 | ajapted | 2013-07-01 12:55:11 +1000 (Mon, 01 Jul 2013) | 2 lines Minor refactoring of event handling in UI_Canvas class. ------------------------------------------------------------------------ r1112 | ajapted | 2013-07-01 11:59:37 +1000 (Mon, 01 Jul 2013) | 2 lines Keys: added 'FL_Wheel' : pseudo key value for the mouse wheel. ------------------------------------------------------------------------ r1111 | ajapted | 2013-07-01 11:41:14 +1000 (Mon, 01 Jul 2013) | 2 lines Moved handling of mouse wheel events to Editor_RawWheel() function. ------------------------------------------------------------------------ r1110 | ajapted | 2013-07-01 11:23:40 +1000 (Mon, 01 Jul 2013) | 2 lines Key bindings: support 4 parameters to a binding (limit was 2 before). ------------------------------------------------------------------------ r1109 | ajapted | 2013-07-01 11:12:24 +1000 (Mon, 01 Jul 2013) | 2 lines handle the FL_KEYUP event in Editor_RawKey(). ------------------------------------------------------------------------ r1108 | ajapted | 2013-06-30 17:16:34 +1000 (Sun, 30 Jun 2013) | 3 lines Moved the raw keyboard event handling out of UI_Canvas class, instead have a global function: Editor_RawKey(). ------------------------------------------------------------------------ r1107 | ajapted | 2013-06-30 16:47:14 +1000 (Sun, 30 Jun 2013) | 2 lines VM: tweak ------------------------------------------------------------------------ r1106 | ajapted | 2013-06-30 16:39:56 +1000 (Sun, 30 Jun 2013) | 2 lines Renamed directory: up_scripts --> ups ------------------------------------------------------------------------ r1105 | ajapted | 2013-06-30 16:38:40 +1000 (Sun, 30 Jun 2013) | 3 lines Updated installation makefiles (etc) to create 'ups' folder and to install the 'core_defs.lua' file. ------------------------------------------------------------------------ r1104 | ajapted | 2013-06-30 16:31:54 +1000 (Sun, 30 Jun 2013) | 3 lines VM: added file 'core_defs.up' -- will define all the builtins and any other needed stuff. ------------------------------------------------------------------------ r1103 | ajapted | 2013-06-30 15:44:13 +1000 (Sun, 30 Jun 2013) | 2 lines Added top-level directory: 'up_scripts' ------------------------------------------------------------------------ r1102 | ajapted | 2013-06-30 13:41:42 +1000 (Sun, 30 Jun 2013) | 2 lines TODO update (did some things, added some things). ------------------------------------------------------------------------ r1101 | ajapted | 2013-06-30 13:40:29 +1000 (Sun, 30 Jun 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1100 | ajapted | 2013-06-30 13:39:18 +1000 (Sun, 30 Jun 2013) | 5 lines Config: added 'render_missing_bright' and 'render_unknown_bright' vars, and handle them in the rendering code. Note: not present in the Preferences dialog (yet). ------------------------------------------------------------------------ r1099 | ajapted | 2013-06-30 13:29:42 +1000 (Sun, 30 Jun 2013) | 2 lines 3D preview: implemented missing textures (an '!' on an orange background). ------------------------------------------------------------------------ r1098 | ajapted | 2013-06-30 13:23:41 +1000 (Sun, 30 Jun 2013) | 3 lines 3D preview: show missing textures as fullbright, so they stand out in dark rooms. ------------------------------------------------------------------------ r1097 | ajapted | 2013-06-30 12:58:35 +1000 (Sun, 30 Jun 2013) | 2 lines 3d preview: tweaked untextured color choice. ------------------------------------------------------------------------ r1096 | ajapted | 2013-06-30 12:57:38 +1000 (Sun, 30 Jun 2013) | 2 lines Game defs / DOOM (etc) : updated color definitions. ------------------------------------------------------------------------ r1095 | ajapted | 2013-06-30 12:56:46 +1000 (Sun, 30 Jun 2013) | 3 lines Auto-load recent map: don't do it when -iwad or -warp has been used on the command line. ------------------------------------------------------------------------ r1094 | ajapted | 2013-06-30 12:31:47 +1000 (Sun, 30 Jun 2013) | 2 lines Game defs / HERETIC: updated with color definitions ('wall', 'missing' etc). ------------------------------------------------------------------------ r1093 | ajapted | 2013-06-30 12:25:19 +1000 (Sun, 30 Jun 2013) | 3 lines 3D preview: use the game-specified wall and floor colors, rather than the hard-coded values which were DOOM specific. ------------------------------------------------------------------------ r1092 | ajapted | 2013-06-30 12:23:01 +1000 (Sun, 30 Jun 2013) | 2 lines Game def parser: support 'wall' and 'floor' color definitions. ------------------------------------------------------------------------ r1091 | ajapted | 2013-06-30 12:00:25 +1000 (Sun, 30 Jun 2013) | 4 lines Game def parser: implemented new 'color' command which takes a keyword and one or two numbers (palette indices). The following keywords are currently supported: 'sky', 'missing', 'unknown_tex', 'unknown_flat'. ------------------------------------------------------------------------ r1090 | ajapted | 2013-06-29 22:19:26 +1000 (Sat, 29 Jun 2013) | 3 lines 1. moved g_sky_color and g_sky_flat into a new 'game_info' structure 2. moved is_sky() function from levels.cc --> m_game.cc ------------------------------------------------------------------------ r1089 | ajapted | 2013-06-29 22:10:44 +1000 (Sat, 29 Jun 2013) | 3 lines GAME DEFS: added common/doom_colors.ugh : color defs for games using the DOOM palette. ------------------------------------------------------------------------ r1088 | ajapted | 2013-06-29 22:03:59 +1000 (Sat, 29 Jun 2013) | 3 lines 3D Preview: implemented displaying a dummy texture for unknown flats or textures (a different one for flats vs textures). ------------------------------------------------------------------------ r1087 | ajapted | 2013-06-29 21:28:57 +1000 (Sat, 29 Jun 2013) | 3 lines Img code: added functions to create dummy textures for the 3D renderer, one for missing (HOM) textures and one for unknown textures. ------------------------------------------------------------------------ r1086 | ajapted | 2013-06-29 21:14:25 +1000 (Sat, 29 Jun 2013) | 2 lines Img class: turned 'scale_img()' into a method, plus various tidying. ------------------------------------------------------------------------ r1085 | ajapted | 2013-06-29 20:38:51 +1000 (Sat, 29 Jun 2013) | 2 lines Fixed thing images in the browser to have a black background. ------------------------------------------------------------------------ r1084 | ajapted | 2013-06-29 20:28:42 +1000 (Sat, 29 Jun 2013) | 3 lines LineDef panel: don't show an upper texture as missing if sky ceilings exist on both sides. ------------------------------------------------------------------------ r1083 | ajapted | 2013-06-29 20:18:27 +1000 (Sat, 29 Jun 2013) | 3 lines LineDef panel: implemented showing missing textures, for uppers and lowers this involves checking for a floor / ceiling difference. ------------------------------------------------------------------------ r1082 | ajapted | 2013-06-29 20:02:08 +1000 (Sat, 29 Jun 2013) | 4 lines UI_Pic : implemented ability to show "unknown" and "missing" textures, the former as a large '?' on a cyan background, the latter as '!' on an orange background. ------------------------------------------------------------------------ r1081 | ajapted | 2013-06-28 21:18:31 +1000 (Fri, 28 Jun 2013) | 3 lines UI: in sidedef panels, show low-contrast "Lower", "Mid" and "Upper" for unset textures. Similarly for pics in sector and thing panels. ------------------------------------------------------------------------ r1080 | ajapted | 2013-06-28 19:51:32 +1000 (Fri, 28 Jun 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1079 | ajapted | 2013-06-28 19:35:54 +1000 (Fri, 28 Jun 2013) | 4 lines Scroll-bars: improved logic for adjusting the scroll bars after the canvas position has moved, having grid.MoveTo() and grid.Scroll() methods instead of directly modifying grid.orig_x/_y ------------------------------------------------------------------------ r1078 | ajapted | 2013-06-28 12:11:35 +1000 (Fri, 28 Jun 2013) | 4 lines Scroll-bars: implemented callbacks, i.e. dragging the knobs actually scrolls the map (and in turn, moves the knobs). Hence the scroll-bar feature is mostly complete now. ------------------------------------------------------------------------ r1077 | ajapted | 2013-06-28 11:46:10 +1000 (Fri, 28 Jun 2013) | 3 lines Scroll-bars: implemented logic to compute the position/size of each bar based on the map bounds and the current view position and zoom level. ------------------------------------------------------------------------ r1076 | ajapted | 2013-06-27 22:46:27 +1000 (Thu, 27 Jun 2013) | 1 line CHANGELOG update ------------------------------------------------------------------------ r1075 | ajapted | 2013-06-27 22:45:07 +1000 (Thu, 27 Jun 2013) | 2 lines Minor coding rename: MapBound_[lh][xy] --> Map_bound_[xy][12] ------------------------------------------------------------------------ r1074 | ajapted | 2013-06-27 22:20:00 +1000 (Thu, 27 Jun 2013) | 3 lines Scroll-bars: implemented ability to hide/show the bars based on the user's preference setting. ------------------------------------------------------------------------ r1073 | ajapted | 2013-06-27 21:46:18 +1000 (Thu, 27 Jun 2013) | 3 lines Config: added 'map_scroll_bars' variable which will be used to enable or disable the scroll-bars for the map view. ------------------------------------------------------------------------ r1072 | ajapted | 2013-06-27 17:14:55 +1000 (Thu, 27 Jun 2013) | 2 lines Updated AUTHORS.txt to match website (Jason's contribution). ------------------------------------------------------------------------ r1071 | ajapted | 2013-06-27 17:10:53 +1000 (Thu, 27 Jun 2013) | 3 lines Reworked the About dialog to show the new logo, and have a fallback just in case we cannot open the file, plus tweaked the text. ------------------------------------------------------------------------ r1070 | ajapted | 2013-06-27 17:09:11 +1000 (Thu, 27 Jun 2013) | 2 lines Added 'about_logo.png' -- cropped and scaled from Jason's original. ------------------------------------------------------------------------ r1069 | ajapted | 2013-06-27 16:27:58 +1000 (Thu, 27 Jun 2013) | 2 lines Checked in Jason R Johnston's logo image, and removed the old cruddy one. ------------------------------------------------------------------------ r1068 | ajapted | 2013-06-26 22:17:47 +1000 (Wed, 26 Jun 2013) | 3 lines More work on having a proper widget for the 3D preview. It seems to be working now, albeit with some ugly hacks. ------------------------------------------------------------------------ r1067 | ajapted | 2013-06-26 19:35:35 +1000 (Wed, 26 Jun 2013) | 4 lines Created a UI_Render3D class for the 3D preview. The idea is to show this widget (and hide the canvas/sbars) when 3D mode is active, and do the reverse when not active -- but keyboard handling is now fubar.... ------------------------------------------------------------------------ r1066 | ajapted | 2013-06-26 16:51:36 +1000 (Wed, 26 Jun 2013) | 4 lines Moved the 'render3d' field out of UI_Canvas and into Editor_State_t, since the canvas is no longer responsible for drawing the 3D preview (the new UI_CanvasScroll wrapper is). ------------------------------------------------------------------------ r1065 | ajapted | 2013-06-26 16:27:21 +1000 (Wed, 26 Jun 2013) | 3 lines Initial work on scrollbars for the map view. This commit merely creates a container for the canvas + scrollbars : UI_CanvasScroll. ------------------------------------------------------------------------ r1064 | ajapted | 2013-06-26 14:17:56 +1000 (Wed, 26 Jun 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1063 | ajapted | 2013-06-26 14:02:15 +1000 (Wed, 26 Jun 2013) | 6 lines Improved handling of bad references when loading a level: If a linedef has a bad vertex, it is removed. Bad sector or sidedef references are replaced with something valid. Details are written to the log file, and a dialog is shown to the user when these happen. ------------------------------------------------------------------------ r1062 | ajapted | 2013-06-25 22:45:26 +1000 (Tue, 25 Jun 2013) | 2 lines Created a definition file for the XDoom source port (by Udo Monk). ------------------------------------------------------------------------ r1061 | ajapted | 2013-06-24 23:47:02 +1000 (Mon, 24 Jun 2013) | 3 lines Fixed splitting void islands : it was adding a sector in _both_ sides, but we only want one in a single side (the smallest). ------------------------------------------------------------------------ r1060 | ajapted | 2013-06-24 23:39:39 +1000 (Mon, 24 Jun 2013) | 4 lines Lineloop class: 1. added a Dump() method to aid debugging 2. fixed silly bug in TotalLength() method ------------------------------------------------------------------------ r1059 | ajapted | 2013-06-24 22:26:42 +1000 (Mon, 24 Jun 2013) | 3 lines Basis: fixed assertion checks in BA_ChangeTH() and BA_ChangeLD() to handle the new HEXEN fields. ------------------------------------------------------------------------ r1058 | ajapted | 2013-06-24 15:59:01 +1000 (Mon, 24 Jun 2013) | 4 lines Minor code tidying: 1. removed unused levelname2xxx() functions 2. removed unused yg_level_name variable ------------------------------------------------------------------------ r1057 | ajapted | 2013-06-23 14:24:06 +1000 (Sun, 23 Jun 2013) | 2 lines CHANGELOG and TODO update. ------------------------------------------------------------------------ r1056 | ajapted | 2013-06-23 14:21:03 +1000 (Sun, 23 Jun 2013) | 2 lines Support Eureka config (.ugh) files as resource files. ------------------------------------------------------------------------ r1055 | ajapted | 2013-06-23 13:38:00 +1000 (Sun, 23 Jun 2013) | 4 lines Minor code refactoring: 1. use "M_" prefix on some m_game.cc functions 2. have a LoadResourceFile() function in main.cc ------------------------------------------------------------------------ r1054 | ajapted | 2013-06-23 12:07:40 +1000 (Sun, 23 Jun 2013) | 2 lines Added 'Level_format' global variable. ------------------------------------------------------------------------ r1053 | ajapted | 2013-06-23 12:02:43 +1000 (Sun, 23 Jun 2013) | 4 lines Hexen: 1. have proper F_ARG1..5 keywords for the argument fields 2. updated the CopyProperties command to copy the Hexen fields ------------------------------------------------------------------------ r1052 | ajapted | 2013-06-23 11:49:44 +1000 (Sun, 23 Jun 2013) | 3 lines Basis: expanded Thing and LineDef structures with HEXEN fields. (Note: not actually used anywhere yet). ------------------------------------------------------------------------ r1051 | ajapted | 2013-06-23 11:33:22 +1000 (Sun, 23 Jun 2013) | 2 lines README: added the new 'N' / 'P' keys : next file / prev file. ------------------------------------------------------------------------ r1050 | ajapted | 2013-06-23 11:29:02 +1000 (Sun, 23 Jun 2013) | 3 lines Implemented SEC_Light() binding command for adjusting sector lighting. It takes a delta parameter as per the SEC_Floor() command. ------------------------------------------------------------------------ r1049 | ajapted | 2013-06-22 23:40:29 +1000 (Sat, 22 Jun 2013) | 2 lines CHANGELOG and TODO update. ------------------------------------------------------------------------ r1048 | ajapted | 2013-06-22 23:37:51 +1000 (Sat, 22 Jun 2013) | 4 lines Browser: 1. remember the "off mode" properly in user state 2. persist the browser width in the user state ------------------------------------------------------------------------ r1047 | ajapted | 2013-06-22 23:00:44 +1000 (Sat, 22 Jun 2013) | 4 lines VM: partial work on ability to read/write the members of a set. There are two new instructions, OP_SET_READ and OP_SET_WRITE, which are generated but their execution is not implemented yet. ------------------------------------------------------------------------ r1046 | ajapted | 2013-06-22 16:31:55 +1000 (Sat, 22 Jun 2013) | 4 lines VM: 1. fixed bug when pushing vector literals onto the stack 2. support assigning 'nil' values to any kind of variable ------------------------------------------------------------------------ r1045 | ajapted | 2013-06-22 16:04:02 +1000 (Sat, 22 Jun 2013) | 2 lines VM: updated VIM syntax file for new types. ------------------------------------------------------------------------ r1044 | ajapted | 2013-06-22 15:58:44 +1000 (Sat, 22 Jun 2013) | 7 lines VM: added the following new types: linedef, sidedef, sector, thing and vertex, plus also set[xxx] where xxx is linedef (etc). So far there is nothing which can be done with any of these types. Also support a "nil" keyword with its own ev_nil type. It cannot be used anywhere yet. ------------------------------------------------------------------------ r1043 | ajapted | 2013-06-22 15:22:46 +1000 (Sat, 22 Jun 2013) | 2 lines VM: removed type_size[] array. ------------------------------------------------------------------------ r1042 | ajapted | 2013-06-22 13:40:38 +1000 (Sat, 22 Jun 2013) | 2 lines Fixed remembering 3D mode (actually the lack of it) for a map. ------------------------------------------------------------------------ r1041 | ajapted | 2013-06-22 13:33:33 +1000 (Sat, 22 Jun 2013) | 2 lines Removed some unused code : word_splitting() ------------------------------------------------------------------------ r1040 | ajapted | 2013-06-22 13:19:26 +1000 (Sat, 22 Jun 2013) | 2 lines Moved code around: put Beep() function into m_keys.cc ------------------------------------------------------------------------ r1039 | ajapted | 2013-06-22 13:10:10 +1000 (Sat, 22 Jun 2013) | 3 lines Fixed the key binding dialog: unable to remove a parameter (when the binding already had a parameter). ------------------------------------------------------------------------ r1038 | ajapted | 2013-06-22 11:30:14 +1000 (Sat, 22 Jun 2013) | 8 lines 1. when registering binding commands, determine the context automatically from the name e.g. "LIN_xxxx" will be KCTX_Line. 2. support finding a binding command as a script function (in the VM), and execute that script function when the command is executed. This is bare-bones at the moment, numerous things (error handling, passing parameters) are NOT done yet. ------------------------------------------------------------------------ r1037 | ajapted | 2013-06-21 22:36:31 +1000 (Fri, 21 Jun 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1036 | ajapted | 2013-06-18 19:36:30 +1000 (Tue, 18 Jun 2013) | 2 lines VM: removed more field-related stuff. ------------------------------------------------------------------------ r1035 | ajapted | 2013-06-18 19:18:08 +1000 (Tue, 18 Jun 2013) | 4 lines VM / compiler: tidied up code to parse global definitions. Also removed code to parse "fields" (won't be needed here). ------------------------------------------------------------------------ r1034 | ajapted | 2013-06-18 18:51:19 +1000 (Tue, 18 Jun 2013) | 2 lines VM: ensure local string variables get a valid default (the empty string). ------------------------------------------------------------------------ r1033 | ajapted | 2013-06-18 18:48:46 +1000 (Tue, 18 Jun 2013) | 2 lines VM: ensure global variables of type 'string' get a valid default. ------------------------------------------------------------------------ r1032 | ajapted | 2013-06-18 18:37:01 +1000 (Tue, 18 Jun 2013) | 3 lines VM: replaced 's_file' field of dfunction_t with a normal string ptr, replaced usages of 's_name' field, and removed mpr.strings[] table. ------------------------------------------------------------------------ r1031 | ajapted | 2013-06-18 18:26:13 +1000 (Tue, 18 Jun 2013) | 4 lines VM: changed OP_LITERAL instruction to store the kval_t value in the following instruction slot. This is a bit cleaner than the previous way of storing the value inside the dstatement_t. ------------------------------------------------------------------------ r1030 | ajapted | 2013-06-18 15:55:03 +1000 (Tue, 18 Jun 2013) | 3 lines VM: changed representation of _string in kval_t, esp. on the stack, to use a pointer to object_ref_c instead of an offset into mpr.strings[]. ------------------------------------------------------------------------ r1029 | ajapted | 2013-06-18 15:25:04 +1000 (Tue, 18 Jun 2013) | 2 lines Makefiles: added vm_object.o to the build. ------------------------------------------------------------------------ r1028 | ajapted | 2013-06-18 15:24:24 +1000 (Tue, 18 Jun 2013) | 2 lines VM / lex: removed lex_eval_t union -- for simpler code. ------------------------------------------------------------------------ r1027 | ajapted | 2013-06-18 15:21:23 +1000 (Tue, 18 Jun 2013) | 2 lines VM / objects: added MakePermanent() method, will be needed for string literals. ------------------------------------------------------------------------ r1026 | ajapted | 2013-06-18 14:07:39 +1000 (Tue, 18 Jun 2013) | 3 lines VM / objects: fleshed out remaining methods, e.g. NewSelection(), and fixed various compiling issues. ------------------------------------------------------------------------ r1025 | ajapted | 2013-06-18 13:47:32 +1000 (Tue, 18 Jun 2013) | 2 lines VM / objects: description of the memory model. ------------------------------------------------------------------------ r1024 | ajapted | 2013-06-18 13:33:42 +1000 (Tue, 18 Jun 2013) | 4 lines VM: began work on some simple object management code for the VM. The objects so far are (1) strings and (2) selections for each map kind of map element. Other objects may be added later. ------------------------------------------------------------------------ r1023 | ajapted | 2013-06-17 13:57:40 +1000 (Mon, 17 Jun 2013) | 2 lines VM: added grammar description, using EBNF notation. ------------------------------------------------------------------------ r1022 | ajapted | 2013-06-17 13:49:17 +1000 (Mon, 17 Jun 2013) | 2 lines VM: made all semicolons optional. ------------------------------------------------------------------------ r1021 | ajapted | 2013-06-16 23:46:45 +1000 (Sun, 16 Jun 2013) | 4 lines VM: 1. removed redundant check on "float" in ParseType(). 2. removed "void" as a usable type. ------------------------------------------------------------------------ r1020 | ajapted | 2013-06-16 20:41:07 +1000 (Sun, 16 Jun 2013) | 4 lines VM: 1. renamed 'extern' keyword --> 'builtin' 2. renamed 'va' function --> 'format' ------------------------------------------------------------------------ r1019 | ajapted | 2013-06-16 20:27:58 +1000 (Sun, 16 Jun 2013) | 3 lines Detect HEXEN format maps, and prevent trying to load them -- instead we show an error message, which is better than crashing out. ------------------------------------------------------------------------ r1018 | ajapted | 2013-06-16 19:15:31 +1000 (Sun, 16 Jun 2013) | 3 lines VM: fixed precedence of the '?:' ternary operator, which needs to be higher than assignment. ------------------------------------------------------------------------ r1017 | ajapted | 2013-06-16 19:01:24 +1000 (Sun, 16 Jun 2013) | 2 lines Minor rename: 'ResourceWads' --> 'Resource_list' ------------------------------------------------------------------------ r1016 | ajapted | 2013-06-16 18:35:32 +1000 (Sun, 16 Jun 2013) | 2 lines Preferences: added button for 'auto_load_recent' config var. ------------------------------------------------------------------------ r1015 | ajapted | 2013-06-16 18:22:33 +1000 (Sun, 16 Jun 2013) | 3 lines Preferences: added a new 'Grid' tab, and moved the griddy stuff there, though I expect to add more griddy stuff too (soon). ------------------------------------------------------------------------ r1014 | ajapted | 2013-06-16 16:26:32 +1000 (Sun, 16 Jun 2013) | 3 lines Implemented opening the most recently saved pwad on startup -- but only when Eureka is started without any pwad filenames. ------------------------------------------------------------------------ r1013 | ajapted | 2013-06-16 16:01:14 +1000 (Sun, 16 Jun 2013) | 2 lines Moved code around in m_files.cc ------------------------------------------------------------------------ r1012 | ajapted | 2013-06-16 15:51:11 +1000 (Sun, 16 Jun 2013) | 2 lines Support DOOMWADPATH for finding IWAD files. ------------------------------------------------------------------------ r1011 | ajapted | 2013-06-16 15:01:57 +1000 (Sun, 16 Jun 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1010 | ajapted | 2013-06-16 14:59:16 +1000 (Sun, 16 Jun 2013) | 2 lines Use Wad_file::Validate() instead of FileExists() where appropriate. ------------------------------------------------------------------------ r1009 | ajapted | 2013-06-16 14:43:26 +1000 (Sun, 16 Jun 2013) | 2 lines Validate all given pwad files (make sure they exist, etc). ------------------------------------------------------------------------ r1008 | ajapted | 2013-06-16 14:40:42 +1000 (Sun, 16 Jun 2013) | 3 lines Wad code: added Validate() static method to check if a wad exists and is indeed a WAD file. ------------------------------------------------------------------------ r1007 | ajapted | 2013-06-16 13:58:10 +1000 (Sun, 16 Jun 2013) | 3 lines Fixed CMD_OpenFileMap() to confirm with user when the current map has been modified. ------------------------------------------------------------------------ r1006 | ajapted | 2013-06-16 13:54:32 +1000 (Sun, 16 Jun 2013) | 3 lines Allow any number of given pwad files (in Pwad_list), only limit them when creating the 'Given Files' menu. ------------------------------------------------------------------------ r1005 | ajapted | 2013-06-16 13:45:44 +1000 (Sun, 16 Jun 2013) | 9 lines Implemented "GivenFile" command which supports loading the next / previous file in the given files list, with default bindings on 'N' and 'P' keys. This makes it easy to step through a large group of wads. The command also supports "first" and "last" keywords, but these are not bound to any keys by default. Also moved binding of PRUNE command from 'P' --> 'p' key. ------------------------------------------------------------------------ r1004 | ajapted | 2013-06-16 11:49:30 +1000 (Sun, 16 Jun 2013) | 2 lines Tidied up the latest 'Recent Files' handling code. ------------------------------------------------------------------------ r1003 | ajapted | 2013-06-16 11:35:29 +1000 (Sun, 16 Jun 2013) | 2 lines Dead code removal : CMD_OpenRecentMap() and UI_RecentFiles dialog. ------------------------------------------------------------------------ r1002 | ajapted | 2013-06-14 21:53:11 +1000 (Fri, 14 Jun 2013) | 3 lines More work on new 'File/Recent Files' sub-menu, which is working now, though the code needs some tidying up... ------------------------------------------------------------------------ r1001 | ajapted | 2013-06-14 21:02:25 +1000 (Fri, 14 Jun 2013) | 7 lines Partial work changing 'File/Recent Files' into a sub-menu which is populated at startup with the recent file list. This commit has the code to populate the sub-menu. Also: disable (gray out) the 'Given Files' sub-menu when there is not multiple specified filenames. ------------------------------------------------------------------------ r1000 | ajapted | 2013-06-14 19:38:26 +1000 (Fri, 14 Jun 2013) | 3 lines Made -file option accept multiple filenames, adding them to Pwad_list as per loose filenames. ------------------------------------------------------------------------ r999 | ajapted | 2013-06-14 18:45:37 +1000 (Fri, 14 Jun 2013) | 3 lines Makefile.xming : removed -lshfolder from linkage [was only there to test a binary under Windows 95]. ------------------------------------------------------------------------ r998 | ajapted | 2013-06-14 16:52:30 +1000 (Fri, 14 Jun 2013) | 3 lines Implemented a 'Given Files' sub-menu of the File menu, which is populated when Eureka is run with a list of wad files. ------------------------------------------------------------------------ r997 | ajapted | 2013-06-14 15:23:58 +1000 (Fri, 14 Jun 2013) | 2 lines VM: checked in a Vim syntax file for the scripting language. ------------------------------------------------------------------------ r996 | ajapted | 2013-06-14 15:23:01 +1000 (Fri, 14 Jun 2013) | 2 lines Makefiles: added VM code files to the build. ------------------------------------------------------------------------ r995 | ajapted | 2013-06-10 23:52:39 +1000 (Mon, 10 Jun 2013) | 2 lines VM: added missing code to resolve builtin functions. ------------------------------------------------------------------------ r994 | ajapted | 2013-06-10 23:40:45 +1000 (Mon, 10 Jun 2013) | 3 lines VM: worked on implementing the API functions, e.g. VM_CompileFile() and VM_Call(), and wrote some test code for loading / running a script. ------------------------------------------------------------------------ r993 | ajapted | 2013-06-10 22:00:38 +1000 (Mon, 10 Jun 2013) | 3 lines VM: more work integrating this code, it compiles now, but is still far away from being able to actually do anything.... ------------------------------------------------------------------------ r992 | ajapted | 2013-06-10 19:21:52 +1000 (Mon, 10 Jun 2013) | 2 lines VM: various work to integrate the VM code into its new environment... ------------------------------------------------------------------------ r991 | ajapted | 2013-06-10 18:10:20 +1000 (Mon, 10 Jun 2013) | 4 lines Began work on a scripting system. This commit contains code for a VM which I have been developing for a while now. It was originally based on the QCC compiler and execution engine from Quake, by Id Software. ------------------------------------------------------------------------ r990 | ajapted | 2013-06-10 16:56:48 +1000 (Mon, 10 Jun 2013) | 5 lines Removed the unfinished support for Radius Triggers (RTS), which is a feature of the EDGE source port. It would've required a lot more code to finish the RTS mode, not only parsing and re-creating the RSCRIPT lump, but also the ability to edit the scripts. ------------------------------------------------------------------------ r989 | ajapted | 2013-06-10 16:39:36 +1000 (Mon, 10 Jun 2013) | 1 line Version bump ------------------------------------------------------------------------ r988 | ajapted | 2013-06-10 15:27:13 +1000 (Mon, 10 Jun 2013) | 3 lines Changed PASTE behavior : place objects around their true centre, instead of around the thing or vertex which is closest to the centre. ------------------------------------------------------------------------ r987 | ajapted | 2013-06-10 15:18:36 +1000 (Mon, 10 Jun 2013) | 4 lines Added 'reselect_second_vertex' variable to control when adding a linedef onto an existing vertex (or line) if the second vertex will be selected. ------------------------------------------------------------------------ r986 | ajapted | 2013-06-10 15:13:28 +1000 (Mon, 10 Jun 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r985 | printz | 2013-05-29 07:23:50 +1000 (Wed, 29 May 2013) | 1 line osx: FLTK is now statically linked ------------------------------------------------------------------------ r984 | ajapted | 2013-05-07 22:30:00 +1000 (Tue, 07 May 2013) | 3 lines Tweaked BA_ChecksumLevel() to produce checksums the same as before, so that persistent data for previously edited maps gets found. ------------------------------------------------------------------------ r983 | ajapted | 2013-05-06 13:19:33 +1000 (Mon, 06 May 2013) | 3 lines Fixed crash bug in BA_ChecksumLevel(), used when loading and saving a map, occurring when a linedef was missing the right sidedef. ------------------------------------------------------------------------ r981 | ajapted | 2013-05-01 15:11:48 +1000 (Wed, 01 May 2013) | 2 lines Preferences: leave_offsets_alone now defaults to TRUE. ------------------------------------------------------------------------ r968 | ajapted | 2013-04-28 21:07:50 +1000 (Sun, 28 Apr 2013) | 2 lines TODO: minor update. ------------------------------------------------------------------------ r967 | ajapted | 2013-04-28 21:07:23 +1000 (Sun, 28 Apr 2013) | 2 lines More grid-color tweakage. ------------------------------------------------------------------------ r943 | ajapted | 2013-03-16 21:57:03 +1100 (Sat, 16 Mar 2013) | 2 lines Grid: color tweakage. ------------------------------------------------------------------------ r942 | ajapted | 2013-03-16 11:19:44 +1100 (Sat, 16 Mar 2013) | 2 lines Grid: improved the simple grid to show flat boundaries. ------------------------------------------------------------------------ r941 | ajapted | 2013-03-16 09:25:33 +1100 (Sat, 16 Mar 2013) | 3 lines Fixed the selection after a sector merge (the "gone away" sectors were still in the selection, preventing a subsequent merge). ------------------------------------------------------------------------ r940 | ajapted | 2013-03-16 09:17:33 +1100 (Sat, 16 Mar 2013) | 2 lines Version bump after 0.95 release. ------------------------------------------------------------------------ r939 | ajapted | 2013-03-16 09:16:08 +1100 (Sat, 16 Mar 2013) | 2 lines CHANGES.txt : added fresh one (post v0.95 release). ------------------------------------------------------------------------ r938 | ajapted | 2013-03-03 11:20:04 +1100 (Sun, 03 Mar 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r937 | ajapted | 2013-03-01 11:09:50 +1100 (Fri, 01 Mar 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r936 | ajapted | 2013-02-25 10:20:28 +1100 (Mon, 25 Feb 2013) | 2 lines Moved CHANGES.txt --> changelog/095.txt [after the 0.95 release] ------------------------------------------------------------------------ r935 | ajapted | 2013-02-25 10:17:39 +1100 (Mon, 25 Feb 2013) | 2 lines bindings.cfg : added SHIFT + cursor keys for scrolling in bigger steps. ------------------------------------------------------------------------ r934 | ajapted | 2013-02-24 15:44:50 +1100 (Sun, 24 Feb 2013) | 2 lines TODO : small addition. ------------------------------------------------------------------------ r933 | ajapted | 2013-02-24 15:36:11 +1100 (Sun, 24 Feb 2013) | 2 lines Updated doc/History.txt with SVN changes since last release. ------------------------------------------------------------------------ r932 | ajapted | 2013-02-24 15:30:07 +1100 (Sun, 24 Feb 2013) | 2 lines Pack-source script: copy the 'osx' directory too. ------------------------------------------------------------------------ r931 | ajapted | 2013-02-24 15:25:07 +1100 (Sun, 24 Feb 2013) | 2 lines MacOSX: fixed bug in Determine_HomeDir() using 'path' twice. ------------------------------------------------------------------------ r930 | printz | 2013-02-23 21:26:12 +1100 (Sat, 23 Feb 2013) | 1 line Bumped PLIST version ------------------------------------------------------------------------ r929 | printz | 2013-02-23 21:13:44 +1100 (Sat, 23 Feb 2013) | 1 line Removed deleted file references in the xcode project ------------------------------------------------------------------------ r928 | ajapted | 2013-02-23 20:11:21 +1100 (Sat, 23 Feb 2013) | 2 lines Win32 / installer: fixed NSIS script to require "admin" rights. ------------------------------------------------------------------------ r927 | ajapted | 2013-02-23 17:49:36 +1100 (Sat, 23 Feb 2013) | 2 lines Pack-source script: updated for 'changelogs' folder. ------------------------------------------------------------------------ r926 | ajapted | 2013-02-23 17:48:30 +1100 (Sat, 23 Feb 2013) | 2 lines Moved changelog documents from docs/ --> changelogs/ ------------------------------------------------------------------------ r925 | ajapted | 2013-02-23 17:46:31 +1100 (Sat, 23 Feb 2013) | 2 lines New top-level folder 'changelogs' -- no prizes for guessing what will go in there! ------------------------------------------------------------------------ r924 | ajapted | 2013-02-23 17:39:06 +1100 (Sat, 23 Feb 2013) | 2 lines README.txt : updated keys for 'd' and 'm' in Things mode. ------------------------------------------------------------------------ r923 | ajapted | 2013-02-23 16:38:12 +1100 (Sat, 23 Feb 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r922 | ajapted | 2013-02-23 16:35:31 +1100 (Sat, 23 Feb 2013) | 3 lines Config: added 'swap_sidedefs' preference setting which swaps the upper and lower sidedefs in the Linedef panel (i.e. to Upper/Middle/Lower). ------------------------------------------------------------------------ r921 | ajapted | 2013-02-23 15:45:40 +1100 (Sat, 23 Feb 2013) | 2 lines Debian: updated control info (mainly version #) for 0.95 release. ------------------------------------------------------------------------ r920 | ajapted | 2013-02-23 15:41:53 +1100 (Sat, 23 Feb 2013) | 2 lines TODO.txt : another addition. ------------------------------------------------------------------------ r919 | ajapted | 2013-02-23 15:33:01 +1100 (Sat, 23 Feb 2013) | 2 lines README.txt : minor changes to FEATURES section. ------------------------------------------------------------------------ r918 | ajapted | 2013-02-23 15:31:39 +1100 (Sat, 23 Feb 2013) | 2 lines TODO updated. ------------------------------------------------------------------------ r917 | ajapted | 2013-02-22 19:27:32 +1100 (Fri, 22 Feb 2013) | 4 lines 1. made UI_ChooseMap window shorter 2. fixed weird order of "ExMx" level names in UI_ChooseMap 3. fixed unclickable bottom row of buttons in UI_OpenMap dialog ------------------------------------------------------------------------ r916 | ajapted | 2013-02-22 19:14:58 +1100 (Fri, 22 Feb 2013) | 2 lines Fixed the mode widget on info bar not having any color at startup. ------------------------------------------------------------------------ r915 | ajapted | 2013-02-22 19:08:35 +1100 (Fri, 22 Feb 2013) | 2 lines Tweaked background colors of some widgets for non-plastic themes. ------------------------------------------------------------------------ r914 | ajapted | 2013-02-22 17:26:14 +1100 (Fri, 22 Feb 2013) | 5 lines Made map buttons in ChooseMap and OpenMap dialogs be ordered differently, increasing across-ways instead of down in columns. That's because I want the map buttons to be placed in predictable places (e.g. the layout does not change depending on number of maps present) -- for better usability. ------------------------------------------------------------------------ r913 | ajapted | 2013-02-22 16:58:48 +1100 (Fri, 22 Feb 2013) | 3 lines Partial work to make ChooseMap and OpenMap dialogs consistent w.r.t the map selection buttons -- same color, font size and positioning. ------------------------------------------------------------------------ r912 | ajapted | 2013-02-22 16:57:42 +1100 (Fri, 22 Feb 2013) | 2 lines Queiten another warning. ------------------------------------------------------------------------ r911 | ajapted | 2013-02-22 16:29:09 +1100 (Fri, 22 Feb 2013) | 2 lines Code: quieten a compiler warning. ------------------------------------------------------------------------ r910 | ajapted | 2013-02-22 15:49:54 +1100 (Fri, 22 Feb 2013) | 2 lines Dead code removal : SliceLineDef() and MakeRectangularNook(). ------------------------------------------------------------------------ r909 | ajapted | 2013-02-22 15:44:42 +1100 (Fri, 22 Feb 2013) | 2 lines Makefiles: added -fno-strict-aliasing to compiler flags. ------------------------------------------------------------------------ r908 | ajapted | 2013-02-22 15:35:02 +1100 (Fri, 22 Feb 2013) | 2 lines Win32 / installer: create a shortcut in the Start Menu. ------------------------------------------------------------------------ r907 | ajapted | 2013-02-22 13:57:16 +1100 (Fri, 22 Feb 2013) | 3 lines View menu: removed the 'Toggle Fullscreen' command, the FLTK fullscreen() method fails miserably on every platform tested, especially Windows XP. ------------------------------------------------------------------------ r906 | ajapted | 2013-02-21 23:30:12 +1100 (Thu, 21 Feb 2013) | 3 lines Wad code: fixed some bugs when adding level lumps -- especially need to fix all the groups when the 'insert_point' is valid. ------------------------------------------------------------------------ r905 | ajapted | 2013-02-21 19:21:36 +1100 (Thu, 21 Feb 2013) | 4 lines Prefs: reset colors when user chooses the "Bright" setting. Unfortunately I don't know how to reset the "Default" colors.... ------------------------------------------------------------------------ r904 | ajapted | 2013-02-21 19:13:10 +1100 (Thu, 21 Feb 2013) | 2 lines Prefs: when 'Custom Colors' is enabled, update the colors immediately. ------------------------------------------------------------------------ r903 | ajapted | 2013-02-21 19:06:02 +1100 (Thu, 21 Feb 2013) | 2 lines Prefs: fixed (I think) the color buttons not updating to a new color. ------------------------------------------------------------------------ r902 | ajapted | 2013-02-21 17:38:56 +1100 (Thu, 21 Feb 2013) | 4 lines Win32: when reading Install_Dir from the registry, ensure that the string is NUL-terminated (the MSDN docs mention that the string may have been stored without a trailing NUL). ------------------------------------------------------------------------ r901 | ajapted | 2013-02-21 17:28:21 +1100 (Thu, 21 Feb 2013) | 3 lines Win32: attempt to fix the problem reading the $Install_Dir registry value, which was returning (I think) UCS2 format unicode instead of ASCII. ------------------------------------------------------------------------ r900 | ajapted | 2013-02-21 17:16:54 +1100 (Thu, 21 Feb 2013) | 2 lines Renamed global var: 'local_dir' --> 'cache_dir' ------------------------------------------------------------------------ r899 | ajapted | 2013-02-21 17:14:53 +1100 (Thu, 21 Feb 2013) | 2 lines MacOSX: set the 'cache_dir' to $HOME/Library/Caches/eureka-editor ------------------------------------------------------------------------ r898 | ajapted | 2013-02-21 16:49:06 +1100 (Thu, 21 Feb 2013) | 2 lines Removed dummy mods/foo.bar file. ------------------------------------------------------------------------ r897 | ajapted | 2013-02-21 16:48:42 +1100 (Thu, 21 Feb 2013) | 2 lines Win32 / nsis_build: I forgot to copy the executable, duh. ------------------------------------------------------------------------ r896 | ajapted | 2013-02-21 16:46:05 +1100 (Thu, 21 Feb 2013) | 4 lines Win32: reworked NSIS script and Makefile.xming so that we first create a replicate of the final directory structure. Main reason is because we need to convert the text files to MSDOS/Windows format. ------------------------------------------------------------------------ r895 | ajapted | 2013-02-21 15:45:18 +1100 (Thu, 21 Feb 2013) | 2 lines svn:ignore update ------------------------------------------------------------------------ r894 | ajapted | 2013-02-21 15:44:24 +1100 (Thu, 21 Feb 2013) | 2 lines Added empty mods/foo.bar file, to keep NSIS happy. ------------------------------------------------------------------------ r893 | ajapted | 2013-02-21 15:41:23 +1100 (Thu, 21 Feb 2013) | 2 lines Version bump to 0.95 -- for upcoming release. ------------------------------------------------------------------------ r892 | ajapted | 2013-02-21 15:40:43 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: some fixes for building the NSIS installer. ------------------------------------------------------------------------ r891 | ajapted | 2013-02-21 15:22:38 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: created obj_win32/glbsp folder. ------------------------------------------------------------------------ r890 | ajapted | 2013-02-21 15:21:47 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: hmmmm, PathAppend() doesn't seem available -- use strcat() instead. ------------------------------------------------------------------------ r889 | ajapted | 2013-02-21 15:16:00 +1100 (Thu, 21 Feb 2013) | 2 lines Fixed typo in last commit. ------------------------------------------------------------------------ r888 | ajapted | 2013-02-21 15:14:52 +1100 (Thu, 21 Feb 2013) | 4 lines Win32 port: 1. fixed not appending our own folder name to %APPDATA% 2. fixed a few compiling issues (e.g. MOD_SHIFT conflicts with windows headers) ------------------------------------------------------------------------ r887 | ajapted | 2013-02-21 14:56:52 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: more work on Makefile.xming, should be usable now (barring mistakes). ------------------------------------------------------------------------ r886 | ajapted | 2013-02-21 14:55:38 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: added folder for build objects: obj_win32/ ------------------------------------------------------------------------ r885 | ajapted | 2013-02-21 14:54:00 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: created a resource file : eureka.rc ------------------------------------------------------------------------ r884 | ajapted | 2013-02-21 14:38:14 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: tweaked name of install directory and registry key. ------------------------------------------------------------------------ r883 | ajapted | 2013-02-21 14:37:08 +1100 (Thu, 21 Feb 2013) | 3 lines Win32: started work on Makefile.xming -- uses a cross-compiler to make the Windows executable. ------------------------------------------------------------------------ r882 | ajapted | 2013-02-21 13:11:31 +1100 (Thu, 21 Feb 2013) | 5 lines Win32: implemented Determine_HomeDir() logic, which uses SHGetFolderPath to determine the %APPDATA% folder. Also have fallback for 'local_dir' value (needed for Linux). ------------------------------------------------------------------------ r881 | ajapted | 2013-02-21 12:57:05 +1100 (Thu, 21 Feb 2013) | 2 lines Use $local_dir (not $home_dir) as prefix for 'cache' and 'backups' folders. ------------------------------------------------------------------------ r880 | ajapted | 2013-02-21 12:51:57 +1100 (Thu, 21 Feb 2013) | 10 lines 1. implemented WIN32 logic to read the "Install_Dir" registry key which is created by the NSIS installer 2. made FatalError() on WIN32 use the system MessageBox() function when FLTK has not been initialized yet. 3. added 'local_dir' global var, this will be the place for the cache and backup folders -- i.e. non-roamable stuff. On Linux it will just be the same as $home_dir. ------------------------------------------------------------------------ r879 | ajapted | 2013-02-21 11:49:16 +1100 (Thu, 21 Feb 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r878 | ajapted | 2013-02-21 11:48:36 +1100 (Thu, 21 Feb 2013) | 2 lines Updated README.txt and CHANGES.txt -- preparing for a release. ------------------------------------------------------------------------ r877 | ajapted | 2013-02-21 11:35:15 +1100 (Thu, 21 Feb 2013) | 2 lines Checked in basic NSIS script to create a Win32 installer : eureka.nsi ------------------------------------------------------------------------ r876 | ajapted | 2013-02-19 22:23:44 +1100 (Tue, 19 Feb 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r875 | ajapted | 2013-02-19 22:16:21 +1100 (Tue, 19 Feb 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r874 | ajapted | 2013-02-19 22:09:43 +1100 (Tue, 19 Feb 2013) | 2 lines Default Props panel: now hidden by default. ------------------------------------------------------------------------ r873 | ajapted | 2013-02-19 22:05:07 +1100 (Tue, 19 Feb 2013) | 2 lines log viewer tweak ------------------------------------------------------------------------ r872 | ajapted | 2013-02-19 22:03:30 +1100 (Tue, 19 Feb 2013) | 3 lines Log Viewer: reduced MAX_LINES to 600, and made it jump to the bottom when adding a new line. ------------------------------------------------------------------------ r871 | ajapted | 2013-02-19 21:56:26 +1100 (Tue, 19 Feb 2013) | 2 lines Print the current time (in the log file) at startup. ------------------------------------------------------------------------ r870 | ajapted | 2013-02-19 21:49:59 +1100 (Tue, 19 Feb 2013) | 2 lines main.h : ensure we #include for WIN32 builds ------------------------------------------------------------------------ r869 | ajapted | 2013-02-19 21:38:58 +1100 (Tue, 19 Feb 2013) | 8 lines Log file rejigging: 1. we always create a log file, default is $home_dir/logs.txt 2. all messages are sent to stdout (unless --quiet is used) 3. remember messages in memory until LogViewer window is opened 4. after opening the log file, write saved messages to it 5. after created LogViewer window, grab the saved messages 6. tweaks to debug handling ------------------------------------------------------------------------ r868 | ajapted | 2013-02-19 18:12:36 +1100 (Tue, 19 Feb 2013) | 3 lines Config: added "-m" as short option for "--merge", and "-v" as short option for "--version". ------------------------------------------------------------------------ r867 | ajapted | 2013-02-19 17:56:53 +1100 (Tue, 19 Feb 2013) | 3 lines Removed 'r_misc' code files -- since we longer use anything in there (such as the SetWindowSize() function and ScrMaxX/Y variables). ------------------------------------------------------------------------ r866 | ajapted | 2013-02-19 16:53:54 +1100 (Tue, 19 Feb 2013) | 3 lines Log Viewer: added 'View/Logs' menu to show the log viewer, and don't show it automatically on start-up. ------------------------------------------------------------------------ r865 | ajapted | 2013-02-19 16:42:58 +1100 (Tue, 19 Feb 2013) | 4 lines Began working on a Log Viewing window. So far the window is opened at startup, and it contains only an Fl_Browser to show the text. Also the LogPrintf() function has been hacked up to send the lines into it. ------------------------------------------------------------------------ r864 | ajapted | 2013-02-19 16:17:15 +1100 (Tue, 19 Feb 2013) | 2 lines Moved Int_TmpStr() function to lib_util.cc/h ------------------------------------------------------------------------ r863 | ajapted | 2013-02-19 15:26:19 +1100 (Tue, 19 Feb 2013) | 2 lines minor menu tweak. ------------------------------------------------------------------------ r862 | ajapted | 2013-02-19 15:23:03 +1100 (Tue, 19 Feb 2013) | 2 lines bindings.cfg : swapped grid keys, 'g' now goes smaller, 'G' goes bigger. ------------------------------------------------------------------------ r861 | ajapted | 2013-02-19 15:20:29 +1100 (Tue, 19 Feb 2013) | 3 lines 1. made sure every Beep() call has a message 2. removed the no-message Beep() function ------------------------------------------------------------------------ r860 | ajapted | 2013-02-19 14:43:44 +1100 (Tue, 19 Feb 2013) | 2 lines File menu: use CTRL-M for Manage Wads, CTRL-P for Preferences. ------------------------------------------------------------------------ r859 | ajapted | 2013-02-19 14:38:28 +1100 (Tue, 19 Feb 2013) | 5 lines Prefs / key binds: 1. save the bindings when APPLY button is clicked 2. fixed bug in M_SaveBindings() which skipped the general context 3. changed ordering which contexts are displayed in the key browser ------------------------------------------------------------------------ r858 | ajapted | 2013-02-19 14:27:21 +1100 (Tue, 19 Feb 2013) | 2 lines bindings.cfg : moved PruneUnused from 'p' --> 'P' key ------------------------------------------------------------------------ r857 | ajapted | 2013-02-19 13:32:11 +1100 (Tue, 19 Feb 2013) | 7 lines Prefs / key binds: 1. changed "Add" button into a "Copy" button, which copies the line and automatically goes into grab-key mode 2. moved "Bind" button to the top 3. made UI_EditKey dialog give focus to the function name input 4. fixed "Edit" button so arrow keys control the browser afterwards ------------------------------------------------------------------------ r856 | ajapted | 2013-02-19 13:03:53 +1100 (Tue, 19 Feb 2013) | 3 lines Prefs / key binds: implemented good method to detect conflicting key bindings -- will be shown in RED no matter how the list is sorted. ------------------------------------------------------------------------ r855 | ajapted | 2013-02-19 12:46:01 +1100 (Tue, 19 Feb 2013) | 3 lines Prefs / key binds: got the "Edit" and "Add" buttons working, using the values chosen in the UI_EditKey dialog. ------------------------------------------------------------------------ r854 | ajapted | 2013-02-18 23:10:56 +1100 (Mon, 18 Feb 2013) | 2 lines TODO updated. ------------------------------------------------------------------------ r853 | ajapted | 2013-02-18 23:02:38 +1100 (Mon, 18 Feb 2013) | 2 lines UI_EditKey dialog: when validating func_name, check the brackets. ------------------------------------------------------------------------ r852 | ajapted | 2013-02-18 22:58:20 +1100 (Mon, 18 Feb 2013) | 2 lines UI_EditKey dialog: implemented ValidateFunc(). ------------------------------------------------------------------------ r851 | ajapted | 2013-02-18 22:52:48 +1100 (Mon, 18 Feb 2013) | 4 lines 1. fixed M_ParseKeyString() not handling hex values like "0x1234" 2. added some synonyms to the M_ParseKeyString() key table, such as "RETURN" for "ENTER", "INSERT" for "INS", etc... ------------------------------------------------------------------------ r850 | ajapted | 2013-02-18 22:41:53 +1100 (Mon, 18 Feb 2013) | 3 lines UI_EditKey dialog: implemented validation of the key name (drawn red when the name fails to parse). ------------------------------------------------------------------------ r849 | ajapted | 2013-02-18 22:23:51 +1100 (Mon, 18 Feb 2013) | 7 lines Prefs / key binds: show duplicated key bindings (same mode and key) using red text in the key browser. This only works when the two keys are together in the list (i.e. the list has been recently sorted, and the sort criterion was either KEY or MODE). It could be done better -- but this will suffice for now. ------------------------------------------------------------------------ r848 | ajapted | 2013-02-18 22:02:05 +1100 (Mon, 18 Feb 2013) | 2 lines Version bump to 0.92 ------------------------------------------------------------------------ r847 | ajapted | 2013-02-18 16:39:04 +1100 (Mon, 18 Feb 2013) | 4 lines Prefs / key binds: 1. setup the initial values for UI_EditKey dialog 2. renamed 'dialog' --> 'prefs' in all UI_Preferences callbacks ------------------------------------------------------------------------ r846 | ajapted | 2013-02-18 16:27:00 +1100 (Mon, 18 Feb 2013) | 3 lines Prefs / key binds: bit more work on UI_EditKey dialog, fixed a few layout issues, added Run() method, implemented Close and OK buttons. ------------------------------------------------------------------------ r845 | ajapted | 2013-02-18 10:31:29 +1100 (Mon, 18 Feb 2013) | 2 lines CHANGELOG and TODO update. ------------------------------------------------------------------------ r844 | ajapted | 2013-02-18 10:27:00 +1100 (Mon, 18 Feb 2013) | 3 lines When saving a map, prefer existing location in the wad directory (i.e. if map already exists, don't place lumps at end of wad). ------------------------------------------------------------------------ r843 | ajapted | 2013-02-17 22:36:36 +1100 (Sun, 17 Feb 2013) | 2 lines Quantize: status message when cannot move some things / vertices. ------------------------------------------------------------------------ r842 | ajapted | 2013-02-17 22:31:18 +1100 (Sun, 17 Feb 2013) | 2 lines CHANGELOG updated. ------------------------------------------------------------------------ r841 | ajapted | 2013-02-17 22:26:51 +1100 (Sun, 17 Feb 2013) | 2 lines Ensure displayed level name is always uppercase. ------------------------------------------------------------------------ r840 | ajapted | 2013-02-17 21:38:58 +1100 (Sun, 17 Feb 2013) | 6 lines Prefs / key binds: initial work on a UI_EditKey dialog, which allows the user to change the key, context and function of a binding. So far only the layout is done (code is output of Fluid with some tidying up). ------------------------------------------------------------------------ r839 | ajapted | 2013-02-17 21:04:03 +1100 (Sun, 17 Feb 2013) | 3 lines Prefs / key binds: added two utility functions: M_GetBindingInfo() and M_IsBindingFuncValid(). ------------------------------------------------------------------------ r838 | ajapted | 2013-02-17 20:41:07 +1100 (Sun, 17 Feb 2013) | 6 lines Prefs / key binds: 1. the ESCAPE key now cancels a bind-in-progress 2. added some shortcut keys: ENTER for "Bind", INSERT and DELETE 3. ensure key browser gets focus after these operations so user can use up/down arrow keys to move through the list. ------------------------------------------------------------------------ r837 | ajapted | 2013-02-17 19:58:52 +1100 (Sun, 17 Feb 2013) | 2 lines TODO.txt : update ------------------------------------------------------------------------ r836 | ajapted | 2013-02-17 19:55:59 +1100 (Sun, 17 Feb 2013) | 7 lines Prefs / key binds: 1. no longer use the 'data' field of browser lines for bind indices, since browser lines map one-to-one with the local bindings 2. renamed 'awaiting_slot' --> 'awaiting_line' and made zero be the "off" value ------------------------------------------------------------------------ r835 | ajapted | 2013-02-17 19:45:34 +1100 (Sun, 17 Feb 2013) | 2 lines Prefs / key binds: implemented the "Delete" button. ------------------------------------------------------------------------ r834 | ajapted | 2013-02-17 19:34:03 +1100 (Sun, 17 Feb 2013) | 3 lines Prefs / key binds: wrote M_AddLocalBinding() and M_DeleteLocalBinding() functions. ------------------------------------------------------------------------ r833 | ajapted | 2013-02-17 19:06:22 +1100 (Sun, 17 Feb 2013) | 2 lines Prefs / key bindings: message tweaks. ------------------------------------------------------------------------ r832 | ajapted | 2013-02-17 17:08:10 +1100 (Sun, 17 Feb 2013) | 8 lines Prefs / key bindings: 1. made key browser higher (i.e. revert previous change, since I don't think a message area will be needded) 2. when waiting for a key press, give the whole preferences window the keyboard focus (via Fl::focus). This fixes certain keys not being bindable (like SPACE). ------------------------------------------------------------------------ r831 | ajapted | 2013-02-17 16:44:00 +1100 (Sun, 17 Feb 2013) | 2 lines Prefs / key bindings: updated code for m_keys rejiggage. ------------------------------------------------------------------------ r830 | ajapted | 2013-02-17 15:47:23 +1100 (Sun, 17 Feb 2013) | 2 lines Prefs / key bindings: better error messages for M_ChangeBindingFunc(). ------------------------------------------------------------------------ r829 | ajapted | 2013-02-17 15:42:41 +1100 (Sun, 17 Feb 2013) | 5 lines Prefs / key bindings: reworked code in m_keys, it now follows a model where the key bindings are copied and the dialog will query and change that copy. The M_ApplyBindings() function will transfer them back. Also the M_ChangeBindingFunc() now returns an error string. ------------------------------------------------------------------------ r828 | ajapted | 2013-02-17 15:19:21 +1100 (Sun, 17 Feb 2013) | 4 lines Prefs / key bindings: 1. renamed CONTEXT column --> MODE 2. began work on "Add", "Delete" and "Load Defaults" buttons ------------------------------------------------------------------------ r827 | ajapted | 2013-02-17 14:54:56 +1100 (Sun, 17 Feb 2013) | 4 lines Prefs / key bindings: 1. changed order of columns to: KEY | CONTEXT | FUNCTION 2. added some space underneath the list for a message ------------------------------------------------------------------------ r826 | ajapted | 2013-02-17 14:05:03 +1100 (Sun, 17 Feb 2013) | 3 lines Preferences dialog: changed "OK" button to "Apply", and added a "Discard" button which does not keep the changes made. ------------------------------------------------------------------------ r825 | ajapted | 2013-02-16 15:15:28 +1100 (Sat, 16 Feb 2013) | 3 lines Prefs / key bindings: implemented the "Edit" button, with code to parse the entered string, find the command and store it + parameters. ------------------------------------------------------------------------ r824 | ajapted | 2013-02-16 13:37:41 +1100 (Sat, 16 Feb 2013) | 2 lines Prefs / key bindings: can actually change a key binding now. ------------------------------------------------------------------------ r823 | ajapted | 2013-02-16 12:44:02 +1100 (Sat, 16 Feb 2013) | 4 lines Prefs / key bindings: worked on ability to show in the current binding (with background changed to yellow) and the next key-press will become the new binding -- or clear the binding on a mouse press. ------------------------------------------------------------------------ r822 | ajapted | 2013-02-16 11:46:55 +1100 (Sat, 16 Feb 2013) | 3 lines Prefs / key bindings: improved display of keys with modifiers, show the modifier in its own column (so that the bare keys are aligned). ------------------------------------------------------------------------ r821 | ajapted | 2013-02-16 11:36:23 +1100 (Sat, 16 Feb 2013) | 4 lines Prefs / key bindings: implemented the different sorting modes -- clicking on the header buttons will select that as the sort column, or toggle reverse mode if it already was. ------------------------------------------------------------------------ r820 | ajapted | 2013-02-16 11:16:32 +1100 (Sat, 16 Feb 2013) | 2 lines Key handling: implemented a key compare function: M_KeyCmp() ------------------------------------------------------------------------ r819 | ajapted | 2013-02-16 11:05:17 +1100 (Sat, 16 Feb 2013) | 5 lines Prefs / key bindings: added M_SortBindingsToVec() which sorts the key bindings (actually an int vector) for display by the key browser. Different sorting methods are not implemented yet. ------------------------------------------------------------------------ r818 | ajapted | 2013-02-16 10:31:02 +1100 (Sat, 16 Feb 2013) | 2 lines Key handling: renamed 'global' context --> 'general'. ------------------------------------------------------------------------ r817 | ajapted | 2013-02-15 23:08:46 +1100 (Fri, 15 Feb 2013) | 2 lines Prefs / key bindings: renamed 'GROUP' column --> 'CONTEXT' ------------------------------------------------------------------------ r816 | ajapted | 2013-02-15 22:36:57 +1100 (Fri, 15 Feb 2013) | 2 lines Fluid work : prefs2.fl ------------------------------------------------------------------------ r815 | ajapted | 2013-02-15 22:36:05 +1100 (Fri, 15 Feb 2013) | 2 lines Prefs / key bindings: partial work on "Bind" and "Edit" buttons. ------------------------------------------------------------------------ r814 | ajapted | 2013-02-15 22:01:55 +1100 (Fri, 15 Feb 2013) | 3 lines Prefs / Key bindings: added buttons above the browser which show what each column is (and later will allow sorting by that column). ------------------------------------------------------------------------ r813 | ajapted | 2013-02-15 21:20:01 +1100 (Fri, 15 Feb 2013) | 3 lines Preference dialog: worked on a new "Keys" tab, which will allow the user to edit the key bindings. So far it can only display them. ------------------------------------------------------------------------ r812 | ajapted | 2013-02-15 21:18:28 +1100 (Fri, 15 Feb 2013) | 3 lines Key handling: added M_StringForBinding() function to format a binding into a string suitable for an Fl_Browser widget. ------------------------------------------------------------------------ r811 | ajapted | 2013-02-15 19:39:32 +1100 (Fri, 15 Feb 2013) | 3 lines bindings.cfg : minor change: use '/' to separate flags letters for LIN_SelectPath and SEC_SelectGroup. ------------------------------------------------------------------------ r810 | ajapted | 2013-02-15 17:16:16 +1100 (Fri, 15 Feb 2013) | 2 lines UI_Scroll: implemented the Scroll() method. ------------------------------------------------------------------------ r809 | ajapted | 2013-02-14 22:43:42 +1100 (Thu, 14 Feb 2013) | 2 lines Browser: started work to fix keyboard scrolling.... ------------------------------------------------------------------------ r808 | ajapted | 2013-02-14 22:21:47 +1100 (Thu, 14 Feb 2013) | 4 lines Fixed editor mode getting out-of-sync with the GUI (side panel etc) after loading a map with no user state. ------------------------------------------------------------------------ r807 | ajapted | 2013-02-14 22:17:14 +1100 (Thu, 14 Feb 2013) | 3 lines Fixed SNAP button which could become out-of-sync with the editor after loading a map with no user state. ------------------------------------------------------------------------ r806 | ajapted | 2013-02-14 22:11:40 +1100 (Thu, 14 Feb 2013) | 4 lines File / OpenMap: don't parse the EUREKA lump (and reload the IWAD and resource files) when the current pwad has not changed. ------------------------------------------------------------------------ r805 | ajapted | 2013-02-14 21:56:13 +1100 (Thu, 14 Feb 2013) | 4 lines Added bindings for CTRL + SPACE and CTRL + INSERT to re-enable the feature of forcing a new sector to be created (rather than correcting an existing one). Thanks to d1337r for the bug report. ------------------------------------------------------------------------ r804 | ajapted | 2013-02-05 14:32:43 +1100 (Tue, 05 Feb 2013) | 6 lines Added an 'error_mode' field to Editor_State_t -- when enabled, the current selection is drawn in bright red instead of blue. This will be used later by the error detection dialog. UI_Canvas: factored some common code --> DrawThing() method. ------------------------------------------------------------------------ r803 | ajapted | 2013-02-05 13:58:06 +1100 (Tue, 05 Feb 2013) | 2 lines CHANGELOG update and rearrangement. ------------------------------------------------------------------------ r802 | ajapted | 2013-02-05 13:55:23 +1100 (Tue, 05 Feb 2013) | 2 lines Scale Objects dialog: finished ability to scale Z of sectors. ------------------------------------------------------------------------ r801 | ajapted | 2013-02-05 11:53:13 +1100 (Tue, 05 Feb 2013) | 3 lines Scale Objects dialog: partial work to introduce a 'Z' component (hidden for modes where it doesn't make sense -- which is most of them). ------------------------------------------------------------------------ r800 | ajapted | 2013-02-05 11:51:26 +1100 (Tue, 05 Feb 2013) | 2 lines Checks.txt : minor addition ------------------------------------------------------------------------ r799 | ajapted | 2013-02-04 14:10:36 +1100 (Mon, 04 Feb 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r798 | ajapted | 2013-02-04 14:08:00 +1100 (Mon, 04 Feb 2013) | 3 lines Implemented new 'PruneUnused' command -- remove unused sectors, sidedefs and vertices. Default binding is on 'p' key. ------------------------------------------------------------------------ r797 | ajapted | 2013-02-03 22:03:16 +1100 (Sun, 03 Feb 2013) | 2 lines Yet another CHANGELOG update. ------------------------------------------------------------------------ r796 | ajapted | 2013-02-03 22:02:45 +1100 (Sun, 03 Feb 2013) | 4 lines 1. TH_Merge and VERT_Merge: support one selected + highlight 2. VERT_Merge: don't re-select the final vertex -- index can be wrong (due to deletions). ------------------------------------------------------------------------ r795 | ajapted | 2013-02-03 20:34:38 +1100 (Sun, 03 Feb 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r794 | ajapted | 2013-02-03 20:30:13 +1100 (Sun, 03 Feb 2013) | 4 lines Side panels: show blue background of 'Nombre' when a single object is selected. This is another visual cue that something is selected, especially when that object is off-screen. ------------------------------------------------------------------------ r793 | ajapted | 2013-02-03 19:09:00 +1100 (Sun, 03 Feb 2013) | 4 lines Fixed bug not clearing an after-drag selection when selecting a group of objects via the outline box. ------------------------------------------------------------------------ r792 | ajapted | 2013-02-03 17:19:15 +1100 (Sun, 03 Feb 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r791 | ajapted | 2013-02-03 17:18:08 +1100 (Sun, 03 Feb 2013) | 3 lines LIN_MergeTwo: support one selected + one highlighted, and merge the second linedef into the first (consistent with SEC_Merge). ------------------------------------------------------------------------ r790 | ajapted | 2013-02-03 17:14:10 +1100 (Sun, 03 Feb 2013) | 2 lines SEC_Merge: support one selected + one highlighted. ------------------------------------------------------------------------ r789 | ajapted | 2013-02-01 22:37:22 +1100 (Fri, 01 Feb 2013) | 2 lines CHANGELOG and TODO update. ------------------------------------------------------------------------ r788 | ajapted | 2013-02-01 22:35:21 +1100 (Fri, 01 Feb 2013) | 4 lines When merging vertices (especially the one being dragged), check for the situation where two linedefs would end up overlapping, if so then delete one of them (the one connected to the dragged vertex). ------------------------------------------------------------------------ r787 | ajapted | 2013-02-01 15:50:11 +1100 (Fri, 01 Feb 2013) | 3 lines Beep messages: ensure first letter is uppercase, also simplified a few of the messages. ------------------------------------------------------------------------ r786 | ajapted | 2013-02-01 15:41:22 +1100 (Fri, 01 Feb 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r785 | ajapted | 2013-02-01 15:39:43 +1100 (Fri, 01 Feb 2013) | 3 lines CMD_CopyProperties: implemented 2S --> 2S for linedef textures, with logic to "intelligently" decide which sides to copy. ------------------------------------------------------------------------ r784 | ajapted | 2013-02-01 15:20:28 +1100 (Fri, 01 Feb 2013) | 2 lines CMD_CopyProperties: implemented 2S --> 1S case for linedefs. ------------------------------------------------------------------------ r783 | ajapted | 2013-02-01 15:01:14 +1100 (Fri, 01 Feb 2013) | 2 lines CMD_CopyProperties: partial work to copy textures between linedefs. ------------------------------------------------------------------------ r782 | ajapted | 2013-02-01 12:00:36 +1100 (Fri, 01 Feb 2013) | 3 lines Fixed jerky RMB scrolling at large zoom factors, done by changing the grid fields 'orig_x' and 'orig_y' from int --> double. ------------------------------------------------------------------------ r781 | ajapted | 2013-01-30 22:32:28 +1100 (Wed, 30 Jan 2013) | 2 lines Yet another TODO / CHANGELOG update. ------------------------------------------------------------------------ r780 | ajapted | 2013-01-30 22:30:55 +1100 (Wed, 30 Jan 2013) | 3 lines Fixed (I hope) ClosestLine_XXX() and OppositeLineDef() functions so that they can never hit a vertex, by offsetting the (x,y) coord by 0.5 units. ------------------------------------------------------------------------ r779 | ajapted | 2013-01-30 22:07:02 +1100 (Wed, 30 Jan 2013) | 3 lines LineDef panel: fixed CRASH when clicking on a flag button and no linedef was selected. ------------------------------------------------------------------------ r778 | ajapted | 2013-01-30 21:37:46 +1100 (Wed, 30 Jan 2013) | 3 lines LineDef panel: made the flag widgets ("upper unpeg" etc) easier to click on, the effective width covers the text (not just the checkbox). ------------------------------------------------------------------------ r777 | ajapted | 2013-01-30 21:15:37 +1100 (Wed, 30 Jan 2013) | 2 lines CHANGELOG and TODO updated. ------------------------------------------------------------------------ r776 | ajapted | 2013-01-30 21:10:48 +1100 (Wed, 30 Jan 2013) | 2 lines Config: added 'backup_max_files' and 'backup_max_space' vars. ------------------------------------------------------------------------ r775 | ajapted | 2013-01-30 21:04:28 +1100 (Wed, 30 Jan 2013) | 2 lines Removed the 'escape_key_quits' config var (and from Prefs dialog). ------------------------------------------------------------------------ r774 | ajapted | 2013-01-30 20:55:42 +1100 (Wed, 30 Jan 2013) | 1 line tweak ------------------------------------------------------------------------ r773 | ajapted | 2013-01-30 20:55:22 +1100 (Wed, 30 Jan 2013) | 4 lines Backup system: implemented the directory scanning (to get the low and high values which are present). The backup system is enabled now, and it seems to be working OK. ------------------------------------------------------------------------ r772 | ajapted | 2013-01-30 19:58:56 +1100 (Wed, 30 Jan 2013) | 4 lines Backup system: implemented logic to limit backups (of a certain wad) to a certain space limit -- currently hard-coded as 100 MB. ------------------------------------------------------------------------ r771 | ajapted | 2013-01-30 16:57:44 +1100 (Wed, 30 Jan 2013) | 2 lines Wad code: set offset to 0 for zero-length lumps. ------------------------------------------------------------------------ r770 | ajapted | 2013-01-30 15:52:49 +1100 (Wed, 30 Jan 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r769 | ajapted | 2013-01-30 15:44:25 +1100 (Wed, 30 Jan 2013) | 2 lines Wad code: small optimisation for zero-length lumps. ------------------------------------------------------------------------ r768 | ajapted | 2013-01-30 15:37:12 +1100 (Wed, 30 Jan 2013) | 4 lines Wad code: implemented new PositionForWrite() logic which tries to use free space in the wad file. We also check that a lump did not write more than the 'max_size' value given to AddLump(). ------------------------------------------------------------------------ r767 | ajapted | 2013-01-30 14:29:24 +1100 (Wed, 30 Jan 2013) | 3 lines Wad code: implemented private FindFreeSpace() method, which can find an unused area of a given size. ------------------------------------------------------------------------ r766 | ajapted | 2013-01-30 13:01:17 +1100 (Wed, 30 Jan 2013) | 2 lines status message tweak. ------------------------------------------------------------------------ r765 | ajapted | 2013-01-30 12:59:08 +1100 (Wed, 30 Jan 2013) | 2 lines Made the status area more distinct: bold font, vertical divider. ------------------------------------------------------------------------ r764 | ajapted | 2013-01-30 12:50:14 +1100 (Wed, 30 Jan 2013) | 2 lines CMD_BuildNodes: update status area. ------------------------------------------------------------------------ r763 | ajapted | 2013-01-30 12:11:49 +1100 (Wed, 30 Jan 2013) | 2 lines TODO: added plan to handle multiple files. ------------------------------------------------------------------------ r762 | printz | 2013-01-29 21:53:11 +1100 (Tue, 29 Jan 2013) | 3 lines osx port: * Updated project to Xcode 4.6 * Removed user-specific files from inside *.xcodeproj ------------------------------------------------------------------------ r761 | printz | 2013-01-29 21:52:55 +1100 (Tue, 29 Jan 2013) | 4 lines osx port: * Removed dead code and comments * Added descriptive comments * Updated version info and copyright formatting in the native automatic About box ------------------------------------------------------------------------ r760 | ajapted | 2013-01-29 17:16:28 +1100 (Tue, 29 Jan 2013) | 3 lines Backup system: the main M_BackupWad() logic is done, but some helper functions are not implemented yet -- namely Backup_ScanDir(). ------------------------------------------------------------------------ r759 | ajapted | 2013-01-29 16:43:06 +1100 (Tue, 29 Jan 2013) | 7 lines Began work on the Back-up system, which will save a copy of the wad into the "backups" folder in $home_dir whenever the user saves the map (CTRL-S) or exports the map into an existing wad. This commit merely (a) creates the "backups" folder and (b) adds the calls to M_BackupWad() at the appropriate places. ------------------------------------------------------------------------ r758 | ajapted | 2013-01-29 16:29:31 +1100 (Tue, 29 Jan 2013) | 3 lines Wad class: implemented a Backup() method. ------------------------------------------------------------------------ r757 | ajapted | 2013-01-29 14:58:32 +1100 (Tue, 29 Jan 2013) | 2 lines Checked in the MacOS X port source, created by Ioan Chera. ------------------------------------------------------------------------ r756 | ajapted | 2013-01-29 14:56:56 +1100 (Tue, 29 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r755 | ajapted | 2013-01-28 16:45:37 +1100 (Mon, 28 Jan 2013) | 2 lines After loading or saving a map, show a message in status bar. ------------------------------------------------------------------------ r754 | ajapted | 2013-01-28 14:47:17 +1100 (Mon, 28 Jan 2013) | 3 lines Fixed bug parsing user state for maps (.dat files), which was not handling strings properly. ------------------------------------------------------------------------ r753 | ajapted | 2013-01-28 14:11:29 +1100 (Mon, 28 Jan 2013) | 2 lines bindings.cfg : removed ESC key (bound to Quit). ------------------------------------------------------------------------ r752 | ajapted | 2013-01-28 11:20:25 +1100 (Mon, 28 Jan 2013) | 2 lines bindings.cfg : fixed LIN_Flip key, which clashed with SNAP toggle key. ------------------------------------------------------------------------ r751 | ajapted | 2013-01-26 14:06:30 +1100 (Sat, 26 Jan 2013) | 2 lines Made Editor_State_t be a struct (not a class). ------------------------------------------------------------------------ r750 | ajapted | 2013-01-26 14:01:44 +1100 (Sat, 26 Jan 2013) | 3 lines Silenced 64-bit compiler warnings (loss of precision when assigning a 64-bit value to a 32-bit variable or parameter). ------------------------------------------------------------------------ r749 | ajapted | 2013-01-26 13:55:34 +1100 (Sat, 26 Jan 2013) | 2 lines Fixed a uninitialized variable bug, and some 64-bit tweaks. ------------------------------------------------------------------------ r748 | ajapted | 2013-01-26 13:39:55 +1100 (Sat, 26 Jan 2013) | 2 lines Render3D: when changing gamma, show new value in status area. ------------------------------------------------------------------------ r747 | ajapted | 2013-01-25 09:43:00 +1100 (Fri, 25 Jan 2013) | 2 lines Wrote some notes about possible scripting API : misc/Scripting.txt ------------------------------------------------------------------------ r746 | ajapted | 2013-01-24 21:42:16 +1100 (Thu, 24 Jan 2013) | 2 lines debug tweak. ------------------------------------------------------------------------ r745 | ajapted | 2013-01-24 21:37:41 +1100 (Thu, 24 Jan 2013) | 2 lines TODO updated. ------------------------------------------------------------------------ r744 | ajapted | 2013-01-24 21:36:59 +1100 (Thu, 24 Jan 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r743 | ajapted | 2013-01-24 21:36:27 +1100 (Thu, 24 Jan 2013) | 3 lines When executing key bindings, clear status area if no error occurs. (Implementation detail: we clear it beforehand). ------------------------------------------------------------------------ r742 | ajapted | 2013-01-24 21:32:17 +1100 (Thu, 24 Jan 2013) | 2 lines SEC_Merge: beep at user if only 1 sector was selected. ------------------------------------------------------------------------ r741 | ajapted | 2013-01-24 16:56:20 +1100 (Thu, 24 Jan 2013) | 3 lines Version bump, in honor of new key binding system (all hard-coded keys, except for digits and the menus, are now handled via key bindings). ------------------------------------------------------------------------ r740 | ajapted | 2013-01-24 15:57:37 +1100 (Thu, 24 Jan 2013) | 2 lines Fixed missing "else" in R3D_Set() function. ------------------------------------------------------------------------ r739 | ajapted | 2013-01-24 15:56:43 +1100 (Thu, 24 Jan 2013) | 2 lines Implemented new '3D_Set' binding command. ------------------------------------------------------------------------ r738 | ajapted | 2013-01-24 15:55:02 +1100 (Thu, 24 Jan 2013) | 2 lines Fixed some bugs in CMD_Set(). ------------------------------------------------------------------------ r737 | ajapted | 2013-01-24 15:43:48 +1100 (Thu, 24 Jan 2013) | 3 lines 1. implemented '3D_Toggle' binding command 2. removed the now-dead Render3D_Key() function ------------------------------------------------------------------------ r736 | ajapted | 2013-01-24 15:42:38 +1100 (Thu, 24 Jan 2013) | 2 lines Tidying of the CMD_Toggle() and CMD_Set() code. ------------------------------------------------------------------------ r735 | ajapted | 2013-01-24 15:30:16 +1100 (Thu, 24 Jan 2013) | 2 lines bindings.cfg : fixed wrong comment syntax ------------------------------------------------------------------------ r734 | ajapted | 2013-01-24 15:28:09 +1100 (Thu, 24 Jan 2013) | 3 lines Implemented more render binding commands: '3D_Up', '3D_Down', '3D_Turn', '3D_DropToFloor' and '3D_Gamma'. ------------------------------------------------------------------------ r733 | ajapted | 2013-01-24 14:43:31 +1100 (Thu, 24 Jan 2013) | 3 lines Implemented four binding commands for renderer: '3D_Forward', '3D_Backward', '3D_Left' and '3D_Right'. ------------------------------------------------------------------------ r732 | ajapted | 2013-01-24 14:23:17 +1100 (Thu, 24 Jan 2013) | 3 lines Fixed missing 'SEC_SwapFlats' registration (I must have clobbered it accidentally in an earlier commit). ------------------------------------------------------------------------ r731 | ajapted | 2013-01-24 14:14:17 +1100 (Thu, 24 Jan 2013) | 3 lines 1. implemented 'JumpToObject' binding command 2. removed the now-dead Editor_Key() code ------------------------------------------------------------------------ r730 | ajapted | 2013-01-24 13:31:03 +1100 (Thu, 24 Jan 2013) | 3 lines Added Editor_DigitKey() function to handle digit keys (which do not use the key binding system). ------------------------------------------------------------------------ r729 | ajapted | 2013-01-24 13:24:18 +1100 (Thu, 24 Jan 2013) | 3 lines Implemented "grid" and "snap" variables for 'Toggle' and 'Set' binding commands. ------------------------------------------------------------------------ r728 | ajapted | 2013-01-24 13:11:53 +1100 (Thu, 24 Jan 2013) | 2 lines Implemented 'GRID_Step' binding command. ------------------------------------------------------------------------ r727 | ajapted | 2013-01-24 12:53:24 +1100 (Thu, 24 Jan 2013) | 2 lines Implemented 'Zoom' binding command. ------------------------------------------------------------------------ r726 | ajapted | 2013-01-24 12:46:03 +1100 (Thu, 24 Jan 2013) | 2 lines Implemented 'ZoomWholeMap' and 'ZoomSelection' binding commands. ------------------------------------------------------------------------ r725 | ajapted | 2013-01-24 12:32:17 +1100 (Thu, 24 Jan 2013) | 2 lines Tweaked a few bits of 'long' usage to prevent warnings. ------------------------------------------------------------------------ r724 | ajapted | 2013-01-24 12:24:56 +1100 (Thu, 24 Jan 2013) | 2 lines Changed rgb_color_t typedef to use u32_t (was: unsigned long). ------------------------------------------------------------------------ r723 | ajapted | 2013-01-24 12:23:49 +1100 (Thu, 24 Jan 2013) | 2 lines Removed unused centre_of_sectors() function. ------------------------------------------------------------------------ r722 | ajapted | 2013-01-24 12:18:50 +1100 (Thu, 24 Jan 2013) | 5 lines 1. renamed IsLineDefInside() --> LineCrossesBox(), tidied up the code and replaced 'long' usage 2. removed unused GetObjectCoords() function 3. replaced 'long' usage in GetOppositeSector() ------------------------------------------------------------------------ r721 | ajapted | 2013-01-23 23:57:42 +1100 (Wed, 23 Jan 2013) | 3 lines Implemented three browser-related binding commands, and removed the no-longer-needed Browser_Key() function. ------------------------------------------------------------------------ r720 | ajapted | 2013-01-23 20:46:04 +1100 (Wed, 23 Jan 2013) | 3 lines 1. implemented 'CMD_SetBrowser' binding command 2. removed dead Global_Key() function ------------------------------------------------------------------------ r719 | ajapted | 2013-01-23 19:48:26 +1100 (Wed, 23 Jan 2013) | 3 lines 1. implemented 'LIN_SelectPath' binding command 2. removed the dead Thing_Key / Sector_Key (etc) functions ------------------------------------------------------------------------ r718 | ajapted | 2013-01-23 19:28:16 +1100 (Wed, 23 Jan 2013) | 3 lines 1. implemented 'LIN_Flip' and 'LIN_SplitHalf' binding commands 2. changed binding of LIN_SplitHalf from 'x' --> 'k' ------------------------------------------------------------------------ r717 | ajapted | 2013-01-23 19:12:53 +1100 (Wed, 23 Jan 2013) | 3 lines 1. Use ExecuteCommand() for some menu functions 2. added some Beep() error messages ------------------------------------------------------------------------ r716 | ajapted | 2013-01-23 16:53:24 +1100 (Wed, 23 Jan 2013) | 2 lines Implemented 'CopyProperties' binding command. ------------------------------------------------------------------------ r715 | ajapted | 2013-01-23 16:45:04 +1100 (Wed, 23 Jan 2013) | 3 lines 1. renamed EXEC_Result --> EXEC_Errno 2. set EXEC_Errno to 1 in the Beep() error function ------------------------------------------------------------------------ r714 | ajapted | 2013-01-23 16:40:45 +1100 (Wed, 23 Jan 2013) | 3 lines 1. added EXEC_Result global, for testing if a command failed 2. implemented an ExecuteCommand() function ------------------------------------------------------------------------ r713 | ajapted | 2013-01-23 15:08:41 +1100 (Wed, 23 Jan 2013) | 3 lines SEC_SelectGroup : implemented new 'w' flag, perform a walking test (i.e. don't spread selection across lines which block the player). ------------------------------------------------------------------------ r712 | ajapted | 2013-01-23 14:56:10 +1100 (Wed, 23 Jan 2013) | 4 lines Implemented 'SEC_SelectGroup' binding command, and expanding the matching capabilities to support matching the light, tag and special values, and also have a flag to allow passing through doors. ------------------------------------------------------------------------ r711 | ajapted | 2013-01-23 12:59:05 +1100 (Wed, 23 Jan 2013) | 3 lines Support "3d" and "browser" variables with 'Toggle' and 'Set' binding commands. This replaces the 'Toggle3D' and 'ToggleBrowser' commands. ------------------------------------------------------------------------ r710 | ajapted | 2013-01-23 12:31:05 +1100 (Wed, 23 Jan 2013) | 2 lines Implemented 'SEC_Floor' and 'SEC_Ceil' binding commands. ------------------------------------------------------------------------ r709 | ajapted | 2013-01-23 11:13:31 +1100 (Wed, 23 Jan 2013) | 2 lines Implemented 'GoToCamera' and 'PlaceCamera' binding commands. ------------------------------------------------------------------------ r708 | ajapted | 2013-01-23 10:57:03 +1100 (Wed, 23 Jan 2013) | 3 lines Implemented new 'Set' binding command, this can set a variable to a particular value. Only one variable "obj_nums" is supported so far. ------------------------------------------------------------------------ r707 | ajapted | 2013-01-23 10:48:00 +1100 (Wed, 23 Jan 2013) | 4 lines Implemented 'Toggle' binding command, which takes a variable name to toggle. Current variables are "obj_nums" and "skills". This replaces the previous 'ToggleObjNums' command. ------------------------------------------------------------------------ r706 | ajapted | 2013-01-22 22:59:16 +1100 (Tue, 22 Jan 2013) | 2 lines Implemented the 'Delete' binding command, with optional "keep" parameter. ------------------------------------------------------------------------ r705 | ajapted | 2013-01-22 22:57:14 +1100 (Tue, 22 Jan 2013) | 4 lines Fixed two bugs in M_ParseKeyString() :- 1. the "SHIFT-" modifier had the wrong value 2. keys found in the table did not apply any modifier mask ------------------------------------------------------------------------ r704 | ajapted | 2013-01-22 22:48:47 +1100 (Tue, 22 Jan 2013) | 3 lines Keys: fixed bug in M_TranslateKey() -- don't use ispunct() on keys which are not ASCII (especially values like FL_BackSpace). ------------------------------------------------------------------------ r703 | ajapted | 2013-01-22 18:56:04 +1100 (Tue, 22 Jan 2013) | 3 lines 1. removed last vestiges of 'keymod_e' and KM_XXX 2. renamed some editor functions to have "Editor_" prefix ------------------------------------------------------------------------ r702 | ajapted | 2013-01-22 18:21:50 +1100 (Tue, 22 Jan 2013) | 5 lines 1. define PACKEDATTR in sys_macro.h -- source was Chocolate-Doom 2. added PACKEDATTR macro to all the raw on-disk structures, which may be needed on certain systems (especially 64-bit systems). ------------------------------------------------------------------------ r701 | ajapted | 2013-01-22 14:26:53 +1100 (Tue, 22 Jan 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r700 | ajapted | 2013-01-22 14:26:11 +1100 (Tue, 22 Jan 2013) | 2 lines Implemented 'Insert' binding command. ------------------------------------------------------------------------ r699 | ajapted | 2013-01-22 14:08:29 +1100 (Tue, 22 Jan 2013) | 3 lines Implemented a 'Nothing' command binding, as the name suggests it does nothing at all -- possibly more useful than it sounds. ------------------------------------------------------------------------ r698 | ajapted | 2013-01-22 14:04:56 +1100 (Tue, 22 Jan 2013) | 3 lines Implemented 'Merge' binding command for things, which places all the selected things at a single location. ------------------------------------------------------------------------ r697 | ajapted | 2013-01-22 12:21:29 +1100 (Tue, 22 Jan 2013) | 3 lines Things: new logic for 'Disconnect' -- the semantics are to move apart things at the same location (or very close). ------------------------------------------------------------------------ r696 | ajapted | 2013-01-22 10:44:39 +1100 (Tue, 22 Jan 2013) | 2 lines Added or tweaked some Beep() messages. ------------------------------------------------------------------------ r695 | ajapted | 2013-01-22 10:43:28 +1100 (Tue, 22 Jan 2013) | 4 lines Things: worked on 'Disconnect' for things, which will separate things which are overlapping each other. The logic in this commit is rather flawed though... ------------------------------------------------------------------------ r694 | ajapted | 2013-01-22 09:55:10 +1100 (Tue, 22 Jan 2013) | 4 lines Implemented 'Merge' and 'Disconnect' binding commands, which are used for every mode ("global" context). These replace the mode-specific binding commands like 'LIN_MergeTwo'. ------------------------------------------------------------------------ r693 | ajapted | 2013-01-22 09:49:08 +1100 (Tue, 22 Jan 2013) | 1 line minor tweak ------------------------------------------------------------------------ r692 | ajapted | 2013-01-21 13:09:26 +1100 (Mon, 21 Jan 2013) | 4 lines Key handling / M_SaveBindings: 1. fixed bug writing an 'UNBOUND' key multiple times 2. aesthetic change : no contiguous blank lines ------------------------------------------------------------------------ r691 | ajapted | 2013-01-21 12:59:36 +1100 (Mon, 21 Jan 2013) | 1 line tweak ------------------------------------------------------------------------ r690 | ajapted | 2013-01-21 12:58:36 +1100 (Mon, 21 Jan 2013) | 6 lines Key handling: 1. when writing the local bindings.cfg, skip bindings which are exactly the same as one from the install_dir 2. detect un-bound keys and write them using "UNBOUND" as the command 3. parse this "UNBOUND" keyword when reading a bindings.cfg ------------------------------------------------------------------------ r689 | ajapted | 2013-01-21 12:23:55 +1100 (Mon, 21 Jan 2013) | 3 lines Key handling: keep an in-memory copy of the install_dir bindings. It will be needed for M_SaveBindings() to only write the differences. ------------------------------------------------------------------------ r688 | ajapted | 2013-01-21 10:38:05 +1100 (Mon, 21 Jan 2013) | 2 lines tidied up Main_key_handler(). ------------------------------------------------------------------------ r687 | ajapted | 2013-01-21 08:53:42 +1100 (Mon, 21 Jan 2013) | 3 lines Key handling: moved translation code to M_TranslateKey() function (out of UI_Canvas::handle_key method). ------------------------------------------------------------------------ r686 | ajapted | 2013-01-21 08:29:28 +1100 (Mon, 21 Jan 2013) | 4 lines 1. replaced map name on info bar with a status box 2. added Status_Set() and Status_Clear() functions 3. updated Beep() to set the status and show message in log ------------------------------------------------------------------------ r685 | ajapted | 2013-01-20 19:05:39 +1100 (Sun, 20 Jan 2013) | 2 lines Implemented 'Scroll' binding command (for scrolling the map view). ------------------------------------------------------------------------ r684 | ajapted | 2013-01-20 18:37:07 +1100 (Sun, 20 Jan 2013) | 2 lines Implemented 'EditMode' binding command. ------------------------------------------------------------------------ r683 | ajapted | 2013-01-20 18:35:16 +1100 (Sun, 20 Jan 2013) | 2 lines tweaks. ------------------------------------------------------------------------ r682 | ajapted | 2013-01-20 16:28:38 +1100 (Sun, 20 Jan 2013) | 4 lines bindings.cfg : 1. fixed key for vertical mirror ('V' not 'v') 2. fixed some command names ------------------------------------------------------------------------ r681 | ajapted | 2013-01-20 16:20:48 +1100 (Sun, 20 Jan 2013) | 2 lines Implemented 'CopyAndPaste' binding command. ------------------------------------------------------------------------ r680 | ajapted | 2013-01-20 16:15:43 +1100 (Sun, 20 Jan 2013) | 7 lines Implemented these binding commands: Mirror (parameter is "horiz" or "vert") Rotate90 (parameter is direction, +1 for acw, -1 for cw) Enlarge (replaces CMD_ScaleObjects, parameter is multiplier) Shrink (replaces CMD_ScaleObjects, parameter is divisor) Quantize ------------------------------------------------------------------------ r679 | ajapted | 2013-01-20 13:14:41 +1100 (Sun, 20 Jan 2013) | 5 lines Implemented following as binding commands: 1. VERT_Merge, VERT_Disconnect 2. LIN_MergeTwo, LIN_Disconnect 3. SEC_Merge, SEC_Disconnect ------------------------------------------------------------------------ r678 | ajapted | 2013-01-20 12:46:06 +1100 (Sun, 20 Jan 2013) | 2 lines Key binding: Implemented 'TH_Spin' command (removed hard-coded 'w' and 'x' keys). ------------------------------------------------------------------------ r677 | ajapted | 2013-01-20 12:36:23 +1100 (Sun, 20 Jan 2013) | 3 lines Key handling: ensure the EXEC_Param[] values are never NULL, use the empty string instead. ------------------------------------------------------------------------ r676 | ajapted | 2013-01-20 12:06:46 +1100 (Sun, 20 Jan 2013) | 2 lines bindings.cfg : tweaked prefixes (e.g. LN --> LIN, GR --> GRID) ------------------------------------------------------------------------ r675 | ajapted | 2013-01-20 10:59:59 +1100 (Sun, 20 Jan 2013) | 2 lines Key handling: merged "edit" and "global" contexts into one (global). ------------------------------------------------------------------------ r674 | ajapted | 2013-01-20 10:36:01 +1100 (Sun, 20 Jan 2013) | 3 lines Key handling: implemented M_RemoveBinding(), and use it to ensure that bindings from the home_dir replace bindings from the install_dir. ------------------------------------------------------------------------ r673 | ajapted | 2013-01-20 10:23:59 +1100 (Sun, 20 Jan 2013) | 5 lines Key handling: 1. load bindings from BOTH install_dir and home_dir paths (otherwise new releases of Eureka would be unable to add new bindings) 2. fixed parsing of double quotes (") in bindings.cfg ------------------------------------------------------------------------ r672 | ajapted | 2013-01-19 21:59:24 +1100 (Sat, 19 Jan 2013) | 2 lines Key handling: un-hard-code the ` (back-quote) key -- rely on binding. ------------------------------------------------------------------------ r671 | ajapted | 2013-01-19 21:57:25 +1100 (Sat, 19 Jan 2013) | 3 lines Key handling: when writing the bindings, group them by their context (a purely aesthetic change). ------------------------------------------------------------------------ r670 | ajapted | 2013-01-19 21:31:19 +1100 (Sat, 19 Jan 2013) | 5 lines Key handling: 1. renamed CMD_SwapFlats --> SEC_SwapFlats 2. made it use key bindings (no hard-coded test against 'w' key) 3. moved M_RegisterCommand() calls into a separate function (editloop.cc) ------------------------------------------------------------------------ r669 | ajapted | 2013-01-19 21:23:30 +1100 (Sat, 19 Jan 2013) | 2 lines tweaked M_ModeToKeyContext() ------------------------------------------------------------------------ r668 | ajapted | 2013-01-19 21:21:23 +1100 (Sat, 19 Jan 2013) | 3 lines Key handling: have EXEC_Param[] global var to contain the parameters from the key binding being executed. ------------------------------------------------------------------------ r667 | ajapted | 2013-01-19 21:15:16 +1100 (Sat, 19 Jan 2013) | 5 lines Key handling: 1. renamed KCTX_INVALID --> KCTX_NONE 2. when registering commands, can specify a required context 3. prevent binding keys to a command in the wrong context ------------------------------------------------------------------------ r666 | ajapted | 2013-01-19 18:48:38 +1100 (Sat, 19 Jan 2013) | 3 lines Key handler: a few commands now rely on new system, e.g. TAB to toggle the 3D view, and 'b' to toggle the browser panel. ------------------------------------------------------------------------ r665 | ajapted | 2013-01-19 18:45:22 +1100 (Sat, 19 Jan 2013) | 7 lines Key handling: use new ExecuteKey() function to handle keys, using the same propagation logic. A few commands now rely on this, e.g. TAB to toggle the 3D view. The existing XXX_Key() functions are still in place, but will only remain during the transition to the new system. ------------------------------------------------------------------------ r664 | ajapted | 2013-01-19 18:40:36 +1100 (Sat, 19 Jan 2013) | 2 lines Key handling: fixed parsing of long key names (like "ESC"). ------------------------------------------------------------------------ r663 | ajapted | 2013-01-19 18:32:38 +1100 (Sat, 19 Jan 2013) | 5 lines Key handling: 1. moved key_context_e enumeration to global scope (header file) 2. added M_ModeToKeyContext() function 3. implemented ExecuteKey() function ------------------------------------------------------------------------ r662 | ajapted | 2013-01-19 15:47:37 +1100 (Sat, 19 Jan 2013) | 2 lines Key handling: finished M_LoadBindings() -- parse each binding and add it. ------------------------------------------------------------------------ r661 | ajapted | 2013-01-19 15:31:46 +1100 (Sat, 19 Jan 2013) | 3 lines Key handling: partial work implementing M_LoadBindings(). This commit just has the code to open the file and read tokens. ------------------------------------------------------------------------ r660 | ajapted | 2013-01-19 14:23:30 +1100 (Sat, 19 Jan 2013) | 3 lines Key handling: handle function and keypad keys in M_ParseKeyString() and M_KeyToString(). ------------------------------------------------------------------------ r659 | ajapted | 2013-01-19 14:10:42 +1100 (Sat, 19 Jan 2013) | 2 lines Key handling: more names for key_map[] table (e.g. VOL_DOWN, CD_PLAY, etc). ------------------------------------------------------------------------ r658 | ajapted | 2013-01-19 14:00:15 +1100 (Sat, 19 Jan 2013) | 4 lines Key handling: added a key_map[] table for mapping special keys from their code to their name or vice versa. ------------------------------------------------------------------------ r657 | ajapted | 2013-01-19 13:25:45 +1100 (Sat, 19 Jan 2013) | 4 lines Key handling: 1. implemented M_WriteBindings() 2. partial work on M_ParseKeyString() and M_KeyToString() ------------------------------------------------------------------------ r656 | ajapted | 2013-01-19 12:52:29 +1100 (Sat, 19 Jan 2013) | 2 lines Makefile: install the 'bindings.cfg' file. ------------------------------------------------------------------------ r655 | ajapted | 2013-01-19 12:45:29 +1100 (Sat, 19 Jan 2013) | 2 lines Added some M_RegisterCommand() calls in Editor_Init(). ------------------------------------------------------------------------ r654 | ajapted | 2013-01-19 12:42:18 +1100 (Sat, 19 Jan 2013) | 2 lines Key handling: changed command_func_t to return 'void' (not 'bool'). ------------------------------------------------------------------------ r653 | ajapted | 2013-01-19 10:41:47 +1100 (Sat, 19 Jan 2013) | 7 lines Key handling (m_keys.cc) : 1. added editor_command_t structure 2. added M_AddEditorCommand() and FindEditorCommand() 3. added key_context_e enumeration 4. added ParseKeyContext() and KeyContextString() functions 5. added key_binding_t structure ------------------------------------------------------------------------ r652 | ajapted | 2013-01-18 21:59:36 +1100 (Fri, 18 Jan 2013) | 2 lines New code files to handle key binding logic : m_keys.cc/h ------------------------------------------------------------------------ r651 | ajapted | 2013-01-18 21:52:26 +1100 (Fri, 18 Jan 2013) | 3 lines Key handling: changed some keymod_e (KM_XXX) usages to use keycode_t (MOD_XXX) defines instead. ------------------------------------------------------------------------ r650 | ajapted | 2013-01-18 21:18:44 +1100 (Fri, 18 Jan 2013) | 2 lines Bindings.txt : simpler format, a few tweaks. ------------------------------------------------------------------------ r649 | ajapted | 2013-01-18 17:11:03 +1100 (Fri, 18 Jan 2013) | 2 lines Finished the list of needed key bindings. ------------------------------------------------------------------------ r648 | ajapted | 2013-01-18 16:42:37 +1100 (Fri, 18 Jan 2013) | 2 lines Partial work on a list of needed key bindings. ------------------------------------------------------------------------ r647 | ajapted | 2013-01-18 16:08:29 +1100 (Fri, 18 Jan 2013) | 3 lines Key handling: convert SHIFT + punctuation key to the shifted value, for example SHIFT + ',' --> '<' ------------------------------------------------------------------------ r646 | ajapted | 2013-01-18 15:55:59 +1100 (Fri, 18 Jan 2013) | 3 lines Updated key handling code (UI_Canvas::handle_key, XXX_Key functions) to use the new keycode_t semantics. ------------------------------------------------------------------------ r645 | ajapted | 2013-01-18 15:35:20 +1100 (Fri, 18 Jan 2013) | 2 lines Updated semantics of keycode_t for digits. ------------------------------------------------------------------------ r644 | ajapted | 2013-01-16 22:16:55 +1100 (Wed, 16 Jan 2013) | 3 lines Added key_code_t typedef (and more importantly, comments defining its semantics). Not used yet, but will be needed for configurable keys... ------------------------------------------------------------------------ r643 | ajapted | 2013-01-15 22:11:41 +1100 (Tue, 15 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r642 | ajapted | 2013-01-15 22:09:55 +1100 (Tue, 15 Jan 2013) | 2 lines Updated some copyright messages for 2013. ------------------------------------------------------------------------ r641 | ajapted | 2013-01-15 22:05:22 +1100 (Tue, 15 Jan 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r640 | ajapted | 2013-01-15 21:28:58 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs and Config: implemented a "default grid mode" setting. ------------------------------------------------------------------------ r639 | ajapted | 2013-01-15 21:05:24 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: implemented 'default_grid_size' setting. ------------------------------------------------------------------------ r638 | ajapted | 2013-01-15 20:52:38 +1100 (Tue, 15 Jan 2013) | 2 lines Grid: removed '192' as a possible grid size. ------------------------------------------------------------------------ r637 | ajapted | 2013-01-15 19:18:17 +1100 (Tue, 15 Jan 2013) | 3 lines Prefs dialog: implemented some of remaining General stuff, such as: default_grid_snap, digits_set_zoom and escape_key_quits. ------------------------------------------------------------------------ r636 | ajapted | 2013-01-15 16:33:40 +1100 (Tue, 15 Jan 2013) | 2 lines Config: added gui_custom_xx color variables. ------------------------------------------------------------------------ r635 | ajapted | 2013-01-15 16:20:40 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: got the theme section of 'General' tab working. ------------------------------------------------------------------------ r634 | ajapted | 2013-01-15 16:03:28 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: got the glBSP settings working. ------------------------------------------------------------------------ r633 | ajapted | 2013-01-15 14:21:08 +1100 (Tue, 15 Jan 2013) | 3 lines Prefs dialog: implemented rest of Editing options (except the modifier key for multi-select has only one choice: CTRL). ------------------------------------------------------------------------ r632 | ajapted | 2013-01-15 14:08:23 +1100 (Tue, 15 Jan 2013) | 4 lines Prefs dialog: 1. call M_WriteConfigFile() to persist the changes 2. implemented one of the settings : new_sector_size ------------------------------------------------------------------------ r631 | ajapted | 2013-01-15 14:04:01 +1100 (Tue, 15 Jan 2013) | 3 lines Config: moved extern declarations into header (m_config.h) so that the preferences code can access them. ------------------------------------------------------------------------ r630 | ajapted | 2013-01-15 13:55:52 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: implemented color_callback(). ------------------------------------------------------------------------ r629 | ajapted | 2013-01-15 13:50:09 +1100 (Tue, 15 Jan 2013) | 3 lines Prefs dialog: make initial tab be the first one, and remember the last active tab for next time preferences dialog is opened. ------------------------------------------------------------------------ r628 | ajapted | 2013-01-15 13:29:10 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: implemented callback for OK button and window close. ------------------------------------------------------------------------ r627 | ajapted | 2013-01-15 13:28:28 +1100 (Tue, 15 Jan 2013) | 1 line layout tweak ------------------------------------------------------------------------ r626 | ajapted | 2013-01-15 12:34:10 +1100 (Tue, 15 Jan 2013) | 3 lines EUREKA lump: better iwad check when a resource cannot be found (i.e. use the IWAD path for the game specified in the lump, not Iwad_name). ------------------------------------------------------------------------ r625 | ajapted | 2013-01-15 12:24:53 +1100 (Tue, 15 Jan 2013) | 2 lines docco tweaks. ------------------------------------------------------------------------ r624 | ajapted | 2013-01-15 12:19:24 +1100 (Tue, 15 Jan 2013) | 3 lines Prefs dialog: inserted the code generated by fluid (from prefs2.fl), with some tidying and adding missing fields and methods. ------------------------------------------------------------------------ r623 | ajapted | 2013-01-15 12:03:19 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: started work on it, e.g. the basic Run() method. ------------------------------------------------------------------------ r622 | ajapted | 2013-01-15 11:50:35 +1100 (Tue, 15 Jan 2013) | 4 lines About dialog: reworked code, use an '_instance' field to keep track of the current window, and allow the rest of the application to function while it is open (i.e. it is _not_ modal). ------------------------------------------------------------------------ r621 | ajapted | 2013-01-15 10:33:13 +1100 (Tue, 15 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r620 | ajapted | 2013-01-15 10:25:36 +1100 (Tue, 15 Jan 2013) | 2 lines CHANGELOG: created a fresh one (after 0.88c release). ------------------------------------------------------------------------ r619 | ajapted | 2013-01-15 10:20:53 +1100 (Tue, 15 Jan 2013) | 3 lines When parsing the EUREKA lump and a resource wad cannot be found, look for it same directory as the PWAD, then try same dir as the IWAD. ------------------------------------------------------------------------ r618 | ajapted | 2013-01-15 10:18:26 +1100 (Tue, 15 Jan 2013) | 2 lines File utils: fixed some bugs in FileReposition(). ------------------------------------------------------------------------ r617 | ajapted | 2013-01-15 10:06:08 +1100 (Tue, 15 Jan 2013) | 3 lines File utils: implemented FilenameReposition() function, which takes a filename and replaces its path with the path from another filename. ------------------------------------------------------------------------ r616 | ajapted | 2013-01-10 22:47:36 +1100 (Thu, 10 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r615 | ajapted | 2013-01-06 19:34:04 +1100 (Sun, 06 Jan 2013) | 2 lines more TO-DO goodies... ------------------------------------------------------------------------ r614 | ajapted | 2013-01-04 12:58:27 +1100 (Fri, 04 Jan 2013) | 2 lines Version bump after 0.88c release. ------------------------------------------------------------------------ r613 | ajapted | 2013-01-04 12:57:24 +1100 (Fri, 04 Jan 2013) | 2 lines README.txt : added my SF email address. ------------------------------------------------------------------------ r612 | ajapted | 2013-01-04 12:56:59 +1100 (Fri, 04 Jan 2013) | 2 lines Debian: control tweak ------------------------------------------------------------------------ r611 | ajapted | 2013-01-04 12:56:29 +1100 (Fri, 04 Jan 2013) | 2 lines Moved CHANGES.txt --> docs/ folder, after 0.88c release. ------------------------------------------------------------------------ r610 | ajapted | 2013-01-04 12:55:45 +1100 (Fri, 04 Jan 2013) | 2 lines CHANGELOG tweak. ------------------------------------------------------------------------ r609 | ajapted | 2013-01-04 12:55:19 +1100 (Fri, 04 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r608 | ajapted | 2013-01-02 15:26:44 +1100 (Wed, 02 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r607 | ajapted | 2012-12-27 21:03:42 +1100 (Thu, 27 Dec 2012) | 2 lines TODO.txt : document logic for texture alignment keys. ------------------------------------------------------------------------ r606 | ajapted | 2012-12-26 21:08:54 +1100 (Wed, 26 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r605 | ajapted | 2012-12-26 19:08:02 +1100 (Wed, 26 Dec 2012) | 2 lines TODO update (fixed the slime trails). ------------------------------------------------------------------------ r604 | ajapted | 2012-12-26 19:06:11 +1100 (Wed, 26 Dec 2012) | 2 lines Makefile: made 'uninstall' also remove the desktop and icon files. ------------------------------------------------------------------------ r603 | ajapted | 2012-12-26 18:44:19 +1100 (Wed, 26 Dec 2012) | 3 lines 3D View: implemented even better DistCmp() logic, which has eliminated nearly all trails. ------------------------------------------------------------------------ r602 | ajapted | 2012-12-26 18:12:10 +1100 (Wed, 26 Dec 2012) | 2 lines 3D View: reduced the slime trails. ------------------------------------------------------------------------ r601 | ajapted | 2012-12-26 16:17:53 +1100 (Wed, 26 Dec 2012) | 2 lines Coding: simpler usage of Fl_Sys_Menu_Bar. ------------------------------------------------------------------------ r600 | ajapted | 2012-12-26 16:17:11 +1100 (Wed, 26 Dec 2012) | 2 lines Dead code removal (ui_menu.cc) ------------------------------------------------------------------------ r599 | ajapted | 2012-12-24 22:23:01 +1100 (Mon, 24 Dec 2012) | 2 lines Renamed WISHLIST.txt --> TODO.txt ------------------------------------------------------------------------ r598 | ajapted | 2012-12-24 22:21:49 +1100 (Mon, 24 Dec 2012) | 2 lines Removed TODO.txt file : about to rename WISHLIST --> TODO... ------------------------------------------------------------------------ r597 | ajapted | 2012-12-24 22:18:25 +1100 (Mon, 24 Dec 2012) | 2 lines WISHLIST update. ------------------------------------------------------------------------ r596 | ajapted | 2012-12-24 22:17:25 +1100 (Mon, 24 Dec 2012) | 1 line tweak ------------------------------------------------------------------------ r595 | ajapted | 2012-12-24 22:16:30 +1100 (Mon, 24 Dec 2012) | 5 lines Debian: updated control file: 1. removed libfltk1.3 as a dependency (statically linked now) 2. added various dependencies, esp. X window stuff 3. bumped version ------------------------------------------------------------------------ r594 | ajapted | 2012-12-24 22:14:49 +1100 (Mon, 24 Dec 2012) | 2 lines Debian: updated Makefile to "install" the eureka desktop file and icon. ------------------------------------------------------------------------ r593 | ajapted | 2012-12-24 19:22:34 +1100 (Mon, 24 Dec 2012) | 4 lines Makefile: support for static linking with an FLTK which does not include OpenGL support and which uses 'localjpeg' and 'localpng' configuration. That is conditional on FLTK_STATIC being defined. ------------------------------------------------------------------------ r592 | ajapted | 2012-12-24 19:18:58 +1100 (Mon, 24 Dec 2012) | 3 lines Manage Wads dialog: fixed bug where the selected port reset to 'boom' unless the user selected something in the choice button. ------------------------------------------------------------------------ r591 | ajapted | 2012-12-24 16:54:40 +1100 (Mon, 24 Dec 2012) | 2 lines PORT defs: tweaks. ------------------------------------------------------------------------ r590 | ajapted | 2012-12-24 16:53:49 +1100 (Mon, 24 Dec 2012) | 2 lines AUTHORS.txt updated. ------------------------------------------------------------------------ r589 | ajapted | 2012-12-24 16:50:52 +1100 (Mon, 24 Dec 2012) | 2 lines LineDef panel: minor rename: 'pass use' --> 'pass thru' ------------------------------------------------------------------------ r588 | ajapted | 2012-12-24 15:47:37 +1100 (Mon, 24 Dec 2012) | 3 lines PORTS: added Doom Legacy definition 'legacy.ugh', by wesleyjohnson (with a few tweaks by me). ------------------------------------------------------------------------ r587 | ajapted | 2012-12-24 12:13:04 +1100 (Mon, 24 Dec 2012) | 3 lines Fix (hopefully) for compile error on 64-bit targets: casting a 'void*' to an 'int' losing precision. ------------------------------------------------------------------------ r586 | ajapted | 2012-12-23 18:24:18 +1100 (Sun, 23 Dec 2012) | 2 lines CHANGELOG: added revision numbers and "Changes since ..." line. ------------------------------------------------------------------------ r585 | ajapted | 2012-12-23 16:12:45 +1100 (Sun, 23 Dec 2012) | 3 lines Docs: created a single file with all the repository commit history, namely the 'docs/History.txt' file. Hence removed the other copies. ------------------------------------------------------------------------ r584 | ajapted | 2012-12-23 14:55:34 +1100 (Sun, 23 Dec 2012) | 2 lines WISHLIST update. ------------------------------------------------------------------------ r583 | ajapted | 2012-12-23 14:23:56 +1100 (Sun, 23 Dec 2012) | 2 lines Changed '__EUREKA' lump format, store 'game' instead than an iwad path. ------------------------------------------------------------------------ r582 | ajapted | 2012-12-23 14:09:25 +1100 (Sun, 23 Dec 2012) | 6 lines Handle the '__EUREKA' lump a lot more robustly: 1. if the game is unsupported, warn user with a choice: ignore/cancel 2. if iwad is not found, but it is known, use the known path 3. if iwad cannot be found at all, warn user with a choice: ignore/cancel 4. log some warnings on syntax errors ------------------------------------------------------------------------ r581 | ajapted | 2012-12-23 12:33:07 +1100 (Sun, 23 Dec 2012) | 4 lines Updated handing of '__EUREKA' lump, the M_ParseEurekaLump() can now return false (e.g. when the iwad cannot be found) -- hence need to be able to cancel the OpenMap or OpenRecentMap command. ------------------------------------------------------------------------ r580 | ajapted | 2012-12-22 22:27:32 +1100 (Sat, 22 Dec 2012) | 2 lines tweaked pack-source script ------------------------------------------------------------------------ r579 | ajapted | 2012-12-22 17:54:38 +1100 (Sat, 22 Dec 2012) | 2 lines README.txt : tweaked a few things, updated keyboard controls. ------------------------------------------------------------------------ r578 | ajapted | 2012-12-22 17:43:49 +1100 (Sat, 22 Dec 2012) | 2 lines INSTALL.txt : small update to setting up section. ------------------------------------------------------------------------ r577 | ajapted | 2012-12-22 17:39:54 +1100 (Sat, 22 Dec 2012) | 2 lines svn ignorations ------------------------------------------------------------------------ r576 | ajapted | 2012-12-22 17:17:53 +1100 (Sat, 22 Dec 2012) | 2 lines TODO updated. ------------------------------------------------------------------------ r575 | ajapted | 2012-12-22 17:15:01 +1100 (Sat, 22 Dec 2012) | 2 lines INSTALL.txt : tweak ------------------------------------------------------------------------ r574 | ajapted | 2012-12-22 17:09:12 +1100 (Sat, 22 Dec 2012) | 2 lines MacOSX: home_dir changed to '~/Library/Application Support/eureka-editor' ------------------------------------------------------------------------ r573 | ajapted | 2012-12-22 17:07:43 +1100 (Sat, 22 Dec 2012) | 2 lines Version bumped to 0.88 -- ready for release. ------------------------------------------------------------------------ r572 | ajapted | 2012-12-17 23:14:55 +1100 (Mon, 17 Dec 2012) | 2 lines WISHLIST update. ------------------------------------------------------------------------ r571 | ajapted | 2012-12-17 23:13:08 +1100 (Mon, 17 Dec 2012) | 2 lines CHANGELOG: updated, e.g. group View menu stuff together. ------------------------------------------------------------------------ r570 | ajapted | 2012-12-17 23:05:22 +1100 (Mon, 17 Dec 2012) | 3 lines Copy'n'paste: properly assign a new middle texture for linedefs which lose a sidedef (because the sector no longer exists). ------------------------------------------------------------------------ r569 | ajapted | 2012-12-17 22:51:56 +1100 (Mon, 17 Dec 2012) | 3 lines Copy'n'paste: when pasting, flip linedefs that would otherwise end up with only a left side (no right side). ------------------------------------------------------------------------ r568 | ajapted | 2012-12-17 15:12:24 +1100 (Mon, 17 Dec 2012) | 2 lines Error message tweak. ------------------------------------------------------------------------ r567 | ajapted | 2012-12-17 15:08:59 +1100 (Mon, 17 Dec 2012) | 2 lines comment tweak ------------------------------------------------------------------------ r566 | ajapted | 2012-12-17 15:07:46 +1100 (Mon, 17 Dec 2012) | 3 lines main: moved IWAD handling into a DetermineIWAD() function, and make sure that the --iwad parameter not only exists but is a supported game. ------------------------------------------------------------------------ r565 | ajapted | 2012-12-17 14:46:59 +1100 (Mon, 17 Dec 2012) | 2 lines Info bar: when map is changed, draw a '*' next to the map name. ------------------------------------------------------------------------ r564 | ajapted | 2012-12-17 14:22:00 +1100 (Mon, 17 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r563 | ajapted | 2012-12-17 14:21:37 +1100 (Mon, 17 Dec 2012) | 2 lines Support for --iwad parameter being a bare game name. ------------------------------------------------------------------------ r562 | ajapted | 2012-12-17 14:11:52 +1100 (Mon, 17 Dec 2012) | 2 lines File utilities: added FilenameIsBare() function. ------------------------------------------------------------------------ r561 | ajapted | 2012-12-17 13:55:17 +1100 (Mon, 17 Dec 2012) | 4 lines If the --iwad parameter is missing an extension, add ".wad". Removed the obsolete DetermineIWAD() code. ------------------------------------------------------------------------ r560 | ajapted | 2012-12-17 12:18:24 +1100 (Mon, 17 Dec 2012) | 2 lines INSTALL.txt : updated the 'Setting Up' section. ------------------------------------------------------------------------ r559 | ajapted | 2012-12-17 12:02:48 +1100 (Mon, 17 Dec 2012) | 2 lines docco tweaks. ------------------------------------------------------------------------ r558 | ajapted | 2012-12-17 11:42:09 +1100 (Mon, 17 Dec 2012) | 2 lines m_files.h needed a forward declaration -- patch courtesy Jeremy Henty. ------------------------------------------------------------------------ r557 | ajapted | 2012-12-17 11:35:36 +1100 (Mon, 17 Dec 2012) | 4 lines HACX things: 1. added missing BRS1 (mummy) and BAR1 (nitro canister) things 2. added two categories: 'Gore' and 'Natural' ------------------------------------------------------------------------ r556 | ajapted | 2012-12-16 20:21:43 +1100 (Sun, 16 Dec 2012) | 2 lines WISHLIST update (e.g. backup system) ------------------------------------------------------------------------ r555 | ajapted | 2012-12-16 20:14:40 +1100 (Sun, 16 Dec 2012) | 2 lines CHANGELOG: update ------------------------------------------------------------------------ r554 | ajapted | 2012-12-16 20:12:21 +1100 (Sun, 16 Dec 2012) | 2 lines HACX: added a lot of missing things. ------------------------------------------------------------------------ r553 | ajapted | 2012-12-16 19:18:06 +1100 (Sun, 16 Dec 2012) | 2 lines HACX: fixed names of powerups (based on the pickup messages). ------------------------------------------------------------------------ r552 | ajapted | 2012-12-16 19:12:32 +1100 (Sun, 16 Dec 2012) | 2 lines Grid: changed default step yet again ---> 64 ------------------------------------------------------------------------ r551 | ajapted | 2012-12-16 16:17:39 +1100 (Sun, 16 Dec 2012) | 2 lines HACX: changed the default textures. ------------------------------------------------------------------------ r550 | ajapted | 2012-12-16 16:06:25 +1100 (Sun, 16 Dec 2012) | 2 lines HACX: added more things (decorations), and fixed a few bugs. ------------------------------------------------------------------------ r549 | ajapted | 2012-12-16 12:13:41 +1100 (Sun, 16 Dec 2012) | 2 lines Game defs: began work on HACX definition file. ------------------------------------------------------------------------ r548 | ajapted | 2012-12-16 11:52:06 +1100 (Sun, 16 Dec 2012) | 2 lines tweaked some warning messages ------------------------------------------------------------------------ r547 | ajapted | 2012-12-16 11:32:27 +1100 (Sun, 16 Dec 2012) | 2 lines dead code removal ------------------------------------------------------------------------ r546 | ajapted | 2012-12-15 22:43:37 +1100 (Sat, 15 Dec 2012) | 2 lines TODO and WISHLIST update. ------------------------------------------------------------------------ r545 | ajapted | 2012-12-15 22:42:14 +1100 (Sat, 15 Dec 2012) | 2 lines Moved file 'New_Workflow.txt' out of docs/ ------------------------------------------------------------------------ r544 | ajapted | 2012-12-15 22:26:03 +1100 (Sat, 15 Dec 2012) | 2 lines Menu: disabled the unimplemented Preferences command. ------------------------------------------------------------------------ r543 | ajapted | 2012-12-15 21:17:28 +1100 (Sat, 15 Dec 2012) | 2 lines Menu: disabled the unimplemented 'Find' and 'Find Next' commands. ------------------------------------------------------------------------ r542 | ajapted | 2012-12-15 20:16:08 +1100 (Sat, 15 Dec 2012) | 2 lines CHANGELOG: added all the recent 'Manage Wads' work... ------------------------------------------------------------------------ r541 | ajapted | 2012-12-15 20:06:58 +1100 (Sat, 15 Dec 2012) | 2 lines minor rename: CMD_PlayMap --> CMD_TestMap ------------------------------------------------------------------------ r540 | ajapted | 2012-12-15 20:03:23 +1100 (Sat, 15 Dec 2012) | 2 lines Added doc about level checking: misc/Checks.txt ------------------------------------------------------------------------ r539 | ajapted | 2012-12-15 16:06:55 +1100 (Sat, 15 Dec 2012) | 2 lines CMD_OpenMap / OpenRecentMap : handle the '__EUREKA' lump. ------------------------------------------------------------------------ r538 | ajapted | 2012-12-15 15:13:31 +1100 (Sat, 15 Dec 2012) | 2 lines tweaks for '__EUREKA' lump handling... ------------------------------------------------------------------------ r537 | ajapted | 2012-12-15 15:11:56 +1100 (Sat, 15 Dec 2012) | 2 lines Wad code: implemented Lump_c::GetLine() method. ------------------------------------------------------------------------ r536 | ajapted | 2012-12-15 14:57:04 +1100 (Sat, 15 Dec 2012) | 4 lines The __EUREKA lump: 1. implemented parsing code 2. fixed missing 'lump->Finish()' in writing code ------------------------------------------------------------------------ r535 | ajapted | 2012-12-15 14:10:57 +1100 (Sat, 15 Dec 2012) | 3 lines Worked on support for '__EUREKA' lump, which contains the project info (the IWAD, port and resource wads). So far, can only create the lump. ------------------------------------------------------------------------ r534 | ajapted | 2012-12-15 14:04:29 +1100 (Sat, 15 Dec 2012) | 2 lines Wad code: added Lump_c::Printf() method. ------------------------------------------------------------------------ r533 | ajapted | 2012-12-15 13:29:53 +1100 (Sat, 15 Dec 2012) | 3 lines Manage Wads dialog: implemented code for 'Find' button which repopulates the iwad choice button with the known iwads. ------------------------------------------------------------------------ r532 | ajapted | 2012-12-14 21:47:11 +1100 (Fri, 14 Dec 2012) | 2 lines Manage Wads dialog: more work on this delightful little f.... ------------------------------------------------------------------------ r531 | ajapted | 2012-12-14 21:13:53 +1100 (Fri, 14 Dec 2012) | 2 lines TODO / WISHLIST update. ------------------------------------------------------------------------ r530 | ajapted | 2012-12-14 21:07:33 +1100 (Fri, 14 Dec 2012) | 3 lines Manage Wads dialog: tweaked startup message, using a red background and yellow text which makes it very striking. ------------------------------------------------------------------------ r529 | ajapted | 2012-12-14 20:55:08 +1100 (Fri, 14 Dec 2012) | 3 lines Worked on showing the Manage Wads dialog at startup when no iwads were found. Also, properly setup Iwad_name (etc) from that dialog. ------------------------------------------------------------------------ r528 | ajapted | 2012-12-14 20:37:49 +1100 (Fri, 14 Dec 2012) | 2 lines Utilities: allow passing NULL to StringDup() -- just return NULL. ------------------------------------------------------------------------ r527 | ajapted | 2012-12-14 20:16:57 +1100 (Fri, 14 Dec 2012) | 2 lines When Iwad_name is unset, try to pick a sensible default. ------------------------------------------------------------------------ r526 | ajapted | 2012-12-14 20:15:27 +1100 (Fri, 14 Dec 2012) | 3 lines Implemented M_PickDefaultIWAD() -- guesses either DOOM or DOOM2 based on level names (if any), and as last resource picks any known iwad. ------------------------------------------------------------------------ r525 | ajapted | 2012-12-14 19:50:38 +1100 (Fri, 14 Dec 2012) | 4 lines Worked on getting the startup sequence in main() sorted out, e.g. we now load the PWAD (but not the map) before other stuff so that the __EUREKA lump can be handled appropriately. ------------------------------------------------------------------------ r524 | ajapted | 2012-12-14 19:24:53 +1100 (Fri, 14 Dec 2012) | 2 lines Added EUREKA_LUMP define, bumped version. ------------------------------------------------------------------------ r523 | ajapted | 2012-12-14 17:18:06 +1100 (Fri, 14 Dec 2012) | 4 lines Removed the unused 'remind_to_build_nodes' stuff, I think for Eureka such a dialog could be really annoying -- for Yadex it was OK since the message was merely printed to the terminal. ------------------------------------------------------------------------ r522 | ajapted | 2012-12-14 15:25:58 +1100 (Fri, 14 Dec 2012) | 2 lines fixed bug in SearchDirForIWAD (need ".wad" extenstion) ------------------------------------------------------------------------ r521 | ajapted | 2012-12-14 13:45:18 +1100 (Fri, 14 Dec 2012) | 4 lines Worked on new M_LookForIWADs() code which looks for each game iwad in various places and updates the known_iwads list when found. This involves moving some code (e.g. SearchDirForIWAD) into m_files.cc. ------------------------------------------------------------------------ r520 | ajapted | 2012-12-14 13:40:10 +1100 (Fri, 14 Dec 2012) | 2 lines Fixed FatalError() messages which lacked a trailing newline. ------------------------------------------------------------------------ r519 | ajapted | 2012-12-14 13:18:15 +1100 (Fri, 14 Dec 2012) | 2 lines Ensure recent filenames and known iwad filenames are absolute. ------------------------------------------------------------------------ r518 | ajapted | 2012-12-14 13:04:23 +1100 (Fri, 14 Dec 2012) | 2 lines debugging fix. ------------------------------------------------------------------------ r517 | ajapted | 2012-12-14 13:00:07 +1100 (Fri, 14 Dec 2012) | 2 lines When loading recent files and known iwads, check the file still exists. ------------------------------------------------------------------------ r516 | ajapted | 2012-12-14 12:57:08 +1100 (Fri, 14 Dec 2012) | 2 lines Implemented parsing logic for "misc.cfg" -- recent wads and known iwads. ------------------------------------------------------------------------ r515 | ajapted | 2012-12-14 12:04:45 +1100 (Fri, 14 Dec 2012) | 3 lines Worked on saving known iwads in the 'misc.cfg' file, and changed the format of the recent files. Loading is not done yet... ------------------------------------------------------------------------ r514 | ajapted | 2012-12-14 10:52:57 +1100 (Fri, 14 Dec 2012) | 4 lines Project Setup dialog: 1. properly setup the 'Game IWAD' choice, using the known iwads list 2. fixed window close button (use close_callback) ------------------------------------------------------------------------ r513 | ajapted | 2012-12-14 10:46:29 +1100 (Fri, 14 Dec 2012) | 3 lines Known iwads: implemented function to return '|'-separated list of game names, namely M_KnownIWADsForMenu(). ------------------------------------------------------------------------ r512 | ajapted | 2012-12-13 22:47:49 +1100 (Thu, 13 Dec 2012) | 2 lines Known iwads: implemented M_AddKnownIWAD() and M_QueryrKnownIWAD() functions. ------------------------------------------------------------------------ r511 | ajapted | 2012-12-13 20:28:57 +1100 (Thu, 13 Dec 2012) | 2 lines Bound '\' key to cycle categories in the browser. ------------------------------------------------------------------------ r510 | ajapted | 2012-12-13 20:09:03 +1100 (Thu, 13 Dec 2012) | 2 lines Renamed recent.cfg --> misc.cfg [it will contain other stuff too] ------------------------------------------------------------------------ r509 | ajapted | 2012-12-13 20:00:01 +1100 (Thu, 13 Dec 2012) | 5 lines Config handling: 1. have a 'v' flag for real variables (only those are written out) 2. hence no need for 'h' flag -- removed 3. tweaked the --help descriptions (esp. for merge) ------------------------------------------------------------------------ r508 | ajapted | 2012-12-13 19:46:51 +1100 (Thu, 13 Dec 2012) | 2 lines Config handling: implemented M_WriteConfigFile(). ------------------------------------------------------------------------ r507 | ajapted | 2012-12-13 19:21:53 +1100 (Thu, 13 Dec 2012) | 3 lines Config handling: minor function rename, e.g. M_ParseConfigFile() and M_ParseCommandLine(), and rejiggage of how they are called. ------------------------------------------------------------------------ r506 | ajapted | 2012-12-13 16:49:51 +1100 (Thu, 13 Dec 2012) | 2 lines part (b) of renamed code files: m_recent --> m_files ------------------------------------------------------------------------ r505 | ajapted | 2012-12-13 15:53:02 +1100 (Thu, 13 Dec 2012) | 2 lines Renamed code file: m_recent.cc/h --> m_files.cc/h ------------------------------------------------------------------------ r504 | ajapted | 2012-12-13 15:42:42 +1100 (Thu, 13 Dec 2012) | 2 lines Game defs: implemented M_CollectKnownDefs() function. ------------------------------------------------------------------------ r503 | ajapted | 2012-12-13 15:22:18 +1100 (Thu, 13 Dec 2012) | 3 lines M_CollectDefsForMenu: pass in an existing name, and pass out its index (if found). ------------------------------------------------------------------------ r502 | ajapted | 2012-12-13 15:20:35 +1100 (Thu, 13 Dec 2012) | 3 lines Renamed the File -> 'Project Setup' command to 'Manage Wads' (as a test, since I haven't decided which one is more intuitive). ------------------------------------------------------------------------ r501 | ajapted | 2012-12-13 00:01:39 +1100 (Thu, 13 Dec 2012) | 3 lines Partial work on logic to get a list of definitions (e.g. list of ports) by scanning the installed UGH files. ------------------------------------------------------------------------ r500 | ajapted | 2012-12-11 22:29:45 +1100 (Tue, 11 Dec 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r499 | ajapted | 2012-12-11 22:09:54 +1100 (Tue, 11 Dec 2012) | 3 lines Project Setup dialog: got the resource buttons ('X' and 'Load') working and got the IWAD 'Find' button mostly working. ------------------------------------------------------------------------ r498 | ajapted | 2012-12-11 21:40:52 +1100 (Tue, 11 Dec 2012) | 3 lines Moved texture loading calls into Main_LoadResources(), making sure that all previous textures are removed and freed. ------------------------------------------------------------------------ r497 | ajapted | 2012-12-11 21:36:55 +1100 (Tue, 11 Dec 2012) | 2 lines Show a '*' in the window title bar when the map has been modified. ------------------------------------------------------------------------ r496 | ajapted | 2012-12-11 21:34:46 +1100 (Tue, 11 Dec 2012) | 2 lines Code tidying: removed some dead code (e.g. DrawScreenText). ------------------------------------------------------------------------ r495 | ajapted | 2012-12-11 14:37:58 +1100 (Tue, 11 Dec 2012) | 5 lines Implemented ability to load "mod" definition files, which correspond to a loaded resource wad. Also fixed Main_LoadResources() to clear all definitions. ------------------------------------------------------------------------ r494 | ajapted | 2012-12-11 14:25:15 +1100 (Tue, 11 Dec 2012) | 3 lines Factored IWAD/resource loading code into Main_LoadResources() function. This is going to allow dynamically changing the iwad/port/resources. ------------------------------------------------------------------------ r493 | ajapted | 2012-12-11 14:11:22 +1100 (Tue, 11 Dec 2012) | 5 lines Code tidying: 1. renamed global var: base_wad --> game_wad 2. renamed Iwad --> Iwad_name, ensure it stays valid 3. renamed Pwad --> Pwad_name, keep it valid (when changing edit_wad) ------------------------------------------------------------------------ r492 | ajapted | 2012-12-11 13:54:56 +1100 (Tue, 11 Dec 2012) | 2 lines Project Setup dialog: bit more work e.g. Populate method... ------------------------------------------------------------------------ r491 | ajapted | 2012-12-11 11:57:22 +1100 (Tue, 11 Dec 2012) | 5 lines File menu update: 1. added 'Project Setup' command 2. CTRL-R is now the shortcut key for 'Recent Files' command 3. tweaked the keyboard navigation ------------------------------------------------------------------------ r490 | ajapted | 2012-12-11 11:55:04 +1100 (Tue, 11 Dec 2012) | 2 lines Project Setup: bit more work, wrote skeletal Main_ProjectSetup() code. ------------------------------------------------------------------------ r489 | ajapted | 2012-12-11 11:50:22 +1100 (Tue, 11 Dec 2012) | 3 lines Renamed UI_ProjectInfo --> UI_ProjectSetup, added skeletal callback functions, fixed window title and resource numbering. ------------------------------------------------------------------------ r488 | ajapted | 2012-12-11 11:33:41 +1100 (Tue, 11 Dec 2012) | 1 line tweak ------------------------------------------------------------------------ r487 | ajapted | 2012-12-11 11:26:04 +1100 (Tue, 11 Dec 2012) | 2 lines manage2.fl : various work ------------------------------------------------------------------------ r486 | ajapted | 2012-12-11 10:57:33 +1100 (Tue, 11 Dec 2012) | 4 lines Began work on a 'Project Info' dialog, where the user can select / change the current IWAD and port (engine) and resource wads. So far this is only the widget layout (imported from fluid output). ------------------------------------------------------------------------ r485 | ajapted | 2012-12-10 22:02:57 +1100 (Mon, 10 Dec 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r484 | ajapted | 2012-12-10 21:23:14 +1100 (Mon, 10 Dec 2012) | 10 lines Open Map dialog: we no longer directly change 'edit_wad' in the dialog itself, instead we keep a local copy of the Wad_file object, and communicate the newly-openness of it via 'is_new_pwad' Run() param. Updated the CMD_OpenMap() logic accordingly, removing the edit_wad from master dir when the returned wad is different, and establishing the 'new_pwad' as the edit_wad if that's what the user selected. So I think the logic is 100% correct now, but will review it soon... ------------------------------------------------------------------------ r483 | ajapted | 2012-12-10 20:55:31 +1100 (Mon, 10 Dec 2012) | 2 lines Disconnect Sectors: fixed texture on the separated linedefs. ------------------------------------------------------------------------ r482 | ajapted | 2012-12-10 15:25:43 +1100 (Mon, 10 Dec 2012) | 2 lines Disconnect Sectors: improved calculation of move vector. ------------------------------------------------------------------------ r481 | ajapted | 2012-12-10 15:16:44 +1100 (Mon, 10 Dec 2012) | 3 lines Disconnect Sectors: got the logic for moving the vertices in a good direction working, via new DETSEC_CalcMoveVector() function. ------------------------------------------------------------------------ r480 | ajapted | 2012-12-10 14:37:17 +1100 (Mon, 10 Dec 2012) | 2 lines Merge linedefs: fixed handling of sidedef textures. ------------------------------------------------------------------------ r479 | ajapted | 2012-12-10 11:29:58 +1100 (Mon, 10 Dec 2012) | 3 lines Open Map dialog: re-check map name after changing the "Look in" wad or after loading a new pwad. Fixed some bugs. ------------------------------------------------------------------------ r478 | ajapted | 2012-12-10 11:19:21 +1100 (Mon, 10 Dec 2012) | 4 lines Open Map dialog: implemented logic to validate the map name, including checking that it exists in the selected wad, and only enable the "OK" button when valid. ------------------------------------------------------------------------ r477 | ajapted | 2012-12-09 22:34:51 +1100 (Sun, 09 Dec 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r476 | ajapted | 2012-12-09 22:29:34 +1100 (Sun, 09 Dec 2012) | 2 lines Open Map dialog: prevent loading a PWAD without any levels. ------------------------------------------------------------------------ r475 | ajapted | 2012-12-09 22:25:51 +1100 (Sun, 09 Dec 2012) | 2 lines CMD_OpenMap: fixed the new 'Replacer' logic. ------------------------------------------------------------------------ r474 | ajapted | 2012-12-09 22:10:30 +1100 (Sun, 09 Dec 2012) | 5 lines Open Map dialog: 1. use it properly in CMD_OpenMap() -- remove a lot of old logic 2. return the selected wad and map from the Run() method 3. support clicking on a map button ------------------------------------------------------------------------ r473 | ajapted | 2012-12-09 21:47:46 +1100 (Sun, 09 Dec 2012) | 6 lines Open Map dialog: implemented the 'Load' button, which pops up a file requester to get a WAD file and can load that as the 'edit_wad' (code portions were copy'n'pasted from CMD_OpenMap). We also setup the currently edited pwad widget. ------------------------------------------------------------------------ r472 | ajapted | 2012-12-09 21:24:05 +1100 (Sun, 09 Dec 2012) | 5 lines Choose Map dialog: implemented checking the map name as the user types it, when invalid it is drawn in RED and the OK button is deactivated. Also removed some gunk. ------------------------------------------------------------------------ r471 | ajapted | 2012-12-09 19:54:33 +1100 (Sun, 09 Dec 2012) | 7 lines Preferences dialog: more work in fluid: 1. fixed the radio and check buttons so the size covers the label 2. added C++ variable names to each widget 3. use BORDER_BOX for color buttons (so the plastic scheme doesn't show the wrong color) 4. miscellaneous tweaking. ------------------------------------------------------------------------ r470 | ajapted | 2012-12-09 18:51:16 +1100 (Sun, 09 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r469 | ajapted | 2012-12-09 18:41:41 +1100 (Sun, 09 Dec 2012) | 3 lines Open Map dialog: improved layout of map buttons, make buttons bigger when there are less columns, and use less rows sometimes. ------------------------------------------------------------------------ r468 | ajapted | 2012-12-09 17:12:35 +1100 (Sun, 09 Dec 2012) | 3 lines Open Map dialog: wrote the Populate() method which creates a button for each found map in the selected "look for" place. ------------------------------------------------------------------------ r467 | ajapted | 2012-12-09 16:40:21 +1100 (Sun, 09 Dec 2012) | 2 lines Open Map dialog: made more compact (vertically) + a few tweaks. ------------------------------------------------------------------------ r466 | ajapted | 2012-12-09 16:08:59 +1100 (Sun, 09 Dec 2012) | 3 lines Open Map dialog: a few fixes, especially a bad labelfont() value which caused a crash. ------------------------------------------------------------------------ r465 | ajapted | 2012-12-09 15:53:27 +1100 (Sun, 09 Dec 2012) | 2 lines Partial work on new 'Open Map' dialog, main skeleton and widget layout. ------------------------------------------------------------------------ r464 | ajapted | 2012-12-09 15:31:35 +1100 (Sun, 09 Dec 2012) | 2 lines Use the new map choosing dialog with File/New command. ------------------------------------------------------------------------ r463 | ajapted | 2012-12-09 14:37:39 +1100 (Sun, 09 Dec 2012) | 5 lines Choose Map dialog: 1. changed the layout so that MAP01/02/03 (etc) goes down columns instead of across rows 2. got the buttons working (implemented the callback) ------------------------------------------------------------------------ r462 | ajapted | 2012-12-09 14:23:05 +1100 (Sun, 09 Dec 2012) | 3 lines Choose Map dialog: code to populate with map-name buttons. It can also test whether the map already exists, changes the color of the button. ------------------------------------------------------------------------ r461 | ajapted | 2012-12-09 13:27:38 +1100 (Sun, 09 Dec 2012) | 4 lines Export map: use the new 'Choose Map' dialog. We also open/create the destination wad file first, so that the dialog will be able to show which maps are used and which maps are free (planned feature). ------------------------------------------------------------------------ r460 | ajapted | 2012-12-09 13:24:17 +1100 (Sun, 09 Dec 2012) | 2 lines UI_ChooseMap: validate the map name, and fixed several issues. ------------------------------------------------------------------------ r459 | ajapted | 2012-12-09 12:52:16 +1100 (Sun, 09 Dec 2012) | 2 lines Worked on 'Choose Map' dialog, basic widgets are in place... ------------------------------------------------------------------------ r458 | ajapted | 2012-12-09 12:23:54 +1100 (Sun, 09 Dec 2012) | 3 lines Added new code files 'ui_file.cc/h', which will contain some File-related dialogs. Currently only has the beginnings of a UI_ChooseMap dialog. ------------------------------------------------------------------------ r457 | ajapted | 2012-12-08 22:14:27 +1100 (Sat, 08 Dec 2012) | 3 lines Misc: commit the in-progress fluid versions of Preference dialog and Project Info (wad manager) dialog. ------------------------------------------------------------------------ r456 | ajapted | 2012-12-08 21:26:14 +1100 (Sat, 08 Dec 2012) | 2 lines implemented 'View / Whole Selection' menu command. ------------------------------------------------------------------------ r455 | ajapted | 2012-12-08 20:38:21 +1100 (Sat, 08 Dec 2012) | 4 lines Preferences: added bare-bones code files: ui_prefs.cc/h (The actual dialog is being worked on in fluid...) ------------------------------------------------------------------------ r454 | ajapted | 2012-12-08 18:30:04 +1100 (Sat, 08 Dec 2012) | 2 lines Removed obselete config vars: 'sprite_scale' and 'copy_linedef_reuse_sidedef'. ------------------------------------------------------------------------ r453 | ajapted | 2012-12-08 15:58:07 +1100 (Sat, 08 Dec 2012) | 2 lines CHANGELOG: update, rejigged the order of some items. ------------------------------------------------------------------------ r452 | ajapted | 2012-12-08 15:56:09 +1100 (Sat, 08 Dec 2012) | 3 lines Fixed File/Open and OpenRecent to not zoom out when there is persisted state for that map. ------------------------------------------------------------------------ r451 | ajapted | 2012-12-08 15:49:48 +1100 (Sat, 08 Dec 2012) | 2 lines Recent files: actually load the file/map picked in the GUI. ------------------------------------------------------------------------ r450 | ajapted | 2012-12-08 15:39:10 +1100 (Sat, 08 Dec 2012) | 3 lines Recent files: implemented callback for the buttons, we use the user data to hold the index number (needed a ugly hack to allow that). ------------------------------------------------------------------------ r449 | ajapted | 2012-12-08 15:25:16 +1100 (Sat, 08 Dec 2012) | 4 lines Recent files: partial work on CMD_OpenRecentMap() code which is responsible for actually opening the selected map. Also updated M_RecentDialog() to pass back the chosen filename and map. ------------------------------------------------------------------------ r448 | ajapted | 2012-12-08 15:08:36 +1100 (Sat, 08 Dec 2012) | 2 lines Recent files: layout tweaks. ------------------------------------------------------------------------ r447 | ajapted | 2012-12-08 15:04:05 +1100 (Sat, 08 Dec 2012) | 8 lines Recent files: 1. reduced MAX_RECENT from 10 to 8 2. the find() method can also match a map name 3. added Format() method to format a file/map for a gui button 4. made the dialog window height depend on # of recent files 5. create buttons for each file/map 6. show a different message when list is empty ------------------------------------------------------------------------ r446 | ajapted | 2012-12-08 14:32:10 +1100 (Sat, 08 Dec 2012) | 2 lines Recent files: implemented the cancel button (close_callback). ------------------------------------------------------------------------ r445 | ajapted | 2012-12-08 14:00:45 +1100 (Sat, 08 Dec 2012) | 3 lines Recent files: began work on dialog to show the files and let the user select one. So far this is just creates the window, nothing works yet. ------------------------------------------------------------------------ r444 | ajapted | 2012-12-08 13:44:37 +1100 (Sat, 08 Dec 2012) | 3 lines Made linedef-path and contig-sector select commands consistent with normal selection -- clear previous selection after a move. ------------------------------------------------------------------------ r443 | ajapted | 2012-12-08 13:37:30 +1100 (Sat, 08 Dec 2012) | 2 lines Merge linedefs tweak. ------------------------------------------------------------------------ r442 | ajapted | 2012-12-08 12:59:28 +1100 (Sat, 08 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r441 | ajapted | 2012-12-08 12:59:03 +1100 (Sat, 08 Dec 2012) | 2 lines Linedef mode: Implemented 'm' merge command for two one-sided lines. ------------------------------------------------------------------------ r440 | ajapted | 2012-12-08 12:38:35 +1100 (Sat, 08 Dec 2012) | 4 lines Added a version of the Beep() function which takes a message, as eventually it would be good to show a message somewhere (like a status bar). ------------------------------------------------------------------------ r439 | ajapted | 2012-12-08 12:31:45 +1100 (Sat, 08 Dec 2012) | 2 lines UI: added 'Recent file' command to File menu (does not work yet). ------------------------------------------------------------------------ r438 | ajapted | 2012-12-08 11:47:48 +1100 (Sat, 08 Dec 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r437 | ajapted | 2012-12-08 11:46:37 +1100 (Sat, 08 Dec 2012) | 2 lines Disconnect sectors: fixed another issue. ------------------------------------------------------------------------ r436 | ajapted | 2012-12-08 11:33:07 +1100 (Sat, 08 Dec 2012) | 5 lines Disconnect sectors: 1. got the sidedef handling in DETSEC_AddNewLine() working properly 2. fixed a bug where we visited newly added linedefs 3. few other fixes to the logic ------------------------------------------------------------------------ r435 | ajapted | 2012-12-08 11:04:28 +1100 (Sat, 08 Dec 2012) | 2 lines Disconnect sectors: worked on line separation logic... ------------------------------------------------------------------------ r434 | ajapted | 2012-12-08 10:47:02 +1100 (Sat, 08 Dec 2012) | 2 lines Worked on a 'd' disconnect command for Sectors... ------------------------------------------------------------------------ r433 | ajapted | 2012-12-07 22:49:02 +1100 (Fri, 07 Dec 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r432 | ajapted | 2012-12-07 22:47:40 +1100 (Fri, 07 Dec 2012) | 2 lines UI: about box tweak. ------------------------------------------------------------------------ r431 | ajapted | 2012-12-07 22:13:27 +1100 (Fri, 07 Dec 2012) | 4 lines Recent files: 1. fixed parse code to remove trailing CR/LF 2. call M_LoadRecent() and M_AddRecent() where needed ------------------------------------------------------------------------ r430 | ajapted | 2012-12-07 21:31:17 +1100 (Fri, 07 Dec 2012) | 2 lines Recent files: implemented M_LoadRecent() and M_SaveRecent(). ------------------------------------------------------------------------ r429 | ajapted | 2012-12-07 21:24:31 +1100 (Fri, 07 Dec 2012) | 2 lines Recent files: implemented ParseFile() method and fixed a few bugs. ------------------------------------------------------------------------ r428 | ajapted | 2012-12-07 21:13:00 +1100 (Fri, 07 Dec 2012) | 5 lines Recent files: 1. implemented insert() method, with logic to find() an existing file with the same base-name and erase() it. 2. implemented the WriteFile() method. ------------------------------------------------------------------------ r427 | ajapted | 2012-12-07 21:00:47 +1100 (Fri, 07 Dec 2012) | 3 lines Began work on code to remember recently edited files, with a goal to show a dialog allowing users to pick one to open. ------------------------------------------------------------------------ r426 | ajapted | 2012-12-07 20:29:10 +1100 (Fri, 07 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r425 | ajapted | 2012-12-07 20:24:10 +1100 (Fri, 07 Dec 2012) | 2 lines View menu: added 'Toggle Grid Type' item. ------------------------------------------------------------------------ r424 | ajapted | 2012-12-07 19:32:37 +1100 (Fri, 07 Dec 2012) | 7 lines Show object nums: use a better algorithm for sectors, keep track of which sectors we have "seen" and draw the number on the first visited linedef. Also changed the linedef position to be directly on the line (which is generally uglier, but less confusing). ------------------------------------------------------------------------ r423 | ajapted | 2012-12-07 18:57:11 +1100 (Fri, 07 Dec 2012) | 6 lines Show object nums: reworked drawing for Linedefs, done in a separate pass (like things etc), and really honed the logic determining how far away from the line's middle to draw the number. Added 'center' parameter to DrawObjNum() method. ------------------------------------------------------------------------ r422 | ajapted | 2012-12-07 17:41:45 +1100 (Fri, 07 Dec 2012) | 2 lines Show object nums: persist the setting. ------------------------------------------------------------------------ r421 | ajapted | 2012-12-07 16:11:43 +1100 (Fri, 07 Dec 2012) | 2 lines Show object numbers: added to VIEW menu, and changed key to 'J'. ------------------------------------------------------------------------ r420 | ajapted | 2012-12-07 15:51:39 +1100 (Fri, 07 Dec 2012) | 8 lines Worked to improve object numbers on canvas: 1. moved thing code into DrawThings() 2. moved sector code into new DrawSectorNums() method 3. OBJ_NUM_COL replaces the THING_NO, SECTOR_NO (etc) defines 4. DrawObjNum() no longer uses obsolete DrawScreenText() function 5. font size depends for the current scale 6. position the number at top/right of things and vertices ------------------------------------------------------------------------ r419 | ajapted | 2012-12-07 15:01:53 +1100 (Fri, 07 Dec 2012) | 2 lines Key propagation: fixed the 3D view eating all keys when active. ------------------------------------------------------------------------ r418 | ajapted | 2012-12-07 13:45:40 +1100 (Fri, 07 Dec 2012) | 6 lines Implemented a decent GoToObject() function, via new GoToSelection() function which can zoom out when the objects are too large to fit on-screen, or zoom in when they are very small. New code is in e_path.cc/h (no longer in objects.cc/h) ------------------------------------------------------------------------ r417 | ajapted | 2012-12-07 12:43:05 +1100 (Fri, 07 Dec 2012) | 2 lines Unbind 'n' and 'p' keys from the next obj / prev obj mis-feature. ------------------------------------------------------------------------ r416 | ajapted | 2012-12-07 11:09:57 +1100 (Fri, 07 Dec 2012) | 5 lines Menu code stuff: 1. replace fl_beep() with Beep() 2. reworked find commands in View menu, removed 'next / prev object' 3. experimental support for Fullscreen mode ------------------------------------------------------------------------ r415 | ajapted | 2012-12-07 11:03:14 +1100 (Fri, 07 Dec 2012) | 3 lines UI_Window: added ToggleFullscreen() method, though it doesn't work too well (here anyway) due to FLTK's implementation. ------------------------------------------------------------------------ r414 | ajapted | 2012-12-06 23:57:21 +1100 (Thu, 06 Dec 2012) | 2 lines TODO and WISHLIST updates. ------------------------------------------------------------------------ r413 | ajapted | 2012-12-06 23:54:16 +1100 (Thu, 06 Dec 2012) | 2 lines Implemented 'm' merge command for vertex mode. ------------------------------------------------------------------------ r412 | ajapted | 2012-12-06 23:20:03 +1100 (Thu, 06 Dec 2012) | 2 lines Removed dead code : set_colour(), push_colour(), pop_colour(). ------------------------------------------------------------------------ r411 | ajapted | 2012-12-06 23:15:50 +1100 (Thu, 06 Dec 2012) | 4 lines Merged stuff from s_misc.cc/h --> e_sector.cc/h (some disabled code which may be needed later). Hence deleted s_misc.cc/h and removed from the Makefile. ------------------------------------------------------------------------ r410 | ajapted | 2012-12-06 23:08:49 +1100 (Thu, 06 Dec 2012) | 2 lines Removed dead code : find_linedef_for_area(). ------------------------------------------------------------------------ r409 | ajapted | 2012-12-06 23:03:54 +1100 (Thu, 06 Dec 2012) | 3 lines Removed dead code : old non-working SplitSector() and SplitLineDefsAndSector() functions. ------------------------------------------------------------------------ r408 | ajapted | 2012-12-06 22:57:39 +1100 (Thu, 06 Dec 2012) | 2 lines Config: support for color variables (via new OPT_COLOR type). ------------------------------------------------------------------------ r407 | ajapted | 2012-12-06 22:56:14 +1100 (Thu, 06 Dec 2012) | 3 lines Added ParseColor() function to im_color code, originally in m_game.cc but updated to support both 3- and 6-digit formats (RGB and RRGGBB). ------------------------------------------------------------------------ r406 | ajapted | 2012-12-06 16:37:21 +1100 (Thu, 06 Dec 2012) | 3 lines Added 'digits_set_zoom' config var which enabled the Yadex behavior where the digit keys set the zoom factor. ------------------------------------------------------------------------ r405 | ajapted | 2012-12-06 16:11:34 +1100 (Thu, 06 Dec 2012) | 2 lines tweaked handling of BackSpace key. ------------------------------------------------------------------------ r404 | ajapted | 2012-12-06 16:10:50 +1100 (Thu, 06 Dec 2012) | 2 lines Removed sector_slice() stuff : was unused and non-working. ------------------------------------------------------------------------ r403 | ajapted | 2012-12-06 15:52:22 +1100 (Thu, 06 Dec 2012) | 2 lines Key propagation: moved more checks into mode-specific functions. ------------------------------------------------------------------------ r402 | ajapted | 2012-12-06 15:39:22 +1100 (Thu, 06 Dec 2012) | 3 lines Key propagation: have a handler function for each editing mode, i.e. Thing_Key(), Sector_Key(), etc... ------------------------------------------------------------------------ r401 | ajapted | 2012-12-06 15:22:50 +1100 (Thu, 06 Dec 2012) | 2 lines Config: removed OPT_STRINGBUF8 as a config type (not needed). ------------------------------------------------------------------------ r400 | ajapted | 2012-12-06 14:34:27 +1100 (Thu, 06 Dec 2012) | 5 lines Key propagation: 1. the Global_Key() handler has highest priority 2. moved handling of TAB and browser open keys to Global_Key() 3. new function: CMD_Toggle3Dview() ------------------------------------------------------------------------ r399 | ajapted | 2012-12-06 11:11:08 +1100 (Thu, 06 Dec 2012) | 2 lines Partial work on new keyboard propagation logic.... ------------------------------------------------------------------------ r398 | ajapted | 2012-12-06 10:34:09 +1100 (Thu, 06 Dec 2012) | 2 lines CHANGELOG updated. ------------------------------------------------------------------------ r397 | ajapted | 2012-12-06 10:32:08 +1100 (Thu, 06 Dec 2012) | 2 lines UI / Default props: persist the hidden/shown state. ------------------------------------------------------------------------ r396 | ajapted | 2012-12-06 10:18:11 +1100 (Thu, 06 Dec 2012) | 3 lines UI / Default props: added a button which hides/shows the properties (since they can be distracting during normal editing). ------------------------------------------------------------------------ r395 | ajapted | 2012-12-05 23:11:45 +1100 (Wed, 05 Dec 2012) | 2 lines minor commenting... ------------------------------------------------------------------------ r394 | ajapted | 2012-12-05 23:10:08 +1100 (Wed, 05 Dec 2012) | 3 lines Fixed Props_LoadValues() being called too early (before main_win was created) and hence not working. ------------------------------------------------------------------------ r393 | ajapted | 2012-12-05 23:09:03 +1100 (Wed, 05 Dec 2012) | 2 lines Game defs / DOOM: changed default_thing --> 2014 (health potion) ------------------------------------------------------------------------ r392 | ajapted | 2012-12-05 23:03:53 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default props: ability to set wall textures via the browser. ------------------------------------------------------------------------ r391 | ajapted | 2012-12-05 22:50:22 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default props: ability to set sector flats via the browser. ------------------------------------------------------------------------ r390 | ajapted | 2012-12-05 22:44:37 +1100 (Wed, 05 Dec 2012) | 2 lines minor rename, UI_Sector::SetTexture() --> SetFlat() ------------------------------------------------------------------------ r389 | ajapted | 2012-12-05 22:40:54 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default props: ability to set default thing via the browser. ------------------------------------------------------------------------ r388 | ajapted | 2012-12-05 22:33:29 +1100 (Wed, 05 Dec 2012) | 2 lines Browser: got existing stuff working again via the new system. ------------------------------------------------------------------------ r387 | ajapted | 2012-12-05 22:23:43 +1100 (Wed, 05 Dec 2012) | 4 lines Browser: partial work on passing all browser selections through a new 'BrowsedItem()' method of UI_MainWin class. This method will decide what to do with the selected item. ------------------------------------------------------------------------ r386 | ajapted | 2012-12-05 21:35:27 +1100 (Wed, 05 Dec 2012) | 4 lines UI / Default props: allow pics to be selected, opening the browser in the right mode. Unselect the pics when browser is closed. Don't allow both textures and flats to be selected. ------------------------------------------------------------------------ r385 | ajapted | 2012-12-05 21:16:01 +1100 (Wed, 05 Dec 2012) | 3 lines UI / Default Props: got the texture and flat input fields working, and make sure the name is normalized (uppercased and length limited). ------------------------------------------------------------------------ r384 | ajapted | 2012-12-05 21:02:31 +1100 (Wed, 05 Dec 2012) | 4 lines UI / Default Props: 1. got the floor_h / ceil_h / light input fields working 2. fixed bug parsing the "thing" value from a user state file ------------------------------------------------------------------------ r383 | ajapted | 2012-12-05 20:50:48 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default Props: implemented callbacks for height buttons. ------------------------------------------------------------------------ r382 | ajapted | 2012-12-05 20:05:55 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default Props: added Props_LoadValues() function, call it where needed. ------------------------------------------------------------------------ r381 | ajapted | 2012-12-05 20:04:53 +1100 (Wed, 05 Dec 2012) | 2 lines Browser: for textual modes, pack them a bit tighter vertically (show more). ------------------------------------------------------------------------ r380 | ajapted | 2012-12-05 19:50:54 +1100 (Wed, 05 Dec 2012) | 3 lines UI / Default Props: implemented LoadValues() method to setup each widget with the current values. ------------------------------------------------------------------------ r379 | ajapted | 2012-12-05 19:38:05 +1100 (Wed, 05 Dec 2012) | 3 lines UI / Default Props: implemented Props_ParseUser(), and changed the write code to use a space after "default". ------------------------------------------------------------------------ r378 | ajapted | 2012-12-05 19:29:09 +1100 (Wed, 05 Dec 2012) | 2 lines Utils: added StringTidy() function. ------------------------------------------------------------------------ r377 | ajapted | 2012-12-05 19:21:00 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default Props: implemented Props_WriteUser(). ------------------------------------------------------------------------ r376 | ajapted | 2012-12-05 19:19:52 +1100 (Wed, 05 Dec 2012) | 2 lines New util function: StringRemoveCRLF(). ------------------------------------------------------------------------ r375 | ajapted | 2012-12-05 17:19:24 +1100 (Wed, 05 Dec 2012) | 2 lines Config: remove trailing LF (and/or CR) from .dat lines, for better warning messages. ------------------------------------------------------------------------ r374 | ajapted | 2012-12-05 17:12:33 +1100 (Wed, 05 Dec 2012) | 2 lines minor renaming. ------------------------------------------------------------------------ r373 | ajapted | 2012-12-05 15:29:09 +1100 (Wed, 05 Dec 2012) | 5 lines UI / Default Props: make consistent use of 'default_xxx' global vars, which replace the 'g_default_xxx' ones in m_game.cc/h. Moved their definition into e_basis.cc (that's the primary place they are used). Simplified some of the names. ------------------------------------------------------------------------ r372 | ajapted | 2012-12-05 15:11:00 +1100 (Wed, 05 Dec 2012) | 3 lines Config: removed default_floor_height, default_middle_texture (etc...) as config variables -- they are now considered as user state of a map. ------------------------------------------------------------------------ r371 | ajapted | 2012-12-05 15:09:06 +1100 (Wed, 05 Dec 2012) | 3 lines UI / Default Props: skeletal functions to read/write the properties into the user state of a map. ------------------------------------------------------------------------ r370 | ajapted | 2012-12-05 15:01:33 +1100 (Wed, 05 Dec 2012) | 2 lines UI: tweaked layout of sidedef pics. ------------------------------------------------------------------------ r369 | ajapted | 2012-12-05 14:29:30 +1100 (Wed, 05 Dec 2012) | 2 lines UI: tweaked layout of sector floor / ceiling properties. ------------------------------------------------------------------------ r368 | ajapted | 2012-12-04 22:36:45 +1100 (Tue, 04 Dec 2012) | 2 lines minor update. ------------------------------------------------------------------------ r367 | ajapted | 2012-12-04 22:34:18 +1100 (Tue, 04 Dec 2012) | 3 lines Sector mode: handle CTRL key with floor/ceiling height adjusters, stepping by 64 units. ------------------------------------------------------------------------ r366 | ajapted | 2012-12-04 22:30:50 +1100 (Tue, 04 Dec 2012) | 9 lines Sector mode: swapped keys to height adjusting: '.' and ',' now adjust the floor height, and '[' and ']' now adjust the ceiling. This was suggested by d1337r. The rationale is that '.' and ',' are lower on the keyboard than the '[' and ']' keys. Also made step amounts consistent between the keys and the GUI buttons: 8 units with no modifier, 1 unit shifted. ------------------------------------------------------------------------ r365 | ajapted | 2012-12-04 22:17:28 +1100 (Tue, 04 Dec 2012) | 5 lines 3D View: 1. disabled '.' and ',' as strafe keys (a sector function using these keys is more important) 2. allow UP and DOWN arrows to work with ALT pressed. ------------------------------------------------------------------------ r364 | ajapted | 2012-12-04 20:12:51 +1100 (Tue, 04 Dec 2012) | 4 lines UI / Default Props: 1. added Thing number and description 2. disabled the sector title (it is fairly obvious) ------------------------------------------------------------------------ r363 | ajapted | 2012-12-04 19:58:30 +1100 (Tue, 04 Dec 2012) | 2 lines UI / Default Props: added and layouted the Sector props. ------------------------------------------------------------------------ r362 | ajapted | 2012-12-04 19:32:17 +1100 (Tue, 04 Dec 2012) | 2 lines UI / Default Props: added widgets for the Linedef textures. ------------------------------------------------------------------------ r361 | ajapted | 2012-12-04 19:19:13 +1100 (Tue, 04 Dec 2012) | 4 lines UI: began work on a 'Default Props' panel, which sits underneath the Vertex panel (with all that unused space) and will be used for setting the default insert properties of objects (e.g. sector floor, wall tex). ------------------------------------------------------------------------ r360 | ajapted | 2012-12-04 19:08:15 +1100 (Tue, 04 Dec 2012) | 2 lines minor commenting. ------------------------------------------------------------------------ r359 | ajapted | 2012-12-04 18:47:00 +1100 (Tue, 04 Dec 2012) | 2 lines Coding: use 'WINDOW_BG' define for window backgrounds. ------------------------------------------------------------------------ r358 | ajapted | 2012-12-04 18:24:44 +1100 (Tue, 04 Dec 2012) | 3 lines Changed default grid size to be 16 (was: 128), and added two new config vars: 'default_grid_size' and 'default_grid_snap'. ------------------------------------------------------------------------ r357 | ajapted | 2012-12-04 18:20:49 +1100 (Tue, 04 Dec 2012) | 2 lines Properly initialise the Grid_State_c object. ------------------------------------------------------------------------ r356 | ajapted | 2012-12-04 18:16:51 +1100 (Tue, 04 Dec 2012) | 2 lines UI: tweaked grid color when zoomed far out (GRID_DARK). ------------------------------------------------------------------------ r355 | ajapted | 2012-12-04 16:55:06 +1100 (Tue, 04 Dec 2012) | 2 lines Made multi-select optional, with new 'multi_select_modifier' config var. ------------------------------------------------------------------------ r354 | ajapted | 2012-12-04 16:15:10 +1100 (Tue, 04 Dec 2012) | 4 lines Code tidying: replaced 'is_butl' and 'is_middle' hacks with 'button_down' field in the Editor_State_c class. Replaced 'click_ctrl' with 'button_mod' field. Removed some dead code. ------------------------------------------------------------------------ r353 | ajapted | 2012-12-04 14:49:13 +1100 (Tue, 04 Dec 2012) | 2 lines UI: changed the grid_snap from a Choice --> Toggle_Button. ------------------------------------------------------------------------ r352 | ajapted | 2012-12-04 14:15:42 +1100 (Tue, 04 Dec 2012) | 3 lines WISHLIST: added a few items, moved a few others, fleshed out the item about configurable keys. ------------------------------------------------------------------------ r351 | ajapted | 2012-12-03 22:16:39 +1100 (Mon, 03 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r350 | ajapted | 2012-12-03 22:15:21 +1100 (Mon, 03 Dec 2012) | 5 lines Building Nodes: added the following config vars: 1. glbsp_fast 2. glbsp_verbose 3. glbsp_warn ------------------------------------------------------------------------ r349 | ajapted | 2012-12-03 20:33:45 +1100 (Mon, 03 Dec 2012) | 3 lines Worked on supporting a configurable GUI scheme and color set, via two new config vars: 'gui_scheme' and 'gui_color_set'. ------------------------------------------------------------------------ r348 | ajapted | 2012-12-03 16:06:37 +1100 (Mon, 03 Dec 2012) | 2 lines TODO and WISHLIST: added some suggestions by d1337r. ------------------------------------------------------------------------ r347 | ajapted | 2012-12-03 15:17:22 +1100 (Mon, 03 Dec 2012) | 3 lines Fixed color of a line or sector when tagged -- only the tagged object should be drawn in pink, not the current line or sector. ------------------------------------------------------------------------ r346 | ajapted | 2012-12-03 14:55:24 +1100 (Mon, 03 Dec 2012) | 1 line compiler warning ------------------------------------------------------------------------ r345 | ajapted | 2012-12-03 14:24:25 +1100 (Mon, 03 Dec 2012) | 3 lines DOOM defs: moved 'Commander Keen' thing out of common/, since it is specific to DOOM 2, and changed its category to OTHER. ------------------------------------------------------------------------ r344 | ajapted | 2012-12-03 10:26:25 +1100 (Mon, 03 Dec 2012) | 2 lines Version bump after release (a little late...) ------------------------------------------------------------------------ r343 | ajapted | 2012-12-03 10:25:17 +1100 (Mon, 03 Dec 2012) | 2 lines TODO and WISHLIST update. ------------------------------------------------------------------------ r342 | ajapted | 2012-12-03 10:21:00 +1100 (Mon, 03 Dec 2012) | 2 lines Renamed doom_common.ugh --> doom_things.ugh ------------------------------------------------------------------------ r341 | ajapted | 2012-12-03 10:20:19 +1100 (Mon, 03 Dec 2012) | 5 lines DOOM definitions: 1. split off common textures into its own file: common/doom_tex 2. moved 'sky_flat', 'default_port' (etc) back to main def (in games/) 3. will rename doom_common.ugh --> doom_things.ugh ------------------------------------------------------------------------ r340 | ajapted | 2012-12-03 09:57:35 +1100 (Mon, 03 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r339 | ajapted | 2012-12-03 09:57:11 +1100 (Mon, 03 Dec 2012) | 3 lines Browser: added 'pic_mode' field to Browser_Box, replaces hard-coded tests against the browser kind (e.g. for resizing behavior). ------------------------------------------------------------------------ r338 | ajapted | 2012-12-03 09:40:26 +1100 (Mon, 03 Dec 2012) | 3 lines Browser / Things: implemented the 'pics' button, show sprites when on and show descriptions when off. ------------------------------------------------------------------------ r337 | ajapted | 2012-12-03 09:18:46 +1100 (Mon, 03 Dec 2012) | 3 lines Browser: added a 'number' field to each Browser_Item, and use it when sorting numerically (and in the callbacks too). ------------------------------------------------------------------------ r336 | ajapted | 2012-12-02 23:24:43 +1100 (Sun, 02 Dec 2012) | 2 lines minor corrections. ------------------------------------------------------------------------ r335 | ajapted | 2012-12-02 23:23:52 +1100 (Sun, 02 Dec 2012) | 2 lines Game defs: moved boss-brain things out of 'Monster' category. ------------------------------------------------------------------------ r334 | ajapted | 2012-12-02 23:16:43 +1100 (Sun, 02 Dec 2012) | 2 lines Tweak : changed thingtype_t::flags field from byte to short. ------------------------------------------------------------------------ r333 | ajapted | 2012-12-02 23:14:22 +1100 (Sun, 02 Dec 2012) | 4 lines Browser | Thing pics: 1. ignore things which have no sprites ("NULL" in the def file). 2. alphabetical sort shows sprite names, numerical sort shows id numbers. ------------------------------------------------------------------------ r332 | ajapted | 2012-12-02 16:55:39 +1100 (Sun, 02 Dec 2012) | 2 lines Browser: initial work on picture mode for Things... ------------------------------------------------------------------------ r331 | ajapted | 2012-12-02 14:21:42 +1100 (Sun, 02 Dec 2012) | 3 lines Removed doc/Features.txt : the info has been absorbed into README.txt and the website. ------------------------------------------------------------------------ r330 | ajapted | 2012-12-02 14:19:24 +1100 (Sun, 02 Dec 2012) | 2 lines README.txt : added 'Features' and 'Supported Games' sections (from wiki). ------------------------------------------------------------------------ r329 | ajapted | 2012-12-01 20:49:36 +1100 (Sat, 01 Dec 2012) | 2 lines Added AUTHORS.txt document. ------------------------------------------------------------------------ r328 | ajapted | 2012-11-30 22:19:08 +1100 (Fri, 30 Nov 2012) | 3 lines Worked on the Jump/Next/Previous commands. However I don't think they are very useful... ------------------------------------------------------------------------ r327 | ajapted | 2012-11-30 21:02:29 +1100 (Fri, 30 Nov 2012) | 3 lines Simplified how new sector squares are created outside of the map, size is fixed but configurable via 'new_sector_size' config var. ------------------------------------------------------------------------ r326 | ajapted | 2012-11-30 20:24:18 +1100 (Fri, 30 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r325 | ajapted | 2012-11-30 20:23:47 +1100 (Fri, 30 Nov 2012) | 2 lines Rotate dialog: implemented its functionality. ------------------------------------------------------------------------ r324 | ajapted | 2012-11-30 19:47:18 +1100 (Fri, 30 Nov 2012) | 2 lines Rotate dialog: began work on it, got the layout done so far... ------------------------------------------------------------------------ r323 | ajapted | 2012-11-30 19:24:20 +1100 (Fri, 30 Nov 2012) | 3 lines When rotating a group of things (or sectors which contain things), update the angles of the things too. ------------------------------------------------------------------------ r322 | ajapted | 2012-11-30 19:09:36 +1100 (Fri, 30 Nov 2012) | 2 lines Scale dialog: fixed percentage parsing ------------------------------------------------------------------------ r321 | ajapted | 2012-11-30 19:02:25 +1100 (Fri, 30 Nov 2012) | 2 lines Scale dialog: completed the functionality. ------------------------------------------------------------------------ r320 | ajapted | 2012-11-30 18:53:41 +1100 (Fri, 30 Nov 2012) | 2 lines Scale dialog: implemented parsing code: ParseScaleStr(). ------------------------------------------------------------------------ r319 | ajapted | 2012-11-30 18:41:33 +1100 (Fri, 30 Nov 2012) | 3 lines Scale dialog: Partial work implementing the scaling, e.g. added code to determine the focus point of scaling from the 'origin' choice. ------------------------------------------------------------------------ r318 | ajapted | 2012-11-30 16:46:33 +1100 (Fri, 30 Nov 2012) | 4 lines Scale dialog layouting: 1. added 'origin' button 2. rearranged bottom section, added some help text ------------------------------------------------------------------------ r317 | ajapted | 2012-11-30 16:04:08 +1100 (Fri, 30 Nov 2012) | 2 lines Move dialog: ensure initial values are zero. ------------------------------------------------------------------------ r316 | ajapted | 2012-11-30 15:57:37 +1100 (Fri, 30 Nov 2012) | 2 lines Began work on 'Scale Objects' dialog... ------------------------------------------------------------------------ r315 | ajapted | 2012-11-30 15:25:59 +1100 (Fri, 30 Nov 2012) | 2 lines Implemented the functionality of the Move dialog. ------------------------------------------------------------------------ r314 | ajapted | 2012-11-30 15:11:29 +1100 (Fri, 30 Nov 2012) | 3 lines Finished layout on UI_MoveDialog window (e.g. added a darker group around the buttons). Renamed "OK" button --> "Move" and made it bold. ------------------------------------------------------------------------ r313 | ajapted | 2012-11-30 14:49:21 +1100 (Fri, 30 Nov 2012) | 3 lines Partial work on a dialog window for moving objects (via the Edit menu). Still in the layout phase.... ------------------------------------------------------------------------ r312 | ajapted | 2012-11-30 14:33:18 +1100 (Fri, 30 Nov 2012) | 3 lines Added new (empty) code files: ui_misc.cc/h -- for miscellaneous dialog windows, such as a move object dialog.... ------------------------------------------------------------------------ r311 | ajapted | 2012-11-30 14:05:10 +1100 (Fri, 30 Nov 2012) | 2 lines Disabled the 'Play Map' feature for now. ------------------------------------------------------------------------ r310 | ajapted | 2012-11-30 10:43:23 +1100 (Fri, 30 Nov 2012) | 2 lines Changed shortcut key for 'File/Export Map' to CTRL-E ------------------------------------------------------------------------ r309 | ajapted | 2012-11-30 10:34:47 +1100 (Fri, 30 Nov 2012) | 4 lines Experiment with a 'File/Play Map' command (CTRL-P). Currently the directory to enter and program to run are hard-coded, these would need to be configurable. ------------------------------------------------------------------------ r308 | ajapted | 2012-11-28 22:37:36 +1100 (Wed, 28 Nov 2012) | 2 lines Began a fresh CHANGES.txt file, tweaked previous one. ------------------------------------------------------------------------ r307 | ajapted | 2012-11-28 22:35:52 +1100 (Wed, 28 Nov 2012) | 2 lines Moved CHANGES.txt --> docs/ folder, after the 0.84 release. ------------------------------------------------------------------------ r306 | ajapted | 2012-11-28 17:44:41 +1100 (Wed, 28 Nov 2012) | 3 lines MacOS X: set home_dir to '~/documents/eureka', making sure we create the ~/documents folder (in case it doesn't exist). ------------------------------------------------------------------------ r305 | ajapted | 2012-11-28 16:30:40 +1100 (Wed, 28 Nov 2012) | 2 lines Renamed 'Nil' method --> 'Clear' (for MacOS X compatibility). ------------------------------------------------------------------------ r304 | ajapted | 2012-11-27 18:09:20 +1100 (Tue, 27 Nov 2012) | 2 lines pack-source script: added debian stuff. ------------------------------------------------------------------------ r303 | ajapted | 2012-11-27 17:55:17 +1100 (Tue, 27 Nov 2012) | 2 lines INSTALL.txt : mention /usr/share/games/doom ------------------------------------------------------------------------ r302 | ajapted | 2012-11-27 17:49:20 +1100 (Tue, 27 Nov 2012) | 2 lines TODO and WISHLIST updated before release. ------------------------------------------------------------------------ r301 | ajapted | 2012-11-27 17:18:59 +1100 (Tue, 27 Nov 2012) | 2 lines README.txt : added a REQUIREMENTS section. ------------------------------------------------------------------------ r300 | ajapted | 2012-11-27 17:06:41 +1100 (Tue, 27 Nov 2012) | 2 lines CHANGELOG: yet another update. ------------------------------------------------------------------------ r299 | ajapted | 2012-11-27 17:04:48 +1100 (Tue, 27 Nov 2012) | 2 lines Made vertices slightly bigger, but not too big when zooming right in. ------------------------------------------------------------------------ r298 | ajapted | 2012-11-27 16:00:39 +1100 (Tue, 27 Nov 2012) | 2 lines TODO / WISHLIST update. ------------------------------------------------------------------------ r297 | ajapted | 2012-11-27 15:57:34 +1100 (Tue, 27 Nov 2012) | 4 lines Implemented a 'mouse_wheel_scrolls_map' config var, when enabled the mouse wheel will scroll the map (can do horizontally too). Pressing the CTRL key (ALT in MacOS X) will perform the zoom function. ------------------------------------------------------------------------ r296 | ajapted | 2012-11-27 15:31:52 +1100 (Tue, 27 Nov 2012) | 2 lines Handle '+' and '-' zooming keys by calling CMD_Zoom() directly (NOT via Editor_Wheel). ------------------------------------------------------------------------ r295 | ajapted | 2012-11-27 15:27:56 +1100 (Tue, 27 Nov 2012) | 3 lines UI_Canvas: tidier event handling code, added handle_key(), handle_push() (and so forth) methods to manage the major event kinds. ------------------------------------------------------------------------ r294 | ajapted | 2012-11-26 22:44:55 +1100 (Mon, 26 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r293 | ajapted | 2012-11-26 15:00:00 +1100 (Mon, 26 Nov 2012) | 2 lines Version bump to 0.84, ready for release. ------------------------------------------------------------------------ r292 | ajapted | 2012-11-26 14:44:49 +1100 (Mon, 26 Nov 2012) | 2 lines commenting... ------------------------------------------------------------------------ r291 | ajapted | 2012-11-26 12:18:55 +1100 (Mon, 26 Nov 2012) | 2 lines Moved Makefile.debian --> misc/ directory. ------------------------------------------------------------------------ r290 | ajapted | 2012-11-25 21:29:25 +1100 (Sun, 25 Nov 2012) | 2 lines Makefile.debian : fixed for moving 'debian' dir --> misc/ ------------------------------------------------------------------------ r289 | ajapted | 2012-11-25 21:23:33 +1100 (Sun, 25 Nov 2012) | 2 lines Moved 'debian' folder from top level --> misc/ folder ------------------------------------------------------------------------ r288 | ajapted | 2012-11-25 21:13:45 +1100 (Sun, 25 Nov 2012) | 7 lines Makefile.debian fixes: 1. added missing PROGRAM value 2. gzip the changelog file 3. do a 'debclean' before doing a 'debbuild' 4. store result in parent dir -- this also gives it the proper package name, with version and architecture in it. ------------------------------------------------------------------------ r287 | ajapted | 2012-11-25 21:07:37 +1100 (Sun, 25 Nov 2012) | 3 lines Removed debian stuff from plain Makefile. (This change should have been in r284....) ------------------------------------------------------------------------ r286 | ajapted | 2012-11-25 21:04:09 +1100 (Sun, 25 Nov 2012) | 3 lines Debian/copyright: indented Copyright lines, which fixes a lintian warning about lacking a copyright statement ^_^ ------------------------------------------------------------------------ r285 | ajapted | 2012-11-25 21:02:20 +1100 (Sun, 25 Nov 2012) | 3 lines Debian/control: changed section to 'misc' and added 'libc6' as a dependency -- both due to lintian errors. ------------------------------------------------------------------------ r284 | ajapted | 2012-11-25 20:43:00 +1100 (Sun, 25 Nov 2012) | 2 lines Makefiles: removed debian package stuff from plain Makefile. ------------------------------------------------------------------------ r283 | ajapted | 2012-11-25 20:41:02 +1100 (Sun, 25 Nov 2012) | 2 lines Added Makefile.debian, logic for making a debian package. ------------------------------------------------------------------------ r282 | ajapted | 2012-11-25 20:37:49 +1100 (Sun, 25 Nov 2012) | 2 lines Debian: tweaked version in debian/control, removed # comment ------------------------------------------------------------------------ r281 | ajapted | 2012-11-25 20:21:20 +1100 (Sun, 25 Nov 2012) | 3 lines Makefile: partial work on 'debinstall' target to create the file heirarchy for the debian package. ------------------------------------------------------------------------ r280 | ajapted | 2012-11-25 18:51:50 +1100 (Sun, 25 Nov 2012) | 2 lines Wrote the debian/copyright file. ------------------------------------------------------------------------ r279 | ajapted | 2012-11-25 18:37:17 +1100 (Sun, 25 Nov 2012) | 2 lines Added basic debian/changelog file. ------------------------------------------------------------------------ r278 | ajapted | 2012-11-25 14:14:24 +1100 (Sun, 25 Nov 2012) | 2 lines Initial work on a debian/control file. ------------------------------------------------------------------------ r277 | ajapted | 2012-11-25 13:28:20 +1100 (Sun, 25 Nov 2012) | 2 lines Don't create a linedef between two vertices at the same spot. ------------------------------------------------------------------------ r276 | ajapted | 2012-11-25 13:20:20 +1100 (Sun, 25 Nov 2012) | 2 lines Tweaked get_split_linedef() to skip lines with bbox < 4x4 ------------------------------------------------------------------------ r275 | ajapted | 2012-11-25 13:07:48 +1100 (Sun, 25 Nov 2012) | 2 lines Reworked last commit, don't split lines with bbox < 4x4. ------------------------------------------------------------------------ r274 | ajapted | 2012-11-25 13:04:00 +1100 (Sun, 25 Nov 2012) | 2 lines Fixed split_linedef command ('x' key) to not create zero-length lines. ------------------------------------------------------------------------ r273 | ajapted | 2012-11-25 12:24:55 +1100 (Sun, 25 Nov 2012) | 3 lines Fixed LineDefWouldOverlap() to skip zero-length lines, otherwise it raises a fatal error in PerpDist(). ------------------------------------------------------------------------ r272 | ajapted | 2012-11-24 17:46:35 +1100 (Sat, 24 Nov 2012) | 2 lines ChangeLog tweak. ------------------------------------------------------------------------ r271 | ajapted | 2012-11-24 17:01:01 +1100 (Sat, 24 Nov 2012) | 2 lines README: updated for 0.84 release, fixed the different keys. ------------------------------------------------------------------------ r270 | ajapted | 2012-11-24 15:40:58 +1100 (Sat, 24 Nov 2012) | 2 lines Tweaked code of previous commit (bound 'R' to RTS mode). ------------------------------------------------------------------------ r269 | ajapted | 2012-11-24 15:39:13 +1100 (Sat, 24 Nov 2012) | 2 lines Bound 'R' key for RTS editing mode, frees up 'r' for a more common function. ------------------------------------------------------------------------ r268 | ajapted | 2012-11-24 15:10:49 +1100 (Sat, 24 Nov 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r267 | ajapted | 2012-11-24 15:10:33 +1100 (Sat, 24 Nov 2012) | 2 lines INSTALL.txt : tweakage. ------------------------------------------------------------------------ r266 | ajapted | 2012-11-24 15:09:13 +1100 (Sat, 24 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r265 | ajapted | 2012-11-24 15:06:20 +1100 (Sat, 24 Nov 2012) | 3 lines Determine split line: removed bbox test (was bad for axis-aligned lines) and fixed the bbox test in get_split_line() which ignored mapslack. ------------------------------------------------------------------------ r264 | ajapted | 2012-11-24 14:46:50 +1100 (Sat, 24 Nov 2012) | 3 lines When finding the split_line, check the non-snapped position, but prevent the snapped position being the same as the linedef's start or end. ------------------------------------------------------------------------ r263 | ajapted | 2012-11-24 14:44:19 +1100 (Sat, 24 Nov 2012) | 2 lines MacOS X: fix pathlen type for _NSGetExecutablePath() call. ------------------------------------------------------------------------ r262 | ajapted | 2012-11-23 22:44:18 +1100 (Fri, 23 Nov 2012) | 2 lines minor docco updates. ------------------------------------------------------------------------ r261 | ajapted | 2012-11-23 21:44:43 +1100 (Fri, 23 Nov 2012) | 2 lines ChangeLog update. ------------------------------------------------------------------------ r260 | ajapted | 2012-11-23 21:42:44 +1100 (Fri, 23 Nov 2012) | 3 lines Made SHIFT + MMB do plain scaling (keep aspect ratio), ALT + MMB to scale X and Y independently. ------------------------------------------------------------------------ r259 | ajapted | 2012-11-23 20:59:45 +1100 (Fri, 23 Nov 2012) | 3 lines Key handling: change the ALT ignore code to return _false_, which means FLTK will send them to other places (especially the menu). ------------------------------------------------------------------------ r258 | ajapted | 2012-11-23 20:51:39 +1100 (Fri, 23 Nov 2012) | 4 lines Key handling: in general, ignore key if ALT is also pressed. Since the META modifier is mapped to KM_ALT, this also ignores keys with META (which I think is the CMD key under MacOS X). ------------------------------------------------------------------------ r257 | ajapted | 2012-11-22 22:23:28 +1100 (Thu, 22 Nov 2012) | 2 lines Implemented the -merge option for adding Resource wads. ------------------------------------------------------------------------ r256 | ajapted | 2012-11-22 22:03:17 +1100 (Thu, 22 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r255 | ajapted | 2012-11-22 22:02:45 +1100 (Thu, 22 Nov 2012) | 2 lines TODO / WISHLIST update. ------------------------------------------------------------------------ r254 | ajapted | 2012-11-22 21:35:53 +1100 (Thu, 22 Nov 2012) | 3 lines MacOSX: renamed the 'nil' method of Objid / Close_obj classes --> 'clear', since it is a reserved keyword in Objective-C. ------------------------------------------------------------------------ r253 | ajapted | 2012-11-22 21:08:32 +1100 (Thu, 22 Nov 2012) | 3 lines The ESC key no longer exits Eureka, unless the new 'escape_key_quits' config variable is enabled. ------------------------------------------------------------------------ r252 | ajapted | 2012-11-22 19:34:19 +1100 (Thu, 22 Nov 2012) | 2 lines MacOSX: Changed #ifdef tests to use __APPLE__ instead of MACOSX. ------------------------------------------------------------------------ r251 | ajapted | 2012-11-22 19:18:04 +1100 (Thu, 22 Nov 2012) | 4 lines Config: new syntax for config files, option name is followed by the value without any '=' sign between -- which is consistent with the game / port definition files. ------------------------------------------------------------------------ r250 | ajapted | 2012-11-22 17:28:25 +1100 (Thu, 22 Nov 2012) | 2 lines Config: split code to parse each line out of parse_config_file() function. ------------------------------------------------------------------------ r249 | ajapted | 2012-11-22 11:25:06 +1100 (Thu, 22 Nov 2012) | 2 lines WISHLIST: finished reorganising / prioritising the desirables. ------------------------------------------------------------------------ r248 | ajapted | 2012-11-22 11:06:47 +1100 (Thu, 22 Nov 2012) | 3 lines IWAD search: check some standard places, like /usr/share/games/doom (and for Win32, places like C:\DOOM). ------------------------------------------------------------------------ r247 | ajapted | 2012-11-22 10:35:07 +1100 (Thu, 22 Nov 2012) | 3 lines Moved some code in main.cc, like InitFLTK, which was sandwiched in between various config and directory handling stuff. ------------------------------------------------------------------------ r246 | ajapted | 2012-11-21 23:14:05 +1100 (Wed, 21 Nov 2012) | 2 lines WISHLIST: more work reorganising... ------------------------------------------------------------------------ r245 | ajapted | 2012-11-21 22:49:13 +1100 (Wed, 21 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r244 | ajapted | 2012-11-21 22:28:39 +1100 (Wed, 21 Nov 2012) | 2 lines minor commenting ------------------------------------------------------------------------ r243 | ajapted | 2012-11-21 22:26:08 +1100 (Wed, 21 Nov 2012) | 3 lines Allow Eureka to run locally (without a make install) by checking "." as a possible install_dir. ------------------------------------------------------------------------ r242 | ajapted | 2012-11-21 22:18:24 +1100 (Wed, 21 Nov 2012) | 2 lines INSTALL.txt : mention Gentoo info (courtesy GuntherDW). ------------------------------------------------------------------------ r241 | ajapted | 2012-11-21 22:12:59 +1100 (Wed, 21 Nov 2012) | 2 lines Config: fixed bug in recent change of OPT_BOOLEAN handling. ------------------------------------------------------------------------ r240 | ajapted | 2012-11-21 19:40:11 +1100 (Wed, 21 Nov 2012) | 2 lines WISHLIST: began reorganizing into HIGH and LOWER priority sections... ------------------------------------------------------------------------ r239 | ajapted | 2012-11-21 19:06:28 +1100 (Wed, 21 Nov 2012) | 4 lines Config: added 'new_islands_are_void' variable -- it forces islands created inside a sector to have a void interior (rather than a new sector which has same properties as the outer sector). ------------------------------------------------------------------------ r238 | ajapted | 2012-11-21 18:58:25 +1100 (Wed, 21 Nov 2012) | 5 lines Config handling: 1. can provide a value on command line for OPT_BOOLEAN vars 2. removed redundant checks on o->data_ptr (only NULL for OPT_END) 3. made boolean and confirm keywords case-insensitive ------------------------------------------------------------------------ r237 | ajapted | 2012-11-21 18:31:18 +1100 (Wed, 21 Nov 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r236 | ajapted | 2012-11-21 18:30:22 +1100 (Wed, 21 Nov 2012) | 2 lines CHANGELOG: mention the new pic-selection feature. ------------------------------------------------------------------------ r235 | ajapted | 2012-11-21 18:28:39 +1100 (Wed, 21 Nov 2012) | 2 lines Closing the browser unselects any pics in the LineDef and Sector panels. ------------------------------------------------------------------------ r234 | ajapted | 2012-11-21 18:18:34 +1100 (Wed, 21 Nov 2012) | 4 lines LineDef Panel: implemented the selected sidedef parts (with red border) getting a texture when clicking in the texture browser -- the mouse button and modifier keys are not used when any parts are selected. ------------------------------------------------------------------------ r233 | ajapted | 2012-11-21 17:27:01 +1100 (Wed, 21 Nov 2012) | 5 lines Sector panel: implemented the pic selection, i.e. when the floor pic is selected then the floor is changed and when the ceiling pic is selected then the ceiling is changed. The mouse button is ignored when one of them is selected. ------------------------------------------------------------------------ r232 | ajapted | 2012-11-21 16:20:48 +1100 (Wed, 21 Nov 2012) | 2 lines LineDef and Sector panels: don't select pic when there's no object(s). ------------------------------------------------------------------------ r231 | ajapted | 2012-11-21 16:16:35 +1100 (Wed, 21 Nov 2012) | 4 lines LineDef and Sector panels: code to clear the selected pics, automatic when the panel is disabled (NO_OBJ), and can be done externally (e.g. when changing editing modes). ------------------------------------------------------------------------ r230 | ajapted | 2012-11-21 16:02:51 +1100 (Wed, 21 Nov 2012) | 2 lines Use CMD_UnselectAll() for the click-in-empty-spot action. ------------------------------------------------------------------------ r229 | ajapted | 2012-11-21 15:51:04 +1100 (Wed, 21 Nov 2012) | 5 lines 1. added ability to UI_Pic to select/unselect it (done externally) 2. in Sector and SideDef panels, can select/unselect the textures and also open/change the browser to Flats or Textures. (Note: still lacking mechanism to actually change the selected stuff) ------------------------------------------------------------------------ r228 | ajapted | 2012-11-21 14:15:49 +1100 (Wed, 21 Nov 2012) | 2 lines UI_Pic: implemented a draw_selected() method. ------------------------------------------------------------------------ r227 | ajapted | 2012-11-21 12:46:06 +1100 (Wed, 21 Nov 2012) | 3 lines Makefile: remove wayward initial space (stops emacs complaining when saving). Patch courtesy Jeremy Henty. ------------------------------------------------------------------------ r226 | ajapted | 2012-11-21 12:39:32 +1100 (Wed, 21 Nov 2012) | 3 lines Implemented 'leave_offsets_alone' config var -- when set, no automatic adjustment of sidedef offsets when splitting lines (etc). ------------------------------------------------------------------------ r225 | ajapted | 2012-11-21 12:31:39 +1100 (Wed, 21 Nov 2012) | 3 lines Thing panel: experimented with option buttons for Hexen player classes, and hence moved the 'ambush' and 'friend' buttons onto their own line. ------------------------------------------------------------------------ r224 | ajapted | 2012-11-20 22:47:29 +1100 (Tue, 20 Nov 2012) | 2 lines TODO, WISHLIST, CHANGELOG update ------------------------------------------------------------------------ r223 | ajapted | 2012-11-20 22:43:32 +1100 (Tue, 20 Nov 2012) | 3 lines UI_Canvas: fixed bug where a pink-highlighted sectors with tag matching the linedef would not be drawn if the linedef was off the screen. ------------------------------------------------------------------------ r222 | ajapted | 2012-11-20 22:34:58 +1100 (Tue, 20 Nov 2012) | 2 lines LineDef panel: experiment with 'Args' line (for Hexen support) ------------------------------------------------------------------------ r221 | ajapted | 2012-11-20 21:23:19 +1100 (Tue, 20 Nov 2012) | 3 lines Multi-select: handle a small selbox as if it were a click/release pair (clearing the current selection) -- shrink the small selbox to zero. ------------------------------------------------------------------------ r220 | ajapted | 2012-11-20 21:07:22 +1100 (Tue, 20 Nov 2012) | 2 lines Insert_Thing: if a thing is already selected, copy properties to new one. ------------------------------------------------------------------------ r219 | ajapted | 2012-11-20 20:58:04 +1100 (Tue, 20 Nov 2012) | 14 lines Implemented multi-select, i.e. clicking on an object to select it will not clear the current selection first -- merely toggle it. This required some big changes and a hack or two, for one thing when clicking on an object, it's selection status is changed when the the mouse button is _released_ (or user tries to drag it). Also to allow dragging individual objects, after any objects are moved we will clear the selection when an unselected object is clicked on (to select it). Removed the dummy 'CANVAS' object kind, we now properly test whether we are drawing a selbox by the isSelboxActive() call. ------------------------------------------------------------------------ r218 | ajapted | 2012-11-20 17:57:55 +1100 (Tue, 20 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r217 | ajapted | 2012-11-20 17:48:00 +1100 (Tue, 20 Nov 2012) | 3 lines Fixed inner sector getting defaults when closing a vertex loop which lies within another sector -- the inner should be a copy of the outer. ------------------------------------------------------------------------ r216 | ajapted | 2012-11-19 22:47:45 +1100 (Mon, 19 Nov 2012) | 4 lines Changed the way level checksum is done (for state persistence), it is no longer done directly in the loading and saving code (and performed on the raw formats), now it is computed on the in-memory version of the map. ------------------------------------------------------------------------ r215 | ajapted | 2012-11-19 22:36:36 +1100 (Mon, 19 Nov 2012) | 2 lines Adler-32: fixed the copy constructor to copy the 'extra' field too. ------------------------------------------------------------------------ r214 | ajapted | 2012-11-19 22:31:29 +1100 (Mon, 19 Nov 2012) | 3 lines Implemented BA_LevelChecksum() which computes the CRC of the level, ignoring any unused vertices, sidedefs or sectors. ------------------------------------------------------------------------ r213 | ajapted | 2012-11-19 21:38:13 +1100 (Mon, 19 Nov 2012) | 3 lines Browser: set the 'linesize' to higher values, so that scrolling with the mouse wheel is better (not so tedious). ------------------------------------------------------------------------ r212 | ajapted | 2012-11-19 21:35:21 +1100 (Mon, 19 Nov 2012) | 2 lines Browser: made default width be a bit wider (to fit 4 flats across). ------------------------------------------------------------------------ r211 | ajapted | 2012-11-19 16:51:43 +1100 (Mon, 19 Nov 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r210 | ajapted | 2012-11-19 16:51:07 +1100 (Mon, 19 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r209 | ajapted | 2012-11-19 16:50:10 +1100 (Mon, 19 Nov 2012) | 3 lines 1. Support a "default_port" command in game definition files 2. Made the fallback port be "vanilla" -- for Heretic ------------------------------------------------------------------------ r208 | ajapted | 2012-11-19 16:42:27 +1100 (Mon, 19 Nov 2012) | 2 lines DOOM defs: added "default_port boom" ------------------------------------------------------------------------ r207 | ajapted | 2012-11-19 16:35:03 +1100 (Mon, 19 Nov 2012) | 2 lines Game def loader: tidied up 'buf' usage, renamed other 'buf' variables. ------------------------------------------------------------------------ r206 | ajapted | 2012-11-19 14:32:53 +1100 (Mon, 19 Nov 2012) | 5 lines lib_file: added GetExecutablePath() function, needed for Win32 builds. Code is from Oblige's lib_file.cc, which I removed earlier as I didn't think it would be needed. ------------------------------------------------------------------------ r205 | ajapted | 2012-11-18 22:26:32 +1100 (Sun, 18 Nov 2012) | 2 lines Updated CHANGELOG, TODO and WISHLIST. ------------------------------------------------------------------------ r204 | ajapted | 2012-11-18 21:38:32 +1100 (Sun, 18 Nov 2012) | 2 lines Thing panel: got new arrow buttons working, and improved the layout. ------------------------------------------------------------------------ r203 | ajapted | 2012-11-18 21:28:24 +1100 (Sun, 18 Nov 2012) | 2 lines Arrow images: trimmed the diagonal arrows, look better now. ------------------------------------------------------------------------ r202 | ajapted | 2012-11-18 21:21:54 +1100 (Sun, 18 Nov 2012) | 3 lines Thing panel: partial work on eight arrow buttons for setting the angle. These replace the <- and -> buttons which rotated things. ------------------------------------------------------------------------ r201 | ajapted | 2012-11-18 20:42:03 +1100 (Sun, 18 Nov 2012) | 2 lines Added 'im_arrows.cc' containing eight small arrow images (XPM format). ------------------------------------------------------------------------ r200 | ajapted | 2012-11-18 18:58:50 +1100 (Sun, 18 Nov 2012) | 2 lines Experiment to make plain MMB insert new objects.... ------------------------------------------------------------------------ r199 | ajapted | 2012-11-18 18:28:14 +1100 (Sun, 18 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r198 | ajapted | 2012-11-18 18:26:57 +1100 (Sun, 18 Nov 2012) | 8 lines 3D View: 1. support WASD keys for movement 2. rebound 's' key to 'o' (toggle sprites) and 'w' --> 'v' 3. added 'g' key to toggle gravity 4. removed CTRL-L : resync thing Zs when toggling sprites Note (1) and (3) were suggested by Dragonsbrethen. ------------------------------------------------------------------------ r197 | ajapted | 2012-11-18 13:38:51 +1100 (Sun, 18 Nov 2012) | 2 lines INSTALL.txt : mention some libraries people may need (thanks to DoomGater). ------------------------------------------------------------------------ r196 | ajapted | 2012-11-18 13:37:44 +1100 (Sun, 18 Nov 2012) | 2 lines Began a fresh CHANGES.txt document ------------------------------------------------------------------------ r195 | ajapted | 2012-11-18 13:36:10 +1100 (Sun, 18 Nov 2012) | 2 lines Moved CHANGES.txt --> docs folder (after 0.81 release) ------------------------------------------------------------------------ r194 | ajapted | 2012-11-18 13:35:17 +1100 (Sun, 18 Nov 2012) | 2 lines CMD_BuildNodes: on success, re-open the wad and reload the map. ------------------------------------------------------------------------ r193 | ajapted | 2012-11-18 12:50:12 +1100 (Sun, 18 Nov 2012) | 2 lines Post-release version bump: 0.81 --> 0.82 ------------------------------------------------------------------------ r192 | ajapted | 2012-11-16 20:23:01 +1100 (Fri, 16 Nov 2012) | 2 lines Fixed pack-source.sh script (had some Oblige stuff left in it). ------------------------------------------------------------------------ r191 | ajapted | 2012-11-16 13:58:54 +1100 (Fri, 16 Nov 2012) | 2 lines Checked in 'pack-source.sh' shell script. ------------------------------------------------------------------------ r190 | ajapted | 2012-11-16 13:21:15 +1100 (Fri, 16 Nov 2012) | 2 lines TODO and WISHLIST update. ------------------------------------------------------------------------ r189 | ajapted | 2012-11-16 13:19:55 +1100 (Fri, 16 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r188 | ajapted | 2012-11-16 13:17:14 +1100 (Fri, 16 Nov 2012) | 5 lines README.txt: 1. completely rewrote the 'RUNNING' section 2. replaced 'INTRODUCTION' section with text from 'About' wiki page 3. replaced 'KEYBOARD / MOUSE' section with text from wiki ------------------------------------------------------------------------ r187 | ajapted | 2012-11-16 11:37:03 +1100 (Fri, 16 Nov 2012) | 2 lines Renamed changelog files (in docs/) ------------------------------------------------------------------------ r186 | ajapted | 2012-11-15 17:29:09 +1100 (Thu, 15 Nov 2012) | 2 lines minor commenting... ------------------------------------------------------------------------ r185 | ajapted | 2012-11-15 17:24:53 +1100 (Thu, 15 Nov 2012) | 3 lines Improved the way AssignSectorToSpace() sets the default sector props from a neighbor. ------------------------------------------------------------------------ r184 | ajapted | 2012-11-15 16:23:04 +1100 (Thu, 15 Nov 2012) | 2 lines With 'c' copy-prop command on things, do not copy the angle. ------------------------------------------------------------------------ r183 | ajapted | 2012-11-15 16:14:59 +1100 (Thu, 15 Nov 2012) | 2 lines Removed no-longer-used code files: editobj.cc/h ------------------------------------------------------------------------ r182 | ajapted | 2012-11-15 16:11:39 +1100 (Thu, 15 Nov 2012) | 4 lines Implemented new 'c' copy-properties command, which will copy the props of a sector (for example) from the selected one to the highlighted one. Works for things and linedefs too (though linedefs is very limited). ------------------------------------------------------------------------ r181 | ajapted | 2012-11-15 15:52:14 +1100 (Thu, 15 Nov 2012) | 2 lines Moved LineDefAlreadyExists() and LineDefWouldOverlap() code --> e_linedef.cc ------------------------------------------------------------------------ r180 | ajapted | 2012-11-15 12:00:04 +1100 (Thu, 15 Nov 2012) | 2 lines CHANGELOG updated. ------------------------------------------------------------------------ r179 | ajapted | 2012-11-15 11:57:10 +1100 (Thu, 15 Nov 2012) | 3 lines Insert_Sector: when creating a square outside of map, if a sector is already selected then copy the properties to the new sector. ------------------------------------------------------------------------ r178 | ajapted | 2012-11-15 11:45:43 +1100 (Thu, 15 Nov 2012) | 2 lines CMD_MergeSectors: if deleting linedefs, delete unused vertices too. ------------------------------------------------------------------------ r177 | ajapted | 2012-11-15 11:43:32 +1100 (Thu, 15 Nov 2012) | 3 lines Wrote DeleteLineDefs() function which not only deletes a list of lines, but also deletes the unused vertices/sidedefs left over. ------------------------------------------------------------------------ r176 | ajapted | 2012-11-15 11:41:54 +1100 (Thu, 15 Nov 2012) | 3 lines Moved UnusedVertices() and UnusedSideDefs() functions to global scope, and renamed the 'list' parameter to 'lines' (for clearer code). ------------------------------------------------------------------------ r175 | ajapted | 2012-11-15 10:49:38 +1100 (Thu, 15 Nov 2012) | 4 lines Emulate the Yadex (DEU?) behavior where trying to set the same mode as currently active will clear the selection. This is enabled by the 'same_mode_clears_selection' config variable (default is OFF). ------------------------------------------------------------------------ r174 | ajapted | 2012-11-15 10:35:56 +1100 (Thu, 15 Nov 2012) | 5 lines CMD_MergeSectors: reworked way common linedefs are found, only detect them between the source sector and a replaced sector (which prevents removing pre-existing "self-ref" linedefs). Also store them in a selection_c. ------------------------------------------------------------------------ r173 | ajapted | 2012-11-15 10:30:24 +1100 (Thu, 15 Nov 2012) | 2 lines Editor_Key: ensure the new 'm' merge command can only be used in Sectors mode. ------------------------------------------------------------------------ r172 | ajapted | 2012-11-14 22:29:26 +1100 (Wed, 14 Nov 2012) | 2 lines Render 3D: made ALT + LEFT / RIGHT keys strafe instead of turn. ------------------------------------------------------------------------ r171 | ajapted | 2012-11-14 22:22:53 +1100 (Wed, 14 Nov 2012) | 2 lines TODO / WISHLIST update. ------------------------------------------------------------------------ r170 | ajapted | 2012-11-14 19:46:24 +1100 (Wed, 14 Nov 2012) | 3 lines Sector mode: implemented 'm' merge command which merges all selected sectors into a single one. The 'M' variant will keep common linedefs, ------------------------------------------------------------------------ r169 | ajapted | 2012-11-14 19:04:33 +1100 (Wed, 14 Nov 2012) | 4 lines Sector mode: reworked handling of SPACE / INSERT key: 1. when a sector is highlighted, assume want to "correct" that sector 2. force insertion of a NEW sector via CTRL key ------------------------------------------------------------------------ r168 | ajapted | 2012-11-14 16:43:28 +1100 (Wed, 14 Nov 2012) | 2 lines CHANGELOG: mention the recent vertex-insertion changes. ------------------------------------------------------------------------ r167 | ajapted | 2012-11-14 16:38:50 +1100 (Wed, 14 Nov 2012) | 4 lines Vertex insertion: handle the case where a new vertex would split a line and the selected vertex is an endpoint of that line -- simply split the line (as if no vertex had been selected). ------------------------------------------------------------------------ r166 | ajapted | 2012-11-14 15:13:36 +1100 (Wed, 14 Nov 2012) | 3 lines Vertex insertion: improved overlap test, refuse the operation for the case of adding a line between old --> new vertex. ------------------------------------------------------------------------ r165 | ajapted | 2012-11-14 15:05:55 +1100 (Wed, 14 Nov 2012) | 3 lines Vertex insertion: prevent adding a new linedef if it would overlap an existing line. ------------------------------------------------------------------------ r164 | ajapted | 2012-11-14 14:57:12 +1100 (Wed, 14 Nov 2012) | 2 lines Basis: added LineDef::CalcLength() method. ------------------------------------------------------------------------ r163 | ajapted | 2012-11-14 14:37:34 +1100 (Wed, 14 Nov 2012) | 7 lines Vertex insertion: 1. if one vertex is selected and it is highlighted (or new position is snapped to same coord), then merely de-select it. 2. if two is selected (or one + highlight) and the linedef already exists, then merely select the second and deselect the first. ------------------------------------------------------------------------ r162 | ajapted | 2012-11-13 21:49:26 +1100 (Tue, 13 Nov 2012) | 4 lines When closing a simple vertex loop which is inside an existing sector, now create a sector on the inside of the loop (instead of creating a pillar). Eventually this will be a config option. ------------------------------------------------------------------------ r161 | ajapted | 2012-11-13 21:38:21 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete CopyObjects() code. ------------------------------------------------------------------------ r160 | ajapted | 2012-11-13 21:35:03 +1100 (Tue, 13 Nov 2012) | 2 lines Fully disabled some usage of 'SelPtr' which I missed before. ------------------------------------------------------------------------ r159 | ajapted | 2012-11-13 21:34:09 +1100 (Tue, 13 Nov 2012) | 2 lines Disabled 'c' and 'm' keys, they are about to be re-purposed... ------------------------------------------------------------------------ r158 | ajapted | 2012-11-13 21:32:18 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete DoInsertObject() code. ------------------------------------------------------------------------ r157 | ajapted | 2012-11-13 21:13:09 +1100 (Tue, 13 Nov 2012) | 2 lines TODO: hammered out new logic for Sector creation / correction / copying. ------------------------------------------------------------------------ r156 | ajapted | 2012-11-13 20:07:29 +1100 (Tue, 13 Nov 2012) | 2 lines TODO / WISHLIST update. ------------------------------------------------------------------------ r155 | ajapted | 2012-11-13 20:01:09 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete ymemory.cc/h code files. ------------------------------------------------------------------------ r154 | ajapted | 2012-11-13 19:59:06 +1100 (Tue, 13 Nov 2012) | 6 lines Config code: 1. define a string_list_t type using std::vector 2. rewrote OPT_STRING_LIST handling to use string_list_t 3. removed append_item_to_list() function 4. replaced a usage of GetMemory() with StringDup() ------------------------------------------------------------------------ r153 | ajapted | 2012-11-13 17:25:09 +1100 (Tue, 13 Nov 2012) | 3 lines Removed the 'SelPtr' type once and for all. Disabled various pieces of code which was using it (most of that was disabled already). ------------------------------------------------------------------------ r152 | ajapted | 2012-11-13 17:22:23 +1100 (Tue, 13 Nov 2012) | 2 lines Removed unused bv_vertices_of_sectors() code. ------------------------------------------------------------------------ r151 | ajapted | 2012-11-13 17:21:33 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete list_to_bitvec() and bitvec_to_list() functions. ------------------------------------------------------------------------ r150 | ajapted | 2012-11-13 17:16:34 +1100 (Tue, 13 Nov 2012) | 2 lines Removed unused linedefs_of_sectors() code. ------------------------------------------------------------------------ r149 | ajapted | 2012-11-13 17:14:13 +1100 (Tue, 13 Nov 2012) | 2 lines Removed unused unlink_sidedef() code. ------------------------------------------------------------------------ r148 | ajapted | 2012-11-13 17:06:16 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete MoveObjectsToCoord() code. ------------------------------------------------------------------------ r147 | ajapted | 2012-11-13 17:05:37 +1100 (Tue, 13 Nov 2012) | 3 lines Removed obsolete list_vertices_of_xxxs() functions. Removed obsolete bv_vertices_of_linedefs(SelPtr) function. ------------------------------------------------------------------------ r146 | ajapted | 2012-11-13 16:57:27 +1100 (Tue, 13 Nov 2012) | 3 lines Removed unused (and mostly broken) centre_of_xxxs functions. Only one left is centre_of_sector(), which is actually used and works. ------------------------------------------------------------------------ r145 | ajapted | 2012-11-13 16:51:55 +1100 (Tue, 13 Nov 2012) | 2 lines Removed old/unused/disabled MergeVertices() and AutoMergeVertices() code. ------------------------------------------------------------------------ r144 | ajapted | 2012-11-13 16:50:06 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete RotateAndScaleObjects() code. ------------------------------------------------------------------------ r143 | ajapted | 2012-11-13 16:09:46 +1100 (Tue, 13 Nov 2012) | 2 lines Removed a bunch of unused stuff from editobj.cc/h ------------------------------------------------------------------------ r142 | ajapted | 2012-11-12 22:32:18 +1100 (Mon, 12 Nov 2012) | 2 lines Fleshed out the INSTALL.txt document. ------------------------------------------------------------------------ r141 | ajapted | 2012-11-12 21:12:28 +1100 (Mon, 12 Nov 2012) | 3 lines CMD_BuildNodes: show an error message if edit_wad has ".new" extension (otherwise the delete + rename logic is going to fail). ------------------------------------------------------------------------ r140 | ajapted | 2012-11-12 21:10:03 +1100 (Mon, 12 Nov 2012) | 2 lines File utils: renamed CheckExtension() --> MatchExtension() ------------------------------------------------------------------------ r139 | ajapted | 2012-11-12 20:24:27 +1100 (Mon, 12 Nov 2012) | 3 lines CMD_BuildNodes: fixed bug where 'old_name' became invalid rubbish because the edit_wad object was deleted. ------------------------------------------------------------------------ r138 | ajapted | 2012-11-12 16:10:50 +1100 (Mon, 12 Nov 2012) | 5 lines CMD_BuildNodes: 1. use proper output name, replacing extension with ".new" 2. delete the ".new" file if the build was unsuccessful (cancel or error) 3. if successful, delete old file and rename new file to old filename ------------------------------------------------------------------------ r137 | ajapted | 2012-11-12 16:08:05 +1100 (Mon, 12 Nov 2012) | 1 line tweak ------------------------------------------------------------------------ r136 | ajapted | 2012-11-12 14:50:31 +1100 (Mon, 12 Nov 2012) | 3 lines CMD_BuildNodes: added proper (albeit simplistic) dialogs when the user tries to build nodes without any PWAD, or when there are unsaved changes. ------------------------------------------------------------------------ r135 | ajapted | 2012-11-12 14:41:23 +1100 (Mon, 12 Nov 2012) | 4 lines CMD_BuildNodes: properly split lines in UI_Nodes::Add() method. Also: added a blank line before each error message. ------------------------------------------------------------------------ r134 | ajapted | 2012-11-12 14:33:49 +1100 (Mon, 12 Nov 2012) | 2 lines CHANGELOG: added entry for the new node building feature. ------------------------------------------------------------------------ r133 | ajapted | 2012-11-12 14:27:34 +1100 (Mon, 12 Nov 2012) | 3 lines CMD_BuildNodes: handle the ESCAPE key better -- if not finished then cancel the build, otherwise close the window. ------------------------------------------------------------------------ r132 | ajapted | 2012-11-12 14:26:38 +1100 (Mon, 12 Nov 2012) | 1 line whitespacing ------------------------------------------------------------------------ r131 | ajapted | 2012-11-12 13:17:48 +1100 (Mon, 12 Nov 2012) | 6 lines CMD_BuildNodes: 1. support the CLOSE button and Cancel button in UI_Nodes 2. cancel the build when user wants to cancel (or close the window) 3. show final status (Success/Cancel/ERROR) in the progress bar 4. on success, use CMD_Quit to exit Eureka ------------------------------------------------------------------------ r130 | ajapted | 2012-11-12 11:32:55 +1100 (Mon, 12 Nov 2012) | 6 lines CMD_BuildNodes: 1. added and implemented the progress bar 2. added 'Cancel' button (not working yet) 3. move text browser to bottom for each Add() 4. tidy up of glbsp callbacks ------------------------------------------------------------------------ r129 | ajapted | 2012-11-11 22:37:48 +1100 (Sun, 11 Nov 2012) | 3 lines CMD_BuildNodes: use Fl::check() to ensure window gets shown before the node building begins. ------------------------------------------------------------------------ r128 | ajapted | 2012-11-11 22:28:37 +1100 (Sun, 11 Nov 2012) | 2 lines Version bump to 0.81 ------------------------------------------------------------------------ r127 | ajapted | 2012-11-11 22:27:04 +1100 (Sun, 11 Nov 2012) | 2 lines svn:ignore ------------------------------------------------------------------------ r126 | ajapted | 2012-11-11 22:14:56 +1100 (Sun, 11 Nov 2012) | 2 lines TODO tidy up. ------------------------------------------------------------------------ r125 | ajapted | 2012-11-11 21:50:49 +1100 (Sun, 11 Nov 2012) | 2 lines Makefile: added ui_nodes.o to the build. ------------------------------------------------------------------------ r124 | ajapted | 2012-11-11 21:50:23 +1100 (Sun, 11 Nov 2012) | 2 lines CMD_BuildNodes: bit more work on dialog window.... ------------------------------------------------------------------------ r123 | ajapted | 2012-11-11 21:24:40 +1100 (Sun, 11 Nov 2012) | 2 lines CMD_BuildNodes: handle the "(Hexen)" suffix when determining map name. ------------------------------------------------------------------------ r122 | ajapted | 2012-11-11 21:22:48 +1100 (Sun, 11 Nov 2012) | 4 lines Initial work on a UI_NodeDialog window, which will show the progress of building nodes and the output from the node builder, as well as have CANCEL and OK buttons. Very skeletal so far.... ------------------------------------------------------------------------ r121 | ajapted | 2012-11-11 20:56:55 +1100 (Sun, 11 Nov 2012) | 2 lines CMD_BuildNodes: extract map name from progress-bar text. ------------------------------------------------------------------------ r120 | ajapted | 2012-11-11 20:50:14 +1100 (Sun, 11 Nov 2012) | 3 lines CMD_BuildNodes: added interface code to glBSP and the function which does all the heavy lifting (DM_BuildNodes). Mainly copy'n'paste from OBLIGE. ------------------------------------------------------------------------ r119 | ajapted | 2012-11-11 20:26:20 +1100 (Sun, 11 Nov 2012) | 4 lines Makefile: logic for building and linking the glBSP code. Also added conditional lines for FLTK in a non-standard place. ------------------------------------------------------------------------ r118 | ajapted | 2012-11-11 20:21:46 +1100 (Sun, 11 Nov 2012) | 2 lines Deleted Makefile.opt -- added the extra bits into 'Makefile' (in a conditional section). ------------------------------------------------------------------------ r117 | ajapted | 2012-11-11 19:15:58 +1100 (Sun, 11 Nov 2012) | 4 lines glbsp code: encapsulated all code into a 'glbsp' namespace. Also removed the 'Glbsp' prefix from a few API functions. ------------------------------------------------------------------------ r116 | ajapted | 2012-11-11 19:00:47 +1100 (Sun, 11 Nov 2012) | 2 lines Checked in a copy of glBSP 2.27 source code. ------------------------------------------------------------------------ r115 | ajapted | 2012-11-11 18:25:04 +1100 (Sun, 11 Nov 2012) | 2 lines CMD_BuildNodes: make sure we have a PWAD. ------------------------------------------------------------------------ r114 | ajapted | 2012-11-11 16:53:06 +1100 (Sun, 11 Nov 2012) | 4 lines Preliminary work on "Build Nodes" command (in File menu, CTRL-B key). This will invoke an external nodes builder (glbsp for now), show the output, then quit. ------------------------------------------------------------------------ r113 | ajapted | 2012-11-10 23:10:38 +1100 (Sat, 10 Nov 2012) | 3 lines 1. Keyboard shortcuts T/F/O/S/L open browser at specific kind 2. Made MIN_BROWSER_W a bit narrower (280 --> 260) ------------------------------------------------------------------------ r112 | ajapted | 2012-11-10 23:08:54 +1100 (Sat, 10 Nov 2012) | 2 lines Browser: tweaked position of 'Pics' button. ------------------------------------------------------------------------ r111 | ajapted | 2012-11-10 22:35:25 +1100 (Sat, 10 Nov 2012) | 2 lines Added 'INSTALL.txt' document (mostly empty). ------------------------------------------------------------------------ r110 | ajapted | 2012-11-10 22:16:58 +1100 (Sat, 10 Nov 2012) | 2 lines Tweaked calculations in zoom_fit(). ------------------------------------------------------------------------ r109 | ajapted | 2012-11-10 22:16:17 +1100 (Sat, 10 Nov 2012) | 2 lines Fixed initial zoom (it was computed while browser was still present). ------------------------------------------------------------------------ r108 | ajapted | 2012-11-10 21:57:45 +1100 (Sat, 10 Nov 2012) | 3 lines Makefiles: updated 'install' target with commands to install the desktop and icon files, using the XDG tools (in the xdg-utils package). ------------------------------------------------------------------------ r107 | ajapted | 2012-11-10 21:11:24 +1100 (Sat, 10 Nov 2012) | 3 lines DESKTOP file: Removed 'Application' from Categories, as the desktop-file-validate program warned it was deprecated. ------------------------------------------------------------------------ r106 | ajapted | 2012-11-10 19:47:55 +1100 (Sat, 10 Nov 2012) | 2 lines Desktop file: added StartupNotify=false ------------------------------------------------------------------------ r105 | ajapted | 2012-11-10 19:07:08 +1100 (Sat, 10 Nov 2012) | 2 lines TODO and CHANGELOG update. ------------------------------------------------------------------------ r104 | ajapted | 2012-11-10 18:45:49 +1100 (Sat, 10 Nov 2012) | 4 lines In game defs, allow texture and flat group to be uppercase, and match these against the 'X' category. This is a very simple way to allow textures and flats to belong (or not) to one additional group. ------------------------------------------------------------------------ r103 | ajapted | 2012-11-10 18:41:05 +1100 (Sat, 10 Nov 2012) | 2 lines Browser: made initial width a bit wider (show 4 flats instead of 3). ------------------------------------------------------------------------ r102 | ajapted | 2012-11-10 17:15:25 +1100 (Sat, 10 Nov 2012) | 2 lines DOOM game def: assigned SKY1/2/3 and F_SKY1 into 'Natural' category. ------------------------------------------------------------------------ r101 | ajapted | 2012-11-10 16:42:14 +1100 (Sat, 10 Nov 2012) | 2 lines PLUTONIA game defs: assigned categories for all the new textures. ------------------------------------------------------------------------ r100 | ajapted | 2012-11-10 16:24:53 +1100 (Sat, 10 Nov 2012) | 3 lines TNT game def: placed all the new TNT textures into categories, including two new categories "Crates" and "Egypt". ------------------------------------------------------------------------ r99 | ajapted | 2012-11-10 15:37:20 +1100 (Sat, 10 Nov 2012) | 3 lines DOOM defs: fixed the 'SW2XXX' textures which were lacking a category line for them -- should be same as their 'SW1' counterparts. ------------------------------------------------------------------------ r98 | ajapted | 2012-11-10 15:32:18 +1100 (Sat, 10 Nov 2012) | 2 lines CHANGELOG: tweaked layout (use two spaces) ------------------------------------------------------------------------ r97 | ajapted | 2012-11-10 15:21:22 +1100 (Sat, 10 Nov 2012) | 2 lines Update for TODO.txt and CHANGES.txt ------------------------------------------------------------------------ r96 | ajapted | 2012-11-10 15:18:45 +1100 (Sat, 10 Nov 2012) | 4 lines Render: strafe left/right when the ALT (or META) key is pressed (in addition to the RMB). It is not ideal, since window manager will typically steal the ALT + RMB combination for themselves. ------------------------------------------------------------------------ r95 | ajapted | 2012-11-10 15:00:50 +1100 (Sat, 10 Nov 2012) | 3 lines When searching for IWADs, check for uppercase'd name (like "DOOM.WAD"). This also required lowercasing it when determining the Game name. ------------------------------------------------------------------------ r94 | ajapted | 2012-11-10 14:56:50 +1100 (Sat, 10 Nov 2012) | 2 lines Utils: added y_strlowr() and rewrote y_strupr(). ------------------------------------------------------------------------ r93 | ajapted | 2012-11-10 14:34:50 +1100 (Sat, 10 Nov 2012) | 6 lines Improved IWAD finding logic: 1. if the -iwad parameter has no extension, add ".wad" 2. if the -iwad parameter is a bare name, look in iwad search path 3. added ~/.eureka/iwads directory to search path 4. when searching, look for other iwad names (e.g. "doom.wad" and "tnt.wad") ------------------------------------------------------------------------ r92 | ajapted | 2012-11-10 13:54:12 +1100 (Sat, 10 Nov 2012) | 3 lines 1. Require a valid home_dir 2. Create extra subdirs in the home dir ("iwads/", "games/" etc) ------------------------------------------------------------------------ r91 | ajapted | 2012-11-10 13:26:44 +1100 (Sat, 10 Nov 2012) | 3 lines Refactored code into DetermineLevel() for finding what level to use, and added support for plain numbers (e.g. -warp 15). ------------------------------------------------------------------------ r90 | ajapted | 2012-11-10 13:23:20 +1100 (Sat, 10 Nov 2012) | 3 lines WAD code: implemented FindLevelByNumber() method for Wad_file, which will look for a match against "MAP##" or "E#M#" level names. ------------------------------------------------------------------------ r89 | ajapted | 2012-11-10 12:57:00 +1100 (Sat, 10 Nov 2012) | 2 lines When level name is not specified, find the first one in the PWAD or IWAD. ------------------------------------------------------------------------ r88 | ajapted | 2012-11-10 12:12:27 +1100 (Sat, 10 Nov 2012) | 2 lines WAD code: added API for reading level list. ------------------------------------------------------------------------ r87 | ajapted | 2012-11-10 12:07:55 +1100 (Sat, 10 Nov 2012) | 2 lines WAD code: added 'FindFirstLevel' method to Wad_file class. ------------------------------------------------------------------------ r86 | ajapted | 2012-11-10 11:57:50 +1100 (Sat, 10 Nov 2012) | 3 lines 1. renamed Editor_Loop --> Main_Loop, moved into main.cc 2. start with browser disabled (turn off after creating main_win) ------------------------------------------------------------------------ r85 | ajapted | 2012-11-09 23:08:49 +1100 (Fri, 09 Nov 2012) | 3 lines UI_Scroll: use clip_children(1) to prevent contents from drawing over other parts of the GUI. ------------------------------------------------------------------------ r84 | ajapted | 2012-11-09 22:54:44 +1100 (Fri, 09 Nov 2012) | 2 lines Browser: tweaked layout of images ------------------------------------------------------------------------ r83 | ajapted | 2012-11-09 22:41:21 +1100 (Fri, 09 Nov 2012) | 2 lines UI_Scroll: added ability to horizontally resize child widgets. ------------------------------------------------------------------------ r82 | ajapted | 2012-11-09 22:21:17 +1100 (Fri, 09 Nov 2012) | 2 lines UI_Scroll: make sure scrollbar gets vertically resized. ------------------------------------------------------------------------ r81 | ajapted | 2012-11-09 22:18:41 +1100 (Fri, 09 Nov 2012) | 2 lines UI_Scroll: fixed Remove_first() which erroneously removed the scrollbar. ------------------------------------------------------------------------ r80 | ajapted | 2012-11-09 21:42:46 +1100 (Fri, 09 Nov 2012) | 4 lines UI_Scroll: made it a subclass of Fl_Group (it is not really possible with FLTK to make container widgets any other way). Renamed the group like methods to use an uppercase letter (Add, Remove, Init_Sizes, etc). ------------------------------------------------------------------------ r79 | ajapted | 2012-11-08 21:52:31 +1100 (Thu, 08 Nov 2012) | 2 lines UI_Scroll: more work on scrolling -- it is working pretty well now. ------------------------------------------------------------------------ r78 | ajapted | 2012-11-08 19:29:29 +1100 (Thu, 08 Nov 2012) | 2 lines UI_Scroll: got ability to scroll working, via new reposition_all() method. ------------------------------------------------------------------------ r77 | ajapted | 2012-11-08 19:20:12 +1100 (Thu, 08 Nov 2012) | 4 lines UI_Scroll: the init_sizes() method now calculates the bottom of all child widgets. Added a callback for the scrollbar (all it does currently is redraw). ------------------------------------------------------------------------ r76 | ajapted | 2012-11-08 15:57:56 +1100 (Thu, 08 Nov 2012) | 2 lines Browser: added an undrawn resize box to control resizing. ------------------------------------------------------------------------ r75 | ajapted | 2012-11-07 20:38:29 +1100 (Wed, 07 Nov 2012) | 2 lines UI_Scroll: draw the box. ------------------------------------------------------------------------ r74 | ajapted | 2012-11-07 20:00:02 +1100 (Wed, 07 Nov 2012) | 4 lines Browser: partial work to transition to new UI_Scroll widget, renamed the 'pack' field --> 'scroll', removed the resize_buttons() and fix_scrollbar_order() hacks, and disabled a few things. ------------------------------------------------------------------------ r73 | ajapted | 2012-11-07 19:57:38 +1100 (Wed, 07 Nov 2012) | 3 lines UI_Scroll widget: fleshed out some methods, and added a few delegates e.g. children() which merely passes through to pack->children(). ------------------------------------------------------------------------ r72 | ajapted | 2012-11-07 19:37:48 +1100 (Wed, 07 Nov 2012) | 5 lines Browser: update the image list when resized (reposition them). This commit includes an attempt to get text buttons horizontally resized, but it doesn't work since Fl_Scroll is an utter piece of crap. ------------------------------------------------------------------------ r71 | ajapted | 2012-11-07 19:12:17 +1100 (Wed, 07 Nov 2012) | 2 lines Began work on a decent scroll widget (Fl_Scroll is fucked). ------------------------------------------------------------------------ r70 | ajapted | 2012-11-07 15:35:01 +1100 (Wed, 07 Nov 2012) | 3 lines Browser: tweak to size and layout, e.g. moved 'X' button to left side and added invisible resize box to the right. ------------------------------------------------------------------------ r69 | ajapted | 2012-11-07 14:50:30 +1100 (Wed, 07 Nov 2012) | 3 lines Fixed UI_Tile event propagation, the FL_NO_BOX 'limiter' was stealing events from the canvas widget. ------------------------------------------------------------------------ r68 | ajapted | 2012-11-07 14:03:40 +1100 (Wed, 07 Nov 2012) | 2 lines CHANGELOG: added browser resize feature. ------------------------------------------------------------------------ r67 | ajapted | 2012-11-07 14:03:23 +1100 (Wed, 07 Nov 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r66 | ajapted | 2012-11-07 14:00:09 +1100 (Wed, 07 Nov 2012) | 4 lines Implemented the resize behavior of UI_Tile, which tries to maintain the width of the right widget (the browser), and remembers that width when it is hidden so it can be restored. ------------------------------------------------------------------------ r65 | ajapted | 2012-11-07 13:36:41 +1100 (Wed, 07 Nov 2012) | 3 lines Implemented new method to show/hide the browser (methods of UI_Tile). Did a bit of work on resize() behavior and handling the limiter box. ------------------------------------------------------------------------ r64 | ajapted | 2012-11-07 13:15:51 +1100 (Wed, 07 Nov 2012) | 2 lines Use the new UI_Tile widget (constructing the main window). ------------------------------------------------------------------------ r63 | ajapted | 2012-11-07 13:08:37 +1100 (Wed, 07 Nov 2012) | 3 lines Began work on UI_Tile widget, a variant on Fl_Tile which will provide better resize behavior and handle the ability to show/hide the browser. ------------------------------------------------------------------------ r62 | ajapted | 2012-11-07 11:10:45 +1100 (Wed, 07 Nov 2012) | 2 lines Added a basic logo image. ------------------------------------------------------------------------ r61 | ajapted | 2012-11-07 11:09:50 +1100 (Wed, 07 Nov 2012) | 2 lines Added a basic icon: eureka.xpm ------------------------------------------------------------------------ r60 | ajapted | 2012-11-01 18:46:49 +1100 (Thu, 01 Nov 2012) | 2 lines Created a basic .desktop file. ------------------------------------------------------------------------ r59 | ajapted | 2012-11-01 18:41:01 +1100 (Thu, 01 Nov 2012) | 2 lines Added top-level 'misc' folder. ------------------------------------------------------------------------ r58 | ajapted | 2012-11-01 12:45:39 +1100 (Thu, 01 Nov 2012) | 2 lines Ignore blank/comment lines in persistent data files. ------------------------------------------------------------------------ r57 | ajapted | 2012-11-01 12:43:41 +1100 (Thu, 01 Nov 2012) | 2 lines Create the cache folder (in home_dir). ------------------------------------------------------------------------ r56 | ajapted | 2012-11-01 12:42:39 +1100 (Thu, 01 Nov 2012) | 2 lines Use proper path for cache data (i.e. home_dir). ------------------------------------------------------------------------ r55 | ajapted | 2012-10-25 15:04:11 +1100 (Thu, 25 Oct 2012) | 2 lines TODO update / tidy up. ------------------------------------------------------------------------ r54 | ajapted | 2012-10-25 15:03:21 +1100 (Thu, 25 Oct 2012) | 4 lines Config: improved output of dump_command_line_options(), use new 'arg_desc' field of option structure to provide a short description of the argument which the option takes. Reordered the list, and removed 'is_file' thang. ------------------------------------------------------------------------ r53 | ajapted | 2012-10-25 12:11:49 +1100 (Thu, 25 Oct 2012) | 4 lines Game defs: look in the "common" folder when an UGH file is not found in the specified folder (like "games"). This is mainly for include directives, and needed for the recent move of shared files to the common folder. ------------------------------------------------------------------------ r52 | ajapted | 2012-10-25 10:47:57 +1100 (Thu, 25 Oct 2012) | 2 lines Makefiles: install the new 'common' folder. ------------------------------------------------------------------------ r51 | ajapted | 2012-10-25 10:47:22 +1100 (Thu, 25 Oct 2012) | 2 lines Moved 'doom_specials.ugh' and 'doom_common.ugh' --> common/ folder. ------------------------------------------------------------------------ r50 | ajapted | 2012-10-25 10:44:04 +1100 (Thu, 25 Oct 2012) | 2 lines Added 'common' folder -- for definitions shared between game defs. ------------------------------------------------------------------------ r49 | ajapted | 2012-10-24 23:37:44 +1100 (Wed, 24 Oct 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r48 | ajapted | 2012-10-24 20:08:49 +1100 (Wed, 24 Oct 2012) | 3 lines Improved dump_command_line_options(), entries need 'h' flag to be displayed, and the '<' flag prints a line break. ------------------------------------------------------------------------ r47 | ajapted | 2012-10-24 19:46:43 +1100 (Wed, 24 Oct 2012) | 2 lines Implemented the --help and --version options. ------------------------------------------------------------------------ r46 | ajapted | 2012-10-24 18:08:40 +1100 (Wed, 24 Oct 2012) | 2 lines tweak to error dialog. ------------------------------------------------------------------------ r45 | ajapted | 2012-10-24 18:06:28 +1100 (Wed, 24 Oct 2012) | 2 lines Config: better handling of lines with extraneous arguments. ------------------------------------------------------------------------ r44 | ajapted | 2012-10-24 17:22:27 +1100 (Wed, 24 Oct 2012) | 6 lines Config handling: 1. simplified OPT_BOOLEAN handling in config files 2. added "WARNING" prefix to some log messages 3. replaced '\0' with 0 4. renamed OPT_STRINGPTRLIST --> OPT_STRING_LIST (etc). ------------------------------------------------------------------------ r43 | ajapted | 2012-10-24 17:05:37 +1100 (Wed, 24 Oct 2012) | 4 lines Config handling: 1. use FatalError() instead of LogPrintf() for some stuff 2. removed OPT_STRINGPTRACC and OPT_UNSIGNED -- simplify the code. ------------------------------------------------------------------------ r42 | ajapted | 2012-10-24 16:42:03 +1100 (Wed, 24 Oct 2012) | 2 lines Error handling polishing. ------------------------------------------------------------------------ r41 | ajapted | 2012-10-24 15:03:14 +1100 (Wed, 24 Oct 2012) | 3 lines Added code files 'ui_dialog' which implements DLG_ShowError(). Source was OBLIGE code. ------------------------------------------------------------------------ r40 | ajapted | 2012-10-24 14:56:22 +1100 (Wed, 24 Oct 2012) | 2 lines FatalError: print message to log file and call DLG_ShowError(). ------------------------------------------------------------------------ r39 | ajapted | 2012-10-24 14:49:11 +1100 (Wed, 24 Oct 2012) | 2 lines Wad: imlemented MasterDir_CloseAll() function. ------------------------------------------------------------------------ r38 | ajapted | 2012-10-23 22:09:18 +1100 (Tue, 23 Oct 2012) | 2 lines Worked on improving the FatalError() logic.... ------------------------------------------------------------------------ r37 | ajapted | 2012-10-23 21:33:42 +1100 (Tue, 23 Oct 2012) | 2 lines Added 'CHANGES.txt' document -- keep track of recent changes. ------------------------------------------------------------------------ r36 | ajapted | 2012-10-23 20:50:09 +1100 (Tue, 23 Oct 2012) | 2 lines Removed last vestiges of err() function. ------------------------------------------------------------------------ r35 | ajapted | 2012-10-23 19:31:30 +1100 (Tue, 23 Oct 2012) | 5 lines Config: 1. replace err() with LogPrintf() 2. show strerror(errno) in some messages 3. fixed warnings about && inside || ------------------------------------------------------------------------ r34 | ajapted | 2012-10-22 22:31:16 +1100 (Mon, 22 Oct 2012) | 2 lines Made 'BugError' just be an alias for FatalError(). ------------------------------------------------------------------------ r33 | ajapted | 2012-10-22 22:24:52 +1100 (Mon, 22 Oct 2012) | 2 lines Replaced 'warn' function with LogPrintf. ------------------------------------------------------------------------ r32 | ajapted | 2012-10-22 22:11:12 +1100 (Mon, 22 Oct 2012) | 3 lines Config: fixed crashing bug with handling loose files (argv and argc were not iterated properly). The same bug also exists in Yadex 1.7.0. ------------------------------------------------------------------------ r31 | ajapted | 2012-10-22 20:47:18 +1100 (Mon, 22 Oct 2012) | 2 lines Config: tweaked handling of loose files, and code reformatting. ------------------------------------------------------------------------ r30 | ajapted | 2012-10-22 20:44:08 +1100 (Mon, 22 Oct 2012) | 3 lines Config: removed hack of first entry in options[] being used for loose filenames. Instead handle them explicitly. ------------------------------------------------------------------------ r29 | ajapted | 2012-10-22 20:26:52 +1100 (Mon, 22 Oct 2012) | 2 lines Makefiles: prevent an install error (since there are currently no mods). ------------------------------------------------------------------------ r28 | ajapted | 2012-10-22 20:25:40 +1100 (Mon, 22 Oct 2012) | 3 lines About box: tweaked Yadex reference -- I don't want to give the impression that Eureka is a continuation of Yadex or is compatible with Yadex. ------------------------------------------------------------------------ r27 | ajapted | 2012-10-22 19:46:27 +1100 (Mon, 22 Oct 2012) | 3 lines Docs: added History_1.txt and History_2.txt -- contains the commit history from the EDGE repository and AwwPorts repository (respectively). ------------------------------------------------------------------------ r26 | ajapted | 2012-10-22 17:19:19 +1100 (Mon, 22 Oct 2012) | 2 lines Makefiles: install the 'mods' folder too (like 'games' and 'ports'). ------------------------------------------------------------------------ r25 | ajapted | 2012-10-22 17:15:34 +1100 (Mon, 22 Oct 2012) | 2 lines Use DebugPrintf() in most places instead of fprintf(stderr). ------------------------------------------------------------------------ r24 | ajapted | 2012-10-22 17:04:23 +1100 (Mon, 22 Oct 2012) | 2 lines Config: fixed --log option (had wrong type, BOOLEAN). ------------------------------------------------------------------------ r23 | ajapted | 2012-10-22 15:47:00 +1100 (Mon, 22 Oct 2012) | 3 lines Version bumped to 0.80, in honor of creating a real sourceforge project and installation of the pmwiki web-site (etc). ------------------------------------------------------------------------ r22 | ajapted | 2012-10-22 15:44:45 +1100 (Mon, 22 Oct 2012) | 3 lines Log file: when output is the terminal, don't print the '=== START OF LOGS ===' message and similar end message. ------------------------------------------------------------------------ r21 | ajapted | 2012-10-22 15:39:15 +1100 (Mon, 22 Oct 2012) | 3 lines Config files: re-implemented the parse_config_file_user() and parse_config_file_default() functions. ------------------------------------------------------------------------ r20 | ajapted | 2012-10-22 15:22:57 +1100 (Mon, 22 Oct 2012) | 2 lines tweakage and movage. ------------------------------------------------------------------------ r19 | ajapted | 2012-10-22 14:22:15 +1100 (Mon, 22 Oct 2012) | 8 lines Rework of log file handling: 1. the --log option specifies a log file, use stdout as fallback 2. the --quiet option suppresses the stdout fallback 3. be sure to LogClose() in error handlers 4. added --debug option to enable debug messages 5. debug messages either go to log file (if used), else stderr 6. added 'init_progress' global var ------------------------------------------------------------------------ r18 | ajapted | 2012-10-22 13:28:25 +1100 (Mon, 22 Oct 2012) | 2 lines Options: better handling of --version (same way as --help). ------------------------------------------------------------------------ r17 | ajapted | 2012-10-22 13:21:45 +1100 (Mon, 22 Oct 2012) | 2 lines Removed unused 'Quieter' option / var. ------------------------------------------------------------------------ r16 | ajapted | 2012-10-21 22:35:58 +1100 (Sun, 21 Oct 2012) | 8 lines Option parsing: 1. revert previous commit, the 'long_name' can now be used with either single or double dashes (e.g. --iwad or just -iwad). I remembered that the options were meant to mimic what DOOM.EXE accepts. 2. handle --version a bit better 3. provide short options for common options: -f (-file), -w (-warp), etc.. 4. reordered entries in options[] table, more common ones near the top. ------------------------------------------------------------------------ r15 | ajapted | 2012-10-21 22:14:51 +1100 (Sun, 21 Oct 2012) | 3 lines Option parsing: require short options be a single letter, and long options begin with double dashes, e.g. --iwad. ------------------------------------------------------------------------ r14 | ajapted | 2012-10-21 21:58:22 +1100 (Sun, 21 Oct 2012) | 4 lines 1. Determine home_dir/install_dir BEFORE parsing config files or normal options 2. Support --home and --install options (override the automatic logic) 3. Renamed --config_file to just --config ------------------------------------------------------------------------ r13 | ajapted | 2012-10-21 21:21:47 +1100 (Sun, 21 Oct 2012) | 4 lines Look for ".ugh" definition files in two places: (1) home_dir and (2) install_dir. (In that order too). This is part of the transition to using proper unixy file location conventions. ------------------------------------------------------------------------ r12 | ajapted | 2012-10-21 21:16:40 +1100 (Sun, 21 Oct 2012) | 2 lines Added 'mods' folder (empty). ------------------------------------------------------------------------ r11 | ajapted | 2012-10-20 22:26:52 +1100 (Sat, 20 Oct 2012) | 2 lines Show the home_dir and install_dir (on stderr), and reformatted that code. ------------------------------------------------------------------------ r10 | ajapted | 2012-10-20 22:17:41 +1100 (Sat, 20 Oct 2012) | 3 lines Added new code files 'lib_file.*' -- contain various file utilities. Source was OBLIGE code, reformatted and tweaked. ------------------------------------------------------------------------ r9 | ajapted | 2012-10-20 22:07:20 +1100 (Sat, 20 Oct 2012) | 3 lines Added the following string utilities (from OBLIGE code) : StringNew(), StringDup(), StringPrintf(), StringFree(). ------------------------------------------------------------------------ r8 | ajapted | 2012-10-20 22:00:56 +1100 (Sat, 20 Oct 2012) | 2 lines Renamed code files: yutil.* --> lib_util.* ------------------------------------------------------------------------ r7 | ajapted | 2012-10-20 21:48:47 +1100 (Sat, 20 Oct 2012) | 3 lines Added 'home_dir' and 'install_dir' global vars, and code to determine what their values should be. ------------------------------------------------------------------------ r6 | ajapted | 2012-10-20 18:50:12 +1100 (Sat, 20 Oct 2012) | 2 lines Makefile: removed FLTK_PREFIX stuff. ------------------------------------------------------------------------ r5 | ajapted | 2012-10-20 17:46:15 +1100 (Sat, 20 Oct 2012) | 2 lines Disabled reading the eureka.cfg file (that mechanism is under review). ------------------------------------------------------------------------ r4 | ajapted | 2012-10-20 17:12:29 +1100 (Sat, 20 Oct 2012) | 2 lines Created 'Makefile.opt' for FLTK installed the /opt folder. ------------------------------------------------------------------------ r3 | ajapted | 2012-10-20 15:40:19 +1100 (Sat, 20 Oct 2012) | 2 lines Initial check-in of existing Eureka code (from the AwwPorts repository). ------------------------------------------------------------------------ r2 | ajapted | 2012-10-20 15:36:36 +1100 (Sat, 20 Oct 2012) | 2 lines Test check-in: README.txt ------------------------------------------------------------------------ r1 | allura | 2012-10-18 22:39:16 +1100 (Thu, 18 Oct 2012) | 1 line Initial commit. ==================================================== DEVELOPMENT IN AWWPORTS REPOSITORY ==================================================== ------------------------------------------------------------------------ r3135 | ajapted | 2012-10-17 Makefile.unix: implemented 'install' and 'uninstall' targets. ------------------------------------------------------------------------ r3134 | ajapted | 2012-10-17 TODO update. ------------------------------------------------------------------------ r3133 | ajapted | 2012-10-17 Eureka: created a Makefile.unix -- will be used to build and install a normal unixy binary. Main difference so far is that it links against a system-wide version of FLTK. ------------------------------------------------------------------------ r3132 | ajapted | 2012-10-16 Eureka: handle a pwad filename given without -file. For example: ./eureka foo.wad ------------------------------------------------------------------------ r3131 | ajapted | 2012-10-16 tweak ------------------------------------------------------------------------ r2744 | ajapted | 2012-07-16 Eureka: TODO item. ------------------------------------------------------------------------ r1468 | ajapted | 2012-05-15 try to unfuck this BZR repository..... ------------------------------------------------------------------------ r1467 | ajapted | 2012-05-15 Eureka / EDGE: various fixes and improvement to new linetypes. ------------------------------------------------------------------------ r1466 | ajapted | 2012-05-15 Eureka / EDGE: fixed remaining linetypes, e.g. rts scripting, sliding doors, aligners, etc.. ------------------------------------------------------------------------ r1465 | ajapted | 2012-05-15 Eureka / EDGE: worked on linetypes, e.g. new keyed doors, hub exits, etc.. ------------------------------------------------------------------------ r1462 | ajapted | 2012-05-14 Eureka / EDGE: added all the sector types. ------------------------------------------------------------------------ r1461 | ajapted | 2012-05-14 Eureka / EDGE: added remaining missing things: dog, glows, stealth monsters. ------------------------------------------------------------------------ r1460 | ajapted | 2012-05-14 Eureka / EDGE: fixed category for slopes, and added some missing things (Jetpack, green keys, new armors). ------------------------------------------------------------------------ r1459 | ajapted | 2012-05-14 Eureka / Odamex: added Blue/Red player starts and Static_Init things (333 to 335). ------------------------------------------------------------------------ r1458 | ajapted | 2012-05-14 Eureka: more work to ODAMEX definitions (sector types, etc etc...) ------------------------------------------------------------------------ r1457 | ajapted | 2012-05-14 Eureka: added slope linetypes to EDGE definition. ------------------------------------------------------------------------ r1456 | ajapted | 2012-05-14 Eureka: partial work on ODAMEX support : ports/odamex.ugh ------------------------------------------------------------------------ r1455 | ajapted | 2012-05-14 Eureka: added bare-bone game definitions for Absolution (Doom64 TC), Blasphemer and HacX. ------------------------------------------------------------------------ r1453 | ajapted | 2012-04-24 Eureka / DOOM defs: fixed linetypes 33 and 34 (red and yellow locked doors) which had swapped descriptions. ------------------------------------------------------------------------ r1452 | ajapted | 2012-04-18 Eureka: fixed W_FindPatchLump() fallback method to try _any_ lump with the matching name (instead of just sprites). This fixes the missing textures with the Doom64 TC. ------------------------------------------------------------------------ r1451 | ajapted | 2012-04-18 Eureka: added a LoadTexture_SinglePatch() function to texture loading code which turned out not to be necessary -- but kept for possible future use. ------------------------------------------------------------------------ r1450 | ajapted | 2012-03-23 Eureka / DOOM: somehow the 'Computer map' pickup disappeared from the definition files -- added it back in. ------------------------------------------------------------------------ r1425 | ajapted | 2012-02-17 Eureka: moved 0.74 changelog --> docs/ directory. ------------------------------------------------------------------------ r1424 | ajapted | 2012-02-17 makefile tweak. ------------------------------------------------------------------------ r1423 | ajapted | 2012-02-17 Eureka: Changelog tweakage. ------------------------------------------------------------------------ r1422 | ajapted | 2012-02-17 Eureka: add revision numbers to changelogs. ------------------------------------------------------------------------ r1421 | ajapted | 2012-02-17 Eureka: CHANGELOG update. ------------------------------------------------------------------------ r1420 | ajapted | 2012-02-17 Eureka: improved the ABOUT box. ------------------------------------------------------------------------ r1419 | ajapted | 2012-02-17 tweakage. ------------------------------------------------------------------------ r1418 | ajapted | 2012-02-17 Eureka: experimented with an 'alternate_look' setting. ------------------------------------------------------------------------ r1417 | ajapted | 2012-02-17 Eureka: tweaked widget positions on the Info bar. ------------------------------------------------------------------------ r1416 | ajapted | 2012-02-17 Eureka: TODO update. ------------------------------------------------------------------------ r1415 | ajapted | 2012-02-17 Eureka: TODO update. ------------------------------------------------------------------------ r1414 | ajapted | 2012-02-17 Eureka: persistence tweak. ------------------------------------------------------------------------ r1413 | ajapted | 2012-02-17 Eureka: persist the rendering On/Off state. ------------------------------------------------------------------------ r1412 | ajapted | 2012-02-17 Eureka: improved layout of sidedefs in LineDef panel (they were a bit cramped). ------------------------------------------------------------------------ r1411 | ajapted | 2012-02-17 Eureka: fixed LineDef panel not updating after "ADD"/"DEL" buttons. ------------------------------------------------------------------------ r1410 | ajapted | 2012-02-17 Eureka: CHANGELOG update (sidedef "ADD" and "DEL" buttons). ------------------------------------------------------------------------ r1409 | ajapted | 2012-02-17 Eureka: e_cutpaste::UnlinkSideFromLine() --> x_loop::LD_RemoveSideDef(). The sidedef "DEL" button uses this to handle sidedef deletion better. ------------------------------------------------------------------------ r1408 | ajapted | 2012-02-17 Eureka: improved "ADD" sidedef button, try GetOppositeSector() to get the new sector for the sidedef, and if that fails then use NumSec - 1. ------------------------------------------------------------------------ r1407 | ajapted | 2012-02-17 Eureka: changelog (etc) update. ------------------------------------------------------------------------ r1406 | ajapted | 2012-02-17 Eureka: implemented the -port option. ------------------------------------------------------------------------ r1405 | ajapted | 2012-02-17 Eureka: version bump to 0.74 ------------------------------------------------------------------------ r1404 | ajapted | 2012-02-17 Eureka: TODO update. ------------------------------------------------------------------------ r1403 | ajapted | 2012-02-17 Eureka: basic implementation of "ADD" button for sidedefs. ------------------------------------------------------------------------ r1402 | ajapted | 2012-02-17 Eureka: implemented the "DEL" button for sidedefs. ------------------------------------------------------------------------ r1401 | ajapted | 2012-02-16 Eureka: in LINEDEF panel, added "ADD" and "DEL" buttons to sidedefs (with only one visible at a time). Currently they do nothing. ------------------------------------------------------------------------ r1400 | ajapted | 2012-02-16 Eureka / Browser: parsing code for persistence (cat, search, etc). ------------------------------------------------------------------------ r1399 | ajapted | 2012-02-16 Eureka: persist which Browser panel is open (if any). ------------------------------------------------------------------------ r1398 | ajapted | 2012-02-16 tweak. ------------------------------------------------------------------------ r1397 | ajapted | 2012-02-16 Eureka: docco update (sector insertion improvements). ------------------------------------------------------------------------ r1396 | ajapted | 2012-02-16 Eureka: improved SECTOR insertion : (a) copy properties from a selected sector, or if none then a neighbor sector. (b) if CTRL is pressed, then the new area BECOMES the same sector as the one selected. ------------------------------------------------------------------------ r1395 | ajapted | 2012-02-16 minor comment. ------------------------------------------------------------------------ r1394 | ajapted | 2012-02-16 Eureka: fixed UI_Pic handling of a certain flat (CEIL4_1 IIRC) which was showing bright cyan in parts that were black (palette color #247). ------------------------------------------------------------------------ r1393 | ajapted | 2012-02-16 docco update. ------------------------------------------------------------------------ r1392 | ajapted | 2012-02-16 Eureka: big rework on CloseLoop_Complex() to fix some failure cases, especially when extending an island within a sector. Also fixed a failure case in CloseLoop_Simple() when surrounding an existing shape WHILE new shape is inside a sector -- we need to assign a sector to both loops for that. ------------------------------------------------------------------------ r1391 | ajapted | 2012-02-15 Eureka: fixed bug where closing a line-loop around an existing shape did not apply the new sector to the outside of that shape. ------------------------------------------------------------------------ r1390 | ajapted | 2012-02-15 Eureka: code tidying, and removed 'e' pointer from UI_Canvas class. ------------------------------------------------------------------------ r1389 | ajapted | 2012-02-15 Eureka / TODO: update. ------------------------------------------------------------------------ r1388 | ajapted | 2012-02-15 Eureka / CHANGELOG: update. ------------------------------------------------------------------------ r1387 | ajapted | 2012-02-15 Eureka: tweakage (e.g. persistent messages). ------------------------------------------------------------------------ r1386 | ajapted | 2012-02-15 Eureka / DOOM config: rearranged linegroups. ------------------------------------------------------------------------ r1385 | ajapted | 2012-02-15 Eureka / Browser: skip the trigger (W1, SR, etc).when sorting line specials alphabetically. ------------------------------------------------------------------------ r1384 | ajapted | 2012-02-15 Eureka / Browser: implemented different SORT methods, and a callback so that changing the Sort setting will update the list. ------------------------------------------------------------------------ r1383 | ajapted | 2012-02-15 Eureka / Browser: fixed display of '&' in linetype descriptions. Added padding to numbers for Thing/Line/Sector types. ------------------------------------------------------------------------ r1382 | ajapted | 2012-02-15 Eureka / Browser: added code to SORT the items (currently the only method is alphabetically). ------------------------------------------------------------------------ r1381 | ajapted | 2012-02-15 Eureka / Browser: updated WriteUser() to write the search string and values for the Sort and Pics widgets. ------------------------------------------------------------------------ r1380 | ajapted | 2012-02-15 Eureka / Browser: added a 'Sort' choice and 'Pics' toggle button to certain browser panels. They currently do NOTHING. ------------------------------------------------------------------------ r1379 | ajapted | 2012-02-15 Eureka: worked on persisting the state of the Browser panels. ------------------------------------------------------------------------ r1378 | ajapted | 2012-02-14 Eureka: fixed bug persisting the 3D preview (view.Sin and view.Cos were not being updated properly). ------------------------------------------------------------------------ r1377 | ajapted | 2012-02-14 Eureka: updated CHANGELOG. ------------------------------------------------------------------------ r1376 | ajapted | 2012-02-14 Eureka: persist the current edit mode. ------------------------------------------------------------------------ r1375 | ajapted | 2012-02-14 Eureka: persist more Render3D state: gamma, texturing, lighting, etc... ------------------------------------------------------------------------ r1374 | ajapted | 2012-02-13 Eureka: properly handle no persistent user state for a map, via new M_DefaultUserState() function which zooms out to show whole map, sets the camera to the player thing, etc.... ------------------------------------------------------------------------ r1373 | ajapted | 2012-02-13 tweak. ------------------------------------------------------------------------ r1372 | ajapted | 2012-02-13 Eureka: make sure the -file pwad exists. ------------------------------------------------------------------------ r1371 | ajapted | 2012-02-13 Eureka: fixed Grid_ParseUser() to update the UI widgets (info bar, etc). ------------------------------------------------------------------------ r1370 | ajapted | 2012-02-12 Eureka: tweaked filename for user state persistence. ------------------------------------------------------------------------ r1369 | ajapted | 2012-02-12 Eureka: separated out some code to Editor_Init() function, and call it earlier than Editor_Loop() so that the user state from LoadLevel() can work properly. ------------------------------------------------------------------------ r1368 | ajapted | 2012-02-12 Eureka: implemented M_LoadUserState(). ------------------------------------------------------------------------ r1367 | ajapted | 2012-02-12 Eureka: implemented a M_ParseLine() function as the general way to break a line into tokens. The strings must be freed with M_FreeLine(). ------------------------------------------------------------------------ r1366 | ajapted | 2012-02-12 Eureka: more work on persisting "user state" when saving and loading maps The parsing and writing logic for the GRID and RENDER systems is now in place, but not yet complete. ------------------------------------------------------------------------ r1365 | ajapted | 2012-02-12 Eureka: more work on persisting "user state" when saving and loading maps The parsing and writing logic for the GRID and RENDER systems is now in place, but not yet complete. ------------------------------------------------------------------------ r1364 | ajapted | 2012-02-12 Eureka: for File/Export function, ask for the map slot _AFTER_ asking for the destination filename. ------------------------------------------------------------------------ r1363 | ajapted | 2012-02-12 Eureka: began work on mechanism to persist user state for a map, stuff like the camera position and angle, grid position and scale and step, browser categories, etc etc..... ------------------------------------------------------------------------ r1362 | ajapted | 2012-02-12 Eureka: added 'cache' directory. ------------------------------------------------------------------------ r1361 | ajapted | 2012-02-12 Eureka: code to compute the adler CRC when loading and saving a map. This required changing the lump processing order in LoadLevel() so that it matches SaveLevel() -- however it cannot do certain checks as it did before (e.g. check for invalid sector numbers in sidedefs), these must be done in a separate pass which hasn't been implemented yet. ------------------------------------------------------------------------ r1360 | ajapted | 2012-02-12 Eureka / Adler-32: tweaks. ------------------------------------------------------------------------ r1359 | ajapted | 2012-02-12 Eureka / Adler-32: added an 'extra' field which is the 32-bit sum of the 16-bit S2 field, modulo a large prime number (0xFFFEFFF9). This should make collisions a lot less likely, but definitely not as good as a proper CRC-64 implementation. ------------------------------------------------------------------------ r1358 | ajapted | 2012-02-12 Eureka: fixed #includes from renamed file: lib_crc --> lib_adler ------------------------------------------------------------------------ r1357 | ajapted | 2012-02-12 Eureka: renamed code file: lib_crc --> lib_adler ------------------------------------------------------------------------ r1356 | ajapted | 2012-02-09 Eureka: TODO (etc) update. ------------------------------------------------------------------------ r1355 | ajapted | 2012-02-09 Eureka: when dragging/scaling/rotating vertices, draw the linedefs too. Changed dynamic rotate (CTRL + Mouse2) to not scale, just rotate. ------------------------------------------------------------------------ r1354 | ajapted | 2012-02-08 Eureka: renamed typedef: obj_type_t --> obj_type_e ------------------------------------------------------------------------ r1353 | ajapted | 2012-02-08 Eureka / DOOM: renamed some Ammunition things. ------------------------------------------------------------------------ r1352 | ajapted | 2012-02-08 Eureka / DOOM: removed "PU:" prefix from pickup items, moved backpack into the Bonus category, and some minor renaming. ------------------------------------------------------------------------ r1351 | ajapted | 2012-02-08 Eureka: TODO update. ------------------------------------------------------------------------ r1350 | ajapted | 2012-02-08 Eureka: implemented MasterDir_Remove(). This should fix the crash issue (and a quick test did not reproduce the crash). ------------------------------------------------------------------------ r1349 | ajapted | 2012-02-08 Eureka: removed obsolete file: w_structs.h ------------------------------------------------------------------------ r1348 | ajapted | 2012-02-08 Eureka: removed most stuff from w_structs.h (obsolete), and moved the two actually used definitions --> w_rawdef.h ------------------------------------------------------------------------ r1347 | ajapted | 2012-02-08 Eureka: updated all header files to have consistent guards (i.e. the #ifndef XXX #define XXX ... #endif paradigm). ------------------------------------------------------------------------ r1346 | ajapted | 2012-02-08 Eureka: replaced 'img_dim_t' typedef with good old 'int'. ------------------------------------------------------------------------ r1345 | ajapted | 2012-02-07 tweak ------------------------------------------------------------------------ r1344 | ajapted | 2012-02-07 Eureka: ChangeLog / TODO update. ------------------------------------------------------------------------ r1343 | ajapted | 2012-02-07 Eureka: for File/New, no need to ask for a map slot when there's no current PWAD, as the File/Save function will do File/Export which always asks for the map slot. ------------------------------------------------------------------------ r1342 | ajapted | 2012-02-07 Eureka: show the current WAD and map name in the window title bar. ------------------------------------------------------------------------ r1341 | ajapted | 2012-02-07 Eureka: TODO twiddling. ------------------------------------------------------------------------ r1340 | ajapted | 2012-02-07 Eureka: committed current change-log. ------------------------------------------------------------------------ r1339 | ajapted | 2012-02-07 Eureka: the clipboard persists when changing maps, allowing copy-n-paste from one map/wad to another map/wad. ------------------------------------------------------------------------ r1338 | ajapted | 2012-02-07 Eureka: renamed variables: Warp --> Level_name, also Game --> Game_name and Port --> Port_name. ------------------------------------------------------------------------ r1337 | ajapted | 2012-02-07 Eureka: snap_to_grid is now the default. ------------------------------------------------------------------------ r1336 | ajapted | 2012-02-07 tweak. ------------------------------------------------------------------------ r1335 | ajapted | 2012-02-05 Eureka: when highlighting the nearest vertex, handle grid-snap mode so that the bbox we check has the same size as the grid step. This ensures we can close a line loop properly, instead of placing a vertex on top of an existing vertex. Bug reported by Lance MDR Rocket. ------------------------------------------------------------------------ r1334 | ajapted | 2012-02-05 Eureka: when creating a square sector (outside of map), make it occupy a single grid square. ------------------------------------------------------------------------ r1333 | ajapted | 2012-02-02 Eureka: moved some documents into new docs/ folder. ------------------------------------------------------------------------ r1332 | ajapted | 2012-02-02 Eureka: WISHLIST update. ------------------------------------------------------------------------ r1331 | ajapted | 2012-02-02 Eureka: added docs/ folder. ------------------------------------------------------------------------ r1330 | ajapted | 2012-02-01 Eureka: TODO update. ------------------------------------------------------------------------ r1329 | ajapted | 2012-02-01 Eureka: disable debugging messages in LOG file. ------------------------------------------------------------------------ r1328 | ajapted | 2012-02-01 Eureka: fixed year in About box text. ------------------------------------------------------------------------ r1327 | ajapted | 2012-02-01 Eureka: disabled some debugging stderr messages. ------------------------------------------------------------------------ r1326 | ajapted | 2012-02-01 tweak. ------------------------------------------------------------------------ r1325 | ajapted | 2012-02-01 Eureka: added changelog for v0.72 ------------------------------------------------------------------------ r1324 | ajapted | 2012-02-01 tweak ------------------------------------------------------------------------ r1323 | ajapted | 2012-02-01 Eureka: updated NEW_WORKFLOW document, various other doc tweaks. ------------------------------------------------------------------------ r1322 | ajapted | 2012-02-01 tweak ------------------------------------------------------------------------ r1321 | ajapted | 2012-02-01 tweak. ------------------------------------------------------------------------ r1320 | ajapted | 2012-02-01 Eureka: fixed FreshLevel() to apply the default textures (etc). ------------------------------------------------------------------------ r1319 | ajapted | 2012-02-01 Eureka: fixed bug in recent commit (Export code). ------------------------------------------------------------------------ r1318 | ajapted | 2012-02-01 Eureka: silenced a few compiler warnings. ------------------------------------------------------------------------ r1317 | ajapted | 2012-02-01 Eureka: tweaked messages when loading/saving/exporting a map. ------------------------------------------------------------------------ r1316 | ajapted | 2012-02-01 Eureka: disabled some unimplemented Menu commands. ------------------------------------------------------------------------ r1315 | ajapted | 2012-02-01 Eureka / DOOM: changed default ceiling texture to CEIL3_5. ------------------------------------------------------------------------ r1314 | ajapted | 2012-02-01 Eureka: more stuff for WISHLIST.... ------------------------------------------------------------------------ r1313 | ajapted | 2012-01-31 Eureka: added MasterDir_Add() and MasterDir_Remove() functions (note the latter is not implemented yet). ------------------------------------------------------------------------ r1312 | ajapted | 2012-01-31 Eureka: improved logic in File/Open function when the user selects a new WAD file -- in particular we only change 'edit_wad' and update the master directory if the operation is successful. Improved File/Export code with the MasterDir_Add/Remove calls. ------------------------------------------------------------------------ r1311 | ajapted | 2012-01-31 Eureka: tidying up... ------------------------------------------------------------------------ r1310 | ajapted | 2012-01-31 Eureka: small fix. ------------------------------------------------------------------------ r1309 | ajapted | 2012-01-31 Eureka: yet another TODO / WISHLIST update. ------------------------------------------------------------------------ r1308 | ajapted | 2012-01-31 Eureka: improved logic for DetermineIWAD(), handle $DOOMWADDIR and when -iwad merely specifies a directory. ------------------------------------------------------------------------ r1307 | ajapted | 2012-01-31 Eureka / Wad_file: fixed ::Open() with mode 'a' to only create the file when it doesn't exist (errno == ENOENT). Before it would try to create the file on other errors (such as no permission to R/W). ------------------------------------------------------------------------ r1306 | ajapted | 2012-01-31 Eureka: changed -file option to only accept a single PWAD. Later on there will be a -merge option for adding resource wads. ------------------------------------------------------------------------ r1305 | ajapted | 2012-01-31 Eureka: ensure new lumps have uppercase names. ------------------------------------------------------------------------ r1304 | ajapted | 2012-01-31 Eureka: TODO and WISHLIST update. ------------------------------------------------------------------------ r1303 | ajapted | 2012-01-31 Eureka: updated README for upcoming test package. ------------------------------------------------------------------------ r1302 | ajapted | 2012-01-31 Eureka: tweaked FEATURES.txt ------------------------------------------------------------------------ r1301 | ajapted | 2012-01-31 Eureka: when creating new sectors, give them proper default values, especially the default floor and ceiling textures. Similarly for new sidedefs. ------------------------------------------------------------------------ r1300 | ajapted | 2012-01-31 Eureka: TODO / WISHLIST update. ------------------------------------------------------------------------ r1299 | ajapted | 2012-01-31 Eureka: use the new 'g_default_thing' global when inserting things, and removed the other one. ------------------------------------------------------------------------ r1298 | ajapted | 2012-01-30 Eureka: added 'default_thing' value to DOOM and HERETIC game defs. ------------------------------------------------------------------------ r1297 | ajapted | 2012-01-30 Eureka: code to parse a 'default_thing' line in game definitions. ------------------------------------------------------------------------ r1296 | ajapted | 2012-01-30 Eureka: added 'default_textures' line to DOOM and HERETIC game defs. ------------------------------------------------------------------------ r1295 | ajapted | 2012-01-30 Eureka: code to parse 'default_textures' line in game definitions. ------------------------------------------------------------------------ r1294 | ajapted | 2012-01-30 Eureka: support for a 'sky_color' field in game definition files. ------------------------------------------------------------------------ r1293 | ajapted | 2012-01-30 Eureka: removed a couple of unused globals. ------------------------------------------------------------------------ r1292 | ajapted | 2012-01-30 tweak ------------------------------------------------------------------------ r1291 | ajapted | 2012-01-30 Eureka: more tidying of obsolete config options... ------------------------------------------------------------------------ r1290 | ajapted | 2012-01-30 Eureka: removed most of the obsolete config settings. ------------------------------------------------------------------------ r1289 | ajapted | 2012-01-30 Eureka: dead code removal. ------------------------------------------------------------------------ r1288 | ajapted | 2012-01-30 Eureka: dead code removal. ------------------------------------------------------------------------ r1287 | ajapted | 2012-01-30 Eureka: removed 'Expert' global variable. ------------------------------------------------------------------------ r1286 | ajapted | 2012-01-30 Eureka / Port defs: consistently have 'BOOM:' or 'EDGE:' in the names of the Boom and Edge specific linetypes, things, etc... ------------------------------------------------------------------------ r1285 | ajapted | 2012-01-30 Eureka: added a DeterminePort() function. ------------------------------------------------------------------------ r1284 | ajapted | 2012-01-30 Eureka: added 'ports/vanilla.ugh' definition, which is empty except for comments (and doesn't need anything). ------------------------------------------------------------------------ r1283 | ajapted | 2012-01-29 Eureka: TODO update. ------------------------------------------------------------------------ r1282 | ajapted | 2012-01-29 Eureka: properly flip linedefs when inserting a sector and the line(s) would have ended up with no right side (only a left side). ------------------------------------------------------------------------ r1281 | ajapted | 2012-01-29 Eureka: when auto-splitting a sector, ensure neither line loop faces outward. ------------------------------------------------------------------------ r1280 | ajapted | 2012-01-29 Eureka: noted a bug with rendering mid-masked textures. ------------------------------------------------------------------------ r1279 | ajapted | 2012-01-29 tweak ------------------------------------------------------------------------ r1278 | ajapted | 2012-01-29 Eureka.cfg : removed the obsolete iwad stuff. ------------------------------------------------------------------------ r1277 | ajapted | 2012-01-29 Eureka: have a single -iwad parameter (instead of -iwad1, -iwad2 etc....) ------------------------------------------------------------------------ r1276 | ajapted | 2012-01-29 tweakage. ------------------------------------------------------------------------ r1275 | ajapted | 2012-01-29 Eureka: WISHLIST update. ------------------------------------------------------------------------ r1274 | ajapted | 2012-01-29 Eureka: determine the 'Game' value from the IWAD filename. ------------------------------------------------------------------------ r1273 | ajapted | 2012-01-29 Eureka: for File/Export function, add ".wad" if filename has no extension. ------------------------------------------------------------------------ r1272 | ajapted | 2012-01-29 Eureka: code tweak (use FileExists utility function). ------------------------------------------------------------------------ r1271 | ajapted | 2012-01-29 Eureka / yutils: removed a few unused functions (fncmp, spec_path) and renamed a few functions (e.g. TimeGetMillies). ------------------------------------------------------------------------ r1270 | ajapted | 2012-01-28 Eureka: TODO update. ------------------------------------------------------------------------ r1269 | ajapted | 2012-01-28 Eureka / Wad_file: added PathName() and IsReadOnly() methods. ------------------------------------------------------------------------ r1268 | ajapted | 2012-01-28 Eureka: made the Wad_file::Open() method mimic the fopen() semantics, it now has a 'mode' parameter which can be 'r', 'w' or 'a'. Hence removed the ::Create() method from the public API. ------------------------------------------------------------------------ r1267 | ajapted | 2012-01-28 Eureka: some work to set 'Game' value differently, it will be based on the IWAD filename instead of being in the CFG file. ------------------------------------------------------------------------ r1266 | ajapted | 2012-01-28 Eureka: for File/Open function, implemented choosing a WAD file to load and improved the wording on the question. ------------------------------------------------------------------------ r1265 | ajapted | 2012-01-28 Eureka: for File/Open command, clear the MadeChanges flag and pan/zoom the canvas to show the whole level. ------------------------------------------------------------------------ r1264 | ajapted | 2012-01-28 Eureka: partial work on File/Open (CTRL-O) functionality. It really needs is a new widget, HOWEVER for now I will make do with fl_input and Confirm/Notify dialogs. ------------------------------------------------------------------------ r1263 | ajapted | 2012-01-28 dead code removal. ------------------------------------------------------------------------ r1262 | ajapted | 2012-01-27 tweakage. ------------------------------------------------------------------------ r1261 | ajapted | 2012-01-27 Eureka: for EXPORT function, if selected wad already exists then we just save the map into that wad, but if the MAP already exists in that wad then get confirmation from the user to overwrite it. ------------------------------------------------------------------------ r1260 | ajapted | 2012-01-27 Eureka: more Wishes.... sigh... ------------------------------------------------------------------------ r1259 | ajapted | 2012-01-27 Eureka: for EXPORT function, ask user for map-slot name and use it, and also make the exported WAD the current PWAD (set 'edit_wad' global). ------------------------------------------------------------------------ r1258 | ajapted | 2012-01-27 Eureka: new global 'Replacer' remembers when the user created a new map (via File/New or CTRL-N) __AND__ it would replace an existing level in the current PWAD. When doing File/Save (CTRL-S), check for Replacer and confirm whether the user really wants to replace the existing map. Improved File/New operation to ask for a map name. ------------------------------------------------------------------------ r1257 | ajapted | 2012-01-27 Eureka: bit of work on wad handling, the 'base_wad' and 'edit_wad' global variables have the current IWAD (required) and current PWAD (optional). ------------------------------------------------------------------------ r1256 | ajapted | 2012-01-27 Eureka / Games: renamed 'doom1.ugh' --> 'doom.ugh', to match the IWAD filename (DOOM.WAD) ------------------------------------------------------------------------ r1255 | ajapted | 2012-01-27 Eureka / Games: added game definitions for FINAL DOOM (tnt.ugh and plutonia.ugh). They merely include the DOOM 2 definitions, although eventually they will need stuff for their new textures. ------------------------------------------------------------------------ r1254 | ajapted | 2012-01-27 Eureka: tweaked color of camera arrow. ------------------------------------------------------------------------ r1253 | ajapted | 2012-01-27 Eureka: implemented 'Go To Camera' function (bound to END key). ------------------------------------------------------------------------ r1252 | ajapted | 2012-01-27 Eureka: version bump to 0.72 ------------------------------------------------------------------------ r1251 | ajapted | 2012-01-27 Eureka / README: document middle click functions (scale etc). ------------------------------------------------------------------------ r1250 | ajapted | 2012-01-27 Eureka: TODO update. ------------------------------------------------------------------------ r1249 | ajapted | 2012-01-27 Eureka: show proper location and angle of camera. ------------------------------------------------------------------------ r1248 | ajapted | 2012-01-27 Eureka: size of the camera arrow now depends on current map scale. ------------------------------------------------------------------------ r1247 | ajapted | 2012-01-27 Eureka: partial work on drawing the camera (a pink arrow)... ------------------------------------------------------------------------ r1246 | ajapted | 2012-01-27 Eureka: worked on semantics for wad handling (the File/ menu) and how the current "game" is defined. ------------------------------------------------------------------------ r1245 | ajapted | 2012-01-26 Eureka / Scaling: fixed bug where a rotation remains in-effect after releasing the CTRL key. ------------------------------------------------------------------------ r1244 | ajapted | 2012-01-26 Eureka / Scaling: properly handle modifiers: none = keep_aspect, SHIFT = any aspect, CTRL = rotate. ------------------------------------------------------------------------ r1243 | ajapted | 2012-01-26 Eureka / Scaling: various fixes... ------------------------------------------------------------------------ r1242 | ajapted | 2012-01-26 Eureka: use new scale_param_t stuff in UI_Canvas class. ------------------------------------------------------------------------ r1241 | ajapted | 2012-01-26 Eureka: added a scale_param_t structure with an Apply() method to transform a coordinate value. Updated all CMD_ScaleObjects2() code to use this structure and method (rather than mid_x etc... parameters). ------------------------------------------------------------------------ r1240 | ajapted | 2012-01-26 TODO bits... ------------------------------------------------------------------------ r1239 | ajapted | 2012-01-26 Eureka: TODO update. ------------------------------------------------------------------------ r1238 | ajapted | 2012-01-26 Eureka: moved next/prev/jump code into CMD_NextObject(), CMD_PrevObject() and CMD_JumpToObject() functions in e_path.cc/h file, and updated menu to call them. ------------------------------------------------------------------------ r1237 | ajapted | 2012-01-26 Eureka: dead code removal. ------------------------------------------------------------------------ r1236 | ajapted | 2012-01-26 Eureka: use 'V' key for the mirror vertically function (not 'I'). ------------------------------------------------------------------------ r1235 | ajapted | 2012-01-26 Eureka: Implemented 'Invert Selection' function (CTRL + I). ------------------------------------------------------------------------ r1234 | ajapted | 2012-01-26 Eureka: moved sel_op_e enum from main.h --> m_bitvec.h ------------------------------------------------------------------------ r1233 | ajapted | 2012-01-26 minor fix. ------------------------------------------------------------------------ r1232 | ajapted | 2012-01-26 WISH-LIST: console idea. ------------------------------------------------------------------------ r1231 | ajapted | 2012-01-25 tweaks. ------------------------------------------------------------------------ r1230 | ajapted | 2012-01-25 Eureka: for 'Export Map' function, properly handle CANCEL and ERROR returns from the file chooser (notify user), and actually use the filename selected, and notify user if creating the file failed. ------------------------------------------------------------------------ r1229 | ajapted | 2012-01-25 Eureka: factored out a Main_ConfirmQuit() function, and use it for the 'New Level' function too (so the user does not lose their changes). ------------------------------------------------------------------------ r1228 | ajapted | 2012-01-25 Eureka: TODO update (scaling stuff). ------------------------------------------------------------------------ r1227 | ajapted | 2012-01-25 Eureka / Scaling: experimental code for dynamic Rotation.... ------------------------------------------------------------------------ r1226 | ajapted | 2012-01-25 Eureka / Scaling: fixed the scaling calculations in Scaled_Coord() and UI_Canvas::ScaleUpdate(). ------------------------------------------------------------------------ r1225 | ajapted | 2012-01-25 Eureka / Scaler: factored out some common mirror logic so it can be used for the dynamic scaling code too (when scale_x or y is negative). Implemented the actual scaling in new CMD_ScaleObjects2() function. For some functions in x_mirror, pass 'selection_c' by reference instead of as a pointer. ------------------------------------------------------------------------ r1224 | ajapted | 2012-01-25 Eureka / Scaling: properly compute middle point of objects. ------------------------------------------------------------------------ r1223 | ajapted | 2012-01-25 Eureka: renamed some stuff, e.g. centre_of_objs() --> Objs_CalcMiddle() bbox_of_objects() --> Objs_CalcBBox(), and a few other things. ------------------------------------------------------------------------ r1222 | ajapted | 2012-01-25 Eureka / Scaling: added code to draw scaled LineDefs and Sectors. ------------------------------------------------------------------------ r1221 | ajapted | 2012-01-25 Eureka / Scaling: proper logic to draw the scaled selection, and added support for a 'keep_aspect' mode (hold down SHIFT key). ------------------------------------------------------------------------ r1220 | ajapted | 2012-01-25 Eureka: initial work on ability to Scale objects via middle mouse button, working very similarly to dragging objects... ------------------------------------------------------------------------ r1219 | ajapted | 2012-01-25 Eureka: WISHLIST bits... ------------------------------------------------------------------------ r1218 | ajapted | 2012-01-25 Eureka: improved Quantization algorithm, for vertices we analyse the linedefs and remember the orientations (V_HORIZ, V_VERT etc), and have better QuantSnapX/Y() grid methods. ------------------------------------------------------------------------ r1217 | ajapted | 2012-01-25 Eureka: for Quantization of vertices, added logic to keep horizontal lines horizontal and vertical lines vertical. ------------------------------------------------------------------------ r1216 | ajapted | 2012-01-25 dead code removal. ------------------------------------------------------------------------ r1215 | ajapted | 2012-01-25 Eureka: preliminary code for Quantize_Vertices(). ------------------------------------------------------------------------ r1214 | ajapted | 2012-01-24 Eureka: worked on Quantization function, for now only for Things. The significant aspects are: (1) leave the unsuccessfully moved things selected (and beep) (2) never move a thing directly on top of another one (3) if the nearest corner is unavailable, try the other corners [these rules will apply to vertex quantization too, and then some] ------------------------------------------------------------------------ r1213 | ajapted | 2012-01-22 Eureka: TODO item. ------------------------------------------------------------------------ r1212 | ajapted | 2012-01-22 Eureka: notes for a better (feasible) quantization algorithm. ------------------------------------------------------------------------ r1211 | ajapted | 2012-01-22 Eureka: experimental code for the 'File/New' menu command, and tweaked some other menu bits. ------------------------------------------------------------------------ r1210 | ajapted | 2012-01-22 Eureka / TODO: moved numerous items to the WISH-LIST, keeping the TODO for stuff which I intend to implemented before the next test package. ------------------------------------------------------------------------ r1209 | ajapted | 2012-01-18 tweak. ------------------------------------------------------------------------ r1208 | ajapted | 2012-01-18 Eureka: call the FLTK load_system_icons() function in InitFLTK(). Doesn't seem to have done anything though (no icons in the file chooser). ------------------------------------------------------------------------ r1207 | ajapted | 2012-01-18 Eureka: better logic for menu 'Zoom In/Out' functions via CMD_Zoom() and CMD_ZoomWholeLevel() functions. Tweaked some other menu bits. ------------------------------------------------------------------------ r1206 | ajapted | 2012-01-18 Eureka: test code for using FL_Native_File_Chooser.... ------------------------------------------------------------------------ r1205 | ajapted | 2012-01-18 Eureka: partial work on the "Export Map" function, i.e. saving the level into a brand spanking new wad file. No file selection dialog yet! ------------------------------------------------------------------------ r1204 | ajapted | 2012-01-18 Eureka: removed 'action' field from UI_MainWin class, have a 'want_quit' global variable instead. ------------------------------------------------------------------------ r1203 | ajapted | 2012-01-17 Eureka: fixed (restored?) deleting things in a sector when deleting that very sector. The things are kept (with the linedefs) in the "keep unused" mode, i.e. when the SHIFT key is held down. ------------------------------------------------------------------------ r1202 | ajapted | 2012-01-17 Eureka: various updates to README, TODO, WISHLIST. ------------------------------------------------------------------------ r1201 | ajapted | 2012-01-17 Eureka: fixed bug when saving a map more than once, the wrong lumps could get removed and hence end up with multiple versions of the map in the output wad file. ------------------------------------------------------------------------ r1200 | ajapted | 2012-01-17 minor code reformatting. ------------------------------------------------------------------------ r1199 | ajapted | 2012-01-17 Eureka: began work on texture alignment functions.... ------------------------------------------------------------------------ r1198 | ajapted | 2012-01-17 Eureka / selection_c class: added a 'first_obj' field which remembers the very first object added to the selection. It is -1 for an empty selection or when that object gets cleared. The find_first() method will return that object if valid, and the find_second() method had been updated to handle it properly too. Reduced MAX_STORE_SEL from 32 --> 24, as I think this will speed up certain operations that make heavy use of selection queries. Did some code formatting (like semicolons in for loops). ------------------------------------------------------------------------ r1197 | ajapted | 2012-01-17 Eureka: changed "rotate 90^ clockwise" key to 'R', leaving 'X' free for texture alignment function. ------------------------------------------------------------------------ r1196 | ajapted | 2012-01-17 Eureka: made grid size button a bit wider. ------------------------------------------------------------------------ r1195 | ajapted | 2012-01-16 Eureka: kicked the "Auto" grid choice code to the curb. ------------------------------------------------------------------------ r1194 | ajapted | 2012-01-16 Eureka: mostly finished grid "AUTO" mode, but it sucks since you cannot see what the current grid step is, so it's gonna get the boot. ------------------------------------------------------------------------ r1193 | ajapted | 2012-01-16 Eureka: fixed wrong initial color of Free/Snap button. ------------------------------------------------------------------------ r1192 | ajapted | 2012-01-16 Eureka: partial work on an "AUTO" mode for the grid, where the grid step automatically follows the current scale. It replaces the "locked" flag, and is now a choice in the Grid setting, so removed the "Locked" choice in the Snap widget. ------------------------------------------------------------------------ r1191 | ajapted | 2012-01-16 Eureka: added ToggleSnap() and ToggleAuto() methods to Grid_State_c. ------------------------------------------------------------------------ r1190 | ajapted | 2012-01-16 TODO update. ------------------------------------------------------------------------ r1189 | ajapted | 2012-01-16 Eureka: made the 'h' key toggle through the alternate grid mode too (i.e. normal --> simple --> none). This replaces the 'P' key function. ------------------------------------------------------------------------ r1188 | ajapted | 2012-01-16 Eureka: don't highlight a split_line if one of its vertices is selected. ------------------------------------------------------------------------ r1187 | ajapted | 2012-01-13 Eureka: in "simple" grid mode, make the X and Y axis lines (at X=0 and at Y=0) a brighter blue than the rest. Can help to orientate yourself. ------------------------------------------------------------------------ r1186 | ajapted | 2012-01-12 Eureka: default for grid snapping is now "FREE". ------------------------------------------------------------------------ r1185 | ajapted | 2012-01-11 Eureka: the digits '1' to '9' now set the GRID step, usually 2^n (i.e. 2, 4, 8, etc) but '8' is 192 units and '9' is 256 units. ------------------------------------------------------------------------ r1184 | ajapted | 2012-01-09 Eureka: notes in TODO.txt and tidying up. ------------------------------------------------------------------------ r1183 | ajapted | 2012-01-09 Eureka: TODO update (iwad stuff, grid keys). ------------------------------------------------------------------------ r1182 | ajapted | 2012-01-08 Eureka: implemented auto-sectoring when EXTENDING off an existing structure. ------------------------------------------------------------------------ r1181 | ajapted | 2012-01-08 Eureka: got automatic splitting of sectors working! :-) ------------------------------------------------------------------------ r1180 | ajapted | 2012-01-08 Eureka: TODO update. ------------------------------------------------------------------------ r1179 | ajapted | 2012-01-08 Eureka / basis: replaced LD_WhatSec() function with LineDef::WhatSector(). ------------------------------------------------------------------------ r1178 | ajapted | 2012-01-08 Eureka / basis: changed TouchesSector() method to take a sector number instead of a Sector pointer. ------------------------------------------------------------------------ r1177 | ajapted | 2012-01-08 Eureka: bit more work on ClosedLoop_Complex() logic.... ------------------------------------------------------------------------ r1176 | ajapted | 2012-01-08 Eureka: began work on logic when adding a new linedef to a vertex with two or more existing linedefs (auto-split OR auto-sectoring). Wrote the TwoNeighboringLinedefs() code and tested it. ------------------------------------------------------------------------ r1175 | ajapted | 2012-01-08 Eureka / basis: added LineDef::TouchesVertex() method. ------------------------------------------------------------------------ r1174 | ajapted | 2012-01-08 Eureka / lineloop: fixed a logic error in LookForIsland() code. ------------------------------------------------------------------------ r1173 | ajapted | 2012-01-08 Eureka / lineloop: removed obsolete super_find_sector_model() code. ------------------------------------------------------------------------ r1172 | ajapted | 2012-01-08 Eureka / lineloop: implemented FacesSector() method for islands. ------------------------------------------------------------------------ r1171 | ajapted | 2012-01-08 Eureka: new Insert_LineDef() function factors out the linedef creation bits from the Insert_Vertex() code. Began work on logic to auto-insert and auto-split sectors when adding new linedefs. New ClosedSimpleLoop() function handles the case of closing a simple loop (last vertex ends up with only two linedefs). ------------------------------------------------------------------------ r1170 | ajapted | 2012-01-08 Eureka / lineloop: made AssignSectorToLoop() part of public API. ------------------------------------------------------------------------ r1169 | ajapted | 2012-01-08 Eureka / lineloop: added clear() method, use it at start of TraceLineLoop(). ------------------------------------------------------------------------ r1168 | ajapted | 2012-01-08 Eureka / lineloop: added AllNew() and NeighboringSector() methods. ------------------------------------------------------------------------ r1167 | ajapted | 2012-01-08 Eureka: added 'ignore_new' flag to TraceLineLoop() function, this will cause "new" linedefs (ones without any sidedefs) to be ignored. ------------------------------------------------------------------------ r1166 | ajapted | 2012-01-06 Eureka / lineloop: added SameSector() method. ------------------------------------------------------------------------ r1165 | ajapted | 2012-01-06 Eureka / lineloop: added TotalLength() method. ------------------------------------------------------------------------ r1164 | ajapted | 2012-01-06 Eureka: updated README.txt ------------------------------------------------------------------------ r1163 | ajapted | 2012-01-06 Eureka / lineloop: determine the 'faces_outward' flag by computing the average angle between lines in the loop (done in TraceLineLoop). Fixed get() and get_just_line() methods to check the islands too, which is vital to make FindIslands() work properly. Fixed AssignSectorToSpace() to handle islands too. ------------------------------------------------------------------------ r1162 | ajapted | 2012-01-06 Eureka / lineloop: reworked TraceLineLoop() code for new class. ------------------------------------------------------------------------ r1161 | ajapted | 2012-01-06 Eureka / lineloop: reworked the FindIslands() logic for new class. ------------------------------------------------------------------------ r1160 | ajapted | 2012-01-06 Eureka / lineloop: destructor now frees the islands. Moved code around. ------------------------------------------------------------------------ r1159 | ajapted | 2012-01-06 Eureka / lineloop: rewrote the CalcBounds() method, which was previously a function called BoundsOfLinePath(). ------------------------------------------------------------------------ r1158 | ajapted | 2012-01-06 Eureka: more work on lineloop_c code, e.g. get() and push_back() methods. ------------------------------------------------------------------------ r1157 | ajapted | 2012-01-06 Eureka: added #include "x_loop.h" where needed. ------------------------------------------------------------------------ r1156 | ajapted | 2012-01-06 Eureka: began work on a lineloop_c class for representing a line-loop (an ordered list of linedef/side pairs). ------------------------------------------------------------------------ r1155 | ajapted | 2012-01-06 Eureka / Makefiles: added 'x_loop' code file to the build. ------------------------------------------------------------------------ r1154 | ajapted | 2012-01-06 Eureka: fixed #includes in x_loop.cc (restored needed, removed uneeded). ------------------------------------------------------------------------ r1153 | ajapted | 2012-01-06 Eureka: moved AssignSectorToSpace() function and related code from s_misc.cc/h --> x_loop.cc/h (new files). ------------------------------------------------------------------------ r1152 | ajapted | 2012-01-05 Eureka / TODO: some notes about line-loop modalities.... ------------------------------------------------------------------------ r1151 | ajapted | 2012-01-05 Eureka: fixed bug with dragging a vertex and splitting a line, the dragged vertex was not moving to the new position. ------------------------------------------------------------------------ r1150 | ajapted | 2012-01-05 tweak. ------------------------------------------------------------------------ r1149 | ajapted | 2012-01-05 Eureka: (tentative commit) : for LoadDefinitions() allow a line or thing or texture/flat to have an unknown group -- print a warning to the log file instead of FatalError. This was prompted by the issue where port-specific stuff (e.g. Boom) was referencing groups that don't exist in a game (e.g. Heretic). I will look for a cleaner way to handle that kind of incompatibility. ------------------------------------------------------------------------ r1148 | ajapted | 2012-01-05 Eureka / HERETIC: added missing 'sky_flat' value. ------------------------------------------------------------------------ r1147 | ajapted | 2012-01-05 Eureka: WISHLIST update. ------------------------------------------------------------------------ r1146 | ajapted | 2012-01-05 Eureka / Browser: implemented '!' in search box for negation. ------------------------------------------------------------------------ r1145 | ajapted | 2012-01-05 Eureka: minor TODO stuff. ------------------------------------------------------------------------ r1144 | ajapted | 2012-01-05 Eureka / DOOM: renamed category letters: l --> p (lifts) L --> l (light related) F --> r (raising floors) C --> h (crusher) E --> x (extrafloor) ------------------------------------------------------------------------ r1143 | ajapted | 2012-01-05 Eureka / HERETIC: changed stairs group letter to 'u' ("up"), and added a new group 's' for 'Sounds' (which the ambient sounds were already using). ------------------------------------------------------------------------ r1142 | ajapted | 2012-01-05 Eureka / DOOM: sorted linetypes into groups, removed the 'D' group (use 'd' for normal and fast doors), and have a single group 'k' for keyed doors. Moved linetype 85 (scroll wall right) into Boom defs. ------------------------------------------------------------------------ r1141 | ajapted | 2012-01-05 Eureka / HERETIC: finished adjusting the line types, using different letters than Yadex did (e.g. 'h' for crushers, 'p' for lifts, 'r' for raising floors -- avoiding upper case letters). ------------------------------------------------------------------------ r1140 | ajapted | 2012-01-05 Eureka / HERETIC: worked on linetypes, pasted line info from YADEX's game definition and sorted them into groups. ------------------------------------------------------------------------ r1139 | ajapted | 2012-01-05 Eureka / HERETIC: finished thing sprites and added the correct sizes. (It would've been a lot easier to copy/paste from YADEX, duh!). ------------------------------------------------------------------------ r1138 | ajapted | 2012-01-05 Eureka / HERETIC: a few more sprites.... ------------------------------------------------------------------------ r1137 | ajapted | 2012-01-05 Eureka / HERETIC: worked on sprite names for things, and fixed the id number for the 'Wings of Wrath' (was 23, should be 83). ------------------------------------------------------------------------ r1136 | ajapted | 2012-01-05 Eureka: worked on thing info for HERETIC game definition.... ------------------------------------------------------------------------ r1135 | ajapted | 2012-01-05 Eureka: began work on a HERETIC game definition file.... ------------------------------------------------------------------------ r1134 | ajapted | 2012-01-04 Eureka: fixed grid-toggle key ('h') not updating the infobar widget. ------------------------------------------------------------------------ r1133 | ajapted | 2012-01-04 Eureka: fixed the Grid menu's "OFF" choice. ------------------------------------------------------------------------ r1132 | ajapted | 2012-01-04 Eureka: WISHLIST update. ------------------------------------------------------------------------ r1131 | ajapted | 2012-01-04 Eureka: added new document 'NEW_WORKFLOW.txt', describing some of the significant differences between Eureka and its precedessor Yadex. ------------------------------------------------------------------------ r1130 | ajapted | 2012-01-04 Eureka: TODO update. ------------------------------------------------------------------------ r1129 | ajapted | 2012-01-04 Eureka: updated MergeVertex() to handle a linedef which exists between the two vertices -- the new logic ensures it gets deleted. ------------------------------------------------------------------------ r1128 | ajapted | 2012-01-04 Eureka: TODO update. ------------------------------------------------------------------------ r1127 | ajapted | 2012-01-04 Eureka: never highlight the same vertex as the one we are dragging, preventing an fatal error when trying to merge a vertex onto itself. ------------------------------------------------------------------------ r1126 | ajapted | 2012-01-04 Eureka: implemented merging vertices when dragging a single vertex onto an existing vertex. ------------------------------------------------------------------------ r1125 | ajapted | 2012-01-04 Eureka: fixed the UI_Canvas widget to draw both a a highlight and a dragged selection at the same time. The logic in UpdateHighlight() is what's responsible for keeping it sane. ------------------------------------------------------------------------ r1124 | ajapted | 2012-01-04 tweaks. ------------------------------------------------------------------------ r1123 | ajapted | 2012-01-04 Eureka: improved the UpdateHighlight() code, with a check for dragging and splitting off the panel stuff into a new UpdatePanel() function. ------------------------------------------------------------------------ r1122 | ajapted | 2012-01-04 Eureka: added Editor_State_c field 'drag_single_vertex', normally -1 but contains a vertex number when dragging just a single vertex. ------------------------------------------------------------------------ r1121 | ajapted | 2012-01-04 Eureka: more DOOM definition tweaks.... ------------------------------------------------------------------------ r1120 | ajapted | 2012-01-04 Eureka: moved most DOOM 2 specific textures and flats into doom2.ugh ------------------------------------------------------------------------ r1119 | ajapted | 2012-01-04 tidying up. ------------------------------------------------------------------------ r1118 | ajapted | 2012-01-04 Eureka: moved rest of BOOM stuff from doom_specials.ugh --> boom.ugh ------------------------------------------------------------------------ r1117 | ajapted | 2012-01-04 Eureka: moved all the EDGE-specific stuff and some BOOM-specific stuff out of the DOOM game definitions and into their own port definitions. ------------------------------------------------------------------------ r1116 | ajapted | 2012-01-04 Eureka: moved DOOM 2 specific things from doom_common.ugh --> doom2.ugh, which includes the Super Shotgun, Megasphere, Boss-brain stuff, extra gore decorations, and the DOOM 2 specific monsters like the Archvile, Mancubus etc.... ------------------------------------------------------------------------ r1115 | ajapted | 2012-01-03 Eureka: merged 'doom_tex.ugh' back into 'doom_common.ugh'. All these shenanigans is to allow some DOOM engine games (such as Chex Quest, HacX, and Harmony) to use the common engine stuff but specify their own thing types and flats/textures. ------------------------------------------------------------------------ r1114 | ajapted | 2012-01-03 Eureka: moved some stuff from doom_tex.ugh --> doom1/2.ugh ------------------------------------------------------------------------ r1113 | ajapted | 2012-01-03 Eureka: separated out the line/sector specials from doom_common.ugh into a new file: 'doom_specials.ugh'. ------------------------------------------------------------------------ r1112 | ajapted | 2012-01-03 Eureka: moved the flat/texture definitions out of doom_common.ugh and into a new file 'doom_tex.ugh'. ------------------------------------------------------------------------ r1111 | ajapted | 2012-01-03 Eureka: added 'doom1.ugh' and 'doom2.ugh' game definitions, which so far do little more than simply include the common file. Work still needs to be done to properly separate everything.... ------------------------------------------------------------------------ r1110 | ajapted | 2012-01-03 Eureka: renamed game config file: doom2.ugh --> doom_common.ugh (as the bulk of that file will be stuff in common to both games). ------------------------------------------------------------------------ r1109 | ajapted | 2012-01-03 Eureka: implemented 'include' directive for ".ugh" definition files. This will be handy for: (a) common stuff between DOOM 1 and DOOM 2 (b) ports which are boom compatible ------------------------------------------------------------------------ r1108 | ajapted | 2012-01-03 Eureka: worked on "ugh" definition file loading, supply a folder name as well as the filename to the LoadDefinitions() function, with some test code which loads the "ports/boom" definition file. ------------------------------------------------------------------------ r1107 | ajapted | 2012-01-03 Eureka: added a mods/ directory. ------------------------------------------------------------------------ r1106 | ajapted | 2012-01-03 WISHLIST tweak. ------------------------------------------------------------------------ r1105 | ajapted | 2012-01-03 Eureka: renamed configs/ folder --> games/ ------------------------------------------------------------------------ r1104 | ajapted | 2012-01-03 Eureka: moved BOOM and EDGE definition files --> ports/ ------------------------------------------------------------------------ r1103 | ajapted | 2012-01-03 Eureka: added 'ports' directory, a place for source-port definitions. ------------------------------------------------------------------------ r1102 | ajapted | 2012-01-03 Eureka: added '192' as a grid size. ------------------------------------------------------------------------ r1101 | ajapted | 2012-01-03 Eureka: draw vertices in proper colors when selected and/or highlighted (previously they remained green, only the box around them has the proper color). Also made vertices more visible (solid area at centre). ------------------------------------------------------------------------ r1100 | ajapted | 2012-01-03 TODO update. ------------------------------------------------------------------------ r1099 | ajapted | 2012-01-03 Eureka: reworked colors of linedefs (UI_Canvas), white is used for single-sided lines (instead of lines with the blocking flag), and white is used in VERTEX mode too now. In LINEDEF mode, cyan is used for double-sided lines which have the blocking flag. ------------------------------------------------------------------------ r1098 | ajapted | 2012-01-03 Eureka: implemented CMD_CorrectSector(). ------------------------------------------------------------------------ r1097 | ajapted | 2012-01-03 Eureka: when splitting a linedef with a new vertex, ensure the vertex lies directly on the linedef (i.e. not slightly off the side). This only applies when grid snapping is OFF. ------------------------------------------------------------------------ r1096 | ajapted | 2012-01-03 Eureka: began work to make 'c' key be a "correct sector" function. ------------------------------------------------------------------------ r1095 | ajapted | 2012-01-03 Eureka / Utilities: added PerpDist() and AlongDist(), and removed some unused stuff. ------------------------------------------------------------------------ r1094 | ajapted | 2012-01-03 Eureka: implemented MoveCoordOntoLineDef() function. ------------------------------------------------------------------------ r1093 | ajapted | 2012-01-03 Eureka: experimented with an alternate grid (simple squares), which can be toggled via 'P' key (need a better key or mechanism though). ------------------------------------------------------------------------ r1092 | ajapted | 2012-01-03 Eureka: made the single-quote key (') move the 3D camera to the cursor position. ------------------------------------------------------------------------ r1091 | ajapted | 2012-01-03 Eureka: changed LighterColor() to be less bright. ------------------------------------------------------------------------ r1090 | ajapted | 2012-01-03 Eureka: added code to create a 'bright_map' table, which maps palette colors to a brighter (closer to white) color in the palette. This could potentially be used in the 3D preview to highlight stuff. ------------------------------------------------------------------------ r1089 | ajapted | 2012-01-03 Eureka: deleting a single vertex attached to TWO linedefs (no more, no less) is now a special case which merges the linedefs together. ------------------------------------------------------------------------ r1088 | ajapted | 2012-01-03 Eureka: TODO update. ------------------------------------------------------------------------ r1087 | ajapted | 2012-01-03 Eureka: changed DisconnectLineDefs logic so that the selected linedefs get any new vertices (existing geometry keeps the existing vertices). ------------------------------------------------------------------------ r1086 | ajapted | 2012-01-03 Eureka: implemented the logic for 'DisconnectLineDefs', which works somewhat different than disconnecting vertices since we want to keep all linedefs in the selection connected and only disconnect from linedefs NOT in the selection. ------------------------------------------------------------------------ r1085 | ajapted | 2012-01-03 tidy up. ------------------------------------------------------------------------ r1084 | ajapted | 2012-01-03 Eureka: added 'd' command to README.txt ------------------------------------------------------------------------ r1083 | ajapted | 2012-01-03 Eureka: fixed problems in the DisconnectVertex code, and improved the logic in CalcDisconnectCoord(). Also assigned to 'd' key (was 'D'). ------------------------------------------------------------------------ r1082 | ajapted | 2012-01-02 Eureka: implemented a 'D' command to Disconnect linedefs. Untested. ------------------------------------------------------------------------ r1081 | ajapted | 2012-01-02 Eureka: version bump to 0.70 -- good progress with vertex stuff. ------------------------------------------------------------------------ r1080 | ajapted | 2012-01-02 Eureka: just some algorithm notes... ------------------------------------------------------------------------ r1079 | ajapted | 2012-01-02 Eureka: yet another TODO update. ------------------------------------------------------------------------ r1078 | ajapted | 2012-01-02 Eureka: when adding a linedef between two existing vertices, reselect the second one IFF it was isolated (not connected to any linedefs). ------------------------------------------------------------------------ r1077 | ajapted | 2012-01-02 Eureka: minor renaming, CastVerty --> CastVert. ------------------------------------------------------------------------ r1076 | ajapted | 2012-01-02 Eureka: use RGB_RED() etc macros instead of directly manipulating color values. ------------------------------------------------------------------------ r1075 | ajapted | 2012-01-02 Eureka: added DarkerColor() function. ------------------------------------------------------------------------ r1074 | ajapted | 2012-01-02 Eureka: renamed pcolour_t --> rgb_color_t ------------------------------------------------------------------------ r1073 | ajapted | 2012-01-02 Eureka: made DARKGREY and LIGHTGREY a bit brighter, and DARKGREY is used for things now (removed THING_REM constant). ------------------------------------------------------------------------ r1072 | ajapted | 2012-01-02 Eureka: implemented dragging a vertex onto a linedef to split it. ------------------------------------------------------------------------ r1071 | ajapted | 2012-01-02 Eureka: use "highlighted()" instead of "! highlighted.is_nil()" ------------------------------------------------------------------------ r1070 | ajapted | 2012-01-02 Eureka / Browser: added a 'X' close button at top right. ------------------------------------------------------------------------ r1069 | ajapted | 2012-01-02 Eureka: for user interface use 'Linedef' instead of 'LineDef'. ------------------------------------------------------------------------ r1068 | ajapted | 2012-01-02 Eureka: TODO update. ------------------------------------------------------------------------ r1067 | ajapted | 2012-01-02 Eureka: made ^U be the main key to unselect everything, instead of END. The back-quota key (`) remains an alternative to ^U, as well as just clicking in an empty spot. Made the '0' key be an alternative for HOME key (centre map, zoom out). ------------------------------------------------------------------------ r1066 | ajapted | 2012-01-02 Eureka: when dragging, require the pointer to move at least 6 pixels before the drag is considered valid. This prevents accidentally moving an object when all you wanted to do was select it. ------------------------------------------------------------------------ r1065 | ajapted | 2012-01-02 Eureka: TODO update. ------------------------------------------------------------------------ r1064 | ajapted | 2012-01-02 Eureka: never highlight a 'split_line' when a vertex is highlighted. Fixed updating the split_line while dragging a single vertex (however the ability to split the line after the drag is not implemented yet). ------------------------------------------------------------------------ r1063 | ajapted | 2012-01-02 Eureka: code reformatting of 'for' loops, have a space before the ';' separators. ------------------------------------------------------------------------ r1062 | ajapted | 2012-01-02 Eureka: added SIDE_RIGHT and SIDE_LEFT constants. ------------------------------------------------------------------------ r1061 | ajapted | 2012-01-02 Eureka: removed unused constant 'Y_NULL'. ------------------------------------------------------------------------ r1060 | ajapted | 2012-01-02 Eureka: TODO update. ------------------------------------------------------------------------ r1059 | ajapted | 2012-01-02 Eureka: when adding vertices, prevent creating zero-length linedefs, and when a vertex is highlighted and nothing is selected then merely select that vertex -- this allows using the SPACE key to begin the process of adding linedefs, which is quite convenient. ------------------------------------------------------------------------ r1058 | ajapted | 2012-01-02 Eureka: when using 'x' key to split linedefs, don't selected the new linedefs if they were not selected before. ------------------------------------------------------------------------ r1057 | ajapted | 2012-01-01 tweak. ------------------------------------------------------------------------ r1056 | ajapted | 2012-01-01 Eureka: pass size to CreateSquare(). ------------------------------------------------------------------------ r1055 | ajapted | 2012-01-01 tweak. ------------------------------------------------------------------------ r1054 | ajapted | 2012-01-01 Eureka: got the 'Choose' buttons in the Line/Sector/Thing panels working [they open up the browser on the appropriate list of types]. ------------------------------------------------------------------------ r1053 | ajapted | 2012-01-01 tweak. ------------------------------------------------------------------------ r1052 | ajapted | 2012-01-01 Eureka / 3D View: removed "walking" mode, the 'w' key now just moves the camera Z to the ground + viewheight. ------------------------------------------------------------------------ r1051 | ajapted | 2012-01-01 Eureka: changed the sector height +/- buttons step from 16 to 8. (It needs to be configurable though). ------------------------------------------------------------------------ r1050 | ajapted | 2011-12-31 Eureka: fixed silly bug in Drag_UpdateObjectDist(). ------------------------------------------------------------------------ r1049 | ajapted | 2011-12-31 Eureka: fixed dragging of objects to honor snapping, and use a focus object as returned by GetDrawFocus(). ------------------------------------------------------------------------ r1048 | ajapted | 2011-12-31 Eureka: fixed bug in GetDragFocus() -- uninitialized variables. ------------------------------------------------------------------------ r1047 | ajapted | 2011-12-31 Eureka: minor renaming: mapx --> map_x, mapy --> map_y ------------------------------------------------------------------------ r1046 | ajapted | 2011-12-31 Eureka: improved GetDragFocus() code in two major ways: (1) check ALL the objects in the selection (2) when snapping is active, check if the majority of the objects are on the grid -- if so then only pick a coordinate which is also on the grid. ------------------------------------------------------------------------ r1045 | ajapted | 2011-12-31 Eureka: added OnGrid() method to test if a point is on the grid. ------------------------------------------------------------------------ r1044 | ajapted | 2011-12-31 Eureka: implemented GetDragFocus() which returns the coordinate of the selected object which will be used as the focus for dragging (especially when grid-snapping, that coordinate will snap to the grid). ------------------------------------------------------------------------ r1043 | ajapted | 2011-12-30 Eureka: TODO update. ------------------------------------------------------------------------ r1042 | ajapted | 2011-12-30 Makefile: lowercased program name: Eureka --> eureka ------------------------------------------------------------------------ r972 | ajapted | 2011-12-11 Eureka: TODO update. ------------------------------------------------------------------------ r960 | ajapted | 2011-12-09 Eureka / Browser: ability to scroll browser with PGUP and PGDN keys. ------------------------------------------------------------------------ r959 | ajapted | 2011-12-09 Eureka: minor reformatting. ------------------------------------------------------------------------ r958 | ajapted | 2011-12-09 Eureka / Browser: fixed scrolling anomalies. ------------------------------------------------------------------------ r957 | ajapted | 2011-12-08 Eureka: mucho tweakage of 'About' window appearance. ------------------------------------------------------------------------ r956 | ajapted | 2011-12-08 Eureka: implemented a basic 'About' window. New code files: ui_about.cc/h and ui_hyper.cc/h ------------------------------------------------------------------------ r955 | ajapted | 2011-12-07 Eureka: TODO update. ------------------------------------------------------------------------ r954 | ajapted | 2011-12-07 Eureka: when adding a vertex which BOTH splits a line and adds a line, don't reselect the new vertex. ------------------------------------------------------------------------ r953 | ajapted | 2011-12-07 color tweak. ------------------------------------------------------------------------ r952 | ajapted | 2011-12-07 Eureka: implemented being able to split a linedef in Vertex mode by simply hovering over a linedef and pressing INSERT. ------------------------------------------------------------------------ r951 | ajapted | 2011-12-07 Eureka: fixed the logic to highlight a to-be-split linedef. ------------------------------------------------------------------------ r950 | ajapted | 2011-12-07 Eureka: worked on logic to find the linedef which would be split by a new vertex. ------------------------------------------------------------------------ r949 | ajapted | 2011-12-07 Eureka: worked on logic to highlight a linedef which would be split by a newly inserted vertex. ------------------------------------------------------------------------ r948 | ajapted | 2011-12-07 Eureka: when adding linedefs in Vertex mode, don't select the second vertex when it wasn't a new vertex (i.e. after closing off an area). ------------------------------------------------------------------------ r947 | ajapted | 2011-12-07 Eureka: TODO update. ------------------------------------------------------------------------ r946 | ajapted | 2011-12-07 Eureka / README: describe 'e' / 'E' keys for SECTOR mode. ------------------------------------------------------------------------ r945 | ajapted | 2011-12-07 Eureka: when selecting contiguous sectors, never go through closed doors. ------------------------------------------------------------------------ r944 | ajapted | 2011-12-07 Eureka: implemented new command 'e' / 'E' in SECTORS mode which selects contiguous sectors with the same floor height / texture. ------------------------------------------------------------------------ r943 | ajapted | 2011-12-07 Eureka: implemented 'E' key which selects lines in a path which all share the same texture. ------------------------------------------------------------------------ r942 | ajapted | 2011-12-07 Eureka: made 'e' key (Select-lines-in-path) use additive mode. The CTRL-E key is also the same function (compatibility with Yadex), though it still could be nabbed for a better use in the future. ------------------------------------------------------------------------ r941 | ajapted | 2011-12-07 Eureka: TODO + WISHLIST update. ------------------------------------------------------------------------ r940 | ajapted | 2011-12-07 Eureka: have a Browser_Key() and Grid_Key() function. ------------------------------------------------------------------------ r939 | ajapted | 2011-12-06 Eureka: worked on having a Global_Key() function which handles all global stuff (such as 'b' to toggle the Browser panel). Editor_Key() will be reserved for commands that modify the map or grid. ------------------------------------------------------------------------ r938 | ajapted | 2011-12-06 Eureka: fixed sidedef info (in LineDef panel) not being updated when picking new textures on selected linedefs. ------------------------------------------------------------------------ r937 | ajapted | 2011-12-06 Eureka: honor grid snapping when pasting + pointer is outside window. ------------------------------------------------------------------------ r936 | ajapted | 2011-12-06 Eureka: fixed Paste (^V) and Copy (o) commands to honor grid snapping, and improved method to find the "centre" vertex or thing (return the coordinate of an actual vertex or thing in the group) -- hence if the copied group was all aligned to the grid, the pasted one will be too. ------------------------------------------------------------------------ r935 | ajapted | 2011-12-06 Eureka: provide a function to check if clipboard contains stuff. ------------------------------------------------------------------------ r934 | ajapted | 2011-12-06 Eureka: when inserting sectors, don't clone the currently selected one unless the SHIFT key is pressed. When inserting linedef, check whether a linedef between the two vertices exists already. Removed the crufty old InsertNewObject() code. ------------------------------------------------------------------------ r933 | ajapted | 2011-12-06 Eureka: implemented key (CTRL-U or CTRL-K) to clear the search box. ------------------------------------------------------------------------ r932 | ajapted | 2011-12-06 Eureka / Browser: implemented 'c' key to cycle through categories, and the 'C' key to reset category to "ALL". ------------------------------------------------------------------------ r931 | ajapted | 2011-12-06 Eureka: yet another TODO / WISHLIST update. ------------------------------------------------------------------------ r930 | ajapted | 2011-12-06 Eureka / Browser: support categories for Thing Types and Line Types. ------------------------------------------------------------------------ r929 | ajapted | 2011-12-06 Eureka / Browser: support categories for Textures and Flats. ------------------------------------------------------------------------ r928 | ajapted | 2011-12-06 Eureka / Browser: worked on getting the Category / Search working, and removed various old crud. ------------------------------------------------------------------------ r927 | ajapted | 2011-12-06 Eureka: version bump, really good progress with the Browser. ------------------------------------------------------------------------ r926 | ajapted | 2011-12-06 Eureka: show mid-masked textures with a bright CYAN background. ------------------------------------------------------------------------ r925 | ajapted | 2011-12-06 Eureka: added panel_W, browser_W fields to UI_Window class. ------------------------------------------------------------------------ r924 | ajapted | 2011-12-06 tweaks. ------------------------------------------------------------------------ r923 | ajapted | 2011-12-06 Eureka: force the Kromulent Factor (KF) = 1 for time being. ------------------------------------------------------------------------ r922 | ajapted | 2011-12-06 Eureka: TODO / WISHLIST update. ------------------------------------------------------------------------ r921 | ajapted | 2011-12-06 Eureka / Browser: make it wider, enough for 4 flats or two 128-wide textures. ------------------------------------------------------------------------ r920 | ajapted | 2011-12-06 Eureka: when loading textures, skip the very first entry (#0) since it's not really usable -- in the DOOM engine the #0 texture is never drawn. ------------------------------------------------------------------------ r919 | ajapted | 2011-12-06 Eureka / Browser: have two constructors for Browser_Item: simple one for text buttons (e.g. Thing Types) and second one for picture buttons (Textures and Flats). The textual buttons are now working again. ------------------------------------------------------------------------ r918 | ajapted | 2011-12-06 Eureka / Browser: show flat and texture names underneath the pic. ------------------------------------------------------------------------ r917 | ajapted | 2011-12-05 Eureka: TODO update. ------------------------------------------------------------------------ r916 | ajapted | 2011-12-05 Eureka / Browser: fixed bug with funny gaps at the top (the Filter method was visited the scrollbar widgets since they were not the last ones). Made the background of scrolling part be BLACK for textures and flats. Various tweaks and tidying of the code. ------------------------------------------------------------------------ r915 | ajapted | 2011-12-05 Eureka / Browser: fixed the side-by-side packing logic in Filter(). ------------------------------------------------------------------------ r914 | ajapted | 2011-12-05 Eureka / Menu: added FL_MENU_INACTIVE to the divider lines, and tidied up some junk in there. ------------------------------------------------------------------------ r913 | ajapted | 2011-12-05 Eureka: TODO / WISHLIST stuff. ------------------------------------------------------------------------ r912 | ajapted | 2011-12-05 Eureka / Browser: worked on Filter() logic and side-by-side packing... ------------------------------------------------------------------------ r911 | ajapted | 2011-12-05 Eureka / Browser: partial work on handling the Category setting.... ------------------------------------------------------------------------ r910 | ajapted | 2011-12-04 Eureka / Browser: code to setup the Category choices for each browser box. (the choice is not used yet however). ------------------------------------------------------------------------ r909 | ajapted | 2011-12-04 Eureka / README: a couple more fixes. ------------------------------------------------------------------------ r908 | ajapted | 2011-12-04 Eureka / README: small fix. ------------------------------------------------------------------------ r907 | ajapted | 2011-12-04 Eureka / Browser: fixed the Texture/Flat browser not showing anything, we need to Populate() the browser boxes _after_ loading all the flats and textures from the wad(s). ------------------------------------------------------------------------ r906 | ajapted | 2011-12-04 Eureka / Browser: various fixes, the new structure is now working OK. ------------------------------------------------------------------------ r905 | ajapted | 2011-12-04 Eureka / Browser: worked on new structure, where UI_Browser is a container widget which contains (and controls) a bunch of UI_Browser_Box widgets. ------------------------------------------------------------------------ r904 | ajapted | 2011-12-04 Eureka: created empty "boom.ugh" and "edge.ugh" engine config files (in preparation to move the specific pieces out of doom2.ugh). ------------------------------------------------------------------------ r903 | ajapted | 2011-12-04 Eureka: moved DOOM2 game configuration file --> configs/ folder. ------------------------------------------------------------------------ r902 | ajapted | 2011-12-04 Eureka: addid configs/ folder. ------------------------------------------------------------------------ r901 | ajapted | 2011-12-04 Eureka: fixes for the new Browser menu... ------------------------------------------------------------------------ r900 | ajapted | 2011-12-04 Eureka: added a "Browser" menu on the main menu bar, worked on code to support it. ------------------------------------------------------------------------ r899 | ajapted | 2011-12-04 Eureka / Canvas: tweaked size of Knobby lines. ------------------------------------------------------------------------ r898 | ajapted | 2011-12-04 Eureka / Browser: worked on a UI_Browser_Menu class. ------------------------------------------------------------------------ r897 | ajapted | 2011-12-04 Eureka: TODO update. ------------------------------------------------------------------------ r896 | ajapted | 2011-12-04 tweak. ------------------------------------------------------------------------ r895 | ajapted | 2011-12-03 Eureka: when making category menu strings, also return the group letters so they can be used to filter the browser items. ------------------------------------------------------------------------ r894 | ajapted | 2011-12-03 tweak. ------------------------------------------------------------------------ r893 | ajapted | 2011-12-03 Eureka: capitalize 'OTHER' in browser categories. ------------------------------------------------------------------------ r892 | ajapted | 2011-12-03 Eureka: fixed missing '|' in category string conversion. ------------------------------------------------------------------------ r891 | ajapted | 2011-12-03 Eureka: added code to convert the descriptions in linegroups (etc) into a menu string which can be used in an Fl_Choice widget. ------------------------------------------------------------------------ r890 | ajapted | 2011-12-03 Eureka: updated game config loader to handle 'texturegroup', 'texture' and 'flat' definitions. ------------------------------------------------------------------------ r889 | ajapted | 2011-12-03 Eureka / DOOM2 config: use '-' (not 'x') as letter for "Other" category, and added the '-' as a thinggroup and a texturegroup too. ------------------------------------------------------------------------ r888 | ajapted | 2011-12-03 Eureka / DOOM2 config: finished texture/flat section, tweaked things section. ------------------------------------------------------------------------ r887 | ajapted | 2011-12-02 Eureka / DOOM2 config: worked on texture categories. ------------------------------------------------------------------------ r886 | ajapted | 2011-11-30 Eureka / 3D view: experimental code to draw a highlight border around a solid surface (lower, upper, floor, ceiling). ------------------------------------------------------------------------ r885 | ajapted | 2011-11-30 Eureka: moved some color #defines --> im_color.h ------------------------------------------------------------------------ r884 | ajapted | 2011-11-30 Eureka / DOOM2 config: tweaked descriptions of some linetypes. ------------------------------------------------------------------------ r883 | ajapted | 2011-11-30 Eureka / DOOM2 config: gave some things prefixes, e.g. "MON:" for monsters, "PU:" for pickups and "WP:" for weapons. ------------------------------------------------------------------------ r882 | ajapted | 2011-11-30 Eureka / Browser: tweaked layout. ------------------------------------------------------------------------ r881 | ajapted | 2011-11-30 Eureka: made the Browser a bit wider (to make things fit more comfortably). ------------------------------------------------------------------------ r880 | ajapted | 2011-11-30 Version bump to 0.666 in honor of Texture/Flat browser working. ------------------------------------------------------------------------ r879 | ajapted | 2011-11-30 Eureka / Browser: only allow Right click to change sector ceilings (not SHIFT or middle click) -- for consistency with linedef handling. ------------------------------------------------------------------------ r878 | ajapted | 2011-11-30 Eureka / Browser: imlemented logic for setting textures on two-sided lines. Left click adjusts lowers and Right click adjusts uppers, and Middle click sets mid-masked textures (on both sides). For lowers and uppers we pick the side that faces out, but SHIFT key picks the opposite side. Also some logic for handling windows nicely (change BOTH lower and upper, but only with Left click). ------------------------------------------------------------------------ r877 | ajapted | 2011-11-30 Eureka: the normal select-lines-in-path (on 'e' key) now doesn't unmerge if the original line was selected, since the whole selection gets cleared anyway. New way is more useful when lots of lines are selected and you only want the new path to be selected. ------------------------------------------------------------------------ r876 | ajapted | 2011-11-30 Eureka / Browser: got texture setting on one-sided linedefs working. ------------------------------------------------------------------------ r875 | ajapted | 2011-11-30 Eureka: tweaked UI_Sector:SetTexture() code (check if count > 0). ------------------------------------------------------------------------ r874 | ajapted | 2011-11-30 Eureka / Browser: got texture setting for floors and ceilings working, where a left click sets the floor and a right click sets the ceilings. ------------------------------------------------------------------------ r873 | ajapted | 2011-11-30 Eureka / Browser: partial worked on ability to set flat and textures on sectors and linedefs via the browser. Changed button to Fl_Repeat_Button since that widget lets us check what buttons / modifiers were used. (The standard Fl_Button callback gets done on RELEASE --> no buttons). ------------------------------------------------------------------------ r872 | ajapted | 2011-11-30 Eureka: renamed code file: selpath --> e_path ------------------------------------------------------------------------ r871 | ajapted | 2011-11-30 Eureka: renamed code file: selpath --> e_path ------------------------------------------------------------------------ r870 | ajapted | 2011-11-30 Eureka: added keys for CMD_SelectLinesInPath : 'e' for normal mode, CTRL-E for the additive mode. ------------------------------------------------------------------------ r869 | ajapted | 2011-11-30 Eureka: for selecting lines in a path, have 'additive' parameter which does not forget the current selection. The 'one_sided' mode proved to be fairly useless, hence removed that logic. ------------------------------------------------------------------------ r868 | ajapted | 2011-11-30 Eureka: finished CMD_SelectLinesInPath() : logic to get starting line. ------------------------------------------------------------------------ r867 | ajapted | 2011-11-30 Eureka: added TwoSided() method to LineDef class. ------------------------------------------------------------------------ r866 | ajapted | 2011-11-30 Eureka: implemented 'one_sided' mode for CMD_SelectLinesInPath(). ------------------------------------------------------------------------ r865 | ajapted | 2011-11-30 Eureka: wrote new logic for selecting linedefs in a path. ------------------------------------------------------------------------ r864 | ajapted | 2011-11-29 Eureka: changed INSERT alternate key from 'a' --> SPACE, and changed the Clear Selection key from SPACE --> END or backquote. ------------------------------------------------------------------------ r863 | ajapted | 2011-11-29 Eureka / Browser: worked on positioning the Flat and Texture pics. ------------------------------------------------------------------------ r862 | ajapted | 2011-11-29 Eureka: made the browser panel a bit wider. ------------------------------------------------------------------------ r861 | ajapted | 2011-11-29 Eureka: upgrade to FLTK 1.3.0 (this is required since the texture browser was overflowing the 16-bit widget coordinates of FLTK 1.1.x). ------------------------------------------------------------------------ r860 | ajapted | 2011-11-29 Eureka / Browser: fixed searching to handle '^' and '$' properly (they are not handled by fl_filename_match). ------------------------------------------------------------------------ r859 | ajapted | 2011-11-29 Eureka: version bump, in honor of progress with the Browser. ------------------------------------------------------------------------ r858 | ajapted | 2011-11-29 Eureka: implemented setting Thing and Sector types via the browser. ------------------------------------------------------------------------ r857 | ajapted | 2011-11-29 Eureka: TODO update. ------------------------------------------------------------------------ r856 | ajapted | 2011-11-29 Eureka / 3D Preview: allow 'b' key to toggle the browser. ------------------------------------------------------------------------ r855 | ajapted | 2011-11-29 Eureka: saving the map now clears MadeChanges, preventing the wrong message about the map having unsaved changes when going to quit. ------------------------------------------------------------------------ r854 | ajapted | 2011-11-29 Eureka: re-implemented a swap-flats command for sectors, bound to 'w' key. ------------------------------------------------------------------------ r853 | ajapted | 2011-11-28 Eureka: TODO updated. ------------------------------------------------------------------------ r852 | ajapted | 2011-11-28 Eureka / Browser: can now change Linedef types via the browser! ------------------------------------------------------------------------ r851 | ajapted | 2011-11-28 Eureka: ensure a new object (added with 'a' / INS) gets selected. ------------------------------------------------------------------------ r850 | ajapted | 2011-11-28 Eureka / Browser: clear search string when mode changes due to a new edit mode. ------------------------------------------------------------------------ r849 | ajapted | 2011-11-28 Eureka / Browser: make each browser item into a button. ------------------------------------------------------------------------ r848 | ajapted | 2011-11-28 Eureka: renamed methods: SetMode() --> NewEditMode() ------------------------------------------------------------------------ r847 | ajapted | 2011-11-28 Eureka / Browser: change the browser mode (Textures / Flats / Things) when the edit mode changes to LineDefs / Sectors / Things bzw. ------------------------------------------------------------------------ r846 | ajapted | 2011-11-28 Eureka / Browser: worked on support for Textures and Flats. Only the names are being shown so far.... ------------------------------------------------------------------------ r845 | ajapted | 2011-11-28 Eureka / Browser: clear search box when changing Mode. ------------------------------------------------------------------------ r844 | ajapted | 2011-11-28 Eureka / Browser: implemented the search function. ------------------------------------------------------------------------ r843 | ajapted | 2011-11-28 Eureka / Doom2 config: tweaked some descriptions, especially the zero linedef type and sector type. ------------------------------------------------------------------------ r842 | ajapted | 2011-11-28 Eureka / Browser: fixed missing end() from Browser_Item constructor, and for search box update the list whenever it changes. ------------------------------------------------------------------------ r841 | ajapted | 2011-11-28 Eureka / Browser: use to callback to update the list when the mode, category or search box changes. ------------------------------------------------------------------------ r840 | ajapted | 2011-11-28 Eureka / Browser: code to populate the list with ThingTypes, LineTypes and SectorTypes. ------------------------------------------------------------------------ r839 | ajapted | 2011-11-28 Eureka / Browser: began work to populate the browser with useful stuff like line_types and thing_types. ------------------------------------------------------------------------ r838 | ajapted | 2011-11-28 Eureka: comment tweak. ------------------------------------------------------------------------ r837 | ajapted | 2011-11-28 Eureka: tweaked gap at bottom of side panel + right end of menu bar. ------------------------------------------------------------------------ r836 | ajapted | 2011-11-28 Eureka / Browser: dead code removal. ------------------------------------------------------------------------ r835 | ajapted | 2011-11-28 Eureka: worked on Browser widget, use Fl_Scroll for the scrolling list. ------------------------------------------------------------------------ r834 | ajapted | 2011-11-28 Eureka: more work to fix Browser size when resizing. ------------------------------------------------------------------------ r833 | ajapted | 2011-11-27 Eureka: needed to call init_sizes() in window's ShowBrowser() method since the widgets got rearranged. ------------------------------------------------------------------------ r832 | ajapted | 2011-11-27 Eureka / README: minor fix. ------------------------------------------------------------------------ r831 | ajapted | 2011-11-27 Eureka / Makefile: fixed 'make clean' target. ------------------------------------------------------------------------ r830 | ajapted | 2011-11-27 Eureka: document tweaks. ------------------------------------------------------------------------ r829 | ajapted | 2011-11-27 Eureka: TODO update. ------------------------------------------------------------------------ r828 | ajapted | 2011-11-27 Eureka: make sure all quit methods (ESCAPE key, File menu, window close button) work the same way, and ask for confirmation if the map has been modified. ------------------------------------------------------------------------ r827 | ajapted | 2011-11-27 Eureka: fixed the current map name (right side of infobar). ------------------------------------------------------------------------ r826 | ajapted | 2011-11-27 Eureka: fixed the infobar "lock" widget to update the editor state (i.e. grid.snap and grid.locked) when changed. ------------------------------------------------------------------------ r825 | ajapted | 2011-11-27 Eureka / README: note requirement of doom2.wad, various tweaks. ------------------------------------------------------------------------ r824 | ajapted | 2011-11-27 Eureka / README: added copyright / license section. ------------------------------------------------------------------------ r823 | ajapted | 2011-11-27 Eureka / README: more work, new "RUNNING" section etc... ------------------------------------------------------------------------ r822 | ajapted | 2011-11-27 Eureka: moved keyboard command list from FEATURES.txt --> README.txt and added some extra ones (especially for 3D preview). ------------------------------------------------------------------------ r821 | ajapted | 2011-11-27 Eureka: began work on a basic README.txt document. ------------------------------------------------------------------------ r820 | ajapted | 2011-11-27 Eureka: added basic INSTALL.txt document. ------------------------------------------------------------------------ r819 | ajapted | 2011-11-27 Eureka: code formatting tweak. ------------------------------------------------------------------------ r818 | ajapted | 2011-11-27 Eureka: minor tweak ------------------------------------------------------------------------ r817 | ajapted | 2011-11-27 Eureka: version bump. ------------------------------------------------------------------------ r816 | ajapted | 2011-11-27 TODO / WISHLIST twiddling.... ------------------------------------------------------------------------ r815 | ajapted | 2011-11-27 Eureka: fixed wrong values with light "-" button (in Sector panel). ------------------------------------------------------------------------ r814 | ajapted | 2011-11-27 Eureka / Render3D: implemented low-detail mode (toggle via F5 key). ------------------------------------------------------------------------ r813 | ajapted | 2011-11-27 Eureka / Render3D: implemented a "lo-res" mode. ------------------------------------------------------------------------ r812 | ajapted | 2011-11-27 Eureka: added 'lib_linux' folder. ------------------------------------------------------------------------ r811 | ajapted | 2011-11-27 Eureka: moved MEMORY.txt document --> attic/ ------------------------------------------------------------------------ r810 | ajapted | 2011-11-27 Eureka: added 'attic' folder. ------------------------------------------------------------------------ r809 | ajapted | 2011-11-27 Eureka / Makefile: fixed location of exe. ------------------------------------------------------------------------ r808 | ajapted | 2011-11-27 Eureka / Makefile: updated for top-level and obj_linux folder. ------------------------------------------------------------------------ r807 | ajapted | 2011-11-27 Eureka: added 'obj_linux' folder for the build process. ------------------------------------------------------------------------ r806 | ajapted | 2011-11-27 Eureka: TODO update. ------------------------------------------------------------------------ r805 | ajapted | 2011-11-27 Eureka: moved Makefile to top level. ------------------------------------------------------------------------ r804 | ajapted | 2011-11-27 Eureka / Render3D: enable 'lighting' by default. ------------------------------------------------------------------------ r803 | ajapted | 2011-11-27 Eureka / Render3D: support for aspect-ratio correction. ------------------------------------------------------------------------ r802 | ajapted | 2011-11-27 Eureka / Render3D: tweaked mouse scrolling (future option to allow both angular and Z movement at same time). ------------------------------------------------------------------------ r801 | ajapted | 2011-11-27 Eureka: fixed 3D preview to handle resizing the main window. ------------------------------------------------------------------------ r800 | ajapted | 2011-11-27 Eureka: draw "knobby" linedefs (only in LineDef and Vertex mode). ------------------------------------------------------------------------ r799 | ajapted | 2011-11-26 Eureka: fixed vertical stretching of info panels (Things etc) when resizing the main window. ------------------------------------------------------------------------ r543 | ajapted | 2010-09-24 MEMORY doc: changed COPY_GROUP to a more general 'GROUP' object, and renamed EDIT_GROUP --> EDIT_SET. ------------------------------------------------------------------------ r542 | ajapted | 2010-09-24 MEMORY doc: described the edit operations, added STRING objects. ------------------------------------------------------------------------ r541 | ajapted | 2010-09-24 MEMORY document: added lots more detail. ------------------------------------------------------------------------ r540 | ajapted | 2010-09-24 Added MEMORY.txt : document the memory model for map objects. ------------------------------------------------------------------------ r539 | ajapted | 2010-09-24 Makefile: library folder is now 'lib_linux' ------------------------------------------------------------------------ r538 | ajapted | 2010-09-24 FIXED (thank dog!) the ESCAPE key quitting unconditionally. ------------------------------------------------------------------------ r528 | ajapted | 2010-05-16 tweak ------------------------------------------------------------------------ r449 | ajapted | 2009-12-02 Eureka: temporary hack (level loading stuff). ------------------------------------------------------------------------ r448 | ajapted | 2009-12-02 Use FLTK 1.1.10 ------------------------------------------------------------------------ r445 | ajapted | 2009-11-09 Eureka: implemented showing and hiding the Browser panel (via 'b' key). ------------------------------------------------------------------------ r444 | ajapted | 2009-11-09 Eureka: bit more work on Browser stuff. ------------------------------------------------------------------------ r443 | ajapted | 2009-11-09 Eureka: worked on the UI_Browser widget, the top section now has a choice button for the current type (Textures, Flats, etc), plus a choice button for the current group (useful for things), plus a search field, and lastly a check button on whether to show images or not. [PROTOTYPE ONLY] ------------------------------------------------------------------------ r442 | ajapted | 2009-11-08 Eureka: renamed UI_FlatTexList --> UI_Browser (et cetera). ------------------------------------------------------------------------ r441 | ajapted | 2009-11-08 Eureka: renamed code files: ui_flattex --> ui_browser ------------------------------------------------------------------------ r440 | ajapted | 2009-11-08 TODO update. ------------------------------------------------------------------------ r439 | ajapted | 2009-11-08 Eureka: draw an selected AND highlighted object in a different color, and changed the selection color to a sky-blue. ------------------------------------------------------------------------ r438 | ajapted | 2009-11-08 Eureka: implemented mirror commands for the Edit menu. ------------------------------------------------------------------------ r437 | ajapted | 2009-11-08 Eureka: fixed Paste from the menu to place new items at centre of canvas. ------------------------------------------------------------------------ r436 | ajapted | 2009-11-08 noted a bug. ------------------------------------------------------------------------ r435 | ajapted | 2009-11-08 Eureka: implemented key to Flip linedefs. ------------------------------------------------------------------------ r434 | ajapted | 2009-11-08 todo tweakage. ------------------------------------------------------------------------ r433 | ajapted | 2009-11-08 Eureka: improved FindIslands() code to handle when the initial path is itself an island, whereby it reaches out to the outer area. ------------------------------------------------------------------------ r432 | ajapted | 2009-11-08 Eureka: finding islands: fixed a bug (erroneous check on sidedefs). ------------------------------------------------------------------------ r431 | ajapted | 2009-11-08 Eureka: FindIslands() : recompute bbox on each call (it can change when islands reach out to other geometry). ------------------------------------------------------------------------ r430 | ajapted | 2009-11-08 Eureka: further work on finding islands... ------------------------------------------------------------------------ r429 | ajapted | 2009-11-08 Eureka: fixed logic in OppositeLineDef() : result_side was wrong. ------------------------------------------------------------------------ r428 | ajapted | 2009-11-07 Eureka: preliminary work on Island-finding algorithm (for sector insertion). ------------------------------------------------------------------------ r427 | ajapted | 2009-11-07 Eureka: decreases the mapslack for highlighting a vertex, making it less likely to accidentally join the wrong vertex while inserting lines (etc). ------------------------------------------------------------------------ r426 | ajapted | 2009-11-07 Eureka: fixed problem with "ugly" 45-degree lines, caused by width = 1 parameter in fl_line_style(). Using width = 0 produces nicer results. ------------------------------------------------------------------------ r425 | ajapted | 2009-11-07 Eureka: fixed bug with wrong initial grid step in the InfoBar. ------------------------------------------------------------------------ r424 | ajapted | 2009-11-07 Eureka: properly update the side panel after map changes. ------------------------------------------------------------------------ r423 | ajapted | 2009-11-07 Eureka: made sure linedefs inserted in vertex mode have Impassible flag. ------------------------------------------------------------------------ r422 | ajapted | 2009-11-07 Eureka: fixed re-selection after inserting a sector (into a space). ------------------------------------------------------------------------ r421 | ajapted | 2009-11-07 reformatted code. ------------------------------------------------------------------------ r420 | ajapted | 2009-11-07 Eureka: when inserting a sector, fixup linedefs which become 2-sided (add 2S flag, clear impassible flag, make middle texture "-"). ------------------------------------------------------------------------ r419 | ajapted | 2009-11-07 Eureka: version bumped to 0.61 ------------------------------------------------------------------------ r418 | ajapted | 2009-11-07 Eureka: try harder to find a usable texture when linedef becomes one-sided (check the to-be-removed sidedef too). ------------------------------------------------------------------------ r417 | ajapted | 2009-11-07 Eureka: for sector deletions, make sure to fix-up any linedefs which become one-sided (update 2S and impassible flag, middle texture, and flip if needed). ------------------------------------------------------------------------ r416 | ajapted | 2009-11-07 Eureka: e_cutpaste.cc : added new DoRemoveSideFromLine() function, and moved all the CMD_Delete() code to the bottom of the file. ------------------------------------------------------------------------ r415 | ajapted | 2009-11-07 Eureka: made SHIFT + DELETE keep any unused bits (vertices etc). ------------------------------------------------------------------------ r414 | ajapted | 2009-11-07 Eureka: pass keymod_e to EditorKey() and similar functions. ------------------------------------------------------------------------ r413 | ajapted | 2009-11-07 Eureka: when deleting sectors, find and delete Linedefs which would be unused afterwards -- and in turn unused vertices and sidedefs. ------------------------------------------------------------------------ r412 | ajapted | 2009-11-07 Eureka: remove unused sidedefs when deleting linedefs (same logic as for vertices). ------------------------------------------------------------------------ r411 | ajapted | 2009-11-07 Eureka: reworked code to delete unused vertices when deleting linedefs. ------------------------------------------------------------------------ r410 | ajapted | 2009-11-07 Eureka: BASIS: no longer delete a linedef when it ends up with no sides, that was too heavy handed (such linedefs are not valid for DOOM engines but is allowed inside the editor). ------------------------------------------------------------------------ r409 | ajapted | 2009-11-07 Eureka: worked on making deletion of linedefs and sectors also remove any vertices and/or sidedefs which would end up unused after deletion. Also merged CMD_Delete() and CMD_FullDelete() into one function. ------------------------------------------------------------------------ r408 | ajapted | 2009-11-07 Eureka: ConvertSelection() now handles LINES->SIDES and SECTORS->SIDES. ------------------------------------------------------------------------ r407 | ajapted | 2009-11-07 Eureka: added new selection_c::unmerge() and intersect() methods. ------------------------------------------------------------------------ r406 | ajapted | 2009-11-06 TODO twiddling. ------------------------------------------------------------------------ r405 | ajapted | 2009-11-06 tweaks ------------------------------------------------------------------------ r404 | ajapted | 2009-11-06 Eureka: improved vertex insertion to merely add a linedef when two vertices are selected (or one selected and one highlighted). ------------------------------------------------------------------------ r403 | ajapted | 2009-11-06 Eureka: added 'find_first' and 'find_second' methods to selection_c class. ------------------------------------------------------------------------ r402 | ajapted | 2009-11-06 Eureka: made the HOME key centre-and-zoom-out the map (instead of '0'). ------------------------------------------------------------------------ r401 | ajapted | 2009-11-06 Eureka: the 'a' key is now equivalent to INSERT key (was 'i' before). ------------------------------------------------------------------------ r400 | ajapted | 2009-11-06 Eureka: bit more work on Sector insertions. ------------------------------------------------------------------------ r399 | ajapted | 2009-11-05 todo update. ------------------------------------------------------------------------ r398 | ajapted | 2009-11-05 Eureka: tweaked the key-binding list (FEATURES.txt) ------------------------------------------------------------------------ r397 | ajapted | 2009-11-05 Eureka: fixed some bugs in the AssignSectorToSpace() code. ------------------------------------------------------------------------ r396 | ajapted | 2009-11-05 Eureka: implemented DoAssignSector() function, for sector insertion code. ------------------------------------------------------------------------ r395 | ajapted | 2009-11-05 Eureka: worked on fixing the code which traces a closed path of linedefs to determine where to place a new (or existing) sector reference. ------------------------------------------------------------------------ r394 | ajapted | 2009-11-05 tweaks. ------------------------------------------------------------------------ r393 | ajapted | 2009-11-05 Eureka: initial code for new OppositeLineDef() function. ------------------------------------------------------------------------ r392 | ajapted | 2009-11-05 Eureka: use new PointOutsideOfMap() check for creating a square when inserting in Sector mode. ------------------------------------------------------------------------ r391 | ajapted | 2009-11-05 dead code removal. ------------------------------------------------------------------------ r390 | ajapted | 2009-11-05 Eureka: x_hover: added PointOutsideOfMap() utility function, and updated the header file with the other new functions. ------------------------------------------------------------------------ r389 | ajapted | 2009-11-05 Eureka: improved get_cur_sector() logic by casting both vertical and horizontal rays to find the closest linedef. ------------------------------------------------------------------------ r388 | ajapted | 2009-11-05 Eureka: fixed bugs in ClosestLine_CastingVerty() function. ------------------------------------------------------------------------ r387 | ajapted | 2009-11-05 Eureka: improved the ClosestLine_CastingXXX functions to (a) check both casting directions, e.g. right AND left, and (b) return which side the test point is on (1, 0, -1). ------------------------------------------------------------------------ r386 | ajapted | 2009-11-05 Eureka: x_hover.cc: separated code into new ClosestLineDef_CastingRight() function, and added new ClosestLineDef_CastingUp() function. ------------------------------------------------------------------------ r385 | ajapted | 2009-11-05 Eureka: renamed map bounds global vars again: MapBound_[lh][xy] ------------------------------------------------------------------------ r384 | ajapted | 2009-11-05 code tidying. ------------------------------------------------------------------------ r383 | ajapted | 2009-11-05 Eureka: no need to invalidate the Selection when the inserted or deleted object is above the max_obj(). ------------------------------------------------------------------------ r382 | ajapted | 2009-11-05 Eureka: added fast max_obj() method to selection_c class, and renamed the slow_count() method --> count_obj(). ------------------------------------------------------------------------ r381 | ajapted | 2009-11-05 Eureka: further work on adjusting move/scroll speeds based on whether SHIFT or CTRL keys are pressed. ------------------------------------------------------------------------ r380 | ajapted | 2009-11-04 Eureka render mode: more control over speed of forward/back/strafe keys (CTRL faster, SHIFT slower). Changed fly up/down keys to PGUP and PGDN. Renamed key_mod_e --> keymod_e ------------------------------------------------------------------------ r379 | ajapted | 2009-11-04 Eureka: for 3D preview, made SHIFT and CTRL control the speed of moving forward/backwards when using the mousewheel. ------------------------------------------------------------------------ r378 | ajapted | 2009-11-04 Eureka: added key_mod_e enumeration (KM_SHIFT, KM_CTRL etc). ------------------------------------------------------------------------ r377 | ajapted | 2009-11-04 Eureka: created new WISHLIST.txt document. ------------------------------------------------------------------------ r376 | ajapted | 2009-11-04 TODO update. ------------------------------------------------------------------------ r375 | ajapted | 2009-11-04 Eureka: made sane the usage of h1 and h2 fields of DrawSurf. ------------------------------------------------------------------------ r374 | ajapted | 2009-11-04 Eureka renderer: fixed y_offset for Mid-Masked textures, YAY! ------------------------------------------------------------------------ r373 | ajapted | 2009-11-04 Eureka: ignore self-referenced lines in 3D renderer. ------------------------------------------------------------------------ r372 | ajapted | 2009-11-04 Eureka: much better mid-masked textures in 3D preview. ------------------------------------------------------------------------ r371 | ajapted | 2009-11-04 reformatted some code. ------------------------------------------------------------------------ r370 | ajapted | 2009-11-04 Eureka: preliminary work on rendering mid-masked textures... ------------------------------------------------------------------------ r369 | ajapted | 2009-11-04 Eureka: worked on improving the x_hover.cc code. ------------------------------------------------------------------------ r368 | ajapted | 2009-11-04 Eureka: disabled experimental new 'get_cur_sector', which did not work properly in several situations (cf MAP02 of TNT). ------------------------------------------------------------------------ r367 | ajapted | 2009-11-04 Eureka: renamed DistanceToLineDef() --> ApproxDistToLineDef(). ------------------------------------------------------------------------ r366 | ajapted | 2009-11-04 Eureka: experimental new way to determine current sector at a point. ------------------------------------------------------------------------ r365 | ajapted | 2009-11-04 Eureka: removed unused utility function. ------------------------------------------------------------------------ r364 | ajapted | 2009-11-04 dead code removal. ------------------------------------------------------------------------ r363 | ajapted | 2009-11-04 Eureka: implemented a DistanceToLineDef() function. Did some tidying in x_hover.cc ------------------------------------------------------------------------ r362 | ajapted | 2009-11-04 Eureka: moved some code in x_hover.cc ------------------------------------------------------------------------ r361 | ajapted | 2009-11-04 Eureka: make sure the Total value in each side panel is kept up-to-date. ------------------------------------------------------------------------ r360 | ajapted | 2009-11-04 Eureka: fixed input widgets on the side panels so that the ENTER key does not jump to another widget, instead staying in that input widget. ------------------------------------------------------------------------ r359 | ajapted | 2009-11-04 Eureka: added list of needed Config items to the TODO. ------------------------------------------------------------------------ r358 | ajapted | 2009-11-04 Eureka: prevent ENTER key doing the 'Unselect All' command. ------------------------------------------------------------------------ r357 | ajapted | 2009-11-04 Eureka: tweaked speed of mouse-wheel forward/back in 3D preview. ------------------------------------------------------------------------ r356 | ajapted | 2009-11-04 Eureka: fixed (Un)select-All commands to update the side panel. ------------------------------------------------------------------------ r355 | ajapted | 2009-11-03 Eureka: show more info (strerror) in LOG.txt when a pwad cannot be opened. ------------------------------------------------------------------------ r354 | ajapted | 2009-11-03 tweak. ------------------------------------------------------------------------ r353 | ajapted | 2009-11-03 Eureka: fixed loading maps with lowercase texture or flat names in the sidedefs or sectors -- they are silently converted to uppercase. ------------------------------------------------------------------------ r352 | ajapted | 2009-11-03 Eureka: support ON_CEILING things in the 3D preview. ------------------------------------------------------------------------ r351 | ajapted | 2009-11-03 Eureka: doom2 game config: lit up the keys and armor vests (added 'l' flag). ------------------------------------------------------------------------ r350 | ajapted | 2009-11-03 Eureka: draw Invis and Lit things properly in the 3D preview. ------------------------------------------------------------------------ r349 | ajapted | 2009-11-03 Eureka: game config: parse new 'l' and 'c' flags for things ('l' for Lit things, 'c' for Ceiling things), and changed 's' --> 'i' (Invis). ------------------------------------------------------------------------ r348 | ajapted | 2009-11-03 Eureka: updated game file (doom2.ugh), giving lit objects the 'l' flags and on-ceiling objects the 'c' flag, and changed 's' flag --> 'i'. Also separated out the EDGE specific things. ------------------------------------------------------------------------ r347 | ajapted | 2009-11-03 Eureka: handle mouse motion/clicks better when the 3D preview is shown. ------------------------------------------------------------------------ r346 | ajapted | 2009-11-03 todo stuff ------------------------------------------------------------------------ r345 | ajapted | 2009-11-03 Eureka: renderer: better code to keep track of what sectors each thing is in, recalculating when the number of things or sectors change, or by the user pressing CTRL-L. ------------------------------------------------------------------------ r344 | ajapted | 2009-11-03 Eureka: can now bump gamma with F11 key (in 3D render view). ------------------------------------------------------------------------ r343 | ajapted | 2009-11-03 minor code reformatting. ------------------------------------------------------------------------ r342 | ajapted | 2009-11-03 Eureka: implemented renderer effect where N/S walls are brighter and E/W walls are darker than normal. ------------------------------------------------------------------------ r341 | ajapted | 2009-11-03 Eureka: r_render.cc: misc tidying, replaced fucking 0 with NULL, etc.. ------------------------------------------------------------------------ r340 | ajapted | 2009-11-02 todo tweak ------------------------------------------------------------------------ r339 | ajapted | 2009-11-02 Eureka: support for Lighting in the 3D preview. ------------------------------------------------------------------------ r338 | ajapted | 2009-11-02 Eureka: added code to load the COLORMAP lump. ------------------------------------------------------------------------ r337 | ajapted | 2009-11-02 Eureka: more reformatting in r_render.cc ------------------------------------------------------------------------ r336 | ajapted | 2009-11-02 Eureka: reformatted the code in r_render.cc ------------------------------------------------------------------------ r335 | ajapted | 2009-11-02 Eureka: added useful mode for Vertex/LineDef inserting: if _one_ vertex is selected, then insert a new one, add a joining linedef, and re-select the new vertex. Also split thing, sector creation into separate funcs. ------------------------------------------------------------------------ r334 | ajapted | 2009-11-02 Eureka: added bare-bones code to create a new square-shape sector. ------------------------------------------------------------------------ r333 | ajapted | 2009-11-02 Eureka: renamed variables: MapMinX/Y, MapMaxX/Y --> Map_lx/y, Map_hx/y. ------------------------------------------------------------------------ r332 | ajapted | 2009-11-02 Eureka: debugging code to draw the level's Bounding box. ------------------------------------------------------------------------ r331 | ajapted | 2009-11-02 Eureka: implemented code (via MapStuff_NotifyXXX functions) to keep the level bounds (MapMinX/Y and MapMaxX/Y globals) up-to-date. ------------------------------------------------------------------------ r330 | ajapted | 2009-11-02 Eureka: fixed Pasted objects to be selected (this broke due to recent work on basis notifications). ------------------------------------------------------------------------ r329 | ajapted | 2009-11-02 Eureka: free textures at exit. ------------------------------------------------------------------------ r328 | ajapted | 2009-11-02 Eureka: fixed finding player for renderer when level has Voodoo dolls. ------------------------------------------------------------------------ r327 | ajapted | 2009-11-02 Eureka: fixed bugs in bitvec_c and selection_c classes. ------------------------------------------------------------------------ r326 | ajapted | 2009-11-02 Eureka: fixed memory leak in bitvec_c::resize() code. ------------------------------------------------------------------------ r325 | ajapted | 2009-11-02 Eureka: updated CMD_SelectAll() for recent selection_c changes. ------------------------------------------------------------------------ r324 | ajapted | 2009-11-02 Eureka: implemented new bitvec_c::resize() method. ------------------------------------------------------------------------ r323 | ajapted | 2009-11-02 Eureka: selection_c class: make the bitvector grow as needed, instead of relying on NumObjects() which changes all the time. ------------------------------------------------------------------------ r322 | ajapted | 2009-11-01 TODO update. ------------------------------------------------------------------------ r321 | ajapted | 2009-11-01 Eureka: beginnings of the code for ObjectBox_NotifyXXX() functions. ------------------------------------------------------------------------ r320 | ajapted | 2009-11-01 Eureka: fixed assertion error due to recent changes. ------------------------------------------------------------------------ r319 | ajapted | 2009-11-01 Eureka: dead code removal (all the 'changed_a_xxxx' variables etc). ------------------------------------------------------------------------ r318 | ajapted | 2009-11-01 Eureka: implemented XXX_Notify() functions for the current Selection. ------------------------------------------------------------------------ r317 | ajapted | 2009-11-01 Eureka: call XXX_NotifyBegin() and XXX_NotifyEnd() functions from the Basis. ------------------------------------------------------------------------ r316 | ajapted | 2009-11-01 Eureka: more work on new BASIS notification framework (Clipboard bits). ------------------------------------------------------------------------ r315 | ajapted | 2009-11-01 Eureka: BASIS: partial work on new way of notifying other code about changes/insertions/deletions of map structures. ------------------------------------------------------------------------ r314 | ajapted | 2009-11-01 Eureka: tweaked turning rate when using RMB. ------------------------------------------------------------------------ r313 | ajapted | 2009-11-01 Eureka: added NumObjects() utility function to the Basis. ------------------------------------------------------------------------ r312 | ajapted | 2009-11-01 Eureka: implemented the 'Select All' command (in edit menu). ------------------------------------------------------------------------ r311 | ajapted | 2009-11-01 Eureka: fixed a bug in selection_c::ConvertToBitvec(). ------------------------------------------------------------------------ r310 | ajapted | 2009-11-01 Eureka: fixed bug using wrong NumXXX values in UI_ThingBox and UI_VertexBox. ------------------------------------------------------------------------ r309 | ajapted | 2009-11-01 todo tweak ------------------------------------------------------------------------ r308 | ajapted | 2009-11-01 Eureka: bit more work on having map changes updated all the widgets (etc). ------------------------------------------------------------------------ r307 | ajapted | 2009-11-01 Eureka: BASIS: new 'appended_an_object' variable. ------------------------------------------------------------------------ r306 | ajapted | 2009-10-31 Eureka: worked on a system (in the Basis) of remembering various types of changes, so that various widgets (e.g. the canvas) can be updated with new information automatically. ------------------------------------------------------------------------ r305 | ajapted | 2009-10-31 Eureka: can now turn and move up/down in the 3D preview with the mouse (RMB). ------------------------------------------------------------------------ r304 | ajapted | 2009-10-31 Eureka: UI_Nombre: improved the format (e.g. use '#' before the number). ------------------------------------------------------------------------ r303 | ajapted | 2009-10-31 Eureka: disabled the thing 'ExFloor' widget for now (punted feature). ------------------------------------------------------------------------ r302 | ajapted | 2009-10-31 Eureka: made '0' key be centre-and-zoom-out function, and disabled the plain centre-map feature (on '`' key) as it seems not very useful. ------------------------------------------------------------------------ r301 | ajapted | 2009-10-31 Eureka: implemented ability to scroll the map with the mouse (RMB). ------------------------------------------------------------------------ r300 | ajapted | 2009-10-30 Eureka: fixed X-Offsets when splitting linedefs. ------------------------------------------------------------------------ r299 | ajapted | 2009-10-30 Eureka: re-implemented 'x' command to Split linedefs. ------------------------------------------------------------------------ r298 | ajapted | 2009-10-30 todo / docco update. ------------------------------------------------------------------------ r297 | ajapted | 2009-10-30 Eureka: the code trying to "fix" bad quantization didn't work and was very inadequate. Disabled for now, until better algorithms can be employed. ------------------------------------------------------------------------ r296 | ajapted | 2009-10-30 Eureka: worked on command to Quantize objects to the grid. ------------------------------------------------------------------------ r295 | ajapted | 2009-10-30 Eureka: added grid::ForceSnapX/Y methods. ------------------------------------------------------------------------ r294 | ajapted | 2009-10-30 Eureka: for 2x scaling, use the bottom left corner of the bbox as the scaling origin, which is better at preserving grid snappage. ------------------------------------------------------------------------ r293 | ajapted | 2009-10-30 Eureka: implemented CMD_ScaleObjects() for 2x and 1/2 scaling. ------------------------------------------------------------------------ r292 | ajapted | 2009-10-30 Eureka: dead code removal (old flip_mirror stuff). ------------------------------------------------------------------------ r291 | ajapted | 2009-10-30 Eureka: implemented the Rotate-by-90-degrees commands. ------------------------------------------------------------------------ r290 | ajapted | 2009-10-30 Eureka: changed mirror keys to 'H' and 'I'. ------------------------------------------------------------------------ r289 | ajapted | 2009-10-30 Eureka: implemented Mirror command (horizontal and vertical). ------------------------------------------------------------------------ r288 | ajapted | 2009-10-30 Eureka: began work on commands to Mirror and Rotate90 objects. ------------------------------------------------------------------------ r287 | ajapted | 2009-10-30 Eureka: improved bbox_of_objects() to use the known radius of things. ------------------------------------------------------------------------ r286 | ajapted | 2009-10-30 Eureka: implemented new bbox_of_objects() function. ------------------------------------------------------------------------ r285 | ajapted | 2009-10-30 Eureka: re-implemented the centre_of_objects() function. ------------------------------------------------------------------------ r284 | ajapted | 2009-10-30 todo stuff. ------------------------------------------------------------------------ r283 | ajapted | 2009-10-30 commenting. ------------------------------------------------------------------------ r282 | ajapted | 2009-10-30 Eureka: implemented re-selected new objects after a Paste. ------------------------------------------------------------------------ r281 | ajapted | 2009-10-30 Eureka: added frob_range() method to selection_c class. ------------------------------------------------------------------------ r280 | ajapted | 2009-10-29 todo twiddle. ------------------------------------------------------------------------ r279 | ajapted | 2009-10-29 Eureka: began creating a list of keyboard commands. ------------------------------------------------------------------------ r278 | ajapted | 2009-10-29 todo twiddle. ------------------------------------------------------------------------ r277 | ajapted | 2009-10-29 debugging tidying. ------------------------------------------------------------------------ r276 | ajapted | 2009-10-29 Eureka: when dragging Sectors, drag their containing Things too. ------------------------------------------------------------------------ r275 | ajapted | 2009-10-29 Eureka: Dragging: actually move the objects after the drag. ------------------------------------------------------------------------ r274 | ajapted | 2009-10-29 Eureka: disable texture listbox for time being. ------------------------------------------------------------------------ r273 | ajapted | 2009-10-29 Eureka: worked on Dragging objects to new places. ------------------------------------------------------------------------ r272 | ajapted | 2009-10-29 Eureka: use 'obj_type_t' instead of 'int' for GetCurObject() parameter. ------------------------------------------------------------------------ r271 | ajapted | 2009-10-29 Eureka: use '0' key instead of '`' for zoom-and-centre-map function. ------------------------------------------------------------------------ r270 | ajapted | 2009-10-29 Eureka: removed unused variable: rulers. ------------------------------------------------------------------------ r269 | ajapted | 2009-10-29 Eureka: restored spin-thing keys to 'w' and 'x'. ------------------------------------------------------------------------ r268 | ajapted | 2009-10-29 Eureka: made clipboard handle sector Insertions like it handles deletions, allowing the copied objects to survive longer (e.g. after undo). ------------------------------------------------------------------------ r267 | ajapted | 2009-10-29 Eureka: improved the way the clipboard reacts to Sector insertions and deletions. In particular, the clipboard can be preserved after a sector is deleted (by adjusting the references). ------------------------------------------------------------------------ r266 | ajapted | 2009-10-29 Eureka: fixed thing positions when Pasting a copied sector. ------------------------------------------------------------------------ r265 | ajapted | 2009-10-29 debugging tweak. ------------------------------------------------------------------------ r264 | ajapted | 2009-10-29 Eureka: implemented Paste for linedefs and sectors (which involves creating associated objects like vertices and sidedefs, and updating the references). ------------------------------------------------------------------------ r263 | ajapted | 2009-10-29 Eureka: further work on Cut'n'Paste code... ------------------------------------------------------------------------ r262 | ajapted | 2009-10-29 Eureka: implemented logic for Copying a group of linedefs or sectors (and all associated objects) into the clipboard. ------------------------------------------------------------------------ r261 | ajapted | 2009-10-29 Eureka: Basis: no need to invalidate the clipboard when inserting new Sectors at the very end of the array. ------------------------------------------------------------------------ r260 | ajapted | 2009-10-29 Eureka: support for Cut/Paste of vertices and RTS triggers. ------------------------------------------------------------------------ r259 | ajapted | 2009-10-29 Eureka: fixed pasting Things to move them to their new position (and when multiple things are in the clipboard, find their centre). ------------------------------------------------------------------------ r258 | ajapted | 2009-10-29 Eureka: better handling of CTRL + letter keys. ------------------------------------------------------------------------ r257 | ajapted | 2009-10-29 Eureka: rewrote 'o' key command to use CMD_Copy + CMD_Paste. ------------------------------------------------------------------------ r256 | ajapted | 2009-10-29 Eureka: Basis: added RawCopy() methods to each class (Thing, Vertex etc). ------------------------------------------------------------------------ r255 | ajapted | 2009-10-29 Eureka: implemented CMD_Copy and CMD_Paste for THINGS. ------------------------------------------------------------------------ r254 | ajapted | 2009-10-29 Eureka: Basis: notify clipboard when sectors are deleted or inserted. ------------------------------------------------------------------------ r253 | ajapted | 2009-10-29 Eureka: fixed bugs in CMD_FullDelete(). ------------------------------------------------------------------------ r252 | ajapted | 2009-10-29 Eureka: mainly commenting (new Cut'n'Paste code). ------------------------------------------------------------------------ r251 | ajapted | 2009-10-29 Eureka: moved CMD_Delete() code into e_cutpaste.cc file, and implemented the CMD_FullDelete() which deletes things in sector mode. ------------------------------------------------------------------------ r250 | ajapted | 2009-10-28 Eureka: made ConvertSelection() into a general purpose function which converts from one selection_c to another. ------------------------------------------------------------------------ r249 | ajapted | 2009-10-28 Eureka: BA_ClearAll() now clears the Clipboard too. ------------------------------------------------------------------------ r248 | ajapted | 2009-10-28 Eureka: preliminary clipboard_data_c class. ------------------------------------------------------------------------ r247 | ajapted | 2009-10-28 Eureka: updated menu code to use new Cut'n'Paste API. ------------------------------------------------------------------------ r246 | ajapted | 2009-10-28 update ------------------------------------------------------------------------ r245 | ajapted | 2009-10-28 Eureka: began work on Cut 'n' Paste functionality. ------------------------------------------------------------------------ r244 | ajapted | 2009-10-28 Eureka: properly handle mouse leaving the canvas area (e.g. unset the currently highlighted object). ------------------------------------------------------------------------ r243 | ajapted | 2009-10-28 Eureka: force custom FLTK color scheme (default with Xfce looked pretty bad). ------------------------------------------------------------------------ r242 | ajapted | 2009-10-28 Eureka: fixed some warnings from GCC 4.3 ------------------------------------------------------------------------ r241 | ajapted | 2009-10-26 Eureka: bit of work on SuperSectorSelector() code. ------------------------------------------------------------------------ r240 | ajapted | 2009-10-25 Eureka: changed default thing type to 2014 (from 3004). ------------------------------------------------------------------------ r239 | ajapted | 2009-10-25 Eureka: ability to Insert new things. ------------------------------------------------------------------------ r238 | ajapted | 2009-10-25 Eureka: for selection_c::clear() method, added unused but potentially useful "slow" version which maintains the order of selections. ------------------------------------------------------------------------ r237 | ajapted | 2009-10-25 Eureka: ability to insert new vertices. ------------------------------------------------------------------------ r236 | ajapted | 2009-10-25 Eureka: don't push empty undo_group_cs onto the undo stack. ------------------------------------------------------------------------ r235 | ajapted | 2009-10-25 Eureka: began work on ability to insert new objects. ------------------------------------------------------------------------ r234 | ajapted | 2009-10-25 Eureka: small fix. ------------------------------------------------------------------------ r233 | ajapted | 2009-10-25 Eureka: implemented trickiest selection conversions: L->S and V->S. ------------------------------------------------------------------------ r232 | ajapted | 2009-10-25 Eureka: implemented V->L selection conversion. ------------------------------------------------------------------------ r231 | ajapted | 2009-10-25 Eureka: implemented S->L, S->V and L->V selection conversions. ------------------------------------------------------------------------ r230 | ajapted | 2009-10-25 Eureka: moved ConvertSelection() from editloop.cc --> selectn.cc ------------------------------------------------------------------------ r229 | ajapted | 2009-10-25 TODO update ------------------------------------------------------------------------ r228 | ajapted | 2009-10-25 Eureka: implemented selection conversion when going from sector mode to things mode. Made the SPACE key unselect everything. ------------------------------------------------------------------------ r227 | ajapted | 2009-10-25 Eureka: fixed BA_Delete() handling of bound objects, it was sufficient to simply delete them before the main object. Also changed sidedef deletion behavior to delete the _linedef_ if it would end up with no sides at all. ------------------------------------------------------------------------ r226 | ajapted | 2009-10-25 Eureka: changed color of "error" linedefs to bright red (from pink). ------------------------------------------------------------------------ r225 | ajapted | 2009-10-25 Eureka: fixed bug in RawInsertLineDef() -- assertion checked wrong value. ------------------------------------------------------------------------ r224 | ajapted | 2009-10-25 Eureka: fixed BA_Delete() which was trying to delete the wrong bound objects (they needed to be collected before applying the deletion). ------------------------------------------------------------------------ r223 | ajapted | 2009-10-25 Eureka: fix highlighted (Panel'd) object after deletion. ------------------------------------------------------------------------ r222 | ajapted | 2009-10-25 Eureka: move the DeleteFinally() stuff out of the edit_op_c destructor and into a 'Destroy' method which gets called explicitly by the undo_group destructor. This fixes serious problems caused by the destructor being called on temporaries of edit_op_c objects. ------------------------------------------------------------------------ r221 | ajapted | 2009-10-25 Eureka: reimplemented deletion of objects. ------------------------------------------------------------------------ r220 | ajapted | 2009-10-25 TODO tweak ------------------------------------------------------------------------ r219 | ajapted | 2009-10-25 Eureka: disable optimisations for time being (as a debugging aide). ------------------------------------------------------------------------ r218 | ajapted | 2009-10-25 Eureka: fixed problem in Undo/Redo code (clearing the history/future arrays) that lead to assertion failures in subsequent operations. ------------------------------------------------------------------------ r217 | ajapted | 2009-10-25 Eureka: disabled some uncompilable code. ------------------------------------------------------------------------ r216 | ajapted | 2009-10-25 Eureka: TODO twiddles. ------------------------------------------------------------------------ r213 | ajapted | 2009-10-25 Moved 'eureka' folder to top level (out of tools/) ------------------------------------------------------------------------ r212 | ajapted | 2009-10-13 Eureka: version bump. ------------------------------------------------------------------------ r211 | ajapted | 2009-10-13 TODO update. ------------------------------------------------------------------------ r210 | ajapted | 2009-10-13 Eureka: fixed changing mode via the button on the Info Bar. ------------------------------------------------------------------------ r209 | ajapted | 2009-10-13 Eureka: fixed issues with initial editing mode. ------------------------------------------------------------------------ r208 | ajapted | 2009-10-13 Eureka: tweaked deltas for raising/lowering floors and ceilings. ------------------------------------------------------------------------ r207 | ajapted | 2009-10-13 Eureka: implemented typing in texture names in the SideDef panels. ------------------------------------------------------------------------ r206 | ajapted | 2009-10-13 Eureka: implemented x_offset/y_offset input boxes in SideDef panel. ------------------------------------------------------------------------ r205 | ajapted | 2009-10-13 updated TODO ------------------------------------------------------------------------ r204 | ajapted | 2009-10-13 Eureka: implemented sector input box for the SideDef Panel. ------------------------------------------------------------------------ r203 | ajapted | 2009-10-13 Eureka: updated UI_SideBox::TexFromWidget() to internalise the string. ------------------------------------------------------------------------ r202 | ajapted | 2009-10-13 Eureka: got the automap flags in the LineDef panel working. ------------------------------------------------------------------------ r201 | ajapted | 2009-10-13 Eureka: implemented ability in LineDef Panel to change type, tag and most of the flags -- supporting multiple linedefs too. ------------------------------------------------------------------------ r200 | ajapted | 2009-10-13 Eureka: ui_thing.cc: renamed opt_callback_data_c --> thing_opt_CB_data_c ------------------------------------------------------------------------ r199 | ajapted | 2009-10-13 Dead code removal. ------------------------------------------------------------------------ r198 | ajapted | 2009-10-13 tweaks ------------------------------------------------------------------------ r197 | ajapted | 2009-10-13 Eureka: small fixes: made FlatFromWidget() uppercase the name, and fixed GetCurrentObjects() to set the correct object type on the selection_c. ------------------------------------------------------------------------ r196 | ajapted | 2009-10-13 Eureka: implemented typing in texture names in the Sector panel. ------------------------------------------------------------------------ r195 | ajapted | 2009-10-13 Eureka: implemented the 'Type' and 'Tag' input boxes in the Sector panel. ------------------------------------------------------------------------ r194 | ajapted | 2009-10-13 minor fix ------------------------------------------------------------------------ r193 | ajapted | 2009-10-13 Eureka: implemented typing a value into light input box in Sector panel. ------------------------------------------------------------------------ r192 | ajapted | 2009-10-13 Eureka: implemented the light up/down buttons in the Sector panel, via new CMD_AdjustLight() function in e_sector.cc ------------------------------------------------------------------------ r191 | ajapted | 2009-10-13 Eureka: moved CMD_MoveFloors() and CMD_MoveCeilings() into e_sector.cc ------------------------------------------------------------------------ r190 | ajapted | 2009-10-13 Eureka: renamed 'spin_things' function --> 'CMD_SpinThings', and moved some of the logic there (GetCurrentObjects etc), simplifying other code. ------------------------------------------------------------------------ r189 | ajapted | 2009-10-13 Eureka: worked on keys and buttons to move sector floors/ceilings, via new CMD_MoveFloors() and CMD_MoveCeilings() functions. ------------------------------------------------------------------------ r188 | ajapted | 2009-10-13 Eureka: reimplemented the floor_h, ceil_h and headroom input boxes in the Sector Panel (support multiple selected sectors). ------------------------------------------------------------------------ r187 | ajapted | 2009-10-13 fixed small bug ------------------------------------------------------------------------ r186 | ajapted | 2009-10-13 Eureka: fixed CLAMP() macro. ------------------------------------------------------------------------ r185 | ajapted | 2009-10-13 Eureka: reimplemented editing X and Y values in Vertex Panel. ------------------------------------------------------------------------ r184 | ajapted | 2009-10-13 Eureka: Thing Panel: fixed the 'type' input callback (handle multiple things). ------------------------------------------------------------------------ r183 | ajapted | 2009-10-13 Eureka: Thing Panel: separated 'pos_callback' into X and Y versions, so that multiple selected things can work properly. ------------------------------------------------------------------------ r182 | ajapted | 2009-10-13 Eureka: Think Panel: reimplemented option_callback, pass a new structure as the 'data' parameter which contains the needed UI_ThingBox pointer. Also fixed a bug (used F_ANGLE instead of F_OPTIONS). ------------------------------------------------------------------------ r181 | ajapted | 2009-10-13 Eureka: Thing Panel: implemented value propagation for X and Y edits. Changed option_callback() method making the 'data' field a mask value, allowing multiple things to be handled but only the apropos bits are actually changed. ------------------------------------------------------------------------ r180 | ajapted | 2009-10-13 tweak. ------------------------------------------------------------------------ r179 | ajapted | 2009-10-13 Eureka: for angle input in Thing panel, implemented propagating the new value to every thing in the current selection. Simplified handling of the < and > rotation buttons. ------------------------------------------------------------------------ r178 | ajapted | 2009-10-13 Eureka: implemented UI_LineBox::UpdateField() method. ------------------------------------------------------------------------ r177 | ajapted | 2009-10-13 Eureka: implemented UpdateField() method for UI_VertexBox and UI_SectorBox. ------------------------------------------------------------------------ r176 | ajapted | 2009-10-13 Eureka: disabled the KF auto-upsizing stuff for now. ------------------------------------------------------------------------ r175 | ajapted | 2009-10-13 Eureka: update Thing UI panel after spin_things. ------------------------------------------------------------------------ r174 | ajapted | 2009-10-13 Eureka: Thing info widget: added UpdateField() method for when a field is changed externally. Removed some dead code. ------------------------------------------------------------------------ r173 | ajapted | 2009-10-13 Eureka: restored keys for spin_things. ------------------------------------------------------------------------ r172 | ajapted | 2009-10-13 Fixed a few warnings. ------------------------------------------------------------------------ r171 | ajapted | 2009-10-13 Eureka: changed keys to spin things to '[' and ']'. Added a function GetCurrentObjects(), and simplified some code using it. ------------------------------------------------------------------------ r170 | ajapted | 2009-10-13 Eureka: improved handling of the current highlighted object and the current selection (for the UI panel). ------------------------------------------------------------------------ r169 | ajapted | 2009-10-13 Eureka: UI_Canvas: renamed some confusing method names: HighlightObject() --> DrawHighlight() HighlightSelection() --> DrawSelection() ------------------------------------------------------------------------ r168 | ajapted | 2009-10-13 Eureka: fixed UI_Nombre::Update() logic. ------------------------------------------------------------------------ r167 | ajapted | 2009-10-13 Eureka: the UI panel should now show how many objects are selected, with a red background to warn that multiple objects may get changed when editing the values in the panel. ------------------------------------------------------------------------ r166 | ajapted | 2009-10-13 Eureka: added 'slow_count' method to selection_c class. ------------------------------------------------------------------------ r165 | ajapted | 2009-10-13 Eureka: updated UI_Nombre widget to support selections. ------------------------------------------------------------------------ r164 | ajapted | 2009-10-12 Eureka: allow 3D renderer to receive mousewheel events. ------------------------------------------------------------------------ r163 | ajapted | 2009-10-12 Eureka: version bump. ------------------------------------------------------------------------ r162 | ajapted | 2009-10-12 Eureka: TODO update. ------------------------------------------------------------------------ r161 | ajapted | 2009-10-12 Eureka: implemented SelectObjectsInBox() for SECTORS. ------------------------------------------------------------------------ r160 | ajapted | 2009-10-12 Eureka: fixed SelectObjectsInBox() for THINGS, LINEDEFS and VERTICES. ------------------------------------------------------------------------ r159 | ajapted | 2009-10-12 Eureka: fixed key handling so that Ctrl-Z (and other menu shortcuts) work. ------------------------------------------------------------------------ r158 | ajapted | 2009-10-12 Eureka: updated TODO, removed old crud. ------------------------------------------------------------------------ r157 | ajapted | 2009-10-12 Eureka: fixed editing of Thing angles in the UI panel. ------------------------------------------------------------------------ r156 | ajapted | 2009-10-12 Eureka: fixed Undo/Redo to redraw map. ------------------------------------------------------------------------ r155 | ajapted | 2009-10-12 tweak ------------------------------------------------------------------------ r154 | ajapted | 2009-10-12 Eureka: replaced 'MadeChanges = 1' with call to MarkChanges(), and replaced 'MadeMapChanges = 1' with MarkChanges(2) function call. This new function remembers to redraw the map too. ------------------------------------------------------------------------ r153 | ajapted | 2009-10-12 Renamed file: AJA_TODO.txt --> TODO.txt ------------------------------------------------------------------------ r152 | ajapted | 2009-10-12 Eureka: implemented 'spin_things' functionality using the BASIS system. ------------------------------------------------------------------------ r151 | ajapted | 2009-10-12 Eureka: implemented menu commands: 'Save', 'Undo' and 'Redo'. ------------------------------------------------------------------------ r150 | ajapted | 2009-10-12 Eureka: dead code removal. ------------------------------------------------------------------------ r149 | ajapted | 2009-10-12 Eureka: fixed bug in saving code (wrong number of linedefs). ------------------------------------------------------------------------ r148 | ajapted | 2009-10-12 Eureka: fixed Wad_file::RemoveLevel() for GL-Nodes, it should remove the "GL_XXX" lumps after the normal level lumps too. ------------------------------------------------------------------------ r147 | ajapted | 2009-10-12 Eureka: load the specified PWADs. ------------------------------------------------------------------------ r4 | ajapted | 2009-09-07 Checked in sources to my 'Eureka DOOM Editor' program. For a while this was developed in EDGE's SVN repository on SourceForge. Before that is was just developed on my hard drive. Eureka is a fork of the Yadex editor (version 1.7.0). ==================================================== DEVELOPMENT IN EDGE REPOSITORY ==================================================== ------------------------------------------------------------------------ r5940 | ajapted | 2009-09-27 14:53:16 Removed eureka code from EDGE's SVN repository. The code has moved to AwwPort's BZR repository. ------------------------------------------------------------------------ r5919 | ajapted | 2009-08-10 16:23:40 Eureka: temporary disable spin_things(). ------------------------------------------------------------------------ r5811 | ajapted | 2009-08-04 14:33:57 Eureka: tweaked Scale choices on the infobar. ------------------------------------------------------------------------ r5810 | ajapted | 2009-08-04 14:28:40 Eureka: fixed privacy of fields in Lump_c and Wad_file classes. ------------------------------------------------------------------------ r5809 | ajapted | 2009-08-03 23:07:55 Tweak. ------------------------------------------------------------------------ r5808 | ajapted | 2009-08-03 22:58:48 Eureka: removed Wad_name class (w_name.h) ------------------------------------------------------------------------ r5807 | ajapted | 2009-08-03 22:39:28 Eureka: dead code removal. ------------------------------------------------------------------------ r5806 | ajapted | 2009-08-03 22:19:51 Eureka: removed the old wad handling code files: w_wads.cc/h w_io.cc/h w_file.cc/h ------------------------------------------------------------------------ r5805 | ajapted | 2009-08-03 22:01:41 Eureka: yet more dead code removed. ------------------------------------------------------------------------ r5804 | ajapted | 2009-08-03 21:20:37 Eureka: removed old patch_dir code. ------------------------------------------------------------------------ r5803 | ajapted | 2009-08-03 20:38:32 Eureka: dead code removal. ------------------------------------------------------------------------ r5802 | ajapted | 2009-08-03 20:25:44 Tweaks. ------------------------------------------------------------------------ r5801 | ajapted | 2009-08-03 20:24:44 Eureka: enabled new texture loading code. ------------------------------------------------------------------------ r5800 | ajapted | 2009-08-03 19:19:13 Eureka: further work on texture loader... ------------------------------------------------------------------------ r5799 | ajapted | 2009-08-03 19:04:15 Eureka: initial work on new texture loading code... ------------------------------------------------------------------------ r5798 | ajapted | 2009-08-03 17:34:03 Eureka: sprite loader updated to use new LoadPicture() code. ------------------------------------------------------------------------ r5797 | ajapted | 2009-08-03 17:17:40 Eureka: new Wad_file function W_FindSpriteLump() which only checks the valid sprites (S_START..S_END), and similarly W_FindPatchLump() for patches. ------------------------------------------------------------------------ r5796 | ajapted | 2009-08-03 16:44:28 Eureka: worked on new LoadPicture() implementation. ------------------------------------------------------------------------ r5795 | ajapted | 2009-08-03 16:26:06 Eureka: added WAD utility function to load a lump into memory. ------------------------------------------------------------------------ r5794 | ajapted | 2009-08-03 14:44:47 Eureka: began work on a new LoadPicture() implementation. ------------------------------------------------------------------------ r5793 | ajapted | 2009-08-03 14:31:38 Eureka: renamed IMG_TRANSP --> TRANS_PIXEL. ------------------------------------------------------------------------ r5792 | ajapted | 2009-08-03 11:22:03 Eureka: updated W_LoadPalette() to use new Wad_file code. ------------------------------------------------------------------------ r5791 | ajapted | 2009-08-03 11:13:20 Eureka: new flat loading code (W_LoadFlats), replaces old stuff. ------------------------------------------------------------------------ r5790 | ajapted | 2009-08-03 10:18:21 Eureka: dead code removal. ------------------------------------------------------------------------ r5789 | ajapted | 2009-08-03 10:09:34 Eureka: replaced calls to 'get_thing_xxx' with new M_GetThingType(). ------------------------------------------------------------------------ r5788 | ajapted | 2009-08-03 09:55:21 Eureka: added 'color' field to thingtype_t (copied from thinggroup). ------------------------------------------------------------------------ r5787 | ajapted | 2009-08-03 09:46:35 Eureka: worked on using std::map for the game def containters (sector_types, line_types, thing_types etc). ------------------------------------------------------------------------ r5786 | ajapted | 2009-08-02 23:47:30 Tweaks. ------------------------------------------------------------------------ r5785 | ajapted | 2009-08-02 23:35:40 Eureka: reworked code which loads the game palette. ------------------------------------------------------------------------ r5784 | ajapted | 2009-08-02 22:52:11 Tweak. ------------------------------------------------------------------------ r5783 | ajapted | 2009-08-02 22:30:52 Eureka: finished new line descriptions for doom2 game def. ------------------------------------------------------------------------ r5782 | ajapted | 2009-08-02 22:11:55 Eureka: yet more line description improvements (doom2 game def). ------------------------------------------------------------------------ r5781 | ajapted | 2009-08-02 21:24:08 Eureka: further work on line descriptions in doom2 game def. ------------------------------------------------------------------------ r5780 | ajapted | 2009-08-02 20:44:25 Eureka: more work on line descriptions in doom2 game definition. ------------------------------------------------------------------------ r5779 | ajapted | 2009-08-02 20:12:16 Eureka: game definition file: for 'thing' commands, moved the sprite name to occur before the description (instead of after it). More work on updating 'line' commands for a single description. ------------------------------------------------------------------------ r5778 | ajapted | 2009-08-02 19:38:05 Eureka: game definitions: began work to make linetype commands only have a single description (instead of short and long). ------------------------------------------------------------------------ r5777 | ajapted | 2009-08-02 19:20:11 Eureka: game definitions: made 'sector' command only have a single description (instead of short and long). ------------------------------------------------------------------------ r5776 | ajapted | 2009-08-02 19:16:40 Eureka: removed acolour_t. ------------------------------------------------------------------------ r5775 | ajapted | 2009-08-02 18:56:31 Eureka: worked on game definition (.ugh) code, renamed some of the commands e.g. ldt --> line and st --> sector, and moved a couple functions into m_game.cc. ------------------------------------------------------------------------ r5774 | ajapted | 2009-08-02 18:12:54 Eureka: dead code removal. ------------------------------------------------------------------------ r5773 | ajapted | 2009-08-02 17:17:33 Eureka: small fixes. ------------------------------------------------------------------------ r5772 | ajapted | 2009-08-02 17:13:35 Eureka: prelim rework of w_texture code (split now complete). ------------------------------------------------------------------------ r5771 | ajapted | 2009-08-02 17:06:13 Eureka: prelim rework of w_sprite.cc code. ------------------------------------------------------------------------ r5770 | ajapted | 2009-08-02 16:59:19 Eureka: preliminary rework of w_flats code. ------------------------------------------------------------------------ r5769 | ajapted | 2009-08-02 16:49:38 Eureka: continued splitting r_images.cc into three files. ------------------------------------------------------------------------ r5768 | ajapted | 2009-08-02 16:48:15 Eureka: began splitting r_image.cc into three (Textures, Flats and Sprites). ------------------------------------------------------------------------ r5767 | ajapted | 2009-08-02 16:45:33 Eureka: dead code removal. ------------------------------------------------------------------------ r5766 | ajapted | 2009-08-02 15:09:30 Eureka: merged w_sprites.cc code into r_images.cc ------------------------------------------------------------------------ r5765 | ajapted | 2009-08-02 14:42:40 Eureka: misc tidying. ------------------------------------------------------------------------ r5764 | ajapted | 2009-08-02 14:27:02 Small fix. ------------------------------------------------------------------------ r5763 | ajapted | 2009-08-02 14:14:06 Eureka: improved canvas drawing, keep the map bbox in member fields (instead of computing it at multiple places), and use a Vis() method for checking if an item would be visible. ------------------------------------------------------------------------ r5762 | ajapted | 2009-08-02 13:28:49 Eureka: reformatted r_grid.h and removed two unused fields. ------------------------------------------------------------------------ r5761 | ajapted | 2009-08-02 13:21:31 Eureka: small fixes. ------------------------------------------------------------------------ r5760 | ajapted | 2009-08-02 12:50:07 Eureka: added constructors to the basis structures (Thing, LineDef etc). ------------------------------------------------------------------------ r5759 | ajapted | 2009-08-02 12:42:56 Eureka: new FreshLevel() function to create a very basic level. ------------------------------------------------------------------------ r5758 | ajapted | 2009-08-02 12:27:37 Eureka: new level load/save code is mostly done. ------------------------------------------------------------------------ r5757 | ajapted | 2009-08-01 15:50:29 Eureka: Wad_file: changed FindLevel() to return a lump index (instead of a level number), which affects the parameter to FindLumpInLevel() and RemoveLevel() as well. Various code tidying. ------------------------------------------------------------------------ r5756 | ajapted | 2009-08-01 11:56:59 Eureka: implemented remaining functionality of Wad_file class. ------------------------------------------------------------------------ r5755 | ajapted | 2009-07-31 22:46:50 Eureka: more Wad_file goodness... ------------------------------------------------------------------------ r5754 | ajapted | 2009-07-31 22:18:34 Eureka: further work on WAD Writing implementation. Fixed the fopen mode string in Open() to "r+b", and in Create() to "w+b". ------------------------------------------------------------------------ r5753 | ajapted | 2009-07-31 19:25:14 Eureka: tweaked the menu. ------------------------------------------------------------------------ r5752 | ajapted | 2009-07-31 19:17:59 Eureka: partial work on fleshing out the Wad_file "Write interface". ------------------------------------------------------------------------ r5751 | ajapted | 2009-07-31 15:48:29 Eureka: created the "Write interface" for new Wad_file class. ------------------------------------------------------------------------ r5750 | ajapted | 2009-07-31 15:37:00 Eureka: fleshed out most of the new SaveLevel() code. ------------------------------------------------------------------------ r5749 | ajapted | 2009-07-30 23:06:51 Eureka: added skeletal SaveLevel() code. ------------------------------------------------------------------------ r5748 | ajapted | 2009-07-30 22:10:50 Eureka: wrote Wad_file::WasExternallyModified() method. ------------------------------------------------------------------------ r5747 | ajapted | 2009-07-30 21:45:53 Eureka: fixed Wad_file::Create() to set 'total_size' field. ------------------------------------------------------------------------ r5746 | ajapted | 2009-07-30 21:44:28 Eureka: determine total size of WAD when opening it. ------------------------------------------------------------------------ r5745 | ajapted | 2009-07-30 20:48:13 Eureka: dead code removal. ------------------------------------------------------------------------ r5744 | ajapted | 2009-07-30 20:47:25 Eureka: implemented Wad_file::ProcessNamespaces(), which handles the S_START/S_END, P_START/P_END, F_START/F_END groups. ------------------------------------------------------------------------ r5743 | ajapted | 2009-07-30 19:53:38 Eureka: version bump, in honor of new WAD reading code. ------------------------------------------------------------------------ r5742 | ajapted | 2009-07-30 19:51:23 Eureka: implemented Wad_file::DetectLevels(). ------------------------------------------------------------------------ r5741 | ajapted | 2009-07-30 19:25:37 Tweak. ------------------------------------------------------------------------ r5740 | ajapted | 2009-07-30 17:41:35 Eureka: preliminary implementation of Wad_file::ReadDirectory(). ------------------------------------------------------------------------ r5739 | ajapted | 2009-07-30 16:51:59 Eureka: reworked LoadLevel() to use new Wad_file class. ------------------------------------------------------------------------ r5738 | ajapted | 2009-07-30 16:51:02 Eureka: mere reformatting. ------------------------------------------------------------------------ r5737 | ajapted | 2009-07-30 16:43:47 Eureka: added w_wad.o to the build, with minor fixes. ------------------------------------------------------------------------ r5736 | ajapted | 2009-07-30 16:42:37 Eureka: temp workaround for old Wad_file class clashing with new one. ------------------------------------------------------------------------ r5735 | ajapted | 2009-07-30 16:25:09 Eureka: new Wad_file class is coming along. ------------------------------------------------------------------------ r5734 | ajapted | 2009-07-30 15:57:08 Eureka: further work on new Wad_file class. ------------------------------------------------------------------------ r5732 | ajapted | 2009-07-30 14:52:33 Eureka: implemented RemoveUnusedVertices() for level loading. ------------------------------------------------------------------------ r5731 | ajapted | 2009-07-30 14:09:29 Eureka: #include math.h by default (via main.h). ------------------------------------------------------------------------ r5730 | ajapted | 2009-07-30 13:57:38 Eureka: bit more work on new Wad_file class. ------------------------------------------------------------------------ r5729 | ajapted | 2009-07-30 13:41:47 Eureka: added Adler-32 CRC code. ------------------------------------------------------------------------ r5728 | ajapted | 2009-07-30 13:36:27 Eureka: check-in of skeletal new Wad_file class. ------------------------------------------------------------------------ r5727 | ajapted | 2009-07-30 12:26:35 Eureka: more miscellaneous tidying. ------------------------------------------------------------------------ r5726 | ajapted | 2009-07-30 12:02:11 Eureka: replaced nf_bug() with BugError(). ------------------------------------------------------------------------ r5725 | ajapted | 2009-07-30 11:55:25 Eureka: removed sys_assert.cc/h. Began tidying the error/log stuff. ------------------------------------------------------------------------ r5724 | ajapted | 2009-07-29 23:35:22 Eureka: removed xref stuff (pretty useless). ------------------------------------------------------------------------ r5723 | ajapted | 2009-07-29 23:33:26 Eureka: moved some prototypes out of main.h ------------------------------------------------------------------------ r5722 | ajapted | 2009-07-29 23:17:29 Eureka: dead code removal. ------------------------------------------------------------------------ r5721 | ajapted | 2009-07-29 22:55:54 Eureka: more tidying / dead code removal. ------------------------------------------------------------------------ r5720 | ajapted | 2009-07-29 22:19:58 Eureka: fixed clashing definitions between w_rawdef.h and w_structs.h and removed some typedefs. ------------------------------------------------------------------------ r5719 | ajapted | 2009-07-29 22:17:17 Eureka: Dead code removal. ------------------------------------------------------------------------ r5718 | ajapted | 2009-07-29 21:56:54 Eureka: fixed side-panel display of sector flats, sidedef textures. ------------------------------------------------------------------------ r5716 | ajapted | 2009-07-29 18:04:00 Eureka: dead code removal. ------------------------------------------------------------------------ r5715 | ajapted | 2009-07-29 16:33:54 Eureka: renamed file: e_load.cc --> e_loadsave.cc ------------------------------------------------------------------------ r5714 | ajapted | 2009-07-29 16:24:15 Eureka: renamed QF --> KF and QF_F --> KF_fonth. ------------------------------------------------------------------------ r5713 | ajapted | 2009-07-29 16:22:59 Eureka: fiddled with menu. ------------------------------------------------------------------------ r5712 | ajapted | 2009-07-29 15:13:17 Eureka: few more fixes to get compiling and running again. ------------------------------------------------------------------------ r5711 | ajapted | 2009-07-29 15:04:25 Eureka: fleshed out new LoadLevel() function, and removed the old crud. ------------------------------------------------------------------------ r5710 | ajapted | 2009-07-29 14:55:38 Eureka: fleshed out LoadThings(), LoadSideDefs() and LoadLineDefs(). ------------------------------------------------------------------------ r5709 | ajapted | 2009-07-29 14:38:05 Eureka: yet more sticky-tape and bubble-gum workarounds... ------------------------------------------------------------------------ r5708 | ajapted | 2009-07-29 13:17:25 Eureka: added LineDef::TouchesSector() method. ------------------------------------------------------------------------ r5707 | ajapted | 2009-07-29 01:10:51 Eureka: more bubble gum patching just to get something to compile. ------------------------------------------------------------------------ r5706 | ajapted | 2009-07-29 00:51:38 Eureka: fleshed out sector loading: LoadSectors(). ------------------------------------------------------------------------ r5705 | ajapted | 2009-07-29 00:48:09 Eureka: added convenience func: BA_InternaliseShortStr(). ------------------------------------------------------------------------ r5704 | ajapted | 2009-07-29 00:09:27 Eureka: began work on new level loading code : e_load.cc ------------------------------------------------------------------------ r5703 | ajapted | 2009-07-29 00:08:32 Eureka: sticky-tape for editloop.cc ------------------------------------------------------------------------ r5702 | ajapted | 2009-07-28 23:04:51 Eureka: wrote a little Features / Requirements doc. ------------------------------------------------------------------------ r5701 | ajapted | 2009-07-28 22:58:06 Eureka: more sticky-tape and bubble-gum to get it compiling again. ------------------------------------------------------------------------ r5700 | ajapted | 2009-07-28 22:51:33 Eureka: fixes for r_images.cc ------------------------------------------------------------------------ r5699 | ajapted | 2009-07-28 22:47:36 Eureka: updated 3D render code for the Basis. ------------------------------------------------------------------------ r5698 | ajapted | 2009-07-28 22:45:19 Eureka: added e_basis.o to the build. ------------------------------------------------------------------------ r5697 | ajapted | 2009-07-28 22:29:31 Eureka: prelim work updating UI widgets for the Basis. ------------------------------------------------------------------------ r5696 | ajapted | 2009-07-28 22:16:50 Eureka: fixed ui_canvas.cc for new basic structs. ------------------------------------------------------------------------ r5695 | ajapted | 2009-07-28 21:53:58 Eureka: remove old defintions of LineDef, Sector (etc) structs. ------------------------------------------------------------------------ r5694 | ajapted | 2009-07-28 21:46:06 Eureka: fixed some things in e_basis.cc ------------------------------------------------------------------------ r5693 | ajapted | 2009-07-28 21:19:02 Eureka: reformatted top-of-file comments, added the word 'Copyright' because the presence of mere '(C)' has no legal significance. ------------------------------------------------------------------------ r5692 | ajapted | 2009-07-28 21:12:18 Eureka: twiddled TODO ------------------------------------------------------------------------ r5525 | ajapted | 2009-07-17 15:27:57 Eureka: completed the BASIS implementation (Undo, Redo, etc). ------------------------------------------------------------------------ r5524 | ajapted | 2009-07-17 14:56:04 Eureka: fleshed out more of the BASIS implementation. ------------------------------------------------------------------------ r5523 | ajapted | 2009-07-17 14:29:00 Eureka: more work on BASIS implementation, moved or removed the irrelevant code out of e_basis.cc. ------------------------------------------------------------------------ r5522 | ajapted | 2009-07-17 14:21:44 Eureka: fleshed out the BASIS API (BA_Begin, BA_Change, etc). ------------------------------------------------------------------------ r5521 | ajapted | 2009-07-17 00:48:52 Eureka: basis stuff yay. ------------------------------------------------------------------------ r5520 | ajapted | 2009-07-16 23:59:32 Eureka: further work on the basis (RawInsert and RawDelete). ------------------------------------------------------------------------ r5519 | ajapted | 2009-07-16 21:27:16 Eureka: removed unused OBJ_XXX constants, added rad-trig bits. ------------------------------------------------------------------------ r5518 | ajapted | 2009-07-16 21:24:38 Eureka: basis code: implemented the helper methods (FloorTex etc), and removed more code that doesn't belong here. ------------------------------------------------------------------------ r5517 | ajapted | 2009-07-16 21:05:32 Eureka: fleshed out all basis InsertXXX() and DeleteXXX() functions. ------------------------------------------------------------------------ r5516 | ajapted | 2009-07-16 20:05:31 Eureka: updated the DeleteObject() code for new basis design. ------------------------------------------------------------------------ r5515 | ajapted | 2009-07-16 19:25:42 Eureka: bit more work on object basis. ------------------------------------------------------------------------ r5514 | ajapted | 2009-07-16 19:22:59 Eureka: updated basis header with design notes and some helper methods in each structure (e.g. Sector::FloorTex). ------------------------------------------------------------------------ r5513 | ajapted | 2009-07-16 18:47:12 Eureka: updated makefile. ------------------------------------------------------------------------ r5512 | ajapted | 2009-07-16 17:28:42 Eureka: improved string table class to support "huge" strings. ------------------------------------------------------------------------ r5511 | ajapted | 2009-07-16 15:49:28 Eureka: fixed string table to find existing strings in add(). ------------------------------------------------------------------------ r5510 | ajapted | 2009-07-16 15:30:11 Eureka: finished implementation of string table. ------------------------------------------------------------------------ r5509 | ajapted | 2009-07-16 15:11:15 Eureka: preliminary work on a string table. ------------------------------------------------------------------------ r5508 | ajapted | 2009-07-16 14:58:40 Eureka: added field enums (F_X, F_FLOOR_TEX, etc) to basis classes. ------------------------------------------------------------------------ r5507 | ajapted | 2009-07-16 14:45:10 Eureka: fleshed out new basis classes (class Thing etc). ------------------------------------------------------------------------ r5506 | ajapted | 2009-07-16 14:20:23 Eureka: began work on new 'e_basis' file for basic object handling. ------------------------------------------------------------------------ r5505 | ajapted | 2009-07-16 14:17:14 Eureka: removed 'ld - LineDefs' and 'sec - Sectors' pointer math. ------------------------------------------------------------------------ r5504 | ajapted | 2009-07-16 00:56:49 Eureka: removed unused 'things_angles' and 'things_types' vars. ------------------------------------------------------------------------ r5503 | ajapted | 2009-07-16 00:55:48 Eureka: fixed 'spin_things' code. ------------------------------------------------------------------------ r5494 | ajapted | 2009-07-14 23:52:22 Eureka: got the code compiling again (after SelPtr change). ------------------------------------------------------------------------ r5493 | ajapted | 2009-07-14 23:14:22 Eureka: partial work, updating all code to use new selection_c class instead of old SelPtr stuff. ------------------------------------------------------------------------ r5492 | ajapted | 2009-07-14 22:56:36 Eureka: optional 'initial' value for selection_c constructor. ------------------------------------------------------------------------ r5491 | ajapted | 2009-07-14 22:48:07 Eureka: reworked InsertObject() code. ------------------------------------------------------------------------ r5490 | ajapted | 2009-07-14 22:23:14 Eureka: new and improved DeleteObjects() code is done. ------------------------------------------------------------------------ r5489 | ajapted | 2009-07-14 21:14:17 Eureka: preliminary rework of DeleteObjects() code. ------------------------------------------------------------------------ r5488 | ajapted | 2009-07-14 21:13:41 Eureka: reinstated objid.h (finished split from objects.h). ------------------------------------------------------------------------ r5487 | ajapted | 2009-07-14 20:33:38 Eureka: reinstated header file: objid.h ------------------------------------------------------------------------ r5486 | ajapted | 2009-07-14 19:43:32 Eureka: improved selection_c class, new change_type() and empty() methods. ------------------------------------------------------------------------ r5485 | ajapted | 2009-07-14 18:42:54 Eureka: new MAX_RADIUS constant. ------------------------------------------------------------------------ r5484 | ajapted | 2009-07-14 18:41:40 Eureka: code reformatting. ------------------------------------------------------------------------ r5483 | ajapted | 2009-07-14 16:54:15 Eureka: yet more reformatting, yay. ------------------------------------------------------------------------ r5482 | ajapted | 2009-07-14 16:28:55 Eureka: more reformatting. ------------------------------------------------------------------------ r5481 | ajapted | 2009-07-14 15:30:07 Eureka: code reformatting. ------------------------------------------------------------------------ r5480 | ajapted | 2009-07-14 15:16:39 Eureka: reformatted code. ------------------------------------------------------------------------ r5479 | ajapted | 2009-07-13 23:30:46 Eureka: implemented iterators for the new selection_c class, with an API similar to (but not the same as) the STL. ------------------------------------------------------------------------ r5478 | ajapted | 2009-07-13 23:01:07 Eureka: fleshed out remaining selection_c methods. ------------------------------------------------------------------------ r5477 | ajapted | 2009-07-13 22:49:17 Eureka: preliminary new class for handling selections. ------------------------------------------------------------------------ r5476 | ajapted | 2009-07-13 22:34:39 Eureka: extended bitvec_c class with set_all(), clear_all(), toggle_all() and merge() methods. ------------------------------------------------------------------------ r5475 | ajapted | 2009-07-13 22:12:38 Eureka: reworked bitvec_c implementation. ------------------------------------------------------------------------ r5474 | ajapted | 2009-07-13 21:47:01 Eureka: incorporated highlight code into UI_Canvas widget. ------------------------------------------------------------------------ r5473 | ajapted | 2009-07-13 20:03:23 Eureka: updated TODO ------------------------------------------------------------------------ r5472 | ajapted | 2009-07-13 19:57:18 Eureka: incorporated selection box functionality into UI_Canvas widget. ------------------------------------------------------------------------ r5471 | ajapted | 2009-07-13 19:20:22 Eureka: updated #includes for recent renamings. ------------------------------------------------------------------------ r5470 | ajapted | 2009-07-13 18:58:35 Eureka: moved levelname2levelno(), levelname2rank() from yutil --> levels.cc ------------------------------------------------------------------------ r5469 | ajapted | 2009-07-13 18:51:00 Eureka: renamed various files, now: e_checks, e_linedef, e_things, e_sector, e_vertex, m_config, m_dialog and m_game. ------------------------------------------------------------------------ r5468 | ajapted | 2009-07-13 18:47:34 Eureka: make side panels wider on higher resolutions. ------------------------------------------------------------------------ r5467 | ajapted | 2009-07-13 18:38:32 Eureka: renamed Makefile.linux --> Makefile.unx ------------------------------------------------------------------------ r5466 | ajapted | 2009-07-13 18:36:07 Eureka: updated #includes for recent file renamings. ------------------------------------------------------------------------ r5465 | ajapted | 2009-07-13 17:46:42 Eureka: renamed files: gfx --> r_misc ------------------------------------------------------------------------ r5464 | ajapted | 2009-07-13 17:45:00 Eureka: dead code removal. ------------------------------------------------------------------------ r5463 | ajapted | 2009-07-13 17:36:33 Eureka: renamed files: grid2 --> r_grid ------------------------------------------------------------------------ r5462 | ajapted | 2009-07-13 17:30:26 Eureka: moved InitFLTK and TermFLTK from gfx.cc --> main.cc, and removed some unused stuff. ------------------------------------------------------------------------ r5461 | ajapted | 2009-07-13 17:00:43 Eureka: merged l_super.h file --> linedefs.cc ------------------------------------------------------------------------ r5460 | ajapted | 2009-07-13 14:51:08 Eureka: merged e_names.cc file --> editobj.cc ------------------------------------------------------------------------ r5459 | ajapted | 2009-07-13 14:47:29 Eureka: merged edit2.h file --> editloop.h ------------------------------------------------------------------------ r5458 | ajapted | 2009-07-13 14:41:43 Eureka: merged gotoobj files --> objects.cc/h ------------------------------------------------------------------------ r5450 | ajapted | 2009-07-12 16:02:58 Eureka: code tidying, removed DRAWING_MAP hack. ------------------------------------------------------------------------ r5449 | ajapted | 2009-07-12 00:40:42 Eureka: renamed various fields of map structures: xoff, yoff --> x_offset, y_offset ceilt, floort --> ceil_tex, floor_tex upper, lower --> upper_tex, lower_tex middle --> mid_tex sidedef1 / 2 --> side_R, side_L when, special --> options, type ------------------------------------------------------------------------ r5448 | ajapted | 2009-07-11 23:46:56 Eureka: Removed unused headers: spot.h and edwidget.h ------------------------------------------------------------------------ r5447 | ajapted | 2009-07-11 23:34:04 Eureka: more file merging, various reformatting and renaming. ------------------------------------------------------------------------ r5446 | ajapted | 2009-07-11 22:46:35 Eureka: reformatting... ------------------------------------------------------------------------ r5445 | ajapted | 2009-07-11 22:32:11 Eureka: more file shenanigans. ------------------------------------------------------------------------ r5444 | ajapted | 2009-07-11 22:22:36 Eureka: merged input.h and y_time.cc/h into other files. ------------------------------------------------------------------------ r5443 | ajapted | 2009-07-11 22:10:29 Eureka: scrollbar tweak. ------------------------------------------------------------------------ r5442 | ajapted | 2009-07-11 21:59:25 Eureka: new top-of-file comments (header files). ------------------------------------------------------------------------ r5441 | ajapted | 2009-07-11 21:44:52 Eureka: new top-of-file comment block. ------------------------------------------------------------------------ r5440 | ajapted | 2009-07-11 18:07:17 Eureka: more work on the Texture list widget. ------------------------------------------------------------------------ r5439 | ajapted | 2009-07-11 15:04:50 Eureka: bit more work on texture selector. ------------------------------------------------------------------------ r5438 | ajapted | 2009-07-11 14:42:58 Eureka: preliminary work on a flat/texture selection panel. ------------------------------------------------------------------------ r5437 | ajapted | 2009-07-11 14:10:45 Eureka: renamed more stuff. ------------------------------------------------------------------------ r5436 | ajapted | 2009-07-11 14:09:23 Eureka: renamed more stuff. ------------------------------------------------------------------------ r5435 | ajapted | 2009-07-11 00:32:21 Eureka: various tidying... ------------------------------------------------------------------------ r5434 | ajapted | 2009-07-11 00:06:45 Eureka: began work on using larger fonts (etc) on higher screen resolutions. ------------------------------------------------------------------------ r5433 | ajapted | 2009-07-10 23:35:44 Eureka: reformatting. ------------------------------------------------------------------------ r5432 | ajapted | 2009-07-10 22:44:04 Eureka: added vim editor settings to each file. ------------------------------------------------------------------------ r5431 | ajapted | 2009-07-10 22:15:48 Eureka: renamed files yadex --> main, merged objid.h into objects.h ------------------------------------------------------------------------ r5430 | ajapted | 2009-07-10 21:59:48 Eureka: tweaks. ------------------------------------------------------------------------ r5429 | ajapted | 2009-07-10 21:54:07 Eureka: yep more twiddling... ------------------------------------------------------------------------ r5428 | ajapted | 2009-07-10 21:38:01 Eureka: more tidying... ------------------------------------------------------------------------ r5427 | ajapted | 2009-07-10 19:31:40 Eureka: more file stuff.... ------------------------------------------------------------------------ r5426 | ajapted | 2009-07-10 19:21:00 Eureka: merged files: im_appcol, im_gamecol, im_rgb --> im_color. ------------------------------------------------------------------------ r5425 | ajapted | 2009-07-10 19:08:03 Eureka: merged files: x_rotate, x_centre, x_exchg --> x_mirror. ------------------------------------------------------------------------ r5424 | ajapted | 2009-07-10 14:56:36 Eureka: finished merging v_* files. ------------------------------------------------------------------------ r5423 | ajapted | 2009-07-10 14:52:39 Eureka: began merging v_* files --> vertices.cc/h ------------------------------------------------------------------------ r5422 | ajapted | 2009-07-10 14:49:52 Eureka: merged s_* files into sectors.cc/h and s_misc.cc/h ------------------------------------------------------------------------ r5421 | ajapted | 2009-07-10 14:38:39 Eureka: merged s_split.cc, s_slice.cc into --> s_misc.cc ------------------------------------------------------------------------ r5420 | ajapted | 2009-07-10 14:33:32 Eureka: renamed files: s_centre --> sectors ------------------------------------------------------------------------ r5419 | ajapted | 2009-07-10 14:32:20 Eureka: renamed file --> s_misc.h ------------------------------------------------------------------------ r5418 | ajapted | 2009-07-10 14:29:40 Eureka: finished merging linedef stuff. ------------------------------------------------------------------------ r5417 | ajapted | 2009-07-10 14:23:12 Eureka: began merging linedef stuff into less files. ------------------------------------------------------------------------ r5416 | ajapted | 2009-07-10 00:38:58 Eureka: renamed file: memory --> ymemory ------------------------------------------------------------------------ r5415 | ajapted | 2009-07-10 00:34:54 Eureka: merged t_spin, t_flags, t_centre files --> things.cc/h ------------------------------------------------------------------------ r5414 | ajapted | 2009-07-10 00:25:51 Eureka: renamed GetFarMemory --> GetMemory (et al). ------------------------------------------------------------------------ r5413 | ajapted | 2009-07-10 00:17:55 Eureka: removed files: locate.cc/h and macro.cc/h ------------------------------------------------------------------------ r5390 | ajapted | 2009-07-09 01:36:07 Eureka: fixed the cpu hogging (use Fl::wait in main loop). ------------------------------------------------------------------------ r5389 | ajapted | 2009-07-09 01:16:45 Eureka: removed dummy atclib.h ------------------------------------------------------------------------ r5388 | ajapted | 2009-07-09 00:52:30 Checked in a map editor based on Yadex 1.7.0 but completely hacked to pieces to work with the FLTK toolkit and removal of the atclib. eureka-1.11-source/docs/MiscNotes.txt0000644000175100017510000001011412647061302017061 0ustar aaptedaapted WAD SEMANTICS ============= (a) there is always an IWAD (given by -iwad or found somewhere). maps are never saved into an IWAD (special command line option to do it) ---> global: 'base_wad' (b) there is _usually_ a PWAD (given by -file). it must be modifiable (e.g. not in /usr), CTRL-S saves into it. when absent, user cannot File/Save, the File/Export function is done instead. ---> global: 'edit_wad' (c) when File/Export is successful, that becomes the new PWAD. the existing PWAD goes away (or becomes a resource wad). (c) user can File/Load another map, but if it's in an uneditable wad (especially the IWAD) then the previous PWAD goes away (or becomes a resource wad). (d) File/New Map needs to ask for a map name. If there is current PWAD and map already exists, warn user GAME SEMANTICS ============== Remove the path and extension from the IWAD, and make the result lowercase, and that is the name of the "game". There must be a config file called 'games/xxx.ugh' which defines everything for that game. SECTOR INSERT FUNCTIONS ======================= (a) in an area without any sector, add a NEW sector there (ideally copying values from a nearby sector) ---> SPACE [there cannot be a highlight] [if a single sector is selected, copy values from it] [if multiple selected sector -- ignore? beep? copy first?] AFTER: this sector becomes selected (b) in an area with sectoring (broken or not), add a NEW sector ---> CTRL + SPACE [the CTRL forces a NEW sector to be made] [if a single sector is selected, copy values from it -- overrides highlight] [else if a sector is highlighted, copy that] [else use logic from (a)] AFTER: this sector becomes selected (c) in an area with broken sectoring, fix the sectoring using the currently highlighted one. ---> SPACE The presence of a highlighted sector is what differentiates case (c) from case (a). [if sectors are selected -- ignore? beep?] this sector DOES NOT get selected [because it is NOT NEW] (d) copy properties from an existing sector (selected) to the highlighted one. Beep if invalid selection. --> 'c' copy command Hmmm, does it make more sense to select the TARGETs and copy from the Highlight ??? ---- CONFIG ITEM! (e) in any area, change sector to an existing one [selected] (i.e. grow that existing sector) ---> 'm' merge command PointCanSeeVoid Algorithm ------------------------- Basically use an angular occlusion buffer. Process each linedef in the level and update the angle range in the buffer. When finished, any gaps in the buffer means that the point can "see" to infinity. Quantization Function --------------------- The selection contains the vertices to move (require vertex mode). Process each vertex in turn, if quantization works then unselect that vertex, otherwise keep it selected. After all processed, BEEP if any vertices remain selected. Have a selection_c variable for ones already processed, and ones which moved successfully. A vertex that is already on the grid trivially succeeds. Otherwise try the FOUR nearby corners (TWO when the vertex is sitting on a grid line), checking nearest first. THE NEW POSITION MUST BE VACANT for the move to succeed. Also must prevent linedefs from crossing or overlapping. There may be a need for additional logic to keep the original orientation of linedefs (horizontal lines stay horizontal, vertical lines stay vertical, diagonal lines stay diagonal). However this is difficult to do in practice : perhaps do it by checking all lines in an initial pass, and mark vertices which are not allowed to "round up" to a nearby grid spot (vertices on a horizontal line are not allowed to round up vertically, and vice versa). CONSOLE IDEA ------------ toggle on/off with the F4 key exists where map/render is (maybe half, above it) (maybe translucent background) turns off browser (and vice versa) have cvars for config items, changeable in console quake-like binding, e.g. "bind w swap-flats" arguments beginning with '+' get executed as console commands eureka-1.11-source/common/0000755000175100017510000000000012647412750014766 5ustar aaptedaaptedeureka-1.11-source/common/doom_specials.ugh0000644000175100017510000001514012647061302020306 0ustar aaptedaapted#------------------------------------------------------------------------ # DOOM 1/2 line and sector specials #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2012 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ # # Definition of linedef groups # Format is : linegroup # linegroup a "Animated" linegroup c "Ceiling" linegroup d "Door" linegroup e "Exit level" linegroup f "Floor (lower)" linegroup g "Floor (raise)" linegroup h "Crusher" linegroup k "Keyed Door" linegroup l "Light" linegroup m "Moving floor" linegroup p "Lift" linegroup s "Stairs" linegroup t "Teleport" linegroup v "Elevator" linegroup - "OTHER" # # Definition of linedef types # Format is : line # line 0 - "-- NOTHING" line 9 - "S1 Donut (raise outer, lower inner)" line 78 - "SR Floor Transfer /NXP" line 48 a "-- Scroll Wall Left" line 6 h "W1 Crusher /fast" line 25 h "W1 Crusher /slow" line 57 h "W1& Stop crusher" line 73 h "WR& Crusher /slow" line 77 h "WR& Crusher" line 74 h "WR& Stop crusher" line 141 h "W1& Crusher /silent" line 24 g "G1 Floor up LIC" line 47 g "G1 Floor up nhEF /TX" line 101 g "S1 Floor up LIC" line 55 g "S1 Floor up LIC-8 /cr" line 18 g "S1 Floor up nhEF" line 15 g "S1& Floor up 24 /TX" line 14 g "S1& Floor up 32 /TX" line 20 g "S1& Floor up nhEF /TX" line 64 g "SR Floor up LIC" line 65 g "SR Floor up LIC-8 /cr" line 69 g "SR Floor up nhEF" line 66 g "SR& Floor up 24 /TX" line 67 g "SR& Floor up 32 /TX" line 68 g "SR& Floor up nhEF /TX" line 59 g "W1 Floor up 24 /TXP" line 58 g "W1 Floor up 24" line 5 g "W1 Floor up LIC" line 30 g "W1 Floor up lowest tex" line 56 g "W1& Floor up LIC-8 /cr" line 22 g "W1& Floor up nhEF /TX" line 93 g "WR Floor up 24 /TXP" line 92 g "WR Floor up 24" line 91 g "WR Floor up LIC" line 94 g "WR Floor up LIC-8 /cr" line 96 g "WR Floor up lowest tex" line 95 g "WR Floor up nhEF /TX" line 119 g "W1 Floor up nhEF" line 128 g "WR Floor up nhEF" line 129 g "WR Floor UP nhEF /fast" line 130 g "W1 Floor UP nhEF /fast" line 131 g "S1 Floor UP nhEF /fast" line 132 g "SR Floor UP nhEF /fast" line 140 g "S1 Floor up 512" line 13 l "W1 Light to 255" line 35 l "W1 Light to 35" line 12 l "W1 Light to highest nb" line 104 l "W1 Light to lowest nb" line 17 l "W1 Start Blinking" line 81 l "WR Light to 255" line 79 l "WR Light to 35" line 80 l "WR Light to highest nb" line 138 l "SR Light to 255" line 139 l "SR Light to 0" line 49 c "S1 Ceiling close flr+8" line 41 c "S1 Ceiling close" line 43 c "SR Ceiling close" line 44 c "W1 Ceiling close flr+8" line 40 c "W1 Ceiling up HEC" line 72 c "WR Ceiling close flr+8" line 31 d "D1 Open and stay open" line 1 d "DR Open door" line 46 d "GR Open and stay" line 50 d "S1 Close door" line 103 d "S1 Open and stay" line 29 d "S1 Open door" line 42 d "SR Close door" line 61 d "SR Open and stay" line 63 d "SR Open door" line 3 d "W1 Close door" line 16 d "W1 Close for 30s" line 2 d "W1 Open and stay open" line 4 d "W1 Open door" line 75 d "WR Close door" line 76 d "WR Close for 30s" line 86 d "WR Open and stay" line 90 d "WR Open door" line 105 d "WR Open door /fast" line 106 d "WR Open and stay /fast" line 107 d "WR Close door /fast" line 108 d "W1 Open door /fast" line 109 d "W1 Open and stay /fast" line 110 d "W1 Close door /fast" line 111 d "S1 Open door /fast" line 112 d "S1 Open and stay /fast" line 113 d "S1 Close door /fast" line 114 d "SR Open door /fast" line 115 d "SR Open and stay /fast" line 116 d "SR Close door /fast" line 117 d "DR Open door /fast" line 118 d "D1 Open and stay /fast" line 26 k "DR Open blue door" line 27 k "DR Open yellow door" line 28 k "DR Open red door" line 32 k "D1 Open blue door (stay)" line 33 k "D1 Open red door (stay)" line 34 k "D1 Open yellow door (stay)" line 99 k "SR Open blue door /fast" line 133 k "S1 Open blue door /fast" line 134 k "SR Open red door /fast" line 135 k "S1 Open red door /fast" line 136 k "SR Open yellow door /fast" line 137 k "S1 Open yellow door /fast" line 11 e "s1 Exit level" line 51 e "s1 Secret exit" line 52 e "w1 Exit level" line 124 e "w1 Secret exit" line 102 f "S1 Floor down HEF" line 71 f "S1 Floor down HEF+8 /fast" line 23 f "S1 Floor down LEF" line 45 f "SR Floor down HEF" line 70 f "SR Floor down HEF+8 /fast" line 60 f "SR Floor down LEF" line 19 f "W1 Floor down HEF" line 36 f "W1 Floor down HEF+8" line 37 f "W1 Floor down LEF /NXP" line 38 f "W1 Floor down LEF" line 98 f "WR Floor dn HEF+8 /fast" line 83 f "WR Floor down HEF" line 84 f "WR Floor down LEF /NXP" line 82 f "WR Floor down LEF" line 21 p "S1 Lower Lift" line 62 p "SR Lower Lift" line 10 p "W1 Lower Lift" line 88 p "WR Lower Lift" line 120 p "WR Lower Lift /fast" line 121 p "W1 Lower Lift /fast" line 122 p "S1 Lower Lift /fast" line 123 p "SR Lower Lift /fast" line 53 m "W1 Start moving floor" line 54 m "W1 Stop moving floor" line 87 m "WR& Start moving floor" line 89 m "WR& Stop moving floor" line 7 s "S1 Stair Raise 8" line 100 s "W1 Stair Raise 16" line 8 s "W1 Stair Raise 8" line 39 t "W1 Teleport" line 97 t "WR Teleport" line 125 t "W1 Teleport /mon" line 126 t "WR Teleport /mon" line 127 s "S1 Stair Raise 16" #------------------------------------------------------------------------ # # Definition of sector types # Format is : sector # sector 0 "NOTHING" sector 1 "Light Blinks Randomly" sector 2 "Light Flashes 2 Hz" sector 3 "Light Flashes 1 Hz" sector 4 "Flashes / 20% Damage" sector 5 "Damage 10%" sector 7 "Damage 5%" sector 8 "Light Oscillates" sector 9 "Secret Area" sector 10 "Close after 30 sec" sector 11 "End level / damage" sector 12 "Flashes 1 Hz sync" sector 13 "Flashes 2 Hz sync" sector 14 "Open after 5 minute" sector 16 "Damage 20%" sector 17 "Light Flickering" eureka-1.11-source/common/xlat_doom.cfg0000644000175100017510000000033712647061302017431 0ustar aaptedaapted#------------------------------------------------------------------------ # MAP FORMAT TRANSLATION : HEXEN --> DOOM #------------------------------------------------------------------------ sector 9 = 9 line 11 tag = 1 eureka-1.11-source/common/doom_colors.ugh0000644000175100017510000000166312647061302020011 0ustar aaptedaapted#------------------------------------------------------------------------ # DOOM 1/2 color stuff #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2013-2016 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. # #------------------------------------------------------------------------ color sky 198 color wall 111 80 color floor 151 128 color missing 215 color unknown_tex 194 color unknown_flat 112 eureka-1.11-source/common/gen_types.ugh0000644000175100017510000000721212647412720017467 0ustar aaptedaapted#------------------------------------------------------------------------ # BOOM GENERALIZED TYPES #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2016 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 information comes from the "BOOM reference v1.3" document. # #------------------------------------------------------------------------ gen_line d 0x3c00 0x0400 "DOOR" gen_field 3 0 7 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 2 5 0 "Kind" "Normal" "STAY OPEN" "Close+Open" "Closes" gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 2 8 1 "Delay" "1 sec" "4 secs" "9 secs" "30 secs" gen_field 1 7 0 "Monsters" no MONSTER gen_line k 0x3800 0x0400 "KEYED DOOR" gen_field 3 0 6 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 3 6 1 "Keys" "Any key" "Red Card" "Blue Card" "Yellow Card" "Red Skull" "Blue Skull" "Yellow Skull" "ALL KEYS" gen_field 1 9 1 "Matching" Precise skull=card gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 1 5 1 "Stay Mode" "Closes" "STAY OPEN" # Note: "Model" and "Monsters" share the same bit position. # The code takes care to enable the approprite one. gen_line f 0x6000 0x2000 "FLOOR" gen_field 3 0 0 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 1 6 0 "Direction" Down UP gen_field 3 7 1 "Target" "Highest Floor" "Lowest Floor" "Next Floor" "Lowest CEIL" "CEILING" "By texture" "24 units" "32 units" gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 2 10 0 "Change" "NONE" "Tex+zero" "Texture" "Tex+type" gen_field 1 5 0 "Model" Trigger Numeric gen_field 1 5 0 "Monsters" no MONSTER gen_field 1 12 0 "Crush" no CRUSH gen_line c 0x4000 0x2000 "CEILING" gen_field 3 0 0 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 1 6 1 "Direction" Down UP gen_field 3 7 0 "Target" "Highest Ceil" "Lowest Ceil" "Next Ceil" "Highest Floor" "FLOOR" "By texture" "24 units" "32 units" gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 2 10 0 "Change" "NONE" "Tex+zero" "Texture" "Tex+type" gen_field 1 5 0 "Model" Trigger Numeric gen_field 1 5 0 "Monsters" no MONSTER gen_field 1 12 0 "Crush" no CRUSH gen_line l 0x3400 0x0400 "LIFT" gen_field 3 0 1 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 2 8 0 "Target" "Lowest Floor" "Next Floor" "Lowest CEIL" "PERPETUAL" gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 2 6 1 "Delay" "1 sec" "3 secs" "5 secs" "10 secs" gen_field 1 5 0 "Monsters" no MONSTER gen_line s 0x3000 0x0400 "STAIR" gen_field 3 0 2 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 1 8 1 "Direction" Down UP gen_field 2 6 1 "Step" "4 units" "8 units" "16 units" "24 units" gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 1 5 0 "Monsters" no MONSTER gen_field 1 9 0 "Tex Match" "Same tex" "ANY TEX" gen_line r 0x2f80 0x0080 "CRUSHER" gen_field 3 0 0 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 2 3 0 "Speed" SLOW Medium Fast Turbo gen_field 1 5 0 "Monsters" no MONSTER gen_field 1 6 0 "Silent" no SILENT eureka-1.11-source/common/doom_things.ugh0000644000175100017510000001347512647061302020010 0ustar aaptedaapted#------------------------------------------------------------------------ # DOOM 1/2 common things #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2015 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ # # Definition of thing groups # Format is : thinggroup # thinggroup p 4F4 "Player" thinggroup m F00 "Monster" thinggroup w FA0 "Weapon" thinggroup a 850 "Ammunition" thinggroup h 280 "Health && Armor" thinggroup b 280 "Bonus" thinggroup k F0F "Key" thinggroup d 66C "Decoration" thinggroup l 66C "Light Source" thinggroup g 66C "Gore" thinggroup - 0BD "OTHER" # # Definition of things # Format is : thing # # should be NULL for things without any sprite # # can contain these letters: # i : invisible # c : on ceiling # l : lit up # n : non-blocking # v : can exist in void-space # t : teleport dest (can overlap certain things) # thing 1 p - 16 PLAY "Player 1 start" thing 2 p - 16 PLAY "Player 2 start" thing 3 p - 16 PLAY "Player 3 start" thing 4 p - 16 PLAY "Player 4 start" thing 11 p t 16 PLAYF1 "Deathmatch start" thing 14 p t 16 TFOG "Teleport exit" thing 2005 w n 20 CSAW "Chainsaw" thing 2001 w n 20 SHOT "Shotgun" thing 2002 w n 20 MGUN "Chaingun" thing 2003 w n 20 LAUN "Rocket launcher" thing 2004 w n 20 PLAS "Plasma gun" thing 2006 w n 20 BFUG "BFG9000" thing 2007 a n 20 CLIP "Clip" thing 2048 a n 20 AMMO "Box of bullets" thing 2008 a n 20 SHEL "Shells" thing 2049 a n 20 SBOX "Box of shells" thing 2010 a n 20 ROCK "Rocket" thing 2046 a n 20 BROK "Box of rockets" thing 2047 a n 20 CELL "Energy cell" thing 17 a n 20 CELP "Box of energy cells" thing 8 b n- 20 BPAK "Backpack of ammo" thing 2022 b nl 20 PINV "Invulnerability" thing 2023 b nl 20 PSTR "Berserk" thing 2024 b nl 20 PINS "Partial invisibility" thing 2025 b nl 20 SUIT "Radiation suit" thing 2026 b n- 20 PMAP "Computer map" thing 2045 b nl 20 PVIS "Light amp. goggles" thing 2011 h n- 20 STIM "Stimpack" thing 2012 h n- 20 MEDI "Medikit" thing 2013 h nl 20 SOUL "Supercharge" thing 2014 h n- 20 BON1 "Health bonus" thing 2015 h n- 20 BON2 "Armor bonus" thing 2018 h nl 20 ARM1 "Green Armor" thing 2019 h nl 20 ARM2 "Blue Armor" thing 5 k nl 20 BKEY "Blue keycard" thing 6 k nl 20 YKEY "Yellow keycard" thing 13 k nl 20 RKEY "Red keycard" thing 40 k nl 20 BSKU "Blue skull key" thing 39 k nl 20 YSKU "Yellow skull key" thing 38 k nl 20 RSKU "Red skull key" thing 15 g n 16 PLAYN "Dead player (green)" thing 18 g n 20 POSSL "Dead trooper" thing 19 g n 20 SPOSL "Dead sergeant" thing 20 g n 20 TROOM "Dead imp" thing 21 g n 16 SARGN "Dead demon" thing 22 g n 16 HEADL "Dead cacodemon" thing 23 g n 16 SKULK "Dead lost soul" thing 2035 d - 10 BAR1 "Barrel" thing 48 d - 16 ELEC "Technical column" thing 30 d - 16 COL1 "Tall green pillar" thing 32 d - 16 COL3 "Tall red pillar" thing 31 d - 16 COL2 "Short green pillar" thing 33 d - 16 COL4 "Short red pillar" thing 36 d - 16 COL5 "Pillar w/heart" thing 37 d - 16 COL6 "Red pillar w/skull" thing 41 d l 16 CEYE "Evil eye" thing 42 g l 16 FSKU "Floating skulls" thing 47 d - 16 SMIT "Brown stub" thing 54 d - 32 TRE2 "Brown tree" thing 43 d - 16 TRE1 "Grey tree" thing 10 g n 16 PLAYW "Mushed player" thing 12 g n 16 PLAYW "Mushed player 2" thing 24 g n 16 POL5 "Pool of blood" thing 27 g - 16 POL4 "Pole with skull" thing 28 g - 16 POL2 "Skewer with heads" thing 29 g l 16 POL3 "Pile of skulls" thing 25 g - 16 POL1 "Impaled body" thing 26 g - 16 POL6 "Impaled twitching" thing 49 g c 16 GOR1 "Swaying body" thing 63 g cn 16 GOR1 "Swaying body /n" thing 50 g c 16 GOR2 "Hanging arms out" thing 59 g cn 16 GOR2 "Hanging arms out /n" thing 53 g c 16 GOR5 "Hanging leg" thing 62 g cn 16 GOR5 "Hanging leg /n" thing 51 g c 16 GOR3 "Hanging one-legged" thing 61 g cn 16 GOR3 "Hanging one-legged /n" thing 52 g c 16 GOR4 "Hanging torso" thing 60 g cn 16 GOR4 "Hanging torso /n" thing 2028 l l 16 COLU "Lamp" thing 34 l ln 16 CAND "Candle" thing 35 l l 16 CBRA "Candelabra" thing 44 l l 16 TBLU "Tall blue torch" thing 45 l l 16 TGRN "Tall green torch" thing 46 l l 16 TRED "Tall red torch" thing 55 l l 16 SMBT "Short blue torch" thing 56 l l 16 SMGT "Short green torch" thing 57 l l 16 SMRT "Short red torch" thing 70 l l 16 FCAN "Burning barrel" thing 3004 m - 20 POSS "Trooper" thing 9 m - 20 SPOS "Sergeant" thing 3001 m - 20 TROO "Imp" thing 3002 m - 30 SARG "Demon" thing 3003 m - 24 BOSS "Baron of Hell" thing 58 m i 30 SARG "Spectre" thing 3006 m l 16 SKUL "Lost soul" thing 3005 m - 31 HEAD "Cacodemon" thing 7 m - 128 SPID "Spider Mastermind" thing 16 m - 40 CYBR "Cyberdemon" eureka-1.11-source/common/doom_tex.ugh0000644000175100017510000001616612647061302017314 0ustar aaptedaapted#------------------------------------------------------------------------ # DOOM 1/2 common textures #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2013 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # 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. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ texturegroup h "Hell" texturegroup n "Natural" texturegroup t "Tech" texturegroup u "Urban" texturegroup - "OTHER" texture u STONE2 texture u STONE3 texture u SW1BRIK texture u SW2BRIK texture u SW1STON1 texture u SW2STON1 texture u CEMENT1 texture u CEMENT2 texture u CEMENT3 texture u CEMENT4 texture u CEMENT5 texture u CEMENT6 texture u SW1CMT texture u SW2CMT texture h BLODRIP1 texture h BLODRIP2 texture h BLODRIP3 texture h BLODRIP4 texture h DOORBLU2 texture h DOORRED2 texture h DOORYEL2 texture h FIREBLU1 texture h FIREBLU2 texture h FIRELAV2 texture h FIRELAV3 texture h FIRELAVA texture h FIREMAG1 texture h FIREMAG2 texture h FIREMAG3 texture h FIREWALA texture h FIREWALB texture h FIREWALL texture h PIPE1 texture h REDWALL texture h SK_LEFT texture h SK_RIGHT texture h SKIN2 texture h SKINCUT texture h SKINEDGE texture h SKINFACE texture h SKINLOW texture h SKINMET1 texture h SKINMET2 texture h SKINSCAB texture h SKINSYMB texture h SKSNAKE1 texture h SKSNAKE2 texture h SKSPINE1 texture h SKSPINE2 texture h SLOPPY1 texture h SLOPPY2 texture h SP_FACE1 texture h SP_FACE2 texture h SP_HOT1 texture h SW1HOT texture h SW2HOT texture h SW1SKIN texture h SW2SKIN texture h GSTFONT1 texture h GSTFONT2 texture h GSTFONT3 texture h GSTGARG texture h GSTLION texture h GSTONE1 texture h GSTONE2 texture h GSTSATYR texture h GSTVINE1 texture h GSTVINE2 texture h MARBFAC2 texture h MARBFAC3 texture h MARBFACE texture h MARBLE1 texture h MARBLE2 texture h MARBLE3 texture h MARBLOD1 texture h SP_DUDE1 texture h SP_DUDE2 texture h SP_DUDE4 texture h SP_DUDE5 texture h SW1GSTON texture h SW2GSTON texture h SW1MARB texture h SW2MARB texture t BIGDOOR2 texture t BIGDOOR3 texture t BIGDOOR4 texture t BRNPOIS texture t BRNSMAL1 texture t BRNSMAL2 texture t BRNSMALC texture t BRNSMALL texture t BRNSMALR texture t BROVINE2 texture t BROWN1 texture t BROWN144 texture t BROWN96 texture t BROWNGRN texture t BROWNHUG texture t BROWNPIP texture t CRATE1 texture t CRATE2 texture t CRATELIT texture t CRATINY texture t CRATWIDE texture t DOORBLU texture t DOORRED texture t DOORSTOP texture t DOORTRAK texture t DOORYEL texture t EXITDOOR texture t EXITSIGN texture t EXITSTON texture t GRAY1 texture t GRAY2 texture t GRAY4 texture t GRAY5 texture t GRAY7 texture t GRAYBIG texture t GRAYPOIS texture t GRAYTALL texture t GRAYVINE texture t ICKWALL1 texture t ICKWALL2 texture t ICKWALL3 texture t ICKWALL4 texture t ICKWALL5 texture t ICKWALL7 texture t NUKE24 texture t NUKEDGE1 texture t NUKEPOIS texture t PIPE2 texture t PIPE4 texture t PIPE6 texture t PLAT1 texture t SLADPOIS texture t SLADSKUL texture t SLADWALL texture t STEP2 texture t STEP3 texture t STEP4 texture t STEPTOP texture t SUPPORT3 texture t SW1BRCOM texture t SW2BRCOM texture t SW1BRN1 texture t SW2BRN1 texture t SW1BRN2 texture t SW2BRN2 texture t SW1BRNGN texture t SW2BRNGN texture t SW1BROWN texture t SW2BROWN texture t SW1DIRT texture t SW2DIRT texture t SW1EXIT texture t SW2EXIT texture t SW1GRAY texture t SW2GRAY texture t SW1GRAY1 texture t SW2GRAY1 texture t SW1PIPE texture t SW2PIPE texture t SW1SLAD texture t SW2SLAD texture t SW1STARG texture t SW2STARG texture t SW1STON2 texture t SW2STON2 texture t SW1STONE texture t SW2STONE texture t SW1VINE texture t SW2VINE texture t METAL texture t METAL1 texture t MIDBRN1 texture t MIDGRATE texture t SW1GARG texture t SW2GARG texture t SW1LION texture t SW2LION texture t SW1MET2 texture t SW2MET2 texture t SW1METAL texture t SW2METAL texture t SW1SATYR texture t SW2SATYR texture n ROCKRED1 texture n ROCKRED2 texture n ROCKRED3 texture n SP_ROCK1 texture n STONE texture n SW1STON6 texture n SW2STON6 texture t BIGDOOR1 texture t BLAKWAL1 texture t BLAKWAL2 texture t COMPBLUE texture t COMPSPAN texture t COMPSTA1 texture t COMPSTA2 texture t COMPTALL texture t COMPWERD texture t DOOR1 texture t DOOR3 texture t LITE3 texture t LITE5 texture t LITEBLU1 texture t LITEBLU4 texture t SHAWN1 texture t SHAWN2 texture t SHAWN3 texture t STARBR2 texture t STARG1 texture t STARG2 texture t STARG3 texture t STARGR1 texture t STARGR2 texture t STARTAN2 texture t STARTAN3 texture t STEP1 texture t STEP5 texture t STEP6 texture t STEPLAD1 texture t SUPPORT2 texture t SW1BLUE texture t SW2BLUE texture t SW1COMM texture t SW2COMM texture t SW1COMP texture t SW2COMP texture t SW1MOD1 texture t SW2MOD1 texture t SW1STRTN texture t SW2STRTN texture t TEKWALL1 texture t TEKWALL4 texture u BIGDOOR5 texture u BIGDOOR6 texture u BIGDOOR7 texture u SW1WOOD texture u SW2WOOD texture u WOOD1 texture u WOOD3 texture u WOOD4 texture u WOOD5 texture u WOODGARG flat h BLOOD1 flat h BLOOD2 flat h BLOOD3 flat u CEIL1_1 flat t CEIL1_2 flat t CEIL1_3 flat t CEIL3_1 flat t CEIL3_2 flat t CEIL3_3 flat t CEIL3_4 flat t CEIL3_5 flat t CEIL3_6 flat t CEIL4_1 flat t CEIL4_2 flat t CEIL4_3 flat t CEIL5_1 flat t CEIL5_2 flat t COMP01 flat t CONS1_1 flat t CONS1_5 flat t CONS1_7 flat t CRATOP1 flat t CRATOP2 flat h DEM1_1 flat h DEM1_2 flat h DEM1_3 flat h DEM1_4 flat h DEM1_5 flat h DEM1_6 flat t FLAT1 flat n FLAT10 flat u FLAT1_1 flat u FLAT1_2 flat u FLAT1_3 flat t FLAT14 flat t FLAT17 flat t FLAT18 flat t FLAT19 flat t FLAT2 flat t FLAT20 flat t FLAT22 flat t FLAT23 flat t FLAT3 flat t FLAT4 flat t FLAT5 flat u FLAT5_1 flat u FLAT5_2 flat h FLAT5_3 flat u FLAT5_4 flat u FLAT5_5 flat h FLAT5_6 flat n FLAT5_7 flat n FLAT5_8 flat u FLAT8 flat t FLAT9 flat t FLOOR0_1 flat t FLOOR0_2 flat t FLOOR0_3 flat t FLOOR0_5 flat t FLOOR0_6 flat t FLOOR0_7 flat t FLOOR1_1 flat t FLOOR1_6 flat t FLOOR1_7 flat t FLOOR3_3 flat t FLOOR4_1 flat t FLOOR4_5 flat t FLOOR4_6 flat t FLOOR4_8 flat t FLOOR5_1 flat t FLOOR5_2 flat t FLOOR5_3 flat u FLOOR5_4 flat h FLOOR6_1 flat n FLOOR6_2 flat t FLOOR7_1 flat h FLOOR7_2 flat n F_SKY1 flat n FWATER1 flat n FWATER2 flat n FWATER3 flat n FWATER4 flat t GATE1 flat t GATE2 flat t GATE3 flat t GATE4 flat h LAVA1 flat h LAVA2 flat h LAVA3 flat h LAVA4 flat u MFLR8_1 flat n MFLR8_2 flat n MFLR8_3 flat n MFLR8_4 flat t NUKAGE1 flat t NUKAGE2 flat t NUKAGE3 flat h SFLR6_1 flat h SFLR6_4 flat h SFLR7_1 flat h SFLR7_4 flat t STEP1 flat t STEP2 flat t TLITE6_1 flat t TLITE6_4 flat t TLITE6_5 flat t TLITE6_6 eureka-1.11-source/common/xlat_hexen.cfg0000644000175100017510000000034112647061302017575 0ustar aaptedaapted#------------------------------------------------------------------------ # MAP FORMAT TRANSLATION : DOOM --> HEXEN #------------------------------------------------------------------------ sector 9 = 9 line 1 = 11 tag 8 eureka-1.11-source/Makefile.xming0000644000175100017510000000722212647061302016253 0ustar aaptedaapted# # --- Eureka Editor --- # # Makefile for WIN32, using a CROSS-COMPILER on Linux # PROGRAM=Eureka.exe CROSS=i686-w64-mingw32- CXX=$(CROSS)g++ LIB_LOC=lib_win32 OBJ_DIR=obj_win32 FLTK_DIR=$(LIB_LOC)/fltk-1.3.3 ZLIB_DIR=$(LIB_LOC)/zlib-1.2.8 OPTIMISE=-O2 -fno-strict-aliasing STRIP_FLAGS=--strip-unneeded # operating system choices: UNIX WIN32 OS=WIN32 #--- Internal stuff from here ----------------------------------- FLTK_FLAGS=-I$(FLTK_DIR) FLTK_LIBS=$(FLTK_DIR)/mingw/lib/libfltk_images.a \ $(FLTK_DIR)/mingw/lib/libfltk_png.a \ $(FLTK_DIR)/mingw/lib/libfltk.a ZLIB_FLAGS=-I$(ZLIB_DIR) ZLIB_LIBS=$(ZLIB_DIR)/libz.a CXXFLAGS=$(OPTIMISE) -Wall -D$(OS) \ -Iglbsp_src $(FLTK_FLAGS) $(ZLIB_FLAGS) LDFLAGS=-static-libgcc -static-libstdc++ LIBS=-lm $(FLTK_LIBS) $(ZLIB_LIBS) \ -mwindows -lshell32 \ -lcomdlg32 -lole32 -luuid -lgdi32 \ -lcomctl32 -lwsock32 -lsupc++ #--- main target --- all: stripped #----- Object files ---------------------------------------------- OBJS = \ $(OBJ_DIR)/editloop.o \ $(OBJ_DIR)/e_basis.o \ $(OBJ_DIR)/e_checks.o \ $(OBJ_DIR)/e_checks2.o \ $(OBJ_DIR)/e_cutpaste.o \ $(OBJ_DIR)/e_linedef.o \ $(OBJ_DIR)/e_loadsave.o \ $(OBJ_DIR)/e_nodes.o \ $(OBJ_DIR)/e_path.o \ $(OBJ_DIR)/e_sector.o \ $(OBJ_DIR)/e_things.o \ $(OBJ_DIR)/e_vertex.o \ $(OBJ_DIR)/im_arrows.o \ $(OBJ_DIR)/im_color.o \ $(OBJ_DIR)/im_img.o \ $(OBJ_DIR)/levels.o \ $(OBJ_DIR)/lib_adler.o \ $(OBJ_DIR)/lib_file.o \ $(OBJ_DIR)/lib_util.o \ $(OBJ_DIR)/main.o \ $(OBJ_DIR)/m_bitvec.o \ $(OBJ_DIR)/m_config.o \ $(OBJ_DIR)/m_files.o \ $(OBJ_DIR)/m_game.o \ $(OBJ_DIR)/m_keys.o \ $(OBJ_DIR)/m_select.o \ $(OBJ_DIR)/m_strings.o \ $(OBJ_DIR)/objects.o \ $(OBJ_DIR)/r_grid.o \ $(OBJ_DIR)/r_render.o \ $(OBJ_DIR)/sys_debug.o \ $(OBJ_DIR)/ui_about.o \ $(OBJ_DIR)/ui_browser.o \ $(OBJ_DIR)/ui_canvas.o \ $(OBJ_DIR)/ui_default.o \ $(OBJ_DIR)/ui_dialog.o \ $(OBJ_DIR)/ui_file.o \ $(OBJ_DIR)/ui_hyper.o \ $(OBJ_DIR)/ui_infobar.o \ $(OBJ_DIR)/ui_linedef.o \ $(OBJ_DIR)/ui_menu.o \ $(OBJ_DIR)/ui_misc.o \ $(OBJ_DIR)/ui_nombre.o \ $(OBJ_DIR)/ui_nodes.o \ $(OBJ_DIR)/ui_pic.o \ $(OBJ_DIR)/ui_prefs.o \ $(OBJ_DIR)/ui_replace.o \ $(OBJ_DIR)/ui_sector.o \ $(OBJ_DIR)/ui_scroll.o \ $(OBJ_DIR)/ui_sidedef.o \ $(OBJ_DIR)/ui_thing.o \ $(OBJ_DIR)/ui_tile.o \ $(OBJ_DIR)/ui_vertex.o \ $(OBJ_DIR)/ui_window.o \ $(OBJ_DIR)/w_loadpic.o \ $(OBJ_DIR)/w_flats.o \ $(OBJ_DIR)/w_sprite.o \ $(OBJ_DIR)/w_texture.o \ $(OBJ_DIR)/w_wad.o \ $(OBJ_DIR)/x_hover.o \ $(OBJ_DIR)/x_loop.o \ $(OBJ_DIR)/x_mirror.o \ \ $(OBJ_DIR)/eureka_res.o $(OBJ_DIR)/eureka_res.o: misc/eureka.rc $(CROSS)windres -i $^ -o $@ $(OBJ_DIR)/%.o: src/%.cc $(CXX) $(CXXFLAGS) -o $@ -c $< #----- glBSP Objects ------------------------------------------------ GLBSP_OBJS= \ $(OBJ_DIR)/glbsp/analyze.o \ $(OBJ_DIR)/glbsp/blockmap.o \ $(OBJ_DIR)/glbsp/glbsp.o \ $(OBJ_DIR)/glbsp/level.o \ $(OBJ_DIR)/glbsp/node.o \ $(OBJ_DIR)/glbsp/reject.o \ $(OBJ_DIR)/glbsp/seg.o \ $(OBJ_DIR)/glbsp/system.o \ $(OBJ_DIR)/glbsp/util.o \ $(OBJ_DIR)/glbsp/wad.o GLBSP_CXXFLAGS=$(OPTIMISE) -Wall -DINLINE_G=inline $(ZLIB_FLAGS) $(OBJ_DIR)/glbsp/%.o: glbsp_src/%.cc $(CXX) $(GLBSP_CXXFLAGS) -o $@ -c $< #----- Targets ----------------------------------------------- clean: rm -f $(PROGRAM) $(OBJ_DIR)/*.* rm -f $(OBJ_DIR)/glbsp/*.* rm -f ERRS LOG.txt update.log $(PROGRAM): $(OBJS) $(GLBSP_OBJS) $(CXX) $^ -o $@ $(LDFLAGS) $(LIBS) stripped: $(PROGRAM) $(CROSS)strip $(STRIP_FLAGS) $(PROGRAM) .PHONY: all clean bin #--- editor settings ------------ # vi:ts=8:sw=8:noexpandtab eureka-1.11-source/INSTALL.txt0000644000175100017510000000435112647061302015341 0ustar aaptedaapted COMPILING Eureka ================ Dependencies: 1. C++ compiler (GNU's G++) and associated tools packages: g++ binutils 2. GNU make package: make 3. FLTK 1.3 website: http://www.fltk.org/ package: libfltk1.3-dev You may also need: libxft-dev libxinerama-dev libjpeg-dev libpng-dev 4. zlib website: http://www.zlib.net/ package: zlib1g-dev 5. XDG Utils (only needed for Linux, to install the desktop and icon files) package: xdg-utils Assuming all those dependencies are met, then the following shell command will build the Eureka binary. (The '>' is just the prompt) > make Some systems may need additional CFLAGS and/or LDFLAGS in order to find the required libraries (especially FLTK). For example, the following is reported to work for Gentoo Linux: CFLAGS += -I/usr/include/fltk-1 LDFLAGS += -L/usr/lib64/fltk-1/ INSTALLING Eureka ================= First make sure the Eureka binary was compiled successfully. Then become root (via the 'sudo' or 'su' command) and enter the following shell command: > make install That will install the eureka binary, definition files for various games and source ports, and the desktop and icon files. SETTING UP Eureka ================= Eureka requires an IWAD file from one of the supported games, for example "doom2.wad". Eureka will look for IWADs when it starts up, but if it cannot find any then the 'Manage Wads' dialog will open and you can browse for an IWAD file there, which will be remembered for next time. Places where Eureka looks for IWADs: 1. The "iwads" directory in Eureka's home directory. In Linux this will be "~/.eureka/iwads". It is created automatically the first time Eureka is run (though there is no harm in creating it yourself). 2. (a) In Linux: /usr/share/games/doom (b) In Windows: C:\DOOM and C:\DOOM2 3. If you run Eureka from the command line and have the DOOMWADDIR or DOOMWADPATH environment variables set, then Eureka should find it the specified directory. 4. If running from the command line, Eureka will look in the current directory for the IWAD. 5. You can specify the IWAD file directly with the --iwad option. eureka-1.11-source/misc/0000755000175100017510000000000012651564371014433 5ustar aaptedaaptedeureka-1.11-source/misc/about_logo.png0000644000175100017510000065033212647061302017273 0ustar aaptedaaptedPNG  IHDR([sRGB pHYs  tIME?% IDATxDr%|"R?Z%OI=LF2&_1sW7#;# }RլǏ f2VwDjw>׊Ꮍ]DTVZD* (j gVUh;9 JTtM\]I1̈œUD$ }߭&Rr!FRa:Exo73f>?3SU=;Hu1__6Ԩ]MB x1LC82@]UjL U8/D{793ٽc$:"Xf&,,,",Y9___ jy5*:1PB?q=}o0|}|vG|! EV!I0jT%Dt߷G7^wzD%K??;}="_~ܽ N™nlgBt3^ӌ 73wwW1W?>~EDrD<̨x_["*,{@ !č uQ[UTޛ{VL2j3kGCn5GFtU~";ͬ[ɦiSLJ^KUr)`6pyU 01S+6@=ͶyB񨪈@QXU}oR0`25nf̕1Ǩʮ6` O&ĤP-,C,2*_D Udz* ddWe; ᮪I YwevJb~<~tu]YAE^Cq&xdffv7>&20  @w%Q}_~NSuͫw0$eư]#OQb"al3_fv&ϮS(lS13bWEÝ"kVwgo&^U__",c*8s΁{IEA%3}H!"jffEDc}o6ad`p_oЪz]q]vMV#䁝kk-iicׯ{E!04 TYy]W,LMґ2Y8=eADxclY3H33*<Ξ%ftKDAԧTyFD@]Uh&s}[U_94׵#U*"}<tFdfEHeU6Y٘c=؞$\bLmA&>#2*c .41{w3H2bd3@.:N(yxU{fCUcfv }bٰW,E`Dx<o)Ђ St4;2;Eݔ"0,ۉYGRf&!^Re`zMMɄnfZi:FG2*J~yyEq/tVǼD3ᡦ VDDE&ƾ)Zu=2΁VՈ8߯m6ȅy]s>ߟ r:;k*??ݛdwD1) ksݞ4lJ!5~r}R&2ט13FRw"adUh\؏Z#*5?K __l=Jϧ b&fi$fe%y}~jrv4SBﵶ|?ata{@5=Zw40-UP@1%T",~ۍZLfv@V VQdUl&@2vhGdr<Y[YTV(AtHPH aJOhp)wOfL`d uV"chGLqFYgwu_čvGsq\5TժھMATĨH&Fu3j}="2na);%L+m$^11o*I.Px0(? Z?%^H2@DBP!D A* &R"ҝĶLr/UUյP]E@\EtKǸjy@,L;M^E%{]ݙ$D_6Vj,~fUĆTfU{yeپ""gnbVBsy9142"U~2TLToku~}{$skϏe;]:p`۬pUsm|f6{Z;Td|(~}F: =EǏyܯWTnR`sh@T]c.:PmCwxZ+TuOWwa zGuUkcGyN8; uo0e罶!ݏp C(0kU0iWIQԨ 4{fHkpVus^%$CE+Q Q#1p7F.$Uij,1++2,;:[%2tUX.7|/(Ǣ XFιz2VpQLƜcp75S1|c! c[E*3A|n0Q֫3r8E,]8, " w2Gklf0`btﯯCT6V,#3F6"O9x#irήnhj_k ûY ߛp$b<|oY@aV0jTTcXD\cL1gU1y@9囌DfdDe R 6e6u9 -TKw1ڪ$X# }oܯ@ޏz^|XJ)xgyY/G?x뵖u{ZUTZZL,"qpFzHx 3qgƪ9lowc::DkGq{z[D fjjB|VWER`t:q_F SywDzî" {hJ&~u]]]YԭJBLFl3 Gj5Ī҆[(70e#+#ԲD9U& t7T`9Ggh4P&pz D$cDko;URt&V#( ++Y3@}.&b0g4/Ή^/5*3{'0 P#=$5/"ReBdvkC% AVp0UwUEu]EtG7놰vڝƃ$K|}+e|>h@cNH:ӘLm\GQDb‘b*0Ǡ!`3r3J5USux͢*:}(0c%x' tug$ Af(i*bjvhHФ:DbOFѽX{iHU))D&(mq=HH1UTŽ/;"WV32[sGmthTHCHET&BI5 3??{4Sp"mMjMb35N%3E=2BMfկ/\Ɔ.S9k ̊5 7fwvExW30c*M"HhwLSeP&h4 o cFXY b(ҩG[l(W<1?dFѹfD9N1^Uq"q?>YH"ZSq tdafU,|W;6s3Uwmfӻ %aqObHwac{gװJ:@F1kŦk׼"&"mb\@f >ab:QsTde6DDm[Q5:3 c;nzF2y=̺"*G^"k(('#sg1amǥf7Ъ[`P&{e=HOituwB2Y]~{zݏq]s98k=sѦǜݍ!lGdvJ~1jivOC}+0SWDchh]h1eшTs>r}Hk^}'uDwוݏke#\ƏKET@RRA]{ x/Sc"a1e&f{/UGc6kb*T?xa`óKbLDE"DV'!&ZYjvb6v6u7us_sʻY'=T#rBIШ尙ʬ* (ӜWl]#vfx}}=E!D讦>Y/ȣ@<^ ˿+rGO[/V})̑ĕDHd@%a@x~)2u1QWV3٤@eHvؾSYMH#ܝ@)"ۯkr:@ͺf:!ٙE;wE2}w 7P7s^{9 HUU'CFe3[@f, "PTӮn(֋cٍmciey !(L\}RDISeWcFf7نZh> Qe`󄄺[TU(Gkfss<{{/k!Ţr#jbn+iAD?uZKT l&wL6]5Ol>z>a&}鑕{ I l pܣUUީݦ  ]]UDVl,"pBȈf25coLgdE$>ֱ =8i!f"gWg%qn v?d6?TUO z-ۛqU5S\&}ZUk0p]WD9No& 5[d0`fĘ.#YkGﵩ(+߁QV%"M4fuΘsFId9.H"f8URDȷC8 yeƁL|q\OhE̙iŒ^Zo("4VbF"`m׸N|#ĴGf1pB1q!a6w‚~Wl"j".^fwje̢֡cqMDM}v)o.]L'ȪXTottx~|<}&&2KY:󚶣Dkjl% BP$uEı]L51e牲*Tukd[,2˩;"!z燪WlߛAOHHO T'DLE8`#@LIT{B*,r:_Yيʒ2 "e 5#U~<>›N8#k-{D !o2KU}1^,+G@.5STzw硫UbcUDx>魃𽖘>ޛ>_9T^ ",t!M{zQNpYN$y #JJtR D7;҄&%wwuO L|?(e^;^ݵ>0s>/QL<3oI(3U-3Sj,UUlfzǏǜ'ګ P a9AOKjޭ/UlʉЦV];B9#qu1 3Pǜg_>݇x է1MTĚBcZ{w&O!'UGC^@kݯX@WT! &&|=ھﷆ{Y.ZDҕ^UW1 :Lوϯ׉U6ut{W9/_ Z!a5m8RUV}̹ Bݽ2 &憘2Qz=WNB3ڑ$ujLh7@7?31D9TP} )sw: Pt't"*]V 銫*^Д az<9X9QWF@f5f@&**gG!{)MU<`2f*ذ3Pr47T5ܛ%"\WӉ{jE,Ӂ#Dvpgzp=O>DP=kjՑّA QEsW D蓜zg~G$"}/2Sk?v[]W3 cGw#N3蹗Gli= ! 娸dPԷGO21`Z'JDk-݇Y)[U[f}"@.y?DyX_ww#Ŵ< #*^uW;ջVWU  4wsV5QWLmw:$JL[t6;;w#Ehcd9C0^"RnO/¢ DJ7tldTE_e"Wzu{9i"_{="b&EU&B`{.b Se HH 4NDˮGFV%%|!KUO$nehuUJxkpFόUbE1D#A{3@^)ZqqPU^ i"VkT=toSS:>f#se_U=kΪڧˏć7^Y3L-O%Ts^)cK@mi`=9ݫQZ ;'rES "sp&jF]Lht!,ډԲ]\TDTGkZF{1ge sDsI9*`ЃNvw|Y_^$'t@h2ƛ~"#bӯqZQ?SePBL@$:}x}|.纰׾XEϥ{wVrUVYtu{yPUfU9}on sXyUwgޛw'\V+MX:8ݾ7QvIqA$jp޾QE T10{9F ~[|@{߉NU9璉+xTU,ki{yT%4U:/|(tF*}흕3"LMܙzX]UɄimߞ^Ťd)$_kw(^b$MEM$Bb*Fw= Y^"R oeA鰺jeΈ7`xg$M5}ϓ]b02*2N\άʌ\M?so$u-}Fh;@lE-G I3#!y4ЖF!F#Y,I3F $$v[F7RU{.ˆ'&&a[p}2wd=X{oeZ㇡`T9RmYL3Y,+e:\ DrrbO :G j/{dI9#r"9ƅCgRYh*kY$֠JY]h!d܏eAtD@"f?4!Z%#8uqTB"p!C?:r4mBnqMrSJ*%?!$NUq HW eg]kk6:_ȮuΠUͰs$8ם 8*3 ~!R=ܝ . :9䜳N|:'$J8ĺLu*({Y]& jsRI) @zXm#"c *1Z{WҽOn`#!,cL }(PIp.:$FCg `:C j!MSb \Rאs@ĀKAIj9CmW]cbEK%D#01-dR@@2g)0R4fDiܭ1C\s)QĸGIb0Np$)?SBm #pEIq Jj $9ZJ8i1( r$hqpIla⒎tu^R,q2 "!ej%0X:k!MX!Z@]'9,9ș`I,C4FKȠκTY'zDD]Jcb$;'q3"R$ӤcZ]^%Irѓ2ISTXfFu:c4 NjZ%rkcH," %Z'R0GZ!%0F) `"d$I+39G@(#F$c0Q \0 TD[ `LBbctI[+S\*bgKrzTР#)hKLfͶD$Ѻ Y9_`Ud8fdEnW~bt+5 |ΘEH"C\3z_e}aZ)N%;f2I C3l+@)cWP!Sws#sVxeW׿gp/{h`_g4fAt~p`H(Lf ,tك4"WY@DDɄDR{U.R1ε6iDSI2%9ZLJ闌,U "I uʸ^w) 3QI}4z̛ƈ`\ qaXr.퍗`3KR//I!|[3KCV 95)GDk ˯|rs#pv̷p&: $@ƢN 2Q#yoX.J$KLeʣ$NxIF-ߑsBHG(=/~ǯ<OZ G#z4~ u2 【nUn 縔aR1sk1攓oA!2JȮc.(~sW3e@sQXk=9H 8F 'N3)1McYѦP,8{+֎Y  _[wݝK$g " cDj u0:Ui<Ĭ#~uN]2tZ-yᝢ7[s#b)KU^_ 8B%c|tbGH!Ѹ6۶!oO?)o%(G8SBɩgIRXq5o+'ΥM_ȳL-  r#keeADit0rΥiA\ĺ `tlҦvm5N9$s: D\Ic" Bfa\3+\(/ֹzmr{јj39t˴׸A;N,џw^7;ygp{I._5V(/^' wr n' |o~ns{5,y8{q:뀄7_鲥* 7WS ###6 mrPԊ~bpFǾ/I {sEGSҗg%s/ҔRD9a39c?oocyzVmod26-Nt53mR!v.8+[ae$Lͭzػ:jojϻ_Z4<08}l//|ݍS?s6}g9+2ƶmww޷zCy䡇 7q*uF2Yc3']V읊fMWBu¹={v.;mdN K6yweɬsӣ'w1Q8\ mRJ#tNI%HhƑyKswq?GGBq'>9rݑ^~nk~Nxtt:.QG✞T=gBIq3O?-T ERT0xwZO鷝 #R-{ '&[;f77r,3R\R;wjӕ|7D\wu&TA*j5\+|ˇI3GFo~7gd,_?5ޓ]eF*1!D&R kY,;Zg0 :ǁ3/G?tcik&kZ[D$.[o,3;4s$L=;w(a۵H_t]{MnpKdߠJHmc~e|Is}azcffV毟U. sL^}X$@0סT O=ԁ;oxLqФF_{mcmi hii Kqݵ߬5W#(Ɠ3v(I""c0 CL{8쎟ǯ?dz̸hF^hIP+a syC9s͉y~`~fo(7OxɠT:r-g.[Vܹ;.~suř; 7_J,D͵Rn,תvQ~x8z-ǎ7 V%k+rj]w'~]]#R,N.-^z\n\כȫΝ#o`Br`\RrY}P[NK]7]7>zڹ+N? Ԧo|,X <]wr卓A_i]熂kĉqk~h͵=}`RV؎Pex\mRR/ .\G=׿vZ3I!( Ƚ)5W zm趐6V EURt HIKCgxL&gALh,Qw?Q܉BkQ, Kkc{w {Ra#!8Y|kyy)G ;8صwo| k9./?G.V]3w׿;zҬCaGxm EEKKu_dikk1H=cFvZR n7R`i'jW.\PɃ##k,+PJddzWDoՃ 9 8 9/TF'-Czpehxy܎?20w%H@IHdr4Eĥ0L{_bZ1vl\obd% oG&5~0}PJZs߯mW&&[p=x{T8xӵa)wO TiUciD}P܌&VGyOfm+T+yUi2C?˛Ã];̾~|xd"թ-ͭ,LNNF&76K11t&Ev7*h}~dx1s7|vT9X_Kf;[i57W[[ZV봛IgJk?=.ˀ;Pb蝷.}L,uijf[ |+\ΗY6tmmTal0F* ( 8gDSDyblki81D T c=oh̷D~ 2 zCrY.@}}Xno֭֊Z*9m9Il< *L/yC㓞2;1 Wq?SLK0MLJ[tvqpG)^)KF~ O\[YCF'zzuڽS;|gf2$`Ց_nLX&O'ݾ"#B.wc̽wwv5fPY\.QV6Z.+kܗܣFt>rW?fu|#M] PW^{j2Op)9eVqwNdryijf[d AdV;IW][[:M]Ŷ3<_H6ꭕZ}njx]Jj#r9cmLbsf G.7` j׎ JMjt:ܼ r&77;'%zsnq8r}q|OI͐F!1>tۦqR_5ČY<&ӳ.b`ڥY_xS]Y[}B!/1&k>y0ٹo)@P&X[E=~yn(;;w?|"ׯƳ.RvZ-k,\Vrͳ3?zϹA&wX娨67+k+;kͥL]_p2^Z8fΞhl\9,^3˛<6Ύ}{Z:{Vb W2eM7\\/{%_3?|yokkkkaTdI(7:FՑNy OJf#%h8#C3ٙY T>L281oץ Pa j?q!*G_qlzu@`r_ܯZ –sKr~^ضcxҎnJ sֹJ{ͷs#\7۩N燾i$mlj*yo0=N9) #F^g-͍J_ɩjn1xuʇ%9${YC(z\"F$ Jԉ[Xj9 9;7} {WDɦܶ Y7SV}R!IS456Ju:IsCWԛR!/4:wb{sLAF{ﴕke>9VJãg-xL>7ٽ{+F-`|`t˳゚;~g׾fn~ k#K1r{nv90?3; ca``oda8:gku]o_ Kj6 M~W~ktWK9|w?ptʅZ㾣|[n\ml]ި#4ɕ#M Vq/u[n*=fy lo +57hm+޾r_0ޚT벅S.P * ԒnngȞɹϴ۪md +oΑZ D˵Jx77.\Ra>m%.[Z웜xsqokvl\g#iB.1T֡R~' m4WSV\i+>(ϓan$Gu]]\pΝ{D~hw-e|%4DH]M[i0q~VvN>r6%Kw}Sz/խXCۏ<7נ^}h`|L8x |FFo:<Ձ\_7ll4N Al.ٸ͖ڬ7>X_y:6_=y?M}KK?G8_(UXܸr/U{Wᆃ>xsG>d=~یI7VWrTi7?k~짖^~ ћ@㻃Vd=!}C;5i <2*g :tHUo4+H3u7}fy U ؍VDH; mғB/V BigfL7۲4`ӂ SU(++C-{d<;OJnFB_~GO|xC& vQ|♯hIbE,[鞨-َv[3Tg \^8p4Zj  2ET*lh>0>bT4j/n%|.MZ)^9ozқX{01Q^J6?~cq/9s7'^y!nwbr,l]Y'^:5~o-+_.SOwokJ^ j}{W^ܭ5B$1L81f>js^I0KY6,VW_''S(3{&cÅفB!ρj6k5R bk!.}3kO^|ݗ_իW7'XuLYI|(8y׾:֥ő@#{iV#k0 dQjвD jbv305{sW0$ccgX`; vK)HTfE#+Cݟ%F`L b~ `^֜8aZi!\Fٗĕ4Pq8) fH 'Q}i5T̘)ZZI1Ɔcn5_3/38Ef﹓OʥJ{}{30iGv{MSeVSHն ԔHCZFFE0k,/.6ňb.O1DJ ksKn |IfBPBc/N|zF'#D0Aٶi9.LH!2-Kd!X3gxAP Oر0,ΦM-[sڪCC cI)4RJFDTֽگzega#S*0[Ċܷf34m[9jի)ݭ*%(.[ -Z=s_dK4SX_'f Ggl[4W&@j& BIFK.!N*X`"E'N i(m08N$٪trw1S'O߹}{#>l~vvtp7cAD౉(札mlݿW j6I0pR^N !jFdz{s>zǯ1y-nn.~EܻȡVQML~1ŅGۻ[f׿`F蘷|tg3~,;eIb}95JZ-g` @)؋fH0 SKɹHbV,RDB6U_jOy^:uw9rpZ:zvVTQc//"Mi l(;*bAFkL+qljIDBH!(GLWhSX@hDe)A޾}CC?kkw, *X 8y̡g^^{P8 "/h!1Ĝs)UGxN)-85#ZteM Գ_T\]7%y5=O2 PBKO0"PYhJ|i\kBj2@3 ڹlGԡtRtlb(H(ڥ)bAK[)k%!HƀTZ=sW_z}hxmu=#P nA$tygRe=VHqgʩaivBR8"dDKʧח$>4FmD~N뻟s:_Zv{ x_o}'zN-#PG,oW< 'o0cT.HonU f2ag|gИhZc_Y-`c~+aUC3(=јX6jnQث{ў޾|kkGw^+m@` ZA{qM uxBRJu+ذ[CӀwi8wG7?-yV v|jQMBM12X)T'ο?Ä- ;l4T&Fv޿淪'~_wō==o~yYOot>5Xp7^gފ3:>S|ɽb>50v-V)5rl޷Z(΁:|U*{}2p+ 4v9n#F3˱\.cY w~9Oۍӧϼ[NB>\Z8utB)G<Ӵ?`)g3RF\b{R@raXvĤ\of{<^Sc(9(-;a$s3 0Q`80o_rҒb0`6D@RӧO*^)(XqOis"BcA)Ti \w{~cAh0?? ^[KwܤϽZm]m/NX"H-)Z+1%$XR)̤UPRK}}5#R>nKnI\pt -6p'N;+[C#BhHf@)MX,K֝_ohtЄ4p;"L׉sێۯE;Z Kl;vG1;~` m;BQ\pk!V D1g#)UJa H x]]f}?ևWMoV wL{x48fb&ZvgG cy~ѕ+MgG+3>ͶӝIY; R_~mlg,N@صs-V*C,ȓ:cí BnܮUkxj')' C  Qϥ˛vH H 4$1)\) *'czy'GKu8@Ja* וf)9^~wە8]պ[iQAjk @!ȶ /Hbst kZ4#LLP{ս6wnN dI4ehM_~&g}r$yAiTo-V7Wd>,MוAF< T$eYKJhǦejH(1|yta#T ts ECWݺ3<=|^gΞx v}`ś7NNL|_Д=2{X/eQghvl.ߜqҕkv:Blgs)Pc=݂ َ)m5Ɩ [e7]::w0cTr#/}ni3>sNjlmf{^!D.>0:@!m7) LI 4,$i@1gفv_^ 8Q#%\ES-vzD.^_oz+;f Z:B4>T7olF I)cٖ WPwxJk Pݶ0y olZuwS,+V֧ϝ 6kV.QU!)vQ;3l-! ˀ P0Y lC8GE^[_Mg6] ^\TRT7]]jaJi r+LYaP( VW@@J?*mM0ik2/z{({'ELL;o.ӆpǯl'6LdGw4MB(Ui>RXA/#$l;igt"HY56o;nXu늁,3pJCв.s LO韞>wjoyuR?vtzD2"%ALLi \YikЄs20vzz?ka ÃO\ڪz0ŠA!@k%$QG1Mbwiݑƞ8>zȱϮ,ܮ*cJ)g}tMGV7wpSm IG؂0V\!A0W@k`*͝-J0Pئ],?<xw)8з{cn΁/-0]_㙻=<7V&2M.iLq'VւS御;3fLOLw6W>S]ye;JmPo֭Ru]{wݩW' °XܩzC+7CӥKnKK Qպ+//u0@F~@,C )[nĐƜII: =m=plrW>s7o <|?|7ט[ͣ$n{'5 W6cRe Yiȅb1;o7,{y}i}^6_n R "jꎓBdض`drnm6߮v.qgZfRZÔ#[YHvf-F]jn"BӨo|z#&G8}osWrnWA6fFfٟ-ٲ6-O{^ԗKO*󥩾cI{cdhZR6- c 0%D*mP,JP%H Y4ree>R=q,9(ܾ^cv7S偻ƤE + !M`AHi쨎Dm,0ztkd'Ξ# nͮɩ/\XVN~o TJaB)DJixX(џ,pBKT}2JcП-looL#N~7߹{&H$?5}wܵ9~Nw}ĢbOo+N?[Wof`%W+O>o hςk{[7vnD+6 Pzum)qaB4ZNve(ePԶ5BRJ0"C~`|Bc~}C37/|7~[5p="?:;M&9Y7CilƁЌMdJajĥjZL潏? @ʅTc?uD~X~ ?{o~u{D&\T'RI2) IDAT!-+bZ{߿HRi3۪,qZT? ["#%4+v'"pYRRP$Dác|soX[\,UʸPł&t4l2gb3CU 66P)b%B&&(AM`LP+lr7wTCC3wt(V {L&#`8_*rC71F0  Ț81N RR&EQCSn(hѳ!І34ܝIR&д-2ګiRg@x h>j`ƜRjfZn6p7WB)nJH0vP'+K Aҹ;$J)$%i 1ѷ_q$c} &h T2]mm&b%a&U"u0!m8V+ S]EvP nM6ع |֎Я}NQ@d _/+~ѥ奩G|FSOy',G^x|۟uQ$Nʉ4\nM`'N,Χ위FZF5ѻ~:TuGuЂُs+}_GR.<6ҷ#w5v2Fx:z`ށ፭t14 kMgw7YRI "PڲAoE0ǡ/)u9;wsO[vF0]bAs}'Ύ8m+hMyXnTMq CϝP]yI>32q??ࡾѩW>Z1ǎM-+5'|)NO$R{n~r}./Ѯ?g?ߨ=W(uGG}^poG|FΞ?=7@bB? 0ݍ8KVn>S{m،n4W7ҙ/|κї ˜8O~}㷿}S|rg^WSQ-@mJT hn8oNαT4% -_govM#0@(k%9Pb8WsȤ&Hn\dJH8|ǩ>@2V4=3[b2IoFe"[fJa 8\|!erV5Q(tk{NAd;.[bkvv}~(X)0T)̥i`yo7RA"fXm~>5Bar+עV4!VFa  K(V{%[^w+啕+_\Atl4|y bBHr @Zr) \k%O!GONM]2K3֔[ݏ?m≻.᥇ё'tz˟_>}CJ h$1vSvY_X09͵aAb}U"" {55/8ot>?B gnTٞYpM7>VV4a>Xzo;[ȎWs+|;ݧ"Hڍ`:-MRG&C 4C+W,G BR\j&l=sV76_꫇|?xek.V_\~置\īϯ|\edB->Xv&_zq᧿^A+p_+/ꌥ5MQcD, )'m՝@&eDEi]ٞop\KNW6~r00=qyp&i/q[(禫Bmc-Ӕ75{{AQ_2z DHl[:ڬE)  2M`"5l Q% KPǏFn,V'\4ע4yNF6Q 1$P2%$ډ8W?[P)Da@H8}JDl3`o}h(MNsT0`ű)GXZr+W9xzD K L dT-v.V˲,`s 0T m'tijC? 'bZK5Z?^W$F1L̻c ;o%%W9v s$CeGRqb~##۟o^݋װQ6cRVUkI%rzaV"ϔwa"P 6Y(u]D`hxxM"QTB41oq.]80r ^y -Gh:GG `)Bw$!qqg|wThܼɏ_պE{vׇH½$Lm|qm0 M5Pi`:TH+0BI DӞ>4;Z]Wk[ߘ}!n,?~' 'm_Ÿŭ7F`SONȓ>QXYԁhGׯ]xާorP}`X~m||5nN7C#l[ _lE%>X )9{;VJl뿛( x?r߃žIkUGHXZ{{IAHei?7"C }u3 E#(ثZ23/޾uc'<_=_xՓˏ7]0>0G2ҭq3w~;;WK_gDJCh$D8,4810, JoI?yÇ?9xqS3_x݅PaB*Kɶ+SνV=y cL?6⋿~F)%fO|ŴA++芅ݽ]Da2L^q@xaG)Updlxm$mgl]߽j{GcN^Rsһz?]˷Í*9&>y/=<40Pxԍ.pSi[#q!'ƔH}inm7fܕZ{6<ǹnmzTtUD:H&=;w^^{ݹ9Odwߚ=zhRsY^aLk_W{¯n*utp5)ªJbyrjPJ<]-̨DoΗ :#YiZ,\xj1t72ウF:*t-H##Z#sD7Z{gb1ޤ4sH!)*C;&z^YA ?XXXZ3o8??Dq~2c:P`2i3=nvl@XOU-ѩ.>=66>m{/`Nn\Q!bC<zNu\(d2%;^Kf@3,Z\HFs΍ N?1[f 9āg!&BRl~+|W|Wrc Ko˺6G?rK||s/S{ٿe𰇿Xv0;:Fd, &Ow|cm!A[]X>̣4Biy=~w.::$\ ^H\鶚Z6<:;-dZvllLs1Lf`S dX=İN3'FY24>^.U/yL> Jk"v1$eʼh󒤗fE Rp׭l۷੿uO2PrvCT.XIpT^ʖs:GC"oAEn!zQ(e ()RfSgAd,#Ƙ!qlIph8T`. `b2v,Ck„_(V~N*i5[ҷ =}aD+ kV+T`BDk fm7ZZMY7g\=yrW;Џ@` acE%*[БB?p} 7_ٱ>_I}ßɷOmO= r߽`ٱ[&gx;چTct}uHerhA|^QF*4<ܸswm&<;q=@M8\Ql$fIFtt|ʼh=kZs{vHWѻyL μx>T[N]t#?ZU|??Gۉ=K#28K0F kdWudvh{o~vCɒtӢ\xG_xEZbYq,^M.avy aQJRV9%(B[(d[zhԗV #[mX]OUT_kvl_^kͅ8:nr GQI'Rv{8Qj#r~/K aCcIȒϛ>*Rж6S*/A+<_+mq1`PypNTsQkFbcΜ5v62i/U *∌kD 1Rg8Iv?TiۯՑ=ֈ PJ1FP$@ŴiVsfrւa (RhPTpw%AJR.Sij0.-.'{a:gqI)I\7맹$z:R1~¸o raR@iCS!'!q=%А4*ONX>r!u<xiPc 3LIxVgV S$w8l\fʥ -ўvj+K m[!ptӭm]; bK!Q EzX Ф2 Իv} }|@AEbRt 9FI.7:wZ+.jy} F>Ϛ[J)&owCc!g8Xd?ϕ MGGyNgW[[sxTՓkW#ݹ˷͠ о0uQF|p񭣽F+WjWݾ|Rm C-㥵De{vn]YXz-ޘ9{v~=f=xO8, pښCH*I)mimhOs{ϦY֥ ?{nRУOoμn=[y}u^=E󅸷Q#mlT,4iрB"BV7M;2yإ=FK_sŐ|#8r8i:i#3[/4i'GwrCʚg l؃%g~C0X"@zVa#Oڛk{gfΟyꝵךekw=/B޶zl2IRQ& { ]ttW p1c.֘$Cu)/RZƘva@k}Ƈ7VWWyJ2iQ+#fVn/TsCbYgialŋozxHq@/`bmEJlwV wNڷg*~~>P< 6|i66no>wZ }۫5DoR[B Mc+ei4I`uWZJƀ֣۶mn.ߺz䱏ߵWV#}7‚bcs .Rc0!g4gc#9L1Ů֘szmQ>3s.nB?8 g柵xS:sqÇ{ʬ-J gXdy i!,IYfo=[.WZIZ-¨rikB.94i\Zwg?Y;N jĘ eϐ'uF)=.Dk'kj$4 @2өnܼrkf=ݸ<5YIxgaFkc=Oi5^x2k=JK?vѲ|c E03y=Q' fZc)&WQbLHx♙U)36nb.o2J1a4xڭw?;>@dbŅȷFԣ(υ@UsI"W?C7OcƴRIW o[N۽z<uRg1OjRJlo.5bgMdt[il|saapӀToْs4,biynkW 0i-,3oܾ'7yv ^ @Zk)؁BhcsKsC+SC` DĂP 8KRJ9lah?wG>HB&q$ ND0q'sM#;z%J+"I%X 14m F;e!M?KB,va B )Bqb5XA {|ht{?7}pnht;W,J09ܹl>oщvm6+@!(qyA'0@]\j w&{ l z#6>{Ž'=oUP#| {D9` #q`JQmUNۯ0X᭓V 03 '?:`V_^k΅^.wz6p <2 S Lq{Zrcans˕_4V\)vZY>zt-1ϡL+jHBfE98@T帯h HJ)m5QQ fّr憔v`m{j\*B^qn3ĺ`>mw`}c{w{PuԆ80Am,FD*P&EC b`O!BJ,8pȂ%Z@RؼCFG:/y8#JFZp}썛yZ1*NVC]o\NPX0Q.<*룃R9)%cO܌Q$2ƐC&1ƺf4z$4^=+ Ɔ2M&3=/RȄf4d~@0P%^ygvz EE$S! 6waιchq^02UZc}C!xLA.yLBdsSX#N 3 , J,G.T*F^$@97T~GҔé.O6)gk9slA[0ZDiL`3i޷/z޻<ť9^*=۟Ϗ~ͧ/W};w<ӯG/pњ`#j!/XZԟq\h; lɇu<_]XڹaZc"kmE B 4RD%MjFQ quƍr˗.cifm`̃8mA.(>>'rɤ(c)u/&d* F& Q Tk8ւ p fb}`;Fi5 Ʀnov|^EA6hRܺsg^OKaOzQvRƸPn^*O偹յϞ}DyjOs6lsCY5Z9[ <"0F) 2& eC+3J e1(V^!Սni1@SE7 R5rNjpGA_{ cX)R:gZ5u2 ccjJpZ1PJ1FJG;>\U_hCFm{rg;vnǚ7rz#ZdF>PrF01u&`}#E:((`<2BaGY`rbd (g 4V9q`:V40iՆ&GW뇞xjtV94+c.7G?_ﲍYe Ok*Ӕ%`Y&8'8!Xd-FX(c3EO ?ƞcwO]}3{l=pǾߵo.  ̴f492|7?ܼ*ܟ9ږ#e(m{)c^]vzà10d@X * 0ň 8<  ~b}aQ鴶4wͫ:`w:J޳{>vOomnp|pi}ͱt"K?{dzbf>tZl7o.-n?tw/^qo`(j lή*p2LIRGA4M1ƞ(Yk1%pIQqgi&~p'?)c/_=uҡCGxW*VZ8sn2:eollߖr>XV1򱔨zԊq\mB>78gAj5FFZ 0lkv׊=kaj 0,)! &DKM0A g)8fodni|px{~/թ2ccֹ\ |MJ +EN13\`t~`q`Bk8f ݺxa/ CK8Kb'KXk RFaNC1d &CځT32@R)5!X*l}ݍ뵫R*kLT*iwb9&Y[kfRy^RiUJQ:8B@(uRIι5se2G/n]w5Vll䎣w9dlRg8Idx/H1%x^1}71411ak9c!OP0TA8!QBp3Fe碐` Nbi-cL)wRe*O:Nym]ƞ|+xcF>2`MKyxUW닷nuQy~ *ԛJwJN2eQș{O\}orf{eٙӸys񵓯._j߸W>128-JZK )jc2:^v\= BgQ8mg{f0 =OϾ83OiwȎT6KKrOK]#5wJ'x}s'+[F7I:Q i\y::D`3@1u98c Dif2vx,LJV* ~w~M*bкX9|`57ssW?{?).'فGDŒTߛ†"XL2a |OvbXk$|^e捅ß©wMN-ި7jGÅ퉃t~}V$5 )ÃГTn)qYCOz/UyXM`fAsrF+x"e>CE̷asfy"KUaY][;{2g@dyéU92FA:o!()10}P!~]Wk)`T\$-/b^Z8;+/?;͙=;ht(?<]pH]D'cJL8,ˤ1Ιy[읰T9d` 8 #[;\ ?yk|.K/|g䋓?.ݘ_qpy4*cy֭(`l93 Ohpژ 2(&vl0Psd6៿}[7ך;8u`x 4~1߼7ӸD:V^8R` n#4:q³' Ih€:10%Jq``! 9n6#wm1ھ1 ﷥(Ƙ>Nc<0r^Hiqf%wE^S[+lŁ9 Ա~z2ZBr6}9osk1s&Kѧi@NKuNJ~Q>Ɍ({i16 s ÎYc080Fg`M?v=(e$_}Ruxl׾zpN^807 ^RΘ\i@9m*E| M%os[?䕟t7>6VfsAtZ@n׍6*hN+\eu~"^n;v$&q{ITLV[bccko>ӟR mr9kFA9IT+[^ 4M8fgq(SO{?}L 9۷w>17;xzݷDAZkn_c%zQ8 ;6齻ݬ;VKO]8|W~969=2umuKfgZsJ2N c,!;W6'th'F,gޞ~~ܩ}yln]'ݸl^ֹqݲmλ{W_>z9A{EY/'~|y䫿hom=?ꕇӞN[*r2s]{ű\YQ98&j ʤNk 7lSb[`a1fÙvlwjNQ$2q'_ڵ7ė]rۮY+V1q ̋|'3S9gL/iQ,,˽`c LR$ȓMfnذ!51`[%kh[>u8^;לڪwF7MFĩ.d<@Jn;w!eC`'džuV:XK3c0!@V[F)5~3DADI@jN T*vڱJ|aԩ4j&"M0jPAXQBN1&VzNݲoeNEcl k9wV݄VX9q*bj 8$#¸1=0Cy20eP6I}rҽwm;-^{~aw߼z:w+2AJ#F`AkB,ъTh\V많VFzGg^zew8y uiftʕ+/k!svu׮Kf.H4|^F ȱIQo)WHR!(0[cXK7Ͱ1`(hvި2d\ D$2JXHz|Y:l !c҈͵چk,>owʕ$@HShcXR`SWnJ=ѭD.;~|yy%Χ&֠hc i|B:N;\k]f?8G>DpY_x|P5rF)in3^X{L t_86 q"+V7 q]?mw~b'5ZmRLhi)K'dhߦ(vbhL~Ўv(4X`T j[0=e\1M,KaYJRJRq\?u%zq$+LԪT*1H5]pA9:=BiϝfScZ+gbd쌿e,u6b ;  x.$m412F"H GJǢ ƘZf/7ʁNʹ+m۴IRJ!HpL\ʔ݁}?I Rm c F'Ik>>P$-uk\H-Ƨ<߿XͅjuSشJg58ALV2rz8 $LrycBKj@8c&12$Ŕ0pw36~JkPЮûT.#rGb1Hq4f@Y,6d;v¡s/$ 'a%ozu#.^w=?eiZ`'B'IH)`(l%gHQ*NNpt߃_~y6\?~L1mכ+ht(ccOgfW|ۉgxy^l n>{_2 ccHԖzi4#?uus$Pq1N2(f=X[2 rtR4aR4wG~N>D?po c `$IDo?g1bG!,92Y3\y3YX,sў|/_V%*~}{\-=yv0!p9A*-4"\G@V>}ק>}_Mo(^id4BP^Y{͍1?S*Cq}Uhr`ddT;J "`4rsMae8w*&'Ϝ=-szd0"ĴUǤn7QR Cض Z`zJW IS9HoJ<|ޡLz7n{?=w\uԭw/?k>R6+#$Jh0b,)UZk$uHPG:OIg\qZY9'NbsR8N'vj S8\8W3Ƹ}i"tU (lW ᩁ NjChfg'AJ,1A5Yϸ2$}_])ZX/l~vj~9[kgX^ǩt8X Kb7?I_{쩹c"ܾez2ȱ>$˒K8pBʰJL' SP i3w{NµxM 3sk]072.]K#mR"uNi"ƗXc7Dk BwQeNW!aN"@~p]c{{GK˳::M+W.tjscg]Ns1T#Hf8u!@kB &Dc@16owq쓫~|rc>\cu}䆤J=KcN c!B$aueګB,_r鿸yqN*pF$۪zOG[ёS^HfxKbp%L;F)nnu`a_rZ)Gmǎ,({Ksc}^t89`Epά`6IRq0BHc;]}q]g PVSFǕJ 87ک7WڿD'bZ$XN(D?[זF?_>Ϳz,'S^vxFh&La,uXVfi޸/c [ UU!u>;Ꙙھ'aSq˶Ħ靼8 {Û\Û#ѡ7?ίߨY?Z.7a(5]-98:^7mzׇ>s0|x*(nJ~/-OҶHV*-asop0^loyWSJk C×֨xezCvoL=SO\~W~u~682 Omӟ[DQ]jfU~HSp/\2]Aֹ]\?#o,k=թ5JQ'.ƞ~?}vر`Ӷ]߱z5s( 86íifoV*Xw az7n L&s?}tzxI10d50hWWVc}n]˳;0<`HlUZQJ$Xrԇ~3\TY[3`ЪFB%lU'vkbb"LbL)al`h'y/}2HBREOvC.(k%`6ٮ!L8e=kmP>Rѵ&Rb~3{f)9rÝvvW$J8 P.Ow6()1t:"i$*) IDATB_c%'Ҫf F#F%"\'`^"ŇRS1 ;ʀQSR4N|"nZM=7߉cSަ5+ s;erLp֛;~kšryeT:*62&YTIo9]:*ŭ7$ai HQfh{}vMI RmB=]6i7h]w|/y a$].߶8+!Q-}/=1HTx[#Igw74vlefJwՋ+7 >زgg=Z}?2m܌.+gSЫZ2*ab:G>ySGȊԉU=-[0^ʂlfH6k5):'UJ8xlCwK1_9/;k噎B$O`,@QwD,}#:Smϭ9Hb0+0iìn!e$@83pƤ1Phß"H1,NK9HETpD ؽn-xC>vY>TMhFzhoG7WʼjOM?m1.lɮWwfwOn|뵯<7<*eHJ]Hƺr0.W.`bc80̎e ^ݾgۼ gNōfێ'}e͛wM0:"0r\" %TlSk!܉#V [C%3#{o^=E50XDR:L*(a@Zf!X^\Qe0(Le7ZuDJ`6Z[*0Za &ĉ&v%c1]۹T{RaJ0:;s,Nxw`ymm ccnY;wmn5W3NϿv:u.&YjmR ιҒ7T;3N)1B$,%'wA"Rckcbcf֫9˖=Z(%zǙBo{vmڭoS_0|3uͬ 9]3LQܡX7V1easןQz8+ggo"Oa`7o۩0NgVk'D<`ZFk4>/dKԑhMu-Tpk%'C !h8{ N1<`E2- OM͟_u ] O߸,3|g&4XBrꞏ穡1/~%d,Eg">v:u\Sht"m7 Nfvl?k4,}׻<2 uέ㻷6G+ۓ[}O~+?r9`ƌuB) Z(FЊ$t#Xk)c8!FQJ0&x1J9!V#B0ZՓ$Gu9qʨ=;s9 Pjɓ§׿5]y7sZ}*N!Y# fnkChꕧ<| ΀Z5g=MGvX8 ۡҎ\5\TRj{$[mB6Noa4&1lGn`h3VÛDl~h<¦+0Z%B}qQjpY[ƀÝ\Q'lɺ'qB8cBҀzF[DZJJ58-Z rN9FDT:PBMo4w97aӝo[Mv]"mB(1ҮٲJq w٢#GF^pQuV}~ޚ~2U}shg''f2= TĀ]PwNucd,XF`9""Q#`Jc c#DOk"l E`B@iBHnbt1c󚥵VYp?ؿwGG7z{ _\w{f/: yBC$c"$ΐ/"CcxijўOW+wl2;vv++nՉ}KTJI2T[aU¹}v2:Л___QT|37no^5W\={WTZ8SW.m@DZRJZ7]xz.Αϯ(b"Xq02>gʵEУ;X :;ގ3o=}~o?lT#t (CihvLH @B$TƸôJQjP@PɤJ) <7QsEOQƂE +WjoFHqjvZPt}O6E.%? +*Jm|pR`q~q@\ DLQSΘFcmg //)m62hjH"u?yvd䖻ػif-UᆭkcjP@026z3B"FGeU7Z򝁁}ozf^>3X@эFKCwg W}U$¿2Q,7wm}'1l瞫L~_6|֯\dVDx֪ˋqim|C^ش]Z׭F^Y]=p+Oo_qtQ"@O~ك[.9KB[Yk6ڔ9Ӕ)&5-/=_=y؞;_8nbqmTTvD_+U[-8ۧ6Xk Zc ƄR !ўX0#;:DJìL2Lʀ:珽2B1q=9Rc)Ō{3Tܽ'f>12L7r7r3>ydC7jGlU>#;`*7P %|*OfZ(Fp6+c#:r~z)HΩ?a3=:1'&𹤉Y۷_:AdE K!L)cTe'?xC(5/<}CvoI%@E!hmB@ ^Ek'IĠۥZʨ$Kk44$=lF[hKm]4X7"j}^nsk-ƔRZKCc! RJcBcQsĄ"Nс{o_ =PwZ>r^_- _عaeR)[(NO..[rPНN&D&H(IX&-0(Ƃ 0#0D, D +1!Q AJ 2BkC)VJZ-X) #RT' hU˽~m,mL]s/×?:#:A"99G_jsDXC9yJ] hud$hҖW'X)F4S|w&ݸ]nJvlݱtN7Pty[jGrI^VgGm:whci97ܼl0.@Fwo\gvl8hۮ[o =T.sϝ4c_pC).Lf C[μK/l_C}dF=NZ!ز98b ߑ޼gϝoM8sJ6:I0=y~ܨ\sO?j[6>R]-~`V)xظ{}wr׾L\à?OVZR_^8G;vn@ݖ V䋖JG :$ر`iDiNT1AEcGjQChhƪ8Ϭp ~91Z+BQ6e:jtIek2rO^ öY9vޛSlzpc;vl8~$hM߳]^>.j"WmSRd(,Q$ %]=в;ry~tv ;I^+e {Ctf|ۛ&ӏ:ُ R3 p"!ޔ͆M;w%ƶgW`#wx8=>UZHWW_*tcV:vlk锗ØX#d6Fil,%VU?Q-oz={xvd۶H,]~KTu$$r) %oRK*֜m,h۵?1Hc-@`YkI຺klqt1PBDgsI+I+Tbo?c^eFOͺi:Qu= CG_<''{z'cK+MQbɘ@GfJ;$#U(MKRP֜3։p (c4: J !L(371"BRB*00 McãN*#YT'^x'~:t+; W\槫a‹ɥlv]:v㏖W(ʍF@Z%:v/;][)ݵ5utKgy@#uœoe}7y韞p7_}>l-JjN: 8Y0uR1P:C!$}!k|N}ץ))XzZ ccMzx,J)QHZ̴E|dXJK6ZS M>~<A GR=3nBTZR.(u>j&RcۈvMeH&$m}L:_^`jdx@]8q*Kk~̹EsY@-kp.\4xmϜs ޷-%XL)`,YiMw"F˒9,՚{ bcm5cQʼn%Q5yPݱ0"6 r<79li"mXeuJ[-tܝKHůK 9Ƙz#Pc;%cҕS荾 JkRZi 6J&Q"Hc !D,Kzyf&GKnnغ)AP'WT^Yþzai-ŕHS 8uF`0$Pp1kׁS0FR&P*ŔsFF[yW?%nǂESFX`l.f%kivlei>.}^7 b aR7  Ōh ĀUF1B9sdQBG40?-wP6eW^|գt!.WDt_}Ov9rb~m_:f;@1M}i\Rk`q@&pYO<-޸kkGj)Jl t\ G+⸥X@Y)7U)^sD29cZEC`p5̲29gʚ`GÒ$R[ "T۝6Ji%MׄC`D7.<~`p8zz;R^|WQaAIbI9DlK =@QZo Zk8wC0Ji⹎p1a"6I)%D(]΀)iv[R":nkaݎGjx약oZ0)TЛ51.NwǖϞz5եӕvۑ t2aؑnzjGTZ*\J&J%BD\n%9T+rff0,":m_ ҉H&gWW8yn-fS =pRRp`Ӕߛ|KvzW CDke #a%Fvu] xTGXx#5ے:g^mOq/8sثR)47qf\ JFFV+`ptzҸ^ZvM1}?M:LZ`.ۗ+ZfpzGcG^D%]7/b :$ݘdZj6N T:C,Дmse(xWxGKvܕOco'ý5ghapKĹV&iՕt6lzӝqTO!^~}mʩS'=mٺMjq۔kxp8ϤsA^*eEGݱe~DO8_N~㐬-h+纔)aRq9c,89w#ixpwZbk9~ZXowZb#Ck ߿O_[oz*p9a8ط+SgH1=!4Z)).LӃ7.gߔrIZaLrcյD^8x3,o*jbA7̏,ocnTǵ냑QGpŭV󌷴]{99St1 ܣ IDATBQAKI5yMyF%FQ R0~3})w{?lqu.!'(]*!x#}sc+%XXE_`EH23+l^"±dB@>X)Qz -:>z:Q{Wv{pf5W^g:&B*$@PIJBB0!$(3T ϰ@)mN8/~-p?1҂o|W'jsɞpLxRpOl٩Xk@r&FBŔ5Ok34Wp˲:v,b57z3wi J)H) (꿲ry{̀|í 6xhr6﹪3205(8E) 0L)ȕ[_p Fbov$t6^j(\G0fr( BL ʓ'w wn랑gN8~ZP81r5vNSu'0b9tKOTf0mccBXC`>jB@P*Ob &p_wr!Afk<{"[^kg Ͻlyf@IRTi$ ӵ/ꗯX4'w?+N>uę<6m^ E/A[Z ̑sӹ0W}&2 YZQŅ%af( 3Vj$ѫ.,잩^<_< Q+^Ұ앗g{mo\i8ؽ? >qSJpizC=0Im.Ʈr)J0i.D:%cs$|eR8LR!L)րtk(y]/RT &bwߟl4VyE@yrM`nr*~ݡo߷?oÞ2ЃB-Q\G?|O~ύÚA=/w̥/jDpğ녏^F,T,7o&h rc!Kqb.V6mi% Rհm9ò%` R3}0YsIR*st\A !J"r4q}RjBR;`AQz|" }_0?ft<_/D!J`!\1\ 1u/U3^A c &r9uwܑ7HsWxKC^/힑&BX WhhjweiZH/޴{[qqֻ0dK04΁'m-VpZv'J7< :s alS ](!+۲=%()0AP W|4'*V[oGF ;>1(WNOv0eB9t܉M;\5WQC:"#AK*&8P12W#gq c1ZH<7⬺R-]j.w|Ս/o>ׂE&9,_vd]]Igҹx{m?/ (յPŷ#{-{Z|qfΏ=H,sR[ώ5te|zbr,qűY ǀR:% R[H%J))" !PcL_*ߗcR8$`mFv^!/j,o[>! qfqJ=O?92\HKՐ8xqtt q+)TO.֭1UZ#a<=j6A#CMȑjE|[mvT­"4 +%(BJ $: Ȧ",im޺l=F(iBQA(;w_2 ?Ҭ^rLMCFPX# _׾b\*t6nrV\斗Rܕxk R T( cC`[E%*1! U^RJX?TBP} TJ)_!A!)$&XPЁW|]GҦշ??䉦P&5,˼VΛ^@Zc'e(W>ziڍ [9@!a/lmжyX)::Zw%C깒 Kh@2QB@ 25@]PT)F(Ec~x>PHe3x kr:{>|ty6dG=_8~b|i2h(}֛K@$ޜ*ফ4XV`Cd:k` F(x kRDmd`(w R:҂e[La;!c;w+co.{5O~󠩃|cHL2(/鸉5{3ڰaglh0>xܹ1L Qym6~ +Lyw^/iغk{>l> 1b՚kdXQ `7[}xRHW8G,&PK1&ժi@@iU&70q=bv0  2bNqvtt8mCS(~aj۟}ݧWo'>h_9#-.WFNBIB#@@םzR Ji}%'r.J ͶtBWx)P%R/nf`BcK*Z%%.00l#S6v $r 7EAUQu"sUpD#hNqhŁf<΃F7+Lh)vӖR,|ia)K@x.cj; \b:c>AgkT($c(bwr߰}Y4<}ͷf2 E8p2?E܎q虦Gt QĐs0tM:Ns!DScR!_v ~Sk.ݶj Aa)2}a<ݳv}t4p%O&!L\.{Fo8RJ.%ڦB4y@"|7\kk:"%:7UCLs~yj @S MSA`v4OzE7bZf$R4PQ'Wަ^g}}_~!r"X =0mMt NL0$,;j0^[MRS]ӆ!"%Cz!d4|5Rlf`G4 $h,Bw+NЩ`WbB4%}w/,~ΞB"r6_^\L$-mW_w[wY湧+vz@"]|aI5 Y;8x٥5^{o}xeUqu !)UJ`PBP꺁0/’J)NM$ ,8+,p8P|Goo 1[/4+fgץ J(<krǧvu{GKHOU5;K{рmTA0a%"*]ʮWJݛcM&cmOzn,g ƻA.%;Y?a[2mJJ, E&i%A >#c#$zsiQN7Ry3 o9:d)/;b0UzMtKCap| B(qNxSsMWR+. ȧT(s78ʲe+(fΟ,;ZOL5/c 9@BuY7BHI5RJiPM NBq:BD4Z(Ɯq @;~P0tlmX_LR,[כo]Fv,DŽq|7YyTZnKYjq/ǖx{?C]W?/ks U.MMG} c1qjp( 8gQ?Z a9a(%5{ 9 U@m|o6qJ4Pe@D7W{^8`RyP $  +*%9As.PB*$C3 T*dZLඍ}lYQt. B[kW*תb2nYEkG,~c;v47 *KJ@ן|OstaU`6-=k<ēFڷn[|:%~KG ^tM܍}n,R[=jPieϱV@3+!@zhWw١;r+ъtJ @H! r(Pp^.4Ԡ RrƋLaVCMݫW]>~߶cSgk-n<23?EVUE{z"Rc _A޴y4t}wx놭vԸ4 H`&b( %1a)kdh:JbYS,} *%M`oĝ^`",ΧxR$ZpVln%YfFEjI_ڱ{n JWjJFC y)Éaͥ3QˌbGxΝ;L>wݗ!?]&\DXhkzaA7 @c IB S(@0>`9-M0Gȗ,\#RL=yC-[>;:QVn2g cę$J*ΤR!!Br [=kطv?{arijO`/NəLoc#H&'g+YnVBy5]CeӖd[ gL:D .J(uP4Zm:ZXhhi~޳\}}5W4Iᒐ* }4NpνRa7!)1XYM/}L]{ j!}O G.;yQ hsaE2lynqh539jrP.ԲiYBl.%du@ЩT~4{&K)@J R@Jl{ BpZb AR&K޵Kle{/_ckoK3 5jK/m~/wKcÆxe2wv4=|𑦶7YJg#-! M414TBJb) @J2 ŔR@w(B蜹bHUr0B:RfhvpeOeK!U[SڹS3S~,BzԿ>6+Vr9|0O]:7A)\=sU\4[$ȭg@xō$@(nr_%` !\ D"1&b }`dd*fu}я^HVf,‰-?xblnp&?b;vӎd A J) (!/] SϾknr]^xsk?|z],G}K Ft]7͛ыAnlLHÃ3fTG,F0iJ!R{+#``(%` $ 3H( 3!$gMıe冽Coޡ5qƞmΏPh˞^ةv&sz- Uk=_?|0ՖgNMU4Եv(jOM8>Kt5%p`E} mTj*✙};ϔJa_Js1.  $^-V "@!`NO,ۻzeza]2kHmRss|`bLN1}`\Ie+ê߱(ϠZŒv%kg&~ IDATޕgsBdCv]9Y#-؛tiF`@\6S-HHڍUQd9@h-^b`1yeIO`ZXX$` [549?K-_XމA+jz:!( EC.c S_!Wa q\MzE$H=Z(L+HIhsO Ø; Rh\Q)Ā[l? Њ+2D&J78;zz 8IڹmLm"5-dux}?{yͶO}~ò\,牀=Rs j|#ڵư\|XinVc Ee{`Cawff¶y q;nhu``Gab >5)1Jz)h5&]P;BQ=v7fƍTi.?f0 =;6/̧GFԼ+SK/եqgi65]7Hz%P)-gKG/Ym6RR)8CXHĈHT@H K(`¸eO{n m wTf5Ӵ|UaC+BrXuXn~M7ok;kQ]ȝ{'ü{9s^z3jWWrb|Z¹L@P}#q|M 钪YV0NN86Eułʕű BߴdijT*o[~O ]xիSϚaWA;Jz%%סljJAQm!Jq!DR x?y diD8>}|lX\s^Zn}~wZ[[z5hiWM;jÇ1Z$gi$mοKn[ p\*}; 0Ay#n JJA(=]ױRyʖ[o9\ղHDH\nhrх;綷%]Y؃ ܱ,h83B@ K$`[VAAꝿ?;-h#MS; ^LzUVw6 4 OB q[Bꎎ`qExp°!g 6nZ̓b/ß fx]{غWߜռk[Fd `>\ P{CśJ٬t,D(]ՠxzqAғbع#ǫ }@X% NHzbL %WBL]w\pf<]=w;cѱ}D>7mC}+\v۷t~>ɿ:skpffamof$bnG6l±ߟJ0"0H`TRJ!r!qܰmh"(!H !=Sb=NAcr=vT¾źUw̥9 =Du!kiR SD]wܽ3w>:uP_C=OP2/_uO-.6 h(`٣0f{*$P1ں38J{f1cu ^vX*$t]ʠ/=jےdS_?oj{Βet~4 [mCttغzyJ܃F.-7}dU22[@8n@kZOxj\?6lضR5\ -1拚]I#Pv?u4kJD1A0 n[nPmO"(&D "K)c>D cH(.Gq%Z wNdյ|)J:{d`%vr'_xx!i$퀂eB0axs3bduٵWVxn=!xY㦹xnd RX"Y"rt{}{aPI(PL5"uMr}{>`JBPPѮp|-"8V0/F=k^BN%w_=[>d,k ){:4B0uea05 ]#&AuHz1]^ew44zh+̈́͞vzl;:0q#7P$huQuC"^i&}zZ*to1e=wYV'LH%ngIWRi^gBq@ށPk|GJ/]N<&dUbiTDDC “ƖW.C. k*F>l*S]!- #G;ZbkWG;W= lo--`;Lp4,%W }=W2rb@qdƂw!Qjf ӵv{k1ı#B!x4(qWN~)ҵP%A#W# MA`\,'@Օ8QBFH+~I T Ĺ[` !tS D%byýgPb4ѹc[B&2HiDd8$k 3 rv@QЈ!E6\0 R$Ȫr؈yACXD94h4r\=-Jr%2gV2Z>dډœ jy_F0jXޑ?r6H̎ צq_}wEk޽O='~Д^wpɎf-ֺ4zz9 5$ ]݊^ d"hǢ֐/_K--uvv`>sh$x$lZ-_B+p1MJnNBAF4 c[B)AEQmOFz=ͤNlS87qՆ'yglqJn@}gyt;vLߺ-r<(--WJ3}Z|@b!G `sfRM*N5B!ń0\HB0&WF yBD0*jҼS `0ڨ#mcmzaDF;{&EzeZZZ Dey9%lmk]'ʵC7Ҷnww^V85)lJjىL/r2)kRxՍ_Er}~܅fGWT6\miQC%973y;w?u o2|oY  5xfyvԱ|:f-ˈ# By6g%ya]gْc®A22+nͧ=}D~/ǥgQFU5 'Cv {~ݱqxk-];Woް>1zU{Vk6xmWڐԌY /u7lz;tح|믿ؒDGf+3TH(hIK3 ac $}F GIwk\AW _* 1sY|ީcV(N--V,:72]qŝCʱsιABРDQxѣQ:8"&&CӉαBW];圳uk=ܷH)>?+/_wr-t/Sl.v ֥\8u>rD&Q*{c݈2 SQ64C?NF* !YRM˜X&ƴQ)d_gz|5k| V9q9Reeٱ.9#=[pG̮55@/Vm&N˶&$O$Dym+| O?WF0T32M;w,ݻϏn+v\dU/>v6λ~S4uj$ecjBڈCqO?H)_)ǀB~$ց4DP%&oFl:F"J04mk| CN) *! A)M!#%W]]wzKKS ]IjǓ}Oի3>w[7[rU #` Y6{E֬NwJQ R_/FM<*S4Z&x᳀ CXJ%@bJ~8PSWRëm86j{zaD ;<%:H4ǃa2V*ѯDgT@ PRGŴ.?{N!TwtTS*T%S5Bz~fQ)::Zkŀ\y[{.  D㈕48/ȷ+ڟRs%7/O}~5e?} GoguK7tК5FY&Z"KSy[bqbZPDثUȀ-XUCPlݳxK^acٳwh4C)3-ʯ,_{©DUaLHB< uoOx ̘:ᓧޚ<ړOK%KCo>T:xlёSǂO^{֯\斫꒨L2U)WCdZZu\uμ΍>[ ( ]-]'RDJN@ !!XBںfqŸA2r9_.} Xw &-+*L33}kW{ۯ[U(n;ۅNX.L.\stإ3x'OlپD_S:-!X7NUYu Q,f f|yUKZH 3-nꂜ4Vm]aAr( ȯre|u2(?cRHz[2w\u}(xfh4_B<}Uunsh:Gh7׹|?T P$j/͌M׶ac/ą3{[3gїzHitӰo3k*_w}5L&tfe7s|Q %!"()0 P2 3M,R"$P GPHH:<B !KM֮޾~:wna_ywvi .f1+O~ᕶ\E*`BXV$bLBt(fG/@p`8PV|WN5ӴRNB@(fLCTxݼ%fxy49w:zMѴCŦ޿W=POlYܸ“O8:qC_~g~sR^WVf|S3R%D]ޥ\T7e[]iQY,j Kx̎ҝW^RjY{vdı(SmjUѝr ^}u$U.lSk-7_:?:8>;aM\=}18[)r=ݜ\7::\>w2I-q$}Ϯ(xrP|5v[MR,TS/uѩYiPS*H a!I!0Bx$hRQA@k!Qd@g IDAT*۶k?tynF4vRn4:0"8לs to䗵ڔpB?pgggf&.x-Km~<fMdsOKǩQMh6 \P b ߘ`bT -w^+U=j%}m (JP $o !䂛Ź@I AhK8 s(s0΄aRJ3segؙ&n۰|lyCDO)4ҵzZ3YB C FٗO=i]283 @ TT .9W;T~M`ш1D8 ]ݑ];++|4s0 &WMYi+dS_tuwNTFmR!^ZkZP^MSVS.d0L>^`dۆEaP4 )}cDR 1QB! P L_/4UItW%[,S鬄TiiH{[!/iSj4I-囿Zuftqb8bF۷,N"cTÙ+e2|)h$qjh oPA41T*Sjsw6U BǕs6<439aeI |߭jƚCuv瞷㎩3'K(K"|d$bS/>]1{?oBXxX 7ds/?}Ύe|WT`Z6Ӻze*, 'D=Z͹ G^K@0{y|fVK&#>A1&B4M8&(FED*1R"0ϟ C u(HR @)ob̔yn~ßJjU?TSk7cnN "7#VHțgN.ھL0mL,n-}י$@P %j8 Bd԰ bfN`RRa&bRK_EOkכ9 0MV 0;\P/Dͼ^ 5Vu4+ B & ( !VA :[9<zѝ9t|zUiΗz h:``fE;Xuъݼw ͝}Ϭrsڹ_ۏyyfkع"(mi=\|u{vpLu2XjX-9;{:lcdq3b:"j:D u!c04MТ&H1zrHƃFPTn^VtJ7':CRZqc$s|iS3Q ]Ǥ\.ymscS=77l t*iDvdr~ɥ}ͽ"Fc1#f Q3(kȤu6\WY񤙈Nə 涳'kZW2ţ[U A7xցSz!Ƙ(B7ru7vogpEDosgϿzǞ Kt@U&76?kEcG _"X}c7N>4,o0ؼ~ݖ|ɿgcDY:LsuZ/V+JʤDZI3dSS;?#O:[?wyN,SRHMݠR2R) Y@(VBJ*.h*!)sT! %, RA@  qNfdڦ8$n4c lJ+#\o5?gҎ]WTmDN',lY{R*aYz]'¤8MDVځtRB`jq^zD) & ) D&X*'J E)#1 @^T^+;?p?M9=57eI(q B םjҀi! BJJ1B@piTpBB\֧K"5ݳrEa4A'iQG qMw|)-CgWޭf&=l% P `D5dH&u&F>%˧eygzӾwfr zt#V/ґ3z6pgߴ}6ޕgGjnذf7~Z[jZ\mmyՍw/~襣et%F 0@HH \ qJT2dB A4=X0AbDB?ĚV(TShjvпkhذ[ĩ27F2LYu dE.斫?s`Q(\5u#SK?/3=`Ϣ\s63fvsޭk5s53 6M5Z[3$ LLO'/[xf`F D4[Oq"g]bt~xҁrKJ7^5sa:S<1m[CZV,ϕ -ȳ?s] ;^KϿO$6]s͖n|y_.kJPpoZ(k2Bjq]߰㰫z=.^9Ijb&#(H0U+9# 6\ؠTr HDP0 s1FC R@EiAw:hW{Vg>(KUjb$`S A$;ꋈ WbFs-~OB枎?P QL NI,\a>߰a3HG0 CCbTwJ% 9Ґ‚siAPȈnCE0!O0! &0Du"LtҫoFcZ+ /Ud,0ߴ-+J'`E!(Vj+Dǐ)ܴE> Fu-Ӕ6t !PJHL$LӜijC4=4TB2%5".Ŀ fP2ӻ/\ꊽnrt쿀`sDkod:p]xʏMrk22^Ps/_Dx|ѩ»?x᧟w:t<njFs,Z0BCBB!kXI%@+% cLx C.ŕRcPɕJAdqli|ߥ*ڔn/f"|ڪCNͭ6шciھuyc=r&kB"k(绺{Bוn#iu)!!ˌxaYI( }4mJH kB$q1s$042ABaWm[B}w4Dy̭L=8E}Jp[&FZf[7 (JITF |1b,0@B(EBe얙'>O~=˒M PT] lhf[d\,,K&$!P* n)\$[0ԛ;RGM'D3'=;ZFz+*/`o|C_ˇw7%{?\_[v-w.D;WiѨ=o,wѴGrmh;Ԝ.bFtD~Zs°cy ` $\p!! ɈfD:>رh`xl-3Z8GN?Dמk|;ޱʵًZi\|_?d{"P$Z`C/8du5'6%@BdC%BXuR@H"}JL)RsQu\ۻŰ4PVڳj}5T]SiBsQp3nOp#0ժI|.BW-6׊E"^42w6XjrlۢZ)9;5L97ۺP <ϴl\ª,MٚS4ַDXFie330R}pE}N@S4jtծ?W=#Am~ sɖ {XNȟݣg;3ՒC_4 _|891lTQdђ6ﰠY8PsCFӏJݛԊ% ^K%jP()P4.%H"0`)L#H0&@(Bl8х}%PkT*囧O R~v՚T:5 c$_2?z-$^=~m\ṉl<;&L^qSs 4d~(GVLMd(EH)RB@RJ`d< 1œ:2skfZFX~R־|5ւQJ4PF5. @ S>Tھt29QTA %aeAӭ1؝(/okr4-q/^.Ղl:FD j8*6.4*ZLӳufQ @ePtݴ-݈$dv7m/?^FrKH+tn>k*l,nhɣ>ޘm̅^ ,ݼm7^ۯI6wJ5ox^<dZ\)iM͘B!Gb<CףVNv-1"d'Q>*F"W'<-l|w9{lv+ xg]CԞO|׶<<)\֝ͭPk(,_scz"uj`TkHqF C@ yL`PI.4}LPu T 9P ;3v)d1;4۶kSykD2.㙹F-۵Vmˆ'zѵk=h!.ũl%YQ/VTm@\Sa>p|J[Z,.-KD[ %F E F1 kZX\Q PXמ,GXc@[m a*n;?~n[Vʌ,c4%~cc3[іn̺/?p.2סߍ(YdƣW,}1u[X_^waٟ}=ףZ?wEX:?2 Uz# SBPa4*]QJABc PKI)B()MCG. "D09>^в͉K|!5 屺R(2|!|GİΟ9ٶj-jm/ƊVX?VLT,8(n?p?_KjO~fqhA"bH)a 4()q<Ǡ6 siBR@2J $h̸Q7_δ7s,s]'?Cߔ8icP-2ѼITW hՃP SJ@|?@!RڂcO9!X֎ _WU64cXNQVȳ͘e`b&1,%SRYݨ+:#9ݾG]ȲM$c߼|0U~M+;$eלҦ4}J X2m 4d(PrJ) J0 `\G}?L@ E B%\Be:u7<ͱԆSn²⒫Ju\nm1vmدGon=c:+BzPJhWk4TUU%e&0VtŒaZΌ)~0,B߭ZZZ%Ώ XX#'İ".3L1zHq|:_i_S8tO?n,ӓqse9 GWnO|]ac3gcBY}>/}j˷IF_X 57ɮJL0[2C&6?15w3Qa]z||'֭>/{N:u7 APca1s0!"¿?!o[1$XiJiA'\X'RƕA:::t?ȦyM71YpR^wl;b64 cV,jgӿ:mitJ@m IDAT߿pj;w? ##s&!3Aa PGkZjRig@J0ϋ؆RJ*ZhtcN\qgK}ݽR9tX&cZ3A(&/ͯ_zBxX3b12_ D~4nh` !B(DC$V8 ?J~.KhFg,k3_G$jL@;Q1E s# ?~ypٖ y}I]/bW60T!/tVw\\h4&&[5ڽOݠ[7lb\w7˺!v;ulW>|?R]&0FwnS4&v]}-p3#Faz5K:$:l ,W%}00&Ht!ff'{͌X0svo{W/< f׿ϿmZM˖T?5fX@A1x fgZc-a}&_V޶e>)Ԗ5_ses:Y_һf͌>{NDBDæ1̬%ꎉwL$ȶ`3&݆JPK9)P b(Ʌ?J@Jɔ)Ti892cAJDׂJ('cmiKGS\*2WΦn̤TG0X?QI ZEuM%=O#DXT1.N)wZKgxMZ|T鰋H<*c) @9ߘL}V*LMO- TRI1`r+2m9Ǧf^TԔ!zwkdŖH{(ox,4C:jv$um_y3}6~ xiɖ+޼}?yA#+V0'gK7nTѨܴ0 I=n>u"(T[n[[ sRJ+@0 @"! !H)ai 0(zAB? 9T`Pɸ!D) CRjT 60d by/@29Ԕ2xGzmjU RQ]ɼS O'h Y?C팊eB)D Ւc~$֖ց`Jd  l1 CPjF0b) (B`AMtB8pքkD,~&> j%ݺ|fd*މ#۶-[O!fL`CZ0A21ETJ}"9c_ :l_kW^T{KjCtVONuxysG?gkutpkjA*a@`hi\:U?&;QN.o_-z j(r^C"N3y.L7 H)[QG toB#?u|{=#?jO DQw@U˖t-vnטsZ]q-Mm a|G+1-ε/íwgז]gޱ玲[6zng|Kmܶa>?S+6j}?|w_Gcx@ak?;,֠0aiB%P AUǂ{YrwػstOF3BH !r-cxlC0||cdc# ,rN&L]q󷮫_ZzuPUm^k~ttZmq:vϞl<^7wn~"ʥp`!p>oo_0,g֏޶!rpī^çr,N6?_Eoazd FJk|xbdv&$&{s,^+C0ѐ$ȕR5a=|m'ykoyrz^Ӵyeb/Fgie>3:|D9E%(a۔iZ\Qr-ioNLOZ˧νtĞ~X?}][]%F96O< ;z6*^z7Rd#xk=ADKzd;,Q HLC[a%IBf(E fbh8ʄ٠MH:(SRH)ؘ, J:E4MS&޺uS':˫qNRK/ /:V"X6wm;K2׶ A` 3bqPP D@`mF` #X% %Bc RJ#e&kvcIc iͯV<旚;gqyr<8;hlַvYUznj{DC9[S%"(3ZsJ@Jm_D\Wްۭksg:lb/&~T׾`Aq8{뷦+8JiX?0˪UUg}ʼn+=o9rm+W׼[Rr[Aqb6bB(c"HD |eN }КڌSG0ћm @J{BHK)P(1(q4eGP7:;|{&[Jcnk&ڣ~S~w`7(cR q6R*q 20^6$ط;Qڂѳ~にpEz7r*m[;eg_Qu7r 6iP.:fkϟ)Nrߊ5nUYcZ.Z^#c Fγ;()n"A.0F-E]-gMtfDžGVd|)[U^-Kێ>>96KlΫm߾U.Y׋sWR^wn{]'=W}C)†c8]w nyͻ'V39^yWZR n+{37ڮIͳn(bX[CHs9Ǡ1 +Zc )l8&T+fFg QH@)&,beq2ʍ1yZjLsS)($  5%ƩoXnJŔ=b6%A/? yq!Z*3{rYN ԰](dn,-NT>Ͻp:)Q +KrPvֺHN ^z?A?W2WHll'+Ӵ.~b;! 6>1^0=S5ѥ}u;g>W?GN}OT?߭z>dSaBtM#ZtfwN~>e+:p}@J'sd2=TKPE00@}D1eK8S ۽A(RJAh~^.v@stl9``/[#VdQӷݽڊ+ZdDa>r\.Ge {._2Z c/ҕe:(W_<20S'/ 2;0`$En\f"jjl"}~"eœnxrw[ź[^vidž#*oh(7^9| $TaΆK"8ٛ/W{~#\Q.u7\M|K?*}O>?|ܳ">͓ǦNuc([TE0RhˢTzZ?i TV`IH8 !8v aFh Fny^R iSoo6XFRrfϱQBwyC3>rgiR?=֡0[&guz&v)e2eN%LKS^5B͛#i*dIjW˖{;krۤVl9}`ƺ5=2< el:֙J\0'qŰgqG|A$sF( [m:y.ĠUp J +7/,\>q.<MHLyiEڼXacS_S^o끫.W_{x |Of7Ǐ>~_˷*xj: IDAT#knTRsJ=۳RB0h43a ݅{mfG(vK7-oY^Ј牴?ՠ5W 9O4ڡy,GQ*&LfL)/ap=pyȵLkVp5L,Qz>~pȩAg(L,RYi9c)ι9bQ ]c[6〱4b! 8K;N @8I"+JngPU y.^yЖ~_)MDK/wk̶n}[122Ջgn|;oW's |?yF{u m*.nfĆuv3Pؒt}_  "9jCwwGvo?g6ltv9ǠV}pY[DARM[` IT)#QJ6orIMDJԏq) <)ecԶY>$YX)'BZHn{fVMPk/0`kǺJ{]I/.`0 cF"`dlR,S#D m T\iQ#fLi" RIAZ8to @(bԶmLʼnK1 *+NeE oiZ0ܶńiufe!,SZAiO]@FSL)Ħ/c mf(jid4(9{ٝ:}0fL7^7èQm9uWO/{lF"yXr4>}ttn%C2 ry ۷ث++unz2A+ F0 RD#@ N=rc|K Fk* @]^ŞjŃ`[ ؾȓO?# #ccvR|nV$05FGar׿疗m4R;wߖ4 R(VJ,zDŽ" JSh)VSL1ZUsN[|W˜&_~/]U815dZb  tJPc@%, ZkQb CPf3_o/fr:Mϴ'WS3NMWBH84MBg:iQm,Dh EI8- Vօbu_,zacd `"۶ض,\mZz Oz'9llo؉'=ۗx͟|6hf)(֛1TR+mm,J4MSιbЍܶm$c0&J"Eάb)஛ðFbk}#Eyu̽xAg>o:@[I$p\[ "G1B)e4H420ZI1RYYe JSgmg@sI$Z=tyPrԹq5TI}z1Q2<@c[\s(@[){˕-xva^[tݲ.wZHFv2\MpJ3T8h !8#D߱i-'Fgc/߯kOo׼q7lϯh<64F rLN?W>>{?DbsKŵl[yoz[rI3Agw|hSK_.=3t/֠H#ra*am3ޤq|D9z]jg|7\14Y٣[yR#0$rɤsdTe:~h!`2pR݋p=BFYϯ_~Ձ[n.Iך8o+n_U wJ-- m\Pu]$#DH!Ec\ ڲ,w7kJ"R lwJ*h4A1%*1&ÊlE4G.€24Ag!T*W3\yjZ53XNvB&jKT%_4Būӿ~/FmQwޟ~[T`u9F= xg۬/Vv1toŠW.ڴt[;cAy˕f]%IB#d'ٝ8%% MߢM֊q1R7KM<4J`@8PιZJYB0εH($-KrГYb8NFϏa 3 ?ͯA>_ 0+Xĥ֌aZ%F)T-6dP./"P};IFe(!2,׍YɳGS%ƹ9l>`LE41Pl摂Αss iP+cò828i\(TN˘CFU-8ΰ1R@pm Dg^^٭fɳ e^(6yܸ1ӍK3XPpkǤjL/B=ŝ}nr^ӴR{'oiF9qF̌Wإ߿͔>$T [;%)-ZP赺"F(z6p+<R?]) NG/8rz߇^g«xx'֎F |ekL̻mA-#ᚿ;f%^jF&F/[>{#;$|EAƜG_7}g?}鵆q)%,)eYYRJ1FMU MBR L0Fe Fh ZLkM\EqokF`͖C,KȸwVssL B )(j Xзo{6]rkȋ@^I;Z~\-j3\.[{zy'A gDJ!"MJk@ [ނ>=J;~crI"^ŖW %Mݳs ۦljk-.{#ecʩ F@Hf@PԱ0 zGZK<\vKCmFu+f[*AuswNBw}vlJ&6  %"_kNGDIذI**[(M2-\[UC$ T\Z*x<ϪƊ>HA ,h0[,MNqho+~N؞ou{oƱ?;4 ℐ,I!#fiQ~g6S2gc6B()%B &S KYV 8VS{60Kc}K{g?{c?yi7S'6y S4F[{+0cV&bdoC]HQ_3'JH,秗{w ?TJZ2dkNYE`-33O˜ El# `Y [  lnY&&$!K n3^#¬3GFlS+ [dХZnkXl\J _$AJD(JfE=oxhUgELʄ2"f1>H{*.фY5KWhX0OL"aʅzvl[LYߒb'ڽ/3'_6}+.9[(sOwEak[޲Xo_s.o ,jf9F)0N@K- JHcRys$Sܘ`RkfPXs9=s@)fk_,?|~팖K,tnBw"i 1w1u\A1R#gZE8HאKU{k;0`iί8>.yW'ޅTA@@Gr((ӴP%bR1n,GW5Hݹ6gL g.՟oF; "Oeå@zI|/ydgVkqQ 'k(j|:ſ `Iw/ZkIpOK'S q]D&n#T2눑&!6;==kkAɪCÜ0Lң#B҄YV׺M63Z.t.g|H*UN9Yv=صqC=_ ̷ w;\|HֽWLׁR 4,P&"fSJЛF[-KIQAiE UR*%Mg!R1Nq='V]YVn7y^nZseȲjȸr 3'уw=o Pq<)sJBf),A(6R6~J9qGQâOtDϴpg5Fw]t}kAxR,uG\?~RXVXlۣJe1z8kF9]cSV8~K?ǐC m_.~ܤ kK[C?ӅH: P iۜ#¹v.wp{v=udWl;~D8XϷbV!n ,Bu. nw]󑪥ܵ]AenŁ IDAT:jdWl9wգ+K B-4IrIQԏa۩TsstcjY3H,-Z2ڡ!gc* ZvW]&{2sn7r3cbg48Nujv"дd.͆MDAW# ijöEӇ>wwiĤo8׾o?{OOTQj0Հ Z!<02< CV>_B`mOB$ ˣfJ/.6$#־;R Ę'` i.!͒D޾:Ve!I,]Ls84z57ВfoaЗb2uM )OE]C  FPd[VuՆ֓^;S0PϻZ3w]ke:Z e6PF媇7>:g+SlyȢ8z70_8?h9~w%>?l Q ,@jCZzpN5 J! N6\$D(wձ:Tڵ^yPx=09OJ1Ji,h+Aq[jL5GJucP0Qkʓ[í<{ͨὦ ֳW =?1KM<-pWf:RHߕK]ӯz;ZBЃOx?+Vz]~mѩiwMsO|_M3ˁI%%9wH` {Zu4}B[]/-wX7bMllT*e(,ey.lNVN M)TɫH)R* "8˲< x?AUa&.p껺a=?xý}5uf.ꙔqY|Co{ɗ^{ōh-xw=s`ڳO5N`,raRbh}bmj_?]>1%c8UZBɋ?skYEyIyda\ RD\rvڅJ!`FnY( Ȉ~3s3`/O]_|/vN,3=K`G4 r`lu]721 ֜s!͸YQJYc8;!( hC:O3coy~~eT&sa] mQbS ax#,Z繄c i\Kun! (S/;g-h,} q52M*Ch x&lpI!Y!*?wWQolw|;^{v ])@XeDXZM2HNaґlyvrv Rfjъx};Ƚ j 7Vi5^EGKx/Kf fVfy) uG:4MOVʩSr1c)aqn2`k,C fw=/_<1  R"emgaq\UkKxn̈́녃H:4PL@2'b9]>0ڪ39Tar6.'/zscdadG`41S(l$@R[nubٗۃa$Mz%MoT;oIݛ[Ó'&xe#c,v D؏2F)e)q_֬!x??9K R _τ;ZGjd:p>VU`GR?qcF k1C5( ĥ{J8k:apuAY_[޺+k$.+K6ťMa}yPY x RkxgRa3믟YZV $eLѭ[_u$oƂ/3TMMi  y_('͒4K]׍XH63^dq)-Z| .u_Mtm.\{v^1S3UR'&dJkV<]령-@ p\`~8_5{#*={JlFʰRXmϡp+}HD5&)0KȨQ1!~-|| 7wEMŇQ]RU%NT":Y9{_?8r嗾^Pϧ'V0B,(_-A2 C(eicaRJ +D6c1iYJ[2@YLݏ߃hoz/HOv>=qˑ) ='(-gXq9ccg)cI$s%@[s`20{!u8s\ 9Uz.o`4*vN°1Qϊ lk&I^4H2=0rʐ\d ДFsWp[/l+N#̢F+`ͫ4C&ia'.nQl2D:s沬獝4X_ *aE#dIij^I}ٳaK@~WU.}{ H7 {"?|o}oKܬ~zܙ;.뭿qKc@(|F@6H[.,in(ݝ?.tƋ9ls<'JI'(6/J+ki(d(͵ a;q̗/.ĄcFV~Z@6 ijk_h4%zde@,o\}M=œ;3! nRʂҔR8ɴBH)ҫ쵵ѩe/KKnڟ_PM/xJkd/^x_^Ola, BKmELgsc7\ۣ)` 3dz\#FeyZKEcdI\wt{?hU+lюZ!SD1I`T!B1h1bB;ם΢7q8BJc xdW_ߟm/O4Ex͆_d{,6dJIm-Hiyg)m1ȋ4O*5 KB*/-ܙַ^\*Zi5f:JsF(&ʰ51 L4,,QYdW [lrs|vK䞙$xc 0k! XJ8LK> ۽c{Uv$)\z7/U +7G8Ǹ2;5sPFS@Õ!p n}-_hRdk~@5FsTi68+2 @061d !B5X+D&5yjb~}Д/]ݭVOtO6ŽSӫO}G?xqɗϟ;{N1ьG}i!o-}ۗ> 7,1ʳ<?[PGq{Y=d̘22H H];ߴ~1@]8~ P__-?;XU 7|1p,QJ0,$s? Ͼ_qtc7$\<5#uPJ)TQB*2p*Q$I0kP(0>GygcDj,s/-mlL4v?N?ϾrjO/-{8$׃0*3NW6i0 @ i2f< hFMŎP/O}J(SyitJ\iwn̻=>N7(ܯ^43R Z'YNk%[>Wp6XvX,S!DJ95Zcv˜$K1Hɋ&CCjy5W{ߌ<=y&orLj #=no\ys|~PũQH9H) <!亮v'J2Zk6RƔRDR!acR5S2L $YUeSjN8JWb<̧nϼa5_OQr2LP3.QA(lH)r @)㖣Hλ&<*sLgu=ԏ{+U>;5p,`BXTa VMۥRMj.績g6v^&L=1*؊R7F0Bw'eY[J\g^9~jΥjbYVFŅ DfkW0ug[h}KdzڠW! GL2#@A"+H g+92 A#b~0Z0B\4RobA+~1`$ $c-@#LqQI KJd$p~_(kUioܘ7^v5:ޛ~U<1-b2OB𓧟7=_x/QJO_G)VCq7?]䳟{*~kQ/W,$+S4"JhCz囯4M~U9܁A Bu*jyZnocB {Avz_&'* %FZ;k'ʡ:ᷚ_wh57OkWzӅ斿q{}ӝWOdÉf7Ix%4z΄el\s"2\+y^HQfr`0ݜA~-MI ~Qlpsjz; (/[EwQ˓%S*Ӆ+7rb:]akPmd>2ݘř-;e9r  j<ÄhR4M 1Z1Vr TUW;L>k&DT8_l?={{oq,5Zc H)6YqR1e[Hy25PZkc %R L1EC0$ Ĭ IDATRKÒ_ ʚg6SԹcOAD\}p'&YB%spQFeGaoM/*7KAwZ> uejJ%!#c "83BL 9˒hzvf{%\e0 ߿y[W?ӧ㍟ OӌݻGS*HY {ˍXIU2`*S/3/h<_>zOG_7>[,s.Y<l'6oEdLe M?6^iG*pt>=TBOxRYKh?E1sXU<խC7ń)^ykp `l4LjB&ikͣl|bK@*Rp(G QIQ92upvZ ժ׻FZOB={zTbF)H%ra4BHQ@ YER(HHI)ǜQ(j...bg?oc~+t¹#W\u鰗jmF$ںḣa,1B(eRNR)-e9BZ뺎5VkۉI!se. M__٧>} ߽҃'̤R9*HfyVsG\\<P bBQd4YRakr^+JBRj/ovۋ ;APR*am|kuhlw\ H*jӉaC65ڶSc:Q jH0RRiyjF֦iARFHk U$ 5HxS~N7(# ˒%X*<:;|(83.hAtYN\4V1 nGnͣE(s)e\{"Õuy PklIR"E;&X"%+EL]MTF.635әC&q[(夈ʁhaL6NbjvWp Ac;@]iʋD*iZ("0 &C|>rrFju{cM^{miяͶQ Ƕ8*4/o;vPɍut!Y߼e=0Ǟ8zE>nSazVkr(eָxdG< ?b;ŽspSu9%-gv57k&:F8r!(6zKmj2m-f1?5J^ߵei jC}Jm9Ea|/ Ixj(Y6jLV\Uo,_H.Al)%b Z j!U(Eul\͊Sӛ 4h{31~#w"잋kw$^ gI>Rh`rpIdi"$0D*۫0NIy4.pHrZUBN2rkre阹X &(!hyk7wk߼˯[;Hk3@wI a4XT³.Zo0vQas@J{J49w.f`̰@H;ByMryys7]pWV_DwyO|+2}. +wΉ5 |Zs<_)c"P>]bC1B@pEÕҌ1-1 lER0 #^G*u@z CAyP&,2ZY{fM1d2|lL#L/=sMp֯d|ib7QFlYXfn !ZPw=7\R.tDq5]l5NPJ28!%Ġ(l'*ܡbGl|SkW_8~ߑӝ#]?;Ú }Gg.wLWyz/3fԒs`&PFܚnIXGӡiIӕ% LJcde @y*kRJ qKFg:#1(Kb҅ޚZy$~mv".9gWcDK~43v%N)N|4~W :oq|𛮰a&Wn$Snhkie=/UÞ O]No hDX}IZu)P6%\RZĨhgޅ奺O=T\Ϋau u-vR+a/ 5V d N.9wGLkK81IʴEI}Uባ0>FJ1BH[`1FFƻ,+GRb3Mo׋ҁ߸~mOszM._vW]+{_ hduM:u'yOsNE*beA PAhqigVG{l[61v V)KiO~4?lOx~YϺǭA6䆛4qEa*ʴ6(e2ϦIuAxq%d".dsd%yE"%pW¦P7Q!&1b]i.6Q^??w7N햽[/<_JcQqy@GJAYqJ)J&1b,hM|sd|e(5}/ ~5ҮW&߽q#'O\xZ:5s9ːrJ,,}{5x,tsreN䯞0HΫJ)r(YjZ>9)mЪS/Hh';ojDRurD)+ea]O>,ՒꠟV {}7*/&gy_x)Nӏ|oѡkq {aEŗ_}(X9̜fɋ2*jr3v|\)9;_/f9*dt"0(mYK"](zwj/NTUi(9[q 1KR[A^@QIrPo7a\Z| yg0 G*sCAFZK2ZcB攕6##4+Er$f3{CR׷u}CMވ}J?k[x ?҅ e0֣ͽ;P|LsDI2 d>qBLdOK0zinL+ U(]q5t.|I%ҨC6+`)~|ҥkrUI)'j0xLtzlqƑӘP!\+< i\Ke*Jy~ҹ)v2CU}LBR ɊUzZ\nX;RVap$&!Sd!\ (JK&E{>G;s'N_}4#7Fg_=hG^'l>bd$- V~w?w/G.7r2GڔMV"f:m>oL+ZM&agr ^r(ި0<˺n=+sbY,ӕIj!vm A6Ueɓ3FhI+E Ì_[,qS`K@m<Qj=F*Ƙ)s2JƬ Yčo[SpeSn:}K^`l׷=t#JxfflruL\.LS6 ",_7}ɝ>~~JwZah>;0D]ze֓N/7n5H- D~[k[֢>=zyh-P: mugv镪y\cse^WY.6J.2 iw4P_]Űzq) sM9Ɔ䶘 ؝,.}\Ux!^@gfKqtIܗ,5_u˭YG[:ӻ?sr|p @5X&fH;rWYc=% ΀` ㍕6Ǒ.lM8bhֹV@N` Ï]dp4:4};U_vӉq΍Fo^xE P$d`i6Dk`$MH27+g.gxQN%{56 jEd 67g+U$9Bsٱx]gjx (K@k]Y9,PF*<+5kyFw%8H0ĀYVti{gom嗎w,,8cɹKC+JX{YpôHWNݛVyԧ__H yrv<0WljZoڳ_\awi=oE7IK g?kt4iн曱 (o.0iӷ{Wo9ڥXntjBBmu1%u$&_+MbZ婥4lEn,%$G~^w'{_wݲIE8(*$u/N4B BJJ#cR" M>Ao\;XG?>ǹ/$jOJɄnh^֔RA*por@ J!QG9pvio7&U ~{N^U_jׯൎ/4opwE %4=`!R&3JY{%-TL;z8|샷?a:8{r 9㢨Ҍ~_yC6r ?zFaL0FJB%":J:BdYv0 5X0Z@UUbFÕRXixt"w?cKfߡ'6n33u]nya7?xG_Ri4Ƴ^3$sں K'HF_IXjDLn[ ]ッ^ڸB}[H G /w"9MbQ;Rێ5hrJ̹H&we4G@%|+^s)Tazz7V){;NaCFWZJN (V幮w4+"hX1s+nG=wfi.|?>v/[z8 ".$0ŕc;T{ՠd Gic-` RoǣYӉQ,r\ؼ#sXcJbaD6VFaY=:M9`FwGF6lsAtZ W~3׾ziht2]bӝc֧^3W,qQ.#|V:3#h›Dmb\\x}M( 'ڋXM:ǚ=S͖-:w=pi|`˰Fһ)|cǏ=xs5ۊkWF4Iz!ݍ,9$4 I`C m zݠ𠗵6PA4BvU 18!\%d|p]IhnmXt]]% *F(F"iBK('i0MFR1G:,Ae󪔅TRA5ZU M Wq<߅}Ś3&L e/N=~B4NbFz]-iNnUlix ,E5FJk1`a0GnfW `F)fݨ~8o"b8߸=۟CL8G[@cEp)!¹Z[m~!1f(!ͷaoWI@S lЈ`H7o?<+6o~Fow޻Z\綜y9?b δ7`u./ThH,~09͕NɌ-,'Xd):ؿ]ZY&=?pK#ÖgMHmC{?>($q 0eLJ?=Ɯ:H&.xhx1L4[Sa&ẻJ=IgC*!3[D&,֘2c善lC)NT2W)ѣ$7>~}~Hp~o*+5B8L u+Ռ/,Ӣ幪]靺l2*x+%WJ^N\?m'gq);ZNڜH=wө3+oZV[SQk};zn_tj+6U r8aX[[H[f q5jF2Ƴ|b\bR9gWoO'xU7. 4v-C\)aEUXV (&JWS( @%|O8ɨ^rV1JqQESFRb|ޝO  zOO]." xXVڷwR*#i1$ВqѝcSu0ԀGLzH#ʸIaDW2ILKXmbW& $1UI-X(Mt|f(h RC׮Z`tpp3R-PͅX]̐{V:]RVmÝzڹ݇|s7&YQ<1:ZffEޯZuJ[7:E,tzmTn<ɜ( 1ɋ,)֘bҐʦHLBʥVԂ;~㫅Dx@*3@t<:FB_olw6kg7Ɨ.s21R4LتF{QKדJ7NN zͷ/3#:Yλ1!$xԈؠio4!4@9`1DdlfفaPP^:+S=M{=W#RHqƣm;(A0T^VqBPδ1J7c6APY9wcĺ|* ןV`'\Bx@X`yLJK(0D!'㎲dr0 `pήN;vˏ>x>4B(!J])c&lgژ4TJvC00ieO& K{[ơrf\=*frtXȼU&$  m .(S.8c'sxx8 c+:@a2-T&V  @0!xǔ1R R4F;̋K$Ux*o?:-VY`+K&'ח6%tEc0 <4 hwsaI'> /^#'M! pZf b's$,w疗/{!~! .O<>88!(j}" IDATr4ViA @Qy'm卓0'Fa=[m"u zA?1=Hvh)lږ3 ,̼iW#km@pFT]ۮ:,32+JF#칮49ǙþO?+`ך4N ĆYðaL!6# gO|oY[?Ĕ`aQe3K RWhq9y57$a7wK<1s: ,~д[@+Vjb"/Ke. |{&D0 2"4N=""O;4FRU4!h0B0Ƭ5%bd:Ck1u]FicRkmQU`)Ƹ @`* xGV.NgnaSьnX F\ѢJǓ!Tp($JdnLq@( CmvjڵиJ盝IgI2 l6&8tvK _ڇF̧K Qpz^oc.\KNݢZkvbo ؀]_pmqtdE4P/A!Ma/ٟX .BE5j B{{,' TyQ(+~ZlRCXO=^L m qY6_ (MVj39FZq\@B=BU37i)ˢPJjk(e2'ei03EUPu-kU5⎄8[[.=qf)}%x~#g~_~)񦏘Mak ў)MB\fqm9KVg>+h0ĵ4ܱSsz+]"8 qYײ4ShF1FVVRJi0r@+aMYjqK-(M!*ڧ8++T [`p& TAq%%%4C_q߮p~vj#BXkjRh뺄sLspŵQsd6O*K](i%4Gf7"JXܲ~MfHχMkxhP "Ŕ`LZ[YMS3beЮwO.IbRk=q4t=UqUb&󦽑,',gnQۭoSc p#toij;>P˥V'S =F)bbz0J.tu9.MN<~y[霿1\/uф:^ʌx2w1X F܎cM^pV|ƹF3rfiUbBcgJ {G5<1z]l-fEF$ cǣ.EGWpjʧt.-h 풗RieE.,-BJK1bB@8SKϋtaojg?OW!8vIh C16p`1`zpk,cs=k9bk?sFHq9,-"-LUDk}x+mJJJVU1z:Ue!fh02ia$PgCd٬jYrq`YhHDKY E-kŇZ>kև@^RJAc1EQbwDRaB틇*K) LYY K%lf 0 |22N,5ȷ iۼʕQyF6[s{vwx℻J3MAԻYj5˪(ƽrR|2.v&,+Ya D\6*Lj27Wf28\b w]PG,(NԍM~e *w.]jRM%&ˬx;'t=_65??WSۻJ0Xp&e&+K9 Hjiu Z9:3G9rTy8NEw]#`QN<l˜,ctoղZk$`YkZ+V+gyU@3'^s0p}"5~a~t6spv~yoO}NI8auC,kD.L:3l,|jM:X$[l 'b`2@ & 31@B`(0fh Ǝ-l˖e먜:?^?ZsW+=5aUcgvlq2?\_~۷<_<,dgT{|Nۓg/Eh:1ynHtuӶ/A/s">{rPխ]oa6߾5pv|6}M棉  !:1@D 15ù1R@$Bk[syY,@687և_٬[trL]4vܴ%Shl=M0T̝yfw+EnG3H/{sO\]hS^G'6 (n?GA n^lmͻj{gj̋0#.+ZךHDOADsQRz D$3 iά|t KC^A:Fds; m Eɧg|ï2^9}hk_YǷ{ÏB.Ɨ5uukw'6r]si3*4 ;Gޮ{s[xWPR 11R )t mΒWL!)n ڭ7_W&VݴݟĭG6/?†=͔e0?‡W>I1FDb#)||eV~RmhPfHy7Ϫ`ՠsoͣaoqܜ9Af/im uN2ό$,6Ѵ)#gLsgѹt$SN$`eHZg]Ayj15vkj1İݟ}\QhJR|[_]g:YYo{V϶աoαi()27G;< /o&C*)Oo>;O7OlLG6uLjmEs_]~k=Sw<?T3 ebR; pc&!"`)sɀH "i 50hXz3剛-Qfε'&V:'ܬ\3iZG)`Z*78ܾK[Z l!`=dngU*{7g"#HݵMAMac{Ǯ~yYCL `ihq e@f}%e|ޫd_5߹wzw{]|'NEFG0K74T ֟ݹ3A0eY'%:ۦu B컮*8Uw˪b>q'=殨<7f{츭b3[npo?ʏ&Fm? :x럙 !*,u.O"XEi}+x]~SƋޥrsE&B[j I+rcnM/:F' b] )7BL./ZsIm5G#⬑zuNZ7GJ#,n?gl$y'"XΈK W2K1R2A2!D53hܯ_߾־u33M}G#i`mf`һybr4z$ܢ"Y뭦A1\2q;ϫ<5 /_|a~ы7/^SlmEuO0~_߽6x5@CJ$$\+BP]WdE+ZsO'~/큶=p|˶G ~VVmtuP7}Osa~2ϫdV N܅۟xuY'_xiꓫ+w?Ǐ |~:~0=H+xLaИ׫U>Į&c@Xi]dLSZzH<Lh6a6p}ևwk™{bu7 xAutR)a$!)loܪ-}mtuj;+UUx'Թw5 G[,[o. |mbܾ`!b67gN[m[nYt~>5JGV6c~tyG#WW6gz~3*r8FJ&M7[qms5({xڗj=#ѓB` ;!6*Ql3Y޶$39ltk`{{3g+׿ P{³oCgo[*oR O'B¾\OݽhRG#[~}A E)sq6кDͼbR%!9sxxvxf+*bVr6 $[w fʲz*ՙ'>cOɕ[wJR %bUUhd!v'̞^L2ǽIoʵk)^;~(VvSPhvTغP'iDze<$zG?9"hmOˁ)2yQckyHAYZ 3"@z |hx/!>@*;/e MfJh[v`sOlqo 8`5<;۾۟62]hT}Id'nͷN棙90noF~.[aOq)Nh {d0{$RI B0 Cw# +k;ٝ_ 5! mٜ=]|w<=C(BJ:QK())EcL۶,8-LTCc߸?~vu?^` x9۰|Pg >*Ԯkf7Wpz|D2㧡?_#]oTF)c $q pPRsɘM"`AfdS +f+!Е1ըZ{ ?;s/~M~Rw#}f;?ϋX̧Tf 40hAk*ޘs= IDAT3U,aQ J*LgFBJi%%3zDN Xu6AXJ.zEgW=ѭCv ī/> $_X5SQL*beYJ:!OYlַq󾣯/eX2A,YBDm: eWk{7v3d-;m~fHz YB܈YJtq> Ӱtٵ 4dmEy)Gd\#B'c@,u7m:-qag= ʓC.c2L'ʐbX|<G~!bhp[T|Bs-0s.ezw]^olS̔HBQ,F& ڦ բς?/{5uSeL(R1&H(.J N 0)1E \ I. SIn ~'6[ktOVyn:2_xw]x?o*?yx0CPCȯSu' v{?x5b*3$gZ(ABJJ1::B)% y FmleʏȬ>lzkfSN[|\t:WF lמ~5nSzޭ c8ĂdLwK0Ɣ|!RbYIv-@\j 31L"(eadIh^ɳ>@@^PL@𐢤szX,6"Lft_,^3iG\)z/Pn>,JV%+UY2"smJqy R(mYLiRL$YN⋗Owwɪ[|K;c=\;.goƇ?|gvK'8E@!Udew~tf(RQd3EZ<ΔJT*}R`I)&)-}r @ JJB;N"&)ar[͏ֿ[@wAjwPSH!H Tv8R<&c8Q7(W\Gd& Q|ifʌLɻ.S,bsz57_}g<ĝgVٴG >LSgm Anᦳ霔F5j 5$n#X cPҹ`[+Xe@M/:Tޟ报Jk!uFxw`Ddyw]DY YZS9/nhyb.]} @ltl~?~\DZϝZcrNjh7+0B:[]Eۀ@l1s""Cpwg2ȏ?7<6<_|t7O]Q[辄y)Zk"IwR AbqM0|L!b1;<Mo|dn,xRд1@tPiz@z2<PzL!d7>N/#'])*,Rs)AjEb\13:떷""P )C)(YHQHf,CRB:!哋벼&7ns` f)"\%bkc1`o"TN {w҅~R p :)B ,!re·z #Rvu/}&!xTHuFӪkʕ^x^5ϭ3ʖ4{K_g_Gy[/YuEY5GU1[{^G0s4L )WJ0HDDޥyo9p$bD&Z КReI$D 5ྣo|||B7%P$EP*2B)bk RJv"DB&4R Q"*Dkܵ.'p}P|b;VAI*e,{6)6)I<6R%YW޵%1F8Ug԰]I(5Y6mc !XD,2!藝RrLRCIHٶ-b"; ՓCO_||8={vP]ÙUVm4Ӗ)g&wn8(WFcت_ ܪFJY yFlmh0L}^@Mi0;33Pz©zLUni{)e{U$ B*M:etk}IeYH{f> xČd\v^?{A_.)_XI9VRsD,tWRgO\`Sg,R2AbddȴB RJٖSJصB"H,SL|"I>4!F^1B $1EBLR+o0m0##3wcJѻcTqdMWOs.Ꭱ ,JHLH+ Ji)lQLk<LVV|{gm RZf D%{e_ +o[_cnZ]wAwQ]% z鶬Qqԍscg6QxJ #JR%$Mm )),캮}J!yL@`D=ђZKr t! $ Fr m(3>q08q:M $!DrMi(Nw${|'wsR!ﭒJKc8&)y|!aw(Xy}W4 "!\V+=t[wusFny'BDpy5{n_8]2=M3)!Ĕ.%p.նU}V:姺Q ,ٝE[y`^! '_цZ2k&)P*!SbLFWc n)Y]]B0Yah%!\IX5]]_W?`#xڀ-47ZkkuT|Z|Sڮc5B >xBBܞ>zz[ve|tP~SqL7? ! \FSq /dCXRR .FRRY)rƴ2(|ls6\9l:il<ɴEqf238~y,KVVVERZEϊLj!Fh:kҷ'>y ]]߱UjMf=t\U%St9M\.C,* Fc",!1C A^7ɲ8oNs<맺R raW>zssWUfNĔFL1"3JRb̌xg$6uR"K1"E2)DH)RLL$$K®ոW\!e % ;ECP\)B3NR,dY%" 2sL09&@<2{Rbp\2)Q&χ+EUR^ FdR@ &Q n5r# vCG,>}"Gc ^| wdځ^AO\JŜMePQ0FZHA\`R"Q b1CXR $B&@]b,: rkcJYX#uއ`I{U&R)r)6& zzgy+-$y (hw,@b:8"yHLG Bd&%h`JH~ix};gw03}%Sʜ˒խٗ?WNfUEfecm%lڝ]}C$Fr>A g4b{P=>cnF4:oPدA)U&SJ!0&!zPiSd!D1e/!EL1DH3-J*{XY~Y%`ZީjUT(TY뼫E^f]ޜN&~[b"$$ )ޝ ͪ^:s K? ^VT3~Y$d%$$H>8C6,1bdE $D]T Q NEWOu5@7ENѯ؀[O 'Ru˴}W7c7F5L9,%O>SM.JmuOHҺHz.$8D)UI"w.Kϳ8̹{+}pwvlزc'7"AH")D"R@"E ɑrŽ0c;v^k9\̿}n\ko|>o2Fcmd11Rr+xxT=piVB̜F70vXP=- όӔs"I h)g"֍rf$]#rkMGo8'mN%N7Gwq0΁N `j1C5V+o?_RW|>8>Ǜ/ݗ_~]{WS4Q>$NӡY2R&5\R*@n}QKa'&йD!#Y {cm@iCj\A'mK y84F"Ʃ┑C#J,LsYJ%yl= Do <@(%`-|ы_뫛'`_W?O6~CE{'?^##?Fm_K,+yv{#Zgk$ H}կУS{vk|⳯̋?ykʣK_d~kPB0;D$f "DKi{wj"d P?NyT|>xzusݯ2|q|z$«921f$@S=^pu4m;3G(o7Fh/>7ӟk\sa$H )LsʈzPsi4uLDI$"RWO:0}u RԶNa]R"&qϾ^۟^Wg^ܛ9 "%TGLӔXw-~\Dնm4K(Դm%`fPurjm :L_B˳1p`h IDAT$Tk˒4Mnm H=lfaȈC8Hji$N6& iuBۺv{w,>zhjIN%vۜ@|5So|^{rW>onB2CN+$""&LL\%Ax-ݽ|5Z*HhemdA r KMsx&]R1%fԇ}c},߽G~[ ])rYSDrΡA;G̶\XOǘx}"kpO2?|?Tr#oׯ?}^>ԛ#t|α 2@^$i13]Qf۶Ѿ?ރ@۶!nlb0Pw"0ewo}Wr jctG讇,NOs2 DIu@eYZֱ\P+p;ϒ=7^]ß9|_o}~8UfHŶmukei[G`)/"nSN7;)c97U'T`]/!0Kjco?jJ \~|zo?Qn~82UddB.!")'D31rNo/'!-OAD#](m*)=j>dbH@:2OY!ZP2y.'|w7rA$fC\[0ˆ[o XRj=P KuDѝœ>])ѡ Nl$?E ͗_/7_|5"v}<)q&Lm4"w3C wO)!n]"jLBd="`3!'ٕ2s w@"aJHvz@H)ޱLnZ%t_)BQG;J GWS`@ĎF23dR0 A<չa ӛt\BG8ε ]Go_|} xsRn}}l tHą"th\tq<HB)_K7e߅ nӌ!aj:m[]VUU Z 9܄eajBt35pRݓu'\C'k?k|5Dack:$8jB$- x{c۶um&ڙ%KчE9,fpHr߫QU )MO/~A~G{>)9)Ԑ1 INTh7=wJ!XdYq>j=M'՟ 5֏|£O @-UdSQD+51tlm)%F wSaf#""[f>(6MG4>YsC75e45ȩ0aD!\% ӮH@.ff!4UacRs-Y D"|!Defc @L%$ T)Dao)y-Iul6 둿>wtڿx_yYt;:<< wY 35#KJ,61࣯\ݛU*щ/WAHDcJ}|<ȶǣs?H߿T1:£s @ytZk#_UDG 1D z<_}X_ɫGy/p$f6tW9O2~S>Yo%r>q5ϮBJ!a*z? շ~{MƠ2c'2\b1^ M<|0 x12O휳X89 +B\kCy7n~k]ON;S ސXz|ƥl%e0MSoFJӛXc$@0w[8fQdp?>G03J%Ăi`[R;d:h g Hg(`N)3c(;.]] (ŵkyP6.uԒ[Hε^.5zI@1q^.RTp6)ۚ5#X IcmL:/}?/_篅:O@osNl,7\@ m[9 G r!bĕZo<%D3C"Z{ɕe]{Ha3y,$I8\3Q$ # (9c\]m9DɎHFkp03\.*l݈ѣm\ 92Re J3-DkRQ')xqrO}&˻׿}x_> ?>A{Ÿ<'И":Xб5HUC'+ce].ۧ^H->哛sӟO>zG?̿Xu!aV0jaT3 uuw7˥*09KDTwzADyXhG@w )&!ދ2i +#&\4%xqH;ˋ~~yttk.z̯ݤ>C Sw+saB](MB"9%|˼-DHd^Ηx8ϋ!EXsM˲[+]^\uodG/7,R)D%% (\O3ZGif>F3rFS(ejM ]-17}amYe<̧ZTSP+V<DH{0M9 \CTpb "g9ބy8SJS74} Hp9B5kݰO$;Zjd)a:9Lɵ#DL%5#!9 ?|Ɵ~oyI!NZdf70} OӬjHt;0>f N%CED݉Q#S><@˶MrY BB݆MNDHIC98J%4.[ nΠAzj>y{dYLYrMej}ur0Cadw(؟?Nǯ~)hS[;2a&Dfj8l\Ͼ'q[r0vxdɒ@_7cc|~'$#< q]^UGuE31s)w&ҽvùi.L[ n@6˽RH3ۖ'e$[?x/ӏ?p_R_}t}}<ÿ?mt$ at\h[9I!6uj$a9jn`@``\_=y=6RՃz۞&Pѳ wC}xbsa9g"ҡHc t!Op ,f<epSOE%oj.#{x8"aƋ! YP-1'Ąnqzkȕ7 0pT#5!ܗ1 [G)i 5"旑PSVT@jюSЉRJ,%H0" "Dn>IwacTBGk+[c1L] c ctp(zlX jmjGqo[br*9!&$(c4]#h]-x:Y "vzNIB Pu+y}M7k]P4|ygqy3K? Ӏe2 qGM2Os۶KO4,t:gɷ}P#l֚%$lY_s.Nj cw2M>}dw`2f}Xu/}~DTD2OJ%'ׁ=#JR"@MU&h`$7=Sre7YFoFLym)a{$ts:Ւ \2B)!)141D\J,sL(\8w}@r 32j$=,޻n7Cwćhm+J[̒4mpJ,9s#}I͜rN`w3yG@NMݝXy7@`k6lG:EızGBSm.9%& /%0SgA@K޶)g(B~̭dLS撈َ'JTrɒHuUuaYI/0s$"@_\h}CʔY-Ya2qډpH.2KW'$s-r' Rbb`#" `zGl;;i6siFttwc% TP)cСMf@~|'h*=ec* )z^uso8ȡmg'o}p$H_o<)Ex#pxp֛/ <[SFz2qh,Bs`ppmNY͝ԞtVM25fmu[ ц*`R"cվލb(@ģo-䐙O2c.DW!C\'@DRǒ{8$TH\6x(t7u]#%ɜM#n mtG9#d$J H4]p !̒La4^%-(:[5kc[u۶;R(T).ˆ0"sUE)(%.pvgwhm.rifzǒ)#Fcqux6See 2.RJ\|<|}2oŝv92r(2ߋ!%Y.5 L /ziZ:#"Xkը8AL w@/%U#l>眭wJ)ֶrH/Rx .BpyDǛ{I2o۳;ј<%d \o\J))to}O{W?[Wo 1?5ʟ}[^?|w(XJS-Ӕ Φfn/;^s_3ewrjaF%\ ǃֆ".nkߜcg9:\\w H3qY@h}pJ>ܾa:.gDG۶%K2UsZ'ffaB-"Ԍ+"1ꡇ:8xFD>0咸0'a,r>/D`cc{w8}k7Q :zڶ3E@xD@ݓY' A6E arDam$5bYZo[kx!e82?sfܗeOjM`*IkzӋ7ҿ-j=*Y@`(6B!þٶ^j-3&|ޭKru8!r1oke>\mI @ʄ5#"FwRm7G";R^yr'hc*|[{k_9kJY bewT7'N+c4~wN7Gu'>{^7iM0< soad& i) G~qXbw LD]ڷrז͑p8y6WCjmh:s\u>lDlH/B a*`B!gp$ $Hv5p\ז"2P&J n:<:k\Z?/+8  @oHؑZB#h6A4̗mK h* ;0Q:_6<="RhSBMSn%Mm5[bbp덓 @`$D!| Ú2 hmDYHb"2 9焉vL%%݈Pӝi6TM0gqnjãFD˺H.܇ŮxS#5u3]-P"0PT{y fBa14uytӦʒ65P89H. }X#b'I)ۆuSfJ"ND[B:ϵYۃϟ,{?ַٌh탏YmJ\,ȶ]uݞ|t&y.X[o2T2?{}3 \Ew6qJ)I*9^59H.%%798l[ۓ9ADh/5RJnpzѽ7Xэ.x^}ӧz<{WEG9hM@BZh+q%>?}vϿOB? ?,"nu#^eO=w4=CQTT'L@{$nYMug&]$puzĴ֭P쉗@K$";a0H޶>})Oưp˥z̆Rϗbr^9 W:D̬%@4 D^Ja$cƺm؆,T7$PE6&L'v8ź,k[# қ IDAT_/p,2zýN%%p7Dd:&L:4qΒ#lgl ,/kbBFm]wÈ%JIon뺖Z 0@h}S37ƃ9ܰȵ\5g2Z_{7@!Y^Z(z_-s-s 0@0T23GR܌M}zѺ]4fc nݡѭu"ct%aZr{s[`^F韁'b DpxVkeDk .}~tcFNUzm; ԆᲝG 8i;\G|,`[ v~~m|[!ێ@a6Fh!9IRi*z $ Oֶ1̓CL BХm*%=pC8\IZY0hCs߼{߱4mj# Amxl(-CZ674[ֵLu6&FsF qCLC9@FA{,M,7m/ֵk`w pzHyDP> asITL3sTًŷ)ʦW7'~Aaa]sI)RfcxP++-+v aD|#t3_.ć[>|}K(lwA0  s "INs{Wb%Q*i'BL93|!ٗe9#G޶mm77ף x\ }攀 P=J=|L+|zkX?NjN"Z$ F/w>m B ie\2"їuU&~H0 AfɉQp_nϟ?UC m ]sd$)%Tk}?"=ĴӼYYJɥ0'VfN9JcG,@WnT5)CPU[oM7.)90L,˺˶rTj E D~90Z+16 ljnmD{Ro#ܷ-lZVA4s"j!2Ad{Ωk RJ}"{9ߋק{tZsPP6: Lc1:T. em=,KUVí'BدOҬQo7ٷSݯzywo?gr<ͷ}mT"Έ֚vLdPbny<2RlV9"ާ3@ʴ)Vxgp~",pH*wOʺ` r>r-R'?wzlן_/l9Vgn2TBPzl 3$*E2 <6a˲YkOe!#W qU(R1@pt8ŋO>/?eL#`X jntnj)RuD"K9x>m:zt3 HYV"01z7$ dLaVD&Za 3$W/Ꚁ 1؏&E)=GXծG}?9ufV[k\ ZcR 2P0dfӰ"DB)rmĀE"<8-JVEnϛ@bX"S ʺX{ۿu{|w/ ?/?/<nw7|PfG۬|^q>)qi; g fD$163,E4 Wk ,߅)Tq-0`WZR0 K>#k) 祮u?GE=޾?sL \nyRW *BYD2\ួX04ِf-[V:nJ<B'~?x} >ׁۓ%tp-4 (a~w_mxbO^?)΃Ud?[U oi$zokұ w$βɰrluY 0)Dcv5\529I\(h):0}A1&}-"#MuՑH zݏko%.&q&f3rW/][@qCXV^RER$E"x{GHz6F:fMsua؅i8g,3ݡj&|%c%uJ"`D/>3WfYdI@!$*H'O6.$œ>AB:&^Ѓ,W\,cpMRms􆘂IPWpA3KB("u7gZ 1F`o/0~<(#+!%fJ(>:3eqJꦌMG7U ONn1z##$<-yudH%e+5U]HHP3wXw L> :L{ypu1Zk]S{t˽/k?D0h_;>{7E#Uux!?g{R&`-Y>zNDz +AH3+gcH}^@U=7I{+O }"|rc5 Ջ?䇟qo_) o/?w/NS*9×u!eBHBz89 ah Ԉ4u] 8m;SzHPSxDv$3'"3g(R=_].Lh`1Ѹ T.R`hKIJ|Z(sXst@bv6:̗ӫYwBJHBڶbHD1 ,S <ہY83} uYkE-b(QуPr#Hu}DZzÀkKɇ-eQaQJzfdRH5G RZ3xYq"5Go@2Ti;yĉf弽=H@6̘|TT0JunP\*M[fz9""TuJ($;"&Ѿ@52U"=CUs-̒Ts UM6u[B]%T+;EPݸ. "R#z) Հ nއ^wj) fvsZY(Yx0s$\=xYjccf&5@Lu]E6TĆ0Yu;x}{'?v%婴Оɲv5.r9!Ov; n%OKLaDA" aU=NH"DDD2;vuYqW a:ysԟ||>?->G}m4{W~{p{/쵿?e{r,UdJL$iL_n,a`VDt@fvxuCb0"l&FRTHf{z'f%"եZBF,֧O=2HC( 9ӳkPnC"ZgQ { v5eXX͇ͲE Ͷ8Dؠ 8m29!=L#tZKdDkBV GF̄(bVL%3#%" 1 U3R `!Rc`YưRJGpm}rPFa^˺F=J9ƈ`DDVb`nIH<:F&8nHgԟ~ʏ>xr{®phNrcFȓ7Up;ݹ˪TO+)ezBx1Jdew6n?[nIg]<Td†۞{g?>Ow[YVg7sϖso}o~_?<8?y}v{Bw5f0%̲]LC&µGZ,0! C),&dX3MFo,ĜqN'$@"$Af$6,\< ˺ ѲiKӶ- c0qo cj& >TBo/_]*q]S>=w C!mZ a9jèV `i:t90އYx]6N$fHa[cW$L>m˵?Dq4[1Z##5=2dup"vm*a]UTȨE:9FfB %0{u,#ˇ:AF.KE2Ͷ0 BGN:}=Û5>;_{'^o<7ow^8ⵖm9OEaZFBR%2p!W*Fp\Nm㼭ՎvLK:-L- ֥ g>Z"fv1KSCH,3k!RXݓTKFM@Z(Q#<6[mJn֢6a^GoB@݁B݆qa}\ vGzuv'k]R62 ,$R+BСQUCV"`d4S ۂBRPԈBeY,I=12A{w5Z߮)3\ ׺m,nDQYoIctD (R-ʋ0sZ<)1c ѵaaȓH1kIz,"PKZe「P6y*KcvaLG>FD P 3IJUV`.CÍ"q" vCDU|rÈĭnAP1"hc> DG' XEƺ.c D|*_:>{Gñx_y/.O姾q77NoI]N_ 0>r;o EL)f7 隖>F̎z(3"nL.-J/8bo6RnH.kO-7>Oϝ3BpP 7B@x\2"A*R!#CV${3RDy0##f "N@s-NHH"a?2Ij)ADD\YF6Pt^E-TG܇z3b-"`]$ʄ4 bCEњH9g*5F j? ]}f"pDT I4z[}ңEj]Q :gy`kdZeل8#9#A͌-ڎGiiﻫH* 3u[(,jঅ"jz{ σ洞Mc]OEbR'߿&3=k9{pܓxd$x康#2 ͣчVD}?ۄ|݁ " 2' ŤLrC  Ճ+";DfGkZu0 Qu{OZ̵Ejd2N dRQU3hU "-ápH $鄢T`Zi0sk: $<GJuE͇Zs4"H@ ifc',*"7&fD>|h'L"afq4dtsӡH\#"(r*Fd3_ Ww8c|*#zo}<΄ 5Is@pц!r SMjfϊ:7…p7U ԛUOݝLv5Rk] 6L-q<dΫqOY?oTjKkngmkނg/uͧw˯~ư˽[}u[<>KC@,e1}\O֖e 7HDLH[i$f `J̮c wUh׫닗WzmZRʶDUd)R֘h!LQHCD{l90qZkka }tS$ԢכֿI"ҏc!ʹ $ .uEcoG8>Zm Gu3{uN^$ a31K|fLM{ߛkt#<̑{CmRIX5 ۾u?CJqs0uk3OD 23dD)FH\Je;3bDRf!bLpO㢭C&F's"3WCF`K۶1ص!A@a t=,q'֚mۦL<\a8(2<̼D,Ha^щnC$P$ϐ Czc]9z,5gfoc^1TuRRg涮,5"z` ac~pѽuoK)ec4$$ R˕XT2*x[dt{:,u3a}mt !<\3mEa訟pN붢,Ow}W?G~K.bER꺞x`{'[ ƺO"L,_"f.f>/%&/IsL.nP=w.oVFb7|h_pΛRu)nRD4/ʈEcB38 0xA:%zMûwfa,n 3"!h$"²,T @c՚BX;:SBa~$G4 R]R}@ ataZ+j"<~9dY[j'"{@ 1Cx7'ᳶfxA\׭wÈk?V'O AtuC"ڶ ,UB˱c9F>p H+(ŝnH&wR5́ˢ#j&u=Ͻփ5-۝G8۶"RmǸ*CyP;к8 EA蚥0EygA3U`ÒJ4<f5hshsd\-"Ui14D9}zUBhZkˌ"1[ eHKWDҞ"aA#1(_ܿX#2)*^ !Rqsm #\!A70fNc?.C۲&>Ez-Dh) r=,/ǵ,fB4%DDsU3HRogކY e`e"Q8# B0R [2v& >pӽ>{?wi_}O)ݓrXPϷCM_>B]DHC U0NҜ,gkstƓ qNˡWW,g_K_?s ngGu~/~;_{Rc]RF7DdfɤȜ4ݔ SVH )3TK-(![;YX""tXpC|VWsPeUk;]=51M#2ya![hi19z{8b1t뺬CYyо_5a5M٪ $jj0sGqPC>1Sd0?<\5 !BfCm͝y)ڣbRr(,bߏ|I6Ca$nJ8wwC )uhc Ab&-fI(D{H2/cX&IBDZ !kH$t K@ݺGnN#&8Tu[@`} a:"LDFX e Ld Bz* `/"=1)m߯Q㊜Ŕ! &cwu]vP >o `Y NoBR"t_C[[wKGn5diYHU'n vNq^FS5Mwd37 T,T(zSWHDf0 m 6.)2E&YyK끸P})ZHH)l9m[F0!R"J%tROL$dBݣ%`hdE$#8O n "=LSz@FLp9۩zO/zLĮi f jaH,K7GD(%qaQa`LrO $OgH4އG @nn}a>/ֆr2izIy:“PJu#A)K #32U@BD!6$lc9x RK]#Mz}߯,rX%z:r z@B:: B4ǘ @Vo?^'OJ xe-0GDߏZں-pP*0JDjeuY"|V3/L˲7$ x "&")D8`M/7OQ_}3O|c77VyW|[^D02 1&Ӿ.!"SB ,ssDݒg; c"sZh7R(^zp }76&cQD2+;BNyݦj#!F{,Ee5}RI{%ca T23ʀL`e;#-4i-f(@z姼~d-/{/?qkx(w{1U "˲pyЬUDȘ@u{Ėb;JD7.;a {s}i[B ` bT qq9AIl%p`lq![ݭwZϔnsk=C@gC SjY koS{S&?z7_Q\]|d9 Lnxb,`yΥ Tz[C0\ !nF*0fBSw6 TЛ91r᢫D02#cc6ͩEdž5Qs*bJ|DS2AAUs.n9\pX$S7 Іtmi4 5Y[7^@ضfv*@FDerOLC̃\"r͍0"YTu{ ʵp04a]WǭC dfLd<ՄʘZ 7Rw.~h!'S Hn[9<|kR"S&1qբL斷r^ VNц8Z"a0;N⥦db@h.GD*!'F51 9My A3eu; á,ĭPw jM4L1E(% X& A1@M܅9F<չf" A@O]&;30@ 9v-Ű4D3,!]zSiJL]CIdy9`s亠Xv5{^7OptPJn 5_ɬ&<ӛ'_pA3!@<{V%y[R0%LLT#P[sHs œT\rBFt[2ZHuڥ:uuCb 䚻HcsI }屍hT"bMu8iKyYzĆcژDAj61;y %JKRr :SYoL0$vD@D]k@0uwOLàC![C6"xY5Z+!ޞT'se BH~.k>?,b1Pu5"@{o)U]f".%Q Q1՝ yRՍr&J`BN]CDXrN˲P.}愌f2.wsJK뎠CD»١7,)Lxj!<團{̉s.nWrN)sNz;4nu*û(P6u5o]͡uk#60"#ql9s}5[nЛVDpm2NIDv󎙉LkNfNdp2З9}9| ؽO_vW/] "Dp@Ɗ2J1IՈ3ZS y1R$\%y %Pn (!b ݴVT[2#UᆘxF\P3 C36phMU={oct tW] +gl;$~{]n^'4tD* t\y$V1H+b*J`Zu1ДX^&cDu2cIDLSN@D}Axb L$"ݎχZw}`y"?9,i`Sܪ *8pǡ!p*& SFd  "sjDt}AmXq#,[@j.j@n:8@[j1$R` "WEiP!>nPJ5m&"Mr82=c; IDAT$:h:(4li%ۭ!7ZCNDiMrb STi%$9Ya" b!$ ȺzHp_ñuGbr -`&NyJn%!D䜙0BJ})'^@Lql~~{_y#ӫo>ޕ\/~_/sv(4eH9q {"#m5"'S%"3"¼Ub=d3#!1nկcw]jG[} y|2gFc"913d_M:3Y[{:"![zxDG/ [su_ׁ>N\X E>ַ std mjM$ۺ e"1ˉ!"nn<1  afFZ"21QW_nnCn4ZRud335Q  @0 jaD,EM6:03! Z Ǧ>2c#%W@ks%Z%7G@24w@Se$3K/m D|bBNỈ݂T5U`Ŗ̛ADp 8;z@`ñZ m;.b.MT"H*"aߟ`"m'm(SmmzsW=>(]}tW\Y-))X-i?%@ʔpݽu".`(.CLeP@o5R)Li% &)ԋX/ 'чccyf.*hWo>x1ܥ#& +  9H# g9ⶢv{FX8%FG'~`뿹jǫCjIޝJ) 1%3/e8U0oRJvc"%nĀfUK Dᱮ*"cXDe n]: r/hn>D8B`"DDٚX̗e\|A< QV^[<ys8Fn桶(C**?X-tx7 TopuQ .BՈS`ZP!8n[f r[0sI*:B#|lE@dD @ Q \ʲp X3Ւ|X8rN5g@fQnȘcZU 4TÌÝ!l#`*Dj:D6z8SR53K)oM KĬr<, |SOâ-kt9-(p2ֆ:>̜91c)EݏcL {@FʹD[+q} K FtWp76Ul5Q17 $E`[2P0Cap@-D@\2*69 l?"JEuG  5\Ӵ71R:+~W g42ؿzᖞ$WF榪 "$klMDƜzΣ1z$""ǥup汴Vj5ӒK*nL09!brʦ=^\l(̜(Jbno\n2 LR#Vr7 $TV)maE Hꪈ`˛bmľxV5!ѶnDump70ۮ1WPֆok 8 $ D݂dTj)SoCV2\2{4d91#}*\E 6DZ77/ aYAͷYv*2s!1c1TcH mRnnS&BibcĴ&cCl"R 2#x0:ƺ*YqCdۘ QIR Fffb[l&5g/emFe7ǀd4nXM)^뒈:$aݺ4al ֢PzczlqB x{iC `)YDkacdNCC{S `wHaFoVsp0% 7R5Q)d2*JTCahx2\]L{k]ւE{l!r~q浵jFMDod1it 0T({?z vNF=(,ߞ#m@C-=J.bLHd*C0VYv[c=J.Ʊ>t 2D!u<H]8 1݀oDYtGűsn ש 2TTV tv&2ձTMݹVIӄ 9aILhe"L)T2ŷV%5w+*қW$%:M2l>.ӽE؝?vo}zuauNeUWڻv&$3#f@4ՉTJ^{gBwy7c0y|:V SMSNcPtܞ~Se4*n)0"PDw L颵)2sόC!1(<1zHQqbpB9]amPrrHr 0P Ti]܇seLbH+DhiM#cVk9vjt0xcWm)d,S.}4 T21[Szs=VۺfVjqM3Gw]{S̍<0G ݻFXxYn.}$su<,GȻi5D>뮐rqm"fLmm#m bޚU|Bp&D-w9Rs99ىY%\^hfȪ)EhjchӍA)Fz> Lq>fwϥӡD4Q^Η<ɡ-l t`Do SJy*ɆMᄠ,c~FQ.[%r+EygDlCf<847 Qk]Rfo(_Zmch-d(}T&P D؆޼ȝIYl`8uh(6kJB=<8 !]L`kZjȈ@ r;"T\#,cyq]n0LXrɹu *k)iػt4 "1TDTQî# gA9LSV̤X E36Qn=4bkLci[Ż F?D_@Eiaj]H i՜Ty̭q{dQ#-0 3-  S> K`"`dbuVFթ: ГiGj#!JcS8=VK3r4AG]բ&ͤSVS*Z22)yozp]l=O&}Z_z?m5_ܚ" ،f, I?G nK0BBy7A1f7}pNSZV(2Zr+v<_?$i}_1@yOg-O .[ܷVo7;/SN@܃$LD1J"zb[C4}Қ眶VQ”S@5+%R\r^d$B caMCUqs]^<-\E7C?&ʭRF`XU5~j9~%7٫nLcDn pNg_$ 5d+MSZ>O?`_sFRNO&9#E27&ğ>S 1dH-.Lד//8;‹/~ཿӆͻ W)P?L  O)H ?~ kjrzsG^s׵kbaS2`F4O&R&#sB7n\|뷮ϻ?٫P LE]dEoZ2Cs'0\aĔJ5͠EeƚK"O}?}Ɏv|炀Xe:na%u O؛B:SZZU#T ])a F  T_t}F?zΧ]@2]~6Ryl$"-ݬ^9jHi. -PKA ܙ ͻ2ș\% ̙j7NOK3aA̪@&c&wZm _q~ nyWy{̓w_[}~ߟk&gx Ĝ_ݻǼ S|h>~\]*W~7o~}n}9L;@˜K ~|Y](W>Ї~= 8B 2ٔRITS/*~7}}W On\?XS`R;>ƥ3O۲.^go}{'??_T'jZK=.Kצ;_YF{ww_+$C[l%O]y0u#޾-<߼ OC~wZ͔)L "ҹ!9K:e=_oׇeKk.Ü3OP*%z ~ֻ7o}BRiw<}J"ݨt?|#זA.sW_}֦Zb^ChNN~3|3~ Mwwq4K5NW>v|SO~G|2zny''gܩFN+W|ey;~o7]ԧ>ᇯ?S>3RsՋq졇z_#SP/|s?7?ĥ< X3pg}FԵ{-4MuHPs[bf90[`s[>?_}O>O?߸xEG==̥;ξ?˪v?'[_+{ɏ<{^]%3{Ygio;;ۋV5BH4j)ƽ'c;67H8 &6MA d z{>SC}?y*Y&zҜIT.1;5+/sNHta`p|dҫܰ{Hw451ۢ aP(۲)6Ô !# rÐK!)\ c4Fh " F#fddҒZ@ VR 58j&FZ2Ik)'0BJTa F ", a0hb`@HN`IJVJ*J#PJ4CqD:k#m!׉Q& .0˲0!S4X(8\46uvw  %+V8Taib#g89auRYIGrwϿGptl{aUK-|~O_KkgLʢylw4T T*G=+ IDAT']bL%,h#>]UЖe)XپhC=dTL 2X_8}ۗ4Ujq+#_z¹ld[Y̗܆v׿vez]ԲRZGzlccwNG?ٹgmw]+n١h#T'ovp ĮGuRr%nG-L!B)m`hO2 2Z_˶]~{W_fWl?{ā#3P,ML$`Mc;LZ0Y_ܚ/j$&_?_y[Z;*FX%cI'-0妦im3̇ݲn-Pz6zb_l2[|KlHÖWwוBB)#ڴ4U~x|olr_B߻cWF:Uӧ %T(UXk[1BW;}5{.{C1'SO̽gDK(g :cJ5Voܰ?ҌD< |C(2@u>s'n!/_?vOer0qc'Μ"Ö,Z=Wzsӳ7,LWM:ZO<1/Y!c/^aN,ɺlҷl?7Y!4E0BukYtBHQK#A!" ⑔J2FWJXr E0HJ-)Wʘ [LTɌ3]$jy#QK7lx/;|,L'e*cwz\a(|OҀrK`Ɇk6_sʊ:rѣI۝@iCT}~Oys3'3 WRn<Ń!Hα`/f <ڳO<=7.߰0Uz]Lϟ9&1XP˶0$FcFk`D$]s'8~G<>āÓSy]ugN"V:ϤElvTnn||5Fc'7~t{n޻7pŗovJ\yǻZ-]}eU^j:|洧ԂkϏM=Sg[}64\qoy+uv˲Y5f-|Ek yѽ/0ζn\Ǧf˲j垳|Vv<6<51_U2BE] ,j٥0vpl٪Wu8/ght"_ w?DP$!( D7E^  {uSʞZ-^_K{Z45u%mvc)(;h";-+bMfy-cdž˪ҽtXtWg9{@4;ӄq:8£gN !c0Am!dB8j`b0Xi򝂺@k۶1!ZT4BfقZCD+i!B F[K&%|` F5҈`%%LiZd\ ھv(ـ(IfATvG-@@aQ֊ AiP3]B AL#.#m` PR2 C52HH 1kVױhᅷڥw_ML&Lcg8t\61j:fd!_?SNKoT{џ7zOe'f"ib|k-Ϟ{l|۷. ̯W O3^%yC|u8;B^81#gN 6_޿ݵ2}o="=G`bӲ%Cى뉬<†RS=*PO֥%\ژl*N%K%FcM L8uNҋow~kSGoz#B 8e.yپ3uG3"J㟸;Wھ O~{Xw  P7\y5 pl\q_f}/w6;O}7M,:Lҋ?5'&[Z{=y&T_U_9^jy۞ R+/Gt^>wG߲coS_v=?q_ܧ>+/W]j^- .qLG${yﻇ !)?'9=voԍu0;~lu֋ִ iYռS`~Z\ş}?< c'3gջPWOƪ7ݰ\ f8p?7 o| Z_Cرˮ (é#Gڵ N>uC2HCJfǂ.3gw,vv?ă%o#hv:?5[Ɔ c 1te Fspo?:MvL0Fu::ĉs'.7֛q(ܮ'˘s~zmlaVgsq߿C"›{΁SPD s 08͇ Ƈ>ϟ:{{xO_gS@e~}ۧK؄u׾cC]ۻ߽,>¡yl}GS3 i֖Ehe#٦ަɡaXܡFSDfB !TR+eHֵJ-#B)0kR2Ri ƍdh1Fm e;2rc)%ԐƱ0RزBږJ3FB)rcm#4&p 1RʘJȲ1QcB BęFKU"fSqu(r;Rą W}Wxlb;M[Dqu^}@Ѕ Ʒt[Nys1pJ#*:wo}T&.d^`(D%x|t(Oh^mZ<734}:}@>RtcIy p{wCqp̉~ύ;}kgBbfH܂i> VSm;Mݽs#VC_}7y.{Ǐ|o @i|vOO)>'(r/jU3Jfgg#SzNS e - [gOl]1(bM.]T.(wӠ31z^\E5 %BF@QL B.VTjj+!)ƘBJj4(%#cj5mu])&XJ!b$hF !TIQkF) E2`VNR1`B0@ y< !tpLFS ckRc2d3j B#R?OqEUqKUڮƵ4e~PK(*°be?pc|e޺lȞZ(1v륦4yUoz6^6@#=7__* %Q87ŠN@b8β- pzw͟+?zEs;[?K{=qR9[XX1A:j0oXT`X Y<@: ]۞[79\io?W>|PڲaH&cƱ3#tْ\riZT JǧxG|VoJ}Og]c{vw2[a{^K_w*} Qi]SR lB#D) H! ^5\{G빧j^d"+7tSkԑ +g_; cM̵1,fࡔiBȄLs|[0.,CBl EJfX+C!@l*D(J^6h_]}h<]}>5mc^^q^}6&  wP)D#Jk10<(EոW_q Wt.JEgg?{˫\ fႣ?ɯƜF >6T[O$T~+`r5<7z̔״RR~l;P˲,l JSfiô6&`ą!RIi!C%5׈Z"XZc@5J֚sJBFJ`\FFږU;"k"F*0EV&KE |fHEV !1F4 i\ו@l(%6FGRc) (v)cF"0!hǵ)md,SJlEi%)aCw_`yȵ13Q |{re,Å4J]Hh|k&Yzca6r\cK}rF7^z`,TF9Q_<&#c?}qg4>9%@ ӯxƋ~㡰{j$uҬo-WmGQ?;7gtj׷] YpʹŮb.P@0 آw+_962|ggf}ٶV[߶pqx?\kSI^|x텝'^;^+?xkJT2|73+2-ˆz|Ůes+,A FFo'Oko0+ 1A`cj7q@1!H"㱪?fU?GQD}}[j8z{a7M_ĺfE#׵21sS. cJ`ODY~E=+T%JCW<ؾ8cZ+BIPkNW[gKJCNϤ^~llL/lrcOƛ3?ӯ輮nijfvbvvh6;23ַ1,%PZ2*͎҄]z5Wtz`9a{]qC>BD,]hƳoΤʅ -x46r£g^:׭|P1$px ÊWG 1w@kэo:b7ug>맶[9% yօk]Dk.Y.p)˜F2Z`10ě܆`𩱦kGKa/[8ԩ 4%Bl;@a .(m,sqqBDA(e_-`4+bhe!c Ccjr!BYLKDH m<"I@wbkul qj1&0ƶm!cLR `("!}ge#۲y$he!%Wc\c@Bj0F(D8J'dTab"fET~ð>\cӘv%Q)nj*ܹ-Ӕib겥 ʭKv31^8=>d;kU'P͝kkZLj]V}՛zRFQ/]5rvPK4\V(gbp0 F׌Q`c)#,FB9oɖ[۶^ᗾnDj ߛ[q[mF O΍_Ǿ=|`96/v>;#셑+WΎLtw,3`nzT:YGu}Z#10[05Z@@ rztncbXJշMwYT3^.4+60x!.yAPӬw{ςZ0{H+?џ[;ݭuY\,xӏ%7cmESFaJBwG^N5څg4"c%@1=Z=h?o? pj|1FI @FӠ)?hIqSXg: ʆNM*Á,˶0rEtz IDATǚWM8;;40Jb6cb P*Hzsxٙgz=qɳ޴O~ꎧl0lZx} Z ʢ}j5UẀ2h:ƼR%ݜ>i}GqTP3?,'Ӭa V pιր 0uc1q01J2[JAQ0۩ấ1KB0!Lp9'ZYLr: 0Be$9@d on1V3ei)c!#5B5H$јT3 2$FkJQJ5 aF ;(a̶]%6JHpFTU)Lf+)TDAx`L>p ssޔ܄ƌJֆĨ$5#-0\mkM5ՇBMM3N+UL}<2sٙb}jI02xs{!'X 0F40RH d#u2-E7M9֖p9`,fldw&/c0P\RAsbqht'~o$ t ΕN<MmV]қ{7|gϵXN[a{>Sp칉~:Hٳ/}#gC@I OLx1ORF#Z; clYFXA0BШ4;;r҅m+uD ,x{]|esbu/ Z0I\L9oȈ(Q,#-8'9>HΕg"XlZҵpYe(`PJJHhhqssYȢbҷpA(嚘O'Eɉ^knݺ41(#"jL<ӱXTK]LZ.قM4CD "s%F96Tn%qQT`:~ _[* `1 \F6B، ضE1JKm}umSG|n z̽7]@虿l_/q=usCQ)'v_?3tkvvw?(r_Ο9ʡ֦Tg[q<ܲ±^tyR^Z:5TƀvMĢ_w2;J*BXXIەQ! DT @[ F(a5$jJ B/RB(J !!DM[gc" 0BF `v i1 #1H[%R5!5FcB6 !F RB@JJ,@i ׸2ZǪ3zRB:U*U*T✑-fTOFcR@KQUɉ|g-qR) Tmq0gsV}2u54D>h!U2hE1xQFŝXI!ձRcӲup\ko7/GgKrhLgD`| (ta$t㮖#$s)Qmp4ku{.YLH$TU>7774twE*pZ|Ǜn4 ;L Z+b^Of`,h'[ :\?YL%$8ܤY1aBuC&$ 2m삮^Kcn3Pҕ) {[~}͏}#~B\[3J LcJ*@ڱmFkF Xh[Mr6[J r*x'4R5\K0ͽr"miTyv.oYK\52WF ڶ,Am ]sf[ѻW/]NOPVFΤx/MOʟ^xՊ5dg^R|I[:ʥ\.(cM;0,\\)Vs]K:̓ZQJؘ1 %BJ dWz)iףe,3oQ#Ask۶=r:/޺·$WF J:2ԟn^冬/_BiWs8t~/S BR3Fq/biq mU]-I\5u97МJ-?77omnSOn#RPƩJ=Wn:D~TƘ\'g82Wlb C>B]nXT@ B2aRW Pa`:䟪THC.]y$ @ ȁ(:?2b/[]o6_/fu!=~<ǷJnrfLD00ؙeK'dt㰱NUs%Q:I1fQRJTmjm:‹xÆ'rCYD FDRqjaLֆ 5B ^iՂtO[868ǟ>_ 9}7^x #d-JG+m& 签xks[oCl? r7KgcuK"j,q.AB1UJ@DBPJ rc4F#ĕKTRBdaPjFȚ5J֔RIp!s`C1FBHR: u3+03KFA =, X}cEV lD}Orۮ}E;<-0]ѻEDii==(M EvHcH(!eRZөxR!4REٕJl\}dӧ''й!Z2FF0PP ZZ+ZRDHgsg}]͗-\|zbt5n*'O>NJysff$b譲uMޟ jg{I|o| y5ˬ` .%z[YuλWu~SIAe3h0fK8RA@B!mEx[sPkeZ2mYeOca* bR+)FxCRM=1 tl|SKjQ򤰅!ಾ>VF߈˗*d}#C^%J1h !Ɣ" FsnrA]mvC(0TF^.bXxq/pCT|Q # 1a,c"ɡ\ZP%_')<$QT) :=Zq %܇p0b1(`I{gzN h(Us̄\<)bu&rK>5?jEx/8Y:s8OV.-Ic`֝ҩg9:\9z6 EQSϸy oyåB'ZC=ϧZJ0v{ʸs¤ qE"J() YD$JY1<` DB FȚDkz 9ghHT0ƭ $$@@46ƨx\5YDrBʒ{4!K6H$9&[tW7d%0JlV3C{i"J96I!`ؑ}S=;X]謽|BC@bJU`k[n4d&=trCn1fsG_x`UZ`y_䝟W?o8S^~w^;s紩1'Q MX7,rOݰwzj{ڱSF'~c`XRQسd/]صs+WfT5F2VVLueRA]©S*guq9o{}%5[=;wݵM~-~z䯧w^kG Nѯ=7l5;vnû/-/tW/B@x9(Oܟ)SQ,*E@J֚\ŭkW~׽pnO<7|S/O?:+:dπuc&~B{{gVoaؒ XO1/k{r^[^:~7}S-ql x7zmuvbg*Զ g|r@<`g^^=Kw=ެW161s*ljtǮ[} xnhƿ;y|w/jdFSK{SB4tXf6%x5ŭhw`gӗ.z W;,PmjxPӓ]M֕)5*@=gCH#gC7M<œz.܁avG>:'c6P5fQRUɪY* 1 Xrb\59 sVh\{)ܦfTg2NE ɲm\Ldiul֘[l% U~u-KD!GEW0k6Jc(2=3&Dm=1sH%asNIYAkmc"BD@i9Ɯ BN9`mBVJycE%Z3_mT)yIFݔwo;ql5d<xk羸k? IDAT/GkzlLxҹ矿8Q+w޷o_=#G+X~K8 @)k־gnK ʹkb X,HIksGKkoaDZv[S 4i_:sx n>zf ^c*ɷpgW;N+.&;t~(`@.olo5 c0DNPFbڜ?7gf^6z߱:|g7oV5dQd& !Ő${֨(0ǘ4Y5Gd 9%DҜch[wx,TŜS{|nˆ ,{ΉCƚv:rYĴh ǘȢVP k fJ9f0Z M]gvm1~0!pNs!>4gP$f$cCʊid,;<VNv FbOH" r3SzQgܮ/ZnDj6 7kӋO=${={3克cP]}@߽v|n8_{5ys^yr_y_(^Xoמ};riV=?z-&,W.iث'uKۧ ZduN涰]J޺3O^{0K~\^߿ժOرѷn'&s;ԋ+3tț5No:rdaS30?3ٻ`{\ڷN5|} oՖ:Egb8L"w,"@N^7 3E6_]{ǿ7}/tN/u۝o;y?]^:{۶=~3Һs]WlVz5fYmәssC_D^|OΞ]Grŋftz+k3w(+f_xznZ:ӗ7$q7S?3||]JɖE1cl28_Ƥ0/-m>7Z>̍{v|hpuJv1}ҺF?[o~k_*w~sOtރӑa$i{{jz*8p]s晗{7<+^|ܽ..fYÈsY|7xtTte)EA_xk:e(籠w2 ǣ޽\_ٟ~݃6q_ݝT~(I4kFb"3PHFs"ﲂ& 2 T SJj}DUHƐjKLZP,YE1&Dg @D΅!%"msޅ&bJIUQ&fzksiRYı*k 2) X4uݠEQBѻBHMZﹻyg-FJO̚'yy׎^ۘ_[2\G;3Yqh>=晇P1Yi';wn#/}+_]ufsmWzB]ы/=[byeicscrj,ZW;t vB/=K}3|zO~䥓fmѽs']pukh|߳s⧟:nwѝWr< 6FтB,o~33Ŏ[t:|`OϿ':{|ktO`ñB+WxYxk8Jy`/ S[j"-isgr!Yxo;u慨\=}o|ًMWW\WzIיm+ո0 se3Y5 saOݍW91 v"QO.ww4̖>m3bk?~aO^ɦ^8qFkr,wӛZ:pcCUZHlJfv9%l-v#dm{N>y6nUW>8'fx~ڹՕ{vىkK[::3[[[ezb=<{ni47'7ҳ_|ߴffO{ܥo8W5d;83wC'hqu\YQ% |9xxyy}I[8< O6>y3P,:Dvu)gì$1S] *IsR $MI17UU!ErkNsniggLVM!©J].M6WM!1c4b,\Q)jSBo (H Xe9&e_RE4iNĆ:McEr܀UuB5lAsQ1U"eQ@Lz'"331QhlQb;ςO?>wیCo>8ƀB`kλ܁]?l׿5ZOCO?7쾫SO]IH!'Mϥ7Bg~?<7]>:Z}un׺h&;s+Ϟ;{ߞf4kp,SG^[d30XĜj%{>/~擧&{g3cN/}y7n8|ۿq%:pc;N"&DglrvC ywo~םCמyzWv;օ}ˣkO’+  N~{ˇ[[yܧ~Nײ Sa/nXp<[n91X2˃n=nP '37-zy;un]ܙ3@vM 7Qu )'Pl2KN2dθx,ܖ 3 9'jD)%}knj]DZRWVUl9&&&&0Ʋ1u]Zesj@Ĉܺ EYH$ܤQJ)'"bs-"b@U&&mQ:hcF$@D"{~9H4$a]hX ''g|Y@%TTC,]q6T7D ssۘZŭYyo OW/wqX_U%wOM~00z aP{֎}359ع5`nX[h4ܺG-Ν5 K9aLڭm(c7A .V'_=p]ZcҌ {Lg!45unw#L$ӛ쑧_='=U#7?L(fo=螽Xon>9񯿶KUf(٠V޹ahL%i޻cTg89jppvg/.Xt9'91!9+84u؎c  9\|bεKҵ};1I+hf{ ;^nvb3ivz^^~q9=)N]c{,BJJ3EizˁݑOf T&4U,;@ f?svmty% f/n*.s/{ゥ3׌+G/{[޼{75riymם==\wdVWW{&3|ѻB7%1|aif9{HlLW^g7ҵv0Tn+>m7s L"/ٽ{G_^z+K}mUV2o?=|4o  2utbjsT DH1Q 1F[j4$w>Ir]b.1q$vXUTU8;AY !1#t km( Ddsm{n/[@}1fV1b{O1F1DS drΝvJzgYlkBM<-;ܙ(U~$awҰgXէC=X#L>}~^0aQ$3~a.e/uƀWV4+X[@T_YLcW Ly+/-oXst6]˯`Q3RQ8y?õˣ VWgv̝p޶ŕZ|@*zj<՟}]\;o}=v|;{c{vZFRJ`R68go?;o&`5%o:_nVY1Ɣݎ!RGuJ V;m+߶yk{xp솩 f;f:4 D``TA c+㿽扸EK5n2 C{qd;잁S/.ؽa|~KsbDpLk{p⅏>~W_<ɪvΪkYێf `!&ddcF1t%!uݜ"HJlm:g% IJ ducIƛE,#ofێ:/\q*Y֕JEȽf8!d,sԧٹ>1mJG-t`:;v:WugZVacy-Yxuytt[0؍Rj4tȞM48Szc8Ovf]=0q֘briy^f*Mճ֊>:޸tGeZc ʲolm䒦 ļT?m~h*0+/m}L]')3`SՆ!'뭋f6ѻmTle&6;"i$I+m+Az(jLJCұcGlU4<\n,%mޱlʵPD¹jӟ6 **J r֐$ДEQW"4!hC0HN93s{ e~bg"P"X$s';!cuƚ"1ijkmrViůC`"&[osJ*4M B͒s"51NP( -KH:P \q֜c@l861Dh s$D cN9Z9_g.RD@ '@@dhQQF"/l5"ڲ8$*cÜrvH⭅Ιs%J*#yfms71%`FՐifb'ɚ,MʩirT@k:dS ^8FD3^TTD$@:4ȜrnPB X8WcQ3}4I HĪuE&4W*̄@,()u]&+4F&SH޸fb 6޴[ "L) "mדd`$sj}kfqjHi\T8lبc2r8"q U8Rll֬S{U-5\b,G e4UlR=g/Y$7U41fk L +Րj/EuZ%! u JB̩Qu)F@0l4f1E!"ms1%VYu1 \i-6έaZ6Lĭ±{=$fZ-$*>:6I2 5 !l*cIJ BC @)fE*cS)%̭3{҄9cXE 9ea6"hwQ!*V0PQE@P6oR\qḦ`"CMSƚx4EDҶNl)Ȗj\RD"Ǒaf&ェJLʞJHxFUY ?!1ۋ"7Md焈 gĜsGwM\BM8p#SRX"yǘo@%DfQ3Y< <0 GsE t#1<*_T5"z *<$FzcǙ˦_{qٯD&"`$fF}*TucDP:3#&RUsHk SP (UEzdnB|R^|flP}{qwAĶ g[MUD{"-f6cO+39)g!B3vS90O"c0:;lqc 3kzGDW"PXUY]ì]DȊ5mBD, PB$kyDT Vl^ṋ?;Sꥆ-D^_8`dDMݪ#oa"+ }-D$afu={9g9܈bs"PfLXJ`fBHf=A2桽 lIVֽe[P8<p5Ej5jfٌfC䘓-8D2A&HHPP !L"* 㳘GI"#˜%~_U"2 wzHu= w9U* YLȢ,n'z#3 "D?7݄ME6c.(..Ϩ*^%ʿEĿΈψx^\ŀL$ UN bzL5t@1Fw3џ x6 d֡U ‰ `u]} QuAEV ?>?b᪊ʈ+©ؗV;)"<= `"0ۈ^-3)[0UHP}ض>w'pc{ײF`=F͢*bkjfD3?wlyBH(㩢"aum/[rn9 Z߷A101u>:"TUtücT:sZD$mqnECAj%a"Ue|>u]ue 2<< HʼG-#3 c09ƘJ^S{fܨkB` "bKffTաDP[ Ⱥ2#2dʈ H'`, eqS33$D#dDC&1W7/Q7D;OQ||o{H |x$|P"*wvD^kQ,:sE 92`.gkB,8tڽ D<+kN5[9Tv0$ &cǙP2ۙ±ʧ"zA]f5*dT <{ڀPX\jWnRs31Ԣ*d"[c,ǘy!49qGp'23kgO}V*3k7c 鏙dn̂FtK@(*D8$歬F#^{EH1y a{ovϡLHY\|dZ+ӕzQz1Kd.3dFSTѢ܏1c,J2UX*DH^U ~x~@|>XX,@̪X ?z#aFu´"8ΓTUX3JT{]tgA{Ns;]UZ@ݪ;*HXTr `*L@B vl"%D#DsIe,cň~ ocFDe!( A QGNPp_3ɽhMgTEDDcfexTU^9cs6(z efYS-5֪rVF4{s/uW鵬DH ^[1/QQb&6WYQu`cՕ2YqLoR^I=G%9p5LD 9&jL:` U5@&@ 47fH2$e6.؞ӽ8wb;-׿|>{Du8!ę -cZGw u'_ CsF} bΌ29!ce{AhUA ;0Z-݄:Mh/ @R/GAof*D`C y<;mC Ic贵Cw؅)w:`4 *J.7F,l=̎^8i)TBd2 YD83}# 1QUu)l3gV"+Lo{!! 3QaY8JEE%+*Iw?1%Ҿӡ8!ޖֆ<>RS` :oXY 最׾ #̗"[gcZk;)UydU9Cϟ?{/"Is+<J1u]\Un~wDiɖ0EBm!2CXwt6̇(15o,!E!1Akh\PxG<YTs~n+9hTBaPum9^IH\("#fa{ =(,L0 `S^kED!!a\`x!yw^E({;$sz}=OzY7q>·/#*6t!"3t l:#ID9u/aS7lCK yKU~O m*bĄH7/DzC0ݼj%C %bYK0 2DTt (qT Hd˂@ޛD$U77 )!DF8[.ފdVDEo/Lx{9x4 >E!>zmsٛ[AHu]]ǘw j!qDr_c̆TӼi*~(&(l&$LwUʐ -Z0u@LTN>q|^dvk{14 SYdQPNjl!۾ *#UI*<[Yug;o XǘHB!J>ZpT'=P9'3YϚv&ţQ7 Nn6(o?~+Pݻ1dbdjy("ǜݼU%*o^P]Go| Ī ?D|]׋ȳ6cDQPIa!UQF,H:`BD.w,uwx|}]{匿^ 쮵8mÂס:{ QNw@'sfxsG~3fE`Dd7HGcDBAH̬•P(7g$y#ƚPr2F YQ P@@@̚U<`&įeʧ Y)]#*ZnVm Gd%fҦ8̙9#ƐvzhTI8!{2'#@ztf3r0Wo3,2pKEZ2gK˘1'7H UlȌ_yb+M\K<χzuD<>QL(fWiW𲫥9z>c`I<0 1" "=gf5 UیUŭZy]W;md Q}"Qvb&8uLx@T&0IE6:5 -%)^4#;=0æqPk]f>%0f|LVb)D|tDI߀D^}>>ykC:w$GߢłĔ"y~~<'iek(d9 FD~$Ց1;-uLADTIeJnlS5hR$÷"Ƃhc A@"ef$@fӲB$"F՗[ ; '" %53bdw#DsRe{n4zFa; >ilDpde0ʨDVMl7[4_H^Vbd4 *kyG9s Kوp;}#UBU"@Oф 㨌`BSxX|}߯KϪ8x<@^oU#!@ȓbi_1Sk-!s?utYA;,$ފĈ~wDFn1gyEʘcD6 q9 |>Y3R cX"*Rd`<0ۧXzѝg kB!9 2}^HYA[O`mΑN QAm w!jC7 A@x>i%ďح7OxVhaj$DsNowB|tBvmkQ2~_{pwH, H8E1x]˪c $J¿,Zޙr:NVL3a21 L3sF}L<$ϸBE‘NU(,-uw2<_v[󙻧;$?@3;To9k bG 'k {GCOsl)iQ!QW !nyJyYFHc<9""#(w|W^ $vp<E0b *~g^^{̱5S>FrmV!Ȳn{}>N@Jx"B_Jmp-{t~x^}}|~c4p8O=Kq09"ޯWCh~烙ֺ_2kG*"bf@xVd=$\4QR: @"zDLD"U,rDHP2~w(Ҙ|f;`u}"z}*02 &"'񇎨0(*/@8|>}翔e_wsϏ?w"Jd"U@p(V1_;@X=LIIݡFE$<-#vFF`/T1&*dZ{-D\nrfF-*!^ʄ2IIP+Jx٦9@7+zj9~꾮yV0bUխ6C#BJ[ 5D^sՅ2"?i0?WIENDB`eureka-1.11-source/misc/Checks.txt0000644000175100017510000000233712647061302016370 0ustar aaptedaapted LineDefs + linedefs without a right side + zero length linedefs + linedefs which directly overlap (share a pair of vertices) + linedefs which partially overlap / cross over [ties in with unclosed logic] - unknown specials - one-sided lines without IMPASS flag [FIX] - two-sided lines without 2S flag [FIX] Vertices + vertices at same location - unused vertices [REMOVE] Sectors + unclosed sectors + sectors with ceil_h < floor_h - sidedefs used on multiple lines (or same line twice) [UNPACK] - unknown specials - unused sectors [REMOVE] - unused sidedefs [REMOVE] Things + things stuck in walls or each other - things in the void - unknown things + no player 1 start - no player 2/3/4 start (merely show it) - no deathmatch starts (merely show it) Texturing - missing textures on solid walls [FIX] - mid-masked textures on solid walls [FIX] - valid flat names in sectors [FIX] - valid texture names in sidedefs [FIX] Tags - linedef with tag but no matching sector - sector with tag but no matching linedef - linedef which requires but lacks a tag - teleporter line with missing/multiple target thing. ? negative tag values ? list of used tag numbers eureka-1.11-source/misc/up_grammar.txt0000644000175100017510000000254012647061302017316 0ustar aaptedaapted--------------- -- GRAMMER -- --------------- file : { global_def }. global_def : constant | variable | field | [qualifier] function. constant : NAME ":=" LITERAL [";"]. variable : NAME ":" type [";"]. field : "." NAME ":" type [";"]. type : "float" | "string" | "vector" | "entity" | func_type. func_type : "function" "(" [parameters] ")" [ ":" type ]. qualifier : "builtin" | "forward". function : NAME "(" [parameters] ")" [ ":" type ] block [";"]. parameters : param { "," param }. param : NAME ":" type. block : "{" { local | statement } "}". local : NAME ":" type [ "=" expression ] [";"]. statement : block | return | if | while | repeat | assignment | func_call. return : "return" [expression] [";"]. if : "if" "(" expression ")" statement [ "else" statement ]. while : "while" "(" expression ")" statement. repeat : "repeat" statement "until" "(" expression ")" [";"]. expression : term | assignment | binary_op | ternary_op. term : LITERAL | NAME | "(" expression ")" | unary_op | func_call | field_access. unary_op : UNOP term. binary_op : expression BINOP expression. ternary_op : expression "?" expression ":" expression. assignment : lvalue "=" expression. lvalue : NAME | field_access. field_access : term "." NAME. func_call : term "(" [actual_params] ")". actual_params : expression { "," expression }. eureka-1.11-source/misc/eureka.ico0000644000175100017510000014407612647061302016406 0ustar aaptedaapted(('m\"*D: 8$(Nz+5~`x3a ^L61:.g#1SMTC'$HW  OHTNHLA$ =l8LXDJ43#S0.IHVEGCCLG5F='p g-VOENGIHNFMWE9@]t o g4MTM9@CECGBGQQJTQ&&r$ ^V.G;2:96>7;98==?AJK;$8U W]0XS;BC9< p9E<0}*u-w(k#i*r-w+w43`w of,GIBF448$$}i ,. aBMMNMK6Q#mH:FQ?<=9>FA=JFRFO&,,Yet V%XXFEKDB,uKAGC8=@GC49>FGGHQ1HA %&R (] V,YDIETAH#n;AG@7812?:9>M@GL;KC3?64 !->1"_/OAEDH8@,uPE>3DA;90A@ACBH?BAK?OM70;w#1^ ` I/PCI,l(E>!*hS6VR>>:==)rDMA>FFI;CLBFCB<3;IO;1J8"tAU%YM&%DK ` `5aOKKEK4dK;AE@DFCMI=I'47EHJM&q1tE4>:KJQK<7.!b&%bM7QFMKWTH*m99HE=CFGKLOFC=B@==>14-y:*i<44@?7.7-D<88>9>:>C?F@U!{LH=@=CBLH99D<*pHGB:BG=>=D=JO=MIBEJ>BJEIBKJQ34!3?SH.\?GM7K6?Q.+CE9I95E,w+oJD4L?;@C@MJ;G?H%u.#\`d2nj IM*zROCF9[ENHAMNK8D>DENGPH?;P;GKJYC09$'D`NT G!hUPAZ"kD9?G8;5;7CDAM)~1q88J7B@I=;7DI>;;/MEA?;8K>B8@D@D>8GCx6ZSM ! W~#QY#n?<>N:-D;@18J8/@8>V7"_U2A6@=A;DJC8A@UJCF>TGZC99E>Ft;Q-2#!+,5ZNWBH;LY77G<94H6D=:U1/hT5Q>CCGD@@FDJD:C=;D>?B4?PE6J7HPEJ=x4YFCFQEDP]?5}>|+`S_Zf/[R(XMzN2vHLTTRLL]ZA2%^IPKTGNbP?9DBGLRB+._J'H$  8 6&lOXN%pEG<8@?1=5@EHFCF3<\8;THGKBXV>AF7?=EEUJ,?CUWPGNMG?7I;MG;G[ u*O H9cRKPK9X2X);14GMA+@IBBHQ99vZ?:@RXQYd&wPS[^KDRJ8E8DJXR1MG77JZL2XE\\=A>?IM;Mg64#l#"#"  > 5cHKHC3z2x`35>@7FA;?FNB=:F5{;sPGD>T^?=PGDM:L:C>N9?8AKGOFFB;H7:WSUL<>BFBAM=@V'\WR^A/(]!  L)bMONP7!v=%_'jGS25>2BNC6$xQ(bL0`L=SK$g*A ([ZNEAGNsM:{SMC:DVBQK7-g,h)i2s5uBHLTO@KOIBF;=AQF=>JQNB47>AFbJZWAAJVP??F:8@FH4UPL3h?}/d ,$- %+Y0,D6>??,?+`0uPLmLS#YArR:MO2~@JW.h^H7AUHIH>ESQL4@^D0>9TkY?DG]YZF;@@E=EN>HDF>QDKDDKb_OHlVCGH>VJPAQ[_>O9L9V$TOIVHe ^6*,(VA"9E=hrc]J==Dd"q=m!S5nT59-Z\Ds:zTRTfl]LE|=y-|BUQ8JLN>G7GEBBPGMRt]56'!n /&b]cNfLbM]IEJS X.t@X7t-u%k"a@z0h0mE;uF?|8s7q;) '&U:-03U0]4lFD{:p9uA|D~LAzIAx:s%_3hCt9jR5s)Ig3g2o1j,b;~4hBg+e+bV;k >K 2 5)%LBFuk²ln^#B8QAU:iL]KYLBO.Er:2*>83m!OJ7y0}?CD;qGZ+ 7)t:743s0mR;LB/t'n>5}=D9KBR]BH;7&(wzo?A9 B>IFUI"fVkNoNXOC`oT=B+v0jF6MD@C@fl, ",/ T RH;g:`J5RP WN/4~S;?[6~.|9?EB>2EWO-`W5zL bHJF\?vf!d VN[% =vo0kd-x9zo5gW'P=E:E9 H3 L8SH TX(Qt,h ^R?<dT>BskT'&!N6jJHP8:vC90yE1{G+k={-j<3z6}(dY1wbt%M@>Eno˹bUMI\S+OEja4~ICa\*91I;G7XB\EeO`Z2N;?;GJVo}@%+++ 6uKQ!-MJ-mG3=K/nX4xJ;=6<9:OFC7>KG7C60~GZD_?,^=n!I}`=l g2 %"VO/TH$JC PH%TP,OP*VS4D7!`G2XH OMJE#rj4GAI84~Hi%kE?DO@-s3|?0w9OE-zC;u Hc&N   +*da9b[+e^5]X7^U$;3}FTG'PF0OD[W#jf1MD$7&;14%H> RNO@ !c K F13.8-+.OHM:FP,{Q3};wWPBMFR6'yJ8}O;7{;zMCg= W} L &(SR,ZU)YU.PN4JDĺ٠q}[ʁuKD#@:%DEWO0NG%A:ZR,_X,lb0[PUJB8A6Q @Q//4; y!N[NP=>NSU5=\P8FRZIAAHSF[MB?JUy%D QM,[T,QM)OH-DARO"of2TVwt4XP%N@-PF-EDA>!<92-/&80LH'LDhc1z?wm!bADT'*/9~s4g#GJ*O(D"EH:IA%I<KBIAS)M9> IL(T=I(K4U4++) --%[U6KDC?SF#KG&7:6; HD(QN(TO+LF#OI%ZU/GA#OK+pk?XPZY!GC"E="81F;^J"0FU"*/<"8&R27:U!99MMA>).)I (FOGIH 9=95C$Q!['L &%UQ1\U-XS1UR-MI'E?D@#KG*LD+G@#GB!KH!nmBxs=ڍmh3QH/ŐF?8HFIHG8!n\\`%$                 RN.^W/UO-^Z5WR1SN-MG*=8@;!JE,OL/GE"78cXV7-! ܑP5+ ??MLUE) $p`2  e^;]Y,XV2WU)QO&QL*GB$B;LL(VV0MK*:80,0* Rݠ֗x\vl:IA5073RI! dY *  $!TN,NJ!SR/QL(PL)@;E@TO0PI31,1-LJ+QQ.MK*F?'94'" ) -!=8mf4U_MBH# >!8  ,'#bZ?SM(MJ*C;#D=$<5HC#[W2PM/C@%?<#3/3.A;$?7]X.lj>GB?7'%BwUMMG%^cݢVT& $%ed9a[-VQ1@:@;C>!D?"C<C?XU.XT2UN2G=&;5'%*$#:9!DG"QN_ӗBFL  !"b_:aZ0@9KE%SN.VQ1OJ)LG&E@'HC+?:?=DD"WU2RP-HF%EA(<5!1)GF/E;zE;ŸgR` 3 [X2OGIC)OL'RN*XU1UQ-PL(OP)DE$::@<(.)-%E='FDTS%VT.@;IK,0 00;8=3u $l   %#'!#TN\马]IJ&KG$OK(RM+OK(SO+FA#C=!GB#ZT5LG&MH'NI+E>$D>#@:!95UP.b^2_])XR"A5IY[abtt{?L NG#K'a&3v,uBWUj/;IKX|RW V X!M"GBI$NK#S&Y'['$W&\(=.4%cX$hC>A<C> JE(ID'<6:3-& :5PK+NI)TP0KF'72D@"E@#<:A;XMuh)s}zy|qv ' %}` ^ t~jz|%$! q d[ O U buz'u)o'<<>=3+1cڂvnCG~1A9WU+ur9up8vp4}Ay;~?{=y=|Bx>ok5ZW#GD>7kb2wIE@}>w9D~@~?zq5vo5f^!kZ _'aMS]WU*RP-II*@<JBwEWLpi=ICJG%0035/1B="YQ)PыیގǀZli0yv{8zt:\X)72)(@<`]4nk7c_)vm=vm=wo9wq|qDgb5aY2LB#?6C:#\X$hc0me2ne/^S$1,+4/$#wcahetr?Pw;;z0' RE,tk:Ŷxׇؑی{M>38-LH.[`6vu7}z?J{F}u@JMXYDa\55/1*95TV.ff5qn=tp=ro:}v?pl5ie.vp:zuEnj>\W.F?F@D;ODeV ) .2-;ZZ1=0D9 !+)iY:`ƻpf{G/0 OQ+xˀ׆ӀؐX^[,TO*ea1a`/TP'?720IF(id:|t@NMLRSQTPLwr?UP,,'3-MG)e^7mf:ib4xk@md7oh:lg9fb3e`6YT)JCc]+]Q tot$ #BC B=#XU8gb=C?IF"@> 2+##FC'Vumotb]T'JG#NN+d]=e^7ph;pg8{mAgg:DB!4,3-NO,}jFGI\]OM[UWXz@OA&0(,0AK&d_8njAe_5a]-^\*TI3HAc]#od'wd%s>D  )QDQ✥W8,58;9D;)?2PC#T|rm|ZLIZW%adTof0mc8ne?mg?2+I?#}rFMDS匪`lg/z|1ۃ}ԿobRLPU\rj%~}=biϽ\keyo=TI%YP+b_3MN)@;&F<)2+YTúsTE^S6[Z0^R5g[1|@ZcawELD89D;UL)kd=snAtqAol:ztAzn9pc0tEvn?jf7i_4dY0MK$DCZN-vn9rƳrU8UtψVmb3TP*^^3[P6sl1c%-*JG'OG${z3o@dߏꇯWvfBjiAYV0DBA?TQ1hjyo0~p0|'& '.H;^i\uk9/"&"rk@id>`[,caW.`b7bZ9sh6gbQT.*+ _V+gzf3<{d7oRZS8eb9liDkfEc[@OH/D:,81 QJ2b[->;#@9#GA&VP0gd:vr4 Q[#0D8L\k`7VP'<;72LAybsh+VdaN*VM/XX(fe2yK}pAzJpĴjxl5UR&YSS;5O  ,+)+-)-,& !]QiTId,@ 5 7   `'%& BBC;%DC&UZ+RP)MH(@4nb8ºtJ21 !)'>:%^Y5gc6jj5sr"E@(<6#63FF ôogR&=8,/5==yi?\[[zs#SV#UdX([M)tEgUMB)PL5RY/_Y(_b`,NP-ZR.d^-Zod+hk-z7&0+) /'>iiDE?<6 /(">=gpi;E8)%CWB5:0 =7 \S*fVR$TO1XR.a[0`v7d[%F. 7/!HpnFrl6h`8H@.826/nj5SffcA493JE%UL O;3H@(MI#X[%uh8WOG? 2#  2jj>mj4\R.H@\T3]T8GA'62YI%si3[\.(#JD*mj7ut<`_.5,:3(3655LJ%WQ"ti/LUSS!+_}?fW1l[)ZY:WY:te0TK^W36-SN$NxoG.(SO%O`xDaR'B7 75 F@M~]J "pr9Kc\mm?SX.DNNO'E>#i_2Yke3KA#}wJe]6\Q&EcTDD,/SO%H_ O .201-<)$#KG%4)!?FCpf>IK'|IX09ZW8{d@[ca,YW2^[sp7^Z,vPO-&56NLL&++p..d                      651)-BXTTEvk3{Mkn=DA:+!f`3uo9BLVLG=?05:>@<26:<566697-;:8;52:=BFH<;CD8@/7w22=?MJ,81=97LH*(V>>;14:<5*E?7A=IA+==!@8#C=JC$}~?ztC0*B?#YR(c4+4,.(PI-`Z9QJ&\V.tf5hmZ,ZN'5 RKIpl2MDUH$WC!SOHPGBG[S('UJEAFFFID8C;$;5::92MK#j_Eil2sn=?6'D?!^V)^D=B=(<7 /*C@.1. \A0u?8SI>B9E98ph:)" ke1KA:DDE<$MKr8227#?:_X*XGA!6162  &(46(1-zjSpf4b\li1tsh`[VUDLQNWV^^OTKNNOGKoe][SDFpPPVZVVQORSMRF>UOy?><@@VZMH'E>RI(VO li/Vxq7_\|Bma0vi5j`2kh=id5uk4kh6& ]W%}xA;3;;?6&DHKpodBJ]a/0]SRIDMIWSDgW9pa8dZ+kZ961.,rm=xsF6472[S+[<7;7&8<$% % (%un6L+(( $%&#4+ jc'OHzm6~s>w@}xAVRSK"xl?~z8[UD>JEZW-RQ TW TP'F?A:NIURVR#SM'RH*UM,JHJ?b[/Nb]3?:[V,^\2__8YY*{q8{FVS'wr>Q=.) ##% ?7 _Wb]Ylf%)L``RUYWhe[]X9z@ZN<;6/;>)+xt/XD?vn9QVK}|:<8VP-unDUO{=pk5YR+OF)VU,VS1 ^U0Ssm[cpo%-/kl`]c^uhOQly;32*97phDypGAC&11XK |oI !;9%98")%=<'!EBC85.,"$3+:-`Z&C<0%"xyG_Y'A3<1jd?urBNINF!SP KZU+OE*A;96LK*SN ~DWzA{w6SN_Y0WP,QK4d_:^[0`Z1[S.VP#{J~yM>3/&D>#\Y/PzJcU(TQ3lo/GthUhd}96]pqfntbwpiVQ)G9'" " ?=]]3b^6?7A<XS/ynH_V4,) ;:#@@#57**-!^W8\[6/%B@;54.SW#if>GBGA f`>d_7YX(UN(>5F>!e_7ke:ZP*A9>5=5IC+II(`W-Pjb1jg<\T3ME&<591&"HFba8a_0b_6^T5\Q4^T4]S.d\2ytCrrFEE%(%+&DD#kk:|lDa^i\qpabq{58MvyydlijGA#BVR$>4!@8)GF&~xL_W,94<7KC(E>!FI(>="96%  UQ&~PNE8627+oj7ll7E@'%)`T-Rkm3AD0-KD+LF$gc8uqGQJ)D8ZP.on>ss@^]7JE*RJ,cZ4pg=B==@!50NJ2@>%480 2*>6JD YO/]Z$a\+dY9_T6bY2`V+~rDQ[V)?9/(7.pp8t.e_@quB@hr}u|taN@"g^5QR%?:"cb6sn~IN~A@@jf8sl>=863(GD)ED'3/KE(NE)NF,F>#QL-WW.kl<}zCoi;]U.]U0ca5SP&SN%h`4yGzr;ia)QF2=AZM)vpcy::I{up]U*>8:2TR}yK_W3JD(A<"JB'F?ig8Nom;c^3fZ4k^;bW3^Q.NB QI.OM.=?^RH_X3R[V8HI"C8 SF$}yBCBK@.RM"~K\T3RJ+xLwq=lf2ld.KNC@"a\2lc9,'  *)LI-LL*KJ$E<pkCMHB;;0`\)RTN,3.GC'KH(`[7[T/_Y.ld5zC~wHT\^M#oc^==N}lH;SL!km9vqCC:80:5EEYT(ztFph>LC D7=5II%DC!OK-EA$NI.D;E>$?;!IBLI{pDrJZU%FG"DG!E?"XN)MB>@8!KF~MYP0=6SL%wo>TWql=KGEC$c^3h`7.)'&! .*?=%?/jb8Ryu7mb5vt@zwKC>!+&-)/*6/JE%PK&UO'XQ#kb5H~oJ|mPO\qmf9rk9KI41>;WR.pjC[W/B?B=%CA(@@#HI*KI2FA(OI,ME'ZP0E=F< @8B@"<=E?!GB#LI)LF)GB$<@OM%YP$UJD!LL(OL"}RVK%?:<:?<le4xq@MF%HB/.0 ^`)KD" "85#1...4530ng>O^X-C?*%5/:7;9622,&"30b^DtljiOID?73JHRP'nh?ph>YP)VM(`Y2SP%CBC@><SR!pn;ws>UQ^Z,E?F>!?;ON,ME*HB%>8B<"@:TM5UN$je,zM%#-)F@ W`V*OM#DB"E@g_1vn?G? <5#=9pn7md<)!  ,)9:79(."! & R461.2,<5@<_^-rpI|kvtk34- ySI&J@NJ&uy?il7NLd\6kb@MD$rk?IEZV):8ZMJ&(#"SL5Z;: # ;8HA/F@)C@$@>?@`[{xAVU'D?7*:0ja;c\9*& '&==%NM)sn;wpA@;60A9ne8qg:HCLJ(DE 76;8  "*$J@yJ20 +(83QK/rƿXUGHIZձиֈ}A:|r/u6VL(I?RG}tC}u@nc7]R"rc*Qg`3NI{s6Kup8a['yvAke1'90VL#TM XQ}yCeW:NE,  TH*~yKQO!/+   f^8ke5?>BD#C=wn>d],3.7:A<:7NM)NN&=@&#?<IDuo>rhVvo[qo` "ӪgcZ}z^~f}y\w~[[nqpdrmPzy[v|[}YalkCSU>e`I~flU`}vU|wWulPmfL|rMysTts\q_SO:JL9[XBifKgfFjgR_ZIhZVT Adobed       z !1AQa"q2BR#b3r$CSc4%s5DUE&Tdt !1AQaq"2Rr#3B$4bSs%5C ?-`ew6ڑH'Bި0mRPm"Og*/5 : !;[v:SAkͤߥw܋Zn<-@1b;津:!WnIAv4c@ B[UEg8{ cA )CnzxSJ9-}B`XXu:Fn^(P'hsP#@kmOhv)=z[44#'^ WN ހRktV SH@cͧg;P>(QC@5j)~ژq:wLV@$(ÿz #ZGΠcueE2Eait[ޘcwZǸlb d j*re#z>UB{xP9Q~ f X@PLk[tH R (.Qjb##BA)dҁڧ4 x C &ڎ0 ZUMN|i 6;ztP\\N58@ (ƅ.~TG*]uCT]($|siƙ"nu!N:E< 3}iE&G@O T>TY?eL:~bdU ' Hb@Ve}L4Jb7h'4Qv`2/'   ש$߹a@u#@ :iT*A?]&ʂW2 ( ^"ܑPU*&"|E kB Ⱥ!OR6\%>t >`SF4 C.-5lրn@J|tKձڡ0Q@ y.ub2ֲրGAo:K9˜P3H$2B.jE" (n>PBX[Hw87@ХEU K)Iʘ qڐL?JP&Go,cG7%vwX 56֙,ktО/@\QSBzzoK_@ Qӱ<*(nJk>?h'I=-LBoڀ8 Pl w }2AhWF@1PHkihTH?q +]jCnBu'@dEVsS,ΐ-RR t)+s*S! tC!0ݨV*_of5.G0;jIMPS^E$N0zj 8_Zb#D5R(-Ԁ#QҘ|{iw@22Jܿd@ KƐLgd,ӧZqqA"s "7|"[_?ۨ-LEU!0T 1˜ BSDu[o~+ %t4 J.p)&(i o0Aʴ,hI=ƀ&cM:|) ^ LIvGcJChTP05G4!H4r5M!nkJPx/ޢ"jXPW9@W|zdDP~T&XQequ4Km*EPƄr'R{C\A7>-hń7UQdR15M¯KyD]4P-!9S@ܪ@\^:dU'@ U7֘ xR:P{ LAڭ) Da[d*/1P-J"ΔbG&ʘ[! {9t⢘Bw:ZpJb>]δ +@4P0NS$W詭E:@ ɡ@úi(@ GA C,U-zU6Vꨞ^pC:{!M0 HsIo42C" ?A@tw!biژ6jt_xxh;ާzCܟi;4*=h)6~h#֙# *R'Jb5{Hc&pPn%, ]+vcH|ҡl 6](,NF|Q׷2Elp.P4 |P]kl, )pB.~4{.HSDhG_-@=z!@ p!S@ˌ֠4yu\@ Nu ;k5_9wLo"Y`p.EPv15[#7R-7,l"@!ށ6sy@%^Iۀ'qS<-P.h8tށ0Mre$HcŎuQހJIjh 4:PuT5Z@4&LLF@!phpAap &@yݾdR#EĒ.P-(=đW5B˜]S@_?:`r/r mʔt_1ґAZɢiH)]G[SRRb9Evq:]z} +-h;NB9A}~oSƀ+ LT>4V\3QG>kcRif9Q{:GyJ[!P<8(„RGW|ttwj O>9T|EĿ(z02Jb` RHQzdaW6i@!) *^uƷ{u2S:^@C(@|ocx$S;4dtn{e ͅ] jiNq.$O_Q8|Lg_UѷCkVrEY)T:<5 i(2BHh!@m#wߢF@sNdLpE7MErc~6iD"ҕG0]"}-Pd1?gj{GiDɐޘRS.KiХSҀI >@T|jdi PzQ6ĉ]h}6(X6"}@24 7qVƮ:|htMh^ISo dtj~D~T J;@֑hvpE .mV`hO"\kx1k x~4ROhh3 L#OCץAZ :$tb:'@Pۥ1sƺW?A| =h(Kiҁ1Nք4 CAUƁfjg^`[xx!,z-4(@5&Oz`5~K@1"PԹhԒ!k@]o`;Bob+l㴩0hMöGH n ƀt!4!)`5?95(($߲P@ޢ};Ԡ1I)`.8=i5@j;S zC]tVV(Z?E!H#STLU9iKmRMX."8ZG@( crAuhmP _&4sv":JQ,dҁ23jd]GZl 9*Bgw1"4e`f-6=5ց1֪Oځ pCmiinۼ2ځq55zd2ڀ)75i,nBQi),SM 2-CHo>/Ph 8IviyywAۉԀ^U;R$dqs{~ mfש"%lY$<ݷBܓ9ozlMy$,O1zd@|#Ϡeq;ʝ @S#_@#TiP1HU{@JҡJL|nR!5*,5M:S&$\`m b$F m{9ALB"R#HREUP# {PP A@Fh'€Dn|isڀc,c@hzQ<1ni ^7v.N@ 3P~ :LBihΫ{ wL\ҠtLA7XTs (<*d/@l{w`lPץ2NjXOJum4cjalVΝ@ln@-E!p{H;(v]44 h|)v0j\2@7'}O!qހ Aڂ)0(D1$(:1/Ǣ~LIFtc: H9cuKSDs $ yRĭ֑I; @T@ȏ*7TK:$t&TFAHg8z-PRĻj y< S$,-@OH ;dT洗)+ҁI\EB^*d8;i(`z;VCP;Z@ǷV(hL^uژ- Ȁ!Sߵ1 =|(F^׫@rtՙH]l /^FZdȔ8;UKԖp~\43~mz!c}S#e_x.j&y;U˶4*Z:*&ƗuePn%^U"1^NE"o$FFH1Prޚ{Siaҁ 6h}X)PV(٨Eiƀ`qt˜<HdjT~Gs˭TA]Zd0)@ A(M5ւ"wZd,=VR .OaH H+6to4*P8sz C\:t Il@ 'EJ?O!5D? R*8:hf栠rPK#QPQ"4@(?k@U[4"G8u`IS|h.q^85];izkNI׵2Nk48;(SkP h.5AU Z1)LHqP4.@K@±H?iקHr[K#8-?dz|i sTRH4<}H)1WP>Thj0 2YȂ'@=: 81^#I: D74@$4Ie7R%DuS^ԊA :!G^'ui.=:TOz{_rzƥ#Wr&ECH'T\ %ͻ%{O]0a:۵odzMBށi [jP((i PHQ qLJw(%ݧ{߷jd ǂ/΁~: (c(CSЭcI|(6BAVSlc@ I~#,QSjCBkҁ@*> _:٥"*~b:"+P:hj@륅"%GzEȈ%4 sB"At j[Hb\P\>T mԊ8R P@ʼnHƁ}’4`⫯Z '&^l7 @odgME@0L1qґD喝ԊD9\1N7! ǥ1TGmƐX< j-ҐW^m!^^5A6:#~L"Sӭ_ kC`ew&bP4пpCztP'Rҁ!Q0" )Zۧ @֠P540\?} DuR4RΙ#qy7BC%h^1 5!P?]TJ`uҤAͬ=E!ԁLAcj}!WI#\Ҁ?hJFɧj s#pOڀ8i~-jLLjҀ!^ 8[KPbsr/N.Dp:4 dreU&$Xq:G&m%T;Quҕ "Guj0Z<4%!eT<(K/Ɓν|i S@)`<. ܭ H|TkHf;O 竃ZUlTkIց]+T cZM%N0 }Z-_(5] k'Tj4cn,m8~Cuhހ|N@4*H+5NN#$;\*vZ8Ȅ!SGnoӡh DȏeZdc\:\I "6Zhq(4p@ zBƚ*;.LGD~CGc:P[z+HBjy4C # _@LBiۥ@6΀](ASs CAQrJnT[F{:\ i(.mqFP1 \4tCT$t"[juLG.Vߦ0AZn uDܚFDK.|<;'zC` +xS dR,u_¨AzmZC`.J  B5I rA 7id*'3gXm:P#QnåL t@h\w'~4c@:b`ܦh$k@WZt]|M"-R(*@? d1OzkUֺ +N֭d&9?EOLBH;B9E2IPy)2) )t `q%;@-B #[ zba87*(V bi=xĕp )ޓ tQx hT+ ;hPes 8|iƁ=-P)uVtDrJ"'NHmu$15EfE2Z#lkEP:q)цAWEI⥔ S >4(ۭe41k@6JkTuRa"Nhjhz-2kNQ:ymZ4[dm;P=TPR 7:R)U)T2E/ra!~P41l!{kB*oI"( Hlb`Ͳhzj k4OS%*c6@}cOTPWZ;D1ۏҿ*(W];ژH^-@ ?{P!OS@f:\jxD[J AiƑBWj/u_EZ|ө4b4R~BA7(cԑZd-'[SD6%S TTZSdoEKw1%4v[Қ$qTCJPf4Ka;o@GX*_$3e!5ۭ!O)=MƐ  SZsg(c@#д}(ؿR?ƁYQ"P:wS$.~t85Q)%s&hq 6I !)JXLL-%nJd'\4H A@# .u:ܝuDZ "J^htM\4T=j@ܶӽIH|Ϸ] ސeMI#Ih _av})k_J 編&LLc@=HNNzP1Tu]~HD-#5(,&)[ґAgj@_,l{.؟LC$hMbʢ!wJi hu4T Oʥ"berj.D;Љl ARzZ#ӡXT0~TE/s%ҁ1"Xʻꖠ<{7%2#ܤTfD?-R6HM5!*GqP0N\@'J 9OPwH<8 x@°wğPHl hK&0-UFI*B@'x&dLcÐ Yt bco!\_ !4Rx|)%4ZC&ztCN:. a)C n|htBOb)_@~MIm9)h!SB!M1: HҐ'E#(I!;?}2-vؓץv놂{48GUM5@!.%E #7Z_  /h'vW^os׷Jb"_ₐTBQO~ {I( ҁH} CQt!m@䎚}h$U$;PPu*~4 P!SPP9ck#Xߵ2{X/eTXET < n_7k4{/CTS rwR*,I(GsԑLԟ W9@=_la-7 ;qB"N9#'@6K[!sI:cbnImj PJ+܂4c;J@!8Pu=E1 KwT!rZ !t@D# !"u$zt .^AY!K'O(vn{Pkh_@T uD 7*U)ζ9I`P!tw:y9#x=DuN@AcZlT](HG?Ehkځ3(+@#5>g#T7(mLBJ9A1CVˡ`nr|hԏӽqpȟGX`uZYѥq?գwWo\ohQ+!}ǵ?a|6̷FF;/)oi';q hXD{Qav4zb#!n&7 /kC51LTҢJНQP¦ʅ)+m@(*jhsnc@3ers\|3d7>#A@Vc+G/܍L/0 =_}ƟљFL?P"ܦ [F%_+wm#y\$f G8?$=L%fL?P,$' 7"]nhpvEYFz_Bu6_oh?]>>,Ý+\h@h]kѸ#Pͪ?uA@il O.%!Y){A9* ]I? =`12rW=zWl4m?h7tQ!pOo,vWEw䟸͟yfh'{r,O1dIF.v(*bF8(Zw6;E ,pB+@ɞ2EcH&{dq`lmR7m0P_h q8_oizaKmhq 0o6oib@#܅t.TDFWزLqcqa-Ѭٲ#đn\tq4'q=PlwTM@p{i72?Qqp|m7zcwУ/v# #@鄆OG&{ѥ_ $}b)N7zcw/܄S ~_V%~Ww[6 8~Dr*/Ѡ=dw>Da@z݂ȏqWf_4A  fL]~G `ԖCOڥe&P.:|*JB<([4JX|(tiLB-@RIkvnU9.;SNmGO~a~"(ȳ3B\_,M#N%?gbb6VcɽrֺcV2[ǝ;l:4L.G9q&lvAͷ6 St7΄O!獀pkCRseFO=r3qɎ$p] ^ִ&˜I& 9)ҫ/ˍ\|p,G:)Ԫeno7:Fryn͏1ԻKT./Wa=Ϲ&W%DHA-ڠ8t?6}kÝ8s䑮t"6%IԮ<;8E;ƀ2cْ!L!lmդr)lLt26bG 2oބJr?|nf~KY+UsܡuCVqʖG%kdqjUKIN{/vT͛,mQ9jJjĵ\KIRmX3gy:u2K H#"1ȖGu\31='-2۠jrTqLdYj -wVFi<2!Ep8yLZHP^q#k2jI<ޓ9y#v֎ǵ4){72yhlI~*.ѱxe9fX8ypafxW|YB[^/j9сQӼX> T5G<fO#ѐ H{ah}Ñ/ ns'АPXjL$<;/ /Λ 23N;sFz8vhNˊ4 #Q;']oHӯ}* 8#c|xn?!Zc"ij|+SL QK,/ <E͇gWJWg=ukd8ui(hq+'eJP4^q^cc+sovLѨ!l\p'>3!ɛ+^BAE҇oRc߇df;;lXfRn9ݼ._'s$v"\*>S q}!B}N b25kh(k]Ryx٧e }>k 30ͥa5N6G (WC8~<ZSjF̖wFClj,{{K%a#k#wXZ@{wopv6Kq+ TZG)1=3D933%;NحR1m>pHɘXuZj.l+=ŗ I'A=.cJtB*砙˜88G^ W];aۣsn*MrԱEoyc8ojµ;tt)#8|) 7܁P3Ge+Gp,DY o3W /&ܼ3? F=X 'B>nG#hdwZ(-L#p3HtPZ%&W%O Υ!ldu,\ըWUlpQ!ѵ$/q$ܩ5'qʼW<\Ew %\G) vL754w{x!9˝yn,d_͹=ChCw[ȑ~hlL45 FB'쪩+8rss|CaFdw-Tɺ۔332d9X&J\>f.FDф9OJLqtő1G7e٦G(#$S=c]l ,I\q㲲XCWiMD5%q<>3C%8璏)LT+K!p28R[es fNS?PB* ̨wNJIHZ{݅2b..Ti=3SO~nw$B9tpG +w mևV1Q՛xeٓH՘8H]OU-Dl<o"TDr@T۷J4(Md#} 2}vBbf*+뤊|^B9C#62 '~=QYj=<&G1mn6:;?Mn1_srs'?S͞_qG17q+D%.dsGȆe}V(q1B)khpܬE>N6N^dʂEbCUi*S/(ቊA;jk$,2v9]aIGWE04e/ yoe(|5'T^9\K 2 W4Ff03J }ב/BL~-͎4rˡxFKq>FQp []h|t*9X[i*ۙhgFլ:v*{B9oAFL2N<eT316^h+:(Ϗ+dy0eG (&6C K6נb>F>|cjwք|cpܮ.LYﻚTќnL ;.;RKƳr>y <#7"uX2XCsp3͟ GҖp]>Vc)Gq8V'dQP\>֑LgwJŔ" ]3~oz7x|L , 7dd8HjԥfK"? ˁłe#WIR.[XUyr)!$s55K Q5|lyβ!(]2YzIx`vZD\J9`ѳ ڄT!^Zn( _\bA}Ynk릶9QsC˸qZAo0h/zESg.`VlXLby /BPi'Myk5/.D 5@ڞ4Ėe9䱏|aE*JGVG c3zXuUŖsO P kTuXI%r>^!:y<à@Y?1Y;l.cB[ʔ%&ˌy2ƃ$Dwŧqq;}VI:$yY,%"kxС* X[x.HR;3sP~H! ^5gV4~k<u5ΏJd?gw/6y0X%͎:U"SӪ -9n$\.JI 1憷1P@RJU<$dSǎ&k`?p^~RId,sbď<]&;܋.يuqhJޞOĘ15kX浢g:cjL?޼ʹL̲=;ev4@!!%d42eo5KLȸ~|в1 hs$ VCe *_9p3% K^Ei })˟G61xLFDyp_+_ZD/ 2lfȕh!GaXX#Jn=ɾ칋3dzWs}ƴ<mcq8dȿfSX[ HxZb'&kH+W%s=->3r㶟? cDc2dav)6SL c .|vZT[3o6ɑ`KO.K.N\-1klFֳ~P'p!lNv6Cb-bbn#_ӥ*Qp2}L×^G5z9hZ„kd/'+tukjG󄻛uv\粬t<ʝc9"r\Tg+*+C: p #`ϦWarp,Y<[eid@i*LHRQy 8HľVwBMeCJK[$Ź,8ҧGxdQTm֌v[f?ꖨBu1Ъ{ַWk{А$f/2KD*CB9tM^%`aΔP{ZE4Yi71Ϻ-oEU [e!vB-##ȸpA⮐QT)E?˾BV،lof:W--g/ArU4*SNp]SCҁ `5ZsnQ ^YZKhr+VyglХ\<1$&ƓH+EҶ§٤qf:92@wJ Zv*&miÀ.S"/F?!s揕 QcB'k9cG5"tYy~C@ts5XHv ^SQ (9;?+3%͑#q-iqBRbkJt-+9gI,ĉ(AqG=IΚ_69̒` ͙鹫E.LD=X Fn&s ~c0^KvQ2WpyG[+ x(>q4bfMA/j{xv&=&rrⰣV#24Pib="3„NvsܚѰk{rB@ [s]xd<ߥsx4rgeU 7vlX,T?wCoX/+*! (fF+\‰`edɛ)n1hdE?K<ayz=>)INhs\yB5ooGzChhS5N[04cUa*kq:(hed;..uilMWʄȔ,Q,v`#;#k'EȊŽӮO/L8#;Pyi}2.,6xk0l+ԞT%@w†<_^L ]^,OVAcgs\I)g=[ޞb;"~B,].ҿI=~47P?;ZƷ2Q& 9adedGu*Y 30q; ˜j⇀Ȥėl0[mrA{BU6BѶ#qqy[3,}>n\;]i+9gb9H2u6I} GUE+Xx27j2(aSL3DHLXN%ڑuBQt@@Pǒ,ȡp16[\cT2j %kGt=ꑓ\Dss@1°m"/n\P =ZQtWrDnnMKufavlWt=hR&Vt&PS[\72 ș: jG,fEft4nnd'bJ$9!ŎoGJMs'X 'tν$TPRrrmil1SMcs#hsdN^j xo"N!r!)}kX cA.5J )<2׶45* cՉNQ8'f2Y4a8-ULBA)ꖍ7HֱM9P{{ɺTsk0:2m( ~@=) YLwӔq(t2vrlKJ3kxyח 9r:^$~\Ȓa֌n4/D"Բ)*º&#K\V4`fUE$O5>gd sZԐuYݫG^ʑ<`w+k3^,{e 8i+X%sr&i* ~Uu9YfÁ @"\鵢%WC9J|MN?YJJ;"PBI:ۭ)!tdC(-{wsmMfХB,\\͚I!-phPҊRi@"lm"6ldbe?Ҋ}+uja^ 'yj)#ABՔH܀^&̰uw%C,>Sj)jFr8YYǸ_8S/M$~JlhdM"Ie6O۷ Or~cۯϟEOCA8'ZuS[\ k@v)މP!> ]hUA~u-@l{ ηhR<~!<܇,k[numn5ܢBB`2cRâf$Cp9n<`<;OSČ~CiJR:+\B#1Ѱ98H k&ba021s~ʻ],pO8?l~;*+Ug4.E/. i"oWw5.upmyZ\z  ^n|iT٭VMi+y1:sKdui&JOpM\6s-[Es'mipӧO-n(L͡[9؍i"e2.ryM3&C؟U>uNKc@at2Jn I2$'A)^clqZ9S7iԗ{H< |3=0B٠_kOk-UQw#c;Mo,eG32$!!b4O B/Zq'Lp7c29rpR$N=G92繀]vST\tJ|llHIrFI LFxXSN8EL9-a @ RQ \ lŏs-gOCRfzN??#tqYuEMENk8gA[?! zb/r1dy,?'s/ Yʼnn;kMIWrqNT#dNd{"rP_'i+?)48Ν^:,۹ n2VQIoV=rqY"P:/]3vvڝs&EoSv=+J\x)]Ri奦Păq81Ǒf$x4E;AVe3cl}!.g{[->FC IRdi-5β;lhU44b ϭnng=T;$C㶴1dӉQ5^yy0M0d Fi\dmc sQZ#Ij#8,Boo率X˫G̸h݉g|,"  oyR6y}<ˡsY5Fi[_'4ݱ2QV/alx0֧n\dDdYuK1&xnjXn}g %wGOV@>;@FǍ%B|ʩv1BWA"bG$NCIfs]vj"̒bIh(`y.}:U)tV!A4f5ڻ|`ŹR2&vtsQiFY,r= Q"HB)-!mڀ7p@U|5CJJ>)O*knt*!)zPzt Aߧ@#?hL0s>cڵG-Vz y܆;Z#]oc=xŇv8r|Xsxs4%uwM+65|V~6a\A8FNֳ"֩`sNXfS{S R-vxWse K>nsiqkoVW3i*>v;vRz*6Epn)O]+;Zv״ #iMd%*TFҴӇrd-!;yJρXr LVX!ߑ#oxi*Y^^FvdFc޻F1_K巑okc@ZFJ6ɞ.#C"ۿlkXL.$y8lGe%Ғ4mVj" [ʴޮVkv+H*q1*3T(Cԕr `+]4^6 ?)ߊw&S {kNEɤqݸ8?[ɽJ0fw*9Drkzٺ|y89-6%5RJHBdQ ?>hmUY![Y>uB65%>;5gpTZ83\-cp`0ܬ{G!Ѭ[jTpux8m& \s ]{WtȜF^w(s3d%RBS)bꊶLx0^~^v s e hNh:<~e1=_!G]jRm?9fs7]=VNs;a~W5|llnLt N\I-%9(t}{z3JwBZohҝaĸZ32lY\ƟW[i[g⫀أlrcDaeQ-ȷY8v,P,Mj;)ԣ M {Om5̑;m"A6_r\c1d<@jN}_ )TqF#5^Pi_52G;41[#Hv7*pHnie`B22"υ,-dlR ߑ4)I2OC(\w)M LF￉cB`" :T^uGN*3)K摫j/GjyN}0J*kޢ*SLL,. kz=cRv_,$IM:)Ɣ<b|XEI 03Id.,oܩNT4 4Ѻ@cQ)&2^[% aw$z;tdsOY#P lxz/t~ N{^w(N^7УaJYҷkI# J+WQҴT0%hsm&DE'*1 k 7=^vRsƙ.?m9Μ!l++;|_Xp-%W }=ʤOcT;_֞YT>%vq`l},xxnԻEY {GsXMD2A1pЎ\*y4ESdr1]M .; ?8A&\bUZ1 P7ځ'ۙicʥ<{i2jڐƸ[@KlP[ *߸G-ק@ NKihQmzr9|(+8\M1?~L 0qITq%TOJ\'6Pu~U9H!s}x(Rw,g>~UEpEs\e2|Hيp78DqjM&d}>\XkD9QJoJ5\Lw[hģOʀ$Nk\H~3xxZ\^&uzK܂Ch:ex,O˃]Kz҆kI^^ C ƏA^=΄tg+.ȑavA?ʪ HDwu&VOĆK&wzNS $"ntRFg5%*ss9sLBodq]xBcW5B:\'!>4 Iܦ4A^^'-X~f#,n͐=Y [lQK"7BDy^SIcC"w,.=VU烣Ԍr,7C'zs`=LӋdy8ctʑ0h@#ۥsh=>Zpffb_帮P{MJ$6Nʳ4LYOhf.R߂t`'RÝ+}H^ SŽ:Mupn"Z%^s.-wM,e#F mU̫LSV0ѷwh~%\XI,̉9@>\|H^>UóYۊg!DӂV?j?dlqGBօmrdG,M8ɥ/ԧIIvdyYqdHc@.'s46hy!9a|+j#Tg㽯v|E%NZ&/sN#w ~Cȏf/BnIT3"4͞,w.}.+WBVit{KKR?$gϖX# |}QִHldУID=)0|4Y! mmhy?6+C6%kt$dm]#'R3an6 0C ;U0^e8*EI;=j&RKŏb3vs,wUҦ<28L`;7$n%ovDn.n#&'{Y҆sꪕ'ۆ1eYw.ޤ^{o kCqIR?mMd$l=Cn8`ʘ9R_ƠѲq K=Ll-`)ϰZ4͘o#[6\.?2`-&PD[tz[)rqDќxǃ6(״uJ敏9hiyj7P__Dr5dKu2N;vkPvLVF6-5t/x3c#W9LC+Qځ+'zaEKDJhr &) h5ְfUh~#C>T'HWUQjƗ89j~ڬQ|Oebg᳒2Y;&_GF[{*{&DF1!``ȅJ+J6'Tؙ\y+Fl^ք@oIeB| |se,cac|*XϩGU&^^ewccW /4z10TL Cp2ΧNl`qro(o(߆i)CC \wRwI?SҨPV`y'E?]* a*7zC B84>A[F8a)KPix0ܢ)KQJ$Yb-$!4g 2 -!kxk53X_#lLOA[MPp<^*ѡ'EosS)j,ܘ嗏$ԞtX'ebLJ1.,zRΑ:uF)b.8bqBKuE UqGԥ}(/L h4ZX/ԁQRͷ ҋu< HtY!҂ȿe4ɒ+9񒁗QVw"~Y#$lerX}1iyjyVXpK{QcIChjuk9qG y}7G)oӽU F~<8tQ5;Ի#:F܃0u7Uci@#m`hnEP1:hpFڸ =׫.>_/#FJ#30Hq]#`eXKOnI-_Yl~tc+"kHkʏ2k$<-#XMEj"ͼW~"VGVLL(^׆C)̟$Eshzh yM7rydTG1N[#sԂ1@jOe<$\<đb7 \&tU^Z-RĞ2!_1?A?%Rc7LGad͙qc._+EwBA)$5O8 g}<ݱZQ99#5##yvaȣson<ΪC͍bn3 ƛ# bj_ԚWFe;9ǐZݭ O RlmG#5A8z{Uxukˉt]? e-k\U+;jHu=Wd*r:]PpsNl|f r%y`aj/zמ(ix5J2wҕ +,sޭ!;W&,Oo:ɵȅ\O$~5I&6HƇݸ9Yd3V:G?鶋[A[rf,m_坠?҇M+K.T0yP'rHK^72AB(hDƘ@`+IQ -u#T=l%\@G,} /)RHCFH,-d.&ۼS%qf%A@R+{kq*M+ #iC4{ABBb` s̍f?:Ӌ̨kqq;8^9Vm $m1%9So||ҵG/31$Nk4Rs+ûb{ 8YhK:.ȝbToI'\ vy5^:CL R/ul< ū7I#k}ܿj.S1F3aGDiֽ+xBtFoE96n<tJG8d 8N2Xe$22B(lpQ5MEGG!|B=BmKO"4Ur? $(+$=}^d~2þaGzo X%zPWqg];ܱEu>`6s#729\]JT8sAA53ܾAH6ozI۵*[p:{Hx$l׾"aĈɐ==kíZřI4 1dp֔RŴ'$wvYIR]^1a~GWgZyT4էDkyJ"wHAnbHjoO)Xځrum*krz$f{n|r4i[jW3}qZ轼C'~T97g\ǼH{ĬK]EF8RIfB?ԒsTHnTɑBM.5s9`apldxsBJ UKVG>: >^Xi}!^¢Q6:g+Da'x /.k^ yWF,X79.&ĸ/z딖H!nIYjkLd+ng\x+є܎xT<1"@*NJ~ނn'E }ʛX"bqlNsi!Y!}r h!1,kվ:Ƨ+mh jJ<1^ TMGJLL5%$=|j@~i1LRQ*8,tU ^ ]t 9aVD#zG;ՠd_@Hg[i1"e7QfNqԨͷ q΂L~@[2M]o.W Y?*z9| đ1/F_"w4oT֔T9:f}:v@F'|Nj{ :y>̜Ȅ$xpm[/YC]x}.6ȌLcs?ôIk=#ܧG ckz7jZ$֧Čdm%K%brCJǐTA<?CI?lx uUq##&ϱ$$\ң O*1đb"8FIjnie)ƹ?IFq: 7qeP_عf%" .{mp+#9no RCfdۣowU`$,w!s:Y܂-x W!`h(!jZrGGN0Zm.Lmk4z3ȐTsnŏST 12mn.ֈ`'Akj[Rlq8Ta:C8p&4zeOo6!`Ht .yy2Wl,.ִ7ҤUoS$T3.¦ɱ,[hM9Jj~%f1' g4D4;u{WAq|Cr?2bОpFH֥ڶUj9e9RP$/s$nZ{uSd3XN&{O⬔"z|:dFcX9sdN)i[{Os ~\?S8xL\tKT6Z"eCԨJ (942F W|j(H/op98ḵq]L)y,`AaazŔ?{ AiQSV8X!WfA΅Z۽w p;¿^M_>c(˧>xQ_º$[mA@ Ԣmp5 |( źh1 PԆp 7:Qqc A?(XT9y\.Dy5^֖oړMUyBtbn.\>B .A(%h9<2kF+"0g1(O 2. I'5?.>C bx86{~Z&yF4iՕRIƐ ZOj%6ϼr1O^.֧QCZ|uCrT%)JMI3~ THdu*Z?"twOPDF⪤_ƲemЅUE>|AS[Z2Kϸ1i-p{ܭ!vCG%O5979 ۴_t3͉qqb V #:8*ULF\+E4O4X6# lyNBc>|_kNW\ZMovszf+76RsI]T+N^M6uf qƟ i}F aZ23^(GbY?3+;HAa]mv[Y#gjp}fy|G}?к"ު*Nzo{kqlC G S0,njtRdKVҕ !sfc>Y96r w:Hpu5XG֫ݥϹi!g!!fƹ B vh_z!?-MV:uoCF99'y?Hi_QA6>T&R˶Gp#*,Z]x8 8^-Rؠ?!JфN߰xEjPhP+֢X_Yl_.>Zd GrA<쉲w0]$˸Z~eMR[EvzLIl\|/$(q/3#٤4=!E`-ʥ9N|!X D{7}7t+u>G)GMrsqQti23g`N(cNS'cf.;4@VRDBrŕPY|[eitj ]Q+/!X\kUǾiETn;k, GEfYͺm@ҳY.;)/J($ HHݭh%`f9|/jv9w8Z8V&qG_iq7<'mkX9nX$e .$'^OO y)ٸ0^@PTdʞrhRy\*kCo^ORxaYas4<t_1I T2,)t&4 0nr#?ܣ |{!k]д5mߔ_w?b^*954#;PECjPq}@åɒHȾ`T=2R >9!zEIpnM+ϽW{}TƏs@)uw,W4lJ~noۡ*K%;r}t߭op?y!p+r4Rl8.s` $9d!.tG]UV̴:n'Evr-g^||Rc'1) ڄ^EZ3>˩nvr@_:P[o.rhq4U%ȗ4\0G,͊3 nir3;hjp̛ ފ 9y\lÚWC7s/EUGjq^VWyB1"h֐Rj- Jhڭ k<`2J5QFֻmw]-7{g;6XcB\;]ܵvZ}in¤0_K(}%2xEJpuH.gs8갯KZU[ȏş?λ޿²NĔ[t񬙲+/[菨j7V35O{mMV>o=G>߄eA;ftr%cvuY&V^l>1ɖK㔂/,n2XQ,*ꪇrXe8ȝ|aʽmYq䡜Ƈ#5Ej;+)*NMI\:2$ʕ-䄵C\4"ߠRu239$Xn[(quPNw[乱 4=lƀ\l)ӧ֢ZrDge͚yHtӽɴ78@+ڢ%#qH(7=FuiI1J s{p,<bq z*>rS3s\HQȈh= Tqě,E/ŗˈȲ vbA-?*n[Rs+75EbflQ6 N|QuXAPy kQnkh>x&62s_ԺЬ5 u4@8x w:'A:-]˒G mmaRMQA 78kxH$КͲ%; mjō { /n~A P55M(r!T2sDrPu?0Qeﶣd~6>y =*.߅ꛢ.wmU='8T\ŏ ҶMЂ*THagEޒs]C41=K)~{Q$LE3(\n_Iyv)< 6{ 6ha֖ %Z w)VҦ0#-r}Ab+{+*X_reƚ X4ZW07ͽK@+ud@sD[4!5R7=>O1O3: o~\c_:ɕ34ɇ"hP% }GA]g=r-)U0ܮ. ĉ׹kC H.GuZ㹾=AIF2W%gnGn\cdp5+SJԙI*Pvd1(鹥dvN7{Oq1#yMۼH|H$m5f̏{b6B!+λmvu~&W^8Q@PBzt } r m@#[|BzC=JZ0zdl Yu-l}qZ]tiy=Jn7S_e}`2`3+21c~Ɩx_p~hae;x\. C}I2]`IRuv":'&C6Lɑ}629$I<0)²ʇ{c)r3ź8:FnZA,0/?|lǡc4n4ڤ\,n6+ Yɒ06 l5Y5!)kf[e !;x?Zzpw3.*G*Y0;s h%P'Dⱓ&?mxJ]hSODgyITbb"WF=Bumg#&| Gh-CY2626 JRK6/M14U5Oԅ>5!of }M!0|m'%|P]$r]t%⛃yxLrEڄB ڌJ1u7,V9,3 S䍭{Q}|zEϏ[mJ21qDťwt%{vÞ~߬y1q-pKJ&~bՍW^¯#qN,E准\=CZG̩.\ ^7NO-yyn&0tU_.'K^JUK/C/ qyQnASH] ga%yZ<+$eff VWq[[Kv5PwdFjƺw?%0k&@>-ݑSaN'WWlUO7,L`~ȉ;G ~Ru<X_FЛwjuoU('6bHaӻ5?nPj-8rrq_[ cX?PT4iG-fִҮ:a~3 hخ? Mi!Knr#sHUԸTekV($)'bU./hoEI@@ݨ n)<x#6zd]Tw~[aO_mܚw^ˏ;#3#vTm*0PH7a\t#іoZ`v/3?7799 ,8 ob6ח<H͠X~DD4/dĝUls]F?? ޢ207dyn4ֶOϕ>g ?dc7A]u=AoQr؟(o'9q?n1W`Iv҉Ŀ 䱟+qps2f->-Tg%K2tҴf|Xtt᣻- @P9Ks/#J;~o4~[6ɤ. \0hFc7Ƒc1r %Z cS^ AҨ 5$[\[( ;n}UT?;k+ /1dh+dAZC9kdB(O.(6YnH4og:*L$d8g@4]zW//cbpYLd .V0m\l4{6w_f~K\?S;vyen^XgŬ J~VRiqe g3&v|E6~rҪtj{?;(xFFKEJ_+rQoќgGeb=8ms0<突M!sSrQ,5FC3@Gm UQPᏈ K'U{?23dke񃍗9cM;Q[JQdZIҘ19zqG Sc88J4XNԭqꚓBo&}-.]F_GstY綒zh#㜈#1Í BCˏ Fƽ;K 7ؔ)2'76,e ECʦ:YqP`3#p$5d+T+l! )7ɏPAH+B{աA'[-"čpCCMuO;u%D9Ѿ":|j2MgՍ a!Ȍ^r:n#?+z_ <ٗ<>R99r([r7N8ȋ]4mp}@W-fx^n+FEgkm+~{x_{)W#ΐ )~kS[Nm 8:w. kS=(W@ _6{ LG |:!IMn~T#2?͠S<!޿A.ZN#(U.+17%ҹ;@j~4(M#0= lTl ToAs_?y1mE>>_gϢoֳed!ےNYT }Z(i*[ZFoؾ} cqP4'/acbW6VrY qs9j @ѭrW7͗-LcżE#L1:-\UzO2+0GdK7VG@kbs~5茒3+ۣXдc'̉dq/!jn!٫oF(W X=ݽWvK蕤( 빞+4pgZL%{D+v?o>;:Q3h'$y$arڲ5Dk oҝw?/at w'2YA!< )f}OSo>'ĺ6qȏCFڸypjcFbc徾;v&o& 3ha-pZT# |ZPn.ѠiM8V/4^oL>lFoN뾨Fy/lޔ|~9y^[rv~^$ds~i>Aq A]G KOyqx;Y#zֻ$cĂ&c`qf9/qzS*芼c/ #q%) e[Jڦr,{5cl'lsoBޥAj>,nc7cĎƉW QN 9.3Is͌]ss\*J3iE8x8dq;IPi5AU`er=z]ہڗ4h˃){`ȎkKn:[P7sّ_'PP *5.AY<>kZcwi({ ,JRaq|h1ţq㻏O%MM1ίǖv}lb VҺ"L6޳3#̈pd:cГ _v:?xc:!vaw{ @Я qQumVT1#^O>64mk?  3V(}k;# %"FP b];F+/嶵I3a,'#A N^"KvKov0P| 191dY@slrZpƼ^ fd㝐ycs۹Z̓xI4362M oHyAk[(C*~6{]1Etgr 9 ;\ȱ/P]}NgMW7379*t{6t؈)'p,q@נ=+&l :ƤdIMV͙8%l^n\EN+_d; _/ I< 39?t+쑣k\mѵq9)GS.t2dG9%@#KSrFx'nD2K.A,ғӡNS+(qss?qX˜+r7==nsrt)q$jo~?q,Nja_1S .ZPj-j*g1J4J;Eiipw%e2'IP$G9ZA%k{ x6qty__:HNIkHM6,9N.:Vl;baDBTB!6ʉqw5WEB E SVe1q{ oAW#KfE7xd$wNw(k̻ͥǧᜫ3?κ(N4tր)U:%1 u& Gp$ @N~=(VGj(궠OmQm>4csfu%pXOw'="CEb՘w{YY>e9&`Z"{mݴ'UҔgrڌ[~,#2l+dYݿiK/vI`* #crrø UT-~H|sv%X{as?/bB% m^ǻRXR\H |DqGabr~i^g̪įՓVn[\NA|m 2&s4סQfW :("iGt{n,Qӌ""gA.RIfL),#?.rXd GNReW?/xJa=TbXKVG:n[-" hn/ʊ J<2!\%ZJJ"I8W̙ a07(j vZJ2cHq%xU=9Gr.rIX1H%S+byciK[1j>=a`ccgH9,r=ov3m#= l4Ø dʐᦩIiS{&cG :/S^S4t6Cgf79gniwUU#Ljq8Ot xFG@f3# r4W9ĔZ0O%^8T X9mCYnhf}y?+6Cd!,;q)}EͲ)2 ۏEGIb'R .~ab?ۆh-Z6%[n?d8X7mͳDJe6=*J =0 Bn˂#LR󩁬,ִ( DNy1p 挗=>4(lںWO/1~_qݨ,Ok!K\ݭr~u[JsLsOnjf QޅiJ~U !#D/]'"5W/ doOHȃBAG];V\-E,F{$+d["oTR)ً?x(}9<úvcg3qY7^RN4zkSt$O^5Мl|19T2yw_i?m+u,T#'#׌6jHq>"eUZ<>x =2V?-p!ftvؼ6[ dvLj:oޛKY*5ukrܻpp p{\ WZ+D)7ʓ4f.+q>$ΉlpXrf{bFfc !e &8gxWq蒡w(A񥡏Ե)cN!7=G k4/^|}&濲8  y%HCt©Pw29w#)Q bX+μx}tu*Z#AhMz[1 ڎB +ށ -V]4|*KGѩB[O]$鉎o#LAo Y;9ys{C3װXi*;IOUCkbpr">a[C B4ߧTQG)Jmr{{H1ۃf TFvhVtum8sp$_Oz֘4s;a9\"*cjN-WL\Hb=w;BTdܞsݑ .?LLU$fdQd\(J8OTs|M7&#Ǐdm GTА!۸ lqe\ytp)EIˌ~" Qێ,<ϮjQkCC}u[<\3EThg[^HKԔYVܶ?U)!Қ_熺G.sukJWd tq?3]c80ZjyJ.5xe(ɎH ; ;믔%ƕ8Tp|ӑfLXx;|FT-M½VF~Y ~ߞڷ-1g['ǍD/x6|o9Y>"@hzG7i8Fca17S'|gIG%2iyNXqdAɕPZ |TE$FfE&92K!=j Ygpky0KUsjYNϧTAy5533U̓3$o,#Ғ95TK sNcy}N,7;H3q|R |+""#{ypTTK])'dsv<7ېts!OjwUp(x̖6)p.8Xp Y4_lO9Ss[r7de^y tWbCY&ҡN&7jLpa7Ti+y,QK6:2T &L}hKyqbwAe&<#'[Qkx1(y/wsV,)7$hj$6Ts/66]>tѷ'XszIPIҬg{~1;%`lj.C]%/CbJKd.;r$%8 D^"RG\GIĹ<ڻ\LO,~_=FK x4, z-T:83\A҈osa͖9"6ԩx6K~Mmm]2gĽg"54DāZ"YB_U4TdhnR5+3 w4@s)2M4lH52K4}?D7WEs|>7F\H!& @Fz epKtMidȩ3BlfvWoHFV3])hǵۻs%buֵ31囓xf3 .*^TA'ETCxǎhϓƹ7"Ss~[wr84j#rEeO,>#>kX ŎkOSK6ND́F鼋-;]?]aF"eLYbK:㧈J2PW{f44$tulE Y8>g0?}E_qmXq>0 ӭbΨL, bEݴ ;nt3\$|~N&oGx~uX3ׇPyzw瑇}p|+ͭti7NPs<>M4tCs+T=cdcCP3Gôi4/rrq͸cO>W(B,YO{\|8ۢUt'=+L3GHsacAlg_3{f'ZJԝB2! ;XI2گf/)]mXC1 nF Fv5d{V'k|y?.ȑcX&V;QXlda& M71e&dq~݂Yx{"U"Fb5ڶ4_J),Ĥd$Ȗ)^ 9.k: r6 qǜwdDwp뭾19nOSҋ\09hn% ǑhƷo_k2JXS{0:=o(_mzQXnq881 'W[ݥUn?sLJm{Dޭ*ўceK6g;Kڰ<<n@Au;9`+oSs~ν31ؑh^m>l~.FbEhr-j`9ܛ@ uc@@-e@ 6ށ b-U DROE- KweCjpV1%F.֋TIwsR(? ;-N-qG+ ܷ#@xV37JIVԳ#g3)̑ %cQQȳ1+4핎>W3]ScTz2>"#_&8$t['Q#))ԗc-1GQ Og d_EMjU~7+_4ϙ*z6F%nL9x}sIحq+-9uĒdteׇ#-{N`zuH֘زV8 j3Mx򉿏YzoR-bBA:Nq|1'g Vm{=12<{|J5B#ȏt5U2# ETVl9$7:^Ee}~'<Ǒ.~H,׵NW31!0rcec9ۼF-*L+y)Kϙ0Ӽ- lm\Po2&f^b0Ml^oo{ʼn qc" ZZ<:!"ɹ /SC rM,ɍϑ7F7%S *oziQWCo*g3~^d>i#OB+/Í>>}M.'5~F9s?YM`\V7A+0`8#7Ǘ .@r+uYj3GG^nk>\3C>W>_vi_M T|T+MŪ>>L w{&s;&13lJ} M3X(OѾs{bix YΡ/=LA1*|Ƚ>5BU-쨥qqX?g3@;w AK&G' 7P6*(~F=0xH~mk$C޸?c]10u$,{ݜ{18܉ps!̩fRlqU̽L$gsǕɶ8rv꺟 в?0}2}c2aDK['$%+1Ueܓ+|CB]jװuRr| VOs{<\/{_! ]l5JZTcVZĻl>NB;rbi Bh ڤ^mx#^,O%x,fmEvI%|=ǟ9yS1d4{w_^'xneΊ,@D X挆i_2.j[kH}w7ί?&|Kwy뗖? m6&I. Ҽ}yb%Oc=Vgs՛e*۶jJ} (&Fv T=JLl2;~ YQxf-pZf?Dz]{W/_LE$nV8.eqWDcזx{l Hl/MDrmR7uA fs\8e~<ɊEaaxKSiiV*;Qcgo ;óp^nS5vR^Gm\N<2fߌl3#9 )`CB*"k3^^RF ׹|mkp+$#y;e\w%qNGsp48)'lj(eܣIZi:CUCX4:? lNcCġZ y1"c\w5ȁ8֊$9yC$ѳ[h $5{8_T=گy NNWc)k|u?Kml809`HI܈Z du_yJu>cCpk/:vGQ&6G򞃟&A :gtҹ_* ;zf_1R8rd3+#w iho)-}FǨqƒ|OU6-Q\=漌Ƚgi]%t9U%qy1ǗԞb qn`d4>|gb<?A?t8ڴo xnbgqj%ǔ^rP>( nRDxs}Վ3?'viL)WyXgy~#5?iFFOUz|j6fV922^Q:4tvu:#d_W!f55 @ḶaYL$y%lh/5lvû.|F'EB5pMP.\t6 ~}0=7mēB :(.&+!Y$kg\R#9Ky?0-3`7NABOӥv_09(ހpDB@jvJׁpBu"&)PJ"v_A5$IKdu69K*$QeT/rn (rmIlT2ok+2sA5`4 ߾&}:?Oj.Ǜo?a8\A3:6z8ZL_y(i^D揦n5\mF^L鿿mnT:)x/!vo)j)ܵTy~jвpv R(z?*g^9}ӇA,lh׃pGӎYUES+nq=HØCWq[Z*\SQL?!)sX qQX\E=q뒣Xo;LNة|k*[Go_7KIJ?#≱%d[PP7ye\X׮K\U;:q˃{{N9aْ߭O5wj~cue9i#-z{FtUvIܰd~}xsl'rB|;W qY{u4YfO'/z4sK29"|nj lld,ǛI#{7mcY OcҖZ W3~8^v7FmoRRs*d}=&aBr #[ҢSQ6qvF93Kn\J\?k(6{,}~r&zn9OJw%i$NDa!ZκYDly82)99acݐCyj@5|F3;ܟ#LOde K}5V mF{/y.Hsz 5qX#,[1YXyFy81~ձqmNſ=۰<&elp9&gH#qpZE6{{ΥvB4g 3lk䈻hOkZ=;Nx缲&|v]doc\r/oZܹܿܛ6dx9s1θWEF/ ҵ %%<(EOnн},s@%m$6=u.i?eb7#s mDSHW_[ey||y&>Qn1xx-['U{/cL3='m?ݎ[7:?W)+9%:*F6K&6lp,GD/hVmw5GQ8?qcp8mdlsUD+hNd׍dlˈxjpR|PJY'RnV NN~V6X͙ጕВǛkw8N$ޫ<' 5'B+\` W,/굷N5~7ܳ=3"! ;M=MՍGz?N_k޾#7s%|)䕬DDG)M2=ߊ_bdm \r4x3(:5$;^{&.TF8Z4}^R]3U)*2n'ΑI ]OdFas𲑤g(HQISK'Xޱ B\:U>hygGϸ'/ΗyuE ,Z=~%):'J/Q%@ue_Io^[ϹrɞF,'Y^4ګIhCָvq:z% 3=7dq=|Q8<9 J/ZrKJB\YŖ< 0MKJ[͸ՉT{ͥy5GNsf3qQd甓X4hcqvoJ\nc]VSfX[?2CcaҐ~&g'F/͛)9)%CSRh#pqrn,g okTl䔛mDsp~?.y7*ڪbf+&×nCSvkO@-ME,!+{y{,NKLa.z~ڳ ~?CVD nEwB#sX"ָ /;4/qwey\oSUDYnE'8bLܮ#k m5בc3z c` :XV z;ʗ''.3%s)IbAkEf!T-s[FDh+K$\)|ɓe{-d=ks 396ϥQHFN3"I=S#vvuݩK?MP_|/N/[R9.^֑UI\qOSEr.^R77ce#._!;J={T^GfKsZ)M}>Qnܗseկ{[^Ny;L:T>ωnW,;LjI$oikb8lOTRBɛ}VGk?RKGSjٳ}Lqn %8رʋZUT"Y#dLaU! .VJf⤚kc.Lߔ7 dn-v9)={ JV]^y mn[8`ǃ5vc#`-'6G[<< Pcrı39^'(Sօhd^R;}/UNL̬Lj2M&s]}}7XvUuv̺սgVOxO~TO|g;fC:9޵YNPM|&򖮸;8o鹠Ð4 ;3K/l32n,pOӷU-^ ,geۈ0p`{kMƊ6ƤmĆ 8Rli&{ۈk%l ǿsAnZIE*F&ƟYl~wKzdFҮ5Ob`ϕ"lNiZ F8mƺ`.'ddS'39Y4#Mtdy/i~͜%0Ǔ#;kˋs~ZJH||~|#ߟ31"cK @29.\UdO+G%[-ٲw㽤Ӹ{^j\TRq⹜gd̖͐,{ekHknk|{]+Jif_φvg; !u?j#KVms^F@vVDGRIllCeY&jo&RDģ>T9 a߭ls'*u)D̳-jFj(1P滢ʵF5׆aST׃wW^'NӽT %zW9ߍr_3,,] N; Jx{ l7bG d{,+LsN9|Ea)UPv c3 lCrCUaJr ' B<)ݮӭeqwt9k[P^ {HQQ-ƺ<":S6-ג"7(fU&MvY?}74F7iR{i^6י=Pf}O7Ii=>B;1xs& \T*+qn9AxX\7nDI cmz ^vqp8Ir4)('$UT4,O8]-%1+b~6Ȫ/N3Ԛ1v9dsDtle"Hdj SJtꔗʒyo7W/eT񕯥G7_s俨Ƃ,3<\%y۪zQ3_yQܣ{ Ǔ'1{ŸhB$ݵX#n2\"yޟ.˗V<?5x )K !cTʕrJ?H4{%aV:M,˔UGe2osqwKͮHNU<[+ڜ'LȀz&`ʫQnߓE;~G^WV)M?@hB,)#1 v.zC7o_^H~BB)'pM^g;WRM͇}WLkNև[#pŋ!;F{՘VBv1XJEWo7̜*_;E_R>*FǍxf S>7# <)FOV>$<%0x4:<0tu xVg[$*_kSh1wBM}zD4 D&@A:61Y unPh+fEVRFa5n?±h0dly$*Ph9ku"O){^ޚ-.ǀupWsw{nh#+3'%R[W-# iWXm'\ G=-+Dz(iG Z{lw vU>4m1>2 (V :^Obg{'L.ieR>rKVN MuMTIBeb٢DNS)S5cdFQ 5TJz3r\81%r1Wƻ,KrKiL96fI@꼋d\~<,k*zQ֫lor?%cZ|4I+9~oǓ'Z767B?:i%OOAdVH@ݍh~s>vmwO9pdqUZSNRk3cyx#0) `MaK#uۏ75a/g :\P $=PD.y =Oད:MߓGx O`)&T5gs>Xxx2chp:5|ORp^G ":6b;֏K7ȾLEĮM 뗨_n4νك`akX=&Q_ϽxdCcPyuQVǍ^!cesxxMs{#ya%q{W&i9z#g 6.̑Iߏ*uSL̏6 5S!b{,|\xsi u j]G-Nm'ϴ= Lhc\1klPS:msLG_ii$zaGFg /]z{52RKT?mK`/ǚXF8e{1>smBⲌrfpQ P4}>b=EE#Hf%}@i/M#MɉB3% h]{*vjN1hnRX`H(1d2σ~̈́ 4 1dF20y)wɢ5H@({W=̨z>z<)p6"@4@Bi^{D``?ºQ䲻>6V+X4TcD`Y&~KGwxF0{{v!ɥ<~b~o7=Ȍ&.@Z/Q퐖PѷrM[z@ׂ(~`4C .%Zb b%Dg} qqy{a`Daz]&nɯO)W"cG\/'{zFH:'2W_}wKǥSRqcoCP6*^!q%B8j'JEOśGc11/#- P75ڥU3[R"Ls52֗A$)hPʦԱ*9z0;vEߨ*P-շGϑ͸ک.:_/\`2#&F:0QGZ-WދF\?q;׭yFR*yF zy{kf_1;hl@G/nqhR]kKfp"6QJ>/}:z%2;+cIt*obSOf`~͒F҅WJET0OTyf8,c`Æ0]'iă7׹Kz$ҧfq//8nȜ<;'F+ߧd>pޮnK!X~kk[wJώ(o q\.%BݥTTpPQ(&gp9{v87ahqp]&v֞Ѽፘ1zcdN  턇y]~ugS=gEmI;Q<_Euo}kۿIs< >W!^"`È蚮V;KRDUw$d`iwi06K]p>|ݕawfCʆ8M_wu/Ư#ˁ%B^\OSJaWGqe$RtGrc; pDPdV{(dc.9ޭJ(KCjorynATi?}vQ[.ܗ+8ܾNVA '{3wmҸwR.mp=ߖ+oxA;_b1sShڼm*wbh,h]*{Zq75(ҷE)tȭhdi>ds KCSEMU9b<|qፒ5.j\ܭqS)҉Y=g:iX3tBΞ31eF"5RuMzDZ{o+׸;/ 0zs<Ρ};ͨ4`t?ڙ2ر@z-k> /z`dOYY5J']el^0#1lQJi-a_7 㙑"h Oҡ?O ;~gvNJ(rd19ΉFƶ ޸7z,_*L'CWy˽E>#;/a1~D/u·ƦEx{o]ď,r =uUҢ:ܾϗfN 9:gc^/p֩:ٚ]rE&\l)+:M1&NΟ? Ef5 Lj/J}^?oNsC4>; ;_:xx1;馝*9E@ TV%O#/cL)@ }­,/lx(7)hj4kaߪ,= Y`Ly-!bh|iٞvU&c佡 sb̓3@#^4{Fvtʌ堋,pHn:Ƈ^R!"ǒXb@C<ĴZ6܌wK3ȆFH2y0i 1$4:õ-%LOG9'<9܆{V&bJ/5-ws~]ec' {_/鴗8mI uEx?RXq>e~kRz|ǽl'T[W9'dsV3G$\@UޓQw6WYt{܁ޘ&l5+"cH\9Cphf}ñDQT/_Yݕ#Se=7+y[H3SqoW?%0 OGơ$Hż2X|7~t_i{rۂXG =f ;~ -4V[rg"{ds$k_$r5\sByR52̜怶)ęZ0uTee^xk>Tbd=]-V vp*K2J*2\j3ȋl(sdq&3G+h ?q= ‡0ןx;ȷюG I0 &ѷ%+Tl唝h87av&R jjrT&ܫTFyIى\Bp{rrĩ}wCF@3 `ʖXS˴s^]ҽ9(ן[㼴?jC8֐^Eyzk n/+-/8̌ٳ!&3 + |Q [Q|.FxcDl|m0fi(Ao5֋Tf\_Yt?8! εk@fK?1E*R/m9]n&;in#W\EۼEL048ϱ [SD6oNꌟ#įl B)KWӚvg~i_b$ۧU5xl(3#kT8  ^ZeEAL>X$WF#B\r9$Lrɓg4?acѿqrBZsmo3.e|܇GIZҒqIb=~_K+gvV),dІѵ KE8\x*1N.'+r/\9"bnvVW.E=*qyјJ9xlA1֝wZA4d֚$|,`9.5mSYwwPz^8#սn',$"8nU ]p;\W}Ȱ8YYL:64yʽJ?ʓdk#N̗?_FL4#&=5kv:_RJJ-TL6>c`Qe-\^! ;=֗FQԋY"'҉/ cnyAEa;JP 9P2x%uJ=(S]Ix3d>[\hD y1Gt3t=.b務} kw`\Lc EQ7Aa i0D\ 鵐Ѯ"deybCB}L zW"e฾k5Yc$sk$єsHr5k[hEqdpp\GE*1qiW4nۭ _N:ltRyv?#b"'J*O-[ۏQ3*_d*vn4b\^>ً|J]gOs|ԾzlÑ9yZ^ zݟGp884ug<8u6?VӦ\'](hdymg[$@vC=2E}_+X5-2VoSsc1xd֕bߪcŊy#?69n+Ƀ kZZW VXg;`K2~H:^Tu͗~زdo+ qt\Mw+щbd/sJWCo#QY[\\^F{nTY1ύnG jhe\gxgv-ԸBwၚ۷u[d&% kX텤w\XD`3q[z!?~> Efcg؋\]RI't=^]+ /D$tn#5MKHU".I7cx~Os66~'dcf׹u UNeA-d? dA1i4!g} NW!k$c3qӍū %(BJOf($2bFFs_ ǙAh)grpGSWU]U "=kL9(G1&GS[dxֱ"Fffd?i!QE^hG=2v9w͏J"ln-So2W9B {iʯpܴ32C7 #6FAIݎ ?͒'(_x5-?{+j%zs)Y70ZrT-Tn<1>X}u=>l?z ?7%>TB#{.e@Jח7P.Yܜ;' MFC5Ā;_Z'+iҁnZQn ]'P r?7)?͑/([,QƪtcY_CΆBD9v$7U5BIɺ1])qSJ5Wr?6Kœ4~4љ.-GC5PHkM+hF#,}O ya{anY(i`y=m.'s|:lɑM?ԙX|W*pnWn䦛lŚc|+.'lm%">+\xfrCG*FY?ժ楁4S!);rMJ-G #ea2BD/bz'J"-ʲxTOymfcL.n@ -USjo~Ӳ<Q]ӧA@ (EژS߲ߧj)7КJ{E@n"UMJAorTB6ّ,MCM |Il&qi8M݌F(:o2ue;ܔX\?q8bDI.n&7&dȡÞGIP͓ƨٟč9h< INзRtG]IF {q3,T& m~֔uΞZYI\cB½X7 VLi]bx֐l?^5s`. CD_3kLhN:8n( ;p7 #2<dit:71.( DQȽHE/\L* NV)! .(@QJu)}.VsJe!$I; uKj{~ar0!{Cbtqے z[lߌE*}89 yƄJ^J_ۯk1ʆHݥ]Aas? +߿đ=9/l;gDc3qAꣽyxw Y9Ʊ#O{ȉ vB-OmTjbeq4}oahP49(zz^Ϫqr^P:#ھcOB>SSic( .><<ɹD,آ`W8UUx$Ei%Y<6=]&8Z,禿{}_%}Hlk˄}3QcUl㹷xn.r s{86dz3!-,*#quDqݸGY;+˒!+rlXH@ZHNL9aUĖ80ZiaE\Ώ~vr!.GAzbF&P1SZ'ҟLݹ%T=oPKYr81\uN͟y[2wc\̘]8Py-S@4{\KqD;\BR5HӰ'nZbY25t$5\e xiZc8d7b\7ryHP?\Dxs$Y täo?=o+gG\[MEstob4R@W̽{wKOXq۸{G.fzYA6p]ρr>2W4/k$  J-\zC̓|,LL~_pb04Xrf;}HDyXȒ6R-*:}8rOòX!҇oR&wMt)ҳK㬥HہÁ7#?52sC">*Tq-IbMxx0H&8dBЁڻ"xe0A\FT7*y'4E0l WGjR-ʊ`9S=xxboMxC(V6{Ϡ}Sycˋx͛8 fKnRͨ`o_)re'>څ1Zb{O D\ZLj^ݮl*5oo}k˞CD[)IqOq}vJkNK"9[(HWd3vLhCϕ$y? /<(i<'V9#"Uۧt\~> y>MI-&<9t%5o6]l^'-9 i$|m{}\ׁbѨ%AUndwy!#hOO6_D.#OҺ6T-ZĆRa}1 @:V[}o/ٽ?ۘ3d$5W_vO<w|o?2܌I^MPw2Ruv^D h =?`mHᤅ;Ҵ#y.D|60f'4hyX6aXmFc,% ar$Zְ"\KxIr=.gg#,ƂS ZC_acW6~^&վ|d@u_}n?mg ?*h xlĂ$i!iߚk\RnR8#vq|txXƹ΀St6k-;snjuڭ](V{<$3@Frx28KB܏kq<hR 2:? ^X* OrD4 ƞ{-1JmnU=y_!G4 Ȃ?yҳa2~.aQ氤;'- \|tS/ p$\J:^ky^ﰚOr4RB)1@@Bn*uܿCXeR88BzRZP2O1#{ctRC{ 4&z' As8r e9q}M&mSI)О0d.9KfWCW"HD Pͯts;rX7ݖ6kv q'4 u'YO[V3RQkOa'k"/sZ:(CU ?r|38?Fސ7sGƼQ7}MuCϓꎻQ_fnH͔oYWUˑRtG53=eCWÑ13[624[ʧʾ{{×57{>0c01X #ʩEo_կMEKEL5Y./spC&;-ӥjf{I>/vߗ`{d7nwmW^/P#/Yo?%y\HFKVǹhp߸Q|oBe4bbq[XtҊ2'ǼҀQWjOuZ^oZ_X\2\F)OMҿ*rXbۍ)R2WDg-+CIJ\>^gܼlF88&.:'sB+8*Qz>6e8:ZϙJuE$g{{ <8lэcZ7 .7Im<9}fBf>)qk'Zb%%g'~œy1(-tJ궫$q$էCOm-&lR;;6iU=67ꮧSq,.qܮ - F|kZm]q;|1;!Η.r$q8^|P3取Ke:~{Bg 2hn+!1c|[Mk%J3Њ~H8YِɎ9c6R;:m]=XKy&'@ajO'uYUx"6,y,ϐP>5St]ꛢdq/EY} _g1w/we3]> ]ל6c62H5P#h?Y޺?1_lȐ\.4Sk͜H*Asnnw)-:(v;"7=" WTLrFi \UN 1"s湠0G:P&.mσ'wۣbk#!UhT.G?6 gdJ".}uˏG?>ߗvIw[^/RM>k'EŏgMwS^kg4WF> JȬ>,?7 Wad2km;GƷ&'%tULc#pqcHB# xSxJLqɴ^ZZJ(4nul494hǰm{?ɏqw]\i6S ](HܛZĆR`=P:) zl~hN74H=9F!rFdJndLqKO0Uy7 kBjmV)6'̟˰|j:7LȜp𒰱"2CWneR+VOȅ.dx,Ji! LXX -@W]mXn%USe<%go0?:i_qcWΟߗf82OV{}nQ݋ep)8%%_cȱҾim_W>gp=v I/R]-)X3cVx08"6s-Thhsf6Lɉ'5i.qߧzcv ksJ`Hwi}SLCZEE!*h.ڀA/}Ǻ&㙁tEDuSdI~=7y ȔlgK+ۤp<+qW)`d 7I(:"J*Lb6rX0;i_7ӗis}OOЇM g/wt!LoF֛7Dz{j{uv1Źעn ЛV~zhb=fL#/^BOTxꌕUQ޻"zC~_BJ#! NJU7>?fcd4|1[F\8gޑcjҌrXߙn/7Ǝ\3~cT! |u Z  n$`{ '8 nhxkHPEv8\d`Ydgr5ZD^ֲ.Fyw1nFd%B-G.CWbd)y&;!q.lpSsCf%ݮM ";đҵR6ZYrKGv3̂W RF B*<g{vK9kqa&5"4ؔ ƻNMj^2s\EI+}@Ik[bW*pnEg!mm89+flsߤU?ƶbtċ~"AifZEsуzg6N[27ebaGnL|GsZ\[ҡAES䫁߱9,X3c@/.+\SO%܏82{:8dnk3B7ggu[ž=ܿ!X}&Ḏf~'sP򴖹@?Uyw[={~ֈSqpؼdPCaktaK5rm+V.xRoUZɋZ\BpUH ?K'dŘJJ$RZǹ]TV--PSm>X Yj ZZ%bι<³᜞V)xVz |~zrs185$τm: At6:k &dl;!tч,`k$us`z2U$\'-ɼߕ;iwajuTs~]8 o c&oՓ>av AUWNUQ,x?N-ppkmˑG~w,6N9 qsXZ /J\8#qpv6]jUjnUȉ\2I  d"{U߄Bv)Qg!  [#K׭s\-9/5ԢO*E\BX ->a}} <[OF^c/ .9f(B ݿM F*s=$=9rhqdFcLjUPҽ (CnMb<9^L28b: lm]k7U+<-ȯ,j'ʾwncG BPwˍ mۥ^|`jcxpnT :vWԝ[A$8Z3"XֵsݠrjjUW#̃s||n4dGk"*ċ jD۹8d|6'*nKQˑ~y9T*NZ=9r|c\d0hTM(.CWa!vd;,x(אi&\^YHp'~43)XȢ @#m՜Q:.w\i3Dk~\~>x~ߗ=;qQ31ǰuEԞT-qrUҸqv tխeOSDj\W~)fBhWmsbA#V2#Ryp$!ɒXsacecCA%Fޝ)56a?I,V>lY񵙱@K+IQPZR -8CgFLX͏rnwP(A\db\jV1o#s^Ɖۥm5/ Iۦ)Y`nD09>GHù#+mƱVd1frr$|cs P[`I rӓ=.YIcx.tvnk~LuT/^\MW ~ imW͇E9La>VS#,ɞW50k+ϻnM.挢uehRVtV>2GǘvǙ eh>bIP=WƏN\*q*W{8)J8߽ZQAֵnJJ.SnTr4+t[~u͸.G+:GT?}w/r-h++T P5dY0%FD qa=swirxqBü1xRKUWF8Pu4lx)t4t^ˑf_/h h-s)(W IU4DJ.2iǑ=әF/,qKug/-զ_k|Pk+^h+yCtxF`ǒ:B,/y;'\n'~Lr8#%9dr92͌÷:"V((Q>}hir TLb:VL6HKPy{Ɓڟw _.ltS&NGL\Tᱵ^{|ˉ6<2y/yagzHX ZI u WW,;Bb3skRFʵO`femƚ >rwtp^FIU:XO X$|rB6Tsѷ+j3nTd7iÛ=)tHWk. }Guv[շRjz{g=mF8iOki^+G\z맀o=˲'܃mjm,^o|Ưak`څZ>\'kR\[%<[as.\d!,`UKoa3MlP|T3̜3g!yk6竾: 9PqtQ>õ9\[7 E5'M/;! >=z.zʣ830p[15q{@ՁNPԱ) D'G&'A*nx9O\~x[qŁ[寡{l~<>)=՞\m<+h=G L~&I`aFHrƾgMI/l9fzw765\KFK/˙ș">3]`\lRs2*E[ Z ZUҏR\؜{3߅ KЦ^S0iBܘLL1c M+A:1i)+[ru4wҜex ϊ7Ks.S:j3ҽ[p/Yi= $ԯ.g)6xCar q5Puo\'fmM<^dm c]*^&*`YjN[@\%EHh0-jhA ;%ZT Aּڲ{Wyx.+N a}^\s>|ҺVX1;2֝!r"hR\Z㣌f5ZI"6M;{(SUҢi< l`ikegcW&!9WEX''w#w2- .~ڻruB%$(#ο0=ff3LiG,@iPWoWZ?yYi;? 2y|b9^ v5ڀ,zױTjg~TtCti!ۜ⚆t>aӡ)Oͪ:cq.c6< +_;6zj>>+d1ޅԃZFo3+dEX~K`4JUp,zs3a29xykH@^ZM4ki*͌ lj;:wӞ}#ݒ yH=7;Z*^޹U 8|d(̏vn'_ժS:2$I'~3dXƐҬȋv>iIMЉ0G_77s\ƴ8=+ כkj+k:#e\F9F5 XpM+\7.4[ջ t#J=Y>!5]> p,emk\y\xZBoK&jY;9=)i kɨ{\X~1(= ,Kj塾m'r<{cb)rߤl'T{x 5_QVg8H"/Ȥ+&aelXl5:jç4z] /Ff^o`DžsܖyE1x2=P nBzT;q|v4OףmxOh8 BG#P .XH(]3x{1F>gۀHwWe֕*r&|B^wLY @T+e7%bњCQޖ<{&vAӵs)ʹӗ.Otp99 srJ+ҍh<;A$yCF"G])R/`jљ1*Z̟q`r) #w҇ Rjk=QOxd{oO옎1 (HQ |JK$O}16EoW`@_5)9i(-Q k~]R"3]T;7~&b@ܽX$sۃ)qMQ-\۫ݹIfCm{sO};H 7n<5>TMMV}1R)*$Xr9aIьy" [$ Yƀxb#ɺ81m ~^iUxbIx.L7$eFoKБTJy$2JEP쵬^1!"pXnI.h\u. mH޹MF$Hcek&ܳq -rޓԮ'DJ(~*7Fc=VII 1L$|ik} ږew$NC7=ԗC~ m{d*в# !BlC0018w/+쪩V5# -ȎH^qāX8,Wd pt׬b^8'!Pc] x= P5D_I.'$WyMn5Q4~\LmUVx鞍m3 ʄC4XyNxl28=7yM+溮v.ⸯyA;{JYzIV6y(l]oޗTNc\]Ѿvu4811Go,!kC@~Cv?cw5W([-KD4PrΎ\/k#!ůi!u^o)+O^ ҁ~Ua>BHX\lO&pi6/yWeߩ~qxfe@"pUjVH朗HdbҀob: QFT-pImJt]h apB UIU"< 9L(̉ǔ̧);n懁H+b͛"ܸS/rc' 7DD5|!eU.Rwֈym>Kn8d;ZkFtj<)*s|sqۉ&?!!$܆߮^̸NJMqػX'g0\ ]_xwoGXqmx!C l5+S :絤. zIBLwsYpMmkZƈ$X$u5QO°;6MT{0!j&tg=,.LMg4;#'cJ,O 4p. R+.{_͇tl7BcLY *!?}Tt^t, 6ɱFҠls3(5Tstv_Mp&tsݷv뱪|* VcZwA#Khmw4`= 1BᇊAW$cһvۥW9w;?px:rs'ʕdS>g1IZ 0PT|Eٹ&n-͋d &(4y.%xk5:ծG^f嵷/*~'`cDQ(C^ߟ33q fp6;k< HCj| lN)qEF,s4 &pN\ZX47hJuA?Ț$(C$$ FꦄŪ'5+IF c{Z Z-Yܰ/S% hcY"B51+$1s7 $q>w.Mď3^VJ\RTO>O-N6CY =-}uR*hZHפs79]m$k,qU1#\HCY*ZQZR\oC"81T8qPk+R>j-ޞj/qAz{のo Z`,ac.y[ާr-\_6 h 9q6~;q'`"|R7\Og}>uO}N1P('ɞ1h2Zۉ uܧLMgLPW]umtJ]_z_-h3ċ UFxr䟝Xq"|>U vp,\m'jWYOpw]lû<^޿c@ߣQ vt)15Ws s}9Ks u CBq|h!5N 1P𦘮CR)n59gPZHbkw 5д1& l~PbbA dQthjYh*W6Qz5tG78: up_uw/.|RĺdU\4ؑ_^OP+pu_}mu<. }LCRwZ n#Wh^P1 IKc@wt)dCQ׭([@Cn/ӵ&4^1ITTWo3ix}Er/tZ f}gQL(Y&0@>ޘmн$7u0\=F{Z1?rw/ϽMMxG簂z5BiV1[4 - &As֖$\xAsZ\TFEÇT}Ֆbo9Y.Rzua)TpB>$ w9ҊމPR8!Fƀ%;-*,zOcnKJq)8 ~OP:ַ_SHD cCbp~/XeM g8'Mąc۸75?PF2\wG4bgfy[b-SkܞjeeZ:~={v+1x]3\vZ8mY Mbk}fS7 Aa5Gx=C+]'˃ka՝%49]fba&<h uՇ|ԴQvVԼY6C;H>,t"|݈lbc6i2 (ppI.CnSrmw$x~!Z0|3 9aӗ\0-iD֮6lx kqqĆO^6I8^-#J'bU Wi6^oWJ}3㕎kWBmJJE+*w bW.L!5 ht .&F:7<]-ڱ! -9h@p֘J彈@=E%/{'γs.1~5rw7lx,ЀwJ4/V]˯o{ \ [0rrz0J6m}500X}/^j `ZzHt RdF~3dh,xMZdJ)˞<6%|r18M~Uo:d/>y۳/=\W~#8fF#ϝPHsuc踨_9[uELO,T +W>ڼLZtd^q,BG1w4 siWkFr \ o Ha:-E\yVXfx7~d !;k3|U_gr~#͠IJ Ɠ-VXp$.5ch׍ZbH:$ |8XCbvP_#og:*8]x}7szjHu߭ UҥO-,ljiKu]4j#)NZ-)3JݘÞGs,|P|xd< },mQ~I^_ee|PrkE$~MrCL}W{sN޷k(3_ =EnլYu L1FfsSQk=!Oo?ǷnPJk>z3 cC+Ad`3H3f||ma,nmkpjP&=Ly J#t%2HÂ![Ys=ON(rNvVLm\_dcB#"itm1?i#6y.LE!c; kMսe.dJF˚Wʊ@QGJL8a dn UD?2bn4J6pUa"±q5V%>LnṮzXrkpƽ}O{흲J>iXOr| 3IBD鍺6,BtQ}/zZ>>VFZ b\9f?vok[3ipcv̔s|,|MJ֤AldWi( :/Я/Vx:$Ӑ/KW]tFf ]>uHLNb;u@q}=ѿa;KJViV- C m !\.QsPhJ\|p23)[kZ#ZܖKmQ#)O}Ã8dgNр_b@;V^;呮gi jUa^&+#?Nr'oMF剝+6!f:`|m-w_лe5onL+rX=ЍQ44Q0-"?m:Kxk2džQv }{%yǵj<4Qu!Q-HtV(`(ToJYD>pDђ!7!k p51*BA%i 5Jmgb!3ʺB'K?߽k6B_Qϑ"J\F`GD)?CGod{-fXvn}$9'LN ۑmQ`J8  te32.>=HHq!s_ P2at&7s7 )# 'vr~ JjUo&78 <: &ZHEʘ9j>)OC߹gySUi֘m~;kx!ӨH֘oZ{qo?ǘݶA/۶ҹ*;eS :cENor;dOLj8yأvwX6}NsS/%irGPYi3IA?0ָ$]=bj6ړ9Yr_/`_\щ /rL~P61CR䈲Orpd13[# KP!t`syC7U]Vk-7,^eJױRcr1i qdtʔq}PCk mY7`;45dμ Qaw_Rp2Ғ8ssH J\&& g .3&K B@#Uo&D3R?G1e%7]ho?syH>VͤGͣ3S|GB6Ӏn,mZ{MJ]tW'*˄Vuq~[b \p E3z݄ͦ3go7SrY{y/C{:WbgBjzu f@\_4.}n[ے8bW8Avq c׼ogxc1t'(R;$i}7.uX v^P19%fӨpVj)OTy|/13b-9P!?•*crX#o A$5f ԓ &f:>'"n5@@s|e}E~䑇f@NU3$y!TT%lx|~7~0>$2^8TXj9speŖx#\Q0Q*f/QBCNX? 1t85E QW5Ed`zvk=;$Ooq -Aҽ]DU{ǑQs28LqYI^KKԚ,"1ŗP $!fȒJCcSRFɏaQaڮ,LvT l,5`.'5ٜD߇h_QFu+;az:fnNԵ[tC=~ g1Wi \SlZ[=͍|D+4ܮ~4# 80- ƢO #}1l|80\ixl|I'wI4_#%q{{Wt->o-ĝVR=|kLhE@]lM(eYq[塁gov؛wnw+MJ5z}.[^O?o1c7>87w _+v0Ϥܫ4\4 }HKD'k#X?pc?"L(?$D6Uk '^ͧHoMtF;-0~K{ݙ͟2F_-?+b_g*k6K[x鶩}j{F5؎V}1u9 b8?cC ɱZ %g(幩#nV>,N  %-[mm)JN,Wcdg>i_EoQ $ɵh kW#8&~y;Ƅ?PH/urvS3O6m/hDK^XdKv;ޖs-J\|& fTB[R`5{9HC}lh}Wʌp7F6.7cG|;O)P6Qeʶ /5-ƝjׂGE񮪜6Җqv*88ƍإZ*ҹw}WQtv4LgBaD }Ԋ(W{;NWKHb~S"kX7}[5Os91x6X_-'32#$ F!i>ztRN]O7koWD,\9\q:8MzڏQ)FW󪨚"LW&&d{<vnM4"H/c<dF@:89o47k|cu׏}V.mIa^f.O2A \iBΔΝA:|yv8K*4SQ2b`@!3⭹L9L LJ𐵱Jٚ)*᥈W !G;Ăֵs߳m;ut80\q g3_yw/۟Iyqɥhd>fҁƐx bll2_ut%Zs#}ͳ{0,taiNAP0g5;W$3[2ݏc;\CCPД\iSW1KK zj+Iʜ#u0S2: TC`nK]&GW!0A>AazA:oy>$&9ѻ noWQ{vHܤMg E־d.[\ڀki2TSLGlbĤIv_ybѻ~?Z HՐlG:֛srOoUY9 <͐ 1ھոZ")\+AueʎSRD#@zh-".(dr앛F uzɚ"oqy?i_JVdo_م蚪Wq-PtC=cy؎<lG5]O;O򻽕ͫ[|~Y36۸nsF gLls a_Ô Qb)PT"VVgYR\JW! pH=JF"ƾg\_ܥaË!b@k"4uIqE$V+ 3xеr:h!i#̊WTG 1\Ie{ *>o[").@;;+T9D?8ۉ̏ ]vmC޼mIOk?שSw.~mMbdVw59zxW+do?@O9t'X{|YIs?gh2KvJM^CE ہd72}yK%=tuV'7)4x Y Iv/¾*.wmMj-ܓ0Ǽy>dx濎uA?R6MEks>_ʽz˵$>*q8hdlRINV"|8ک105#kDd31T%fUdePHPs41W5DpM" g)%J}/O>fcjۣIrh?hsp ̒3qtlkE{n?޾C}X*|x}uƑ_,ׁ×ʛ39` uE9 PC6)c6K3pG1C=mU8ȘK5<܎C.2 kl%gCBQaZW/M Br|&nT/-k {j2J)=>/'3 F!Z9bm%vV-7/ij%;;yO}OB}؜@$ǀwVr>E}&aon>׸.x`",+*DI(5CHLlv47CZ"Q'`W XhD s1ZҕB!v h$m *>?1V@KrLDZ,qn6<ܲB8pdLF Ɂ04'n_¾k{.op=Qu5s<ݱA4~-ﭟ??gV Y L MfPn8n۸{ kCGѿˏݑ뼏+Ҥ6|,c~%WZa{[͸R7sV,~WҾg?w#'w ȁ8.@u뾧 .%,q@OT+s@nj**YPT:\)becH|J4v噫ޙ4zw=kF7/ci61e^7"O{m>ko.y;> /-ϡqgMЪ=W4.)dtN֖+%ͤuQh= ՠ6HE |’,C9 j*nTi<%ɒt"d^\3Zf?Y/JљYUKJD_o%J?!b=F*$#k\t(|l~I37dL-{Յi+).dNB4pFHoZ+iXӹ ;)YvKϊ7{qhc+HD?m^yokk>|Ԑ¾5BcnҁD"m(Tz^#T AnC8o!Ny>ↇ$#uquȟwz}P{j T*\|d[0@=vl!ޫ 㴞47tb:P;)3%k6)ǥڋrlRho' !9rt|w* ĀtAFCT̾ #˄#ʹ: ,eA!CE+HL4@Z*H$X u Ts Q!0H(PIͪst}>{ +D|˼|G!NǛ8 Yj fxW%+7Yxw8R@AZTqbr/\KlfaG'5?UfX\P2⫙KO׳ٌU8W۲kGL^4Qeyd^dXpܞOrxг&\pN9 K˺pn[]̬\W"kT/r٣?vfQwZ8ÊXڳ 1mi_,rTާ.i11jDBz3)"Kc qQmkD䁼#Zo2hPZ{+BVeo6\BOtUȍl>$Ucu~C1@i5Dlu(E ͳD><$|P3w$%XI4NY3g|Mr8\=ǰ͐D^d>mK{tk;Q;+nX&&3蕏ԔɸQ)nzwo:{~|Ia@aHBa' ƍrL T*շ'Cq!y:ZYDcGL)JNud5΃M14444=ER!rB{Vw-G=U sKJPpz~ڊ 5M0cHs]Q$s1l vODcjy/%捅s Pu ]kŷyIG8qA|+t BcWNr6M 5* SlV1Ӱmn̆.Ǒ:i_Z1[-!;,j O!Nhg#<%`q氿V^wUon73蛴oXtWM?RExqHir§U8ӭ0 q,4^,#W ݊3kq6NFL)=<E?9)W1;,p33b2C(sBAGVre'̔؜5زUPʍѦ?OisEe5 ~SMQJ~d_ 0GZK!_@hTHc;h }h$]H:tO/}k\<[Q}gѿ˷3n#8jnRn ξ2GUn2[$2n@=Hڹ 8JnbzRX̖D +{AYn~%wXp-2!%<5B܎[\}c31fR P'J[aN*汀W:bE%ΙdG.\D+ԝ([Uoe0:#C8xv7]'MZkgH?5Ϣ=ݽScoݶkBi^gDȠ-h(5'c0(xٲD1Т 7]K+c!J:R36UN>?ZfIcdLrn*,DF ;y#tInU:?͔4m~*Jiaepޞ4ÛI:oJ.,g9fg2wݪ@K=kѧZvzu_j+_.f|_}ÆMoʹKbZ\KzM{yj)j)TtX*U*X"UCk&kIq EAb5uS)P%z6fl!_i4J"[2EE؈bڟyD0 NXKK@P֚dЯ+pȒ*3@MH #q2"Q5ҎpĠMȣM= r\ l@mjb$%[m#[&`8,+DrTA+ddYllzt*;dD_j8 s35p mjPP Yj S+6rX @l(&=5PEƚVreG$saϻv5{\3YGu;OXGdF8>2{'*rz{Ut~dr]ѳ#>YfK֭Í%}ǣFw/wgmϖ9wXxƵ5q7$R׭9aǸ+:PEpcd4TtYɻO7h%$0y/{v#HYN +pv\E=,!~oPo6P($R]kL%W㥫t̅tOT$UbHǭc&lh1j+)2,Jɲ8G#NTdL>ZE tjdWߘʪ'hP٢EPYZͱА1UD^H΅d ;kx3)W}{}䟆 Ɏ5X\ I$|nèk]\WwgaTÑ =C'#J7 i,QNR %d(iP:.EMvgp db%_[^\`͂A4oK) ^kTK5[xS1}LN3k[^RX3J$Lnw^ߥ|RuF\FMDzꝖdYcH p)f6YRI=&-s¸onyk¶Ȅ̛ C)|I|[Ke~*:NZ54t¾41֨ }@={P:7֨@B*G~t/Vb]h8m_hD%~@]{&=;K|P7zq&}g" jL5ҽ'إqx4lq|puPr8 pXo`p(>WQ2p&ya[*OaD]簴U^›br<~&$md7={)6" IȆp| =#M^CץIocdt ^±* x_npΚ\?/ytn5T5tQ1^E-季%9Kl2N>qtq_a۱C>/w7S<Xt8eA-&6B !Da(SJ48kMC( HM (CŽi/ -+H)aL͏ĔSHHl{ k D,,{C s1VL$-4* 8lz; w0ClƭIWU|I<6Amh AAcT1wD11:uj"Pt!$  g#XK`RCPh 5ӯƙ,z^P3) GjdȀd , hddrڵC/㵠5$oMRI(fv *$+Ҵ!kWT feZ !CN0/Bk4fj ύaWY9@$Vfr@&P+hW8:4Z6Vgtv[Z´b4h#QAC0H.9oeJF f  Vre m!:jL(Ō}mn)eۄ^}4ժW>!GM^O #u\Hf0m`ٲA QЋẗl!sŠ%mmbc2R:DQ5/Nýq3#׿PAp" iP*vSoT4*DQ3%L& s[H3)tJIZ:~FA.~>k T@5H1kXKVh؉tVUO(RFtEɕLI(ҵHŰPbEDy|j:V6l݈@DD,G)#`-Iw#V& ڴ!S®4Z22q<6RGp˜إwSۿMw>(m~.g{+׺_N3WmkHp[[WIc?s>kU40<%rv''DDGx?_yG czT2nGH"&vDԂ7lp/l $,@<"ۋ}+n]=W"NG -9p(Wzq ZF?$Rw' ^mys .pF:SWJ;s ]]zjY{KG> Y/.kJu-~зWeh}R42PnM# xU1Mۡ`z;kD1Z} C먹 oS@ )n//{׈kB8 kG[L㉉ݩj-:WźQMbVdV>]*8t̐<{TQ[åƹ\:MEIBdV6Ӯh2q*b2k}L`2X%!7DFW/EW1B۔|ߺ2F?…|H _d!]J嫓zmxۻ{tX]g#,C>i Z:_Wj-GD9jⴀt׽S`",m!SAKQI1:x|h inRsaЊdGJAthI^=mRP\:&AdЍj%$4ֱfM&5ZXxHI 2g +q6.q$sIXX \ ɚt-);P8(Ej* 6ýZd4+nZC!Jv $RHkgCJ2j:S'JR쪡5( +6VLC%Z!\u5H.eܭA\Feoh#CVMsSiP!8(R$g"!W] 뉃 >pّn>bT":?k46dCӡ+<(ZřI RGQֵ2lD LQkd̚"L1Oc/뷐.vk1O#G!P ^2HXeuOFAͷVL -bYɚEc pzijʱ52Gr)|kf̒%Ǐk:l FzBrn߭bP9ތr|Z^!PkH?RP ۷[ ew7)lH;Hn!߹mos#8h_IkGR:m*UB6@K@Xt|)426"LzF\uAIf;lNHH)UJH`wԍ+FPOsȺبEhl<<6!G^Qe.d-~]0Fe\.[M [$b.vKWF#w<:V,c(h_!6Aڕԯh]\WjedTz֨Ͳ}I@,kddGv;ʌû=Zh܋b8Qt 'ͽ{܁]ox`%mTt@v)KQIl`!(zd{_R$G#+.=KHwH@W)YTƴkoV?ZxDUij*TJaSDߙAslpj6_[_Ye|G̡|B_© vL` mOZXuNLhH@/ߧƐ"h*B8t*t֘N [wZoy}gPW؜Lm#k0\B,H]FɈ<{ iǸcʼnA%r EUAx,h?BusN_ҡ@@Uj`:(.d-Bk<t<ɟi9nkf8йwy޽Ѫ=?ǝukr0a.qY.8&hXw b]QБU #=@+BQTEJ?k؝)"@LqnT5-I$HR(TNIB<=z!]*% :frC? {|FC'c@Eg,+h/1c;c\FǸ(lbu MLkZD"vZ͕dBTkRMM׵ /ǭ $9hp = #:AJ@$j|,i9l+GdLU@0,@ ڮH6Ptn+h.b. [kXj<9vl3*"G4%k]6̤eWȵ?v@)7v 0'Q\M(t*(,ΘH#K d̤ R[#3HKE]lDs"qr!9|GEOiZWVѽ1>2!!9Яk3D,y-ע5H6CAI}V Ci&6Oܦ:=fZw4ȅCwyؚ%J :ߘZ{἖fތ'|@K~|9&xL@|4)@ u(ıA0; BS3 .=h֓W1xTiv_)AؚGẇϧ8RANK'Ck]}.&D0an<|nq۴˴)֜cN'+![4 oa:Jh9vr.rA! x7QY;.~CtLv5*/ XwxIݚZCu{&h'6Czv-?ȵ{ooIߡwv?K*1Ɔ(`EQ,|**U o*OҨ?rڍ ?BގOSF* ~HyN55HL%_S$Cڋ֤{L=T}Kczh][DEn[5L70;DLdi2J5eZN$#H6'PI &$DcD{j,ޡ:jW,Ƿp?uhH0#h=HZ.?] qܭ]ER :ުPoc\ _QBlNUl|@sv4pWdUC9l:|V3LJr&eY ) ұh0͕CEJ%<~ [37Ew@+"=5e@RXEśn5+:p%QS&P˨ꭓ2,?rVf-dnA̤' `;>/3hd' GXmOЇnQVrbžctXɚ$oӭe#DE %( bMi",(!O_k2rM 7HHuVȝS` uE2:o1ZLU¦c48o/ ikgBe:5'iҡڒC` cKE@Hș BQf{? |o󮨣 2$$)VAyƀ/yF;65Q㠤HD%-e6j #iyh8HU-V KT c\U2Qm*: ~AF6}ꆕF^~Zqds\1&ڡx(ЇQ^7[#Ү'┧qz&,#zsc9{׍qg\ۨLqg>*%װ8!i%Lj;)zogIHfsOe(GT|9,[C:qh4=]'FlGߜhlˉ n#~eZF[7bo  ]R˭}O@ۧSM -SQU~ֵ1:"+@ùNO8X"/^Av}!r QQ?{q')}>I*S>v?f n+5G?0۽Ď4T稱c{_t UX6Sݼ d˙ q1i^ [,j,aĔs< =73x#CDHW-:a\_<קvU@=đk”Ed٢DitSPh ?I<(J<( S.H&M0FHEdBMV`$+MGʨ 15:HhHdYd'E&y^ 5!GV3P؝ʵekzW\Fe2KH$S&,8 Y;ޡ:w*I!6Bs @ְ&F$Sw[8 jJ,xH~UhqNqbtBw ly;߫%tNդYDw?x ,H Ou*ʛ̨ ƀ'biT6DӡZCMuNՋf $YH=6 ^¢HA*ԒЀ#D"CkP_(I.6C(*Ҫ &C~5Q-%CZ4MH/E4$.GG[Z@ML_;t[̙;htj.%e+thkPx.Դ:s ~ Dz44LcMiL9wjERR+RTD0.$\\Q1qv&ftD@Zu띣j<,E7H]@!V@Л5"g&P.2aak>"_63x2H: N zdJT +iKd)ۨD|mc!4M>ME´5RD.׿D81OTY:YSPL!}7*v/lf0#S5>YEen4\Uһ.Pz{czC2A2;F}\w2t:6vMʺpScg*4CBxyqCr5o}mҔ7 x$jǹ軀 Z*: ! R+Kuۀ1 ﴓE&ҋ!{y-sKvO ^3f kI !U+_6BI[x%R"A%~B!l 4KUۡLG/[|Vakt{(/)oR!o1cl aoBRּwFOz="ۖ=Aeq- vCX~3F#TԳ^wȟ6$I19F a6%ۧj.lRUὭ '"&\-&C iӺEr+! 4Ƣh29UGX4lh2,&K37¢TfaХZLks"@jJ e(fѭHlm˥q\XdI{> wUHGzUAIiX84JA/3me-EdRDЋVM>Ph:p`4OLXV'm Q))*#E !I!ݪصI eTRD6A2.C[AIq ~4*A\z%[i iK%n+Td)6ĠӵLQ&P?ʅTS'AU \)֩T}2+X+c$ZЂf(WYHHp@z°f dW5T RJP`Eu҄"MCVVeNJkCeiy/@iC:c'qJ kD<Q:8 VmgD t$ B44B|Y;2"{ʁ8F<]ZqWTMU<qz9!_x:8r&g?>Cwv1⻹<>~qWkx )Oz,cԭݽ\VX" "nIFg^'6,qOګ?es3십~|u'Q4kkU!p(V4L[iKk(W}) 3BƐjS^C^@4 P#տ __;侒 Xp9,>Mkq^HkO}=7Os8_qq>V(c<٠6Mz*Y#TKEzօJ-a)ZF$ɕR0IMTV&U bSS֭!THFzAhF*jţdpXޥlRڂݻIE ,KOEv!yA[{լQdBnZPL_[(h%@ҹkd`%(լhրͣO:"w::Rd69h|nt=h%S_/~KNLv0;1GD$Cu;Ww-ߢ^mcu+xK(<1PTf ǯ)B}+rv2G]I;I|WY3_`[cI:ijsm@`>Hu"pW z OE^1.Bw`%y =|h(*C $()~APf K#N?‹ܼ ;o̔%DMi ;X=fn+q ~z _Kz& aM!6DW)Uf/[NUPUi"jTHWUHUjtZh4NFz4K{J/I$7?TɐeT"̘WB *f{@+XiM!l@u+}!/XMKe꽏EHM!EED V-tb}ZBIn*"0$)`O4L̍I H "԰fPpChif:ӭCCd -BF5qF?*ʨ%'N_V*rcҭD%lT W5[#:w'U*: H:=nAiWj{2Kqa"Sk.hIdSmN7', u!i%~+Rj2'(bE7tSYL%SbXW= lx oe.@fI[OA $n?]hf!H\ &إGlhH2OtVm&%߷AzCt_ |Gr\,7ﭒ1!O$o {~"*Al o|*$ STZ-S>5#dJcׯõ&Q> -Jɖ|fPX"_$,h$ڴDh%袵DW/ge>NR9q!ND!]N&)q^UԪW}Otq>oW#H'z,SOGjū)\DZos T e񼴿\Oxŕ37hC ZoCmyfi|ZY C@r >t1Ut|;S@9Pw1z4CkiXBt!+ҁ/:!\-%  _|9lMQ-cCw!>gW8ae⓬;rY" lk̗DC$c$`T^yRLQhLj~#CE {/N4G۩QE1ӻly\S F-'$'mIZVԹǚ"sKxNѓU+RKdG rd_m'ԏ0ٽӍʿ"N* rR9Ӛ7dicȁRZe&sH=;n&C5Z@D)Ǒ-,~yۖI4#̙!^;('OF@u'5r?B ԏ0NyxFO*=H"we60dIv@ "T^\d+u!h?]c^s.!>/<7 (d{  P.?g*~_h k<ĄϓeAStB4(hjH,'5'㲲!w$P- rC}#1-6ֹk;-K5̛V9ihek\KqYdǗZj,Nk>歿_jN̍Kf:9Q~;('_BDU.ۦCW#\Î3㲍Ⱦ=*}7ȯYW4 'Ko"vZ| KW^Zx'TCw 1q*y?Qd9c0H61#dKG#n!k;-44*摺&VzkNǭdƋw~5 sJn6| i bn<*& nԷíZ f7ԏլId\OHN'%\?Dд׷G4X8\ZRqu=_|?q],n7+KE&MZEvUH[۶P*8WA8ٜy5G܌@"Mp {NkAqCsPbt;a#UorcgxiN]6jnm''٧Yo2;!bC`UU/1q3>EnOZ~a>i'*ź!NLHV [zs(Gf.c|tfTJ|lJ|MCu:g{DŽߙNs8U:GPSҝct4R2Bb.Vg}'+1=%Y«Q.#oµN/>,M䂊 \߫PNh3a{d8c;$s!FS!B<_Zsdd+v5%,VɛGY貲%tX'OƦbT945 uǏa9Y!2caM͗neyG-pnK.2E L1HxўwXJ~PU5>syG ۏsdQGN?:8 Άxl38!@y\q҈X tR0fzypegk44n 49>`!340Ώьy$k*7kB ʝp;ω\m{}QkZ֐ .=ƞGb3=;/<AmK{*Q4O<89 '63 !6mLn5(eύo<7\p&Zn=fG64cd1 'K= ڑO[O;r11,xŮlfWWh4Zr4CxI (|̂9v S q 7'wE#2pC6tgB8ι\r?0qCC~>D<[<;ܾÞFKM$$lfKA-p) ${򖵙epy%{%:Q$yܬcӓfCC;('EjyOK3"O䢣ҍ98*r%y42d9swN6n$ onH깷PPk9T>^F+xyc%db`t{vPؼ=;Z!$sFdJXp[\Xy;@s=rf <;Q4*NSŊX׌ = n0+jMO?q8f1rlG+ŒC= 0Nbp/#3Bxhc/=/PR6mZw_;~QJRr~ƛZblN 5Yf{ ]M-'ƨqaX/;pie8Cb[WpIs@╤]RfiRrX幇?c,E#)V)\Gs/ 9146LN>!{+voz$mu0Y>2Ey2iۋMS%_tmflӭKEFO&?}W4"'G¥:2漌|\Ll,$H'873J{ffW/.4I䙸*\(^7'.W5c`aV^F9@KE]ke7$cpId&dnMTC FIٍLJ4wsb`Rm%&RQFYr2g'0 sD-ПUՐACƶ,pc;W97*2O jdQ!>sbkزĜ/\Gd%\l.~FX-T>PxD>atHDI]=,Zȓ:Z$IYܯZ)q.)J"Y uAx։D}@n Hs 8pZuzZ''+#&l;3sB+0bb6۫ŀqUS[vH )i֘<*cB4R򦟢q;Fۭ!轨Vt$F6ҿ :3;Lȿ0yg# wyfgT#VsXNr^҉~dG1{8SoU^=k,ziP'{x9#d-ջL^?ZǎҖ;RVnQ>{Tb`Z+cYݵv1t49RQeʗh46}5-qumz3ɘg;WviDYQaq8 -BHlv9ƣGj"눒k3avSkٰ1szYz9xywr̆#b'Hk%r^Z{ooIWKd\{5dV]RV4'a጗;˃19|mL)B2vcsDI3_+ZU4Z[-W1xyGyzC.j;s\[` A[lY&=GkKo &kycFDFbꖉpi]s#o5ZKSrk#,nhLs5bpw5AQXػ\]Pfl?tIq #$K "aloiVop+Kxu_n/|MѰ )TpZ$dq8\cLdч \eG| /!2l+'U5G}YY.eR"&i3},,tљ$QY-|kJatg/΂؞ݱֻp[oMDRwp6.,2(91Ǹ49qoQA{ؕ?SE4̈́$R/i@Y_ݤʆ%:9H@E _`FU@%ق?cLg\K$@5,t8 a$ cJ#IU/(:kXnzQoZxϻʾ/8RňFfݠ!?kOe_kSeBT~NI9qs^NAkZ_ {AxC9?Yr!a)WJ5?Yyvk%8sZ#BjUUfgv/ nR5"NG'*, "bciΣ~0-@4Dr7HJ J)Xǹxcv&ā]3#k{矴B {Zr&(c {kf۫Ɇ['\־Cm7j,_3 1i ˉ0=?teþ4;C{Y6`6i"i,bȗjϫWC۹Q߽?,`{$͋gE;d,nISZ'H#=v84W(|-$3$Z F4pn ʱleG&LRW|ǹֲx3 i9$͆G-lo<5 c^u\VKKk؜< |fx!"&vSsirJRڋbGC!sY&T9ŏ2B#hշ͛qy>ZnRxb$ ǁ[m SR\ TcR&g)]5 >QCYwC_],x1X?(:YKb 6 ڼz1N.ojZt۝''lGB64SzٿL6 %"ȱ#|z|q'PMl<qCd |ИKD|+jZzt׏iG+E#Z=OP콟[oPIY^9}1!9,s,.VuB!Qqkj ̭cj~bFfS.DN 6U\I=Q3y3msċ8r^\t'A W,o3)%-Y9xm Ă\QwRrH?(l'}-{$F@ |RvbTwV< 3?$ftPok=*H{U< {󬛈#!<|LG/hjSzJcYkurU]KgENFX Ƽ^2@ko)Gm\?nG1aO͈Y cqp/ZB[KsٖF ~v)XT4UmT=} \F8\#2lr!E<|u$ȋt]EdGIPtWAm!JM>%kDH?uU$&GՈ(И8H 4'EӢS ">fXTPFm"HK# ýqHa“$֥9P}%,%FJB :"GBm(OU c@wL+ZV@m ǥERC%ҕQΑn4ޕ Ls䢉Ȋ|xCƼ?vbCa͓?mq:kЉ\yC0Ck+5 :Y݄ Cmkԕ9G' 1dĵ.(;.F,SSڵb3s.c9kZS˼ptu,x'VHA(ׯ_Z,02n}hǚ7uZpuuOK|Qŏ.R/oQ H-ζy;i^qWn̉%DLI; j-]6u :h11~%7oX\KĩD 4UvȑQdzںƽ{̗y`uuºNqKB||>$iC6?2YO3lŃݴ O^Qo!ߓeff&h2 -ѶJ w=p[&pkydpqey .z=VޑQYJfXnZX#INxGwZ#ƉߝR56, ۹T_ :sOwGMԿҏ ooҽCƝzki!i&<{&f\ܿ-aC475k go*mptX\`cXNz{AakZ]o]L 3/|R}+̵Urƶ.'=]nNc! Kºʏ.j`u{Z6=|]I yWDDO?_qaƷ3vy1#NccfvI{7!GZ;8|GB'1$%8!'mEx>\x}(HG2d?kMbmqRzRFdIϔ;'\w:a;Y z9\!֢av[ô&C[Zݐ봂G*UZ;GjTn)19.5YIKY,%UX4kKѩ^KĈÏ+&sb <6ڊf3ۚ9ID BfN}I7f\jK[ sE͙҅zY_%w&,6\Z% [צﺼOM׸g$o2 Gҙxס X34tE/x80=<&dD@to(^idjٛ2l@dnivQ uFfWm("ㄋFmv3DATc5 *T=rSaIK[y"էә(JBw^"cBizHr|6D`Py>#2yy\,Տ9͍Ė+tsܒyxK …̚X;Y\>m}[yGdrrs&.5^\Fqm-u wp`e1-ă5Ƌk;OtaZ'tU#K!pBYZ,U*2B~ʤIw UCdwHMRB6Ȫ UATE_HxRL@\I8UP-PS"'ʁ6x^JrJ{GT괆5W[}D#D0Ҡ /%t: SJ#4uZt9 ֚DI \8ۯ“@KC%)mKR=SSB8e?mr D+ԥy[ƈbWmhuލVu% |D)!| F;z-snGҗ]uI|]~-|eC zESHs(.x@*mUa┺"$q!QI weJ8;fq č$88:ǽXS\.jjH#+#%LJ@sM׾-.WWmxvM0ъFc*5"V2}N-ڡ=<Y,mdo3G#Q] A&WL\\%Z AO:3Nᠵu*ynʒX!#\s">9`+o]Kq׆HS`i,pwJzd= ^_wyHĮӭ{B,EPN.**J|G'3Gf3RP߫T#c/iOpX~n{ CDWctGn:ߚ\kJזlk̴\^}GSJ6([EϷ휜X`dy9=KA}G*jkqP KT;_8=c+˥Ǎh.'zn+pֹ[#KvpEW uB2&_@+}Z[i^SKh^FLGc$l0:r4> ߊf[q0qFĸ>&rlߩ+K偔+;%*} |h%Sv4͘? cL-&i vML*Δ_?p޾>^;ZU ͽVTumt5onJl7 e\;h7R޳\RW>,˂s ]LW S /ѷvD~)!Z_qA̫d^nV=h/g':N%;W6v1^bc<_*Ykk_Y6Po3n-ֺ KrJ!qݽH p+-2,\(%ۆ  ݜՒȲ33 qI,('POʧB\׸Fw8 xCQW r( sּP(%nmj_{qJ,=$,abti*<'?-]#xs\MpoY+ɷY_imڙpW8Bu -bԾ'r?*Ɗh3#ȖA磏?w=sT(t=*r8['fV L|8w[}UmM3UftNv^6hIY#! T+J*TxC=ƞH 9.% t25^mG e+rKW[G dLAumMKfSv#jT@d84YZi B4uiB*҅*JhFE%դK"bP~ݪx9pǭ_t[x%) B:Ё@逍h .*mM)Ի1 ,w E &25#1wO P =h5^2>PxkSz[4CQ@&tRɬ- lғCD[T .C 3BBYji]iܙ49Aq'F]K#쒑|dΘN7F8] JT;6[ml$Dip wߢjX&];t6f=|Bv|+ҷu\Qv\T_?9#39< NlZR\J/J0[r_/`?\T,̌丱CFOHN+%~F>LD7lTPY <'۱e2faCk)@Oe)'Yrܿ|]75Pf \Jݺ# <"n=,}gyd9Hkuq+QZ#36R~HϺr1:oI+MDj~Wna{2_a}=7\UC[۷zF_.~[a@knuRRuH8]h{ lE5{ꥼqFw1G~lٽ\zݭX7ꛉ/Hʰ<(V !2;PIȲg!IkYݷ4* ).s^縬yrZ#ƆB(ЅnM+n]sÓ>ʽkSeD\CcYr19CƵz.r7%#,ۥj3ŕ^{&lH֔֫D3qCG8-e;ܨ;(4?Ơ!'7Kܣ;u qJi{o OH/x v'`:.:"M}5,"v*Mo56&76K+ fJWrFcERI8V+38"uZR䃻|t[kJ~zZ[vR5<Lds7>VE=3wiڌ17oGJ~g?yr39k|c؄Fsmaiutn)M\V]p{sYqq Uܠs,ê˔8Xw[ M@%Z1u|ajvmVE)˕aC%0nҡcok6CUŎq92EO]us%ϓ l~&!<#^OSZ~ƏFr9)ʤkKa~!fzVבﹸf.&s&C=VUwg.7z4Φ;|y,F28,dnto**g;؏>48i^8Y yX|áiֳ I&QEq|hY{v…4 kɵsѓRť_*{8/'Vf׵k}-P;PT85ٝ&y9c9\`BlkthqK.l^,t_GeR]/Jn\YR5O92Et:tZNK;%2.|.Y8YKAc1ZLፄ4u-Y*4D3q;n&FHo7HֵKY/r޺aHvRMF)[2 z8P=':+i,/x|wq{w:cUoM'Ϲ9N 4ec@يTQڮ}i15^ᥐW/Ѱky ]1VQ_.@fP1I&}:4u:zb[e'½ ] \D<<};MgqV,j5V&LlqwjVtop6=G+  KN]o varC~CjcZ'Ѷ}v^Gu=kh)\PD)PuTM!6GMץh@|H+E*1jDt[Hc @M [ /} o]t뭨h5$JbH=]LE~b  ,`  G_JCB=&0GZ@ Gyty hE<| .!ʥTc#ր 괨2t *zRDH:RbE-G4u$)Yi`o`c:>b9Cʶ63.wneXs Й G!I}.v. ɖpb|A*{RW)t'>Al\&\#G4iANWS&;j2e9c9aacH+8^Áse~:><~fr3 "jj*MͽˍU%Z}_S|YyJS$.i&xWmJ Ŀj I|+CqY pPWljm4z~?ɶ7eo h/wmUkl~:[D'](foW/2WR\1x9Be,;\d-@ MT%qFP˓(dw!5 ZVq9?DZqs{7㕆v 'ߋ+{9A ]fb}{WG{T㵸^ v4qFm檤$c~^dxC$xk+k4zihl}3e_1% i#"evnp D̴?̖ 99 {J+f jy4L__:m7ׂlmFЮtK%/eY.6sT|6Zq3{ui\akݼ'ʡ<ʓl[qk^^8 GmY]r#DpqO*o!OG7x^zn?Od1;7㰰"nD,h`k}ԵRMTî^JZk<0Liz,'7yu4W!/U.8n2Y[w %+Sp>卥kŽg&)ydO,N&vIcnjJkg!,;7!>+]hOJ2'`!?C[#&#koLLw]H~4FO}M4&_Wg*$T SksՎgnǨ\J/5̽Y3yB^>i1Ѣ]:pi%}uKlÇ@I\PwNW)dwHsYT#{A^ĺa|AֆCn +uLbsKԨB 2"?O“UB=OὌ]\G8NI7X ywS`}Lllj_YCawd"Mc3$Iu*A֦w/}=dnR0Yf_-8̑ZzS\MԩuGJ+!O <.NG4d2sX@.+73G^yrĵAqp2?^j? ޭ[\|\rk}R|q,DDyrr` 〼``R:Zq>rre0Ysp0ɻ.P.մ(u[Ḻ< p%us;FTeJ6Y{c#?<\_$Z时hU߬Wu-OK+>|^{KsLdЂkO³~0}keRީQ,Ge-;*itruZL:NqpjJ;+H5xcqNmJGD NSkS]W:*h-#!@҃9i#Ƙ^SBb5$@ۄ@ TԳD+?ZB9T:0XrzP3v Okp `$ ֘2~: E* LH,,pz ]V-4.#^ 搖hDEBuҘhmA"#a\):j0ߨYM|8\l[S;HWh_(*B {JHdqUeQ4'L%u ;GAAHqxƸ8 55ցkB褔@ (:@ q"W c=$Ѷ5+uΩO k@n.!c% ^[Tرpq :-&ZC;rԌ6n:b Ҁ>(k@E* t$ޚ,h֙ E6] @P07=O~>&^Ȕ/P!ЏƘ;DB j_SFATT!Q(7]V4EC E([v*"Ɛ^ƙ#H;(O @K *E Cn p5nn)2 utJh1TL+@3\aJE\+USgv2)q@I@u}cBAC@P0Ԇ/tP Mƺ!O:+Ԉ,LIEm)71A0h=4ȈZP6G~曩jw&&h*l~TgcZOkĉGXXƤXUD`Sh10aojdPr5t=AF dy||ihHŮQ,T"Rs J8T wLoHOaL̾JE!5tpF"h@ dIڝEAhhNxLcJ$As֑@Ct1\@-t_$ *-zd5u'ƑgX @:=. +Ҷ+jUŬ@؀b>T:ut$b:}!!ihF*Z􆀾3(kL4GSo Z40P} !j1F!p}"R:U""zu=1H pGo KI/^HE9 Y櫺|* H{o  sB hVo@o~"T @CmujQcөJb/@=NM1% EVL8)1' iq sM0 #TFܖ{4 ԇi+};(|R E4@@rt`@0nsD&4*m@%Hѣ!@|0 W)tHd A@4:Cd]<ʊGH;nij  *R^,2ȅ<:P4 h+đUfCڙ Y"Ht7 ?UI bu@vNZE{CtS%WKCvNԐ k~0sڦ9BVĉ0}Nrh zC`\L6RJC078SO[(F\{@τ[fPVJ" EBB4Dn-?J]hx*aIx4MhF1@_IOdxrGr4Q@V'uK ZDwjFF\)T4F.Ж @ [j:L4u2SLLIAwCMԅA[PiE$^-KHTb6P:vft;Qi :E0nkB,~G-zPe!,OkG-YM!ԱfE>e:T h{S)p"O d JkH !-.6F CCc |mH|(({u j JABF[HcCrO DƁ1\Geb5p@|>t)nS! =}&PԚ"3KFD1Tj$Xl[lHwi׽ahMړҡ$ɂ2_)ł?VLhsH(1Mʁq[~@\ hu Н(Ch'vSH]^) ZIcQǵ1ݨ:贆6脐jZxP!%zI*tLh)f؎ [cv oo! t S@cȺwPiڀ\T(0@ sb@Jb W ^ӧƐ´{"! @Tr/ Jn:()!N61hNޙ,dmihMP # #O0a!)2!z e$:WeǴ@@]5%k7e֐lqi!R@ҘZdd_J1phth ,Må8HdN."I; s>v~GS$z1_#:h;F!`xbTC&l 4Ӎ D j|iKMR@:xY(cDdyoU4&DNU#Jd$ Zd2siԳD~3ýsq@|:ΠU-RCqG FJ|1eSKRf ЋBc׸*-xz)Chq%h,&⦈Ѝ4nwNZ4cTTRaZ؆BM#AȷLM]֯f=F'BPfP t=+R)0KǯHlCATHҨ/so;S4 !7A.KIOS4-54 fIs =~ĠhV%ktZ]ɥQ3#k@m. i`#Ҁ`5B[€@I:* !G€CjGe[]iǢJ iTF ^^ RE0J1OmMl۹c^d24[ \ @p.${'A7`4_CLCeܗ K5-7Zc[JOhjEtivomoM @7LcsAA>4%G7 Ȗo(){H75ucJi1 EzC;҆Q(Fe<}@) 1 !ihPjLHduRXX6S1R.k%?mԲA# p@wC^׸| M7OL@ T((;& pZdԃJdOHKvE%.)Cm<*M3) 1;JtU |^}<6.$:|(P Ck]MY'pl<V?mΣHh7UN:~@omˎG2X:[^$9@Psˀ_(_1y:`mhwծ@?@-7i_ROh!V@?}2Njt7N 4z1:;_n~d{ !Κ%w'&8v@>dwi49:H^DbGJ#X2v4`AMM(|) $nz"#9h$YvdP]\ڂ40AΠƁTY1I,Pj@B}E z&U1@  * Z"1E(W(Uת@U> @aX'ΑHk:?qf+YV6#\t)zCEJpn)C wa_dt hHk:I  #EE]m:vN44 :ҙ,Ḑ C8nPF6 Kd4|E"Э'${|i &#H 9 |鉅c߷aYi# 'O hLsdk!yjES)B ^ߧƐ\BAM>u]u)1Й4!HAd+-!P~/ #*!Ӧ vZ2'vT;c&eBH*~G<6 u3ln&M(蘒}րg1-")c~mHa鰀.n.B= **CLw'Sօ!;`rHͪkÞ^qD6 h Zd[PcBP2dQU">WmK n\)sd hA@-P EWptҁZOjYha`  Pu,M>c;A6V AOSqS@,iBKAkQIb mp 1JE!dAC@0AUO e/ʀB@0~4`-oJzR(VyvKLxM|iQ񢪧E|EG9څUMhh ZCAdzDI_Rl4l oLC Rn t`W>Er\ !SdtjM1 @];P!:|( Z,5J 29Hbʀb(A]3WMM&7>B9@%A 5U![plu:ҁPGZLj+‚"@%L6&zYi ~W%zC#K".[M120vlz_ZHRD’O:!d: (C`\H/L;ԓᨦIbO^ћ9˜ RG@mڐ} Vp>w 7zޙ,lrF!j/o H#95S# nhPnMQ#]ҪX DyCu"b4祵H,} ֓)lBw@s榈Lj%tZ$9@؂.HGJzA["Oݠ֝P_׏SP5Mh<T/tPcCa[1T(>X 9M2ZDZ6i [6q${S; Ȁ(60\4 GU",N]QjY>={*,."BA)U@R8n0=hG9v{\~  Ԃ,1½RY#%ۀDJ`E(w'4Jd6)!= t:4= u61E d|TI-SRPړF~2YikJdx>@ѩPl5s2X%9aHb/)u!_׭ @:R &.@7Ē€9"Ǧ@0jwXN dh*"qiK(/P|)U['0'hxuP)4HT.Rdրl wPOcL~sH Qc+AIrXDp(A!e,z4Na?vU*:2X0M/@p_21U(|(DeNp%-m0@7ց1.Iu0wu"f-c>tHh3rJi=hFs{tDGj5 V8-Y РG+Kܥ ƃ彈:(ǕcT,8FTN%a IUL.68}l@yzu0#o:SHL Wޔ@m{SDhOSruCƴ@"A.a]M Y?=4 <Ѕ;TT{SKNn F@jFIAe+I0ᄥ*,]d|h bu_H@B;X (='RlZ[$A sv(-FWzuIh~>5JD M_PIa@:8 .s-}j\hQ Qz(_QOҷ!f*R@1 mN ׁ"iOs\H/Rqb=)84hBsě%Z0K'ʁ3#TEi [TT4k ܇S3G]i2$tSu@xܞR4 ,-jԆ1 R7"#gm[֠Nn#J GCL P AӷO2FpХ ͸PMSQ@o⨟* *)HD6ױaڧz=v"@QLm[} kH^@soqK&kiށ{F@ k #A# ݫStJ~49 i{ޤ4Ӣ"<ipp |h𴸷4|Q K{@u ؝($t$ߡ1[߱!ŠuT( )D ,akI?P}ԊH!$,k#H%tsEͯ@C`+ л$l u>4X|gQ:%R,iXҐpf+hG4G+js\wܧR;Um)XR P1'k=) 2R+"iP CԵ{" nBxPvȎz+HQ߳P1: !5p>0?Mi (T6>7ҁ0K@u|oHhy{==-09 m '& #:|ސTHC?em8Oj̠{uP p *9>R@C)Қ A.sޤ~ {P1@|8k֘1vP+p,! ZztpZ4&CT=LJjdb t0$5tN񽮸* kUS_@| ^RҝP 7UaKK7\GPdƦP)6RC6O_ӥb\߷ꔨ-À7_y%ݺj( l5Mh he d:z@EK$;CGP +n 려P@2;$eP}(ΔGn!0e? b"H6K`B }C-:~b2ߨ1@6ýLCNHGm7AЧz9h M(dRMhDQA@R1,n7cz[ק@I@OLB?Une@>]iP>+ZlH;Bˡ4NƐƀMnh@1$AS@rޙ58>ɡMz*SBu64m춦HX!RhT j@#@ u趠`roS1lkڀՕHzH!RWpݻS5!Dq8Ii sGS^ rҺtryPL&:ʩ@%u2;۪XGJIH cL~>:ߒS:Ygh:&R2XV9M(k]F bL.;l540CwP(^;˶-2XbHH<(րfK7M;Sy8Cߎw:0F| : 3,^T?~#[OƠIcFJ}-Kuߋ: v0̉6 G>E.=t_Q[ު:?e87ցV/Mi׽ZA'R.⁈wtK;R, 1$+nAƀnb!FktLAnSkҐ I|6;_ZCpvܤGLG4@P.=i hHi6ƀ+Z*Ip]M~s_ (/j k_HpZb48;xPkUN {])3b{Gt$X_igoq@#ۺDnxb6A$25wҐc6å678{(_W@  %Nӽ1yAE@ڇNT'e Qu41J  t u^ uրCO~ЂBN*R +IҐ9r*b;*W}(I/PzS%2*tDI ښXq:ӓ %삤D ~ SAjZ@Aҁi O"LN { * L{%M0c @@iU@ 'ށi~sJ(Dsc|rI?eu*(O a>_*X4B2Ep4P'Kӭ9]"\m)yڋt*#Cå*0e TSL(Wy*Iڛ#79P[fťt#NiI @k|Pu BuA7 HhyPGpai?ů蔊]~|(`LDCBF%,E+kdЊC`KZL4$;M)P.Ƙ+6:FWҁG@uޘh"Xu4g+>l%?h(!i%@'ƀU>"9,(փ*o!oK/nԆ+cݠPm4K+ @ú™, 㧅1kP C /@-]v4 G$ހ㸞蝩0WC@|M":vyMaHʷk@&,|Pޘl.>WR~~! 3NJ\@ȁix=Hg G@Ƒ<) JG^ h .$(P~#z95:-@IRT˃$`A|(eDqrݶ) kk(7[=mEbĪQt )Bn4ИXwKꝨ_FӪ$6L݄S'4XydrAn:P zk%qPP'A{ijCAZ1t Pz'1 uh|*F)aUi0q=!> aLKPt65kQA)Pv+{ hP׾e[ wOC$=/C@v;̏KG$1!m> YuJ#ޣ@. s\ OUE RSR ￯Ƙ"|($PET Li1:ӨOAh ;@tR@ 7B֠E7@wI$t=9|ք)tܦ(DfȖ::# -9e>#!$5jbr~iMuK$4קjLqnVHjNc[*) ~_ dʃoCC%olFE6HHj/41ZTґDyNE2A:{_ìҝBCcڃeW7m[R? =TShzx@n/PPxd!,) sm>u@67ځPn¶ $^}4H8~T`oTCHۭ/UCwP \*xӠ u1]P!B'b=?K08<h  :N@J|) R/C@u*z'kJ8!Qo !P<ͻN5K"X )u u@GoLZށ-[P!cB|(GD:_f7 )0sK/H`nB2Y \)}Lp@_!@/Ha] +tE :t 9 k%A?A@lgTQePvB#qӯzbO!׿A@:Q ?uiz6XxRmå;U.(juPlF#/pT hoEX(,M$}4N, GLkP4?eHbeN& [|#]'k~P+hSt ۟:hGJn:55@ knTw ;G1ހ;)3Ti{$2ڒHCRQ PHq(z|s\74jJѵ)?P_Eˑgq& `HăC0)Czld" GN5q6)뀠(IQ@xՃq?tpӥ %%])R(\9b Ϝ&6ꩯAq@(!h.1qMRE!z-Poh]~" +eZ|JdkOE!EB Jpy..7(-Z[(9$xvN`s,AzC.KZD(c+t“'E{u($(M4+N Qǵ n0(uhD:B饩 #zǢ D)e nKjs0iAHrMƩ4BF-08cF^'@T>X' 3 AКE!uExP֗nWB9w LL~KZlZu1zP9p e€8 >@ oxԒR/Wm[4XP"+K|zP& 5ƙ#~=N׷@_9,zSvP̄|P>swKP($ҁ0@:`@;w~5րc\`@wRJw?,@j>43T*)C@O}5 p(6O@W 5!tFS"Cr5b];8"h&@Di!4T*{P8AKؔg~{F5ץG7bdgMM2t@Vi -PPA>a~@&'Ce: IGC@!]%#J˨@% 9I@h&`;'OCmA;@0$$iOU,$ѶLr\ȊYǷZdƁs_ n-@ `t4+(7"/1զh 6=:i֙,p:@UN Hd>3C) l*{bKOL47(Djhcl@PssBx S:X@48kZC >klO9qp=lLCni Vc\M@ \r%vPo0U#܇q'>4=ʊF t-D*CH ]@z|;Dr"ƀWցu@ܽ@1 bdR:'2D%j#B!?r#JC6 =&ݾC54@rӭ4&/snh`` oKށjDm\R>g )ׯz`F{G]N K"P&4]u/LHroqڀK0)NƐ5pj:"ݥj>+MPD!=4}$/}h7 cH {a$5'1k!PӮHcSE]L=?ObƘ8#4Nl m,t:xF{HcJ΁hý05ttAY])@g|hGt~szO€>HE ~t uM>tW. dCӾ`G_+tAB])-Ӧ|%Gïʀ_-i:G4a#) n4W˜A@?tҀ5@ƟENe!G~f_H4C'~?RQ_7_>4cFfqhN|hL_H$I_PP'ud#p_&7~?RJ!Z@tZhM ϡkI~##~t t >T zP[=j?U ?4ZCG;:|eWL xN3'CMh#?OY?Ҁ>u1B,{RDvte?oƁӦ0:ckƀN ~Wk@Ss?$:~ߕ1gOߍ8j?CCt:PA)^@3>hL??m&?@nz~@#>i>]?sր!:So]:PKHtS1ƔYj(|z2FZ=5@7J >Tw4B;^@ >ZwQ,Zb4g~LvLtAǥ14׮C:=] t@5NX>~1eureka-1.11-source/misc/manage2.fl0000644000175100017510000000421512647061302016261 0ustar aaptedaapted# data file for the Fltk User Interface Designer (fluid) version 1.0300 header_name {.h} code_name {.cxx} widget_class UI_ProjectInfo { label {PROJECT SETUP} callback load_res_callback open xywh {176 215 400 375} type Double visible } { Fl_Choice iwad_name { label {IWAD (Game) file: } callback iwad_callback open xywh {145 25 120 25} down_box BORDER_BOX } {} Fl_Choice port_name { label {Port (Engine) :} callback port_callback open xywh {145 60 120 25} down_box BORDER_BOX } {} Fl_Button {} { label Browse callback browse_callback xywh {285 25 100 25} } Fl_Group {} {open xywh {0 110 410 190} } { Fl_Box {} { label {Resource Wads:} xywh {15 110 185 35} align 20 } Fl_Output {res[0]} { label {1. } xywh {55 145 205 25} } Fl_Output {res[1]} { label {2. } xywh {55 180 205 25} } Fl_Output {res[2]} { label {3. } xywh {55 215 205 25} } Fl_Output {res[3]} { label {4. } xywh {55 250 205 25} } Fl_Button {} { label x callback kill_callback xywh {270 145 30 25} labelsize 20 } Fl_Button {} { label x callback kill_callback xywh {270 180 30 25} labelsize 20 } Fl_Button {} { label x callback kill_callback xywh {270 215 30 25} labelsize 20 } Fl_Button {} { label x callback kill_callback xywh {270 250 30 25} labelsize 20 } Fl_Button {} { label Load callback load_callback xywh {315 145 75 25} } Fl_Button {} { label Load callback load_callback xywh {315 180 75 25} } Fl_Button {} { label Load callback load_callback xywh {315 215 75 25} } Fl_Button {} { label Load callback load_callback xywh {315 250 75 25} } } Fl_Group {} {open xywh {0 315 400 60} box FLAT_BOX color 18 } { Fl_Button cancel { label Cancel callback close_callback selected xywh {165 330 80 35} } Fl_Button ok_but { label Use callback apply_callback xywh {290 330 80 35} labelfont 1 } } } eureka-1.11-source/misc/eureka.xpm0000644000175100017510000000325312647061302016427 0ustar aaptedaapted/* XPM */ static char * logo_E4_32x32_xpm[] = { "32 32 33 1", " c None", ". c #310A0C", "+ c #5D0904", "@ c #211B16", "# c #102025", "$ c #002E54", "% c #841606", "& c #1B3A3E", "* c #295258", "= c #C83326", "- c #9E3E3A", "; c #9B4B0E", "> c #5E5E5C", ", c #3A7078", "' c #E14B0E", ") c #816728", "! c #BE5E59", "~ c #8E7577", "{ c #807B68", "] c #FD5D51", "^ c #3F909C", "/ c #678E96", "( c #D7963C", "_ c #62B2C0", ": c #F29A42", "< c #83B1B7", "[ c #FF9B2F", "} c #A9ABA8", "| c #FDB44A", "1 c #79E0EB", "2 c #FFCB51", "3 c #C7E1E9", "4 c #FBE849", " ", " ", " 3<<<<,***,&***,,*##&*#,<> ", " >,&*#&&*&**,*,&&,*,,! ", " @***&@*@,/,>>,,,,,,*- ", " {*****^! .~~~ ~>>- ", " >,,*,,&- ", " >**_#,_= ", " >^&&^^^' ", " >/*_&,^,&@@,&@&% ", " >/_^&_*,,,^^_11] ", " >,,/__&*,1^,,**= ", " >/*,#,1_,,^^^^^% ", " >/*&&#&]%.+-+... ", " >*&&#*^- ", " >*&*,,*- +++++%+ ", " >*^_*$$% |2|:::|' ", " >_*$*)|[ %':::::::' ", " >^{:':|' ':|(((((::|' ", " %2|;|:(:22|||(|||::4[ ", " %|:::(:(((((((:|||[; ", " %|:[::(|||||:||4| ", " %2|||:(:|||224; ", " %2|((((|(:24% ", " %22:[[224( ", " %2|(||4; ", " %2244) ", " 244 ", " )( ", " ", " "}; eureka-1.11-source/misc/pack-source.sh0000755000175100017510000000137312651560605017206 0ustar aaptedaapted#!/bin/bash set -e if [ ! -d glbsp_src ]; then echo "Run this script from the top level." exit 1 fi echo "Creating source package for Eureka..." dest="eureka-X.XX-source" mkdir $dest # # Source code # cp -av Makefile* $dest/ cp -av src $dest/src cp -av osx $dest/osx cp -av glbsp_src $dest/glbsp_src cp -av misc $dest/misc mkdir $dest/obj_linux mkdir $dest/obj_linux/glbsp mkdir $dest/obj_win32 mkdir $dest/obj_win32/glbsp # # Data files # cp -av bindings.cfg $dest cp -av common $dest/common cp -av games $dest/games cp -av ports $dest/ports mkdir $dest/mods # # Documentation # cp -av *.txt $dest cp -av docs $dest/docs cp -av changelogs $dest/changelogs # # all done # echo "------------------------------------" echo "All done." eureka-1.11-source/misc/pack-win32.sh0000755000175100017510000000112612651560543016645 0ustar aaptedaapted#!/bin/bash set -e if [ ! -d glbsp_src ]; then echo "Run this script from the top level." exit 1 fi echo "Creating WIN32 package for Eureka..." dest="Eureka-X.XX" mkdir $dest # # Executable(s) # cp -av Eureka.exe $dest # # Data files # cp -av common $dest/common cp -av games $dest/games cp -av ports $dest/ports mkdir $dest/mods cp -av bindings.cfg $dest cp -av misc/about_logo.png $dest/common # # Documentation # cp -av *.txt $dest rm $dest/INSTALL.txt # # all done # echo "------------------------------------" echo "zip -l -r eureka-XXX-win.zip Eureka-X.XX" echo "" eureka-1.11-source/misc/eureka.60000644000175100017510000001053212651552023015766 0ustar aaptedaapted.\" -*-nroff-*- .TH EUREKA "6" "January 2016" .SH NAME Eureka \- a DOOM map editor .SH SYNOPSIS .B eureka .RI "[" FILE "...]" .RI "[" OPTION "...]" .SH DESCRIPTION Eureka is a cross-platform map editor for the classic DOOM games. It features multiple-level undo and redo, a 3D preview, texture and thing browsers, a built-in nodes builder, panels for directly editing the properties of map objects, a flexible key binding system, and low system requirements (e.g. a 3D card is .I not required). .SH OPTIONS Note that long options are shown here with two dashes, but may also be used with a single dash for compatibility with the original DOOM binary and various source ports. .TP .BI "\-f, \-\-file" " ..." Wad file(s) to edit. This is mainly for compatibility with DOOM command-line syntax, since filenames are more easily provided without this option (i.e. directly after the program name). When no file is specified, Eureka will open the first map in the IWAD (game wad). .TP .BI "\-w, \-\-warp" " " Level to edit. This can be the full map name, e.g. "MAP12" or "E3M7", but can also be a single number like "12" or "37", or two separate numbers like "3 7" for compatibility with DOOM 1 and Ultimate DOOM. When absent, the first level found in the edited wad is used. .TP .BI "\-i, \-\-iwad" " " The name of the IWAD (game data). This also determines which game the map is for, e.g. "doom.wad" will mean the map is for DOOM 1, whereas "heretic.wad" will mean we are editing for the game Heretic. .TP .BI "\-m, \-\-merge" " ..." Resource file(s) to load. These can be wad files containing textures, flats, sprites (etc) but can also be Eureka definitions files (with ".ugh" extension). .TP .BI "\-p, \-\-port" " " Port (engine) name. The default port is "boom", but some other supported ports are "vanilla" (the original EXE), "odamex", "edge" and "legacy". .TP .B \-h, \-\-help Show usage summary .TP .B \-v, \-\-version Show the version .TP .B \-d, \-\-debug Enable debugging messages .TP .B \-q, \-\-quiet Quiet mode (no messages on stdout) .SH CONFIGURATION OPTIONS The following options control how Eureka finds some important files and directories. They are not particular useful per se, but may be needed for special circumstances. .TP .BI "\-\-install" " " The installation directory where game definition files, default key bindings, etc are stored. This defaults to .I $PREFIX/share/eureka (see FILES section below...) Specifying "." for the current directory is useful when testing a locally compiled version without doing "make install". In fact Eureka will try it automatically when it cannot find its normal installation directory. .TP .BI "\-\-home" " " The home directory where user settings, backups, etc are stored. This defaults to the .I "~/.eureka" directory. .TP .BI "\-\-log" " " File where all log messages are written. Defaults to "logs.txt" under the home directory. .TP .BI "\-\-config" " " The config file which stores the general user settings (but not key bindings). This file will loaded during startup, and also saved to when the user uses the Preferences dialog. .SH FILES .TP .I "$PREFIX/share/eureka/ The installation directory for Eureka. PREFIX is typically /usr or /usr/local, depending on how Eureka was installed. This directory contains the standard key bindings, plus all the definition files (with .ugh extension) for the supported games, ports and mods. .TP .I "~/.eureka/config.cfg" Contains user settings .TP .I "~/.eureka/bindings.cfg" Contains user key bindings .TP .I "~/.eureka/logs.txt" The logs from the previous session of Eureka, or the current one if Eureka is currently running. .TP .I "~/.eureka/backups" Whenever a file is saved, Eureka makes a backup of the existing file and stores it here, in a directory based on the filename. Multiple backups are made, upto a configurable limit on number and total size of the files. If something goes awry with your wad, look here! .TP .I "~/.eureka/iwads" IWAD files can be placed here and Eureka will find them automatically .SH "ENVIRONMENT" .TP .BI DOOMWADDIR If set, contains a single directory name where Eureka will look for IWADs. .TP .BI DOOMWADPATH If set, contains a colon-separated list of directories where Eureka will look for IWADs. .SH "SEE ALSO" .BR glbsp (6), .BR prboom (6), .BR deutex (6), .BR xwadtools (6) .PP Eureka site: http://eureka-editor.sourceforge.net/ eureka-1.11-source/misc/up_syntax.vim0000644000175100017510000000470012647061302017172 0ustar aaptedaapted" Vim syntax file " For version 5.x: Clear all syntax items " For version 6.x: Quit when a syntax file was already loaded if version < 600 syntax clear elseif exists("b:current_syntax") finish endif syn sync lines=250 syn keyword upConstant true false nil syn keyword upConditional if else syn keyword upStatement return syn keyword upRepeat while repeat until for syn keyword upStruct class syn keyword upStorage forward builtin syn keyword upType float vector string function void syn keyword upType linedef sidedef sector thing vertex set syn keyword upTodo contained TODO FIXME DEBUG NOTE WISH OPTIMIZE OPTIMISE " strings syn match upSpecial contained "\\[\\abfnrtv\'\"]\|\\\d\{,3}" syn region upString start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=upSpecial " syn match upIdentifier "\<[a-zA-Z_][a-zA-Z0-9_]*\>" syn match upDefine "\<[a-zA-Z_][a-zA-Z0-9_]*\>\s*\(:=\)\@=" syn region upFrame start="[$]frame" end="$" keepend syn match upNumber "-\=\<\d\+\>" syn match upFloat "-\=\<\d\+\.\d\+\>" syn match upFloat "-\=\<\d\+\.\d\+[eE]-\=\d\+\>" syn match upHexNumber "0[xX][0-9a-fA-F]\+\>" syn region upComment start="//" skip="\\$" end="$" keepend contains=upTodo syn region upComment start="/\*" end="\*/" contains=upTodo extend syn match upState "\(=\)\@<=\s*\[[^]]*,[^]]*\]" if !exists("ec_no_functions") " entity functions syn keyword upFunction spawn remove " math functions syn keyword upFunction random endif " Define the default highlighting. " For version 5.7 and earlier: only when not done already " For version 5.8 and later: only when an item doesn't have highlighting yet if version >= 508 || !exists("did_ec_syn_inits") if version < 508 let did_ec_syn_inits = 1 command -nargs=+ HiLink hi link else command -nargs=+ HiLink hi def link endif HiLink upBoolean Boolean HiLink upComment Comment HiLink upConditional Conditional HiLink upConstant Constant HiLink upDefine Special HiLink upFrame Special HiLink upFunction Function HiLink upLabel Label HiLink upNumber Number HiLink upFloat Float HiLink upRepeat Repeat HiLink upStatement Statement HiLink upStorage StorageClass HiLink upString String HiLink upStruct upStatement HiLink upTodo Todo HiLink upType Type HiLink upSpecial SpecialChar HiLink upState Special HiLink upError Error delcommand HiLink endif let b:current_syntax = "up" " vim: ts=4 sw=4 noexpandtab eureka-1.11-source/misc/New_Workflow.txt0000644000175100017510000000266212647061302017614 0ustar aaptedaapted WORKFLOW DIFFERENCES TO YADEX ----------------------------- (TODO: move this stuff to documentation) 1. can "draw" linedefs in VERTEX mode by pressing SPACE. can start in a blank spot or highlight a vertex to start at. after first vertex is selected, press SPACE again in a blank spot to add a new vertex and a new linedef to that vertex. can continue doing this until pressing SPACE on an existing vertex, which will finish the line drawing. If the last line creates a loop, a new sector will be added as well. 2. can insert a vertex on an orange highlighted linedef, causing that linedef to be split by the new vertex. 3. can drag a vertex onto an orange highlighted linedef and that linedef is automatically split by the dragged vertex. 4. can delete a vertex which is connected to TWO linedefs and those linedefs are merged into one. 5. can drag a vertex onto an existing vertex and the two vertices are automatically merged into one. plus, if the two vertices were the opposite ends of a linedef then that linedef is automatically deleted. 6. can split a sector by just adding one or more linedefs from one side of the sector to the another. 7. in SECTOR mode, can position the mouse pointer inside an sectorless area and press SPACE to insert a new sector. 8. in SECTOR mode, the SPACE key will "correct" an existing sector (which currently must be highlighted when pressing SPACE). eureka-1.11-source/misc/prefs2.fl0000644000175100017510000001337012647061302016152 0ustar aaptedaapted# data file for the Fltk User Interface Designer (fluid) version 1.0302 header_name {.h} code_name {.cxx} widget_class UI_Preferences { label PREFERENCES open xywh {376 124 600 500} type Double color 18 visible } { Fl_Tabs tabs {open xywh {0 0 590 435} } { Fl_Group {} { label { General } open xywh {0 25 590 405} labelsize 16 hide } { Fl_Box {} { label {GUI Appearance} xywh {25 50 145 30} labelfont 1 align 20 } Fl_Group {} { xywh {45 90 250 115} } { Fl_Round_Button theme_FLTK { label { FLTK theme} xywh {50 90 150 25} type Radio down_box ROUND_DOWN_BOX } Fl_Round_Button theme_GTK { label { GTK+ theme } xywh {50 120 150 25} type Radio down_box ROUND_DOWN_BOX } Fl_Round_Button theme_plastic { label { plastic theme } xywh {50 150 165 25} type Radio down_box ROUND_DOWN_BOX } } Fl_Group {} { xywh {220 90 190 90} } { Fl_Round_Button cols_default { label {default colors} xywh {245 90 135 25} type Radio down_box ROUND_DOWN_BOX } Fl_Round_Button cols_bright { label {bright colors} xywh {245 120 140 25} type Radio down_box ROUND_DOWN_BOX } Fl_Round_Button cols_custom { label {custom colors ---->} xywh {245 150 165 25} type Radio down_box ROUND_DOWN_BOX } } Fl_Group {} { xywh {385 80 205 100} color 50 align 22 } { Fl_Button bg_colorbox { label background xywh {430 90 45 25} box BORDER_BOX align 8 } Fl_Button ig_colorbox { label {input bg} xywh {430 120 45 25} box BORDER_BOX color 7 align 8 } Fl_Button fg_colorbox { label {text color} xywh {430 150 45 25} box BORDER_BOX color 32 align 8 } } Fl_Box {} { label {Map Grid and Scrolling} xywh {30 195 195 25} labelfont 1 align 20 } Fl_Check_Button grid_snap { label { default SNAP mode} xywh {50 230 235 25} down_box DOWN_BOX } Fl_Choice grid_size { label {default grid size } open xywh {435 230 85 25} down_box BORDER_BOX } {} Fl_Check_Button gen_digitzoom { label { digit keys zoom the map} xywh {50 265 240 25} down_box DOWN_BOX } Fl_Choice gen_smallscroll { label {small scroll step } open xywh {435 265 85 25} down_box BORDER_BOX } {} Fl_Choice gen_largescroll { label {large scroll step } open xywh {435 300 85 25} down_box BORDER_BOX } {} Fl_Check_Button gen_wheelscroll { label { mouse wheel scrolls the map} xywh {50 300 245 25} down_box DOWN_BOX } Fl_Box {} { label {Other Stuff} xywh {30 340 280 35} labelfont 1 align 20 } Fl_Check_Button gen_escapequit { label { Escape key can Quit the program} xywh {50 380 265 30} down_box DOWN_BOX } } Fl_Group {} { label { Editing } xywh {0 25 585 410} labelsize 16 hide } { Fl_Box {} { label {Editing Options} xywh {25 50 355 30} labelfont 1 align 20 } Fl_Check_Button edit_newislands { label { new islands have void interior} xywh {50 80 265 30} down_box DOWN_BOX } Fl_Check_Button edit_samemode { label { same mode key will clear selection} xywh {50 140 270 30} down_box DOWN_BOX } Fl_Check_Button edit_autoadjustX { label { auto-adjust X offsets} xywh {50 110 260 30} down_box DOWN_BOX } Fl_Check_Button edit_multiselect { label { multi-select requires a modifier key} xywh {50 170 275 30} down_box DOWN_BOX } Fl_Choice edit_modkey { label {----> } open xywh {370 170 95 30} down_box BORDER_BOX } {} Fl_Input edit_sectorsize { label {new sector size:} xywh {440 80 105 25} type Int } } Fl_Group {} { label { glBSP } open xywh {0 25 585 410} selection_color 50 labelsize 16 hide } { Fl_Box {} { label {glBSP Node Building Options} xywh {25 50 280 30} labelfont 1 align 20 } Fl_Check_Button glbsp_warn { label { Show all warning messages} xywh {60 90 220 30} down_box DOWN_BOX } Fl_Check_Button glbsp_verbose { label { Verbose -- show information about each level} xywh {60 120 350 30} down_box DOWN_BOX } Fl_Check_Button glbsp_fast { label { Fast -- build the fastest way, but nodes may not be as good} xywh {60 150 440 30} down_box DOWN_BOX } } Fl_Group {} { label { Keys } open xywh {0 25 585 410} selection_color 50 labelsize 16 } { Fl_Box {} { label {Key Bindings} xywh {10 46 440 29} labelfont 1 align 20 } Fl_Browser {} { xywh {25 116 555 238} type Hold } Fl_Button {} { label Add xywh {50 375 90 35} color 55 } Fl_Button {} { label {Change Key} xywh {290 375 122 35} color 55 } Fl_Button {} { label Edit xywh {175 375 83 35} color 55 } Fl_Button {} { label Remove xywh {440 375 104 35} color 55 } Fl_Button key_group { label Group xywh {25 87 125 28} color 231 align 20 } Fl_Button key_key { label Key xywh {150 87 150 28} color 231 align 20 } Fl_Button key_func { label Function selected xywh {300 87 260 28} color 231 align 20 } } } Fl_Button {} { label OK xywh {460 450 85 35} } } eureka-1.11-source/misc/eureka.rc0000644000175100017510000000220112651120444016215 0ustar aaptedaapted// // --- Eureka Editor --- // // Windows Resources // #define MAIN_MENU 100 #define MAIN_MENU_FILE_EXIT 1001 #define MAIN_ICON 1 MAIN_MENU MENU DISCARDABLE { POPUP "File" { MENUITEM "Exit", MAIN_MENU_FILE_EXIT } } MAIN_ICON ICON "misc/eureka.ico" 1 VERSIONINFO FILEVERSION 4, 1, 11, 0 PRODUCTVERSION 4, 1, 11, 0 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", "Eureka DOOM Editor\0" VALUE "FileVersion", "1.11\0" VALUE "InternalName", "Eureka\0" VALUE "LegalCopyright", "\251 Andrew Apted, GNU General Public License\0" VALUE "OriginalFilename", "Eureka.EXE\0" VALUE "ProductName", "Eureka\0" VALUE "ProductVersion", "1.11\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 0x04B0 END END //--- editor settings --- // vi:ts=2:sw=2:expandtab:filetype=rc eureka-1.11-source/misc/eureka.desktop0000644000175100017510000000046012651552071017274 0ustar aaptedaapted[Desktop Entry] Name=Eureka DOOM Editor GenericName=DOOM Editor Comment=Edit maps for the game DOOM Exec=eureka %f Icon=eureka Terminal=false Type=Application Categories=Game;ActionGame; StartupNotify=false MimeType=application/x-doom-wad; Keywords=doom;heretic;hexen;level;map;wad;editor;builder;yadex;