mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-08-09 20:24:14 +00:00
[client] add SVG loading support and use icons for status display
This brings nanosvg into the project for SVG loading and rendering. Unfortunatly we can not at this time use a submodule for this project until https://github.com/memononen/nanosvg/pull/214 is merged.
This commit is contained in:
@@ -110,7 +110,10 @@ add_custom_command(
|
||||
include_directories(
|
||||
${PROJECT_TOP}
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_BINARY_DIR}/include
|
||||
|
||||
${PROJECT_TOP}/repos/nanosvg/src
|
||||
)
|
||||
|
||||
link_libraries(
|
||||
@@ -142,12 +145,13 @@ set(SOURCES
|
||||
src/overlay/help.c
|
||||
src/overlay/config.c
|
||||
src/overlay/msg.c
|
||||
src/overlay/record.c
|
||||
src/overlay/status.c
|
||||
)
|
||||
|
||||
# Force cimgui to build as a static library.
|
||||
set(IMGUI_STATIC "yes" CACHE STRING "Build as a static library")
|
||||
|
||||
add_subdirectory("${PROJECT_TOP}/resources" "${CMAKE_BINARY_DIR}/resources")
|
||||
add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common" )
|
||||
add_subdirectory("${PROJECT_TOP}/repos/LGMP/lgmp" "${CMAKE_BINARY_DIR}/LGMP" )
|
||||
add_subdirectory("${PROJECT_TOP}/repos/PureSpice" "${CMAKE_BINARY_DIR}/PureSpice")
|
||||
@@ -163,6 +167,7 @@ target_compile_definitions(looking-glass-client PRIVATE CIMGUI_DEFINE_ENUMS_AND_
|
||||
target_link_libraries(looking-glass-client
|
||||
${EXE_FLAGS}
|
||||
PkgConfig::FONTCONFIG
|
||||
lg_resources
|
||||
lg_common
|
||||
displayservers
|
||||
lgmp
|
||||
|
@@ -1,42 +0,0 @@
|
||||
function(make_object out_var)
|
||||
set(result)
|
||||
set(result_h)
|
||||
foreach(in_f ${ARGN})
|
||||
file(RELATIVE_PATH out_f ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/${in_f}")
|
||||
set(out_h "${CMAKE_CURRENT_BINARY_DIR}/${out_f}.h")
|
||||
set(out_f "${CMAKE_CURRENT_BINARY_DIR}/${out_f}.o")
|
||||
string(REGEX REPLACE "[/.-]" "_" sym_in "${in_f}")
|
||||
|
||||
add_custom_command(OUTPUT ${out_f}
|
||||
COMMAND ${CMAKE_LINKER} -r -b binary -o ${out_f} "${in_f}"
|
||||
COMMAND ${CMAKE_OBJCOPY} --rename-section .data=.rodata,CONTENTS,ALLOC,LOAD,READONLY,DATA ${out_f} ${out_f}
|
||||
COMMAND ${CMAKE_OBJCOPY} --redefine-sym _binary_${sym_in}_start=b_${sym_in} ${out_f} ${out_f}
|
||||
COMMAND ${CMAKE_OBJCOPY} --redefine-sym _binary_${sym_in}_end=b_${sym_in}_end ${out_f} ${out_f}
|
||||
COMMAND ${CMAKE_OBJCOPY} --strip-symbol _binary_${sym_in}_size ${out_f} ${out_f}
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${in_f}"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Creating object from ${in_f}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
file(WRITE ${out_h} "extern const char b_${sym_in}[];\n")
|
||||
file(APPEND ${out_h} "extern const char b_${sym_in}_end[];\n")
|
||||
file(APPEND ${out_h} "#define b_${sym_in}_size (b_${sym_in}_end - b_${sym_in})\n")
|
||||
|
||||
get_filename_component(h_dir ${out_h} DIRECTORY)
|
||||
list(APPEND result_h ${h_dir})
|
||||
list(APPEND result ${out_f})
|
||||
endforeach()
|
||||
list(REMOVE_DUPLICATES result_h)
|
||||
|
||||
set(${out_var}_OBJS "${result}" PARENT_SCOPE)
|
||||
set(${out_var}_INCS "${result_h}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(make_defines in_file out_file)
|
||||
add_custom_command(OUTPUT ${out_file}
|
||||
COMMAND grep "^#define" "${in_file}" > "${out_file}"
|
||||
DEPENDS ${in_file}
|
||||
COMMENT "Creating #defines from ${in_file}"
|
||||
)
|
||||
endfunction()
|
@@ -172,6 +172,17 @@ typedef struct LG_RendererOps
|
||||
const bool newFrame, const bool invalidateWindow,
|
||||
void (*preSwap)(void * udata), void * udata);
|
||||
|
||||
/* called to create a texture from the specified 32-bit RGB image data. This
|
||||
* method is for use with Dear ImGui
|
||||
* Context: renderThread */
|
||||
void * (*createTexture)(LG_Renderer * renderer,
|
||||
int width, int height, uint8_t * data);
|
||||
|
||||
/* called to free a texture previously created by createTexture. This method
|
||||
* is for use with Dear ImGui
|
||||
* Context: renderThread */
|
||||
void (*freeTexture)(LG_Renderer * renderer, void * texture);
|
||||
|
||||
/* setup the spice display */
|
||||
void (*spiceConfigure)(LG_Renderer * renderer, int width, int height);
|
||||
|
||||
|
@@ -27,9 +27,23 @@
|
||||
|
||||
typedef struct ImVec2 ImVec2;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void * tex;
|
||||
int width;
|
||||
int height;
|
||||
}
|
||||
OverlayImage;
|
||||
|
||||
void overlayGetImGuiRect(struct Rect * rect);
|
||||
ImVec2 * overlayGetScreenSize(void);
|
||||
void overlayTextURL(const char * url, const char * text);
|
||||
void overlayTextMaybeURL(const char * text, bool wrapped);
|
||||
|
||||
// create a texture from a SVG and scale it to fit the supplied width & height
|
||||
bool overlayLoadSVG(const char * data, unsigned int size, OverlayImage * image,
|
||||
int width, int height);
|
||||
|
||||
void overlayFreeImage(OverlayImage * image);
|
||||
|
||||
#endif
|
||||
|
@@ -1210,6 +1210,41 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void * egl_createTexture(LG_Renderer * renderer,
|
||||
int width, int height, uint8_t * data)
|
||||
{
|
||||
GLuint tex;
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGBA,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
data);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return (void*)(intptr_t)tex;
|
||||
}
|
||||
|
||||
static void egl_freeTexture(LG_Renderer * renderer, void * texture)
|
||||
{
|
||||
GLuint tex = (GLuint)(intptr_t)texture;
|
||||
glDeleteTextures(1, &tex);
|
||||
}
|
||||
|
||||
static void egl_spiceConfigure(LG_Renderer * renderer, int width, int height)
|
||||
{
|
||||
struct Inst * this = UPCAST(struct Inst, renderer);
|
||||
@@ -1257,6 +1292,8 @@ struct LG_RendererOps LGR_EGL =
|
||||
.renderStartup = egl_renderStartup,
|
||||
.needsRender = egl_needsRender,
|
||||
.render = egl_render,
|
||||
.createTexture = egl_createTexture,
|
||||
.freeTexture = egl_freeTexture,
|
||||
|
||||
.spiceConfigure = egl_spiceConfigure,
|
||||
.spiceDrawFill = egl_spiceDrawFill,
|
||||
|
@@ -663,6 +663,41 @@ static void renderWait(struct Inst * this)
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
static void * opengl_createTexture(LG_Renderer * renderer,
|
||||
int width, int height, uint8_t * data)
|
||||
{
|
||||
GLuint tex;
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGBA,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
data);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return (void*)(intptr_t)tex;
|
||||
}
|
||||
|
||||
static void opengl_freeTexture(LG_Renderer * renderer, void * texture)
|
||||
{
|
||||
GLuint tex = (GLuint)(intptr_t)texture;
|
||||
glDeleteTextures(1, &tex);
|
||||
}
|
||||
|
||||
static void opengl_spiceConfigure(LG_Renderer * renderer, int width, int height)
|
||||
{
|
||||
struct Inst * this = UPCAST(struct Inst, renderer);
|
||||
@@ -797,6 +832,8 @@ const LG_RendererOps LGR_OpenGL =
|
||||
.renderStartup = opengl_renderStartup,
|
||||
.needsRender = opengl_needsRender,
|
||||
.render = opengl_render,
|
||||
.createTexture = opengl_createTexture,
|
||||
.freeTexture = opengl_freeTexture,
|
||||
|
||||
.spiceConfigure = opengl_spiceConfigure,
|
||||
.spiceDrawFill = opengl_spiceDrawFill,
|
||||
|
@@ -676,7 +676,7 @@ void app_msgBoxClose(MsgBoxHandle handle)
|
||||
|
||||
void app_showRecord(bool show)
|
||||
{
|
||||
overlayRecord_show(show);
|
||||
overlayStatus_set(LG_USER_STATUS_RECORDING, show);
|
||||
}
|
||||
|
||||
KeybindHandle app_registerKeybind(int sc, KeybindFn callback, void * opaque, const char * description)
|
||||
@@ -1072,4 +1072,5 @@ void app_useSpiceDisplay(bool enable)
|
||||
renderQueue_spiceShow(false);
|
||||
purespice_disconnectChannel(PS_CHANNEL_DISPLAY);
|
||||
}
|
||||
overlayStatus_set(LG_USER_STATUS_SPICE, enable);
|
||||
}
|
||||
|
@@ -1725,7 +1725,7 @@ int main(int argc, char * argv[])
|
||||
app_registerOverlay(&LGOverlayGraphs, NULL);
|
||||
app_registerOverlay(&LGOverlayHelp , NULL);
|
||||
app_registerOverlay(&LGOverlayMsg , NULL);
|
||||
app_registerOverlay(&LGOverlayRecord, NULL);
|
||||
app_registerOverlay(&LGOverlayStatus, NULL);
|
||||
|
||||
// early renderer setup for option registration
|
||||
for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i)
|
||||
|
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "interface/overlay.h"
|
||||
#include "cimgui.h"
|
||||
#include "overlay_utils.h"
|
||||
|
||||
#include "common/stringutils.h"
|
||||
|
||||
#include "../main.h"
|
||||
|
||||
static bool recordShow = false;
|
||||
static bool recordToggle = false;
|
||||
static unsigned long long lastTick = 0;
|
||||
|
||||
static bool record_init(void ** udata, const void * params)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void record_free(void * udata)
|
||||
{}
|
||||
|
||||
static int record_render(void * udata, bool interactive, struct Rect * windowRects,
|
||||
int maxRects)
|
||||
{
|
||||
if (!recordShow || !recordToggle)
|
||||
return 0;
|
||||
|
||||
ImVec2 * screen = overlayGetScreenSize();
|
||||
ImDrawList_AddCircleFilled(igGetBackgroundDrawList_Nil(),
|
||||
(ImVec2) { screen->x - 20.0f, 20.0f },
|
||||
5.0f, 0xFF0000FF, 0
|
||||
);
|
||||
|
||||
*windowRects = (struct Rect) {
|
||||
.x = screen->x - 26, .y = 14, .w = 12, .h = 12
|
||||
};
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool record_tick(void * udata, unsigned long long tickCount)
|
||||
{
|
||||
if (tickCount - lastTick >= 25)
|
||||
{
|
||||
recordToggle = !recordToggle;
|
||||
lastTick = tickCount;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct LG_OverlayOps LGOverlayRecord =
|
||||
{
|
||||
.name = "record",
|
||||
.init = record_init,
|
||||
.free = record_free,
|
||||
.render = record_render,
|
||||
.tick = record_tick,
|
||||
};
|
||||
|
||||
void overlayRecord_show(bool show)
|
||||
{
|
||||
if (show == recordShow)
|
||||
return;
|
||||
|
||||
recordShow = show;
|
||||
if (g_state.state != APP_STATE_SHUTDOWN)
|
||||
app_invalidateOverlay(true);
|
||||
}
|
134
client/src/overlay/status.c
Normal file
134
client/src/overlay/status.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "interface/overlay.h"
|
||||
#include "cimgui.h"
|
||||
|
||||
#include "../overlays.h"
|
||||
#include "../main.h"
|
||||
#include "overlay_utils.h"
|
||||
|
||||
#include "resources/status/recording.svg.h"
|
||||
#include "resources/status/spice.svg.h"
|
||||
|
||||
//TODO: Make this user configurable?
|
||||
#define ICON_SIZE 32
|
||||
|
||||
static bool l_state[LG_USER_STATUS_MAX] = { 0 };
|
||||
static OverlayImage l_image[LG_USER_STATUS_MAX] = { 0 };
|
||||
static bool l_recordToggle;
|
||||
|
||||
static bool status_init(void ** udata, const void * params)
|
||||
{
|
||||
overlayLoadSVG(b_status_recording_svg, b_status_recording_svg_size,
|
||||
&l_image[LG_USER_STATUS_RECORDING], ICON_SIZE, ICON_SIZE);
|
||||
|
||||
overlayLoadSVG(b_status_spice_svg, b_status_spice_svg_size,
|
||||
&l_image[LG_USER_STATUS_SPICE], ICON_SIZE, ICON_SIZE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void status_free(void * udata)
|
||||
{
|
||||
for(int i = 0; i < LG_USER_STATUS_MAX; ++i)
|
||||
overlayFreeImage(&l_image[i]);
|
||||
}
|
||||
|
||||
static int status_render(void * udata, bool interactive, struct Rect * windowRects,
|
||||
int maxRects)
|
||||
{
|
||||
const int marginX = 10;
|
||||
const int marginY = 10;
|
||||
const int gapX = 5;
|
||||
|
||||
ImVec2 * screen = overlayGetScreenSize();
|
||||
struct Rect rect = {
|
||||
.x = screen->x - LG_USER_STATUS_MAX * (ICON_SIZE + gapX) - marginX,
|
||||
.y = marginY,
|
||||
.w = LG_USER_STATUS_MAX * (ICON_SIZE + gapX),
|
||||
.h = ICON_SIZE
|
||||
};
|
||||
|
||||
int xPos = screen->x - marginX;
|
||||
for(int i = 0; i < LG_USER_STATUS_MAX; ++i)
|
||||
{
|
||||
OverlayImage * img = &l_image[i];
|
||||
if (!l_state[i] || !img->tex)
|
||||
continue;
|
||||
|
||||
// if the recording indicator is off, don't draw but reserve space
|
||||
if (i == LG_USER_STATUS_RECORDING && !l_recordToggle)
|
||||
goto next;
|
||||
|
||||
ImDrawList_AddImage(
|
||||
igGetBackgroundDrawList_Nil(),
|
||||
img->tex,
|
||||
(ImVec2){
|
||||
xPos,
|
||||
marginY
|
||||
},
|
||||
(ImVec2){
|
||||
xPos - ICON_SIZE,
|
||||
img->height + marginY
|
||||
},
|
||||
(ImVec2){ 0, 0 },
|
||||
(ImVec2){ 1, 1 },
|
||||
0xFFFFFFFF);
|
||||
|
||||
next:
|
||||
xPos -= ICON_SIZE + gapX;
|
||||
}
|
||||
|
||||
*windowRects = rect;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool status_tick(void * udata, unsigned long long tickCount)
|
||||
{
|
||||
static unsigned long long lastTick = 0;
|
||||
|
||||
if (tickCount - lastTick >= 25)
|
||||
{
|
||||
l_recordToggle = !l_recordToggle;
|
||||
lastTick = tickCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct LG_OverlayOps LGOverlayStatus =
|
||||
{
|
||||
.name = "status",
|
||||
.init = status_init,
|
||||
.free = status_free,
|
||||
.render = status_render,
|
||||
.tick = status_tick,
|
||||
};
|
||||
|
||||
void overlayStatus_set(LGUserStatus status, bool value)
|
||||
{
|
||||
if (l_state[status] == value)
|
||||
return;
|
||||
|
||||
l_state[status] = value;
|
||||
app_invalidateOverlay(true);
|
||||
};
|
@@ -26,6 +26,11 @@
|
||||
#include "cimgui.h"
|
||||
#include "main.h"
|
||||
|
||||
#define NANOSVG_IMPLEMENTATION
|
||||
#define NANOSVG_ALL_COLOR_KEYWORDS
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
#include "nanosvgrast.h"
|
||||
|
||||
void overlayGetImGuiRect(struct Rect * rect)
|
||||
{
|
||||
ImVec2 size;
|
||||
@@ -78,3 +83,93 @@ void overlayTextMaybeURL(const char * text, bool wrapped)
|
||||
else
|
||||
igText(text);
|
||||
}
|
||||
|
||||
bool overlayLoadSVG(const char * data, unsigned int size, OverlayImage * image,
|
||||
int width, int height)
|
||||
{
|
||||
image->tex = NULL;
|
||||
|
||||
//nsvgParse alters the data, we need to make a copy and null terminate it
|
||||
char * svg = malloc(size + 1);
|
||||
if (!svg)
|
||||
{
|
||||
DEBUG_ERROR("out of ram");
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(svg, data, size);
|
||||
svg[size] = 0;
|
||||
|
||||
NSVGimage * nvi = nsvgParse(svg, "px", 96.0);
|
||||
if (!nvi)
|
||||
{
|
||||
free(svg);
|
||||
DEBUG_ERROR("nvsgParseFromData failed");
|
||||
goto err;
|
||||
}
|
||||
free(svg);
|
||||
|
||||
NSVGrasterizer * rast = nsvgCreateRasterizer();
|
||||
if (!rast)
|
||||
{
|
||||
DEBUG_ERROR("nsvgCreateRasterizer failed");
|
||||
goto err_image;
|
||||
}
|
||||
|
||||
double srcAspect = nvi->width / nvi->height;
|
||||
double dstAspect = (double)width / (double)height;
|
||||
float scale;
|
||||
if (dstAspect > srcAspect)
|
||||
{
|
||||
image->width = (double)height * srcAspect;
|
||||
image->height = height;
|
||||
scale = (float)image->width / nvi->width;
|
||||
}
|
||||
else
|
||||
{
|
||||
image->width = width;
|
||||
image->height = (double)width / srcAspect;
|
||||
scale = (float)image->height / nvi->height;
|
||||
}
|
||||
|
||||
uint8_t * img = malloc(image->width * image->height * 4);
|
||||
if (!img)
|
||||
{
|
||||
DEBUG_ERROR("out of ram");
|
||||
goto err_rast;
|
||||
}
|
||||
|
||||
nsvgRasterize(rast, nvi,
|
||||
0.0f, 0.0f,
|
||||
scale,
|
||||
img,
|
||||
image->width,
|
||||
image->height,
|
||||
image->width * 4);
|
||||
|
||||
image->tex = RENDERER(createTexture, image->width, image->height, img);
|
||||
free(img);
|
||||
|
||||
if (!image->tex)
|
||||
{
|
||||
DEBUG_ERROR("renderer failed to create the texture");
|
||||
goto err_rast;
|
||||
}
|
||||
|
||||
err_rast:
|
||||
nsvgDeleteRasterizer(rast);
|
||||
|
||||
err_image:
|
||||
nsvgDelete(nvi);
|
||||
|
||||
err:
|
||||
return image->tex != NULL;
|
||||
}
|
||||
|
||||
void overlayFreeImage(OverlayImage * image)
|
||||
{
|
||||
if (!image->tex)
|
||||
return;
|
||||
|
||||
RENDERER(freeTexture, image->tex);
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ extern struct LG_OverlayOps LGOverlayGraphs;
|
||||
extern struct LG_OverlayOps LGOverlayHelp;
|
||||
extern struct LG_OverlayOps LGOverlayConfig;
|
||||
extern struct LG_OverlayOps LGOverlayMsg;
|
||||
extern struct LG_OverlayOps LGOverlayRecord;
|
||||
extern struct LG_OverlayOps LGOverlayStatus;
|
||||
|
||||
void overlayAlert_show(LG_MsgAlert type, const char * fmt, va_list args);
|
||||
|
||||
@@ -56,6 +56,14 @@ void overlayConfig_register(const char * title,
|
||||
void overlayConfig_registerTab(const char * title,
|
||||
void (*callback)(void * udata, int * id), void * udata);
|
||||
|
||||
void overlayRecord_show(bool show);
|
||||
typedef enum LG_UserStatus
|
||||
{
|
||||
LG_USER_STATUS_SPICE,
|
||||
LG_USER_STATUS_RECORDING,
|
||||
LG_USER_STATUS_MAX
|
||||
}
|
||||
LGUserStatus;
|
||||
|
||||
void overlayStatus_set(LGUserStatus, bool value);
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user