1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2010 Intel Corporation.
7  *
8  * Permission is hereby granted, free of charge, to any person
9  * obtaining a copy of this software and associated documentation
10  * files (the "Software"), to deal in the Software without
11  * restriction, including without limitation the rights to use, copy,
12  * modify, merge, publish, distribute, sublicense, and/or sell copies
13  * of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  *
28  *
29  *
30  * Authors:
31  *   Robert Bragg <robert@linux.intel.com>
32  *   Neil Roberts <neil@linux.intel.com>
33  */
34 
35 #include "cogl-config.h"
36 
37 #include "cogl-util.h"
38 #include "cogl-object-private.h"
39 #include "cogl-context-private.h"
40 #include "cogl-indices.h"
41 #include "cogl-indices-private.h"
42 #include "cogl-index-buffer.h"
43 #include "cogl-gtype-private.h"
44 
45 #include <stdarg.h>
46 
47 static void _cogl_indices_free (CoglIndices *indices);
48 
49 COGL_OBJECT_DEFINE (Indices, indices);
50 COGL_GTYPE_DEFINE_CLASS (Indices, indices);
51 
52 static size_t
sizeof_indices_type(CoglIndicesType type)53 sizeof_indices_type (CoglIndicesType type)
54 {
55   switch (type)
56     {
57     case COGL_INDICES_TYPE_UNSIGNED_BYTE:
58       return 1;
59     case COGL_INDICES_TYPE_UNSIGNED_SHORT:
60       return 2;
61     case COGL_INDICES_TYPE_UNSIGNED_INT:
62       return 4;
63     }
64   g_return_val_if_reached (0);
65 }
66 
67 CoglIndices *
cogl_indices_new_for_buffer(CoglIndicesType type,CoglIndexBuffer * buffer,size_t offset)68 cogl_indices_new_for_buffer (CoglIndicesType type,
69                              CoglIndexBuffer *buffer,
70                              size_t offset)
71 {
72   CoglIndices *indices = g_new0 (CoglIndices, 1);
73 
74   indices->buffer = cogl_object_ref (buffer);
75   indices->offset = offset;
76 
77   indices->type = type;
78 
79   indices->immutable_ref = 0;
80 
81   return _cogl_indices_object_new (indices);
82 }
83 
84 CoglIndices *
cogl_indices_new(CoglContext * context,CoglIndicesType type,const void * indices_data,int n_indices)85 cogl_indices_new (CoglContext *context,
86                   CoglIndicesType type,
87                   const void *indices_data,
88                   int n_indices)
89 {
90   size_t buffer_bytes = sizeof_indices_type (type) * n_indices;
91   CoglIndexBuffer *index_buffer = cogl_index_buffer_new (context, buffer_bytes);
92   CoglBuffer *buffer = COGL_BUFFER (index_buffer);
93   CoglIndices *indices;
94   GError *ignore_error = NULL;
95 
96   _cogl_buffer_set_data (buffer,
97                          0,
98                          indices_data,
99                          buffer_bytes,
100                          &ignore_error);
101   if (ignore_error)
102     {
103       g_error_free (ignore_error);
104       cogl_object_unref (index_buffer);
105       return NULL;
106     }
107 
108   indices = cogl_indices_new_for_buffer (type, index_buffer, 0);
109   cogl_object_unref (index_buffer);
110 
111   return indices;
112 }
113 
114 CoglIndexBuffer *
cogl_indices_get_buffer(CoglIndices * indices)115 cogl_indices_get_buffer (CoglIndices *indices)
116 {
117   return indices->buffer;
118 }
119 
120 CoglIndicesType
cogl_indices_get_type(CoglIndices * indices)121 cogl_indices_get_type (CoglIndices *indices)
122 {
123   g_return_val_if_fail (cogl_is_indices (indices),
124                         COGL_INDICES_TYPE_UNSIGNED_BYTE);
125   return indices->type;
126 }
127 
128 size_t
cogl_indices_get_offset(CoglIndices * indices)129 cogl_indices_get_offset (CoglIndices *indices)
130 {
131   g_return_val_if_fail (cogl_is_indices (indices), 0);
132 
133   return indices->offset;
134 }
135 
136 static void
warn_about_midscene_changes(void)137 warn_about_midscene_changes (void)
138 {
139   static gboolean seen = FALSE;
140   if (!seen)
141     {
142       g_warning ("Mid-scene modification of indices has "
143                  "undefined results\n");
144       seen = TRUE;
145     }
146 }
147 
148 void
cogl_indices_set_offset(CoglIndices * indices,size_t offset)149 cogl_indices_set_offset (CoglIndices *indices,
150                          size_t offset)
151 {
152   g_return_if_fail (cogl_is_indices (indices));
153 
154   if (G_UNLIKELY (indices->immutable_ref))
155     warn_about_midscene_changes ();
156 
157   indices->offset = offset;
158 }
159 
160 static void
_cogl_indices_free(CoglIndices * indices)161 _cogl_indices_free (CoglIndices *indices)
162 {
163   cogl_object_unref (indices->buffer);
164   g_free (indices);
165 }
166 
167 CoglIndices *
_cogl_indices_immutable_ref(CoglIndices * indices)168 _cogl_indices_immutable_ref (CoglIndices *indices)
169 {
170   g_return_val_if_fail (cogl_is_indices (indices), NULL);
171 
172   indices->immutable_ref++;
173   _cogl_buffer_immutable_ref (COGL_BUFFER (indices->buffer));
174   return indices;
175 }
176 
177 void
_cogl_indices_immutable_unref(CoglIndices * indices)178 _cogl_indices_immutable_unref (CoglIndices *indices)
179 {
180   g_return_if_fail (cogl_is_indices (indices));
181   g_return_if_fail (indices->immutable_ref > 0);
182 
183   indices->immutable_ref--;
184   _cogl_buffer_immutable_unref (COGL_BUFFER (indices->buffer));
185 }
186 
187 CoglIndices *
cogl_get_rectangle_indices(CoglContext * ctx,int n_rectangles)188 cogl_get_rectangle_indices (CoglContext *ctx, int n_rectangles)
189 {
190   int n_indices = n_rectangles * 6;
191 
192   /* Check if the largest index required will fit in a byte array... */
193   if (n_indices <= 256 / 4 * 6)
194     {
195       /* Generate the byte array if we haven't already */
196       if (ctx->rectangle_byte_indices == NULL)
197         {
198           uint8_t *byte_array = g_malloc (256 / 4 * 6 * sizeof (uint8_t));
199           uint8_t *p = byte_array;
200           int i, vert_num = 0;
201 
202           for (i = 0; i < 256 / 4; i++)
203             {
204               *(p++) = vert_num + 0;
205               *(p++) = vert_num + 1;
206               *(p++) = vert_num + 2;
207               *(p++) = vert_num + 0;
208               *(p++) = vert_num + 2;
209               *(p++) = vert_num + 3;
210               vert_num += 4;
211             }
212 
213           ctx->rectangle_byte_indices
214             = cogl_indices_new (ctx,
215                                 COGL_INDICES_TYPE_UNSIGNED_BYTE,
216                                 byte_array,
217                                 256 / 4 * 6);
218 
219           g_free (byte_array);
220         }
221 
222       return ctx->rectangle_byte_indices;
223     }
224   else
225     {
226       if (ctx->rectangle_short_indices_len < n_indices)
227         {
228           uint16_t *short_array;
229           uint16_t *p;
230           int i, vert_num = 0;
231 
232           if (ctx->rectangle_short_indices != NULL)
233             cogl_object_unref (ctx->rectangle_short_indices);
234           /* Pick a power of two >= MAX (512, n_indices) */
235           if (ctx->rectangle_short_indices_len == 0)
236             ctx->rectangle_short_indices_len = 512;
237           while (ctx->rectangle_short_indices_len < n_indices)
238             ctx->rectangle_short_indices_len *= 2;
239 
240           /* Over-allocate to generate a whole number of quads */
241           p = short_array = g_malloc ((ctx->rectangle_short_indices_len
242                                        + 5) / 6 * 6
243                                       * sizeof (uint16_t));
244 
245           /* Fill in the complete quads */
246           for (i = 0; i < ctx->rectangle_short_indices_len; i += 6)
247             {
248               *(p++) = vert_num + 0;
249               *(p++) = vert_num + 1;
250               *(p++) = vert_num + 2;
251               *(p++) = vert_num + 0;
252               *(p++) = vert_num + 2;
253               *(p++) = vert_num + 3;
254               vert_num += 4;
255             }
256 
257           ctx->rectangle_short_indices
258             = cogl_indices_new (ctx,
259                                 COGL_INDICES_TYPE_UNSIGNED_SHORT,
260                                 short_array,
261                                 ctx->rectangle_short_indices_len);
262 
263           g_free (short_array);
264         }
265 
266       return ctx->rectangle_short_indices;
267     }
268 }
269 
270