static void test_coglbox_paint(ClutterActor *self) { TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (self); ClutterColor cback = {0x66, 0x66, 0xDD, 0xFF}; ClutterColor cwhite = {0xFF, 0xFF, 0xFF, 0xFF}; ClutterFixed texcoords[4] = { CLUTTER_FLOAT_TO_FIXED (0.3f), CLUTTER_FLOAT_TO_FIXED (0.3f), CLUTTER_FLOAT_TO_FIXED (0.7f), CLUTTER_FLOAT_TO_FIXED (0.7f) }; priv = TEST_COGLBOX_GET_PRIVATE (self); cogl_color (&cback); cogl_rectangle (0,0,400,400); cogl_color (&cwhite); cogl_push_matrix (); cogl_translate (100,100,0); cogl_texture_rectangle (priv->cogl_handle, 0, 0, CLUTTER_INT_TO_FIXED (200), CLUTTER_INT_TO_FIXED (200), texcoords[0], texcoords[1], texcoords[2], texcoords[3]); cogl_pop_matrix(); }
static void mex_action_button_paint_background (MxWidget *widget, ClutterActor *background, const ClutterColor *color) { MexActionButtonPrivate *priv = MEX_ACTION_BUTTON (widget)->priv; gfloat width, height; gfloat factor_x, factor_y; cogl_push_matrix (); if (priv->has_focus) { clutter_actor_get_size (background, &width, &height); factor_x = (width + 4) / width; factor_y = (height + 4) / height; cogl_translate (width/2, height/2, 0); cogl_scale (factor_x, factor_y, 1); cogl_translate (-width/2, -height/2, 0); } MX_WIDGET_CLASS(mex_action_button_parent_class)->paint_background (widget, background, color); cogl_pop_matrix (); }
static void clutter_widget_paint ( ClutterActor *_self ) { ClutterGeometry geom; ClutterWidgetPrivate *priv; int borderWidth = 1; priv = CLUTTER_WIDGET_GET_PRIVATE (_self); clutter_actor_get_geometry (_self, &geom); cogl_push_matrix (); cogl_path_round_rectangle ( -borderWidth, -borderWidth, geom.width + borderWidth, geom.height + borderWidth, 5, 1 ); cogl_set_source_color4ub ( priv->borderColor.red, priv->borderColor.green, priv->borderColor.blue, priv->borderColor.alpha ); cogl_path_fill (); cogl_path_round_rectangle ( 0, 0, geom.width, geom.height, 5, 1 ); cogl_set_source_color4ub ( 0xcf, 0xcf, 0xcf, 0xff ); cogl_path_fill (); cogl_pop_matrix(); // call the parent paint CLUTTER_ACTOR_CLASS (clutter_widget_parent_class)->paint (_self); }
static void empathy_rounded_effect_paint (ClutterEffect *effect, ClutterEffectPaintFlags flags) { EmpathyRoundedEffect *self = EMPATHY_ROUNDED_EFFECT (effect); ClutterActor *actor; ClutterActorBox allocation = { 0, }; gfloat width, height; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self)); clutter_actor_get_allocation_box (actor, &allocation); clutter_actor_box_get_size (&allocation, &width, &height); cogl_path_new (); /* Create and store a path describing a rounded rectangle. The small * size of the preview window makes the radius of the rounded corners * very small too, so we can safely use a very coarse angle step * without loosing rendering accuracy. It also significantly reduces * the time spent in the underlying internal cogl path functions */ cogl_path_round_rectangle (0, 0, width, height, height / 16., 15); cogl_clip_push_from_path (); /* Flip */ cogl_push_matrix (); cogl_translate (width, 0, 0); cogl_scale (-1, 1, 1); clutter_actor_continue_paint (actor); cogl_pop_matrix (); cogl_clip_pop (); }
static void mx_fade_effect_post_paint (ClutterEffect *effect) { MxFadeEffectPrivate *priv = MX_FADE_EFFECT (effect)->priv; if (!priv->freeze_update) CLUTTER_EFFECT_CLASS (mx_fade_effect_parent_class)->post_paint (effect); else { CoglMatrix modelview; ClutterActor *actor, *stage; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); stage = clutter_actor_get_stage (actor); /* Set up the draw matrix so we draw the offscreen texture at the * absolute coordinates of the actor-box. We need to do this to * avoid transforming by the actor matrix twice, as when it's drawn * into the offscreen surface, it'll already be transformed. */ cogl_push_matrix (); cogl_matrix_init_identity (&modelview); CLUTTER_ACTOR_CLASS (G_OBJECT_GET_CLASS (stage))-> apply_transform (stage, &modelview); cogl_matrix_translate (&modelview, priv->x_offset, priv->y_offset, 0.f); cogl_set_modelview_matrix (&modelview); clutter_offscreen_effect_paint_target (CLUTTER_OFFSCREEN_EFFECT (effect)); cogl_pop_matrix (); } }
static void st_box_layout_paint (ClutterActor *actor) { StBoxLayout *self = ST_BOX_LAYOUT (actor); StBoxLayoutPrivate *priv = self->priv; StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); GList *l, *children; gdouble x, y; ClutterActorBox allocation_box; ClutterActorBox content_box; get_border_paint_offsets (self, &x, &y); if (x != 0 || y != 0) { cogl_push_matrix (); cogl_translate ((int)x, (int)y, 0); } CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->paint (actor); if (x != 0 || y != 0) { cogl_pop_matrix (); } children = st_container_get_children_list (ST_CONTAINER (actor)); if (children == NULL) return; clutter_actor_get_allocation_box (actor, &allocation_box); st_theme_node_get_content_box (theme_node, &allocation_box, &content_box); content_box.x1 += x; content_box.y1 += y; content_box.x2 += x; content_box.y2 += y; /* The content area forms the viewport into the scrolled contents, while * the borders and background stay in place; after drawing the borders and * background, we clip to the content area */ if (priv->hadjustment || priv->vadjustment) cogl_clip_push_rectangle ((int)content_box.x1, (int)content_box.y1, (int)content_box.x2, (int)content_box.y2); for (l = children; l; l = g_list_next (l)) { ClutterActor *child = (ClutterActor*) l->data; if (CLUTTER_ACTOR_IS_VISIBLE (child)) clutter_actor_paint (child); } if (priv->hadjustment || priv->vadjustment) cogl_clip_pop (); }
static void test_coglbox_paint(ClutterActor *self) { TestCoglboxPrivate *priv; ClutterColor cfill; ClutterColor cstroke; static GTimer *timer = NULL; static gint paint_index = 0; gint NUM_PAINT_FUNCS; NUM_PAINT_FUNCS = G_N_ELEMENTS (paint_func); priv = TEST_COGLBOX_GET_PRIVATE (self); if (!timer) { timer = g_timer_new (); g_timer_start (timer); } if (g_timer_elapsed (timer, NULL) >= 1) { paint_index += 1; paint_index = paint_index % NUM_PAINT_FUNCS; g_timer_start (timer); } cfill.red = 0; cfill.green = 160; cfill.blue = 0; cfill.alpha = 255; cstroke.red = 200; cstroke.green = 0; cstroke.blue = 0; cstroke.alpha = 255; cogl_push_matrix (); paint_func[paint_index] (); cogl_translate (100,100,0); cogl_color (&cstroke); cogl_path_stroke (); cogl_translate (150,0,0); cogl_color (&cfill); cogl_path_fill (); cogl_pop_matrix(); }
static void st_box_layout_paint (ClutterActor *actor) { StBoxLayout *self = ST_BOX_LAYOUT (actor); StBoxLayoutPrivate *priv = self->priv; StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); gdouble x, y; ClutterActorBox allocation_box; ClutterActorBox content_box; ClutterActor *child; get_border_paint_offsets (self, &x, &y); if (x != 0 || y != 0) { cogl_push_matrix (); cogl_translate ((int)x, (int)y, 0); } st_widget_paint_background (ST_WIDGET (actor)); if (x != 0 || y != 0) { cogl_pop_matrix (); } if (clutter_actor_get_n_children (actor) == 0) return; clutter_actor_get_allocation_box (actor, &allocation_box); st_theme_node_get_content_box (theme_node, &allocation_box, &content_box); content_box.x1 += x; content_box.y1 += y; content_box.x2 += x; content_box.y2 += y; /* The content area forms the viewport into the scrolled contents, while * the borders and background stay in place; after drawing the borders and * background, we clip to the content area */ if (priv->hadjustment || priv->vadjustment) cogl_clip_push_rectangle ((int)content_box.x1, (int)content_box.y1, (int)content_box.x2, (int)content_box.y2); for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) clutter_actor_paint (child); if (priv->hadjustment || priv->vadjustment) cogl_clip_pop (); }
static void st_box_layout_pick (ClutterActor *actor, const ClutterColor *color) { StBoxLayout *self = ST_BOX_LAYOUT (actor); StBoxLayoutPrivate *priv = self->priv; StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); gdouble x, y; ClutterActorBox allocation_box; ClutterActorBox content_box; ClutterActor *child; get_border_paint_offsets (self, &x, &y); if (x != 0 || y != 0) { cogl_push_matrix (); cogl_translate ((int)x, (int)y, 0); } CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->pick (actor, color); if (x != 0 || y != 0) { cogl_pop_matrix (); } if (clutter_actor_get_n_children (actor) == 0) return; clutter_actor_get_allocation_box (actor, &allocation_box); st_theme_node_get_content_box (theme_node, &allocation_box, &content_box); content_box.x1 += x; content_box.y1 += y; content_box.x2 += x; content_box.y2 += y; if (priv->hadjustment || priv->vadjustment) cogl_clip_push_rectangle ((int)content_box.x1, (int)content_box.y1, (int)content_box.x2, (int)content_box.y2); for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) clutter_actor_paint (child); if (priv->hadjustment || priv->vadjustment) cogl_clip_pop (); }
static void clutter_reflect_texture_paint (ClutterActor *self) { ClutterReflectTexturePrivate *priv; ClutterActor *parent_texture; gint x1, y1, x2, y2; GLenum target_type; priv = CLUTTER_REFLECT_TEXTURE (self)->priv; /* no need to paint stuff if we don't have a texture to reflect */ if (!clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self))) return; /* parent texture may have been hidden, there for need to make sure its * realised with resources available. */ parent_texture = CLUTTER_ACTOR (clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self))); if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture)) clutter_actor_realize (parent_texture); /* FIXME: figure out nicer way of getting at this info... */ if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE) && clutter_texture_is_tiled (CLUTTER_TEXTURE (parent_texture)) == FALSE) { target_type = CGL_TEXTURE_RECTANGLE_ARB; cogl_enable (CGL_ENABLE_TEXTURE_RECT | CGL_ENABLE_BLEND); } else { target_type = CGL_TEXTURE_2D; cogl_enable (CGL_ENABLE_TEXTURE_2D|CGL_ENABLE_BLEND); } cogl_push_matrix (); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4ub (255, 255, 255, clutter_actor_get_opacity (self)); clutter_actor_get_coords (self, &x1, &y1, &x2, &y2); /* Parent paint translated us into position */ reflect_texture_render_to_gl_quad (CLUTTER_REFLECT_TEXTURE (self), 0, 0, x2 - x1, y2 - y1); cogl_pop_matrix (); }
static void aisleriot_card_paint (ClutterActor *actor) { AisleriotCard *card = (AisleriotCard *) actor; AisleriotCardPrivate *priv = card->priv; CoglHandle top_tex, bottom_tex; ClutterActorBox alloc_box; cogl_enable_backface_culling (TRUE); top_tex = games_card_textures_cache_get_card_texture (priv->cache, priv->top_card); bottom_tex = games_card_textures_cache_get_card_texture (priv->cache, priv->bottom_card); if (G_UNLIKELY (top_tex == COGL_INVALID_HANDLE || bottom_tex == COGL_INVALID_HANDLE)) return; clutter_actor_get_allocation_box (actor, &alloc_box); /* Draw both sides of the card. Backface culling is enabled so only one side will actually be rendered */ cogl_set_source_texture (top_tex); cogl_rectangle (0.0f, 0.0f, CLUTTER_UNITS_TO_FLOAT (alloc_box.x2 - alloc_box.x1), CLUTTER_UNITS_TO_FLOAT (alloc_box.y2 - alloc_box.y1)); cogl_set_source_texture (bottom_tex); /* Rotate along the y-axis about the center of the card to make the bottom of the card face the other way */ cogl_push_matrix (); cogl_translate (CLUTTER_UNITS_TO_DEVICE (alloc_box.x2 - alloc_box.x1) / 2, 0, 0); cogl_rotate (180, 0, 1, 0); cogl_translate (-CLUTTER_UNITS_TO_DEVICE (alloc_box.x2 - alloc_box.x1) / 2, 0, 0); cogl_rectangle (0.0f, 0.0f, CLUTTER_UNITS_TO_FLOAT (alloc_box.x2 - alloc_box.x1), CLUTTER_UNITS_TO_FLOAT (alloc_box.y2 - alloc_box.y1)); cogl_pop_matrix (); cogl_enable_backface_culling (FALSE); }
static gboolean draw_rectangle (TestState *state, int x, int y, TestDepthState *rect_state) { guint8 Cr = MASK_RED (rect_state->color); guint8 Cg = MASK_GREEN (rect_state->color); guint8 Cb = MASK_BLUE (rect_state->color); guint8 Ca = MASK_ALPHA (rect_state->color); CoglHandle pipeline; CoglDepthState depth_state; cogl_depth_state_init (&depth_state); cogl_depth_state_set_test_enabled (&depth_state, rect_state->test_enable); cogl_depth_state_set_test_function (&depth_state, rect_state->test_function); cogl_depth_state_set_write_enabled (&depth_state, rect_state->write_enable); cogl_depth_state_set_range (&depth_state, rect_state->range_near, rect_state->range_far); pipeline = cogl_pipeline_new (); if (!cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL)) { cogl_object_unref (pipeline); return FALSE; } cogl_pipeline_set_color4ub (pipeline, Cr, Cg, Cb, Ca); cogl_set_source (pipeline); cogl_push_matrix (); cogl_translate (0, 0, rect_state->depth); cogl_rectangle (x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); cogl_pop_matrix (); cogl_object_unref (pipeline); return TRUE; }
static void paint_cb (ClutterActor *self, ClutterTimeline *tl) { gint paint_index = (clutter_timeline_get_progress (tl) * G_N_ELEMENTS (paint_func)); cogl_push_matrix (); paint_func[paint_index] (); cogl_translate (100, 100, 0); cogl_set_source_color4ub (0, 160, 0, 255); cogl_path_stroke_preserve (); cogl_translate (150, 0, 0); cogl_set_source_color4ub (200, 0, 0, 255); cogl_path_fill (); cogl_pop_matrix(); }
static void mx_tooltip_paint (ClutterActor *self) { MxTooltipPrivate *priv = MX_TOOLTIP (self)->priv; gfloat width, height; CoglHandle arrow_image; guint alpha; clutter_actor_get_size (self, &width, &height); width = (gint)(width / 2.f); height = (gint)(height / 2.f); alpha = clutter_actor_get_paint_opacity (self); cogl_push_matrix (); cogl_translate (priv->text_allocation.x1, priv->text_allocation.y1, 0); if (priv->border_image_texture) mx_texture_frame_paint_texture (priv->border_image_texture, alpha, priv->border_image->top, priv->border_image->right, priv->border_image->bottom, priv->border_image->left, priv->text_allocation.x2 - priv->text_allocation.x1, priv->text_allocation.y2 - priv->text_allocation.y1); cogl_pop_matrix (); arrow_image = mx_widget_get_background_texture (MX_WIDGET (self)); if (arrow_image && !priv->actor_below) { _mx_paint_texture_with_opacity (arrow_image, alpha, priv->arrow_box.x1, priv->arrow_box.y1, priv->arrow_box.x2 - priv->arrow_box.x1, priv->arrow_box.y2 - priv->arrow_box.y1); } clutter_actor_paint (priv->label); }
static void material_rectangle_paint (ClutterActor *actor, gpointer data) { TestMultiLayerMaterialState *state = data; cogl_push_matrix (); cogl_translate (150, 15, 0); cogl_set_source (state->material0); cogl_rectangle_with_multitexture_coords (0, 0, 200, 213, state->tex_coords, 12); cogl_translate (-300, -30, 0); cogl_set_source (state->material1); cogl_rectangle_with_multitexture_coords (0, 0, 200, 213, state->tex_coords, 12); cogl_pop_matrix (); }
static void shell_slicer_paint_child (ShellSlicer *self) { ClutterActor *child; ClutterActorBox self_box; ClutterActorBox child_box; float width, height, child_width, child_height; StAlign x_align, y_align; double x_align_factor, y_align_factor; child = st_bin_get_child (ST_BIN (self)); if (!child) return; st_bin_get_alignment (ST_BIN (self), &x_align, &y_align); _st_get_align_factors (x_align, y_align, &x_align_factor, &y_align_factor); clutter_actor_get_allocation_box (CLUTTER_ACTOR (self), &self_box); clutter_actor_get_allocation_box (child, &child_box); width = self_box.x2 - self_box.x1; height = self_box.y2 - self_box.y1; child_width = child_box.x2 - child_box.x1; child_height = child_box.y2 - child_box.y1; cogl_push_matrix (); cogl_clip_push_rectangle (0, 0, width, height); cogl_translate ((int)(0.5 + x_align_factor * (width - child_width)), (int)(0.5 + y_align_factor * (height - child_height)), 0); clutter_actor_paint (child); cogl_clip_pop (); cogl_pop_matrix (); }
static void on_paint (ClutterActor *actor, CallbackData *data) { int i; ClutterGeometry stage_size; gint hand_width, hand_height; GSList *node; clutter_actor_get_allocation_geometry (data->stage, &stage_size); hand_width = cogl_texture_get_width (data->hand); hand_height = cogl_texture_get_height (data->hand); /* Setup the clipping */ for (node = data->clips; node; node = node->next) { Clip *clip = (Clip *) node->data; if (clip->type == CLIP_RECTANGLE) cogl_clip_push_rectangle (clip->x1, clip->y1, clip->x2, clip->y2); else if (clip->type == CLIP_ROTATED_RECTANGLE) { float size = MIN (ABS (clip->x2 - clip->x1), ABS (clip->y2 - clip->y1)); int cx = (clip->x1 + clip->x2) / 2; int cy = (clip->y1 + clip->y2) / 2; size = sqrtf ((size / 2) * (size / 2) * 2); cogl_push_matrix (); /* Rotate 45° about the centre point */ cogl_translate (cx, cy, 0.0f); cogl_rotate (45.0f, 0.0f, 0.0f, 1.0f); cogl_clip_push_rectangle (-size / 2, -size / 2, size / 2, size / 2); cogl_pop_matrix (); } else { make_clip_path (clip); cogl_clip_push_from_path (); } } /* Draw a rectangle filling the entire stage */ cogl_set_source_color4ub (0x80, 0x80, 0xff, 0xff); cogl_rectangle (0, 0, stage_size.width, stage_size.height); draw_shapes (10, 10); /* Draw the hand at different rotations */ for (i = -2; i <= 2; i++) { cogl_push_matrix (); cogl_translate (stage_size.width / 2 + stage_size.width / 6 * i, stage_size.height / 2, 0); cogl_rotate (i * 40, 0, 1, 0); cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff); cogl_set_source_texture (data->hand); cogl_rectangle_with_texture_coords ((-hand_width / 2), (-hand_height / 2), (hand_width / 2), (hand_height / 2), 0, 0, 1, 1); cogl_pop_matrix (); } draw_shapes (stage_size.width - 310, stage_size.height - 110); /* Remove all of the clipping */ g_slist_foreach (data->clips, (GFunc) cogl_clip_pop, NULL); /* Draw the bounding box for each of the clips */ for (node = data->clips; node; node = node->next) { Clip *clip = (Clip *) node->data; make_clip_path (clip); cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff); cogl_path_stroke (); } /* Draw the bounding box for the pending new clip */ if (data->current_clip.type != CLIP_NONE) { make_clip_path (&data->current_clip); cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_path_stroke (); } }
static void clutter_reflect_texture_paint (ClutterActor *actor) { ClutterReflectTexturePrivate *priv; ClutterReflectTexture *texture; ClutterClone *clone; ClutterTexture *parent; guint width, height; gfloat fwidth, fheight; gint r_height; gint opacity; gint bottom; CoglHandle cogl_texture; CoglTextureVertex tvert[4]; CoglFixed rty; texture = CLUTTER_REFLECT_TEXTURE (actor); clone = CLUTTER_CLONE (actor); parent = (ClutterTexture*) clutter_clone_get_source (clone); if (!parent) return; if (!CLUTTER_ACTOR_IS_REALIZED (parent)) clutter_actor_realize (CLUTTER_ACTOR (parent)); cogl_texture = clutter_texture_get_cogl_texture (parent); if (cogl_texture == COGL_INVALID_HANDLE) return; priv = texture->priv; clutter_actor_get_size (CLUTTER_ACTOR(parent), &fwidth, &fheight); width = fwidth; height = fheight; if (!height) // probably won't happen, but just in case, to avoid divide by zero. return; r_height = priv->reflection_height; bottom = priv->reflect_bottom; opacity = clutter_actor_get_opacity(actor); if (r_height < 0 || r_height > height) r_height = height; #define FX(x) COGL_FIXED_FROM_INT(x) rty = COGL_FIXED_FAST_DIV(FX(bottom ? height-r_height : r_height),FX(height)); /* clockise vertices and tex coords and colors! */ tvert[0].x = tvert[0].y = tvert[0].z = 0; tvert[0].tx = 0; tvert[0].ty = bottom ? COGL_FIXED_1 : rty; tvert[0].color.red = tvert[0].color.green = tvert[0].color.blue = 0xff; tvert[0].color.alpha = bottom ? opacity : 0; tvert[1].x = FX(width); tvert[1].y = tvert[1].z = 0; tvert[1].tx = COGL_FIXED_1; tvert[1].ty = bottom ? COGL_FIXED_1 : rty; tvert[1].color.red = tvert[1].color.green = tvert[1].color.blue = 0xff; tvert[1].color.alpha = bottom ? opacity : 0; tvert[2].x = FX(width); tvert[2].y = FX(r_height); tvert[2].z = 0; tvert[2].tx = COGL_FIXED_1; tvert[2].ty = bottom ? rty : 0; tvert[2].color.red = tvert[2].color.green = tvert[2].color.blue = 0xff; tvert[2].color.alpha = bottom ? 0 : opacity; tvert[3].x = 0; tvert[3].y = FX(r_height); tvert[3].z = 0; tvert[3].tx = 0; tvert[3].ty = bottom ? rty : 0; tvert[3].color.red = tvert[3].color.green = tvert[3].color.blue = 0xff; tvert[3].color.alpha = bottom ? 0 : opacity; cogl_push_matrix (); cogl_set_source_texture(cogl_texture); /* FIXME: this does not work as expected */ /* cogl_polygon(tvert, 4, TRUE); */ cogl_pop_matrix (); }
static void tidy_texture_frame_paint (ClutterActor *self) { TidyTextureFramePrivate *priv; ClutterActor *parent_texture; guint width, height; gint pwidth, pheight, ex, ey; ClutterFixed tx1, ty1, tx2, ty2, tw, th; GLenum target_type; ClutterColor col = { 0xff, 0xff, 0xff, 0xff }; priv = TIDY_TEXTURE_FRAME (self)->priv; /* no need to paint stuff if we don't have a texture to reflect */ if (!clutter_clone_texture_get_parent_texture (CLUTTER_CLONE_TEXTURE(self))) return; /* parent texture may have been hidden, there for need to make sure its * realised with resources available. */ parent_texture = CLUTTER_ACTOR (clutter_clone_texture_get_parent_texture(CLUTTER_CLONE_TEXTURE(self))); if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture)) clutter_actor_realize (parent_texture); if (clutter_texture_is_tiled (CLUTTER_TEXTURE (parent_texture))) { g_warning("tiled textures not yet supported..."); return; } cogl_push_matrix (); #define FX(x) CLUTTER_INT_TO_FIXED(x) clutter_texture_get_base_size (CLUTTER_TEXTURE(parent_texture), &pwidth, &pheight); clutter_actor_get_size (self, &width, &height); tx1 = FX (priv->left); tx2 = FX (pwidth - priv->right); ty1 = FX (priv->top); ty2 = FX (pheight - priv->bottom); tw = FX (pwidth); th = FX (pheight); if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE)) { target_type = CGL_TEXTURE_RECTANGLE_ARB; cogl_enable (CGL_ENABLE_TEXTURE_RECT|CGL_ENABLE_BLEND); } else { target_type = CGL_TEXTURE_2D; cogl_enable (CGL_ENABLE_TEXTURE_2D|CGL_ENABLE_BLEND); tw = clutter_util_next_p2 (pwidth); th = clutter_util_next_p2 (pheight); tx1 = tx1/tw; tx2 = tx2/tw; ty1 = ty1/th; ty2 = ty2/th; tw = FX(pwidth)/tw; th = FX(pheight)/th; } col.alpha = clutter_actor_get_opacity (self); cogl_color (&col); clutter_texture_bind_tile (CLUTTER_TEXTURE(parent_texture), 0); ex = width - priv->right; if (ex < 0) ex = priv->right; /* FIXME */ ey = height - priv->bottom; if (ey < 0) ey = priv->bottom; /* FIXME */ /* top left corner */ cogl_texture_quad (0, priv->left, /* FIXME: clip if smaller */ 0, priv->top, 0, 0, tx1, ty1); /* top middle */ cogl_texture_quad (priv->left, ex, 0, priv->top, tx1, 0, tx2, ty1); /* top right */ cogl_texture_quad (ex, width, 0, priv->top, tx2, 0, tw, ty1); /* mid left */ cogl_texture_quad (0, priv->left, priv->top, ey, 0, ty1, tx1, ty2); /* center */ cogl_texture_quad (priv->left, ex, priv->top, ey, tx1, ty1, tx2, ty2); /* mid right */ cogl_texture_quad (ex, width, priv->top, ey, tx2, ty1, tw, ty2); /* bottom left */ cogl_texture_quad (0, priv->left, ey, height, 0, ty2, tx1, th); /* bottom center */ cogl_texture_quad (priv->left, ex, ey, height, tx1, ty2, tx2, th); /* bottom right */ cogl_texture_quad (ex, width, ey, height, tx2, ty2, tw, th); cogl_pop_matrix (); #undef FX }
static void test_rectangles (TestState *state) { #define RECT_WIDTH 5 #define RECT_HEIGHT 5 int x; int y; /* Should the rectangles be randomly positioned/colored/rotated? * * It could be good to develop equivalent GL and Cairo tests so we can * have a sanity check for our Cogl performance. * * The color should vary to check that we correctly batch color changes * The use of alpha should vary so we have a variation of which rectangles * require blending. * Should this be a random variation? * It could be good to experiment with focibly enabling blending for * rectangles that don't technically need it for the sake of extending * batching. E.g. if you a long run of interleved rectangles with every * other rectangle needing blending then it may be worth enabling blending * for all the rectangles to avoid the state changes. * The modelview should change between rectangles to check the software * transform codepath. * Should we group some rectangles under the same modelview? Potentially * we could avoid software transform for long runs of rectangles with the * same modelview. * */ for (y = 0; y < STAGE_HEIGHT; y += RECT_HEIGHT) { for (x = 0; x < STAGE_WIDTH; x += RECT_WIDTH) { cogl_push_matrix (); cogl_translate (x, y, 0); cogl_rotate (45, 0, 0, 1); cogl_set_source_color4f (1, (1.0f/STAGE_WIDTH)*y, (1.0f/STAGE_HEIGHT)*x, 1); cogl_rectangle (0, 0, RECT_WIDTH, RECT_HEIGHT); cogl_pop_matrix (); } } for (y = 0; y < STAGE_HEIGHT; y += RECT_HEIGHT) { for (x = 0; x < STAGE_WIDTH; x += RECT_WIDTH) { cogl_push_matrix (); cogl_translate (x, y, 0); cogl_rotate (0, 0, 0, 1); cogl_set_source_color4f (1, (1.0f/STAGE_WIDTH)*x, (1.0f/STAGE_HEIGHT)*y, (1.0f/STAGE_WIDTH)*x); cogl_rectangle (0, 0, RECT_WIDTH, RECT_HEIGHT); cogl_pop_matrix (); } } }
static void clutter_stage_glx_redraw (ClutterStageWindow *stage_window) { ClutterBackendX11 *backend_x11; ClutterBackendGLX *backend_glx; ClutterStageX11 *stage_x11; ClutterStageGLX *stage_glx; GLXDrawable drawable; unsigned int video_sync_count; gboolean may_use_clipped_redraw; gboolean use_clipped_redraw; CLUTTER_STATIC_TIMER (painting_timer, "Redrawing", /* parent */ "Painting actors", "The time spent painting actors", 0 /* no application private data */); CLUTTER_STATIC_TIMER (swapbuffers_timer, "Redrawing", /* parent */ "glXSwapBuffers", "The time spent blocked by glXSwapBuffers", 0 /* no application private data */); CLUTTER_STATIC_TIMER (blit_sub_buffer_timer, "Redrawing", /* parent */ "glx_blit_sub_buffer", "The time spent in _glx_blit_sub_buffer", 0 /* no application private data */); stage_x11 = CLUTTER_STAGE_X11 (stage_window); if (stage_x11->xwin == None) return; stage_glx = CLUTTER_STAGE_GLX (stage_window); backend_x11 = stage_x11->backend; backend_glx = CLUTTER_BACKEND_GLX (backend_x11); CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer); if (G_LIKELY (backend_glx->can_blit_sub_buffer) && /* NB: a zero width redraw clip == full stage redraw */ stage_glx->bounding_redraw_clip.width != 0 && /* some drivers struggle to get going and produce some junk * frames when starting up... */ G_LIKELY (stage_glx->frame_count > 3) && /* While resizing a window clipped redraws are disabled to avoid * artefacts. See clutter-event-x11.c:event_translate for a * detailed explanation */ G_LIKELY (stage_x11->clipped_redraws_cool_off == 0)) { may_use_clipped_redraw = TRUE; } else may_use_clipped_redraw = FALSE; if (may_use_clipped_redraw && G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS))) use_clipped_redraw = TRUE; else use_clipped_redraw = FALSE; if (use_clipped_redraw) { CLUTTER_NOTE (CLIPPING, "Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n", stage_glx->bounding_redraw_clip.x, stage_glx->bounding_redraw_clip.y, stage_glx->bounding_redraw_clip.width, stage_glx->bounding_redraw_clip.height); cogl_clip_push_window_rectangle (stage_glx->bounding_redraw_clip.x, stage_glx->bounding_redraw_clip.y, stage_glx->bounding_redraw_clip.width, stage_glx->bounding_redraw_clip.height); _clutter_stage_do_paint (stage_x11->wrapper, &stage_glx->bounding_redraw_clip); cogl_clip_pop (); } else { CLUTTER_NOTE (CLIPPING, "Unclipped stage paint\n"); _clutter_stage_do_paint (stage_x11->wrapper, NULL); } if (may_use_clipped_redraw && G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))) { static CoglMaterial *outline = NULL; ClutterGeometry *clip = &stage_glx->bounding_redraw_clip; ClutterActor *actor = CLUTTER_ACTOR (stage_x11->wrapper); CoglHandle vbo; float x_1 = clip->x; float x_2 = clip->x + clip->width; float y_1 = clip->y; float y_2 = clip->y + clip->height; float quad[8] = { x_1, y_1, x_2, y_1, x_2, y_2, x_1, y_2 }; CoglMatrix modelview; if (outline == NULL) { outline = cogl_material_new (); cogl_material_set_color4ub (outline, 0xff, 0x00, 0x00, 0xff); } vbo = cogl_vertex_buffer_new (4); cogl_vertex_buffer_add (vbo, "gl_Vertex", 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, /* normalized */ 0, /* stride */ quad); cogl_vertex_buffer_submit (vbo); cogl_push_matrix (); cogl_matrix_init_identity (&modelview); _clutter_actor_apply_modelview_transform (actor, &modelview); cogl_set_modelview_matrix (&modelview); cogl_set_source (outline); cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_LINE_LOOP, 0 , 4); cogl_pop_matrix (); cogl_object_unref (vbo); } cogl_flush (); CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer); drawable = stage_glx->glxwin ? stage_glx->glxwin : stage_x11->xwin; /* If we might ever use _clutter_backend_glx_blit_sub_buffer then we * always need to keep track of the video_sync_count so that we can * throttle blits. * * Note: we get the count *before* we issue any glXCopySubBuffer or * blit_sub_buffer request in case the count would go up before * returning control to us. */ if (backend_glx->can_blit_sub_buffer && backend_glx->get_video_sync) backend_glx->get_video_sync (&video_sync_count); /* push on the screen */ if (use_clipped_redraw) { ClutterGeometry *clip = &stage_glx->bounding_redraw_clip; ClutterGeometry copy_area; ClutterActor *actor; CLUTTER_NOTE (BACKEND, "_glx_blit_sub_buffer (window: 0x%lx, " "x: %d, y: %d, " "width: %d, height: %d)", (unsigned long) drawable, stage_glx->bounding_redraw_clip.x, stage_glx->bounding_redraw_clip.y, stage_glx->bounding_redraw_clip.width, stage_glx->bounding_redraw_clip.height); /* XXX: It seems there will be a race here in that the stage * window may be resized before glXCopySubBufferMESA is handled * and so we may copy the wrong region. I can't really see how * we can handle this with the current state of X but at least * in this case a full redraw should be queued by the resize * anyway so it should only exhibit temporary artefacts. */ actor = CLUTTER_ACTOR (stage_x11->wrapper); copy_area.y = clutter_actor_get_height (actor) - clip->y - clip->height; copy_area.x = clip->x; copy_area.width = clip->width; copy_area.height = clip->height; /* glXCopySubBufferMESA and glBlitFramebuffer are not integrated * with the glXSwapIntervalSGI mechanism which we usually use to * throttle the Clutter framerate to the vertical refresh and so * we have to manually wait for the vblank period... */ /* Here 'is_synchronized' only means that the blit won't cause a * tear, ie it won't prevent multiple blits per retrace if they * can all be performed in the blanking period. If that's the * case then we still want to use the vblank sync menchanism but * we only need it to throttle redraws. */ if (!backend_glx->blit_sub_buffer_is_synchronized) { /* XXX: note that glXCopySubBuffer, at least for Intel, is * synchronized with the vblank but glBlitFramebuffer may * not be so we use the same scheme we do when calling * glXSwapBuffers without the swap_control extension and * call glFinish () before waiting for the vblank period. * * See where we call glXSwapBuffers for more details. */ glFinish (); wait_for_vblank (backend_glx); } else if (backend_glx->get_video_sync) { /* If we have the GLX_SGI_video_sync extension then we can * be a bit smarter about how we throttle blits by avoiding * any waits if we can see that the video sync count has * already progressed. */ if (backend_glx->last_video_sync_count == video_sync_count) wait_for_vblank (backend_glx); } else wait_for_vblank (backend_glx); CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer); _clutter_backend_glx_blit_sub_buffer (backend_glx, drawable, copy_area.x, copy_area.y, copy_area.width, copy_area.height); CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer); } else { CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)", backend_x11->xdpy, (unsigned long) drawable); /* If we have GLX swap buffer events then glXSwapBuffers will return * immediately and we need to track that there is a swap in * progress... */ if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)) stage_glx->pending_swaps++; if (backend_glx->vblank_type != CLUTTER_VBLANK_GLX_SWAP && backend_glx->vblank_type != CLUTTER_VBLANK_NONE) { /* If we are going to wait for VBLANK manually, we not only * need to flush out pending drawing to the GPU before we * sleep, we need to wait for it to finish. Otherwise, we * may end up with the situation: * * - We finish drawing - GPU drawing continues * - We go to sleep - GPU drawing continues * VBLANK - We call glXSwapBuffers - GPU drawing continues * - GPU drawing continues * - Swap buffers happens * * Producing a tear. Calling glFinish() first will cause us * to properly wait for the next VBLANK before we swap. This * obviously does not happen when we use _GLX_SWAP and let * the driver do the right thing */ glFinish (); wait_for_vblank (backend_glx); } CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer); glXSwapBuffers (backend_x11->xdpy, drawable); CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer); _cogl_swap_buffers_notify (); } backend_glx->last_video_sync_count = video_sync_count; /* reset the redraw clipping for the next paint... */ stage_glx->initialized_redraw_clip = FALSE; stage_glx->frame_count++; }
static CoglBool draw_rectangle (TestState *state, int x, int y, TestDepthState *rect_state, CoglBool legacy_mode) { uint8_t Cr = MASK_RED (rect_state->color); uint8_t Cg = MASK_GREEN (rect_state->color); uint8_t Cb = MASK_BLUE (rect_state->color); uint8_t Ca = MASK_ALPHA (rect_state->color); CoglPipeline *pipeline; CoglDepthState depth_state; cogl_depth_state_init (&depth_state); cogl_depth_state_set_test_enabled (&depth_state, rect_state->test_enable); cogl_depth_state_set_test_function (&depth_state, rect_state->test_function); cogl_depth_state_set_write_enabled (&depth_state, rect_state->write_enable); cogl_depth_state_set_range (&depth_state, rect_state->range_near, rect_state->range_far); pipeline = cogl_pipeline_new (test_ctx); if (!cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL)) { cogl_object_unref (pipeline); return FALSE; } if (!legacy_mode) { cogl_pipeline_set_color4ub (pipeline, Cr, Cg, Cb, Ca); cogl_framebuffer_set_depth_write_enabled (test_fb, rect_state->fb_write_enable); cogl_framebuffer_push_matrix (test_fb); cogl_framebuffer_translate (test_fb, 0, 0, rect_state->depth); cogl_framebuffer_draw_rectangle (test_fb, pipeline, x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); cogl_framebuffer_pop_matrix (test_fb); } else { cogl_push_framebuffer (test_fb); cogl_push_matrix (); cogl_set_source_color4ub (Cr, Cg, Cb, Ca); cogl_translate (0, 0, rect_state->depth); cogl_rectangle (x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); cogl_pop_matrix (); cogl_pop_framebuffer (); } cogl_object_unref (pipeline); return TRUE; }
static void on_paint (ClutterActor *actor, void *state) { float saved_viewport[4]; CoglMatrix saved_projection; CoglMatrix projection; CoglMatrix modelview; guchar *data; CoglHandle tex; CoglHandle offscreen; CoglColor black; float x0; float y0; float width; float height; /* for clearing the offscreen framebuffer to black... */ cogl_color_init_from_4ub (&black, 0x00, 0x00, 0x00, 0xff); cogl_get_viewport (saved_viewport); cogl_get_projection_matrix (&saved_projection); cogl_push_matrix (); cogl_matrix_init_identity (&projection); cogl_matrix_init_identity (&modelview); cogl_set_projection_matrix (&projection); cogl_set_modelview_matrix (&modelview); /* - Create a 100x200 viewport (i.e. smaller than the onscreen framebuffer) * and position it a (20, 10) inside the framebuffer. * - Fill the whole viewport with a purple rectangle * - Verify that the framebuffer is black with a 100x200 purple rectangle at * (20, 10) */ cogl_set_viewport (20, /* x */ 10, /* y */ 100, /* width */ 200); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* fill the viewport with purple.. */ cogl_set_source_color4ub (0xff, 0x00, 0xff, 0xff); cogl_rectangle (-1, 1, 1, -1); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0xff, 0x00, 0xff); /* - Create a viewport twice the size of the onscreen framebuffer with * a negative offset positioning it at (-20, -10) relative to the * buffer itself. * - Draw a 100x200 green rectangle at (40, 20) within the viewport (which * is (20, 10) within the framebuffer) * - Verify that the framebuffer is black with a 100x200 green rectangle at * (20, 10) */ cogl_set_viewport (-20, /* x */ -10, /* y */ FRAMEBUFFER_WIDTH * 2, /* width */ FRAMEBUFFER_HEIGHT * 2); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* draw a 100x200 green rectangle offset into the viewport such that its * top left corner should be found at (20, 10) in the offscreen buffer */ /* (offset 40 pixels right from the left of the viewport) */ x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f; /* (offset 20 pixels down from the top of the viewport) */ y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f; width = (1.0f / FRAMEBUFFER_WIDTH) * 100; height = (1.0f / FRAMEBUFFER_HEIGHT) * 200; cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff); cogl_rectangle (x0, y0, x0 + width, y0 - height); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0x00, 0xff, 0x00); /* - Create a 200x400 viewport and position it a (20, 10) inside the draw * buffer. * - Push a 100x200 window space clip rectangle at (20, 10) * - Fill the whole viewport with a blue rectangle * - Verify that the framebuffer is black with a 100x200 blue rectangle at * (20, 10) */ cogl_set_viewport (20, /* x */ 10, /* y */ 200, /* width */ 400); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); cogl_clip_push_window_rectangle (20, 10, 100, 200); /* fill the viewport with blue.. */ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff); cogl_rectangle (-1, 1, 1, -1); cogl_clip_pop (); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0x00, 0x00, 0xff); /* - Create a 200x400 viewport and position it a (20, 10) inside the draw * buffer. * - Push a 100x200 model space clip rectangle at (20, 10) in the viewport * (i.e. (40, 20) inside the framebuffer) * - Fill the whole viewport with a green rectangle * - Verify that the framebuffer is black with a 100x200 green rectangle at * (40, 20) */ cogl_set_viewport (20, /* x */ 10, /* y */ 200, /* width */ 400); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* figure out where to position our clip rectangle in model space * coordinates... */ /* (offset 40 pixels right from the left of the viewport) */ x0 = -1.0f + (2.0f / 200) * 20.f; /* (offset 20 pixels down from the top of the viewport) */ y0 = 1.0f - (2.0f / 400) * 10.0f; width = (2.0f / 200) * 100; height = (2.0f / 400) * 200; /* add the clip rectangle... */ cogl_push_matrix (); cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0); /* XXX: Rotate just enough to stop Cogl from converting our model space * rectangle into a window space rectangle.. */ cogl_rotate (0.1, 0, 0, 1); cogl_clip_push_rectangle (-(width/2.0), -(height/2.0), width/2.0, height/2.0); cogl_pop_matrix (); /* fill the viewport with green.. */ cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff); cogl_rectangle (-1, 1, 1, -1); cogl_clip_pop (); assert_rectangle_color_and_black_border (40, 20, 100, 200, 0x00, 0xff, 0x00); /* Set the viewport to something specific so we can verify that it gets * restored after we are done testing with an offscreen framebuffer... */ cogl_set_viewport (20, 10, 100, 200); /* * Next test offscreen drawing... */ data = g_malloc (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT); tex = cogl_texture_new_from_data (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888, /* data fmt */ COGL_PIXEL_FORMAT_ANY, /* internal fmt */ FRAMEBUFFER_WIDTH * 4, /* rowstride */ data); g_free (data); offscreen = cogl_offscreen_new_to_texture (tex); cogl_push_framebuffer (offscreen); /* - Create a 100x200 viewport (i.e. smaller than the offscreen framebuffer) * and position it a (20, 10) inside the framebuffer. * - Fill the whole viewport with a blue rectangle * - Verify that the framebuffer is black with a 100x200 blue rectangle at * (20, 10) */ cogl_set_viewport (20, /* x */ 10, /* y */ 100, /* width */ 200); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* fill the viewport with blue.. */ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff); cogl_rectangle (-1, 1, 1, -1); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0x00, 0x00, 0xff); /* - Create a viewport twice the size of the offscreen framebuffer with * a negative offset positioning it at (-20, -10) relative to the * buffer itself. * - Draw a 100x200 red rectangle at (40, 20) within the viewport (which * is (20, 10) within the framebuffer) * - Verify that the framebuffer is black with a 100x200 red rectangle at * (20, 10) */ cogl_set_viewport (-20, /* x */ -10, /* y */ FRAMEBUFFER_WIDTH * 2, /* width */ FRAMEBUFFER_HEIGHT * 2); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* draw a 100x200 red rectangle offset into the viewport such that its * top left corner should be found at (20, 10) in the offscreen buffer */ /* (offset 40 pixels right from the left of the viewport) */ x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f; /* (offset 20 pixels down from the top of the viewport) */ y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f; width = (1.0f / FRAMEBUFFER_WIDTH) * 100; height = (1.0f / FRAMEBUFFER_HEIGHT) * 200; cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_rectangle (x0, y0, x0 + width, y0 - height); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0xff, 0x00, 0x00); /* - Create a 200x400 viewport and position it a (20, 10) inside the draw * buffer. * - Push a 100x200 window space clip rectangle at (20, 10) * - Fill the whole viewport with a blue rectangle * - Verify that the framebuffer is black with a 100x200 blue rectangle at * (20, 10) */ cogl_set_viewport (20, /* x */ 10, /* y */ 200, /* width */ 400); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); cogl_clip_push_window_rectangle (20, 10, 100, 200); /* fill the viewport with blue.. */ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff); cogl_rectangle (-1, 1, 1, -1); cogl_clip_pop (); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0x00, 0x00, 0xff); /* - Create a 200x400 viewport and position it a (20, 10) inside the draw * buffer. * - Push a 100x200 model space clip rectangle at (20, 10) in the viewport * (i.e. (40, 20) inside the framebuffer) * - Fill the whole viewport with a green rectangle * - Verify that the framebuffer is black with a 100x200 green rectangle at * (40, 20) */ cogl_set_viewport (20, /* x */ 10, /* y */ 200, /* width */ 400); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* figure out where to position our clip rectangle in model space * coordinates... */ /* (offset 40 pixels right from the left of the viewport) */ x0 = -1.0f + (2.0f / 200) * 20.f; /* (offset 20 pixels down from the top of the viewport) */ y0 = 1.0f - (2.0f / 400) * 10.0f; width = (2.0f / 200) * 100; height = (2.0f / 400) * 200; /* add the clip rectangle... */ cogl_push_matrix (); cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0); /* XXX: Rotate just enough to stop Cogl from converting our model space * rectangle into a window space rectangle.. */ cogl_rotate (0.1, 0, 0, 1); cogl_clip_push_rectangle (-(width/2.0), -(height/2.0), width/2, height/2); cogl_pop_matrix (); /* fill the viewport with green.. */ cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff); cogl_rectangle (-1, 1, 1, -1); cogl_clip_pop (); assert_rectangle_color_and_black_border (40, 20, 100, 200, 0x00, 0xff, 0x00); /* Set the viewport to something obscure to verify that it gets * replace when we switch back to the onscreen framebuffer... */ cogl_set_viewport (0, 0, 10, 10); cogl_pop_framebuffer (); cogl_handle_unref (offscreen); /* * Verify that the previous onscreen framebuffer's viewport was restored * by drawing a white rectangle across the whole viewport. This should * draw a 100x200 rectangle at (20,10) relative to the onscreen draw * buffer... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff); cogl_rectangle (-1, 1, 1, -1); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0xff, 0xff, 0xff); /* Uncomment to display the last contents of the offscreen framebuffer */ #if 1 cogl_matrix_init_identity (&projection); cogl_matrix_init_identity (&modelview); cogl_set_viewport (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT); cogl_set_projection_matrix (&projection); cogl_set_modelview_matrix (&modelview); cogl_set_source_texture (tex); cogl_rectangle (-1, 1, 1, -1); #endif cogl_handle_unref (tex); /* Finally restore the stage's original state... */ cogl_pop_matrix (); cogl_set_projection_matrix (&saved_projection); cogl_set_viewport (saved_viewport[0], saved_viewport[1], saved_viewport[2], saved_viewport[3]); /* Comment this out if you want visual feedback of what this test * paints. */ clutter_main_quit (); }
static void _clutter_stage_wayland_repair_dirty(ClutterStageWayland *stage_wayland, ClutterStage *stage) { CoglMaterial *outline = NULL; CoglHandle vbo; float vertices[8], texcoords[8]; CoglMatrix modelview; cairo_region_t *dirty; cairo_rectangle_int_t rect; int i, count; float width, height; dirty = stage_wayland->back_buffer->dirty_region; stage_wayland->back_buffer->dirty_region = NULL; cairo_region_subtract (dirty, stage_wayland->repaint_region); width = stage_wayland->allocation.width; height = stage_wayland->allocation.height; /* If this is the first time we render, there is no front buffer to * copy back from, but then the dirty region not covered by the * repaint should be empty, because we repaint the entire stage. * * assert(stage_wayland->front_buffer != NULL) || * cairo_region_is_empty(dirty); * * FIXME: in test-rotate, the stage never queues a full repaint * initially, it's restricted to the paint box of it's rotating * children. */ if (!stage_wayland->front_buffer) return; outline = cogl_material_new (); cogl_material_set_layer (outline, 0, stage_wayland->front_buffer->tex); count = cairo_region_num_rectangles (dirty); for (i = 0; i < count; i++) { cairo_region_get_rectangle (dirty, i, &rect); vbo = cogl_vertex_buffer_new (4); vertices[0] = rect.x - 1; vertices[1] = rect.y - 1; vertices[2] = rect.x + rect.width + 1; vertices[3] = rect.y - 1; vertices[4] = rect.x + rect.width + 1; vertices[5] = rect.y + rect.height + 1; vertices[6] = rect.x - 1; vertices[7] = rect.y + rect.height + 1; cogl_vertex_buffer_add (vbo, "gl_Vertex", 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, /* normalized */ 0, /* stride */ vertices); texcoords[0] = vertices[0] / width; texcoords[1] = vertices[1] / height; texcoords[2] = vertices[2] / width; texcoords[3] = vertices[3] / height; texcoords[4] = vertices[4] / width; texcoords[5] = vertices[5] / height; texcoords[6] = vertices[6] / width; texcoords[7] = vertices[7] / height; cogl_vertex_buffer_add (vbo, "gl_MultiTexCoord0", 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, /* normalized */ 0, /* stride */ texcoords); cogl_vertex_buffer_submit (vbo); cogl_push_matrix (); cogl_matrix_init_identity (&modelview); _clutter_actor_apply_modelview_transform (CLUTTER_ACTOR (stage), &modelview); cogl_set_modelview_matrix (&modelview); cogl_set_source (outline); cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_TRIANGLE_FAN, 0 , 4); cogl_pop_matrix (); cogl_object_unref (vbo); } cairo_region_destroy (dirty); }
static void paint_test_backface_culling (TestState *state) { int draw_num; CoglPipeline *base_pipeline = cogl_pipeline_new (); CoglColor clear_color; cogl_ortho (0, state->width, /* left, right */ state->height, 0, /* bottom, top */ -1, 100 /* z near, far */); cogl_color_init_from_4ub (&clear_color, 0x00, 0x00, 0x00, 0xff); cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_STENCIL); cogl_pipeline_set_layer_texture (base_pipeline, 0, state->texture); cogl_pipeline_set_layer_filters (base_pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); /* Render the scene sixteen times to test all of the combinations of cull face mode, legacy state and winding orders */ for (draw_num = 0; draw_num < 16; draw_num++) { float x1 = 0, x2, y1 = 0, y2 = (float)(TEXTURE_RENDER_SIZE); CoglTextureVertex verts[4]; CoglPipeline *pipeline; cogl_push_matrix (); cogl_translate (0, TEXTURE_RENDER_SIZE * draw_num, 0); pipeline = cogl_pipeline_copy (base_pipeline); cogl_set_backface_culling_enabled (USE_LEGACY_STATE (draw_num)); cogl_pipeline_set_front_face_winding (pipeline, FRONT_WINDING (draw_num)); cogl_pipeline_set_cull_face_mode (pipeline, CULL_FACE_MODE (draw_num)); cogl_push_source (pipeline); memset (verts, 0, sizeof (verts)); x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a front-facing texture */ cogl_rectangle (x1, y1, x2, y2); x1 = x2; x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a front-facing texture with flipped texcoords */ cogl_rectangle_with_texture_coords (x1, y1, x2, y2, 1.0, 0.0, 0.0, 1.0); x1 = x2; x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a back-facing texture */ cogl_rectangle (x2, y1, x1, y2); x1 = x2; x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* If the texture is sliced then cogl_polygon doesn't work so we'll just use a solid color instead */ if (cogl_texture_is_sliced (state->texture)) cogl_set_source_color4ub (255, 0, 0, 255); /* Draw a front-facing polygon */ verts[0].x = x1; verts[0].y = y2; verts[1].x = x2; verts[1].y = y2; verts[2].x = x2; verts[2].y = y1; verts[3].x = x1; verts[3].y = y1; verts[0].tx = 0; verts[0].ty = 0; verts[1].tx = 1.0; verts[1].ty = 0; verts[2].tx = 1.0; verts[2].ty = 1.0; verts[3].tx = 0; verts[3].ty = 1.0; cogl_polygon (verts, 4, FALSE); x1 = x2; x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a back-facing polygon */ verts[0].x = x1; verts[0].y = y1; verts[1].x = x2; verts[1].y = y1; verts[2].x = x2; verts[2].y = y2; verts[3].x = x1; verts[3].y = y2; verts[0].tx = 0; verts[0].ty = 0; verts[1].tx = 1.0; verts[1].ty = 0; verts[2].tx = 1.0; verts[2].ty = 1.0; verts[3].tx = 0; verts[3].ty = 1.0; cogl_polygon (verts, 4, FALSE); x1 = x2; x2 = x1 + (float)(TEXTURE_RENDER_SIZE); cogl_pop_matrix (); cogl_pop_source (); cogl_object_unref (pipeline); } cogl_object_unref (base_pipeline); }