Logo Search packages:      
Sourcecode: timfx version File versions  Download package

gl_blur.cc

// timfx 
// Copyright 2002, Timothy M. Shead
//
// Contact: tshead@k-3d.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 the Free Software Foundation; either
// version 2 of the License, or (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, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "gl_blur.h"

#include <kino/image_filters.h>

#include <gtkmm/adjustment.h>
#include <gtkmm/box.h>
#include <gtkmm/checkbutton.h>
#include <gtkmm/label.h>
#include <gtkmm/main.h>
#include <gtkmm/spinbutton.h>
#include <gtkmm/window.h>

#include <algorithm>
#include <memory>
#include <numeric>
#include <sstream>

#include "kino_opengl_utility.h"

namespace
{

class gl_blur :
      public GDKImageFilter
{
public:
      gl_blur() :
            m_radius(5)
      {
            Gtk::Main main(0, 0);

            m_radius_spin_button.set_adjustment(*manage(new Gtk::Adjustment(m_radius, 1, 1000, 1, 10)));
            m_radius_spin_button.set_numeric(true);
            m_radius_spin_button.set_digits(0);
            m_radius_spin_button.set_wrap(false);
            m_radius_spin_button.set_snap_to_ticks(true);
            m_radius_spin_button.set_value(m_radius);

            Gtk::HBox* const options_group = new Gtk::HBox(false, 0);
            options_group->pack_start(*manage(new Gtk::Label("Radius:")), false, true);
            options_group->pack_start(m_radius_spin_button, true, true);

            Gtk::VBox* const vbox = new Gtk::VBox(false, 0);
            vbox->pack_start(*manage(options_group), false, true);
            vbox->show_all();

            m_window.add(*manage(vbox));
      }

      char *GetDescription( ) const
      {
            return "Blur (OpenGL)"; 
      }

      void FilterFrame(uint8_t* pixels, int width, int height, double position, double frame_delta)
      {
std::cout << position << ": " << frame_delta << std::endl;
            
            // Uncomment this to disable pbuffer rendering
//          kino::gl::use_pbuffers(false);      

            if(0 == m_buffer.get())
                  m_buffer.reset(new kino::gl::render_buffer(width, height));

            // Start drawing ...
            m_buffer->start_render();

            // Check to be sure we haven't exceeded the limits of this implementation
            GLint max_width = 0;
            GLint max_height = 0;
            glGetConvolutionParameteriv(GL_SEPARABLE_2D, GL_MAX_CONVOLUTION_WIDTH, &max_width);
            glGetConvolutionParameteriv(GL_SEPARABLE_2D, GL_MAX_CONVOLUTION_HEIGHT, &max_height);
            
            if(m_radius > std::min(max_width, max_height))
                  {
                        static std::ostringstream error_message;
                        error_message.str().clear();
                        error_message << "Blur radius exceeds local OpenGL limit of " << std::min(max_width, max_height) << " pixels";
                        throw error_message.str().c_str();
                  }

            // Setup our convolution ...
            std::vector<GLfloat> unweighted_filter(m_radius, 1.0); // box filter
            std::vector<GLfloat> filter   ;
            std::transform(unweighted_filter.begin(), unweighted_filter.end(), std::back_inserter(filter), std::bind2nd(std::divides<GLfloat>(), std::accumulate(unweighted_filter.begin(), unweighted_filter.end(), 0.0)));
            
            glSeparableFilter2D(GL_SEPARABLE_2D, GL_INTENSITY, m_radius, m_radius, GL_LUMINANCE, GL_FLOAT, &filter[0], &filter[0]);
            glConvolutionParameteri(GL_SEPARABLE_2D, GL_CONVOLUTION_BORDER_MODE, GL_REPLICATE_BORDER);
            glEnable(GL_SEPARABLE_2D);
            
            // Draw the background ...
            m_buffer->draw_background(width, height, pixels);
            
            // Finish drawing ...
            m_buffer->finish_render();

            // Copy rendered image back to Kino
            glDisable(GL_SEPARABLE_2D);
            m_buffer->read_pixels(width, height, pixels);
      }

      void AttachWidgets(GtkBin* bin)
      {
            gtk_widget_reparent( ( GTK_BIN( m_window.gobj() ) )->child, GTK_WIDGET( bin ) );
      }

      void DetachWidgets(GtkBin* bin)
      {
            gtk_widget_reparent( ( GTK_BIN( bin ) )->child, GTK_WIDGET( m_window.gobj() ) );
      }

      void InterpretWidgets( GtkBin *bin )
      {
            m_radius = m_radius_spin_button.get_value_as_int();
            m_buffer.reset(0);
      }

private:
      Gtk::SpinButton m_radius_spin_button;
      
      Gtk::Window m_window;
      
      unsigned int m_radius;
      
      std::auto_ptr<kino::gl::render_buffer> m_buffer;
};

} // namespace

GDKImageFilter* gl_blur_factory()
{
      return new gl_blur();
}

Generated by  Doxygen 1.6.0   Back to index