Just implemented a SDL_Renderer in my engine
state_t init_rend(window_t *context,flag_t flags) {
rend.renderer = NULL;
rend.renderer = SDL_CreateRenderer(context,-1,flags);
rend.index = -1;
if (rend.renderer != NULL) {
return TRUE;
} else {
return FALSE;
}
}
In my client/test app:
// Init Base2D game
init_env(VIDEO|AUDIO);
// Init Display display
init_disp(640,480,"Display",RESIZABLE|VISIBLE,make_color(255,255,255,255));
// Init Renderer renderer
init_rend(display->window,SOFTWARE);
// Game Loop
state_t status;
while (TRUE) {
update();
status = listen();
if (!status) {
break;
}
/* User Event Handles */
}
And I could handle window resizing successfully with:
void resize_window() {
printf("I was here!\n");
SDL_FreeSurface(display->container);
printf("Now I am here\n");
display->container = SDL_GetWindowSurface(display->window);
SDL_FillRect(
display->container,
NULL,
SDL_MapRGBA(
display->container->format,
get_red(),
get_green(),
get_blue(),
get_alpha()
)
);
}
However, since I have implemented the renderer, whenever I attempt to resize my display it segfaults when trying to SDL_FreeSurface(display->container).
As I have mentioned, the resizing worked fine until I implemented a renderer.
Why is this happening?
Following the link provided by user:keltar,
It seems to me the way to go with SDL2 is to use a renderer for drawing to the window intead of the old SDL1 method of using a surface.
I did just that, removed the surface code and used a renderer only and the code works without problem
Thank You
Related
Rewriting this to try to provide some clarity and update the code with some things that have changed.
I am restructuring a project that used SDL2, and have encountered issues trying to create a blank window. I have attempted to structure the project similarly to the original by separating all functionality dealing with SDL_Window into its own class. If I move the call to SDL_CreateWindow into the same class as the event loop or move the event loop to the same class as the window, the window is created and shown as expected, however as it is now, the window appears to be created successfully (SDL_CreateWindow is not returning NULL) and the program doesn't seem to be hanging, but it does not display a window while the program is running.
The SDL_Window is created in the Graphics class and stored in a member variable:
Graphics::Graphics(const char* title, unsigned int w, unsigned int h, unsigned int flags, int& status) {
screen = SDL_CreateWindow(title,
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
w, h,
flags);
status = 0;
if (screen == NULL)
status = 1;
}
Graphics is instantiated in the Window class and stored in a member variable.
Window::Window(const char* title, unsigned int w, unsigned int h, unsigned int flags, int& status) {
g = Graphics(title, w,h, flags, status);
}
Window is instantiated in main, and if the window is created successfully, it starts the event loop.
{
int status;
Window window("Mirari", 640,480, SDL_WINDOW_SHOWN, status);
if (status == 0) {
window.eventLoop();
} else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window and renderer: %s", SDL_GetError());
return 1;
}
}
The event loop itself to be thorough (update and draw are both currently empty functions).
void Window::eventLoop() {
SDL_Event ev;
bool running = true;
while (running) {
const int start_time = SDL_GetTicks();
while (SDL_PollEvent(&ev)) {
switch (ev.type) {
case SDL_QUIT:
running = false;
break;
default:
break;
}
}
//update();
//draw();
std::cout << "." << std::endl;
const int elapsed = SDL_GetTicks() - start_time;
if (elapsed < 1000 / FPS)
SDL_Delay(1000 / FPS - elapsed);
}
}
SDL is initialized with this static function and these flags.
void Window::init(unsigned int sdl_flags, IMG_InitFlags img_flags) {
SDL_Init(sdl_flags);
IMG_Init(img_flags);
TTF_Init();
}
...
Window::init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER, IMG_INIT_PNG);
I know that a window can be created in a separate class because the first version of this project did that and it worked, I'm just not sure what has changed that is causing the window not to show up.
As said by some programmer dude, you design is not perfect and should be thought again.
Nevertheless, from what we can see on your code : If the Window constructor is called (and the SDL_Init was called before, which I assume so), then the windows should be created.
From there we only can guess what we can't see (as it's not part of what you are displaying) :
is the definition of SDL_WINDOWPOS_UNDEFINED, the same in both context ?
is the screen variable definition the same in both context ?
is the "screen" used in "update", or "draw" method, and, as uninitialized : it fails
... ?
As you probably are new to development, I suggest you adopt this habit very early : your code should check and report everything it does. A good program is easy to debug, as it says what's wrong
For instance, just after :
screen = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
w, h, flags);
you may want to write something like :
if(!screen)
{
std::cout << "Failed to create window\n";
return -1;
}
or better :
if(!screen)
{
throw std::exception("Failed to create window\n");
}
And so on.
For instance, in your function update, you may want to have something like :
if(!screen)
{
throw std::exception("Unable to update the display as it is uninitialized\n");
}
I assume your application would not end without any comment... but that's a guess
I use the following structure to get new width and height of the resized SDL window:
if (sdl_set->GetMainEvent()->type == SDL_WINDOWEVENT)
{
if (sdl_set->GetMainEvent()->window.event == SDL_WINDOWEVENT_RESIZED)
{
ScreenWidth = sdl_set->GetMainEvent()->window.data1;
ScreenHeight = sdl_set->GetMainEvent()->window.data2;
cout << "Window Resized!" << endl;
}
}
But with this structure I'm only able to get new data after the resizing is done that is when I finish dragging and release the mouse button.
How can I get the new data continuously, that is while I'm dragging the window?
static int resizingEventWatcher(void* data, SDL_Event* event) {
if (event->type == SDL_WINDOWEVENT &&
event->window.event == SDL_WINDOWEVENT_RESIZED) {
SDL_Window* win = SDL_GetWindowFromID(event->window.windowID);
if (win == (SDL_Window*)data) {
printf("resizing.....\n");
}
}
return 0;
}
int main() {
SDL_Window* win = ...
...
SDL_AddEventWatch(resizingEventWatcher, win);
...
}
use SDL's EventWatch can resolve it.
If you are on windows, have you tried using the windows api?
I know its not a real fix but if you are not making a cross platform application, you should give it a shot.
Use HWND to find SDL's window and return the window size.
Okay so while i was on holiday i was working on my laptop and i decided to make the move from Win32 API to Qt and everything was working fine. Until i got back on my PC, that is. This problem only occurs on my PC and not on my laptop i have used win merge to try and detect any differences and there are NONE.
The way i have implemented this is i have a GameView class derived from QWidget and I've overridden the paintEngine function to do nothing and i set the DirectX HWND to the WId of the game view QWidget.
Any help on this would be greatly appreciated
This gets called during initialization to create the window
bool Engine::CreateDisplay()
{
m_pQtApp = new QApplication(m_nArgCount, m_pArgV);
m_pGameWindow = new GameWindow(this);
m_pGameWindow->show();
m_pGameView = new GameView(this);
m_pGameView->setParent(m_pGameWindow);
m_pGameView->show();
m_pGameView->resize(800, 600);
m_pGameWindow->setCentralWidget((QWidget*)m_pGameView);
return true;
}
Then once everything is initialized this gets called
int Engine::StartGameLoop()
{
m_bIsRunning = true;
m_pCurrentWorld->BeginPlay();
//MSG msg {};
while(m_bIsRunning)
{
/*if(PeekMessage(&msg, m_hWnd, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}*/
m_pQtApp->processEvents();
if(m_bIsRunning)
{
//m_pGameView->update();
Update();
Render();
}
}
m_pCurrentWorld->EndPlay();
return 0;
}
This is the resize event I modified
void GameView::resizeEvent(QResizeEvent* pEvent)
{
if(m_pEngine->GetGraphics())
m_pEngine->GetGraphics()->SetResolution(pEvent->size().width(), pEvent->size().height());
//QWidget::resizeEvent(pEvent);
}
I think I have a bug in my program. I use SDL and OpenGL to render an animation. The program also measures the average FPS. Tipically, when I run the program, it will run at around 550 FPS.
However, if I start a second instance of the program, the FPS drops for both at around half (220 FPS). The strange thing is that if I close the first instance, the second one will still run at only 220 FPS. This leads me to believe that my cleanup code is somehow flawed.
Sometimes, even if I run a single instance, it will run at only 220 FPS, probably due to a previous instance that failed to clean up properly. Is there something wrong with my approach below?
I use a screen class which has the following *tors:
namespace gfx
{
screen::screen(const settings& vs) : dbl_buf_(false), sdl_surface_(0)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
throw util::exception(::std::string("Unable to initialize SDL video: ") + SDL_GetError());
if (!set(vs))
{
SDL_Quit();
throw util::exception("Unable to setup initial video mode.");
}
glewInit();
}
screen::~screen()
{
SDL_Quit();
}
bool screen::set(const settings& vs)
{
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
Uint32 flags = SDL_HWSURFACE | SDL_OPENGL;
if (vs.full_screen) flags |= SDL_FULLSCREEN;
sdl_surface_ = SDL_SetVideoMode(vs.size_x, vs.size_y, vs.bpp, flags);
if (!sdl_surface_) return false;
settings_ = vs;
int db_flag = 0;
SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &db_flag);
dbl_buf_ = (db_flag == 1);
return true;
}
// ...
}
Also:
int main()
{
try
{
gfx::settings vs = {800, 600, 32, false};
gfx::screen scr(vs);
// main app loop, render animation using OpenGL calls
// loop runs while running_ variable is true (see below)
}
// catch, etc.
return 0;
}
If it makes any difference, I use Linux and an ATI card.
Update: Event handling code:
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_ESCAPE)
running_ = false;
break;
case SDL_QUIT:
running_ = false;
break;
default:
world_.process_event(event);
break;
}
}
When a process terminates all the resources it used are freed automatically. That includes OpenGL. What may happen is, that you don't terminate your process but only hide the window by clicking the close button.
I wish to have a semi-transparent SDL background (nothing to do with sub-surfaces or images), such that instead of having a black background it is actually transparent, but the other things I draw are not. My current code is a slightly modified copy of Code::Blocks' SDL project, similar to how various applications have rounded borders or odd shapes besides rectangles.
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#ifdef __APPLE__
#include <SDL/SDL.h>
#else
#include <SDL.h>
#endif
int main ( int argc, char** argv )
{
putenv("SDL_VIDEO_WINDOW_POS");
putenv("SDL_VIDEO_CENTERED=1");
// initialize SDL video
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "Unable to init SDL: %s\n", SDL_GetError() );
return 1;
}
// make sure SDL cleans up before exit
atexit(SDL_Quit);
// create a new window
SDL_Surface* screen = SDL_SetVideoMode(640, 480, 16,
SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_NOFRAME);
if ( !screen )
{
printf("Unable to set 640x480 video: %s\n", SDL_GetError());
return 1;
}
// load an image
SDL_Surface* bmp = SDL_LoadBMP("cb.bmp");
if (!bmp)
{
printf("Unable to load bitmap: %s\n", SDL_GetError());
return 1;
}
// centre the bitmap on screen
SDL_Rect dstrect;
dstrect.x = (screen->w - bmp->w) / 2;
dstrect.y = (screen->h - bmp->h) / 2;
// program main loop
bool done = false;
while (!done)
{
// message processing loop
SDL_Event event;
while (SDL_PollEvent(&event))
{
// check for messages
switch (event.type)
{
// exit if the window is closed
case SDL_QUIT:
done = true;
break;
// check for keypresses
case SDL_KEYDOWN:
{
// exit if ESCAPE is pressed
if (event.key.keysym.sym == SDLK_ESCAPE)
done = true;
break;
}
} // end switch
} // end of message processing
// DRAWING STARTS HERE
// clear screen
SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
// draw bitmap
SDL_BlitSurface(bmp, 0, screen, &dstrect);
// DRAWING ENDS HERE
// finally, update the screen :)
SDL_Flip(screen);
} // end main loop
// free loaded bitmap
SDL_FreeSurface(bmp);
// all is well ;)
printf("Exited cleanly\n");
return 0;
}
I think what you're trying to do is in fact a shaped window (parts of the window are transparent depending on a mask that you provide). It seems there's no way to do that with SDL 1.2, however there is a SDL_SetWindowShape function just for this in SDL 1.3 for which you can find a pre-release snapshot here but it's not even in beta yet so I suggest waiting until it's officialy released :)
this is a link to a pretty neat article about development of an older application for Mac OS 9, which did not have support for shaped windows, either.
It's actually a neat article in general about software development.
But the idea seems pretty smart, and I wonder if you might be able to get it working here, too. Instead of trying to make a transparent background, they actually take a screen-shot of the computer right where their window is going to go, and then use that screen shot for their background. When the user drags the window around on the screen, they continue to update the background with new screen-shots. I think this might be more complicated than you were hoping for, but it's certainly an interesting idea.