In the event handling loop of SDL2, calling the method SDL_GetMouseState(&x,&y);
or using event.motion.x
and event.motion.y
for the relative mouse coordinates makes SDL2 responsiveness VERY SLUGGISH. Whats weird is SDL_GetMouseState()
is alot faster than event.motion.x and y
, however they are both unbearably bad. Is there any other way of getting the mouse pos? You can even try this. I setup a simple text program in SDL2 to test something responsive such as scrolling, where you offset the y values. Try with and without vsync and with and without getting the mouse pos this way. I am currently using linux mint.
Code: (You will need arial.ttf in your folder where the project is if using codeblocks like i am)
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <SDL2/SDL_image.h>
#include <string>
using std::string;
using std::to_string;
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
SDL_Window *window = SDL_CreateWindow("Test Program", 0, 30, 1280, 720, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);// | SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
SDL_Event event;
SDL_Point mousePos = {0,0};
///Fps vars
int fpsCounter, fpsStart, fpsEnd;
fpsStart = SDL_GetTicks();
fpsEnd = SDL_GetTicks();
fpsCounter = 0;
TTF_Font *fpsFont = TTF_OpenFont("arial.ttf", 30);
SDL_Surface *fpsSurface = TTF_RenderText_Blended(fpsFont, "FPS: ", {0,0,0});
SDL_Texture *fpsTexture = SDL_CreateTextureFromSurface(renderer, fpsSurface);
SDL_FreeSurface(fpsSurface);
int textW, textH, yVal;
yVal = 50;
SDL_QueryTexture(fpsTexture, NULL, NULL, &textW, &textH);
SDL_Rect fpsRect = {1000, yVal, textW, textH};
bool running = true;
while (running)
{
while ( SDL_PollEvent(&event) )
{
if (event.type == SDL_QUIT)
{
running = false;
break;
}
else if (event.type == SDL_MOUSEMOTION){
int x,y;
SDL_GetMouseState(&x,&y);
mousePos = {x,y};
break;
}
else if (event.type == SDL_MOUSEWHEEL){
if (event.wheel.y > 0){ ///Scrolling up here
yVal -= 50;
fpsRect.y = yVal;
break;
}
if (event.wheel.y < 0){ ///Scrolling down here
yVal += 50;
fpsRect.y = yVal;
break;
}
}
}
SDL_SetRenderDrawColor(renderer, 255,255,255,255);
SDL_RenderClear(renderer);
//Update every 0.5s (500ms)
fpsEnd = SDL_GetTicks();
fpsCounter += 2;
if ( (fpsEnd-fpsStart) > 500 ){
fpsStart = SDL_GetTicks();
SDL_DestroyTexture(fpsTexture);
///Change text
string newText = ("FPS: " + to_string(fpsCounter));
fpsSurface = TTF_RenderText_Blended(fpsFont, newText.c_str(), {0,0,0});
fpsTexture = SDL_CreateTextureFromSurface(renderer, fpsSurface);
SDL_FreeSurface(fpsSurface);
SDL_QueryTexture(fpsTexture, NULL, NULL, &textW, &textH);
fpsRect = {1000, yVal, textW, textH};
fpsCounter = 0;
}
SDL_RenderCopy(renderer, fpsTexture, NULL, &fpsRect);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(fpsTexture);
TTF_CloseFont(fpsFont);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
TTF_Quit();
SDL_Quit();
return 0;
}
I don't agree that turning off VSYNC is a solution. It shouldn't be like this with VSYNC on regardless. It isn't like this in windows for some reason, it works fine there. Capping the FPS with SDL_Delay() to the refresh rate of the display also gives me the same problem.
The problem is that you "break" every time you get an event. So, your event queue is full all the time as you only process one event per draw.
Replace "break" with "continue" and process all events.