/*
 *  overlay.c
 *
 *  WGL/OpenGL program
 *
 *  Copyright (C) 1997 by Nate Robins (ndr@pobox.com)
 *
 *  This program is freely distributable without licensing fees and is
 *  provided without guarantee or warrantee expressed or implied. This
 *  program is not in the public domain.
 */


/* includes */
#include <windows.h>			/* must include this before GL/gl.h */
#include <GL/gl.h>			/* OpenGL header file */
#include <stdio.h>


/* pragmas */
#pragma warning(disable : 4244)		/* disable conversion warnings */


/* globals */
HDC   hDC;				/* device context */
HGLRC hRC;				/* opengl context */
HGLRC hOverlayRC;			/* opengl overlay context */


/* functions */

/* WindowProc()
 *  Minimum Window Procedure
 */
LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ 
    LONG        lRet = 1;
    PAINTSTRUCT ps;

    switch(uMsg) {
    case WM_CREATE:
        break; 

    case WM_DESTROY:
        break; 

    case WM_PAINT: 
        BeginPaint(hWnd, &ps); 
        EndPaint(hWnd, &ps); 
        break; 

    case WM_CHAR:
	if(wParam == 27)		/* ESC */
	    PostQuitMessage(0);
	break;

    case WM_SIZE:
	wglMakeCurrent(hDC, hRC);
	glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
	wglMakeCurrent(hDC, hOverlayRC);
	glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
	break;

    case WM_CLOSE:
	PostQuitMessage(0);
	break;

    default: 
        lRet = DefWindowProc(hWnd, uMsg, wParam, lParam); 
        break; 
    }

    return lRet; 
} 

/* oglCreateWindow
 *  Create a window suitable for OpenGL rendering
 */
HWND oglCreateWindow(char* title, int x, int y, int width, int height)
{
    WNDCLASS  wc;
    HWND      hWnd;
    HINSTANCE hInstance;

    /* get this modules instance */
    hInstance = GetModuleHandle(NULL);

    /* fill in the window class structure */
    wc.style         = 0;                           /* no special styles */
    wc.lpfnWndProc   = (WNDPROC)WindowProc;         /* event handler */
    wc.cbClsExtra    = 0;                           /* no extra class data */
    wc.cbWndExtra    = 0;                           /* no extra window data */
    wc.hInstance     = hInstance;                   /* instance */
    wc.hIcon         = LoadIcon(NULL, IDI_WINLOGO); /* load a default icon */
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW); /* load a default cursor */
    wc.hbrBackground = NULL;                        /* redraw our own bg */
    wc.lpszMenuName  = NULL;                        /* no menu */
    wc.lpszClassName = title;                       /* use a special class */

    /* register the window class */
    if (!RegisterClass(&wc)) {
      MessageBox(NULL, 
		   "RegisterClass() failed:  Cannot register window class,",
		   "Error", MB_OK);
	return NULL;
    }

    /* create a window */
    hWnd = CreateWindow(title,          /* class */
			title,          /* title (caption) */
			WS_OVERLAPPEDWINDOW | /* resize handles, etc */
			WS_CLIPSIBLINGS | WS_CLIPCHILDREN,  /* style */
			x, y, width, height, /* dimensions */
			NULL,		/* no parent */
			NULL,		/* no menu */
			hInstance,	/* instance */
			NULL);		/* don't pass anything to WM_CREATE */

    /* make sure we got a window */
    if (hWnd == NULL) {
	MessageBox(NULL,
		   "CreateWindow() failed:  Cannot create a window.",
		   "Error", MB_OK);
	return NULL;
    }

    /* show the window (map it) */
    ShowWindow(hWnd, SW_SHOW);

    /* send an initial WM_PAINT message (expose) */
    UpdateWindow(hWnd);

    return hWnd;
}

/* oglPixelFormat()
 *  Sets the pixel format for the context
 */
int oglSetPixelFormatOverlay(HDC hDC, BYTE type, DWORD flags)
{
    int pf, maxpf;
    PIXELFORMATDESCRIPTOR pfd;
    LAYERPLANEDESCRIPTOR  lpd;		/* layer plane descriptor */
    int   nEntries = 2;			/* number of entries in palette */
    COLORREF crEntries[2] = {		/* entries in custom palette */
      0x00000000,			/* black (ref #0 = transparent) */
      0x00ff0000,			/* blue */
    };

    /* get the maximum number of pixel formats */
    maxpf = DescribePixelFormat(hDC, 0, 0, NULL);
    
    /* find an overlay layer descriptor */
    for(pf = 0; pf < maxpf; pf++) {
        DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

	/* the bReserved field of the PIXELFORMATDESCRIPTOR contains the
	   number of overlay/underlay planes */
	if (pfd.bReserved > 0) {
	  /* aha! This format has overlays/underlays */
	  wglDescribeLayerPlane(hDC, pf, 1,
				sizeof(LAYERPLANEDESCRIPTOR), &lpd);
	  if (lpd.dwFlags & LPD_SUPPORT_OPENGL &&
	      lpd.dwFlags & flags)
	    {
	      goto found;
	    }
	}
    }
    /* couldn't find any overlay/underlay planes */
    MessageBox(NULL,
	       "Fatal Error:  Hardware does not support overlay planes.",
	       "Error", MB_OK);
    return 0;

found:
    /* now get the "normal" pixel format descriptor for the layer */
    DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

    /* set the pixel format */
    if(SetPixelFormat(hDC, pf, &pfd) == FALSE) {
	MessageBox(NULL,
		   "SetPixelFormat() failed:  Cannot set format specified.",
		   "Error", MB_OK);
        return 0;
    }
    
    /* set up the layer palette */
    wglSetLayerPaletteEntries(hDC, 1, 0, nEntries, crEntries);

    /* realize the palette */
    wglRealizeLayerPalette(hDC, 1, TRUE);

    /* announce what we've got */
    printf("Number of overlays = %d\n", pfd.bReserved);
    printf("Color bits in the overlay = %d\n", lpd.cColorBits);

    return pf;
}    

/* main()
 *  Entry point
 */
int main(int argc, char** argv)
{
    HWND      hWnd;			/* window */
    MSG       msg;			/* message */

    /* create a window */
    hWnd = oglCreateWindow("OpenGL", 0, 0, 200, 200);
    if (hWnd == NULL)
      exit(1);

    /* get the device context */
    hDC = GetDC(hWnd);

    /* set the pixel format */
    if (oglSetPixelFormatOverlay(hDC, PFD_TYPE_RGBA, LPD_DOUBLEBUFFER) == 0)
      exit(1);
      
    /* get the device context */
    hDC = GetDC(hWnd);

    /* create an OpenGL overlay context */
    hOverlayRC = wglCreateLayerContext(hDC, 1);

    /* create an OpenGL context */
    hRC = wglCreateContext(hDC);
    wglMakeCurrent(hDC, hRC);

    /* now we can start changing state & rendering */
    while(1) {
        /* first, check for (and process) messages in the queue */
	while(PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE)) {
	    if(GetMessage(&msg, hWnd, 0, 0)) {
		TranslateMessage(&msg); /* translate virtual-key messages */
		DispatchMessage(&msg);	/* call the window proc */
	    } else {
		goto quit;
	    }
	}

	/* make current and draw a triangle */
	wglMakeCurrent(hDC, hRC);
	glClear(GL_COLOR_BUFFER_BIT);
	glRotatef(1.0, 0.0, 0.0, 1.0);
	glBegin(GL_TRIANGLES);
	glColor3f(1.0, 0.0, 0.0);
	glVertex2i( 0,  1);
	glColor3f(0.0, 1.0, 0.0);
	glVertex2i(-1, -1);
	glColor3f(0.0, 0.0, 1.0);
	glVertex2i( 1, -1);
	glEnd();
	glFlush();
	wglSwapLayerBuffers(hDC, WGL_SWAP_MAIN_PLANE);

	/* make current and draw a triangle */
	wglMakeCurrent(hDC, hOverlayRC);
	glClear(GL_COLOR_BUFFER_BIT);
	glRotatef(-1.0, 0.0, 0.0, 1.0);
	glBegin(GL_TRIANGLES);
	glIndexi(1);
	glVertex2i( 0,  1);
	glVertex2i(-1, -1);
	glVertex2i( 1, -1);
	glEnd();
	glFlush();
	wglSwapLayerBuffers(hDC, WGL_SWAP_OVERLAY1);
    }

quit:

    /* clean up */
    wglMakeCurrent(NULL, NULL);		/* make our context 'un-'current */
    ReleaseDC(hDC, hWnd);		/* release handle to DC */
    wglDeleteContext(hRC);		/* delete the rendering context */
    wglDeleteContext(hOverlayRC);	/* delete the overlay context */
    DestroyWindow(hWnd);		/* destroy the window */

    return TRUE;
}
