Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/visualization/ToolsSG/include/private/G4ToolsSGViewer.hh

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 //
  2 // ********************************************************************
  3 // * License and Disclaimer                                           *
  4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.                             *
 10 // *                                                                  *
 11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                                                  *
 18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // ********************************************************************
 25 //
 26 // John Allison  6th October 2019
 27 
 28 #ifndef G4TOOLSSGVIEWER_HH
 29 #define G4TOOLSSGVIEWER_HH
 30 
 31 #include "G4VViewer.hh"
 32 
 33 #include "G4ToolsSGSceneHandler.hh"
 34 #include "G4Scene.hh"
 35 #include "G4VVisCommand.hh"
 36 
 37 #include <tools/fpng>
 38 #include <tools/toojpeg>
 39 
 40 #include <tools/sg/device_interactor>
 41 #include <tools/sg/separator>
 42 #include <tools/sg/ortho>
 43 #include <tools/sg/perspective>
 44 #include <tools/sg/torche>
 45 #include <tools/sg/blend>
 46 #include <tools/sg/noderef>
 47 #include <tools/sg/keys>
 48 
 49 #include <tools/tokenize>
 50 #include <tools/sg/write_paper>
 51 
 52 template <class SG_SESSION,class SG_VIEWER>
 53 class G4ToolsSGViewer : public G4VViewer, tools::sg::device_interactor {
 54   typedef G4VViewer parent;
 55   typedef tools::sg::device_interactor parent_interactor;
 56 public: //tools::sg::device_interactor interface.
 57   virtual void key_press(const tools::sg::key_down_event& a_event) {
 58     fKeyPressed = true;
 59     fKeyShift = a_event.key() == tools::sg::key_shift()?true:false;
 60   }
 61   virtual void key_release(const tools::sg::key_up_event&) {fKeyPressed = false;}
 62   virtual void mouse_press(const tools::sg::mouse_down_event& a_event) {
 63     fMousePressed = true;
 64     fMousePressedX = a_event.x();
 65     fMousePressedY = a_event.y();
 66   }
 67   virtual void mouse_release(const tools::sg::mouse_up_event&) {fMousePressed = false;}    
 68   virtual void mouse_move(const tools::sg::mouse_move_event& a_event) {
 69     G4double x = a_event.x();
 70     G4double y = a_event.y();
 71     G4double dx = x-fMousePressedX;
 72     G4double dy = y-fMousePressedY;
 73     fMousePressedX = x;
 74     fMousePressedY = y;
 75 
 76     if (fMousePressed) {
 77 
 78       if (fKeyPressed && fKeyShift) {  // Translation (pan)
 79 
 80         const G4double sceneRadius = fSGSceneHandler.GetScene()->GetExtent().GetExtentRadius();
 81         const G4double scale = 300;  // Roughly pixels per window, empirically chosen
 82         const G4double dxScene = dx*sceneRadius/scale;
 83         const G4double dyScene = dy*sceneRadius/scale;
 84         fVP.IncrementPan(-dxScene,dyScene);
 85 
 86       } else {  // Rotation
 87 
 88         // Simple ad-hoc algorithms
 89         const G4Vector3D& x_prime = fVP.GetViewpointDirection().cross(fVP.GetUpVector());
 90         const G4Vector3D& y_prime = x_prime.cross(fVP.GetViewpointDirection());
 91         const G4double scale = 200;  // Roughly pixels per window, empirically chosen
 92         G4Vector3D newViewpointDirection = fVP.GetViewpointDirection();
 93         newViewpointDirection += dx*x_prime/scale;
 94         newViewpointDirection += dy*y_prime/scale;
 95         fVP.SetViewpointDirection(newViewpointDirection.unit());
 96 
 97         if (fVP.GetRotationStyle() == G4ViewParameters::freeRotation) {
 98           G4Vector3D newUpVector = fVP.GetUpVector();
 99           newUpVector += dx*x_prime/scale;
100           newUpVector += dy*y_prime/scale;
101           fVP.SetUpVector(newUpVector.unit());
102         }
103       }
104     }
105 
106     SetView();
107     DrawView();
108   }
109   virtual void wheel_rotate(const tools::sg::wheel_rotate_event& a_event) {
110     const G4double angleY = a_event.angle();
111     if (fVP.GetFieldHalfAngle() == 0.) {  // Orthographic projection
112       const G4double scale = 500;  // Empirically chosen
113       fVP.MultiplyZoomFactor(1.+angleY/scale);
114     } else {                              // Perspective projection
115       const G4double delta = fSceneHandler.GetExtent().GetExtentRadius()/200.;  // Empirical
116       fVP.SetDolly(fVP.GetDolly()+angleY*delta);
117     }
118     SetView();
119     DrawView();
120   }
121 public:
122   G4ToolsSGViewer(SG_SESSION& a_session,G4ToolsSGSceneHandler& a_scene_handler, const G4String& a_name)
123   :parent(a_scene_handler,a_scene_handler.IncrementViewCount(),a_name)
124   ,fSGSession(a_session)
125   ,fSGSceneHandler(a_scene_handler)
126   ,fSGViewer(nullptr)
127   ,fKeyPressed(false)
128   ,fKeyShift(false)
129   ,fMousePressed(false)
130   ,fMousePressedX(0)
131   ,fMousePressedY(0)
132   {
133     //::printf("debug : G4ToolsSGViewer::G4ToolsSGViewer: %lu, %s\n",this,a_name.c_str());
134     Messenger::Create();
135   }
136 
137   virtual ~G4ToolsSGViewer() {
138     //::printf("debug : G4ToolsSGViewer::~G4ToolsSGViewer: %lu\n",this);
139     //WARNING : nodes may refer f_gl2ps_mgr, f_zb_mgr (to handle gstos (for GPU) or textures), then
140     //          we have to delete them first.
141     fSGViewer->sg().clear();
142     delete fSGViewer;
143   }
144 protected:
145   G4ToolsSGViewer(const G4ToolsSGViewer& a_from)
146   :parent(a_from)
147   ,parent_interactor(a_from)
148   ,fSGSession(a_from.fSGSession)
149   ,fSGSceneHandler(a_from.fSGSceneHandler)
150   ,fSGViewer(nullptr)
151   ,fKeyPressed(false)
152   ,fKeyShift(false)
153   ,fMousePressed(false)
154   ,fMousePressedX(0)
155   ,fMousePressedY(0)
156   {}
157   G4ToolsSGViewer& operator=(const G4ToolsSGViewer&) {return *this;}
158 public:  
159   virtual void Initialise() {
160     if(fSGViewer) return; //done.
161     fVP.SetAutoRefresh(true);
162     fDefaultVP.SetAutoRefresh(true);
163     //::printf("debug : G4ToolsSGViewer::Initialise\n");
164     //////////////////////////////////////////////////////////
165     /// create the viewer, set the scene graph ///////////////
166     //////////////////////////////////////////////////////////
167     fSGViewer = new SG_VIEWER(fSGSession
168       ,fVP.GetWindowAbsoluteLocationHintX(1440)
169       ,fVP.GetWindowAbsoluteLocationHintY(900)
170       ,fVP.GetWindowSizeHintX()
171       ,fVP.GetWindowSizeHintY()
172       ,fName);
173     if(!fSGViewer->has_window()) {
174       fViewId = -1;  // This flags an error.
175       G4cerr << "G4ToolsSGViewer::Initialise : SG_VIEWER::has_window() failed." << G4endl;
176       return;
177     }
178     fSGViewer->set_device_interactor(this);
179   }
180   
181   virtual void SetView() {
182     //::printf("debug : G4ToolsSGViewer::SetView\n");
183     if(!fSceneHandler.GetScene()) {
184       fSGViewer->set_clear_color(0.3,0.3,0.3,1); //some grey color to signal the user that something is wrong.
185       G4cerr << "G4ToolsSGViewer::SetView : no G4Scene.." << G4endl;
186       return;
187     }
188 
189     //////////////////////////////////////////////////////////
190     //////////////////////////////////////////////////////////
191     //////////////////////////////////////////////////////////
192     // Get radius of scene, etc.
193     // Note that this procedure properly takes into account zoom, dolly and pan.
194     const G4Point3D targetPoint
195       = fSceneHandler.GetScene()->GetStandardTargetPoint() + fVP.GetCurrentTargetPoint ();
196     G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
197     if(radius<=0.) radius = 1.;
198     const G4double cameraDistance = fVP.GetCameraDistance (radius);
199     const G4Point3D cameraPosition = targetPoint + cameraDistance * fVP.GetViewpointDirection().unit();
200     const G4Normal3D& up = fVP.GetUpVector ();  
201     const G4double pnear  = fVP.GetNearDistance (cameraDistance, radius);
202     const G4double pfar   = fVP.GetFarDistance  (cameraDistance, pnear, radius);
203   //const G4double right  = fVP.GetFrontHalfHeight (pnear, radius);
204   //const G4double left   = -right;
205     const G4double top    = fVP.GetFrontHalfHeight (pnear, radius);
206     const G4double bottom = -top;
207     // sanity check :
208     tools::vec3f dir(float(targetPoint.x()-cameraPosition.x()),
209                      float(targetPoint.y()-cameraPosition.y()),
210                      float(targetPoint.z()-cameraPosition.z()));
211     if(!dir.length()) {
212       fSGViewer->set_clear_color(0.3,0.3,0.3,1);
213       G4cerr << "G4ToolsSGViewer::SetView : null size viewer area." << G4endl;
214       return;      
215     }
216     
217     //////////////////////////////////////////////////////////
218     //////////////////////////////////////////////////////////
219     //////////////////////////////////////////////////////////
220     /*
221     G4cout << "debug : 0002 : radius " << radius << std::endl;
222     G4cout << "debug : cameraDistance : " << cameraDistance << std::endl;
223     G4cout << "debug : fieldHalfAngle : " << fVP.GetFieldHalfAngle() << std::endl;
224     G4cout << "debug : zoomFactor : " << fVP.GetZoomFactor() << std::endl;
225     G4cout << "debug : up : " << up.x() << " " << up.y() << " " << up.z() << std::endl;
226     G4cout << "debug : targetPoint : " << targetPoint.x() << " " << targetPoint.y() << " " << targetPoint.z() << std::endl;
227     G4cout << "debug : cameraPosition : " << cameraPosition.x() << " " << cameraPosition.y() << " " << cameraPosition.z() << std::endl;
228     G4cout << "debug : camera : znear " << pnear << ", zfar " << pfar << std::endl;
229     */
230     //////////////////////////////////////////////////////////
231     /// create scene graph ///////////////////////////////////
232     //////////////////////////////////////////////////////////
233     // Set projection, then create the tools::sg camera node :
234     tools::sg::base_camera* _camera = nullptr;
235     if (fVP.GetFieldHalfAngle() <= 0.) {
236       //G4cout << "debug : camera : ortho : top " << top << " bottom " << bottom << " top-bottom " << top-bottom << std::endl;
237       if((top-bottom)<=0) {
238         fSGViewer->set_clear_color(0.3,0.3,0.3,1);
239         G4cerr << "G4ToolsSGViewer::SetView : for ortho camera, (top-bottom)<=0." << G4endl;
240         return;
241       }
242       tools::sg::ortho* ortho_camera = new tools::sg::ortho;
243       ortho_camera->height.value(float(top-bottom));
244       _camera = ortho_camera;
245     } else {
246       //G4cout << "debug : camera : perspec : heightAngle " << float(2*fVP.GetFieldHalfAngle()) << std::endl;
247       tools::sg::perspective* perspective_camera = new tools::sg::perspective;
248       perspective_camera->height_angle.value(float(2*fVP.GetFieldHalfAngle()));
249       _camera = perspective_camera;
250     }
251     
252     _camera->position.value
253       (tools::vec3f(float(cameraPosition.x()),
254         float(cameraPosition.y()),
255         float(cameraPosition.z())));
256     _camera->znear.value(float(pnear));
257     _camera->zfar.value(float(pfar));
258 
259     _camera->look_at(dir,tools::vec3f(up.x(),up.y(),up.z()));  //same logic as in G4OpenInventorViewer.
260 
261     /*
262     const G4Vector3D& lightDirection = fVP.GetLightpointDirection();
263     G4cout << "debug : lightDirection : " << lightDirection.x() << " " << lightDirection.y() << " " << lightDirection.z() << std::endl;
264     const G4Vector3D& actualLightDirection = fVP.GetActualLightpointDirection();
265     G4cout << "debug : actualLightDirection : " << actualLightDirection.x() << " " << actualLightDirection.y() << " " << actualLightDirection.z() << std::endl;
266     */
267 
268     CreateSG(_camera,fVP.GetActualLightpointDirection());
269     
270    {G4Color background = fVP.GetBackgroundColour ();
271     fSGViewer->set_clear_color(float(background.GetRed()),float(background.GetGreen()),float(background.GetBlue()),1);}
272   }
273 
274   virtual void ClearView() {}
275 
276   virtual void DrawView() {
277     if (!fNeedKernelVisit) KernelVisitDecision();
278     G4bool kernelVisitWasNeeded = fNeedKernelVisit; // Keep (ProcessView resets).
279     fLastVP = fVP;
280     ProcessView();  // Clears store and processes scene only if necessary.
281     if (kernelVisitWasNeeded) {
282       // We might need to do something if the kernel was visited.
283     } else {
284     }
285     FinishView ();       // Flush streams and/or swap buffers.
286   }
287 
288   virtual void ShowView() {FinishView();}
289 
290   virtual void FinishView() {
291     if(fSGViewer) {
292       fSGSceneHandler.TouchPlotters(fSGViewer->sg());
293       fSGViewer->show();
294       fSGViewer->win_render();
295       fSGSession.sync();
296     }
297   }
298 
299   virtual void SwitchToVisSubThread() {}
300   
301   virtual void SwitchToMasterThread() {
302     if (G4Threading::IsMultithreadedApplication()) {
303       // I have not figured out how to draw during a run.
304       //
305       // Setting fNeedKernelVisit=true causes scene deletion and a complete rebuild,
306       // including trajectories, hits, etc. from kept events.
307       //
308       // Clearly this is a limitation because even if you run 1000 events you only
309       // get those kept (default 100), and even worse, if end-if-event-action is
310       // "refresh", you only get one event (the last I think).
311       //
312       // Also, strictly, there is no need to rebuid run-duration models (detector),
313       // but a complete rebuild is the easiest way (already imeplemented).
314       //
315       // Only do this if there are end-of-event models (e.g., trajectories) that
316       // may require it.
317       if (fSceneHandler.GetScene() && fSceneHandler.GetScene()->GetEndOfEventModelList().size()) {
318         fNeedKernelVisit = true;
319         DrawView();  // Draw trajectories, etc., from kept events
320       }
321     }
322   }
323   
324   //SG_VIEWER* sg_viewer() {return fSGViewer;}
325 protected:
326   void KernelVisitDecision () {
327     if (CompareForKernelVisit(fLastVP)) {
328       NeedKernelVisit ();  // Sets fNeedKernelVisit.
329     }
330   }
331   
332   G4bool CompareForKernelVisit(G4ViewParameters& vp) {
333     // Typical comparison.  Taken from OpenInventor.
334     if (
335        (vp.GetDrawingStyle ()    != fVP.GetDrawingStyle ())    ||
336        (vp.GetNumberOfCloudPoints()  != fVP.GetNumberOfCloudPoints())  ||
337        (vp.IsAuxEdgeVisible ()   != fVP.IsAuxEdgeVisible ())   ||
338        (vp.IsCulling ()          != fVP.IsCulling ())          ||
339        (vp.IsCullingInvisible () != fVP.IsCullingInvisible ()) ||
340        (vp.IsDensityCulling ()   != fVP.IsDensityCulling ())   ||
341        (vp.IsCullingCovered ()   != fVP.IsCullingCovered ())   ||
342        (vp.GetCBDAlgorithmNumber() !=
343         fVP.GetCBDAlgorithmNumber())                           ||
344        (vp.IsSection ()          != fVP.IsSection ())          ||
345        (vp.IsCutaway ()          != fVP.IsCutaway ())          ||
346        // This assumes use of generic clipping (sectioning, slicing,
347        // DCUT, cutaway).  If a decision is made to implement locally,
348        // this will need changing.  See G4OpenGLViewer::SetView,
349        // G4OpenGLStoredViewer.cc::CompareForKernelVisit and
350        // G4OpenGLStoredSceneHander::CreateSection/CutawayPolyhedron.
351        (vp.IsExplode ()          != fVP.IsExplode ())          ||
352        (vp.GetNoOfSides ()       != fVP.GetNoOfSides ())       ||
353        (vp.GetGlobalMarkerScale()    != fVP.GetGlobalMarkerScale())    ||
354        (vp.GetGlobalLineWidthScale() != fVP.GetGlobalLineWidthScale()) ||
355        (vp.IsMarkerNotHidden ()  != fVP.IsMarkerNotHidden ())  ||
356        (vp.GetDefaultVisAttributes()->GetColour() !=
357         fVP.GetDefaultVisAttributes()->GetColour())            ||
358        (vp.GetDefaultTextVisAttributes()->GetColour() !=
359         fVP.GetDefaultTextVisAttributes()->GetColour())        ||
360        (vp.GetBackgroundColour ()!= fVP.GetBackgroundColour ())||
361        (vp.IsPicking ()          != fVP.IsPicking ())          ||
362        // Scaling for Open Inventor is done by the scene handler so it
363        // needs a kernel visit.  (In this respect, it differs from the
364        // OpenGL drivers, where it's done in SetView.)
365        (vp.GetScaleFactor ()     != fVP.GetScaleFactor ())     ||
366        (vp.GetVisAttributesModifiers() !=
367         fVP.GetVisAttributesModifiers())                       ||
368        (vp.IsSpecialMeshRendering() !=
369         fVP.IsSpecialMeshRendering())                          ||
370        (vp.GetSpecialMeshRenderingOption() !=
371         fVP.GetSpecialMeshRenderingOption())
372        )
373     return true;
374 
375     if (vp.IsDensityCulling () &&
376         (vp.GetVisibleDensity () != fVP.GetVisibleDensity ()))
377       return true;
378 
379     if (vp.GetCBDAlgorithmNumber() > 0) {
380       if (vp.GetCBDParameters().size() != fVP.GetCBDParameters().size()) return true;
381       else if (vp.GetCBDParameters() != fVP.GetCBDParameters()) return true;
382     }
383 
384     if (vp.IsSection () &&
385         (vp.GetSectionPlane () != fVP.GetSectionPlane ()))
386       return true;
387 
388     if (vp.IsCutaway ()) {
389       if (vp.GetCutawayMode() != fVP.GetCutawayMode()) return true;
390       if (vp.GetCutawayPlanes ().size () !=
391           fVP.GetCutawayPlanes ().size ()) return true;
392       for (size_t i = 0; i < vp.GetCutawayPlanes().size(); ++i)
393       if (vp.GetCutawayPlanes()[i] != fVP.GetCutawayPlanes()[i])
394         return true;
395     }
396 
397     if (vp.IsExplode () &&
398         (vp.GetExplodeFactor () != fVP.GetExplodeFactor ()))
399       return true;
400 
401     if (vp.IsSpecialMeshRendering() &&
402         (vp.GetSpecialMeshVolumes() != fVP.GetSpecialMeshVolumes()))
403       return true;
404 
405     return false;
406   }
407 //  void keyPressEvent        (KeyEvent*);
408 //  void keyReleaseEvent      (KeyEvent*);
409 //  void mouseDoubleClickEvent(MouseEvent*);
410 //  void mouseMoveEvent       (MouseEvent*);
411 //  void mousePressEvent      (MouseEvent*);
412 //  void mouseReleaseEvent    (MouseEvent*);
413 //  void wheelEvent           (WheelEvent*);
414 
415 protected:
416   void CreateSG(tools::sg::base_camera* a_camera,const G4Vector3D& a_light_dir) {
417     tools::sg::group& _parent = fSGViewer->sg();
418     _parent.clear();    
419 
420     ///////////////////////////////////////////////////
421     /// 2D scene graph: ///////////////////////////////
422     ///////////////////////////////////////////////////
423     tools::sg::separator* scene_2D = new tools::sg::separator;
424     _parent.add(scene_2D);
425     scene_2D->add(new tools::sg::noderef(fSGSceneHandler.GetTransient2DObjects()));
426     scene_2D->add(new tools::sg::noderef(fSGSceneHandler.GetPersistent2DObjects()));
427   
428     ///////////////////////////////////////////////////
429     /// 3D scene graph: ///////////////////////////////
430     ///////////////////////////////////////////////////
431     tools::sg::separator* scene_3D = new tools::sg::separator;
432     _parent.add(scene_3D);
433   
434     scene_3D->add(a_camera);
435   
436    {tools::sg::torche* light = new tools::sg::torche;
437     light->on = true;
438     light->direction = tools::vec3f(-a_light_dir.x(),-a_light_dir.y(),-a_light_dir.z());
439     light->ambient = tools::colorf(0.2f,0.2f,0.2f,1.0f);  //same as in G4OpenGLViewer.cc glLight(GL_LIGHT0,GL_AMBIENT and GL_DIFFUSE).
440     light->color = tools::colorf(0.8f,0.8f,0.8f,1.0f);    //idem.
441     scene_3D->add(light);}
442   
443    {tools::sg::blend* blend = new tools::sg::blend;
444     blend->on = true; //to handle transparency.
445     scene_3D->add(blend);}
446 
447     scene_3D->add(new tools::sg::noderef(fSGSceneHandler.GetTransient3DObjects()));
448     scene_3D->add(new tools::sg::noderef(fSGSceneHandler.GetPersistent3DObjects()));
449   }
450   
451   void Export(const G4String& a_format,const G4String& a_file,G4bool a_do_transparency) {
452     if(!fSGViewer) return;
453     const G4Colour& back_color = fVP.GetBackgroundColour();
454     bool top_to_bottom = false;  //if using tools::fpng, tools::toojpeg.
455     if(!tools::sg::write_paper(G4cout,f_gl2ps_mgr,f_zb_mgr,
456                     tools::fpng::write,tools::toojpeg::write,
457                     float(back_color.GetRed()),float(back_color.GetGreen()),float(back_color.GetBlue()),float(back_color.GetAlpha()),
458                     fSGViewer->sg(),fSGViewer->width(),fSGViewer->height(),
459                     a_file,a_format,a_do_transparency,top_to_bottom,std::string(),std::string())) {
460       G4cout << "G4ToolsSGViewer::Export: write_paper() failed." << G4endl;
461       return;
462     }
463   }
464 
465 protected:  
466   class Messenger: public G4VVisCommand {
467   public:  
468     static void Create() {static Messenger s_messenger;}
469   private:  
470     Messenger() {
471       G4UIparameter* parameter;
472       //////////////////////////////////////////////////////////
473       //////////////////////////////////////////////////////////
474       write_scene = new G4UIcommand("/vis/tsg/export", this);
475       write_scene->SetGuidance("Write the content of the current viewer in a file at various formats.");
476       write_scene->SetGuidance("Default file is out.eps and default format is gl2ps_eps.");
477       write_scene->SetGuidance("Available formats are:");
478       write_scene->SetGuidance("- gl2ps_eps: gl2ps producing eps");
479       write_scene->SetGuidance("- gl2ps_ps:  gl2ps producing ps");
480       write_scene->SetGuidance("- gl2ps_pdf: gl2ps producing pdf");
481       write_scene->SetGuidance("- gl2ps_svg: gl2ps producing svg");
482       write_scene->SetGuidance("- gl2ps_tex: gl2ps producing tex");
483       write_scene->SetGuidance("- gl2ps_pgf: gl2ps producing pgf");
484       write_scene->SetGuidance("- zb_ps: tools::sg offscreen zbuffer put in a PostScript file.");
485       write_scene->SetGuidance("- zb_png: tools::sg offscreen zbuffer put in a png file.");
486       write_scene->SetGuidance("- zb_jpeg: tools::sg offscreen zbuffer put in a jpeg file.");
487 
488       parameter = new G4UIparameter("format",'s',true);
489       parameter->SetDefaultValue("gl2ps_eps");
490       write_scene->SetParameter (parameter);
491 
492       parameter = new G4UIparameter("file",'s',true);
493       parameter->SetDefaultValue("out.eps");
494       write_scene->SetParameter (parameter);
495 
496       parameter =  new G4UIparameter ("do_transparency", 'b', true);
497       parameter->SetDefaultValue  ("true");
498       write_scene->SetParameter (parameter);
499 
500     }
501     virtual ~Messenger() {
502       delete write_scene;
503     }
504   public:
505     virtual void SetNewValue(G4UIcommand* a_cmd,G4String a_value) {
506       G4VisManager::Verbosity verbosity = GetVisManager()->GetVerbosity();
507       G4VViewer* viewer = GetVisManager()->GetCurrentViewer();
508       if (!viewer) {
509         if (verbosity >= G4VisManager::errors) G4cerr << "ERROR: No current viewer." << G4endl;
510         return;
511       }
512       G4ToolsSGViewer* tsg_viewer = dynamic_cast<G4ToolsSGViewer*>(viewer);
513       if(!tsg_viewer) {
514         G4cout << "G4ToolsSGViewer::SetNewValue:"
515                << " current viewer is not a G4ToolsSGViewer." << G4endl;
516         return;
517       }
518       std::vector<std::string> args;
519       tools::double_quotes_tokenize(a_value,args);
520       if(args.size()!=a_cmd->GetParameterEntries()) return;
521       if(a_cmd==write_scene) {
522         G4bool do_transparency = G4UIcommand::ConvertToBool(args[2].c_str());
523         tsg_viewer->Export(args[0],args[1],do_transparency);
524       }
525     }
526   private:
527     G4UIcommand* write_scene;
528   };
529   
530 protected:
531   SG_SESSION& fSGSession;
532   G4ToolsSGSceneHandler& fSGSceneHandler;
533   SG_VIEWER* fSGViewer;
534   G4ViewParameters fLastVP;  // Memory for making kernel visit decisions.
535   
536   G4bool fKeyPressed;
537   G4bool fKeyShift;
538   G4bool fMousePressed;
539   G4double fMousePressedX, fMousePressedY;
540 
541   tools::sg::zb_manager f_zb_mgr;
542   tools::sg::gl2ps_manager f_gl2ps_mgr;
543   
544 };
545 
546 #endif
547