C++ và Lập trình hướng đối tượng - Chương 8: Đồ họa
Để hiểu kỹ thuật lập trình đồ họa, đầu tiên phải hiểu các yếu tố cơ bản của đồ họa. Từ trước đến nay chúng ta chủ yếu làm việc với kiểu văn bản. Nghĩa là màn hình được thiết lập để hiển thị 25 dòng, mỗi dòng có thể chứa 80 ký tự. Trong kiểu văn bản, các ký tự hiển thị trên màn hình đã được phần cứng của máy PC ấn định trước và ta không thể nào thay đổi được kích thước, kiểu chữ.
Ở màn hình đồ họa, ta có thể xử lý đến từng chấm điểm (pixel) trên màn hình và do vậy muốn vẽ bất kỳ thứ gì cũng được. Sự bài trí và số pixel trên màn hình được gọi là độ phân giải (resolution). Do mỗi kiểu màn hình đồ họa có một cách xử lý đồ họa riêng nên TURBO C cung cấp một tệp tin điều khiển riêng cho từng kiểu đồ họa. Bảng 8-1 cho thấy các kiểu đồ họa và các tệp tin điều khiển chúng.
nh ảnh chuyển động. Ví dụ 1: Chương trình dưới đây minh hoạ cách dùng imagesize, malloc, getimage và putimage. #include #include main() { int mh=0,mode=0; char *p; unsigend size; initgraph (&mh,&mode,""); bar(0,0,getmaxx(),getmaxy()); size = imagesize(10,20,30,40); p=(char*)malloc(size); // p trỏ tới vùng nhớ size byte // mới được cấp phát getimage (10,20,30,40,p); getch(); cleardevice(); putimage (100,100,p,COPY_PUT); getch(); closegraph(); } 5. Tảo ảnh di động Nguyên tắc tạo ảnh di động giống như phim hoạt hình: - Vẽ một hình (trong chuỗi hình mô tả chuyển động) - Delay - Xoá hình đó - Vẽ hình kế theo - Delay . . . A) Vẽ hình Cách 1: Vẽ lại một ảnh nhưng tại các vị trí khác nhau. Cách 2: Lưu ảnh vào một vùng nhớ rối đưa ảnh ra màn hình tại các vị trí khác nhau. B) Xóa ảnh Cách 1: Dùng hàm cleardevice Cách 2: Dùng hàm putimage (mode XOR_PUT) để xếp chồng lên ảnh cần xoá. Cách 3: Lưu trạng thái màn hình vào một chỗ nào đó. Vẽ một hình ảnh. Đưa trạng thái cũ màn hình ra xếp đè lên ảnh vừa vẽ. Kỹ thuật tạo ảnh di động được minh hoạ trong các chương trình của Đ11. Đ 11. Một số chương trình đồ hoạ Chương trình 1: Đầu tiên vẽ bầu trời đầu sao. Sau đó từng chùm pháo hoa được bắn lên bầu trời. Khi bấm phím Enter thì việc bắn pháo hoa kết thúc, ta nhận lại bầu trời đầy sao. Bấm tiếp Enter thì kết thúc chương trình. // Bắn pháo hoa trên bầu trời đầy sao #include #include #include #include main() { int x[101],y[101]; int mh=0,mode=0,i,n; char *p[101]; 478 479 initgraph(&mh,&mode,""); if (graphresult()!=0) exit(1); setcolor(RED); // Vẽ bầu trời đầy sao for (i=1;i<=1000;++i) { putpixel(random(getmaxx()), random(getmaxy()),random(getmaxcolor())); } // Lưu hiện trạng 100 hình chữ nhật trên màn hình để khôi phục for (i=1;i<=100;++i) { x[i]=random(getmaxx())-10; y[i]=random(getmaxy())-10; if (x[i]<0) x[i]=0; if (y[i]<0) y[i]=0; n=imagesize(x[i],y[i],x[i]+10,y[i]+10); p[i]=(char*)malloc(n); getimage(x[i],y[i],x[i]+10,y[i]+10,p[i]); } // Chu trình bắn pháo hoa do { // Đưa 100 quả pháo lên màn hình tại các vị trí quy định for (i=1;i<=100;++i) { setfillstyle(SOLID_FILL,i%15+1); pieslice(x[i]+5,y[i]+5,0,360,5); } delay(500); //Xoá chùm pháo hoa vừa bắn bằng cách khôi phục màn hình for (i=100;i>=1;--i) putimage(x[i],y[i],p[i],COPY_PUT); delay(500); } while(!kbhit()); getch(); getch(); closegraph(); } Chương trình 2: Vẽ đồng hồ có 3 kim giờ, phút và giây. Đồng hồ chạy đúng theo giờ hệ thống. Muốn kết thúc chương trình bấm Enter. // Đồng hồ #include #include #include #include // Hàm kẻ đoạn thẳng từ tâm đồng hồ theo độ, chiều dài, // độ dầy và mầu void ke(int ddo, unsigned dai, unsigned day,unsigned mau); // Kẻ kim giây khi biết số giây void ke_giay(unsigned giay); // Kẻ kim phút khi biết số phút void ke_phut(unsigned phut); // Kẻ kim giờ khi biết số giờ void ke_gio(unsigned gio, unsigned phut); void chay_kim_giay(void); void chay_kim_phut(void); void chay_kim_gio(void); int x0,y0,rgio,rphut,rgiay,mgio,mphut,mgiay; 480 481 unsigned phutgioht,gioht,phutht,giayht; void ke(int ddo, unsigned dai, unsigned day,unsigned mau) { unsigned x,y; float goc; while (ddo>=360) ddo=ddo-360; goc=(M_PI/180)*ddo; x=x0+ (int)(dai*cos(goc)+0.5); y=y0- (int)(dai*sin(goc)+0.5); setcolor(mau); setlinestyle(0,0,day); line(x0,y0,x,y); } // Hàm ke kim giay void ke_giay(unsigned giay) { int ddo; ddo = (90 - 6*giay); ke(ddo,rgiay,1,mgiay); } // Hàm ke kim phut void ke_phut(unsigned phut) { int ddo; ddo= (90-6*phut); ke(ddo,rphut,3,mphut); } // Hàm ke kim gio void ke_gio(unsigned gio, unsigned phut) { int ddo; ddo = 360 + 90 - 30*(gio%12) - (phut+1)/2; ke(ddo,rgio,3,mgio); } // Hàm chỉnh giây hiện tại và làm chuyển động kim giây void chay_kim_giay(void) { unsigned giay; struct time t; gettime(&t); giay=t.ti_sec; if (giay!=giayht) { ke_giay(giayht); giayht=giay; ke_giay(giayht); } } // Hàm chỉnh phút hiện tại và làm chuyển động kim phút void chay_kim_phut(void) { unsigned phut; struct time t; gettime(&t); phut=t.ti_min; if (phut!=phutht) { ke_phut(phutht); phutht=phut; ke_phut(phutht); } 482 483 } // Hàm chỉnh giờ phút hiện tại và làm chuyển động kim giờ void chay_kim_gio(void) { unsigned h,gio,phut,sophut,sophutht; struct time t; gettime(&t); gio=t.ti_hour; phut=t.ti_min; sophut = gio*60+phut; sophutht = gioht*60+phutgioht; if ( sophut<sophutht) sophut=sophut+ 12*60; h=sophut-sophutht; if (h>=12) { ke_gio(gioht,phutgioht); phutgioht=phut; gioht=gio; ke_gio(gioht,phutgioht); } } main() { struct time t; char *dso[]={"", "12", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}; int i,mh=0,mode=0,r,x,y; float goc; initgraph(&mh,&mode,""); x0=(getmaxx()/2)-1; y0=(getmaxy()/2)-1; r=y0-2; rgiay = r-10; rphut=r-50; rgio=r-90; mgiay= BROWN; mphut=RED; // mgio:=magenta; mgio=YELLOW; // Vẽ chu vi đồng hồ setcolor(BLUE); setlinestyle(0,0,3); circle(x0,y0,r); setfillstyle(1,YELLOW); floodfill(0,0,BLUE); setfillstyle(1,WHITE); floodfill(x0,y0,BLUE); setlinestyle(0,0,1); circle(x0,y0,10); setfillstyle(1,GREEN); floodfill(x0,y0,BLUE); settextjustify(1,1); setcolor(MAGENTA); outtextxy(x0,y0+120,"IBM-JIMIKO"); // Ghi chữ số settextstyle(3,0,3); settextjustify(1,1); setcolor(BLUE); for (i=1;i<=12;++i) { goc=(2*M_PI+M_PI/2) - (i-1)*(M_PI/6); x = x0+ (int)(rphut*cos(goc)+0.5); y = y0- (int)(rphut*sin(goc)+0.5); outtextxy(x,y,dso[i]); } // Xác định thời điểm đầu gettime(&t); gioht=t.ti_hour; phutht=t.ti_min; giayht=t.ti_sec; phutgioht=phutht; setwritemode(XOR_PUT); // Ve kim gio,phut,giay 484 485 ke_gio(gioht,phutgioht); ke_phut(phutht); ke_giay(giayht); // Làm chuyển động các kim do { chay_kim_giay(); chay_kim_phut(); chay_kim_gio(); } while(!kbhit()); closegraph(); } Chương trình 3: Vẽ một con tầu vũ trụ bay trên bầu trời đầy sao theo quỹ đạo ellipse. Trong khi tầu chuyển động thì các ngôi sao thay nhau nhấp nháy // Tầu vũ trụ chuyển động trên bầu trời đầy sao nhấp nháy #include #include #include #include #include #include // Khai báo các hàm trong chương trình void tau_cd(void); // tầu chuyển động void nhap_nhay_bt(void); // nhấp nháy bầu trời void main(void); // hàm main // Khai báo các biến mảng ngoài int a,b,x,y,x0,y0,mh=0,mode=0,n,i; float goc,xt,yt; char *p; int xx[1001],yy[1001]; // Hàm main void main(void) { initgraph(&mh,&mode,""); if (graphresult()!=0) exit(1); // Vẽ tầu vũ trụ setcolor(RED); ellipse(100,50,0,360,20,8); ellipse (100,46,190,357,20,6); line(107,44,110,38); circle(110,38,2); line(93,44,90,38); circle(90,38,2); setfillstyle(SOLID_FILL,BLUE); floodfill(101,54,RED); setfillstyle(SOLID_FILL,MAGENTA); floodfill(94,45,RED); // Lưu ảnh của tầu vũ trụ vào bộ nhớ n=imagesize(79,36,121,59); p=(char*)malloc(n); getimage(79,36,121,59,p); // Vẽ bầu trời đầy sao và lưu vị trí của chúng // vào các mảng xx, yy để phục vụ hàm nhap_nhay_bt cleardevice(); for (i=1;i<=1000;++i) { xx[i]=random(getmaxx()); yy[i]=random(getmaxy()); putpixel(xx[i],yy[i],random(getmaxcolor())); 486 487 } // Xác định giá trị ban đầu cho các biến // dùng để điều khiển chuyển động tầu goc= 2*M_PI + M_PI/2; x0= (getmaxx() - 42)/2; y0= (getmaxy() - 25)/2; a=x0; b=y0; // chu trình tầu vũ trụ chuyển động và các ngôi sao nhấp nháy do { tau_cd(); nhap_nhay_bt(); } while(!kbhit()); getch(); closegraph(); } void tau_cd(void) { xt=a*cos(goc)+x0; yt=-b*sin(goc)+y0; x=(int)(xt+0.5); y=(int)(yt+0.5); // Đặt tầu vũ trụ lên màn hình putimage(x,y,p,XOR_PUT); delay(500); // Xóa putimage(x,y,p,XOR_PUT); // Thay đổi góc để làm cho tầu chuyển động goc -= M_PI/30; if (goc<M_PI/2) goc=2*M_PI+M_PI/2; } void nhap_nhay_bt(void) { static i=1; // Lệnh này thực hiện một lần khi dịch int j; // Cho nhấp nháy bằng cách đổi mầu 50 ngôi sao for (j=1;j<=50;++j) { putpixel(xx[i],yy[i],random(getmaxcolor())); ++i; if (i>1000) i=1; } } Đ 12. In ảnh từ màn hình đồ hoạ Hàm in_anh dưới đây sẽ in ảnh trong miền chữ nhật (xt, yt, xd, yd) của màn hình đồ hoạ ra giấy trên các máy in LQ1070, LQ1170 và FX1050. void in_anh(int dd,int xt,int yt,int xd,int yd); Tham số dd là độ đậm của nét in. Thực chất dd là số lần in lại. Bình thường chon dd=1. Nếu muốn in rõ hơn ta chọn dd bằng 2 hay 3. Trong hàm in_anh có dùng hàm tao_mau, nó được mô tả như sau: int tao_mau(int k,int x,int y); Hàm này sẽ dò trên k chấm điểm theo chiều dọc bắt đầu từ toạ độ (x,y) trên màn hình để biết xem chấm điểm nào đã tô mầu. Hàm sẽ trả về một giá trị nguyên tạo bởi các bit 1 (ứng với điểm đã tô mầu) và 0 (ứng với điểm chưa tô mầu). 488 489 Hàm in_anh sẽ dùng hàm tao_mau để duyệt trên miền chữ nhật (xt,yt,xd,yd). Mỗi lần duyệt sẽ nhận được một mẫu các chấm điểm (giá trị nguyên) và mẫu này được in ra giấy. Dưới đây là nội dung của 2 hàm nói trên. // in ảnh #include "stdio.h" #include "graphics.h" int tao_mau(int k,int x,int y); void in_anh(int dd,int xt,int yt,int xd,int yd); int tao_mau(int k,int x,int y) { int c=0,i; for (i=0;i<k;++i) if (getpixel(x,y+i)) c =c|(128>>i); return c; } void in_anh(int dd,int xt,int yt,int xd,int yd) { //dd - so lan in lai mot dong char c,ch1; int scot,m,mm,k,dong,cot,i,j,n1,n2; dong=(yd-yt+1)/6; mm=(yd-yt+1) % 6; cot=xd-xt+1; for (i=0;i<=dong;++i) { if (i<dong) m=6; else m=mm; if (m>0) { scot=0; for (j=0;j < cot;++j) if (tao_mau(m,xt+j,yt+i*6)) scot=j+1; if (scot) { n1=scot % 256; n2= scot/256; for (k=0;k<dd;++k) { fprintf(stdprn,"%c%c%c%c%c%c",13,27,'*', 0,n1,n2); //LQ for (j=0;j < scot;++j) { if (kbhit())//bat phim { if ((ch1=getch())==0) getch(); if (ch1==27) goto ket; } c=tao_mau(m,xt+j,yt+i*6); fprintf(stdprn,"%c",c); } } } fprintf(stdprn,"%c%c%c",27,'A',m); fprintf(stdprn,"\n"); } } ket: fprintf(stdprn,"%c%c",27,'@'); } 490
File đính kèm:
- C++ và Lập trình hướng đối tượng - Chương 8 Đồ họa.DOC