How to center fullscreen window - c++

I have a 16:9 display where I'd like to show fullscreen SDL window which is in 4:3 mode.SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN) sets the window to the left side of the screen and leaves a big black bar to the right.
I'd like to center the window and have black bars on the left and the right side.
It seems that SDL_SetWindowPosition(window, x, y) has no effect on window when it is in fullscreen mode. Can I center the fullscreen window in SDL2?

There are two situation:
(1) display with renderer and texture base on window size.
(2) display with screen and surface base on pixel.
For (1) here is a simple solution base on setting view port for renderer.(no testing but a guideline)
void SDL_SetRendererViewportRatio_4_3(SDL_Window *window,
SDL_Renderer *renderer
SDL_Rect *viewport) {
Uint8 r, g, b, a;
SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_SetRenderDrawColor(renderer, r, g, b, a);
int w, h;
SDL_GetWindowSize(window, &w, &h);
if (w * 3 > h * 4) {
viewport->w = h * 4 / 3;
viewport->h = h;
} else {
viewport->w = w;
viewport->h = w * 3 / 4;
}
viewport->x = (w - viewport->w) / 2;
viewport->y = (h - viewport->h) / 2;
SDL_RenderSetViewport(renderer, viewport);
}
Note that you should call this function whenever window changed size.
For (2) I guess you should calculate the coordinate of surface and draw big black bars by yourself. It is more difficult that I cannot prove simple solution.

Related

Scrolling and zooming GtkDrawingArea with GtkScrolledWindow consumes a lot of memory and causes the application to crash

Is it possible to zoom (scale) the content of GtkDrawingArea and scroll it with GtkScrolledWindow without changing the drawing area size? My strategy was to use ViewPort and manually adjust the upper horizontal and vertical adjustments to match the content's size. This is useless. It only works if the line gtk widget set size request(area, w * scale, h * scale); is employed in the leftPressed function. In this case, however, the application consumes a large amount of memory and eventually crashes.
To demonstrate, the following code employs left mouse clicks to increase scale (zoom). The application's memory requirements quickly exceed 1GB, and the application crashes.
The question is whether there is a way to scale and scroll the content of the drawing area without resizing it. Such an approach would be much smoother (since it wouldn't require large buffer allocations). Such an approach would be much smoother (because it would not necessitate large buffer allocations).
The example code is written in C and employs GTK 4.6.7. It has been tested on Mac OS X Monterey and Windows 10. In both cases, the application stops responding and crashes after 6-7 left mouse clicks. The use of memory can be easily tracked in activity monitor on a Mac or task manager on a Windows computer.
#include <gtk/gtk.h>
GtkWidget* vp, *sw;
double scale = 1;
int w = 500, h = 300;
GtkAdjustment* ha, * va;
static void leftPressed(GtkGestureClick* gesture, int n_press, double x, double y, GtkWidget* area)
{
scale *= 2;
//zooming should work by setting upper value only, without changing size of drawing area
gtk_adjustment_set_upper(ha, w * scale);
gtk_adjustment_set_upper(va, h * scale);
gtk_widget_set_size_request(area, w * scale, h * scale);
gtk_widget_queue_draw(area);
}
static void rightPressed(GtkGestureClick* gesture, int n_press, double x, double y, GtkWidget* area)
{
scale /= 2;
//gtk_widget_set_size_request(child, w / scale, h / scale);
gtk_adjustment_set_upper(ha, w / scale);
gtk_adjustment_set_upper(va, h / scale);
gtk_widget_queue_draw(area);
}
static void drawRectangles(GtkDrawingArea* drawingarea, cairo_t* cr, int width, int height, gpointer data)
{
cairo_scale(cr, scale, scale);
cairo_set_source_rgb(cr, 1, 0, 0);
cairo_rectangle(cr, 0, 0, 100, 50);
cairo_fill(cr);
cairo_set_source_rgb(cr, 0, 1, 0);
cairo_rectangle(cr, 200, 100, 100, 50);
cairo_fill(cr);
cairo_set_source_rgb(cr, 0, 0, 1);
cairo_rectangle(cr, 400, 250, 100, 50);
cairo_fill(cr);
}
static void createWindow(GtkApplication* app, gpointer data)
{
GtkWidget* window = gtk_application_window_new(app);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 200);
//Drawing Area
GtkWidget* area = gtk_drawing_area_new();
gtk_widget_set_size_request(area, w, h);
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), drawRectangles, NULL, NULL);
//viewport
//ha = gtk_adjustment_new();
ha = gtk_adjustment_new(0, 0, w, 30, 360, 400);
va = gtk_adjustment_new(0, 0, h, 20, 180, 200);
vp = gtk_viewport_new(ha, va);
gtk_viewport_set_child(GTK_VIEWPORT(vp), area);
//Scrolled Window
sw = gtk_scrolled_window_new();
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), vp);
gtk_scrolled_window_set_max_content_height(GTK_SCROLLED_WINDOW(sw), 4000);
gtk_scrolled_window_set_max_content_width(GTK_SCROLLED_WINDOW(sw), 4000);
ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(sw));
va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(sw));
//GtkGesture
GtkGesture* pressElement = gtk_gesture_click_new();
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(pressElement), GDK_BUTTON_PRIMARY);
gtk_widget_add_controller(area, GTK_EVENT_CONTROLLER(pressElement));
g_signal_connect(pressElement, "pressed", G_CALLBACK(leftPressed), area);
GtkGesture* pressElement2 = gtk_gesture_click_new();
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(pressElement2), GDK_BUTTON_SECONDARY);
gtk_widget_add_controller(area, GTK_EVENT_CONTROLLER(pressElement2));
g_signal_connect(pressElement2, "pressed", G_CALLBACK(rightPressed), area);
gtk_window_set_child(GTK_WINDOW(window), sw);
gtk_window_present(GTK_WINDOW(window));
}
int main(int argc, char* argv[])
{
// Create a new application
GtkApplication* app = gtk_application_new("com.example.GtkApplication", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(createWindow), NULL);
return g_application_run(G_APPLICATION(app), argc, argv);
}

how to get coordinate of image using mouse click when resize window?

I am making Game in openGl which contain start menu screen.Problem is when i click start game button (which is a texture image) game start successfully but when i resize window and then click start game button the texture image coordinates change and game did not start how i prevent to change image coordinates after resize window.
Here is My Mouse funtion
void mouseClick (int button, int state, int x, int y)
{
if (!menu)
{
xMin = 300, xMax = 400, yMin = 350, yMax = 400;
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
y = height - y;
if (x >= xMin && x <= xMax && y >= yMin && y <= yMax)
{
printf_s("starting 2d Game ");
}
}
}
}
Here is my texture Image code
glBegin(GL_QUAD_STRIP);
glTexCoord2f(0, 0);
glVertex2f(300, 350);
glTexCoord2f(1, 0);
glVertex2f(400, 350);
glTexCoord2f(0, 1);
glVertex2f(300, 400);
glTexCoord2f(1, 1);
glVertex2f(400,400);
glEnd();
glFlush();
Here is my Matrix Projection Code:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluOrtho2D(0.0, 640.0, 0.0, 440);//dino window
gluOrtho2D(0.0, 640.0, 0.0, 440);//dino window
//gluOrtho2D(1.0, 1.0, 1.0,1.0);//house window
//gluOrtho2D(1.0, 1.0, 1.0, 1.0);//bird window
glViewport(0, 0, width, height);
//glViewport(220, 100, 100, 200);
Actually, it is the mouse click coordinates that are changing. You will have to convert your mouse click position (x,y) from viewport coordinates to your drawing coordinates (i.e. Ortho2D coordinates).
Assuming that width and height variables are provided by the system whenever the window is resized, try the following:
x = x/width * 640;
y = (height -y) / height * 440;
And then test for the button bounds.
The correct way to implement this is to use selection buffer.
With this, you know which polygon is being clicked. This is not affected by the size of the window.

glFrustum on Macbook Pro gives unexpected results

I'm just setting up a simple renderer using LWJGL 3 and when it runs on my external display it looks like I expect but when resize it on my Macbook it shrinks the viewport. Then if I move the window it fixes it. Here's the code that I run when I init my GL stuff and on window resize.
public void resize(int width, int height)
{
val near = 0.1
val far = 100.0
GL11.glViewport(0, 0, width, height);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
float aspect = width / (float)height
float fov = (float)(45.0 / 360.0 * Math.PI)
float fH = Math.tan(fov) * near
float fW = fH * aspect
GL11.glFrustum(-fW, fW, -fH, fH, near, far);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glLoadIdentity();
}
Here's what I'm seeing
Wrong
Right
If I'm running it on my external display it doesn't change, it's always right.
Reading the size of the frame buffer was the answer here. I create the window with the pixel size the user passes in and then read the frameBuffer size to pass to glViewport.
public Window(String title, int width, int height)
{
_errorCallback = GLFWErrorCallback.createPrint(System.err);
GLFW.glfwSetErrorCallback(_errorCallback);
if (GLFW.glfwInit() != GLFW.GLFW_TRUE)
{
throw IllegalStateException("Unable to initialize GLFW");
}
GLFW.glfwDefaultWindowHints();
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GLFW.GLFW_TRUE);
_window = GLFW.glfwCreateWindow(width, height, title ?: "", 0, 0);
if (_window == 0L)
{
throw RuntimeException("Failed to create window");
}
// Setup Callbacks
// Get the resolution of the primary monitor
GLFWVidMode vidmode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor());
// Center our window
GLFW.glfwSetWindowPos(_window, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);
// Make the OpenGL context current
GLFW.glfwMakeContextCurrent(_window);
// Enable v-sync
GLFW.glfwSwapInterval(1);
// Make the window visible
GLFW.glfwShowWindow(_window);
}
Then I read the frame buffer size to pass into glViewport and glFrustum.
public Vector2 frameBufferSize()
{
IntBuffer bufferWidth = BufferUtils.createIntBuffer(4);
IntBuffer bufferHeight = BufferUtils.createIntBuffer(4);
GLFW.glfwGetFramebufferSize(_window, bufferWidth, bufferHeight);
return Vector2(bufferWidth.get(0), bufferHeight.get(0));
}

Problems with SDL rendering frames

I'm still a somewhat beginner in SDL, and I've come accross a problem that I am little lost on. I've been loosely following LazyFoo's tutorials along with some other additional resources.
The problem is trying to create an animated sprite onto a window.
I managed to isolate the malfunctioning code to whenever I press a key down.
When I press a key down, a new window opens up in addition to the one previously intialized using the SDL_CreateWindow function.
case SDL_KEYDOWN:
int frame = 0;
//Clear Screen
SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(renderer);
//Render Current frame
SDL_Rect* currentFrame = &iKey.MegamanRun[frame / 6];
iKey.mmxrender((sx - currentFrame->w) / 2, (sy - currentFrame->h) / 2, currentFrame);
//update screen
SDL_RenderPresent(renderer);
//Next frame
++frame;
I'm using a simple megaman sprite, if that helps you understand some of the names.
Specifically, the
iKey.mmxrender((sx - currentFrame->w) / 2, (sy - currentFrame->h) / 2, currentFrame);
is causing new windows to pop up.
the mmxrender function is in a different class on a different file, sx and sy are the size of the window.
void Megaman::mmxrender(int x, int y, SDL_Rect* clip)
{
Init mkey;
//Set rendering space
SDL_Rect renderQuad = { x, y, iWidth, iHeight };
//Set clip dimensions
if (clip != NULL)
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}
//Render to screen
SDL_RenderCopy(mkey.renderer, iTexture, clip, &renderQuad);
}
Not sure how to proceed, any help is appreciated.

OpenGL Aspect Ratio Issue

I am using Qt + OpenGl for 2D rendering.
I am a beginner at OpenGL and for the life of me i am not able to figure out this aspect ratio issue. Everytime i think i have understood glOrtho and gViewPort, but very next time i am into another issue with them. While if coordinates are symmetric like between -1 and 1, my code works else it doesn't. I really want to get through these for once and all. All the suggestions i have searched and applied have gone fruitless for me.
My Problem Statement:
I am rendering a square and a triangle and i switch between them with keystroke "R". I am also zooming in and out. While square is maintaining aspect ratio, triangle is not. Coordinates for shapes are:
Square: (-10, -250), (500, -250), (500, -260), (-10, -260);
Triangle: (250, 0), (310, 0), (280, 30)
Basically I am not able to render above triangle. Here is code for same:
My Code
#include <QtGui/QMouseEvent>
#include <qdebug.h>
#include "GLWidget.h"
#include "stdio.h"
#include "qgl.h"
#include "qimage.h"
GLWidget::GLWidget(QWidget *parent) : QGLWidget(parent)
{
setMouseTracking(true);
}
void GLWidget::initializeGL()
{
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_COLOR_MATERIAL);
glEnable(GL_BLEND);
glEnable(GL_POLYGON_SMOOTH);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(1, 1, 1, 0);
glEnable( GL_POINT_SMOOTH ); // For Circular Points
}
void GLWidget::resizeGL(int w, int h)
{
canvas_width = (double)w;
canvas_height = (double)h;
aspect_ratio = canvas_width/canvas_height;
left_plane = 250;
right_plane = 310;
bottom_plane = 0;
top_plane = 60;
z_near_plane = 1;
z_far_plane = -1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if( canvas_width > canvas_height ){
glOrtho(left_plane*aspect_ratio, right_plane*aspect_ratio, bottom_plane, top_plane, z_near_plane, z_far_plane);
}else{
glOrtho(left_plane, right_plane, bottom_plane/aspect_ratio, top_plane/aspect_ratio, z_near_plane, z_far_plane);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1,0,0); // red
glBegin(GL_POLYGON);
//glVertex2f(-30,0);
//glVertex2f(30,0);
//glVertex2f(0,60);
glVertex2f(250,0);
glVertex2f(310,0);
glVertex2f(280,60);
glEnd();
}
I do not see any traingle because left_plane*aspect_ratio clips my drawing (250 is minimum X, 250*1.4 > 310, 310 is maximum X).
I hope i have made myself clear.
I will try to place images as well (i guess i will have to upload images to some other site and link them here?).
Your problem is that the bounding box (the values assigned to left/right/top/bottom_plane) doesn't have the same aspect ratio as the viewport. If you have the bounding box for the object, you need to find viewport coordinates with the correct aspect ratio (w/h). The viewport needs to be both centered on the bounding box center, and be big enough to fit the bounding box. But the aspect ratio of the viewport has nothing to do with the size of the bounding box.
In general you have a 3D bounding box (8 corner points). You would project each corner onto the screen, then use min/max to get a rectangle that needs to be centered on screen. You then check the aspect ratio ar = wr/hr of that rectangle against the aspect ratio of the viewport a=w/r. If a < ar, you need to fit wr to w, otherwise fit hr to h.
void GLWidget::resizeGL(int w, int h)
{
// First set up the projection.
double canvas_width = (double)w;
double canvas_height = (double)h;
double a = canvas_width / canvas_height;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-a, +a, -1, +1, -1, +1);
// Now set up the view matrix.
double leftBoundingRectangle = 250;
double rightBoundingRectangle = 310;
double bottomBoundingRectangle = 0;
double topBoundingRectangle = 60;
double widthBoundingRectangle = rightBoundingRectangle - leftBoundingRectangle;
double heightBoundingRectangle = topBoundingRectangle - bottomBoundingRectangle;
double ar = widthBoundingRectangle / heightBoundingRectangle;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Center on bounding rectangle center.
double tx = (leftBoundingRectangle + rightBoundingRectangle)/2.0, ty = (topBoundingRectangle + bottomBoundingRectangle)/2.0;
glTranslated(tx, ty, 0.0); // or is it -tx, -ty?
// Scale to fit bounding box.
double s;
if (ar > a)
{
s = ... // sorry, but you have to figure this one out for yourself. :)
}
else
{
s = ...
}
glScaled(s,s,s);
}