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