"Initial commit to Gerrit"
[profile/ivi/cogl.git] / cogl / cogl-primitive.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2010 Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see
20  * <http://www.gnu.org/licenses/>.
21  *
22  *
23  *
24  * Authors:
25  *   Robert Bragg <robert@linux.intel.com>
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "cogl-util.h"
33 #include "cogl-object-private.h"
34 #include "cogl-primitive.h"
35 #include "cogl-primitive-private.h"
36 #include "cogl-attribute-private.h"
37
38 #include <stdarg.h>
39 #include <string.h>
40
41 static void _cogl_primitive_free (CoglPrimitive *primitive);
42
43 COGL_OBJECT_DEFINE (Primitive, primitive);
44
45 CoglPrimitive *
46 cogl_primitive_new_with_attributes (CoglVerticesMode mode,
47                                     int n_vertices,
48                                     CoglAttribute **attributes,
49                                     int n_attributes)
50 {
51   CoglPrimitive *primitive;
52   int i;
53
54   primitive = g_slice_alloc (sizeof (CoglPrimitive) +
55                              sizeof (CoglAttribute *) * (n_attributes - 1));
56   primitive->mode = mode;
57   primitive->first_vertex = 0;
58   primitive->n_vertices = n_vertices;
59   primitive->indices = NULL;
60   primitive->immutable_ref = 0;
61
62   primitive->n_attributes = n_attributes;
63   primitive->n_embedded_attributes = n_attributes;
64   primitive->attributes = &primitive->embedded_attribute;
65   for (i = 0; i < n_attributes; i++)
66     {
67       CoglAttribute *attribute = attributes[i];
68       cogl_object_ref (attribute);
69
70       _COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), NULL);
71
72       primitive->attributes[i] = attribute;
73     }
74
75   return _cogl_primitive_object_new (primitive);
76 }
77
78 /* This is just an internal convenience wrapper around
79    new_with_attributes that also unrefs the attributes. It is just
80    used for the builtin struct constructors */
81 static CoglPrimitive *
82 _cogl_primitive_new_with_attributes_unref (CoglVerticesMode mode,
83                                            int n_vertices,
84                                            CoglAttribute **attributes,
85                                            int n_attributes)
86 {
87   CoglPrimitive *primitive;
88   int i;
89
90   primitive = cogl_primitive_new_with_attributes (mode,
91                                                   n_vertices,
92                                                   attributes,
93                                                   n_attributes);
94
95   for (i = 0; i < n_attributes; i++)
96     cogl_object_unref (attributes[i]);
97
98   return primitive;
99 }
100
101 CoglPrimitive *
102 cogl_primitive_new (CoglVerticesMode mode,
103                     int n_vertices,
104                     ...)
105 {
106   va_list ap;
107   int n_attributes;
108   CoglAttribute **attributes;
109   int i;
110   CoglAttribute *attribute;
111
112   va_start (ap, n_vertices);
113   for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
114     ;
115   va_end (ap);
116
117   attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes);
118
119   va_start (ap, n_vertices);
120   for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
121     attributes[i] = attribute;
122   va_end (ap);
123
124   return cogl_primitive_new_with_attributes (mode, n_vertices,
125                                              attributes,
126                                              i);
127 }
128
129 CoglPrimitive *
130 cogl_primitive_new_p2 (CoglContext *ctx,
131                        CoglVerticesMode mode,
132                        int n_vertices,
133                        const CoglVertexP2 *data)
134 {
135   CoglAttributeBuffer *attribute_buffer =
136     cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP2), data);
137   CoglAttribute *attributes[1];
138
139   attributes[0] = cogl_attribute_new (attribute_buffer,
140                                       "cogl_position_in",
141                                       sizeof (CoglVertexP2),
142                                       offsetof (CoglVertexP2, x),
143                                       2,
144                                       COGL_ATTRIBUTE_TYPE_FLOAT);
145
146   cogl_object_unref (attribute_buffer);
147
148   return _cogl_primitive_new_with_attributes_unref (mode, n_vertices,
149                                                     attributes,
150                                                     1);
151 }
152
153 CoglPrimitive *
154 cogl_primitive_new_p3 (CoglContext *ctx,
155                        CoglVerticesMode mode,
156                        int n_vertices,
157                        const CoglVertexP3 *data)
158 {
159   CoglAttributeBuffer *attribute_buffer =
160     cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP3), data);
161   CoglAttribute *attributes[1];
162
163   attributes[0] = cogl_attribute_new (attribute_buffer,
164                                       "cogl_position_in",
165                                       sizeof (CoglVertexP3),
166                                       offsetof (CoglVertexP3, x),
167                                       3,
168                                       COGL_ATTRIBUTE_TYPE_FLOAT);
169
170   cogl_object_unref (attribute_buffer);
171
172   return _cogl_primitive_new_with_attributes_unref (mode, n_vertices,
173                                                     attributes,
174                                                     1);
175 }
176
177 CoglPrimitive *
178 cogl_primitive_new_p2c4 (CoglContext *ctx,
179                          CoglVerticesMode mode,
180                          int n_vertices,
181                          const CoglVertexP2C4 *data)
182 {
183   CoglAttributeBuffer *attribute_buffer =
184     cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP2C4), data);
185   CoglAttribute *attributes[2];
186
187   attributes[0] = cogl_attribute_new (attribute_buffer,
188                                       "cogl_position_in",
189                                       sizeof (CoglVertexP2C4),
190                                       offsetof (CoglVertexP2C4, x),
191                                       2,
192                                       COGL_ATTRIBUTE_TYPE_FLOAT);
193   attributes[1] = cogl_attribute_new (attribute_buffer,
194                                       "cogl_color_in",
195                                       sizeof (CoglVertexP2C4),
196                                       offsetof (CoglVertexP2C4, r),
197                                       4,
198                                       COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
199
200   cogl_object_unref (attribute_buffer);
201
202   return _cogl_primitive_new_with_attributes_unref (mode, n_vertices,
203                                                     attributes,
204                                                     2);
205 }
206
207 CoglPrimitive *
208 cogl_primitive_new_p3c4 (CoglContext *ctx,
209                          CoglVerticesMode mode,
210                          int n_vertices,
211                          const CoglVertexP3C4 *data)
212 {
213   CoglAttributeBuffer *attribute_buffer =
214     cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP3C4), data);
215   CoglAttribute *attributes[2];
216
217   attributes[0] = cogl_attribute_new (attribute_buffer,
218                                       "cogl_position_in",
219                                       sizeof (CoglVertexP3C4),
220                                       offsetof (CoglVertexP3C4, x),
221                                       3,
222                                       COGL_ATTRIBUTE_TYPE_FLOAT);
223   attributes[1] = cogl_attribute_new (attribute_buffer,
224                                       "cogl_color_in",
225                                       sizeof (CoglVertexP3C4),
226                                       offsetof (CoglVertexP3C4, r),
227                                       4,
228                                       COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
229
230   cogl_object_unref (attribute_buffer);
231
232   return _cogl_primitive_new_with_attributes_unref (mode, n_vertices,
233                                                     attributes,
234                                                     2);
235 }
236
237 CoglPrimitive *
238 cogl_primitive_new_p2t2 (CoglContext *ctx,
239                          CoglVerticesMode mode,
240                          int n_vertices,
241                          const CoglVertexP2T2 *data)
242 {
243   CoglAttributeBuffer *attribute_buffer =
244     cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP2T2), data);
245   CoglAttribute *attributes[2];
246
247   attributes[0] = cogl_attribute_new (attribute_buffer,
248                                       "cogl_position_in",
249                                       sizeof (CoglVertexP2T2),
250                                       offsetof (CoglVertexP2T2, x),
251                                       2,
252                                       COGL_ATTRIBUTE_TYPE_FLOAT);
253   attributes[1] = cogl_attribute_new (attribute_buffer,
254                                       "cogl_tex_coord0_in",
255                                       sizeof (CoglVertexP2T2),
256                                       offsetof (CoglVertexP2T2, s),
257                                       2,
258                                       COGL_ATTRIBUTE_TYPE_FLOAT);
259
260   cogl_object_unref (attribute_buffer);
261
262   return _cogl_primitive_new_with_attributes_unref (mode, n_vertices,
263                                                     attributes,
264                                                     2);
265 }
266
267 CoglPrimitive *
268 cogl_primitive_new_p3t2 (CoglContext *ctx,
269                          CoglVerticesMode mode,
270                          int n_vertices,
271                          const CoglVertexP3T2 *data)
272 {
273   CoglAttributeBuffer *attribute_buffer =
274     cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP3T2), data);
275   CoglAttribute *attributes[2];
276
277   attributes[0] = cogl_attribute_new (attribute_buffer,
278                                       "cogl_position_in",
279                                       sizeof (CoglVertexP3T2),
280                                       offsetof (CoglVertexP3T2, x),
281                                       3,
282                                       COGL_ATTRIBUTE_TYPE_FLOAT);
283   attributes[1] = cogl_attribute_new (attribute_buffer,
284                                       "cogl_tex_coord0_in",
285                                       sizeof (CoglVertexP3T2),
286                                       offsetof (CoglVertexP3T2, s),
287                                       2,
288                                       COGL_ATTRIBUTE_TYPE_FLOAT);
289
290   cogl_object_unref (attribute_buffer);
291
292   return _cogl_primitive_new_with_attributes_unref (mode, n_vertices,
293                                                     attributes,
294                                                     2);
295 }
296
297 CoglPrimitive *
298 cogl_primitive_new_p2t2c4 (CoglContext *ctx,
299                            CoglVerticesMode mode,
300                            int n_vertices,
301                            const CoglVertexP2T2C4 *data)
302 {
303   CoglAttributeBuffer *attribute_buffer =
304     cogl_attribute_buffer_new (ctx,
305                                n_vertices * sizeof (CoglVertexP2T2C4), data);
306   CoglAttribute *attributes[3];
307
308   attributes[0] = cogl_attribute_new (attribute_buffer,
309                                       "cogl_position_in",
310                                       sizeof (CoglVertexP2T2C4),
311                                       offsetof (CoglVertexP2T2C4, x),
312                                       2,
313                                       COGL_ATTRIBUTE_TYPE_FLOAT);
314   attributes[1] = cogl_attribute_new (attribute_buffer,
315                                       "cogl_tex_coord0_in",
316                                       sizeof (CoglVertexP2T2C4),
317                                       offsetof (CoglVertexP2T2C4, s),
318                                       2,
319                                       COGL_ATTRIBUTE_TYPE_FLOAT);
320   attributes[2] = cogl_attribute_new (attribute_buffer,
321                                       "cogl_color_in",
322                                       sizeof (CoglVertexP2T2C4),
323                                       offsetof (CoglVertexP2T2C4, r),
324                                       4,
325                                       COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
326
327   cogl_object_unref (attribute_buffer);
328
329   return _cogl_primitive_new_with_attributes_unref (mode, n_vertices,
330                                                     attributes,
331                                                     3);
332 }
333
334 CoglPrimitive *
335 cogl_primitive_new_p3t2c4 (CoglContext *ctx,
336                            CoglVerticesMode mode,
337                            int n_vertices,
338                            const CoglVertexP3T2C4 *data)
339 {
340   CoglAttributeBuffer *attribute_buffer =
341     cogl_attribute_buffer_new (ctx,
342                                n_vertices * sizeof (CoglVertexP3T2C4), data);
343   CoglAttribute *attributes[3];
344
345   attributes[0] = cogl_attribute_new (attribute_buffer,
346                                       "cogl_position_in",
347                                       sizeof (CoglVertexP3T2C4),
348                                       offsetof (CoglVertexP3T2C4, x),
349                                       3,
350                                       COGL_ATTRIBUTE_TYPE_FLOAT);
351   attributes[1] = cogl_attribute_new (attribute_buffer,
352                                       "cogl_tex_coord0_in",
353                                       sizeof (CoglVertexP3T2C4),
354                                       offsetof (CoglVertexP3T2C4, s),
355                                       2,
356                                       COGL_ATTRIBUTE_TYPE_FLOAT);
357   attributes[2] = cogl_attribute_new (attribute_buffer,
358                                       "cogl_color_in",
359                                       sizeof (CoglVertexP3T2C4),
360                                       offsetof (CoglVertexP3T2C4, r),
361                                       4,
362                                       COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
363
364   cogl_object_unref (attribute_buffer);
365
366   return _cogl_primitive_new_with_attributes_unref (mode, n_vertices,
367                                                     attributes,
368                                                     3);
369 }
370
371 static void
372 _cogl_primitive_free (CoglPrimitive *primitive)
373 {
374   int i;
375
376   for (i = 0; i < primitive->n_attributes; i++)
377     cogl_object_unref (primitive->attributes[i]);
378
379   if (primitive->attributes != &primitive->embedded_attribute)
380     g_slice_free1 (sizeof (CoglAttribute *) * primitive->n_attributes,
381                    primitive->attributes);
382
383   g_slice_free1 (sizeof (CoglPrimitive) +
384                  sizeof (CoglAttribute *) *
385                  (primitive->n_embedded_attributes - 1), primitive);
386 }
387
388 static void
389 warn_about_midscene_changes (void)
390 {
391   static gboolean seen = FALSE;
392   if (!seen)
393     {
394       g_warning ("Mid-scene modification of primitives has "
395                  "undefined results\n");
396       seen = TRUE;
397     }
398 }
399
400 void
401 cogl_primitive_set_attributes (CoglPrimitive *primitive,
402                                CoglAttribute **attributes,
403                                int n_attributes)
404 {
405   int i;
406
407   _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive));
408
409   if (G_UNLIKELY (primitive->immutable_ref))
410     {
411       warn_about_midscene_changes ();
412       return;
413     }
414
415   /* NB: we don't unref the previous attributes before refing the new
416    * in case we would end up releasing the last reference for an
417    * attribute thats actually in the new list too. */
418   for (i = 0; i < n_attributes; i++)
419     {
420       _COGL_RETURN_IF_FAIL (cogl_is_attribute (attributes[i]));
421       cogl_object_ref (attributes[i]);
422     }
423
424   for (i = 0; i < primitive->n_attributes; i++)
425     cogl_object_unref (primitive->attributes[i]);
426
427   /* First try to use the embedded storage assocated with the
428    * primitive, else fallback to slice allocating separate storage for
429    * the attribute pointers... */
430
431   if (n_attributes <= primitive->n_embedded_attributes)
432     {
433       if (primitive->attributes != &primitive->embedded_attribute)
434         g_slice_free1 (sizeof (CoglAttribute *) * primitive->n_attributes,
435                        primitive->attributes);
436       primitive->attributes = &primitive->embedded_attribute;
437     }
438   else
439     {
440       if (primitive->attributes != &primitive->embedded_attribute)
441         g_slice_free1 (sizeof (CoglAttribute *) * primitive->n_attributes,
442                        primitive->attributes);
443       primitive->attributes =
444         g_slice_alloc (sizeof (CoglAttribute *) * n_attributes);
445     }
446
447   memcpy (primitive->attributes, attributes,
448           sizeof (CoglAttribute *) * n_attributes);
449
450   primitive->n_attributes = n_attributes;
451 }
452
453 int
454 cogl_primitive_get_first_vertex (CoglPrimitive *primitive)
455 {
456   _COGL_RETURN_VAL_IF_FAIL (cogl_is_primitive (primitive), 0);
457
458   return primitive->first_vertex;
459 }
460
461 void
462 cogl_primitive_set_first_vertex (CoglPrimitive *primitive,
463                                  int first_vertex)
464 {
465   _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive));
466
467   if (G_UNLIKELY (primitive->immutable_ref))
468     {
469       warn_about_midscene_changes ();
470       return;
471     }
472
473   primitive->first_vertex = first_vertex;
474 }
475
476 int
477 cogl_primitive_get_n_vertices (CoglPrimitive *primitive)
478 {
479   _COGL_RETURN_VAL_IF_FAIL (cogl_is_primitive (primitive), 0);
480
481   return primitive->n_vertices;
482 }
483
484 void
485 cogl_primitive_set_n_vertices (CoglPrimitive *primitive,
486                                int n_vertices)
487 {
488   _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive));
489
490   primitive->n_vertices = n_vertices;
491 }
492
493 CoglVerticesMode
494 cogl_primitive_get_mode (CoglPrimitive *primitive)
495 {
496   _COGL_RETURN_VAL_IF_FAIL (cogl_is_primitive (primitive), 0);
497
498   return primitive->mode;
499 }
500
501 void
502 cogl_primitive_set_mode (CoglPrimitive *primitive,
503                          CoglVerticesMode mode)
504 {
505   _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive));
506
507   if (G_UNLIKELY (primitive->immutable_ref))
508     {
509       warn_about_midscene_changes ();
510       return;
511     }
512
513   primitive->mode = mode;
514 }
515
516 void
517 cogl_primitive_set_indices (CoglPrimitive *primitive,
518                             CoglIndices *indices,
519                             int n_indices)
520 {
521   _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive));
522
523   if (G_UNLIKELY (primitive->immutable_ref))
524     {
525       warn_about_midscene_changes ();
526       return;
527     }
528
529   if (indices)
530     cogl_object_ref (indices);
531   if (primitive->indices)
532     cogl_object_unref (primitive->indices);
533   primitive->indices = indices;
534   primitive->n_vertices = n_indices;
535 }
536
537 CoglIndices *
538 cogl_primitive_get_indices (CoglPrimitive *primitive)
539 {
540   return primitive->indices;
541 }
542
543 CoglPrimitive *
544 cogl_primitive_copy (CoglPrimitive *primitive)
545 {
546   CoglPrimitive *copy;
547
548   copy = cogl_primitive_new_with_attributes (primitive->mode,
549                                              primitive->n_vertices,
550                                              primitive->attributes,
551                                              primitive->n_attributes);
552
553   cogl_primitive_set_indices (copy, primitive->indices, primitive->n_vertices);
554   cogl_primitive_set_first_vertex (copy, primitive->first_vertex);
555
556   return copy;
557 }
558
559 CoglPrimitive *
560 _cogl_primitive_immutable_ref (CoglPrimitive *primitive)
561 {
562   int i;
563
564   _COGL_RETURN_VAL_IF_FAIL (cogl_is_primitive (primitive), NULL);
565
566   primitive->immutable_ref++;
567
568   for (i = 0; i < primitive->n_attributes; i++)
569     _cogl_attribute_immutable_ref (primitive->attributes[i]);
570
571   return primitive;
572 }
573
574 void
575 _cogl_primitive_immutable_unref (CoglPrimitive *primitive)
576 {
577   int i;
578
579   _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive));
580   _COGL_RETURN_IF_FAIL (primitive->immutable_ref > 0);
581
582   primitive->immutable_ref--;
583
584   for (i = 0; i < primitive->n_attributes; i++)
585     _cogl_attribute_immutable_unref (primitive->attributes[i]);
586 }
587
588 void
589 cogl_primitive_foreach_attribute (CoglPrimitive *primitive,
590                                   CoglPrimitiveAttributeCallback callback,
591                                   void *user_data)
592 {
593   int i;
594
595   for (i = 0; i < primitive->n_attributes; i++)
596     if (!callback (primitive, primitive->attributes[i], user_data))
597       break;
598 }