Finding screen width and height dynamically in OpenGL GLUT program - opengl

In my OpenGL program, in order to run it in fullscreen mode, I'm using the GLUT function glutGameModeString(const char *string). (where 'string' specifies the screen width,height,pixelDepth and refresh rate) To make it working in any system,i need to dynamically determine the screen width and screen height of the host system, prior to making the call to 'glutGameModeString' function.How do I do that?

I think you are wrong, there are the following constants:
GLUT_SCREEN_HEIGHT
GLUT_SCREEN_WIDTH
I've tested it, it works.

Just tested on Linux Mint 18
std::cout << "glut screen width(DEFUALT): " << GLUT_SCREEN_WIDTH << std::endl;
std::cout << "glut screen height(DEFAULT): " << GLUT_SCREEN_HEIGHT << std::endl;
std::cout << "glut screen width: " << glutGet(GLUT_SCREEN_WIDTH) << std::endl;
std::cout << "glut screen height: " << glutGet(GLUT_SCREEN_HEIGHT) << std::endl;
outputs:
glut screen width(DEFAULT): 200
glut screen height(DEFAULT): 201
glut screen width: 1366
glut screen height: 768
setting your window size to glutGet(GLUT_SCREEN_WIDTH/HEIGHT); will maximize your window, still has top bar and border.
Just calling glutFullScreen(); after initializing your window will make it full screen with no borders or anything, no need for the above stuff of getting your screen size.

Related

How do I access shape position in SFML?

I'm using SFML to draw in C++. It was going well until I tried accessing the position of a circle I drew on the screen. Code:
sf::Shape RootCircle = sf::Shape::Circle(300, 30, 30, sf::Color::Blue);
App.Draw(RootCircle);
cout << "X: " << RootCircle.GetPosition().x << endl;
cout << "Y: " << RootCircle.GetPosition().y << endl;
It's consisting telling me that the x and y positions are set to 0. What am I missing?
By calling the sf::Shape::Circle() constructor, only the offset relative to the position is set to 300,30. To actually set the position of the circle, you need to call:
rootCircle.SetPosition(300.0f, 30.0f);
Note that by setting the position to 300,30, whatever offset is specified in the Circle() constructor will be relative to the actual position specified.

Why is QFontMetrics::lineSpacing() smaller than the height of the characters' bounding boxes?

This happens on Linux.
The problem shows when executing this code (I'm drawing in the paint event of a widget):
painter.drawText(0, 0, 1000, 1000, 0, QString("0"), &charBoundingBox);
qDebug() << "bounding box height" << charBoundingBox.height();
qDebug() << "lineSpacing" << painter.fontMetrics().lineSpacing();
qDebug() << "leading" << painter.fontMetrics().leading();
qDebug() << "height" << painter.fontMetrics().height();
qDebug() << painter.font();
It outputs:
bounding box height 11
lineSpacing 7
leading -1
height 8
QFont( "Digital-7,10,-1,5,50,0,0,0,0,0" )
Notice the height of the bounding box for the character is 11, while the line spacing is 7. This is partly because the leading is negative, but even without that, the font height is still smaller.
How does Qt calculate the character bounding box it returns? Its height obviously is not derived from fontMetrics::height and fontMetrics::leading.
There's no guarantee that the height of the bounding box returned by the painter will be the same as the font height. Also, the line spacing is the sum of the height and leading of the font. If the leading for a font is negative, the line spacing will be smaller than the height.
Furthermore, to make sure you're using the correct metrics, you should probably use painter.fontMetrics() instead of constructing a QFontMetrics(font).
In any event, to make sure which of the above is happening in your situation, you should print out the font leading and font height separately (using painter.fontMetrics()).

Why does GetSystemMetrics() return these values?

I am having some issues creating a client area of a set size. AdjustWindowRect() won't work properly so I decided to try manually calculating the width and height of the window.
That didn't work either and I wondered why so I checked up the values I used to take in account the borders etc.
#include <iostream>
#include <Windows.h>
int main(void)
{
std::cout << "GetSystemMetrics(SM_CYEDGE) = " << GetSystemMetrics(SM_CYEDGE) << std::endl;
std::cout << "GetSystemMetrics(SM_CXEDGE) = " << GetSystemMetrics(SM_CXEDGE) << std::endl;
std::cout << "GetSystemMetrics(SM_CYBORDER) = " << GetSystemMetrics(SM_CYBORDER) << std::endl;
std::cout << "GetSystemMetrics(SM_CXBORDER) = " << GetSystemMetrics(SM_CXBORDER) << std::endl;
std::cout << "GetSystemMetrics(SM_CYCAPTION) = " << GetSystemMetrics(SM_CYCAPTION);
std::cin.get();
}
This gives me:
GetSystemMetrics(SM_CYEDGE) = 2
GetSystemMetrics(SM_CXEDGE) = 2
GetSystemMetrics(SM_CYBORDER) = 1
GetSystemMetrics(SM_CXBORDER) = 1
GetSystemMetrics(SM_CYCAPTION) = 22
I am PRETTY sure that the borders of my window aren't that thin. What am I doing wrong?
EDIT 1:
Initially my window used the WS_OVERLAPPED style. Since the AdjustWindowRect does not allow that style to be used alongside it I constructed the same type of window I wanted with: (WS_BORDER | WS_CAPTION | WS_SYSMENU). This is the same style I use during the call to AdjustWindowRect and AdjustWindowRectEx(this one with NULL as extended style since I do not use any). This gives me the correct width but the height is missing a few pixels.
RECT rect = { 0, 0, 800, 600};
AdjustWindowRectEx( &rect, (WS_BORDER | WS_CAPTION | WS_SYSMENU), FALSE, NULL);
CreateWindowEx( ..., rect.right - rect.left, rect.bottom - rect.top, ...);
This gives me 800 pixels wide client-area but only 582 pixels in height.
EDIT 2:
CURIOUS, I used GetClientRect(); and it gave me that the width is 800 and the height IS 600. How come it doesn't display properly?
It seems that when I painted the whole window it all measured up. The reason? I don't know.
Maybe someone else can shed some light over this.
The first issue is that you use the wrong metric. You'll need to use SM_CXSIZEFRAME to get the width of a resizable border.
The second issue is that Windows won't give you the correct value. The fat borders of a window on Aero are a serious appcompat problem. Windows intentionally lies about the window rectangle and border size. Required to allow old programs to still work correctly, they specify the size of the window in the CreateWindow() call. But that's the size of the frame, including the borders. Without the lie, the window would end up with a client area that's too small.
To turn off the lie, you have to tell Windows that you know about the Aero behavior and don't need to be lied to. Project + Properties, Linker, Command Line, Additional options box and add:
/SUBSYSTEM:CONSOLE,6.0
Version 6.0 is the Vista version number, the first version of Windows that had Aero. Beware that your program won't run on XP anymore when you do this.
Have you tried AdjustWindowRectEx() instead of AdjustWindowRect() ?
As long as you are passing the correct styles (and extended styles) there's no reason I know of for that not to work properly.

QPainter doesn't change color

I'm learning Qt. I'm failing to realize the exercise of chapter 11 of Qt tutorial, which states "Change the color of the cannon when a shot is in the air." I chose to implement the change in paintCannon function (below). What's wrong with my code below?
void CannonField::paintCannon(QPainter &painter)
{
painter.setPen(Qt::NoPen);
if (autoShootTimer->isActive()){
std::cout << "in paintCannon yellow; " << std::endl;
// This gets called everytime `paintEvent` occurs.
// Please see the code in the web page (http://doc.trolltech.com/4.3/tutorial-t11-cannonfield-cpp.html) for this part.
painter.setBrush(Qt::yellow);
}else{
std::cout << "in paintCannon blue; " << std::endl;
painter.setBrush(Qt::blue);
}
painter.save();
painter.translate(0, height());
painter.drawPie(QRect(-35, -35, 70, 70), 0, 90 * 16);
painter.rotate(-currentAngle);
painter.drawRect(barrelRect);
painter.restore();
}
Since I first suspected Qpainter's save and restore might have been doing something wrong, I commented them out which ended up re-painting nothing.
Thanks.
The problem you are having is in this routine:
void CannonField::moveShot()
{
QRegion region = shotRect();
++timerCount;
QRect shotR = shotRect();
if (shotR.x() > width() || shotR.y() > height())
{
autoShootTimer->stop();
}
else
{
region = region.unite(shotR);
}
update(region);
}
When the shot is moved, update() is being called with a region specified. This results in only the shot rectangle being repainted. If you remove the region from the call to update(), the entire widget is repainted and your color change will work correctly.

Qt Resizing a QMainWindow with a Splitter

I have a QMainWindow with:
Two widgets in a horizontal splitter. "m_liner" is on the right side
Both widgets have a minimum size of say, 300 pixels.
A checkbox to hide/show the right-side widget m_liner.
I want the overall QMainWindow to expand when showing the widget, and shrink when hiding. The code below does this except:
If both widgets are shown, the minimum window size is 600 pixels.
Shrink the window to this smallest size.
Uncheck the box to hide the right-side widget.
Program hides the right-side widget.
Program calls this->resize(300, height);
The window ends up being 600 pixels wide (the minimum size with both widgets visible), instead of around 300 (the minimum size with only the left widget).
Later, I can resize the window down to 300 pixels with the mouse or another button. But it won't resize to 300 in the checkbox event, even if I call resize several times.
Does anyone have an idea how to solve this?
Critical bit of code follows, I have a full project available if you need it:
void MainWindow::on_checkBox_stateChanged(int val)
{
std::cout << "-------------------- Checkbox clicked " << val << std::endl;
bool visible = val;
QWidget * m_liner = ui->textEdit_2;
QSplitter * m_splitter = ui->splitter;
int linerWidth = m_liner->width();
if (linerWidth <= 0) linerWidth = m_lastLinerWidth;
if (linerWidth <= 0) linerWidth = m_liner->sizeHint().width();
// Account for the splitter handle
linerWidth += m_splitter->handleWidth() - 4;
std::cout << "Frame width starts at " << this->width() << std::endl;
std::cout << "Right Panel width is " << m_liner->width() << std::endl;
// this->setUpdatesEnabled(false);
if (visible && !m_liner->isVisible())
{
// Expand the window to include the Right Panel
int w = this->width() + linerWidth;
m_liner->setVisible(true);
QList<int> sizes = m_splitter->sizes();
if (sizes[1] == 0)
{
sizes[1] = linerWidth;
m_splitter->setSizes(sizes);
}
this->resize(w, this->height());
}
else if (!visible && m_liner->isVisible())
{
// Shrink the window to exclude the Right Panel
int w = this->width() - linerWidth;
std::cout << "Shrinking to " << w << std::endl;
m_lastLinerWidth = m_liner->width();
m_liner->setVisible(false);
m_splitter->setStretchFactor(1, 0);
this->resize(w, this->height());
m_splitter->resize(w, this->height());
this->update();
this->resize(w, this->height());
}
else
{
// Toggle the visibility of the liner
m_liner->setVisible(visible);
}
this->setUpdatesEnabled(true);
std::cout << "Frame width of " << this->width() << std::endl;
}
Sounds to me like there are some internal Qt events that need to get propagated before it recognizes that you can resize the main window. If this is the case then I can think of two potential solutions:
Use a queued single shot timer to call the code that resizes your window down to 300px:
m_liner->hide();
QTimer::singleShot( 0, this, SLOT(resizeTo300px()) );
or, after you hide your widget you can try a call to processEvents() (this function has potentially dangerous side effects, so use with caution):
m_liner->hide();
QApplication::processEvents();
resize( w, height() );
Another potential solution would be to set the horizontal size policy of your widget to ignored when hiding it:
m_liner->hide();
m_liner->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred );
resize( w, height() );
When showing your widget again, you'd need to adjust the size policy again.