diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 3b49b5945..a909bdf19 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -75,6 +75,7 @@ cogl_public_h = \ $(srcdir)/cogl-index-array.h \ $(srcdir)/cogl-vertex-array.h \ $(srcdir)/cogl-indices.h \ + $(srcdir)/cogl-vertex-attribute.h \ $(srcdir)/cogl.h \ $(NULL) @@ -214,6 +215,8 @@ cogl_sources_c = \ $(srcdir)/cogl-vertex-array.c \ $(srcdir)/cogl-indices-private.h \ $(srcdir)/cogl-indices.c \ + $(srcdir)/cogl-vertex-attribute-private.h \ + $(srcdir)/cogl-vertex-attribute.c \ $(srcdir)/cogl-matrix.c \ $(srcdir)/cogl-vector.c \ $(srcdir)/cogl-matrix-private.h \ diff --git a/cogl/cogl-vertex-attribute-private.h b/cogl/cogl-vertex-attribute-private.h new file mode 100644 index 000000000..9b0d6076b --- /dev/null +++ b/cogl/cogl-vertex-attribute-private.h @@ -0,0 +1,80 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * + * + * Authors: + * Robert Bragg + */ + +#ifndef __COGL_VERTEX_ATTRIBUTE_PRIVATE_H +#define __COGL_VERTEX_ATTRIBUTE_PRIVATE_H + +#include "cogl-object-private.h" +#include "cogl-vertex-attribute.h" + +typedef enum +{ + COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY, + COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY, + COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY, + COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY, + COGL_VERTEX_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY +} CoglVertexAttributeNameID; + +struct _CoglVertexAttribute +{ + CoglObject _parent; + + CoglVertexArray *array; + char *name; + CoglVertexAttributeNameID name_id; + gsize stride; + gsize offset; + int n_components; + CoglVertexAttributeType type; + gboolean normalized; + unsigned int texture_unit; + + int immutable_ref; +}; + +CoglVertexAttribute * +_cogl_vertex_attribute_immutable_ref (CoglVertexAttribute *vertex_attribute); + +void +_cogl_vertex_attribute_immutable_unref (CoglVertexAttribute *vertex_attribute); + +void +_cogl_draw_vertex_attributes_array (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglVertexAttribute **attributes); + +void +_cogl_draw_indexed_vertex_attributes_array (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglIndices *indices, + CoglVertexAttribute **attributes); + +#endif /* __COGL_VERTEX_ATTRIBUTE_PRIVATE_H */ + diff --git a/cogl/cogl-vertex-attribute.c b/cogl/cogl-vertex-attribute.c new file mode 100644 index 000000000..875a7ad79 --- /dev/null +++ b/cogl/cogl-vertex-attribute.c @@ -0,0 +1,882 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * + * + * Authors: + * Robert Bragg + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl-context.h" +#include "cogl-object-private.h" +#include "cogl-journal-private.h" +#include "cogl-vertex-attribute.h" +#include "cogl-vertex-attribute-private.h" +#include "cogl-material.h" +#include "cogl-material-private.h" +#include "cogl-material-opengl-private.h" +#include "cogl-texture-private.h" +#include "cogl-framebuffer-private.h" +#include "cogl-indices-private.h" + +#include +#include + +#if defined (HAVE_COGL_GL) + +#define glGenBuffers ctx->drv.pf_glGenBuffers +#define glBindBuffer ctx->drv.pf_glBindBuffer +#define glBufferData ctx->drv.pf_glBufferData +#define glBufferSubData ctx->drv.pf_glBufferSubData +#define glGetBufferSubData ctx->drv.pf_glGetBufferSubData +#define glDeleteBuffers ctx->drv.pf_glDeleteBuffers +#define glMapBuffer ctx->drv.pf_glMapBuffer +#define glUnmapBuffer ctx->drv.pf_glUnmapBuffer +#define glClientActiveTexture ctx->drv.pf_glClientActiveTexture +#ifndef GL_ARRAY_BUFFER +#define GL_ARRAY_BUFFER GL_ARRAY_BUFFER_ARB +#endif + +#define glVertexAttribPointer ctx->drv.pf_glVertexAttribPointer +#define glEnableVertexAttribArray ctx->drv.pf_glEnableVertexAttribArray +#define glDisableVertexAttribArray ctx->drv.pf_glDisableVertexAttribArray +#define MAY_HAVE_PROGRAMABLE_GL + +#define glDrawRangeElements(mode, start, end, count, type, indices) \ + ctx->drv.pf_glDrawRangeElements (mode, start, end, count, type, indices) + +#else /* GLES 1/2 */ + +/* GLES doesn't have glDrawRangeElements, so we simply pretend it does + * but that it makes no use of the start, end constraints: */ +#define glDrawRangeElements(mode, start, end, count, type, indices) \ + glDrawElements (mode, count, type, indices) + +/* This isn't defined in the GLES headers */ +#ifndef GL_UNSIGNED_INT +#define GL_UNSIGNED_INT 0x1405 +#endif + +#ifdef HAVE_COGL_GLES2 + +#include "../gles/cogl-gles2-wrapper.h" +#define MAY_HAVE_PROGRAMABLE_GL + +#endif /* HAVE_COGL_GLES2 */ + +#endif + +static void _cogl_vertex_attribute_free (CoglVertexAttribute *attribute); + +COGL_OBJECT_DEFINE (VertexAttribute, vertex_attribute); + +#if 0 +gboolean +validate_gl_attribute (const char *name, + int n_components, + CoglVertexAttributeNameID *name_id, + gboolean *normalized, + unsigned int *texture_unit) +{ + name = name + 3; /* skip past "gl_" */ + + *normalized = FALSE; + *texture_unit = 0; + + if (strcmp (name, "Vertex") == 0) + { + if (G_UNLIKELY (n_components == 1)) + { + g_critical ("glVertexPointer doesn't allow 1 component vertex " + "positions so we currently only support \"gl_Vertex\" " + "attributes where n_components == 2, 3 or 4"); + return FALSE; + } + *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY; + } + else if (strcmp (name, "Color") == 0) + { + if (G_UNLIKELY (n_components != 3 && n_components != 4)) + { + g_critical ("glColorPointer expects 3 or 4 component colors so we " + "currently only support \"gl_Color\" attributes where " + "n_components == 3 or 4"); + return FALSE; + } + *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY; + *normalized = TRUE; + } + else if (strncmp (name, "MultiTexCoord", strlen ("MultiTexCoord")) == 0) + { + if (sscanf (gl_attribute, "MultiTexCoord%u", texture_unit) != 1) + { + g_warning ("gl_MultiTexCoord attributes should include a\n" + "texture unit number, E.g. gl_MultiTexCoord0\n"); + unit = 0; + } + *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY; + } + else if (strncmp (name, "Normal") == 0) + { + if (G_UNLIKELY (n_components != 3)) + { + g_critical ("glNormalPointer expects 3 component normals so we " + "currently only support \"gl_Normal\" attributes where " + "n_components == 3"); + return FALSE; + } + *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY; + *normalized = TRUE; + } + else + { + g_warning ("Unknown gl_* attribute name gl_%s\n", name); + return FALSE; + } + + return TRUE; +} +#endif + +gboolean +validate_cogl_attribute (const char *name, + int n_components, + CoglVertexAttributeNameID *name_id, + gboolean *normalized, + unsigned int *texture_unit) +{ + name = name + 5; /* skip "cogl_" */ + + *normalized = FALSE; + *texture_unit = 0; + + if (strcmp (name, "position_in") == 0) + { + if (G_UNLIKELY (n_components == 1)) + { + g_critical ("glVertexPointer doesn't allow 1 component vertex " + "positions so we currently only support \"cogl_vertex\" " + "attributes where n_components == 2, 3 or 4"); + return FALSE; + } + *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY; + } + else if (strcmp (name, "color_in") == 0) + { + if (G_UNLIKELY (n_components != 3 && n_components != 4)) + { + g_critical ("glColorPointer expects 3 or 4 component colors so we " + "currently only support \"cogl_color\" attributes where " + "n_components == 3 or 4"); + return FALSE; + } + *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY; + } + else if (strcmp (name, "tex_coord_in") == 0) + *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY; + else if (strncmp (name, "tex_coord", strlen ("tex_coord")) == 0) + { + if (sscanf (name, "tex_coord%u_in", texture_unit) != 1) + { + g_warning ("Texture coordinate attributes should either be named " + "\"cogl_tex_coord\" or named with a texture unit index " + "like \"cogl_tex_coord2_in\"\n"); + return FALSE; + } + *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY; + } + else if (strcmp (name, "normal") == 0) + { + if (G_UNLIKELY (n_components != 3)) + { + g_critical ("glNormalPointer expects 3 component normals so we " + "currently only support \"cogl_normal\" attributes " + "where n_components == 3"); + return FALSE; + } + *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY; + *normalized = TRUE; + } + else + { + g_warning ("Unknown cogl_* attribute name cogl_%s\n", name); + return FALSE; + } + + return TRUE; +} + +CoglVertexAttribute * +cogl_vertex_attribute_new (CoglVertexArray *array, + const char *name, + gsize stride, + gsize offset, + int n_components, + CoglVertexAttributeType type) +{ + CoglVertexAttribute *attribute = g_slice_new (CoglVertexAttribute); + gboolean status; + + attribute->array = cogl_object_ref (array); + attribute->name = g_strdup (name); + attribute->stride = stride; + attribute->offset = offset; + attribute->n_components = n_components; + attribute->type = type; + attribute->immutable_ref = 0; + + if (strncmp (name, "cogl_", 5) == 0) + status = validate_cogl_attribute (attribute->name, + n_components, + &attribute->name_id, + &attribute->normalized, + &attribute->texture_unit); +#if 0 + else if (strncmp (name, "gl_", 3) == 0) + status = validate_gl_attribute (attribute->name, + n_components, + &attribute->name_id, + &attribute->normalized, + &attribute->texture_unit); +#endif + else + { + attribute->name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY; + attribute->normalized = FALSE; + attribute->texture_unit = 0; + status = TRUE; + } + + if (!status) + { + _cogl_vertex_attribute_free (attribute); + return NULL; + } + + return _cogl_vertex_attribute_object_new (attribute); +} + +gboolean +cogl_vertex_attribute_get_normalized (CoglVertexAttribute *attribute) +{ + g_return_val_if_fail (cogl_is_vertex_attribute (attribute), FALSE); + + return attribute->normalized; +} + +static void +warn_about_midscene_changes (void) +{ + static gboolean seen = FALSE; + if (!seen) + { + g_warning ("Mid-scene modification of attributes has " + "undefined results\n"); + seen = TRUE; + } +} + +void +cogl_vertex_attribute_set_normalized (CoglVertexAttribute *attribute, + gboolean normalized) +{ + g_return_if_fail (cogl_is_vertex_attribute (attribute)); + + if (G_UNLIKELY (attribute->immutable_ref)) + warn_about_midscene_changes (); + + attribute->normalized = normalized; +} + +CoglVertexArray * +cogl_vertex_attribute_get_array (CoglVertexAttribute *attribute) +{ + g_return_val_if_fail (cogl_is_vertex_attribute (attribute), NULL); + + return attribute->array; +} + +void +cogl_vertex_attribute_set_array (CoglVertexAttribute *attribute, + CoglVertexArray *array) +{ + g_return_if_fail (cogl_is_vertex_attribute (attribute)); + + if (G_UNLIKELY (attribute->immutable_ref)) + warn_about_midscene_changes (); + + cogl_object_ref (array); + + cogl_object_unref (attribute->array); + attribute->array = array; +} + +CoglVertexAttribute * +_cogl_vertex_attribute_immutable_ref (CoglVertexAttribute *vertex_attribute) +{ + g_return_val_if_fail (cogl_is_vertex_attribute (vertex_attribute), NULL); + + vertex_attribute->immutable_ref++; + _cogl_buffer_immutable_ref (COGL_BUFFER (vertex_attribute->array)); + return vertex_attribute; +} + +void +_cogl_vertex_attribute_immutable_unref (CoglVertexAttribute *vertex_attribute) +{ + g_return_if_fail (cogl_is_vertex_attribute (vertex_attribute)); + g_return_if_fail (vertex_attribute->immutable_ref > 0); + + vertex_attribute->immutable_ref--; + _cogl_buffer_immutable_unref (COGL_BUFFER (vertex_attribute->array)); +} + +static void +_cogl_vertex_attribute_free (CoglVertexAttribute *attribute) +{ + g_free (attribute->name); + cogl_object_unref (attribute->array); + + g_slice_free (CoglVertexAttribute, attribute); +} + +typedef struct +{ + int unit; + CoglMaterialFlushOptions options; + guint32 fallback_layers; +} ValidateLayerState; + +static gboolean +validate_layer_cb (CoglMaterial *material, + int layer_index, + void *user_data) +{ + CoglHandle texture = + _cogl_material_get_layer_texture (material, layer_index); + ValidateLayerState *state = user_data; + gboolean status = TRUE; + + /* invalid textures will be handled correctly in + * _cogl_material_flush_layers_gl_state */ + if (texture == COGL_INVALID_HANDLE) + goto validated; + + /* Give the texture a chance to know that we're rendering + non-quad shaped primitives. If the texture is in an atlas it + will be migrated */ + _cogl_texture_ensure_non_quad_rendering (texture); + + /* We need to ensure the mipmaps are ready before deciding + * anything else about the texture because the texture storate + * could completely change if it needs to be migrated out of the + * atlas and will affect how we validate the layer. + */ + _cogl_material_pre_paint_for_layer (material, layer_index); + + if (!_cogl_texture_can_hardware_repeat (texture)) + { + g_warning ("Disabling layer %d of the current source material, " + "because texturing with the vertex buffer API is not " + "currently supported using sliced textures, or textures " + "with waste\n", layer_index); + + /* XXX: maybe we can add a mechanism for users to forcibly use + * textures with waste where it would be their responsability to use + * texture coords in the range [0,1] such that sampling outside isn't + * required. We can then use a texture matrix (or a modification of + * the users own matrix) to map 1 to the edge of the texture data. + * + * Potentially, given the same guarantee as above we could also + * support a single sliced layer too. We would have to redraw the + * vertices once for each layer, each time with a fiddled texture + * matrix. + */ + state->fallback_layers |= (1 << state->unit); + state->options.flags |= COGL_MATERIAL_FLUSH_FALLBACK_MASK; + } + +validated: + state->unit++; + return status; +} + +static CoglHandle +enable_gl_state (CoglVertexAttribute **attributes, + ValidateLayerState *state) +{ + int i; +#ifdef MAY_HAVE_PROGRAMABLE_GL + GLuint generic_index = 0; +#endif + unsigned long enable_flags = 0; + gboolean skip_gl_color = FALSE; + CoglMaterial *source; + CoglMaterial *copy = NULL; + + _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); + + /* NB: _cogl_framebuffer_flush_state may disrupt various state (such + * as the material state) when flushing the clip stack, so should + * always be done first when preparing to draw. We need to do this + * before setting up the array pointers because setting up the clip + * stack can cause some drawing which would change the array + * pointers. */ + _cogl_framebuffer_flush_state (_cogl_get_framebuffer (), 0); + + source = cogl_get_source (); + + _cogl_bitmask_clear_all (&ctx->temp_bitmask); + + for (i = 0; attributes[i]; i++) + { + CoglVertexAttribute *attribute = attributes[i]; + CoglVertexArray *vertex_array; + CoglBuffer *buffer; + void *base; + + vertex_array = cogl_vertex_attribute_get_array (attribute); + buffer = COGL_BUFFER (vertex_array); + base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_VERTEX_ARRAY); + + switch (attribute->name_id) + { + case COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY: + enable_flags |= COGL_ENABLE_COLOR_ARRAY; + /* GE (glEnableClientState (GL_COLOR_ARRAY)); */ + GE (glColorPointer (attribute->n_components, + attribute->type, + attribute->stride, + base + attribute->offset)); + + if (!_cogl_material_get_real_blend_enabled (source)) + { + CoglMaterialBlendEnable blend_enable = + COGL_MATERIAL_BLEND_ENABLE_ENABLED; + copy = cogl_material_copy (source); + _cogl_material_set_blend_enabled (copy, blend_enable); + source = copy; + } + skip_gl_color = TRUE; + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY: + /* FIXME: go through cogl cache to enable normal array */ + GE (glEnableClientState (GL_NORMAL_ARRAY)); + GE (glNormalPointer (attribute->type, + attribute->stride, + base + attribute->offset)); + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY: + GE (glClientActiveTexture (GL_TEXTURE0 + + attribute->texture_unit)); + GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); + GE (glTexCoordPointer (attribute->n_components, + attribute->type, + attribute->stride, + base + attribute->offset)); + _cogl_bitmask_set (&ctx->temp_bitmask, + attribute->texture_unit, TRUE); + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY: + enable_flags |= COGL_ENABLE_VERTEX_ARRAY; + /* GE (glEnableClientState (GL_VERTEX_ARRAY)); */ + GE (glVertexPointer (attribute->n_components, + attribute->type, + attribute->stride, + base + attribute->offset)); + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY: + { +#ifdef MAY_HAVE_PROGRAMABLE_GL + /* FIXME: go through cogl cache to enable generic array */ + GE (glEnableVertexAttribArray (generic_index++)); + GE (glVertexAttribPointer (generic_index, + attribute->n_components, + attribute->type, + attribute->normalized, + attribute->stride, + base + attribute->offset)); +#endif + } + break; + default: + g_warning ("Unrecognised attribute type 0x%08x", attribute->type); + } + + _cogl_buffer_unbind (buffer); + } + + /* Disable any tex coord arrays that we didn't use */ + _cogl_disable_other_texcoord_arrays (&ctx->temp_bitmask); + + if (G_UNLIKELY (state->options.flags)) + { + /* If we haven't already created a derived material... */ + if (!copy) + { + copy = cogl_material_copy (source); + source = copy; + } + _cogl_material_apply_overrides (source, &state->options); + + /* TODO: + * overrides = cogl_material_get_data (material, + * last_overrides_key); + * if (overrides) + * { + * age = cogl_material_get_age (material); + * XXX: actually we also need to check for legacy_state + * and blending overrides for use of glColorPointer... + * if (overrides->ags != age || + * memcmp (&overrides->options, &options, + * sizeof (options) != 0) + * { + * cogl_object_unref (overrides->weak_material); + * g_slice_free (Overrides, overrides); + * overrides = NULL; + * } + * } + * if (!overrides) + * { + * overrides = g_slice_new (Overrides); + * overrides->weak_material = + * cogl_material_weak_copy (cogl_get_source ()); + * _cogl_material_apply_overrides (overrides->weak_material, + * &options); + * + * cogl_material_set_data (material, last_overrides_key, + * weak_overrides, + * free_overrides_cb, + * NULL); + * } + * source = overrides->weak_material; + */ + } + + if (G_UNLIKELY (ctx->legacy_state_set)) + { + /* If we haven't already created a derived material... */ + if (!copy) + { + copy = cogl_material_copy (source); + source = copy; + } + _cogl_material_apply_legacy_state (source); + } + + _cogl_material_flush_gl_state (source, skip_gl_color); + + if (ctx->enable_backface_culling) + enable_flags |= COGL_ENABLE_BACKFACE_CULLING; + + _cogl_enable (enable_flags); + _cogl_flush_face_winding (); + + return source; +} + +/* FIXME: we shouldn't be disabling state after drawing we should + * just disable the things not needed after enabling state. */ +static void +disable_gl_state (CoglVertexAttribute **attributes, + CoglMaterial *source) +{ +#ifdef MAY_HAVE_PROGRAMABLE_GL + GLuint generic_index = 0; +#endif + int i; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (G_UNLIKELY (source != cogl_get_source ())) + cogl_object_unref (source); + + for (i = 0; attributes[i]; i++) + { + CoglVertexAttribute *attribute = attributes[i]; + + switch (attribute->name_id) + { + case COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY: + /* GE (glDisableClientState (GL_COLOR_ARRAY)); */ + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY: + /* FIXME: go through cogl cache to enable normal array */ + GE (glDisableClientState (GL_NORMAL_ARRAY)); + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY: + /* The enabled state of the texture coord arrays is + cached in ctx->enabled_texcoord_arrays so we don't + need to do anything here. The array will be disabled + by the next drawing primitive if it is not + required */ + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY: + /* GE (glDisableClientState (GL_VERTEX_ARRAY)); */ + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY: +#ifdef MAY_HAVE_PROGRAMABLE_GL + /* FIXME: go through cogl cache to enable generic array */ + GE (glDisableVertexAttribArray (generic_index++)); +#endif + break; + default: + g_warning ("Unrecognised attribute type 0x%08x", attribute->type); + } + } +} + +static void +_cogl_draw_vertex_attributes_array_real (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglVertexAttribute **attributes, + ValidateLayerState *state) +{ + CoglMaterial *source = enable_gl_state (attributes, state); + + GE (glDrawArrays ((GLenum)mode, first_vertex, n_vertices)); + + /* FIXME: we shouldn't be disabling state after drawing we should + * just disable the things not needed after enabling state. */ + disable_gl_state (attributes, source); +} + +/* This can be used by the CoglJournal to draw attributes skiping + * the implicit journal flush and material validation. */ +void +_cogl_draw_vertex_attributes_array (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglVertexAttribute **attributes) +{ + ValidateLayerState state; + + state.unit = 0; + state.options.flags = 0; + state.fallback_layers = 0; + + _cogl_draw_vertex_attributes_array_real (mode, first_vertex, n_vertices, + attributes, &state); +} + +void +cogl_draw_vertex_attributes_array (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglVertexAttribute **attributes) +{ + ValidateLayerState state; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + _cogl_journal_flush (); + + state.unit = 0; + state.options.flags = 0; + state.fallback_layers = 0; + + cogl_material_foreach_layer (cogl_get_source (), + validate_layer_cb, + &state); + + _cogl_draw_vertex_attributes_array_real (mode, first_vertex, n_vertices, + attributes, &state); +} + +void +cogl_draw_vertex_attributes (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + ...) +{ + va_list ap; + int n_attributes; + CoglVertexAttribute *attribute; + CoglVertexAttribute **attributes; + int i; + + va_start (ap, n_vertices); + for (n_attributes = 0; va_arg (ap, CoglVertexAttribute *); n_attributes++) + ; + va_end (ap); + + attributes = g_alloca (sizeof (CoglVertexAttribute *) * (n_attributes + 1)); + attributes[n_attributes] = NULL; + + va_start (ap, n_vertices); + for (i = 0; (attribute = va_arg (ap, CoglVertexAttribute *)); i++) + attributes[i] = attribute; + va_end (ap); + + cogl_draw_vertex_attributes_array (mode, first_vertex, n_vertices, + attributes); +} + +static size_t +sizeof_index_type (CoglIndicesType type) +{ + switch (type) + { + case COGL_INDICES_TYPE_UNSIGNED_BYTE: + return 1; + case COGL_INDICES_TYPE_UNSIGNED_SHORT: + return 2; + case COGL_INDICES_TYPE_UNSIGNED_INT: + return 4; + } + g_return_val_if_reached (0); +} + +static void +_cogl_draw_indexed_vertex_attributes_array_real (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglIndices *indices, + CoglVertexAttribute **attributes, + ValidateLayerState *state) +{ + CoglMaterial *source = enable_gl_state (attributes, state); + CoglBuffer *buffer; + void *base; + size_t array_offset; + size_t index_size; + GLenum indices_gl_type; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + buffer = COGL_BUFFER (_cogl_indices_get_array (indices)); + base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_INDEX_ARRAY); + array_offset = cogl_indices_get_offset (indices); + index_size = sizeof_index_type (cogl_indices_get_type (indices)); + + switch (cogl_indices_get_type (indices)) + { + case COGL_INDICES_TYPE_UNSIGNED_BYTE: + indices_gl_type = GL_UNSIGNED_BYTE; + break; + case COGL_INDICES_TYPE_UNSIGNED_SHORT: + indices_gl_type = GL_UNSIGNED_SHORT; + break; + case COGL_INDICES_TYPE_UNSIGNED_INT: + indices_gl_type = GL_UNSIGNED_INT; + break; + } + GE (glDrawElements ((GLenum)mode, + n_vertices, + indices_gl_type, + base + array_offset + index_size * first_vertex)); + + _cogl_buffer_unbind (buffer); + + /* FIXME: we shouldn't be disabling state after drawing we should + * just disable the things not needed after enabling state. */ + disable_gl_state (attributes, source); +} + +void +_cogl_draw_indexed_vertex_attributes_array (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglIndices *indices, + CoglVertexAttribute **attributes) +{ + ValidateLayerState state; + + state.unit = 0; + state.options.flags = 0; + state.fallback_layers = 0; + + _cogl_draw_indexed_vertex_attributes_array_real (mode, + first_vertex, + n_vertices, + indices, + attributes, + &state); +} + +void +cogl_draw_indexed_vertex_attributes_array (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglIndices *indices, + CoglVertexAttribute **attributes) +{ + ValidateLayerState state; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + _cogl_journal_flush (); + + state.unit = 0; + state.options.flags = 0; + state.fallback_layers = 0; + + cogl_material_foreach_layer (cogl_get_source (), + validate_layer_cb, + &state); + + _cogl_draw_indexed_vertex_attributes_array_real (mode, + first_vertex, + n_vertices, + indices, + attributes, + &state); +} + +void +cogl_draw_indexed_vertex_attributes (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglIndices *indices, + ...) +{ + va_list ap; + int n_attributes; + CoglVertexAttribute **attributes; + int i; + CoglVertexAttribute *attribute; + + va_start (ap, indices); + for (n_attributes = 0; va_arg (ap, CoglVertexAttribute *); n_attributes++) + ; + va_end (ap); + + attributes = g_alloca (sizeof (CoglVertexAttribute *) * (n_attributes + 1)); + attributes[n_attributes] = NULL; + + va_start (ap, indices); + for (i = 0; (attribute = va_arg (ap, CoglVertexAttribute *)); i++) + attributes[i] = attribute; + va_end (ap); + + cogl_draw_indexed_vertex_attributes_array (mode, + first_vertex, + n_vertices, + indices, + attributes); +} + + diff --git a/cogl/cogl-vertex-attribute.h b/cogl/cogl-vertex-attribute.h new file mode 100644 index 000000000..8545939c2 --- /dev/null +++ b/cogl/cogl-vertex-attribute.h @@ -0,0 +1,205 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + * + * + * Authors: + * Robert Bragg + */ + +#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __COGL_VERTEX_ATTRIBUTE_H__ +#define __COGL_VERTEX_ATTRIBUTE_H__ + +#include +#include + +G_BEGIN_DECLS + +/** + * SECTION:cogl-vertex-attribute + * @short_description: Fuctions for declaring and drawing vertex + * attributes + * + * FIXME + */ + +typedef struct _CoglVertexAttribute CoglVertexAttribute; + +/** + * CoglVertexAttributeType: + * @COGL_VERTEX_ATTRIBUTE_TYPE_BYTE: Data is the same size of a byte + * @COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_BYTE: Data is the same size of an + * unsigned byte + * @COGL_VERTEX_ATTRIBUTE_TYPE_SHORT: Data is the same size of a short integer + * @COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_SHORT: Data is the same size of + * an unsigned short integer + * @COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT: Data is the same size of a float + * + * Data types for the components of a vertex attribute. + * + * Since: 1.4 + * Stability: Unstable + */ +typedef enum { + COGL_VERTEX_ATTRIBUTE_TYPE_BYTE = 0x1400, + COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_BYTE = 0x1401, + COGL_VERTEX_ATTRIBUTE_TYPE_SHORT = 0x1402, + COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_SHORT = 0x1403, + COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT = 0x1406 +} CoglVertexAttributeType; + +/** + * cogl_vertex_attribute_new: + * @array: The #CoglVertexArray containing the actual attribute data + * @name: The name of the attribute (used to reference it from GLSL) + * @stride: The number of bytes to jump to get to the next attribute + * value for the next vertex. (Usually + *
sizeof (MyVertex)
) + * @offset: The byte offset from the start of @array for the first + * attribute value. (Usually + *
offsetof (MyVertex, component0)
+ * @components: The number of components (e.g. 4 for an rgba color or + * 3 for and (x,y,z) position) + * @type: + * + * Describes the layout for a list of vertex attribute values (For + * example, a list of texture coordinates or colors). + * + * The @name is used to access the attribute inside a GLSL vertex + * shader and there are some special names you should use if they are + * applicable: + * + * "cogl_position_in" (used for vertex positions) + * "cogl_color_in" (used for vertex colors) + * "cogl_tex_coord0_in", "cogl_tex_coord1", ... + * (used for vertex texture coordinates) + * "cogl_normal_in" (used for vertex normals) + * + * + * The attribute values corresponding to different vertices can either + * be tightly packed or interleaved with other attribute values. For + * example it's common to define a structure for a single vertex like: + * |[ + * typedef struct + * { + * float x, y, z; /* position attribute */ + * float s, t; /* texture coordinate attribute */ + * } MyVertex; + * ]| + * + * And then create an array of vertex data something like: + * |[ + * MyVertex vertices[100] = { .... } + * ]| + * + * In this case, to describe either the position or texture coordinate + * attribute you have to move
sizeof (MyVertex)
bytes to + * move from one vertex to the next. This is called the attribute + * @stride. If you weren't interleving attributes and you instead had + * a packed array of float x, y pairs then the attribute stride would + * be
(2 * sizeof (float))
. So the @stride is the number of + * bytes to move to find the attribute value of the next vertex. + * + * Normally a list of attributes starts at the beginning of an array. + * So for the
MyVertex
example above the @offset is the + * offset inside the
MyVertex
structure to the first + * component of the attribute. For the texture coordinate attribute + * the offset would be
offsetof (MyVertex, s)
or instead of + * using the offsetof macro you could use
sizeof (float) * 3
. + * If you've divided your @array into blocks of non-interleved + * attributes then you will need to calculate the @offset as the + * number of bytes in blocks preceding the attribute you're + * describing. + * + * An attribute often has more than one component. For example a color + * is often comprised of 4 red, green, blue and alpha @components, and a + * position may be comprised of 2 x and y @components. You should aim + * to keep the number of components to a minimum as more components + * means more data needs to be mapped into the GPU which can be a + * bottlneck when dealing with a large number of vertices. + * + * Finally you need to specify the component data type. Here you + * should aim to use the smallest type that meets your precision + * requirements. Again the larger the type then more data needs to be + * mapped into the GPU which can be a bottlneck when dealing with + * a large number of vertices. + * + * Returns: A newly allocated #CoglVertexAttribute describing the + * layout for a list of attribute values stored in @array. + * + * Since: 1.4 + * Stability: Unstable + */ +/* XXX: look for a precedent to see if the stride/offset args should + * have a different order. */ +CoglVertexAttribute * +cogl_vertex_attribute_new (CoglVertexArray *array, + const char *name, + gsize stride, + gsize offset, + int components, + CoglVertexAttributeType type); + +/** + * cogl_is_vertex_attribute: + * @object: A #CoglObject + * + * Gets whether the given object references a #CoglVertexAttribute. + * + * Return value: %TRUE if the handle references a #CoglVertexAttribute, + * %FALSE otherwise + */ +gboolean +cogl_is_vertex_attribute (void *object); + +void +cogl_draw_vertex_attributes (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + ...) G_GNUC_NULL_TERMINATED; + +void +cogl_draw_vertex_attributes_array (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglVertexAttribute **attributes); + +void +cogl_draw_indexed_vertex_attributes (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglIndices *indices, + ...) G_GNUC_NULL_TERMINATED; + +void +cogl_draw_indexed_vertex_attributes_array (CoglVerticesMode mode, + int first_vertex, + int n_vertices, + CoglIndices *indices, + CoglVertexAttribute **attributes); + +G_END_DECLS + +#endif /* __COGL_VERTEX_ATTRIBUTE_H__ */ + diff --git a/cogl/cogl.h b/cogl/cogl.h index 7b756f86a..21200708b 100644 --- a/cogl/cogl.h +++ b/cogl/cogl.h @@ -57,6 +57,7 @@ #include #include #include +#include #endif G_BEGIN_DECLS