mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 05:27:20 +00:00
[obs] added monochrome cursor support
This commit is contained in:
parent
eb343ca82e
commit
4f40ce4b40
171
obs/lg.c
171
obs/lg.c
@ -12,6 +12,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@ -40,14 +41,17 @@ typedef struct
|
|||||||
pthread_t frameThread, pointerThread;
|
pthread_t frameThread, pointerThread;
|
||||||
os_sem_t * frameSem;
|
os_sem_t * frameSem;
|
||||||
|
|
||||||
|
bool cursorMono;
|
||||||
gs_texture_t * cursorTex;
|
gs_texture_t * cursorTex;
|
||||||
|
struct gs_rect cursorRect;
|
||||||
|
|
||||||
bool cursorVisible;
|
bool cursorVisible;
|
||||||
volatile KVMFRCursor cursor;
|
KVMFRCursor cursor;
|
||||||
os_sem_t * cursorSem;
|
os_sem_t * cursorSem;
|
||||||
atomic_uint cursorVer;
|
atomic_uint cursorVer;
|
||||||
unsigned int cursorCurVer;
|
unsigned int cursorCurVer;
|
||||||
uint32_t cursorSize;
|
uint32_t cursorSize;
|
||||||
void * cursorData;
|
uint32_t * cursorData;
|
||||||
}
|
}
|
||||||
LGPlugin;
|
LGPlugin;
|
||||||
|
|
||||||
@ -182,6 +186,16 @@ static void * frameThread(void * data)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static void allocCursorData(LGPlugin * this, const unsigned int size)
|
||||||
|
{
|
||||||
|
if (this->cursorSize >= size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bfree(this->cursorData);
|
||||||
|
this->cursorSize = size;
|
||||||
|
this->cursorData = bmalloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
static void * pointerThread(void * data)
|
static void * pointerThread(void * data)
|
||||||
{
|
{
|
||||||
LGPlugin * this = (LGPlugin *)data;
|
LGPlugin * this = (LGPlugin *)data;
|
||||||
@ -209,57 +223,69 @@ static void * pointerThread(void * data)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
KVMFRCursor * cursor = (KVMFRCursor *)msg.mem;
|
const KVMFRCursor * const cursor = (const KVMFRCursor * const)msg.mem;
|
||||||
this->cursorVisible =
|
this->cursorVisible =
|
||||||
msg.udata & CURSOR_FLAG_VISIBLE;
|
msg.udata & CURSOR_FLAG_VISIBLE;
|
||||||
|
|
||||||
if (msg.udata & CURSOR_FLAG_SHAPE)
|
if (msg.udata & CURSOR_FLAG_SHAPE)
|
||||||
{
|
{
|
||||||
os_sem_wait(this->cursorSem);
|
os_sem_wait(this->cursorSem);
|
||||||
const uint8_t * data = (const uint8_t *)(cursor + 1);
|
const uint8_t * const data = (const uint8_t * const)(cursor + 1);
|
||||||
unsigned int dataSize = 0;
|
unsigned int dataSize = 0;
|
||||||
|
|
||||||
this->cursor.type = cursor->type;
|
|
||||||
switch(cursor->type)
|
switch(cursor->type)
|
||||||
{
|
{
|
||||||
case CURSOR_TYPE_MASKED_COLOR:
|
case CURSOR_TYPE_MASKED_COLOR:
|
||||||
// fall through
|
{
|
||||||
|
dataSize = cursor->height * cursor->pitch;
|
||||||
|
allocCursorData(this, dataSize);
|
||||||
|
|
||||||
|
const uint32_t * s = (const uint32_t *)data;
|
||||||
|
uint32_t * d = this->cursorData;
|
||||||
|
for(int i = 0; i < dataSize; ++i, ++s, ++d)
|
||||||
|
*d = (*s & ~0xFF000000) | (*s & 0xFF000000 ? 0x0 : 0xFF000000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CURSOR_TYPE_COLOR:
|
case CURSOR_TYPE_COLOR:
|
||||||
|
{
|
||||||
dataSize = cursor->height * cursor->pitch;
|
dataSize = cursor->height * cursor->pitch;
|
||||||
|
allocCursorData(this, dataSize);
|
||||||
|
memcpy(this->cursorData, data, dataSize);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CURSOR_TYPE_MONOCHROME:
|
case CURSOR_TYPE_MONOCHROME:
|
||||||
dataSize = cursor->width * cursor->height;
|
{
|
||||||
|
dataSize = cursor->height * sizeof(uint32_t);
|
||||||
|
allocCursorData(this, dataSize);
|
||||||
|
|
||||||
|
const int hheight = cursor->height / 2;
|
||||||
|
uint32_t * d = this->cursorData;
|
||||||
|
for(int y = 0; y < hheight; ++y)
|
||||||
|
for(int x = 0; x < cursor->width; ++x)
|
||||||
|
{
|
||||||
|
const uint8_t * srcAnd = data + (cursor->pitch * y) + (x / 8);
|
||||||
|
const uint8_t * srcXor = srcAnd + cursor->pitch * hheight;
|
||||||
|
const uint8_t mask = 0x80 >> (x % 8);
|
||||||
|
const uint32_t andMask = (*srcAnd & mask) ? 0xFFFFFFFF : 0xFF000000;
|
||||||
|
const uint32_t xorMask = (*srcXor & mask) ? 0x00FFFFFF : 0x00000000;
|
||||||
|
|
||||||
|
d[y * cursor->width + x ] = andMask;
|
||||||
|
d[y * cursor->width + x + cursor->width * hheight] = xorMask;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("Invalid cursor type\n");
|
printf("Invalid cursor type\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->cursorSize < dataSize)
|
this->cursor.type = cursor->type;
|
||||||
{
|
|
||||||
free(this->cursorData);
|
|
||||||
this->cursorSize = dataSize;
|
|
||||||
this->cursorData = bmalloc(dataSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(this->cursorData, data, dataSize);
|
|
||||||
|
|
||||||
if (cursor->type == CURSOR_TYPE_MASKED_COLOR)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < dataSize; ++i)
|
|
||||||
{
|
|
||||||
const uint32_t c = ((uint32_t *)this->cursorData)[i];
|
|
||||||
((uint32_t *)this->cursorData)[i] = (c & ~0xFF000000) | (c & 0xFF000000 ? 0x0 : 0xFF000000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->cursor.width = cursor->width;
|
this->cursor.width = cursor->width;
|
||||||
this->cursor.height = cursor->height;
|
this->cursor.height = cursor->height;
|
||||||
this->cursor.hx = cursor->hx;
|
|
||||||
this->cursor.hy = cursor->hy;
|
|
||||||
|
|
||||||
atomic_fetch_add_explicit(&this->cursorVer, 1, memory_order_relaxed);
|
atomic_fetch_add_explicit(&this->cursorVer, 1, memory_order_relaxed);
|
||||||
os_sem_post(this->cursorSem);
|
os_sem_post(this->cursorSem);
|
||||||
@ -342,6 +368,9 @@ static void lgVideoTick(void * data, float seconds)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->cursorRect.x = this->cursor.x;
|
||||||
|
this->cursorRect.y = this->cursor.y;
|
||||||
|
|
||||||
/* update the cursor texture */
|
/* update the cursor texture */
|
||||||
unsigned int cursorVer = atomic_load(&this->cursorVer);
|
unsigned int cursorVer = atomic_load(&this->cursorVer);
|
||||||
if (cursorVer != this->cursorCurVer)
|
if (cursorVer != this->cursorCurVer)
|
||||||
@ -361,23 +390,39 @@ static void lgVideoTick(void * data, float seconds)
|
|||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
|
|
||||||
case CURSOR_TYPE_COLOR:
|
case CURSOR_TYPE_COLOR:
|
||||||
this->cursorTex =
|
this->cursorMono = false;
|
||||||
|
this->cursorTex =
|
||||||
gs_texture_create(
|
gs_texture_create(
|
||||||
this->cursor.width,
|
this->cursor.width,
|
||||||
this->cursor.height,
|
this->cursor.height,
|
||||||
GS_BGRA,
|
GS_BGRA,
|
||||||
1,
|
1,
|
||||||
(const uint8_t**)&this->cursorData,
|
(const uint8_t **)&this->cursorData,
|
||||||
|
GS_DYNAMIC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURSOR_TYPE_MONOCHROME:
|
||||||
|
this->cursorMono = true;
|
||||||
|
this->cursorTex =
|
||||||
|
gs_texture_create(
|
||||||
|
this->cursor.width,
|
||||||
|
this->cursor.height,
|
||||||
|
GS_RGBA,
|
||||||
|
1,
|
||||||
|
(const uint8_t **)&this->cursorData,
|
||||||
GS_DYNAMIC);
|
GS_DYNAMIC);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("only rgb cursors supported at this time\n");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_leave_graphics();
|
obs_leave_graphics();
|
||||||
this->cursorCurVer = cursorVer;
|
|
||||||
|
this->cursorCurVer = cursorVer;
|
||||||
|
this->cursorRect.cx = this->cursor.width;
|
||||||
|
this->cursorRect.cy = this->cursor.height;
|
||||||
|
|
||||||
os_sem_post(this->cursorSem);
|
os_sem_post(this->cursorSem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,17 +528,6 @@ static void lgVideoRender(void * data, gs_effect_t * effect)
|
|||||||
if (!this->texture)
|
if (!this->texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
struct matrix4 m4;
|
|
||||||
gs_matrix_get(&m4);
|
|
||||||
struct gs_rect r =
|
|
||||||
{
|
|
||||||
.x = m4.t.x,
|
|
||||||
.y = m4.t.y,
|
|
||||||
.cx = (double)this->width * m4.x.x,
|
|
||||||
.cy = (double)this->height * m4.y.y
|
|
||||||
};
|
|
||||||
gs_set_scissor_rect(&r);
|
|
||||||
|
|
||||||
effect = obs_get_base_effect(OBS_EFFECT_OPAQUE);
|
effect = obs_get_base_effect(OBS_EFFECT_OPAQUE);
|
||||||
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
|
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
|
||||||
gs_effect_set_texture(image, this->texture);
|
gs_effect_set_texture(image, this->texture);
|
||||||
@ -503,19 +537,54 @@ static void lgVideoRender(void * data, gs_effect_t * effect)
|
|||||||
|
|
||||||
if (this->cursorVisible && this->cursorTex)
|
if (this->cursorVisible && this->cursorTex)
|
||||||
{
|
{
|
||||||
|
struct matrix4 m4;
|
||||||
|
gs_matrix_get(&m4);
|
||||||
|
struct gs_rect r =
|
||||||
|
{
|
||||||
|
.x = m4.t.x,
|
||||||
|
.y = m4.t.y,
|
||||||
|
.cx = (double)this->width * m4.x.x,
|
||||||
|
.cy = (double)this->height * m4.y.y
|
||||||
|
};
|
||||||
|
gs_set_scissor_rect(&r);
|
||||||
|
|
||||||
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
|
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
|
||||||
image = gs_effect_get_param_by_name(effect, "image");
|
image = gs_effect_get_param_by_name(effect, "image");
|
||||||
gs_effect_set_texture(image, this->cursorTex);
|
gs_effect_set_texture(image, this->cursorTex);
|
||||||
while (gs_effect_loop(effect, "Draw"))
|
|
||||||
{
|
|
||||||
gs_matrix_push();
|
|
||||||
gs_matrix_translate3f(this->cursor.x, this->cursor.y, 0.0f);
|
|
||||||
gs_draw_sprite(this->cursorTex, 0, 0, 0);
|
|
||||||
gs_matrix_pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gs_set_scissor_rect(NULL);
|
gs_matrix_push();
|
||||||
|
gs_matrix_translate3f(this->cursorRect.x, this->cursorRect.y, 0.0f);
|
||||||
|
|
||||||
|
if (!this->cursorMono)
|
||||||
|
{
|
||||||
|
while (gs_effect_loop(effect, "Draw"))
|
||||||
|
gs_draw_sprite(this->cursorTex, 0, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (gs_effect_loop(effect, "Draw"))
|
||||||
|
{
|
||||||
|
glEnable(GL_COLOR_LOGIC_OP);
|
||||||
|
|
||||||
|
glLogicOp(GL_AND);
|
||||||
|
gs_draw_sprite_subregion(
|
||||||
|
this->cursorTex , 0,
|
||||||
|
0 , 0,
|
||||||
|
this->cursorRect.cx, this->cursorRect.cy / 2 - 1);
|
||||||
|
|
||||||
|
glLogicOp(GL_XOR);
|
||||||
|
gs_draw_sprite_subregion(
|
||||||
|
this->cursorTex , 0,
|
||||||
|
0 , this->cursorRect.cy / 2 + 1,
|
||||||
|
this->cursorRect.cx, this->cursorRect.cy / 2);
|
||||||
|
|
||||||
|
glDisable(GL_COLOR_LOGIC_OP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gs_matrix_pop();
|
||||||
|
gs_set_scissor_rect(NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t lgGetWidth(void * data)
|
static uint32_t lgGetWidth(void * data)
|
||||||
|
Loading…
Reference in New Issue
Block a user