#include <windows.h>
#include <gl/gl.h>
#include <stdlib.h>
#include <memory.h>

HWND       m_hWnd;
HDC        m_hDC;
HGLRC      m_hRC;
SYSTEMTIME st;

bool       rota=false;
GLuint     StundenZeiger,MinutenZeiger,SekundenZeiger;

LRESULT CALLBACK MainWndProc(HWND,UINT,WPARAM,LPARAM);
bool   bSetupPixelFormat();
GLvoid Resize(GLsizei,GLsizei);
GLvoid InitializeGL();
GLvoid DrawScene();
GLvoid CloseGL();

/*****************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR     lpCmdLine,
                   int       nCmdShow)
{
  MSG      msg;
  WNDCLASS wndclass;
  char     szAppName[]="RotatingClock";

   wndclass.style         = 0;
   wndclass.lpfnWndProc   = (WNDPROC)MainWndProc;
   wndclass.cbClsExtra    = 0;
   wndclass.cbWndExtra    = 0;
   wndclass.hInstance     = hInstance;
   wndclass.hIcon         = LoadIcon(hInstance,szAppName);
   wndclass.hCursor       = LoadCursor(NULL,IDC_ARROW);
   wndclass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
   wndclass.lpszMenuName  = szAppName;
   wndclass.lpszClassName = szAppName;

   if (!RegisterClass(&wndclass)) return false;

   m_hWnd = CreateWindow(szAppName,
               "Rotating Clock",
               WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
               CW_USEDEFAULT,
               CW_USEDEFAULT,
               640,
               500,
               NULL,
               NULL,
               hInstance,
               NULL);
   if (!m_hWnd) return false;

   GetLocalTime(&st);
   srand(st.wMilliseconds);

   ShowWindow(m_hWnd,nCmdShow);
   UpdateWindow(m_hWnd);

   SetTimer(m_hWnd,1,20,NULL);

   while (GetMessage(&msg,NULL,0,0)){
      TranslateMessage(&msg);
      DispatchMessage (&msg);
   }
   return msg.wParam;
}
/*****************************************************************************/
LONG WINAPI MainWndProc(HWND    hWnd,
                        UINT    uMsg,
                        WPARAM  wParam,
                        LPARAM  lParam)
{
  LONG lRet = 1;
  PAINTSTRUCT ps;
  RECT rc;

   switch(uMsg){
      case WM_CREATE:
         m_hDC = GetDC(hWnd);
         if (!bSetupPixelFormat()) PostQuitMessage(0);
         m_hRC = wglCreateContext(m_hDC);
         wglMakeCurrent(m_hDC,m_hRC);
         InitializeGL();
      break;

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

      case WM_SIZE:
         GetClientRect(hWnd,&rc);
         Resize(rc.right-rc.left,rc.bottom-rc.top);
         DrawScene();
      break;

      case WM_CLOSE:
         KillTimer(m_hWnd,1);
         CloseGL();
         wglMakeCurrent(0,0);
         if (m_hRC) wglDeleteContext(m_hRC);
         if (m_hDC) ReleaseDC(hWnd,m_hDC);
         m_hRC=0;
         m_hDC=0;
         DestroyWindow(hWnd);
      break;

      case WM_DESTROY:
         PostQuitMessage(0);
      break;

      case WM_TIMER:
         GetLocalTime(&st);
         DrawScene();
      break;

      case WM_LBUTTONDOWN:
         rota=!rota;
      break;
      case WM_LBUTTONUP:
         rota=!rota;
      break;

      case WM_KEYDOWN:
         switch(wParam){
            case VK_ESCAPE:
               SendMessage(m_hWnd,WM_CLOSE,0,0);
            break;
            case VK_F1:
               rota=!rota;
            break;
         }

      default:
         lRet=DefWindowProc(hWnd,uMsg,wParam,lParam);
      break;
   }
   return lRet;
}
/*****************************************************************************/
bool bSetupPixelFormat()
{
  PIXELFORMATDESCRIPTOR pfd;
  int pixelformat;

   memset(&pfd,0,sizeof(pfd));
   pfd.nSize       = sizeof(PIXELFORMATDESCRIPTOR);
   pfd.nVersion    = 1;
   pfd.dwFlags     = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL
                                        | PFD_DOUBLEBUFFER;
   pfd.dwLayerMask = PFD_MAIN_PLANE;
   pfd.iPixelType  = PFD_TYPE_RGBA;
   pfd.cColorBits  = 16;
   pfd.cDepthBits  = 8;

   if ((pixelformat=ChoosePixelFormat(m_hDC,&pfd)) == 0){
      MessageBox(NULL,"ChoosePixelFormat Fehler","Fehler",MB_OK);
      return false;
   }

   if (SetPixelFormat(m_hDC,pixelformat,&pfd) == false){
      MessageBox(NULL,"SetPixelFormat Fehler","Fehler",MB_OK);
      return false;
   }

   return true;
}
/*****************************************************************************/
GLvoid Resize(GLsizei width, GLsizei height)
{
   GLdouble aspect= (GLdouble)width/height;

   glViewport(0,0,width,height);

   glMatrixMode(GL_PROJECTION);   glLoadIdentity();
   if (aspect>1) glOrtho(-aspect,aspect,-1.0     ,1.0     ,-3.0,3.0);
            else glOrtho(-1.0   ,1.0   ,-1/aspect,1/aspect,-3.0,3.0);
   glMatrixMode(GL_MODELVIEW);
}
/*****************************************************************************/
GLvoid InitializeGL()
{
   glClearColor(0.99f,0.99f,0.99f,0.99f);

   glDisable(GL_LIGHTING);
   glDisable(GL_DEPTH_TEST);
   glShadeModel(GL_SMOOTH);


   StundenZeiger = glGenLists(1);
   glNewList(StundenZeiger,GL_COMPILE);
      glBegin(GL_QUADS);
         glColor3f(0.4f,0.4f,0.4f);   glVertex2f( 0.00f,0.5f);
         glColor3f(1.0f,1.0f,1.0f);   glVertex2f( 0.05f,0.1f);
         glColor3f(0.4f,0.4f,0.4f);   glVertex2f( 0.00f,0.0f);
         glColor3f(0.1f,0.1f,0.1f);   glVertex2f(-0.05f,0.1f);
      glEnd();
   glEndList();


   MinutenZeiger = glGenLists(1);
   glNewList(MinutenZeiger,GL_COMPILE);
      glBegin(GL_QUADS);
         glColor3f(1.0f,1.0f,1.0f);   glVertex2f( 0.00f,0.9f);
         glColor3f(1.0f,1.0f,1.0f);   glVertex2f( 0.04f,0.1f);
         glColor3f(0.5f,0.5f,0.5f);   glVertex2f( 0.00f,0.0f);
         glColor3f(0.1f,0.1f,0.1f);   glVertex2f(-0.04f,0.1f);
      glEnd();
   glEndList();


   SekundenZeiger = glGenLists(1);
   glNewList(SekundenZeiger,GL_COMPILE);
      glBegin(GL_QUADS);
         glColor3f(1.0f,0.0f,0.0f);   glVertex2f( 0.00f,1.0f);
         glColor3f(1.0f,0.0f,0.0f);   glVertex2f( 0.02f,0.3f);
         glColor3f(1.0f,1.0f,0.0f);   glVertex2f( 0.00f,0.0f);
         glColor3f(1.0f,0.0f,0.0f);   glVertex2f(-0.02f,0.3f);
      glEnd();
   glEndList();
}
/*****************************************************************************/
GLvoid DrawScene()
{
  static bool chan=true;
  static int  ax=rand()-RAND_MAX/2;
  static int  ay=rand()-RAND_MAX/2;
  static int  az=rand()-RAND_MAX/2;


   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glPushMatrix();

      if ((st.wSecond==0) && chan){
         ax=rand()-RAND_MAX/2;
         ay=rand()-RAND_MAX/2;
         az=rand()-RAND_MAX/2;
         chan=false;
      }
      if (st.wSecond) chan=true;

      glLoadIdentity();
      if (rota)
          glRotated(
          -360.0/60.0*
          (st.wSecond+st.wMilliseconds/1000.0),
          ax,ay,az);


      glBegin(GL_QUADS);
         glColor3f(1.0f,0.0f,0.0f);   glVertex2f(-1.0f,-1.0f);
         glColor3f(0.0f,1.0f,0.0f);   glVertex2f( 1.0f,-1.0f);
         glColor3f(0.0f,0.0f,1.0f);   glVertex2f( 1.0f, 1.0f);
         glColor3f(1.0f,1.0f,0.0f);   glVertex2f(-1.0f, 1.0f);
      glEnd();

      glPushMatrix();
         glRotated(
            -360.0/12.0*
            (st.wHour+
             st.wMinute/60.0+
             st.wSecond/3600.0+
             st.wMilliseconds/3600000.0),
            0,0,1);
         glCallList(StundenZeiger);
      glPopMatrix();

      glPushMatrix();
         glRotated(
            -360.0/60.0*
            (st.wMinute+
             st.wSecond/60.0+
             st.wMilliseconds/60000.0),
            0,0,1);
         glCallList(MinutenZeiger);
      glPopMatrix();

      glPushMatrix();
         glRotated(
            -360.0/60.0*
            (st.wSecond+
             st.wMilliseconds/1000.0),
            0,0,1);
         glCallList(SekundenZeiger);
      glPopMatrix();

   glPopMatrix();

   glFlush();
   SwapBuffers(m_hDC);
}
/*****************************************************************************/
GLvoid CloseGL()
{
   glDeleteLists( StundenZeiger,1);
   glDeleteLists( MinutenZeiger,1);
   glDeleteLists(SekundenZeiger,1);
}
/*****************************************************************************/