obs-scene.c 8.3 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 22 23 24 25 26 27 28 29 30
static inline void signal_item_destroy(struct obs_scene_item *item,
		struct calldata *params)
{
	calldata_setptr(params, "scene", item->parent);
	calldata_setptr(params, "item", item);
	signal_handler_signal(item->parent->source->signals, "remove",
			params);
	calldata_clear(params);
}

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

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

	if (pthread_mutex_init(&scene->mutex, NULL) != 0) {
		blog(LOG_ERROR, "scene_create: Couldn't initialize mutex");
		bfree(scene);
		return NULL;
	}
J
jp9000 已提交
48 49 50 51

	return scene;
}

52
static void scene_destroy(void *data)
J
jp9000 已提交
53 54
{
	struct obs_scene *scene = data;
55
	struct obs_scene_item *item = scene->first_item;
J
jp9000 已提交
56
	struct calldata params = {0};
J
jp9000 已提交
57

58 59 60 61
	while (item) {
		struct obs_scene_item *del_item = item;
		item = item->next;

J
jp9000 已提交
62 63
		signal_item_destroy(del_item, &params);

64 65 66
		if (del_item->source)
			obs_source_release(del_item->source);
		bfree(del_item);
67
	}
J
jp9000 已提交
68

J
jp9000 已提交
69
	calldata_free(&params);
70
	pthread_mutex_destroy(&scene->mutex);
J
jp9000 已提交
71 72 73
	bfree(scene);
}

74
static uint32_t scene_get_output_flags(void *data)
J
jp9000 已提交
75
{
76
	return SOURCE_VIDEO;
J
jp9000 已提交
77 78
}

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
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;
}

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

106
static void scene_video_render(void *data)
J
jp9000 已提交
107 108
{
	struct obs_scene *scene = data;
109
	struct obs_scene_item *item = scene->first_item;
J
jp9000 已提交
110

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

113
	while (item) {
114
		if (obs_source_removed(item->source)) {
115 116 117 118
			struct obs_scene_item *del_item = item;
			item = item->next;

			obs_sceneitem_destroy(del_item);
119 120 121
			continue;
		}

J
jp9000 已提交
122 123 124 125 126 127
		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);

128
		obs_source_video_render(item->source);
J
jp9000 已提交
129 130

		gs_matrix_pop();
131 132

		item = item->next;
J
jp9000 已提交
133
	}
134 135

	pthread_mutex_unlock(&scene->mutex);
J
jp9000 已提交
136 137
}

J
jp9000 已提交
138
static uint32_t scene_getsize(void *data)
J
jp9000 已提交
139
{
J
jp9000 已提交
140
	return 0;
J
jp9000 已提交
141 142 143 144
}

static const struct source_info scene_info =
{
145
	.id               = "scene",
146
	.getname          = scene_getname,
147 148 149 150 151 152
	.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 已提交
153 154
};

155
obs_scene_t obs_scene_create(const char *name)
J
jp9000 已提交
156 157
{
	struct obs_source *source = bmalloc(sizeof(struct obs_source));
J
jp9000 已提交
158
	struct obs_scene  *scene;
J
jp9000 已提交
159

160
	memset(source, 0, sizeof(struct obs_source));
J
jp9000 已提交
161 162 163 164
	if (!obs_source_init_handlers(source)) {
		bfree(source);
		return NULL;
	}
165

J
jp9000 已提交
166
	scene = scene_create(NULL, source);
J
jp9000 已提交
167
	source->data = scene;
168

J
jp9000 已提交
169 170
	assert(scene);
	if (!scene) {
J
jp9000 已提交
171 172 173 174
		bfree(source);
		return NULL;
	}

175 176 177
	source->name  = bstrdup(name);
	source->type  = SOURCE_SCENE;

J
jp9000 已提交
178
	scene->source = source;
179
	obs_source_init(source, NULL, &scene_info);
J
jp9000 已提交
180 181 182 183
	memcpy(&source->callbacks, &scene_info, sizeof(struct source_info));
	return scene;
}

184 185 186 187 188 189
int obs_scene_addref(obs_scene_t scene)
{
	return obs_source_addref(scene->source);
}

int obs_scene_release(obs_scene_t scene)
J
jp9000 已提交
190 191
{
	if (scene)
192 193
		return obs_source_release(scene->source);
	return 0;
J
jp9000 已提交
194 195
}

196
obs_source_t obs_scene_getsource(obs_scene_t scene)
J
jp9000 已提交
197 198 199 200
{
	return scene->source;
}

201 202 203 204 205 206 207 208
obs_scene_t obs_scene_fromsource(obs_source_t source)
{
	if (source->type != SOURCE_SCENE)
		return NULL;

	return source->data;
}

209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
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) {
		if (strcmp(item->source->name, name) == 0) {
			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) {
		if (!callback(scene, item, param))
			break;

		item = item->next;
	}

	pthread_mutex_unlock(&scene->mutex);
}

248
obs_sceneitem_t obs_scene_add(obs_scene_t scene, obs_source_t source)
J
jp9000 已提交
249
{
250
	struct obs_scene_item *last;
J
jp9000 已提交
251
	struct obs_scene_item *item = bmalloc(sizeof(struct obs_scene_item));
J
jp9000 已提交
252
	struct calldata params = {0};
253

J
jp9000 已提交
254 255 256 257 258 259
	memset(item, 0, sizeof(struct obs_scene_item));
	item->source  = source;
	item->visible = true;
	item->parent  = scene;
	vec2_set(&item->scale, 1.0f, 1.0f);

260 261 262
	if (source)
		obs_source_addref(source);

263 264 265 266 267 268 269 270 271 272 273 274
	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 已提交
275

276 277
	pthread_mutex_unlock(&scene->mutex);

J
jp9000 已提交
278 279 280 281 282
	calldata_setptr(&params, "scene", scene);
	calldata_setptr(&params, "item", item);
	signal_handler_signal(scene->source->signals, "add", &params);
	calldata_free(&params);

J
jp9000 已提交
283 284 285
	return item;
}

286
int obs_sceneitem_destroy(obs_sceneitem_t item)
J
jp9000 已提交
287
{
288
	int ref = 0;
289

J
jp9000 已提交
290
	if (item) {
J
jp9000 已提交
291 292 293 294
		struct calldata params = {0};
		signal_item_destroy(item, &params);
		calldata_free(&params);

295
		pthread_mutex_lock(&item->parent->mutex);
296
		detach_sceneitem(item);
297 298
		pthread_mutex_unlock(&item->parent->mutex);

299
		if (item->source)
300
			ref = obs_source_release(item->source);
J
jp9000 已提交
301 302
		bfree(item);
	}
303 304 305 306

	return ref;
}

J
jp9000 已提交
307 308 309 310 311
obs_scene_t obs_sceneitem_getscene(obs_sceneitem_t item)
{
	return item->parent;
}

312 313 314
obs_source_t obs_sceneitem_getsource(obs_sceneitem_t item)
{
	return item->source;
J
jp9000 已提交
315 316
}

317
void obs_sceneitem_setpos(obs_sceneitem_t item, const struct vec2 *pos)
J
jp9000 已提交
318 319 320 321
{
	vec2_copy(&item->pos, pos);
}

322
void obs_sceneitem_setrot(obs_sceneitem_t item, float rot)
J
jp9000 已提交
323 324 325 326
{
	item->rot = rot;
}

327
void obs_sceneitem_setorigin(obs_sceneitem_t item, const struct vec2 *origin)
J
jp9000 已提交
328 329 330 331
{
	vec2_copy(&item->origin, origin);
}

332
void obs_sceneitem_setscale(obs_sceneitem_t item, const struct vec2 *scale)
J
jp9000 已提交
333 334 335 336
{
	vec2_copy(&item->scale, scale);
}

337
void obs_sceneitem_setorder(obs_sceneitem_t item, enum order_movement movement)
J
jp9000 已提交
338 339 340
{
	struct obs_scene *scene = item->parent;

341 342 343 344
	pthread_mutex_lock(&scene->mutex);

	detach_sceneitem(item);

J
jp9000 已提交
345
	if (movement == ORDER_MOVE_UP) {
346
		attach_sceneitem(item, item->prev);
J
jp9000 已提交
347 348

	} else if (movement == ORDER_MOVE_DOWN) {
349
		attach_sceneitem(item, item->next);
J
jp9000 已提交
350 351

	} else if (movement == ORDER_MOVE_TOP) {
352 353 354 355 356 357 358
		struct obs_scene_item *last = item->next;
		if (!last) {
			last = item->prev;
		} else {
			while (last->next)
				last = last->next;
		}
J
jp9000 已提交
359

360 361 362 363
		attach_sceneitem(item, last);

	} else if (movement == ORDER_MOVE_BOTTOM) {
		attach_sceneitem(item, NULL);
J
jp9000 已提交
364
	}
365 366

	pthread_mutex_unlock(&scene->mutex);
J
jp9000 已提交
367 368
}

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

374
float obs_sceneitem_getrot(obs_sceneitem_t item)
J
jp9000 已提交
375 376 377 378
{
	return item->rot;
}

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

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