Home > Delphi > Adjustable clipping for pixelrage

Adjustable clipping for pixelrage

This is an experimental clipping routine for pixelrage I wrote long ago. The idea being to have standard helper functions that are universal and that can be used anywhere, in this case it applies as much to pixelrage as it does TBitmap.

Pixel clipping

When copying graphics (blitting) to a surface that has a cliprect installed, there are several steps that needs to be taken (pixelrage takes care of these things for you naturally):

  1. If the source rectangle is larger or overlaps the cliprect, it must be adjusted
  2. the difference between source x1,y1 and target x1,y1 must be added to x1,y1
  3. the difference between source x2,y2 and target x2,y2 must be subtracted from source
  4. Once correctly adjusted, the input and output codec’s must be pre-fetched
  5. Copy over each scanline using codec->read to codec->write
With fast graphics, every pixel counts

With fast graphics, every pixel counts

When stretching however, the ordeal becomes somewhat different. You still have to adjust the source and target regions, but if the source is smaller than the target your copy routine must be smart enough to apply a fixed math scale factor (which basically means, some pixels will be read more than once in order for scaling to occur).

And clipping for all

I never really got to finish this one, so I release it into the wild (together with pixelrage and byterage). I use these libraries in various older products but I don’t mind sharing and giving back to the community. Hopefully people can re-cycle some of my work, or perhaps use it as inspiration for something better.


  Function  StretchClip(var srcRect:TRect;var targetRect:TRect;
            targetClip:TRect):Boolean;
  var
    srcWD:  Integer;
    srcHD:  Integer;
    dstWD:  Integer;
    dstHD:  Integer;
    clpWD:  Integer;
    clpHD:  Integer;
    xOff:   Integer;
    yOff:   Integer;
  Begin
    result:=False;

    srcWD:=srcRect.right-srcrect.left;
    srcHD:=srcRect.bottom-srcRect.Top;
    if (srcWD>0) and (srcHD>0) then
    begin
      dstWD:=targetRect.right-targetRect.left;
      dstHD:=targetRect.bottom-targetRect.Top;
      if (dstWD>0) and (dstHD>0) then
      begin
        clpWD:=targetClip.right-targetClip.left;
        clpHD:=targetClip.bottom-targetClip.Top;
        if (clpWD>0) and (clpHD>0) then
        Begin
          inc(srcWD);
          inc(srcHD);
          inc(dstWD);
          inc(dstHD);
          inc(clpWD);
          inc(clpHD);

          (* Check of target is within extreme Right and left of clip *)
          if  (targetRect.left<targetClip.Right)
          and (targetRect.top<targetClip.Bottom) then
          Begin

            (* Clip LEFT *)
            if targetrect.Left<targetclip.Left then
            Begin
              (* X Offset by how much? *)
              xOff:=abs(targetclip.Left - targetrect.Left);

              (* Is it off by less than the whole width? *)
              if xoff<srcWD then
              Begin
                srcRect.Left:=srcRect.left + xoff;
                targetRect.Left:=targetclip.Left;
                dec(dstWD,xoff);
                dec(srcWD,xoff);
              end else
              exit;
            end;

            (* CLIP TOP *)
            if targetrect.Top<targetclip.top then
            Begin
              (* Y offset by how much? *)
              yOff:=abs(targetclip.Top - targetrect.Top);

              (* is it off by less than the whole height? *)
              if yOff<srcHD then
              Begin
                srcRect.top:=srcRect.top + yOff;
                targetRect.top:=targetClip.Top;
                dec(dstHD,yoff);
                dec(srcHD,yoff);
              end else
              exit;
            end;

            (* CLIP RIGHT *)
            if (targetrect.right > targetClip.right) then
            Begin
              xOff:=abs(targetrect.right - targetClip.right);
              if xoff<srcWD then
              Begin
                srcRect.Right := srcRect.Right - xoff;
                targetRect.right:=targetClip.Right;
                dec(dstWD,xoff);
                dec(srcWD,xoff);
              end else
              exit;
            end;

            (* CLIP BOTTOM *)
            if (targetrect.bottom > targetClip.bottom) then
            Begin
              yOff:=abs(targetrect.bottom - targetClip.bottom);
              if yoff<srcHD then
              Begin
                srcRect.bottom := srcRect.bottom - yOff;
                targetRect.bottom:=targetClip.bottom;
                dec(dstHD,yOff);
                dec(srcHD,yOff);
              end else
              exit;
            end;

            (* Final verdict *)
            result:=(srcWD>0) and (srcHD>0)
            and (dstWD>0) and (dstHD>0)
            and (clpWD>0) and (clpHD>0);

          end;
        end;
      end;
    end;
  end;
Isnt clipper the name of a boat?

Isnt clipper the name of a boat?

When we apply our clipper on two unsuspecting rectangles passing by my lab on their way to a square dance, we see that it calculates the correct offset’s and adjusts the buffer values as expected. Now you can feed the adjusted source and target rectangles to your blitter without having to test each scanline or accidentally writing beyond the memory buffer.

Pixels are fun 🙂

  procedure TfrmTest.testClip;
  var
    srcRect, dstRect,Clip:TRect;
  begin
    Clip:=Rect(10,10,109,109);
    srcRect:=Rect(10,10,60,60);
    dstRect:=Rect(0,0,115,40);

    DrawOriginalCords(srcRect,dstRect,clip);

    if StretchClip(srcRect,dstRect,Clip) then
    Begin
      LogToMemo('Clip successfull:');
      LogtoMemo('Source = ' + pxlrage.TPXRRect.toString(srcRect));
      LogtoMemo('Target = ' + pxlrage.TPXRRect.toString(dstRect));

      DrawClippedCords(srcRect,dstRect,clip);

    end else
    logToMemo('Clipping resulted in no activity');
  end;
Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: