3 Replies Latest reply on Apr 9, 2012 2:49 AM by shachar carmi

    Quartz and Quickdraw with MacOS

    salvati marc Newcomer

      Hello guys,

      long time no posts...


      I m trying to make my plugins running on Windows and Mac.

      Basically it works... except for the UI part.

      As for drawing rectangle and so on... i succeded to do it with quickdraw until CS4 and with drawBot with CS5

      My problem is for circular handles, that i want to get stretched, rotated according to the Layer scale, rotation, zoom factor...

      With windows, I succeed to get my stuff done using GDI+




          PF_FloatMatrix&            xform,

          const PF_InData        *in_data,

          const PF_EventExtra    *event_extra)


          event_extra->cbs.get_layer2comp_xform(event_extra->cbs.refcon, event_extra->contextH, in_data->current_time, in_data->time_scale, &xform);

          //need to nullify the translation column?



          //! Transforms the source coordinates in the current context to screen coordinates.

          //! Screen (frame) coordinates are affected by the current zoom level.

          PF_FixedPoint scale = { INT2FIX(1), INT2FIX(1) };

          event_extra->cbs.source_to_frame(event_extra->cbs.refcon, event_extra->contextH, &scale);


          float scaleX = static_cast<float>(FIX_2_FLOAT(scale.x));

          float scaleY = static_cast<float>(FIX_2_FLOAT(scale.y));


          xform.mat[0][0] *= scaleX;

          xform.mat[0][1] *= scaleY;

          xform.mat[1][0] *= scaleX;

          xform.mat[1][1] *= scaleY;

          xform.mat[2][0] *= scaleX;

          xform.mat[2][1] *= scaleY;



           PF_FixedPoint center ={cx ,cy};

           PF_FloatMatrix xform;       

           getLayer2FrameMatrix(xform, in_data, event_extraP);

               HDC hdc;

              PF_GET_CGRAF_DATA((*(event_extraP->contextH))->cgrafptr, PF_CGrafData_HDC, reinterpret_cast<void**>(&hdc));

              Gdiplus::Graphics g(hdc);

              Gdiplus::Pen pen(Gdiplus::Color(color.alpha, color.red, color.green, color.blue), 1);


              Gdiplus::Matrix mat(xform.mat[0][0], xform.mat[0][1], xform.mat[1][0], xform.mat[1][1], xform.mat[2][0], xform.mat[2][1]);



              g.DrawEllipse(&pen, center.x-cr, center.y-cr, cr+cr, cr+cr);



      This is ok for windows and make the deal.


      My problem occurs when i do it with Mac...

      Of course drawbot with CS5 works perfectly. My problem is for anterior version of after effects.


      With quickdraw there is no ways to make like with GDI+ and specify a matrix.

      So I have two solution:

      1) compute transform matrix, computing all the point of my circle, transform them with a transformation matrix, use the PaintPoly and FillPoly function

      2) use Quartz and its context transformation matrix...


      I thought that Quartz would work perfectly and simply...

      but i was wrong.

      The coordinate system is different....

      Y is inverted, and the origin is not top left, but bottom left.

      I tried to make it work anyways... but it did not...

      So i just tried to understand what s happening. I tried to paint a rectangle at the origin of the coordinate system:


      void *dp = (*(event_extraP->contextH))->cgrafptr;

      CGrafPtr port = reinterpret_cast<CGrafPtr>(dp);

      CGContextRef context;

      OSStatus err = QDBeginCGContext (port, &context);

      if (err== noErr){

                  CGRect rect = CGRectMake ( 0,0,100,100);      

                  CGAffineTransform userToDevice = CGContextGetUserSpaceToDeviceSpaceTransform (context);

                  CGAffineTransform deviceToUser = CGAffineTransformInvert ( userToDevice);

                  CGContextSetRGBFillColor (context, 1, 0, 0, 1);

                  CGContextFillRect (context,rect)

                  QDEndCGContext (port, &context);    



      I get a red rectangle... but not on the top or bottom left corner, kind of in the middle of theleft edge of the layer...


      Then I tried to go back to more basics  and tried

      CGAffineTransform userToDevice = CGContextGetUserSpaceToDeviceSpaceTransform (context);
      CGAffineTransform deviceToUser = CGAffineTransformInvert ( userToDevice);

      to transform my rectangle, and i got in the top left corner of the panel containing the layer panel.

      That would be helpfull if I could get the top left corner of the layer panel... But I did not find a way to get it

      source_to_frame gives only zoom factor


      layer_to_comp get the transformation into the layer panel...


      I m really thinking about going back to the solution 1)...


      Does anyone have any idea of how to use properly quartz inside after effects?



      Sorry for the vague of my question.

        • 1. Re: Quartz and Quickdraw with MacOS
          shachar carmi Rockstar

          i hear your pain.

          seriously, i do.


          this is what i did to solve it. (after almost giving up)


          CGPoint zero = {0,0};

          CGPoint flipOrigin = CGContextConvertPointToUserSpace(context, zero);

          flippedY = flipOrigin.y - (originaY - event_extraP->u.draw.update_rect.top);


          i changed the param names to such that would make sense to you.

          i hope i didn't screw it up while changing.

          you need to get flipOrigin only once per draw call, and not for each drawing operation you do. (but that's obvious)


          • 2. Re: Quartz and Quickdraw with MacOS
            salvati marc Newcomer

            As always Shachar, you are saving me. I finally could get my piece of drawing to get the expected result.

            To make it work perfectly, I needed  to include the Y inversion in the context matrix, as well as the translation transformation.

            For information, I attach the piece of code to write a circle at one position in the screen, accounting for scale, rotation and layer position (which means it get to look like an ellipse after transformation).

            Thank you again for your help.


                    PF_FloatMatrix xform;

                    getLayer2FrameMatrix(xform, in_data, event_extraP);

                    void *dp = (*(event_extraP->contextH))->cgrafptr;

                    CGrafPtr port = reinterpret_cast<CGrafPtr>(dp);

                    CGContextRef context;

                    OSStatus err = QDBeginCGContext (port, &context);

                    if (err== noErr){

                        float a = xform.mat[0][0];

                        float b = xform.mat[0][1];

                        float c = xform.mat[1][0];

                        float d = xform.mat[1][1];

                        float tx = xform.mat[2][0];

                        float ty = xform.mat[2][1];


                        CGPoint origin = CGPointMake(0,0);

                        CGPoint originFlipped = CGContextConvertPointToUserSpace(context, origin);

                        CGAffineTransform trans =  CGAffineTransformMake (a, -b, c, -d, tx, originFlipped.y - (ty - event_extraP->u.draw.update_rect.top)); 

                        CGContextConcatCTM (context, trans);           

                        CGRect rect =  CGRectMake ( center.x  -cr, center.y - cr,2*cr,2*cr);

                        CGContextAddEllipseInRect(context, rect);

                        CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);



                        QDEndCGContext (port, &context);    


            • 3. Re: Quartz and Quickdraw with MacOS
              shachar carmi Rockstar

              no problem man.

              i'm just glad that my sorrow brought joy to someone.




              kudos to you for posting your full solution code!

              that's how real contribution to the common knowledge looks like!