gs_device::gs_device(gs_init_data *data)
	: curRenderTarget      (NULL),
	  curZStencilBuffer    (NULL),
	  curRenderSide        (0),
	  curIndexBuffer       (NULL),
	  curVertexBuffer      (NULL),
	  curVertexShader      (NULL),
	  curPixelShader       (NULL),
	  curSwapChain         (&defaultSwap),
	  zstencilStateChanged (true),
	  rasterStateChanged   (true),
	  blendStateChanged    (true),
	  curDepthStencilState (NULL),
	  curRasterState       (NULL),
	  curBlendState        (NULL),
	  curToplogy           (D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED)
{
	ComPtr<IDXGIAdapter1> adapter;

	matrix4_identity(&curProjMatrix);
	matrix4_identity(&curViewMatrix);
	matrix4_identity(&curViewProjMatrix);

	memset(&viewport, 0, sizeof(viewport));

	for (size_t i = 0; i < GS_MAX_TEXTURES; i++) {
		curTextures[i] = NULL;
		curSamplers[i] = NULL;
	}

	InitFactory(data->adapter, adapter.Assign());
	InitDevice(data, adapter);
	device_set_render_target(this, NULL, NULL);
}
示例#2
0
Matrix4 testMatrix4MultipliedConstant2(const Matrix4& a)
{
  return matrix4_for_expression(
    matrix4_multiplied(
      matrix4_identity(a),
      matrix4_identity(g_matrix4_identity)
    )
  );
}
示例#3
0
Matrix4 testMatrix4AffineMultiplied2(const Matrix4& a, const Matrix4& b)
{
  return matrix4_affine_for_expression(
    matrix4_multiplied(
      matrix4_identity(a),
      matrix4_identity(b)
    )
  );
}
示例#4
0
文件: matrix4.c 项目: ifzz/hypatia
/**
 * @ingroup matrix4
 * @brief Multiply a matrix by a matrix, returns the matrix changed
 *
 * @param self the matrix being changed
 * @param mT The matrix being multiplied into self
 * 
 * self = self * mT
 */
HYPAPI matrix4 * matrix4_multiply(matrix4 *self, const matrix4 *mT)
{
	/* mT is the multiplicand */
	
	matrix4 r;
	matrix4_identity(&r);
	
	/* first row */
	r.r00 = self->c00 * mT->c00 + self->c01 * mT->c10 + self->c02 * mT->c20 + self->c03 * mT->c30;
	r.r01 = self->c10 * mT->c00 + self->c11 * mT->c10 + self->c12 * mT->c20 + self->c13 * mT->c30;
	r.r02 = self->c20 * mT->c00 + self->c21 * mT->c10 + self->c22 * mT->c20 + self->c23 * mT->c30;
	r.r03 = self->c30 * mT->c00 + self->c31 * mT->c10 + self->c32 * mT->c20 + self->c33 * mT->c30;
	
	/* second row */
	r.r10 = self->c00 * mT->c01 + self->c01 * mT->c11 + self->c02 * mT->c21 + self->c03 * mT->c31;
	r.r11 = self->c10 * mT->c01 + self->c11 * mT->c11 + self->c12 * mT->c21 + self->c13 * mT->c31;
	r.r12 = self->c20 * mT->c01 + self->c21 * mT->c11 + self->c22 * mT->c21 + self->c23 * mT->c31;
	r.r13 = self->c30 * mT->c01 + self->c31 * mT->c11 + self->c32 * mT->c21 + self->c33 * mT->c31;
	
	/* third row */
	r.r20 = self->c00 * mT->c02 + self->c01 * mT->c12 + self->c02 * mT->c22 + self->c03 * mT->c32;
	r.r21 = self->c10 * mT->c02 + self->c11 * mT->c12 + self->c12 * mT->c22 + self->c13 * mT->c32;
	r.r22 = self->c20 * mT->c02 + self->c21 * mT->c12 + self->c22 * mT->c22 + self->c23 * mT->c32;
	r.r23 = self->c30 * mT->c02 + self->c31 * mT->c12 + self->c32 * mT->c22 + self->c33 * mT->c32;
	
	/* fourth row */
	r.r30 = self->c00 * mT->c03 + self->c01 * mT->c13 + self->c02 * mT->c23 + self->c03 * mT->c33;
	r.r31 = self->c10 * mT->c03 + self->c11 * mT->c13 + self->c12 * mT->c23 + self->c13 * mT->c33;
	r.r32 = self->c20 * mT->c03 + self->c21 * mT->c13 + self->c22 * mT->c23 + self->c23 * mT->c33;
	r.c33 = self->c30 * mT->c03 + self->c31 * mT->c13 + self->c32 * mT->c23 + self->c33 * mT->c33;
	
	matrix4_set(self, &r); /* overwrite/save it */
	
	return self;
}
示例#5
0
文件: matrix4.c 项目: ifzz/hypatia
/**
 * @ingroup matrix4
 * @brief creates a translation matrix.  It's opinionated about what that means.
 *
 */
HYPAPI matrix4 * matrix4_make_transformation_translationv3(matrix4 *self, const vector3 *translation)
{
	matrix4_identity(self);
	
	/* assuming col-major */
	self->m[12] = translation->x;
	self->m[13] = translation->y;
	self->m[14] = translation->z;
	
	return self;
}
示例#6
0
文件: matrix4.c 项目: ifzz/hypatia
/**
 * @ingroup matrix4
 * @brief creates a scaling matrix.  It's opinionated about what that means.
 *
 */
HYPAPI matrix4 * matrix4_make_transformation_scalingv3(matrix4 *self, const vector3 *scale)
{
	matrix4_identity(self);
	
	/* assuming col-major */
	self->m[0] = scale->x;
	self->m[5] = scale->y;
	self->m[10] = scale->z;
	
	return self;
}
示例#7
0
Vector3 testMulti2(const Matrix4& a, const Vector3& b, const Vector3& c)
{
  return vector3_for_expression(
    vector_added(
      point_multiplied(
        vector3_identity(b),
        matrix_transposed(matrix4_identity(a))
      ),
      vector3_identity(c)
    )
  );
}
示例#8
0
Vector3 testMatrixMultiplied2(const Vector3& a, const Matrix4& b)
{
  return vector3_for_expression(
    point_multiplied(
      vector_added(
        vector3_identity(a),
        vector3_literal(Vector3(1, 0, 0))
      ),
      matrix4_identity(b)
    )
  );
}
void OBSBasicPreview::GetStretchHandleData(const vec2 &pos)
{
	OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());

	OBSScene scene = main->GetCurrentScene();
	if (!scene)
		return;

	HandleFindData data(pos, main->previewScale);
	obs_scene_enum_items(scene, FindHandleAtPos, &data);

	stretchItem     = std::move(data.item);
	stretchHandle   = data.handle;

	if (stretchHandle != ItemHandle::None) {
		matrix4 boxTransform;
		vec3    itemUL;
		float   itemRot;

		stretchItemSize = GetItemSize(stretchItem);

		obs_sceneitem_get_box_transform(stretchItem, &boxTransform);
		itemRot = obs_sceneitem_getrot(stretchItem);
		vec3_from_vec4(&itemUL, &boxTransform.t);

		/* build the item space conversion matrices */
		matrix4_identity(&itemToScreen);
		matrix4_rotate_aa4f(&itemToScreen, &itemToScreen,
				0.0f, 0.0f, 1.0f, RAD(itemRot));
		matrix4_translate3f(&itemToScreen, &itemToScreen,
				itemUL.x, itemUL.y, 0.0f);

		matrix4_identity(&screenToItem);
		matrix4_translate3f(&screenToItem, &screenToItem,
				-itemUL.x, -itemUL.y, 0.0f);
		matrix4_rotate_aa4f(&screenToItem, &screenToItem,
				0.0f, 0.0f, 1.0f, RAD(-itemRot));
	}
}
示例#10
0
gs_device::gs_device(const gs_init_data *data)
	: curSwapChain         (&defaultSwap),
	  curToplogy           (D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED)
{
	ComPtr<IDXGIAdapter1> adapter;

	matrix4_identity(&curProjMatrix);
	matrix4_identity(&curViewMatrix);
	matrix4_identity(&curViewProjMatrix);

	memset(&viewport, 0, sizeof(viewport));

	for (size_t i = 0; i < GS_MAX_TEXTURES; i++) {
		curTextures[i] = NULL;
		curSamplers[i] = NULL;
	}

	InitCompiler();
	InitFactory(data->adapter, adapter.Assign());
	InitDevice(data, adapter);
	device_set_render_target(this, NULL, NULL);
}
示例#11
0
文件: matrix4.c 项目: ifzz/hypatia
/**
 * @ingroup matrix4
 * @brief creates a rotation matrix about the z.  It's opinionated about what that means.
 *
 * multiply this matrix by another matrix to rotate the other matrix
 */
HYPAPI matrix4 * matrix4_make_transformation_rotationf_z(matrix4 *m, float angle)
{
	float c = HYP_COS(angle);
	float s = HYP_SIN(angle);
	
	matrix4_identity(m);
	
	/* assuming col-major */
	m->r00 = c;
	m->r01 = s;
	m->r10 = -s;
	m->r11 = c;
	
	return m;
}
示例#12
0
static inline void renderVB(gs_effect_t *effect, gs_vertbuffer_t *vb,
		int cx, int cy)
{
	if (!vb)
		return;

	matrix4 transform;
	matrix4_identity(&transform);
	transform.x.x = cx;
	transform.y.y = cy;

	gs_load_vertexbuffer(vb);

	gs_matrix_push();
	gs_matrix_mul(&transform);

	while (gs_effect_loop(effect, "Solid"))
		gs_draw(GS_LINESTRIP, 0, 0);

	gs_matrix_pop();
}
示例#13
0
文件: matrix4.c 项目: ifzz/hypatia
/**
 * @ingroup matrix4
 * @brief converts the quaternion to a 4x4 rotation matrix (column major, right hand rule)
 *
 */
HYPAPI matrix4 * matrix4_make_transformation_rotationq(matrix4 *self, const quaternion *qT)
{
	matrix4 *m;
	const quaternion *q;
	
	q = qT;
	m = self;
	
	matrix4_identity(m);
	
	m->m[0] = 1.0f - 2.0f * (q->y * q->y + q->z * q->z);
	m->m[4] = 2.0f * (q->x * q->y - q->z * q->w);
	m->m[8] = 2.0f * (q->x * q->z + q->y * q->w);
	m->m[1] = 2.0f * (q->x * q->y + q->z * q->w);
	m->m[5] = 1.0f - 2.0f * (q->x * q->x + q->z * q->z);
	m->m[9] = 2.0f * (q->y * q->z - q->x * q->w);
	m->m[2] = 2.0f * (q->x * q->z - q->y * q->w);
	m->m[6] = 2.0f * (q->y * q->z + q->x * q->w);
	m->m[10] = 1.0f - 2.0f * (q->x * q->x + q->y * q->y);
	
	return self;
}
示例#14
0
void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
{
	OBSProjector *window = (OBSProjector *)data;

	if (updatingMultiview || !window->ready)
		return;

	OBSBasic     *main   = (OBSBasic *)obs_frontend_get_main_window();
	uint32_t     targetCX, targetCY;
	int          x, y;
	float        scale;

	targetCX = (uint32_t)window->fw;
	targetCY = (uint32_t)window->fh;

	GetScaleAndCenterPos(targetCX, targetCY, cx, cy, x, y, scale);

	OBSSource previewSrc = main->GetCurrentSceneSource();
	OBSSource programSrc = main->GetProgramSource();
	bool studioMode = main->IsPreviewProgramMode();

	auto renderVB = [&](gs_vertbuffer_t *vb, int cx, int cy,
			uint32_t colorVal)
	{
		if (!vb)
			return;

		matrix4 transform;
		matrix4_identity(&transform);
		transform.x.x = cx;
		transform.y.y = cy;

		gs_load_vertexbuffer(vb);

		gs_matrix_push();
		gs_matrix_mul(&transform);

		gs_effect_set_color(window->color, colorVal);
		while (gs_effect_loop(window->solid, "Solid"))
			gs_draw(GS_LINESTRIP, 0, 0);

		gs_matrix_pop();
	};

	auto drawBox = [&](float cx, float cy, uint32_t colorVal)
	{
		gs_effect_set_color(window->color, colorVal);
		while (gs_effect_loop(window->solid, "Solid"))
			gs_draw_sprite(nullptr, 0, (uint32_t)cx, (uint32_t)cy);
	};

	auto setRegion = [&](float bx, float by, float cx,
			float cy)
	{
		float vX  = int(x + bx * scale);
		float vY  = int(y + by * scale);
		float vCX = int(cx * scale);
		float vCY = int(cy * scale);

		float oL = bx;
		float oT = by;
		float oR = (bx + cx);
		float oB = (by + cy);

		startRegion(vX, vY, vCX, vCY, oL, oR, oT, oB);
	};

	auto calcBaseSource = [&](size_t i)
	{
		switch (multiviewLayout) {
		case MultiviewLayout::HORIZONTAL_TOP_24_SCENES:
			window->sourceX = (i % 6) * window->scenesCX;
			window->sourceY = window->pvwprgCY +
					(i / 6) * window->scenesCY;
			break;
		case MultiviewLayout::VERTICAL_LEFT_8_SCENES:
			window->sourceX = window->pvwprgCX;
			window->sourceY = (i / 2 ) * window->scenesCY;
			if (i % 2 != 0)
				window->sourceX += window->scenesCX;
			break;
		case MultiviewLayout::VERTICAL_RIGHT_8_SCENES:
			window->sourceX = 0;
			window->sourceY = (i / 2 ) * window->scenesCY;
			if (i % 2 != 0)
				window->sourceX = window->scenesCX;
			break;
		case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES:
			if (i < 4) {
				window->sourceX = (float(i) * window->scenesCX);
				window->sourceY = 0;
			} else {
				window->sourceX = (float(i - 4) *
						window->scenesCX);
				window->sourceY = window->scenesCY;
			}
			break;
		default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES:
			if (i < 4) {
				window->sourceX = (float(i) * window->scenesCX);
				window->sourceY = window->pvwprgCY;
			} else {
				window->sourceX = (float(i - 4) *
						window->scenesCX);
				window->sourceY = window->pvwprgCY +
						window->scenesCY;
			}
		}
		window->siX = window->sourceX + window->thickness;
		window->siY = window->sourceY + window->thickness;
	};

	auto calcPreviewProgram = [&](bool program)
	{
		switch (multiviewLayout) {
		case MultiviewLayout::HORIZONTAL_TOP_24_SCENES:
			window->sourceX = window->thickness +
					window->pvwprgCX / 2;
			window->sourceY = window->thickness;
			window->labelX = window->offset + window->pvwprgCX / 2;
			window->labelY = window->pvwprgCY * 0.85f;
			if (program) {
				window->sourceX += window->pvwprgCX;
				window->labelX += window->pvwprgCX;
			}
			break;
		case MultiviewLayout::VERTICAL_LEFT_8_SCENES:
			window->sourceX = window->thickness;
			window->sourceY = window->pvwprgCY + window->thickness;
			window->labelX = window->offset;
			window->labelY = window->pvwprgCY * 1.85f;
			if (program) {
				window->sourceY = window->thickness;
				window->labelY = window->pvwprgCY * 0.85f;
			}
			break;
		case MultiviewLayout::VERTICAL_RIGHT_8_SCENES:
			window->sourceX = window->pvwprgCX + window->thickness;
			window->sourceY = window->pvwprgCY + window->thickness;
			window->labelX = window->pvwprgCX + window->offset;
			window->labelY = window->pvwprgCY * 1.85f;
			if (program) {
				window->sourceY = window->thickness;
				window->labelY = window->pvwprgCY * 0.85f;
			}
			break;
		case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES:
			window->sourceX = window->thickness;
			window->sourceY = window->pvwprgCY + window->thickness;
			window->labelX = window->offset;
			window->labelY = window->pvwprgCY * 1.85f;
			if (program) {
				window->sourceX += window->pvwprgCX;
				window->labelX += window->pvwprgCX;
			}
			break;
		default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES:
			window->sourceX = window->thickness;
			window->sourceY = window->thickness;
			window->labelX = window->offset;
			window->labelY = window->pvwprgCY * 0.85f;
			if (program) {
				window->sourceX += window->pvwprgCX;
				window->labelX += window->pvwprgCX;
			}
		}
	};

	auto paintAreaWithColor = [&](float tx, float ty, float cx, float cy,
			uint32_t color)
	{
		gs_matrix_push();
		gs_matrix_translate3f(tx, ty, 0.0f);
		drawBox(cx, cy, color);
		gs_matrix_pop();
	};

	// Define the whole usable region for the multiview
	startRegion(x, y, targetCX * scale, targetCY * scale, 0.0f, window->fw,
			0.0f, window->fh);

	// Change the background color to highlight all sources
	drawBox(window->fw, window->fh, outerColor);

	/* ----------------------------- */
	/* draw sources                  */

	for (size_t i = 0; i < maxSrcs; i++) {
		// Handle all the offsets
		calcBaseSource(i);

		if (i >= numSrcs) {
			// Just paint the background and continue
			paintAreaWithColor(window->sourceX, window->sourceY,
					window->scenesCX, window->scenesCY,
					outerColor);
			paintAreaWithColor(window->siX, window->siY,
					window->siCX, window->siCY,
					backgroundColor);
			continue;
		}

		OBSSource src = OBSGetStrongRef(window->multiviewScenes[i]);

		// We have a source. Now chose the proper highlight color
		uint32_t colorVal = outerColor;
		if (src == programSrc)
			colorVal = programColor;
		else if (src == previewSrc)
			colorVal = studioMode ? previewColor : programColor;

		// Paint the background
		paintAreaWithColor(window->sourceX, window->sourceY,
				window->scenesCX, window->scenesCY, colorVal);
		paintAreaWithColor(window->siX, window->siY, window->siCX,
				window->siCY, backgroundColor);

		/* ----------- */

		// Render the source
		gs_matrix_push();
		gs_matrix_translate3f(window->siX, window->siY, 0.0f);
		gs_matrix_scale3f(window->siScaleX, window->siScaleY, 1.0f);
		setRegion(window->siX, window->siY, window->siCX, window->siCY);
		obs_source_video_render(src);
		endRegion();
		gs_matrix_pop();

		/* ----------- */

		// Render the label
		if (!drawLabel)
			continue;

		obs_source *label = window->multiviewLabels[i + 2];
		if (!label)
			continue;

		window->offset = labelOffset(label, window->scenesCX);

		gs_matrix_push();
		gs_matrix_translate3f(window->sourceX + window->offset,
				(window->scenesCY * 0.85f) + window->sourceY,
				0.0f);
		gs_matrix_scale3f(window->ppiScaleX, window->ppiScaleY, 1.0f);
		drawBox(obs_source_get_width(label),
				obs_source_get_height(label) +
				int(window->sourceY * 0.015f), labelColor);
		obs_source_video_render(label);
		gs_matrix_pop();
	}

	/* ----------------------------- */
	/* draw preview                  */

	obs_source_t *previewLabel = window->multiviewLabels[0];
	window->offset = labelOffset(previewLabel, window->pvwprgCX);
	calcPreviewProgram(false);

	// Paint the background
	paintAreaWithColor(window->sourceX, window->sourceY, window->ppiCX,
			window->ppiCY, backgroundColor);

	// Scale and Draw the preview
	gs_matrix_push();
	gs_matrix_translate3f(window->sourceX, window->sourceY, 0.0f);
	gs_matrix_scale3f(window->ppiScaleX, window->ppiScaleY, 1.0f);
	setRegion(window->sourceX, window->sourceY, window->ppiCX,
			window->ppiCY);
	if (studioMode)
		obs_source_video_render(previewSrc);
	else
		obs_render_main_texture();
	if (drawSafeArea) {
		renderVB(window->actionSafeMargin, targetCX, targetCY,
				outerColor);
		renderVB(window->graphicsSafeMargin, targetCX, targetCY,
				outerColor);
		renderVB(window->fourByThreeSafeMargin, targetCX, targetCY,
				outerColor);
		renderVB(window->leftLine, targetCX, targetCY, outerColor);
		renderVB(window->topLine, targetCX, targetCY, outerColor);
		renderVB(window->rightLine, targetCX, targetCY, outerColor);
	}
	endRegion();
	gs_matrix_pop();

	/* ----------- */

	// Draw the Label
	if (drawLabel) {
		gs_matrix_push();
		gs_matrix_translate3f(window->labelX, window->labelY, 0.0f);
		gs_matrix_scale3f(window->ppiScaleX, window->ppiScaleY, 1.0f);
		drawBox(obs_source_get_width(previewLabel),
				obs_source_get_height(previewLabel) +
				int(window->pvwprgCX * 0.015f), labelColor);
		obs_source_video_render(previewLabel);
		gs_matrix_pop();
	}

	/* ----------------------------- */
	/* draw program                  */

	obs_source_t *programLabel = window->multiviewLabels[1];
	window->offset = labelOffset(programLabel, window->pvwprgCX);
	calcPreviewProgram(true);

	paintAreaWithColor(window->sourceX, window->sourceY, window->ppiCX,
		window->ppiCY, backgroundColor);

	// Scale and Draw the program
	gs_matrix_push();
	gs_matrix_translate3f(window->sourceX, window->sourceY, 0.0f);
	gs_matrix_scale3f(window->ppiScaleX, window->ppiScaleY, 1.0f);
	setRegion(window->sourceX, window->sourceY, window->ppiCX,
			window->ppiCY);
	obs_render_main_texture();
	endRegion();
	gs_matrix_pop();

	/* ----------- */

	// Draw the Label
	if (drawLabel) {
		gs_matrix_push();
		gs_matrix_translate3f(window->labelX, window->labelY, 0.0f);
		gs_matrix_scale3f(window->ppiScaleX, window->ppiScaleY, 1.0f);
		drawBox(obs_source_get_width(programLabel),
				obs_source_get_height(programLabel) +
				int(window->pvwprgCX * 0.015f), labelColor);
		obs_source_video_render(programLabel);
		gs_matrix_pop();
	}

	// Region for future usage with aditional info.
	if (multiviewLayout == MultiviewLayout::HORIZONTAL_TOP_24_SCENES) {
		// Just paint the background for now
		paintAreaWithColor(window->thickness, window->thickness,
				window->siCX, window->siCY * 2 +
				window->thicknessx2, backgroundColor);
		paintAreaWithColor(window->thickness + 2.5 * (
				window->thicknessx2 + window->ppiCX),
				window->thickness, window->siCX,
				window->siCY * 2 + window->thicknessx2,
				backgroundColor);
	}

	endRegion();
}
/*
 * This function is called (see bottom of this file for more details)
 * whenever the OBS filter interface changes. So when the user is messing
 * with a slider this function is called to update the internal settings
 * in OBS, and hence the settings being passed to the CPU/GPU.
 */
static void color_correction_filter_update(void *data, obs_data_t *settings)
{
	struct color_correction_filter_data *filter = data;

	/* Build our Gamma numbers. */
	double gamma = obs_data_get_double(settings, SETTING_GAMMA);
	gamma = (gamma < 0.0) ? (-gamma + 1.0) : (1.0 / (gamma + 1.0));
	vec3_set(&filter->gamma, (float)gamma, (float)gamma, (float)gamma);

	/* Build our contrast number. */
	filter->contrast = (float)obs_data_get_double(settings,
			SETTING_CONTRAST) + 1.0f;
	float one_minus_con = (1.0f - filter->contrast) / 2.0f;

	/* Now let's build our Contrast matrix. */
	filter->con_matrix = (struct matrix4)
	{
		filter->contrast, 0.0f, 0.0f, 0.0f,
		0.0f, filter->contrast, 0.0f, 0.0f,
		0.0f, 0.0f, filter->contrast, 0.0f,
		one_minus_con, one_minus_con, one_minus_con, 1.0f
	};

	/* Build our brightness number. */
	filter->brightness = (float)obs_data_get_double(settings,
			SETTING_BRIGHTNESS);

	/*
	 * Now let's build our Brightness matrix.
	 * Earlier (in the function color_correction_filter_create) we set
	 * this matrix to the identity matrix, so now we only need
	 * to set the 3 variables that have changed.
	 */
	filter->bright_matrix.t.x = filter->brightness;
	filter->bright_matrix.t.y = filter->brightness;
	filter->bright_matrix.t.z = filter->brightness;

	/* Build our Saturation number. */
	filter->saturation = (float)obs_data_get_double(settings,
			SETTING_SATURATION) + 1.0f;

	/* Factor in the selected color weights. */
	float one_minus_sat = (1.0f - filter->saturation) / 3.0f;
	float sat_val = one_minus_sat + filter->saturation;

	/* Now we build our Saturation matrix. */
	filter->sat_matrix = (struct matrix4)
	{
		sat_val, one_minus_sat, one_minus_sat, 0.0f,
		one_minus_sat, sat_val, one_minus_sat, 0.0f,
		one_minus_sat, one_minus_sat, sat_val, 0.0f,
		0.0f, 0.0f, 0.0f, 1.0f
	};

	/* Build our Hue number. */
	filter->hue_shift = (float)obs_data_get_double(settings,
			SETTING_HUESHIFT);

	/* Build our Transparency number. */
	filter->opacity = (float)obs_data_get_int(settings,
			SETTING_OPACITY) * 0.01f;

	/* Hue is the radian of 0 to 360 degrees. */
	float half_angle = 0.5f * (float)(filter->hue_shift / (180.0f / M_PI));

	/* Pseudo-Quaternion To Matrix. */
	float rot_quad1 = root3 * (float)sin(half_angle);
	vec3_set(&filter->rot_quaternion, rot_quad1, rot_quad1,
			rot_quad1);
	filter->rot_quaternion_w = (float)cos(half_angle);

	vec3_mul(&filter->cross, &filter->rot_quaternion,
			&filter->rot_quaternion);
	vec3_mul(&filter->square, &filter->rot_quaternion,
			&filter->rot_quaternion);
	vec3_mulf(&filter->wimag, &filter->rot_quaternion,
			filter->rot_quaternion_w);

	vec3_mulf(&filter->square, &filter->square, 2.0f);
	vec3_sub(&filter->diag, &filter->half_unit, &filter->square);
	vec3_add(&filter->a_line, &filter->cross, &filter->wimag);
	vec3_sub(&filter->b_line, &filter->cross, &filter->wimag);

	/* Now we build our Hue and Opacity matrix. */
	filter->hue_op_matrix = (struct matrix4)
	{
		filter->diag.x * 2.0f,
		filter->b_line.z * 2.0f,
		filter->a_line.y * 2.0f,
		0.0f,

		filter->a_line.z * 2.0f,
		filter->diag.y * 2.0f,
		filter->b_line.x * 2.0f,
		0.0f,

		filter->b_line.y * 2.0f,
		filter->a_line.x * 2.0f,
		filter->diag.z * 2.0f,
		0.0f,

		0.0f, 0.0f, 0.0f, filter->opacity
	};

	/* Now get the overlay color data. */
	uint32_t color = (uint32_t)obs_data_get_int(settings,
			SETTING_COLOR);
	vec4_from_rgba(&filter->color, color);

	/*
	* Now let's build our Color 'overlay' matrix.
	* Earlier (in the function color_correction_filter_create) we set
	* this matrix to the identity matrix, so now we only need
	* to set the 6 variables that have changed.
	*/
	filter->color_matrix.x.x = filter->color.x;
	filter->color_matrix.y.y = filter->color.y;
	filter->color_matrix.z.z = filter->color.z;

	filter->color_matrix.t.x = filter->color.w *
			filter->color.x;
	filter->color_matrix.t.y = filter->color.w *
			filter->color.y;
	filter->color_matrix.t.z = filter->color.w *
			filter->color.z;


	/* First we apply the Contrast & Brightness matrix. */
	matrix4_mul(&filter->final_matrix, &filter->bright_matrix,
			&filter->con_matrix);
	/* Now we apply the Saturation matrix. */
	matrix4_mul(&filter->final_matrix, &filter->final_matrix,
			&filter->sat_matrix);
	/* Next we apply the Hue+Opacity matrix. */
	matrix4_mul(&filter->final_matrix, &filter->final_matrix,
			&filter->hue_op_matrix);
	/* Lastly we apply the Color Wash matrix. */
	matrix4_mul(&filter->final_matrix, &filter->final_matrix,
			&filter->color_matrix);
}

/*
 * Since this is C we have to be careful when destroying/removing items from
 * OBS. Jim has added several useful functions to help keep memory leaks to
 * a minimum, and handle the destruction and construction of these filters.
 */
static void color_correction_filter_destroy(void *data)
{
	struct color_correction_filter_data *filter = data;

	if (filter->effect) {
		obs_enter_graphics();
		gs_effect_destroy(filter->effect);
		obs_leave_graphics();
	}

	bfree(data);
}

/*
 * When you apply a filter OBS creates it, and adds it to the source. OBS also
 * starts rendering it immediately. This function doesn't just 'create' the
 * filter, it also calls the render function (farther below) that contains the
 * actual rendering code.
 */
static void *color_correction_filter_create(obs_data_t *settings,
	obs_source_t *context)
{
	/*
	* Because of limitations of pre-c99 compilers, you can't create an
	* array that doesn't have a known size at compile time. The below
	* function calculates the size needed and allocates memory to
	* handle the source.
	*/
	struct color_correction_filter_data *filter =
		bzalloc(sizeof(struct color_correction_filter_data));

	/*
	 * By default the effect file is stored in the ./data directory that
	 * your filter resides in.
	 */
	char *effect_path = obs_module_file("color_correction_filter.effect");

	filter->context = context;

	/* Set/clear/assign for all necessary vectors. */
	vec3_set(&filter->half_unit, 0.5f, 0.5f, 0.5f);
	matrix4_identity(&filter->bright_matrix);
	matrix4_identity(&filter->color_matrix);

	/* Here we enter the GPU drawing/shader portion of our code. */
	obs_enter_graphics();

	/* Load the shader on the GPU. */
	filter->effect = gs_effect_create_from_file(effect_path, NULL);

	/* If the filter is active pass the parameters to the filter. */
	if (filter->effect) {
		filter->gamma_param = gs_effect_get_param_by_name(
				filter->effect, SETTING_GAMMA);
		filter->final_matrix_param = gs_effect_get_param_by_name(
				filter->effect, "color_matrix");
	}

	obs_leave_graphics();

	bfree(effect_path);

	/*
	 * If the filter has been removed/deactivated, destroy the filter
	 * and exit out so we don't crash OBS by telling it to update
	 * values that don't exist anymore.
	 */
	if (!filter->effect) {
		color_correction_filter_destroy(filter);
		return NULL;
	}

	/*
	 * It's important to call the update function here. If we don't
	 * we could end up with the user controlled sliders and values
	 * updating, but the visuals not updating to match.
	 */
	color_correction_filter_update(filter, settings);
	return filter;
}

/* This is where the actual rendering of the filter takes place. */
static void color_correction_filter_render(void *data, gs_effect_t *effect)
{
	struct color_correction_filter_data *filter = data;

	if (!obs_source_process_filter_begin(filter->context, GS_RGBA,
			OBS_ALLOW_DIRECT_RENDERING))
		return;

	/* Now pass the interface variables to the .effect file. */
	gs_effect_set_vec3(filter->gamma_param, &filter->gamma);
	gs_effect_set_matrix4(filter->final_matrix_param, &filter->final_matrix);

	obs_source_process_filter_end(filter->context, filter->effect, 0, 0);

	UNUSED_PARAMETER(effect);
}

/*
 * This function sets the interface. the types (add_*_Slider), the type of
 * data collected (int), the internal name, user-facing name, minimum,
 * maximum and step values. While a custom interface can be built, for a
 * simple filter like this it's better to use the supplied functions.
 */
static obs_properties_t *color_correction_filter_properties(void *data)
{
	obs_properties_t *props = obs_properties_create();

	obs_properties_add_float_slider(props, SETTING_GAMMA,
			TEXT_GAMMA, -3.0f, 3.0f, 0.01f);

	obs_properties_add_float_slider(props, SETTING_CONTRAST,
			TEXT_CONTRAST, -2.0f, 2.0f, 0.01f);
	obs_properties_add_float_slider(props, SETTING_BRIGHTNESS,
			TEXT_BRIGHTNESS, -1.0f, 1.0f, 0.01f);
	obs_properties_add_float_slider(props, SETTING_SATURATION,
			TEXT_SATURATION, -1.0f, 5.0f, 0.01f);
	obs_properties_add_float_slider(props, SETTING_HUESHIFT,
			TEXT_HUESHIFT, -180.0f, 180.0f, 0.01f);
	obs_properties_add_int_slider(props, SETTING_OPACITY,
			TEXT_OPACITY, 0, 100, 1);

	obs_properties_add_color(props, SETTING_COLOR, TEXT_COLOR);

	UNUSED_PARAMETER(data);
	return props;
}

/*
 * As the functions' namesake, this provides the default settings for any
 * options you wish to provide a default for. Try to select defaults that
 * make sense to the end user, or that don't effect the data.
 * *NOTE* this function is completely optional, as is providing a default
 * for any particular setting.
 */
static void color_correction_filter_defaults(obs_data_t *settings)
{
	obs_data_set_default_double(settings, SETTING_GAMMA, 0.0);
	obs_data_set_default_double(settings, SETTING_CONTRAST, 0.0);
	obs_data_set_default_double(settings, SETTING_BRIGHTNESS, 0.0);
	obs_data_set_default_double(settings,
			SETTING_SATURATION, 0.0);
	obs_data_set_default_double(settings, SETTING_HUESHIFT, 0.0);
	obs_data_set_default_double(settings, SETTING_OPACITY, 100.0);
	obs_data_set_default_int(settings, SETTING_COLOR, 0xFFFFFF);
}

/*
 * So how does OBS keep track of all these plug-ins/filters? How does OBS know
 * which function to call when it needs to update a setting? Or a source? Or
 * what type of source this is?
 *
 * OBS does it through the obs_source_info_struct. Notice how variables are
 * assigned the name of a function? Notice how the function name has the
 * variable name in it? While not mandatory, it helps a ton for you (and those
 * reading your code) to follow this convention.
 */
struct obs_source_info color_filter = {
	.id = "color_filter",
	.type = OBS_SOURCE_TYPE_FILTER,
	.output_flags = OBS_SOURCE_VIDEO,
	.get_name = color_correction_filter_name,
	.create = color_correction_filter_create,
	.destroy = color_correction_filter_destroy,
	.video_render = color_correction_filter_render,
	.update = color_correction_filter_update,
	.get_properties = color_correction_filter_properties,
	.get_defaults = color_correction_filter_defaults
};
示例#16
0
static void update_item_transform(struct obs_scene_item *item)
{
	uint32_t        width         = obs_source_get_width(item->source);
	uint32_t        height        = obs_source_get_height(item->source);
	uint32_t        cx            = calc_cx(item, width);
	uint32_t        cy            = calc_cy(item, height);
	struct vec2     base_origin;
	struct vec2     origin;
	struct vec2     scale         = item->scale;
	struct calldata params;
	uint8_t         stack[128];

	if (os_atomic_load_long(&item->defer_update) > 0)
		return;

	width = cx;
	height = cy;

	vec2_zero(&base_origin);
	vec2_zero(&origin);

	/* ----------------------- */

	if (item->bounds_type != OBS_BOUNDS_NONE) {
		calculate_bounds_data(item, &origin, &scale, &cx, &cy);
	} else {
		cx = (uint32_t)((float)cx * scale.x);
		cy = (uint32_t)((float)cy * scale.y);
	}

	add_alignment(&origin, item->align, (int)cx, (int)cy);

	matrix4_identity(&item->draw_transform);
	matrix4_scale3f(&item->draw_transform, &item->draw_transform,
			scale.x, scale.y, 1.0f);
	matrix4_translate3f(&item->draw_transform, &item->draw_transform,
			-origin.x, -origin.y, 0.0f);
	matrix4_rotate_aa4f(&item->draw_transform, &item->draw_transform,
			0.0f, 0.0f, 1.0f, RAD(item->rot));
	matrix4_translate3f(&item->draw_transform, &item->draw_transform,
			item->pos.x, item->pos.y, 0.0f);

	item->output_scale = scale;

	/* ----------------------- */

	if (item->bounds_type != OBS_BOUNDS_NONE) {
		vec2_copy(&scale, &item->bounds);
	} else {
		scale.x = (float)width  * item->scale.x;
		scale.y = (float)height * item->scale.y;
	}

	add_alignment(&base_origin, item->align, (int)scale.x, (int)scale.y);

	matrix4_identity(&item->box_transform);
	matrix4_scale3f(&item->box_transform, &item->box_transform,
			scale.x, scale.y, 1.0f);
	matrix4_translate3f(&item->box_transform, &item->box_transform,
			-base_origin.x, -base_origin.y, 0.0f);
	matrix4_rotate_aa4f(&item->box_transform, &item->box_transform,
			0.0f, 0.0f, 1.0f, RAD(item->rot));
	matrix4_translate3f(&item->box_transform, &item->box_transform,
			item->pos.x, item->pos.y, 0.0f);

	/* ----------------------- */

	item->last_width  = width;
	item->last_height = height;

	calldata_init_fixed(&params, stack, sizeof(stack));
	calldata_set_ptr(&params, "scene", item->parent);
	calldata_set_ptr(&params, "item", item);
	signal_handler_signal(item->parent->source->context.signals,
			"item_transform", &params);
}
示例#17
0
static void recalculate_transition_matrix(obs_source_t *tr, size_t idx)
{
    obs_source_t *child;
    struct matrix4 mat;
    struct vec2 pos;
    struct vec2 scale;
    float tr_cx = (float)tr->transition_actual_cx;
    float tr_cy = (float)tr->transition_actual_cy;
    float source_cx;
    float source_cy;
    float tr_aspect = tr_cx / tr_cy;
    float source_aspect;
    enum obs_transition_scale_type scale_type = tr->transition_scale_type;

    lock_transition(tr);

    child = tr->transition_sources[idx];
    if (!child) {
        unlock_transition(tr);
        return;
    }

    source_cx = (float)obs_source_get_width(child);
    source_cy = (float)obs_source_get_height(child);
    unlock_transition(tr);

    if (source_cx == 0.0f || source_cy == 0.0f)
        return;

    source_aspect = source_cx / source_cy;

    if (scale_type == OBS_TRANSITION_SCALE_MAX_ONLY) {
        if (source_cx > tr_cx || source_cy > tr_cy) {
            scale_type = OBS_TRANSITION_SCALE_ASPECT;
        } else {
            scale.x = 1.0f;
            scale.y = 1.0f;
        }
    }

    if (scale_type == OBS_TRANSITION_SCALE_ASPECT) {
        bool use_width = tr_aspect < source_aspect;
        scale.x = scale.y = use_width ?
                            tr_cx / source_cx :
                            tr_cy / source_cy;

    } else if (scale_type == OBS_TRANSITION_SCALE_STRETCH) {
        scale.x = tr_cx / source_cx;
        scale.y = tr_cy / source_cy;
    }

    source_cx *= scale.x;
    source_cy *= scale.y;

    vec2_zero(&pos);
    add_alignment(&pos, tr->transition_alignment,
                  (int)(tr_cx - source_cx),
                  (int)(tr_cy - source_cy));

    matrix4_identity(&mat);
    matrix4_scale3f(&mat, &mat, scale.x, scale.y, 1.0f);
    matrix4_translate3f(&mat, &mat, pos.x, pos.y, 0.0f);
    matrix4_copy(&tr->transition_matrices[idx], &mat);
}
示例#18
0
Matrix4 testMatrix4Transposed2(const Matrix4& a)
{
  return matrix4_for_expression( matrix_transposed( matrix4_identity(a) ) );
}