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