ADDED: PCB 3D image raytracing rendering from CLI.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/3691
This commit is contained in:
parent
7721bdc441
commit
f6f0b9a661
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2023 CERN
|
||||
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -32,7 +32,7 @@
|
|||
#include "../3d_rendering/raytracing/accelerators/container_3d.h"
|
||||
#include "../3d_rendering/raytracing/shapes3D/bbox_3d.h"
|
||||
#include <gal/3d/camera.h>
|
||||
#include "../3d_enums.h"
|
||||
#include <3d_enums.h>
|
||||
#include "../3d_cache/3d_cache.h"
|
||||
#include "../common_ogl/ogl_attr_list.h"
|
||||
#include "../3d_viewer/eda_3d_viewer_settings.h"
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "../common_ogl/ogl_utils.h"
|
||||
#include "eda_3d_canvas.h"
|
||||
#include <eda_3d_viewer_frame.h>
|
||||
#include <3d_rendering/raytracing/render_3d_raytrace.h>
|
||||
#include <3d_rendering/raytracing/render_3d_raytrace_gl.h>
|
||||
#include <3d_rendering/opengl/render_3d_opengl.h>
|
||||
#include <3d_viewer_id.h>
|
||||
#include <advanced_config.h>
|
||||
|
@ -119,7 +119,7 @@ EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow* aParent, const wxGLAttributes& aGLAttrib
|
|||
|
||||
m_is_currently_painting.clear();
|
||||
|
||||
m_3d_render_raytracing = new RENDER_3D_RAYTRACE( this, m_boardAdapter, m_camera );
|
||||
m_3d_render_raytracing = new RENDER_3D_RAYTRACE_GL( this, m_boardAdapter, m_camera );
|
||||
m_3d_render_opengl = new RENDER_3D_OPENGL( this, m_boardAdapter, m_camera );
|
||||
|
||||
wxASSERT( m_3d_render_raytracing != nullptr );
|
||||
|
@ -979,66 +979,24 @@ bool EDA_3D_CANVAS::SetView3D( VIEW3D_TYPE aRequestedView )
|
|||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_RIGHT:
|
||||
m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
|
||||
m_camera.SetT0_and_T1_current_T();
|
||||
m_camera.Reset_T1();
|
||||
m_camera.RotateZ_T1( glm::radians( -90.0f ) );
|
||||
m_camera.RotateX_T1( glm::radians( -90.0f ) );
|
||||
request_start_moving_camera();
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_LEFT:
|
||||
m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
|
||||
m_camera.SetT0_and_T1_current_T();
|
||||
m_camera.Reset_T1();
|
||||
m_camera.RotateZ_T1( glm::radians( 90.0f ) );
|
||||
m_camera.RotateX_T1( glm::radians( -90.0f ) );
|
||||
request_start_moving_camera();
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_FRONT:
|
||||
m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
|
||||
m_camera.SetT0_and_T1_current_T();
|
||||
m_camera.Reset_T1();
|
||||
m_camera.RotateX_T1( glm::radians( -90.0f ) );
|
||||
request_start_moving_camera();
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_BACK:
|
||||
case VIEW3D_TYPE::VIEW3D_FLIP:
|
||||
m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
|
||||
m_camera.SetT0_and_T1_current_T();
|
||||
m_camera.Reset_T1();
|
||||
m_camera.RotateX_T1( glm::radians( -90.0f ) );
|
||||
|
||||
// The rotation angle should be 180.
|
||||
// We use 179.999 (180 - epsilon) to avoid a full 360 deg rotation when
|
||||
// using 180 deg if the previous rotated position was already 180 deg
|
||||
m_camera.RotateZ_T1( glm::radians( 179.999f ) );
|
||||
m_camera.ViewCommand_T1( aRequestedView );
|
||||
request_start_moving_camera();
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_TOP:
|
||||
m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
|
||||
m_camera.SetT0_and_T1_current_T();
|
||||
m_camera.Reset_T1();
|
||||
request_start_moving_camera( glm::min( glm::max( m_camera.GetZoom(), 0.5f ), 1.125f ) );
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_BOTTOM:
|
||||
m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
|
||||
m_camera.SetT0_and_T1_current_T();
|
||||
m_camera.Reset_T1();
|
||||
m_camera.RotateY_T1( glm::radians( 179.999f ) ); // Rotation = 180 - epsilon
|
||||
m_camera.ViewCommand_T1( aRequestedView );
|
||||
request_start_moving_camera( glm::min( glm::max( m_camera.GetZoom(), 0.5f ), 1.125f ) );
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_FLIP:
|
||||
m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER );
|
||||
m_camera.SetT0_and_T1_current_T();
|
||||
m_camera.RotateY_T1( glm::radians( 179.999f ) );
|
||||
request_start_moving_camera();
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -38,7 +38,7 @@
|
|||
class WX_INFOBAR;
|
||||
class wxStatusBar;
|
||||
class BOARD;
|
||||
class RENDER_3D_RAYTRACE;
|
||||
class RENDER_3D_RAYTRACE_GL;
|
||||
class RENDER_3D_OPENGL;
|
||||
|
||||
|
||||
|
@ -97,7 +97,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the current render ( a RENDER_3D_RAYTRACE* or a RENDER_3D_OPENGL* render )
|
||||
* @return the current render ( a RENDER_3D_RAYTRACE_GL* or a RENDER_3D_OPENGL* render )
|
||||
*/
|
||||
RENDER_3D_BASE* GetCurrentRender() const { return m_3d_render; }
|
||||
|
||||
|
@ -311,7 +311,7 @@ private:
|
|||
|
||||
BOARD_ADAPTER& m_boardAdapter; // Pre-computed 3D info and settings
|
||||
RENDER_3D_BASE* m_3d_render;
|
||||
RENDER_3D_RAYTRACE* m_3d_render_raytracing;
|
||||
RENDER_3D_RAYTRACE_GL* m_3d_render_raytracing;
|
||||
RENDER_3D_OPENGL* m_3d_render_opengl;
|
||||
|
||||
bool m_opengl_supports_raytracing;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2020 Oleg Endo <olegendo@gcc.gnu.org>
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -30,7 +30,7 @@
|
|||
#include <plugins/3dapi/c3dmodel.h>
|
||||
#include "../../common_ogl/openGL_includes.h"
|
||||
#include "../raytracing/shapes3D/bbox_3d.h"
|
||||
#include "../../3d_enums.h"
|
||||
#include <3d_enums.h>
|
||||
|
||||
#include <wx/chartype.h>
|
||||
|
||||
|
|
|
@ -47,7 +47,8 @@
|
|||
|
||||
RENDER_3D_OPENGL::RENDER_3D_OPENGL( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& aAdapter,
|
||||
CAMERA& aCamera ) :
|
||||
RENDER_3D_BASE( aCanvas, aAdapter, aCamera )
|
||||
RENDER_3D_BASE( aAdapter, aCamera ),
|
||||
m_canvas( aCanvas )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "RENDER_3D_OPENGL::RENDER_3D_OPENGL" ) );
|
||||
|
||||
|
@ -454,7 +455,7 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
|||
REPORTER* aWarningReporter )
|
||||
{
|
||||
// Initialize OpenGL
|
||||
if( !m_is_opengl_initialized )
|
||||
if( !m_canvasInitialized )
|
||||
{
|
||||
if( !initializeOpenGL() )
|
||||
return false;
|
||||
|
@ -823,7 +824,7 @@ bool RENDER_3D_OPENGL::initializeOpenGL()
|
|||
|
||||
// Use this mode if you want see the triangle lines (debug proposes)
|
||||
//glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
|
||||
m_is_opengl_initialized = true;
|
||||
m_canvasInitialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -208,6 +208,8 @@ private:
|
|||
SMATERIAL m_GrayMaterial;
|
||||
} m_materials;
|
||||
|
||||
EDA_3D_CANVAS* m_canvas;
|
||||
|
||||
MAP_OGL_DISP_LISTS m_layers;
|
||||
OPENGL_RENDER_LIST* m_platedPadsFront;
|
||||
OPENGL_RENDER_LIST* m_platedPadsBack;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "render_3d_raytrace.h"
|
||||
#include "render_3d_raytrace_base.h"
|
||||
#include "shapes3D/plane_3d.h"
|
||||
#include "shapes3D/round_segment_3d.h"
|
||||
#include "shapes3D/layer_item_3d.h"
|
||||
|
@ -72,7 +72,7 @@ static float TransparencyControl( float aGrayColorValue, float aTransparency )
|
|||
#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::setupMaterials()
|
||||
void RENDER_3D_RAYTRACE_BASE::setupMaterials()
|
||||
{
|
||||
MATERIAL::SetDefaultRefractionRayCount( m_boardAdapter.m_Cfg->m_Render.raytrace_nrsamples_refractions );
|
||||
MATERIAL::SetDefaultReflectionRayCount( m_boardAdapter.m_Cfg->m_Render.raytrace_nrsamples_reflections );
|
||||
|
@ -176,7 +176,7 @@ void RENDER_3D_RAYTRACE::setupMaterials()
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::createObject( CONTAINER_3D& aDstContainer, const OBJECT_2D* aObject2D,
|
||||
void RENDER_3D_RAYTRACE_BASE::createObject( CONTAINER_3D& aDstContainer, const OBJECT_2D* aObject2D,
|
||||
float aZMin, float aZMax, const MATERIAL* aMaterial,
|
||||
const SFVEC3F& aObjColor )
|
||||
{
|
||||
|
@ -227,7 +227,7 @@ void RENDER_3D_RAYTRACE::createObject( CONTAINER_3D& aDstContainer, const OBJECT
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::createItemsFromContainer( const BVH_CONTAINER_2D* aContainer2d,
|
||||
void RENDER_3D_RAYTRACE_BASE::createItemsFromContainer( const BVH_CONTAINER_2D* aContainer2d,
|
||||
PCB_LAYER_ID aLayer_id,
|
||||
const MATERIAL* aMaterialLayer,
|
||||
const SFVEC3F& aLayerColor,
|
||||
|
@ -358,7 +358,7 @@ void RENDER_3D_RAYTRACE::createItemsFromContainer( const BVH_CONTAINER_2D* aCont
|
|||
extern void buildBoardBoundingBoxPoly( const BOARD* aBoard, SHAPE_POLY_SET& aOutline );
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::Reload( REPORTER* aStatusReporter, REPORTER* aWarningReporter,
|
||||
void RENDER_3D_RAYTRACE_BASE::Reload( REPORTER* aStatusReporter, REPORTER* aWarningReporter,
|
||||
bool aOnlyLoadCopperAndShapes )
|
||||
{
|
||||
m_reloadRequested = false;
|
||||
|
@ -962,7 +962,7 @@ void RENDER_3D_RAYTRACE::Reload( REPORTER* aStatusReporter, REPORTER* aWarningRe
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::insertHole( const PCB_VIA* aVia )
|
||||
void RENDER_3D_RAYTRACE_BASE::insertHole( const PCB_VIA* aVia )
|
||||
{
|
||||
PCB_LAYER_ID top_layer, bottom_layer;
|
||||
int radiusBUI = ( aVia->GetDrillValue() / 2 );
|
||||
|
@ -993,7 +993,7 @@ void RENDER_3D_RAYTRACE::insertHole( const PCB_VIA* aVia )
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::insertHole( const PAD* aPad )
|
||||
void RENDER_3D_RAYTRACE_BASE::insertHole( const PAD* aPad )
|
||||
{
|
||||
const OBJECT_2D* object2d_A = nullptr;
|
||||
|
||||
|
@ -1164,7 +1164,7 @@ void RENDER_3D_RAYTRACE::insertHole( const PAD* aPad )
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::addPadsAndVias()
|
||||
void RENDER_3D_RAYTRACE_BASE::addPadsAndVias()
|
||||
{
|
||||
if( !m_boardAdapter.GetBoard() )
|
||||
return;
|
||||
|
@ -1193,7 +1193,7 @@ void RENDER_3D_RAYTRACE::addPadsAndVias()
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::load3DModels( CONTAINER_3D& aDstContainer, bool aSkipMaterialInformation )
|
||||
void RENDER_3D_RAYTRACE_BASE::load3DModels( CONTAINER_3D& aDstContainer, bool aSkipMaterialInformation )
|
||||
{
|
||||
if( !m_boardAdapter.GetBoard() )
|
||||
return;
|
||||
|
@ -1315,7 +1315,7 @@ void RENDER_3D_RAYTRACE::load3DModels( CONTAINER_3D& aDstContainer, bool aSkipMa
|
|||
}
|
||||
|
||||
|
||||
MODEL_MATERIALS* RENDER_3D_RAYTRACE::getModelMaterial( const S3DMODEL* a3DModel )
|
||||
MODEL_MATERIALS* RENDER_3D_RAYTRACE_BASE::getModelMaterial( const S3DMODEL* a3DModel )
|
||||
{
|
||||
MODEL_MATERIALS* materialVector;
|
||||
|
||||
|
@ -1418,7 +1418,7 @@ MODEL_MATERIALS* RENDER_3D_RAYTRACE::getModelMaterial( const S3DMODEL* a3DModel
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::addModels( CONTAINER_3D& aDstContainer, const S3DMODEL* a3DModel,
|
||||
void RENDER_3D_RAYTRACE_BASE::addModels( CONTAINER_3D& aDstContainer, const S3DMODEL* a3DModel,
|
||||
const glm::mat4& aModelMatrix, float aFPOpacity,
|
||||
bool aSkipMaterialInformation, BOARD_ITEM* aBoardItem )
|
||||
{
|
||||
|
|
|
@ -22,32 +22,28 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <gal/opengl/kiglew.h> // Must be included first
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "render_3d_raytrace.h"
|
||||
#include "render_3d_raytrace_base.h"
|
||||
#include "mortoncodes.h"
|
||||
#include "../color_rgba.h"
|
||||
#include "3d_fastmath.h"
|
||||
#include "3d_math.h"
|
||||
#include "../common_ogl/ogl_utils.h"
|
||||
#include <core/profile.h> // To use GetRunningMicroSecs or another profiling utility
|
||||
#include <wx/log.h>
|
||||
|
||||
|
||||
RENDER_3D_RAYTRACE::RENDER_3D_RAYTRACE( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& aAdapter, CAMERA& aCamera ) :
|
||||
RENDER_3D_BASE( aCanvas, aAdapter, aCamera ),
|
||||
RENDER_3D_RAYTRACE_BASE::RENDER_3D_RAYTRACE_BASE( BOARD_ADAPTER& aAdapter, CAMERA& aCamera ) :
|
||||
RENDER_3D_BASE( aAdapter, aCamera ),
|
||||
m_postShaderSsao( aCamera )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE::RENDER_3D_RAYTRACE" ) );
|
||||
wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE_BASE::RENDER_3D_RAYTRACE_BASE" ) );
|
||||
|
||||
m_openglSupportsVertexBufferObjects = false;
|
||||
m_pboId = GL_NONE;
|
||||
m_pboDataSize = 0;
|
||||
//m_pboId = GL_NONE;
|
||||
//m_pboDataSize = 0;
|
||||
m_accelerator = nullptr;
|
||||
m_convertedDummyBlockCount = 0;
|
||||
m_converted2dRoundSegmentCount = 0;
|
||||
|
@ -62,6 +58,7 @@ RENDER_3D_RAYTRACE::RENDER_3D_RAYTRACE( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& a
|
|||
m_xoffset = 0;
|
||||
m_yoffset = 0;
|
||||
|
||||
m_is_canvas_initialized = false;
|
||||
m_isPreview = false;
|
||||
m_renderState = RT_RENDER_STATE_MAX; // Set to an initial invalid state
|
||||
m_renderStartTime = 0;
|
||||
|
@ -69,9 +66,9 @@ RENDER_3D_RAYTRACE::RENDER_3D_RAYTRACE( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& a
|
|||
}
|
||||
|
||||
|
||||
RENDER_3D_RAYTRACE::~RENDER_3D_RAYTRACE()
|
||||
RENDER_3D_RAYTRACE_BASE::~RENDER_3D_RAYTRACE_BASE()
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE::~RENDER_3D_RAYTRACE" ) );
|
||||
wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE_BASE::~RENDER_3D_RAYTRACE_BASE" ) );
|
||||
|
||||
delete m_accelerator;
|
||||
m_accelerator = nullptr;
|
||||
|
@ -84,43 +81,16 @@ RENDER_3D_RAYTRACE::~RENDER_3D_RAYTRACE()
|
|||
|
||||
delete[] m_shaderBuffer;
|
||||
m_shaderBuffer = nullptr;
|
||||
|
||||
deletePbo();
|
||||
}
|
||||
|
||||
|
||||
int RENDER_3D_RAYTRACE::GetWaitForEditingTimeOut()
|
||||
int RENDER_3D_RAYTRACE_BASE::GetWaitForEditingTimeOut()
|
||||
{
|
||||
return 200; // ms
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::deletePbo()
|
||||
{
|
||||
// Delete PBO if it was created
|
||||
if( m_openglSupportsVertexBufferObjects )
|
||||
{
|
||||
if( glIsBufferARB( m_pboId ) )
|
||||
glDeleteBuffers( 1, &m_pboId );
|
||||
|
||||
m_pboId = GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::SetCurWindowSize( const wxSize& aSize )
|
||||
{
|
||||
if( m_windowSize != aSize )
|
||||
{
|
||||
m_windowSize = aSize;
|
||||
glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
|
||||
|
||||
initializeNewWindowSize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::restartRenderState()
|
||||
void RENDER_3D_RAYTRACE_BASE::restartRenderState()
|
||||
{
|
||||
m_renderStartTime = GetRunningMicroSecs();
|
||||
|
||||
|
@ -145,151 +115,13 @@ static inline void SetPixel( GLubyte* p, const COLOR_RGBA& v )
|
|||
}
|
||||
|
||||
|
||||
static inline SFVEC4F premultiplyAlpha( const SFVEC4F& aInput )
|
||||
SFVEC4F RENDER_3D_RAYTRACE_BASE::premultiplyAlpha( const SFVEC4F& aInput )
|
||||
{
|
||||
return SFVEC4F( aInput.r * aInput.a, aInput.g * aInput.a, aInput.b * aInput.a, aInput.a );
|
||||
}
|
||||
|
||||
|
||||
bool RENDER_3D_RAYTRACE::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||
REPORTER* aWarningReporter )
|
||||
{
|
||||
bool requestRedraw = false;
|
||||
|
||||
// Initialize openGL if need
|
||||
if( !m_is_opengl_initialized )
|
||||
{
|
||||
if( !initializeOpenGL() )
|
||||
return false;
|
||||
|
||||
//aIsMoving = true;
|
||||
requestRedraw = true;
|
||||
|
||||
// It will assign the first time the windows size, so it will now
|
||||
// revert to preview mode the first time the Redraw is called
|
||||
m_oldWindowsSize = m_windowSize;
|
||||
initializeBlockPositions();
|
||||
}
|
||||
|
||||
std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
|
||||
|
||||
// Reload board if it was requested
|
||||
if( m_reloadRequested )
|
||||
{
|
||||
if( aStatusReporter )
|
||||
aStatusReporter->Report( _( "Loading..." ) );
|
||||
|
||||
//aIsMoving = true;
|
||||
requestRedraw = true;
|
||||
Reload( aStatusReporter, aWarningReporter, false );
|
||||
}
|
||||
|
||||
|
||||
// Recalculate constants if windows size was changed
|
||||
if( m_windowSize != m_oldWindowsSize )
|
||||
{
|
||||
m_oldWindowsSize = m_windowSize;
|
||||
aIsMoving = true;
|
||||
requestRedraw = true;
|
||||
|
||||
initializeBlockPositions();
|
||||
}
|
||||
|
||||
|
||||
// Clear buffers
|
||||
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
|
||||
glClearDepth( 1.0f );
|
||||
glClearStencil( 0x00 );
|
||||
glClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
|
||||
|
||||
// 4-byte pixel alignment
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
|
||||
|
||||
glDisable( GL_STENCIL_TEST );
|
||||
glDisable( GL_LIGHTING );
|
||||
glDisable( GL_COLOR_MATERIAL );
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
glDisable( GL_BLEND );
|
||||
glDisable( GL_MULTISAMPLE );
|
||||
|
||||
const bool was_camera_changed = m_camera.ParametersChanged();
|
||||
|
||||
if( requestRedraw || aIsMoving || was_camera_changed )
|
||||
m_renderState = RT_RENDER_STATE_MAX; // Set to an invalid state,
|
||||
// so it will restart again latter
|
||||
|
||||
// This will only render if need, otherwise it will redraw the PBO on the screen again
|
||||
if( aIsMoving || was_camera_changed )
|
||||
{
|
||||
// Set head light (camera view light) with the opposite direction of the camera
|
||||
if( m_cameraLight )
|
||||
m_cameraLight->SetDirection( -m_camera.GetDir() );
|
||||
|
||||
OglDrawBackground( premultiplyAlpha( m_boardAdapter.m_BgColorTop ),
|
||||
premultiplyAlpha( m_boardAdapter.m_BgColorBot ) );
|
||||
|
||||
// Bind PBO
|
||||
glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
|
||||
|
||||
// Get the PBO pixel pointer to write the data
|
||||
GLubyte* ptrPBO = (GLubyte *)glMapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB,
|
||||
GL_WRITE_ONLY_ARB );
|
||||
|
||||
if( ptrPBO )
|
||||
{
|
||||
renderPreview( ptrPBO );
|
||||
|
||||
// release pointer to mapping buffer, this initialize the coping to PBO
|
||||
glUnmapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB );
|
||||
}
|
||||
|
||||
glWindowPos2i( m_xoffset, m_yoffset );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Bind PBO
|
||||
glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
|
||||
|
||||
if( m_renderState != RT_RENDER_STATE_FINISH )
|
||||
{
|
||||
// Get the PBO pixel pointer to write the data
|
||||
GLubyte* ptrPBO = (GLubyte *)glMapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB,
|
||||
GL_WRITE_ONLY_ARB );
|
||||
|
||||
if( ptrPBO )
|
||||
{
|
||||
render( ptrPBO, aStatusReporter );
|
||||
|
||||
if( m_renderState != RT_RENDER_STATE_FINISH )
|
||||
requestRedraw = true;
|
||||
|
||||
// release pointer to mapping buffer, this initialize the coping to PBO
|
||||
glUnmapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB );
|
||||
}
|
||||
}
|
||||
|
||||
if( m_renderState == RT_RENDER_STATE_FINISH )
|
||||
{
|
||||
glClear( GL_COLOR_BUFFER_BIT );
|
||||
}
|
||||
|
||||
glWindowPos2i( m_xoffset, m_yoffset );
|
||||
}
|
||||
|
||||
// This way it will blend the progress rendering with the last buffer. eg:
|
||||
// if it was called after a openGL.
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
glEnable( GL_ALPHA_TEST );
|
||||
glDrawPixels( m_realBufferSize.x, m_realBufferSize.y, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
|
||||
glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
|
||||
|
||||
return requestRedraw;
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::render( GLubyte* ptrPBO, REPORTER* aStatusReporter )
|
||||
void RENDER_3D_RAYTRACE_BASE::render( GLubyte* ptrPBO, REPORTER* aStatusReporter )
|
||||
{
|
||||
if( ( m_renderState == RT_RENDER_STATE_FINISH ) || ( m_renderState >= RT_RENDER_STATE_MAX ) )
|
||||
{
|
||||
|
@ -342,14 +174,14 @@ void RENDER_3D_RAYTRACE::render( GLubyte* ptrPBO, REPORTER* aStatusReporter )
|
|||
if( aStatusReporter && ( m_renderState == RT_RENDER_STATE_FINISH ) )
|
||||
{
|
||||
// Calculation time in seconds
|
||||
const double elapsed_time = (double)( GetRunningMicroSecs() - m_renderStartTime ) / 1e6;
|
||||
const double elapsed_time = (double) ( GetRunningMicroSecs() - m_renderStartTime ) / 1e6;
|
||||
|
||||
aStatusReporter->Report( wxString::Format( _( "Rendering time %.3f s" ), elapsed_time ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::renderTracing( GLubyte* ptrPBO, REPORTER* aStatusReporter )
|
||||
void RENDER_3D_RAYTRACE_BASE::renderTracing( GLubyte* ptrPBO, REPORTER* aStatusReporter )
|
||||
{
|
||||
m_isPreview = false;
|
||||
|
||||
|
@ -364,6 +196,8 @@ void RENDER_3D_RAYTRACE::renderTracing( GLubyte* ptrPBO, REPORTER* aStatusReport
|
|||
std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
|
||||
m_blockPositions.size() );
|
||||
|
||||
const int timeLimit = m_blockPositions.size() > 40000 ? 500 : 200;
|
||||
|
||||
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
|
||||
{
|
||||
std::thread t = std::thread( [&]()
|
||||
|
@ -380,8 +214,10 @@ void RENDER_3D_RAYTRACE::renderTracing( GLubyte* ptrPBO, REPORTER* aStatusReport
|
|||
|
||||
// Check if it spend already some time render and request to exit
|
||||
// to display the progress
|
||||
if( std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - startTime ).count() > 150 )
|
||||
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - startTime );
|
||||
|
||||
if( diff.count() > timeLimit )
|
||||
breakLoop = true;
|
||||
}
|
||||
}
|
||||
|
@ -459,7 +295,7 @@ SFVEC4F ConvertSRGBAToLinear( const SFVEC4F& aSRGBAcolor )
|
|||
#endif
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::renderFinalColor( GLubyte* ptrPBO, const SFVEC4F& rgbColor,
|
||||
void RENDER_3D_RAYTRACE_BASE::renderFinalColor( GLubyte* ptrPBO, const SFVEC4F& rgbColor,
|
||||
bool applyColorSpaceConversion )
|
||||
{
|
||||
SFVEC4F color = rgbColor;
|
||||
|
@ -494,7 +330,7 @@ static void HITINFO_PACKET_init( HITINFO_PACKET* aHitPacket )
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::renderRayPackets( const SFVEC4F* bgColorY, const RAY* aRayPkt,
|
||||
void RENDER_3D_RAYTRACE_BASE::renderRayPackets( const SFVEC4F* bgColorY, const RAY* aRayPkt,
|
||||
HITINFO_PACKET* aHitPacket, bool is_testShadow,
|
||||
SFVEC4F* aOutHitColor )
|
||||
{
|
||||
|
@ -516,7 +352,7 @@ void RENDER_3D_RAYTRACE::renderRayPackets( const SFVEC4F* bgColorY, const RAY* a
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::renderAntiAliasPackets( const SFVEC4F* aBgColorY,
|
||||
void RENDER_3D_RAYTRACE_BASE::renderAntiAliasPackets( const SFVEC4F* aBgColorY,
|
||||
const HITINFO_PACKET* aHitPck_X0Y0,
|
||||
const HITINFO_PACKET* aHitPck_AA_X1Y1,
|
||||
const RAY* aRayPck, SFVEC4F* aOutHitColor )
|
||||
|
@ -640,7 +476,7 @@ void RENDER_3D_RAYTRACE::renderAntiAliasPackets( const SFVEC4F* aBgColorY,
|
|||
#define DISP_FACTOR 0.075f
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::renderBlockTracing( GLubyte* ptrPBO, signed int iBlock )
|
||||
void RENDER_3D_RAYTRACE_BASE::renderBlockTracing( GLubyte* ptrPBO, signed int iBlock )
|
||||
{
|
||||
// Initialize ray packets
|
||||
const SFVEC2UI& blockPos = m_blockPositions[iBlock];
|
||||
|
@ -851,7 +687,7 @@ void RENDER_3D_RAYTRACE::renderBlockTracing( GLubyte* ptrPBO, signed int iBlock
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::postProcessShading( GLubyte* /* ptrPBO */, REPORTER* aStatusReporter )
|
||||
void RENDER_3D_RAYTRACE_BASE::postProcessShading( GLubyte* /* ptrPBO */, REPORTER* aStatusReporter )
|
||||
{
|
||||
if( m_boardAdapter.m_Cfg->m_Render.raytrace_post_processing )
|
||||
{
|
||||
|
@ -903,7 +739,7 @@ void RENDER_3D_RAYTRACE::postProcessShading( GLubyte* /* ptrPBO */, REPORTER* aS
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::postProcessBlurFinish( GLubyte* ptrPBO, REPORTER* /* aStatusReporter */ )
|
||||
void RENDER_3D_RAYTRACE_BASE::postProcessBlurFinish( GLubyte* ptrPBO, REPORTER* /* aStatusReporter */ )
|
||||
{
|
||||
if( m_boardAdapter.m_Cfg->m_Render.raytrace_post_processing )
|
||||
{
|
||||
|
@ -960,7 +796,7 @@ void RENDER_3D_RAYTRACE::postProcessBlurFinish( GLubyte* ptrPBO, REPORTER* /* aS
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::renderPreview( GLubyte* ptrPBO )
|
||||
void RENDER_3D_RAYTRACE_BASE::renderPreview( GLubyte* ptrPBO )
|
||||
{
|
||||
m_isPreview = true;
|
||||
|
||||
|
@ -1558,7 +1394,7 @@ void RENDER_3D_RAYTRACE::renderPreview( GLubyte* ptrPBO )
|
|||
|
||||
#define USE_EXPERIMENTAL_SOFT_SHADOWS 1
|
||||
|
||||
SFVEC4F RENDER_3D_RAYTRACE::shadeHit( const SFVEC4F& aBgColor, const RAY& aRay, HITINFO& aHitInfo,
|
||||
SFVEC4F RENDER_3D_RAYTRACE_BASE::shadeHit( const SFVEC4F& aBgColor, const RAY& aRay, HITINFO& aHitInfo,
|
||||
bool aIsInsideObject, unsigned int aRecursiveLevel,
|
||||
bool is_testShadow ) const
|
||||
{
|
||||
|
@ -1734,6 +1570,10 @@ SFVEC4F RENDER_3D_RAYTRACE::shadeHit( const SFVEC4F& aBgColor, const RAY& aRay,
|
|||
|
||||
sum_color += add;
|
||||
}
|
||||
else
|
||||
{
|
||||
sum_color += aBgColor;
|
||||
}
|
||||
}
|
||||
|
||||
outColor += (sum_color / SFVEC4F( (float)reflection_number_of_samples) );
|
||||
|
@ -1825,49 +1665,6 @@ SFVEC4F RENDER_3D_RAYTRACE::shadeHit( const SFVEC4F& aBgColor, const RAY& aRay,
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::initializeNewWindowSize()
|
||||
{
|
||||
initPbo();
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::initPbo()
|
||||
{
|
||||
if( GLEW_ARB_pixel_buffer_object )
|
||||
{
|
||||
m_openglSupportsVertexBufferObjects = true;
|
||||
|
||||
// Try to delete vbo if it was already initialized
|
||||
deletePbo();
|
||||
|
||||
// Learn about Pixel buffer objects at:
|
||||
// http://www.songho.ca/opengl/gl_pbo.html
|
||||
// http://web.eecs.umich.edu/~sugih/courses/eecs487/lectures/25-PBO+Mipmapping.pdf
|
||||
// "create 2 pixel buffer objects, you need to delete them when program exits.
|
||||
// glBufferDataARB with NULL pointer reserves only memory space."
|
||||
|
||||
// This sets the number of RGBA pixels
|
||||
m_pboDataSize = m_realBufferSize.x * m_realBufferSize.y * 4;
|
||||
|
||||
glGenBuffersARB( 1, &m_pboId );
|
||||
glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
|
||||
glBufferDataARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboDataSize, 0, GL_STREAM_DRAW_ARB );
|
||||
glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
|
||||
|
||||
wxLogTrace( m_logTrace,
|
||||
wxT( "RENDER_3D_RAYTRACE:: GLEW_ARB_pixel_buffer_object is supported" ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool RENDER_3D_RAYTRACE::initializeOpenGL()
|
||||
{
|
||||
m_is_opengl_initialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static float distance( const SFVEC2UI& a, const SFVEC2UI& b )
|
||||
{
|
||||
const float dx = (float) a.x - (float) b.x;
|
||||
|
@ -1876,7 +1673,7 @@ static float distance( const SFVEC2UI& a, const SFVEC2UI& b )
|
|||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE::initializeBlockPositions()
|
||||
void RENDER_3D_RAYTRACE_BASE::initializeBlockPositions()
|
||||
{
|
||||
m_realBufferSize = SFVEC2UI( 0 );
|
||||
|
||||
|
@ -1959,7 +1756,7 @@ void RENDER_3D_RAYTRACE::initializeBlockPositions()
|
|||
}
|
||||
|
||||
|
||||
BOARD_ITEM* RENDER_3D_RAYTRACE::IntersectBoardItem( const RAY& aRay )
|
||||
BOARD_ITEM* RENDER_3D_RAYTRACE_BASE::IntersectBoardItem( const RAY& aRay )
|
||||
{
|
||||
HITINFO hitInfo;
|
||||
hitInfo.m_tHit = std::numeric_limits<float>::infinity();
|
|
@ -22,10 +22,9 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef RENDER_3D_RAYTRACE_H
|
||||
#define RENDER_3D_RAYTRACE_H
|
||||
#ifndef RENDER_3D_RAYTRACE_BASE_H
|
||||
#define RENDER_3D_RAYTRACE_BASE_H
|
||||
|
||||
#include "../../common_ogl/openGL_includes.h"
|
||||
#include "accelerators/container_3d.h"
|
||||
#include "accelerators/accelerator_3d.h"
|
||||
#include "../render_3d_base.h"
|
||||
|
@ -52,19 +51,16 @@ typedef enum
|
|||
} RT_RENDER_STATE;
|
||||
|
||||
|
||||
class RENDER_3D_RAYTRACE : public RENDER_3D_BASE
|
||||
class RENDER_3D_RAYTRACE_BASE : public RENDER_3D_BASE
|
||||
{
|
||||
public:
|
||||
// TODO: Take into account board thickness so that the camera won't move inside of the board
|
||||
// when facing it perpendicularly.
|
||||
static constexpr float MIN_DISTANCE_IU = 4 * PCB_IU_PER_MM;
|
||||
|
||||
explicit RENDER_3D_RAYTRACE( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& aAdapter, CAMERA& aCamera );
|
||||
explicit RENDER_3D_RAYTRACE_BASE( BOARD_ADAPTER& aAdapter, CAMERA& aCamera );
|
||||
|
||||
~RENDER_3D_RAYTRACE();
|
||||
|
||||
void SetCurWindowSize( const wxSize& aSize ) override;
|
||||
bool Redraw( bool aIsMoving, REPORTER* aStatusReporter, REPORTER* aWarningReporter ) override;
|
||||
~RENDER_3D_RAYTRACE_BASE();
|
||||
|
||||
int GetWaitForEditingTimeOut() override;
|
||||
|
||||
|
@ -73,11 +69,9 @@ public:
|
|||
|
||||
BOARD_ITEM *IntersectBoardItem( const RAY& aRay );
|
||||
|
||||
private:
|
||||
bool initializeOpenGL();
|
||||
void initializeNewWindowSize();
|
||||
void initPbo();
|
||||
void deletePbo();
|
||||
protected:
|
||||
virtual void initPbo() = 0;
|
||||
virtual void deletePbo() = 0;
|
||||
void createItemsFromContainer( const BVH_CONTAINER_2D* aContainer2d, PCB_LAYER_ID aLayer_id,
|
||||
const MATERIAL* aMaterialLayer, const SFVEC3F& aLayerColor,
|
||||
float aLayerZOffset );
|
||||
|
@ -128,6 +122,8 @@ private:
|
|||
void render( GLubyte* ptrPBO, REPORTER* aStatusReporter );
|
||||
void renderPreview( GLubyte* ptrPBO );
|
||||
|
||||
static SFVEC4F premultiplyAlpha( const SFVEC4F& aInput );
|
||||
|
||||
struct
|
||||
{
|
||||
BLINN_PHONG_MATERIAL m_Paste;
|
||||
|
@ -148,6 +144,7 @@ private:
|
|||
BRUSHED_METAL_NORMAL m_brushedMetalMaterial;
|
||||
SILK_SCREEN_NORMAL m_silkScreenMaterial;
|
||||
|
||||
bool m_is_canvas_initialized;
|
||||
bool m_isPreview;
|
||||
|
||||
/// State used on quality render
|
||||
|
@ -165,10 +162,8 @@ private:
|
|||
|
||||
DIRECTIONAL_LIGHT* m_cameraLight;
|
||||
|
||||
bool m_openglSupportsVertexBufferObjects;
|
||||
|
||||
GLuint m_pboId;
|
||||
GLuint m_pboDataSize;
|
||||
/*GLuint m_pboId;
|
||||
GLuint m_pboDataSize;*/
|
||||
|
||||
CONTAINER_3D m_objectContainer;
|
||||
|
||||
|
@ -224,4 +219,4 @@ extern SFVEC4F ConvertSRGBAToLinear( const SFVEC4F& aSRGBAcolor );
|
|||
#define ConvertSRGBAToLinear( v ) ( v )
|
||||
#endif
|
||||
|
||||
#endif // RENDER_3D_RAYTRACE_H
|
||||
#endif // RENDER_3D_RAYTRACE_BASE_H
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2020 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2024 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
* Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <gal/opengl/kiglew.h> // Must be included first
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "render_3d_raytrace_gl.h"
|
||||
#include "../common_ogl/ogl_utils.h"
|
||||
#include <core/profile.h> // To use GetRunningMicroSecs or another profiling utility
|
||||
#include <wx/log.h>
|
||||
|
||||
|
||||
RENDER_3D_RAYTRACE_GL::RENDER_3D_RAYTRACE_GL( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& aAdapter, CAMERA& aCamera ) :
|
||||
RENDER_3D_RAYTRACE_BASE( aAdapter, aCamera )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE_GL::RENDER_3D_RAYTRACE_GL" ) );
|
||||
|
||||
m_openglSupportsVertexBufferObjects = false;
|
||||
m_pboId = GL_NONE;
|
||||
m_pboDataSize = 0;
|
||||
}
|
||||
|
||||
|
||||
RENDER_3D_RAYTRACE_GL::~RENDER_3D_RAYTRACE_GL()
|
||||
{
|
||||
deletePbo();
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE_GL::deletePbo()
|
||||
{
|
||||
// Delete PBO if it was created
|
||||
if( m_openglSupportsVertexBufferObjects )
|
||||
{
|
||||
if( glIsBufferARB( m_pboId ) )
|
||||
glDeleteBuffers( 1, &m_pboId );
|
||||
|
||||
m_pboId = GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE_GL::SetCurWindowSize( const wxSize& aSize )
|
||||
{
|
||||
if( m_windowSize != aSize )
|
||||
{
|
||||
m_windowSize = aSize;
|
||||
glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
|
||||
|
||||
initPbo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool RENDER_3D_RAYTRACE_GL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||
REPORTER* aWarningReporter )
|
||||
{
|
||||
bool requestRedraw = false;
|
||||
|
||||
// Initialize openGL if need
|
||||
if( !m_canvasInitialized )
|
||||
{
|
||||
m_canvasInitialized = true;
|
||||
|
||||
//aIsMoving = true;
|
||||
requestRedraw = true;
|
||||
|
||||
// It will assign the first time the windows size, so it will now
|
||||
// revert to preview mode the first time the Redraw is called
|
||||
m_oldWindowsSize = m_windowSize;
|
||||
initializeBlockPositions();
|
||||
}
|
||||
|
||||
std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
|
||||
|
||||
// Reload board if it was requested
|
||||
if( m_reloadRequested )
|
||||
{
|
||||
if( aStatusReporter )
|
||||
aStatusReporter->Report( _( "Loading..." ) );
|
||||
|
||||
//aIsMoving = true;
|
||||
requestRedraw = true;
|
||||
Reload( aStatusReporter, aWarningReporter, false );
|
||||
}
|
||||
|
||||
|
||||
// Recalculate constants if windows size was changed
|
||||
if( m_windowSize != m_oldWindowsSize )
|
||||
{
|
||||
m_oldWindowsSize = m_windowSize;
|
||||
aIsMoving = true;
|
||||
requestRedraw = true;
|
||||
|
||||
initializeBlockPositions();
|
||||
}
|
||||
|
||||
// Clear buffers
|
||||
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
|
||||
glClearDepth( 1.0f );
|
||||
glClearStencil( 0x00 );
|
||||
glClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
|
||||
|
||||
// 4-byte pixel alignment
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
|
||||
|
||||
glDisable( GL_STENCIL_TEST );
|
||||
glDisable( GL_LIGHTING );
|
||||
glDisable( GL_COLOR_MATERIAL );
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
glDisable( GL_BLEND );
|
||||
glDisable( GL_MULTISAMPLE );
|
||||
|
||||
const bool was_camera_changed = m_camera.ParametersChanged();
|
||||
|
||||
if( requestRedraw || aIsMoving || was_camera_changed )
|
||||
m_renderState = RT_RENDER_STATE_MAX; // Set to an invalid state,
|
||||
// so it will restart again latter
|
||||
|
||||
// This will only render if need, otherwise it will redraw the PBO on the screen again
|
||||
if( aIsMoving || was_camera_changed )
|
||||
{
|
||||
// Set head light (camera view light) with the opposite direction of the camera
|
||||
if( m_cameraLight )
|
||||
m_cameraLight->SetDirection( -m_camera.GetDir() );
|
||||
|
||||
OglDrawBackground( premultiplyAlpha( m_boardAdapter.m_BgColorTop ),
|
||||
premultiplyAlpha( m_boardAdapter.m_BgColorBot ) );
|
||||
|
||||
// Bind PBO
|
||||
glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
|
||||
|
||||
// Get the PBO pixel pointer to write the data
|
||||
GLubyte* ptrPBO = (GLubyte *)glMapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB,
|
||||
GL_WRITE_ONLY_ARB );
|
||||
|
||||
if( ptrPBO )
|
||||
{
|
||||
renderPreview( ptrPBO );
|
||||
|
||||
// release pointer to mapping buffer, this initialize the coping to PBO
|
||||
glUnmapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB );
|
||||
}
|
||||
|
||||
glWindowPos2i( m_xoffset, m_yoffset );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Bind PBO
|
||||
glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
|
||||
|
||||
if( m_renderState != RT_RENDER_STATE_FINISH )
|
||||
{
|
||||
// Get the PBO pixel pointer to write the data
|
||||
GLubyte* ptrPBO = (GLubyte *)glMapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB,
|
||||
GL_WRITE_ONLY_ARB );
|
||||
|
||||
if( ptrPBO )
|
||||
{
|
||||
render( ptrPBO, aStatusReporter );
|
||||
|
||||
if( m_renderState != RT_RENDER_STATE_FINISH )
|
||||
requestRedraw = true;
|
||||
|
||||
// release pointer to mapping buffer, this initialize the coping to PBO
|
||||
glUnmapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB );
|
||||
}
|
||||
}
|
||||
|
||||
if( m_renderState == RT_RENDER_STATE_FINISH )
|
||||
{
|
||||
glClear( GL_COLOR_BUFFER_BIT );
|
||||
}
|
||||
|
||||
glWindowPos2i( m_xoffset, m_yoffset );
|
||||
}
|
||||
|
||||
// This way it will blend the progress rendering with the last buffer. eg:
|
||||
// if it was called after a openGL.
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
glEnable( GL_ALPHA_TEST );
|
||||
glDrawPixels( m_realBufferSize.x, m_realBufferSize.y, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
|
||||
glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
|
||||
|
||||
return requestRedraw;
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE_GL::initPbo()
|
||||
{
|
||||
if( GLEW_ARB_pixel_buffer_object )
|
||||
{
|
||||
m_openglSupportsVertexBufferObjects = true;
|
||||
|
||||
// Try to delete vbo if it was already initialized
|
||||
deletePbo();
|
||||
|
||||
// Learn about Pixel buffer objects at:
|
||||
// http://www.songho.ca/opengl/gl_pbo.html
|
||||
// http://web.eecs.umich.edu/~sugih/courses/eecs487/lectures/25-PBO+Mipmapping.pdf
|
||||
// "create 2 pixel buffer objects, you need to delete them when program exits.
|
||||
// glBufferDataARB with NULL pointer reserves only memory space."
|
||||
|
||||
// This sets the number of RGBA pixels
|
||||
m_pboDataSize = m_realBufferSize.x * m_realBufferSize.y * 4;
|
||||
|
||||
glGenBuffersARB( 1, &m_pboId );
|
||||
glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
|
||||
glBufferDataARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboDataSize, 0, GL_STREAM_DRAW_ARB );
|
||||
glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
|
||||
|
||||
wxLogTrace( m_logTrace,
|
||||
wxT( "RENDER_3D_RAYTRACE_GL:: GLEW_ARB_pixel_buffer_object is supported" ) );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2020 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2024 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
* Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef RENDER_3D_RAYTRACE_GL_H
|
||||
#define RENDER_3D_RAYTRACE_GL_H
|
||||
|
||||
#include "../../common_ogl/openGL_includes.h"
|
||||
#include "render_3d_raytrace_base.h"
|
||||
|
||||
|
||||
class RENDER_3D_RAYTRACE_GL : public RENDER_3D_RAYTRACE_BASE
|
||||
{
|
||||
public:
|
||||
explicit RENDER_3D_RAYTRACE_GL( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& aAdapter,
|
||||
CAMERA& aCamera );
|
||||
|
||||
~RENDER_3D_RAYTRACE_GL();
|
||||
|
||||
void SetCurWindowSize( const wxSize& aSize ) override;
|
||||
bool Redraw( bool aIsMoving, REPORTER* aStatusReporter, REPORTER* aWarningReporter ) override;
|
||||
|
||||
protected:
|
||||
void initPbo() override;
|
||||
void deletePbo() override;
|
||||
|
||||
bool m_openglSupportsVertexBufferObjects;
|
||||
GLuint m_pboId;
|
||||
GLuint m_pboDataSize;
|
||||
};
|
||||
|
||||
|
||||
#endif // RENDER_3D_RAYTRACE_GL_H
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2020 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2024 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
* Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "render_3d_raytrace_ram.h"
|
||||
#include <wx/log.h>
|
||||
|
||||
|
||||
RENDER_3D_RAYTRACE_RAM::RENDER_3D_RAYTRACE_RAM( BOARD_ADAPTER& aAdapter, CAMERA& aCamera ) :
|
||||
RENDER_3D_RAYTRACE_BASE( aAdapter, aCamera ),
|
||||
m_outputBuffer( nullptr ),
|
||||
m_pboDataSize( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RENDER_3D_RAYTRACE_RAM::~RENDER_3D_RAYTRACE_RAM()
|
||||
{
|
||||
deletePbo();
|
||||
}
|
||||
|
||||
|
||||
GLubyte* RENDER_3D_RAYTRACE_RAM::GetBuffer()
|
||||
{
|
||||
return m_outputBuffer;
|
||||
}
|
||||
|
||||
|
||||
wxSize RENDER_3D_RAYTRACE_RAM::GetRealBufferSize()
|
||||
{
|
||||
return wxSize( m_realBufferSize.x, m_realBufferSize.y );
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE_RAM::deletePbo()
|
||||
{
|
||||
delete[] m_outputBuffer;
|
||||
m_outputBuffer = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE_RAM::SetCurWindowSize( const wxSize& aSize )
|
||||
{
|
||||
if( m_windowSize != aSize )
|
||||
{
|
||||
m_windowSize = aSize;
|
||||
|
||||
initPbo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool RENDER_3D_RAYTRACE_RAM::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||
REPORTER* aWarningReporter )
|
||||
{
|
||||
bool requestRedraw = false;
|
||||
|
||||
// Initialize openGL if need
|
||||
if( !m_canvasInitialized )
|
||||
{
|
||||
m_canvasInitialized = true;
|
||||
|
||||
//aIsMoving = true;
|
||||
requestRedraw = true;
|
||||
|
||||
// It will assign the first time the windows size, so it will now
|
||||
// revert to preview mode the first time the Redraw is called
|
||||
m_oldWindowsSize = m_windowSize;
|
||||
initializeBlockPositions();
|
||||
}
|
||||
|
||||
std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
|
||||
|
||||
// Reload board if it was requested
|
||||
if( m_reloadRequested )
|
||||
{
|
||||
if( aStatusReporter )
|
||||
aStatusReporter->Report( _( "Loading..." ) );
|
||||
|
||||
//aIsMoving = true;
|
||||
requestRedraw = true;
|
||||
Reload( aStatusReporter, aWarningReporter, false );
|
||||
}
|
||||
|
||||
|
||||
// Recalculate constants if windows size was changed
|
||||
if( m_windowSize != m_oldWindowsSize )
|
||||
{
|
||||
m_oldWindowsSize = m_windowSize;
|
||||
aIsMoving = true;
|
||||
requestRedraw = true;
|
||||
|
||||
initializeBlockPositions();
|
||||
}
|
||||
|
||||
const bool was_camera_changed = m_camera.ParametersChanged();
|
||||
|
||||
if( requestRedraw || aIsMoving || was_camera_changed )
|
||||
m_renderState = RT_RENDER_STATE_MAX; // Set to an invalid state,
|
||||
// so it will restart again latter
|
||||
|
||||
// This will only render if need, otherwise it will redraw the PBO on the screen again
|
||||
if( aIsMoving || was_camera_changed )
|
||||
{
|
||||
// Set head light (camera view light) with the opposite direction of the camera
|
||||
if( m_cameraLight )
|
||||
m_cameraLight->SetDirection( -m_camera.GetDir() );
|
||||
|
||||
if( m_outputBuffer )
|
||||
{
|
||||
renderPreview( m_outputBuffer );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( m_renderState != RT_RENDER_STATE_FINISH )
|
||||
{
|
||||
if( m_outputBuffer )
|
||||
{
|
||||
render( m_outputBuffer, aStatusReporter );
|
||||
|
||||
if( m_renderState != RT_RENDER_STATE_FINISH )
|
||||
requestRedraw = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return requestRedraw;
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_RAYTRACE_RAM::initPbo()
|
||||
{
|
||||
deletePbo();
|
||||
|
||||
m_pboDataSize = m_realBufferSize.x * m_realBufferSize.y * 4;
|
||||
m_outputBuffer = new GLubyte[m_pboDataSize]();
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2020 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2024 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
* Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef RENDER_3D_RAYTRACE_RAM_H
|
||||
#define RENDER_3D_RAYTRACE_RAM_H
|
||||
|
||||
#include "render_3d_raytrace_base.h"
|
||||
|
||||
|
||||
class RENDER_3D_RAYTRACE_RAM : public RENDER_3D_RAYTRACE_BASE
|
||||
{
|
||||
public:
|
||||
// TODO: Take into account board thickness so that the camera won't move inside of the board
|
||||
// when facing it perpendicularly.
|
||||
static constexpr float MIN_DISTANCE_IU = 4 * PCB_IU_PER_MM;
|
||||
|
||||
explicit RENDER_3D_RAYTRACE_RAM( BOARD_ADAPTER& aAdapter, CAMERA& aCamera );
|
||||
|
||||
~RENDER_3D_RAYTRACE_RAM();
|
||||
|
||||
GLubyte* GetBuffer();
|
||||
wxSize GetRealBufferSize();
|
||||
|
||||
void SetCurWindowSize( const wxSize& aSize ) override;
|
||||
bool Redraw( bool aIsMoving, REPORTER* aStatusReporter, REPORTER* aWarningReporter ) override;
|
||||
|
||||
private:
|
||||
void initPbo() override;
|
||||
void deletePbo() override;
|
||||
|
||||
GLubyte* m_outputBuffer;
|
||||
GLuint m_pboDataSize;
|
||||
};
|
||||
|
||||
|
||||
#endif // RENDER_3D_RAYTRACE_RAM_H
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -44,13 +44,12 @@
|
|||
const wxChar* RENDER_3D_BASE::m_logTrace = wxT( "KI_TRACE_3D_RENDER" );
|
||||
|
||||
|
||||
RENDER_3D_BASE::RENDER_3D_BASE( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& aBoardAdapter, CAMERA& aCamera ) :
|
||||
RENDER_3D_BASE::RENDER_3D_BASE( BOARD_ADAPTER& aBoardAdapter, CAMERA& aCamera ) :
|
||||
m_boardAdapter( aBoardAdapter ),
|
||||
m_camera( aCamera )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "RENDER_3D_BASE::RENDER_3D_BASE" ) );
|
||||
m_canvas = aCanvas;
|
||||
m_is_opengl_initialized = false;
|
||||
m_canvasInitialized = false;
|
||||
m_windowSize = wxSize( -1, -1 );
|
||||
m_reloadRequested = true;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -42,7 +42,7 @@
|
|||
class RENDER_3D_BASE
|
||||
{
|
||||
public:
|
||||
explicit RENDER_3D_BASE( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& aBoardAdapter, CAMERA& aCamera );
|
||||
explicit RENDER_3D_BASE( BOARD_ADAPTER& aBoardAdapter, CAMERA& aCamera );
|
||||
|
||||
virtual ~RENDER_3D_BASE() = 0;
|
||||
|
||||
|
@ -98,16 +98,13 @@ protected:
|
|||
*/
|
||||
std::unique_ptr<BUSY_INDICATOR> CreateBusyIndicator() const;
|
||||
|
||||
///< the canvas to display the scene
|
||||
EDA_3D_CANVAS* m_canvas;
|
||||
|
||||
///< Settings reference in use for this render.
|
||||
BOARD_ADAPTER& m_boardAdapter;
|
||||
|
||||
CAMERA& m_camera;
|
||||
|
||||
///< Flag if the opengl specific for this render was already initialized.
|
||||
bool m_is_opengl_initialized;
|
||||
///< Flag if the canvas specific for this render was already initialized.
|
||||
bool m_canvasInitialized;
|
||||
|
||||
///< @todo This must be reviewed in order to flag change types.
|
||||
bool m_reloadRequested;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -38,11 +38,24 @@
|
|||
// stdlib
|
||||
#include <algorithm>
|
||||
|
||||
TRACK_BALL::TRACK_BALL( float aInitialDistance ) :
|
||||
CAMERA( aInitialDistance )
|
||||
|
||||
TRACK_BALL::TRACK_BALL( float aInitialDistance ) : CAMERA( aInitialDistance )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "TRACK_BALL::TRACK_BALL" ) );
|
||||
initQuat();
|
||||
}
|
||||
|
||||
|
||||
TRACK_BALL::TRACK_BALL( SFVEC3F aInitPos, SFVEC3F aLookat, PROJECTION_TYPE aProjectionType ) :
|
||||
CAMERA( aInitPos, aLookat, aProjectionType )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "TRACK_BALL::TRACK_BALL" ) );
|
||||
initQuat();
|
||||
}
|
||||
|
||||
|
||||
void TRACK_BALL::initQuat()
|
||||
{
|
||||
memset( m_quat_t0, 0, sizeof( m_quat_t0 ) );
|
||||
memset( m_quat_t1, 0, sizeof( m_quat_t1 ) );
|
||||
|
||||
|
@ -50,6 +63,7 @@ TRACK_BALL::TRACK_BALL( float aInitialDistance ) :
|
|||
trackball( m_quat_t1, 0.0, 0.0, 0.0, 0.0 );
|
||||
}
|
||||
|
||||
|
||||
void TRACK_BALL::Drag( const wxPoint& aNewMousePosition )
|
||||
{
|
||||
m_parametersChanged = true;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -37,6 +37,7 @@ class TRACK_BALL : public CAMERA
|
|||
{
|
||||
public:
|
||||
explicit TRACK_BALL( float aInitialDistance );
|
||||
explicit TRACK_BALL( SFVEC3F aInitPos, SFVEC3F aLookat, PROJECTION_TYPE aProjectionType );
|
||||
|
||||
virtual ~TRACK_BALL()
|
||||
{
|
||||
|
@ -57,6 +58,8 @@ public:
|
|||
void Interpolate( float t ) override;
|
||||
|
||||
private:
|
||||
void initQuat();
|
||||
|
||||
/**
|
||||
* interpolate quaternions of the trackball
|
||||
*/
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2020 Jon Evans <jon@craftyjon.com>
|
||||
* Copyright (C) 2023 CERN
|
||||
* Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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
|
||||
|
@ -23,7 +23,6 @@
|
|||
#define EDA_3D_VIEWER_SETTINGS_H_
|
||||
|
||||
#include <3d_enums.h>
|
||||
#include <common_ogl/ogl_attr_list.h>
|
||||
#include <plugins/3dapi/xv3d_types.h>
|
||||
#include <settings/app_settings.h>
|
||||
#include <settings/parameters.h>
|
||||
|
@ -34,6 +33,8 @@
|
|||
#define FOLLOW_PLOT_SETTINGS wxT( "follow_plot_settings" )
|
||||
#define LEGACY_PRESET_FLAG wxT( "legacy_preset_flag" )
|
||||
|
||||
enum class ANTIALIASING_MODE;
|
||||
|
||||
|
||||
struct LAYER_PRESET_3D
|
||||
{
|
||||
|
|
|
@ -45,7 +45,9 @@ set(3D-VIEWER_SRCS
|
|||
${DIR_RAY_ACC}/container_2d.cpp
|
||||
${DIR_RAY}/PerlinNoise.cpp
|
||||
${DIR_RAY}/create_scene.cpp
|
||||
${DIR_RAY}/render_3d_raytrace.cpp
|
||||
${DIR_RAY}/render_3d_raytrace_base.cpp
|
||||
${DIR_RAY}/render_3d_raytrace_gl.cpp
|
||||
${DIR_RAY}/render_3d_raytrace_ram.cpp
|
||||
${DIR_RAY}/frustum.cpp
|
||||
${DIR_RAY}/material.cpp
|
||||
${DIR_RAY}/mortoncodes.cpp
|
||||
|
|
|
@ -88,6 +88,7 @@ set( KICOMMON_SRCS
|
|||
jobs/job_export_sch_pythonbom.cpp
|
||||
jobs/job_fp_export_svg.cpp
|
||||
jobs/job_fp_upgrade.cpp
|
||||
jobs/job_pcb_render.cpp
|
||||
jobs/job_pcb_drc.cpp
|
||||
jobs/job_sch_erc.cpp
|
||||
jobs/job_sym_export_svg.cpp
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -29,6 +29,7 @@
|
|||
#include <gal/3d/camera.h>
|
||||
#include <wx/log.h>
|
||||
#include <algorithm>
|
||||
#include <3d_enums.h>
|
||||
|
||||
// A helper function to normalize aAngle between -2PI and +2PI
|
||||
inline void normalise2PI( float& aAngle )
|
||||
|
@ -50,14 +51,21 @@ const float CAMERA::DEFAULT_MIN_ZOOM = 0.020f;
|
|||
const float CAMERA::DEFAULT_MAX_ZOOM = 2.0f;
|
||||
|
||||
|
||||
CAMERA::CAMERA( float aInitialDistance )
|
||||
CAMERA::CAMERA( float aInitialDistance ) :
|
||||
CAMERA( SFVEC3F( 0.0f, 0.0f, -aInitialDistance ), SFVEC3F( 0.0f ),
|
||||
PROJECTION_TYPE::PERSPECTIVE )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CAMERA::CAMERA( SFVEC3F aInitPos, SFVEC3F aLookat, PROJECTION_TYPE aProjectionType )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "CAMERA::CAMERA" ) );
|
||||
|
||||
m_camera_pos_init = SFVEC3F( 0.0f, 0.0f, -aInitialDistance );
|
||||
m_board_lookat_pos_init = SFVEC3F( 0.0f );
|
||||
m_camera_pos_init = aInitPos;
|
||||
m_board_lookat_pos_init = aLookat;
|
||||
m_windowSize = SFVEC2I( 0, 0 );
|
||||
m_projectionType = PROJECTION_TYPE::PERSPECTIVE;
|
||||
m_projectionType = aProjectionType;
|
||||
m_interpolation_mode = CAMERA_INTERPOLATION::BEZIER;
|
||||
|
||||
m_minZoom = DEFAULT_MIN_ZOOM;
|
||||
|
@ -99,6 +107,57 @@ void CAMERA::Reset()
|
|||
}
|
||||
|
||||
|
||||
bool CAMERA::ViewCommand_T1( VIEW3D_TYPE aRequestedView )
|
||||
{
|
||||
switch( aRequestedView )
|
||||
{
|
||||
case VIEW3D_TYPE::VIEW3D_RIGHT:
|
||||
SetT0_and_T1_current_T();
|
||||
Reset_T1();
|
||||
RotateZ_T1( glm::radians( -90.0f ) );
|
||||
RotateX_T1( glm::radians( -90.0f ) );
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_LEFT:
|
||||
Reset_T1();
|
||||
RotateZ_T1( glm::radians( 90.0f ) );
|
||||
RotateX_T1( glm::radians( -90.0f ) );
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_FRONT:
|
||||
Reset_T1();
|
||||
RotateX_T1( glm::radians( -90.0f ) );
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_BACK:
|
||||
Reset_T1();
|
||||
RotateX_T1( glm::radians( -90.0f ) );
|
||||
|
||||
// The rotation angle should be 180.
|
||||
// We use 179.999 (180 - epsilon) to avoid a full 360 deg rotation when
|
||||
// using 180 deg if the previous rotated position was already 180 deg
|
||||
RotateZ_T1( glm::radians( 179.999f ) );
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_TOP:
|
||||
Reset_T1();
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_BOTTOM:
|
||||
Reset_T1();
|
||||
RotateY_T1( glm::radians( 179.999f ) ); // Rotation = 180 - epsilon
|
||||
return true;
|
||||
|
||||
case VIEW3D_TYPE::VIEW3D_FLIP:
|
||||
RotateY_T1( glm::radians( 179.999f ) );
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::Reset_T1()
|
||||
{
|
||||
m_camera_pos_t1 = m_camera_pos_init;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Mark Roszko <mark.roszko@gmail.com>
|
||||
* Copyright (C) 2024 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
* Copyright (C) 2023-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <jobs/job_pcb_render.h>
|
||||
|
||||
|
||||
JOB_PCB_RENDER::JOB_PCB_RENDER( bool aIsCli ) :
|
||||
JOB( "render", aIsCli ), m_filename(), m_outputFile()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
|
||||
* Copyright (C) 2024 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
* Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef JOB_PCB_RENDER_H
|
||||
#define JOB_PCB_RENDER_H
|
||||
|
||||
#include <kicommon.h>
|
||||
#include <wx/string.h>
|
||||
#include "job.h"
|
||||
#include <optional>
|
||||
#include <math/vector3.h>
|
||||
|
||||
class KICOMMON_API JOB_PCB_RENDER : public JOB
|
||||
{
|
||||
public:
|
||||
JOB_PCB_RENDER( bool aIsCli );
|
||||
|
||||
wxString m_filename;
|
||||
wxString m_outputFile;
|
||||
|
||||
enum class FORMAT
|
||||
{
|
||||
PNG,
|
||||
JPEG
|
||||
};
|
||||
|
||||
enum class QUALITY
|
||||
{
|
||||
BASIC,
|
||||
HIGH,
|
||||
USER
|
||||
};
|
||||
|
||||
enum class BG_STYLE
|
||||
{
|
||||
DEFAULT,
|
||||
TRANSPARENT,
|
||||
OPAQUE
|
||||
};
|
||||
|
||||
enum class SIDE
|
||||
{
|
||||
TOP,
|
||||
BOTTOM,
|
||||
LEFT,
|
||||
RIGHT,
|
||||
FRONT,
|
||||
BACK
|
||||
};
|
||||
|
||||
FORMAT m_format = FORMAT::PNG;
|
||||
QUALITY m_quality = QUALITY::BASIC;
|
||||
BG_STYLE m_bgStyle = BG_STYLE::DEFAULT;
|
||||
int m_width = 0;
|
||||
int m_height = 0;
|
||||
std::string m_colorPreset;
|
||||
SIDE m_side = SIDE::TOP;
|
||||
double m_zoom = 1.0;
|
||||
bool m_perspective = false;
|
||||
VECTOR3D m_rotation;
|
||||
VECTOR3D m_pan;
|
||||
VECTOR3D m_pivot;
|
||||
bool m_floor = false;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -34,6 +34,7 @@
|
|||
#include <plugins/3dapi/xv3d_types.h>
|
||||
#include <wx/gdicmn.h> // for wxSize
|
||||
#include <vector>
|
||||
#include <3d_enums.h>
|
||||
|
||||
enum class PROJECTION_TYPE
|
||||
{
|
||||
|
@ -110,6 +111,7 @@ public:
|
|||
* @param aInitialDistance Initial Z-distance to the board
|
||||
*/
|
||||
explicit CAMERA( float aInitialDistance );
|
||||
explicit CAMERA( SFVEC3F aInitPos, SFVEC3F aLookat, PROJECTION_TYPE aProjectionType );
|
||||
|
||||
virtual ~CAMERA()
|
||||
{
|
||||
|
@ -232,6 +234,8 @@ public:
|
|||
zoomChanged();
|
||||
}
|
||||
|
||||
bool ViewCommand_T1( VIEW3D_TYPE aRequestedView );
|
||||
|
||||
void RotateX( float aAngleInRadians );
|
||||
void RotateY( float aAngleInRadians );
|
||||
void RotateZ( float aAngleInRadians );
|
||||
|
|
|
@ -42,6 +42,7 @@ set( KICAD_CLI_SRCS
|
|||
cli/command.cpp
|
||||
cli/command_pcb_export_base.cpp
|
||||
cli/command_pcb_drc.cpp
|
||||
cli/command_pcb_render.cpp
|
||||
cli/command_pcb_export_3d.cpp
|
||||
cli/command_pcb_export_drill.cpp
|
||||
cli/command_pcb_export_dxf.cpp
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
|
||||
* Copyright (C) 2024 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
* Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "command_pcb_render.h"
|
||||
#include <cli/exit_codes.h>
|
||||
#include "jobs/job_pcb_render.h"
|
||||
#include <kiface_base.h>
|
||||
#include <layer_ids.h>
|
||||
#include <string_utils.h>
|
||||
#include <wx/crt.h>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include <macros.h>
|
||||
#include <wx/tokenzr.h>
|
||||
#include "../../3d-viewer/3d_viewer/eda_3d_viewer_settings.h"
|
||||
#include <math/vector3.h>
|
||||
|
||||
#define ARG_BACKGROUND "--background"
|
||||
#define ARG_QUALITY "--quality"
|
||||
|
||||
#define ARG_WIDTH "--width"
|
||||
#define ARG_WIDTH_SHORT "-w"
|
||||
|
||||
#define ARG_HEIGHT "--height"
|
||||
#define ARG_HEIGHT_SHORT "-h"
|
||||
|
||||
#define ARG_SIDE "--side"
|
||||
#define ARG_PRESET "--preset"
|
||||
#define ARG_PAN "--pan"
|
||||
#define ARG_PIVOT "--pivot"
|
||||
#define ARG_ROTATE "--rotate"
|
||||
#define ARG_ZOOM "--zoom"
|
||||
#define ARG_PERSPECTIVE "--perspective"
|
||||
#define ARG_FLOOR "--floor"
|
||||
|
||||
|
||||
template <typename T>
|
||||
static wxString enumString()
|
||||
{
|
||||
wxString str;
|
||||
auto names = magic_enum::enum_names<T>();
|
||||
|
||||
for( size_t i = 0; i < names.size(); i++ )
|
||||
{
|
||||
std::string name = { names[i].begin(), names[i].end() };
|
||||
|
||||
if( i > 0 )
|
||||
str << ", ";
|
||||
|
||||
std::transform( name.begin(), name.end(), name.begin(),
|
||||
[]( unsigned char c )
|
||||
{
|
||||
return std::tolower( c );
|
||||
} );
|
||||
|
||||
str << name;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static std::vector<std::string> enumChoices()
|
||||
{
|
||||
std::vector<std::string> out;
|
||||
|
||||
for( auto& strView : magic_enum::enum_names<T>() )
|
||||
{
|
||||
std::string name = { strView.begin(), strView.end() };
|
||||
|
||||
std::transform( name.begin(), name.end(), name.begin(),
|
||||
[]( unsigned char c )
|
||||
{
|
||||
return std::tolower( c );
|
||||
} );
|
||||
|
||||
out.emplace_back( name );
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static std::optional<T> strToEnum( std::string& aInput )
|
||||
{
|
||||
return magic_enum::enum_cast<T>( aInput, magic_enum::case_insensitive );
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static bool getToEnum( const std::string& aInput, T& aOutput )
|
||||
{
|
||||
// If not specified, leave at default
|
||||
if( aInput.empty() )
|
||||
return true;
|
||||
|
||||
if( auto opt = magic_enum::enum_cast<T>( aInput, magic_enum::case_insensitive ) )
|
||||
{
|
||||
aOutput = *opt;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool getToVector3( const std::string& aInput, VECTOR3D& aOutput )
|
||||
{
|
||||
// If not specified, leave at default
|
||||
if( aInput.empty() )
|
||||
return true;
|
||||
|
||||
// Remove potential quotes
|
||||
wxString wxStr = From_UTF8( aInput );
|
||||
|
||||
if( wxStr[0] == '\'' )
|
||||
wxStr = wxStr.AfterFirst( '\'' );
|
||||
|
||||
if( wxStr[wxStr.length() - 1] == '\'' )
|
||||
wxStr = wxStr.BeforeLast( '\'' );
|
||||
|
||||
wxArrayString arr = wxSplit( wxStr, ',', 0 );
|
||||
|
||||
if( arr.size() != 3 )
|
||||
return false;
|
||||
|
||||
VECTOR3D vec;
|
||||
bool success = true;
|
||||
success &= arr[0].Trim().ToCDouble( &vec.x );
|
||||
success &= arr[1].Trim().ToCDouble( &vec.y );
|
||||
success &= arr[2].Trim().ToCDouble( &vec.z );
|
||||
|
||||
if( !success )
|
||||
return false;
|
||||
|
||||
aOutput = vec;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
CLI::PCB_RENDER_COMMAND::PCB_RENDER_COMMAND() : COMMAND( "render" )
|
||||
{
|
||||
addCommonArgs( true, true, false, false );
|
||||
addDefineArg();
|
||||
|
||||
m_argParser.add_description(
|
||||
UTF8STDSTR( _( "Renders the PCB in 3D view to PNG or JPEG image" ) ) );
|
||||
|
||||
m_argParser.add_argument( ARG_WIDTH, ARG_WIDTH_SHORT )
|
||||
.default_value( 1600 )
|
||||
.scan<'i', int>()
|
||||
.metavar( "WIDTH" )
|
||||
.help( UTF8STDSTR( _( "Image width" ) ) );
|
||||
|
||||
m_argParser.add_argument( ARG_HEIGHT, ARG_HEIGHT_SHORT )
|
||||
.default_value( 900 )
|
||||
.scan<'i', int>()
|
||||
.metavar( "HEIGHT" )
|
||||
.help( UTF8STDSTR( _( "Image height" ) ) );
|
||||
|
||||
m_argParser.add_argument( ARG_SIDE )
|
||||
.default_value( std::string( "top" ) )
|
||||
.add_choices( enumChoices<JOB_PCB_RENDER::SIDE>() )
|
||||
.metavar( "SIDE" )
|
||||
.help( UTF8STDSTR( wxString::Format( _( "Render from side. Options: %s" ),
|
||||
enumString<JOB_PCB_RENDER::SIDE>() ) ) );
|
||||
|
||||
m_argParser.add_argument( ARG_BACKGROUND )
|
||||
.default_value( std::string( "" ) )
|
||||
.help( UTF8STDSTR( _( "Image background. Options: transparent, opaque. Default: "
|
||||
"transparent for PNG, opaque for JPEG" ) ) )
|
||||
.metavar( "BG" );
|
||||
|
||||
m_argParser.add_argument( ARG_QUALITY )
|
||||
.default_value( std::string( "basic" ) )
|
||||
.add_choices( enumChoices<JOB_PCB_RENDER::QUALITY>() )
|
||||
.metavar( "QUALITY" )
|
||||
.help( UTF8STDSTR( wxString::Format( _( "Render quality. Options: %s" ),
|
||||
enumString<JOB_PCB_RENDER::QUALITY>() ) ) );
|
||||
|
||||
m_argParser.add_argument( ARG_PRESET )
|
||||
.default_value( std::string( wxString( FOLLOW_PLOT_SETTINGS ) ) )
|
||||
.metavar( "PRESET" )
|
||||
.help( UTF8STDSTR( wxString::Format( _( "Color preset. Options: %s, %s, %s, ..." ),
|
||||
FOLLOW_PCB, FOLLOW_PLOT_SETTINGS,
|
||||
LEGACY_PRESET_FLAG ) ) );
|
||||
|
||||
m_argParser.add_argument( ARG_FLOOR )
|
||||
.flag()
|
||||
.help( UTF8STDSTR( _( "Enables floor, shadows and post-processing, even if disabled in "
|
||||
"quality preset" ) ) );
|
||||
|
||||
m_argParser.add_argument( ARG_PERSPECTIVE )
|
||||
.flag()
|
||||
.help( UTF8STDSTR( _( "Use perspective projection instead of orthogonal" ) ) );
|
||||
|
||||
m_argParser.add_argument( ARG_ZOOM )
|
||||
.default_value( 1.0 )
|
||||
.scan<'g', double>()
|
||||
.metavar( "ZOOM" )
|
||||
.help( UTF8STDSTR( _( "Camera zoom" ) ) );
|
||||
|
||||
m_argParser.add_argument( ARG_PAN )
|
||||
.default_value( std::string( "" ) )
|
||||
.metavar( "VECTOR" )
|
||||
.help( UTF8STDSTR( _( "Pan camera, format 'X,Y,Z' e.g.: '3,0,0'" ) ) );
|
||||
|
||||
m_argParser.add_argument( ARG_PIVOT )
|
||||
.default_value( std::string( "" ) )
|
||||
.metavar( "PIVOT" )
|
||||
.help( UTF8STDSTR( _( "Set pivot point relative to the board center in centimeters, format 'X,Y,Z' "
|
||||
"e.g.: '-10,2,0'" ) ) );
|
||||
|
||||
m_argParser.add_argument( ARG_ROTATE )
|
||||
.default_value( std::string( "" ) )
|
||||
.metavar( "ANGLES" )
|
||||
.help( UTF8STDSTR(
|
||||
_( "Rotate board, format 'X,Y,Z' e.g.: '-45,0,45' for isometric view" ) ) );
|
||||
}
|
||||
|
||||
|
||||
int CLI::PCB_RENDER_COMMAND::doPerform( KIWAY& aKiway )
|
||||
{
|
||||
std::unique_ptr<JOB_PCB_RENDER> renderJob( new JOB_PCB_RENDER( true ) );
|
||||
|
||||
renderJob->m_outputFile = m_argOutput;
|
||||
renderJob->m_filename = m_argInput;
|
||||
renderJob->SetVarOverrides( m_argDefineVars );
|
||||
|
||||
renderJob->m_colorPreset = m_argParser.get<std::string>( ARG_PRESET );
|
||||
renderJob->m_width = m_argParser.get<int>( ARG_WIDTH );
|
||||
renderJob->m_height = m_argParser.get<int>( ARG_HEIGHT );
|
||||
renderJob->m_zoom = m_argParser.get<double>( ARG_ZOOM );
|
||||
renderJob->m_perspective = m_argParser.get<bool>( ARG_PERSPECTIVE );
|
||||
renderJob->m_floor = m_argParser.get<bool>( ARG_FLOOR );
|
||||
|
||||
getToEnum( m_argParser.get<std::string>( ARG_QUALITY ), renderJob->m_quality );
|
||||
getToEnum( m_argParser.get<std::string>( ARG_SIDE ), renderJob->m_side );
|
||||
|
||||
if( !getToEnum( m_argParser.get<std::string>( ARG_BACKGROUND ), renderJob->m_bgStyle ) )
|
||||
{
|
||||
wxFprintf( stderr, _( "Invalid background\n" ) );
|
||||
return EXIT_CODES::ERR_ARGS;
|
||||
}
|
||||
|
||||
if( !getToVector3( m_argParser.get<std::string>( ARG_ROTATE ), renderJob->m_rotation ) )
|
||||
{
|
||||
wxFprintf( stderr, _( "Invalid rotation format\n" ) );
|
||||
return EXIT_CODES::ERR_ARGS;
|
||||
}
|
||||
|
||||
if( !getToVector3( m_argParser.get<std::string>( ARG_PAN ), renderJob->m_pan ) )
|
||||
{
|
||||
wxFprintf( stderr, _( "Invalid pan format\n" ) );
|
||||
return EXIT_CODES::ERR_ARGS;
|
||||
}
|
||||
|
||||
if( !getToVector3( m_argParser.get<std::string>( ARG_PIVOT ), renderJob->m_pivot ) )
|
||||
{
|
||||
wxFprintf( stderr, _( "Invalid pivot format\n" ) );
|
||||
return EXIT_CODES::ERR_ARGS;
|
||||
}
|
||||
|
||||
if( m_argOutput.Lower().EndsWith( wxS( ".png" ) ) )
|
||||
{
|
||||
renderJob->m_format = JOB_PCB_RENDER::FORMAT::PNG;
|
||||
}
|
||||
else if( m_argOutput.Lower().EndsWith( wxS( ".jpg" ) )
|
||||
|| m_argOutput.Lower().EndsWith( wxS( ".jpeg" ) ) )
|
||||
{
|
||||
renderJob->m_format = JOB_PCB_RENDER::FORMAT::JPEG;
|
||||
}
|
||||
else
|
||||
{
|
||||
wxFprintf( stderr, _( "Invalid image format\n" ) );
|
||||
return EXIT_CODES::ERR_ARGS;
|
||||
}
|
||||
|
||||
int exitCode = aKiway.ProcessJob( KIWAY::FACE_PCB, renderJob.get() );
|
||||
|
||||
return exitCode;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
|
||||
* Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef COMMAND_EXPORT_PCB_RENDER_H
|
||||
#define COMMAND_EXPORT_PCB_RENDER_H
|
||||
|
||||
#include "command.h"
|
||||
|
||||
namespace CLI
|
||||
{
|
||||
class PCB_RENDER_COMMAND : public COMMAND
|
||||
{
|
||||
public:
|
||||
PCB_RENDER_COMMAND();
|
||||
|
||||
protected:
|
||||
int doPerform( KIWAY& aKiway ) override;
|
||||
};
|
||||
} // namespace CLI
|
||||
|
||||
#endif
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2004-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -49,6 +49,7 @@
|
|||
#include "cli/command_pcb.h"
|
||||
#include "cli/command_pcb_export.h"
|
||||
#include "cli/command_pcb_drc.h"
|
||||
#include "cli/command_pcb_render.h"
|
||||
#include "cli/command_pcb_export_3d.h"
|
||||
#include "cli/command_pcb_export_drill.h"
|
||||
#include "cli/command_pcb_export_dxf.h"
|
||||
|
@ -128,6 +129,7 @@ struct COMMAND_ENTRY
|
|||
|
||||
static CLI::PCB_COMMAND pcbCmd{};
|
||||
static CLI::PCB_DRC_COMMAND pcbDrcCmd{};
|
||||
static CLI::PCB_RENDER_COMMAND pcbRenderCmd{};
|
||||
static CLI::PCB_EXPORT_DRILL_COMMAND exportPcbDrillCmd{};
|
||||
static CLI::PCB_EXPORT_DXF_COMMAND exportPcbDxfCmd{};
|
||||
static CLI::PCB_EXPORT_3D_COMMAND exportPcbGlbCmd{ "glb", UTF8STDSTR( _( "Export GLB (binary GLTF)" ) ), JOB_EXPORT_PCB_3D::FORMAT::GLB };
|
||||
|
@ -183,6 +185,9 @@ static std::vector<COMMAND_ENTRY> commandStack = {
|
|||
{
|
||||
&pcbDrcCmd
|
||||
},
|
||||
{
|
||||
&pcbRenderCmd
|
||||
},
|
||||
{
|
||||
&exportPcbCmd,
|
||||
{
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <jobs/job_export_pcb_pos.h>
|
||||
#include <jobs/job_export_pcb_svg.h>
|
||||
#include <jobs/job_export_pcb_3d.h>
|
||||
#include <jobs/job_pcb_render.h>
|
||||
#include <jobs/job_pcb_drc.h>
|
||||
#include <cli/exit_codes.h>
|
||||
#include <exporters/place_file_exporter.h>
|
||||
|
@ -62,6 +63,9 @@
|
|||
#include <pcbnew_settings.h>
|
||||
#include <pcbplot.h>
|
||||
#include <pgm_base.h>
|
||||
#include <3d_rendering/raytracing/render_3d_raytrace_ram.h>
|
||||
#include <3d_rendering/track_ball.h>
|
||||
#include <project_pcb.h>
|
||||
#include <pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h>
|
||||
#include <reporter.h>
|
||||
#include <string_utf8_map.h>
|
||||
|
@ -73,10 +77,18 @@
|
|||
#include "pcbnew_scripting_helpers.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef TRANSPARENT
|
||||
#undef TRANSPARENT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
PCBNEW_JOBS_HANDLER::PCBNEW_JOBS_HANDLER( KIWAY* aKiway ) :
|
||||
JOB_DISPATCHER( aKiway )
|
||||
{
|
||||
Register( "3d", std::bind( &PCBNEW_JOBS_HANDLER::JobExportStep, this, std::placeholders::_1 ) );
|
||||
Register( "render", std::bind( &PCBNEW_JOBS_HANDLER::JobExportRender, this, std::placeholders::_1 ) );
|
||||
Register( "svg", std::bind( &PCBNEW_JOBS_HANDLER::JobExportSvg, this, std::placeholders::_1 ) );
|
||||
Register( "dxf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportDxf, this, std::placeholders::_1 ) );
|
||||
Register( "pdf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPdf, this, std::placeholders::_1 ) );
|
||||
|
@ -212,6 +224,186 @@ int PCBNEW_JOBS_HANDLER::JobExportStep( JOB* aJob )
|
|||
}
|
||||
|
||||
|
||||
int PCBNEW_JOBS_HANDLER::JobExportRender( JOB* aJob )
|
||||
{
|
||||
JOB_PCB_RENDER* aRenderJob = dynamic_cast<JOB_PCB_RENDER*>( aJob );
|
||||
|
||||
if( aRenderJob == nullptr )
|
||||
return CLI::EXIT_CODES::ERR_UNKNOWN;
|
||||
|
||||
if( aJob->IsCli() )
|
||||
m_reporter->Report( _( "Loading board\n" ), RPT_SEVERITY_INFO );
|
||||
|
||||
BOARD* brd = LoadBoard( aRenderJob->m_filename, true );
|
||||
brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
|
||||
|
||||
BOARD_ADAPTER m_boardAdapter;
|
||||
|
||||
m_boardAdapter.SetBoard( brd );
|
||||
m_boardAdapter.m_IsBoardView = false;
|
||||
m_boardAdapter.m_IsPreviewer =
|
||||
true; // Force display 3D models, regardless the 3D viewer options
|
||||
|
||||
EDA_3D_VIEWER_SETTINGS* cfg =
|
||||
Pgm().GetSettingsManager().GetAppSettings<EDA_3D_VIEWER_SETTINGS>();
|
||||
|
||||
if( aRenderJob->m_bgStyle == JOB_PCB_RENDER::BG_STYLE::TRANSPARENT
|
||||
|| aRenderJob->m_bgStyle == JOB_PCB_RENDER::BG_STYLE::DEFAULT
|
||||
&& aRenderJob->m_format == JOB_PCB_RENDER::FORMAT::PNG )
|
||||
{
|
||||
BOARD_ADAPTER::g_DefaultBackgroundTop = COLOR4D( 1.0, 1.0, 1.0, 0.0 );
|
||||
BOARD_ADAPTER::g_DefaultBackgroundBot = COLOR4D( 1.0, 1.0, 1.0, 0.0 );
|
||||
}
|
||||
|
||||
if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::BASIC )
|
||||
{
|
||||
// Silkscreen is pixelated without antialiasing
|
||||
cfg->m_Render.raytrace_anti_aliasing = true;
|
||||
|
||||
cfg->m_Render.raytrace_backfloor = false;
|
||||
cfg->m_Render.raytrace_post_processing = false;
|
||||
|
||||
cfg->m_Render.raytrace_procedural_textures = false;
|
||||
cfg->m_Render.raytrace_reflections = false;
|
||||
cfg->m_Render.raytrace_shadows = false;
|
||||
|
||||
// Better colors
|
||||
cfg->m_Render.differentiate_plated_copper = true;
|
||||
|
||||
// Tracks below soldermask are not visible without refractions
|
||||
cfg->m_Render.raytrace_refractions = true;
|
||||
cfg->m_Render.raytrace_recursivelevel_refractions = 1;
|
||||
}
|
||||
else if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::HIGH )
|
||||
{
|
||||
cfg->m_Render.raytrace_anti_aliasing = true;
|
||||
cfg->m_Render.raytrace_backfloor = true;
|
||||
cfg->m_Render.raytrace_post_processing = true;
|
||||
cfg->m_Render.raytrace_procedural_textures = true;
|
||||
cfg->m_Render.raytrace_reflections = true;
|
||||
cfg->m_Render.raytrace_shadows = true;
|
||||
cfg->m_Render.raytrace_refractions = true;
|
||||
cfg->m_Render.differentiate_plated_copper = true;
|
||||
}
|
||||
|
||||
if( aRenderJob->m_floor )
|
||||
{
|
||||
cfg->m_Render.raytrace_backfloor = true;
|
||||
cfg->m_Render.raytrace_shadows = true;
|
||||
cfg->m_Render.raytrace_post_processing = true;
|
||||
}
|
||||
|
||||
cfg->m_CurrentPreset = aRenderJob->m_colorPreset;
|
||||
m_boardAdapter.m_Cfg = cfg;
|
||||
|
||||
m_boardAdapter.Set3dCacheManager( PROJECT_PCB::Get3DCacheManager( brd->GetProject() ) );
|
||||
|
||||
static std::map<JOB_PCB_RENDER::SIDE, VIEW3D_TYPE> s_viewCmdMap = {
|
||||
{ JOB_PCB_RENDER::SIDE::TOP, VIEW3D_TYPE::VIEW3D_TOP },
|
||||
{ JOB_PCB_RENDER::SIDE::BOTTOM, VIEW3D_TYPE::VIEW3D_BOTTOM },
|
||||
{ JOB_PCB_RENDER::SIDE::LEFT, VIEW3D_TYPE::VIEW3D_LEFT },
|
||||
{ JOB_PCB_RENDER::SIDE::RIGHT, VIEW3D_TYPE::VIEW3D_RIGHT },
|
||||
{ JOB_PCB_RENDER::SIDE::FRONT, VIEW3D_TYPE::VIEW3D_FRONT },
|
||||
{ JOB_PCB_RENDER::SIDE::BACK, VIEW3D_TYPE::VIEW3D_BACK },
|
||||
};
|
||||
|
||||
PROJECTION_TYPE projection =
|
||||
aRenderJob->m_perspective ? PROJECTION_TYPE::PERSPECTIVE : PROJECTION_TYPE::ORTHO;
|
||||
|
||||
wxSize windowSize( aRenderJob->m_width, aRenderJob->m_height );
|
||||
TRACK_BALL camera( 2 * RANGE_SCALE_3D );
|
||||
|
||||
camera.SetProjection( projection );
|
||||
camera.SetCurWindowSize( windowSize );
|
||||
|
||||
RENDER_3D_RAYTRACE_RAM raytrace( m_boardAdapter, camera );
|
||||
raytrace.SetCurWindowSize( windowSize );
|
||||
|
||||
for( bool first = true; raytrace.Redraw( false, m_reporter, m_reporter ); first = false )
|
||||
{
|
||||
if( first )
|
||||
{
|
||||
const float cmTo3D = m_boardAdapter.BiuTo3dUnits() * pcbIUScale.mmToIU( 10.0 );
|
||||
|
||||
// First redraw resets lookat point to the board center, so set up the camera here
|
||||
camera.ViewCommand_T1( s_viewCmdMap[aRenderJob->m_side] );
|
||||
|
||||
camera.SetLookAtPos_T1(
|
||||
camera.GetLookAtPos_T1()
|
||||
+ SFVEC3F( aRenderJob->m_pivot.x, aRenderJob->m_pivot.y, aRenderJob->m_pivot.z )
|
||||
* cmTo3D );
|
||||
|
||||
camera.Pan_T1(
|
||||
SFVEC3F( aRenderJob->m_pan.x, aRenderJob->m_pan.y, aRenderJob->m_pan.z ) );
|
||||
|
||||
camera.Zoom_T1( aRenderJob->m_zoom );
|
||||
|
||||
camera.RotateX_T1( DEG2RAD( aRenderJob->m_rotation.x ) );
|
||||
camera.RotateY_T1( DEG2RAD( aRenderJob->m_rotation.y ) );
|
||||
camera.RotateZ_T1( DEG2RAD( aRenderJob->m_rotation.z ) );
|
||||
|
||||
camera.Interpolate( 1.0f );
|
||||
camera.SetT0_and_T1_current_T();
|
||||
camera.ParametersChanged();
|
||||
}
|
||||
}
|
||||
|
||||
GLubyte* rgbaBuffer = raytrace.GetBuffer();
|
||||
wxSize realSize = raytrace.GetRealBufferSize();
|
||||
bool success = !!rgbaBuffer;
|
||||
|
||||
if( rgbaBuffer )
|
||||
{
|
||||
const unsigned int wxh = realSize.x * realSize.y;
|
||||
|
||||
unsigned char* rgbBuffer = (unsigned char*) malloc( wxh * 3 );
|
||||
unsigned char* alphaBuffer = (unsigned char*) malloc( wxh );
|
||||
|
||||
unsigned char* rgbaPtr = rgbaBuffer;
|
||||
unsigned char* rgbPtr = rgbBuffer;
|
||||
unsigned char* alphaPtr = alphaBuffer;
|
||||
|
||||
for( int y = 0; y < realSize.y; y++ )
|
||||
{
|
||||
for( int x = 0; x < realSize.x; x++ )
|
||||
{
|
||||
rgbPtr[0] = rgbaPtr[0];
|
||||
rgbPtr[1] = rgbaPtr[1];
|
||||
rgbPtr[2] = rgbaPtr[2];
|
||||
alphaPtr[0] = rgbaPtr[3];
|
||||
|
||||
rgbaPtr += 4;
|
||||
rgbPtr += 3;
|
||||
alphaPtr += 1;
|
||||
}
|
||||
}
|
||||
|
||||
wxImage image( realSize );
|
||||
image.SetData( rgbBuffer );
|
||||
image.SetAlpha( alphaBuffer );
|
||||
image = image.Mirror( false );
|
||||
|
||||
image.SetOption( wxIMAGE_OPTION_QUALITY, 90 );
|
||||
image.SaveFile( aRenderJob->m_outputFile,
|
||||
aRenderJob->m_format == JOB_PCB_RENDER::FORMAT::PNG ? wxBITMAP_TYPE_PNG
|
||||
: wxBITMAP_TYPE_JPEG );
|
||||
}
|
||||
|
||||
m_reporter->Report( wxString::Format( _( "Actual image size: %dx%d" ), realSize.x, realSize.y )
|
||||
+ wxS( "\n" ),
|
||||
RPT_SEVERITY_INFO );
|
||||
|
||||
if( success )
|
||||
m_reporter->Report( _( "Successfully created 3D render image" ) + wxS( "\n" ),
|
||||
RPT_SEVERITY_INFO );
|
||||
else
|
||||
m_reporter->Report( _( "Error creating 3D render image" ) + wxS( "\n" ),
|
||||
RPT_SEVERITY_ERROR );
|
||||
|
||||
return CLI::EXIT_CODES::OK;
|
||||
}
|
||||
|
||||
|
||||
int PCBNEW_JOBS_HANDLER::JobExportSvg( JOB* aJob )
|
||||
{
|
||||
JOB_EXPORT_PCB_SVG* aSvgJob = dynamic_cast<JOB_EXPORT_PCB_SVG*>( aJob );
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
|
||||
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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
|
||||
|
@ -36,6 +36,7 @@ class PCBNEW_JOBS_HANDLER : public JOB_DISPATCHER
|
|||
public:
|
||||
PCBNEW_JOBS_HANDLER( KIWAY* aKiway );
|
||||
int JobExportStep( JOB* aJob );
|
||||
int JobExportRender( JOB* aJob );
|
||||
int JobExportSvg( JOB* aJob );
|
||||
int JobExportDxf( JOB* aJob );
|
||||
int JobExportPdf( JOB* aJob );
|
||||
|
|
Loading…
Reference in New Issue