void Playback3D::copy_from_sync(Playback3DCommand *command) { #ifdef HAVE_GL command->canvas->lock_canvas("Playback3D::draw_refresh_sync"); BC_WindowBase *window = command->canvas->get_canvas(); if(window) { window->lock_window("Playback3D:draw_refresh_sync"); window->enable_opengl(); int w = command->input->get_w(); int h = command->input->get_h(); if(command->input->get_opengl_state() == VFrame::SCREEN && w == command->frame->get_w() && h == command->frame->get_h()) { // printf("Playback3D::copy_from_sync 1 %d %d %d %d %d\n", // command->input->get_w(), // command->input->get_h(), // command->frame->get_w(), // command->frame->get_h(), // command->frame->get_color_model()); // With NVidia at least, if(w % 4) { printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w); } else // Copy to texture if(command->want_texture) { //printf("Playback3D::copy_from_sync 1 dst=%p src=%p\n", command->frame, command->input); // Screen_to_texture requires the source pbuffer enabled. command->input->enable_opengl(); command->frame->screen_to_texture(); command->frame->set_opengl_state(VFrame::TEXTURE); } else // Copy to RAM { command->input->enable_opengl(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, command->frame->get_rows()[0]); command->frame->flip_vert(); command->frame->set_opengl_state(VFrame::RAM); } } else { printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n", command->input->get_opengl_state(), w, h, command->frame->get_w(), command->frame->get_h()); } window->unlock_window(); } command->canvas->unlock_canvas(); #endif }
void Playback3D::run_plugin_sync(Playback3DCommand *command) { command->canvas->lock_canvas("Playback3D::run_plugin_sync"); if(command->canvas->get_canvas()) { BC_WindowBase *window = command->canvas->get_canvas(); window->lock_window("Playback3D::run_plugin_sync"); window->enable_opengl(); command->result = ((PluginVClient*)command->plugin_client)->handle_opengl(); window->unlock_window(); } command->canvas->unlock_canvas(); }
void Playback3D::write_buffer_sync(Playback3DCommand *command) { command->canvas->lock_canvas("Playback3D::write_buffer_sync"); if(command->canvas->get_canvas()) { BC_WindowBase *window = command->canvas->get_canvas(); window->lock_window("Playback3D::write_buffer_sync"); // Update hidden cursor window->update_video_cursor(); // Make sure OpenGL is enabled first. window->enable_opengl(); //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id()); switch(command->frame->get_opengl_state()) { // Upload texture and composite to screen case VFrame::RAM: command->frame->to_texture(); draw_output(command); break; // Composite texture to screen and swap buffer case VFrame::TEXTURE: draw_output(command); break; case VFrame::SCREEN: // swap buffers only window->flip_opengl(); break; default: printf("Playback3D::write_buffer_sync unknown state\n"); break; } window->unlock_window(); } command->canvas->unlock_canvas(); }
int RecordPrefs::create_objects() { int x, y, x2; char string[BCTEXTLEN]; BC_Resources *resources = BC_WindowBase::get_resources(); BC_Title *title; BC_WindowBase *win; int maxw, curw, ybix[5]; x = mwindow->theme->preferencesoptions_x; y = mwindow->theme->preferencesoptions_y; add_subwindow(title = new BC_Title(x, y, _("File Format:"), LARGEFONT, resources->text_default)); y += title->get_h() + 5; recording_format = new FormatTools(mwindow, this, pwindow->thread->edl->session->recording_format); recording_format->create_objects(x, y, 1, // Include tools for audio 1, // Include tools for video 1, // Include checkbox for audio 1, // Include checkbox for video 0, 1, 0, // Select compressors to be offered 1, // Prompt for recording options 0, // If nonzero, prompt for insertion strategy 0, // Supply file formats for background rendering 1); // Horizontal layout // Audio hardware add_subwindow(new BC_Bar(5, y, get_w() - 10)); y += 5; add_subwindow(title = new BC_Title(x, y, _("Audio In"), LARGEFONT, resources->text_default)); y += title->get_h(); win = add_subwindow(new BC_Title(x, y, _("Record Driver:"), MEDIUMFONT, resources->text_default)); y += win->get_h(); audio_in_device = new ADevicePrefs(x + 55, y, pwindow, this, 0, pwindow->thread->edl->session->aconfig_in, MODERECORD); audio_in_device->initialize(1); y += audio_in_device->get_h(1); BC_TextBox *textbox; BC_Title *title1, *title2, *title3; ybix[0] = y; add_subwindow(title1 = new BC_Title(x, y, _("Samples to write to disk at a time:"))); ybix[1] = y += title1->get_h() + 8; add_subwindow(title2 = new BC_Title(x, y, _("Sample rate for recording:"))); ybix[2] = y += title2->get_h() + 8; add_subwindow(title3 = new BC_Title(x, y, _("Channels to record:"))); x2 = MAX(title1->get_w(), title2->get_w()) + 10; x2 = MAX(x2, title3->get_w() + 10); sprintf(string, "%jd", pwindow->thread->edl->session->record_write_length); add_subwindow(textbox = new RecordWriteLength(mwindow, pwindow, x2, ybix[0], string)); add_subwindow(textbox = new SampleRateSelection(x2, ybix[1], this, &pwindow->thread->edl->session->aconfig_in->in_samplerate)); textbox->update(pwindow->thread->edl->session->aconfig_in->in_samplerate); RecordChannels *channels = new RecordChannels(pwindow, this, x2, ybix[2]); channels->create_objects(); y += title3->get_h() + 15; x = 5; // Video hardware add_subwindow(new BC_Bar(5, y, get_w() - 10)); y += 5; win = add_subwindow(new BC_Title(x, y, _("Video In"), LARGEFONT, resources->text_default)); y += win->get_h(); win = add_subwindow(new BC_Title(x, y, _("Record Driver:"), MEDIUMFONT, resources->text_default)); y += win->get_h() + 5; video_in_device = new VDevicePrefs(x + 55, y, pwindow, this, 0, pwindow->thread->edl->session->vconfig_in, MODERECORD); video_in_device->initialize(1); ybix[0] = y += 50; win = add_subwindow(new BC_Title(x, y, _("Frames to record to disk at a time:"))); ybix[1] = y += win->get_h() + 8; maxw = win->get_w(); win = add_subwindow(new BC_Title(x, y, _("Frames to buffer in device:"))); y += win->get_h() + 8; if((curw = win->get_w()) > maxw) maxw = curw; win = add_subwindow(new RecordSoftwareTimer(pwindow, pwindow->thread->edl->session->record_software_position, x, y)); y += win->get_h(); win = add_subwindow(new RecordSyncDrives(pwindow, pwindow->thread->edl->session->record_sync_drives, x, y)); ybix[2] = y += win->get_h() + 5; win = add_subwindow(new BC_Title(x, y, _("Size of captured frame:"))); ybix[3] = y += win->get_h() + 8; if((curw = win->get_w()) > maxw) maxw = curw; win = add_subwindow(new BC_Title(x, y, _("Frame rate for recording:"))); ybix[4] = y += win->get_h() + 15; if((curw = win->get_w()) > maxw) maxw = curw; maxw += x + 10; // Frames to record to disk at a time sprintf(string, "%d", pwindow->thread->edl->session->video_write_length); add_subwindow(textbox = new VideoWriteLength(pwindow, string, maxw, ybix[0])); add_subwindow(new CaptureLengthTumbler(pwindow, textbox, textbox->get_x() + textbox->get_w(), ybix[0])); // Frames to buffer in device sprintf(string, "%d", pwindow->thread->edl->session->vconfig_in->capture_length); add_subwindow(textbox = new VideoCaptureLength(pwindow, string, maxw, ybix[1])); add_subwindow(new CaptureLengthTumbler(pwindow, textbox, textbox->get_x() + textbox->get_w(), ybix[1])); // Size of captured frame BC_TextBox *w_text, *h_text; x = maxw; y = ybix[2]; FrameSizeSelection *fselector; add_subwindow(fselector = new FrameSizeSelection(x, y, x + SELECTION_TB_WIDTH + 12, y, this, &pwindow->thread->edl->session->vconfig_in->w, &pwindow->thread->edl->session->vconfig_in->h)); fselector->update(pwindow->thread->edl->session->vconfig_in->w, pwindow->thread->edl->session->vconfig_in->h); y = ybix[3]; x = maxw; add_subwindow(textbox = new FrameRateSelection(x, y, this, &pwindow->thread->edl->session->vconfig_in->in_framerate)); textbox->update(pwindow->thread->edl->session->vconfig_in->in_framerate); y = ybix[4]; x = 5; add_subwindow(new BC_Bar(5, y, get_w() - 10)); y += 5; add_subwindow(new BC_Title(x, y, _("Images"), LARGEFONT, get_resources()->text_default)); y += 25; win = add_subwindow(new StillImageUseDuration(pwindow, pwindow->thread->edl->session->si_useduration, x, y)); x += win->get_w() + 10; win = add_subwindow(new StillImageDuration(pwindow, x, y)); x += win->get_w() + 10; y += 3; add_subwindow(new BC_Title(x, y, _("Seconds"))); return 0; }
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 }
void Playback3D::draw_output(Playback3DCommand *command) { #ifdef HAVE_GL int texture_id = command->frame->get_texture_id(); BC_WindowBase *window = command->canvas->get_canvas(); // printf("Playback3D::draw_output 1 texture_id=%d window=%p\n", // texture_id, // command->canvas->get_canvas()); // If virtual console is being used, everything in this function has // already been done except the page flip. if(texture_id >= 0) { canvas_w = window->get_w(); canvas_h = window->get_h(); VFrame::init_screen(canvas_w, canvas_h); if(!command->is_cleared) { // If we get here, the virtual console was not used. init_frame(command); } // Texture // Undo any previous shader settings command->frame->bind_texture(0); // Convert colormodel unsigned int frag_shader = 0; switch(command->frame->get_color_model()) { case BC_YUV888: case BC_YUVA8888: frag_shader = VFrame::make_shader(0, yuv_to_rgb_frag, 0); break; } if(frag_shader > 0) { glUseProgram(frag_shader); int variable = glGetUniformLocation(frag_shader, "tex"); // Set texture unit of the texture glUniform1i(variable, 0); } if(BC_CModels::components(command->frame->get_color_model()) == 4) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } command->frame->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, 1); // printf("Playback3D::draw_output 2 %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); glUseProgram(0); command->canvas->get_canvas()->flip_opengl(); } #endif }
void Playback3D::do_fade_sync(Playback3DCommand *command) { #ifdef HAVE_GL command->canvas->lock_canvas("Playback3D::do_mask_sync"); if(command->canvas->get_canvas()) { BC_WindowBase *window = command->canvas->get_canvas(); window->lock_window("Playback3D::do_fade_sync"); window->enable_opengl(); switch(command->frame->get_opengl_state()) { case VFrame::RAM: command->frame->to_texture(); break; case VFrame::SCREEN: // Read back from PBuffer // Bind context to pbuffer command->frame->enable_opengl(); command->frame->screen_to_texture(); break; } command->frame->enable_opengl(); command->frame->init_screen(); command->frame->bind_texture(0); // glClearColor(0.0, 0.0, 0.0, 0.0); // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDisable(GL_BLEND); unsigned int frag_shader = 0; switch(command->frame->get_color_model()) { // For the alpha colormodels, the native function seems to multiply the // components by the alpha instead of just the alpha. case BC_RGBA8888: case BC_RGBA_FLOAT: case BC_YUVA8888: frag_shader = VFrame::make_shader(0, fade_rgba_frag, 0); break; case BC_RGB888: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ZERO); glColor4f(command->alpha, command->alpha, command->alpha, 1); break; case BC_YUV888: frag_shader = VFrame::make_shader(0, fade_yuv_frag, 0); break; } if(frag_shader) { glUseProgram(frag_shader); int variable; if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0) glUniform1i(variable, 0); if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0) glUniform1f(variable, command->alpha); } command->frame->draw_texture(); command->frame->set_opengl_state(VFrame::SCREEN); if(frag_shader) { glUseProgram(0); } glColor4f(1, 1, 1, 1); glDisable(GL_BLEND); window->unlock_window(); } command->canvas->unlock_canvas(); #endif }
void Playback3D::convert_cmodel_sync(Playback3DCommand *command) { #ifdef HAVE_GL command->canvas->lock_canvas("Playback3D::convert_cmodel_sync"); if(command->canvas->get_canvas()) { BC_WindowBase *window = command->canvas->get_canvas(); window->lock_window("Playback3D::convert_cmodel_sync"); window->enable_opengl(); // Import into hardware command->frame->enable_opengl(); command->frame->init_screen(); command->frame->to_texture(); // Colormodel permutation const char *shader = 0; int src_cmodel = command->frame->get_color_model(); int dst_cmodel = command->dst_cmodel; typedef struct { int src; int dst; const char *shader; } cmodel_shader_table_t; static cmodel_shader_table_t cmodel_shader_table[] = { { BC_RGB888, BC_YUV888, rgb_to_yuv_frag }, { BC_RGB888, BC_YUVA8888, rgb_to_yuv_frag }, { BC_RGBA8888, BC_RGB888, rgba_to_rgb_frag }, { BC_RGBA8888, BC_RGB_FLOAT, rgba_to_rgb_frag }, { BC_RGBA8888, BC_YUV888, rgba_to_yuv_frag }, { BC_RGBA8888, BC_YUVA8888, rgb_to_yuv_frag }, { BC_RGB_FLOAT, BC_YUV888, rgb_to_yuv_frag }, { BC_RGB_FLOAT, BC_YUVA8888, rgb_to_yuv_frag }, { BC_RGBA_FLOAT, BC_RGB888, rgba_to_rgb_frag }, { BC_RGBA_FLOAT, BC_RGB_FLOAT, rgba_to_rgb_frag }, { BC_RGBA_FLOAT, BC_YUV888, rgba_to_yuv_frag }, { BC_RGBA_FLOAT, BC_YUVA8888, rgb_to_yuv_frag }, { BC_YUV888, BC_RGB888, yuv_to_rgb_frag }, { BC_YUV888, BC_RGBA8888, yuv_to_rgb_frag }, { BC_YUV888, BC_RGB_FLOAT, yuv_to_rgb_frag }, { BC_YUV888, BC_RGBA_FLOAT, yuv_to_rgb_frag }, { BC_YUVA8888, BC_RGB888, yuva_to_rgb_frag }, { BC_YUVA8888, BC_RGBA8888, yuv_to_rgb_frag }, { BC_YUVA8888, BC_RGB_FLOAT, yuva_to_rgb_frag }, { BC_YUVA8888, BC_RGBA_FLOAT, yuv_to_rgb_frag }, { BC_YUVA8888, BC_YUV888, yuva_to_yuv_frag }, }; for(int i = 0; i < sizeof(cmodel_shader_table) / sizeof(cmodel_shader_table_t); i++) { if(cmodel_shader_table[i].src == src_cmodel && cmodel_shader_table[i].dst == dst_cmodel) { shader = cmodel_shader_table[i].shader; break; } } // printf("Playback3D::convert_cmodel_sync %d %d %d shader=\n%s", // __LINE__, // command->frame->get_color_model(), // command->dst_cmodel, // shader); if(shader) { //printf("Playback3D::convert_cmodel_sync %d\n", __LINE__); command->frame->bind_texture(0); unsigned int shader_id = -1; if(shader) { shader_id = VFrame::make_shader(0, shader, 0); glUseProgram(shader_id); glUniform1i(glGetUniformLocation(shader_id, "tex"), 0); } command->frame->draw_texture(); if(shader) glUseProgram(0); command->frame->set_opengl_state(VFrame::SCREEN); } window->unlock_window(); } command->canvas->unlock_canvas(); #endif // HAVE_GL }
void Playback3D::do_mask_sync(Playback3DCommand *command) { #ifdef HAVE_GL command->canvas->lock_canvas("Playback3D::do_mask_sync"); if(command->canvas->get_canvas()) { BC_WindowBase *window = command->canvas->get_canvas(); window->lock_window("Playback3D::do_mask_sync"); window->enable_opengl(); switch(command->frame->get_opengl_state()) { case VFrame::RAM: // Time to upload to the texture command->frame->to_texture(); break; case VFrame::SCREEN: // Read back from PBuffer // Bind context to pbuffer command->frame->enable_opengl(); command->frame->screen_to_texture(); break; } // Create PBuffer and draw the mask on it command->frame->enable_opengl(); // Initialize coordinate system int w = command->frame->get_w(); int h = command->frame->get_h(); command->frame->init_screen(); int value = command->keyframe_set->get_value(command->start_position_project, PLAY_FORWARD); float feather = command->keyframe_set->get_feather(command->start_position_project, PLAY_FORWARD); // Clear screen glDisable(GL_TEXTURE_2D); if(command->default_auto->mode == MASK_MULTIPLY_ALPHA) { glClearColor(0.0, 0.0, 0.0, 0.0); glColor4f((float)value / 100, (float)value / 100, (float)value / 100, 1.0); } else { glClearColor(1.0, 1.0, 1.0, 1.0); glColor4f((float)1.0 - (float)value / 100, (float)1.0 - (float)value / 100, (float)1.0 - (float)value / 100, 1.0); } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Draw mask with scaling to simulate feathering GLUtesselator *tesselator = gluNewTess(); gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv); gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin); gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd); gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback); // Draw every submask as a new polygon int total_submasks = command->keyframe_set->total_submasks( command->start_position_project, PLAY_FORWARD); float scale = feather + 1; int display_list = glGenLists(1); glNewList(display_list, GL_COMPILE); for(int k = 0; k < total_submasks; k++) { gluTessBeginPolygon(tesselator, NULL); gluTessBeginContour(tesselator); ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>; command->keyframe_set->get_points(points, k, command->start_position_project, PLAY_FORWARD); int first_point = 0; // Need to tabulate every vertex in persistent memory because // gluTessVertex doesn't copy them. ArrayList<GLdouble*> coords; for(int i = 0; i < points->total; i++) { MaskPoint *point1 = points->values[i]; MaskPoint *point2 = (i >= points->total - 1) ? points->values[0] : points->values[i + 1]; // This is very slow. float x, y; int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y))); if(point1->control_x2 == 0 && point1->control_y2 == 0 && point2->control_x1 == 0 && point2->control_y1 == 0) segments = 1; float x0 = point1->x; float y0 = point1->y; float x1 = point1->x + point1->control_x2; float y1 = point1->y + point1->control_y2; float x2 = point2->x + point2->control_x1; float y2 = point2->y + point2->control_y1; float x3 = point2->x; float y3 = point2->y; for(int j = 0; j <= segments; j++) { float t = (float)j / segments; float tpow2 = t * t; float tpow3 = t * t * t; float invt = 1 - t; float invtpow2 = invt * invt; float invtpow3 = invt * invt * invt; x = ( invtpow3 * x0 + 3 * t * invtpow2 * x1 + 3 * tpow2 * invt * x2 + tpow3 * x3); y = ( invtpow3 * y0 + 3 * t * invtpow2 * y1 + 3 * tpow2 * invt * y2 + tpow3 * y3); if(j > 0 || first_point) { GLdouble *coord = new GLdouble[3]; coord[0] = x / scale; coord[1] = -h + y / scale; coord[2] = 0; coords.append(coord); first_point = 0; } } } // Now that we know the total vertices, send them to GLU for(int i = 0; i < coords.total; i++) gluTessVertex(tesselator, coords.values[i], coords.values[i]); gluTessEndContour(tesselator); gluTessEndPolygon(tesselator); points->remove_all_objects(); delete points; coords.remove_all_objects(); } glEndList(); glCallList(display_list); glDeleteLists(display_list, 1); glColor4f(1, 1, 1, 1); // Read mask into temporary texture. // For feathering, just read the part of the screen after the downscaling. float w_scaled = w / scale; float h_scaled = h / scale; // Don't vary the texture size according to scaling because that // would waste memory. // This enables and binds the temporary texture. glActiveTexture(GL_TEXTURE1); BC_Texture::new_texture(&temp_texture, w, h, command->frame->get_color_model()); temp_texture->bind(1); glReadBuffer(GL_BACK); // Need to add extra size to fill in the bottom right glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, (int)MIN(w_scaled + 2, w), (int)MIN(h_scaled + 2, h)); command->frame->bind_texture(0); // For feathered masks, use a shader to multiply. // For unfeathered masks, we could use a stencil buffer // for further optimization but we also need a YUV algorithm. unsigned int frag_shader = 0; switch(temp_texture->get_texture_components()) { case 3: if(command->frame->get_color_model() == BC_YUV888) frag_shader = VFrame::make_shader(0, multiply_yuvmask3_frag, 0); else frag_shader = VFrame::make_shader(0, multiply_mask3_frag, 0); break; case 4: frag_shader = VFrame::make_shader(0, multiply_mask4_frag, 0); break; } if(frag_shader) { int variable; glUseProgram(frag_shader); if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0) glUniform1i(variable, 0); if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0) glUniform1i(variable, 1); if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0) glUniform1f(variable, scale); } // Write texture to PBuffer with multiply and scaling for feather. command->frame->draw_texture(0, 0, w, h, 0, 0, w, h); command->frame->set_opengl_state(VFrame::SCREEN); // Disable temp texture glUseProgram(0); glActiveTexture(GL_TEXTURE1); glDisable(GL_TEXTURE_2D); delete temp_texture; temp_texture = 0; glActiveTexture(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); // Default drawable window->enable_opengl(); window->unlock_window(); } command->canvas->unlock_canvas(); #endif }
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 }