Improved fonts

Moderator: GZDoom Developers

User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49188
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Improved fonts

Post by Graf Zahl »

After all that discussions about non-productive nonsense like auto-update etc. let's return to some features that actually do have a purpose and benefit mappers.

I recently dug out some code I experimented with and one of the featues it had were custom multilump fonts (like STCFN***). It didn't take me long to port it to ZDoom's font management system and here's the result:

Code: Select all

//===========================================================================
// 
// Essentially a normal multilump font but 
// with an explicit list of character patches
//
//===========================================================================
class FSpecialFont : public FFont
{
public:
	FSpecialFont (const char *name, int first, int count, int * lumplist, const bool * notranslate);
};


FSpecialFont::FSpecialFont (const char *name, int first, int count, int * lumplist, const bool * notranslate)
{
	int i, j, lump;
	char buffer[12];
	int *charlumps;
	byte usedcolors[256], identity[256];
	double *luminosity;
	int maxyoffs;
	int TotalColors;

	Name=copystring(name);
	Chars = new CharData[count];
	charlumps = new int[count];
	PatchRemap = new BYTE[256];
	Ranges = NULL;
	FirstChar = first;
	LastChar = first + count - 1;
	FontHeight = 0;
	GlobalKerning = false;
	memset (usedcolors, 0, 256);
	Name = copystring (name);
	Next = FirstFont;
	FirstFont = this;

	maxyoffs = 0;

	for (i = 0; i < count; i++)
	{
		lump = charlumps[i] = lumplist[i];
		if (lump >= 0)
		{
			Wads.GetLumpName(buffer,lump);
			FTexture *pic = TexMan[TexMan.AddPatch (buffer)];
			int height = pic->GetHeight();
			int yoffs = pic->TopOffset;

			if (yoffs > maxyoffs)
			{
				maxyoffs = yoffs;
			}
			height += abs (yoffs);
			if (height > FontHeight)
			{
				FontHeight = height;
			}

			/* experimental True Color OpenGL font support ;)
			if (TexMan.GLSupport())
			{
				RecordGLTextureColors(lump, usedcolors);
			}
			else
			*/
			{
				RecordTextureColors (pic, usedcolors);
			}
		}
	}

	// exclude the non-translated colors from the translation calculation
	if (notranslate!=NULL)
	{
		for(i=0;i<256;i++) if (notranslate[i]) usedcolors[i]=false;
	}

	TotalColors = ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, &luminosity);

	// Map all untranslated colors into the table of used colors
	if (notranslate!=NULL)
	{
		for(i=0;i<256;i++) 
		{
			if (notranslate[i]) 
			{
				PatchRemap[i]=TotalColors;
				identity[TotalColors]=i;
				TotalColors++;
			}
		}
	}

	for (i = 0; i < count; i++)
	{
		if (charlumps[i] >= 0)
		{
			/* experimental True Color OpenGL font support ;)
			if (TexMan.GLSupport()) 
			{
				Chars[i].Pic = new FGLFontChar1(charlumps[i], PatchRemap, TotalColors, &Ranges);
			}
			else 
			*/
			{
				Chars[i].Pic = new FFontChar1 (charlumps[i], PatchRemap);
			}
		}
		else
		{
			Chars[i].Pic = NULL;
		}
	}

	// Special fonts normally don't have all characters so be careful here!
	if ('N'-first>=0 && 'N'-first<count && Chars['N' - first].Pic) 
	{
		SpaceWidth = (Chars['N' - first].Pic->GetWidth() + 1) / 2;
	}
	else SpaceWidth=4;

	BuildTranslations (luminosity, identity/*, TexMan.GLSupport()*/);


	// add the untranslated colors to the Ranges table
	if (ActiveColors<TotalColors)
	{
		int factor = 1;//3 * TexMan.GLSupport();
		byte * oldranges=Ranges;
		Ranges = new byte[NUM_TEXT_COLORS * TotalColors * factor ];

		for (i = 0; i < CR_UNTRANSLATED; i++)
		{
			memcpy(&Ranges[i * TotalColors * factor], &oldranges[i * ActiveColors * factor], ActiveColors * factor);

			for(j=ActiveColors;j<TotalColors;j++)
			{
				/* experimental True Color OpenGL font support ;)
				if (TexMan.GLSupport())
				{
					Ranges[(TotalColors*i + j)*3 + 0]=GPalette.BaseColors[identity[j]].r;
					Ranges[(TotalColors*i + j)*3 + 1]=GPalette.BaseColors[identity[j]].g;
					Ranges[(TotalColors*i + j)*3 + 2]=GPalette.BaseColors[identity[j]].b;
				}
				else
				*/
				{
					Ranges[TotalColors*i + j]=identity[j];
				}
			}
		}
		delete [] oldranges;
	}
	ActiveColors=TotalColors;

	delete[] luminosity;
	delete[] charlumps;
}


//===========================================================================
// 
// Initialize a list of custom multipatch fonts
//
//===========================================================================
BOOL SC_CheckNumber (void);

void V_InitCustomFonts()
{
	int lumplist[256];
	bool notranslate[256];
	char namebuffer[16],templatebuf[16];
	int adder=0;
	int i;
	int llump,lastlump=-1;
	int format=0;
	int start=33;
	int first=33;
	int count=223;


	while ((llump = Wads.FindLump ("FONTDEFS", &lastlump)) != -1)
	{
		SC_OpenLumpNum(llump,"FONTDEFS");
		while (SC_GetString())
		{
			memset(lumplist,-1,sizeof(lumplist));
			memset(notranslate,0,sizeof(notranslate));
			strncpy(namebuffer,sc_String,16);
			namebuffer[15]=0;
			format=0;
			start=33;
			first=33;
			count=223;

			SC_MustGetStringName("{");
			while (!SC_CheckString("}"))
			{
				SC_MustGetString();
				if (SC_Compare("TEMPLATE"))
				{
					if (format==2) goto wrong;
					SC_MustGetString();
					strncpy(templatebuf,sc_String,16);
					templatebuf[15]=0;
					format=1;
				}
				else if (SC_Compare("BASE"))
				{
					if (format==2) goto wrong;
					SC_MustGetNumber();
					start=sc_Number;
					format=1;
				}
				else if (SC_Compare("FIRST"))
				{
					if (format==2) goto wrong;
					SC_MustGetNumber();
					first=sc_Number;
					format=1;
				}
				else if (SC_Compare("COUNT"))
				{
					if (format==2) goto wrong;
					SC_MustGetNumber();
					count=sc_Number;
					format=1;
				}
				else if (SC_Compare("NOTRANSLATION"))
				{
					if (format==1) goto wrong;
					while (SC_CheckNumber() && !sc_Crossed)
					{
						if (sc_Number>=0 && sc_Number<256) notranslate[sc_Number]=true;
					}
					format=2;
				}
				else
				{
					if (format==1) goto wrong;
					int * p=&lumplist[*(unsigned char*)sc_String];
					SC_MustGetString();
					*p=Wads.CheckNumForName(sc_String);
					format=2;
				}
			}
			if (format==1)
			{
				new FFont(namebuffer, templatebuf, first, count, start);
			}
			else if (format==2)
			{
				for(i=0;i<256;i++)
				{
					if (lumplist[i]!=-1)
					{
						first=i;
						break;
					}
				}
				for(i=255;i>=0;i--)
				{
					if (lumplist[i]!=-1)
					{
						count=i-first+1;
						break;
					}
				}
				if (count>0) new FSpecialFont(namebuffer, first, count, &lumplist[first], notranslate);
			}
			else goto wrong;
		}
		SC_Close();
	}
	return;

wrong:
	SC_ScriptError("Invalid combination of properties in font '%s'", namebuffer);

}

Just copy and paste it to the end of V_Font.cpp, change the line

Code: Select all

	SpaceWidth = (Chars['N' - first].Pic->GetWidth() + 1) / 2;
in FFont::FFont to

Code: Select all

	if ('N'-first>=0 && 'N'-first<count && Chars['N' - first].Pic) 
	{
		SpaceWidth = (Chars['N' - first].Pic->GetWidth() + 1) / 2;
	}
	else SpaceWidth=4;
(this is important. It will crash there for incomplete fonts!)

and call V_InitCustomFonts from V_Init and it should work.

And here's a small WAD that demonstrates it.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49188
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

And here's a screenshot:

Image
User avatar
Xaser
 
 
Posts: 10773
Joined: Sun Jul 20, 2003 12:15 pm

Post by Xaser »

Heh, cool, does this mean that we can make new fonts by adding the individual letter graphics instead of making one of those annoying font files?
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49188
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

Yes, exactly! The word 'annoying' perfectly sums it up! ;)
User avatar
Chilvence
Posts: 1647
Joined: Mon Aug 11, 2003 6:36 pm

Post by Chilvence »

It's still headache inducing making a nice graphical font. Creating the graphic itself is great, with a nice ttf you can slap together something that looks amazing in 10 minutes. But seperating the individual letters, getting the alpha right, and naming them....
User avatar
Infurnus
Posts: 58
Joined: Thu Aug 07, 2003 2:43 am

Post by Infurnus »

Now THIS is a good idea. Lots of cool things you could do with this...
User avatar
Enjay
 
 
Posts: 26645
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland

Post by Enjay »

In some ways the "annoying" font is better IMO. The fact that it is a single lump, rather than all those small lumps is tidier. If Zdoom could read the graphic directly, rather than having to convert it to the font format(that proprietary graphics tools can't read), it would be an easy, tidy format to produce and edit.

However, if you are just ripping an already produced, multi-lump font, Graf's solution would probably be quicker.

52
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49188
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

You know what: The code is there, it works and it can be copied in without any change. There's really no need to discuss which solution is more efficient if both are available. ;)
User avatar
Chris
Posts: 2958
Joined: Thu Jul 17, 2003 12:07 am
Graphics Processor: ATI/AMD with Vulkan/Metal Support

Post by Chris »

After all that discussions about non-productive nonsense like auto-update etc. let's return to some features that actually do have a purpose and benefit mappers.
That makes you feel all mighty and superior to say that, don't it?
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49188
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

At least I have the common sense to recognize that as such. ZDoom should focus on the gaming/mapping experience, not on some 1337 crap nobody really needs Do I need to say 'ACS networking'? It's the same kind of overblown nonsense which doesn't make the game better but requires a lot of work.
User avatar
Bio Hazard
Posts: 4019
Joined: Fri Aug 15, 2003 8:15 pm
Location: ferret ~/C/ZDL $

Post by Bio Hazard »

Isint ACS networking part of the "Mapping experience" you mentioned? sure seems like it to me...
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49188
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

If you could do something useful with it it might. But despite being discussed to death there wasn't a single practicable use with larger appeal. Investing time in such features isn't worth it.
User avatar
wildweasel
Posts: 21706
Joined: Tue Jul 15, 2003 7:33 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): A lot of them
Graphics Processor: Not Listed

Post by wildweasel »

Please don't let that thread bleed into this one. It'll only balloon this one's size exponentially and decrease the likelihood that Randy will bother looking at it.
User avatar
Chris
Posts: 2958
Joined: Thu Jul 17, 2003 12:07 am
Graphics Processor: ATI/AMD with Vulkan/Metal Support

Post by Chris »

Please don't let that thread bleed into this one.
Ask mister big-shot that just had to mention it in the first place where it had no bussiness being. But alright, I'll shut up about it here.

As for the font idea itself, it's not terribly bad. Though honestly I'm with Enjay. Single-lump fonts are the way to go (especially if you want to factor in compression if it's a PNG image). You don't seem to have mentioned how it's used, though.
User avatar
wildweasel
Posts: 21706
Joined: Tue Jul 15, 2003 7:33 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): A lot of them
Graphics Processor: Not Listed

Post by wildweasel »

I was speaking to everybody, including Graf.

Return to “Closed Feature Suggestions [GZDoom]”