"Initial commit to Gerrit"
[profile/ivi/cogl.git] / examples / cogl-crate.c
1 #include <cogl/cogl.h>
2 #include <cogl-pango/cogl-pango.h>
3
4 /* The state for this example... */
5 typedef struct _Data
6 {
7   CoglFramebuffer *fb;
8   int framebuffer_width;
9   int framebuffer_height;
10
11   CoglMatrix view;
12
13   CoglIndices *indices;
14   CoglPrimitive *prim;
15   CoglTexture *texture;
16   CoglPipeline *crate_pipeline;
17
18   CoglPangoFontMap *pango_font_map;
19   PangoContext *pango_context;
20   PangoFontDescription *pango_font_desc;
21
22   PangoLayout *hello_label;
23   int hello_label_width;
24   int hello_label_height;
25
26   GTimer *timer;
27
28   gboolean swap_ready;
29
30 } Data;
31
32 /* A static identity matrix initialized for convenience. */
33 static CoglMatrix identity;
34 /* static colors initialized for convenience. */
35 static CoglColor white;
36
37 /* A cube modelled using 4 vertices for each face.
38  *
39  * We use an index buffer when drawing the cube later so the GPU will
40  * actually read each face as 2 separate triangles.
41  */
42 static CoglVertexP3T2 vertices[] =
43 {
44   /* Front face */
45   { /* pos = */ -1.0f, -1.0f,  1.0f, /* tex coords = */ 0.0f, 1.0f},
46   { /* pos = */  1.0f, -1.0f,  1.0f, /* tex coords = */ 1.0f, 1.0f},
47   { /* pos = */  1.0f,  1.0f,  1.0f, /* tex coords = */ 1.0f, 0.0f},
48   { /* pos = */ -1.0f,  1.0f,  1.0f, /* tex coords = */ 0.0f, 0.0f},
49
50   /* Back face */
51   { /* pos = */ -1.0f, -1.0f, -1.0f, /* tex coords = */ 1.0f, 0.0f},
52   { /* pos = */ -1.0f,  1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f},
53   { /* pos = */  1.0f,  1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f},
54   { /* pos = */  1.0f, -1.0f, -1.0f, /* tex coords = */ 0.0f, 0.0f},
55
56   /* Top face */
57   { /* pos = */ -1.0f,  1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f},
58   { /* pos = */ -1.0f,  1.0f,  1.0f, /* tex coords = */ 0.0f, 0.0f},
59   { /* pos = */  1.0f,  1.0f,  1.0f, /* tex coords = */ 1.0f, 0.0f},
60   { /* pos = */  1.0f,  1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f},
61
62   /* Bottom face */
63   { /* pos = */ -1.0f, -1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f},
64   { /* pos = */  1.0f, -1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f},
65   { /* pos = */  1.0f, -1.0f,  1.0f, /* tex coords = */ 0.0f, 0.0f},
66   { /* pos = */ -1.0f, -1.0f,  1.0f, /* tex coords = */ 1.0f, 0.0f},
67
68   /* Right face */
69   { /* pos = */ 1.0f, -1.0f, -1.0f, /* tex coords = */ 1.0f, 0.0f},
70   { /* pos = */ 1.0f,  1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f},
71   { /* pos = */ 1.0f,  1.0f,  1.0f, /* tex coords = */ 0.0f, 1.0f},
72   { /* pos = */ 1.0f, -1.0f,  1.0f, /* tex coords = */ 0.0f, 0.0f},
73
74   /* Left face */
75   { /* pos = */ -1.0f, -1.0f, -1.0f, /* tex coords = */ 0.0f, 0.0f},
76   { /* pos = */ -1.0f, -1.0f,  1.0f, /* tex coords = */ 1.0f, 0.0f},
77   { /* pos = */ -1.0f,  1.0f,  1.0f, /* tex coords = */ 1.0f, 1.0f},
78   { /* pos = */ -1.0f,  1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f}
79 };
80
81 static void
82 paint (Data *data)
83 {
84   CoglFramebuffer *fb = data->fb;
85   float rotation;
86
87   cogl_framebuffer_clear4f (fb,
88                             COGL_BUFFER_BIT_COLOR|COGL_BUFFER_BIT_DEPTH,
89                             0, 0, 0, 1);
90
91   cogl_framebuffer_push_matrix (fb);
92
93   cogl_framebuffer_translate (fb,
94                               data->framebuffer_width / 2,
95                               data->framebuffer_height / 2,
96                               0);
97
98   cogl_framebuffer_scale (fb, 75, 75, 75);
99
100   /* Update the rotation based on the time the application has been
101      running so that we get a linear animation regardless of the frame
102      rate */
103   rotation = g_timer_elapsed (data->timer, NULL) * 60.0f;
104
105   /* Rotate the cube separately around each axis.
106    *
107    * Note: Cogl matrix manipulation follows the same rules as for
108    * OpenGL. We use column-major matrices and - if you consider the
109    * transformations happening to the model - then they are combined
110    * in reverse order which is why the rotation is done last, since
111    * we want it to be a rotation around the origin, before it is
112    * scaled and translated.
113    */
114   cogl_framebuffer_rotate (fb, rotation, 0, 0, 1);
115   cogl_framebuffer_rotate (fb, rotation, 0, 1, 0);
116   cogl_framebuffer_rotate (fb, rotation, 1, 0, 0);
117
118   cogl_framebuffer_draw_primitive (fb, data->crate_pipeline, data->prim);
119
120   cogl_framebuffer_pop_matrix (fb);
121
122   /* And finally render our Pango layouts... */
123
124   cogl_pango_render_layout (data->hello_label,
125                             (data->framebuffer_width / 2) -
126                             (data->hello_label_width / 2),
127                             (data->framebuffer_height / 2) -
128                             (data->hello_label_height / 2),
129                             &white, 0);
130 }
131
132 static void
133 swap_notify_cb (CoglFramebuffer *framebuffer,
134                 void *user_data)
135 {
136   Data *data = user_data;
137
138   data->swap_ready = TRUE;
139 }
140
141 int
142 main (int argc, char **argv)
143 {
144   CoglContext *ctx;
145   CoglOnscreen *onscreen;
146   CoglFramebuffer *fb;
147   GError *error = NULL;
148   Data data;
149   PangoRectangle hello_label_size;
150   float fovy, aspect, z_near, z_2d, z_far;
151   CoglDepthState depth_state;
152   gboolean has_swap_notify;
153
154   ctx = cogl_context_new (NULL, &error);
155   if (!ctx) {
156       fprintf (stderr, "Failed to create context: %s\n", error->message);
157       return 1;
158   }
159
160   onscreen = cogl_onscreen_new (ctx, 640, 480);
161   fb = COGL_FRAMEBUFFER (onscreen);
162   data.fb = fb;
163   data.framebuffer_width = cogl_framebuffer_get_width (fb);
164   data.framebuffer_height = cogl_framebuffer_get_height (fb);
165
166   data.timer = g_timer_new ();
167
168   cogl_onscreen_show (onscreen);
169
170   cogl_push_framebuffer (fb);
171   cogl_set_viewport (0, 0, data.framebuffer_width, data.framebuffer_height);
172
173   fovy = 60; /* y-axis field of view */
174   aspect = (float)data.framebuffer_width/(float)data.framebuffer_height;
175   z_near = 0.1; /* distance to near clipping plane */
176   z_2d = 1000; /* position to 2d plane */
177   z_far = 2000; /* distance to far clipping plane */
178
179   cogl_perspective (fovy, aspect, z_near, z_far);
180
181   /* Since the pango renderer emits geometry in pixel/device coordinates
182    * and the anti aliasing is implemented with the assumption that the
183    * geometry *really* does end up pixel aligned, we setup a modelview
184    * matrix so that for geometry in the plane z = 0 we exactly map x
185    * coordinates in the range [0,stage_width] and y coordinates in the
186    * range [0,stage_height] to the framebuffer extents with (0,0) being
187    * the top left.
188    *
189    * This is roughly what Clutter does for a ClutterStage, but this
190    * demonstrates how it is done manually using Cogl.
191    */
192   cogl_matrix_init_identity (&data.view);
193   cogl_matrix_view_2d_in_perspective (&data.view, fovy, aspect, z_near, z_2d,
194                                       data.framebuffer_width,
195                                       data.framebuffer_height);
196   cogl_set_modelview_matrix (&data.view);
197   cogl_pop_framebuffer ();
198
199   /* Initialize some convenient constants */
200   cogl_matrix_init_identity (&identity);
201   cogl_color_set_from_4ub (&white, 0xff, 0xff, 0xff, 0xff);
202
203   /* rectangle indices allow the GPU to interpret a list of quads (the
204    * faces of our cube) as a list of triangles.
205    *
206    * Since this is a very common thing to do
207    * cogl_get_rectangle_indices() is a convenience function for
208    * accessing internal index buffers that can be shared.
209    */
210   data.indices = cogl_get_rectangle_indices (ctx, 6 /* n_rectangles */);
211   data.prim = cogl_primitive_new_p3t2 (ctx, COGL_VERTICES_MODE_TRIANGLES,
212                                        G_N_ELEMENTS (vertices),
213                                        vertices);
214   /* Each face will have 6 indices so we have 6 * 6 indices in total... */
215   cogl_primitive_set_indices (data.prim,
216                               data.indices,
217                               6 * 6);
218
219   /* Load a jpeg crate texture from a file */
220   printf ("crate.jpg (CC by-nc-nd http://bit.ly/9kP45T) ShadowRunner27 http://bit.ly/m1YXLh\n");
221   data.texture = cogl_texture_new_from_file (COGL_EXAMPLES_DATA "crate.jpg",
222                                              COGL_TEXTURE_NO_SLICING,
223                                              COGL_PIXEL_FORMAT_ANY,
224                                              &error);
225   if (!data.texture)
226     g_error ("Failed to load texture: %s", error->message);
227
228   /* a CoglPipeline conceptually describes all the state for vertex
229    * processing, fragment processing and blending geometry. When
230    * drawing the geometry for the crate this pipeline says to sample a
231    * single texture during fragment processing... */
232   data.crate_pipeline = cogl_pipeline_new (ctx);
233   cogl_pipeline_set_layer_texture (data.crate_pipeline, 0, data.texture);
234
235   /* Since the box is made of multiple triangles that will overlap
236    * when drawn and we don't control the order they are drawn in, we
237    * enable depth testing to make sure that triangles that shouldn't
238    * be visible get culled by the GPU. */
239   cogl_depth_state_init (&depth_state);
240   cogl_depth_state_set_test_enabled (&depth_state, TRUE);
241
242   cogl_pipeline_set_depth_state (data.crate_pipeline, &depth_state, NULL);
243
244   /* Setup a Pango font map and context */
245
246   data.pango_font_map = COGL_PANGO_FONT_MAP (cogl_pango_font_map_new());
247
248   cogl_pango_font_map_set_use_mipmapping (data.pango_font_map, TRUE);
249
250   data.pango_context = cogl_pango_font_map_create_context (data.pango_font_map);
251
252   data.pango_font_desc = pango_font_description_new ();
253   pango_font_description_set_family (data.pango_font_desc, "Sans");
254   pango_font_description_set_size (data.pango_font_desc, 30 * PANGO_SCALE);
255
256   /* Setup the "Hello Cogl" text */
257
258   data.hello_label = pango_layout_new (data.pango_context);
259   pango_layout_set_font_description (data.hello_label, data.pango_font_desc);
260   pango_layout_set_text (data.hello_label, "Hello Cogl", -1);
261
262   pango_layout_get_extents (data.hello_label, NULL, &hello_label_size);
263   data.hello_label_width = PANGO_PIXELS (hello_label_size.width);
264   data.hello_label_height = PANGO_PIXELS (hello_label_size.height);
265
266   cogl_push_framebuffer (fb);
267
268   data.swap_ready = TRUE;
269
270   has_swap_notify =
271     cogl_has_feature (ctx, COGL_FEATURE_ID_SWAP_BUFFERS_EVENT);
272
273   if (has_swap_notify)
274     cogl_onscreen_add_swap_buffers_callback (COGL_ONSCREEN (fb),
275                                              swap_notify_cb,
276                                              &data);
277
278   while (1)
279     {
280       CoglPollFD *poll_fds;
281       int n_poll_fds;
282       gint64 timeout;
283
284       if (data.swap_ready)
285         {
286           paint (&data);
287           cogl_onscreen_swap_buffers (COGL_ONSCREEN (fb));
288         }
289
290       cogl_poll_get_info (ctx, &poll_fds, &n_poll_fds, &timeout);
291
292       if (!has_swap_notify)
293         {
294           /* If the winsys doesn't support swap event notification
295              then we'll just redraw constantly */
296           data.swap_ready = TRUE;
297           timeout = 0;
298         }
299
300       g_poll ((GPollFD *) poll_fds, n_poll_fds,
301               timeout == -1 ? -1 : timeout / 1000);
302
303       cogl_poll_dispatch (ctx, poll_fds, n_poll_fds);
304     }
305
306   return 0;
307 }
308