KiCad PCB EDA Suite
c3d_model_viewer.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
5  * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
32 #include <iostream>
34 #include "c3d_model_viewer.h"
35 #include "../3d_rendering/3d_render_ogl_legacy/ogl_legacy_utils.h"
36 #include "../3d_cache/3d_cache.h"
37 #include "common_ogl/ogl_utils.h"
38 #include <wx/dcclient.h>
39 #include <base_units.h>
40 #include <gl_context_mgr.h>
41 
45 #define UNITS3D_TO_UNITSPCB (IU_PER_MM)
46 
53 const wxChar * C3D_MODEL_VIEWER::m_logTrace = wxT( "KI_TRACE_EDA_3D_MODEL_VIEWER" );
54 
55 
56 BEGIN_EVENT_TABLE( C3D_MODEL_VIEWER, wxGLCanvas )
57  EVT_PAINT( C3D_MODEL_VIEWER::OnPaint )
58 
59  // mouse events
60  EVT_LEFT_DOWN( C3D_MODEL_VIEWER::OnLeftDown )
61  EVT_LEFT_UP( C3D_MODEL_VIEWER::OnLeftUp )
62  EVT_MIDDLE_UP( C3D_MODEL_VIEWER::OnMiddleUp )
63  EVT_MIDDLE_DOWN(C3D_MODEL_VIEWER::OnMiddleDown)
64  EVT_RIGHT_DOWN( C3D_MODEL_VIEWER::OnRightClick )
65  EVT_MOUSEWHEEL( C3D_MODEL_VIEWER::OnMouseWheel )
66  EVT_MOTION( C3D_MODEL_VIEWER::OnMouseMove )
67 
68 #ifdef USE_OSX_MAGNIFY_EVENT
69  EVT_MAGNIFY( C3D_MODEL_VIEWER::OnMagnify )
70 #endif
71 
72  // other events
73  EVT_ERASE_BACKGROUND( C3D_MODEL_VIEWER::OnEraseBackground )
74 END_EVENT_TABLE()
75 
76 
77 // This defines the range that all coord will have to be rendered.
78 // It will use this value to convert to a normalized value between
79 // -(RANGE_SCALE_3D/2) .. +(RANGE_SCALE_3D/2)
80 #define RANGE_SCALE_3D 8.0f
81 
82 
84  const int *aAttribList , S3D_CACHE *aCacheManager) :
85 
86  wxGLCanvas( aParent,
87  wxID_ANY,
88  aAttribList,
89  wxDefaultPosition,
90  wxDefaultSize,
91  wxFULL_REPAINT_ON_RESIZE ),
92  m_trackBallCamera( RANGE_SCALE_3D * 2.0f ),
93  m_cacheManager(aCacheManager)
94 {
95  wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::C3D_MODEL_VIEWER" ) );
96 
97  m_ogl_initialized = false;
98  m_reload_is_needed = false;
99  m_ogl_3dmodel = NULL;
100  m_3d_model = NULL;
101  m_BiuTo3Dunits = 1.0;
102 
103  m_glRC = NULL;
104 }
105 
106 
108 {
109  wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::~C3D_MODEL_VIEWER" ) );
110 
111  if( m_glRC )
112  {
114 
115  delete m_ogl_3dmodel;
116  m_ogl_3dmodel = NULL;
117 
120  }
121 }
122 
123 
124 void C3D_MODEL_VIEWER::Set3DModel( const S3DMODEL &a3DModel )
125 {
126  wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::Set3DModel with a S3DMODEL" ) );
127 
128  // Validate a3DModel pointers
129  wxASSERT( a3DModel.m_Materials != NULL );
130  wxASSERT( a3DModel.m_Meshes != NULL );
131  wxASSERT( a3DModel.m_MaterialsSize > 0 );
132  wxASSERT( a3DModel.m_MeshesSize > 0 );
133 
134  // Delete the old model
135  delete m_ogl_3dmodel;
136  m_ogl_3dmodel = NULL;
137 
138  m_3d_model = NULL;
139 
140  if( (a3DModel.m_Materials != NULL) && (a3DModel.m_Meshes != NULL) &&
141  (a3DModel.m_MaterialsSize > 0) && (a3DModel.m_MeshesSize > 0) )
142  {
143  m_3d_model = &a3DModel;
144  m_reload_is_needed = true;
145  }
146 
147  Refresh();
148 }
149 
150 
151 void C3D_MODEL_VIEWER::Set3DModel(const wxString &aModelPathName)
152 {
153  wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::Set3DModel with a wxString" ) );
154 
155  if( m_cacheManager )
156  {
157  const S3DMODEL* model = m_cacheManager->GetModel( aModelPathName );
158 
159  if( model )
160  Set3DModel( (const S3DMODEL &)*model );
161  else
162  Clear3DModel();
163  }
164 }
165 
166 
168 {
169  // Delete the old model
170  m_reload_is_needed = false;
171 
172  delete m_ogl_3dmodel;
173  m_ogl_3dmodel = NULL;
174 
175  m_3d_model = NULL;
176 
177  Refresh();
178 }
179 
180 
182 {
183  glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
184  glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
185  glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
186 
187  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
188  glEnable( GL_DEPTH_TEST );
189  //glDepthFunc( GL_LEQUAL );
190  glEnable( GL_CULL_FACE );
191  glShadeModel( GL_SMOOTH );
192  glEnable( GL_LINE_SMOOTH );
193  glEnable( GL_NORMALIZE );
194 
195  // Setup light
196  // https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
197  // /////////////////////////////////////////////////////////////////////////
198  const GLfloat ambient[] = { 0.01f, 0.01f, 0.01f, 1.0f };
199  const GLfloat diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
200  const GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
201 
202  // defines a directional light that points along the negative z-axis
203  const GLfloat position[] = { 0.0f, 0.0f, 2.0f * RANGE_SCALE_3D, 0.0f };
204 
205  const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
206 
207  glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
208  glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
209  glLightfv( GL_LIGHT0, GL_SPECULAR, specular );
210  glLightfv( GL_LIGHT0, GL_POSITION, position );
211  glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
212 }
213 
214 
216 {
217  glEnable( GL_COLOR_MATERIAL );
218  glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
219 
220  const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
221 
222  glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
223  glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
224 }
225 
226 
227 void C3D_MODEL_VIEWER::OnPaint( wxPaintEvent &event )
228 {
229  wxPaintDC( this );
230 
231  event.Skip( false );
232 
233  // SwapBuffer requires the window to be shown before calling
234  if( !IsShownOnScreen() )
235  {
236  wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnPaint !IsShown" ) );
237  return;
238  }
239 
240  // "Makes the OpenGL state that is represented by the OpenGL rendering
241  // context context current, i.e. it will be used by all subsequent OpenGL calls.
242  // This function may only be called when the window is shown on screen"
243  if( m_glRC == NULL )
245 
247 
248  // Set the OpenGL viewport according to the client size of this canvas.
249  // This is done here rather than in a wxSizeEvent handler because our
250  // OpenGL rendering context (and thus viewport setting) is used with
251  // multiple canvases: If we updated the viewport in the wxSizeEvent
252  // handler, changing the size of one canvas causes a viewport setting that
253  // is wrong when next another canvas is repainted.
254  wxSize clientSize = GetClientSize();
255 
256  if( !m_ogl_initialized )
257  {
258  m_ogl_initialized = true;
259  ogl_initialize();
260  }
261 
262  if( m_reload_is_needed )
263  {
264  wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnPaint m_reload_is_needed" ) );
265 
266  m_reload_is_needed = false;
268 
269  // It convert a model as it was a board, so get the max size dimension of the board
270  // and compute the conversion scale
271  m_BiuTo3Dunits = (double)RANGE_SCALE_3D /
272  ( (double)m_ogl_3dmodel->GetBBox().GetMaxDimension() *
274  }
275 
276  glViewport( 0, 0, clientSize.x, clientSize.y );
277 
278  m_trackBallCamera.SetCurWindowSize( clientSize );
279 
280  // clear color and depth buffers
281  // /////////////////////////////////////////////////////////////////////////
282  glEnable( GL_DEPTH_TEST );
283 
284  glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
285  glClearDepth( 1.0f );
286  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
287 
288  // Set projection and modelview matrixes
289  // /////////////////////////////////////////////////////////////////////////
290  glMatrixMode( GL_PROJECTION );
291  glLoadMatrixf( glm::value_ptr( m_trackBallCamera.GetProjectionMatrix() ) );
292 
293  glMatrixMode( GL_MODELVIEW );
294  glLoadMatrixf( glm::value_ptr( m_trackBallCamera.GetViewMatrix() ) );
295 
296  glEnable( GL_LIGHTING );
297  glEnable( GL_LIGHT0 );
298 
299  // Render Model
300  if( m_ogl_3dmodel )
301  {
302  glPushMatrix();
303 
304  double modelunit_to_3d_units_factor = m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
305 
306  glScaled( modelunit_to_3d_units_factor,
307  modelunit_to_3d_units_factor,
308  modelunit_to_3d_units_factor );
309 
310  // Center model in the render viewport
311  const SFVEC3F model_center = m_ogl_3dmodel->GetBBox().GetCenter();
312 
313  glTranslatef( -model_center.x, -model_center.y, -model_center.z );
314 
317 
318  glPopMatrix();
319  }
320 
321 
322  // YxY squared view port
323  glViewport( 0, 0, clientSize.y / 8 , clientSize.y / 8 );
324  glClear( GL_DEPTH_BUFFER_BIT );
325 
326  glMatrixMode( GL_PROJECTION );
327  glLoadIdentity();
328  gluPerspective( 45.0f, 1.0f, 0.01f, RANGE_SCALE_3D * 2.0f );
329 
330  glMatrixMode( GL_MODELVIEW );
331  glLoadIdentity();
332 
333  const glm::mat4 TranslationMatrix = glm::translate( glm::mat4(1.0f),
334  SFVEC3F( 0.0f, 0.0f, -RANGE_SCALE_3D ) );
335 
336  const glm::mat4 ViewMatrix = TranslationMatrix * m_trackBallCamera.GetRotationMatrix();
337 
338  glLoadMatrixf( glm::value_ptr( ViewMatrix ) );
339 
341 
342  glColor3f( 0.9f, 0.0f, 0.0f );
343  OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
344  SFVEC3F( RANGE_SCALE_3D / 2.65f, 0.0f, 0.0f ),
345  0.275f );
346 
347  glColor3f( 0.0f, 0.9f, 0.0f );
348  OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
349  SFVEC3F( 0.0f, RANGE_SCALE_3D / 2.65f, 0.0f ),
350  0.275f );
351 
352  glColor3f( 0.0f, 0.0f, 0.9f );
353  OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
354  SFVEC3F( 0.0f, 0.0f, RANGE_SCALE_3D / 2.65f ),
355  0.275f );
356 
357  // "Swaps the double-buffer of this window, making the back-buffer the
358  // front-buffer and vice versa, so that the output of the previous OpenGL
359  // commands is displayed on the window."
360  SwapBuffers();
361 
363 }
364 
365 
366 void C3D_MODEL_VIEWER::OnEraseBackground( wxEraseEvent &event )
367 {
368  wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnEraseBackground" ) );
369  // Do nothing, to avoid flashing.
370 }
371 
372 
373 void C3D_MODEL_VIEWER::OnMouseWheel( wxMouseEvent &event )
374 {
375  wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnMouseWheel" ) );
376 
377  if( event.ShiftDown() )
378  {
379  //if( event.GetWheelRotation() < 0 )
380  //SetView3D( WXK_UP ); // move up
381  //else
382  //SetView3D( WXK_DOWN ); // move down
383  }
384  else if( event.ControlDown() )
385  {
386  //if( event.GetWheelRotation() > 0 )
387  //SetView3D( WXK_RIGHT ); // move right
388  //else
389  //SetView3D( WXK_LEFT ); // move left
390  }
391  else
392  {
393  m_trackBallCamera.Zoom( event.GetWheelRotation() > 0 ? 1.1f : 1/1.1f );
394 
395  //DisplayStatus();
396  Refresh( false );
397  }
398 
399  m_trackBallCamera.SetCurMousePosition( event.GetPosition() );
400 }
401 
402 
403 #ifdef USE_OSX_MAGNIFY_EVENT
404 void C3D_MODEL_VIEWER::OnMagnify( wxMouseEvent& event )
405 {
406  /*
407  double magnification = ( event.GetMagnification() + 1.0f );
408  GetPrm3DVisu().m_Zoom /= magnification;
409  if( GetPrm3DVisu().m_Zoom <= 0.01 )
410  GetPrm3DVisu().m_Zoom = 0.01;
411  DisplayStatus();
412  Refresh( false );
413  */
414 }
415 #endif
416 
417 
418 void C3D_MODEL_VIEWER::OnMouseMove( wxMouseEvent &event )
419 {
420  m_trackBallCamera.SetCurWindowSize( GetClientSize() );
421 
422  if( event.Dragging() )
423  {
424  if( event.LeftIsDown() ) // Drag
425  m_trackBallCamera.Drag( event.GetPosition() );
426  //else if( event.MiddleIsDown() ) // Pan
427  // m_trackBallCamera.Pan( event.GetPosition() );
428 
429  // orientation has changed, redraw mesh
430  Refresh( false );
431  }
432 
433  m_trackBallCamera.SetCurMousePosition( event.GetPosition() );
434 }
435 
436 
437 void C3D_MODEL_VIEWER::OnLeftDown( wxMouseEvent &event )
438 {
439  //m_is_moving_mouse = true;
440  event.Skip();
441 }
442 
443 
444 void C3D_MODEL_VIEWER::OnLeftUp( wxMouseEvent &event )
445 {
446  //m_is_moving_mouse = false;
447  //Refresh( false );
448  event.Skip();
449 }
450 
451 
452 void C3D_MODEL_VIEWER::OnMiddleDown( wxMouseEvent &event )
453 {
454  //m_is_moving_mouse = true;
455  event.Skip();
456 }
457 
458 
459 void C3D_MODEL_VIEWER::OnMiddleUp( wxMouseEvent &event )
460 {
461  //m_is_moving_mouse = false;
462  //Refresh( false );
463  event.Skip();
464 }
465 
466 
467 void C3D_MODEL_VIEWER::OnRightClick( wxMouseEvent &event )
468 {
469  event.Skip();
470 }
471 
const S3DMODEL * m_3d_model
Original 3d model data.
bool m_reload_is_needed
Flag that we have a new model and it need to be reloaded when the paint is called.
#define UNITS3D_TO_UNITSPCB
Scale convertion from 3d model units to pcb units.
implement a legacy 3dmodel render
wxGLContext * m_glRC
openGL context
void OnMiddleDown(wxMouseEvent &event)
Implementation of conversion functions that require both schematic and board internal units...
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
glm::vec4 SFVEC4F
Definition: xv3d_types.h:49
void OnLeftDown(wxMouseEvent &event)
void OnMouseWheel(wxMouseEvent &event)
const glm::mat4 & GetProjectionMatrix() const
Definition: ccamera.cpp:359
const glm::mat4 & GetViewMatrix() const
Definition: ccamera.cpp:389
void Draw_transparent() const
Draw_transparent - render the model into the current context.
void Draw_opaque() const
Draw_opaque - render the model into the current context.
void OnMiddleUp(wxMouseEvent &event)
Class C3D_MODEL_VIEWER Implement a canvas based on a wxGLCanvas.
#define RANGE_SCALE_3D
void UnlockCtx(wxGLContext *aContext)
Function UnlockCtx allows other canvases to bind an OpenGL context.
SMESH * m_Meshes
The meshes list of this model.
Definition: c3dmodel.h:93
float GetMaxDimension() const
GetMaxDimension.
Definition: cbbox.cpp:169
void SetCurMousePosition(const wxPoint &aPosition)
It updates the current mouse position without make any new recalculations on camera.
Definition: ccamera.cpp:401
S3DMODEL * GetModel(const wxString &aModelFileName)
Function GetModel attempts to load the scene data for a model and to translate it into an S3D_MODEL s...
Definition: 3d_cache.cpp:781
bool Zoom(float aFactor)
Definition: ccamera.cpp:454
const CBBOX & GetBBox() const
GetBBox - Get main bbox.
Definition: c_ogl_3dmodel.h:85
C3D_MODEL_VIEWER(wxWindow *aParent, const int *aAttribList=0, S3D_CACHE *aCacheManager=NULL)
Creates a new 3D Canvas with a attribute list.
static GL_CONTEXT_MANAGER & Get()
Function Get returns the GL_CONTEXT_MANAGER instance (singleton).
void Refresh()
Update the board display after modifying it bu a python script (note: it is automatically called by a...
Implements a model viewer canvas.
void OnRightClick(wxMouseEvent &event)
void Set3DModel(const S3DMODEL &a3DModel)
Set3DModel - Set this model to be displayed.
EVT_MIDDLE_DOWN(mpWindow::OnMouseMiddleDown) EVT_MOUSEWHEEL(mpWindow
Definition: mathplot.cpp:1724
double m_BiuTo3Dunits
factor to convert the model or any other items to keep it in relation to the +/-RANGE_SCALE_3D (it is...
S3D_CACHE * m_cacheManager
Optional cache manager.
bool SetCurWindowSize(const wxSize &aSize)
SetCurWindowSize - update the windows size of the camera.
Definition: ccamera.cpp:428
unsigned int m_MaterialsSize
Number of materials in the material array.
Definition: c3dmodel.h:95
void Drag(const wxPoint &aNewMousePosition) override
Calculate a new mouse drag position.
Definition: ctrack_ball.cpp:51
void LockCtx(wxGLContext *aContext, wxGLCanvas *aCanvas)
Function LockCtx sets a context as current and prevents other canvases from switching it...
SFVEC3F GetCenter() const
Function GetCenter return the center point of the bounding box.
Definition: cbbox.cpp:135
Use all material properties from model file.
Definition: 3d_enums.h:93
glm::vec3 SFVEC3F
Definition: xv3d_types.h:47
void OnLeftUp(wxMouseEvent &event)
const glm::mat4 GetRotationMatrix() const
Function GetRotationMatrix Get the rotation matrix to be applied in a transformation camera...
Definition: ccamera.cpp:130
SMATERIAL * m_Materials
The materials list of this model.
Definition: c3dmodel.h:96
implements generic openGL functions that are common to any openGL target
void OnEraseBackground(wxEraseEvent &event)
void OnMouseMove(wxMouseEvent &event)
void DestroyCtx(wxGLContext *aContext)
Function DestroyCtx destroys a managed OpenGL context.
Store the a model based on meshes and materials.
Definition: c3dmodel.h:90
void Clear3DModel()
Clear3DModel - Unloads the displayed 3d model.
bool m_ogl_initialized
Flag if open gl was initialized.
void OnPaint(wxPaintEvent &event)
wxGLContext * CreateCtx(wxGLCanvas *aCanvas, const wxGLContext *aOther=NULL)
Function CreateCtx creates a managed OpenGL context.
C_OGL_3DMODEL * m_ogl_3dmodel
Class holder for 3d model to display on openGL.
unsigned int m_MeshesSize
Number of meshes in the array.
Definition: c3dmodel.h:92
CTRACK_BALL m_trackBallCamera
Camera used in this canvas.
void OGL_draw_arrow(SFVEC3F aPosition, SFVEC3F aTargetPos, float aSize)
OGL_draw_arrow - draw a round arrow.