void Playback3D::overlay_sync(Playback3DCommand *command)
{
#ifdef HAVE_GL
	command->canvas->lock_canvas("Playback3D::overlay_sync");
	if(command->canvas->get_canvas())
	{
		BC_WindowBase *window = command->canvas->get_canvas();
	    window->lock_window("Playback3D::overlay_sync");
// Make sure OpenGL is enabled first.
		window->enable_opengl();

		window->update_video_cursor();


// Render to PBuffer
		if(command->frame)
		{
			command->frame->enable_opengl();
			command->frame->set_opengl_state(VFrame::SCREEN);
			canvas_w = command->frame->get_w();
			canvas_h = command->frame->get_h();
		}
		else
// Render to canvas
		{
			canvas_w = window->get_w();
			canvas_h = window->get_h();
		}

		glColor4f(1, 1, 1, 1);

//printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
		switch(command->input->get_opengl_state())
		{
// Upload texture and composite to screen
			case VFrame::RAM:
				command->input->to_texture();
				break;
// Just composite texture to screen
			case VFrame::TEXTURE:
				break;
// read from PBuffer to texture, then composite texture to screen
			case VFrame::SCREEN:
				command->input->enable_opengl();
				command->input->screen_to_texture();
				if(command->frame)
					command->frame->enable_opengl();
				else
					window->enable_opengl();
				break;
			default:
				printf("Playback3D::overlay_sync unknown state\n");
				break;
		}


		const char *shader_stack[3] = { 0, 0, 0 };
		int total_shaders = 0;

		VFrame::init_screen(canvas_w, canvas_h);

// Enable texture
		command->input->bind_texture(0);

// Convert colormodel to RGB if not nested.
// The color model setting in the output frame is ignored.
		if(!command->is_nested)
		{
			switch(command->input->get_color_model())
			{
				case BC_YUV888:
				case BC_YUVA8888:
					shader_stack[total_shaders++] = yuv_to_rgb_frag;
					break;
			}
		}

// Change blend operation
		switch(command->mode)
		{
			case TRANSFER_NORMAL:
				glEnable(GL_BLEND);
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				break;

			case TRANSFER_REPLACE:
// This requires overlaying an alpha multiplied image on a black screen.
				glDisable(GL_BLEND);
				if(command->input->get_texture_components() == 4)
				{
					if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
					shader_stack[total_shaders++] = multiply_alpha_frag;
				}
				break;

// To do these operations, we need to copy the input buffer to a texture
// and blend 2 textures in another shader
			case TRANSFER_ADDITION:
				enable_overlay_texture(command);
				if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
				shader_stack[total_shaders++] = blend_add_frag;
				break;
			case TRANSFER_SUBTRACT:
				enable_overlay_texture(command);
				if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
				shader_stack[total_shaders++] = blend_subtract_frag;
				break;
			case TRANSFER_MULTIPLY:
				enable_overlay_texture(command);
				if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
				shader_stack[total_shaders++] = blend_multiply_frag;
				break;
			case TRANSFER_MAX:
				enable_overlay_texture(command);
				if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
				shader_stack[total_shaders++] = blend_max_frag;
				break;
			case TRANSFER_MIN:
				enable_overlay_texture(command);
				if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
				shader_stack[total_shaders++] = blend_min_frag;
				break;
			case TRANSFER_DIVIDE:
				enable_overlay_texture(command);
				if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
				shader_stack[total_shaders++] = blend_divide_frag;
				break;
		}

		unsigned int frag_shader = 0;
		if(shader_stack[0]) 
		{
			frag_shader = VFrame::make_shader(0,
				shader_stack[0],
				shader_stack[1],
				0);

			glUseProgram(frag_shader);


// Set texture unit of the texture
			glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
// Set texture unit of the temp texture
			glUniform1i(glGetUniformLocation(frag_shader, "tex2"), 1);
// Set dimensions of the temp texture
			if(temp_texture)
				glUniform2f(glGetUniformLocation(frag_shader, "tex2_dimensions"), 
					(float)temp_texture->get_texture_w(), 
					(float)temp_texture->get_texture_h());
		}
		else
			glUseProgram(0);






// printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
// command->in_x1,
// command->in_y1,
// command->in_x2,
// command->in_y2,
// command->out_x1,
// command->out_y1,
// command->out_x2,
// command->out_y2);



		command->input->draw_texture(command->in_x1, 
			command->in_y1,
			command->in_x2,
			command->in_y2,
			command->out_x1,
			command->out_y1,
			command->out_x2,
			command->out_y2,
// Don't flip vertical if nested
			!command->is_nested);

		glUseProgram(0);


// Delete temp texture
		if(temp_texture)
		{
			delete temp_texture;
			temp_texture = 0;
			glActiveTexture(GL_TEXTURE1);
			glDisable(GL_TEXTURE_2D);
		}
		glActiveTexture(GL_TEXTURE0);
		glDisable(GL_TEXTURE_2D);



		window->unlock_window();
	}
	command->canvas->unlock_canvas();
#endif
}
示例#2
0
void Playback3D::overlay_sync(Playback3DCommand *command)
{
#ifdef HAVE_GL
// To do these operations, we need to copy the input buffer to a texture
// and blend 2 textures in a shader
	static const char * const overlay_shaders[TRANSFER_TYPES] = {
		blend_normal_frag,	// TRANSFER_NORMAL
		blend_add_frag,		// TRANSFER_ADDITION
		blend_subtract_frag,	// TRANSFER_SUBTRACT
		blend_multiply_frag,	// TRANSFER_MULTIPLY
		blend_divide_frag,	// TRANSFER_DIVIDE
		blend_replace_frag,	// TRANSFER_REPLACE
		blend_max_frag,		// TRANSFER_MAX
		blend_min_frag,		// TRANSFER_MIN
		blend_average_frag,	// TRANSFER_AVERAGE
		blend_darken_frag,	// TRANSFER_DARKEN
		blend_lighten_frag,	// TRANSFER_LIGHTEN
		blend_dst_frag,		// TRANSFER_DST
		blend_dst_atop_frag,	// TRANSFER_DST_ATOP
		blend_dst_in_frag,	// TRANSFER_DST_IN
		blend_dst_out_frag,	// TRANSFER_DST_OUT
		blend_dst_over_frag,	// TRANSFER_DST_OVER
		blend_src_frag,		// TRANSFER_SRC
		blend_src_atop_frag,	// TRANSFER_SRC_ATOP
		blend_src_in_frag,	// TRANSFER_SRC_IN
		blend_src_out_frag,	// TRANSFER_SRC_OUT
		blend_src_over_frag,	// TRANSFER_SRC_OVER
		blend_or_frag,		// TRANSFER_OR
		blend_xor_frag		// TRANSFER_XOR
	};

	command->canvas->lock_canvas("Playback3D::overlay_sync");
	if(command->canvas->get_canvas()) {
		BC_WindowBase *window = command->canvas->get_canvas();
		window->lock_window("Playback3D::overlay_sync");
// Make sure OpenGL is enabled first.
		window->enable_opengl();
	 	window->update_video_cursor();

		glColor4f(1, 1, 1, 1);
		glDisable(GL_BLEND);

		if(command->frame) {
// Render to PBuffer
			command->frame->enable_opengl();
			command->frame->set_opengl_state(VFrame::SCREEN);
			canvas_w = command->frame->get_w();
			canvas_h = command->frame->get_h();
		}
		else {
// Render to canvas
			canvas_w = window->get_w();
			canvas_h = window->get_h();
		}


//printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
		switch(command->input->get_opengl_state()) {
// Upload texture and composite to screen
		case VFrame::RAM:
			command->input->to_texture();
			break;
// Just composite texture to screen
		case VFrame::TEXTURE:
			break;
// read from PBuffer to texture, then composite texture to screen
		case VFrame::SCREEN:
			command->input->enable_opengl();
			command->input->screen_to_texture();
			if(command->frame)
				command->frame->enable_opengl();
			else
				window->enable_opengl();
			break;
		default:
			printf("Playback3D::overlay_sync unknown state\n");
			break;
		}


		const char *shader_stack[4] = { 0, 0, 0, 0, };
		int total_shaders = 0;

		VFrame::init_screen(canvas_w, canvas_h);

// Enable texture
		command->input->bind_texture(0);

// Convert colormodel to RGB if not nested.
// The color model setting in the output frame is ignored.
		if( command->is_nested <= 0 ) {  // not nested
			switch(command->input->get_color_model()) {
			case BC_YUV888:
			case BC_YUVA8888:
				shader_stack[total_shaders++] = yuv_to_rgb_frag;
				break;
			}
		}

// get the shaders
#define add_shader(s) \
  if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag; \
  shader_stack[total_shaders++] = s

		switch(command->mode) {
		case TRANSFER_REPLACE:
// This requires overlaying an alpha multiplied image on a black screen.
			if( command->input->get_texture_components() != 4 ) break;
			add_shader(overlay_shaders[command->mode]);
			break;
		default:
			enable_overlay_texture(command);
			add_shader(overlay_shaders[command->mode]);
			break;
		}

// if to flatten alpha
		if( command->is_nested < 0 ) {
			switch(command->input->get_color_model()) {
// yuv has already been converted to rgb
			case BC_YUVA8888:
			case BC_RGBA_FLOAT:
			case BC_RGBA8888:
				add_shader(rgba_to_rgb_flatten);
				break;
			}
		}

// run the shaders
		unsigned int frag_shader = 0;
		if(shader_stack[0]) {
			frag_shader = VFrame::make_shader(0,
				shader_stack[0], shader_stack[1],
				shader_stack[2], shader_stack[3], 0);

			glUseProgram(frag_shader);

// Set texture unit of the texture
			glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
// Set texture unit of the temp texture
			glUniform1i(glGetUniformLocation(frag_shader, "tex2"), 1);
// Set alpha
			int variable = glGetUniformLocation(frag_shader, "alpha");
			glUniform1f(variable, command->alpha);
// Set dimensions of the temp texture
			if(temp_texture)
				glUniform2f(glGetUniformLocation(frag_shader, "tex2_dimensions"), 
					(float)temp_texture->get_texture_w(), 
					(float)temp_texture->get_texture_h());
		}
		else
			glUseProgram(0);


// printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
// command->in_x1, command->in_y1, command->in_x2, command->in_y2,
// command->out_x1, command->out_y1, command->out_x2, command->out_y2);

		command->input->draw_texture(
			command->in_x1, command->in_y1, command->in_x2, command->in_y2,
			command->out_x1, command->out_y1, command->out_x2, command->out_y2,
// Don't flip vertical if nested
			command->is_nested > 0 ? 0 : 1);
		glUseProgram(0);

// Delete temp texture
		if(temp_texture) {
			delete temp_texture;
			temp_texture = 0;
			glActiveTexture(GL_TEXTURE1);
			glDisable(GL_TEXTURE_2D);
		}
		glActiveTexture(GL_TEXTURE0);
		glDisable(GL_TEXTURE_2D);

		window->unlock_window();
	}
	command->canvas->unlock_canvas();
#endif
}