How to change screen resolution using QT, OpenGL, C++, and Linux? - c++

I just want to make a full screen game. I know how to change resolution on Windows but how do I change the resolution under Linux? Is there a cross platform QT solution for this? Also I've got borders around my GLWidget. How do I make the widget cover the entire window?
I'm just going to post the code:
#include <QtOpenGL>
class GLWidget : public QGLWidget
{
public:
void initializeGL()
{
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
glClearDepth(1.0f);
}
void paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
}
void resizeGL(int width, int height)
{
int side = qMin(width, height);
glViewport((width - side) / 2, (height - side) / 2, side, side);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-0.5f, +0.5f, -0.5f, +0.5f, 4.0f, 15.0f);
glMatrixMode(GL_MODELVIEW);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QDesktopWidget *desktop = app.desktop();
QWidget window;
GLWidget *glWidget = new GLWidget;
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(glWidget);
window.setLayout(mainLayout);
window.setWindowTitle("Hello GL");
window.resize(QSize(640, 480));
window.show();
window.showFullScreen();
return app.exec();
}

You can use xrrsetscreenconfigandrate, as explained here:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<X11/Xlib.h>
#include<X11/extensions/Xrandr.h>
Display *dpy;
Window root;
int num_sizes;
XRRScreenSize *xrrs;
XRRScreenConfiguration *conf;
short possible_frequencies[64][64];
short original_rate;
Rotation original_rotation;
SizeID original_size_id;
int main(int argc, char *argv[]){
//
// CONNECT TO X-SERVER, GET ROOT WINDOW ID
//
dpy = XOpenDisplay(NULL);
root = RootWindow(dpy, 0);
//
// GET POSSIBLE SCREEN RESOLUTIONS
//
xrrs = XRRSizes(dpy, 0, &num_sizes);
//
// LOOP THROUGH ALL POSSIBLE RESOLUTIONS,
// GETTING THE SELECTABLE DISPLAY FREQUENCIES
//
for(int i = 0; i < num_sizes; i ++) {
short *rates;
int num_rates;
printf("\n\t%2i : %4i x %4i (%4imm x%4imm ) ", i, xrrs[i].width, xrrs[i].height, xrrs[i].mwidth, xrrs[i].mheight);
rates = XRRRates(dpy, 0, i, &num_rates);
for(int j = 0; j < num_rates; j ++) {
possible_frequencies[i][j] = rates[j];
printf("%4i ", rates[j]); } }
printf("\n");
//
// GET CURRENT RESOLUTION AND FREQUENCY
//
conf = XRRGetScreenInfo(dpy, root);
original_rate = XRRConfigCurrentRate(conf);
original_size_id = XRRConfigCurrentConfiguration(conf, &original_rotation);
printf("\n\tCURRENT SIZE ID : %i\n", original_size_id);
printf("\tCURRENT ROTATION : %i \n", original_rotation);
printf("\tCURRENT RATE : %i Hz\n\n", original_rate);
//
// CHANGE RESOLUTION
//
printf("\tCHANGED TO %i x %i PIXELS, %i Hz\n\n", xrrs[1].width, xrrs[1].height, possible_frequencies[1][0]);
XRRSetScreenConfigAndRate(dpy, conf, root, 1, RR_Rotate_0, possible_frequencies[1][0], CurrentTime);
//
// SLEEP A WHILE
//
usleep(6000000);
//
// RESTORE ORIGINAL CONFIGURATION
//
printf("\tRESTORING %i x %i PIXELS, %i Hz\n\n", xrrs[original_size_id].width, xrrs[original_size_id].height, original_rate);
XRRSetScreenConfigAndRate(dpy, conf, root, original_size_id, original_rotation, original_rate, CurrentTime);
//
// EXIT
//
XCloseDisplay(dpy); }
//
// gcc -o Xrandr Xrandr.cc -lX11 -lXrandr -lstdc++
//

Related

FLTK: Clearing a graph when drawing another

I wrote a simple FLTK program to draw a circle when clicking on the "Draw Circle" button and to draw a line when clicking on the "Draw Line" button. I supposed to have only one graph. But I got two graphs in the panel. I want only one showing and the other disappearing. The following is the code:
#include <FL/Fl.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Box.H>
using namespace std;
int flag = 0;
class Drawing : public Fl_Box {
void draw() {
fl_color(255, 0, 0);
int x, y, x1, y1;
if (flag == 1) {
double radius = 100;
x = (int)(w() / 2);
y = (int)(h() / 2);
fl_circle(x, y, radius);
}
else if (flag == -1) {
x = (int)(w() / 4);
y = (int)(h() / 4);
x1 = (int)(w() *3/ 4);
y1 = (int)(h() *3/ 4);
fl_line(x, y, x1, y1);
}
}
public:
Drawing(int X, int Y, int W, int H) : Fl_Box(X, Y, W, H) {}
};
Drawing* d;
void circle_cb(Fl_Widget*, void*) {
flag = 1;
fl_overlay_clear();
d->redraw();
} // end sumbit_cb
void line_cb(Fl_Widget*, void*) {
flag = -1;
fl_overlay_clear();
d->redraw();
} // end clear_cb
int main(int argc, char** argv) {
Fl_Window* window = new Fl_Window(600, 550); // create a window, originally(400,400)
Drawing dr(0, 0, 600, 600);
d = &dr;
Fl_Button *b, *c;
b = new Fl_Button(150, 80, 100, 25, "&Draw Circle");
b->callback(circle_cb);
c = new Fl_Button(350, 80, 100, 25, "&Draw Line");
c->callback(line_cb);
window->end(); //show the window
window->show(argc, argv);
return Fl::run();
}
I have used fl_overlay_clear() to clear graph. However it is not working. Any help will be appreciated.
There are several issues that need to be fixed in your program, but first of all using the draw() method as you did is basically correct. However, using fl_overlay_clear(); is useless, you can remove it.
My solution: your widget doesn't have a solid background (boxtype), i.e. your draw method draws over the background over and over again w/o clearing it. There are several ways to solve this, but if you want to learn what happens, try this first: add window->resizable(window); before window->show(argc, argv);, run the program again and resize the window. You'll notice that the previous drawing disappears and only one drawing stays. That's because the background is cleared when you resize the widget.
Next step: add a solid boxtype:
d = &dr;
d->box(FL_DOWN_BOX);
and add Fl_Box::draw(); right at the beginning of your draw() method.
If you do that you may notice that your button(s) disappear when you click one of them - because your buttons are inside the area of your Drawing. The last thing(s) I fixed was to correct the coordinates of buttons and to enlarge the window (it was too small anyway to cover the entire Drawing). Here's my complete result:
#include <FL/Fl.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Box.H>
using namespace std;
int flag = 0;
class Drawing : public Fl_Box {
void draw() {
Fl_Box::draw();
fl_color(255, 0, 0);
int x, y, x1, y1;
if (flag == 1) {
double radius = 100;
x = (int)(w() / 2);
y = (int)(h() / 2);
fl_circle(x, y, radius);
} else if (flag == -1) {
x = (int)(w() / 4);
y = (int)(h() / 4);
x1 = (int)(w() * 3 / 4);
y1 = (int)(h() * 3 / 4);
fl_line(x, y, x1, y1);
}
}
public:
Drawing(int X, int Y, int W, int H)
: Fl_Box(X, Y, W, H) {}
};
Drawing *d;
void circle_cb(Fl_Widget *, void *) {
flag = 1;
// fl_overlay_clear(); // not useful
d->redraw();
} // end sumbit_cb
void line_cb(Fl_Widget *, void *) {
flag = -1;
// fl_overlay_clear(); // not useful
d->redraw();
} // end clear_cb
int main(int argc, char **argv) {
Fl_Window *window = new Fl_Window(600, 660); // create a window, originally(400,400)
Drawing dr(0, 60, 600, 600); // FIXED
d = &dr;
d->box(FL_DOWN_BOX); // ADDED
Fl_Button *b, *c;
b = new Fl_Button(150, 20, 100, 25, "&Draw Circle"); // FIXED
b->callback(circle_cb);
c = new Fl_Button(350, 20, 100, 25, "&Draw Line"); // FIXED
c->callback(line_cb);
window->end(); // show the window
window->resizable(window); // ADDED
window->show(argc, argv);
return Fl::run();
}
I believe this does what you want.
PS: the official FLTK support forum can be found on our website https://www.fltk.org/ and the direct link to the user forum (Google Groups) is https://groups.google.com/g/fltkgeneral
Just a quick addition to what Albrecht put so perfectly: FLTK drawing coordinates are relative to the window, not relative to the widget. You probably want to offset your drawing by the x() and y() coordinates of your widget.
In your handle() methods line_cb() , circle_cb() should call window()->make_current() and then fl_overlay_rect() after FL_DRAG events, and should call fl_overlay_clear() after a FL_RELEASE event. Refer for more details

OpenGL GLFW not correctly recognising window resize

I have some graph that I need to resize concurrently when the window is also resized, however as of now, it changes the axis size's perfectly when resizing but when I let go of the resize (stop clicking on the corner of a window) the application's graph limits revert back to something entirely incorrect.
Here is a MRE displaying the issue:
#include <GL/glew.h>
#ifndef GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#endif // GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include "ImGui/imgui.h"
#include "ImGui/implot.h"
#include "ImGui/implot_internal.h"
#include "ImGui/imgui_impl_glfw.h"
#include "ImGui/imgui_impl_opengl3.h"
#include <iostream>
static bool changedWinSize = false;
static int winWidth = 1280;
static int winHeight = 720;
static void MainLoop(GLFWwindow* window)
{
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::SetNextWindowSize({ (float)winWidth, (float)winHeight });
ImGui::SetNextWindowPos({ 0, 0 });
ImGui::Begin("Window", (bool*)0, ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
static bool fitPlot = false;
if (fitPlot) {
fitPlot = false;
ImPlot::SetNextPlotLimits(-10, 80, -3, 20, ImGuiCond_Always);
}
ImPlotStyle& style = ImPlot::GetStyle();
style.PlotDefaultSize.y = ImGui::GetWindowSize().y / 2 - 45 + (style.PlotDefaultSize.y = ImGui::GetWindowSize().y / 3 - 30) / 2 - 60;
style.PlotDefaultSize.x = ImGui::GetWindowSize().x - 150;
if (ImPlot::BeginPlot("Sim", "Range (m)", "Height (m)", { 0, 0 }, ImPlotFlags_NoLegend | ImPlotFlags_Equal)) {
if (ImPlot::BeginItem("Sim"))
{
if (ImPlot::FitThisFrame() || changedWinSize) {
fitPlot = true;
}
}
ImPlot::EndPlot();
}
ImGui::End();
changedWinSize = false;
// Rendering
ImGui::Render();
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
}
static void window_size_callback(GLFWwindow* window, int width, int height)
{
changedWinSize = true;
winWidth = width;
winHeight = height;
MainLoop(window);
}
int main(int argc, char* argv[])
{
const char* glslVersion = "#version 460";
glfwInit();
// Create window with graphics context
GLFWwindow* window = glfwCreateWindow(1280, 720, "Program", NULL, NULL);
glfwMakeContextCurrent(window);
glfwSwapInterval(0); // vsync
//Initialize GLEW + ImGui
glewInit();
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImPlot::CreateContext();
// Setup Dear ImGui style
ImGui::StyleColorsLight();
// Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init(glslVersion);
glfwSetWindowSizeCallback(window, window_size_callback);
while (!glfwWindowShouldClose(window))
{
//Events
glfwPollEvents();
MainLoop(window);
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImPlot::DestroyContext();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
From this example, the plot x-axis labels begin at -5 and go to 75. When you try to resize the window (shorten the width) after a pixel or so shrinking the window, the plot lables display -10 and 80, which is exactly what I want. This correct size only occurs when resizing the window and not letting go. It is only when you let go of the window that it reverts back to the incorrect side. I can't figure out where in my code it goes wrong.
ImPlot::FitThisFrame() returns true when double clicking on the plot, however what is weird is that the plot fits correctly if winChangedSize is true, entering that if statement, but when i double click to enter it it doesn't fit the plot correctly?

FLTK flickering animation

I'm trying to make a simple animation using FLTK(a circle with increasing and decreasing radius). I've managed to write a simple program that seems to work, but the animation flickers. The circle disappears for a couple of milliseconds and then gets back. I've changed Fl_Window class to Fl_Double_Window, but that didn't fix this problem.
class Painting : public Fl_Widget {
public:
Painting(int x, int y, int w, int h) : Fl_Widget(x, y, w, h, 0) {}
private:
void draw()
{
static double inc = 0;
inc += 0.2;
double radius = 50 + 10*sin(inc);
fl_begin_polygon();
fl_arc(100, 100, radius, 0, 360);
fl_end_polygon();
}
};
void redraw_cb(void *data)
{
Fl_Widget *w = (Fl_Widget*)data;
w->redraw();
Fl::repeat_timeout(0.01, redraw_cb, data);
}
int main(int argc, char **argv)
{
Fl_Double_Window *win = new Fl_Double_Window(1000, 500, "hello");
Painting *painting = new Painting(0, 0, 1000, 500);
Fl::add_timeout(1, redraw_cb, painting);
Fl::visual(FL_DOUBLE|FL_INDEX);
win->resizable(painting);
win->end();
win->show();
return Fl::run();
}

How to disable minimum size setting on widgets for drawing a window background image

I'm new to Gtkmm3 and I try several things. At the moment, I program a window class with a background image. I have searched a lot, but I don't find any useful/helpful examples for Gtkmm3. Finally, it should be possible to resize the window, and the background resizes itself by building a pattern of the same image and cutting them to the desired size (not by scaling the image).
So I add a base grid (Gtk::Grid) to the main window (Gtk::Image), load an image, put them into a background grid (Gtk::Grid) and attach this to the base grid at the same position as the foreground grid (Gtk::Grid).
A method helps to resize the background.
Here comes the code:
makefile
SRC = main.cpp
SRC += ./src/MainWindow.cpp
TARGET = prog
CC = g++
LIBS = `pkg-config gtkmm-3.0 --cflags --libs`
all:
$(CC) $(SRC) $(LIBS) -o $(TARGET)
main.cpp
#include "./inc/MainWindow.h"
#include <gtkmm.h>
int main (int argc, char* argv[])
{
Glib::RefPtr<Gtk::Application> app =
Gtk::Application::create(argc, argv, "org.gtkmm.example");
MainWindow mainWindow;
//Shows the mainWindow and returns when it is closed.
return app->run(mainWindow);
}
inc/MainWindow.h
#ifndef MAINWINDOW_H_INCLUDED
#define MAINWINDOW_H_INCLUDED
#include <gtkmm.h>
#include <gdkmm.h>
class MainWindow :
public Gtk::Window
{
public:
/** Default constructor */
MainWindow();
/** Default destructor */
virtual ~MainWindow();
protected:
private:
// signal handlers
void on_ButtonQuit_clicked ( void );
void on_MainWindow_check_resize();
// methods
void resizeBackground(int width, int height);
// member data
Gtk::Grid m_GridBase;
Gtk::Grid m_ForegroundGrid;
Gtk::Label m_Label1;
Gtk::ButtonBox m_ButtonBox;
Gtk::Button m_ButtonQuit;
Gtk::Image m_BackgroundImage;
Glib::RefPtr<Gdk::Pixbuf> m_BackgroundImagePixbuf;
int m_BackgroundImageWidth;
int m_BackgroundImageHeight;
bool m_resizeBackgroundStatus;
};
#endif // MAINWINDOW_H_INCLUDED
src/MainWindow.cpp
#include "../inc/MainWindow.h"
MainWindow::MainWindow() :
m_ButtonBox(),
m_ButtonQuit( Gtk::Stock::QUIT ),
m_BackgroundImage( "res/background.png" ),
m_ForegroundGrid(),
m_GridBase(),
m_Label1 ( "Beispiel Label",
/*xalign*/ Gtk::ALIGN_CENTER,
/*yalign*/ Gtk::ALIGN_CENTER,
/*mnemonic*/ false)
{
// setting up the window
this->set_title( "Window with backround" );
this->set_border_width(0);
// hide titlebar
//this->set_decorated(false);
m_BackgroundImagePixbuf = m_BackgroundImage.get_pixbuf();
m_BackgroundImageWidth = m_BackgroundImagePixbuf->get_width();
m_BackgroundImageHeight = m_BackgroundImagePixbuf->get_height();
// ad the base grid to the window
this->add(m_GridBase);
// attach the foreground grid and the background image to the base grid
m_GridBase.attach(m_ForegroundGrid,1,1,1,1);
// at least (!) attach the background picture
m_GridBase.attach(m_BackgroundImage,1,1,1,1);
// pack the foreground grid
m_ForegroundGrid.attach(m_ButtonBox,2,2,1,1);
m_ForegroundGrid.attach(m_Label1,1,1,1,1);
m_ButtonBox.pack_start(m_ButtonQuit, Gtk::PACK_SHRINK);
// get the dimension of packed foreground grid for resizing the background
m_ForegroundGrid.show_all();
int min_width; int nat_width; int min_height; int nat_height;
m_ForegroundGrid.get_preferred_width(min_width,nat_width);
m_ForegroundGrid.get_preferred_height(min_height,nat_height);
this->resizeBackground(min_width, min_height);
// initialize the status flag for on_MainWindow_check_resize
m_resizeBackgroundStatus = true;
// connect signals
m_ButtonQuit.signal_clicked().connect(
sigc::mem_fun(*this, &MainWindow::on_ButtonQuit_clicked));
this->signal_check_resize().connect(
sigc::mem_fun(*this, &MainWindow::on_MainWindow_check_resize));
this->show_all_children();
}
MainWindow::~MainWindow()
{
//dtor
}
void MainWindow::on_ButtonQuit_clicked(void)
{
this->hide();
}
void MainWindow::on_MainWindow_check_resize()
{
// check status to prevent recursive callings
if(m_resizeBackgroundStatus==true)
{
Gtk::Allocation allocation = this->get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
m_resizeBackgroundStatus = false;
this->resizeBackground(width, height);
}
else
{
m_resizeBackgroundStatus = true;
}
}
void MainWindow::resizeBackground(int width, int height)
{
Glib::RefPtr<Gdk::Pixbuf> BackgroundPixbuf =
Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB,true,8,width,height);
int xcnt = width/m_BackgroundImageWidth + 1;
int ycnt = height/m_BackgroundImageHeight + 1;
Glib::RefPtr<Gdk::Pixbuf> BackgroundTmpPixbuf =
Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB,true,8,
xcnt*m_BackgroundImageWidth,
ycnt*m_BackgroundImageHeight);
for( xcnt = width/m_BackgroundImageWidth; xcnt>=0; xcnt--)
{
for( ycnt = height/m_BackgroundImageHeight; ycnt>=0; ycnt--)
{
m_BackgroundImagePixbuf->scale(
BackgroundTmpPixbuf, // destination Pixbuf
xcnt*m_BackgroundImageWidth, // dest_x
ycnt*m_BackgroundImageHeight, // dest_y
m_BackgroundImageWidth, // dest_width
m_BackgroundImageHeight, // dest_height
xcnt*m_BackgroundImageWidth, // offset_x = dest_x
ycnt*m_BackgroundImageHeight, // offset_y = dest_y
1, // scale_x
1, // scale_y
Gdk::INTERP_NEAREST //interp_type
);
}
}
BackgroundTmpPixbuf->scale(
BackgroundPixbuf, // destination Pixbuf
0, // dest_x
0, // dest_y
width, // dest_width
height, // dest_height
0, // offset_x = dest_x
0, // offset_y = dest_y
1, // scale_x
1, // scale_y
Gdk::INTERP_NEAREST //interp_type
);
m_BackgroundImage.set(BackgroundPixbuf);
// int min_width; int nat_width; int min_height; int nat_height;
// m_Grid.get_preferred_width(min_width,nat_width);
// m_Grid.get_preferred_height(min_height,nat_height);
// printf("%d\n",min_width);
// m_GridBase.set_size_request(min_width,min_height);
// this->set_size_request(min_width,min_height);
// m_BackgroundImage.set_size_request(min_width,min_height);
// const Gdk::Geometry geometry = 0;
// this->set_geometry_hints(geometry,0);
}
res/background.png
snapshot of the window after start
snapshot of the window after resizing
The Question
As you can see, you can enlarge the window and the background fits its size. But you can't reduce the size. What do I have to do to enable resizing back to the size of the foreground?
I search for the opposite method of get_preferred_width because I think this adjustment limits resizing.
My Approaches
I tried out set_size_request or set_geometry_hints, but without any effect.

glutMouseWheelFunc doesnt trigger callback

I am trying to implement zoom in or zoom out operations using mouse scroll button
by glutMouseWheelFunc in opengl . I have implemted the code as below :
#include<GL/freeglut.h>
void mouseWheel(int button, int dir, int x, int y)
{
printf("in mouse wheel \n");
if (dir > 0)
{
// Zoom in
ztrans = ztrans - 1.0;
printf("scroll in = %0.3f\n ",ztrans);
}
else
{
// Zoom out
ztrans = ztrans + 1.0;
printf("scroll out = %0.3f\n ",ztrans);
}
glutPostRedisplay();
}
int main(int argc, char **argv)
{
// general initializations
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(800, 400);
glutCreateWindow("Rotation");
// register callbacks
glutReshapeFunc(changeSize);
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
glutIgnoreKeyRepeat(1);
glutMouseFunc(mouseButton);
glutMotionFunc(mouseMove);
glutMouseWheelFunc(mouseWheel); // Register mouse wheel function
glEnable(GL_DEPTH_TEST);
glutMainLoop();
return 0;
}
On executing, it is not calling the registered callback function(mouseWheel) . My system has freeglut3 installed.
try using
a static int inside void mouseWheelmethod, and then use it in renderScene
like this
static int k;
static int ztrans
void mouseWheel(int button, int dir, int x, int y)
{
k = dir; // int dir is +1 of -1 based on the direction of the wheel motion
ztrans = ztrans + k;
}
This worked for me,
Try this and feedback, GoodLuck .