static void penge_magic_texture_paint (ClutterActor *actor) { ClutterActorBox box; CoglHandle *material, *tex; float bw, bh; float aw, ah; float v; float tx1, tx2, ty1, ty2; guint8 alpha; clutter_actor_get_allocation_box (actor, &box); material = clutter_texture_get_cogl_material (CLUTTER_TEXTURE (actor)); tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (actor)); bw = (float) cogl_texture_get_width (tex); /* base texture width */ bh = (float) cogl_texture_get_height (tex); /* base texture height */ aw = (float) (box.x2 - box.x1); /* allocation width */ ah = (float) (box.y2 - box.y1); /* allocation height */ /* no comment */ if ((float)bw/bh < (float)aw/ah) { /* fit width */ v = (((float)ah * bw) / ((float)aw * bh)) / 2; tx1 = 0; tx2 = 1; ty1 = (0.5 - v); ty2 = (0.5 + v); } else { /* fit height */ v = (((float)aw * bh) / ((float)ah * bw)) / 2; tx1 = (0.5 - v); tx2 = (0.5 + v); ty1 = 0; ty2 = 1; } alpha = clutter_actor_get_paint_opacity (actor); cogl_material_set_color4ub (material, alpha, alpha, alpha, alpha); cogl_set_source (material); cogl_rectangle_with_texture_coords (0, 0, aw, ah, tx1, ty1, tx2, ty2); }
static void mx_fade_effect_paint_target (ClutterOffscreenEffect *effect) { guint8 opacity; CoglColor color; ClutterActor *actor; CoglMaterial *material = clutter_offscreen_effect_get_target (effect); MxFadeEffect *self = MX_FADE_EFFECT (effect); MxFadeEffectPrivate *priv = self->priv; if (priv->update_vbo) mx_fade_effect_update_vbo (self); if (!priv->vbo || !priv->indices || !material) return; /* Set the blend string if the material has changed so we can blend with * the paint opacity. */ if (material != priv->old_material) { GError *error = NULL; priv->old_material = material; if (!cogl_material_set_layer_combine (material, 1, "RGBA = MODULATE(PREVIOUS,CONSTANT)", &error)) { g_warning (G_STRLOC ": Error setting layer combine blend string: %s", error->message); g_error_free (error); } } /* Set the layer-combine constant so the texture is blended with the paint * opacity when painted. */ actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); opacity = clutter_actor_get_paint_opacity (actor); cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity); cogl_material_set_layer_combine_constant (material, 1, &color); /* Draw the texture */ cogl_set_source (material); cogl_vertex_buffer_draw_elements (priv->vbo, COGL_VERTICES_MODE_TRIANGLES, priv->indices, 0, (priv->n_quads * 4) - 1, 0, priv->n_quads * 6); }
static void paint_cb (ClutterActor *actor) { int stage_width = clutter_actor_get_width (actor); int stage_height = clutter_actor_get_height (actor); int image_width = cogl_texture_get_width (redhand); int image_height = cogl_texture_get_height (redhand); cogl_set_source (material); cogl_rectangle (stage_width/2.0f - image_width/2.0f, stage_height/2.0f - image_height/2.0f, stage_width/2.0f + image_width/2.0f, stage_height/2.0f + image_height/2.0f); }
static void mnb_spinner_paint (ClutterActor *self) { MnbSpinnerPrivate *priv = MNB_SPINNER (self)->priv; MxWidget *widget = MX_WIDGET (self); ClutterTexture *background; /* * This paints border-image. */ CLUTTER_ACTOR_CLASS (mnb_spinner_parent_class)->paint (self); if ((background = (ClutterTexture *) mx_widget_get_background_image (widget))) { gint tx_w, tx_h; gfloat tf_x, tf_y, tf_w, tf_h; guint8 opacity; ClutterActorBox box = { 0, }; CoglHandle material; if (!CLUTTER_IS_TEXTURE (background)) return; opacity = clutter_actor_get_paint_opacity (self); if (opacity == 0) return; clutter_texture_get_base_size (background, &tx_w, &tx_h); material = clutter_texture_get_cogl_material (background); cogl_material_set_color4ub (material, opacity, opacity, opacity, opacity); clutter_actor_get_allocation_box (self, &box); tf_x = (gfloat)priv->frame / (gfloat) priv->n_frames; tf_y = 0.0; tf_w = tf_x + 1.0 / priv->n_frames; tf_h = 1.0; /* Paint will have translated us */ cogl_set_source (material); cogl_rectangle_with_texture_coords (0.0, 0.0, box.x2 - box.x1, box.y2 - box.y1, tf_x, tf_y, tf_w, tf_h); } }
static void meta_background_actor_paint (ClutterActor *actor) { MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor); MetaBackgroundActorPrivate *priv = self->priv; guint8 opacity = clutter_actor_get_paint_opacity (actor); guint8 color_component; int width, height; meta_screen_get_size (priv->background->screen, &width, &height); color_component = (int)(0.5 + opacity * priv->dim_factor); cogl_material_set_color4ub (priv->material, color_component, color_component, color_component, opacity); cogl_set_source (priv->material); if (priv->visible_region) { int n_rectangles = cairo_region_num_rectangles (priv->visible_region); int i; for (i = 0; i < n_rectangles; i++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (priv->visible_region, i, &rect); cogl_rectangle_with_texture_coords (rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, rect.x / priv->background->texture_width, rect.y / priv->background->texture_height, (rect.x + rect.width) / priv->background->texture_width, (rect.y + rect.height) / priv->background->texture_height); } } else { cogl_rectangle_with_texture_coords (0.0f, 0.0f, width, height, 0.0f, 0.0f, width / priv->background->texture_width, height / priv->background->texture_height); } }
static void on_paint (ClutterActor *actor, TestState *state) { /* Draw a faded blue triangle */ cogl_vertex_buffer_enable (state->buffer, "gl_Color::blue"); cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_draw (state->buffer, GL_TRIANGLE_STRIP, /* mode */ 0, /* first */ 3); /* count */ /* Draw a red triangle */ /* Here we are testing that the disable attribute works; if it doesn't * the triangle will remain faded blue */ cogl_translate (100, 0, 0); cogl_vertex_buffer_disable (state->buffer, "gl_Color::blue"); cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_draw (state->buffer, GL_TRIANGLE_STRIP, /* mode */ 0, /* first */ 3); /* count */ /* Draw a faded blue triangle */ /* Here we are testing that the re-enable works; if it doesn't * the triangle will remain red */ cogl_translate (100, 0, 0); cogl_vertex_buffer_enable (state->buffer, "gl_Color::blue"); cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_draw (state->buffer, GL_TRIANGLE_STRIP, /* mode */ 0, /* first */ 3); /* count */ /* Draw a textured triangle */ cogl_translate (100, 0, 0); cogl_vertex_buffer_disable (state->buffer, "gl_Color::blue"); cogl_set_source (state->material); cogl_material_set_color4ub (state->material, 0xff, 0xff, 0xff, 0xff); cogl_vertex_buffer_draw (state->buffer, GL_TRIANGLE_STRIP, /* mode */ 0, /* first */ 3); /* count */ validate_result (state); }
void st_theme_node_transition_paint (StThemeNodeTransition *transition, ClutterActorBox *allocation, guint8 paint_opacity) { StThemeNodeTransitionPrivate *priv = transition->priv; CoglColor constant; float tex_coords[] = { 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, }; g_return_if_fail (ST_IS_THEME_NODE (priv->old_theme_node)); g_return_if_fail (ST_IS_THEME_NODE (priv->new_theme_node)); if (!clutter_actor_box_equal (allocation, &priv->last_allocation)) priv->needs_setup = TRUE; if (priv->needs_setup) { priv->last_allocation = *allocation; calculate_offscreen_box (transition, allocation); priv->needs_setup = !setup_framebuffers (transition, allocation); if (priv->needs_setup) /* setting up framebuffers failed */ return; } cogl_color_set_from_4f (&constant, 0., 0., 0., clutter_timeline_get_progress (priv->timeline)); cogl_material_set_layer_combine_constant (priv->material, 1, &constant); cogl_material_set_color4ub (priv->material, paint_opacity, paint_opacity, paint_opacity, paint_opacity); cogl_set_source (priv->material); cogl_rectangle_with_multitexture_coords (priv->offscreen_box.x1, priv->offscreen_box.y1, priv->offscreen_box.x2, priv->offscreen_box.y2, tex_coords, 8); }
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 aisleriot_slot_renderer_set_material_for_card (AisleriotSlotRenderer *srend, CoglHandle tex, gboolean show_highlight) { AisleriotSlotRendererPrivate *priv = srend->priv; guint8 opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (srend)); if (priv->material == COGL_INVALID_HANDLE) priv->material = cogl_material_new (); if (show_highlight) { CoglColor color; /* The previous code for drawing the highlight rendered the normal card texture and then rendered the card again multiplied by the highlight color but with 50% transparency. The blend function is alpha*src+(1-alpha*dst) where src is effectively the tex times the highlight color and the dst is the original tex. Therefore the final color is 0.5*tex+0.5*tex*highlight which is the same as (0.5+highlight/2)*tex. We can precompute that value to avoid having to draw the card twice */ cogl_color_set_from_4ub (&color, MIN (priv->highlight_color.red / 2 + 128, 0xff), MIN (priv->highlight_color.green / 2 + 128, 0xff), MIN (priv->highlight_color.blue / 2 + 128, 0xff), opacity); cogl_color_premultiply (&color); cogl_material_set_color (priv->material, &color); } else cogl_material_set_color4ub (priv->material, opacity, opacity, opacity, opacity); cogl_material_set_layer (priv->material, 0, tex); cogl_set_source (priv->material); }
void cogl_set_source_color (const CoglColor *color) { CoglPipeline *pipeline; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (cogl_color_get_alpha_byte (color) == 0xff) { cogl_pipeline_set_color (ctx->opaque_color_pipeline, color); pipeline = ctx->opaque_color_pipeline; } else { CoglColor premultiplied = *color; cogl_color_premultiply (&premultiplied); cogl_pipeline_set_color (ctx->blended_color_pipeline, &premultiplied); pipeline = ctx->blended_color_pipeline; } cogl_set_source (pipeline); }
static void trickplay_webgl_canvas_paint (ClutterActor *self) { ClutterTexture *texture = CLUTTER_TEXTURE (self); guint8 paint_opacity = clutter_actor_get_paint_opacity (self); CoglMaterial * material = ( CoglMaterial * ) clutter_texture_get_cogl_material( texture ); cogl_material_set_color4ub (material, paint_opacity, paint_opacity, paint_opacity, paint_opacity); cogl_set_source (material); ClutterActorBox box; clutter_actor_get_allocation_box (self, &box); cogl_rectangle_with_texture_coords ( 0 , 0 , box.x2 - box.x1 , box.y2 - box.y1 , 0, 1, 1, 0); }
void add_stencil_clip_rectangle (float x_1, float y_1, float x_2, float y_2, gboolean first) { CoglHandle current_source; CoglHandle framebuffer = _cogl_get_framebuffer (); _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* We don't log changes to the stencil buffer so need to flush any * batched geometry before we start... */ _cogl_journal_flush (); _cogl_framebuffer_flush_state (framebuffer, 0); /* temporarily swap in our special stenciling material */ current_source = cogl_handle_ref (ctx->source_material); cogl_set_source (ctx->stencil_material); if (first) { GE( glEnable (GL_STENCIL_TEST) ); /* Initially disallow everything */ GE( glClearStencil (0) ); GE( glClear (GL_STENCIL_BUFFER_BIT) ); /* Punch out a hole to allow the rectangle */ GE( glStencilFunc (GL_NEVER, 0x1, 0x1) ); GE( glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) ); cogl_rectangle (x_1, y_1, x_2, y_2); } else { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); /* Add one to every pixel of the stencil buffer in the rectangle */ GE( glStencilFunc (GL_NEVER, 0x1, 0x3) ); GE( glStencilOp (GL_INCR, GL_INCR, GL_INCR) ); cogl_rectangle (x_1, y_1, x_2, y_2); /* make sure our rectangle hits the stencil buffer before we * change the stencil operation */ _cogl_journal_flush (); /* Subtract one from all pixels in the stencil buffer so that only pixels where both the original stencil buffer and the rectangle are set will be valid */ GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) ); _cogl_matrix_stack_push (projection_stack); _cogl_matrix_stack_load_identity (projection_stack); _cogl_matrix_stack_push (modelview_stack); _cogl_matrix_stack_load_identity (modelview_stack); cogl_rectangle (-1.0, -1.0, 1.0, 1.0); _cogl_matrix_stack_pop (modelview_stack); _cogl_matrix_stack_pop (projection_stack); } /* make sure our rectangles hit the stencil buffer before we restore * the stencil function / operation */ _cogl_journal_flush (); /* Restore the stencil mode */ GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) ); GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) ); /* restore the original source material */ cogl_set_source (current_source); cogl_handle_unref (current_source); }
static void on_paint (ClutterActor *actor, TestState *state) { CoglHandle tex0, tex1; CoglHandle material; gboolean status; GError *error = NULL; float tex_coords[] = { 0, 0, 0.5, 0.5, /* tex0 */ 0.5, 0.5, 1, 1 /* tex1 */ }; /* XXX: * We haven't always had good luck with GL drivers implementing glReadPixels * reliably and skipping the first two frames improves our chances... */ if (state->frame++ <= 2) { g_usleep (G_USEC_PER_SEC); return; } tex0 = make_texture (0x00); tex1 = make_texture (0x11); material = cogl_material_new (); /* An arbitrary color which should be replaced by the first texture layer */ cogl_material_set_color4ub (material, 0x80, 0x80, 0x80, 0x80); cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL); cogl_material_set_layer (material, 0, tex0); cogl_material_set_layer_combine (material, 0, "RGBA = REPLACE (TEXTURE)", NULL); cogl_material_set_layer (material, 1, tex1); status = cogl_material_set_layer_combine (material, 1, "RGBA = ADD (PREVIOUS, TEXTURE)", &error); if (!status) { /* It's not strictly a test failure; you need a more capable GPU or * driver to test this texture combine string. */ g_debug ("Failed to setup texture combine string " "RGBA = ADD (PREVIOUS, TEXTURE): %s", error->message); } cogl_set_source (material); cogl_rectangle_with_multitexture_coords (0, 0, QUAD_WIDTH, QUAD_WIDTH, tex_coords, 8); cogl_handle_unref (material); cogl_handle_unref (tex0); cogl_handle_unref (tex1); /* See what we got... */ assert_region_color (0, 0, QUAD_WIDTH, QUAD_WIDTH, 0x55, 0x55, 0x55, 0x55); /* Comment this out if you want visual feedback for what this test paints */ #if 1 clutter_main_quit (); #endif }
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 gboolean cogl_create_context () { GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; gulong enable_flags = 0; CoglDrawBufferState *draw_buffer; if (_context != NULL) return FALSE; /* Allocate context memory */ _context = (CoglContext*) g_malloc (sizeof (CoglContext)); /* Init default values */ _context->feature_flags = 0; _context->features_cached = FALSE; _context->enable_flags = 0; _context->color_alpha = 0; _context->enable_backface_culling = FALSE; _context->indirect = gl_is_indirect; _context->default_material = cogl_material_new (); _context->source_material = NULL; _context->default_gl_texture_2d_tex = COGL_INVALID_HANDLE; _context->default_gl_texture_rect_tex = COGL_INVALID_HANDLE; _context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry)); _context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat)); _context->journal_vbo = 0; _context->journal_vbo_len = 0; _context->current_material = NULL; _context->current_material_flags = 0; memset (&_context->current_material_flush_options, 0, sizeof (CoglMaterialFlushOptions)); _context->current_layers = g_array_new (FALSE, FALSE, sizeof (CoglLayerInfo)); _context->n_texcoord_arrays_enabled = 0; draw_buffer = g_slice_new0 (CoglDrawBufferState); draw_buffer->target = COGL_WINDOW_BUFFER; draw_buffer->offscreen = COGL_INVALID_HANDLE; _context->draw_buffer_stack = g_slist_prepend (NULL, draw_buffer); _context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); _context->last_path = 0; _context->stencil_material = cogl_material_new (); _context->in_begin_gl_block = FALSE; _context->viewport_width = 0; _context->viewport_height = 0; _context->pf_glGenRenderbuffersEXT = NULL; _context->pf_glBindRenderbufferEXT = NULL; _context->pf_glRenderbufferStorageEXT = NULL; _context->pf_glGenFramebuffersEXT = NULL; _context->pf_glBindFramebufferEXT = NULL; _context->pf_glFramebufferTexture2DEXT = NULL; _context->pf_glFramebufferRenderbufferEXT = NULL; _context->pf_glCheckFramebufferStatusEXT = NULL; _context->pf_glDeleteFramebuffersEXT = NULL; _context->pf_glBlitFramebufferEXT = NULL; _context->pf_glRenderbufferStorageMultisampleEXT = NULL; _context->pf_glCreateProgramObjectARB = NULL; _context->pf_glCreateShaderObjectARB = NULL; _context->pf_glShaderSourceARB = NULL; _context->pf_glCompileShaderARB = NULL; _context->pf_glAttachObjectARB = NULL; _context->pf_glLinkProgramARB = NULL; _context->pf_glUseProgramObjectARB = NULL; _context->pf_glGetUniformLocationARB = NULL; _context->pf_glDeleteObjectARB = NULL; _context->pf_glGetInfoLogARB = NULL; _context->pf_glGetObjectParameterivARB = NULL; _context->pf_glUniform1fARB = NULL; _context->pf_glUniform2fARB = NULL; _context->pf_glUniform3fARB = NULL; _context->pf_glUniform4fARB = NULL; _context->pf_glUniform1fvARB = NULL; _context->pf_glUniform2fvARB = NULL; _context->pf_glUniform3fvARB = NULL; _context->pf_glUniform4fvARB = NULL; _context->pf_glUniform1iARB = NULL; _context->pf_glUniform2iARB = NULL; _context->pf_glUniform3iARB = NULL; _context->pf_glUniform4iARB = NULL; _context->pf_glUniform1ivARB = NULL; _context->pf_glUniform2ivARB = NULL; _context->pf_glUniform3ivARB = NULL; _context->pf_glUniform4ivARB = NULL; _context->pf_glUniformMatrix2fvARB = NULL; _context->pf_glUniformMatrix3fvARB = NULL; _context->pf_glUniformMatrix4fvARB = NULL; _context->pf_glDrawRangeElements = NULL; _context->pf_glActiveTexture = NULL; _context->pf_glClientActiveTexture = NULL; _context->pf_glBlendFuncSeparate = NULL; _context->pf_glBlendEquationSeparate = NULL; /* Initialise the clip stack */ _cogl_clip_stack_state_init (); /* Initialise matrix stack */ _cogl_current_matrix_state_init (); /* Create default textures used for fall backs */ _context->default_gl_texture_2d_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 0, /* auto calc row stride */ default_texture_data); _context->default_gl_texture_rect_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 0, /* auto calc row stride */ default_texture_data); cogl_set_source (_context->default_material); _cogl_material_flush_gl_state (_context->source_material, NULL); enable_flags = _cogl_material_get_cogl_enable_flags (_context->source_material); cogl_enable (enable_flags); _context->quad_indices_byte = COGL_INVALID_HANDLE; _context->quad_indices_short = COGL_INVALID_HANDLE; _context->quad_indices_short_len = 0; return TRUE; }
static gboolean cogl_create_context (void) { GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; unsigned long enable_flags = 0; CoglHandle window_buffer; if (_context != NULL) return FALSE; /* Allocate context memory */ _context = (CoglContext*) g_malloc (sizeof (CoglContext)); /* Init default values */ _context->feature_flags = 0; _context->features_cached = FALSE; /* Initialise the driver specific state */ /* TODO: combine these two into one function */ _cogl_create_context_driver (_context); _cogl_features_init (); _cogl_material_init_default_material (); _context->enable_flags = 0; _context->color_alpha = 0; _context->enable_backface_culling = FALSE; _context->flushed_front_winding = COGL_FRONT_WINDING_COUNTER_CLOCKWISE; _context->indirect = gl_is_indirect; cogl_matrix_init_identity (&_context->identity_matrix); cogl_matrix_init_identity (&_context->y_flip_matrix); cogl_matrix_scale (&_context->y_flip_matrix, 1, -1, 1); _context->flushed_matrix_mode = COGL_MATRIX_MODELVIEW; _context->texture_units = NULL; _context->simple_material = cogl_material_new (); _context->source_material = NULL; _context->default_gl_texture_2d_tex = COGL_INVALID_HANDLE; _context->default_gl_texture_rect_tex = COGL_INVALID_HANDLE; _context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry)); _context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat)); _context->current_material = NULL; _context->current_material_flags = 0; memset (&_context->current_material_flush_options, 0, sizeof (CoglMaterialFlushOptions)); _context->current_layers = g_array_new (FALSE, FALSE, sizeof (CoglLayerInfo)); _context->n_texcoord_arrays_enabled = 0; _context->framebuffer_stack = _cogl_create_framebuffer_stack (); window_buffer = _cogl_onscreen_new (); cogl_set_framebuffer (window_buffer); /* XXX: the deprecated _cogl_set_draw_buffer API expects to * find the window buffer here... */ _context->window_buffer = window_buffer; _context->dirty_bound_framebuffer = TRUE; _context->dirty_gl_viewport = TRUE; _context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); _context->last_path = 0; _context->stencil_material = cogl_material_new (); _context->in_begin_gl_block = FALSE; _context->quad_indices_byte = COGL_INVALID_HANDLE; _context->quad_indices_short = COGL_INVALID_HANDLE; _context->quad_indices_short_len = 0; _context->texture_download_material = COGL_INVALID_HANDLE; /* Create default textures used for fall backs */ _context->default_gl_texture_2d_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 0, /* auto calc row stride */ default_texture_data); _context->default_gl_texture_rect_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 0, /* auto calc row stride */ default_texture_data); cogl_set_source (_context->simple_material); _cogl_material_flush_gl_state (_context->source_material, NULL); enable_flags = _cogl_material_get_cogl_enable_flags (_context->source_material); cogl_enable (enable_flags); _cogl_flush_face_winding (); _context->atlas = NULL; _context->atlas_texture = COGL_INVALID_HANDLE; _context->current_pbo = NULL; _context->max_texture_units = -1; return TRUE; }
static void _clone_paint_cb (ClutterActor *actor) { ClutterActor *source; ClutterActorBox box; CoglHandle material; gfloat width, height; guint8 opacity; CoglColor color_1, color_2; CoglTextureVertex vertices[4]; /* if we don't have a source actor, don't paint */ source = clutter_clone_get_source (CLUTTER_CLONE (actor)); if (source == NULL) goto out; /* if the source texture does not have any content, don't paint */ material = clutter_texture_get_cogl_material (CLUTTER_TEXTURE (source)); if (material == NULL) goto out; /* get the size of the reflection */ clutter_actor_get_allocation_box (actor, &box); clutter_actor_box_get_size (&box, &width, &height); /* get the composite opacity of the actor */ opacity = clutter_actor_get_paint_opacity (actor); /* figure out the two colors for the reflection: the first is * full color and the second is the same, but at 0 opacity */ cogl_color_init_from_4f (&color_1, 1.0, 1.0, 1.0, opacity / 255.0); cogl_color_premultiply (&color_1); cogl_color_init_from_4f (&color_2, 1.0, 1.0, 1.0, 0.0); cogl_color_premultiply (&color_2); /* now describe the four vertices of the quad; since it has * to be a reflection, we need to invert it as well */ vertices[0].x = 0; vertices[0].y = 0; vertices[0].z = 0; vertices[0].tx = 0.0; vertices[0].ty = 1.0; vertices[0].color = color_1; vertices[1].x = width; vertices[1].y = 0; vertices[1].z = 0; vertices[1].tx = 1.0; vertices[1].ty = 1.0; vertices[1].color = color_1; vertices[2].x = width; vertices[2].y = height; vertices[2].z = 0; vertices[2].tx = 1.0; vertices[2].ty = 0.0; vertices[2].color = color_2; vertices[3].x = 0; vertices[3].y = height; vertices[3].z = 0; vertices[3].tx = 0.0; vertices[3].ty = 0.0; vertices[3].color = color_2; /* paint the same texture but with a different geometry */ cogl_set_source (material); cogl_polygon (vertices, 4, TRUE); out: /* prevent the default clone handler from running */ g_signal_stop_emission_by_name (actor, "paint"); }
static void paint (TestState *state) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); CoglTexture *tex; CoglColor color; CoglError *error = NULL; CoglHandle shader, program; cogl_color_init_from_4ub (&color, 0, 0, 0, 255); cogl_clear (&color, COGL_BUFFER_BIT_COLOR); /* Set the primary vertex color as red */ cogl_color_set_from_4ub (&color, 0xff, 0x00, 0x00, 0xff); cogl_pipeline_set_color (pipeline, &color); /* Override the vertex color in the texture environment with a constant green color provided by a texture */ tex = create_dummy_texture (); cogl_pipeline_set_layer_texture (pipeline, 0, tex); cogl_object_unref (tex); if (!cogl_pipeline_set_layer_combine (pipeline, 0, "RGBA=REPLACE(TEXTURE)", &error)) { g_warning ("Error setting layer combine: %s", error->message); g_assert_not_reached (); } /* Set up a dummy vertex shader that does nothing but the usual fixed function transform */ shader = cogl_create_shader (COGL_SHADER_TYPE_VERTEX); cogl_shader_source (shader, "void\n" "main ()\n" "{\n" " cogl_position_out = " "cogl_modelview_projection_matrix * " "cogl_position_in;\n" " cogl_color_out = cogl_color_in;\n" " cogl_tex_coord_out[0] = cogl_tex_coord_in;\n" "}\n"); cogl_shader_compile (shader); if (!cogl_shader_is_compiled (shader)) { char *log = cogl_shader_get_info_log (shader); g_warning ("Shader compilation failed:\n%s", log); g_free (log); g_assert_not_reached (); } program = cogl_create_program (); cogl_program_attach_shader (program, shader); cogl_program_link (program); cogl_handle_unref (shader); /* Draw something without the program */ cogl_set_source (pipeline); cogl_rectangle (0, 0, 50, 50); /* Draw it again using the program. It should look exactly the same */ cogl_pipeline_set_user_program (pipeline, program); cogl_handle_unref (program); cogl_rectangle (50, 0, 100, 50); cogl_pipeline_set_user_program (pipeline, COGL_INVALID_HANDLE); cogl_object_unref (pipeline); }
static void clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect) { ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect); ClutterDeformEffectPrivate *priv = self->priv; gboolean is_depth_enabled, is_cull_enabled; CoglHandle material; gint n_tiles; if (priv->is_dirty) { ClutterActor *actor; gfloat width, height; guint opacity; gint i, j; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); opacity = clutter_actor_get_paint_opacity (actor); /* if we don't have a target size, fall back to the actor's * allocation, though wrong it might be */ if (!clutter_offscreen_effect_get_target_size (effect, &width, &height)) clutter_actor_get_size (actor, &width, &height); for (i = 0; i < priv->y_tiles + 1; i++) { for (j = 0; j < priv->x_tiles + 1; j++) { CoglTextureVertex *vertex; vertex = &priv->vertices[(i * (priv->x_tiles + 1)) + j]; vertex->tx = (float) j / priv->x_tiles; vertex->ty = (float) i / priv->y_tiles; vertex->x = width * vertex->tx; vertex->y = height * vertex->ty; vertex->z = 0.0f; cogl_color_init_from_4ub (&vertex->color, 255, 255, 255, opacity); _clutter_deform_effect_deform_vertex (self, width, height, vertex); } } /* XXX in theory, the sub-classes should tell us what they changed * in the texture vertices; we then would be able to avoid resubmitting * the same data, if it did not change. for the time being, we resubmit * everything */ cogl_vertex_buffer_add (priv->vbo, "gl_Vertex", 3, COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, sizeof (CoglTextureVertex), &priv->vertices->x); cogl_vertex_buffer_add (priv->vbo, "gl_MultiTexCoord0", 2, COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, sizeof (CoglTextureVertex), &priv->vertices->tx); cogl_vertex_buffer_add (priv->vbo, "gl_Color", 4, COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE, FALSE, sizeof (CoglTextureVertex), &priv->vertices->color); priv->is_dirty = FALSE; } /* enable depth test, if it's not already enabled */ is_depth_enabled = cogl_get_depth_test_enabled (); if (!is_depth_enabled) cogl_set_depth_test_enabled (TRUE); /* enable backface culling if it's not already enabled and if * we have a back material */ is_cull_enabled = cogl_get_backface_culling_enabled (); if (priv->back_material != COGL_INVALID_HANDLE && !is_cull_enabled) cogl_set_backface_culling_enabled (TRUE); else if (priv->back_material == COGL_INVALID_HANDLE && is_cull_enabled) cogl_set_backface_culling_enabled (FALSE); n_tiles = (priv->x_tiles + 1) * (priv->y_tiles + 1); /* draw the front */ material = clutter_offscreen_effect_get_target (effect); if (material != COGL_INVALID_HANDLE) { cogl_set_source (material); cogl_vertex_buffer_draw_elements (priv->vbo, COGL_VERTICES_MODE_TRIANGLE_STRIP, priv->indices, 0, n_tiles, 0, priv->n_indices); } /* draw the back */ material = priv->back_material; if (material != COGL_INVALID_HANDLE) { cogl_set_source (priv->back_material); cogl_vertex_buffer_draw_elements (priv->vbo, COGL_VERTICES_MODE_TRIANGLE_STRIP, priv->back_indices, 0, n_tiles, 0, priv->n_indices); } /* restore the previous state */ if (!is_depth_enabled) cogl_set_depth_test_enabled (FALSE); if (priv->back_material != COGL_INVALID_HANDLE && !is_cull_enabled) cogl_set_backface_culling_enabled (FALSE); else if (priv->back_material == COGL_INVALID_HANDLE && is_cull_enabled) cogl_set_backface_culling_enabled (TRUE); }
static void mnb_toolbar_background_paint_background (MxWidget *self, ClutterActor *background, const ClutterColor *color) { MnbToolbarBackgroundPrivate *priv = TOOLBAR_BACKGROUND_PRIVATE (self); ClutterActor *actor = (ClutterActor *) self; CoglHandle cogl_texture, cogl_material; ClutterActorBox box = { 0, }; gfloat width, height; gfloat tex_width, tex_height; gfloat ex, ey; gfloat tx1, ty1, tx2, ty2; guint8 opacity; /* Copied from MxWidget: * * Default implementation just draws the background * colour and the image on top */ if (color && color->alpha != 0) { ClutterColor bg_color = *color; bg_color.alpha = clutter_actor_get_paint_opacity (actor) * bg_color.alpha / 255; clutter_actor_get_allocation_box (actor, &box); width = box.x2 - box.x1; height = box.y2 - box.y1; cogl_set_source_color4ub (bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha); cogl_rectangle (0, 0, width, height); } /* * Copied from MxTextureFrame */ /* no need to paint stuff if we don't have a texture */ if (G_UNLIKELY (priv->parent_texture == NULL)) return; cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture); if (cogl_texture == COGL_INVALID_HANDLE) return; cogl_material = clutter_texture_get_cogl_material (priv->parent_texture); if (cogl_material == COGL_INVALID_HANDLE) return; tex_width = cogl_texture_get_width (cogl_texture); tex_height = cogl_texture_get_height (cogl_texture); clutter_actor_get_allocation_box (actor, &box); width = box.x2 - box.x1; height = box.y2 - box.y1; opacity = clutter_actor_get_paint_opacity (actor); /* Paint using the parent texture's material. It should already have the cogl texture set as the first layer */ /* NB: for correct blending we need set a preumultiplied color here: */ cogl_material_set_color4ub (cogl_material, opacity, opacity, opacity, opacity); selector_texture = mnb_toolbar_get_selector_texture (priv->toolbar); cogl_material_set_layer (cogl_material, 1, selector_texture); cogl_material_set_layer_wrap_mode (cogl_material, 1, COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE); if (!cogl_material_set_layer_combine (cogl_material, 1, "RGBA = MODULATE(PREVIOUS,TEXTURE)", &error)) { g_warning (G_STRLOC ": Error setting layer combine blend string: %s", error->message); g_error_free (error); } cogl_set_source (cogl_material); /* simple stretch */ if (priv->left == 0 && priv->right == 0 && priv->top == 0 && priv->bottom == 0) { float spot_width, spot_height; float coords[8] = { 0, 0, 1, 1, 0, 0, 0, 0 }; mnb_toolbar_get_selector_allocation_box (priv->toolbar, &box); spot_width = box.x2 - box.x1; spot_height = box.y2 - box.y1; coords[4] = -(box.x1 / width) * (width / spot_width); coords[5] = -(box.y1 / height) * (height / spot_height); coords[6] = width / spot_width - (box.x1 / width) * (width / spot_width); coords[7] = height / spot_height - (box.y1 / height) * (height / spot_height); cogl_rectangle_with_multitexture_coords (0, 0, width, height, coords, 8); return; } tx1 = priv->left / tex_width; tx2 = (tex_width - priv->right) / tex_width; ty1 = priv->top / tex_height; ty2 = (tex_height - priv->bottom) / tex_height; ex = width - priv->right; if (ex < priv->left) ex = priv->left; ey = height - priv->bottom; if (ey < priv->top) ey = priv->top; { GLfloat rectangles[] = { /* top left corner */ 0, 0, priv->left, priv->top, 0.0, 0.0, tx1, ty1, /* top middle */ priv->left, 0, MAX (priv->left, ex), priv->top, tx1, 0.0, tx2, ty1, /* top right */ ex, 0, MAX (ex + priv->right, width), priv->top, tx2, 0.0, 1.0, ty1, /* mid left */ 0, priv->top, priv->left, ey, 0.0, ty1, tx1, ty2, /* center */ priv->left, priv->top, ex, ey, tx1, ty1, tx2, ty2, /* mid right */ ex, priv->top, MAX (ex + priv->right, width), ey, tx2, ty1, 1.0, ty2, /* bottom left */ 0, ey, priv->left, MAX (ey + priv->bottom, height), 0.0, ty2, tx1, 1.0, /* bottom center */ priv->left, ey, ex, MAX (ey + priv->bottom, height), tx1, ty2, tx2, 1.0, /* bottom right */ ex, ey, MAX (ex + priv->right, width), MAX (ey + priv->bottom, height), tx2, ty2, 1.0, 1.0 }; cogl_rectangles_with_texture_coords (rectangles, 9); } }
static void st_drawing_area_paint (ClutterActor *self) { StDrawingArea *area = ST_DRAWING_AREA (self); StDrawingAreaPrivate *priv = area->priv; StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self)); ClutterActorBox allocation_box; ClutterActorBox content_box; int width, height; CoglColor color; guint8 paint_opacity; (CLUTTER_ACTOR_CLASS (st_drawing_area_parent_class))->paint (self); clutter_actor_get_allocation_box (self, &allocation_box); st_theme_node_get_content_box (theme_node, &allocation_box, &content_box); width = (int)(0.5 + content_box.x2 - content_box.x1); height = (int)(0.5 + content_box.y2 - content_box.y1); if (priv->material == COGL_INVALID_HANDLE) priv->material = cogl_material_new (); if (priv->texture != COGL_INVALID_HANDLE && (width != cogl_texture_get_width (priv->texture) || height != cogl_texture_get_height (priv->texture))) { cogl_handle_unref (priv->texture); priv->texture = COGL_INVALID_HANDLE; } if (width > 0 && height > 0) { if (priv->texture == COGL_INVALID_HANDLE) { priv->texture = cogl_texture_new_with_size (width, height, COGL_TEXTURE_NONE, CLUTTER_CAIRO_FORMAT_ARGB32); priv->needs_repaint = TRUE; } if (priv->needs_repaint) { cairo_surface_t *surface; surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); priv->context = cairo_create (surface); priv->in_repaint = TRUE; priv->needs_repaint = FALSE; g_signal_emit ((GObject*)area, st_drawing_area_signals[REPAINT], 0); priv->in_repaint = FALSE; cairo_destroy (priv->context); priv->context = NULL; cogl_texture_set_region (priv->texture, 0, 0, 0, 0, width, height, width, height, CLUTTER_CAIRO_FORMAT_ARGB32, cairo_image_surface_get_stride (surface), cairo_image_surface_get_data (surface)); cairo_surface_destroy (surface); } } cogl_material_set_layer (priv->material, 0, priv->texture); if (priv->texture) { paint_opacity = clutter_actor_get_paint_opacity (self); cogl_color_set_from_4ub (&color, paint_opacity, paint_opacity, paint_opacity, paint_opacity); cogl_material_set_color (priv->material, &color); cogl_set_source (priv->material); cogl_rectangle_with_texture_coords (content_box.x1, content_box.y1, width, height, 0.0f, 0.0f, 1.0f, 1.0f); } }
static void on_paint (ClutterActor *actor, TestState *state) { CoglHandle tex0, tex1; CoglHandle material; gboolean status; GError *error = NULL; float tex_coords[] = { 0, 0, 0.5, 0.5, /* tex0 */ 0.5, 0.5, 1, 1 /* tex1 */ }; tex0 = make_texture (0x00); tex1 = make_texture (0x11); material = cogl_material_new (); /* An arbitrary color which should be replaced by the first texture layer */ cogl_material_set_color4ub (material, 0x80, 0x80, 0x80, 0x80); cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL); cogl_material_set_layer (material, 0, tex0); cogl_material_set_layer_combine (material, 0, "RGBA = REPLACE (TEXTURE)", NULL); /* We'll use nearest filtering mode on the textures, otherwise the edge of the quad can pull in texels from the neighbouring quarters of the texture due to imprecision */ cogl_material_set_layer_filters (material, 0, COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST); cogl_material_set_layer (material, 1, tex1); cogl_material_set_layer_filters (material, 1, COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST); status = cogl_material_set_layer_combine (material, 1, "RGBA = ADD (PREVIOUS, TEXTURE)", &error); if (!status) { /* It's not strictly a test failure; you need a more capable GPU or * driver to test this texture combine string. */ g_debug ("Failed to setup texture combine string " "RGBA = ADD (PREVIOUS, TEXTURE): %s", error->message); } cogl_set_source (material); cogl_rectangle_with_multitexture_coords (0, 0, QUAD_WIDTH, QUAD_WIDTH, tex_coords, 8); cogl_handle_unref (material); cogl_handle_unref (tex0); cogl_handle_unref (tex1); /* See what we got... */ assert_region_color (0, 0, QUAD_WIDTH, QUAD_WIDTH, 0x55, 0x55, 0x55, 0x55); /* Comment this out if you want visual feedback for what this test paints */ #if 1 clutter_main_quit (); #endif }
/* * Paints the provided texture frame trimming to the area indicated by padding. * * (Basically, we have one asset that gets split into two parts: an border area * that matches the padding, and the inside; MplPanelBackground paints the * latter, while the border is painted by the compositor as the window shadow.) */ static void mpl_panel_background_paint_border_image (CoglHandle *frame, MxPadding *padding) { CoglHandle cogl_texture = COGL_INVALID_HANDLE; CoglHandle cogl_material = COGL_INVALID_HANDLE; ClutterActorBox box = { 0, }; gfloat width, height; gfloat tex_width, tex_height; gfloat ex, ey; gfloat tx1, ty1, tx2, ty2; gfloat left = 4, right = 4 , top = 4, bottom =4; guint8 opacity; ClutterTexture *parent_texture; gfloat margin_l, margin_r, margin_t, margin_b; parent_texture = mx_texture_frame_get_parent_texture (frame); mx_texture_frame_get_border_values (frame, &top, &right, &bottom, &left); /* no need to paint stuff if we don't have a texture */ if (G_UNLIKELY (parent_texture == NULL)) return; /* parent texture may have been hidden, so need to make sure it gets * realized */ if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture)) clutter_actor_realize (CLUTTER_ACTOR (parent_texture)); cogl_texture = clutter_texture_get_cogl_texture (parent_texture); if (cogl_texture == COGL_INVALID_HANDLE) return; cogl_material = clutter_texture_get_cogl_material (parent_texture); if (cogl_material == COGL_INVALID_HANDLE) return; tex_width = cogl_texture_get_width (cogl_texture); tex_height = cogl_texture_get_height (cogl_texture); clutter_actor_get_allocation_box ((ClutterActor*) frame, &box); width = box.x2 - box.x1; height = box.y2 - box.y1; /* * These are the margins we are to trim expressed in texture coordinates. */ margin_l = padding->left / tex_width; margin_r = padding->right / tex_width; margin_t = padding->top / tex_height; margin_b = padding->bottom / tex_height; tx1 = left / tex_width; tx2 = (tex_width - right) / tex_width; ty1 = top / tex_height; ty2 = (tex_height - bottom) / tex_height; ex = width - right; if (ex < 0) ex = right; ey = height - bottom; if (ey < 0) ey = bottom; opacity = clutter_actor_get_paint_opacity ((ClutterActor*)frame); cogl_material_set_color4ub (cogl_material, opacity, opacity, opacity, opacity); cogl_set_source (cogl_material); cogl_material_set_layer_filters (cogl_material, 0, COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST); { GLfloat rectangles[] = { /* top left corner */ 0.0, 0.0, left, top, margin_l, margin_t, tx1, ty1, /* top middle */ left, 0.0, ex, top, tx1, margin_t, tx2, ty1, /* top right */ ex, 0.0, width, top, tx2, margin_t, 1.0 - margin_r, ty1, /* mid left */ 0.0, top, left, ey, margin_l, ty1, tx1, ty2, /* center */ left, top, ex, ey, tx1, ty1, tx2, ty2, /* mid right */ ex, top, width, ey, tx2, ty1, 1.0 - margin_r, ty2, /* bottom left */ 0.0, ey, left, height, margin_l, ty2, tx1, 1.0 - margin_b, /* bottom center */ left, ey, ex, height, tx1, ty2, tx2, 1.0 - margin_b, /* bottom right */ ex, ey, width, height, tx2, ty2, 1.0 - margin_r, 1.0 - margin_b }; cogl_rectangles_with_texture_coords (rectangles, 9); } }
/** * meta_shadow_paint: * @window_x: x position of the region to paint a shadow for * @window_y: y position of the region to paint a shadow for * @window_width: actual width of the region to paint a shadow for * @window_height: actual height of the region to paint a shadow for * @clip: (allow-none): if non-%NULL specifies the visible portion * of the shadow. * @clip_strictly: if %TRUE, drawing will be clipped strictly * to @clip, otherwise, it will be only used to optimize * drawing. * * Paints the shadow at the given position, for the specified actual * size of the region. (Since a #MetaShadow can be shared between * different sizes with the same extracted #MetaWindowShape the * size needs to be passed in here.) */ void meta_shadow_paint (MetaShadow *shadow, int window_x, int window_y, int window_width, int window_height, guint8 opacity, cairo_region_t *clip, gboolean clip_strictly) { float texture_width = cogl_texture_get_width (shadow->texture); float texture_height = cogl_texture_get_height (shadow->texture); int i, j; float src_x[4]; float src_y[4]; int dest_x[4]; int dest_y[4]; int n_x, n_y; cogl_material_set_color4ub (shadow->material, opacity, opacity, opacity, opacity); cogl_set_source (shadow->material); if (shadow->scale_width) { n_x = 3; src_x[0] = 0.0; src_x[1] = (shadow->inner_border_left + shadow->outer_border_left) / texture_width; src_x[2] = (texture_width - (shadow->inner_border_right + shadow->outer_border_right)) / texture_width; src_x[3] = 1.0; dest_x[0] = window_x - shadow->outer_border_left; dest_x[1] = window_x + shadow->inner_border_left; dest_x[2] = window_x + window_width - shadow->inner_border_right; dest_x[3] = window_x + window_width + shadow->outer_border_right; } else { n_x = 1; src_x[0] = 0.0; src_x[1] = 1.0; dest_x[0] = window_x - shadow->outer_border_left; dest_x[1] = window_x + window_width + shadow->outer_border_right; } if (shadow->scale_height) { n_y = 3; src_y[0] = 0.0; src_y[1] = (shadow->inner_border_top + shadow->outer_border_top) / texture_height; src_y[2] = (texture_height - (shadow->inner_border_bottom + shadow->outer_border_bottom)) / texture_height; src_y[3] = 1.0; dest_y[0] = window_y - shadow->outer_border_top; dest_y[1] = window_y + shadow->inner_border_top; dest_y[2] = window_y + window_height - shadow->inner_border_bottom; dest_y[3] = window_y + window_height + shadow->outer_border_bottom; } else { n_y = 1; src_y[0] = 0.0; src_y[1] = 1.0; dest_y[0] = window_y - shadow->outer_border_top; dest_y[1] = window_y + window_height + shadow->outer_border_bottom; } for (j = 0; j < n_y; j++) { cairo_rectangle_int_t dest_rect; dest_rect.y = dest_y[j]; dest_rect.height = dest_y[j + 1] - dest_y[j]; if (dest_rect.height == 0) continue; for (i = 0; i < n_x; i++) { cairo_region_overlap_t overlap; dest_rect.x = dest_x[i]; dest_rect.width = dest_x[i + 1] - dest_x[i]; if (dest_rect.width == 0) continue; if (clip) overlap = cairo_region_contains_rectangle (clip, &dest_rect); else overlap = CAIRO_REGION_OVERLAP_IN; /* There's quite a bit of overhead from allocating a new * region in order to find an exact intersection and * generating more geometry - we make the assumption that * unless we have to clip strictly it will be cheaper to * just draw the entire rectangle. */ if (overlap == CAIRO_REGION_OVERLAP_IN || (overlap == CAIRO_REGION_OVERLAP_PART && !clip_strictly)) { cogl_rectangle_with_texture_coords (dest_x[i], dest_y[j], dest_x[i + 1], dest_y[j + 1], src_x[i], src_y[j], src_x[i + 1], src_y[j + 1]); } else if (overlap == CAIRO_REGION_OVERLAP_PART) { cairo_region_t *intersection; int n_rectangles, k; intersection = cairo_region_create_rectangle (&dest_rect); cairo_region_intersect (intersection, clip); n_rectangles = cairo_region_num_rectangles (intersection); for (k = 0; k < n_rectangles; k++) { cairo_rectangle_int_t rect; float src_x1, src_x2, src_y1, src_y2; cairo_region_get_rectangle (intersection, k, &rect); /* Separately linear interpolate X and Y coordinates in the source * based on the destination X and Y coordinates */ src_x1 = (src_x[i] * (dest_rect.x + dest_rect.width - rect.x) + src_x[i + 1] * (rect.x - dest_rect.x)) / dest_rect.width; src_x2 = (src_x[i] * (dest_rect.x + dest_rect.width - (rect.x + rect.width)) + src_x[i + 1] * (rect.x + rect.width - dest_rect.x)) / dest_rect.width; src_y1 = (src_y[j] * (dest_rect.y + dest_rect.height - rect.y) + src_y[j + 1] * (rect.y - dest_rect.y)) / dest_rect.height; src_y2 = (src_y[j] * (dest_rect.y + dest_rect.height - (rect.y + rect.height)) + src_y[j + 1] * (rect.y + rect.height - dest_rect.y)) / dest_rect.height; cogl_rectangle_with_texture_coords (rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, src_x1, src_y1, src_x2, src_y2); } cairo_region_destroy (intersection); } } } }
static void mnb_toolbar_shadow_paint (ClutterActor *self) { MnbToolbarShadowPrivate *priv = MNB_TOOLBAR_SHADOW (self)->priv; CoglHandle cogl_texture = COGL_INVALID_HANDLE; CoglHandle cogl_material = COGL_INVALID_HANDLE; ClutterActorBox box = { 0, }; gfloat width, height; gfloat tex_width, tex_height; gfloat ex, ey; gfloat tx1, ty1, tx2, ty2; guint8 opacity; /* no need to paint stuff if we don't have a texture */ if (G_UNLIKELY (priv->parent_texture == NULL)) return; /* parent texture may have been hidden, so need to make sure it gets * realized */ if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_texture)) clutter_actor_realize (CLUTTER_ACTOR (priv->parent_texture)); cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture); if (cogl_texture == COGL_INVALID_HANDLE) return; cogl_material = clutter_texture_get_cogl_material (priv->parent_texture); if (cogl_material == COGL_INVALID_HANDLE) return; tex_width = cogl_texture_get_width (cogl_texture); tex_height = cogl_texture_get_height (cogl_texture); clutter_actor_get_allocation_box (self, &box); width = box.x2 - box.x1; height = box.y2 - box.y1; opacity = clutter_actor_get_paint_opacity (self); /* Paint using the parent texture's material. It should already have the cogl texture set as the first layer */ /* NB: for correct blending we need set a preumultiplied color here: */ cogl_material_set_color4ub (cogl_material, opacity, opacity, opacity, opacity); #if TOOLBAR_CUT_OUT selector_texture = mnb_toolbar_get_selector_texture (priv->toolbar); cogl_material_set_layer (cogl_material, 1, selector_texture); cogl_material_set_layer_wrap_mode (cogl_material, 1, COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE); if (!cogl_material_set_layer_combine (cogl_material, 1, "RGBA = MODULATE(PREVIOUS,TEXTURE)", &error)) { g_warning (G_STRLOC ": Error setting layer combine blend string: %s", error->message); g_error_free (error); } #endif cogl_set_source (cogl_material); /* simple stretch */ if (priv->left == 0 && priv->right == 0 && priv->top == 0 && priv->bottom == 0) { #if TOOLBAR_CUT_OUT float spot_width, spot_height; float coords[8] = { 0, 0, 1, 1, 0, 0, 0, 0 }; mnb_toolbar_get_selector_allocation_box (priv->toolbar, &box); spot_width = box.x2 - box.x1; spot_height = box.y2 - box.y1; coords[4] = -(box.x1 / width) * (width / spot_width); coords[5] = -(box.y1 + SHADOW_CUT_OUT_OFFSET / height) * (height / spot_height); coords[6] = width / spot_width - (box.x1 / width) * (width / spot_width); coords[7] = height / spot_height - (box.y1 + SHADOW_CUT_OUT_OFFSET / height) * (height / spot_height); cogl_rectangle_with_multitexture_coords (0, 0, width, height, coords, 8); #else cogl_rectangle (0, 0, width, height); #endif /* TOOLBAR_CUT_OUT */ return; } tx1 = priv->left / tex_width; tx2 = (tex_width - priv->right) / tex_width; ty1 = priv->top / tex_height; ty2 = (tex_height - priv->bottom) / tex_height; ex = width - priv->right; if (ex < priv->left) ex = priv->left; ey = height - priv->bottom; if (ey < priv->top) ey = priv->top; { GLfloat rectangles[] = { /* top left corner */ 0, 0, priv->left, priv->top, 0.0, 0.0, tx1, ty1, /* top middle */ priv->left, 0, MAX (priv->left, ex), priv->top, tx1, 0.0, tx2, ty1, /* top right */ ex, 0, MAX (ex + priv->right, width), priv->top, tx2, 0.0, 1.0, ty1, /* mid left */ 0, priv->top, priv->left, ey, 0.0, ty1, tx1, ty2, /* center */ priv->left, priv->top, ex, ey, tx1, ty1, tx2, ty2, /* mid right */ ex, priv->top, MAX (ex + priv->right, width), ey, tx2, ty1, 1.0, ty2, /* bottom left */ 0, ey, priv->left, MAX (ey + priv->bottom, height), 0.0, ty2, tx1, 1.0, /* bottom center */ priv->left, ey, ex, MAX (ey + priv->bottom, height), tx1, ty2, tx2, 1.0, /* bottom right */ ex, ey, MAX (ex + priv->right, width), MAX (ey + priv->bottom, height), tx2, ty2, 1.0, 1.0 }; cogl_rectangles_with_texture_coords (rectangles, 9); } }
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 mx_texture_frame_paint_texture_internal (CoglHandle material, CoglHandle texture, guint8 opacity, gfloat top, gfloat right, gfloat bottom, gfloat left, gfloat width, gfloat height) { gfloat tex_width, tex_height; gfloat ex, ey; gfloat tx1, ty1, tx2, ty2; /* apply opacity */ cogl_material_set_color4ub (material, opacity, opacity, opacity, opacity); /* add the texture */ cogl_material_set_layer (material, 0, texture); /* set the source */ cogl_set_source (material); tex_width = cogl_texture_get_width (texture); tex_height = cogl_texture_get_height (texture); /* simple stretch */ if (left == 0 && right == 0 && top == 0 && bottom == 0) { cogl_rectangle (0, 0, width, height); return; } tx1 = left / tex_width; tx2 = (tex_width - right) / tex_width; ty1 = top / tex_height; ty2 = (tex_height - bottom) / tex_height; ex = width - right; if (ex < left) ex = left; ey = height - bottom; if (ey < top) ey = top; { float rectangles[] = { /* top left corner */ 0, 0, left, top, 0.0, 0.0, tx1, ty1, /* top middle */ left, 0, MAX (left, ex), top, tx1, 0.0, tx2, ty1, /* top right */ ex, 0, MAX (ex + right, width), top, tx2, 0.0, 1.0, ty1, /* mid left */ 0, top, left, ey, 0.0, ty1, tx1, ty2, /* center */ left, top, ex, ey, tx1, ty1, tx2, ty2, /* mid right */ ex, top, MAX (ex + right, width), ey, tx2, ty1, 1.0, ty2, /* bottom left */ 0, ey, left, MAX (ey + bottom, height), 0.0, ty2, tx1, 1.0, /* bottom center */ left, ey, ex, MAX (ey + bottom, height), tx1, ty2, tx2, 1.0, /* bottom right */ ex, ey, MAX (ex + right, width), MAX (ey + bottom, height), tx2, ty2, 1.0, 1.0 }; cogl_rectangles_with_texture_coords (rectangles, 9); } }