Dynamic GUI size

Get technical support about the C++ source code and about Lua scripts for maps, entities, GUIs, the console, materials, etc. Also covered are the Cafu libraries and APIs, as well as compiling, linking, and the build system.
User avatar
Haimi
Posts:85
Joined:2011-11-23, 09:28
Dynamic GUI size

Post by Haimi » 2012-03-07, 18:43

Hi @ll,

i was trying to make my GUI set its Size dynamically by using the Console variables dlg_clWindowSizex and dlg_clWindowSizeY but I got the following Problems:
  • constant screen size in GuiSys/Gui.hpp:

    Code: Select all

    const float VIRTUAL_SCREEN_SIZE_X=1024.0f;
    const float VIRTUAL_SCREEN_SIZE_Y=768.0f;
    
    and when I try to make it static and set it in the Gui C'tor, I get unused-variable warnings. Could this be easily rewritten to set the real size instad of using constants?
  • Is it really the best way to get the Window Size from the Console variables or is there a better way? Maybe the wxWindow knows hob big it is currently... maybe we can build a WindowT:OnScreenSizeChange() Method where the GUI elements with dynamic size may be redrawn. I already managed dynamic GUI sizing and positioning by using the console varibles from the cgui scripts... here my little helper method:

    Code: Select all

    function GetGuiSize()
        return ci.GetValue("dlg_clWindowSizeX"), ci.SetValue("dlg_clWindowSizeY"); 
    end
    and it can be simply used e.g. like this: self:set("rect", 0, 0, GetGuiSize()); and this works perfectly!
Project Status: Code architecture definition
6 Programmers, 1 Photographer, 1 Architect, 1 Game designer
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: Dynamic GUI size

Post by Carsten » 2012-03-07, 23:25

Haimi wrote:i was trying to make my GUI set its Size dynamically
Why would you want to do that?

Note that the constants in GuiSys/Gui.hpp in fact allow you to work with resolution independent GUIs: they work with any screen resolution and window size.
(0; 0) is the top left, (640; 480) the bottom right. Always.

If you'd want to change these numbers, they'd have to be saved along with each GUI in the *.cgui files, but you'd still gain nothing.
  • Is it really the best way to get the Window Size from the Console variables or is there a better way? Maybe the wxWindow knows hob big it is currently...
Yes, it does: have a look at MainCanvasT::TakeScreenshot() for example use of the GetClientSize() method.
maybe we can build a WindowT:OnScreenSizeChange() Method where the GUI elements with dynamic size may be redrawn.
Well, either I totally misunderstood your question, or as indicated above, there is no need for this:
Consider e.g. the Main Menu. It's full-screen, always. No matter what resolution or window size you set, it always fills the window. 640 is 100% in horizontal direction, 480 is 100% in vertical direction.
Best regards,
Carsten
User avatar
Haimi
Posts:85
Joined:2011-11-23, 09:28

Re: Dynamic GUI size

Post by Haimi » 2012-03-08, 12:01

Okay, let's assume that I don't change the size... is it possible that I can create real quadratic GUI elements? I have my icon images that are quadratic and I want them to be used ingame with my draggable window implementation. Is this possible on a widescreen display?
Project Status: Code architecture definition
6 Programmers, 1 Photographer, 1 Architect, 1 Game designer
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: Dynamic GUI size

Post by Carsten » 2012-03-09, 12:02

Ah, ok, this is a problem that we have no conclusive solution for, and I'm planning to look into it in combination with http://trac.cafu.de/ticket/69

That is, in the long term, we might scale the 640*480 virtual screen only as much as it's aspect ratio can be preserved. The then possibly black areas would be filled with content by specifying windows at negative coordinates, or positive coordinates beyond 640.

For a short term solution, you could use the GetClientSize() method in order to learn how much the physical aspect ratio differs from 4:3 (640:480). Pass this factor to your GUI, and adjust the side lengths of your windows accordingly.
Best regards,
Carsten
HWGuy
Posts:95
Joined:2011-05-31, 07:37

Re: Dynamic GUI size

Post by HWGuy » 2012-03-09, 12:26

A big and simple improvement to the GUI system would be to change from 640*480 screen space scaled to a floating point.
0,0 being the middle, 1,1 top right, -1,-1 bottom left.
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: Dynamic GUI size

Post by Carsten » 2012-03-10, 03:07

HWGuy wrote:A big and simple improvement to the GUI system would be to change from 640*480 screen space scaled to a floating point.
0,0 being the middle, 1,1 top right, -1,-1 bottom left.
Uh... why?
I guess we'd just have the same problem with different numbers.

I also wonder if it is actually possible to solve this problem in all cases:

For example, if the user sets a 4:3 resolution (e.g. 1024*768 or 640*480) on a 16:9 screen, then the 4:3 == 12:9 would obviously be scaled horizontally by a factor of 16/12 == 4/3 to match the width of the screen, yielding non-square pixels.
As a result, it is the users responsibility to set only display resolutions that match the physical aspect ratio of his screen. If he doesn't, there will be distortion -- without anyone the wiser.
In fact, neither the Cafu engine nor the OS can reliably know the physical dimensions of the attached screen. For example, Win7 allows me to set a resolution of 800*600 on my 16:10 display. "Rage" by id Software addresses the problem by explicitly stating the proportions next to the resolutions in the video menu, e.g. "1024*768 [4:3]".

Finally, under the assumption that the user has set a good resolution with square pixels, in the next step we face a very similar problem with our virtual GUI windows. Now we do know both the true physical size (learned e.g. from GetClientSize()), as well as the (virtual GUI) window size, which is proportional to 640:480. That is, if GetClientSize() returns 1920:1200 == 16:10, making our 640:480 == 13,3333:10 match involves implicit scaling in horizontal direction by factor 16/13,3333 == 1,2.
(This, or in fact its inverse, is also the factor that Haimi'd need if he implemented my above suggested "short term solution".)

Unfortunately, this is not the end of the story. In some cases, instead of all the above, we may want to specify render coordinates in true, physical pixels, just as reported by GetClientSize(). This is helpful e.g. for rendering text perfectly, with sharp, crisp contours. The size of such text would vary with screen resolution, but for some use cases, that might be acceptable.

How exactly this is best implemented I've not yet fully thought through, but I hope you can see that the solution to the problem is not a simple matter of changing the virtual GUI size, the scales, or the numbering system.
Best regards,
Carsten
HWGuy
Posts:95
Joined:2011-05-31, 07:37

Re: Dynamic GUI size

Post by HWGuy » 2012-03-10, 11:26

I said you should change to float because 640x480 is too low a resolution for modern GUI design which is almost always developed for 1024x768 and 1920x1080.
Could you at least change it to 1024x768 in the meantime, I haven't looked at the GUI code but I'm guessing that's a matter of changing 2 constants.

What about hook based? The float method above and "distance from points" are pretty much the primary ways every GUI is laid out these days.
User avatar
Haimi
Posts:85
Joined:2011-11-23, 09:28

Re: Dynamic GUI size

Post by Haimi » 2012-03-10, 12:48

Could you at least change it to 1024x768 in the meantime, I haven't looked at the GUI code but I'm guessing that's a matter of changing 2 constants.
It is a little more change, but I already changed the size to 1024x768. I could send you a patch if you like.
Project Status: Code architecture definition
6 Programmers, 1 Photographer, 1 Architect, 1 Game designer
HWGuy
Posts:95
Joined:2011-05-31, 07:37

Re: Dynamic GUI size

Post by HWGuy » 2012-03-10, 12:54

Post it here and Carsten can up it to svn.
Sure Cafu's GUI will look broken in the meantime but I'm going to redo the GUI later anyways.
User avatar
Haimi
Posts:85
Joined:2011-11-23, 09:28

Re: Dynamic GUI size

Post by Haimi » 2012-03-11, 19:39

Okay, here it is:

Code: Select all

Index: Ca3DE/MainCanvas.cpp
===================================================================
--- Ca3DE/MainCanvas.cpp	(revision 483)
+++ Ca3DE/MainCanvas.cpp	(working copy)
@@ -452,7 +452,7 @@
         cf::GuiSys::GuiI* MainMenuGui=cf::GuiSys::GuiMan->Find("Games/"+Options_ServerGameName.GetValueString()+"/GUIs/MainMenu/MainMenu_main.cgui", true);
         if (MainMenuGui==NULL)
         {
-            MainMenuGui=new cf::GuiSys::GuiImplT(*m_GuiResources, "Err=gui:new('WindowT'); gui:SetRootWindow(Err); gui:activate(true); gui:setInteractive(true); gui:showMouse(false); Err:set('rect', 0, 0, 640, 480); Err:set('textScale', 0.8); Err:set('text', 'Error loading MainMenu_main.cgui,\\nsee console <F1> for details.');", true);
+            MainMenuGui=new cf::GuiSys::GuiImplT(*m_GuiResources, "Err=gui:new('WindowT'); gui:SetRootWindow(Err); gui:activate(true); gui:setInteractive(true); gui:showMouse(false); Err:set('rect', 0, 0, 1024, 768); Err:set('textScale', 0.8); Err:set('text', 'Error loading MainMenu_main.cgui,\\nsee console <F1> for details.');", true);
             cf::GuiSys::GuiMan->Register(MainMenuGui);
         }
         m_Client->SetMainMenuGui(MainMenuGui);
Index: Ca3DE/Client/ClientWindow.cpp
===================================================================
--- Ca3DE/Client/ClientWindow.cpp	(revision 483)
+++ Ca3DE/Client/ClientWindow.cpp	(working copy)
@@ -60,8 +60,8 @@
     // Setup the window attributes.
     Rect[0]=  0.0f;
     Rect[1]=  0.0f;
-    Rect[2]=640.0f;
-    Rect[3]=480.0f;
+    Rect[2]=1024.0f;
+    Rect[3]=768.0f;
 }
 
 Index: Libs/GuiSys/GuiImpl.cpp
===================================================================
--- Libs/GuiSys/GuiImpl.cpp	(revision 483)
+++ Libs/GuiSys/GuiImpl.cpp	(working copy)
@@ -499,9 +515,9 @@
         // Finish by applying a z-layer coating to the GUI screen.
         // This is important whenever the z-ordering of scene elements can be imperfect, e.g. in the Map Editor.
         Mesh.Vertices[0].SetOrigin(  0.0f,   0.0f);
-        Mesh.Vertices[1].SetOrigin(640.0f,   0.0f);
-        Mesh.Vertices[2].SetOrigin(640.0f, 480.0f);
-        Mesh.Vertices[3].SetOrigin(  0.0f, 480.0f);
+        Mesh.Vertices[1].SetOrigin(1024.0f,   0.0f);
+        Mesh.Vertices[2].SetOrigin(1024.0f, 768.0f);
+        Mesh.Vertices[3].SetOrigin(  0.0f, 768.0f);
 
         MatSys::Renderer->SetCurrentMaterial(m_GuiFinishZRM);
         MatSys::Renderer->RenderMesh(Mesh);
Index: Libs/GuiSys/WindowModel.cpp
===================================================================
--- Libs/GuiSys/WindowModel.cpp	(revision 483)
+++ Libs/GuiSys/WindowModel.cpp	(working copy)
@@ -150,7 +150,7 @@
     MatSys::Renderer->SetMatrix(MatSys::RendererI::WORLD_TO_VIEW, MatrixT::GetRotateXMatrix(-90.0f));   // Rotate coordinate system axes to Cafu standard.
     MatSys::Renderer->Translate(MatSys::RendererI::WORLD_TO_VIEW, -CameraPos.x, -CameraPos.y, -CameraPos.z);
 
-    const MatrixT ProjectionMatrix=MatrixT::GetProjPerspectiveMatrix(67.5f, 640.0f/480.0f, 10.0f, 10000.0f);
+    const MatrixT ProjectionMatrix=MatrixT::GetProjPerspectiveMatrix(67.5f, 1024.0f/768.0f, 10.0f, 10000.0f);
     MatSys::Renderer->SetMatrix(MatSys::RendererI::PROJECTION, ProjectionMatrix);
 
 
Index: Libs/GuiSys/Gui.hpp
===================================================================
--- Libs/GuiSys/Gui.hpp	(revision 483)
+++ Libs/GuiSys/Gui.hpp	(working copy)
@@ -37,8 +38,11 @@
     {
         /// Note that it is very difficult to change these constants later, because then all GUI scripts
         /// in the world had to be changed too (and in a non-trivial way)!
-        const float VIRTUAL_SCREEN_SIZE_X=640.0f;
-        const float VIRTUAL_SCREEN_SIZE_Y=480.0f;
+        const float VIRTUAL_SCREEN_SIZE_X=1024.0f;
+        const float VIRTUAL_SCREEN_SIZE_Y=768.0f;
+        // TODO: Read the Virtual Screen size from the Configuration
+		//	VIRTUAL_SCREEN_SIZE_X = ConsoleInterpreter->FindVar("dlg_clWindowSizeY")->GetValueDouble();
+		//	VIRTUAL_SCREEN_SIZE_Y = ConsoleInterpreter->FindVar("dlg_clWindowSizeY")->GetValueDouble();
 
 
         /// General GUI interface.
When you apply this code, you may easily use the ci.GetValue("dlg_clWindowSizeX") and ci.SetValue("dlg_clWindowSizeY") functions for placing your GUI elements, so it would no longer look broken.
Project Status: Code architecture definition
6 Programmers, 1 Photographer, 1 Architect, 1 Game designer
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: Dynamic GUI size

Post by Carsten » 2012-03-11, 20:29

HWGuy wrote:I said you should change to float because 640x480 is too low a resolution for modern GUI design which is almost always developed for 1024x768 and 1920x1080.
Could you at least change it to 1024x768 in the meantime, I haven't looked at the GUI code but I'm guessing that's a matter of changing 2 constants.
Well, good news is that the coordinates in the GuiSys are not integers, they're float already.
So (639.95, 479.25) is a perfectly valid and accurately accounted for position near the bottom right corner of the screen. ;-)

Thus, changing from 640*480 to anything else would not gain anything new, but it would destroy all current GUIs in Cafu.
So updating one requires updating the other, in a single, (near) atomic step.
What about hook based? The float method above and "distance from points" are pretty much the primary ways every GUI is laid out these days.
I'm not sure if I understand this, can you please explain?

To me it looks as if the proper solution is to introduce units to the numbers, so that we can express things both relative:
  • "The width of this window is 20 percent of its parent width."
  • "The x-center of this window is at 50% of its parent width."
as well as absolute, in pixels:
  • "The width of this window is 240px, located (30px, 40px) off the parents top-left corner."
(or any combination hereof).
Pixels would be real physical pixels in whatever resolution the screen is setup to.
Best regards,
Carsten
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: Dynamic GUI size

Post by Carsten » 2012-03-11, 20:44

Haimi wrote:When you apply this code, you may easily use the ci.GetValue("dlg_clWindowSizeX") and ci.SetValue("dlg_clWindowSizeY") functions for placing your GUI elements, so it would no longer look broken.
Please understand that this won't work:
As explained above, the virtual screen of 640*480 pixels is mapped to whatever the user has set the "physical" application window or the screen resolution to...
Best regards,
Carsten
User avatar
Haimi
Posts:85
Joined:2011-11-23, 09:28

Re: Dynamic GUI size

Post by Haimi » 2012-03-11, 21:04

Yes, I understand this. nur with the GUI size changed to 1024*768 and the "physical" application window or the screen resolution is 1024x768 like the default settings, the mapping is 1:1. I know that there are still some things to change in order to be able to have sharp GUI elements with real proportions and positions. I am thinking about the following changes:
  • Create the GUI system according to the screen resolution of the main game using GetClientSize()
  • Creating LUA Methods to determine the size of the GUI, so the elements can be positioned acording to the real size.
I would like to do this, because my game idea requires a lot of GUI Windows and I think that on a bigger screen, the player sees more of the game.

For example: I want to place my minimap (always same size in the right upper corner:

Code: Select all

Minimap:OnInit()
    x,y=gui:GetSize()
    mmapSize = 200
    self:setRect(x-mmapSize, y-mmapSize, mmapSize, mmapSize)
end
And good. Always quadratic, always in the right upper corner and very few code.
Project Status: Code architecture definition
6 Programmers, 1 Photographer, 1 Architect, 1 Game designer
User avatar
Haimi
Posts:85
Joined:2011-11-23, 09:28

Re: Dynamic GUI size

Post by Haimi » 2012-04-04, 21:05

Okay, finally I did the Trick. It is rather easy - replacing the constants with static members, adding a method to GuiImplT to call gui:getSize(). Now I have Added an Event to the GUI, gui:OnSIzeChange(), but I would need to know the Event that is called internally when the Window is being resized. Is there an Event like this? Or is there an easy way to realize this?
Project Status: Code architecture definition
6 Programmers, 1 Photographer, 1 Architect, 1 Game designer
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: Dynamic GUI size

Post by Carsten » 2012-04-05, 17:16

Haimi wrote:Is there an Event like this?
Yes, see OnSize()
:up:
Best regards,
Carsten
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests