dc-capture.c 5.6 KB
Newer Older
J
jp9000 已提交
1 2 3 4 5 6 7
#include "dc-capture.h"

#define WIN32_MEAN_AND_LEAN
#include <windows.h>

static inline void init_textures(struct dc_capture *capture)
{
J
jp9000 已提交
8
	for (int i = 0; i < capture->num_textures; i++) {
J
jp9000 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
		if (capture->compatibility)
			capture->textures[i] = gs_create_texture(
					capture->width, capture->height,
					GS_BGRA, 1, NULL, GS_DYNAMIC);
		else
			capture->textures[i] = gs_create_gdi_texture(
					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)
{
J
jp9000 已提交
31 32
	memset(capture, 0, sizeof(struct dc_capture));

J
jp9000 已提交
33 34 35 36 37 38
	capture->x              = x;
	capture->y              = y;
	capture->width          = width;
	capture->height         = height;
	capture->capture_cursor = cursor;

J
jp9000 已提交
39
	obs_enter_graphics();
J
jp9000 已提交
40 41 42 43 44 45 46 47 48

	if (!gs_gdi_texture_available())
		compatibility = true;

	capture->compatibility = compatibility;
	capture->num_textures  = compatibility ? 1 : 2;

	init_textures(capture);

J
jp9000 已提交
49
	obs_leave_graphics();
J
jp9000 已提交
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78

	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);
	}

J
jp9000 已提交
79
	obs_enter_graphics();
J
jp9000 已提交
80

J
jp9000 已提交
81
	for (int i = 0; i < capture->num_textures; i++)
J
jp9000 已提交
82 83
		texture_destroy(capture->textures[i]);

J
jp9000 已提交
84
	obs_leave_graphics();
J
jp9000 已提交
85 86 87 88

	memset(capture, 0, sizeof(struct dc_capture));
}

89
static void draw_cursor(struct dc_capture *capture, HDC hdc, HWND window)
J
jp9000 已提交
90
{
91 92
	HICON      icon;
	ICONINFO   ii;
J
jp9000 已提交
93
	CURSORINFO *ci = &capture->ci;
94
	POINT      win_pos = {capture->x, capture->y};
J
jp9000 已提交
95 96 97 98 99 100 101 102 103 104

	if (!(capture->ci.flags & CURSOR_SHOWING))
		return;

	icon = CopyIcon(capture->ci.hCursor);
	if (!icon)
		return;

	if (GetIconInfo(icon, &ii)) {
		POINT pos;
105 106 107 108 109 110

		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;
J
jp9000 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170

		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
		return texture_get_dc(capture->textures[capture->cur_tex]);
}

static inline void dc_capture_release_dc(struct dc_capture *capture)
{
	if (capture->compatibility) {
		texture_setimage(capture->textures[capture->cur_tex],
				capture->bits, capture->width*4, false);
	} else {
		texture_release_dc(capture->textures[capture->cur_tex]);
	}
}

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)
171
		draw_cursor(capture, hdc, window);
J
jp9000 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184

	dc_capture_release_dc(capture);

	capture->textures_written[capture->cur_tex] = true;
}

static void draw_texture(struct dc_capture *capture, int id, effect_t effect)
{
	texture_t   texture = capture->textures[id];
	technique_t tech    = effect_gettechnique(effect, "Draw");
	eparam_t    image   = effect_getparambyname(effect, "image");
	size_t      passes;

185
	effect_settexture(image, texture);
J
jp9000 已提交
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218

	passes = technique_begin(tech);
	for (size_t i = 0; i < passes; i++) {
		if (technique_beginpass(tech, i)) {
			if (capture->compatibility)
				gs_draw_sprite(texture, GS_FLIP_V, 0, 0);
			else
				gs_draw_sprite(texture, 0, 0, 0);

			technique_endpass(tech);
		}
	}
	technique_end(tech);
}

void dc_capture_render(struct dc_capture *capture, effect_t effect)
{
	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);
}

effect_t create_opaque_effect(void)
{
	effect_t opaque_effect;
	char *effect_file;
	char *error_string = NULL;

J
jp9000 已提交
219
	effect_file = obs_module_file("opaque.effect");
J
jp9000 已提交
220 221 222 223 224 225
	if (!effect_file) {
		blog(LOG_ERROR, "[create_opaque_effect] Could not find "
		                "opaque effect file");
		return false;
	}

J
jp9000 已提交
226
	obs_enter_graphics();
J
jp9000 已提交
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

	opaque_effect = gs_create_effect_from_file(effect_file, &error_string);

	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);

J
jp9000 已提交
243
	obs_leave_graphics();
J
jp9000 已提交
244 245 246

	return opaque_effect;
}