f53df7da64
Code submissions have continually suffered from formatting inconsistencies that constantly have to be addressed. Using clang-format simplifies this by making code formatting more consistent, and allows automation of the code formatting so that maintainers can focus more on the code itself instead of code formatting.
196 lines
4.4 KiB
C
196 lines
4.4 KiB
C
#include "dc-capture.h"
|
|
|
|
#define WIN32_MEAN_AND_LEAN
|
|
#include <windows.h>
|
|
|
|
static inline void init_textures(struct dc_capture *capture)
|
|
{
|
|
if (capture->compatibility)
|
|
capture->texture = gs_texture_create(capture->width,
|
|
capture->height, GS_BGRA,
|
|
1, NULL, GS_DYNAMIC);
|
|
else
|
|
capture->texture =
|
|
gs_texture_create_gdi(capture->width, capture->height);
|
|
|
|
if (!capture->texture) {
|
|
blog(LOG_WARNING, "[dc_capture_init] Failed to "
|
|
"create textures");
|
|
return;
|
|
}
|
|
|
|
capture->valid = true;
|
|
}
|
|
|
|
void dc_capture_init(struct dc_capture *capture, int x, int y, uint32_t width,
|
|
uint32_t height, bool cursor, bool compatibility)
|
|
{
|
|
memset(capture, 0, sizeof(struct dc_capture));
|
|
|
|
capture->x = x;
|
|
capture->y = y;
|
|
capture->width = width;
|
|
capture->height = height;
|
|
capture->capture_cursor = cursor;
|
|
|
|
obs_enter_graphics();
|
|
|
|
if (!gs_gdi_texture_available())
|
|
compatibility = true;
|
|
|
|
capture->compatibility = compatibility;
|
|
|
|
init_textures(capture);
|
|
|
|
obs_leave_graphics();
|
|
|
|
if (!capture->valid)
|
|
return;
|
|
|
|
if (compatibility) {
|
|
BITMAPINFO bi = {0};
|
|
BITMAPINFOHEADER *bih = &bi.bmiHeader;
|
|
bih->biSize = sizeof(BITMAPINFOHEADER);
|
|
bih->biBitCount = 32;
|
|
bih->biWidth = width;
|
|
bih->biHeight = height;
|
|
bih->biPlanes = 1;
|
|
|
|
capture->hdc = CreateCompatibleDC(NULL);
|
|
capture->bmp =
|
|
CreateDIBSection(capture->hdc, &bi, DIB_RGB_COLORS,
|
|
(void **)&capture->bits, NULL, 0);
|
|
capture->old_bmp = SelectObject(capture->hdc, capture->bmp);
|
|
}
|
|
}
|
|
|
|
void dc_capture_free(struct dc_capture *capture)
|
|
{
|
|
if (capture->hdc) {
|
|
SelectObject(capture->hdc, capture->old_bmp);
|
|
DeleteDC(capture->hdc);
|
|
DeleteObject(capture->bmp);
|
|
}
|
|
|
|
obs_enter_graphics();
|
|
gs_texture_destroy(capture->texture);
|
|
obs_leave_graphics();
|
|
|
|
memset(capture, 0, sizeof(struct dc_capture));
|
|
}
|
|
|
|
static void draw_cursor(struct dc_capture *capture, HDC hdc, HWND window)
|
|
{
|
|
HICON icon;
|
|
ICONINFO ii;
|
|
CURSORINFO *ci = &capture->ci;
|
|
POINT win_pos = {capture->x, capture->y};
|
|
|
|
if (!(capture->ci.flags & CURSOR_SHOWING))
|
|
return;
|
|
|
|
icon = CopyIcon(capture->ci.hCursor);
|
|
if (!icon)
|
|
return;
|
|
|
|
if (GetIconInfo(icon, &ii)) {
|
|
POINT pos;
|
|
|
|
if (window)
|
|
ClientToScreen(window, &win_pos);
|
|
|
|
pos.x = ci->ptScreenPos.x - (int)ii.xHotspot - win_pos.x;
|
|
pos.y = ci->ptScreenPos.y - (int)ii.yHotspot - win_pos.y;
|
|
|
|
DrawIconEx(hdc, pos.x, pos.y, icon, 0, 0, 0, NULL, DI_NORMAL);
|
|
|
|
DeleteObject(ii.hbmColor);
|
|
DeleteObject(ii.hbmMask);
|
|
}
|
|
|
|
DestroyIcon(icon);
|
|
}
|
|
|
|
static inline HDC dc_capture_get_dc(struct dc_capture *capture)
|
|
{
|
|
if (!capture->valid)
|
|
return NULL;
|
|
|
|
if (capture->compatibility)
|
|
return capture->hdc;
|
|
else
|
|
return gs_texture_get_dc(capture->texture);
|
|
}
|
|
|
|
static inline void dc_capture_release_dc(struct dc_capture *capture)
|
|
{
|
|
if (capture->compatibility) {
|
|
gs_texture_set_image(capture->texture, capture->bits,
|
|
capture->width * 4, false);
|
|
} else {
|
|
gs_texture_release_dc(capture->texture);
|
|
}
|
|
}
|
|
|
|
void dc_capture_capture(struct dc_capture *capture, HWND window)
|
|
{
|
|
HDC hdc_target;
|
|
HDC hdc;
|
|
|
|
if (capture->capture_cursor) {
|
|
memset(&capture->ci, 0, sizeof(CURSORINFO));
|
|
capture->ci.cbSize = sizeof(CURSORINFO);
|
|
capture->cursor_captured = GetCursorInfo(&capture->ci);
|
|
}
|
|
|
|
hdc = dc_capture_get_dc(capture);
|
|
if (!hdc) {
|
|
blog(LOG_WARNING, "[capture_screen] Failed to get "
|
|
"texture DC");
|
|
return;
|
|
}
|
|
|
|
hdc_target = GetDC(window);
|
|
|
|
BitBlt(hdc, 0, 0, capture->width, capture->height, hdc_target,
|
|
capture->x, capture->y, SRCCOPY);
|
|
|
|
ReleaseDC(NULL, hdc_target);
|
|
|
|
if (capture->cursor_captured && !capture->cursor_hidden)
|
|
draw_cursor(capture, hdc, window);
|
|
|
|
dc_capture_release_dc(capture);
|
|
|
|
capture->texture_written = true;
|
|
}
|
|
|
|
static void draw_texture(struct dc_capture *capture, gs_effect_t *effect)
|
|
{
|
|
gs_texture_t *texture = capture->texture;
|
|
gs_technique_t *tech = gs_effect_get_technique(effect, "Draw");
|
|
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
|
|
size_t passes;
|
|
|
|
gs_effect_set_texture(image, texture);
|
|
|
|
passes = gs_technique_begin(tech);
|
|
for (size_t i = 0; i < passes; i++) {
|
|
if (gs_technique_begin_pass(tech, i)) {
|
|
if (capture->compatibility)
|
|
gs_draw_sprite(texture, GS_FLIP_V, 0, 0);
|
|
else
|
|
gs_draw_sprite(texture, 0, 0, 0);
|
|
|
|
gs_technique_end_pass(tech);
|
|
}
|
|
}
|
|
gs_technique_end(tech);
|
|
}
|
|
|
|
void dc_capture_render(struct dc_capture *capture, gs_effect_t *effect)
|
|
{
|
|
if (capture->valid && capture->texture_written)
|
|
draw_texture(capture, effect);
|
|
}
|