diff --git a/client/include/interface/renderer.h b/client/include/interface/renderer.h index 3e2bd19c..a0a5e88c 100644 --- a/client/include/interface/renderer.h +++ b/client/include/interface/renderer.h @@ -66,6 +66,10 @@ typedef enum LG_RendererRotate } LG_RendererRotate; +// kept out of the enum so gcc doesn't warn when it's missing from a switch +// statement. +#define LG_ROTATE_MAX (LG_ROTATE_270+1) + typedef struct LG_RendererFormat { FrameType type; // frame type @@ -74,7 +78,7 @@ typedef struct LG_RendererFormat unsigned int stride; // scanline width (zero if compresed) unsigned int pitch; // scanline bytes (or compressed size) unsigned int bpp; // bits per pixel (zero if compressed) - LG_RendererRotate rotate; // output rotation + LG_RendererRotate rotate; // guest rotation } LG_RendererFormat; @@ -107,13 +111,14 @@ typedef bool (* LG_RendererInitialize )(void * opaque, Uint32 * sdlFla typedef void (* LG_RendererDeInitialize )(void * opaque); typedef bool (* LG_RendererSupports )(void * opaque, LG_RendererSupport support); typedef void (* LG_RendererOnRestart )(void * opaque); -typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height, const LG_RendererRect destRect); -typedef bool (* LG_RendererOnMouseShape )(void * opaque, const LG_RendererCursor cursor, const int width, const int height, const LG_RendererRotate rotate, const int pitch, const uint8_t * data); +typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height, const LG_RendererRect destRect, LG_RendererRotate rotate); +typedef bool (* LG_RendererOnMouseShape )(void * opaque, const LG_RendererCursor cursor, const int width, const int height, const int pitch, const uint8_t * data); typedef bool (* LG_RendererOnMouseEvent )(void * opaque, const bool visible , const int x, const int y); typedef bool (* LG_RendererOnFrameFormat)(void * opaque, const LG_RendererFormat format, bool useDMA); typedef bool (* LG_RendererOnFrame )(void * opaque, const FrameBuffer * frame, int dmaFD); typedef void (* LG_RendererOnAlert )(void * opaque, const LG_MsgAlert alert, const char * message, bool ** closeFlag); -typedef bool (* LG_RendererRender )(void * opaque, SDL_Window *window); +typedef bool (* LG_RendererRenderStartup)(void * opaque, SDL_Window *window); +typedef bool (* LG_RendererRender )(void * opaque, SDL_Window *window, LG_RendererRotate rotate); typedef void (* LG_RendererUpdateFPS )(void * opaque, const float avgUPS, const float avgFPS); typedef struct LG_Renderer @@ -132,7 +137,7 @@ typedef struct LG_Renderer LG_RendererOnFrameFormat on_frame_format; LG_RendererOnFrame on_frame; LG_RendererOnAlert on_alert; - LG_RendererRender render_startup; + LG_RendererRenderStartup render_startup; LG_RendererRender render; LG_RendererUpdateFPS update_fps; } diff --git a/client/renderers/EGL/cursor.c b/client/renderers/EGL/cursor.c index d7dc5571..a4b53d89 100644 --- a/client/renderers/EGL/cursor.c +++ b/client/renderers/EGL/cursor.c @@ -57,7 +57,7 @@ struct EGL_Cursor // cursor state bool visible; float x, y, w, h; - int rotate; + LG_RendererRotate rotate; int cbMode; struct CursorTex norm; @@ -170,8 +170,7 @@ void egl_cursor_free(EGL_Cursor ** cursor) } bool egl_cursor_set_shape(EGL_Cursor * cursor, const LG_RendererCursor type, - const int width, const int height, const LG_RendererRotate rotate, - const int stride, const uint8_t * data) + const int width, const int height, const int stride, const uint8_t * data) { LG_LOCK(cursor->lock); @@ -179,7 +178,6 @@ bool egl_cursor_set_shape(EGL_Cursor * cursor, const LG_RendererCursor type, cursor->width = width; cursor->height = (type == LG_CURSOR_MONOCHROME ? height / 2 : height); cursor->stride = stride; - cursor->rotate = rotate; const size_t size = height * stride; if (size > cursor->dataSize) @@ -217,7 +215,7 @@ void egl_cursor_set_state(EGL_Cursor * cursor, const bool visible, const float x cursor->y = y; } -void egl_cursor_render(EGL_Cursor * cursor) +void egl_cursor_render(EGL_Cursor * cursor, LG_RendererRotate rotate) { if (!cursor->visible) return; @@ -270,6 +268,8 @@ void egl_cursor_render(EGL_Cursor * cursor) LG_UNLOCK(cursor->lock); } + cursor->rotate = rotate; + glEnable(GL_BLEND); switch(cursor->type) { diff --git a/client/renderers/EGL/cursor.h b/client/renderers/EGL/cursor.h index 4169a588..bd9002fb 100644 --- a/client/renderers/EGL/cursor.h +++ b/client/renderers/EGL/cursor.h @@ -33,10 +33,12 @@ bool egl_cursor_set_shape( const LG_RendererCursor type, const int width, const int height, - const LG_RendererRotate rotate, const int stride, const uint8_t * data); -void egl_cursor_set_size (EGL_Cursor * cursor, const float x, const float y); -void egl_cursor_set_state(EGL_Cursor * cursor, const bool visible, const float x, const float y); -void egl_cursor_render (EGL_Cursor * cursor); +void egl_cursor_set_size(EGL_Cursor * cursor, const float x, const float y); + +void egl_cursor_set_state(EGL_Cursor * cursor, const bool visible, + const float x, const float y); + +void egl_cursor_render(EGL_Cursor * cursor, LG_RendererRotate rotate); diff --git a/client/renderers/EGL/desktop.c b/client/renderers/EGL/desktop.c index 01442424..766306e1 100644 --- a/client/renderers/EGL/desktop.c +++ b/client/renderers/EGL/desktop.c @@ -204,7 +204,6 @@ bool egl_desktop_setup(EGL_Desktop * desktop, const LG_RendererFormat format, bo desktop->width = format.width; desktop->height = format.height; - desktop->rotate = format.rotate; if (!egl_texture_setup( desktop->texture, @@ -246,7 +245,9 @@ bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame, int dm return true; } -bool egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, const float scaleX, const float scaleY, const bool nearest) +bool egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, + const float scaleX, const float scaleY, const bool nearest, + LG_RendererRotate rotate) { if (!desktop->shader) return false; @@ -254,7 +255,7 @@ bool egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, con const struct DesktopShader * shader = desktop->shader; egl_shader_use(shader->shader); glUniform4f(shader->uDesktopPos , x, y, scaleX, scaleY); - glUniform1i(shader->uRotate , desktop->rotate); + glUniform1i(shader->uRotate , rotate); glUniform1i(shader->uNearest , nearest ? 1 : 0); glUniform2f(shader->uDesktopSize, desktop->width, desktop->height); diff --git a/client/renderers/EGL/desktop.h b/client/renderers/EGL/desktop.h index fa9b9f5d..b3fac51a 100644 --- a/client/renderers/EGL/desktop.h +++ b/client/renderers/EGL/desktop.h @@ -31,4 +31,6 @@ void egl_desktop_free(EGL_Desktop ** desktop); bool egl_desktop_setup (EGL_Desktop * desktop, const LG_RendererFormat format, bool useDMA); bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame, int dmaFd); -bool egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, const float scaleX, const float scaleY, const bool nearest); +bool egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, + const float scaleX, const float scaleY, const bool nearest, + LG_RendererRotate rotate); diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index d03dd08d..42c0b122 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -80,8 +80,9 @@ struct Inst bool useCloseFlag; bool closeFlag; - int width, height; - LG_RendererRect destRect; + int width, height; + LG_RendererRect destRect; + LG_RendererRotate rotate; //client side rotation float translateX , translateY; float scaleX , scaleY; @@ -263,12 +264,83 @@ void egl_on_restart(void * opaque) this->start = false; } -void egl_on_resize(void * opaque, const int width, const int height, const LG_RendererRect destRect) +static void egl_calc_mouse_size(struct Inst * this) +{ + int w, h; + switch(this->format.rotate) + { + case LG_ROTATE_0: + case LG_ROTATE_180: + this->mouseScaleX = 2.0f / this->format.width; + this->mouseScaleY = 2.0f / this->format.height; + w = this->format.width; + h = this->format.height; + break; + + case LG_ROTATE_90: + case LG_ROTATE_270: + this->mouseScaleX = 2.0f / this->format.height; + this->mouseScaleY = 2.0f / this->format.width; + w = this->format.height; + h = this->format.width; + break; + } + + switch((this->format.rotate + this->rotate) % LG_ROTATE_MAX) + { + case LG_ROTATE_0: + case LG_ROTATE_180: + egl_cursor_set_size(this->cursor, + (this->mouseWidth * (1.0f / w)) * this->scaleX, + (this->mouseHeight * (1.0f / h)) * this->scaleY + ); + break; + + case LG_ROTATE_90: + case LG_ROTATE_270: + egl_cursor_set_size(this->cursor, + (this->mouseWidth * (1.0f / w)) * this->scaleY, + (this->mouseHeight * (1.0f / h)) * this->scaleX + ); + break; + } +} + +static void egl_calc_mouse_state(struct Inst * this) +{ + switch((this->format.rotate + this->rotate) % LG_ROTATE_MAX) + { + case LG_ROTATE_0: + case LG_ROTATE_180: + egl_cursor_set_state( + this->cursor, + this->cursorVisible, + (((float)this->cursorX * this->mouseScaleX) - 1.0f) * this->scaleX, + (((float)this->cursorY * this->mouseScaleY) - 1.0f) * this->scaleY + ); + break; + + case LG_ROTATE_90: + case LG_ROTATE_270: + egl_cursor_set_state( + this->cursor, + this->cursorVisible, + (((float)this->cursorX * this->mouseScaleX) - 1.0f) * this->scaleY, + (((float)this->cursorY * this->mouseScaleY) - 1.0f) * this->scaleX + ); + break; + } +} + +void egl_on_resize(void * opaque, const int width, const int height, + const LG_RendererRect destRect, LG_RendererRotate rotate) { struct Inst * this = (struct Inst *)opaque; this->width = width; this->height = height; + this->rotate = rotate; + memcpy(&this->destRect, &destRect, sizeof(LG_RendererRect)); glViewport(0, 0, width, height); @@ -281,31 +353,22 @@ void egl_on_resize(void * opaque, const int width, const int height, const LG_Re this->scaleY = (float)destRect.h / (float)height; } - this->mouseScaleX = 2.0f / this->format.width ; - this->mouseScaleY = 2.0f / this->format.height; - egl_cursor_set_size(this->cursor, - (this->mouseWidth * (1.0f / this->format.width )) * this->scaleX, - (this->mouseHeight * (1.0f / this->format.height)) * this->scaleY - ); + egl_calc_mouse_size(this); this->splashRatio = (float)width / (float)height; this->screenScaleX = 1.0f / width; this->screenScaleY = 1.0f / height; - egl_cursor_set_state( - this->cursor, - this->cursorVisible, - (((float)this->cursorX * this->mouseScaleX) - 1.0f) * this->scaleX, - (((float)this->cursorY * this->mouseScaleY) - 1.0f) * this->scaleY - ); + egl_calc_mouse_state(this); } bool egl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, - const int width, const int height, const LG_RendererRotate rotate, + const int width, const int height, const int pitch, const uint8_t * data) { struct Inst * this = (struct Inst *)opaque; - if (!egl_cursor_set_shape(this->cursor, cursor, width, height, rotate, pitch, data)) + + if (!egl_cursor_set_shape(this->cursor, cursor, width, height, pitch, data)) { DEBUG_ERROR("Failed to update the cursor shape"); return false; @@ -313,10 +376,7 @@ bool egl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, this->mouseWidth = width; this->mouseHeight = height; - egl_cursor_set_size(this->cursor, - (this->mouseWidth * (1.0f / this->format.width )) * this->scaleX, - (this->mouseHeight * (1.0f / this->format.height)) * this->scaleY - ); + egl_calc_mouse_size(this); return true; } @@ -327,14 +387,7 @@ bool egl_on_mouse_event(void * opaque, const bool visible, const int x, const in this->cursorVisible = visible; this->cursorX = x; this->cursorY = y; - - egl_cursor_set_state( - this->cursor, - this->cursorVisible, - (((float)this->cursorX * this->mouseScaleX) - 1.0f) * this->scaleX, - (((float)this->cursorY * this->mouseScaleY) - 1.0f) * this->scaleY - ); - + egl_calc_mouse_state(this); return true; } @@ -621,7 +674,7 @@ bool egl_render_startup(void * opaque, SDL_Window * window) return true; } -bool egl_render(void * opaque, SDL_Window * window) +bool egl_render(void * opaque, SDL_Window * window, LG_RendererRotate rotate) { struct Inst * this = (struct Inst *)opaque; @@ -631,7 +684,8 @@ bool egl_render(void * opaque, SDL_Window * window) if (this->start && egl_desktop_render(this->desktop, this->translateX, this->translateY, this->scaleX , this->scaleY , - this->useNearest)) + this->useNearest, + rotate)) { if (!this->waitFadeTime) { @@ -640,7 +694,9 @@ bool egl_render(void * opaque, SDL_Window * window) else this->waitDone = true; } - egl_cursor_render(this->cursor); + + egl_cursor_render(this->cursor, + (this->format.rotate + rotate) % LG_ROTATE_MAX); } if (!this->waitDone) diff --git a/client/renderers/OpenGL/opengl.c b/client/renderers/OpenGL/opengl.c index ac73a765..136aaca0 100644 --- a/client/renderers/OpenGL/opengl.c +++ b/client/renderers/OpenGL/opengl.c @@ -316,7 +316,8 @@ void opengl_on_restart(void * opaque) this->waiting = true; } -void opengl_on_resize(void * opaque, const int width, const int height, const LG_RendererRect destRect) +void opengl_on_resize(void * opaque, const int width, const int height, + const LG_RendererRect destRect, LG_RendererRotate rotate) { struct Inst * this = (struct Inst *)opaque; @@ -346,7 +347,8 @@ void opengl_on_resize(void * opaque, const int width, const int height, const LG } } -bool opengl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, const int width, const int height, const LG_RendererRotate rotate, const int pitch, const uint8_t * data) +bool opengl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, + const int width, const int height, const int pitch, const uint8_t * data) { struct Inst * this = (struct Inst *)opaque; if (!this) @@ -562,7 +564,7 @@ bool opengl_render_startup(void * opaque, SDL_Window * window) return true; } -bool opengl_render(void * opaque, SDL_Window * window) +bool opengl_render(void * opaque, SDL_Window * window, LG_RendererRotate rotate) { struct Inst * this = (struct Inst *)opaque; if (!this) diff --git a/client/src/main.c b/client/src/main.c index 909b4e91..2a79db24 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -173,74 +173,92 @@ static void alignToGuest(void) static void updatePositionInfo(void) { - if (g_state.haveSrcSize) + if (!g_state.haveSrcSize) + goto done; + + float srcW; + float srcH; + switch(params.winRotate) { - if (params.keepAspect) + case LG_ROTATE_0: + case LG_ROTATE_180: + srcW = g_state.srcSize.x; + srcH = g_state.srcSize.y; + break; + + case LG_ROTATE_90: + case LG_ROTATE_270: + srcW = g_state.srcSize.y; + srcH = g_state.srcSize.x; + break; + } + + if (params.keepAspect) + { + const float srcAspect = srcH / srcW; + const float wndAspect = (float)g_state.windowH / (float)g_state.windowW; + bool force = true; + + if (params.dontUpscale && + srcW <= g_state.windowW && + srcH <= g_state.windowH) { - const float srcAspect = (float)g_state.srcSize.y / (float)g_state.srcSize.x; - const float wndAspect = (float)g_state.windowH / (float)g_state.windowW; - bool force = true; - - if (params.dontUpscale && - g_state.srcSize.x <= g_state.windowW && - g_state.srcSize.y <= g_state.windowH) - { - force = false; - g_state.dstRect.w = g_state.srcSize.x; - g_state.dstRect.h = g_state.srcSize.y; - g_state.dstRect.x = g_state.windowCX - g_state.srcSize.x / 2; - g_state.dstRect.y = g_state.windowCY - g_state.srcSize.y / 2; - } - else - if ((int)(wndAspect * 1000) == (int)(srcAspect * 1000)) - { - force = false; - g_state.dstRect.w = g_state.windowW; - g_state.dstRect.h = g_state.windowH; - g_state.dstRect.x = 0; - g_state.dstRect.y = 0; - } - else - if (wndAspect < srcAspect) - { - g_state.dstRect.w = (float)g_state.windowH / srcAspect; - g_state.dstRect.h = g_state.windowH; - g_state.dstRect.x = (g_state.windowW >> 1) - (g_state.dstRect.w >> 1); - g_state.dstRect.y = 0; - } - else - { - g_state.dstRect.w = g_state.windowW; - g_state.dstRect.h = (float)g_state.windowW * srcAspect; - g_state.dstRect.x = 0; - g_state.dstRect.y = (g_state.windowH >> 1) - (g_state.dstRect.h >> 1); - } - - if (force && params.forceAspect) - { - g_state.resizeTimeout = microtime() + RESIZE_TIMEOUT; - g_state.resizeDone = false; - } + force = false; + g_state.dstRect.w = srcW; + g_state.dstRect.h = srcH; + g_state.dstRect.x = g_state.windowCX - srcW / 2; + g_state.dstRect.y = g_state.windowCY - srcH / 2; + } + else + if ((int)(wndAspect * 1000) == (int)(srcAspect * 1000)) + { + force = false; + g_state.dstRect.w = g_state.windowW; + g_state.dstRect.h = g_state.windowH; + g_state.dstRect.x = 0; + g_state.dstRect.y = 0; + } + else + if (wndAspect < srcAspect) + { + g_state.dstRect.w = (float)g_state.windowH / srcAspect; + g_state.dstRect.h = g_state.windowH; + g_state.dstRect.x = (g_state.windowW >> 1) - (g_state.dstRect.w >> 1); + g_state.dstRect.y = 0; } else { - g_state.dstRect.x = 0; - g_state.dstRect.y = 0; g_state.dstRect.w = g_state.windowW; - g_state.dstRect.h = g_state.windowH; + g_state.dstRect.h = (float)g_state.windowW * srcAspect; + g_state.dstRect.x = 0; + g_state.dstRect.y = (g_state.windowH >> 1) - (g_state.dstRect.h >> 1); } - g_state.dstRect.valid = true; - g_cursor.useScale = ( - g_state.srcSize.y != g_state.dstRect.h || - g_state.srcSize.x != g_state.dstRect.w || - g_cursor.guest.dpiScale != 100); - - g_cursor.scale.x = (float)g_state.srcSize.y / (float)g_state.dstRect.h; - g_cursor.scale.y = (float)g_state.srcSize.x / (float)g_state.dstRect.w; - g_cursor.dpiScale = g_cursor.guest.dpiScale / 100.0f; + if (force && params.forceAspect) + { + g_state.resizeTimeout = microtime() + RESIZE_TIMEOUT; + g_state.resizeDone = false; + } } + else + { + g_state.dstRect.x = 0; + g_state.dstRect.y = 0; + g_state.dstRect.w = g_state.windowW; + g_state.dstRect.h = g_state.windowH; + } + g_state.dstRect.valid = true; + g_cursor.useScale = ( + srcH != g_state.dstRect.h || + srcW != g_state.dstRect.w || + g_cursor.guest.dpiScale != 100); + + g_cursor.scale.x = (float)srcH / (float)g_state.dstRect.h; + g_cursor.scale.y = (float)srcW / (float)g_state.dstRect.w; + g_cursor.dpiScale = g_cursor.guest.dpiScale / 100.0f; + +done: atomic_fetch_add(&g_state.lgrResize, 1); } @@ -274,11 +292,12 @@ static int renderThread(void * unused) if (resize) { if (g_state.lgr) - g_state.lgr->on_resize(g_state.lgrData, g_state.windowW, g_state.windowH, g_state.dstRect); + g_state.lgr->on_resize(g_state.lgrData, g_state.windowW, g_state.windowH, + g_state.dstRect, params.winRotate); atomic_compare_exchange_weak(&g_state.lgrResize, &resize, 0); } - if (!g_state.lgr->render(g_state.lgrData, g_state.window)) + if (!g_state.lgr->render(g_state.lgrData, g_state.window, params.winRotate)) break; if (params.showFPS) @@ -430,7 +449,6 @@ static int cursorThread(void * unused) cursorType, cursor->width, cursor->height, - params.winRotate, cursor->pitch, data) ) @@ -568,6 +586,15 @@ static int frameThread(void * unused) lgrFormat.stride = frame->stride; lgrFormat.pitch = frame->pitch; + switch(frame->rotation) + { + case FRAME_ROT_0 : lgrFormat.rotate = LG_ROTATE_0 ; break; + case FRAME_ROT_90 : lgrFormat.rotate = LG_ROTATE_90 ; break; + case FRAME_ROT_180: lgrFormat.rotate = LG_ROTATE_180; break; + case FRAME_ROT_270: lgrFormat.rotate = LG_ROTATE_270; break; + } + g_state.rotate = lgrFormat.rotate; + bool error = false; switch(frame->type) { @@ -599,12 +626,11 @@ static int frameThread(void * unused) formatValid = true; formatVer = frame->formatVer; - DEBUG_INFO("Format: %s %ux%u %u %u", + DEBUG_INFO("Format: %s %ux%u stride:%u pitch:%u rotation:%d", FrameTypeStr[frame->type], frame->width, frame->height, - frame->stride, frame->pitch); - - lgrFormat.rotate = params.winRotate; + frame->stride, frame->pitch, + frame->rotation); if (!g_state.lgr->on_frame_format(g_state.lgrData, lgrFormat, useDMA)) { @@ -1104,12 +1130,101 @@ void app_handleKeyRelease(int sc) } } +static void rotatePoint(struct DoublePoint *point) +{ + double temp; + + switch((g_state.rotate + params.winRotate) % LG_ROTATE_MAX) + { + case LG_ROTATE_0: + break; + + case LG_ROTATE_90: + temp = point->x; + point->x = point->y; + point->y = -temp; + break; + + case LG_ROTATE_180: + point->x = -point->x; + point->y = -point->y; + break; + + case LG_ROTATE_270: + temp = point->x; + point->x = -point->y; + point->y = temp; + break; + } +} + static void guestCurToLocal(struct DoublePoint *local) { - local->x = g_state.dstRect.x + - (g_cursor.guest.x + g_cursor.guest.hx) / g_cursor.scale.x; - local->y = g_state.dstRect.y + - (g_cursor.guest.y + g_cursor.guest.hy) / g_cursor.scale.y; + const struct DoublePoint point = + { + .x = g_cursor.guest.x + g_cursor.guest.hx, + .y = g_cursor.guest.y + g_cursor.guest.hy + }; + + switch((g_state.rotate + params.winRotate) % LG_ROTATE_MAX) + { + case LG_ROTATE_0: + local->x = (point.x / g_cursor.scale.x) + g_state.dstRect.x; + local->y = (point.y / g_cursor.scale.y) + g_state.dstRect.y;; + break; + + case LG_ROTATE_90: + local->x = (g_state.dstRect.x + g_state.dstRect.w) - + point.y / g_cursor.scale.y; + local->y = (point.x / g_cursor.scale.x) + g_state.dstRect.y; + break; + + case LG_ROTATE_180: + local->x = (g_state.dstRect.x + g_state.dstRect.w) - + point.x / g_cursor.scale.x; + local->y = (g_state.dstRect.y + g_state.dstRect.h) - + point.y / g_cursor.scale.y; + break; + + case LG_ROTATE_270: + local->x = (point.y / g_cursor.scale.y) + g_state.dstRect.x; + local->y = (g_state.dstRect.y + g_state.dstRect.h) - + point.x / g_cursor.scale.x; + break; + } +} + +inline static void localCurToGuest(struct DoublePoint *guest) +{ + const struct DoublePoint point = + g_cursor.pos; + + switch((g_state.rotate - params.winRotate) % LG_ROTATE_MAX) + { + case LG_ROTATE_0: + guest->x = (point.x - g_state.dstRect.x) * g_cursor.scale.x; + guest->y = (point.y - g_state.dstRect.y) * g_cursor.scale.y; + break; + + case LG_ROTATE_90: + guest->x = (point.y - g_state.dstRect.y) * g_cursor.scale.y; + guest->y = (g_state.dstRect.w - point.x + g_state.dstRect.x) + * g_cursor.scale.x; + break; + + case LG_ROTATE_180: + guest->x = (g_state.dstRect.w - point.x + g_state.dstRect.x) + * g_cursor.scale.x; + guest->y = (g_state.dstRect.h - point.y + g_state.dstRect.y) + * g_cursor.scale.y; + break; + + case LG_ROTATE_270: + guest->x = (g_state.dstRect.h - point.y + g_state.dstRect.y) + * g_cursor.scale.y; + guest->y = (point.x - g_state.dstRect.x) * g_cursor.scale.x; + break; + } } void app_handleMouseNormal(double ex, double ey) @@ -1154,11 +1269,8 @@ void app_handleMouseNormal(double ex, double ey) { g_cursor.realign = false; - struct DoublePoint guest = - { - .x = (g_cursor.pos.x - g_state.dstRect.x) * g_cursor.scale.x, - .y = (g_cursor.pos.y - g_state.dstRect.y) * g_cursor.scale.y - }; + struct DoublePoint guest; + localCurToGuest(&guest); /* add the difference to the offset */ ex += guest.x - (g_cursor.guest.x + g_cursor.guest.hx); @@ -1174,41 +1286,48 @@ void app_handleMouseNormal(double ex, double ey) (fabs(ex) > 100.0 / g_cursor.scale.x || fabs(ey) > 100.0 / g_cursor.scale.y)) testExit = false; - /* translate the guests position to our coordinate space */ - struct DoublePoint local; - guestCurToLocal(&local); - /* if any buttons are held we should not allow exit to happen */ if (g_cursor.buttons) testExit = false; - /* check if the move would push the cursor outside the guest's viewport */ - if (testExit && ( - local.x + ex < g_state.dstRect.x || - local.y + ey < g_state.dstRect.y || - local.x + ex >= g_state.dstRect.x + g_state.dstRect.w || - local.y + ey >= g_state.dstRect.y + g_state.dstRect.h)) + if (testExit) { - local.x += ex; - local.y += ey; - const int tx = (local.x <= 0.0) ? floor(local.x) : ceil(local.x); - const int ty = (local.y <= 0.0) ? floor(local.y) : ceil(local.y); + /* translate the move to the guests orientation */ + struct DoublePoint move = {.x = ex, .y = ey}; + rotatePoint(&move); - if (isValidCursorLocation( - g_state.windowPos.x + g_state.border.x + tx, - g_state.windowPos.y + g_state.border.y + ty)) + /* translate the guests position to our coordinate space */ + struct DoublePoint local; + guestCurToLocal(&local); + + /* check if the move would push the cursor outside the guest's viewport */ + if ( + local.x + move.x < g_state.dstRect.x || + local.y + move.y < g_state.dstRect.y || + local.x + move.x >= g_state.dstRect.x + g_state.dstRect.w || + local.y + move.y >= g_state.dstRect.y + g_state.dstRect.h) { - setCursorInView(false); + local.x += move.x; + local.y += move.y; + const int tx = (local.x <= 0.0) ? floor(local.x) : ceil(local.x); + const int ty = (local.y <= 0.0) ? floor(local.y) : ceil(local.y); - /* preempt the window leave flag if the warp will leave our window */ - if (tx < 0 || ty < 0 || tx > g_state.windowW || ty > g_state.windowH) - g_cursor.inWindow = false; + if (isValidCursorLocation( + g_state.windowPos.x + g_state.border.x + tx, + g_state.windowPos.y + g_state.border.y + ty)) + { + setCursorInView(false); - /* ungrab the pointer and move the local cursor to the exit point */ - g_state.ds->ungrabPointer(); + /* preempt the window leave flag if the warp will leave our window */ + if (tx < 0 || ty < 0 || tx > g_state.windowW || ty > g_state.windowH) + g_cursor.inWindow = false; - warpPointer(tx, ty, true); - return; + /* ungrab the pointer and move the local cursor to the exit point */ + g_state.ds->ungrabPointer(); + + warpPointer(tx, ty, true); + return; + } } } diff --git a/client/src/main.h b/client/src/main.h index 736eeeca..6f52b912 100644 --- a/client/src/main.h +++ b/client/src/main.h @@ -54,6 +54,7 @@ struct AppState SDL_Point windowPos; int windowW, windowH; int windowCX, windowCY; + LG_RendererRotate rotate; bool focused; SDL_Rect border; SDL_Point srcSize;