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 } 251