Summary: - Prefix all graphics subsystem names with gs_ or GS_ - Unsquish funciton names (for example _setfloat to _set_float) - Changed create functions to be more consistent with the rest of the API elsewhere. For exmaple, instead of gs_create_texture/gs_texture_destroy, it's now gs_texture_create/gs_texture_destroy - Renamed gs_stencil_op enum to gs_stencil_op_type From: To: ----------------------------------------------------------- tvertarray gs_tvertarray vb_data gs_vb_data vbdata_create gs_vbdata_create vbdata_destroy gs_vbdata_destroy shader_param gs_shader_param gs_effect gs_effect effect_technique gs_effect_technique effect_pass gs_effect_pass effect_param gs_effect_param texture_t gs_texture_t stagesurf_t gs_stagesurf_t zstencil_t gs_zstencil_t vertbuffer_t gs_vertbuffer_t indexbuffer_t gs_indexbuffer_t samplerstate_t gs_samplerstate_t swapchain_t gs_swapchain_t texrender_t gs_texrender_t shader_t gs_shader_t sparam_t gs_sparam_t effect_t gs_effect_t technique_t gs_technique_t eparam_t gs_eparam_t device_t gs_device_t graphics_t graphics_t shader_param_type gs_shader_param_type SHADER_PARAM_UNKNOWN GS_SHADER_PARAM_UNKNOWN SHADER_PARAM_BOOL GS_SHADER_PARAM_BOOL SHADER_PARAM_FLOAT GS_SHADER_PARAM_FLOAT SHADER_PARAM_INT GS_SHADER_PARAM_INT SHADER_PARAM_STRING GS_SHADER_PARAM_STRING SHADER_PARAM_VEC2 GS_SHADER_PARAM_VEC2 SHADER_PARAM_VEC3 GS_SHADER_PARAM_VEC3 SHADER_PARAM_VEC4 GS_SHADER_PARAM_VEC4 SHADER_PARAM_MATRIX4X4 GS_SHADER_PARAM_MATRIX4X4 SHADER_PARAM_TEXTURE GS_SHADER_PARAM_TEXTURE shader_param_info gs_shader_param_info shader_type gs_shader_type SHADER_VERTEX GS_SHADER_VERTEX SHADER_PIXEL GS_SHADER_PIXEL shader_destroy gs_shader_destroy shader_numparams gs_shader_get_num_params shader_getparambyidx gs_shader_get_param_by_idx shader_getparambyname gs_shader_get_param_by_name shader_getviewprojmatrix gs_shader_get_viewproj_matrix shader_getworldmatrix gs_shader_get_world_matrix shader_getparaminfo gs_shader_get_param_info shader_setbool gs_shader_set_bool shader_setfloat gs_shader_set_float shader_setint gs_shader_set_int shader_setmatrix3 gs_shader_setmatrix3 shader_setmatrix4 gs_shader_set_matrix4 shader_setvec2 gs_shader_set_vec2 shader_setvec3 gs_shader_set_vec3 shader_setvec4 gs_shader_set_vec4 shader_settexture gs_shader_set_texture shader_setval gs_shader_set_val shader_setdefault gs_shader_set_default effect_property_type gs_effect_property_type EFFECT_NONE GS_EFFECT_NONE EFFECT_BOOL GS_EFFECT_BOOL EFFECT_FLOAT GS_EFFECT_FLOAT EFFECT_COLOR GS_EFFECT_COLOR EFFECT_TEXTURE GS_EFFECT_TEXTURE effect_param_info gs_effect_param_info effect_destroy gs_effect_destroy effect_gettechnique gs_effect_get_technique technique_begin gs_technique_begin technique_end gs_technique_end technique_beginpass gs_technique_begin_pass technique_beginpassbyname gs_technique_begin_pass_by_name technique_endpass gs_technique_end_pass effect_numparams gs_effect_get_num_params effect_getparambyidx gs_effect_get_param_by_idx effect_getparambyname gs_effect_get_param_by_name effect_updateparams gs_effect_update_params effect_getviewprojmatrix gs_effect_get_viewproj_matrix effect_getworldmatrix gs_effect_get_world_matrix effect_getparaminfo gs_effect_get_param_info effect_setbool gs_effect_set_bool effect_setfloat gs_effect_set_float effect_setint gs_effect_set_int effect_setmatrix4 gs_effect_set_matrix4 effect_setvec2 gs_effect_set_vec2 effect_setvec3 gs_effect_set_vec3 effect_setvec4 gs_effect_set_vec4 effect_settexture gs_effect_set_texture effect_setval gs_effect_set_val effect_setdefault gs_effect_set_default texrender_create gs_texrender_create texrender_destroy gs_texrender_destroy texrender_begin gs_texrender_begin texrender_end gs_texrender_end texrender_reset gs_texrender_reset texrender_gettexture gs_texrender_get_texture GS_BUILDMIPMAPS GS_BUILD_MIPMAPS GS_RENDERTARGET GS_RENDER_TARGET gs_device_name gs_get_device_name gs_device_type gs_get_device_type gs_entercontext gs_enter_context gs_leavecontext gs_leave_context gs_getcontext gs_get_context gs_renderstart gs_render_start gs_renderstop gs_render_stop gs_rendersave gs_render_save gs_getinput gs_get_input gs_geteffect gs_get_effect gs_create_effect_from_file gs_effect_create_from_file gs_create_effect gs_effect_create gs_create_vertexshader_from_file gs_vertexshader_create_from_file gs_create_pixelshader_from_file gs_pixelshader_create_from_file gs_create_texture_from_file gs_texture_create_from_file gs_resetviewport gs_reset_viewport gs_set2dmode gs_set_2d_mode gs_set3dmode gs_set_3d_mode gs_create_swapchain gs_swapchain_create gs_getsize gs_get_size gs_getwidth gs_get_width gs_getheight gs_get_height gs_create_texture gs_texture_create gs_create_cubetexture gs_cubetexture_create gs_create_volumetexture gs_voltexture_create gs_create_zstencil gs_zstencil_create gs_create_stagesurface gs_stagesurface_create gs_create_samplerstate gs_samplerstate_create gs_create_vertexshader gs_vertexshader_create gs_create_pixelshader gs_pixelshader_create gs_create_vertexbuffer gs_vertexbuffer_create gs_create_indexbuffer gs_indexbuffer_create gs_gettexturetype gs_get_texture_type gs_load_defaultsamplerstate gs_load_default_samplerstate gs_getvertexshader gs_get_vertex_shader gs_getpixelshader gs_get_pixel_shader gs_getrendertarget gs_get_render_target gs_getzstenciltarget gs_get_zstencil_target gs_setrendertarget gs_set_render_target gs_setcuberendertarget gs_set_cube_render_target gs_beginscene gs_begin_scene gs_draw gs_draw gs_endscene gs_end_scene gs_setcullmode gs_set_cull_mode gs_getcullmode gs_get_cull_mode gs_enable_depthtest gs_enable_depth_test gs_enable_stenciltest gs_enable_stencil_test gs_enable_stencilwrite gs_enable_stencil_write gs_blendfunction gs_blend_function gs_depthfunction gs_depth_function gs_stencilfunction gs_stencil_function gs_stencilop gs_stencil_op gs_setviewport gs_set_viewport gs_getviewport gs_get_viewport gs_setscissorrect gs_set_scissor_rect gs_create_texture_from_iosurface gs_texture_create_from_iosurface gs_create_gdi_texture gs_texture_create_gdi gs_is_compressed_format gs_is_compressed_format gs_num_total_levels gs_get_total_levels texture_setimage gs_texture_set_image cubetexture_setimage gs_cubetexture_set_image swapchain_destroy gs_swapchain_destroy texture_destroy gs_texture_destroy texture_getwidth gs_texture_get_width texture_getheight gs_texture_get_height texture_getcolorformat gs_texture_get_color_format texture_map gs_texture_map texture_unmap gs_texture_unmap texture_isrect gs_texture_is_rect texture_getobj gs_texture_get_obj cubetexture_destroy gs_cubetexture_destroy cubetexture_getsize gs_cubetexture_get_size cubetexture_getcolorformat gs_cubetexture_get_color_format volumetexture_destroy gs_voltexture_destroy volumetexture_getwidth gs_voltexture_get_width volumetexture_getheight gs_voltexture_get_height volumetexture_getdepth gs_voltexture_getdepth volumetexture_getcolorformat gs_voltexture_get_color_format stagesurface_destroy gs_stagesurface_destroy stagesurface_getwidth gs_stagesurface_get_width stagesurface_getheight gs_stagesurface_get_height stagesurface_getcolorformat gs_stagesurface_get_color_format stagesurface_map gs_stagesurface_map stagesurface_unmap gs_stagesurface_unmap zstencil_destroy gs_zstencil_destroy samplerstate_destroy gs_samplerstate_destroy vertexbuffer_destroy gs_vertexbuffer_destroy vertexbuffer_flush gs_vertexbuffer_flush vertexbuffer_getdata gs_vertexbuffer_get_data indexbuffer_destroy gs_indexbuffer_destroy indexbuffer_flush gs_indexbuffer_flush indexbuffer_getdata gs_indexbuffer_get_data indexbuffer_numindices gs_indexbuffer_get_num_indices indexbuffer_gettype gs_indexbuffer_get_type texture_rebind_iosurface gs_texture_rebind_iosurface texture_get_dc gs_texture_get_dc texture_release_dc gs_texture_release_dc
458 lines
9.8 KiB
C++
458 lines
9.8 KiB
C++
#include <glad/glad.h>
|
|
#include <glad/glad_glx.h>
|
|
#include <X11/Xlib.h>
|
|
#include <X11/extensions/Xcomposite.h>
|
|
#include <pthread.h>
|
|
|
|
#include <vector>
|
|
|
|
#include <obs-module.h>
|
|
#include <graphics/vec4.h>
|
|
#include <util/platform.h>
|
|
|
|
#include "xcompcap-main.h"
|
|
#include "xcompcap-helper.h"
|
|
|
|
#define xdisp (XCompcap::disp())
|
|
#define WIN_STRING_DIV "\r\n"
|
|
|
|
bool XCompcapMain::init()
|
|
{
|
|
if (!xdisp) {
|
|
blog(LOG_ERROR, "failed opening display");
|
|
return false;
|
|
}
|
|
|
|
int eventBase, errorBase;
|
|
if (!XCompositeQueryExtension(xdisp, &eventBase, &errorBase)) {
|
|
blog(LOG_ERROR, "Xcomposite extension not supported");
|
|
return false;
|
|
}
|
|
|
|
int major = 0, minor = 2;
|
|
XCompositeQueryVersion(xdisp, &major, &minor);
|
|
|
|
if (major == 0 && minor < 2) {
|
|
blog(LOG_ERROR, "Xcomposite extension is too old: %d.%d < 0.2",
|
|
major, minor);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void XCompcapMain::deinit()
|
|
{
|
|
XCompcap::cleanupDisplay();
|
|
}
|
|
|
|
obs_properties_t XCompcapMain::properties()
|
|
{
|
|
obs_properties_t props = obs_properties_create();
|
|
|
|
obs_property_t wins = obs_properties_add_list(props, "capture_window",
|
|
obs_module_text("Window"),
|
|
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
|
|
|
for (Window win: XCompcap::getTopLevelWindows()) {
|
|
std::string wname = XCompcap::getWindowName(win);
|
|
std::string progpath = XCompcap::getWindowCommand(win);
|
|
std::string winid = std::to_string((long long)win);
|
|
std::string desc =
|
|
(winid + WIN_STRING_DIV + wname +
|
|
WIN_STRING_DIV + progpath);
|
|
|
|
obs_property_list_add_string(wins, wname.c_str(),
|
|
desc.c_str());
|
|
}
|
|
|
|
obs_properties_add_int(props, "cut_top", obs_module_text("CropTop"),
|
|
0, 4096, 1);
|
|
obs_properties_add_int(props, "cut_left", obs_module_text("CropLeft"),
|
|
0, 4096, 1);
|
|
obs_properties_add_int(props, "cut_right", obs_module_text("CropRight"),
|
|
0, 4096, 1);
|
|
obs_properties_add_int(props, "cut_bot", obs_module_text("CropBottom"),
|
|
0, 4096, 1);
|
|
|
|
obs_properties_add_bool(props, "swap_redblue",
|
|
obs_module_text("SwapRedBlue"));
|
|
obs_properties_add_bool(props, "lock_x", obs_module_text("LockX"));
|
|
|
|
return props;
|
|
}
|
|
|
|
void XCompcapMain::defaults(obs_data_t settings)
|
|
{
|
|
obs_data_set_default_string(settings, "capture_window", "");
|
|
obs_data_set_default_int(settings, "cut_top", 0);
|
|
obs_data_set_default_int(settings, "cut_left", 0);
|
|
obs_data_set_default_int(settings, "cut_right", 0);
|
|
obs_data_set_default_int(settings, "cut_bot", 0);
|
|
obs_data_set_default_bool(settings, "swap_redblue", false);
|
|
obs_data_set_default_bool(settings, "lock_x", false);
|
|
}
|
|
|
|
|
|
struct XCompcapMain_private
|
|
{
|
|
XCompcapMain_private()
|
|
:win(0)
|
|
,cut_top(0), cur_cut_top(0)
|
|
,cut_left(0), cur_cut_left(0)
|
|
,cut_right(0), cur_cut_right(0)
|
|
,cut_bot(0), cur_cut_bot(0)
|
|
,inverted(false)
|
|
,width(0),height(0)
|
|
,pixmap(0)
|
|
,glxpixmap(0)
|
|
,tex(0)
|
|
,gltex(0)
|
|
{
|
|
pthread_mutexattr_init(&lockattr);
|
|
pthread_mutexattr_settype(&lockattr, PTHREAD_MUTEX_RECURSIVE);
|
|
|
|
pthread_mutex_init(&lock, &lockattr);
|
|
}
|
|
|
|
~XCompcapMain_private()
|
|
{
|
|
pthread_mutex_destroy(&lock);
|
|
pthread_mutexattr_destroy(&lockattr);
|
|
}
|
|
|
|
obs_source_t source;
|
|
|
|
Window win;
|
|
int cut_top, cur_cut_top;
|
|
int cut_left, cur_cut_left;
|
|
int cut_right, cur_cut_right;
|
|
int cut_bot, cur_cut_bot;
|
|
bool inverted;
|
|
bool swapRedBlue;
|
|
bool lockX;
|
|
|
|
uint32_t width;
|
|
uint32_t height;
|
|
|
|
Pixmap pixmap;
|
|
GLXPixmap glxpixmap;
|
|
gs_texture_t tex;
|
|
gs_texture_t gltex;
|
|
|
|
pthread_mutex_t lock;
|
|
pthread_mutexattr_t lockattr;
|
|
};
|
|
|
|
|
|
XCompcapMain::XCompcapMain(obs_data_t settings, obs_source_t source)
|
|
{
|
|
p = new XCompcapMain_private;
|
|
p->source = source;
|
|
|
|
updateSettings(settings);
|
|
}
|
|
|
|
static void xcc_cleanup(XCompcapMain_private *p);
|
|
|
|
XCompcapMain::~XCompcapMain()
|
|
{
|
|
ObsGsContextHolder obsctx;
|
|
|
|
if (p->tex) {
|
|
gs_texture_destroy(p->tex);
|
|
p->tex = 0;
|
|
}
|
|
|
|
xcc_cleanup(p);
|
|
|
|
delete p;
|
|
}
|
|
|
|
static Window getWindowFromString(std::string wstr)
|
|
{
|
|
if (wstr == "") {
|
|
return XCompcap::getTopLevelWindows().front();
|
|
}
|
|
|
|
if (wstr.substr(0, 4) == "root") {
|
|
int i = std::stoi("0" + wstr.substr(4));
|
|
return RootWindow(xdisp, i);
|
|
}
|
|
|
|
size_t firstMark = wstr.find(WIN_STRING_DIV);
|
|
|
|
if (firstMark == std::string::npos)
|
|
return (Window)std::stol(wstr);
|
|
|
|
std::string widstr = wstr.substr(0, firstMark);
|
|
Window wid = (Window)std::stol(widstr);
|
|
|
|
wstr = wstr.substr(firstMark + strlen(WIN_STRING_DIV));
|
|
|
|
size_t lastMark = wstr.rfind(WIN_STRING_DIV);
|
|
std::string wname = wstr.substr(0, lastMark);
|
|
|
|
Window matchedNameWin = wid;
|
|
for (Window cwin: XCompcap::getTopLevelWindows()) {
|
|
std::string cwinname = XCompcap::getWindowName(cwin);
|
|
|
|
if (cwin == wid && wname == cwinname)
|
|
return wid;
|
|
|
|
if (wname == cwinname)
|
|
matchedNameWin = cwin;
|
|
}
|
|
|
|
return matchedNameWin;
|
|
}
|
|
|
|
static void xcc_cleanup(XCompcapMain_private *p)
|
|
{
|
|
if (p->gltex) {
|
|
gs_texture_destroy(p->gltex);
|
|
p->gltex = 0;
|
|
}
|
|
|
|
if (p->glxpixmap) {
|
|
glXDestroyPixmap(xdisp, p->glxpixmap);
|
|
p->glxpixmap = 0;
|
|
}
|
|
|
|
if (p->pixmap) {
|
|
XFreePixmap(xdisp, p->pixmap);
|
|
p->pixmap = 0;
|
|
}
|
|
|
|
if (p->win) {
|
|
XCompositeUnredirectWindow(xdisp, p->win,
|
|
CompositeRedirectAutomatic);
|
|
XSelectInput(xdisp, p->win, 0);
|
|
p->win = 0;
|
|
}
|
|
}
|
|
|
|
void XCompcapMain::updateSettings(obs_data_t settings)
|
|
{
|
|
PLock lock(&p->lock);
|
|
XErrorLock xlock;
|
|
ObsGsContextHolder obsctx;
|
|
|
|
blog(LOG_DEBUG, "Settings updating");
|
|
|
|
Window prevWin = p->win;
|
|
|
|
xcc_cleanup(p);
|
|
|
|
if (settings) {
|
|
const char *windowName = obs_data_get_string(settings,
|
|
"capture_window");
|
|
|
|
p->win = getWindowFromString(windowName);
|
|
|
|
p->cut_top = obs_data_get_int(settings, "cut_top");
|
|
p->cut_left = obs_data_get_int(settings, "cut_left");
|
|
p->cut_right = obs_data_get_int(settings, "cut_right");
|
|
p->cut_bot = obs_data_get_int(settings, "cut_bot");
|
|
p->lockX = obs_data_get_bool(settings, "lock_x");
|
|
p->swapRedBlue = obs_data_get_bool(settings, "swap_redblue");
|
|
} else {
|
|
p->win = prevWin;
|
|
}
|
|
|
|
xlock.resetError();
|
|
|
|
XCompositeRedirectWindow(xdisp, p->win, CompositeRedirectAutomatic);
|
|
|
|
if (xlock.gotError()) {
|
|
blog(LOG_ERROR, "XCompositeRedirectWindow failed: %s",
|
|
xlock.getErrorText().c_str());
|
|
return;
|
|
}
|
|
|
|
XSelectInput(xdisp, p->win, StructureNotifyMask);
|
|
XSync(xdisp, 0);
|
|
|
|
XWindowAttributes attr;
|
|
if (!XGetWindowAttributes(xdisp, p->win, &attr)) {
|
|
p->win = 0;
|
|
p->width = 0;
|
|
p->height = 0;
|
|
return;
|
|
}
|
|
|
|
gs_color_format cf = GS_RGBA;
|
|
|
|
p->width = attr.width;
|
|
p->height = attr.height;
|
|
|
|
if (p->cut_top + p->cut_bot < (int)p->height) {
|
|
p->cur_cut_top = p->cut_top;
|
|
p->cur_cut_bot = p->cut_bot;
|
|
} else {
|
|
p->cur_cut_top = 0;
|
|
p->cur_cut_bot = 0;
|
|
}
|
|
|
|
if (p->cut_left + p->cut_right < (int)p->width) {
|
|
p->cur_cut_left = p->cut_left;
|
|
p->cur_cut_right = p->cut_right;
|
|
} else {
|
|
p->cur_cut_left = 0;
|
|
p->cur_cut_right = 0;
|
|
}
|
|
|
|
if (p->tex)
|
|
gs_texture_destroy(p->tex);
|
|
|
|
uint8_t *texData = new uint8_t[width() * height() * 4];
|
|
|
|
for (unsigned int i = 0; i < width() * height() * 4; i += 4) {
|
|
texData[i + 0] = p->swapRedBlue ? 0 : 0xFF;
|
|
texData[i + 1] = 0;
|
|
texData[i + 2] = p->swapRedBlue ? 0xFF : 0;
|
|
texData[i + 3] = 0xFF;
|
|
}
|
|
|
|
const uint8_t* texDataArr[] = { texData, 0 };
|
|
|
|
p->tex = gs_texture_create(width(), height(), cf, 1,
|
|
texDataArr, 0);
|
|
|
|
delete[] texData;
|
|
|
|
if (p->swapRedBlue) {
|
|
GLuint tex = *(GLuint*)gs_texture_get_obj(p->tex);
|
|
glBindTexture(GL_TEXTURE_2D, tex);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|
|
|
|
const int attrs[] =
|
|
{
|
|
GLX_BIND_TO_TEXTURE_RGBA_EXT, GL_TRUE,
|
|
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
|
|
GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
|
|
GLX_DOUBLEBUFFER, GL_FALSE,
|
|
None
|
|
};
|
|
|
|
int nelem = 0;
|
|
GLXFBConfig* configs = glXChooseFBConfig(xdisp,
|
|
XCompcap::getRootWindowScreen(attr.root),
|
|
attrs, &nelem);
|
|
|
|
if (nelem <= 0) {
|
|
blog(LOG_ERROR, "no matching fb config found");
|
|
p->win = 0;
|
|
p->height = 0;
|
|
p->width = 0;
|
|
return;
|
|
}
|
|
|
|
glXGetFBConfigAttrib(xdisp, configs[0], GLX_Y_INVERTED_EXT, &nelem);
|
|
p->inverted = nelem != 0;
|
|
|
|
xlock.resetError();
|
|
|
|
p->pixmap = XCompositeNameWindowPixmap(xdisp, p->win);
|
|
|
|
if (xlock.gotError()) {
|
|
blog(LOG_ERROR, "XCompositeNameWindowPixmap failed: %s",
|
|
xlock.getErrorText().c_str());
|
|
p->pixmap = 0;
|
|
XFree(configs);
|
|
return;
|
|
}
|
|
|
|
const int attribs[] =
|
|
{
|
|
GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
|
|
GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
|
|
None
|
|
};
|
|
|
|
p->glxpixmap = glXCreatePixmap(xdisp, configs[0], p->pixmap, attribs);
|
|
|
|
if (xlock.gotError()) {
|
|
blog(LOG_ERROR, "glXCreatePixmap failed: %s",
|
|
xlock.getErrorText().c_str());
|
|
XFreePixmap(xdisp, p->pixmap);
|
|
XFree(configs);
|
|
p->pixmap = 0;
|
|
p->glxpixmap = 0;
|
|
return;
|
|
}
|
|
|
|
XFree(configs);
|
|
|
|
p->gltex = gs_texture_create(p->width, p->height, cf, 1, 0,
|
|
GS_GL_DUMMYTEX);
|
|
|
|
GLuint gltex = *(GLuint*)gs_texture_get_obj(p->gltex);
|
|
glBindTexture(GL_TEXTURE_2D, gltex);
|
|
glXBindTexImageEXT(xdisp, p->glxpixmap, GLX_FRONT_LEFT_EXT, NULL);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
}
|
|
|
|
void XCompcapMain::tick(float seconds)
|
|
{
|
|
UNUSED_PARAMETER(seconds);
|
|
|
|
PLock lock(&p->lock, true);
|
|
|
|
if (!lock.isLocked())
|
|
return;
|
|
|
|
XCompcap::processEvents();
|
|
|
|
if (XCompcap::windowWasReconfigured(p->win))
|
|
updateSettings(0);
|
|
|
|
if (!p->tex || !p->gltex)
|
|
return;
|
|
|
|
obs_enter_graphics();
|
|
|
|
if (p->lockX) {
|
|
XLockDisplay(xdisp);
|
|
XSync(xdisp, 0);
|
|
}
|
|
|
|
gs_copy_texture_region(p->tex, 0, 0, p->gltex, p->cur_cut_left,
|
|
p->cur_cut_top, width(), height());
|
|
|
|
if (p->lockX)
|
|
XUnlockDisplay(xdisp);
|
|
|
|
obs_leave_graphics();
|
|
}
|
|
|
|
void XCompcapMain::render(gs_effect_t effect)
|
|
{
|
|
PLock lock(&p->lock, true);
|
|
|
|
if (!lock.isLocked() || !p->tex)
|
|
return;
|
|
|
|
gs_eparam_t image = gs_effect_get_param_by_name(effect, "image");
|
|
gs_effect_set_texture(image, p->tex);
|
|
|
|
gs_enable_blending(false);
|
|
gs_draw_sprite(p->tex, 0, 0, 0);
|
|
|
|
gs_reset_blend_state();
|
|
}
|
|
|
|
uint32_t XCompcapMain::width()
|
|
{
|
|
return p->width - p->cur_cut_left - p->cur_cut_right;
|
|
}
|
|
|
|
uint32_t XCompcapMain::height()
|
|
{
|
|
return p->height - p->cur_cut_bot - p->cur_cut_top;
|
|
}
|