Sign in to follow this  
colinisinhere

SDL_WarpMouse() = really slow?

Recommended Posts

colinisinhere    100
I'm using SDL_WarpMouse() to reset my mouse for my rotateByMouse() function in my 3d camera class. It works right, it is just extremly laggy. Has anyone else used this function for a 3d camera? Does it work for you? Any input? BTW I'm on Linux Thanks

Share this post


Link to post
Share on other sites
Mushu    1396
I looked around and didn't see any negative notes on it. Are you sure that calling it is causing the bottleneck? How often are you calling it? Does it lag only when the mouse is warped, or the whole time?

One thing to note is that warping the mouse will generate a mouse motion event, which can lead to some weird things if you warp the mouse if you're checking for the mouse position after a mouse move. Wow, that sentence was dizzy. Think circular calls. move -> warp -> move -> warp -> move -> pie.

Share this post


Link to post
Share on other sites
colinisinhere    100
There is no framerate drop, the framerate is extremly high. It is just that the movement of the mouse is laggy.

What you said makes sense.

I call SD_WarpMouse() every frame, and I also check for mouse events every frame. But I check for events first. Here is a simplified version of my code:


// Device.cpp //
bool Device::run() {
SDL_Event event;

while(SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_MOUSEMOTION:
m_vMousePos.x = event.motion.x;
m_vMousePos.y = event.motion.y;
break;
default:
break;
}
}

return active;
}

// Camera.pp //
void Camera::setViewByMouse(dimension2d<unsigned short> screenSize, vector2di vMousePos) {
int middleX = screenSize.width >> 1;
int middleY = screenSize.height >> 1;
float angleY = 0.0f;
float angleZ = 0.0f;
static float currentRotX = 0.0f;

if((vMousePos.x == middleX) && (vMousePos.y == middleY))
return;

angleY = (float)((middleX - vMousePos.x))/1000.0f;
angleZ = (float)((middleY - vMousePos.y))/1000.0f;

currentRotX -= angleZ;

if(currentRotX > 1.45f) {
currentRotX = 1.45f;
}
else if(currentRotX < -1.45f) {
currentRotX = -1.45f;
}
else {
vector3df vAxis = (m_vTarget - m_vPos).crossProduct(m_vUp);
vAxis.normalize();

rotateView(angleZ, vAxis.x, vAxis.y, vAxis.z);
rotateView(angleY, 0, 1, 0);
}

SDL_WarpMouse(middleX, middleY);
}

// Main.cpp //
// MAIN LOOP //
while(device->run()) {
camera->setViewByMouse(renderer->getScreenSize(), device->getMousePos());

renderer->beginScene();
camera->render(renderer);
((OpenGLRenderer*)renderer)->renderTestCube(test.id);
renderer->endScene();
}




It might be hard to understand what is going on with just that small snippet.. But you will see that Device.run() runs every frame, and so does setViewByMouse().

Any ideas on how to make this faster?

Share this post


Link to post
Share on other sites
Mushu    1396
Well, the mouse shouldn't be moving at all, jumping is how I would describe what I would expect the output to be. Is it the mouse cursor which is laggy or the motion of the camera itself?

If its just the cursor, I remember reading about a SDL function to make the cursor invisible (which may or may not be a viable solution).

If the camera is being laggy/jumping, I'd leap to some kind of rounding error (I can't seem to find any in your code, so I'm doubting that that would be the actual cause :/)

To toggle the visibility of the cursor, you can pass SDL_ENABLE/SDL_DISABLE to SDL_ShowCursor(int);

Share this post


Link to post
Share on other sites
BleedingBlue    102
Since the mouse movement on most systems is velocity based, I would assume thats whats causing your lag if you move the mouse really slowly, it should appear smooth, but if you move it quickly then it will move further away from the point you warp it to, then when you warp it back it will appear to jump to the new position, this will give it an appearance of lag.

Share this post


Link to post
Share on other sites
Zanthos    300
This line:

camera->setViewByMouse(renderer->getScreenSize(), device->getMousePos());

should really go in the SDL_MOUSEMOTION event handler, as it's being called when it doesn't need to be.

The situation is how Mushu described, with the self-perpetuating event cycle of doom. You could fix this by scrapping the event loop altogether, and use this method:

1. Use SDL_GetRelativeMouseState(int* x,int* y) to retrieve your x and y mouse cursor deltas each frame.
2. Call SDL_WarpMouse when the x and y deltas != 0. Then straight after call SDL_GetRelativeMouseState(...) to cancel out any affect WarpMouse might have on the relative mouse positions(I'm not sure if it does or not, you could experiment or just call GRMS just to be on the safe side).

This will stop the huge amount of unnecessary event processing, and hopefully fix your problem :)

Share this post


Link to post
Share on other sites
colinisinhere    100
Zenthos:

I changed some stuff...

Everything is in the one function. And I completely removed the mouse event in Device::run()


void Camera::setViewByMouse(dimension2d<unsigned short> screenSize) {
int middleX = screenSize.width >> 1;
int middleY = screenSize.height >> 1;
float angleY = 0.0f;
float angleZ = 0.0f;
static float currentRotX = 0.0f;
int x, y;

SDL_GetRelativeMouseState(&x, &y);

if((x == middleX) && (y == middleY))
return;

angleY = (float)((middleX - x))/1000.0f;
angleZ = (float)((middleY - y))/1000.0f;

currentRotX -= angleZ;

if(currentRotX > 1.45f) {
currentRotX = 1.45f;
}
else if(currentRotX < -1.45f) {
currentRotX = -1.45f;
}
else {
vector3df vAxis = (m_vTarget - m_vPos).crossProduct(m_vUp);
vAxis.normalize();

rotateView(angleZ, vAxis.x, vAxis.y, vAxis.z);
rotateView(angleY, 0, 1, 0);
}

SDL_WarpMouse(middleX, middleY);
}




But now it doesn't work at all. The mouse returns at 0,0 on "SDL_GetRelativeMouseState(&x, &y);"

...

Share this post


Link to post
Share on other sites
Drew_Benton    1861
That code looks very familiar to me [wink] Common camera code I mean. Anyways, the problem I think is that when you use WarpMouse, it generates those mouse motion events, which end up countering your movements and cause lots of side effects, on of which is lag.

I found a way a while back that should fix that, so here's the revelant code segment. If you want to see the entire input library, here it is.


// Warp the mouse
SDL_WarpMouse( X, Y );

// Pump all events
SDL_PumpEvents();

// Temporary event variable
SDL_Event msg;

// We want to preserve the events
std::vector<SDL_Event> eventList;

// Eat away the mouse motions
while( SDL_PollEvent( &msg ) )
{
// If it's not a mouse motion, we want it!
if( msg.type != SDL_MOUSEMOTION )
{
// Save it
eventList.push_back( msg );
}
}

// Now go back and restore the event queue
for( int x = 0; x < eventList.size(); x++ )
{
SDL_PushEvent( &eventList.at(x) );
}




So simply add that stuff after you replace that SDL_WarpMouse and see if that does anything for the problem. Oh and if you need to see the function in the camera code that uses it, I can post that as well, just gotta find it first.

Share this post


Link to post
Share on other sites
rip-off    10979
@Drew_Benton

there is a function

void SDL_SetEventFilter(SDL_EventFilter filter);

that takes a pointer to a "int" function that takes
an SDL_Event*

if you make your function return 1 said event will be added
otherwise it will be dropped

you could use that to drop all mouse motion events...

Share this post


Link to post
Share on other sites
Drew_Benton    1861
While that solution could probabally work rip-off, it would involve doing a lot more things rather than the simple thing I have done. When testing, the maximum number of events I could generate between that block of code was 1 event. So in essence, I was only pushing one event. I have it setup to handle multiple evemts of it happens, but as for my testing went, its a quick easy solution. Thanks though for the suggeston.

In reality, that code was added to ensure that not a single event would be discared. You could easily just have a while( SDL_PollEvent( &msg ) ); and not have anything major to worry about in simple cases, ones that do not use threads.

Share this post


Link to post
Share on other sites
choffstein    1090
I just worked on something extremely similar. Here is how I solved it:


while(SDL_PollEvent(&e))
{
switch(e.type)
{
case SDL_KEYDOWN: {
keyMap[e.key.keysym.sym] = true;
wasUsed[e.key.keysym.sym] = false;
} break;

case SDL_KEYUP: {
keyMap[e.key.keysym.sym] = false;
wasUsed[e.key.keysym.sym] = false;
} break;

case SDL_MOUSEMOTION:
{
mouseXRel = e.motion.xrel;
mouseYRel = e.motion.yrel;
} break;
}
}

//warp us to the center of the screen again
//but we don't want to register it as a mouse
//movement, so we kill it.
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
SDL_WarpMouse(400,300);
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);



Simple as that. Wasn't laggy or jumpy anymore.

Share this post


Link to post
Share on other sites
Drew_Benton    1861
Quote:
Original post by visage
I just worked on something extremely similar. Here is how I solved it:

*** Source Snippet Removed ***

Simple as that. Wasn't laggy or jumpy anymore.


Great idea!

But your method has brought something to my attention that I've missed. Technically it is possible to have a valid mouse motion during the time of warping, so in my code it'd be better if I expanded it to consider that, so it doesn't just throw away ALL mouse motions, just the first. Time to do some updating for my own personal benefit.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this