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
When the application draws the image, it needs to draw it one pixel at a time. Then, depending on the light level, we simply add 0, 64, 128, or 192 to the color of the original pixel. This will draw the pixel using the colors lower and lower in the palette, resulting in an image with darker and darker pixels. Using this technique, we can create a spotlight effect as demonstrated in Listing 11-4. Figure 11-4: A segregated palette Listing 11-4: Using lighting techniques to create a spotlight
    procedure TfrmDXAppMain.FormCreate(Sender: TObject);

    begin

       .

       .

       .

      {position the mouse cursor to appear in the center of the screen}

      CurX := 320;

      CurY := 240;

      OldX := 320;

      OldY := 240;

       .

       .

       .

    end;

       .

       .

       .

    procedure TfrmDXAppMain.FormActivate(Sender: TObject);

    begin

       .

       .

       .

      {load the palette for the image}

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

                                ‘image.bmp’);

      {set the palette}

      FPrimarySurface.SetPalette(FPalette);

      {finally, load the image}

      Image := DDLoadBitmap(FDirectDraw, ExtractFilePath(ParamStr(0))+‘image.bmp’);

      {erase the background}

      ColorFill(FBackBuffer, 255, nil);

      ColorFill(FPrimarySurface, 255, nil);

       .

       .

       .

    end;

       .

       .

       .

    procedure TfrmDXAppMain.DrawSurfaces;

    var

      DestSrfcInfo, ImageSrfcInfo: TDDSurfaceDesc2;

      DestPtr, ImagePtr: PByteArray;

      ImgStartX, ImgStartY,

      PointX, PointY,

      Distance: Integer;

      iCount, iCount2: Integer;

    begin

      try

        {lock the image surface}

        ImageSrfcInfo.dwSize := SizeOf(TDDSurfaceDesc2);

        DXCheck( Image.Lock(nil, ImageSrfcInfo, DDLOCK_SURFACEMEMORYPTR or

                            DDLOCK_WAIT, 0) );

        ImagePtr := PByteArray(ImageSrfcInfo.lpSurface);

        {lock the destination surface}

        DestSrfcInfo.dwSize := SizeOf(TDDSurfaceDesc2);

        DXCheck( FBackBuffer.Lock(nil, DestSrfcInfo, DDLOCK_SURFACEMEMORYPTR or

                                  DDLOCK_WAIT, 0) );

        {this positions the initial starting point of destination drawing

         so that the image will be centered horizontally and vertically}

        DestPtr := PByteArray(integer(DestSrfcInfo.lpSurface)+

                              (DestSrfcInfo.lPitch*((DXHEIGHT div 2)-

                              (ImageSrfcInfo.dwHeight div 2)))+

                              ((DXWIDTH div 2)-(ImageSrfcInfo.dwWidth div 2)));

        {store the starting offset of the image}

        ImgStartX := (DXWIDTH div 2)-(ImageSrfcInfo.dwWidth div 2);

        ImgStartY := (DXHEIGHT div 2)-(ImageSrfcInfo.dwHeight div 2);

        for iCount := 0 to ImageSrfcInfo.dwHeight-1 do

        begin

          for iCount2 := 0 to ImageSrfcInfo.dwWidth-1 do

          begin

            {retrieve the current pixel coordinates and translate them such

             that the mouse cursor acts as the origin}

            PointX := (ImgStartX+iCount2) - CurX;

            PointY := (ImgStartY+iCount) - CurY;

            {determine the relative distance of this pixel from the mouse

             cursor, and restrain it to a range of 0-4}

            Distance := ((PointX*PointX)+(PointY*PointY)) div 600;

            if Distance > 3 then

              Distance := 3;

            {draw the destination pixel. the distance is used to determine

             which 64-slot segment of the palette is used to draw the

             destination pixel color}

            DestPtr[iCount2] := ImagePtr[iCount2]+(64*Distance);

          end;

          {increment to the next line in the image}

          ImagePtr := PByteArray(Integer(ImagePtr)+ImageSrfcInfo.lPitch);

          {increment to the next line in the destination buffer}

          DestPtr := PByteArray(Integer(DestPtr)+DestSrfcInfo.lPitch);

        end;

      finally

        {release all locks}

        Image.Unlock(nil);

        FBackBuffer.Unlock(nil);

      end;

    end;
Alternatives/Enhancements This is a really cheap trick that is easy to implement and does not put too great a strain on your artists. However, another method for implementing lighting involves creating a lookup table for each level of light intensity desired. Specifically, the application creates a 256-entry array of integers, and begins iterating through each entry in the original palette. For each color, the application determines the color components at a darker intensity, and then searches the original palette for an entry that is the closest match for this darker color. The number of this matching palette entry is then placed into the array at the index of the original color. The pixels in the bitmap now act as an index into the new array, which in turn then act as an index into the original palette. It is possible to create many more light intensity levels using this technique as opposed to the one described above. It also allows your artists to use more colors, but they must be mindful to use a palette containing several shades of each individual color so that the color-matching step finds an appropriate match. Alternatively, you could use a non-palettized video mode. Using a non- palettized color mode frees your artists to use whatever colors they wish, and the results of this trick can be much more spectacular than that shown here. The effect will take a little longer, depending on the chosen video mode, as the application must move double to quadruple the information. However, using this technique, the banding side effect of the technique shown above can be eliminated, and the lighting effect can be much more realistic.
| Tip: It is possible to lessen the banding effect using the above illustrated technique by using a mask for the lighted area instead of programmatically calculating the distance from the mouse cursor. The pixels in each band could be dithered somewhat around the edges of each band to help lessen the banding effect.
#### Transition Effects While it is perfectly acceptable to simply move from one scene to another with no fanfare, providing some sort of animation during scene transitions makes the software appear to have a smoother flow. We can take another lesson from the motion picture industry here. Typically, movies use a number of different wipes, fades, and other effects to smoothly transition from one scene to another. The next time you watch any of the Star Wars films, pay attention to how these transition effects create a smooth flow throughout the movie.
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.