A BitBlt-Like Function With Rotation Angle: ROTBlt

Environment: Visual C++

Description

RotBlt is a function that works like BitBlt. It's different in that it has an additional param theta which is the angle in degrees by which the source DC is rotated when blitted onto the destination.

I wrote this in about 10 minutes, out of which I spent about 6 creating the Win32 app to test the code. So it is slow. (It took 1 second to rotate a 150x150x16bpp DC on a 333MHz Celeron.)

So if you wanted to rotate 1024x768x32 bits, umm, well....

Besides, I wrote this because I saw Hans Buhler's 90 degree rotate dc code which I assume has some issues with Win 95/98 and that seems to be for buttons and stuff. And then, why just 90 degrees??? Why not 3.635 degrees?

So, here's rotblt.

This is the code that generated this image.

  Rectangle (memDC,50,50,100,100);

  BitBlt(dc, 0,0,150,150,memDC,0,0,SRCAND);
  RotBlt(dc, 0,0,150,150,memDC,200,0, 45, SRCAND);

  TextOut(dc, 0,140,"BitBlt",strlen("BitBlt"));
  TextOut(dc, 200,140,"RotBlt 45 degs",strlen("RotBlt 45 degs"));



Function  : RotBlt
Parameters :
  HDC destDC, //destDC onto which to perform blt operation
  int srcx1,  //start x coordinate of src DC
  int srcy1,  //start y coordinate of src DC
  int srcx2,  //end x coordinate of src DC
              //remember this isn't width
  int srcy2,  //end y coordinate of src DC
              //remember this isn't height
  HDC srcDC , //srcDC
  int destx1, //left Xcoordinate of destDC where rotated DC will
              //be blt (top -left)
  int desty1 ,//top Ycoordinate of destDC where rotated DC will
              //be blt (top - left)
  int thetaInDegrees , // angle in degrees in which to rotate srcDC
  DWORD mode  //ROp code same as Bitblt


Return value : NULL

Body :

void RotBlt(HDC destDC, int srcx1, int srcy1, int srcx2, int srcy2,
  HDC srcDC , int destx1, int desty1 ,int thetaInDegrees ,DWORD mode)
{
  double theta = thetaInDegrees * (3.14159/180);
  //multiply degrees by PI/180 to convert to radians

  //determine width and height of source
  int width = srcx2 - srcx1;
  int height = srcy2 - srcy1;

  //determine centre/pivot point ofsource
  int centreX = int(float(srcx2 + srcx1)/2);
  int centreY = int(float(srcy2 + srcy1)/2);

  //since image is rotated we need to allocate a rectangle
  //which can hold the image in any orientation
  if(width>height)height = width;
  else
    width = height;


  //allocate memory and blah blah
  HDC memDC = CreateCompatibleDC(destDC);
  HBITMAP memBmp = CreateCompatibleBitmap(destDC, width, height);

  HBITMAP obmp = (HBITMAP) SelectObject(memDC, memBmp);

  //pivot point of our mem DC
  int newCentre = int(float(width)/2);

  //hmmm here's the rotation code. X std maths :|
  for(int x = srcx1; x<=srcx2; x++)
    for(int y = srcy1; y<=srcy2; y++)
    {
      COLORREF col = GetPixel(srcDC,x,y);

      int newX = int((x-centreX)*sin(theta)+(y-centreY)*cos(theta));
      int newY = int((x-centreX)*cos(theta)-(y-centreY)*sin(theta));


      SetPixel(memDC , newX + newCentre, newY + newCentre, col);
    }

  //splash onto the destination
  BitBlt(destDC, destx1, desty1, width, height, memDC, 0,0,mode);


  //free mem and blah
  SelectObject(memDC, obmp);

  DeleteDC(memDC);
  DeleteObject(memBmp);
}



Comments

  • Oh oh oh!

    Posted by Legacy on 01/25/2004 12:00am

    Originally posted by: Just guess!

    Hello little kids!

    Just check this code (in Pascal please!)

    Assume DC1 is the DC you want to rotate of an angle named o around its center. Assume DC2 is a DC with the same properties (pixelformat, dimensions...) as DC1. Assume w is the width of DC1 (and DC2), and that DC1 and DC2 are squares (then their heights are w too). DC2 is just a "transition DC" to make the intermediate computation (of course it could be created locally in the function).

    Then:

    procedure Rotate(DC1,DC2:HDC;w:Integer;o:Single);
    var
    a:Integer;
    c,s,u,v:single;
    begin
    c:=cos(o);
    s:=sin(o);
    for a:=0 to w-1 do begin
    v:=2*a/(w-1)-1;
    StretchBlt(DC2,round(0.5*w*(1+(s*v-c))),a,round(w*c),1,DC1,0,a,w,1,SRCCOPY);
    end;
    for a:=0 to w-1 do begin
    u:=2*a/(w-1)-1;
    StretchBlt(DC1,a,round(0.5*w*(1-c-s*(s+u)/c)),1,round(w*(s*s+c*c)/c),DC2,a,0,1,w,SRCCOPY);
    end;
    end;

    I think this is at least 10 times faster than everything you wrote so far... except the great OpenGl, of course. You could do some optimization: in fact for o which is near 90� or 270�, it could be better to compute the first for-loop before the second one. But I think you are good enough to implement it yourself, I leave it as an exercise for the reader!

    Sorry, and excuse my poor English!

    Reply
  • artifacts caused by a little mistake

    Posted by Legacy on 12/18/2003 12:00am

    Originally posted by: jes

    i think you intended to design the rotblt parameters to match bitblt, other than the added theta param. Your rotblt looks like:
    RotBlt(HDC destDC, int srcx1, int srcy1, int srcx2, int srcy2,HDC srcDC , int destx1, int desty1 ,int thetaInDegrees ,DWORD mode){...}

    while the bitblt usage is actually:
    BitBlt(destDC, destx, desty, width, height, srcDC, srcx, srcy, mode)

    your rotblt function still works, but will create holes (looks like scattered dot artifacts) because rotblt takes a pixel from the source, rotates it, and plots it into memDC. due to floating point to integer conversions, holes will be created. what you want to do is traverse the width/height of the destination DC, and use the trig to find the pixel in the source DC to copy into that location, which makes sure there are no holes in destDC.

    I was thinking that is what you intended to do but had some values in the parameter switched, but looking back, you did use wording such as "newX" and "newY", which implies to me that maybe it was ... in a way... unintentional and intentional at the same time? Perhaps renaming them to oldX and oldY would be less confusing.

    in any case, switching srcx1 and srcy1 with destx1 and desty1 in the for loop will correct the artifact issue, although the variable names should also be switched to avoid confusion. (i just left the names because im lazy)

    i actually dont mind the slow speed because i'm loading the rotations i need into ddraw surfaces before the gameplay begins. reading this article still saved me a lot of time :)

    Reply
  • thanks for sharing

    Posted by Legacy on 12/16/2003 12:00am

    Originally posted by: jes

    i'm currently working on my first ddraw game which required rotation of bitmaps. I wanted to generate 360 rotated surfaces from 1 bmp, and wasn't quite sure what i could do with bitblt to achieve such rotations. i'm very much a beginner at programming... and found your code (and the comments) to be very helpful in what i wanted to do.

    thx :) -jes

    Reply
  • Quit being so pretentious

    Posted by Legacy on 10/18/2003 12:00am

    Originally posted by: DrPhil

    Lay off the guy, programming may be a difficult task, but that is no reason to act snobby. Usually those people who say such things do so because of their low self efficacy. This appears to make them feel better about themselves.

    Reply
  • Error

    Posted by Legacy on 08/22/2002 12:00am

    Originally posted by: sikander Rafiq

    Image is not rotated.
    

    Reply
  • Remove GetPixel and SetPixel

    Posted by Legacy on 06/27/2002 12:00am

    Originally posted by: Rolf

    The inner loop can even be more simplified by eliminating the GetPixel and SetPixel calls. The resulting code will be at least 3 times faster and will benefit from the presence of a graphics accelerator card. The idea is simply to use the BitBlt function to set the pixel:

    int newX = int((x-centreX)*sin(theta) +(y-centreY)*cos(theta));
    int newY = int((x-centreX)*cos(theta)- (y-centreY)*sin(theta));
    BitBlt(memDC, newX+newCentre, newY+newCentre,1,1,srcDC,x,y,SRCCOPY);


    Reply
  • Consider using Sin/Cos table

    Posted by Legacy on 06/26/2002 12:00am

    Originally posted by: Albert

    Consider using Sin/Cos tables instead of calling sin() and cos() in each iteration, that slow the process a lot. You can create your sin/cos tables everytime the project starts, so maybe the startup time is a little bit slower, but that will make your code faster. So, your program will have something like this:
    
    

    double sintable[360];

    void createsintable() {
    for (int i=0; i<360; i++) {
    sintable[i] = sin(i);
    }
    }

    I've not included the casting thingy, but you can figure it out by yourself. Call this function everytime the program starts.

    Reply
  • Nice one

    Posted by Legacy on 06/26/2002 12:00am

    Originally posted by: Ben

    good one fella, always good to see a take on a subject.  Nice and simple, as you say may not be the fastest but the i will be taking the rotation equation and using it in my projects in the future.  probablity won't be rotating bitmaps, but the idea will hold with some vector stuff.
    
    

    I'm not great at maths so this will have saved me loads of time. Don't be put off by some comments all code is useful to see. People sould realize that programming is not all cut and paste, you have to think around problems.

    Keep it up

    Reply
  • Just an advice ...

    Posted by Legacy on 06/26/2002 12:00am

    Originally posted by: spartacus

    I think you need a Cray to do your job. In fact, event with a big image, it will work better on Z80, if you
    precompute sin(theta). Just think... why do you need to do 1000000 times the same thing: sin(theta).

    Reply
  • This is junk

    Posted by Legacy on 06/25/2002 12:00am

    Originally posted by: Anon

    Come on guy. No one's learning anything from this code, nor would anyone actually implement a rotation like this.
    There'll be holes and artifacts galore.
    Better to transform the basis for the image and use it to
    construct an affine transformation. The affine transformation can be implemented very quickly using difference equations and fixed point math.

    This stuff junks up CodeGuru and makes it hard to find useful or enlightening code. Who wants to wade through a ton of crap for the gold?

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date