/* fullscreen.c Nate Robins, 1997. An example of rendering OpenGL fullscreen using Win32. Use the mouse to select a mode. Modes that are highlighted in green are modes that can be changed to dynamically. Those in red can't be changed to dynamically (they require a reboot). If you change to a mode that has the wrong refresh rate, you can press the right mouse button which will take you to the default display mode. The mode that is highlighted in yellow is the current display mode. Press 'Esc' to quit. The program returns to the defalt display mode on exit. */#include <windows.h>#include <GL/glut.h>#include <stdio.h>HDC hDC;int win_width, win_height;int row = 0, col = 0;int num_modes = 0;int row_size = 10, col_size = 0;int num_cols = 3, num_rows = 0;int current = -1;int cant = 0;DEVMODE devmode;DEVMODE *devmodes;/* general purpose text routine. draws a string according to the format in a stroke font at x, y after scaling it by the scale specified. x, y and scale are all in window-space [i.e., pixels] with origin at the lower-left. */void text(GLuint x, GLuint y, GLuint scale, char* format, ...){ va_list args; char buffer[255], *p; GLfloat font_scale = 119.05F + 33.33F; va_start(args, format); vsprintf(buffer, format, args); va_end(args); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, win_width, 0, win_height); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); glTranslatef((GLfloat) x, (GLfloat) y, 0.0F); glScalef(scale/font_scale, scale/font_scale, scale/font_scale); for(p = buffer; *p; p++)glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, *p); glPopAttrib(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW);}voiddisplay(){ int i, x, y; glViewport(0, 0, win_width, win_height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, win_width, 0, win_height); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPolygonMode(GL_FRONT, GL_LINE); glClear(GL_COLOR_BUFFER_BIT); for (i = 0; i < num_modes; i++) {x = i / num_rows * col_size;y = i % num_rows * row_size;glColor3f(1.0F, 1.0F, 1.0F);if (current == i) glColor3f(1.0F, 1.0F, 0.0F);if (row*row_size == y && col*col_size == x) { /* test to see if the mode that the mouse pointer is above is dynamic. */ if (ChangeDisplaySettings(&devmodes[i], CDS_TEST) ==DISP_CHANGE_SUCCESSFUL) {glColor3f(0.0F, 1.0F, 0.0F); } else {glColor3f(1.0F, 0.0F, 0.0F); } /* draw a box around the current choice. */ glRecti(x, y-2, x+col_size, y+row_size-1);}text(x, y, row_size, "%3d: %4dx%4d %2d bps %3dhz\n", i, devmodes[i].dmPelsWidth, devmodes[i].dmPelsHeight, devmodes[i].dmBitsPerPel, devmodes[i].dmDisplayFrequency); } /* let the user know that they can't choose that one. "cant" decrements so that a few frames of the message are seen (otherwise it blinks off too quickly to read). */ if (cant) {glColor3f(1.0F, 0.0F, 0.0F);text(0, win_height-20, 20, "Can't dynamically resize to that format.");cant--; } glFlush(); SwapBuffers(hDC);}LONG WINAPIWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ int i; static PAINTSTRUCT ps; switch(uMsg) { case WM_PAINT:display();BeginPaint(hWnd, &ps);EndPaint(hWnd, &ps);return 0; case WM_SIZE: win_width = LOWORD(lParam);win_height = HIWORD(lParam);num_rows = win_height / row_size;col_size = win_width / num_cols;PostMessage(hWnd, WM_PAINT, 0, 0);return 0; case WM_CHAR:switch (wParam) {case 27:/* ESC key */ PostQuitMessage(0); break;}return 0; case WM_LBUTTONDOWN:i = col * num_rows + row;if (i < num_modes) { /* test first, then change, just in case. */ if (ChangeDisplaySettings(&devmodes[i], CDS_TEST) == DISP_CHANGE_SUCCESSFUL) {ChangeDisplaySettings(&devmodes[i], 0);current = i; } else {cant = 5;PostMessage(hWnd, WM_PAINT, 0, 0); }}return 0; case WM_RBUTTONDOWN:/* click your heels three times...hang on toto. */ChangeDisplaySettings(NULL, 0);return 0; case WM_MOUSEMOVE:col = LOWORD(lParam) / col_size;row = (win_height - HIWORD(lParam)) / row_size;PostMessage(hWnd, WM_PAINT, 0, 0);return 0; case WM_CLOSE:PostQuitMessage(0);return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } HWNDCreateOpenGLWindow(char* title, int x, int y, int width, int height, BYTE type, DWORD flags){ int pf; HDC hDC; HWND hWnd; WNDCLASS wc; PIXELFORMATDESCRIPTOR pfd; static HINSTANCE hInstance = 0; /* only register the window class once - use hInstance as a flag. */ if (!hInstance) {hInstance = GetModuleHandle(NULL);wc.style = CS_OWNDC;wc.lpfnWndProc = (WNDPROC)WindowProc;wc.cbClsExtra = 0;wc.cbWndExtra = 0;wc.hInstance = hInstance;wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);wc.hCursor = LoadCursor(NULL, IDC_ARROW);wc.hbrBackground = NULL;wc.lpszMenuName = NULL;wc.lpszClassName = "OpenGL";if (!RegisterClass(&wc)) { MessageBox(NULL, "RegisterClass() failed: " "Cannot register window class.", "Error", MB_OK); return NULL;} } hWnd = CreateWindow("OpenGL", title, WS_POPUP | WS_MAXIMIZE |WS_CLIPSIBLINGS | WS_CLIPCHILDREN,x, y, width, height, NULL, NULL, hInstance, NULL); if (hWnd == NULL) {MessageBox(NULL, "CreateWindow() failed: Cannot create a window.", "Error", MB_OK);return NULL; } hDC = GetDC(hWnd); /* there is no guarantee that the contents of the stack that become the pfd are zeroed, therefore _make sure_ to clear these bits. */ memset(&pfd, 0, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | flags; pfd.iPixelType = type; pfd.cColorBits = 32; pf = ChoosePixelFormat(hDC, &pfd); if (pf == 0) {MessageBox(NULL, "ChoosePixelFormat() failed: " "Cannot find a suitable pixel format.", "Error", MB_OK); return 0; } if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {MessageBox(NULL, "SetPixelFormat() failed: " "Cannot set format specified.", "Error", MB_OK);return 0; } DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd); ReleaseDC(hWnd, hDC); return hWnd;} int APIENTRYWinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,LPSTR lpszCmdLine, int nCmdShow){ HGLRC hRC;/* opengl context */ HWND hWnd;/* window */ MSG msg;/* message */ hWnd = CreateOpenGLWindow("minimal", 0, 0, win_width, win_height, PFD_TYPE_RGBA, PFD_DOUBLEBUFFER); if (hWnd == NULL)exit(1); hDC = GetDC(hWnd); hRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hRC); ShowWindow(hWnd, SW_SHOW); /* get the total number of modes so we can allocate memory for all of 'em. */ num_modes = 0; while (EnumDisplaySettings(NULL, num_modes, &devmode))num_modes++; /* fill an array with all the devmodes so we don't have to keep grabbing 'em. */ devmodes = (DEVMODE*)malloc(sizeof(DEVMODE)*num_modes); num_modes = 0; while (EnumDisplaySettings(NULL, num_modes, &devmodes[num_modes]))num_modes++; while(GetMessage(&msg, hWnd, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg); } /* free the array of devmodes, and click our heels to come back from Oz...don't forget Toto. */ free(devmodes); ChangeDisplaySettings(NULL, 0); wglMakeCurrent(NULL, NULL); ReleaseDC(hWnd, hDC); wglDeleteContext(hRC); DestroyWindow(hWnd); return msg.wParam;}