Задача : создать приложение, выводящее на экран анимированное изображение Приложение выводит на экран вид из окна на некоторый пейзаж. Горы нарисованы при помощи рисования многоугольников, брёвна причала рисуются при помощи двух окружностей и одного прямоугольника. #include <gtk/gtk.h> #include <stdlib.h> #include <math.h> // макрос для создания графического контекста gc с цветом r;g;b на основании окна w, // используя вспомагательную переменную-цвет clr #define CREATE_RGB_GC(w,gc,clr,r,g,b)\ gc=gdk_gc_new(w);\ (clr).red=(r)*257;\ (clr).green=(g)*257;\ (clr).blue=(b)*257;\ gdk_gc_set_rgb_fg_color((gc),&(clr)) // t - текущий момент времени (поддерживается в виде числа из отрезка [0,2*M_PI]) double t; // r[i] - базовая длина i-того луча солнца int r[10]; // rt[i] - параметр, который используется для того, чтобы посчитать длину i-того луча в текущий момент. // Тоже является числом из отрезка [0,2*M_PI] double rt[10]; // Координаты солца int sunx,suny; // Радиус солнца double srad; // Ширина и высота окна int width=640,height=480; // Палитра: для рисования солнца, окна, неба, гор, травы, моря и причала GdkGC *sungc,*windowgc,*skygc,*mountaingc,*grassgc,*seagc,*shipyardgc; // Буфер, в котором будет рисоваться картинка, перед тем как нарисовать в окне. GdkPixmap *pixm; // Функция, которая будет вызываться каждую десятую секунды, используется для того, чтобы // увеличить t и все rt[i] и перерисовать всю картинку gboolean inc_t(GtkWidget* w) { int i; t+=0.1; if(t>2*M_PI) t-=2*M_PI; for(i=0;i<10;i++) { rt[i]+=0.05; if(rt[i]>2*M_PI) rt[i]-=2*M_PI; } expose_event(w,NULL,NULL); return TRUE; } // Нарисовать горы в буфере, используя информацию о // чёрном и белом цвете из виджета w void draw_mountain(GtkWidget *w) { int i; GdkPoint m1[5],m2[4]; // задаём вершины многоугольника, которые обозначают коричневую часть горы m1[0].x=0+70; m1[0].y=height-20-180; m1[1].x=90+70; m1[1].y=height-180-20-180; m1[2].x=120+70; m1[2].y=height-120-20-180; m1[3].x=150+70; m1[3].y=height-180-20-180; m1[4].x=240+70; m1[4].y=height-20-180; // задаём вершины многоугольника, которые обозначают белую часть горы m2[0].x=120+70; m2[0].y=height-120-20-180; m2[1].x=150+70; m2[1].y=height-180-20-180; m2[2].x=120+70; m2[2].y=height-240-20-180; m2[3].x=90+70; m2[3].y=height-180-20-180; // рисуем залитые многоугольника, обозначающие горы gdk_draw_polygon(pixm,mountaingc,TRUE,m1,5); gdk_draw_polygon(pixm,w->style->white_gc,TRUE,m2,4); // обводим их линиями gdk_draw_lines(pixm,w->style->black_gc,m1,5); gdk_draw_lines(pixm,w->style->black_gc,m2,4); // смещаем гору на 70 единиц влево и на 20 единиц вниз и перерисовываем их for(i=0;i<5;i++) { m1[i].x-=70; m1[i].y+=20; } for(i=0;i<4;i++) { m2[i].x-=70; m2[i].y+=20; } gdk_draw_polygon(pixm,mountaingc,TRUE,m1,5); gdk_draw_polygon(pixm,w->style->white_gc,TRUE,m2,4); gdk_draw_lines(pixm,w->style->black_gc,m1,5); gdk_draw_lines(pixm,w->style->black_gc,m2,4); } // море рисуется как множество точек, ограниченное функцией, заданной параметрическими уравнениями: int sea_func_x(double t) { return width+10*t*t-300; } int sea_func_y(double t) { return height-200+40*t; } // рисуем море void draw_sea(GtkWidget *w) { double c; int i; // заводим большой массив под море и заполняем его координатами моря GdkPoint m1[100]; m1[0].x=width; m1[0].y=height-200; for(i=1,c=0;;i++,c+=0.5) { if(i!=1&&m1[i-1].x>=width) break; // если это первый элемент массива или предыдущий // был виден, то добавляем ещё одну точку m1[i].x=sea_func_x(c); m1[i].y=sea_func_y(c); } // отрисовываем море и обводим его линией gdk_draw_polygon(pixm,seagc,TRUE,m1,i); gdk_draw_lines(pixm,w->style->black_gc,m1,i); } // рисуем причал void draw_shipyard(GtkWidget *w) { int i; // рисуем 14 брёвен for(i=0;i<14;i++) { //задаём координаты правого верхнего угла int x=width-320+20*i,y=height-145; // рисуем дальнюю окружность и обводим её линиями gdk_draw_arc(pixm,shipyardgc,TRUE,x,y,20,20,0,64*360); gdk_draw_arc(pixm,w->style->black_gc,FALSE,x,y,20,20,0,64*360); // рисуем прямоугольник от середины дальней окружности к середине ближней и обводим побокам линией gdk_draw_rectangle(pixm,shipyardgc,TRUE,x,y+10,20,50); gdk_draw_line(pixm,w->style->black_gc,x,y+10,x,y+60); gdk_draw_line(pixm,w->style->black_gc,x+20,y+10,x+20,y+60); // рисуем ближнюю окружность и обводим окружностью gdk_draw_arc(pixm,shipyardgc,TRUE,x,y+50,20,20,0,64*360); gdk_draw_arc(pixm,w->style->black_gc,FALSE,x,y+50,20,20,0,64*360); } } // рисуем корабль void draw_ship(GtkWidget *w) { // координаты точки, относительной которой будет проивзодится рисование корабля. // чтобы корабль плавал её y координата меняется в интервале [height-155; height-145] int x=width-200,y=height-150+5*sin(t); GdkPoint m1[4],m2[5]; // задаём координаты "кормы" корабля m1[0].x=x; m1[0].y=y; m1[1].x=x+20; m1[1].y=y+20; m1[2].x=x+100; m1[2].y=y+20; m1[3].x=x+110; m1[3].y=y; // рисуем корму корабля gdk_draw_polygon(pixm,shipyardgc,TRUE,m1,4); gdk_draw_polygon(pixm,w->style->black_gc,FALSE,m1,4); // рисуем мачту корабля gdk_draw_rectangle(pixm,shipyardgc,TRUE,x+65,y-40,4,40); gdk_draw_rectangle(pixm,w->style->black_gc,FALSE,x+65,y-40,4,40); // задаём координаты "флага" корабля m2[0].x=x+65; m2[0].y=y-40; m2[1].x=x+45; m2[1].y=y-40; m2[2].x=x+40; m2[2].y=y-30; m2[3].x=x+45; m2[3].y=y-20; m2[4].x=x+65; m2[4].y=y-20; // рисуем флаг корабля gdk_draw_polygon(pixm,w->style->white_gc,TRUE,m2,5); gdk_draw_polygon(pixm,w->style->black_gc,FALSE,m2,5); } // рисуем солнце и его лучи void draw_sun(GtkWidget *w) { int i; // рисуем солнце gdk_draw_arc(pixm,sungc,TRUE,sunx-srad,suny-srad,2*srad,2*srad,0,64*360); for(i=0;i<10;i++) { // рисуем лучи солнца. // т.к. окружность можно задать в форме: // x=r*cos(t) // y=r*sin(t) // то мы можем рисовать луч от точки ((srad+5)*cos(t);(srad+5)*sin(t)) до точки // ((srad+5+rad[i] ))*cos(t);(srad+5+rad[i])*sin(t)), где rad[i]=r[i]*|cos(rt[i])|- радиус луча gdk_draw_line(pixm,sungc,(int)((srad+5)*cos(t+i*M_PI/5))+sunx,(int)((srad+5)*sin(t+i*M_PI/5))+suny,(int)(((srad+5)+r[i]*fabs(cos(rt[i])))*cos(t+i*M_PI/5))+sunx,(int)(((srad+5)+r[i]*fabs(cos(rt[i])))*sin(t+i*M_PI/5))+suny); } } // отрисовка картинки в буфере и перемещение его на окно gboolean expose_event(GtkWidget* w,GdkEvent*e,gpointer d) { int i; // рисуем небо gdk_draw_rectangle(pixm,skygc,TRUE,15,20,width-30,height-40); // рисуем траву gdk_draw_rectangle(pixm,grassgc,TRUE,0,height-200,width,200); // рисуем солнца, горы, море, корабль и пристань draw_sun(w); draw_mountain(w); draw_sea(w); draw_ship(w); draw_shipyard(w); // рисуем окно и обводим его gdk_draw_rectangle(pixm,windowgc,TRUE,0,0,15,height); gdk_draw_rectangle(pixm,windowgc,TRUE,width-15,0,15,height); gdk_draw_rectangle(pixm,windowgc,TRUE,15,0,width-30,20); gdk_draw_rectangle(pixm,windowgc,TRUE,15,height-20,width-30,20); gdk_draw_rectangle(pixm,w->style->black_gc,FALSE,0,0,width,height); gdk_draw_rectangle(pixm,windowgc,TRUE,width/2-15,20,30,height-40); gdk_draw_rectangle(pixm,w->style->black_gc,FALSE,15,20,width/2-30,height-40); gdk_draw_rectangle(pixm,w->style->black_gc,FALSE,width/2+15,20,width/2-30,height-40); // копируем прямоугольник из буфера с левым верхним углом в точке (0,0) в окно в прямоугольник // с левым верхним углом (0,0) шириной width и высотой height gdk_draw_drawable(w->window,w->style->fg_gc[0],pixm,0,0,0,0,width,height); return TRUE; } int main(int argc,char **argv) { GdkColor c; GtkWidget * window; int i; // инициализируем gtk, создаём окно, задаём его размеры и показываем его gtk_init(&argc,&argv); window=gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_size_request(window,width,height); gtk_widget_show(window); // создаём палитру CREATE_RGB_GC(window->window,sungc,c,255,255,0); CREATE_RGB_GC(window->window,windowgc,c,255,125,0); CREATE_RGB_GC(window->window,skygc,c,0,170,224); CREATE_RGB_GC(window->window,mountaingc,c,131,61,1); CREATE_RGB_GC(window->window,grassgc,c,150,255,0); CREATE_RGB_GC(window->window,seagc,c,0,51,181); CREATE_RGB_GC(window->window,shipyardgc,c,121,46,0); // задаём координаты и радиус солнца sunx=width-50; suny=50; srad=25; // задаём некоторые начальные параметры лучей for(i=0;i<10;i++) { rt[i]=((double)i)/23*M_PI; r[i]=10*(2+sin(((double)i))/5); } // создаём буфер, в котором мы будем рисовать. pixm=gdk_pixmap_new(window->window,width,height,-1); // привязываем событие при закрытии окна и событие перерисовки с соответствующими функциями g_signal_connect(G_OBJECT(window),"delete-event",G_CALLBACK(gtk_main_quit),NULL); g_signal_connect(G_OBJECT(window),"expose-event",G_CALLBACK(expose_event),NULL); // функция inc_t будет вызываться по таймеру каждые 100 милисекунд g_timeout_add(100,(GSourceFunc) inc_t,window); gtk_main(); return 0; }
Ключевые слова:
анимация
|
|||||||