Заполнение Clutter Actor нестандартной формы холстом, нарисованным Cairo

Clutter 1.12
Cogl 1.10
Vala, C или Python.

У меня может быть фундаментальное недоразумение здесь —

Я думаю об «Актёрах» как о трехмерных многоугольниках. Я думаю об их цветах либо как цвета вершин, либо как наложение текстуры. В связи с этим я пытался нарисовать собственного Актера и заполнить его материалом, нарисованным через Cairo. Я никуда не денусь.

Код приведен ниже (на вале). Может ли кто-нибудь рассказать мне об основах Clutter (документы просто не сокращают его) или, если я близок, помогите мне заставить этот код работать.

Я ожидаю увидеть скругленный прямоугольник со смайликом внутри. Вместо этого я вижу заполнение пути Cogl, покрывающее* лицо. Я думаю, что paint() выполняется после drawme()

*Если вы установите Clutter.Color в "#0001" в методе paint(), вы увидите это.

/*

Clutter Actor with custom paint() and filled with a Cairo-drawn texture.
(NOT yet working.)

Compile with:

    valac \
  --pkg clutter-1.0 \
  --pkg cogl-1.0 \
    somename.vala

*/


public class SmileyRect : Clutter.Actor {

  //private vars
  private Clutter.Canvas _canvas;
  private bool _flip = false;
  private int _w = 300;
  private int _h = 300;

  //Constructor
  construct {
    _canvas = new Clutter.Canvas();
    _canvas.set_size( this._w, this._h );

    this.set_size( this._w, this._h );
    this.set_content( _canvas );

    //Connect to the draw signal - this is as-per Clutter docs.
    _canvas.draw.connect( drawme );

    //Make it reactive and connect to the button-press-event
    this.set_reactive( true );
    this.button_press_event.connect( button_press );
  }

  /*
    Button press signal handler.
    Changes the colour of what will be painted on the canvas.
  */
  private bool button_press ( Clutter.ButtonEvent evt ) {
    this._flip = !this._flip; //Jiggle a value.
    this.redraw(); // Forces re-run of the drawme() method.
    return true; //all done with this signal.
  }

  //Common function to draw Cogl stuff - used in paint and pick.
  private void draw_rr( Clutter.Color? color ) {
    if (color != null ) { Cogl.set_source_color4ub(color.red,color.green,color.blue,color.alpha); }
    Cogl.Path.round_rectangle( 0, 0, this._w, this._h, 15, 0.3f );
    Cogl.Path.close();

    // When from paint(): 
    // Is there some way to fill this Cogl path with the contents
    // of this._canvas? Or some other paradigm?
    if (color != null ) { Cogl.Path.fill(); }
  }

  /* Some kind of freaky, this magic paint() thing.
     Took me ages to get it running.
     I want to draw a rounded rectangle as the basic shape
     of this actor. 
  */
  public override void paint() {
    stdout.printf("paint runs.\n");
    // I did try a transparent color #0000 - just to see. No go.
    // #000f - draws a black rounded rect *OVER* the Cairo canvas. It covers
    // the smiley face.
    this.draw_rr( Clutter.Color.from_string("#0000") );
  }


  /* I followed paint() example, but the argument was tricky.
     I eventually found it from some PyClutter source code. 
  */
  public override void pick(Clutter.Color color) {
    stdout.printf("pick runs.\n");
    this.draw_rr( color );
  }

  /*
    Draws the Cairo art to the canvas.
    I want this art to be the bitmap/pixmap that *fills* the
    basic rounded rectangle shape of this actor.
    i.e I want the smile face cairo rectangle to be *within* the
    polygon that is draw via Cogl in paint() method.

    Does this even make sense?
  */
  private bool drawme( Cairo.Context ctx, int width, int height) {
    //Draw a rectangle
    double[] col;
    if (this._flip) {
      col = {1f,0f,0f};
      } 
    else {
      col = {0f,1f,0f};
    }

    ctx.set_source_rgb( col[0], col[1], col[2] );
    ctx.rectangle( 0, 0, width, height );
    ctx.fill();

    //Draw a smiley face.

    // Aside: Been trying to avoid all the weird casting of the floats/doubles used below
    // (see the generated c source.) Not at all sure what's going on there.
    // Also not sure about that 'f' on the numbers. Where/when do I have to use it?

    double pi = 3.14f;
    double w = (double) width;
    double h = (double) height;

    ctx.set_line_width( 6f );

    ctx.set_source_rgb( 0f, 0f, 0.8f );

    //eyes
    ctx.move_to( w/3f, h/3f );
    ctx.rel_line_to( 0f, h/6f );
    ctx.move_to(  2*(w/3f), h/3f );
    ctx.rel_line_to( 0f, h/6f );
    ctx.stroke();

    ctx.set_source_rgb( 1f, 1f, 0f );

    double rad = (w > h) ? h : w;
    //face
    ctx.arc( w/2f, h/2f, (rad/2f) - 20f,0f,2f * pi );
    ctx.stroke();
    //smile
    ctx.arc( w/2f, h/2f, (rad/3f) -10f, pi/3f, 2f * (pi/3f) );
    ctx.stroke();

    return true;
  }

  //Redraw - forces invalidate which trips the draw event
  public void redraw() {
    this._canvas.invalidate();
  }
} //end SmileyRect class



void main( string[] args ) {
  Clutter.init(ref args);

  var stage = new Clutter.Stage();
  stage.set_size(400,400);

  var rs = new SmileyRect();
  stage.add_child(rs);
  rs.redraw();

  stage.destroy.connect(Clutter.main_quit);
  stage.show();
  Clutter.main();

}

person Donn    schedule 23.04.2013    source источник
comment
Только что поговорил с разработчиками Clutter на #clutter. Новости смешанные. Кажется, у меня проблема с парадигмой, но было неясно, что это было. Также кажется, что Clutter как набор инструментов сталкивается с радикальными изменениями, которые могут сделать его нецелесообразным для моего предполагаемого использования. Похоже, нам нужно подождать, чтобы увидеть, как он объединится в Gnome и GTK в следующем году.   -  person Donn    schedule 23.04.2013
comment
Я не эксперт по беспорядку, но я думаю, что у Cultutter есть функции pre-paint и post-paint. Может быть, вам стоит взглянуть на эти.   -  person CYB3R    schedule 11.08.2015