Page 1 of 1

Change kerning of an existing DBIGFONT lump?

Posted: Sat Dec 25, 2021 12:50 pm
by Tormentor667
Is it possible in an easy way to expand the kerning of an existing DBIGFONT lump without too much hazzle? I read something about an font.inf in the wiki and that there is a Kerning = <int> property, but no idea how to use it on an existing DBIGFONT lump.

Re: Change kerning of an existing DBIGFONT lump?

Posted: Tue Dec 28, 2021 2:28 am
by Acts 19 quiz
I'm fairly certain font.inf (and the property you described) is only for the new-style Unicode characters (like 002E.lmp) that are in individual files rather than one big dbigfont.lmp. I think GZDoom is beyond the point of adding any new features to the old style dbigfont since the switchover in GZDoom 4.0.0.

About the only thing I can think to do is, if there's a dbigfont.lmp you want to alter the kerning on, either get the .bmp that the old imagetool would have converted into the binary dbigfont lump, or worst case scenario use SLADE to convert a dbigfont to PNG and edit it back into a new dbigfont. I don't know of any way to run imagetool in reverse (export a dbigfont into a plain BMP with the grid, etc.). Also obviously can't have negative kerning with dbigfont. Sorry. :\

Re: Change kerning of an existing DBIGFONT lump?

Posted: Tue Dec 28, 2021 6:15 am
by Enjay
Acts 19 quiz wrote:I don't know of any way to run imagetool in reverse (export a dbigfont into a plain BMP with the grid, etc.).
If you run imagetool without any parameters, it tells you how to do it.

Code: Select all

Usage: imagetool [-0] <type> <source> <output>
<type> can be:
        confont : Monospaced console font
        font    : Normal font
        image   : Raw image
        xhair   : Crosshair
        pcx     : Convert <source> to a PCX file
        bmp     : Convert <source> to a BMP file
        ilbm    : Convert <source> to an ILBM file
<source> can be an ILBM, BMP, PCX, IMGZ, FON1, FON2, or Doom patch.
Specify -0 to swap colors 0 and 247 in <source>.
See the line where it says what source can be? So, it's just the same as converting an image to a font except you use the font as the input and specify an image as the output. I've done it loads of times. It works just fine.

Something like:

Code: Select all

imagetool bmp DBIGFONT.lmp DBIGFONT.bmp
would probably do it.
[edit]Yup, that worked for the DBIGFONT in ZDoom 1.23
Image
[/edit]

I have always tended to use PCX images as the output because that's what it ships with, but I assume that BMPs work too. If not, PCX is an older format but it should be supported by any decent graphics program.

All that being said, this is probably not what Tormentor is looking for.

Re: Change kerning of an existing DBIGFONT lump?

Posted: Tue Dec 28, 2021 8:11 am
by Tormentor667
Well, the question for me is: If I can make it to export the file and make a PCX/BMP out of it, how can I add the kerning? I already used IMAGETOOL to export the FON2 to a PCX but how can I add the kerning now?

Re: Change kerning of an existing DBIGFONT lump?

Posted: Tue Dec 28, 2021 10:18 am
by Acts 19 quiz
Enjay wrote:
Acts 19 quiz wrote:I don't know of any way to run imagetool in reverse (export a dbigfont into a plain BMP with the grid, etc.).
If you run imagetool without any parameters, it tells you how to do it.
Duly noted and thanks, however to TC's point, and what I was saying is I don't think there's anyway to jerryrig font.inf to alter dbigfont.lmp, or any automated way to add kerning beyond manually editing a .bmp/.pcx to include it. Something like this 256-bit BMP (colours are accurate):

Re: Change kerning of an existing DBIGFONT lump?

Posted: Tue Dec 28, 2021 11:40 am
by Tormentor667
Acts 19 quiz wrote:attachement
Thanks kindly, that solves the problem in most cases, but not for the intermission screen's percentage numbers
2021-12-28_183837.jpg
I wonder if you can override these somehow in an intermission zscript?

Code: Select all

class RefStatusScreen : DoomStatusScreen
{
	override int drawLF ()
	{
		bool ispatch = wbs.LName0.isValid();
		int oldy = TITLEY+6 * CleanYfac;
		int h;
		
		if (!ispatch)
		{
			let asc = mapname.mFont.GetMaxAscender(lnametexts[1]);
			if (asc > TITLEY - 2)
			{
				oldy = (asc+2) * CleanYfac;
			}
		}
		
		int y = DrawName(oldy, wbs.LName0, lnametexts[0]);

		// If the displayed info is made of patches we need some additional offsetting here.
		if (ispatch) 
		{
			int disp = 0;
			// The offset getting applied here must at least be as tall as the largest ascender in the following text to avoid overlaps.
			if (authortexts[0].length() == 0)
			{
				int h1 = BigFont.GetHeight() - BigFont.GetDisplacement();
				int h2 = (y - oldy) / CleanYfac / 4;
				disp = min(h1, h2);
				
				if (!TexMan.OkForLocalization(finishedPatch, "$WI_FINISHED"))
				{
					disp += finished.mFont.GetMaxAscender("$WI_FINISHED");
				}
			}
			else
			{
					disp += author.mFont.GetMaxAscender(authortexts[0]);
			}
			y += disp * CleanYfac;
		}
		
		y = DrawAuthor(y, authortexts[0]);
		
		// draw "Finished!"

		int statsy = multiplayer? NG_STATSY : SP_STATSY * CleanYFac;
		if (y < (statsy - finished.mFont.GetHeight()*3/4) * CleanYfac)
		{
			// don't draw 'finished' if the level name is too tall
			y = DrawPatchOrText(y, finished, finishedPatch, "$WI_FINISHED");
		}
		return y;
	}

	override void drawEL ()
	{
		bool ispatch = TexMan.OkForLocalization(enteringPatch, "$WI_ENTERING");
		int oldy = TITLEY+6 * CleanYfac;

		if (!ispatch)
		{
			let asc = entering.mFont.GetMaxAscender("$WI_ENTERING");
			if (asc > TITLEY - 2)
			{
				oldy = (asc+2) * CleanYfac;
			}
		}

		int y = DrawPatchOrText(oldy, entering, enteringPatch, "$WI_ENTERING");
		
		// If the displayed info is made of patches we need some additional offsetting here.
		
		if (ispatch)
		{
			int h1 = BigFont.GetHeight() - BigFont.GetDisplacement();
			let size = TexMan.GetScaledSize(enteringPatch);
			int h2 = int(size.Y);
			let disp = min(h1, h2) / 4;
			// The offset getting applied here must at least be as tall as the largest ascender in the following text to avoid overlaps.
			if (!wbs.LName1.isValid())
			{
				disp += mapname.mFont.GetMaxAscender(lnametexts[1]);
			}
			y += disp * CleanYfac;
		}

		y = DrawName(y, wbs.LName1, lnametexts[1]);

		if (wbs.LName1.isValid() && authortexts[1].length() > 0) 
		{
			// Consdider the ascender height of the following text.
			y += author.mFont.GetMaxAscender(authortexts[1]) * CleanYfac;
		}
			
		DrawAuthor(y, authortexts[1]);

	}

	override void drawStats (void)
	{
		// line height
		int lh = IntermissionFont.GetHeight() * 3 / 2;

		drawLF();
		
	
		// For visual consistency, only use the patches here if all are present.
		bool useGfx = TexMan.OkForLocalization(Kills, "$TXT_IMKILLS")
			&& TexMan.OkForLocalization(Items, "$TXT_IMITEMS")
			&& TexMan.OkForLocalization(P_secret, "$TXT_IMSECRETS")
			&& TexMan.OkForLocalization(Timepic, "$TXT_IMTIME")
			&& (!wbs.partime || TexMan.OkForLocalization(Par, "$TXT_IMPAR"));

		// The font color may only be used when the entire screen is printed as text.
		// Otherwise the text based parts should not be translated to match the other graphics patches.
		let tcolor = useGfx? Font.CR_UNTRANSLATED : content.mColor;

		Font printFont;
		Font textFont = generic_ui? NewSmallFont : content.mFont;
		int statsx = SP_STATSX;


		if (useGfx)
		{
			printFont = IntermissionFont;
			screen.DrawTexture (Kills, true, statsx, SP_STATSY, DTA_Clean, true);
			screen.DrawTexture (Items, true, statsx, SP_STATSY+lh, DTA_Clean, true);
			screen.DrawTexture (P_secret, true, statsx, SP_STATSY+2*lh, DTA_Clean, true);
			screen.DrawTexture (Timepic, true, SP_TIMEX, SP_TIMEY-2*lh, DTA_Clean, true);
			if (wbs.partime) screen.DrawTexture (Par, true, 160 + SP_TIMEX, SP_TIMEY-2*lh, DTA_Clean, true);
		}
		else
		{
			// Check if everything fits on the screen.
			String percentage = wi_percents? " 0000%" : " 0000/0000";
			int perc_width = textFont.StringWidth(percentage);
			int k_width = textFont.StringWidth("$TXT_IMKILLS");
			int i_width = textFont.StringWidth("$TXT_IMITEMS");
			int s_width = textFont.StringWidth("$TXT_IMSECRETS");
			int allwidth = max(k_width, i_width, s_width) + perc_width;
			if ((SP_STATSX*2 + allwidth) > 320)	// The content does not fit so adjust the position a bit.
			{
				statsx = max(0, (320 - allwidth) / 2);
			}

			printFont = generic_ui? IntermissionFont : BigFont;
			screen.DrawText (textFont, tcolor, statsx, SP_STATSY, "$TXT_IMKILLS", DTA_Clean, true);
			screen.DrawText (textFont, tcolor, statsx, SP_STATSY+lh, "$TXT_IMITEMS", DTA_Clean, true);
			screen.DrawText (textFont, tcolor, statsx, SP_STATSY+2*lh, "$TXT_IMSECRETS", DTA_Clean, true);
			screen.DrawText (textFont, tcolor, SP_TIMEX, SP_TIMEY-2*lh, "$TXT_IMTIME", DTA_Clean, true);
			if (wbs.partime) screen.DrawText (textFont, tcolor, 160 + SP_TIMEX, SP_TIMEY-2*lh, "$TXT_IMPAR", DTA_Clean, true);
		}
			 
		drawPercent (printFont, 320 - statsx, SP_STATSY, cnt_kills[0], wbs.maxkills, true, tcolor);
		drawPercent (printFont, 320 - statsx, SP_STATSY+lh, cnt_items[0], wbs.maxitems, true, tcolor);
		drawPercent (printFont, 320 - statsx, SP_STATSY+2*lh, cnt_secret[0], wbs.maxsecret, true, tcolor);
		drawTimeFont (printFont, 160 - SP_TIMEX, SP_TIMEY-2*lh, cnt_time, tcolor);
			 
		// This really sucks - not just by its message - and should have been removed long ago!
		// To avoid problems here, the "sucks" text only gets printed if the lump is present, this even applies to the text replacement.
			 
		if (cnt_time >= wbs.sucktime * 60 * 60 && wbs.sucktime > 0 && Sucks.IsValid())
		{ // "sucks"
			int x = 160 - SP_TIMEX;
			int y = SP_TIMEY;
			if (useGfx && TexMan.OkForLocalization(Sucks, "$TXT_IMSUCKS"))
			{
				let size = TexMan.GetScaledSize(Sucks);
				screen.DrawTexture (Sucks, true, x - size.X, y - size.Y - 2, DTA_Clean, true);
			}
			else
			{
				screen.DrawText (textFont, tColor, x  - printFont.StringWidth("$TXT_IMSUCKS"), y - printFont.GetHeight() - 2,	"$TXT_IMSUCKS", DTA_Clean, true);
			}
		}

		if (wi_showtotaltime)
		{
			 drawTimeFont (printFont, 160 - SP_TIMEX, SP_TIMEY-2*lh + lh, cnt_total_time, tcolor);
		}

		if (wbs.partime)
		{
			drawTimeFont (printFont, 320 - SP_TIMEX, SP_TIMEY-2*lh, cnt_par, tcolor);
		}
	}
}

Re: Change kerning of an existing DBIGFONT lump?

Posted: Tue Dec 28, 2021 1:24 pm
by Acts 19 quiz
So... good news/bad news. Good news is, you can adjust dbigfont kerning with dbigfont.lmp itself, not within GZDoom, font.inf, or whatever. After reading up on dbigfont and noting the bytes regarding kerning, I stumbled upon a helpful post. I was able to successfully take your original dbigfont and add kerning in the header--no artificial kerning needed. You can compare this one to your original in XVI32 or your hex editor of choice to see what I did and how to adjust it yourself if you want.

Bad news... well, look at the screenshots. The first one is the original dbigfont, and the second one has the adjusted kerning. Look at the level name--it looks like what you'd expect and want. Where it looks like you're running into trouble is with right-justified text (usually number fields). It looks like kerning isn't the answer here, though I wouldn't have any clue how to adjust this. Maybe with menu zscript, converting it to new-style Unicode with multiple lumps, adding left-side padding rather than right (like kerning), or perhaps changing dbigfont character spacing.

Someone with more knowledge working with imagetool/font2 would need to step in for that last part. Sorry if this isn't enough.

Re: Change kerning of an existing DBIGFONT lump?

Posted: Wed Dec 29, 2021 5:29 am
by Tormentor667
Thanks kindly for your support and the changes. Very interesting info, I think this should be documented somewhere on the wiki by the way.

Regarding the intermission screen: The problem is the right-aligned text if I understand that correctly. So making it left aligned would already solve the problem (by making it look worse)?