Resolution Switching (NUI)

Howdy all. Supporting 3 resolutions has now become the bane of my project and it’s driving me nuts. I’m starting to wonder if I’m going about this the best way.



Basically to change resolutions I use recreateWindow to change the resolution and then setLocalScale on the rootNode. A few of the issues that have arisen are that:



A. The scaling is dependent on the initial screen resolution. This is not a major problem as I just keep track of the current and initial resolutions.



B. When scaling with the nui stuff the screen may scale correctly but the hotspots for buttons seem to be skewed off to the side of the actual button.



I had everything working well prior to the nui stuff, but I feel like I’m back at square one now with things scaling all screwy. For example, when I switch resolutions the gui scales but there are black spaces at the top of the screen and what was previously the bottom extent of my screen now seems to be about 200 pixels below the bottom edge of the monitor.



I know it has been suggested to just nail things to the edges of the screen and let things scale, but my interface design requires that things be placed very tightly in relation to one another.



Anyway, any suggestions or tips or thoughts as to why the nui stuff might not work with the method I outlined above, would be appreciated.

Don’t give up Slowdive.



The reason you are having problems with nui is that the Absolute Layout Manager and the _layout members of the UIWindow based components have been layed out at a particular resolution.



Since OpenGL (or at least jME’s usage of OpenGL) uses a origin at the lower left of the screen and NUI and all other GUI interfaces (and thus NUI) use an origin at the upper left the layout manager has translated all the coordinates from one set to another.



Also, don’t scale NUI nodes. I’m not supprised that it doesn’t work. Window location and layout information is stored outside of the actual node that renders. This is because there may be an aggegation of nodes for each window.



The only way to get properly scaled UI is to create your own layout manager. Right now the AbsoluteLayoutManger is very simple. It truly just puts things where you tell it on a pixel by pixel basis. I’m working on a GridBagLayoutManager, but I’m a little behind right now.



You could even derrive from the AbsoluteLM into your own where you scale the incomming layouts based on a ‘standard’ resolution. (Call it AbsoluteLM++ :wink: ) If you position all the components based on say a 800x600 resolution then you’d just scale all x values by CurrentXResolution/800 and y values by CurrentYResolution/600. I think you get the math…



I also need to finish the code that’ll check for screen re-sizes (along with all UIFrameWindow resizes) and re-call window layout. … That one is comming.



Also, it’s a good idea to recreate everything from your xml when you resize. I figure that really resetting resolution is actually something that happens maybe twice for each of your users… as they figure out what the best resolution is for their particular hardware. Thus it’s not a big drawback to wait a couple seconds while you rebuild your gui node tree.



Finally, feel free to create some more layout managers! I can always use the help.



And, once again Slowdive, thanks for testing! I hope this helps.

Guurk,



Thanks for the quick response. I took your advice and wrote my own layoutManager, however I think there’s a bug that lies somewhere in the NUI code and I’ll be damned if I can find it. Here’s what’s happening:



My UI is layed out at 1600x1200, I startup my game at 1024x768 and hope that the layout manager will adjust everything. I have 4 quads that makeup my main interface background. Here’s the setup for the first one in the lower left corner:


 ip1 = new UIImagePanel( _controlFrame, "MenuState", "main1", "", new Float( 0.0f), new Float( 176.0f), new Float( 1024.0f), new Float( 1024.0f) );



The layout manager seems to scale the width correctly for the new resolution, but the height exceeds the height of the screen at 768. However, if I turn off my scaling calculations and manually do it, changing the above to:

ip1 = new UIImagePanel( _controlFrame, "MenuState", "main1", "", new Float( 0.0f), new Float( 113.0f), new Float( 655.0f), new Float( 655.0f) );
       



It scales the quad correctly. So I go into the layoutManager and look at what values were being passed to UIRect in the first example vs the second example and what do you know, they're the exact same values that I explicitly pass in during the second example.

In other words, it seems like NUI is using the _height and _width without reference to the layout manager somewhere. But the only places I could find it doing that are in the text stuff, which I know is incomplete and should have no bearing on a UIImagePanel.

So I'm at a bit of a loss. Does this sound like a bug to you? The layout manager is straight forward enough that I don't think the problem is there.

Could this issue be in UIScheme? It doesn’t seem to be referencing the layoutManager.

I believe (I don’t have the code right in front of me right now) that you need to adjust for the quad location maybe.



Remember that the job of a LayoutManager is to translate from OpenGL coordinates to Screen Coordinates.



Not only do you have to use a different coordinate set, but you also have to account for the quad’s location relative to the screen layout.



In UI layouts the upper left corner of a window is where things are drawn from. In jME things are drawn based on the center.



So, if things are off the screen into the positive (OpenGL based) direction (off the top) then it’s probably because you need to subtract half the height from the y.



Just a quick thought. If you still have problems… or for that matter if you get it working, post the code of your layout manager. I’ll include it in the next build of NUI, with full credits of course :).

I guess my explaination was a bit incorrect above. I wasn’t passing the values in the second example directly to UIRect. I left in the code from your layoutManager and basically just passed them to that. So it looks something like (this is a bit simplified for only one resolution):


            
              xScaled = Math.round(x * 0.64f);
              yScaled = Math.round(y * 0.64f);
              wScaled = Math.round(width * 0.64f);
              hScaled = Math.round(height * 0.64f);
             
        if( parentLayout == null) {
            // parent is the controlframe
            retval = new UIRect( xScaled + wScaled / 2, _display.getHeight() - yScaled - hScaled / 2, wScaled, hScaled);
        } else {
            retval = new UIRect( xScaled + wScaled / 2 - parentLayout._width / 2, -yScaled - hScaled / 2
                    + parentLayout._height / 2, wScaled, hScaled);
        }



Since all I really want to do differently with my layout manager is to scale the coordinates and size of the components from the original 1600x1200 res, this should suffice from what I can tell, however it's just not working properly.

I've actually decided to abandon using the layout manager and just use couple of static methods that just scale height and width on component creation and then rebuild the tree when a user switches resolutions. It's a bit kludgy, but it works.

If you find anything about UIScheme not referencing the layoutManager, lemme know. I think that's where the bug is.

No worries. It was just driving me crazy so I had to move on. :wink:



I look forward to seeing what you come up with.

Oh, one other minor thing, it would be great if you could switch the mip mapping in UIScheme from MM_Nearest to MM_Linear to allow for nice looking anti-aliased resizing of graphics.