Page 6 of 16

Re: Test builds for 3.3.0

PostPosted: March 21st, 2020, 3:22 pm
by uckelman
Current state of things:

1. I have set up a VASSAL repo on github:

I had not been intending to do this for V3, on the assumption that by now we'd be working on V4; however, the work for V3.3 has reminded me of just how painful Subversion is in comparison with Git and I can't stand it anymore.

I'm not abandoning our svn repo, but the rest of the work I do for V3.3 is going to happen using git and then be pushed back to svn later.

The two branches in the git repo are master, which is the same as master in svn at present, and hdpi, which is where I'md going the HiDPI work.

2. Traditionally, one screen pixel has equaled one "user space" pixel. This changed when Apple introduced their "Retina" displays some years ago. On a Retina screen, each user-space pixel is twice as wide and twice as tall as a screen pixel---i.e., each user-space pixel corresponds to four screen pixels. Screens where user-space pixels correspond to multiple screen pixels are HiDPI screens.

Through Java 8, Java treated HiDPI displays as regular displays, which is why Java applications running in those versions of Java looked very small on HiDPI displays. Java 9 has HiDPI support for Swing components---a Swing application (as VASSAL is) running on Java 9 or later on a HiDPI display will look the right size, since the Swing components in Java 9 are drawn to allow for a difference betwen user and screen pixels. In order to accomplish this, how all the standard Swing components are drawn had to be modified. (Specifically, each component has to be aware that its user-space dimensions differ from its screen dimensions by a constant factor.) We get all this for free with the standard components when moving from Java 8 to Java 9---but we're stuck undertaking that work for any custom components we have which draw themselves. One such component is the map. There are no standard Swing components which are even remotely close to being able to handle displaying game maps.

3. With Java 8 on a HiDPI display, Swing applications are drawn at half scale. With Java 9 (or later) on a HiDPI display, Swing applications which haven't been updated for HiDPI have their custom components drawn at user-space size but then upscaled to fill the pixels, with predictably crappy looking results. This has the virtue of keeping the applications nominally functional, but makes anything your application draws quite blurry. The correct solution is to paint on the basis of how many screen pixels you have to fill, so that no upscaling occurs. To take a concrete example: If a map is being displayed at 25% zoom on a HiDPI display where each user-space pixel is four screen pixels, then we need to treat the map's zoom as 50% when drawing (25% map zoom * screen scale factor of 2).

That sounds simple, but in practice it is not---the reason being that drawing and component interaction had previously always taken place in the same coordinate space, so there are no indicators in the code for which are which, and coordinates originating from component interaction necesasrily get fed into drawing when doing things like dragging pieces.

4. So, if you look at, you'll find Map.View, which is the Swing component which displays the map. Map.View.paint(Graphics g) is the function which paints the map, and that's where we have to start.

That Graphics is actually a Graphics2D, so you can cast it to one and get an AffineTransform from it:

Code: Select all
  final Graphics2D g2d = (Graphics2D) g;
  final AffineTransform orig_t = g2d.getTransform();

If you're running Java 8 or using a display which is not HiDPI and you check the scale elements of the AffineTransform (using getScaleX(), getScaleY()), you'll find that they're 1.0. If you're using Java 9 or later on a HiDPI system, however (or setting the sun.java2d.uiScale property to simulate a HiDPI system---more on that later), you'll find that your scale elements are 2.0. Now we see how exactly Java 9 handles upscaling custom Swing components which haven't been modified for HiDPI support---it's the scale factor on the AffineTransform which does it.

So, how do we adjust this to avoid upscaling and get crisp drawing back? What we need to do is save the AffineTransform we're given and replace it with an indentity transform but then draw everything with an effective zoom that's our actual map zoom multiplied by the scale factor the original AffineTransform had.

In service of this, I've expanded the coordinate space transformation functions in Map to handle conversions to and from drawing coordinates, because we have to deal with three coordinate spaces now---map, component, AND drawing, whereas previously component and drawing coordinates were always identical. These functions all have names of the form "aToB", where "a" and "B" are coordinate spaces. E.g., componentToDrawing() converts component coordinates to drawing coordinates, while drawingToMap() converts drawing coordinates to map coordinates.)

Map.View.paint() doesn't do much itself, but there we convert the visible rectangle from component space to drawing space before passing it on to Map.paintRegion():

Code: Select all
  final Rectangle r = map.componentToDrawing(getVisibleRect());

Map.paintRegion() calls in succession the functions which clear the map border, paint the boards, and draw the pieces. What I've done in each of these is similar, so I'll take Map.drawBoardsInRegion() as an exmaple and omit discussion of the others.

Code: Select all
  public void drawBoardsInRegion(Graphics g,
                                 Rectangle visibleRect,
                                 Component c) {
    final double dzoom = getZoom() * os_scale;
    for (Board b : boards) {
      b.drawRegion(g, getLocation(b, dzoom), visibleRect, dzoom, c);

The change I've made is simply to the scale factor which gets passed on: It used to be Map.getZoom(), but is now getZoom() * os_scale (which is the HiDPI scale factor). That's it. Everything further down this call tree is expecting to be told a scale factor and to draw at that scale factor, so by adjusting the scale factor here, it does the right thing. (*This is not 100% true, I had to make a small modification in as well, but for most things we draw it is true.)

5. I've made a bunch of changes as in #4 which get us most of the way back to correct rendering. However, there are a few difficult components which involve both rendering and user interaction which are not yet done: GlobalMap, MenuDisplayer, PieceMover for sure; possibly also LOS_Thread, FreeRotator, MapCenterer.

In order to troubleshoot these, you need to run with Java 9 or later, and either use a HiDPI display OR set the sun.java2d.uiScale property to force Java to upscale your UI. The following has been my test setup:

Code: Select all
  java -classpath lib/Vengine.jar --add-exports java.desktop/sun.java2d.cmm=ALL-UNNAMED -Dsun.java2d.uiScale=2 VASSAL.launch.Player --standalone ../mods/The_caucasus_campaign_1_2_1.vmod

(Note that 2 is likely the only value which makese sense for uiScale. 1 is just normal, so you won't be able to troubleshoot that way. Non-integers seem not to work, and anyhow would be awful for aliasing if they did. 3 is way too huge.)

Particular problems:

* GlobalMap is very broken. It needs a complete read-through.
* MenuDisplayer handles showing context menus when you right-click. The problem to solve here is that the map jumps when you right-click under HiDPI.
* PieceMover handles piece drags, among other things. The problem here is incorrect repainting behind drags.

There are likely to be other problems I have yet to find. I'd appreciate being made aware of those and shown how to reproduce them.

6. If you'd like to help with this, clone the git repo and start reading through the relevant code.

Re: Test builds for 3.3.0

PostPosted: March 21st, 2020, 8:56 pm
by AlisterMcLane
Baseline : git commit id 29c901de8cfd8a93cd144a3d509d1f021b55e57c

I could not do a proper compile of ImageIOImageLoader due to a missing class named sun.java2d.cmm.ProfileDeferralMgr.

Well I ran the tests on my Windows Box with different JDKs and I noticed these things

TileToImageTest :: testTileToImage - differs but image looks the same
-> maybe read in.png and out.png again and compare the loaded Image ?

ProcessCallableTest :: testNormal differs by 1 byte (longer on windows) and the test contains '\n' sequences so most likely OS dependent test.

- may be required due to using make.
- IDE integration (here Eclipse) complains about its presence.

Re: Test builds for 3.3.0

PostPosted: March 21st, 2020, 9:12 pm
by AlisterMcLane
Baseline : git commit id 7255ef7cadb977f0d3b86ab6499def27ec224760

Situation is basically the same, but when running the tests on Java 14
TileToImageTest :: testTileToImage is green.

Re: Test builds for 3.3.0

PostPosted: March 21st, 2020, 11:39 pm
by AlisterMcLane
Here is an observation on the code:

A lot of felt weight comes from dispersed explicit low-level math.
Basically we have a super tight coupling with Framework code.
So these calculations are treated 2nd class compared to libary code.

Decoupling stuff and treating 2d-Math as the core-domain of Vassal-the-UI-Library will help.
We are talking about Vassal specific representations of Point, Rectangle or Dimenions, etc.

I would start with Vassal.internal.math.Rectangle2D class as there is a lot of drawing / collission code that can be moved to a dedicated spot. Once that is out of the way a clearer picture will emerge.

Seamless integration is key. So being able to "cast" between Vassal / AWT / Swing types is crucial.
So getting back to AWT / Swing should be a simple .toAWT() or .toSwing() call on the Vassal-Object.
Active refactorings will quickly make the actual functionality emerge - so don't worry too much about it.

Unless we're talking about FULL images the memory offset is effectively neglectible.
However there are significant effects to development speed due to readability, testability and comfort.

I had multiple instances where performing such changes had multiple positive effects at the same time that sound contradicting in the first place:
- reduced technical complexity of an application code
- extending feature-complexity drastically
- performance gains - probably because the Hotspot JVM Compiler kicked in for the first time

Re: Test builds for 3.3.0

PostPosted: March 22nd, 2020, 11:51 pm
by uckelman
I've fixed the problems with display of context menus and repainting while dragging and scrolling (which I thought were with MenuDisplayer and PieceMover, but turned out to be due to an oversight in handling the AffineTransform in Map.View.paint()).

Left to fix are GlobalMap, LOS_Thread, FreeRotator.

Re: Test builds for 3.3.0

PostPosted: March 23rd, 2020, 12:21 am
by uckelman
GlobalMap is fixed now.

Re: Test builds for 3.3.0

PostPosted: March 23rd, 2020, 10:07 pm
by uckelman
FreeRotator is fixed now.

Re: Test builds for 3.3.0

PostPosted: March 25th, 2020, 10:36 pm
by AlisterMcLane
Started looking at PieceMover, however it is quite a beast to understand.

Re: Test builds for 3.3.0

PostPosted: March 25th, 2020, 11:12 pm
by uckelman
Thus spake AlisterMcLane via messages:
> Started looking at PieceMover, however it is quite a beast to
> understand.

No need. It turned out that there was nothing to fix in PieceMover.

What's on the hdpi branch presently has fixes for every problem I've
found save for the repaint problem in LOS_Thread I'm working on at
the moment.


Re: Test builds for 3.3.0

PostPosted: March 26th, 2020, 12:40 am
by uckelman
I've now fixed every HiDPI problem I've seen.

Please try the 3.3.0-svn9303 builds here:

Re: Test builds for 3.3.0

PostPosted: March 26th, 2020, 11:11 pm
by uckelman
New test build: 3.3.0-svn9324.

Please give this a try. This needs some testing with a variety of modules before we can release it as 3.3.0. I am not confident that I caught all of the HiDPI problems, so if you find a rendering bug and you're using a HiDPI display, PLEASE let me know what it was and how to reproduce it.

Re: Test builds for 3.3.0

PostPosted: March 27th, 2020, 11:15 am
by burzum51

Is the supposed to work on mac ? i tried the launch "ModuleManager" the module start i see the module windows and then the app close itself with no errors.

Re: Test builds for 3.3.0

PostPosted: March 27th, 2020, 11:25 am
by uckelman
Thus spake burzum51:
> Hi,
> Is the[1] supposed to work on mac ? i
> tried the launch "ModuleManager" the module start i see the module
> windows and then the app close itself with no errors.

(That's the link to the page on github btw, not to the test builds.)

We need more details about what exactly you're doing to be able to say
whether it should work.

* What are you running?
* How are you runniung it?
* What's in the errorLog after it fails?


Re: Test builds for 3.3.0

PostPosted: March 27th, 2020, 12:05 pm
by burzum51
I would like to try to run vassal is nthe lastest build to check my eclipse conf.

Il run the main of the "ModuleManager" class in ecplise with JDK 14 on an mac os.

I have no error log and don't know if the is a log file supposed to be somewhere

Re: Test builds for 3.3.0

PostPosted: March 27th, 2020, 12:35 pm
by burzum51
nevermind it's working.