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
Basic Theory Each transition effect may be implemented in wildly differing ways or with only subtle, minor differences, depending on the desired effect. In this example, let’s use three simple effects that are relatively easy to implement yet provide cool animation effects. Specifically, these transition effects will be melt, crawl, and dissolve. Melt This is the classic melting screen effect made popular by id software’s Doom. It works by first drawing the next scene image to the back buffer, and then drawing the closing scene one column at a time into the back buffer. An array of integers, one entry per column of pixels, is used to track the vertical offset of the start of the pixel column. By starting some columns before others, we can create the illusion of the foreground screen melting away to reveal the next scene. Figure 11-5: The melt effect Crawl This is a variation of the dissolve effect below. Starting from one side of the screen, we use two variables to track a beginning and ending column (or row), spaced some arbitrary distance apart. At each frame of the animation, we increment both the beginning and ending columns (or rows). These define an area into which several pixels from the next scene are drawn. Their coordinates are chosen at random and copied into the back buffer at the same position. Past the ending column (or row), the “exposed” portion of the next scene is drawn. The effect appears to eat away at the foreground image, revealing the image of the next scene underneath. Figure 11-6: The crawl effect Dissolve This is a common effect that makes one image appear to dissolve, revealing the image beneath it. It works by randomly choosing a pixel from the next image and copying it to the back buffer (over the previous image) at the same position. However, it is rather slow to use the entire screen area for the range of random pixel selection. Thus, we constrain the random pixel selection to an 8 × 8 pixel area, and then replicate that throughout the entire image. In other words, the screen is divided into 8×8 blocks. The next pixel is chosen from the first 8×8 area, and we use this coordinate as an offset for each 8×8 block throughout the screen. This creates a fast, effective dissolve effect. Figure 11-7: The dissolve effect The following listing demonstrates a simple implementation of these three effects. Press the spacebar to move from one image to the next. Listing 11-5: Transition effects
    interface

       .

       .

       .

    type

      TTransitionType = (transMelt, transCrawl, transDissolve);

       .

       .

       .

    var

       .

       .

       .

      {holds the scene images}

      ScreenBackgrounds: array[0..2] of IDirectDrawSurface4;

      {tracks which background image is used next}

      NextBackground: Integer;

      {tracks the next transition effect to be used}

      NextTransition: TTransitionType;

    implementation

       .

       .

       .

    procedure TfrmDXAppMain.FormCreate(Sender: TObject);

    begin

       .

       .

       .

      {initialize the next background}

      NextBackground := 0;

      {initialize the next transition effect}

      NextTransition := transMelt;

      NextTransition := transMelt;

    end;

       .

       .

       .

    procedure TfrmDXAppMain.FormActivate(Sender: TObject);

    begin

       .

       .

       .

    {load the palette}

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

                                ‘begin.bmp’);

      {set the palette}

      FPrimarySurface.SetPalette(FPalette);

      {load the three images to be used in the transition effect animations}

      ScreenBackgrounds[0] := DDLoadBitmap(FDirectDraw, ExtractFilePath(

                                           ParamStr(0))+‘begin.bmp’);

      ScreenBackgrounds[1] := DDLoadBitmap(FDirectDraw, ExtractFilePath(

                                           ParamStr(0))+‘middle.bmp’);

      ScreenBackgrounds[2] := DDLoadBitmap(FDirectDraw, ExtractFilePath(

                                           ParamStr(0))+‘end.bmp’);

      {copy the first image to the screen}

      DestRect := Rect(0, 0, DXWIDTH, DXHEIGHT);

      FPrimarySurface.BltFast(0, 0, ScreenBackgrounds[0], DestRect,

                              DDBLTFAST_NOCOLORKEY OR DDBLTFAST_WAIT);

      FBackBuffer.BltFast(0, 0, ScreenBackgrounds[0], DestRect,

                          DDBLTFAST_NOCOLORKEY OR DDBLTFAST_WAIT);

       .

       .

       .

    end;

       .

       .

       .

    procedure TfrmDXAppMain.FormKeyDown(Sender: TObject; var Key: Word;

      Shift: TShiftState);

    begin

      if Key = VK_ESCAPE then

        Close;

      {if the spacebar was pressed...}

      if Key = Ord(‘ ’) then

      begin

        {move to the next transition}

        NextTransition := Succ(NextTransition);

        {rollover the transition effect if necessary}

        if Ord(NextTransition) > Ord(transDissolve) then

          NextTransition := transMelt;

        {perform the transition effect}

        CoolScreenTransition(NextTransition);

      end;

    end;

    procedure TfrmDXAppMain.CoolScreenTransition(TransitionType: TTransitionType);

    var

      HeadCol, TailCol: Integer;

      iCount, iCount2, iCount3: Integer;

      Block, DestRect: TRect;

      RandBlock, RandBlock2: Integer;

      Worms: array[0..DXWIDTH-1] of Integer;

      StillGoing: Boolean;

    begin

      {move to the next image}

      Inc(NextBackground);

      {rollover the image index, if necessary}

      if NextBackground > 2 then

        NextBackground := 0;

      {copy the foreground image into the back buffer}

      DestRect := Rect(0, 0, DXWIDTH, DXHEIGHT);

      FBackbuffer.BltFast(0, 0, FPrimarySurface, DestRect, DDBLTFAST_NOCOLORKEY or

                          DDBLTFAST_WAIT);

      case TransitionType of

        transMelt   : begin

                        {initialize the starting offsets for each column of

                         pixels}

                        for iCount := 0 to DXWIDTH-1 do

                          Worms[iCount] := 0;

                        {initialize the loop variable}

                        StillGoing := TRUE;

                        {begin the effect}

                        while StillGoing do

                        begin

                          {assume that the effect will stop}

                          StillGoing := FALSE;

                          {for each column of pixels...}

                          for iCount := 0 to DXWIDTH-1 do

                          begin

                            {if this column has not yet started to move...}

                            if Worms[iCount] = 0 then

                              {...give the column a 25% chance of starting}

                              if Random(4) = 1 then

                                Worms[iCount] := 1;

                            {if this column has not yet reached to bottom,

                             but is in motion...}

                            if (Worms[iCount]<DXHEIGHT-1)and(Worms[iCount]>0) then

                            begin

                              {...there is still at least one column still

                               ‘alive’, so the effect has not yet stopped}

                              StillGoing := TRUE;

                              {copy this column of pixels into its new position}

                              Block := Rect(iCount, Worms[iCount], iCount+1,

                                            DXHEIGHT-3);

                              FBackBuffer.BltFast(iCount, Worms[iCount]+3,

                                                  FBackBuffer, Block,

                                                  DDBLTFAST_NOCOLORKEY or

                                                  DDBLTFAST_WAIT);

                              {copy the same column from the next scene above

                               the currently moving column}

                              Block := Rect(iCount, 0, iCount+1, Worms[iCount]+3);

                              FBackBuffer.BltFast(iCount, 0,

                                                 ScreenBackgrounds[NextBackground],

                                                 Block, DDBLTFAST_NOCOLORKEY or

                                                 DDBLTFAST_WAIT);

                              {move the column down a bit}

                              Worms[iCount] := Worms[iCount]+3;

                            end;

                          end;

                          {the back buffer now contains the next frame of the

                           animation, so copy it to the screen}

                          DestRect := Rect(0, 0, DXWIDTH, DXHEIGHT);

                          FPrimarySurface.BltFast(0, 0, FBackbuffer, DestRect,

                                                  DDBLTFAST_NOCOLORKEY or

                                                  DDBLTFAST_WAIT);

                        end;

                        {the animation is over, so copy the final image to both

                         the front and back buffers to erase the last remains of

                         the animation sequence}

                        Block := Rect(0, 0, DXWIDTH, DXHEIGHT);

                        FBackbuffer.BltFast(0, 0,

                                            ScreenBackgrounds[NextBackground],

                                            Block, DDBLTFAST_NOCOLORKEY or

                                            DDBLTFAST_WAIT);

                        FPrimarySurface.BltFast(0, 0,

                                                ScreenBackgrounds[NextBackground],

                                                Block, DDBLTFAST_NOCOLORKEY or

                                                DDBLTFAST_WAIT);

                      end;

        transCrawl  : begin

                        {begin tracking the beginning and ending columns}

                        HeadCol := 0;

                        TailCol := -10;

                        {while the ending column is still on the screen...}

                        while TailCol < (DXWIDTH div 5)-1 do

                        begin

                          {iterate through the columns of pixels between the

                           beginning and ending column}

                          for iCount := TailCol to HeadCol do

                            {if this column is on the screen...}

                            if iCount > -1 then

                              for iCount2 := 0 to 20 do

                              begin

                                {choose a random block of pixels}

                                RandBlock := Random(DXHEIGHT div 5);

                                {copy this block of pixels from the next image

                                 into the destination at the same coordinates}

                                Block := Rect(5*iCount, 5*RandBlock, 5*iCount+5,

                                              5*RandBlock+5);

                                FBackBuffer.BltFast(Block.Left, Block.Top,

                                                 ScreenBackgrounds[NextBackground],

                                                 Block, DDBLTFAST_NOCOLORKEY or

                                                 DDBLTFAST_WAIT);

                              end;

                          {if the ending column is on the screen...}

                          if TailCol > -1 then

                          begin

                            {make sure we copy the entire column of pixels from

                             the next image into the destination so that the

                             final image will be complete}

                            Block := Rect(5*TailCol, 0, 5*TailCol+5, DXHEIGHT);

                            FBackBuffer.BltFast(Block.Left, Block.Top,

                                                ScreenBackgrounds[NextBackground],

                                                Block, DDBLTFAST_NOCOLORKEY or

                                                DDBLTFAST_WAIT);

                          end;

                          {increment the beginning and ending columns}

                          Inc(HeadCol);

                          Inc(TailCol);

                          {copy this frame of animation to the screen}

                          Block := Rect(0, 0, DXWIDTH, DXHEIGHT);

                          FPrimarySurface.BltFast(0, 0, FBackbuffer, Block,

                                                  DDBLTFAST_NOCOLORKEY or

                                                  DDBLTFAST_WAIT);

                          {pause for a short period}

                          Sleep(20);

                        end;

                        {the animation is over, so copy the final image to both

                         the front and back buffers to erase the last remains of

                         the animation sequence}

                        Block := Rect(0, 0, DXWIDTH, DXHEIGHT);

                        FBackbuffer.BltFast(0, 0,

                                            ScreenBackgrounds[NextBackground],

                                            Block, DDBLTFAST_NOCOLORKEY or

                                            DDBLTFAST_WAIT);

                        FPrimarySurface.BltFast(0, 0,

                                                ScreenBackgrounds[NextBackground],

                                                Block, DDBLTFAST_NOCOLORKEY or

                                                DDBLTFAST_WAIT);

                      end;

        transDissolve : begin

                          {we will copy 100 blocks of pixels for this effect}

                          for iCount := 0 to 100 do

                          begin

                            {choose a random block of pixels from our 8×8 area}

                            RandBlock := Random(8);

                            RandBlock2 := Random(8);

                            {this will be mirrored throughout the screen relative

                             to each segmented 8×8 block of pixels}

                            for iCount2 := 0 to 15 do

                              for iCount3 := 0 to 12 do

                              begin

                                {copy the relative block of pixels from the

                                 next image into the back buffer}

                                Block := Rect((5*RandBlock)+(iCount2*8*5),

                                              (5*RandBlock2)+(iCount3*8*5),

                                              (5*RandBlock)+(iCount2*8*5)+5,

                                              (5*RandBlock2)+(iCount3*8*5)+5);

                                FBackBuffer.BltFast(Block.Left, Block.Top,

                                                 ScreenBackgrounds[NextBackground],

                                                 Block, DDBLTFAST_NOCOLORKEY or

                                                 DDBLTFAST_WAIT);

                              end;

                            {copy this frame of animation to the screen}

                            Block := Rect(0, 0, DXWIDTH, DXHEIGHT);

                            FPrimarySurface.BltFast(0, 0, FBackbuffer, Block,

                                                    DDBLTFAST_NOCOLORKEY or

                                                    DDBLTFAST_WAIT);

                            {pause for a short period}

                            Sleep(20);

                          end;

                          {the animation is over, so copy the final image to both

                           the front and back buffers to erase the last remains of

                           the animation sequence}

                          Block := Rect(0, 0, DXWIDTH, DXHEIGHT);

                          FBackbuffer.BltFast(0, 0,

                                              ScreenBackgrounds[NextBackground],

                                              Block, DDBLTFAST_NOCOLORKEY or

                                              DDBLTFAST_WAIT);

                          FPrimarySurface.BltFast(0, 0,

                                                 ScreenBackgrounds[NextBackground],

                                                 Block, DDBLTFAST_NOCOLORKEY or

                                                 DDBLTFAST_WAIT);

                      end;

      end;

    end;
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.