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