views:

117

answers:

2

I am following a tutorial. And I am trying to draw a .bmp file to the screen. It builds with no errors but no image appears. according to the book, I should see the image pop up in random places. Below is my code. The author doesnt recommend this technique for drawing objects, he is just doing for demostration. In case your wondering.

The image is a 25x25 square red square.

#include <windows.h>
#include <iostream>
#include <time.h>

using namespace std;

const string APPTITLE = "Game Loop";
HWND window;
HDC device;
bool gameover = false;


void DrawBitmap(char *filename, int x, int y)
{
 //load the bitmap image
 HBITMAP image = (HBITMAP)LoadImage(0,"c.bmp", IMAGE_BITMAP,0,0, LR_LOADFROMFILE);

 BITMAP bm;
 GetObject(image, sizeof(BITMAP), &bm);

 HDC hdcImage = CreateCompatibleDC(device);
 SelectObject(hdcImage,image);

 BitBlt(
  device,
  x,y,
  bm.bmWidth, bm.bmHeight,
  hdcImage,
  0,0,
  SRCCOPY);

 //deletec the device context and bitmap
 DeleteDC(hdcImage);
 DeleteObject((HBITMAP)image);
}

bool Game_Init()
{
 srand(time(NULL));
 return 1;
}

void Game_Run()
{
 if(gameover == true) return;

 RECT rect;
 GetClientRect(window, &rect);

 //draw bitmap at random location
 int x = rand() % (rect.right - rect.left);
 int y = rand() % (rect.bottom - rect.top);

 DrawBitmap("c.bmp",x,y);
}

void Game_End()
{
 //free the device
 ReleaseDC(window,device);
}

LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM WParam, LPARAM lparam)
{
 switch(message)
 {
  case WM_DESTROY:
   gameover = true;
   PostQuitMessage(0);
  break;
 }

 return DefWindowProc(hWnd, message, WParam, lparam);
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
 //set the new windows properties

 WNDCLASSEX wc;

 wc.cbSize  = sizeof(WNDCLASSEX);
 wc.style  = CS_HREDRAW | CS_VREDRAW;
 wc.lpfnWndProc = (WNDPROC) WinProc;
 wc.cbClsExtra = 0;
 wc.cbWndExtra = 0;
 wc.hInstance = hInstance;
 wc.hIcon  = NULL;
 wc.hCursor  = LoadCursor(NULL, IDC_ARROW);
 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
 wc.lpszMenuName = NULL;
 wc.lpszClassName= APPTITLE.c_str();
 wc.hIconSm  = NULL;

 return RegisterClassEx(&wc);
}

bool InitInstance(HINSTANCE hInstance, int nCmdShow)
{
 //create a  new window
 window = CreateWindow(
  APPTITLE.c_str(),
  APPTITLE.c_str(),
  WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT, CW_USEDEFAULT,
  640,480,
  NULL,
  NULL,
  hInstance,
  NULL);

 //was there an error creating the window ?
 if(window == 0) return 0;

 //display the window 
 ShowWindow(window, nCmdShow);
 UpdateWindow(window);
 device = GetDC(window);

 return 1;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
      LPSTR lpCmdLine, int nCmdShow)
{
 //declare variables
 MSG msg;

 //register the class
 MyRegisterClass(hInstance);

 //initialize application
 if(!InitInstance(hInstance, nCmdShow)) return 0;

 //initilize the game
 if(!Game_Init()) return 0;

 //main message loop
 while(!gameover)
 {
  if(PeekMessage(&msg,NULL, 0, 0,PM_REMOVE))
  {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  }
  Game_Run();
 }

 Game_End();

 return msg.wParam;
}

I am not sure if its because I have the image in the wrong location. but if that was the case. I figure it would throw a error. I have the image placed at the root of my source folder.

[EDIT]

Also , when I rebuild, I get a warning which might be a cause but here is the warning

1>------ Rebuild All started: Project: Begin, Configuration: Debug Win32 ------
1>Deleting intermediate and output files for project 'Begin', configuration 'Debug|Win32'
1>Compiling...
1>main.cpp
1>c:\users\numerical25\documents\visual studio 2008\projects\begin\begin\main.cpp(39) : warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data
1>Compiling manifest to resources...
1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Copyright (C) Microsoft Corporation.  All rights reserved.
1>Linking...
1>LINK : C:\Users\numerical25\Documents\Visual Studio 2008\Projects\Begin\Debug\Begin.exe not found or not built by the last incremental link; performing full link
1>Embedding manifest...
1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Copyright (C) Microsoft Corporation.  All rights reserved.
1>Build log was saved at "file://c:\Users\numerical25\Documents\Visual Studio 2008\Projects\Begin\Begin\Debug\BuildLog.htm"
1>Begin - 0 error(s), 1 warning(s)
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

alt text

+5  A: 

The code does work, you just forgot to put your c.bmp in the right location. Put it in the project output folder (i.e. bin/Debug) if you're launching the program from Explorer or to the project folder if you're lanching the program from Visual Studio.

Kerido
k, I will try it out. thanks
numerical25
It worked. I wasnt sure where images run relative to the application. but it makes sense that would run relative to the .exe file. Thanks
numerical25
I can't count how many simple little games I wrote back in the day where I'd be scratching my head for hours until I realized this... every single time.
rmeador
A: 

Your code seems to work, for a sufficiently loose definition of "work". Unless you've modified the code (quite a bit) in attempting to make it work, my advice would be to find a different tutorial to follow -- at least to me, most of what's there right now is quite unimpressive.

Just for example, Game_Run() passes the name of the bitmap file as a parameter to Draw_Bitmap(), but the parameter gets ignored, and Draw_Bitmap() uses a hard-coded file name instead.

The PeekMessage() loop makes the program look like it was written about 25 years ago, in the days of 16-bit Windows (and arguably not so great even then). There's rarely (if ever) a good reason to use PeekMessage() in a new code, and code that did use it is probably overdue for an overhaul. The main loop normally uses GetMessage(), and you can (for example) use SetTimer (with a duration of 0) to compute new coordinates for drawing the bitmap, and then calling InvalidateRect() to get it drawn. At one time there was a fair argument that the extra messages involved in this caused excessive overhead, but on a modern machine it'll keep up with the monitor refresh rate while using on the order of 10% of the CPU or less.

To keep CPU usage down, however, you want to restructure the code a bit -- right now, every time you draw, you're getting the window rectangle, reloading the BMP from disk, selecting the BMP into a compatible DC, and finally BitBlting to get the image to the screen. That's the part of the code where optimization will make a difference -- by strong preference, you want it to just call BitBlt and be done. The rest of the code should be moved elsewhere so it happens only when needed. For example, you can retrieve the window rectangle in response to WM_SIZE, and just save it in-between. Since you're using the same bitmap for the duration, load it once, and from them on just display it.

Jerry Coffin
Yea I notice the ignore parameter in Draw_Bitmap(). as well . I corrected it. I am trying to find a errata for the book. The book is "Beginning Game Programming" Third Edition. Also the arthur stated that that type of format would be the last he will use in the book and he acknowledge that it was not a correct way of drawing objects. He was demonstrating how you would have to render objects if you did not use the direct x sdk. This is at the very beginning of the book just to get things going. I am going to give it a chance a little while longer.
numerical25
@numerical25: Even without using DirectX, this isn't really (at least IMO) the "right" way to draw much of anything.
Jerry Coffin