Compare commits

..

191 Commits

Author SHA1 Message Date
jean-pierre charras 9f35e384c1 Pcbnew: fix a few plot issues (from master branch) 2017-08-01 12:39:06 +02:00
Chris Pavlina 6b1b6d4ff7 Add several missing libraries 2017-07-31 12:50:45 -04:00
jean-pierre charras be070d95be Fix issues in plot functions, when used from python scripts. 2017-07-25 10:12:08 +02:00
jean-pierre charras 17f7921311 kicad: create zip archive: test for write file error (crashes when the folder was not writable) 2017-07-24 18:07:29 +02:00
Wayne Stambaugh 631f6d53d3 Tag stable release 4.0.7 2017-07-14 15:17:29 -04:00
Wayne Stambaugh aba04c6ec5 Remove leading/trailing white space error message from field validator.
The illegal white space testing for reference and value (library editor
only) fields are adequate to ensure the user cannot enter invalid white
space characters.  Leading and/or trailing white space should not be an
issue for field storage in the schematic file as they are quoted.  Rather
than silently removing the leading and/or trailing white space which is
frowned upon, let the user fix it.

Fixes lp:1659526

https://bugs.launchpad.net/kicad/+bug/1659526
2017-07-14 13:43:27 -04:00
Maciej Suminski 133cb01f79 Fix crash when dragging a track
Fixes: lp:1657226
* https://bugs.launchpad.net/kicad/+bug/1657226
2017-07-13 10:54:12 +02:00
jean-pierre charras 464175e995 Fix possible crash and issues when a incorrect fp lib table is loaded:
correct lines are loaded, and pcbnew is no longer aborted.
2017-07-12 20:27:18 +02:00
jean-pierre charras c0fab4b350 Cvpcb: fix incorrect automatic assignments when using .equ files and the automatic association.
Fix from master branch.
2017-06-10 20:12:02 +02:00
jean-pierre charras 17c8198c05 Better error messages when throwing an io error or parse error.
Only the name of the .cpp file throwing the error instead of its full path is printed, like in master branch.
2017-06-04 11:15:45 +02:00
Cirilo Bernardo 683da9acd1 Fix default line widths for non-mm units in DXF import 2017-05-29 09:51:28 +02:00
jean-pierre charras 5a67fc99d3 Fixes: pl-editor doesn't save text thickness when it is not the default value (from master) 2017-05-29 08:00:38 +02:00
jean-pierre charras a7223a95b9 Fix style of gost page layouts in accordance with GOST (from master) 2017-05-29 07:57:16 +02:00
jean-pierre charras 58f90b3adb Eeschema bom scripts: move python scripts to eeschema/plugins/python_scripts and xsl scripts to subdir xsl_scripts.
Python scripts are now installed (previously: were ignored by the make install command)
Better comments in python scripts.
2017-05-15 16:40:21 +02:00
Eldar Khayrullin a374f46b5e Pcbnew: add option to plot DXF editable text
Add option to plot DXF oneline ASCII text as editable text (in non-outline mode)

Fixes: lp:1423515
* https://bugs.launchpad.net/kicad/+bug/1423515
2017-05-08 08:24:22 -04:00
Eldar Khayrullin bfacf02360 Pcbnew: add option to plot DXF lines in outline mode
Add option to plot dialog to plot DXF layers *.Cu, *.Adhes, *.Paste, and
*.Mask in outline mode or line mode.

Fixes lp:1643330

https://bugs.launchpad.net/kicad/+bug/1643330
2017-05-08 08:24:10 -04:00
Wayne Stambaugh 4e8a35cb84 Don't apply last line width to text thickness in symbol library editor.
The symbol library header was setting the text thickness using the
last line thickness setting which is incorrect so use the default
thickness when creating new text objects.

Fixes lp:1635344

https://bugs.launchpad.net/kicad/+bug/1635344
2017-05-04 16:31:02 -04:00
Wayne Stambaugh 6a9f38ecc4 Pcbnew: continue loading footprints after first failure.
The footprint library cache handler would throw an exception on the
first error it encountered preventing all subsequent footprint files
from being parsed even if there was nothing wrong with them.  This
commit queues errors until all of the footprint files in the folder
have been parsed.

Fixes lp:1416736

https://bugs.launchpad.net/kicad/+bug/1416736
2017-05-04 16:25:14 -04:00
jean-pierre charras 593136aca3 Remove some useless or incorrect wxASSERT in plot functions.
Fixes: lp:1685188 Crash on export SVG file with mirrored option
https://bugs.launchpad.net/kicad/+bug/1685188
2017-04-26 09:10:05 +02:00
jean-pierre charras 1754b42ba3 Dialog copper zones: fix a tooltip error 2017-04-22 10:17:59 +02:00
jean-pierre charras 3ae069ed4f Fixes: lp:1684998 (append a board in GAL mode can crashes Pcbnew)
https://bugs.launchpad.net/kicad/+bug/1684998

The crash is due to the fact updating nets and netclasses was made too late, after use.
2017-04-22 09:09:31 +02:00
Wayne Stambaugh fc527f3cc1 Fix zone properties dialog level setting tooltip.
Fix a spelling error and improve the clarity of the zone priority level
tooltip information.

Fixes lp:1681024

https://bugs.launchpad.net/kicad/+bug/1681024
2017-04-10 14:31:11 -04:00
hauptmech 7a5e632455 Prevent segfault when aOutline has no vertices.
When attempting to read a pcad file exported from Altium, kicad was
segfaulting because it was trying to access an empty array. This patch
fixes that.

The reason the array was empty was the the board outline in the pcad
file was composed of only arcs and the plugin only processes lines in
the board outline. Adding this functionality is for another patch I
suppose.

Signed-off-by: Clemens Koller <cko@embeon.de>
2017-04-03 10:46:57 -04:00
Chris Pavlina 82d7a4e61e Highlight the first choice in rescue dialog
Fixes: lp:1455970
* https://bugs.launchpad.net/kicad/+bug/1455970
2017-03-27 09:20:28 -04:00
Wayne Stambaugh 63569551a4 Fix broken links and add correct links to about dialog.
Fixes lp:1670582

https://bugs.launchpad.net/kicad/+bug/1670582
2017-03-08 08:28:15 -05:00
jean-pierre charras 3b7aa48d16 Pcbnew: fix bug: files written when layers have numeric name (like +24)cannot be read
Remove a printf clearly for debug, certainly a very old bug.
2017-02-27 08:12:07 +01:00
Wayne Stambaugh 249b0a0ce5 Reset KiCad version for 4.0.7 stable release development. 2017-02-26 11:30:35 -05:00
Wayne Stambaugh 3c6959b7de Tag stable release 4.0.6 2017-02-17 15:11:08 -05:00
Oliver e5307ca1fb Fix for bug where rotating / editing a selected item would remove it from screen
- Added test to see if there was a currently-editing item

Fixes: lp:1661866

https://bugs.launchpad.net/kicad/+bug/1661866
2017-02-07 09:30:11 -05:00
Wayne Stambaugh d1f8dbb9de Fix rotate bug in symbol library editor.
The rotate hotkey was rotating individual items when a block was selected
which is invalid behavior.  Add check for block mode and disable rotating
items when block mode is active.

Fixes: lp:1660875

https://bugs.launchpad.net/kicad/+bug/1660875
2017-02-01 15:10:07 -05:00
Chris Pavlina 99d7a35797 Reorder eeschema toolbar slightly
- Put the output generation steps (annotation through pcbnew) in the
  correct order as expected by the user running through them.

- Add a Plot button to match pcbnew
2017-01-31 16:08:57 -05:00
jean-pierre charras 0145a03f79 In SetActiveLayer(): fix a potential bug, as a GAL method was called in Legacy mode.
This is a fix from commit b66cb871e6 in master branch.
2017-01-31 11:11:03 +01:00
jean-pierre charras df191606ab Fix a potential incompatibility (due to an old bug) with files which could be created by some recent pcbnew versions
It is unusual to fix an incompatibility with later versions, but it is due to a bug existing in this version,
and this is especially important for footprint files.
2017-01-28 09:00:54 +01:00
Wayne Stambaugh 556be7b431 Do not use default board solder mask clearance in footprint editor.
The footprint editor was displaying the default solder mask clearance
defined by the temporary BOARD object created a start up.  Change the
temporary BOARD default solder mask to 0 so the pad or footprint solder
mask clearance setting is displayed when editing the footprint.

fixes lp:1653980

https://bugs.launchpad.net/kicad/+bug/1653980
2017-01-27 07:52:12 -05:00
Simon Richter e15ba3bf32 Add missing include directory
The common library uses CURL.
2017-01-27 07:38:23 -05:00
jean-pierre charras c23c52834c cleanup a comment 2017-01-24 17:53:33 +01:00
jean-pierre charras 981fddc649 Try to replace avhttp by Curl 2017-01-24 17:44:06 +01:00
jean-pierre charras 5127a6bd09 Fix an issue (from a patch of the master branch): slashes are not translated from \ in windows to / on unix
(see https://bugs.launchpad.net/kicad/+bug/16585)
2017-01-24 17:41:03 +01:00
Wayne Stambaugh 136ba26896 Reset KiCad version for 4.0.6 stable release development. 2017-01-24 10:26:54 -05:00
Wayne Stambaugh 575b22d018 Stable 4.0.5 release.
Set version string to "4.0.5" in KiCadVersion.cmake
Add .gitignore from master branch.
2016-12-02 10:49:09 -05:00
jean-pierre charras 5f01ca8f88 Fixes: lp:1645430 (CSV BOM generation using bom2csv.xsl script with custom entries has wrong format)
https://bugs.launchpad.net/kicad/+bug/1645430
2016-12-02 09:31:04 -05:00
Maciej Suminski 5a3c944b2a Fix crashes when BOARD members are changed and PNS is active
PNS has its own data model with pointers to the BOARD members. If the
tool is active and pointers become stale, pcbnew crashes.

Currently there is a workaround that deactivates the current tool when a
dialog opens. This is the way it is done in the legacy canvas as well.

Fixes: lp:1553804
* https://bugs.launchpad.net/kicad/+bug/1553804
2016-12-01 15:11:26 +01:00
Wayne Stambaugh 50a4b5553a Version string improvements.
Define empty string variable KICAD_BRANCH_NAME that can be used as an
optional version string element.  When git is used to build the version
string, this variable is set to the git branch name.  It can also be
defined at configuration time as an optional string appended to the
$KICAD_VERSION variable.

Define empty string variable KICAD_VERSION_EXTRA that can be set by
the user at configuration.

The variables KICAD_BRANCH_NAME and KICAD_VERSION_EXTRA are only
appended to KICAD_VERSION if they are set.  Otherwise, only KICAD_VERSION
is uses as the version string.

Update the developer building from source document to reflect the changes.
2016-11-28 09:15:04 -05:00
Chris Pavlina 4cb084cd63 Bring back KICAD_REPO_NAME 2016-11-24 13:03:35 -05:00
Chris Pavlina a458342cfc Fix KICAD_BUILD_VERSION build option 2016-11-24 13:03:34 -05:00
jean-pierre charras 8023c7a794 Pcbnew: fix outdated environment vars settings for Kicad python on Windows (from master branch):
On Windows, previously, Pcbnew try to set env vars PYTHONPATH, if <kicad>/bin/python27_us folder is found.
Now, if python.exe is found in kicad bin folder (therefore if our python executable and libs are
installed in Kicad), PYTHONPATH and PYTHONHOME are set to an empty string.
( the default python path work fine with our standard python install )
2016-11-14 08:35:12 +01:00
jean-pierre charras 65fe561a4b Fix from master branch: lp:1635723 (pcbnew: allows sometimes to draw tracks in non copper layers in Gal Mode) 2016-11-13 19:03:52 +01:00
Jean-Noel Avila 18f77b894e Fix off-by-one in saving bitmaps 2016-11-09 09:53:47 +01:00
jean-pierre charras 94a3390544 * Pcbnew: in fill zones calculations, make polygons strictly simple before fracturing them. 2016-11-06 19:50:38 +01:00
jean-pierre charras cec3e300a8 fix incorrect indentation which generates compil warnings 2016-11-06 19:42:10 +01:00
jean-pierre charras a262445047 Fixes: lp:1638499 (footprint editor, footprint transform: incorrect mirror for pads (noticeable only for pads with offset)
https://bugs.launchpad.net/kicad/+bug/1638499
2016-11-05 15:53:01 -04:00
Henner Zeller 0fbdec4c08 Pcbnew: prevent reversal of pad loading order when loading board.
When opening a board file and storing it again, the pads in all
embedded modules get reversed.  This is generally not really nice
if the PCB is managed by version control as it creates churn and
could make merges hard.
2016-10-17 10:17:37 -04:00
Wayne Stambaugh de52ae6c70 Allow the contents of KiCadVersion.cmake to override git version.
When the version string in KiCadVersion.cmake is set to something other
than the default "no-vcs-found", it ignores the git version even if a
.git folder exists in the source folder.
2016-10-14 14:41:36 -04:00
Wayne Stambaugh 9ca6405bcb Minor version string generation improvements.
Remove the KICAD_REPO_NAME option from the main cmake file and the
generated config.h file since it is no longer used.

Set the default branch name to "undefined" in CreateGitVersionHeader.cmake
instead of the KICAD_REPO_NAME option.

Remove generating KICAD_FULL_VERSION from CreateGitVersionHeader.cmake
and add it to WriteVersionHeader.cmake so that the default settings and
the new KiCadVersion.cmake definitions can be used to generate the full
version string as well.

Check to see if the branch name is set and only use the version to
generate the full version string.  This allows the use of the KiCad
version cmake file to create a version only string like "4.0.4" with
no trailing branch name.

Change build_version.cpp to use the full version string rather than
concatenating the version and branch strings.
2016-10-14 08:09:13 -04:00
Wayne Stambaugh 1dc747c0ae Improve version string generation for stable release source archives.
Add KiCadVersion.cmake to set the build version and branch name.

Update WriteVersionHeader.cmake to include KiCadVersion.cmake to set
the defaults in case no .git directory is found.
2016-10-12 21:05:48 -04:00
Chris Pavlina 183835ee67 cmake: rewrite version header when branch changes
Before, only KICAD_BUILD_VERSION, which includes the hash but not the
branch, was compared when deciding whether to regenerate
kicad_build_version.h. This header also contains the branch name though,
so we should compare both to address the case of two branches pointing
at the same commit.
2016-10-12 20:57:10 -04:00
Chris Pavlina 6dbe262b53 Update version string formatting after git migration
It is no longer necessary (or sensible) to include a simulated bzr
revision number, and we can reliably get a branch name now. Therefore,
the new version strings look like:

(2016-08-26 revision 67230ac)-master
 |                   |        |
 |                   |        branch name, "HEAD" if not on a branch,
 |                   |          or "unknown" if no .git present
 |                   |
 |                   abbreviated commit hash, or no-git if no .git
 |                     present
 |
 date of commit, or date of build if no .git present

Signed-off-by: Chris Pavlina <pavlina.chris@gmail.com>
2016-10-12 20:32:38 -04:00
Wayne Stambaugh e074c798bf CvPcb: remove broken footprint documentation feature.
At one point, all of the footprints provided by the KiCad footprint
libraries were merged into a single pdf file. The link to open this
file was provided on the toolbar. Since the footprint libraries have
been split out into individual repositories, this file is no longer
created so the toolbar button and the underlying code to open this
file were removed.

Improve a few CvPcb menu strings.

Fixes lp:702785

https://bugs.launchpad.net/ubuntu/+source/kicad/+bug/702785
2016-10-11 20:14:06 -04:00
Maciej Suminski bd1aae9071 Fixed a crash when a negative (although invalid) net code occurs in legacy plugin 2016-10-11 21:24:37 +02:00
Wayne Stambaugh 6382db4ebf Pcbnew: fix epic footprint editor DXF import fail.
The unfortunate combination of using static_cast to promote board items
to module items then using the assignment operator without any thought as
to what would happen in MODULE::Add() caused the board objects to not be
added to the module.  This is expected because board items cannot be in
modules.  Did this ever work or did someone have a colossal brain cramp?
If it did work, who ever changed it did not test it because in debug
builds, you would have gotten and assertion on every object imported.  On
release builds nothing is imported silently.

Add module object types to the DXF importer and code to choose which type
of object to import.

Remove offending static casts and assignment operator and pass the correct
object directly to the MODULE::Add() function when importing DXF in the
footprint editor.

The usual coding policy fixes.
2016-10-07 22:06:09 -04:00
Wayne Stambaugh 8151ec387c Pcbnew: fix drill file naming issue.
On windows when the project path include a remote volume name (\\NAME),
the volume name does not get cleared by calling wxFileName.SetDir( "" ).
This caused the volume name to be prepended to the file name when
calling wxFileName::GetFullPath().  Use wxFileName::GetFullName()
which resolves the issue.

Fixes lp:1606240

https://bugs.launchpad.net/kicad/+bug/1606240
2016-10-07 15:05:32 -04:00
jean-pierre charras 6e1d45c79e Gerbview: Fix a compil issue I created when copying a fix from the master branch 2016-10-07 19:23:45 +02:00
jean-pierre charras 1d05076761 Eeschema: remove a line which uses a non existing enum value. 2016-10-04 10:26:58 +02:00
jean-pierre charras 89e7d89223 Fix from master branch (lp:1630105 Gerbview print dialog does not display graphic layers list on some windows managers like Unity) 2016-10-04 10:25:35 +02:00
Maciej Suminski 115d70e060 Fixed a crash when drawing a single point polyline 2016-09-29 09:55:42 -04:00
Wayne Stambaugh 1a89a0601a Eeschema: fix assertion on delete node hot key while busy.
Performing a delete node hot key operation while Eeschema is busy performing
another operation causes an assertion in the delete node command event
handler in debug builds.  It also causes the operation in progress to be
cleared if the assertion is ignored or in release builds.

Fix a similar issue when the leave current sheet hot key is called while
busing performing another operation which causes rather interesting behavior
in the sheet that was exited.

Fixes lp:1627434

https://bugs.launchpad.net/kicad/+bug/1627434
2016-09-28 19:26:35 -04:00
Wayne Stambaugh ca0aa6c971 Pcbnew: fix several auto save file issues.
* When Pcbnew is launched in the stand alone mode with no board file command
  line option, the project path is set to the current working directory.  The
  user may not have write access to the current working directory which would
  cause the auto save to generate an error.  If the user does not have write
  access to the current working directory, set the path to a platform specific
  temporary path that the user has write permission.

* When Pcbnew is launched in the stand alone mode with no board file command
  line option, the default BOARD object has no file name.  Set the file name
  to "noname.kicad_pcb" to fix incorrect auto save file name and set the path
  to the user's platform specific document folder.

* Delete orphaned auto save files when closing without saving due to broken
  auto save file generation logic which prepended the file name with "$" rather
  than "_autosave-".

* Fixes: lp:1596382
2016-09-27 20:55:24 -04:00
jp charras 5b4542231e KiCad: fix crash when attempting to view ERC log with text editor.
Fixes lp:1619436

https://bugs.launchpad.net/kicad/+bug/1619436
2016-09-27 15:03:26 -04:00
jean-pierre charras fa85cb3a8b Do not allow spaces in component name (value field) in component library editor, in dialogs (Edit field, Create component).
In component libraries, a space in name breaks the library, and is not allowed.
2016-08-19 21:49:48 -04:00
Chris Pavlina 853984120c FUTURE_FORMAT_ERROR: don't nest errors unnecessarily. 2016-08-17 15:13:28 -04:00
Wayne Stambaugh be62a1ade6 Eeschema: fix broken component reference field in hierarchies. (fixes lp:1572812) 2016-08-10 09:44:19 -04:00
Simon Wells 3b4cdd96ab Hide OpenGL scrollbars on OS X to fix freeze. (fixes lp:1553428) 2016-08-09 15:07:17 -04:00
Jean-Pierre Charras f776b7c3fb Pcbnew: fix a minor bug where the DRC report file is always created. (fixes lp:1593389)
* Prevent DRC file from being created regardless the option selected in the check box.
* The browse file dialog now open the current project folder by default.
2016-08-09 10:49:36 -04:00
Maciej Sumiski 9d233b4cdb Pcbnew: fixed a crash when dragging a line was interrupted. (fixes lp:1606332)
* Crash was caused by removing an element from m_activeTools list, causing other
  iterators to be invalidated when dragging line in GAL mode.
2016-08-09 09:54:57 -04:00
Tomasz Wlostowski 19c54933c1 Polygon: fixed polygon filleting glitch for colinear outline segments. (fixes lp:1527827) 2016-08-05 15:07:42 -04:00
Jean-Pierre Charras 7aca6174d6 Fix window positioning bug when context menu is open. (fixes lp:1606378)
* When a context menu was open and a left mouse click event in the window title
  bar occurred, the window would shift from the title bar click position to the
  context menu select position.  This only seemed to effect windows.
2016-08-05 10:46:36 -04:00
Michael Steinberg 5f98fc0591 Fix dangling board reference crash in GAL. (fixes lp:1584489) 2016-08-05 08:49:12 -04:00
Thomas Pointhuber bcdcaa724d Remove front silkscreen default setting for PTH and NPTH pads. 2016-08-03 14:23:14 -04:00
Michael Steinberg 32f24289bd Fix segfault on BOARDs without tracks. 2016-08-03 08:40:07 -04:00
Jean-Pierre Charras 021320be1b Fix: footprint libraries wizard fails with personal GitHub accounts (now uses https://api.github.com/users/xxx instead of https://api.github.com/orgs/xxx to retrieve the list of .pretty footprint libraries) 2016-07-20 15:56:19 -04:00
Jean-Pierre Charras e309ca10d1 More OSX dialog fixes. 2016-07-18 19:33:12 -04:00
Jean-Pierre Charras a65b7963d1 Eeschema: incorrect dialog size fixes and OSX copy text fix. 2016-07-18 09:59:50 -04:00
Jean-Pierre Charras 26c5485be9 Pcbnew: OSX dialog fixes. 2016-07-15 16:51:28 -04:00
Maciej Sumiski 48d2ac15d5 Fix a GAL crash bug caused by invalid iterator (thanks to Michael Steinberg).
* TOOL_MANAGER::finishTool() caused iterator to become invalid when an
  element was removed from the m_activeTools deque.
2016-07-09 12:33:37 -04:00
jean-pierre charras 2ab90d6d20 Pcbnew: fix potential issue (crash) when loading board files with a missing net section (like created by Gerbview) due to an initialization made to late. 2016-07-05 11:20:38 -04:00
Bernhard Stegmaier 81cc0b4c42 OSX: back port touchpad support from development branch. 2016-07-05 05:44:14 -04:00
Bernhard Stegmaier 95b84f4a8d Fix 3d-viewer regressions introduced by touchpad-panning for non-touchpad-panning (merge of rev. 6593 from development branch). 2016-07-04 21:58:46 +02:00
Bernhard Stegmaier 6c25b29e9f Fix touchpad scrolling on OSX (merge of rev. 6606 from development branch). 2016-07-04 21:47:33 +02:00
Bernhard Stegmaier 1f6789e692 Add support for optional touchpad panning (merge of rev. 6586 from development branch). 2016-07-04 21:43:55 +02:00
Bernhard Stegmaier e4307a86cc OSX: legacy canvas rendering speed improvements.
* Enables USE_WX_GRAPHICS_CONTEXT for OSX by default. This shouldn't be a
  major change because it seems to get used on OSX behind the scenes anyway.
  As a side effect, this might improve behavior with anti-aliasing because
  KiCad shifts drawing by (0.5, 0.5) into the middle of the virtual pixels so
  things may be less blurry. It will still build without enabling
  USE_WX_GRAPHICS_CONTEXT, but the optimizations obviously won¡¯t be used.
* The optimizations currently only are effective when USE_WX_GRAPHICS_CONTEXT
  is enabled and OSX. They might be also good for other platforms using
  USE_WX_GRAPHICS_CONTEXT because it aggregates some drawing primitives using
  paths wxGraphicsContext provides.
* It adds some #ifdefs for disabling the wxGraphicsContext stuff when
  USE_WX_GRAPHICS_CONTEXT isn't enabled. If you hate #ifdefs, this also
  could be dropped but then it will always check if wxGraphicsContext can be
  applied.
2016-06-30 16:51:24 -04:00
jean-pierre charras ce181e6e0a PolyLine.cpp: NormalizeAreaOutlines now removes null segments.
* CPolyLine::Chamfer (and CPolyLine::Fillet) : removes null segments before calculating modified outlines.
  It fixes some incorrect outlines after chamfer or fillet due to null segments creating overflow during calculations.
* CPolyLine::Chamfer : code cleaning (avoid useless double to integer and integer to double conversions).
2016-06-26 20:28:52 -04:00
jean-pierre charras 4212d99c3d Gerbview: Read excellon files: fix incorrect handling of G85 command. (fixes lp:1485420) 2016-06-21 11:56:13 -04:00
jean-pierre charras 535f3ae006 Fix a (minor) issue in Kicad manager: when the schematic editor or the board editor are run from the project tree frame to edit files of the current project, editors are opened on the background. 2016-06-21 11:26:59 -04:00
jean-pierre charras 90ed0183c8 Fix an issue in LOCALE_IO class, used to switch to/back locale "C" when reading/writing files: the back to locale was broken, and created issues in countries using the ',' as fp separator, especially when the non default language was used.
It was reported in many bugs.
2016-06-21 10:48:42 -04:00
Dan Cross 2bb695b767 Fix broken swig import script when using swig 3.0.10. 2016-06-20 16:53:32 -04:00
jean-pierre charras c980e6999a Fix script fix_swig_imports.py to work with swig version 3.0.9. 2016-06-20 16:50:39 -04:00
Wayne Stambaugh 1e7ba6c644 KiCad: fix segfault bug when switching from remote to local project.
* Deleting the wxFileSystemWatcher when switching from a remote project to
  a local project caused KiCad to segfault. Switching from a local project
  to a remote project did not cause KiCad to crash. The fix was to clear all
  of the file system watcher paths instead of deleting and creating a new file
  system watcher object between project changes. The object still crashes on
  exit when deleted in the main window dtor. Allocating the file system
  watcher object on the stack instead of on the heap did not make any difference.
2016-06-20 16:48:43 -04:00
jean-pierre charras 53f6bf29c7 Fix bug: DRC report to File crashes Pcbnew, if the file cannot be created (for instance if the CWD is not writable, or if the path does not exist)
Fix also an other issue: if the file path is not entered, the file is now created in the current project directory.
2016-06-15 15:00:41 -04:00
jean-pierre charras 8e4098f3f1 Cvpcb: fix a focus issue (on OSX), when using arrow keys to scroll the footprint list box, if the footprint and 3D viewers are opened. 2016-05-27 16:51:23 -04:00
Simon Wells 7179a71cdc Multiple monitor loses window when single monitor 2016-05-27 16:46:24 -04:00
Alexander Lunev 606978297d pcad2kicadpcb: fixed an issue with an uppercase fileUnits parameter. 2016-05-27 16:40:37 -04:00
Simon Wells 648b7d53b5 Fix mirrored graphics when moving SCH_BITMAP on OS X 2016-05-27 16:27:11 -04:00
Dick Hollenbeck 93c5e5e4aa Eeschema: updated footprint field after picking from footprint viewer in the eeschema LIB_PART or component text field properties editors. 2016-05-27 16:24:36 -04:00
jean-pierre charras 7940f0773c Try to fix a compil issue on OSX (no viable conversion from 'const wxString' to 'const wxChar *', in colors.cpp). 2016-05-27 16:22:11 -04:00
Dick Hollenbeck 226d56433c Remove support for in processing setting of ld library path. 2016-05-27 15:31:09 -04:00
Dick Hollenbeck 5cf68726d6 Eeschema: make footprint and datasheet initially invisible, when creating a component. 2016-05-27 15:26:10 -04:00
jean-pierre charras 3c233ae08e Make color names translatable in color selection dialog. 2016-05-27 15:23:00 -04:00
Maciej Suminski 9810236314 Mark locked tracks with 'L' letter in status field. 2016-05-27 14:56:09 -04:00
Collin Anderson 7dbf84a9bd Fix beep on hotkey press in OS X 2016-05-27 14:53:10 -04:00
Maciej Suminski b73a71c696 Added 'Reset Grid Origin' hot key (GAL). 2016-05-27 14:51:32 -04:00
Wayne Stambaugh e4e635d3b5 Component library editor field properties dialog improvements.
* Remove fixed dialog size setting to allow sizers to do thier job.
* General spacing and layout improvements.
2016-05-27 14:47:59 -04:00
Chris Pavlina 2ffdc0d03d Fix file version support build error on some platforms. 2016-05-27 14:38:51 -04:00
Chris Pavlina 91f34a9478 Add support for PCB and footprint format versioning
Currently, kicad_pcb files have a (version ...) tag, but it is ignored. This
commit does the following:

1. Parse the version. If it's later than the last supported version, present an
alternative error message suggesting an upgrade if the file does not load
correctly. The version will be interpreted as an integer YYYYMMDD to suggest
a KiCad release date.

2. Accept a (version ...) tag also in kicad_mod files, but do not write them
yet. If no version tag is present in these files, assume the version to be that
of the current format version at the time of this commit.

This is meant to be merged to the 4.x stable series, and preps for KiCad 5
which will start emitting version tags also in footprints - users with what
will then be 'old stable' will not get a parse error when we introduce this for
footprints, and we can safely increment the format version later.
2016-05-27 14:36:53 -04:00
Matthew Petroff 67ab1be495 Correct multiple UI spelling errors. 2016-05-03 12:44:32 -04:00
Martin d`Allens fdc4d2a8a9 Fix typos in dialogs. 2016-05-03 11:32:49 -04:00
Wayne Stambaugh 72f19ded75 Fix value field editing bug in component library editor. (fixes lp:1576363)
* Allow editing value field for power components in the component library editor.
2016-04-29 12:05:08 -04:00
jean-pierre charras 3c8bed9c92 Fix issues in dialog drc: because it is not modal, DRC parameters and unit selection can be modified outside the dialog, still opened. Now, the new parameters are taken in account.
Fixa also a corner case which crashes Pcbnew: if the dialog is opened, and the board was changed (reloaded, cleared), pcbnew crashed because many pointers stored in dialog become invalid. Now the dialog is just closed.
2016-04-15 14:49:33 -04:00
jean-pierre charras 6a33549b68 Gerber files: ensure the "level polarity dark" is set in each file (this is the default, but ensuring that is better and can avoid issues when panneling files) 2016-04-15 14:24:25 -04:00
Wayne Stambaugh ab99c58ead Fix quasi-modal dialog mode in DIALOG_SHIM class.
* Add event handler to check all button clicks for default command event
  IDs and handle them appropriately by either calling EndQuasiModal() or
  passing the event up the event handler chain to allow the default dialog
  handlers to perform their magic.
* Add event handler to handle the close window event properly.
* Add scope brackets so the wxBusyCursor will stop being displayed when
  the footprint library loading is complete in CvPcb.
2016-04-12 18:22:01 -04:00
Wayne Stambaugh c8daccbe0e CvPcb: remove footprint library load failure limit. (fixes lp:1553756)
* Remove the artificial footprint library read error limit to prevent
  potentially readable libraries from being loaded after the error limit
  is reached.
* Change error message dialog to an HTML dialog so that potentially large
  error messages can be displayed with scrolling and the ability to copy
  and paste the error message for bug reporting purposes.
* Add busy cursor when loading the footprint libraries so the user has some
  idea that something is happening while the footprint libraries are being
  loaded.
2016-04-11 14:15:26 -04:00
Wayne Stambaugh b6dedd9f5b Eeschema: fix wxFileDialog assertion when importing component. (fixes lp:1558486)
* wxFileDialog ctor was setting the file name using the most recently used
  path which was incorrect. Set the file path parameter to the most recently
  used path and the file name parameter to an empty string.
* Remove last used import path and use the application wide most recently
  path instead.
* Remove last used export path and use the application wide most recently
  path instead.
2016-04-11 13:58:52 -04:00
Wayne Stambaugh fd054f566e Eeschema: fix build error due to field auto place code merged along with bug fix. 2016-04-07 15:30:12 -04:00
Wayne Stambaugh 4a665f492e Undo cached container commit. 2016-04-07 15:18:19 -04:00
jean-pierre charras a0d41f75ff OpenGL mode: Disable frequent (and not very usefull) memory deallocation/reallocation to avoid "out of memory" issue due to heap fragmentation (noticeable only with large boards).
Note: there is still this issue when switching back legacy mode and to Opengl mode because the heap is still freed and reallocated.
2016-04-07 14:56:16 -04:00
Wayne Stambaugh 5f72cca19a Eeschema: fix field edit dialog power component warning bug.
* Prevent power component warning from being shown when edit normal component
  fields.
* Make text edit dialog size itself instead of using a fixed size.
* Improve the alignment and spacing in the text edit dialog.
* Fix field name typo in field validator (thanks Jean-Pierre Charras for
  catching this).
2016-04-07 14:43:55 -04:00
Wayne Stambaugh 8191327fc2 Eeschema: fix illegal field characters causing corrupt schematic files on Linux. (fixes lp:1529358)
* Refactor edit one field dialogs to use validators and transfer data to and
  from window functions.
* Add code to DIALOG_SHIM to handle validation and transfer functions since
  the base dialog class code is not called by EndQuasiModal().
* Add custom validator class for filtering field text control characters.
* Add new field validator to edit schematic component dialog field text
  control.
* Add new field validator to edit fields in library editor dialog field
  text control.
* Make a few LIB_PART member functions const.
2016-04-07 14:32:53 -04:00
Chris Pavlina a19a52398a Fix graphics rendering on RTL systems (lp:1559545)
* wxWidgets mirrors graphics by default on RTL systems so it is necessary to
  individually set graphics canvases to LTR mode to avoid this.
2016-03-23 14:38:00 -04:00
Baranovskiy Konstantin f3d173fe64 Pcbnew: prevent zone tool from switching to no tool when deleting zone corner. 2016-03-22 13:49:38 -04:00
Chris Pavlina 3076e98b29 Eeschema: fix printf format string in find status message. 2016-03-22 11:39:55 -04:00
jean-pierre charras 1d55823fef Page layout reader fixes.
* Fix a minor issue in parseGraphic method to ensure correct parenthesis balance.
* Update a old (incorrect) .kicad_wks file in demo.
* page_layout_writer.cpp: remove a few useless spaces in output files.
2016-03-22 11:35:16 -04:00
Mark Roszko 62475d0464 PL Editor: fix page layout default description missing parenthesis before the keyword "end" in a few lines. 2016-03-22 11:32:03 -04:00
Cirilo Bernardo 1060d4ac6e Fix and improve IDF tools
The attached patch makes the following changes to the IDF
tool 'dxf2idf':

1. DXF units are now correctly scaled to mm
2. Polylines are now supported
3. LWPolylines are now supported
2016-03-22 11:29:59 -04:00
Cirilo Bernardo 44038c47c6 Various fixes to DXF import
* Correctly implement scaling based on DXF $INSUNITS - at least where
  INSUNITS is sensible. I ignore units like miles, gigameters, AU,
  lightyear, parsec ...
* Correctly implements LWPolylines, adding an ARC segment rather than a
  line segment when bulge != 0. A number of users have been complaining
  about getting the wrong board shape (chamfered corners rather than
  rounded corners) on DXF Import, now they shouldn't complain.
2016-03-21 10:22:04 -04:00
Carl Poirier fef0759155 Eeschema: fix minor issue creating extra whitespace in .lib. 2016-03-21 10:18:28 -04:00
Jon Neal 16dbe11868 Change misspelled dxf conversion constant from member variable to static const like other conversion constants. 2016-03-21 10:15:56 -04:00
Chris Pavlina 68725bc20c pcbnew: don't pick up selection after unsuccessful Duplicate
Following rev 6627 (git 2777182), if a non-duplicatable item was the object of
a Duplicate action, the original item would be picked up, potentially
misleading the user into thinking something was actually duplicated.
2016-03-21 10:11:56 -04:00
dwilches 963b4d5ed6 Fix Preferred Editor dialog (lp: 1558353)
The functions involved in the problem were PGM_BASE::GetEditorName and
EDA_BASE_FRAME::OnSelectPreferredEditor:

1) OnSelectPreferredEditor showed a dialog to allow the user selecting the
editor, but before that called GetEditorName to get the name of the current
editor (to show as a default in the choose file dialog).

2) The problem was when there was no editor, GetEditorName showed its own
dialog.

3) So the user was seeing first the dialog from (2) and then the dialog from
(1).

4) As GetEditorName is used in many other places the solution I did was to add
to it an optional parameter that tells it what to do if no editor is set. To
avoid modifying other code that relies on the current behaviour, this parameter
has a default value that causes to show the dialog. But now when
OnSelectPreferredEditor calls it, it passes the parameter that causes it to
return an empty string if no editor was set.

5) Also, I found a second bug while doing it which allowed in the first dialog
to select an unexistent file (the dialog was missing the wxFD_FILE_MUST_EXIST
flag).

6) Lastly, to avoid having duplicated code (the one that showed the same dialog
and that configured the wildcard was in two methods) I created a single
function that now both functions call: PGM_BASE::AskUserForPreferredEditor.
This way we also will have consistency in the behaviour of both dialogs and
there is a single place where it needs to be modified.
2016-03-18 08:11:19 -04:00
jean-pierre charras 6657981553 Pcbnew: loading file with footprint on an inner layer causes an assertion. (fixes lp:1556424) 2016-03-14 09:20:51 -04:00
Eldar Khayrullin 286f6a426b Pcbnew: fix exception when importing pcad pcb with zero size pads (fixes lp: 1551353)
* Zero size pads are now just ignored.
2016-03-14 09:13:53 -04:00
jean-pierre charras cc058033cc Fix incorrect (too small) bounding box EDA_TEXT, noticeable when chars like j or { are used in zone fill functions.
I tried to merge some constants used both in legacy mode and gal mode (which were, before this patch, separate constants).
There is still a serious work to avoid different calculation code for the same text in draw and plot functions.
Work in progress to merge these calculation functions.
2016-03-11 16:30:32 -05:00
jean-pierre charras 18f07d8efb Pcbnew: create array dialog fixes. (fixes lp:1549231)
* No initial copied object changed (this was a serious bug to modify these
  objects. Previous version modified references and other texts using a
  broken algorithm).
* Only new pads are numbered (therefore renumbering is used only in footprint
  editor)
* Remove not working feature in circular array: now only use number for
  pads (other options using alphabetical letters are removed: did not work
  correctly).
* A more clear option is used to choose if the pads are numbered from a chosen
  value or from the first available value.
* Adding a warning message if a parameter is incorrect.
2016-03-09 09:15:42 -05:00
jean-pierre charras 6d3e1b9391 Fix environment variable initialization issue on Linux. (fixes lp:1550620)
* Linux environment variables are not initialized properly if the value
  contains any non ASCII7 characters and if the locale is not set.  Set
  the locale before reading the environment variable configuration.
2016-03-01 08:53:19 -05:00
Tomasz Wlostowski 79fe4a0acb More accurate pushout force calculation for circle-segment collisions. (fixes lp:1551579) 2016-03-01 08:44:02 -05:00
Wayne Stambaugh 5c4fbbec43 Pcbnew: prevent delete hot key from deleting locked footprints. (fixes lp:1538805) 2016-02-29 18:44:09 -05:00
Eldar Khayrullin 7d0299f153 Pcbnew: fix issues in PCAD import of P-CAD ASCII files. (fixes lp:1547822) 2016-02-24 13:03:56 -05:00
jean-pierre charras e9570fddd6 Remove CK1202_V1.pcb sample file, actually not used in Kicad, due to its unclear copyright. The http link to this sample file is in files.txt. 2016-02-23 10:38:51 -05:00
jean-pierre charras 34217c0199 Pcbnew: fix a crash when trying to export a footprint in a non writable directory, or if a non writable old file was existing. (Linux only. On Windows, the wxWidgets file dialog dectects this issue) 2016-02-23 09:16:50 -05:00
Nick Winters ab0e3d0ce2 OSX: fix bug caused by wxBitmap drawing 0 width or heigth bitmap. (fixes lp:1529159) 2016-02-23 09:05:52 -05:00
Wayne Stambaugh c8b2971d1c Fix bug in component library editor. (fixes lp:1547299)
* Use temporary storage of new pins to prevent corruption of the library part draw items
  list when adding alternater body style pins to existing component which caused segfault.
2016-02-19 17:13:32 -05:00
jean-pierre charras 9b0bd7ca1f Pcbnew: minor bug fixes.
* Use case insensitive comparison to choose import plugin from the file extension.  The
  file extension is not always lower case especially on Windows.
* onleftclick.cpp: fix false warning message in the legacy canvas which happens afte
   switching from the GAL canvas when a board item is still selected.
2016-02-19 09:52:18 -05:00
jean-pierre charras fd009f924a Eeschema: fix bug where global bus labels were being ignored. (fixes lp:1545708) 2016-02-18 11:35:56 -05:00
Dick Hollenbeck 48e2addd69 Pcbnew: fix bug opening P-CAD ASCII files. (fixes lp:1545668) 2016-02-18 11:33:11 -05:00
Bernhard Stegmaier a773ecc735 Disable FPS limiter for OSX (GAL). 2016-02-18 11:29:12 -05:00
jean-pierre charras dcd81e23f4 Fix incorrect assertion failure in specctra export when a footprint contains segments on edge.cut layer (fixes lp:1545546) 2016-02-18 11:06:40 -05:00
Rohan Agrawal bff0068065 Merge lp:~rohbotics/kicad/bug_1424003 into lp:kicad 2016-02-13 15:23:08 -05:00
unknown d0932944fc Fix long text values truncated in position file and serious cleanup of gen_modules_placefile.cpp code. (fixes lp:1412628) 2016-02-13 15:20:59 -05:00
Tomasz Wlostowski 5c3a56bdcc Fixed segfault in selection tool. (fixes lp:1542856) 2016-02-13 15:15:15 -05:00
jean-pierre charras e9bfcc28c3 Fix HPGL plot divide by zero bug. 2016-02-11 19:12:06 -05:00
Maciej Suminski 3cdac44ac2 GAL::DrawPolygon() and GAL::DrawPolyline() variants that work with VECTOR2D array. 2016-02-11 19:05:24 -05:00
jean-pierre charras 2cebaa2d79 3D Viewer: fix no solder mask unless there is something on the layer. (fixes lp:542935) 2016-02-10 20:47:34 -05:00
jean-pierre charras 609b996abe Pcbnew: zone keepout incorrectly created if previously a corner-smoothed copper zone was created. (fixes lp:1540967) 2016-02-10 20:21:26 -05:00
Simon Richter ea0c187e09 Executable icon resource build configuration fixes.
* The resource setting for bitmap2component is too late in the CMakeLists.txt,
  and is being ignored. Bitmap2component does not have an icon resource on
  Windows. Moving the entire section resolves the issue.
* The other programs only have the mingw special case listed, not the generic
  declaration for the resource file so added them.
2016-02-10 20:14:35 -05:00
jean-pierre charras bf6cd8445a Page layout editor: custom text size not saved when X or Y size value is not default. (fixes lp:1538603) 2016-02-10 20:12:16 -05:00
Chris Pavlina c50763bd5b libedit: fix iterator off end of vector (fixes lp:1537946) 2016-02-09 19:04:36 -05:00
Andrew Zonenberg 1aa6932b12 Pcbnew DRC: allow technical->copper pad overlap
* This permits things like mask "pads" over copper pads for custom mask openings.
2016-02-09 18:59:56 -05:00
Maciej Suminski 342ec2be0e Highlight a net when crossprobing with eeschema and highlight net tool is enabled. 2016-02-09 18:57:46 -05:00
Martin d'Allens d451800d0a Eeschema: Set modified flag after "Append Schematic Sheet" 2016-02-09 18:56:10 -05:00
jean-pierre charras 48435c5cb3 Fix bug in "User Custom" size selection in"Page Settings" in non English languages. (fixes lp:1536427) 2016-02-09 18:41:47 -05:00
Maciej Suminski 8999ae9fb2 Make DRC markers not editable with the standard tools (GAL). 2016-02-09 18:38:26 -05:00
Maciej Suminski 8184ba1cf3 Draw arrows for DRC markers (GAL). 2016-02-09 18:36:43 -05:00
Simon Wells 228ed4ea41 GAL: Update grid color when changed by user 2016-02-09 18:34:16 -05:00
Chris Pavlina 3031a3f5cf Pcbnew: fix Flip hotkey for blocks in legacy (fixes lp:1534120) 2016-02-09 18:31:39 -05:00
Tomasz Wlostowski 42aa93e34b GAL: apply grid offset when board is loaded and respect grid color setting. (fixes lp:1533168) 2016-02-09 18:27:13 -05:00
Tomasz Wlostowski eb8b407717 Router: check layers of all traversed joints in FindLinesBetweenJoints(). (fixes lp:1531762) 2016-02-08 21:28:22 -05:00
Johannes Agricola eaea15fbef Properly set keepout flag for new zones in GAL 2016-02-08 21:26:03 -05:00
Maciej Suminski 72a69f9428 pcbnew asks before rotating/flipping a locked item (GAL). 2016-02-08 20:06:22 -05:00
Simon Wells c66656c5d4 Open PDF viewer improvements. (fixes lp:1530162)
* Fix broken ExecuteCommand() when path contains spaces on OSX.
* Only use system defined mime type for PDF files.
* Remove system dependent fallback applications for opening PDF files.
2016-02-08 20:03:57 -05:00
Element Green 14363262c2 Pcbnew: fix VRML export dialog settings having no effect. (fixes lp:1529214) 2016-02-08 19:58:21 -05:00
Jean-Pierre Charras 509e71fdb3 Pcbnew: fix bug when flipping a block that dosesn't flip inner layers nor their connected microvias. (fixes lp:1527446) 2016-02-08 19:16:07 -05:00
Jean-Pierre Charras 6c5e2f3900 Pcbnew: avoid crash if something is wrong when opening the Python Console (for instance missing python module). 2016-02-07 19:38:08 -05:00
Chris Pavlina f46272bed9 Pcbnew: fix zone tool bug when minimum width is compared against thermal relief spoke when Pad connection set to none. (fixes lp 1526158) 2016-02-07 19:35:43 -05:00
Jean-Pierre Charras 2f7b3ab56e Eeschema: fix segfault when loading malformed libraries. (fixes lp:1527804) 2015-12-20 16:46:33 -05:00
Maciej Suminski b526227529 Fixed crash on undo pad placement in the footprint editor using GAL canvases. (fixes lp:1525552) 2015-12-15 10:22:49 -05:00
Maciej Suminski e93c815e02 Fixed ratsnest for PCBs imported using plugins (GAL). 2015-12-15 10:16:15 -05:00
Mark Roszko 5c8f7c7a3a Use defined environment variables before falling back to DEFAULT_INSTALL_PATH. 2015-12-09 09:46:56 -05:00
Jean-Pierre Charras 7fb6698e29 Kicad manager: fix a potential bug which could crash Kicad manager. 2015-12-07 09:55:59 -05:00
Jean-Pierre Charras f11b426151 Better sizing of wx_html_report_panel in dialog_netlist (fix bug #1522758) 2015-12-06 18:24:32 -05:00
Maciej Suminski 827dad3197 GAL bug fixes cherry picked from product branch. 2015-12-06 18:22:13 -05:00
Wayne Stambaugh 593c974063 One last update before 4.0.0 stable release. 2015-11-29 14:53:12 -05:00
Wayne Stambaugh a68b3cb486 Merge with tip of product branch for 4.0.0 stable release. 2015-11-29 14:06:50 -05:00
Wayne Stambaugh ce81524b83 Merge with tip of product branch r6303, 4.0.0-rc1. 2015-11-08 16:22:19 -05:00
18141 changed files with 1109670 additions and 17327534 deletions
+50
View File
@@ -0,0 +1,50 @@
boost_root
.downloads-by-cmake
Build
build
common/netlist_keywords.*
common/netlist_lexer.h
common/pcb_plot_params_lexer.h
common/page_layout/page_layout_reader_keywords.cpp
common/fp_lib_table_keywords.*
common/gal/opengl/shader_src.h
include/fp_lib_table_lexer.h
include/netlist_lexer.h
include/page_layout_reader_lexer.h
eeschema/cmp_library_lexer.h
eeschema/cmp_library_keywords.*
eeschema/dialogs/dialog_bom_cfg_keywords.cpp
eeschema/dialogs/dialog_bom_cfg_lexer.h
eeschema/dialogs/dialog_bom_help_html.h
eeschema/template_fieldnames_keywords.*
eeschema/template_fieldnames_lexer.h
pcbnew/dialogs/dialog_freeroute_exchange_help_html.h
pcbnew/pcb_plot_params_keywords.cpp
pcbnew/pcb_plot_params_lexer.h
Makefile
CMakeCache.txt
auto_renamed_to_cpp
Testing
version.h
config.h
install_manifest.txt
Documentation/doxygen
Documentation/development/doxygen
*.bak
.*.swp
*.~*
common/pcb_plot_params_keywords.cpp
include/pcb_plot_params_lexer.h
pcbnew/specctra_keywords.cpp
pcbnew/specctra_lexer.h
pcb_calculator/pcb_calculator_datafile_keywords.cpp
pcb_calculator/pcb_calculator_datafile_lexer.h
new/html
new/sch_lib_table_keywords.cpp
new/sch_lib_table_lexer.h
new/sweet_keywords.cpp
new/sweet_lexer.h
bitmaps_png/png*
bitmaps_png/tmp
common/pcb_keywords.cpp
include/pcb_lexer.h
-57
View File
@@ -1,57 +0,0 @@
# minimum clang-format 10
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: true
AlignOperands: true
AlignTrailingComments: true
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: None
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Allman
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakConstructorInitializersBeforeComma: false
BreakStringLiterals: true
ColumnLimit: 100
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ForEachMacros: [ BOOST_FOREACH ]
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
MaxEmptyLinesToKeep: 2
NamespaceIndentation: Inner
PointerAlignment: Left
ReflowComments: false
SortIncludes: false
SpaceAfterCStyleCast: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: Never
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: true
SpacesInSquareBrackets: false
Standard: c++11
TabWidth: 4
UseTab: Never
-5
View File
@@ -1,5 +0,0 @@
# SPDX-License-Identifier: GPL-3.0-or-later
Checks: '-clang-diagnostic-*,clang-analyzer-*, bugprone-*, modernize-deprecated-headers, modernize-loop-convert, modernize-use-override, modernize-redundant-void-arg, modernize-use-emplace, modernize-use-noexcept, modernize-use-bool-literals, modernize-pass-by-value, modernize-use-equals-default, modernize-use-equals-delete, modernize-use-default-member-init, cppcoreguidelines-prefer-member-initializer, cppcoreguidelines-init-variables, cppcoreguidelines-pro-type-member-init'
WarningsAsErrors: ''
HeaderFilterRegex: '.*'
FormatStyle: 'file'
-36
View File
@@ -1,36 +0,0 @@
# Custom attribute to mark source files using KiCad C++ formatting
[attr]kicad-cpp-source text=auto whitepace=tab-in-indent format.clang-format-kicad
# Custom attribute to mark KiCad's own CMake files
[attr]kicad-cmake-source text=auto whitespace=tab-in-indent
# Custom attribute for auto-generated sources:
# * Do not perform whitespace checking
# * Do not format
[attr]generated whitespace=-tab-in-indent,-indent-with-non-tab -format.clang-format-kicad
# By default, all C and C++ files conform to KiCad formatting,
# unless overridden
*.c kicad-cpp-source
*.cpp kicad-cpp-source
*.h kicad-cpp-source
*.cmake kicad-cmake-source
*.txt kicad-cmake-source
*.md text=auto
# Compiled bitmap sources
bitmaps_png/cpp_*/*.cpp generated
# wxFormBuilder-generated files
**/dialog*/*_base.cpp generated
**/dialog*/*_base.h generated
# Lemon grammars
common/libeval/grammar.c generated
common/libeval/grammar.h generated
# Scripts
*.sh text eol=lf
*.bat text eol=crlf
+2
View File
@@ -0,0 +1,2 @@
[core]
excludesfile .bzrignore
-49
View File
@@ -1,49 +0,0 @@
#!/usr/bin/env bash
#
# Git "hook chain", used to execute multiple scripts per hook.
# To use:
# * create a directory called <hookname>.d
# * add scripts to this directory (executable)
# * ln -s hook-chain <hookname>
#
# Now the scripts in that directory should be called in order.
#
# Set $HOOKCHAIN_DEBUG to see the names of invoked scripts.
#
# Based on script by Oliver Reflalo:
# https://stackoverflow.com/questions/8730514/chaining-git-hooks
#
hookname=`basename $0`
# Temp file for stdin, cleared at exit
FILE=`mktemp`
trap 'rm -f $FILE' EXIT
cat - > $FILE
# Git hooks directory (this dir)
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Execute hooks in the directory one by one
for hook in $DIR/$hookname.d/*;
do
if [ -x "$hook" ]; then
if [ "$HOOKCHAIN_DEBUG" ]; then
echo "Running hook $hook"
fi
cat $FILE | $hook "$@"
status=$?
if [ $status -ne 0 ]; then
echo "Hook $hook failed with error code $status"
echo "To commit anyway, use --no-verify"
exit $status
else
if [ "$HOOKCHAIN_DEBUG" ]; then
echo "Hook passed: $hook"
fi
fi
fi
done
-1
View File
@@ -1 +0,0 @@
hook-chain
-91
View File
@@ -1,91 +0,0 @@
#!/usr/bin/env bash
#
# Runs clang-format on changed regions before commit.
#
# Remaining installation checks/instructions will be printed when you commit.
#
# Based on clang-format pre-commit hook by Alex Eagle
# https://gist.github.com/alexeagle/c8ed91b14a407342d9a8e112b5ac7dab
# Set kicad.check-format to allow this hook to run
# If not set, the hook always succeeds.
do_format=false
# Check if formatting is configured
if [ "$(git config --get kicad.check-format)" = true ]; then
do_format=true
fi
# Older env variable method
if [ ! -z "$KICAD_CHECK_FORMAT" ]; then
do_format=true
fi
if [ ! ${do_format} = true ]; then
# No formatting required
exit 0;
fi
check_clang_format() {
if hash git-clang-format 2>/dev/null; then
return
else
echo "SETUP ERROR: no git-clang-format executable found, or it is not executable"
exit 1
fi
}
check_git_config() {
if [[ "$(git config --get clangFormat.style)" != "file" ]]; then
echo "SETUP ERROR: git config clangFormat.style is wrong (should be 'file'). Fix this with:"
echo "git config clangFormat.style file"
exit 1
fi
}
get_filtered_filenames()
{
format_attr='clang-format-kicad'
# command to get list of candidate files
git_list_files='git diff --cached --name-only --diff-filter=ACM'
files=$(${git_list_files} |
# Filter for format-controlled files
git check-attr --stdin format.${format_attr} |
# output only the file names
grep ": set$" |
cut -d: -f1)
echo ${files}
}
check_clang_format
check_git_config
files_to_check=$(get_filtered_filenames)
if [ -z "${files_to_check}" ]; then
# No controlled files to check
exit 0;
fi
git_clang_format_cmd="git clang-format -v --diff -- ${files_to_check}"
readonly out=$(${git_clang_format_cmd})
# In these cases, there is no formatting issues, so we succeed
if [[ "$out" == *"no modified files to format"* ]]; then exit 0; fi
if [[ "$out" == *"clang-format did not modify any files"* ]]; then exit 0; fi
# Any other case implies formatting results
echo "ERROR: you need to run clang-format (e.g. using tools/check_coding.sh) on your commit"
# print the errors to show what's the issue
${git_clang_format_cmd}
# fail the pre-commit
exit 1
-2
View File
@@ -1,2 +0,0 @@
custom: "https://donate.kicad.org"
community_bridge: kicad
-26
View File
@@ -1,26 +0,0 @@
name: 'Redirect PRs'
on:
pull_request:
types: opened
jobs:
lockdown:
runs-on: ubuntu-latest
steps:
- uses: dessant/repo-lockdown@v2
with:
github-token: ${{ github.token }}
pr-comment: >
Thank you for offering to help improve KiCad.
This repository is a one-way mirror that can not accept pull requests.
Please submit your merge request to the official KiCad repository
at https://gitlab.com/kicad/code/kicad/-/merge_requests
While we know that _your_ PR is not spam, we mark it as such to dissuade
the Hacktoberfest PRs. Please join us over at GitLab. You can even use
your GitHub credentials to log in there without creating a new account.
skip-closed-pr-comment: true
pr-labels: 'spam'
close-pr: true
lock-pr: true
pr-lock-reason: 'spam'
+22 -106
View File
@@ -1,44 +1,47 @@
.downloads-by-cmake
.gdb_history
boost_root
/Build*
/build*
/cmake-build-*
common/fp_lib_table_keywords.cpp
common/drc_rules_keywords.cpp
common/drc_rules_lexer.h
.downloads-by-cmake
Build*
build*
common/netlist_keywords.*
common/netlist_lexer.h
common/pcb_plot_params_lexer.h
common/drawing_sheet/drawing_sheet_reader_keywords.cpp
common/page_layout/page_layout_reader_keywords.cpp
common/lib_table_keywords.*
common/gal/opengl/shader_src.h
include/fp_lib_table_lexer.h
include/lib_table_lexer.h
include/netlist_lexer.h
include/page_layout_reader_lexer.h
eeschema/cmp_library_lexer.h
eeschema/cmp_library_keywords.*
eeschema/dialogs/dialog_bom_cfg_keywords.cpp
eeschema/dialogs/dialog_bom_cfg_lexer.h
common/template_fieldnames_keywords.cpp
common/template_fieldnames_lexer.h
eeschema/schematic_keywords.*
eeschema/dialogs/dialog_bom_help_html.h
eeschema/template_fieldnames_keywords.*
eeschema/template_fieldnames_lexer.h
pcbnew/dialogs/dialog_freeroute_exchange_help_html.h
pcbnew/pcb_plot_params_keywords.cpp
pcbnew/pcb_plot_params_lexer.h
pcb_calculator/attenuators/bridget_tee_formula.h
pcb_calculator/attenuators/pi_formula.h
pcb_calculator/attenuators/splitter_formula.h
pcb_calculator/attenuators/tee_formula.h
Makefile
CMakeUserPresets.json
CMakeCache.txt
.cache/
auto_renamed_to_cpp
Testing
version.h
config.h
install_manifest.txt
doxygen/out
Documentation/doxygen
Documentation/development/doxygen
*.bak
*.pyc
.*.swp
*~
common/pcb_plot_params_keywords.cpp
include/pcb_plot_params_lexer.h
pcbnew/specctra_import_export/specctra_keywords.cpp
pcbnew/specctra_import_export/specctra_lexer.h
pcbnew/specctra_keywords.cpp
pcbnew/specctra_lexer.h
pcb_calculator/pcb_calculator_datafile_keywords.cpp
pcb_calculator/pcb_calculator_datafile_lexer.h
new/html
@@ -46,94 +49,7 @@ new/sch_lib_table_keywords.cpp
new/sch_lib_table_lexer.h
new/sweet_keywords.cpp
new/sweet_lexer.h
bitmaps_png/png*
bitmaps_png/tmp
common/pcb_keywords.cpp
include/pcb_lexer.h
fp-info-cache
qa/tests/output/**
# demo project auxiliary files
demos/**/*-bak
demos/**/_autosave-*
demos/**/fp-info-cache
demos/**/~*.lck
# MacOS package info created by CMake
bitmap2component/Info.plist
cvpcb/Info.plist
eeschema/Info.plist
gerbview/Info.plist
kicad/Info.plist
pagelayout_editor/Info.plist
pcb_calculator/Info.plist
pcbnew/Info.plist
# editor/OS fluff
.*.swp
*~
.idea
.DS_Store
*.png
*.kiface
*.o
*.o.*
*.a
*.a.*
*.orig
*.rej
*.so
*.old
*.gch
*.orig
*.patch
# These CMake files are wanted
!cmake/**/*.cmake
# Eclipse IDE
.settings/
.project
.cproject
.pydevproject
__pycache__
# Visual Studio
.vs/
.editorconfig
CMakeSettings.json
.vscode/
compile_commands.json
/vcpkg_installed
CMakePresets.json
# Sublime Text
*.sublime-*
# KDevelop
.kdev4/
*.kdev4
# Qt Creator
CMakeLists.txt.user
*.autosave
# Translations
*.mo
i18n_status.svg
i18n_status.csv
# Project local settings files and backups (in demos and qa tests)
*.kicad_prl
*-backups
# QA dataoutput
qa/data/**/*.csv
# Don't actually ignore any of these files, since we need them in the tree
!resources/linux/icons/hicolor/**/**/*
!resources/linux/icons-nightly/hicolor/**/**/*
!CMakeModules/**/*
!resources/bitmaps_png/png/**/*
# Junk temp files generated by MSVC for resource files
/resources/msw/RC*
-23
View File
@@ -1,23 +0,0 @@
stages:
- build
- test
- report
variables:
DEFAULT_FEDORA_IMAGE: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:40
default:
image:
name: $DEFAULT_FEDORA_IMAGE
entrypoint: ["/bin/sh", "-c"]
include:
- local: '/.gitlab/templates.yml'
- local: '/.gitlab/Fedora-Linux-CI.yml'
- local: '/.gitlab/Ubuntu-20.04-CI.yml'
- local: '/.gitlab/Windows-CI.yml'
- local: '/.gitlab/macOS-CI.yml'
- local: '/.gitlab/coverity.yml'
- local: '/.gitlab/linux-metadata-validate.yml'
- local: '/.gitlab/doxygen.yml'
- local: '/.gitlab/mr_formatting.yml'
-179
View File
@@ -1,179 +0,0 @@
##########################################################################
# Build KiCad on Fedora and save the results
##########################################################################
.fedora_build_linux_base:
stage: build
# Don't tag until we have separate CI for MRs
# tags:
# - kicad-fedora
image: $DEFAULT_FEDORA_IMAGE
extends: .only_code
interruptible: false
cache:
key: "cache-fedora-linux"
paths:
- ccache/
before_script:
# CCache Config
- mkdir -p ccache
- export CCACHE_BASEDIR=${PWD}
- export CCACHE_DIR=${PWD}/ccache
script:
- mkdir -p build/linux
- cd build/linux
- cmake
-G Ninja
-DCMAKE_BUILD_TYPE=QABUILD
-DKICAD_STDLIB_LIGHT_DEBUG=ON
-DKICAD_BUILD_I18N=ON
-DKICAD_TEST_XML_OUTPUT=ON
-DKICAD_BUILD_PNS_DEBUG_TOOL=ON
-DKICAD_USE_CMAKE_FINDPROTOBUF=ON
../../
- ninja 2>&1 | tee compilation_log.txt
- cd ../../
artifacts:
# Only save the artifacts that are needed for running the tests in the next stage
# and the compilation log. The entire build directory is too large to save as an
# artifact.
expire_in: 2 hrs
when: always
paths:
- build/linux/3d-viewer/
- build/linux/api/libkiapi.so*
- build/linux/common/libkicommon.so*
- build/linux/common/gal/libkigal.so*
- build/linux/eeschema/_eeschema.kiface
- build/linux/cvpcb/_cvpcb.kiface
- build/linux/kicad/kicad-cli
- build/linux/pcbnew/pcbnew.py
- build/linux/pcbnew/_pcbnew.kiface
- build/linux/pcbnew/_pcbnew.so
- build/linux/qa/
- build/linux/schemas/
- build/linux/compilation_log.txt
exclude:
- build/linux/**/*.o
- build/linux/**/*.a
# This split is to ensure we can always use our runner for our jobs
fedora_build_linux_kicad:
extends: .fedora_build_linux_base
tags:
- kicad-fedora
only:
variables:
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
fedora_build_linux_public:
extends: .fedora_build_linux_base
tags:
- saas-linux-medium-amd64
except:
variables:
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
# Upload the compilation log in an easily downloadable form
.fedora_report_build_warn:
stage: report
extends: .only_code
when: always
script:
- echo "Uploading compilation log"
- cp build/linux/compilation_log.txt compilation_log.txt
artifacts:
expire_in: 1 year
expose_as: 'Build log'
name: "build_log.txt"
paths:
- compilation_log.txt
fedora_report_build_warn_kicad:
extends: .fedora_report_build_warn
tags:
- kicad-fedora
needs:
- job: fedora_build_linux_kicad
artifacts: true
only:
variables:
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
fedora_report_build_warn_public:
extends: .fedora_report_build_warn
needs:
- job: fedora_build_linux_public
artifacts: true
except:
variables:
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
# Report on the metrics of the code
.fedora_report_metrics:
stage: report
extends: .only_code
when: always
script:
- cat build/linux/compilation_log.txt | { grep "warning:" || test $? = 1; } | awk 'END{print "number_of_fedora_warnings "NR}' > metrics.txt
- cat metrics.txt
artifacts:
reports:
metrics: metrics.txt
fedora_report_metrics_kicad:
extends: .fedora_report_metrics
tags:
- kicad-fedora
needs:
- job: fedora_build_linux_kicad
artifacts: true
only:
variables:
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
fedora_report_metrics_public:
extends: .fedora_report_metrics
needs:
- job: fedora_build_linux_public
artifacts: true
except:
variables:
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
##########################################################################
# Run the code unit tests.
##########################################################################
.fedora_qa:
image: $DEFAULT_FEDORA_IMAGE
extends:
- .unit_test
- .only_code
before_script:
- if [ "$TEST" == "cli" ] || [ "$TEST" == "python" ]; then python3 -m pip install -r qa/tests/requirements.txt; fi
- if [ "$TEST" == "cli" ]; then sudo dnf -y install gerbv; fi
parallel:
matrix:
# The name of the test without the qa_ prefix
- TEST: [python, cli, common, gerbview, pcbnew, pns_regressions, eeschema, kimath, sexpr, kicad2step, spice, api]
fedora_qa_kicad:
extends: .fedora_qa
tags:
- kicad-fedora
needs:
- job: fedora_build_linux_kicad
artifacts: true
only:
variables:
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
fedora_qa_public:
extends: .fedora_qa
needs:
- job: fedora_build_linux_public
artifacts: true
except:
variables:
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
-118
View File
@@ -1,118 +0,0 @@
##########################################################################
# Build KiCad on Ubuntu 20.04 and save the results
##########################################################################
.ubuntu20.04_build:
stage: build
tags:
- kicad-ubuntu20.04
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/ubuntu:20.04
only:
- branches@kicad/code/kicad
- tags@kicad/code/kicad
except:
- schedules
interruptible: false
cache:
key: "cache-ubuntu20.04-linux"
paths:
- ccache/
before_script:
# CCache Config
- mkdir -p ccache
- export CCACHE_BASEDIR=${PWD}
- export CCACHE_DIR=${PWD}/ccache
script:
- mkdir -p build/linux
- cd build/linux
- cmake
-G Ninja
-DCMAKE_C_COMPILER_LAUNCHER=ccache
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
-DCMAKE_BUILD_TYPE=Release
-DKICAD_STDLIB_LIGHT_DEBUG=ON
-DKICAD_SCRIPTING_WXPYTHON=ON
-DKICAD_USE_OCC=ON
-DKICAD_BUILD_I18N=ON
-DKICAD_BUILD_PNS_DEBUG_TOOL=ON
../../
- ninja 2>&1 | tee compilation_log.txt
- cd ../../
artifacts:
# Only save the artifacts that are needed for running the tests in the next stage
# and the compilation log. The entire build directory is too large to save as an
# artifact.
expire_in: 2 hrs
when: always
paths:
- build/linux/3d-viewer/
- build/linux/pcbnew/pcbnew.py
- build/linux/pcbnew/_pcbnew.kiface
- build/linux/pcbnew/_pcbnew.so
- build/linux/qa/
- build/linux/compilation_log.txt
exclude:
- build/linux/**/*.o
- build/linux/**/*.a
# Upload the compilation log in an easily downloadable form
.ubuntu20.04_report_build_warn:
stage: report
when: always
only:
- branches@kicad/code/kicad
- tags@kicad/code/kicad
except:
- schedules
needs:
- job: ubuntu20.04_build
artifacts: true
script:
- echo "Uploading compilation log"
- cp build/linux/compilation_log.txt compilation_log.txt
artifacts:
expire_in: 1 year
expose_as: 'Build log'
name: "build_log.txt"
paths:
- compilation_log.txt
# Report on the metrics of the code
.ubuntu20.04_report_metrics:
stage: report
when: always
only:
- branches@kicad/code/kicad
- tags@kicad/code/kicad
except:
- schedules
needs:
- job: ubuntu20.04_build
artifacts: true
script:
- cat build/linux/compilation_log.txt | { grep "warning:" || test $? = 1; } | awk 'END{print "number_of_ubuntu_20.04_warnings "NR}' > metrics.txt
- cat metrics.txt
artifacts:
reports:
metrics: metrics.txt
##########################################################################
# Run the code unit tests.
##########################################################################
.ubuntu20.04_qa:
extends:
- .unit_test
needs:
- job: ubuntu20.04_build
artifacts: true
tags:
- kicad-ubuntu20.04
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/ubuntu:20.04
only:
- branches@kicad/code/kicad
- tags@kicad/code/kicad
except:
- schedules
parallel:
matrix:
# The name of the test without the qa_ prefix
- TEST: [python, common, gerbview, pcbnew, eeschema, kimath, sexpr, kicad2step, spice]
-47
View File
@@ -1,47 +0,0 @@
##########################################################################
# Build KiCad on Windows and save the results
##########################################################################
win64_build:
stage: build
tags:
- kicad-windows-ltsc2022
interruptible: false
image: registry.gitlab.com/kicad/kicad-ci/windows-build-image/ltsc2022-msvc:latest
variables:
# Switch the compressor to fastzip and reduce the compression level
FF_USE_FASTZIP: "true"
CACHE_COMPRESSION_LEVEL: "fast"
cache:
key: win64-vcpkg-$CI_COMMIT_REF_SLUG
paths:
- build\windows\vcpkg_installed
- .vcpkgCache
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
when: never
- if: $CI_PROJECT_ROOT_NAMESPACE == "kicad"
script:
- C:\builder\build.ps1 -Env -Arch x64
- $vcpkgCache=Join-Path -Path (Get-Location) -ChildPath ".vcpkgCache";$env:VCPKG_DEFAULT_BINARY_CACHE=$vcpkgCache;New-Item -ItemType Directory -Force -Path $vcpkgCache
- mkdir -p build/windows -Force
- cd build/windows
- cmake `
-G "Ninja" `
-DCMAKE_TOOLCHAIN_FILE=C:\builder\vcpkg\scripts\buildsystems\vcpkg.cmake `
-DCMAKE_BUILD_TYPE=Debug `
-DKICAD_SCRIPTING_WXPYTHON=OFF `
-DKICAD_USE_OCC=ON `
-DKICAD_BUILD_PNS_DEBUG_TOOL=ON `
-DKICAD_USE_3DCONNEXION=ON `
-DVCPKG_BUILD_TYPE=debug `
../../
- cmake --build . 2>&1 | tee compilation_log.txt
- cd ../../
artifacts:
# Only save the artifacts that are needed for running the tests in the next stage
# and the compilation log. The entire build directory is too large to save as an
# artifact.
expire_in: 2 hrs
when: always
paths:
- build/windows/compilation_log.txt
-76
View File
@@ -1,76 +0,0 @@
# This script is responsible for configuring the coverity file from the cache
# (e.g. extracting it or updating it if needed)
.coverity_cache_prep: &coverity_cache_prep |
echo "Downloading MD5 hash of current Coverity Scan version to compare against cache"
curl --output cov-analysis-linux64.md5 https://scan.coverity.com/download/linux64 \
--form project=$COVERITY_SCAN_PROJECT_NAME \
--form token=$COVERITY_SCAN_TOKEN \
--form md5=1
echo " *cov-analysis-linux64.tgz" >> cov-analysis-linux64.md5
(md5sum --ignore-missing -c cov-analysis-linux64.md5) || (
echo "Downloading new Coverity Scan version"
curl --output cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64 \
--form project=$COVERITY_SCAN_PROJECT_NAME \
--form token=$COVERITY_SCAN_TOKEN
)
echo "Extracting Coverity Scan"
mkdir coverity/
tar xzf cov-analysis-linux64.tgz --strip-components=1 -C coverity
test -d coverity/bin
# This script is responsible for tar'ing and submitting the results of the build.
# These results will be saved for 1 day if the build fails.
.coverity_submit: &coverity_submit |
echo "Creating tar file of scan results"
export COV_INT_FILENAME=cov-int-$(date +"%Y%m%d%H%M").tar.gz
tar cfz $COV_INT_FILENAME cov-int
echo "Submitting scan results"
s5cmd/s5cmd cp $COV_INT_FILENAME s3://$KICAD_CI_R2_BUCKET/coverity/
export FILE_URL="$KICAD_CI_R2_PUBLIC_BASE/coverity/$COV_INT_FILENAME"
export KICAD_VERSION=$(sed 's/[()]//g' kicad_build_version.txt)
curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME \
--form token=$COVERITY_SCAN_TOKEN \
--form email=$GITLAB_USER_EMAIL \
--form url="$FILE_URL" \
--form version="$KICAD_VERSION" \
--form description="$KICAD_VERSION / $CI_COMMIT_TITLE" 2>&1 \
| tee curl-response.txt
grep -q 'Build successfully submitted' curl-response.txt
Coverity:
tags:
- coverity
stage: build
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:40
rules:
- if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULED_JOB_NAME == "coverity"
cache:
key: coverity
paths:
- cov-analysis-linux64.tgz
before_script:
- export COVERITY_SCAN_PROJECT_NAME="kicad"
- test "$(git rev-parse --is-shallow-repository)" = "false" || (git fetch --unshallow)
- git fetch origin
- curl -LO https://github.com/peak/s5cmd/releases/download/v2.0.0/s5cmd_2.0.0_Linux-64bit.tar.gz
- mkdir s5cmd
- tar -xvf ./s5cmd_2.0.0_Linux-64bit.tar.gz -C s5cmd
- export AWS_ACCESS_KEY_ID=$KICAD_CI_R2_KEY_ID
- export AWS_SECRET_ACCESS_KEY=$KICAD_CI_R2_ACCESS_KEY
- export S3_ENDPOINT_URL=$KICAD_CI_R2_ENDPOINT
script:
- *coverity_cache_prep
- cmake
-DCMAKE_BUILD_TYPE=RelWithDebInfo
-DKICAD_STDLIB_LIGHT_DEBUG=ON
-DKICAD_SCRIPTING_WXPYTHON=ON
-DKICAD_USE_CMAKE_FINDPROTOBUF=ON
- coverity/bin/cov-build --dir cov-int make -j10
- *coverity_submit
artifacts:
expire_in: 1 year
expose_as: 'Coverity log'
name: "coverity_log.txt"
paths:
- cov-int/build-log.txt
-15
View File
@@ -1,15 +0,0 @@
build_doxygen_docker:
image: docker:stable
services:
- docker:dind
stage: build
rules:
- if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULED_JOB_NAME == "doxygen"
tags:
- gitlab-org-docker
before_script:
- docker info
- docker login -u gitlab-ci-token -p "$CI_JOB_TOKEN" "$CI_REGISTRY"
script:
- docker build -t "${CI_REGISTRY_IMAGE}/doxygen:$CI_COMMIT_BRANCH" -f ./doxygen/doxygen.Dockerfile .
- docker push "${CI_REGISTRY_IMAGE}/doxygen:$CI_COMMIT_BRANCH"
-20
View File
@@ -1,20 +0,0 @@
<!-- --------Before Creating a New Issue-----------
* Limit report to a single issue.
* Search the issue tracker to verify the issue has not already been reported.
* Complete all instructions between `template comment markers <>.
* Keep report contents limited to the necessary information required to fix the issue.
* When creating an issue against the stable version of KiCad, make sure the latest available stable version is installed as issues may have already been resolved in later stable versions. -->
# Description
<!-- What is the current behavior and what is the expected behavior? -->
<!-- If the issue is visual/graphical, please attach screenshots of the problem. -->
<!-- Add the issue details below this line and before the "Steps to reproduce" heading. -->
# Steps to reproduce
<!-- If there are multiple steps to reproduce it or it is a visual issue, then providing a screen recording as an attachment to this report is recommended. -->
<!-- If this issue is specific to a project, please attach the necessary files to this issue. -->
<!-- Add the steps to reproduce using the numbers below -->
<!-- Add new step numbers before the "KiCad Version" heading. -->
1.
# KiCad Version
-32
View File
@@ -1,32 +0,0 @@
##########################################################################
# Run a validation of the metadata files for Linux
##########################################################################
validate_linux_metadata:
stage: test
needs: []
interruptible: false
image: $DEFAULT_FEDORA_IMAGE
# Due to bug https://github.com/hughsie/appstream-glib/issues/381, this doesn't think our description tag
# is localized even though it actually is.
allow_failure: true
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
when: never
- if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- resources/linux/**/*
- qa/resources/linux/**/*
- translation/**/*
# Only build the metadata files in this CI job
script:
- mkdir -p build/linux
- cd build/linux
- cmake
-DCMAKE_BUILD_TYPE=Debug
-DKICAD_STDLIB_LIGHT_DEBUG=ON
-DKICAD_SCRIPTING_WXPYTHON=ON
-DKICAD_BUILD_I18N=ON
../../
- make metadata
- cd ../../
- ./qa/resources/linux/verifyMetadataFiles.sh ./ ./build/linux
-29
View File
@@ -1,29 +0,0 @@
##########################################################################
# Build KiCad on Windows and save the results
##########################################################################
macos_build:
stage: build
tags:
- kicad-macos
interruptible: false
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
when: never
- if: $CI_PROJECT_ROOT_NAMESPACE == "kicad"
script:
- mkdir -p build/macos
- cd build/macos
- cmake
-G Ninja
-DCMAKE_TOOLCHAIN_FILE=/Users/$USER/kicad-mac-builder/toolchain/kicad-mac-builder.cmake
../../
- cmake --build . 2>&1 | tee compilation_log.txt
- cd ../../
artifacts:
# Only save the artifacts that are needed for running the tests in the next stage
# and the compilation log. The entire build directory is too large to save as an
# artifact.
expire_in: 2 hrs
when: always
paths:
- build/macos/compilation_log.txt
-27
View File
@@ -1,27 +0,0 @@
##########################################################################
# Test the formatting in a merge request using clang-format
##########################################################################
# The variable CI_COMMIT_BEFORE_SHA is not available in normal merge requests
# so we must build the commit hash ourselves, see:
# https://gitlab.com/gitlab-org/gitlab/-/issues/12850
test_formatting:
stage: test
needs: []
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
allow_failure: true
before_script:
# We must manually add the KiCad remote to ensure it is named sensibly
- git remote add product https://gitlab.com/kicad/code/kicad.git ||
git remote set-url product https://gitlab.com/kicad/code/kicad.git
- git remote add source ${CI_MERGE_REQUEST_SOURCE_PROJECT_URL}.git ||
git remote set-url source ${CI_MERGE_REQUEST_SOURCE_PROJECT_URL}.git
- git fetch -n product
- git fetch -n source
# Get the SHAs of the commits
- "TARGET_HEAD_SHA=$(git rev-parse product/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME})"
- "SOURCE_HEAD_SHA=$(git rev-parse source/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME})"
- "MERGE_BASE_SHA=$(git merge-base ${TARGET_HEAD_SHA} ${SOURCE_HEAD_SHA})"
script:
- echo "Testing formatting from commit ${MERGE_BASE_SHA}"
- ./tools/check_coding.sh --diff --ci --commit ${MERGE_BASE_SHA}
-37
View File
@@ -1,37 +0,0 @@
##########################################################################
# This will allow the job to run whenever code events trigger it.
##########################################################################
.only_code:
only:
- master
- branches
- merge_requests
- pushes
except:
- schedules
##########################################################################
# Define a template for all the unit tests, since each one is run in a separate
# job to make the display nicer.
##########################################################################
.unit_test:
stage: test
when: on_success
variables:
BOOST_TEST_LOGGER: 'JUNIT,warning,test_results.${TEST}.xml:HRF,message'
CTEST_OUTPUT_ON_FAILURE: 1
script:
- cd build/linux/qa
- ctest -R qa_${TEST}
# GitLab supports displaying the results in the GUI through JUNIT artifacts
# (https://docs.gitlab.com/ee/ci/junit_test_reports.html)
# so we upload the JUNIT results.
artifacts:
when: always
paths:
- build/linux/qa/**/*.log
- build/linux/qa/**/output/*
- build/linux/qa/**/*.xml
reports:
junit:
- build/linux/qa/**/*.xml
+233
View File
@@ -0,0 +1,233 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2012 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
*/
/**
* @file 3d_aux.cpp
*/
#include <fctsys.h>
#include <common.h>
#include <trigo.h>
#include <wxBasePcbFrame.h>
#include <class_board_design_settings.h>
#include <class_zone.h>
#include <class_text_mod.h>
#include <class_module.h>
#include <class_drawsegment.h>
#include <class_pcb_text.h>
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <trackball.h>
void S3D_MASTER::ObjectCoordsTo3DUnits( std::vector< S3D_VERTEX >& aVertices )
{
/* adjust object scale, rotation and offset position */
for( unsigned ii = 0; ii < aVertices.size(); ii++ )
{
aVertices[ii].x *= m_MatScale.x;
aVertices[ii].y *= m_MatScale.y;
aVertices[ii].z *= m_MatScale.z;
// adjust rotation
if( m_MatRotation.x )
{
double a = aVertices[ii].y;
double b = aVertices[ii].z;
RotatePoint( &a, &b, m_MatRotation.x * 10 );
aVertices[ii].y = (float)a;
aVertices[ii].z = (float)b;
}
if( m_MatRotation.y )
{
double a = aVertices[ii].z;
double b = aVertices[ii].x;
RotatePoint( &a, &b, m_MatRotation.x * 10 );
aVertices[ii].z = (float)a;
aVertices[ii].x = (float)b;
}
if( m_MatRotation.z )
{
double a = aVertices[ii].x;
double b = aVertices[ii].y;
RotatePoint( &a, &b, m_MatRotation.x * 10 );
aVertices[ii].x = (float)a;
aVertices[ii].y = (float)b;
}
/* adjust offset position (offset is given in UNIT 3D (0.1 inch) */
aVertices[ii].x += m_MatPosition.x * SCALE_3D_CONV;
aVertices[ii].y += m_MatPosition.y * SCALE_3D_CONV;
aVertices[ii].z += m_MatPosition.z * SCALE_3D_CONV;
}
}
void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits )
{
unsigned ii;
GLfloat ax, ay, az, bx, by, bz, nx, ny, nz, r;
/* ignore faces with less than 3 points */
if( aVertices.size() < 3 )
return;
/* calculate normal direction */
ax = aVertices[1].x - aVertices[0].x;
ay = aVertices[1].y - aVertices[0].y;
az = aVertices[1].z - aVertices[0].z;
bx = aVertices[2].x - aVertices[0].x;
by = aVertices[2].y - aVertices[0].y;
bz = aVertices[2].z - aVertices[0].z;
nx = ay * bz - az * by;
ny = az * bx - ax * bz;
nz = ax * by - ay * bx;
r = sqrt( nx * nx + ny * ny + nz * nz );
if( r >= 0.000001 ) /* avoid division by zero */
{
nx /= r;
ny /= r;
nz /= r;
glNormal3f( nx, ny, nz );
}
/* glBegin/glEnd */
switch( aVertices.size() )
{
case 3:
glBegin( GL_TRIANGLES );
break;
case 4:
glBegin( GL_QUADS );
break;
default:
glBegin( GL_POLYGON );
break;
}
/* draw polygon/triangle/quad */
for( ii = 0; ii < aVertices.size(); ii++ )
{
glVertex3d( aVertices[ii].x * aBiuTo3DUnits,
aVertices[ii].y * aBiuTo3DUnits,
aVertices[ii].z * aBiuTo3DUnits );
}
glEnd();
}
S3DPOINT_VALUE_CTRL::S3DPOINT_VALUE_CTRL( wxWindow* aParent, wxBoxSizer* aBoxSizer )
{
wxString text;
wxFlexGridSizer* gridSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
gridSizer->AddGrowableCol( 1 );
gridSizer->SetFlexibleDirection( wxHORIZONTAL );
gridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
aBoxSizer->Add( gridSizer, 0, wxEXPAND, 5 );
wxStaticText* msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "X:" ) );
gridSizer->Add( msgtitle, 0, wxALL , 5 );
m_XValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
wxDefaultPosition,wxDefaultSize, 0 );
gridSizer->Add( m_XValueCtrl, 0, wxALL|wxEXPAND, 5 );
msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "Y:" ), wxDefaultPosition,
wxDefaultSize, 0 );
gridSizer->Add( msgtitle, 0, wxALL, 5 );
m_YValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize, 0 );
gridSizer->Add( m_YValueCtrl, 0, wxALL|wxEXPAND, 5 );
msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "Z:" ), wxDefaultPosition,
wxDefaultSize, 0 );
gridSizer->Add( msgtitle, 0, wxALL, 5 );
m_ZValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize, 0 );
gridSizer->Add( m_ZValueCtrl, 0, wxALL|wxEXPAND, 5 );
}
S3DPOINT_VALUE_CTRL::~S3DPOINT_VALUE_CTRL()
{
// Nothing to delete: all items are managed by the parent window.
}
S3DPOINT S3DPOINT_VALUE_CTRL::GetValue()
{
S3DPOINT value;
double dtmp;
m_XValueCtrl->GetValue().ToDouble( &dtmp );
value.x = dtmp;
m_YValueCtrl->GetValue().ToDouble( &dtmp );
value.y = dtmp;
m_ZValueCtrl->GetValue().ToDouble( &dtmp );
value.z = dtmp;
return value;
}
void S3DPOINT_VALUE_CTRL::SetValue( S3DPOINT vertex )
{
wxString text;
text.Printf( wxT( "%f" ), vertex.x );
m_XValueCtrl->Clear();
m_XValueCtrl->AppendText( text );
text.Printf( wxT( "%f" ), vertex.y );
m_YValueCtrl->Clear();
m_YValueCtrl->AppendText( text );
text.Printf( wxT( "%f" ), vertex.z );
m_ZValueCtrl->Clear();
m_ZValueCtrl->AppendText( text );
}
void S3DPOINT_VALUE_CTRL::Enable( bool onoff )
{
m_XValueCtrl->Enable( onoff );
m_YValueCtrl->Enable( onoff );
m_ZValueCtrl->Enable( onoff );
}
-616
View File
@@ -1,616 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022 CERN
*
* 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
*/
#define GLM_FORCE_RADIANS
#include <mutex>
#include <utility>
#include <wx/datetime.h>
#include <wx/dir.h>
#include <wx/log.h>
#include <wx/stdpaths.h>
#include "3d_cache.h"
#include "3d_info.h"
#include "3d_plugin_manager.h"
#include "sg/scenegraph.h"
#include "plugins/3dapi/ifsg_api.h"
#include <advanced_config.h>
#include <common.h> // For ExpandEnvVarSubstitutions
#include <filename_resolver.h>
#include <mmh3_hash.h>
#include <paths.h>
#include <pgm_base.h>
#include <project.h>
#include <settings/common_settings.h>
#include <settings/settings_manager.h>
#include <wx_filename.h>
#define MASK_3D_CACHE "3D_CACHE"
static std::mutex mutex3D_cache;
static bool checkTag( const char* aTag, void* aPluginMgrPtr )
{
if( nullptr == aTag || nullptr == aPluginMgrPtr )
return false;
S3D_PLUGIN_MANAGER *pp = (S3D_PLUGIN_MANAGER*) aPluginMgrPtr;
return pp->CheckTag( aTag );
}
class S3D_CACHE_ENTRY
{
public:
S3D_CACHE_ENTRY();
~S3D_CACHE_ENTRY();
void SetHash( const HASH_128& aHash );
const wxString GetCacheBaseName();
wxDateTime modTime; // file modification time
HASH_128 m_hash;
std::string pluginInfo; // PluginName:Version string
SCENEGRAPH* sceneData;
S3DMODEL* renderData;
private:
// prohibit assignment and default copy constructor
S3D_CACHE_ENTRY( const S3D_CACHE_ENTRY& source );
S3D_CACHE_ENTRY& operator=( const S3D_CACHE_ENTRY& source );
wxString m_CacheBaseName; // base name of cache file
};
S3D_CACHE_ENTRY::S3D_CACHE_ENTRY()
{
sceneData = nullptr;
renderData = nullptr;
m_hash.Clear();
}
S3D_CACHE_ENTRY::~S3D_CACHE_ENTRY()
{
delete sceneData;
if( nullptr != renderData )
S3D::Destroy3DModel( &renderData );
}
void S3D_CACHE_ENTRY::SetHash( const HASH_128& aHash )
{
m_hash = aHash;
}
const wxString S3D_CACHE_ENTRY::GetCacheBaseName()
{
if( m_CacheBaseName.empty() )
m_CacheBaseName = m_hash.ToString();
return m_CacheBaseName;
}
S3D_CACHE::S3D_CACHE()
{
m_FNResolver = new FILENAME_RESOLVER;
m_project = nullptr;
m_Plugins = new S3D_PLUGIN_MANAGER;
}
S3D_CACHE::~S3D_CACHE()
{
FlushCache();
delete m_FNResolver;
delete m_Plugins;
}
SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, const wxString& aBasePath,
S3D_CACHE_ENTRY** aCachePtr, const EMBEDDED_FILES* aEmbeddedFiles )
{
if( aCachePtr )
*aCachePtr = nullptr;
wxString full3Dpath = m_FNResolver->ResolvePath( aModelFile, aBasePath, aEmbeddedFiles );
if( full3Dpath.empty() )
{
// the model cannot be found; we cannot proceed
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * [3D model] could not find model '%s'\n" ),
__FILE__, __FUNCTION__, __LINE__, aModelFile );
return nullptr;
}
// check cache if file is already loaded
std::lock_guard<std::mutex> lock( mutex3D_cache );
std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString >::iterator mi;
mi = m_CacheMap.find( full3Dpath );
if( mi != m_CacheMap.end() )
{
wxFileName fname( full3Dpath );
if( fname.FileExists() ) // Only check if file exists. If not, it will
{ // use the same model in cache.
bool reload = ADVANCED_CFG::GetCfg().m_Skip3DModelMemoryCache;
wxDateTime fmdate = fname.GetModificationTime();
if( fmdate != mi->second->modTime )
{
HASH_128 hashSum;
getHash( full3Dpath, hashSum );
mi->second->modTime = fmdate;
if( hashSum != mi->second->m_hash )
{
mi->second->SetHash( hashSum );
reload = true;
}
}
if( reload )
{
if( nullptr != mi->second->sceneData )
{
S3D::DestroyNode( mi->second->sceneData );
mi->second->sceneData = nullptr;
}
if( nullptr != mi->second->renderData )
S3D::Destroy3DModel( &mi->second->renderData );
mi->second->sceneData = m_Plugins->Load3DModel( full3Dpath,
mi->second->pluginInfo );
}
}
if( nullptr != aCachePtr )
*aCachePtr = mi->second;
return mi->second->sceneData;
}
// a cache item does not exist; search the Filename->Cachename map
return checkCache( full3Dpath, aCachePtr );
}
SCENEGRAPH* S3D_CACHE::Load( const wxString& aModelFile, const wxString& aBasePath,
const EMBEDDED_FILES* aEmbeddedFiles )
{
return load( aModelFile, aBasePath, nullptr, aEmbeddedFiles );
}
SCENEGRAPH* S3D_CACHE::checkCache( const wxString& aFileName, S3D_CACHE_ENTRY** aCachePtr )
{
if( aCachePtr )
*aCachePtr = nullptr;
HASH_128 hashSum;
S3D_CACHE_ENTRY* ep = new S3D_CACHE_ENTRY;
m_CacheList.push_back( ep );
wxFileName fname( aFileName );
ep->modTime = fname.GetModificationTime();
if( !getHash( aFileName, hashSum ) || m_CacheDir.empty() )
{
// just in case we can't get a hash digest (for example, on access issues)
// or we do not have a configured cache file directory, we create an
// entry to prevent further attempts at loading the file
if( m_CacheMap.emplace( aFileName, ep ).second == false )
{
wxLogTrace( MASK_3D_CACHE,
wxT( "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
__FILE__, __FUNCTION__, __LINE__, aFileName );
m_CacheList.pop_back();
delete ep;
}
else
{
if( aCachePtr )
*aCachePtr = ep;
}
return nullptr;
}
if( m_CacheMap.emplace( aFileName, ep ).second == false )
{
wxLogTrace( MASK_3D_CACHE,
wxT( "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
__FILE__, __FUNCTION__, __LINE__, aFileName );
m_CacheList.pop_back();
delete ep;
return nullptr;
}
if( aCachePtr )
*aCachePtr = ep;
ep->SetHash( hashSum );
wxString bname = ep->GetCacheBaseName();
wxString cachename = m_CacheDir + bname + wxT( ".3dc" );
if( !ADVANCED_CFG::GetCfg().m_Skip3DModelFileCache && wxFileName::FileExists( cachename )
&& loadCacheData( ep ) )
return ep->sceneData;
ep->sceneData = m_Plugins->Load3DModel( aFileName, ep->pluginInfo );
if( !ADVANCED_CFG::GetCfg().m_Skip3DModelFileCache && nullptr != ep->sceneData )
saveCacheData( ep );
return ep->sceneData;
}
bool S3D_CACHE::getHash( const wxString& aFileName, HASH_128& aHash )
{
if( aFileName.empty() )
{
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * [BUG] empty filename" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
#ifdef _WIN32
FILE* fp = _wfopen( aFileName.wc_str(), L"rb" );
#else
FILE* fp = fopen( aFileName.ToUTF8(), "rb" );
#endif
if( nullptr == fp )
return false;
MMH3_HASH dblock( 0xA1B2C3D4 );
std::vector<char> block( 4096 );
size_t bsize = 0;
while( ( bsize = fread( block.data(), 1, 4096, fp ) ) > 0 )
dblock.add( block );
fclose( fp );
aHash = dblock.digest();
return true;
}
bool S3D_CACHE::loadCacheData( S3D_CACHE_ENTRY* aCacheItem )
{
wxString bname = aCacheItem->GetCacheBaseName();
if( bname.empty() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( " * [3D model] cannot load cached model; no file hash available" ) );
return false;
}
if( m_CacheDir.empty() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( " * [3D model] cannot load cached model; config directory unknown" ) );
return false;
}
wxString fname = m_CacheDir + bname + wxT( ".3dc" );
if( !wxFileName::FileExists( fname ) )
{
wxLogTrace( MASK_3D_CACHE, wxT( " * [3D model] cannot open file '%s'" ), fname.GetData() );
return false;
}
if( nullptr != aCacheItem->sceneData )
S3D::DestroyNode( (SGNODE*) aCacheItem->sceneData );
aCacheItem->sceneData = (SCENEGRAPH*)S3D::ReadCache( fname.ToUTF8(), m_Plugins, checkTag );
if( nullptr == aCacheItem->sceneData )
return false;
return true;
}
bool S3D_CACHE::saveCacheData( S3D_CACHE_ENTRY* aCacheItem )
{
if( nullptr == aCacheItem )
{
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * NULL passed for aCacheItem" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
if( nullptr == aCacheItem->sceneData )
{
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * aCacheItem has no valid scene data" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
wxString bname = aCacheItem->GetCacheBaseName();
if( bname.empty() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( " * [3D model] cannot load cached model; no file hash available" ) );
return false;
}
if( m_CacheDir.empty() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( " * [3D model] cannot load cached model; config directory unknown" ) );
return false;
}
wxString fname = m_CacheDir + bname + wxT( ".3dc" );
if( wxFileName::Exists( fname ) )
{
if( !wxFileName::FileExists( fname ) )
{
wxLogTrace( MASK_3D_CACHE,
wxT( " * [3D model] path exists but is not a regular file '%s'" ), fname );
return false;
}
}
return S3D::WriteCache( fname.ToUTF8(), true, (SGNODE*)aCacheItem->sceneData,
aCacheItem->pluginInfo.c_str() );
}
bool S3D_CACHE::Set3DConfigDir( const wxString& aConfigDir )
{
if( !m_ConfigDir.empty() )
return false;
wxFileName cfgdir( ExpandEnvVarSubstitutions( aConfigDir, m_project ), wxEmptyString );
cfgdir.Normalize( FN_NORMALIZE_FLAGS );
if( !cfgdir.DirExists() )
{
cfgdir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
if( !cfgdir.DirExists() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( "%s:%s:%d\n * failed to create 3D configuration directory '%s'" ),
__FILE__, __FUNCTION__, __LINE__, cfgdir.GetPath() );
return false;
}
}
m_ConfigDir = cfgdir.GetPath();
// inform the file resolver of the config directory
if( !m_FNResolver->Set3DConfigDir( m_ConfigDir ) )
{
wxLogTrace( MASK_3D_CACHE,
wxT( "%s:%s:%d\n * could not set 3D Config Directory on filename resolver\n"
" * config directory: '%s'" ),
__FILE__, __FUNCTION__, __LINE__, m_ConfigDir );
}
// 3D cache data must go to a user's cache directory;
// unfortunately wxWidgets doesn't seem to provide
// functions to retrieve such a directory.
//
// 1. OSX: ~/Library/Caches/kicad/3d/
// 2. Linux: ${XDG_CACHE_HOME}/kicad/3d ~/.cache/kicad/3d/
// 3. MSWin: AppData\Local\kicad\3d
wxFileName cacheDir;
cacheDir.AssignDir( PATHS::GetUserCachePath() );
cacheDir.AppendDir( wxT( "3d" ) );
if( !cacheDir.DirExists() )
{
cacheDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
if( !cacheDir.DirExists() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( "%s:%s:%d\n * failed to create 3D cache directory '%s'" ),
__FILE__, __FUNCTION__, __LINE__, cacheDir.GetPath() );
return false;
}
}
m_CacheDir = cacheDir.GetPathWithSep();
return true;
}
bool S3D_CACHE::SetProject( PROJECT* aProject )
{
m_project = aProject;
bool hasChanged = false;
if( m_FNResolver->SetProject( aProject, &hasChanged ) && hasChanged )
{
m_CacheMap.clear();
std::list< S3D_CACHE_ENTRY* >::iterator sL = m_CacheList.begin();
std::list< S3D_CACHE_ENTRY* >::iterator eL = m_CacheList.end();
while( sL != eL )
{
delete *sL;
++sL;
}
m_CacheList.clear();
return true;
}
return false;
}
void S3D_CACHE::SetProgramBase( PGM_BASE* aBase )
{
m_FNResolver->SetProgramBase( aBase );
}
FILENAME_RESOLVER* S3D_CACHE::GetResolver() noexcept
{
return m_FNResolver;
}
std::list< wxString > const* S3D_CACHE::GetFileFilters() const
{
return m_Plugins->GetFileFilters();
}
void S3D_CACHE::FlushCache( bool closePlugins )
{
std::list< S3D_CACHE_ENTRY* >::iterator sCL = m_CacheList.begin();
std::list< S3D_CACHE_ENTRY* >::iterator eCL = m_CacheList.end();
while( sCL != eCL )
{
delete *sCL;
++sCL;
}
m_CacheList.clear();
m_CacheMap.clear();
if( closePlugins )
ClosePlugins();
}
void S3D_CACHE::ClosePlugins()
{
if( m_Plugins )
m_Plugins->ClosePlugins();
}
S3DMODEL* S3D_CACHE::GetModel( const wxString& aModelFileName, const wxString& aBasePath,
const EMBEDDED_FILES* aEmbeddedFiles )
{
S3D_CACHE_ENTRY* cp = nullptr;
SCENEGRAPH* sp = load( aModelFileName, aBasePath, &cp, aEmbeddedFiles );
if( !sp )
return nullptr;
if( !cp )
{
wxLogTrace( MASK_3D_CACHE,
wxT( "%s:%s:%d\n * [BUG] model loaded with no associated S3D_CACHE_ENTRY" ),
__FILE__, __FUNCTION__, __LINE__ );
return nullptr;
}
if( cp->renderData )
return cp->renderData;
S3DMODEL* mp = S3D::GetModel( sp );
cp->renderData = mp;
return mp;
}
void S3D_CACHE::CleanCacheDir( int aNumDaysOld )
{
wxDir dir;
wxString fileSpec = wxT( "*.3dc" );
wxArrayString fileList; // Holds list of ".3dc" files found in cache directory
size_t numFilesFound = 0;
wxFileName thisFile;
wxDateTime lastAccess, thresholdDate;
wxDateSpan durationInDays;
// Calc the threshold date above which we delete cache files
durationInDays.SetDays( aNumDaysOld );
thresholdDate = wxDateTime::Now() - durationInDays;
// If the cache directory can be found and opened, then we'll try and clean it up
if( dir.Open( m_CacheDir ) )
{
thisFile.SetPath( m_CacheDir ); // Set the base path to the cache folder
// Get a list of all the ".3dc" files in the cache directory
numFilesFound = dir.GetAllFiles( m_CacheDir, &fileList, fileSpec );
for( unsigned int i = 0; i < numFilesFound; i++ )
{
// Completes path to specific file so we can get its "last access" date
thisFile.SetFullName( fileList[i] );
// Only get "last access" time to compare against. Don't need the other 2 timestamps.
if( thisFile.GetTimes( &lastAccess, nullptr, nullptr ) )
{
if( lastAccess.IsEarlierThan( thresholdDate ) )
{
// This file is older than the threshold so delete it
wxRemoveFile( thisFile.GetFullPath() );
}
}
}
}
}
-194
View File
@@ -1,194 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file 3d_cache.h
*/
#ifndef CACHE_3D_H
#define CACHE_3D_H
#include "3d_info.h"
#include <core/typeinfo.h>
#include "string_utils.h"
#include <hash_128.h>
#include <list>
#include <map>
#include "plugins/3dapi/c3dmodel.h"
#include <project.h>
#include <wx/string.h>
class EMBEDDED_FILES;
class PGM_BASE;
class S3D_CACHE_ENTRY;
class SCENEGRAPH;
class FILENAME_RESOLVER;
class S3D_PLUGIN_MANAGER;
/**
* Cache for storing the 3D shapes. This cache is able to be stored as a project
* element (since it inherits from PROJECT::_ELEM).
*/
class S3D_CACHE : public PROJECT::_ELEM
{
public:
S3D_CACHE();
virtual ~S3D_CACHE();
PROJECT::ELEM ProjectElementType() noexcept override
{
return PROJECT::ELEM::S3DCACHE;
}
/**
* Set the configuration directory to be used by the model manager for storing 3D
* model manager configuration data and the model cache.
*
* The config directory may only be set once in the lifetime of the object.
*
* @param aConfigDir is the configuration directory to use for 3D model manager data
* @return true on success
*/
bool Set3DConfigDir( const wxString& aConfigDir );
/**
* Set the current project's working directory; this affects the model search path.
*/
bool SetProject( PROJECT* aProject );
/**
* Set the filename resolver's pointer to the application's PGM_BASE instance.
*
* The pointer is used to extract the local environment variables.
*/
void SetProgramBase( PGM_BASE* aBase );
/**
* Attempt to load the scene data for a model.
*
* It will consult the internal cache list and load from cache if possible before invoking
* the load() function of the available plugins. The model may fail to load if, for example,
* the plugin does not support rendering of the 3D model.
*
* @param aModelFile is the partial or full path to the model to be loaded.
* @param aBasePath is the path to search for any relative files
* @param aEmbeddedFiles is a pointer to the embedded files list.
* @return true if the model was successfully loaded, otherwise false.
*/
SCENEGRAPH* Load( const wxString& aModelFile, const wxString& aBasePath,
const EMBEDDED_FILES* aEmbeddedFiles );
FILENAME_RESOLVER* GetResolver() noexcept;
/**
* Return the list of file filters retrieved from the plugins.
*
* This will contain at least the default "All Files (*.*)|*.*"
*
* @return a pointer to the filter list.
*/
std::list< wxString > const* GetFileFilters() const;
/**
* Free all data in the cache and by default closes all plugins.
*/
void FlushCache( bool closePlugins = true );
/**
* Unload plugins to free memory.
*/
void ClosePlugins();
/**
* Attempt to load the scene data for a model and to translate it into an S3D_MODEL
* structure for display by a renderer.
*
* @param aModelFileName is the full path to the model to be loaded.
* @param aBasePath is the path to search for any relative files.
* @param aEmbeddedFiles is a pointer to the embedded files list.
* @return is a pointer to the render data or NULL if not available.
*/
S3DMODEL* GetModel( const wxString& aModelFileName, const wxString& aBasePath,
const EMBEDDED_FILES* aEmbeddedFiles );
/**
* Delete up old cache files in cache directory.
*
* Deletes ".3dc" files in the cache directory that are older than \a aNumDaysOld.
*
* @param aNumDaysOld is age threshold to delete ".3dc" cache files.
*/
void CleanCacheDir( int aNumDaysOld );
private:
/**
* Find or create cache entry for file name
*
* Searches the cache list for the given filename and retrieves the cache data; a cache
* entry is created if one does not already exist.
*
* @param aFileName is the file name (full or partial path).
* @param aCachePtr is an optional return address for cache entry pointer.
* @return SCENEGRAPH object associated with file name or NULL on error.
*/
SCENEGRAPH* checkCache( const wxString& aFileName, S3D_CACHE_ENTRY** aCachePtr = nullptr );
/**
* Calculate the SHA1 hash of the given file.
*
* @param aFileName file name (full path).
* @param aHash a 128 bit hash to hold the hash.
* @return true on success, otherwise false.
*/
bool getHash( const wxString& aFileName, HASH_128& aHash );
// load scene data from a cache file
bool loadCacheData( S3D_CACHE_ENTRY* aCacheItem );
// save scene data to a cache file
bool saveCacheData( S3D_CACHE_ENTRY* aCacheItem );
// the real load function (can supply a cache entry pointer to member functions)
SCENEGRAPH* load( const wxString& aModelFile, const wxString& aBasePath,
S3D_CACHE_ENTRY** aCachePtr = nullptr,
const EMBEDDED_FILES* aEmbeddedFiles = nullptr );
/// Cache entries.
std::list< S3D_CACHE_ENTRY* > m_CacheList;
/// Mapping of file names to cache names and data.
std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString > m_CacheMap;
FILENAME_RESOLVER* m_FNResolver;
S3D_PLUGIN_MANAGER* m_Plugins;
PROJECT* m_project;
wxString m_CacheDir;
wxString m_ConfigDir; ///< base configuration path for 3D items.
};
#endif // CACHE_3D_H
-52
View File
@@ -1,52 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright The 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
*/
/**
* @file 3d_info.h
* defines the basic data associated with a single 3D model.
*/
#ifndef INFO_3D_H
#define INFO_3D_H
#include <wx/string.h>
#include <plugins/3dapi/sg_base.h>
class FP_3DMODEL;
struct S3D_INFO
{
S3D_INFO();
S3D_INFO( const FP_3DMODEL& aModel );
SGPOINT m_Scale; ///< scaling factors for the 3D footprint shape
SGPOINT m_Rotation; ///< an X,Y,Z rotation (unit = degrees) for the 3D shape
SGPOINT m_Offset; ///< an offset (unit = inch) for the 3D shape
wxString m_Filename; ///< The 3D shape filename in 3D library
};
#endif // INFO_3D_H
-535
View File
@@ -1,535 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <utility>
#include <iostream>
#include <sstream>
#include <wx/dir.h>
#include <wx/dynlib.h>
#include <wx/log.h>
#include <wx/stdpaths.h>
#include <wx/string.h>
#include <common.h>
#include <paths.h>
#include <wx_filename.h>
#include "3d_plugin_manager.h"
#include "plugins/3d/3d_plugin.h"
#include "3d_cache/sg/scenegraph.h"
#include "plugins/ldr/3d/pluginldr3D.h"
/**
* Flag to enable 3D plugin manager debug tracing.
*
* Use "KI_TRACE_EDA_3D_VIEWER" to enable.
*
* @ingroup trace_env_vars
*/
#define MASK_3D_PLUGINMGR "3D_PLUGIN_MANAGER"
S3D_PLUGIN_MANAGER::S3D_PLUGIN_MANAGER()
{
// create the initial file filter list entry
m_FileFilters.emplace_back( _( "All Files" ) + wxT( " (*.*)|*.*" ) );
// discover and load plugins
loadPlugins();
#ifdef DEBUG
if( !m_ExtMap.empty() )
{
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::const_iterator sM = m_ExtMap.begin();
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::const_iterator eM = m_ExtMap.end();
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * Extension [plugin name]:\n" ) );
while( sM != eM )
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " + '%s' [%s]\n" ), sM->first.GetData(),
sM->second->GetKicadPluginName() );
++sM;
}
}
else
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * No plugins available\n" ) );
}
if( !m_FileFilters.empty() )
{
/// list of file filters
std::list< wxString >::const_iterator sFF = m_FileFilters.begin();
std::list< wxString >::const_iterator eFF = m_FileFilters.end();
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * File filters:\n" ) );
while( sFF != eFF )
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " + '%s'\n" ), (*sFF).GetData() );
++sFF;
}
}
else
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * No file filters available\n" ) );
}
#endif // DEBUG
}
S3D_PLUGIN_MANAGER::~S3D_PLUGIN_MANAGER()
{
std::list< KICAD_PLUGIN_LDR_3D* >::iterator sP = m_Plugins.begin();
std::list< KICAD_PLUGIN_LDR_3D* >::iterator eP = m_Plugins.end();
while( sP != eP )
{
(*sP)->Close();
delete *sP;
++sP;
}
m_Plugins.clear();
}
void S3D_PLUGIN_MANAGER::loadPlugins( void )
{
std::list<wxString> searchpaths;
std::list<wxString> pluginlist;
wxFileName fn;
#ifndef __WXMAC__
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
{
// set up to work from the build directory
fn.Assign( wxStandardPaths::Get().GetExecutablePath() );
fn.AppendDir( wxT( ".." ) );
fn.AppendDir( wxT( "plugins" ) );
fn.AppendDir( wxT( "3d" ) );
std::string testpath = std::string( fn.GetPathWithSep().ToUTF8() );
checkPluginPath( testpath, searchpaths );
// add subdirectories too
wxDir debugPluginDir;
wxString subdir;
debugPluginDir.Open( testpath );
if( debugPluginDir.IsOpened()
&& debugPluginDir.GetFirst( &subdir, wxEmptyString, wxDIR_DIRS ) )
{
checkPluginPath( testpath + subdir, searchpaths );
while( debugPluginDir.GetNext( &subdir ) )
checkPluginPath( testpath + subdir, searchpaths );
}
}
fn.AssignDir( PATHS::GetStockPlugins3DPath() );
checkPluginPath( std::string( fn.GetPathWithSep().ToUTF8() ), searchpaths );
#else
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
{
// Exe will be at <build_dir>/pcbnew/pcbnew.app/Contents/MacOS/pcbnew for standalone
// Plugin will be at <build_dir>/kicad/KiCad.app/Contents/PlugIns/3d
fn.Assign( wxStandardPaths::Get().GetExecutablePath() );
if( fn.GetName() == wxT( "kicad" ) )
{
fn.AppendDir( wxT( ".." ) ); // Contents
}
else
{
fn.AppendDir( wxT( ".." ) ); // Contents
fn.AppendDir( wxT( ".." ) ); // pcbnew.app
fn.AppendDir( wxT( ".." ) ); // pcbnew
fn.AppendDir( wxT( ".." ) ); // Build root
fn.AppendDir( wxT( "kicad" ) );
fn.AppendDir( wxT( "KiCad.app" ) );
fn.AppendDir( wxT( "Contents" ) );
}
fn.AppendDir( wxT( "PlugIns" ) );
fn.AppendDir( wxT( "3d" ) );
fn.MakeAbsolute();
std::string testpath = std::string( fn.GetPathWithSep().ToUTF8() );
checkPluginPath( testpath, searchpaths );
// Also check when running KiCad manager from build dir
}
else
{
// Search path on OS X is
// (1) Machine /Library/Application Support/kicad/PlugIns/3d
checkPluginPath( PATHS::GetOSXKicadMachineDataDir() + wxT( "/PlugIns/3d" ), searchpaths );
// (2) Bundle kicad.app/Contents/PlugIns/3d
fn.AssignDir( PATHS::GetStockPlugins3DPath() );
checkPluginPath( fn.GetPathWithSep(), searchpaths );
}
#endif
std::list< wxString >::iterator sPL = searchpaths.begin();
std::list< wxString >::iterator ePL = searchpaths.end();
while( sPL != ePL )
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] searching path: '%s'" ),
__FILE__, __FUNCTION__, __LINE__, (*sPL).ToUTF8() );
listPlugins( *sPL, pluginlist );
++sPL;
}
if( pluginlist.empty() )
return;
sPL = pluginlist.begin();
ePL = pluginlist.end();
while( sPL != ePL )
{
KICAD_PLUGIN_LDR_3D* pp = new KICAD_PLUGIN_LDR_3D;
if( pp->Open( sPL->ToUTF8() ) )
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] adding plugin" ),
__FILE__, __FUNCTION__, __LINE__ );
m_Plugins.push_back( pp );
int nf = pp->GetNFilters();
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] adding %d filters" ),
__FILE__, __FUNCTION__, __LINE__, nf );
for( int i = 0; i < nf; ++i )
{
char const* cp = pp->GetFileFilter( i );
if( cp )
addFilterString( cp );
}
addExtensionMap( pp );
// close the loaded library
pp->Close();
}
else
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] deleting plugin" ),
__FILE__, __FUNCTION__, __LINE__ );
delete pp;
}
++sPL;
}
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] plugins loaded" ),
__FILE__, __FUNCTION__, __LINE__ );
}
void S3D_PLUGIN_MANAGER::listPlugins( const wxString& aPath, std::list< wxString >& aPluginList )
{
// list potential plugins given a search path
wxString nameFilter; // filter for user-loadable libraries (aka footprints)
wxString lName; // stores name of enumerated files
wxString fName; // full name of file
wxDir wd;
wd.Open( aPath );
if( !wd.IsOpened() )
return;
nameFilter = wxT( "*" );
#ifndef __WXMAC__
nameFilter.Append( wxDynamicLibrary::GetDllExt( wxDL_MODULE ) );
#else
// wxDynamicLibrary::GetDllExt( wxDL_MODULE ) will return ".bundle" on OS X.
// This might be correct, but cmake builds a ".so" for a library MODULE.
// Per definition a loadable "xxx.bundle" is similar to an "xxx.app" app
// bundle being a folder with some special content in it. We obviously don't
// want to have that here for our loadable module, so just use ".so".
nameFilter.Append( wxS( ".so" ) );
#endif
wxString lp = wd.GetNameWithSep();
if( wd.GetFirst( &lName, nameFilter, wxDIR_FILES ) )
{
fName = lp + lName;
checkPluginName( fName, aPluginList );
while( wd.GetNext( &lName ) )
{
fName = lp + lName;
checkPluginName( fName, aPluginList );
}
}
wd.Close();
}
void S3D_PLUGIN_MANAGER::checkPluginName( const wxString& aPath,
std::list< wxString >& aPluginList )
{
// check the existence of a plugin name and add it to the list
if( aPath.empty() || !wxFileName::FileExists( aPath ) )
return;
wxFileName path( ExpandEnvVarSubstitutions( aPath, nullptr ) );
path.Normalize( FN_NORMALIZE_FLAGS );
// determine if the path is already in the list
wxString wxpath = path.GetFullPath();
std::list< wxString >::iterator bl = aPluginList.begin();
std::list< wxString >::iterator el = aPluginList.end();
while( bl != el )
{
if( 0 == (*bl).Cmp( wxpath ) )
return;
++bl;
}
// prevent loading non-plugin dlls
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
{
if( !path.GetName().StartsWith( "s3d_plugin" )
&& !path.GetName().StartsWith( "libs3d_plugin" ) )
{
return;
}
}
aPluginList.push_back( wxpath );
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * [INFO] found 3D plugin '%s'\n" ), wxpath.GetData() );
}
void S3D_PLUGIN_MANAGER::checkPluginPath( const wxString& aPath,
std::list< wxString >& aSearchList )
{
if( aPath.empty() )
return;
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * [INFO] checking if valid plugin directory '%s'\n" ),
aPath.GetData() );
wxFileName path;
path.AssignDir( aPath );
path.Normalize( FN_NORMALIZE_FLAGS );
if( !wxFileName::DirExists( path.GetFullPath() ) )
return;
// determine if the directory is already in the list
wxString wxpath = path.GetFullPath();
std::list< wxString >::iterator bl = aSearchList.begin();
std::list< wxString >::iterator el = aSearchList.end();
while( bl != el )
{
if( 0 == (*bl).Cmp( wxpath ) )
return;
++bl;
}
aSearchList.push_back( wxpath );
}
void S3D_PLUGIN_MANAGER::addFilterString( const wxString& aFilterString )
{
// add an entry to the file filter list
if( aFilterString.empty() )
return;
std::list< wxString >::iterator sFF = m_FileFilters.begin();
std::list< wxString >::iterator eFF = m_FileFilters.end();
while( sFF != eFF )
{
if( 0 == (*sFF).Cmp( aFilterString ) )
return;
++sFF;
}
m_FileFilters.push_back( aFilterString );
return;
}
void S3D_PLUGIN_MANAGER::addExtensionMap( KICAD_PLUGIN_LDR_3D* aPlugin )
{
// add entries to the extension map
if( nullptr == aPlugin )
return;
int nExt = aPlugin->GetNExtensions();
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [INFO] adding %d extensions" ),
__FILE__, __FUNCTION__, __LINE__, nExt );
for( int i = 0; i < nExt; ++i )
{
char const* cp = aPlugin->GetModelExtension( i );
wxString ws;
if( cp )
ws = wxString( cp );
if( !ws.empty() )
{
m_ExtMap.emplace( ws, aPlugin );
}
}
}
std::list< wxString > const* S3D_PLUGIN_MANAGER::GetFileFilters( void ) const noexcept
{
return &m_FileFilters;
}
SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName, std::string& aPluginInfo )
{
wxFileName raw( aFileName );
wxString ext_to_find = raw.GetExt();
#ifdef _WIN32
// note: plugins only have a lowercase filter within Windows; including an uppercase
// filter will result in duplicate file entries and should be avoided.
ext_to_find.MakeLower();
#endif
// .gz files are compressed versions that may have additional information in the previous
// extension.
if( ext_to_find == wxT( "gz" ) )
{
wxFileName second( raw.GetName() );
ext_to_find = second.GetExt() + wxT( ".gz" );
}
std::pair < std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator,
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator > items;
items = m_ExtMap.equal_range( ext_to_find );
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator sL = items.first;
while( sL != items.second )
{
if( sL->second->CanRender() )
{
SCENEGRAPH* sp = sL->second->Load( aFileName.ToUTF8() );
if( nullptr != sp )
{
sL->second->GetPluginInfo( aPluginInfo );
return sp;
}
}
++sL;
}
return nullptr;
}
void S3D_PLUGIN_MANAGER::ClosePlugins( void )
{
std::list< KICAD_PLUGIN_LDR_3D* >::iterator sP = m_Plugins.begin();
std::list< KICAD_PLUGIN_LDR_3D* >::iterator eP = m_Plugins.end();
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [INFO] closing %d extensions" ),
__FILE__, __FUNCTION__, __LINE__, static_cast<int>( m_Plugins.size() ) );
while( sP != eP )
{
(*sP)->Close();
++sP;
}
}
bool S3D_PLUGIN_MANAGER::CheckTag( const char* aTag )
{
if( nullptr == aTag || aTag[0] == 0 || m_Plugins.empty() )
return false;
std::string tname = aTag;
std::string pname; // plugin name
size_t cpos = tname.find( ':' );
// if there is no colon or plugin name then the tag is bad
if( cpos == std::string::npos || cpos == 0 )
return false;
pname = tname.substr( 0, cpos );
std::string ptag; // tag from the plugin
std::list< KICAD_PLUGIN_LDR_3D* >::iterator pS = m_Plugins.begin();
std::list< KICAD_PLUGIN_LDR_3D* >::iterator pE = m_Plugins.end();
while( pS != pE )
{
ptag.clear();
(*pS)->GetPluginInfo( ptag );
// if the plugin name matches then the version must also match
if( !ptag.compare( 0, pname.size(), pname ) )
{
if( ptag.compare( tname ) )
return false;
return true;
}
++pS;
}
return true;
}
-101
View File
@@ -1,101 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file 3d_plugin_manager.h
* manages 3D model plugins
*/
#ifndef PLUGIN_MANAGER_3D_H
#define PLUGIN_MANAGER_3D_H
#include <map>
#include <list>
#include <string>
#include <wx/string.h>
class wxWindow;
class KICAD_PLUGIN_LDR_3D;
class SCENEGRAPH;
class S3D_PLUGIN_MANAGER
{
public:
S3D_PLUGIN_MANAGER();
virtual ~S3D_PLUGIN_MANAGER();
/**
* Return the list of file filters; this will contain at least the default
* "All Files (*.*)|*.*" and the file filters supported by any available plugins.
*
* @return a pointer to the internal filter list.
*/
std::list< wxString > const* GetFileFilters( void ) const noexcept;
SCENEGRAPH* Load3DModel( const wxString& aFileName, std::string& aPluginInfo );
/**
* Iterate through all discovered plugins and closes them to reclaim memory.
*
* The individual plugins will be automatically reloaded as calls are made to load
* specific models.
*/
void ClosePlugins( void );
/**
* Check the given tag and returns true if the plugin named in the tag is not loaded
* or the plugin is loaded and the version matches.
*/
bool CheckTag( const char* aTag );
private:
/// load plugins
void loadPlugins( void );
/// list potential plugins
void listPlugins( const wxString& aPath, std::list< wxString >& aPluginList );
/// check the existence of a plugin name and add it to the list
void checkPluginName( const wxString& aPath, std::list< wxString >& aPluginList );
/// check the existence of a path and add it to the path search list
void checkPluginPath( const wxString& aPath, std::list< wxString >& aSearchList );
/// add an entry to the file filter list
void addFilterString( const wxString& aFilterString );
/// add entries to the extension map
void addExtensionMap( KICAD_PLUGIN_LDR_3D* aPlugin );
/// list of discovered plugins
std::list< KICAD_PLUGIN_LDR_3D* > m_Plugins;
/// mapping of extensions to available plugins
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* > m_ExtMap;
/// list of file filters
std::list< wxString > m_FileFilters;
};
#endif // PLUGIN_MANAGER_3D_H
-1
View File
@@ -1 +0,0 @@
add_subdirectory( sg )
-111
View File
@@ -1,111 +0,0 @@
include_directories(
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/3d-viewer
)
set( SG_FILES
sg_base.cpp
sg_node.cpp
sg_helpers.cpp
scenegraph.cpp
sg_appearance.cpp
sg_faceset.cpp
sg_shape.cpp
sg_colors.cpp
sg_coords.cpp
sg_normals.cpp
sg_index.cpp
sg_coordindex.cpp
ifsg_node.cpp
ifsg_transform.cpp
ifsg_appearance.cpp
ifsg_index.cpp
ifsg_coordindex.cpp
ifsg_colors.cpp
ifsg_coords.cpp
ifsg_faceset.cpp
ifsg_normals.cpp
ifsg_shape.cpp
ifsg_api.cpp
)
if( MINGW )
list( APPEND SG_FILES ${CMAKE_SOURCE_DIR}/common/streamwrapper.cpp )
endif( MINGW )
add_library( kicad_3dsg SHARED ${SG_FILES} )
if( APPLE )
# puts library into the main kicad.app bundle in build tree
set_target_properties( kicad_3dsg PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${OSX_BUNDLE_BUILD_LIB_DIR}"
INSTALL_NAME_DIR "${OSX_BUNDLE_BUILD_LIB_DIR}"
)
endif()
find_file( S3DSG_VERSION_FILE sg_version.h
PATHS ${CMAKE_SOURCE_DIR}/include/plugins/3dapi NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
if( NOT ${S3DSG_VERSION_FILE} STREQUAL "S3DSG_VERSION_FILE-NOTFOUND" )
# extract the "#define KICADSG_VERSION_*" lines
file( STRINGS ${S3DSG_VERSION_FILE} _version
REGEX "^[' ','\t']*#define[' ','\t']*KICADSG_VERSION_.*" )
foreach( SVAR ${_version} )
string( REGEX MATCH KICADSG_VERSION_[M,A,J,O,R,I,N,P,T,C,H,E,V]* _VARNAME ${SVAR} )
string( REGEX MATCH [0-9]+ _VALUE ${SVAR} )
if( NOT ${_VARNAME} STREQUAL "" )
if( NOT ${_VALUE} STREQUAL "" )
set( ${_VARNAME} ${_VALUE} )
else()
set( ${_VARNAME} 0 )
endif()
endif()
endforeach()
if( NOT KICADSG_VERSION_MAJOR AND NOT ${KICADSG_VERSION_MAJOR} STREQUAL "0" )
message( FATAL_ERROR "Cannot determine the S3DSG library version" )
endif()
#ensure that NOT SG_VERSION* will evaluate to '0'
if( NOT KICADSG_VERSION_MINOR )
set( KICADSG_VERSION_MINOR 0 )
endif()
if( NOT KICADSG_VERSION_PATCH )
set( KICADSG_VERSION_PATCH 0 )
endif()
set_target_properties( kicad_3dsg
PROPERTIES SOVERSION
${KICADSG_VERSION_MAJOR}.${KICADSG_VERSION_MINOR}.${KICADSG_VERSION_PATCH} )
message( STATUS "S3DSG version: ${KICADSG_VERSION_MAJOR}.${KICADSG_VERSION_MINOR}.${KICADSG_VERSION_PATCH}" )
else()
message( FATAL_ERROR "Cannot determine the S3DSG library version" )
endif()
unset( S3DSG_VERSION_FILE CACHE )
# Define a flag to expose the appropriate EXPORT macro at build time
target_compile_definitions( kicad_3dsg PRIVATE COMPILE_SGLIB )
target_link_libraries( kicad_3dsg ${wxWidgets_LIBRARIES} )
# Don't specify the ARCHIVE DESTINATION parameter to prevent
# the install of the import library on Windows
# https://cmake.org/pipermail/cmake/2011-November/047746.html
install( TARGETS
kicad_3dsg
RUNTIME DESTINATION ${KICAD_LIB}
LIBRARY DESTINATION ${KICAD_LIB}
COMPONENT binary
)
if( KICAD_WIN32_INSTALL_PDBS )
# Get the PDBs to copy over for MSVC
install(FILES $<TARGET_PDB_FILE:kicad_3dsg> DESTINATION ${KICAD_BIN})
endif()
-527
View File
@@ -1,527 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <fstream>
#include <memory>
#include <wx/filename.h>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_api.h"
#include "plugins/3dapi/sg_version.h"
#include "streamwrapper.h"
#include "3d_cache/sg/sg_node.h"
#include "3d_cache/sg/scenegraph.h"
#include "3d_cache/sg/sg_appearance.h"
#include "3d_cache/sg/sg_shape.h"
#include "3d_cache/sg/sg_helpers.h"
// version format of the cache file
#define SG_VERSION_TAG "VERSION:2"
static void formatMaterial( SMATERIAL& mat, SGAPPEARANCE const* app )
{
float v0, v1, v2;
app->ambient.GetColor( v0, v1, v2 );
mat.m_Ambient.x = v0;
mat.m_Ambient.y = v1;
mat.m_Ambient.z = v2;
app->diffuse.GetColor( v0, v1, v2 );
mat.m_Diffuse.x = v0;
mat.m_Diffuse.y = v1;
mat.m_Diffuse.z = v2;
mat.m_Ambient.x *= v0;
mat.m_Ambient.y *= v1;
mat.m_Ambient.z *= v2;
app->emissive.GetColor( v0, v1, v2 );
mat.m_Emissive.x = v0;
mat.m_Emissive.y = v1;
mat.m_Emissive.z = v2;
app->specular.GetColor( v0, v1, v2 );
mat.m_Specular.x = v0;
mat.m_Specular.y = v1;
mat.m_Specular.z = v2;
mat.m_Shininess = app->shininess;
mat.m_Transparency = app->transparency;
}
bool S3D::WriteVRML( const char* filename, bool overwrite, SGNODE* aTopNode,
bool reuse, bool renameNodes )
{
if( nullptr == filename || filename[0] == 0 )
return false;
wxString ofile = wxString::FromUTF8Unchecked( filename );
if( wxFileName::Exists( ofile ) )
{
if( !overwrite )
return false;
// make sure we make no attempt to write a directory
if( !wxFileName::FileExists( ofile ) )
return false;
}
wxCHECK( aTopNode && aTopNode->GetNodeType() == S3D::SGTYPE_TRANSFORM, false );
OPEN_OSTREAM( op, filename );
if( op.fail() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] failed to open file '%s'" ),
__FILE__, __FUNCTION__, __LINE__, filename );
return false;
}
op.imbue( std::locale::classic() );
op << "#VRML V2.0 utf8\n";
if( renameNodes )
{
aTopNode->ResetNodeIndex();
aTopNode->ReNameNodes();
}
aTopNode->WriteVRML( op, reuse );
if( !op.fail() )
{
CLOSE_STREAM( op );
return true;
}
CLOSE_STREAM( op );
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] problems encountered writing file '%s'" ),
__FILE__, __FUNCTION__, __LINE__, filename );
return false;
}
void S3D::ResetNodeIndex( SGNODE* aNode )
{
wxCHECK( aNode, /* void */ );
aNode->ResetNodeIndex();
}
void S3D::RenameNodes( SGNODE* aNode )
{
wxCHECK( aNode, /* void */ );
aNode->ReNameNodes();
}
void S3D::DestroyNode( SGNODE* aNode ) noexcept
{
wxCHECK( aNode, /* void */ );
delete aNode;
}
bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode,
const char* aPluginInfo )
{
if( nullptr == aFileName || aFileName[0] == 0 )
return false;
wxString ofile = wxString::FromUTF8Unchecked( aFileName );
wxCHECK( aNode, false );
if( wxFileName::Exists( ofile ) )
{
if( !overwrite )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] file exists not overwriting '%s'" ),
__FILE__, __FUNCTION__, __LINE__, aFileName );
return false;
}
// make sure we make no attempt to write a directory
if( !wxFileName::FileExists( aFileName ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] specified path is a directory '%s'" ),
__FILE__, __FUNCTION__, __LINE__, aFileName );
return false;
}
}
OPEN_OSTREAM( output, aFileName );
if( output.fail() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] failed to open file '%s'" ),
__FILE__, __FUNCTION__, __LINE__, aFileName );
return false;
}
output << "(" << SG_VERSION_TAG << ")";
if( nullptr != aPluginInfo && aPluginInfo[0] != 0 )
output << "(" << aPluginInfo << ")";
else
output << "(INTERNAL:0.0.0.0)";
bool rval = aNode->WriteCache( output, nullptr );
CLOSE_STREAM( output );
if( !rval )
{
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [INFO] problems encountered writing cache file '%s'" ),
__FILE__, __FUNCTION__, __LINE__, aFileName );
// delete the defective file
wxRemoveFile( ofile );
}
return rval;
}
SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
bool (*aTagCheck)( const char*, void* ) )
{
if( nullptr == aFileName || aFileName[0] == 0 )
return nullptr;
wxString ofile = wxString::FromUTF8Unchecked( aFileName );
if( !wxFileName::FileExists( aFileName ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] no such file '%s'" ),
__FILE__, __FUNCTION__, __LINE__, aFileName );
return nullptr;
}
std::unique_ptr<SGNODE> np = std::make_unique<SCENEGRAPH>( nullptr );
OPEN_ISTREAM( file, aFileName );
if( file.fail() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] failed to open file '%s'" ),
__FILE__, __FUNCTION__, __LINE__, aFileName );
return nullptr;
}
// from SG_VERSION_TAG 1, read the version tag; if it's not the expected tag
// then we fail to read the cache file
do
{
std::string name;
char schar;
file.get( schar );
if( '(' != schar )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; missing left parenthesis"
" at position '%d'" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<int>( file.tellg() ) );
CLOSE_STREAM( file );
return nullptr;
}
file.get( schar );
while( ')' != schar && file.good() )
{
name.push_back( schar );
file.get( schar );
}
if( name.compare( SG_VERSION_TAG ) )
{
CLOSE_STREAM( file );
return nullptr;
}
} while( 0 );
// from SG_VERSION_TAG 2, read the PluginInfo string and check that it matches
// version tag; if it's not the expected tag then we fail to read the file
do
{
std::string name;
char schar;
file.get( schar );
if( '(' != schar )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; missing left parenthesis"
" at position '%d'" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<int>( file.tellg() ) );
CLOSE_STREAM( file );
return nullptr;
}
file.get( schar );
while( ')' != schar && file.good() )
{
name.push_back( schar );
file.get( schar );
}
// check the plugin tag
if( nullptr != aTagCheck && nullptr != aPluginMgr
&& !aTagCheck( name.c_str(), aPluginMgr ) )
{
CLOSE_STREAM( file );
return nullptr;
}
} while( 0 );
bool rval = np->ReadCache( file, nullptr );
CLOSE_STREAM( file );
if( !rval )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] problems encountered reading cache file "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__,
aFileName );
return nullptr;
}
return np.release();
}
S3DMODEL* S3D::GetModel( SCENEGRAPH* aNode )
{
if( nullptr == aNode )
return nullptr;
if( aNode->GetNodeType() != S3D::SGTYPE_TRANSFORM )
return nullptr;
S3D::MATLIST materials;
std::vector< SMESH > meshes;
// the materials list shall have a default color; although the VRML
// default is an opaque black, the default used here shall be a median
// gray in hopes that it may help highlight faulty models; this color is
// also typical of MCAD applications. When a model has no associated
// material color it shall be assigned the index 0.
SGAPPEARANCE app( nullptr );
app.ambient = SGCOLOR( 0.6f, 0.6f, 0.6f );
app.diffuse = SGCOLOR( 0.6f, 0.6f, 0.6f );
app.specular = app.diffuse;
app.shininess = 0.05f;
app.transparency = 0.0f;
materials.matorder.push_back( &app );
materials.matmap.emplace( &app, 0 );
if( aNode->Prepare( nullptr, materials, meshes ) )
{
if( meshes.empty() )
return nullptr;
S3DMODEL* model = S3D::New3DModel();
// add all the materials
size_t j = materials.matorder.size();
SMATERIAL* lmat = new SMATERIAL[j];
for( size_t i = 0; i < j; ++i )
formatMaterial( lmat[i], materials.matorder[i] );
model->m_Materials = lmat;
model->m_MaterialsSize = j;
// add all the meshes
j = meshes.size();
SMESH* lmesh = new SMESH[j];
for( size_t i = 0; i < j; ++i )
lmesh[i] = meshes[i];
model->m_Meshes = lmesh;
model->m_MeshesSize = j;
return model;
}
size_t j = meshes.size();
for( size_t i = 0; i < j; ++i )
S3D::Free3DMesh( meshes[i] );
return nullptr;
}
void S3D::Destroy3DModel( S3DMODEL** aModel )
{
if( nullptr == aModel || nullptr == *aModel )
return;
S3DMODEL* m = *aModel;
S3D::FREE_S3DMODEL( *m );
delete m;
*aModel = nullptr;
}
void Free3DModel( S3DMODEL& aModel )
{
S3D::FREE_S3DMODEL( aModel );
}
void S3D::Free3DMesh( SMESH& aMesh )
{
S3D::FREE_SMESH( aMesh );
}
S3DMODEL* S3D::New3DModel( void )
{
S3DMODEL* mp = new S3DMODEL;
S3D::INIT_S3DMODEL( *mp );
return mp;
}
void S3D::Init3DMaterial( SMATERIAL& aMat )
{
S3D::INIT_SMATERIAL( aMat );
}
void S3D::Init3DMesh( SMESH& aMesh )
{
S3D::INIT_SMESH( aMesh );
}
void S3D::GetLibVersion( unsigned char* Major, unsigned char* Minor, unsigned char* Patch,
unsigned char* Revision ) noexcept
{
if( Major )
*Major = KICADSG_VERSION_MAJOR;
if( Minor )
*Minor = KICADSG_VERSION_MINOR;
if( Revision )
*Revision = KICADSG_VERSION_REVISION;
if( Patch )
*Patch = KICADSG_VERSION_PATCH;
}
SGVECTOR S3D::CalcTriNorm( const SGPOINT& p1, const SGPOINT& p2, const SGPOINT& p3 )
{
glm::dvec3 tri = glm::dvec3( 0.0, 0.0, 0.0 );
glm::dvec3 pts[3];
pts[0] = glm::dvec3( p1.x, p1.y, p1.z );
pts[1] = glm::dvec3( p2.x, p2.y, p2.z );
pts[2] = glm::dvec3( p3.x, p3.y, p3.z );
// degenerate points are given a default 0, 0, 1 normal
if( S3D::degenerate( pts ) )
return SGVECTOR( 0.0, 0.0, 1.0 );
// normal
tri = glm::cross( pts[1] - pts[0], pts[2] - pts[0] );
(void)glm::normalize( tri );
return SGVECTOR( tri.x, tri.y, tri.z );
}
S3D::SGTYPES S3D::GetSGNodeType( SGNODE* aNode )
{
if( nullptr == aNode )
return SGTYPE_END;
return aNode->GetNodeType();
}
SGNODE* S3D::GetSGNodeParent( SGNODE* aNode )
{
if( nullptr == aNode )
return nullptr;
return aNode->GetParent();
}
bool S3D::AddSGNodeRef( SGNODE* aParent, SGNODE* aChild )
{
if( nullptr == aParent || nullptr == aChild )
return false;
return aParent->AddRefNode( aChild );
}
bool S3D::AddSGNodeChild( SGNODE* aParent, SGNODE* aChild )
{
if( nullptr == aParent || nullptr == aChild )
return false;
return aParent->AddChildNode( aChild );
}
void S3D::AssociateSGNodeWrapper( SGNODE* aObject, SGNODE** aRefPtr )
{
if( nullptr == aObject || nullptr == aRefPtr || aObject != *aRefPtr )
return;
aObject->AssociateWrapper( aRefPtr );
}
-284
View File
@@ -1,284 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_appearance.h"
#include "3d_cache/sg/sg_appearance.h"
extern char BadParent[];
extern char WrongParent[];
IFSG_APPEARANCE::IFSG_APPEARANCE( bool create )
{
m_node = nullptr;
if( !create )
return ;
m_node = new SGAPPEARANCE( nullptr );
m_node->AssociateWrapper( &m_node );
}
IFSG_APPEARANCE::IFSG_APPEARANCE( SGNODE* aParent )
{
m_node = new SGAPPEARANCE( nullptr );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
IFSG_APPEARANCE::IFSG_APPEARANCE( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
#ifdef DEBUG
if( ! pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
}
#endif
m_node = new SGAPPEARANCE( nullptr );
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
bool IFSG_APPEARANCE::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
if( !aNode )
return false;
if( S3D::SGTYPE_APPEARANCE != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_APPEARANCE::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGAPPEARANCE( aParent );
if( aParent != m_node->GetParent() )
{
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGAPPEARANCE" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
delete m_node;
m_node = nullptr;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_APPEARANCE::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
return NewNode( np );
}
bool IFSG_APPEARANCE::SetEmissive( float aRVal, float aGVal, float aBVal )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRVal, aGVal, aBVal );
}
bool IFSG_APPEARANCE::SetEmissive( const SGCOLOR* aRGBColor )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRGBColor );
}
bool IFSG_APPEARANCE::SetEmissive( const SGCOLOR& aRGBColor )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRGBColor );
}
bool IFSG_APPEARANCE::SetDiffuse( float aRVal, float aGVal, float aBVal )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRVal, aGVal, aBVal );
}
bool IFSG_APPEARANCE::SetDiffuse( const SGCOLOR* aRGBColor )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRGBColor );
}
bool IFSG_APPEARANCE::SetDiffuse( const SGCOLOR& aRGBColor )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRGBColor );
}
bool IFSG_APPEARANCE::SetSpecular( float aRVal, float aGVal, float aBVal )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRVal, aGVal, aBVal );
}
bool IFSG_APPEARANCE::SetSpecular( const SGCOLOR* aRGBColor )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRGBColor );
}
bool IFSG_APPEARANCE::SetSpecular( const SGCOLOR& aRGBColor )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRGBColor );
}
bool IFSG_APPEARANCE::SetAmbient( float aRVal, float aGVal, float aBVal )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRVal, aGVal, aBVal );
}
bool IFSG_APPEARANCE::SetAmbient( const SGCOLOR* aRGBColor )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRGBColor );
}
bool IFSG_APPEARANCE::SetAmbient( const SGCOLOR& aRGBColor )
{
wxCHECK( m_node, false );
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRGBColor );
}
bool IFSG_APPEARANCE::SetShininess( float aShininess ) noexcept
{
wxCHECK( m_node, false );
if( aShininess < 0 || aShininess > 1.0 )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] shininess out of range [0..1]" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
( (SGAPPEARANCE*) m_node )->shininess = aShininess;
return true;
}
bool IFSG_APPEARANCE::SetTransparency( float aTransparency ) noexcept
{
wxCHECK( m_node, false );
if( aTransparency < 0 || aTransparency > 1.0 )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] transparency out of range [0..1]" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
( (SGAPPEARANCE*) m_node )->transparency = aTransparency;
return true;
}
-189
View File
@@ -1,189 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_colors.h"
#include "3d_cache/sg/sg_colors.h"
extern char BadParent[];
extern char WrongParent[];
IFSG_COLORS::IFSG_COLORS( bool create )
{
m_node = nullptr;
if( !create )
return;
m_node = new SGCOLORS( nullptr );
m_node->AssociateWrapper( &m_node );
}
IFSG_COLORS::IFSG_COLORS( SGNODE* aParent )
{
m_node = new SGCOLORS( nullptr );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d" ), __FILE__, __FUNCTION__, __LINE__ );
return;
}
m_node->AssociateWrapper( &m_node );
}
IFSG_COLORS::IFSG_COLORS( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
#ifdef DEBUG
// Braces needed due to dangling else warning from wxLogTrace macro
if( !pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
}
#endif
m_node = new SGCOLORS( nullptr );
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
bool IFSG_COLORS::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
if( !aNode )
return false;
if( S3D::SGTYPE_COLORS != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COLORS::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGCOLORS( aParent );
if( aParent != m_node->GetParent() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGCOLORS" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
delete m_node;
m_node = nullptr;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COLORS::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
return NewNode( np );
}
bool IFSG_COLORS::GetColorList( size_t& aListSize, SGCOLOR*& aColorList )
{
wxCHECK( m_node, false );
return ( (SGCOLORS*) m_node )->GetColorList( aListSize, aColorList );
}
bool IFSG_COLORS::SetColorList( size_t aListSize, const SGCOLOR* aColorList )
{
wxCHECK( m_node, false );
( (SGCOLORS*) m_node )->SetColorList( aListSize, aColorList );
return true;
}
bool IFSG_COLORS::AddColor( double aRedValue, double aGreenValue, double aBlueValue )
{
wxCHECK( m_node, false );
( (SGCOLORS*) m_node )->AddColor( aRedValue, aGreenValue, aBlueValue );
return true;
}
bool IFSG_COLORS::AddColor( const SGCOLOR& aColor )
{
wxCHECK( m_node, false );
( (SGCOLORS*) m_node )->AddColor( aColor );
return true;
}
-152
View File
@@ -1,152 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_coordindex.h"
#include "3d_cache/sg/sg_coordindex.h"
extern char BadParent[];
extern char WrongParent[];
IFSG_COORDINDEX::IFSG_COORDINDEX( bool create )
{
m_node = nullptr;
if( !create )
return;
m_node = new SGCOORDINDEX( nullptr );
m_node->AssociateWrapper( &m_node );
}
IFSG_COORDINDEX::IFSG_COORDINDEX( SGNODE* aParent )
{
m_node = new SGCOORDINDEX( nullptr );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
IFSG_COORDINDEX::IFSG_COORDINDEX( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
if( !pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
return;
}
m_node = new SGCOORDINDEX( nullptr );
if( !m_node->SetParent( pp ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
delete m_node;
m_node = nullptr;
return;
}
m_node->AssociateWrapper( &m_node );
}
bool IFSG_COORDINDEX::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
if( !aNode )
return false;
if( S3D::SGTYPE_COORDINDEX != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COORDINDEX::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGCOORDINDEX( aParent );
if( aParent != m_node->GetParent() )
{
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGCOORDINDEX" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
delete m_node;
m_node = nullptr;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COORDINDEX::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
return NewNode( np );
}
-189
View File
@@ -1,189 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_coords.h"
#include "3d_cache/sg/sg_coords.h"
extern char BadParent[];
extern char WrongParent[];
IFSG_COORDS::IFSG_COORDS( bool create )
{
m_node = nullptr;
if( !create )
return ;
m_node = new SGCOORDS( nullptr );
m_node->AssociateWrapper( &m_node );
}
IFSG_COORDS::IFSG_COORDS( SGNODE* aParent )
{
m_node = new SGCOORDS( nullptr );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
IFSG_COORDS::IFSG_COORDS( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
#ifdef DEBUG
if( !pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
}
#endif
m_node = new SGCOORDS( nullptr );
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
bool IFSG_COORDS::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
if( !aNode )
return false;
if( S3D::SGTYPE_COORDS != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COORDS::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGCOORDS( aParent );
if( aParent != m_node->GetParent() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGCOORDS" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
delete m_node;
m_node = nullptr;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COORDS::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
return NewNode( np );
}
bool IFSG_COORDS::GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList )
{
wxCHECK( m_node, false );
return ( (SGCOORDS*) m_node )->GetCoordsList( aListSize, aCoordsList );
}
bool IFSG_COORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
{
wxCHECK( m_node, false );
( (SGCOORDS*) m_node )->SetCoordsList( aListSize, aCoordsList );
return true;
}
bool IFSG_COORDS::AddCoord( double aXValue, double aYValue, double aZValue )
{
wxCHECK( m_node, false );
( (SGCOORDS*) m_node )->AddCoord( aXValue, aYValue, aZValue );
return true;
}
bool IFSG_COORDS::AddCoord( const SGPOINT& aPoint )
{
wxCHECK( m_node, false );
( (SGCOORDS*) m_node )->AddCoord( aPoint );
return true;
}
-161
View File
@@ -1,161 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_faceset.h"
#include "3d_cache/sg/sg_faceset.h"
extern char BadParent[];
extern char WrongParent[];
IFSG_FACESET::IFSG_FACESET( bool create )
{
m_node = nullptr;
if( !create )
return ;
m_node = new SGFACESET( nullptr );
m_node->AssociateWrapper( &m_node );
}
IFSG_FACESET::IFSG_FACESET( SGNODE* aParent )
{
m_node = new SGFACESET( nullptr );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
IFSG_FACESET::IFSG_FACESET( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
#ifdef DEBUG
if( ! pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
}
#endif
m_node = new SGFACESET( nullptr );
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
bool IFSG_FACESET::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
if( !aNode )
return false;
if( S3D::SGTYPE_FACESET != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_FACESET::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGFACESET( aParent );
if( aParent != m_node->GetParent() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGFACESET" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
delete m_node;
m_node = nullptr;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_FACESET::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
return NewNode( np );
}
bool IFSG_FACESET::CalcNormals( SGNODE** aPtr )
{
if( m_node )
return ( (SGFACESET*) m_node )->CalcNormals( aPtr );
return false;
}
-64
View File
@@ -1,64 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_index.h"
#include "3d_cache/sg/sg_coordindex.h"
IFSG_INDEX::IFSG_INDEX() : IFSG_NODE()
{
}
bool IFSG_INDEX::GetIndices( size_t& nIndices, int*& aIndexList )
{
wxCHECK( m_node, false );
return ( (SGINDEX*) m_node )->GetIndices( nIndices, aIndexList );
}
bool IFSG_INDEX::SetIndices( size_t nIndices, int* aIndexList )
{
wxCHECK( m_node, false );
( (SGINDEX*) m_node )->SetIndices( nIndices, aIndexList );
return true;
}
bool IFSG_INDEX::AddIndex( int aIndex )
{
wxCHECK( m_node, false );
( (SGINDEX*) m_node )->AddIndex( aIndex );
return true;
}
-165
View File
@@ -1,165 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_node.h"
#include "3d_cache/sg/sg_node.h"
#include "plugins/3dapi/ifsg_api.h"
// collection of common error strings used by the wrappers
char BadObject[] = " * [BUG] operating on an invalid wrapper (object may have been deleted)";
char BadOperand[] = " * [BUG] parameter aNode is an invalid wrapper; its data may have been deleted";
char BadParent[] = " * [BUG] invalid parent node (data may have been deleted)";
char WrongParent[] = " * [BUG] parent node type is incompatible";
IFSG_NODE::IFSG_NODE()
{
m_node = nullptr;
}
IFSG_NODE::~IFSG_NODE()
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
}
void IFSG_NODE::Destroy( void )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
delete m_node;
m_node = nullptr;
}
SGNODE* IFSG_NODE::GetRawPtr( void ) noexcept
{
return m_node;
}
S3D::SGTYPES IFSG_NODE::GetNodeType( void ) const
{
wxCHECK( m_node, S3D::SGTYPE_END );
return m_node->GetNodeType();
}
SGNODE* IFSG_NODE::GetParent( void ) const
{
wxCHECK( m_node, nullptr );
return m_node->GetParent();
}
bool IFSG_NODE::SetParent( SGNODE* aParent )
{
wxCHECK( m_node, false );
return m_node->SetParent( aParent );
}
const char* IFSG_NODE::GetName( void )
{
wxCHECK( m_node, nullptr );
return m_node->GetName();
}
bool IFSG_NODE::SetName( const char* aName )
{
wxCHECK( m_node, false );
m_node->SetName( aName );
return true;
}
const char* IFSG_NODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const
{
wxCHECK( m_node, nullptr );
return m_node->GetNodeTypeName( aNodeType );
}
SGNODE* IFSG_NODE::FindNode( const char* aNodeName )
{
wxCHECK( m_node, nullptr );
return m_node->FindNode( aNodeName, nullptr );
}
bool IFSG_NODE::AddRefNode( SGNODE* aNode )
{
wxCHECK( m_node, false );
return m_node->AddRefNode( aNode );
}
bool IFSG_NODE::AddRefNode( IFSG_NODE& aNode )
{
wxCHECK( m_node, false );
SGNODE* np = aNode.GetRawPtr();
wxCHECK( np, false );
return m_node->AddRefNode( np );
}
bool IFSG_NODE::AddChildNode( SGNODE* aNode )
{
wxCHECK( m_node, false );
return m_node->AddChildNode( aNode );
}
bool IFSG_NODE::AddChildNode( IFSG_NODE& aNode )
{
wxCHECK( m_node, false );
SGNODE* np = aNode.GetRawPtr();
wxCHECK( np, false );
return m_node->AddChildNode( np );
}
-187
View File
@@ -1,187 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_normals.h"
#include "3d_cache/sg/sg_normals.h"
extern char BadParent[];
extern char WrongParent[];
IFSG_NORMALS::IFSG_NORMALS( bool create )
{
m_node = nullptr;
if( !create )
return;
m_node = new SGNORMALS( nullptr );
m_node->AssociateWrapper( &m_node );
}
IFSG_NORMALS::IFSG_NORMALS( SGNODE* aParent )
{
m_node = new SGNORMALS( nullptr );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
IFSG_NORMALS::IFSG_NORMALS( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
#ifdef DEBUG
if( ! pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
}
#endif
m_node = new SGNORMALS( nullptr );
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
bool IFSG_NORMALS::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
if( !aNode )
return false;
if( S3D::SGTYPE_NORMALS != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_NORMALS::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGNORMALS( aParent );
if( aParent != m_node->GetParent() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGNORMALS" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
delete m_node;
m_node = nullptr;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_NORMALS::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
return NewNode( np );
}
bool IFSG_NORMALS::GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList )
{
wxCHECK( m_node, false );
return ( (SGNORMALS*) m_node )->GetNormalList( aListSize, aNormalList );
}
bool IFSG_NORMALS::SetNormalList( size_t aListSize, const SGVECTOR* aNormalList )
{
wxCHECK( m_node, false );
( (SGNORMALS*) m_node )->SetNormalList( aListSize, aNormalList );
return true;
}
bool IFSG_NORMALS::AddNormal( double aXValue, double aYValue, double aZValue )
{
wxCHECK( m_node, false );
( (SGNORMALS*) m_node )->AddNormal( aXValue, aYValue, aZValue );
return true;
}
bool IFSG_NORMALS::AddNormal( const SGVECTOR& aNormal )
{
wxCHECK( m_node, false );
( (SGNORMALS*) m_node )->AddNormal( aNormal );
return true;
}
-152
View File
@@ -1,152 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_shape.h"
#include "3d_cache/sg/sg_shape.h"
extern char BadParent[];
extern char WrongParent[];
IFSG_SHAPE::IFSG_SHAPE( bool create )
{
m_node = nullptr;
if( !create )
return ;
m_node = new SGSHAPE( nullptr );
m_node->AssociateWrapper( &m_node );
}
IFSG_SHAPE::IFSG_SHAPE( SGNODE* aParent )
{
m_node = new SGSHAPE( nullptr );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
IFSG_SHAPE::IFSG_SHAPE( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
#ifdef DEBUG
if( !pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
}
#endif
m_node = new SGSHAPE( nullptr );
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
bool IFSG_SHAPE::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
if( !aNode )
return false;
if( S3D::SGTYPE_SHAPE != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_SHAPE::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGSHAPE( aParent );
if( aParent != m_node->GetParent() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGSHAPE" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
delete m_node;
m_node = nullptr;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_SHAPE::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
return NewNode( np );
}
-192
View File
@@ -1,192 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_transform.h"
#include "3d_cache/sg/scenegraph.h"
extern char WrongParent[];
IFSG_TRANSFORM::IFSG_TRANSFORM( bool create )
{
m_node = nullptr;
if( !create )
return;
m_node = new SCENEGRAPH( nullptr );
m_node->AssociateWrapper( &m_node );
}
IFSG_TRANSFORM::IFSG_TRANSFORM( SGNODE* aParent )
{
m_node = new SCENEGRAPH( nullptr );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
return;
}
m_node->AssociateWrapper( &m_node );
}
bool IFSG_TRANSFORM::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
if( !aNode )
return false;
if( S3D::SGTYPE_TRANSFORM != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_TRANSFORM::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SCENEGRAPH( aParent );
if( aParent != m_node->GetParent() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SCENEGRAPH" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
delete m_node;
m_node = nullptr;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_TRANSFORM::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
return NewNode( np );
}
bool IFSG_TRANSFORM::SetRotation( const SGVECTOR& aRotationAxis, double aAngle )
{
wxCHECK( m_node, false );
( (SCENEGRAPH*) m_node )->rotation_axis = aRotationAxis;
( (SCENEGRAPH*) m_node )->rotation_angle = aAngle;
return true;
}
bool IFSG_TRANSFORM::SetScale( const SGPOINT& aScale ) noexcept
{
wxCHECK( m_node, false );
( (SCENEGRAPH*) m_node )->scale = aScale;
return true;
}
bool IFSG_TRANSFORM::SetScale( double aScale )
{
wxCHECK( m_node, false );
if( aScale < 1e-8 && aScale > -1e-8 )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] |scale| is < 1e-8 - this seems strange" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
( (SCENEGRAPH*) m_node )->scale = SGPOINT( aScale, aScale, aScale );
return true;
}
bool IFSG_TRANSFORM::SetTranslation( const SGPOINT& aTranslation ) noexcept
{
wxCHECK( m_node, false );
( (SCENEGRAPH*) m_node )->translation = aTranslation;
return true;
}
bool IFSG_TRANSFORM::SetScaleOrientation( const SGVECTOR& aScaleAxis, double aAngle )
{
wxCHECK( m_node, false );
( (SCENEGRAPH*) m_node )->scale_axis = aScaleAxis;
( (SCENEGRAPH*) m_node )->scale_angle = aAngle;
return true;
}
bool IFSG_TRANSFORM::SetCenter( const SGPOINT& aCenter ) noexcept
{
wxCHECK( m_node, false );
( (SCENEGRAPH*) m_node )->center = aCenter;
return true;
}
-733
View File
@@ -1,733 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
#define GLM_FORCE_RADIANS
#include <iostream>
#include <sstream>
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <wx/log.h>
#include "3d_cache/sg/scenegraph.h"
#include "3d_cache/sg/sg_shape.h"
#include "3d_cache/sg/sg_helpers.h"
SCENEGRAPH::SCENEGRAPH( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_TRANSFORM;
rotation_angle = 0.0;
scale_angle = 0.0;
scale.x = 1.0;
scale.y = 1.0;
scale.z = 1.0;
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
{
m_Parent = nullptr;
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] inappropriate parent to SCENEGRAPH (type %d)" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeType() );
}
else if( nullptr != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
}
SCENEGRAPH::~SCENEGRAPH()
{
// drop references
DROP_REFS( SCENEGRAPH, m_RTransforms );
DROP_REFS( SGSHAPE, m_RShape );
// delete owned objects
DEL_OBJS( SCENEGRAPH, m_Transforms );
DEL_OBJS( SGSHAPE, m_Shape );
}
bool SCENEGRAPH::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
if( nullptr == aParent )
return true;
}
// only a transform may be parent to a transform
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SCENEGRAPH::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( !m_Name.compare( aNodeName ) )
return this;
FIND_NODE( SCENEGRAPH, aNodeName, m_Transforms, aCaller );
FIND_NODE( SGSHAPE, aNodeName, m_Shape, aCaller );
// query the parent if appropriate
if( aCaller == m_Parent || nullptr == m_Parent )
return nullptr;
return m_Parent->FindNode( aNodeName, this );
}
void SCENEGRAPH::unlinkNode( const SGNODE* aNode, bool isChild )
{
if( nullptr == aNode )
return;
switch( aNode->GetNodeType() )
{
case S3D::SGTYPE_TRANSFORM:
UNLINK_NODE( S3D::SGTYPE_TRANSFORM, SCENEGRAPH, aNode, m_Transforms, m_RTransforms,
isChild );
break;
case S3D::SGTYPE_SHAPE:
UNLINK_NODE( S3D::SGTYPE_SHAPE, SGSHAPE, aNode, m_Shape, m_RShape, isChild );
break;
default:
break;
}
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
__FILE__, __FUNCTION__, __LINE__ );
}
void SCENEGRAPH::unlinkChildNode( const SGNODE* aNode )
{
unlinkNode( aNode, true );
return;
}
void SCENEGRAPH::unlinkRefNode( const SGNODE* aNode )
{
unlinkNode( aNode, false );
return;
}
bool SCENEGRAPH::addNode( SGNODE* aNode, bool isChild )
{
wxCHECK( aNode, false );
ADD_NODE( S3D::SGTYPE_TRANSFORM, SCENEGRAPH, aNode, m_Transforms, m_RTransforms, isChild );
ADD_NODE( S3D::SGTYPE_SHAPE, SGSHAPE, aNode, m_Shape, m_RShape, isChild );
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] object '%s' is not a valid type for this object (%d)" ),
__FILE__, __FUNCTION__, __LINE__,
aNode->GetName(),
aNode->GetNodeType() );
return false;
}
bool SCENEGRAPH::AddRefNode( SGNODE* aNode )
{
return addNode( aNode, false );
}
bool SCENEGRAPH::AddChildNode( SGNODE* aNode )
{
return addNode( aNode, true );
}
void SCENEGRAPH::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
// rename all shapes
do
{
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
while( sL != eL )
{
(*sL)->ReNameNodes();
++sL;
}
} while( 0 );
// rename all transforms
do
{
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
while( sL != eL )
{
(*sL)->ReNameNodes();
++sL;
}
} while( 0 );
}
bool SCENEGRAPH::WriteVRML( std::ostream& aFile, bool aReuseFlag )
{
if( m_Transforms.empty() && m_RTransforms.empty() && m_Shape.empty() && m_RShape.empty() )
{
return false;
}
std::string tmp;
if( aReuseFlag )
{
if( !m_written )
{
aFile << "DEF " << GetName() << " Transform {\n";
m_written = true;
}
else
{
aFile << "USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << " Transform {\n";
}
// convert center to 1VRML unit = 0.1 inch
SGPOINT pt = center;
pt.x /= 2.54;
pt.y /= 2.54;
pt.z /= 2.54;
S3D::FormatPoint( tmp, pt );
aFile << " center " << tmp << "\n";
S3D::FormatOrientation( tmp, rotation_axis, rotation_angle );
aFile << " rotation " << tmp << "\n";
S3D::FormatPoint( tmp, scale );
aFile << " scale " << tmp << "\n";
S3D::FormatOrientation( tmp, scale_axis, scale_angle );
aFile << " scaleOrientation " << tmp << "\n";
// convert translation to 1VRML unit = 0.1 inch
pt = translation;
pt.x /= 2.54;
pt.y /= 2.54;
pt.z /= 2.54;
S3D::FormatPoint( tmp, pt );
aFile << " translation " << tmp << "\n";
aFile << " children [\n";
if( !m_Transforms.empty() )
{
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
while( sL != eL )
{
(*sL)->WriteVRML( aFile, aReuseFlag );
++sL;
}
}
if( !m_RTransforms.empty() )
{
std::vector< SCENEGRAPH* >::iterator sL = m_RTransforms.begin();
std::vector< SCENEGRAPH* >::iterator eL = m_RTransforms.end();
while( sL != eL )
{
(*sL)->WriteVRML( aFile, aReuseFlag );
++sL;
}
}
if( !m_Shape.empty() )
{
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
while( sL != eL )
{
(*sL)->WriteVRML( aFile, aReuseFlag );
++sL;
}
}
if( !m_RShape.empty() )
{
std::vector< SGSHAPE* >::iterator sL = m_RShape.begin();
std::vector< SGSHAPE* >::iterator eL = m_RShape.end();
while( sL != eL )
{
(*sL)->WriteVRML( aFile, aReuseFlag );
++sL;
}
}
aFile << "] }\n";
return true;
}
bool SCENEGRAPH::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode && nullptr != m_Parent )
{
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
{
m_written = true;
return true;
}
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( nullptr == m_Parent )
{
// ensure unique node names
ResetNodeIndex();
ReNameNodes();
}
if( aFile.fail() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
aFile << "[" << GetName() << "]";
S3D::WritePoint( aFile, center );
S3D::WritePoint( aFile, translation );
S3D::WriteVector( aFile, rotation_axis );
aFile.write( (char*)&rotation_angle, sizeof( rotation_angle ) );
S3D::WritePoint( aFile, scale );
S3D::WriteVector( aFile, scale_axis );
aFile.write( (char*)&scale_angle, sizeof( scale_angle ) );
// Transfer ownership of any Transform references which hadn't been written
size_t asize = m_RTransforms.size();
size_t i;
for( i = 0; i < asize; ++i )
{
if( !m_RTransforms[i]->isWritten() )
{
m_RTransforms[i]->SwapParent( this );
--asize;
--i;
}
}
// Transfer ownership of any Shape references which hadn't been written
asize = m_RShape.size();
for( i = 0; i < asize; ++i )
{
if( !m_RShape[i]->isWritten() )
{
m_RShape[i]->SwapParent( this );
--asize;
--i;
}
}
asize = m_Transforms.size();
aFile.write( (char*)&asize, sizeof( size_t ) );
asize = m_RTransforms.size();
aFile.write( (char*)&asize, sizeof( size_t ) );
asize = m_Shape.size();
aFile.write( (char*)&asize, sizeof( size_t ) );
asize = m_RShape.size();
aFile.write( (char*)&asize, sizeof( size_t ) );
asize = m_Transforms.size();
// write child transforms
for( i = 0; i < asize; ++i )
{
if( !m_Transforms[i]->WriteCache( aFile, this ) )
{
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [INFO] bad stream while writing child transforms" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
}
// write referenced transform names
asize = m_RTransforms.size();
for( i = 0; i < asize; ++i )
aFile << "[" << m_RTransforms[i]->GetName() << "]";
// write child shapes
asize = m_Shape.size();
for( i = 0; i < asize; ++i )
{
if( !m_Shape[i]->WriteCache( aFile, this ) )
{
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [INFO] bad stream while writing child shapes" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
}
// write referenced transform names
asize = m_RShape.size();
for( i = 0; i < asize; ++i )
aFile << "[" << m_RShape[i]->GetName() << "]";
if( aFile.fail() )
return false;
m_written = true;
return true;
}
bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( m_Transforms.empty() && m_RTransforms.empty() && m_Shape.empty() && m_RShape.empty(),
false );
std::string name; // name of the node
if( nullptr == parentNode )
{
// we need to read the tag and verify its type
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; tag mismatch at position "
"%ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
m_Name = name;
}
// read fixed member data
S3D::ReadPoint( aFile, center );
S3D::ReadPoint( aFile, translation );
S3D::ReadVector( aFile, rotation_axis );
aFile.read( (char*)&rotation_angle, sizeof( rotation_angle ) );
S3D::ReadPoint( aFile, scale );
S3D::ReadVector( aFile, scale_axis );
aFile.read( (char*)&scale_angle, sizeof( scale_angle ) );
size_t sizeCT = 0; // child transforms
size_t sizeRT = 0; // referenced transforms
size_t sizeCS = 0; // child shapes
size_t sizeRS = 0; // referenced shapes
aFile.read( (char*)&sizeCT, sizeof( size_t ) );
aFile.read( (char*)&sizeRT, sizeof( size_t ) );
aFile.read( (char*)&sizeCS, sizeof( size_t ) );
aFile.read( (char*)&sizeRS, sizeof( size_t ) );
size_t i;
// read child transforms
for( i = 0; i < sizeCT; ++i )
{
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child transform tag "
"at position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
SCENEGRAPH* sp = new SCENEGRAPH( this );
sp->SetName( name.c_str() );
if( !sp->ReadCache( aFile, this ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading transform "
"%ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
}
// read referenced transforms
for( i = 0; i < sizeRT; ++i )
{
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref transform tag at "
"position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
SGNODE* sp = FindNode( name.c_str(), this );
if( !sp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref "
"transform at position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
if( S3D::SGTYPE_TRANSFORM != sp->GetNodeType() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not TRANSFORM "
"at position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
AddRefNode( sp );
}
// read child shapes
for( i = 0; i < sizeCS; ++i )
{
if( S3D::SGTYPE_SHAPE != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child shape tag at "
"position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
SGSHAPE* sp = new SGSHAPE( this );
sp->SetName( name.c_str() );
if( !sp->ReadCache( aFile, this ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; corrupt data while "
"reading shape at position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
}
// read referenced shapes
for( i = 0; i < sizeRS; ++i )
{
if( S3D::SGTYPE_SHAPE != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref shape tag at "
"position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
SGNODE* sp = FindNode( name.c_str(), this );
if( !sp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref shape "
"at position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
if( S3D::SGTYPE_SHAPE != sp->GetNodeType() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGSHAPE at "
"position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
AddRefNode( sp );
}
if( aFile.fail() )
return false;
return true;
}
bool SCENEGRAPH::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
std::vector< SMESH >& meshes )
{
// calculate the accumulated transform
double rX, rY, rZ;
// rotation
rotation_axis.GetVector( rX, rY, rZ );
glm::dmat4 rM = glm::rotate( glm::dmat4( 1.0 ), rotation_angle, glm::dvec3( rX, rY, rZ ) );
// translation
glm::dmat4 tM = glm::translate( glm::dmat4( 1.0 ), glm::dvec3( translation.x, translation.y,
translation.z ) );
// center
glm::dmat4 cM = glm::translate( glm::dmat4( 1.0 ), glm::dvec3( center.x, center.y, center.z ) );
glm::dmat4 ncM = glm::translate( glm::dmat4( 1.0 ), glm::dvec3( -center.x, -center.y,
-center.z ) );
// scale
glm::dmat4 sM = glm::scale( glm::dmat4( 1.0 ), glm::dvec3( scale.x, scale.y, scale.z ) );
// scaleOrientation
scale_axis.GetVector( rX, rY, rZ );
glm::dmat4 srM = glm::rotate( glm::dmat4( 1.0 ), scale_angle, glm::dvec3( rX, rY, rZ ) );
glm::dmat4 nsrM = glm::rotate( glm::dmat4( 1.0 ), -scale_angle, glm::dvec3( rX, rY, rZ ) );
// resultant point:
// P' = T x C x R x SR x S x -SR x -C x P
// resultant transform:
// tx0 = tM * cM * rM * srM * sM * nsrM * ncM
glm::dmat4 tx0;
if( nullptr != aTransform )
tx0 = (*aTransform) * tM * cM * rM * srM * sM * nsrM * ncM;
else
tx0 = tM * cM * rM * srM * sM * nsrM * ncM;
bool ok = true;
// prepare all shapes
do
{
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
while( sL != eL && ok )
{
ok = (*sL)->Prepare( &tx0, materials, meshes );
++sL;
}
sL = m_RShape.begin();
eL = m_RShape.end();
while( sL != eL && ok )
{
ok = (*sL)->Prepare( &tx0, materials, meshes );
++sL;
}
} while( 0 );
// prepare all transforms
do
{
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
while( sL != eL && ok )
{
ok = (*sL)->Prepare( &tx0, materials, meshes );
++sL;
}
sL = m_RTransforms.begin();
eL = m_RTransforms.end();
while( sL != eL && ok )
{
ok = (*sL)->Prepare( &tx0, materials, meshes );
++sL;
}
} while( 0 );
return ok;
}
-109
View File
@@ -1,109 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file scenegraph.h
*/
#ifndef SCENE_GRAPH_H
#define SCENE_GRAPH_H
#include <vector>
#include "3d_cache/sg/sg_node.h"
class SGSHAPE;
/**
* Define the basic data set required to represent a 3D model.
*
* This model must remain compatible with VRML2.0 in order to facilitate VRML export of
* scene graph data created by available 3D plugins.
*/
class SCENEGRAPH : public SGNODE
{
public:
void unlinkChildNode( const SGNODE* aNode ) override;
void unlinkRefNode( const SGNODE* aNode ) override;
SCENEGRAPH( SGNODE* aParent );
virtual ~SCENEGRAPH();
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) override;
bool AddRefNode( SGNODE* aNode ) override;
bool AddChildNode( SGNODE* aNode ) override;
void ReNameNodes( void ) override;
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
bool Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
std::vector< SMESH >& meshes );
private:
void unlinkNode( const SGNODE* aNode, bool isChild );
bool addNode( SGNODE* aNode, bool isChild );
public:
// note: order of transformation is Translate, Rotate, Offset
SGPOINT center;
SGPOINT translation;
SGVECTOR rotation_axis;
double rotation_angle; // radians
SGPOINT scale;
SGVECTOR scale_axis;
double scale_angle; // radians
private:
// The following are items which may be defined for reuse
// in a VRML output file. They do not necessarily correspond
// to the use of DEF within a VRML input file; it is the
// responsibility of the plugin to perform any necessary
// conversions to comply with the restrictions imposed by
// this scene graph structure
std::vector< SCENEGRAPH* > m_Transforms; // local Transform nodes
std::vector< SGSHAPE* > m_Shape; // local Shape nodes
std::vector< SCENEGRAPH* > m_RTransforms; // referenced Transform nodes
std::vector< SGSHAPE* > m_RShape; // referenced Shape nodes
};
/*
p.120
Transform {
center 0 0 0
children []
rotation 0 0 1 0
scale 1 1 1
scaleOrientation 0 0 1 0
translation 0 0 0
bboxCenter 0 0 0
bboxSize -1 -1 -1
}
*/
#endif // SCENE_GRAPH_H
-363
View File
@@ -1,363 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <utility>
#include <sstream>
#include <wx/log.h>
#include "3d_cache/sg/sg_appearance.h"
#include "3d_cache/sg/sg_helpers.h"
SGAPPEARANCE::SGAPPEARANCE( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_APPEARANCE;
// defaults in accord with VRML2.0 spec
ambient.SetColor( 0.05317f, 0.17879f, 0.01804f );
shininess = 0.2f;
transparency = 0.0f;
diffuse.SetColor( 0.8f, 0.8f, 0.8f );
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
{
m_Parent = nullptr;
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGAPPEARANCE (type %s )" ),
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
}
else if( nullptr != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
}
SGAPPEARANCE::~SGAPPEARANCE()
{
}
bool SGAPPEARANCE::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
if( nullptr == aParent )
return true;
}
// only a SGSHAPE may be parent to a SGAPPEARANCE
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
bool SGAPPEARANCE::SetEmissive( float aRVal, float aGVal, float aBVal )
{
return emissive.SetColor( aRVal, aGVal, aBVal );
}
bool SGAPPEARANCE::SetEmissive( const SGCOLOR* aRGBColor )
{
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
return emissive.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetEmissive( const SGCOLOR& aRGBColor )
{
return emissive.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetDiffuse( float aRVal, float aGVal, float aBVal )
{
return diffuse.SetColor( aRVal, aGVal, aBVal );
}
bool SGAPPEARANCE::SetDiffuse( const SGCOLOR* aRGBColor )
{
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
return diffuse.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetDiffuse( const SGCOLOR& aRGBColor )
{
return diffuse.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetSpecular( float aRVal, float aGVal, float aBVal )
{
return specular.SetColor( aRVal, aGVal, aBVal );
}
bool SGAPPEARANCE::SetSpecular( const SGCOLOR* aRGBColor )
{
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
return specular.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetSpecular( const SGCOLOR& aRGBColor )
{
return specular.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetAmbient( float aRVal, float aGVal, float aBVal )
{
return ambient.SetColor( aRVal, aGVal, aBVal );
}
bool SGAPPEARANCE::SetAmbient( const SGCOLOR* aRGBColor )
{
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
return ambient.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetAmbient( const SGCOLOR& aRGBColor )
{
return ambient.SetColor( aRGBColor );
}
SGNODE* SGAPPEARANCE::FindNode( const char* aNodeName, const SGNODE* aCaller) noexcept
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( !m_Name.compare( aNodeName ) )
return this;
return nullptr;
}
void SGAPPEARANCE::unlinkChildNode( const SGNODE* aCaller ) noexcept
{
wxCHECK_MSG( aCaller, /* void */,
wxT( "unexpected code branch; node should have no children or refs" ) );
}
void SGAPPEARANCE::unlinkRefNode( const SGNODE* aCaller ) noexcept
{
wxCHECK_MSG( aCaller, /* void */,
wxT( "unexpected code branch; node should have no children or refs" ) );
}
bool SGAPPEARANCE::AddRefNode( SGNODE* aNode ) noexcept
{
wxCHECK_MSG( aNode, false, wxT( "this node does not accept children or refs" ) );
// This is redundant but it keeps gcc from generating a warning on debug builds.
return false;
}
bool SGAPPEARANCE::AddChildNode( SGNODE* aNode ) noexcept
{
wxCHECK_MSG( aNode, false, wxT( "this node does not accept children or refs" ) );
// This is redundant but it keeps gcc from generating a warning on debug builds.
return false;
}
void SGAPPEARANCE::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
}
bool SGAPPEARANCE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
{
if( aReuseFlag )
{
if( !m_written )
{
aFile << " appearance DEF " << GetName() << " Appearance {\n";
m_written = true;
}
else
{
aFile << " appearance USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << " appearance Appearance {\n";
}
aFile << " material Material {\n";
std::string tmp;
float ambr, ambg, ambb;
ambient.GetColor( ambr, ambg, ambb );
float amb = ( 0.212671 * ambr + 0.71516 * ambg + 0.072169 * ambb );
diffuse.GetColor( ambr, ambg, ambb );
float den = ( 0.212671 * ambr + 0.71516 * ambg + 0.072169 * ambb );
if( den < 0.004f )
den = 0.004f;
amb /= den;
if( amb > 1.0f )
amb = 1.0f;
S3D::FormatFloat( tmp, amb );
aFile << " ambientIntensity " << tmp << "\n";
float red, green, blue;
diffuse.GetColor( red, green, blue );
S3D::FormatFloat( tmp, red );
aFile << " diffuseColor " << tmp << " ";
S3D::FormatFloat( tmp, green );
aFile << tmp << " ";
S3D::FormatFloat( tmp, blue);
aFile << tmp << "\n";
emissive.GetColor( red, green, blue );
S3D::FormatFloat( tmp, red );
aFile << " emissiveColor " << tmp << " ";
S3D::FormatFloat( tmp, green );
aFile << tmp << " ";
S3D::FormatFloat( tmp, blue);
aFile << tmp << "\n";
S3D::FormatFloat( tmp, shininess );
aFile << " shininess " << tmp << "\n";
specular.GetColor( red, green, blue );
S3D::FormatFloat( tmp, red );
aFile << " specularColor " << tmp << " ";
S3D::FormatFloat( tmp, green );
aFile << tmp << " ";
S3D::FormatFloat( tmp, blue);
aFile << tmp << "\n";
S3D::FormatFloat( tmp, transparency );
aFile << " transparency " << tmp << "\n";
aFile << "} }\n";
return true;
}
bool SGAPPEARANCE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
{
wxCHECK_MSG( m_Parent, false, wxT( "corrupt data; m_aParent is NULL" ) );
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
{
m_written = true;
return true;
}
return false;
}
wxCHECK_MSG( parentNode == m_Parent, false, wxT( "corrupt data; parentNode != m_aParent" ) );
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
aFile << "[" << GetName() << "]";
S3D::WriteColor( aFile, ambient );
aFile.write( (char*) &shininess, sizeof( shininess ) );
aFile.write( (char*) &transparency, sizeof( transparency ) );
S3D::WriteColor( aFile, diffuse );
S3D::WriteColor( aFile, emissive );
S3D::WriteColor( aFile, specular );
if( aFile.fail() )
return false;
m_written = true;
return true;
}
bool SGAPPEARANCE::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
S3D::ReadColor( aFile, ambient );
aFile.read( (char*) &shininess, sizeof( shininess ) );
aFile.read( (char*) &transparency, sizeof( transparency ) );
S3D::ReadColor( aFile, diffuse );
S3D::ReadColor( aFile, emissive );
S3D::ReadColor( aFile, specular );
if( aFile.fail() )
return false;
return true;
}
-83
View File
@@ -1,83 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file sg_appearance.h
*/
#ifndef SG_APPEARANCE_H
#define SG_APPEARANCE_H
#include "3d_cache/sg/sg_node.h"
/**
* Defines the generic material appearance of a scenegraph object.
*/
class SGAPPEARANCE : public SGNODE
{
public:
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
SGAPPEARANCE( SGNODE* aParent );
virtual ~SGAPPEARANCE();
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
bool SetEmissive( float aRVal, float aGVal, float aBVal );
bool SetEmissive( const SGCOLOR* aRGBColor );
bool SetEmissive( const SGCOLOR& aRGBColor );
bool SetDiffuse( float aRVal, float aGVal, float aBVal );
bool SetDiffuse( const SGCOLOR* aRGBColor );
bool SetDiffuse( const SGCOLOR& aRGBColor );
bool SetSpecular( float aRVal, float aGVal, float aBVal );
bool SetSpecular( const SGCOLOR* aRGBColor );
bool SetSpecular( const SGCOLOR& aRGBColor );
bool SetAmbient( float aRVal, float aGVal, float aBVal );
bool SetAmbient( const SGCOLOR* aRGBColor );
bool SetAmbient( const SGCOLOR& aRGBColor );
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override;
bool AddRefNode( SGNODE* aNode ) noexcept override;
bool AddChildNode( SGNODE* aNode ) noexcept override;
void ReNameNodes( void ) override;
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
float shininess; // default 0.2
float transparency; // default 0.0
SGCOLOR ambient; // default 0.05317 0.17879 0.01804
SGCOLOR diffuse; // default 0.8 0.8 0.8
SGCOLOR emissive; // default 0.0 0.0 0.0
SGCOLOR specular; // default 0.0 0.0 0.0
};
#endif // SG_APPEARANCE_H
-276
View File
@@ -1,276 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <cmath>
#include <iostream>
#include <sstream>
#include <wx/log.h>
#include "plugins/3dapi/sg_base.h"
SGCOLOR::SGCOLOR()
{
red = 0.0;
green = 0.0;
blue = 0.0;
}
SGCOLOR::SGCOLOR( float aRVal, float aGVal, float aBVal )
{
if( !checkRange( aRVal, aGVal, aBVal ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid value passed to constructor" ),
__FILE__, __FUNCTION__, __LINE__ );
red = 0.0;
green = 0.0;
blue = 0.0;
return;
}
red = aRVal;
green = aGVal;
blue = aBVal;
}
void SGCOLOR::GetColor( float& aRedVal, float& aGreenVal, float& aBlueVal ) const noexcept
{
aRedVal = red;
aGreenVal = green;
aBlueVal = blue;
}
void SGCOLOR::GetColor( SGCOLOR& aColor ) const noexcept
{
aColor.red = red;
aColor.green = green;
aColor.blue = blue;
}
void SGCOLOR::GetColor( SGCOLOR* aColor ) const noexcept
{
wxCHECK_MSG( aColor, /* void */, wxT( "NULL pointer passed for aRGBColor" ) );
aColor->red = red;
aColor->green = green;
aColor->blue = blue;
}
bool SGCOLOR::SetColor( float aRedVal, float aGreenVal, float aBlueVal )
{
if( !checkRange( aRedVal, aGreenVal, aBlueVal ) )
return false;
red = aRedVal;
green = aGreenVal;
blue = aBlueVal;
return true;
}
bool SGCOLOR::SetColor( const SGCOLOR& aColor ) noexcept
{
red = aColor.red;
green = aColor.green;
blue = aColor.blue;
return true;
}
bool SGCOLOR::SetColor( const SGCOLOR* aColor ) noexcept
{
wxCHECK_MSG( aColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
red = aColor->red;
green = aColor->green;
blue = aColor->blue;
return true;
}
bool SGCOLOR::checkRange( float aRedVal, float aGreenVal, float aBlueVal ) const noexcept
{
bool ok = true;
if( aRedVal < 0.0 || aRedVal > 1.0 )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid RED value: %g" ),
__FILE__, __FUNCTION__, __LINE__, aRedVal );
ok = false;
}
if( aGreenVal < 0.0 || aGreenVal > 1.0 )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid GREEN value: %g" ),
__FILE__, __FUNCTION__, __LINE__, aGreenVal );
ok = false;
}
if( aBlueVal < 0.0 || aBlueVal > 1.0 )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid BLUE value: %g" ),
__FILE__, __FUNCTION__, __LINE__, aBlueVal );
ok = false;
}
return ok;
}
SGPOINT::SGPOINT()
{
x = 0.0;
y = 0.0;
z = 0.0;
}
SGPOINT::SGPOINT( double aXVal, double aYVal, double aZVal ) noexcept
{
x = aXVal;
y = aYVal;
z = aZVal;
}
void SGPOINT::GetPoint( const double& aXVal, const double& aYVal, const double& aZVal ) noexcept
{
x = aXVal;
y = aYVal;
z = aZVal;
}
void SGPOINT::GetPoint( const SGPOINT& aPoint ) noexcept
{
x = aPoint.x;
y = aPoint.y;
z = aPoint.z;
}
void SGPOINT::GetPoint( const SGPOINT* aPoint ) noexcept
{
wxCHECK_MSG( aPoint, /* void */, wxT( "NULL pointer passed for aPoint" ) );
x = aPoint->x;
y = aPoint->y;
z = aPoint->z;
}
void SGPOINT::SetPoint( double aXVal, double aYVal, double aZVal ) noexcept
{
x = aXVal;
y = aYVal;
z = aZVal;
}
void SGPOINT::SetPoint( const SGPOINT& aPoint ) noexcept
{
x = aPoint.x;
y = aPoint.y;
z = aPoint.z;
}
SGVECTOR::SGVECTOR()
{
vx = 0.0;
vy = 0.0;
vz = 1.0;
}
SGVECTOR::SGVECTOR( double aXVal, double aYVal, double aZVal )
{
vx = aXVal;
vy = aYVal;
vz = aZVal;
normalize();
}
void SGVECTOR::GetVector( double& aXVal, double& aYVal, double& aZVal ) const noexcept
{
aXVal = vx;
aYVal = vy;
aZVal = vz;
}
void SGVECTOR::SetVector( double aXVal, double aYVal, double aZVal )
{
vx = aXVal;
vy = aYVal;
vz = aZVal;
normalize();
}
void SGVECTOR::SetVector( const SGVECTOR& aVector )
{
aVector.GetVector( vx, vy, vz );
}
void SGVECTOR::normalize( void ) noexcept
{
double dx = vx * vx;
double dy = vy * vy;
double dz = vz * vz;
double dv2 = sqrt( dx + dy + dz );
if( ( dx + dy + dz ) < 1e-8 )
{
// use the default; the numbers are too small to be believable
vx = 0.0;
vy = 0.0;
vz = 1.0;
return;
}
vx /= dv2;
vy /= dv2;
vz /= dv2;
}
SGVECTOR& SGVECTOR::operator=( const SGVECTOR& source ) noexcept
{
vx = source.vx;
vy = source.vy;
vz = source.vz;
return *this;
}
-304
View File
@@ -1,304 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "3d_cache/sg/sg_colors.h"
#include "3d_cache/sg/sg_helpers.h"
SGCOLORS::SGCOLORS( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_COLORS;
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = nullptr;
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGCOLORS (type %s)" ),
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
}
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
}
SGCOLORS::~SGCOLORS()
{
colors.clear();
}
bool SGCOLORS::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
if( nullptr == aParent )
return true;
}
// only a SGFACESET may be parent to a SGCOLORS
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SGCOLORS::FindNode(const char* aNodeName, const SGNODE *aCaller) noexcept
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( !m_Name.compare( aNodeName ) )
return this;
return nullptr;
}
void SGCOLORS::unlinkChildNode( const SGNODE* aCaller ) noexcept
{
wxCHECK( aCaller, /* void */ );
}
void SGCOLORS::unlinkRefNode( const SGNODE* aCaller ) noexcept
{
wxCHECK( aCaller, /* void */ );
}
bool SGCOLORS::AddRefNode( SGNODE* aNode ) noexcept
{
wxCHECK( aNode, false );
return false;
}
bool SGCOLORS::AddChildNode( SGNODE* aNode ) noexcept
{
wxCHECK( aNode, false );
return false;
}
bool SGCOLORS::GetColorList( size_t& aListSize, SGCOLOR*& aColorList )
{
if( colors.empty() )
{
aListSize = 0;
aColorList = nullptr;
return false;
}
aListSize = colors.size();
aColorList = &colors[0];
return true;
}
void SGCOLORS::SetColorList( size_t aListSize, const SGCOLOR* aColorList )
{
colors.clear();
if( 0 == aListSize || nullptr == aColorList )
return;
for( size_t i = 0; i < aListSize; ++i )
colors.push_back( aColorList[i] );
return;
}
void SGCOLORS::AddColor( double aRedValue, double aGreenValue, double aBlueValue )
{
colors.emplace_back( aRedValue, aGreenValue, aBlueValue );
return;
}
void SGCOLORS::AddColor( const SGCOLOR& aColor )
{
colors.push_back( aColor );
return;
}
void SGCOLORS::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
}
bool SGCOLORS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
{
if( colors.empty() )
return false;
if( aReuseFlag )
{
if( !m_written )
{
aFile << "color DEF " << GetName() << " Color { color [\n ";
m_written = true;
}
else
{
aFile << "color USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << "color Color { color [\n ";
}
std::string tmp;
size_t n = colors.size();
bool nline = false;
for( size_t i = 0; i < n; )
{
S3D::FormatColor( tmp, colors[i] );
float r,g,b;
colors[i].GetColor(r, g, b);
aFile << tmp ;
++i;
if( i < n )
{
aFile << ",";
if( nline )
{
aFile << "\n ";
nline = false;
}
else
{
nline = true;
}
}
}
aFile << "] }\n";
return true;
}
bool SGCOLORS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
{
wxCHECK( m_Parent, false );
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
{
m_written = true;
return true;
}
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
aFile << "[" << GetName() << "]";
size_t ncolors = colors.size();
aFile.write( (char*)&ncolors, sizeof(size_t) );
for( size_t i = 0; i < ncolors; ++i )
S3D::WriteColor( aFile, colors[i] );
if( aFile.fail() )
return false;
m_written = true;
return true;
}
bool SGCOLORS::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( colors.empty(), false );
size_t ncolors;
aFile.read( (char*) &ncolors, sizeof( size_t ) );
SGCOLOR tmp;
if( aFile.fail() )
return false;
for( size_t i = 0; i < ncolors; ++i )
{
if( !S3D::ReadColor( aFile, tmp ) || aFile.fail() )
return false;
colors.push_back( tmp );
}
return true;
}
-67
View File
@@ -1,67 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file sg_colors.h
*/
#ifndef SG_COLORS_H
#define SG_COLORS_H
#include <vector>
#include "3d_cache/sg/sg_node.h"
/**
* Define an RGB color set for a scenegraph object.
*/
class SGCOLORS : public SGNODE
{
public:
SGCOLORS( SGNODE* aParent );
virtual ~SGCOLORS();
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override;
bool AddRefNode( SGNODE* aNode ) noexcept override;
bool AddChildNode( SGNODE* aNode ) noexcept override;
bool GetColorList( size_t& aListSize, SGCOLOR*& aColorList );
void SetColorList( size_t aListSize, const SGCOLOR* aColorList );
void AddColor( double aRedValue, double aGreenValue, double aBlueValue );
void AddColor( const SGCOLOR& aColor );
void ReNameNodes( void ) override;
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
std::vector< SGCOLOR > colors;
};
#endif // SG_COLORS_H
-50
View File
@@ -1,50 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 "3d_cache/sg/sg_coordindex.h"
SGCOORDINDEX::SGCOORDINDEX( SGNODE* aParent ) : SGINDEX( aParent )
{
m_SGtype = S3D::SGTYPE_COORDINDEX;
if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
}
SGCOORDINDEX::~SGCOORDINDEX()
{
}
void SGCOORDINDEX::GatherCoordIndices( std::vector< int >& aIndexList )
{
if( index.empty() )
return;
aIndexList.insert( aIndexList.end(), index.begin(), index.end() );
}
-54
View File
@@ -1,54 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file sg_coordindex.h
*/
#ifndef SG_COORDINDEX_H
#define SG_COORDINDEX_H
#include "3d_cache/sg/sg_index.h"
/**
* An object to maintain a coordinate index list.
*
* Users must ensure that coordinate indices are specified as triplets (triangular faces)
* since no checking is performed. In instances where it is not possible to determine which
* side of the triangle is to be rendered (for example IGES entities) then the user must
* supply each triplet in both point orders.
*/
class SGCOORDINDEX : public SGINDEX
{
public:
SGCOORDINDEX( SGNODE* aParent );
virtual ~SGCOORDINDEX();
/**
* Add all coordinate indices to the given list in preparation for a normals calculation.
*/
void GatherCoordIndices( std::vector< int >& aIndexList );
};
#endif // SG_COORDINDEX_H
-363
View File
@@ -1,363 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "3d_cache/sg/sg_coords.h"
#include "3d_cache/sg/sg_helpers.h"
#include "3d_cache/sg/sg_normals.h"
#include "3d_cache/sg/sg_faceset.h"
SGCOORDS::SGCOORDS( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_COORDS;
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = nullptr;
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGCOORDS (type %s)" ),
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
}
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
}
SGCOORDS::~SGCOORDS()
{
coords.clear();
}
bool SGCOORDS::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
if( nullptr == aParent )
return true;
}
// only a SGFACESET may be parent to a SGCOORDS
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SGCOORDS::FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( !m_Name.compare( aNodeName ) )
return this;
return nullptr;
}
void SGCOORDS::unlinkChildNode( const SGNODE* aCaller ) noexcept
{
wxCHECK( aCaller, /* void */ );
}
void SGCOORDS::unlinkRefNode( const SGNODE* aCaller ) noexcept
{
wxCHECK( aCaller, /* void */ );
}
bool SGCOORDS::AddRefNode( SGNODE* aNode ) noexcept
{
wxCHECK( aNode, false );
return false;
}
bool SGCOORDS::AddChildNode( SGNODE* aNode ) noexcept
{
wxCHECK( aNode, false );
return false;
}
bool SGCOORDS::GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList )
{
if( coords.empty() )
{
aListSize = 0;
aCoordsList = nullptr;
return false;
}
aListSize = coords.size();
aCoordsList = &coords[0];
return true;
}
void SGCOORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
{
coords.clear();
if( 0 == aListSize || nullptr == aCoordsList )
return;
for( size_t i = 0; i < aListSize; ++i )
coords.push_back( aCoordsList[i] );
}
void SGCOORDS::AddCoord( double aXValue, double aYValue, double aZValue )
{
coords.emplace_back( aXValue, aYValue, aZValue );
}
void SGCOORDS::AddCoord( const SGPOINT& aPoint )
{
coords.push_back( aPoint );
}
void SGCOORDS::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
}
bool SGCOORDS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
{
if( coords.empty() )
return false;
if( aReuseFlag )
{
if( !m_written )
{
aFile << " coord DEF " << GetName() << " Coordinate { point [\n ";
m_written = true;
}
else
{
aFile << " coord USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << " coord Coordinate { point [\n ";
}
std::string tmp;
size_t n = coords.size();
bool nline = false;
SGPOINT pt;
for( size_t i = 0; i < n; )
{
// ensure VRML output has 1U = 0.1 inch as per legacy kicad expectations
pt = coords[i];
pt.x /= 2.54;
pt.y /= 2.54;
pt.z /= 2.54;
S3D::FormatPoint( tmp, pt );
aFile << tmp ;
++i;
if( i < n )
{
aFile << ",";
if( nline )
{
aFile << "\n ";
nline = false;
}
else
{
nline = true;
}
}
}
aFile << "] }\n";
return true;
}
bool SGCOORDS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
{
wxCHECK( m_Parent, false );
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
{
m_written = true;
return true;
}
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
aFile << "[" << GetName() << "]";
size_t npts = coords.size();
aFile.write( (char*)&npts, sizeof(size_t) );
for( size_t i = 0; i < npts; ++i )
S3D::WritePoint( aFile, coords[i] );
if( aFile.fail() )
return false;
m_written = true;
return true;
}
bool SGCOORDS::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( coords.empty(), false );
size_t npts;
aFile.read( (char*) &npts, sizeof( size_t ) );
SGPOINT tmp;
if( aFile.fail() )
return false;
for( size_t i = 0; i < npts; ++i )
{
if( !S3D::ReadPoint( aFile, tmp ) || aFile.fail() )
return false;
coords.push_back( tmp );
}
return true;
}
bool SGCOORDS::CalcNormals( SGFACESET* callingNode, SGNODE** aPtr )
{
if( aPtr )
*aPtr = nullptr;
if( nullptr == m_Parent || nullptr == callingNode )
return false;
// the parent and all references must have indices; collect all
// indices into one std::vector<>
std::vector< int > ilist;
SGNORMALS* np = nullptr;
if( callingNode == m_Parent )
{
((SGFACESET*)m_Parent)->GatherCoordIndices( ilist );
std::list< SGNODE* >::iterator sB = m_BackPointers.begin();
std::list< SGNODE* >::iterator eB = m_BackPointers.end();
while( sB != eB )
{
SGFACESET* fp = (SGFACESET*)(*sB);
fp->GatherCoordIndices( ilist );
++sB;
}
np = ( (SGFACESET*) m_Parent )->m_Normals;
if( !np )
np = new SGNORMALS( m_Parent );
}
else
{
callingNode->GatherCoordIndices( ilist );
np = callingNode->m_Normals;
if( !np )
np = new SGNORMALS( callingNode );
}
if( S3D::CalcTriangleNormals( coords, ilist, np->norms ) )
{
if( aPtr )
*aPtr = np;
return true;
}
delete np;
return false;
}
-75
View File
@@ -1,75 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file sg_coords.h
*/
#ifndef SG_COORDS_H
#define SG_COORDS_H
#include <vector>
#include "3d_cache/sg/sg_node.h"
class SGFACESET;
/**
* Define a vertex coordinate set for a scenegraph object.
*/
class SGCOORDS : public SGNODE
{
public:
SGCOORDS( SGNODE* aParent );
virtual ~SGCOORDS();
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override;
bool AddRefNode( SGNODE* aNode ) noexcept override;
bool AddChildNode( SGNODE* aNode ) noexcept override;
bool GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList );
void SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList );
void AddCoord( double aXValue, double aYValue, double aZValue );
void AddCoord( const SGPOINT& aPoint );
/**
* Calculate normals for this coordinate list and sets the normals list in the
* parent #SGFACESET.
*/
bool CalcNormals( SGFACESET* callingNode, SGNODE** aPtr = nullptr );
void ReNameNodes( void ) override;
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
std::vector< SGPOINT > coords;
};
#endif // SG_COORDS_H
-992
View File
@@ -1,992 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "3d_cache/sg/sg_faceset.h"
#include "3d_cache/sg/sg_colors.h"
#include "3d_cache/sg/sg_coords.h"
#include "3d_cache/sg/sg_normals.h"
#include "3d_cache/sg/sg_coordindex.h"
#include "3d_cache/sg/sg_helpers.h"
SGFACESET::SGFACESET( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_FACESET;
m_Colors = nullptr;
m_Coords = nullptr;
m_CoordIndices = nullptr;
m_Normals = nullptr;
m_RColors = nullptr;
m_RCoords = nullptr;
m_RNormals = nullptr;
valid = false;
validated = false;
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
{
m_Parent = nullptr;
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGFACESET (type %s)" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeType() );
}
else if( nullptr != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
}
SGFACESET::~SGFACESET()
{
// drop references
if( m_RColors )
{
m_RColors->delNodeRef( this );
m_RColors = nullptr;
}
if( m_RCoords )
{
m_RCoords->delNodeRef( this );
m_RCoords = nullptr;
}
if( m_RNormals )
{
m_RNormals->delNodeRef( this );
m_RNormals = nullptr;
}
// delete owned objects
if( m_Colors )
{
m_Colors->SetParent( nullptr, false );
delete m_Colors;
m_Colors = nullptr;
}
if( m_Coords )
{
m_Coords->SetParent( nullptr, false );
delete m_Coords;
m_Coords = nullptr;
}
if( m_Normals )
{
m_Normals->SetParent( nullptr, false );
delete m_Normals;
m_Normals = nullptr;
}
if( m_CoordIndices )
{
m_CoordIndices->SetParent( nullptr, false );
delete m_CoordIndices;
m_CoordIndices = nullptr;
}
}
bool SGFACESET::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
if( nullptr == aParent )
return true;
}
// only a SGSHAPE may be parent to a SGFACESET
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SGFACESET::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( !m_Name.compare( aNodeName ) )
return this;
SGNODE* np = nullptr;
if( m_Colors )
{
np = m_Colors->FindNode( aNodeName, this );
if( np )
return np;
}
if( m_Coords )
{
np = m_Coords->FindNode( aNodeName, this );
if( np )
return np;
}
if( m_CoordIndices )
{
np = m_CoordIndices->FindNode( aNodeName, this );
if( np )
return np;
}
if( m_Normals )
{
np = m_Normals->FindNode( aNodeName, this );
if( np )
return np;
}
// query the parent if appropriate
if( aCaller == m_Parent || nullptr == m_Parent )
return nullptr;
return m_Parent->FindNode( aNodeName, this );
}
void SGFACESET::unlinkNode( const SGNODE* aNode, bool isChild )
{
if( nullptr == aNode )
return;
valid = false;
validated = false;
if( isChild )
{
if( aNode == m_Colors )
{
m_Colors = nullptr;
return;
}
if( aNode == m_Coords )
{
m_Coords = nullptr;
return;
}
if( aNode == m_Normals )
{
m_Normals = nullptr;
return;
}
if( aNode == m_CoordIndices )
{
m_CoordIndices = nullptr;
return;
}
}
else
{
if( aNode == m_RColors )
{
delNodeRef( this );
m_RColors = nullptr;
return;
}
if( aNode == m_RCoords )
{
delNodeRef( this );
m_RCoords = nullptr;
return;
}
if( aNode == m_RNormals )
{
delNodeRef( this );
m_RNormals = nullptr;
return;
}
}
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
__FILE__, __FUNCTION__, __LINE__ );
}
void SGFACESET::unlinkChildNode( const SGNODE* aNode )
{
unlinkNode( aNode, true );
}
void SGFACESET::unlinkRefNode( const SGNODE* aNode )
{
unlinkNode( aNode, false );
}
bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
{
wxCHECK( aNode, false );
valid = false;
validated = false;
if( S3D::SGTYPE_COLORS == aNode->GetNodeType() )
{
if( m_Colors || m_RColors )
{
if( aNode != m_Colors && aNode != m_RColors )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
return true;
}
if( isChild )
{
m_Colors = (SGCOLORS*)aNode;
m_Colors->SetParent( this );
}
else
{
m_RColors = (SGCOLORS*)aNode;
m_RColors->addNodeRef( this );
}
return true;
}
if( S3D::SGTYPE_COORDS == aNode->GetNodeType() )
{
if( m_Coords || m_RCoords )
{
if( aNode != m_Coords && aNode != m_RCoords )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
return true;
}
if( isChild )
{
m_Coords = (SGCOORDS*)aNode;
m_Coords->SetParent( this );
}
else
{
m_RCoords = (SGCOORDS*)aNode;
m_RCoords->addNodeRef( this );
}
return true;
}
if( S3D::SGTYPE_NORMALS == aNode->GetNodeType() )
{
if( m_Normals || m_RNormals )
{
if( aNode != m_Normals && aNode != m_RNormals )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Normals nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
return true;
}
if( isChild )
{
m_Normals = (SGNORMALS*)aNode;
m_Normals->SetParent( this );
}
else
{
m_RNormals = (SGNORMALS*)aNode;
m_RNormals->addNodeRef( this );
}
return true;
}
if( S3D::SGTYPE_COORDINDEX == aNode->GetNodeType() )
{
if( m_CoordIndices )
{
if( aNode != m_CoordIndices )
{
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] assigning multiple CoordIndex nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
return true;
}
m_CoordIndices = (SGCOORDINDEX*)aNode;
m_CoordIndices->SetParent( this );
return true;
}
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] object type '%s' is not a valid type for "
"this object '%d'" ),
__FILE__, __FUNCTION__, __LINE__,
aNode->GetName(),
aNode->GetNodeType() );
return false;
}
bool SGFACESET::AddRefNode( SGNODE* aNode )
{
return addNode( aNode, false );
}
bool SGFACESET::AddChildNode( SGNODE* aNode )
{
return addNode( aNode, true );
}
void SGFACESET::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
// rename all Colors and Indices
if( m_Colors )
m_Colors->ReNameNodes();
// rename all Coordinates and Indices
if( m_Coords )
m_Coords->ReNameNodes();
if( m_CoordIndices )
m_CoordIndices->ReNameNodes();
// rename all Normals and Indices
if( m_Normals )
m_Normals->ReNameNodes();
}
bool SGFACESET::WriteVRML( std::ostream& aFile, bool aReuseFlag )
{
if( ( nullptr == m_Coords && nullptr == m_RCoords ) || ( nullptr == m_CoordIndices ) )
{
return false;
}
if( aReuseFlag )
{
if( !m_written )
{
aFile << " geometry DEF " << GetName() << " IndexedFaceSet {\n";
m_written = true;
}
else
{
aFile << "USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << " geometry IndexedFaceSet {\n";
}
if( m_Coords )
m_Coords->WriteVRML( aFile, aReuseFlag );
if( m_RCoords )
m_RCoords->WriteVRML( aFile, aReuseFlag );
if( m_CoordIndices )
m_CoordIndices->WriteVRML( aFile, aReuseFlag );
if( m_Normals || m_RNormals )
aFile << " normalPerVertex TRUE\n";
if( m_Normals )
m_Normals->WriteVRML( aFile, aReuseFlag );
if( m_RNormals )
m_RNormals->WriteVRML( aFile, aReuseFlag );
if( m_Colors )
m_Colors->WriteVRML( aFile, aReuseFlag );
if( m_RColors )
m_RColors->WriteVRML( aFile, aReuseFlag );
aFile << "}\n";
return true;
}
bool SGFACESET::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
{
wxCHECK( m_Parent, false );
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
{
m_written = true;
return true;
}
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
// check if any references are unwritten and swap parents if so
if( nullptr != m_RCoords && !m_RCoords->isWritten() )
m_RCoords->SwapParent( this );
if( nullptr != m_RNormals && !m_RNormals->isWritten() )
m_RNormals->SwapParent( this );
if( nullptr != m_RColors && !m_RColors->isWritten() )
m_RColors->SwapParent( this );
aFile << "[" << GetName() << "]";
#define NITEMS 7
bool items[NITEMS];
int i;
for( i = 0; i < NITEMS; ++i )
items[i] = 0;
i = 0;
if( nullptr != m_Coords )
items[i] = true;
++i;
if( nullptr != m_RCoords )
items[i] = true;
++i;
if( nullptr != m_CoordIndices )
items[i] = true;
++i;
if( nullptr != m_Normals )
items[i] = true;
++i;
if( nullptr != m_RNormals )
items[i] = true;
++i;
if( nullptr != m_Colors )
items[i] = true;
++i;
if( nullptr != m_RColors )
items[i] = true;
for( int jj = 0; jj < NITEMS; ++jj )
aFile.write( (char*) &items[jj], sizeof( bool ) );
if( items[0] )
m_Coords->WriteCache( aFile, this );
if( items[1] )
aFile << "[" << m_RCoords->GetName() << "]";
if( items[2] )
m_CoordIndices->WriteCache( aFile, this );
if( items[3] )
m_Normals->WriteCache( aFile, this );
if( items[4] )
aFile << "[" << m_RNormals->GetName() << "]";
if( items[5] )
m_Colors->WriteCache( aFile, this );
if( items[6] )
aFile << "[" << m_RColors->GetName() << "]";
if( aFile.fail() )
return false;
m_written = true;
return true;
}
bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
if( m_Coords || m_RCoords || m_CoordIndices || m_Colors || m_RColors || m_Normals
|| m_RNormals )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] non-empty node" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
#define NITEMS 7
bool items[NITEMS];
for( int i = 0; i < NITEMS; ++i )
aFile.read( (char*) &items[i], sizeof( bool ) );
if( ( items[0] && items[1] ) || ( items[3] && items[4] ) || ( items[5] && items[6] ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; multiple item definitions "
"at position %d" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<int>( aFile.tellg() ) );
return false;
}
std::string name;
if( items[0] )
{
if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child coords tag at "
"position %d" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<int>( aFile.tellg() ) );
return false;
}
m_Coords = new SGCOORDS( this );
m_Coords->SetName( name.c_str() );
if( !m_Coords->ReadCache( aFile, this ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; corrupt data while "
"reading coords '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
}
if( items[1] )
{
if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref coords tag at "
"position %d" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<int>( aFile.tellg() ) );
return false;
}
SGNODE* np = FindNode( name.c_str(), this );
if( !np )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; cannot find ref "
"coords '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
if( S3D::SGTYPE_COORDS != np->GetNodeType() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; type is not SGCOORDS "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
m_RCoords = (SGCOORDS*)np;
m_RCoords->addNodeRef( this );
}
if( items[2] )
{
if( S3D::SGTYPE_COORDINDEX != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad coord index tag at "
"position %d" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<int>( aFile.tellg() ) );
return false;
}
m_CoordIndices = new SGCOORDINDEX( this );
m_CoordIndices->SetName( name.c_str() );
if( !m_CoordIndices->ReadCache( aFile, this ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading coord "
"index '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
}
if( items[3] )
{
if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child normals tag "
"at position %d" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<int>( aFile.tellg() ) );
return false;
}
m_Normals = new SGNORMALS( this );
m_Normals->SetName( name.c_str() );
if( !m_Normals->ReadCache( aFile, this ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading normals "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
}
if( items[4] )
{
if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref normals tag at "
"position %d" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<int>( aFile.tellg() ) );
return false;
}
SGNODE* np = FindNode( name.c_str(), this );
if( !np )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt: cannot find ref normals "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
if( S3D::SGTYPE_NORMALS != np->GetNodeType() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt: type is not SGNORMALS '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
m_RNormals = (SGNORMALS*)np;
m_RNormals->addNodeRef( this );
}
if( items[5] )
{
if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child colors tag "
"at position %d" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<int>( aFile.tellg() ) );
return false;
}
m_Colors = new SGCOLORS( this );
m_Colors->SetName( name.c_str() );
if( !m_Colors->ReadCache( aFile, this ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading colors "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
}
if( items[6] )
{
if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref colors tag at "
"position %d" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<int>( aFile.tellg() ) );
return false;
}
SGNODE* np = FindNode( name.c_str(), this );
if( !np )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref colors "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
if( S3D::SGTYPE_COLORS != np->GetNodeType() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGCOLORS "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
m_RColors = (SGCOLORS*)np;
m_RColors->addNodeRef( this );
}
if( aFile.fail() )
return false;
return true;
}
bool SGFACESET::validate( void )
{
// verify the integrity of this object's data
if( validated )
return valid;
// ensure we have at least coordinates and their normals
if( ( nullptr == m_Coords && nullptr == m_RCoords )
|| ( nullptr == m_Normals && nullptr == m_RNormals )
|| ( nullptr == m_CoordIndices ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; no vertices, vertex indices, "
"or normals" ),
__FILE__, __FUNCTION__, __LINE__ );
validated = true;
valid = false;
return false;
}
// check that there are >3 vertices
SGCOORDS* coords = m_Coords;
if( nullptr == coords )
coords = m_RCoords;
size_t nCoords = 0;
SGPOINT* lCoords = nullptr;
coords->GetCoordsList( nCoords, lCoords );
if( nCoords < 3 )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; fewer than 3 vertices" ),
__FILE__, __FUNCTION__, __LINE__ );
validated = true;
valid = false;
return false;
}
// check that nVertices is divisible by 3 (facets are triangles)
size_t nCIdx = 0;
int* lCIdx = nullptr;
m_CoordIndices->GetIndices( nCIdx, lCIdx );
if( nCIdx < 3 || ( nCIdx % 3 > 0 ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; no vertex indices or not "
"multiple of 3" ),
__FILE__, __FUNCTION__, __LINE__ );
validated = true;
valid = false;
return false;
}
// check that vertex[n] >= 0 and < nVertices
for( size_t i = 0; i < nCIdx; ++i )
{
if( lCIdx[i] < 0 || lCIdx[i] >= (int)nCoords )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; vertex index out of "
"bounds" ),
__FILE__, __FUNCTION__, __LINE__ );
validated = true;
valid = false;
return false;
}
}
// check that there are as many normals as vertices
size_t nNorms = 0;
SGVECTOR* lNorms = nullptr;
SGNORMALS* pNorms = m_Normals;
if( nullptr == pNorms )
pNorms = m_RNormals;
pNorms->GetNormalList( nNorms, lNorms );
if( nNorms != nCoords )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; number of normals (%ul) does "
"not match number of vertices (%ul)" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( nNorms ),
static_cast<unsigned long>( nCoords ) );
validated = true;
valid = false;
return false;
}
// if there are colors then ensure there are as many colors as vertices
SGCOLORS* pColors = m_Colors;
if( nullptr == pColors )
pColors = m_RColors;
if( nullptr != pColors )
{
// we must have at least as many colors as vertices
size_t nColor = 0;
SGCOLOR* pColor = nullptr;
pColors->GetColorList( nColor, pColor );
}
validated = true;
valid = true;
return true;
}
void SGFACESET::GatherCoordIndices( std::vector< int >& aIndexList )
{
if( m_CoordIndices )
m_CoordIndices->GatherCoordIndices( aIndexList );
}
bool SGFACESET::CalcNormals( SGNODE** aPtr )
{
SGCOORDS* coords = m_Coords;
if( m_RCoords )
coords = m_RCoords;
if( nullptr == coords || coords->coords.empty() )
return false;
if( m_Normals && !m_Normals->norms.empty( ) )
return true;
if( m_RNormals && !m_RNormals->norms.empty( ) )
return true;
return coords->CalcNormals( this, aPtr );
}
-117
View File
@@ -1,117 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file sg_faceset.h
*/
#ifndef SG_FACESET_H
#define SG_FACESET_H
#include <vector>
#include "3d_cache/sg/sg_node.h"
class SGCOLORS;
class SGCOORDS;
class SGNORMALS;
class SGCOLORINDEX;
class SGCOORDINDEX;
/**
* Define an indexed face set for a scenegraph.
*/
class SGFACESET : public SGNODE
{
public:
SGFACESET( SGNODE* aParent );
virtual ~SGFACESET();
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
SGNODE* FindNode( const char* aNodeName, const SGNODE* aCaller ) override;
bool AddRefNode( SGNODE* aNode ) override;
bool AddChildNode( SGNODE* aNode ) override;
bool CalcNormals( SGNODE** aPtr );
void ReNameNodes( void ) override;
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
/**
* Add all internal coordinate indices to the given list in preparation for a normals
* calculation.
*/
void GatherCoordIndices( std::vector< int >& aIndexList );
void unlinkChildNode( const SGNODE* aNode ) override;
void unlinkRefNode( const SGNODE* aNode ) override;
// validate the data held by this face set
bool validate( void );
// owned objects
SGCOLORS* m_Colors;
SGCOORDS* m_Coords;
SGCOORDINDEX* m_CoordIndices;
SGNORMALS* m_Normals;
// referenced objects
SGCOLORS* m_RColors;
SGCOORDS* m_RCoords;
SGNORMALS* m_RNormals;
private:
bool valid;
bool validated;
void unlinkNode( const SGNODE* aNode, bool isChild );
bool addNode( SGNODE* aNode, bool isChild );
};
/*
p.88
IndexedFaceSet {
color NULL
coord NULL
normal NULL
texCoord NULL
ccw TRUE
colorIndex []
colorPerVertex TRUE
convex TRUE
coordIndex []
creaseAngle 0
normalIndex []
normalPerVertex TRUE
solid TRUE
texCoordIndex []
}
*/
#endif // SG_FACESET_H
-490
View File
@@ -1,490 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iomanip>
#include <iostream>
#include <map>
#include <sstream>
#include <utility>
#include <wx/log.h>
#include "3d_cache/sg/sg_helpers.h"
#include "3d_cache/sg/sg_node.h"
void S3D::FormatFloat( std::string& result, double value )
{
if( value < 1e-8 && value > -1e-8 )
{
result = "0";
return;
}
// note: many VRML implementations use float so we use the max.
// precision here of 8 digits.
std::ostringstream out;
out << std::setprecision( 8 ) << value;
result = out.str();
size_t p = result.find( '.' );
// trim trailing 0 if appropriate
if( std::string::npos == p )
return;
p = result.find_first_of( "eE" );
if( std::string::npos == p )
{
while( '0' == *( result.rbegin() ) )
result.erase( result.size() - 1 );
return;
}
if( '0' != result.at( p - 1 ) )
return;
// trim all 0 to the left of 'p'
std::string tmp = result.substr( p );
result = result.substr( 0, p );
while( '0' == *( result.rbegin() ) )
result.erase( result.size() - 1 );
result.append( tmp );
}
void S3D::FormatOrientation( std::string& result, const SGVECTOR& axis, double rotation )
{
double aX;
double aY;
double aZ;
axis.GetVector( aX, aY, aZ );
FormatFloat( result, aX );
std::string tmp;
FormatFloat( tmp, aY );
result.append( " " );
result.append( tmp );
FormatFloat( tmp, aZ );
result.append( " " );
result.append( tmp );
FormatFloat( tmp, rotation );
result.append( " " );
result.append( tmp );
}
void S3D::FormatPoint( std::string& result, const SGPOINT& point )
{
FormatFloat( result, point.x );
std::string tmp;
FormatFloat( tmp, point.y );
result.append( " " );
result.append( tmp );
FormatFloat( tmp, point.z );
result.append( " " );
result.append( tmp );
}
void S3D::FormatVector( std::string& result, const SGVECTOR& aVector )
{
double X, Y, Z;
aVector.GetVector( X, Y, Z );
FormatFloat( result, X );
std::string tmp;
FormatFloat( tmp, Y );
result.append( " " );
result.append( tmp );
FormatFloat( tmp, Z );
result.append( " " );
result.append( tmp );
}
void S3D::FormatColor( std::string& result, const SGCOLOR& aColor )
{
float R, G, B;
aColor.GetColor( R, G, B );
FormatFloat( result, R );
std::string tmp;
FormatFloat( tmp, G );
result.append( " " );
result.append( tmp );
FormatFloat( tmp, B );
result.append( " " );
result.append( tmp );
}
bool S3D::WritePoint( std::ostream& aFile, const SGPOINT& aPoint )
{
aFile.write( (char*) &aPoint.x, sizeof( aPoint.x ) );
aFile.write( (char*) &aPoint.y, sizeof( aPoint.y ) );
aFile.write( (char*) &aPoint.z, sizeof( aPoint.z ) );
if( aFile.fail() )
return false;
return true;
}
bool S3D::WriteVector( std::ostream& aFile, const SGVECTOR& aVector )
{
double x, y, z;
aVector.GetVector( x, y, z );
aFile.write( (char*) &x, sizeof( double ) );
aFile.write( (char*) &y, sizeof( double ) );
aFile.write( (char*) &z, sizeof( double ) );
if( aFile.fail() )
return false;
return true;
}
bool S3D::WriteColor( std::ostream& aFile, const SGCOLOR& aColor )
{
float r, g, b;
aColor.GetColor( r, g, b );
aFile.write( (char*) &r, sizeof( float ) );
aFile.write( (char*) &g, sizeof( float ) );
aFile.write( (char*) &b, sizeof( float ) );
if( aFile.fail() )
return false;
return true;
}
S3D::SGTYPES S3D::ReadTag( std::istream& aFile, std::string& aName )
{
char schar;
aFile.get( schar );
if( '[' != schar )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; missing left bracket at "
"position %d" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<int>( aFile.tellg() ) );
return S3D::SGTYPE_END;
}
std::string name;
aFile.get( schar );
while( ']' != schar && aFile.good() )
{
name.push_back( schar );
aFile.get( schar );
}
if( schar != ']' )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; could not find right "
"bracket" ),
__FILE__, __FUNCTION__, __LINE__ );
return S3D::SGTYPE_END;
}
aName = name;
size_t upos = name.find( '_' );
if( std::string::npos == upos )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; no underscore in name '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return S3D::SGTYPE_END;
}
name = name.substr( 0, upos );
S3D::SGTYPES types[S3D::SGTYPE_END] = {
SGTYPE_TRANSFORM,
SGTYPE_APPEARANCE,
SGTYPE_COLORS,
SGTYPE_COLORINDEX,
SGTYPE_FACESET,
SGTYPE_COORDS,
SGTYPE_COORDINDEX,
SGTYPE_NORMALS,
SGTYPE_SHAPE
};
for( int i = 0; i < S3D::SGTYPE_END; ++i )
{
if( !name.compare( S3D::GetNodeTypeName( types[i] ) ) )
return types[i];
}
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; no node type matching '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return S3D::SGTYPE_END;
}
bool S3D::ReadPoint( std::istream& aFile, SGPOINT& aPoint )
{
aFile.read( (char*) &aPoint.x, sizeof( aPoint.x ) );
aFile.read( (char*) &aPoint.y, sizeof( aPoint.y ) );
aFile.read( (char*) &aPoint.z, sizeof( aPoint.z ) );
if( aFile.fail() )
return false;
return true;
}
bool S3D::ReadVector( std::istream& aFile, SGVECTOR& aVector )
{
double x, y, z;
aFile.read( (char*) &x, sizeof( double ) );
aFile.read( (char*) &y, sizeof( double ) );
aFile.read( (char*) &z, sizeof( double ) );
aVector.SetVector( x, y, z );
if( aFile.fail() )
return false;
return true;
}
bool S3D::ReadColor( std::istream& aFile, SGCOLOR& aColor )
{
float r, g, b;
aFile.read( (char*) &r, sizeof( float ) );
aFile.read( (char*) &g, sizeof( float ) );
aFile.read( (char*) &b, sizeof( float ) );
aColor.SetColor( r, g, b );
if( aFile.fail() )
return false;
return true;
}
bool S3D::degenerate( glm::dvec3* pts ) noexcept
{
double dx, dy, dz;
dx = pts[1].x - pts[0].x;
dy = pts[1].y - pts[0].y;
dz = pts[1].z - pts[0].z;
if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
return true;
dx = pts[2].x - pts[0].x;
dy = pts[2].y - pts[0].y;
dz = pts[2].z - pts[0].z;
if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
return true;
dx = pts[2].x - pts[1].x;
dy = pts[2].y - pts[1].y;
dz = pts[2].z - pts[1].z;
if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
return true;
return false;
}
static void calcTriad( glm::dvec3* pts, glm::dvec3& tri )
{
if( S3D::degenerate( pts ) )
{
// degenerate points should contribute nothing to the result
tri = glm::dvec3( 0.0, 0.0, 0.0 );
return;
}
// normal * 2 * area
tri = glm::cross( pts[1] - pts[0], pts[2] - pts[0] );
}
bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >& index,
std::vector< SGVECTOR >& norms )
{
size_t vsize = coords.size();
if( vsize < 3 )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] invalid vertex set (fewer than 3 "
"vertices)" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
size_t isize = index.size();
if( 0 != isize % 3 || index.empty() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] invalid index set (not multiple of 3)" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
if( !norms.empty() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] normals set is not empty" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
std::map< int, std::list< glm::dvec3 > >vmap;
int p1, p2, p3;
// create the map of indices to facet sets
for( size_t i = 0; i < isize; )
{
p1 = index[i++];
p2 = index[i++];
p3 = index[i++];
if( p1 < 0 || p1 >= (int)vsize || p2 < 0 || p2 >= (int)vsize || p3 < 0 || p3 >= (int)vsize )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] invalid index set; index out of bounds";
wxLogTrace( MASK_3D_SG, wxT( "%s\n" ), ostr.str().c_str() );
#endif
return false;
}
glm::dvec3 tri;
glm::dvec3 trip[3];
trip[0] = glm::dvec3( coords[p1].x, coords[p1].y, coords[p1].z );
trip[1] = glm::dvec3( coords[p2].x, coords[p2].y, coords[p2].z );
trip[2] = glm::dvec3( coords[p3].x, coords[p3].y, coords[p3].z );
calcTriad( trip, tri );
std::map< int, std::list< glm::dvec3 > >::iterator ip = vmap.find( p1 );
if( ip != vmap.end() )
{
ip->second.push_back( tri );
}
else
{
vmap.emplace( p1, std::list < glm::dvec3 >( 1, tri ) );
}
ip = vmap.find( p2 );
if( ip != vmap.end() )
{
ip->second.push_back( tri );
}
else
{
vmap.emplace( p2, std::list < glm::dvec3 >( 1, tri ) );
}
ip = vmap.find( p3 );
if( ip != vmap.end() )
{
ip->second.push_back( tri );
}
else
{
vmap.emplace( p3, std::list < glm::dvec3 >( 1, tri ) );
}
}
std::map< int, std::list< glm::dvec3 > >::iterator sM = vmap.begin();
std::map< int, std::list< glm::dvec3 > >::iterator eM = vmap.end();
size_t idx = 0;
while( sM != eM )
{
size_t item = sM->first;
// assign any skipped coordinates a normal of (0,0,1)
while( item > idx )
{
norms.emplace_back( 0, 0, 1 );
++idx;
}
std::list< glm::dvec3 >::iterator sT = sM->second.begin();
std::list< glm::dvec3 >::iterator eT = sM->second.end();
glm::dvec3 norm( 0.0, 0.0, 0.0 );
while( sT != eT )
{
norm += *sT;
++sT;
}
norms.emplace_back( norm.x, norm.y, norm.z );
++idx;
++sM;
}
if( norms.size() != coords.size() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] number of normals does not equal number "
"of vertices" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
return true;
}
-273
View File
@@ -1,273 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file sg_helpers.h
*
* Define a number of macros to aid in repetitious code which is probably best expressed
* as a preprocessor macro rather than as a template. This header also declares a number
* of functions which are only of use within the sg_* classes.
*/
#ifndef SG_HELPERS_H
#define SG_HELPERS_H
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include "plugins/3dapi/sg_base.h"
#include "plugins/3dapi/sg_types.h"
#include <glm/glm.hpp>
class SGNORMALS;
class SGCOORDS;
class SGCOORDINDEX;
// Function to drop references within an SGNODE
// The node being destroyed must remove itself from the object reference's
// backpointer list in order to avoid a segfault.
#define DROP_REFS( aType, aList ) \
do \
{ \
std::vector<aType*>::iterator sL = aList.begin(); \
std::vector<aType*>::iterator eL = aList.end(); \
while( sL != eL ) \
{ \
( (SGNODE*) *sL )->delNodeRef( this ); \
++sL; \
} \
aList.clear(); \
} while( 0 )
// Function to delete owned objects within an SGNODE
// The owned object's parent is set to NULL before
// deletion to avoid a redundant 'unlinkChildNode' call.
#define DEL_OBJS( aType, aList ) \
do \
{ \
std::vector<aType*>::iterator sL = aList.begin(); \
std::vector<aType*>::iterator eL = aList.end(); \
while( sL != eL ) \
{ \
( (SGNODE*) *sL )->SetParent( nullptr, false ); \
delete *sL; \
++sL; \
} \
aList.clear(); \
} while( 0 )
// Function to unlink a child or reference node when that child or
// reference node is being destroyed.
#define UNLINK_NODE( aNodeID, aType, aNode, aOwnedList, aRefList, isChild ) \
do \
{ \
if( aNodeID == aNode->GetNodeType() ) \
{ \
std::vector<aType*>* oSL; \
std::vector<aType*>::iterator sL; \
std::vector<aType*>::iterator eL; \
if( isChild ) \
{ \
oSL = &aOwnedList; \
sL = oSL->begin(); \
eL = oSL->end(); \
while( sL != eL ) \
{ \
if( (SGNODE*) *sL == aNode ) \
{ \
oSL->erase( sL ); \
return; \
} \
++sL; \
} \
} \
else \
{ \
oSL = &aRefList; \
sL = oSL->begin(); \
eL = oSL->end(); \
while( sL != eL ) \
{ \
if( (SGNODE*) *sL == aNode ) \
{ \
delNodeRef( this ); \
oSL->erase( sL ); \
return; \
} \
++sL; \
} \
} \
return; \
} \
} while( 0 )
// Function to check a node type, check for an existing reference,
// and add the node type to the reference list if applicable
#define ADD_NODE( aNodeID, aType, aNode, aOwnedList, aRefList, isChild ) \
do \
{ \
if( aNodeID == aNode->GetNodeType() ) \
{ \
std::vector<aType*>::iterator sL; \
sL = std::find( aOwnedList.begin(), aOwnedList.end(), aNode ); \
if( sL != aOwnedList.end() ) \
return true; \
sL = std::find( aRefList.begin(), aRefList.end(), aNode ); \
if( sL != aRefList.end() ) \
return true; \
if( isChild ) \
{ \
SGNODE* ppn = (SGNODE*) aNode->GetParent(); \
if( nullptr != ppn ) \
{ \
if( this != ppn ) \
{ \
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; \
std::cerr << " * [BUG] object '" << aNode->GetName(); \
std::cerr << "' has multiple parents '" << ppn->GetName() << "', '"; \
std::cerr << m_Name << "'\n"; \
return false; \
} \
} \
aOwnedList.push_back( (aType*) aNode ); \
aNode->SetParent( this, false ); \
} \
else \
{ \
/*if( nullptr == aNode->GetParent() ) { \
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; \
std::cerr << " * [BUG] object '" << aNode->GetName(); \
std::cerr << "' has no parent\n"; \
std::cerr << " * [INFO] possible copy assignment or copy constructor bug\n"; \
return false; \
} */ \
aRefList.push_back( (aType*) aNode ); \
aNode->addNodeRef( this ); \
} \
return true; \
} \
} while( 0 )
// Function to find a node object given a (non-unique) node name
#define FIND_NODE( aType, aName, aNodeList, aCallingNode ) \
do \
{ \
std::vector<aType*>::iterator sLA = aNodeList.begin(); \
std::vector<aType*>::iterator eLA = aNodeList.end(); \
SGNODE* psg = nullptr; \
while( sLA != eLA ) \
{ \
if( (SGNODE*) *sLA != aCallingNode ) \
{ \
psg = (SGNODE*) ( *sLA )->FindNode( aName, this ); \
if( nullptr != psg ) \
return psg; \
} \
++sLA; \
} \
} while( 0 )
namespace S3D
{
bool degenerate( glm::dvec3* pts ) noexcept;
//
// Normals calculations from triangles
//
/*
* Take an array of 3D coordinates and its corresponding index set and calculates
* the normals assuming that indices are given in CCW order.
*
* Care must be taken in using this function to ensure that:
* -# All coordinates are indexed; unindexed coordinates are assigned normal(0,0,1);
* when dealing with VRML models which may list and reuse one large coordinate set it
* is necessary to gather all index sets and perform this operation only once.
* -# Index sets must represent triangles (multiple of 3 indices) and must not be
* degenerate, that is all indices and coordinates in a triad must be unique.
*
* @param coords is the array of 3D vertices.
* @param index is the array of 3x vertex indices (triads).
* @param norms is an empty array which holds the normals corresponding to each vector.
* @return true on success; otherwise false.
*/
bool CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >& index,
std::vector< SGVECTOR >& norms );
// formats a floating point number for text output to a VRML file
void FormatFloat( std::string& result, double value );
// format orientation data for VRML output
void FormatOrientation( std::string& result, const SGVECTOR& axis, double rotation );
// format point data for VRML output
void FormatPoint( std::string& result, const SGPOINT& point );
// format vector data for VRML output
void FormatVector( std::string& result, const SGVECTOR& aVector );
// format Color data for VRML output
void FormatColor( std::string& result, const SGCOLOR& aColor );
//
// Cache related WRITE functions
//
// write out an XYZ vertex
bool WritePoint( std::ostream& aFile, const SGPOINT& aPoint );
// write out a unit vector
bool WriteVector( std::ostream& aFile, const SGVECTOR& aVector );
// write out an RGB color
bool WriteColor( std::ostream& aFile, const SGCOLOR& aColor );
/**
* Read the text tag of a binary cache file which is the NodeTag and unique ID number combined.
*
* @param aFile is a binary file open for reading.
* @param aName will hold the tag name on successful return.
* @return will be the NodeType which the tag represents or S3D::SGTYPES::SGTYPE_END on
* failure.
*/
S3D::SGTYPES ReadTag( std::istream& aFile, std::string& aName );
// read an XYZ vertex
bool ReadPoint( std::istream& aFile, SGPOINT& aPoint );
// read a unit vector
bool ReadVector( std::istream& aFile, SGVECTOR& aVector );
// read an RGB color
bool ReadColor( std::istream& aFile, SGCOLOR& aColor );
}
#endif // SG_HELPERS_H
-329
View File
@@ -1,329 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "3d_cache/sg/sg_index.h"
SGINDEX::SGINDEX( SGNODE* aParent ) : SGNODE( aParent )
{
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGINDEX (type "
"'%d')" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeType() );
}
}
SGINDEX::~SGINDEX()
{
index.clear();
}
bool SGINDEX::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
if( nullptr == aParent )
return true;
}
// only a SGFACESET may be parent to a SGINDEX and derived types
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SGINDEX::FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( !m_Name.compare( aNodeName ) )
return this;
return nullptr;
}
void SGINDEX::unlinkChildNode( const SGNODE* aCaller ) noexcept
{
// Node should have no children or refs.
wxCHECK( false, /* void */ );
}
void SGINDEX::unlinkRefNode( const SGNODE* aCaller ) noexcept
{
// Node should have no children or refs.
wxCHECK( false, /* void */ );
}
bool SGINDEX::AddRefNode( SGNODE* aNode ) noexcept
{
// Node should have no children or refs.
wxCHECK( false, false );
return false;
}
bool SGINDEX::AddChildNode( SGNODE* aNode ) noexcept
{
// Node should have no children or refs.
wxCHECK( false, false );
return false;
}
bool SGINDEX::GetIndices( size_t& nIndices, int*& aIndexList )
{
if( index.empty() )
{
nIndices = 0;
aIndexList = nullptr;
return false;
}
nIndices = index.size();
aIndexList = & index[0];
return true;
}
void SGINDEX::SetIndices( size_t nIndices, int* aIndexList )
{
index.clear();
if( 0 == nIndices || nullptr == aIndexList )
return;
for( size_t i = 0; i < nIndices; ++i )
index.push_back( aIndexList[i] );
return;
}
void SGINDEX::AddIndex( int aIndex )
{
index.push_back( aIndex );
}
void SGINDEX::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
}
bool SGINDEX::WriteVRML( std::ostream& aFile, bool aReuseFlag )
{
if( index.empty() )
return false;
if( S3D::SGTYPE_COORDINDEX == m_SGtype )
return writeCoordIndex( aFile );
return writeColorIndex( aFile );
}
bool SGINDEX::writeCoordIndex( std::ostream& aFile )
{
size_t n = index.size();
wxCHECK_MSG( n % 3 == 0, false, wxT( "Coordinate index is not divisible by three (violates "
"triangle constraint)" ) );
aFile << " coordIndex [\n ";
// indices to control formatting
int nv0 = 0;
int nv1 = 0;
for( size_t i = 0; i < n; )
{
aFile << index[i];
++i;
if( ++nv0 == 3 )
{
aFile << ",-1";
++nv1;
nv0 = 0;
}
if( i < n )
{
aFile << ",";
if( nv1 == 8 )
{
nv1 = 0;
aFile << "\n ";
}
}
}
aFile << "]\n";
return true;
}
bool SGINDEX::writeColorIndex( std::ostream& aFile )
{
aFile << " colorIndex [\n ";
return writeIndexList( aFile );
}
bool SGINDEX::writeIndexList( std::ostream& aFile )
{
// index to control formatting
int nv = 0;
size_t n = index.size();
for( size_t i = 0; i < n; )
{
aFile << index[i];
++i;
if( i < n )
{
aFile << ",";
if( ++nv == 20 )
{
aFile << "\n ";
nv = 0;
}
}
}
aFile << "]\n";
return true;
}
bool SGINDEX::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
{
wxCHECK( m_Parent, false );
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
{
m_written = true;
return true;
}
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
aFile << "[" << GetName() << "]";
size_t npts = index.size();
aFile.write( (char*)&npts, sizeof(size_t) );
for( size_t i = 0; i < npts; ++i )
aFile.write( (char*)&index[i], sizeof(int) );
if( aFile.fail() )
return false;
m_written = true;
return true;
}
bool SGINDEX::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( index.empty(), false );
size_t npts;
aFile.read( (char*)&npts, sizeof(size_t) );
int tmp;
if( aFile.fail() )
return false;
for( size_t i = 0; i < npts; ++i )
{
aFile.read( (char*) &tmp, sizeof( int ) );
if( aFile.fail() )
return false;
index.push_back( tmp );
}
return true;
}
-98
View File
@@ -1,98 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file sg_index.h
*/
#ifndef SG_INDEX_H
#define SG_INDEX_H
#include <vector>
#include "3d_cache/sg/sg_node.h"
/**
* Define a generic index interface for a scenegraph object.
*/
class SGINDEX : public SGNODE
{
public:
SGINDEX( SGNODE* aParent );
virtual ~SGINDEX();
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
SGNODE* FindNode(const char* aNodeName, const SGNODE* aCaller) noexcept override;
bool AddRefNode( SGNODE* aNode ) noexcept override;
bool AddChildNode( SGNODE* aNode ) noexcept override;
void unlinkChildNode( const SGNODE* aCaller ) noexcept override;
void unlinkRefNode( const SGNODE* aCaller ) noexcept override;
/**
* Retrieve the number of indices and a pointer to the list.
*
* @note The returned pointer may be invalidated by future operations on the SGNODE. The
* caller must make immediate use of the data and must not rely on the pointer's
* validity in the future.
*
* @param nIndices will hold the number of indices in the list.
* @param aIndexList will store a pointer to the data.
* @return true if there was available data (nIndices > 0) otherwise false.
*/
bool GetIndices( size_t& nIndices, int*& aIndexList );
/**
* Set the number of indices and creates a copy of the given index data.
*
* @param nIndices the number of indices to be stored.
* @param aIndexList the index data.
*/
void SetIndices( size_t nIndices, int* aIndexList );
/**
* Add a single index to the list.
*
* @param aIndex is the index to add.
*/
void AddIndex( int aIndex );
void ReNameNodes( void ) override;
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
protected:
bool writeCoordIndex( std::ostream& aFile );
bool writeColorIndex( std::ostream& aFile );
bool writeIndexList( std::ostream& aFile );
public:
// for internal SG consumption only
std::vector< int > index;
};
#endif // SG_INDEX_H
-346
View File
@@ -1,346 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <sstream>
#include <wx/log.h>
#include "3d_cache/sg/sg_node.h"
#include "plugins/3dapi/c3dmodel.h"
static const std::string node_names[S3D::SGTYPE_END + 1] = {
"TXFM",
"APP",
"COL",
"COLIDX",
"FACE",
"COORD",
"COORDIDX",
"NORM",
"SHAPE",
"INVALID"
};
static unsigned int node_counts[S3D::SGTYPE_END] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
char const* S3D::GetNodeTypeName( S3D::SGTYPES aType ) noexcept
{
return node_names[aType].c_str();
}
static void getNodeName( S3D::SGTYPES nodeType, std::string& aName )
{
if( nodeType < 0 || nodeType >= S3D::SGTYPE_END )
{
aName = node_names[S3D::SGTYPE_END];
return;
}
unsigned int seqNum = node_counts[nodeType];
++node_counts[nodeType];
std::ostringstream ostr;
ostr << node_names[nodeType] << "_" << seqNum;
aName = ostr.str();
}
SGNODE::SGNODE( SGNODE* aParent )
{
m_Parent = aParent;
m_Association = nullptr;
m_written = false;
m_SGtype = S3D::SGTYPE_END;
}
SGNODE::~SGNODE()
{
if( m_Parent )
m_Parent->unlinkChildNode( this );
if( m_Association )
*m_Association = nullptr;
std::list< SGNODE* >::iterator sBP = m_BackPointers.begin();
std::list< SGNODE* >::iterator eBP = m_BackPointers.end();
while( sBP != eBP )
{
(*sBP)->unlinkRefNode( this );
++sBP;
}
}
S3D::SGTYPES SGNODE::GetNodeType( void ) const noexcept
{
return m_SGtype;
}
SGNODE* SGNODE::GetParent( void ) const noexcept
{
return m_Parent;
}
bool SGNODE::SwapParent( SGNODE* aNewParent )
{
if( aNewParent == m_Parent )
return true;
if( nullptr == aNewParent )
return false;
if( nullptr == m_Parent )
{
if( aNewParent->AddChildNode( this ) )
return true;
return false;
}
if( aNewParent->GetNodeType() != m_Parent->GetNodeType() )
return false;
SGNODE* oldParent = m_Parent;
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
aNewParent->unlinkRefNode( this );
aNewParent->AddChildNode( this );
oldParent->AddRefNode( this );
return true;
}
const char* SGNODE::GetName( void )
{
if( m_Name.empty() )
getNodeName( m_SGtype, m_Name );
return m_Name.c_str();
}
void SGNODE::SetName( const char* aName )
{
if( nullptr == aName || 0 == aName[0] )
getNodeName( m_SGtype, m_Name );
else
m_Name = aName;
}
const char* SGNODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const noexcept
{
return node_names[aNodeType].c_str();
}
void SGNODE::addNodeRef( SGNODE* aNode )
{
if( nullptr == aNode )
return;
std::list< SGNODE* >::iterator np =
std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
if( np != m_BackPointers.end() )
return;
m_BackPointers.push_back( aNode );
}
void SGNODE::delNodeRef( const SGNODE* aNode )
{
if( nullptr == aNode )
return;
std::list< SGNODE* >::iterator np =
std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
if( np != m_BackPointers.end() )
{
m_BackPointers.erase( np );
return;
}
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] delNodeRef() did not find its target, this "
"node type %d, referenced node type %d" ),
__FILE__, __FUNCTION__, __LINE__,
m_SGtype,
aNode->GetNodeType() );
}
void SGNODE::AssociateWrapper( SGNODE** aWrapperRef ) noexcept
{
wxCHECK( aWrapperRef && *aWrapperRef == this, /* void */ );
// if there is an existing association then break it and emit a warning
// just in case the behavior is undesired
if( m_Association )
{
*m_Association = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [WARNING] association being broken with "
"previous wrapper" ),
__FILE__, __FUNCTION__, __LINE__ );
}
m_Association = aWrapperRef;
}
void SGNODE::DisassociateWrapper( SGNODE** aWrapperRef ) noexcept
{
if( !m_Association )
return;
wxCHECK( aWrapperRef, /* void */ );
wxCHECK( *aWrapperRef == *m_Association && aWrapperRef == m_Association, /* void */ );
m_Association = nullptr;
}
void SGNODE::ResetNodeIndex( void ) noexcept
{
for( int i = 0; i < (int)S3D::SGTYPE_END; ++i )
node_counts[i] = 1;
}
bool S3D::GetMatIndex( MATLIST& aList, SGNODE* aNode, int& aIndex )
{
aIndex = 0;
wxCHECK( aNode && S3D::SGTYPE_APPEARANCE == aNode->GetNodeType(), false );
SGAPPEARANCE* node = (SGAPPEARANCE*)aNode;
std::map< SGAPPEARANCE const*, int >::iterator it = aList.matmap.find( node );
if( it != aList.matmap.end() )
{
aIndex = it->second;
return true;
}
int idx = (int)aList.matorder.size();
aList.matorder.push_back( node );
aList.matmap.emplace( node, idx );
aIndex = idx;
return true;
}
void S3D::INIT_SMATERIAL( SMATERIAL& aMaterial )
{
aMaterial = {};
}
void S3D::INIT_SMESH( SMESH& aMesh ) noexcept
{
aMesh = {};
}
void S3D::INIT_S3DMODEL( S3DMODEL& aModel ) noexcept
{
aModel = {};
}
void S3D::FREE_SMESH( SMESH& aMesh ) noexcept
{
if( nullptr != aMesh.m_Positions )
{
delete [] aMesh.m_Positions;
aMesh.m_Positions = nullptr;
}
if( nullptr != aMesh.m_Normals )
{
delete [] aMesh.m_Normals;
aMesh.m_Normals = nullptr;
}
if( nullptr != aMesh.m_Texcoords )
{
delete [] aMesh.m_Texcoords;
aMesh.m_Texcoords = nullptr;
}
if( nullptr != aMesh.m_Color )
{
delete [] aMesh.m_Color;
aMesh.m_Color = nullptr;
}
if( nullptr != aMesh.m_FaceIdx )
{
delete [] aMesh.m_FaceIdx;
aMesh.m_FaceIdx = nullptr;
}
aMesh.m_VertexSize = 0;
aMesh.m_FaceIdxSize = 0;
aMesh.m_MaterialIdx = 0;
}
void S3D::FREE_S3DMODEL( S3DMODEL& aModel )
{
if( nullptr != aModel.m_Materials )
{
delete [] aModel.m_Materials;
aModel.m_Materials = nullptr;
}
aModel.m_MaterialsSize = 0;
if( nullptr != aModel.m_Meshes )
{
for( unsigned int i = 0; i < aModel.m_MeshesSize; ++i )
FREE_SMESH( aModel.m_Meshes[i] );
delete [] aModel.m_Meshes;
aModel.m_Meshes = nullptr;
}
aModel.m_MeshesSize = 0;
}
-236
View File
@@ -1,236 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file sg_node.h
*/
#ifndef SG_NODE_H
#define SG_NODE_H
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <glm/glm.hpp>
#include "plugins/3dapi/c3dmodel.h"
#include "plugins/3dapi/sg_base.h"
#include "plugins/3dapi/sg_types.h"
class SGNODE;
class SGAPPEARANCE;
namespace S3D
{
/**
* Return the name of the given type of node
*/
char const* GetNodeTypeName( S3D::SGTYPES aType ) noexcept;
struct MATLIST
{
std::vector< SGAPPEARANCE const* > matorder; // materials in order of addition
std::map< SGAPPEARANCE const*, int > matmap; // mapping from material to index
};
bool GetMatIndex( MATLIST& aList, SGNODE* aNode, int& aIndex );
void INIT_SMATERIAL( SMATERIAL& aMaterial );
void INIT_SMESH( SMESH& aMesh ) noexcept;
void INIT_S3DMODEL( S3DMODEL& aModel ) noexcept;
void FREE_SMESH( SMESH& aMesh) noexcept;
void FREE_S3DMODEL( S3DMODEL& aModel );
}
/**
* The base class of all Scene Graph nodes.
*/
class SGNODE
{
public:
SGNODE( SGNODE* aParent );
virtual ~SGNODE();
/**
* Return the type of this node instance.
*/
S3D::SGTYPES GetNodeType( void ) const noexcept;
/**
* Returns a pointer to the parent SGNODE of this object or NULL if the object has
* no parent (ie. top level transform).
*/
SGNODE* GetParent( void ) const noexcept;
/**
* Set the parent #SGNODE of this object.
*
* @param aParent [in] is the desired parent node
* @return true if the operation succeeds; false if the given node is not allowed to
* be a parent to the derived object.
*/
virtual bool SetParent( SGNODE* aParent, bool notify = true ) = 0;
/**
* Swap the ownership with the given parent.
*
* This operation may be required when reordering nodes for optimization.
*
* @param aNewParent will become the new parent to the object; it must be the same type
* as the parent of this instance.
*/
bool SwapParent( SGNODE* aNewParent );
const char* GetName( void );
void SetName(const char *aName);
const char * GetNodeTypeName( S3D::SGTYPES aNodeType ) const noexcept;
/**
* Search the tree of linked nodes and return a reference to the first node found with
* the given name.
*
* The reference is then typically added to another node via AddRefNode().
*
* @param aNodeName is the name of the node to search for.
* @param aCaller is a pointer to the node invoking this function.
* @return is a valid node pointer on success, otherwise NULL.
*/
virtual SGNODE* FindNode( const char *aNodeName, const SGNODE *aCaller ) = 0;
virtual bool AddRefNode( SGNODE* aNode ) = 0;
virtual bool AddChildNode( SGNODE* aNode ) = 0;
/**
* Associate this object with a handle to itself.
*
* The handle is typically held by an IFSG* wrapper and the pointer which it refers to
* is set to NULL upon destruction of this object. This mechanism provides a scheme
* by which a wrapper can be notified of the destruction of the object which it wraps.
*/
void AssociateWrapper( SGNODE** aWrapperRef ) noexcept;
/**
* Remove the association between an IFSG* wrapper object and this object.
*/
void DisassociateWrapper( SGNODE** aWrapperRef ) noexcept;
/**
* Reset the global SG* node indices in preparation for write operations.
*/
void ResetNodeIndex( void ) noexcept;
/**
* Rename a node and all its child nodes in preparation for write operations.
*/
virtual void ReNameNodes( void ) = 0;
/**
* Writes this node's data to a VRML file.
*
* This includes all data of child and referenced nodes.
*/
virtual bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) = 0;
/**
* Write this node's data to a binary cache file.
*
* The data includes all data of children and references to children. If this function
* is invoked by the user, parentNode must be set to NULL in order to ensure coherent data.
*/
virtual bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) = 0;
/**
* Reads binary format data from a cache file.
*
* To read a cache file, open the file for reading and invoke this function from a new
* #SCENEGRAPH node.
*/
virtual bool ReadCache( std::istream& aFile, SGNODE* parentNode ) = 0;
/**
* Remove references to an owned child.
*
* This is invoked by the child upon destruction to ensure that the parent has no
* invalid references.
*
* @param aNode is the child which is being deleted.
*/
virtual void unlinkChildNode( const SGNODE* aNode ) = 0;
/**
* Remove pointers to a referenced node.
*
* This is invoked by the referenced node upon destruction to ensure that the referring
* node has no invalid references.
*
* @param aNode is the node which is being deleted.
*/
virtual void unlinkRefNode( const SGNODE* aNode ) = 0;
/**
* Add a pointer to a node which references this node, but does not own.
*
* Such back-pointers are required to ensure that invalidated references are removed
* when a node is deleted.
*
* @param aNode is the node holding a reference to this object.
*/
void addNodeRef( SGNODE* aNode );
/**
* Remove a pointer to a node which references this node, but does not own.
*
* @param aNode is the node holding a reference to this object.
*/
void delNodeRef( const SGNODE* aNode );
/**
* Return true if the object had already been written to a cache file or VRML file
*
* For internal use only.
*/
bool isWritten( void ) noexcept
{
return m_written;
}
protected:
std::list< SGNODE* > m_BackPointers; ///< nodes which hold a reference to this.
SGNODE* m_Parent; ///< Pointer to parent node; may be NULL for top level transform.
S3D::SGTYPES m_SGtype; ///< Type of Scene Graph node.
std::string m_Name; ///< name to use for referencing the entity by name.
bool m_written; ///< Set to true when the object has been written after a ReNameNodes().
private:
SGNODE** m_Association; ///< Handle to the instance held by a wrapper.
};
#endif // SG_NODE_H
-299
View File
@@ -1,299 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "3d_cache/sg/sg_normals.h"
#include "3d_cache/sg/sg_helpers.h"
SGNORMALS::SGNORMALS( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_NORMALS;
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGNORMALS "
"(type %d)" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeType() );
}
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
}
SGNORMALS::~SGNORMALS()
{
norms.clear();
}
bool SGNORMALS::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
if( nullptr == aParent )
return true;
}
// only a SGFACESET may be parent to a SGNORMALS
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SGNORMALS::FindNode( const char* aNodeName, const SGNODE* aCaller ) noexcept
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( !m_Name.compare( aNodeName ) )
return this;
return nullptr;
}
void SGNORMALS::unlinkChildNode( const SGNODE* aCaller ) noexcept
{
wxCHECK( false, /* void */ );
}
void SGNORMALS::unlinkRefNode( const SGNODE* aCaller ) noexcept
{
wxCHECK( false, /* void */ );
}
bool SGNORMALS::AddRefNode( SGNODE* aNode ) noexcept
{
wxCHECK( false, false );
return false;
}
bool SGNORMALS::AddChildNode( SGNODE* aNode ) noexcept
{
wxCHECK( false, false );
return false;
}
bool SGNORMALS::GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList )
{
if( norms.empty() )
{
aListSize = 0;
aNormalList = nullptr;
return false;
}
aListSize = norms.size();
aNormalList = &norms[0];
return true;
}
void SGNORMALS::SetNormalList( size_t aListSize, const SGVECTOR* aNormalList )
{
norms.clear();
if( 0 == aListSize || nullptr == aNormalList )
return;
for( int i = 0; i < (int)aListSize; ++i )
norms.push_back( aNormalList[i] );
}
void SGNORMALS::AddNormal( double aXValue, double aYValue, double aZValue )
{
norms.emplace_back( aXValue, aYValue, aZValue );
}
void SGNORMALS::AddNormal( const SGVECTOR& aNormal )
{
norms.push_back( aNormal );
}
void SGNORMALS::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
}
bool SGNORMALS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
{
if( norms.empty() )
return false;
if( aReuseFlag )
{
if( !m_written )
{
aFile << " normal DEF " << GetName() << " Normal { vector [\n ";
m_written = true;
}
else
{
aFile << " normal USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << " normal Normal { vector [\n ";
}
std::string tmp;
size_t n = norms.size();
bool nline = false;
for( size_t i = 0; i < n; )
{
S3D::FormatVector( tmp, norms[i] );
aFile << tmp ;
++i;
if( i < n )
{
aFile << ",";
if( nline )
{
aFile << "\n ";
nline = false;
}
else
{
nline = true;
}
}
}
aFile << "] }\n";
return true;
}
bool SGNORMALS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
{
wxCHECK( m_Parent, false );
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
{
m_written = true;
return true;
}
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
aFile << "[" << GetName() << "]";
size_t npts = norms.size();
aFile.write( (char*)&npts, sizeof(size_t) );
for( size_t i = 0; i < npts; ++i )
S3D::WriteVector( aFile, norms[i] );
if( aFile.fail() )
return false;
m_written = true;
return true;
}
bool SGNORMALS::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( norms.empty(), false );
size_t npts;
aFile.read( (char*) &npts, sizeof( size_t ) );
SGVECTOR tmp;
if( aFile.fail() )
return false;
for( size_t i = 0; i < npts; ++i )
{
if( !S3D::ReadVector( aFile, tmp ) || aFile.fail() )
return false;
norms.push_back( tmp );
}
return true;
}
-67
View File
@@ -1,67 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file sg_normals.h
*/
#ifndef SG_NORMALS_H
#define SG_NORMALS_H
#include <vector>
#include "3d_cache/sg/sg_node.h"
/**
* Define a set of vertex normals for a scene graph object
*/
class SGNORMALS : public SGNODE
{
public:
SGNORMALS( SGNODE* aParent );
virtual ~SGNORMALS();
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
SGNODE* FindNode( const char* aNodeName, const SGNODE* aCaller ) noexcept override;
bool AddRefNode( SGNODE* aNode ) noexcept override;
bool AddChildNode( SGNODE* aNode ) noexcept override;
bool GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList );
void SetNormalList( size_t aListSize, const SGVECTOR* aNormalList );
void AddNormal( double aXValue, double aYValue, double aZValue );
void AddNormal( const SGVECTOR& aNormal );
void ReNameNodes( void ) override;
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
std::vector< SGVECTOR > norms;
};
#endif // SG_NORMALS_H
-783
View File
@@ -1,783 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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 <iostream>
#include <sstream>
#include <wx/log.h>
#include "3d_cache/sg/sg_shape.h"
#include "3d_cache/sg/sg_faceset.h"
#include "3d_cache/sg/sg_appearance.h"
#include "3d_cache/sg/sg_helpers.h"
#include "3d_cache/sg/sg_coordindex.h"
#include "3d_cache/sg/sg_coords.h"
#include "3d_cache/sg/sg_colors.h"
#include "3d_cache/sg/sg_normals.h"
SGSHAPE::SGSHAPE( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_SHAPE;
m_Appearance = nullptr;
m_RAppearance = nullptr;
m_FaceSet = nullptr;
m_RFaceSet = nullptr;
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
{
m_Parent = nullptr;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGSHAPE (type %d)" ),
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
}
else if( nullptr != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
}
SGSHAPE::~SGSHAPE()
{
// drop references
if( m_RAppearance )
{
m_RAppearance->delNodeRef( this );
m_RAppearance = nullptr;
}
if( m_RFaceSet )
{
m_RFaceSet->delNodeRef( this );
m_RFaceSet = nullptr;
}
// delete objects
if( m_Appearance )
{
m_Appearance->SetParent( nullptr, false );
delete m_Appearance;
m_Appearance = nullptr;
}
if( m_FaceSet )
{
m_FaceSet->SetParent( nullptr, false );
delete m_FaceSet;
m_FaceSet = nullptr;
}
}
bool SGSHAPE::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
if( nullptr == aParent )
return true;
}
// only a SGTRANSFORM may be parent to a SGSHAPE
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SGSHAPE::FindNode( const char* aNodeName, const SGNODE* aCaller )
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( !m_Name.compare( aNodeName ) )
return this;
SGNODE* tmp = nullptr;
if( nullptr != m_Appearance )
{
tmp = m_Appearance->FindNode( aNodeName, this );
if( tmp )
{
return tmp;
}
}
if( nullptr != m_FaceSet )
{
tmp = m_FaceSet->FindNode( aNodeName, this );
if( tmp )
{
return tmp;
}
}
// query the parent if appropriate
if( aCaller == m_Parent || nullptr == m_Parent )
return nullptr;
return m_Parent->FindNode( aNodeName, this );
}
void SGSHAPE::unlinkNode( const SGNODE* aNode, bool isChild )
{
if( nullptr == aNode )
return;
if( isChild )
{
if( aNode == m_Appearance )
{
m_Appearance = nullptr;
return;
}
if( aNode == m_FaceSet )
{
m_FaceSet = nullptr;
return;
}
}
else
{
if( aNode == m_RAppearance )
{
delNodeRef( this );
m_RAppearance = nullptr;
return;
}
if( aNode == m_RFaceSet )
{
delNodeRef( this );
m_RFaceSet = nullptr;
return;
}
}
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
__FILE__, __FUNCTION__, __LINE__ );
}
void SGSHAPE::unlinkChildNode( const SGNODE* aNode )
{
unlinkNode( aNode, true );
}
void SGSHAPE::unlinkRefNode( const SGNODE* aNode )
{
unlinkNode( aNode, false );
}
bool SGSHAPE::addNode( SGNODE* aNode, bool isChild )
{
wxCHECK( aNode, false );
if( S3D::SGTYPE_APPEARANCE == aNode->GetNodeType() )
{
if( m_Appearance || m_RAppearance )
{
if( aNode != m_Appearance && aNode != m_RAppearance )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Appearance "
"nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
return true;
}
if( isChild )
{
m_Appearance = (SGAPPEARANCE*)aNode;
m_Appearance->SetParent( this );
}
else
{
m_RAppearance = (SGAPPEARANCE*)aNode;
m_RAppearance->addNodeRef( this );
}
return true;
}
if( S3D::SGTYPE_FACESET == aNode->GetNodeType() )
{
if( m_FaceSet || m_RFaceSet )
{
if( aNode != m_FaceSet && aNode != m_RFaceSet )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple FaceSet nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
return true;
}
if( isChild )
{
m_FaceSet = (SGFACESET*)aNode;
m_FaceSet->SetParent( this );
}
else
{
m_RFaceSet = (SGFACESET*)aNode;
m_RFaceSet->addNodeRef( this );
}
return true;
}
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] object %s is not a valid type for this "
"object (%d)" ),
__FILE__, __FUNCTION__, __LINE__, aNode->GetName(), aNode->GetNodeType() );
return false;
}
bool SGSHAPE::AddRefNode( SGNODE* aNode )
{
return addNode( aNode, false );
}
bool SGSHAPE::AddChildNode( SGNODE* aNode )
{
return addNode( aNode, true );
}
void SGSHAPE::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
// rename Appearance
if( m_Appearance )
m_Appearance->ReNameNodes();
// rename FaceSet
if( m_FaceSet )
m_FaceSet->ReNameNodes();
}
bool SGSHAPE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
{
if( !m_Appearance && !m_RAppearance && !m_FaceSet && !m_RFaceSet )
{
return false;
}
if( aReuseFlag )
{
if( !m_written )
{
aFile << "DEF " << GetName() << " Shape {\n";
m_written = true;
}
else
{
aFile << " USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << " Shape {\n";
}
if( m_Appearance )
m_Appearance->WriteVRML( aFile, aReuseFlag );
if( m_RAppearance )
m_RAppearance->WriteVRML( aFile, aReuseFlag );
if( m_FaceSet )
m_FaceSet->WriteVRML( aFile, aReuseFlag );
if( m_RFaceSet )
m_RFaceSet->WriteVRML( aFile, aReuseFlag );
aFile << "}\n";
return true;
}
bool SGSHAPE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
{
wxCHECK( m_Parent, false );
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
{
m_written = true;
return true;
}
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
// check if any references are unwritten and swap parents if so
if( nullptr != m_RAppearance && !m_RAppearance->isWritten() )
m_RAppearance->SwapParent(this);
if( nullptr != m_RFaceSet && !m_RFaceSet->isWritten() )
m_RFaceSet->SwapParent( this );
aFile << "[" << GetName() << "]";
#define NITEMS 4
bool items[NITEMS];
int i;
for( i = 0; i < NITEMS; ++i )
items[i] = 0;
i = 0;
if( nullptr != m_Appearance )
items[i] = true;
++i;
if( nullptr != m_RAppearance )
items[i] = true;
++i;
if( nullptr != m_FaceSet )
items[i] = true;
++i;
if( nullptr != m_RFaceSet )
items[i] = true;
for( int jj = 0; jj < NITEMS; ++jj )
aFile.write( (char*)&items[jj], sizeof(bool) );
if( items[0] )
m_Appearance->WriteCache( aFile, this );
if( items[1] )
aFile << "[" << m_RAppearance->GetName() << "]";
if( items[2] )
m_FaceSet->WriteCache( aFile, this );
if( items[3] )
aFile << "[" << m_RFaceSet->GetName() << "]";
if( aFile.fail() )
return false;
m_written = true;
return true;
}
bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( m_Appearance == nullptr && m_RAppearance == nullptr && m_FaceSet == nullptr &&
m_RFaceSet == nullptr, false );
#define NITEMS 4
bool items[NITEMS];
for( int i = 0; i < NITEMS; ++i )
aFile.read( (char*)&items[i], sizeof(bool) );
if( ( items[0] && items[1] ) || ( items[2] && items[3] ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; multiple item definitions "
"at position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
std::string name;
if( items[0] )
{
if( S3D::SGTYPE_APPEARANCE != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child appearance "
"tag at position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
m_Appearance = new SGAPPEARANCE( this );
m_Appearance->SetName( name.c_str() );
if( !m_Appearance->ReadCache( aFile, this ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading appearance "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__, name );
return false;
}
}
if( items[1] )
{
if( S3D::SGTYPE_APPEARANCE != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref appearance tag "
"at position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
SGNODE* np = FindNode( name.c_str(), this );
if( !np )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref "
"appearance '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
if( S3D::SGTYPE_APPEARANCE != np->GetNodeType() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not "
"SGAPPEARANCE '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
m_RAppearance = (SGAPPEARANCE*)np;
m_RAppearance->addNodeRef( this );
}
if( items[2] )
{
if( S3D::SGTYPE_FACESET != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child face set tag "
"at position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
m_FaceSet = new SGFACESET( this );
m_FaceSet->SetName( name.c_str() );
if( !m_FaceSet->ReadCache( aFile, this ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading face set "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__, name );
return false;
}
}
if( items[3] )
{
if( S3D::SGTYPE_FACESET != S3D::ReadTag( aFile, name ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref face set tag at "
"position %ul" ),
__FILE__, __FUNCTION__, __LINE__,
static_cast<unsigned long>( aFile.tellg() ) );
return false;
}
SGNODE* np = FindNode( name.c_str(), this );
if( !np )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref face "
"set '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
if( S3D::SGTYPE_FACESET != np->GetNodeType() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGFACESET "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
return false;
}
m_RFaceSet = (SGFACESET*)np;
m_RFaceSet->addNodeRef( this );
}
if( aFile.fail() )
return false;
return true;
}
bool SGSHAPE::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
std::vector< SMESH >& meshes )
{
SMESH m;
S3D::INIT_SMESH( m );
SGAPPEARANCE* pa = m_Appearance;
SGFACESET* pf = m_FaceSet;
if( nullptr == pa )
pa = m_RAppearance;
if( nullptr == pf )
pf = m_RFaceSet;
// no face sets = nothing to render, which is valid though pointless
if( nullptr == pf )
return true;
if( !pf->validate() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; inconsistent data" ),
__FILE__, __FUNCTION__, __LINE__ );
return true;
}
if( nullptr == pa )
{
m.m_MaterialIdx = 0;
}
else
{
int idx;
if( !S3D::GetMatIndex( materials, pa, idx ) )
{
m.m_MaterialIdx = 0;
}
else
{
m.m_MaterialIdx = idx;
}
}
SGCOLORS* pc = pf->m_Colors;
SGCOORDS* pv = pf->m_Coords;
SGCOORDINDEX* vidx = pf->m_CoordIndices;
SGNORMALS* pn = pf->m_Normals;
if( nullptr == pc )
pc = pf->m_RColors;
if( nullptr == pv )
pv = pf->m_RCoords;
if( nullptr == pn )
pn = pf->m_RNormals;
// set the vertex points and indices
size_t nCoords = 0;
SGPOINT* pCoords = nullptr;
pv->GetCoordsList( nCoords, pCoords );
size_t nColors = 0;
SGCOLOR* pColors = nullptr;
if( pc )
{
// check the vertex colors
pc->GetColorList( nColors, pColors );
if( nColors < nCoords )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; not enough colors per "
"vertex (%ul vs %ul)" ),
__FILE__, __FUNCTION__, __LINE__, static_cast<unsigned long>( nColors ),
static_cast<unsigned long>( nCoords ) );
return true;
}
}
// set the vertex indices
size_t nvidx = 0;
int* lv = nullptr;
vidx->GetIndices( nvidx, lv );
// note: reduce the vertex set to include only the referenced vertices
std::vector< int > vertices; // store the list of temp vertex indices
std::map< int, unsigned int > indexmap; // map temp vertex to true vertex
std::map< int, unsigned int >::iterator mit;
for( unsigned int i = 0; i < nvidx; ++i )
{
mit = indexmap.find( lv[i] );
if( mit == indexmap.end() )
{
indexmap.emplace( lv[i], vertices.size() );
vertices.push_back( lv[i] );
}
}
if( vertices.size() < 3 )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; not enough vertices" ),
__FILE__, __FUNCTION__, __LINE__ );
return true;
}
// construct the final vertex/color list
SFVEC3F* lColors = nullptr;
SFVEC3F* lCoords = new SFVEC3F[ vertices.size() ];
int ti;
if( pc )
{
lColors = new SFVEC3F[vertices.size()];
m.m_Color = lColors;
}
if( pc )
{
for( size_t i = 0; i < vertices.size(); ++i )
{
ti = vertices[i];
glm::dvec4 pt( pCoords[ti].x, pCoords[ti].y, pCoords[ti].z, 1.0 );
pt = (*aTransform) * pt;
pColors[ti].GetColor( lColors[i].x, lColors[i].y, lColors[i].z );
lCoords[i] = SFVEC3F( pt.x, pt.y, pt.z );
}
}
else
{
for( size_t i = 0; i < vertices.size(); ++i )
{
ti = vertices[i];
glm::dvec4 pt( pCoords[ti].x, pCoords[ti].y, pCoords[ti].z, 1.0 );
pt = (*aTransform) * pt;
lCoords[i] = SFVEC3F( pt.x, pt.y, pt.z );
}
}
m.m_VertexSize = (unsigned int) vertices.size();
m.m_Positions = lCoords;
unsigned int* lvidx = new unsigned int[ nvidx ];
for( unsigned int i = 0; i < nvidx; ++i )
{
mit = indexmap.find( lv[i] );
lvidx[i] = mit->second;
}
m.m_FaceIdxSize = (unsigned int )nvidx;
m.m_FaceIdx = lvidx;
// set the per-vertex normals
size_t nNorms = 0;
SGVECTOR* pNorms = nullptr;
double x, y, z;
pn->GetNormalList( nNorms, pNorms );
SFVEC3F* lNorms = new SFVEC3F[ vertices.size() ];
for( size_t i = 0; i < vertices.size(); ++i )
{
ti = vertices[i];
pNorms[ti].GetVector( x, y, z );
glm::dvec4 pt( x, y, z, 0.0 );
pt = (*aTransform) * pt;
lNorms[i] = SFVEC3F( pt.x, pt.y, pt.z );
}
m.m_Normals = lNorms;
meshes.push_back( m );
return true;
}
-88
View File
@@ -1,88 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright The 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
*/
/**
* @file sg_shape.h
*/
#ifndef SG_SHAPE_H
#define SG_SHAPE_H
#include <vector>
#include "3d_cache/sg/sg_node.h"
class SGAPPEARANCE;
class SGFACESET;
/**
* Define a complex 3D shape for a scenegraph object.
*/
class SGSHAPE : public SGNODE
{
public:
SGSHAPE( SGNODE* aParent );
virtual ~SGSHAPE();
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
SGNODE* FindNode(const char* aNodeName, const SGNODE* aCaller) override;
bool AddRefNode( SGNODE* aNode ) override;
bool AddChildNode( SGNODE* aNode ) override;
void ReNameNodes( void ) override;
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
bool Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
std::vector< SMESH >& meshes );
void unlinkChildNode( const SGNODE* aNode ) override;
void unlinkRefNode( const SGNODE* aNode ) override;
private:
void unlinkNode( const SGNODE* aNode, bool isChild );
bool addNode( SGNODE* aNode, bool isChild );
public:
// owned node
SGAPPEARANCE* m_Appearance;
SGFACESET* m_FaceSet;
// referenced nodes
SGAPPEARANCE* m_RAppearance;
SGFACESET* m_RFaceSet;
};
/*
p.107
Shape {
appearance NULL
geometry NULL
}
*/
#endif // SG_SHAPE_H
+735
View File
@@ -0,0 +1,735 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2016 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
*/
/**
* @file 3d_canvas.cpp
*/
#include <fctsys.h>
#include <trigo.h>
#include <project.h>
#include <gestfich.h>
#include <wx/image.h>
#if !wxUSE_GLCANVAS
#error Please set wxUSE_GLCANVAS to 1 in setup.h.
#endif
#include <wx/dataobj.h>
#include <wx/clipbrd.h>
#include <wx/wupdlock.h>
#ifdef __WINDOWS__
#include <GL/glew.h> // must be included before gl.h
#endif
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <trackball.h>
#include <3d_viewer_id.h>
#include <textures/text_silk.h>
#include <textures/text_pcb.h>
static const double DELTA_MOVE_STEP = 0.7;
/*
* EDA_3D_CANVAS implementation
*/
BEGIN_EVENT_TABLE( EDA_3D_CANVAS, wxGLCanvas )
EVT_PAINT( EDA_3D_CANVAS::OnPaint )
// key event:
EVT_CHAR( EDA_3D_CANVAS::OnChar )
// mouse events
EVT_RIGHT_DOWN( EDA_3D_CANVAS::OnRightClick )
EVT_MOUSEWHEEL( EDA_3D_CANVAS::OnMouseWheel )
#ifdef USE_OSX_MAGNIFY_EVENT
EVT_MAGNIFY( EDA_3D_CANVAS::OnMagnify )
#endif
EVT_MOTION( EDA_3D_CANVAS::OnMouseMove )
// other events
EVT_ERASE_BACKGROUND( EDA_3D_CANVAS::OnEraseBackground )
EVT_MENU_RANGE( ID_POPUP_3D_VIEW_START, ID_POPUP_3D_VIEW_END, EDA_3D_CANVAS::OnPopUpMenu )
END_EVENT_TABLE()
// Define an invalid value for some unsigned int indexes
#define INVALID_INDEX GL_INVALID_VALUE
EDA_3D_CANVAS::EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList ) :
wxGLCanvas( parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE )
{
m_init = false;
m_reportWarnings = true;
m_shadow_init = false;
// set an invalid value to not yet initialized indexes managing
// textures created to enhance 3D rendering
m_text_pcb = m_text_silk = INVALID_INDEX;
m_text_fake_shadow_front = INVALID_INDEX;
m_text_fake_shadow_back = INVALID_INDEX;
m_text_fake_shadow_board = INVALID_INDEX;
// position of the front and back layers
// (will be initialized to a better value later)
m_ZBottom = 0.0;
m_ZTop = 0.0;
m_lightPos = S3D_VERTEX(0.0f, 0.0f, 30.0f);
// Clear all gl list identifiers:
for( int ii = GL_ID_BEGIN; ii < GL_ID_END; ii++ )
m_glLists[ii] = 0;
// Explicitly create a new rendering context instance for this canvas.
m_glRC = new wxGLContext( this );
DisplayStatus();
}
EDA_3D_CANVAS::~EDA_3D_CANVAS()
{
ClearLists();
m_init = false;
delete m_glRC;
// Free the list of parsers list
for( unsigned int i = 0; i < m_model_parsers_list.size(); i++ )
delete m_model_parsers_list[i];
}
void EDA_3D_CANVAS::ClearLists( int aGlList )
{
if( aGlList )
{
if( m_glLists[aGlList] > 0 )
glDeleteLists( m_glLists[aGlList], 1 );
m_glLists[aGlList] = 0;
return;
}
for( int ii = GL_ID_BEGIN; ii < GL_ID_END; ii++ )
{
if( m_glLists[ii] > 0 )
glDeleteLists( m_glLists[ii], 1 );
m_glLists[ii] = 0;
}
// When m_text_fake_shadow_??? is set to INVALID_INDEX, textures are not yet created.
if( m_text_fake_shadow_front != INVALID_INDEX )
glDeleteTextures( 1, &m_text_fake_shadow_front );
if( m_text_fake_shadow_back != INVALID_INDEX )
glDeleteTextures( 1, &m_text_fake_shadow_back );
if( m_text_fake_shadow_board != INVALID_INDEX )
glDeleteTextures( 1, &m_text_fake_shadow_board );
m_shadow_init = false;
}
void EDA_3D_CANVAS::OnChar( wxKeyEvent& event )
{
SetView3D( event.GetKeyCode() );
event.Skip();
}
void EDA_3D_CANVAS::SetView3D( int keycode )
{
int ii;
double delta_move = DELTA_MOVE_STEP * GetPrm3DVisu().m_Zoom;
switch( keycode )
{
case WXK_LEFT:
m_draw3dOffset.x -= delta_move;
break;
case WXK_RIGHT:
m_draw3dOffset.x += delta_move;
break;
case WXK_UP:
m_draw3dOffset.y += delta_move;
break;
case WXK_DOWN:
m_draw3dOffset.y -= delta_move;
break;
case WXK_HOME:
GetPrm3DVisu().m_Zoom = 1.0;
m_draw3dOffset.x = m_draw3dOffset.y = 0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
break;
case WXK_END:
break;
case WXK_F1:
GetPrm3DVisu().m_Zoom /= 1.4;
if( GetPrm3DVisu().m_Zoom <= 0.01 )
GetPrm3DVisu().m_Zoom = 0.01;
break;
case WXK_F2:
GetPrm3DVisu().m_Zoom *= 1.4;
break;
case '+':
break;
case '-':
break;
case 'r':
case 'R':
m_draw3dOffset.x = m_draw3dOffset.y = 0;
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
break;
case 'x':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
GetPrm3DVisu().m_ROTZ = -90;
GetPrm3DVisu().m_ROTX = -90;
break;
case 'X':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
GetPrm3DVisu().m_ROTZ = 90;
GetPrm3DVisu().m_ROTX = -90;
break;
case 'y':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
GetPrm3DVisu().m_ROTX = -90;
break;
case 'Y':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
GetPrm3DVisu().m_ROTX = -90;
GetPrm3DVisu().m_ROTZ = -180;
break;
case 'z':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
break;
case 'Z':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
GetPrm3DVisu().m_ROTX = -180;
break;
default:
return;
}
DisplayStatus();
Refresh( false );
}
void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent& event )
{
double delta = DELTA_MOVE_STEP * GetPrm3DVisu().m_Zoom;
if ( GetPrm3DVisu().GetFlag( FL_MOUSEWHEEL_PANNING ) )
delta *= 0.05 * event.GetWheelRotation();
else
if ( event.GetWheelRotation() < 0 )
delta = -delta;
if( GetPrm3DVisu().GetFlag( FL_MOUSEWHEEL_PANNING ) )
{
if( event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL )
m_draw3dOffset.x -= delta;
else
m_draw3dOffset.y -= delta;
}
else if( event.ShiftDown() )
{
m_draw3dOffset.y -= delta;
}
else if( event.ControlDown() )
{
m_draw3dOffset.x += delta;
}
else
{
if( event.GetWheelRotation() > 0 )
{
GetPrm3DVisu().m_Zoom /= 1.4;
if( GetPrm3DVisu().m_Zoom <= 0.01 )
GetPrm3DVisu().m_Zoom = 0.01;
}
else
GetPrm3DVisu().m_Zoom *= 1.4;
}
DisplayStatus();
Refresh( false );
GetPrm3DVisu().m_Beginx = event.GetX();
GetPrm3DVisu().m_Beginy = event.GetY();
}
#ifdef USE_OSX_MAGNIFY_EVENT
void EDA_3D_CANVAS::OnMagnify( wxMouseEvent& event )
{
double magnification = ( event.GetMagnification() + 1.0f );
GetPrm3DVisu().m_Zoom /= magnification;
if( GetPrm3DVisu().m_Zoom <= 0.01 )
{
GetPrm3DVisu().m_Zoom = 0.01;
}
DisplayStatus();
Refresh( false );
}
#endif
void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent& event )
{
wxSize size( GetClientSize() );
double spin_quat[4];
if( event.Dragging() )
{
if( event.LeftIsDown() )
{
/* drag in progress, simulate trackball */
trackball( spin_quat,
(2.0 * GetPrm3DVisu().m_Beginx - size.x) / size.x,
(size.y - 2.0 * GetPrm3DVisu().m_Beginy) / size.y,
( 2.0 * event.GetX() - size.x) / size.x,
( size.y - 2.0 * event.GetY() ) / size.y );
add_quats( spin_quat, GetPrm3DVisu().m_Quat, GetPrm3DVisu().m_Quat );
}
else if( event.MiddleIsDown() )
{
/* middle button drag -> pan */
/* Current zoom and an additional factor are taken into account
* for the amount of panning. */
const double PAN_FACTOR = 8.0 * GetPrm3DVisu().m_Zoom;
m_draw3dOffset.x -= PAN_FACTOR *
( GetPrm3DVisu().m_Beginx - event.GetX() ) / size.x;
m_draw3dOffset.y -= PAN_FACTOR *
(event.GetY() - GetPrm3DVisu().m_Beginy) / size.y;
}
/* orientation has changed, redraw mesh */
DisplayStatus();
Refresh( false );
}
GetPrm3DVisu().m_Beginx = event.GetX();
GetPrm3DVisu().m_Beginy = event.GetY();
}
void EDA_3D_CANVAS::OnRightClick( wxMouseEvent& event )
{
wxPoint pos;
wxMenu PopUpMenu;
pos.x = event.GetX();
pos.y = event.GetY();
wxMenuItem* item = new wxMenuItem( &PopUpMenu, ID_POPUP_ZOOMIN, _( "Zoom +" ) );
item->SetBitmap( KiBitmap( zoom_in_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_ZOOMOUT, _( "Zoom -" ) );
item->SetBitmap( KiBitmap( zoom_out_xpm ));
PopUpMenu.Append( item );
PopUpMenu.AppendSeparator();
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZPOS, _( "Top View" ) );
item->SetBitmap( KiBitmap( axis3d_top_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZNEG, _( "Bottom View" ) );
item->SetBitmap( KiBitmap( axis3d_bottom_xpm ));
PopUpMenu.Append( item );
PopUpMenu.AppendSeparator();
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_XPOS, _( "Right View" ) );
item->SetBitmap( KiBitmap( axis3d_right_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_XNEG, _( "Left View" ) );
item->SetBitmap( KiBitmap( axis3d_left_xpm ));
PopUpMenu.Append( item );
PopUpMenu.AppendSeparator();
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_YPOS, _( "Front View" ) );
item->SetBitmap( KiBitmap( axis3d_front_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_YNEG, _( "Back View" ) );
item->SetBitmap( KiBitmap( axis3d_back_xpm ));
PopUpMenu.Append( item );
PopUpMenu.AppendSeparator();
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_LEFT, _( "Move left <-" ) );
item->SetBitmap( KiBitmap( left_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_RIGHT, _( "Move right ->" ) );
item->SetBitmap( KiBitmap( right_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_UP, _( "Move Up ^" ) );
item->SetBitmap( KiBitmap( up_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_DOWN, _( "Move Down" ) );
item->SetBitmap( KiBitmap( down_xpm ));
PopUpMenu.Append( item );
PopupMenu( &PopUpMenu, pos );
}
void EDA_3D_CANVAS::OnPopUpMenu( wxCommandEvent& event )
{
int key = 0;
switch( event.GetId() )
{
case ID_POPUP_ZOOMIN:
key = WXK_F1;
break;
case ID_POPUP_ZOOMOUT:
key = WXK_F2;
break;
case ID_POPUP_VIEW_XPOS:
key = 'x';
break;
case ID_POPUP_VIEW_XNEG:
key = 'X';
break;
case ID_POPUP_VIEW_YPOS:
key = 'y';
break;
case ID_POPUP_VIEW_YNEG:
key = 'Y';
break;
case ID_POPUP_VIEW_ZPOS:
key = 'z';
break;
case ID_POPUP_VIEW_ZNEG:
key = 'Z';
break;
case ID_POPUP_MOVE3D_LEFT:
key = WXK_LEFT;
break;
case ID_POPUP_MOVE3D_RIGHT:
key = WXK_RIGHT;
break;
case ID_POPUP_MOVE3D_UP:
key = WXK_UP;
break;
case ID_POPUP_MOVE3D_DOWN:
key = WXK_DOWN;
break;
default:
return;
}
SetView3D( key );
}
void EDA_3D_CANVAS::DisplayStatus()
{
wxString msg;
msg.Printf( wxT( "dx %3.2f" ), m_draw3dOffset.x );
Parent()->SetStatusText( msg, 1 );
msg.Printf( wxT( "dy %3.2f" ), m_draw3dOffset.y );
Parent()->SetStatusText( msg, 2 );
msg.Printf( _( "Zoom: %3.1f" ), 45 * GetPrm3DVisu().m_Zoom );
Parent()->SetStatusText( msg, 3 );
}
void EDA_3D_CANVAS::OnPaint( wxPaintEvent& event )
{
wxPaintDC dc( this );
Redraw();
event.Skip();
}
void EDA_3D_CANVAS::OnEraseBackground( wxEraseEvent& event )
{
// Do nothing, to avoid flashing.
}
typedef struct s_sImage
{
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
unsigned char pixel_data[64 * 64 * 4 + 1];
}tsImage;
GLuint load_and_generate_texture( tsImage *image )
{
GLuint texture;
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_PACK_ALIGNMENT, 1);
glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );
gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, image->width, image->height,
GL_RGBA, GL_UNSIGNED_BYTE, image->pixel_data );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
return texture;
}
void EDA_3D_CANVAS::InitGL()
{
if( !m_init )
{
m_init = true;
m_text_pcb = load_and_generate_texture( (tsImage *)&text_pcb );
m_text_silk = load_and_generate_texture( (tsImage *)&text_silk );
GetPrm3DVisu().m_Zoom = 1.0;
m_ZBottom = 1.0;
m_ZTop = 10.0;
glDisable( GL_CULL_FACE ); // show back faces
glEnable( GL_DEPTH_TEST ); // Enable z-buffering
glEnable( GL_ALPHA_TEST );
glEnable( GL_LINE_SMOOTH );
// glEnable(GL_POLYGON_SMOOTH); // creates issues with some graphic cards
glEnable( GL_NORMALIZE );
glEnable( GL_COLOR_MATERIAL );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
// speedups
//glEnable( GL_DITHER );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE );
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
// Initialize alpha blending function.
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
}
void EDA_3D_CANVAS::SetLights()
{
// activate light. the source is above the xy plane, at source_pos
GLfloat source_pos[4] = { m_lightPos.x, m_lightPos.y, m_lightPos.z, 0.0f };
GLfloat light_color[4]; // color of lights (RGBA values)
light_color[3] = 1.0;
// Light above the xy plane
light_color[0] = light_color[1] = light_color[2] = 0.0;
glLightfv( GL_LIGHT0, GL_AMBIENT, light_color );
light_color[0] = light_color[1] = light_color[2] = 1.0;
glLightfv( GL_LIGHT0, GL_DIFFUSE, light_color );
light_color[0] = light_color[1] = light_color[2] = 1.0;
glLightfv( GL_LIGHT0, GL_SPECULAR, light_color );
glLightfv( GL_LIGHT0, GL_POSITION, source_pos );
light_color[0] = light_color[1] = light_color[2] = 0.2;
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, light_color );
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
glEnable( GL_LIGHT0 ); // White spot on Z axis ( top )
glEnable( GL_LIGHTING );
}
void EDA_3D_CANVAS::TakeScreenshot( wxCommandEvent& event )
{
static wxFileName fn; // Remember path between saves during this session only.
wxString FullFileName;
wxString file_ext, mask;
bool fmt_is_jpeg = false;
// First time path is set to the project path.
if( !fn.IsOk() )
fn = Parent()->Prj().GetProjectFullName();
if( event.GetId() == ID_MENU_SCREENCOPY_JPEG )
fmt_is_jpeg = true;
if( event.GetId() != ID_TOOL_SCREENCOPY_TOCLIBBOARD )
{
file_ext = fmt_is_jpeg ? wxT( "jpg" ) : wxT( "png" );
mask = wxT( "*." ) + file_ext;
fn.SetExt( file_ext );
FullFileName = EDA_FILE_SELECTOR( _( "3D Image File Name:" ), fn.GetPath(),
fn.GetFullName(), file_ext, mask, this,
wxFD_SAVE | wxFD_OVERWRITE_PROMPT, true );
if( FullFileName.IsEmpty() )
return;
fn = FullFileName;
// Be sure the screen area destroyed by the file dialog is redrawn before making
// a screen copy.
// Without this call, under Linux the screen refresh is made to late.
wxYield();
}
struct viewport_params
{
GLint originx;
GLint originy;
GLint x;
GLint y;
} viewport;
// Be sure we have the latest 3D view (remember 3D view is buffered)
Refresh();
wxYield();
// Build image from the 3D buffer
wxWindowUpdateLocker noUpdates( this );
glGetIntegerv( GL_VIEWPORT, (GLint*) &viewport );
unsigned char* pixelbuffer = (unsigned char*) malloc( viewport.x * viewport.y * 3 );
unsigned char* alphabuffer = (unsigned char*) malloc( viewport.x * viewport.y );
wxImage image( viewport.x, viewport.y );
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
glReadBuffer( GL_BACK_LEFT );
glReadPixels( viewport.originx, viewport.originy,
viewport.x, viewport.y,
GL_RGB, GL_UNSIGNED_BYTE, pixelbuffer );
glReadPixels( viewport.originx, viewport.originy,
viewport.x, viewport.y,
GL_ALPHA, GL_UNSIGNED_BYTE, alphabuffer );
image.SetData( pixelbuffer );
image.SetAlpha( alphabuffer );
image = image.Mirror( false );
wxBitmap bitmap( image );
if( event.GetId() == ID_TOOL_SCREENCOPY_TOCLIBBOARD )
{
if( wxTheClipboard->Open() )
{
wxBitmapDataObject* dobjBmp = new wxBitmapDataObject( bitmap );
if( !wxTheClipboard->SetData( dobjBmp ) )
wxMessageBox( _( "Failed to copy image to clipboard" ) );
wxTheClipboard->Flush(); /* the data in clipboard will stay
* available after the application exits */
wxTheClipboard->Close();
}
}
else
{
wxImage image = bitmap.ConvertToImage();
if( !image.SaveFile( FullFileName,
fmt_is_jpeg ? wxBITMAP_TYPE_JPEG : wxBITMAP_TYPE_PNG ) )
wxMessageBox( _( "Can't save file" ) );
image.Destroy();
}
}
+375
View File
@@ -0,0 +1,375 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2015 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
*/
/**
* @file 3d_viewer.h
*/
#ifndef _3D_CANVAS_H_
#define _3D_CANVAS_H_
#include <wx/glcanvas.h>
#ifdef __WXMAC__
# ifdef __DARWIN__
# include <OpenGL/glu.h>
# else
# include <glu.h>
# endif
#else
# include <GL/glu.h>
#endif
#include <3d_struct.h>
#include <modelparsers.h>
#include <class_module.h>
#include <CBBox.h>
class BOARD_DESIGN_SETTINGS;
class EDA_3D_FRAME;
class SHAPE_POLY_SET;
class REPORTER;
class VIA;
class D_PAD;
// We are using GL lists to store layers and other items
// to draw or not
// GL_LIST_ID are the GL lists indexes in m_glLists
enum GL_LIST_ID
{
GL_ID_BEGIN = 0,
GL_ID_AXIS = GL_ID_BEGIN, // list id for 3D axis
GL_ID_GRID, // list id for 3D grid
GL_ID_BOARD, // List id for copper layers
GL_ID_TECH_LAYERS, // List id for non copper layers (masks...)
GL_ID_AUX_LAYERS, // List id for user layers (draw, eco, comment)
GL_ID_3DSHAPES_SOLID_FRONT, // List id for 3D shapes, non transparent entities
GL_ID_3DSHAPES_TRANSP_FRONT,// List id for 3D shapes, transparent entities
GL_ID_3DSHAPES_SOLID_BACK, // List id for 3D shapes, non transparent entities
GL_ID_3DSHAPES_TRANSP_BACK, // List id for 3D shapes, transparent entities
GL_ID_SHADOW_FRONT,
GL_ID_SHADOW_BACK,
GL_ID_SHADOW_BOARD,
GL_ID_BODY, // Body only list
GL_ID_END
};
class EDA_3D_CANVAS : public wxGLCanvas
{
private:
bool m_init;
bool m_reportWarnings; ///< true to report all warnings when building the 3D scene
///< false to report errors only
GLuint m_glLists[GL_ID_END]; ///< GL lists
wxGLContext* m_glRC;
wxRealPoint m_draw3dOffset; ///< offset to draw the 3D mesh.
double m_ZBottom; ///< position of the back layer
double m_ZTop; ///< position of the front layer
GLuint m_text_pcb; ///< an index to the texture generated for pcb texts
GLuint m_text_silk; ///< an index to the texture generated for silk layers
// Index to the textures generated for shadows
bool m_shadow_init;
GLuint m_text_fake_shadow_front;
GLuint m_text_fake_shadow_back;
GLuint m_text_fake_shadow_board;
CBBOX m_boardAABBox; ///< Axis Align Bounding Box of the board
CBBOX m_fastAABBox; ///< Axis Align Bounding Box that contain the other bounding boxes
CBBOX m_fastAABBox_Shadow; ///< A bit scalled version of the m_fastAABBox
S3D_VERTEX m_lightPos;
/// Stores the list of parsers for each new file name (dont repeat files already loaded)
std::vector<S3D_MODEL_PARSER *> m_model_parsers_list;
std::vector<wxString> m_model_filename_list;
void create_and_render_shadow_buffer( GLuint *aDst_gl_texture,
GLuint aTexture_size, bool aDraw_body, int aBlurPasses );
void calcBBox();
public:
EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList = 0 );
~EDA_3D_CANVAS();
EDA_3D_FRAME* Parent() const { return static_cast<EDA_3D_FRAME*>( GetParent() ); }
BOARD* GetBoard() { return Parent()->GetBoard(); }
/**
* Function ClearLists
* Clear the display list.
* @param aGlList = the list to clear.
* if 0 (default) all lists are cleared
*/
void ClearLists( int aGlList = 0 );
// Event functions:
void OnPaint( wxPaintEvent& event );
void OnEraseBackground( wxEraseEvent& event );
void OnChar( wxKeyEvent& event );
void OnMouseWheel( wxMouseEvent& event );
#ifdef USE_OSX_MAGNIFY_EVENT
void OnMagnify( wxMouseEvent& event );
#endif
void OnMouseMove( wxMouseEvent& event );
void OnRightClick( wxMouseEvent& event );
void OnPopUpMenu( wxCommandEvent& event );
/**
* Function TakeScreenshot
*
* creates a screenshot of the current 3D view and save to file as png or jpeg or image
* is copied to the clipboard
*/
void TakeScreenshot( wxCommandEvent& event );
void OnEnterWindow( wxMouseEvent& event );
// Display functions
void SetView3D( int keycode );
void DisplayStatus();
void Redraw();
void Render();
/**
* Function CreateDrawGL_List
* Prepares the parameters of the OpenGL draw list
* creates the OpenGL draw list items (board, grid ...)
* @param aErrorMessages = a REPORTER which will filled with error messages,
* if any
* @param aActivity = a REPORTER to display activity state
*/
void CreateDrawGL_List( REPORTER* aErrorMessages, REPORTER* aActivity );
void InitGL();
void ReportWarnings( bool aReport ) { m_reportWarnings = aReport; }
void SetLights();
void SetOffset(double aPosX, double aPosY)
{
m_draw3dOffset.x = aPosX;
m_draw3dOffset.y = aPosY;
}
/** @return the INFO3D_VISU which contains the current parameters
* to draw the 3D view og the board
*/
INFO3D_VISU& GetPrm3DVisu() const;
private:
/**
* return true if we are in realistic mode render
*/
bool isRealisticMode() const;
/**
* @return true if aItem should be displayed
* @param aItem = an item of DISPLAY3D_FLG enum
*/
bool isEnabled( DISPLAY3D_FLG aItem ) const;
/** Helper function
* @return true if aLayer should be displayed, false otherwise
*/
bool is3DLayerEnabled( LAYER_ID aLayer ) const;
/**
* @return the size of the board in pcb units
*/
wxSize getBoardSize() const;
/**
* @return the position of the board center in pcb units
*/
wxPoint getBoardCenter() const;
/**
* Helper function setGLTechLayersColor
* Initialize the color to draw the non copper layers
* in realistic mode and normal mode.
*/
void setGLTechLayersColor( LAYER_NUM aLayer );
/**
* Helper function setGLCopperColor
* Initialize the copper color to draw the board
* in realistic mode (a golden yellow color )
*/
void setGLCopperColor();
/**
* Helper function setGLEpoxyColor
* Initialize the color to draw the epoxy body board in realistic mode.
*/
void setGLEpoxyColor( float aTransparency = 1.0 );
/**
* Helper function setGLSolderMaskColor
* Initialize the color to draw the solder mask layers in realistic mode.
*/
void setGLSolderMaskColor( float aTransparency = 1.0 );
/**
* Function buildBoard3DView
* Called by CreateDrawGL_List()
* Populates the OpenGL GL_ID_BOARD draw list with board items only on copper layers.
* 3D footprint shapes, tech layers and aux layers are not on this list
* Fills aErrorMessages with error messages created by some calculation function
* display activity state
* @param aBoardList =
* @param aBodyOnlyList =
* @param aErrorMessages = a REPORTER to add error and warning messages
* created by the build process (can be NULL)
* @param aActivity = a REPORTER to display activity state
*/
void buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
REPORTER* aErrorMessages, REPORTER* aActivity );
/**
* Function buildTechLayers3DView
* Called by CreateDrawGL_List()
* Populates the OpenGL GL_ID_TECH_LAYERS draw list with items on tech layers
* @param aErrorMessages = a REPORTER to add error and warning messages
* created by the build process (can be NULL)
* @param aActivity = a REPORTER to display activity state
*/
void buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* aActivity );
/**
* Function buildBoardThroughHolesPolygonList
* Helper funtion to build the list of the board through holes polygons
* @param allBoardHoles = the SHAPE_POLY_SET to populate
* @param aSegCountPerCircle = the number of segments to approximate a circle
* @param aOptimizeLargeCircles = true to use more than aSegCountPerCircle
* for large circles (a large circle dimatere is > 1mm )
*/
void buildBoardThroughHolesPolygonList( SHAPE_POLY_SET& allBoardHoles,
int aSegCountPerCircle, bool aOptimizeLargeCircles );
/**
* Function buildShadowList
* Called by CreateDrawGL_List()
*/
void buildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList );
/**
* Function buildFootprintShape3DList
* Called by CreateDrawGL_List()
* Fills the OpenGL GL_ID_3DSHAPES_SOLID and GL_ID_3DSHAPES_TRANSP
* draw lists with 3D footprint shapes
* @param aOpaqueList is the gl list for non transparent items
* @param aTransparentList is the gl list for non transparent items,
* @param aErrorMessages = a REPORTER to add error and warning messages
* created by the build process (can be NULL)
* @param aActivity = a REPORTER to display activity state
* which need to be drawn after all other items
*/
void buildFootprintShape3DList( GLuint aOpaqueList,
GLuint aTransparentList,
REPORTER* aErrorMessages, REPORTER* aActivity );
/**
* Function buildBoard3DAuxLayers
* Called by CreateDrawGL_List()
* Fills the OpenGL GL_ID_AUX_LAYERS draw list
* with items on aux layers only
* @param aErrorMessages = a REPORTER to add error and warning messages
* created by the build process (can be NULL)
* @param aActivity = a REPORTER to display activity state
* which need to be drawn after all other items
*/
void buildBoard3DAuxLayers( REPORTER* aErrorMessages, REPORTER* aActivity );
void draw3DGrid( double aGriSizeMM );
void draw3DAxis();
/**
* Helper function BuildPadShapeThickOutlineAsPolygon:
* Build a pad outline as non filled polygon, to draw pads on silkscreen layer
* with a line thickness = aWidth
* Used only to draw pads outlines on silkscreen layers.
*/
void buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
SHAPE_POLY_SET& aCornerBuffer,
int aWidth,
int aCircleToSegmentsCount,
double aCorrectionFactor );
/**
* Helper function draw3DViaHole:
* Draw the via hole:
* Build a vertical hole (a cylinder) between the first and the last via layers
*/
void draw3DViaHole( const VIA * aVia );
/**
* Helper function draw3DPadHole:
* Draw the pad hole:
* Build a vertical hole (round or oblong) between the front and back layers
*/
void draw3DPadHole( const D_PAD * aPad );
/**
* function render3DComponentShape
* insert mesh in gl list
* @param module
* @param aIsRenderingJustNonTransparentObjects = true to load non transparent objects
* @param aIsRenderingJustTransparentObjects = true to load non transparent objects
* in openGL, transparent objects should be drawn *after* non transparent objects
*/
void render3DComponentShape( MODULE* module,
bool aIsRenderingJustNonTransparentObjects,
bool aIsRenderingJustTransparentObjects );
/**
* function read3DComponentShape
* read the 3D component shape(s) of the footprint (physical shape).
* @param module
* @return true if load was succeeded, false otherwise
*/
bool read3DComponentShape( MODULE* module );
/**
* function generateFakeShadowsTextures
* creates shadows of the board an footprints
* for aesthetical purpose
* @param aErrorMessages = a REPORTER to add error and warning messages
* created by the build process (can be NULL)
* @param aActivity = a REPORTER to display activity state
*/
void generateFakeShadowsTextures( REPORTER* aErrorMessages, REPORTER* aActivity );
DECLARE_EVENT_TABLE()
};
void CheckGLError(const char *aFileName, int aLineNumber);
#endif /* _3D_CANVAS_H_ */
File diff suppressed because it is too large Load Diff
-537
View File
@@ -1,537 +0,0 @@
/*
* 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) 2023 CERN
* Copyright The 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 BOARD_ADAPTER_H
#define BOARD_ADAPTER_H
#include <array>
#include <vector>
#include "../3d_rendering/raytracing/accelerators/container_2d.h"
#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_cache/3d_cache.h"
#include "../common_ogl/ogl_attr_list.h"
#include "../3d_viewer/eda_3d_viewer_settings.h"
#include <layer_ids.h>
#include <pad.h>
#include <pcb_track.h>
#include <pcb_base_frame.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <pcb_table.h>
#include <pcb_shape.h>
#include <pcb_dimension.h>
#include <zone.h>
#include <footprint.h>
#include <reporter.h>
#include <dialogs/dialog_color_picker.h>
class COLOR_SETTINGS;
class PCB_TEXTBOX;
/// A type that stores a container of 2d objects for each layer id
typedef std::map<PCB_LAYER_ID, BVH_CONTAINER_2D*> MAP_CONTAINER_2D_BASE;
/// A type that stores polysets for each layer id
typedef std::map<PCB_LAYER_ID, SHAPE_POLY_SET*> MAP_POLY;
/// This defines the range that all coord will have to be rendered.
/// It will use this value to convert to a normalized value between
/// -(RANGE_SCALE_3D/2) .. +(RANGE_SCALE_3D/2)
#define RANGE_SCALE_3D 8.0f
/**
* Helper class to handle information needed to display 3D board.
*/
class BOARD_ADAPTER
{
public:
BOARD_ADAPTER();
~BOARD_ADAPTER();
/**
* Update the cache manager pointer.
*
* @param aCachePointer: the pointer to the 3D cache manager.
*/
void Set3dCacheManager( S3D_CACHE* aCacheMgr ) noexcept { m_3dModelManager = aCacheMgr; }
S3D_CACHE* Get3dCacheManager() const noexcept { return m_3dModelManager; }
/**
* Check if a layer is enabled.
*
* @param aLayer layer ID to get status.
*/
bool Is3dLayerEnabled( PCB_LAYER_ID aLayer,
const std::bitset<LAYER_3D_END>& aVisibilityFlags ) const;
/**
* Test if footprint should be displayed in relation to attributes and the flags.
*/
bool IsFootprintShown( FOOTPRINT_ATTR_T aFPAttributes ) const;
/**
* Set current board to be rendered.
*
* @param aBoard board to process.
*/
void SetBoard( BOARD* aBoard ) noexcept { m_board = aBoard; }
const BOARD* GetBoard() const noexcept { return m_board; }
void ReloadColorSettings() noexcept;
/**
* Build a color list which is used to store colors layers
*/
std::map<int, COLOR4D> GetLayerColors() const;
/**
* Build the copper color list used by the board editor, and store it in m_BoardEditorColors
*/
void GetBoardEditorCopperLayerColors( PCBNEW_SETTINGS* aCfg );
std::map<int, COLOR4D> GetDefaultColors() const;
void SetLayerColors( const std::map<int, COLOR4D>& aColors );
std::bitset<LAYER_3D_END> GetVisibleLayers() const;
std::bitset<LAYER_3D_END> GetDefaultVisibleLayers() const;
void SetVisibleLayers( const std::bitset<LAYER_3D_END>& aLayers );
/**
* Function to be called by the render when it need to reload the settings for the board.
*
* @param aStatusReporter the pointer for the status reporter.
* @param aWarningReporter pointer for the warning reporter.
*/
void InitSettings( REPORTER* aStatusReporter, REPORTER* aWarningReporter );
/**
* Board integer units To 3D units.
*
* @return the conversion factor to transform a position from the board to 3D units.
*/
double BiuTo3dUnits() const noexcept { return m_biuTo3Dunits; }
/**
* Get the board outline bounding box.
*
* @return the board bounding box in 3D units.
*/
const BBOX_3D& GetBBox() const noexcept { return m_boardBoundingBox; }
/**
* Get the board body thickness, including internal copper layers (in 3D units).
*/
float GetBoardBodyThickness() const noexcept { return m_boardBodyThickness3DU; }
/**
* Get the non copper layers thickness (in 3D units).
*/
float GetNonCopperLayerThickness() const noexcept { return m_nonCopperLayerThickness3DU; }
/**
* Get the copper layer thicknesses (in 3D units).
*/
float GetFrontCopperThickness() const noexcept { return m_frontCopperThickness3DU; }
float GetBackCopperThickness() const noexcept { return m_backCopperThickness3DU; }
/**
* Get the hole plating thickness (NB: in BOARD UNITS!).
*/
int GetHolePlatingThickness() const noexcept;
/**
* Get the board size.
*
* @return size in BIU units.
*/
VECTOR2I GetBoardSize() const noexcept { return m_boardSize; }
/**
* Get the board center.
*
* @return position in BIU units.
*/
VECTOR2I GetBoardPos() const noexcept { return m_boardPos; }
/**
* The board center position in 3D units.
*
* @return board center vector position in 3D units.
*/
const SFVEC3F& GetBoardCenter() const noexcept { return m_boardCenter; }
/**
* Get the position of the footprint in 3d integer units considering if it is flipped or not.
*
* @param aIsFlipped true for use in footprints on Front (top) layer, false
* if footprint is on back (bottom) layer.
* @return the Z position of 3D shapes, in 3D integer units.
*/
float GetFootprintZPos( bool aIsFlipped ) const ;
/**
* Get the current polygon of the epoxy board.
*
* @return the shape polygon
*/
const SHAPE_POLY_SET& GetBoardPoly() const noexcept { return m_board_poly; }
/**
* Get the technical color of a layer.
*
* @param aLayerId the layer to get the color information.
* @return the color in SFVEC3F format.
*/
SFVEC4F GetLayerColor( PCB_LAYER_ID aLayerId ) const;
/**
* Get the technical color of a layer.
*
* @param aItemId the item id to get the color information.
* @return the color in SFVEC3F format.
*/
SFVEC4F GetItemColor( int aItemId ) const;
/**
* @param[in] aColor is the color mapped.
* @return the color in SFVEC3F format
*/
SFVEC4F GetColor( const COLOR4D& aColor ) const;
SFVEC2F GetSphericalCoord( int i ) const;
/**
* Get the top z position.
*
* @param aLayerId layer id.
* @return position in 3D units.
*/
float GetLayerTopZPos( PCB_LAYER_ID aLayerId ) const noexcept
{
auto it = m_layerZcoordTop.find( aLayerId );
if( it != m_layerZcoordTop.end() )
return it->second;
else
return -( m_boardBodyThickness3DU / 2.0f );
}
/**
* Get the bottom z position.
*
* @param aLayerId layer id.
* @return position in 3D units.
*/
float GetLayerBottomZPos( PCB_LAYER_ID aLayerId ) const noexcept
{
auto it = m_layerZcoordBottom.find( aLayerId );
if( it != m_layerZcoordBottom.end() )
return it->second;
else
return -( m_boardBodyThickness3DU / 2.0f ) - m_backCopperThickness3DU;
}
/**
* Get the map of containers that have the objects per layer.
*
* @return the map containers of this board.
*/
const MAP_CONTAINER_2D_BASE& GetLayerMap() const noexcept { return m_layerMap; }
const BVH_CONTAINER_2D* GetPlatedPadsFront() const noexcept { return m_platedPadsFront; }
const BVH_CONTAINER_2D* GetPlatedPadsBack() const noexcept { return m_platedPadsBack; }
const BVH_CONTAINER_2D* GetOffboardPadsFront() const noexcept { return m_offboardPadsFront; }
const BVH_CONTAINER_2D* GetOffboardPadsBack() const noexcept { return m_offboardPadsBack; }
const MAP_CONTAINER_2D_BASE& GetLayerHoleMap() const noexcept { return m_layerHoleMap; }
const BVH_CONTAINER_2D& GetTH_IDs() const noexcept { return m_TH_IDs; }
const BVH_CONTAINER_2D& GetTH_ODs() const noexcept { return m_TH_ODs; }
/**
* Get through hole outside diameter 2D polygons.
*
* The outside diameter 2D polygon is the hole diameter plus the plating thickness.
*
* @return a container with through hold outside diameter 2D polygons.
*/
const SHAPE_POLY_SET& GetTH_ODPolys() const noexcept
{
return m_TH_ODPolys;
}
const BVH_CONTAINER_2D& GetViaAnnuli() const noexcept
{
return m_viaAnnuli;
}
const SHAPE_POLY_SET& GetViaAnnuliPolys() const noexcept
{
return m_viaAnnuliPolys;
}
const SHAPE_POLY_SET& GetNPTH_ODPolys() const noexcept
{
return m_NPTH_ODPolys;
}
/**
* @return a container with through hole via hole outside diameters.
*/
const BVH_CONTAINER_2D& GetViaTH_ODs() const noexcept
{
return m_viaTH_ODs;
}
const SHAPE_POLY_SET& GetViaTH_ODPolys() const noexcept
{
return m_viaTH_ODPolys;
}
unsigned int GetViaCount() const noexcept { return m_viaCount; }
unsigned int GetHoleCount() const noexcept { return m_holeCount; }
/**
* @return via hole average diameter dimension in 3D units.
*/
float GetAverageViaHoleDiameter() const noexcept { return m_averageViaHoleDiameter; }
/**
* @return the average diameter of through holes in 3D units.
*/
float GetAverageHoleDiameter() const noexcept { return m_averageHoleDiameter; }
/**
* @return average track width in 3D units.
*/
float GetAverageTrackWidth() const noexcept { return m_averageTrackWidth; }
/**
* @param aDiameter3DU diameter in 3DU.
* @return number of sides that should be used in a circle with \a aDiameter3DU.
*/
unsigned int GetCircleSegmentCount( float aDiameter3DU ) const;
/**
* @param aDiameterBIU diameter in board internal units.
* @return number of sides that should be used in circle with \a aDiameterBIU.
*/
unsigned int GetCircleSegmentCount( int aDiameterBIU ) const;
/**
* Get map of polygon's layers.
*
* @return the map with polygon's layers.
*/
const MAP_POLY& GetPolyMap() const noexcept { return m_layers_poly; }
const SHAPE_POLY_SET* GetFrontPlatedPadAndGraphicPolys()
{
return m_frontPlatedPadAndGraphicPolys;
}
const SHAPE_POLY_SET* GetBackPlatedPadAndGraphicPolys()
{
return m_backPlatedPadAndGraphicPolys;
}
const MAP_POLY& GetHoleIdPolysMap() const noexcept { return m_layerHoleIdPolys; }
const MAP_POLY& GetHoleOdPolysMap() const noexcept { return m_layerHoleOdPolys; }
private:
/**
* Create the board outline polygon.
*
* @return false if the outline could not be created
*/
bool createBoardPolygon( wxString* aErrorMsg );
void createLayers( REPORTER* aStatusReporter );
void destroyLayers();
// Helper functions to create the board
void createTrackWithMargin( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer,
PCB_LAYER_ID aLayer, int aMargin = 0 );
void createPadWithMargin( const PAD *aPad, CONTAINER_2D_BASE* aDstContainer,
PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const;
void createPadWithHole( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer,
int aInflateValue );
void addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer,
PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads );
void addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer,
PCB_LAYER_ID aLayerId,
const std::bitset<LAYER_3D_END>& aVisibilityFlags );
void addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aDstContainer,
const BOARD_ITEM* aOwner );
void addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM* aOwner, PCB_LAYER_ID aLayer );
void addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aDstContainer,
const BOARD_ITEM* aOwner );
void addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM* aOwner );
void addTable( const PCB_TABLE* aTable, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM* aOwner );
void addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aDstContainer,
PCB_LAYER_ID aLayerId );
void createArcSegments( const VECTOR2I& aCentre, const VECTOR2I& aStart,
const EDA_ANGLE& aArcAngle, int aCircleToSegmentsCount, int aWidth,
CONTAINER_2D_BASE* aContainer, const BOARD_ITEM& aOwner );
void buildPadOutlineAsSegments( const PAD* aPad, PCB_LAYER_ID aLayer,
CONTAINER_2D_BASE* aDstContainer, int aWidth );
public:
static CUSTOM_COLORS_LIST g_SilkColors;
static CUSTOM_COLORS_LIST g_MaskColors;
static CUSTOM_COLORS_LIST g_PasteColors;
static CUSTOM_COLORS_LIST g_FinishColors;
static CUSTOM_COLORS_LIST g_BoardColors;
static KIGFX::COLOR4D g_DefaultBackgroundTop;
static KIGFX::COLOR4D g_DefaultBackgroundBot;
static KIGFX::COLOR4D g_DefaultSilkscreen;
static KIGFX::COLOR4D g_DefaultSolderMask;
static KIGFX::COLOR4D g_DefaultSolderPaste;
static KIGFX::COLOR4D g_DefaultSurfaceFinish;
static KIGFX::COLOR4D g_DefaultBoardBody;
static KIGFX::COLOR4D g_DefaultComments;
static KIGFX::COLOR4D g_DefaultECOs;
public:
EDA_3D_VIEWER_SETTINGS* m_Cfg;
bool m_IsBoardView;
bool m_MousewheelPanning;
bool m_IsPreviewer; ///< true if we're in a 3D preview panel, false
///< for the standard 3D viewer
SFVEC4F m_BgColorBot; ///< background bottom color
SFVEC4F m_BgColorTop; ///< background top color
SFVEC4F m_BoardBodyColor; ///< in realistic mode: FR4 board color
SFVEC4F m_SolderMaskColorBot; ///< in realistic mode: solder mask color ( bot )
SFVEC4F m_SolderMaskColorTop; ///< in realistic mode: solder mask color ( top )
SFVEC4F m_SolderPasteColor; ///< in realistic mode: solder paste color
SFVEC4F m_SilkScreenColorBot; ///< in realistic mode: SilkScreen color ( bot )
SFVEC4F m_SilkScreenColorTop; ///< in realistic mode: SilkScreen color ( top )
SFVEC4F m_CopperColor; ///< in realistic mode: copper color
SFVEC4F m_UserDrawingsColor;
SFVEC4F m_UserCommentsColor;
SFVEC4F m_ECO1Color;
SFVEC4F m_ECO2Color;
std::map<int, COLOR4D> m_ColorOverrides; ///< allows to override color scheme colors
std::map<int, COLOR4D> m_BoardEditorColors; ///< list of colors used by the board editor
private:
BOARD* m_board;
S3D_CACHE* m_3dModelManager;
COLOR_SETTINGS* m_colors;
VECTOR2I m_boardPos; ///< Board center position in board internal units.
VECTOR2I m_boardSize; ///< Board size in board internal units.
SFVEC3F m_boardCenter; ///< 3D center position of the board in 3D units.
BBOX_3D m_boardBoundingBox; ///< 3D bounding box of the board in 3D units.
MAP_POLY m_layers_poly; ///< Amalgamated polygon contours for various types
///< of items
SHAPE_POLY_SET* m_frontPlatedPadAndGraphicPolys;
SHAPE_POLY_SET* m_backPlatedPadAndGraphicPolys;
SHAPE_POLY_SET* m_frontPlatedCopperPolys;
SHAPE_POLY_SET* m_backPlatedCopperPolys;
MAP_POLY m_layerHoleOdPolys; ///< Hole outer diameters (per layer)
MAP_POLY m_layerHoleIdPolys; ///< Hole inner diameters (per layer)
SHAPE_POLY_SET m_NPTH_ODPolys; ///< NPTH outer diameters
SHAPE_POLY_SET m_TH_ODPolys; ///< PTH outer diameters
SHAPE_POLY_SET m_viaTH_ODPolys; ///< Via hole outer diameters
SHAPE_POLY_SET m_viaAnnuliPolys; ///< Via annular ring outer diameters
SHAPE_POLY_SET m_board_poly; ///< Board outline polygon.
MAP_CONTAINER_2D_BASE m_layerMap; ///< 2D elements for each layer.
MAP_CONTAINER_2D_BASE m_layerHoleMap; ///< Holes for each layer.
BVH_CONTAINER_2D* m_platedPadsFront;
BVH_CONTAINER_2D* m_platedPadsBack;
BVH_CONTAINER_2D* m_offboardPadsFront;
BVH_CONTAINER_2D* m_offboardPadsBack;
BVH_CONTAINER_2D m_TH_ODs; ///< List of PTH outer diameters
BVH_CONTAINER_2D m_TH_IDs; ///< List of PTH inner diameters
BVH_CONTAINER_2D m_viaAnnuli; ///< List of via annular rings
BVH_CONTAINER_2D m_viaTH_ODs; ///< List of via hole outer diameters
unsigned int m_copperLayersCount;
double m_biuTo3Dunits; ///< Scale factor to convert board internal units
///< to 3D units normalized between -1.0 and 1.0.
std::map<PCB_LAYER_ID, float> m_layerZcoordTop; ///< Top (End) Z position of each
///< layer in 3D units.
std::map<PCB_LAYER_ID, float> m_layerZcoordBottom; ///< Bottom (Start) Z position of
///< each layer in 3D units.
float m_frontCopperThickness3DU;
float m_backCopperThickness3DU;
float m_boardBodyThickness3DU;
float m_nonCopperLayerThickness3DU;
float m_solderPasteLayerThickness3DU;
unsigned int m_trackCount;
float m_averageTrackWidth;
unsigned int m_viaCount;
float m_averageViaHoleDiameter;
unsigned int m_holeCount;
float m_averageHoleDiameter;
/**
* Trace mask used to enable or disable debug output for this class. Output can be turned
* on by setting the WXTRACE environment variable to "KI_TRACE_EDA_CINFO3D_VISU". See the
* wxWidgets documentation on wxLogTrace for more information.
*/
static const wxChar* m_logTrace;
};
#endif // BOARD_ADAPTER_H
@@ -1,840 +0,0 @@
/*
* 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) 2023 CERN
* Copyright The 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
*/
/**
* @file create_3Dgraphic_brd_items.cpp
* @brief This file implements the creation of 2D graphic primitives of pcb items:
* pads, tracks, drawsegments, texts....
*/
#include "../3d_rendering/raytracing/shapes2D/ring_2d.h"
#include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h"
#include "../3d_rendering/raytracing/shapes2D/round_segment_2d.h"
#include "../3d_rendering/raytracing/shapes2D/triangle_2d.h"
#include <board_adapter.h>
#include <board.h>
#include <footprint.h>
#include <pad.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <pcb_table.h>
#include <board_design_settings.h>
#include <pcb_painter.h> // for PCB_RENDER_SETTINGS
#include <zone.h>
#include <convert_basic_shapes_to_polygon.h>
#include <trigo.h>
#include <geometry/shape_segment.h>
#include <geometry/geometry_utils.h>
#include <geometry/shape_circle.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_simple.h>
#include <utility>
#include <vector>
#include <wx/log.h>
#include <macros.h>
#include <callback_gal.h>
#define TO_3DU( x ) ( ( x ) * m_biuTo3Dunits )
#define TO_SFVEC2F( vec ) SFVEC2F( TO_3DU( vec.x ), TO_3DU( -vec.y ) )
void addFILLED_CIRCLE_2D( CONTAINER_2D_BASE* aContainer, const SFVEC2F& aCenter, float aRadius,
const BOARD_ITEM& aBoardItem )
{
if( aRadius > 0.0f )
aContainer->Add( new FILLED_CIRCLE_2D( aCenter, aRadius, aBoardItem ) );
}
void addRING_2D( CONTAINER_2D_BASE* aContainer, const SFVEC2F& aCenter, float aInnerRadius,
float aOuterRadius, const BOARD_ITEM& aBoardItem )
{
if( aOuterRadius > aInnerRadius && aInnerRadius > 0.0f )
aContainer->Add( new RING_2D( aCenter, aInnerRadius, aOuterRadius, aBoardItem ) );
}
void addROUND_SEGMENT_2D( CONTAINER_2D_BASE* aContainer, const SFVEC2F& aStart, const SFVEC2F& aEnd,
float aWidth, const BOARD_ITEM& aBoardItem )
{
if( Is_segment_a_circle( aStart, aEnd ) )
{
// Cannot add segments that have the same start and end point
addFILLED_CIRCLE_2D( aContainer, aStart, aWidth / 2, aBoardItem );
return;
}
if( aWidth > 0.0f )
aContainer->Add( new ROUND_SEGMENT_2D( aStart, aEnd, aWidth, aBoardItem ) );
}
void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM* aOwner )
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
float penWidth_3DU = TO_3DU( aText->GetEffectiveTextPenWidth() );
KIFONT::FONT* font = aText->GetFont();
wxString shownText = aText->GetShownText( true );
if( !font )
font = KIFONT::FONT::GetFont( wxEmptyString, aText->IsBold(), aText->IsItalic() );
if( aOwner && aOwner->IsKnockout() )
{
SHAPE_POLY_SET finalPoly;
const PCB_TEXT* pcbText = static_cast<const PCB_TEXT*>( aOwner );
pcbText->TransformTextToPolySet( finalPoly, 0, m_board->GetDesignSettings().m_MaxError,
ERROR_INSIDE );
// Do not call finalPoly.Fracture() here: ConvertPolygonToTriangles() call it
// if needed, and Fracture() called twice can create bad results and is useless
ConvertPolygonToTriangles( finalPoly, *aContainer, m_biuTo3Dunits, *aOwner );
}
else
{
CALLBACK_GAL callback_gal( empty_opts,
// Stroke callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
{
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( aPt1 ), TO_SFVEC2F( aPt2 ),
penWidth_3DU, *aOwner );
},
// Triangulation callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
{
aContainer->Add( new TRIANGLE_2D( TO_SFVEC2F( aPt1 ), TO_SFVEC2F( aPt2 ),
TO_SFVEC2F( aPt3 ), *aOwner ) );
} );
attrs.m_Angle = aText->GetDrawRotation();
if( auto* cache = aText->GetRenderCache( font, shownText ) )
{
callback_gal.DrawGlyphs( *cache );
}
else
{
font->Draw( &callback_gal, shownText, aText->GetDrawPos(), attrs,
aOwner->GetFontMetrics() );
}
}
}
void BOARD_ADAPTER::addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM* aOwner )
{
addText( aDimension, aContainer, aDimension );
const int linewidth = aDimension->GetLineThickness();
for( const std::shared_ptr<SHAPE>& shape : aDimension->GetShapes() )
{
switch( shape->Type() )
{
case SH_SEGMENT:
{
const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( seg.A ), TO_SFVEC2F( seg.B ),
TO_3DU( linewidth ), *aOwner );
break;
}
case SH_CIRCLE:
{
int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
float innerR3DU = TO_3DU( radius ) - TO_3DU( aDimension->GetLineThickness() ) / 2.0f;
float outerR3DU = TO_3DU( radius ) + TO_3DU( aDimension->GetLineThickness() ) / 2.0f;
addRING_2D( aContainer, TO_SFVEC2F( shape->Centre() ), innerR3DU, outerR3DU, *aOwner );
break;
}
default:
break;
}
}
}
void BOARD_ADAPTER::addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer,
PCB_LAYER_ID aLayerId,
const std::bitset<LAYER_3D_END>& aVisibilityFlags )
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
for( PCB_FIELD* field : aFootprint->GetFields() )
{
if( field->GetLayer() == aLayerId && field->IsVisible() )
{
if( !aVisibilityFlags.test( LAYER_FP_TEXT ) )
continue;
else if( field->IsReference() && !aVisibilityFlags.test( LAYER_FP_REFERENCES ) )
continue;
else if( field->IsValue() && !aVisibilityFlags.test( LAYER_FP_VALUES ) )
continue;
addText( field, aContainer, field );
}
}
for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
{
switch( item->Type() )
{
case PCB_TEXT_T:
{
PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
if( text->GetLayer() == aLayerId && text->IsVisible() )
{
if( !aVisibilityFlags.test( LAYER_FP_TEXT ) )
continue;
else if( text->GetText() == wxT( "${REFERENCE}" )
&& !aVisibilityFlags.test( LAYER_FP_REFERENCES ) )
continue;
else if( text->GetText() == wxT( "${VALUE}" )
&& !aVisibilityFlags.test( LAYER_FP_VALUES ) )
continue;
addText( text, aContainer, text );
}
break;
}
case PCB_TEXTBOX_T:
{
PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
if( textbox->GetLayer() == aLayerId )
addShape( textbox, aContainer, aFootprint );
break;
}
case PCB_TABLE_T:
{
PCB_TABLE* table = static_cast<PCB_TABLE*>( item );
if( table->GetLayer() == aLayerId )
addTable( table, aContainer, aFootprint );
break;
}
case PCB_DIM_ALIGNED_T:
case PCB_DIM_CENTER_T:
case PCB_DIM_ORTHOGONAL_T:
case PCB_DIM_RADIAL_T:
case PCB_DIM_LEADER_T:
{
PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( item );
if( dimension->GetLayer() == aLayerId )
addShape( dimension, aContainer, aFootprint );
break;
}
case PCB_SHAPE_T:
{
PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
if( shape->IsOnLayer( aLayerId ) )
addShape( shape, aContainer, aFootprint, aLayerId );
break;
}
default:
break;
}
}
}
void BOARD_ADAPTER::createTrackWithMargin( const PCB_TRACK* aTrack,
CONTAINER_2D_BASE* aDstContainer, PCB_LAYER_ID aLayer,
int aMargin )
{
SFVEC2F start3DU = TO_SFVEC2F( aTrack->GetStart() );
SFVEC2F end3DU = TO_SFVEC2F( aTrack->GetEnd() );
switch( aTrack->Type() )
{
case PCB_VIA_T:
{
const PCB_VIA* via = static_cast<const PCB_VIA*>( aTrack );
float width3DU = TO_3DU( via->GetWidth( aLayer ) + aMargin * 2 );
addFILLED_CIRCLE_2D( aDstContainer, start3DU, width3DU / 2.0, *aTrack );
break;
}
case PCB_ARC_T:
{
const PCB_ARC* arc = static_cast<const PCB_ARC*>( aTrack );
if( arc->IsDegenerated() )
{
// Draw this very small arc like a track segment (a PCB_TRACE_T)
PCB_TRACK track( arc->GetParent() );
track.SetStart( arc->GetStart() );
track.SetEnd( arc->GetEnd() );
track.SetWidth( arc->GetWidth() );
track.SetLayer( arc->GetLayer() );
createTrackWithMargin( &track, aDstContainer, aLayer, aMargin );
return;
}
VECTOR2I center( arc->GetCenter() );
EDA_ANGLE arc_angle = arc->GetAngle();
double radius = arc->GetRadius();
int arcsegcount = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF, arc_angle );
int circlesegcount;
// Avoid arcs that cannot be drawn
if( radius < std::numeric_limits<double>::min() || arc_angle.IsZero() )
break;
// We need a circle to segment count. However, the arc angle can be small, and the
// radius very big. so we calculate a reasonable value for circlesegcount.
if( arcsegcount <= 1 ) // The arc will be approximated by a segment
{
circlesegcount = 1;
}
else
{
circlesegcount = KiROUND( arcsegcount * 360.0 / std::abs( arc_angle.AsDegrees() ) );
circlesegcount = std::clamp( circlesegcount, 1, 128 );
}
createArcSegments( center, arc->GetStart(), arc_angle, circlesegcount,
arc->GetWidth() + aMargin * 2,
aDstContainer, *arc );
break;
}
case PCB_TRACE_T: // Track is a usual straight segment
{
float width3DU = TO_3DU( aTrack->GetWidth() + aMargin * 2 );
addROUND_SEGMENT_2D( aDstContainer, start3DU, end3DU, width3DU, *aTrack );
break;
}
default:
break;
}
}
void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aContainer,
PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const
{
SHAPE_POLY_SET poly;
int maxError = GetBoard()->GetDesignSettings().m_MaxError;
VECTOR2I clearance = aMargin;
// Our shape-based builder can't handle negative or differing x:y clearance values (the
// former are common for solder paste while the later get generated when a relative paste
// margin is used with an oblong pad). So we apply this huge hack and fake a larger pad to
// run the general-purpose polygon builder on.
// Of course being a hack it falls down when dealing with custom shape pads (where the size
// is only the size of the anchor), so for those we punt and just use aMargin.x.
if( ( clearance.x < 0 || clearance.x != clearance.y )
&& aPad->GetShape( aLayer ) != PAD_SHAPE::CUSTOM )
{
VECTOR2I dummySize = VECTOR2I( aPad->GetSize( aLayer ) ) + clearance + clearance;
if( dummySize.x <= 0 || dummySize.y <= 0 )
return;
PAD dummy( *aPad );
dummy.SetSize( aLayer, VECTOR2I( dummySize.x, dummySize.y ) );
dummy.TransformShapeToPolygon( poly, aLayer, 0, maxError, ERROR_INSIDE );
clearance = { 0, 0 };
// Remove group membership from dummy item before deleting
dummy.SetParentGroup( nullptr );
}
else if( aPad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
{
// A custom pad can have many complex subshape items. To avoid issues, use its
// final polygon shape, not its basic shape set. One cannot apply the clearance
// to each subshape: it does no work
aPad->TransformShapeToPolygon( poly, aLayer, 0, maxError );
}
else
{
auto padShapes =
std::static_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape( aLayer ) );
for( const SHAPE* shape : padShapes->Shapes() )
{
switch( shape->Type() )
{
case SH_SEGMENT:
{
const SHAPE_SEGMENT* seg = static_cast<const SHAPE_SEGMENT*>( shape );
addROUND_SEGMENT_2D( aContainer,
TO_SFVEC2F( seg->GetSeg().A ),
TO_SFVEC2F( seg->GetSeg().B ),
TO_3DU( seg->GetWidth() + clearance.x * 2 ),
*aPad );
break;
}
case SH_CIRCLE:
{
const SHAPE_CIRCLE* circle = static_cast<const SHAPE_CIRCLE*>( shape );
addFILLED_CIRCLE_2D( aContainer,
TO_SFVEC2F( circle->GetCenter() ),
TO_3DU( circle->GetRadius() + clearance.x ),
*aPad );
break;
}
case SH_RECT:
{
const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>( shape );
poly.NewOutline();
poly.Append( rect->GetPosition() );
poly.Append( rect->GetPosition().x + rect->GetSize().x, rect->GetPosition().y );
poly.Append( rect->GetPosition() + rect->GetSize() );
poly.Append( rect->GetPosition().x, rect->GetPosition().y + rect->GetSize().y );
break;
}
case SH_SIMPLE:
poly.AddOutline( static_cast<const SHAPE_SIMPLE*>( shape )->Vertices() );
break;
case SH_POLY_SET:
poly.Append( *static_cast<const SHAPE_POLY_SET*>( shape ) );
break;
case SH_ARC:
{
const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( shape );
SHAPE_LINE_CHAIN l = arc->ConvertToPolyline( maxError );
for( int i = 0; i < l.SegmentCount(); i++ )
{
SHAPE_SEGMENT seg( l.Segment( i ).A, l.Segment( i ).B, arc->GetWidth() );
addROUND_SEGMENT_2D( aContainer,
TO_SFVEC2F( seg.GetSeg().A ),
TO_SFVEC2F( seg.GetSeg().B ),
TO_3DU( arc->GetWidth() + clearance.x * 2 ),
*aPad );
}
break;
}
default:
UNIMPLEMENTED_FOR( SHAPE_TYPE_asString( shape->Type() ) );
break;
}
}
}
if( !poly.IsEmpty() )
{
if( clearance.x )
poly.Inflate( clearance.x, CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
// Add the PAD polygon
ConvertPolygonToTriangles( poly, *aContainer, m_biuTo3Dunits, *aPad );
}
}
void BOARD_ADAPTER::createPadWithHole( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer,
int aInflateValue )
{
if( !aPad->HasHole() )
{
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::createPadWithHole - found an invalid pad" ) );
return;
}
std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
addROUND_SEGMENT_2D( aDstContainer,
TO_SFVEC2F( slot->GetSeg().A ),
TO_SFVEC2F( slot->GetSeg().B ),
TO_3DU( slot->GetWidth() + aInflateValue * 2 ),
*aPad );
}
void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer,
PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads )
{
for( PAD* pad : aFootprint->Pads() )
{
if( !pad->IsOnLayer( aLayerId ) )
continue;
if( IsCopperLayer( aLayerId ) )
{
// Skip pad annulus when there isn't one (note: this is more discerning than
// pad->IsOnLayer(), which doesn't check for NPTH pads with holes that consume
// the entire pad).
if( !pad->IsOnCopperLayer() )
continue;
// Skip pad annulus when not connected on this layer (if removing is enabled)
if( !pad->FlashLayer( aLayerId ) )
continue;
}
VECTOR2I margin( 0, 0 );
switch( aLayerId )
{
case F_Cu:
if( aSkipPlatedPads && pad->FlashLayer( F_Mask ) )
continue;
if( aSkipNonPlatedPads && !pad->FlashLayer( F_Mask ) )
continue;
break;
case B_Cu:
if( aSkipPlatedPads && pad->FlashLayer( B_Mask ) )
continue;
if( aSkipNonPlatedPads && !pad->FlashLayer( B_Mask ) )
continue;
break;
case F_Mask:
case B_Mask:
margin.x += pad->GetSolderMaskExpansion( aLayerId );
margin.y += pad->GetSolderMaskExpansion( aLayerId );
break;
case F_Paste:
case B_Paste:
margin += pad->GetSolderPasteMargin( aLayerId );
break;
default:
break;
}
createPadWithMargin( pad, aContainer, aLayerId, margin );
}
}
// based on TransformArcToPolygon function from
// common/convert_basic_shapes_to_polygon.cpp
void BOARD_ADAPTER::createArcSegments( const VECTOR2I& aCentre, const VECTOR2I& aStart,
const EDA_ANGLE& aArcAngle, int aCircleToSegmentsCount,
int aWidth, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM& aOwner )
{
// Don't attempt to render degenerate shapes
if( aWidth == 0 )
return;
VECTOR2I arc_start, arc_end;
EDA_ANGLE arcAngle( aArcAngle );
EDA_ANGLE delta = ANGLE_360 / aCircleToSegmentsCount; // rotate angle
arc_end = arc_start = aStart;
if( arcAngle != ANGLE_360 )
RotatePoint( arc_end, aCentre, -arcAngle );
if( arcAngle < ANGLE_0 )
{
std::swap( arc_start, arc_end );
arcAngle = -arcAngle;
}
// Compute the ends of segments and creates poly
VECTOR2I curr_end = arc_start;
VECTOR2I curr_start = arc_start;
for( EDA_ANGLE ii = delta; ii < arcAngle; ii += delta )
{
curr_end = arc_start;
RotatePoint( curr_end, aCentre, -ii );
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( curr_start ), TO_SFVEC2F( curr_end ),
TO_3DU( aWidth ), aOwner );
curr_start = curr_end;
}
if( curr_end != arc_end )
{
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( curr_end ), TO_SFVEC2F( arc_end ),
TO_3DU( aWidth ), aOwner );
}
}
void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM* aOwner, PCB_LAYER_ID aLayer )
{
// The full width of the lines to create
int linewidth = aShape->GetWidth();
int margin = 0;
if( IsSolderMaskLayer( aLayer )
&& aShape->HasSolderMask()
&& IsExternalCopperLayer( aShape->GetLayer() ) )
{
margin = aShape->GetSolderMaskExpansion();
linewidth += margin * 2;
}
float linewidth3DU = TO_3DU( linewidth );
LINE_STYLE lineStyle = aShape->GetStroke().GetLineStyle();
if( lineStyle <= LINE_STYLE::FIRST_TYPE )
{
switch( aShape->GetShape() )
{
case SHAPE_T::CIRCLE:
{
SFVEC2F center3DU = TO_SFVEC2F( aShape->GetCenter() );
float innerR3DU = TO_3DU( aShape->GetRadius() ) - linewidth3DU / 2.0;
float outerR3DU = TO_3DU( aShape->GetRadius() ) + linewidth3DU / 2.0;
if( aShape->IsFilled() || innerR3DU <= 0.0 )
addFILLED_CIRCLE_2D( aContainer, center3DU, outerR3DU, *aOwner );
else
addRING_2D( aContainer, center3DU, innerR3DU, outerR3DU, *aOwner );
break;
}
case SHAPE_T::RECTANGLE:
if( aShape->IsFilled() )
{
SHAPE_POLY_SET polyList;
aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
ERROR_INSIDE );
polyList.Simplify();
if( margin != 0 )
{
polyList.Inflate( margin, CORNER_STRATEGY::ROUND_ALL_CORNERS,
GetBoard()->GetDesignSettings().m_MaxError );
}
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
}
else
{
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[0] ), TO_SFVEC2F( pts[1] ),
linewidth3DU, *aOwner );
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[1] ), TO_SFVEC2F( pts[2] ),
linewidth3DU, *aOwner );
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[2] ), TO_SFVEC2F( pts[3] ),
linewidth3DU, *aOwner );
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[3] ), TO_SFVEC2F( pts[0] ),
linewidth3DU, *aOwner );
}
break;
case SHAPE_T::ARC:
{
unsigned int segCount = GetCircleSegmentCount( aShape->GetBoundingBox().GetSizeMax() );
createArcSegments( aShape->GetCenter(), aShape->GetStart(), aShape->GetArcAngle(),
segCount, linewidth, aContainer, *aOwner );
break;
}
case SHAPE_T::SEGMENT:
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( aShape->GetStart() ),
TO_SFVEC2F( aShape->GetEnd() ), linewidth3DU, *aOwner );
break;
case SHAPE_T::BEZIER:
case SHAPE_T::POLY:
{
SHAPE_POLY_SET polyList;
aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
ERROR_INSIDE );
// Some polygons can be a bit complex (especially when coming from a
// picture of a text converted to a polygon
// So call Simplify before calling ConvertPolygonToTriangles, just in case.
polyList.Simplify();
if( polyList.IsEmpty() ) // Just for caution
break;
if( margin != 0 )
{
CORNER_STRATEGY cornerStr = margin >= 0 ? CORNER_STRATEGY::ROUND_ALL_CORNERS
: CORNER_STRATEGY::ALLOW_ACUTE_CORNERS;
polyList.Inflate( margin, cornerStr, GetBoard()->GetDesignSettings().m_MaxError );
}
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
break;
}
default:
wxFAIL_MSG( wxT( "BOARD_ADAPTER::addShape no implementation for " )
+ aShape->SHAPE_T_asString() );
break;
}
}
else
{
std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
SFVEC2F a3DU;
SFVEC2F b3DU;
const PCB_PLOT_PARAMS& plotParams = aShape->GetBoard()->GetPlotOptions();
KIGFX::PCB_RENDER_SETTINGS renderSettings;
renderSettings.SetDashLengthRatio( plotParams.GetDashedLineDashRatio() );
renderSettings.SetGapLengthRatio( plotParams.GetDashedLineGapRatio() );
for( SHAPE* shape : shapes )
{
STROKE_PARAMS::Stroke( shape, lineStyle, aShape->GetWidth(), &renderSettings,
[&]( const VECTOR2I& a, const VECTOR2I& b )
{
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( a ), TO_SFVEC2F( b ),
linewidth3DU, *aOwner );
} );
}
for( SHAPE* shape : shapes )
delete shape;
}
}
void BOARD_ADAPTER::addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM* aOwner )
{
addText( aTextBox, aContainer, aOwner );
if( !aTextBox->IsBorderEnabled() )
return;
// We cannot use PCB_TEXTBOX::TransformShapeToPolygon because it convert the textbox
// as filled polygon even if there's no background colour.
// So for polygon, we use PCB_SHAPE::TransformShapeToPolygon
if( aTextBox->GetShape() == SHAPE_T::RECTANGLE )
{
addShape( static_cast<const PCB_SHAPE*>( aTextBox ), aContainer, aOwner, UNDEFINED_LAYER );
}
else
{
SHAPE_POLY_SET polyList;
aTextBox->PCB_SHAPE::TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
ERROR_INSIDE );
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
}
}
void BOARD_ADAPTER::addTable( const PCB_TABLE* aTable, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM* aOwner )
{
// JEY TODO: tables
// add borders
for( PCB_TABLECELL* cell : aTable->GetCells() )
addText( cell, aContainer, aOwner );
}
void BOARD_ADAPTER::addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aContainer,
PCB_LAYER_ID aLayerId )
{
// This convert the poly in outline and holes
ConvertPolygonToTriangles( *aZone->GetFilledPolysList( aLayerId ), *aContainer, m_biuTo3Dunits,
*aZone );
}
void BOARD_ADAPTER::buildPadOutlineAsSegments( const PAD* aPad, PCB_LAYER_ID aLayer,
CONTAINER_2D_BASE* aContainer, int aWidth )
{
if( aPad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE ) // Draw a ring
{
const SFVEC2F center3DU = TO_SFVEC2F( aPad->ShapePos( aLayer ) );
const int radius = aPad->GetSize( aLayer ).x / 2;
const float inner_radius3DU = TO_3DU( radius - aWidth / 2.0 );
const float outer_radius3DU = TO_3DU( radius + aWidth / 2.0 );
addRING_2D( aContainer, center3DU, inner_radius3DU, outer_radius3DU, *aPad );
}
else
{
// For other shapes, add outlines as thick segments in polygon buffer
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( aLayer,
ERROR_INSIDE );
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
for( int j = 0; j < path.PointCount(); j++ )
{
SFVEC2F start3DU = TO_SFVEC2F( path.CPoint( j ) );
SFVEC2F end3DU = TO_SFVEC2F( path.CPoint( j + 1 ) );
addROUND_SEGMENT_2D( aContainer, start3DU, end3DU, TO_3DU( aWidth ), *aPad );
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-348
View File
@@ -1,348 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright The 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 EDA_3D_CANVAS_H
#define EDA_3D_CANVAS_H
#include <atomic>
#include "board_adapter.h"
#include "3d_rendering/raytracing/accelerators/accelerator_3d.h"
#include "3d_rendering/render_3d_base.h"
#include "3d_cache/3d_cache.h"
#include <gal/hidpi_gl_3D_canvas.h>
#include <wx/image.h>
#include <wx/timer.h>
class WX_INFOBAR;
class wxStatusBar;
class BOARD;
class RENDER_3D_RAYTRACE_GL;
class RENDER_3D_OPENGL;
#define EDA_3D_CANVAS_ID wxID_HIGHEST + 1321
/**
* Implement a canvas based on a wxGLCanvas
*/
class EDA_3D_CANVAS : public HIDPI_GL_3D_CANVAS
{
public:
/**
* Create a new 3D Canvas with an attribute list.
*
* @param aParent the parent creator of this canvas.
* @param aGLAttribs openGL attributes created by #OGL_ATT_LIST::GetAttributesList.
* @param aBoard The board.
* @param aSettings the settings options to be used by this canvas.
*/
EDA_3D_CANVAS( wxWindow* aParent, const wxGLAttributes& aGLAttribs, BOARD_ADAPTER& aSettings,
CAMERA& aCamera, S3D_CACHE* a3DCachePointer );
~EDA_3D_CANVAS();
/**
* Set a dispatcher that processes events and forwards them to tools.
*
* #DRAW_PANEL_GAL does not take over the ownership. Passing NULL disconnects all event
* handlers from the DRAW_PANEL_GAL and parent frame.
*
* @param aEventDispatcher is the object that will be used for dispatching events.
*/
void SetEventDispatcher( TOOL_DISPATCHER* aEventDispatcher );
void SetStatusBar( wxStatusBar* aStatusBar )
{
m_parentStatusBar = aStatusBar;
}
void SetInfoBar( WX_INFOBAR* aInfoBar )
{
m_parentInfoBar = aInfoBar;
}
void ReloadRequest( BOARD* aBoard = nullptr, S3D_CACHE* aCachePointer = nullptr );
/**
* Query if there is a pending reload request.
*
* @return true if it wants to reload, false if there is no reload pending.
*/
bool IsReloadRequestPending() const
{
if( m_3d_render )
return m_3d_render->IsReloadRequestPending();
else
return false;
}
/**
* @return the current render ( a RENDER_3D_RAYTRACE_GL* or a RENDER_3D_OPENGL* render )
*/
RENDER_3D_BASE* GetCurrentRender() const { return m_3d_render; }
/**
* Request to render the current view in Raytracing mode.
*/
void RenderRaytracingRequest();
/**
* Request a screenshot and output it to the \a aDstImage.
*
* @param aDstImage - Screenshot destination image.
*/
void GetScreenshot( wxImage& aDstImage );
/**
* Select a specific 3D view or operation.
*
* @param aRequestedView the view to move to.
* @return true if the view request was handled, false if no command found for this view.
*/
bool SetView3D( VIEW3D_TYPE aRequestedView );
/**
* Enable or disable camera animation when switching to a pre-defined view.
*/
void SetAnimationEnabled( bool aEnable ) { m_animation_enabled = aEnable; }
bool GetAnimationEnabled() const { return m_animation_enabled; }
/**
* Set the camera animation moving speed multiplier option.
*
* @param aMultiplier one of the possible integer options: [1,2,3,4,5].
*/
void SetMovingSpeedMultiplier( int aMultiplier ) { m_moving_speed_multiplier = aMultiplier; }
int GetMovingSpeedMultiplier() const { return m_moving_speed_multiplier; }
int GetProjectionMode() const { return (int) m_camera.GetProjection(); };
void SetProjectionMode( int aMode ) { m_camera.SetProjection( (PROJECTION_TYPE) aMode ); }
/**
* Notify that the render engine was changed.
*/
void RenderEngineChanged();
/**
* Update the status bar with the position information.
*/
void DisplayStatus();
/**
* Schedule a refresh update of the canvas.
*
* @param aRedrawImmediately true will request a redraw, false will schedule a redraw
* after a short timeout.
*/
void Request_refresh( bool aRedrawImmediately = true );
/**
* Used to forward events to the canvas from popups, etc.
*/
void OnEvent( wxEvent& aEvent );
/**
* Get information used to display 3D board.
*/
const BOARD_ADAPTER& GetBoardAdapter() const { return m_boardAdapter; }
/**
* Get a value indicating whether to render the pivot.
*/
bool GetRenderPivot() { return m_render_pivot; }
/**
* Set aValue indicating whether to render the pivot.
*
* @param aValue true will cause the pivot to be rendered on the next redraw.
*/
void SetRenderPivot( bool aValue ) { m_render_pivot = aValue; }
/**
* Get a value indicating whether to render the 3dmouse pivot.
*/
bool GetRender3dmousePivot()
{
return m_render3dmousePivot;
}
/**
* Set aValue indicating whether to render the 3dmouse pivot.
*
* @param aValue true will cause the pivot to be rendered on the next redraw.
*/
void SetRender3dmousePivot( bool aValue )
{
m_render3dmousePivot = aValue;
}
/**
* Set the position of the the 3dmouse pivot.
*
* @param aPos is the position of the 3dmouse rotation pivot
*/
void Set3dmousePivotPos( const SFVEC3F& aPos )
{
m_3dmousePivotPos = aPos;
}
/**
* The actual function to repaint the canvas.
*
* It is usually called by OnPaint() but because it does not use a wxPaintDC it can be
* called outside a wxPaintEvent
*/
void DoRePaint();
void OnCloseWindow( wxCloseEvent& event );
private:
// The wxPaintEvent event. mainly calls DoRePaint()
void OnPaint( wxPaintEvent& aEvent );
void OnEraseBackground( wxEraseEvent& event );
void OnRefreshRequest( wxEvent& aEvent );
void OnMouseWheel( wxMouseEvent& event );
void OnMagnify( wxMouseEvent& event );
void OnMouseMove( wxMouseEvent& event );
void OnLeftDown( wxMouseEvent& event );
void OnLeftUp( wxMouseEvent& event );
void OnMiddleUp( wxMouseEvent& event );
void OnMiddleDown( wxMouseEvent& event );
void OnTimerTimeout_Editing( wxTimerEvent& event );
void OnResize( wxSizeEvent& event );
void OnTimerTimeout_Redraw( wxTimerEvent& event );
void OnZoomGesture( wxZoomGestureEvent& event );
void OnPanGesture( wxPanGestureEvent& event );
void OnRotateGesture( wxRotateGestureEvent& event );
DECLARE_EVENT_TABLE()
/**
*Stop the editing time so it will not timeout.
*/
void stop_editingTimeOut_Timer();
/**
* Reset the editing timer.
*/
void restart_editingTimeOut_Timer();
/**
* Start a camera movement.
*
* @param aMovingSpeed the time speed.
* @param aRenderPivot if it should display pivot cursor while move.
*/
void request_start_moving_camera( float aMovingSpeed = 2.0f, bool aRenderPivot = true );
/**
* This function hits a ray to the board and start a movement.
*/
void move_pivot_based_on_cur_mouse_position();
/**
* Render the pivot cursor.
*
* @param t time between 0.0 and 1.0.
* @param aScale scale to apply on the cursor.
*/
void render_pivot( float t, float aScale );
/**
* Render the 3dmouse pivot cursor.
*
* @param aScale scale to apply on the cursor.
*/
void render3dmousePivot( float aScale );
/**
* @return true if OpenGL initialization succeeded.
*/
bool initializeOpenGL();
/**
* Free created targets and openGL context.
*/
void releaseOpenGL();
RAY getRayAtCurrentMousePosition();
private:
TOOL_DISPATCHER* m_eventDispatcher;
wxStatusBar* m_parentStatusBar; // Parent statusbar to report progress
WX_INFOBAR* m_parentInfoBar;
wxGLContext* m_glRC; // Current OpenGL context
bool m_is_opengl_initialized;
bool m_is_opengl_version_supported;
wxTimer m_editing_timeout_timer; // Expires after some time signaling that
// the mouse / keyboard movements are over
wxTimer m_redraw_trigger_timer; // Used to schedule a redraw event
std::atomic_flag m_is_currently_painting; // Avoid drawing twice at the same time
bool m_render_pivot; // Render the pivot while camera moving
float m_camera_moving_speed; // 1.0f will be 1:1
int64_t m_strtime_camera_movement; // Ticktime of camera movement start
bool m_animation_enabled; // Camera animation enabled
int m_moving_speed_multiplier; // Camera animation speed multiplier option
BOARD_ADAPTER& m_boardAdapter; // Pre-computed 3D info and settings
RENDER_3D_BASE* m_3d_render;
RENDER_3D_RAYTRACE_GL* m_3d_render_raytracing;
RENDER_3D_OPENGL* m_3d_render_opengl;
bool m_opengl_supports_raytracing;
bool m_render_raytracing_was_requested;
ACCELERATOR_3D* m_accelerator3DShapes; // used for mouse over searching
BOARD_ITEM* m_currentRollOverItem;
bool m_render3dmousePivot = false; // Render the 3dmouse pivot
SFVEC3F m_3dmousePivotPos; // The position of the 3dmouse pivot
/// Used to track gesture events.
double m_gestureLastZoomFactor = 1.0;
double m_gestureLastAngle = 0.0;
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_EDA_3D_CANVAS". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
static const wxChar* m_logTrace;
};
#endif // EDA_3D_CANVAS_H
-161
View File
@@ -1,161 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright The 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
*/
/**
* @file eda_3d_canvas_pivot.cpp
* @brief Implementation of a 3d cursor
*/
#include "../common_ogl/openGL_includes.h"
#include "../common_ogl/ogl_utils.h"
#include "eda_3d_canvas.h"
static void pivot_render_triangles( float t )
{
wxASSERT( t >= 0.0f );
SFVEC3F vertexPointer[12];
const float u = 1.0f / 6.0f;
vertexPointer[0] = SFVEC3F( ( -3.0f + t ) * u, -2.0f * u, 0.0f );
vertexPointer[1] = SFVEC3F( ( -3.0f + t ) * u, 2.0f * u, 0.0f );
vertexPointer[2] = SFVEC3F( ( -1.0f + t ) * u, 0.0f * u, 0.0f );
vertexPointer[3] = SFVEC3F( -2.0f * u, ( -3.0f + t ) * u, 0.0f );
vertexPointer[4] = SFVEC3F( 2.0f * u, ( -3.0f + t ) * u, 0.0f );
vertexPointer[5] = SFVEC3F( 0.0f * u, ( -1.0f + t ) * u, 0.0f );
vertexPointer[6] = SFVEC3F( ( 3.0f - t ) * u, -2.0f * u, 0.0f );
vertexPointer[7] = SFVEC3F( ( 3.0f - t ) * u, 2.0f * u, 0.0f );
vertexPointer[8] = SFVEC3F( ( 1.0f - t ) * u, 0.0f * u, 0.0f );
vertexPointer[9] = SFVEC3F( 2.0f * u, ( 3.0f - t ) * u, 0.0f );
vertexPointer[10] = SFVEC3F( -2.0f * u, ( 3.0f - t ) * u, 0.0f );
vertexPointer[11] = SFVEC3F( 0.0f * u, ( 1.0f - t ) * u, 0.0f );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, vertexPointer );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glDrawArrays( GL_TRIANGLES, 0, 4 * 3 );
glDisable( GL_BLEND );
glDisableClientState( GL_VERTEX_ARRAY );
}
void EDA_3D_CANVAS::render_pivot( float t, float aScale )
{
wxASSERT( aScale >= 0.0f );
wxASSERT( t >= 0.0f );
if( t > 1.0f )
t = 1.0f;
const SFVEC3F &lookAtPos = m_camera.GetLookAtPos_T1();
glDisable( GL_LIGHTING );
glDisable( GL_DEPTH_TEST );
glDisable( GL_CULL_FACE );
// Set projection and modelview matrixes
glMatrixMode( GL_PROJECTION );
glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
glEnable( GL_COLOR_MATERIAL );
glColor4f( 0.0f, 1.0f, 0.0f, 0.75f - t * 0.75f );
// Translate to the look at position
glTranslatef( lookAtPos.x, lookAtPos.y, lookAtPos.z );
glScalef( aScale, aScale, aScale );
pivot_render_triangles( t * 0.5f );
t = t * 0.80f;
glScalef( 1.0f - t, 1.0f - t, 1.0f - t );
glColor4f( 0.0f, 1.0f, 0.0f, 0.8f - t );
glPushMatrix();
glRotatef( t * 90.0f, 0.0f, 0.0f, 1.0f );
pivot_render_triangles( t * 0.5f );
glPopMatrix();
glPushMatrix();
glRotatef( -t * 90.0f, 0.0f, 0.0f, 1.0f );
pivot_render_triangles( t * 0.5f );
glPopMatrix();
}
void EDA_3D_CANVAS::render3dmousePivot( float aScale )
{
wxASSERT( aScale >= 0.0f );
glDisable( GL_LIGHTING );
glDisable( GL_DEPTH_TEST );
glDisable( GL_CULL_FACE );
// Set projection and modelview matrixes
glMatrixMode( GL_PROJECTION );
glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
glEnable( GL_COLOR_MATERIAL );
glColor4f( 0.0f, 0.667f, 0.902f, 0.75f );
// Translate to the look at position
glTranslatef( m_3dmousePivotPos.x, m_3dmousePivotPos.y, m_3dmousePivotPos.z );
glPointSize( 16.0f );
glEnable( GL_POINT_SMOOTH );
glHint( GL_POINT_SMOOTH_HINT, GL_NICEST );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glScalef( aScale, aScale, aScale );
// Draw a point at the look at position.
glBegin( GL_POINTS );
glVertex3f( 0, 0, 0 );
glEnd();
glDisable( GL_BLEND );
glDisable( GL_POINT_SMOOTH );
}
+185
View File
@@ -0,0 +1,185 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2015 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
*/
/**
* @file 3d_class.cpp
*/
#include <fctsys.h>
#include "3d_viewer.h"
#include "3d_struct.h"
#include "modelparsers.h"
void S3D_MASTER::Insert( S3D_MATERIAL* aMaterial )
{
aMaterial->SetNext( m_Materials );
m_Materials = aMaterial;
}
void S3D_MASTER::Copy( S3D_MASTER* pattern )
{
SetShape3DName( pattern->GetShape3DName() );
m_MatScale = pattern->m_MatScale;
m_MatRotation = pattern->m_MatRotation;
m_MatPosition = pattern->m_MatPosition;
m_3D_Drawings = NULL;
m_Materials = NULL;
}
S3D_MASTER::S3D_MASTER( EDA_ITEM* aParent ) :
EDA_ITEM( aParent, NOT_USED )
{
m_MatScale.x = m_MatScale.y = m_MatScale.z = 1.0;
m_3D_Drawings = NULL;
m_Materials = NULL;
m_parser = NULL;
m_ShapeType = FILE3D_NONE;
m_use_modelfile_diffuseColor = true;
m_use_modelfile_emissiveColor = true;
m_use_modelfile_specularColor = true;
m_use_modelfile_ambientIntensity = true;
m_use_modelfile_transparency = true;
m_use_modelfile_shininess = true;
}
S3D_MASTER:: ~S3D_MASTER()
{
STRUCT_3D_SHAPE* next;
S3D_MATERIAL* nextmat;
for( ; m_3D_Drawings != NULL; m_3D_Drawings = next )
{
next = m_3D_Drawings->Next();
delete m_3D_Drawings;
m_3D_Drawings = 0;
}
for( ; m_Materials != NULL; m_Materials = nextmat )
{
nextmat = m_Materials->Next();
delete m_Materials;
m_Materials = NULL;
}
}
bool S3D_MASTER::Is3DType( enum FILE3D_TYPE aShapeType )
{
// type 'none' is not valid and will always return false
if( aShapeType == FILE3D_NONE )
return false;
// no one is interested if we have no file
if( m_Shape3DName.empty() )
return false;
if( aShapeType == m_ShapeType )
return true;
return false;
}
void S3D_MASTER::SetShape3DName( const wxString& aShapeName )
{
m_ShapeType = FILE3D_NONE;
m_Shape3DName = aShapeName;
if( m_Shape3DName.empty() )
return;
wxFileName fn = m_Shape3DName;
m_Shape3DNameExtension = fn.GetExt();
if( m_Shape3DNameExtension == wxT( "wrl" ) ||
m_Shape3DNameExtension == wxT( "x3d" ) )
m_ShapeType = FILE3D_VRML;
else if( m_Shape3DNameExtension == wxT( "idf" ) )
m_ShapeType = FILE3D_IDF;
else
m_ShapeType = FILE3D_UNKNOWN;
// Expand any environment variables embedded in footprint's m_Shape3DName field.
// To ensure compatibility with most of footprint's m_Shape3DName field,
// if the m_Shape3DName is not an absolute path the default path
// given by the environment variable KISYS3DMOD will be used
if( m_Shape3DName.StartsWith( wxT("${") ) )
m_Shape3DFullFilename = wxExpandEnvVars( m_Shape3DName );
else
m_Shape3DFullFilename = m_Shape3DName;
wxFileName fnFull( m_Shape3DFullFilename );
if( !( fnFull.IsAbsolute() || m_Shape3DFullFilename.StartsWith( wxT(".") ) ) )
{
wxString default_path;
wxGetEnv( KISYS3DMOD, &default_path );
if( !( default_path.IsEmpty() ) )
{
if( !default_path.EndsWith( wxT("/") ) && !default_path.EndsWith( wxT("\\") ) )
default_path += wxT("/");
m_Shape3DFullFilename = default_path + m_Shape3DFullFilename;
}
}
return;
}
const wxString S3D_MASTER::GetShape3DFullFilename()
{
return m_Shape3DFullFilename;
}
const wxString S3D_MASTER::GetShape3DExtension()
{
return m_Shape3DNameExtension;
}
STRUCT_3D_SHAPE::STRUCT_3D_SHAPE( EDA_ITEM* aParent ) :
EDA_ITEM( aParent, NOT_USED )
{
m_3D_Coord = NULL;
m_3D_CoordIndex = NULL;
m_3D_Points = 0;
}
STRUCT_3D_SHAPE:: ~STRUCT_3D_SHAPE()
{
delete m_3D_Coord;
delete m_3D_CoordIndex;
}
File diff suppressed because it is too large Load Diff
+426
View File
@@ -0,0 +1,426 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2012 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
*/
/**
* @file 3d_draw_basic_functions.cpp
*/
#include <fctsys.h>
#include <trigo.h>
#include <convert_basic_shapes_to_polygon.h>
#include <3d_viewer.h>
#include <info3d_visu.h>
#include <3d_draw_basic_functions.h>
#include <modelparsers.h>
// Number of segments to approximate a circle by segments
#define SEGM_PER_CIRCLE 24
#ifndef CALLBACK
#define CALLBACK
#endif
// Variables used to pass a value to call back openGL functions
static float s_textureScale;
static double s_currentZpos;
static double s_biuTo3Dunits;
bool s_useTextures;
// CALLBACK functions for GLU_TESS
static void CALLBACK tessBeginCB( GLenum which );
static void CALLBACK tessEndCB();
static void CALLBACK tessErrorCB( GLenum errorCode );
static void CALLBACK tessCPolyPt2Vertex( const GLvoid* data );
void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
/* Draw3D_VerticalPolygonalCylinder is a helper function.
*
* draws a "vertical cylinder" having a polygon shape
* from Z position = aZpos to aZpos + aHeight
* Used to create the vertical sides of 3D horizontal shapes with thickness.
*/
static void Draw3D_VerticalPolygonalCylinder( const SHAPE_POLY_SET& aPolysList,
int aHeight, int aZpos,
bool aInside, double aBiuTo3DUnits )
{
if( aHeight == 0 )
return;
std::vector<S3D_VERTEX> coords;
coords.resize( 4 );
// Init Z position of the 4 points of a GL_QUAD
if( aInside )
{
coords[0].z = aZpos;
coords[1].z = aZpos + aHeight;
}
else
{
coords[0].z = aZpos + aHeight;
coords[1].z = aZpos;
}
coords[2].z = coords[1].z;
coords[3].z = coords[0].z;
// Draw the vertical polygonal side
for( int idx = 0; idx < aPolysList.OutlineCount(); idx++ )
{
// Each polygon in aPolysList is a polygon with holes
const SHAPE_POLY_SET::POLYGON& curr_polywithholes = aPolysList.CPolygon( idx );
// Draw the outline of each simple polygon inside the polygon with holes:
for( unsigned ipoly = 0; ipoly < curr_polywithholes.size(); ipoly++ )
{
const SHAPE_LINE_CHAIN& path = curr_polywithholes[ipoly]; // a simple polygon
for( int jj = 0; jj < path.PointCount(); jj++ )
{
const VECTOR2I& a = path.CPoint( jj );
const VECTOR2I& b = path.CPoint( jj + 1 );
// Build the 4 vertices of each GL_QUAD
coords[0].x = a.x;
coords[0].y = -a.y;
coords[1].x = coords[0].x;
coords[1].y = coords[0].y; // only z change
coords[2].x = b.x;
coords[2].y = -b.y;
coords[3].x = coords[2].x;
coords[3].y = coords[2].y; // only z change
// Creates the GL_QUAD
TransfertToGLlist( coords, aBiuTo3DUnits );
}
}
}
}
void SetGLColor( EDA_COLOR_T color, double alpha )
{
const StructColors &colordata = g_ColorRefs[ColorGetBase( color )];
float red = colordata.m_Red / 255.0;
float blue = colordata.m_Blue / 255.0;
float green = colordata.m_Green / 255.0;
glColor4f( red, green, blue, (float)alpha );
}
void SetGLColor( S3D_COLOR& aColor, float aTransparency )
{
glColor4f( aColor.m_Red, aColor.m_Green, aColor.m_Blue, aTransparency );
}
void SetGLTexture( GLuint text_id, float scale )
{
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, text_id );
s_textureScale = scale; // for Tess callback functions
}
/* draw all solid polygons found in aPolysList
* aZpos = z position in board internal units
* aThickness = thickness in board internal units
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
* If aThickness > 0, a solid object is drawn.
* The top side is located at aZpos + aThickness / 2
* The bottom side is located at aZpos - aThickness / 2
*/
void Draw3D_SolidHorizontalPolyPolygons( const SHAPE_POLY_SET& aPolysList,
int aZpos, int aThickness, double aBiuTo3DUnits,
bool aUseTextures,
float aNormal_Z_Orientation )
{
// for Tess callback functions:
s_biuTo3Dunits = aBiuTo3DUnits;
s_useTextures = aUseTextures;
GLUtesselator* tess = gluNewTess();
gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*) () )tessBeginCB );
gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*) () )tessEndCB );
gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*) () )tessErrorCB );
gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )tessCPolyPt2Vertex );
GLdouble v_data[3];
double zpos = ( aZpos + (aThickness / 2.0) ) * aBiuTo3DUnits;
s_currentZpos = zpos; // for Tess callback functions
v_data[2] = zpos;
// Set normal toward positive Z axis, for a solid object on the top side
//gluTessProperty( tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE );
gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD );
glNormal3f( 0.0, 0.0, aNormal_Z_Orientation );
// Draw solid areas contained in this list
SHAPE_POLY_SET polylist = aPolysList; // temporary copy for gluTessVertex
for( int side = 0; side < 2; side++ )
{
for ( int idx = 0; idx < polylist.OutlineCount(); ++idx )
{
gluTessBeginPolygon( tess, NULL );
SHAPE_POLY_SET::POLYGON& curr_polywithholes = polylist.Polygon( idx ); // a polygon with holes
for( unsigned ipoly = 0; ipoly < curr_polywithholes.size(); ipoly++ )
{
SHAPE_LINE_CHAIN& curr_poly = curr_polywithholes[ipoly]; // a simple polygon
gluTessBeginContour( tess );
for( int ipt = 0; ipt < curr_poly.PointCount(); ipt++ )
{
v_data[0] = curr_poly.Point( ipt ).x * aBiuTo3DUnits;
v_data[1] = -curr_poly.Point( ipt ).y * aBiuTo3DUnits;
// gluTessVertex store pointers on data, not data, so do not store
// different corners values in a temporary variable
// but send pointer on each CPolyPt value in polylist
// before calling gluDeleteTess
gluTessVertex( tess, v_data, &curr_poly.Point( ipt ) );
}
gluTessEndContour( tess );
}
gluTessEndPolygon( tess );
}
if( aThickness == 0 )
break;
// Prepare the bottom side of solid areas
zpos = ( aZpos - (aThickness / 2.0) ) * aBiuTo3DUnits;
s_currentZpos = zpos; // for Tess callback functions
v_data[2] = zpos;
glNormal3f( 0.0, 0.0, -aNormal_Z_Orientation );
}
gluDeleteTess( tess );
if( aThickness == 0 )
return;
// Build the 3D data : vertical side
Draw3D_VerticalPolygonalCylinder( polylist, aThickness, aZpos - (aThickness / 2.0),
true, aBiuTo3DUnits );
}
/* draw a cylinder (a tube) using 3D primitives.
* the cylinder axis is parallel to the Z axis
* If aHeight = height of the cylinder is 0, only one ring will be drawn
* If aThickness = 0, only one cylinder will be drawn
*/
void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
int aHeight, int aThickness,
int aZpos, double aBiuTo3DUnits )
{
const int slice = SEGM_PER_CIRCLE;
SHAPE_POLY_SET outer_cornerBuffer;
TransformCircleToPolygon( outer_cornerBuffer, aCenterPos,
aRadius + (aThickness / 2), slice );
std::vector<S3D_VERTEX> coords;
coords.resize( 4 );
SHAPE_POLY_SET inner_cornerBuffer;
if( aThickness ) // build the the vertical inner polygon (hole)
TransformCircleToPolygon( inner_cornerBuffer, aCenterPos,
aRadius - (aThickness / 2), slice );
if( aHeight )
{
// Draw the vertical outer side
Draw3D_VerticalPolygonalCylinder( outer_cornerBuffer,
aHeight, aZpos, false, aBiuTo3DUnits );
if( aThickness )
// Draws the vertical inner side (hole)
Draw3D_VerticalPolygonalCylinder( inner_cornerBuffer,
aHeight, aZpos, true, aBiuTo3DUnits );
}
if( aThickness )
{
// draw top (front) and bottom (back) horizontal sides (rings)
outer_cornerBuffer.AddHole( inner_cornerBuffer.COutline( 0 ) );
// draw top (front) horizontal ring
Draw3D_SolidHorizontalPolyPolygons( outer_cornerBuffer, aZpos + aHeight,
0, aBiuTo3DUnits, false, 1.0f );
if( aHeight )
{
// draw bottom (back) horizontal ring
Draw3D_SolidHorizontalPolyPolygons( outer_cornerBuffer, aZpos,
0, aBiuTo3DUnits, false, -1.0f );
}
}
}
/*
* Function Draw3D_ZaxisOblongCylinder:
* draw a segment with an oblong hole.
* Used to draw oblong holes
* If aHeight = height of the cylinder is 0, only one ring will be drawn
* If aThickness = 0, only one cylinder will be drawn
*/
void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
int aRadius, int aHeight, int aThickness,
int aZpos, double aBiuTo3DUnits )
{
const int slice = SEGM_PER_CIRCLE;
// Build the points to approximate oblong cylinder by segments
SHAPE_POLY_SET cornerBuffer;
int segm_width = (aRadius * 2) + aThickness;
TransformRoundedEndsSegmentToPolygon( cornerBuffer, aAxis1Pos,
aAxis2Pos, slice, segm_width );
// Draw the oblong outer cylinder
if( aHeight )
Draw3D_VerticalPolygonalCylinder( cornerBuffer, aHeight, aZpos,
false, aBiuTo3DUnits );
if( aThickness )
{
SHAPE_POLY_SET inner_cornerBuffer;
segm_width = aRadius * 2;
TransformRoundedEndsSegmentToPolygon( inner_cornerBuffer, aAxis1Pos,
aAxis2Pos, slice, segm_width );
// Draw the oblong inner cylinder
if( aHeight )
Draw3D_VerticalPolygonalCylinder( inner_cornerBuffer, aHeight,
aZpos, true, aBiuTo3DUnits );
// Build the horizontal full polygon shape
// (outer polygon shape - inner polygon shape)
cornerBuffer.AddHole( inner_cornerBuffer.COutline( 0 ) );
// draw top (front) horizontal side (ring)
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos + aHeight, 0, aBiuTo3DUnits, false,
1.0f );
if( aHeight )
{
// draw bottom (back) horizontal side (ring)
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, 0, aBiuTo3DUnits, false,
-1.0f );
}
}
}
/* draw a thick segment using 3D primitives, in a XY plane
* wxPoint aStart, wxPoint aEnd = YX position of end in board units
* aWidth = width of segment in board units
* aThickness = thickness of segment in board units
* aZpos = z position of segment in board units
*/
void Draw3D_SolidSegment( const wxPoint& aStart, const wxPoint& aEnd,
int aWidth, int aThickness, int aZpos, double aBiuTo3DUnits )
{
SHAPE_POLY_SET cornerBuffer;
const int slice = SEGM_PER_CIRCLE;
TransformRoundedEndsSegmentToPolygon( cornerBuffer, aStart, aEnd, slice, aWidth );
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, aThickness, aBiuTo3DUnits, false, 1.0f );
}
void Draw3D_ArcSegment( const wxPoint& aCenterPos, const wxPoint& aStartPoint,
double aArcAngle, int aWidth, int aThickness,
int aZpos, double aBiuTo3DUnits )
{
const int slice = SEGM_PER_CIRCLE;
SHAPE_POLY_SET cornerBuffer;
TransformArcToPolygon( cornerBuffer, aCenterPos, aStartPoint, aArcAngle,
slice, aWidth );
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, aThickness, aBiuTo3DUnits, false, 1.0f );
}
// /////////////////////////////////////////////////////////////////////////////
// GLU_TESS CALLBACKS
// /////////////////////////////////////////////////////////////////////////////
void CALLBACK tessBeginCB( GLenum which )
{
glBegin( which );
}
void CALLBACK tessEndCB()
{
glEnd();
}
void CALLBACK tessCPolyPt2Vertex( const GLvoid* data )
{
// cast back to double type
const VECTOR2I* ptr = (const VECTOR2I*) data;
if( s_useTextures )
{
glTexCoord2f( ptr->x * s_biuTo3Dunits * s_textureScale,
-ptr->y * s_biuTo3Dunits * s_textureScale);
}
glVertex3d( ptr->x * s_biuTo3Dunits, -ptr->y * s_biuTo3Dunits, s_currentZpos );
}
void CALLBACK tessErrorCB( GLenum errorCode )
{
#if defined(DEBUG)
const GLubyte* errorStr;
errorStr = gluErrorString( errorCode );
// DEBUG //
DBG( printf( "Tess ERROR: %s\n", errorStr ); )
#endif
}
+134
View File
@@ -0,0 +1,134 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2012 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
*/
/**
* @file 3d_draw_basic_functions.h
*/
#ifndef _3D_DRAW_BASIC_FUNCTIONS_H_
#define _3D_DRAW_BASIC_FUNCTIONS_H_
// angle increment to draw a circle, approximated by segments
#define ANGLE_INC( x ) ( 3600 / (x) )
/** draw all solid polygons found in aPolysList
* @param aPolysList = the poligon list to draw
* @param aZpos = z position in board internal units
* @param aThickness = thickness in board internal units
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
* @param aUseTextures = true to use textxures for the polygons
* @param aNormal_Z_Orientation = the normal Z orientation to apply
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
* If aThickness > 0, a solid object is drawn.
* The top side is located at aZpos + aThickness / 2
* The bottom side is located at aZpos - aThickness / 2
*/
void Draw3D_SolidHorizontalPolyPolygons( const SHAPE_POLY_SET& aPolysList,
int aZpos, int aThickness, double aBiuTo3DUnits,
bool aUseTextures,
float aNormal_Z_Orientation );
/** draw a thick segment using 3D primitives, in a XY plane
* @param aStart = YX position of start point in board units
* @param aEnd = YX position of end point in board units
* @param aWidth = width of segment in board units
* @param aThickness = thickness of segment in board units
* @param aZpos = z position of segment in board units
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
* If aThickness > 0, a solid object is drawn.
* The top side is located at aZpos + aThickness / 2
* The bottom side is located at aZpos - aThickness / 2
*/
void Draw3D_SolidSegment( const wxPoint& aStart, const wxPoint& aEnd,
int aWidth, int aThickness, int aZpos,
double aBiuTo3DUnits );
/** draw an arc using 3D primitives, in a XY plane
* @param aCenterPos = XY position of the center in board units
* @param aStartPoint = start point coordinate of arc in board units
* @param aWidth = width of the circle in board units
* @param aArcAngle = arc angle in 1/10 degrees
* @param aWidth = thickness of arc
* @param aThickness = thickness of segment in board units
* @param aZpos = z position of segment in board units
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
*/
void Draw3D_ArcSegment( const wxPoint& aCenterPos, const wxPoint& aStartPoint,
double aArcAngle, int aWidth, int aThickness,
int aZpos, double aBiuTo3DUnits );
/** draw a thick cylinder (a tube) using 3D primitives.
* the cylinder axis is parallel to the Z axis
* @param aCenterPos = XY position of the axis cylinder ( board internal units)
* @param aRadius = radius of the cylinder ( board internal units)
* @param aHeight = height of the cylinder ( boardinternal units)
* @param aThickness = tichkness of tube ( boardinternal units)
* @param aZpos = Z position of the bottom side of the cylinder ( board internal units)
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
*
* If aHeight = height of the cylinder is 0, only one ring will be drawn
* If aThickness = 0, only one cylinder (not a tube) will be drawn
*/
void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
int aHeight, int aThickness,
int aZpos, double aBiuTo3DUnits );
/** draw an oblong cylinder (oblong tube) using 3D primitives.
* the cylinder axis are parallel to the Z axis
* @param aAxis1Pos = position of the first axis cylinder
* @param aAxis2Pos = position of the second axis cylinder
* @param aRadius = radius of the cylinder ( board internal units )
* @param aHeight = height of the cylinder ( board internal units )
* @param aThickness = tichkness of tube ( board internal units )
* @param aZpos = Z position of the bottom side of the cylinder ( board internal units )
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
*/
void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
int aRadius, int aHeight, int aThickness,
int aZpos, double aBiuTo3DUnits );
/**
* Set the current 3D color from a Kicad color, with optional transparency
* @param aColor = a EDA_COLOR_T kicad color index
* @param aTransparency = the color transparency (default = 1.0 = no transparency)
*/
void SetGLColor( EDA_COLOR_T aColor, double aTransparency = 1.0 );
/**
* Set the current 3D color from a S3D_COLOR color, with optional transparency
* @param aColor = a S3D_COLOR RGB color index
* @param aTransparency = the color transparency (default = 1.0 = no transparency)
*/
void SetGLColor( S3D_COLOR& aColor, float aTransparency );
/**
* Set a texture id and a scale to apply when rendering the polygons
* @param text_id = texture ID created by glGenTextures
* @param scale = scale to apply to texture coords
*/
void SetGLTexture( GLuint text_id, float scale );
#endif // _3D_DRAW_BASIC_FUNCTIONS_H_
+640
View File
@@ -0,0 +1,640 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2015 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
*/
/**
* @file 3d_draw_board_body.cpp
*
*/
#include <fctsys.h>
#include <common.h>
#include <trigo.h>
#include <pcbstruct.h>
#include <drawtxt.h>
#include <layers_id_colors_and_visibility.h>
#include <wxBasePcbFrame.h>
#include <class_board.h>
#include <class_module.h>
#include <class_track.h>
#include <class_edge_mod.h>
#include <class_zone.h>
#include <class_drawsegment.h>
#include <class_pcb_text.h>
#include <colors_selection.h>
#include <convert_basic_shapes_to_polygon.h>
#define GLM_FORCE_RADIANS
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
#include <gal/opengl/opengl_compositor.h>
#ifdef __WINDOWS__
#include <GL/glew.h> // must be included before gl.h
#endif
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <trackball.h>
#include <3d_draw_basic_functions.h>
#include <geometry/shape_poly_set.h>
#include <geometry/shape_file_io.h>
#include <CImage.h>
#include <reporter.h>
// An option for all operations on polygons:
// when useFastModeForPolygons = true, calculations can be *a lot* faster.
// but created polygons can be not stricty simple (can share edges)
// Although stricty simple are better for glu tesselation functions, I do not see
// any issue when allowing not stricty simple polygons.
// But I see *very* long calculations when setting useFastMode to false.
// So, be careful if changing thie option
bool useFastModeForPolygons = true;
/* returns the Z orientation parameter 1.0 or -1.0 for aLayer
* Z orientation is 1.0 for all layers but "back" layers:
* B_Cu , B_Adhes, B_Paste ), B_SilkS
* used to calculate the Z orientation parameter for glNormal3f
*/
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer );
void EDA_3D_CANVAS::buildBoardThroughHolesPolygonList( SHAPE_POLY_SET& allBoardHoles,
int aSegCountPerCircle, bool aOptimizeLargeCircles )
{
// hole diameter value to change seg count by circle:
int small_hole_limit = Millimeter2iu( 1.0 );
int copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU();
BOARD* pcb = GetBoard();
// Build holes of through vias:
for( TRACK* track = pcb->m_Track; track; track = track->Next() )
{
if( track->Type() != PCB_VIA_T )
continue;
VIA *via = static_cast<VIA*>( track );
if( via->GetViaType() != VIA_THROUGH )
continue;
int holediameter = via->GetDrillValue();
int hole_outer_radius = (holediameter + copper_thickness) / 2;
TransformCircleToPolygon( allBoardHoles,
via->GetStart(), hole_outer_radius,
aSegCountPerCircle );
}
// Build holes of through pads:
for( MODULE* footprint = pcb->m_Modules; footprint; footprint = footprint->Next() )
{
for( D_PAD* pad = footprint->Pads(); pad; pad = pad->Next() )
{
// Calculate a factor to apply to segcount for large holes ( > 1 mm)
// (bigger pad drill size -> more segments) because holes in pads can have
// very different sizes and optimizing this segcount gives a better look
// Mainly mounting holes have a size bigger than small_hole_limit
wxSize padHole = pad->GetDrillSize();
if( ! padHole.x ) // Not drilled pad like SMD pad
continue;
// we use the hole diameter to calculate the seg count.
// for round holes, padHole.x == padHole.y
// for oblong holes, the diameter is the smaller of (padHole.x, padHole.y)
int diam = std::min( padHole.x, padHole.y );
int segcount = aSegCountPerCircle;
if( diam > small_hole_limit )
{
double segFactor = (double)diam / small_hole_limit;
segcount = (int)(aSegCountPerCircle * segFactor);
// limit segcount to 48. For a circle this is a very good approx.
if( segcount > 48 )
segcount = 48;
}
// The hole in the body is inflated by copper thickness.
int inflate = copper_thickness;
// If not plated, no copper.
if( pad->GetAttribute () == PAD_ATTRIB_HOLE_NOT_PLATED )
inflate = 0;
pad->BuildPadDrillShapePolygon( allBoardHoles, inflate, segcount );
}
}
allBoardHoles.Simplify( useFastModeForPolygons );
}
void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
REPORTER* aErrorMessages, REPORTER* aActivity )
{
BOARD* pcb = GetBoard();
// If FL_RENDER_SHOW_HOLES_IN_ZONES is true, holes are correctly removed from copper zones areas.
// If FL_RENDER_SHOW_HOLES_IN_ZONES is false, holes are not removed from copper zones areas,
// but the calculation time is twice shorter.
bool remove_Holes = isEnabled( FL_RENDER_SHOW_HOLES_IN_ZONES );
bool realistic_mode = isRealisticMode();
bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );
// Number of segments to convert a circle to polygon
// We use 2 values: the first gives a good shape (for instanes rond pads)
// the second is used to speed up calculations, when a poor approximation is acceptable (holes)
const int segcountforcircle = 18;
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2.0) );
const int segcountLowQuality = 12; // segments to draw a circle with low quality
// to reduce time calculations
// for holes and items which do not need
// a fine representation
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2.0) );
SHAPE_POLY_SET bufferPolys; // copper areas: tracks, pads and filled zones areas
// when holes are removed from zones
SHAPE_POLY_SET bufferPcbOutlines; // stores the board main outlines
SHAPE_POLY_SET bufferZonesPolys; // copper filled zones areas
// when holes are not removed from zones
SHAPE_POLY_SET currLayerHoles; // Contains holes for the current layer
SHAPE_POLY_SET allLayerHoles; // Contains holes for all layers
// Build a polygon from edge cut items
wxString msg;
if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
{
if( aErrorMessages )
{
msg << wxT("\n") << _("Unable to calculate the board outlines.\n"
"Therefore use the board boundary box.") << wxT("\n\n");
aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
}
}
// Build board holes, with optimization of large holes shape.
buildBoardThroughHolesPolygonList( allLayerHoles, segcountLowQuality, true );
LSET cu_set = LSET::AllCuMask( GetPrm3DVisu().m_CopperLayersCount );
glNewList( aBoardList, GL_COMPILE );
for( LSEQ cu = cu_set.CuStack(); cu; ++cu )
{
LAYER_ID layer = *cu;
// Skip non enabled layers in normal mode,
// and internal layers in realistic mode
if( !is3DLayerEnabled( layer ) )
continue;
if( aActivity )
aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );
bufferPolys.RemoveAllContours();
bufferZonesPolys.RemoveAllContours();
currLayerHoles.RemoveAllContours();
// Draw track shapes:
for( TRACK* track = pcb->m_Track; track; track = track->Next() )
{
if( !track->IsOnLayer( layer ) )
continue;
track->TransformShapeWithClearanceToPolygon( bufferPolys,
0, segcountforcircle,
correctionFactor );
// Add blind/buried via holes
if( track->Type() == PCB_VIA_T )
{
VIA *via = static_cast<VIA*>( track );
if( via->GetViaType() == VIA_THROUGH )
continue; // already done
int holediameter = via->GetDrillValue();
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
int hole_outer_radius = (holediameter + thickness) / 2;
TransformCircleToPolygon( currLayerHoles,
via->GetStart(), hole_outer_radius,
segcountLowQuality );
}
}
// draw pad shapes
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
{
// Note: NPTH pads are not drawn on copper layers when the pad
// has same shape as its hole
module->TransformPadsShapesWithClearanceToPolygon( layer,
bufferPolys,
0,
segcountforcircle,
correctionFactor, true );
// Micro-wave modules may have items on copper layers
module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
bufferPolys,
0,
segcountforcircle,
correctionFactor );
// pad holes are already in list.
}
// Draw copper zones. Note:
// * if the holes are removed from copper zones
// the polygons are stored in bufferPolys (which contains all other polygons)
// * if the holes are NOT removed from copper zones
// the polygons are stored in bufferZonesPolys
if( isEnabled( FL_ZONE ) )
{
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
{
ZONE_CONTAINER* zone = pcb->GetArea( ii );
LAYER_NUM zonelayer = zone->GetLayer();
if( zonelayer == layer )
{
zone->TransformSolidAreasShapesToPolygonSet(
remove_Holes ? bufferPolys : bufferZonesPolys,
segcountLowQuality, correctionFactorLQ );
}
}
}
// draw graphic items on copper layers (texts)
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
{
if( !item->IsOnLayer( layer ) )
continue;
switch( item->Type() )
{
case PCB_LINE_T: // should not exist on copper layers
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
bufferPolys, 0, segcountforcircle, correctionFactor );
break;
case PCB_TEXT_T:
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
bufferPolys, 0, segcountLowQuality, correctionFactor );
break;
default:
break;
}
}
// bufferPolys contains polygons to merge. Many overlaps .
// Calculate merged polygons
if( bufferPolys.IsEmpty() )
continue;
// Use Clipper lib to subtract holes to copper areas
if( currLayerHoles.OutlineCount() )
{
currLayerHoles.Append(allLayerHoles);
currLayerHoles.Simplify( useFastModeForPolygons );
bufferPolys.BooleanSubtract( currLayerHoles, useFastModeForPolygons );
}
else
bufferPolys.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)
// If we are not using thickness, then the z-normal has to match the layer direction
// because just one plane will be drawn
if( !thickness )
zNormal = Get3DLayer_Z_Orientation( layer );
if( realistic_mode )
{
setGLCopperColor();
}
else
{
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
SetGLColor( color );
}
// If holes are removed from copper zones, bufferPolys contains all polygons
// to draw (tracks+zones+texts).
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos, thickness,
GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
zNormal );
// If holes are not removed from copper zones (for calculation time reasons,
// the zone polygons are stored in bufferZonesPolys and have to be drawn now:
if( !bufferZonesPolys.IsEmpty() )
{
Draw3D_SolidHorizontalPolyPolygons( bufferZonesPolys, zpos, thickness,
GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
zNormal );
}
}
if( aActivity )
aActivity->Report( _( "Build board body" ) );
// Draw plated vertical holes inside the board, but not always. They are drawn:
// - if the board body is not shown, to show the holes.
// - or if the copper thickness is shown
if( !isEnabled( FL_SHOW_BOARD_BODY ) || isEnabled( FL_USE_COPPER_THICKNESS ) )
{
// Draw vias holes (vertical cylinders)
for( const TRACK* track = pcb->m_Track; track; track = track->Next() )
{
if( track->Type() == PCB_VIA_T )
{
const VIA *via = static_cast<const VIA*>(track);
draw3DViaHole( via );
}
}
// Draw pads holes (vertical cylinders)
for( const MODULE* module = pcb->m_Modules; module; module = module->Next() )
{
for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
if( pad->GetAttribute () != PAD_ATTRIB_HOLE_NOT_PLATED )
draw3DPadHole( pad );
}
}
glEndList();
// Build the body board:
glNewList( aBodyOnlyList, GL_COMPILE );
if( isRealisticMode() )
{
setGLEpoxyColor( 1.00 );
}
else
{
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( Edge_Cuts );
SetGLColor( color, 0.7 );
}
float copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU();
// a small offset between substrate and external copper layer to avoid artifacts
// when drawing copper items on board
float epsilon = Millimeter2iu( 0.01 );
float zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
float board_thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
- GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
// items on copper layers and having a thickness = copper_thickness
// are drawn from zpos - copper_thickness/2 to zpos + copper_thickness
// therefore substrate position is copper_thickness/2 to
// substrate_height - copper_thickness/2
zpos += (copper_thickness + epsilon) / 2.0f;
board_thickness -= copper_thickness + epsilon;
bufferPcbOutlines.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
if( !bufferPcbOutlines.IsEmpty() )
{
Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness / 2.0,
board_thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
1.0f );
}
glEndList();
}
void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* aActivity )
{
BOARD* pcb = GetBoard();
bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );
// Number of segments to draw a circle using segments
const int segcountforcircle = 18;
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) );
const int segcountLowQuality = 12; // segments to draw a circle with low quality
// to reduce time calculations
// for holes and items which do not need
// a fine representation
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2) );
// segments to draw a circle to build texts. Is is used only to build
// the shape of each segment of the stroke font, therefore no need to have
// many segments per circle.
const int segcountInStrokeFont = 8;
SHAPE_POLY_SET bufferPolys;
SHAPE_POLY_SET allLayerHoles; // Contains through holes, calculated only once
SHAPE_POLY_SET bufferPcbOutlines; // stores the board main outlines
// Build a polygon from edge cut items
wxString msg;
if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
{
if( aErrorMessages )
{
msg << wxT("\n") <<
_("Unable to calculate the board outlines.\n"
"Therefore use the board boundary box.") << wxT("\n\n");
aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
}
}
// Build board holes, with no optimization of large holes shape.
buildBoardThroughHolesPolygonList( allLayerHoles, segcountLowQuality, false );
// draw graphic items, on technical layers
static const LAYER_ID teckLayerList[] = {
B_Adhes,
F_Adhes,
B_Paste,
F_Paste,
B_SilkS,
F_SilkS,
B_Mask,
F_Mask,
};
// User layers are not drawn here, only technical layers
for( LSEQ seq = LSET::AllTechMask().Seq( teckLayerList, DIM( teckLayerList ) ); seq; ++seq )
{
LAYER_ID layer = *seq;
if( !is3DLayerEnabled( layer ) )
continue;
if( layer == Edge_Cuts && isEnabled( FL_SHOW_BOARD_BODY ) )
continue;
if( aActivity )
aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );
bufferPolys.RemoveAllContours();
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
{
if( !item->IsOnLayer( layer ) )
continue;
switch( item->Type() )
{
case PCB_LINE_T:
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
bufferPolys, 0, segcountforcircle, correctionFactor );
break;
case PCB_TEXT_T:
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
bufferPolys, 0, segcountLowQuality, 1.0 );
break;
default:
break;
}
}
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
{
if( layer == F_SilkS || layer == B_SilkS )
{
// On silk screen layers, the pad shape is only the pad outline
// never a filled shape
D_PAD* pad = module->Pads();
int linewidth = g_DrawDefaultLineThickness;
for( ; pad; pad = pad->Next() )
{
if( !pad->IsOnLayer( layer ) )
continue;
buildPadShapeThickOutlineAsPolygon( pad, bufferPolys,
linewidth, segcountforcircle, correctionFactor );
}
}
else
module->TransformPadsShapesWithClearanceToPolygon( layer,
bufferPolys, 0, segcountforcircle, correctionFactor );
// On tech layers, use a poor circle approximation, only for texts (stroke font)
module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
bufferPolys, 0, segcountforcircle, correctionFactor, segcountInStrokeFont );
}
// Draw non copper zones
if( isEnabled( FL_ZONE ) )
{
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
{
ZONE_CONTAINER* zone = pcb->GetArea( ii );
if( !zone->IsOnLayer( layer ) )
continue;
zone->TransformSolidAreasShapesToPolygonSet(
bufferPolys, segcountLowQuality, correctionFactorLQ );
}
}
// bufferPolys contains polygons to merge. Many overlaps .
// Calculate merged polygons and remove pads and vias holes
if( layer != B_Mask && layer != F_Mask && bufferPolys.IsEmpty() )
// if a layer has no iten to draw, skip it
// However solder mask layers are negative layers, so no item
// means only a full layer mask
continue;
// Solder mask layers are "negative" layers.
// Shapes should be removed from the full board area.
if( layer == B_Mask || layer == F_Mask )
{
SHAPE_POLY_SET cuts = bufferPolys;
bufferPolys = bufferPcbOutlines;
cuts.Append(allLayerHoles);
cuts.Simplify( useFastModeForPolygons );
bufferPolys.BooleanSubtract( cuts, useFastModeForPolygons );
}
// Remove holes from Solder paste layers and silkscreen
else if( layer == B_Paste || layer == F_Paste
|| layer == B_SilkS || layer == F_SilkS )
{
bufferPolys.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
}
int thickness = 0;
if( layer != B_Mask && layer != F_Mask )
thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
if( layer == Edge_Cuts )
{
thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
- GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu )
+ (thickness / 2);
}
else
{
// for Draw3D_SolidHorizontalPolyPolygons, zpos it the middle between bottom and top
// sides.
// However for top layers, zpos should be the bottom layer pos,
// and for bottom layers, zpos should be the top layer pos.
if( Get3DLayer_Z_Orientation( layer ) > 0 )
zpos += thickness/2;
else
zpos -= thickness/2 ;
}
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)
// If we are not using thickness, then the znormal must face the layer direction
// because it will draw just one plane
if( !thickness )
zNormal = Get3DLayer_Z_Orientation( layer );
setGLTechLayersColor( layer );
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos,
thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
zNormal );
}
}
+493
View File
@@ -0,0 +1,493 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2014 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
*/
/**
* @file 3d_draw_helper_functions.cpp
*/
#include <fctsys.h>
#include <PolyLine.h>
#include <colors.h>
#include <colors_selection.h>
#include <class_pad.h>
#include <class_track.h>
#include <convert_basic_shapes_to_polygon.h>
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <3d_draw_basic_functions.h>
#define TEXTURE_PCB_SCALE 5.0
// -----------------
// helper function (from wxWidgets, opengl/cube.cpp sample
// -----------------
void CheckGLError(const char *aFileName, int aLineNumber)
{
GLenum errLast = GL_NO_ERROR;
for ( ; ; )
{
GLenum err = glGetError();
if ( err == GL_NO_ERROR )
return;
// normally the error is reset by the call to glGetError() but if
// glGetError() itself returns an error, we risk looping forever here
// so check that we get a different error than the last time
if ( err == errLast )
{
wxLogError(wxT("OpenGL error state couldn't be reset."));
return;
}
errLast = err;
wxLogError( wxT( "OpenGL error %d At: %s, line: %d" ), err,
GetChars( FROM_UTF8( aFileName ) ), aLineNumber );
}
}
INFO3D_VISU& EDA_3D_CANVAS::GetPrm3DVisu() const
{
return Parent()->GetPrm3DVisu();
}
wxSize EDA_3D_CANVAS::getBoardSize() const
{
// return the size of the board in pcb units
return GetPrm3DVisu().m_BoardSize;
}
wxPoint EDA_3D_CANVAS::getBoardCenter() const
{
// return the position of the board center in pcb units
return GetPrm3DVisu().m_BoardPos;
}
// return true if we are in realistic mode render
bool EDA_3D_CANVAS::isRealisticMode() const
{
return GetPrm3DVisu().IsRealisticMode();
}
// return true if aItem should be displayed
bool EDA_3D_CANVAS::isEnabled( DISPLAY3D_FLG aItem ) const
{
return GetPrm3DVisu().GetFlag( aItem );
}
// Helper function: initialize the copper color to draw the board
// in realistic mode.
void EDA_3D_CANVAS::setGLCopperColor()
{
glDisable( GL_TEXTURE_2D );
SetGLColor( GetPrm3DVisu().m_CopperColor, 1.0 );
}
// Helper function: initialize the color to draw the epoxy
// body board in realistic mode.
void EDA_3D_CANVAS::setGLEpoxyColor( float aTransparency )
{
// Generates an epoxy color, near board color
SetGLColor( GetPrm3DVisu().m_BoardBodyColor, aTransparency );
if( isEnabled( FL_RENDER_TEXTURES ) )
{
SetGLTexture( m_text_pcb, TEXTURE_PCB_SCALE );
}
}
// Helper function: initialize the color to draw the
// solder mask layers in realistic mode.
void EDA_3D_CANVAS::setGLSolderMaskColor( float aTransparency )
{
// Generates a solder mask color
SetGLColor( GetPrm3DVisu().m_SolderMaskColor, aTransparency );
if( isEnabled( FL_RENDER_TEXTURES ) )
{
SetGLTexture( m_text_pcb, TEXTURE_PCB_SCALE );
}
}
// Helper function: initialize the color to draw the non copper layers
// in realistic mode and normal mode.
void EDA_3D_CANVAS::setGLTechLayersColor( LAYER_NUM aLayer )
{
EDA_COLOR_T color;
if( isRealisticMode() )
{
switch( aLayer )
{
case B_Paste:
case F_Paste:
SetGLColor( GetPrm3DVisu().m_SolderPasteColor, 1 );
break;
case B_SilkS:
case F_SilkS:
SetGLColor( GetPrm3DVisu().m_SilkScreenColor, 0.96 );
if( isEnabled( FL_RENDER_TEXTURES ) )
{
SetGLTexture( m_text_silk, 10.0f );
}
break;
case B_Mask:
case F_Mask:
setGLSolderMaskColor( 0.90 );
break;
default:
color = g_ColorsSettings.GetLayerColor( aLayer );
SetGLColor( color, 0.7 );
break;
}
}
else
{
color = g_ColorsSettings.GetLayerColor( aLayer );
SetGLColor( color, 0.7 );
}
}
void EDA_3D_CANVAS::draw3DAxis()
{
if( ! m_glLists[GL_ID_AXIS] )
{
m_glLists[GL_ID_AXIS] = glGenLists( 1 );
glNewList( m_glLists[GL_ID_AXIS], GL_COMPILE );
glEnable( GL_COLOR_MATERIAL );
glBegin( GL_LINES );
SetGLColor( RED );
glNormal3f( 0.0f, 0.0f, 1.0f ); // Normal is Z axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( -10.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 10.0f, 0.0f, 0.0f ); // X axis
SetGLColor( GREEN );
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, -10.0f, 0.0f ); // Y axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 10.0f, 0.0f );
SetGLColor( BLUE );
glNormal3f( 1.0f, 0.0f, 0.0f ); // Normal is Y axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 0.0f, -10.0f );
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 0.0f, 10.0f ); // Z axis
glEnd();
glEndList();
}
}
// draw a 3D grid: an horizontal grid (XY plane and Z = 0,
// and a vertical grid (XZ plane and Y = 0)
void EDA_3D_CANVAS::draw3DGrid( double aGriSizeMM )
{
double zpos = 0.0;
EDA_COLOR_T gridcolor = DARKGRAY; // Color of grid lines
EDA_COLOR_T gridcolor_marker = LIGHTGRAY; // Color of grid lines every 5 lines
const double scale = GetPrm3DVisu().m_BiuTo3Dunits;
const double transparency = 0.3;
glNormal3f( 0.0, 0.0, 1.0 );
wxSize brd_size = getBoardSize();
wxPoint brd_center_pos = getBoardCenter();
brd_center_pos.y = -brd_center_pos.y;
int xsize = std::max( brd_size.x, Millimeter2iu( 100 ) ) * 1.2;
int ysize = std::max( brd_size.y, Millimeter2iu( 100 ) ) * 1.2;
// Grid limits, in 3D units
double xmin = (brd_center_pos.x - xsize / 2) * scale;
double xmax = (brd_center_pos.x + xsize / 2) * scale;
double ymin = (brd_center_pos.y - ysize / 2) * scale;
double ymax = (brd_center_pos.y + ysize / 2) * scale;
double zmin = Millimeter2iu( -50 ) * scale;
double zmax = Millimeter2iu( 100 ) * scale;
// Draw horizontal grid centered on 3D origin (center of the board)
for( int ii = 0; ; ii++ )
{
if( (ii % 5) )
SetGLColor( gridcolor, transparency );
else
SetGLColor( gridcolor_marker, transparency );
int delta = KiROUND( ii * aGriSizeMM * IU_PER_MM );
if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
{
glBegin( GL_LINES );
glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
glEnd();
if( ii != 0 )
{
glBegin( GL_LINES );
glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
glEnd();
}
}
if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
{
glBegin( GL_LINES );
glVertex3f( xmin, -(brd_center_pos.y + delta) * scale, zpos );
glVertex3f( xmax, -(brd_center_pos.y + delta) * scale, zpos );
glEnd();
if( ii != 0 )
{
glBegin( GL_LINES );
glVertex3f( xmin, -(brd_center_pos.y - delta) * scale, zpos );
glVertex3f( xmax, -(brd_center_pos.y - delta) * scale, zpos );
glEnd();
}
}
if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
break;
}
// Draw vertical grid on Z axis
glNormal3f( 0.0, -1.0, 0.0 );
// Draw vertical grid lines (parallel to Z axis)
double posy = -brd_center_pos.y * scale;
for( int ii = 0; ; ii++ )
{
if( (ii % 5) )
SetGLColor( gridcolor, transparency );
else
SetGLColor( gridcolor_marker, transparency );
double delta = ii * aGriSizeMM * IU_PER_MM;
glBegin( GL_LINES );
xmax = (brd_center_pos.x + delta) * scale;
glVertex3f( xmax, posy, zmin );
glVertex3f( xmax, posy, zmax );
glEnd();
if( ii != 0 )
{
glBegin( GL_LINES );
xmin = (brd_center_pos.x - delta) * scale;
glVertex3f( xmin, posy, zmin );
glVertex3f( xmin, posy, zmax );
glEnd();
}
if( delta > xsize / 2.0f )
break;
}
// Draw horizontal grid lines on Z axis (parallel to X axis)
for( int ii = 0; ; ii++ )
{
if( (ii % 5) )
SetGLColor( gridcolor, transparency);
else
SetGLColor( gridcolor_marker, transparency );
double delta = ii * aGriSizeMM * IU_PER_MM * scale;
if( delta <= zmax )
{
// Draw grid lines on Z axis (positive Z axis coordinates)
glBegin( GL_LINES );
glVertex3f( xmin, posy, delta );
glVertex3f( xmax, posy, delta );
glEnd();
}
if( delta <= -zmin && ( ii != 0 ) )
{
// Draw grid lines on Z axis (negative Z axis coordinates)
glBegin( GL_LINES );
glVertex3f( xmin, posy, -delta );
glVertex3f( xmax, posy, -delta );
glEnd();
}
if( ( delta > zmax ) && ( delta > -zmin ) )
break;
}
}
// Draw 3D pads.
void EDA_3D_CANVAS::draw3DPadHole( const D_PAD* aPad )
{
// Draw the pad hole
wxSize drillsize = aPad->GetDrillSize();
bool hasHole = drillsize.x && drillsize.y;
if( !hasHole )
return;
// Store here the points to approximate hole by segments
SHAPE_POLY_SET holecornersBuffer;
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
int height = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu ) -
GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
if( isRealisticMode() )
setGLCopperColor();
else
SetGLColor( DARKGRAY );
int holeZpoz = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu ) - thickness / 2;
int holeHeight = height + thickness;
if( drillsize.x == drillsize.y ) // usual round hole
{
int hole_radius = ( drillsize.x + thickness ) / 2;
Draw3D_ZaxisCylinder( aPad->GetPosition(),
hole_radius, holeHeight,
thickness, holeZpoz, GetPrm3DVisu().m_BiuTo3Dunits );
}
else // Oblong hole
{
wxPoint ends_offset;
int width;
if( drillsize.x > drillsize.y ) // Horizontal oval
{
ends_offset.x = ( drillsize.x - drillsize.y ) / 2;
width = drillsize.y;
}
else // Vertical oval
{
ends_offset.y = ( drillsize.y - drillsize.x ) / 2;
width = drillsize.x;
}
RotatePoint( &ends_offset, aPad->GetOrientation() );
wxPoint start = aPad->GetPosition() + ends_offset;
wxPoint end = aPad->GetPosition() - ends_offset;
int hole_radius = ( width + thickness ) / 2;
// Draw the hole
Draw3D_ZaxisOblongCylinder( start, end, hole_radius, holeHeight,
thickness, holeZpoz, GetPrm3DVisu().m_BiuTo3Dunits );
}
}
void EDA_3D_CANVAS::draw3DViaHole( const VIA* aVia )
{
LAYER_ID top_layer, bottom_layer;
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
int inner_radius = (int)((float)aVia->GetDrillValue() * 1.01f) / 2.0f; // This add a bit more in order to correct a draw artifact while using tickness
aVia->LayerPair( &top_layer, &bottom_layer );
// Drawing via hole:
if( isRealisticMode() )
setGLCopperColor();
else
{
EDA_COLOR_T color = g_ColorsSettings.GetItemColor( VIAS_VISIBLE + aVia->GetViaType() );
SetGLColor( color );
}
int height = GetPrm3DVisu().GetLayerZcoordBIU( top_layer ) -
GetPrm3DVisu().GetLayerZcoordBIU( bottom_layer ) + thickness;
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( bottom_layer ) - thickness / 2;
Draw3D_ZaxisCylinder( aVia->GetStart(), inner_radius, height,
thickness, zpos, GetPrm3DVisu().m_BiuTo3Dunits );
}
/* Build a pad outline as non filled polygon, to draw pads on silkscreen layer
* Used only to draw pads outlines on silkscreen layers.
*/
void EDA_3D_CANVAS::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
SHAPE_POLY_SET& aCornerBuffer,
int aWidth,
int aCircleToSegmentsCount,
double aCorrectionFactor )
{
if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring
{
TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(),
aPad->GetSize().x / 2, aCircleToSegmentsCount, aWidth );
return;
}
// For other shapes, draw polygon outlines
SHAPE_POLY_SET corners;
aPad->BuildPadShapePolygon( corners, wxSize( 0, 0 ),
aCircleToSegmentsCount, aCorrectionFactor );
// Add outlines as thick segments in polygon buffer
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
for( int ii = 0; ii < path.PointCount(); ii++ )
{
const VECTOR2I& a = path.CPoint( ii );
const VECTOR2I& b = path.CPoint( ii + 1 );
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
wxPoint( a.x, a.y ),
wxPoint( b.x, b.y ),
aCircleToSegmentsCount, aWidth );
}
}
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer )
{
double nZ = 1.0;
if( ( aLayer == B_Cu )
|| ( aLayer == B_Adhes )
|| ( aLayer == B_Paste )
|| ( aLayer == B_SilkS )
|| ( aLayer == B_Mask ) )
nZ = -1.0;
return nZ;
}
-68
View File
@@ -1,68 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright The 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
*/
/**
* @file 3d_fastmath.cpp
* @brief
*/
#include "3d_fastmath.h"
// Fast Float Random Numbers
// a small and fast implementation for random float numbers in the range [-1,1]
// References : Posted by dominik.ries[AT]gmail[DOT]com
// http://www.musicdsp.org/showone.php?id=273
// set the initial seed to whatever you like
static int s_randSeed = 1;
// fast rand float, using full 32bit precision
// returns in the range [-1, 1] (not confirmed)
float Fast_RandFloat()
{
s_randSeed *= 16807;
return (float)s_randSeed * 4.6566129e-010f;
}
// Fast rand, as described here:
// http://wiki.osdev.org/Random_Number_Generator
static unsigned long int s_nextRandSeed = 1;
int Fast_rand( void ) // RAND_MAX assumed to be 32767
{
s_nextRandSeed = s_nextRandSeed * 1103515245 + 12345;
return (unsigned int)(s_nextRandSeed >> 16) & 0x7FFF;
}
void Fast_srand( unsigned int seed )
{
s_nextRandSeed = seed;
}
-176
View File
@@ -1,176 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright The 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
*/
/**
* @file 3d_fastmath.h
* @brief Defines math related functions
*/
#ifndef _3D_FASTMATH_H
#define _3D_FASTMATH_H
#include <cmath>
#include <cstdint>
#include <cstring>
// Define this flag to use fast math optimizations
#define FASTMATH_USE
#define L1_CACHE_LINE_SIZE 64
#ifdef FASTMATH_USE
#define INTFLOORF(s) (lrintf( (s) - (0.5f - FLT_EPSILON) ))
#else
#define INTFLOORF(s) ((int)( floor(s) ))
#endif
// Fast Float Random Numbers
// a small and fast implementation for random float numbers in the range [-1,1]
// This is not thread safe
float Fast_RandFloat();
int Fast_rand( void );
void Fast_srand( unsigned int seed );
/**
* This part contains some functions from the PBRT 3 source code.
* https://github.com/mmp/pbrt-v3/blob/master/src/core/pbrt.h
*/
/*
pbrt source code is Copyright(c) 1998-2015
Matt Pharr, Greg Humphreys, and Wenzel Jakob.
This file is part of pbrt.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Global Inline Functions
inline uint32_t FloatToBits( float f )
{
uint32_t ui;
memcpy( &ui, &f, sizeof( float ) );
return ui;
}
inline float BitsToFloat( uint32_t ui )
{
float f;
memcpy( &f, &ui, sizeof (uint32_t ) );
return f;
}
inline uint64_t FloatToBits( double f )
{
uint64_t ui;
memcpy( &ui, &f, sizeof( double ) );
return ui;
}
inline double BitsToFloat( uint64_t ui )
{
double f;
memcpy( &f, &ui, sizeof( uint64_t ) );
return f;
}
inline float NextFloatUp( float v )
{
// Handle infinity and negative zero for _NextFloatUp()_
if( std::isinf( v ) && (v > 0.) )
return v;
if( v == -0.f )
v = 0.f;
// Advance _v_ to next higher float
uint32_t ui = FloatToBits( v );
if( v >= 0. )
++ui;
else
--ui;
return BitsToFloat( ui );
}
inline float NextFloatDown( float v )
{
// Handle infinity and positive zero for _NextFloatDown()_
if( std::isinf( v ) && (v < 0.) )
return v;
if( v == 0.f )
v = -0.f;
uint32_t ui = FloatToBits( v );
if( v > 0. )
--ui;
else
++ui;
return BitsToFloat( ui );
}
#endif // 3D_FASTMATH_H
+915
View File
@@ -0,0 +1,915 @@
/**
* @file 3d_frame.cpp
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2016 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 <fctsys.h>
#include <kiface_i.h>
#include <pgm_base.h>
#include <macros.h>
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <trackball.h>
#include <wx/colordlg.h>
#include <3d_viewer_id.h>
#include <wxBasePcbFrame.h>
INFO3D_VISU g_Parm_3D_Visu;
// Key to store 3D Viewer config:
static const wxChar keyBgColor_Red[] = wxT( "BgColor_Red" );
static const wxChar keyBgColor_Green[] = wxT( "BgColor_Green" );
static const wxChar keyBgColor_Blue[] = wxT( "BgColor_Blue" );
static const wxChar keyBgColor_Red_Top[] = wxT( "BgColor_Red_Top" );
static const wxChar keyBgColor_Green_Top[] = wxT( "BgColor_Green_Top" );
static const wxChar keyBgColor_Blue_Top[] = wxT( "BgColor_Blue_Top" );
static const wxChar keySMaskColor_Red[] = wxT( "SMaskColor_Red" );
static const wxChar keySMaskColor_Green[] = wxT( "SMaskColor_Green" );
static const wxChar keySMaskColor_Blue[] = wxT( "SMaskColor_Blue" );
static const wxChar keySPasteColor_Red[] = wxT( "SPasteColor_Red" );
static const wxChar keySPasteColor_Green[] = wxT( "SPasteColor_Green" );
static const wxChar keySPasteColor_Blue[] = wxT( "SPasteColor_Blue" );
static const wxChar keySilkColor_Red[] = wxT( "SilkColor_Red" );
static const wxChar keySilkColor_Green[] = wxT( "SilkColor_Green" );
static const wxChar keySilkColor_Blue[] = wxT( "SilkColor_Blue" );
static const wxChar keyCopperColor_Red[] = wxT( "CopperColor_Red" );
static const wxChar keyCopperColor_Green[] = wxT( "CopperColor_Green" );
static const wxChar keyCopperColor_Blue[] = wxT( "CopperColor_Blue" );
static const wxChar keyBoardBodyColor_Red[] = wxT( "BoardBodyColor_Red" );
static const wxChar keyBoardBodyColor_Green[] = wxT( "BoardBodyColor_Green" );
static const wxChar keyBoardBodyColor_Blue[]= wxT( "BoardBodyColor_Blue" );
static const wxChar keyMousewheelPanning[] = wxT( "MousewheelPAN3D" );
static const wxChar keyShowRealisticMode[] = wxT( "ShowRealisticMode" );
static const wxChar keyRenderShadows[] = wxT( "Render_Shadows" );
static const wxChar keyRenderRemoveHoles[] = wxT( "Render_RemoveHoles" );
static const wxChar keyRenderTextures[] = wxT( "Render_Textures" );
static const wxChar keyRenderSmoothNormals[] = wxT( "Render_Smooth_Normals" );
static const wxChar keyRenderUseModelNormals[] =wxT( "Render_Use_Model_Normals" );
static const wxChar keyRenderMaterial[] = wxT( "Render_Material" );
static const wxChar keyRenderShowModelBBox[] = wxT( "Render_ShowModelBoudingBoxes" );
static const wxChar keyShowAxis[] = wxT( "ShowAxis" );
static const wxChar keyShowGrid[] = wxT( "ShowGrid3D" );
static const wxChar keyShowGridSize[] = wxT( "Grid3DSize" );
static const wxChar keyShowZones[] = wxT( "ShowZones" );
static const wxChar keyShowFootprints[] = wxT( "ShowFootprints" );
static const wxChar keyShowCopperThickness[] = wxT( "ShowCopperThickness" );
static const wxChar keyShowAdhesiveLayers[] = wxT( "ShowAdhesiveLayers" );
static const wxChar keyShowSilkScreenLayers[] = wxT( "ShowSilkScreenLayers" );
static const wxChar keyShowSolderMaskLayers[] = wxT( "ShowSolderMasLayers" );
static const wxChar keyShowSolderPasteLayers[] =wxT( "ShowSolderPasteLayers" );
static const wxChar keyShowCommentsLayer[] = wxT( "ShowCommentsLayers" );
static const wxChar keyShowBoardBody[] = wxT( "ShowBoardBody" );
static const wxChar keyShowEcoLayers[] = wxT( "ShowEcoLayers" );
BEGIN_EVENT_TABLE( EDA_3D_FRAME, EDA_BASE_FRAME )
EVT_ACTIVATE( EDA_3D_FRAME::OnActivate )
EVT_TOOL_RANGE( ID_ZOOM_IN, ID_ZOOM_PAGE, EDA_3D_FRAME::Process_Zoom )
EVT_TOOL_RANGE( ID_START_COMMAND_3D, ID_END_COMMAND_3D,
EDA_3D_FRAME::Process_Special_Functions )
EVT_TOOL( ID_TOOL_SET_VISIBLE_ITEMS, EDA_3D_FRAME::Process_Special_Functions )
EVT_MENU( wxID_EXIT, EDA_3D_FRAME::Exit3DFrame )
EVT_MENU( ID_MENU_SCREENCOPY_PNG, EDA_3D_FRAME::Process_Special_Functions )
EVT_MENU( ID_MENU_SCREENCOPY_JPEG, EDA_3D_FRAME::Process_Special_Functions )
EVT_MENU_RANGE( ID_MENU3D_GRID, ID_MENU3D_GRID_END,
EDA_3D_FRAME::On3DGridSelection )
EVT_CLOSE( EDA_3D_FRAME::OnCloseWindow )
END_EVENT_TABLE()
EDA_3D_FRAME::EDA_3D_FRAME( KIWAY* aKiway, PCB_BASE_FRAME* aParent,
const wxString& aTitle, long style ) :
KIWAY_PLAYER( aKiway, aParent, FRAME_PCB_DISPLAY3D, aTitle,
wxDefaultPosition, wxDefaultSize, style, wxT( "Frame3D" ) )
{
m_canvas = NULL;
m_reloadRequest = false;
m_ortho = false;
// Give it an icon
wxIcon icon;
icon.CopyFromBitmap( KiBitmap( icon_3d_xpm ) );
SetIcon( icon );
LoadSettings( config() );
SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y );
// Create the status line
static const int status_dims[4] = { -1, 130, 130, 170 };
CreateStatusBar( DIM( status_dims ) );
SetStatusWidths( DIM( status_dims ), status_dims );
CreateMenuBar();
ReCreateMainToolbar();
// Make a EDA_3D_CANVAS
// Note: We try to use anti aliasing if the graphic card allows that,
// but only on wxWidgets >= 3.0.0 (this option does not exist on wxWidgets 2.8)
int attrs[] = { // This array should be 2*n+1
// Sadly wxwidgets / glx < 13 allowed
// a thing named "boolean attributes" that don't take a value.
// (See src/unix/glx11.cpp -> wxGLCanvasX11::ConvertWXAttrsToGL() ).
// To avoid problems due to this, just specify those attributes twice.
// Only WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_STEREO are such boolean
// attributes.
// Boolean attributes (using itself at padding):
WX_GL_RGBA, WX_GL_RGBA,
WX_GL_DOUBLEBUFFER, WX_GL_DOUBLEBUFFER,
// Normal attributes with values:
WX_GL_DEPTH_SIZE, 16,
WX_GL_STENCIL_SIZE, 1,
WX_GL_SAMPLE_BUFFERS, 1, // Enable multisampling support (antialiasing).
WX_GL_SAMPLES, 0, // Disable AA for the start.
0 }; // NULL termination
// Check if the canvas supports multisampling.
if( EDA_3D_CANVAS::IsDisplaySupported( attrs ) )
{
// Check for possible sample sizes, start form the top.
int maxSamples = 8; // Any higher doesn't change anything.
int samplesOffset = 0;
for( unsigned int ii = 0; ii < DIM( attrs ); ii += 2 )
{
if( attrs[ii] == WX_GL_SAMPLES )
{
samplesOffset = ii+1;
break;
}
}
attrs[samplesOffset] = maxSamples;
for( ; maxSamples > 0 && !EDA_3D_CANVAS::IsDisplaySupported( attrs );
maxSamples = maxSamples>>1 )
{
attrs[samplesOffset] = maxSamples;
}
}
else
{
// Disable multisampling
for( unsigned int ii = 0; ii < DIM( attrs ); ii += 2 )
{
if( attrs[ii] == WX_GL_SAMPLE_BUFFERS )
{
attrs[ii+1] = 0;
break;
}
}
}
m_canvas = new EDA_3D_CANVAS( this, attrs );
m_auimgr.SetManagedWindow( this );
EDA_PANEINFO horiztb;
horiztb.HorizontalToolbarPane();
m_auimgr.AddPane( m_mainToolBar,
wxAuiPaneInfo( horiztb ).Name( wxT( "m_mainToolBar" ) ).Top() );
m_auimgr.AddPane( m_canvas,
wxAuiPaneInfo().Name( wxT( "DrawFrame" ) ).CentrePane() );
m_auimgr.Update();
// Fixes bug in Windows (XP and possibly others) where the canvas requires the focus
// in order to receive mouse events. Otherwise, the user has to click somewhere on
// the canvas before it will respond to mouse wheel events.
m_canvas->SetFocus();
}
EDA_3D_FRAME::~EDA_3D_FRAME()
{
m_auimgr.UnInit();
}
void EDA_3D_FRAME::Exit3DFrame( wxCommandEvent& event )
{
Close( true );
}
void EDA_3D_FRAME::OnCloseWindow( wxCloseEvent& Event )
{
if( Parent() )
Parent()->m_Draw3DFrame = NULL;
Destroy();
}
void EDA_3D_FRAME::LoadSettings( wxConfigBase* aCfg )
{
EDA_BASE_FRAME::LoadSettings( aCfg );
INFO3D_VISU& prms = GetPrm3DVisu();
aCfg->Read( keyBgColor_Red, &GetPrm3DVisu().m_BgColor.m_Red, 0.4 );
aCfg->Read( keyBgColor_Green, &GetPrm3DVisu().m_BgColor.m_Green, 0.4 );
aCfg->Read( keyBgColor_Blue, &GetPrm3DVisu().m_BgColor.m_Blue, 0.5 );
aCfg->Read( keyBgColor_Red_Top, &GetPrm3DVisu().m_BgColor_Top.m_Red, 0.8 );
aCfg->Read( keyBgColor_Green_Top, &GetPrm3DVisu().m_BgColor_Top.m_Green, 0.8 );
aCfg->Read( keyBgColor_Blue_Top, &GetPrm3DVisu().m_BgColor_Top.m_Blue, 0.9 );
// m_SolderMaskColor default value = dark grey-green
aCfg->Read( keySMaskColor_Red, &GetPrm3DVisu().m_SolderMaskColor.m_Red, 100.0 * 0.2 / 255.0 );
aCfg->Read( keySMaskColor_Green, &GetPrm3DVisu().m_SolderMaskColor.m_Green, 255.0 * 0.2 / 255.0 );
aCfg->Read( keySMaskColor_Blue, &GetPrm3DVisu().m_SolderMaskColor.m_Blue, 180.0 * 0.2 / 255.0 );
// m_SolderPasteColor default value = light grey
aCfg->Read( keySPasteColor_Red, &GetPrm3DVisu().m_SolderPasteColor.m_Red, 128.0 /255.0 );
aCfg->Read( keySPasteColor_Green, &GetPrm3DVisu().m_SolderPasteColor.m_Green, 128.0 /255.0 );
aCfg->Read( keySPasteColor_Blue, &GetPrm3DVisu().m_SolderPasteColor.m_Blue, 128.0 /255.0 );
// m_SilkScreenColor default value = white
aCfg->Read( keySilkColor_Red, &GetPrm3DVisu().m_SilkScreenColor.m_Red, 0.9 );
aCfg->Read( keySilkColor_Green, &GetPrm3DVisu().m_SilkScreenColor.m_Green, 0.9 );
aCfg->Read( keySilkColor_Blue, &GetPrm3DVisu().m_SilkScreenColor.m_Blue, 0.9 );
// m_CopperColor default value = gold
aCfg->Read( keyCopperColor_Red, &GetPrm3DVisu().m_CopperColor.m_Red, 255.0 * 0.7 / 255.0 );
aCfg->Read( keyCopperColor_Green, &GetPrm3DVisu().m_CopperColor.m_Green, 223.0 * 0.7 / 255.0 );
aCfg->Read( keyCopperColor_Blue, &GetPrm3DVisu().m_CopperColor.m_Blue, 0.0 /255.0 );
// m_BoardBodyColor default value = FR4, in realistic mode
aCfg->Read( keyBoardBodyColor_Red, &GetPrm3DVisu().m_BoardBodyColor.m_Red, 51.0 / 255.0 );
aCfg->Read( keyBoardBodyColor_Green, &GetPrm3DVisu().m_BoardBodyColor.m_Green, 43.0 / 255.0 );
aCfg->Read( keyBoardBodyColor_Blue, &GetPrm3DVisu().m_BoardBodyColor.m_Blue, 22.0 /255.0 );
bool tmp;
aCfg->Read( keyMousewheelPanning, &tmp, false );
prms.SetFlag( FL_MOUSEWHEEL_PANNING, tmp );
aCfg->Read( keyShowRealisticMode, &tmp, false );
prms.SetFlag( FL_USE_REALISTIC_MODE, tmp );
aCfg->Read( keyRenderShadows, &tmp, false );
prms.SetFlag( FL_RENDER_SHADOWS, tmp );
aCfg->Read( keyRenderRemoveHoles, &tmp, false );
prms.SetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES, tmp );
aCfg->Read( keyRenderTextures, &tmp, false );
prms.SetFlag( FL_RENDER_TEXTURES, tmp );
aCfg->Read( keyRenderSmoothNormals, &tmp, false );
prms.SetFlag( FL_RENDER_SMOOTH_NORMALS, tmp );
aCfg->Read( keyRenderUseModelNormals, &tmp, false );
prms.SetFlag( FL_RENDER_USE_MODEL_NORMALS, tmp );
aCfg->Read( keyRenderMaterial, &tmp, false );
prms.SetFlag( FL_RENDER_MATERIAL, tmp );
aCfg->Read( keyRenderShowModelBBox, &tmp, false );
prms.SetFlag( FL_RENDER_SHOW_MODEL_BBOX, tmp );
aCfg->Read( keyShowAxis, &tmp, true );
prms.SetFlag( FL_AXIS, tmp );
aCfg->Read( keyShowGrid, &tmp, true );
prms.SetFlag( FL_GRID, tmp );
aCfg->Read( keyShowGridSize, &prms.m_3D_Grid, 10.0 );
aCfg->Read( keyShowFootprints, &tmp, true );
prms.SetFlag( FL_MODULE, tmp );
aCfg->Read( keyShowCopperThickness, &tmp, false );
prms.SetFlag( FL_USE_COPPER_THICKNESS, tmp );
aCfg->Read( keyShowZones, &tmp, true );
prms.SetFlag( FL_ZONE, tmp );
aCfg->Read( keyShowAdhesiveLayers, &tmp, true );
prms.SetFlag( FL_ADHESIVE, tmp );
aCfg->Read( keyShowSilkScreenLayers, &tmp, true );
prms.SetFlag( FL_SILKSCREEN, tmp );
aCfg->Read( keyShowSolderMaskLayers, &tmp, true );
prms.SetFlag( FL_SOLDERMASK, tmp );
aCfg->Read( keyShowSolderPasteLayers, &tmp, true );
prms.SetFlag( FL_SOLDERPASTE, tmp );
aCfg->Read( keyShowCommentsLayer, &tmp, true );
prms.SetFlag( FL_COMMENTS, tmp );
aCfg->Read( keyShowEcoLayers, &tmp, true );
prms.SetFlag( FL_ECO, tmp );
aCfg->Read( keyShowBoardBody, &tmp, true );
prms.SetFlag( FL_SHOW_BOARD_BODY, tmp );
}
void EDA_3D_FRAME::SaveSettings( wxConfigBase* aCfg )
{
EDA_BASE_FRAME::SaveSettings( aCfg );
INFO3D_VISU& prms = GetPrm3DVisu();
aCfg->Write( keyBgColor_Red, GetPrm3DVisu().m_BgColor.m_Red );
aCfg->Write( keyBgColor_Green, GetPrm3DVisu().m_BgColor.m_Green );
aCfg->Write( keyBgColor_Blue, GetPrm3DVisu().m_BgColor.m_Blue );
aCfg->Write( keyBgColor_Red_Top, GetPrm3DVisu().m_BgColor_Top.m_Red );
aCfg->Write( keyBgColor_Green_Top, GetPrm3DVisu().m_BgColor_Top.m_Green );
aCfg->Write( keyBgColor_Blue_Top, GetPrm3DVisu().m_BgColor_Top.m_Blue );
aCfg->Write( keySMaskColor_Red, GetPrm3DVisu().m_SolderMaskColor.m_Red );
aCfg->Write( keySMaskColor_Green, GetPrm3DVisu().m_SolderMaskColor.m_Green );
aCfg->Write( keySMaskColor_Blue, GetPrm3DVisu().m_SolderMaskColor.m_Blue );
aCfg->Write( keySPasteColor_Red, GetPrm3DVisu().m_SolderPasteColor.m_Red );
aCfg->Write( keySPasteColor_Green, GetPrm3DVisu().m_SolderPasteColor.m_Green );
aCfg->Write( keySPasteColor_Blue, GetPrm3DVisu().m_SolderPasteColor.m_Blue );
aCfg->Write( keySilkColor_Red, GetPrm3DVisu().m_SilkScreenColor.m_Red );
aCfg->Write( keySilkColor_Green, GetPrm3DVisu().m_SilkScreenColor.m_Green );
aCfg->Write( keySilkColor_Blue, GetPrm3DVisu().m_SilkScreenColor.m_Blue );
aCfg->Write( keyCopperColor_Red, GetPrm3DVisu().m_CopperColor.m_Red );
aCfg->Write( keyCopperColor_Green, GetPrm3DVisu().m_CopperColor.m_Green );
aCfg->Write( keyCopperColor_Blue, GetPrm3DVisu().m_CopperColor.m_Blue );
aCfg->Write( keyBoardBodyColor_Red, GetPrm3DVisu().m_BoardBodyColor.m_Red );
aCfg->Write( keyBoardBodyColor_Green, GetPrm3DVisu().m_BoardBodyColor.m_Green );
aCfg->Write( keyBoardBodyColor_Blue, GetPrm3DVisu().m_BoardBodyColor.m_Blue );
aCfg->Write( keyMousewheelPanning, prms.GetFlag( FL_MOUSEWHEEL_PANNING ) );
aCfg->Write( keyShowRealisticMode, prms.GetFlag( FL_USE_REALISTIC_MODE ) );
aCfg->Write( keyRenderShadows, prms.GetFlag( FL_RENDER_SHADOWS ) );
aCfg->Write( keyRenderRemoveHoles, prms.GetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES ) );
aCfg->Write( keyRenderTextures, prms.GetFlag( FL_RENDER_TEXTURES ) );
aCfg->Write( keyRenderSmoothNormals, prms.GetFlag( FL_RENDER_SMOOTH_NORMALS ) );
aCfg->Write( keyRenderUseModelNormals, prms.GetFlag( FL_RENDER_USE_MODEL_NORMALS ) );
aCfg->Write( keyRenderMaterial, prms.GetFlag( FL_RENDER_MATERIAL ) );
aCfg->Write( keyRenderShowModelBBox, prms.GetFlag( FL_RENDER_SHOW_MODEL_BBOX ) );
aCfg->Write( keyShowAxis, prms.GetFlag( FL_AXIS ) );
aCfg->Write( keyShowGrid, prms.GetFlag( FL_GRID ) );
aCfg->Write( keyShowGridSize, prms.m_3D_Grid );
aCfg->Write( keyShowFootprints, prms.GetFlag( FL_MODULE ) );
aCfg->Write( keyShowCopperThickness, prms.GetFlag( FL_USE_COPPER_THICKNESS ) );
aCfg->Write( keyShowZones, prms.GetFlag( FL_ZONE ) );
aCfg->Write( keyShowAdhesiveLayers, prms.GetFlag( FL_ADHESIVE ) );
aCfg->Write( keyShowSilkScreenLayers, prms.GetFlag( FL_SILKSCREEN ) );
aCfg->Write( keyShowSolderMaskLayers, prms.GetFlag( FL_SOLDERMASK ) );
aCfg->Write( keyShowSolderPasteLayers, prms.GetFlag( FL_SOLDERPASTE ) );
aCfg->Write( keyShowCommentsLayer, prms.GetFlag( FL_COMMENTS ) );
aCfg->Write( keyShowEcoLayers, prms.GetFlag( FL_ECO ) );
aCfg->Write( keyShowBoardBody, prms.GetFlag( FL_SHOW_BOARD_BODY ) );
}
void EDA_3D_FRAME::Process_Zoom( wxCommandEvent& event )
{
int ii;
switch( event.GetId() )
{
case ID_ZOOM_PAGE:
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
GetPrm3DVisu().m_Zoom = 1.0;
m_canvas->SetOffset( 0.0, 0.0 );
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
break;
case ID_ZOOM_IN:
GetPrm3DVisu().m_Zoom /= 1.2;
if( GetPrm3DVisu().m_Zoom <= 0.01 )
GetPrm3DVisu().m_Zoom = 0.01;
break;
case ID_ZOOM_OUT:
GetPrm3DVisu().m_Zoom *= 1.2;
break;
case ID_ZOOM_REDRAW:
break;
default:
return;
}
m_canvas->Refresh( false );
m_canvas->DisplayStatus();
}
void EDA_3D_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos )
{
}
void EDA_3D_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu )
{
}
double EDA_3D_FRAME::BestZoom()
{
return 1.0;
}
void EDA_3D_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg )
{
}
void EDA_3D_FRAME::Process_Special_Functions( wxCommandEvent& event )
{
#define ROT_ANGLE 10.0
int id = event.GetId();
bool isChecked = event.IsChecked();
switch( id )
{
case ID_TOOL_SET_VISIBLE_ITEMS:
Install_3D_ViewOptionDialog( event );
break;
case ID_RELOAD3D_BOARD:
m_reloadRequest = true;
NewDisplay();
return;
break;
case ID_ROTATE3D_X_POS:
GetPrm3DVisu().m_ROTX += ROT_ANGLE;
break;
case ID_ROTATE3D_X_NEG:
GetPrm3DVisu().m_ROTX -= ROT_ANGLE;
break;
case ID_ROTATE3D_Y_POS:
GetPrm3DVisu().m_ROTY += ROT_ANGLE;
break;
case ID_ROTATE3D_Y_NEG:
GetPrm3DVisu().m_ROTY -= ROT_ANGLE;
break;
case ID_ROTATE3D_Z_POS:
GetPrm3DVisu().m_ROTZ += ROT_ANGLE;
break;
case ID_ROTATE3D_Z_NEG:
GetPrm3DVisu().m_ROTZ -= ROT_ANGLE;
break;
case ID_MOVE3D_LEFT:
m_canvas->SetView3D( WXK_LEFT );
return;
case ID_MOVE3D_RIGHT:
m_canvas->SetView3D( WXK_RIGHT );
return;
case ID_MOVE3D_UP:
m_canvas->SetView3D( WXK_UP );
return;
case ID_MOVE3D_DOWN:
m_canvas->SetView3D( WXK_DOWN );
return;
case ID_ORTHO:
ToggleOrtho();
return;
case ID_TOOL_SCREENCOPY_TOCLIBBOARD:
case ID_MENU_SCREENCOPY_PNG:
case ID_MENU_SCREENCOPY_JPEG:
m_canvas->TakeScreenshot( event );
break;
case ID_MENU3D_BGCOLOR_BOTTOM_SELECTION:
if( Set3DColorFromUser( GetPrm3DVisu().m_BgColor, _( "Background Color, Bottom" ) ) )
m_canvas->Refresh( true );
return;
case ID_MENU3D_BGCOLOR_TOP_SELECTION:
if( Set3DColorFromUser( GetPrm3DVisu().m_BgColor_Top, _( "Background Color, Top" ) ) )
m_canvas->Refresh( true );
return;
case ID_MENU3D_SILKSCREEN_COLOR_SELECTION:
Set3DSilkScreenColorFromUser();
return;
case ID_MENU3D_SOLDERMASK_COLOR_SELECTION:
Set3DSolderMaskColorFromUser();
return;
case ID_MENU3D_SOLDERPASTE_COLOR_SELECTION:
Set3DSolderPasteColorFromUser();
return;
case ID_MENU3D_COPPER_COLOR_SELECTION:
Set3DCopperColorFromUser();
break;
case ID_MENU3D_PCB_BODY_COLOR_SELECTION:
Set3DBoardBodyColorFromUser();
break;
case ID_MENU3D_MOUSEWHEEL_PANNING:
GetPrm3DVisu().SetFlag( FL_MOUSEWHEEL_PANNING, isChecked );
return;
case ID_MENU3D_REALISTIC_MODE:
GetPrm3DVisu().SetFlag( FL_USE_REALISTIC_MODE, isChecked );
GetMenuBar()->FindItem( ID_MENU3D_COMMENTS_ONOFF )->Enable( !isChecked );
GetMenuBar()->FindItem( ID_MENU3D_ECO_ONOFF )->Enable( !isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_SHADOWS:
GetPrm3DVisu().SetFlag( FL_RENDER_SHADOWS, isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_SHOW_HOLES_IN_ZONES:
GetPrm3DVisu().SetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES, isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_TEXTURES:
GetPrm3DVisu().SetFlag( FL_RENDER_TEXTURES, isChecked );
NewDisplay(GL_ID_BOARD);
NewDisplay(GL_ID_TECH_LAYERS);
return;
case ID_MENU3D_FL_RENDER_SMOOTH_NORMALS:
GetPrm3DVisu().SetFlag( FL_RENDER_SMOOTH_NORMALS, isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_USE_MODEL_NORMALS:
GetPrm3DVisu().SetFlag( FL_RENDER_USE_MODEL_NORMALS, isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_MATERIAL:
GetPrm3DVisu().SetFlag( FL_RENDER_MATERIAL, isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_SHOW_MODEL_BBOX:
GetPrm3DVisu().SetFlag( FL_RENDER_SHOW_MODEL_BBOX, isChecked );
NewDisplay();
return;
case ID_MENU3D_SHOW_BOARD_BODY:
GetPrm3DVisu().SetFlag( FL_SHOW_BOARD_BODY, isChecked );
NewDisplay();
return;
case ID_MENU3D_AXIS_ONOFF:
GetPrm3DVisu().SetFlag( FL_AXIS, isChecked );
m_canvas->Refresh();
return;
case ID_MENU3D_MODULE_ONOFF:
GetPrm3DVisu().SetFlag( FL_MODULE, isChecked );
m_canvas->Refresh();
return;
case ID_MENU3D_USE_COPPER_THICKNESS:
GetPrm3DVisu().SetFlag( FL_USE_COPPER_THICKNESS, isChecked );
NewDisplay( GL_ID_BOARD );
NewDisplay( GL_ID_TECH_LAYERS );
return;
case ID_MENU3D_ZONE_ONOFF:
GetPrm3DVisu().SetFlag( FL_ZONE, isChecked );
NewDisplay( GL_ID_BOARD );
return;
case ID_MENU3D_ADHESIVE_ONOFF:
GetPrm3DVisu().SetFlag( FL_ADHESIVE, isChecked );
NewDisplay( GL_ID_TECH_LAYERS );
return;
case ID_MENU3D_SILKSCREEN_ONOFF:
GetPrm3DVisu().SetFlag( FL_SILKSCREEN, isChecked );
NewDisplay( GL_ID_TECH_LAYERS );
return;
case ID_MENU3D_SOLDER_MASK_ONOFF:
GetPrm3DVisu().SetFlag( FL_SOLDERMASK, isChecked );
NewDisplay( GL_ID_TECH_LAYERS );
return;
case ID_MENU3D_SOLDER_PASTE_ONOFF:
GetPrm3DVisu().SetFlag( FL_SOLDERPASTE, isChecked );
NewDisplay( GL_ID_TECH_LAYERS );
return;
case ID_MENU3D_COMMENTS_ONOFF:
GetPrm3DVisu().SetFlag( FL_COMMENTS, isChecked );
NewDisplay( GL_ID_AUX_LAYERS );
return;
case ID_MENU3D_ECO_ONOFF:
GetPrm3DVisu().SetFlag( FL_ECO, isChecked );
NewDisplay( GL_ID_AUX_LAYERS );
return;
default:
wxLogMessage( wxT( "EDA_3D_FRAME::Process_Special_Functions() error: unknown command" ) );
return;
}
m_canvas->Refresh( true );
m_canvas->DisplayStatus();
}
void EDA_3D_FRAME::On3DGridSelection( wxCommandEvent& event )
{
int id = event.GetId();
for( int ii = ID_MENU3D_GRID_NOGRID; ii < ID_MENU3D_GRID_END; ii++ )
{
if( event.GetId() == ii )
continue;
GetMenuBar()->Check( ii, false );
}
switch( id )
{
case ID_MENU3D_GRID_NOGRID:
GetPrm3DVisu().SetFlag( FL_GRID, false );
break;
case ID_MENU3D_GRID_10_MM:
GetPrm3DVisu().SetFlag( FL_GRID, true );
GetPrm3DVisu().m_3D_Grid = 10.0;
break;
case ID_MENU3D_GRID_5_MM:
GetPrm3DVisu().SetFlag( FL_GRID, true );
GetPrm3DVisu().m_3D_Grid = 5.0;
break;
case ID_MENU3D_GRID_2P5_MM:
GetPrm3DVisu().SetFlag( FL_GRID, true );
GetPrm3DVisu().m_3D_Grid = 2.5;
break;
case ID_MENU3D_GRID_1_MM:
GetPrm3DVisu().SetFlag( FL_GRID, true );
GetPrm3DVisu().m_3D_Grid = 1.0;
break;
default:
wxLogMessage( wxT( "EDA_3D_FRAME::On3DGridSelection() error: unknown command" ) );
return;
}
NewDisplay( GL_ID_GRID );
}
void EDA_3D_FRAME::NewDisplay( int aGlList )
{
m_canvas->ClearLists( aGlList );
// Rebuild the 3D board and refresh the view on reload request:
if( m_reloadRequest )
m_canvas->ReportWarnings( true );
m_canvas->Refresh( true );
m_canvas->DisplayStatus();
m_reloadRequest = false;
}
void EDA_3D_FRAME::OnActivate( wxActivateEvent& event )
{
// Reload data if 3D frame shows a board,
// because it can be changed since last frame activation
if( m_reloadRequest )
NewDisplay();
event.Skip(); // required under wxMAC
}
bool EDA_3D_FRAME::Set3DColorFromUser( S3D_COLOR &aColor, const wxString& aTitle,
wxColourData* aPredefinedColors )
{
wxColour newcolor, oldcolor;
oldcolor.Set( KiROUND( aColor.m_Red * 255 ),
KiROUND( aColor.m_Green * 255 ),
KiROUND( aColor.m_Blue * 255 ) );
wxColourData emptyColorSet; // Provides a empty predefined set of colors
// if no color set available to avoid use of an
// old color set
if( aPredefinedColors == NULL )
aPredefinedColors = &emptyColorSet;
newcolor = wxGetColourFromUser( this, oldcolor, aTitle, aPredefinedColors );
if( !newcolor.IsOk() ) // Cancel command
return false;
if( newcolor != oldcolor )
{
aColor.m_Red = (double) newcolor.Red() / 255.0;
aColor.m_Green = (double) newcolor.Green() / 255.0;
aColor.m_Blue = (double) newcolor.Blue() / 255.0;
}
return true;
}
bool EDA_3D_FRAME::Set3DSilkScreenColorFromUser()
{
wxColourData definedColors;
definedColors.SetCustomColour(0, wxColour( 241, 241, 241 ) ); // White
definedColors.SetCustomColour(1, wxColour( 180, 180, 180 ) ); // Gray
bool change = Set3DColorFromUser( GetPrm3DVisu().m_SilkScreenColor,
_( "Silk Screen Color" ),
&definedColors );
if( change )
NewDisplay( GL_ID_TECH_LAYERS );
return change;
}
bool EDA_3D_FRAME::Set3DSolderMaskColorFromUser()
{
wxColourData definedColors;
definedColors.SetCustomColour(0, wxColour( 20, 51, 36 ) ); // Green
definedColors.SetCustomColour(1, wxColour( 43, 10, 65 ) ); // Purple
definedColors.SetCustomColour(2, wxColour( 117, 19, 21 ) ); // Red
definedColors.SetCustomColour(3, wxColour( 54, 79, 116) ); // Light blue
definedColors.SetCustomColour(4, wxColour( 11, 11, 11 ) ); // Black
definedColors.SetCustomColour(5, wxColour( 241, 241,241) ); // White
bool change = Set3DColorFromUser( GetPrm3DVisu().m_SolderMaskColor,
_( "Solder Mask Color" ),
&definedColors );
if( change )
NewDisplay( GL_ID_TECH_LAYERS );
return change;
}
bool EDA_3D_FRAME::Set3DCopperColorFromUser()
{
wxColourData definedColors;
definedColors.SetCustomColour( 0, wxColour( 184, 115, 50 ) ); // Copper
definedColors.SetCustomColour( 1, wxColour( 233, 221, 82 ) ); // Gold
definedColors.SetCustomColour( 2, wxColour( 213, 213, 213) ); // Silver
definedColors.SetCustomColour( 3, wxColour( 160, 160, 160) ); // tin
bool change = Set3DColorFromUser( GetPrm3DVisu().m_CopperColor,
_( "Copper Color" ),
&definedColors );
if( change )
NewDisplay( GL_ID_BOARD );
return change;
}
bool EDA_3D_FRAME::Set3DBoardBodyColorFromUser()
{
wxColourData definedColors;
definedColors.SetCustomColour( 0, wxColour( 51, 43, 22 ) ); // FR4 natural, dark
definedColors.SetCustomColour( 1, wxColour( 109, 116, 75 ) ); // FR4 natural
definedColors.SetCustomColour( 2, wxColour( 78, 14, 5 ) ); // brown/red
definedColors.SetCustomColour( 3, wxColour( 146, 99, 47 ) ); // brown 1
definedColors.SetCustomColour( 4, wxColour( 160, 123, 54 ) ); // brown 2
definedColors.SetCustomColour( 5, wxColour( 146, 99, 47 ) ); // brown 3
definedColors.SetCustomColour( 6, wxColour( 63, 126, 71 ) ); // green 1
definedColors.SetCustomColour( 7, wxColour( 117, 122, 90 ) ); // green 2
bool change = Set3DColorFromUser( GetPrm3DVisu().m_BoardBodyColor,
_( "Board Body Color" ),
&definedColors );
if( change )
NewDisplay( GL_ID_BOARD );
return change;
}
bool EDA_3D_FRAME::Set3DSolderPasteColorFromUser()
{
wxColourData definedColors;
definedColors.SetCustomColour(0, wxColour( 128, 128, 128 ) ); // grey
definedColors.SetCustomColour(1, wxColour( 213, 213, 213 ) ); // Silver
definedColors.SetCustomColour(2, wxColour( 90, 90, 90 ) ); // grey 2
bool change = Set3DColorFromUser( GetPrm3DVisu().m_SolderPasteColor,
_( "Solder Paste Color" ),
&definedColors );
if( change )
NewDisplay( GL_ID_TECH_LAYERS );
return change;
}
BOARD* EDA_3D_FRAME::GetBoard()
{
return Parent()->GetBoard();
}
INFO3D_VISU& EDA_3D_FRAME::GetPrm3DVisu() const
{
// return the INFO3D_VISU which contains the current parameters
// to draw the 3D view of the board
return g_Parm_3D_Visu;
}
bool EDA_3D_FRAME::IsEnabled( DISPLAY3D_FLG aItem ) const
{
// return true if aItem must be displayed
return GetPrm3DVisu().GetFlag( aItem );
}
+156
View File
@@ -0,0 +1,156 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2012 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
*/
/**
* @file 3d_class.cpp
*/
#include <fctsys.h>
#include <3d_struct.h>
#include <3d_material.h>
#include <info3d_visu.h>
#ifdef __WXMAC__
# ifdef __DARWIN__
# include <OpenGL/glu.h>
# else
# include <glu.h>
# endif
#else
# include <GL/glu.h>
#endif
S3D_MATERIAL::S3D_MATERIAL( S3D_MASTER* father, const wxString& name ) :
EDA_ITEM( father, NOT_USED )
{
m_Name = name;
m_AmbientColor.clear();
m_DiffuseColor.clear();
m_EmissiveColor.clear();
m_SpecularColor.clear();
m_Shininess.clear();
m_Transparency.clear();
m_ColorPerVertex = false;
}
void SetOpenGlDefaultMaterial()
{
glm::vec4 ambient( 0.2f, 0.2f, 0.2f, 1.0f );
glm::vec4 specular( 0.0f, 0.0f, 0.0f, 1.0f );
glm::vec4 emissive( 0.0f, 0.0f, 0.0f, 1.0f );
glm::vec4 diffuse( 0.0f, 0.0f, 0.0f, 1.0f );
GLint shininess_value = 0;
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
glMateriali ( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value );
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.x );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.x );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.x );
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.x );
}
bool S3D_MATERIAL::SetOpenGLMaterial( unsigned int aMaterialIndex, bool aUseMaterial )
{
if( aUseMaterial )
{
float transparency_value = 0.0f;
if( m_Transparency.size() > aMaterialIndex )
{
transparency_value = m_Transparency[aMaterialIndex];
}
else
{
if( m_Transparency.size() > 0 )
transparency_value = m_Transparency[0];
}
if( m_DiffuseColor.size() > aMaterialIndex )
{
glm::vec3 color = m_DiffuseColor[aMaterialIndex];
glColor4f( color.x, color.y, color.z, 1.0f - transparency_value );
}
else
{
if( m_DiffuseColor.size() == 0 )
{
glColor4f( 0.8f, 0.8f, 0.8f, 1.0f );
}
}
if( m_Shininess.size() > 0 )
{
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, m_Shininess[0] );
}
// emissive
if( m_EmissiveColor.size() > aMaterialIndex )
{
glm::vec4 emissive;
emissive[0] = m_EmissiveColor[aMaterialIndex].x;
emissive[1] = m_EmissiveColor[aMaterialIndex].y;
emissive[2] = m_EmissiveColor[aMaterialIndex].z;
emissive[3] = 1.0f;
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.x );
}
// specular
if( m_SpecularColor.size() > aMaterialIndex )
{
glm::vec4 specular;
specular[0] = m_SpecularColor[aMaterialIndex].x;
specular[1] = m_SpecularColor[aMaterialIndex].y;
specular[2] = m_SpecularColor[aMaterialIndex].z;
specular[3] = 1.0f;
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.x );
}
// ambient
if( m_AmbientColor.size() > aMaterialIndex )
{
glm::vec4 ambient;
ambient[0] = m_AmbientColor[aMaterialIndex].x;
ambient[1] = m_AmbientColor[aMaterialIndex].y;
ambient[2] = m_AmbientColor[aMaterialIndex].z;
ambient[3] = 1.0f;
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.x );
}
return (transparency_value != 0.0f);
}
else
{
if( m_DiffuseColor.size() > aMaterialIndex )
{
glm::vec3 color = m_DiffuseColor[aMaterialIndex];
glColor4f( color.x, color.y, color.z, 1.0 );
}
}
return false;
}
+83
View File
@@ -0,0 +1,83 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2014 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
*/
/**
* @file 3d_material.h
*/
#ifndef STRUCT_3D_MATERIAL_H
#define STRUCT_3D_MATERIAL_H
#include <common.h>
#include <base_struct.h>
#define GLM_FORCE_RADIANS
#include <gal/opengl/glm/glm.hpp>
class S3D_MASTER;
class S3D_MATERIAL : public EDA_ITEM // openGL "material" data
{
public:
wxString m_Name;
// Material list
std::vector< glm::vec3 > m_AmbientColor;
std::vector< glm::vec3 > m_DiffuseColor;
std::vector< glm::vec3 > m_EmissiveColor;
std::vector< glm::vec3 > m_SpecularColor;
std::vector< float > m_Shininess;
std::vector< float > m_Transparency;
bool m_ColorPerVertex;
public:
S3D_MATERIAL( S3D_MASTER* father, const wxString& name );
S3D_MATERIAL* Next() const { return (S3D_MATERIAL*) Pnext; }
S3D_MATERIAL* Back() const { return (S3D_MATERIAL*) Pback; }
/**
* Initialize the material prms.
* @param aMaterialIndex = the index in list of available materials
* @param aUseMaterial = true to use the values found in the available material
* = false to use only the color, and other prms are fixed
* @return true if the material is transparency
*/
bool SetOpenGLMaterial(unsigned int aMaterialIndex, bool aUseMaterial);
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override
#endif
/** Get class name
* @return string "S3D_MATERIAL"
*/
virtual wxString GetClass() const
{
return wxT( "S3D_MATERIAL" );
}
};
void SetOpenGlDefaultMaterial();
#endif
-31
View File
@@ -1,31 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright The 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
*/
/**
* @file 3d_math.cpp
* @brief
*/
#include "3d_math.h"
-184
View File
@@ -1,184 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright The 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
*/
/**
* @file 3d_math.h
* @brief Defines math related functions
*/
#ifndef _3D_MATH_H
#define _3D_MATH_H
#include <plugins/3dapi/xv3d_types.h>
#include "3d_fastmath.h"
/**
* https://en.wikipedia.org/wiki/Spherical_coordinate_system
*
* @param aInclination θ ∈ [0, π]
* @param aAzimuth φ ∈ [0, 2π]
* @return Cartesian coordinates
*/
inline SFVEC3F SphericalToCartesian( float aInclination, float aAzimuth )
{
float sinInc = glm::sin( aInclination );
return SFVEC3F( sinInc * glm::cos( aAzimuth ), sinInc * glm::sin( aAzimuth ),
glm::cos( aInclination ) );
}
/**
* @todo This is not correct because it is not a gaussian random.
*/
inline SFVEC3F UniformRandomHemisphereDirection()
{
// It was experienced that this function is slow! do not use it :/
// SFVEC3F b( (rand()/(float)RAND_MAX) - 0.5f,
// (rand()/(float)RAND_MAX) - 0.5f,
// (rand()/(float)RAND_MAX) - 0.5f );
SFVEC3F b( Fast_RandFloat() * 0.5f, Fast_RandFloat() * 0.5f, Fast_RandFloat() * 0.5f );
return b;
}
// https://pathtracing.wordpress.com/2011/03/03/cosine-weighted-hemisphere/
inline SFVEC3F CosWeightedRandomHemisphereDirection( const SFVEC3F& n )
{
const float Xi1 = (float) rand() / (float) RAND_MAX;
const float Xi2 = (float) rand() / (float) RAND_MAX;
const float theta = acos( sqrt( 1.0f - Xi1 ) );
const float phi = 2.0f * glm::pi<float>() * Xi2;
const float xs = sinf( theta ) * cosf( phi );
const float ys = cosf( theta );
const float zs = sinf( theta ) * sinf( phi );
const SFVEC3F y( n.x, n.y, n.z );
SFVEC3F h = y;
if( fabs( h.x ) <= fabs( h.y ) && fabs( h.x ) <= fabs( h.z ) )
h.x= 1.0f;
else if( fabs( h.y ) <= fabs( h.x ) && fabs( h.y ) <= fabs( h.z ) )
h.y= 1.0f;
else
h.z= 1.0f;
const SFVEC3F x = glm::normalize( glm::cross( h, y ) );
const SFVEC3F z = glm::normalize( glm::cross( x, y ) );
SFVEC3F direction = xs * x + ys * y + zs * z;
return glm::normalize( direction );
}
/**
* Based on:
* https://github.com/mmp/pbrt-v3/blob/master/src/core/reflection.h
* See also:
* http://www.flipcode.com/archives/Raytracing_Topics_Techniques-Part_3_Refractions_and_Beers_Law.shtml
*
* @param aInVector incoming vector.
* @param aNormal normal in the intersection point.
* @param aRin_over_Rout incoming refraction index / out refraction index.
* @param aOutVector the refracted vector.
* @return true
*/
inline bool Refract( const SFVEC3F &aInVector, const SFVEC3F &aNormal, float aRin_over_Rout,
SFVEC3F& aOutVector )
{
float cosThetaI = -glm::dot( aNormal, aInVector );
float sin2ThetaI = glm::max( 0.0f, 1.0f - cosThetaI * cosThetaI );
float sin2ThetaT = aRin_over_Rout * aRin_over_Rout * sin2ThetaI;
// Handle total internal reflection for transmission
if( sin2ThetaT >= 1.0f )
return false;
float cosThetaT = sqrtf( 1.0f - sin2ThetaT );
aOutVector = glm::normalize( aRin_over_Rout * aInVector +
( aRin_over_Rout * cosThetaI - cosThetaT ) *
aNormal );
return true;
}
inline float mapf( float x, float in_min, float in_max, float out_min, float out_max )
{
x = glm::clamp( x, in_min, in_max );
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
inline float RGBtoGray( const SFVEC3F &aColor )
{
return (aColor.r * 0.2126f +
aColor.g * 0.7152f +
aColor.b * 0.0722f);
}
inline SFVEC3F MaterialDiffuseToColorCAD( const SFVEC3F &aDiffuseColor )
{
// convert to a discret scale of grays
const float luminance = glm::min(
( ( (float) ( (unsigned int) ( 4.0f * RGBtoGray( aDiffuseColor ) ) ) + 0.5f ) / 4.0f )
* 1.0f,
1.0f );
const float maxValue = glm::max( glm::max( glm::max( aDiffuseColor.r, aDiffuseColor.g ),
aDiffuseColor.b ), FLT_EPSILON );
return ( aDiffuseColor / SFVEC3F( maxValue ) ) * 0.125f + luminance * 0.875f;
}
// http://fooplot.com/#W3sidHlwZSI6MCwiZXEiOiJ4KngqMiIsImNvbG9yIjoiIzAwMDAwMCJ9LHsidHlwZSI6MCwiZXEiOiItKCh4LTEpXjIpKjIrMSIsImNvbG9yIjoiIzAwMDAwMCJ9LHsidHlwZSI6MTAwMCwid2luZG93IjpbIi0xLjM4NzUwMDAwMDAwMDAwMDIiLCIxLjg2MjQ5OTk5OTk5OTk5OTgiLCItMC43IiwiMS4zIl19XQ--
inline float QuadricEasingInOut( float t )
{
if( t <= 0.5f )
{
return t * t * 2.0f;
}
else
{
t = t - 1.0f;
return -2.0f * ( t * t ) + 1.0f;
}
}
// http://www.wolframalpha.com/input/?i=t%5E2(3-2t)
inline float BezierBlend( float t )
{
return t * t * ( 3.0f - 2.0f * t );
}
#endif // 3D_MATH_H
File diff suppressed because it is too large Load Diff
+107
View File
@@ -0,0 +1,107 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2014 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
*/
/**
* @file 3d_mesh_model.h
* @brief
*/
#ifndef __3D_MESH_MODEL_H__
#define __3D_MESH_MODEL_H__
#include <memory>
#include <boost/shared_ptr.hpp>
#include <vector>
#define GLM_FORCE_RADIANS
#include <gal/opengl/glm/glm.hpp>
#include "3d_struct.h"
#include "3d_material.h"
#include "CBBox.h"
class S3D_MESH;
/** A smart pointer to an S3D_MESH object */
typedef boost::shared_ptr<S3D_MESH> S3D_MESH_PTR;
/** A container of smar S3D_MESH object pointers */
typedef std::vector<S3D_MESH_PTR> S3D_MESH_PTRS;
class S3D_MESH
{
public:
S3D_MESH();
~S3D_MESH();
void openGL_RenderAllChilds( bool aIsRenderingJustNonTransparentObjects,
bool aIsRenderingJustTransparentObjects );
S3D_MATERIAL *m_Materials;
// Point and index list
std::vector< S3D_VERTEX > m_Point;
std::vector< std::vector<int> > m_CoordIndex;
std::vector< std::vector<int> > m_NormalIndex;
std::vector< S3D_VERTEX > m_PerFaceColor;
std::vector< S3D_VERTEX > m_PerFaceNormalsNormalized;
std::vector< S3D_VERTEX > m_PerVertexNormalsNormalized;
std::vector< int > m_MaterialIndexPerFace;
std::vector< std::vector<int> > m_MaterialIndexPerVertex;
S3D_MESH_PTRS childs;
S3D_VERTEX m_translation;
glm::vec4 m_rotation;
S3D_VERTEX m_scale;
CBBOX &getBBox();
private:
std::vector< S3D_VERTEX > m_PerFaceNormalsRaw_X_PerFaceSquaredArea;
std::vector< std::vector< S3D_VERTEX > > m_PerFaceVertexNormals;
std::vector< S3D_VERTEX > m_PointNormalized;
std::vector< std::vector<int> > m_InvalidCoordIndexes; //!TODO: check for invalid CoordIndex in file and remove the index and the same material index
bool isPerFaceNormalsComputed;
void calcPerFaceNormals ();
bool isPointNormalizedComputed;
void calcPointNormalized();
bool isPerPointNormalsComputed;
void calcPerPointNormals();
bool isPerVertexNormalsVerified;
void perVertexNormalsVerify_and_Repair();
void calcBBox();
void calcBBoxAllChilds();
CBBOX m_BBox;
void openGL_Render( bool aIsRenderingJustNonTransparentObjects,
bool aIsRenderingJustTransparentObjects );
};
#endif
@@ -1,483 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright The 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
*/
/**
* @brief Implements a model viewer canvas. The purpose of the model viewer is to render
* 3d models that come in the original data from the files without any transformations.
*/
#include <gal/opengl/kiglew.h> // Must be included first
#include <iostream>
#include "3d_rendering/opengl/3d_model.h"
#include "eda_3d_model_viewer.h"
#include "../3d_rendering/opengl/opengl_utils.h"
#include "../3d_cache/3d_cache.h"
#include <wx/dcclient.h>
#include <base_units.h>
#include <build_version.h>
#include <gal/opengl/gl_context_mgr.h>
#include <settings/common_settings.h>
#include <pgm_base.h>
#include <dpi_scaling_common.h>
#include <class_draw_panel_gal.h>
#include <macros.h>
/**
* Scale conversion from 3d model units to pcb units
*/
#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_EDA_3D_MODEL_VIEWER". See the wxWidgets documentation on wxLogTrace for
* more information.
*
* @ingroup trace_env_vars
*/
const wxChar* EDA_3D_MODEL_VIEWER::m_logTrace = wxT( "KI_TRACE_EDA_3D_MODEL_VIEWER" );
BEGIN_EVENT_TABLE( EDA_3D_MODEL_VIEWER, wxGLCanvas )
EVT_PAINT( EDA_3D_MODEL_VIEWER::OnPaint )
// mouse events
EVT_LEFT_DOWN( EDA_3D_MODEL_VIEWER::OnLeftDown )
EVT_LEFT_UP( EDA_3D_MODEL_VIEWER::OnLeftUp )
EVT_MIDDLE_UP( EDA_3D_MODEL_VIEWER::OnMiddleUp )
EVT_MIDDLE_DOWN( EDA_3D_MODEL_VIEWER::OnMiddleDown)
EVT_RIGHT_DOWN( EDA_3D_MODEL_VIEWER::OnRightClick )
EVT_MOUSEWHEEL( EDA_3D_MODEL_VIEWER::OnMouseWheel )
EVT_MOTION( EDA_3D_MODEL_VIEWER::OnMouseMove )
#ifdef USE_OSX_MAGNIFY_EVENT
EVT_MAGNIFY( EDA_3D_MODEL_VIEWER::OnMagnify )
#endif
// other events
EVT_ERASE_BACKGROUND( EDA_3D_MODEL_VIEWER::OnEraseBackground )
END_EVENT_TABLE()
// This defines the range that all coord will have to be rendered.
// It will use this value to convert to a normalized value between
// -(RANGE_SCALE_3D/2) .. +(RANGE_SCALE_3D/2)
#define RANGE_SCALE_3D 8.0f
EDA_3D_MODEL_VIEWER::EDA_3D_MODEL_VIEWER( wxWindow* aParent, const wxGLAttributes& aGLAttribs,
S3D_CACHE* aCacheManager ) :
HIDPI_GL_CANVAS( EDA_DRAW_PANEL_GAL::GetVcSettings(), aParent, aGLAttribs, wxID_ANY,
wxDefaultPosition, wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE ),
m_trackBallCamera( RANGE_SCALE_3D * 4.0f ),
m_cacheManager( aCacheManager )
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::EDA_3D_MODEL_VIEWER" ) );
m_ogl_initialized = false;
m_reload_is_needed = false;
m_ogl_3dmodel = nullptr;
m_3d_model = nullptr;
m_BiuTo3dUnits = 1.0;
m_glRC = nullptr;
}
EDA_3D_MODEL_VIEWER::~EDA_3D_MODEL_VIEWER()
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::~EDA_3D_MODEL_VIEWER" ) );
GL_CONTEXT_MANAGER* gl_mgr = Pgm().GetGLContextManager();
if( m_glRC )
{
gl_mgr->LockCtx( m_glRC, this );
delete m_ogl_3dmodel;
m_ogl_3dmodel = nullptr;
gl_mgr->UnlockCtx( m_glRC );
gl_mgr->DestroyCtx( m_glRC );
}
}
void EDA_3D_MODEL_VIEWER::Set3DModel( const S3DMODEL& a3DModel )
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::Set3DModel with a S3DMODEL" ) );
// Validate a3DModel pointers
wxASSERT( a3DModel.m_Materials != nullptr );
wxASSERT( a3DModel.m_Meshes != nullptr );
wxASSERT( a3DModel.m_MaterialsSize > 0 );
wxASSERT( a3DModel.m_MeshesSize > 0 );
// Delete the old model
delete m_ogl_3dmodel;
m_ogl_3dmodel = nullptr;
m_3d_model = nullptr;
if( ( a3DModel.m_Materials != nullptr ) && ( a3DModel.m_Meshes != nullptr )
&& ( a3DModel.m_MaterialsSize > 0 ) && ( a3DModel.m_MeshesSize > 0 ) )
{
m_3d_model = &a3DModel;
m_reload_is_needed = true;
}
Refresh();
}
void EDA_3D_MODEL_VIEWER::Set3DModel( const wxString& aModelPathName)
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::Set3DModel with a wxString" ) );
if( m_cacheManager )
{
const S3DMODEL* model = m_cacheManager->GetModel( aModelPathName, wxEmptyString, nullptr );
if( model )
Set3DModel( (const S3DMODEL &)*model );
else
Clear3DModel();
}
}
void EDA_3D_MODEL_VIEWER::Clear3DModel()
{
// Delete the old model
m_reload_is_needed = false;
delete m_ogl_3dmodel;
m_ogl_3dmodel = nullptr;
m_3d_model = nullptr;
Refresh();
}
void EDA_3D_MODEL_VIEWER::ogl_initialize()
{
const GLenum err = glewInit();
if( GLEW_OK != err )
{
const wxString msgError = (const char*) glewGetErrorString( err );
wxLogMessage( msgError );
}
else
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::ogl_initialize Using GLEW version %s" ),
From_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
}
SetOpenGLInfo( (const char*) glGetString( GL_VENDOR ), (const char*) glGetString( GL_RENDERER ),
(const char*) glGetString( GL_VERSION ) );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glEnable( GL_DEPTH_TEST );
glEnable( GL_CULL_FACE );
glShadeModel( GL_SMOOTH );
glEnable( GL_LINE_SMOOTH );
glEnable( GL_NORMALIZE );
// Setup light
// https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
const GLfloat ambient[] = { 0.01f, 0.01f, 0.01f, 1.0f };
const GLfloat diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
// defines a directional light that points along the negative z-axis
const GLfloat position[] = { 0.0f, 0.0f, 2.0f * RANGE_SCALE_3D, 0.0f };
const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
glLightfv( GL_LIGHT0, GL_SPECULAR, specular );
glLightfv( GL_LIGHT0, GL_POSITION, position );
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
}
void EDA_3D_MODEL_VIEWER::ogl_set_arrow_material()
{
glEnable( GL_COLOR_MATERIAL );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
}
void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
{
event.Skip( false );
// SwapBuffer requires the window to be shown before calling
if( !IsShownOnScreen() )
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnPaint !IsShown" ) );
return;
}
// "Makes the OpenGL state that is represented by the OpenGL rendering
// context context current, i.e. it will be used by all subsequent OpenGL calls.
// This function may only be called when the window is shown on screen"
if( m_glRC == nullptr )
m_glRC = Pgm().GetGLContextManager()->CreateCtx( this );
// CreateCtx could and does fail per sentry crash events, lets be graceful
if( m_glRC == nullptr )
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnPaint creating gl context failed" ) );
return;
}
Pgm().GetGLContextManager()->LockCtx( m_glRC, this );
// Set the OpenGL viewport according to the client size of this canvas.
// This is done here rather than in a wxSizeEvent handler because our
// OpenGL rendering context (and thus viewport setting) is used with
// multiple canvases: If we updated the viewport in the wxSizeEvent
// handler, changing the size of one canvas causes a viewport setting that
// is wrong when next another canvas is repainted.
wxSize clientSize = GetNativePixelSize();
if( !m_ogl_initialized )
{
m_ogl_initialized = true;
ogl_initialize();
}
if( m_reload_is_needed )
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnPaint m_reload_is_needed" ) );
m_reload_is_needed = false;
m_ogl_3dmodel = new MODEL_3D( *m_3d_model, MATERIAL_MODE::NORMAL );
// It convert a model as it was a board, so get the max size dimension of the board
// and compute the conversion scale
m_BiuTo3dUnits =
(double) RANGE_SCALE_3D
/ ( (double) m_ogl_3dmodel->GetBBox().GetMaxDimension() * UNITS3D_TO_UNITSPCB );
}
glViewport( 0, 0, clientSize.x, clientSize.y );
m_trackBallCamera.SetCurWindowSize( clientSize );
// clear color and depth buffers
glEnable( GL_DEPTH_TEST );
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
glClearDepth( 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// Set projection and modelview matrices
glMatrixMode( GL_PROJECTION );
glLoadMatrixf( glm::value_ptr( m_trackBallCamera.GetProjectionMatrix() ) );
glMatrixMode( GL_MODELVIEW );
glLoadMatrixf( glm::value_ptr( m_trackBallCamera.GetViewMatrix() ) );
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
// Render Model
if( m_ogl_3dmodel )
{
glPushMatrix();
double modelunit_to_3d_units_factor = m_BiuTo3dUnits * UNITS3D_TO_UNITSPCB;
glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
modelunit_to_3d_units_factor );
// Center model in the render viewport
const SFVEC3F model_center = m_ogl_3dmodel->GetBBox().GetCenter();
glTranslatef( -model_center.x, -model_center.y, -model_center.z );
m_ogl_3dmodel->BeginDrawMulti( true );
m_ogl_3dmodel->DrawOpaque( false );
glDepthMask( GL_FALSE );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
m_ogl_3dmodel->DrawTransparent( 1.0f, false );
glDisable( GL_BLEND );
glDepthMask( GL_TRUE );
m_ogl_3dmodel->EndDrawMulti();
glPopMatrix();
}
// YxY squared view port
glViewport( 0, 0, clientSize.y / 8 , clientSize.y / 8 );
glClear( GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0f, 1.0f, 0.01f, RANGE_SCALE_3D * 2.0f );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
const glm::mat4 TranslationMatrix = glm::translate( glm::mat4(1.0f),
SFVEC3F( 0.0f, 0.0f, -RANGE_SCALE_3D ) );
const glm::mat4 ViewMatrix = TranslationMatrix * m_trackBallCamera.GetRotationMatrix();
glLoadMatrixf( glm::value_ptr( ViewMatrix ) );
ogl_set_arrow_material();
glColor3f( 0.9f, 0.0f, 0.0f );
DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( RANGE_SCALE_3D / 2.65f, 0.0f, 0.0f ),
0.275f );
glColor3f( 0.0f, 0.9f, 0.0f );
DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, RANGE_SCALE_3D / 2.65f, 0.0f ),
0.275f );
glColor3f( 0.0f, 0.0f, 0.9f );
DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, 0.0f, RANGE_SCALE_3D / 2.65f ),
0.275f );
// "Swaps the double-buffer of this window, making the back-buffer the
// front-buffer and vice versa, so that the output of the previous OpenGL
// commands is displayed on the window."
SwapBuffers();
Pgm().GetGLContextManager()->UnlockCtx( m_glRC );
}
void EDA_3D_MODEL_VIEWER::OnEraseBackground( wxEraseEvent& event )
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnEraseBackground" ) );
// Do nothing, to avoid flashing.
}
void EDA_3D_MODEL_VIEWER::OnMouseWheel( wxMouseEvent& event )
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnMouseWheel" ) );
if( event.ShiftDown() )
{
//if( event.GetWheelRotation() < 0 )
//SetView3D( VIEW_3D_TYPE::VIEW3D_PAN_UP ); // move up
//else
//SetView3D( VIEW_3D_TYPE::VIEW3D_PAN_DOWN ); // move down
}
else if( event.ControlDown() )
{
//if( event.GetWheelRotation() > 0 )
//SetView3D( VIEW_3D_TYPE::VIEW3D_PAN_RIGHT ); // move right
//else
//SetView3D( VIEW_3D_TYPE::VIEW3D_PAN_LEFT ); // move left
}
else
{
m_trackBallCamera.Zoom( event.GetWheelRotation() > 0 ? 1.1f : 1/1.1f );
//DisplayStatus();
Refresh( false );
}
m_trackBallCamera.SetCurMousePosition( event.GetPosition() );
}
#ifdef USE_OSX_MAGNIFY_EVENT
void EDA_3D_MODEL_VIEWER::OnMagnify( wxMouseEvent& event )
{
}
#endif
void EDA_3D_MODEL_VIEWER::OnMouseMove( wxMouseEvent& event )
{
const wxSize& nativeWinSize = GetNativePixelSize();
const wxPoint& nativePosition = GetNativePosition( event.GetPosition() );
m_trackBallCamera.SetCurWindowSize( nativeWinSize );
if( event.Dragging() )
{
if( event.LeftIsDown() ) // Drag
m_trackBallCamera.Drag( nativePosition );
// orientation has changed, redraw mesh
Refresh( false );
}
m_trackBallCamera.SetCurMousePosition( nativePosition );
}
void EDA_3D_MODEL_VIEWER::OnLeftDown( wxMouseEvent& event )
{
event.Skip();
}
void EDA_3D_MODEL_VIEWER::OnLeftUp( wxMouseEvent& event )
{
event.Skip();
}
void EDA_3D_MODEL_VIEWER::OnMiddleDown( wxMouseEvent& event )
{
event.Skip();
}
void EDA_3D_MODEL_VIEWER::OnMiddleUp( wxMouseEvent& event )
{
event.Skip();
}
void EDA_3D_MODEL_VIEWER::OnRightClick( wxMouseEvent& event )
{
event.Skip();
}
@@ -1,143 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright The 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
*/
/**
* @file eda_3d_model_viewer.h
* @brief Implements a model viewer canvas.
*
* The purpose of model viewer is to render 3d models that come in the original data from
* the files without any transformations.
*/
#ifndef _C3D_MODEL_VIEWER_H_
#define _C3D_MODEL_VIEWER_H_
#include "3d_rendering/track_ball.h"
#include <gal/hidpi_gl_canvas.h>
class S3D_CACHE;
class MODEL_3D;
/**
* Implement a canvas based on a wxGLCanvas.
*/
class EDA_3D_MODEL_VIEWER : public HIDPI_GL_CANVAS
{
public:
/**
* Create a new 3D Canvas with a attribute list.
*
* @param aParent the parent creator of this canvas.
* @param aGLAttribs openGL attributes created by #OGL_ATT_LIST::GetAttributesList.
*/
EDA_3D_MODEL_VIEWER( wxWindow* aParent, const wxGLAttributes& aGLAttribs,
S3D_CACHE* aCacheManager = nullptr );
~EDA_3D_MODEL_VIEWER();
/**
* Set this model to be displayed.
*
* @param a3DModel 3D model data.
*/
void Set3DModel( const S3DMODEL& a3DModel );
/**
* Set this model to be displayed.
*
* N.B. This will not load a model from the internal cache. Only from on disk.
*
* @param aModelPathName 3D model path name. Must be a file on disk.
*/
void Set3DModel( const wxString& aModelPathName );
/**
* Unload the displayed 3D model.
*/
void Clear3DModel();
private:
void ogl_initialize();
void ogl_set_arrow_material();
void OnPaint( wxPaintEvent& event );
void OnEraseBackground( wxEraseEvent& event );
void OnMouseWheel( wxMouseEvent& event );
#ifdef USE_OSX_MAGNIFY_EVENT
void OnMagnify( wxMouseEvent& event );
#endif
void OnMouseMove( wxMouseEvent& event );
void OnLeftDown( wxMouseEvent& event );
void OnLeftUp( wxMouseEvent& event );
void OnMiddleUp( wxMouseEvent& event );
void OnMiddleDown( wxMouseEvent& event );
void OnRightClick( wxMouseEvent& event );
DECLARE_EVENT_TABLE()
/// openGL context
wxGLContext* m_glRC;
/// Camera used in this canvas
TRACK_BALL m_trackBallCamera;
/// Original 3d model data
const S3DMODEL* m_3d_model;
/// Class holder for 3d model to display on openGL
MODEL_3D* m_ogl_3dmodel;
/// Flag that we have a new model and it need to be reloaded when the paint is called
bool m_reload_is_needed;
/// Flag if open gl was initialized
bool m_ogl_initialized;
/// factor to convert the model or any other items to keep it in relation to
/// the +/-RANGE_SCALE_3D
/// (it is named same as the board render for better understanding proposes)
double m_BiuTo3dUnits;
/// Optional cache manager
S3D_CACHE* m_cacheManager;
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_EDA_3D_MODEL_VIEWER". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
static const wxChar* m_logTrace;
};
#endif // _C3D_MODEL_VIEWER_H_
-27
View File
@@ -1,27 +0,0 @@
add_library(3d-viewer_navlib STATIC
"nl_3d_viewer_plugin.cpp"
"nl_3d_viewer_plugin_impl.cpp"
"nl_footprint_properties_plugin.cpp"
"nl_footprint_properties_plugin_impl.cpp"
)
# 3d-viewer_navlib depends on make_lexer outputs in common
add_dependencies( 3d-viewer_navlib pcbcommon )
# Find the 3DxWare SDK component 3DxWare::NlClient
# find_package(TDxWare_SDK 4.0 REQUIRED COMPONENTS 3DxWare::Navlib)
target_compile_definitions(3d-viewer_navlib PRIVATE
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_COMPILE_DEFINITIONS>
)
target_compile_options(3d-viewer_navlib PRIVATE
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_COMPILE_OPTIONS>
)
target_include_directories(3d-viewer_navlib PRIVATE
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:pcbnew_kiface_objects,INCLUDE_DIRECTORIES>
)
target_link_libraries(3d-viewer_navlib
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_LINK_LIBRARIES>
3DxWare::Navlib
)
@@ -1,45 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 3Dconnexion
* Copyright The 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 "nl_3d_viewer_plugin.h"
#include "nl_3d_viewer_plugin_impl.h"
#include <advanced_config.h>
#include <kiplatform/drivers.h>
NL_3D_VIEWER_PLUGIN::NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport )
{
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver
&& KIPLATFORM::DRIVERS::Valid3DConnexionDriverVersion() )
{
m_impl = std::make_unique<NL_3D_VIEWER_PLUGIN_IMPL>( aViewport, "KiCAD 3D" );
m_impl->Connect();
}
}
NL_3D_VIEWER_PLUGIN::~NL_3D_VIEWER_PLUGIN() = default;
void NL_3D_VIEWER_PLUGIN::SetFocus( bool focus )
{
if( m_impl )
m_impl->SetFocus( focus );
}
-62
View File
@@ -1,62 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 3Dconnexion
* Copyright The 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/>.
*/
/**
* @file nl_3d_viewer_plugin.h
* @brief Declaration of the NL_3D_VIEWER_PLUGIN class
*/
#ifndef NL_3D_VIEWER_PLUGIN_H_
#define NL_3D_VIEWER_PLUGIN_H_
#include <memory>
// Forward declarations.
class EDA_3D_CANVAS;
class NL_3D_VIEWER_PLUGIN_IMPL;
/**
* The class that implements the public interface to the SpaceMouse plug-in.
*/
class NL_3D_VIEWER_PLUGIN
{
public:
/**
* Initializes a new instance of the NL_3D_VIEWER_PLUGIN.
*
* @param aViewport is the viewport to be navigated.
*/
NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport );
virtual ~NL_3D_VIEWER_PLUGIN();
/**
* Set the connection to the 3Dconnexion driver to the focus state so that
* 3DMouse data is routed here.
*
* @param aFocus is true to set the connection active.
*/
void SetFocus( bool aFocus = true );
private:
std::unique_ptr<NL_3D_VIEWER_PLUGIN_IMPL> m_impl;
};
#endif // NL_3D_VIEWER_PLUGIN_H_
@@ -1,663 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright The 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 "nl_3d_viewer_plugin_impl.h"
// 3d-viewer
#include <3d-viewer/3d_rendering/track_ball.h>
#include <3d-viewer/3d_canvas/eda_3d_canvas.h>
// KiCad includes
#include <tool/action_manager.h>
#include <tool/tool_manager.h>
#include <tool/tools_holder.h>
// stdlib
#include <map>
#include <string>
#include <vector>
#include <wx/mstream.h>
/**
* Flag to enable the NL_3D_VIEWER_PLUGIN debug tracing.
*
* Use "KI_TRACE_NL_3D_VIEWER_PLUGIN" to enable.
*
* @ingroup trace_env_vars
*/
const wxChar* NL_3D_VIEWER_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_3D_VIEWER_PLUGIN" );
/**
* Template to compare two glm::mat<T> values for equality within a required epsilon.
*
* @param aFirst value to compare.
* @param aSecond value to compare.
* @param aEpsilon allowed error.
* @return true if the values considered equal within the specified epsilon, otherwise false.
*/
template <glm::length_t L, glm::length_t C, class T, glm::qualifier Q>
bool equals( glm::mat<L, C, T, Q> const& aFirst, glm::mat<L, C, T, Q> const& aSecond,
T aEpsilon = static_cast<T>( FLT_EPSILON * 10 ) )
{
T const* first = glm::value_ptr( aFirst );
T const* second = glm::value_ptr( aSecond );
for( glm::length_t j = 0; j < L * C; ++j )
{
if( !equals( first[j], second[j], aEpsilon ) )
{
return false;
}
}
return true;
}
NL_3D_VIEWER_PLUGIN_IMPL::NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas,
const std::string& aProfileHint ) :
NAV_3D( false, false ),
m_canvas( aCanvas ),
m_capIsMoving( false ),
m_newWidth( 0.0 )
{
m_camera = dynamic_cast<TRACK_BALL*>( m_canvas->GetCamera() );
PutProfileHint( aProfileHint );
}
NL_3D_VIEWER_PLUGIN_IMPL::~NL_3D_VIEWER_PLUGIN_IMPL()
{
EnableNavigation( false );
}
void NL_3D_VIEWER_PLUGIN_IMPL::SetFocus( bool aFocus )
{
wxLogTrace( m_logTrace, wxT( "NL_3D_VIEWER_PLUGIN_IMPL::SetFocus %d" ), aFocus );
NAV_3D::Write( navlib::focus_k, aFocus );
}
EDA_3D_CANVAS* NL_3D_VIEWER_PLUGIN_IMPL::GetCanvas() const
{
return m_canvas;
}
void NL_3D_VIEWER_PLUGIN_IMPL::Connect()
{
EnableNavigation(true);
PutFrameTimingSource(TimingSource::SpaceMouse);
exportCommandsAndImages();
}
CATEGORY_STORE::iterator add_category( std::string aCategoryPath, CATEGORY_STORE& aCategoryStore )
{
using TDx::SpaceMouse::CCategory;
CATEGORY_STORE::iterator parent_iter = aCategoryStore.begin();
std::string::size_type pos = aCategoryPath.find_last_of( '.' );
if( pos != std::string::npos )
{
std::string parentPath = aCategoryPath.substr( 0, pos );
parent_iter = aCategoryStore.find( parentPath );
if( parent_iter == aCategoryStore.end() )
{
parent_iter = add_category( parentPath, aCategoryStore );
}
}
std::string name = aCategoryPath.substr( pos + 1 );
std::unique_ptr<CCategory> categoryNode =
std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() );
CATEGORY_STORE::iterator iter = aCategoryStore.insert(
aCategoryStore.end(), CATEGORY_STORE::value_type( aCategoryPath, categoryNode.get() ) );
parent_iter->second->push_back( std::move( categoryNode ) );
return iter;
}
void NL_3D_VIEWER_PLUGIN_IMPL::exportCommandsAndImages()
{
wxLogTrace( m_logTrace, wxT( "NL_3D_VIEWER_PLUGIN_IMPL::exportCommandsAndImages" ) );
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
if( actions.size() == 0 )
{
return;
}
using TDx::SpaceMouse::CCommand;
using TDx::SpaceMouse::CCommandSet;
// The root action set node
CCommandSet commandSet( "EDA_3D_CANVAS", "3D Viewer" );
// Activate the command set
NAV_3D::PutActiveCommands( commandSet.GetId() );
// temporary store for the categories
CATEGORY_STORE categoryStore;
std::vector<TDx::CImage> vImages;
// add the action set to the category_store
categoryStore.insert( categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) );
std::list<TOOL_ACTION*>::const_iterator it;
for( it = actions.begin(); it != actions.end(); ++it )
{
const TOOL_ACTION* action = *it;
std::string label = action->GetMenuLabel().ToStdString();
if( label.empty() )
{
continue;
}
std::string name = action->GetName();
// Do no export commands for the Pcbnew app.
if( name.rfind( "pcbnew.", 0 ) == 0 )
{
continue;
}
std::string strCategory = action->GetToolName();
CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
if( iter == categoryStore.end() )
{
iter = add_category( std::move( strCategory ), categoryStore );
}
std::string description = action->GetDescription().ToStdString();
// Arbitrary 8-bit data stream
wxMemoryOutputStream imageStream;
if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
{
wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
image.Destroy();
if( imageStream.GetSize() )
{
wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
tdxImage.AssignImage( std::string( reinterpret_cast<const char*>(
streamBuffer->GetBufferStart() ),
streamBuffer->GetBufferSize() ),
0 );
wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
vImages.push_back( std::move( tdxImage ) );
}
}
wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
name, description, iter->first );
iter->second->push_back(
CCommand( std::move( name ), std::move( label ), std::move( description ) ) );
}
NAV_3D::AddCommandSet( commandSet );
NAV_3D::AddImages( vImages );
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
{
// cache the camera matrix so that we can tell if the view has been moved and
// calculate a delta transform if required.
m_cameraMatrix = m_camera->GetViewMatrix();
std::copy_n( glm::value_ptr( glm::inverse( m_cameraMatrix ) ), 16, matrix.m );
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
{
SFVEC3F origin, direction;
m_camera->MakeRayAtCurrentMousePosition( origin, direction );
position = { origin.x, origin.y, origin.z };
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
{
if( m_camera->GetProjection() == PROJECTION_TYPE::PERSPECTIVE )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
double half_width = f.fw / 2.;
double half_height = f.fh / 2.;
extents = { -half_width, -half_height, f.nearD, half_width, half_height, f.farD };
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewFOV( double& aFov ) const
{
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
aFov = glm::radians( f.angle );
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& aFrustum ) const
{
if( m_camera->GetProjection() != PROJECTION_TYPE::PERSPECTIVE )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
double half_width = f.nw / 2.;
double half_height = f.nh / 2.;
aFrustum = { -half_width, half_width, -half_height, half_height, f.nearD, f.farD };
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
{
perspective = m_camera->GetProjection() == PROJECTION_TYPE::PERSPECTIVE ? 1 : 0;
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& aCameraMatrix )
{
long result = 0;
glm::mat4 cam, viewMatrix;
std::copy_n( aCameraMatrix.m, 16, glm::value_ptr( cam ) );
viewMatrix = glm::inverse( cam );
glm::mat4 camera = m_camera->GetViewMatrix();
// The navlib does not move the camera in its z-axis in an orthographic projection
// as this does not change the viewed object size. However ...
if( m_camera->GetProjection() == PROJECTION_TYPE::ORTHO )
{
// ... the CAMERA class couples zoom and distance to the object: we need to
// ensure that The CAMERA's z position relative to the lookat_pos is not changed
// in an orthographic projection.
glm::vec4 lookat( m_camera->GetLookAtPos(), 1.0f );
glm::vec4 lookat_new = viewMatrix * lookat;
glm::vec4 lookat_old = camera * lookat;
viewMatrix[3].z += lookat_old.z - lookat_new.z;
}
if( !equals( camera, m_cameraMatrix ) )
{
// Some other input device has moved the camera. Apply only the intended delta
// transform ...
m_camera->SetViewMatrix( viewMatrix * glm::inverse( m_cameraMatrix ) * camera );
m_camera->Update();
// .., cache the intended camera matrix so that we can calculate the delta
// transform when needed ...
m_cameraMatrix = viewMatrix;
// ... and let the 3DMouse controller know, that something is amiss.
return navlib::make_result_code( navlib::navlib_errc::error );
}
m_camera->SetViewMatrix( viewMatrix );
m_camera->Update();
// cache the view matrix so that we know when it has changed.
m_cameraMatrix = m_camera->GetViewMatrix();
// The camera has a constraint on the z position so we need to check that ...
if( !equals( m_cameraMatrix[3].z, viewMatrix[3].z ) )
{
// ... and let the 3DMouse controller know, when something is amiss.
return navlib::make_result_code( navlib::navlib_errc::error );
}
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
{
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
float factor = f.nw / ( extents.max_x - extents.min_x );
float zoom = m_camera->GetZoom() / factor;
m_camera->Zoom( factor );
// The camera auto positions the camera to match the zoom values. We need to
// update our cached camera matrix to match the new z value
m_cameraMatrix[3].z = m_camera->GetViewMatrix()[3].z;
// The camera has a constraint on the zoom factor so we need to check that ...
if( zoom != m_camera->GetZoom() )
{
// ... and let the 3DMouse controller know, when something is amiss.
return navlib::make_result_code( navlib::navlib_errc::error );
}
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewFOV( double fov )
{
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
{
return navlib::make_result_code( navlib::navlib_errc::permission_denied );
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
{
SFVEC3F min = m_canvas->GetBoardAdapter().GetBBox().Min();
SFVEC3F max = m_canvas->GetBoardAdapter().GetBBox().Max();
extents = { min.x, min.y, min.z, max.x, max.y, max.z };
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
{
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
{
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsSelectionEmpty( navlib::bool_t& empty ) const
{
empty = true;
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
{
SFVEC3F lap = m_camera->GetLookAtPos();
position = { lap.x, lap.y, lap.z };
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
{
userPivot = false;
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
{
SFVEC3F pivotPos = SFVEC3F( position.x, position.y, position.z );
// Set the 3dmouse pivot position.
m_canvas->Set3dmousePivotPos( pivotPos );
// Set the camera lookat pos.
m_camera->SetLookAtPos_T1( pivotPos );
m_canvas->Request_refresh();
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
{
visible = m_canvas->GetRender3dmousePivot();
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetPivotVisible( bool visible )
{
m_canvas->SetRender3dmousePivot( visible );
m_canvas->Request_refresh();
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
{
RAY mouseRay;
mouseRay.Init( m_rayOrigin, m_rayDirection );
float hit;
glm::vec3 vec;
// Test it with the board bounding box
if( m_canvas->GetBoardAdapter().GetBBox().Intersect( mouseRay, &hit ) )
{
vec = mouseRay.at( hit );
position = { vec.x, vec.y, vec.z };
return 0;
}
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitAperture( double aperture )
{
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
{
m_rayDirection = { direction.x, direction.y, direction.z };
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
{
m_rayOrigin = { eye.x, eye.y, eye.z };
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitSelectionOnly( bool onlySelection )
{
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetActiveCommand( std::string commandId )
{
if( commandId.empty() )
{
return 0;
}
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
TOOL_ACTION* context = nullptr;
for( std::list<TOOL_ACTION*>::const_iterator it = actions.begin(); it != actions.end(); it++ )
{
TOOL_ACTION* action = *it;
std::string nm = action->GetName();
if( commandId == nm )
{
context = action;
}
}
if( context != nullptr )
{
wxWindow* parent = m_canvas->GetParent();
// Only allow command execution if the window is enabled. i.e. there is not a modal dialog
// currently active.
TOOLS_HOLDER* tools_holder = nullptr;
if( parent->IsEnabled() && ( tools_holder = dynamic_cast<TOOLS_HOLDER*>( parent ) ) )
{
TOOL_MANAGER* tool_manager = tools_holder->GetToolManager();
if( tool_manager == nullptr )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
// Get the selection to use to test if the action is enabled
SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
bool runAction = true;
if( const ACTION_CONDITIONS* aCond =
tool_manager->GetActionManager()->GetCondition( *context ) )
{
runAction = aCond->enableCondition( sel );
}
if( runAction )
{
tool_manager->RunAction( *context );
m_canvas->Request_refresh();
}
}
else
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
}
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetSettingsChanged( long change )
{
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetMotionFlag( bool value )
{
m_capIsMoving = value;
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetTransaction( long value )
{
if( value != 0L )
{
}
else
{
m_canvas->Request_refresh( true );
wxLogTrace( m_logTrace, wxT( "End of transaction" ) );
}
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
{
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
{
matrix = { 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1 };
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
{
// Use the right-handed coordinate system X-right, Z-up, Y-in (row vectors)
matrix = { 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1 };
return 0;
}
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
{
isRotatable = true;
return 0;
}
@@ -1,162 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright The 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/>.
*/
/**
* @file nl_3d_viewer_plugin_impl.h
* @brief Declaration of the NL_3D_VIEWER_PLUGIN_IMPL class
*/
#ifndef NL_3D_VIEWER_PLUGIN_IMPL_H_
#define NL_3D_VIEWER_PLUGIN_IMPL_H_
// TDxWare SDK.
#include <SpaceMouse/CNavigation3D.hpp>
// KiCad
#include <include/plugins/3dapi/xv3d_types.h>
// wx
#include <wx/chartype.h>
// glm
#include <glm/glm.hpp>
// Forward declarations.
class EDA_3D_CANVAS;
class TRACK_BALL;
// temporary store for the categories
typedef std::map<std::string, TDx::CCommandTreeNode*> CATEGORY_STORE;
/**
* Add a category to the store.
*
* The function adds category paths of the format "A.B" where B is a sub-category of A.
*
* @param aCategoryPath is the std::string representation of the category.
* @param aCategoryStore is the CATEGORY_STORE instance to add to.
* @return a CATEGORY_STORE::iterator where the category was added.
*/
CATEGORY_STORE::iterator add_category( std::string aCategoryPath, CATEGORY_STORE& aCategoryStore );
// Convenience typedef.
typedef TDx::SpaceMouse::Navigation3D::CNavigation3D NAV_3D;
/**
* The class that implements the accessors and mutators required for
* 3D navigation in an EDA_3D_CANVAS using a SpaceMouse.
*/
class NL_3D_VIEWER_PLUGIN_IMPL : public NAV_3D
{
public:
/**
* Initializes a new instance of the NL_3DVIEWER_PLUGIN.
*
* @param aCanvas is the viewport to be navigated.
* @param aProfileHint tells the 3DConnexion UI which profile to use.
*/
NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas, const std::string& aProfileHint );
virtual ~NL_3D_VIEWER_PLUGIN_IMPL();
/**
* Set the connection to the 3Dconnexion driver to the focus state so that
* 3DMouse data is routed here.
*
* @param aFocus is true to set the connection active.
*/
void SetFocus( bool aFocus = true );
/**
* Get the m_canvas pointer.
*/
EDA_3D_CANVAS* GetCanvas() const;
/**
* Connect plugin implementation to the driver.
*/
void Connect();
private:
/**
* Export the invocable actions and images to the 3Dconnexion UI.
*/
virtual void exportCommandsAndImages();
long GetCameraMatrix( navlib::matrix_t& aMatrix ) const override;
long GetPointerPosition( navlib::point_t& aPosition ) const override;
long GetViewExtents( navlib::box_t& aExtents ) const override;
long GetViewFOV( double& aFov ) const override;
long GetViewFrustum( navlib::frustum_t& aFrustum ) const override;
long GetIsViewPerspective( navlib::bool_t& aPerspective ) const override;
long SetCameraMatrix( const navlib::matrix_t& aMatrix ) override;
long SetViewExtents( const navlib::box_t& aExtents ) override;
long SetViewFOV( double aFov ) override;
long SetViewFrustum( const navlib::frustum_t& aFrustum ) override;
long GetModelExtents( navlib::box_t& aExtents ) const override;
long GetSelectionExtents( navlib::box_t& aExtents ) const override;
long GetSelectionTransform( navlib::matrix_t& aTransform ) const override;
long GetIsSelectionEmpty( navlib::bool_t& aEmpty ) const override;
long SetSelectionTransform( const navlib::matrix_t& aMatrix ) override;
long GetPivotPosition( navlib::point_t& aPosition ) const override;
long IsUserPivot( navlib::bool_t& aUserPivot ) const override;
long SetPivotPosition( const navlib::point_t& aPosition ) override;
long GetPivotVisible( navlib::bool_t& aVisible ) const override;
long SetPivotVisible( bool aVisible ) override;
long GetHitLookAt( navlib::point_t& aPosition ) const override;
long SetHitAperture( double aAperture ) override;
long SetHitDirection( const navlib::vector_t& aDirection ) override;
long SetHitLookFrom( const navlib::point_t& aPosition ) override;
long SetHitSelectionOnly( bool aSelectionOnly ) override;
long SetActiveCommand( std::string aCommandId ) override;
long SetSettingsChanged( long aChangeNumber ) override;
long SetMotionFlag( bool aValue ) override;
long SetTransaction( long aValue ) override;
long SetCameraTarget( const navlib::point_t& aPosition ) override;
long GetFrontView( navlib::matrix_t& aMatrix ) const override;
long GetCoordinateSystem( navlib::matrix_t& aMatrix ) const override;
long GetIsViewRotatable( navlib::bool_t& isRotatable ) const override;
private:
EDA_3D_CANVAS* m_canvas;
TRACK_BALL* m_camera;
bool m_capIsMoving;
double m_newWidth;
SFVEC3F m_rayOrigin;
SFVEC3F m_rayDirection;
// The cached CAMERA affine matrix. This is used to determine if the camera has been
// moved. The camera matrix is the world to camera affine.
mutable glm::mat4 m_cameraMatrix;
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_NL_3DVIEWER_PLUGIN". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
static const wxChar* m_logTrace;
};
#endif // NL_3D_VIEWER_PLUGIN_IMPL_H_
@@ -1,45 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright The 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 "nl_footprint_properties_plugin.h"
#include "nl_footprint_properties_plugin_impl.h"
#include <advanced_config.h>
#include <kiplatform/drivers.h>
NL_FOOTPRINT_PROPERTIES_PLUGIN::NL_FOOTPRINT_PROPERTIES_PLUGIN( EDA_3D_CANVAS* aViewport )
{
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver
&& KIPLATFORM::DRIVERS::Valid3DConnexionDriverVersion() )
{
m_impl = std::make_unique<NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL>( aViewport );
m_impl->Connect();
}
}
NL_FOOTPRINT_PROPERTIES_PLUGIN::~NL_FOOTPRINT_PROPERTIES_PLUGIN() = default;
void NL_FOOTPRINT_PROPERTIES_PLUGIN::SetFocus( bool focus )
{
if( m_impl )
m_impl->SetFocus( focus );
}
@@ -1,62 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright The 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/>.
*/
/**
* @file nl_footprint_properties_plugin.h
* @brief declaration of the nl_footprint_properties_plugin class
*/
#ifndef NL_FOOTPRINT_PROPERTIES_PLUGIN_H_
#define NL_FOOTPRINT_PROPERTIES_PLUGIN_H_
#include <memory>
// Forward declarations.
class EDA_3D_CANVAS;
class NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL;
/**
* The class that implements the public interface to the SpaceMouse plug-in.
*/
class NL_FOOTPRINT_PROPERTIES_PLUGIN
{
public:
/**
* Initializes a new instance of the NL_FOOTPRINT_PROPERTIES_PLUGIN.
*
* @param aViewport is the viewport to be navigated.
*/
NL_FOOTPRINT_PROPERTIES_PLUGIN( EDA_3D_CANVAS* aViewport );
virtual ~NL_FOOTPRINT_PROPERTIES_PLUGIN();
/**
* Set the connection to the 3Dconnexion driver to the focus state so that
* 3DMouse data is routed here.
*
* @param aFocus is true to set the connection active.
*/
void SetFocus( bool aFocus = true );
private:
std::unique_ptr<NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL> m_impl;
};
#endif // NL_FOOTPRINT_PROPERTIES_PLUGIN_H_
@@ -1,162 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright The 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 "nl_footprint_properties_plugin_impl.h"
#include <3d-viewer/3d_canvas/eda_3d_canvas.h>
// KiCAD includes
#include <tool/action_manager.h>
#include <tool/tool_manager.h>
#include <tool/tools_holder.h>
#include <wx/mstream.h>
#define BOUNDING_BOX_SCALE_FACTOR 1.3f
/**
* Flag to enable the NL_FOOTPRINT_PROPERTIES_PLUGIN debug tracing.
*
* Use "KI_TRACE_NL_FOOTPRINT_PROPERTIES_PLUGIN" to enable.
*
* @ingroup trace_env_vars
*/
const wxChar* NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::m_logTrace =
wxT( "KI_TRACE_NL_FOOTPRINT_PROPERTIES_PLUGIN" );
NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL(EDA_3D_CANVAS* aCanvas) :
NL_3D_VIEWER_PLUGIN_IMPL(aCanvas, "KiCAD Footprint Properties")
{}
long NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
{
SFVEC3F min = NL_3D_VIEWER_PLUGIN_IMPL::GetCanvas()->GetBoardAdapter().GetBBox().Min();
SFVEC3F max = NL_3D_VIEWER_PLUGIN_IMPL::GetCanvas()->GetBoardAdapter().GetBBox().Max();
SFVEC3F diff = ( BOUNDING_BOX_SCALE_FACTOR - 1.f ) / 2.f * ( max - min );
min -= diff;
max += diff;
extents = { min.x, min.y, min.z, max.x, max.y, max.z };
return 0;
}
void NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::exportCommandsAndImages()
{
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
if( actions.size() == 0 )
{
return;
}
using TDx::SpaceMouse::CCommand;
using TDx::SpaceMouse::CCommandSet;
// The root action set node
CCommandSet commandSet( "EDA_3D_CANVAS", "3D Viewer" );
// Activate the command set
NAV_3D::PutActiveCommands( commandSet.GetId() );
// temporary store for the categories
CATEGORY_STORE categoryStore;
std::vector<TDx::CImage> vImages;
// add the action set to the category_store
categoryStore.insert( categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) );
std::list<TOOL_ACTION*>::const_iterator it;
for( it = actions.begin(); it != actions.end(); ++it )
{
const TOOL_ACTION* action = *it;
std::string label = action->GetMenuLabel().ToStdString();
if( label.empty() )
{
continue;
}
std::string name = action->GetName();
// Do no export commands for the pcbnew app.
if( name.rfind( "pcbnew.", 0 ) == 0 )
{
continue;
}
// Exclude commands which can't be used in the footprint properties.
if( name.rfind( "3DViewer.Control.pivotCenter", 0 ) == 0
|| name.rfind( "3DViewer.Control.material", 0 ) == 0
|| name.rfind( "3DViewer.Control.attribute", 0 ) == 0
|| name.rfind( "3DViewer.Control.show", 0 ) == 0 )
{
continue;
}
std::string strCategory = action->GetToolName();
CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
if( iter == categoryStore.end() )
{
iter = add_category( std::move( strCategory ), categoryStore );
}
std::string description = action->GetDescription().ToStdString();
// Arbitrary 8-bit data stream
wxMemoryOutputStream imageStream;
if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
{
wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
image.Destroy();
if( imageStream.GetSize() )
{
wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
tdxImage.AssignImage( std::string( reinterpret_cast<const char*>(
streamBuffer->GetBufferStart() ),
streamBuffer->GetBufferSize() ),
0 );
wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
vImages.push_back( std::move( tdxImage ) );
}
}
wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
name, description, iter->first );
iter->second->push_back(
CCommand( std::move( name ), std::move( label ), std::move( description ) ) );
}
NAV_3D::AddCommandSet( commandSet );
NAV_3D::AddImages( vImages );
}
@@ -1,69 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright The 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/>.
*/
/**
* @file nl_footprint_properties_plugin_impl.h
* @brief declaration of the nl_footprint_properties_plugin_impl class
*/
#ifndef NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL_H_
#define NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL_H_
#include "nl_3d_viewer_plugin_impl.h"
// TDxWare SDK.
#include <SpaceMouse/CNavigation3D.hpp>
/**
* The class that adjusts NL_3D_VIEWER_PLUGIN_IMPL implementation for 3D Model preview in
* footprint properties dialog.
*/
class NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL : public NL_3D_VIEWER_PLUGIN_IMPL
{
public:
/**
* Initialize a new instance of the NL_FOOTPRINT_PROPERTIES_PLUGIN.
*
* @param aCanvas is the viewport to be navigated.
*/
NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas );
private:
/**
* Get Footprint 3D Model extents.
*
* @param extents is the box around the 3D model.
*/
long GetModelExtents( navlib::box_t& extents ) const override;
/**
* Export the invocable actions and images to the 3Dconnexion UI.
*/
void exportCommandsAndImages() override;
private:
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_NL_FOOTPRINT_PROPERTIES_PLUGIN". See the wxWidgets documentation on
* wxLogTrace for more information.
*/
static const wxChar* m_logTrace;
};
#endif // NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL_H_
+179
View File
@@ -0,0 +1,179 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras@wanadoo.fr
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2015 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
*/
/**
* @file 3d_read_mesh.cpp
*/
#include <fctsys.h>
#include <common.h>
#include <macros.h>
#include <kicad_string.h>
#include <pgm_base.h>
#define GLM_FORCE_RADIANS
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
#include <3d_viewer.h>
#include <info3d_visu.h>
#include "3d_struct.h"
#include "modelparsers.h"
S3D_MODEL_PARSER *S3D_MODEL_PARSER::Create( S3D_MASTER* aMaster,
const wxString aExtension )
{
if ( aExtension == wxT( "x3d" ) )
return new X3D_MODEL_PARSER( aMaster );
else if ( aExtension == wxT( "wrl" ) )
return new VRML_MODEL_PARSER( aMaster );
return NULL;
}
int S3D_MASTER::ReadData( S3D_MODEL_PARSER* aParser )
{
if( m_Shape3DFullFilename.IsEmpty() || aParser == NULL )
return -1;
wxString filename = m_Shape3DFullFilename;
#ifdef __WINDOWS__
filename.Replace( wxT( "/" ), wxT( "\\" ) );
#else
filename.Replace( wxT( "\\" ), wxT( "/" ) );
#endif
if( wxFileName::FileExists( filename ) )
{
wxFileName fn( filename );
if( aParser->Load( filename ) )
{
// Invalidate bounding boxes
m_fastAABBox.Reset();
m_BBox.Reset();
m_parser = aParser;
return 0;
}
}
wxLogDebug( wxT( "3D shape '%s' not found, even tried '%s' after env var substitution." ),
GetChars( m_Shape3DName ),
GetChars( filename ) );
return -1;
}
void S3D_MASTER::Render( bool aIsRenderingJustNonTransparentObjects,
bool aIsRenderingJustTransparentObjects )
{
if( m_parser == NULL )
return;
double aVrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
glScalef( aVrmlunits_to_3Dunits, aVrmlunits_to_3Dunits, aVrmlunits_to_3Dunits );
glTranslatef( m_MatPosition.x * SCALE_3D_CONV,
m_MatPosition.y * SCALE_3D_CONV,
m_MatPosition.z * SCALE_3D_CONV );
glRotatef( -m_MatRotation.z, 0.0f, 0.0f, 1.0f );
glRotatef( -m_MatRotation.y, 0.0f, 1.0f, 0.0f );
glRotatef( -m_MatRotation.x, 1.0f, 0.0f, 0.0f );
glScalef( m_MatScale.x, m_MatScale.y, m_MatScale.z );
for( unsigned int idx = 0; idx < m_parser->childs.size(); idx++ )
m_parser->childs[idx]->openGL_RenderAllChilds( aIsRenderingJustNonTransparentObjects,
aIsRenderingJustTransparentObjects );
}
CBBOX &S3D_MASTER::getBBox( )
{
if( !m_BBox.IsInitialized() )
calcBBox();
return m_BBox;
}
CBBOX &S3D_MASTER::getFastAABBox( )
{
if( !m_fastAABBox.IsInitialized() )
calcBBox();
return m_fastAABBox;
}
void S3D_MASTER::calcBBox()
{
if( m_parser == NULL )
return;
bool firstBBox = true;
for( unsigned int idx = 0; idx < m_parser->childs.size(); idx++ )
if( firstBBox )
{
firstBBox = false;
m_BBox = m_parser->childs[idx]->getBBox();
}
else
m_BBox.Union( m_parser->childs[idx]->getBBox() );
// Calc transformation matrix to apply in AABBox
float aVrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
glm::mat4 fullTransformMatrix;
fullTransformMatrix = glm::scale( glm::mat4(), S3D_VERTEX( aVrmlunits_to_3Dunits,
aVrmlunits_to_3Dunits,
aVrmlunits_to_3Dunits ) );
fullTransformMatrix = glm::translate( fullTransformMatrix, S3D_VERTEX( m_MatPosition.x * SCALE_3D_CONV,
m_MatPosition.y * SCALE_3D_CONV,
m_MatPosition.z * SCALE_3D_CONV) );
if( m_MatRotation.z != 0.0 )
fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians(-(float)m_MatRotation.z), S3D_VERTEX( 0.0f, 0.0f, 1.0f ) );
if( m_MatRotation.y != 0.0 )
fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians(-(float)m_MatRotation.y), S3D_VERTEX( 0.0f, 1.0f, 0.0f ) );
if( m_MatRotation.x != 0.0 )
fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians(-(float)m_MatRotation.x), S3D_VERTEX( 1.0f, 0.0f, 0.0f ) );
fullTransformMatrix = glm::scale( fullTransformMatrix, S3D_VERTEX( m_MatScale.x, m_MatScale.y, m_MatScale.z ) );
// Apply transformation
m_fastAABBox = m_BBox;
m_fastAABBox.ApplyTransformationAA( fullTransformMatrix );
}

Some files were not shown because too many files have changed in this diff Show More