How can I handle input in SDL? - c++

My SDL program wont work. It was supposed to change the image when I pressed Up. However, it changes the image only when I click on the x in the Window
#include "SDL.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
int main(int argc, char* argv[])
{
enum KeyPressSurfaces {
KEY_PRESS_SURFACE_DEFAULT,
KEY_PRESS_SURFACE_UP,
KEY_PRESS_SURFACE_LEFT,
KEY_PRESS_SURFACE_RIGHT,
KEY_PRESS_SURFACE_DOWN,
KEY_PRESS_SURFACE_TOTAL
};
SDL_Init(SDL_INIT_VIDEO);
SDL_Event e;
SDL_Window* window = SDL_CreateWindow("antena1", // window's title
10, 25, // coordinates on the screen, in pixels, of the window's upper left corner
640, 420, // window's length and height in pixels
SDL_WINDOW_OPENGL);
SDL_Surface* key_press_surface[KEY_PRESS_SURFACE_TOTAL];
SDL_Surface* gImage = NULL;
SDL_Surface* gScreenSurface = NULL;
bool quit = false;
key_press_surface[KEY_PRESS_SURFACE_UP] = SDL_LoadBMP("hello_world.bmp");
gScreenSurface = SDL_GetWindowSurface(window);
gImage = SDL_LoadBMP("nick.bmp");
if (gImage == NULL) {
printf("Erro", SDL_GetError);
}
SDL_BlitSurface(gImage, NULL, gScreenSurface, NULL);
SDL_UpdateWindowSurface(window);
gScreenSurface = SDL_GetWindowSurface(window);
while (!quit) {
while (SDL_PollEvent(&e) == 0) {
if (e.type == SDL_QUIT) {
quit = true;
//SDL_DestroyWindow(window);#
}
else if (e.type == SDL_KEYDOWN) {
switch (e.key.keysym.sym) {
case SDLK_LEFT:
gImage = key_press_surface[KEY_PRESS_SURFACE_UP];
break;
default:
gScreenSurface = NULL;
break;
}
}
}
};
SDL_BlitSurface(gImage, NULL, gScreenSurface, NULL);
SDL_UpdateWindowSurface(window);
SDL_Delay(30000);
return 0;
}

https://wiki.libsdl.org/SDL_PollEvent
SDL_PollEvent returns 0 if there are no events available. So per the example in the above article, in order to get into the while statement for SDL_PollEvent, there must be events in the queue. However, your code only goes into the loop if there are NO events in the queue. So anything that happens once you get there is undefined.
IOW, just remove the "== 0".

Related

Why doesn't the default case run here?

I wrote these following lines of codes:
#include <sdl.h>
#include <iostream>
#include <stdio.h>
#include <string>
bool running = true;
enum KeyPressSurfaces {
KEY_PRESS_SURFACE_DEFAULT,
KEY_PRESS_SURFACE_UP,
KEY_PRESS_SURFACE_DOWN,
KEY_PRESS_SURFACE_LEFT,
KEY_PRESS_SURFACE_RIGHT,
//de deallocate surface
KEY_PRESS_SURFACE_TOTAL
};
int main(int argc, char** argv) {
//standard stuffs
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("vibin' with smug pika", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 300, 300, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Surface* loadSurface(std::string path);
SDL_Surface* surface = SDL_GetWindowSurface(window);
SDL_Surface* keypress [KEY_PRESS_SURFACE_TOTAL];
//anh hien tai dang duoc load, de BlitSurface len surface
//SDL_BlitSurface(current --> surface)
SDL_Surface* current = NULL;
//set windows icon
SDL_Surface* icon = SDL_LoadBMP("../pikachu/keypress_bmp/icon.bmp");
SDL_SetWindowIcon(window, icon);
SDL_Event event;
//load each image into the keypress array
keypress[KEY_PRESS_SURFACE_DEFAULT] = SDL_LoadBMP("../pikachu/keypress_bmp/default.bmp");
keypress[KEY_PRESS_SURFACE_UP] = SDL_LoadBMP("../pikachu/keypress_bmp/up.bmp");
keypress[KEY_PRESS_SURFACE_DOWN] = SDL_LoadBMP("../pikachu/keypress_bmp/down.bmp");
keypress[KEY_PRESS_SURFACE_LEFT] = SDL_LoadBMP("../pikachu/keypress_bmp/left.bmp");
keypress[KEY_PRESS_SURFACE_RIGHT] = SDL_LoadBMP("../pikachu/keypress_bmp/right.bmp");
while (running) {
while (SDL_PollEvent(&event)){
switch (event.type) {
//user click x
case SDL_QUIT:
running = false;
break;
//where all the user inputs are handled
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_UP:
current = keypress[KEY_PRESS_SURFACE_UP];
break;
case SDLK_DOWN:
current = keypress[KEY_PRESS_SURFACE_DOWN];
break;
case SDLK_LEFT:
current = keypress[KEY_PRESS_SURFACE_LEFT];
break;
case SDLK_RIGHT:
current = keypress[KEY_PRESS_SURFACE_RIGHT];
break;
case SDLK_SPACE:
current = keypress[KEY_PRESS_SURFACE_DEFAULT];
break;
default:
current = keypress[KEY_PRESS_SURFACE_DEFAULT];
}
}
}
SDL_BlitSurface(current, NULL, surface, NULL);
SDL_UpdateWindowSurface(window);
}
//deallocating surfaces
for(int i=0; i<KEY_PRESS_SURFACE_TOTAL; ++i) {
SDL_FreeSurface(keypress[i]);
keypress[i] = NULL;
}
//destroy everythangggg
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}
However, this bit:
default:
current = keypress[KEY_PRESS_SURFACE_DEFAULT];
does not run at all, no matter where I put it. The program should have shown the default image at the beginning, but there's only black when I compiled. Everything else runs fine and I cannot determine what mistake I make.
I'm using CodeBlock version 20.03 and the latest version of SDL2.
I created a solution for you, and I have some notes to check from your end,
Check if the file path is correct
../pikachu/keypress_bmp/default.bmp.
When you want to trigger the default, you should press another key
e.i Enter, A, B, etc.
I have downloaded an SDL library I am not sure if you are using the
same, but mine is V2.
I have commented on your code, which I didn't use here in the image
path.
here is my code and result:
//#include <sdl.h>
#include <SDL.h>
#include <iostream>
#include <stdio.h>
#include <string>
bool running = true;
enum KeyPressSurfaces {
KEY_PRESS_SURFACE_DEFAULT,
KEY_PRESS_SURFACE_UP,
KEY_PRESS_SURFACE_DOWN,
KEY_PRESS_SURFACE_LEFT,
KEY_PRESS_SURFACE_RIGHT,
//de deallocate surface
KEY_PRESS_SURFACE_TOTAL
};
int main(int argc, char** argv) {
//standard stuffs
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("vibin' with smug pika", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 300, 300, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Surface* loadSurface(std::string path);
SDL_Surface* surface = SDL_GetWindowSurface(window);
SDL_Surface* keypress[KEY_PRESS_SURFACE_TOTAL];
//anh hien tai dang duoc load, de BlitSurface len surface
//SDL_BlitSurface(current --> surface)
SDL_Surface* current = NULL;
//set windows icon
//SDL_Surface* icon = SDL_LoadBMP("../pikachu/keypress_bmp/icon.bmp");
SDL_Surface* icon = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/img1.bmp");
SDL_SetWindowIcon(window, icon);
SDL_Event event;
//load each image into the keypress array
/*
keypress[KEY_PRESS_SURFACE_DEFAULT] = SDL_LoadBMP("../pikachu/keypress_bmp/default.bmp");
keypress[KEY_PRESS_SURFACE_UP] = SDL_LoadBMP("../pikachu/keypress_bmp/up.bmp");
keypress[KEY_PRESS_SURFACE_DOWN] = SDL_LoadBMP("../pikachu/keypress_bmp/down.bmp");
keypress[KEY_PRESS_SURFACE_LEFT] = SDL_LoadBMP("../pikachu/keypress_bmp/left.bmp");
keypress[KEY_PRESS_SURFACE_RIGHT] = SDL_LoadBMP("../pikachu/keypress_bmp/right.bmp");
*/
keypress[KEY_PRESS_SURFACE_DEFAULT] = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/imgD.bmp");
keypress[KEY_PRESS_SURFACE_UP] = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/img3.bmp");
keypress[KEY_PRESS_SURFACE_DOWN] = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/img4.bmp");
keypress[KEY_PRESS_SURFACE_LEFT] = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/img5.bmp");
keypress[KEY_PRESS_SURFACE_RIGHT] = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/img6.bmp");
while (running) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
//user click x
case SDL_QUIT:
running = false;
break;
//where all the user inputs are handled
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_UP:
current = keypress[KEY_PRESS_SURFACE_UP];
break;
case SDLK_DOWN:
current = keypress[KEY_PRESS_SURFACE_DOWN];
break;
case SDLK_LEFT:
current = keypress[KEY_PRESS_SURFACE_LEFT];
break;
case SDLK_RIGHT:
current = keypress[KEY_PRESS_SURFACE_RIGHT];
break;
case SDLK_SPACE:
current = keypress[KEY_PRESS_SURFACE_DEFAULT];
break;
default:
current = keypress[KEY_PRESS_SURFACE_DEFAULT];
}
}
}
SDL_BlitSurface(current, NULL, surface, NULL);
SDL_UpdateWindowSurface(window);
}
//deallocating surfaces
for (int i = 0; i < KEY_PRESS_SURFACE_TOTAL; ++i) {
SDL_FreeSurface(keypress[i]);
keypress[i] = NULL;
}
//destroy everythangggg
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}

Compiler can't find SDL headers?

I downloaded the SDL .zip files and added the added the "include" files as necessary. When I went to run the example that had been pre-made by Code::Blocks, an error occured that said "SDL/SDL.h: No file or directory". Any help? Code below:
ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include <SDL/SDL.h>
int main ( int argc, char** argv )
{
// 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);
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;
}

SDL_BlitSurface doesn't draw to screen

I'm trying to simply create a window and blit an image to the screen but for some reason the image is not showing up and the screen remains white. I've been using lazyfoo's tutorial for reference in order to figure this out. I posted all my code below, hopefully it's readable enough. Help would be appreciated as I've been stuck on this for an hour or two, thank you.
#include <SDL.h>
#include <SDL_audio.h>
#include <cstdio>
#include <iostream>
#include <Windows.h>
// creates Load_surface function
SDL_Surface *loadSurface(std::string path) {
SDL_Surface *loadedSurface = SDL_LoadBMP(path.c_str());
if (loadedSurface == NULL) {
printf("Unable to load image %s! SDL Error: %s\n", path.c_str(),
SDL_GetError());
}
return loadedSurface;
}
int main(int argc, char ** argv)
{
// pointer variable for window
SDL_Window *window;
SDL_Surface *surface = NULL;
SDL_Surface *media =
loadSurface("C:\\Users\\nickl\\Desktop\\buttonpressed.bmp");
// initialize and test for failure
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) == -1) {
return 1;
}
// create the window
window = SDL_CreateWindow(
"Ice Cream Boys Software",
48,
48,
640,
480,
SDL_WINDOW_OPENGL
);
// safety check, see if window was created, otherwise throw an error
if (window = NULL) {
printf("Could not create window: %s", SDL_GetError());
return 1;
}
else {
OutputDebugString(TEXT("Surface loaded.\n"));
surface = SDL_GetWindowSurface(window);
}
SDL_BlitSurface(media, NULL, surface, NULL);
SDL_UpdateWindowSurface(window);
/* ************************************** loop **************************** */
// bool to keep window open and event handler
bool quit = false;
SDL_Event e;
// loop to keep window open
while (!quit) {
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = true;
}
else if (e.type == SDL_KEYDOWN) {
OutputDebugString(TEXT("My output string.\n"));
}
}
}
/* ************************************************************************** */
// close and destroy window
SDL_DestroyWindow(window);
// quit
SDL_Quit();
return 0;
}

SDL text rendering access violation

I'm using SDL 2.0 with C++ for 2D graphics, compressed image format loading, sound playback and so on. Consider the following code:
int main(int argc, char *args[])
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
SDL_Window *pWindow = SDL_CreateWindow("Access Violation", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1920, 1080, SDL_WINDOW_FULLSCREEN);
SDL_Renderer *pRenderer = SDL_CreateRenderer(pWindow, -1, SDL_RENDERER_ACCELERATED);
Mix_Init(0);
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048);
Mix_Music *pMusic = Mix_LoadMUS("music.wav");
TTF_Init();
TTF_Font *pFont = TTF_OpenFont("font.ttf", 28);
bool quit = false;
SDL_Event ev;
while(!quit)
{
while(SDL_PollEvent(&ev) != 0)
{
switch(ev.type)
{
case SDL_QUIT:
quit = true;
break;
}
}
SDL_SetRenderDrawColor(pRenderer, 255, 255, 255, 255);
SDL_RenderClear(pRenderer);
for(int i = 0; i < 864; i++)
{
SDL_Color clr = { 0, 0, 0 };
SDL_Surface *pSurface = TTF_RenderText_Solid(pFont, "Hey!", clr);
SDL_Texture *pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);
SDL_Rect dstrect = { (int)(i/27) * 60, (i%27)*40, pSurface->w, pSurface->h };
SDL_RenderCopy(pRenderer, pTexture, 0, &dstrect);
SDL_DestroyTexture(pTexture);
SDL_FreeSurface(pSurface);
}
SDL_RenderPresent(pRenderer);
}
TTF_CloseFont(pFont);
Mix_FreeMusic(pMusic);
SDL_DestroyRenderer(pRenderer);
SDL_DestroyWindow(pWindow);
Mix_CloseAudio();
Mix_Quit();
IMG_Quit();
TTF_Quit();
SDL_Quit();
return 0;
}
What this basically does is that it just initializes SDL, loads a music, loads a font, and fills continuously the whole screen with text. Fine.
But!
If I add this line
...
SDL_Event ev;
Mix_PlayMusic(pMusic, 0);
while(!quit)
...
right here, text redrawing in the cycle
for(int i = 0; i < 864; i++)
{
...
}
starts to behave unpredictably. One of the SDL's function will shoot an access violation, after some time - between 1 and 30 seconds after start. On the other hand, would I omit text redrawing, music is playing fine.
Any ideas? Of course, all return values are checked. I've omitted checks because of the clarity of the code.
EDIT: Typos.

XOpenDisplay failing

I'm writing a simple window class which is failing to return a display. Here's the short version:
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
class WindowImpl
{
public:
WindowImpl()
{
open = true;
}
WindowImpl(float width, float height)
{
if(!create(width, height))
{
fprintf(stderr, "Could not open display\n");
exit(1);
}
open = true;
}
~WindowImpl()
{
XCloseDisplay(display);
};
bool create(float width, float height)
{
display = XOpenDisplay(NULL);
if(display == NULL)
return false;
int displayID = DefaultScreen(display);
window = XCreateSimpleWindow(display, RootWindow(display, displayID), 10, 10, width, height, 1, BlackPixel(display, displayID), WhitePixel(display, displayID));
XMapWindow(display, window);
return true;
}
bool isOpen()
{
return open;
}
void close()
{
open == false;
}
private:
Display* display;
Window window;
bool open;
};
int main()
{
WindowImpl myWindow(1920, 1080);
char* cmd;
while(myWindow.isOpen())
{
if(gets(cmd) == "close")
myWindow.close();
}
return 0;
}
WindowImpl::create fails, XOpenDisplay is returning NULL but I'm not sure why. Hopefully someone could shed some light on the problem here.
Edit: Changing WindowImpl::create to return true and false instead of 0 and 1 causes it to go through but the window still doesn't open;
For clarification:
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
Display* display;
Window window;
XEvent event;
char* message = "Hello";
int screenSize;
display = XOpenDisplay(NULL);
if(display == NULL)
{
fprintf(stderr, "Cannot open display\n");
exit(1);
}
screenSize = DefaultScreen(display);
window = XCreateSimpleWindow(display, RootWindow(display, screenSize), 10, 10, 1920, 1080, 1, BlackPixel(display, screenSize), WhitePixel(display, screenSize));
XSelectInput(display, window, ExposureMask | KeyPressMask);
XMapWindow(display, window);
KeySym keysym = XK_Escape;
KeyCode keycode = XKeysymToKeycode(display, keysym);
while(true)
{
XNextEvent(display, &event);
if(event.type == KeyPress && event.xkey.keycode == keycode)
break;
}
XCloseDisplay(display);
return 0;
}
Compiles and runs just fine.
When you create a windows, you need to let the X server to handle output buffer. Normally this is done when you enter into the window event loop, i.e. calling any function that has EVENT in its name.
Once you are not dealing with events in your code, another way to flush the output buffer is calling XFlush, as said in its manual:
The XFlush function flushes the output buffer. Most client applications need not use this function because the output buffer is automatically flushed as needed by calls to XPending, XNextEvent, and XWindowEvent. Events generated by the server may be enqueued into the library's event queue.
The XSync function flushes the output buffer and then waits until all requests have been received and processed by the X server.
So, to solve your issue, I suggest to put this line of code:
window = XCreateSimpleWindow(display, RootWindow(display, displayID), 10, 10, width, height, 1, BlackPixel(display, displayID), WhitePixel(display, displayID));
XMapWindow(display, window);
XFlush(display); // <------------
return true;