//This is a whimsical program which demonstrates some techniques. #define BORDER 20 #define PTY_PT 0 #define PTY_CIRCLE 1 #define PTY_LINE 2 #define PTY_SPRITE 3 #define PTY_NUM 4 extern class PObj; class PPt { CD3I32 p; }; class PCircle { PObj *p; I64 radius; }; class PLine { PObj *p1,*p2; }; class PCSprite { PObj *p; U8 *img; I64 *r, *dr; //Rounding error might eventually screw this up } class PObj { PObj *next,*last; I64 type,color; union { PPt p; PCircle c; PLine l; PCSprite g; }; }; class PickFrame { PObj o_head; I64 o_cnts[PTY_NUM]; I64 cx,cy; }; #define IMGS_NUM 3 <1>/* Graphics Not Rendered in HTML */ <2>/* Graphics Not Rendered in HTML */ <3>/* Graphics Not Rendered in HTML */ U8 *imgs[IMGS_NUM]={<1>,<2>,<3>}; U0 DrawIt(CTask *task,CDC *dc) { I64 *r,*old_r; PickFrame *pf=FramePtr("PickFrame",task); PObj *tmpo=pf->o_head.next; pf->cx=task->pix_width>>1; pf->cy=task->pix_height>>1; DCDepthBufAlloc(dc); dc->color=LTRED; dc->thick=3; GrBorder(dc,BORDER,BORDER,2*pf->cx-BORDER,2*pf->cy-BORDER); while (tmpo!=&pf->o_head) { dc->color=tmpo->color; switch (tmpo->type) { case PTY_PT: GrLine(dc,pf->cx+tmpo->p.p.x+2,pf->cy+tmpo->p.p.y+2, pf->cx+tmpo->p.p.x-2,pf->cy+tmpo->p.p.y-2); GrLine(dc,pf->cx+tmpo->p.p.x-2,pf->cy+tmpo->p.p.y+2, pf->cx+tmpo->p.p.x+2,pf->cy+tmpo->p.p.y-2); break; case PTY_CIRCLE: GrCircle(dc,pf->cx+tmpo->c.p->p.p.x,pf->cy+tmpo->c.p->p.p.y, tmpo->c.radius); break; case PTY_LINE: GrLine(dc,pf->cx+tmpo->l.p1->p.p.x,pf->cy+tmpo->l.p1->p.p.y, pf->cx+tmpo->l.p2->p.p.x,pf->cy+tmpo->l.p2->p.p.y); break; case PTY_SPRITE: old_r=dc->r; dc->r=tmpo->g.r; dc->x=pf->cx+tmpo->g.p->p.p.x; dc->y=pf->cy+tmpo->g.p->p.p.y; dc->z=GR_Z_ALL; dc->flags|=DCF_TRANSFORMATION; Sprite3(dc,0,0,0,tmpo->g.img); dc->flags&=~DCF_TRANSFORMATION; dc->r=old_r; //Updated each refresh, not guarenteed to be uniform. //Rounding error might corrupt, as well. r=Mat4x4MulMat4x4New(tmpo->g.dr,tmpo->g.r,task); Free(tmpo->g.r); tmpo->g.r=r; break; } tmpo=tmpo->next; } } PObj *PObjNew(PickFrame *pf,I64 type,I64 color) { PObj *tmpo=CAlloc(sizeof(PObj)); tmpo->type=type; tmpo->color=color; pf->o_cnts[type]++; QueIns(tmpo,pf->o_head.last); return tmpo; } U0 PObjDel(PickFrame *pf,PObj *tmpo) { QueRem(tmpo); switch (tmpo->type) { case PTY_SPRITE: Free(tmpo->g.r); Free(tmpo->g.dr); break; } pf->o_cnts[tmpo->type]--; Free(tmpo); } PObj *PPtNew(PickFrame *pf,I64 x,I64 y) { PObj *tmpo=PObjNew(pf,PTY_PT,BLACK); tmpo->p.p.x=x; tmpo->p.p.y=y; return tmpo; } PObj *PPtNum(PickFrame *pf,I64 num) { PObj *tmpo=pf->o_head.next; while (tmpo!=&pf->o_head) { if (tmpo->type==PTY_PT && !num--) return tmpo; tmpo=tmpo->next; } return NULL; } PObj *PPtFind(PickFrame *pf,I64 x,I64 y) { I64 dd,best_dd=I64_MAX; PObj *tmpo=pf->o_head.next,*res=NULL; while (tmpo!=&pf->o_head) { if (tmpo->type==PTY_PT) { dd=SqrI64(tmpo->p.p.x-x)+SqrI64(tmpo->p.p.y-y); if (dd<best_dd) { best_dd=dd; res=tmpo; } } tmpo=tmpo->next; } return res; } PObj *PCircleNew(PickFrame *pf,I64 p_num,I64 r) { PObj *tmpo=PObjNew(pf,PTY_CIRCLE,RED); tmpo->c.p=PPtNum(pf,p_num); tmpo->c.radius=r; return tmpo; } PObj *PLineNew(PickFrame *pf,I64 p1_num,I64 p2_num) { PObj *tmpo=PObjNew(pf,PTY_LINE,GREEN); tmpo->l.p1=PPtNum(pf,p1_num); tmpo->l.p2=PPtNum(pf,p2_num); return tmpo; } PObj *PCSpriteNew(PickFrame *pf,U8 *img,I64 p_num,I64 *r,I64 *dr) { PObj *tmpo=PObjNew(pf,PTY_SPRITE,BLACK); tmpo->g.p=PPtNum(pf,p_num); tmpo->g.img=img; tmpo->g.r=r; tmpo->g.dr=dr; return tmpo; } PickFrame *Init() { PickFrame *pf=CAlloc(sizeof(PickFrame)); I64 i,*r,*dr; pf->cx=Fs->pix_width>>1; pf->cy=Fs->pix_height>>1; pf->o_head.next=pf->o_head.last=&pf->o_head; for (i=0;i<50;i++) PPtNew(pf,RandI32%(pf->cx-BORDER),RandI32%(pf->cy-BORDER)); for (i=0;i<20;i++) PCircleNew(pf,pf->o_cnts[PTY_PT]*RandU16/U16_MAX,6); for (i=0;i<20;i++) PLineNew(pf,pf->o_cnts[PTY_PT]*RandU16/U16_MAX, pf->o_cnts[PTY_PT]*RandU16/U16_MAX); for (i=0;i<10;i++) { r=Mat4x4IdentNew; dr=Mat4x4IdentNew; Mat4x4RotZ(dr,0.05*2*(Rand-0.5)); Mat4x4RotY(dr,0.05*2*(Rand-0.5)); Mat4x4RotX(dr,0.05*2*(Rand-0.5)); PCSpriteNew(pf,imgs[IMGS_NUM*RandU16/U16_MAX], pf->o_cnts[PTY_PT]*RandU16/U16_MAX,r,dr); } FramePtrSet("PickFrame",pf); return pf; } U0 CleanUp(PickFrame *pf) { PObj *tmpo=pf->o_head.next,*tmpo1; while (tmpo!=&pf->o_head) { tmpo1=tmpo->next; PObjDel(pf,tmpo); tmpo=tmpo1; } Free(pf); } U0 Pick3D() { I64 msg_code,arg1,arg2; PObj *tmpo; PickFrame *pf=NULL; FramePtrAdd("PickFrame"); MenuPush( "File {" " Abort(,CH_SHIFT_ESC);" " Exit(,CH_ESC);" "}" "Play {" " Restart(,'\n');" "}" ); SettingsPush; //See SettingsPush AutoComplete; WinBorder; WinMax; DocClear; "$BK,1$Move things around.$BK,0$\n"; pf=Init; tmpo=NULL; Fs->win_inhibit=WIG_TASK_DFT-WIF_SELF_FOCUS -WIF_SELF_CTRLS-WIF_FOCUS_TASK_MENU; Fs->draw_it=&DrawIt; try { while (TRUE) { switch (msg_code=GetMsg(&arg1,&arg2, 1<<MSG_KEY_DOWN|1<<MSG_MS_L_DOWN|1<<MSG_MS_L_UP|1<<MSG_MS_MOVE)) { case MSG_KEY_DOWN: switch (arg1) { case '\n': CleanUp(pf); pf=Init; tmpo=NULL; break; case CH_SHIFT_ESC: case CH_ESC: goto pd_done; } break; case MSG_MS_L_DOWN: tmpo=PPtFind(pf,arg1-pf->cx,arg2-pf->cy); break; case MSG_MS_L_UP: if (tmpo) { tmpo->p.p.x=arg1-pf->cx; tmpo->p.p.y=arg2-pf->cy; tmpo=NULL; } break; case MSG_MS_MOVE: if (tmpo) { tmpo->p.p.x=arg1-pf->cx; tmpo->p.p.y=arg2-pf->cy; } break; } } pd_done: GetMsg(,,1<<MSG_KEY_UP); } catch PutExcept; SettingsPop; MenuPop; CleanUp(pf); FramePtrDel("PickFrame"); } Pick3D;