2014-03-05 09:43:14 -08:00
|
|
|
#include "dc-capture.h"
|
|
|
|
|
|
|
|
#define WIN32_MEAN_AND_LEAN
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
static inline void init_textures(struct dc_capture *capture)
|
|
|
|
{
|
2014-03-16 18:26:46 -07:00
|
|
|
for (int i = 0; i < capture->num_textures; i++) {
|
2014-03-05 09:43:14 -08:00
|
|
|
if (capture->compatibility)
|
2014-08-07 23:42:07 -07:00
|
|
|
capture->textures[i] = gs_texture_create(
|
2014-03-05 09:43:14 -08:00
|
|
|
capture->width, capture->height,
|
|
|
|
GS_BGRA, 1, NULL, GS_DYNAMIC);
|
|
|
|
else
|
2014-08-07 23:42:07 -07:00
|
|
|
capture->textures[i] = gs_texture_create_gdi(
|
2014-03-05 09:43:14 -08:00
|
|
|
capture->width, capture->height);
|
|
|
|
|
|
|
|
if (!capture->textures[i]) {
|
|
|
|
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)
|
|
|
|
{
|
2014-03-16 18:26:46 -07:00
|
|
|
memset(capture, 0, sizeof(struct dc_capture));
|
|
|
|
|
2014-03-05 09:43:14 -08:00
|
|
|
capture->x = x;
|
|
|
|
capture->y = y;
|
|
|
|
capture->width = width;
|
|
|
|
capture->height = height;
|
|
|
|
capture->capture_cursor = cursor;
|
|
|
|
|
2014-08-04 05:48:58 -07:00
|
|
|
obs_enter_graphics();
|
2014-03-05 09:43:14 -08:00
|
|
|
|
|
|
|
if (!gs_gdi_texture_available())
|
|
|
|
compatibility = true;
|
|
|
|
|
|
|
|
capture->compatibility = compatibility;
|
|
|
|
capture->num_textures = compatibility ? 1 : 2;
|
|
|
|
|
|
|
|
init_textures(capture);
|
|
|
|
|
2014-08-04 05:48:58 -07:00
|
|
|
obs_leave_graphics();
|
2014-03-05 09:43:14 -08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-08-04 05:48:58 -07:00
|
|
|
obs_enter_graphics();
|
2014-03-05 09:43:14 -08:00
|
|
|
|
2014-03-16 18:26:46 -07:00
|
|
|
for (int i = 0; i < capture->num_textures; i++)
|
2014-08-07 23:42:07 -07:00
|
|
|
gs_texture_destroy(capture->textures[i]);
|
2014-03-05 09:43:14 -08:00
|
|
|
|
2014-08-04 05:48:58 -07:00
|
|
|
obs_leave_graphics();
|
2014-03-05 09:43:14 -08:00
|
|
|
|
|
|
|
memset(capture, 0, sizeof(struct dc_capture));
|
|
|
|
}
|
|
|
|
|
2014-06-14 23:49:35 -07:00
|
|
|
static void draw_cursor(struct dc_capture *capture, HDC hdc, HWND window)
|
2014-03-05 09:43:14 -08:00
|
|
|
{
|
2014-06-14 23:49:35 -07:00
|
|
|
HICON icon;
|
|
|
|
ICONINFO ii;
|
2014-03-05 09:43:14 -08:00
|
|
|
CURSORINFO *ci = &capture->ci;
|
2014-06-14 23:49:35 -07:00
|
|
|
POINT win_pos = {capture->x, capture->y};
|
2014-03-05 09:43:14 -08:00
|
|
|
|
|
|
|
if (!(capture->ci.flags & CURSOR_SHOWING))
|
|
|
|
return;
|
|
|
|
|
|
|
|
icon = CopyIcon(capture->ci.hCursor);
|
|
|
|
if (!icon)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (GetIconInfo(icon, &ii)) {
|
|
|
|
POINT pos;
|
2014-06-14 23:49:35 -07:00
|
|
|
|
|
|
|
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;
|
2014-03-05 09:43:14 -08:00
|
|
|
|
|
|
|
DrawIcon(hdc, pos.x, pos.y, icon);
|
|
|
|
|
|
|
|
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
|
2014-08-07 23:42:07 -07:00
|
|
|
return gs_texture_get_dc(capture->textures[capture->cur_tex]);
|
2014-03-05 09:43:14 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void dc_capture_release_dc(struct dc_capture *capture)
|
|
|
|
{
|
|
|
|
if (capture->compatibility) {
|
2014-08-07 23:42:07 -07:00
|
|
|
gs_texture_set_image(capture->textures[capture->cur_tex],
|
2014-03-05 09:43:14 -08:00
|
|
|
capture->bits, capture->width*4, false);
|
|
|
|
} else {
|
2014-08-07 23:42:07 -07:00
|
|
|
gs_texture_release_dc(capture->textures[capture->cur_tex]);
|
2014-03-05 09:43:14 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (++capture->cur_tex == capture->num_textures)
|
|
|
|
capture->cur_tex = 0;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2017-05-10 14:47:44 -07:00
|
|
|
if (capture->cursor_captured && !capture->cursor_hidden)
|
2014-06-14 23:49:35 -07:00
|
|
|
draw_cursor(capture, hdc, window);
|
2014-03-05 09:43:14 -08:00
|
|
|
|
|
|
|
dc_capture_release_dc(capture);
|
|
|
|
|
|
|
|
capture->textures_written[capture->cur_tex] = true;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
static void draw_texture(struct dc_capture *capture, int id,
|
|
|
|
gs_effect_t *effect)
|
2014-03-05 09:43:14 -08:00
|
|
|
{
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_texture_t *texture = capture->textures[id];
|
|
|
|
gs_technique_t *tech = gs_effect_get_technique(effect, "Draw");
|
|
|
|
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
|
2014-03-05 09:43:14 -08:00
|
|
|
size_t passes;
|
|
|
|
|
2014-08-07 23:42:07 -07:00
|
|
|
gs_effect_set_texture(image, texture);
|
2014-03-05 09:43:14 -08:00
|
|
|
|
2014-08-07 23:42:07 -07:00
|
|
|
passes = gs_technique_begin(tech);
|
2014-03-05 09:43:14 -08:00
|
|
|
for (size_t i = 0; i < passes; i++) {
|
2014-08-07 23:42:07 -07:00
|
|
|
if (gs_technique_begin_pass(tech, i)) {
|
2014-03-05 09:43:14 -08:00
|
|
|
if (capture->compatibility)
|
|
|
|
gs_draw_sprite(texture, GS_FLIP_V, 0, 0);
|
|
|
|
else
|
|
|
|
gs_draw_sprite(texture, 0, 0, 0);
|
|
|
|
|
2014-08-07 23:42:07 -07:00
|
|
|
gs_technique_end_pass(tech);
|
2014-03-05 09:43:14 -08:00
|
|
|
}
|
|
|
|
}
|
2014-08-07 23:42:07 -07:00
|
|
|
gs_technique_end(tech);
|
2014-03-05 09:43:14 -08:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void dc_capture_render(struct dc_capture *capture, gs_effect_t *effect)
|
2014-03-05 09:43:14 -08:00
|
|
|
{
|
|
|
|
int last_tex = (capture->cur_tex > 0) ?
|
|
|
|
capture->cur_tex-1 : capture->num_textures-1;
|
|
|
|
|
|
|
|
if (!capture->valid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (capture->textures_written[last_tex])
|
|
|
|
draw_texture(capture, last_tex, effect);
|
|
|
|
}
|