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