4 // Matrix-window implementation
14 void DoMatrixMessage(HDC hdc
, MATRIX
*matrix
);
16 // pseudo-random number generator, based on 16bit CRC algorithm
17 static WORD _crc_reg
= 0;
20 const WORD mask
= 0xb400;
23 _crc_reg
= (_crc_reg
>> 1) ^ mask
;
25 _crc_reg
= (_crc_reg
>> 1);
30 int GlyphIntensity(GLYPH glyph
)
32 return (int)((glyph
& 0x7f00) >> 8);
35 GLYPH
DarkenGlyph(GLYPH glyph
)
37 int intensity
= GlyphIntensity(glyph
);
40 return GLYPH_REDRAW
| ((intensity
- 1) << 8) | (glyph
& 0x00FF);
45 GLYPH
RandomGlyph(int intensity
)
47 return GLYPH_REDRAW
| (intensity
<< 8) | (crc_rand() % NUM_GLYPHS
);
50 void RedrawBlip(GLYPH
*glypharr
, int blippos
)
52 glypharr
[blippos
+0] |= GLYPH_REDRAW
;
53 glypharr
[blippos
+1] |= GLYPH_REDRAW
;
54 glypharr
[blippos
+8] |= GLYPH_REDRAW
;
55 glypharr
[blippos
+9] |= GLYPH_REDRAW
;
58 void ScrollMatrixColumn(MATRIX_COLUMN
*col
)
64 // wait until we are allowed to scroll
65 if(col
->started
== FALSE
)
67 if(--col
->countdown
<= 0)
73 // "seed" the glyph-run
74 lastglyph
= col
->state
? (GLYPH
)0 : (GLYPH
)(MAX_INTENSITY
<< 8);
77 // loop over the entire length of the column, looking for changes
78 // in intensity/darkness. This change signifies the start/end
79 // of a run of glyphs.
81 for(y
= 0; y
< col
->length
; y
++)
83 thisglyph
= col
->glyph
[y
];
85 // bottom-most part of "run". Insert a new character (glyph)
86 // at the end to lengthen the run down the screen..gives the
87 // impression that the run is "falling" down the screen
88 if(GlyphIntensity(thisglyph
) < GlyphIntensity(lastglyph
) &&
89 GlyphIntensity(thisglyph
) == 0)
91 col
->glyph
[y
] = RandomGlyph(MAX_INTENSITY
- 1);
94 // top-most part of "run". Delete a character off the top by
95 // darkening the glyph until it eventually disappears (turns black).
96 // this gives the effect that the run as dropped downwards
97 else if(GlyphIntensity(thisglyph
) > GlyphIntensity(lastglyph
))
99 col
->glyph
[y
] = DarkenGlyph(thisglyph
);
101 // if we've just darkened the last bit, skip on so
102 // the whole run doesn't go dark
103 if(GlyphIntensity(thisglyph
) == MAX_INTENSITY
- 1)
107 lastglyph
= col
->glyph
[y
];
110 // change state from blanks <-> runs when the current run as expired
111 if(--col
->runlen
<= 0)
114 col
->runlen
= crc_rand() % (3 * DENSITY
/2) + DENSITY_MIN
;
116 col
->runlen
= crc_rand() % (DENSITY_MAX
+1-DENSITY
) + (DENSITY_MIN
*2);
120 // make a "blip" run down this column at double-speed
123 // mark current blip as redraw so it gets "erased"
124 if(col
->blippos
>= 0 && col
->blippos
< col
->length
)
125 RedrawBlip(col
->glyph
, col
->blippos
);
127 // advance down screen at double-speed
130 // if the blip gets to the end of a run, start it again (for a random
131 // length so that the blips never get synched together)
132 if(col
->blippos
>= col
->bliplen
)
134 col
->bliplen
= col
->length
+ crc_rand() % 50;
138 // now redraw blip at new position
139 if(col
->blippos
>= 0 && col
->blippos
< col
->length
)
140 RedrawBlip(col
->glyph
, col
->blippos
);
145 // randomly change a small collection glyphs in a column
147 void RandomMatrixColumn(MATRIX_COLUMN
*col
)
151 for(i
= 1, y
= 0; i
< 16; i
++)
154 while(GlyphIntensity(col
->glyph
[y
]) < MAX_INTENSITY
-1 && y
< col
->length
)
160 col
->glyph
[y
] = (col
->glyph
[y
] & 0xff00) | (crc_rand() % NUM_GLYPHS
);
161 col
->glyph
[y
] |= GLYPH_REDRAW
;
163 y
+= crc_rand() % 10;
167 void DrawGlyph(MATRIX
*matrix
, HDC hdc
, int xpos
, int ypos
, GLYPH glyph
)
169 int intensity
= GlyphIntensity(glyph
);
170 int glyphidx
= glyph
& 0xff;
172 BitBlt(hdc
, xpos
, ypos
, GLYPH_WIDTH
, GLYPH_HEIGHT
, matrix
->hdcBitmap
,
173 glyphidx
* GLYPH_WIDTH
, intensity
* GLYPH_HEIGHT
, SRCCOPY
);
176 void RedrawMatrixColumn(MATRIX_COLUMN
*col
, MATRIX
*matrix
, HDC hdc
, int xpos
)
180 // loop down the length of the column redrawing only what needs doing
181 for(y
= 0; y
< col
->length
; y
++)
183 GLYPH glyph
= col
->glyph
[y
];
185 // does this glyph (character) need to be redrawn?
186 if(glyph
& GLYPH_REDRAW
)
188 if((y
== col
->blippos
+0 || y
== col
->blippos
+1 ||
189 y
== col
->blippos
+8 || y
== col
->blippos
+9) &&
190 GlyphIntensity(glyph
) >= MAX_INTENSITY
-1)
191 glyph
|= MAX_INTENSITY
<< 8;
193 DrawGlyph(matrix
, hdc
, xpos
, y
* GLYPH_HEIGHT
, glyph
);
195 // clear redraw state
196 col
->glyph
[y
] &= ~GLYPH_REDRAW
;
201 void DecodeMatrix(HWND hwnd
, MATRIX
*matrix
)
204 HDC hdc
= GetDC(hwnd
);
206 for(x
= 0; x
< matrix
->numcols
; x
++)
208 RandomMatrixColumn(&matrix
->column
[x
]);
209 ScrollMatrixColumn(&matrix
->column
[x
]);
210 RedrawMatrixColumn(&matrix
->column
[x
], matrix
, hdc
, x
* GLYPH_WIDTH
);
214 DoMatrixMessage(hdc
, matrix
);
216 ReleaseDC(hwnd
, hdc
);
220 // Allocate matrix structures
222 MATRIX
*CreateMatrix(HWND hwnd
, int width
, int height
)
228 int rows
= height
/ GLYPH_HEIGHT
+ 1;
229 int cols
= width
/ GLYPH_WIDTH
+ 1;
232 if((matrix
= malloc(sizeof(MATRIX
) + sizeof(MATRIX_COLUMN
) * cols
)) == 0)
235 matrix
->numcols
= cols
;
236 matrix
->numrows
= rows
;
237 matrix
->width
= width
;
238 matrix
->height
= height
;
240 for(x
= 0; x
< cols
; x
++)
242 matrix
->column
[x
].length
= rows
;
243 matrix
->column
[x
].started
= FALSE
;
244 matrix
->column
[x
].countdown
= crc_rand() % 100;
245 matrix
->column
[x
].state
= crc_rand() % 2;
246 matrix
->column
[x
].runlen
= crc_rand() % 20 + 3;
248 matrix
->column
[x
].glyph
= malloc(sizeof(GLYPH
) * (rows
+16));
250 for(y
= 0; y
< rows
; y
++)
251 matrix
->column
[x
].glyph
[y
] = 0;//;
256 matrix
->hbmBitmap
= LoadBitmap(GetModuleHandle(0), MAKEINTRESOURCE(IDB_BITMAP1
));
257 matrix
->hdcBitmap
= CreateCompatibleDC(hdc
);
258 SelectObject(matrix
->hdcBitmap
, matrix
->hbmBitmap
);
259 ReleaseDC(NULL
, hdc
);
261 // Create a message for this window...only if we are
262 // screen-saving (not if in preview mode)
263 if(GetParent(hwnd
) == 0)
264 matrix
->message
= InitMatrixMessage(hwnd
, matrix
->numcols
, matrix
->numrows
);
272 // Free up matrix structures
274 void DestroyMatrix(MATRIX
*matrix
)
278 // free the matrix columns
279 for(x
= 0; x
< matrix
->numcols
; x
++)
280 free(matrix
->column
[x
].glyph
);
282 DeleteDC(matrix
->hdcBitmap
);
283 DeleteObject(matrix
->hbmBitmap
);
285 // now delete the matrix!
289 MATRIX
*GetMatrix(HWND hwnd
)
291 return (MATRIX
*)GetWindowLongPtr(hwnd
, GWLP_USERDATA
);
294 void SetMatrix(HWND hwnd
, MATRIX
*matrix
)
296 SetWindowLongPtr(hwnd
, GWLP_USERDATA
, (LONG_PTR
)matrix
);
300 // Window procedure for one matrix (1 per screen)
302 LRESULT WINAPI
MatrixWndProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
305 static POINT ptCursor
;
306 static BOOL fFirstTime
= TRUE
;
308 MATRIX
*matrix
= GetMatrix(hwnd
);
315 // create the matrix based on how big this window is
316 matrix
= CreateMatrix(hwnd
, ((CREATESTRUCT
*)lParam
)->cx
, ((CREATESTRUCT
*)lParam
)->cy
);
318 // failed to allocate? stop window creation!
322 SetMatrix(hwnd
, matrix
);
324 // start off an animation timer
325 SetTimer(hwnd
, 0xdeadbeef, ((SPEED_MAX
- g_nMatrixSpeed
) + SPEED_MIN
) * 10, 0);
329 // window being destroyed, cleanup
331 DestroyMatrix(matrix
);
335 // animation timer has gone off, redraw the matrix!
337 DecodeMatrix(hwnd
, matrix
);
340 // break out of screen-saver if any keyboard activity
343 PostMessage(hwnd
, WM_CLOSE
, 0, 0);
346 // break out of screen-saver if any mouse activity
355 // If we've got a parent then we must be a preview
356 if(GetParent(hwnd
) != 0)
361 GetCursorPos(&ptLast
);
365 GetCursorPos(&ptCursor
);
367 // if the mouse has moved more than 3 pixels then exit
368 if(abs(ptCursor
.x
- ptLast
.x
) >= 3 || abs(ptCursor
.y
- ptLast
.y
) >= 3)
369 PostMessage(hwnd
, WM_CLOSE
, 0, 0);
375 // someone wants to close us...see if it's ok
378 if(VerifyPassword(hwnd
))
380 KillTimer(hwnd
, 0xdeadbeef);
387 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
390 HWND
CreateScreenSaveWnd(HWND hwndParent
, RECT
*rect
)
392 DWORD dwStyle
= hwndParent
? WS_CHILD
: WS_POPUP
;
397 DWORD dwStyleEx
= WS_EX_TOPMOST
;
401 GetClientRect(hwndParent
, rect
);
403 return CreateWindowEx( dwStyleEx
,
406 WS_VISIBLE
| dwStyle
,
409 rect
->right
- rect
->left
,
410 rect
->bottom
- rect
->top
,
419 // Initialize class for matrix window
421 void InitScreenSaveClass(BOOL fPreview
)
425 wcx
.cbSize
= sizeof(WNDCLASSEX
);
427 wcx
.lpfnWndProc
= MatrixWndProc
;
429 wcx
.cbWndExtra
= sizeof(MATRIX
*);
430 wcx
.hInstance
= GetModuleHandle(0);
432 wcx
.hbrBackground
= (HBRUSH
)GetStockObject(BLACK_BRUSH
);
433 wcx
.lpszMenuName
= 0;
434 wcx
.lpszClassName
= APPNAME
;
438 wcx
.hCursor
= LoadCursor(0, IDC_ARROW
);
440 wcx
.hCursor
= LoadCursor(wcx
.hInstance
, MAKEINTRESOURCE(IDC_BLANKCURSOR
));
442 // initialize the crc register used for "random" number generation
443 _crc_reg
= (WORD
)GetTickCount();
445 RegisterClassEx(&wcx
);