218f51ace566c4536a8289bcfc754563f16c890b
[reactos.git] / reactos / base / applications / screensavers / 3dtext / 3dtext.c
1 /*
2 * Copyright 2000 Jeff Molofee http://nehe.gamedev.net/ (Original code)
3 * Copyright 2006 Eric Kohl
4 * Copyright 2007 Marc Piulachs (marc.piulachs@codexchange.net) - minor modifications , converted to screensaver
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20
21 #include <windows.h>
22 #include <math.h>
23 #include <GL/gl.h>
24 #include <GL/glu.h>
25 #include <tchar.h>
26
27 #include "resource.h"
28 #include "3dtext.h"
29
30 static HGLRC hRC; // Permanent Rendering Context
31 static HDC hDC; // Private GDI Device Context
32
33 GLuint base; // Base Display List For The Font Set
34 GLfloat rot; // Used To Rotate The Text
35 GLfloat extentX = 0.0f;
36 GLfloat extentY = 0.0f;
37
38 #define APPNAME _T("3DText")
39
40 HINSTANCE hInstance;
41 BOOL fullscreen = FALSE;
42
43 // Build Our Bitmap Font
44 GLvoid BuildFont(GLvoid)
45 {
46 // Address Buffer For Font Storage
47 GLYPHMETRICSFLOAT gmf[256];
48 // Windows Font Handle
49 HFONT font;
50 int i;
51 TCHAR c;
52 GLfloat cellOriginX = 0.0f;
53 GLfloat stringOriginX;
54 GLfloat stringExtentX = 0.0f;
55 GLfloat stringExtentY = 0.0f;
56
57 // Storage For 256 Characters
58 base = glGenLists(256);
59
60 font = CreateFont(-12,
61 0, // Width Of Font
62 0, // Angle Of Escapement
63 0, // Orientation Angle
64 FW_BOLD, // Font Weight
65 FALSE, // Italic
66 FALSE, // Underline
67 FALSE, // Strikeout
68 DEFAULT_CHARSET, // Character Set Identifier
69 OUT_TT_PRECIS, // Output Precision
70 CLIP_DEFAULT_PRECIS, // Clipping Precision
71 ANTIALIASED_QUALITY, // Output Quality
72 FF_DONTCARE|DEFAULT_PITCH, // Family And Pitch
73 _T("Tahoma")); // Font Name
74
75 // Selects The Font We Created
76 SelectObject(hDC, font);
77
78 wglUseFontOutlines(hDC, // Select The Current DC
79 0, // Starting Character
80 255, // Number Of Display Lists To Build
81 base, // Starting Display Lists
82 0.0f, // Deviation From The True Outlines
83 0.2f, // Font Thickness In The Z Direction
84 WGL_FONT_POLYGONS, // Use Polygons, Not Lines
85 gmf); // Address Of Buffer To Recieve Data
86
87 // Calculate the string extent
88 for (i = 0; i < _tcslen(m_Text); i++)
89 {
90 c = m_Text[i];
91
92 stringOriginX = cellOriginX + gmf[c].gmfptGlyphOrigin.x;
93
94 stringExtentX = stringOriginX + gmf[c].gmfBlackBoxX;
95 if (gmf[c].gmfBlackBoxY > stringExtentY)
96 stringExtentY = gmf[c].gmfBlackBoxY;
97
98 cellOriginX = cellOriginX + gmf[c].gmfCellIncX;
99 }
100
101 extentX = stringExtentX;
102 extentY = stringExtentY;
103 }
104
105 // Delete The Font
106 GLvoid KillFont(GLvoid)
107 {
108 // Delete all 256 characters
109 glDeleteLists(base, 256);
110 }
111
112 // Custom GL "Print" Routine
113 GLvoid glPrint(LPTSTR text)
114 {
115 // If there's no text, do nothing
116 if (text == NULL)
117 return;
118
119 // Pushes The Display List Bits
120 glPushAttrib(GL_LIST_BIT);
121
122 // Sets The Base Character to 32
123 glListBase(base);
124
125 // Draws The Display List Text
126 glCallLists(_tcslen(text),
127 #ifdef UNICODE
128 GL_UNSIGNED_SHORT,
129 #else
130 GL_UNSIGNED_BYTE,
131 #endif
132 text);
133
134 // Pops The Display List Bits
135 glPopAttrib();
136 }
137
138 // Will Be Called Right After The GL Window Is Created
139 GLvoid InitGL(GLsizei Width, GLsizei Height)
140 {
141 // Clear The Background Color To Black
142 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
143
144 // Enables Clearing Of The Depth Buffer
145 glClearDepth(1.0);
146
147 // The Type Of Depth Test To Do
148 glDepthFunc(GL_LESS);
149
150 // Enables Depth Testing
151 glEnable(GL_DEPTH_TEST);
152
153 // Enables Smooth Color Shading
154 glShadeModel(GL_SMOOTH);
155
156 // Select The Projection Matrix
157 glMatrixMode(GL_PROJECTION);
158
159 // Reset The Projection Matrix
160 glLoadIdentity();
161
162 // Calculate The Aspect Ratio Of The Window
163 gluPerspective(45.0f, (GLfloat)Width / (GLfloat)Height, 0.1f, 100.0f);
164
165 // Select The Modelview Matrix
166 glMatrixMode(GL_MODELVIEW);
167
168 // Build The Font
169 BuildFont();
170
171 // Enable Default Light (Quick And Dirty)
172 glEnable(GL_LIGHT0);
173
174 // Enable Lighting
175 glEnable(GL_LIGHTING);
176
177 // Enable Coloring Of Material
178 glEnable(GL_COLOR_MATERIAL);
179 }
180
181 // Handles Window Resizing
182 GLvoid ReSizeGLScene(GLsizei Width, GLsizei Height)
183 {
184 // Is Window Too Small (Divide By Zero Error)
185 if (Height == 0)
186 {
187 // If So Make It One Pixel Tall
188 Height = 1;
189 }
190
191 // Reset The Current Viewport And Perspective Transformation
192 glViewport(0, 0, Width, Height);
193
194 // Select The Projection Matrix
195 glMatrixMode(GL_PROJECTION);
196
197 // Reset The Projection Matrix
198 glLoadIdentity();
199
200 // Calculate The Aspect Ratio Of The Window
201 gluPerspective(45.0f, (GLfloat)Width / (GLfloat)Height, 0.1f, 100.0f);
202
203 // Select The Modelview Matrix
204 glMatrixMode(GL_MODELVIEW);
205 }
206
207 // Handles Rendering
208 GLvoid DrawGLScene(GLvoid)
209 {
210 // Clear The Screen And The Depth Buffer
211 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
212
213 // Reset The View
214 glLoadIdentity();
215
216 // Move One Unit Into The Screen
217 glTranslatef(0.0f, 0.0f, -10.0f);
218
219 // Rotate On The X Axis
220 glRotatef(rot, 1.0f, 0.0f, 0.0f);
221
222 // Rotate On The Y Axis
223 glRotatef(rot * 1.2f, 0.0f, 1.0f, 0.0f);
224
225 // Rotate On The Z Axis
226 glRotatef(rot * 1.4f, 0.0f, 0.0f, 1.0f);
227
228 // Move to the Left and Down before drawing
229 glTranslatef(-(extentX / 2.0f),
230 -(extentY / 2.0f),
231 0.0f);
232
233 // Pulsing Colors Based On The Rotation
234 glColor3f((1.0f * (cos(rot / 20.0f))),
235 (1.0f * (sin(rot / 25.0f))),
236 (1.0f - 0.5f * (cos(rot / 17.0f))));
237
238 // Print GL Text To The Screen
239 glPrint(m_Text);
240
241 // Make The Text Blue
242 glColor3f(0.0f, 0.0f, 1.0f);
243
244 // Increase The Rotation Variable
245 rot += 0.1f;
246 }
247
248 LRESULT CALLBACK
249 WndProc(HWND hWnd,
250 UINT message,
251 WPARAM wParam,
252 LPARAM lParam)
253 {
254 static POINT ptLast;
255 static POINT ptCursor;
256 static BOOL fFirstTime = TRUE;
257 RECT Screen; // Used Later On To Get The Size Of The Window
258 GLuint PixelFormat; // Pixel Format Storage
259 static PIXELFORMATDESCRIPTOR pfd= // Pixel Format Descriptor
260 {
261 sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
262 1, // Version Number (?)
263 PFD_DRAW_TO_WINDOW | // Format Must Support Window
264 PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
265 PFD_DOUBLEBUFFER, // Must Support Double Buffering
266 PFD_TYPE_RGBA, // Request An RGBA Format
267 16, // Select A 16Bit Color Depth
268 0, 0, 0, 0, 0, 0, // Color Bits Ignored (?)
269 0, // No Alpha Buffer
270 0, // Shift Bit Ignored (?)
271 0, // No Accumulation Buffer
272 0, 0, 0, 0, // Accumulation Bits Ignored (?)
273 16, // 16Bit Z-Buffer (Depth Buffer)
274 0, // No Stencil Buffer
275 0, // No Auxiliary Buffer (?)
276 PFD_MAIN_PLANE, // Main Drawing Layer
277 0, // Reserved (?)
278 0, 0, 0 // Layer Masks Ignored (?)
279 };
280
281 switch (message)
282 {
283 case WM_CREATE:
284 // Gets A Device Context For The Window
285 hDC = GetDC(hWnd);
286
287 // Finds The Closest Match To The Pixel Format We Set Above
288 PixelFormat = ChoosePixelFormat(hDC, &pfd);
289
290 // No Matching Pixel Format?
291 if (!PixelFormat)
292 {
293 MessageBox(0, _TEXT("Can't Find A Suitable PixelFormat."), _TEXT("Error"),MB_OK | MB_ICONERROR);
294
295 // This Sends A 'Message' Telling The Program To Quit
296 PostQuitMessage(0);
297 break;
298 }
299
300 // Can We Set The Pixel Mode?
301 if (!SetPixelFormat(hDC, PixelFormat, &pfd))
302 {
303 MessageBox(0, _TEXT("Can't Set The PixelFormat."), _TEXT("Error"), MB_OK | MB_ICONERROR);
304
305 // This Sends A 'Message' Telling The Program To Quit
306 PostQuitMessage(0);
307 break;
308 }
309
310 // Grab A Rendering Context
311 hRC = wglCreateContext(hDC);
312
313 // Did We Get One?
314 if (!hRC)
315 {
316 MessageBox(0, _TEXT("Can't Create A GL Rendering Context."), _TEXT("Error"), MB_OK | MB_ICONERROR);
317
318 // This Sends A 'Message' Telling The Program To Quit
319 PostQuitMessage(0);
320 break;
321 }
322
323 // Can We Make The RC Active?
324 if (!wglMakeCurrent(hDC, hRC))
325 {
326 MessageBox(0, _TEXT("Can't Activate GLRC."), _TEXT("Error"), MB_OK | MB_ICONERROR);
327
328 // This Sends A 'Message' Telling The Program To Quit
329 PostQuitMessage(0);
330 break;
331 }
332
333 // Grab Screen Info For The Current Window
334 GetClientRect(hWnd, &Screen);
335
336 // Initialize The GL Screen Using Screen Info
337 InitGL(Screen.right, Screen.bottom);
338 break;
339
340 case WM_DESTROY:
341 case WM_CLOSE:
342 // Disable Fullscreen Mode
343 ChangeDisplaySettings(NULL, 0);
344
345 // Deletes The Font Display List
346 KillFont();
347
348 // Make The DC Current
349 wglMakeCurrent(hDC, NULL);
350
351 // Kill The RC
352 wglDeleteContext(hRC);
353
354 // Free The DC
355 ReleaseDC(hWnd, hDC);
356
357 // Quit The Program
358 PostQuitMessage(0);
359 break;
360
361 case WM_PAINT:
362 DrawGLScene();
363 SwapBuffers(hDC);
364 break;
365
366 case WM_NOTIFY:
367 case WM_SYSKEYDOWN:
368 PostMessage(hWnd, WM_CLOSE, 0, 0);
369 break;
370
371 case WM_LBUTTONDOWN:
372 case WM_LBUTTONUP:
373 case WM_RBUTTONDOWN:
374 case WM_RBUTTONUP:
375 case WM_MBUTTONDOWN:
376 case WM_MBUTTONUP:
377 case WM_MOUSEMOVE:
378 // If we've got a parent then we must be a preview
379 if (GetParent(hWnd) != 0)
380 return 0;
381
382 if (fFirstTime)
383 {
384 GetCursorPos(&ptLast);
385 fFirstTime = FALSE;
386 }
387
388 GetCursorPos(&ptCursor);
389
390 // if the mouse has moved more than 3 pixels then exit
391 if (abs(ptCursor.x - ptLast.x) >= 3 || abs(ptCursor.y - ptLast.y) >= 3)
392 PostMessage(hWnd, WM_CLOSE, 0, 0);
393
394 ptLast = ptCursor;
395 return 0;
396
397 case WM_SIZE: // Resizing The Screen
398 // Resize To The New Window Size
399 ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));
400 break;
401
402 default:
403 // Pass Windows Messages
404 return DefWindowProc(hWnd, message, wParam, lParam);
405 }
406
407 return 0;
408 }
409
410 VOID InitSaver(HWND hwndParent)
411 {
412 WNDCLASS wc;
413
414 ZeroMemory(&wc, sizeof(wc));
415 wc.style = CS_HREDRAW | CS_VREDRAW;
416 wc.lpfnWndProc = WndProc;
417 wc.lpszClassName = APPNAME;
418 RegisterClass(&wc);
419
420 if (hwndParent != 0)
421 {
422 RECT rect;
423
424 GetClientRect(hwndParent, &rect);
425 CreateWindow(APPNAME, APPNAME,
426 WS_VISIBLE | WS_CHILD,
427 0, 0,
428 rect.right,
429 rect.bottom,
430 hwndParent, 0,
431 hInstance, NULL);
432 fullscreen = FALSE;
433 }
434 else
435 {
436 HWND hwnd;
437 hwnd = CreateWindow(APPNAME, APPNAME,
438 WS_VISIBLE | WS_POPUP | WS_EX_TOPMOST,
439 0, 0,
440 GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
441 HWND_DESKTOP, 0,
442 hInstance, NULL);
443 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
444 ShowCursor(FALSE);
445 fullscreen = TRUE;
446 }
447 }
448
449 //
450 // Look for any options Windows has passed to us:
451 //
452 // -a <hwnd> (set password)
453 // -s (screensave)
454 // -p <hwnd> (preview)
455 // -c <hwnd> (configure)
456 //
457 VOID ParseCommandLine(LPTSTR szCmdLine, UCHAR *chOption, HWND *hwndParent)
458 {
459 TCHAR ch = *szCmdLine++;
460
461 if (ch == _T('-') || ch == _T('/'))
462 ch = *szCmdLine++;
463
464 //convert to lower case
465 if (ch >= _T('A') && ch <= _T('Z'))
466 ch += _T('a') - _T('A');
467
468 *chOption = ch;
469 ch = *szCmdLine++;
470
471 if (ch == _T(':'))
472 ch = *szCmdLine++;
473
474 while (ch == _T(' ') || ch == _T('\t'))
475 ch = *szCmdLine++;
476
477 if (_istdigit(ch))
478 {
479 unsigned int i = _ttoi(szCmdLine - 1);
480 *hwndParent = (HWND)i;
481 }
482 else
483 {
484 *hwndParent = NULL;
485 }
486 }
487
488
489 //
490 // Dialogbox procedure for Configuration window
491 //
492 BOOL CALLBACK ConfigDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
493 {
494 switch (uMsg)
495 {
496 case WM_INITDIALOG:
497 SetDlgItemText(hwnd, IDC_MESSAGE_TEXT, m_Text);
498 return TRUE;
499
500 case WM_COMMAND:
501 switch (LOWORD(wParam))
502 {
503 case IDOK:
504 GetDlgItemText(hwnd, IDC_MESSAGE_TEXT, m_Text, MAX_PATH);
505 SaveSettings();
506 EndDialog(hwnd, IDOK);
507 break;
508
509 case IDCANCEL:
510 EndDialog(hwnd, IDCANCEL);
511 break;
512 }
513 return FALSE;
514
515 case WM_CLOSE:
516 EndDialog(hwnd, 0);
517 break;
518
519 default:
520 return FALSE;
521 }
522
523 return TRUE;
524 }
525
526 VOID Configure(VOID)
527 {
528 DialogBox(hInstance, MAKEINTRESOURCE(IDD_CONFIG), NULL , (DLGPROC)ConfigDlgProc);
529 }
530
531 INT CALLBACK
532 _tWinMain(HINSTANCE hInst,
533 HINSTANCE hPrev,
534 LPTSTR lpCmdLine,
535 INT iCmdShow)
536 {
537 HWND hwndParent = 0;
538 UCHAR chOption;
539 MSG Message;
540
541 hInstance = hInst;
542
543 ParseCommandLine(lpCmdLine, &chOption, &hwndParent);
544
545 LoadSettings();
546
547 switch (chOption)
548 {
549 case _T('s'):
550 InitSaver(0);
551 break;
552
553 case _T('p'):
554 InitSaver(hwndParent);
555 break;
556
557 case _T('c'):
558 default:
559 Configure();
560 return 0;
561 }
562
563 while (GetMessage(&Message, 0, 0, 0))
564 DispatchMessage(&Message);
565
566 return Message.wParam;
567 }
568