/* 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; 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;fl.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; 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; TRACE; for(f=0;fdata)) { 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; 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; 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; 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;(rv.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; 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; 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) { TRACE; } void LocateObject_VERTEX(void *obj) { EditVert *v; 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; 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; 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"); FullRedraw(); } } 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; 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"); redraw=TRUE; } 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"); redraw=TRUE; 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;fdata) { v=o->data; if (ListSize(v->l)==0) { ListClear(v->l); Release(o->data); o->data=NULL; n++; } } } GuiInfoBox("NOTICE","Deleted %d vertices",n); FullRedraw(); break; default: break; } } int ObjectHasTag_VERTEX(void *obj, int tag) { return(FALSE); } /* END OF FILE */