В данной задаче рисуется аквариум с анимированными пузырьками и перемещающимся лучом света, проходящим через аквариум. Алгоритм: for (i=50;i<w->allocation.height;i++) { cairo_move_to(cr,0,i); cairo_set_line_width(cr, 1); // установка ширины линий cairo_line_to(cr,w->allocation.width,i); // рисуем линию воды cairo_set_source_rgb(cr, 0, 0.8 - (((float)6/w->allocation.width)*i)/10, 1); //Вычисление цвета воды cairo_stroke(cr); } 2. Рисуем остальные части аквариума: песок, рамка, луч света. Луч света рисуется следующим образом: Из исходной точки рассеиваем линии белого прозрачного цвета. В центре лучи менее, а по бокам более прозрачные. for(j=0; j < 400; j++) { cairo_set_source_rgba(cr, 1, 1, 1,0.35 - (abs(200-j)/410.0)); // Задаём цвет cairo_move_to(cr,adj+j/3,50); cairo_line_to(cr,adj+150+j/2.0-(200-j)*sin(0.45*j*3.14/180),w->allocation.height-50-(200-j)*0.4*cos(0.45*j*3.14/180)); // вычисление точки падения луча cairo_stroke(cr); // проводим линии } 3. Сохраняем полученную картину в pixbuf. 4. Перемещаем пузырьки вверх по формуле: y -= 1 - d/100.0; x +=sin(((float)(5+rand()%2)/10)*y); // x, y - координаты пузырька, d - диаметр пузырька 5. Рисуем пузырьки. 6. Прорисовываем сохранённый pixbuf. 7. Возвращаемся в пункт 4. В случае перемещения источника света перерисовываем задний фон, сохраняем новый полученный фон в pixbuf. #include <stdlib.h> #include <math.h> #include <gtk/gtk.h> #define N 20 int timer=0; char timeractive=0; int adj=0; struct bubble //структура, описывающие пузырьки { float x, y, d; }bub[N]; GdkPixbuf * pb = NULL; void init_bubble(int id, float dem) //начальное состояние пузырька { bub[id].x = -50.0; bub[id].y = -50.0; bub[id].d = dem; } gint engine(gpointer data) //передвигаем пузырьки, проверка на выход за пределы окна { if(timeractive == 0) { return 0; } timer++; int i=0; { for(i=0; i < N; i++) { if(bub[i].y > 50) { bub[i].y -= 1 - bub[i].d/100.0; bub[i].x +=sin(((float)(5+rand()%2)/10)*bub[i].y); } if(bub[i].y < 50 && timer >= 30) { init_bubble(i,5 + rand()%5); bub[i].x = 250+200*(rand()%2); bub[i].y = 550; timer = 0; } } } gtk_widget_queue_draw((GtkWidget *) data); return 1; } gint draw(GtkWidget * w, GdkEventExpose *event, gpointer data) // функция рисования, перерисовки { int i=0,j=0; cairo_t *cr=gdk_cairo_create(w->window); if(timeractive == 0 || timeractive == 2) { cairo_set_source_rgb(cr, 1, 1, 1); cairo_set_line_width(cr, 0.1); cairo_rectangle(cr,0,0,w->allocation.width,50); cairo_fill(cr); for (i=50;i<w->allocation.height;i++) //Прорисовка воды { cairo_move_to(cr,0,i); cairo_set_line_width(cr, 1); cairo_line_to(cr,w->allocation.width,i); cairo_set_source_rgb(cr, 0, 0.8 - (((float)6/w->allocation.width)*i)/10, 1); cairo_stroke(cr); } //рисуем песок cairo_move_to (cr, 0, w->allocation.height-100); cairo_curve_to (cr, (w->allocation.width)/3, w->allocation.height-125, (w->allocation.width)/2, w->allocation.height-90, w->allocation.width, w->allocation.height-110); cairo_line_to(cr, w->allocation.width, w->allocation.height); cairo_line_to(cr, 0, w->allocation.height); cairo_line_to(cr, 0, w->allocation.height-100); cairo_set_line_width (cr, 0.1); cairo_set_source_rgb(cr, 244.0/255.0, 148.0/255.0, 30.0/255.0); cairo_fill (cr); cairo_set_line_width (cr, 1); //рисуем луч света for(j=0; j < 400; j++) { cairo_set_source_rgba(cr, 1, 1, 1,0.35 - (abs(200-j)/410.0)); cairo_move_to(cr,adj+j/3,50); cairo_line_to(cr,adj+150+j/2.0-(200-j)*sin(0.45*j*3.14/180),w->allocation.height-50-(200-j)*0.4*cos(0.45*j*3.14/180)); cairo_stroke(cr); } //Рисуем рамку аквариума cairo_set_source_rgb(cr, 0, 0, 0); cairo_set_line_width(cr, 9); cairo_rectangle(cr,0,0,w->allocation.width,w->allocation.height); cairo_stroke(cr); //Сохраняем-обновляем изображение if(pb == NULL) pb = gdk_pixbuf_get_from_drawable(NULL,w->window,NULL,0,0,0,0,w->allocation.width,w->allocation.height); else gdk_pixbuf_get_from_drawable(pb,w->window,NULL,0,0,0,0,w->allocation.width,w->allocation.height); if(timeractive == 0)//Создаём таймер при первом запуске { g_timeout_add(25,engine,w); } timeractive = 1; } else { GdkGC * gc = w->style->fg_gc[GTK_WIDGET_STATE (w)]; //Вывод сохранённого изображения gdk_draw_pixbuf(w->window,gc,pb,0,0,0,0,w->allocation.width,w->allocation.height,0,0,0); //Рисование пузырьков for(i = 0; i < N; i++) { if(bub[i].y > 50) { cairo_arc (cr, bub[i].x, bub[i].y, bub[i].d, 0, 360); cairo_set_source_rgb(cr, 1, 1, 1); cairo_set_line_width(cr, 0.5); cairo_stroke(cr); cairo_rectangle(cr,bub[i].x+bub[i].d/2,bub[i].y-bub[i].d/2,2,2); cairo_fill(cr); } } } return 1; } gint move(GtkAdjustment *get) { adj = gtk_adjustment_get_value(get); } gint ButtonPressed(GtkWidget * window, GdkEventButton *event, gpointer d)//Вызов перерисовки изображения при скролинге { timeractive = 2; return 0; } int main ( int argc, char ** argv) { srand(time(0)); gtk_init(&argc, &argv); GtkWidget *scrollbar, *adj1, *area; adj1 = gtk_adjustment_new(0,0,800,10,1.0,50); area = gtk_drawing_area_new();//создание области рисования GtkWidget * window = gtk_window_new (GTK_WINDOW_TOPLEVEL);//Создание окна gtk_widget_set_size_request (window, 800, 600);//Задание параметров окна gtk_window_set_title (window, "Bubbles v1.0 Deluxe edition :D"); gtk_window_set_resizable(window,0); GtkWidget *table = gtk_table_new (2, 2, FALSE);//Создание таблицы scrollbar = gtk_hscrollbar_new (adj1);//Создание скролинга //gtk_container_add (GTK_CONTAINER (window), scrollbar); gtk_container_add (GTK_CONTAINER (window), table);//Добавление таблицы в окно gtk_widget_show (table); gtk_table_attach (GTK_TABLE (table),area, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);//Вставляем в таблицу область рисования gtk_table_attach (GTK_TABLE (table), scrollbar, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);//Вставляем в таблицу полоску скролинга gtk_widget_show (scrollbar); int i=0; for(; i < N; i++)//Инициализация стартового состояния пузырьков { init_bubble(i,5 + rand()%5); } g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect (G_OBJECT (area), "expose_event", G_CALLBACK (draw), NULL); g_signal_connect (G_OBJECT (adj1), "value_changed",G_CALLBACK (move), NULL); g_signal_connect (G_OBJECT (scrollbar), "button_release_event", G_CALLBACK (ButtonPressed), NULL); gtk_widget_show_all(window); gtk_main(); return 0; }
Ключевые слова:
Аквариум, GTK, Cairo, пузырьки
|
|||||||