/*_______________________________________________________________ tc-006.c Function: This program demonstrates how to create accurate 3D images on the display screen. Compatibility: Supports all graphics adapters and monitors. The software uses the 640x480 16-color mode if a VGA is present, the 640x350 16-color mode if an EGA and enhanced monitor are present, the 640x200 16-color mode if an EGA and standard monitor are present, and the 320x200 4-color mode if a CGA or MCGA is present. Remarks: In addition to the standard 3D perspective formulas, versatile viewport and line-clipping routines are provided. Copyright 1988 Lee Adams and TAB BOOKS Inc. _________________________________________________________________ I N C L U D E F I L E S */ #include /* supports the BIOS call */ #include /* supports the printf function */ #include /* supports the graphics functions */ #include /* supports sine and cosine functions */ /*_______________________________________________________________ D E C L A R A T I O N S */ /* declare global variables */ 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=5.68319; /* 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=0.0,mz=-350.0; /* viewpoint position */ int maxx=638,minx=1,maxy=198,miny=1; /* clipping viewport */ float screen_x=639,screen_y=199; /* dimensions of screen mode */ float c=0.0; /* used in line-clipping routine */ float rx=0.0,ry=0.0; /* scaling values used in mapping routine */ int t1=0,t2=0; /* loop counters */ int p1=0; /* array indexer */ /* database of xyz cartesian world coordinates for 3D cube */ int array1[][3]={ 30,-30,30, 30,-30,-30, -30,-30,-30, -30,-30,30, 30,-30,30, 30,30,-30, -30,30,-30, -30,-30,-30, 30,-30,-30, 30,30,-30, -30,30,-30, -30,30,30, -30,-30,30, -30,-30,-30, -30,30,-30, -30,30,30, 30,30,30, 30,-30,30, -30,-30,30, -30,30,30, 30,30,30, 30,30,-30, 30,-30,-30, 30,-30,30, 30,30,30, -30,30,-30, 30,30,-30, 30,30,30, -30,30,30, -30,30,-30}; int C0=0,C1=1,C2=2,C3=3,C4=4,C5=5,C6=7,C7=7,C8=8,C9=9,C10=10, C11=11,C12=12,C13=13,C14=14,C15=15,mode_flag=0; float sx1,sy1,sx2,sy2; float x_res,y_res; /* declare global subroutines */ void keyboard(void);void quit_pgm(void);void calc_3d(void); void rotation(void);void window(void);void viewport(void); void graphics_setup(void);void coords(void); void notice(float x,float y); /*_______________________________________________________________ M A I N R O U T I N E */ main(){ graphics_setup(); /* establish graphics mode */ setcolor(C7);sx=0;sy=24;coords();sx1=sx;sy1=sy; sx=638;sy=455;coords();sx2=sx;sy2=sy; rectangle(sx1,sy1,sx2,sy2); rotation(); /* calculate yaw, roll, pitch rotation factors */ for (t2=1;t2<=6;t2++) /* draw 6 sides of the cube */ {if (t2<4) setlinestyle(USERBIT_LINE,0x8888,NORM_WIDTH); else setlinestyle(USERBIT_LINE,0xffff,NORM_WIDTH); x=array1[p1][0];y=array1[p1][1];z=array1[p1][2]; calc_3d();window();sxa=sx;sya=sy; for (t1=1;t1<=4;t1++) {p1++;x=array1[p1][0];y=array1[p1][1];z=array1[p1][2]; calc_3d();window();sxs=sx;sys=sy;sxb=sx;syb=sy;viewport(); moveto(sxa,sya);lineto(sxb,syb);sxa=sxs;sya=sys;}; p1++;}; notice(0,0); keyboard(); /* wait for user to press */ quit_pgm();} /* end the program gracefully */ /*_______________________________________________________________ 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. 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 viewport(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: CHECK THE KEYBOARD BUFFER */ void keyboard(void){ union u_type {int a;char b[3];} keystroke; int get_keystroke(void); /* declare a local subroutine */ do keystroke.a=get_keystroke(); while (keystroke.b[0]!=27); /* return if is pressed */ } /* LOCAL SUBROUTINE: RETRIEVE ONE KEYSTROKE */ int get_keystroke(void){ union REGS regs;regs.h.ah=0;return int86(0x16,®s,®s);} /*_______________________________________________________________ SUBROUTINE: GRACEFUL EXIT FROM THE PROGRAM */ void quit_pgm(void){ cleardevice();restorecrtmode();exit(0);} /*______________________________________________________________ SUBROUTINE: VGA/EGA/CGA/MCGA compatibility module This subroutine invokes the highest-resolution graphics mode which is permitted by the hardware. The 640x480 16-color mode is established if a VGA is present. The 640x350 16-color mode is established if an EGA is being used with an enhanced color display monitor or a multiscanning monitor. The 640x200 16-color mode is established if an EGA is being used with a standard color monitor. The 320x200 4-color mode is invoked if a CGA or MCGA is present. */ void graphics_setup(void){ int graphics_adapter,graphics_mode; detectgraph(&graphics_adapter,&graphics_mode); if (graphics_adapter==VGA) goto VGA_mode; /* if VGA */ if (graphics_mode==EGAHI) goto EGA_ECD_mode; /* if EGA and ECD */ if (graphics_mode==EGALO) goto EGA_SCD_mode; /* if EGA and SCD */ if (graphics_adapter==CGA) goto CGA_mode; /* if CGA */ if (graphics_adapter==MCGA) goto MCGA_mode; /* if MCGA */ goto abort_message; /* if no VGA, EGA, CGA, or MCGA */ VGA_mode: /* establish 640x480 16-color mode */ graphics_adapter=VGA;graphics_mode=VGAHI; initgraph(&graphics_adapter,&graphics_mode,""); x_res=640;y_res=480;mode_flag=1; maxx=638;minx=1;maxy=478;miny=1;screen_x=639;screen_y=479; setcolor(C7);outtextxy(0,472,"640x480 16-color VGA mode."); outtextxy(200,0,"USING C TO GENERATE 3D IMAGES"); return; EGA_ECD_mode: /* establish 640x350 16-color mode */ graphics_adapter=EGA;graphics_mode=EGAHI; initgraph(&graphics_adapter,&graphics_mode,""); x_res=640;y_res=350;mode_flag=2; maxx=638;minx=1;maxy=348;miny=1;screen_x=639;screen_y=349; setcolor(C7);outtextxy(0,342,"640x350 16-color EGA mode."); outtextxy(200,0,"USING C TO GENERATE 3D IMAGES"); return; EGA_SCD_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;screen_x=639;screen_y=199; setcolor(C7);outtextxy(0,192,"640x200 16-color EGA mode."); outtextxy(200,0,"USING C TO GENERATE 3D IMAGES"); return; CGA_mode: /* establish 320x200 4-color mode */ graphics_adapter=CGA;graphics_mode=CGAC3; initgraph(&graphics_adapter,&graphics_mode,""); x_res=320;y_res=200;C7=3;mode_flag=4; maxx=318;minx=1;maxy=198;miny=1;screen_x=319;screen_y=199; setcolor(C7);outtextxy(0,192,"320x200 4-color CGA mode."); outtextxy(128,0,"3D IMAGES"); return; MCGA_mode: /* establish 320x200 4-color mode */ graphics_adapter=MCGA;graphics_mode=MCGAC3; initgraph(&graphics_adapter,&graphics_mode,""); x_res=320;y_res=200;C7=3;mode_flag=4; maxx=318;minx=1;maxy=198;miny=1;screen_x=319;screen_y=199; setcolor(C7);outtextxy(0,192,"320x200 4-color MCGA mode."); outtextxy(128,0,"3D IMAGES"); return; abort_message: printf("\n\nUnable to proceed.\n"); printf("Requires VGA, EGA, MCGA, or CGA 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 */