Thread: Slow drawing code

  1. #1
    Registered User
    Join Date
    Oct 2007
    Posts
    66

    Slow drawing code

    I'm using the WinAPI directly for drawing a grid, and extrapolating a 32x32 bitmap image to fit inside of that grid. (Basically, it's a zoom function with a grid-overlay.) Anyways, I've been looking for alternative ways to do this that would be faster but I can't quite find any, so I'm here asking for help!

    The code takes around 3-4 seconds to draw the "image." I would like it to be instant. I'm not sure how I can optimize the code, so, any suggestions/pointers in the right direction would be _wonderful!_ Thanks in advanced if anyone can help me:

    (btw: I've tested the code with just drawing the grid and just drawing the bitmap, it appears to take roughly 3-4 seconds regardless of weather I render only the grid, only the bitmap, or both. It doesn't make any sense to me, seems like it should take longer to draw both together if it was the drawing code at fault, so I'm wondering if it's either my loops or something else, but I'm not sure how to optimize any of it :x)

    EDIT: Oh, also CSize is a class that basically stores two ints, int x and int y. getX() returns that x, and getY() returns that y. (It's really basic, the prototype for the functions is pretty much simply void getX() { return x; } void getY() { return y; }) I doubt that's the slow-down...but maybe?

    Code:
    bool CCharEdit::renderGrid(HDC hdc)
    {
    	// Stuff we need
    	RECT gridRect;
    	CSize gridRectSize;
    
    	HDC hdcMem;
    	HBITMAP hBmOld;
    	BITMAP bm;
    
    	// Create a Black color
    	HBRUSH hBr = CreateSolidBrush(RGB(0,0,0));
    
    	// find the size of each grid "pixel"
    	gridRectSize.setSize((m_gridZoom*m_gridSize.getX()), (m_gridZoom*m_gridSize.getY()));
    
    	// Set the upper-bounds for the grid
    	gridRect.top = 10;
    	gridRect.left = 10;
    
    	// Find the lower-bounds for the grid
    	gridRect.bottom = gridRect.top + gridRectSize.getY();
    	gridRect.right = gridRect.left + gridRectSize.getX();
    
    	// Initialize the bitmap
    	hdcMem = CreateCompatibleDC(hdc);
    
    	hBmOld = (HBITMAP)SelectObject(hdcMem, m_hBmp);
    	GetObject(m_hBmp, sizeof(bm), &bm);
    
    	// Draw the grid
    	for ( int i = 0; i < m_Size.getX(); ++i )			// the rows
    	{
    		for ( int j = 0; j < m_Size.getY(); ++j )		// the columns
    		{
    			// Draw the grid-square
    			MoveToEx(hdc, gridRect.left, gridRect.top, NULL);
    			LineTo(hdc, gridRect.left, gridRect.bottom);
    			LineTo(hdc, gridRect.right, gridRect.bottom);
    			LineTo(hdc, gridRect.right, gridRect.top);
    			LineTo(hdc, gridRect.left, gridRect.top);
    
    			// Render the portion of the model
    			// that corresponds to this portion
    			// of the grid
    			for ( int k = 1; k < m_gridZoom; ++k )
    			{
    				for ( int l = 1; l < m_gridZoom; ++l )
    				{
    					BitBlt(hdc, gridRect.left+k, gridRect.top+l, 1, 
    						1, hdcMem, i, j, SRCCOPY);
    				}
    			}
    
    			// Translate on to the next grid-square
    			gridRect.top = gridRect.bottom;
    			gridRect.bottom = gridRect.top + gridRectSize.getY();
    		}
    		// Translate on to the next row
    		gridRect.left = gridRect.right;
    		gridRect.right = gridRect.left + gridRectSize.getX();
    
    		// Set the grid column back to the top
    		gridRect.top = 10;
    		gridRect.bottom = gridRect.top + gridRectSize.getY();
    	}
    
    	// Clean Up
    	DeleteObject(hBr);
    
    	SelectObject(hdcMem, hBmOld);
    	DeleteDC(hdcMem);
    	DeleteObject(hBmOld);
    
    	// return true for success
    	return true;
    }
    Last edited by tjpanda; 05-08-2008 at 02:04 AM. Reason: Noted what CSize is
    "When your work speaks for itself - don't interrupt!"

    -Samantha Ingraham.

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Small benefit can perhaps be had from copying this out of the loop condition:
    Code:
    xSize = m_Size.getX();
    ySize = m_Size.getY();
    	for ( int i = 0; i < xSize; ++i )			// the rows
    	{
    		for ( int j = 0; j < ySize; ++j )		// the columns
    		{
    Blitting a single pixel at a time is definitely going to be HIGHLY time consuming. Perhapa StretchBlt may help here.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    Oct 2007
    Posts
    66
    Ohh that's a nifty function - thanks matsp! I'll go implement that right now.

    edit:

    That helped _a lot_ !! It's instant, it flashes a lot but it's instant! I just need to double buffer then I think to get rid of the flashing and it should be good to go, hooray XD Thanks again matsp!
    Last edited by tjpanda; 05-08-2008 at 02:18 AM.
    "When your work speaks for itself - don't interrupt!"

    -Samantha Ingraham.

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Use StretchBlt or some other appropriate GDI blit function.

    Only draw from rect.top to rect.bottom in rect.left to rect.right order. The moment you go beyond rect.bottom, reset your Y to rect.top, and increment your map_offset. There are fewer pixels down the screen than across the screen so drawing top to bottom left to right is faster than left to right, top to bottom.

    Get rid of the inner loop and use a linear offset inside of the outer loop to access your world tile map data. In this way you can completely remove the multiply from the equation and your loop boils down to a few adds.

    But beyond that GDI is slow. It was meant for robustness not speed. Use OpenGL, Direct3D or some other graphics API for doing graphics in Windows. GDI is not worth the trouble.
    Last edited by VirtualAce; 05-08-2008 at 04:55 PM.

  5. #5
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    I use GDI, its fine for anything up to about 100 fps, but all I really use it for is to display an already composed image.

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I use GDI, its fine for anything up to about 100 fps, but all I really use it for is to display an already composed image.
    It depends on what you want to do. GDI isn't even good for simple 2D games.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. making programms faster
    By deian in forum C Programming
    Replies: 23
    Last Post: 10-09-2004, 12:19 AM
  2. Binary Search Trees Part III
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 10-02-2004, 03:00 PM
  3. True ASM vs. Fake ASM ????
    By DavidP in forum A Brief History of Cprogramming.com
    Replies: 7
    Last Post: 04-02-2003, 04:28 AM
  4. Interface Question
    By smog890 in forum C Programming
    Replies: 11
    Last Post: 06-03-2002, 05:06 PM
  5. Replies: 4
    Last Post: 01-16-2002, 12:04 AM