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
Alternatives/Enhancements The only thing limiting transition effects from one scene to another is the imagination of the programmer. While the three covered here are easy to implement, you can probably think of several dozen more that could be implemented just as easily. Many transition effects available from third-party products are little more than extensions of the effects implemented in the above example. The effects demonstrated above rely on the fact that the images involved in the transition have the same palette. Using some palette manipulation, it may be possible to use images with two different palettes. This would require a new palette to be created for each frame of the transition animation, but this would result in a more flexible scene transitioning system.
| Tip: Using a non-palettized display mode would, of course, eliminate this drawback.
#### Simple Texture Mapping We’ve seen how easy it is to blit rectangular sections of bitmaps onto the screen or into offscreen buffers. If you’ve done any basic Windows graphics programming, you also know how easy it is to draw geometric shapes. It would be cool if we could somehow draw geometric shapes but use a bitmap as the contents of that shape, as opposed to simply filling it with color. The technique of mapping a bitmap image onto a geometric shape is known as texture mapping.
| texture mapping: A general term for algorithms that map a bitmap image onto a geometric shape.
Texture mapping techniques can be applied in many exciting ways. Texture mapping techniques allow us to produce very convincing graphical images of real-world objects, which would be very difficult or impossible to achieve otherwise. Algorithms that implement texture mapping range from the childishly simple to the absurdly complex. Let’s look at a relatively simple texture mapping method that will allow us to wrap a bitmap around a circular shape to produce the illusion of a sphere. Basic Theory Perhaps the first thing we will need is the texture to be mapped onto the shape. In this example, we’ll create an animation of a planet spinning in space. Thus, our texture map should look like a planet, and will be rectangular in shape. Figure 11-8: The texture map Next, we need to define the circular shape itself. Specifically, we’ll be using some of the scaling techniques described previously, so we need a series of points that define the perimeter of the circle. We can generate these points by using the equation for a circle:
    MinorAxis := Sqrt((Radius * Radius)-(MajorAxis * MajorAxis))
The circle is generated at application startup and therefore does not have to be particularly fast. However, we’ll make use of the symmetrical property of circles to generate points only for the first quadrant. These points can then be mirrored around the horizontal, vertical, and diagonal axes to form an entire circle, as illustrated in Figure 11-9. Figure 11-9: Using symmetry to mirror points around a circle Since our circular shape will be drawn one line of pixels at a time, the generated points serve as endpoints for each line of the circle. The actual texture mapping occurs by using the scaling techniques described above in conjunction with these endpoints to stretch each line of the texture bitmap between the endpoints of each line in the circle. Figure 11-10: Defining a circle using endpoints By defining a rectangular area smaller than the texture map, and then using scaling techniques to stretch the defined rectangular area not only vertically across the circular shape but also horizontally between each pair of endpoints, the resulting image seems to warp and magnify at the center of the circle. This produces a convincing illusion of an image wrapped around a sphere. The following listing demonstrates this technique. Listing 11-6: Wrapping a texture around a sphere
    interface

    const

       .

       .

       .

      {the position of the center of the screen}

      XPos = 320;

      YPos = 240;

       .

       .

       .

    var

       .

       .

       .

      {tracks our endpoints}

      FEndptList: TList;

      {tracks the width of the portion of the texture to be wrapped

       around the sphere}

      FTextureSwatchWidth: Integer;

      {tracks the texture offset}

      TextureOffset: Integer;

       .

       .

       .

    @code =

    procedure TfrmDXAppMain.FormDestroy(Sender: TObject);

    begin

       .

       .

       .

      {free the endpoint list}

      FEndptList.Free;

    end;

    procedure TfrmDXAppMain.FormActivate(Sender: TObject);

    begin

       .

       .

       .

      {load the palette}

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

                                ‘Texture.bmp’);

      {set the palette}

      FPrimarySurface.SetPalette(FPalette);

      {create the circle}

      GenerateCircle(100, ExtractFilePath(ParamStr(0))+‘Texture.bmp’);

      {initialize the texture offset}

      TextureOffset := 0;

      {erase the screen}

      ColorFill(FPrimarySurface, 255, nil);

      ColorFill(FBackBuffer, 255, nil);

       .

       .

       .

    end;

    procedure TfrmDXAppMain.DrawSurfaces;

    var

      iCount, iCount2: Integer;

      SrcYRatio, SrcXRatio: Double;

      TextureX: Integer;

      SrcRect: TRect;

      SourceSrfcDesc, DestSrfcDesc: TDDSurfaceDesc2;

      iCol, iRow: Integer;

      SourceSrfcPtr, DestSrfcPtr: PBytePtr;

    begin

      try

        {begin by locking the source buffer}

        FillChar(SourceSrfcDesc, SizeOf(TDDSurfaceDesc2), 0);

        SourceSrfcDesc.dwSize := SizeOf(TDDSurfaceDesc2);

        FTexture.Lock(nil, SourceSrfcDesc, DDLOCK_WAIT, 0);

        {now lock the destination buffer}

        FillChar(DestSrfcDesc, SizeOf(TDDSurfaceDesc2), 0);

        DestSrfcDesc.dwSize := SizeOf(TDDSurfaceDesc2);

        FBackBuffer.Lock(nil, DestSrfcDesc, DDLOCK_WAIT, 0);

        DestSrfcPtr := PBytePtr(Longint(DestSrfcDesc.lpSurface)+XPos+

                       ((YPos-(FEndptList.Count div 2))*DestSrfcDesc.lPitch));

        {determine the ratio for stretching the texture map vertically}

        SrcYRatio := SourceSrfcDesc.dwHeight / FEndptList.Count;

        {increment the texture offset}

        Inc(TextureOffset);

        {rollover the texture offset if necessary}

        if TextureOffset > SourceSrfcDesc.dwWidth then

          TextureOffset := 0;

        {for each pair of endpoints in the endpoint list...}

        for iCount := 0 to FEndptList.Count-1 do

        begin

          {initialize the source pointer according to the next vertical pixel}

          SourceSrfcPtr := PBytePtr(Longint(SourceSrfcDesc.lpSurface)+

                           (SourceSrfcDesc.lPitch*Trunc(SrcYRatio * iCount)));

          {determine the ratio for stretching the texture map horizontally.

           the endpoints are stored as a single value relative to the center of

           the circle, so this value must be doubled to get the correct ratio}

          SrcXRatio := FTextureSwatchWidth / (Integer(FEndptList[iCount])*2);

          {for each pixel in this horizontal row...}

          for iCount2 := 0 to Integer(FEndptList[iCount])*2 do

          begin

            {retrieve the next texture pixel}

            TextureX := Trunc(SrcXRatio * iCount2)+TextureOffset;

            {roll this over if necessary}

            if TextureX >= SourceSrfcDesc.dwWidth then

              TextureX := TextureX-SourceSrfcDesc.dwWidth;

            {since the endpoint is a value relative to the center axis of

             the circle, we simply subtract the endpoint value from our loop

             counter to get the correct horizontal pixel coordinate}

            DestSrfcPtr^[iCount2-Integer(FEndptList[iCount])] :=

                        SourceSrfcPtr^[TextureX];

          end;

          {increment to the next line of pixels in the destination}

          Inc(DestSrfcPtr, DestSrfcDesc.lPitch);

        end;

      finally

        {unlock both buffers}

        FTexture.Unlock(nil);

        FBackBuffer.Unlock(nil);

      end;

    end;

       .

       .

       .

    procedure TfrmDXAppMain.GenerateCircle(Radius: Integer; Texture: string);

    var

      MajorAxis, MinorAxis: integer;

      YOffset: Integer;

      XOfsQuad1, XOfsQuad2: TList;

      iCount: Integer;

    begin

      {create the endpoint list}

      FEndptList := TList.Create;

      {create the quadrant lists}

      XOfsQuad1 := TList.Create;

      XOfsQuad2 := TList.Create;

      {initialize the major and minor axes and the y offset}

      MajorAxis := 0;

      YOffset := Radius;

      MinorAxis := Radius;

      {using the symmetry of a circle, we will store endpoints as only a single

       value relative to the Y axis, or center, of the circle. when drawing

       the texture, we will simply use 0-EndPointValue as the first point in

       the pair of endpoints}

      {loop until the major and minor axes meet}

      while MajorAxis <= MinorAxis do

      begin

        {increment the major axis}

        Inc(MajorAxis);

        {find the minor axis according to the circle equation, adding a small

         offset to make a more rounded circle}

        MinorAxis := Trunc(Sqrt((Radius*Radius) - (MajorAxis*MajorAxis))+0.5);

        {add this value to the second quadrant}

        XOfsQuad2.Insert(0, TObject(MinorAxis));

        {in the first 8th of the circle, the Y value will not be incrementing

         each time, so only store this endpoint when the Y value increases}

        if MinorAxis < YOffset then

        begin

          {add this endpoint to the first quadrant}

          XOfsQuad1.Add(TObject(MajorAxis));

          YOffset := MinorAxis;

        end;

      end;

      {define the width of the texture to be mapped as the major axis value. this

       will cause the texture to be shrunk near the top of the circle, and

       stretched near the center of the circle}

      FTextureSwatchWidth := MajorAxis;

      {finally, add the endpoints in our quadrant lists to the final endpoint

       list in the correct order (from the top of the circle to the bottom)}

      for iCount := 0 to XOfsQuad1.Count-1 do

        FEndptList.Add(XOfsQuad1[iCount]);

      for iCount := 1 to XOfsQuad2.Count-1 do

        FEndptList.Add(XOfsQuad2[iCount]);

      {these coordinates just list the top half of the circle, so we must

       mirror these and add them to the list to define the bottom half}

      for iCount := FEndptList.Count-1 downto 0 do

        FEndptList.Add(FEndptList[iCount]);

      {free the quadrant lists}

      XOfsQuad1.Free;

      XOfsQuad2.Free;

      {load the circle’s texture map}

      FTexture := DDLoadBitmap(FDirectDraw, Texture)

    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.