| 
 DirectDraw:
Scrolling Pictures 
By: Jack Hoxley 
Written: June 2000 
  Download: 
  DD_Scrolling.Zip 
  (302kb)    
 
Scrolling backgrounds are fairly 
  easy once you know how; but there are several places where it is easy to slip 
  up; it also seems to be quite popular with people - I'm often getting asked 
  how to do this. 
Making a scrolling background 
  isn't difficult at all; you just need to get the maths correct and the rectangle 
  to fit together correctly. The main reason everyone slips up is with wide surfaces. 
  Although I am not sure of this, most graphics cards support wide surfaces, that 
  is, a surface wider than the screen. But then there are those that dont - such 
  as the older computers, people also find that performance drops dramatically 
  when using large pictures 
There are two choices - whether 
  you use one large backdrop divided into several smaller ones; or lots of repeating 
  small ones. When you're dealing with 16-32mb graphics cards you can safely go 
  for the first option; only when you are dealing with 4mb cards or lower does 
  it become a problem. Do not be fooled by the amount of video memory on a card 
  - My Savage 4 has 32Mb on board, yet reports that DirectDraw has 29,400kb (28.7mb) 
  of available memory, and my 1mb unbranded 2D card has only 602kb of available 
  space. Basically, although it may well have 32Mb of memory, it will old a little 
  back for itself - temporary data or other drivers etc... You may well think 
  that using system memory solves this problem, in a way it does - but it will 
  also slow things down. 
In this example we will discuss 
  1-way scrolling, such as a background moving along behind a platformer game. 
  2-way scrolling has exactly the same ideas, but requires a little bit more thought. 
We will have 3 640x480 pictures, 
  in total that will represent a 1920x480 surface. Dont be surprised if your computer 
  grinds to a halt whilst trying this, see above for why. The complex part of 
  doing the scrolling is working out which parts of which surface we are going 
  to require. We will require either one or two rectangles. 
The logic behind it is: 
  If the X coordinate is >0 and <640 then RECT1 is on surface 1 
  If the X coordinate is >640 and <1280 then RECT1 is on surface 2 
  If the X coordinate is >1280 and <1920 then RECT1 is on surface 3 
we can then work out the size
of this first rectangle from this formula: 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        Rect.Left = X coordinate 
      - (SurfaceNum *640 ) 'where the surfaces are 0,1,2 
      Rect.Top = 0: Rect.Bottom = 480 
      Rect.Right = 640 - Rect.Left | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
 Then, what if the
rectangle requires to go over the boundaries of a surface - we require a second
rectangle to Blit the second part. The easiest way to work things out here is
with a select case - If there were lots of sections you may well need to rethink
this:  
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        Select case Xcoordinate 
        case is <640 'Rect1 will be part of surface 1 
        'So we need Rect2 to be part of surface 2 
        case is <1280 'Rect1 will be part of surface 
        2 
        'So we need Rect2 to be part of surface 3 
        case is <1920 'Rect1 will be part of surface 
        3 
        'we dont need another Rect 
        end select | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
So we now know if we need a
second rectangle, and which surface it will be part of. We now need to work out
it's position: 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        Dim XPos As Integer 
      XPos = (Rect1.Right - Rect1.Left)  
      Rect2.Left = 0 'Always on the left hand part of the 
      surface 
      Rect2.Right = 640 - XPos 'we want the width of the 
      screen - the distance into the screen.  
      Rect2.Top = 0: Rect2.Bottom = 480 | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Now we should have either one
or two correctly sized rectangles. Now we need to work out their screen X/Y
coordinates, and use BltFast to copy them there... 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        'First (left hand) section 
         
        ddrval = backbuffer.BltFast(0, 0, Section(SurfaceNum), Rect1, DDBLTFAST_WAIT) 
        'Second (Right Hand) section 
        ddrval = backbuffer.BltFast(XPos, 0, Section(SurfaceNum + 1), Rect2, DDBLTFAST_WAIT) 
         | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Now; we should be able to
change a global variable "XCoordinate" and the program will adapt and
work the rest out itself - Easy! Should you want more sections it will be fairly
easy to do, but remember that fullscreen surfaces will use up lots of memory and
possibly stop working completely. Using sections that are smaller than the width
of the screen is easy now, just modify the correct lines above and it'll work... 
You can download a working
example from the top of this page, or from the downloads
page.  
                                       |