/*_______________________________________________________________ tc-012.c Function: This program demonstrates high speed frame animation of a 3D shaded object. Visual perception of the model is improved by the rotation of the model, which enhances the three dimensional effect. Compatibility: Supports VGA and EGA graphics adapters and monitors. The software uses the 640x200 16-color mode. Remarks: The speed of the microprocessor has a dramatic effect upon the required animation speed. Refer to the book. Copyright 1988 Lee Adams and TAB BOOKS Inc. _________________________________________________________________ I N C L U D E F I L E S */ #include /* supports the printf function */ #include /* supports the graphics functions */ #include /* supports the exit() function */ #include /* supports read of keyboard buffer */ #include /* supports the sine and cosine functions */ /*_______________________________________________________________ D E C L A R A T I O N S */ void keyboard(void);void quit_pgm(void); void notice(float x,float y);void coords(void); void graphics_setup(void);void labels(void);void draw_object(void); void calc_3d(void);void rotation(void);void window(void); void line_clip(void);void get_coords(void);void draw_poly(void); void animVGAEGA(void); int t1=1,t2=2,t3=1; /* loop counters */ float x_res,y_res; /* used by compatibility mapping routine */ int C0=0,C1=1,C2=2,C3=3,C4=4,C5=5,C6=6,C7=7,C8=8,C9=9,C10=10, C11=11,C12=12,C13=13,C14=14,C15=15,mode_flag=0; /* colors */ int CLR,CLR1,CLR2,CLR3,EDGE; int p1=0,p2=0; /* pointer into arrays */ float x=0.0,y=0.0,z=0.0; /* world coordinates */ float sx=0.0,sy=0.0; /* output of 3D perspective formulas */ float xa=0.0,ya=0.0,za=0.0; /* temporary values in 3D formulas */ float sxa=0.0,sya=0.0,sxb=0.0,syb=0.0; /* 2D line endpoints */ float sxs=0.0,sys=0.0; /* temp storage of 2D line startpoint */ float temp_swap=0.0; /* used for variable swaps */ float d=1200.0; /* angular perspective factor */ double r1=.48539; /* yaw angle in radians */ double r2=6.28319; /* roll angle in radians */ double r3=5.79778; /* pitch angle in radians */ double sr1=0.0,sr2=0.0,sr3=0.0; /* sine rotation factors */ double cr1=0.0,cr2=0.0,cr3=0.0; /* cosine rotation factors */ float mx=0.0,my=-5.0,mz=-250.0; /* viewpoint position */ int maxx=638,minx=1,maxy=198,miny=1; /* clipping viewport */ float c=0.0; /* used in line-clipping routine */ float screen_x=639,screen_y=199; /* dimensions of screen mode */ float rx=0.0,ry=0.0; /* scaling values used in mapping routine */ /* database of xyz world coordinates */ int array_xyz[][3]={ 20,-20,-30, 20,20,-30, 20,20,-20, 20,-20,-20, 20,-20,-30, 20,0,-25, 20,-20,-30, -20,-20,-30, -20,-20,-20, 20,-20,-20, 20,-20,-30, 0,-20,-25, -30,30,-30, 30,30,-30, 30,30,-20, -30,30,-20, -30,30,-30, 0,30,-25, -30,30,-30, -30,30,-20, -30,-30,-20, -30,-30,-30, -30,30,-30, -30,0,-25, -30,30,-20, 30,30,-20, 30,20,-20, -30,20,-20, -30,30,-20, 0,25,-20, 30,30,-20, 30,-30,-20, 20,-30,-20, 20,30,-20, 30,30,-20, 25,0,-20, 30,-30,-20, -30,-30,-20, -30,-20,-20, 30,-20,-20, 30,-30,-20, 0,-25,-20, -30,-30,-20, -30,30,-20, -20,30,-20, -20,-30,-20, -30,-30,-20, -25,0,-20, 20,-30,-20, 20,-20,-20, 20,-20,20, 20,-30,20, 20,-30,-20, 20,-25,0, -30,-30,30, -30,-20,30, 30,-20,30, 30,-30,30, -30,-30,30, 0,-25,30, -30,-30,-30, -30,-20,-30, -30,-20,30, -30,-30,30, -30,-30,-30, -30,-25,0, -30,-20,-20, -20,-20,-20, -20,-20,30, -30,-20,30, -30,-20,-20, -25,-20,0, 30,-20,-20, 30,-20,30, 20,-20,30, 20,-20,-20, 30,-20,-20, 25,-20,0, -30,-20,30, -30,-20,20, 30,-20,20, 30,-20,30, -30,-20,30, 0,-20,25, 20,30,-20, 20,30,30, 20,20,30, 20,20,-20, 20,30,-20, 20,25,0, 20,30,30, 20,-20,30, 20,-20,20, 20,30,20, 20,30,30, 20,0,25, -30,30,-30, -20,30,-30, -20,30,30, -30,30,30, -30,30,-30, -25,30,0, 20,30,-30, 30,30,-30, 30,30,30, 20,30,30, 20,30,-30, 25,30,0, -30,30,30, -30,30,20, 30,30,20, 30,30,30, -30,30,30, 0,30,25, -30,-30,30, -30,30,30, -20,30,30, -20,-30,30, -30,-30,30, -25,0,30, 20,-30,30, 20,30,30, 30,30,30, 30,-30,30, 20,-30,30, 25,0,30, -30,30,30, 30,30,30, 30,20,30, -30,20,30, -30,30,30, 0,25,30, -30,20,-30, -30,30,-30, -30,30,30, -30,20,30, -30,20,-30, -30,25,0, -30,-30,20, -30,30,20, -30,30,30, -30,-30,30, -30,-30,20, -30,0,25}; /*_______________________________________________________________ M A I N R O U T I N E */ main(){ graphics_setup(); /* establish graphics mode */ CLR1=C7;CLR2=C9;CLR3=C1;EDGE=C1; /* color scheme for rendering */ setvisualpage(0);setactivepage(0);cleardevice(); r1=.58539;r2=6.28319;r3=5.79778;labels();draw_object(); setvisualpage(1);setactivepage(1);cleardevice(); r1=r1+.08727;r2=6.28319;r3=r3+.04363;labels();draw_object(); setvisualpage(2);setactivepage(2);cleardevice(); r1=r1+.08727;r2=6.28319;r3=r3+.04363;labels();draw_object(); setvisualpage(3);setactivepage(3);cleardevice(); r1=r1+.08727;r2=6.28319;r3=r3+.04363;labels();draw_object(); setvisualpage(0);setactivepage(0); /* reset to frame 0 */ for (t1=1;t1<=30000;t1++); /* pause */ animVGAEGA(); /* animation for VGA and EGA */ quit_pgm();} /* end the program gracefully */ /*_______________________________________________________________ SUBROUTINE: display the alphanumeric labels */ void labels(void){ setcolor(C7);moveto(0,192); outtext("640x200 16-color VGA and EGA mode"); moveto(168,0); outtext("USING C FOR HIGH SPEED FRAME ANIMATION"); moveto(464,192);outtext("Press any key to stop."); setcolor(C12);moveto(176,24); outtext("Animated rotation of solid 3D object"); setcolor(C7);moveto(0,40);outtext("Animation rate:"); moveto(0,48);outtext("36 frames per second."); return;} /*_______________________________________________________________ SUBROUTINE: draw the graphics */ void draw_object(void){ rotation(); /* recalculate sine and cosine rotation factors */ p1=0; /* reset array index pointer */ CLR=CLR3;EDGE=CLR3;draw_poly(); /* step one */ CLR=CLR1;EDGE=CLR1;draw_poly(); draw_poly(); /* step two */ CLR=CLR3;EDGE=CLR3;draw_poly(); CLR=CLR2;EDGE=CLR2;for (t3=1;t3<=4;t3++){draw_poly();} CLR=CLR3;EDGE=CLR3;draw_poly(); /* step three */ CLR=CLR2;EDGE=CLR2;draw_poly(); /* step four */ CLR=CLR3;EDGE=CLR3;draw_poly(); CLR=CLR1;EDGE=CLR1;for (t3=1;t3<=3;t3++){draw_poly();} CLR=CLR3;EDGE=CLR3;for (t3=1;t3<=2;t3++) /* step five */ {draw_poly();} CLR=CLR1;EDGE=CLR1;for (t3=1;t3<=3;t3++) /* step six */ {draw_poly();} CLR=CLR2;EDGE=CLR2;for (t3=1;t3<=3;t3++){draw_poly();} CLR=CLR3;EDGE=CLR3;for (t3=1;t3<=2;t3++){draw_poly();} setcolor(C7);sx=5;sy=400;coords();notice(sx,sy);return;} /*_______________________________________________________________ SUBROUTINE: draw and fill polygon in 3D space */ void draw_poly(void){ setcolor(C13); /* set the key matte drawing color */ setfillstyle(SOLID_FILL,C13); /* set the key matte fill color */ get_coords(); /* retrieve xyz vertex coords from database */ calc_3d(); /* 3D rotation, translation, projection */ window(); /* map display coords to fit 4:3 screen */ sxa=sx;sya=sy; /* line start point */ for (t1=1;t1<=4;t1++){ /* draw 4 lines in 3D */ get_coords(); /* retrieve xyz vertex coords from database */ calc_3d(); /* 3D rotation, translation, projection */ window(); /* map display coords to fit 4:3 screen */ sxs=sx;sys=sy;sxb=sx;syb=sy; /* line is sxa,sya to sxb,syb */ line_clip(); /* clip line to screen edges */ moveto(sxa,sya);lineto(sxb,syb); /* draw the line in 3D */ sxa=sxs;sya=sys; /* define next start point */ } /* repeat until done */ get_coords(); /* retrieve xyz area fill coords from database */ calc_3d();window();floodfill(sx,sy,C13); /* area fill */ setcolor(CLR); /* set the drawing color */ setfillstyle(SOLID_FILL,CLR); /* set the fill color */ EDGE=CLR; p1=p1-6; /* reset index pointer */ get_coords();calc_3d();window();sxa=sx;sya=sy; for (t1=1;t1<=4;t1++){ get_coords();calc_3d();window();sxs=sx;sys=sy;sxb=sx;syb=sy; line_clip();moveto(sxa,sya);lineto(sxb,syb); sxa=sxs;sya=sys;} get_coords();calc_3d();window();floodfill(sx,sy,EDGE); return;} /* return to caller */ /*_______________________________________________________________ SUBROUTINE: frame animation manager for VGA and EGA */ void animVGAEGA(void){ for (t1=1;t1!=2; ){ /* animate for endless loop */ setvisualpage(1);for (t2=1;t2<=1500;t2++); setvisualpage(2);for (t2=1;t2<=1500;t2++); setvisualpage(3);for (t2=1;t2<=30000;t2++);keyboard(); setvisualpage(2);for (t2=1;t2<=1500;t2++); setvisualpage(1);for (t2=1;t2<=1500;t2++); setvisualpage(0);for (t2=1;t2<=30000;t2++);keyboard(); setvisualpage(1);for (t2=1;t2<=2500;t2++); setvisualpage(2);for (t2=1;t2<=2500;t2++); setvisualpage(3);for (t2=1;t2<=30000;t2++);keyboard(); setvisualpage(2);for (t2=1;t2<=2500;t2++); setvisualpage(1);for (t2=1;t2<=2500;t2++); setvisualpage(0);for (t2=1;t2<=30000;t2++);keyboard();}; return;} /*_______________________________________________________________ SUBROUTINE: RETRIEVE xyz WORLD COORDINATES FROM DATABASE This subroutine retrieves a set of xyz cartresian world coordinates from the database. The index pointer is automatically incremented. */ void get_coords(void){ x=array_xyz[p1][0];y=array_xyz[p1][1];z=array_xyz[p1][2]; p1++;return;} /*_______________________________________________________________ SUBROUTINE: CALCULATE SIN, COS FACTORS Enter with r1,r2,r3 viewing angles for yaw, roll, pitch expressed in radians 0.0 through 6.28319. Returns sine and cosine factors. */ void rotation(void){ sr1=sin(r1);sr2=sin(r2);sr3=sin(r3);cr1=cos(r1);cr2=cos(r2); cr3=cos(r3);return;} /*_______________________________________________________________ SUBROUTINE: STANDARD 3D FORMULAS Enter with x,y,z cartesian world coordinates. Returns sx,sy cartesian display coordinates. Returns x,y,z cartesian view coordinates. */ void calc_3d(void){ x=(-1)*x;xa=cr1*x-sr1*z;za=sr1*x+cr1*z;x=cr2*xa+sr2*y; ya=cr2*y-sr2*xa;z=cr3*za-sr3*ya;y=sr3*za+cr3*ya;x=x+mx;y=y+my; z=z+mz;sx=d*x/z;sy=d*y/z;return;} /*_______________________________________________________________ SUBROUTINE: MAP CARTESIAN COORDS TO PHYSICAL SCREEN COORDS Enter with sx,sy cartesian display coordinates derived from world coordinate space -399,-299 to 400,300. Returns sx,sy unclipped physical display coordinates. */ void window(void){ sx=sx+399;sy=sy+299;rx=screen_x/799;ry=screen_y/599;sx=sx*rx; sy=sy*ry;return;} /*_______________________________________________________________ SUBROUTINE: 2D LINE-CLIPPING Enter with sxa,sya and sxb,syb endpoints of line to be clipped. Returns display coordinates for line clipped to fit physical screen viewport defined by minx,miny and maxx,maxy. */ void line_clip(void){ if (sxa>sxb) {temp_swap=sxa;sxa=sxb;sxb=temp_swap; temp_swap=sya;sya=syb;syb=temp_swap;}; if (sxamaxx) if (sxb>maxx) return; if (syamaxy) if (syb>maxy) return; if (sxamaxy) if (syb>maxy) return; }; if (sxb>maxx) {{c=(syb-sya)/(sxb-sxa)*(maxx-sxa); /* push left */ sxb=maxx;syb=sya+c;}; if (syamaxy) if (syb>maxy) return; }; if (sya>syb) {temp_swap=sya;sya=syb;syb=temp_swap; temp_swap=sxa;sxa=sxb;sxb=temp_swap;}; if (syamaxy) {c=(sxb-sxa)/(syb-sya)*(maxy-sya); /* push up */ sxb=sxa+c;syb=maxy;}; return;} /*_______________________________________________________________ SUBROUTINE: press any key to quit */ void keyboard(void){ if (bioskey(1)==0) return; else quit_pgm();} /*_______________________________________________________________ SUBROUTINE: GRACEFUL EXIT FROM THE PROGRAM */ void quit_pgm(void){ if (mode_flag==3) {setvisualpage(0);setactivepage(0);}; cleardevice();restorecrtmode();exit(0);} /*______________________________________________________________ SUBROUTINE: VGA/EGA/CGA/MCGA compatibility module */ void graphics_setup(void){ int graphics_adapter,graphics_mode; detectgraph(&graphics_adapter,&graphics_mode); if (graphics_adapter==VGA) goto VGA_EGA_mode; /* if VGA */ if (graphics_mode==EGAHI) goto VGA_EGA_mode; /* if EGA and ECD */ if (graphics_mode==EGALO) goto VGA_EGA_mode; /* if EGA and SCD */ if (graphics_adapter==CGA) goto abort_message; /* if CGA */ if (graphics_adapter==MCGA) goto abort_message; /* if MCGA */ goto abort_message; /* if no VGA, EGA, CGA, or MCGA */ VGA_EGA_mode: /* establish 640x200 16-color mode */ graphics_adapter=EGA;graphics_mode=EGALO; initgraph(&graphics_adapter,&graphics_mode,""); x_res=640;y_res=200;mode_flag=3; maxx=638;minx=1;maxy=198;miny=1; /* clipping viewport */ screen_x=639;screen_y=199; /* dimensions of screen */ x_res=640;y_res=200; /* resolution of screen */ return; abort_message: printf("\n\nUnable to proceed.\n"); printf("Requires VGA or EGA adapter\n"); printf(" with appropriate monitor.\n"); printf("Please refer to the book.\n\n"); exit(0); } /*_______________________________________________________________ SUBROUTINE: coords() This subroutine accepts sx,sy device-independent display coordinates and returns sx,sy device-dependent screen coordinates scaled to fit the 640x480, 640x350, 640x200, or 320x200 screen, depending upon the graphics mode being used. */ void coords(void){ sx=sx*(x_res/640);sy=sy*(y_res/480);return;} /*_______________________________________________________________ SUBROUTINE: Copyright Notice This subroutine displays the standard copyright notice. If you are typing in this program from the book you can safely omit this subroutine, provided that you also remove the instruction "notice()" from the main routine. */ int copyright[][3]={0x7c00,0x0000,0x0000,0x8231, 0x819c,0x645e,0xba4a,0x4252,0x96d0,0xa231,0x8252,0x955e,0xba4a, 0x43d2,0xf442,0x8231,0x825c,0x945e,0x7c00,0x0000,0x0000}; void notice(float x, float y){ int a,b,c; int t1=0; for (t1=0;t1<=6;t1++){a=copyright[t1][0];b=copyright[t1][1]; c=copyright[t1][2]; setlinestyle(USERBIT_LINE,a,NORM_WIDTH); moveto(x,y);lineto(x+15,y); setlinestyle(USERBIT_LINE,b,NORM_WIDTH); moveto(x+16,y);lineto(x+31,y); setlinestyle(USERBIT_LINE,c,NORM_WIDTH); moveto(x+32,y);lineto(x+47,y);y=y+1;}; setlinestyle(USERBIT_LINE,0xFFFF,NORM_WIDTH); return;} /*_______________________________________________________________ End of source code */