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
CreateStarBitmap(HWND hWnd,HDC hDC)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
InitGL(HBITMAP hStarTex)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
render(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
OnCreate(HWND hWnd,WPARAM wParam,LPARAM lParam)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
OnDestroy(HWND hWnd,WPARAM wParam,LPARAM lParam)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
OnPaint(HWND hWnd,WPARAM wParam,LPARAM lParam)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
OnSize(HWND hWnd,WPARAM wParam,LPARAM lParam)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
ScreenSaverProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)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
InitApp(HINSTANCE hInstance,LPCTSTR szClassName)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
InitInstance(HINSTANCE hInstance,int nCmdShow)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
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)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