summaryrefslogtreecommitdiff
path: root/editline.c
diff options
context:
space:
mode:
Diffstat (limited to 'editline.c')
-rw-r--r--editline.c3322
1 files changed, 3322 insertions, 0 deletions
diff --git a/editline.c b/editline.c
new file mode 100644
index 0000000..1efcb7f
--- /dev/null
+++ b/editline.c
@@ -0,0 +1,3322 @@
+/*
+
+ viDOOM - level editor for DOOM
+
+ Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Editor LINEDEF definitions
+
+*/
+static const char rcs_id[]="$Id$";
+
+#include "config.h"
+#include "globals.h"
+
+#include <math.h>
+#include <ctype.h>
+
+#include "editvar.h"
+#include "sectors.h"
+#include "texture.h"
+
+
+/* ---------------------------------------- MACROS
+*/
+#define LinesCrossV(v1,v2,v3,v4) \
+ LinesCross ((v1)->v.x,(v1)->v.y,(v2)->v.x,(v2)->v.y, \
+ (v3)->v.x,(v3)->v.y,(v4)->v.x,(v4)->v.y)
+
+#define SetPoint(pt,vt) do {(pt).x=(vt)->v.x;(pt).y=(vt)->v.y;} while(0)
+
+#define SPLINE_THRESH 1
+
+/* This following define relies on the naming of parameters in DoCalcSpline()
+ and DoCalcLine()
+*/
+#define CHECKSTEP(X,Y) do { \
+ (*len)++; \
+ \
+ if (p) \
+ if (((*len)%step)==0) \
+ { \
+ if ((*idx)<MAX_STEPS) \
+ { \
+ p[*idx].x=X; \
+ p[*idx].y=Y; \
+ (*idx)++; \
+ } \
+ } \
+ } while(0)
+
+/* ---------------------------------------- STEP CREATION SHARED DATA
+*/
+#define MIN_STEPS 1
+#define MAX_STEPS 128
+
+struct {
+ int x;
+ int y;
+
+ EditLine *from;
+ EditLine *to;
+ int from_c;
+ int to_c;
+ int from_f;
+ int to_f;
+
+ int swap;
+ Point vf[2];
+ Point vt[2];
+
+ int no;
+ double step_f;
+ double step_c;
+ int circular;
+ int side;
+
+ Point p[2][MAX_STEPS+2];
+ } step;
+
+
+/* ---------------------------------------- PRIVATE UTILS
+*/
+static void DrawLinedef(EditLine *l, int col)
+{
+ double dx,dy;
+
+ TRACE;
+
+ dx=((l->v[0]->v.x)-(l->v[1]->v.x))/2;
+ dy=((l->v[0]->v.y)-(l->v[1]->v.y))/2;
+
+ MapLineD(l,col);
+
+ MapLine((int)(l->v[0]->v.x-dx),(int)(l->v[0]->v.y-dy),
+ (int)(l->v[0]->v.x-dx-dy/6),(int)(l->v[0]->v.y-dy+dx/6),col);
+}
+
+
+static int SelColour(int selmode)
+{
+ switch(selmode)
+ {
+ case SELECT_OVER:
+ return(OVERCOL);
+ break;
+ case SELECT_SELECTED:
+ return(SELCOL);
+ break;
+ default:
+ if (edit_mode==SECTOR_MODE)
+ return(SECTCOL);
+ else
+ return(LINECOL);
+ break;
+ }
+}
+
+
+static void RemoveHighlights(List l)
+{
+ Iterator i;
+ Object *o;
+ int *n;
+
+ i=ListIterator(l);
+
+ while(i)
+ {
+ n=IteratorData(i);
+
+ if ((o=MapElem(linedef,*n)))
+ DrawLinedef(o->data,SelColour(o->select));
+
+ i=IteratorNext(i);
+ }
+}
+
+
+static void LineSelectionCentre(int *x,int *y)
+{
+ int *f;
+ EditLine *l;
+ Iterator i;
+ int min_x,min_y,max_x,max_y;
+
+ TRACE;
+
+ i=ListIterator(selected);
+
+ min_x=99999;
+ min_y=99999;
+ max_x=-99999;
+ max_y=-99999;
+
+ while(i)
+ {
+ f=IteratorData(i);
+ l=GETLINE(*f);
+
+ min_x=MIN(l->min_x,min_x);
+ min_y=MIN(l->min_y,min_y);
+ max_x=MAX(l->max_x,max_x);
+ max_y=MAX(l->max_y,max_y);
+
+ i=IteratorNext(i);
+ }
+
+ *x=min_x+(max_x-min_x)/2;
+ *y=min_y+(max_y-min_y)/2;
+}
+
+
+static void DeleteLeftSidedef(EditLine *l)
+{
+ Object *o;
+ int n;
+ int del;
+ int side;
+ EditLine *cl;
+
+ TRACE;
+
+ if (l->l.left==-1)
+ return;
+
+ l->sl=NULL;
+ side=l->l.left;
+ l->l.left=-1;
+
+ /* Free up the sidedef if there is no other linedef
+ bound to it
+ */
+ del=TRUE;
+
+ for(n=0;(n<MapSize(linedef))&&(del);n++)
+ {
+ cl=GETLINE(n);
+
+ if ((cl)&&((cl->l.left==side)||(cl->l.right==side)))
+ del=FALSE;
+ }
+
+ if (del)
+ {
+ o=MapElem(sidedef,side);
+ Release(o->data);
+ o->data=NULL;
+ }
+}
+
+
+static void DeleteRightSidedef(EditLine *l)
+{
+ Object *o;
+ int n;
+ int del;
+ int side;
+ EditLine *cl;
+
+ TRACE;
+
+ if (l->l.right==-1)
+ return;
+
+ l->sr=NULL;
+ side=l->l.right;
+ l->l.right=-1;
+
+ /* Free up the sidedef if there is no other linedef
+ bound to it
+ */
+ del=TRUE;
+
+ for(n=0;(n<MapSize(linedef))&&(del);n++)
+ {
+ cl=GETLINE(n);
+
+ if ((cl)&&((cl->l.left==side)||(cl->l.right==side)))
+ del=FALSE;
+ }
+
+ if (del)
+ {
+ o=MapElem(sidedef,side);
+ Release(o->data);
+ o->data=NULL;
+ }
+}
+
+
+static void DeleteLinedef(int f)
+{
+ Object *o;
+ EditLine *l;
+
+ TRACE;
+
+ o=MapElem(linedef,f);
+ l=o->data;
+ DeleteLeftSidedef(l);
+ DeleteRightSidedef(l);
+
+ IntListRm(l->v[0]->l,f);
+ IntListRm(l->v[1]->l,f);
+
+ Release(o->data);
+ o->data=NULL;
+ o->select=SELECT_NONE;
+}
+
+
+static int SplitLinedef(int f)
+{
+ Object o;
+ EditLine *l,*nl;
+ Sidedef *nsl,*nsr;
+ EditVert *nv;
+ int n_nl,dx,dy,tw;
+
+ TRACE;
+
+ l=GETLINE(f);
+
+ o.select=SELECT_NONE;
+
+ /* Create copies of the original linedefs and sidedefs
+ */
+ nl=Grab(sizeof(EditLine));
+ memcpy(nl,l,sizeof(EditLine));
+ o.data=nl;
+ n_nl=MapSize(linedef);
+ nl->no=n_nl;
+ MapAdd(linedef,n_nl,&o);
+
+ nsr=Grab(sizeof(Sidedef));
+ memcpy(nsr,l->sr,sizeof(Sidedef));
+ o.data=nsr;
+ nl->l.right=MapSize(sidedef);
+ MapAdd(sidedef,nl->l.right,&o);
+ nl->sr=GETSIDE(nl->l.right);
+
+ if (l->l.left!=-1)
+ {
+ nsl=Grab(sizeof(Sidedef));
+ memcpy(nsl,l->sl,sizeof(Sidedef));
+ o.data=nsl;
+ nl->l.left=MapSize(sidedef);
+ MapAdd(sidedef,nl->l.left,&o);
+ nl->sl=GETSIDE(nl->l.left);
+ }
+ else
+ nsl=NULL;
+
+ /* Work out the middle of the current line and create the vertex there
+ */
+ nv=Grab(sizeof(EditVert));
+ nv->l=ListNew(sizeof(int));
+
+ dx=((l->v[1]->v.x)-(l->v[0]->v.x))/2;
+ dy=((l->v[1]->v.y)-(l->v[0]->v.y))/2;
+
+ nv->v.x=l->v[0]->v.x+dx;
+ nv->v.y=l->v[0]->v.y+dy;
+ o.data=nv;
+
+ /* Update the vertex map, and the from/to in the old/new linedefs
+ */
+ nl->l.from=MapSize(vertex);
+ MapAdd(vertex,nl->l.from,&o);
+
+ l->l.to=nl->l.from;
+
+ l->v[1]=GETVERT(l->l.to);
+ nl->v[0]=GETVERT(nl->l.from);
+
+ /* Update the vertex lists
+ */
+ IntListRm(nl->v[1]->l,f);
+ IntListUniqAdd(nl->v[0]->l,f);
+ IntListUniqAdd(nl->v[0]->l,n_nl);
+
+ /* Align textures
+ */
+ tw=CalcTextureWidth(nsr->upper,nsr->middle,nsr->lower);
+
+ if (tw)
+ nsr->x=(l->sr->x+Len(l->v[0]->v.x,l->v[0]->v.y,
+ l->v[1]->v.x,l->v[1]->v.y))%tw;
+ else
+ nsr->x=0;
+
+ if (nsl)
+ {
+ tw=CalcTextureWidth(nsl->upper,nsl->middle,nsl->lower);
+ if (tw)
+ nsl->x=(l->sl->x+Len(l->v[0]->v.x,l->v[0]->v.y,
+ l->v[1]->v.x,l->v[1]->v.y))%tw;
+ else
+ nsl->x=0;
+ }
+
+ /* New linedef no
+ */
+ return(n_nl);
+}
+
+
+/* ---------------------------------------- STEP CREATION CODE CALCULATIONS
+*/
+static void DoCalcLine (int x0,int y0,int x1,int y1,
+ Point p[],int step,int *idx,int *len)
+{
+ int dx,dy,ix,iy,incre,incrne,d,x,y,ymode;
+ int p1x,p1y,p2x,p2y;
+
+ TRACE;
+
+ p1x=x0;
+ p1y=y0;
+ p2x=x1;
+ p2y=y1;
+
+ dx=p2x-p1x;
+ dy=p2y-p1y;
+
+ ix=SGN(dx);
+ iy=SGN(dy);
+
+ dx=ABS(dx);
+ dy=ABS(dy);
+
+ if (dy>dx)
+ {
+ ymode=TRUE;
+ d=dx*2-dy;
+ incre=dx*2;
+ incrne=(dx-dy)*2;
+ }
+ else
+ {
+ ymode=FALSE;
+ d=dy*2-dx;
+ incre=dy*2;
+ incrne=(dy-dx)*2;
+ }
+
+ x=p1x;
+ y=p1y;
+
+ CHECKSTEP(x,y);
+
+ if (ymode)
+ while(y!=p2y)
+ {
+ if (d<=0)
+ {
+ d+=incre;
+ y+=iy;
+ }
+ else
+ {
+ d+=incrne;
+ y+=iy;
+ x+=ix;
+ }
+
+ CHECKSTEP(x,y);
+ }
+ else
+ while(x!=p2x)
+ {
+ if (d<=0)
+ {
+ d+=incre;
+ x+=ix;
+ }
+ else
+ {
+ d+=incrne;
+ y+=iy;
+ x+=ix;
+ }
+
+ CHECKSTEP(x,y);
+ }
+}
+
+
+static void DoCalcSpline (int x0,int y0,int x1,int y1,int x2,int y2,
+ Point p[],int step,int *idx,int *len)
+{
+ int xa, ya, xb, yb, xc, yc, xp, yp;
+
+ TRACE;
+
+ if ((x0==x1==x2)&&(y0==y1==y2))
+ {
+ CHECKSTEP(x0,y0);
+ return;
+ }
+
+ if ((x0==x1)&&(y0==y1))
+ {
+ if (p)
+ DoCalcLine(x1,y1,x2,y2,p,step,idx,len);
+ else
+ *len+=Len(x1,y1,x2,y2);
+ return;
+ }
+
+ if ((x0==x2)&&(y0==y2))
+ {
+ if (p)
+ DoCalcLine(x0,y0,x1,y1,p,step,idx,len);
+ else
+ *len+=Len(x0,y0,x1,y1);
+ return;
+ }
+
+ if ((x1==x2)&&(y1==y2))
+ {
+ if (p)
+ DoCalcLine(x0,y0,x2,y2,p,step,idx,len);
+ else
+ *len+=Len(x0,y0,x2,y2);
+ return;
+ }
+
+ xa = ( x0 + x1 ) / 2;
+ ya = ( y0 + y1 ) / 2;
+ xc = ( x1 + x2 ) / 2;
+ yc = ( y1 + y2 ) / 2;
+ xb = ( xa + xc ) / 2;
+ yb = ( ya + yc ) / 2;
+
+ xp = ( x0 + xb ) / 2;
+ yp = ( y0 + yb ) / 2;
+
+ if ( ABS( xa - xp ) + ABS( ya - yp ) > SPLINE_THRESH )
+ DoCalcSpline(x0,y0,xa,ya,xb,yb,p,step,idx,len);
+ else
+ if (p)
+ DoCalcLine(x0,y0,xb,yb,p,step,idx,len);
+ else
+ *len+=Len(x0,y0,xb,yb);
+
+ xp = ( x2 + xb ) / 2;
+ yp = ( y2 + yb ) / 2;
+ if ( ABS( xc - xp ) + ABS( yc - yp ) > SPLINE_THRESH )
+ DoCalcSpline(xb,yb,xc,yc,x2,y2,p,step,idx,len);
+ else
+ if (p)
+ DoCalcLine(xb,yb,x2,y2,p,step,idx,len);
+ else
+ *len+=Len(xb,yb,x2,y2);
+}
+
+
+static void Spline(int x0,int y0, int x1, int y1, int x2, int y2,
+ Point p[],int step)
+{
+ int len;
+ int idx;
+
+ TRACE;
+
+ len=0;
+ idx=0;
+ DoCalcSpline(x0,y0,x1,y1,x2,y2,p,step,&idx,&len);
+}
+
+
+static int SplineLen(int x0,int y0, int x1, int y1, int x2, int y2)
+{
+ int len;
+
+ TRACE;
+
+ len=0;
+ DoCalcSpline(x0,y0,x1,y1,x2,y2,NULL,0,NULL,&len);
+ return (len);
+}
+
+
+static void CalcSteps(void)
+{
+ double dx,dy;
+ int f,r;
+ int len;
+
+ TRACE;
+
+ step.step_f=((double)step.to_f-step.from_f)/(step.no+2);
+ step.step_c=((double)step.to_c-step.from_c)/(step.no+2);
+
+ if (step.circular)
+ {
+ f=step.side;
+
+ len=SplineLen(step.vf[f].x,step.vf[f].y,step.x,step.y,
+ step.vt[f].x,step.vt[f].y);
+
+ len=(int)((double)len/((double)step.no+1.0)+1.0);
+
+ if (len<1)
+ len=1;
+
+ Spline(step.vf[f].x,step.vf[f].y,step.x,step.y,
+ step.vt[f].x,step.vt[f].y,&step.p[f][1],len);
+
+ step.p[f][0].x=step.vf[f].x;
+ step.p[f][0].y=step.vf[f].y;
+
+ step.p[f][step.no+1].x=step.vt[f].x;
+ step.p[f][step.no+1].y=step.vt[f].y;
+ }
+ else
+ for(f=0;f<2;f++)
+ {
+ dx=(double)(step.vt[f].x-step.vf[f].x)/(step.no+1);
+ dy=(double)(step.vt[f].y-step.vf[f].y)/(step.no+1);
+
+ for(r=1;r<=step.no;r++)
+ {
+ step.p[f][r].x=(int)(step.vf[f].x+(dx*r));
+ step.p[f][r].y=(int)(step.vf[f].y+(dy*r));
+ }
+
+ step.p[f][0].x=step.vf[f].x;
+ step.p[f][0].y=step.vf[f].y;
+
+ step.p[f][step.no+1].x=step.vt[f].x;
+ step.p[f][step.no+1].y=step.vt[f].y;
+ }
+}
+
+
+int SectorInBox(Point tl, Point br)
+{
+ int x,y;
+
+ x=tl.x+(br.x-tl.x)/2;
+ y=tl.y+(br.y-tl.y)/2;
+
+ return (SectorHoldingPoint(x,y));
+}
+
+
+/* ---------------------------------------- STEP CREATION CALLBACKS
+*/
+static void PickDraw(int *x, int *y)
+{
+ int f;
+
+ TRACE;
+
+ step.x=*x;
+ step.y=*y;
+
+ if (step.circular)
+ CalcSteps();
+
+ for(f=0;f<2;f++)
+ MapLine(step.p[f][0].x,step.p[f][0].y,
+ step.p[f][1].x,step.p[f][1].y,LINECOL);
+
+ for(f=1;f<=step.no;f++)
+ {
+ MapLine(step.p[0][f].x,step.p[0][f].y,
+ step.p[1][f].x,step.p[1][f].y,LINECOL);
+
+ MapLine(step.p[0][f].x,step.p[0][f].y,
+ step.p[0][f+1].x,step.p[0][f+1].y,LINECOL);
+
+ MapLine(step.p[1][f].x,step.p[1][f].y,
+ step.p[1][f+1].x,step.p[1][f+1].y,LINECOL);
+ }
+}
+
+
+static void PickKey(GFXKey k)
+{
+ TRACE;
+
+ if (k.code==GFX_ASCII)
+ switch(toupper(k.ascii))
+ {
+ case 'C':
+ step.circular=!step.circular;
+ CalcSteps();
+ break;
+
+ case 'S':
+ step.side^=1;
+ CalcSteps();
+ break;
+
+ case 'R':
+ step.swap=!step.swap;
+
+ if (!step.swap)
+ {
+ SetPoint(step.vf[0],step.from->v[0]);
+ SetPoint(step.vf[1],step.from->v[1]);
+ SetPoint(step.vt[0],step.to->v[0]);
+ SetPoint(step.vt[1],step.to->v[1]);
+ }
+ else
+ {
+ SetPoint(step.vf[0],step.from->v[0]);
+ SetPoint(step.vf[1],step.from->v[1]);
+ SetPoint(step.vt[0],step.to->v[1]);
+ SetPoint(step.vt[1],step.to->v[0]);
+ }
+
+ CalcSteps();
+
+ if (step.circular)
+ {
+ step.side^=1;
+ CalcSteps();
+ step.side^=1;
+ }
+
+ break;
+
+ case '+':
+ if (step.no<MAX_STEPS)
+ {
+ step.no++;
+ CalcSteps();
+
+ if (step.circular)
+ {
+ step.side^=1;
+ CalcSteps();
+ step.side^=1;
+ }
+ }
+ break;
+
+ case '-':
+ if (step.no>MIN_STEPS)
+ {
+ step.no--;
+ CalcSteps();
+
+ if (step.circular)
+ {
+ step.side^=1;
+ CalcSteps();
+ step.side^=1;
+ }
+ }
+ break;
+ }
+}
+
+
+static void PickInfo(char *p)
+{
+ TRACE;
+
+ GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE,
+ "No : %d|"
+ "Step (F) : %d|"
+ "Step (C) : %d|"
+ "Mode : %-s|"
+ "Side : %d",
+ step.no,ABS((int)step.step_f),ABS((int)step.step_c),
+ step.circular ? "Curve " : "Straight",
+ step.side);
+
+ GuiDrawInfoBox(p,GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE,
+ "+ - increase number of steps|"
+ "- - decrease number of steps|"
+ "C - change between straight/curve|"
+ "S - change wall being moved in curve mode|"
+ "R - swap vertex matching|"
+ " |"
+ "Press left button to complete. ESC to cancel");
+}
+
+
+/* ---------------------------------------- STEP CREATION CODE
+*/
+typedef struct
+ {
+ int line;
+ int apply;
+ } TextureMatch;
+
+static void ApplyTextureOffset(List li,int tw,int right)
+{
+ int off;
+ Iterator i;
+ TextureMatch *tm;
+ EditLine *l;
+ Sidedef *s;
+
+ TRACE;
+
+ i=ListIterator(li);
+ off=0;
+
+ while(i)
+ {
+ tm=IteratorData(i);
+
+ l=GETLINE(tm->line);
+
+ if (tm->apply)
+ {
+ if (right)
+ s=l->sr;
+ else
+ s=l->sl;
+
+ s->x=off;
+ }
+
+ off=(off+Len(l->v[0]->v.x,l->v[0]->v.y,l->v[1]->v.x,l->v[1]->v.y))%tw;
+
+ i=IteratorNext(i);
+ }
+}
+
+
+static int CreateSteps(int i_from, int i_to)
+{
+ EditSect *s;
+ EditLine *from,*to;
+ DirName upper,lower,middle,floor,ceiling;
+ int s_flag;
+ int type;
+
+ TRACE;
+
+ from=GETLINE(i_from);
+ to=GETLINE(i_to);
+
+ if ((Len(from->v[0]->v.x,from->v[0]->v.y,
+ from->v[1]->v.x,from->v[1]->v.y)==0)||
+ (Len(to->v[0]->v.x,to->v[0]->v.y,to->v[1]->v.x,to->v[1]->v.y)==0))
+ {
+ GuiInfoBox("ERROR","Lines must be non-zero length");
+ return(FALSE);
+ }
+
+ if (((from->l.from==to->l.from)&&(to->l.to==to->l.to))||
+ ((from->l.from==to->l.to)&&(to->l.to==to->l.from)))
+ {
+ GuiInfoBox("ERROR","Lines cannot share a vertex");
+ return(FALSE);
+ }
+
+ if (!(LinesCrossV(from->v[0],to->v[0],from->v[1],to->v[1])))
+ {
+ step.swap=FALSE;
+ SetPoint(step.vf[0],from->v[0]);
+ SetPoint(step.vf[1],from->v[1]);
+ SetPoint(step.vt[0],to->v[0]);
+ SetPoint(step.vt[1],to->v[1]);
+ }
+ else
+ {
+ step.swap=TRUE;
+ SetPoint(step.vf[0],from->v[0]);
+ SetPoint(step.vf[1],from->v[1]);
+ SetPoint(step.vt[0],to->v[1]);
+ SetPoint(step.vt[1],to->v[0]);
+ }
+
+ step.x=ms.x;
+ step.y=ms.y;
+ step.from=from;
+ step.to=to;
+ step.no=1;
+ step.circular=FALSE;
+ step.side=0;
+
+ s=GETSECT(from->sr->sector);
+ step.from_c=s->s.ceiling;
+ step.from_f=s->s.floor;
+
+ s=GETSECT(to->sr->sector);
+ step.to_c=s->s.ceiling;
+ step.to_f=s->s.floor;
+
+ CalcSteps();
+
+ if ((PickPoint("Create steps",&step.x,&step.y,PickDraw,PickKey,PickInfo))&&
+ (ChooseSectorStyle(&s_flag,upper,middle,lower,floor,ceiling))&&
+ ((type=SelectSector())!=SECTOR_NULLID))
+ {
+ Object o;
+ EditLine *el;
+ EditVert *ev[2][MAX_STEPS+2];
+ EditSect *s;
+ Sidedef *ns;
+ TextureMatch tm;
+ List side_sl[2],side_sr[2];
+ int n;
+ int v[2][MAX_STEPS+2];
+ int do_ceiling;
+ double fh,ch;
+ int prev_fh,prev_ch;
+ int in_sect,sect,prev_sect;
+ int nl,flags;
+ int offy_c,offy_f,tw,th;
+ int f,r;
+
+ /* Create lists for mainting lines for afterward texture alignment
+ */
+ for(f=0;f<2;f++)
+ {
+ side_sl[f]=ListNew(sizeof(TextureMatch));
+ side_sr[f]=ListNew(sizeof(TextureMatch));
+ }
+
+ if ((do_ceiling=GUI_yesno("Move ceiling with steps?")))
+ ch=step.from_c+step.step_c;
+ else
+ ch=MAX(step.to_c,step.from_c);
+
+ fh=step.from_f+step.step_f;
+
+ tw=CalcTextureWidth(upper,middle,lower);
+
+ TextureSize(middle,NULL,&th);
+
+ /* Create/get all the vertexes needed
+ */
+ for(f=0;f<=step.no+1;f++)
+ if (f==0)
+ {
+ v[0][f]=step.from->l.from;
+ v[1][f]=step.from->l.to;
+ ev[0][f]=step.from->v[0];
+ ev[1][f]=step.from->v[1];
+ }
+ else if (f==step.no+1)
+ {
+ if (step.swap)
+ {
+ v[1][f]=step.to->l.from;
+ v[0][f]=step.to->l.to;
+ ev[1][f]=step.to->v[0];
+ ev[0][f]=step.to->v[1];
+ }
+ else
+ {
+ v[0][f]=step.to->l.from;
+ v[1][f]=step.to->l.to;
+ ev[0][f]=step.to->v[0];
+ ev[1][f]=step.to->v[1];
+ }
+ }
+ else
+ for(r=0;r<2;r++)
+ {
+ ev[r][f]=Grab(sizeof(EditVert));
+ ev[r][f]->v.x=step.p[r][f].x;
+ ev[r][f]->v.y=step.p[r][f].y;
+ ev[r][f]->l=ListNew(sizeof(int));
+
+ o.data=ev[r][f];
+ o.select=SELECT_NONE;
+ v[r][f]=MapSize(vertex);
+ MapAdd(vertex,-1,&o);
+ }
+
+ /* Delete current left sidedefs on the anchor lines
+ */
+ if (step.from->l.left!=-1)
+ DeleteLeftSidedef(step.from);
+
+ if (step.to->l.left!=-1)
+ DeleteLeftSidedef(step.to);
+
+ /* Set up the flags for the 1st line and all the previous sector and
+ height vars
+ */
+ prev_fh=step.from_f;
+ prev_ch=step.from_c;
+ prev_sect=step.from->sr->sector;
+ offy_c=0;
+ offy_f=0;
+
+ /* Create the steps up to the last one
+ */
+ for(f=0;f<=step.no;f++)
+ {
+ in_sect=SectorInBox(step.p[0][f],step.p[1][f+1]);
+
+ if (in_sect!=-1)
+ s=GETSECT(in_sect);
+ else
+ s=NULL;
+
+ sect=CreateUnboundSector
+ (type,(int)fh,(int)ch,default_light_level,0,floor,ceiling);
+
+ /* Create the linedef at the start of the step. For the 1st step
+ we adjust the original linedef. Otherwise create a new one
+ */
+ if (!f)
+ {
+ el=step.from;
+ el->l.flags|=side2_mask;
+ el->l.flags&=~block_mask;
+
+ ns=Grab(sizeof(Sidedef));
+ ns->x=0;
+ ns->y=0;
+
+ el->l.flags|=upper_peg_mask;
+ el->l.flags&=~lower_peg_mask;
+
+ if (prev_ch>(int)ch)
+ {
+ strcpy(el->sr->upper,upper);
+ strcpy(ns->upper,empty_texture);
+ }
+ else if (prev_ch<(int)ch)
+ {
+ strcpy(el->sr->upper,empty_texture);
+ strcpy(ns->upper,upper);
+ }
+ else
+ {
+ strcpy(el->sr->upper,empty_texture);
+ strcpy(ns->upper,empty_texture);
+ }
+
+ if (prev_fh<(int)fh)
+ {
+ strcpy(el->sr->lower,lower);
+ strcpy(ns->lower,empty_texture);
+ }
+ else if (prev_fh>(int)fh)
+ {
+ strcpy(el->sr->lower,empty_texture);
+ strcpy(ns->lower,lower);
+ }
+ else
+ {
+ strcpy(el->sr->lower,empty_texture);
+ strcpy(ns->lower,empty_texture);
+ }
+
+ strcpy(el->sr->middle,empty_texture);
+ strcpy(ns->middle,empty_texture);
+
+ ns->sector=sect;
+
+ o.data=ns;
+ o.select=SELECT_NONE;
+
+ n=MapSize(sidedef);
+ MapAdd(sidedef,n,&o);
+ el->sl=ns;
+ el->l.left=n;
+ }
+ else
+ {
+ flags=side2_mask|upper_peg_mask;
+
+ nl=CreateNewLinedef
+ (v[0][f],v[1][f],flags,normal_linedef,0,TRUE,
+ 0,0,prev_sect,
+ (prev_ch > (int)ch) ? upper : empty_texture,
+ empty_texture,
+ (prev_fh < (int)fh) ? lower : empty_texture,
+ 0,0,sect,
+ (prev_ch < (int)ch) ? upper : empty_texture,
+ empty_texture,
+ (prev_fh > (int)fh) ? lower : empty_texture);
+
+ /* Add the new linedef to the vertex lists
+ */
+ IntListUniqAdd(ev[0][f]->l,nl);
+ IntListUniqAdd(ev[1][f]->l,nl);
+ }
+
+ /* Create the linedefs for the walls
+ */
+ if (th)
+ {
+ offy_f-=(int)fh-prev_fh;
+
+ while (offy_f<0)
+ offy_f+=th;
+
+ offy_f%=th;
+ }
+
+ if (do_ceiling)
+ if (th)
+ {
+ offy_c-=(int)ch-prev_ch;
+
+ while (offy_c<0)
+ offy_c+=th;
+
+ offy_c%=th;
+ }
+
+ for(r=0;r<2;r++)
+ {
+ if (in_sect==-1)
+ {
+ int offy;
+
+ flags=block_mask;
+
+ if (!do_ceiling)
+ {
+ flags|=upper_peg_mask;
+ offy=0;
+ }
+ else
+ offy=offy_c;
+
+ nl=CreateNewLinedef(v[r][f+r],v[r][f+(r^1)],
+ flags,normal_linedef,0,FALSE,
+ 0,offy,sect,
+ empty_texture,
+ middle,
+ empty_texture,
+ 0,0,-1,
+ empty_texture,
+ empty_texture,
+ empty_texture);
+
+ tm.line=nl;
+
+ if (r==0)
+ {
+ tm.apply=TRUE;
+ ListAppend(side_sr[r],&tm);
+ tm.apply=FALSE;
+ ListInsert(side_sl[r],&tm);
+ }
+ else
+ {
+ tm.apply=TRUE;
+ ListInsert(side_sr[r],&tm);
+ tm.apply=FALSE;
+ ListAppend(side_sl[r],&tm);
+ }
+ }
+ else
+ {
+ int offy_l,offy_r;
+
+ flags=side2_mask;
+ flags=side2_mask|lower_peg_mask|upper_peg_mask;
+
+ if ((int)ch>s->s.ceiling)
+ offy_r=offy_c;
+ else if ((int)fh<s->s.floor)
+ offy_r=offy_c;
+ else
+ offy_r=0;
+
+ offy_l=0;
+
+ nl=CreateNewLinedef(v[r][f+r],v[r][f+(r^1)],
+ flags,normal_linedef,0,TRUE,
+ 0,offy_r,sect,
+ ((int)ch > s->s.ceiling) ?
+ upper : empty_texture,
+ empty_texture,
+ ((int)fh < s->s.floor) ?
+ lower : empty_texture,
+ 0,offy_l,in_sect,
+ ((int)ch < s->s.ceiling) ?
+ upper : empty_texture,
+ empty_texture,
+ ((int)fh > s->s.floor) ?
+ lower : empty_texture);
+
+ tm.line=nl;
+
+ if (r==0)
+ {
+ tm.apply=TRUE;
+ ListAppend(side_sr[r],&tm);
+ tm.apply=TRUE;
+ ListInsert(side_sl[r],&tm);
+ }
+ else
+ {
+ tm.apply=TRUE;
+ ListInsert(side_sr[r],&tm);
+ tm.apply=TRUE;
+ ListAppend(side_sl[r],&tm);
+ }
+ }
+
+ /* Add the new linedef to the vertex lists
+ */
+ IntListUniqAdd(ev[r][f]->l,nl);
+ IntListUniqAdd(ev[r][f+1]->l,nl);
+ }
+
+ prev_fh=(int)fh;
+ prev_ch=(int)ch;
+
+ fh+=step.step_f;
+
+ if (do_ceiling)
+ ch+=step.step_c;
+
+ prev_sect=sect;
+ }
+
+ /* Adjust the end linedef anchor
+ */
+ el=step.to;
+ el->l.flags|=side2_mask;
+ el->l.flags&=~block_mask;
+
+ ns=Grab(sizeof(Sidedef));
+ ns->x=0;
+ ns->y=0;
+
+ if ((prev_ch!=step.to_c)&&(s_flag&SSTYLE_UPPER_PEG))
+ el->l.flags|=upper_peg_mask;
+ else if (!(s_flag&SSTYLE_LEAVE_PEG))
+ el->l.flags&=~upper_peg_mask;
+
+ if ((prev_fh!=step.to_f)&&(s_flag&SSTYLE_LOWER_PEG))
+ el->l.flags|=lower_peg_mask;
+ else if (!(s_flag&SSTYLE_LEAVE_PEG))
+ el->l.flags&=~lower_peg_mask;
+
+ if (prev_ch<step.to_c)
+ {
+ strcpy(el->sr->upper,upper);
+ strcpy(ns->upper,empty_texture);
+ }
+ else if (prev_ch>step.to_c)
+ {
+ strcpy(el->sr->upper,empty_texture);
+ strcpy(ns->upper,upper);
+ }
+ else
+ {
+ strcpy(el->sr->upper,empty_texture);
+ strcpy(ns->upper,empty_texture);
+ }
+
+ if (prev_fh>step.to_f)
+ {
+ strcpy(el->sr->lower,lower);
+ strcpy(ns->lower,empty_texture);
+ }
+ else if (prev_fh<step.to_f)
+ {
+ strcpy(el->sr->lower,empty_texture);
+ strcpy(ns->lower,lower);
+ }
+ else
+ {
+ strcpy(el->sr->lower,empty_texture);
+ strcpy(ns->lower,empty_texture);
+ }
+
+ strcpy(el->sr->middle,empty_texture);
+ strcpy(ns->middle,empty_texture);
+
+ ns->sector=prev_sect;
+
+ o.data=ns;
+ o.select=SELECT_NONE;
+
+ n=MapSize(sidedef);
+ MapAdd(sidedef,n,&o);
+ el->sl=ns;
+ el->l.left=n;
+
+ /* Calculate the texture offsets for the walls
+ */
+ for(f=0;f<2;f++)
+ {
+ ApplyTextureOffset(side_sl[f],tw,FALSE);
+ ApplyTextureOffset(side_sr[f],tw,TRUE);
+
+ ListClear(side_sl[f]);
+ ListClear(side_sr[f]);
+ }
+
+ SectorCalcContainingAll();
+
+ return(TRUE);
+ }
+ else
+ return(FALSE);
+}
+
+
+/* ---------------------------------------- LINEDEF VECTOR MAP UTILS
+*/
+
+/* Note this is repeated, rather than shared with the sector vector map to save
+ any unexpected later interactions
+*/
+static int vno=0;
+static char *vmap=NULL;
+
+static void InitVMAP(void)
+{
+ TRACE;
+
+ if (vno<MapSize(vertex))
+ vmap=ReGrab(vmap,MapSize(vertex));
+
+ memset(vmap,FALSE,MapSize(vertex));
+}
+
+
+/* ---------------------------------------- SECTOR LINEDEF MAP UTILS
+*/
+static int lno=0;
+static char *lmap=NULL;
+
+static void InitLMAP(void)
+{
+ TRACE;
+
+ if (lno<MapSize(linedef))
+ lmap=ReGrab(lmap,MapSize(linedef));
+
+ memset(lmap,FALSE,MapSize(linedef));
+}
+
+
+/* ---------------------------------------- LINEDEF TRACK FUNCTIONS
+*/
+List TrackLinedef(int line_no)
+{
+ EditSect *s;
+ EditLine *l;
+ List ll;
+ Iterator i;
+ int sec_no;
+ int done;
+ int f;
+ int vert_no;
+
+ TRACE;
+
+ if (!(l=GETLINE(line_no)))
+ return(NULL);
+
+ InitLMAP();
+
+ lmap[line_no]=TRUE;
+
+ ll=ListNew(sizeof(int));
+ ListAppend(ll,&line_no);
+
+ sec_no=l->sr->sector;
+
+ if (!(s=GETSECT(sec_no)))
+ return(ll);
+
+ vert_no=l->l.to;
+
+ /* If the start LINEDEF is 2-sided and wholy within the sector, we only
+ track along connected 2-sided lines in the same sector.
+
+ If the start line is 1-sided then we allow both 1 and 2 sided LINEDEFs
+ in the resulting list, but only 2 sided LINEDEFs that just have this
+ sector on one side of the line.
+
+ To make this easier we mark the LMAP entries for those lines we wish to
+ ignore before starting.
+ */
+ if ((l->sl)&&(l->sl->sector==sec_no))
+ {
+ i=ListIterator(s->all);
+
+ while(i)
+ {
+ memcpy(&l,IteratorData(i),sizeof(l));
+
+ if (!l->sl)
+ lmap[l->no]=TRUE;
+ else
+ if (!((l->sl->sector==sec_no)&&(l->sr->sector==sec_no)))
+ lmap[l->no]=TRUE;
+
+ i=IteratorNext(i);
+ }
+ }
+ else
+ {
+ i=ListIterator(s->all);
+
+ while(i)
+ {
+ memcpy(&l,IteratorData(i),sizeof(l));
+
+ if ((l->sl)&&(l->sl->sector==sec_no)&&(l->sr->sector==sec_no))
+ lmap[l->no]=TRUE;
+
+ i=IteratorNext(i);
+ }
+ }
+
+ done=FALSE;
+
+ while(!done)
+ {
+ done=TRUE;
+
+ i=ListIterator(s->all);
+
+ while(i)
+ {
+ memcpy(&l,IteratorData(i),sizeof(l));
+
+ f=l->no;
+
+ if (!lmap[f])
+ {
+ /* We need two seperate checks, as obviously left sidedefs
+ pointing into the sector will need TO, rather than FROM,
+ checking
+ */
+ if ((l->sr->sector==sec_no)&&(l->l.from==vert_no))
+ {
+ lmap[f]=TRUE;
+ ListAppend(ll,&f);
+ done=FALSE;
+ vert_no=l->l.to;
+ }
+ else if ((l->sl)&&(l->sl->sector==sec_no)&&(l->l.to==vert_no))
+ {
+ lmap[f]=TRUE;
+ ListAppend(ll,&f);
+ done=FALSE;
+ vert_no=l->l.from;
+ }
+ }
+
+ i=IteratorNext(i);
+ }
+ }
+
+ return(ll);
+}
+
+
+/* ---------------------------------------- LINEDEF MERGING
+*/
+void CheckMergeLinedef(EditVert *v)
+{
+ Iterator i;
+ int *f;
+ int r;
+ EditLine *ol,*cl;
+ int same_dir;
+ int merge;
+
+ TRACE;
+
+ i=ListIterator(v->l);
+
+ while(i)
+ {
+ f=IteratorData(i);
+
+ ol=GETLINE(*f);
+
+ for(r=0;r<MapSize(linedef);r++)
+ if ((r!=*f)&&(cl=GETLINE(r)))
+ {
+ if (((cl->l.from==ol->l.from)&&(cl->l.to==ol->l.to))||
+ ((cl->l.from==ol->l.to)&&(cl->l.to==ol->l.from)))
+ {
+ if ((cl->l.from==ol->l.from)&&(cl->l.to==ol->l.to))
+ same_dir=TRUE;
+ else
+ same_dir=FALSE;
+
+ if(merge_linedef==MERGE_ASK)
+ merge=YesNo("Linedefs %d and %d overlap. Merge?",*f,r);
+ else
+ merge=TRUE;
+
+ if (merge)
+ {
+ if (same_dir)
+ {
+ if (cl->l.left!=-1)
+ {
+ DeleteLeftSidedef(ol);
+ ol->l.left=cl->l.left;
+ ol->sl=GETSIDE(ol->l.left);
+ ol->l.flags|=side2_mask;
+
+ if (auto_block_linedefs)
+ ol->l.flags&=~block_mask;
+ }
+ }
+ else
+ {
+ DeleteLeftSidedef(ol);
+ ol->l.left=cl->l.right;
+ ol->sl=GETSIDE(ol->l.left);
+ ol->l.flags|=side2_mask;
+
+ if (auto_block_linedefs)
+ ol->l.flags&=~block_mask;
+ }
+
+ DeleteLinedef(r);
+ }
+ }
+ }
+
+ i=IteratorNext(i);
+ }
+}
+
+
+/* ---------------------------------------- LINEDEF CREATION
+*/
+int CreateNewLinedef(int from, int to,
+ int flags, int type, int tag, int two_sided,
+ int sr_ox, int sr_oy, int sr_sector,
+ DirName sr_upper, DirName sr_middle, DirName sr_lower,
+ int sl_ox, int sl_oy, int sl_sector,
+ DirName sl_upper, DirName sl_middle, DirName sl_lower)
+{
+ Object o;
+ EditLine *l;
+ Sidedef *s;
+ int ln,srn,sln;
+
+ TRACE;
+
+ ln=MapSize(linedef);
+
+ srn=MapSize(sidedef);
+
+ if (two_sided)
+ sln=srn+1;
+ else
+ sln=-1;
+
+ o.select=SELECT_NONE;
+
+ s=Grab(sizeof(Sidedef));
+ s->x=sr_ox;
+ s->y=sr_oy;
+ s->sector=sr_sector;
+ strcpy(s->upper,sr_upper);
+ strcpy(s->middle,sr_middle);
+ strcpy(s->lower,sr_lower);
+ o.data=s;
+ MapAdd(sidedef,srn,&o);
+
+ if (sln!=-1)
+ {
+ s=Grab(sizeof(Sidedef));
+ s->x=sl_ox;
+ s->y=sl_oy;
+ s->sector=sl_sector;
+ strcpy(s->upper,sl_upper);
+ strcpy(s->middle,sl_middle);
+ strcpy(s->lower,sl_lower);
+ o.data=s;
+ MapAdd(sidedef,sln,&o);
+ }
+
+ l=Grab(sizeof(EditLine));
+
+ l->no=ln;
+
+ l->l.from=from;
+ l->l.to=to;
+
+ l->l.flags=flags;
+ l->l.type=type;
+ l->l.tag=tag;
+
+ l->v[0]=GETVERT(l->l.from);
+ l->v[1]=GETVERT(l->l.to);
+
+ l->l.right=srn;
+ l->l.left=sln;
+
+ l->sr=GETSIDE(srn);
+
+ if (sln!=-1)
+ l->sl=GETSIDE(sln);
+ else
+ l->sl=NULL;
+
+ if (edit_mode==LINEDEF_MODE)
+ switch(insert_select)
+ {
+ case HOVER_NONE:
+ o.select=SELECT_NONE;
+ break;
+ case HOVER_ADD:
+ case HOVER_SINGLE:
+ o.select=SELECT_SELECTED;
+ break;
+ }
+ else
+ o.select=SELECT_NONE;
+
+ LineCalcBounding(l);
+ o.data=l;
+ MapAdd(linedef,ln,&o);
+
+ if (edit_mode==LINEDEF_MODE)
+ switch(insert_select)
+ {
+ case HOVER_NONE:
+ break;
+ case HOVER_ADD:
+ ListAppend(selected,&ln);
+ break;
+ case HOVER_SINGLE:
+ ClearSelection();
+ o.select=SELECT_SELECTED;
+ ListAppend(selected,&ln);
+ FullRedraw();
+ break;
+ }
+
+ return(ln);
+}
+
+
+/* ---------------------------------------- GENERIC LINEDEF FUNCS
+*/
+int PositionOnObject_LINEDEF(int x,int y,void *data)
+{
+ EditLine *l;
+
+ TRACE;
+
+ l=data;
+
+ /*
+ if (scale<4)
+ box=BOXBOUND_FUZZY(x,y,l->min_x,l->min_y,l->max_x,l->max_y,2);
+ else
+ box=BOXBOUND_FUZZY(x,y,l->min_x,l->min_y,l->max_x,l->max_y,scale/2);
+
+ if (!box)
+ return(FALSE);
+ */
+
+ if(LinesCross(x-(scale*linedef_select),y,x+(scale*linedef_select),y,
+ l->v[0]->v.x,l->v[0]->v.y,
+ l->v[1]->v.x,l->v[1]->v.y))
+ return(TRUE);
+
+ return(LinesCross(x,y-(scale*linedef_select),x,y+(scale*linedef_select),
+ l->v[0]->v.x,l->v[0]->v.y,
+ l->v[1]->v.x,l->v[1]->v.y));
+}
+
+
+void SelectBox_LINEDEF(int x1,int y1,int x2,int y2)
+{
+ Object *o;
+ EditLine *l;
+ int f;
+
+ TRACE;
+
+ for(f=0;f<MapSize(linedef);f++)
+ {
+ o=MapElem(linedef,f);
+
+ if ((l=o->data))
+ {
+ if ((o->select!=SELECT_SELECTED)&&
+ (BOXBOUND(l->v[0]->v.x,l->v[0]->v.y,x1,y1,x2,y2))&&
+ (BOXBOUND(l->v[1]->v.x,l->v[1]->v.y,x1,y1,x2,y2)))
+ {
+ SetSelect(f,SELECT_SELECTED);
+ ListAppend(selected,&f);
+ }
+ }
+ }
+}
+
+
+void SelectByType_LINEDEF(void)
+{
+ Object *o;
+ EditLine *l;
+ int id;
+ int f;
+
+ if ((id=SelectLinedef())!=LINEDEF_NULLID)
+ {
+ ClearSelection();
+
+ for(f=0;f<MapSize(linedef);f++)
+ if ((o=MapElem(linedef,f)))
+ if ((l=o->data)&&(l->l.type==id))
+ {
+ SetSelect(f,SELECT_SELECTED);
+ ListAppend(selected,&f);
+ }
+ }
+}
+
+
+void DrawObject_LINEDEF(void *data, int selmode)
+{
+ static List hilite=NULL;
+ static int drawn=FALSE;
+ Iterator i;
+ EditLine *l;
+ EditLine *sl=NULL;
+ EditSect *s;
+ Object *o;
+ int f;
+
+ TRACE;
+
+ if (!hilite)
+ hilite=ListNew(sizeof(int));
+
+ l=data;
+
+ /* If the current object has changed, remove the highlighted tag objects
+ */
+ if ((current==-1)&&(drawn))
+ {
+ drawn=FALSE;
+ RemoveHighlights(hilite);
+ ListEmpty(hilite);
+ }
+
+ /* Draw tagged sectors
+ */
+ if ((tag_highlight)&&(current==l->no))
+ {
+ RemoveHighlights(hilite);
+ ListEmpty(hilite);
+
+ if (l->l.tag)
+ {
+ drawn=TRUE;
+
+ for(f=0;f<MapSize(sector);f++)
+ if ((s=GETSECT(f)))
+ if ((s->s.tag==l->l.tag)&&(SectorOnDisplay(s)))
+ {
+ i=ListIterator(s->all);
+
+ while(i)
+ {
+ memcpy(&sl,IteratorData(i),sizeof(sl));
+ o=MapElem(linedef,sl->no);
+
+ if (o->select==SELECT_NONE)
+ {
+ ListAppend(hilite,&(sl->no));
+ DrawLinedef(sl,TAGCOL);
+ }
+
+ i=IteratorNext(i);
+ }
+ }
+ }
+
+ }
+
+ /* Only draw the line if it's not been drawn tagged or is selected.
+ */
+ if ((!tag_highlight)||(selmode==SELECT_SELECTED)||
+ (!InIntList(hilite,l->no)))
+ DrawLinedef(data,SelColour(selmode));
+}
+
+
+void DrawObjectInfo_LINEDEF(void)
+{
+ EditLine *l;
+
+ TRACE;
+
+ if (!draw_current_info)
+ return;
+
+ if ((current!=-1)&&((l=GETLINE(current))))
+ {
+ if (show_full_linedef_info)
+ GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE,
+ "Linedef No : %-5d|"
+ "Flags : %s|"
+ "Type [%4.4x]: %-35.35s|"
+ "Tag : %-5d",
+ current,
+ LinedefFlagText(l->l.flags),
+ l->l.type,LinedefName(l->l.type),l->l.tag);
+ else
+ GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE,
+ "Linedef No : %-5d|"
+ "Flags : %s|"
+ "Type [%4.4x]: %-20.20s|"
+ "Tag : %-5d",
+ current,
+ LinedefFlagText(l->l.flags),
+ l->l.type,LinedefClass(l->l.type),l->l.tag);
+
+ GuiDrawInfoBox("RIGHT SIDEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE,
+ "Offset : %d,%d|"
+ "Upper : %-10s|"
+ "Middle : %-10s|"
+ "Lower : %-10s|"
+ "Sector : %d",
+ l->sr->x,l->sr->y,
+ l->sr->upper,l->sr->middle,l->sr->lower,
+ l->sr->sector);
+
+ if (l->sl)
+ GuiDrawInfoBox("LEFT SIDEDEF",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE,
+ "Offset : %d,%d|"
+ "Upper : %-10s|"
+ "Middle : %-10s|"
+ "Lower : %-10s|"
+ "Sector : %d",
+ l->sl->x,l->sl->y,
+ l->sl->upper,l->sl->middle,l->sl->lower,
+ l->sl->sector);
+ else
+ GuiDrawInfoBox("NO LEFT SIDEDEF",GUI_FLUSH_LEFT,
+ GUI_FLUSH_LOWER,FALSE,
+ " |"
+ " %-10s|"
+ " |"
+ " |"
+ " ","");
+ }
+ else
+ {
+ if (show_full_linedef_info)
+ GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE,
+ "Linedef No : -|"
+ "Flags : -|"
+ "Type : %35s|"
+ "Tag : -","");
+ else
+ GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE,
+ "Linedef No : -|"
+ "Flags : -|"
+ "Type : %20s|"
+ "Tag : -","");
+
+ GuiDrawInfoBox("RIGHT SIDEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE,
+ " |"
+ " %-10s|"
+ " |"
+ " |"
+ " ","");
+
+ GuiDrawInfoBox("LEFT SIDEDEF",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE,
+ " |"
+ " %-10s|"
+ " |"
+ " |"
+ " ","");
+ }
+}
+
+
+void DrawObjectHeader_LINEDEF(void)
+{
+ if (tag_highlight)
+ GFX_print(0,FH,WHITE,"Tag highlight: ON");
+ else
+ GFX_print(0,FH,WHITE,"Tag highlight: OFF");
+}
+
+
+void MoveObject_LINEDEF(void)
+{
+ GFXEvent ev;
+ int omx,omy;
+ int dmx,dmy;
+ int done;
+ Iterator i;
+ Iterator i2;
+ EditLine *l;
+ List orig;
+ int *f,r;
+ Point p;
+ unsigned char *vmap;
+ int cancel;
+
+ TRACE;
+
+ omx=SnapX(XToMap(ms.x));
+ omy=SnapY(YToMap(ms.y));
+ GFX_bounce();
+
+ done=FALSE;
+ cancel=FALSE;
+ orig=ListNew(sizeof(Point));
+
+ vmap=Grab(MapSize(vertex));
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ f=IteratorData(i);
+ l=GETLINE(*f);
+ p.x=l->v[0]->v.x;
+ p.y=l->v[0]->v.y;
+ ListAppend(orig,&p);
+ p.x=l->v[1]->v.x;
+ p.y=l->v[1]->v.y;
+ ListAppend(orig,&p);
+ i=IteratorNext(i);
+ }
+
+ while(!done)
+ {
+ GuiDrawInfoBox("Move LINEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE,
+ "Left mouse button to place|ESC to cancel");
+
+ GFX_redraw();
+ GFX_await_input_full(&ev);
+
+ switch(ev.type)
+ {
+ case GFX_KEY_EVENT:
+ HandleMoveKey(ev.key,FALSE);
+
+ /* Cancel the move
+ */
+ if (ev.key.code==GFX_ESC)
+ {
+ cancel=TRUE;
+
+ i=ListIterator(selected);
+ i2=ListIterator(orig);
+
+ while(i2)
+ {
+ f=IteratorData(i);
+
+ l=GETLINE(*f);
+
+ memcpy(&p,IteratorData(i2),sizeof(Point));
+ l->v[0]->v.x=p.x;
+ l->v[0]->v.y=p.y;
+ i2=IteratorNext(i2);
+
+ memcpy(&p,IteratorData(i2),sizeof(Point));
+ l->v[1]->v.x=p.x;
+ l->v[1]->v.y=p.y;
+ i2=IteratorNext(i2);
+
+ i=IteratorNext(i);
+ }
+
+ done=TRUE;
+ dmx=0;
+ dmy=0;
+ }
+ else
+ {
+ dmx=SnapX(XToMap(ms.x))-omx;
+ dmy=SnapY(YToMap(ms.y))-omy;
+ }
+
+ break;
+
+ case GFX_MOUSE_EVENT:
+ memcpy(&ms,&ev.mouse,sizeof(ev.mouse));
+
+ if (ms.b&GFX_BUTLEFT)
+ done=TRUE;
+
+ dmx=SnapX(XToMap(ms.x))-omx;
+ dmy=SnapY(YToMap(ms.y))-omy;
+ break;
+
+ default:
+ dmx=0;
+ dmy=0;
+ break;
+ }
+
+ if ((dmx)||(dmy))
+ {
+ for(r=0;r<MapSize(vertex);r++)
+ vmap[r]=FALSE;
+
+ i=ListIterator(selected);
+ while(i)
+ {
+ f=IteratorData(i);
+
+ l=GETLINE(*f);
+
+ if (!vmap[l->l.from])
+ {
+ l->v[0]->v.x+=dmx;
+ l->v[0]->v.y+=dmy;
+ vmap[l->l.from]=TRUE;
+ }
+
+ if (!vmap[l->l.to])
+ {
+ l->v[1]->v.x+=dmx;
+ l->v[1]->v.y+=dmy;
+ vmap[l->l.to]=TRUE;
+ }
+
+ i=IteratorNext(i);
+ }
+
+ omx=SnapX(XToMap(ms.x));
+ omy=SnapY(YToMap(ms.y));
+
+ FullRedraw();
+ }
+ }
+
+ ListClear(orig);
+ Release(vmap);
+
+ if ((clear_on_move)&&(!cancel))
+ ClearSelection();
+
+ FullRedraw();
+}
+
+
+void RotateObject_LINEDEF(double angle)
+{
+ int cx,cy;
+ int x,y;
+ int *f;
+ Iterator i;
+ EditLine *l;
+
+ TRACE;
+
+ InitVMAP();
+
+ LineSelectionCentre(&cx,&cy);
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ f=IteratorData(i);
+ l=GETLINE(*f);
+
+ if (!vmap[l->l.from])
+ {
+ vmap[l->l.from]=TRUE;
+ x=l->v[0]->v.x;
+ y=l->v[0]->v.y;
+
+ Rotate(cx,cy,&x,&y,angle);
+
+ l->v[0]->v.x=x;
+ l->v[0]->v.y=y;
+ }
+
+ if (!vmap[l->l.to])
+ {
+ vmap[l->l.to]=TRUE;
+ x=l->v[1]->v.x;
+ y=l->v[1]->v.y;
+
+ Rotate(cx,cy,&x,&y,angle);
+
+ l->v[1]->v.x=x;
+ l->v[1]->v.y=y;
+ }
+
+ i=IteratorNext(i);
+ }
+}
+
+
+void ScaleObject_LINEDEF(double scale)
+{
+ int cx,cy;
+ int x,y;
+ int *f;
+ Iterator i;
+ EditLine *l;
+
+ TRACE;
+
+ LineSelectionCentre(&cx,&cy);
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ f=IteratorData(i);
+ l=GETLINE(*f);
+
+ x=l->v[0]->v.x;
+ y=l->v[0]->v.y;
+
+ Scale(cx,cy,&x,&y,scale);
+
+ l->v[0]->v.x=x;
+ l->v[0]->v.y=y;
+
+ x=l->v[1]->v.x;
+ y=l->v[1]->v.y;
+
+ Scale(cx,cy,&x,&y,scale);
+
+ l->v[1]->v.x=x;
+ l->v[1]->v.y=y;
+
+ i=IteratorNext(i);
+ }
+}
+
+
+void SetTagObject_LINEDEF(int tag)
+{
+ int *f;
+ Iterator i;
+ EditLine *l;
+
+ TRACE;
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ f=IteratorData(i);
+ l=GETLINE(*f);
+ l->l.tag=tag;
+ i=IteratorNext(i);
+ }
+}
+
+
+void LocateObject_LINEDEF(void *obj)
+{
+ int cx,cy;
+ EditLine *l;
+
+ TRACE;
+
+ l=obj;
+ cx=l->min_x+(l->max_x-l->min_x)/2;
+ cy=l->min_y+(l->max_y-l->min_y)/2;
+ ox=cx-scale*SCRW/2;
+ oy=cy+scale*SCRH/2;
+}
+
+
+void ObjectInsert_LINEDEF(void)
+{
+ int type;
+ int fl,two;
+ DirName sr_upper,sr_lower,sr_middle;
+ DirName sl_upper,sl_lower,sl_middle;
+ int ok;
+ int from,to;
+ int nl;
+ EditVert *v;
+
+ TRACE;
+
+ if (MapSize(vertex)<2)
+ {
+ GuiInfoBox("ERROR","Need more that 2 vertices|to make a line");
+ FullRedraw();
+ }
+ else
+ {
+ vertex_dialog[D_VERTEX_FROM].data.i=MapSize(vertex)-2;
+ vertex_dialog[D_VERTEX_TO].data.i=MapSize(vertex)-1;
+
+ ok=GUI_dialog("Create LINEDEF",D_VERTEX_NO,vertex_dialog);
+
+ if (ok)
+ {
+ from=vertex_dialog[D_VERTEX_FROM].data.i;
+ to=vertex_dialog[D_VERTEX_TO].data.i;
+
+ if ((from>=MapSize(vertex))||(from<0)||(!GETVERT(from)))
+ {
+ GuiInfoBox("ERROR","%d (from) is an invalid vertex",from);
+ FullRedraw();
+ ok=FALSE;
+ }
+ else if ((to>=MapSize(vertex))||(to<0)||(!GETVERT(to)))
+ {
+ GuiInfoBox("ERROR","%d (to) is an invalid vertex",to);
+ FullRedraw();
+ ok=FALSE;
+ }
+ }
+
+ if (ok)
+ if (GetLinedefValues(TRUE,0,0,0,0,
+ &type,&fl,&two,
+ sr_upper,sr_middle,sr_lower,
+ sl_upper,sl_middle,sl_lower))
+ {
+ nl=CreateNewLinedef(from,to,
+ fl,type,0,two,
+ 0,0,0,
+ sr_upper,sr_middle,sr_lower,
+ 0,0,0,
+ sl_upper,sl_middle,sl_lower);
+
+ v=GETVERT(from);
+ IntListUniqAdd(v->l,from);
+ v=GETVERT(to);
+ IntListUniqAdd(v->l,from);
+
+ FullRedraw();
+ }
+ }
+}
+
+
+void ObjectDelete_LINEDEF(void)
+{
+ Iterator i;
+ int *f;
+
+ TRACE;
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ f=IteratorData(i);
+ DeleteLinedef(*f);
+ i=IteratorNext(i);
+ }
+
+ SectorCalcContainingAll();
+ ClearSelection();
+ FullRedraw();
+}
+
+
+void ObjectMenu_LINEDEF(void)
+{
+ static int ax=0;
+ static int ay=0;
+ EditLine *l;
+ int f,*s;
+ Iterator i;
+ int cancel;
+ int opt;
+
+ TRACE;
+
+ s=NULL;
+ cancel=FALSE;
+ GFX_redraw();
+
+ opt=GUI_menu("Linedef/sidedef",ms.x,ms.y,linedef_popup,GUI_CANCEL);
+
+ switch(opt)
+ {
+ case TM_RIGHT_SIDE:
+ opt=GUI_menu("Right sidedef",ms.x,ms.y,right_popup,GUI_CANCEL);
+ break;
+
+ case TM_LEFT_SIDE:
+ opt=GUI_menu("Left sidedef",ms.x,ms.y,left_popup,GUI_CANCEL);
+ break;
+
+ default:
+ break;
+ }
+
+ switch(opt)
+ {
+ case TM_TYPE:
+ {
+ f=SelectLinedef();
+
+ if (f!=LINEDEF_NULLID)
+ {
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ l->l.type=f;
+ i=IteratorNext(i);
+ }
+
+ FullRedraw();
+ }
+ break;
+ }
+
+ case TM_FLAGS:
+ l=SelHead();
+ f=l->l.flags;
+
+ if (GUI_multi_box("Flags",LinedefFlagArray(),&f))
+ {
+ int new_side;
+ List new;
+
+ new=ListNew(sizeof(int));
+ new_side=FALSE;
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ int new_f;
+
+ new_f=f;
+ s=IteratorData(i);
+ l=GETLINE(*s);
+
+ /* If the line was 2 sided, and is now one - removed the
+ left sidedef
+ */
+ if ((l->l.flags&side2_mask)&&(!(new_f&side2_mask)))
+ {
+ DeleteLeftSidedef(l);
+
+ if (auto_block_linedefs)
+ new_f|=block_mask;
+ }
+
+ /* If the line was 1 sided, and is now two - add the
+ left sidedef
+ */
+ if ((!(l->l.flags&side2_mask))&&(new_f&side2_mask))
+ {
+ Object o;
+ Sidedef *ns;
+ int n;
+
+ ns=Grab(sizeof(Sidedef));
+ ns->x=0;
+ ns->y=0;
+ strcpy(ns->upper,empty_texture);
+ strcpy(ns->middle,empty_texture);
+ strcpy(ns->lower,empty_texture);
+ ns->sector=-1;
+
+ o.data=ns;
+ o.select=SELECT_NONE;
+
+ n=MapSize(sidedef);
+ MapAdd(sidedef,n,&o);
+ l->sl=ns;
+ l->l.left=n;
+
+ new_side=TRUE;
+
+ ListAppend(new,s);
+
+ if (auto_block_linedefs)
+ new_f&=~block_mask;
+ }
+
+ l->l.flags=new_f;
+ i=IteratorNext(i);
+ }
+
+ if (new_side)
+ switch(new_2sided_select)
+ {
+ case NEWSELECT_NEVER:
+ GuiInfoBox("NOTICE","Left SIDEDEFS have been added|"
+ "to some or all LINEDEFS");
+ break;
+
+ /* WARNING: This case cascades into the following
+ one
+ */
+ case NEWSELECT_ASK:
+ if (!YesNo("New left SIDEDEFS created. "
+ "Select those LINEDEFS?"))
+ break;
+ case NEWSELECT_SELECT:
+ {
+ Object *o;
+
+ new_selection=TRUE;
+ ClearSelection();
+ i=ListIterator(new);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ o=MapElem(linedef,*s);
+ SetSelect(*s,SELECT_SELECTED);
+ ListAppend(selected,s);
+ i=IteratorNext(i);
+ }
+ break;
+ }
+ }
+
+ ListClear(new);
+
+ FullRedraw();
+ }
+
+ break;
+
+ case TM_SWAP_SIDES:
+ {
+ int tmp;
+ Sidedef *tmp_s;
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+
+ if (l->l.left!=-1)
+ {
+ tmp=l->l.left;
+ tmp_s=l->sl;
+
+ l->sl=l->sr;
+ l->l.left=l->l.right;
+
+ l->sr=tmp_s;
+ l->l.right=tmp;
+
+ tmp=l->l.from;
+ l->l.from=l->l.to;
+ l->l.to=tmp;
+
+ l->v[0]=GETVERT(l->l.from);
+ l->v[1]=GETVERT(l->l.to);
+ }
+
+ i=IteratorNext(i);
+ }
+
+ SectorCalcContainingAll();
+ FullRedraw();
+
+ break;
+ }
+
+ case TM_SPLIT_LINE:
+ {
+ List new;
+ int no;
+ Object *o;
+
+ new=ListNew(sizeof(int));
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ no=SplitLinedef(*s);
+ ListAppend(new,&no);
+ i=IteratorNext(i);
+ }
+
+ i=ListIterator(new);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ o=MapElem(linedef,*s);
+ SetSelect(*s,SELECT_SELECTED);
+
+ ListAppend(selected,s);
+ i=IteratorNext(i);
+ }
+
+ ListClear(new);
+ SectorCalcContainingAll();
+ FullRedraw();
+
+ break;
+ }
+
+ case TM_TRACK_LINE:
+ {
+ List new;
+ Object *o;
+
+ i=ListIterator(selected);
+
+ *s=MapSize(linedef)+1;
+
+ while(i)
+ {
+ s=IteratorData(i);
+ i=IteratorNext(i);
+ }
+
+ if ((new=TrackLinedef(*s)))
+ {
+ ClearSelection();
+ i=ListIterator(new);
+
+ while(i)
+ {
+ s=IteratorData(i);
+
+ o=MapElem(linedef,*s);
+ SetSelect(*s,SELECT_SELECTED);
+ ListAppend(selected,s);
+
+ i=IteratorNext(i);
+ }
+
+ ListClear(new);
+ new_selection=TRUE;
+ FullRedraw();
+ }
+
+ break;
+ }
+
+ case TM_STEPS:
+ if (ListSize(selected)!=2)
+ GuiInfoBox("ERROR","Just select 2 linedefs|for this function");
+ else
+ {
+ int *l1,*l2;
+
+ i=ListIterator(selected);
+ l1=IteratorData(i);
+ i=IteratorNext(i);
+ l2=IteratorData(i);
+ IteratorClear(i);
+
+ cancel=CreateSteps(*l1,*l2);
+ }
+
+ FullRedraw();
+ break;
+
+
+ case TM_OFFSET_R:
+ l=SelHead();
+
+ offset_dialog[D_OFFSET_OFFX].data.i=l->sr->x;
+ offset_dialog[D_OFFSET_OFFY].data.i=l->sr->y;
+
+ if (GUI_dialog("Right offset",D_OFFSET_NO,offset_dialog))
+ {
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ if (l->sr)
+ {
+ l->sr->x=offset_dialog[D_OFFSET_OFFX].data.i;
+ l->sr->y=offset_dialog[D_OFFSET_OFFY].data.i;
+ }
+ i=IteratorNext(i);
+ }
+
+ i=IteratorClear(i);
+ FullRedraw();
+ }
+
+ break;
+
+ case TM_ADJUST_R:
+ l=SelHead();
+
+ offset_dialog[D_OFFSET_OFFX].data.i=ax;
+ offset_dialog[D_OFFSET_OFFY].data.i=ay;
+
+ if (GUI_dialog("Right offset adjustment",D_OFFSET_NO,offset_dialog))
+ {
+ ax=offset_dialog[D_OFFSET_OFFX].data.i;
+ ay=offset_dialog[D_OFFSET_OFFY].data.i;
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ if (l->sr)
+ {
+ l->sr->x+=ax;
+ l->sr->y+=ay;
+ }
+ i=IteratorNext(i);
+ }
+
+ i=IteratorClear(i);
+ FullRedraw();
+ }
+
+ break;
+
+ case TM_SECTOR_R:
+ l=SelHead();
+
+ sectorn_dialog[D_SECTORN_SECNO].data.i=l->sr->sector;
+
+ if (GUI_dialog("Right sector",D_SECTORN_NO,sectorn_dialog))
+ {
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ if (l->sr)
+ l->sr->sector=sectorn_dialog[D_SECTORN_SECNO].data.i;
+ i=IteratorNext(i);
+ }
+
+ i=IteratorClear(i);
+ SectorCalcContainingAll();
+ FullRedraw();
+ }
+
+ break;
+
+ case TM_UPPER_T_R:
+ {
+ DirName d;
+
+ if ((GetTexture("Upper Right texture",d)))
+ {
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ strcpy(l->sr->upper,d);
+ i=IteratorNext(i);
+ }
+
+ FullRedraw();
+ }
+
+ break;
+ }
+
+ case TM_MIDDLE_T_R:
+ {
+ DirName d;
+
+ if ((GetTexture("Middle Right texture",d)))
+ {
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ strcpy(l->sr->middle,d);
+ i=IteratorNext(i);
+ }
+
+ FullRedraw();
+ }
+
+ break;
+ }
+
+ case TM_LOWER_T_R:
+ {
+ DirName d;
+
+ if ((GetTexture("Lower Right texture",d)))
+ {
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ strcpy(l->sr->lower,d);
+ i=IteratorNext(i);
+ }
+
+ FullRedraw();
+ }
+
+ break;
+ }
+
+ case TM_ALIGN_R:
+ {
+ int tw;
+ int ox;
+
+ l=SelHead();
+
+ tw=CalcTextureWidth(l->sr->upper,l->sr->middle,l->sr->lower);
+
+ if (tw==0)
+ {
+ GuiInfoBox("ERROR","First selected linedef has no texture");
+ FullRedraw();
+ }
+ else
+ {
+ ox=l->sr->x;
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+
+ l=GETLINE(*s);
+
+ l->sr->x=ox;
+
+ ox=(ox+Len(l->v[0]->v.x,l->v[0]->v.y,
+ l->v[1]->v.x,l->v[1]->v.y))%tw;
+
+ i=IteratorNext(i);
+ }
+
+ FullRedraw();
+ }
+
+ }
+ break;
+
+
+ case TM_OFFSET_L:
+ l=SelHead();
+
+ if (l->sl)
+ {
+ offset_dialog[D_OFFSET_OFFX].data.i=l->sl->x;
+ offset_dialog[D_OFFSET_OFFY].data.i=l->sl->y;
+ }
+
+ if (GUI_dialog("Left offset",D_OFFSET_NO,offset_dialog))
+ {
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ if (l->sl)
+ {
+ l->sl->x=offset_dialog[D_OFFSET_OFFX].data.i;
+ l->sl->y=offset_dialog[D_OFFSET_OFFY].data.i;
+ }
+ i=IteratorNext(i);
+ }
+
+ i=IteratorClear(i);
+ FullRedraw();
+ }
+
+ break;
+
+ case TM_ADJUST_L:
+ l=SelHead();
+
+ offset_dialog[D_OFFSET_OFFX].data.i=ax;
+ offset_dialog[D_OFFSET_OFFY].data.i=ay;
+
+ if (GUI_dialog("Left offset adjustment",D_OFFSET_NO,offset_dialog))
+ {
+ ax=offset_dialog[D_OFFSET_OFFX].data.i;
+ ay=offset_dialog[D_OFFSET_OFFY].data.i;
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ if (l->sl)
+ {
+ l->sl->x+=ax;
+ l->sl->y+=ay;
+ }
+ i=IteratorNext(i);
+ }
+
+ i=IteratorClear(i);
+ FullRedraw();
+ }
+
+ break;
+
+ case TM_SECTOR_L:
+ l=SelHead();
+
+ if (l->sl)
+ sectorn_dialog[D_SECTORN_SECNO].data.i=l->sl->sector;
+
+ if (GUI_dialog("Left sector",D_SECTORN_NO,sectorn_dialog))
+ {
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ if (l->sl)
+ l->sl->sector=sectorn_dialog[D_SECTORN_SECNO].data.i;
+ i=IteratorNext(i);
+ }
+
+ i=IteratorClear(i);
+ SectorCalcContainingAll();
+ FullRedraw();
+ }
+
+ break;
+
+ case TM_UPPER_T_L:
+ {
+ DirName d;
+
+ if ((GetTexture("Upper Left texture",d)))
+ {
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ if (l->sl)
+ strcpy(l->sl->upper,d);
+ i=IteratorNext(i);
+ }
+
+ FullRedraw();
+ }
+
+ break;
+ }
+
+ case TM_MIDDLE_T_L:
+ {
+ DirName d;
+
+ if ((GetTexture("Middle Left texture",d)))
+ {
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ if (l->sl)
+ strcpy(l->sl->middle,d);
+ i=IteratorNext(i);
+ }
+
+ FullRedraw();
+ }
+
+ break;
+ }
+
+ case TM_LOWER_T_L:
+ {
+ DirName d;
+
+ if ((GetTexture("Lower Left texture",d)))
+ {
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+ if (l->sl)
+ strcpy(l->sl->lower,d);
+ i=IteratorNext(i);
+ }
+
+ FullRedraw();
+ }
+
+ break;
+ }
+
+ case TM_ALIGN_L:
+ {
+ int tw;
+ int ox;
+ int ok;
+
+ ok=TRUE;
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+ l=GETLINE(*s);
+
+ if (!(l->sl))
+ ok=FALSE;
+
+ i=IteratorNext(i);
+ }
+
+ if (!ok)
+ {
+ GuiInfoBox("ERROR","Some linedefs with no left sidedef");
+ FullRedraw();
+ }
+ else
+ {
+ l=SelHead();
+
+ tw=CalcTextureWidth(l->sl->upper,l->sl->middle,l->sl->lower);
+
+ if (tw==0)
+ {
+ GuiInfoBox("ERROR","First selected linedef has no texture");
+ FullRedraw();
+ }
+ else
+ {
+ ox=l->sl->x;
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ s=IteratorData(i);
+
+ l=GETLINE(*s);
+
+ l->sl->x=ox;
+
+ ox=(ox+Len(l->v[0]->v.x,l->v[0]->v.y,
+ l->v[1]->v.x,l->v[1]->v.y))%tw;
+
+ i=IteratorNext(i);
+ }
+
+ FullRedraw();
+ }
+ }
+
+ }
+ break;
+
+
+ case TM_TAG:
+ l=SelHead();
+ tag_dialog[D_TAG].data.i=l->l.tag;
+
+ if (GUI_dialog("Tag",D_TAG_NO,tag_dialog))
+ {
+ SetTagObject_LINEDEF(tag_dialog[D_TAG].data.i);
+ FullRedraw();
+ }
+
+ break;
+
+ case TM_DELETE:
+ ObjectDelete_LINEDEF();
+ break;
+
+ case TM_MOVE:
+ MoveObject_LINEDEF();
+ break;
+
+ default:
+ cancel=TRUE;
+ break;
+ }
+
+ if ((!cancel)&&(!new_selection)&&(clear_on_menu))
+ {
+ ClearSelection();
+ FullRedraw();
+ }
+}
+
+
+void ObjectKey_LINEDEF(GFXKey k)
+{
+ char s[128];
+ EditLine *l;
+ int f;
+ int change;
+ List li;
+ Iterator i;
+ EditSect *sr,*sl;
+ DirName d;
+ Object *o;
+ int apply;
+
+ TRACE;
+
+ switch(k.code)
+ {
+ case GFX_F12:
+ li=ListNew(sizeof(int));
+
+ change=FALSE;
+
+ if (ListSize(selected)==0)
+ {
+ GuiInfoBox("ERROR","No linedefs selected");
+ FullRedraw();
+ return;
+ }
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ memcpy(&f,IteratorData(i),sizeof(f));
+
+ if ((l=GETLINE(f)))
+ {
+ TRACE;
+ if (check_1side_lower)
+ if ((!l->sl)&&(strcmp(l->sr->lower,empty_texture)))
+ if ((check_line_assume_yes)||
+ (YesNo("LINEDEF %d is one-sided with a "
+ "lower texture. Remove?",f)))
+ {
+ strcpy(l->sr->lower,empty_texture);
+ change=TRUE;
+ IntListUniqAdd(li,f);
+ }
+
+ TRACE;
+ if (check_1side_middle)
+ if ((!l->sl)&&(!strcmp(l->sr->middle,empty_texture)))
+ if ((check_line_assume_yes)||
+ (YesNo("LINEDEF %d is one-sided with no "
+ "middle texture. Add?",f)))
+ {
+ sprintf(s,"Pick MIDDLE texture "
+ "for LINEDEF %d",f);
+
+ if (strcmp(linedef_check_default,empty_texture))
+ {
+ apply=TRUE;
+ strcpy(d,linedef_check_default);
+ }
+ else
+ apply=GetTexture(s,d);
+
+ if (apply)
+ {
+ strcpy(l->sr->middle,d);
+ change=TRUE;
+ IntListUniqAdd(li,f);
+ }
+ }
+
+ TRACE;
+ if (check_1side_upper)
+ if ((!l->sl)&&(strcmp(l->sr->upper,empty_texture)))
+ if ((check_line_assume_yes)||
+ (YesNo("LINEDEF %d is one-sided with a "
+ "upper texture. Remove?",f)))
+ {
+ strcpy(l->sr->upper,empty_texture);
+ change=TRUE;
+ IntListUniqAdd(li,f);
+ }
+
+ TRACE;
+ if ((check_2side_lower)&&(l->sl)&&(l->sl->sector!=-1)&&
+ (l->sr->sector!=-1))
+ {
+ sr=GETSECT(l->sr->sector);
+ sl=GETSECT(l->sl->sector);
+
+ if ((sr->s.floor<sl->s.floor)&&
+ (!strcmp(l->sr->lower,empty_texture)))
+ if ((check_line_assume_yes)||
+ (YesNo("LINEDEF %d is two-sided with no "
+ "lower texture. Add?",f)))
+ {
+ sprintf(s,"Pick LOWER texture "
+ "for LINEDEF %d",f);
+
+ if (strcmp(linedef_check_default,empty_texture))
+ {
+ apply=TRUE;
+ strcpy(d,linedef_check_default);
+ }
+ else
+ apply=GetTexture(s,d);
+
+ if (apply)
+ {
+ strcpy(l->sr->lower,d);
+ strcpy(l->sl->lower,empty_texture);
+ change=TRUE;
+ IntListUniqAdd(li,f);
+ }
+ }
+
+ if ((sr->s.floor>sl->s.floor)&&
+ (!strcmp(l->sl->lower,empty_texture)))
+ if ((check_line_assume_yes)||
+ (YesNo("LINEDEF %d is two-sided with no "
+ "lower texture. Add?",f)))
+ {
+ sprintf(s,"Pick LOWER texture "
+ "for LINEDEF %d",f);
+
+ if (strcmp(linedef_check_default,empty_texture))
+ {
+ apply=TRUE;
+ strcpy(d,linedef_check_default);
+ }
+ else
+ apply=GetTexture(s,d);
+
+ if (apply)
+ {
+ strcpy(l->sl->lower,d);
+ strcpy(l->sr->lower,empty_texture);
+ change=TRUE;
+ IntListUniqAdd(li,f);
+ }
+ }
+
+ if ((sr->s.floor==sl->s.floor)&&
+ ((strcmp(l->sl->lower,empty_texture))||
+ (strcmp(l->sr->lower,empty_texture))))
+ if ((check_line_assume_yes)||
+ (YesNo("LINEDEF %d is two-sided with pointless "
+ "lower texture. Remove?",f)))
+ {
+ strcpy(l->sl->lower,empty_texture);
+ strcpy(l->sr->lower,empty_texture);
+ change=TRUE;
+ IntListUniqAdd(li,f);
+ }
+ }
+
+ TRACE;
+ if ((check_2side_middle)&&(l->sl)&&(l->sl->sector!=-1))
+ {
+ if (((strcmp(l->sr->middle,empty_texture))||
+ (strcmp(l->sl->middle,empty_texture)))&&
+ (l->sl->sector!=l->sr->sector))
+ if ((check_line_assume_yes)||
+ (YesNo("LINEDEF %d is two-sided with a "
+ "middle texture. Remove?",f)))
+ {
+ strcpy(l->sr->middle,empty_texture);
+ strcpy(l->sl->middle,empty_texture);
+ change=TRUE;
+ IntListUniqAdd(li,f);
+ }
+ }
+
+ TRACE;
+ if ((check_2side_upper)&&(l->sl)&&(l->sl->sector!=-1)&&
+ (l->sr->sector!=-1))
+ {
+ sr=GETSECT(l->sr->sector);
+ sl=GETSECT(l->sl->sector);
+
+ if ((sr->s.ceiling>sl->s.ceiling)&&
+ (!strcmp(l->sr->upper,empty_texture)))
+ if ((check_line_assume_yes)||
+ (YesNo("LINEDEF %d is two-sided with no "
+ "upper texture. Add?",f)))
+ {
+ sprintf(s,"Pick UPPER texture "
+ "for LINEDEF %d",f);
+
+ if (strcmp(linedef_check_default,empty_texture))
+ {
+ apply=TRUE;
+ strcpy(d,linedef_check_default);
+ }
+ else
+ apply=GetTexture(s,d);
+
+ if (apply)
+ {
+ strcpy(l->sr->upper,d);
+ strcpy(l->sl->upper,empty_texture);
+ change=TRUE;
+ IntListUniqAdd(li,f);
+ }
+ }
+
+ if ((sr->s.ceiling<sl->s.ceiling)&&
+ (!strcmp(l->sl->upper,empty_texture)))
+ if ((check_line_assume_yes)||
+ (YesNo("LINEDEF %d is two-sided with no "
+ "upper texture. Add?",f)))
+ {
+ sprintf(s,"Pick UPPER texture "
+ "for LINEDEF %d",f);
+
+ if (strcmp(linedef_check_default,empty_texture))
+ {
+ apply=TRUE;
+ strcpy(d,linedef_check_default);
+ }
+ else
+ apply=GetTexture(s,d);
+
+ if (apply)
+ {
+ strcpy(l->sl->upper,d);
+ strcpy(l->sr->upper,empty_texture);
+ change=TRUE;
+ IntListUniqAdd(li,f);
+ }
+ }
+
+ if ((sr->s.ceiling==sl->s.ceiling)&&
+ ((strcmp(l->sl->upper,empty_texture))||
+ (strcmp(l->sr->upper,empty_texture))))
+ if ((check_line_assume_yes)||
+ (YesNo("LINEDEF %d is two-sided with pointless "
+ "upper texture. Remove?",f)))
+ {
+ strcpy(l->sl->upper,empty_texture);
+ strcpy(l->sr->upper,empty_texture);
+ change=TRUE;
+ IntListUniqAdd(li,f);
+ }
+ }
+
+ TRACE;
+ if ((check_2side_same_sector)&&(l->sl)&&(l->sl->sector!=-1))
+ {
+ if ((l->sl->sector==l->sr->sector)&&
+ ((strcmp(l->sr->lower,empty_texture))||
+ (strcmp(l->sr->middle,empty_texture))||
+ (strcmp(l->sr->upper,empty_texture))||
+ (strcmp(l->sl->lower,empty_texture))||
+ (strcmp(l->sl->middle,empty_texture))||
+ (strcmp(l->sl->upper,empty_texture))))
+ if ((check_line_assume_yes)||
+ (YesNo("LINEDEF %d is two-sided within a "
+ "sector and is textured. Remove all?",f)))
+ {
+ strcpy(l->sr->lower,empty_texture);
+ strcpy(l->sl->lower,empty_texture);
+ strcpy(l->sr->middle,empty_texture);
+ strcpy(l->sl->middle,empty_texture);
+ strcpy(l->sr->upper,empty_texture);
+ strcpy(l->sl->upper,empty_texture);
+ change=TRUE;
+ IntListUniqAdd(li,f);
+ }
+ }
+
+ }
+
+ i=IteratorNext(i);
+ }
+
+ if (change)
+ {
+ if (YesNo("Select altered LINEDEFs?"))
+ {
+ ClearSelection();
+ i=ListIterator(li);
+
+ while(i)
+ {
+ memcpy(&f,IteratorData(i),sizeof(int));
+ o=MapElem(linedef,f);
+ SetSelect(f,SELECT_SELECTED);
+ ListAppend(selected,&f);
+ i=IteratorNext(i);
+ }
+
+ FullRedraw();
+ }
+ }
+ else
+ {
+ GuiInfoBox("NOTICE","No problems found");
+ FullRedraw();
+ }
+
+ ListClear(li);
+ break;
+
+ default:
+
+ case GFX_ASCII:
+ switch(toupper(k.ascii))
+ {
+ case 'H':
+ tag_highlight=!tag_highlight;
+ FullRedraw();
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+}
+
+
+int ObjectHasTag_LINEDEF(void *obj, int tag)
+{
+ EditLine *l;
+
+ return ((l=obj)&&(l->l.tag==tag));
+}
+
+
+/* END OF FILE */