/* There is a coarse and a fine-grained. The coarse gets flood-filled but the fine grained is only outlines. */ class Photon { Photon *next,*last; CD3 p,v,p_snell_inhibit; } p_root[mp_cnt]; I64 p_root_locks; #define ANIMATE_JIFFIES (JIFFY_FREQ*0.01) I64 master_sleep_jiffy; CTask *animate_tasks[mp_cnt]; CDC *map; I64 photon_cnt,snell_cnt; Bool full_speed; U8 *bmp; F64 bmp_scale,bmp_scale_sqr; I64 bmp_mem,bmp_width,bmp_height,bmp_norm_radius; I64 BmpPeek(I64 x,I64 y) { if (0<=xcolor=WHITE; GrPrint(dc,0,0,"Mem:0x%X %,dMeg Scale:%0.3f (%d,%d)-->(%d,%d)", bmp_mem,bmp_mem/1024/1024,bmp_scale, map->width,map->height,bmp_width,bmp_height); GrPrint(dc,0,FONT_HEIGHT,"PhotonCnt:%d SnellCnt:%d",photon_cnt,snell_cnt); for (i=0;icolor=LTRED; GrLine(dc,tmpp->p.x-TAIL*tmpp->v.x,tmpp->p.y-TAIL*tmpp->v.y, tmpp->p.x,tmpp->p.y); tmpp=tmpp->next; } LBtr(&p_root_locks,i); } } U0 RayBurst(I64 x1,I64 y1,I64 x2,I64 y2) { CD3 p,v,n,n2; I64 i; Photon *tmpp; D3Equ(&p,x2,y2); D3Equ(&v,x2-x1,y2-y1); D3Unit(&v); D3Equ(&n,v.y,-v.x); tmpp=PhotonNew; D3Copy(&tmpp->p,&p); D3Copy(&tmpp->v,&v); for (i=2;i<=9;i+=3) { D3Mul(&n2,i,&n); tmpp=PhotonNew; D3Add(&tmpp->p,&p,&n2); D3Copy(&tmpp->v,&v); tmpp=PhotonNew; D3Sub(&tmpp->p,&p,&n2); D3Copy(&tmpp->v,&v); } } U0 RandomBurst() { I64 i; F64 é; Photon *tmpp; for (i=0;i<256;i++) { tmpp=PhotonNew; D3Equ(&tmpp->p,Fs->pix_width*Rand,Fs->pix_height*Rand); é=2*ã*Rand; D3Equ(&tmpp->v,Cos(é),Sin(é)); } } U0 FindNormal(Photon *tmpp,CD3 *_normal) { CD3 p,p1,p2,v,s; F64 é=Arg(tmpp->v.x,tmpp->v.y),è; D3Copy(&tmpp->p_snell_inhibit,&tmpp->p); //Coarse grains has black and white filled-in BSplines. //Fine grained has only white outline without being filled-in. //Back-up a step and move fwd to get a fined-grained value //for the point of contact. D3SubEqu(&tmpp->p,&tmpp->v); D3Mul(&p,bmp_scale,&tmpp->p); D3Copy(&p1,&p); while (BmpPeek(p1.x,p1.y)==BLACK && D3DistSqr(&p,&p1)v); D3Copy(&p,&p1); D3Div(&tmpp->p,&p,bmp_scale); //Draw an arc one direction, finding point of contact. for (è=0;è<ã/2;è+=ã/bmp_norm_radius) { D3Equ(&s,Cos(é+ã-ã/4-è),Sin(é+ã-ã/4-è)); D3Mul(&v,bmp_norm_radius,&s); D3Add(&p1,&p,&v); if (BmpPeek(p1.x,p1.y)!=BLACK) break; } if (BmpPeek(p1.x,p1.y)!=WHITE) D3Copy(&p1,&tmpp->p); //Draw an arc other direction, finding point of contact. for (è=0;è<ã/2;è+=ã/bmp_norm_radius) { D3Equ(&s,Cos(é+ã+ã/4+è),Sin(é+ã+ã/4+è)); D3Mul(&v,bmp_norm_radius,&s); D3Add(&p2,&p,&v); if (BmpPeek(p2.x,p2.y)!=BLACK) break; } if (BmpPeek(p2.x,p2.y)!=WHITE) D3Copy(&p2,&tmpp->p); D3Sub(&s,&p1,&p2); D3Equ(_normal,s.y,-s.x); if (D3Dot(_normal,&tmpp->v)<0) D3Equ(_normal,-s.y,s.x); D3Unit(_normal); } U0 SnellsLaw(Photon *tmpp,I64 last,I64 next) { //n1 and n2 are refraction index. //n1 Sin(é1) == n2 Sin(é2) F64 é=Arg(tmpp->v.x,tmpp->v.y),én,n1,n2,é1,é2,éa,éb; CD3 normal; if (last==WHITE) n1=1.5; else n1=1.0; if (next==WHITE) n2=1.5; else n2=1.0; FindNormal(tmpp,&normal); én=Arg(normal.x,normal.y); //dot=m1m2Cos(é); é1=ACos(D3Dot(&normal,&tmpp->v)); é2=ASin(n1*Sin(é1)/n2); //é --> (én+é1) //é <-- (én+é2) éa=én+é2; éb=én-é2; if (Abs(Wrap(éa-é))v,Cos(é),Sin(é)); lock {snell_cnt++;} } U0 AnimateTask(I64) { while (TRUE) { master_sleep_jiffy+=ANIMATE_JIFFIES; if (cnts.jiffies>=master_sleep_jiffy) master_sleep_jiffy=cnts.jiffies+ANIMATE_JIFFIES; SleepUntil(master_sleep_jiffy); } } U0 MPAnimateTask(I64) { I64 last_master_jiffy=0, timeout_jiffy=master_sleep_jiffy+ANIMATE_JIFFIES, last,next; Photon *tmpp,*root=&p_root[Gs->num]; while (TRUE) { while (LBts(&p_root_locks,Gs->num)) Yield; tmpp=root->next; while (tmpp!=root) { last=GrPeek(map,tmpp->p.x,tmpp->p.y); D3AddEqu(&tmpp->p,&tmpp->v); if (tmpp->p.x<0) { tmpp->p.x=-tmpp->p.x; tmpp->v.x=-tmpp->v.x; } if (tmpp->p.x>=map->width) { tmpp->p.x-=tmpp->p.x-map->width; tmpp->v.x=-tmpp->v.x; } if (tmpp->p.y<0) { tmpp->p.y=-tmpp->p.y; tmpp->v.y=-tmpp->v.y; } if (tmpp->p.y>=map->height) { tmpp->p.y-=tmpp->p.y-map->height; tmpp->v.y=-tmpp->v.y; } next=GrPeek(map,tmpp->p.x,tmpp->p.y); if (last!=next && (last==BLACK && next==WHITE) || (last==WHITE && next==BLACK) && //Don't do a snell operation too close to the last. Just ignore it. D3DistSqr(&tmpp->p_snell_inhibit,&tmpp->p)>=4.0) SnellsLaw(tmpp,last,next); tmpp=tmpp->next; if (cnts.jiffies>=timeout_jiffy) break; } LBtr(&p_root_locks,Gs->num); if (cnts.jiffies>=timeout_jiffy) { Sleep(1); timeout_jiffy=master_sleep_jiffy+ANIMATE_JIFFIES; } if (!full_speed) { while (master_sleep_jiffy==last_master_jiffy) Sleep(1); last_master_jiffy=master_sleep_jiffy; SleepUntil(master_sleep_jiffy); timeout_jiffy=master_sleep_jiffy+ANIMATE_JIFFIES; } } } U0 Init() { I64 i; master_sleep_jiffy=cnts.jiffies; full_speed=FALSE; photon_cnt=snell_cnt=0; map=DCNew(Fs->pix_width,Fs->pix_height); for (i=0;ipix_height/Fs->pix_width)/Fs->pix_height; bmp_scale_sqr=Sqr(bmp_scale); bmp_width =bmp_scale*Fs->pix_width; bmp_height=bmp_scale*Fs->pix_height; bmp=CAlloc(bmp_width*bmp_height/8); bmp_norm_radius=Min(10*bmp_scale,250); } U0 CleanUp() { I64 i; for (i=0;i$$FG$$.\n\n" "$$GREEN$${Right-drag}$$FG$$ to fire rays.\n" ); SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$ Fs->win_inhibit=WIG_TASK_DFT-WIF_SELF_FOCUS- WIF_SELF_BORDER-WIF_FOCUS_TASK_MENU; Fs->text_attr=BLACK<<4+WHITE; //Current $LK,"CTask",A="MN:CTask"$ is Fs segment register. AutoComplete; WinBorder; WinMax; DocCursor; DocClear; Init; Fs->draw_it=&DrawIt; Fs->animate_task=Spawn(&AnimateTask,NULL,"Animate",,Fs); for (i=0;icolor=ROP_XOR+WHITE; do { c[cnt].x=arg1; c[cnt].y=arg2; c[cnt].z=0; Gr2BSpline(map,c,cnt+1); msg_code=GetMsg(&arg1,&arg2, 1<color=WHITE; Gr2BSpline3(map,c,cnt); for (i=0;ipix_left,ms.pos.y-Fs->pix_top); break; case '\n': CleanUp; Init; break; case 'r': RandomBurst; break; case 'e': full_speed=TRUE; Sleep(1500); FlushMsgs; full_speed=FALSE; break; case CH_ESC: case CH_SHIFT_ESC: goto lt_done; } break; } } lt_done: GetMsg(,,1<