hschumann2/TempleOS-Source-Code
0847
1 2/*3There is a coarse and a fine-grained.4The coarse gets flood-filled but the5fine grained is only outlines.6*/7 8class Photon9{10 Photon *next,*last;11 CD3 p,v,n,p_normal_inhibit;12} p_root[mp_cnt];13I64 p_root_locks;14 15#define ANIMATE_JIFFIES (JIFFY_FREQ*0.01)16I64 master_sleep_jiffy;17CTask *animate_tasks[mp_cnt];18 19#define LENS_COLOR WHITE20#define MIRROR_COLOR DKGRAY21CDC *map;22 23I64 photon_cnt,mirror_cnt,snell_cnt,normal_inhibit,zero_normal;24Bool full_speed,show_normals;25 26U8 *bmp_refract,*bmp_reflect;27F64 bmp_scale,find_normal_dist_sqr;28I64 bmp_mem,bmp_width,bmp_height,bmp_norm_radius;29 30#define BORDER 1031I64 BmpPeek(U8 *bmp,I64 x,I64 y)32{33 return Bt(bmp,y*bmp_width+x);34}35 36U0 BmpPlot(U8 *bmp,I64 x,I64 y,I64)37{38 if (0<=x<bmp_width && 0<=y<bmp_height)39 Bts(bmp,y*bmp_width+x);40}41 42U0 BmpLine(U8 *bmp,F64 x1,F64 y1,F64 x2,F64 y2)43{44 Line(bmp,x1*bmp_scale,y1*bmp_scale,0,x2*bmp_scale,y2*bmp_scale,0,&BmpPlot);45}46 47Photon *PhotonNew()48{49 I64 num=photon_cnt++%mp_cnt;50 Photon *res=CAlloc(sizeof(Photon));51 while (LBts(&p_root_locks,num))52 Yield;53 QueIns(res,p_root[num].last);54 LBtr(&p_root_locks,num);55 return res;56}57 58#define VECTOR 2059U0 DrawIt(CTask *,CDC *dc)60{61 I64 i;62 Photon *tmpp;63 GrBlot(dc,0,0,map);64 dc->color=WHITE;65 GrPrint(dc,0,0,"Mem:0x%X %,dMeg Scale:%0.3f (%d,%d)-->(%d,%d)",66 bmp_mem,bmp_mem/1024/1024,bmp_scale,67 map->width,map->height,bmp_width,bmp_height);68 GrPrint(dc,0,FONT_HEIGHT,69 "PhotonCnt:%d MirrorCnt:%d SnellCnt:%d SnellInhibit:%d ZeroNormal:%d",70 photon_cnt,mirror_cnt,snell_cnt,normal_inhibit,zero_normal);71 for (i=0;i<mp_cnt;i++) {72 while (LBts(&p_root_locks,i))73 Yield;74 tmpp=p_root[i].next;75 while (tmpp!=&p_root[i]) {76 dc->color=LTRED;77 GrLine(dc,tmpp->p.x-VECTOR*tmpp->v.x,tmpp->p.y-VECTOR*tmpp->v.y,78 tmpp->p.x,tmpp->p.y);79 if (show_normals) {80 dc->color=LTGREEN;81 GrLine(dc,tmpp->p.x,tmpp->p.y,82 tmpp->p.x+VECTOR*tmpp->n.x,tmpp->p.y+VECTOR*tmpp->n.y);83 }84 tmpp=tmpp->next;85 }86 LBtr(&p_root_locks,i);87 }88}89 90#define WING 991 92U0 RayBurst(I64 x1,I64 y1,I64 x2,I64 y2)93{94 CD3 p,v,n,n2;95 I64 i;96 Photon *tmpp;97 if ((x1!=x2 || y1!=y2) && BORDER+WING<x2<map->width-BORDER-WING &&98 BORDER+WING<y2<map->height-BORDER-WING) {99 D3Equ(&p,x2,y2);100 D3Equ(&v,x2-x1,y2-y1);101 D3Unit(&v);102 D3Equ(&n,v.y,-v.x);103 104 tmpp=PhotonNew;105 D3Copy(&tmpp->p,&p);106 D3Copy(&tmpp->v,&v);107 108 for (i=2;i<=WING;i+=3) {109 D3Mul(&n2,i,&n);110 111 tmpp=PhotonNew;112 D3Add(&tmpp->p,&p,&n2);113 D3Copy(&tmpp->v,&v);114 115 tmpp=PhotonNew;116 D3Sub(&tmpp->p,&p,&n2);117 D3Copy(&tmpp->v,&v);118 }119 }120}121 122U0 RandomBurst()123{124 I64 i;125 F64 theta;126 Photon *tmpp;127 for (i=0;i<256;i++) {128 tmpp=PhotonNew;129 D3Equ(&tmpp->p,(Fs->pix_width-BORDER*2)*Rand+BORDER,130 (Fs->pix_height-BORDER*2)*Rand+BORDER);131 theta=2*pi*Rand;132 D3Equ(&tmpp->v,Cos(theta),Sin(theta));133 }134}135 136U0 FindNormal(U8 *bmp,Photon *tmpp)137{138 CD3 p,p1,p2;139 F64 step,x,y,theta=Arg(tmpp->v.x,tmpp->v.y),phi;140 I64 state;141 142 D3Copy(&tmpp->p_normal_inhibit,&tmpp->p);143 144 //Coarse grains has black and white filled-in BSplines.145 //Fine grained has only white outline without being filled-in.146 147 //Back-up a step and move fwd to get a fined-grained value148 //for the point of contact.149 D3SubEqu(&tmpp->p,&tmpp->v);150 D3Mul(&p,bmp_scale,&tmpp->p);151 D3Copy(&p1,&p);152 while (BmpPeek(bmp,p1.x,p1.y)==BLACK &&153 D3DistSqr(&p,&p1)<find_normal_dist_sqr)154 D3AddEqu(&p1,&tmpp->v);155 D3Copy(&p,&p1);156 D3Div(&tmpp->p,&p,bmp_scale);157 158 //Draw an arc one direction, finding point of contact.159 for (step=1.0;step>=0.01;step/=4) {160 for (phi=0;phi<=pi/4;phi+=step*pi/bmp_norm_radius) {161 x=p.x+bmp_norm_radius*Cos(theta+pi-pi/4-phi);162 y=p.y+bmp_norm_radius*Sin(theta+pi-pi/4-phi);163 if (state=BmpPeek(bmp,x,y))164 goto fn_p1;165 x=p.x+bmp_norm_radius*Cos(theta+pi-pi/4+phi);166 y=p.y+bmp_norm_radius*Sin(theta+pi-pi/4+phi);167 if (state=BmpPeek(bmp,x,y))168 goto fn_p1;169 }170 for (;phi<=3*pi/4;phi+=step*pi/bmp_norm_radius) {171 x=p.x+bmp_norm_radius*Cos(theta+pi-pi/4-phi);172 y=p.y+bmp_norm_radius*Sin(theta+pi-pi/4-phi);173 if (state=BmpPeek(bmp,x,y))174 goto fn_p1;175 }176 }177fn_p1:178 if (state)179 D3Equ(&p1,x,y);180 else181 D3Copy(&p1,&tmpp->p);182 183 //Draw an arc other direction, finding point of contact.184 for (step=1.0;step>=0.01;step/=4) {185 for (phi=0;phi<=pi/4;phi+=step*pi/bmp_norm_radius) {186 x=p.x+bmp_norm_radius*Cos(theta+pi+pi/4+phi);187 y=p.y+bmp_norm_radius*Sin(theta+pi+pi/4+phi);188 if (state=BmpPeek(bmp,x,y))189 goto fn_p2;190 x=p.x+bmp_norm_radius*Cos(theta+pi+pi/4-phi);191 y=p.y+bmp_norm_radius*Sin(theta+pi+pi/4-phi);192 if (state=BmpPeek(bmp,x,y))193 goto fn_p2;194 }195 for (;phi<=3*pi/4;phi+=step*pi/bmp_norm_radius) {196 x=p.x+bmp_norm_radius*Cos(theta+pi+pi/4+phi);197 y=p.y+bmp_norm_radius*Sin(theta+pi+pi/4+phi);198 if (state=BmpPeek(bmp,x,y))199 goto fn_p2;200 }201 }202fn_p2:203 if (state)204 D3Equ(&p2,x,y);205 else206 D3Copy(&p2,&tmpp->p);207 208 D3Sub(&p,&p1,&p2);209 if (D3NormSqr(&p)<0.01) {210 D3Equ(&tmpp->n,Cos(theta),Sin(theta));211 lock {zero_normal++;}212 } else {213 D3Equ(&tmpp->n,p.y,-p.x);214 if (D3Dot(&tmpp->n,&tmpp->v)<0)215 D3Equ(&tmpp->n,-p.y,p.x);216 D3Unit(&tmpp->n);217 }218}219 220U0 Mirror(Photon *tmpp)221{/*<1>/* Graphics Not Rendered in HTML */222 223 224 225 226 227 228 229 230 231 232thetaout = pi+thetan - (thetain-thetan)233 234*/235 F64 theta=Arg(tmpp->v.x,tmpp->v.y),thetan;236 FindNormal(bmp_reflect,tmpp);237 thetan=Arg(tmpp->n.x,tmpp->n.y);238 239 D3Equ(&tmpp->v,Cos(2*thetan+pi-theta),Sin(2*thetan+pi-theta));240 lock {mirror_cnt++;}241}242 243U0 SnellsLaw(Photon *tmpp,I64 last,I64 next)244{245//n1 and n2 are refraction index.246//n1 Sin(theta1) == n2 Sin(theta2)247 F64 theta=Arg(tmpp->v.x,tmpp->v.y),thetan,n1,n2,theta1,theta2;248 if (last==LENS_COLOR)249 n1=1.5;250 else251 n1=1.0;252 if (next==LENS_COLOR)253 n2=1.5;254 else255 n2=1.0;256 FindNormal(bmp_refract,tmpp);257 thetan=Arg(tmpp->n.x,tmpp->n.y);258 259 //Dot=m1m2Cos(theta);260 theta1=ACos(D3Dot(&tmpp->n,&tmpp->v));261 theta2=ASin(n1*Sin(theta1)/n2);262 if (Wrap(theta-thetan)>=0)263 theta=thetan+theta2;264 else265 theta=thetan-theta2;266 267 D3Equ(&tmpp->v,Cos(theta),Sin(theta));268 lock {snell_cnt++;}269}270 271U0 AnimateTask(I64)272{273 while (TRUE) {274 master_sleep_jiffy+=ANIMATE_JIFFIES;275 if (cnts.jiffies>=master_sleep_jiffy)276 master_sleep_jiffy=cnts.jiffies+ANIMATE_JIFFIES;277 SleepUntil(master_sleep_jiffy);278 }279}280 281#define BABY_STEPS 4282 283U0 MPAnimateTask(I64)284{285 I64 i,last_master_jiffy=0,286 timeout_jiffy=master_sleep_jiffy+ANIMATE_JIFFIES,287 last,next;288 Bool inhibit;289 CD3 step;290 Photon *tmpp,*root=&p_root[Gs->num];291 while (TRUE) {292 while (LBts(&p_root_locks,Gs->num))293 Yield;294 tmpp=root->next;295 while (tmpp!=root) {296 for (i=0;i<BABY_STEPS;i++) {297 last=GrPeek(map,tmpp->p.x,tmpp->p.y);298 D3Div(&step,&tmpp->v,BABY_STEPS);299 D3AddEqu(&tmpp->p,&step);300 if (tmpp->p.x<BORDER) {301 tmpp->p.x=2*BORDER-tmpp->p.x;302 tmpp->v.x=-tmpp->v.x;303 }304 if (tmpp->p.x>=map->width-BORDER) {305 tmpp->p.x-=tmpp->p.x-map->width+BORDER;306 tmpp->v.x=-tmpp->v.x;307 }308 if (tmpp->p.y<BORDER) {309 tmpp->p.y=2*BORDER-tmpp->p.y;310 tmpp->v.y=-tmpp->v.y;311 }312 if (tmpp->p.y>=map->height-BORDER) {313 tmpp->p.y-=tmpp->p.y-map->height+BORDER;314 tmpp->v.y=-tmpp->v.y;315 }316 next=GrPeek(map,tmpp->p.x,tmpp->p.y);317 318 if (D3DistSqr(&tmpp->p_normal_inhibit,&tmpp->p)<4.0)319 inhibit=TRUE;320 else321 inhibit=FALSE;322 323 if (last!=next) {324 if ((last==BLACK && next==LENS_COLOR) ||325 (last==LENS_COLOR && next==BLACK)) {326 if (inhibit)327 lock {normal_inhibit++;}328 else329 SnellsLaw(tmpp,last,next);330 } else if (last==BLACK && next==MIRROR_COLOR) {331 if (inhibit)332 lock {normal_inhibit++;}333 else334 Mirror(tmpp);335 } else if (!inhibit)336 D3Zero(&tmpp->p_normal_inhibit);337 } else if (!inhibit)338 D3Zero(&tmpp->p_normal_inhibit);339 }340 341 tmpp=tmpp->next;342 if (cnts.jiffies>=timeout_jiffy)343 break;344 }345 LBtr(&p_root_locks,Gs->num);346 if (cnts.jiffies>=timeout_jiffy) {347 Sleep(1);348 timeout_jiffy=master_sleep_jiffy+ANIMATE_JIFFIES;349 }350 if (!full_speed) {351 while (master_sleep_jiffy==last_master_jiffy)352 Sleep(1);353 last_master_jiffy=master_sleep_jiffy;354 SleepUntil(master_sleep_jiffy);355 timeout_jiffy=master_sleep_jiffy+ANIMATE_JIFFIES;356 }357 }358}359 360U0 Init()361{362 I64 i;363 master_sleep_jiffy=cnts.jiffies;364 full_speed=show_normals=FALSE;365 photon_cnt=mirror_cnt=snell_cnt=normal_inhibit=zero_normal=0;366 map=DCNew(Fs->pix_width,Fs->pix_height);367 for (i=0;i<mp_cnt;i++) {368 while (LBts(&p_root_locks,i))369 Yield;370 QueInit(&p_root[i]);371 LBtr(&p_root_locks,i);372 }373//x*y=bmp_mem*8374 //x/y=640/480375 //x=640/480*y376 //640/480*y^2=bmp_mem*8377 //y=Sqrt(bmp_mem*8*480/640)378 //bmp_scale=Sqrt(bmp_mem*8*480/640)/480379 bmp_scale=Sqrt(bmp_mem/2*8*Fs->pix_height/Fs->pix_width)/Fs->pix_height;380 381 find_normal_dist_sqr=2*Sqr(bmp_scale);382#assert Sqrt(2)<=BORDER383 384 bmp_width =bmp_scale*Fs->pix_width;385 bmp_height=bmp_scale*Fs->pix_height;386 bmp_refract=CAlloc(bmp_width*bmp_height/8);387 bmp_reflect=CAlloc(bmp_width*bmp_height/8);388 bmp_norm_radius=Min(10*bmp_scale,250);389#assert 10<=BORDER390}391 392U0 CleanUp()393{394 I64 i;395 for (i=0;i<mp_cnt;i++) {396 while (LBts(&p_root_locks,i))397 Yield;398 QueDel(&p_root[i],TRUE);399 LBtr(&p_root_locks,i);400 }401 DCDel(map);402 Free(bmp_refract);403 Free(bmp_reflect);404}405 406#define LTM_REFLECT_LINE 0407#define LTM_REFLECT_SPLINE 1408#define LTM_REFRACT_LINE 2409#define LTM_REFRACT_SPLINE 3410#define LTM_REFRACT_FLOOD_FILL 4411#define LTM_TEST_RAY 5412 413U0 LTMenuSet(I64 mode)414{415 CMenuEntry *entry=MenuEntryFind(Fs->cur_menu,"View/ToggleNormals");416 if (show_normals)417 entry->checked=TRUE;418 else419 entry->checked=FALSE;420 421 entry=MenuEntryFind(Fs->cur_menu,"Mode/ReflectLine");422 if (mode==LTM_REFLECT_LINE)423 entry->checked=TRUE;424 else425 entry->checked=FALSE;426 entry=MenuEntryFind(Fs->cur_menu,"Mode/ReflectSpline");427 if (mode==LTM_REFLECT_SPLINE)428 entry->checked=TRUE;429 else430 entry->checked=FALSE;431 entry=MenuEntryFind(Fs->cur_menu,"Mode/RefractLine");432 if (mode==LTM_REFRACT_LINE)433 entry->checked=TRUE;434 else435 entry->checked=FALSE;436 entry=MenuEntryFind(Fs->cur_menu,"Mode/RefractSpline");437 if (mode==LTM_REFRACT_SPLINE)438 entry->checked=TRUE;439 else440 entry->checked=FALSE;441 entry=MenuEntryFind(Fs->cur_menu,"Mode/RefractFloodFill");442 if (mode==LTM_REFRACT_FLOOD_FILL)443 entry->checked=TRUE;444 else445 entry->checked=FALSE;446 entry=MenuEntryFind(Fs->cur_menu,"Mode/TestRay");447 if (mode==LTM_TEST_RAY)448 entry->checked=TRUE;449 else450 entry->checked=FALSE;451}452 453#define PTS_NUM 1024454U0 LightTable()455{456 I64 msg_code,mode=LTM_REFLECT_LINE,i,cnt,arg1,arg2,x1,y1,x2,y2;457 CD3I32 *c=MAlloc(PTS_NUM*sizeof(CD3I32));458 459 p_root_locks=0;460 MenuPush(461 "File {"462 " Restart(,'\n');"463 " Abort(,CH_SHIFT_ESC);"464 " Exit(,CH_ESC);"465 "}"466 "Mode {"467 " ReflectLine(,'0');"468 " ReflectSpline(,'1');"469 " RefractLine(,'2');"470 " RefractSpline(,'3');"471 " RefractFloodFill(,'4');"472 " TestRay(,'5');"473 "}"474 "Play {"475 " RandomBurst(,'r');"476 " ElapseTime(,'e');"477 "}"478 "View {"479 " ToggleNormals(,'n');"480 "}"481 );482 LTMenuSet(mode);483 484 MemBIOSRep;485 bmp_mem=GetI64("\n\n\nHow much memory for the high resolution\n"486 "shadow bitmap that helps improve the\n"487 "accuracy of the normal vector estimate?\n"488 "You can choose up to the largest\n"489 "contiguous chunk of physical memory.\n\n"490 "Mem (0x%0X):",1024*1024*16);491 492 SettingsPush; //See SettingsPush493 Fs->win_inhibit=WIG_TASK_DFT-WIF_SELF_FOCUS-494 WIF_SELF_BORDER-WIF_FOCUS_TASK_MENU;495 Fs->text_attr=BLACK<<4+WHITE; //Current CTask is Fs segment register.496 AutoComplete;497 WinBorder;498 WinMax;499 DocCursor;500 DocClear;501 Init;502 Fs->draw_it=&DrawIt;503 Fs->animate_task=Spawn(&AnimateTask,NULL,"Animate",,Fs);504 for (i=0;i<mp_cnt;i++)505 animate_tasks[i]=Spawn(&MPAnimateTask,NULL,"MPAnimate",i);506 try {507 while (TRUE) {508 msg_code=GetMsg(&arg1,&arg2,509 1<<MSG_KEY_DOWN+1<<MSG_MS_L_DOWN+1<<MSG_MS_L_UP+1<<MSG_MS_R_UP);510lt_restart:511 switch (msg_code) {512 case MSG_MS_L_UP:513 Sweep(100,90,100);514 x2=arg1; y2=arg2;515 switch (mode) {516 case LTM_REFRACT_FLOOD_FILL:517 map->color=LENS_COLOR;518 GrFloodFill(map,x2,y2);519 mode=LTM_REFLECT_LINE;520 LTMenuSet(mode);521 break;522 case LTM_TEST_RAY:523 RayBurst(x1,y1,x2,y2);524 break;525 }526 break;527 case MSG_MS_L_DOWN:528 x1=arg1; y1=arg2;529 switch (mode) {530 case LTM_REFLECT_LINE:531 case LTM_REFRACT_LINE:532 if (mode==LTM_REFLECT_LINE)533 map->color=ROP_XOR+MIRROR_COLOR;534 else535 map->color=ROP_XOR+LENS_COLOR;536 while (TRUE) {537 x2=arg1; y2=arg2;538 GrLine(map,x1,y1,x2,y2);539 msg_code=GetMsg(&arg1,&arg2,540 1<<MSG_KEY_DOWN+1<<MSG_MS_L_UP+1<<MSG_MS_MOVE);541 GrLine(map,x1,y1,x2,y2);542 if (msg_code==MSG_KEY_DOWN)543 goto lt_restart;544 else if (msg_code==MSG_MS_L_UP) {545 Sweep(100,90,100);546 x2=arg1; y2=arg2;547 break;548 }549 }550 if (mode==LTM_REFLECT_LINE)551 map->color=MIRROR_COLOR;552 else553 map->color=LENS_COLOR;554 GrLine(map,x1,y1,x2,y2);555 if (mode==LTM_REFLECT_LINE)556 BmpLine(bmp_reflect,x1,y1,x2,y2);557 else558 BmpLine(bmp_refract,x1,y1,x2,y2);559 break;560 case LTM_REFLECT_SPLINE:561 case LTM_REFRACT_SPLINE:562 cnt=0;563 if (mode==LTM_REFLECT_SPLINE)564 map->color=ROP_XOR+MIRROR_COLOR;565 else566 map->color=ROP_XOR+LENS_COLOR;567 do {568 c[cnt].x=arg1; c[cnt].y=arg2; c[cnt].z=0;569 Gr2BSpline(map,c,cnt+1);570 msg_code=GetMsg(&arg1,&arg2,1<<MSG_KEY_DOWN+1<<MSG_MS_L_UP+571 1<<MSG_MS_MOVE+1<<MSG_MS_R_UP);572 Gr2BSpline(map,c,cnt+1);573 if (msg_code==MSG_KEY_DOWN)574 goto lt_restart;575 else if (msg_code==MSG_MS_L_UP) {576 Sweep(100,90,100);577 cnt++;578 }579 } while (cnt<PTS_NUM-1 && msg_code!=MSG_MS_R_UP);580 if (mode==LTM_REFLECT_SPLINE)581 map->color=MIRROR_COLOR;582 else583 map->color=LENS_COLOR;584 Gr2BSpline3(map,c,cnt);585 for (i=0;i<cnt;i++) {586 c[i].x*=bmp_scale;587 c[i].y*=bmp_scale;588 }589 if (mode==LTM_REFLECT_SPLINE)590 BSpline2(bmp_reflect,c,cnt,&BmpPlot);591 else592 BSpline2(bmp_refract,c,cnt,&BmpPlot);593 mode=LTM_REFLECT_LINE;594 LTMenuSet(mode);595 break;596 }597 break;598 case MSG_MS_R_UP:599 i=PopUpPickLst("Reflect Line\0Reflect Spline\0Refract Line\0"600 "Refract Spline\0Refract Flood Fill\0TestRay\0");601 if (i>=0) {602 mode=i;603 LTMenuSet(mode);604 }605 break;606 case MSG_KEY_DOWN:607 switch (arg1) {608 case '\n':609 CleanUp;610 Init;611 mode=LTM_REFLECT_LINE;612 LTMenuSet(mode);613 break;614 case 'r':615 RandomBurst;616 break;617 case 'e':618 full_speed=TRUE;619 Sleep(1500);620 FlushMsgs;621 full_speed=FALSE;622 break;623 case 'n':624 show_normals=!show_normals;625 LTMenuSet(mode);626 break;627 case '0'...'5':628 mode=arg1-'0';629 LTMenuSet(mode);630 break;631 case CH_ESC:632 case CH_SHIFT_ESC:633 goto lt_done;634 }635 break;636 }637 }638lt_done:639 GetMsg(,,1<<MSG_KEY_UP);640 } catch641 PutExcept;642 Free(c);643 SettingsPop;644 for (i=0;i<mp_cnt;i++)645 Kill(animate_tasks[i]);646 CleanUp;647 MenuPop;648}649 650LightTable;651 