1 /*
2  *  Copyright 2003 J Brown
3  *  Copyright 2006 Andrey Korotaev <unC0Rr@inbox.ru>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18  */
19 
20 #include <windows.h>
21 #include <GL/gl.h>
22 #include <GL/glu.h>
23 #include <tchar.h>
24 #include <scrnsave.h>
25 #include "resource.h"
26 
27 #define APPNAME _T("Cylfrac")
28 #define wfactor 0.9
29 #define rotfactor 1.5
30 #define FPS 100
31 #define timerdelay 1000/FPS
32 
33 POINT initpoint;
34 HDC dc;
35 HGLRC hrc;
36 DWORD oldticks;
37 MMRESULT TimerID;
38 
39 DWORD lvls = 7;
40 int cylquality = 8;
41 
42 HINSTANCE hInstance;
43 
44 GLUquadricObj * cylinder;
45 
46 float angle = 0;
47 float colorh = 0.0;
48 float rval, gval, bval;
49 
50 BOOL fullscreen = FALSE;
51 
52 float _RGB(float H, float M1, float M2)
53 {
54     if(H < 0.0) H += 360.0;
55         else if(H > 360.0) H -= 360.0;
56     if(H < 60) return M1 + (M2 - M1) * H / 60.0;
57     if((H >= 60 )&&(H < 180)) return M2;
58     if((H >= 180)&&(H < 240)) return M1 + (M2 - M1)*(240 - H) / 60.0;
59     return M1;
60 }
61 
62 void HLStoRGB(float H, float L, float S,
63               float* R, float* G, float* B)
64 {
65     float M1, M2;
66     if(S <= 0.5) M2 = S * (1 + L);
67         else M2 = S * (1 - L) + L;
68     M1 = 2 * S - M2;
69     if (L == 0.0)
70     {
71         *R = S;
72         *G = S;
73         *B = S;
74     } else {
75         *R = _RGB(H + 120.0, M1, M2);
76         *G = _RGB(H        , M1, M2);
77         *B = _RGB(H - 120.0, M1, M2);
78     }
79 }
80 
81 void DrawCylinder(int n, float rota, float width)
82 {
83     glPushMatrix();
84     glColor3f(rval/n, gval/n, bval/n);
85     glRotatef(rota, 0.0, 1.0, 0.0);
86     gluCylinder(cylinder, width, width * wfactor, n * 0.5, cylquality, 1);
87     glTranslatef(0.0, 0.0, -n * 0.5);
88     gluCylinder(cylinder, width * wfactor, width, n * 0.5, cylquality, 1);
89     if(n > 1)
90     {
91         float r = rota * rotfactor;
92         glRotatef(90.0, 1.0, 0.0, 0.0);
93         DrawCylinder(n - 1,  r, width * wfactor);
94         glTranslatef(0.0, n, 0.0);
95         DrawCylinder(n - 1, -r, width * wfactor);
96     }
97     glPopMatrix();
98 }
99 
100 void DrawScene(HWND hwnd, HDC dc, int ticks)
101 {
102     PAINTSTRUCT ps;
103     dc = BeginPaint(hwnd, &ps);
104     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
105     glRotatef(ticks * 0.01, 0.0, 1.0, -0.5);
106     angle += ticks * 0.01;
107     colorh += ticks * 0.003;
108     if (colorh > 360.0) colorh -= 360.0;
109     HLStoRGB(colorh, 1.0f, 0.7f, &rval, &gval, &bval);
110     DrawCylinder(lvls, angle, 0.2f);
111     SwapBuffers(dc);
112     EndPaint(hwnd, &ps);
113 }
114 
115 void CALLBACK TimeProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
116 {
117     InvalidateRect((HWND)dwUser, NULL, 0);
118 }
119 
120 void MyPixelFormat(HDC dc)
121 {
122     int npf;
123     PIXELFORMATDESCRIPTOR pfd;
124 
125     ZeroMemory(&pfd, sizeof(pfd));
126     pfd.nSize = sizeof(pfd);
127     pfd.nVersion = 1;
128     pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
129 
130     npf = ChoosePixelFormat(dc, &pfd);
131     if(npf != 0)
132         SetPixelFormat(dc, npf, &pfd);
133 }
134 
135 void InitGL(HWND hwnd)
136 {
137     GLfloat lightpos[4] = {2.0f, 2.0f, -2.0f, 0.7f};
138     GLfloat ca = 1.0;
139     dc = GetDC(hwnd);
140     MyPixelFormat(dc);
141     hrc = wglCreateContext(dc);
142     wglMakeCurrent(dc, hrc);
143     cylinder = gluNewQuadric();
144     glEnable(GL_DEPTH_TEST);
145     glEnable(GL_LIGHT0);
146     glLightfv(GL_LIGHT0,  GL_POSITION, (GLfloat *)&lightpos);
147     glLightfv(GL_LIGHT0,  GL_LINEAR_ATTENUATION, &ca);
148     glEnable(GL_LIGHTING);
149     glEnable(GL_COLOR_MATERIAL);
150 }
151 
152 LRESULT WINAPI ScreenSaverProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
153 {
154     switch(msg) {
155         case WM_CREATE:
156         {
157             GetCursorPos(&initpoint);
158             InitGL(hwnd);
159             oldticks = GetTickCount();
160             TimerID = timeSetEvent(timerdelay, 0, TimeProc, (DWORD_PTR)hwnd, TIME_PERIODIC);
161         }
162         break;
163         case WM_PAINT:
164         {
165             DWORD ticks = oldticks;
166             POINT currpoint;
167             oldticks = GetTickCount();
168             DrawScene(hwnd, dc, oldticks - ticks);
169             if(fullscreen)
170             {
171                 GetCursorPos(&currpoint);
172                 if(abs(currpoint.x - initpoint.x) + (abs(currpoint.y - initpoint.y)) > 10)
173                     PostMessage(hwnd, WM_CLOSE, 0, 0);
174             }
175         }
176         break;
177         case WM_DESTROY:
178         {
179             timeKillEvent(TimerID);
180             gluDeleteQuadric(cylinder);
181             wglMakeCurrent(0, 0);
182             wglDeleteContext(hrc);
183             ReleaseDC(hwnd, dc);
184             DeleteDC(dc);
185             if (fullscreen)
186                 ShowCursor(TRUE);
187             PostQuitMessage(0);
188         }
189         break;
190         case WM_SIZE:
191         {
192             int width = LOWORD(lParam);
193             int height = HIWORD(lParam);
194             float fscale;
195             glViewport(0, 0, width, height);
196             glMatrixMode(GL_MODELVIEW);
197             glLoadIdentity();
198             fscale = 0.8/(float)lvls;
199             glScalef(fscale, fscale, fscale);
200         }
201         break;
202         default:
203             return DefScreenSaverProc(hwnd, msg, wParam, lParam);
204     }
205     return 0;
206 }
207 
208 BOOL WINAPI ScreenSaverConfigureDialog(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
209 {
210     return FALSE;
211 }
212 
213 BOOL WINAPI RegisterDialogClasses(HANDLE hmodule)
214 {
215     TCHAR szTitle[256];
216     TCHAR szText[256];
217 
218     LoadString(hmodule,
219             IDS_TITLE,
220             szTitle,
221             256);
222 
223     LoadString(hmodule,
224             IDS_TEXT,
225             szText,
226             256);
227 
228     MessageBox(0,
229             szText,
230             szTitle,
231             MB_OK | MB_ICONWARNING);
232     return FALSE;
233 }
234