/*
 *  wglinfo.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 */


/* 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; 

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

    return lRet; 
} 

/* VisualInfo() 
 *  Shows a graph of all the visuals that support OpenGL and their
 *  capabilities.  Just like (well, almost) glxinfo on SGI's.  
 */
void VisualInfo(HDC hDC)
{
    int i, maxpf;
    PIXELFORMATDESCRIPTOR pfd;

    /* calling DescribePixelFormat() with NULL args return maximum
       number of pixel formats */
    maxpf = DescribePixelFormat(hDC, 0, 0, NULL);

    /* print the table header */
 printf("   visual  x  bf lv rg d st  r  g  b a  ax dp st accum buffs  ms \n");
 printf(" id dep cl sp sz l  ci b ro sz sz sz sz bf th cl  r  g  b  a ns b\n");
 printf("-----------------------------------------------------------------\n");

    /* loop through all the pixel formats */
    for(i = 1; i <= maxpf; i++) {

	DescribePixelFormat(hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

	/* only describe this format if it supports OpenGL */
	if(!(pfd.dwFlags & PFD_SUPPORT_OPENGL))
	    continue;

	/* other criteria could be tested here for actual pixel format
           choosing in an application:
	   
	   for (...each pixel format...) {

	     if (pfd.dwFlags & PFD_SUPPORT_OPENGL &&
	         pfd.dwFlags & PFD_DOUBLEBUFFER &&
	         pfd.cDepthBits >= 24 &&
	         pfd.cColorBits >= 24)
	         {
	            goto found;
                 }
           }
	   ... not found so exit ...
	    
           found:
	   ... found so use it ...
	*/

	/* print out the information for this pixel format */
	printf("0x%02x ", i);

	printf("%2d ", pfd.cColorBits);
	if(pfd.dwFlags & PFD_DRAW_TO_WINDOW)      printf("wn ");
	else if(pfd.dwFlags & PFD_DRAW_TO_BITMAP) printf("bm ");
	else printf(".  ");

	/* should find transparent pixel from LAYERPLANEDESCRIPTOR */
	printf(" . "); 

	printf("%2d ", pfd.cColorBits);

	/* bReserved field indicates number of over/underlays */
	if(pfd.bReserved) printf(" %d ", pfd.bReserved);
	else printf(" . "); 

	printf(" %c ", pfd.iPixelType == PFD_TYPE_RGBA ? 'r' : 'c');

	printf("%c ", pfd.dwFlags & PFD_DOUBLEBUFFER ? 'y' : '.');

	printf(" %c ", pfd.dwFlags & PFD_STEREO ? 'y' : '.');

	if(pfd.cRedBits)        printf("%2d ", pfd.cRedBits);
	else printf(" . ");

	if(pfd.cGreenBits)      printf("%2d ", pfd.cGreenBits);
	else printf(" . ");

	if(pfd.cBlueBits)       printf("%2d ", pfd.cBlueBits);
	else printf(" . ");

	if(pfd.cAlphaBits)      printf("%2d ", pfd.cAlphaBits);
	else printf(" . ");

	if(pfd.cAuxBuffers)     printf("%2d ", pfd.cAuxBuffers);
	else printf(" . ");

	if(pfd.cDepthBits)      printf("%2d ", pfd.cDepthBits);
	else printf(" . ");

	if(pfd.cStencilBits)    printf("%2d ", pfd.cStencilBits);
	else printf(" . ");

	if(pfd.cAccumRedBits)   printf("%2d ", pfd.cAccumRedBits);
	else printf(" . ");

	if(pfd.cAccumGreenBits) printf("%2d ", pfd.cAccumGreenBits);
	else printf(" . ");

	if(pfd.cAccumBlueBits)  printf("%2d ", pfd.cAccumBlueBits);
	else printf(" . ");

	if(pfd.cAccumAlphaBits) printf("%2d ", pfd.cAccumAlphaBits);
	else printf(" . ");

	/* no multisample in Win32 */
	printf(" . .\n");
    }

    /* print table footer */
 printf("-----------------------------------------------------------------\n");
 printf("   visual  x  bf lv rg d st  r  g  b a  ax dp st accum buffs  ms \n");
 printf(" id dep cl sp sz l  ci b ro sz sz sz sz bf th cl  r  g  b  a ns b\n");
 printf("-----------------------------------------------------------------\n");

}

/* 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_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;
    }

    return hWnd;
}


/* oglPixelFormat()
 *  Sets the pixel format for the context
 */
int oglSetPixelFormat(HDC hDC, BYTE type, DWORD flags)
{
    int pf;
    PIXELFORMATDESCRIPTOR pfd;

    /* fill in the pixel format descriptor */
    pfd.nSize        = sizeof(PIXELFORMATDESCRIPTOR);
    pfd.nVersion     = 1;		    /* version (should be 1) */
    pfd.dwFlags      = PFD_DRAW_TO_WINDOW | /* draw to window (not bitmap) */
                       PFD_SUPPORT_OPENGL | /* draw using opengl */
                       flags;               /* user supplied flags */
    pfd.iPixelType   = type;                /* PFD_TYPE_RGBA or COLORINDEX */
    pfd.cColorBits   = 24;
    /* other criteria here */
    
    /* get the appropriate pixel format */
    pf = ChoosePixelFormat(hDC, &pfd);
    if (pf == 0) {
       MessageBox(NULL,
		  "ChoosePixelFormat() failed:  Cannot find format specified.",
		  "Error", MB_OK); 
       return 0;
    } 
 
    /* set the pixel format */
    if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
	MessageBox(NULL,
		   "SetPixelFormat() failed:  Cannot set format specified.",
		   "Error", MB_OK);
        return 0;
    } 

    return pf;
}    

/* main()
 *  Entry point
 */
int main(int argc, char** argv)
{
    HDC       hDC;			/* device context */
    HGLRC     hRC;			/* OpenGL context */
    HWND      hWnd;			/* window */
    int   i;
    char* s;
    char  t[80];
    char* p;

    /* 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 (oglSetPixelFormat(hDC, PFD_TYPE_RGBA, 0) == 0)
      exit(1);
      
    /* create an OpenGL context */
    hRC = wglCreateContext(hDC);
    wglMakeCurrent(hDC, hRC);

    /* output header information */
    printf("hDC: 0x%x\n", hDC);
    printf("server wgl vendor string: N/A\n");
    printf("server wgl version string: N/A\n");
    printf("server wgl extensions (WGL_): N/A\n");
    printf("client wgl version: N/A\n");
    printf("client wgl extensions (WGL_): none\n");
    printf("OpenGL vendor string: %s\n", glGetString(GL_VENDOR));
    printf("OpenGL renderer string: %s\n", glGetString(GL_RENDERER));
    printf("OpenGL version string: %s\n", glGetString(GL_VERSION));
    printf("OpenGL extensions (GL_): \n");

    /* do the magic to separate all extensions with comma's */
    i = 0;
    s = (char*)glGetString(GL_EXTENSIONS);
    t[79] = '\0';
    while(*s) {
	t[i++] = *s;
	if(*s == ' ') {
	    t[i-1] = ',';
	    t[i] = ' ';
	    p = &t[i++];
	}
	if(i > 80 - 5) {
	    *p = t[i] = '\0';
	    printf("    %s\n", t);
	    p++;
	    i = strlen(p);
	    strcpy(t, p);
	}
	s++;
    }
    t[i] = '\0';
    printf("    %s.\n\n", t);

    /* enumerate all the formats */
    VisualInfo(hDC);

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

    return 0;
}
