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);
|
|
|
|
|
|
|
|
if (capture->cursor_captured)
|
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);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_effect_t *create_opaque_effect(void)
|
2014-03-05 09:43:14 -08:00
|
|
|
{
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_effect_t *opaque_effect;
|
2014-03-05 09:43:14 -08:00
|
|
|
char *effect_file;
|
|
|
|
char *error_string = NULL;
|
|
|
|
|
(API Change) Refactor module handling
Changed API:
- char *obs_find_plugin_file(const char *sub_path);
Changed to: char *obs_module_file(const char *file);
Cahnge it so you no longer need to specify a sub-path such as:
obs_find_plugin_file("module_name/file.ext")
Instead, now automatically handle the module data path so all you need
to do is:
obs_module_file("file.ext")
- int obs_load_module(const char *name);
Changed to: int obs_open_module(obs_module_t *module,
const char *path,
const char *data_path);
bool obs_init_module(obs_module_t module);
Change the module loading API so that if the front-end chooses, it can
load modules directly from a specified path, and associate a data
directory with it on the spot.
The module will not be initialized immediately; obs_init_module must
be called on the module pointer in order to fully initialize the
module. This is done so a module can be disabled by the front-end if
the it so chooses.
New API:
- void obs_add_module_path(const char *bin, const char *data);
These functions allow you to specify new module search paths to add,
and allow you to search through them, or optionally just load all
modules from them. If the string %module% is included, it will
replace it with the module's name when that string is used as a
lookup. Data paths are now directly added to the module's internal
storage structure, and when obs_find_module_file is used, it will look
up the pointer to the obs_module structure and get its data directory
that way.
Example:
obs_add_module_path("/opt/obs/my-modules/%module%/bin",
"/opt/obs/my-modules/%module%/data");
This would cause it to additionally look for the binary of a
hypthetical module named "foo" at /opt/obs/my-modules/foo/bin/foo.so
(or libfoo.so), and then look for the data in
/opt/obs/my-modules/foo/data.
This gives the front-end more flexibility for handling third-party
plugin modules, or handling all plugin modules in a custom way.
- void obs_find_modules(obs_find_module_callback_t callback, void
*param);
This searches the existing paths for modules and calls the callback
function when any are found. Useful for plugin management and custom
handling of the paths by the front-end if desired.
- void obs_load_all_modules(void);
Search through the paths and both loads and initializes all modules
automatically without custom handling.
- void obs_enum_modules(obs_enum_module_callback_t callback,
void *param);
Enumerates currently opened modules.
2014-07-27 12:00:11 -07:00
|
|
|
effect_file = obs_module_file("opaque.effect");
|
2014-03-05 09:43:14 -08:00
|
|
|
if (!effect_file) {
|
|
|
|
blog(LOG_ERROR, "[create_opaque_effect] Could not find "
|
|
|
|
"opaque effect file");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-08-04 05:48:58 -07:00
|
|
|
obs_enter_graphics();
|
2014-03-05 09:43:14 -08:00
|
|
|
|
2014-08-07 23:42:07 -07:00
|
|
|
opaque_effect = gs_effect_create_from_file(effect_file, &error_string);
|
2014-03-05 09:43:14 -08:00
|
|
|
|
|
|
|
if (!opaque_effect) {
|
|
|
|
if (error_string)
|
|
|
|
blog(LOG_ERROR, "[create_opaque_effect] Failed to "
|
|
|
|
"create opaque effect:\n%s",
|
|
|
|
error_string);
|
|
|
|
else
|
|
|
|
blog(LOG_ERROR, "[create_opaque_effect] Failed to "
|
|
|
|
"create opaque effect");
|
|
|
|
}
|
|
|
|
|
|
|
|
bfree(effect_file);
|
|
|
|
bfree(error_string);
|
|
|
|
|
2014-08-04 05:48:58 -07:00
|
|
|
obs_leave_graphics();
|
2014-03-05 09:43:14 -08:00
|
|
|
|
|
|
|
return opaque_effect;
|
|
|
|
}
|