diff --git a/clutter/cogl/cogl-vertex-buffer.h b/clutter/cogl/cogl-vertex-buffer.h
index 717281db0..580ecfa10 100644
--- a/clutter/cogl/cogl-vertex-buffer.h
+++ b/clutter/cogl/cogl-vertex-buffer.h
@@ -256,6 +256,54 @@ cogl_vertex_buffer_draw (CoglHandle handle,
GLint first,
GLsizei count);
+/**
+ * CoglIndicesType:
+ * @COGL_INDICES_TYPE_UNSIGNED_BYTE: Your indices are unsigned bytes
+ * @COGL_INDICES_TYPE_UNSIGNED_SHORT: Your indices are unsigned shorts
+ * @COGL_INDICES_TYPE_UNSIGNED_INT: You indices are unsigned integers
+ *
+ * You should aim to use the smallest data type that gives you enough
+ * range, since it reduces the size of your index array and can help
+ * reduce the demand on memory bandwidth.
+ */
+typedef enum _CoglIndicesType
+{
+ COGL_INDICES_TYPE_UNSIGNED_BYTE,
+ COGL_INDICES_TYPE_UNSIGNED_SHORT,
+ COGL_INDICES_TYPE_UNSIGNED_INT
+} CoglIndicesType;
+
+/**
+ * cogl_vertex_buffer_add_indices:
+ * @handle: A vertex buffer handle
+ * @id: Any unique number. It's used to identify the indices when you later
+ * call cogl_vertex_buffer_draw_elements()
+ * @min_index: Specifies the minimum vertex index contained in indices
+ * @max_index: Specifies the maximum vertex index contained in indices
+ * @indices_type: a #CoglIndicesType specifying the data type used for
+ * the indices.
+ * @indices_array: Specifies the address of your array of indices
+ * @indices_len: The number of indices in indices_array
+ *
+ * Depending on how much geometry you are submitting it can be worthwhile
+ * optimizing the number of redundant vertices you submit. Using an index
+ * array allows you to reference vertices multiple times, for example
+ * during triangle strips.
+ *
+ * You should aim to use the COGL_INDICES_TYPE_UNSIGNED_SHORT when possible
+ * and correctly reflect the range of index values in the {min,max}_index
+ * arguments. This allows Cogl to optimize the internal storage used for
+ * the indices and reduce the demand for memory bandwidth.
+ */
+void
+cogl_vertex_buffer_add_indices (CoglHandle handle,
+ int id,
+ unsigned int min_index,
+ unsigned int max_index,
+ CoglIndicesType indices_type,
+ const void *indices_array,
+ size_t indices_len);
+
/**
* cogl_vertex_buffer_draw_elements:
* @handle: A vertex buffer handle
@@ -270,33 +318,26 @@ cogl_vertex_buffer_draw (CoglHandle handle,
* GL_TRIANGLE_FAN
* GL_TRIANGLES
*
- * (Note: only types available in GLES are listed)
- * @min_index: Specifies the minimum vertex index contained in indices
- * @max_index: Specifies the maximum vertex index contained in indices
+ * @indices_id: The identifier for a an array of indices previously added to
+ * the given Cogl vertex buffer using
+ * cogl_vertex_buffer_add_indices().
+ * @indices_offset: An offset into named indices. The offset marks the first
+ * index to use for drawing.
* @count: Specifies the number of vertices you want to draw.
- * @indices_type: Specifies the data type used for the indices, and must be
- * one of:
- *
- * GL_UNSIGNED_BYTE
- * GL_UNSIGNED_SHORT
- * GL_UNSIGNED_INT
- *
- * @indices: Specifies the address of your array of indices
*
* This function lets you use an array of indices to specify the vertices
- * within your vertex buffer that you want to draw.
+ * within your vertex buffer that you want to draw. The indices themselves
+ * are given by calling cogl_vertex_buffer_add_indices ()
*
* Any un-submitted attribute changes are automatically submitted before
* drawing.
*/
void
-cogl_vertex_buffer_draw_elements (CoglHandle handle,
- GLenum mode,
- GLuint min_index,
- GLuint max_index,
- GLsizei count,
- GLenum indices_type,
- const GLvoid *indices);
+cogl_vertex_buffer_draw_elements (CoglHandle handle,
+ GLenum mode,
+ int indices_id,
+ unsigned int indices_offset,
+ unsigned int count);
/**
* cogl_vertex_buffer_ref:
diff --git a/clutter/cogl/common/cogl-vertex-buffer-private.h b/clutter/cogl/common/cogl-vertex-buffer-private.h
index 68a709b54..cc87b1828 100644
--- a/clutter/cogl/common/cogl-vertex-buffer-private.h
+++ b/clutter/cogl/common/cogl-vertex-buffer-private.h
@@ -99,9 +99,9 @@ typedef struct _CoglVertexBufferAttrib
union _u
{
const void *pointer;
- gsize vbo_offset;
+ size_t vbo_offset;
} u;
- gsize span_bytes;
+ size_t span_bytes;
guint16 stride;
guint8 n_components;
guint8 texture_unit;
@@ -129,24 +129,39 @@ typedef struct _CoglVertexBufferVBO
{
CoglVertexBufferVBOFlags flags;
- /* Note: this is a pointer to handle fallbacks, and normally holds
- * a GLuint value */
- gpointer vbo_name; /*!< The name of the corresponding buffer object */
- gsize vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */
+ /* Note: this is a pointer to handle fallbacks. It normally holds
+ * a GLuint VBO name, but when the driver doesn't support VBOs then
+ * this simply points to an malloc'd buffer. */
+ void *vbo_name; /*!< The name of the corresponding buffer object */
+ size_t vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */
GList *attributes;
} CoglVertexBufferVBO;
+typedef struct _CoglVertexBufferIndices
+{
+ int id;
+ /* Note: this is a pointer to handle fallbacks. It normally holds
+ * a GLuint VBO name, but when the driver doesn't support VBOs then
+ * this simply points to an malloc'd buffer. */
+ void *vbo_name;
+ GLenum type;
+ GLuint min_index;
+ GLuint max_index;
+} CoglVertexBufferIndices;
typedef struct _CoglVertexBuffer
{
CoglHandleObject _parent;
- guint n_vertices; /*!< The number of vertices in the buffer */
- GList *submitted_vbos; /* The VBOs currently submitted to the GPU */
+ int n_vertices; /*!< The number of vertices in the buffer */
+ GList *submitted_vbos; /* The VBOs currently submitted to the GPU */
/* Note: new_attributes is normally NULL and only valid while
* modifying a buffer. */
- GList *new_attributes; /*!< attributes pending submission */
+ GList *new_attributes; /*!< attributes pending submission */
+
+ GList *indices; /*!< A list of associated index arrays */
+
} CoglVertexBuffer;
#endif /* __COGL_VERTEX_BUFFER_H */
diff --git a/clutter/cogl/common/cogl-vertex-buffer.c b/clutter/cogl/common/cogl-vertex-buffer.c
index 842551b04..cd450ea93 100644
--- a/clutter/cogl/common/cogl-vertex-buffer.c
+++ b/clutter/cogl/common/cogl-vertex-buffer.c
@@ -214,6 +214,8 @@ cogl_vertex_buffer_new (guint n_vertices)
buffer->submitted_vbos = NULL;
buffer->new_attributes = NULL;
+ buffer->indices = NULL;
+
/* return COGL_INVALID_HANDLE; */
return _cogl_vertex_buffer_handle_new (buffer);
}
@@ -1727,13 +1729,11 @@ cogl_vertex_buffer_draw (CoglHandle handle,
if (!cogl_is_vertex_buffer (handle))
return;
- cogl_clip_ensure ();
-
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
- enable_state_for_drawing_buffer (buffer);
-
+ cogl_clip_ensure ();
_cogl_current_matrix_state_flush ();
+ enable_state_for_drawing_buffer (buffer);
/* FIXME: flush cogl cache */
GE (glDrawArrays (mode, first, count));
@@ -1741,35 +1741,158 @@ cogl_vertex_buffer_draw (CoglHandle handle,
disable_state_for_drawing_buffer (buffer);
}
+static void
+free_vertex_buffer_indices (CoglVertexBufferIndices *indices)
+{
+ gboolean fallback =
+ (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ if (fallback)
+ g_free (indices->vbo_name);
+ else
+ GE (glDeleteBuffers (1, (GLuint *)&indices->vbo_name));
+
+ g_slice_free (CoglVertexBufferIndices, indices);
+}
+
+static int
+get_indices_type_size (GLuint indices_type)
+{
+ if (indices_type == GL_UNSIGNED_BYTE)
+ return sizeof (GLubyte);
+ if (indices_type == GL_UNSIGNED_SHORT)
+ return sizeof (GLushort);
+ else
+ {
+ g_critical ("Unknown indices type %d\n", indices_type);
+ return 0;
+ }
+}
+
void
-cogl_vertex_buffer_draw_elements (CoglHandle handle,
- GLenum mode,
- GLuint min_index,
- GLuint max_index,
- GLsizei count,
- GLenum indices_type,
- const GLvoid *indices)
+cogl_vertex_buffer_add_indices (CoglHandle handle,
+ int id,
+ unsigned int min_index,
+ unsigned int max_index,
+ CoglIndicesType indices_type,
+ const void *indices_array,
+ size_t indices_len)
{
CoglVertexBuffer *buffer;
+ GList *l;
+ gboolean fallback =
+ (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
+ size_t indices_bytes;
+ CoglVertexBufferIndices *indices;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!cogl_is_vertex_buffer (handle))
return;
- cogl_clip_ensure ();
+ buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
+
+ for (l = buffer->indices; l; l = l->next)
+ {
+ CoglVertexBufferIndices *current_indices = l->data;
+ if (current_indices->id == id)
+ {
+ free_vertex_buffer_indices (l->data);
+ buffer->indices = g_list_delete_link (buffer->indices, l);
+ break;
+ }
+ }
+
+ indices = g_slice_alloc (sizeof (CoglVertexBufferIndices));
+ indices->id = id;
+ indices->min_index = min_index;
+ indices->max_index = max_index;
+
+ if (indices_type == COGL_INDICES_TYPE_UNSIGNED_BYTE)
+ indices->type = GL_UNSIGNED_BYTE;
+ else if (indices_type == COGL_INDICES_TYPE_UNSIGNED_SHORT)
+ indices->type = GL_UNSIGNED_SHORT;
+ else
+ {
+ g_critical ("unknown indices type %d", indices_type);
+ g_slice_free (CoglVertexBufferIndices, indices);
+ return;
+ }
+
+ indices_bytes = get_indices_type_size (indices->type) * indices_len;
+ if (fallback)
+ {
+ indices->vbo_name = g_malloc (indices_len);
+ memcpy (indices->vbo_name, indices_array, indices_bytes);
+ }
+ else
+ {
+ GE (glGenBuffers (1, (GLuint *)&indices->vbo_name));
+ GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
+ GPOINTER_TO_UINT (indices->vbo_name)));
+ GE (glBufferData (GL_ELEMENT_ARRAY_BUFFER,
+ indices_bytes,
+ indices_array,
+ GL_STATIC_DRAW));
+ GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0));
+ }
+
+ buffer->indices = g_list_prepend (buffer->indices, indices);
+}
+
+void
+cogl_vertex_buffer_draw_elements (CoglHandle handle,
+ GLenum mode,
+ int indices_id,
+ unsigned int indices_offset,
+ unsigned int count)
+{
+ CoglVertexBuffer *buffer;
+ gboolean fallback =
+ (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
+ size_t byte_offset;
+ GList *l;
+ CoglVertexBufferIndices *indices = NULL;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ if (!cogl_is_vertex_buffer (handle))
+ return;
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
+ cogl_clip_ensure ();
+ _cogl_current_matrix_state_flush ();
enable_state_for_drawing_buffer (buffer);
- _cogl_current_matrix_state_flush ();
+ for (l = buffer->indices; l; l = l->next)
+ {
+ CoglVertexBufferIndices *current_indices = l->data;
+ if (current_indices->id == indices_id)
+ {
+ indices = current_indices;
+ break;
+ }
+ }
+ if (!indices)
+ return;
+
+ byte_offset = indices_offset * get_indices_type_size (indices->type);
+ if (fallback)
+ byte_offset = (size_t)(((char *)indices->vbo_name) + byte_offset);
+ else
+ GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
+ GPOINTER_TO_UINT (indices->vbo_name)));
/* FIXME: flush cogl cache */
- GE (glDrawRangeElements (mode, min_index, max_index,
- count, indices_type, indices));
+ GE (glDrawRangeElements (mode, indices->min_index, indices->max_index,
+ count, indices->type, (void *)byte_offset));
disable_state_for_drawing_buffer (buffer);
+
+ GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0));
}
static void
@@ -1779,8 +1902,16 @@ _cogl_vertex_buffer_free (CoglVertexBuffer *buffer)
for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
cogl_vertex_buffer_vbo_free (tmp->data, TRUE);
+ g_list_free (buffer->submitted_vbos);
+
for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next)
cogl_vertex_buffer_attribute_free (tmp->data);
+ g_list_free (buffer->new_attributes);
+
+ for (tmp = buffer->indices; tmp != NULL; tmp = tmp->next)
+ free_vertex_buffer_indices (tmp->data);
+ g_list_free (buffer->indices);
g_slice_free (CoglVertexBuffer, buffer);
}
+
diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt
index 1041ded78..8b1d5161c 100644
--- a/doc/reference/cogl/cogl-sections.txt
+++ b/doc/reference/cogl/cogl-sections.txt
@@ -307,6 +307,8 @@ cogl_vertex_buffer_submit
cogl_vertex_buffer_disable
cogl_vertex_buffer_enable
cogl_vertex_buffer_draw
+CoglIndicesType
+cogl_vertex_buffer_add_indices
cogl_vertex_buffer_draw_elements
CoglVertexBufferAttribFlags
diff --git a/tests/interactive/test-cogl-vertex-buffer.c b/tests/interactive/test-cogl-vertex-buffer.c
index 903cbfc23..5a0d45e31 100644
--- a/tests/interactive/test-cogl-vertex-buffer.c
+++ b/tests/interactive/test-cogl-vertex-buffer.c
@@ -140,11 +140,9 @@ on_paint (ClutterActor *actor, TestState *state)
cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
cogl_vertex_buffer_draw_elements (state->buffer,
GL_TRIANGLE_STRIP,
- 0,
- (MESH_WIDTH + 1) * (MESH_HEIGHT + 1),
- state->n_static_indices,
- GL_UNSIGNED_SHORT,
- state->static_indices);
+ 0, /* indices identifier */
+ 0, /* indices offset */
+ state->n_static_indices);
}
static void
@@ -220,6 +218,15 @@ init_static_index_arrays (TestState *state)
}
#undef MESH_INDEX
+
+ cogl_vertex_buffer_add_indices (state->buffer,
+ 0, /* identifier */
+ 0, /* min index */
+ (MESH_WIDTH + 1) *
+ (MESH_HEIGHT + 1), /* max index */
+ COGL_INDICES_TYPE_UNSIGNED_SHORT,
+ state->static_indices,
+ state->n_static_indices);
}
static float