How to center an opengl window with glfw? - c++

I wanna draw an opengl window in center of the screen,however I searched everywhere but didn't find any answer to it. Below is a common snippet code of creating a window But it always show up in most left-top position.How can I control it.
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);
glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(400,200,"LearnOpenGl",NULL,NULL);
if(window == NULL)
{
cout<<"Failed to create GLFW window!!"<<endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
cout<<"Failed to initialize GLAD!!"<<endl;
return -1;
}
glViewport(400, 400, 100, 200);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
while(!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
}

Please use this function "glfwSetWindowPos".
Here is an example.

#Himanshu answered a question on how to get the max-width and max-height of a window aka window size How to get maximum possible window size when creating window in MFC?
So with that piece of code, you can center it like below:
int width=800;// could declare them as "const int" if you like
int hight=800;
GLFWwindow* window = glfwCreateWindow(width,hight, "OpenGL", NULL, NULL);
int max_width = GetSystemMetrics(SM_CXSCREEN);
int max_hieght = GetSystemMetrics(SM_CYSCREEN);
glfwSetWindowMonitor(window, NULL, (max_width/2)-(width/2), (max_hieght/2) - (height/2), width, height, GLFW_DONT_CARE);

Here is a sample from my game engine made using glad and glfw it uses the windows api to find to screen resolution and then centers the window accordingly.
#include <iostream>
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <GLFW/glfw3.h>
#include <Windows.h>
const unsigned int width = 1600;
const unsigned int height = 900;
const char* title = "Frog2D";
void getDesktopResolution(int& horizontal, int& vertical)
{
RECT desktop;
const HWND hDesktop = GetDesktopWindow();
GetWindowRect(hDesktop, &desktop);
horizontal = desktop.right;
vertical = desktop.bottom;
}
int main()
{
glfwInit();
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); //borderless
int horizontal = 0;
int vertical = 0;
getDesktopResolution(horizontal, vertical);
GLFWwindow* window = glfwCreateWindow(width, height, title, NULL, NULL);
glfwSetWindowPos(window, horizontal / 2 - width / 2, vertical / 2 - height / 2);
return 0;
}

Related

How to embed GLFW window in to WinAPI window frame?

I have the following working code, which attaches the OpenGL handle to an existing WinAPI window. It works fine and I can properly get the properties (height and width for example) of the WinAPI dialog through calling openGL glfwGetWindowSize(glfwWnd, &windowWidth, &windowHeight); function.
LPCTSTR WindowName = "Untitled - Notepad";
HWND hwnd = FindWindow("Notepad", WindowName);
if (!glfwInit()) {
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL);
GLFWwindow* glfwWnd = glfwAttachWin32Window(hwnd, window);
GLint windowWidth, windowHeight;
glfwGetWindowSize(glfwWnd, &windowWidth, &windowHeight);
But what I actually want is for window "My Title" to be embedded inside the Notepad window frame. Which is not happening as they are still two separate windows. Any way of achieving this?

How do I create a centered GLFW window?

I'm looking for the SDL equivalent of
gWindow = SDL_CreateWindow( "SDL window",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH, WINDOW_HEIGHT, windowFlags );
for GLFW. I can center the glfw window after its creation with the below code, however, for a split second, the window is shown non-centered. So it doesn't look smooth.
// init glfw
if (!initGLFW())
{
return -1;
}
// create main window
int count;
int windowWidth, windowHeight;
int monitorX, monitorY;
GLFWwindow* gWindow;
GLFWmonitor** monitors = glfwGetMonitors(&count);
const GLFWvidmode* videoMode = glfwGetVideoMode(monitors[0]);
// width: 75% of the screen
windowWidth = videoMode->width / 1.5;
// Aspect ratio 16 to 9
windowHeight = windowWidth / 16 * 9;
glfwGetMonitorPos(monitors[0], &monitorX, &monitorY);
gWindow = glfwCreateWindow(windowWidth, windowHeight, "Engine v" ENGINE_VERSION, NULL, NULL);
if (!gWindow)
{
glfwTerminate();
std::cout << "Failed to create main window" << std::endl;
return -1;
}
glfwSetWindowPos(gWindow,
monitorX + (videoMode->width - windowWidth) / 2,
monitorY + (videoMode->height - windowHeight) / 2);
From the documentation:
By default, newly created windows use the placement recommended by the window system. To create the window at a specific position, make it initially invisible using the GLFW_VISIBLE window hint, set its position and then show it.
Example
Using your code above, you would add a call to glfwWindowHint before glfwCreateWindow like so:
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
and once you have positioned the window where you would like it, make a call to glfwShowWindow like so:
glfwShowWindow(gWindow);
Depending on your use case, it may also be prudent to reset the window hints using glfwDefaultWindowHints after creating the window, to ensure that future window creation isn't modified.
Putting all that together, I have something like:
if (!glfwInit())
{
return -1;
}
int count;
int windowWidth, windowHeight;
int monitorX, monitorY;
GLFWwindow* gWindow;
GLFWmonitor** monitors = glfwGetMonitors(&count);
const GLFWvidmode* videoMode = glfwGetVideoMode(monitors[0]);
windowWidth = videoMode->width / 1.5;
windowHeight = windowWidth / 16 * 9;
glfwGetMonitorPos(monitors[0], &monitorX, &monitorY);
// (1). Set the visibility window hint to false for subsequent window creation
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
gWindow = glfwCreateWindow(windowWidth, windowHeight, "Engine v", NULL, NULL);
if (!gWindow)
{
glfwTerminate();
std::cout << "Failed to create main window" << std::endl;
return -1;
}
// (2). Reset the window hints to default
glfwDefaultWindowHints();
glfwSetWindowPos(gWindow,
monitorX + (videoMode->width - windowWidth) / 2,
monitorY + (videoMode->height - windowHeight) / 2);
// (3). Show the window
glfwShowWindow(gWindow);

SDL: How to set size of pixel (stretch) of a window

I'm making a retro pixel game so I want to make my window a very low resolution (256x256). However when I try to make it fullscreen, the whole window was just rendered top left, while leaving all other areas black.
I want to know a way of globally setting the size of each pixel in a window, in order to let it fit the fullscreen, or, a way of stretching the whole window (or a renderer?) to a specified size(and full screen) while having the (w, h) unchanged in parameter 2 and 3 in SDL_CreateWindow, and also whilst having the sizes proportional (so, if it was a square window, it should be a square window after stretched, not a rect after stretched into a rect displayer).
First, render your game to a 256x256 texture. This gist has an example, I will inline it below.
Next, figure out the correct size and position of your game texture on your actual window, and render the texture there. That will require modifications to the SDL_RenderCopyEx call, as the gist simply renders it stretched to the screen.
#include <iostream>
#ifdef __linux__
#include <SDL2/SDL.h>
#elif defined(_WIN32)
#include <SDL.h>
#endif
const int WIN_WIDTH = 640;
const int WIN_HEIGHT = 480;
int main(int argc, char **argv){
if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
std::cerr << "SDL_Init failed: " << SDL_GetError() << "\n";
return 1;
}
SDL_Window *win = SDL_CreateWindow("Rendering to a texture!", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, WIN_WIDTH, WIN_HEIGHT, 0);
SDL_Renderer *renderer = SDL_CreateRenderer(win, -1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
//Put your own bmp image here
SDL_Surface *bmpSurf = SDL_LoadBMP("../res/image.bmp");
SDL_Texture *bmpTex = SDL_CreateTextureFromSurface(renderer, bmpSurf);
SDL_FreeSurface(bmpSurf);
//Make a target texture to render too
SDL_Texture *texTarget = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET, WIN_WIDTH, WIN_HEIGHT);
//Now render to the texture
SDL_SetRenderTarget(renderer, texTarget);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, bmpTex, NULL, NULL);
//Detach the texture
SDL_SetRenderTarget(renderer, NULL);
//Now render the texture target to our screen, but upside down
SDL_RenderClear(renderer);
SDL_RenderCopyEx(renderer, texTarget, NULL, NULL, 0, NULL, SDL_FLIP_VERTICAL);
SDL_RenderPresent(renderer);
SDL_Delay(1000);
SDL_DestroyTexture(texTarget);
SDL_DestroyTexture(bmpTex);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}

Change background of SDL2 window?

I can create a SDL2 window but I don't know how to change background color of this window.
My code:
#include "SDL.h"
SDL_Window *window;
void main()
{
window = SDL_CreateWindow("TEST", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Delay(3000);
}
How can I change background color of this window to black?
You should set drawing colour with SDL_SetRenderDrawColor and then use SDL_RenderClear:
(code comes directly from SDL wiki)
int main(int argc, char* argv[])
{
SDL_Window* window;
SDL_Renderer* renderer;
// Initialize SDL.
if (SDL_Init(SDL_INIT_VIDEO) < 0)
return 1;
// Create the window where we will draw.
window = SDL_CreateWindow("SDL_RenderClear",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
512, 512,
0);
// We must call SDL_CreateRenderer in order for draw calls to affect this window.
renderer = SDL_CreateRenderer(window, -1, 0);
// Select the color for drawing. It is set to red here.
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
// Clear the entire screen to our selected color.
SDL_RenderClear(renderer);
// Up until now everything was drawn behind the scenes.
// This will show the new, red contents of the window.
SDL_RenderPresent(renderer);
// Give us time to see the window.
SDL_Delay(5000);
// Always be sure to clean up
SDL_Quit();
return 0;
}
If you do not use SDL2 renderer you can do this:
Just call:
SDL_GL_SwapWindow(window);
After :
SDL_GL_MakeCurrent(window, context);
That's all! Now you have a black screen.
#include <SDL2/SDL.h>
#include <iostream>
using namespace std;
int main(){
int width=512, height=512;
SDL_Window *window=SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_RESIZABLE);
if(window==NULL)
cout << "There was an error while initializing the window" << endl << SDL_GetError << endl;
SDL_Event event;
bool running=true;
while(running){
while(SDL_PollEvent(&event)){
if(event.type==SDL_QUIT){
running=false;
break;
}
}
SDL_GetWindowSize(window, &width, &height);
SDL_Surface *surface=SDL_GetWindowSurface(window);
Uint32 skyblue=SDL_MapRGB(surface->format, 65,193,193);
SDL_FillRect(surface, NULL, skyblue);
SDL_UpdateWindowSurface(window);
}
SDL_DestroyWindow(window);
SDL_Quit();
}
Note, none of these solutions work properly with OpenGL. The question was how to init the window with predefined color, not how to paint the first frame. There's still a blink of white color before the first frame is painted.
Try this one :
SDL_Window *wind;
SDL_Surface *windSurface = NULL
void main()
{
wind = SDL_CreateWindow("TEST", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
windSurface = SDL_GetWindowSurface(wind);
SDL_FillRect(windSurface, NULL, SDL_MapRGB(windSurface->format, 240, 200, 112));
SDL_UpdateWindowSurface(wind);
SDL_Delay(3000);
}

SDL OpenGL window not responding, transparent

The SDL window that I have created with an OpenGL context has problems:
It's transparent, you can see the console behind it. As you can see from the code below, I just wrote something to display red to the screen.
It doesn't respond to anything. As soon as I hover my mouse over the screen, the loading cursor appears, and clicking does nothing.
#define main SDL_main
#include "stdafx.h"
int main(int argc, char **argv)
{
bool quit = false;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
SDL_Quit( );
return 1;
}
SDL_Window* window = NULL;
window = SDL_CreateWindow("SandVox", 100, 100, 600, 400, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
if (!window) {
std::cout << "Unable to create window" << std::endl;
SDL_DestroyWindow(window);
return 0;
}
SDL_GLContext glcontext = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, glcontext);
glewInit( );
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetSwapInterval(1);
SDL_Renderer* render = NULL;
render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Event *mainEvent = NULL;
mainEvent = new SDL_Event( );
while (!quit && mainEvent->type != SDL_QUIT) ;
{
SDL_PollEvent(mainEvent);
/*
SDL_RenderClear(render);
SDL_RenderPresent(render);
*/
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(window);
}
SDL_GL_DeleteContext(glcontext);
SDL_DestroyRenderer(render);
SDL_DestroyWindow(window);
delete mainEvent;
SDL_Quit( );
return 0;
}
stdafx.h doesn't have anything very exciting, just this:
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_mixer.h>
#include <GL/glew.h>
#include <GL/GL.h>
#include <GL/glxew.h>
#include <GL/wglew.h>
#include <GL/GLU.h>
EDIT: To preempt a question people might have, yes, I have OpenGL 4.0 installed on my computer, I've checked :)
Setting the pixel format properties after you create your context is pretty pointless. The pixel format of the default framebuffer is immutable once the context is created.
Move all your calls to SDL_GL_SetAttribute (...) so that they come before SDL_GL_CreateContext(window).
The swap interval can be set at any time, but everything else in this block of code needs to be moved:
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetSwapInterval(1);
Right now, you are probably getting a single-buffered pixel format. That does not jive well with modern window managers, which only update individual windows when you swap back/front buffers. Buffer swapping causes an implicit flush (whether or not it swaps buffers), so this problem is most likely due to a compositing window manager.