Search Tips Advanced Search |
| Delphi Graphics and Game Programming Exposed with DirectX 7.0 by John Ayres Wordware Publishing, Inc. ISBN: 1556226373 Pub Date: 12/01/99
Search this book:
Previous | Table of Contents | Next
This will result in a perfectly rotated image with no holes. Incidentally, we should load our source image into system memory as opposed to video memory. This will speed up the rotation, as it is much faster to access a surface in system memory than video memory. Also, we’ll further optimize this by creating a sine and cosine lookup table instead of calling the Sin and Cos functions, using the angle as the index within these tables. The following listing demonstrates this technique. Listing 11-3: Rotating a bitmap
    interface

       .

       .

       .

    var

       .

       .

       .

      {the arbitrary angle}

      Theta: Integer;

      {these are used to create sine and cosine function lookup tables

       as an optimization}

      iAngle: Integer;

      SinTable: array[0..359] of single;

      CosTable: array[0..359] of single;

    implementation

       .

       .

       .

    procedure TfrmDXAppMain.FormCreate(Sender: TObject);

    begin

       .

       .

       .

    {initialize our starting angle}

      Theta := 0;

    end;

       .

       .

       .

    procedure TfrmDXAppMain.FormActivate(Sender: TObject);

    begin

       .

       .

       .

      {load the palette from this bitmap}

      FPalette := DDLoadPalette(FDirectDraw, ExtractFilePath(ParamStr(0))+

                                ‘athena.bmp’);

      {set the palette}

      FPrimarySurface.SetPalette(FPalette);

      {load the bitmap to be rotated}

      FImage := DDLoadBitmapSysMem(FDirectDraw, ExtractFilePath(ParamStr(0))+

                                   ‘athena.bmp’);

       .

       .

       .

    end;

       .

       .

       .

    procedure TfrmDXAppMain.DrawSurfaces;

    var

      SrcInfo, DestInfo: TDDSurfaceDesc2;

      SrcPtr, DestPtr: PByteArray;

      DestX, DestY,

      SrcX, SrcY: Integer;

      SinTheta, CosTheta: Single;

      Area: TRect;

      CenterX, CenterY: Single;

    begin

      {erase the last frame of animation}

      ColorFill(FBackBuffer, 0, nil);

      {increment our angle, making sure to roll it over if necessary}

      Inc(Theta);

      if Theta>359 then

        Theta := 0;

      {determine the sine and cosine of this angle by using our

       lookup tables}

      SinTheta := SinTable[Theta];

      CosTheta := CosTable[Theta];

      try

        {lock the source image}

        SrcInfo.dwSize := SizeOf(TDDSurfaceDesc2);

        DXCheck( FImage.Lock(nil, SrcInfo, DDLOCK_SURFACEMEMORYPTR or

                             DDLOCK_WAIT, 0) );

        SrcPtr := PByteArray(SrcInfo.lpSurface);

        {specify the rectangular area in the destination image to lock by

         determining coordinates that will center the image}

        Area := Rect((DXWIDTH div 2)-(SrcInfo.dwWidth div 2),

                     (DXHEIGHT div 2)-(SrcInfo.dwHeight div 2),

                     (DXWIDTH div 2)+(SrcInfo.dwWidth div 2),

                     (DXHEIGHT div 2)+(SrcInfo.dwHeight div 2));

        {lock the destination surface}

        DestInfo.dwSize := SizeOf(TDDSurfaceDesc2);

        DXCheck( FBackBuffer.Lock(@Area, DestInfo, DDLOCK_SURFACEMEMORYPTR or

                                  DDLOCK_WAIT, 0) );

        DestPtr := PByteArray(DestInfo.lpSurface);

        {determine the center of the source image}

        CenterX := (SrcInfo.dwWidth / 2);

        CenterY := (SrcInfo.dwHeight / 2);

        {begin iterating through the pixels of the destination image}

        for DestY := 0 to SrcInfo.dwHeight do

        begin

          for DestX := 0 to SrcInfo.dwWidth do

          begin

            {determine the source pixel to use for this destination pixel}

            SrcX := Trunc(CenterX + (DestX - CenterX)*CosTheta -

                          (DestY - CenterY)*SinTheta);

            SrcY := Trunc(CenterY + (DestX - CenterX)*SinTheta +

                          (DestY - CenterY)*CosTheta);

            {if this pixel is within the source image...}

            if (SrcX > 0) and (SrcX < SrcInfo.dwWidth) and

               (SrcY > 0) and (SrcY < SrcInfo.dwHeight) then

              {...copy it to the destination}

              DestPtr[DestX] := SrcPtr[SrcY*SrcInfo.lPitch+SrcX];

          end;

          {move to the next line in the destination image}

          DestPtr := PByteArray(Longint(DestPtr)+DestInfo.lPitch);

        end;

      finally

        {clean up}

        FImage.Unlock(nil);

        FBackBuffer.Unlock(@Area);

      end;

    end;

       .

       .

       .

    initialization

      {we’ll create lookup tables for the sine and cosine functions, using

       the angle as an index into these tables}

      for iAngle := 0 to 359 do

      begin

        SinTable[iAngle] := Sin(iAngle*(PI/180));

        CosTable[iAngle] := Cos(iAngle*(PI/180));

      end;
Alternatives/Enhancements Unlike bitmap scaling, rotation is not something that is emulated by DirectDraw. Some cards provide hardware support for bitmap rotation, but even these could be restricted to rotations by only 90-degree angles. Therefore, you cannot rely on DirectDraw for bitmap rotation on every machine; you must implement this functionality yourself. Bitmap rotation can be very slow due to its mathematically intense nature. However, rotation could be optimized by the use of assembly language. A less dramatic approach may be to use lookup tables that contained the rotated pixel coordinates for all angles. The angle could then be used as an index into this lookup table. This would result in incredibly fast bitmap rotation, but it would be a memory hog. #### Lighting Tricks In nature, the color of an object can vary according to the intensity of light to which it is subjected. When the lights go down, things appear darker; when an object moves into the shadow of another object, its color darkens. Modeling this in our graphics engines can make our game worlds appear much more realistic and dynamic. There are many ways to model realistic lighting, but one method in particular is easy to implement and produces acceptable results. Basic Theory This technique works by imposing restrictions on the palette of an image. For example, say we want to display an image that will have four different levels of light intensity. We need to segregate our palette into four different segments, so 256 / 4 = 64 palette slots per segment. Now, our artists need to draw the image using only the first 64 palette slots. These slots should contain the colors of the image at their brightest intensity. The other three segments of 64 palette slots contain exactly the same colors as those in the first 64 slots, but at darker and darker intensities. In other words, the second segment of 64 slots contains the colors of the first 64 slots at 75% of their original intensity, the third segment of 64 slots contains these colors at 50% intensity, and the final segment contains the colors at 25% of their original intensity.
Previous | Table of Contents | Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.