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;
65
	struct obs_scene_item *item = scene->first_item;
J
jp9000 已提交
66 67

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

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

J
jp9000 已提交
73
		obs_sceneitem_remove(del_item);
74
	}
J
jp9000 已提交
75

J
jp9000 已提交
76 77
	pthread_mutex_unlock(&scene->mutex);

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

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

87 88 89 90 91 92 93 94 95
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 已提交
96 97

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

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

116
static void scene_video_render(void *data)
J
jp9000 已提交
117 118
{
	struct obs_scene *scene = data;
119
	struct obs_scene_item *item = scene->first_item;
J
jp9000 已提交
120

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

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

J
jp9000 已提交
128
			obs_sceneitem_remove(del_item);
129 130 131
			continue;
		}

J
jp9000 已提交
132 133 134 135 136 137
		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);

138
		obs_source_video_render(item->source);
J
jp9000 已提交
139 140

		gs_matrix_pop();
141 142

		item = item->next;
J
jp9000 已提交
143
	}
144 145

	pthread_mutex_unlock(&scene->mutex);
J
jp9000 已提交
146 147
}

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

static const struct source_info scene_info =
{
155
	.id               = "scene",
156
	.getname          = scene_getname,
157 158 159 160 161 162
	.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 已提交
163 164
};

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

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

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

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

187 188 189
	source->name  = bstrdup(name);
	source->type  = SOURCE_SCENE;

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

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

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

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

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

	return source->data;
}

221 222 223 224 225 226 227 228
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 已提交
229
		if (strcmp(item->source->name, name) == 0)
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
			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 已提交
250 251 252 253
		struct obs_scene_item *next = item->next;

		obs_sceneitem_addref(item);

254 255 256
		if (!callback(scene, item, param))
			break;

J
jp9000 已提交
257 258 259
		obs_sceneitem_release(item);

		item = next;
260 261 262 263 264
	}

	pthread_mutex_unlock(&scene->mutex);
}

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

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

278 279 280
	if (source)
		obs_source_addref(source);

281 282 283 284 285 286 287 288 289 290 291 292
	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 已提交
293

294 295
	pthread_mutex_unlock(&scene->mutex);

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

J
jp9000 已提交
301 302 303
	return item;
}

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

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

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

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

328 329 330
	return ref;
}

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

335
	if (!item)
J
jp9000 已提交
336 337
		return;

338
	scene = item->parent;
J
jp9000 已提交
339

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

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

J
jp9000 已提交
349 350
	item->removed = true;

351
	signal_item_remove(item);
J
jp9000 已提交
352
	detach_sceneitem(item);
353 354 355

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

	obs_sceneitem_release(item);
}

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

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

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

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

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

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

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

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

	detach_sceneitem(item);

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

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

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

414 415 416 417
		attach_sceneitem(item, last);

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

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

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

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

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

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