summaryrefslogtreecommitdiff
path: root/editvert.c
diff options
context:
space:
mode:
Diffstat (limited to 'editvert.c')
-rw-r--r--editvert.c834
1 files changed, 834 insertions, 0 deletions
diff --git a/editvert.c b/editvert.c
new file mode 100644
index 0000000..361aa00
--- /dev/null
+++ b/editvert.c
@@ -0,0 +1,834 @@
+/*
+
+ 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 VERTEX definitions
+
+*/
+static const char rcs_id[]="$Id$";
+
+#include "config.h"
+#include "globals.h"
+
+#include "editvar.h"
+
+
+/* ---------------------------------------- PRIVATE UTILS
+*/
+static void VertexSelectionCentre(int *x,int *y)
+{
+ int *f;
+ EditVert *v;
+ Iterator i;
+ int min_x,min_y,max_x,max_y;
+
+ VIDOOM_TRACE;
+
+ i=ListIterator(selected);
+
+ min_x=99999;
+ min_y=99999;
+ max_x=-99999;
+ max_y=-99999;
+
+ while(i)
+ {
+ f=IteratorData(i);
+ v=GETVERT(*f);
+
+ min_x=MIN(v->v.x,min_x);
+ min_y=MIN(v->v.y,min_y);
+ max_x=MAX(v->v.x,max_x);
+ max_y=MAX(v->v.y,max_y);
+
+ i=IteratorNext(i);
+ }
+
+ *x=min_x+(max_x-min_x)/2;
+ *y=min_y+(max_y-min_y)/2;
+}
+
+
+static void MergeVertex(int new,int old)
+{
+ Object *o;
+ EditVert *v;
+ EditLine *l;
+ int f;
+
+ o=MapElem(vertex,old);
+ v=o->data;
+ ListClear(v->l);
+ Release(o->data);
+ o->data=NULL;
+ o->select=SELECT_NONE;
+
+ v=GETVERT(new);
+
+ for(f=0;f<MapSize(linedef);f++)
+ if ((l=GETLINE(f)))
+ {
+ if (l->l.from==old)
+ {
+ l->l.from=new;
+ l->v[0]=v;
+ IntListUniqAdd(v->l,f);
+ }
+
+ if (l->l.to==old)
+ {
+ l->l.to=new;
+ l->v[1]=v;
+ IntListUniqAdd(v->l,f);
+ }
+ }
+
+ if (merge_linedef!=MERGE_NEVER)
+ {
+ v=GETVERT(new);
+ CheckMergeLinedef(v);
+ }
+}
+
+/* ---------------------------------------- GENERIC VERTEX FUNCS
+*/
+int PositionOnObject_VERTEX(int x,int y,void *data)
+{
+ EditVert *v;
+
+ VIDOOM_TRACE;
+
+ v=data;
+ return (RADBOUND(x,y,v->v.x,v->v.y,vertex_rad));
+}
+
+
+void SelectBox_VERTEX(int x1,int y1,int x2,int y2)
+{
+ Object *o;
+ EditVert *v;
+ int f;
+
+ VIDOOM_TRACE;
+
+ for(f=0;f<MapSize(vertex);f++)
+ {
+ o=MapElem(vertex,f);
+
+ if ((v=o->data))
+ {
+ if ((o->select!=SELECT_SELECTED)&&
+ (BOXBOUND(v->v.x,v->v.y,x1,y1,x2,y2)))
+ {
+ SetSelect(f,SELECT_SELECTED);
+ ListAppend(selected,&f);
+ }
+ }
+ }
+}
+
+
+void SelectByType_VERTEX(void)
+{
+ return;
+}
+
+
+void DrawObject_VERTEX(void *data, int selmode)
+{
+ EditVert *v;
+ int col;
+
+ VIDOOM_TRACE;
+ v=data;
+
+ MapPlot(v->v.x,v->v.y,VERTCOL);
+
+ switch(selmode)
+ {
+ case SELECT_OVER:
+ col=OVERCOL;
+ break;
+ case SELECT_SELECTED:
+ col=SELCOL;
+ break;
+ default:
+ col=VERTBOXCOL;
+ break;
+ }
+
+ MapRect(v->v.x-vertex_rad,v->v.y+vertex_rad,vertex_rad*2,vertex_rad*2,col);
+}
+
+
+void DrawObjectInfo_VERTEX(void)
+{
+ EditVert *v;
+
+ VIDOOM_TRACE;
+
+ if (!draw_current_info)
+ return;
+
+ if ((current!=-1)&&((v=GETVERT(current))))
+ GuiDrawInfoBox("VERTEX",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE,
+ "Vertex No : %10d|"
+ "X : %10d|"
+ "Y : %10d",
+ current,
+ v->v.x,v->v.y);
+ else
+ GuiDrawInfoBox("VERTEX",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE,
+ "Vertex No : - |"
+ "X : - |"
+ "Y : - ");
+}
+
+
+void DrawObjectHeader_VERTEX(void)
+{
+}
+
+
+void MoveObject_VERTEX(void)
+{
+ GFXEvent ev;
+ int omx,omy;
+ int dmx,dmy;
+ int done;
+ Iterator i;
+ Iterator i2;
+ EditVert *v,*v2;
+ List orig;
+ int *f;
+ int r;
+ Point p;
+ int cancel;
+ int done_merge;
+
+ VIDOOM_TRACE;
+
+ omx=SnapX(XToMap(ms.x));
+ omy=SnapY(YToMap(ms.y));
+ GFX_bounce();
+
+ done=FALSE;
+ cancel=FALSE;
+ done_merge=FALSE;
+ orig=ListNew(sizeof(Point));
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ f=IteratorData(i);
+ v=GETVERT(*f);
+ p.x=v->v.x;
+ p.y=v->v.y;
+ ListAppend(orig,&p);
+ i=IteratorNext(i);
+ }
+
+ while(!done)
+ {
+ GuiDrawInfoBox("Move VERTEX",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);
+ memcpy(&p,IteratorData(i2),sizeof(Point));
+ v=GETVERT(*f);
+ v->v.x=p.x;
+ v->v.y=p.y;
+
+ i=IteratorNext(i);
+ i2=IteratorNext(i2);
+ }
+
+ 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))
+ {
+ i=ListIterator(selected);
+ while(i)
+ {
+ f=IteratorData(i);
+
+ v=GETVERT(*f);
+
+ v->v.x+=dmx;
+ v->v.y+=dmy;
+
+ i=IteratorNext(i);
+ }
+
+ omx=SnapX(XToMap(ms.x));
+ omy=SnapY(YToMap(ms.y));
+
+ FullRedraw();
+ }
+ }
+
+ ListClear(orig);
+
+ if (!cancel)
+ {
+ int ask;
+ int ok;
+
+ ask=TRUE;
+ ok=TRUE;
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ f=IteratorData(i);
+
+ for(r=0;(r<MapSize(vertex))&&(ok);r++)
+ if (r!=*f)
+ {
+ v=GETVERT(*f);
+ v2=GETVERT(r);
+
+ if ((v)&&(v2))
+ if ((v->v.x==v2->v.x)&&(v->v.y==v2->v.y))
+ {
+ if (ask)
+ {
+ ok=YesNo("Merge overlapping vertexes?");
+ ask=FALSE;
+ }
+
+ if (ok)
+ {
+ MergeVertex(*f,r);
+ done_merge=TRUE;
+ }
+ }
+ }
+
+ i=IteratorNext(i);
+ }
+
+ if (done_merge)
+ SectorCalcContainingAll();
+ }
+
+ if ((clear_on_move)&&(!cancel))
+ ClearSelection();
+
+ FullRedraw();
+}
+
+
+void RotateObject_VERTEX(double angle)
+{
+ int cx,cy;
+ int x,y;
+ int *f;
+ Iterator i;
+ EditVert *v;
+
+ VIDOOM_TRACE;
+
+ VertexSelectionCentre(&cx,&cy);
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ f=IteratorData(i);
+ v=GETVERT(*f);
+
+ x=v->v.x;
+ y=v->v.y;
+
+ Rotate(cx,cy,&x,&y,angle);
+
+ v->v.x=x;
+ v->v.y=y;
+
+ i=IteratorNext(i);
+ }
+}
+
+
+void ScaleObject_VERTEX(double scale)
+{
+ int cx,cy;
+ int x,y;
+ int *f;
+ Iterator i;
+ EditVert *v;
+
+ VIDOOM_TRACE;
+
+ VertexSelectionCentre(&cx,&cy);
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ f=IteratorData(i);
+ v=GETVERT(*f);
+
+ x=v->v.x;
+ y=v->v.y;
+
+ Scale(cx,cy,&x,&y,scale);
+
+ v->v.x=x;
+ v->v.y=y;
+
+ i=IteratorNext(i);
+ }
+}
+
+
+void SetTagObject_VERTEX(int tag)
+{
+ VIDOOM_TRACE;
+}
+
+
+void LocateObject_VERTEX(void *obj)
+{
+ EditVert *v;
+
+ VIDOOM_TRACE;
+
+ v=obj;
+
+ ox=v->v.x-scale*SCRW/2;
+ oy=v->v.y+scale*SCRH/2;
+}
+
+
+void ObjectInsert_VERTEX(void)
+{
+ Object o;
+ EditVert *v;
+ int f;
+
+ VIDOOM_TRACE;
+
+ v=Grab(sizeof(EditVert));
+ v->v.x=SnapX(XToMap(ms.x));
+ v->v.y=SnapY(YToMap(ms.y));
+ v->l=ListNew(sizeof(int));
+
+ f=MapSize(vertex);
+
+ switch(insert_select)
+ {
+ case HOVER_NONE:
+ o.select=SELECT_NONE;
+ break;
+ case HOVER_ADD:
+ case HOVER_SINGLE:
+ o.select=SELECT_SELECTED;
+ break;
+ }
+
+ o.data=v;
+ DrawObject_VERTEX(v,o.select);
+ MapAdd(vertex,f,&o);
+
+ switch(insert_select)
+ {
+ case HOVER_NONE:
+ break;
+ case HOVER_ADD:
+ ListAppend(selected,&f);
+ break;
+ case HOVER_SINGLE:
+ ClearSelection();
+ ListAppend(selected,&f);
+ FullRedraw();
+ break;
+ }
+}
+
+
+void ObjectDelete_VERTEX(void)
+{
+ Iterator i;
+ Object *o;
+ EditVert *v;
+ int *f;
+ int bound;
+
+ VIDOOM_TRACE;
+
+ i=ListIterator(selected);
+ bound=FALSE;
+
+ while(i)
+ {
+ f=IteratorData(i);
+
+ o=MapElem(vertex,*f);
+ v=o->data;
+
+ if (ListSize(v->l))
+ bound=TRUE;
+ else
+ {
+ Release(o->data);
+ o->data=NULL;
+ o->select=SELECT_NONE;
+ }
+
+ i=IteratorNext(i);
+ }
+
+ ClearSelection();
+ FullRedraw();
+
+ if (bound)
+ GuiInfoBox("WARNING","1 or more VERTEX found still bound to LINEDEF|"
+ "These have not been deleted");
+}
+
+
+void ObjectMenu_VERTEX(void)
+{
+ Iterator i;
+ int from;
+ int to;
+ int first;
+ int type;
+ int flag;
+ int two;
+ int wr,wl;
+ int oxr,oxl;
+ DirName sr_upper,sr_middle,sr_lower;
+ DirName sl_upper,sl_middle,sl_lower;
+ EditVert *v1=NULL,*v2=NULL;
+ int cancel=FALSE;
+ int redraw=FALSE;
+ int in_sector;
+ int loop;
+ int nl;
+
+ VIDOOM_TRACE;
+
+ GFX_redraw();
+
+ switch(GUI_menu("Vertex",ms.x,ms.y,vertex_popup,GUI_CANCEL))
+ {
+ case TM_CHAIN:
+ cancel=TRUE;
+
+ if (ListSize(selected)<2)
+ GuiInfoBox("ERROR","Need 2 or more vertices|to chain a line");
+ else
+ {
+ if (GetLinedefValues(TRUE,0,0,0,0,
+ &type,&flag,&two,
+ sr_upper,sr_middle,sr_lower,
+ sl_upper,sl_middle,sl_lower))
+ {
+ if (ListSize(selected)>2)
+ loop=YesNo("Join last vertex to first one?");
+ else
+ loop=FALSE;
+
+ oxr=0;
+ oxl=0;
+
+ wr=CalcTextureWidth(sr_upper,sr_middle,sr_lower);
+
+ if (two)
+ wl=CalcTextureWidth(sl_upper,sl_middle,sl_lower);
+ else
+ wl=0;
+
+ i=ListIterator(selected);
+
+ memcpy(&to,IteratorData(i),sizeof(int));
+ i=IteratorNext(i);
+ first=to;
+
+ while(i)
+ {
+ from=to;
+ memcpy(&to,IteratorData(i),sizeof(int));
+ i=IteratorNext(i);
+
+ v1=GETVERT(from);
+ v2=GETVERT(to);
+
+ in_sector=SectorHoldingPoint(v1->v.x,v1->v.y);
+
+ nl=CreateNewLinedef(from,to,
+ flag,type,0,two,
+ oxr,0,in_sector,
+ sr_upper,sr_middle,sr_lower,
+ oxl,0,in_sector,
+ sl_upper,sl_middle,sl_lower);
+
+ IntListUniqAdd(v1->l,nl);
+ IntListUniqAdd(v2->l,nl);
+
+ if (wr)
+ oxr=(oxr+Len(v1->v.x,v1->v.y,v2->v.x,v2->v.y))%wr;
+
+ if ((two)&&(wl))
+ oxl=(oxl+Len(v1->v.x,v1->v.y,v2->v.x,v2->v.y))%wl;
+ }
+
+ in_sector=SectorHoldingPoint(v2->v.x,v2->v.y);
+
+ if (loop)
+ {
+ v1=GETVERT(to);
+ v2=GETVERT(first);
+
+ nl=CreateNewLinedef(to,first,
+ flag,type,0,two,
+ oxr,0,in_sector,
+ sr_upper,sr_middle,sr_lower,
+ oxl,0,in_sector,
+ sl_upper,sl_middle,sl_lower);
+
+ IntListUniqAdd(v1->l,nl);
+ IntListUniqAdd(v2->l,nl);
+ }
+
+ cancel=FALSE;
+ redraw=TRUE;
+
+ SectorCalcContainingAll();
+ }
+ }
+
+ break;
+
+ case TM_CHAIN_SECTOR:
+ if (CreateSector(selected))
+ redraw=TRUE;
+ else
+ cancel=TRUE;
+ break;
+
+ case TM_MERGE:
+ if (ListSize(selected)<2)
+ {
+ GuiInfoBox("ERROR","Need 2 or more vertices|to merge them");
+ cancel=TRUE;
+ }
+ else
+ {
+ redraw=TRUE;
+ i=ListIterator(selected);
+ memcpy(&first,IteratorData(i),sizeof(int));
+ i=IteratorNext(i);
+
+ while(i)
+ {
+ memcpy(&to,IteratorData(i),sizeof(int));
+ MergeVertex(first,to);
+ i=IteratorNext(i);
+ }
+
+ SectorCalcContainingAll();
+ }
+ break;
+
+ case TM_SNAP:
+ {
+ int orig_lock;
+ int *f;
+ EditVert *v;
+
+ orig_lock=grid_lock;
+ grid_lock=TRUE;
+
+ i=ListIterator(selected);
+
+ while(i)
+ {
+ f=IteratorData(i);
+ v=GETVERT(*f);
+
+ v->v.x=SnapX(v->v.x);
+ v->v.y=SnapX(v->v.y);
+
+ i=IteratorNext(i);
+ }
+
+ grid_lock=orig_lock;
+ redraw=TRUE;
+
+ break;
+ }
+
+ case TM_DELETE:
+ ObjectDelete_VERTEX();
+ break;
+
+ case TM_MOVE:
+ MoveObject_VERTEX();
+ break;
+
+ default:
+ cancel=TRUE;
+ break;
+ }
+
+ if ((!cancel)&&(clear_on_menu))
+ {
+ ClearSelection();
+ FullRedraw();
+ }
+ else if (redraw)
+ FullRedraw();
+}
+
+
+void ObjectKey_VERTEX(GFXKey k)
+{
+ int f;
+ int n;
+ Object *o;
+ EditVert *v;
+
+ switch(k.code)
+ {
+ case GFX_F12:
+ ClearSelection();
+ n=0;
+
+ for(f=0;f<MapSize(vertex);f++)
+ {
+ o=MapElem(vertex,f);
+
+ if (o->data)
+ {
+ v=o->data;
+
+ if (ListSize(v->l)==0)
+ {
+ ListClear(v->l);
+ Release(o->data);
+ o->data=NULL;
+ n++;
+ }
+ }
+ }
+
+ FullRedraw();
+ GFX_redraw();
+
+ GuiInfoBox("NOTICE","Deleted %d vertices",n);
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+int ObjectHasTag_VERTEX(void *obj, int tag)
+{
+ return(FALSE);
+}
+
+
+ObjDesc *ObjectOverlaid_VERTEX(int x, int y, int *no)
+{
+ int n;
+ EditVert *v;
+ ObjDesc *od;
+ int f;
+
+ VIDOOM_TRACE;
+
+ od=NULL;
+
+ n=0;
+
+ for(f=0;f<MapSize(vertex);f++)
+ {
+ v=GETVERT(f);
+
+ if ((v)&&(PositionOnObject_VERTEX(x,y,v)))
+ {
+ n++;
+ od=ReGrab(od,sizeof(ObjDesc)*n);
+ od[n-1].no=f;
+ sprintf(od[n-1].detail,"%5d - %d,%d",f,v->v.x,v->v.y);
+ }
+ }
+
+ *no=n;
+ return(od);
+}
+
+
+/* END OF FILE */