[cogl/cogl-1.14: 75/174] attribute: Adds support for constant CoglAttributes



commit 6e379fb54ef0a6539dc175e1af1bb4200743c856
Author: Robert Bragg <robert linux intel com>
Date:   Mon Aug 6 21:19:27 2012 +0100

    attribute: Adds support for constant CoglAttributes
    
    This makes it possible to create vertex attributes that efficiently
    represent constant values without duplicating the constant for every
    vertex. This adds the following new constructors for constant
    attributes:
    
      cogl_attribute_new_const_1f
      cogl_attribute_new_const_2fv
      cogl_attribute_new_const_3fv
      cogl_attribute_new_const_4fv
      cogl_attribute_new_const_2f
      cogl_attribute_new_const_3f
      cogl_attribute_new_const_4f
      cogl_attribute_new_const_2x2fv
      cogl_attribute_new_const_3x3fv
      cogl_attribute_new_const_4x4fv
    
    Reviewed-by: Neil Roberts <neil linux intel com>
    
    (cherry picked from commit 6507216f8030e84dcf2e63b8ecfe906ac47f2ca7)

 cogl/cogl-attribute-private.h             |   22 ++-
 cogl/cogl-attribute.c                     |  316 ++++++++++++++++++++++++-----
 cogl/cogl-attribute.h                     |  311 ++++++++++++++++++++++++++++
 cogl/driver/gl/cogl-attribute-gl.c        |  275 +++++++++++++++++--------
 cogl/gl-prototypes/cogl-fixed-functions.h |    8 +
 5 files changed, 790 insertions(+), 142 deletions(-)
---
diff --git a/cogl/cogl-attribute-private.h b/cogl/cogl-attribute-private.h
index beb5609..d38f4e6 100644
--- a/cogl/cogl-attribute-private.h
+++ b/cogl/cogl-attribute-private.h
@@ -32,6 +32,7 @@
 #include "cogl-attribute.h"
 #include "cogl-framebuffer.h"
 #include "cogl-pipeline-private.h"
+#include "cogl-boxed-value.h"
 
 typedef enum
 {
@@ -55,14 +56,25 @@ struct _CoglAttribute
 {
   CoglObject _parent;
 
-  CoglAttributeBuffer *attribute_buffer;
   const CoglAttributeNameState *name_state;
-  size_t stride;
-  size_t offset;
-  int n_components;
-  CoglAttributeType type;
   CoglBool normalized;
 
+  CoglBool is_buffered;
+
+  union {
+    struct {
+      CoglAttributeBuffer *attribute_buffer;
+      size_t stride;
+      size_t offset;
+      int n_components;
+      CoglAttributeType type;
+    } buffered;
+    struct {
+      CoglContext *context;
+      CoglBoxedValue boxed;
+    } constant;
+  } d;
+
   int immutable_ref;
 };
 
diff --git a/cogl/cogl-attribute.c b/cogl/cogl-attribute.c
index edcfb83..81a7578 100644
--- a/cogl/cogl-attribute.c
+++ b/cogl/cogl-attribute.c
@@ -158,6 +158,48 @@ error:
   return NULL;
 }
 
+static CoglBool
+validate_n_components (const CoglAttributeNameState *name_state,
+                       int n_components)
+{
+  switch (name_state->name_id)
+    {
+    case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
+      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;
+        }
+      break;
+    case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
+      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;
+        }
+      break;
+    case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
+      break;
+    case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
+      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;
+        }
+      break;
+    case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
+      return TRUE;
+    }
+
+  return TRUE;
+}
+
 CoglAttribute *
 cogl_attribute_new (CoglAttributeBuffer *attribute_buffer,
                     const char *name,
@@ -167,9 +209,10 @@ cogl_attribute_new (CoglAttributeBuffer *attribute_buffer,
                     CoglAttributeType type)
 {
   CoglAttribute *attribute = g_slice_new (CoglAttribute);
+  CoglBuffer *buffer = COGL_BUFFER (attribute_buffer);
+  CoglContext *ctx = buffer->context;
 
-  /* FIXME: retrieve the context from the buffer */
-  _COGL_GET_CONTEXT (ctx, NULL);
+  attribute->is_buffered = TRUE;
 
   attribute->name_state =
     g_hash_table_lookup (ctx->attribute_name_states_hash, name);
@@ -181,50 +224,21 @@ cogl_attribute_new (CoglAttributeBuffer *attribute_buffer,
         goto error;
       attribute->name_state = name_state;
     }
-  attribute->attribute_buffer = cogl_object_ref (attribute_buffer);
-  attribute->stride = stride;
-  attribute->offset = offset;
-  attribute->n_components = n_components;
-  attribute->type = type;
+
+  attribute->d.buffered.attribute_buffer = cogl_object_ref (attribute_buffer);
+  attribute->d.buffered.stride = stride;
+  attribute->d.buffered.offset = offset;
+  attribute->d.buffered.n_components = n_components;
+  attribute->d.buffered.type = type;
+
   attribute->immutable_ref = 0;
 
   if (attribute->name_state->name_id != COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY)
     {
-      switch (attribute->name_state->name_id)
-        {
-        case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
-          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;
-            }
-          break;
-        case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
-          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;
-            }
-          break;
-        case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
-          break;
-        case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
-          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;
-            }
-          break;
-        default:
-          g_warn_if_reached ();
-        }
-      attribute->normalized = attribute->name_state->normalized_default;
+      if (!validate_n_components (attribute->name_state, n_components))
+        return NULL;
+      attribute->normalized =
+        attribute->name_state->normalized_default;
     }
   else
     attribute->normalized = FALSE;
@@ -236,6 +250,206 @@ error:
   return NULL;
 }
 
+static CoglAttribute *
+_cogl_attribute_new_const (CoglContext *context,
+                           const char *name,
+                           int n_components,
+                           int n_columns,
+                           CoglBool transpose,
+                           const float *value)
+{
+  CoglAttribute *attribute = g_slice_new (CoglAttribute);
+
+  attribute->name_state =
+    g_hash_table_lookup (context->attribute_name_states_hash, name);
+  if (!attribute->name_state)
+    {
+      CoglAttributeNameState *name_state =
+        _cogl_attribute_register_attribute_name (context, name);
+      if (!name_state)
+        goto error;
+      attribute->name_state = name_state;
+    }
+
+  if (!validate_n_components (attribute->name_state, n_components))
+    goto error;
+
+  attribute->is_buffered = FALSE;
+  attribute->normalized = FALSE;
+
+  attribute->d.constant.context = cogl_object_ref (context);
+
+  attribute->d.constant.boxed.v.array = NULL;
+
+  if (n_columns == 1)
+    {
+      _cogl_boxed_value_set_float (&attribute->d.constant.boxed,
+                                   n_components,
+                                   1,
+                                   value);
+    }
+  else
+    {
+      /* FIXME: Up until GL[ES] 3 only square matrices were supported
+       * and we don't currently expose non-square matrices in Cogl.
+       */
+      _COGL_RETURN_VAL_IF_FAIL (n_columns == n_components, NULL);
+      _cogl_boxed_value_set_matrix (&attribute->d.constant.boxed,
+                                    n_columns,
+                                    1,
+                                    transpose,
+                                    value);
+    }
+
+  return _cogl_attribute_object_new (attribute);
+
+error:
+  _cogl_attribute_free (attribute);
+  return NULL;
+}
+
+CoglAttribute *
+cogl_attribute_new_const_1f (CoglContext *context,
+                             const char *name,
+                             float value)
+{
+  return _cogl_attribute_new_const (context,
+                                    name,
+                                    1, /* n_components */
+                                    1, /* 1 column vector */
+                                    FALSE, /* no transpose */
+                                    &value);
+}
+
+CoglAttribute *
+cogl_attribute_new_const_2fv (CoglContext *context,
+                              const char *name,
+                              const float *value)
+{
+  return _cogl_attribute_new_const (context,
+                                    name,
+                                    2, /* n_components */
+                                    1, /* 1 column vector */
+                                    FALSE, /* no transpose */
+                                    value);
+}
+
+CoglAttribute *
+cogl_attribute_new_const_3fv (CoglContext *context,
+                              const char *name,
+                              const float *value)
+{
+  return _cogl_attribute_new_const (context,
+                                    name,
+                                    3, /* n_components */
+                                    1, /* 1 column vector */
+                                    FALSE, /* no transpose */
+                                    value);
+}
+
+CoglAttribute *
+cogl_attribute_new_const_4fv (CoglContext *context,
+                              const char *name,
+                              const float *value)
+{
+  return _cogl_attribute_new_const (context,
+                                    name,
+                                    4, /* n_components */
+                                    1, /* 1 column vector */
+                                    FALSE, /* no transpose */
+                                    value);
+}
+
+CoglAttribute *
+cogl_attribute_new_const_2f (CoglContext *context,
+                             const char *name,
+                             float component0,
+                             float component1)
+{
+  float vec2[2] = { component0, component1 };
+  return _cogl_attribute_new_const (context,
+                                    name,
+                                    2, /* n_components */
+                                    1, /* 1 column vector */
+                                    FALSE, /* no transpose */
+                                    vec2);
+}
+
+CoglAttribute *
+cogl_attribute_new_const_3f (CoglContext *context,
+                             const char *name,
+                             float component0,
+                             float component1,
+                             float component2)
+{
+  float vec3[3] = { component0, component1, component2 };
+  return _cogl_attribute_new_const (context,
+                                    name,
+                                    3, /* n_components */
+                                    1, /* 1 column vector */
+                                    FALSE, /* no transpose */
+                                    vec3);
+}
+
+CoglAttribute *
+cogl_attribute_new_const_4f (CoglContext *context,
+                             const char *name,
+                             float component0,
+                             float component1,
+                             float component2,
+                             float component3)
+{
+  float vec4[4] = { component0, component1, component2, component3 };
+  return _cogl_attribute_new_const (context,
+                                    name,
+                                    4, /* n_components */
+                                    1, /* 1 column vector */
+                                    FALSE, /* no transpose */
+                                    vec4);
+}
+
+CoglAttribute *
+cogl_attribute_new_const_2x2fv (CoglContext *context,
+                                const char *name,
+                                const float *matrix2x2,
+                                CoglBool transpose)
+{
+  return _cogl_attribute_new_const (context,
+                                    name,
+                                    2, /* n_components */
+                                    2, /* 2 column vector */
+                                    FALSE, /* no transpose */
+                                    matrix2x2);
+}
+
+CoglAttribute *
+cogl_attribute_new_const_3x3fv (CoglContext *context,
+                                const char *name,
+                                const float *matrix3x3,
+                                CoglBool transpose)
+{
+  return _cogl_attribute_new_const (context,
+                                    name,
+                                    3, /* n_components */
+                                    3, /* 3 column vector */
+                                    FALSE, /* no transpose */
+                                    matrix3x3);
+}
+
+CoglAttribute *
+cogl_attribute_new_const_4x4fv (CoglContext *context,
+                                const char *name,
+                                const float *matrix4x4,
+                                CoglBool transpose)
+{
+  return _cogl_attribute_new_const (context,
+                                    name,
+                                    4, /* n_components */
+                                    4, /* 4 column vector */
+                                    FALSE, /* no transpose */
+                                    matrix4x4);
+}
+
 CoglBool
 cogl_attribute_get_normalized (CoglAttribute *attribute)
 {
@@ -272,8 +486,9 @@ CoglAttributeBuffer *
 cogl_attribute_get_buffer (CoglAttribute *attribute)
 {
   _COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), NULL);
+  _COGL_RETURN_VAL_IF_FAIL (attribute->is_buffered, NULL);
 
-  return attribute->attribute_buffer;
+  return attribute->d.buffered.attribute_buffer;
 }
 
 void
@@ -281,40 +496,45 @@ cogl_attribute_set_buffer (CoglAttribute *attribute,
                            CoglAttributeBuffer *attribute_buffer)
 {
   _COGL_RETURN_IF_FAIL (cogl_is_attribute (attribute));
+  _COGL_RETURN_IF_FAIL (attribute->is_buffered);
 
   if (G_UNLIKELY (attribute->immutable_ref))
     warn_about_midscene_changes ();
 
   cogl_object_ref (attribute_buffer);
 
-  cogl_object_unref (attribute->attribute_buffer);
-  attribute->attribute_buffer = attribute_buffer;
+  cogl_object_unref (attribute->d.buffered.attribute_buffer);
+  attribute->d.buffered.attribute_buffer = attribute_buffer;
 }
 
 CoglAttribute *
 _cogl_attribute_immutable_ref (CoglAttribute *attribute)
 {
+  CoglBuffer *buffer = COGL_BUFFER (attribute->d.buffered.attribute_buffer);
+
   _COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), NULL);
 
   attribute->immutable_ref++;
-  _cogl_buffer_immutable_ref (COGL_BUFFER (attribute->attribute_buffer));
+  _cogl_buffer_immutable_ref (buffer);
   return attribute;
 }
 
 void
 _cogl_attribute_immutable_unref (CoglAttribute *attribute)
 {
+  CoglBuffer *buffer = COGL_BUFFER (attribute->d.buffered.attribute_buffer);
+
   _COGL_RETURN_IF_FAIL (cogl_is_attribute (attribute));
   _COGL_RETURN_IF_FAIL (attribute->immutable_ref > 0);
 
   attribute->immutable_ref--;
-  _cogl_buffer_immutable_unref (COGL_BUFFER (attribute->attribute_buffer));
+  _cogl_buffer_immutable_unref (buffer);
 }
 
 static void
 _cogl_attribute_free (CoglAttribute *attribute)
 {
-  cogl_object_unref (attribute->attribute_buffer);
+  cogl_object_unref (attribute->d.buffered.attribute_buffer);
 
   g_slice_free (CoglAttribute, attribute);
 }
diff --git a/cogl/cogl-attribute.h b/cogl/cogl-attribute.h
index 129d4ce..580446e 100644
--- a/cogl/cogl-attribute.h
+++ b/cogl/cogl-attribute.h
@@ -142,6 +142,317 @@ cogl_attribute_new (CoglAttributeBuffer *attribute_buffer,
                     CoglAttributeType type);
 
 /**
+ * cogl_attribute_new_const_1f:
+ * @context: A #CoglContext
+ * @name: The name of the attribute (used to reference it from GLSL)
+ * @value: The constant value for the attribute
+ *
+ * Creates a new, single component, attribute whose value remains
+ * constant across all the vertices of a primitive without needing to
+ * duplicate the value for each vertex.
+ *
+ * The constant @value is a single precision floating point scalar
+ * which should have a corresponding declaration in GLSL code like:
+ *
+ * [|
+ * attribute float name;
+ * |]
+ *
+ * Returns: A newly allocated #CoglAttribute representing the given
+ *          constant @value.
+ */
+CoglAttribute *
+cogl_attribute_new_const_1f (CoglContext *context,
+                             const char *name,
+                             float value);
+
+/**
+ * cogl_attribute_new_const_2f:
+ * @context: A #CoglContext
+ * @name: The name of the attribute (used to reference it from GLSL)
+ * @constant0: The first component of a 2 component vector
+ * @constant1: The second component of a 2 component vector
+ *
+ * Creates a new, 2 component, attribute whose value remains
+ * constant across all the vertices of a primitive without needing to
+ * duplicate the value for each vertex.
+ *
+ * The constants (@component0, @component1) represent a 2 component
+ * float vector which should have a corresponding declaration in GLSL
+ * code like:
+ *
+ * [|
+ * attribute vec2 name;
+ * |]
+ *
+ * Returns: A newly allocated #CoglAttribute representing the given
+ *          constant vector.
+ */
+CoglAttribute *
+cogl_attribute_new_const_2f (CoglContext *context,
+                             const char *name,
+                             float component0,
+                             float component1);
+
+/**
+ * cogl_attribute_new_const_3f:
+ * @context: A #CoglContext
+ * @name: The name of the attribute (used to reference it from GLSL)
+ * @constant0: The first component of a 3 component vector
+ * @constant1: The second component of a 3 component vector
+ * @constant2: The third component of a 3 component vector
+ *
+ * Creates a new, 3 component, attribute whose value remains
+ * constant across all the vertices of a primitive without needing to
+ * duplicate the value for each vertex.
+ *
+ * The constants (@component0, @component1, @component2) represent a 3
+ * component float vector which should have a corresponding
+ * declaration in GLSL code like:
+ *
+ * [|
+ * attribute vec3 name;
+ * |]
+ *
+ * unless the built in name "cogl_normal_in" is being used where no
+ * explicit GLSL declaration need be made.
+ *
+ * Returns: A newly allocated #CoglAttribute representing the given
+ *          constant vector.
+ */
+CoglAttribute *
+cogl_attribute_new_const_3f (CoglContext *context,
+                             const char *name,
+                             float component0,
+                             float component1,
+                             float component2);
+
+/**
+ * cogl_attribute_new_const_4f:
+ * @context: A #CoglContext
+ * @name: The name of the attribute (used to reference it from GLSL)
+ * @constant0: The first component of a 4 component vector
+ * @constant1: The second component of a 4 component vector
+ * @constant2: The third component of a 4 component vector
+ * @constant3: The fourth component of a 4 component vector
+ *
+ * Creates a new, 4 component, attribute whose value remains
+ * constant across all the vertices of a primitive without needing to
+ * duplicate the value for each vertex.
+ *
+ * The constants (@component0, @component1, @component2, @constant3)
+ * represent a 4 component float vector which should have a
+ * corresponding declaration in GLSL code like:
+ *
+ * [|
+ * attribute vec4 name;
+ * |]
+ *
+ * unless one of the built in names "cogl_color_in",
+ * "cogl_tex_coord0_in or "cogl_tex_coord1_in" etc is being used where
+ * no explicit GLSL declaration need be made.
+ *
+ * Returns: A newly allocated #CoglAttribute representing the given
+ *          constant vector.
+ */
+CoglAttribute *
+cogl_attribute_new_const_4f (CoglContext *context,
+                             const char *name,
+                             float component0,
+                             float component1,
+                             float component2,
+                             float component3);
+
+/**
+ * cogl_attribute_new_const_2fv:
+ * @context: A #CoglContext
+ * @name: The name of the attribute (used to reference it from GLSL)
+ * @value: A pointer to a 2 component float vector
+ *
+ * Creates a new, 2 component, attribute whose value remains
+ * constant across all the vertices of a primitive without needing to
+ * duplicate the value for each vertex.
+ *
+ * The constants (value[0], value[1]) represent a 2 component float
+ * vector which should have a corresponding declaration in GLSL code
+ * like:
+ *
+ * [|
+ * attribute vec2 name;
+ * |]
+ *
+ * Returns: A newly allocated #CoglAttribute representing the given
+ *          constant vector.
+ */
+CoglAttribute *
+cogl_attribute_new_const_2fv (CoglContext *context,
+                              const char *name,
+                              const float *value);
+
+/**
+ * cogl_attribute_new_const_3fv:
+ * @context: A #CoglContext
+ * @name: The name of the attribute (used to reference it from GLSL)
+ * @value: A pointer to a 3 component float vector
+ *
+ * Creates a new, 3 component, attribute whose value remains
+ * constant across all the vertices of a primitive without needing to
+ * duplicate the value for each vertex.
+ *
+ * The constants (value[0], value[1], value[2]) represent a 3
+ * component float vector which should have a corresponding
+ * declaration in GLSL code like:
+ *
+ * [|
+ * attribute vec3 name;
+ * |]
+ *
+ * unless the built in name "cogl_normal_in" is being used where no
+ * explicit GLSL declaration need be made.
+ *
+ * Returns: A newly allocated #CoglAttribute representing the given
+ *          constant vector.
+ */
+CoglAttribute *
+cogl_attribute_new_const_3fv (CoglContext *context,
+                              const char *name,
+                              const float *value);
+
+/**
+ * cogl_attribute_new_const_4fv:
+ * @context: A #CoglContext
+ * @name: The name of the attribute (used to reference it from GLSL)
+ * @value: A pointer to a 4 component float vector
+ *
+ * Creates a new, 4 component, attribute whose value remains
+ * constant across all the vertices of a primitive without needing to
+ * duplicate the value for each vertex.
+ *
+ * The constants (value[0], value[1], value[2], value[3]) represent a
+ * 4 component float vector which should have a corresponding
+ * declaration in GLSL code like:
+ *
+ * [|
+ * attribute vec4 name;
+ * |]
+ *
+ * unless one of the built in names "cogl_color_in",
+ * "cogl_tex_coord0_in or "cogl_tex_coord1_in" etc is being used where
+ * no explicit GLSL declaration need be made.
+ *
+ * Returns: A newly allocated #CoglAttribute representing the given
+ *          constant vector.
+ */
+CoglAttribute *
+cogl_attribute_new_const_4fv (CoglContext *context,
+                              const char *name,
+                              const float *value);
+
+/**
+ * cogl_attribute_new_const_2x2fv:
+ * @context: A #CoglContext
+ * @name: The name of the attribute (used to reference it from GLSL)
+ * @matrix2x2: A pointer to a 2 by 2 matrix
+ * @transpose: Whether the matrix should be transposed on upload or
+ *             not
+ *
+ * Creates a new matrix attribute whose value remains constant
+ * across all the vertices of a primitive without needing to duplicate
+ * the value for each vertex.
+ *
+ * @matrix2x2 represent a square 2 by 2 matrix specified in
+ * column-major order (each pair of consecutive numbers represents a
+ * column) which should have a corresponding declaration in GLSL code
+ * like:
+ *
+ * [|
+ * attribute mat2 name;
+ * |]
+ *
+ * If @transpose is %TRUE then all matrix components are rotated
+ * around the diagonal of the matrix such that the first column
+ * becomes the first row and the second column becomes the second row.
+ *
+ * Returns: A newly allocated #CoglAttribute representing the given
+ *          constant matrix.
+ */
+CoglAttribute *
+cogl_attribute_new_const_2x2fv (CoglContext *context,
+                                const char *name,
+                                const float *matrix2x2,
+                                CoglBool transpose);
+
+/**
+ * cogl_attribute_new_const_3x3fv:
+ * @context: A #CoglContext
+ * @name: The name of the attribute (used to reference it from GLSL)
+ * @matrix3x3: A pointer to a 3 by 3 matrix
+ * @transpose: Whether the matrix should be transposed on upload or
+ *             not
+ *
+ * Creates a new matrix attribute whose value remains constant
+ * across all the vertices of a primitive without needing to duplicate
+ * the value for each vertex.
+ *
+ * @matrix3x3 represent a square 3 by 3 matrix specified in
+ * column-major order (each triple of consecutive numbers represents a
+ * column) which should have a corresponding declaration in GLSL code
+ * like:
+ *
+ * [|
+ * attribute mat3 name;
+ * |]
+ *
+ * If @transpose is %TRUE then all matrix components are rotated
+ * around the diagonal of the matrix such that the first column
+ * becomes the first row and the second column becomes the second row
+ * etc.
+ *
+ * Returns: A newly allocated #CoglAttribute representing the given
+ *          constant matrix.
+ */
+CoglAttribute *
+cogl_attribute_new_const_3x3fv (CoglContext *context,
+                                const char *name,
+                                const float *matrix3x3,
+                                CoglBool transpose);
+
+/**
+ * cogl_attribute_new_const_4x4fv:
+ * @context: A #CoglContext
+ * @name: The name of the attribute (used to reference it from GLSL)
+ * @matrix4x4: A pointer to a 4 by 4 matrix
+ * @transpose: Whether the matrix should be transposed on upload or
+ *             not
+ *
+ * Creates a new matrix attribute whose value remains constant
+ * across all the vertices of a primitive without needing to duplicate
+ * the value for each vertex.
+ *
+ * @matrix4x4 represent a square 4 by 4 matrix specified in
+ * column-major order (each 4-tuple of consecutive numbers represents a
+ * column) which should have a corresponding declaration in GLSL code
+ * like:
+ *
+ * [|
+ * attribute mat4 name;
+ * |]
+ *
+ * If @transpose is %TRUE then all matrix components are rotated
+ * around the diagonal of the matrix such that the first column
+ * becomes the first row and the second column becomes the second row
+ * etc.
+ *
+ * Returns: A newly allocated #CoglAttribute representing the given
+ *          constant matrix.
+ */
+CoglAttribute *
+cogl_attribute_new_const_4x4fv (CoglContext *context,
+                                const char *name,
+                                const float *matrix4x4,
+                                CoglBool transpose);
+
+/**
  * cogl_attribute_set_normalized:
  * @attribute: A #CoglAttribute
  * @normalized: The new value for the normalized property.
diff --git a/cogl/driver/gl/cogl-attribute-gl.c b/cogl/driver/gl/cogl-attribute-gl.c
index ce90e4a..9210b95 100644
--- a/cogl/driver/gl/cogl-attribute-gl.c
+++ b/cogl/driver/gl/cogl-attribute-gl.c
@@ -152,30 +152,188 @@ foreach_changed_bit_and_save (CoglContext *context,
 #ifdef COGL_PIPELINE_PROGEND_GLSL
 
 static void
-setup_generic_attribute (CoglContext *context,
-                         CoglPipeline *pipeline,
-                         CoglAttribute *attribute,
-                         uint8_t *base)
+setup_generic_buffered_attribute (CoglContext *context,
+                                  CoglPipeline *pipeline,
+                                  CoglAttribute *attribute,
+                                  uint8_t *base)
 {
   int name_index = attribute->name_state->name_index;
   int attrib_location =
     _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index);
-  if (attrib_location != -1)
+
+  if (attrib_location == -1)
+    return;
+
+  GE( context, glVertexAttribPointer (attrib_location,
+                                      attribute->d.buffered.n_components,
+                                      attribute->d.buffered.type,
+                                      attribute->normalized,
+                                      attribute->d.buffered.stride,
+                                      base + attribute->d.buffered.offset) );
+  _cogl_bitmask_set (&context->enable_custom_attributes_tmp,
+                     attrib_location, TRUE);
+}
+
+static void
+setup_generic_const_attribute (CoglContext *context,
+                               CoglPipeline *pipeline,
+                               CoglAttribute *attribute)
+{
+  int name_index = attribute->name_state->name_index;
+  int attrib_location =
+    _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index);
+  int columns;
+  int i;
+
+  if (attrib_location == -1)
+    return;
+
+  if (attribute->d.constant.boxed.type == COGL_BOXED_MATRIX)
+    columns = attribute->d.constant.boxed.size;
+  else
+    columns = 1;
+
+  /* Note: it's ok to access a COGL_BOXED_FLOAT as a matrix with only
+   * one column... */
+
+  switch (attribute->d.constant.boxed.size)
     {
-      GE( context, glVertexAttribPointer (attrib_location,
-                                          attribute->n_components,
-                                          attribute->type,
-                                          attribute->normalized,
-                                          attribute->stride,
-                                          base + attribute->offset) );
-      _cogl_bitmask_set (&context->enable_custom_attributes_tmp,
-                         attrib_location, TRUE);
+    case 1:
+      GE( context, glVertexAttrib1fv (attrib_location,
+                                      attribute->d.constant.boxed.v.matrix));
+      break;
+    case 2:
+      for (i = 0; i < columns; i++)
+        GE( context, glVertexAttrib2fv (attrib_location + i,
+                                        attribute->d.constant.boxed.v.matrix));
+      break;
+    case 3:
+      for (i = 0; i < columns; i++)
+        GE( context, glVertexAttrib3fv (attrib_location + i,
+                                        attribute->d.constant.boxed.v.matrix));
+      break;
+    case 4:
+      for (i = 0; i < columns; i++)
+        GE( context, glVertexAttrib4fv (attrib_location + i,
+                                        attribute->d.constant.boxed.v.matrix));
+      break;
+    default:
+      g_warn_if_reached ();
     }
 }
 
 #endif /* COGL_PIPELINE_PROGEND_GLSL */
 
 static void
+setup_legacy_buffered_attribute (CoglContext *ctx,
+                                 CoglPipeline *pipeline,
+                                 CoglAttribute *attribute,
+                                 uint8_t *base)
+{
+  switch (attribute->name_state->name_id)
+    {
+    case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
+      _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
+                         COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY, TRUE);
+      GE (ctx, glColorPointer (attribute->d.buffered.n_components,
+                               attribute->d.buffered.type,
+                               attribute->d.buffered.stride,
+                               base + attribute->d.buffered.offset));
+      break;
+    case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
+      _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
+                         COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY, TRUE);
+      GE (ctx, glNormalPointer (attribute->d.buffered.type,
+                                attribute->d.buffered.stride,
+                                base + attribute->d.buffered.offset));
+      break;
+    case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
+      {
+        int layer_number = attribute->name_state->layer_number;
+        CoglPipelineLayer *layer =
+          _cogl_pipeline_get_layer (pipeline, layer_number);
+        int unit = _cogl_pipeline_layer_get_unit_index (layer);
+
+        _cogl_bitmask_set (&ctx->enable_texcoord_attributes_tmp, unit, TRUE);
+
+        GE (ctx, glClientActiveTexture (GL_TEXTURE0 + unit));
+        GE (ctx, glTexCoordPointer (attribute->d.buffered.n_components,
+                                    attribute->d.buffered.type,
+                                    attribute->d.buffered.stride,
+                                    base + attribute->d.buffered.offset));
+        break;
+      }
+    case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
+      _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
+                         COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY, TRUE);
+      GE (ctx, glVertexPointer (attribute->d.buffered.n_components,
+                                attribute->d.buffered.type,
+                                attribute->d.buffered.stride,
+                                base + attribute->d.buffered.offset));
+      break;
+    case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
+#ifdef COGL_PIPELINE_PROGEND_GLSL
+      if (ctx->driver != COGL_DRIVER_GLES1)
+        setup_generic_buffered_attribute (ctx, pipeline, attribute, base);
+#endif
+      break;
+    default:
+      g_warn_if_reached ();
+    }
+}
+
+static void
+setup_legacy_const_attribute (CoglContext *ctx,
+                              CoglPipeline *pipeline,
+                              CoglAttribute *attribute)
+{
+#ifdef COGL_PIPELINE_PROGEND_GLSL
+  if (attribute->name_state->name_id == COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY)
+    {
+      if (ctx->driver != COGL_DRIVER_GLES1)
+        setup_generic_const_attribute (ctx, pipeline, attribute);
+    }
+  else
+#endif
+    {
+      float vector[4] = { 0, 0, 0, 1 };
+      float *boxed = attribute->d.constant.boxed.v.float_value;
+      int n_components = attribute->d.constant.boxed.size;
+      int i;
+
+      for (i = 0; i < n_components; i++)
+        vector[i] = boxed[i];
+
+      switch (attribute->name_state->name_id)
+        {
+        case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
+          GE (ctx, glColor4f (vector[0], vector[1], vector[2], vector[3]));
+          break;
+        case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
+          GE (ctx, glNormal3f (vector[0], vector[1], vector[2]));
+          break;
+        case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
+          {
+            int layer_number = attribute->name_state->layer_number;
+            CoglPipelineLayer *layer =
+              _cogl_pipeline_get_layer (pipeline, layer_number);
+            int unit = _cogl_pipeline_layer_get_unit_index (layer);
+
+            GE (ctx, glClientActiveTexture (GL_TEXTURE0 + unit));
+
+            GE (ctx, glMultiTexCoord4f (vector[0], vector[1], vector[2], vector[3]));
+            break;
+          }
+        case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
+          GE (ctx, glVertex4f (vector[0], vector[1], vector[2], vector[3]));
+          break;
+        default:
+          g_warn_if_reached ();
+        }
+    }
+}
+
+static void
 apply_attribute_enable_updates (CoglContext *context,
                                 CoglPipeline *pipeline)
 {
@@ -305,88 +463,27 @@ _cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer,
       CoglBuffer *buffer;
       uint8_t *base;
 
-      attribute_buffer = cogl_attribute_get_buffer (attribute);
-      buffer = COGL_BUFFER (attribute_buffer);
-      base = _cogl_buffer_gl_bind (buffer, COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER);
-
-      switch (attribute->name_state->name_id)
+      if (attribute->is_buffered)
         {
-        case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
-#ifdef COGL_PIPELINE_PROGEND_GLSL
-          if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL)
-            setup_generic_attribute (ctx, pipeline, attribute, base);
-          else
-#endif
-            {
-              _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
-                                 COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY, TRUE);
-              GE (ctx, glColorPointer (attribute->n_components,
-                                       attribute->type,
-                                       attribute->stride,
-                                       base + attribute->offset));
-            }
-          break;
-        case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
-#ifdef COGL_PIPELINE_PROGEND_GLSL
-          if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL)
-            setup_generic_attribute (ctx, pipeline, attribute, base);
-          else
-#endif
-            {
-              _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
-                                 COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY, TRUE);
-              GE (ctx, glNormalPointer (attribute->type,
-                                        attribute->stride,
-                                        base + attribute->offset));
-            }
-          break;
-        case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
-#ifdef COGL_PIPELINE_PROGEND_GLSL
+          attribute_buffer = cogl_attribute_get_buffer (attribute);
+          buffer = COGL_BUFFER (attribute_buffer);
+          base = _cogl_buffer_gl_bind (buffer,
+                                       COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER);
+
           if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL)
-            setup_generic_attribute (ctx, pipeline, attribute, base);
+            setup_generic_buffered_attribute (ctx, pipeline, attribute, base);
           else
-#endif
-            {
-              int layer_number = attribute->name_state->layer_number;
-              CoglPipelineLayer *layer =
-                _cogl_pipeline_get_layer (pipeline, layer_number);
-              int unit = _cogl_pipeline_layer_get_unit_index (layer);
-
-              _cogl_bitmask_set (&ctx->enable_texcoord_attributes_tmp,
-                                 unit, TRUE);
-              GE (ctx, glClientActiveTexture (GL_TEXTURE0 + unit));
-              GE (ctx, glTexCoordPointer (attribute->n_components,
-                                          attribute->type,
-                                          attribute->stride,
-                                          base + attribute->offset));
-            }
-          break;
-        case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
-#ifdef COGL_PIPELINE_PROGEND_GLSL
+            setup_legacy_buffered_attribute (ctx, pipeline, attribute, base);
+
+          _cogl_buffer_gl_unbind (buffer);
+        }
+      else
+        {
           if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL)
-            setup_generic_attribute (ctx, pipeline, attribute, base);
+            setup_generic_const_attribute (ctx, pipeline, attribute);
           else
-#endif
-            {
-              _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
-                                 COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY, TRUE);
-              GE (ctx, glVertexPointer (attribute->n_components,
-                                        attribute->type,
-                                        attribute->stride,
-                                        base + attribute->offset));
-            }
-          break;
-        case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
-#ifdef COGL_PIPELINE_PROGEND_GLSL
-          if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL)
-            setup_generic_attribute (ctx, pipeline, attribute, base);
-#endif
-          break;
-        default:
-          g_warning ("Unrecognised attribute type 0x%08x", attribute->type);
+            setup_legacy_const_attribute (ctx, pipeline, attribute);
         }
-
-      _cogl_buffer_gl_unbind (buffer);
     }
 
   apply_attribute_enable_updates (ctx, pipeline);
diff --git a/cogl/gl-prototypes/cogl-fixed-functions.h b/cogl/gl-prototypes/cogl-fixed-functions.h
index 6ac3c92..7e5ab8e 100644
--- a/cogl/gl-prototypes/cogl-fixed-functions.h
+++ b/cogl/gl-prototypes/cogl-fixed-functions.h
@@ -72,6 +72,8 @@ COGL_EXT_FUNCTION (void, glTexEnvfv,
                    (GLenum target, GLenum pname, const GLfloat *params))
 COGL_EXT_FUNCTION (void, glColor4ub,
                    (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha))
+COGL_EXT_FUNCTION (void, glColor4f,
+                   (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha))
 COGL_EXT_FUNCTION (void, glColorPointer,
                    (GLint size,
                     GLenum type,
@@ -85,8 +87,12 @@ COGL_EXT_FUNCTION (void, glLoadIdentity,
                    (void))
 COGL_EXT_FUNCTION (void, glMatrixMode,
                    (GLenum mode))
+COGL_EXT_FUNCTION (void, glNormal3f,
+                   (GLfloat x, GLfloat y, GLfloat z))
 COGL_EXT_FUNCTION (void, glNormalPointer,
                    (GLenum type, GLsizei stride, const GLvoid *pointer))
+COGL_EXT_FUNCTION (void, glMultiTexCoord4f,
+                   (GLfloat s, GLfloat t, GLfloat r, GLfloat q))
 COGL_EXT_FUNCTION (void, glTexCoordPointer,
                    (GLint size,
                     GLenum type,
@@ -96,6 +102,8 @@ COGL_EXT_FUNCTION (void, glTexEnvi,
                    (GLenum target,
                     GLenum pname,
                     GLint param))
+COGL_EXT_FUNCTION (void, glVertex4f,
+                   (GLfloat x, GLfloat y, GLfloat z, GLfloat w))
 COGL_EXT_FUNCTION (void, glVertexPointer,
                    (GLint size,
                     GLenum type,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]