Changeset - r24440:3295012a081c
[Not reviewed]
master
0 3 0
Patric Stout - 3 years ago 2020-12-06 19:18:19
truebrain@openttd.org
Add: [Emscripten] use "relative mouse mode" with SDL2

This mode doesn't wrap the mouse constantly, but requests SDL
to lock the mouse pointer. This is needed, as with Emscripten
you are not allowed to change the mouse poisition (only to lock
it into place).
3 files changed with 59 insertions and 1 deletions:
0 comments (0 inline, 0 general)
src/gfx.cpp
Show inline comments
 
@@ -1785,6 +1785,30 @@ void SetAnimatedMouseCursor(const AnimCu
 
}
 

	
 
/**
 
 * Update cursor position on mouse movement for relative modes.
 
 * @param delta_x How much change in the X position.
 
 * @param delta_y How much change in the Y position.
 
 */
 
void CursorVars::UpdateCursorPositionRelative(int delta_x, int delta_y)
 
{
 
	if (this->fix_at) {
 
		this->delta.x = delta_x;
 
		this->delta.y = delta_y;
 
	} else {
 
		int last_position_x = this->pos.x;
 
		int last_position_y = this->pos.y;
 

	
 
		this->pos.x = Clamp(this->pos.x + delta_x, 0, _cur_resolution.width - 1);
 
		this->pos.y = Clamp(this->pos.y + delta_y, 0, _cur_resolution.height - 1);
 

	
 
		this->delta.x = last_position_x - this->pos.x;
 
		this->delta.y = last_position_y - this->pos.y;
 

	
 
		this->dirty = true;
 
	}
 
}
 

	
 
/**
 
 * Update cursor position on mouse movement.
 
 * @param x New X position.
 
 * @param y New Y position.
src/gfx_type.h
Show inline comments
 
@@ -143,6 +143,7 @@ struct CursorVars {
 
	/* Drag data */
 
	bool vehchain;                ///< vehicle chain is dragged
 

	
 
	void UpdateCursorPositionRelative(int delta_x, int delta_y);
 
	bool UpdateCursorPosition(int x, int y, bool queued_warp);
 

	
 
private:
src/video/sdl2_v.cpp
Show inline comments
 
@@ -51,6 +51,11 @@ static volatile bool _draw_continue;
 
static Palette _local_palette;
 
static SDL_Palette *_sdl_palette;
 

	
 
#ifdef __EMSCRIPTEN__
 
/** Whether we just had a window-enter event. */
 
static bool _cursor_new_in_window = false;
 
#endif
 

	
 
#define MAX_DIRTY_RECTS 100
 
static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS];
 
static int _num_dirty_rects;
 
@@ -350,6 +355,9 @@ bool VideoDriver_SDL::CreateMainSurface(
 
bool VideoDriver_SDL::ClaimMousePointer()
 
{
 
	SDL_ShowCursor(0);
 
#ifdef __EMSCRIPTEN__
 
	SDL_SetRelativeMouseMode(SDL_TRUE);
 
#endif
 
	return true;
 
}
 

	
 
@@ -509,9 +517,27 @@ int VideoDriver_SDL::PollEvent()
 

	
 
	switch (ev.type) {
 
		case SDL_MOUSEMOTION:
 
#ifdef __EMSCRIPTEN__
 
			if (_cursor_new_in_window) {
 
				/* The cursor just moved into the window; this means we don't
 
				* know the absolutely position yet to move relative from.
 
				* Before this time, SDL didn't know it either, and this is
 
				* why we postpone it till now. Update the absolute position
 
				* for this once, and work relative after. */
 
				_cursor.pos.x = ev.motion.x;
 
				_cursor.pos.y = ev.motion.y;
 
				_cursor.dirty = true;
 

	
 
				_cursor_new_in_window = false;
 
				SDL_SetRelativeMouseMode(SDL_TRUE);
 
			} else {
 
				_cursor.UpdateCursorPositionRelative(ev.motion.xrel, ev.motion.yrel);
 
			}
 
#else
 
			if (_cursor.UpdateCursorPosition(ev.motion.x, ev.motion.y, true)) {
 
				SDL_WarpMouseInWindow(_sdl_window, _cursor.pos.x, _cursor.pos.y);
 
			}
 
#endif
 
			HandleMouseEvents();
 
			break;
 

	
 
@@ -615,6 +641,12 @@ int VideoDriver_SDL::PollEvent()
 
			} else if (ev.window.event == SDL_WINDOWEVENT_ENTER) {
 
				// mouse entered the window, enable cursor
 
				_cursor.in_window = true;
 
#ifdef __EMSCRIPTEN__
 
				/* Disable relative mouse mode for the first mouse motion,
 
				 * so we can pick up the absolutely position again. */
 
				_cursor_new_in_window = true;
 
				SDL_SetRelativeMouseMode(SDL_FALSE);
 
#endif
 
			} else if (ev.window.event == SDL_WINDOWEVENT_LEAVE) {
 
				// mouse left the window, undraw cursor
 
				UndrawMouseCursor();
 
@@ -631,7 +663,8 @@ const char *VideoDriver_SDL::Start(const
 
	/* Explicitly disable hardware acceleration. Enabling this causes
 
	 * UpdateWindowSurface() to update the window's texture instead of
 
	 * its surface. */
 
	SDL_SetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION , "0");
 
	SDL_SetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION, "0");
 
	SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1");
 

	
 
	/* Just on the offchance the audio subsystem started before the video system,
 
	 * check whether any part of SDL has been initialised before getting here.
0 comments (0 inline, 0 general)