#define ZBUFFER 0 #define DBLBUFFER 1 #define USE_COLOR_INDEX 1 #include #include #include #include #include #include long WndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ); long DlgProcRotate ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ); void DoGlStuff( HWND hWnd, HDC hDc ); HGLRC hrcInitGL(HWND hwnd, HDC hdc); void vResizeDoubleBuffer(HWND hwnd, HDC hdc); void vCleanupGL(HGLRC hrc); #include #define TERMINATE DbgPrint("%s (%d)\n", __FILE__, __LINE__), ExitProcess(0) #define WINDSIZEX(Rect) (Rect.right - Rect.left) #define WINDSIZEY(Rect) (Rect.bottom - Rect.top) // Default Logical Palette indexes #define BLACK_INDEX 0 #define WHITE_INDEX 19 #define RED_INDEX 13 #define GREEN_INDEX 14 #define BLUE_INDEX 16 #define YELLOW_INDEX 15 #define MAGENTA_INDEX 17 #define CYAN_INDEX 18 // Global variables defining current position and orientation. GLfloat AngleX = 145.0; GLfloat AngleY = 50.0; GLfloat AngleZ = 0.0; GLfloat DeltaAngle[3] = { 0.0, 0.0, 0.0 }; GLfloat OffsetX = 0.0; GLfloat OffsetY = 0.0; GLfloat OffsetZ = -3.0; GLuint DListCube; UINT guiTimerTick = 128; HGLRC ghrc = (HGLRC) 0; #ifdef DBLBUFFER HDC ghdcMem; HBITMAP ghbmBackBuffer = (HBITMAP) 0, ghbmOld; #endif HWND hdlgRotate; int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { static char szAppName[] = "TimeCube"; HWND hwnd; MSG msg; RECT Rect; WNDCLASS wndclass; if ( !hPrevInstance ) { //wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.style = 0; wndclass.lpfnWndProc = (WNDPROC)WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; // With a NULL icon handle, app will paint into the icon window. wndclass.hIcon = NULL; //wndclass.hIcon = LoadIcon(hInstance, "CubeIcon"); RegisterClass(&wndclass); } /* * Make the windows a reasonable size and pick a * position for it. */ Rect.left = GetPrivateProfileInt("Window", "left", 100, "timecube.ini"); Rect.top = GetPrivateProfileInt("Window", "top", 100, "timecube.ini");; Rect.right = GetPrivateProfileInt("Window", "right", 200, "timecube.ini");; Rect.bottom = GetPrivateProfileInt("Window", "bottom", 200, "timecube.ini");; guiTimerTick= GetPrivateProfileInt("Animate", "Timer", 32, "timecube.ini");; AdjustWindowRect( &Rect, WS_OVERLAPPEDWINDOW, FALSE ); hwnd = CreateWindow ( szAppName, // window class name "TimeCube", // window caption WS_OVERLAPPEDWINDOW, // window style Rect.left, // initial x position Rect.top, // initial y position WINDSIZEX(Rect), // initial x size WINDSIZEY(Rect), // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL // creation parameter ); ShowWindow( hwnd, nCmdShow ); UpdateWindow( hwnd ); hdlgRotate = CreateDialog(hInstance, "RotateDlg", hwnd, DlgProcRotate); SetTimer(hwnd, 1, guiTimerTick, NULL); while ( GetMessage( &msg, NULL, 0, 0 )) { if ( (hdlgRotate == 0) || !IsDialogMessage(hdlgRotate, &msg) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } return( msg.wParam ); } long WndProc ( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { HDC hDc; PAINTSTRUCT ps; int iWidth, iHeight; switch ( message ) { case WM_PAINT: hDc = BeginPaint( hWnd, &ps ); if (ghrc == (HGLRC) 0) ghrc = hrcInitGL(hWnd, hDc); DoGlStuff( hWnd, hDc ); EndPaint( hWnd, &ps ); return(0); case WM_SIZE: iWidth = LOWORD(lParam); iHeight = HIWORD(lParam); #if 0 SetWindowPos (hWnd, // hwnd HWND_TOP, // z-order 0, 0, // position max(iWidth, iHeight), // new width max(iWidth, iHeight), // new height SWP_NOMOVE); // keep old postion #endif hDc = GetDC(hWnd); vResizeDoubleBuffer(hWnd, hDc); ReleaseDC(hWnd, hDc); return(0); case WM_CHAR: switch(wParam) { case 'd': case 'D': OffsetX += 0.2; break; case 'a': case 'A': OffsetX -= 0.2; break; // !!! Note: currently the coordinate system is upside down, so // !!! so up and down are reversed. case 's': case 'S': OffsetY += 0.2; break; case 'w': case 'W': OffsetY -= 0.2; break; case 'q': case 'Q': OffsetZ += 0.2; break; case 'e': case 'E': OffsetZ -= 0.2; break; case ',': case '<': guiTimerTick = guiTimerTick << 1; guiTimerTick = min(0x40000000, guiTimerTick); KillTimer(hWnd, 1); SetTimer(hWnd, 1, guiTimerTick, NULL); break; case '.': case '>': guiTimerTick = guiTimerTick >> 1; guiTimerTick = max(1, guiTimerTick); KillTimer(hWnd, 1); SetTimer(hWnd, 1, guiTimerTick, NULL); break; default: break; } return 0; case WM_TIMER: AngleX += DeltaAngle[0]; AngleY += DeltaAngle[1]; AngleZ += DeltaAngle[2]; hDc = GetDC(hWnd); if (ghrc == (HGLRC) 0) ghrc = hrcInitGL(hWnd, hDc); DoGlStuff( hWnd, hDc ); ReleaseDC(hWnd, hDc); return 0; case WM_DESTROY: vCleanupGL(ghrc); KillTimer(hWnd, 1); PostQuitMessage( 0 ); DestroyWindow(hdlgRotate); return( 0 ); } return( DefWindowProc( hWnd, message, wParam, lParam ) ); } BOOL DlgProcRotate(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HWND hwndCtrl; int iCtrl, iIndex; long lPos, lVal; static char ach[80]; switch(msg) { case WM_INITDIALOG: for (iCtrl = 10; iCtrl < 13; iCtrl += 1) { hwndCtrl = GetDlgItem(hwnd, iCtrl); SetScrollRange(hwndCtrl, SB_CTL, 0, 90, FALSE); SetScrollPos(hwndCtrl, SB_CTL, 45, FALSE); } return TRUE; case WM_VSCROLL: hwndCtrl = lParam; iCtrl = GetWindowLong(hwndCtrl, GWL_ID); iIndex = iCtrl - 10; lVal = (long) DeltaAngle[iIndex]; switch(LOWORD(wParam)) { case SB_BOTTOM: lVal = -45; lPos = 90; DeltaAngle[iIndex] = -45.0; break; case SB_TOP: lVal = 45; lPos = 0; DeltaAngle[iIndex] = 45.0; break; case SB_PAGEDOWN: lVal -= 4; case SB_LINEDOWN: lVal = max(-45, lVal - 1); lPos = 45 - lVal; DeltaAngle[iIndex] = (float) lVal; break; case SB_PAGEUP: lVal += 4; case SB_LINEUP: lVal = min(45, lVal + 1); lPos = 45 - lVal; DeltaAngle[iIndex] = (float) lVal; break; case SB_THUMBPOSITION: case SB_THUMBTRACK: lPos = (long) HIWORD(wParam); lVal = 45 - lPos; // invert and unbias DeltaAngle[iIndex] = (float) lVal; break; default: return FALSE; } // Update scroll bar. SetScrollPos(hwndCtrl, SB_CTL, lPos, TRUE); // Update the static text with new value. wsprintf(ach, "%ld", lVal); SetDlgItemText(hwnd, iCtrl + 10, ach); return TRUE; default: break; } return FALSE; } void vResizeDoubleBuffer(HWND hwnd, HDC hdc) { RECT Rect; /* Get the size of the client area */ GetClientRect( hwnd, &Rect ); if (ghbmBackBuffer != (HBITMAP) 0) DeleteObject(SelectObject(ghdcMem, ghbmOld)); ghbmBackBuffer = CreateCompatibleBitmap(hdc, WINDSIZEX(Rect), WINDSIZEY(Rect)); ghbmOld = SelectObject(ghdcMem, ghbmBackBuffer); //!!! [GilmanW] OpenGL hack !!! //!!! //!!! For some reason we need to prepare the memory DC. GL //!!! drawing seems limited to the area drawn to by GDI calls. //!!! By BitBlt'ing the entire memory DC, the whole thing is //!!! is available to GL. //!!! //!!! There must be something we need to update on the server //!!! side so that this is not necessary. BitBlt(ghdcMem, 0, 0, WINDSIZEX(Rect), WINDSIZEY(Rect), NULL, 0, 0, BLACKNESS); } HGLRC hrcInitGL(HWND hwnd, HDC hdc) { HGLRC hrc; #if !USE_COLOR_INDEX static GLfloat ClearColor[] = { (GLfloat)0.0, // Red (GLfloat)0.0, // Green (GLfloat)0.0, // Blue (GLfloat)1.0 // Alpha }; static GLfloat Cyan[] = { (GLfloat)0.0, // Read (GLfloat)0.666, // Green (GLfloat)0.666, // Blue (GLfloat)1.0 // Alpha }; static GLfloat Yellow[] = { (GLfloat)0.666, // Red (GLfloat)0.666, // Green (GLfloat)0.0, // Blue (GLfloat)1.0 // Alpha }; static GLfloat Magenta[] = { (GLfloat)0.666, // Red (GLfloat)0.0, // Green (GLfloat)0.666, // Blue (GLfloat)1.0 // Alpha }; static GLfloat Red[] = { (GLfloat)1.0, // Red (GLfloat)0.0, // Green (GLfloat)0.0, // Blue (GLfloat)1.0 // Alpha }; static GLfloat Green[] = { (GLfloat)0.0, // Red (GLfloat)1.0, // Green (GLfloat)0.0, // Blue (GLfloat)1.0 // Alpha }; static GLfloat Blue[] = { (GLfloat)0.0, // Red (GLfloat)0.0, // Green (GLfloat)1.0, // Blue (GLfloat)1.0 // Alpha }; #endif /* Create a Rendering Context */ #if DBLBUFFER ghdcMem = CreateCompatibleDC(hdc); SelectObject(ghdcMem, GetStockObject(DEFAULT_PALETTE)); vResizeDoubleBuffer(hwnd, hdc); hrc = wglCreateContext( ghdcMem ); #else hrc = wglCreateContext( hdc ); #endif /* Make it Current */ #if DBLBUFFER wglMakeCurrent( ghdcMem, hrc ); #else wglMakeCurrent( hdc, hrc ); #endif // !!! Note: currently the coordinate system is upside down, so we // !!! need to reverse the default "front face" definition. glFrontFace(GL_CW); /* Set the clear color */ #if USE_COLOR_INDEX glClearIndex(BLACK_INDEX); #else glClearColor( ClearColor[0], ClearColor[1], ClearColor[2], ClearColor[3] ); #endif /* Turn off dithering */ glDisable(GL_DITHER); /* Turn on z-buffer */ #if ZBUFFER glEnable(GL_DEPTH_TEST); #else glDisable(GL_DEPTH_TEST); #endif /* Turn on backface culling */ glEnable(GL_CULL_FACE); /* Generate a display list for a cube */ DListCube = glGenLists(1); glNewList(DListCube, GL_COMPILE); glBegin(GL_QUADS); #if USE_COLOR_INDEX glIndexi(BLUE_INDEX); #else glColor4fv( Blue ); #endif glVertex3f( (GLfloat) 0.7, (GLfloat) 0.7, (GLfloat) 0.7); glVertex3f( (GLfloat) 0.7, (GLfloat) -0.7, (GLfloat) 0.7); glVertex3f( (GLfloat) 0.7, (GLfloat) -0.7, (GLfloat) -0.7); glVertex3f( (GLfloat) 0.7, (GLfloat) 0.7, (GLfloat) -0.7); #if USE_COLOR_INDEX glIndexi(GREEN_INDEX); #else glColor4fv( Green ); #endif glVertex3f( (GLfloat) 0.7, (GLfloat) 0.7, (GLfloat) -0.7); glVertex3f( (GLfloat) 0.7, (GLfloat) -0.7, (GLfloat) -0.7); glVertex3f( (GLfloat) -0.7, (GLfloat) -0.7, (GLfloat) -0.7); glVertex3f( (GLfloat) -0.7, (GLfloat) 0.7, (GLfloat) -0.7); #if USE_COLOR_INDEX glIndexi(RED_INDEX); #else glColor4fv( Red ); #endif glVertex3f( (GLfloat) -0.7, (GLfloat) 0.7, (GLfloat) -0.7); glVertex3f( (GLfloat) -0.7, (GLfloat) -0.7, (GLfloat) -0.7); glVertex3f( (GLfloat) -0.7, (GLfloat) -0.7, (GLfloat) 0.7); glVertex3f( (GLfloat) -0.7, (GLfloat) 0.7, (GLfloat) 0.7); #if USE_COLOR_INDEX glIndexi(CYAN_INDEX); #else glColor4fv( Cyan ); #endif glVertex3f( (GLfloat) -0.7, (GLfloat) 0.7, (GLfloat) 0.7); glVertex3f( (GLfloat) -0.7, (GLfloat) -0.7, (GLfloat) 0.7); glVertex3f( (GLfloat) 0.7, (GLfloat) -0.7, (GLfloat) 0.7); glVertex3f( (GLfloat) 0.7, (GLfloat) 0.7, (GLfloat) 0.7); #if USE_COLOR_INDEX glIndexi(YELLOW_INDEX); #else glColor4fv( Yellow ); #endif glVertex3f( (GLfloat) 0.7, (GLfloat) 0.7, (GLfloat) 0.7); glVertex3f( (GLfloat) 0.7, (GLfloat) 0.7, (GLfloat) -0.7); glVertex3f( (GLfloat) -0.7, (GLfloat) 0.7, (GLfloat) -0.7); glVertex3f( (GLfloat) -0.7, (GLfloat) 0.7, (GLfloat) 0.7); #if USE_COLOR_INDEX glIndexi(MAGENTA_INDEX); #else glColor4fv( Magenta ); #endif glVertex3f( (GLfloat) 0.7, (GLfloat) -0.7, (GLfloat) 0.7); glVertex3f( (GLfloat) -0.7, (GLfloat) -0.7, (GLfloat) 0.7); glVertex3f( (GLfloat) -0.7, (GLfloat) -0.7, (GLfloat) -0.7); glVertex3f( (GLfloat) 0.7, (GLfloat) -0.7, (GLfloat) -0.7); glEnd(); glEndList(); return hrc; } void vCleanupGL(hrc) { /* Destroy our context */ wglDeleteContext( hrc ); #if DBLBUFFER DeleteObject(SelectObject(ghdcMem, ghbmOld)); DeleteDC(ghdcMem); #endif } void DoGlStuff( HWND hWnd, HDC hDc ) { RECT Rect; HGLRC hRc; /* Get the size of the client area */ GetClientRect( hWnd, &Rect ); /* Set up the projection matrix */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(OffsetX, OffsetY, OffsetZ); glRotatef(AngleX, 1.0, 0.0, 0.0); glRotatef(AngleY, 0.0, 1.0, 0.0); glRotatef(AngleZ, 0.0, 0.0, 1.0); glViewport(0, 0, WINDSIZEX(Rect), WINDSIZEY(Rect)); /* Clear the color buffer */ #if ZBUFFER glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); #else glClear( GL_COLOR_BUFFER_BIT ); #endif /* Draw the cube */ /* Draw the cube */ glCallList(DListCube); glFlush(); #if DBLBUFFER BitBlt(hDc, 0, 0, Rect.right-Rect.left, Rect.bottom-Rect.top, ghdcMem, 0, 0, SRCCOPY); GdiFlush(); #endif }