reactos/modules/rosapps/applications/screensavers/matrix/message.c

251 lines
5.5 KiB
C

//
// message.c
//
// Dissolve in/out messages into the "matrix"
//
//
//
#include <windows.h>
#include "globals.h"
#include "message.h"
#include "matrix.h"
//
// this isn't really a random-number generator. It's based on
// a 16bit CRC algorithm. With the right mask (0xb400) it is possible
// to call this function 65536 times and get a unique result every time
// with *NO* repeats. The results look random but they're not - if we
// call this function another 65536 times we get exactly the same results
// in the same order. This is necessary for fading in messages because
// we need to be guaranteed that all cells...it's completely uniform in
// operation but looks random enough to be very effective
//
WORD crc_msgrand(WORD reg)
{
const WORD mask = 0xb400;
if(reg & 1)
reg = (reg >> 1) ^ mask;
else
reg = (reg >> 1);
return reg;
}
//
// Set a new message based on font and text
//
void SetMatrixMessage(MATRIX_MESSAGE *msg, HFONT hFont, TCHAR *text)
{
HDC hdc;
RECT rect;
int x, y;
HDC hdcMessage;
HBITMAP hbmMessage;
HANDLE hOldFont, hOldBmp;
//
// Create a monochrome off-screen buffer
//
hdc = GetDC(NULL);
hdcMessage = CreateCompatibleDC(hdc);
hbmMessage = CreateBitmap(MAXMSG_WIDTH, MAXMSG_HEIGHT, 1, 1, 0);
hOldBmp = SelectObject(hdcMessage, hbmMessage);
ReleaseDC(NULL, hdc);
//
// Draw text into bitmap
//
SetRect(&rect, 0, 0, msg->width, MAXMSG_HEIGHT);
FillRect(hdcMessage, &rect, GetStockObject(WHITE_BRUSH));
hOldFont = SelectObject(hdcMessage, g_hFont);
DrawText(hdcMessage, text, -1, &rect, DT_CENTER|DT_VCENTER|DT_WORDBREAK|DT_CALCRECT);
OffsetRect(&rect, (msg->width-(rect.right-rect.left))/2, (msg->height-(rect.bottom-rect.top))/2);
DrawText(hdcMessage, text, -1, &rect, DT_CENTER|DT_VCENTER|DT_WORDBREAK);
//
// Convert bitmap into an array of cells for easy drawing
//
for(y = 0; y < msg->height; y++)
{
for(x = 0; x < msg->width; x++)
{
msg->message[x][y] = GetPixel(hdcMessage, x, y) ? 0 : 1;
}
}
//
// Cleanup
//
SelectObject(hdcMessage, hOldFont);
SelectObject(hdcMessage, hOldBmp);
DeleteDC(hdcMessage);
DeleteObject(hbmMessage);
}
//
// Draw any part of the message that is visible. Make the
// message "shimmer" by using a random glyph each time
//
void DrawMatrixMessage(MATRIX *matrix, MATRIX_MESSAGE *msg, HDC hdc)
{
int x, y;
for(x = 0; x < msg->width; x++)
for(y = 0; y < msg->height; y++)
if((msg->message[x][y] & 0x8000) &&
(msg->message[x][y] & 0x00FF))
{
DrawGlyph(matrix, hdc, x * GLYPH_WIDTH, y * GLYPH_HEIGHT, RandomGlyph(MAX_INTENSITY));
}
}
//
// Reveal specified amount of message
//
void RevealMatrixMessage(MATRIX_MESSAGE *msg, int amount)
{
while(amount--)
{
int pos;
msg->random_reg1 = crc_msgrand(msg->random_reg1);
pos = msg->random_reg1 & 0xffff;
msg->message[pos / 256][pos % 256] |= GLYPH_REDRAW;
}
}
//
// Reset (hide) the message
//
void ClearMatrixMessage(MATRIX_MESSAGE *msg)
{
int x, y;
for(x = 0; x < msg->width; x++)
for(y = 0; y < msg->height; y++)
msg->message[x][y] = 0;
}
//
// convert from 50-500 (fast-slow) to slow(50) - fast(500)
//
int MessageSpeed()
{
return (MSGSPEED_MAX-MSGSPEED_MIN) - (g_nMessageSpeed-MSGSPEED_MIN) + MSGSPEED_MIN;
}
//
// Called once for each iteration of the matrix
//
void DoMatrixMessage(HDC hdc, MATRIX *matrix)
{
MATRIX_MESSAGE *msg = matrix->message;
int RealSpeed = MessageSpeed();
if(g_nNumMessages > 0)
{
// nothing to do yet..
if(msg->counter++ < 0)
return;
// has counter reached limit..clear the message
if(msg->counter++ == RealSpeed / 2 + (RealSpeed/4))
ClearMatrixMessage(msg);
// reset counter + display a new message
if(msg->counter >= RealSpeed)
{
// mark all message-cells as being "invisible" so the
// message gets cleared by the matrix decoding naturally
if(g_fRandomizeMessages)
msg->msgindex = crc_rand() % g_nNumMessages;
else
msg->msgindex = (msg->msgindex + 1) % g_nNumMessages;
// make a new message..initially invisible
SetMatrixMessage(msg, 0, g_szMessages[msg->msgindex]);
msg->counter = -(int)(crc_rand() % MSGSPEED_MAX);
}
// reveal the next part of the message
else if(msg->counter < RealSpeed / 2)
{
int w = (g_nMessageSpeed - MSGSPEED_MIN);
w = (1 << 16) + ((w<<16) / MSGSPEED_MAX);
w = (w * 3 * g_nMessageSpeed) >> 16;
RevealMatrixMessage(msg, w + 100);
}
//
// draw whatever part of the message is visible at this time
//
DrawMatrixMessage(matrix, msg, hdc);
}
}
//
// Set current font used for messages
//
void SetMessageFont(HWND hwnd, TCHAR *szFontName, int nPointSize, BOOL fBold)
{
int lfHeight;
HDC hdc;
HFONT hFont;
hdc = GetDC(hwnd);
lfHeight = -MulDiv(nPointSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
ReleaseDC(hwnd, hdc);
hFont = CreateFont(lfHeight, 0, 0, 0, fBold ? FW_BOLD: FW_NORMAL, 0, 0, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
ANTIALIASED_QUALITY, DEFAULT_PITCH, szFontName);
if(hFont != 0)
{
if(g_hFont != 0)
DeleteObject(g_hFont);
g_hFont = hFont;
}
}
//
// Create a message!
//
MATRIX_MESSAGE *InitMatrixMessage(HWND hwnd, int width, int height)
{
MATRIX_MESSAGE *msg;
if((msg = malloc(sizeof(MATRIX_MESSAGE))) == 0)
return 0;
ClearMatrixMessage(msg);
msg->msgindex = 0;
msg->width = min(width, MAXMSG_WIDTH);
msg->height = min(height, MAXMSG_HEIGHT);
msg->counter = -(int)(crc_rand() % MSGSPEED_MIN + MSGSPEED_MIN);
msg->random_reg1 = (WORD)GetTickCount();
SetMessageFont(hwnd, g_szFontName, g_nFontSize, g_fFontBold);
SetMatrixMessage(msg, 0, g_szMessages[0]);
return msg;
}