コード例 #1
0
ファイル: rut-shim.c プロジェクト: cee1/rig
void
rut_shim_set_child (RutShim *shim, RutObject *child)
{
  g_return_if_fail (rut_object_get_type (shim) == &rut_shim_type);

  if (shim->child == child)
    return;

  if (shim->child)
    {
      rut_graphable_remove_child (shim->child);
      rut_closure_disconnect (shim->child_preferred_size_closure);
      shim->child_preferred_size_closure = NULL;
      rut_refable_unref (shim->child);
    }

  if (child)
    {
      shim->child = rut_refable_ref (child);
      rut_graphable_add_child (shim, child);

      shim->child_preferred_size_closure =
        rut_sizable_add_preferred_size_callback (child,
                                                 child_preferred_size_cb,
                                                 shim,
                                                 NULL /* destroy */);
      queue_allocation (shim);
    }
  else
    shim->child = NULL;

  rut_shell_queue_redraw (shim->context->shell);
}
コード例 #2
0
static void
objects_selection_event_cb(rig_objects_selection_t *selection,
                           rig_objects_selection_event_t event,
                           rut_object_t *object,
                           void *user_data)
{
    rig_selection_tool_t *tool = user_data;
    entity_state_t *entity_state;
    c_llist_t *l;

    if (!tool->active && event == RIG_OBJECTS_SELECTION_ADD_EVENT)
        return;

    if (rut_object_get_type(object) != &rig_entity_type)
        return;

    for (l = tool->selected_entities; l; l = l->next) {
        entity_state = l->data;
        if (entity_state->entity == object)
            break;
    }
    if (l == NULL)
        entity_state = NULL;

    switch (event) {
    case RIG_OBJECTS_SELECTION_ADD_EVENT: {
        c_return_if_fail(entity_state == NULL);

        entity_state = c_slice_new0(entity_state_t);
        entity_state->tool = tool;
        entity_state->entity = rut_object_ref(object);
        entity_state->control_points = NULL;

        tool->selected_entities =
            c_llist_prepend(tool->selected_entities, entity_state);

        entity_state->sizeable = find_sizeable_component(entity_state->entity);
        if (entity_state->sizeable)
            create_sizeable_control_points(entity_state);
        else
            create_dummy_control_points(entity_state);

        break;
    }

    case RIG_OBJECTS_SELECTION_REMOVE_EVENT:
        c_return_if_fail(entity_state != NULL);

        tool->selected_entities =
            c_llist_remove(tool->selected_entities, entity_state);
        entity_state_destroy(entity_state);
        break;
    }
}
コード例 #3
0
ファイル: rig-selection-tool.c プロジェクト: cee1/rig
static void
objects_selection_event_cb (RigObjectsSelection *selection,
                            RigObjectsSelectionEvent event,
                            RutObject *object,
                            void *user_data)
{
  RigSelectionTool *tool = user_data;
  EntityState *entity_state;
  GList *l;

  if (!tool->active && event == RIG_OBJECTS_SELECTION_ADD_EVENT)
    return;

  if (rut_object_get_type (object) != &rut_entity_type)
    return;

  for (l = tool->selected_entities; l; l = l->next)
    {
      entity_state = l->data;
      if (entity_state->entity == object)
        break;
    }
  if (l == NULL)
    entity_state = NULL;

  switch (event)
    {
    case RIG_OBJECTS_SELECTION_ADD_EVENT:
      {
        g_return_if_fail (entity_state == NULL);

        entity_state = g_slice_new0 (EntityState);
        entity_state->tool = tool;
        entity_state->entity = rut_refable_ref (object);
        entity_state->control_points = NULL;

        tool->selected_entities = g_list_prepend (tool->selected_entities,
                                                  entity_state);

#warning "TODO: create meaningful control points!"
        create_dummy_control_points (entity_state);

        break;
      }

    case RIG_OBJECTS_SELECTION_REMOVE_EVENT:
      g_return_if_fail (entity_state != NULL);

      tool->selected_entities = g_list_remove (tool->selected_entities, entity_state);
      entity_state_destroy (entity_state);
      break;
    }
}
コード例 #4
0
ファイル: rut-interfaces.c プロジェクト: cee1/rig
void
rut_refable_release (void *object, void *owner)
{
  RutObject *obj = object;
  const RutType *type = rut_object_get_type (obj);
  RutRefableVTable *vtable =
    type->interfaces[RUT_INTERFACE_ID_REF_COUNTABLE].vtable;

  _rut_refcount_debug_release (object, owner);

  vtable->unref (obj);
}
コード例 #5
0
ファイル: rut-interfaces.c プロジェクト: cee1/rig
void *
rut_refable_ref (void *object)
{
  RutObject *obj = object;
  const RutType *type = rut_object_get_type (obj);

  RutRefableVTable *vtable =
    type->interfaces[RUT_INTERFACE_ID_REF_COUNTABLE].vtable;

  _rut_refcount_debug_ref (object);

  return vtable->ref (obj);
}
コード例 #6
0
ファイル: rig-renderer.c プロジェクト: sanyaade-mobiledev/rig
static RutTraverseVisitFlags
entitygraph_pre_paint_cb (RutObject *object,
                          int depth,
                          void *user_data)
{
  RigPaintContext *paint_ctx = user_data;
  RutPaintContext *rut_paint_ctx = user_data;
  RutCamera *camera = rut_paint_ctx->camera;
  CoglFramebuffer *fb = rut_camera_get_framebuffer (camera);

  if (rut_object_is (object, RUT_INTERFACE_ID_TRANSFORMABLE))
    {
      const CoglMatrix *matrix = rut_transformable_get_matrix (object);
      cogl_framebuffer_push_matrix (fb);
      cogl_framebuffer_transform (fb, matrix);
    }

  if (rut_object_get_type (object) == &rut_entity_type)
    {
      RutEntity *entity = RUT_ENTITY (object);
      RutObject *geometry;
      CoglMatrix matrix;

      if (!rut_entity_get_visible (entity) ||
          (paint_ctx->pass == RIG_PASS_SHADOW && !rut_entity_get_cast_shadow (entity)))
        return RUT_TRAVERSE_VISIT_CONTINUE;

      geometry =
        rut_entity_get_component (object, RUT_COMPONENT_TYPE_GEOMETRY);
      if (!geometry)
        {
          if (!paint_ctx->engine->play_mode &&
              object == paint_ctx->engine->light)
            draw_entity_camera_frustum (paint_ctx->engine, object, fb);
          return RUT_TRAVERSE_VISIT_CONTINUE;
        }

      cogl_framebuffer_get_modelview_matrix (fb, &matrix);
      rig_journal_log (paint_ctx->engine->journal,
                       paint_ctx,
                       entity,
                       &matrix);

      return RUT_TRAVERSE_VISIT_CONTINUE;
    }

  return RUT_TRAVERSE_VISIT_CONTINUE;
}
コード例 #7
0
void
rut_fold_set_header_child(rut_fold_t *fold, rut_object_t *child)
{
    c_return_if_fail(rut_object_get_type(fold) == &rut_fold_type);

    if (child)
        rut_object_claim(child, fold);

    if (fold->header_child) {
        rut_box_layout_remove(fold->header_hbox_right, fold->header_child);
        rut_object_release(fold->header_child, fold);
    }

    fold->header_child = child;
    rut_box_layout_add(fold->header_hbox_right, true, child);
}
コード例 #8
0
ファイル: rut-fold.c プロジェクト: cee1/rig
void
rut_fold_set_header_child (RutFold *fold, RutObject *child)
{
  g_return_if_fail (rut_object_get_type (fold) == &rut_fold_type);

  if (child)
    rut_refable_claim (child, fold);

  if (fold->header_child)
    {
      rut_box_layout_remove (fold->header_hbox_right, fold->header_child);
      rut_refable_release (fold->header_child, fold);
    }

  fold->header_child = child;
  rut_box_layout_add (fold->header_hbox_right, TRUE, child);
}
コード例 #9
0
ファイル: rut-graphable.c プロジェクト: cee1/rig
RutCamera *
rut_graphable_find_camera (RutObject *object)
{
  do {
    RutGraphableProps *graphable_priv;

    if (rut_object_get_type (object) == &rut_camera_type)
      return RUT_CAMERA (object);

    graphable_priv =
      rut_object_get_properties (object, RUT_INTERFACE_ID_GRAPHABLE);

    object = graphable_priv->parent;

  } while (object);

  return NULL;
}
コード例 #10
0
void
rut_fold_set_child(rut_fold_t *fold, rut_object_t *child)
{
    c_return_if_fail(rut_object_get_type(fold) == &rut_fold_type);

    if (child)
        rut_object_claim(child, fold);

    if (fold->child) {
        if (!fold->folded)
            rut_box_layout_remove(fold->vbox, fold->child);
        rut_object_release(fold->child, fold);
    }

    fold->child = child;
    if (child && !fold->folded)
        rut_box_layout_add(fold->vbox, true, child);
}
コード例 #11
0
ファイル: rut-fold.c プロジェクト: cee1/rig
void
rut_fold_set_child (RutFold *fold, RutObject *child)
{
  g_return_if_fail (rut_object_get_type (fold) == &rut_fold_type);

  if (child)
    rut_refable_claim (child, fold);

  if (fold->child)
    {
      if (!fold->folded)
        rut_box_layout_remove (fold->vbox, fold->child);
      rut_refable_release (fold->child, fold);
    }

  fold->child = child;
  if (child && !fold->folded)
    rut_box_layout_add (fold->vbox, TRUE, child);
}
コード例 #12
0
ファイル: rut-bin.c プロジェクト: cee1/rig
void
rut_bin_set_child (RutBin *bin,
                   RutObject *child_widget)
{
  g_return_if_fail (rut_object_get_type (bin) == &rut_bin_type);

  if (bin->child == child_widget)
    return;

  if (child_widget)
    rut_refable_claim (child_widget, bin);

  if (bin->child)
    {
      rut_graphable_remove_child (bin->child);
      rut_closure_disconnect (bin->child_preferred_size_closure);
      bin->child_preferred_size_closure = NULL;
      rut_refable_release (bin->child, bin);
    }

  bin->child = child_widget;

  if (child_widget)
    {
      rut_graphable_add_child (bin->child_transform, child_widget);
      bin->child_preferred_size_closure =
        rut_sizable_add_preferred_size_callback (child_widget,
                                                 child_preferred_size_cb,
                                                 bin,
                                                 NULL /* destroy */);
      queue_allocation (bin);
    }

  preferred_size_changed (bin);
  rut_shell_queue_redraw (bin->context->shell);
}
コード例 #13
0
ファイル: rut-shim.c プロジェクト: cee1/rig
void
rut_shim_remove_child (RutShim *shim, RutObject *child)
{
  g_return_if_fail (rut_object_get_type (shim) == &rut_shim_type);
  rut_graphable_remove_child (child);
}
コード例 #14
0
ファイル: rig-renderer.c プロジェクト: sanyaade-mobiledev/rig
static CoglPipeline *
get_entity_mask_pipeline (RigEngine *engine,
                          RutEntity *entity,
                          RutComponent *geometry)
{
  CoglPipeline *pipeline;

  pipeline = rut_entity_get_pipeline_cache (entity, CACHE_SLOT_SHADOW);
  if (pipeline)
    return cogl_object_ref (pipeline);

  /* TODO: move into init() somewhere */
  if (G_UNLIKELY (!engine->dof_pipeline_template))
    {
      CoglPipeline *pipeline;
      CoglDepthState depth_state;
      CoglSnippet *snippet;

      pipeline = cogl_pipeline_new (engine->ctx->cogl_context);

      cogl_pipeline_set_color_mask (pipeline, COGL_COLOR_MASK_ALPHA);

      cogl_pipeline_set_blend (pipeline, "RGBA=ADD(SRC_COLOR, 0)", NULL);

      cogl_depth_state_init (&depth_state);
      cogl_depth_state_set_test_enabled (&depth_state, TRUE);
      cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL);

      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,

                                  /* definitions */
                                  "uniform float dof_focal_distance;\n"
                                  "uniform float dof_depth_of_field;\n"

                                  "varying float dof_blur;\n",
                                  //"varying vec4 world_pos;\n",

                                  /* compute the amount of bluriness we want */
                                  "vec4 world_pos = cogl_modelview_matrix * cogl_position_in;\n"
                                  //"world_pos = cogl_modelview_matrix * cogl_position_in;\n"
                                  "dof_blur = 1.0 - clamp (abs (world_pos.z - dof_focal_distance) /\n"
                                  "                  dof_depth_of_field, 0.0, 1.0);\n"
      );

      cogl_pipeline_add_snippet (pipeline, snippet);
      cogl_object_unref (snippet);

      /* This was used to debug the focal distance and bluriness amount in the DoF
       * effect: */
#if 0
      cogl_pipeline_set_color_mask (pipeline, COGL_COLOR_MASK_ALL);
      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
                                  "varying vec4 world_pos;\n"
                                  "varying float dof_blur;",

                                  "cogl_color_out = vec4(dof_blur,0,0,1);\n"
                                  //"cogl_color_out = vec4(1.0, 0.0, 0.0, 1.0);\n"
                                  //"if (world_pos.z < -30.0) cogl_color_out = vec4(0,1,0,1);\n"
                                  //"if (abs (world_pos.z + 30.f) < 0.1) cogl_color_out = vec4(0,1,0,1);\n"
                                  "cogl_color_out.a = dof_blur;\n"
                                  //"cogl_color_out.a = 1.0;\n"
      );

      cogl_pipeline_add_snippet (pipeline, snippet);
      cogl_object_unref (snippet);
#endif

      engine->dof_pipeline_template = pipeline;
    }

  /* TODO: move into init() somewhere */
  if (G_UNLIKELY (!engine->dof_diamond_pipeline))
    {
      CoglPipeline *dof_diamond_pipeline =
        cogl_pipeline_copy (engine->dof_pipeline_template);
      CoglSnippet *snippet;

      cogl_pipeline_set_layer_texture (dof_diamond_pipeline,
                                       0,
                                       engine->ctx->circle_texture);

      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
                                  /* declarations */
                                  "varying float dof_blur;",

                                  /* post */
                                  "if (cogl_color_out.a <= 0.0)\n"
                                  "  discard;\n"
                                  "\n"
                                  "cogl_color_out.a = dof_blur;\n");

      cogl_pipeline_add_snippet (dof_diamond_pipeline, snippet);
      cogl_object_unref (snippet);

      engine->dof_diamond_pipeline = dof_diamond_pipeline;
    }

  /* TODO: move into init() somewhere */
  if (G_UNLIKELY (!engine->dof_unshaped_pipeline))
    {
      CoglPipeline *dof_unshaped_pipeline =
        cogl_pipeline_copy (engine->dof_pipeline_template);
      CoglSnippet *snippet;

      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
                                  /* declarations */
                                  "varying float dof_blur;",

                                  /* post */
                                  "if (cogl_color_out.a < 0.25)\n"
                                  "  discard;\n"
                                  "\n"
                                  "cogl_color_out.a = dof_blur;\n");

      cogl_pipeline_add_snippet (dof_unshaped_pipeline, snippet);
      cogl_object_unref (snippet);

      engine->dof_unshaped_pipeline = dof_unshaped_pipeline;
    }

  /* TODO: move into init() somewhere */
  if (G_UNLIKELY (!engine->dof_pipeline))
    {
      CoglPipeline *dof_pipeline =
        cogl_pipeline_copy (engine->dof_pipeline_template);
      CoglSnippet *snippet;

      /* store the bluriness in the alpha channel */
      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
                                  "varying float dof_blur;",

                                  "cogl_color_out.a = dof_blur;\n"
      );
      cogl_pipeline_add_snippet (dof_pipeline, snippet);
      cogl_object_unref (snippet);

      engine->dof_pipeline = dof_pipeline;
    }

  if (rut_object_get_type (geometry) == &rut_diamond_type)
    {
      pipeline = cogl_object_ref (engine->dof_diamond_pipeline);
    }
  else if (rut_object_get_type (geometry) == &rut_shape_type)
    {
      RutMaterial *material =
        rut_entity_get_component (entity, RUT_COMPONENT_TYPE_MATERIAL);

      pipeline = cogl_pipeline_copy (engine->dof_unshaped_pipeline);

      if (rut_shape_get_shaped (RUT_SHAPE (geometry)))
        {
          CoglTexture *shape_texture =
            rut_shape_get_shape_texture (RUT_SHAPE (geometry));

          cogl_pipeline_set_layer_texture (pipeline, 0, shape_texture);
        }

      if (material)
        {
          RutAsset *texture_asset = rut_material_get_texture_asset (material);
          RutAsset *alpha_mask_asset =
            rut_material_get_alpha_mask_asset (material);

          if (texture_asset)
            cogl_pipeline_set_layer_texture (pipeline, 1,
                                             rut_asset_get_texture (texture_asset));

          if (alpha_mask_asset)
            {
              /* We don't want this layer to be automatically modulated with the
               * previous layers so we set its combine mode to "REPLACE" so it
               * will be skipped past and we can sample its texture manually */
              cogl_pipeline_set_layer_combine (pipeline, 2, "RGBA=REPLACE(PREVIOUS)", NULL);
              cogl_pipeline_set_layer_texture (pipeline, 2,
                                               rut_asset_get_texture (alpha_mask_asset));

              cogl_pipeline_add_snippet (pipeline, engine->alpha_mask_snippet);
            }
        }
    }
  else
    pipeline = cogl_object_ref (engine->dof_pipeline);

  rut_entity_set_pipeline_cache (entity, CACHE_SLOT_SHADOW, pipeline);

  return pipeline;
}
コード例 #15
0
ファイル: rut-fixed.c プロジェクト: cee1/rig
void
rut_fixed_remove_child (RutFixed *fixed, RutObject *child)
{
  g_return_if_fail (rut_object_get_type (fixed) == &rut_fixed_type);
  rut_graphable_remove_child (child);
}
コード例 #16
0
ファイル: rig-renderer.c プロジェクト: sanyaade-mobiledev/rig
static void
rig_journal_flush (GArray *journal,
                   RigPaintContext *paint_ctx)
{
  RutPaintContext *rut_paint_ctx = &paint_ctx->_parent;
  RutCamera *camera = rut_paint_ctx->camera;
  CoglFramebuffer *fb = rut_camera_get_framebuffer (camera);
  int start, dir, end;
  int i;

  /* TODO: use an inline qsort implementation */
  g_array_sort (journal, (void *)sort_entry_cb);

  /* We draw opaque geometry front-to-back so we are more likely to be
   * able to discard later fragments earlier by depth testing.
   *
   * We draw transparent geometry back-to-front so it blends
   * correctly.
   */
  if ( paint_ctx->pass == RIG_PASS_COLOR_BLENDED)
    {
      start = 0;
      dir = 1;
      end = journal->len;
    }
  else
    {
      start = journal->len - 1;
      dir = -1;
      end = -1;
    }

  cogl_framebuffer_push_matrix (fb);

  for (i = start; i != end; i += dir)
    {
      RigJournalEntry *entry = &g_array_index (journal, RigJournalEntry, i);
      RutEntity *entity = entry->entity;
      RutComponent *geometry =
        rut_entity_get_component (entity, RUT_COMPONENT_TYPE_GEOMETRY);
      CoglPipeline *pipeline;
      CoglPrimitive *primitive;
      float normal_matrix[9];
      RutMaterial *material;

      pipeline = get_entity_pipeline (paint_ctx->engine,
                                      entity,
                                      geometry,
                                      paint_ctx->pass);

      if (paint_ctx->pass == RIG_PASS_DOF_DEPTH ||
          paint_ctx->pass == RIG_PASS_SHADOW)
        {
          /* FIXME: avoid updating these uniforms for every primitive if
           * the focal parameters haven't change! */
          set_focal_parameters (pipeline,
                                camera->focal_distance,
                                camera->depth_of_field);
        }
      else if (paint_ctx->pass == RIG_PASS_COLOR_UNBLENDED ||
               paint_ctx->pass == RIG_PASS_COLOR_BLENDED)
        {
          int location;
          RutLight *light = rut_entity_get_component (paint_ctx->engine->light,
                                                      RUT_COMPONENT_TYPE_LIGHT);
          /* FIXME: only update the lighting uniforms when the light has
           * actually moved! */
          rut_light_set_uniforms (light, pipeline);

          /* FIXME: only update the material uniforms when the material has
           * actually changed! */
          material = rut_entity_get_component (entity, RUT_COMPONENT_TYPE_MATERIAL);
          if (material)
            rut_material_flush_uniforms (material, pipeline);

          get_normal_matrix (&entry->matrix, normal_matrix);

          location = cogl_pipeline_get_uniform_location (pipeline, "normal_matrix");
          cogl_pipeline_set_uniform_matrix (pipeline,
                                            location,
                                            3, /* dimensions */
                                            1, /* count */
                                            FALSE, /* don't transpose again */
                                            normal_matrix);
        }

      if (rut_object_is (geometry, RUT_INTERFACE_ID_PRIMABLE))
        {
          primitive = rut_primable_get_primitive (geometry);
          cogl_framebuffer_set_modelview_matrix (fb, &entry->matrix);
          cogl_framebuffer_draw_primitive (fb,
                                           pipeline,
                                           primitive);
        }
      else if (rut_object_get_type (geometry) == &rut_text_type &&
               paint_ctx->pass == RIG_PASS_COLOR_BLENDED)
        {
          cogl_framebuffer_set_modelview_matrix (fb, &entry->matrix);
          rut_paintable_paint (geometry, rut_paint_ctx);
        }

      cogl_object_unref (pipeline);

      rut_refable_unref (entry->entity);
    }

  cogl_framebuffer_pop_matrix (fb);

  g_array_set_size (journal, 0);
}
コード例 #17
0
ファイル: rig-renderer.c プロジェクト: sanyaade-mobiledev/rig
static CoglPipeline *
get_entity_color_pipeline (RigEngine *engine,
                           RutEntity *entity,
                           RutComponent *geometry,
                           CoglBool blended)
{
  CoglSnippet *snippet;
  CoglDepthState depth_state;
  RutMaterial *material;
  CoglTexture *texture = NULL;
  CoglTexture *normal_map = NULL;
  CoglTexture *alpha_mask = NULL;
  CoglPipeline *pipeline;
  CoglFramebuffer *shadow_fb;

  if (blended)
    pipeline = rut_entity_get_pipeline_cache (entity,
                                              CACHE_SLOT_COLOR_BLENDED);
  else
    pipeline = rut_entity_get_pipeline_cache (entity,
                                              CACHE_SLOT_COLOR_UNBLENDED);
  if (pipeline)
    {
      cogl_object_ref (pipeline);
      goto FOUND;
    }

  pipeline = cogl_pipeline_new (engine->ctx->cogl_context);

  material = rut_entity_get_component (entity, RUT_COMPONENT_TYPE_MATERIAL);
  if (material)
    {
      RutAsset *texture_asset = rut_material_get_texture_asset (material);
      RutAsset *normal_map_asset =
        rut_material_get_normal_map_asset (material);
      RutAsset *alpha_mask_asset =
        rut_material_get_alpha_mask_asset (material);

      if (texture_asset)
        texture = rut_asset_get_texture (texture_asset);
      if (texture)
        cogl_pipeline_set_layer_texture (pipeline, 1, texture);

      if (normal_map_asset)
        normal_map = rut_asset_get_texture (normal_map_asset);

      if (alpha_mask_asset)
        alpha_mask = rut_asset_get_texture (alpha_mask_asset);
    }

#if 0
  /* NB: Our texture colours aren't premultiplied */
  cogl_pipeline_set_blend (pipeline,
                           "RGB = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))"
                           "A   = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))",
                           NULL);
#endif

#if 0
  if (rut_object_get_type (geometry) == &rut_shape_type)
    rut_geometry_component_update_pipeline (geometry, pipeline);

  pipeline = cogl_pipeline_new (rut_cogl_context);
#endif

  cogl_pipeline_set_color4f (pipeline, 0.8f, 0.8f, 0.8f, 1.f);

  /* enable depth testing */
  cogl_depth_state_init (&depth_state);
  cogl_depth_state_set_test_enabled (&depth_state, TRUE);

  if (blended)
    cogl_depth_state_set_write_enabled (&depth_state, FALSE);

  cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL);

  /* Vertex shader setup for lighting */
  cogl_pipeline_add_snippet (pipeline, engine->lighting_vertex_snippet);

  if (normal_map)
    cogl_pipeline_add_snippet (pipeline, engine->normal_map_vertex_snippet);

  if (rut_entity_get_receive_shadow (entity))
    cogl_pipeline_add_snippet (pipeline, engine->shadow_mapping_vertex_snippet);

  /* and fragment shader */

  /* XXX: ideally we wouldn't have to rely on conditionals + discards
   * in the fragment shader to differentiate blended and unblended
   * regions and instead we should let users mark out opaque regions
   * in geometry.
   */
  cogl_pipeline_add_snippet (pipeline,
                             blended ?
                             engine->blended_discard_snippet :
                             engine->unblended_discard_snippet);

  cogl_pipeline_add_snippet (pipeline, engine->unpremultiply_snippet);

  if (material)
    {
      if (alpha_mask)
        {
          /* We don't want this layer to be automatically modulated with the
           * previous layers so we set its combine mode to "REPLACE" so it
           * will be skipped past and we can sample its texture manually */
          cogl_pipeline_set_layer_combine (pipeline, 2, "RGBA=REPLACE(PREVIOUS)", NULL);
          cogl_pipeline_set_layer_texture (pipeline, 2, alpha_mask);

          cogl_pipeline_add_snippet (pipeline, engine->alpha_mask_snippet);
        }

      if (normal_map)
        {
          /* We don't want this layer to be automatically modulated with the
           * previous layers so we set its combine mode to "REPLACE" so it
           * will be skipped past and we can sample its texture manually */
          cogl_pipeline_set_layer_combine (pipeline, 5, "RGBA=REPLACE(PREVIOUS)", NULL);
          cogl_pipeline_set_layer_texture (pipeline, 5, normal_map);

          snippet = engine->normal_map_fragment_snippet;
        }
      else
        {
          snippet = engine->material_lighting_snippet;
        }
    }
  else
    {
      snippet = engine->simple_lighting_snippet;
    }

  cogl_pipeline_add_snippet (pipeline, snippet);

  if (rut_entity_get_receive_shadow (entity))
    {
      /* Hook the shadow map sampling */

      cogl_pipeline_set_layer_texture (pipeline, 7, engine->shadow_map);
      /* For debugging the shadow mapping... */
      //cogl_pipeline_set_layer_texture (pipeline, 7, engine->shadow_color);
      //cogl_pipeline_set_layer_texture (pipeline, 7, engine->gradient);

      /* We don't want this layer to be automatically modulated with the
       * previous layers so we set its combine mode to "REPLACE" so it
       * will be skipped past and we can sample its texture manually */
      cogl_pipeline_set_layer_combine (pipeline, 7, "RGBA=REPLACE(PREVIOUS)", NULL);

      /* Handle shadow mapping */
      cogl_pipeline_add_snippet (pipeline,
                                 engine->shadow_mapping_fragment_snippet);
    }

  cogl_pipeline_add_snippet (pipeline, engine->premultiply_snippet);

  if (rut_object_get_type (geometry) == &rut_shape_type)
    {
      CoglTexture *shape_texture;

      if (rut_shape_get_shaped (RUT_SHAPE (geometry)))
        {
          shape_texture =
            rut_shape_get_shape_texture (RUT_SHAPE (geometry));
          cogl_pipeline_set_layer_texture (pipeline, 0, shape_texture);
        }

      rut_shape_add_reshaped_callback (RUT_SHAPE (geometry),
                                       reshape_cb,
                                       NULL,
                                       NULL);
    }
  else if (rut_object_get_type (geometry) == &rut_diamond_type)
    rut_diamond_apply_mask (RUT_DIAMOND (geometry), pipeline);

  if (!blended)
    {
      cogl_pipeline_set_blend (pipeline, "RGBA = ADD (SRC_COLOR, 0)", NULL);
      rut_entity_set_pipeline_cache (entity,
                                     CACHE_SLOT_COLOR_UNBLENDED, pipeline);
    }
  else
    {
      rut_entity_set_pipeline_cache (entity,
                                     CACHE_SLOT_COLOR_BLENDED, pipeline);
    }

FOUND:

  /* FIXME: there's lots to optimize about this! */
  shadow_fb = COGL_FRAMEBUFFER (engine->shadow_fb);

  /* update uniforms in pipelines */
  {
    CoglMatrix light_shadow_matrix, light_projection;
    CoglMatrix model_transform;
    const float *light_matrix;
    int location;

    cogl_framebuffer_get_projection_matrix (shadow_fb, &light_projection);

    /* XXX: This is pretty bad that we are having to do this. It would
     * be nicer if cogl exposed matrix-stacks publicly so we could
     * maintain the entity model_matrix incrementally as we traverse
     * the scenegraph. */
    rut_graphable_get_transform (entity, &model_transform);

    get_light_modelviewprojection (&model_transform,
                                   engine->light,
                                   &light_projection,
                                   &light_shadow_matrix);

    light_matrix = cogl_matrix_get_array (&light_shadow_matrix);

    location = cogl_pipeline_get_uniform_location (pipeline,
                                                   "light_shadow_matrix");
    cogl_pipeline_set_uniform_matrix (pipeline,
                                      location,
                                      4, 1,
                                      FALSE,
                                      light_matrix);
  }

  return pipeline;
}