#include #include "v_text.h" #include "i_system.h" #include "v_video.h" #include "hu_stuff.h" #include "w_wad.h" #include "z_zone.h" #include "m_swap.h" #include "doomstat.h" extern patch_t *hu_font[HU_FONTSIZE]; static byte *ConChars; byte *Ranges; // Convert the CONCHARS patch into the internal format used by // the console font drawer. void V_InitConChars (byte transcolor) { byte *d, *s, v, *src; patch_t *chars; int x, y, z, a; screen_t temp; temp.impdata = NULL; if (!V_AllocScreen (&temp, 128, 128, 8)) I_FatalError ("Could not create console characters"); V_LockScreen (&temp); chars = W_CacheLumpName ("CONCHARS", PU_CACHE); { long *scrn, fill; fill = (transcolor << 24) | (transcolor << 16) | (transcolor << 8) | transcolor; for (y = 0; y < 128; y++) { scrn = (long *)(temp.buffer + temp.pitch * y); for (x = 0; x < 128/4; x++) { *scrn++ = fill; } } V_DrawPatch (0, 0, &temp, chars); } src = temp.buffer; if ( (ConChars = Z_Malloc (256*8*8*2, PU_STATIC, 0)) ) { d = ConChars; for (y = 0; y < 16; y++) { for (x = 0; x < 16; x++) { s = src + x * 8 + (y * 8 * temp.pitch); for (z = 0; z < 8; z++) { for (a = 0; a < 8; a++) { v = s[a]; if (v == transcolor) { d[a] = 0x00; d[a+8] = 0xff; } else { d[a] = v; d[a+8] = 0x00; } } d += 16; s += temp.pitch; } } } } V_UnlockScreen (&temp); V_FreeScreen (&temp); } // // V_PrintStr // Print a line of text using the console font // extern void STACK_ARGS PrintChar1P (long *charimg, byte *dest, int screenpitch); extern void STACK_ARGS PrintChar2P_MMX (long *charimg, byte *dest, int screenpitch); void V_PrintStr (int x, int y, const byte *str, int count) { byte *temp; long *charimg; if (!screen.buffer) return; if (y > (screen.height - 8) || y<0) return; if (x < 0) { int skip; skip = -(x - 7) / 8; x += skip * 8; if (count <= skip) { return; } else { count -= skip; str += skip; } } x &= ~3; temp = screen.buffer + y * screen.pitch; while (count && x <= (screen.width - 8)) { charimg = (long *)&ConChars[(*str) * 128]; if (screen.is8bit) { #ifdef USEASM PrintChar1P (charimg, temp + x, screen.pitch); #else int z; long *writepos; writepos = (long *)(temp + x); for (z = 0; z < 8; z++) { *writepos = (*writepos & charimg[2]) ^ charimg[0]; writepos++; *writepos = (*writepos & charimg[3]) ^ charimg[1]; writepos += (screen.pitch >> 2) - 1; charimg += 4; } #endif } else { int z; int *writepos; writepos = (int *)(temp + (x << 2)); for (z = 0; z < 8; z++) { #define BYTEIMG ((byte *)charimg) #define SPOT(a) \ writepos[a] = (writepos[a] & \ ((BYTEIMG[a+8]<<16)|(BYTEIMG[a+8]<<8)|(BYTEIMG[a+8]))) \ ^ V_Palette[BYTEIMG[a]] SPOT(0); SPOT(1); SPOT(2); SPOT(3); SPOT(4); SPOT(5); SPOT(6); SPOT(7); #undef SPOT #undef BYTEIMG writepos += screen.pitch >> 2; charimg += 4; } } str++; count--; x += 8; } } // // V_PrintStr2 // Same as V_PrintStr but doubles the size of every character. // void V_PrintStr2 (int x, int y, const byte *str, int count) { byte *temp; long *charimg; if (y > (screen.height - 16)) return; if (x < 0) { int skip; skip = -(x - 15) / 16; x += skip * 16; if (count <= skip) { return; } else { count -= skip; str += skip; } } x &= ~3; temp = screen.buffer + y * screen.pitch; while (count && x <= (screen.width - 16)) { charimg = (long *)&ConChars[(*str) * 128]; #ifdef USEASM if (UseMMX) { PrintChar2P_MMX (charimg, temp + x, screen.pitch); } else #endif { int z; byte *buildmask, *buildbits, *image; unsigned int m1, s1; unsigned int *writepos; writepos = (unsigned int *)(temp + x); buildbits = (byte *)&s1; buildmask = (byte *)&m1; image = (byte *)charimg; for (z = 0; z < 8; z++) { buildmask[0] = buildmask[1] = image[8]; buildmask[2] = buildmask[3] = image[9]; buildbits[0] = buildbits[1] = image[0]; buildbits[2] = buildbits[3] = image[1]; writepos[0] = (writepos[0] & m1) ^ s1; writepos[screen.pitch/4] = (writepos[screen.pitch/4] & m1) ^ s1; buildmask[0] = buildmask[1] = image[10]; buildmask[2] = buildmask[3] = image[11]; buildbits[0] = buildbits[1] = image[2]; buildbits[2] = buildbits[3] = image[3]; writepos[1] = (writepos[1] & m1) ^ s1; writepos[1+screen.pitch/4] = (writepos[1+screen.pitch/4] & m1) ^ s1; buildmask[0] = buildmask[1] = image[12]; buildmask[2] = buildmask[3] = image[13]; buildbits[0] = buildbits[1] = image[4]; buildbits[2] = buildbits[3] = image[5]; writepos[2] = (writepos[2] & m1) ^ s1; writepos[2+screen.pitch/4] = (writepos[2+screen.pitch/4] & m1) ^ s1; buildmask[0] = buildmask[1] = image[14]; buildmask[2] = buildmask[3] = image[15]; buildbits[0] = buildbits[1] = image[6]; buildbits[2] = buildbits[3] = image[7]; writepos[3] = (writepos[3] & m1) ^ s1; writepos[3+screen.pitch/4] = (writepos[3+screen.pitch/4] & m1) ^ s1; writepos += screen.pitch >> 1; image += 16; } } str++; count--; x += 16; } #ifdef USEASM ENDMMX; #endif } // // V_DrawText // // Write a string using the hu_font // extern patch_t *hu_font[HU_FONTSIZE]; extern byte *Ranges; static void drawtext (int drawer, int normalcolor, int x, int y, const byte *string) { int w; const byte *ch; int c; int cx; int cy; int boldcolor; if (normalcolor > NUM_TEXT_COLORS) normalcolor = CR_RED; boldcolor = normalcolor ? normalcolor - 1 : NUM_TEXT_COLORS - 1; V_ColorMap = Ranges + normalcolor * 256; ch = string; cx = x; cy = y; while (1) { c = *ch++; if (!c) break; if (c == 0x8a) { int newcolor = toupper(*ch++); if (newcolor == 0) { return; } else if (newcolor == '-') { newcolor = normalcolor; } else if (newcolor >= 'A' && newcolor < 'A' + NUM_TEXT_COLORS) { newcolor -= 'A'; } else if (newcolor == '+') { newcolor = boldcolor; } else { continue; } V_ColorMap = Ranges + newcolor * 256; continue; } if (c == '\n') { cx = x; cy += 9; continue; } c = toupper(c) - HU_FONTSTART; if (c < 0 || c>= HU_FONTSIZE) { cx += 4; continue; } w = SHORT (hu_font[c]->width); if (cx+w > screen.width) break; V_DrawWrapper (drawer, cx, cy, &screen, hu_font[c]); cx+=w; } } static void drawscaledtext (int drawer, int normalcolor, int x, int y, const byte *string) { int w; const byte *ch; int c; int cx; int cy; int boldcolor; if (normalcolor > NUM_TEXT_COLORS) normalcolor = CR_RED; boldcolor = normalcolor ? normalcolor - 1 : NUM_TEXT_COLORS - 1; V_ColorMap = Ranges + normalcolor * 256; ch = string; cx = x; cy = y; while (1) { c = *ch++; if (!c) break; if (c == 0x8a) { int newcolor = toupper(*ch++); if (newcolor == 0) { return; } else if (newcolor == '-') { newcolor = normalcolor; } else if (newcolor >= 'A' && newcolor < 'A' + NUM_TEXT_COLORS) { newcolor -= 'A'; } else if (newcolor == '+') { newcolor = boldcolor; } else { continue; } V_ColorMap = Ranges + newcolor * 256; continue; } if (c == '\n') { cx = x; cy += 9 * CleanYfac; continue; } c = toupper(c) - HU_FONTSTART; if (c < 0 || c>= HU_FONTSIZE) { cx += 4 * CleanXfac; continue; } w = SHORT (hu_font[c]->width) * CleanXfac; if (cx+w > screen.width) break; V_DrawCNMWrapper (drawer, cx, cy, &screen, hu_font[c]); cx+=w; } } void V_DrawText (int normalcolor, int x, int y, const byte *string) { drawtext (V_DRAWTRANSLATEDPATCH, normalcolor, x, y, string); } void V_DrawTextLuc (int normalcolor, int x, int y, const byte *string) { drawtext (V_DRAWTLATEDLUCENTPATCH, normalcolor, x, y, string); } void V_DrawTextClean (int normalcolor, int x, int y, const byte *string) { drawscaledtext (V_DRAWTRANSLATEDPATCH, normalcolor, x, y, string); } void V_DrawTextCleanLuc (int normalcolor, int x, int y, const byte *string) { drawscaledtext (V_DRAWTLATEDLUCENTPATCH, normalcolor, x, y, string); } void V_DrawTextCleanMove (int normalcolor, int x, int y, const byte *string) { drawscaledtext (V_DRAWTRANSLATEDPATCH, normalcolor, (x - 160) * CleanXfac + screen.width / 2, (y - 100) * CleanYfac + screen.height / 2, string); } // // Find string width from hu_font chars // int V_StringWidth (const byte *string) { int w = 0, c; while (*string) { if (*string == 0x8a) { if (*(++string)) string++; continue; } else { c = toupper((*string++) & 0x7f) - HU_FONTSTART; if (c < 0 || c >= HU_FONTSIZE) { w += 4; } else { w += SHORT (hu_font[c]->width); } } } return w; } // // Break long lines of text into multiple lines no longer than maxwidth pixels // static void breakit (brokenlines_t *line, const byte *start, const byte *string) { // Leave out trailing white space while (string > start && isspace (*(string - 1))) string--; line->string = Z_Malloc (string - start + 1, PU_STATIC, 0); strncpy (line->string, start, string - start); line->string[string - start] = 0; line->width = V_StringWidth (line->string); } brokenlines_t *V_BreakLines (int maxwidth, const byte *string) { brokenlines_t lines[128]; // Support up to 128 lines (should be plenty) const byte *space = NULL, *start = string; int i, c, w, nw; BOOL lastWasSpace = false; i = w = 0; while ( (c = *string++) ) { if (c == 0x8a) { if (*string) string++; continue; } if (isspace(c)) { if (!lastWasSpace) { space = string - 1; lastWasSpace = true; } } else lastWasSpace = false; c = toupper (c & 0x7f) - HU_FONTSTART; if (c < 0 || c >= HU_FONTSIZE) nw = 4; else nw = SHORT (hu_font[c]->width); if (w + nw > maxwidth || c == '\n' - HU_FONTSTART) { // Time to break the line if (!space) space = string - 1; breakit (&lines[i], start, space); i++; w = 0; lastWasSpace = false; start = space; space = NULL; while (*start && isspace (*start)) start++; string = start; } else w += nw; } if (string - start > 1) { const byte *s = start; while (s < string) { if (!isspace (*s++)) { breakit (&lines[i++], start, string); break; } } } { // Make a copy of the broken lines and return them brokenlines_t *broken = Z_Malloc (sizeof(brokenlines_t) * (i + 1), PU_STATIC, 0); memcpy (broken, lines, sizeof(brokenlines_t) * i); broken[i].string = NULL; broken[i].width = -1; return broken; } } void V_FreeBrokenLines (brokenlines_t *lines) { if (lines) { int i = 0; while (lines[i].width != -1) { Z_Free (lines[i].string); lines[i].string = NULL; i++; } Z_Free (lines); } }