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); }
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; } }
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; } }
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); }
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); }
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; }
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); }
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); }
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; }
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); }
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); }
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); }
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); }
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; }
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); }
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); }
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; }