I'm attempting to create a window using SDL2 and initialize BGFX to use it. My current test is just to set the window to purple using a clear color.
I tried creating a window using CreateWindowEx as well, and was also unable to update the window with the clear color I specified in my call to bgfx::setViewClear. I've been scouring open source projects as well as the docs and samples, and I can't figure out what step of bgfx initialization/update I could be missing. Please help! I've attached my current approach as a small test main.
int main(int, char**) {
SDL_InitSubSystem(SDL_INIT_VIDEO);
const int width = 800;
const int height = 600;
SDL_Window* window = nullptr;
HWND nativeWindow;
// sdl2
{
window = SDL_CreateWindow(
"test_window",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
width, height,
0
);
SDL_SysWMinfo windowManInfo;
SDL_VERSION(&windowManInfo.version);
if (SDL_GetWindowWMInfo(window, &windowManInfo)) {
nativeWindow = windowManInfo.info.win.window;
}
}
// bgfx
{
bgfx::PlatformData platformData;
platformData.ndt = nullptr;
platformData.nwh = nativeWindow;
bgfx::setPlatformData(platformData);
// prevent creation of a renderer thread
bgfx::renderFrame();
bgfx::Init init;
init.type = bgfx::RendererType::Count;
init.resolution.width = width;
init.resolution.height = height;
init.resolution.reset = BGFX_RESET_VSYNC;
bgfx::init(init);
bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x443355FF /*purple*/, 1.f, 0);
}
while (1) {
// sdl events
{
SDL_Event _event;
while (SDL_PollEvent(&_event) > 0);
}
bgfx::frame();
}
bgfx::shutdown();
SDL_Quit();
return 0;
}
After asking around work/etc.. I finally got a solution, and there were actually a couple of things that I was missing.
Because I wasn't adding any render work to the frame, bgfx is 'smart' and doesn't actually do anything. Adding a call to bgfx::touch will add an empty primitve for rendering. After I added this I could see a small dot in the top-left of my window, which leads to the other call I was missing.
I never set my view! I was also only rendering to one pixel of my window. By adding a call to bgfx::setViewRect I was able to set a size for my window view and the clear color finally took.
Related
I am facing an issue with the SDL library and different resolution than 1920x1080.
I want to copy display an image of dimension 1080x608 at the center of a screen of resolution 1080x1920 (portrait).
I have only one plugged monitor screen.
I used the following command to switch screen from 1920x1080 to 1080x1920 :
xrandr --output DP-1 --mode 1920x1080 --rotate left --primary
I am using the following code to initialize the SDL renderer :
/**
* initialize everything so we are ready to display
*/
int SdlHandler::initialize(
unsigned int positionX,
unsigned int positionY,
unsigned int width,
unsigned int height,
bool showWindow,
std::string name) {
// Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
return -1;
}
// Size if the window
this->width = width;
this->height = height;
this->positionX = positionX;
this->positionY = positionY;
// Create the SDL window
// 0 and 0 are the position in X and Y
unsigned int flags = SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS;
if (showWindow) {
flags |= SDL_WINDOW_SHOWN;
} else {
flags |= SDL_WINDOW_HIDDEN;
}
this->window = SDL_CreateWindow(name.c_str(), this->positionX, this->positionY, this->width, this->height, flags);
// If there had been a problem, leave
if (!this->window) {
return -1;
}
// Create a new renderer
this->renderer = SDL_CreateRenderer(this->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
// If there is an error creating it, just leave
if (!this->renderer) {
return -1;
}
// Setup the best for the SDL render quality
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2");
return 0;
}
Then, i call the SDL_RenderCopy function to display the image. I pass it the created renderer created with theSDL_CreateRenderer on the above code :
// Create a window at 0,0 of dimension 1080x1920
this->initialize(0, 0, 1080, 1920, true, SDL_BASE_DISPLAY_WINDOW);
// Create the SDL Rectangle that will contain the image, at the center of the window
SDL_Rect *howToDraw = new SDL_Rect();
howToDraw->x = this->positionX + floor((this->width - this->imageWidth) / 2);
howToDraw->y = this->positionY + floor((this->height - this->imageHeight) / 2);
howToDraw->w = this->imageWidth;
howToDraw->h = this->imageHeight;
SDL_RenderCopy(this->renderer, this->texture, NULL, howToDraw);
But the axis seems to be at the wrong position, igot the following result :
EDIT AND SOLUTION
This was a bug related to Compton, the window manager, everything is working good without Compton ...
Since you are rotating your display using xrandr, we can consider this is a post processing step that will rotate everything after each framebuffer is rendered.
Because this post processing step takes a 1920x1080 image resolution as input, you should use the SDL at this resolution.
What if you change your code for:
// Create a window at 0,0 of dimension 1920x1080
this->initialize(0, 0, 1920, 1080, true, SDL_BASE_DISPLAY_WINDOW);
EDIT: I also understand that you want your image to start at the center of the window, but your are placing the middle of the image at the center of the window.
You should also try the following:
howToDraw->x = this->positionX + this->imageWidth / 2;
I'm trying to use ofxProjectorKinectV2Calibration to calibrate my Kinect v2 and projector. It's an add-on to openFrameworks, and the set-up is relatively complicated.
Anyway, ofxProjectorKinectV2Calibration uses another add-on, ofxSecondWindow, to create a second window to display a chessboard. My problem is I do not see this second window at all. It's not even shown on the taskbar.
Here is the code from ofxSecondWindow to create the second window:
void ofxSecondWindow::setup(const char *name, int xpos, int ypos, int width, int height, bool undecorated) {
this->width = width;
this->height = height;
glfwWindowHint(GLFW_DECORATED, !undecorated);
mainWindow = glfwGetCurrentContext();
auxWindow = glfwCreateWindow(width, height, name, NULL, mainWindow);
glfwSetWindowPos(auxWindow, xpos, ypos);
/* enable alpha blending by default */
glfwMakeContextCurrent(auxWindow);
glEnable(GL_BLEND);
#ifndef TARGET_OPENGLES
glBlendEquation(GL_FUNC_ADD);
#endif
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glfwMakeContextCurrent(mainWindow);
hidden = false;
}
I am sure that width and height are correct, turning undecorated on or off does not change anything, and glfwCreateWindow does return some handle that is not null.
Environment: Windows 10 64-bit, Visual Studio 2015 32-bit build target, projector (1024x768) is display 1 and PC screen is display 2. openFrameworks version 0.9.3, add-ons:
ofxOpenCv
ofxXmlSettings
ofxCv
ofxKinect2ProjectorCalibration
ofxKinectV2
ofxSecondWindow
ofxUI
Ideas?
Turns out I had to call show(), or in implementation, glfwShowWindow, on the newly created window.
class Game {
public:
Game(int width, int height) {
gwidth = width;
gheight = height;
}
~Game() {
}
bool initGame() {
bool sucsess = true;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
sucsess = false;
}
//gTetrisSurface = SDL_LoadBMP("TetrisBg.bmp");
gWindow = SDL_CreateWindow("Petris V1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, gwidth, gheight, SDL_WINDOW_SHOWN);
gScreenSurface = SDL_GetWindowSurface(gWindow);
gMainBG = SDL_LoadBMP("test.bmp");
/**if (gMainBG == NULL) {
return false;
}**/
bool running = true;
//SDL_SetWindowFullscreen(gWindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
while (running == true) {
SDL_BlitSurface(gMainBG, NULL, gScreenSurface, NULL);
SDL_UpdateWindowSurface( gWindow );
}
return sucsess;
}
protected:
int gwidth, gheight;
SDL_Window* gWindow = NULL;
SDL_Surface* gScreenSurface = NULL;
SDL_Surface* gTetrisSurface = NULL;
SDL_Surface* gPongSurface = NULL;
SDL_Surface* gMainBG = NULL;
};
The thought behind this, is that this should be one huge surface, containing 2 other surfaces for 2 other games. Problem is, it wont seem to draw the BMP that i try to draw on it. Because of this my development got kinda stuck. Anyone see a possible sulotion for this problem? Thanks!
EDIT: I made it so it flushes the events, BUT, i did a bit of debugging, the problem seems to be that the img file returns NULL, why? It should be loaded with a bmp... (No error messages at all..)
From the documentation of SDL2:
https://wiki.libsdl.org/SDL_GetWindowSurface
This surface will be invalidated if the window is resized. After resizing a window this function must be called again to return a valid surface.
You may not combine this with 3D or the rendering API on this window.
My advice is to avoid using the window surface directly.
Instead, you should use a renderer and copy your own main surface to your background texture.
The SDL2 migration guide explains clearly the right way to copy surfaces and textures on the screen, especially the paragraph "If your game wants to do both".
The whole problem was that the BMP file was in the wrong folder.
If anyone have the same problem, the picture should either be in the same directory as the src (when debugging) or the solution (if building).
Hope this might help someone in the future, either way, thanks to those who tried coming up with other possibilites.
(Using visual studio)
so I got the following code(piece):
_Bool create_new_window(rectanglestruct *rectangle, colorstruct *colorfill, char *winname)
{
....
log_printf("creating main renderer for window ( window : %s )\n", ptr->winname);
// Setup renderer
SDL_Renderer *renderer = SDL_CreateRenderer( ptr->window, -1, SDL_RENDERER_ACCELERATED);
ptr->renderer = renderer;
if (colorfill != NULL)
{
log_printf("\n - background color set r=%d g=%d b=%d with opacity of %d\n", colorfill->r,colorfill->g,colorfill->b, colorfill->opacity);
// Set render color to red ( background will be rendered in this color )
SDL_SetRenderDrawColor( ptr->renderer, colorfill->r,colorfill->g,colorfill->b, colorfill->opacity );
log_printf("background rendered\n");
}
// Clear window
SDL_RenderClear( ptr->renderer );
SDL_ShowWindow(ptr->window);
SDL_RenderPresent( ptr->renderer );
getchar();
with
typedef struct SDL_Window SDL_Window;
typedef struct windowstruct {
char *winname;
SDL_Window *window;
SDL_Renderer *renderer;
struct windowstruct *next;
struct windowstruct *previous;
} windowstruct;
static windowstruct *root = NULL;
and
typedef struct colorstruct {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t opacity;
} colorstruct;
With in main:
_Bool start_SDL(void)
// scope this
{
//draw background
colorstruct *colorfill = malloc(sizeof(rectanglestruct));
colorfill->r = 0xFF;
colorfill->g = 0xFF;
colorfill->b = 0xFF;
colorfill->opacity = 0xFF;
rectanglestruct *winplace = malloc(sizeof(rectanglestruct));
winplace->x = 0;
winplace->y = 0;
winplace->w = 300;
winplace->h = 300;
create_new_window(winplace, colorfill, "appscreen");
free(colorfill);
free(winplace);
}
and
_Bool start_SDL(void)
{
//Initialization flag
_Bool success = true;
//Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
log_printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
success = false;
}
}
and I got the following output (after a couple of times):
The point is I thought that the renderer was just a copy of the screen like a buffer in which you can write and refresh on the screen. But I gues not?
No, SDL_Renderer implements SDL2 drawing, usually with hardware-accelerated backend. Your image is corrupt because you didn't issue redraw at appropriate time. If your window needs redraw (resized, overshadowed by other window or sceen borders) - you have to draw again and present result (this is in fact the same for every windowing library; even in GUI toolkits like Qt or GTK if your callback didn't return quickly, you can experience the same corruption). You can render to texture and then display it again if your image remains unchanged and calculations are heavy.
To do what you've said would require accumulating all data sent to renderer (may be high memory usage) and either calling update on regular intervals or on events, or taking away main loop from calling side (like most GUI toolkits do), which is against SDL design. Also, since SDL's main target are video games, scenes there are rarely static.
Before SDL2 there was no renderer and SDL only provided display surface to which you draw, but it is quite the same basic concept, it wouldn't update all by itself.
It doesn't mean it cannot be done with SDL, however - it gives you much more control. If you want to redraw only when it is really required - watch for SDL_WindowEvent.
I'm trying to display a texture onto the screen but all I'm getting is a black window.
No SDL Errors are being reported. There's a good chance that I'm missing something stupid, but I can't see it. Hopefully another set of eyes will help. Feel free to ask for more code/info.
main.cpp
SDL_Window * window;
SDL_Renderer * renderer;
SDL_Texture * grass;
SDL_Rect g_dst;
SDL_Event event;
Game app;
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("tmp", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
g_dst.x = g_dst.y = 0;
g_dst.w = 640;
g_dst.h = 480;
grass = IMG_LoadTexture(renderer, "grass.bmp");
while (app.isRunning()) {
app.pollEvents(&event);
app.render_init();
app.render(grass, NULL, &g_dst);
app.render_end();
}
//SDL_Quit() is handled by the Game class' destructor
Game.cpp
//Only functions used for rendering are shown
void render_init(Uint8 red=0, Uint8 green=0, Uint8 blue=0, Uint8 alpha=255)
{
SDL_SetRenderDrawColor(renderer, red, green, blue, alpha);
SDL_RenderClear(renderer);
}
void render(SDL_Texture * texture, SDL_Rect * src, SDL_Rect * dest) {
SDL_RenderCopy(renderer, texture, src, dest);
}
void render_end() { SDL_RenderPresent(renderer); }
First of all, you're initializing everything? please don't do that frequently, mind you that you're also initializing MANY unnecessary stuffs like for game controllers, etc. if the app gets bigger then the efficiency and the possibility of this app running at a smoot speed is at stake.
I also noticed that you are declaring variables in the .cpp file, do that in the header file and just recall the header to the cpp file that will be using it.
You want to render the grass right? and render it as much as the screens size.
(I'll just assume that you used this in the game.cpp part, which is the very first file, thus, not regarding any classes made)
int winWidth = 680; //The reason for this is just in case you make the window resizable
int winHeight = 480; //then the texture would also resize along with the window
SDL_Window *window = window = SDL_CreateWindow("The Space Project", 100, 100, winWidth, winHeight, SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = NULL; //I've set this to NULL so that we can know if
the reason as to why your image is not rendering is because the renderer is not properly working.
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED);
if(renderer == NULL)
{
cout >> "Renderer is not working" >> endl;
//This shows a line at the command prompt that your renderer doesn't have any output, thus, only having a NULL as an equivalent
}
SDL_Texture* grass= NULL;
grass= IMG_LoadTexture(renderer, "grass.bmp"); //As you can see, I've set the grass to Null again
if(grass == NULL)
{
cout >> "Grass have failed to initialize" >> endl;
/*I don't normally do this but it's very important if you really need trouble shooting guides
but this time, were here to check IF the grass.bmp entered the SDL_Texture grass, so if the system can't find the .bmp file then it would show this error
since the grass (SDL_Texture) still doesn't have anything inside it (NULL)*/
}
SDL_Rect grass_rect;
grass_rect.x = 0;
grass_rect.y = 0;
grass_rect.w = winWidth;
grass_rect.h = winHeight;
//Loop part, I'll skip some of it
while (!quit && mainEvent->type != SDL_QUIT) //!quit is just an imaginary Boolean I've typed)
{
SDL_PollEvent(mainEvent); //Let's say you created the event already
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, grass, NULL, &grass_rect);
//The NULL part is also similar to a rect but it's a limiting type, we didn't assign anything to it
since I assumed that you wanted the whole image to be rendered
SDL_RenderPresent(renderer);
}
I revised the code and made it more efficient since your code called for useless extras which might result in lower performance.
I also notice that you tried calling for color changes?
use this
SDL_SetTextureColorMod(texture, red-value, green-value, blue-value);
and put it in the loops part under the render present of the same texture.
SDL_SetTextureColorMod(grass, 250, 250, 250);
Doing this would set all color values to 250, thus, having a white color, this change your texture color to white.
You're also wasting space on making the app.is running(), you could easily replace it with a boolean, which consumes much less space or you could omit it if you don't have an exit button inside the application and just make your loop read the SDL_QUIT, this saves space for the file, mind the efficiency.
If this still doesn't work then try replacing the image your using, make a simple one on paint name it something like "grass.png" or anything then try it again.
Don't forget to put the file in the proper folder, in the DEBUG folder if you haven't specified a folder, and also put it in the app folder so it would also read it when it executes as an .exe file and not as part of the debug command.