-
-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue #726: Adding a Font generator to the plugin #731
Conversation
Hi, I'm just seeing this PR, I may take a look at it tonight.
For the 4th item, here is what I've done on my PoC :
|
Hey @mprevel! Thanks again for the idea / PoC! Let me walk through your points (quickly, I'm on my lunch break.. 😄 ). These are just my current opinions, not set in stone. Opposing views are welcome.
Yes, as with all the generators the idea is that you can call them as many times as you like with different params. E.g. same font different chars, same chars different font, same font same chars different size, etc. Keep it simple, make it the user's problem to decide how to make use of it.
Undecided, I was wondering about this too. We can do that, but it isn't a requirement for WebGL 2. WebGL 1 needs pow2 image sizes but Indigo's WebGL 1 support is poor at best. However if we did want this, there are two approaches: a. Do the current process, then expand to a pow2 size. Inefficient, will probably lead to lots of empty space, but the implementation is trivial. b. Build a process that reorganises the chars to attempt to fit a pow2 size. Not difficult but more work.
Yes indeed, quite right. I've ignored the problem in the code so far, but it's an issue I had to deal with in the roguelike starterkit too. Thanks for the code sample.
Trying to read that code quickly, apologies if I've misunderstood. I guess you mean for allowing the user to specify character ranges? I was going to leave that to the user. In the good old days of Flash, you could provide things like "all ASCII chars" or "abcde12345" and those where the chars that got embedded.
Can do, but don't forget the user can also do this in their game code, and there's a funny interplay here between what we generate and what we're given. For example, if you user asks for "abc" chars... I assume they literally mean those chars in lower case, rather than "abc" and also "ABC". So I'm tempted to say that we should always embed case sensitive...? |
That's a good point, it's about font but also size, font color, bg color, and so on.
You're welcome.
It's about the way the user sets the expected characters, the way they are handled by the image generator and the code generation for the font info.
I think we agree. I mean that the current default value for font info is |
I've done a bit more work, the point of use now looks like this (taken from the simplistic test I wrote): val options: FontOptions =
FontOptions("my font", 16, List(' ', 'a', 'b', 'c'))
.withMaxCharactersPerLine(16)
.noAntiAliasing
val files =
IndigoGenerators("com.example.test")
.embedFont("MyFont", sourceFontTTF, options)
.toSourcePaths(targetDir) Going to work on that clunky list next and make it easier to express which characters you want. |
However, the above generates these: package com.example.test
import indigo.*
// DO NOT EDIT: Generated by Indigo.
object MyFont {
val fontKey: FontKey = FontKey("my font")
val fontInfo: FontInfo =
FontInfo(
fontKey,
36,
17,
FontChar(" ", 0, 0, 9, 17)
).isCaseSensitive
.addChars(
Batch(
FontChar(" ", 0, 0, 9, 17),
FontChar("a", 9, 0, 9, 17),
FontChar("b", 18, 0, 9, 17),
FontChar("c", 27, 0, 9, 17)
)
)
} |
This API looks good to me.
I don't know if there is something to do for this List since it can be built easily with a " abc".toList or ('a' to 'c').toList ::: List(' '), ... So IMO, it is good like this. Nonetheless, an alternative constructor could allow to use a string if preferred. About the code generation I was a bit misleaded by the current method ".isCaseSensitive" that looks like an accessor to a boolean value, otherwise it seems good. I just have questions about colors. |
Yeah it is a poor naming decision that I made at the dawn of time when the world was young. 🤷 😄 Regarding colours, I think there's two things you may be suggesting in there - unless I've misread:
Transparent characters is an interesting idea as it allows some small efficiency gain in the engine if you know that your font is always one fix transparency. But otherwise, you can do this in Indigo itself just by choosing a different material. Background colours I'm not sure about (particularly in combination with transparent chars). Can we fill the background a solid colour? I'm sure we can. However, Indigo is not expecting it, and I fear you might end up with strange artefacts and gaps between letters or misaligned top / bottom edges and so on. Also you can always draw your In both cases there are simple workarounds, so for now I think I'm inclined to keep it as is, make it work, get it out there and get feedback. I do want to work on the character range constructors a bit more though. I think something like this might be nice (made up, horrible names): enum CharRange:
case Exact(chars: String)
case FromTo(from: Int, to: Int)
case CharFromTo(from: Char, to: Char)
case Codes(chars: Array[Char])
..etc..
object CharRange:
val ASCII ...
val EXTENDED_ASCII ...
..etc... Although possibly rather than an ADT, these are all just constructors of the range type. Not sure yet, but I think this is the bit that needs options to let people express themselves easily. |
Getting there, but as you correctly pointed out, there's a bunch of unrepresentable characters. FontOptions("my font", 16, CharSet.ASCII)
.withMaxCharactersPerLine(16)
.noAntiAliasing Seems like a fundamental flaw with the |
I think I'm there: Test case: val options: FontOptions =
FontOptions("my font", 16, CharSet.Alphanumeric)
.withColor(RGB.Green)
.withMaxCharactersPerLine(16)
.noAntiAliasing
val files =
IndigoGenerators("com.example.test")
.embedFont("MyFont", sourceFontTTF, options, targetDir / Generators.OutputDirName / "images")
.toSourcePaths(targetDir) Font sheet:
package com.example.test
import indigo.*
// DO NOT EDIT: Generated by Indigo.
object MyFont {
val fontKey: FontKey = FontKey("my font")
val fontInfo: FontInfo =
FontInfo(
fontKey,
151,
68,
FontChar(" ", 129, 51, 9, 17)
).isCaseSensitive
.addChars(
Batch(
FontChar("a", 0, 0, 9, 17),
FontChar("b", 9, 0, 9, 17),
FontChar("c", 18, 0, 9, 17),
FontChar("d", 27, 0, 9, 17),
FontChar("e", 36, 0, 9, 17),
FontChar("f", 45, 0, 9, 17),
FontChar("g", 54, 0, 9, 17),
FontChar("h", 63, 0, 10, 17),
FontChar("i", 73, 0, 9, 17),
FontChar("j", 82, 0, 9, 17),
FontChar("k", 91, 0, 9, 17),
FontChar("l", 100, 0, 9, 17),
FontChar("m", 109, 0, 10, 17),
FontChar("n", 119, 0, 10, 17),
FontChar("o", 129, 0, 9, 17),
FontChar("p", 138, 0, 9, 17),
FontChar("q", 0, 17, 10, 17),
FontChar("r", 10, 17, 9, 17),
FontChar("s", 19, 17, 9, 17),
FontChar("t", 28, 17, 9, 17),
FontChar("u", 37, 17, 10, 17),
FontChar("v", 47, 17, 10, 17),
FontChar("w", 57, 17, 10, 17),
FontChar("x", 67, 17, 9, 17),
FontChar("y", 76, 17, 9, 17),
FontChar("z", 85, 17, 9, 17),
FontChar("A", 94, 17, 10, 17),
FontChar("B", 104, 17, 9, 17),
FontChar("C", 113, 17, 9, 17),
FontChar("D", 122, 17, 9, 17),
FontChar("E", 131, 17, 9, 17),
FontChar("F", 140, 17, 9, 17),
FontChar("G", 0, 34, 10, 17),
FontChar("H", 10, 34, 10, 17),
FontChar("I", 20, 34, 9, 17),
FontChar("J", 29, 34, 9, 17),
FontChar("K", 38, 34, 9, 17),
FontChar("L", 47, 34, 9, 17),
FontChar("M", 56, 34, 10, 17),
FontChar("N", 66, 34, 10, 17),
FontChar("O", 76, 34, 9, 17),
FontChar("P", 85, 34, 9, 17),
FontChar("Q", 94, 34, 10, 17),
FontChar("R", 104, 34, 9, 17),
FontChar("S", 113, 34, 9, 17),
FontChar("T", 122, 34, 9, 17),
FontChar("U", 131, 34, 10, 17),
FontChar("V", 141, 34, 10, 17),
FontChar("W", 0, 51, 10, 17),
FontChar("X", 10, 51, 9, 17),
FontChar("Y", 19, 51, 10, 17),
FontChar("Z", 29, 51, 9, 17),
FontChar("0", 38, 51, 9, 17),
FontChar("1", 47, 51, 9, 17),
FontChar("2", 56, 51, 9, 17),
FontChar("3", 65, 51, 9, 17),
FontChar("4", 74, 51, 9, 17),
FontChar("5", 83, 51, 9, 17),
FontChar("6", 92, 51, 9, 17),
FontChar("7", 101, 51, 10, 17),
FontChar("8", 111, 51, 9, 17),
FontChar("9", 120, 51, 9, 17),
FontChar(" ", 129, 51, 9, 17)
)
)
} |
So the only thing left to resolve is that the package aliases aren't working. I always get this bit wrong, somehow. 😅 Luckily it's gone in Scala 3, but here we are in 2.12 because sbt. Oh well. Note: Compile / sourceGenerators += Def.task {
IndigoGenerators("example")
.embedFont(
"TestFont",
os.pwd / "sandbox" / "assets" / "fonts" / "pixelated.ttf",
indigoplugin.generators
.FontOptions(
"test font",
32,
indigoplugin.generators.CharSet.fromUniqueString("The quick brown fox\njumps over the\nlazy dog.")
)
.withColor(indigoplugin.generators.RGB.White)
.withMaxCharactersPerLine(16)
.noAntiAliasing,
os.pwd / "sandbox" / "assets" / "generated"
)
.toSourceFiles((Compile / sourceManaged).value)
} |
s"""FontChar("$c", $x, $y, $w, $h)""" | ||
} | ||
|
||
def filterUnsupportedChars(c: Char, code: Int): Boolean = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If my understanding is good, these characters are not included in the font sheet.
Maybe all the control characters, so codes from 0 to 31 should be excluded?
Or is there a use case for some of them?
After some googling, it seems that some fonts have such kind of support but it seems to be very specific :
https://graphicdesign.stackexchange.com/questions/57352/font-for-representing-unicode-non-printable-characters
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I don't know, honestly.
I'm at the point with this where this improvement adds a lot of value - imperfect as it is - and I think I'm just going to unleash it into the wild and wait for the issues to emerge that help shape it's future direction.
No description provided.