[PSDK]
[reactos.git] / rosapps / applications / screensavers / matrix / message.c
1 //
2 // message.c
3 //
4 // Dissolve in/out messages into the "matrix"
5 //
6 //
7 //
8 #include <windows.h>
9 #include "globals.h"
10 #include "message.h"
11 #include "matrix.h"
12
13 //
14 // this isn't really a random-number generator. It's based on
15 // a 16bit CRC algorithm. With the right mask (0xb400) it is possible
16 // to call this function 65536 times and get a unique result every time
17 // with *NO* repeats. The results look random but they're not - if we
18 // call this function another 65536 times we get exactly the same results
19 // in the same order. This is necessary for fading in messages because
20 // we need to be guaranteed that all cells...it's completely uniform in
21 // operation but looks random enough to be very effective
22 //
23 WORD crc_msgrand(WORD reg)
24 {
25 const WORD mask = 0xb400;
26
27 if(reg & 1)
28 reg = (reg >> 1) ^ mask;
29 else
30 reg = (reg >> 1);
31
32 return reg;
33 }
34
35 //
36 // Set a new message based on font and text
37 //
38 void SetMatrixMessage(MATRIX_MESSAGE *msg, HFONT hFont, TCHAR *text)
39 {
40 HDC hdc;
41 RECT rect;
42 int x, y;
43
44 HDC hdcMessage;
45 HBITMAP hbmMessage;
46
47 HANDLE hOldFont, hOldBmp;
48
49 //
50 // Create a monochrome off-screen buffer
51 //
52 hdc = GetDC(NULL);
53
54 hdcMessage = CreateCompatibleDC(hdc);
55 hbmMessage = CreateBitmap(MAXMSG_WIDTH, MAXMSG_HEIGHT, 1, 1, 0);
56 hOldBmp = SelectObject(hdcMessage, hbmMessage);
57
58 ReleaseDC(NULL, hdc);
59
60 //
61 // Draw text into bitmap
62 //
63 SetRect(&rect, 0, 0, msg->width, MAXMSG_HEIGHT);
64 FillRect(hdcMessage, &rect, GetStockObject(WHITE_BRUSH));
65
66 hOldFont = SelectObject(hdcMessage, g_hFont);
67 DrawText(hdcMessage, text, -1, &rect, DT_CENTER|DT_VCENTER|DT_WORDBREAK|DT_CALCRECT);
68
69 OffsetRect(&rect, (msg->width-(rect.right-rect.left))/2, (msg->height-(rect.bottom-rect.top))/2);
70 DrawText(hdcMessage, text, -1, &rect, DT_CENTER|DT_VCENTER|DT_WORDBREAK);
71
72 //
73 // Convert bitmap into an array of cells for easy drawing
74 //
75 for(y = 0; y < msg->height; y++)
76 {
77 for(x = 0; x < msg->width; x++)
78 {
79 msg->message[x][y] = GetPixel(hdcMessage, x, y) ? 0 : 1;
80 }
81 }
82
83 //
84 // Cleanup
85 //
86 SelectObject(hdcMessage, hOldFont);
87 SelectObject(hdcMessage, hOldBmp);
88
89 DeleteDC(hdcMessage);
90 DeleteObject(hbmMessage);
91 }
92
93 //
94 // Draw any part of the message that is visible. Make the
95 // message "shimmer" by using a random glyph each time
96 //
97 void DrawMatrixMessage(MATRIX *matrix, MATRIX_MESSAGE *msg, HDC hdc)
98 {
99 int x, y;
100
101 for(x = 0; x < msg->width; x++)
102 for(y = 0; y < msg->height; y++)
103 if((msg->message[x][y] & 0x8000) &&
104 (msg->message[x][y] & 0x00FF))
105 {
106 DrawGlyph(matrix, hdc, x * GLYPH_WIDTH, y * GLYPH_HEIGHT, RandomGlyph(MAX_INTENSITY));
107 }
108 }
109
110 //
111 // Reveal specified amount of message
112 //
113 void RevealMatrixMessage(MATRIX_MESSAGE *msg, int amount)
114 {
115 while(amount--)
116 {
117 int pos;
118
119 msg->random_reg1 = crc_msgrand(msg->random_reg1);
120 pos = msg->random_reg1 & 0xffff;
121
122 msg->message[pos / 256][pos % 256] |= GLYPH_REDRAW;
123 }
124 }
125
126 //
127 // Reset (hide) the message
128 //
129 void ClearMatrixMessage(MATRIX_MESSAGE *msg)
130 {
131 int x, y;
132
133 for(x = 0; x < msg->width; x++)
134 for(y = 0; y < msg->height; y++)
135 msg->message[x][y] = 0;
136 }
137
138 //
139 // convert from 50-500 (fast-slow) to slow(50) - fast(500)
140 //
141 int MessageSpeed()
142 {
143 return (MSGSPEED_MAX-MSGSPEED_MIN) - (g_nMessageSpeed-MSGSPEED_MIN) + MSGSPEED_MIN;
144 }
145
146 //
147 // Called once for each iteration of the matrix
148 //
149 void DoMatrixMessage(HDC hdc, MATRIX *matrix)
150 {
151 MATRIX_MESSAGE *msg = matrix->message;
152
153 int RealSpeed = MessageSpeed();
154
155 if(g_nNumMessages > 0)
156 {
157 // nothing to do yet..
158 if(msg->counter++ < 0)
159 return;
160
161 // has counter reached limit..clear the message
162 if(msg->counter++ == RealSpeed / 2 + (RealSpeed/4))
163 ClearMatrixMessage(msg);
164
165 // reset counter + display a new message
166 if(msg->counter >= RealSpeed)
167 {
168 // mark all message-cells as being "invisible" so the
169 // message gets cleared by the matrix decoding naturally
170
171 if(g_fRandomizeMessages)
172 msg->msgindex = crc_rand() % g_nNumMessages;
173 else
174 msg->msgindex = (msg->msgindex + 1) % g_nNumMessages;
175
176 // make a new message..initially invisible
177 SetMatrixMessage(msg, 0, g_szMessages[msg->msgindex]);
178
179 msg->counter = -(int)(crc_rand() % MSGSPEED_MAX);
180 }
181 // reveal the next part of the message
182 else if(msg->counter < RealSpeed / 2)
183 {
184 int w = (g_nMessageSpeed - MSGSPEED_MIN);
185 w = (1 << 16) + ((w<<16) / MSGSPEED_MAX);
186 w = (w * 3 * g_nMessageSpeed) >> 16;
187
188 RevealMatrixMessage(msg, w + 100);
189 }
190
191 //
192 // draw whatever part of the message is visible at this time
193 //
194 DrawMatrixMessage(matrix, msg, hdc);
195 }
196 }
197
198 //
199 // Set current font used for messages
200 //
201 void SetMessageFont(HWND hwnd, TCHAR *szFontName, int nPointSize, BOOL fBold)
202 {
203 int lfHeight;
204 HDC hdc;
205 HFONT hFont;
206
207 hdc = GetDC(hwnd);
208
209 lfHeight = -MulDiv(nPointSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
210
211 ReleaseDC(hwnd, hdc);
212
213 hFont = CreateFont(lfHeight, 0, 0, 0, fBold ? FW_BOLD: FW_NORMAL, 0, 0, 0,
214 ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
215 ANTIALIASED_QUALITY, DEFAULT_PITCH, szFontName);
216
217 if(hFont != 0)
218 {
219 if(g_hFont != 0)
220 DeleteObject(g_hFont);
221
222 g_hFont = hFont;
223 }
224 }
225
226 //
227 // Create a message!
228 //
229 MATRIX_MESSAGE *InitMatrixMessage(HWND hwnd, int width, int height)
230 {
231 MATRIX_MESSAGE *msg;
232
233 if((msg = malloc(sizeof(MATRIX_MESSAGE))) == 0)
234 return 0;
235
236 ClearMatrixMessage(msg);
237
238 msg->msgindex = 0;
239 msg->width = min(width, MAXMSG_WIDTH);
240 msg->height = min(height, MAXMSG_HEIGHT);
241 msg->counter = -(int)(crc_rand() % MSGSPEED_MIN + MSGSPEED_MIN);
242
243 msg->random_reg1 = (WORD)GetTickCount();
244
245 SetMessageFont(hwnd, g_szFontName, g_nFontSize, g_fFontBold);
246
247 SetMatrixMessage(msg, 0, g_szMessages[0]);
248
249 return msg;
250 }