0001 #include "GarbageCollector";
0002 #ifndef LEVEL_ED_HH
0003 #define LEVEL_ED_HH 'Leveled up'
0004 #include "Set.HC";
0005 #include "Intersect";
0006 #include "Matrix4x4Inv";
0007 class CNode:CQue {
0008   F64 x,y;
0009   Bool selected;
0010 };
0011 class CLine:CQue {
0012   CNode *start,*end;
0013   Bool selected;
0014 };
0015 class CFill:CQue {
0016   F64 x,y;
0017   I64 start,height;
0018   I64 tile;
0019   Bool door,selected;
0020 };
0021 class CThing:CQue {
0022   F64 x,y,z;
0023   U8 class_name[STR_LEN];
0024   Bool selected;
0025 };
0026 #define GRID_SZ 128
0027 class CCopyPaste {
0028   CQue nodes;
0029   CQue lines;
0030 };
0031 #define LF_COPYING 1
0032 #define LF_CUTTING 2
0033 class CLevel {
0034   CQue nodes;
0035   CQue fills;
0036   CQue lines;
0037   CQue things;
0038   CHashTable *grid;
0039   F64 center_x,center_y;
0040   F64 scale;
0041   F64 snap;
0042 //Private
0043   I64 flags;
0044   I64 mat[16],clip_transform[16];
0045   CLine * cur_line;
0046   F64 x,y;
0047   F64 select_start_x,select_start_y;
0048   CNode *line_start;
0049   CCopyPaste *clipboard;
0050   Bool select_active;
0051   Bool remove_from_grid;
0052 };
0053 //Accounts for snap,and near nodes
0054 U0 AddNode(CLevel *l,CNode *n) {
0055   if(l->snap>=1.001) {
0056     n->x=Round(n->x/l->snap)*l->snap;
0057     n->y=Round(n->y/l->snap)*l->snap;
0058   }
0059   QueIns(n,&l->nodes);
0060 }
0061 extern U0 DrawClip(CLevel *l,F64 x,F64 y,CDC *dc,I64 *mat=NULL);
0062 Bool GridPlot(CLevel *l,I64 x,I64 y,I64 z) {
0063   I64 ox,oy;
0064   CD2 tr,tl,bl,br,*st=&l->cur_line->start->x,*en=&l->cur_line->end->x;
0065   CHashGeneric *gen;
0066   U8 buf[STR_LEN];
0067   for(ox=-GRID_SZ;ox<=GRID_SZ;ox+=GRID_SZ)
0068     for(oy=-GRID_SZ;oy<=GRID_SZ;oy+=GRID_SZ) {
0069       tl.x=FloorI64(x+ox,GRID_SZ);
0070       bl.x=FloorI64(x+ox,GRID_SZ);
0071       tr.x=tl.x+GRID_SZ;
0072       br.x=bl.x+GRID_SZ;
0073       tl.y=FloorI64(y+oy,GRID_SZ);
0074       tr.y=FloorI64(y+oy,GRID_SZ);
0075       bl.y=tl.y+GRID_SZ;
0076       br.y=tr.y+GRID_SZ;
0077 
0078       if(tl.x<=x<=tr.x)
0079         if(tl.y<=y<=bl.y) {
0080 add:
0081           StrPrint(buf,"G.%d.%d",FloorI64(x+ox,GRID_SZ)/GRID_SZ,FloorI64(y+oy,GRID_SZ)/GRID_SZ);
0082           if(gen=HashFind(buf,l->grid,HTT_FRAME_PTR)) {
0083           } else {
0084             gen=CAlloc(sizeof(CHashGeneric),mem_task);
0085             gen->type=HTT_FRAME_PTR;
0086             gen->str=StrNew(buf,mem_task);
0087             gen->user_data0=I64SetNew;
0088             HashAdd(gen,l->grid);
0089           }
0090           if(l->remove_from_grid)
0091             I64SetRem(gen->user_data0,l->cur_line);
0092           else
0093             I64SetAdd(gen->user_data0,l->cur_line);
0094           goto next;
0095         }
0096       if(PlaneIntersect(NULL,&tl,&tr,st,en))
0097         goto add;
0098       if(PlaneIntersect(NULL,&tr,&br,st,en))
0099         goto add;
0100       if(PlaneIntersect(NULL,&bl,&br,st,en))
0101         goto add;
0102       if(PlaneIntersect(NULL,&bl,&tl,st,en))
0103         goto add;
0104 next:;
0105     }
0106   return TRUE;
0107 }
0108 U0 LevelAddLineToGrid(CLevel *l,CLine *ln) {
0109   if(!l->grid) return;
0110   CD2 *st=&ln->start->x,*en=&ln->end->x;
0111   l->cur_line=ln;
0112   l->remove_from_grid=FALSE;
0113   Line(l,st->x,st->y,0,en->x,en->y,0,&GridPlot,64);
0114 }
0115 U0 LevelRemoveLineFromGrid(CLevel *l,CLine *ln) {
0116   if(!l->grid) return;
0117   CD2 *st=&ln->start->x,*en=&ln->end->x;
0118   l->cur_line=ln;
0119   l->remove_from_grid=TRUE;
0120   Line(l,st->x,st->y,0,en->x,en->y,0,&GridPlot,64);
0121 }
0122 U0 LevelInitGrid(CLevel *l) {
0123   CLine *ln,*head=&l->lines;
0124   l->grid=Fs->hash_table;
0125   for(ln=head->next;ln!=head;ln=ln->next)
0126     LevelAddLineToGrid(l,ln);
0127 }
0128 I64 QueIndex(CQue *head,CQue *have) {
0129   I64 idx=0;
0130   CQue *q;
0131   for(q=head->next;q!=head;q=q->next) {
0132     if(q==have)
0133       return idx;
0134     ++idx;
0135   }
0136   return -1;
0137 }
0138 CQue NthQue(CQue *head,I64 idx) {
0139   head=head->next;
0140   while(--idx>=0)
0141     head=head->next;
0142   return head;
0143 }
0144 U0 LoadLevel(CLevel *l,U8 *from) {
0145   if(!FileFind(from))
0146     return;
0147   F64 x,y,z;
0148   I64 sn,en,ln;
0149   U8 *text,*p;
0150   CNode *n;
0151   CLine *line;
0152   CThing *thing;
0153   for(ln=1;text=DocLineRead(from,ln);++ln) {
0154     if(!StrNCmp(text,"NODE:",5)) {
0155       n=GCCAlloc(sizeof CNode);
0156       StrScan(text,"NODE:%f,%f\n",&x,&y);
0157       n->x=x;
0158         n->y=y;
0159       QueIns(n,l->nodes.last);
0160     }
0161     Free(text);
0162   }
0163   for(ln=1;text=DocLineRead(from,ln);++ln) {
0164     if(!StrNCmp(text,"LINE:",5)) {
0165       line=GCCAlloc(sizeof CLine);
0166       StrScan(text,"LINE:%d,%d\n",&sn,&en);
0167       line->start=NthQue(&l->nodes,sn);
0168       line->end=NthQue(&l->nodes,en);
0169       QueIns(line,l->lines.last);
0170     }
0171     Free(text);
0172   }
0173   for(ln=1;text=DocLineRead(from,ln);++ln) {
0174     if(!StrNCmp(text,"THNG:",5)) {
0175       thing=GCCAlloc(sizeof CThing);
0176       QueIns(thing,l->things.last);
0177       p=&thing->class_name;
0178       StrScan(text,"THNG:%f,%f,%f,%s\n",&x,&y,&z,&p);
0179       thing->x=x;
0180       thing->y=y;
0181       thing->z=z;
0182     }
0183     Free(text);
0184   }
0185 }
0186 U0 SaveLevel(CLevel *l,U8 *to) {
0187   CDoc *doc=DocNew(to);
0188   CQue *head;
0189   CNode *node;
0190   CLine *line;
0191   CThing *thing;
0192   head=&l->nodes;
0193   for(node=head->next;node!=head;node=node->next) {
0194     DocPrint(doc,"NODE:%f,%f\n",node->x,node->y);
0195   }
0196   head=&l->lines;
0197   for(line=head->next;line!=head;line=line->next) {
0198     DocPrint(doc,"LINE:%d,%d\n",QueIndex(&l->nodes,line->start),QueIndex(&l->nodes,line->end));
0199   }
0200   head=&l->things;
0201   for(thing=head->next;thing!=head;thing=thing->next) {
0202     DocPrint(doc,"THNG:%f,%f,%f,%s\n",thing->x,thing->y,thing->z,thing->class_name);
0203   }
0204   DocWrite(doc);
0205   DocDel(doc);
0206 }
0207 Bool NodeIsUsed(CLevel *l,CNode *node) {
0208   CQue *head=&l->lines;
0209   CLine *cur;
0210   for(cur=head->next;cur!=head;cur=cur->next) {
0211     if(node==cur->start||node==cur->end)
0212       return TRUE;
0213   }
0214   return FALSE;
0215 }
0216 CLevel *l=NULL;
0217 CLevel *LevelNew() {
0218   CLevel *l=GCCAlloc(sizeof CLevel);
0219   QueInit(&l->nodes);
0220   QueInit(&l->fills);
0221   QueInit(&l->lines);
0222   QueInit(&l->things);
0223   return l;
0224 }
0225 U0 LevelDel(CLevel *l) {
0226   GCFree(l);
0227 }
0228 U0 GrPrintCenter(CDC *dc,F64 x,F64 y,U8 *fmt,...) {
0229   fmt=StrPrintJoin(NULL,fmt,argc,argv);
0230   GrPrint3(dc,x-StrLen(fmt)*4/l->scale,y,"%s",fmt);
0231   Free(fmt);
0232 }
0233 U0 DrawNodes(CDC *dc) {
0234   CQue *head=&l->nodes;
0235   CNode *node;
0236   for(node=head->next;node!=head;node=node->next) {
0237     if(!node->selected)
0238       dc->color=LTGRAY;
0239     else {
0240       if(Blink)
0241         dc->color=LTRED;
0242       else
0243         dc->color=LTBLUE;
0244     }
0245     dc->thick=3;
0246     GrPlot3(dc,node->x,node->y,0);
0247     dc->color=RED<<16|GREEN|ROPF_DITHER;
0248     dc->thick=1;
0249     if(node->selected) {
0250       GrBorder(dc,node->x-5,node->y-5,node->x+5,node->y+5);
0251     }
0252   }
0253 }
0254 U0 DrawLines(CDC *dc) {
0255   CQue *head=&l->lines;
0256   CLine *line;
0257   CD2 *st,*en;
0258   for(line=head->next;line!=head;line=line->next) {
0259     dc->thick=2;
0260     if(line->selected) {
0261       if(Blink)
0262         dc->color=YELLOW;
0263       else
0264         dc->color=BROWN;
0265     } else 
0266       dc->color=LTPURPLE;
0267     st=&line->start->x;
0268     en=&line->end->x;
0269     GrLine3(dc,st->x,st->y,0,en->x,en->y,0);
0270   } 
0271 }
0272 U0 DrawLines(CDC *dc) {
0273   CQue *head=&l->lines;
0274   CLine *line;
0275   CD2 *st,*en;
0276   for(line=head->next;line!=head;line=line->next) {
0277     dc->thick=2;
0278     if(line->selected) {
0279       if(Blink)
0280         dc->color=YELLOW;
0281       else
0282         dc->color=BROWN;
0283     } else 
0284       dc->color=LTPURPLE;
0285     st=&line->start->x;
0286     en=&line->end->x;
0287     GrLine3(dc,st->x,st->y,0,en->x,en->y,0);
0288   } 
0289 }
0290 U0 DrawThings(CDC *dc) {
0291   CQue *head=&l->things;
0292   CThing *thing;  
0293   U8 *str;
0294   for(thing=head->next;thing!=head;thing=thing->next) {
0295     if(thing->selected) {
0296       if(Blink)
0297         dc->color=YELLOW;
0298       else
0299         dc->color=BROWN;
0300     } else 
0301       dc->color=LTGREEN;
0302     dc->thick=3;
0303     str=MStrPrint("Thng:%s(Z:%f)",thing->class_name,thing->z);
0304     GrPrintCenter(dc,thing->x,thing->y,"%s",str);
0305     Free(str);
0306     GrPlot3(dc,thing->x,thing->y+8,0);
0307 
0308     dc->thick=1;
0309     if(thing->selected)
0310       GrBorder(dc,thing->x-5,thing->y-5,thing->x+5,thing->y+5);
0311   }
0312 }
0313 U0 DrawIt(CTask *t,CDC *_dc) {
0314   if(!l) return;
0315   CNode *ls;
0316   CDC *dc=DCNew(GR_WIDTH,GR_HEIGHT);
0317   dc->x=GR_WIDTH/2;
0318   dc->y=GR_HEIGHT/2;
0319   Mat4x4IdentEqu(l->mat);
0320   Mat4x4Scale(l->mat,l->scale);
0321   Mat4x4TranslationEqu(l->mat,-l->center_x,-l->center_y,0);
0322   Mat4x4Equ(dc->r,l->mat);
0323 
0324   dc->flags|=DCF_TRANSFORMATION;
0325   TextRect(t->win_left,t->win_right,t->win_top,t->win_bottom,0);
0326   DrawThings(dc);
0327   DrawLines(dc);
0328   DrawNodes(dc);
0329   DrawThings(dc);
0330   if(ls=l->line_start) {
0331     dc->color=LTRED;
0332     dc->thick=3;
0333     GrLine3(dc,ls->x,ls->y,0,l->x,l->y,0);
0334   }
0335   if(l->select_active) {
0336     dc->color=RED<<16|LTCYAN|ROPF_DITHER;
0337     dc->thick=1;
0338     GrBorder(dc,l->select_start_x,l->select_start_y,l->x,l->y);
0339   }
0340   DrawClip(l,l->x,l->y,dc,l->clip_transform);
0341   GrBlot(_dc,0,0,dc);
0342   DCDel(dc);
0343 }
0344 F64 DistFromPoint(CD2 *n,F64 x,F64 y) {
0345  return Sqrt(Sqr(n->x-x)+Sqr(y-n->y));
0346 }
0347 F64 DistFromLine(CLine *l,F64 x,F64 y) {
0348   CD2 *st=&l->start->x,*en=&l->end->x;
0349   F64 dx=en->x-st->x,dy=en->y-st->y,span=Sqrt(Sqr(dy)+Sqr(dx));
0350   F64 d=Abs(dy*x-dx*y+en->x*st->y-en->y*st->x)/span;
0351 //Dot product from start
0352   if((st->x-en->x)*(x-en->x)+(st->y-en->y)*(y-en->y)<0.) {
0353     return DistFromPoint(st,x,y);
0354   }
0355 //Dot product from end
0356   if((en->x-st->x)*(x-st->x)+(en->y-st->y)*(y-st->y)<0.) {
0357     return DistFromPoint(en,x,y);
0358   }
0359   return d;
0360 }
0361 
0362 //Needs grid
0363 CI64Set *LevelGetLinesInRadius(CLevel *l,F64 x,F64 y,F64 radius) {
0364   CLine *head=&l->lines;
0365   I64 gr=Ceil(radius/GRID_SZ)+.001,ox,oy,ix,iy,idx;
0366   CI64Set *tmp,*ret=I64SetNew;
0367   CHashGeneric *gen;
0368   U8 buf[STR_LEN];
0369   CLine *ln;
0370   if(l->grid) {
0371     for(ox=-gr;ox<=gr;++ox)
0372       for(oy=-gr;oy<=gr;++oy) {
0373         ix=FloorI64(x+ox*GRID_SZ,GRID_SZ);
0374         iy=FloorI64(y+oy*GRID_SZ,GRID_SZ);
0375         StrPrint(buf,"G.%d.%d",ix/GRID_SZ,iy/GRID_SZ);
0376         if(gen=HashSingleTableFind(buf,l->grid,HTT_FRAME_PTR)) {
0377           tmp=gen->user_data0;
0378           if(tmp) {
0379             idx=tmp->cnt;
0380             while(--idx>=0) {
0381               ln=tmp->body[idx];
0382               if(DistFromLine(ln,x,y)<=radius)
0383                 I64SetAdd(ret,ln);
0384             }
0385           }
0386         }
0387       }
0388   } else {
0389     for(ln=head->next;ln!=head;ln=ln->next) {
0390       if(DistFromLine(ln,x,y)<radius)
0391         I64SetAdd(ret,ln);
0392     }
0393   }
0394   return ret; 
0395 }
0396 
0397 
0398 U0 DeselectAll(CLevel *l) {
0399   CQue *head=&l->nodes;
0400   CNode *node;
0401   CLine *line;
0402   CFill *fill;
0403   CThing *cur;
0404   for(node=head->next;node!=head;node=node->next)
0405     node->selected=FALSE;
0406   head=&l->lines;
0407   for(line=head->next;line!=head;line=line->next)
0408     line->selected=FALSE;
0409   head=&l->things;
0410   for(cur=head->next;cur!=head;cur=cur->next)
0411     cur->selected=FALSE;
0412   fill=&l->fills;
0413   for(fill=head->next;fill!=head;fill=fill->next)
0414     fill->selected=FALSE;
0415 }
0416 
0417 
0418 U0 MoveSelected(F64 x,F64 y) {
0419   CQue *head=&l->nodes;
0420   CNode *node;
0421   CLine *line;
0422   CFill *fill;
0423   CThing *cur;
0424   for(node=head->next;node!=head;node=node->next) {
0425     if(node->selected) {
0426       node->x+=x;
0427       node->y+=y;
0428     }
0429   }
0430   head=&l->things;
0431   for(cur=head->next;cur!=head;cur=cur->next) {
0432     if(cur->selected) {
0433       cur->x+=x;
0434       cur->y+=y;
0435     }
0436   }
0437   fill=&l->fills;
0438   for(fill=head->next;fill!=head;fill=fill->next) {
0439     if(fill->selected) {
0440       fill->x+=x;
0441       fill->y+=y;
0442     }
0443   }
0444 }
0445 
0446 U0 SnapSelected() {
0447   CQue *head=&l->nodes;
0448   CNode *node;
0449   if(l->snap) {
0450     for(node=head->next;node!=head;node=node->next) {
0451       node->x=Round(node->x/l->snap)*l->snap;
0452       node->y=Round(node->y/l->snap)*l->snap;
0453     }
0454   }
0455 }
0456 
0457 U0 DeleteSelected() {
0458   CQue *head=&l->nodes;
0459   CNode *node;
0460   CLine *line;
0461   CFill *fill;
0462    CThing *cur;
0463 again:;
0464   head=&l->lines;
0465   for(line=head->next;line!=head;line=line->next) {
0466     if(line->start->selected||line->end->selected||line->selected) {
0467         QueRem(line);
0468         goto again;
0469     }
0470   }
0471   head=&l->nodes;
0472   for(node=head->next;node!=head;node=node->next) {
0473     if(node->selected) {
0474       QueRem(node);
0475       goto again;
0476     }
0477   }
0478   head=&l->things;
0479   for(cur=head->next;cur!=head;cur=cur->next) {
0480     if(cur->selected) {
0481       QueRem(cur);
0482       goto again;
0483     }
0484   }
0485   fill=&l->fills;
0486   for(fill=head->next;fill!=head;fill=fill->next) {
0487     if(fill->selected) {
0488       QueRem(fill);
0489       goto again;
0490     }
0491   }
0492 }
0493 
0494 //Returns TRUE if not near a CNode and we have things selected;
0495 Bool IsMoveStuff(F64 x,F64 y,F64 threshold=10) {
0496   CQue *head=&l->nodes;
0497   CNode *node;
0498   CLine *line;
0499   CFill *fill;
0500   CThing *cur;
0501   Bool has_selected=FALSE;
0502   for(node=head->next;node!=head;node=node->next) {
0503     if(node->selected) {
0504       has_selected=TRUE;
0505       if(DistFromPoint(&node->x,x,y)<threshold) {
0506         return FALSE;
0507       }
0508     }
0509   }
0510   head=&l->lines;
0511   for(line=head->next;line!=head;line=line->next) {
0512     if(line->selected)
0513       return TRUE;
0514   }
0515   head=&l->fills;
0516   for(fill=head->next;fill!=head;fill=fill->next) {
0517     if(fill->selected)
0518       return TRUE;
0519   }
0520   head=&l->things;
0521   for(cur=head->next;cur!=head;cur=cur->next) {
0522     if(cur->selected)
0523       return TRUE;
0524   }
0525   return has_selected;
0526 }
0527 
0528 F64 SelectThings(F64 x,F64 y,F64 threshold=-1.,Bool only_nodes=FALSE) {
0529   threshold+=.5;
0530   CQue *head=&l->nodes;
0531   CNode *node;
0532   CLine *line;
0533   CFill *fill;
0534   CThing *cur;
0535 
0536   F64 best=I16_MAX,tmp;
0537   for(node=head->next;node!=head;node=node->next) {
0538     tmp=DistFromPoint(&node->x,x,y);
0539     if(tmp<threshold)
0540       node->selected=TRUE;
0541     best=Min(tmp,best);
0542   }
0543   if(!only_nodes) {
0544     head=&l->lines;
0545     for(line=head->next;line!=head;line=line->next) {
0546       tmp=DistFromLine(line,x,y);
0547       if(tmp<threshold)
0548         line->selected=TRUE;
0549       best=Min(tmp,best);
0550     }
0551     head=&l->things;
0552     for(cur=head->next;cur!=head;cur=cur->next) {
0553       tmp=DistFromPoint(&cur->x,x,y);
0554       if(tmp<threshold)
0555         cur->selected=TRUE;
0556       best=Min(tmp,best);
0557     }
0558     fill=&l->fills;
0559     for(fill=head->next;fill!=head;fill=fill->next) {
0560       tmp=DistFromPoint(&fill->x,x,y);
0561       if(tmp<threshold)
0562         fill->selected=TRUE;
0563       best=Min(tmp,best);
0564     }
0565   }
0566   return best;
0567 }
0568 #include "Intersect";
0569 Bool GetPolyLines0(CLevel *l,CNode *node,CLine **lines,CNode *target=NULL,I64 idx=0) {
0570   CQue *head=&l->lines;
0571   if(!target) target=node;
0572   CLine *line;
0573   I64 idx2;
0574   for(line=head->next;line!=head;line=line->next) {
0575     if(line->selected&&!idx)
0576       goto skip;
0577     for(idx2=0;idx2!=idx;idx2++)
0578       if(line==lines[idx2])
0579         goto skip;
0580     if(line->start==node) {
0581       lines[idx]=line;
0582       if(line->end==target)
0583         return TRUE;
0584       if(GetPolyLines0(l,line->end,lines,target,idx+1))
0585         return TRUE;
0586       lines[idx]=NULL;
0587     }
0588     if(line->end==node) {
0589       lines[idx]=line;
0590       if(line->start==target)
0591         return TRUE;
0592       if(GetPolyLines0(l,line->start,lines,target,idx+1))
0593         return TRUE;
0594       lines[idx]=NULL;
0595     }
0596 skip:;
0597   }
0598   return FALSE;  
0599 }
0600 CLine **GetPolyLines(CLevel *l,CNode *node) {
0601   CLine **ret=GCCAlloc((1+QueCnt(&l->lines))*8);
0602   if(!GetPolyLines0(l,node,ret)) {
0603     GCFree(ret);
0604     return NULL;
0605   }
0606   return ret;
0607 }
0608 I64 I64Sort(I64 a,I64 b) {
0609   return a-b;
0610 }
0611 Bool LineSetHas(I64 *a,I64 v) {
0612   I64 i=0,have;
0613   for(;have=a[i];++i) {
0614     if(have>v) return FALSE;
0615     if(have==v) return TRUE;
0616   }
0617   return FALSE;
0618 }
0619 CLine **MergeSet(CLine **a,CLine **b) {
0620   I64 cnt=0,cnt2=0;
0621   if(!a) a=GCCAlloc(8);
0622   if(!b) b=GCCAlloc(8);
0623   for(cnt=0;a[cnt];cnt++)
0624     ;  
0625   for(cnt2=0;b[cnt2];cnt2++)
0626     ; 
0627   QSortI64(a,cnt,&I64Sort);
0628   QSortI64(b,cnt2,&I64Sort);
0629   CLine **ret=GCCAlloc((cnt+cnt2+1)*8);
0630   MemCpy(ret,a,cnt*8);
0631   for(cnt2=0;b[cnt2];++cnt2) {
0632     if(!LineSetHas(a,b[cnt2]))
0633       ret[cnt++]=b[cnt2];
0634   }
0635   QSortI64(ret,cnt,&I64Sort);
0636   return ret;
0637 }
0638 I64 LineSetCnt(CLine **lines) {
0639   if(!lines) return 0;
0640   I64 cnt=0;
0641   while(*lines)
0642     ++lines,++cnt;
0643   return cnt;
0644 }
0645 
0646 CLine **StronglyConnected(CLevel *l,CNode *node) {
0647   I64 old_sz=0,idx;
0648   CLine **lines,**lines2,**lines3,*line,*old;
0649   lines=GetPolyLines(l,node);
0650   if(!lines) return NULL;
0651 again:;
0652   old=GCMAllocIdent(lines);
0653   for(idx=0;line=lines[idx];idx++) {
0654     lines2=GetPolyLines(l,line->end);
0655     lines=MergeSet(lines,lines2);
0656     lines2=GetPolyLines(l,line->start);
0657     lines=MergeSet(lines,lines2);
0658     line->selected=TRUE;
0659   }
0660   if(MemCmp(old,lines,(LineSetCnt(old)+1)*8)) {
0661     GCFree(old);
0662     goto again;
0663   }
0664   return lines;
0665 }
0666 
0667 U0 ClipPolygonRect0(CLevel *l,CLine *line,F64 x,F64 y,F64 x2,F64 y2) {
0668   CD3 tr,tl,bl,br;
0669   CD3 dst,tmp,tmp2;
0670   CD3 ls_d,le_d;
0671   CD3 *ls=&line->start->x,*le=&line->end->x,*a,*b;
0672   CLine *newl;
0673   Bool modified=FALSE;
0674   CNode *new;
0675   if(x>x2) 
0676     SwapI64(&x,&x2);
0677   if(y>y2) 
0678     SwapI64(&y,&y2);
0679   tr.x=x2;
0680   br.x=x2;
0681   tl.x=x;
0682   bl.x=x;
0683 
0684   tr.y=y;
0685   br.y=y2;
0686   tl.y=y;
0687   bl.y=y2;
0688 
0689   Bool tested=0;
0690   if(x<=le->x<=x2&&y<=le->y<=y2)
0691     if(x<=ls->x<=x2&&y<=ls->y<=y2) {
0692       LevelRemoveLineFromGrid(l,line);
0693       QueRem(line);
0694       return;
0695     }
0696 again:;
0697   if(!Bts(&tested,0)&&PlaneIntersect(&dst,a=&tl,b=&tr,ls,le)) {
0698 found:
0699 //MAke sure our node is far away from hit spot(because of flaoting points accuracy)
0700     if(Sqr(dst.x-ls->x)+Sqr(dst.y-ls->y)<2.5||
0701           Sqr(dst.x-le->x)+Sqr(dst.y-le->y)<2.5)
0702       goto again;
0703     D3Sub(&tmp2,le,a);
0704     D3Sub(&tmp,b,a);
0705 
0706     if(tmp.x*tmp2.y<tmp.y*tmp2.x) {
0707       if(!(x<=le->x<=x2&&y<=le->y<=y2)) {
0708         newl=GCCAlloc(sizeof CLine);
0709         QueIns(newl,l->lines.last);
0710         new=GCCAlloc(sizeof CNode);
0711         new->x=dst.x;
0712         new->y=dst.y;
0713         QueIns(new,l->nodes.last);
0714         newl->start=new;
0715         newl->end=line->end;
0716         modified=TRUE;
0717         LevelAddLineToGrid(l,newl);
0718       }
0719     } else {
0720       if(!(x<=ls->x<=x2&&y<=ls->y<=y2)) {
0721         newl=GCCAlloc(sizeof CLine);
0722         QueIns(newl,l->lines.last);
0723         new=GCCAlloc(sizeof CNode);
0724         new->x=dst.x;
0725         new->y=dst.y;
0726         QueIns(new,l->nodes.last);
0727         newl->start=line->start;
0728         newl->end=new;
0729         LevelAddLineToGrid(l,newl);
0730         modified=TRUE;
0731       }
0732     }
0733     goto again;
0734   }
0735   if(!Bts(&tested,1)&&PlaneIntersect(&dst,a=&tr,b=&br,ls,le))
0736     goto found;
0737   if(!Bts(&tested,2)&&PlaneIntersect(&dst,a=&br,b=&bl,ls,le))
0738     goto found;
0739   if(!Bts(&tested,3)&&PlaneIntersect(&dst,a=&bl,b=&tl,ls,le))
0740     goto found;
0741 
0742   if(modified) {
0743     LevelRemoveLineFromGrid(l,line);
0744     QueRem(line);
0745   }
0746 }
0747 
0748 
0749 Bool InsideRect(CD2 *p,F64 x,F64 y,F64 x2,F64 y2) {
0750   if(x<=p->x<=x2)
0751     if(y<=p->y<=y2)
0752       return TRUE;
0753   return FALSE;
0754 }
0755 U0 DrawClip(CLevel *l,F64 x,F64 y,CDC *dc,I64 *mat=NULL) {
0756   if(!l->clipboard) return;
0757   CCopyPaste *cp=l->clipboard,*cloned=GCCAlloc(sizeof CCopyPaste);
0758   CQue *lines=&cp->lines;
0759   CQue *nodes=&cp->nodes;
0760   CNode *node,*copyn;
0761   CLine *line,*copyl;
0762   I64 z,xx,yy,color;
0763   QueInit(&cloned->lines);
0764   QueInit(&cloned->nodes);
0765 //Do reverse to nodes are in same other for QueIndex
0766   for(node=nodes->last;node!=nodes;node=node->last) {
0767     copyn=GCMAllocIdent(node);
0768     if(mat) {
0769       xx=copyn->x;
0770       yy=copyn->y;
0771       z=1;
0772       Mat4x4MulXYZ(mat,&xx,&yy,&z);
0773       copyn->x=xx+x;
0774       copyn->y=yy+y;
0775     } else {
0776       copyn->x+=x;
0777       copyn->y+=y;
0778     }
0779 //Put at front
0780     QueIns(copyn,&cloned->nodes);
0781   }
0782   for(line=lines->next;line!=lines;line=line->next) {
0783     copyl=GCMAllocIdent(line);
0784     copyl->start=NthQue(&cloned->nodes,QueIndex(nodes,copyl->start));
0785     copyl->end=NthQue(&cloned->nodes,QueIndex(nodes,copyl->end));
0786     QueIns(copyl,&cloned->lines);
0787   }
0788 
0789 
0790   if(Blink)
0791     color=RED;
0792   else 
0793     color=LTGRAY;
0794 
0795   lines=&cloned->lines;
0796   dc->thick=2;
0797   for(line=lines->next;line!=lines;line=line->next) {
0798     dc->color=color;
0799     GrLine3(dc,line->start->x,line->start->y,0,line->end->x,line->end->y,0);
0800     dc->color=LTGRAY;
0801     GrPlot3(dc,line->start->x,line->start->y,0);
0802     GrPlot3(dc,line->end->x,line->end->y,0);
0803   }
0804 
0805 }
0806 
0807 U0 Paste(CLevel *l,F64 x,F64 y,I64 *mat=NULL) {
0808   if(!l->clipboard) return;
0809   CCopyPaste *cp=l->clipboard;
0810   CQue *lines=&cp->lines;
0811   CQue *nodes=&cp->nodes;
0812   CNode *node,*copyn;
0813   CLine *line,*copyl;
0814   I64 z,xx,yy;
0815 //Do reverse to nodes are in same other for QueIndex
0816   for(node=nodes->last;node!=nodes;node=node->last) {
0817     copyn=GCMAllocIdent(node);
0818     if(mat) {
0819       xx=copyn->x;
0820       yy=copyn->y;
0821       z=1;
0822       Mat4x4MulXYZ(mat,&xx,&yy,&z);
0823       copyn->x=xx+x;
0824       copyn->y=yy+y;
0825     } else {
0826       copyn->x+=x;
0827       copyn->y+=y;
0828     }
0829 //Put at front
0830     AddNode(l,copyn);
0831   }
0832   for(line=lines->next;line!=lines;line=line->next) {
0833     copyl=GCMAllocIdent(line);
0834     copyl->start=NthQue(&l->nodes,QueIndex(nodes,copyl->start));
0835     copyl->end=NthQue(&l->nodes,QueIndex(nodes,copyl->end));
0836     QueIns(copyl,&l->lines);
0837   }
0838   DeselectAll(l);
0839 }
0840 
0841 CCopyPaste *CopyRegion(CLevel *l,F64 x,F64 y,F64 x2,F64 y2) {
0842   if(x>x2)
0843     SwapI64(&x,&x2);
0844   if(y>y2)
0845     SwapI64(&y,&y2);
0846   I64 tested;
0847   CQue *head=&l->lines;
0848   CCopyPaste *cp=GCCAlloc(sizeof CCopyPaste);
0849   CNode *node;
0850   CLine *line,*new_line;
0851   CD2 tl,tr,bl,br,hit_at,*start,*end,*st2,*en2;
0852   CD3 tmp,tmp2;
0853   CNode *new_start,*new_end;
0854   Bool passes;
0855   F64 lowx=x2,lowy=y2;
0856   tl.x=x,tl.y=y;
0857   tr.x=x2,tr.y=y;
0858   bl.x=x,bl.y=y2;
0859   br.x=x2,br.y=y2;
0860 
0861   QueInit(&cp->nodes);
0862   QueInit(&cp->lines);
0863   for(line=head->next;line!=head;line=line->next) {
0864     start=&line->start->x;
0865     end=&line->end->x;
0866     tested=0;
0867     new_start=GCMAllocIdent(line->start);
0868     new_end=GCMAllocIdent(line->end);
0869     passes=FALSE;
0870 again:;
0871     if(!Bts(&tested,0)&&PlaneIntersect(&hit_at,st2=&tl,en2=&tr,start,end)) {
0872 found:
0873       D3Sub(&tmp,en2,st2);
0874       D3Sub(&tmp2,end,st2);
0875 
0876       if(tmp.x*tmp2.y>tmp.y*tmp2.x) {
0877         new_start=GCCAlloc(sizeof CNode);
0878         new_start->x=hit_at.x;
0879         new_start->y=hit_at.y;
0880         passes=TRUE;
0881       } else {
0882         new_end=GCCAlloc(sizeof CNode);
0883         new_end->x=hit_at.x;
0884         new_end->y=hit_at.y;
0885         passes=TRUE;
0886       }
0887       goto again;
0888     }
0889     if(!Bts(&tested,1)&&PlaneIntersect(&hit_at,st2=&tr,en2=&br,start,end)) {
0890       goto found;
0891     }
0892     if(!Bts(&tested,2)&&PlaneIntersect(&hit_at,st2=&br,en2=&bl,start,end)) {
0893       goto found;
0894     }
0895     if(!Bts(&tested,3)&&PlaneIntersect(&hit_at,st2=&bl,en2=&tl,start,end)) {
0896       goto found;
0897     }
0898     if(!passes) {
0899       passes=InsideRect(start,x,y,x2,y2)||InsideRect(end,x,y,x2,y2);
0900     }
0901     if(passes) {
0902       new_line=GCCAlloc(sizeof CLine);
0903       new_line->start=new_start;
0904       new_line->end=new_end;
0905       QueIns(new_line->start,&cp->nodes);
0906       QueIns(new_line->end,&cp->nodes);
0907       QueIns(new_line,&cp->lines);
0908       lowx=Min(lowx,new_start->x);
0909       lowy=Min(lowy,new_start->y);
0910       lowx=Min(lowx,new_end->x);
0911       lowy=Min(lowy,new_end->y);
0912     }
0913   }
0914   head=&cp->nodes;
0915   for(new_start=head->next;new_start!=head;new_start=new_start->next) {
0916     new_start->x-=lowx;
0917     new_start->y-=lowy;
0918   }
0919   return cp;
0920 }
0921 U0 ClipRect(CLevel *l,F64 x,F64 y,F64 x2,F64 y2) {
0922   if(x>x2)
0923     SwapI64(&x,&x2);
0924   if(y>y2)
0925     SwapI64(&y,&y2);
0926   DeselectAll(l);
0927   I64 idx;
0928 
0929   CLine *line,*next,**lines,*line2;
0930   CNode *node;
0931   CQue *head=&l->lines;
0932 again:
0933   for(line=head->next;line!=head;line=next) {
0934     next=line->next;
0935     ClipPolygonRect0(l,line,x,y,x2,y2);
0936   }
0937   head=&l->nodes;  
0938   for(node=head->next;node!=head;node=next) {
0939     next=node->next;
0940     if(x+2.5<node->x<x2-2.5&&y+2.5<node->y<y2-2.5) {
0941       //QueRem(node);
0942     }
0943   }
0944   DeselectAll(l);
0945 }
0946 U0 TransCords(CLevel *l,I64 *x,I64 *y) {
0947   I64 mat[16];
0948   *x-=GR_WIDTH/2;
0949   *y-=GR_HEIGHT/2;
0950   Mat4x4IdentEqu(l->mat);
0951   Mat4x4Scale(l->mat,l->scale);
0952   Mat4x4TranslationEqu(l->mat,-l->center_x,-l->center_y,0);
0953   Mat4x4Equ(mat,l->mat);
0954   Mat4x4Inv(mat);
0955   I64 z=1;
0956   Mat4x4MulXYZ(mat,x,y,&z);
0957 }
0958 U0 EditLevel(U8 *name="Test.DD") {
0959   SettingsPush;
0960   WinBorder(0);
0961   WinMax;
0962   Fs->draw_it=&DrawIt;
0963 //  Bts(&Fs->win_inhibit,WIf_FOCUS_TASK_GRAB_SCROLL);
0964   Bts(&Fs->win_inhibit,WIf_FOCUS_TASK_MS_L_D);
0965   Bts(&Fs->win_inhibit,WIf_FOCUS_TASK_MS_R_D);
0966   Bts(&Fs->win_inhibit,WIf_FOCUS_TASK_MS_L);
0967   Bts(&Fs->win_inhibit,WIf_FOCUS_TASK_MS_R);
0968   l=LevelNew;
0969   Mat4x4IdentEqu(l->mat);
0970   Mat4x4IdentEqu(l->clip_transform);
0971   l->center_x=0;
0972   l->center_y=0;
0973   l->scale=1.;
0974   l->snap=16.;
0975   l->clipboard=NULL;
0976   if(FileFind(name))
0977     LoadLevel(l,name);
0978   I64 last_z=ms.pos.z;
0979   I64 msg,x,y,old_x=-1,old_y=-1;
0980   I64 last_raw_x=-1,last_raw_y=-1;
0981   I64 raw_x,raw_y;
0982   I64 drag_start_x,drag_start_y;
0983   U64 tool='Point',old_tool=tool;
0984   Bool old_down=FALSE;
0985   Bool drag=FALSE,down=FALSE;
0986   Bool moved_scrn=FALSE;
0987   U8 *thing_class;
0988   F64 closest,select_start_x,select_start_y,scale;
0989   CLine *ln;
0990   CThing *thing;
0991   CNode *line_start=NULL,*line_end,*node;
0992   while(TRUE) {
0993 DbgPrint("oxy:%d,%d-%d,%d\n",last_raw_x,last_raw_y,old_x,old_y);
0994     if(ms.pos.z!=last_z) {
0995       scale=l->scale;
0996 //      last_raw_x=GR_WIDTH/2;
0997 //      last_raw_y=GR_HEIGHT/2;
0998 adjust:;
0999       l->scale=Max(scale+(last_z-ms.pos.z)*.05,.05);
1000       x=last_raw_x,y=last_raw_y;
1001       TransCords(l,&x,&y);
1002 DbgPrint("]%d,%d,%d,%d,%n\n",old_x,x,old_y,y,l->scale);
1003       l->center_x+=Sign(old_x-x);
1004       l->center_y+=Sign(old_y-y);
1005       x=last_raw_x,y=last_raw_y;
1006       TransCords(l,&x,&y);
1007    if(AbsI64(x-old_x)>Max(3,1.5/l->scale)||AbsI64(y-old_y)>Max(3,1.5/l->scale))
1008         goto adjust;
1009       x=last_raw_x,y=last_raw_y;
1010       TransCords(l,&x,&y);
1011       last_z=ms.pos.z;
1012 DbgPrint("TEART:%d,%d\n",x-old_x,y-old_y);
1013       old_x=x,old_y=y;
1014     }
1015     while(msg=ScanMsg(&x,&y)) {
1016       switch(msg) {
1017         case MSG_KEY_DOWN:
1018           line_start=NULL;
1019           if(x==CH_CTRLC) {
1020             DeselectAll(l);
1021             l->select_active=TRUE;
1022             l->select_start_x=l->x;
1023             l->select_start_y=l->y;
1024             l->flags|=LF_COPYING;
1025             break;
1026           }
1027 //Rotate clipboard
1028           if(ToUpper(x)=='R') {
1029             Mat4x4RotZ(l->clip_transform,pi/2);
1030             break;
1031           }
1032           if(x=='f') {
1033             Mat4x4RotY(l->clip_transform,pi);
1034             break;
1035           }
1036           if(x=='F') {
1037             Mat4x4RotX(l->clip_transform,pi);
1038             break;
1039           }
1040           if(x==CH_CTRLV) {
1041             Paste(l,old_x,old_y,l->clip_transform);
1042             break;
1043           }
1044           if(y.u8[0]==SC_CURSOR_UP) {
1045             l->center_y-=10/l->scale;
1046           } else if(y.u8[0]==SC_CURSOR_DOWN) {
1047             l->center_y+=10/l->scale;
1048           } else if(y.u8[0]==SC_CURSOR_LEFT) {
1049             l->center_x-=10/l->scale;
1050           } else if(y.u8[0]==SC_CURSOR_RIGHT) {
1051             l->center_x+=10/l->scale;
1052           } else if(x==CH_ESC) {
1053             SaveLevel(l,name);
1054             goto fin;
1055           } else if(x==CH_SHIFT_ESC)
1056             goto fin;
1057           if(ToUpper(x)=='P') {
1058             DeselectAll(l);
1059             SelectThings(l->x,l->y,Max(10,10/l->scale));
1060             for(line_start=l->nodes.next;line_start!=&l->nodes;line_start=line_start->next)
1061               if(line_start->selected) {
1062                 DeselectAll(l);
1063                 StronglyConnected(l,line_start);
1064                 break;
1065               }
1066             break;
1067           } else if(ToUpper(x)=='L')
1068             tool='Line';
1069           else if(ToUpper(x)=='T') {
1070             thing=GCCAlloc(sizeof CThing);
1071             thing->x=l->x;
1072             thing->y=l->y;
1073             thing_class=PopUpGetStr("Thing Class Name:");
1074             StrCpy(thing->class_name,thing_class);
1075             Free(thing_class);
1076             QueIns(thing,&l->things);
1077           } else if(ToUpper(x)=='F')
1078             tool='Fill';
1079           if(tool!=old_tool) {
1080             DeselectAll(l);
1081           }
1082           break;
1083         case MSG_MS_R_DOWN:
1084           last_raw_x=x,last_raw_y=y;
1085           TransCords(l,&x,&y);
1086           closest=SelectThings(x,y);
1087           if(closest<Max(10,10/l->scale))
1088             SelectThings(x,y,closest);
1089           DeleteSelected;
1090           old_x=x;
1091           old_y=y;
1092           break;
1093         case MSG_MS_L_DOWN:
1094           last_raw_x=x,last_raw_y=y;
1095           TransCords(l,&x,&y);
1096           drag_start_x=x;
1097           drag_start_y=y;
1098           down=TRUE;
1099           old_x=x;
1100           old_y=y;
1101           break;
1102         case MSG_MS_MOVE:
1103           raw_x=x,raw_y=y;
1104           last_raw_x=raw_x,last_raw_y=raw_y;
1105           TransCords(l,&x,&y);
1106           if(l->select_active) {
1107             old_x=x;
1108             old_y=y;
1109             l->x=x;
1110             l->y=y;
1111             break;
1112           }
1113           l->select_active=FALSE;
1114           if(Bt(kbd.down_bitmap,SC_SHIFT)) {
1115             DeselectAll(l);
1116             l->select_active=TRUE;
1117             l->select_start_x=x;
1118             l->select_start_y=y;
1119           }
1120           if(!drag&&down) {
1121             closest=SelectThings(x,y,,TRUE);
1122             if(closest<Max(10,10./l->scale))
1123               SelectThings(x,y,closest,TRUE);
1124             for(line_start=l->nodes.next;line_start!=&l->nodes;line_start=line_start->next) {
1125               if(line_start->selected) {
1126                 goto found;
1127               }
1128             }
1129             line_start=NULL;
1130 select:;
1131             DeselectAll(l);
1132 found:;
1133           } else if(IsMoveStuff(x,y,Max(10*l->scale,10/l->scale))&&!line_start) {
1134             MoveSelected(x-old_x,y-old_y);
1135           }
1136           drag=x!=drag_start_x||drag_start_y!=y;
1137           old_x=x;
1138           old_y=y;
1139           break;
1140         case MSG_MS_L_UP:
1141           last_raw_x=x,last_raw_y=y;
1142           TransCords(l,&x,&y);
1143           down=FALSE;
1144           if(l->select_active) {
1145             if(l->x<l->select_start_x)
1146               SwapI64(&l->x,&l->select_start_x);
1147             if(l->y<l->select_start_y)
1148               SwapI64(&l->y,&l->select_start_y);
1149             if(l->x-l->select_start_x<=10)
1150               goto no_select;
1151             if(l->y-l->select_start_y<=10)
1152               goto no_select;
1153             DeselectAll(l);
1154             for(x=l->select_start_x;x<l->x;x+=10) {
1155               for(y=l->select_start_y;y<l->y;y+=10) {
1156                 SelectThings(x,y,Max(10,10/l->scale),FALSE);
1157               }
1158             }
1159             if(l->flags&LF_COPYING) { 
1160               l->clipboard=CopyRegion(l,l->select_start_x,l->select_start_y,l->x,l->y);
1161               l->flags&=~LF_COPYING;
1162               Mat4x4IdentEqu(l->clip_transform);
1163               DeselectAll(l);
1164             }
1165             l->select_active=FALSE;
1166           old_x=x;
1167           old_y=y;
1168             break;
1169           }
1170 no_select:;
1171           if(line_start) {
1172             DeselectAll(l);
1173             SelectThings(x,y,Max(10,10/l->scale),TRUE);
1174             for(line_end=l->nodes.next;line_end!=&l->nodes;line_end=line_end->next) {
1175               if(line_end->selected) {
1176                 ln=GCCAlloc(sizeof CLine);
1177                 ln->start=line_start;
1178                 ln->end=line_end;
1179                 QueIns(ln,&l->lines);
1180               }
1181             }
1182             DeselectAll(l);
1183             line_start=NULL;
1184           } else if(IsMoveStuff(x,y,Max(10*l->scale,10/l->scale))) {
1185             SnapSelected;
1186             DeselectAll(l);
1187           } else if(tool=='Point') {
1188             node=GCCAlloc(sizeof CLine);
1189             node->x=x;
1190             node->y=y;
1191             AddNode(l,node);
1192           }
1193           drag=FALSE;
1194           old_x=x;
1195           old_y=y;
1196           break;
1197       }
1198     }
1199     l->line_start=line_start;
1200     l->x=old_x;
1201     l->y=old_y;
1202     old_tool=tool;
1203     if(!down)
1204       drag=FALSE;
1205     old_down=down;
1206     GCCollect;
1207     Refresh;
1208   }
1209   SaveLevel(l,name);
1210 fin:;
1211   SettingsPop;
1212   Fs->draw_it=NULL;
1213   Refresh;
1214   LevelDel(l);
1215 }
1216 #if __CMD_LINE__
1217 EditLevel;
1218 #endif
1219 #endif