home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OpenGL Superbible
/
OpenGL_Superbible_Waite_Group_Press_1996.iso
/
book
/
chapt8
/
dither
/
dither.c
next >
Wrap
C/C++ Source or Header
|
1996-07-06
|
15KB
|
578 lines
// Dither.c
// Demonstrates dithering by drawing a rotatable cube that has colors
// not easily represented purely by a 332 palette or in 16 color mode.
// Dithering can be turned on and off by a menu selection.
#include <windows.h> // Window defines
#include <gl\gl.h> // OpenGL
#include <gl\glu.h> // GLU library
#include "resource.h" // About box resource identifiers.
// Application name and instance storeage
static LPCTSTR lpszAppName = "Dithered Cube";
static HINSTANCE hInstance;
static bDither = FALSE;
// Rotation amounts
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
static GLsizei lastHeight;
static GLsizei lastWidth;
// Normalize, keep the angles within 0 to 360 degrees
GLfloat Normal360(GLfloat dSource)
{
if(dSource < 0.0)
dSource = 360.0f + dSource;
if(dSource > 360.0f)
dSource = 360.0f - dSource;
return dSource;
}
// Declaration for Window procedure
LRESULT CALLBACK WndProc( HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// Dialog procedure for about box
BOOL APIENTRY AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam);
// Set Pixel Format function - forward declaration
void SetDCPixelFormat(HDC hDC);
// Change viewing volume and viewport. Called when window is resized
void ChangeSize(GLsizei w, GLsizei h)
{
// Prevent a divide by zero
if(h == 0)
h = 1;
lastWidth = w;
lastHeight = h;
// Set Viewport to window dimensions
glViewport(0, 0, w, h);
// Reset coordinate system
glLoadIdentity();
// Establish clipping volume (left, right, bottom, top, near, far)
if (w <= h)
glOrtho (-100.0f, 100.0f, 100.0f*h/w, -100.0f*h/w, 100.0, -100.0);
else
glOrtho (-100.0f*w/h, 100.0f*w/h, 100.0f, -100.0f, 100.0, -100.0);
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
}
// Called to draw scene
void RenderScene(void)
{
glEnable(GL_DEPTH_TEST);
if(bDither)
glEnable(GL_DITHER);
else
glDisable(GL_DITHER);
glShadeModel(GL_SMOOTH);
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ChangeSize(lastWidth,lastHeight);
// Front face
// Gray
glColor3f(0.75f, 0.75f, 0.75f);
glBegin(GL_POLYGON);
glVertex3f(50.0f,50.0f,50.0f);
glVertex3f(50.0f,-50.0f,50.0f);
glVertex3f(-50.0f,-50.0f,50.0f);
glVertex3f(-50.0f,50.0f,50.0f);
glEnd();
// Back Face
// Pink
glColor3f(0.98f, 0.04f, 0.7f);
glBegin(GL_POLYGON);
glVertex3f(50.0f,50.0f,-50.0f);
glVertex3f(50.0f,-50.0f,-50.0f);
glVertex3f(-50.0f,-50.0f,-50.0f);
glVertex3f(-50.0f,50.0f,-50.0f);
glEnd();
// Top Face
// Barney Purple
glColor3f(.60f, 0.40f, 0.7f);
glBegin(GL_POLYGON);
glVertex3f(50.0f,50.0f,-50.0f);
glVertex3f(50.0f,50.0f,50.0f);
glVertex3f(-50.0f,50.0f,50.0f);
glVertex3f(-50.0f,50.0f,-50.0f);
glEnd();
// Bottom Face
glColor3f(0.976f, 0.55f, 0.18f);
glBegin(GL_POLYGON);
glVertex3f(50.0f,-50.0f,-50.0f);
glVertex3f(50.0f,-50.0f,50.0f);
glVertex3f(-50.0f,-50.0f,50.0f);
glVertex3f(-50.0f,-50.0f,-50.0f);
glEnd();
// Left face
glColor3f(0.49f, 0.84f, 0.30f);
glBegin(GL_POLYGON);
glVertex3f(50.0f,50.0f,50.0f);
glVertex3f(50.0f,50.0f,-50.0f);
glVertex3f(50.0f,-50.0f,-50.0f);
glVertex3f(50.0f,-50.0f,50.0f);
glEnd();
// Right face
// Pumpkin Orange
glColor3f(0.98f, 0.625f, 0.12f);
glBegin(GL_POLYGON);
glVertex3f(-50.0f,50.0f,50.0f);
glVertex3f(-50.0f,50.0f,-50.0f);
glVertex3f(-50.0f,-50.0f,-50.0f);
glVertex3f(-50.0f,-50.0f,50.0f);
glEnd();
// Flush drawing commands
glFlush();
}
// Select the pixel format for a given device context
void SetDCPixelFormat(HDC hDC)
{
int nPixelFormat;
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure
1, // Version of this structure
PFD_DRAW_TO_WINDOW | // Draw to Window (not to bitmap)
PFD_SUPPORT_OPENGL | // Support OpenGL calls in window
PFD_DOUBLEBUFFER, // Double buffered
PFD_TYPE_RGBA, // RGBA Color mode
24, // Want 24bit color
0,0,0,0,0,0, // Not used to select mode
0,0, // Not used to select mode
0,0,0,0,0, // Not used to select mode
32, // Size of depth buffer
0, // Not used to select mode
0, // Not used to select mode
PFD_MAIN_PLANE, // Draw in main plane
0, // Not used to select mode
0,0,0 }; // Not used to select mode
// Choose a pixel format that best matches that described in pfd
nPixelFormat = ChoosePixelFormat(hDC, &pfd);
// Set the pixel format for the device context
SetPixelFormat(hDC, nPixelFormat, &pfd);
}
// If necessary, creates a 3-3-2 palette for the device context listed.
HPALETTE GetOpenGLPalette(HDC hDC)
{
HPALETTE hRetPal = NULL; // Handle to palette to be created
PIXELFORMATDESCRIPTOR pfd; // Pixel Format Descriptor
LOGPALETTE *pPal; // Pointer to memory for logical palette
int nPixelFormat; // Pixel format index
int nColors; // Number of entries in palette
int i; // Counting variable
BYTE RedRange,GreenRange,BlueRange;
// Range for each color entry (7,7,and 3)
// Get the pixel format index and retrieve the pixel format description
nPixelFormat = GetPixelFormat(hDC);
DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
// Does this pixel format require a palette? If not, do not create a
// palette and just return NULL
if(!(pfd.dwFlags & PFD_NEED_PALETTE))
return NULL;
// Number of entries in palette. 8 bits yeilds 256 entries
nColors = 1 << pfd.cColorBits;
// Allocate space for a logical palette structure plus all the palette entries
pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +nColors*sizeof(PALETTEENTRY));
// Fill in palette header
pPal->palVersion = 0x300; // Windows 3.0
pPal->palNumEntries = nColors; // table size
// Build mask of all 1's. This creates a number represented by having
// the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
// pfd.cBlueBits.
RedRange = (1 << pfd.cRedBits) -1;
GreenRange = (1 << pfd.cGreenBits) - 1;
BlueRange = (1 << pfd.cBlueBits) -1;
// Loop through all the palette entries
for(i = 0; i < nColors; i++)
{
// Fill in the 8-bit equivalents for each component
pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
pPal->palPalEntry[i].peRed = (unsigned char)(
(double) pPal->palPalEntry[i].peRed * 255.0 / RedRange);
pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
pPal->palPalEntry[i].peGreen = (unsigned char)(
(double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange);
pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
pPal->palPalEntry[i].peBlue = (unsigned char)(
(double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);
pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
}
// Create the palette
hRetPal = CreatePalette(pPal);
// Go ahead and select and realize the palette for this device context
SelectPalette(hDC,hRetPal,FALSE);
RealizePalette(hDC);
// Free the memory used for the logical palette structure
free(pPal);
// Return the handle to the new palette
return hRetPal;
}
// Entry point of all Windows programs
int APIENTRY WinMain( HINSTANCE hInst,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg; // Windows message structure
WNDCLASS wc; // Windows class structure
HWND hWnd; // Storeage for window handle
hInstance = hInst;
// Register Window style
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// No need for background brush for OpenGL window
wc.hbrBackground = NULL;
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
wc.lpszClassName = lpszAppName;
// Register the window class
if(RegisterClass(&wc) == 0)
return FALSE;
// Create the main application window
hWnd = CreateWindow(
lpszAppName,
lpszAppName,
// OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
// Window position and size
50, 50,
400, 400,
NULL,
NULL,
hInstance,
NULL);
// If window was not created, quit
if(hWnd == NULL)
return FALSE;
// Display the window
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
// Process application messages until the application closes
while( GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// Window procedure, handles all messages for this program
LRESULT CALLBACK WndProc( HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
static HGLRC hRC; // Permenant Rendering context
static HDC hDC; // Private GDI Device context
static HMENU hMenu; // Handle to the menu
static HPALETTE hPalette = NULL;// Handle to the palette
switch (message)
{
// Window creation, setup for OpenGL
case WM_CREATE:
// Store the device context
hDC = GetDC(hWnd);
// Select the pixel format
SetDCPixelFormat(hDC);
hPalette = GetOpenGLPalette(hDC);
// Create the rendering context and make it current
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
break;
// Window is being destroyed, cleanup
case WM_DESTROY:
// Deselect the current rendering context and delete it
wglMakeCurrent(hDC,NULL);
wglDeleteContext(hRC);
if(hPalette != NULL)
DeleteObject(hPalette);
// Tell the application to terminate after the window
// is gone.
PostQuitMessage(0);
break;
// Window is resized.
case WM_SIZE:
// Call our function which modifies the clipping
// volume and viewport
ChangeSize(LOWORD(lParam), HIWORD(lParam));
break;
// The painting function. This message sent by Windows
// whenever the screen needs updating.
case WM_PAINT:
{
// Call OpenGL drawing code
RenderScene();
SwapBuffers(hDC);
// Validate the newly painted client area
ValidateRect(hWnd,NULL);
}
break;
// Windows is telling the application that it may modify
// the system palette. This message in essance asks the
// application for a new palette.
case WM_QUERYNEWPALETTE:
// If the palette was created.
if(hPalette)
{
int nRet;
// Selects the palette into the current device context
SelectPalette(hDC, hPalette, FALSE);
// Map entries from the currently selected palette to
// the system palette. The return value is the number
// of palette entries modified.
nRet = RealizePalette(hDC);
// Repaint, forces remap of palette in current window
InvalidateRect(hWnd,NULL,FALSE);
return nRet;
}
break;
// This window may set the palette, even though it is not the
// currently active window.
case WM_PALETTECHANGED:
// Don't do anything if the palette does not exist, or if
// this is the window that changed the palette.
if((hPalette != NULL) && ((HWND)wParam != hWnd))
{
// Select the palette into the device context
SelectPalette(hDC,hPalette,FALSE);
// Map entries to system palette
RealizePalette(hDC);
// Remap the current colors to the newly realized palette
UpdateColors(hDC);
return 0;
}
break;
case WM_KEYDOWN:
{
if(wParam == VK_UP)
xRot-= 5.0f;
if(wParam == VK_DOWN)
xRot += 5.0f;
if(wParam == VK_LEFT)
yRot += 5.0f;
if(wParam == VK_RIGHT)
yRot -= 5.0f;
xRot = Normal360(xRot);
yRot = Normal360(yRot);
InvalidateRect(hWnd,NULL,FALSE);
}
break;
// A menu command
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
// Exit the program
case ID_FILE_EXIT:
DestroyWindow(hWnd);
break;
// Display the about box
case ID_HELP_ABOUT:
DialogBox (hInstance,
MAKEINTRESOURCE(IDD_DIALOG_ABOUT),
hWnd,
AboutDlgProc);
break;
// Toggle dithering
case ID_EFFECTS_DITHER:
// Toggle dither flag
bDither = !bDither;
// Check or uncheck menu item
hMenu = GetMenu(hWnd);
hMenu = GetSubMenu(hMenu,1);
if(bDither)
CheckMenuItem(hMenu,0,MF_BYPOSITION | MF_CHECKED);
else
CheckMenuItem(hMenu,0,MF_BYPOSITION | MF_UNCHECKED);
InvalidateRect(hWnd,NULL,FALSE);
break;
}
}
break;
default: // Passes it on if unproccessed
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (0L);
}
// Dialog procedure.
BOOL APIENTRY AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam)
{
switch (message)
{
// Initialize the dialog box
case WM_INITDIALOG:
{
int i;
GLenum glError;
// glGetString demo
SetDlgItemText(hDlg,IDC_OPENGL_VENDOR,glGetString(GL_VENDOR));
SetDlgItemText(hDlg,IDC_OPENGL_RENDERER,glGetString(GL_RENDERER));
SetDlgItemText(hDlg,IDC_OPENGL_VERSION,glGetString(GL_VERSION));
SetDlgItemText(hDlg,IDC_OPENGL_EXTENSIONS,glGetString(GL_EXTENSIONS));
// gluGetString demo
SetDlgItemText(hDlg,IDC_GLU_VERSION,gluGetString(GLU_VERSION));
SetDlgItemText(hDlg,IDC_GLU_EXTENSIONS,gluGetString(GLU_EXTENSIONS));
// Display any recent error messages
i = 0;
do {
glError = glGetError();
SetDlgItemText(hDlg,IDC_ERROR1+i,gluErrorString(glError));
i++;
}
while(i < 6 && glError != GL_NO_ERROR);
return (TRUE);
}
break;
// Process command messages
case WM_COMMAND:
{
// Validate and Make the changes
if(LOWORD(wParam) == IDOK)
EndDialog(hDlg,TRUE);
}
break;
// Closed from sysbox
case WM_CLOSE:
EndDialog(hDlg,TRUE);
break;
}
return FALSE;
}