mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-25 14:57:20 +00:00
[client] all: properly support guest rotation
If the guest has it's output rotated (ie, landscape) we must rotate and translate the pointer draw location, as well as all the translations of cursor coordinate spaces based on the rotation, along with any local rotations that may also be applied.
This commit is contained in:
parent
733bbf5153
commit
8a1578230f
@ -66,6 +66,10 @@ typedef enum LG_RendererRotate
|
|||||||
}
|
}
|
||||||
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
|
typedef struct LG_RendererFormat
|
||||||
{
|
{
|
||||||
FrameType type; // frame type
|
FrameType type; // frame type
|
||||||
@ -74,7 +78,7 @@ typedef struct LG_RendererFormat
|
|||||||
unsigned int stride; // scanline width (zero if compresed)
|
unsigned int stride; // scanline width (zero if compresed)
|
||||||
unsigned int pitch; // scanline bytes (or compressed size)
|
unsigned int pitch; // scanline bytes (or compressed size)
|
||||||
unsigned int bpp; // bits per pixel (zero if compressed)
|
unsigned int bpp; // bits per pixel (zero if compressed)
|
||||||
LG_RendererRotate rotate; // output rotation
|
LG_RendererRotate rotate; // guest rotation
|
||||||
}
|
}
|
||||||
LG_RendererFormat;
|
LG_RendererFormat;
|
||||||
|
|
||||||
@ -107,13 +111,14 @@ typedef bool (* LG_RendererInitialize )(void * opaque, Uint32 * sdlFla
|
|||||||
typedef void (* LG_RendererDeInitialize )(void * opaque);
|
typedef void (* LG_RendererDeInitialize )(void * opaque);
|
||||||
typedef bool (* LG_RendererSupports )(void * opaque, LG_RendererSupport support);
|
typedef bool (* LG_RendererSupports )(void * opaque, LG_RendererSupport support);
|
||||||
typedef void (* LG_RendererOnRestart )(void * opaque);
|
typedef void (* LG_RendererOnRestart )(void * opaque);
|
||||||
typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height, const LG_RendererRect destRect);
|
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 LG_RendererRotate rotate, const int pitch, const uint8_t * data);
|
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_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_RendererOnFrameFormat)(void * opaque, const LG_RendererFormat format, bool useDMA);
|
||||||
typedef bool (* LG_RendererOnFrame )(void * opaque, const FrameBuffer * frame, int dmaFD);
|
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 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 void (* LG_RendererUpdateFPS )(void * opaque, const float avgUPS, const float avgFPS);
|
||||||
|
|
||||||
typedef struct LG_Renderer
|
typedef struct LG_Renderer
|
||||||
@ -132,7 +137,7 @@ typedef struct LG_Renderer
|
|||||||
LG_RendererOnFrameFormat on_frame_format;
|
LG_RendererOnFrameFormat on_frame_format;
|
||||||
LG_RendererOnFrame on_frame;
|
LG_RendererOnFrame on_frame;
|
||||||
LG_RendererOnAlert on_alert;
|
LG_RendererOnAlert on_alert;
|
||||||
LG_RendererRender render_startup;
|
LG_RendererRenderStartup render_startup;
|
||||||
LG_RendererRender render;
|
LG_RendererRender render;
|
||||||
LG_RendererUpdateFPS update_fps;
|
LG_RendererUpdateFPS update_fps;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ struct EGL_Cursor
|
|||||||
// cursor state
|
// cursor state
|
||||||
bool visible;
|
bool visible;
|
||||||
float x, y, w, h;
|
float x, y, w, h;
|
||||||
int rotate;
|
LG_RendererRotate rotate;
|
||||||
int cbMode;
|
int cbMode;
|
||||||
|
|
||||||
struct CursorTex norm;
|
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,
|
bool egl_cursor_set_shape(EGL_Cursor * cursor, const LG_RendererCursor type,
|
||||||
const int width, const int height, const LG_RendererRotate rotate,
|
const int width, const int height, const int stride, const uint8_t * data)
|
||||||
const int stride, const uint8_t * data)
|
|
||||||
{
|
{
|
||||||
LG_LOCK(cursor->lock);
|
LG_LOCK(cursor->lock);
|
||||||
|
|
||||||
@ -179,7 +178,6 @@ bool egl_cursor_set_shape(EGL_Cursor * cursor, const LG_RendererCursor type,
|
|||||||
cursor->width = width;
|
cursor->width = width;
|
||||||
cursor->height = (type == LG_CURSOR_MONOCHROME ? height / 2 : height);
|
cursor->height = (type == LG_CURSOR_MONOCHROME ? height / 2 : height);
|
||||||
cursor->stride = stride;
|
cursor->stride = stride;
|
||||||
cursor->rotate = rotate;
|
|
||||||
|
|
||||||
const size_t size = height * stride;
|
const size_t size = height * stride;
|
||||||
if (size > cursor->dataSize)
|
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;
|
cursor->y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void egl_cursor_render(EGL_Cursor * cursor)
|
void egl_cursor_render(EGL_Cursor * cursor, LG_RendererRotate rotate)
|
||||||
{
|
{
|
||||||
if (!cursor->visible)
|
if (!cursor->visible)
|
||||||
return;
|
return;
|
||||||
@ -270,6 +268,8 @@ void egl_cursor_render(EGL_Cursor * cursor)
|
|||||||
LG_UNLOCK(cursor->lock);
|
LG_UNLOCK(cursor->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cursor->rotate = rotate;
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
switch(cursor->type)
|
switch(cursor->type)
|
||||||
{
|
{
|
||||||
|
@ -33,10 +33,12 @@ bool egl_cursor_set_shape(
|
|||||||
const LG_RendererCursor type,
|
const LG_RendererCursor type,
|
||||||
const int width,
|
const int width,
|
||||||
const int height,
|
const int height,
|
||||||
const LG_RendererRotate rotate,
|
|
||||||
const int stride,
|
const int stride,
|
||||||
const uint8_t * data);
|
const uint8_t * data);
|
||||||
|
|
||||||
void egl_cursor_set_size (EGL_Cursor * cursor, const float x, const float y);
|
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_state(EGL_Cursor * cursor, const bool visible,
|
||||||
|
const float x, const float y);
|
||||||
|
|
||||||
|
void egl_cursor_render(EGL_Cursor * cursor, LG_RendererRotate rotate);
|
||||||
|
@ -204,7 +204,6 @@ bool egl_desktop_setup(EGL_Desktop * desktop, const LG_RendererFormat format, bo
|
|||||||
|
|
||||||
desktop->width = format.width;
|
desktop->width = format.width;
|
||||||
desktop->height = format.height;
|
desktop->height = format.height;
|
||||||
desktop->rotate = format.rotate;
|
|
||||||
|
|
||||||
if (!egl_texture_setup(
|
if (!egl_texture_setup(
|
||||||
desktop->texture,
|
desktop->texture,
|
||||||
@ -246,7 +245,9 @@ bool egl_desktop_update(EGL_Desktop * desktop, const FrameBuffer * frame, int dm
|
|||||||
return true;
|
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)
|
if (!desktop->shader)
|
||||||
return false;
|
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;
|
const struct DesktopShader * shader = desktop->shader;
|
||||||
egl_shader_use(shader->shader);
|
egl_shader_use(shader->shader);
|
||||||
glUniform4f(shader->uDesktopPos , x, y, scaleX, scaleY);
|
glUniform4f(shader->uDesktopPos , x, y, scaleX, scaleY);
|
||||||
glUniform1i(shader->uRotate , desktop->rotate);
|
glUniform1i(shader->uRotate , rotate);
|
||||||
glUniform1i(shader->uNearest , nearest ? 1 : 0);
|
glUniform1i(shader->uNearest , nearest ? 1 : 0);
|
||||||
glUniform2f(shader->uDesktopSize, desktop->width, desktop->height);
|
glUniform2f(shader->uDesktopSize, desktop->width, desktop->height);
|
||||||
|
|
||||||
|
@ -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_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_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);
|
||||||
|
@ -80,8 +80,9 @@ struct Inst
|
|||||||
bool useCloseFlag;
|
bool useCloseFlag;
|
||||||
bool closeFlag;
|
bool closeFlag;
|
||||||
|
|
||||||
int width, height;
|
int width, height;
|
||||||
LG_RendererRect destRect;
|
LG_RendererRect destRect;
|
||||||
|
LG_RendererRotate rotate; //client side rotation
|
||||||
|
|
||||||
float translateX , translateY;
|
float translateX , translateY;
|
||||||
float scaleX , scaleY;
|
float scaleX , scaleY;
|
||||||
@ -263,12 +264,83 @@ void egl_on_restart(void * opaque)
|
|||||||
this->start = false;
|
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;
|
struct Inst * this = (struct Inst *)opaque;
|
||||||
|
|
||||||
this->width = width;
|
this->width = width;
|
||||||
this->height = height;
|
this->height = height;
|
||||||
|
this->rotate = rotate;
|
||||||
|
|
||||||
memcpy(&this->destRect, &destRect, sizeof(LG_RendererRect));
|
memcpy(&this->destRect, &destRect, sizeof(LG_RendererRect));
|
||||||
|
|
||||||
glViewport(0, 0, width, height);
|
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->scaleY = (float)destRect.h / (float)height;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->mouseScaleX = 2.0f / this->format.width ;
|
egl_calc_mouse_size(this);
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
this->splashRatio = (float)width / (float)height;
|
this->splashRatio = (float)width / (float)height;
|
||||||
this->screenScaleX = 1.0f / width;
|
this->screenScaleX = 1.0f / width;
|
||||||
this->screenScaleY = 1.0f / height;
|
this->screenScaleY = 1.0f / height;
|
||||||
|
|
||||||
egl_cursor_set_state(
|
egl_calc_mouse_state(this);
|
||||||
this->cursor,
|
|
||||||
this->cursorVisible,
|
|
||||||
(((float)this->cursorX * this->mouseScaleX) - 1.0f) * this->scaleX,
|
|
||||||
(((float)this->cursorY * this->mouseScaleY) - 1.0f) * this->scaleY
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool egl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor,
|
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)
|
const int pitch, const uint8_t * data)
|
||||||
{
|
{
|
||||||
struct Inst * this = (struct Inst *)opaque;
|
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");
|
DEBUG_ERROR("Failed to update the cursor shape");
|
||||||
return false;
|
return false;
|
||||||
@ -313,10 +376,7 @@ bool egl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor,
|
|||||||
|
|
||||||
this->mouseWidth = width;
|
this->mouseWidth = width;
|
||||||
this->mouseHeight = height;
|
this->mouseHeight = height;
|
||||||
egl_cursor_set_size(this->cursor,
|
egl_calc_mouse_size(this);
|
||||||
(this->mouseWidth * (1.0f / this->format.width )) * this->scaleX,
|
|
||||||
(this->mouseHeight * (1.0f / this->format.height)) * this->scaleY
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
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->cursorVisible = visible;
|
||||||
this->cursorX = x;
|
this->cursorX = x;
|
||||||
this->cursorY = y;
|
this->cursorY = y;
|
||||||
|
egl_calc_mouse_state(this);
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,7 +674,7 @@ bool egl_render_startup(void * opaque, SDL_Window * window)
|
|||||||
return true;
|
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;
|
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,
|
if (this->start && egl_desktop_render(this->desktop,
|
||||||
this->translateX, this->translateY,
|
this->translateX, this->translateY,
|
||||||
this->scaleX , this->scaleY ,
|
this->scaleX , this->scaleY ,
|
||||||
this->useNearest))
|
this->useNearest,
|
||||||
|
rotate))
|
||||||
{
|
{
|
||||||
if (!this->waitFadeTime)
|
if (!this->waitFadeTime)
|
||||||
{
|
{
|
||||||
@ -640,7 +694,9 @@ bool egl_render(void * opaque, SDL_Window * window)
|
|||||||
else
|
else
|
||||||
this->waitDone = true;
|
this->waitDone = true;
|
||||||
}
|
}
|
||||||
egl_cursor_render(this->cursor);
|
|
||||||
|
egl_cursor_render(this->cursor,
|
||||||
|
(this->format.rotate + rotate) % LG_ROTATE_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->waitDone)
|
if (!this->waitDone)
|
||||||
|
@ -316,7 +316,8 @@ void opengl_on_restart(void * opaque)
|
|||||||
this->waiting = true;
|
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;
|
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;
|
struct Inst * this = (struct Inst *)opaque;
|
||||||
if (!this)
|
if (!this)
|
||||||
@ -562,7 +564,7 @@ bool opengl_render_startup(void * opaque, SDL_Window * window)
|
|||||||
return true;
|
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;
|
struct Inst * this = (struct Inst *)opaque;
|
||||||
if (!this)
|
if (!this)
|
||||||
|
@ -173,74 +173,92 @@ static void alignToGuest(void)
|
|||||||
|
|
||||||
static void updatePositionInfo(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;
|
force = false;
|
||||||
const float wndAspect = (float)g_state.windowH / (float)g_state.windowW;
|
g_state.dstRect.w = srcW;
|
||||||
bool force = true;
|
g_state.dstRect.h = srcH;
|
||||||
|
g_state.dstRect.x = g_state.windowCX - srcW / 2;
|
||||||
if (params.dontUpscale &&
|
g_state.dstRect.y = g_state.windowCY - srcH / 2;
|
||||||
g_state.srcSize.x <= g_state.windowW &&
|
}
|
||||||
g_state.srcSize.y <= g_state.windowH)
|
else
|
||||||
{
|
if ((int)(wndAspect * 1000) == (int)(srcAspect * 1000))
|
||||||
force = false;
|
{
|
||||||
g_state.dstRect.w = g_state.srcSize.x;
|
force = false;
|
||||||
g_state.dstRect.h = g_state.srcSize.y;
|
g_state.dstRect.w = g_state.windowW;
|
||||||
g_state.dstRect.x = g_state.windowCX - g_state.srcSize.x / 2;
|
g_state.dstRect.h = g_state.windowH;
|
||||||
g_state.dstRect.y = g_state.windowCY - g_state.srcSize.y / 2;
|
g_state.dstRect.x = 0;
|
||||||
}
|
g_state.dstRect.y = 0;
|
||||||
else
|
}
|
||||||
if ((int)(wndAspect * 1000) == (int)(srcAspect * 1000))
|
else
|
||||||
{
|
if (wndAspect < srcAspect)
|
||||||
force = false;
|
{
|
||||||
g_state.dstRect.w = g_state.windowW;
|
g_state.dstRect.w = (float)g_state.windowH / srcAspect;
|
||||||
g_state.dstRect.h = g_state.windowH;
|
g_state.dstRect.h = g_state.windowH;
|
||||||
g_state.dstRect.x = 0;
|
g_state.dstRect.x = (g_state.windowW >> 1) - (g_state.dstRect.w >> 1);
|
||||||
g_state.dstRect.y = 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_state.dstRect.x = 0;
|
|
||||||
g_state.dstRect.y = 0;
|
|
||||||
g_state.dstRect.w = g_state.windowW;
|
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 = (
|
if (force && params.forceAspect)
|
||||||
g_state.srcSize.y != g_state.dstRect.h ||
|
{
|
||||||
g_state.srcSize.x != g_state.dstRect.w ||
|
g_state.resizeTimeout = microtime() + RESIZE_TIMEOUT;
|
||||||
g_cursor.guest.dpiScale != 100);
|
g_state.resizeDone = false;
|
||||||
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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);
|
atomic_fetch_add(&g_state.lgrResize, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,11 +292,12 @@ static int renderThread(void * unused)
|
|||||||
if (resize)
|
if (resize)
|
||||||
{
|
{
|
||||||
if (g_state.lgr)
|
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);
|
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;
|
break;
|
||||||
|
|
||||||
if (params.showFPS)
|
if (params.showFPS)
|
||||||
@ -430,7 +449,6 @@ static int cursorThread(void * unused)
|
|||||||
cursorType,
|
cursorType,
|
||||||
cursor->width,
|
cursor->width,
|
||||||
cursor->height,
|
cursor->height,
|
||||||
params.winRotate,
|
|
||||||
cursor->pitch,
|
cursor->pitch,
|
||||||
data)
|
data)
|
||||||
)
|
)
|
||||||
@ -568,6 +586,15 @@ static int frameThread(void * unused)
|
|||||||
lgrFormat.stride = frame->stride;
|
lgrFormat.stride = frame->stride;
|
||||||
lgrFormat.pitch = frame->pitch;
|
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;
|
bool error = false;
|
||||||
switch(frame->type)
|
switch(frame->type)
|
||||||
{
|
{
|
||||||
@ -599,12 +626,11 @@ static int frameThread(void * unused)
|
|||||||
formatValid = true;
|
formatValid = true;
|
||||||
formatVer = frame->formatVer;
|
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],
|
FrameTypeStr[frame->type],
|
||||||
frame->width, frame->height,
|
frame->width, frame->height,
|
||||||
frame->stride, frame->pitch);
|
frame->stride, frame->pitch,
|
||||||
|
frame->rotation);
|
||||||
lgrFormat.rotate = params.winRotate;
|
|
||||||
|
|
||||||
if (!g_state.lgr->on_frame_format(g_state.lgrData, lgrFormat, useDMA))
|
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)
|
static void guestCurToLocal(struct DoublePoint *local)
|
||||||
{
|
{
|
||||||
local->x = g_state.dstRect.x +
|
const struct DoublePoint point =
|
||||||
(g_cursor.guest.x + g_cursor.guest.hx) / g_cursor.scale.x;
|
{
|
||||||
local->y = g_state.dstRect.y +
|
.x = g_cursor.guest.x + g_cursor.guest.hx,
|
||||||
(g_cursor.guest.y + g_cursor.guest.hy) / g_cursor.scale.y;
|
.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)
|
void app_handleMouseNormal(double ex, double ey)
|
||||||
@ -1154,11 +1269,8 @@ void app_handleMouseNormal(double ex, double ey)
|
|||||||
{
|
{
|
||||||
g_cursor.realign = false;
|
g_cursor.realign = false;
|
||||||
|
|
||||||
struct DoublePoint guest =
|
struct DoublePoint guest;
|
||||||
{
|
localCurToGuest(&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
|
|
||||||
};
|
|
||||||
|
|
||||||
/* add the difference to the offset */
|
/* add the difference to the offset */
|
||||||
ex += guest.x - (g_cursor.guest.x + g_cursor.guest.hx);
|
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))
|
(fabs(ex) > 100.0 / g_cursor.scale.x || fabs(ey) > 100.0 / g_cursor.scale.y))
|
||||||
testExit = false;
|
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 any buttons are held we should not allow exit to happen */
|
||||||
if (g_cursor.buttons)
|
if (g_cursor.buttons)
|
||||||
testExit = false;
|
testExit = false;
|
||||||
|
|
||||||
/* check if the move would push the cursor outside the guest's viewport */
|
if (testExit)
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
local.x += ex;
|
/* translate the move to the guests orientation */
|
||||||
local.y += ey;
|
struct DoublePoint move = {.x = ex, .y = ey};
|
||||||
const int tx = (local.x <= 0.0) ? floor(local.x) : ceil(local.x);
|
rotatePoint(&move);
|
||||||
const int ty = (local.y <= 0.0) ? floor(local.y) : ceil(local.y);
|
|
||||||
|
|
||||||
if (isValidCursorLocation(
|
/* translate the guests position to our coordinate space */
|
||||||
g_state.windowPos.x + g_state.border.x + tx,
|
struct DoublePoint local;
|
||||||
g_state.windowPos.y + g_state.border.y + ty))
|
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 (isValidCursorLocation(
|
||||||
if (tx < 0 || ty < 0 || tx > g_state.windowW || ty > g_state.windowH)
|
g_state.windowPos.x + g_state.border.x + tx,
|
||||||
g_cursor.inWindow = false;
|
g_state.windowPos.y + g_state.border.y + ty))
|
||||||
|
{
|
||||||
|
setCursorInView(false);
|
||||||
|
|
||||||
/* ungrab the pointer and move the local cursor to the exit point */
|
/* preempt the window leave flag if the warp will leave our window */
|
||||||
g_state.ds->ungrabPointer();
|
if (tx < 0 || ty < 0 || tx > g_state.windowW || ty > g_state.windowH)
|
||||||
|
g_cursor.inWindow = false;
|
||||||
|
|
||||||
warpPointer(tx, ty, true);
|
/* ungrab the pointer and move the local cursor to the exit point */
|
||||||
return;
|
g_state.ds->ungrabPointer();
|
||||||
|
|
||||||
|
warpPointer(tx, ty, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ struct AppState
|
|||||||
SDL_Point windowPos;
|
SDL_Point windowPos;
|
||||||
int windowW, windowH;
|
int windowW, windowH;
|
||||||
int windowCX, windowCY;
|
int windowCX, windowCY;
|
||||||
|
LG_RendererRotate rotate;
|
||||||
bool focused;
|
bool focused;
|
||||||
SDL_Rect border;
|
SDL_Rect border;
|
||||||
SDL_Point srcSize;
|
SDL_Point srcSize;
|
||||||
|
Loading…
Reference in New Issue
Block a user