I am trying to develop SVG based scalable counters for the VASL module and cannot seem to find a way to embed the fonts used on the counters. Ideally I would have one copy of the fonts within the module that can be used by all the counters. Unfortunately I can’t seem to find a valid way to do this. I would love to discuss it with any module developers who have done so or are working on a module doing so.
I would advise against using SVGs anywhere in a VASSAL module. Java’s rendering of SVG is really slow. It is better, performance-wise, to make slightly higher resolution PNGs.
It is kind of unfortunate that Java is so slow at rendering SVGs. It would be nice to use them for boards, counters, etc.
In general, one can say that
Vector graphics is great when developing and for flexibility, but you pay a price at run-time
Raster graphics is a hassle for development and has far less flexibility, but are fast at run-time
In other words, I think the best strategy is to use SVG to develop with, and then build raster images from those, possibly using custom tools to make these raster images. That will give you the best of both worlds.
Data that is needed at runtime generally need to be in the .vmod file - which is really just a ZIP archive. You can use any decent ZIP tool to add your font files to the module file.
However, the SVG rendering engine needs to know where to find the font files (presumably OTF or TTF), and it may be that it will not look inside the archive. Thus, if you need to set the font-loading path to include the archive, you will most likely need to add some custom Java code to your module file, and make sure it gets executed. Perhaps something a la (code not checked!)
public class FontPathSetter extends AbstractBuildable
{
public String getAttributeValueString(String key) {return "";}
public void setAttribute(String key, Object value) {}
public String[] getAttributeNames() { return [];}
@Override public void build(Element e) {
if (e == null) {
return;
}
this.setFontLoadPath();
Builder.build(e, this);
}
protected void setFontLoadPath() {
// Do something that sets the SVG renderer's font load path
}
}
and then add an element of that type to the buildFile.xml document
<FontPathSetter />
Note that many fonts have rather restrictive licenses, and you are often not allowed to redistribute fonts without express permission.
This is not accurate w/r/t performance. SVG is rendered once by Vassal and then cached; there is no difference in performance on subsequent draws to the screen between raster and vector images.
If I have to look into what the right approach is, I will, but I won’t do it before the game library conversion is finished, so you could be waiting a month or more.
I believe you said elsewhere that counters are not cached - only boards. Or did I misunderstand?
Nevertheless, rendering the SVGs by Java takes a long time, so even if the counter images are cached, you will still be hit by the rendering time when the module loads (possibly only the first time). A raster image can be directly cached (no rendering step - except, perhaps, scaling).
I tried a couple of times to use SVGs in VASSAL modules - even smaller ones - but the overhead was too big, so I reverted back to PNGs. To me, it’s not a big issue because the images are generated by LaTeX code where I have all the flexibility I need
Another tool for generating NATO App6 counters is Pelle Nilsson’s Inkscapecounter-sheet extension (Pelle also has a hex-map extension). It takse a spreadsheet (as comma-separated-values - or CSV) input file and generates counters using Inkscape (a free and open SVG editor). One can then export to a PNG from Inkscape.
Aside
If you’re really into coding things, you could use my Python module pywargame together with this to generate the module from external sources
A CSV file containing the counter description. This is read by Inkscape with the above extension to make the individual PNGs for the counters. The CSV file is also read by a Python script using the pywargame module, to define the pieces in the module.
Some SVG of the board(s), possibly using the above mentioned hex-map extension, that is processed by Inkscape to make the board PNG(s). The Python script can read in settings from the sources of that SVG to configure the board in the module.
In the Python script, you use the pywargame API to define the various components of the module, including piece traits, global key commands, turn tracker, and so on.
This is what I do, except that I start from LaTeX sources using my wargame package
Maybe this hits different at bigger orders of magnitude, but I’ve used SVG extensively for years and never noticed any kind of slowness or had any reported to me. If there is some, maybe it’s in fractions of a second–really not remotely a big deal. But this is for modules containing some hundreds of SVG assets, not many thousands.
Compared to the PNG version, the SVG version takes a loong time to load, and I needed to increase the JVM heap size to a god-awful big number. Zooming in or out also takes some time. However, it is also clear that the images are cached (in a lot of memory), as the going back to a previous zoom-level is fast.
Using this module with SVGs makes VASSAL take up a lot of memory - way more than needed even with very high resolution PNGs.
Granted, the board is a relatively big SVG - some 88MB unpacked - and does have a fair bunch of “clip” paths. Granted, not the simplest SVG. Also, the Java SVG renderer did not take the global transform="scale(2)" into account. However, I don’t think the board image is all that complicated wrt what one could expect from a larger game.
Are SVGs tiles cached on-disk too? It doesn’t seem like it.
My personal take is, that SVGs are not worth the runtime hassle. But, of course, I generate the PNGs from a much more flexible format (LaTeX) so I get the best of both worlds - development flexibility and runtime speed and low resource use
I would not recommend using SVG for maps in V3. My recommendation will change for that with V4, because the renderer won’t be the same in V4. Batik, the SVG renderer in use for V3, appears to be receiving maintenance only for some years now, so I don’t expect it to ever improve; there are no other options I know of for rendering SVG in Java that are as complete as Batik, and I see no one volunteering to do the work to test any if we had one in hand. Secondly, SVG maps aren’t tiled to disk—they’re the one image type which isn’t tiled to disk first when used as a map. The reason for this is that tiles for intermediate scale factors are cobbled from on-disk ones, and doing so for SVG would degrade the image quality. SVG map tiles are rendered directly, by setting an area of interest for the renderer and then rendering just that area. If Batik isn’t very fast at rendering reduced areas, that’s probably why you’re seeing the behavior you’re seeing.
However, the question here is not about using SVG for maps. The question is about using SVG for pieces. Pieces are tiny and uncomplicated in comparison with maps. You won’t see the problems you cited with pieces.
I don’t think the slow-down is with “reduced areas”. The test module starts up with the board fully visible, so that doesn’t seem to be the problem. Granted, it could be the problem when zooming in, but I also saw slow-down when zooming out. Maybe the Batik is just really slow
I guess it, to some extend, depends on the number of pieces and their complexity. For example, it could be attractive to change piece images on-the-fly (f.ex. by applying style-sheets), or if multiple SVGs are overlayed via layer traits, and so on. The problem with Batik is probably more fundamental than that.
For the font question, perhaps it’s worth looking into ttf2svg from Batik, which converts a TTF to SVG font that can be embedded in the SVGs. Perhaps also look here and here. That is, it seems one can generate an SVG font from some file content via org.apache.batik.svggen.font.Font, which I then guess can be made available to the SVG rendering part.
There has been some experimental work I’m not making available because I don’t want to get diverted answering questions about it. The game library service is the part of V4 that’s publicly available right now, and I’m not devoting time to anything else before that’s finished.
If I’m not going fast enough for you, there are module pages to be rechecked.
Cairo is a native library. How are you going to deal with packaging it so that it works everywhere? Feel free to give it a try, but that’s a problem you’d have to solve for Cairo to be viable.
Does anyone know if there is a way to force SVG/Java/VASSAL to use ONLY glyphs from the specified fonts and to not fall back to a glyph that’s available in a system font? I want to ensure that that glyphs being used are actually from the font that I’m trying to use. TIA