1 #include <cogl/cogl.h>
2 #include <glib.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <string.h>
6
7 #define N_FIREWORKS 32
8 /* Units per second per second */
9 #define GRAVITY -1.5f
10
11 #define N_SPARKS (N_FIREWORKS * 32) /* Must be a power of two */
12 #define TIME_PER_SPARK 0.01f /* in seconds */
13
14 #define TEXTURE_SIZE 32
15
16 typedef struct
17 {
18 uint8_t red, green, blue, alpha;
19 } Color;
20
21 typedef struct
22 {
23 float size;
24 float x, y;
25 float start_x, start_y;
26 Color color;
27
28 /* Velocities are in units per second */
29 float initial_x_velocity;
30 float initial_y_velocity;
31
32 GTimer *timer;
33 } Firework;
34
35 typedef struct
36 {
37 float x, y;
38 Color color;
39 Color base_color;
40 } Spark;
41
42 typedef struct
43 {
44 Firework fireworks[N_FIREWORKS];
45
46 int next_spark_num;
47 Spark sparks[N_SPARKS];
48 GTimer *last_spark_time;
49
50 CoglContext *context;
51 CoglFramebuffer *fb;
52 CoglPipeline *pipeline;
53 CoglPrimitive *primitive;
54 CoglAttributeBuffer *attribute_buffer;
55 } Data;
56
57 static CoglTexture *
generate_round_texture(CoglContext * context)58 generate_round_texture (CoglContext *context)
59 {
60 uint8_t *p, *data;
61 int x, y;
62 CoglTexture2D *tex;
63
64 p = data = g_malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4);
65
66 /* Generate a white circle which gets transparent towards the edges */
67 for (y = 0; y < TEXTURE_SIZE; y++)
68 for (x = 0; x < TEXTURE_SIZE; x++)
69 {
70 int dx = x - TEXTURE_SIZE / 2;
71 int dy = y - TEXTURE_SIZE / 2;
72 float value = sqrtf (dx * dx + dy * dy) * 255.0 / (TEXTURE_SIZE / 2);
73 if (value > 255.0f)
74 value = 255.0f;
75 value = 255.0f - value;
76 *(p++) = value;
77 *(p++) = value;
78 *(p++) = value;
79 *(p++) = value;
80 }
81
82 tex = cogl_texture_2d_new_from_data (context,
83 TEXTURE_SIZE, TEXTURE_SIZE,
84 COGL_PIXEL_FORMAT_RGBA_8888_PRE,
85 TEXTURE_SIZE * 4,
86 data,
87 NULL /* error */);
88
89 g_free (data);
90
91 return tex;
92 }
93
94 static void
paint(Data * data)95 paint (Data *data)
96 {
97 int i;
98 float diff_time;
99
100 /* Update all of the firework's positions */
101 for (i = 0; i < N_FIREWORKS; i++)
102 {
103 Firework *firework = data->fireworks + i;
104
105 if ((fabsf (firework->x - firework->start_x) > 2.0f) ||
106 firework->y < -1.0f)
107 {
108 firework->size = g_random_double_range (0.001f, 0.1f);
109 firework->start_x = 1.0f + firework->size;
110 firework->start_y = -1.0f;
111 firework->initial_x_velocity = g_random_double_range (-0.1f, -2.0f);
112 firework->initial_y_velocity = g_random_double_range (0.1f, 4.0f);
113 g_timer_reset (firework->timer);
114
115 /* Pick a random color out of six */
116 if (g_random_boolean ())
117 {
118 memset (&firework->color, 0, sizeof (Color));
119 ((uint8_t *) &firework->color)[g_random_int_range (0, 3)] = 255;
120 }
121 else
122 {
123 memset (&firework->color, 255, sizeof (Color));
124 ((uint8_t *) &firework->color)[g_random_int_range (0, 3)] = 0;
125 }
126 firework->color.alpha = 255;
127
128 /* Fire some of the fireworks from the other side */
129 if (g_random_boolean ())
130 {
131 firework->start_x = -firework->start_x;
132 firework->initial_x_velocity = -firework->initial_x_velocity;
133 }
134 }
135
136 diff_time = g_timer_elapsed (firework->timer, NULL);
137
138 firework->x = (firework->start_x +
139 firework->initial_x_velocity * diff_time);
140
141 firework->y = ((firework->initial_y_velocity * diff_time +
142 0.5f * GRAVITY * diff_time * diff_time) +
143 firework->start_y);
144 }
145
146 diff_time = g_timer_elapsed (data->last_spark_time, NULL);
147 if (diff_time < 0.0f || diff_time >= TIME_PER_SPARK)
148 {
149 /* Add a new spark for each firework, overwriting the oldest ones */
150 for (i = 0; i < N_FIREWORKS; i++)
151 {
152 Spark *spark = data->sparks + data->next_spark_num;
153 Firework *firework = data->fireworks + i;
154
155 spark->x = (firework->x +
156 g_random_double_range (-firework->size / 2.0f,
157 firework->size / 2.0f));
158 spark->y = (firework->y +
159 g_random_double_range (-firework->size / 2.0f,
160 firework->size / 2.0f));
161 spark->base_color = firework->color;
162
163 data->next_spark_num = (data->next_spark_num + 1) & (N_SPARKS - 1);
164 }
165
166 /* Update the colour of each spark */
167 for (i = 0; i < N_SPARKS; i++)
168 {
169 float color_value;
170
171 /* First spark is the oldest */
172 Spark *spark = data->sparks + ((data->next_spark_num + i)
173 & (N_SPARKS - 1));
174
175 color_value = i / (N_SPARKS - 1.0f);
176 spark->color.red = spark->base_color.red * color_value;
177 spark->color.green = spark->base_color.green * color_value;
178 spark->color.blue = spark->base_color.blue * color_value;
179 spark->color.alpha = 255.0f * color_value;
180 }
181
182 g_timer_reset (data->last_spark_time);
183 }
184
185 cogl_buffer_set_data (data->attribute_buffer,
186 0, /* offset */
187 data->sparks,
188 sizeof (data->sparks));
189
190 cogl_framebuffer_clear4f (data->fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
191
192 cogl_primitive_draw (data->primitive,
193 data->fb,
194 data->pipeline);
195
196 cogl_onscreen_swap_buffers (data->fb);
197 }
198
199 static void
create_primitive(Data * data)200 create_primitive (Data *data)
201 {
202 CoglAttribute *attributes[2];
203 int i;
204
205 data->attribute_buffer =
206 cogl_attribute_buffer_new_with_size (data->context,
207 sizeof (data->sparks));
208 cogl_buffer_set_update_hint (data->attribute_buffer,
209 COGL_BUFFER_UPDATE_HINT_DYNAMIC);
210
211 attributes[0] = cogl_attribute_new (data->attribute_buffer,
212 "cogl_position_in",
213 sizeof (Spark),
214 G_STRUCT_OFFSET (Spark, x),
215 2, /* n_components */
216 COGL_ATTRIBUTE_TYPE_FLOAT);
217 attributes[1] = cogl_attribute_new (data->attribute_buffer,
218 "cogl_color_in",
219 sizeof (Spark),
220 G_STRUCT_OFFSET (Spark, color),
221 4, /* n_components */
222 COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
223
224 data->primitive =
225 cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_POINTS,
226 N_SPARKS,
227 attributes,
228 G_N_ELEMENTS (attributes));
229
230 for (i = 0; i < G_N_ELEMENTS (attributes); i++)
231 cogl_object_unref (attributes[i]);
232 }
233
234 static void
frame_event_cb(CoglOnscreen * onscreen,CoglFrameEvent event,CoglFrameInfo * info,void * user_data)235 frame_event_cb (CoglOnscreen *onscreen,
236 CoglFrameEvent event,
237 CoglFrameInfo *info,
238 void *user_data)
239 {
240 Data *data = user_data;
241
242 if (event == COGL_FRAME_EVENT_SYNC)
243 paint (data);
244 }
245
246 int
main(int argc,char * argv[])247 main (int argc, char *argv[])
248 {
249 CoglTexture *tex;
250 CoglOnscreen *onscreen;
251 GSource *cogl_source;
252 GMainLoop *loop;
253 Data data;
254 int i;
255
256 data.context = cogl_context_new (NULL, NULL);
257
258 create_primitive (&data);
259
260 data.pipeline = cogl_pipeline_new (data.context);
261 data.last_spark_time = g_timer_new ();
262 data.next_spark_num = 0;
263 cogl_pipeline_set_point_size (data.pipeline, TEXTURE_SIZE);
264
265 tex = generate_round_texture (data.context);
266 cogl_pipeline_set_layer_texture (data.pipeline, 0, tex);
267 cogl_object_unref (tex);
268
269 cogl_pipeline_set_layer_point_sprite_coords_enabled (data.pipeline,
270 0, /* layer */
271 TRUE,
272 NULL /* error */);
273
274 for (i = 0; i < N_FIREWORKS; i++)
275 {
276 data.fireworks[i].x = -FLT_MAX;
277 data.fireworks[i].y = FLT_MAX;
278 data.fireworks[i].size = 0.0f;
279 data.fireworks[i].timer = g_timer_new ();
280 }
281
282 for (i = 0; i < N_SPARKS; i++)
283 {
284 data.sparks[i].x = 2.0f;
285 data.sparks[i].y = 2.0f;
286 }
287
288 onscreen = cogl_onscreen_new (data.context, 800, 600);
289 cogl_onscreen_show (onscreen);
290 data.fb = onscreen;
291
292 cogl_source = cogl_glib_source_new (data.context, G_PRIORITY_DEFAULT);
293
294 g_source_attach (cogl_source, NULL);
295
296 cogl_onscreen_add_frame_callback (onscreen,
297 frame_event_cb,
298 &data,
299 NULL /* destroy notify */);
300
301 loop = g_main_loop_new (NULL, TRUE);
302
303 paint (&data);
304
305 g_main_loop_run (loop);
306
307 g_main_loop_unref (loop);
308
309 g_source_destroy (cogl_source);
310
311 cogl_object_unref (data.pipeline);
312 cogl_object_unref (data.attribute_buffer);
313 cogl_object_unref (data.primitive);
314 cogl_object_unref (onscreen);
315 cogl_object_unref (data.context);
316
317 g_timer_destroy (data.last_spark_time);
318
319 for (i = 0; i < N_FIREWORKS; i++)
320 g_timer_destroy (data.fireworks[i].timer);
321
322 return 0;
323 }
324