//Program: Image Viewer
//Author:  Dave Javaheri
//Date:    9/08/2000
//DEFINES//////////////////////////////////////////////////////////////
#define INITGUID
#define WIN32_LEAN_AND_MEAN  
#define SCREEN_WIDTH      640   //screen resolution
#define SCREEN_HEIGHT     480
#define SCREEN_BPP        16    //screen bitdepth (8,16,24 etc.)
#define DDRAW_INIT_STRUCT(ddstruct) {memset(&ddstruct,0,sizeof(ddstruct));ddstruct.dwSize=sizeof(ddstruct);}
#define SafeRelease(x) if (x) { x->Release(); x=NULL;}
  
//INCLUDES/////////////////////////////////////////////////////////////
#include <windows.h>   // include important windows stuff
#include <windowsx.h> 
#include <stdio.h>
#include <ddraw.h>
#include <mmsystem.h>
  
//ERROR STRINGS////////////////////////////////////////////////////////
const char *ErrStr=NULL;	
  const char Err_Reg_Class[]			= "Error Registering Window Class";
const char Err_Create_Win[]			= "Error Creating Window";
const char Err_DirectDrawCreate[]	= "DirectDrawCreate FAILED";
const char Err_Coop[]				= "SetCooperativeLevel FAILED";
const char Err_CreateSurf[]			= "CreateSurface FAILED";
const char Err_GetBack[]			= "Error Retrieving Back Buffer";
const char Err_DispMode[]			= "Error Setting Display Mode";
const char Err_LoadImage[]			= "Error Loading Image";
  
//WINDOW CLASS INFORMATION/////////////////////////////////////////////
static char szClass[] = "Image Loader";
static char szCaption[] = "Image Loader";
  
//GLOBALS//////////////////////////////////////////////////////////////
LPDIRECTDRAW7        lpDD = NULL;         //ddraw object
LPDIRECTDRAWSURFACE7 lpDDSPrimary = NULL; //primary surface
LPDIRECTDRAWSURFACE7 lpDDSBack = NULL;    //backbuffer
LPDIRECTDRAWSURFACE7 bitmap_surface = NULL; //holds bitmap
HWND hWnd = NULL; //main window handle
int x1 = 0;   //starting size of rect
int y1 = 0;
int x2 = 200;
int y2 = 200;
  RECT rct;
char buffer[126];
  char *g_filename = "bitmap24.bmp";  //the file name of the bmp
  //PROTOTYPES///////////////////////////////////////////////////////////
void Game_Shutdown();
static BOOL Init(HINSTANCE hInstance, int nCmdShow);
int Game_Main();
LPDIRECTDRAWSURFACE7 LoadSurface(LPCTSTR file_name,RECT *dims=NULL);
int Draw_Text(char*,int,int,COLORREF, LPDIRECTDRAWSURFACE7);
int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color);
  
//------ Windows Message Handler ------//
LRESULT CALLBACK 
WindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
		
	case WM_DESTROY:
		Game_Shutdown();
		PostQuitMessage(0);
		break;
		
	case WM_KEYDOWN: 
		switch (wParam) 
		{ 
		case VK_ESCAPE: // exit the program on escape
			DestroyWindow(hWnd);
			break;
		case VK_RIGHT: //move rect to the right
			x1 += 1;
			x2 += 1;
			break;
		case VK_LEFT: //move rect to the left
			x1 -= 1;
			x2 -= 1;
			break;
		case VK_UP: //move rect up
			y1 -= 1;
			y2 -= 1;
			break;
		case VK_DOWN: //move rect down
			y1 += 1;
			y2 += 1;
			break;
		case 'E': //increase height
			y1 -= 1;
			break;
		case 'D': //decrease height
			y2 -= 1;
			break;
		case 'S': //increase width
			x1 -= 1;
			break;
		case 'F': //decrease width
			x2 -= 1;
			break;
			// Process other non-character keystrokes. 
		default: 
			break; 
		}
		
		default:
			return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
	return 0L;
}
///////////////////////////////////////////////////////////////////////
//------ Application Loop ------//
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	MSG msg;                 // message from queue
	BOOL notDone=TRUE;       // flag for thread completion
	WNDCLASS                    wc;
	
	// Set up and register window class
	wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = (WNDPROC) WindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = sizeof(DWORD);
    wc.hInstance = hInstance;
    wc.hIcon = NULL;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = szClass;
	
    if (!RegisterClass(&wc)) 
	{
		ErrStr=Err_Reg_Class;
        return FALSE;
	}
	
    // Get dimensions of display
	int ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
    int ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
	
    // Create a window and display
    hWnd = CreateWindow(szClass,	//class
		szCaption,					//caption
		WS_VISIBLE|WS_POPUP,		//style 
		0,							//left
		0,							//top
		ScreenWidth,			   	//width
		ScreenHeight,				//height
		NULL,						//parent window
		NULL,						//menu 
		hInstance,					//instance
		NULL);						//parms
    
	if (!hWnd) 
	{
		ErrStr=Err_Create_Win;
        return FALSE;
	}
    
	ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
	
	//initialize the application, exit on failure
    if (!Init(hInstance, nCmdShow)) 
	{
		Game_Shutdown();
        return FALSE;
	}
	
	while (notDone) 
	{ 
		// is there a message to process? 
		if (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE)) 
		{ 
			// yes, is it a quit message? 
			if (msg.message==WM_QUIT) 
				notDone=FALSE; 
			
			// dispatch the message 
			TranslateMessage(&msg);
			DispatchMessage(&msg); 
		} 
		else 
		{
			//User does not want to quit so run game main
			Game_Main();
		}
	}
	//exit returning final message
    return (msg.wParam);
}
  
//------ Function to Initialize DirectDraw and the Application ------//
static BOOL Init(HINSTANCE hInstance, int nCmdShow)
{
    HRESULT ddrval;
	
    //Create the main DirectDraw object
    ddrval=DirectDrawCreateEx(NULL,(VOID **)&lpDD,IID_IDirectDraw7,NULL);
    
	if (ddrval != DD_OK) 
	{
		ErrStr=Err_DirectDrawCreate;
		return FALSE;
	}
	
    //Set our cooperative level
    ddrval=lpDD->SetCooperativeLevel(hWnd,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
    
	if (ddrval != DD_OK) 
	{
		ErrStr=Err_Coop;
		return FALSE;
	}
	
	//Set the display mode
	ddrval=lpDD->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,0,0);
	
	if (ddrval !=DD_OK)
	{
		ErrStr=Err_DispMode;
		return FALSE;
	}
	
    //Create the primary surface with 1 back buffer
	DDSURFACEDESC2 ddsd;
	ZeroMemory(&ddsd,sizeof(ddsd));
    ddsd.dwSize = sizeof( ddsd );
    ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
	 	                  DDSCAPS_FLIP | DDSCAPS_COMPLEX;
    ddsd.dwBackBufferCount = 1;
    ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );
	
	if (ddrval!=DD_OK) 
	{
		ErrStr=Err_CreateSurf;
		return FALSE;
	}
	
	//Fetch back buffer interface
	DDSCAPS2 ddscaps;
	ZeroMemory(&ddscaps,sizeof(ddscaps));
	ddscaps.dwCaps=DDSCAPS_BACKBUFFER;
	ddrval=lpDDSPrimary->GetAttachedSurface(&ddscaps,&lpDDSBack);
	
	if (ddrval!=DD_OK)
	{
		ErrStr=Err_GetBack;
		return FALSE;
	}
	
	//Clear out the back buffer
	DDraw_Fill_Surface(lpDDSBack, 0);
	
	bitmap_surface=LoadSurface(g_filename);
	if(!bitmap_surface) 
	{
		ErrStr=Err_LoadImage;
		return FALSE;
	}
	
	//return success to caller
	return TRUE;
}
  
///////////////////////////////////////////////////////////////////////
int Game_Main()
{
	//clip the sprite if necessary
	rct.left = x1;
	rct.top  = y1;
	rct.right =  x2;
	rct.bottom = y2;
	
	//test for clipping
	if(x1<0)
	{
		rct.left+=x1;
		x2-=x1;
		x1=0;
	}
	if(y1<0)
	{
		rct.top +=y1;
		y2-=y1;
		y1 =0;
	}
	if(x2>640)
	{
		rct.right += x2;
		x1-=1;
		x2=640;
	}
	if(y2>480)
	{
		rct.bottom += y2;
		y1-=1;
		y2=480;
	}
	
	//blt bitmap to back buffer
	lpDDSBack->BltFast(x1,y1,bitmap_surface,&rct,DDBLTFAST_WAIT);
	
	sprintf(buffer,"X1 = [%d]  Y1 = [%d]  X2 = [%d]  Y2 = [%d]  E,S,D,F"
		    " resize image, arrow keys move Rect ", x1, y1, x2, y2);
	Draw_Text(buffer,8,0,RGB(0,255,0),lpDDSBack);
	
	//flip the surfaces
	lpDDSPrimary->Flip(NULL, DDFLIP_WAIT);
	
	//Clear out the back buffer
	DDraw_Fill_Surface(lpDDSBack, 0);
	
	//return success
	return(1);
	
} //end Game_Main
///////////////////////////////////////////////////////////////////////
//Cleanup Function to Release Objects//////////////////////////////////
void Game_Shutdown()
{
	//release the surface
	SafeRelease(bitmap_surface);
	
	//release DirectDraw interfaces
	SafeRelease(lpDDSPrimary);
	SafeRelease(lpDD);
	
	//display error if one thrown
	if (ErrStr) 
	{
		MessageBox(NULL, ErrStr, szCaption, MB_OK);
		ErrStr=NULL;
	}
}
  
LPDIRECTDRAWSURFACE7 LoadSurface(LPCTSTR file_name,RECT *dims)
{
	HDC hdc;
	HBITMAP bit;
	LPDIRECTDRAWSURFACE7 surf;
	
	//load the interface bitmap
	bit=(HBITMAP) LoadImage(NULL,file_name,IMAGE_BITMAP,0,0,
								LR_DEFAULTSIZE|LR_LOADFROMFILE);
	if(!bit) 
		// failed to load, return failure to caller
		return NULL;
	
	//get bitmap dimensions
	BITMAP bitmap;
    GetObject( bit, sizeof(BITMAP), &bitmap );
	int surf_width=bitmap.bmWidth;
	int surf_height=bitmap.bmHeight;
	
	//create surface
	HRESULT ddrval;
	DDSURFACEDESC2 ddsd;
	ZeroMemory(&ddsd,sizeof(ddsd));
	ddsd.dwSize = sizeof(DDSURFACEDESC2);
	ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
	ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; 
	ddsd.dwWidth = surf_width;
	ddsd.dwHeight = surf_height; 
	
	//attempt to create surface
	ddrval=lpDD->CreateSurface(&ddsd,&surf,NULL);
	
	//created ok?
	if(ddrval!=DD_OK) 
	{
		//no, release the bitmap and return failure to caller
		DeleteObject(bit);
		return NULL;
	} 
	
	else 
	{
		//yes, get a DC for the surface
		surf->GetDC(&hdc);
		
		//generate a compatible DC
		HDC bit_dc=CreateCompatibleDC(hdc);
		
		//blit the interface to the surface
		SelectObject(bit_dc,bit);
		BitBlt(hdc,0,0,surf_width,surf_height,bit_dc,0,0,SRCCOPY);
		
		//release the DCs
		surf->ReleaseDC(hdc);
		DeleteDC(bit_dc);
		
		//save the dimensions if rectangle pointer provided
		if(dims)
		{
			dims->left=0;
			dims->top=0;
			dims->right=surf_width;
			dims->bottom=surf_height;
		}
	}
	
	//clear bitmap 
	DeleteObject(bit);
	
	//return pointer to caller
	return surf;
}
  
//------ Function to clear a surface ----------------------//
int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color)
{
	DDBLTFX ddbltfx; // this contains the DDBLTFX structure
	
	//clear out the structure and set the size field 
	DDRAW_INIT_STRUCT(ddbltfx);
	
	//set the dwfillcolor field to the desired color
	ddbltfx.dwFillColor = color; 
	
	//ready to blt to surface
	lpdds->Blt(NULL,       //ptr to dest rectangle
		NULL,              //ptr to source surface, NA            
		NULL,			   //ptr to source rectangle, NA
		DDBLT_COLORFILL | DDBLT_WAIT,   //fill and wait                   
		&ddbltfx);         //ptr to DDBLTFX structure
	
	//return success
	return(1);
} //end DDraw_Fill_Surface
/////////////////////////////////////////////////////////// 
  int Draw_Text(char*text,int x,int y,COLORREF color,LPDIRECTDRAWSURFACE7 lpdds)
{
	//this function draws the sent text on the sent surface 
	//using color index as the color in the palette
	
	HDC xdc; //the working dc
	
	//get the dc from surface
	if(FAILED(lpdds->GetDC(&xdc)))
		return(0);
	
	//set the colors for the text up
	SetTextColor(xdc,color);
	
	//set background mode to transparent so black isn't copied
	SetBkMode(xdc, TRANSPARENT);
	
	//draw the text a
	TextOut(xdc,x,y,text,strlen(text));
	
	//release the dc
	lpdds->ReleaseDC(xdc);
	
	//return success
	return(1);
} //end Draw_Text_GDI
///////////////////////////////////////////////////////////
  |