Not getting correct extents after resolution change
by Todd D. Degani · in Torque Game Engine · 05/03/2005 (6:19 pm) · 9 replies
This is a post about an issue which I eventually have tracked down to what appears to be a bug. I have not come up with a solution for it though.
Here is the situation.
Basically I am trying to get the extents of the root control of a gui. Its sizing is set to width and height. It is a GuiChunkedBitmapCtrl.
To repro this add this to the end of the startMissionGui::onWake() function in startMissionGui.gui of a stock build:
Now launch the game and go to the start mission screen.
Check the console echo, it is the current correct resolution.
Go back to the main screen, choose options, then choose a new resolution
Go to the start mission screen and check the console echo, it is the old resolution
Go back to the main screen
Go to the start mission screen and check the console echo, it is now showing the new resolution
I originally believed this has something to do with me checking its extents before it gets resized and was correct.
The code that is actually changing the extents of the start mission screen is:
guiCanvas.cc about line 1019
Now the reason this causes a problem is because onWake actually happens BEFORE this code happens.
In the main game loop, DemoGame::main about line 506
onWake happens in Platform::process() while the extents resizing voodoo happens in TimeManager::process(). Thus if you are attempting to check the extents in onWake you will not get the correct result.
A possible solution is that whenever the canvas resizes we should check the root control of the canvas to make sure it is the correct size. So possibly doing the resize after the canvas gets resized might solve the problem. I would try this but I have yet to track down exactly where the canvas size gets reset.
A workaround is to force a refresh before you check the extents by using Canvas.repaint(). The problem with this method though is that you get a visible flicker of the background repainting.
Here is the situation.
Basically I am trying to get the extents of the root control of a gui. Its sizing is set to width and height. It is a GuiChunkedBitmapCtrl.
To repro this add this to the end of the startMissionGui::onWake() function in startMissionGui.gui of a stock build:
%extent = startMissionGui.getExtent();
echo("extent = " @ %extent);Now launch the game and go to the start mission screen.
Check the console echo, it is the current correct resolution.
Go back to the main screen, choose options, then choose a new resolution
Go to the start mission screen and check the console echo, it is the old resolution
Go back to the main screen
Go to the start mission screen and check the console echo, it is now showing the new resolution
I originally believed this has something to do with me checking its extents before it gets resized and was correct.
The code that is actually changing the extents of the start mission screen is:
guiCanvas.cc about line 1019
//all bottom level controls should be the same dimensions as the canvas
//this is necessary for passing mouse events accurately
iterator i;
for (i = begin(); i != end(); i++)
{
AssertFatal(static_cast<GuiControl*>((*i))->isAwake(), "GuiCanvas::renderFrame: ctrl is not awake");
GuiControl *ctrl = static_cast<GuiControl*>(*i);
Point2I ext = ctrl->getExtent();
Point2I pos = ctrl->getPosition();
if(pos != screenRect.point || ext != screenRect.extent)
{
ctrl->resize(screenRect.point, screenRect.extent);
resetUpdateRegions();
}
}Now the reason this causes a problem is because onWake actually happens BEFORE this code happens.
In the main game loop, DemoGame::main about line 506
Platform::process(); // keys, etc.
TelConsole->process();
TelDebugger->process();
TimeManager::process(); // guaranteed to produce an eventonWake happens in Platform::process() while the extents resizing voodoo happens in TimeManager::process(). Thus if you are attempting to check the extents in onWake you will not get the correct result.
A possible solution is that whenever the canvas resizes we should check the root control of the canvas to make sure it is the correct size. So possibly doing the resize after the canvas gets resized might solve the problem. I would try this but I have yet to track down exactly where the canvas size gets reset.
A workaround is to force a refresh before you check the extents by using Canvas.repaint(). The problem with this method though is that you get a visible flicker of the background repainting.
#2
is the most important matter in the whole engine and I cant believe its not fixed yet..." whining post of some sort.
In my original post in the engine forum I posted it as an issue that I did not know the cause of nor know the solution to. Also in that same thread I made other follow up posts as to what I did and didn not try and the success or failures of those attempts in case anyone else currently or in the future attempts to solve the issue.
I posted the thread in this forum because originally I did not know it was an SDK bug but after digging deeper into the issue I discovered it was, which led me to post it here, which I felt would be the appropriate place for it.
05/03/2005 (9:12 pm)
Gonzo, while I respect your opinion and your posts are very knowledgable, I did not feel that I was spamming anything. I only have one thread in one other forum on the subject. Also any other posts in the original thread are either a) responses to Ben or b) information I discovered while researching the issue. It's not like I was posting insignificant information on the matter or creating a "waaahh some body help me, In my original post in the engine forum I posted it as an issue that I did not know the cause of nor know the solution to. Also in that same thread I made other follow up posts as to what I did and didn not try and the success or failures of those attempts in case anyone else currently or in the future attempts to solve the issue.
I posted the thread in this forum because originally I did not know it was an SDK bug but after digging deeper into the issue I discovered it was, which led me to post it here, which I felt would be the appropriate place for it.
#3
As best I can tell, you might be trying to get a childs extent before the parent has awoken.
05/04/2005 (12:48 am)
Spamming was a harsh word, my bad. I meant, cross posting the same issue. GG is not real fond of it. As of the issue of this "bug", I'm not of the opinion that it is a bug. The onWake() method has been in use for god knows how long now, and you are the first that I know of to have an issue with it. If I better understood the desired result of your functions I could better help you figure out if this is indeed a bug or if it is nothin more than a misunderstanding of action/event timing.As best I can tell, you might be trying to get a childs extent before the parent has awoken.
#4
Hmm, maybe. I'll check it out.
Edit: The desired result of the function is to get the extents of the root control so that I can center some dynamically created controls on the screen. The root control will be the parent of these dynamically created controls. I could use the screen width for this, but I am just trying to figure out why I am seeing the results noted above.
05/04/2005 (7:32 am)
Quote:As best I can tell, you might be trying to get a childs extent before the parent has awoken.
Hmm, maybe. I'll check it out.
Edit: The desired result of the function is to get the extents of the root control so that I can center some dynamically created controls on the screen. The root control will be the parent of these dynamically created controls. I could use the screen width for this, but I am just trying to figure out why I am seeing the results noted above.
#5
05/04/2005 (12:05 pm)
The root control will always be the size of your screen without question. If it's ever not, the engine will assert and your done. Since this is a hardcoded fact and has been forever, there is never a problem getting the root control's extent. You simply get your screen size. A function is a function, be it "getExtent()" or "getResolution()" the end result is the same. So techinically you are inventing a problem where there is no problem. You have to have a root control, every other control can be as dynamic as you choose because they will all use the root resolution which will always be the screen resolution. Take some advice on this, you are wasting time on this that could be better spent on being more creative or learning something else. I can still see no reason that you cannot get your desired results with a stock TGE so that's the best advice I can offer at this time.
#6
05/04/2005 (12:14 pm)
BTW, you said center a control... I don't know if you have "favorite functions" like I do(functions I wrote), but this is one of my favorites...function Canvas::centerWindow(%canvas, %win)
{
%win.position = (getWord(vectorSub($Pref::Video::resolution, %win.extent), 0) * 0.5)
SPC (getWord(vectorSub($Pref::Video::resolution, %win.extent), 1) * 0.5);
}
#7
Thats not exactly true. If you change resolutions the root control does not get resized until the canvas repaints.
Example:
You start at a main screen with a button on it whos command is to set its content to another gui, which we will call destination gui
You press the button
In the onWake of the destination gui, the extents of the root control will be the extents of the old resolution since the canvas has not been repainted yet
Edit: The reason this is an issue for me is that I want my control to center itself horizontally with whatever control is its parent. If I add my control to the root control, it will end up not being positioned properly the first time the gui is viewed in the case where someone changes screen resolutions.
05/04/2005 (12:51 pm)
Quote:The root control will always be the size of your screen without question.
Thats not exactly true. If you change resolutions the root control does not get resized until the canvas repaints.
Example:
You start at a main screen with a button on it whos command is to set its content to another gui, which we will call destination gui
You press the button
In the onWake of the destination gui, the extents of the root control will be the extents of the old resolution since the canvas has not been repainted yet
Edit: The reason this is an issue for me is that I want my control to center itself horizontally with whatever control is its parent. If I add my control to the root control, it will end up not being positioned properly the first time the gui is viewed in the case where someone changes screen resolutions.
#8
05/04/2005 (1:21 pm)
Then set horizontal sizing to "relative", problem solved.
#9
To fix this you must call repaint, but only pre-render, not render the frame.
I created a Canvas->preparePaint(); script function that you can call which organizes the objects so that they are in relation to the root object in terms of sizing. Call this before getting the size or location of any object in a gui you just loaded and is in the process of waking up (problem explained in detail above).
I added the following function to guiCanvas.cc:
//SOMATIC VISION CHANGES START
void GuiCanvas::preparePaint() {
resetUpdateRegions();
// inhibit explicit refreshes in the case we're swapped out
if (gDGLRender)
renderFrame(true);
}
//SOMATIC VISION CHANGES END
And the following console function to call it:
//SOMATIC VISION CHANGES START
ConsoleMethod( GuiCanvas, preparePaint, void, 2, 2, "Prepare the canvas by calculating and applying the location of all objects.")
{
Canvas->preparePaint();
}
//SOMATIC VISION CHANGES END
Also in guiCanvas.h we must add the function declaration:
//SOMATIC VISION CHANGES START
void preparePaint(); //sets object locations to allow script to reposition
//SOMATIC VISION CHANGES END
02/27/2008 (10:15 am)
I have add difficulties with this also. Here is a "fix":To fix this you must call repaint, but only pre-render, not render the frame.
I created a Canvas->preparePaint(); script function that you can call which organizes the objects so that they are in relation to the root object in terms of sizing. Call this before getting the size or location of any object in a gui you just loaded and is in the process of waking up (problem explained in detail above).
I added the following function to guiCanvas.cc:
//SOMATIC VISION CHANGES START
void GuiCanvas::preparePaint() {
resetUpdateRegions();
// inhibit explicit refreshes in the case we're swapped out
if (gDGLRender)
renderFrame(true);
}
//SOMATIC VISION CHANGES END
And the following console function to call it:
//SOMATIC VISION CHANGES START
ConsoleMethod( GuiCanvas, preparePaint, void, 2, 2, "Prepare the canvas by calculating and applying the location of all objects.")
{
Canvas->preparePaint();
}
//SOMATIC VISION CHANGES END
Also in guiCanvas.h we must add the function declaration:
//SOMATIC VISION CHANGES START
void preparePaint(); //sets object locations to allow script to reposition
//SOMATIC VISION CHANGES END
Torque Owner Gonzo T. Clown