OpenWalnut  1.5.0dev
WQtGLScreenCapture.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <iostream>
26 #include <sstream>
27 #include <string>
28 
29 #include <osgDB/WriteFile>
30 
31 #include <QtCore/QDir>
32 #include <QtCore/QEvent>
33 #include <QApplication>
34 #include <QGroupBox>
35 
36 #include "core/common/WLogger.h"
37 #include "events/WEventTypes.h"
38 #include "WMainWindow.h"
39 #include "WQtGLWidget.h"
40 #include "WQtGLDockWidget.h"
41 #include "WQtGui.h"
42 #include "WQtGLScreenCapture.h"
43 
45  QWidget( parent ),
46  m_glDockWidget( parent ),
47  m_viewer( m_glDockWidget->getGLWidget()->getViewer() )
48 {
49  // initialize
50  setObjectName( "Recorder Dock - " + parent->getDockTitle() );
51  setWindowTitle( "Recorder - " + parent->getDockTitle() );
52 
53  // create our toolbox and add it to the main layout
54  m_toolbox = new QToolBox( this );
55  QHBoxLayout* layout = new QHBoxLayout( this );
56  layout->addWidget( m_toolbox );
57 
58  connect( m_toolbox, SIGNAL( currentChanged( int ) ), this, SLOT( toolBoxChanged( int ) ) );
59 
60  /////////////////////////////////////////////////////////////////////////////////////////////////////////
61  // common config tools
62  /////////////////////////////////////////////////////////////////////////////////////////////////////////
63 
64  m_configWidget = new QWidget();
65  QVBoxLayout* configLayout = new QVBoxLayout();
66  m_configWidget->setLayout( configLayout );
67 
68  // frame related stuff
69  QGroupBox* frameCounterGroup = new QGroupBox( "Frame" );
70  QVBoxLayout* frameCounterGroupLayout = new QVBoxLayout();
71  frameCounterGroup->setLayout( frameCounterGroupLayout );
72  m_configFrameLabel = new QLabel();
73  m_configFrameLabel->setText( "Recorded Frames: 0" );
74  m_configFrameResetButton = new QPushButton( "Reset" );
75  connect( m_configFrameResetButton, SIGNAL( clicked( bool ) ), this, SLOT( resetFrames() ) );
76  frameCounterGroupLayout->addWidget( m_configFrameLabel );
77  frameCounterGroupLayout->addWidget( m_configFrameResetButton );
78 
79  QGroupBox* resolutionGroup = new QGroupBox( "Resolution" );
80  QGridLayout* resolutionGroupLayout = new QGridLayout();
81  resolutionGroup->setLayout( resolutionGroupLayout );
82 
83  m_resolutionCombo = new QComboBox();
84  m_resolutionCombo->addItem( "640x480" );
85  m_resolutionCombo->addItem( "800x600" );
86  m_resolutionCombo->addItem( "1024x768" );
87  m_resolutionCombo->addItem( "1280x1024" );
88  m_resolutionCombo->addItem( "1280x720 (720p)" );
89  m_resolutionCombo->addItem( "1920x1080 (1080p)" );
90  m_resolutionCombo->addItem( "Custom" );
91 
92  m_customWidth = new QLineEdit( "1980", this );
93  m_customHeight = new QLineEdit( "1080", this );
94  m_customWidth->setValidator( new QIntValidator( 0, 4096, m_customWidth ) );
95  m_customHeight->setValidator( new QIntValidator( 0, 4096, m_customHeight ) );
96 
97  QPushButton* resolutionButton = new QPushButton( "Set" );
98  resolutionButton->setCheckable( true );
99  resolutionGroupLayout->addWidget( m_resolutionCombo, 0, 0, 1, 2 );
100  resolutionGroupLayout->addWidget( resolutionButton, 0, 2 );
101  resolutionGroupLayout->addWidget( new QLabel( "Custom Resolution" ), 1, 0, 1, 3 );
102  resolutionGroupLayout->addWidget( m_customWidth, 2, 0 );
103  resolutionGroupLayout->addWidget( m_customHeight, 2, 1 );
104 
105  connect( resolutionButton, SIGNAL( toggled( bool ) ), this, SLOT( resolutionChange( bool ) ) );
106 
107  // filename config
108  QGroupBox* fileGroup = new QGroupBox( "Output Files" );
109  QVBoxLayout* fileGroupLayout = new QVBoxLayout();
110  fileGroup->setLayout( fileGroupLayout );
111 
112  QLabel* configFileHint = new QLabel();
113  configFileHint->setWordWrap( true );
114  configFileHint->setText(
115  "The filename used for all captured frames. This filename can contain some special tags which get replaced:"
116  "<ul>"
117  "<li> %f - the frame number"
118  "</ul>"
119  );
120 
121  m_configFileEdit = new QLineEdit();
122  std::string defaultFilename = ( QDir::homePath() + QDir::separator() +
123  "OpenWalnut - " + parent->getDockTitle() + " - Frame %f.png" ).toStdString();
124  m_configFileEdit->setText( QString::fromStdString( defaultFilename ) );
125 
126  fileGroupLayout->addWidget( configFileHint );
127  fileGroupLayout->addWidget( m_configFileEdit );
128 
129  // add the groups
130  configLayout->addWidget( resolutionGroup );
131  configLayout->addWidget( frameCounterGroup );
132  configLayout->addWidget( fileGroup );
133 
134  /////////////////////////////////////////////////////////////////////////////////////////////////////////
135  // screenshot tools
136  /////////////////////////////////////////////////////////////////////////////////////////////////////////
137 
138  m_screenshotWidget = new QWidget();
139  QVBoxLayout* screenshotLayout = new QVBoxLayout();
140  m_screenshotWidget->setLayout( screenshotLayout );
141 
142  m_screenshotButton = new QPushButton( "Screenshot" );
143  m_screenshotButton->setToolTip( "Take a screenshot of this view" );
144  m_screenshotAction = new QAction( WQtGui::getIconManager()->getIcon( "image" ), "Screenshot", this );
145  m_screenshotAction->setToolTip( "Take a screenshot of this view" );
146  m_screenshotAction->setShortcut( QKeySequence( Qt::Key_F12 ) );
147  m_screenshotAction->setShortcutContext( Qt::ApplicationShortcut );
148  connect( m_screenshotAction, SIGNAL( triggered( bool ) ), this, SLOT( screenShot() ) );
149  connect( m_screenshotButton, SIGNAL( clicked( bool ) ), this, SLOT( screenShot() ) );
150 
151  QLabel* screenshotLabel = new QLabel();
152  screenshotLabel->setWordWrap( true );
153  screenshotLabel->setText( "Take a screenshot of the current scene with the current camera. You need to specify "
154  "a filename in the toolbox item \"Configuration\"." );
155  screenshotLayout->addWidget( screenshotLabel );
156  screenshotLayout->addWidget( m_screenshotButton );
157 
158  /////////////////////////////////////////////////////////////////////////////////////////////////////////
159  // movie tools
160  /////////////////////////////////////////////////////////////////////////////////////////////////////////
161 
162  m_movieWidget = new QWidget();
163  QVBoxLayout* movieLayout = new QVBoxLayout();
164  m_movieWidget->setLayout( movieLayout );
165 
166  QLabel* movieLabel = new QLabel();
167  movieLabel->setWordWrap( true );
168  movieLabel->setText( "Take a screenshot for every frame with the current camera. You need to specify a filename "
169  "in the toolbox item \"Configuration\". "
170  "You should always add %f to your filename to differentiate between each frame. "
171  "This kind of recording can be very slow and produce a high IO load on your machine. Consider recording movies with "
172  "the animation tool which plays back a previously recorded scene and snapshot it frame-wise. "
173  "To create a movie with these images, you can use free encoders like ffmpeg, transcode or mencoder."
174  );
175  movieLabel->setTextInteractionFlags( Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse );
176 
177  m_movieTimeLabel = new QLabel();
178  m_movieTimeLabel->setText( "Recorded Movie-Time: 0s" );
179 
180  m_movieRecButton = new QPushButton( "Record" );
181  connect( m_movieRecButton, SIGNAL( clicked( bool ) ), this, SLOT( startRec() ) );
182 
183  m_movieStopButton = new QPushButton( "Stop" );
184  m_movieStopButton->setDisabled( true );
185  connect( m_movieStopButton, SIGNAL( clicked( bool ) ), this, SLOT( stopRec() ) );
186 
187  movieLayout->addWidget( movieLabel );
188  movieLayout->addWidget( m_movieTimeLabel );
189  movieLayout->addWidget( m_movieRecButton );
190  movieLayout->addWidget( m_movieStopButton );
191 
192  /////////////////////////////////////////////////////////////////////////////////////////////////////////
193  // plug it together
194  /////////////////////////////////////////////////////////////////////////////////////////////////////////
195 
196  // this forces the elements to be initialized properly
197  QCoreApplication::postEvent( this, new QEvent( static_cast< QEvent::Type >( WQT_SCREENCAPTURE_EVENT ) ) );
198 
199  // add them
200  m_toolbox->insertItem( 0, m_configWidget, WQtGui::getIconManager()->getIcon( "preferences" ), "Configuration" );
201  m_toolbox->insertItem( 1, m_screenshotWidget, WQtGui::getIconManager()->getIcon( "image" ), "Screenshot" );
202  m_toolbox->insertItem( 2, m_movieWidget, WQtGui::getIconManager()->getIcon( "video" ), "Movie" );
203 
204  // we need to be notified about the screen grabbers state
205  m_recordConnection = m_viewer->getScreenCapture()->getRecordCondition()->subscribeSignal( boost::bind( &WQtGLScreenCapture::recCallback, this ) );
206  m_imageConnection = m_viewer->getScreenCapture()->subscribeSignal( boost::bind( &WQtGLScreenCapture::handleImage,
207  this,
208  boost::placeholders::_1,
209  boost::placeholders::_2,
210  boost::placeholders::_3 ) );
211 }
212 
214 {
215  // cleanup
216  m_recordConnection.disconnect();
217  m_imageConnection.disconnect();
218 }
219 
221 {
222  WQtGui::getSettings().setValue( objectName() + "/resolution", m_resolutionCombo->currentIndex() );
223  WQtGui::getSettings().setValue( objectName() + "/customResolutionWidth", m_customWidth->text() );
224  WQtGui::getSettings().setValue( objectName() + "/customResolutionHeight", m_customHeight->text() );
225  WQtGui::getSettings().setValue( objectName() + "/filename", m_configFileEdit->text() );
226 }
227 
229 {
230  m_customWidth->setText( WQtGui::getSettings().value( objectName() + "/customResolutionWidth", m_customWidth->text() ).toString() );
231  m_customHeight->setText( WQtGui::getSettings().value( objectName() + "/customResolutionHeight", m_customHeight->text() ).toString() );
232  m_configFileEdit->setText( WQtGui::getSettings().value( objectName() + "/filename", m_configFileEdit->text() ).toString() );
233  m_resolutionCombo->setCurrentIndex( WQtGui::getSettings().value( objectName() + "/resolution", m_resolutionCombo->currentIndex() ).toInt() );
234 }
235 
237 {
238  return m_screenshotAction;
239 }
240 
241 void WQtGLScreenCapture::handleImage( size_t /* framesLeft */, size_t totalFrames, osg::ref_ptr< osg::Image > image ) const
242 {
243  std::string filename = m_configFileEdit->text().toStdString();
244  std::ostringstream ss;
245 
246  // this allows 999999 frames -> over 11h of movie material -> should be enough
247  ss.setf( std::ios::right, std::ios::adjustfield );
248  ss.setf( std::ios::fixed, std::ios::floatfield );
249  ss.precision( 6 );
250  ss.width( 6 );
251  ss.fill( '0' );
252  ss << totalFrames;
253 
254  size_t pos;
255  while( ( pos = filename.find( "%f" ) ) != std::string::npos )
256  {
257  filename.replace( pos, 2, ss.str() );
258  }
259 
260  wlog::info( "WQtGLScreenCapture" ) << "Writing frame " << totalFrames << " to " << filename;
261  osgDB::writeImageFile( *image, filename );
262 }
263 
265 {
266  // a module got associated with the root container -> add it to the list
267  if( event->type() == WQT_SCREENCAPTURE_EVENT )
268  {
269  // grab the needed info
270  WGEScreenCapture::SharedRecordingInformation::ReadTicket r = m_viewer->getScreenCapture()->getRecordingInformation();
271  size_t frame = r->get().m_frames;
272  size_t framesLeft = r->get().m_framesLeft;
273  r.reset();
274 
275  // generate some label texts
276  std::ostringstream time;
277  time.precision( 2 );
278  time << "Recorded Movie-Time: " << static_cast< float >( frame ) / 24.0f;
279  m_movieTimeLabel->setText( QString::fromStdString( time.str() ) );
280 
281  std::ostringstream frames;
282  frames << "Recorded Frames: " << frame;
283  m_configFrameLabel->setText( QString::fromStdString( frames.str() ) );
284 
285  // disable some elements if in recording mode
286  if( framesLeft == 0 ) // recording done:
287  {
288  m_screenshotWidget->setDisabled( false );
289  m_configWidget->setDisabled( false );
290  m_movieStopButton->setDisabled( true );
291  m_movieRecButton->setDisabled( false );
292  }
293  else // still recording
294  {
295  m_screenshotWidget->setDisabled( true );
296  m_configWidget->setDisabled( true );
297  m_movieStopButton->setDisabled( false );
298  m_movieRecButton->setDisabled( true );
299  }
300  }
301 
302  return QWidget::event( event );
303 }
304 
306 {
307  m_viewer->getScreenCapture()->screenshot();
308 }
309 
311 {
312  wlog::info( "WQtGLScreenCapture" ) << "Started recording.";
313  m_viewer->getScreenCapture()->recordStart();
314 }
315 
317 {
318  wlog::info( "WQtGLScreenCapture" ) << "Stopped recording.";
319  m_viewer->getScreenCapture()->recordStop();
320 }
321 
323 {
324  wlog::debug( "WQtGLScreenCapture" ) << "Resetting frame-counter.";
325  m_viewer->getScreenCapture()->resetFrameCounter();
326 }
327 
329 {
330  QCoreApplication::postEvent( this, new QEvent( static_cast< QEvent::Type >( WQT_SCREENCAPTURE_EVENT ) ) );
331 }
332 
333 void WQtGLScreenCapture::toolBoxChanged( int /* index */ )
334 {
335  // no operation if toolbox changes.
336 }
337 
339 {
340  if( force )
341  {
342  wlog::debug( "WQtGLScreenCapture" ) << "Forcing resolution";
343 
344  switch( m_resolutionCombo->currentIndex() )
345  {
346  case 0:
347  m_glDockWidget->forceGLWidgetSize( 640, 480 );
348  break;
349  case 1:
350  m_glDockWidget->forceGLWidgetSize( 800, 600 );
351  break;
352  case 2:
353  m_glDockWidget->forceGLWidgetSize( 1024, 768 );
354  break;
355  case 3:
356  m_glDockWidget->forceGLWidgetSize( 1280, 1024 );
357  break;
358  case 4:
359  m_glDockWidget->forceGLWidgetSize( 1280, 720 );
360  break;
361  case 5:
362  m_glDockWidget->forceGLWidgetSize( 1920, 1080 );
363  break;
364  case 6: // custom size
365  m_glDockWidget->forceGLWidgetSize( m_customWidth->text().toInt(), m_customHeight->text().toInt() );
366  break;
367  }
368  }
369  else
370  {
371  wlog::debug( "WQtGLScreenCapture" ) << "Restoring resolution";
373  }
374 }
Dock widget containing only a GLWidget.
const QString & getDockTitle() const
Return the title of the view/dock.
void forceGLWidgetSize(size_t w, size_t h)
Forces the GL widget to have the desired size.
void restoreGLWidgetSize()
Restores the GL widget size if it was fixed with forceMainGLWidgetSize() previously.
QLineEdit * m_customHeight
Widget for entering a custom resolution height.
void resetFrames()
Slot triggered by m_configFrameResetButton.
void screenShot()
Initiates taking a screenshot.
virtual ~WQtGLScreenCapture()
Destructor.
boost::signals2::connection m_recordConnection
Recording - callback connection.
QPushButton * m_screenshotButton
The trigger which triggers the screenshot.
QWidget * m_screenshotWidget
Widget containing all the widgets to control movie recording.
QLabel * m_configFrameLabel
Shows recorded frames.
QWidget * m_configWidget
The configuration widget.
QPushButton * m_movieRecButton
record button
boost::signals2::connection m_imageConnection
New image incoming - callback connection to handleImage.
void handleImage(size_t framesLeft, size_t totalFrames, osg::ref_ptr< osg::Image > image) const
The function handles new images.
QPushButton * m_configFrameResetButton
Triggers frame counter reset.
WGEViewer::SPtr m_viewer
The actual screen capture instance.
QToolBox * m_toolbox
The toolbox containing all the stuff.
void toolBoxChanged(int index)
Someone changed the open tab in the toolbox.
virtual void saveSettings()
Save settings.
virtual void restoreSettings()
Restore settings.
QAction * m_screenshotAction
This action triggers a screenshot.
void resolutionChange(bool force)
Changes resolution of gl widget.
void stopRec()
Slot triggered by m_moveStopButton.
void startRec()
Slot triggered by m_moveRecButton.
QPushButton * m_movieStopButton
stop button
QWidget * m_movieWidget
Widget containing all the widgets to control movie recording.
QAction * getScreenshotTrigger() const
Returns the trigger used for screenshotting.
QLabel * m_movieTimeLabel
Shows recorded time in movie-time.
QComboBox * m_resolutionCombo
Stores the resolution the user wants to have.
void recCallback()
Called by the screencapture callback to notify this widget about recording.
WQtGLScreenCapture(WQtGLDockWidget *parent)
Creates screen capture gui for the specified capture callback of a certain view.
QLineEdit * m_customWidth
Widget for entering a custom resolution width.
QLineEdit * m_configFileEdit
The filename for the screenshot.
WQtGLDockWidget * m_glDockWidget
My parent.
virtual bool event(QEvent *event)
Custom event dispatcher.
static QSettings & getSettings()
Returns the settings object.
Definition: WQtGui.cpp:394
static WIconManager * getIconManager()
Get the icon manager of this gui instance.
Definition: WQtGui.cpp:93
std::shared_ptr< WSharedObjectTicketRead< RecordingInformation > > ReadTicket
Type for read tickets.
Definition: WSharedObject.h:65
WStreamedLogger debug(const std::string &source)
Logging a debug message.
Definition: WLogger.h:331
WStreamedLogger info(const std::string &source)
Logging an information message.
Definition: WLogger.h:320