1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: ui_font.cpp 4297 2010-06-03 22:49:00Z firebrand_kh $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 #include "gamedefs.h"
29 #include "r_tex.h"
30 #include "ui.h"
31
32 // MACROS ------------------------------------------------------------------
33
34 // TYPES -------------------------------------------------------------------
35
36 struct VColTranslationDef
37 {
38 rgba_t From;
39 rgba_t To;
40 int LumFrom;
41 int LumTo;
42 };
43
44 struct VTextColourDef
45 {
46 TArray<VColTranslationDef> Translations;
47 TArray<VColTranslationDef> ConsoleTranslations;
48 rgba_t FlatColour;
49 int Index;
50 };
51
52 struct VColTransMap
53 {
54 VName Name;
55 int Index;
56 };
57
58 //
59 // VSpecialFont
60 //
61 // Like regular font, but initialised using explicit list of patches.
62 //
63 class VSpecialFont : public VFont
64 {
65 public:
66 VSpecialFont(VName, const TArray<int>&, const TArray<VName>&,
67 const bool*);
68 };
69
70 //
71 // VFon1Font
72 //
73 // Font in FON1 format.
74 //
75 class VFon1Font : public VFont
76 {
77 public:
78 VFon1Font(VName, int);
79 };
80
81 //
82 // VFon2Font
83 //
84 // Font in FON2 format.
85 //
86 class VFon2Font : public VFont
87 {
88 public:
89 VFon2Font(VName, int);
90 };
91
92 //
93 // VSingleTextureFont
94 //
95 // Font consisting of a single texture for character 'A'.
96 //
97 class VSingleTextureFont : public VFont
98 {
99 public:
100 VSingleTextureFont(VName, int);
101 };
102
103 //
104 // VFontChar
105 //
106 // Texture class for regular font characters.
107 //
108 class VFontChar : public VTexture
109 {
110 private:
111 VTexture* BaseTex;
112 rgba_t* Palette;
113
114 public:
115 VFontChar(VTexture*, rgba_t*);
116 ~VFontChar();
117 vuint8* GetPixels();
118 rgba_t* GetPalette();
119 void Unload();
120 VTexture* GetHighResolutionTexture();
121 };
122
123 //
124 // VFontChar2
125 //
126 // Texture class for FON1 font characters.
127 //
128 class VFontChar2 : public VTexture
129 {
130 private:
131 int LumpNum;
132 int FilePos;
133 vuint8* Pixels;
134 rgba_t* Palette;
135 int MaxCol;
136
137 public:
138 VFontChar2(int, int, int, int, rgba_t*, int);
139 ~VFontChar2();
140 vuint8* GetPixels();
141 rgba_t* GetPalette();
142 void Unload();
143 };
144
145 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
146
147 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
148
149 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
150
151 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
152
153 // PUBLIC DATA DEFINITIONS -------------------------------------------------
154
155 VFont* SmallFont;
156 VFont* ConFont;
157
158 // PRIVATE DATA DEFINITIONS ------------------------------------------------
159
160 VFont* VFont::Fonts;
161
162 static TArray<VTextColourDef> TextColours;
163 static TArray<VColTransMap> TextColourLookup;
164
165 // CODE --------------------------------------------------------------------
166
167 //==========================================================================
168 //
169 // VFont::StaticInit
170 //
171 //==========================================================================
172
StaticInit()173 void VFont::StaticInit()
174 {
175 guard(VFont::StaticInit);
176 ParseTextColours();
177
178 //
179 // Initialise standard fonts.
180 //
181
182 // Small font.
183 if (W_CheckNumForName(NAME_fonta_s) >= 0)
184 {
185 SmallFont = new VFont(NAME_smallfont, "fonta%02d", 33, 95, 1);
186 }
187 else
188 {
189 SmallFont = new VFont(NAME_smallfont, "stcfn%03d", 33, 95, 33);
190 }
191 // Strife's second small font.
192 if (W_CheckNumForName(NAME_stbfn033) >= 0)
193 {
194 new VFont(NAME_smallfont2, "stbfn%03d", 33, 95, 33);
195 }
196 // Big font.
197 if (W_CheckNumForName(NAME_bigfont) >= 0)
198 {
199 GetFont(NAME_bigfont, NAME_bigfont);
200 }
201 else
202 {
203 new VFont(NAME_bigfont, "fontb%02d", 33, 95, 1);
204 }
205 // Console font
206 ConFont = GetFont(NAME_consolefont, NAME_confont);
207
208 // Load custom fonts.
209 ParseFontDefs();
210 unguard;
211 }
212
213 //==========================================================================
214 //
215 // VFont::StaticShutdown
216 //
217 //==========================================================================
218
StaticShutdown()219 void VFont::StaticShutdown()
220 {
221 guard(VFont::StaticShutdown);
222 VFont* F = Fonts;
223 while (F)
224 {
225 VFont* Next = F->Next;
226 delete F;
227 F = NULL;
228 F = Next;
229 }
230 Fonts = NULL;
231 TextColours.Clear();
232 TextColourLookup.Clear();
233 unguard;
234 }
235
236 //==========================================================================
237 //
238 // VFont::ParseTextColours
239 //
240 //==========================================================================
241
ParseTextColours()242 void VFont::ParseTextColours()
243 {
244 guard(VFont::ParseTextColours);
245 TArray<VTextColourDef> TempDefs;
246 TArray<VColTransMap> TempColours;
247 for (int Lump = W_IterateNS(-1, WADNS_Global); Lump >= 0;
248 Lump = W_IterateNS(Lump, WADNS_Global))
249 {
250 if (W_LumpName(Lump) != NAME_textcolo)
251 {
252 continue;
253 }
254 VScriptParser sc(*W_LumpName(Lump), W_CreateLumpReaderNum(Lump));
255 while (!sc.AtEnd())
256 {
257 VTextColourDef& Col = TempDefs.Alloc();
258 Col.FlatColour.r = 0;
259 Col.FlatColour.g = 0;
260 Col.FlatColour.b = 0;
261 Col.FlatColour.a = 255;
262 Col.Index = -1;
263
264 TArray<VName> Names;
265 VColTranslationDef TDef;
266 TDef.LumFrom = -1;
267 TDef.LumTo = -1;
268
269 // Name for this colour.
270 sc.ExpectString();
271 Names.Append(*sc.String.ToLower());
272 // Additional names.
273 while (!sc.Check("{"))
274 {
275 if (Names[0] == "untranslated")
276 {
277 sc.Error("Colour \"untranslated\" cannot have any other names");
278 }
279 sc.ExpectString();
280 Names.Append(*sc.String.ToLower());
281 }
282
283 int TranslationMode = 0;
284 while (!sc.Check("}"))
285 {
286 if (sc.Check("Console:"))
287 {
288 if (TranslationMode == 1)
289 {
290 sc.Error("Only one console text colour definition allowed");
291 }
292 TranslationMode = 1;
293 TDef.LumFrom = -1;
294 TDef.LumTo = -1;
295 }
296 else if (sc.Check("Flat:"))
297 {
298 sc.ExpectString();
299 vuint32 C = M_ParseColour(sc.String);
300 Col.FlatColour.r = (C >> 16) & 0xff;
301 Col.FlatColour.g = (C >> 8) & 0xff;
302 Col.FlatColour.b = C & 0xff;
303 Col.FlatColour.a = 255;
304 }
305 else
306 {
307 // From colour.
308 sc.ExpectString();
309 vuint32 C = M_ParseColour(sc.String);
310 TDef.From.r = (C >> 16) & 0xff;
311 TDef.From.g = (C >> 8) & 0xff;
312 TDef.From.b = C & 0xff;
313 TDef.From.a = 255;
314
315 // To colour.
316 sc.ExpectString();
317 C = M_ParseColour(sc.String);
318 TDef.To.r = (C >> 16) & 0xff;
319 TDef.To.g = (C >> 8) & 0xff;
320 TDef.To.b = C & 0xff;
321 TDef.To.a = 255;
322
323 if (sc.CheckNumber())
324 {
325 // Optional luminosity ranges.
326 if (TDef.LumFrom == -1 && sc.Number != 0)
327 {
328 sc.Error("First colour range must start at position 0");
329 }
330 if (sc.Number < 0 || sc.Number > 256)
331 {
332 sc.Error("Colour index must be in range from 0 to 256");
333 }
334 if (sc.Number <= TDef.LumTo)
335 {
336 sc.Error("Colour range must start after end of previous range");
337 }
338 TDef.LumFrom = sc.Number;
339
340 sc.ExpectNumber();
341 if (sc.Number < 0 || sc.Number > 256)
342 {
343 sc.Error("Colour index must be in range from 0 to 256");
344 }
345 if (sc.Number <= TDef.LumFrom)
346 {
347 sc.Error("Ending colour index must be greater than start index");
348 }
349 TDef.LumTo = sc.Number;
350 }
351 else
352 {
353 // Set default luminosity range.
354 TDef.LumFrom = 0;
355 TDef.LumTo = 256;
356 }
357
358 if (TranslationMode == 0)
359 {
360 Col.Translations.Append(TDef);
361 }
362 else if (TranslationMode == 1)
363 {
364 Col.ConsoleTranslations.Append(TDef);
365 }
366 }
367 }
368
369 if (Names[0] == "untranslated")
370 {
371 if (Col.Translations.Num() != 0 ||
372 Col.ConsoleTranslations.Num() != 0)
373 {
374 sc.Error("The \"untranslated\" colour must be left undefined");
375 }
376 }
377 else
378 {
379 if (Col.Translations.Num() == 0)
380 {
381 sc.Error("There must be at least one normal range for a colour");
382 }
383 if (Col.ConsoleTranslations.Num() == 0)
384 {
385 // If console colour translation is not defined, make
386 // it white.
387 TDef.From.r = 0;
388 TDef.From.g = 0;
389 TDef.From.b = 0;
390 TDef.From.a = 255;
391 TDef.To.r = 255;
392 TDef.To.g = 255;
393 TDef.To.b = 255;
394 TDef.To.a = 255;
395 TDef.LumFrom = 0;
396 TDef.LumTo = 256;
397 Col.ConsoleTranslations.Append(TDef);
398 }
399 }
400
401 // Add all names to the list of colours.
402 for (int i = 0; i < Names.Num(); i++)
403 {
404 // Check for redefined colours.
405 int CIdx;
406 for (CIdx = 0; CIdx < TempColours.Num(); CIdx++)
407 {
408 if (TempColours[CIdx].Name == Names[i])
409 {
410 TempColours[CIdx].Index = TempDefs.Num() - 1;
411 break;
412 }
413 }
414 if (CIdx == TempColours.Num())
415 {
416 VColTransMap& CMap = TempColours.Alloc();
417 CMap.Name = Names[i];
418 CMap.Index = TempDefs.Num() - 1;
419 }
420 }
421 }
422 }
423
424 // Put colour definitions in it's final location.
425 for (int i = 0; i < TempColours.Num(); i++)
426 {
427 VColTransMap& TmpCol = TempColours[i];
428 VTextColourDef& TmpDef = TempDefs[TmpCol.Index];
429 if (TmpDef.Index == -1)
430 {
431 TmpDef.Index = TextColours.Num();
432 TextColours.Append(TmpDef);
433 }
434 VColTransMap& Col = TextColourLookup.Alloc();
435 Col.Name = TmpCol.Name;
436 Col.Index = TmpDef.Index;
437 }
438
439 // Make sure all biilt-in colours are defined.
440 check(TextColours.Num() >= NUM_TEXT_COLOURS);
441 unguard;
442 }
443
444 //==========================================================================
445 //
446 // VFont::ParseFontDefs
447 //
448 //==========================================================================
449
ParseFontDefs()450 void VFont::ParseFontDefs()
451 {
452 guard(VFont::ParseFontDefs);
453 for (int Lump = W_IterateNS(-1, WADNS_Global); Lump >= 0;
454 Lump = W_IterateNS(Lump, WADNS_Global))
455 {
456 if (W_LumpName(Lump) != NAME_fontdefs)
457 {
458 continue;
459 }
460 VScriptParser sc(*W_LumpName(Lump), W_CreateLumpReaderNum(Lump));
461 while (!sc.AtEnd())
462 {
463 // Name of the font.
464 sc.ExpectString();
465 VName FontName = *sc.String.ToLower();
466 sc.Expect("{");
467
468 #define CHECK_TYPE(Id) if (FontType == Id) \
469 sc.Error(va("Invalid combination of properties in font '%s'", *FontName))
470 int FontType = 0;
471 VStr Template;
472 int First = 33;
473 int Count = 223;
474 int Start = 33;
475 TArray<int> CharIndexes;
476 TArray<VName> CharLumps;
477 bool NoTranslate[256];
478 memset(NoTranslate, 0, sizeof(NoTranslate));
479
480 while (!sc.Check("}"))
481 {
482 if (sc.Check("template"))
483 {
484 CHECK_TYPE(2);
485 sc.ExpectString();
486 Template = sc.String;
487 FontType = 1;
488 }
489 else if (sc.Check("first"))
490 {
491 CHECK_TYPE(2);
492 sc.ExpectNumber();
493 First = sc.Number;
494 FontType = 1;
495 }
496 else if (sc.Check("count"))
497 {
498 CHECK_TYPE(2);
499 sc.ExpectNumber();
500 Count = sc.Number;
501 FontType = 1;
502 }
503 else if (sc.Check("base"))
504 {
505 CHECK_TYPE(2);
506 sc.ExpectNumber();
507 Start = sc.Number;
508 FontType = 1;
509 }
510 else if (sc.Check("notranslate"))
511 {
512 CHECK_TYPE(1);
513 while (sc.CheckNumber() && !sc.Crossed)
514 {
515 if (sc.Number >= 0 && sc.Number < 256)
516 {
517 NoTranslate[sc.Number] = true;
518 }
519 }
520 FontType = 2;
521 }
522 else
523 {
524 CHECK_TYPE(1);
525 sc.ExpectString();
526 const char* CPtr = *sc.String;
527 int CharIdx = VStr::GetChar(CPtr);
528 sc.ExpectString();
529 VName LumpName(*sc.String, VName::AddLower8);
530 if (W_CheckNumForName(LumpName, WADNS_Graphics) >= 0)
531 {
532 CharIndexes.Append(CharIdx);
533 CharLumps.Append(LumpName);
534 }
535 FontType = 2;
536 }
537 }
538 if (FontType == 1)
539 {
540 new VFont(FontName, Template, First, Count, Start);
541 }
542 else if (FontType == 2)
543 {
544 if (CharIndexes.Num())
545 {
546 new VSpecialFont(FontName, CharIndexes, CharLumps,
547 NoTranslate);
548 }
549 }
550 else
551 {
552 sc.Error("Font has no attributes");
553 }
554 }
555 }
556 unguard;
557 }
558
559 //==========================================================================
560 //
561 // VFont::FindFont
562 //
563 //==========================================================================
564
FindFont(VName AName)565 VFont* VFont::FindFont(VName AName)
566 {
567 guard(VFont::FindFont);
568 for (VFont* F = Fonts; F; F = F->Next)
569 {
570 if (F->Name == AName)
571 {
572 return F;
573 }
574 }
575 return NULL;
576 unguard;
577 }
578
579 //==========================================================================
580 //
581 // VFont::GetFont
582 //
583 //==========================================================================
584
GetFont(VName AName,VName LumpName)585 VFont* VFont::GetFont(VName AName, VName LumpName)
586 {
587 guard(VFont::GetFont);
588 VFont* F = FindFont(AName);
589 if (F)
590 {
591 return F;
592 }
593
594 // Check for wad lump.
595 int Lump = W_CheckNumForName(LumpName);
596 if (Lump >= 0)
597 {
598 // Read header.
599 VStream* Strm = W_CreateLumpReaderNum(Lump);
600 char Hdr[4];
601 Strm->Serialise(Hdr, 4);
602 delete Strm;
603 Strm = NULL;
604
605 if (Hdr[0] == 'F' && Hdr[1] == 'O' && Hdr[2] == 'N')
606 {
607 if (Hdr[3] == '1')
608 {
609 return new VFon1Font(AName, Lump);
610 }
611 if (Hdr[3] == '2')
612 {
613 return new VFon2Font(AName, Lump);
614 }
615 }
616 }
617
618 int TexNum = GTextureManager.CheckNumForName(LumpName, TEXTYPE_Any);
619 if (TexNum <= 0)
620 {
621 TexNum = GTextureManager.AddPatch(LumpName, TEXTYPE_Pic);
622 }
623 if (TexNum > 0)
624 {
625 return new VSingleTextureFont(AName, TexNum);
626 }
627
628 return NULL;
629 unguard;
630 }
631
632 //==========================================================================
633 //
634 // VFont::VFont
635 //
636 //==========================================================================
637
VFont()638 VFont::VFont()
639 {
640 }
641
642 //==========================================================================
643 //
644 // VFont::VFont
645 //
646 //==========================================================================
647
VFont(VName AName,const VStr & FormatStr,int First,int Count,int StartIndex)648 VFont::VFont(VName AName, const VStr& FormatStr, int First, int Count,
649 int StartIndex)
650 {
651 guard(VFont::VFont);
652 Name = AName;
653 Next = Fonts;
654 Fonts = this;
655
656 for (int i = 0; i < 128; i++)
657 {
658 AsciiChars[i] = -1;
659 }
660 FirstChar = -1;
661 LastChar = -1;
662 FontHeight = 0;
663 Kerning = 0;
664 Translation = NULL;
665 bool ColoursUsed[256];
666 memset(ColoursUsed, 0, sizeof(ColoursUsed));
667
668 for (int i = 0; i < Count; i++)
669 {
670 int Char = i + First;
671 char Buffer[10];
672 sprintf(Buffer, *FormatStr, i + StartIndex);
673 VName LumpName(Buffer, VName::AddLower8);
674 int Lump = W_CheckNumForName(LumpName, WADNS_Graphics);
675
676 // In Doom stcfn121 is actually a '|' and not 'y' and many wad
677 // authors provide it as such, so put it in correct location.
678 if (LumpName == "stcfn121" &&
679 (W_CheckNumForName("stcfn120", WADNS_Graphics) == -1 ||
680 W_CheckNumForName("stcfn122", WADNS_Graphics) == -1))
681 {
682 Char = '|';
683 }
684
685 if (Lump >= 0)
686 {
687 VTexture* Tex = GTextureManager[GTextureManager.AddPatch(LumpName,
688 TEXTYPE_Pic)];
689 FFontChar& FChar = Chars.Alloc();
690 FChar.Char = Char;
691 FChar.TexNum = -1;
692 FChar.BaseTex = Tex;
693 if (Char < 128)
694 {
695 AsciiChars[Char] = Chars.Num() - 1;
696 }
697
698 // Calculate height of font character and adjust font height
699 // as needed.
700 int Height = Tex->GetScaledHeight();
701 int TOffs = Tex->GetScaledTOffset();
702 Height += abs(TOffs);
703 if (FontHeight < Height)
704 {
705 FontHeight = Height;
706 }
707
708 // Update first and last characters.
709 if (FirstChar == -1)
710 {
711 FirstChar = Char;
712 }
713 LastChar = Char;
714
715 // Mark colours that are used by this texture.
716 MarkUsedColours(Tex, ColoursUsed);
717 }
718 }
719
720 // Set up width of a space character as half width of N character
721 // or 4 if character N has no graphic for it.
722 int NIdx = FindChar('N');
723 if (NIdx >= 0)
724 {
725 SpaceWidth = (Chars[NIdx].BaseTex->GetScaledWidth() + 1) / 2;
726 }
727 else
728 {
729 SpaceWidth = 4;
730 }
731
732 BuildTranslations(ColoursUsed, r_palette, false, true);
733
734 // Create texture objects for all different colours.
735 for (int i = 0; i < Chars.Num(); i++)
736 {
737 Chars[i].Textures = new VTexture*[TextColours.Num()];
738 for (int j = 0; j < TextColours.Num(); j++)
739 {
740 Chars[i].Textures[j] = new VFontChar(Chars[i].BaseTex,
741 Translation + j * 256);
742 // Currently all render drivers expect all textures to be
743 // registered in texture manager.
744 GTextureManager.AddTexture(Chars[i].Textures[j]);
745 }
746 }
747 unguard;
748 }
749
750 //==========================================================================
751 //
752 // VFont::~VFont
753 //
754 //==========================================================================
755
~VFont()756 VFont::~VFont()
757 {
758 guard(VFont::~VFont);
759 for (int i = 0; i < Chars.Num(); i++)
760 {
761 if (Chars[i].Textures)
762 {
763 delete[] Chars[i].Textures;
764 Chars[i].Textures = NULL;
765 }
766 }
767 Chars.Clear();
768 if (Translation)
769 {
770 delete[] Translation;
771 Translation = NULL;
772 }
773 unguard;
774 }
775
776 //==========================================================================
777 //
778 // VFont::BuildTranslations
779 //
780 //==========================================================================
781
BuildTranslations(const bool * ColoursUsed,rgba_t * Pal,bool ConsoleTrans,bool Rescale)782 void VFont::BuildTranslations(const bool* ColoursUsed, rgba_t* Pal,
783 bool ConsoleTrans, bool Rescale)
784 {
785 guard(VFont::BuildTranslations);
786 // Calculate luminosity for all colours and find minimal and maximal
787 // values for used colours.
788 float Luminosity[256];
789 float MinLum = 1000000.0;
790 float MaxLum = 0.0;
791 for (int i = 1; i < 256; i++)
792 {
793 Luminosity[i] = Pal[i].r * 0.299 + Pal[i].g * 0.587 +
794 Pal[i].b * 0.114;
795 if (ColoursUsed[i])
796 {
797 if (MinLum > Luminosity[i])
798 {
799 MinLum = Luminosity[i];
800 }
801 if (MaxLum < Luminosity[i])
802 {
803 MaxLum = Luminosity[i];
804 }
805 }
806 }
807 // Create gradual luminosity values.
808 float Scale = 1.0 / (Rescale ? (MaxLum - MinLum) : 255.0);
809 for (int i = 1; i < 256; i++)
810 {
811 Luminosity[i] = (Luminosity[i] - MinLum) *Scale;
812 Luminosity[i] = MID(0.0, Luminosity[i], 1.0);
813 }
814
815 Translation = new rgba_t[256 * TextColours.Num()];
816 for (int ColIdx = 0; ColIdx < TextColours.Num(); ColIdx++)
817 {
818 rgba_t* pOut = Translation + ColIdx * 256;
819 const TArray<VColTranslationDef>& TList = ConsoleTrans ?
820 TextColours[ColIdx].ConsoleTranslations :
821 TextColours[ColIdx].Translations;
822 if (ColIdx == CR_UNTRANSLATED || !TList.Num())
823 {
824 memcpy(pOut, Pal, 4 * 256);
825 continue;
826 }
827
828 pOut[0] = Pal[0];
829 for (int i = 1; i < 256; i++)
830 {
831 int ILum = (int)(Luminosity[i] * 256);
832 int TDefIdx = 0;
833 while (TDefIdx < TList.Num() - 1 && ILum > TList[TDefIdx].LumTo)
834 {
835 TDefIdx++;
836 }
837 const VColTranslationDef& TDef = TList[TDefIdx];
838
839 // Linearly interpolate between colours.
840 float v = ((float)(ILum - TDef.LumFrom) /
841 (float)(TDef.LumTo - TDef.LumFrom));
842 int r = (int)((1.0 - v) * TDef.From.r + v * TDef.To.r);
843 int g = (int)((1.0 - v) * TDef.From.g + v * TDef.To.g);
844 int b = (int)((1.0 - v) * TDef.From.b + v * TDef.To.b);
845 pOut[i].r = MID(0, r, 255);
846 pOut[i].g = MID(0, g, 255);
847 pOut[i].b = MID(0, b, 255);
848 pOut[i].a = 255;
849 }
850 }
851 unguard;
852 }
853
854 //==========================================================================
855 //
856 // VFont::GetChar
857 //
858 //==========================================================================
859
FindChar(int Chr) const860 int VFont::FindChar(int Chr) const
861 {
862 // Check if character is outside of available character range.
863 if (Chr < FirstChar || Chr > LastChar)
864 {
865 return -1;
866 }
867
868 // Fast look-up for ASCII characters
869 if (Chr < 128)
870 {
871 return AsciiChars[Chr];
872 }
873
874 // A slower one for unicode.
875 for (int i = 0; i < Chars.Num(); i++)
876 {
877 if (Chars[i].Char == Chr)
878 {
879 return i;
880 }
881 }
882 return -1;
883 }
884
885 //==========================================================================
886 //
887 // VFont::GetChar
888 //
889 //==========================================================================
890
GetChar(int Chr,int * pWidth,int Colour) const891 VTexture* VFont::GetChar(int Chr, int* pWidth, int Colour) const
892 {
893 guard(VFont::GetChar);
894 int Idx = FindChar(Chr);
895 if (Idx < 0)
896 {
897 // Try upper-case letter.
898 Chr = VStr::ToUpper(Chr);
899 Idx = FindChar(Chr);
900 if (Idx < 0)
901 {
902 *pWidth = SpaceWidth;
903 return NULL;
904 }
905 }
906
907 if (Colour < 0 || Colour >= TextColours.Num())
908 {
909 Colour = CR_UNTRANSLATED;
910 }
911 VTexture* Tex = Chars[Idx].Textures ? Chars[Idx].Textures[Colour] :
912 Chars[Idx].TexNum > 0 ? GTextureManager(Chars[Idx].TexNum) :
913 Chars[Idx].BaseTex;
914 *pWidth = Tex->GetScaledWidth();
915 return Tex;
916 unguard;
917 }
918
919 //==========================================================================
920 //
921 // VFont::GetCharWidth
922 //
923 //==========================================================================
924
GetCharWidth(int Chr) const925 int VFont::GetCharWidth(int Chr) const
926 {
927 guard(VFont::GetCharWidth);
928 int Idx = FindChar(Chr);
929 if (Idx < 0)
930 {
931 // Try upper-case letter.
932 Chr = VStr::ToUpper(Chr);
933 Idx = FindChar(Chr);
934 if (Idx < 0)
935 {
936 return SpaceWidth;
937 }
938 }
939
940 return Chars[Idx].BaseTex->GetScaledWidth();
941 unguard;
942 }
943
944 //==========================================================================
945 //
946 // VFont::MarkUsedColours
947 //
948 //==========================================================================
949
MarkUsedColours(VTexture * Tex,bool * Used)950 void VFont::MarkUsedColours(VTexture* Tex, bool* Used)
951 {
952 guard(VFont::MarkUsedColours);
953 const vuint8* Pixels = Tex->GetPixels8();
954 int Count = Tex->GetWidth() * Tex->GetHeight();
955 for (int i = 0; i < Count; i++)
956 {
957 Used[Pixels[i]] = true;
958 }
959 unguard;
960 }
961
962 //==========================================================================
963 //
964 // VFont::ParseColourEscape
965 //
966 // Assumes that pColour points to the character right after the colour
967 // escape character.
968 //
969 //==========================================================================
970
ParseColourEscape(const char * & pColour,int NormalColour,int BoldColour)971 int VFont::ParseColourEscape(const char*& pColour, int NormalColour,
972 int BoldColour)
973 {
974 guard(VFont::ParseColourEscape);
975 const char* Chr = pColour;
976 int Col = *Chr++;
977
978 // Standard colors, upper case
979 if (Col >= 'A' && Col < 'A' + NUM_TEXT_COLOURS)
980 {
981 Col -= 'A';
982 }
983 // Standard colors, lower case
984 else if (Col >= 'a' && Col < 'a' + NUM_TEXT_COLOURS)
985 {
986 Col -= 'a';
987 }
988 // Normal colour
989 else if (Col == '-')
990 {
991 Col = NormalColour;
992 }
993 // Bold colour
994 else if (Col == '+')
995 {
996 Col = BoldColour;
997 }
998 // Named colours.
999 else if (Col == '[')
1000 {
1001 VStr CName;
1002 while (*Chr && *Chr != ']')
1003 {
1004 CName += *Chr++;
1005 }
1006 if (*Chr == ']')
1007 {
1008 Chr++;
1009 }
1010 Col = FindTextColour(*CName.ToLower());
1011 }
1012 else
1013 {
1014 if (!Col)
1015 {
1016 Chr--;
1017 }
1018 Col = CR_UNDEFINED;
1019 }
1020
1021 // Set pointer after the colour definition.
1022 pColour = Chr;
1023 return Col;
1024 unguard;
1025 }
1026
1027 //==========================================================================
1028 //
1029 // VFont::FindTextColour
1030 //
1031 //==========================================================================
1032
FindTextColour(VName Name)1033 int VFont::FindTextColour(VName Name)
1034 {
1035 guard(VFont::FindTextColour);
1036 for (int i = 0; i < TextColourLookup.Num(); i++)
1037 {
1038 if (TextColourLookup[i].Name == Name)
1039 {
1040 return TextColourLookup[i].Index;
1041 }
1042 }
1043 return CR_UNTRANSLATED;
1044 unguard;
1045 }
1046
1047 //==========================================================================
1048 //
1049 // VFont::StringWidth
1050 //
1051 //==========================================================================
1052
StringWidth(const VStr & String) const1053 int VFont::StringWidth(const VStr& String) const
1054 {
1055 guard(VFont::StringWidth);
1056 int w = 0;
1057 for (const char* SPtr = *String; *SPtr;)
1058 {
1059 int c = VStr::GetChar(SPtr);
1060 // Check for colour escape.
1061 if (c == TEXT_COLOUR_ESCAPE)
1062 {
1063 ParseColourEscape(SPtr, CR_UNDEFINED, CR_UNDEFINED);
1064 continue;
1065 }
1066 w += GetCharWidth(c) + GetKerning();
1067 }
1068 return w;
1069 unguard;
1070 }
1071
1072 //==========================================================================
1073 //
1074 // VFont::TextWidth
1075 //
1076 //==========================================================================
1077
TextWidth(const VStr & String) const1078 int VFont::TextWidth(const VStr& String) const
1079 {
1080 guard(VFont::TextWidth);
1081 size_t i;
1082 int w1;
1083 int w = 0;
1084 int start = 0;
1085
1086 for (i = 0; i <= String.Length(); i++)
1087 if ((String[i] == '\n') || !String[i])
1088 {
1089 w1 = StringWidth(VStr(String, start, i - start));
1090 if (w1 > w)
1091 w = w1;
1092 start = i;
1093 }
1094 return w;
1095 unguard;
1096 }
1097
1098 //==========================================================================
1099 //
1100 // VFont::TextHeight
1101 //
1102 //==========================================================================
1103
TextHeight(const VStr & String) const1104 int VFont::TextHeight(const VStr& String) const
1105 {
1106 guard(VFont::TextHeight);
1107 int h = FontHeight;
1108 for (size_t i = 0; i < String.Length(); i++)
1109 {
1110 if (String[i] == '\n')
1111 {
1112 h += FontHeight;
1113 }
1114 }
1115 return h;
1116 unguard;
1117 }
1118
1119 //==========================================================================
1120 //
1121 // VFont::SplitText
1122 //
1123 //==========================================================================
1124
SplitText(const VStr & Text,TArray<VSplitLine> & Lines,int MaxWidth) const1125 int VFont::SplitText(const VStr& Text, TArray<VSplitLine>& Lines,
1126 int MaxWidth) const
1127 {
1128 guard(VFont::SplitText);
1129 Lines.Clear();
1130 const char* Start = *Text;
1131 bool WordStart = true;
1132 int CurW = 0;
1133 for (const char* SPtr = *Text; *SPtr;)
1134 {
1135 const char* PChar = SPtr;
1136 int c = VStr::GetChar(SPtr);
1137
1138 // Check for colour escape.
1139 if (c == TEXT_COLOUR_ESCAPE)
1140 {
1141 ParseColourEscape(SPtr, CR_UNDEFINED, CR_UNDEFINED);
1142 continue;
1143 }
1144
1145 if (c == '\n')
1146 {
1147 VSplitLine& L = Lines.Alloc();
1148 L.Text = VStr(Text, Start - *Text, PChar - Start);
1149 L.Width = CurW;
1150 Start = SPtr;
1151 WordStart = true;
1152 CurW = 0;
1153 }
1154 else if (WordStart && c > ' ')
1155 {
1156 const char* SPtr2 = SPtr;
1157 const char* PChar2 = PChar;
1158 int c2 = c;
1159 int NewW = CurW;
1160 while (c2 > ' ' || c2 == TEXT_COLOUR_ESCAPE)
1161 {
1162 if (c2 != TEXT_COLOUR_ESCAPE)
1163 {
1164 NewW += GetCharWidth(c2);
1165 }
1166 PChar2 = SPtr2;
1167 c2 = VStr::GetChar(SPtr2);
1168 // Check for colour escape.
1169 if (c2 == TEXT_COLOUR_ESCAPE)
1170 {
1171 ParseColourEscape(SPtr2, CR_UNDEFINED, CR_UNDEFINED);
1172 }
1173 }
1174 if (NewW > MaxWidth && PChar != Start)
1175 {
1176 VSplitLine& L = Lines.Alloc();
1177 L.Text = VStr(Text, Start - *Text, PChar - Start);
1178 L.Width = CurW;
1179 Start = PChar;
1180 CurW = 0;
1181 }
1182 WordStart = false;
1183 CurW += GetCharWidth(c);
1184 }
1185 else if (c <= ' ')
1186 {
1187 WordStart = true;
1188 CurW += GetCharWidth(c);
1189 }
1190 else
1191 {
1192 CurW += GetCharWidth(c);
1193 }
1194 if (!*SPtr && Start != SPtr)
1195 {
1196 VSplitLine& L = Lines.Alloc();
1197 L.Text = Start;
1198 L.Width = CurW;
1199 }
1200 }
1201 return Lines.Num() * FontHeight;
1202 unguard;
1203 }
1204
1205 //==========================================================================
1206 //
1207 // VFont::SplitTextWithNewlines
1208 //
1209 //==========================================================================
1210
SplitTextWithNewlines(const VStr & Text,int MaxWidth) const1211 VStr VFont::SplitTextWithNewlines(const VStr& Text, int MaxWidth) const
1212 {
1213 guard(VFont::SplitTextWithNewlines);
1214 TArray<VSplitLine> Lines;
1215 SplitText(Text, Lines, MaxWidth);
1216 VStr Ret;
1217 for (int i = 0; i < Lines.Num(); i++)
1218 {
1219 Ret += Lines[i].Text + "\n";
1220 }
1221 return Ret;
1222 unguard;
1223 }
1224
1225 //==========================================================================
1226 //
1227 // VSpecialFont::VSpecialFont
1228 //
1229 //==========================================================================
1230
VSpecialFont(VName AName,const TArray<int> & CharIndexes,const TArray<VName> & CharLumps,const bool * NoTranslate)1231 VSpecialFont::VSpecialFont(VName AName, const TArray<int>& CharIndexes,
1232 const TArray<VName>& CharLumps, const bool* NoTranslate)
1233 {
1234 guard(VSpecialFont::VSpecialFont);
1235 Name = AName;
1236 Next = Fonts;
1237 Fonts = this;
1238
1239 for (int i = 0; i < 128; i++)
1240 {
1241 AsciiChars[i] = -1;
1242 }
1243 FirstChar = -1;
1244 LastChar = -1;
1245 FontHeight = 0;
1246 Kerning = 0;
1247 Translation = NULL;
1248 bool ColoursUsed[256];
1249 memset(ColoursUsed, 0, sizeof(ColoursUsed));
1250
1251 check(CharIndexes.Num() == CharLumps.Num());
1252 for (int i = 0; i < CharIndexes.Num(); i++)
1253 {
1254 int Char = CharIndexes[i];
1255 VName LumpName = CharLumps[i];
1256
1257 VTexture* Tex = GTextureManager[GTextureManager.AddPatch(LumpName,
1258 TEXTYPE_Pic)];
1259 FFontChar& FChar = Chars.Alloc();
1260 FChar.Char = Char;
1261 FChar.TexNum = -1;
1262 FChar.BaseTex = Tex;
1263 if (Char < 128)
1264 {
1265 AsciiChars[Char] = Chars.Num() - 1;
1266 }
1267
1268 // Calculate height of font character and adjust font height
1269 // as needed.
1270 int Height = Tex->GetScaledHeight();
1271 int TOffs = Tex->GetScaledTOffset();
1272 Height += abs(TOffs);
1273 if (FontHeight < Height)
1274 {
1275 FontHeight = Height;
1276 }
1277
1278 // Update first and last characters.
1279 if (FirstChar == -1)
1280 {
1281 FirstChar = Char;
1282 }
1283 LastChar = Char;
1284
1285 // Mark colours that are used by this texture.
1286 MarkUsedColours(Tex, ColoursUsed);
1287 }
1288
1289 // Exclude non-translated colours from calculations.
1290 for (int i = 0; i < 256; i++)
1291 {
1292 if (NoTranslate[i])
1293 {
1294 ColoursUsed[i] = false;
1295 }
1296 }
1297
1298 // Set up width of a space character as half width of N character
1299 // or 4 if character N has no graphic for it.
1300 int NIdx = FindChar('N');
1301 if (NIdx >= 0)
1302 {
1303 SpaceWidth = (Chars[NIdx].BaseTex->GetScaledWidth() + 1) / 2;
1304 }
1305 else
1306 {
1307 SpaceWidth = 4;
1308 }
1309
1310 BuildTranslations(ColoursUsed, r_palette, false, true);
1311
1312 // Map non-translated colours to their original values
1313 for (int i = 0; i < TextColours.Num(); i++)
1314 {
1315 for (int j = 0; j < 256; j++)
1316 {
1317 if (NoTranslate[j])
1318 {
1319 Translation[i * 256 + j] = r_palette[j];
1320 }
1321 }
1322 }
1323
1324 // Create texture objects for all different colours.
1325 for (int i = 0; i < Chars.Num(); i++)
1326 {
1327 Chars[i].Textures = new VTexture*[TextColours.Num()];
1328 for (int j = 0; j < TextColours.Num(); j++)
1329 {
1330 Chars[i].Textures[j] = new VFontChar(Chars[i].BaseTex,
1331 Translation + j * 256);
1332 // Currently all render drivers expect all textures to be
1333 // registered in texture manager.
1334 GTextureManager.AddTexture(Chars[i].Textures[j]);
1335 }
1336 }
1337 unguard;
1338 }
1339
1340 //==========================================================================
1341 //
1342 // VFon1Font::VFon1Font
1343 //
1344 //==========================================================================
1345
VFon1Font(VName AName,int LumpNum)1346 VFon1Font::VFon1Font(VName AName, int LumpNum)
1347 {
1348 guard(VFon1Font::VFon1Font);
1349 Name = AName;
1350 Next = Fonts;
1351 Fonts = this;
1352
1353 VStream* Strm = W_CreateLumpReaderNum(LumpNum);
1354 // Skip ID.
1355 Strm->Seek(4);
1356 vuint16 w;
1357 vuint16 h;
1358 *Strm << w << h;
1359 SpaceWidth = w;
1360 FontHeight = h;
1361
1362 FirstChar = 0;
1363 LastChar = 255;
1364 Kerning = 0;
1365 Translation = NULL;
1366 for (int i = 0; i < 128; i++)
1367 {
1368 AsciiChars[i] = i;
1369 }
1370
1371 // Mark all colours as used and construct a grayscale palette.
1372 bool ColoursUsed[256];
1373 rgba_t Pal[256];
1374 ColoursUsed[0] = false;
1375 Pal[0].r = 0;
1376 Pal[0].g = 0;
1377 Pal[0].b = 0;
1378 Pal[0].a = 0;
1379 for (int i = 1; i < 256; i++)
1380 {
1381 ColoursUsed[i] = true;
1382 Pal[i].r = (i - 1) * 255 / 254;
1383 Pal[i].g = Pal[i].r;
1384 Pal[i].b = Pal[i].r;
1385 Pal[i].a = 255;
1386 }
1387
1388 BuildTranslations(ColoursUsed, Pal, true, false);
1389
1390 for (int i = 0; i < 256; i++)
1391 {
1392 FFontChar& FChar = Chars.Alloc();
1393 FChar.Char = i;
1394 FChar.TexNum = -1;
1395
1396 // Create texture objects for all different colours.
1397 FChar.Textures = new VTexture*[TextColours.Num()];
1398 for (int j = 0; j < TextColours.Num(); j++)
1399 {
1400 FChar.Textures[j] = new VFontChar2(LumpNum, Strm->Tell(),
1401 SpaceWidth, FontHeight, Translation + j * 256, 255);
1402 // Currently all render drivers expect all textures to be
1403 // registered in texture manager.
1404 GTextureManager.AddTexture(FChar.Textures[j]);
1405 }
1406 FChar.BaseTex = FChar.Textures[CR_UNTRANSLATED];
1407
1408 // Skip character data.
1409 int Count = SpaceWidth * FontHeight;
1410 do
1411 {
1412 vint8 Code = Streamer<vint8>(*Strm);
1413 if (Code >= 0)
1414 {
1415 Count -= Code + 1;
1416 while (Code-- >= 0)
1417 {
1418 Streamer<vint8>(*Strm);
1419 }
1420 }
1421 else if (Code != -128)
1422 {
1423 Count -= 1 - Code;
1424 Streamer<vint8>(*Strm);
1425 }
1426 }
1427 while (Count > 0);
1428 if (Count < 0)
1429 {
1430 Sys_Error("Overflow decompressing a character %d", i);
1431 }
1432 }
1433
1434 delete Strm;
1435 Strm = NULL;
1436 unguard;
1437 }
1438
1439 //==========================================================================
1440 //
1441 // VFon2Font::VFon2Font
1442 //
1443 // 4 - header
1444 // 2 - height
1445 // 1 - first char
1446 // 1 - last char
1447 // 1 - fixed width flag
1448 // 1
1449 // 1 - active colours
1450 // 1 - kerning flag
1451 // 2 (if have flag) - kerning
1452 //
1453 //==========================================================================
1454
VFon2Font(VName AName,int LumpNum)1455 VFon2Font::VFon2Font(VName AName, int LumpNum)
1456 {
1457 guard(VFon2Font::VFon2Font);
1458 Name = AName;
1459 Next = Fonts;
1460 Fonts = this;
1461
1462 VStream* Strm = W_CreateLumpReaderNum(LumpNum);
1463 // Skip ID.
1464 Strm->Seek(4);
1465
1466 // Read header.
1467 FontHeight = Streamer<vuint16>(*Strm);
1468 FirstChar = Streamer<vuint8>(*Strm);
1469 LastChar = Streamer<vuint8>(*Strm);
1470 vuint8 FixedWidthFlag;
1471 vuint8 RescalePal;
1472 vuint8 ActiveColours;
1473 vuint8 KerningFlag;
1474 *Strm << FixedWidthFlag << RescalePal << ActiveColours << KerningFlag;
1475 Kerning = 0;
1476 if (KerningFlag & 1)
1477 {
1478 Kerning = Streamer<vint16>(*Strm);
1479 }
1480
1481 Translation = NULL;
1482 for (int i = 0; i < 128; i++)
1483 {
1484 AsciiChars[i] = -1;
1485 }
1486
1487 // Read character widths.
1488 int Count = LastChar - FirstChar + 1;
1489 vuint16* Widths = new vuint16[Count];
1490 int TotalWidth = 0;
1491 if (FixedWidthFlag)
1492 {
1493 *Strm << Widths[0];
1494 for (int i = 1; i < Count; i++)
1495 {
1496 Widths[i] = Widths[0];
1497 }
1498 TotalWidth = Widths[0] * Count;
1499 }
1500 else
1501 {
1502 for (int i = 0; i < Count; i++)
1503 {
1504 *Strm << Widths[i];
1505 TotalWidth += Widths[i];
1506 }
1507 }
1508
1509 if (FirstChar <= ' ' && LastChar >= ' ')
1510 {
1511 SpaceWidth = Widths[' ' - FirstChar];
1512 }
1513 else if (FirstChar <= 'N' && LastChar >= 'N')
1514 {
1515 SpaceWidth = (Widths['N' - FirstChar] + 1) / 2;
1516 }
1517 else
1518 {
1519 SpaceWidth = TotalWidth * 2 / (3 * Count);
1520 }
1521
1522 // Read palette
1523 bool ColoursUsed[256];
1524 rgba_t Pal[256];
1525 memset(ColoursUsed, 0, sizeof(ColoursUsed));
1526 memset(Pal, 0, sizeof(Pal));
1527 for (int i = 0; i <= ActiveColours; i++)
1528 {
1529 ColoursUsed[i] = true;
1530 *Strm << Pal[i].r << Pal[i].g << Pal[i].b;
1531 Pal[i].a = i ? 255 : 0;
1532 }
1533
1534 BuildTranslations(ColoursUsed, Pal, false, !!RescalePal);
1535
1536 for (int i = 0; i < Count; i++)
1537 {
1538 int Chr = FirstChar + i;
1539 int DataSize = Widths[i] * FontHeight;
1540 if (DataSize > 0)
1541 {
1542 FFontChar& FChar = Chars.Alloc();
1543 FChar.Char = Chr;
1544 FChar.TexNum = -1;
1545 if (Chr < 128)
1546 {
1547 AsciiChars[Chr] = Chars.Num() - 1;
1548 }
1549
1550 // Create texture objects for all different colours.
1551 FChar.Textures = new VTexture*[TextColours.Num()];
1552 for (int j = 0; j < TextColours.Num(); j++)
1553 {
1554 FChar.Textures[j] = new VFontChar2(LumpNum, Strm->Tell(),
1555 Widths[i], FontHeight, Translation + j * 256,
1556 ActiveColours);
1557 // Currently all render drivers expect all textures to be
1558 // registered in texture manager.
1559 GTextureManager.AddTexture(FChar.Textures[j]);
1560 }
1561 FChar.BaseTex = FChar.Textures[CR_UNTRANSLATED];
1562
1563 // Skip character data.
1564 do
1565 {
1566 vint8 Code = Streamer<vint8>(*Strm);
1567 if (Code >= 0)
1568 {
1569 DataSize -= Code + 1;
1570 while (Code-- >= 0)
1571 {
1572 Streamer<vint8>(*Strm);
1573 }
1574 }
1575 else if (Code != -128)
1576 {
1577 DataSize -= 1 - Code;
1578 Streamer<vint8>(*Strm);
1579 }
1580 }
1581 while (DataSize > 0);
1582 if (DataSize < 0)
1583 {
1584 Sys_Error("Overflow decompressing a character %d", i);
1585 }
1586 }
1587 }
1588
1589 delete Strm;
1590 Strm = NULL;
1591 delete[] Widths;
1592 Widths = NULL;
1593 unguard;
1594 }
1595
1596 //==========================================================================
1597 //
1598 // VSingleTextureFont::VSingleTextureFont
1599 //
1600 //==========================================================================
1601
VSingleTextureFont(VName AName,int TexNum)1602 VSingleTextureFont::VSingleTextureFont(VName AName, int TexNum)
1603 {
1604 guard(VSingleTextureFont::VSingleTextureFont);
1605 Name = AName;
1606 Next = Fonts;
1607 Fonts = this;
1608
1609 VTexture* Tex = GTextureManager[TexNum];
1610 for (int i = 0; i < 128; i++)
1611 {
1612 AsciiChars[i] = -1;
1613 }
1614 AsciiChars[(int)'A'] = 0;
1615 FirstChar = 'A';
1616 LastChar = 'A';
1617 SpaceWidth = Tex->GetScaledWidth();
1618 FontHeight = Tex->GetScaledHeight();
1619 Kerning = 0;
1620 Translation = NULL;
1621
1622 FFontChar& FChar = Chars.Alloc();
1623 FChar.Char = 'A';
1624 FChar.TexNum = TexNum;
1625 FChar.BaseTex = Tex;
1626 FChar.Textures = NULL;
1627 unguard;
1628 }
1629
1630 //==========================================================================
1631 //
1632 // VFontChar::VFontChar
1633 //
1634 //==========================================================================
1635
VFontChar(VTexture * ATex,rgba_t * APalette)1636 VFontChar::VFontChar(VTexture* ATex, rgba_t* APalette)
1637 : BaseTex(ATex)
1638 , Palette(APalette)
1639 {
1640 Type = TEXTYPE_FontChar;
1641 Format = TEXFMT_8Pal;
1642 Name = NAME_None;
1643 Width = BaseTex->GetWidth();
1644 Height = BaseTex->GetHeight();
1645 SOffset = BaseTex->SOffset;
1646 TOffset = BaseTex->TOffset;
1647 SScale = BaseTex->SScale;
1648 TScale = BaseTex->TScale;
1649 }
1650
1651 //==========================================================================
1652 //
1653 // VFontChar::~VFontChar
1654 //
1655 //==========================================================================
1656
~VFontChar()1657 VFontChar::~VFontChar()
1658 {
1659 }
1660
1661 //==========================================================================
1662 //
1663 // VFontChar::GetPixels
1664 //
1665 //==========================================================================
1666
GetPixels()1667 vuint8* VFontChar::GetPixels()
1668 {
1669 guard(VFontChar::GetPixels);
1670 return BaseTex->GetPixels8();
1671 unguard;
1672 }
1673
1674 //==========================================================================
1675 //
1676 // VFontChar::GetPalette
1677 //
1678 //==========================================================================
1679
GetPalette()1680 rgba_t* VFontChar::GetPalette()
1681 {
1682 guard(VFontChar::GetPalette);
1683 return Palette;
1684 unguard;
1685 }
1686
1687 //==========================================================================
1688 //
1689 // VFontChar::Unload
1690 //
1691 //==========================================================================
1692
Unload()1693 void VFontChar::Unload()
1694 {
1695 guard(VFontChar::Unload);
1696 BaseTex->Unload();
1697 unguard;
1698 }
1699
1700 //==========================================================================
1701 //
1702 // VFontChar::GetHighResolutionTexture
1703 //
1704 //==========================================================================
1705
GetHighResolutionTexture()1706 VTexture* VFontChar::GetHighResolutionTexture()
1707 {
1708 guard(VFontChar::GetHighResolutionTexture);
1709 if (!r_hirestex)
1710 {
1711 return NULL;
1712 }
1713 if (!HiResTexture)
1714 {
1715 VTexture* Tex = BaseTex->GetHighResolutionTexture();
1716 if (Tex)
1717 {
1718 HiResTexture = new VFontChar(Tex, Palette);
1719 }
1720 }
1721 return HiResTexture;
1722 unguard;
1723 }
1724
1725 //==========================================================================
1726 //
1727 // VFontChar2::VFontChar2
1728 //
1729 //==========================================================================
1730
VFontChar2(int ALumpNum,int AFilePos,int CharW,int CharH,rgba_t * APalette,int AMaxCol)1731 VFontChar2::VFontChar2(int ALumpNum, int AFilePos, int CharW, int CharH,
1732 rgba_t* APalette, int AMaxCol)
1733 : LumpNum(ALumpNum)
1734 , FilePos(AFilePos)
1735 , Pixels(NULL)
1736 , Palette(APalette)
1737 , MaxCol(AMaxCol)
1738 {
1739 Type = TEXTYPE_FontChar;
1740 Format = TEXFMT_8Pal;
1741 Name = NAME_None;
1742 Width = CharW;
1743 Height = CharH;
1744 }
1745
1746 //==========================================================================
1747 //
1748 // VFontChar2::~VFontChar2
1749 //
1750 //==========================================================================
1751
~VFontChar2()1752 VFontChar2::~VFontChar2()
1753 {
1754 if (Pixels)
1755 {
1756 delete[] Pixels;
1757 Pixels = NULL;
1758 }
1759 }
1760
1761 //==========================================================================
1762 //
1763 // VFontChar2::GetPixels
1764 //
1765 //==========================================================================
1766
GetPixels()1767 vuint8* VFontChar2::GetPixels()
1768 {
1769 guard(VFontChar2::GetPixels);
1770 if (Pixels)
1771 {
1772 return Pixels;
1773 }
1774
1775 VStream* Strm = W_CreateLumpReaderNum(LumpNum);
1776 Strm->Seek(FilePos);
1777
1778 int Count = Width * Height;
1779 Pixels = new vuint8[Count];
1780 vuint8* pDst = Pixels;
1781 do
1782 {
1783 vint32 Code = Streamer<vint8>(*Strm);
1784 if (Code >= 0)
1785 {
1786 Count -= Code + 1;
1787 while (Code-- >= 0)
1788 {
1789 *pDst = Streamer<vuint8>(*Strm);
1790 *pDst = MIN(*pDst, MaxCol);
1791 pDst++;
1792 }
1793 }
1794 else if (Code != -128)
1795 {
1796 Code = 1 - Code;
1797 Count -= Code;
1798 vuint8 Val = Streamer<vuint8>(*Strm);
1799 Val = MIN(Val, MaxCol);
1800 while (Code-- > 0)
1801 {
1802 *pDst++ = Val;
1803 }
1804 }
1805 }
1806 while (Count > 0);
1807
1808 delete Strm;
1809 Strm = NULL;
1810 return Pixels;
1811 unguard;
1812 }
1813
1814 //==========================================================================
1815 //
1816 // VFontChar2::GetPalette
1817 //
1818 //==========================================================================
1819
GetPalette()1820 rgba_t* VFontChar2::GetPalette()
1821 {
1822 guard(VFontChar2::GetPalette);
1823 return Palette;
1824 unguard;
1825 }
1826
1827 //==========================================================================
1828 //
1829 // VFontChar2::Unload
1830 //
1831 //==========================================================================
1832
Unload()1833 void VFontChar2::Unload()
1834 {
1835 guard(VFontChar2::Unload);
1836 if (Pixels)
1837 {
1838 delete[] Pixels;
1839 Pixels = NULL;
1840 }
1841 unguard;
1842 }
1843