27#include <wx/tokenzr.h>
53#include <fmt/format.h>
105 wxDefaultSize, wxFULL_REPAINT_ON_RESIZE ),
110 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::EDA_3D_CANVAS" ) );
128 auto busy_indicator_factory =
131 return std::make_unique<WX_BUSY_INDICATOR>();
143 wxASSERT( a3DCachePointer !=
nullptr );
146#if defined( __WXMSW__ )
147 EnableTouchEvents( wxTOUCH_ZOOM_GESTURE | wxTOUCH_ROTATE_GESTURE | wxTOUCH_PAN_GESTURES );
148#elif defined( __WXGTK__ )
149 EnableTouchEvents( wxTOUCH_ZOOM_GESTURE | wxTOUCH_ROTATE_GESTURE );
152 const wxEventType events[] =
158 wxEVT_LEFT_UP, wxEVT_LEFT_DOWN, wxEVT_LEFT_DCLICK,
159 wxEVT_RIGHT_UP, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_DCLICK,
160 wxEVT_MIDDLE_UP, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_DCLICK,
161 wxEVT_MOTION, wxEVT_MOUSEWHEEL, wxEVT_CHAR, wxEVT_CHAR_HOOK,
163 wxEVT_MENU_OPEN, wxEVT_MENU_CLOSE, wxEVT_MENU_HIGHLIGHT
166 for( wxEventType eventType : events )
173 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::~EDA_3D_CANVAS" ) );
221 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::initializeOpenGL" ) );
223 const GLenum err = glewInit();
227 const wxString msgError = (
const char*) glewGetErrorString( err );
229 wxLogMessage( msgError );
235 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::initializeOpenGL Using GLEW version %s" ),
236 From_UTF8( (
char*) glewGetString( GLEW_VERSION ) ) );
239 SetOpenGLInfo( (
const char*) glGetString( GL_VENDOR ), (
const char*) glGetString( GL_RENDERER ),
240 (
const char*) glGetString( GL_VERSION ) );
242 wxString version =
From_UTF8( (
char *) glGetString( GL_VERSION ) );
244 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::%s OpenGL version string %s." ),
245 __WXFUNCTION__, version );
251 wxStringTokenizer tokenizer( version,
" \t\r\n" );
253 if( tokenizer.HasMoreTokens() )
258 tmp = tokenizer.GetNextToken();
260 tokenizer.SetString( tmp, wxString( wxT(
"." ) ) );
262 if( tokenizer.HasMoreTokens() )
263 tokenizer.GetNextToken().ToLong( &major );
265 if( tokenizer.HasMoreTokens() )
266 tokenizer.GetNextToken().ToLong( &minor );
268 if( major < 2 || ( ( major == 2 ) && ( minor < 1 ) ) )
270 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::%s OpenGL ray tracing not supported." ),
276 GetParent()->ProcessWindowEvent( evt );
282 if( ( major == 1 ) && ( minor < 5 ) )
284 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::%s OpenGL not supported." ),
306 if( aCachePointer !=
nullptr )
309 if( aBoard !=
nullptr )
338 msg.Printf( wxT(
"dx %3.2f" ),
m_camera.GetCameraPos().x );
341 msg.Printf( wxT(
"dy %3.2f" ),
m_camera.GetCameraPos().y );
344 msg.Printf( wxT(
"zoom %3.2f" ), 1 /
m_camera.GetZoom() );
364 if( !IsShownOnScreen() )
366 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::DoRePaint !IsShown" ) );
377 if( !GetParent()->GetParent()->IsShownOnScreen() )
380 wxString err_messages;
413 const bool windows_size_changed =
m_camera.SetCurWindowSize( clientSize );
428 warningReporter.
Report(
_(
"Your OpenGL version is not supported. Minimum required "
437 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
438 glClear( GL_COLOR_BUFFER_BIT );
459 const bool was_camera_changed =
m_camera.ParametersChanged();
464 || windows_size_changed )
472 float curtime_delta_s = 0.0f;
478 curtime_delta_s =
static_cast<float>(
static_cast<double>( curtime_delta ) / 1e6 )
480 m_camera.Interpolate( curtime_delta_s );
482 if( curtime_delta_s > 1.0f )
498 bool requested_redraw =
false;
506 bool reloadRaytracingForCalculations =
false;
511 reloadRaytracingForCalculations =
true;
515 &activityReporter, &warningReporter );
524 if( reloadRaytracingForCalculations )
527 catch( std::runtime_error& )
564 activityReporter.
Report( wxString::Format(
_(
"Last render time %.0f ms" ),
565 calculation_time ) );
573 if( !err_messages.IsEmpty() )
574 wxLogMessage( err_messages );
587 int index =
static_cast<int>( selectedGizmoSphere );
588 if( index >= 0 && index <
static_cast<int>( viewTable.size() ) )
605 if( !buffer || width <= 0 || height <= 0 )
613 if( !GetParent() || !GetParent()->GetParent() || !GetParent()->GetParent()->IsShownOnScreen() )
619 wxString err_messages;
629 wxLogError(
_(
"OpenGL context creation error" ) );
637 GLuint framebuffer = 0;
638 GLuint colorTexture = 0;
639 GLuint depthBuffer = 0;
640 GLint oldFramebuffer = 0;
641 GLint oldViewport[4];
644 glGetIntegerv( GL_FRAMEBUFFER_BINDING, &oldFramebuffer );
645 glGetIntegerv( GL_VIEWPORT, oldViewport );
648 glGenFramebuffers( 1, &framebuffer );
649 glBindFramebuffer( GL_FRAMEBUFFER, framebuffer );
652 glGenTextures( 1, &colorTexture );
653 glBindTexture( GL_TEXTURE_2D, colorTexture );
654 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr );
655 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
656 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
657 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
658 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
659 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0 );
662 glGenRenderbuffers( 1, &depthBuffer );
663 glBindRenderbuffer( GL_RENDERBUFFER, depthBuffer );
664 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height );
665 glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer );
667 auto resetState = std::unique_ptr<void, std::function<void(
void*)>>(
668 reinterpret_cast<void*
>(1),
670 glBindFramebuffer( GL_FRAMEBUFFER, oldFramebuffer );
671 glViewport( oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3] );
672 glDeleteFramebuffers( 1, &framebuffer );
673 glDeleteTextures( 1, &colorTexture );
674 glDeleteRenderbuffers( 1, &depthBuffer );
681 GLenum framebufferStatus = glCheckFramebufferStatus( GL_FRAMEBUFFER );
683 if( framebufferStatus != GL_FRAMEBUFFER_COMPLETE )
685 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::RenderToFrameBuffer Framebuffer incomplete: 0x%04X" ),
692 glViewport( 0, 0, width, height );
695 wxSize clientSize( width, height );
696 const bool windows_size_changed =
m_camera.SetCurWindowSize( clientSize );
703 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::RenderToFrameBuffer OpenGL initialization failed." ) );
709 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::RenderToFrameBuffer OpenGL version not supported." ) );
715 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
716 glClear( GL_COLOR_BUFFER_BIT );
719 glReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
733 const bool was_camera_changed =
m_camera.ParametersChanged();
744 float curtime_delta_s = 0.0f;
748 curtime_delta_s =
static_cast<float>(
static_cast<double>( curtime_delta ) / 1e6 )
750 m_camera.Interpolate( curtime_delta_s );
752 if( curtime_delta_s > 1.0f )
761 bool requested_redraw =
false;
768 bool reloadRaytracingForCalculations =
false;
772 reloadRaytracingForCalculations =
true;
775 requested_redraw =
m_3d_render->Redraw(
false,
nullptr,
nullptr );
777 if( reloadRaytracingForCalculations )
780 catch( std::runtime_error& )
791 glReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
794 GLenum error = glGetError();
795 if( error != GL_NO_ERROR )
797 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::RenderToFrameBuffer OpenGL error: 0x%04X" ), error );
798 err_messages += wxString::Format(
_(
"OpenGL error during off-screen rendering: 0x%04X\n" ), error );
804 if( !err_messages.IsEmpty() )
805 wxLogMessage( err_messages );
828 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::OnEraseBackground" ) );
835 wxLogTrace(
m_logTrace, wxT(
"EDA_3D_CANVAS::OnMouseWheel" ) );
858 float magnification = (
event.GetMagnification() + 1.0f );
871 if( aEvent.IsGestureStart() )
874 m_camera.SetCurMousePosition( aEvent.GetPosition() );
882 m_camera.Pan( aEvent.GetPosition() );
883 m_camera.SetCurMousePosition( aEvent.GetPosition() );
898 if( aEvent.IsGestureStart() )
899 m_camera.SetCurMousePosition( aEvent.GetPosition() );
904 m_camera.Pan( aEvent.GetPosition() );
905 m_camera.SetCurMousePosition( aEvent.GetPosition() );
916 if( aEvent.IsGestureStart() )
919 m_camera.SetCurMousePosition( aEvent.GetPosition() );
962 return wxString::Format(
_(
"Net %s\tNet class %s" ), aItem->GetNet()->GetNetname(),
963 aItem->GetNet()->GetNetClass()->GetHumanReadableName() );
978 switch( rollOverItem->
Type() )
982 PAD*
pad =
static_cast<PAD*
>( rollOverItem );
984 if( !
pad->GetNumber().IsEmpty() )
985 msg += wxString::Format(
_(
"Pad %s\t" ),
pad->GetNumber() );
987 if(
pad->IsOnCopperLayer() )
988 msg += printNetInfo(
pad );
1005 msg += printNetInfo( track );
1011 ZONE* zone =
static_cast<ZONE*
>( rollOverItem );
1016 msg += wxString::Format(
_(
"Rule area %s\t" ), zone->
GetZoneName() );
1018 msg += wxString::Format(
_(
"Zone %s\t" ), zone->
GetZoneName() );
1022 msg += printNetInfo( zone );
1041 reporter.
Report( wxEmptyString );
1066 if( intersectedBoardItem )
1070 switch( intersectedBoardItem->
Type() )
1073 footprint =
static_cast<FOOTPRINT*
>( intersectedBoardItem );
1077 footprint =
static_cast<PAD*
>( intersectedBoardItem )->GetParentFootprint();
1081 footprint =
static_cast<PCB_FIELD*
>( intersectedBoardItem )->GetParentFootprint();
1097 std::string command = fmt::format(
"$SELECT: 0,F{}",
1120 wxSize logicalSize = GetClientSize();
1121 int logicalW = logicalSize.GetWidth();
1122 int logicalH = logicalSize.GetHeight();
1124 int gizmo_x = 0, gizmo_y = 0, gizmo_width = 0, gizmo_height = 0;
1125 std::tie( gizmo_x, gizmo_y, gizmo_width, gizmo_height ) =
m_3d_render_opengl->getGizmoViewport();
1127 float scaleX =
static_cast<float>(
static_cast<double>( gizmo_width ) /
static_cast<double>( logicalW ) );
1128 float scaleY =
static_cast<float>(
static_cast<double>( gizmo_height ) /
static_cast<double>( logicalH ) );
1130 int scaledMouseX =
static_cast<int>(
static_cast<float>(
event.GetX() ) * scaleX );
1131 int scaledMouseY =
static_cast<int>(
static_cast<float>( logicalH -
event.GetY() ) * scaleY );
1233 if( aRedrawImmediately )
1240 wxPostEvent(
this, redrawEvent );
1252 wxASSERT( aMovingSpeed > FLT_EPSILON );
1292 m_camera.SetLookAtPos_T1( mouseRay.
at( hit_t ) );
1306 const float arrow_moving_time_speed = 8.0f;
1308 switch( aRequestedView )
1374 m_camera.ViewCommand_T1( aRequestedView );
1382 m_camera.ViewCommand_T1( aRequestedView );
1396 switch( cfg->m_Render.engine )
1419 m_camera.MakeRayAtCurrentMousePosition( rayOrigin, rayDir );
1422 mouseRay.
Init( rayOrigin, rayDir );
void SetOpenGLInfo(const char *aVendor, const char *aRenderer, const char *aVersion)
A setter for OpenGL info when it's initialized.
Helper class to handle information needed to display 3D board.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Information pertinent to a Pcbnew printed circuit board.
A class used to derive camera objects from.
Implement a canvas based on a wxGLCanvas.
RENDER_3D_OPENGL * m_3d_render_opengl
TOOL_DISPATCHER * m_eventDispatcher
void OnEvent(wxEvent &aEvent)
Used to forward events to the canvas from popups, etc.
void OnMagnify(wxMouseEvent &event)
void restart_editingTimeOut_Timer()
Reset the editing timer.
void RenderToFrameBuffer(unsigned char *aBuffer, int aWidth, int aHeight)
BOARD_ITEM * m_currentRollOverItem
RENDER_3D_BASE * m_3d_render
bool m_is_opengl_initialized
void OnResize(wxSizeEvent &event)
bool m_render3dmousePivot
void OnMouseWheel(wxMouseEvent &event)
WX_INFOBAR * m_parentInfoBar
wxTimer m_editing_timeout_timer
int64_t m_strtime_camera_movement
void OnLeftDown(wxMouseEvent &event)
void OnPanGesture(wxPanGestureEvent &event)
void OnRightUp(wxMouseEvent &event)
ACCELERATOR_3D * m_accelerator3DShapes
void OnTimerTimeout_Redraw(wxTimerEvent &event)
wxStatusBar * m_parentStatusBar
void DoRePaint()
The actual function to repaint the canvas.
void OnRightDown(wxMouseEvent &event)
int m_moving_speed_multiplier
bool m_is_opengl_version_supported
wxTimer m_redraw_trigger_timer
BOARD_ADAPTER & m_boardAdapter
void DisplayStatus()
Update the status bar with the position information.
void render3dmousePivot(float aScale)
Render the 3dmouse pivot cursor.
void OnPaint(wxPaintEvent &aEvent)
void RenderRaytracingRequest()
Request to render the current view in Raytracing mode.
void SetEventDispatcher(TOOL_DISPATCHER *aEventDispatcher)
Set a dispatcher that processes events and forwards them to tools.
bool m_render_raytracing_was_requested
float m_camera_moving_speed
void OnLeftUp(wxMouseEvent &event)
void ReloadRequest(BOARD *aBoard=nullptr, S3D_CACHE *aCachePointer=nullptr)
RAY getRayAtCurrentMousePosition()
double m_gestureLastZoomFactor
Used to track gesture events.
void OnCloseWindow(wxCloseEvent &event)
bool SetView3D(VIEW3D_TYPE aRequestedView)
Select a specific 3D view or operation.
void OnMiddleDown(wxMouseEvent &event)
void GetScreenshot(wxImage &aDstImage)
Request a screenshot and output it to the aDstImage.
RENDER_3D_RAYTRACE_GL * m_3d_render_raytracing
void OnZoomGesture(wxZoomGestureEvent &event)
void OnMiddleUp(wxMouseEvent &event)
void render_pivot(float t, float aScale)
Render the pivot cursor.
void request_start_moving_camera(float aMovingSpeed=2.0f, bool aRenderPivot=true)
Start a camera movement.
void RenderEngineChanged()
Notify that the render engine was changed.
std::atomic_flag m_is_currently_painting
void OnRefreshRequest(wxEvent &aEvent)
void OnEraseBackground(wxEraseEvent &event)
void releaseOpenGL()
Free created targets and openGL context.
void Request_refresh(bool aRedrawImmediately=true)
Schedule a refresh update of the canvas.
bool m_opengl_supports_raytracing
~EDA_3D_CANVAS() override
void OnMouseMove(wxMouseEvent &event)
void OnRotateGesture(wxRotateGestureEvent &event)
EDA_3D_CANVAS(wxWindow *aParent, const wxGLAttributes &aGLAttribs, BOARD_ADAPTER &aSettings, CAMERA &aCamera, S3D_CACHE *a3DCachePointer)
Create a new 3D Canvas with an attribute list.
void move_pivot_based_on_cur_mouse_position()
This function hits a ray to the board and start a movement.
double m_gestureLastAngle
void OnTimerTimeout_Editing(wxTimerEvent &event)
void stop_editingTimeOut_Timer()
Stop the editing time so it will not timeout.
Create and handle a window for the 3d viewer connected to a Kiway and a pcbboard.
KICAD_T Type() const
Returns the type of object.
void UnlockCtx(wxGLContext *aContext)
Allow other canvases to bind an OpenGL context.
void DestroyCtx(wxGLContext *aContext)
Destroy a managed OpenGL context.
void LockCtx(wxGLContext *aContext, wxGLCanvas *aCanvas)
Set a context as current and prevents other canvases from switching it.
wxGLContext * CreateCtx(wxGLCanvas *aCanvas, const wxGLContext *aOther=nullptr)
Create a managed OpenGL context.
static int SetSwapInterval(int aVal)
Attempt to set the OpenGL swap interval.
Provides basic 3D controls ( zoom, rotate, translate, ... )
static const float m_delta_move_step_factor
HIDPI_GL_3D_CANVAS(const KIGFX::VC_SETTINGS &aVcSettings, CAMERA &aCamera, wxWindow *parent, const wxGLAttributes &aGLAttribs, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=0, const wxString &name=wxGLCanvasName, const wxPalette &palette=wxNullPalette)
void OnMouseWheelCamera(wxMouseEvent &event, bool aPan)
void OnMouseMoveCamera(wxMouseEvent &event)
virtual wxSize GetNativePixelSize() const
A wrapper for reporting to a WX_INFOBAR UI element.
void Finalize()
Update the infobar with the reported text.
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr)
Send aPayload to aDestination from aSource.
GL_CONTEXT_MANAGER * GetGLContextManager()
Object to render the board using openGL.
Cache for storing the 3D shapes.
GizmoSphereSelection
Enum to indicate which sphere (direction) is selected.
@ Count
Number of selectable spheres.
A wrapper for reporting to a specific text location in a statusbar.
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
Handle a list of polygons defining a copper zone.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
const wxString & GetZoneName() const
bool IsOnCopperLayer() const override
wxDEFINE_EVENT(wxEVT_REFRESH_CUSTOM_COMMAND, wxEvent)
Declaration of the eda_3d_viewer class.
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
This file contains miscellaneous commonly used macros and functions.
void OglGetScreenshot(wxImage &aDstImage)
Get the pixel data of current OpenGL image.
Define generic OpenGL functions that are common to any OpenGL target.
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
PGM_BASE & Pgm()
The global program "get" accessor.
int64_t GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
T * GetAppSettings(const char *aFilename)
wxString From_UTF8(const char *cstring)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
void Init(const SFVEC3F &o, const SFVEC3F &d)
SFVEC3F at(float t) const
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_ZONE_T
class ZONE, a copper pour area
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)