Tuesday, October 7, 2008

SDL Window

I got SDL 1.3 to fully initialisize a window - without and use of 1.2-commands of course!
There's one problem though: The renderer seems to somehow get screwed when you user minimizes the window and then opens it again... I haven't found a decent solution yet.

If you want more information about the SDL-functions, justlook at the declaration - there's a big block of comment to tell you what it's for and how to use it.

Anyways, so far it's easy:
First, initialisize the video sub-system:
SDL_VideoInit(NULL, 0)
If the first argument is NULL then the default video driver is choosen; the second argument defines the flags to initialisize with. The only flag useable here is SDL_INIT_EVENTTHREAD, which puts the events into an own thread - but that's not supported by some OSs. If you try to initialisize with this flag, but the OS does not support it, SDL will throw an error and exit. On OSs where you have to have the events an an own thread, it's set automatically. As I use Win32 it's 0, because Windows does not support that.
To check if it is available on your platform (in the code) you can use CANT_THREAD_EVENTS in SDL_sysevents.h. So if you prefer threaded events, but also want platform independence, you just use that.

Now that we have initialisized the video sub-system, let's create a window:
mainWnd = SDL_CreateWindow("Title", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
The only two things worthy to mentoin here are, that SDL_WINDOW_SHOWN will automatically raise the window, and mainWnd is a variable of the type SDL_WindowID.
mainWnd will be useful if you want to do something with your created window, such as

creating a renderer:
SDL_CreateRenderer(mainWnd, -1, SDL_RENDERER_PRESENTFLIP2|SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_ACCELERATED)
This -1 there picks the first driver which can handle the flags given.
The ones I gave are for having a double buffered renderer which has vertical synchonisazion and is hardware accelerated.

For now I just filled it with one color. To do that you need to select the renderer of the window first:
SDL_SelectRenderer(mainWnd)
The renderer is stored internally, so you don't need some variable to save that.

Then you can draw in it, e.g. filling the window with one color:
SDL_RenderFill(0x22, 0x22, 0xFF, SDL_ALPHA_OPAQUE, NULL)
The NULL-argument shoud be a pointer to a SDL_Rect; if it's NULL then the whole plane will be filled with the given color.

So, you will need an event-handler, which is as simple as in SDL.
So, here's my main-code, a little bit beautified:

#include "libbase.h"

#include
#include

#include "SDL.h"
#include "SDL_video.h"

using ::std::cerr;
using ::std::clog;
using ::std::endl;

static SDL_WindowID mainWnd;

static void initSDL(const Uint32& flags = 0);
static void quit(const int& exitVal);
static void render(void);
static void createWindow(void);
inline static void error(const string_t& msg = _T(""), const int& exitVal = ERROR);

int main(int, char**) {
bool done = false;
SDL_Event event;
Uint32 mainWndFlags;

initSDL(); //SDL_INIT_EVENTTHREAD
createWindow();

while (!done) {
/*if(SDL_WaitEvent(&event) == 0) {
clog <<>
continue;
}*/
while(SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYUP:
switch(event.key.keysym.sym) {
case SDLK_ESCAPE:
SDL_Event quit;
quit.type = SDL_QUIT;
SDL_PushEvent(&quit);
break;

default:
break;
}
break;

case SDL_WINDOWEVENT:
switch(event.window.event) {
case SDL_WINDOWEVENT_CLOSE:
SDL_Event quit;
quit.type = SDL_QUIT;
SDL_PushEvent(&quit);
break;

case SDL_WINDOWEVENT_EXPOSED:
render();

default:
break;
}
break;

case SDL_QUIT:
done = true;
break;

default:
break;
}
}
mainWndFlags = SDL_GetWindowFlags(mainWnd);
if(!(mainWndFlags & SDL_WINDOW_INPUT_FOCUS))
SDL_Delay(200);
}
quit(NORMAL);
#if defined(_DEBUG)
return 0;
#endif
}

void quit(const int& exitVal) {
if(mainWnd)
SDL_DestroyWindow(mainWnd);

clog <<>

SDL_Quit();
exit(exitVal);
}

static void initSDL(const Uint32& flags) {
//if(SDL_Init(flags) <>
// error(_T("Unable to init SDL: "));
if(SDL_VideoInit(NULL, flags) <>
error(_T("Unable to init video"));
}

static void createWindow(void) {
/*
Uint32 bpp = SDL_VideoModeOK(800, 600, 32, SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_HWACCEL); //SDL_RESIZABLE; SDL_HWACCEL; SDL_PREALLOC
if(!bpp)
error(_T("Mode not available"));
else if(bpp != 32)
cerr <<>
*/

/*
SDL_DisplayMode mode;
mode.format = 32;
mode.h = 800;
mode.w = 600;
*/
//if (SDL_SetDisplayMode(NULL) <>
// error(_T("Couldn't set display mode: "));

mainWnd = SDL_CreateWindow("hi!", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN); //SDL_WINDOW_FULLSCREEN
if(!mainWnd)
error(_T("Could not create window"));
if(SDL_CreateRenderer(mainWnd, -1, SDL_RENDERER_PRESENTFLIP2|SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_ACCELERATED) <>
error(_T("Could not create renderer"));

    if(SDL_SelectRenderer(mainWnd)<0)
error(_T("Could not select main-renderer"));
}

static void render(void) {
    if(SDL_RenderFill(0xFF, 0x22, 0xFF, SDL_ALPHA_OPAQUE, NULL)<0)
error(_T("Could not draw in main-renderer"));

SDL_RenderPresent();
}

static void error(const std::string& msg, const int& exitVal) {
std::string err(SDL_GetError());

cerr <<>

if(err.empty()) {
cerr <<>
quit(FATAL);
} else
cerr <<>

quit(exitVal);
}

I used some stuff defined in libbase.h; I think you can imagine what. I know the streams are not made for _T yet. And the codingstyle is not final at all; it's just something right now, close to what I normally use (for private code). I need to discuss with Ionenbombe how we will format our code.

EDIT: Blogger fucked of the formatation somehow. I wanted to give the code a different font... oh well, you have to live with that. It also fucked with the streaming-operators.. no big deal though.

2 comments:

Anonymous said...

Hi,
Thanks for providing information first of all.

I tried using ur example and successfully created two windows but what I want to achieve is to play 2 videos simultaneously on these two windows. On debugging, I found that the overlay on these windows was not getting created. It could only be created on window creted with SetVideoMode api.

Can you please provide help on this.

z33ky said...

As you see, SetVideoMode is a function for backwardscompatibility to SDL 1.2.*. I want to avoid using these and do is the straight way.
I have posted the bug I found here: http://bugzilla.libsdl.org/show_bug.cgi?id=635
There is also a bit more explanation(I found out it's somehow related to the DirectX-Layer).

Then, for two windows you cannot use the SDL_compat-function as SDL 1.2.* does not support multiple windows (at least not by itself).
So, what you wanna do is simply storing two SDL_WindowID's and initializing both windows.
You might wanna make a thread per window and then render to one SDL_WindowID.

If your error however is related to playing videos than I cannot help. The SDL-project is abandoned for an unknown time as I am concentrating on the two HL2-mods and a little side-project right now.