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



HWND         m_hWnd;
HDC          m_hDC;
HGLRC        m_hRC;

SYSTEMTIME   st;
MEMORYSTATUS memstat;

const GLuint CuiMinZeilenAnzahl=1,
             CuiMaxZeilenAnzahl=80;

bool         rota=false,bMonitorActivated=true,bClockActivated=true;
GLuint       StundenZeiger,MinutenZeiger,SekundenZeiger;
GLuint       uiBmpFont=0;
int          iFontWidth=0,iFontHeight=0;
GLuint       uiZeilenAnzahl=18;
GLsizei      iCurViewHeight=0;


LRESULT CALLBACK MainWndProc(HWND,UINT,WPARAM,LPARAM);
bool   bSetupPixelFormat();
GLvoid Print(const char *pcText,int inFontHeight,int inFontWidth);
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[]="Memorymonitor";

   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,
               "Memory monitor",
               WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
               CW_USEDEFAULT,
               CW_USEDEFAULT,
               CW_USEDEFAULT,
               CW_USEDEFAULT,
               NULL,
               NULL,
               hInstance,
               NULL);
   if (!m_hWnd) return false;

   GetLocalTime(&st);
   GlobalMemoryStatus(&memstat);
   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);
         GlobalMemoryStatus(&memstat);
         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:
               if (uiZeilenAnzahl<CuiMaxZeilenAnzahl) uiZeilenAnzahl++;
            break;
            case VK_F2:
               if (uiZeilenAnzahl>CuiMinZeilenAnzahl) uiZeilenAnzahl--;
            break;
            case VK_F3:
               bMonitorActivated= !bMonitorActivated;
            break;
            case VK_F4:
               rota=!rota;
            break;
            case VK_F5:
               bClockActivated= !bClockActivated;
            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 Print(const char *pcText,int inFontHeight,int inFontWidth)
{
  HFONT   hFont;
  HGDIOBJ hOldFont;

   if (pcText==NULL) return;

   if ((iFontWidth!=inFontWidth || iFontHeight!=inFontHeight) &&
       (inFontWidth>3||!inFontWidth) && (inFontHeight>3)) {

       iFontWidth = inFontWidth;
       iFontHeight= inFontHeight;

       if (uiBmpFont) glDeleteLists(uiBmpFont,224);

       uiBmpFont= glGenLists(224);
       hFont    = CreateFont(iFontHeight,iFontWidth,0,0,
                     FW_SEMIBOLD,                 // Textdicke
                     false,                       // Kursiv
                     false,                       // unterstrichen
                     false,                       // durchgestrichen
                     ANSI_CHARSET,                // Zeichensatz
                     OUT_TT_PRECIS,               // Ausgabegenauigkeit
                     CLIP_DEFAULT_PRECIS,         // Clippinggenauigkeit
                     ANTIALIASED_QUALITY,         // Ausgabequalität
                     FF_DONTCARE | DEFAULT_PITCH, // Familie & Ausrichtung
                     "Courier New"                // Font
                  );
       hOldFont= SelectObject(m_hDC,hFont);
       wglUseFontBitmaps(m_hDC,32,224,uiBmpFont);
       SelectObject(m_hDC,hOldFont);
       DeleteObject(hFont);
   };

   if (uiBmpFont) {
      glPushAttrib(GL_LIST_BIT);
      glListBase(uiBmpFont-32);
      glCallLists(strlen(pcText),GL_UNSIGNED_BYTE,pcText);
      glPopAttrib();
   }
}
/*****************************************************************************/
GLvoid Resize(GLsizei width, GLsizei height)
{
  GLdouble aspect= (GLdouble)width/height;

   iCurViewHeight= 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;

  GLuint uiAktuelleZeile;
  char   szBuffer[100];


   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   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;


   if (bClockActivated) {
      glPushMatrix();

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


         glColor3f(0.95f,0.95f,0.95f);
         glBegin(GL_QUADS);
            glVertex2f(-1.0f,-1.0f);
            glVertex2f( 1.0f,-1.0f);
            glVertex2f( 1.0f, 1.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();
   }


   if (bMonitorActivated) {
      glMatrixMode(GL_PROJECTION);
      glPushMatrix();
      glLoadIdentity();
      if (uiZeilenAnzahl) glOrtho(-0.007,1,-0.25,uiZeilenAnzahl-0.25,-3.0,3.0);

      glColor3f(0.0f,0.0f,0.0f);

      uiAktuelleZeile= uiZeilenAnzahl-2;
      //****************************************************
      glRasterPos2i(0,uiAktuelleZeile--);
      sprintf(szBuffer,"%s","Physikalischer Speicher (KB)");
      Print(szBuffer,iCurViewHeight/uiZeilenAnzahl,0);

      uiAktuelleZeile--;
      glRasterPos2i(0,uiAktuelleZeile--);
      sprintf(szBuffer,"%s%d"," Insgesamt  : ",
                               memstat.dwTotalPhys/1024);
      Print(szBuffer,iCurViewHeight/uiZeilenAnzahl,0);

      glRasterPos2i(0,uiAktuelleZeile--);
      sprintf(szBuffer,"%s%d"," Verfügbar  : ",
                               memstat.dwAvailPhys/1024);
      Print(szBuffer,iCurViewHeight/uiZeilenAnzahl,0);
      //****************************************************
      uiAktuelleZeile--;
      glRasterPos2i(0,uiAktuelleZeile--);
      sprintf(szBuffer,"%s","Zugesicherter Speicher (KB)");
      Print(szBuffer,iCurViewHeight/uiZeilenAnzahl,0);

      uiAktuelleZeile--;
      glRasterPos2i(0,uiAktuelleZeile--);
      sprintf(szBuffer,"%s%d"," Insgesamt  : ",
                               (memstat.dwTotalPageFile-
                                memstat.dwAvailPageFile)
                               /1024);
      Print(szBuffer,iCurViewHeight/uiZeilenAnzahl,0);


      glRasterPos2i(0,uiAktuelleZeile--);
      sprintf(szBuffer,"%s%d"," Grenzwert  : ",
                               memstat.dwTotalPageFile/1024);
      Print(szBuffer,iCurViewHeight/uiZeilenAnzahl,0);
      //****************************************************
      uiAktuelleZeile--;
      glRasterPos2i(0,uiAktuelleZeile--);
      sprintf(szBuffer,"%s","Virtueller Speicher dieser Anwendung (KB)");
      Print(szBuffer,iCurViewHeight/uiZeilenAnzahl,0);

      uiAktuelleZeile--;
      glRasterPos2i(0,uiAktuelleZeile--);
      sprintf(szBuffer,"%s%d"," Insgesamt  : ",
                               memstat.dwTotalVirtual/1024);
      Print(szBuffer,iCurViewHeight/uiZeilenAnzahl,0);


      glRasterPos2i(0,uiAktuelleZeile--);
      sprintf(szBuffer,"%s%d"," Verfügbar  : ",
                               memstat.dwAvailVirtual/1024);
      Print(szBuffer,iCurViewHeight/uiZeilenAnzahl,0);
      //****************************************************
      uiAktuelleZeile--;
      glRasterPos2i(0,uiAktuelleZeile--);
      sprintf(szBuffer,"%s%d%s"," Die Speicherauslastung beträgt ",
                               memstat.dwMemoryLoad,"%.");
      Print(szBuffer,iCurViewHeight/uiZeilenAnzahl,0);
      //****************************************************

      glPopMatrix();
      glMatrixMode(GL_MODELVIEW);
   }

   glFlush();
   SwapBuffers(m_hDC);
}
/*****************************************************************************/
GLvoid CloseGL()
{
   if (uiBmpFont) {
      glDeleteLists(uiBmpFont,224);
      uiBmpFont= 0;
   }

   glDeleteLists( StundenZeiger,1);
   glDeleteLists( MinutenZeiger,1);
   glDeleteLists(SekundenZeiger,1);
}
/*****************************************************************************/