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 along
17  *  with this program; if not, write to the Free Software Foundation, Inc.,
18  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include "3dtext.h"
22 
23 #include <winbase.h>
24 #include <wingdi.h>
25 #include <winuser.h>
26 #include <scrnsave.h>
27 #include <math.h>
28 #include <GL/glu.h>
29 
30 #include "resource.h"
31 
32 static HGLRC hRC;       // Permanent Rendering Context
33 static HDC hDC;         // Private GDI Device Context
34 
35 GLuint base;            // Base Display List For The Font Set
36 GLfloat rot;            // Used To Rotate The Text
37 GLfloat extentX = 0.0f;
38 GLfloat extentY = 0.0f;
39 
40 #define APPNAME _T("3DText")
41 
42 HINSTANCE hInstance;
43 BOOL fullscreen = FALSE;
44 UINT uTimerID;                                          // SetTimer Actual ID
45 #define APP_TIMER             1                         // Graphics Update Timer ID
46 #define APP_TIMER_INTERVAL    (USER_TIMER_MINIMUM * 5)  // Graphics Update Interval
47 
48 // Build Our Bitmap Font
49 GLvoid BuildFont(GLvoid)
50 {
51     // Address Buffer For Font Storage
52     GLYPHMETRICSFLOAT gmf[256];
53     // Windows Font Handle
54     HFONT font;
55     size_t i;
56     TCHAR c;
57     GLfloat cellOriginX = 0.0f;
58     GLfloat stringOriginX;
59     GLfloat stringExtentX = 0.0f;
60     GLfloat stringExtentY = 0.0f;
61 
62     // Storage For 256 Characters
63     base = glGenLists(256);
64 
65     font = CreateFont(-12,
66                       0,                            // Width Of Font
67                       0,                            // Angle Of Escapement
68                       0,                            // Orientation Angle
69                       FW_BOLD,                      // Font Weight
70                       FALSE,                        // Italic
71                       FALSE,                        // Underline
72                       FALSE,                        // Strikeout
73                       DEFAULT_CHARSET,              // Character Set Identifier
74                       OUT_TT_PRECIS,                // Output Precision
75                       CLIP_DEFAULT_PRECIS,          // Clipping Precision
76                       ANTIALIASED_QUALITY,          // Output Quality
77                       FF_DONTCARE|DEFAULT_PITCH,    // Family And Pitch
78                       _T("Tahoma"));                // Font Name
79 
80     // Selects The Font We Created
81     SelectObject(hDC, font);
82 
83     wglUseFontOutlines(hDC,                     // Select The Current DC
84                        0,                       // Starting Character
85                        255,                     // Number Of Display Lists To Build
86                        base,                    // Starting Display Lists
87                        0.0f,                    // Deviation From The True Outlines
88                        0.2f,                    // Font Thickness In The Z Direction
89                        WGL_FONT_POLYGONS,       // Use Polygons, Not Lines
90                        gmf);                    // Address Of Buffer To Receive Data
91 
92     // Calculate the string extent
93     for (i = 0; i < _tcslen(m_Text); i++)
94     {
95         c = m_Text[i];
96 
97         stringOriginX = cellOriginX + gmf[c].gmfptGlyphOrigin.x;
98 
99         stringExtentX = stringOriginX + gmf[c].gmfBlackBoxX;
100         if (gmf[c].gmfBlackBoxY > stringExtentY)
101             stringExtentY = gmf[c].gmfBlackBoxY;
102 
103         cellOriginX = cellOriginX + gmf[c].gmfCellIncX;
104     }
105 
106     extentX = stringExtentX;
107     extentY = stringExtentY;
108 }
109 
110 // Delete The Font
111 GLvoid KillFont(GLvoid)
112 {
113     // Delete all 256 characters
114     glDeleteLists(base, 256);
115 }
116 
117 // Custom GL "Print" Routine
118 GLvoid glPrint(LPTSTR text)
119 {
120     // If there's no text, do nothing
121     if (text == NULL)
122         return;
123 
124     // Pushes The Display List Bits
125     glPushAttrib(GL_LIST_BIT);
126 
127     // Sets The Base Character to 32
128     glListBase(base);
129 
130     // Draws The Display List Text
131     glCallLists(_tcslen(text),
132 #ifdef UNICODE
133                 GL_UNSIGNED_SHORT,
134 #else
135                 GL_UNSIGNED_BYTE,
136 #endif
137                 text);
138 
139     // Pops The Display List Bits
140     glPopAttrib();
141 }
142 
143 // Will Be Called Right After The GL Window Is Created
144 GLvoid InitGL(GLsizei Width, GLsizei Height)
145 {
146     // Clear The Background Color To Black
147     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
148 
149     // Enables Clearing Of The Depth Buffer
150     glClearDepth(1.0);
151 
152     // The Type Of Depth Test To Do
153     glDepthFunc(GL_LESS);
154 
155     // Enables Depth Testing
156     glEnable(GL_DEPTH_TEST);
157 
158     // Enables Smooth Color Shading
159     glShadeModel(GL_SMOOTH);
160 
161     // Select The Projection Matrix
162     glMatrixMode(GL_PROJECTION);
163 
164     // Reset The Projection Matrix
165     glLoadIdentity();
166 
167     // Calculate The Aspect Ratio Of The Window
168     gluPerspective(45.0f, (GLfloat)Width / (GLfloat)Height, 0.1f, 100.0f);
169 
170     // Select The Modelview Matrix
171     glMatrixMode(GL_MODELVIEW);
172 
173     // Build The Font
174     BuildFont();
175 
176     // Enable Default Light (Quick And Dirty)
177     glEnable(GL_LIGHT0);
178 
179     // Enable Lighting
180     glEnable(GL_LIGHTING);
181 
182     // Enable Coloring Of Material
183     glEnable(GL_COLOR_MATERIAL);
184 }
185 
186 // Handles Window Resizing
187 GLvoid ReSizeGLScene(GLsizei Width, GLsizei Height)
188 {
189     // Is Window Too Small (Divide By Zero Error)
190     if (Height == 0)
191     {
192         // If So Make It One Pixel Tall
193         Height = 1;
194     }
195 
196     // Reset The Current Viewport And Perspective Transformation
197     glViewport(0, 0, Width, Height);
198 
199     // Select The Projection Matrix
200     glMatrixMode(GL_PROJECTION);
201 
202     // Reset The Projection Matrix
203     glLoadIdentity();
204 
205     // Calculate The Aspect Ratio Of The Window
206     gluPerspective(45.0f, (GLfloat)Width / (GLfloat)Height, 0.1f, 100.0f);
207 
208     // Select The Modelview Matrix
209     glMatrixMode(GL_MODELVIEW);
210 }
211 
212 // Handles Rendering
213 GLvoid DrawGLScene(GLvoid)
214 {
215     // Save ticks count of previous frame here
216     static DWORD dwTicks = 0;
217 
218     // Clear The Screen And The Depth Buffer
219     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
220 
221     // Reset The View
222     glLoadIdentity();
223 
224     // Move One Unit Into The Screen
225     glTranslatef(0.0f, 0.0f, -10.0f);
226 
227     // Rotate On The X Axis
228     glRotatef(rot, 1.0f, 0.0f, 0.0f);
229 
230     // Rotate On The Y Axis
231     glRotatef(rot * 1.2f, 0.0f, 1.0f, 0.0f);
232 
233     // Rotate On The Z Axis
234     glRotatef(rot * 1.4f, 0.0f, 0.0f, 1.0f);
235 
236     // Move to the Left and Down before drawing
237     glTranslatef(-(extentX / 2.0f),
238                  -(extentY / 2.0f),
239                  0.0f);
240 
241     // Pulsing Colors Based On The Rotation
242     glColor3f((1.0f * (GLfloat)(cos(rot / 20.0f))),
243               (1.0f * (GLfloat)(sin(rot / 25.0f))),
244               (1.0f - 0.5f * (GLfloat)(cos(rot / 17.0f))));
245 
246     // Print GL Text To The Screen
247     glPrint(m_Text);
248 
249     // Make The Text Blue
250     glColor3f(0.0f, 0.0f, 1.0f);
251 
252     // Increase The Rotation Variable
253     if(dwTicks)
254         rot += (GetTickCount() - dwTicks) / 20.0f;
255     dwTicks = GetTickCount();
256 }
257 
258 LRESULT CALLBACK
259 ScreenSaverProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
260 {
261     RECT Screen;                            // Used Later On To Get The Size Of The Window
262     GLuint PixelFormat;                     // Pixel Format Storage
263     static PIXELFORMATDESCRIPTOR pfd=       // Pixel Format Descriptor
264     {
265         sizeof(PIXELFORMATDESCRIPTOR),      // Size Of This Pixel Format Descriptor
266         1,                                  // Version Number (?)
267         PFD_DRAW_TO_WINDOW |                // Format Must Support Window
268         PFD_SUPPORT_OPENGL |                // Format Must Support OpenGL
269         PFD_DOUBLEBUFFER,                   // Must Support Double Buffering
270         PFD_TYPE_RGBA,                      // Request An RGBA Format
271         16,                                 // Select A 16Bit Color Depth
272         0, 0, 0, 0, 0, 0,                   // Color Bits Ignored (?)
273         0,                                  // No Alpha Buffer
274         0,                                  // Shift Bit Ignored (?)
275         0,                                  // No Accumulation Buffer
276         0, 0, 0, 0,                         // Accumulation Bits Ignored (?)
277         16,                                 // 16Bit Z-Buffer (Depth Buffer)
278         0,                                  // No Stencil Buffer
279         0,                                  // No Auxiliary Buffer (?)
280         PFD_MAIN_PLANE,                     // Main Drawing Layer
281         0,                                  // Reserved (?)
282         0, 0, 0                             // Layer Masks Ignored (?)
283     };
284 
285     switch (message)
286     {
287         case WM_CREATE:
288             LoadSettings();
289 
290             // Gets A Device Context For The Window
291             hDC = GetDC(hWnd);
292 
293             // Finds The Closest Match To The Pixel Format We Set Above
294             PixelFormat = ChoosePixelFormat(hDC, &pfd);
295 
296             // No Matching Pixel Format?
297             if (!PixelFormat)
298             {
299                 MessageBox(0, _TEXT("Can't Find A Suitable PixelFormat."), _TEXT("Error"),MB_OK | MB_ICONERROR);
300 
301                 // This Sends A 'Message' Telling The Program To Quit
302                 PostQuitMessage(0);
303                 break;
304             }
305 
306             // Can We Set The Pixel Mode?
307             if (!SetPixelFormat(hDC, PixelFormat, &pfd))
308             {
309                 MessageBox(0, _TEXT("Can't Set The PixelFormat."), _TEXT("Error"), MB_OK | MB_ICONERROR);
310 
311                 // This Sends A 'Message' Telling The Program To Quit
312                 PostQuitMessage(0);
313                 break;
314             }
315 
316             // Grab A Rendering Context
317             hRC = wglCreateContext(hDC);
318 
319             // Did We Get One?
320             if (!hRC)
321             {
322                 MessageBox(0, _TEXT("Can't Create A GL Rendering Context."), _TEXT("Error"), MB_OK | MB_ICONERROR);
323 
324                 // This Sends A 'Message' Telling The Program To Quit
325                 PostQuitMessage(0);
326                 break;
327             }
328 
329             // Can We Make The RC Active?
330             if (!wglMakeCurrent(hDC, hRC))
331             {
332                 MessageBox(0, _TEXT("Can't Activate GLRC."), _TEXT("Error"), MB_OK | MB_ICONERROR);
333 
334                 // This Sends A 'Message' Telling The Program To Quit
335                 PostQuitMessage(0);
336                 break;
337             }
338 
339             // Grab Screen Info For The Current Window
340             GetClientRect(hWnd, &Screen);
341 
342             // Initialize The GL Screen Using Screen Info
343             InitGL(Screen.right, Screen.bottom);
344 
345             // Create Graphics update timer
346             uTimerID = SetTimer(hWnd, APP_TIMER, APP_TIMER_INTERVAL, NULL);
347             break;
348 
349         case WM_DESTROY:
350             // Disable Fullscreen Mode
351             ChangeDisplaySettings(NULL, 0);
352 
353             // Delete the Update Timer
354             KillTimer(hWnd, uTimerID);
355 
356             // Deletes The Font Display List
357             KillFont();
358 
359             // Make The DC Current
360             wglMakeCurrent(hDC, NULL);
361 
362             // Kill The RC
363             wglDeleteContext(hRC);
364 
365             // Free The DC
366             ReleaseDC(hWnd, hDC);
367             break;
368 
369         case WM_PAINT:
370             DrawGLScene();
371             SwapBuffers(hDC);
372             // Mark this window as updated, so the OS won't ask us to update it again.
373             ValidateRect(hWnd, NULL);
374             break;
375 
376         case WM_SIZE: // Resizing The Screen
377             // Resize To The New Window Size
378             ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));
379             break;
380 
381         case WM_TIMER:
382             // Used to update graphic based on timer udpate interval
383             InvalidateRect(hWnd, NULL, TRUE);
384             break;
385 
386         default:
387             // Pass Windows Messages to the default screensaver window procedure
388             return DefScreenSaverProc(hWnd, message, wParam, lParam);
389     }
390 
391     return 0;
392 }
393 
394 //
395 // Dialogbox procedure for Configuration window
396 //
397 BOOL CALLBACK ScreenSaverConfigureDialog(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
398 {
399     switch (uMsg)
400     {
401         case WM_INITDIALOG:
402             LoadSettings();
403             SetDlgItemText(hDlg, IDC_MESSAGE_TEXT, m_Text);
404             return TRUE;
405 
406         case WM_COMMAND:
407             switch (LOWORD(wParam))
408             {
409                 case IDOK:
410                     GetDlgItemText(hDlg, IDC_MESSAGE_TEXT, m_Text, MAX_PATH);
411                     SaveSettings();
412 
413                     /* Fall through */
414 
415                 case IDCANCEL:
416                     EndDialog(hDlg, IDCANCEL);
417                     break;
418             }
419             return FALSE;
420 
421         case WM_CLOSE:
422             EndDialog(hDlg, 0);
423             break;
424 
425         default:
426             return FALSE;
427     }
428 
429     return TRUE;
430 }
431 
432 BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
433 {
434     return TRUE;
435 }
436