# HG changeset patch # User Matti Hamalainen # Date 1316569212 -10800 # Node ID db8b4f975bad36794bfe588afe1444372a4192a3 # Parent 7817e13d25eab71e4463ece4cf3c86c70db9d3e2 "Tools" patch by Andrew Apted. Adds a few extra tools to Yadex's repertoire: [w] key splits a sector in vertex mode, [T] key transfers properties (especially sectors), and [Z] key is a very useful feature to change the sector of an area (all surrounding linedefs) either to an existing sector or to a new one. diff -r 7817e13d25ea -r db8b4f975bad src/editloop.cc --- a/src/editloop.cc Wed Sep 21 04:38:23 2011 +0300 +++ b/src/editloop.cc Wed Sep 21 04:40:12 2011 +0300 @@ -1707,7 +1707,15 @@ select_linedefs_path (&e.Selected, e.highlighted.num, YS_TOGGLE); RedrawMap = 1; } - + // [E]: add linedef and split sector -- [AJA] + else if (is.key == 'E' && e.obj_type == OBJ_VERTICES) + { + if (e.Selected) + { + MiscOperations (e.obj_type, &e.Selected, 5); + RedrawMap = 1; + } + } // [E]: Select/unselect all 1s linedefs in path else if (is.key == 'E' && e.highlighted._is_linedef ()) { @@ -1972,6 +1980,17 @@ StretchSelBox = false; } + // [w]: split sector between vertices + else if (is.key == 'w' && e.obj_type == OBJ_VERTICES + && e.Selected && e.Selected->next && ! e.Selected->next->next) + { + SplitSector (e.Selected->next->objnum, e.Selected->objnum); + ForgetSelection (&e.Selected); + RedrawMap = 1; + DragObject = false; + StretchSelBox = false; + } + // [x]: spin things 1/8 turn clockwise else if (is.key == 'x' && e.obj_type == OBJ_THINGS && (e.Selected || e.highlighted ())) @@ -2252,6 +2271,21 @@ RedrawMap = 1; } + // [Z] Set sector on surrounding linedefs (AJA) + else if (is.key == 'Z' && e.pointer_in_window) + { + if (e.obj_type == OBJ_SECTORS && e.Selected) + { + SuperSectorSelector (e.pointer_x, e.pointer_y, + e.Selected->objnum); + } + else + { + SuperSectorSelector (e.pointer_x, e.pointer_y, OBJ_NO_NONE); + } + RedrawMap = 1; + } + // [!] Debug info (not documented) else if (is.key == '!') { @@ -2265,6 +2299,30 @@ RedrawMap = 1; } + // [T] Transfer properties to selected objects (AJA) + else if (is.key == 'T' && e.Selected + && e.highlighted.num >= 0) + { + switch (e.obj_type) + { + case OBJ_SECTORS: + TransferSectorProperties (e.highlighted.num, e.Selected); + RedrawMap = 1; + break; + case OBJ_THINGS: + TransferThingProperties (e.highlighted.num, e.Selected); + RedrawMap = 1; + break; + case OBJ_LINEDEFS: + TransferLinedefProperties (e.highlighted.num, e.Selected); + RedrawMap = 1; + break; + default: + Beep (); + break; + } + } + // [|] Show colours (not documented) else if (is.key == '|') { diff -r 7817e13d25ea -r db8b4f975bad src/l_prop.cc --- a/src/l_prop.cc Wed Sep 21 04:38:23 2011 +0300 +++ b/src/l_prop.cc Wed Sep 21 04:40:12 2011 +0300 @@ -547,3 +547,37 @@ return ((ldtgroup_t *)ptr)->desc; } +/* + * TransferLinedefProperties + * + * Note: right now nothing is done about sidedefs. Being able to + * (intelligently) transfer sidedef properties from source line to + * destination linedefs could be a useful feature -- though it is + * unclear the best way to do it. OTOH not touching sidedefs might + * be useful too. + * + * -AJA- 2001-05-27 + */ +#define LINEDEF_FLAG_KEEP (1 + 4) + +void TransferLinedefProperties (int src_linedef, SelPtr linedefs) +{ + SelPtr cur; + wad_ldflags_t src_flags = LineDefs[src_linedef].flags & ~LINEDEF_FLAG_KEEP; + + for (cur=linedefs; cur; cur=cur->next) + { + if (! is_obj(cur->objnum)) + continue; + + // don't transfer certain flags + LineDefs[cur->objnum].flags &= LINEDEF_FLAG_KEEP; + LineDefs[cur->objnum].flags |= src_flags; + + LineDefs[cur->objnum].type = LineDefs[src_linedef].type; + LineDefs[cur->objnum].tag = LineDefs[src_linedef].tag; + + MadeChanges = 1; + } +} + diff -r 7817e13d25ea -r db8b4f975bad src/s_misc.cc --- a/src/s_misc.cc Wed Sep 21 04:38:23 2011 +0300 +++ b/src/s_misc.cc Wed Sep 21 04:40:12 2011 +0300 @@ -29,11 +29,15 @@ #include "yadex.h" +#include + #include "entry.h" #include "gfx.h" #include "levels.h" #include "objid.h" #include "selectn.h" +#include "objects.h" +#include "dialog.h" /* @@ -179,4 +183,340 @@ MadeChanges = 1; } + +static int find_linedef_for_area (int x, int y, int& side) +{ + int n, m, curx; + int best_match = -1; + + curx = 32767; // Oh yes, one more hard-coded constant! + + for (n = 0; n < NumLineDefs; n++) + if ((Vertices[LineDefs[n].start].y > y) + != (Vertices[LineDefs[n].end].y > y)) + { + int lx0 = Vertices[LineDefs[n].start].x; + int ly0 = Vertices[LineDefs[n].start].y; + int lx1 = Vertices[LineDefs[n].end].x; + int ly1 = Vertices[LineDefs[n].end].y; + m = lx0 + (int) ((long) (y - ly0) * (long) (lx1 - lx0) + / (long) (ly1 - ly0)); + if (m >= x && m < curx) + { + curx = m; + best_match = n; + } + } + + /* now look if this linedef has a sidedef bound to one sector */ + if (best_match < 0) + return OBJ_NO_NONE; + + if (Vertices[LineDefs[best_match].start].y + > Vertices[LineDefs[best_match].end].y) + side = 1; + else + side = 2; + + return best_match; +} + +/* + compute the angle between lines AB and BC, going anticlockwise. + result is in degrees 0 - 359. A, B and C are vertex indices. + -AJA- 2001-05-09 + */ +#define DEBUG_ANGLE 0 + +static double angle_between_linedefs (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; + + if (result >= 360) + result -= 360; + + while (result < 0) + result += 360; + +#if (DEBUG_ANGLE) + fprintf(stderr, "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; +} + +/* + follows the path clockwise from the given start line, adding each + line into the appropriate set. If the path is not closed, zero is + returned. + + -AJA- 2001-05-09 + */ +#define DEBUG_PATH 0 + +static int select_sides_in_closed_path (bitvec_c& ld_side1, + bitvec_c& ld_side2, int line, int side) +{ + int cur_vert, prev_vert, final_vert; + + if (side == 1) + { + ld_side1.set (line); + cur_vert = LineDefs[line].end; + prev_vert = final_vert = LineDefs[line].start; + } + else + { + ld_side2.set (line); + cur_vert = LineDefs[line].start; + prev_vert = final_vert = LineDefs[line].end; + } + +#if (DEBUG_PATH) + fprintf(stderr, "PATH: line %d side %d cur %d final %d\n", + line, side, cur_vert, final_vert); +#endif + + while (cur_vert != final_vert) + { + int next_line = OBJ_NO_NONE; + int next_vert = OBJ_NO_NONE; + int next_side; + double best_angle = 999; + + // Look for the next linedef in the path. It's the linedef that + // uses the current vertex and is not the current one. + + for (int n = 0; n < NumLineDefs; n++) + { + if (n == line) + continue; + + int other_vert; + int which_side; + + if (LineDefs[n].start == cur_vert) + { + other_vert = LineDefs[n].end; + which_side = 1; + } + else if (LineDefs[n].end == cur_vert) + { + other_vert = LineDefs[n].start; + which_side = 2; + } + else + continue; + + // found adjoining linedef + + double angle = angle_between_linedefs (prev_vert, cur_vert, + other_vert); + + if (! is_obj (next_line) || angle < best_angle) + { + next_line = n; + next_vert = other_vert; + next_side = which_side; + + best_angle = angle; + } + + // Continue the search + } + + line = next_line; + side = next_side; + +#if (DEBUG_PATH) + fprintf(stderr, "PATH NEXT: line %d side %d vert %d angle %1.6f\n", + line, side, next_vert, best_angle); +#endif + + // None ? Path cannot be closed + if (! is_obj (line)) + return 0; + + // Line already seen ? Under normal circumstances this won't + // happen, but it _can_ happen and indicates a non-closed + // structure + if (ld_side1.get (line) || ld_side2.get (line)) + return 0; + + if (side == 1) + ld_side1.set (line); + else + ld_side2.set (line); + + prev_vert = cur_vert; + cur_vert = next_vert; + } + +#if (DEBUG_PATH) + fprintf(stderr, "PATH CLOSED !\n"); +#endif + + return 1; +} + +/* + update the side on a single linedef, using the given sector + reference. Will create a new sidedef if necessary. + */ +static void super_set_sector_on_side (int line, wad_sdn_t& side, + wad_sdn_t& other, int side_no, int sector) +{ + if (is_obj (side) && SideDefs[side].sector == sector) + { + // there was no change. + return; + } + + int must_flip = 0; + + if (! is_obj (side)) + { + // 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 (! is_obj (other) && side_no == 2) + must_flip = 1; + + InsertObject (OBJ_SIDEDEFS, OBJ_NO_NONE, 0, 0); + side = NumSideDefs - 1; + + // 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 (is_obj (other)) + { + strncpy (SideDefs[side].tex3, "-", WAD_TEX_NAME); + strncpy (SideDefs[other].tex3, "-", WAD_TEX_NAME); + + LineDefs[line].flags |= 4; // Set the 2S bit + LineDefs[line].flags &= ~1; // Clear the Im bit + } + } + + SideDefs[side].sector = sector; + + if (must_flip) + { + int temp = LineDefs[line].start; + LineDefs[line].start = LineDefs[line].end; + LineDefs[line].end = temp; + + temp = side; + side = other; + other = temp; + } + + MadeChanges = 1; + MadeMapChanges = 1; +} + +static int super_find_sector_model (bitvec_c& ld_side1, + bitvec_c& ld_side2) +{ + for (int line=0; line < NumLineDefs; line++) + { + int side1 = LineDefs[line].sidedef1; + int side2 = LineDefs[line].sidedef2; + + if (ld_side1.get (line)) + if (is_obj (side2)) + return SideDefs[side2].sector; + + if (ld_side2.get (line)) + if (is_obj (side1)) + return SideDefs[side1].sector; + } + + return OBJ_NO_NONE; +} + + +/* + 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. Two basic + operations: (a) set the sidedef sector references to a completely + new sector, or (b) set them to an existing sector. This is + controlled by the `new_sec' parameter. + + -AJA- 2001-05-08 + */ + +void SuperSectorSelector (int map_x, int map_y, int new_sec) +{ + int line, side; + char msg_buf[200]; + + line = find_linedef_for_area (map_x, map_y, side); + + if (! is_obj (line)) + { + Beep (); + sprintf (msg_buf, "Chosen area is not closed"); + Notify (-1, -1, msg_buf, NULL); + return; + } + + bitvec_c ld_side1 (NumLineDefs); + bitvec_c ld_side2 (NumLineDefs); + + int closed = select_sides_in_closed_path (ld_side1, ld_side2, + line, side); + + if (! closed) + { + Beep (); + sprintf (msg_buf, "Area chosen is not closed"); + Notify (-1, -1, msg_buf, NULL); + return; + } + + // -AJA- FIXME: look for "islands", closed linedef paths that lie + // completely inside the area, i.e. not connected to the main path. + // Example: the two pillars at the start of MAP01 of DOOM 2. See + // GetOppositeSector() and the end of SplitSector() for a possible + // algorithm. + + if (! is_obj (new_sec)) + { + int model = super_find_sector_model (ld_side1, ld_side2); + InsertObject (OBJ_SECTORS, model, 0, 0); + new_sec = NumSectors - 1; + } + + for (line=0; line < NumLineDefs; line++) + { + if (ld_side1.get (line)) + super_set_sector_on_side (line, LineDefs[line].sidedef1, + LineDefs[line].sidedef2, 1, new_sec); + + else if (ld_side2.get (line)) + super_set_sector_on_side (line, LineDefs[line].sidedef2, + LineDefs[line].sidedef1, 2, new_sec); + } +} + /* end of file */ diff -r 7817e13d25ea -r db8b4f975bad src/s_prop.cc --- a/src/s_prop.cc Wed Sep 21 04:38:23 2011 +0300 +++ b/src/s_prop.cc Wed Sep 21 04:40:12 2011 +0300 @@ -260,6 +260,35 @@ } /* + * TransferSectorProperties + * + * -AJA- 2001-05-27 + */ +void TransferSectorProperties (int src_sector, SelPtr sectors) +{ + SelPtr cur; + + for (cur=sectors; cur; cur=cur->next) + { + if (! is_obj(cur->objnum)) + continue; + + strncpy (Sectors[cur->objnum].floort, Sectors[src_sector].floort, + WAD_FLAT_NAME); + strncpy (Sectors[cur->objnum].ceilt, Sectors[src_sector].ceilt, + WAD_FLAT_NAME); + + Sectors[cur->objnum].floorh = Sectors[src_sector].floorh; + Sectors[cur->objnum].ceilh = Sectors[src_sector].ceilh; + Sectors[cur->objnum].light = Sectors[src_sector].light; + Sectors[cur->objnum].special = Sectors[src_sector].special; + Sectors[cur->objnum].tag = Sectors[src_sector].tag; + + MadeChanges = 1; + } +} + +/* * InputSectorType * Let the user select a sector type number and return it * Returns 0 if OK, <>0 if cancelled diff -r 7817e13d25ea -r db8b4f975bad src/s_split.cc --- a/src/s_split.cc Wed Sep 21 04:38:23 2011 +0300 +++ b/src/s_split.cc Wed Sep 21 04:40:12 2011 +0300 @@ -36,6 +36,7 @@ #include "s_linedefs.h" #include "selectn.h" #include "x_hover.h" +#include "entry.h" /* diff -r 7817e13d25ea -r db8b4f975bad src/t_prop.cc --- a/src/t_prop.cc Wed Sep 21 04:38:23 2011 +0300 +++ b/src/t_prop.cc Wed Sep 21 04:40:12 2011 +0300 @@ -36,6 +36,8 @@ #include "gfx.h" #include "levels.h" #include "oldmenus.h" +#include "objid.h" +#include "objects.h" #include "selectn.h" #include "things.h" @@ -331,4 +333,30 @@ } +/* + * TransferThingProperties + * + * -AJA- 2001-05-27 + */ +void TransferThingProperties (int src_thing, SelPtr things) +{ + SelPtr cur; + + for (cur=things; cur; cur=cur->next) + { + if (! is_obj(cur->objnum)) + continue; + + Things[cur->objnum].angle = Things[src_thing].angle; + Things[cur->objnum].type = Things[src_thing].type; + Things[cur->objnum].when = Things[src_thing].when; + + MadeChanges = 1; + + things_types++; + things_angles++; + } +} + + /* end of file */ diff -r 7817e13d25ea -r db8b4f975bad src/yadex.h --- a/src/yadex.h Wed Sep 21 04:38:23 2011 +0300 +++ b/src/yadex.h Wed Sep 21 04:40:12 2011 +0300 @@ -479,6 +479,7 @@ // l_prop.cc (previously in editobj.cc) void LinedefProperties (int x0, int y0, SelPtr obj); +void TransferLinedefProperties (int src_linedef, SelPtr linedefs); // l_unlink.cc void unlink_sidedef (SelPtr linedefs, int side1, int side2); @@ -541,13 +542,16 @@ void DistributeSectorCeilings (SelPtr); /* SWAP! */ void RaiseOrLowerSectors (SelPtr obj); void BrightenOrDarkenSectors (SelPtr obj); +void SuperSectorSelector (int map_x, int map_y, int new_sec); // s_prop.cc (previously in editobj.cc) void SectorProperties (int x0, int y0, SelPtr obj); +void TransferSectorProperties (int src_sector, SelPtr sectors); // s_split.cc (previously in objects.cc) void SplitSector (int, int); /* SWAP! */ void SplitLineDefsAndSector (int, int); /* SWAP! */ +void MultiSplitLineDefsAndSector (int, int); /* SWAP! */ // swapmem.cc void InitSwap (void); @@ -560,6 +564,7 @@ // selrect.cc // t_prop.c (previously in editobj.c) void ThingProperties (int x0, int y0, SelPtr obj); +void TransferThingProperties (int src_thing, SelPtr things); // v_merge.cc void DeleteVerticesJoinLineDefs (SelPtr ); /* SWAP! */