FransIsAGeek

Posts   
 
    
Marcus avatar
Marcus
User
Posts: 747
Joined: 23-Apr-2004
# Posted on: 02-Nov-2005 13:21:15   

I you don't believe me... just try out the new "About LLBLGen Pro" from the Designer... stuck_out_tongue_winking_eye

Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 02-Nov-2005 14:37:38   

i concur, however the about box is pretty cool. i guess that puts me into the same boat.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39800
Joined: 17-Aug-2003
# Posted on: 02-Nov-2005 15:48:08   

0ld sk00l d3mosc33n smile

Here, for kicks: (.NET 2.0)


// MainForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;

namespace CSRotoZoomer
{
    public partial class MainForm : Form
    {
        #region Members
        private int     _imageWidth, _imageHeight, _zoomCounter, _zoomInMax, _zoomOutMax;
        private Bitmap  _image;
        private bool    _zoomIn;
        private double  _gamma, _deltaGamma, _xZoomDelta, _yZoomDelta, _imageWidthD, _imageHeightD;

        // coordinate source.
        double[]        _xSourceCoords ={ -128, 128, -128 };
        double[]        _ySourceCoords ={ -64, -64, 64 };

        // coordinate destination. (for drawing).
        double[]        _xDestinationCoords ={ -128, 128, -128 };
        double[]        _yDestinationCoords ={ -64, -64, 64 };

        uint[]          _sourcePixels;
        #endregion


        /// <summary>
        /// CTor
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            // be sure this dialog uses double buffered rendering
            this.SetStyle( ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true );

            // initialize our parameters.
            _zoomCounter = 0;
            _zoomIn = false;

            // deltaGamma value, controls rotation.
            _deltaGamma = 2.0;

            // deltas for x and y zooming. If they're not the same the image gets stretched.
            _xZoomDelta = 2.0;
            _yZoomDelta = 1.0;

            // zoom counter values when the zoom action (in/out) will swap
            _zoomInMax = 200;
            _zoomOutMax = 300;
        }

        private void openImageToolStripMenuItem_Click( object sender, EventArgs e )
        {
            DialogResult result = _openImageDialog.ShowDialog( this );
            if( result != DialogResult.OK )
            {
                return;
            }

            // load bitmap.
            _image = new Bitmap( _openImageDialog.FileName );

            _imageWidth = _image.Width;
            _imageHeight = _image.Height;
            _imageWidthD = (double)_imageWidth;
            _imageHeightD = (double)_imageHeight;
            _sourcePixels = new uint[_imageWidth * _imageHeight];
            if( _xZoomDelta != 0 )
            {
                _zoomInMax = (int)(((_imageWidthD / 2.0) / _xZoomDelta) - 10.0);
            }
            _zoomOutMax = _zoomInMax * 5;
            _yZoomDelta = (_imageHeightD / _imageWidth) * _xZoomDelta;

            // read the initial pixels into the srcpixel array. This makes it possible to perform an in-place rendering to avoid memory trashing
            BitmapData srcData = _image.LockBits( new Rectangle( 0, 0, _imageWidth, _imageHeight ), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb );
            unsafe
            {
                uint* pSrc = (uint*)srcData.Scan0;

                for( int i = 0; i < _imageHeight; i++ )
                {
                    for( int j = 0; j < _imageWidth; j++ )
                    {
                        _sourcePixels[(i * _imageWidth) + j] = pSrc[(i * _imageWidth) + j];
                    }
                }
            }
            _image.UnlockBits( srcData );

            // init coord arrays for the three points we're using to read the source pixels
            // A ---------- B
            // |
            // |
            // |
            // |
            // C
            double halfWidth = _imageWidthD / 2.0;
            _xSourceCoords[0] = -halfWidth;
            _xSourceCoords[1] = halfWidth;
            _xSourceCoords[2] = -halfWidth;
            _xDestinationCoords[0] = -halfWidth;
            _xDestinationCoords[1] = halfWidth;
            _xDestinationCoords[2] = -halfWidth;

            double halfHeight = _imageHeightD / 2.0;
            _ySourceCoords[0] = -halfHeight;
            _ySourceCoords[1] = -halfHeight;
            _ySourceCoords[2] = halfHeight;
            _yDestinationCoords[0] = -halfHeight;
            _yDestinationCoords[1] = -halfHeight;
            _yDestinationCoords[2] = halfHeight;

            _animTimer.Start();
        }


        private void _animTimer_Tick( object sender, System.EventArgs e )
        {
            Zoom();
            Rotate();
            Animate();
        }


        private void Zoom()
        {
            if( _zoomIn )
            {
                for( int i = 0; i < 3; i++ )
                {
                    if( _xSourceCoords[i] < 0 )
                    {
                        _xSourceCoords[i] += _xZoomDelta;
                    }
                    else
                    {
                        _xSourceCoords[i] -= _xZoomDelta;
                    }
                    if( _ySourceCoords[i] < 0 )
                    {
                        _ySourceCoords[i] += _yZoomDelta;
                    }
                    else
                    {
                        _ySourceCoords[i] -= _yZoomDelta;
                    }
                }
                _zoomCounter++;
                if( _zoomCounter > _zoomInMax )
                {
                    _zoomIn = false;
                }
            }
            else
            {
                for( int i = 0; i < 3; i++ )
                {
                    if( _xSourceCoords[i] < 0 )
                    {
                        _xSourceCoords[i] -= _xZoomDelta;
                    }
                    else
                    {
                        _xSourceCoords[i] += _xZoomDelta;
                    }
                    if( _ySourceCoords[i] < 0 )
                    {
                        _ySourceCoords[i] -= _yZoomDelta;
                    }
                    else
                    {
                        _ySourceCoords[i] += _yZoomDelta;
                    }
                }
                _zoomCounter--;
                if( _zoomCounter < -_zoomOutMax )
                {
                    _zoomIn = true;
                }
            }

            label1.Text = _zoomCounter.ToString();
        }

        private void Animate()
        {
            double xa = _xDestinationCoords[0];
            double xb = _xDestinationCoords[1];
            double xc = _xDestinationCoords[2];
            double ya = _yDestinationCoords[0];
            double yb = _yDestinationCoords[1];
            double yc = _yDestinationCoords[2];
            double xab_delta = (xb - xa) / _imageWidthD;
            double yab_delta = (yb - ya) / _imageWidthD;
            double xac_delta = (xc - xa) / _imageHeightD;
            double yac_delta = (yc - ya) / _imageHeightD;

            // transpose the rotating centre to the middle of the picture.
            double x_off = xa + (_imageWidthD * 0.5);
            double y_off = ya + (_imageHeightD * 0.5);

            BitmapData imageDst = _image.LockBits( new Rectangle( 0, 0, _imageWidth, _imageHeight ), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb );

            System.IntPtr scan0 = imageDst.Scan0;

            unsafe
            {
                uint* pDest = (uint*)scan0;

                for( int i = 0; i < _imageHeight; i++ )
                {
                    for( int j = 0; j < _imageWidth; j++ )
                    {
                        int readX = (int)x_off;
                        int readY = (int)y_off;
                        if( readX < 0 )
                        {
                            readX = (_imageWidth - 1) - (-readX % (_imageWidth - 1));
                        }
                        if( readY < 0 )
                        {
                            readY = (_imageHeight - 1) - (-readY % (_imageHeight - 1));
                        }
                        if( readX >= _imageWidth )
                        {
                            readX = 0 + (readX % (_imageWidth - 1));
                        }
                        if( readY >= _imageHeight )
                        {
                            readY = 0 + (readY % (_imageHeight - 1));
                        }
                        pDest[0] = _sourcePixels[(readY * _imageWidth) + readX];
                        x_off += xab_delta;
                        y_off += yab_delta;
                        pDest++;
                    }
                    double iD = (double)i;
                    x_off = xa + (iD * (xac_delta - 0.002 * iD)) + (_imageWidthD * 0.5);
                    y_off = ya + (iD * (yac_delta + 0.001 * iD)) + (_imageHeightD * 0.5);
                }
            }

            _image.UnlockBits( imageDst );
            _renderCanvas.Image = _image;
        }


        public void Rotate()
        {
            // first update the angle. only gamma is interesting...
            _gamma = (_gamma + _deltaGamma) % 360;
            double gammaRad = (_gamma / 360) * 2 * Math.PI;

            // get the sin and cos of the angles
            double sinG = Math.Sin( gammaRad );
            double cosG = Math.Cos( gammaRad );

            // now rotate the coords...
            for( int i = 0; i < 3; i++ )
            {
                double yn = _ySourceCoords[i];
                double xn = _xSourceCoords[i];

                _xDestinationCoords[i] = (xn * cosG) - (yn * sinG);
                _yDestinationCoords[i] = (yn * cosG) + (xn * sinG);
            }
        }

    }
}

Now put a picture box on a form, a timer (_animTimer) and an openfiledialog, and off you go! smile

Connect the timer's event to _animTimer_Tick and set the timer to 20ms

Frans Bouma | Lead developer LLBLGen Pro