1 /* 2 * Star field screensaver 3 * 4 * Copyright 2011 Carlo Bramini 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 #define WIN32_LEAN_AND_MEAN 22 #include <windows.h> 23 #include <tchar.h> 24 #include <scrnsave.h> 25 26 #include <stdlib.h> 27 #include <time.h> 28 #include <math.h> 29 30 #include <GL/gl.h> 31 #include <GL/glu.h> 32 33 #include "resource.h" 34 #include "settings.h" 35 36 #define FAR_PLANE -80.0f 37 #define NEAR_PLANE 3.0f 38 #define GAP 0.0f 39 #define FIELD_WIDTH 50.f 40 #define FIELD_HEIGHT 45.f 41 #define FIELD_DEPTH (NEAR_PLANE - FAR_PLANE + GAP) 42 43 #define STAR_RED 0.f 44 #define STAR_GREEN 0.f 45 #define STAR_BLUE 0.10f 46 #define STAR_TAIL 0.9f 47 48 typedef struct { 49 float x1; 50 float y1; 51 float x2; 52 float y2; 53 float z; 54 } VERTEX; 55 56 static VERTEX Vertex[MAX_STARS]; 57 static HGLRC hRC; // Permanent Rendering Context 58 static HDC hDC; // Private GDI Device Context 59 static float fAngle; 60 static GLuint glStarTex; 61 62 // Light position 63 static GLfloat g_light_position[4] = { 64 0.0f, 0.0f, 3.0f, 1.0f 65 }; 66 67 static PIXELFORMATDESCRIPTOR pfd= // Pixel Format Descriptor 68 { 69 sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 70 1, // Version Number (?) 71 PFD_DRAW_TO_WINDOW | // Format Must Support Window 72 PFD_SUPPORT_OPENGL | // Format Must Support OpenGL 73 PFD_DOUBLEBUFFER, // Must Support Double Buffering 74 PFD_TYPE_RGBA, // Request An RGBA Format 75 16, // Select A 16Bit Color Depth 76 0, 0, 0, 0, 0, 0, // Color Bits Ignored (?) 77 0, // No Alpha Buffer 78 0, // Shift Bit Ignored (?) 79 0, // No Accumulation Buffer 80 0, 0, 0, 0, // Accumulation Bits Ignored (?) 81 16, // 16Bit Z-Buffer (Depth Buffer) 82 0, // No Stencil Buffer 83 0, // No Auxiliary Buffer (?) 84 PFD_MAIN_PLANE, // Main Drawing Layer 85 0, // Reserved (?) 86 0, 0, 0 // Layer Masks Ignored (?) 87 }; 88 89 static HBITMAP CreateStarBitmap(HWND hWnd, HDC hDC) 90 { 91 BITMAPINFO bi; 92 LPBYTE lpBits; 93 LPBYTE *lppBits; 94 HBITMAP hTextBmp, hFileBmp; 95 HDC hTextDC, hFileDC; 96 HGDIOBJ hOldText, hOldFile; 97 UINT i; 98 DWORD *Ptr32; 99 BITMAP bm; 100 HINSTANCE hInstance; 101 102 // Get instance for loading the texture 103 hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE); 104 105 // Load the texture 106 hFileBmp = (HBITMAP) 107 LoadImage( 108 hInstance, 109 MAKEINTRESOURCE(IDB_STAR), 110 IMAGE_BITMAP, 111 0, 0, 112 LR_CREATEDIBSECTION | LR_DEFAULTSIZE 113 ); 114 115 // Get texture specs 116 GetObject(hFileBmp, sizeof(BITMAP), &bm); 117 118 // Allocate new 32 bit texture 119 ZeroMemory(&bi, sizeof(bi)); 120 121 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 122 bi.bmiHeader.biWidth = bm.bmWidth; 123 bi.bmiHeader.biHeight = -bm.bmHeight; 124 bi.bmiHeader.biPlanes = 1; 125 bi.bmiHeader.biBitCount = 32; 126 bi.bmiHeader.biCompression = BI_RGB; 127 128 // Makes GCC happy ;-| 129 lppBits = &lpBits; 130 131 hTextBmp = CreateDIBSection(hDC, 132 (BITMAPINFO*)&bi, 133 DIB_RGB_COLORS, 134 (void**)lppBits, 135 NULL, 136 0); 137 138 // Save new texture specs 139 // GetObject(hTextBmp, sizeof(BITMAP), &bmStarTex); 140 // bmStarTex.bmBits = lpBits; 141 142 // Copy 24 bit texture in 32 texture 143 hTextDC = CreateCompatibleDC(hDC); 144 hFileDC = CreateCompatibleDC(hDC); 145 146 hOldText = SelectObject(hTextDC, hTextBmp); 147 hOldFile = SelectObject(hFileDC, hFileBmp); 148 149 BitBlt(hTextDC, 0, 0, bm.bmWidth, bm.bmHeight, hFileDC, 0, 0, SRCCOPY); 150 151 SelectObject(hTextDC, hOldText); 152 SelectObject(hFileDC, hOldFile); 153 154 DeleteDC(hTextDC); 155 DeleteDC(hFileDC); 156 157 // Delete 24 bit texture 158 DeleteObject(hFileBmp); 159 160 GetObject(hTextBmp, sizeof(BITMAP), &bm); 161 162 // Apply ALPHA channel to new texture 163 for (Ptr32=(DWORD *)lpBits, i=0; i < (UINT)(bm.bmWidth * bm.bmHeight); i++) 164 { 165 DWORD Color = Ptr32[i] & 0x00FFFFFF; 166 DWORD Alpha = Color & 0xFF; 167 168 Color |= Alpha << 24; 169 170 Ptr32[i] = Color; 171 } 172 173 return hTextBmp; 174 } 175 176 static void InitGL(HBITMAP hStarTex) 177 { 178 BITMAP bm; 179 unsigned int i; 180 float xp, yp, zp; 181 182 // set the GL clear color - use when the color buffer is cleared 183 glClearColor(STAR_RED, STAR_GREEN, STAR_BLUE, STAR_TAIL); 184 185 if (Settings.bSmoothShading) 186 // set the shading model to 'smooth' 187 glShadeModel( GL_SMOOTH ); 188 else 189 // set the shading model to 'flat' 190 glShadeModel( GL_FLAT ); 191 192 // set GL to render front of polygons 193 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); 194 // enable depth test 195 glDisable( GL_DEPTH_TEST ); 196 197 // enable lighting 198 glEnable( GL_LIGHTING ); 199 // enable lighting for front 200 glLightModeli( GL_FRONT, GL_TRUE ); 201 // material have diffuse and ambient lighting 202 glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); 203 // enable color 204 glEnable( GL_COLOR_MATERIAL ); 205 // enable light 0 206 glEnable( GL_LIGHT0 ); 207 208 // set light attenuation 209 glLightf( GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.01f); //0.01f ); 210 glLightf( GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.01f); //0.2f ); 211 glLightf( GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.005f); //0.001f ); 212 213 // clear the color buffer once 214 glClear( GL_COLOR_BUFFER_BIT ); 215 216 // randomly generate 217 srand( time( NULL ) ); 218 219 // Initialize *ALL* stars vertexes (not just programmed ones). 220 for (i = 0; i < MAX_STARS; i++) 221 { 222 xp = ( (float) rand() / RAND_MAX - .5f ) * FIELD_WIDTH; 223 yp = ( (float) rand() / RAND_MAX - .5f ) * FIELD_HEIGHT; 224 zp = ( (float) rand() / RAND_MAX ) * FIELD_DEPTH + FAR_PLANE; 225 226 Vertex[i].x1 = -1.f + xp; 227 Vertex[i].y1 = -1.f + yp; 228 Vertex[i].x2 = 1.f + xp; 229 Vertex[i].y2 = 1.f + yp; 230 Vertex[i].z = zp; 231 } 232 233 glGenTextures(1, &glStarTex); // Create One Texture 234 235 // Create Linear Filtered Texture 236 glBindTexture(GL_TEXTURE_2D, glStarTex); 237 238 if (Settings.bEnableFiltering) 239 { 240 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 241 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 242 } else { 243 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 244 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 245 } 246 247 // Get Texture properties 248 GetObject(hStarTex, sizeof(BITMAP), &bm); 249 250 // Create texture as a mipmap 251 #if 0 252 glTexImage2D(GL_TEXTURE_2D, 0, 4, bm.bmWidth, bm.bmHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, bm.bmBits); 253 #else 254 gluBuild2DMipmaps(GL_TEXTURE_2D, 4, bm.bmWidth, bm.bmHeight, GL_RGBA, GL_UNSIGNED_BYTE, bm.bmBits); 255 #endif 256 257 // Disable Texture Mapping (background smoothing) 258 glDisable(GL_TEXTURE_2D); 259 260 if (Settings.bFinePerspective) 261 // Really Fast Perspective Calculations 262 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); 263 else 264 // Really Nice Perspective Calculations 265 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 266 267 // enable blending 268 glEnable( GL_BLEND ); 269 } 270 271 static void 272 render(void) 273 { 274 unsigned int i; 275 float fSpin; 276 float fSpeed; 277 float xp, yp; 278 279 // Initialize current speed 280 fSpeed = (float)Settings.uiSpeed / 100.f; 281 282 glEnable(GL_TEXTURE_2D); // Enable Texture Mapping 283 284 glBlendFunc(GL_SRC_ALPHA,GL_ONE); // Set The Blending Function For Translucency 285 286 switch (Settings.uiRotation) { 287 case ROTATION_LINEAR: 288 fAngle += fSpeed; 289 glRotatef( fAngle, 0.0f, 0.0f, 1.0f ); 290 break; 291 292 case ROTATION_PERIODIC: 293 fAngle += fSpeed / 75.f; 294 fSpin = (float)(50. * cos(fAngle)); 295 glRotatef( fSpin, 0.0f, 0.0f, 1.0f ); 296 break; 297 } 298 299 glColor3ub(255, 255, 255); 300 301 glBegin(GL_QUADS); // Begin Drawing The Textured Quad 302 303 // Draw the stars 304 for (i = 0; i < Settings.uiNumStars; i++) 305 { 306 glTexCoord2f(0.0f, 0.0f); glVertex3f(Vertex[i].x1, Vertex[i].y1, Vertex[i].z); 307 glTexCoord2f(1.0f, 0.0f); glVertex3f(Vertex[i].x2, Vertex[i].y1, Vertex[i].z); 308 glTexCoord2f(1.0f, 1.0f); glVertex3f(Vertex[i].x2, Vertex[i].y2, Vertex[i].z); 309 glTexCoord2f(0.0f, 1.0f); glVertex3f(Vertex[i].x1, Vertex[i].y2, Vertex[i].z); 310 311 // increment z 312 Vertex[i].z += fSpeed; 313 314 // check to see if passed view 315 if( Vertex[i].z > NEAR_PLANE + GAP || 316 Vertex[i].z < FAR_PLANE ) 317 { 318 xp = ( (float) rand() / RAND_MAX - .5f ) * FIELD_WIDTH; 319 yp = ( (float) rand() / RAND_MAX - .5f ) * FIELD_HEIGHT; 320 321 Vertex[i].x1 = -1.f + xp; 322 Vertex[i].y1 = -1.f + yp; 323 Vertex[i].x2 = 1.f + xp; 324 Vertex[i].y2 = 1.f + yp; 325 Vertex[i].z = FAR_PLANE; 326 } 327 } 328 329 glEnd(); // Done Drawing The Textured Quad 330 331 glDisable(GL_TEXTURE_2D); // Enable Texture Mapping 332 } 333 334 static LRESULT CALLBACK 335 OnCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) 336 { 337 GLuint PixelFormat; 338 HBITMAP hStarTex; 339 340 LoadSettings(); 341 342 // Gets A Device Context For The Window 343 hDC = GetDC(hWnd); 344 345 // Finds The Closest Match To The Pixel Format We Set Above 346 PixelFormat = ChoosePixelFormat(hDC, &pfd); 347 348 // No Matching Pixel Format? 349 if (!PixelFormat) 350 { 351 MessageBox(0, _T("Can't Find A Suitable PixelFormat."), _T("Error"),MB_OK | MB_ICONERROR); 352 353 // This Sends A 'Message' Telling The Program To Quit 354 PostQuitMessage(0); 355 return 0; 356 } 357 358 // Can We Set The Pixel Mode? 359 if (!SetPixelFormat(hDC, PixelFormat, &pfd)) 360 { 361 MessageBox(0, _TEXT("Can't Set The PixelFormat."), _T("Error"), MB_OK | MB_ICONERROR); 362 363 // This Sends A 'Message' Telling The Program To Quit 364 PostQuitMessage(0); 365 return 0; 366 } 367 368 // Grab A Rendering Context 369 hRC = wglCreateContext(hDC); 370 371 // Did We Get One? 372 if (!hRC) 373 { 374 MessageBox(0, _T("Can't Create A GL Rendering Context."), _T("Error"), MB_OK | MB_ICONERROR); 375 376 // This Sends A 'Message' Telling The Program To Quit 377 PostQuitMessage(0); 378 return 0; 379 } 380 381 // Can We Make The RC Active? 382 if (!wglMakeCurrent(hDC, hRC)) 383 { 384 MessageBox(0, _T("Can't Activate GLRC."), _TEXT("Error"), MB_OK | MB_ICONERROR); 385 386 // This Sends A 'Message' Telling The Program To Quit 387 PostQuitMessage(0); 388 return 0; 389 } 390 391 // Load star texture 392 hStarTex = CreateStarBitmap(hWnd, hDC); 393 394 // Initialize The GL Screen Using Screen Info 395 InitGL(hStarTex); 396 397 // Delete GDI object for texture 398 DeleteObject(hStarTex); 399 400 // Update screen every 10ms 401 SetTimer(hWnd, 1, 10, NULL); 402 403 // Initialize spinning angle 404 fAngle = 0.f; 405 406 return 0L; 407 } 408 409 static LRESULT CALLBACK 410 OnDestroy(HWND hWnd, WPARAM wParam, LPARAM lParam) 411 { 412 // Delete update timer 413 KillTimer(hWnd, 1); 414 415 // Disable Fullscreen Mode 416 ChangeDisplaySettings(NULL, 0); 417 418 // Make The DC Current 419 wglMakeCurrent(hDC, NULL); 420 421 // Kill The RC 422 wglDeleteContext(hRC); 423 424 // Free The DC 425 ReleaseDC(hWnd, hDC); 426 427 #ifdef _DEBUG_SSTARS 428 PostQuitMessage(0); 429 #endif 430 431 return 0L; 432 } 433 434 static LRESULT CALLBACK 435 OnPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) 436 { 437 if (Settings.bDoBlending) 438 { 439 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); 440 441 // disable lighting 442 glDisable( GL_LIGHTING ); 443 444 // blend in a polygon 445 glColor4f(STAR_RED, STAR_GREEN, STAR_BLUE, STAR_TAIL); 446 447 // Restore both model view and projection to identity 448 glMatrixMode(GL_MODELVIEW); 449 glPushMatrix(); 450 glLoadIdentity(); 451 452 glMatrixMode(GL_PROJECTION); 453 glPushMatrix(); 454 glLoadIdentity(); 455 456 // Blur the background 457 glBegin( GL_QUADS ); 458 glVertex3f( -1.0f, -1.0f, -1.0f ); 459 glVertex3f( -1.0f, 1.0f, -1.0f ); 460 glVertex3f( 1.0f, 1.0f, -1.0f ); 461 glVertex3f( 1.0f, -1.0f, -1.0f ); 462 glEnd(); 463 464 // Recover previous matrix 465 glPopMatrix(); 466 glMatrixMode(GL_MODELVIEW); 467 glPopMatrix(); 468 469 // enable lighting 470 glEnable( GL_LIGHTING ); 471 } else { 472 glClear(GL_COLOR_BUFFER_BIT); 473 } 474 475 // save the current matrix state, so transformation will 476 // not persist across displayFunc calls, since we 477 // will do a glPopMatrix() at the end of this function 478 glPushMatrix(); 479 480 // render the scene 481 render(); 482 483 // restore the matrix state 484 glPopMatrix(); 485 486 // flush the buffer 487 glFlush(); 488 489 // swap the double buffer 490 SwapBuffers(hDC); 491 492 // Clear redraw event 493 ValidateRect(hWnd, NULL); 494 495 return 0L; 496 } 497 498 static LRESULT CALLBACK 499 OnSize(HWND hWnd, WPARAM wParam, LPARAM lParam) 500 { 501 GLsizei w = LOWORD(lParam); 502 GLsizei h = HIWORD(lParam); 503 504 // map the view port to the entire client area 505 glViewport(0, 0, w, h); 506 507 // set the matrix mode to projection matrix 508 glMatrixMode(GL_PROJECTION); 509 510 // load the identity matrix 511 glLoadIdentity(); 512 513 // set the perspective matrix 514 gluPerspective( 64.0, (GLdouble) w / (GLdouble)h, .1, 300.0 ); 515 516 // set the matrix mode to the modelview matrix 517 glMatrixMode(GL_MODELVIEW); 518 519 // load the identity matrix into the modelview matrix 520 glLoadIdentity(); 521 522 // set the 'camera' 523 gluLookAt( 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 2.0, 3.0 ); 524 525 // set the position of the light 526 glLightfv( GL_LIGHT0, GL_POSITION, g_light_position ); 527 528 return 0L; 529 } 530 531 LRESULT CALLBACK 532 ScreenSaverProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 533 { 534 switch (uMsg) { 535 case WM_CREATE: 536 return OnCreate(hWnd, wParam, lParam); 537 538 case WM_TIMER: 539 InvalidateRect(hWnd, NULL, FALSE); 540 return 0L; 541 542 case WM_DESTROY: 543 return OnDestroy(hWnd, wParam, lParam); 544 545 case WM_PAINT: 546 return OnPaint(hWnd, wParam, lParam); 547 548 case WM_SIZE: // Resizing The Screen 549 return OnSize(hWnd, wParam, lParam); 550 } 551 552 #ifdef _DEBUG_SSTARS 553 return DefWindowProc(hWnd, uMsg, wParam, lParam); 554 #else 555 return DefScreenSaverProc(hWnd, uMsg, wParam, lParam); 556 #endif 557 } 558 559 #ifdef _DEBUG_SSTARS 560 561 ATOM InitApp(HINSTANCE hInstance, LPCTSTR szClassName) 562 { 563 WNDCLASS wc; 564 565 ZeroMemory(&wc, sizeof(wc)); 566 567 wc.style = CS_HREDRAW | CS_VREDRAW; 568 wc.lpfnWndProc = ScreenSaverProc; 569 wc.cbClsExtra = 0; 570 wc.cbWndExtra = 0; 571 wc.hInstance = hInstance; 572 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 573 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 574 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 575 wc.lpszMenuName = NULL; 576 wc.lpszClassName = szClassName; 577 578 return RegisterClass(&wc); 579 } 580 581 HWND InitInstance(HINSTANCE hInstance, int nCmdShow) 582 { 583 HWND hWnd; 584 TCHAR szClass[] = _T("CLASS"); 585 TCHAR szTitle[] = _T("TITLE"); 586 587 InitApp(hInstance, szClass); 588 589 hWnd = CreateWindow( 590 szClass, 591 szTitle, 592 WS_OVERLAPPEDWINDOW, 593 CW_USEDEFAULT, 594 CW_USEDEFAULT, 595 192*3, //CW_USEDEFAULT, 596 108*3, //CW_USEDEFAULT, 597 NULL, 598 NULL, 599 hInstance, 600 NULL); 601 602 if (hWnd) 603 { 604 ShowWindow(hWnd, nCmdShow); 605 UpdateWindow(hWnd); 606 } 607 608 return hWnd; 609 } 610 611 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) 612 { 613 MSG msg; 614 HWND hWnd; 615 HWND hDlg; 616 617 RegisterDialogClasses(hInstance); 618 619 hWnd = InitInstance(hInstance, nShowCmd); 620 621 hDlg = CreateDialog(hInstance, MAKEINTRESOURCE(DLG_SCRNSAVECONFIGURE), NULL, ScreenSaverConfigureDialog); 622 ShowWindow(hDlg, SW_SHOW); 623 UpdateWindow(hDlg); 624 625 for (;;) 626 { 627 if (GetMessage(&msg, NULL, 0, 0) <= 0) 628 break; 629 630 TranslateMessage(&msg); 631 DispatchMessage(&msg); 632 } 633 634 return 0; 635 } 636 #endif 637