Skip to main content
GameDev.net gamedev.net
🔒 Locked

DirectDraw: 16-bit RGB problem

Started by nullsmind Apr 25, 2006 at 8:23 PM 4 replies 2.5k views
Original Post
nullsmind
nullsmind
The goal of this application is to draw a background rect with a cornflowerblue color. This should be a light blue-gray color with RGB values of 100, 149, 237. On execution, the color looks like a dim blue-gray color. I don't see why this is. Any help would be great.

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <windowsx.h>
#include "winmain.h"
#include <ddraw.h>

#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
#define MsgErr(errMsg)   { MessageBox(NULL, errMsg, "Error", MB_OK | MB_ICONERROR); }
#define SAFE_RELEASE(ob) { if (ob) { ob->Release(); ob = NULL; } }
#define ALIGN32		 __declspec(align(32))
#define INIT_STRUCT(ddstruct) { memset(&ddstruct, 0, sizeof(ddstruct)); 	ddstruct.dwSize = sizeof(ddstruct); }
#define _RGB16BIT555(r,g,b) ((b & 31) + ((g & 31) << 5) + ((r & 31) << 10))
#define _RGB16BIT565(r,g,b) ((b & 31) + ((g & 63) << 5) + ((r & 31) << 11))

#define SCREEN_WIDTH  800
#define SCREEN_HEIGHT 600
#define SCREEN_BPP    16
#define FULLSCREEN    1

namespace {
	const char *g_szClassName = "WndClass1";
	const char *g_szWinTitle  = "DirectX Application";
	bool exiting = false;
	HWND  g_hWnd = NULL;
	HINSTANCE g_hInstance; 
	HRESULT hr;
	PALETTEENTRY palette[256];
	LPDIRECTDRAW7 lpdd = NULL;
	LPDIRECTDRAWPALETTE lpddpal = NULL;
	LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;
	DDSURFACEDESC2 ddsd;
	DDPIXELFORMAT ddpf;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{
	WNDCLASSEX wc;
	HWND hWnd;
	MSG msg; 

	// Create the parent window class
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	wc.hInstance = hInstance;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = g_szClassName;
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;

	if (!RegisterClassEx(&wc)) {
		MsgErr("Registering the parent window class failed.");
		return 0;
	}

	// Determine Full Screen
	int xPos = 0, yPos = 0;
	DWORD flags;
	if (FULLSCREEN)  
		flags = WS_POPUP | WS_EX_TOPMOST; 
	else {
		// Center a normal overlapped window
		flags = WS_OVERLAPPEDWINDOW;
		xPos = (GetSystemMetrics(SM_CXSCREEN) - SCREEN_WIDTH) / 2;
		yPos = (GetSystemMetrics(SM_CYSCREEN) - SCREEN_HEIGHT) / 2;
	}

	// Create the parent window handle
	hWnd = CreateWindowEx(NULL, g_szClassName, g_szWinTitle, flags, xPos, yPos, 
		SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL);

	if (hWnd == NULL) {
		MsgErr("Creating the parent window failed.");
		return 0;
	}

	// Create global handles
	g_hWnd = hWnd;
	g_hInstance = hInstance; 

	// Show & Update Window
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	srand(GetTickCount());

	if (!Game_Init()) {
		MsgErr("Initializing the game failed.");
		return 0;
	}

	// Message Loop
	while (TRUE) 
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
				break;

			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
 
		Game_Main();
	}

	Game_Destroy();

	return (int) msg.lParam; 
}

bool Game_Init(void)
{  
	// Create a DirectDraw 7.0 Object Interface
	hr = DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL);
	if (FAILED(hr))
		return false;

	// Set the cooperative level
	hr = lpdd->SetCooperativeLevel(g_hWnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | 
		DDSCL_ALLOWMODEX | DDSCL_ALLOWREBOOT);
	if (FAILED(hr))
		return false;

	// Set the video mode
	hr = lpdd->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, 0, 0);
	if (FAILED(hr))
		return false;

	// Create the primary surface
	INIT_STRUCT(ddsd);
	ddsd.dwFlags = DDSD_CAPS;
	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	hr = lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL);
	if (FAILED(hr))
		return false;  
	
	return true;
}

void Game_Main(void)
{
	GetInput();
	Render();
}

void Game_Destroy(void)
{
	SAFE_RELEASE(lpddpal);
	SAFE_RELEASE(lpddsprimary); 
	SAFE_RELEASE(lpdd);
}

void GetInput(void)
{
	if (KEYDOWN(VK_ESCAPE)) {
		exiting = true;
		SendMessage(g_hWnd, WM_CLOSE, 0, 0);
	}
}

void Render(void)
{ 
	if (exiting == true)
		return;

	INIT_STRUCT(ddsd);

	hr = lpddsprimary->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
	if (FAILED(hr))
		return;

	int mempitch = (int) (ddsd.lPitch >> 1);
	USHORT *videoBuffer = (USHORT *) ddsd.lpSurface; 

	DrawRect16(0, 0, 800, 600, 100, 149, 237, videoBuffer, mempitch);

	hr = lpddsprimary->Unlock(NULL);
	if (FAILED(hr))
		return;

	Sleep(30);
}  

inline void DrawPixel16(int x, int y, int r, int g, int b, 
						USHORT *videoBuffer, int mempitch)
{
	USHORT pixel = _RGB16BIT565(r, g, b);
	videoBuffer[x + y * mempitch] = pixel;
}

inline void DrawRect16(int x1, int y1, int x2, int y2, int r, int g, int b, 
					   USHORT *videoBuffer, int mempitch) 
{
	for (int y = y1; y < y2; y++) 
		for (int x = x1; x < x2; x++) 
			DrawPixel16(x, y, r, g, b, videoBuffer, mempitch);  
}




Mastaba
Mastaba
Your macro for creating the RGB value is incorrect. You are using the least significant bits of each channel rather than the most significant bits.
nullsmind
nullsmind
So it should be this?

#define _RGB16BIT565(r,g,b) ((r & 31) + ((g & 63) << 5) + ((b & 31) << 11))

My concerns:
1) The result makes a dark-yellow color which is not the desired result.
2) The book suggests the RGB order from MSB to LSB w/ the macro origionally in my code. The explanation...
"This may seem backwards because PCs are little-endian and place data in low-to-high order, but in this case the bits are big-endian format, which is much better because they follow RGB order from MSB to LSB." - Tricks edition 2

d15 - red (high bit)
d7 - green
d0 - blue (low bit)
Mastaba
Mastaba
No, something more like this: ((b & 0xF8) >> 3 + ((g & 0xFC) << 3) + ((r & 0xF8) << 8))
nullsmind
nullsmind
Edit: I had to fix the operator precedence with your macro, but it gave the desired color result this time.

#define _RGB16BIT565(r,g,b) (((b & 0xF8) >> 3) + ((g & 0xFC) << 3) + ((r & 0xF8) << 8))

I'd like to know how this macro differs from the origional. What is it doing overall? Thanks.
Mastaba
Mastaba
Here is a hint, write down the r, g, & b values in binary and do the operations. [grin]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.