I'm preparing a basic engine setup for my game project that I'm going to do in C#. This is an assignment for university, and we've been instructed to not use APIs such as OpenGL and DirectX. I've made a basic image rendering class which is almost complete, I just haven't fully completed the method for rotating a Bitmap.

Personally, I don't feel like I'm 100% educated in terms of rotation logic and such. What I'm hoping is that the reponses to this, code samples or not, will help shed some light on the issue at hand. I'm aware of how rotation works for matrices and such, just not how to properly apply them to a bitmap.

The rotation function that I've used is courtesy of vcskicks.com.

private System.Drawing.Image RotateImage(System.Drawing.Image inputImg, double degreeAngle) { //Corners of the image PointF[] rotationPoints = { new PointF(0, 0), new PointF(inputImg.Width, 0), new PointF(0, inputImg.Height), new PointF(inputImg.Width, inputImg.Height)}; //Rotate the corners PointMath.RotatePoints(rotationPoints, new PointF(inputImg.Width / 2.0f, inputImg.Height / 2.0f), degreeAngle); //Get the new bounds given from the rotation of the corners //(avoid clipping of the image) Rectangle bounds = PointMath.GetBounds(rotationPoints); //An empy bitmap to draw the rotated image Bitmap rotatedBitmap = new Bitmap(bounds.Width, bounds.Height); using (Graphics g = Graphics.FromImage(rotatedBitmap)) { g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; //Transformation matrix Matrix m = new Matrix(); m.RotateAt((float)degreeAngle, new PointF(inputImg.Width / 2.0f, inputImg.Height / 2.0f)); m.Translate(-bounds.Left, -bounds.Top, MatrixOrder.Append); //shift to compensate for the rotation g.Transform = m; g.Clear(Color.White); g.DrawImage(inputImg, 0, 0); } return (System.Drawing.Image)rotatedBitmap; } public static class PointMath { private static double DegreeToRadian(double angle) { return Math.PI * angle / 180.0; } public static PointF RotatePoint(PointF pnt, double degreeAngle) { return RotatePoint(pnt, new PointF(0, 0), degreeAngle); } public static PointF RotatePoint(PointF pnt, PointF origin, double degreeAngle) { double radAngle = DegreeToRadian(degreeAngle); PointF newPoint = new PointF(); double deltaX = pnt.X - origin.X; double deltaY = pnt.Y - origin.Y; newPoint.X = (float)(origin.X + (Math.Cos(radAngle) * deltaX - Math.Sin(radAngle) * deltaY)); newPoint.Y = (float)(origin.Y + (Math.Sin(radAngle) * deltaX + Math.Cos(radAngle) * deltaY)); return newPoint; } public static void RotatePoints(PointF[] pnts, double degreeAngle) { for (int i = 0; i < pnts.Length; i++) { pnts[i] = RotatePoint(pnts[i], degreeAngle); } } public static void RotatePoints(PointF[] pnts, PointF origin, double degreeAngle) { for (int i = 0; i < pnts.Length; i++) { pnts[i] = RotatePoint(pnts[i], origin, degreeAngle); } } public static Rectangle GetBounds(PointF[] pnts) { RectangleF boundsF = GetBoundsF(pnts); return new Rectangle((int)Math.Round(boundsF.Left), (int)Math.Round(boundsF.Top), (int)Math.Round(boundsF.Width), (int)Math.Round(boundsF.Height)); } public static RectangleF GetBoundsF(PointF[] pnts) { float left = pnts[0].X; float right = pnts[0].X; float top = pnts[0].Y; float bottom = pnts[0].Y; for (int i = 1; i < pnts.Length; i++) { if (pnts[i].X < left) left = pnts[i].X; else if (pnts[i].X > right) right = pnts[i].X; if (pnts[i].Y < top) top = pnts[i].Y; else if (pnts[i].Y > bottom) bottom = pnts[i].Y; } return new RectangleF(left, top, (float)Math.Abs(right - left), (float)Math.Abs(bottom - top)); } }

This produces the following result:

0 degrees: http://i47.tinypic.com/r8cxhd.png

22.5 degrees: http://i46.tinypic.com/hsoxo9.png

45 degrees: http://i50.tinypic.com/vy6q8z.png

From what I can see, the produced Bitmap only extends its boundaries towards the right and the bottom, while it should also extend in the other 2 directions to make the image rotate properly around the center. I spent quite a while playing around with the method, and in the end I was unable to produce the desired result. The background of the produced Bitmap is colored white simply to be able to see its real size.

Any form of assistance is gladly appreciated. :)