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
BuildFont(GLvoid)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
KillFont(GLvoid)111 GLvoid KillFont(GLvoid)
112 {
113 // Delete all 256 characters
114 glDeleteLists(base, 256);
115 }
116
117 // Custom GL "Print" Routine
glPrint(LPTSTR text)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
InitGL(GLsizei Width,GLsizei Height)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
ReSizeGLScene(GLsizei Width,GLsizei Height)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
DrawGLScene(GLvoid)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
ScreenSaverProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)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 //
ScreenSaverConfigureDialog(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)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
RegisterDialogClasses(HANDLE hInst)432 BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
433 {
434 return TRUE;
435 }
436