Thread: [GDI] Scrolling texture?

  1. #1
    Registered User
    Join Date
    Dec 2005
    Posts
    43

    [GDI] Scrolling texture?

    Hello.

    I'm writing a basic Asteroid game in GDI using double buffering. The ship, the background and the asteroids (which are drawn using Polygon()) were initially colored with a solid color HBRUSH, but now I'm trying to replace all of the colors with BMP textures. For the background, I used LoadBitmap() and CreatePatternBrush() to add a starry texture. That method doesn't seem to work with the asteroids though, because they are moving, so I get a scrolling texture. Is there any way to fix that? Here's my code for moving/drawing the asteroids:

    Code:
    HBITMAP asteroidsBitmap = LoadBitmap ( GetModuleHandle ( NULL ), MAKEINTRESOURCE ( IDB_BITMAP2 ) );
    HBRUSH  asteroidsBrush  = CreatePatternBrush ( asteroidsBitmap );
    Code:
    	// Move asteroids
    	for ( int element = 0; element < MAX_ROCKS; element++ )
    	{
    		if ( rocks [ element ].alive )
    		{
    			x = rocks [ element ].xCenter;
    			y = rocks [ element ].yCenter;
    
    			x += rocks [ element ].xMove;
    			y += rocks [ element ].yMove;
    
    			// Check if out of range on x axis
    			if ( ( x < 25 ) || ( x > ( WINDOW_WIDTH - 25 ) ) )
    				x = WINDOW_WIDTH - x;
    
    			// Check if out of range on y axis
    			if ( ( y < 25 ) || ( y > ( WINDOW_HEIGHT - 25 ) ) )
    				y = WINDOW_HEIGHT - y;
    
    			rocks [ element ].xCenter = x;
    			rocks [ element ].yCenter = y;
    
    			SelectObject ( backDC, asteroidsBrush );
    
    			SetAsteroidVertices ( element );
    
    			Polygon ( backDC, asteroidVertices, 9 );
    		}
    	}
    Thanks.

  2. #2
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,273
    Well... if that's what you really wanna do, I'd actually use a bitmap instead of a patterned brush like you have there. Use LoadImage to get something from a file or resource and keep it with a memory DC (created using CreateCompatibleDC(NULL)). Then use the polygon to define a clipping region and just BitBlt the bitmap to the back buffer.

    That's the theory, anyways. Haven't actually done it myself...

  3. #3
    Registered User
    Join Date
    Dec 2005
    Posts
    43
    Thanks. I'm not too familiar with clipping and regions, but here's what I came up with:

    In Globals:
    Code:
    HDC       memoryDC     = NULL;
    
    HBITMAP asteroidBitmap = LoadBitmap ( GetModuleHandle ( NULL ), MAKEINTRESOURCE ( IDB_BITMAP2 ) );
    HRGN    asteroidRegion;
    In Game Initialization Function:
    Code:
    	memoryDC = CreateCompatibleDC ( backDC );
    In Move/Draw Asteroids Function:
    Code:
    			SetAsteroidVertices ( element );
    
    			SelectObject ( memoryDC, asteroidBitmap );
    
    			asteroidRegion = CreatePolygonRgn ( asteroidVertices, 9, ALTERNATE );
    			SelectClipRgn ( memoryDC, asteroidRegion );
    
    			BitBlt ( backDC, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, memoryDC, 0, 0, SRCCOPY );
    Something's not right though. I don't see the asteroids; instead, I see my asteroid bitmap texture at the top left corner of the screen. What am I doing wrong?

  4. #4
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,273
    Code:
    	memoryDC = CreateCompatibleDC ( backDC );
    To my knowledge this will get you a black and white DC due to the funny way memory DCs work. You should be using the desktop (screen) DC instead (change "backDC" to "NULL") for colour.
    Code:
    			SelectObject ( memoryDC, asteroidBitmap );
    Be careful! By not storing the return value here you are leaving a 1x1 black and white bitmap dangling out in the emptyness of memory. When a memory DC is created it has a bitmap, so in order to prevent a memory leak you should store the return value and select it back into the memory DC when your program exits.
    Code:
    			SelectClipRgn ( memoryDC, asteroidRegion );
    			BitBlt ( backDC, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, memoryDC, 0, 0, SRCCOPY );
    You should be selecting the clipping region into the back DC. BitBlt will then respect the region when you copy from the memory DC. There should also be the top-left coordinates and the total width and height of the asteroid for the second to fifth parameters of BitBlt, so if the asteroid was at 10, 10 and was 32x16 you'd have:-
    Code:
    BitBlt (backDC, 10, 10, 32, 16, memoryDC, 0, 0, SRCCOPY);

  5. #5
    Registered User
    Join Date
    Dec 2005
    Posts
    43
    Alright, here's the updated code:

    In Globals:
    Code:
    HGDIOBJ memoryBmp = NULL;
    In Game Initialization Function:
    Code:
    	memoryDC = CreateCompatibleDC ( NULL );
    In Move/Draw Asteroids Function:
    Code:
    			SetAsteroidVertices ( element );
    
    			memoryBmp = SelectObject ( memoryDC, asteroidBitmap );
    
    			asteroidRegion = CreatePolygonRgn ( asteroidVertices, 9, ALTERNATE );
    			SelectClipRgn ( backDC, asteroidRegion );
    
    			BitBlt ( backDC, rocks [ element ].xCenter - 12 * rocks [ element ].size, rocks [ element ].yCenter - 12 * rocks [ element ].size, 12 * rocks [ element ].size * 2, 12 * rocks [ element ].size * 2, memoryDC, 0, 0, SRCCOPY );
    		        SelectClipRgn ( backDC, NULL );
    In GameQuit Function:
    Code:
    	SelectObject ( memoryDC, memoryBmp );
            DeleteDC ( memoryDC );
    The texture is not scrolling anymore and everything seems to work fine, but after a while, the asteroids become rectangles and the ship's bullets are not displayed anymore. Am I doing anything wrong?

  6. #6
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,273
    Can't tell without reviewing the entire code (which I don't want to do), but now's a good time to learn how to debug. Look up each of the functions you use in MSDN, check what is returned when there's a problem and test for it.

    Seeing as everything works fine for a time, I would say you're creating GDI objects but not properly destroying them afterwards, like what I pointed out with the memory DC's initial bitmap.

    This is where you earn your stripes.

  7. #7
    Registered User
    Join Date
    Dec 2005
    Posts
    43
    It works! I had to delete the HRGN using DeleteObject() after using it, as specified in the MSDN.

    Thanks for all the help.

    Time to texture the ship!

  8. #8
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Quote Originally Posted by SMurf
    To my knowledge this will get you a black and white DC due to the funny way memory DCs work. You should be using the desktop (screen) DC instead (change "backDC" to "NULL") for colour.
    A memory DC is created with a 1x1 Black and white bitmap selected into it.

    You need to CreateCompatibleBitmap() and select it in.

    It is not as important (under .NET IDEs) but is good practice to put a DC back EXACTLY the way you found it (ie catch all SelectObject() returns and SelectObject() the default items back before deleting the new / created objects and the DC)
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. d3d9 c++ texture wrapper... again...
    By yaya in forum Game Programming
    Replies: 0
    Last Post: 04-01-2009, 01:08 PM
  2. D3d Texture Wrapper == ARRRGGGGHHH
    By yaya in forum Game Programming
    Replies: 1
    Last Post: 03-25-2009, 06:41 PM
  3. Replies: 4
    Last Post: 02-27-2008, 03:10 PM
  4. OpenGL - look trough surface -nehe lesson
    By GanglyLamb in forum Game Programming
    Replies: 8
    Last Post: 08-24-2006, 11:06 PM
  5. Pong is completed!!!
    By Shamino in forum Game Programming
    Replies: 11
    Last Post: 05-26-2005, 10:50 AM