Алгоритм размытого движения

tail.jpg

В данной программе показан алгоритм размытия в движении. Язык С, реализовано на GTK и Cairo.

Алгоритм:
1) закрашиваем сцену полупрозрачным черным цветом
2) передвигаем и прорисовываем шары. Движение задается по случайно придуманной формуле:)
z = d/5 * (cos(a+=s) * (1 - cos(a)); d - расстояние от центра, а - угол относительно центра, s - скорость
x =350 + (d * sin(a))/(1 - z/50); изменения угла
y =350 + (-d * cos(a))/(1 - z/50);
3) возвращаемся в пункт 1)

#include <stdlib.h>
#include <gtk/gtk.h>
 
typedef struct met met;
typedef struct vars vars;
 
struct met // структура описывающая шарики
{
    float x0;
    float y0;
    float z0;
    float radi;
    float speed;
    float dts;
    float angle;
    float r,g,b;
};
 
struct vars // структура для хранения данных программы
{
    met *meteors;
    int mCount;
    GtkWidget *w;
};
 
void init_met(met *m, float rad, float spx, float angl, float dist, float r, float g, float b) // инициализация шарика
{
    m->x0 = 0;
    m->y0 = 0;
    m->speed = spx;
    m->radi = rad;
    m->angle = angl;
    m->dts = dist;
    m->r = r;
    m->g = g;
    m->b = b;
}
 
void init_vars(vars *v,GtkWidget *wd, int count) // инициализация всех переменных программы
{
    v->w = wd;
    v->mCount = count;
    v->meteors = (met *) malloc(sizeof(met)*count);
    int i=0;
    for(;i<count; i++)
    {
        init_met(&v->meteors[i],19+rand()%20,
        (((float) 6+rand()%10)/10) * pow(-1,rand()%2),
        rand()%360,
        70 + (35+rand()%10) * (i+1),
        (rand()%9) / 10.0,
        (rand()%9) / 10.0,
        (rand()%9) / 10.0);
    }
}
 
gint draw_met(vars *v,met *m) // прорисовка шарика
{
    cairo_t *cr = gdk_cairo_create(v->w->window);
    cairo_pattern_t *pt;
    cairo_set_line_width(cr,0.1);
    pt = cairo_pattern_create_radial(m->x0,m->y0,0,m->x0,m->y0,m->radi);
    cairo_pattern_add_color_stop_rgba(pt,0.2,m->r,m->g,m->b,0.5);
    cairo_pattern_add_color_stop_rgba(pt,0.9,0,0,0.0,0.05);
    cairo_arc(cr,m->x0,m->y0,m->radi,0,360);
    cairo_set_source(cr, pt);
    cairo_fill(cr);
    cairo_pattern_destroy(pt);
    cairo_destroy(cr);
    return 1;
}
 
gint draw(GtkWidget *w, GdkEventExpose *event, gpointer *data) // прорисовка начального состоЯния окна
{
    cairo_t *cr = gdk_cairo_create(w->window);
    cairo_set_source_rgb(cr, 0, 0, 0);
    cairo_rectangle (cr, 0, 0, 800, 800);
    cairo_fill(cr);
    cairo_destroy(cr);
    return 1;
}
 
gint tail(vars *v) // функция создает эффект "хвоста" за шариком
{
    // эффект хвоста предельно прост
    cairo_t *cr = gdk_cairo_create(v->w->window); // инициализация cairo
    cairo_set_source_rgba(cr, 0, 0, 0,0.06); // задаем очень прозрачный цвет для заливки
    cairo_rectangle (cr, 0, 0, 800, 800);  // накладываем на всю картинку прозрачный слой
    cairo_fill(cr); // закрашиваем
    //
    // далее рисуем центральный шар
    cairo_pattern_t *pt = cairo_pattern_create_radial(350,350,0,350,350,80); // создаем тип заливки - круговой градиент
    cairo_pattern_add_color_stop_rgba(pt,0.2,cos(v->meteors[0].angle),sin(v->meteors[0].angle),0.8,0.5); // указываем начальный цвет
    cairo_pattern_add_color_stop_rgba(pt,0.9,0,0,0.0,0.01); // указываем конечный цвет
    cairo_arc(cr,350,350,90,0,360); // рисуем окружность
    cairo_set_source(cr, pt); // передаем параметры заливки
    cairo_fill(cr); // заливаем окружность
    cairo_pattern_destroy(pt); // отчищаем память
    cairo_destroy(cr); // отчищаем память
    return 1;
}
 
gint timer(gpointer data)
{
    vars *v = (vars *) data;
    int i;
    for(i=0;i<v->mCount;i++) // перемещаем шарики по траектории заданной произвольной функцией=)
    {
        v->meteors[i].z0 = v->meteors[i].dts/5 * (cos((v->meteors[i].angle+=v->meteors[i].speed) * 3.1415/180) * (1 - cos(v->meteors[i].angle * 3.1415/180)));
        v->meteors[i].x0 =350 + ((v->meteors[i].dts * sin(v->meteors[i].angle * 3.1415/180)));
        v->meteors[i].y0 =350 + ((-v->meteors[i].dts * cos(v->meteors[i].angle * 3.1415/180)));
        v->meteors[i].x0 =  v->meteors[i].x0/(1 - v->meteors[i].z0/50.0);
        v->meteors[i].y0 =  v->meteors[i].y0/(1 - v->meteors[i].z0/50.0);
        draw_met(v,&v->meteors[i]); // прорисовываем шарик
        if(v->meteors[i].angle >= 360 || v->meteors[i].angle <= -360)
        {
            v->meteors[i].angle = 0;
        }
    }
    tail(v);
}
 
int main (int argc, char *argv[])
{
    srand(time(0));
    vars v;
    GtkWidget *win = NULL;
    g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING, (GLogFunc) gtk_false, NULL);
    gtk_init (&argc, &argv);
    g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING, g_log_default_handler, NULL);
    win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_container_set_border_width (GTK_CONTAINER (win), 8);
    gtk_window_set_title (GTK_WINDOW (win), "Picture");
    gtk_widget_set_size_request(win,700,700);
    gtk_window_set_position (GTK_WINDOW (win), GTK_WIN_POS_CENTER);
    gtk_widget_realize (win);
    g_signal_connect (win, "destroy", gtk_main_quit, NULL);
    g_signal_connect (win, "expose_event", G_CALLBACK(draw), NULL);
    gtk_widget_show_all (win);
    init_vars(&v,win, 5);
    gtk_timeout_add(25,timer,(gpointer)&v);
    gtk_main ();
    return 0;
}

Ключевые слова: 
gtk gtk+ cairo размытие движения
ВложениеРазмер
main.c.rar2.9 кб