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.

 

doc23 trang | Chuyên mục: C/C++ | Chia sẻ: dkS00TYs | Lượt xem: 2944 | Lượt tải: 1download
Tóm tắt nội dung C++ và Lập trình hướng đối tượng - Chương 8: Đồ họa, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
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:

  • docC++ và Lập trình hướng đối tượng - Chương 8 Đồ họa.DOC