mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 13:37:22 +00:00
[client] all: add screen rotation support win:rotate
Currently only supports EGL, if there is enough demand for OpenGL support this can be added later. Closes #231
This commit is contained in:
parent
c40a81ddf4
commit
72c86d7125
@ -57,14 +57,24 @@ typedef enum LG_RendererSupport
|
|||||||
}
|
}
|
||||||
LG_RendererSupport;
|
LG_RendererSupport;
|
||||||
|
|
||||||
|
typedef enum LG_RendererRotate
|
||||||
|
{
|
||||||
|
LG_ROTATE_UP,
|
||||||
|
LG_ROTATE_DOWN,
|
||||||
|
LG_ROTATE_LEFT,
|
||||||
|
LG_ROTATE_RIGHT
|
||||||
|
}
|
||||||
|
LG_RendererRotate;
|
||||||
|
|
||||||
typedef struct LG_RendererFormat
|
typedef struct LG_RendererFormat
|
||||||
{
|
{
|
||||||
FrameType type; // frame type
|
FrameType type; // frame type
|
||||||
unsigned int width; // image width
|
unsigned int width; // image width
|
||||||
unsigned int height; // image height
|
unsigned int height; // image height
|
||||||
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_RendererFormat;
|
LG_RendererFormat;
|
||||||
|
|
||||||
@ -98,7 +108,7 @@ 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);
|
||||||
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_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_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);
|
||||||
|
@ -39,6 +39,7 @@ struct CursorTex
|
|||||||
struct EGL_Texture * texture;
|
struct EGL_Texture * texture;
|
||||||
struct EGL_Shader * shader;
|
struct EGL_Shader * shader;
|
||||||
GLuint uMousePos;
|
GLuint uMousePos;
|
||||||
|
GLuint uRotate;
|
||||||
GLuint uCBMode;
|
GLuint uCBMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,6 +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;
|
||||||
int cbMode;
|
int cbMode;
|
||||||
|
|
||||||
struct CursorTex norm;
|
struct CursorTex norm;
|
||||||
@ -87,11 +89,61 @@ static bool egl_cursor_tex_init(struct CursorTex * t,
|
|||||||
}
|
}
|
||||||
|
|
||||||
t->uMousePos = egl_shader_get_uniform_location(t->shader, "mouse" );
|
t->uMousePos = egl_shader_get_uniform_location(t->shader, "mouse" );
|
||||||
|
t->uRotate = egl_shader_get_uniform_location(t->shader, "rotate");
|
||||||
t->uCBMode = egl_shader_get_uniform_location(t->shader, "cbMode");
|
t->uCBMode = egl_shader_get_uniform_location(t->shader, "cbMode");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void egl_cursor_tex_uniforms(EGL_Cursor * cursor, struct CursorTex * t, bool mono)
|
||||||
|
{
|
||||||
|
float x, y, w, h;
|
||||||
|
|
||||||
|
switch(cursor->rotate)
|
||||||
|
{
|
||||||
|
case LG_ROTATE_UP:
|
||||||
|
x = cursor->x;
|
||||||
|
y = cursor->y;
|
||||||
|
w = cursor->w;
|
||||||
|
h = cursor->h;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LG_ROTATE_DOWN:
|
||||||
|
x = -cursor->x;
|
||||||
|
y = -cursor->y;
|
||||||
|
w = cursor->w;
|
||||||
|
h = cursor->h;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LG_ROTATE_LEFT:
|
||||||
|
x = cursor->y;
|
||||||
|
y = -cursor->x;
|
||||||
|
w = cursor->h;
|
||||||
|
h = cursor->w;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LG_ROTATE_RIGHT:
|
||||||
|
x = -cursor->y;
|
||||||
|
y = cursor->x;
|
||||||
|
w = cursor->h;
|
||||||
|
h = cursor->w;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mono)
|
||||||
|
{
|
||||||
|
glUniform4f(t->uMousePos, x, y, w, h / 2);
|
||||||
|
glUniform1i(t->uRotate , cursor->rotate);
|
||||||
|
glUniform1i(t->uCBMode , cursor->cbMode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glUniform4f(t->uMousePos, x, y, w, h);
|
||||||
|
glUniform1i(t->uRotate , cursor->rotate);
|
||||||
|
glUniform1i(t->uCBMode , cursor->cbMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void egl_cursor_tex_free(struct CursorTex * t)
|
static void egl_cursor_tex_free(struct CursorTex * t)
|
||||||
{
|
{
|
||||||
egl_texture_free(&t->texture);
|
egl_texture_free(&t->texture);
|
||||||
@ -150,14 +202,17 @@ void egl_cursor_free(EGL_Cursor ** cursor)
|
|||||||
*cursor = NULL;
|
*cursor = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool egl_cursor_set_shape(EGL_Cursor * cursor, const LG_RendererCursor type, const int width, const int height, const int stride, const uint8_t * data)
|
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)
|
||||||
{
|
{
|
||||||
LG_LOCK(cursor->lock);
|
LG_LOCK(cursor->lock);
|
||||||
|
|
||||||
cursor->type = type;
|
cursor->type = 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)
|
||||||
@ -238,9 +293,9 @@ void egl_cursor_render(EGL_Cursor * cursor)
|
|||||||
xor[y * cursor->width + x] = xorMask;
|
xor[y * cursor->width + x] = xorMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
egl_texture_setup (cursor->norm.texture , EGL_PF_BGRA, cursor->width, cursor->height, cursor->width * 4, false, false);
|
egl_texture_setup (cursor->norm.texture, EGL_PF_BGRA, cursor->width, cursor->height, cursor->width * 4, false, false);
|
||||||
egl_texture_setup (cursor->mono.texture, EGL_PF_BGRA, cursor->width, cursor->height, cursor->width * 4, false, false);
|
egl_texture_setup (cursor->mono.texture, EGL_PF_BGRA, cursor->width, cursor->height, cursor->width * 4, false, false);
|
||||||
egl_texture_update(cursor->norm.texture , (uint8_t *)and);
|
egl_texture_update(cursor->norm.texture, (uint8_t *)and);
|
||||||
egl_texture_update(cursor->mono.texture, (uint8_t *)xor);
|
egl_texture_update(cursor->mono.texture, (uint8_t *)xor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -254,14 +309,13 @@ void egl_cursor_render(EGL_Cursor * cursor)
|
|||||||
case LG_CURSOR_MONOCHROME:
|
case LG_CURSOR_MONOCHROME:
|
||||||
{
|
{
|
||||||
egl_shader_use(cursor->norm.shader);
|
egl_shader_use(cursor->norm.shader);
|
||||||
glUniform4f(cursor->norm.uMousePos, cursor->x, cursor->y, cursor->w, cursor->h / 2);
|
egl_cursor_tex_uniforms(cursor, &cursor->norm, true);;
|
||||||
glUniform1i(cursor->norm.uCBMode , cursor->cbMode);
|
|
||||||
glBlendFunc(GL_ZERO, GL_SRC_COLOR);
|
glBlendFunc(GL_ZERO, GL_SRC_COLOR);
|
||||||
egl_model_set_texture(cursor->model, cursor->norm.texture);
|
egl_model_set_texture(cursor->model, cursor->norm.texture);
|
||||||
egl_model_render(cursor->model);
|
egl_model_render(cursor->model);
|
||||||
|
|
||||||
egl_shader_use(cursor->mono.shader);
|
egl_shader_use(cursor->mono.shader);
|
||||||
glUniform4f(cursor->mono.uMousePos, cursor->x, cursor->y, cursor->w, cursor->h / 2);
|
egl_cursor_tex_uniforms(cursor, &cursor->mono, true);;
|
||||||
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
|
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
|
||||||
egl_model_set_texture(cursor->model, cursor->mono.texture);
|
egl_model_set_texture(cursor->model, cursor->mono.texture);
|
||||||
egl_model_render(cursor->model);
|
egl_model_render(cursor->model);
|
||||||
@ -271,8 +325,7 @@ void egl_cursor_render(EGL_Cursor * cursor)
|
|||||||
case LG_CURSOR_COLOR:
|
case LG_CURSOR_COLOR:
|
||||||
{
|
{
|
||||||
egl_shader_use(cursor->norm.shader);
|
egl_shader_use(cursor->norm.shader);
|
||||||
glUniform4f(cursor->norm.uMousePos, cursor->x, cursor->y, cursor->w, cursor->h);
|
egl_cursor_tex_uniforms(cursor, &cursor->norm, false);
|
||||||
glUniform1i(cursor->norm.uCBMode , cursor->cbMode);
|
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
egl_model_render(cursor->model);
|
egl_model_render(cursor->model);
|
||||||
break;
|
break;
|
||||||
@ -281,7 +334,7 @@ void egl_cursor_render(EGL_Cursor * cursor)
|
|||||||
case LG_CURSOR_MASKED_COLOR:
|
case LG_CURSOR_MASKED_COLOR:
|
||||||
{
|
{
|
||||||
egl_shader_use(cursor->mono.shader);
|
egl_shader_use(cursor->mono.shader);
|
||||||
glUniform4f(cursor->mono.uMousePos, cursor->x, cursor->y, cursor->w, cursor->h);
|
egl_cursor_tex_uniforms(cursor, &cursor->mono, false);
|
||||||
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
|
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
|
||||||
egl_model_render(cursor->model);
|
egl_model_render(cursor->model);
|
||||||
break;
|
break;
|
||||||
|
@ -28,7 +28,15 @@ typedef struct EGL_Cursor EGL_Cursor;
|
|||||||
bool egl_cursor_init(EGL_Cursor ** cursor);
|
bool egl_cursor_init(EGL_Cursor ** cursor);
|
||||||
void egl_cursor_free(EGL_Cursor ** cursor);
|
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 int stride, const uint8_t * data);
|
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);
|
||||||
|
|
||||||
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_set_state(EGL_Cursor * cursor, const bool visible, const float x, const float y);
|
||||||
void egl_cursor_render (EGL_Cursor * cursor);
|
void egl_cursor_render (EGL_Cursor * cursor);
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||||
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
|
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
|
||||||
https://looking-glass.hostfission.com
|
https://looking-glass.hostfission.com
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
@ -34,13 +34,13 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
// these headers are auto generated by cmake
|
// these headers are auto generated by cmake
|
||||||
#include "desktop.vert.h"
|
#include "desktop.vert.h"
|
||||||
#include "desktop_rgb.frag.h"
|
#include "desktop_rgb.frag.h"
|
||||||
#include "desktop_yuv.frag.h"
|
|
||||||
|
|
||||||
struct DesktopShader
|
struct DesktopShader
|
||||||
{
|
{
|
||||||
EGL_Shader * shader;
|
EGL_Shader * shader;
|
||||||
GLint uDesktopPos;
|
GLint uDesktopPos;
|
||||||
GLint uDesktopSize;
|
GLint uDesktopSize;
|
||||||
|
GLint uRotate;
|
||||||
GLint uNearest;
|
GLint uNearest;
|
||||||
GLint uNV, uNVGain;
|
GLint uNV, uNVGain;
|
||||||
GLint uCBMode;
|
GLint uCBMode;
|
||||||
@ -55,11 +55,11 @@ struct EGL_Desktop
|
|||||||
EGL_Model * model;
|
EGL_Model * model;
|
||||||
|
|
||||||
// internals
|
// internals
|
||||||
int width, height;
|
int width, height;
|
||||||
|
LG_RendererRotate rotate;
|
||||||
|
|
||||||
// shader instances
|
// shader instances
|
||||||
struct DesktopShader shader_generic;
|
struct DesktopShader shader_generic;
|
||||||
struct DesktopShader shader_yuv;
|
|
||||||
|
|
||||||
// night vision
|
// night vision
|
||||||
KeybindHandle kbNV;
|
KeybindHandle kbNV;
|
||||||
@ -91,6 +91,7 @@ static bool egl_init_desktop_shader(
|
|||||||
|
|
||||||
shader->uDesktopPos = egl_shader_get_uniform_location(shader->shader, "position");
|
shader->uDesktopPos = egl_shader_get_uniform_location(shader->shader, "position");
|
||||||
shader->uDesktopSize = egl_shader_get_uniform_location(shader->shader, "size" );
|
shader->uDesktopSize = egl_shader_get_uniform_location(shader->shader, "size" );
|
||||||
|
shader->uRotate = egl_shader_get_uniform_location(shader->shader, "rotate" );
|
||||||
shader->uNearest = egl_shader_get_uniform_location(shader->shader, "nearest" );
|
shader->uNearest = egl_shader_get_uniform_location(shader->shader, "nearest" );
|
||||||
shader->uNV = egl_shader_get_uniform_location(shader->shader, "nv" );
|
shader->uNV = egl_shader_get_uniform_location(shader->shader, "nv" );
|
||||||
shader->uNVGain = egl_shader_get_uniform_location(shader->shader, "nvGain" );
|
shader->uNVGain = egl_shader_get_uniform_location(shader->shader, "nvGain" );
|
||||||
@ -203,6 +204,7 @@ 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,
|
||||||
@ -252,6 +254,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->uNearest , nearest ? 1 : 0);
|
glUniform1i(shader->uNearest , nearest ? 1 : 0);
|
||||||
glUniform2f(shader->uDesktopSize, desktop->width, desktop->height);
|
glUniform2f(shader->uDesktopSize, desktop->width, desktop->height);
|
||||||
|
|
||||||
|
@ -318,10 +318,12 @@ void egl_on_resize(void * opaque, const int width, const int height, const LG_Re
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool egl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, const int width, const int height, const int pitch, const uint8_t * data)
|
bool egl_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)
|
||||||
{
|
{
|
||||||
struct Inst * this = (struct Inst *)opaque;
|
struct Inst * this = (struct Inst *)opaque;
|
||||||
if (!egl_cursor_set_shape(this->cursor, cursor, width, height, pitch, data))
|
if (!egl_cursor_set_shape(this->cursor, cursor, width, height, rotate, pitch, data))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to update the cursor shape");
|
DEBUG_ERROR("Failed to update the cursor shape");
|
||||||
return false;
|
return false;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
in highp vec2 uv;
|
in highp vec2 uv;
|
||||||
out highp vec4 color;
|
out highp vec4 color;
|
||||||
|
uniform int rotate;
|
||||||
|
|
||||||
uniform sampler2D sampler1;
|
uniform sampler2D sampler1;
|
||||||
|
|
||||||
@ -9,7 +10,28 @@ uniform int cbMode;
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
color = texture(sampler1, uv);
|
highp vec2 ruv;
|
||||||
|
if (rotate == 0) // up
|
||||||
|
{
|
||||||
|
ruv = uv;
|
||||||
|
}
|
||||||
|
else if (rotate == 1) // down
|
||||||
|
{
|
||||||
|
ruv.x = -uv.x + 1.0f;
|
||||||
|
ruv.y = -uv.y + 1.0f;
|
||||||
|
}
|
||||||
|
else if (rotate == 2) // left
|
||||||
|
{
|
||||||
|
ruv.x = -uv.y + 1.0f;
|
||||||
|
ruv.y = uv.x;
|
||||||
|
}
|
||||||
|
else if (rotate == 3) // right
|
||||||
|
{
|
||||||
|
ruv.x = uv.y;
|
||||||
|
ruv.y = -uv.x + 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
color = texture(sampler1, ruv);
|
||||||
|
|
||||||
if (cbMode > 0)
|
if (cbMode > 0)
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ uniform sampler2D sampler1;
|
|||||||
|
|
||||||
uniform int nearest;
|
uniform int nearest;
|
||||||
uniform highp vec2 size;
|
uniform highp vec2 size;
|
||||||
|
uniform int rotate;
|
||||||
|
|
||||||
uniform int nv;
|
uniform int nv;
|
||||||
uniform highp float nvGain;
|
uniform highp float nvGain;
|
||||||
@ -14,10 +15,31 @@ uniform int cbMode;
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
highp vec2 ruv;
|
||||||
|
if (rotate == 0) // up
|
||||||
|
{
|
||||||
|
ruv = uv;
|
||||||
|
}
|
||||||
|
else if (rotate == 1) // down
|
||||||
|
{
|
||||||
|
ruv.x = -uv.x + 1.0f;
|
||||||
|
ruv.y = -uv.y + 1.0f;
|
||||||
|
}
|
||||||
|
else if (rotate == 2) // left
|
||||||
|
{
|
||||||
|
ruv.x = -uv.y + 1.0f;
|
||||||
|
ruv.y = uv.x;
|
||||||
|
}
|
||||||
|
else if (rotate == 3) // right
|
||||||
|
{
|
||||||
|
ruv.x = uv.y;
|
||||||
|
ruv.y = -uv.x + 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
if(nearest == 1)
|
if(nearest == 1)
|
||||||
color = texture(sampler1, uv);
|
color = texture(sampler1, ruv);
|
||||||
else
|
else
|
||||||
color = texelFetch(sampler1, ivec2(uv * size), 0);
|
color = texelFetch(sampler1, ivec2(ruv * size), 0);
|
||||||
|
|
||||||
if (cbMode > 0)
|
if (cbMode > 0)
|
||||||
{
|
{
|
||||||
|
@ -346,7 +346,7 @@ 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 int pitch, const uint8_t * data)
|
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)
|
||||||
{
|
{
|
||||||
struct Inst * this = (struct Inst *)opaque;
|
struct Inst * this = (struct Inst *)opaque;
|
||||||
if (!this)
|
if (!this)
|
||||||
|
@ -38,6 +38,9 @@ static bool optSizeParse (struct Option * opt, const char * str);
|
|||||||
static StringList optSizeValues (struct Option * opt);
|
static StringList optSizeValues (struct Option * opt);
|
||||||
static char * optSizeToString (struct Option * opt);
|
static char * optSizeToString (struct Option * opt);
|
||||||
static char * optScancodeToString(struct Option * opt);
|
static char * optScancodeToString(struct Option * opt);
|
||||||
|
static bool optRotateParse (struct Option * opt, const char * str);
|
||||||
|
static StringList optRotateValues (struct Option * opt);
|
||||||
|
static char * optRotateToString (struct Option * opt);
|
||||||
|
|
||||||
static void doLicense();
|
static void doLicense();
|
||||||
|
|
||||||
@ -234,6 +237,15 @@ static struct Option options[] =
|
|||||||
.type = OPTION_TYPE_BOOL,
|
.type = OPTION_TYPE_BOOL,
|
||||||
.value.x_bool = false,
|
.value.x_bool = false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.module = "win",
|
||||||
|
.name = "rotate",
|
||||||
|
.description = "Rotate the displayed image",
|
||||||
|
.type = OPTION_TYPE_CUSTOM,
|
||||||
|
.parser = optRotateParse,
|
||||||
|
.getValues = optRotateValues,
|
||||||
|
.toString = optRotateToString
|
||||||
|
},
|
||||||
|
|
||||||
// input options
|
// input options
|
||||||
{
|
{
|
||||||
@ -664,3 +676,46 @@ static char * optScancodeToString(struct Option * opt)
|
|||||||
alloc_sprintf(&str, "%d = %s", opt->value.x_int, SDL_GetScancodeName(opt->value.x_int));
|
alloc_sprintf(&str, "%d = %s", opt->value.x_int, SDL_GetScancodeName(opt->value.x_int));
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool optRotateParse(struct Option * opt, const char * str)
|
||||||
|
{
|
||||||
|
if (!str)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (strcasecmp(str, "up" ) == 0) params.winRotate = LG_ROTATE_UP;
|
||||||
|
else if (strcasecmp(str, "down" ) == 0) params.winRotate = LG_ROTATE_DOWN;
|
||||||
|
else if (strcasecmp(str, "left" ) == 0) params.winRotate = LG_ROTATE_LEFT;
|
||||||
|
else if (strcasecmp(str, "right") == 0) params.winRotate = LG_ROTATE_RIGHT;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringList optRotateValues(struct Option * opt)
|
||||||
|
{
|
||||||
|
StringList sl = stringlist_new(false);
|
||||||
|
|
||||||
|
stringlist_push(sl, "UP" );
|
||||||
|
stringlist_push(sl, "DOWN" );
|
||||||
|
stringlist_push(sl, "LEFT" );
|
||||||
|
stringlist_push(sl, "RIGHT");
|
||||||
|
|
||||||
|
return sl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char * optRotateToString(struct Option * opt)
|
||||||
|
{
|
||||||
|
const char * str;
|
||||||
|
switch(params.winRotate)
|
||||||
|
{
|
||||||
|
case LG_ROTATE_UP : str = "UP" ; break;
|
||||||
|
case LG_ROTATE_DOWN : str = "DOWN" ; break;
|
||||||
|
case LG_ROTATE_LEFT : str = "LEFT" ; break;
|
||||||
|
case LG_ROTATE_RIGHT: str = "RIGHT"; break;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strdup(str);
|
||||||
|
}
|
||||||
|
@ -379,6 +379,7 @@ static int cursorThread(void * unused)
|
|||||||
cursorType,
|
cursorType,
|
||||||
cursor->width,
|
cursor->width,
|
||||||
cursor->height,
|
cursor->height,
|
||||||
|
params.winRotate,
|
||||||
cursor->pitch,
|
cursor->pitch,
|
||||||
data)
|
data)
|
||||||
)
|
)
|
||||||
@ -558,6 +559,8 @@ static int frameThread(void * unused)
|
|||||||
frame->width, frame->height,
|
frame->width, frame->height,
|
||||||
frame->stride, frame->pitch);
|
frame->stride, frame->pitch);
|
||||||
|
|
||||||
|
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))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("renderer failed to configure format");
|
DEBUG_ERROR("renderer failed to configure format");
|
||||||
|
@ -95,53 +95,54 @@ struct AppState
|
|||||||
|
|
||||||
struct AppParams
|
struct AppParams
|
||||||
{
|
{
|
||||||
bool autoResize;
|
bool autoResize;
|
||||||
bool allowResize;
|
bool allowResize;
|
||||||
bool keepAspect;
|
bool keepAspect;
|
||||||
bool forceAspect;
|
bool forceAspect;
|
||||||
bool dontUpscale;
|
bool dontUpscale;
|
||||||
bool borderless;
|
bool borderless;
|
||||||
bool fullscreen;
|
bool fullscreen;
|
||||||
bool maximize;
|
bool maximize;
|
||||||
bool minimizeOnFocusLoss;
|
bool minimizeOnFocusLoss;
|
||||||
bool center;
|
bool center;
|
||||||
int x, y;
|
int x, y;
|
||||||
unsigned int w, h;
|
unsigned int w, h;
|
||||||
int fpsMin;
|
int fpsMin;
|
||||||
bool showFPS;
|
bool showFPS;
|
||||||
bool useSpiceInput;
|
LG_RendererRotate winRotate;
|
||||||
bool useSpiceClipboard;
|
bool useSpiceInput;
|
||||||
const char * spiceHost;
|
bool useSpiceClipboard;
|
||||||
unsigned int spicePort;
|
const char * spiceHost;
|
||||||
bool clipboardToVM;
|
unsigned int spicePort;
|
||||||
bool clipboardToLocal;
|
bool clipboardToVM;
|
||||||
bool scaleMouseInput;
|
bool clipboardToLocal;
|
||||||
bool hideMouse;
|
bool scaleMouseInput;
|
||||||
bool ignoreQuit;
|
bool hideMouse;
|
||||||
bool noScreensaver;
|
bool ignoreQuit;
|
||||||
bool grabKeyboard;
|
bool noScreensaver;
|
||||||
bool grabKeyboardOnFocus;
|
bool grabKeyboard;
|
||||||
SDL_Scancode escapeKey;
|
bool grabKeyboardOnFocus;
|
||||||
bool ignoreWindowsKeys;
|
SDL_Scancode escapeKey;
|
||||||
bool showAlerts;
|
bool ignoreWindowsKeys;
|
||||||
bool captureOnStart;
|
bool showAlerts;
|
||||||
bool quickSplash;
|
bool captureOnStart;
|
||||||
bool alwaysShowCursor;
|
bool quickSplash;
|
||||||
|
bool alwaysShowCursor;
|
||||||
|
|
||||||
unsigned int cursorPollInterval;
|
unsigned int cursorPollInterval;
|
||||||
unsigned int framePollInterval;
|
unsigned int framePollInterval;
|
||||||
bool allowDMA;
|
bool allowDMA;
|
||||||
|
|
||||||
bool forceRenderer;
|
bool forceRenderer;
|
||||||
unsigned int forceRendererIndex;
|
unsigned int forceRendererIndex;
|
||||||
|
|
||||||
const char * windowTitle;
|
const char * windowTitle;
|
||||||
bool mouseRedraw;
|
bool mouseRedraw;
|
||||||
int mouseSens;
|
int mouseSens;
|
||||||
bool mouseSmoothing;
|
bool mouseSmoothing;
|
||||||
bool rawMouse;
|
bool rawMouse;
|
||||||
bool autoCapture;
|
bool autoCapture;
|
||||||
bool captureInputOnly;
|
bool captureInputOnly;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CBRequest
|
struct CBRequest
|
||||||
|
Loading…
Reference in New Issue
Block a user