obs-scene.c 9.9 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
static const char *scene_getname(const char *locale)
{
J
jp9000 已提交
34 35
	UNUSED_PARAMETER(locale);
	return "Scene internal source type";
36 37
}

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

J
jp9000 已提交
54
	UNUSED_PARAMETER(settings);
J
jp9000 已提交
55
	return scene;
P
Palana 已提交
56 57 58 59 60

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

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

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

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

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

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

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

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

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
static void scene_enum_sources(void *data,
		obs_source_enum_proc_t enum_callback,
		void *param)
{
	struct obs_scene *scene = data;
	struct obs_scene_item *item;

	pthread_mutex_lock(&scene->mutex);

	item = scene->first_item;
	while (item) {
		struct obs_scene_item *next = item->next;

		obs_sceneitem_addref(item);
		enum_callback(scene->source, item->source, param);
		obs_sceneitem_release(item);

		item = next;
	}

	pthread_mutex_unlock(&scene->mutex);
}

108 109 110 111 112 113 114 115 116
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 已提交
117 118

	item->parent = NULL;
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
}

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

J
jp9000 已提交
137
static void scene_video_render(void *data, effect_t effect)
J
jp9000 已提交
138
{
139 140 141
	struct obs_scene *scene = data;
	struct obs_scene_item *item;

142 143
	pthread_mutex_lock(&scene->mutex);

144
	item = scene->first_item;
J
jp9000 已提交
145

146
	while (item) {
147
		if (obs_source_removed(item->source)) {
148 149 150
			struct obs_scene_item *del_item = item;
			item = item->next;

J
jp9000 已提交
151
			obs_sceneitem_remove(del_item);
152 153 154
			continue;
		}

J
jp9000 已提交
155 156 157 158 159 160
		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);

161
		obs_source_video_render(item->source);
J
jp9000 已提交
162 163

		gs_matrix_pop();
164 165

		item = item->next;
J
jp9000 已提交
166
	}
167 168

	pthread_mutex_unlock(&scene->mutex);
J
jp9000 已提交
169 170 171 172 173 174 175 176

	UNUSED_PARAMETER(effect);
}

static uint32_t scene_getwidth(void *data)
{
	UNUSED_PARAMETER(data);
	return obs->video.base_width;
J
jp9000 已提交
177 178
}

J
jp9000 已提交
179
static uint32_t scene_getheight(void *data)
J
jp9000 已提交
180
{
J
jp9000 已提交
181 182
	UNUSED_PARAMETER(data);
	return obs->video.base_height;
J
jp9000 已提交
183 184
}

J
jp9000 已提交
185
static const struct obs_source_info scene_info =
J
jp9000 已提交
186
{
J
jp9000 已提交
187 188 189 190 191 192 193
	.id           = "scene",
	.type         = OBS_SOURCE_TYPE_SCENE,
	.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW,
	.getname      = scene_getname,
	.create       = scene_create,
	.destroy      = scene_destroy,
	.video_render = scene_video_render,
J
jp9000 已提交
194 195
	.getwidth     = scene_getwidth,
	.getheight    = scene_getheight,
196
	.enum_sources = scene_enum_sources
J
jp9000 已提交
197 198
};

199
obs_scene_t obs_scene_create(const char *name)
J
jp9000 已提交
200
{
201
	struct obs_source *source = bzalloc(sizeof(struct obs_source));
J
jp9000 已提交
202
	struct obs_scene  *scene;
J
jp9000 已提交
203

J
jp9000 已提交
204 205 206 207
	if (!obs_source_init_handlers(source)) {
		bfree(source);
		return NULL;
	}
208

J
jp9000 已提交
209 210
	source->settings = obs_data_create();
	scene = scene_create(source->settings, source);
J
jp9000 已提交
211
	source->data = scene;
212

J
jp9000 已提交
213 214
	assert(scene);
	if (!scene) {
J
jp9000 已提交
215
		obs_data_release(source->settings);
J
jp9000 已提交
216 217 218 219
		bfree(source);
		return NULL;
	}

220 221
	source->name  = bstrdup(name);

J
jp9000 已提交
222
	scene->source = source;
J
jp9000 已提交
223
	obs_source_init(source, &scene_info);
J
jp9000 已提交
224
	memcpy(&source->info, &scene_info, sizeof(struct obs_source_info));
J
jp9000 已提交
225 226 227
	return scene;
}

P
Palana 已提交
228
void obs_scene_addref(obs_scene_t scene)
229
{
P
Palana 已提交
230 231
	if (scene)
		obs_source_addref(scene->source);
232 233
}

P
Palana 已提交
234
void obs_scene_release(obs_scene_t scene)
J
jp9000 已提交
235
{
P
Palana 已提交
236 237
	if (scene)
		obs_source_release(scene->source);
J
jp9000 已提交
238 239
}

240
obs_source_t obs_scene_getsource(obs_scene_t scene)
J
jp9000 已提交
241
{
J
jp9000 已提交
242
	return scene ? scene->source : NULL;
J
jp9000 已提交
243 244
}

245 246
obs_scene_t obs_scene_fromsource(obs_source_t source)
{
J
jp9000 已提交
247
	if (source->info.type != OBS_SOURCE_TYPE_SCENE)
248 249 250 251 252
		return NULL;

	return source->data;
}

253 254 255 256 257 258 259 260
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 已提交
261
		if (strcmp(item->source->name, name) == 0)
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
			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 已提交
282 283 284 285
		struct obs_scene_item *next = item->next;

		obs_sceneitem_addref(item);

286 287 288
		if (!callback(scene, item, param))
			break;

J
jp9000 已提交
289 290 291
		obs_sceneitem_release(item);

		item = next;
292 293 294 295 296
	}

	pthread_mutex_unlock(&scene->mutex);
}

297
obs_sceneitem_t obs_scene_add(obs_scene_t scene, obs_source_t source)
J
jp9000 已提交
298
{
299
	struct obs_scene_item *last;
300
	struct obs_scene_item *item;
J
jp9000 已提交
301
	struct calldata params = {0};
302

303 304 305 306 307 308 309 310 311
	if (!scene)
		return NULL;

	if (!source) {
		blog(LOG_WARNING, "Tried to add a NULL source to a scene");
		return NULL;
	}

	item = bzalloc(sizeof(struct obs_scene_item));
J
jp9000 已提交
312 313 314
	item->source  = source;
	item->visible = true;
	item->parent  = scene;
J
jp9000 已提交
315
	item->ref     = 1;
J
jp9000 已提交
316 317
	vec2_set(&item->scale, 1.0f, 1.0f);

318 319
	obs_source_addref(source);
	obs_source_add_child(scene->source, source);
320

321 322 323 324 325 326 327 328 329 330 331 332
	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 已提交
333

334 335
	pthread_mutex_unlock(&scene->mutex);

J
jp9000 已提交
336 337 338 339 340
	calldata_setptr(&params, "scene", scene);
	calldata_setptr(&params, "item", item);
	signal_handler_signal(scene->source->signals, "add", &params);
	calldata_free(&params);

J
jp9000 已提交
341 342 343
	return item;
}

J
jp9000 已提交
344
static void obs_sceneitem_destroy(obs_sceneitem_t item)
J
jp9000 已提交
345
{
346
	if (item) {
347
		if (item->source)
J
jp9000 已提交
348
			obs_source_release(item->source);
J
jp9000 已提交
349
		bfree(item);
J
jp9000 已提交
350 351 352
	}
}

P
Palana 已提交
353
void obs_sceneitem_addref(obs_sceneitem_t item)
J
jp9000 已提交
354
{
P
Palana 已提交
355 356
	if (item)
		++item->ref;
J
jp9000 已提交
357
}
358

P
Palana 已提交
359
void obs_sceneitem_release(obs_sceneitem_t item)
J
jp9000 已提交
360
{
P
Palana 已提交
361 362
	if (!item)
		return;
P
Palana 已提交
363

P
Palana 已提交
364 365
	if (--item->ref == 0)
		obs_sceneitem_destroy(item);
366 367
}

J
jp9000 已提交
368 369 370 371
void obs_sceneitem_remove(obs_sceneitem_t item)
{
	obs_scene_t scene;

372
	if (!item)
J
jp9000 已提交
373 374
		return;

375
	scene = item->parent;
J
jp9000 已提交
376

377 378
	if (scene)
		pthread_mutex_lock(&scene->mutex);
J
jp9000 已提交
379

J
jp9000 已提交
380
	if (item->removed) {
381 382 383 384 385
		if (scene)
			pthread_mutex_unlock(&scene->mutex);
		return;
	}

J
jp9000 已提交
386 387
	item->removed = true;

388 389
	obs_source_remove_child(scene->source, item->source);

390
	signal_item_remove(item);
J
jp9000 已提交
391
	detach_sceneitem(item);
392

393
	pthread_mutex_unlock(&scene->mutex);
J
jp9000 已提交
394 395 396 397

	obs_sceneitem_release(item);
}

J
jp9000 已提交
398 399 400 401 402
obs_scene_t obs_sceneitem_getscene(obs_sceneitem_t item)
{
	return item->parent;
}

403 404 405
obs_source_t obs_sceneitem_getsource(obs_sceneitem_t item)
{
	return item->source;
J
jp9000 已提交
406 407
}

408
void obs_sceneitem_setpos(obs_sceneitem_t item, const struct vec2 *pos)
J
jp9000 已提交
409 410 411 412
{
	vec2_copy(&item->pos, pos);
}

413
void obs_sceneitem_setrot(obs_sceneitem_t item, float rot)
J
jp9000 已提交
414 415 416 417
{
	item->rot = rot;
}

418
void obs_sceneitem_setorigin(obs_sceneitem_t item, const struct vec2 *origin)
J
jp9000 已提交
419 420 421 422
{
	vec2_copy(&item->origin, origin);
}

423
void obs_sceneitem_setscale(obs_sceneitem_t item, const struct vec2 *scale)
J
jp9000 已提交
424 425 426 427
{
	vec2_copy(&item->scale, scale);
}

428
void obs_sceneitem_setorder(obs_sceneitem_t item, enum order_movement movement)
J
jp9000 已提交
429 430 431
{
	struct obs_scene *scene = item->parent;

J
jp9000 已提交
432
	obs_scene_addref(scene);
433
	pthread_mutex_lock(&scene->mutex);
434 435 436

	detach_sceneitem(item);

J
jp9000 已提交
437
	if (movement == ORDER_MOVE_UP) {
438
		attach_sceneitem(item, item->prev);
J
jp9000 已提交
439 440

	} else if (movement == ORDER_MOVE_DOWN) {
441
		attach_sceneitem(item, item->next);
J
jp9000 已提交
442 443

	} else if (movement == ORDER_MOVE_TOP) {
444 445 446 447 448 449 450
		struct obs_scene_item *last = item->next;
		if (!last) {
			last = item->prev;
		} else {
			while (last->next)
				last = last->next;
		}
J
jp9000 已提交
451

452 453 454 455
		attach_sceneitem(item, last);

	} else if (movement == ORDER_MOVE_BOTTOM) {
		attach_sceneitem(item, NULL);
J
jp9000 已提交
456
	}
457 458

	pthread_mutex_unlock(&scene->mutex);
459
	obs_scene_release(scene);
J
jp9000 已提交
460 461
}

462
void obs_sceneitem_getpos(obs_sceneitem_t item, struct vec2 *pos)
J
jp9000 已提交
463 464 465 466
{
	vec2_copy(pos, &item->pos);
}

467
float obs_sceneitem_getrot(obs_sceneitem_t item)
J
jp9000 已提交
468 469 470 471
{
	return item->rot;
}

472
void obs_sceneitem_getorigin(obs_sceneitem_t item, struct vec2 *origin)
J
jp9000 已提交
473 474 475 476
{
	vec2_copy(origin, &item->origin);
}

477
void obs_sceneitem_getscale(obs_sceneitem_t item, struct vec2 *scale)
J
jp9000 已提交
478 479 480
{
	vec2_copy(scale, &item->scale);
}