Загрузка данных
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define MAX_FLOWERS 50
#define PETAL_COUNT_MIN 6
#define PETAL_COUNT_MAX 10
#define BASE_PETAL_W 15.0
#define BASE_PETAL_H 45.0
#define BASE_CENTER_R 20
#define SCALE_MIN 0.8
#define SCALE_MAX 1.2
#define SPAWN_INTERVAL_US 500000
typedef struct {
int x, y;
int petals;
double scale;
unsigned long color;
struct timespec birth_time;
int active;
} Daisy;
static int rand_range(int min, int max) {
if (min == max) return min;
return min + rand() % (max - min + 1);
}
static int check_overlap(Daisy *new_d, Daisy *daisies, int count, int win_w, int win_h) {
double r_new = (BASE_PETAL_H + BASE_CENTER_R) * new_d->scale;
if (new_d->x - r_new < 0 || new_d->x + r_new > win_w ||
new_d->y - r_new < 0 || new_d->y + r_new > win_h) {
return 1;
}
for (int i = 0; i < count; i++) {
if (!daisies[i].active) continue;
double r_old = (BASE_PETAL_H + BASE_CENTER_R) * daisies[i].scale;
double dx = new_d->x - daisies[i].x;
double dy = new_d->y - daisies[i].y;
double dist = sqrt(dx * dx + dy * dy);
if (dist < (r_new + r_old)) {
return 1;
}
}
return 0;
}
static long time_diff_us(struct timespec *start, struct timespec *end) {
return (end->tv_sec - start->tv_sec) * 1000000L + (end->tv_nsec - start->tv_nsec) / 1000L;
}
void draw_scene(Display *dpy, Window win, GC gc, Daisy *daisies, int max, unsigned long white, unsigned long yellow, int win_w, int win_h) {
XSetForeground(dpy, gc, white);
XFillRectangle(dpy, win, gc, 0, 0, win_w, win_h);
const int PTS_COUNT = 32;
XPoint *pts = malloc(PTS_COUNT * sizeof(XPoint));
for (int f = 0; f < max; f++) {
if (!daisies[f].active) continue;
Daisy *d = &daisies[f];
double s = d->scale;
double p_w = BASE_PETAL_W * s;
double p_h = BASE_PETAL_H * s;
double dist = (BASE_PETAL_H + BASE_CENTER_R) * 0.6 * s;
int c_r = (int)(BASE_CENTER_R * s);
XSetForeground(dpy, gc, d->color);
for (int i = 0; i < d->petals; i++) {
double angle = (2.0 * M_PI * i) / d->petals;
double cos_a = cos(angle);
double sin_a = sin(angle);
for (int p = 0; p < PTS_COUNT; p++) {
double t = (2.0 * M_PI * p) / PTS_COUNT;
double lx = p_h * cos(t);
double ly = p_w * sin(t);
double rx = lx * cos_a - ly * sin_a;
double ry = lx * sin_a + ly * cos_a;
pts[p].x = (short)(d->x + rx + dist * cos_a);
pts[p].y = (short)(d->y + ry + dist * sin_a);
}
XFillPolygon(dpy, win, gc, pts, PTS_COUNT, Convex, CoordModeOrigin);
}
XSetForeground(dpy, gc, yellow);
XFillArc(dpy, win, gc, d->x - c_r, d->y - c_r,
c_r * 2, c_r * 2, 0, 360 * 64);
}
free(pts);
}
int main() {
srand((unsigned)time(NULL));
Display *dpy = XOpenDisplay(NULL);
if (!dpy) { fprintf(stderr, "Error\n"); return 1; }
int screen = DefaultScreen(dpy);
Window root = RootWindow(dpy, screen);
int win_w = 800, win_h = 600;
Window win = XCreateSimpleWindow(dpy, root, 50, 50, win_w, win_h, 1,
BlackPixel(dpy, screen), WhitePixel(dpy, screen));
// Подписываемся на все нужные события
XSelectInput(dpy, win, ExposureMask | KeyPressMask | StructureNotifyMask);
XMapWindow(dpy, win);
GC gc = XCreateGC(dpy, win, 0, NULL);
XSetFillStyle(dpy, gc, FillSolid);
Colormap cmap = DefaultColormap(dpy, screen);
const char *colors[] = {
"skyblue", "cyan", "lightblue", "powderblue",
"cadetblue", "steelblue", "dodgerblue", "deepskyblue",
"cornflowerblue", "mediumturquoise"
};
int num_colors = sizeof(colors) / sizeof(colors[0]);
unsigned long pixel_colors[20];
for(int i=0; i<num_colors; i++) {
XColor xc;
XAllocNamedColor(dpy, cmap, colors[i], &xc, &xc);
pixel_colors[i] = xc.pixel;
}
XColor xc_white, xc_yellow;
XAllocNamedColor(dpy, cmap, "white", &xc_white, &xc_white);
XAllocNamedColor(dpy, cmap, "yellow", &xc_yellow, &xc_yellow);
unsigned long white = xc_white.pixel;
unsigned long yellow = xc_yellow.pixel;
Atom wmDelete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
XSetWMProtocols(dpy, win, &wmDelete, 1);
Daisy daisies[MAX_FLOWERS];
memset(daisies, 0, sizeof(daisies));
int active_count = 0;
struct timespec last_spawn;
clock_gettime(CLOCK_MONOTONIC, &last_spawn);
XEvent ev;
int running = 1;
// Инициализация: рисуем пустой белый экран
draw_scene(dpy, win, gc, daisies, MAX_FLOWERS, white, yellow, win_w, win_h);
while (running) {
// Неблокирующая проверка событий
if (XCheckWindowEvent(dpy, win, ExposureMask | KeyPressMask | StructureNotifyMask, &ev)) {
switch (ev.type) {
case Expose:
// Игнорируем лишние Expose во время анимации, рисуем только когда нужно
// Но так как мы вызываем draw_scene вручную, здесь можно просто обновить
draw_scene(dpy, win, gc, daisies, MAX_FLOWERS, white, yellow, win_w, win_h);
break;
case KeyPress:
running = 0;
break;
case ClientMessage:
if (ev.xclient.data.l[0] == wmDelete) running = 0;
break;
}
} else {
// Логика таймера и спавна
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if (time_diff_us(&last_spawn, &now) >= SPAWN_INTERVAL_US) {
int placed = 0;
int attempts = 0;
Daisy new_d;
// Пытаемся найти место
while (!placed && attempts < 200) {
new_d.x = rand_range(50, win_w - 50);
new_d.y = rand_range(50, win_h - 50);
new_d.petals = rand_range(PETAL_COUNT_MIN, PETAL_COUNT_MAX);
new_d.scale = SCALE_MIN + ((double)rand() / RAND_MAX) * (SCALE_MAX - SCALE_MIN);
new_d.color = pixel_colors[rand() % num_colors];
new_d.birth_time = now;
if (!check_overlap(&new_d, daisies, MAX_FLOWERS, win_w, win_h)) {
placed = 1;
}
attempts++;
}
if (placed) {
int slot = -1;
// Поиск свободного слота или самого старого
if (active_count < MAX_FLOWERS) {
for(int i=0; i<MAX_FLOWERS; i++) {
if(!daisies[i].active) {
slot = i;
break;
}
}
active_count++;
} else {
struct timespec oldest = daisies[0].birth_time;
slot = 0;
for(int i=1; i<MAX_FLOWERS; i++) {
if (time_diff_us(&daisies[i].birth_time, &oldest) > 0) {
oldest = daisies[i].birth_time;
slot = i;
}
}
}
daisies[slot] = new_d;
daisies[slot].active = 1;
// Принудительная перерисовка сразу после добавления
draw_scene(dpy, win, gc, daisies, MAX_FLOWERS, white, yellow, win_w, win_h);
XFlush(dpy);
}
last_spawn = now;
}
usleep(10000);
}
}
XFreeGC(dpy, gc);
XDestroyWindow(dpy, win);
XCloseDisplay(dpy);
return 0;
}