home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible / OpenGL_Superbible_Waite_Group_Press_1996.iso / book / chapt8 / dither / dither.c next >
C/C++ Source or Header  |  1996-07-06  |  15KB  |  578 lines

  1. // Dither.c
  2. // Demonstrates dithering by drawing a rotatable cube that has colors
  3. // not easily represented purely by a 332 palette or in 16 color mode.
  4. //  Dithering can be turned on and off by a menu selection.
  5.  
  6. #include <windows.h>            // Window defines
  7. #include <gl\gl.h>              // OpenGL
  8. #include <gl\glu.h>             // GLU library
  9. #include "resource.h"           // About box resource identifiers.
  10.  
  11.  
  12. // Application name and instance storeage
  13. static LPCTSTR lpszAppName = "Dithered Cube";
  14. static HINSTANCE hInstance;
  15.  
  16. static bDither = FALSE;
  17.  
  18. // Rotation amounts
  19. static GLfloat xRot = 0.0f;
  20. static GLfloat yRot = 0.0f;
  21.  
  22.  
  23. static GLsizei lastHeight;
  24. static GLsizei lastWidth;
  25.  
  26.  
  27. // Normalize, keep the angles within 0 to 360 degrees
  28. GLfloat Normal360(GLfloat dSource)
  29.     {
  30.     if(dSource < 0.0)
  31.         dSource = 360.0f + dSource;
  32.  
  33.     if(dSource > 360.0f)
  34.         dSource = 360.0f - dSource;    
  35.  
  36.     return dSource;
  37.     }
  38.  
  39.  
  40. // Declaration for Window procedure
  41. LRESULT CALLBACK WndProc(       HWND    hWnd,
  42.                             UINT    message,
  43.                             WPARAM  wParam,
  44.                             LPARAM  lParam);
  45.  
  46. // Dialog procedure for about box
  47. BOOL APIENTRY AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam);
  48.  
  49. // Set Pixel Format function - forward declaration
  50. void SetDCPixelFormat(HDC hDC);
  51.  
  52.  
  53.  
  54. // Change viewing volume and viewport.  Called when window is resized
  55. void ChangeSize(GLsizei w, GLsizei h)
  56.     {
  57. // Prevent a divide by zero
  58.     if(h == 0)
  59.         h = 1;
  60.  
  61.     lastWidth = w;
  62.     lastHeight = h;
  63.         
  64.     // Set Viewport to window dimensions
  65.     glViewport(0, 0, w, h);
  66.  
  67.     // Reset coordinate system
  68.     glLoadIdentity();
  69.  
  70.     // Establish clipping volume (left, right, bottom, top, near, far)
  71.     if (w <= h) 
  72.         glOrtho (-100.0f, 100.0f, 100.0f*h/w, -100.0f*h/w, 100.0, -100.0);
  73.     else 
  74.         glOrtho (-100.0f*w/h, 100.0f*w/h, 100.0f, -100.0f, 100.0, -100.0);
  75.  
  76.     glRotatef(xRot, 1.0f, 0.0f, 0.0f);
  77.     glRotatef(yRot, 0.0f, 1.0f, 0.0f);
  78.     }
  79.  
  80.  
  81.  
  82. // Called to draw scene
  83. void RenderScene(void)
  84.     {
  85.     glEnable(GL_DEPTH_TEST);    
  86.  
  87.     if(bDither)
  88.         glEnable(GL_DITHER);
  89.     else
  90.         glDisable(GL_DITHER);
  91.  
  92.     glShadeModel(GL_SMOOTH);
  93.  
  94.     // Clear the window with current clearing color
  95.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  96.  
  97.     ChangeSize(lastWidth,lastHeight);
  98.  
  99.     // Front face
  100.     // Gray
  101.     glColor3f(0.75f, 0.75f, 0.75f);
  102.     glBegin(GL_POLYGON);
  103.         glVertex3f(50.0f,50.0f,50.0f);
  104.         glVertex3f(50.0f,-50.0f,50.0f);
  105.         glVertex3f(-50.0f,-50.0f,50.0f);
  106.         glVertex3f(-50.0f,50.0f,50.0f);
  107.     glEnd();
  108.  
  109.     
  110.     // Back Face
  111.     // Pink
  112.     glColor3f(0.98f, 0.04f, 0.7f);
  113.     glBegin(GL_POLYGON);
  114.         glVertex3f(50.0f,50.0f,-50.0f);
  115.         glVertex3f(50.0f,-50.0f,-50.0f);
  116.         glVertex3f(-50.0f,-50.0f,-50.0f);
  117.         glVertex3f(-50.0f,50.0f,-50.0f);
  118.     glEnd();
  119.  
  120.  
  121.     // Top Face
  122.     // Barney Purple
  123.     glColor3f(.60f, 0.40f, 0.7f);
  124.     glBegin(GL_POLYGON);
  125.         glVertex3f(50.0f,50.0f,-50.0f);
  126.         glVertex3f(50.0f,50.0f,50.0f);
  127.         glVertex3f(-50.0f,50.0f,50.0f);
  128.         glVertex3f(-50.0f,50.0f,-50.0f);
  129.     glEnd();
  130.  
  131.  
  132.     // Bottom Face
  133.     glColor3f(0.976f, 0.55f, 0.18f);
  134.     glBegin(GL_POLYGON);
  135.         glVertex3f(50.0f,-50.0f,-50.0f);
  136.         glVertex3f(50.0f,-50.0f,50.0f);
  137.         glVertex3f(-50.0f,-50.0f,50.0f);
  138.         glVertex3f(-50.0f,-50.0f,-50.0f);
  139.     glEnd();
  140.  
  141.  
  142.     // Left face
  143.     glColor3f(0.49f, 0.84f, 0.30f);
  144.     glBegin(GL_POLYGON);
  145.         glVertex3f(50.0f,50.0f,50.0f);
  146.         glVertex3f(50.0f,50.0f,-50.0f);
  147.         glVertex3f(50.0f,-50.0f,-50.0f);
  148.         glVertex3f(50.0f,-50.0f,50.0f);
  149.     glEnd();
  150.  
  151.  
  152.     // Right face
  153.     // Pumpkin Orange
  154.     glColor3f(0.98f, 0.625f, 0.12f);
  155.     glBegin(GL_POLYGON);
  156.         glVertex3f(-50.0f,50.0f,50.0f);
  157.         glVertex3f(-50.0f,50.0f,-50.0f);
  158.         glVertex3f(-50.0f,-50.0f,-50.0f);
  159.         glVertex3f(-50.0f,-50.0f,50.0f);
  160.     glEnd();
  161.  
  162.     // Flush drawing commands
  163.     glFlush();
  164.     }
  165.  
  166.  
  167. // Select the pixel format for a given device context
  168. void SetDCPixelFormat(HDC hDC)
  169.     {
  170.     int nPixelFormat;
  171.  
  172.     static PIXELFORMATDESCRIPTOR pfd = {
  173.         sizeof(PIXELFORMATDESCRIPTOR),  // Size of this structure
  174.         1,                                                              // Version of this structure    
  175.         PFD_DRAW_TO_WINDOW |                    // Draw to Window (not to bitmap)
  176.         PFD_SUPPORT_OPENGL |                    // Support OpenGL calls in window
  177.         PFD_DOUBLEBUFFER,                       // Double buffered
  178.         PFD_TYPE_RGBA,                          // RGBA Color mode
  179.         24,                                     // Want 24bit color 
  180.         0,0,0,0,0,0,                            // Not used to select mode
  181.         0,0,                                    // Not used to select mode
  182.         0,0,0,0,0,                              // Not used to select mode
  183.         32,                                     // Size of depth buffer
  184.         0,                                      // Not used to select mode
  185.         0,                                      // Not used to select mode
  186.         PFD_MAIN_PLANE,                         // Draw in main plane
  187.         0,                                      // Not used to select mode
  188.         0,0,0 };                                // Not used to select mode
  189.  
  190.     // Choose a pixel format that best matches that described in pfd
  191.     nPixelFormat = ChoosePixelFormat(hDC, &pfd);
  192.  
  193.     // Set the pixel format for the device context
  194.     SetPixelFormat(hDC, nPixelFormat, &pfd);
  195.     }
  196.  
  197.  
  198.  
  199. // If necessary, creates a 3-3-2 palette for the device context listed.
  200. HPALETTE GetOpenGLPalette(HDC hDC)
  201.     {
  202.     HPALETTE hRetPal = NULL;    // Handle to palette to be created
  203.     PIXELFORMATDESCRIPTOR pfd;    // Pixel Format Descriptor
  204.     LOGPALETTE *pPal;            // Pointer to memory for logical palette
  205.     int nPixelFormat;            // Pixel format index
  206.     int nColors;                // Number of entries in palette
  207.     int i;                        // Counting variable
  208.     BYTE RedRange,GreenRange,BlueRange;
  209.                                 // Range for each color entry (7,7,and 3)
  210.  
  211.  
  212.     // Get the pixel format index and retrieve the pixel format description
  213.     nPixelFormat = GetPixelFormat(hDC);
  214.     DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
  215.  
  216.     // Does this pixel format require a palette?  If not, do not create a
  217.     // palette and just return NULL
  218.     if(!(pfd.dwFlags & PFD_NEED_PALETTE))
  219.         return NULL;
  220.  
  221.     // Number of entries in palette.  8 bits yeilds 256 entries
  222.     nColors = 1 << pfd.cColorBits;    
  223.  
  224.     // Allocate space for a logical palette structure plus all the palette entries
  225.     pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +nColors*sizeof(PALETTEENTRY));
  226.  
  227.     // Fill in palette header 
  228.     pPal->palVersion = 0x300;        // Windows 3.0
  229.     pPal->palNumEntries = nColors; // table size
  230.  
  231.     // Build mask of all 1's.  This creates a number represented by having
  232.     // the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
  233.     // pfd.cBlueBits.  
  234.     RedRange = (1 << pfd.cRedBits) -1;
  235.     GreenRange = (1 << pfd.cGreenBits) - 1;
  236.     BlueRange = (1 << pfd.cBlueBits) -1;
  237.  
  238.     // Loop through all the palette entries
  239.     for(i = 0; i < nColors; i++)
  240.         {
  241.         // Fill in the 8-bit equivalents for each component
  242.         pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
  243.         pPal->palPalEntry[i].peRed = (unsigned char)(
  244.             (double) pPal->palPalEntry[i].peRed * 255.0 / RedRange);
  245.  
  246.         pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
  247.         pPal->palPalEntry[i].peGreen = (unsigned char)(
  248.             (double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange);
  249.  
  250.         pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
  251.         pPal->palPalEntry[i].peBlue = (unsigned char)(
  252.             (double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);
  253.  
  254.         pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
  255.         }
  256.         
  257.  
  258.     // Create the palette
  259.     hRetPal = CreatePalette(pPal);
  260.  
  261.     // Go ahead and select and realize the palette for this device context
  262.     SelectPalette(hDC,hRetPal,FALSE);
  263.     RealizePalette(hDC);
  264.  
  265.     // Free the memory used for the logical palette structure
  266.     free(pPal);
  267.  
  268.     // Return the handle to the new palette
  269.     return hRetPal;
  270.     }
  271.  
  272.  
  273. // Entry point of all Windows programs
  274. int APIENTRY WinMain(   HINSTANCE       hInst,
  275.                         HINSTANCE       hPrevInstance,
  276.                         LPSTR           lpCmdLine,
  277.                         int                     nCmdShow)
  278.     {
  279.     MSG                     msg;            // Windows message structure
  280.     WNDCLASS        wc;                     // Windows class structure
  281.     HWND            hWnd;           // Storeage for window handle
  282.  
  283.     hInstance = hInst;
  284.  
  285.     // Register Window style
  286.     wc.style                        = CS_HREDRAW | CS_VREDRAW;
  287.     wc.lpfnWndProc          = (WNDPROC) WndProc;
  288.     wc.cbClsExtra           = 0;
  289.     wc.cbWndExtra           = 0;
  290.     wc.hInstance            = hInstance;
  291.     wc.hIcon                        = NULL;
  292.     wc.hCursor                      = LoadCursor(NULL, IDC_ARROW);
  293.     
  294.     // No need for background brush for OpenGL window
  295.     wc.hbrBackground        = NULL;         
  296.     
  297.     wc.lpszMenuName         = MAKEINTRESOURCE(IDR_MENU);
  298.     wc.lpszClassName        = lpszAppName;
  299.  
  300.     // Register the window class
  301.     if(RegisterClass(&wc) == 0)
  302.         return FALSE;
  303.  
  304.  
  305.     // Create the main application window
  306.     hWnd = CreateWindow(
  307.                 lpszAppName,
  308.                 lpszAppName,
  309.                 
  310.                 // OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS
  311.                 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  312.     
  313.                 // Window position and size
  314.                 50, 50,
  315.                 400, 400,
  316.                 NULL,
  317.                 NULL,
  318.                 hInstance,
  319.                 NULL);
  320.  
  321.     // If window was not created, quit
  322.     if(hWnd == NULL)
  323.         return FALSE;
  324.  
  325.  
  326.     // Display the window
  327.     ShowWindow(hWnd,SW_SHOW);
  328.     UpdateWindow(hWnd);
  329.  
  330.     // Process application messages until the application closes
  331.     while( GetMessage(&msg, NULL, 0, 0))
  332.         {
  333.         TranslateMessage(&msg);
  334.         DispatchMessage(&msg);
  335.         }
  336.  
  337.     return msg.wParam;
  338.     }
  339.  
  340.  
  341.  
  342.  
  343. // Window procedure, handles all messages for this program
  344. LRESULT CALLBACK WndProc(       HWND    hWnd,
  345.                             UINT    message,
  346.                             WPARAM  wParam,
  347.                             LPARAM  lParam)
  348.     {
  349.     static HGLRC hRC;               // Permenant Rendering context
  350.     static HDC hDC;                 // Private GDI Device context
  351.     static HMENU hMenu;                // Handle to the menu
  352.     static HPALETTE hPalette = NULL;// Handle to the palette
  353.  
  354.     switch (message)
  355.         {
  356.         // Window creation, setup for OpenGL
  357.         case WM_CREATE:
  358.             // Store the device context
  359.             hDC = GetDC(hWnd);              
  360.  
  361.             // Select the pixel format
  362.             SetDCPixelFormat(hDC);          
  363.  
  364.             hPalette = GetOpenGLPalette(hDC);
  365.  
  366.             // Create the rendering context and make it current
  367.             hRC = wglCreateContext(hDC);
  368.             wglMakeCurrent(hDC, hRC);
  369.  
  370.             break;
  371.  
  372.         // Window is being destroyed, cleanup
  373.         case WM_DESTROY:
  374.             // Deselect the current rendering context and delete it
  375.             wglMakeCurrent(hDC,NULL);
  376.             wglDeleteContext(hRC);
  377.  
  378.             if(hPalette != NULL)
  379.                 DeleteObject(hPalette);
  380.  
  381.             // Tell the application to terminate after the window
  382.             // is gone.
  383.             PostQuitMessage(0);
  384.             break;
  385.  
  386.         // Window is resized.
  387.         case WM_SIZE:
  388.             // Call our function which modifies the clipping
  389.             // volume and viewport
  390.             ChangeSize(LOWORD(lParam), HIWORD(lParam));
  391.             break;
  392.  
  393.  
  394.         // The painting function.  This message sent by Windows 
  395.         // whenever the screen needs updating.
  396.         case WM_PAINT:
  397.             {
  398.             // Call OpenGL drawing code
  399.             RenderScene();
  400.  
  401.             SwapBuffers(hDC);
  402.  
  403.             // Validate the newly painted client area
  404.             ValidateRect(hWnd,NULL);
  405.             }
  406.             break;
  407.  
  408.         // Windows is telling the application that it may modify
  409.         // the system palette.  This message in essance asks the 
  410.         // application for a new palette.
  411.         case WM_QUERYNEWPALETTE:
  412.             // If the palette was created.
  413.             if(hPalette)
  414.                 {
  415.                 int nRet;
  416.  
  417.                 // Selects the palette into the current device context
  418.                 SelectPalette(hDC, hPalette, FALSE);
  419.  
  420.                 // Map entries from the currently selected palette to
  421.                 // the system palette.  The return value is the number 
  422.                 // of palette entries modified.
  423.                 nRet = RealizePalette(hDC);
  424.  
  425.                 // Repaint, forces remap of palette in current window
  426.                 InvalidateRect(hWnd,NULL,FALSE);
  427.  
  428.                 return nRet;
  429.                 }
  430.             break;
  431.  
  432.     
  433.         // This window may set the palette, even though it is not the 
  434.         // currently active window.
  435.         case WM_PALETTECHANGED:
  436.             // Don't do anything if the palette does not exist, or if
  437.             // this is the window that changed the palette.
  438.             if((hPalette != NULL) && ((HWND)wParam != hWnd))
  439.                 {
  440.                 // Select the palette into the device context
  441.                 SelectPalette(hDC,hPalette,FALSE);
  442.  
  443.                 // Map entries to system palette
  444.                 RealizePalette(hDC);
  445.                 
  446.                 // Remap the current colors to the newly realized palette
  447.                 UpdateColors(hDC);
  448.                 return 0;
  449.                 }
  450.             break;
  451.  
  452.         case WM_KEYDOWN:
  453.             {
  454.             if(wParam == VK_UP)
  455.                 xRot-= 5.0f;
  456.  
  457.             if(wParam == VK_DOWN)
  458.                 xRot += 5.0f;
  459.  
  460.             if(wParam == VK_LEFT)
  461.                 yRot += 5.0f;
  462.  
  463.             if(wParam == VK_RIGHT)
  464.                 yRot -= 5.0f;
  465.  
  466.             xRot = Normal360(xRot);
  467.             yRot = Normal360(yRot);
  468.  
  469.             InvalidateRect(hWnd,NULL,FALSE);
  470.             }
  471.             break;
  472.  
  473.         // A menu command
  474.         case WM_COMMAND:
  475.             {
  476.             switch(LOWORD(wParam))
  477.                 {
  478.                 // Exit the program
  479.                 case ID_FILE_EXIT:
  480.                     DestroyWindow(hWnd);
  481.                     break;
  482.  
  483.                 // Display the about box
  484.                 case ID_HELP_ABOUT:
  485.                     DialogBox (hInstance,
  486.                         MAKEINTRESOURCE(IDD_DIALOG_ABOUT),
  487.                         hWnd,
  488.                         AboutDlgProc);
  489.                     break;
  490.  
  491.                 // Toggle dithering
  492.                 case ID_EFFECTS_DITHER:
  493.  
  494.                     // Toggle dither flag
  495.                     bDither = !bDither;
  496.  
  497.                     // Check or uncheck menu item
  498.                     hMenu = GetMenu(hWnd);
  499.                     hMenu = GetSubMenu(hMenu,1);
  500.                     
  501.                     if(bDither)
  502.                         CheckMenuItem(hMenu,0,MF_BYPOSITION | MF_CHECKED);
  503.                     else
  504.                         CheckMenuItem(hMenu,0,MF_BYPOSITION | MF_UNCHECKED);
  505.  
  506.                     InvalidateRect(hWnd,NULL,FALSE);
  507.                     break;
  508.                 }
  509.             }
  510.             break;
  511.  
  512.  
  513.     default:   // Passes it on if unproccessed
  514.         return (DefWindowProc(hWnd, message, wParam, lParam));
  515.  
  516.     }
  517.  
  518.     return (0L);
  519.     }
  520.  
  521.  
  522.  
  523.  
  524. // Dialog procedure.
  525. BOOL APIENTRY AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam)
  526.     {
  527.     
  528.     switch (message)
  529.     {
  530.         // Initialize the dialog box
  531.         case WM_INITDIALOG:
  532.             {
  533.             int i;
  534.             GLenum glError;
  535.  
  536.             // glGetString demo
  537.             SetDlgItemText(hDlg,IDC_OPENGL_VENDOR,glGetString(GL_VENDOR));
  538.             SetDlgItemText(hDlg,IDC_OPENGL_RENDERER,glGetString(GL_RENDERER));
  539.             SetDlgItemText(hDlg,IDC_OPENGL_VERSION,glGetString(GL_VERSION));
  540.             SetDlgItemText(hDlg,IDC_OPENGL_EXTENSIONS,glGetString(GL_EXTENSIONS));
  541.  
  542.             // gluGetString demo
  543.             SetDlgItemText(hDlg,IDC_GLU_VERSION,gluGetString(GLU_VERSION));
  544.             SetDlgItemText(hDlg,IDC_GLU_EXTENSIONS,gluGetString(GLU_EXTENSIONS));
  545.  
  546.  
  547.             // Display any recent error messages
  548.             i = 0;
  549.             do {
  550.                 glError = glGetError();
  551.                 SetDlgItemText(hDlg,IDC_ERROR1+i,gluErrorString(glError));
  552.                 i++;
  553.                 }
  554.             while(i < 6 && glError != GL_NO_ERROR);
  555.  
  556.  
  557.             return (TRUE);
  558.             }
  559.             break;
  560.  
  561.         // Process command messages
  562.         case WM_COMMAND:      
  563.             {
  564.             // Validate and Make the changes
  565.             if(LOWORD(wParam) == IDOK)
  566.                 EndDialog(hDlg,TRUE);
  567.             }
  568.             break;
  569.  
  570.         // Closed from sysbox
  571.         case WM_CLOSE:
  572.             EndDialog(hDlg,TRUE);
  573.             break;
  574.         }
  575.  
  576.     return FALSE;
  577.     }
  578.