// // message.c // // Dissolve in/out messages into the "matrix" // // // #include #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; }