obs-scene.c 9.1 KB
Newer Older
J
jp9000 已提交
1 2 3 4 5
/******************************************************************************
    Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
6
    the Free Software Foundation, either version 2 of the License, or
J
jp9000 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

#include "graphics/math-defs.h"
#include "obs-scene.h"

J
jp9000 已提交
21
static inline void signal_item_remove(struct obs_scene_item *item)
J
jp9000 已提交
22
{
J
jp9000 已提交
23 24 25 26
	struct calldata params = {0};
	calldata_setptr(&params, "scene", item->parent);
	calldata_setptr(&params, "item", item);

J
jp9000 已提交
27
	signal_handler_signal(item->parent->source->signals, "remove",
J
jp9000 已提交
28 29
			&params);
	calldata_free(&params);
J
jp9000 已提交
30 31
}

32 33 34 35 36 37
static const char *scene_getname(const char *locale)
{
	/* TODO: locale lookup of display name */
	return "Scene";
}

38
static void *scene_create(obs_data_t settings, struct obs_source *source)
J
jp9000 已提交
39
{
P
Palana 已提交
40
	pthread_mutexattr_t attr;
J
jp9000 已提交
41
	struct obs_scene *scene = bmalloc(sizeof(struct obs_scene));
42 43 44
	scene->source     = source;
	scene->first_item = NULL;

P
Palana 已提交
45 46 47 48 49
	if (pthread_mutexattr_init(&attr) != 0)
		goto fail;
	if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
		goto fail;
	if (pthread_mutex_init(&scene->mutex, &attr) != 0) {
50
		blog(LOG_ERROR, "scene_create: Couldn't initialize mutex");
P
Palana 已提交
51
		goto fail;
52
	}
J
jp9000 已提交
53 54

	return scene;
P
Palana 已提交
55 56 57 58 59

fail:
	pthread_mutexattr_destroy(&attr);
	bfree(scene);
	return NULL;
J
jp9000 已提交
60 61
}

62
static void scene_destroy(void *data)
J
jp9000 已提交
63 64
{
	struct obs_scene *scene = data;
J
jp9000 已提交
65
	struct obs_scene_item *item;
J
jp9000 已提交
66 67

	pthread_mutex_lock(&scene->mutex);
J
jp9000 已提交
68

J
jp9000 已提交
69 70
	item = scene->first_item;

71 72 73 74
	while (item) {
		struct obs_scene_item *del_item = item;
		item = item->next;

J
jp9000 已提交
75
		obs_sceneitem_remove(del_item);
76
	}
J
jp9000 已提交
77

J
jp9000 已提交
78 79
	pthread_mutex_unlock(&scene->mutex);

80
	pthread_mutex_destroy(&scene->mutex);
J
jp9000 已提交
81 82 83
	bfree(scene);
}

84
static uint32_t scene_get_output_flags(void *data)
J
jp9000 已提交
85
{
86
	return SOURCE_VIDEO;
J
jp9000 已提交
87 88
}

89 90 91 92 93 94 95 96 97
static inline void detach_sceneitem(struct obs_scene_item *item)
{
	if (item->prev)
		item->prev->next = item->next;
	else
		item->parent->first_item = item->next;

	if (item->next)
		item->next->prev = item->prev;
J
jp9000 已提交
98 99

	item->parent = NULL;
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
}

static inline void attach_sceneitem(struct obs_scene_item *item,
		struct obs_scene_item *prev)
{
	item->prev = prev;

	if (prev) {
		item->next = prev->next;
		if (prev->next)
			prev->next->prev = item;
		prev->next = item;
	} else {
		item->next = item->parent->first_item;
		item->parent->first_item = item;
	}
}

118
static void scene_video_render(void *data)
J
jp9000 已提交
119
{
120 121
	pthread_mutex_lock(&scene->mutex);

J
jp9000 已提交
122
	struct obs_scene *scene = data;
123
	struct obs_scene_item *item = scene->first_item;
J
jp9000 已提交
124

125
	while (item) {
126
		if (obs_source_removed(item->source)) {
127 128 129
			struct obs_scene_item *del_item = item;
			item = item->next;

J
jp9000 已提交
130
			obs_sceneitem_remove(del_item);
131 132 133
			continue;
		}

J
jp9000 已提交
134 135 136 137 138 139
		gs_matrix_push();
		gs_matrix_translate3f(item->origin.x, item->origin.y, 0.0f);
		gs_matrix_scale3f(item->scale.x, item->scale.y, 1.0f);
		gs_matrix_rotaa4f(0.0f, 0.0f, 1.0f, RAD(-item->rot));
		gs_matrix_translate3f(-item->pos.x, -item->pos.y, 0.0f);

140
		obs_source_video_render(item->source);
J
jp9000 已提交
141 142

		gs_matrix_pop();
143 144

		item = item->next;
J
jp9000 已提交
145
	}
146 147

	pthread_mutex_unlock(&scene->mutex);
J
jp9000 已提交
148 149
}

J
jp9000 已提交
150
static uint32_t scene_getsize(void *data)
J
jp9000 已提交
151
{
J
jp9000 已提交
152
	return 0;
J
jp9000 已提交
153 154 155 156
}

static const struct source_info scene_info =
{
157
	.id               = "scene",
158
	.getname          = scene_getname,
159 160 161 162 163 164
	.create           = scene_create,
	.destroy          = scene_destroy,
	.get_output_flags = scene_get_output_flags,
	.video_render     = scene_video_render,
	.getwidth         = scene_getsize,
	.getheight        = scene_getsize,
J
jp9000 已提交
165 166
};

167
obs_scene_t obs_scene_create(const char *name)
J
jp9000 已提交
168 169
{
	struct obs_source *source = bmalloc(sizeof(struct obs_source));
J
jp9000 已提交
170
	struct obs_scene  *scene;
J
jp9000 已提交
171

172
	memset(source, 0, sizeof(struct obs_source));
J
jp9000 已提交
173 174 175 176
	if (!obs_source_init_handlers(source)) {
		bfree(source);
		return NULL;
	}
177

J
jp9000 已提交
178 179
	source->settings = obs_data_create();
	scene = scene_create(source->settings, source);
J
jp9000 已提交
180
	source->data = scene;
181

J
jp9000 已提交
182 183
	assert(scene);
	if (!scene) {
J
jp9000 已提交
184
		obs_data_release(source->settings);
J
jp9000 已提交
185 186 187 188
		bfree(source);
		return NULL;
	}

189 190 191
	source->name  = bstrdup(name);
	source->type  = SOURCE_SCENE;

J
jp9000 已提交
192
	scene->source = source;
J
jp9000 已提交
193
	obs_source_init(source, &scene_info);
J
jp9000 已提交
194 195 196 197
	memcpy(&source->callbacks, &scene_info, sizeof(struct source_info));
	return scene;
}

198 199 200 201 202 203
int obs_scene_addref(obs_scene_t scene)
{
	return obs_source_addref(scene->source);
}

int obs_scene_release(obs_scene_t scene)
J
jp9000 已提交
204 205
{
	if (scene)
206 207
		return obs_source_release(scene->source);
	return 0;
J
jp9000 已提交
208 209
}

210
obs_source_t obs_scene_getsource(obs_scene_t scene)
J
jp9000 已提交
211 212 213 214
{
	return scene->source;
}

215 216 217 218 219 220 221 222
obs_scene_t obs_scene_fromsource(obs_source_t source)
{
	if (source->type != SOURCE_SCENE)
		return NULL;

	return source->data;
}

223 224 225 226 227 228 229 230
obs_sceneitem_t obs_scene_findsource(obs_scene_t scene, const char *name)
{
	struct obs_scene_item *item;

	pthread_mutex_lock(&scene->mutex);

	item = scene->first_item;
	while (item) {
J
jp9000 已提交
231
		if (strcmp(item->source->name, name) == 0)
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
			break;

		item = item->next;
	}

	pthread_mutex_unlock(&scene->mutex);

	return item;
}

void obs_scene_enum_items(obs_scene_t scene,
		bool (*callback)(obs_scene_t, obs_sceneitem_t, void*),
		void *param)
{
	struct obs_scene_item *item;

	pthread_mutex_lock(&scene->mutex);

	item = scene->first_item;
	while (item) {
J
jp9000 已提交
252 253 254 255
		struct obs_scene_item *next = item->next;

		obs_sceneitem_addref(item);

256 257 258
		if (!callback(scene, item, param))
			break;

J
jp9000 已提交
259 260 261
		obs_sceneitem_release(item);

		item = next;
262 263 264 265 266
	}

	pthread_mutex_unlock(&scene->mutex);
}

267
obs_sceneitem_t obs_scene_add(obs_scene_t scene, obs_source_t source)
J
jp9000 已提交
268
{
269
	struct obs_scene_item *last;
J
jp9000 已提交
270
	struct obs_scene_item *item = bmalloc(sizeof(struct obs_scene_item));
J
jp9000 已提交
271
	struct calldata params = {0};
272

J
jp9000 已提交
273 274 275 276
	memset(item, 0, sizeof(struct obs_scene_item));
	item->source  = source;
	item->visible = true;
	item->parent  = scene;
J
jp9000 已提交
277
	item->ref     = 1;
J
jp9000 已提交
278 279
	vec2_set(&item->scale, 1.0f, 1.0f);

280 281 282
	if (source)
		obs_source_addref(source);

283 284 285 286 287 288 289 290 291 292 293 294
	pthread_mutex_lock(&scene->mutex);

	last = scene->first_item;
	if (!last) {
		scene->first_item = item;
	} else {
		while (last->next)
			last = last->next;

		last->next = item;
		item->prev = last;
	}
J
jp9000 已提交
295

296 297
	pthread_mutex_unlock(&scene->mutex);

J
jp9000 已提交
298 299 300 301 302
	calldata_setptr(&params, "scene", scene);
	calldata_setptr(&params, "item", item);
	signal_handler_signal(scene->source->signals, "add", &params);
	calldata_free(&params);

J
jp9000 已提交
303 304 305
	return item;
}

J
jp9000 已提交
306
static void obs_sceneitem_destroy(obs_sceneitem_t item)
J
jp9000 已提交
307
{
308
	if (item) {
309
		if (item->source)
J
jp9000 已提交
310
			obs_source_release(item->source);
J
jp9000 已提交
311
		bfree(item);
J
jp9000 已提交
312 313 314 315 316 317 318
	}
}

int obs_sceneitem_addref(obs_sceneitem_t item)
{
	return ++item->ref;
}
319

J
jp9000 已提交
320 321 322 323 324 325 326 327
int obs_sceneitem_release(obs_sceneitem_t item)
{
	int ref = 0;

	if (item ) {
		ref = --item->ref;
		if (!ref)
			obs_sceneitem_destroy(item);
328
	}
P
Palana 已提交
329

330 331 332
	return ref;
}

J
jp9000 已提交
333 334 335 336
void obs_sceneitem_remove(obs_sceneitem_t item)
{
	obs_scene_t scene;

337
	if (!item)
J
jp9000 已提交
338 339
		return;

340
	scene = item->parent;
J
jp9000 已提交
341

342 343
	if (scene)
		pthread_mutex_lock(&scene->mutex);
J
jp9000 已提交
344

J
jp9000 已提交
345
	if (item->removed) {
346 347 348 349 350
		if (scene)
			pthread_mutex_unlock(&scene->mutex);
		return;
	}

J
jp9000 已提交
351 352
	item->removed = true;

353
	signal_item_remove(item);
J
jp9000 已提交
354
	detach_sceneitem(item);
355 356 357

	if (scene)
		pthread_mutex_unlock(&scene->mutex);
J
jp9000 已提交
358 359 360 361

	obs_sceneitem_release(item);
}

J
jp9000 已提交
362 363 364 365 366
obs_scene_t obs_sceneitem_getscene(obs_sceneitem_t item)
{
	return item->parent;
}

367 368 369
obs_source_t obs_sceneitem_getsource(obs_sceneitem_t item)
{
	return item->source;
J
jp9000 已提交
370 371
}

372
void obs_sceneitem_setpos(obs_sceneitem_t item, const struct vec2 *pos)
J
jp9000 已提交
373 374 375 376
{
	vec2_copy(&item->pos, pos);
}

377
void obs_sceneitem_setrot(obs_sceneitem_t item, float rot)
J
jp9000 已提交
378 379 380 381
{
	item->rot = rot;
}

382
void obs_sceneitem_setorigin(obs_sceneitem_t item, const struct vec2 *origin)
J
jp9000 已提交
383 384 385 386
{
	vec2_copy(&item->origin, origin);
}

387
void obs_sceneitem_setscale(obs_sceneitem_t item, const struct vec2 *scale)
J
jp9000 已提交
388 389 390 391
{
	vec2_copy(&item->scale, scale);
}

392
void obs_sceneitem_setorder(obs_sceneitem_t item, enum order_movement movement)
J
jp9000 已提交
393 394 395
{
	struct obs_scene *scene = item->parent;

396
	pthread_mutex_lock(&scene->mutex);
J
jp9000 已提交
397
	obs_scene_addref(scene);
398 399 400

	detach_sceneitem(item);

J
jp9000 已提交
401
	if (movement == ORDER_MOVE_UP) {
402
		attach_sceneitem(item, item->prev);
J
jp9000 已提交
403 404

	} else if (movement == ORDER_MOVE_DOWN) {
405
		attach_sceneitem(item, item->next);
J
jp9000 已提交
406 407

	} else if (movement == ORDER_MOVE_TOP) {
408 409 410 411 412 413 414
		struct obs_scene_item *last = item->next;
		if (!last) {
			last = item->prev;
		} else {
			while (last->next)
				last = last->next;
		}
J
jp9000 已提交
415

416 417 418 419
		attach_sceneitem(item, last);

	} else if (movement == ORDER_MOVE_BOTTOM) {
		attach_sceneitem(item, NULL);
J
jp9000 已提交
420
	}
421

J
jp9000 已提交
422
	obs_scene_release(scene);
423
	pthread_mutex_unlock(&scene->mutex);
J
jp9000 已提交
424 425
}

426
void obs_sceneitem_getpos(obs_sceneitem_t item, struct vec2 *pos)
J
jp9000 已提交
427 428 429 430
{
	vec2_copy(pos, &item->pos);
}

431
float obs_sceneitem_getrot(obs_sceneitem_t item)
J
jp9000 已提交
432 433 434 435
{
	return item->rot;
}

436
void obs_sceneitem_getorigin(obs_sceneitem_t item, struct vec2 *origin)
J
jp9000 已提交
437 438 439 440
{
	vec2_copy(origin, &item->origin);
}

441
void obs_sceneitem_getscale(obs_sceneitem_t item, struct vec2 *scale)
J
jp9000 已提交
442 443 444
{
	vec2_copy(scale, &item->scale);
}