Compare commits

..

371 Commits

Author SHA1 Message Date
Wayne Stambaugh c3dc1f65d4 Tag release version 5.1.4. 2019-08-04 12:36:25 -04:00
Wayne Stambaugh 238fb00727 Revert "Eeschema: fix many append schematic bugs."
This reverts commit 3518153d5b.
2019-08-04 12:34:25 -04:00
Wayne Stambaugh 2d48c81d58 Revert "Eeschema: fix edit sheet bug."
This reverts commit 6051dfae30.
2019-08-04 12:33:55 -04:00
Wayne Stambaugh 0893e0043f Revert "Eeschema: remove rogue symbol libraries from project file."
This reverts commit 5d60fe6812.
2019-08-04 12:33:19 -04:00
Jeff Young 72c0267fe6 Ativate delete tool so it can display the selection clarification menu when needed.
Fixes: lp:1835371
* https://bugs.launchpad.net/kicad/+bug/1835371

(cherry picked from commit c60118b6a4)
2019-08-03 22:49:27 -06:00
Seth Hillbrand c9956def36 pcbnew: Fix copy-paste error from 161dc9ce7
create_vrml_shell() needed the idxSide check but create_vrml_plane only
had an extra variable that wasn't used and so shouldn't be checked.
2019-08-02 13:14:02 -07:00
Wayne Stambaugh 5d60fe6812 Eeschema: remove rogue symbol libraries from project file.
Check for symbol libraries that somehow ended up in the project file
after remapping occurred and remove all of them to prevent potentially
broken symbol library links.

Add nagware dialog to warn the user and a checkbox to never show the
dialog again.

Fixes lp:1838185

https://bugs.launchpad.net/kicad/+bug/1838185
(cherry picked from commit 8789ab9265)
2019-08-01 15:24:55 -04:00
Wayne Stambaugh 6051dfae30 Eeschema: fix edit sheet bug.
Remove an existing sheet from the current page that requires a schematic
load from file to prevent a corrupt screen list from causing a segfault.

Merge the edit sheet file loading with the append schematic code since
they are functionally the same.  This allows the sheet edit code to
take advantage of all of the added broken symbol library links added in
the recent append schematic fixes.

Fixes lp:1835841

https://bugs.launchpad.net/kicad/+bug/1835841
(cherry picked from commit b595dc0d3b)
2019-08-01 15:24:55 -04:00
Wayne Stambaugh 3518153d5b Eeschema: fix many append schematic bugs.
Do not add cache library from another project to old library list.  This
is wrong and can cause all kinds of symbol library linking issues.  It's
better to force the user to fix broken symbol library links than the false
security of using multiple cache libraries.

Use correct paths when appending schematic outside of the current project
path when hierarchical sheets are appended.  If the path can be relative,
give the user the option to use either relative or absolute paths.

Do not change symbol library names in schematics appended from a source
outside the current project.  This will almost ensure the symbol library
links will be broken in the source project.

When the appended schematic is from another project, attempt to check all
of the possible combinations of symbol library table importing that could
cause broken symbol library links and give the user the option of canceling
the append operation or live with the possibility that there may be broken
symbol library links.

When the append schematic is in the current project path but not part of
the schematic, check to see if there are any library nicknames that do
no exist in the project symbol library table and give the user a chance
to cancel the append process.

(cherry picked from commit 9fae30162d)
2019-08-01 15:24:55 -04:00
Seth Hillbrand cf949609b2 eeschema: Properly map edge cases of legacy onto GAL
While we do not generate these arcs internally, some external tools
generate arcs that are technically valid but display correctly only
because of an oddity in the degeneracy mapping.

Fixes: lp:1838557
* https://bugs.launchpad.net/kicad/+bug/1838557
2019-08-01 11:45:10 -07:00
Jeff Young d482a8805c Perform better cleanup after cancelling text placement.
Fixes: lp:1838452
* https://bugs.launchpad.net/kicad/+bug/1838452
2019-07-31 23:17:08 -06:00
Seth Hillbrand 161dc9ce7e pcbnew: Fix VRML export checking
In rare cases, the VRML triangulator may claim to work but return empty
vectors.  These cases need to be caught before we dereference the vector
elements.

Fixes: lp:1838448
* https://bugs.launchpad.net/kicad/+bug/1838448
2019-07-31 20:03:49 -07:00
jean-pierre charras 090073cc3b Pcbnew, exchange footprints: fix a bug that prevent the new footprint to be at the right place.
Fixes: lp:1838446
https://bugs.launchpad.net/kicad/+bug/1838446
2019-07-31 12:07:49 +02:00
Ian McInerney 6ae718e4d6 pcbnew: Fix DXF units in drill map plotting
Fixes: lp:1836924
* https://bugs.launchpad.net/kicad/+bug/1836924

(cherry picked from commit 6c401ecce7)
2019-07-30 17:20:38 -04:00
Thomas Pointhuber 783b1cb611 Fix handling of filled circle in eagle importer (was only partly fixed)
Partly fixed in 4fc692f04b, but missed
that there is a loadPlain where I need to handle this case as well.

(cherry picked from commit 5f438b7a85)
2019-07-30 15:33:39 -04:00
Jeff Young 4b01f80e8d Fix typo in cherry-pick.
Fixes: lp:1838006
* https://bugs.launchpad.net/kicad/+bug/1838006
2019-07-30 11:49:06 -06:00
Jeff Young c8278f377b Alternative to cherry-picking b70df18939.
Fixes: lp:1838158
* https://bugs.launchpad.net/kicad/+bug/1838158
2019-07-29 20:19:46 -06:00
jean-pierre charras d34b664933 Simulation: do not add .save V(0) and/or .save V(GND) to ngspice.
These 2 nets are internally added by ngspice (info from Holger Vogt)

(cherry picked from commit d92396341e)
2019-07-28 04:52:57 -07:00
jean-pierre charras c8f40e1d26 PANEL_SETUP_NETCLASSES_BASE: fix minor wxAlert. 2019-07-28 13:26:58 +02:00
jean-pierre charras 185a8d7582 Try to fix UI issues in select layer pair dialog and slect layer dialog.
Fixes: lp:1838173
https://bugs.launchpad.net/kicad/+bug/1838173
2019-07-28 12:55:47 +02:00
jean-pierre charras 8373e91a1b Python scripting: fix missing definition of uint32_t (and some other similar defs).
Fixes: lp:1837867
https://bugs.launchpad.net/kicad/+bug/1837867
2019-07-27 08:22:10 +02:00
Jeff Young 6aeedfb70c Partial cherry-pick of 3904d7ccfc.
Fixes: lp:1838006
* https://bugs.launchpad.net/kicad/+bug/1838006
2019-07-26 20:46:12 -06:00
Stefan Hamminga e7f3851212 Rebased LTO fix for coroutines
Fixes: lp:1793329
* https://bugs.launchpad.net/kicad/+bug/1793329

(cherry picked from commit e58d9606dd)
2019-07-25 12:17:11 -07:00
jean-pierre charras 7df05ade4c Pcbnew: Fix bug in MODULE::FindPadByName( const wxString& aPadName ). This method was using a case insensitive comparison to find the pad matching aPadName. But in netlist we are using case sensitive comparisons to attribute a net to a pad. So if in the netlist there is a pad name that does not match any footprint pad name using case sensitive comparison but if it matches some pads using case insensitive comparison, the net is not set, but the test to detect non existing pads fails. 2019-07-25 17:57:38 +02:00
Seth Hillbrand 24b032ce5b Project Templates: Allow multiple line titles
This fixes two display issues in the project template selector.  The
first captured HTML tags in the template title display and the second
prevented more than one line for showing (at least on GTK) in the
preview.  This prevented disambiguation between the various templates.
2019-07-23 15:05:25 -07:00
Seth Hillbrand b6fe4ff637 eeschema: Clean up backup name
This fixes the last suffix that was missed by 168fa09f5.  The schematic
backup files should have the suffix .sch-bak to distinguish from
.kicad_pcb-bak or other backups.
2019-07-23 10:47:15 -07:00
Wayne Stambaugh 8f1aa28b37 Begin version 5.1.4 development. 2019-07-23 08:16:06 -04:00
Wayne Stambaugh 55c1e22a67 Tag release version 5.1.3. 2019-07-23 08:07:28 -04:00
Jeff Young ca0d4511a9 Copy ratsnest flags when exchanging modules.
Fixes: lp:1834214
* https://bugs.launchpad.net/kicad/+bug/1834214

(cherry picked from commit 2ca379b281)
2019-07-21 20:27:12 -06:00
Jeff Young b56855c542 Don't shove stitching vias.
Whether or not it's a good idea, the current algorithm doesn't support
it and leaves them on top of each other.

Fixes: lp:1833214
* https://bugs.launchpad.net/kicad/+bug/1833214

(cherry picked from commit aa4d7682ca)
2019-07-21 16:41:56 -06:00
Jeff Young 72e8eb3b94 Initialize plot with aux origin checkbox.
Fixes: lp:1836923
* https://bugs.launchpad.net/kicad/+bug/1836923

(cherry picked from commit b5e01ea163)
2019-07-20 07:58:43 -06:00
Jeff Young 281a1cdc2c Update DXF units drop-down.
Fixes: lp:1836927
* https://bugs.launchpad.net/kicad/+bug/1836927

(cherry picked from commit 4a1edf581e)
2019-07-20 07:58:38 -06:00
jean-pierre charras 3c8f901a1f Revert "Fix ngspice netlisting when net names contain '/'"
This reverts commit 216573bf48,
because the issue with net names containing '/' is not actually inside the netlist.
This commit 2165 creates issues with ngspice 2.8 and older, and do not fix anything in ngspice
2019-07-19 15:52:18 +02:00
Seth Hillbrand e0589d2908 pcbnew: Make clearance translucent
This sets the clearance outline to a slightly better opacity to allow
viewing of items behind the routed track clearance.  Future work should
include making this a configuration option.

Fixes: lp:1826719
* https://bugs.launchpad.net/kicad/+bug/1826719
2019-07-18 10:44:44 -07:00
Jeff Young dfd53976d4 Fix double-highlighted radio buttons on GTK.
Fixes: lp:1836538
* https://bugs.launchpad.net/kicad/+bug/1836538
2019-07-17 12:57:21 +01:00
Ian McInerney 02d43be93c pcbnew: Make the netlist class panel usable with a lot of classes
Fixes: lp:1826154
* https://bugs.launchpad.net/kicad/+bug/1826154

(cherry picked from commit 39954b20fe)
2019-07-15 06:12:13 -07:00
jean-pierre charras 2e8bceb676 Fix a minor wxWidgets alert, already fixed in master branch. 2019-07-15 12:27:54 +02:00
Jeff Young 16f9e697ab Allow edits to self-intersecting polygons.
1) Intermediate states might be self-intersecting, and we shouldn't
be policing our users on what order to do things in
2) The polygon might already be self-intersecting, at which point we're
preventing the user from fixing it.

Also includes better const management for SHAPE_POLY_SET API.

Fixes: lp:1833831
* https://bugs.launchpad.net/kicad/+bug/1833831

(cherry picked from commit a3c74051c2)
2019-07-14 18:36:47 +01:00
jean-pierre charras 269f88ee28 Fix incorrect handling of unicode chars (non ASCII7) in filenames in .gbrjob files. 2019-07-14 11:19:03 +02:00
Jeff Young f11d950448 Don't let visibility bit get nuked when updating effects.
Fixes: lp:1836183
* https://bugs.launchpad.net/kicad/+bug/1836183

(cherry picked from commit 6c9e34e799)
2019-07-11 23:01:54 +01:00
Jeff Young 6ba2c44e88 Add FootprintExists() which can be more careful about FS differences.
(And in particular, MSW's case-insensitive FS.)

Fixes: lp:1835999
* https://bugs.launchpad.net/kicad/+bug/1835999

(cherry picked from commit 20036f8105)
2019-07-11 23:01:25 +01:00
Jeff Young d1ed4665de OSX compiler didn't like the other syntax.
(cherry picked from commit f14e41133b)
2019-07-11 12:35:11 -07:00
Seth Hillbrand 5b68cfa018 Fix import graphics routines and tests
The returns of KiCad file extensions on GTK contain basic regex matching
case-insensitive file extensions.  We need to match these in the
provider and tests

(cherry picked from commit 1956c074ba)
2019-07-10 10:47:13 -07:00
Seth Hillbrand 85f88b6b05 Fix case-sensitive import using KiCad std
Fixes: lp:1832853
* https://bugs.launchpad.net/kicad/+bug/1832853

(cherry picked from commit 79e2000af4)
2019-07-10 10:33:03 -07:00
Seth Hillbrand ea467441d2 import_gfx: Make file selection case-insensitive
This adds the upper-case version of files names to the selection box for
filesystems that support case-sensitive file names.

Fixes: lp:1832853
* https://bugs.launchpad.net/kicad/+bug/1832853

(cherry picked from commit 36f70704eb)
2019-07-10 10:32:48 -07:00
Ian McInerney 40ba502853 pcbnew: Clean up warnings with unit handling in the DXF export
(cherry picked from commit ff9d899ae0)
2019-07-10 12:42:54 -04:00
Ian McInerney 09d7d0f1bc Update ngspice build tool script to ngspice-30
(cherry picked from commit 6186dd5c51)
2019-07-10 09:20:41 -04:00
Jeff Young 3418d53a6d Update symbol ID before running Update Fields from Library.
Fixes: lp:1827707
* https://bugs.launchpad.net/kicad/+bug/1827707

(cherry picked from commit fb881ee209)
2019-07-08 22:57:15 +01:00
Ian McInerney d5440d60ab eeschema: Fix initial selected text in reference value dialog
Fixes: lp:1834741
* https://bugs.launchpad.net/kicad/+bug/1834741

(cherry picked from commit e32306c232)
2019-07-08 14:50:53 -04:00
Jeff Young 2ba237ec12 Test for crash bug fix. 2019-07-08 15:34:01 +01:00
Jeff Young 01a343f28e Fix crash when re-entering a drag operation with a move.
Fixes: lp:1834111
* https://bugs.launchpad.net/kicad/+bug/1834111
2019-07-05 02:24:15 +01:00
Jeff Young 85220591e2 Fix bugs in keyboard cursor movement.
1) Generate refreshPreview events so the modern toolset doesn't
fall behind by one event (see LP:1818667)
2) In the legacy toolset don't call unimplemented routines and don't
snap to grid on the non-movement axis.
2019-07-05 01:32:15 +01:00
Jeff Young ecadc8bbba Fix bugs in new wire/line-width split.
If Symbol Editor isn't open then Eeschema needs to read in the
default line width.

Symbol Editor was failing to write line width parameter back to
properties.

Fixes: lp:1835051
* https://bugs.launchpad.net/kicad/+bug/1835051

(cherry picked from commit ef03afe289)
2019-07-03 14:34:11 +01:00
Jeff Young 26c92eaf0f Give up on KillFocus validation.
wxWidgets sends the KillFocus event before the Cancel button event,
and it sets the receiving-focus window pointer to NULL (so you can't
even check for it being the Cancel button.  Last time around (with
the UNIT_BINDER) I also tried a bunch of hacks for whether the window
pointer is NULL, etc., but they aren't discriminatory either.

Fixes: lp:1834975
* https://bugs.launchpad.net/kicad/+bug/1834975

Fixes: lp:1834966
* https://bugs.launchpad.net/kicad/+bug/1834966

(cherry picked from commit 1c30f3d9a9)
2019-07-02 18:13:27 +01:00
jean-pierre charras d129abb9c9 Eeschema, lib editor: fix a message error when loading a symbol from the schematic editor.
Adaptation from master branch, commit ff995bb7
2019-07-02 18:40:48 +02:00
Jeff Young 3b98b00d6f Only warn once in KillFocus for each error value in footprint name.
More than that just gets annoying, and there is at least one edge case
which throws us into an infinite loop if we don't have something to
break us out.

Fixes: lp:1834966
* https://bugs.launchpad.net/kicad/+bug/1834966

(cherry picked from commit 29db6152b3)
2019-07-02 00:48:57 +01:00
Jeff Young ce329e13fb Set library selection when pre-loading the Footprint Viewer.
Fixes: lp:1826932
* https://bugs.launchpad.net/kicad/+bug/1826932

(cherry picked from commit 8efe8d1835)
2019-07-01 22:17:57 +01:00
Seth Hillbrand be9cd98cb1 Move zone refill to action
This unifies the zone refill across architecture into the tool-based
architecture.  Also provides ZONE_FILLER-based progress managment for
tools.
2019-07-01 09:16:32 -07:00
Jeff Young 216acd98d6 Separate default line and wire thicknesses.
Fixes: lp:1834324
* https://bugs.launchpad.net/kicad/+bug/1834324
2019-06-30 11:13:17 +01:00
Jeff Young 10fd8a59b2 Apply relevant fixes from 51479c2042.
Fixes: lp:1834703
* https://bugs.launchpad.net/kicad/+bug/1834703
2019-06-29 21:17:22 +01:00
Seth Hillbrand 3974c6fd89 Enforcing rational limits on length tuner
The length tuning dialog needed validators on close to prevent negative
and percentages >100%

Fixes: lp:1834734
* https://bugs.launchpad.net/kicad/+bug/1834734
2019-06-29 09:37:47 -07:00
Ian McInerney f82962e42c eeschema: Fix python BOM generators to handle symbols
* Implement proper natural sorting of the reference values
* Perform quoting of all items in BOM generators that use csv.writer

Fixes: lp:1833822
* https://bugs.launchpad.net/kicad/+bug/1833822
2019-06-29 17:17:20 +02:00
Seth Hillbrand bf1ced4184 Allow more segments for large-arc footprints
When approximating arcs for polygons, we should allow for large radius
arcs/circles without coarsening the arc beyond a limit.  This is a
5.1.x-only patch to address this issue.  It should not be picked to
master as this is already addressed separately by max_error
2019-06-28 19:25:42 -07:00
Seth Hillbrand cabfcbc73c pcbnew: Drop tracks not on copper
We do not allow non-copper routed tracks and they will break assumptions
elsewhere in the code.  We drop them in the beginning so that they are
not saved.
2019-06-28 19:25:28 -07:00
Wayne Stambaugh 574473c480 Pcbnew: fix clean up tracks and vias segfault bug.
If a track has no connected items, do not attempt to access an empty
connected item map.

Fixes lp:1823973

https://bugs.launchpad.net/kicad/+bug/1823973
2019-06-28 13:12:23 -04:00
jean-pierre charras 17143fd53f Pcbnew, connectivity: fix incorrect detection of dangling track ends when a end is inside a zone.
This end was not detected as connected by the IsDangling method
2019-06-28 15:27:01 +02:00
Jeff Young b8fff99e68 Hook up zone-connection controls in Edit Footprint dialog.
Fixes: lp:1834629
* https://bugs.launchpad.net/kicad/+bug/1834629
2019-06-28 12:26:28 +01:00
Ian McInerney 3b038feae0 Cleanup cmake python dependency handling to catch errors
* Changed the KICAD_SCRIPTING flag to be a global disable, so it
  will disable all other scripting flags when set to OFF
* Added version testing with the wxPython flags to ensure the
  proper version is found for the flags provided

(cherry picked from commit 42e14b5a4e)
2019-06-27 13:41:55 -04:00
jean-pierre charras 032bda223e Gerber drill file: Modify a aperture attribute for oblong holes (slots).
Oblong holes (slots) use now a aperture attribute similar to round holes.
(The previous attribute "slot" is now deprecated)
However they have a specific aperture, and a comment is added in drill files for these apertures.
2019-06-26 17:53:09 +02:00
Jeff Young b16d4d18e0 Don't select items on inactive layers in high-contrast mode.
Fixes: lp:1833870
* https://bugs.launchpad.net/kicad/+bug/1833870
2019-06-26 01:18:59 +01:00
Wayne Stambaugh df3a57dcda Symbol and footprint library table editor fix.
Prevent the symbol and footprint library table editors from substituting
the current project path (${KIPRJMOD}) when adding libraries to the global
library table.  This will almost assuredly fail when opening a different
project.  We still allow users to manually use ${KIPRJMOD} in global table
paths under the assumption that if they are typing this in then they most
likely understand environment variable substitution.

Fixes lp:1830694

https://bugs.launchpad.net/kicad/+bug/1830694

(cherry picked from commit 288982b15d)
2019-06-25 08:46:27 -04:00
Tomasz Włostowski 3bf7ab910f TestSegmentHit: add corner case for null segment (start == end)
Fixes: lp:1833059
* https://bugs.launchpad.net/kicad/+bug/1833059

(cherry picked from commit 6180687bbd)
2019-06-25 08:45:27 -04:00
Seth Hillbrand e8ce0ba6ef pcbnew: Avoid wxassert in message
wxstring::Printf() needs size_t cast to acceptable type or it gives an
assertion in debug mode.
2019-06-24 09:42:06 -07:00
Wayne Stambaugh d8fff5c820 Footprint library nickname comparison fixes.
Footprint library nicknames are case sensitive but the comparison for
the library tree control was case insensitive.

Also make the footprint name comparisons case sensitive as well.  While
not strictly necessary, the plan is to start using the name defined in
the footprint file instead of the file name which will allow for case
sensitivity.

Fixes lp:1833701

https://bugs.launchpad.net/kicad/+bug/1833701
2019-06-24 08:00:21 -04:00
Seth Hillbrand aa9897d932 Fix bug in tesselation
When we hit a self-intersection, we need to be careful that we don't
lose the stop vertex.

Fixes: lp:1833819
* https://bugs.launchpad.net/kicad/+bug/1833819

(cherry picked from commit 6d60b98dc8)
2019-06-23 20:56:29 -07:00
Seth Hillbrand f265a52c96 Enforce build order with qa system
The QA objects link to the direct kiface objects, which creates a second
dependency on the generated lexer files.  To ensure that the primary
apps are finished building them in a (potentially) different thread, we
set a false dependency on the final build product in the qa CMake.

Fixes: lp:1833851
* https://bugs.launchpad.net/kicad/+bug/1833851

(cherry picked from commit 172542cfc4)
2019-06-23 12:53:19 -07:00
Jeff Young f214cfae12 Don't try to show sub-dialog in OnActivate(). High Sierra asserts.
Fixes: lp:1832635
* https://bugs.launchpad.net/kicad/+bug/1832635
2019-06-23 15:39:05 +01:00
Seth Hillbrand febc8cd6aa pcbnew: Ensure save dialog with zones
Fixes: lp:1833748
* https://bugs.launchpad.net/kicad/+bug/1833748
2019-06-22 08:45:00 -07:00
Seth Hillbrand 463e061740 Clear non-copper edge rounding
Non-copper zones do not have a fillet/chamfer option, so we need to
clear it before the zone tool uses the last-used option.

Fixes: lp:1833672
* https://bugs.launchpad.net/kicad/+bug/1833672
2019-06-22 08:25:38 -07:00
Ian McInerney d80759efb8 cvpcb: Implement delete/cut/copy/paste for individual associations
Fixes: lp:1794883
* https://bugs.launchpad.net/kicad/+bug/1794883
2019-06-21 09:58:53 -04:00
Ian McInerney 1d66aad4df cvpcb: Allow the escape key to close the window
Fixes: lp:1830483
* https://bugs.launchpad.net/kicad/+bug/1830483
2019-06-21 09:22:51 -04:00
Seth Hillbrand f5284ced54 Allow null path in 3d model
This allows a setting where the path is not one of the options.  This
permits the user to select once to go to any path option (rather than
off the current and then back to currect) when the filetree doesn't
match the dropdown.  This also selects the drop down item if it matches
the tree.
2019-06-20 20:10:25 -07:00
Ian McInerney c951ca6f47 cvpcb: Added library location to status bar
Fixes: lp:1782805
* https://bugs.launchpad.net/kicad/+bug/1782805
2019-06-20 16:20:15 -04:00
Seth Hillbrand f25ae373bb Fixup previous move commit
The previous commit missed a case where the number was so large that it
overflowed the integer invalidating the comparison.  This protects
against that case by using floating point comparison.
2019-06-20 06:46:41 -07:00
Seth Hillbrand 845833e8fd pcbnew: Enforce maximum movement in Move Exact
This checks the movement against a maximum value that would place the
selection outside of the valid area for the footprint or board.

Fixes: lp:1833478
* https://bugs.launchpad.net/kicad/+bug/1833478
2019-06-20 06:29:53 -07:00
jean-pierre charras f0ac61a8fd Eeschema: minor fix for root sheet plot file name.
Fixes: lp:1833487
https://bugs.launchpad.net/kicad/+bug/1833487
2019-06-20 13:41:04 +02:00
Seth Hillbrand 8f7278e34f Eeschema: Normalize layer ordering between plot and screen
Fixes: lp:1833428
* https://bugs.launchpad.net/kicad/+bug/1833428
2019-06-19 10:49:28 -07:00
Seth Hillbrand b124599de3 Don't skip handled events in GTK
Now that our tool framework handles the hotkeys, we need to skip the
passed handling work-around for actions that are already handled in the
event.

Fixes: lp:1832604
* https://bugs.launchpad.net/kicad/+bug/1832604

(cherry picked from commit b876309999)

Fixes: lp:1819210
* https://bugs.launchpad.net/kicad/+bug/1819210
2019-06-18 22:06:10 -07:00
Seth Hillbrand 697234dd51 eeschema: Insert junctions when repeating
Fixes: lp:1832253
* https://bugs.launchpad.net/kicad/+bug/1832253
2019-06-18 19:38:13 -07:00
Seth Hillbrand ba97494d6f Update toolbar to get new icon/tooltip
After a save-as the footprint belongs to the library, we need to refresh
the toolbar to get the correct icon.

Fixes: lp:1826889
* https://bugs.launchpad.net/kicad/+bug/1826889
2019-06-18 19:24:47 -07:00
Jeff Young 1996fba8a6 Check for a tree selection before checking it against the board item.
Fixes: lp:1833295
* https://bugs.launchpad.net/kicad/+bug/1833295
2019-06-19 00:11:23 +01:00
Wayne Stambaugh a6bbe907ee Set about dialog name for 3D viewer frame.
(cherry picked from commit 2f2c358aef)
2019-06-18 15:32:09 -04:00
Wayne Stambaugh 43579f4c02 Minor library identifier validator change.
Use the wxTextValidator style flag to allow the user to clear the library
identifier string.  Use wxTextValidator::SetStyle( wxFILTER_EMPTY ) to
prevent empty library identifier strings which is the current behavior.

(cherry picked from commit 9f9e87f11f)
2019-06-18 12:16:51 -04:00
Seth Hillbrand 909a25c147 pcbnew: Correct polygon flipping in custom pads
Custom pads are referenced to the anchor pad 0-point, so flipping the
polygon should be about 0 and not the flip point.

Fixes: lp:1831311
* https://bugs.launchpad.net/kicad/+bug/1831311
2019-06-17 15:26:56 -07:00
Wayne Stambaugh aa3aafc4ff Eeschema: fix sheet plotting bug.
Prefix the sheet name with "Sheet: " and the sheet file name with "File: "
when plotting so that it matches the display sheet rendering.

Improve the root sheet plot file name.

Fixes lp:1832081

https://bugs.launchpad.net/kicad/+bug/1832081
(cherry picked from commit 7235da0979)
2019-06-17 17:02:21 -04:00
Seth Hillbrand b32439a694 Plotting: Handle mask transparency
This handles images with transparent colors by mapping the transparent
color to white.  This only works when plotted into the background.
2019-06-17 13:27:58 -07:00
Seth Hillbrand ddbc25077c Eeschema: Plot in same order as drawing
This ensures the junctions are on top and the bitmaps are on bottom
2019-06-17 13:27:11 -07:00
Seth Hillbrand b075886b19 DC printing: Place worksheet behind schematic
And place bitmaps behind other items.  This ensures they are drawn in
the background of the page rather than covering schematic elements.

This also hacks around the buggy wxPostScriptDC implementation that
resets the page to print an image.

Fixes: lp:1819934
* https://bugs.launchpad.net/kicad/+bug/1819934
2019-06-17 13:03:00 -07:00
Wayne Stambaugh eae999a85a Eeschema: allow empty field strings in field table editor.
The grid apply code was always preventing empty fields.  Change this the
broken behavior to allow any field to be empty except the reference and
value fields.

Fixes lp:1832722

https://bugs.launchpad.net/kicad/+bug/1832722
(cherry picked from commit d74ec1a1b2)
2019-06-17 15:06:27 -04:00
Seth Hillbrand 77f0799750 Print bitmaps using BW setting
When selecting the "Print in B&W", all items on the schematic should be
printed using black and white.  This converts the embedded images
greyscale before outputting to the printer
2019-06-17 09:54:52 -07:00
jean-pierre charras 8de93ad8b4 Eeschema: fix incorrect size of junctions on screen.
Fixes: lp:1831931
https://bugs.launchpad.net/kicad/+bug/1831931
2019-06-17 18:08:44 +02:00
Ian McInerney b377b5bbed pcbnew: Fix invalid hotkeys 2019-06-17 08:11:01 -04:00
Seth Hillbrand 75b5324762 Eeschema: Allow junction dots to be hidden
Drawing junction dots at the line width allows users who do not like
them in their schematics to avoid having them drawn.
2019-06-17 04:48:10 -07:00
Wayne Stambaugh 610d200e8a Fix spelling error in symbol library table warning string.
(cherry picked from commit be8fe3884f)
2019-06-16 12:28:56 -04:00
Wayne Stambaugh 8002692f3e CvPcb: fix save changes dialog layout issue.
DIALOG_EXIT was not being laid out correctly after setting the dialog
message.  Rather than fix our custom DIALOG_EXIT, wxMessageDialog and
wxRichMessageDialog were substituted as direct replacements for all
of the variants of DIALOG_EXIT.  This make message dialogs appear more
consistent because wxMessageDialog uses the default platform message
dialog and wxRichMessageDialog uses the default platform rich message
dialog on windows.

Remove DIALOG_EXIT_BASE as it is no longer required.

Fixes lp:1832899

https://bugs.launchpad.net/kicad/+bug/1832899

(cherry picked from commit 3f665318f4ab5c02b7d3c29b5233a273fdac2e4e)
2019-06-16 12:28:35 -04:00
Seth Hillbrand 9496b57b01 tool_mgr: Don't invalidate our own iterators
Re-arranging the stack will invalidate the iterator that is removed and
inserted (begin()).  Because this is not a threaded operation, we can
only do it to ourselves, so check that the operation isn't a NOP before
performing.

Fixes: lp:1832930
* https://bugs.launchpad.net/kicad/+bug/1832930

(cherry picked from commit 552815d486)
2019-06-15 17:49:52 -07:00
jean-pierre charras a5cd5844ec Fix invalid wxImageList build.
Fixes: lp:1832905
https://bugs.launchpad.net/kicad/+bug/1832905
2019-06-15 16:08:07 +02:00
Ian McInerney da16b479a0 Make DXF monochrome output only contain Black layer
Fixes: lp:1832359
* https://bugs.launchpad.net/kicad/+bug/1832359

(cherry picked from commit dc56678289)
2019-06-13 16:10:17 -07:00
Ian McInerney 44f1059000 Allow DXF to be exported in either inches or millimeters
Fixes: lp:1832188
* https://bugs.launchpad.net/kicad/+bug/1832188

(cherry picked from commit d5f680ecd2)
2019-06-13 16:10:12 -07:00
Ian McInerney cf4b41f7d9 pcbnew: Update plot dialog to contain a unit selector for DXF
(cherry picked from commit b2c848579a)
2019-06-13 16:10:03 -07:00
Seth Hillbrand a84ca5b147 cmake: Further petting dependencies
eeschema cpp files consume generated header files that have targets in
the common directory, so no dependencies get created from eeschema.  We
add the dependencies in common to force the setting through libraries.

Fixes: lp:1831643
* https://bugs.launchpad.net/kicad/+bug/1831643
2019-06-13 16:09:45 -07:00
Ian McInerney 71f5f96e64 Remove help from F1 key and move it to an action
Create a new action in pcbnew, gerbview and the footprint viewer/
editor to display the help documentation. Disconnect the wxID_HELP
event from the window so that it no longer conflicts with the zoom
action.

Fixes: lp:1822041
* https://bugs.launchpad.net/kicad/+bug/1822041
2019-06-13 14:11:24 -04:00
Ian McInerney 2aa8e444ee Added hotkey validity checking to the preferences menu 2019-06-13 13:53:04 -04:00
Steven A. Falco cfa187f477 Show the current grid setting. 2019-06-13 12:14:41 -04:00
Wayne Stambaugh 1ed411e431 LibEdit: fix library tree refresh issue when library is removed.
A bug in LIB_MANAGER::LibraryExists() prevented a library removed from
the symbol library table from being removed from the tree view.  Add the
proper check to SYMBOL_TREE_SYNCHRONIZING_ADAPTER::Sync().

This exposed another issue with synchronization between the library
table editor and the tree view which could lead to orphaned library
modifications and/or a segfault when the currently selected library was
removed from the symbol library table.  Give the user a chance to save
or revert any changes before allowing changes to the symbol library
table.

Fixes lp:1821691

https://bugs.launchpad.net/kicad/+bug/1821691

(cherry picked from commit 028973d182)
2019-06-13 08:59:26 -04:00
Seppe Stas 9233ae97d0 Set KiCad version in MacOS apps
Uses CMake's configure_file function [1] to automaticaly set the
CFBundleShortVersionString [2] value in every app's Info.plist file.

Also updates the CFBundleLongVersionString and CFBundleVersion with the
extended KiCad Version

[1]: https://cmake.org/cmake/help/latest/command/configure_file.html
[2]: https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring

(cherry picked from commit 455ee4c08c)
2019-06-12 14:12:01 -07:00
Seth Hillbrand 0ee38653f7 Fix default User Template location
When we assign a string to the wxFilename, it takes the last section as
the filename (unless there is a trailing '/').  So on Linux, we got
/home/user for the Documents dir and /home/ was the directory while
'user' was the filename.  Appending directories 'kicad/templates' made
the final directory '/home/kicad/templates'.  Forcing this to be a
directory restores correct behavior.
2019-06-11 13:46:10 -07:00
Seth Hillbrand df89b5bf8a eeschema: Don't extend the block when finalizing action
The block draw function is called during the mouse capture callback.  It
shouldn't be called after the block size is finalized.

Fixes: lp:1832289
* https://bugs.launchpad.net/kicad/+bug/1832289
2019-06-11 12:17:25 -07:00
Seth Hillbrand cca4037fec CMake: Another go at linear dependencies
This simplifies the linear dependencies for custom targets.  Should be
single shot for make this time.

Fixes: lp:1831643
* https://bugs.launchpad.net/kicad/+bug/1831643

(cherry picked from commit 720889edd0)
2019-06-10 14:55:01 -07:00
jean-pierre charras e015da8d95 Add a search path to allow find ngspice include dir on some msys2 installs 2019-06-10 20:42:21 +02:00
jean-pierre charras 4ceb186251 Eeschema: fix incorrect saving in prj config on the default netlist format. It was not always saved, and this was not the default, but the last used format. 2019-06-10 20:37:34 +02:00
Seth Hillbrand 370109b868 Eagle: Fix stacked NC pin import
Since Eagle does not connect stacked NC pins but KiCad will if the pins
are coincident, we choose to only import the first of the stacked NC
pins.  While this creates symbols that are slightly different in pin
count from the Eagle version, it keeps the schematic and netlist
functionally correct relative to the Eagle version.

Fixes: lp:1821319
* https://bugs.launchpad.net/kicad/+bug/1821319
2019-06-09 17:02:46 -07:00
Seth Hillbrand 3b3165ad51 pcbnew: Allow DRC violations when marked
We shouldn't consider any obstacles when we are routing in DRC violation
mode.

Fixes: lp:1826723
* https://bugs.launchpad.net/kicad/+bug/1826723
2019-06-09 13:00:13 -07:00
Seth Hillbrand 98e68cd66a Adding MIT license
The tinyspline library is under MIT, so needs to be included in our
license bundle.
2019-06-09 08:38:54 -07:00
jean-pierre charras 407301a28c Fix issue in cairo_gal when drawing a 360 deg arc (in fact a circle). It was due to a angle normalization between -360 and 360 degrees. So, in arcs, if the start angle and end angle diff is n*360 deg, this normalization gives start angle = end angle. The fix forces end angle = start angle+360deg in this case.
Fixes: lp:1832096
https://bugs.launchpad.net/kicad/+bug/1832096
2019-06-09 11:09:43 +02:00
Seth Hillbrand 5ce0e7265b modedit: Clear undo when importing
Importing a footprint is creating a new board.  Undo breaks here as we
don't maintain undo/redo across boards.

Fixes: lp:1832107
* https://bugs.launchpad.net/kicad/+bug/1832107
2019-06-08 13:05:02 -07:00
Seth Hillbrand f1704fd61a bitmap2component: Fix logic for alpha mask
For POTRACE, black is the foreground and white is the background.  We
should keep the convention by requiring the pixin to be less than the
black threshhold as well as the alpha to be at least the alpha
threshhold.

Fixes: lp:1821563
* https://bugs.launchpad.net/kicad/+bug/1821563
2019-06-08 12:03:48 -07:00
Seth Hillbrand 35e87128f5 pcbnew: Ensure cursor remains set during tool activity
Mouse capture end is called by some actions such as save board.  This
resets the cursor image but doesn't change the current tool.  Resetting
the cursor image during action prevents this.
2019-06-08 10:23:38 -07:00
Seth Hillbrand dd93f89931 Import Vector Dialog formatting
This standardizes the import vector graphics file dialog to use the
sbSizer titles instead of bold+lines.  Tooltip changes will be in the
next change as we don't change strings for bugfix releases and this
commit is targeted for 5.1.3

Fixes: lp:1823462
* https://bugs.launchpad.net/kicad/+bug/1823462

(cherry picked from commit f7550940ee)
2019-06-08 09:47:29 -07:00
Seth Hillbrand fb85612f81 eagle: Strip newlines from description
Eeschema old format is line-terminated so the newlines in descriptions
will break the schematic file if saved.

Fixes: lp:1829707
* https://bugs.launchpad.net/kicad/+bug/1829707
2019-06-07 22:08:06 -07:00
Seth Hillbrand 966173c129 pcbnew: Don't reset triangular points for intersection
We prevent the creation of invalid polygons by keeping the converging
lines from intersecting.  This test doesn't make sense for triangular
polygons as they always intersect and we want to allow them to move
outside of the singular point.

Fixes: lp:1831481
* https://bugs.launchpad.net/kicad/+bug/1831481
2019-06-07 21:35:03 -07:00
jean-pierre charras 55757039fa Custom pads: fix a bug when plotting the custom shape. This bug was seen only with some shapes, not all, and only for layers having a negative margin.
Fixes: lp:1831941
https://bugs.launchpad.net/kicad/+bug/
2019-06-07 10:51:43 +02:00
jean-pierre charras 1113e18c40 Fix incorrect initialization of some menuitems IDs.
Although is is currently working, it is a potential issue.
2019-06-06 08:01:24 +02:00
Jon Evans 02947345e8 Mathplot: properly set foreground color when saving screenshots
Fixes: lp:1810914
* https://bugs.launchpad.net/kicad/+bug/1810914

(cherry picked from commit 27a5ed1a9f)
2019-06-05 22:44:18 -04:00
Seth Hillbrand 63f18f0b03 CMake: Handle custom_target indirection
Building custom targets that depend on custom commands such as our
keyword lexer requires two layers of indirection to pick up changes
properly and not overwrite the same file in parallel builds.

Fixes: lp:1831643
* https://bugs.launchpad.net/kicad/+bug/1831643

(cherry picked from commit c6af38477d)
2019-06-05 13:10:00 -07:00
Jeff Young cd6da987cc Make sure the current desc is shown for parts being edited.
Fixes: lp:1820298
* https://bugs.launchpad.net/kicad/+bug/1820298

(cherry picked from commit 7c337ec45d)
2019-06-04 16:30:59 +01:00
Ian McInerney 006d7ddd31 pcbnew: Add context menu for measure tool
Fixes: lp:1831063
* https://bugs.launchpad.net/kicad/+bug/1831063
2019-06-02 07:57:41 -07:00
Ian McInerney 81842fc9d0 eeschema: Make symbol editor cursor track crosshairs with arrow keys
Fixes: lp:1829280
* https://bugs.launchpad.net/kicad/+bug/1829280
2019-05-31 07:47:18 -04:00
Ian McInerney ec9e0b2086 pcbnew: Fix export of edge.cuts layer to STEP format
Fixes: lp:1820841
* https://bugs.launchpad.net/kicad/+bug/1820841

(cherry picked from commit 55261eb223)
2019-05-29 19:43:16 -07:00
Jon Evans 64b71644bb Zoom to fit: only consider worksheet if there are no other items
(cherry picked from commit 04d6ec7de7e7f90482310311fcee416e8ed6410f)
2019-05-29 20:52:07 -04:00
Seth Hillbrand 1e58b09d96 Don't change the board without user action
Grid and ratsnest visibility are stored in the board file and should not
be changed without the user explicitly modifying them.

In the future, we'll move these settings out of the board file but we
shouldn't cause extra file-churn for flipped bits.

Fixes: lp:1828285
* https://bugs.launchpad.net/kicad/+bug/1828285

(cherry picked from commit e7e20b85b5)
2019-05-29 11:28:28 -07:00
Seth Hillbrand 455136ee50 eeschema: end mouse capture before exiting sheet
The mouse capture has a cleanup associated that we call to cancel the
action.  This prevents issues when trying to copy between hierarchical
sheets.

Fixes: lp:1819278
* https://bugs.launchpad.net/kicad/+bug/1819278
2019-05-28 21:19:21 -07:00
Jon Evans 1058ba6a0f PcbNew: ensure Bezier points are updated before plotting
(cherry picked from commit b060880aacfb5e2ff44dea0000733e835d0b8b2a)
2019-05-29 00:07:22 -04:00
Jon Evans f8c541c0d7 PcbNew: fix Bezier curves not having bounding boxes at startup
(cherry picked from commit 40621de3559ee3993d7193a0faee5d0a777be848)
2019-05-29 00:06:55 -04:00
Ian McInerney b485e78030 gal: Decoupled X and Y grid step sizes
Made the X and Y step sizes for the grid separate in the GAL.

Cleaned up the types inside the DrawGrid functions.

Fixes: lp:1821416
* https://bugs.launchpad.net/kicad/+bug/1821416

(cherry picked from commit 45f10fcff1)
2019-05-28 20:37:07 -07:00
Ian McInerney d8e7892081 pcbnew: Fix reload of python plugins in python 3
Update the reload function call to be python3 compatible along with
simplifying the load function to unify the loading of simple and
complex plugins.

Fixes: lp:1828595
* https://bugs.launchpad.net/kicad/+bug/1828595

(cherry picked from commit 59b729c731)
2019-05-28 17:21:00 -07:00
Wayne Stambaugh 1638c3b1c2 Eeschema: fix broken symbol library links after sheet edit.
Refresh the currently edit sheet screen symbol links when the sheet file
name is changed.

This fix was better than the previous fix as it was the same diff between
the master and 5.1 branches.

https://bugs.launchpad.net/kicad/+bug/1830315

Fixes lp:1830315

(cherry picked from commit 89ada624d3d3b28ad5ee1477b353501d46dae3a2)
2019-05-28 17:29:48 -04:00
Wayne Stambaugh 2d0e92d412 Revert "Eeschema: fix broken symbol library links after sheet edit."
This reverts commit f1a43f4977.
2019-05-28 17:07:46 -04:00
Wayne Stambaugh f1a43f4977 Eeschema: fix broken symbol library links after sheet edit.
Refresh the currently edit sheet screen symbol links when the sheet file
name is changed.

https://bugs.launchpad.net/kicad/+bug/1830315

Fixes lp:1830315
2019-05-28 14:49:02 -04:00
Michael Kavanagh 18f7d0129a Stop PNS router settings from being overwritten when switching modes
Fixes: lp:1824967
* https://bugs.launchpad.net/kicad/+bug/1824967

(cherry picked from commit 27d097a78c)
2019-05-27 16:16:55 -07:00
Jon Evans 356ccd0314 Eeschema: improve simulator behavior for two-source DC analysis
Fixes: lp:1830478
* https://bugs.launchpad.net/kicad/+bug/1830478
2019-05-27 18:13:07 -04:00
Jon Evans 4adf89b40b Improve image alpha handling in PDF and PS plotters
Fixes: lp:1825276
* https://bugs.launchpad.net/kicad/+bug/1825276
2019-05-27 12:35:12 -04:00
Jon Evans eb4aded5d6 PcbNew: Fix ordering of fab and courtyard layers
Fixes: lp:1829511
* https://bugs.launchpad.net/kicad/+bug/1829511
2019-05-27 11:54:43 -04:00
Jon Evans 5230f45658 Prevent unbalanced PTH pad labels from being hidden by drills
Fixes: lp:1829067
* https://bugs.launchpad.net/kicad/+bug/1829067
2019-05-27 11:54:43 -04:00
Seth Hillbrand b4e70e56a6 Eagle: Fix crash when importing Eagle V6
This fixes multiple issues when importing Eagle V6 files.

Crashes occured when arcs of 0-length were found and when parts were
referenced in the schematic that were not found in the library.  This
could happen if the library and schematic were different cases.

Fixes: lp:1830564
* https://bugs.launchpad.net/kicad/+bug/1830564

(cherry picked from commit 0e5cc54ec9)
2019-05-26 20:34:05 -07:00
Jon Evans cb3edf2607 PcbNew: Fix layer alpha overrides being overwritten by color changes
Fixes: lp:1827518
* https://bugs.launchpad.net/kicad/+bug/1827518
2019-05-26 20:20:31 -04:00
Jon Evans 720b26d11e Eeschema: fix worksheet and background color for printing
Fixes: lp:1820611
* https://bugs.launchpad.net/kicad/+bug/1820611
2019-05-26 14:25:57 -04:00
Jon Evans e35be13b23 Eeschema: use worksheet color when plotting
Fixes: lp:1825568
* https://bugs.launchpad.net/kicad/+bug/1825568
2019-05-26 12:21:08 -04:00
Jon Evans ba19d93df9 GerbView: Fix selection of the last two grid settings
Fixes: lp:1827642
* https://bugs.launchpad.net/kicad/+bug/1827642
2019-05-25 17:14:35 -04:00
Jon Evans 5d1dcb4387 GerbView: properly load worksheet visibility at startup 2019-05-25 16:58:10 -04:00
Jon Evans f101934909 Report actual intersection position for crossing tracks
Fixes: lp:1825588
* https://bugs.launchpad.net/kicad/+bug/1825588
2019-05-25 15:02:06 -04:00
Jon Evans ede2575018 Exclude invisible items from view bounding box for zoom-to-fit
Fixes: lp:1116457
* https://bugs.launchpad.net/kicad/+bug/1116457
2019-05-25 10:44:15 -04:00
Jon Evans fb80ee5a0e Store items changed by connectivity algorithm in undo list
Fixes: lp:1828442
* https://bugs.launchpad.net/kicad/+bug/1828442
2019-05-24 21:55:49 -04:00
Michael Kavanagh 44fc69398c Fix footprint marked as modified when layer visibility changed
Fixes: lp:1830330
* https://bugs.launchpad.net/kicad/+bug/1830330

(cherry picked from commit 741140e4a4)
2019-05-24 16:17:43 -04:00
Wayne Stambaugh c162337cab Pcbnew: Python scripting support clean up.
Always check the return value of PyRun_SimpleString() for errors when a
Python script is run and show an error message rather than fail silently.

Enable Python interpreter I/O redirection in debug builds so that script
string errors will be shown when PyRun_SimpleString() is called.

Do not call PyErr_Print() after a PyRun_SimpleString() call failure.  It
doesn't do anything useful.

Do not call Py_Finalize() after a PyRun_SimpleString() call failure.  It
seems to cause Pcbnew to crash.

(cherry picked from commit 816f6db310)
2019-05-24 08:01:57 -04:00
John Beard 821faaf3c0 Format: add some formatting aliases, improve dev docs
The aliases are easier than calling check_coding.sh manually,
and we already provide an alias file for the fixes alias, so
do the same for these.

(cherry picked from commit 241127788e)
2019-05-23 21:29:36 +01:00
Ian McInerney bf85eb9b4e pcbnew: Fixed listing of 3D libraries in the github wizard
Fixes: lp:1830137
* https://bugs.launchpad.net/kicad/+bug/1830137

(cherry picked from commit 0daf14f9c3)
2019-05-23 09:51:10 -07:00
Seth Hillbrand 691c6614a8 Plotter: Ensure group style is respected in SVG
Graphics Changed is cleared when setting graphics for a group but needs
to be reset when the group ends.

Fixes: lp:1830245
* https://bugs.launchpad.net/kicad/+bug/1830245

(cherry picked from commit 1a56dfe342)
2019-05-23 09:48:38 -07:00
Wayne Stambaugh 6db7cb8937 Symbol Editor: fix datasheet field bug loading old symbol libraries.
This only applies to the root symbol when the datasheet field is not
empty and the datasheet for root symbol alias in the document file is
empty.  Use the root symbol datasheet field value when adding a new
symbol that meets this criteria.

The root symbol datasheet field gets copied to the root symbol alias
datasheet member variable so if the symbol is modified and saved, the
datasheet information is saved in the .dcm file.

https://bugs.launchpad.net/kicad/+bug/1830078

Fixes lp:1830078

(cherry picked from commit c52ff1ca23)
2019-05-23 09:02:21 -04:00
Wayne Stambaugh 6afc572eae Eeschema: fix datasheet field bug loading old symbol libraries.
This only applies to the root symbol when the datasheet field is not
empty and the datasheet for root symbol alias in the document file is
empty.  Use the root symbol datasheet field value when adding a new
symbol that meets this criteria.

https://bugs.launchpad.net/kicad/+bug/1830083

Fixes lp:1830083

(cherry picked from commit 300f5cb082)
2019-05-23 07:35:10 -04:00
Michael Kavanagh 2a932a2176 Allow setting cursor and aux items colour in footprint editor
Fixes: lp:1829850
* https://bugs.launchpad.net/kicad/+bug/1829850
2019-05-22 15:11:20 -04:00
Seth Hillbrand b2bcde1bfc EAGLE: Correct pcb text orientation
Fixes: lp:1829711
* https://bugs.launchpad.net/kicad/+bug/1829711

(cherry picked from commit 1181b9f9b4)
2019-05-22 10:38:16 -07:00
Seth Hillbrand ec6fd23636 EAGLE: Prevent numeric-only component references
KiCad does not allow references to be numeric only.  This prefixes such
references with "UNK" to note that the reference designator type is
unknown.

(cherry picked from commit a62a89eac3)
2019-05-22 10:38:16 -07:00
Seth Hillbrand 6f34f95c52 Allow squared inflation and inflate Eagle Zones
Sometimes we want to inflate a polygon without adding rounded edges.
This add the option using the jtMiter setting.

This is used in the Eagle parser to expand the Eagle zones for KiCad.
Eagle Zones are drawn on the polygon edge, so they extend out from the
outline.  KiCad zones are drawn inside the polygon.  We need to both
increase the zone size and decrease the minimum pen width to account for
this.

Fixes: lp:1817312
* https://bugs.launchpad.net/kicad/+bug/1817312

(cherry picked from commit 490c805319)
2019-05-22 10:38:16 -07:00
Seth Hillbrand 94e5b36279 pcbnew: Allow adding SHAPE_LINE_CHAIN to zones
(cherry picked from commit bf0a466642)
2019-05-22 10:38:16 -07:00
Seth Hillbrand f0ce4d6336 eagle: Use width on imported lines if available
If not, use the current board design settings for line thickness based
on the board layer.

(cherry picked from commit c80e3e0ffc)
2019-05-22 10:33:24 -07:00
Seth Hillbrand d06b42b917 Eagle: Allow directory creation when importing
The DD_MUST_EXIST flag prevents users from creating a new directory for
their imported eagle project.  This is a UX annoyance.

(cherry picked from commit 9992839c78)
2019-05-22 10:33:09 -07:00
jean-pierre charras 764986a9b0 Fix a compil issue 2019-05-22 18:35:58 +02:00
jean-pierre charras c4efa95b4a * Eeschema: Ensure axis are always drawn in libedit and viewlib
(From master branch)
2019-05-22 17:56:08 +02:00
Wayne Stambaugh 5a655779d7 Eeschema: fix broken cursor after mouse wheel pan.
Fixes lp:1827787

https://bugs.launchpad.net/kicad/+bug/1827787
2019-05-21 14:21:53 -04:00
Wayne Stambaugh 0403437ad0 Eeschema: replace invalid characters when converting from text to label.
Fixes lp:1829664

https://bugs.launchpad.net/kicad/+bug/1829664
2019-05-20 14:49:49 -04:00
jean-pierre charras b62f94f5c2 Pcbnew: release the lock file if a board was loaded, and when clearing the board currently edited. When the board is cleared, the previous loaded board is no longer in edit. 2019-05-20 18:38:03 +02:00
jean-pierre charras daf09ed9fe Pcbnew: fix a (minor) lock file issue: the lock was too early set. If the file was (for some reason) not actually loaded, it was locked. Now, the file is locked only if it is actually loaded. 2019-05-20 18:37:49 +02:00
Seth Hillbrand 72794f1416 eagle: Use the "first" tag instead of pin num
Eagle parsing allows pin 1 to be different from the other pins in the
package but this is set by a tag marking the pin as "first" rather than
the actual number of the pin.

Fixes: lp:1829251
* https://bugs.launchpad.net/kicad/+bug/1829251

(cherry picked from commit dbc40096db)
2019-05-20 06:03:07 -07:00
Jon Evans b00e20b23f GerbView: fix saving of canvas type and lingering legacy menu item
Fixes: lp:1829647
* https://bugs.launchpad.net/kicad/+bug/1829647
2019-05-19 15:28:27 -04:00
John Beard e99a2181ff Correct Slovenian flag
The symbol was wrong (copied from Slovakian flag) and the
blue colour was not the same as the flag on Wikipedia (which
does admittedly seem contentious, but they seem to have reached
some kind of consensus).

(cherry picked from commit de055031a3)
2019-05-17 21:06:32 +01:00
Seth Hillbrand 65b38e8dcf pcbnew: Check for valid data before deleting
We need to check for valid rows and iterators before removing a 3d model

Fixes: lp:1829337
* https://bugs.launchpad.net/kicad/+bug/1829337

(cherry picked from commit f32c95229e)
2019-05-17 09:36:18 -07:00
Wayne Stambaugh 9b8780a2fd Pcbnew: fix bug in Eagle footprint plugin.
Some how a board object was required to fetch the line width when a
footprint is being parsed.  The problem is that there is no board
defined when loading Eagle footprint libraries so there was a nullptr
segfault as a result.  When there is no board defined, use the default
KiCad layer line widths.

Fixes lp:1829243

https://bugs.launchpad.net/kicad/+bug/1829243

(cherry picked from commit 97166a72f5)
2019-05-17 08:40:05 -04:00
jean-pierre charras 9c0e4cae74 Eeschema: fix incorrect position of fields of a hierarchical sheet when rotated
(From master branch)

Fixes: lp:1829048
https://bugs.launchpad.net/kicad/+bug/1829048
2019-05-17 08:36:09 +02:00
Wayne Stambaugh deb387f54c A better fix for commit d34433a1.
Replace INCREMENTAL_TEXT_CTRL with wxSpinCtrlDouble because it looks
and works better.

Remove INCREMENTAL_TEXT_CTRL header and source files because the only
place they were used was in GAL_OPTIONS_PANEL.

(cherry picked from commit f08d040c02)
2019-05-15 18:19:40 -04:00
Seth Hillbrand 5d5422b4c5 Fix default button option on close
The default is meant to be "Save" but "Discard" was selected due to ID
ordering on creation.  Setting the focus before setting the default
makes the "Save" option the highlighted option that can be selected
immediately by pressing enter.

(cherry picked from commit a0f477cc5f)
2019-05-15 14:55:12 -07:00
Seth Hillbrand 85b8dd8b34 plotter: We we trying to export mm but chose in
Note that the comment in line 142 where the scale factor was set had the
correct value to indicate metric (1) but in the actual boilerplate, we
set imperial (0).  This has been around for 6-8 years, so it would seem
DXF is not our most popular export.

Note, I initially tried to use '1' to specify metric units but this was
not handled by DXF readers (QCAM, Inkscape).  Instead, scaling the page
units to inches properly seems to work.

(cherry picked from commit 0eb391b13f)
2019-05-15 14:55:00 -07:00
Wayne Stambaugh b93d34dff4 Fix GAL display options panel spin button layout on windows.
Fixes lp:1829224

https://bugs.launchpad.net/kicad/+bug/1829224

(cherry picked from commit d34433a1df)
2019-05-15 15:01:00 -04:00
jean-pierre charras e997a7db9a Gerbview: Sync issue between the D Code drop list and the active layer
Fixes: lp:1829234
https://bugs.launchpad.net/kicad/+bug/1829234
2019-05-15 16:28:18 +02:00
Wayne Stambaugh d1a065119e Pcbnew: fix crash when deleting DRC errors from DRC dialog.
Fixes lp:1828726

https://bugs.launchpad.net/kicad/+bug/1828726

(cherry picked from commit a32bb4e9a5)
2019-05-14 18:42:03 -04:00
Mario Luzeiro 1dab468e20 Add some epsilon value to ray dir on orthographic mode
so they will not be zero when viewing the board com the top/bot.
This was causing problems with BBox intersect function that was using
invDir values.

Fixes lp:1828747
https://bugs.launchpad.net/kicad/+bug/1828747
2019-05-14 16:10:54 +02:00
Henner Zeller c5cd0c73a3 Raytracing - a more pleasing way sequencing blocks to render.
(cherry picked from commit 2aea26de1e)
2019-05-14 09:28:55 -04:00
Wayne Stambaugh ae139403e4 Fix library table editor dialog environment variable grid column names.
Fixes lp:1825977

https://bugs.launchpad.net/kicad/+bug/1828459
(cherry picked from commit 6f27ef7f66)
2019-05-14 07:59:22 -04:00
Wayne Stambaugh d3c9154f9a Fix frame name capitalization in all about dialogs.
This is a stop gap fix.  It should be possible to use the wxFrame title
string for this but some of the frame windows have appropriated the title
string for configuration file naming purposes which is less than ideal.

Fixes lp:1825977

https://bugs.launchpad.net/kicad/+bug/1825977
(cherry picked from commit 3c4f8c1bf7)
2019-05-13 16:22:52 -04:00
jean-pierre charras caba60968a Python fp wizards: fix a few issues in qrcode_footprint_wizard.py
Fixes: lp:1828744
https://bugs.launchpad.net/kicad/+bug/1828744
2019-05-13 13:26:08 +02:00
Jeff Young 2e0def8670 Defensive coding that will possibly fix a crash when scrolling through footprints.
Fixes: lp:1828289
* https://bugs.launchpad.net/kicad/+bug/1828289

(cherry picked from commit 717b1d37be)
2019-05-11 23:55:08 +01:00
Martin McNamara 8c3d16a395 PCBnew: Fixes crosshair issue with "Place Text" and "Add Dimension".
When using "Place Text" the crosshair was freezing if cancelled before
placing text.

After the crosshair freezes, the next uses of the "Place Text" or
"Add Dimension" caused the crosshair to jump to the screen location
where the previously the crosshair was frozen.

Cancelling the "Add Dimension" caused the crosshair to jump to the
screen location where the crosshair was when cancelled on the next use
of the "Place Text" or "Add Dimension".

Fixes: lp:1822578
* https://bugs.launchpad.net/kicad/+bug/1822578
2019-05-11 06:54:40 -07:00
jean-pierre charras 3f48531da7 DIALOG_EDIT_COMPONENT_IN_LIBRARY: fix a dialog resize issue (grid not resized). 2019-05-11 10:09:32 +02:00
Mark 128cdca068 Fix for SWIG 4.0.0
(cherry picked from commit 5685174808)
2019-05-10 14:38:26 -04:00
Michael Kavanagh bd997a3900 Add Save As hotkey to footprint editor
Fixes: lp:1828481
* https://bugs.launchpad.net/kicad/+bug/1828481

(cherry picked from commit a3483f44d2)
2019-05-10 15:39:33 +01:00
Wayne Stambaugh 8e93eda449 Eeschema: fix corrupted schematic and symbol library files.
Prevent user from pasting text with carriage return and/or line feed
characters in field value edit control in the schematic symbol and symbol
library properties dialogs.

Make all objects derived from GRID_CELL_TEXT_BUTTON use validators
correctly.

Add validators to FIELDS_GRID_TABLE object for field values other than
the mandatory fields.

Create a validator to check that a string is a valid LIB_ID.

Fixes lp:1828214

https://bugs.launchpad.net/kicad/+bug/1828214
(cherry picked from commit ae54f34392)
2019-05-10 09:16:38 -04:00
John Beard a6674ecd56 Pcbnew: remove SVG from menu text
The SVG importer is an advanced config. It's not supported or
normally available in 5.1, so don't advertise in the menu.

If the advanced config is enabled, the dialog will be able
to import SVG.

This could have been "Import *Vector* Graphics" like in master,
5.1 documentation will probably still say "DXF", so keep consistent.

Fixes: lp:1821571
* https://bugs.launchpad.net/kicad/+bug/1821571
2019-05-10 12:41:29 +01:00
jean-pierre charras 654651856f Custom pads: minor fix in legacy mode related to commit a155289f. 2019-05-09 16:46:13 +02:00
jean-pierre charras c489659a20 Custom pads: fix incorrect shape of masks when the shape is a polygon with holes and the mask margin is < 0. This is mainly the solder paste layer that shows this issue. This is due to the fact SHAPE_POLY_SET::Inflate does not work fine with polygons with linked holes. SHAPE_POLY_SET::InflateWithLinkedHoles it added to fix this issue.
Fixes: lp:1828287
https://bugs.launchpad.net/kicad/+bug/1828287
2019-05-09 16:24:39 +02:00
Wayne Stambaugh 18377e0c9f Developer documentation updates.
Remove version 5 road map since version 5 has been released.

Update version 6 road map to reflect current development goals.

Cleaned out old goals from generic road map in preparation for version
7 development.

Add note to compiling document about building with Boost 1.70 on Windows.

Fix link to Linux coding style policy in KiCad Coding Style Guide.

Update tool framework documentation to reflect changes in the tool
framework code.

(cherry picked from commit 3caa4376a5)
2019-05-08 08:39:00 -04:00
jean-pierre charras cebba6c0b9 Cairo GAL: fix incorrect arc position in mirror mode. the previous fix
(c56e540e5d) did not really work.

Fix from master branch.
2019-05-08 14:25:14 +02:00
John Beard 89f9bf545d All: fix horizontal touchpad panning
Commit e10c01aaf didn't work when touchpad panning was enabled.

This commit changes it to only discard horizontal wheel events
when in "scroll mode" rather than "pan mode".

Based on a patch by Adrian Scripcă <benishor@gmail.com>.

Follow-up to fix: lp:1828080
https://bugs.launchpad.net/kicad/+bug/1828080

(cherry picked from commit e6fe220f84)
2019-05-08 11:07:45 +01:00
Adrian Scripca 055d36abd7 All: fix spurious wheel scroll events caused when using modern mice.
Modern mice feature horizontal scrolling capabilities and those end
up being treated by KiCad as regular scroll events causing confusion
among users.

The fix works by discarding the handling of wheel events other than
the ones for the vertical axis.

Fixes: lp:1828080
https://bugs.launchpad.net/kicad/+bug/1828080
(cherry picked from commit e10c01aaff)
2019-05-07 17:36:23 +01:00
John Beard 7bafc5fa8b About dialog: Add mnemonics to the buttons
(cherry picked from commit 4a3add7ac5)
2019-05-07 11:15:13 +01:00
John Beard 6946c0bedb About dialog: update wxFB version
Avoid contaminating wxFB files with version fluff, which hides real
changes in the version history.

(cherry picked from commit cc28fb18fd)
2019-05-07 11:15:13 +01:00
jean-pierre charras bb40f86daa * Eeschema: fix incorrect display of the page number in a complex hierarchy.
When, inside a complex hierarchy, one switch from an instance of a sheet to an other instance of this sheet,
the page number shown in the worksheet was not updated on screen, and the initial number was displayed.

Fix from master branch.
2019-05-07 11:02:05 +02:00
John Beard 89d198659c Format: Default to switch cases on separate lines by default
Currently, the format enforces single lines when possible, but does
not enforce readable column-based alignment (and, moreover, *removes*
such manually added alignment:

    switch( m_orientation )
    {
    case PIN_RIGHT: m_orientation = PIN_UP; break;
    case PIN_UP: m_orientation = PIN_LEFT; break;
    }

Change this to multi-line by default:

    switch( m_orientation )
    {
    case PIN_RIGHT:
        m_orientation = PIN_UP;
        break;
    case PIN_UP:
        m_orientation = PIN_LEFT;
        break;
    }

If the developer wishes for column-aligned single-line cases, this
is permitted, but much be done manually:

    switch( m_orientation )
    {
    case PIN_RIGHT: m_orientation = PIN_DOWN;  break;
    case PIN_UP:    m_orientation = PIN_RIGHT; break;
    }

CHANGE: the _clang-format file to reflect this, and add note about
manual override in the dev docs.

(cherry picked from commit 272c045c37)
2019-05-07 09:50:22 +01:00
jean-pierre charras c56e540e5d Cairo GAL: fix incorrect arc position in mirror mode. It happens in print mode and also when the Pcb view is flipped.
Fixes: lp:1824720
https://bugs.launchpad.net/kicad/+bug/1824720

Fixes: lp:1822772
https://bugs.launchpad.net/kicad/+bug/1822772

Fixes: lp:1823147
https://bugs.launchpad.net/kicad/+bug/1823147
2019-05-06 11:30:15 +02:00
Seth Hillbrand d3fd74246f Merge remote-tracking branch 'andrei/pr-gitignore'
(cherry picked from commit 4d776034ca)

This also picks up an additional line from 45aa514591 that keeps
CMakeModules/*.cmake.  The rest of that commit does not merge cleanly.
2019-05-02 10:38:40 -07:00
Wayne Stambaugh 616061a6ca Eeschema: fix broken symbol library links.
Force the symbol library links whenever the symbol library table has been
modified.  This will use the cache as a fallback when a library has been
removed that contains links in the schematic rather than display.

Fix the SCH_COMPONENT symbol resolver when falling back to the cache.  The
resolver was using the LIB_ID ':' notation which was failing.  Replacing
':' with '_' fixed this issue.  This was also an issue when generating the
symbol message panel information.

Convert wxLogDebug to wxLogTrace in symbol resolver code path.  Add new
trace type KICAD_SYM_RESOLVE.

Fixes lp:1821606

https://bugs.launchpad.net/kicad/+bug/1821606
(cherry picked from commit 7d803437e2)
2019-05-02 12:13:30 -04:00
Tomasz Włostowski d94b8b9c0e router: copy m_maxClearance when cloning/branching PNS::NODEs
Fixes: lp:1813328
* https://bugs.launchpad.net/kicad/+bug/1813328

(cherry picked from commit 9e00f48efc)
2019-05-01 11:39:15 +01:00
John Beard 89d39cf8ff Pcbnew: use same null check as eeschema for recently used
When Pcbnew's add footprint browser is run up, it constructs
the recently used list without checking for nulls.

Although the DoAddLibrary call does internally check for
null, it's easier to filter these out before placing into
the vector in the first place.

The same logic in the symbol tree is already handled in the
same way.

(cherry picked from commit 42d20cbd96)
2019-04-29 17:00:42 +01:00
jean-pierre charras 0ba130dbd3 Pcbnew: fix in board editor crash when try to load a footprint from Add footprint tool if the latest loaded footprint was deleted. In this case, the history has a cleared link that created the crash when the dialog tried to select this deleted FootprintEnumerate
Fixes: lp:1826794
https://bugs.launchpad.net/kicad/+bug/1826794
2019-04-29 17:23:27 +02:00
John Beard 434935613c Eeschema: Fix/circumvert GTK3 tree view bug
There is a rendering bug in GTK3, which appears to be
an upstream GTK issue.

This can be worked around by, when filtering, ensuring the
*parent* item of the selected item is visible. This will
not cause the selected item to not be visible, as the selected
item will be the first shown child. So it will be visible, as long
as the list box is greater than a single row high, which it will be
in all practical scenarios.

This is done on all platforms, as it has a beneficial side-effect:
the parent library of the selection is naturally shown to the
user, so they don't need to scroll up to see what library their
current filter selection was in.

Fixes: lp:1804400
* https://bugs.launchpad.net/kicad/+bug/1804400

(cherry picked from commit 10900c918f)
2019-04-28 17:18:09 +01:00
John Beard 454585d3d2 GAL: add some trace to GAL display options config
This can be helpful when tracing where certain configurations
come from (some apps load from other apps' config basenames).

(cherry picked from commit fcc4a84e0e)
2019-04-27 14:58:50 +01:00
John Beard 65a6e341ad Eeschema: Symbol preview widget needs common config for Hi-DPI
Currently, this widget doesn't read the common library settings.
This means it doesn't use the configured DPI scaling or anti-aliasing
settings.

Use the ReadConfig method on the GAL options to fix (rather than
only ReadAppConfig).

Fixes: lp:1825913
* https://bugs.launchpad.net/kicad/+bug/1825913

(cherry picked from commit 33fe9a2761)
2019-04-27 14:58:50 +01:00
John Beard fc933034db Eeschema: fix resizing of pin table and edit symbol dialog
These dialogs had logic to avoid a table re-adjustment unless
the width changed. This was done to avoid spurious resizing
calls under GTK+3. This was commit
13249b723b, fixing bug lp:1817810.

However, by only calling event.Skip() when the width changed,
redraws were inhibited when only the height changed.

Placing the Skip() outside the width-change check fixes this,
and does not re-introduce the lp:1817810 bug (it is the column
adjust call that causes that).

Fixes: lp:1826615
* https://bugs.launchpad.net/kicad/+bug/1826615

(cherry picked from commit eccadd92fb)
2019-04-27 14:12:00 +01:00
John Beard 20c8b094d6 SHAPE_ARC: Fix bug introduced in 5813164d1.
This fixes the bug exposed in the previous commit.
The tests which exposed it now pass and expected failures
removed.

(cherry picked from commit d89d0e6b74)
2019-04-25 23:51:01 +01:00
John Beard 552ddfbdfa SHAPE_ARC: Expose bug introduced by 5813164d1 in tests
The angle needs to be added to the start angle.

Add tests to cover this:

* Check end point is correct
* Check midpoints are within tolerance

This would have prevented the bug fixed in 5813164d1,
as well as the bug fixed in this commit.

As well as failed tests, this manifests when routing across
Edge.Cuts arcs (unless they happen to start at 0 degrees
staritng angle).

Expose as expected failure to prove tests catch it.
Fix to follow in separate commit.

(cherry picked from commit 183f4fe9a5)
2019-04-25 23:51:01 +01:00
Tomasz Włostowski 9743eec3ab SHAPE_ARC: fixed polyline conversion bug introduced in e312e2b286
Fixes: lp:1826278
* https://bugs.launchpad.net/kicad/+bug/1826278

Fixes: lp:1826270
* https://bugs.launchpad.net/kicad/+bug/1826270

(cherry picked from commit 5813164d15)
2019-04-25 23:51:01 +01:00
Michael Kavanagh b3ad1dc26e PL editor: fix delete hotkey behaviour
Fixes: lp:1819419
* https://bugs.launchpad.net/kicad/+bug/1819419
2019-04-25 20:27:10 +02:00
Seth Hillbrand b6c9d4a88c Add missing header to qa
(cherry picked from commit 9c00a7a5c3)
2019-04-24 14:33:28 +01:00
Wayne Stambaugh 25b6ac61cb Begin version 5.1.2 development. 2019-04-22 17:16:51 -04:00
Wayne Stambaugh 9c9252e8a3 Tag release version 5.1.2. 2019-04-22 17:14:54 -04:00
John Beard 3a744ad72f Use old-style boost includes
The Boost::boost style library dependencies don't work
on some CMake versions (couldn't find library -lBoost::boost)

Use ${Boost_INCLUDE_DIRS} in the target_include_dirs() instead.

Cherry-picked (with changes) from: 1a9aa2e92d
2019-04-22 01:10:50 +01:00
jean-pierre charras 554e2a4bce qfn_wizard.py fixes. 2019-04-21 14:08:01 +02:00
Jeff Young 6e8979d8d8 Add try/catch block around writing a new library.
Fixes: lp:1825203
* https://bugs.launchpad.net/kicad/+bug/1825203

(cherry picked from commit 2bcf38d2b6)
2019-04-18 22:02:24 +01:00
jean-pierre charras 583d416640 DIALOG_CONFIGURE_PATHS: do not allow users to define the env var KIPRJMOD It always defines the project path, and should never be defined by users.
Fixes: lp:1824912
https://bugs.launchpad.net/kicad/+bug/1824912
2019-04-17 14:55:14 +02:00
jean-pierre charras 03b50b4f85 BOARD_NETLIST_UPDATER: fix 2 serious issues in dry run (memory leak and incorrect single pad nets deletion) Single pad nets deletion in dry run was incorrect when a new footprint was added, because in dry run it is not actually added, and the single pad nets deletion does not see these new pads, and can (incorrectly) delete some nets. 2019-04-17 14:55:13 +02:00
John Beard 440e135e3a QA: Remove expected failure from fixed tests
Commit 55fcbddde8 fixed a couple of
failures in the SHAPE_POLY_SET tests, so these no longer
need the expected failure markers.

(cherry picked from commit 371149756d)
2019-04-17 11:48:11 +01:00
John Beard ab39f06003 SHAPE_ARC: fix polyline conversion when radius=0
Prevent a divide-by-zero bug in SHAPE_ARC::ConvertToPolyline.

When the radius is zero, just use the initial angle (it makes
no different anyway, the result is the centre point, which is
the start point.

(cherry picked from commit e312e2b286)
2019-04-17 11:29:28 +01:00
John Beard 98f78f534c QA: Test arc to polylines - this has a bug
Add unit test of SHAPE_ARC::ConvertToPolyline.

This function has a bug when the arc is of zero radius. This
test shows the bug, but does not fix it yet.

(cherry picked from commit ce84c19a38)
2019-04-17 11:29:28 +01:00
Jon Evans d18b12c1a3 Hide simulator settings tabs that aren't implemented yet
Calling Hide() is apparently not enough in Windows

(cherry picked from commit 895d4c9e1a)
2019-04-15 23:21:31 -04:00
Simon Richter 6a7b1aa39a List Boost as a dependency for kicad2step
This is not technically correct (the Boost dependency is introduced through
libcommon), but less invasive as it doesn't pull in libcommon on the linker
command line.
2019-04-15 23:43:42 +01:00
Seth Hillbrand c4be74a9d0 eeschema: Prevent invalid '0' element in components
In the component, an m_unit/m_convert element is 1-indexed as opposed to
the library where they are 0-indexed.  The 0-index in the library is
reserved for those elements that are shared across all conversion/unit
whereas it is invalid for the component.

Fixes: lp:1824764
* https://bugs.launchpad.net/kicad/+bug/1824764
2019-04-15 12:32:29 -07:00
John Beard 9092048dbc Kicad2Step: handle quoted layers
More recent Kicad_pcb files have quoted layer names (i.e.
strings, not symbols). The importer in K2S doesn't handle that,
so it chokes on elements like (layer "Edge.Cuts").

Fixes: lp:1824750
* https://bugs.launchpad.net/kicad/+bug/1824750

(cherry picked from commit c135158364)
2019-04-15 15:01:57 +01:00
Wayne Stambaugh bb419f1201 Begin version 5.1.2 development. 2019-04-14 15:36:47 -04:00
Wayne Stambaugh d505fd2b60 Tag release version 5.1.1. 2019-04-14 15:32:40 -04:00
Jon Evans a771e0eccb Set new module parent early enough to allow pad clearance to be shown
Fixes: lp:1824587
* https://bugs.launchpad.net/kicad/+bug/1824587
2019-04-14 14:26:15 -04:00
Jon Evans 593a5181d7 Fix rotation of global and hierarchical labels
Fixes: lp:1824432
* https://bugs.launchpad.net/kicad/+bug/1824432
2019-04-13 17:02:33 -04:00
Jon Evans c29274e760 Fix ngspice nested DC sweep command
Fixes: lp:1824336
* https://bugs.launchpad.net/kicad/+bug/1824336
2019-04-13 16:38:31 -04:00
Jon Evans 216573bf48 Fix ngspice netlisting when net names contain '/'
Fixes: lp:1821502
* https://bugs.launchpad.net/kicad/+bug/1821502
2019-04-13 15:35:00 -04:00
Jon Evans 1c235a5c89 Properly initialize sheets when loading them from ERC dialog
When displaying a sheet from this path, it's possible the sheet will
not have been initialized yet.  Call DisplayCurrentSheet() to make sure
it is initialized, and then call RedrawScreen to update the zoom level.

Fixes: lp:1824362
* https://bugs.launchpad.net/kicad/+bug/1824362
2019-04-13 12:25:06 -04:00
Jon Evans f90049dd9e Veto mouse warping from DRC dialog
Fixes: lp:1824630
* https://bugs.launchpad.net/kicad/+bug/1824630

(cherry picked from commit dec5d80180)
2019-04-13 11:30:21 -04:00
Jeff Young 90787e84bf Allow dialogs to veto mouse-warping when called from context menu.
Fixes: lp:1745731
* https://bugs.launchpad.net/kicad/+bug/1745731

(cherry picked from commit adf3637476)
2019-04-13 11:30:09 -04:00
John Beard c36c80a077 Fix GAL option spin button layout
These need to not be wxEXPAND and to be vertically centred
to match the adjacent text controls.

Fixes: lp:1804461
* https://bugs.launchpad.net/kicad/+bug/1804461

(cherry picked from commit 203019d959)
2019-04-12 23:36:56 +01:00
Jon Evans 227333239f Improve selection behavior of DRC markers in DRC dialog list 2019-04-12 12:58:47 -04:00
John Beard 2d43fcf9ee GAL opts: move config reading into GAL_DISPLAY_OPTIONS
Move repeated GAL config reading routines into GAL_DISPLAY_OPTIONS.
THe app-level config is in here already, do the same for the
common config.

This means that the configs are loaded consistently, which fixes
the symbol-chooser preview window, which previously didn't use the
same config routine as other GAL canvases.

Future work could move these functions to free functions that
act on the public interface of GAL_DISPLAY_OPTIONS to avoid
GAL_DISPLAY_OPTIONS having to know about wxConfig and wxWindow.

Fixes: lp:1824524
* https://bugs.launchpad.net/kicad/+bug/1824524

(cherry picked from commit ab2281d26f)
2019-04-12 16:48:50 +01:00
Jeff Young 3edad56e6b Refocus control after doing our little raise/raise dance.
Fixes: lp:1821451
* https://bugs.launchpad.net/kicad/+bug/1821451

(cherry picked from commit 4020b5689b)
2019-04-12 00:30:50 +01:00
John Beard 4e2d900775 Pcbnew: FOOTPRINT_PREVIEW_PANEL passes reference to local
Previously, the GAL_DISPLAY_OPTIONS object in FOOTPRINT_PREVIEW_PANEL::New
was passed by reference in the ctor, down to EDA_DRAW_PANEL_GAL, which stored
it as a reference. The object in New() then goes out of scope, so the
referencing panel outlives the options.

Fix this by making a copy in a std::unique_ptr of the options, and giving
ownership to the panel.

There is another issue here: when the Pcbnew options are copies, the
OBSERVABLE subscriber list is copied too. This means if the panel called
NotifyChanged() on the options, Pcbnew would get updates, even though a copy
of the options changed. However, the panel doesn't change the options or
notify, so it's OK for now.

(cherry picked from commit 17e88d0944)
2019-04-11 17:14:07 +01:00
Jeff Young 4dae82054e Increase GervView layers to 51.
This also makes its use of LSET consistent with PCBNew.

Fixes: lp:1809019
* https://bugs.launchpad.net/kicad/+bug/1809019

(cherry picked from commit b7c12b238f)
2019-04-10 21:23:29 +01:00
Jeff Young cb5948d3a5 When checking for duplicate aliases look in the dialog not the symbol.
Fixes: lp:1821543
* https://bugs.launchpad.net/kicad/+bug/1821543

(cherry picked from commit e90452d0e2)
2019-04-10 21:23:14 +01:00
jean-pierre charras 9fc7281fab Zone filler: fix missing calculation of filled polygons when fill mode is ZFM::SEGMENTS 2019-04-10 18:13:15 +02:00
Seth Hillbrand bb779b237a 3d-viewer: Refresh raytracing on rotate
(cherry picked from commit 89d2e67e45)
2019-04-09 15:18:48 -07:00
Seth Hillbrand 1294b4fec8 3d-viewer: Force canvas refresh before screenshot
In some linux configurations, the canvas refresh must be posted before
being handled.  Simply requesting the refresh can queue the event,
preventing an up to date GL canvas from being saved.

Fixes: lp:1819536
* https://bugs.launchpad.net/kicad/+bug/1819536

(cherry picked from commit 707e7b4b65)
2019-04-09 14:47:54 -07:00
Seth Hillbrand 0b754562f6 pcbnew: Handle missing footprint wizards
When we do not have any footprint wizards to display, we cannot select
the grid rows.

Fixes: lp:1823608
* https://bugs.launchpad.net/kicad/+bug/1823608

(cherry picked from commit 7cf394e34f)
2019-04-09 12:07:08 -07:00
Jeff Young 15cb032ab7 Readjust Edit Symbol Properties when symbol references changes.
The new reference may contain different numbers of units and/or
different deMorgan conversion settings.

Fixes: lp:1822316
* https://bugs.launchpad.net/kicad/+bug/1822316
2019-04-09 17:02:29 +01:00
jean-pierre charras c85d2fd3bf Pcbnew: fix a serious issue in ZONE_FILLER. 2019-04-09 16:34:38 +02:00
Wayne Stambaugh bc821ff47d Eeschema: fix schematic text object plotting issue.
Save and restore text thickness in SCH_TEXT::Plot() function to prevent
the plotting default thickness value from stepping on the original text
thickness and causing all of the text objects to magically change to bold.

Fixes lp:1823165

https://bugs.launchpad.net/kicad/+bug/1823165
(cherry picked from commit 3d33cba574)
2019-04-09 10:18:08 -04:00
Jeff Young 42d9f42807 Allow no-connects to be dragged.
Fixes: lp:1821342
* https://bugs.launchpad.net/kicad/+bug/1821342

(cherry picked from commit c78c3c8198)
2019-04-09 11:20:03 +01:00
Jeff Young 7ceff4cf5d Trim zone fills to board outline.
Fixes: lp:1820306
* https://bugs.launchpad.net/kicad/+bug/1820306

(cherry picked from commit 52e3a1d7c4)
2019-04-09 11:20:03 +01:00
Jeff Young 4147da312b Adjust justified text for rotation.
Fixes: lp:1823090
* https://bugs.launchpad.net/kicad/+bug/1823090

(cherry picked from commit a81512ca96)
2019-04-09 00:36:17 +01:00
Jeff Young 439891c31f Adjust left- or right-justified text for mirroring.
(cherry picked from commit 97063440bb)
2019-04-09 00:36:06 +01:00
John Beard 322524101d Libeval: consistent formatting for NaN
On some platforms like MSVC, NaN prints as "-nan(ind)". This
is a bit needlessly ugly, so print "NaN" on all platforms
consistently.

This fixes a test failure on MSVC.

(cherry picked from commit dd17f24c04)
2019-04-08 16:29:24 +01:00
John Beard fd698653d9 QA: numeric evaluator: add a context to tests
This allows a failing test to report which case failed more clearly.

Add a quick helper to make an "in -> out" context string.

(cherry picked from commit 3f32dc9a64)
2019-04-08 15:58:59 +01:00
John Beard 8b503a06fa 3D viewer: update icons from common settings
Use the icon scaling logic and call a toolbar rebuild when the
common settings change (echos the handling in Pcbnew and friends).

Remove an unused function.

(cherry picked from commit 8548e69382)
2019-04-08 14:30:26 +01:00
John Beard 4a201df556 3D viewer: use hi-DPI settings for canvases
The 3D viewer also uses OpenGL, so it also needs to
adjust based on DPI scale factors.

This patch moves the 3D viewer common config code solely
within the 3D viewer, and adds handling of the DPI scale. This
also avoids duplicated logic in PCB_BASE_FRAME::CommonSettingsChanged.

For now, as EDA_3D_VIEWER is not included in the Kiway settings
dispatch, still manually invoke the settings update from
PCB_BASE_FRAME.

The PANEL_3D_PREV gets a similar function to read the config, but
it doesn't have a listener for the update, so it's set just once
at dialog init, just like the existing pan settings.

Fixes: lp:1823681
* https://bugs.launchpad.net/kicad/+bug/1823681

(cherry picked from commit 124dd5e59a)
2019-04-08 14:30:26 +01:00
Seth Hillbrand 577b9f478b pcbnew: Show clearance when editing tracks
When requested by display options, we should show the track clearance
when dragging tracks.

Fixes: lp:1818343
* https://bugs.launchpad.net/kicad/+bug/1818343

(cherry picked from commit cf63ae7ae2)
2019-04-07 21:26:06 -07:00
Seth Hillbrand f5a2eb1ab0 pcbnew: Allow click+drag of tracks
This behavior existed in 5.0.x but did not properly exit the edit tool
in 5.1.  This removes stops the edit tool when we begin dragging a track
using the interactive router.

Fixes: lp:1820312
* https://bugs.launchpad.net/kicad/+bug/1820312

(cherry picked from commit c8118e3ce4)
2019-04-07 20:59:38 -07:00
Michael Kavanagh 4379480d4b Change "Switch track width to previous" default hotkey from Ctrl+W to Shift+W
Tiny improvement in consistency.

Fixes lp:1785842
https://bugs.launchpad.net/kicad/+bug/1785842

(cherry picked from commit 27e6f5b9e8)
2019-04-07 10:52:15 -07:00
Seth Hillbrand dfa4afa826 pcbnew: Freeze the netclasses dialog on init
Prevents the size events from firing on Mac when we set up the netclass
panel

Fixes: lp:1819426
* https://bugs.launchpad.net/kicad/+bug/1819426

(cherry picked from commit a300ae105d)
2019-04-07 07:08:35 -07:00
Wayne Stambaugh a533514763 Minor symbol library rescue dialog fixes.
Adjust the sizer proportions slightly to eliminate the reported bug.
This may not be the ideal way to do this and there could be some issues
on other platforms but it does resolve the issue on gtk3.

Fixes lp:1820084

https://bugs.launchpad.net/kicad/+bug/1820084

(cherry picked from commit 615c49315f)
2019-04-06 08:19:06 -04:00
Wayne Stambaugh 952aaef52a Minor drill file dialog improvements.
(cherry picked from commit b6a0bf1142)
2019-04-05 16:49:51 -04:00
Wayne Stambaugh a54016a6f7 Minor footprint position dialog improvements.
(cherry picked from commit dfee7bddd3)
2019-04-05 16:17:00 -04:00
Michael Kavanagh 0c8a95c44b Invert maximum and minimum endpoints on color picker sliders
Put the maximum values at the "top" of the sliders.

Fixes: lp:1823196
* https://bugs.launchpad.net/kicad/+bug/1823196

(cherry picked from commit 1ccef6dc80)
2019-04-05 14:38:48 +01:00
John Beard 403633d21f Regenerate DIALOG_COLOR_PICKER_BASE wxFB files
This avoids the wxFB automatic changes hiding substantive changes
to be made in later commits.

(cherry picked from commit 0f39d4907f)
2019-04-05 14:38:48 +01:00
jean-pierre charras cc6f1d784d DIALOG_COPPER_ZONE: fix bug that prevent to convert a zone filled by segments to a zone filled by solid polygons 2019-04-05 10:21:16 +02:00
Wayne Stambaugh e07ef3be9c Minor schematic formatter fix.
Apparently at some point in KiCad's development, a '~' character was
prefixed to the symbol name to indicate that it was not visible.  The
visibility state is now saved in the name field so remove the prefix.
The parser was kept unchanged.

Fixes lp:1632048

https://bugs.launchpad.net/kicad/+bug/1632048

(cherry picked from commit ee14da3093)
2019-04-04 10:50:23 -04:00
jean-pierre charras f35f534ff4 DIALOG_PAD_PROPERTIES: Fix incorrect calculation of Round Rect Radius Ratio, when inches are selected.
Fix from master branch.
2019-04-04 15:56:06 +02:00
Jeff Young 3899ec136b Use a bigger hammer when refreshing fields in table.
Fixes: lp:1823050
* https://bugs.launchpad.net/kicad/+bug/1823050
2019-04-04 12:27:29 +01:00
Seth Hillbrand 91ee809558 pcbnew: Prevent aux axis after-image
Grid helper in the router tool is persistent, so remember to turn off
the aux axes after setting.

Fixes: lp:1822577
* https://bugs.launchpad.net/kicad/+bug/1822577

(cherry picked from commit 428e7a900b)
2019-04-03 16:27:37 -07:00
jean-pierre charras 4c94e2729f geometry/geometry_utils.cpp: Fix a minimal value (6) to calculate the segments by circle count to approximate a circle.
Use also this minimal value to calculate  the circle to poly correction factor
Also, remove a useless code.

(cherry picked from commit 0d2dd48cad)
2019-04-03 16:25:52 -07:00
Seth Hillbrand 2a5a207148 pcbnew: Update points before refresh
When removing a point from the polygon, the vertex is removed before it
is tested for validity.  If it fails validation, the edit is reverted
and the point count doesn't change, so the view update only modifies the
existing points.  But the revert may also have changed the shared
pointer to the point array, invalidating the view's copy.

Fixes: lp:1821909
* https://bugs.launchpad.net/kicad/+bug/1821909

(cherry picked from commit 940aef77af)
2019-04-03 16:13:20 -07:00
Seth Hillbrand c75bd89d63 GAL: Deal with thick circles
Both Cairo and OpenGL had issues (different, though) with circles that are
thicker in line width than they have radius.  This corrects the OpenGL
implementation (radius is calculated to the outer edge) as well as Cairo
(line width needs to be clamped to twice the radius)

Fixes: lp:1822765
* https://bugs.launchpad.net/kicad/+bug/1822765

(cherry picked from commit db0523626c)
2019-04-03 16:03:49 -07:00
Seth Hillbrand f58844bf8b pcbnew: Allow Missing legacy option
LEGACY is disabled for GTK3, so we may not find the menu item

Fixes: lp:1822877
* https://bugs.launchpad.net/kicad/+bug/1822877

(cherry picked from commit ce254d1061)
2019-04-03 16:03:21 -07:00
Wayne Stambaugh 07ac3499f3 Remove debugging code added in commit d2cb0ca7.
(cherry picked from commit 75366bce74)
2019-04-03 12:20:37 -04:00
Wayne Stambaugh 050b64b822 Pcbnew: fix DXF import line width bug.
There is a circular dependency between the GRAPHICS_IMPORTER object and
the GRAPHICS_IMPORT_PLUGIN object which makes sharing the settings in
the GRAPHICS_IMPORTER unwieldy.  This fix is a ugly hack that resolves
the issue.  The underlying issue will require some major refactoring.

Fixes lp:1821234

https://bugs.launchpad.net/kicad/+bug/1821234

(cherry picked from commit 120ab06db4)
2019-04-03 11:32:30 -04:00
Wayne Stambaugh 43aa94dcfc Pcbnew: fix import graphics dialog issues.
Improve padding, spacing and alignment of dialog layout.

Fix title capitalization.

Make file dialog wildcard string translatable.

Remove fixed initial dialog size to allow sizers to work their magic.

Replace OK button event handler with TransferDataFromWindow.

Remember last line width units between dialog instances and sessions.

Save configuration file settings in a separate group and remove GfxImport
prefix from the entry names.

Add fencing to dialog header file to prevent nested includes.

Fixes lp:1822568

https://bugs.launchpad.net/kicad/+bug/1822568

(cherry picked from commit d2cb0ca75f)
2019-04-03 11:32:09 -04:00
John Beard b2e54a432b QA: Use own unit test headers for eagle test
These include the appropriate "polyfills" for things like
Boost versions.

(cherry picked from commit 20d36c18350fcccb1bee835553a68da8a0c96b0b)
2019-04-02 23:31:33 +01:00
John Beard e766732020 QA: Eagle test: look up test data in the source tree
Also provide a utility function to get this path, and
a way to override at run time to quickly sub in alternative
data.

The test itself is still broken, as this plugin won't accept
a call to Load() without a KiWay.

(cherry picked from commit 88faac309f)
2019-04-02 19:08:26 +01:00
John Beard 3a5e01c44a QA: Enable eeschema tests
Redesignate the eagle test as eeschema tests and build
more like the other unit tests.

Enable as a test in Ctest now that the test executes without
crashing.

The loading of the file with the hardocded part is still
not enabled, as this needs more infrastructure to support it.

(cherry picked from commit 4eb30f6b85)
2019-04-02 19:08:26 +01:00
John Beard d4883da98b Eeschema: construct simulator cursors on demand
Statically constructing wxCursors as used for the probe
and tune cursors crashes the qa_eagle_plugin test
instantly.

Fix this by introducing a new class CURSOR_STORE,
which allows to abstract the platform wierdness of wxCursors
and allow the simulator to laziliy init its own cursors
at runtime.

This code isn't properly tested, as these cursors are never
actually used. However, it does allow the eeschema unit test
to run.

Fixes: lp:1781191
* https://bugs.launchpad.net/kicad/+bug/1781191

(cherry picked from commit 6f1c3f5ef8)
2019-04-02 19:08:26 +01:00
Michael Kavanagh 7cc3e9a16d Add Ctrl+, hotkey to preferences dialog
Also change interactive router settings from Ctrl+, to Ctrl+Shift+,

(cherry picked from commit b0674b8802)
2019-04-02 13:17:37 -04:00
Michael Kavanagh 9ad352d4bd Fix 'hokey' -> 'hotkey' typo
(cherry picked from commit fe6bc411dd)
2019-04-02 13:17:18 -04:00
Seth Hillbrand 031173bc47 pcbnew: Handle old stable translated layers
This inserts a translation map in the layer names so that the old stable
files with Italian/French layer names get updated to the standard
English layer names (instead of not opening).

Fixes: lp:1370575
* https://bugs.launchpad.net/kicad/+bug/1370575

(cherry picked from commit 6f4d1345f3)
2019-04-01 14:25:27 -07:00
Seth Hillbrand 658820a25e pcbnew: Ensure DRC circles have at least 4 points
This prevents invalid outline errors for small circles.

Fixes: lp:1822641
* https://bugs.launchpad.net/kicad/+bug/1822641

(cherry picked from commit 5eb2a33498)
2019-04-01 14:25:27 -07:00
Wayne Stambaugh 17fdce01a9 GerbView: remember last open gerber file dialog wildcard.
This is only for the current GerbView session.  When GerbView is closed,
the last open gerber file dialog wildcard setting is lost.

(cherry picked from commit f20a1314ff)
2019-04-01 12:47:45 -04:00
Jeff Young bc4cc00332 Update description when tree item is in editor.
Fixes: lp:1820298
* https://bugs.launchpad.net/kicad/+bug/1820298
2019-04-01 13:47:40 +01:00
Jeff Young b57e9492b1 Disable alias controls when no alias is selected.
Fixes: lp:1821698
* https://bugs.launchpad.net/kicad/+bug/1821698
2019-04-01 13:47:31 +01:00
Jeff Young 712bdc9d8d Set initial focus to track width / via size.
Fixes: lp:1822177
* https://bugs.launchpad.net/kicad/+bug/1822177
2019-04-01 13:47:22 +01:00
Jeff Young 33a7c95455 Remove angle brackets from indeterminate string.
They don't really help any, and they confuse some users into
thinking they need angle brackets around real values.

Fixes: lp:1821601
* https://bugs.launchpad.net/kicad/+bug/1821601
2019-04-01 13:47:13 +01:00
Jeff Young f054dcc77d Allow save after importing footprint.
Fixes: lp:1819777
* https://bugs.launchpad.net/kicad/+bug/1819777
2019-04-01 13:47:02 +01:00
Jeff Young 95858b77c1 Ignore BRIGHTENED state when printing.
Fixes: lp:1788480
* https://bugs.launchpad.net/kicad/+bug/1788480
2019-04-01 13:46:46 +01:00
Jeff Young 4afbce5ad6 Fixes for importing board setup properties.
Save/restore default netclass.
Read layers back in with correct syntax ('.' between keyword and layer name).
Write layers to project file.
Read/write layer enablement bits.
Don't set solder paste margin min to 0 (most of them are negative).

Fixes: lp:1811990
* https://bugs.launchpad.net/kicad/+bug/1811990
2019-04-01 13:46:33 +01:00
Wayne Stambaugh 93956002ac Tag version 5.1.0-dev. 2019-04-01 13:32:55 +01:00
Wayne Stambaugh 006dd290e9 Revert "appdata.xml: Remove additional license metadata"
This reverts commit 8a7e501fe6.
2019-03-31 14:35:26 -04:00
Michael Kavanagh fb875145aa Read Footprint Library Browser grid settings from Footprint Editor.
Implements commit 3a0dbf48c8 for Footprint Library Browser/Editor.

Fixes: lp:1822401
https://bugs.launchpad.net/kicad/+bug/1822401
(cherry picked from commit a611269975)
2019-03-31 07:07:52 -07:00
jean-pierre charras 77993ced7e Symbol editor, DIALOG_LIB_EDIT_PIN_TABLE: fix crash when trying to delete a pin when the table is empty.
Fixes: lp:1822406
https://bugs.launchpad.net/kicad/+bug/1822406
2019-03-30 09:32:32 +01:00
jean-pierre charras e1f64d6283 Kicad and Gerbview: add .nc and .xnc file ext to files seen as drill files. .nc is an other usual Excellon drill file ext, and .xnc will be soon also in use. 2019-03-30 09:32:32 +01:00
John Beard 2b60ce484e Formatting: prefer a Git config variable to env var
The keeps all the formatting config together in the Git ecosystem
and keeps the config on a per-repo basis, unless the user explicitly
sets it --global.

Keep the old env var behaviour for now for backwards compatibility.

(cherry picked from commit a7270f8c1c)
2019-03-29 15:12:36 +00:00
John Beard a21b336138 Formatting: exclude generated files from git formatting hook
Add a .gitattributes files to provide a place to store file
attributes. Add a custom attribute for files that should be under
KiCad style guidelines.

Exclude generated files from the style enforcement. So far:

* bitmap .cpp files
* wxFormBuilder base classes
* Lemon grammars

It's now trivial to add the 'generated' attribute to any such
file.

Putting this into .gitattributes also means it can be retreived
programmatically, by other scripts, git alaises or on the command
line.

Use the attributes to provide a utility script to show or apply
formatting to controlled files (plain git clang-format won't
pick up our custom git attributes). Add details for the script in
the dev docs.

Also modiify the check-format hook to follow the .gitattributes
and only apply to cached (staged for commit) changes. Then you
won't be stopped committing because of bad formatting in unstaged
changed, or uncontrolled files.

Concept and some aspects of the implementation inspired by
CMake commit d5f39a56 [1].

[1]: https://gitlab.kitware.com/cmake/cmake/commit/d5f39a56a44fe061018c6acc15e1c3aa7337ff54

tool

(cherry picked from commit a69cdf1793)
2019-03-29 15:12:36 +00:00
John Beard 0655280f2c QA: nullptr_t -> std::nullptr_t
This fixes a build failure on some systems.

(cherry picked from commit 49d75e2383)
2019-03-29 12:49:16 +00:00
John Beard 2793578dcb QA: Allow BOOST_CHECKing of nullptr_t
Before Boost 1.64, there was no test logging function
for std::nullptr_t.

Add a logging struct to Boost to deal with this, and some
macros to assist in similar cases. These macros are bit
untidy-looking, but due to GCC bug #56480, we can't use
namespace aliasing to solve this. From Boost 1.64 onwards,
these namespaces are not needed at all.

Remove some code added to work around lack of nullptr printing
in the past.

These macros, and the nullptr printer, can be removed when
the Boost min version is 1.64 or greater.

(cherry picked from commit ad76ebd82a)
2019-03-29 10:11:19 +00:00
Wayne Stambaugh f1a70662c5 Eeschema: do not merge graphical lines with different attributes.
Fixes lp:1821728

https://bugs.launchpad.net/kicad/+bug/1821728

(cherry picked from commit 2447933b54)
2019-03-28 13:47:58 -04:00
Carsten Schoenert 8a7e501fe6 appdata.xml: Remove additional license metadata
The extra field metadata is not really needed nor helpful as various
other additional licenses are used within the KiCad project.
All used licenses are documented with the file LICENSE.README within top
root folder of the source.

(cherry picked from commit e5de787f88)
2019-03-27 14:50:23 -04:00
Carsten Schoenert 86fc2dc2ba Adding license text for CC-BY-SA-4.0 for completeness
As for the other used licenses adding also the license content for the
CC-BY-SA-4.0 license.

(cherry picked from commit 54aed9b17e)
2019-03-27 14:50:05 -04:00
Carsten Schoenert 9cff42b4ed Adding license information for demo files
The demo files are covered by the CC-BY-SA-4.0 license.
Please note some discussion about this on the developers mailing list:

https://lists.launchpad.net/kicad-developers/msg39174.html
(cherry picked from commit 444050c7d5)
2019-03-27 14:49:44 -04:00
John Beard 55546126a1 Clang-format: break after templates
Enforce the following format:

template<>
void function<TYPE>()

Rather than:

template<> void function<TYPE>()

This is the more common format in KiCad (about 8:1) and agrees
with the uncrustify.cfg rules.

(cherry picked from commit 3536840f52)
2019-03-27 14:38:52 +00:00
John Beard 5a11dacd9e Pcbnew: Improve tab traversal in text properties dialog
Tab through the grid vertically, then horizontally, as the fields
are laid out with "related" fields (like the co-ords) vertically.

Also neaten headers.

Fixes: lp:1821887
* https://bugs.launchpad.net/kicad/+bug/1821887

(cherry picked from commit d6b8e9e037)
2019-03-27 14:06:16 +00:00
John Beard bb5873bf20 Pcbnew: Align right margins in text properties dialog
(cherry picked from commit b7017167f0)
2019-03-27 14:06:16 +00:00
John Beard 20eda54349 Pcbnew: update text properties dialog wxFB version
No actual changes, but this keeps the diffs clean(er).

(cherry picked from commit dd3252445d)
2019-03-27 14:06:16 +00:00
Michael Kavanagh c98461f59e Open drill file in gerbview from KiCad manager tree
Fixes lp:1819754
https://bugs.launchpad.net/kicad/+bug/1819754

(cherry picked from commit b681e4a68e)
2019-03-27 09:13:23 -04:00
jean-pierre charras b154c9a5c4 Eeschema: Force time stamp to 32 bits unsigned values, and make it
tolerant to files using 64 bits values. define timestamp_t as uint32_t.

This fix is adapted from master, commit 175a2bc0b (bug fix lp:1821476)
2019-03-27 13:17:54 +01:00
jean-pierre charras 12255e3680 Eeschema: fix incorrect handling of Escape key. Key events do not have to be skipped after they are handled. 2019-03-27 13:17:54 +01:00
John Beard 473c41ddbf Eeschema: internal tidying of field editor ApplyData
Make a few things const (specficially the reference into
m_fieldStore - we should commit to not modifying that in this
function.

Also avoid a couple of needless string copies.

Also explicitly dereference the into a (non-const) reference at the outset.
For the whole if this function, comp is the same object and may not
be null (as it is used unchecked).

(cherry picked from commit edd94ce2d6)
2019-03-27 10:29:36 +00:00
Baranovskiy Konstantin b93382831c Eeschema: place new field near parent component
For now fields created in Fields Editor are placed at
position (0, 0).
Every new field must be placed at the origin of
the parent component.

(cherry picked from commit 11f03c8551)
2019-03-27 10:29:36 +00:00
Michael Kavanagh 5ee61f5ae7 Fix mnemonic typo in pcbnew menubar
(cherry picked from commit bbcea3c98d)
2019-03-26 19:19:11 -04:00
Seth Hillbrand 082bbd49e7 sim: Prevent stepping
Introduced by 416e64a334.  The code
appears to have been stepped on purpose but this would be incorrect for
most applications.  There remains a good deal of cleanup in mathplot
available for the motivated dev.

Fixes: lp:1810311
* https://bugs.launchpad.net/kicad/+bug/1810311

(cherry picked from commit c1c4a0925d)
2019-03-26 14:59:18 -07:00
John Beard 4e2e69c9cb Fix MSYS2 build breakage
wxPlatformInfo::Get() causes a linker error on Msys2.

Fix this by making common link wx explicitly, rather
than implicity via it's dependencies, which cause
wrong-order linker command lines on windows.

(cherry picked from commit aef369f4af)
2019-03-26 10:53:31 +00:00
John Beard 6f78bb6960 Add configuration of Hi-DPI canvas scaling in OpenGL
First, add automatic detection of toolkit DPI scaling options. For now, this
is, in order,

* Check the GDK_SCALE option under GTK+ (users can set this to force the scaling)
* Check the value from WX's GetContentScalingFactor(). This will start to work
  correctly from WX 3.1 and GTK+ 3.10.

Then, add a user-settable override in the main prefs panel, next to the icon
scaling. This is independent of the icon scaling options.

DPI handling is performed in a standalone class, so they can be shared between
the prefs UI and the OpenGL backend easily. Also means Cairo could use the same
interface in future.

Also adjust the OpenGL grid drawing code to use the computed scale factor,
which avoids over-thick grids in scaled environments (the user can manually
thicken the grid if wanted).

Fixes: lp:1797308
* https://bugs.launchpad.net/kicad/+bug/1797308

Cherry-pick of: 567bdd9b9 (master)
2019-03-25 15:16:18 +00:00
jean-pierre charras a00caac789 Gerbview: fix crash when reading a .gbrjob, and when a file given by the .gbrjob is not found. A incorrect gerber image was created, creating crash on exit or when enable the layer view. 2019-03-24 17:40:16 +01:00
Brian Henning 4e8f191f43 Added an include to tell the compiler where to find wxIsdigit 2019-03-24 15:38:59 +01:00
jean-pierre charras b1c5afd72f Drc dialog: make track to copper zones test optional, because it can be really very time consuming 2019-03-24 15:38:59 +01:00
jean-pierre charras aa5a2225e7 Fix incorrect detection of filled zones changes in DRC check.
Commit 6006703798 fixed a crash but broke the filled zones changes detection.
Filled zones were always seen as not up to date due to the fact the filled areas were cleared too early.

The up to date detection is also optimized: the old filled polygons are no longer stored.
Instead of, the MD5_HASH is calculated and stored before clearing the filled polygons.
2019-03-24 15:38:59 +01:00
jean-pierre charras 4c7672b581 Cvpcb: cosmetic enhancement in toolbar: add a text. 2019-03-24 15:38:59 +01:00
Jon Evans 5f9fa05e21 Fix loading of components with convert parameter set to zero
(cherry picked from commit ab74445df4)
2019-03-23 18:58:17 -04:00
Wayne Stambaugh ee92fa51bc Symbol editor: improve tooltip in symbol properties dialog.
Make the "Define as power symbol" checkbox tooltip more descriptive so
the user has a better understanding of enabling this option.

Fixes lp:1804932

https://bugs.launchpad.net/kicad/+bug/1804932

(cherry picked from commit a7c8df5666)
2019-03-20 15:58:11 -04:00
Simon Richter 63b3960120 Update/regenerate pcb_calculator_frame_base.fbp
(cherry picked from commit 4896daaae5)
2019-03-19 15:21:38 -04:00
Simon Richter e5c76ddf3e Fix line endings in pcb_calculator_frame_base.fbp
No text changes

(cherry picked from commit e286ca170d)
2019-03-19 15:21:19 -04:00
Simon Richter 4b07979008 Add a few dielectric values
- Isola FR408
   https://www.isola-group.com/wp-content/uploads/data-sheets/fr408.pdf
 - Isola 370HR
   https://www.isola-group.com/wp-content/uploads/data-sheets/370hr.pdf
 - Rogers RO4003C
   https://www.rogerscorp.com/documents/726/acm/RO4000-Laminates---Data-sheet.pdf
 - Rogers RO4350B
   (as above)

(cherry picked from commit 432e12effd)
2019-03-19 10:38:43 -04:00
Seth Hillbrand 168fa09f5f Unify and correct Autosave functions
Autosave was not working correctly, partly due to different
implementations in eeschema and pcbnew and partly due to a mistaken
refactor at some point during v5 development.  This unifies the expected
autosave prefix to _autosave- for both pcbnew and eeschema.  It also
unifies the expected suffix for the backup files to -bak.

Fixes: lp:1820433
* https://bugs.launchpad.net/kicad/+bug/1820433

(cherry picked from commit 078320e2fb)
2019-03-18 10:27:09 -07:00
Seth Hillbrand 4facd57cb7 libedit: Don't move the field below the last item
There needs to be at least one item below the one we want to move down
in order to allow the action.

Fixes: lp:1820532
* https://bugs.launchpad.net/kicad/+bug/1820532

(cherry picked from commit 0943c176a3)
2019-03-18 10:27:09 -07:00
Wayne Stambaugh e999636048 Symbol editor: fix superfluous dialog display.
Call base object TransferDataFromWindow() to prevent Validate() from
being called twice.  Validation is handled completely under the hood
so there is no need to call Validate() directly.

Fixes lp:1820301

https://bugs.launchpad.net/kicad/+bug/1820301
2019-03-18 11:46:03 -04:00
Seth Hillbrand 5bd769ea40 Remove global library from pspice simulation 2019-03-17 20:56:24 +01:00
jean-pierre charras bd693f97a1 Print on Linux: use 600 DPI instead of the default 72 DPI (noticeable in Pcbnew) 2019-03-17 20:52:42 +01:00
jean-pierre charras af0cb68c1b Eeschema: do not draw dangling symbol (circle) for PIN_NC pin types. These pins are never connected, so a dangling symbol makes no sense.
Fix also a fex minor coding style issues.
2019-03-17 20:52:42 +01:00
jean-pierre charras 761d7fd438 Demo pic_programmer: remove unused schematic library from list. 2019-03-17 08:52:00 +01:00
jean-pierre charras c537e8a892 Eeschema: shows the opened sheet info in title bar.
Fixes: lp:1819564
https://bugs.launchpad.net/kicad/+bug/1819564
2019-03-17 08:52:00 +01:00
jean-pierre charras 702e85cd96 Pcbnew: disable commit 3692c511 on non Windows platforms A zone refill display progress bar is shown when deselecting the zone after geometry changes. However, on Linux, there are some artifact between the progress bar refresh and the board view refresh: the filled areas are incorrectly shown: the insulated islands remain displayed, although they are removed from the actual filled areas list So it is disabled until a fix is found. 2019-03-17 08:52:00 +01:00
Wayne Stambaugh c93e0b6c5e Minor board editor menu fixes.
Correct menu string capitalization.

Remove duplicate mnemonic characters.

Fixes lp:1818906

https://bugs.launchpad.net/kicad/+bug/1818906
2019-03-16 10:37:35 -04:00
Wayne Stambaugh f7b4a20066 Replace isdigit() with wxIsdigit() when testing wxString characters.
This is a continuation of commit 8a03025a.  All known instances of
using isdigit() to test a character in a wxString have been replaced
by wxIsdigit().
2019-03-15 15:54:49 -04:00
Seth Hillbrand 49ac89bfed pcbnew: Don't refresh S_CURVE in bbox()
The bounding box calculation needs to be fast and is threaded in many
places in pcbnew.  We cannot invalidate items (the function is const but
this wasn't caught at compile-time for some reason) when getting the
bbox. This shouldn't be an issue as the m_BezierPoints is rebuilt each
time the curve is updated, so rebuilding during the bbox seems extra.

Fixes: lp:1819984
* https://bugs.launchpad.net/kicad/+bug/1819984

(cherry picked from commit ec24981cc8)
2019-03-14 05:49:30 -07:00
jean-pierre charras 16e62b29f9 Zone fill: display progress bar when refilling a zone after edition.
Previously, refilling a zone after edition was made silently,
thus creating not understandable but very noticeable freeze time for complex zones.

(cherry picked from commit 3692c511d0)
2019-03-14 05:49:30 -07:00
jean-pierre charras b8180b0459 PROF_COUNTER: add a helper method.
(cherry picked from commit 3fc681c1b7)
2019-03-14 05:49:30 -07:00
Seth Hillbrand 37f250b384 pcbnew: Remove fills prior to updates
Removing existing fills will prevent re-drawing invalid polygons before
they are ready.  This seems to happen on Macs more easily due to redraw
timing.

Fixes: lp:1819553
* https://bugs.launchpad.net/kicad/+bug/1819553

(cherry picked from commit 6006703798)
2019-03-11 16:29:02 -07:00
Seth Hillbrand 5685ec525b GAL: Handle negative line widths
When displaying negative line width elements, the outline of the item
should be hidden rather than displayed.

Fixes: lp:1819247
* https://bugs.launchpad.net/kicad/+bug/1819247

(cherry picked from commit c61ec8ee3b)
2019-03-11 12:38:26 -07:00
Seth Hillbrand 5be59ea8dd eeschema: Fix plot line width for negative lines
Negative width lines are used to hide the outline of shapes in eeschema.
Plot should not show these lines.

(cherry picked from commit 94fa734c61)
2019-03-11 12:38:19 -07:00
Seth Hillbrand 5855f2d909 Ensure LIB_ALIAS elements are always drawn
We add LIB_ALIAS to the VIEW rtree when choosing a new symbol or
browsing.  The actual display element may change based on the unit or
demorgan representation but there will only ever be a single one drawn.
This will set the view bbox to maximum to ensure it is always checked
for drawing.

 Related to lp:1796960
 https://bugs.launchpad.net/kicad/+bug/1796960

(cherry picked from commit d25d62295a)
2019-03-10 20:18:12 -07:00
jean-pierre charras 5424223949 Thermal reliefs: fix a corner case that wrongly removes a stub in a thermal shape.
This was due to the stub removal tests if a stub end is outside a solid area to remove it.
There is a corner case: is the stub end is exactly on a solid area outline extra segment
created by Fracture() used in calculations.

The stub removal tests are now made before fracturing.

Fixes: lp:1819317
https://bugs.launchpad.net/kicad/+bug/1819317
(cherry picked from commit b9944e2c06)
2019-03-10 11:50:33 -07:00
Seth Hillbrand de22148b44 Move env var substitution into GetAssociatedDocument
We always want the documents to have their variables replaced when
opening the associated file.

Fixes: lp:1819309
* https://bugs.launchpad.net/kicad/+bug/1819309

(cherry picked from commit 9bfce26ce7)
2019-03-10 10:44:23 -07:00
Wayne Stambaugh 73664e610b Begin version 5.1.1 development. 2019-03-08 13:11:03 -05:00
12237 changed files with 979058 additions and 6110978 deletions
-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'
+2 -3
View File
@@ -1,9 +1,9 @@
# Custom attribute to mark source files using KiCad C++ formatting
[attr]kicad-cpp-source text=auto whitepace=tab-in-indent format.clang-format-kicad
[attr]kicad-cpp-source 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
[attr]kicad-cmake-source whitespace=tab-in-indent
# Custom attribute for auto-generated sources:
# * Do not perform whitespace checking
@@ -18,7 +18,6 @@
*.cmake kicad-cmake-source
*.txt kicad-cmake-source
*.md text=auto
# Compiled bitmap sources
bitmaps_png/cpp_*/*.cpp generated
-2
View File
@@ -1,2 +0,0 @@
community_bridge: kicad
custom: "https://donate.cernandsocietyfoundation.cern/b/my-donation?cid=4&_cv=1"
-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'
+17 -52
View File
@@ -1,16 +1,12 @@
.downloads-by-cmake
.gdb_history
boost_root
/Build
/build
/cmake-build-*
.downloads-by-cmake
Build*
build*
common/fp_lib_table_keywords.cpp
common/drc_rules_keywords.cpp
common/drc_rules_lexer.h
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
@@ -21,20 +17,24 @@ 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/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
CMakeCache.txt
.cache/
auto_renamed_to_cpp
Testing
version.h
config.h
install_manifest.txt
doxygen/out
Documentation/doxygen
Documentation/development/doxygen
*.bak
*.pyc
common/pcb_plot_params_keywords.cpp
@@ -48,12 +48,13 @@ 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
# demo project auxiliary files
# demo project auxillary files
demos/**/*-bak
demos/**/_autosave-*
demos/**/fp-info-cache
@@ -76,9 +77,8 @@ pcbnew/Info.plist
*.png
*.kiface
*.o
*.o.*
*.a
*.a.*
*.cmake
*.orig
*.rej
*.so
@@ -88,45 +88,10 @@ pcbnew/Info.plist
*.patch
# These CMake files are wanted
!cmake/**/*.cmake
!CMakeModules/*.cmake
# Eclipse IDE
.settings/
.project
.cproject
.pydevproject
__pycache__
# Visual Studio
.vs/
.editorconfig
CMakeSettings.json
.vscode/
# Sublime Text
*.sublime-*
# KDevelop
.kdev4/
*.kdev4
# 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*
-48
View File
@@ -1,48 +0,0 @@
stages:
- build
- test
- report
default:
image:
name: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:36
entrypoint: ["/bin/sh", "-c"]
##########################################################################
# 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: []
only:
- merge_requests
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}
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/coverity.yml'
- local: '/.gitlab/linux-metadata-validate.yml'
- local: '/.gitlab/doxygen.yml'
-165
View File
@@ -1,165 +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: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:37
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_SPICE=ON
-DKICAD_BUILD_I18N=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
# 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
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: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:37
extends:
- .unit_test
- .only_code
parallel:
matrix:
# The name of the test without the qa_ prefix
- TEST: [python, common, gerbview, pcbnew, eeschema, kimath, sexpr, kicad2step]
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"
-119
View File
@@ -1,119 +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_SPICE=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]
-47
View File
@@ -1,47 +0,0 @@
##########################################################################
# Build KiCad on Windows and save the results
##########################################################################
win64_build:
stage: build
tags:
- kicad-windows-1809
extends: .only_code
interruptible: false
image: registry.gitlab.com/kicad/kicad-ci/windows-build-image/win1809-msvc:latest
variables:
VCPKG_BINARY_SOURCES: 'nuget,kicad,readwrite'
cache:
key: win64-vcpkg-"$CI_COMMIT_REF_SLUG"
paths:
- build\windows\vcpkg_installed
- .vcpkgCache
only:
- branches@kicad/code/kicad
- tags@kicad/code/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
- nuget.exe sources add -Name kicad -Source "https://nuget.kicad.org:443/v3/index.json"
- nuget.exe setapikey $env:KICAD_NUGET_KEY -Source "https://nuget.kicad.org:443/v3/index.json"
- 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_SPICE=ON `
-DKICAD_BUILD_PNS_DEBUG_TOOL=ON `
-DKICAD_USE_3DCONNEXION=ON `
../../
- 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
-70
View File
@@ -1,70 +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"
tar cfz cov-int.tar.gz cov-int
echo "Submitting scan results"
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 file=@cov-int.tar.gz \
--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:37
only:
refs:
- schedules
variables:
- $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
script:
- *coverity_cache_prep
- cmake
-DCMAKE_BUILD_TYPE=Debug
-DKICAD_STDLIB_LIGHT_DEBUG=ON
-DKICAD_SCRIPTING_WXPYTHON=ON
-DKICAD_SPICE=ON
- coverity/bin/cov-build --dir cov-int make -j8
- *coverity_submit
artifacts:
expire_in: 1 year
expose_as: 'Coverity log'
name: "coverity_log.txt"
paths:
- cov-int/build-log.txt
-18
View File
@@ -1,18 +0,0 @@
build_doxygen_docker:
image: docker:stable
services:
- docker:dind
stage: build
tags:
- 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"
only:
refs:
- schedules
variables:
- $SCHEDULED_JOB_NAME == "doxygen"
-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
-39
View File
@@ -1,39 +0,0 @@
##########################################################################
# Run a validation of the metadata files for Linux
##########################################################################
validate_linux_metadata:
stage: test
needs: []
interruptible: false
# This is the only CI image with the utilities needed for this test
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:37
# 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
only:
refs:
- master
- branches
- merge_requests
- pushes
changes:
# Only run if the resources, its tests, or the translations are updated
- resources/linux/**/*
- qa/resources/linux/**/*
- translation/**/*
except:
- schedules
# 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_SPICE=ON
-DKICAD_BUILD_I18N=ON
../../
- make metadata
- cd ../../
- ./qa/resources/linux/verifyMetadataFiles.sh ./ ./build/linux
-25
View File
@@ -1,25 +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 add 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
# We define this using a before script because GitLab cannot merge variable
# definitions across inheritance (so the variables block from this would disappear)
before_script:
- export BOOST_TEST_LOGGER='JUNIT,all,test_results.${TEST}.xml:HRF,warning'
- export 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. Note that there is a bug with how paths
# are processed in the junit report (https://gitlab.com/gitlab-org/gitlab/-/issues/23835)
# so we can't use a glob and have to list out each hierarchy separately.
artifacts:
reports:
junit:
- build/linux/qa/*/*.xml
- build/linux/qa/*/*/*.xml
+233 -218
View File
@@ -2,8 +2,7 @@
* 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 (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022 CERN
* Copyright (C) 2018 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
@@ -25,11 +24,14 @@
#define GLM_FORCE_RADIANS
#include <mutex>
#include <iostream>
#include <sstream>
#include <fstream>
#include <utility>
#include <iterator>
#include <wx/datetime.h>
#include <wx/dir.h>
#include <wx/filename.h>
#include <wx/log.h>
#include <wx/stdpaths.h>
@@ -41,36 +43,28 @@
#include <boost/uuid/sha1.hpp>
#endif
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include "common.h"
#include "3d_cache.h"
#include "3d_info.h"
#include "3d_plugin_manager.h"
#include "sg/scenegraph.h"
#include "filename_resolver.h"
#include "3d_plugin_manager.h"
#include "plugins/3dapi/ifsg_api.h"
#include <advanced_config.h>
#include <common.h> // For ExpandEnvVarSubstitutions
#include <filename_resolver.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 std::mutex mutex3D_cacheManager;
static wxCriticalSection lock3D_cache;
static bool isSHA1Same( const unsigned char* shaA, const unsigned char* shaB ) noexcept
static bool isSHA1Same( const unsigned char* shaA, const unsigned char* shaB )
{
for( int i = 0; i < 20; ++i )
{
if( shaA[i] != shaB[i] )
return false;
}
return true;
}
@@ -78,7 +72,7 @@ static bool isSHA1Same( const unsigned char* shaA, const unsigned char* shaB ) n
static bool checkTag( const char* aTag, void* aPluginMgrPtr )
{
if( nullptr == aTag || nullptr == aPluginMgrPtr )
if( NULL == aTag || NULL == aPluginMgrPtr )
return false;
S3D_PLUGIN_MANAGER *pp = (S3D_PLUGIN_MANAGER*) aPluginMgrPtr;
@@ -123,60 +117,62 @@ static const wxString sha1ToWXString( const unsigned char* aSHA1Sum )
class S3D_CACHE_ENTRY
{
public:
S3D_CACHE_ENTRY();
~S3D_CACHE_ENTRY();
void SetSHA1( const unsigned char* aSHA1Sum );
const wxString GetCacheBaseName();
wxDateTime modTime; // file modification time
unsigned char sha1sum[20];
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 (a SHA1 digest)
public:
S3D_CACHE_ENTRY();
~S3D_CACHE_ENTRY();
void SetSHA1( const unsigned char* aSHA1Sum );
const wxString GetCacheBaseName( void );
wxDateTime modTime; // file modification time
unsigned char sha1sum[20];
std::string pluginInfo; // PluginName:Version string
SCENEGRAPH* sceneData;
S3DMODEL* renderData;
};
S3D_CACHE_ENTRY::S3D_CACHE_ENTRY()
{
sceneData = nullptr;
renderData = nullptr;
sceneData = NULL;
renderData = NULL;
memset( sha1sum, 0, 20 );
}
S3D_CACHE_ENTRY::~S3D_CACHE_ENTRY()
{
delete sceneData;
if( NULL != sceneData )
delete sceneData;
if( nullptr != renderData )
if( NULL != renderData )
S3D::Destroy3DModel( &renderData );
}
void S3D_CACHE_ENTRY::SetSHA1( const unsigned char* aSHA1Sum )
{
if( nullptr == aSHA1Sum )
if( NULL == aSHA1Sum )
{
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * [BUG] NULL passed for aSHA1Sum" ),
wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * [BUG] NULL passed for aSHA1Sum",
__FILE__, __FUNCTION__, __LINE__ );
return;
}
memcpy( sha1sum, aSHA1Sum, 20 );
return;
}
const wxString S3D_CACHE_ENTRY::GetCacheBaseName()
const wxString S3D_CACHE_ENTRY::GetCacheBaseName( void )
{
if( m_CacheBaseName.empty() )
m_CacheBaseName = sha1ToWXString( sha1sum );
@@ -187,9 +183,11 @@ const wxString S3D_CACHE_ENTRY::GetCacheBaseName()
S3D_CACHE::S3D_CACHE()
{
m_DirtyCache = false;
m_FNResolver = new FILENAME_RESOLVER;
m_project = nullptr;
m_Plugins = new S3D_PLUGIN_MANAGER;
return;
}
@@ -197,30 +195,33 @@ S3D_CACHE::~S3D_CACHE()
{
FlushCache();
delete m_FNResolver;
delete m_Plugins;
if( m_FNResolver )
delete m_FNResolver;
if( m_Plugins )
delete m_Plugins;
return;
}
SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, const wxString& aBasePath,
S3D_CACHE_ENTRY** aCachePtr )
SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, S3D_CACHE_ENTRY** aCachePtr )
{
if( aCachePtr )
*aCachePtr = nullptr;
*aCachePtr = NULL;
wxString full3Dpath = m_FNResolver->ResolvePath( aModelFile, aBasePath );
wxString full3Dpath = m_FNResolver->ResolvePath( aModelFile );
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" ),
wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * [3D model] could not find model '%s'\n",
__FILE__, __FUNCTION__, __LINE__, aModelFile );
return nullptr;
return NULL;
}
// check cache if file is already loaded
std::lock_guard<std::mutex> lock( mutex3D_cache );
wxCriticalSectionLocker lock( lock3D_cache );
std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString >::iterator mi;
mi = m_CacheMap.find( full3Dpath );
@@ -230,7 +231,7 @@ SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, const wxString& aBasePa
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;
bool reload = false;
wxDateTime fmdate = fname.GetModificationTime();
if( fmdate != mi->second->modTime )
@@ -248,21 +249,20 @@ SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, const wxString& aBasePa
if( reload )
{
if( nullptr != mi->second->sceneData )
if( NULL != mi->second->sceneData )
{
S3D::DestroyNode( mi->second->sceneData );
mi->second->sceneData = nullptr;
mi->second->sceneData = NULL;
}
if( nullptr != mi->second->renderData )
if( NULL != mi->second->renderData )
S3D::Destroy3DModel( &mi->second->renderData );
mi->second->sceneData = m_Plugins->Load3DModel( full3Dpath,
mi->second->pluginInfo );
mi->second->sceneData = m_Plugins->Load3DModel( full3Dpath, mi->second->pluginInfo );
}
}
if( nullptr != aCachePtr )
if( NULL != aCachePtr )
*aCachePtr = mi->second;
return mi->second->sceneData;
@@ -273,33 +273,33 @@ SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, const wxString& aBasePa
}
SCENEGRAPH* S3D_CACHE::Load( const wxString& aModelFile, const wxString& aBasePath )
SCENEGRAPH* S3D_CACHE::Load( const wxString& aModelFile )
{
return load( aModelFile, aBasePath );
return load( aModelFile );
}
SCENEGRAPH* S3D_CACHE::checkCache( const wxString& aFileName, S3D_CACHE_ENTRY** aCachePtr )
{
if( aCachePtr )
*aCachePtr = nullptr;
*aCachePtr = NULL;
unsigned char sha1sum[20];
S3D_CACHE_ENTRY* ep = new S3D_CACHE_ENTRY;
m_CacheList.push_back( ep );
wxFileName fname( aFileName );
ep->modTime = fname.GetModificationTime();
unsigned char sha1sum[20];
if( !getSHA1( aFileName, sha1sum ) || 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
S3D_CACHE_ENTRY* ep = new S3D_CACHE_ENTRY;
m_CacheList.push_back( ep );
wxFileName fname( aFileName );
ep->modTime = fname.GetModificationTime();
if( m_CacheMap.emplace( aFileName, ep ).second == false )
if( m_CacheMap.insert( std::pair< wxString, S3D_CACHE_ENTRY* >
( aFileName, ep ) ).second == false )
{
wxLogTrace( MASK_3D_CACHE,
wxT( "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'",
__FILE__, __FUNCTION__, __LINE__, aFileName );
m_CacheList.pop_back();
@@ -309,20 +309,26 @@ SCENEGRAPH* S3D_CACHE::checkCache( const wxString& aFileName, S3D_CACHE_ENTRY**
{
if( aCachePtr )
*aCachePtr = ep;
}
return nullptr;
return NULL;
}
if( m_CacheMap.emplace( aFileName, ep ).second == false )
S3D_CACHE_ENTRY* ep = new S3D_CACHE_ENTRY;
m_CacheList.push_back( ep );
wxFileName fname( aFileName );
ep->modTime = fname.GetModificationTime();
if( m_CacheMap.insert( std::pair< wxString, S3D_CACHE_ENTRY* >
( aFileName, ep ) ).second == false )
{
wxLogTrace( MASK_3D_CACHE,
wxT( "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'",
__FILE__, __FUNCTION__, __LINE__, aFileName );
m_CacheList.pop_back();
delete ep;
return nullptr;
return NULL;
}
if( aCachePtr )
@@ -333,13 +339,12 @@ SCENEGRAPH* S3D_CACHE::checkCache( const wxString& aFileName, S3D_CACHE_ENTRY**
wxString bname = ep->GetCacheBaseName();
wxString cachename = m_CacheDir + bname + wxT( ".3dc" );
if( !ADVANCED_CFG::GetCfg().m_Skip3DModelFileCache && wxFileName::FileExists( cachename )
&& loadCacheData( ep ) )
if( 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 )
if( NULL != ep->sceneData )
saveCacheData( ep );
return ep->sceneData;
@@ -350,27 +355,27 @@ bool S3D_CACHE::getSHA1( const wxString& aFileName, unsigned char* aSHA1Sum )
{
if( aFileName.empty() )
{
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * [BUG] empty filename" ),
wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * [BUG] empty filename",
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
if( nullptr == aSHA1Sum )
if( NULL == aSHA1Sum )
{
wxLogTrace( MASK_3D_CACHE, wxT( "%s\n * [BUG] NULL pointer passed for aMD5Sum" ),
wxLogTrace( MASK_3D_CACHE, "%s\n * [BUG] NULL pointer passed for aMD5Sum",
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
#ifdef _WIN32
#ifdef _WIN32
FILE* fp = _wfopen( aFileName.wc_str(), L"rb" );
#else
#else
FILE* fp = fopen( aFileName.ToUTF8(), "rb" );
#endif
#endif
if( nullptr == fp )
if( NULL == fp )
return false;
boost::uuids::detail::sha1 dblock;
@@ -409,7 +414,7 @@ bool S3D_CACHE::loadCacheData( S3D_CACHE_ENTRY* aCacheItem )
if( bname.empty() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( " * [3D model] cannot load cached model; no file hash available" ) );
" * [3D model] cannot load cached model; no file hash available" );
return false;
}
@@ -417,7 +422,7 @@ bool S3D_CACHE::loadCacheData( S3D_CACHE_ENTRY* aCacheItem )
if( m_CacheDir.empty() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( " * [3D model] cannot load cached model; config directory unknown" ) );
" * [3D model] cannot load cached model; config directory unknown" );
return false;
}
@@ -426,16 +431,17 @@ bool S3D_CACHE::loadCacheData( S3D_CACHE_ENTRY* aCacheItem )
if( !wxFileName::FileExists( fname ) )
{
wxLogTrace( MASK_3D_CACHE, wxT( " * [3D model] cannot open file '%s'" ), fname.GetData() );
wxString errmsg = "cannot open file";
wxLogTrace( MASK_3D_CACHE, " * [3D model] %s '%s'", errmsg.GetData(), fname.GetData() );
return false;
}
if( nullptr != aCacheItem->sceneData )
if( NULL != aCacheItem->sceneData )
S3D::DestroyNode( (SGNODE*) aCacheItem->sceneData );
aCacheItem->sceneData = (SCENEGRAPH*)S3D::ReadCache( fname.ToUTF8(), m_Plugins, checkTag );
if( nullptr == aCacheItem->sceneData )
if( NULL == aCacheItem->sceneData )
return false;
return true;
@@ -444,17 +450,17 @@ bool S3D_CACHE::loadCacheData( S3D_CACHE_ENTRY* aCacheItem )
bool S3D_CACHE::saveCacheData( S3D_CACHE_ENTRY* aCacheItem )
{
if( nullptr == aCacheItem )
if( NULL == aCacheItem )
{
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * NULL passed for aCacheItem" ),
wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * NULL passed for aCacheItem",
__FILE__, __FUNCTION__, __LINE__ );
return false;
}
if( nullptr == aCacheItem->sceneData )
if( NULL == aCacheItem->sceneData )
{
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * aCacheItem has no valid scene data" ),
wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * aCacheItem has no valid scene data",
__FILE__, __FUNCTION__, __LINE__ );
return false;
@@ -465,7 +471,7 @@ bool S3D_CACHE::saveCacheData( S3D_CACHE_ENTRY* aCacheItem )
if( bname.empty() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( " * [3D model] cannot load cached model; no file hash available" ) );
" * [3D model] cannot load cached model; no file hash available" );
return false;
}
@@ -473,7 +479,7 @@ bool S3D_CACHE::saveCacheData( S3D_CACHE_ENTRY* aCacheItem )
if( m_CacheDir.empty() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( " * [3D model] cannot load cached model; config directory unknown" ) );
" * [3D model] cannot load cached model; config directory unknown" );
return false;
}
@@ -484,15 +490,15 @@ bool S3D_CACHE::saveCacheData( S3D_CACHE_ENTRY* aCacheItem )
{
if( !wxFileName::FileExists( fname ) )
{
wxLogTrace( MASK_3D_CACHE,
wxT( " * [3D model] path exists but is not a regular file '%s'" ), fname );
wxLogTrace( MASK_3D_CACHE, " * [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() );
aCacheItem->pluginInfo.c_str() );
}
@@ -501,9 +507,14 @@ bool S3D_CACHE::Set3DConfigDir( const wxString& aConfigDir )
if( !m_ConfigDir.empty() )
return false;
wxFileName cfgdir( ExpandEnvVarSubstitutions( aConfigDir, m_project ), wxEmptyString );
wxFileName cfgdir;
cfgdir.Normalize( FN_NORMALIZE_FLAGS );
if( aConfigDir.StartsWith( "${" ) || aConfigDir.StartsWith( "$(" ) )
cfgdir.Assign( ExpandEnvVarSubstitutions( aConfigDir ), "" );
else
cfgdir.Assign( aConfigDir, "" );
cfgdir.Normalize();
if( !cfgdir.DirExists() )
{
@@ -512,7 +523,7 @@ bool S3D_CACHE::Set3DConfigDir( const wxString& aConfigDir )
if( !cfgdir.DirExists() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( "%s:%s:%d\n * failed to create 3D configuration directory '%s'" ),
"%s:%s:%d\n * failed to create 3D configuration directory '%s'",
__FILE__, __FUNCTION__, __LINE__, cfgdir.GetPath() );
return false;
@@ -525,8 +536,8 @@ bool S3D_CACHE::Set3DConfigDir( const wxString& aConfigDir )
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'" ),
"%s:%s:%d\n * could not set 3D Config Directory on filename resolver\n"
" * config directory: '%s'",
__FILE__, __FUNCTION__, __LINE__, m_ConfigDir );
}
@@ -537,36 +548,104 @@ bool S3D_CACHE::Set3DConfigDir( const wxString& aConfigDir )
// 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" ) );
wxString cacheDir;
if( !cacheDir.DirExists() )
#if defined(_WIN32)
wxStandardPaths::Get().UseAppInfo( wxStandardPaths::AppInfo_None );
cacheDir = wxStandardPaths::Get().GetUserLocalDataDir();
cacheDir.append( "\\kicad\\3d" );
#elif defined(__APPLE)
cacheDir = "${HOME}/Library/Caches/kicad/3d";
#else // assume Linux
cacheDir = ExpandEnvVarSubstitutions( "${XDG_CACHE_HOME}" );
if( cacheDir.empty() || cacheDir == "${XDG_CACHE_HOME}" )
cacheDir = "${HOME}/.cache";
cacheDir.append( "/kicad/3d" );
#endif
cacheDir = ExpandEnvVarSubstitutions( cacheDir );
cfgdir.Assign( cacheDir, "" );
if( !cfgdir.DirExists() )
{
cacheDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
cfgdir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
if( !cacheDir.DirExists() )
if( !cfgdir.DirExists() )
{
wxLogTrace( MASK_3D_CACHE,
wxT( "%s:%s:%d\n * failed to create 3D cache directory '%s'" ),
__FILE__, __FUNCTION__, __LINE__, cacheDir.GetPath() );
wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * failed to create 3D cache directory '%s'",
__FILE__, __FUNCTION__, __LINE__, cfgdir.GetPath() );
return false;
}
}
m_CacheDir = cacheDir.GetPathWithSep();
m_CacheDir = cfgdir.GetPathWithSep();
return true;
}
bool S3D_CACHE::SetProject( PROJECT* aProject )
wxString S3D_CACHE::Get3DConfigDir( bool createDefault )
{
m_project = aProject;
if( !m_ConfigDir.empty() || !createDefault )
return m_ConfigDir;
// note: duplicated from common/common.cpp GetKicadConfigPath() to avoid
// code coupling; ideally the instantiating code should call
// Set3DConfigDir() to set the directory rather than relying on this
// directory remaining the same in future KiCad releases.
wxFileName cfgpath;
// From the wxWidgets wxStandardPaths::GetUserConfigDir() help:
// Unix: ~ (the home directory)
// Windows: "C:\Documents and Settings\username\Application Data"
// Mac: ~/Library/Preferences
cfgpath.AssignDir( wxStandardPaths::Get().GetUserConfigDir() );
#if !defined( __WINDOWS__ ) && !defined( __WXMAC__ )
wxString envstr = ExpandEnvVarSubstitutions( "${XDG_CONFIG_HOME}" );
if( envstr.IsEmpty() || envstr == "${XDG_CONFIG_HOME}" )
{
// XDG_CONFIG_HOME is not set, so use the fallback
cfgpath.AppendDir( wxT( ".config" ) );
}
else
{
// Override the assignment above with XDG_CONFIG_HOME
cfgpath.AssignDir( envstr );
}
#endif
cfgpath.AppendDir( wxT( "kicad" ) );
cfgpath.AppendDir( wxT( "3d" ) );
if( !cfgpath.DirExists() )
{
cfgpath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
}
if( !cfgpath.DirExists() )
{
wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * failed to create 3D configuration directory '%s'",
__FILE__, __FUNCTION__, __LINE__, cfgpath.GetPath() );
return wxT( "" );
}
if( Set3DConfigDir( cfgpath.GetPath() ) )
return m_ConfigDir;
return wxEmptyString;
}
bool S3D_CACHE::SetProjectDir( const wxString& aProjDir )
{
bool hasChanged = false;
if( m_FNResolver->SetProject( aProject, &hasChanged ) && hasChanged )
if( m_FNResolver->SetProjectDir( aProjDir, &hasChanged ) && hasChanged )
{
m_CacheMap.clear();
@@ -591,16 +670,23 @@ bool S3D_CACHE::SetProject( PROJECT* aProject )
void S3D_CACHE::SetProgramBase( PGM_BASE* aBase )
{
m_FNResolver->SetProgramBase( aBase );
return;
}
FILENAME_RESOLVER* S3D_CACHE::GetResolver() noexcept
wxString S3D_CACHE::GetProjectDir( void )
{
return m_FNResolver->GetProjectDir();
}
FILENAME_RESOLVER* S3D_CACHE::GetResolver( void )
{
return m_FNResolver;
}
std::list< wxString > const* S3D_CACHE::GetFileFilters() const
std::list< wxString > const* S3D_CACHE::GetFileFilters( void ) const
{
return m_Plugins->GetFileFilters();
}
@@ -622,31 +708,35 @@ void S3D_CACHE::FlushCache( bool closePlugins )
if( closePlugins )
ClosePlugins();
return;
}
void S3D_CACHE::ClosePlugins()
void S3D_CACHE::ClosePlugins( void )
{
if( m_Plugins )
if( NULL != m_Plugins )
m_Plugins->ClosePlugins();
return;
}
S3DMODEL* S3D_CACHE::GetModel( const wxString& aModelFileName, const wxString& aBasePath )
S3DMODEL* S3D_CACHE::GetModel( const wxString& aModelFileName )
{
S3D_CACHE_ENTRY* cp = nullptr;
SCENEGRAPH* sp = load( aModelFileName, aBasePath,&cp );
S3D_CACHE_ENTRY* cp = NULL;
SCENEGRAPH* sp = load( aModelFileName, &cp );
if( !sp )
return nullptr;
return NULL;
if( !cp )
{
wxLogTrace( MASK_3D_CACHE,
wxT( "%s:%s:%d\n * [BUG] model loaded with no associated S3D_CACHE_ENTRY" ),
"%s:%s:%d\n * [BUG] model loaded with no associated S3D_CACHE_ENTRY",
__FILE__, __FUNCTION__, __LINE__ );
return nullptr;
return NULL;
}
if( cp->renderData )
@@ -658,102 +748,27 @@ S3DMODEL* S3D_CACHE::GetModel( const wxString& aModelFileName, const wxString& a
return mp;
}
void S3D_CACHE::CleanCacheDir( int aNumDaysOld )
wxString S3D_CACHE::GetModelHash( const wxString& aModelFileName )
{
wxDir dir;
wxString fileSpec = wxT( "*.3dc" );
wxArrayString fileList; // Holds list of ".3dc" files found in cache directory
size_t numFilesFound = 0;
wxString full3Dpath = m_FNResolver->ResolvePath( aModelFileName );
wxFileName thisFile;
wxDateTime lastAccess, thresholdDate;
wxDateSpan durationInDays;
if( full3Dpath.empty() || !wxFileName::FileExists( full3Dpath ) )
return wxEmptyString;
// Calc the threshold date above which we delete cache files
durationInDays.SetDays( aNumDaysOld );
thresholdDate = wxDateTime::Now() - durationInDays;
// check cache if file is already loaded
std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString >::iterator mi;
mi = m_CacheMap.find( full3Dpath );
// 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
if( mi != m_CacheMap.end() )
return mi->second->GetCacheBaseName();
// Get a list of all the ".3dc" files in the cache directory
numFilesFound = dir.GetAllFiles( m_CacheDir, &fileList, fileSpec );
// a cache item does not exist; search the Filename->Cachename map
S3D_CACHE_ENTRY* cp = NULL;
checkCache( full3Dpath, &cp );
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] );
if( NULL != cp )
return cp->GetCacheBaseName();
// 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() );
}
}
}
}
}
void PROJECT::Cleanup3DCache()
{
std::lock_guard<std::mutex> lock( mutex3D_cacheManager );
// Get the existing cache from the project
S3D_CACHE* cache = dynamic_cast<S3D_CACHE*>( GetElem( ELEM_3DCACHE ) );
if( cache )
{
// We'll delete ".3dc" cache files older than this many days
int clearCacheInterval = 0;
if( Pgm().GetCommonSettings() )
clearCacheInterval = Pgm().GetCommonSettings()->m_System.clear_3d_cache_interval;
// An interval of zero means the user doesn't want to ever clear the cache
if( clearCacheInterval > 0 )
cache->CleanCacheDir( clearCacheInterval );
}
}
S3D_CACHE* PROJECT::Get3DCacheManager( bool aUpdateProjDir )
{
std::lock_guard<std::mutex> lock( mutex3D_cacheManager );
// Get the existing cache from the project
S3D_CACHE* cache = dynamic_cast<S3D_CACHE*>( GetElem( ELEM_3DCACHE ) );
if( !cache )
{
// Create a cache if there is not one already
cache = new S3D_CACHE();
wxFileName cfgpath;
cfgpath.AssignDir( SETTINGS_MANAGER::GetUserSettingsPath() );
cfgpath.AppendDir( wxT( "3d" ) );
cache->SetProgramBase( &Pgm() );
cache->Set3DConfigDir( cfgpath.GetFullPath() );
SetElem( ELEM_3DCACHE, cache );
aUpdateProjDir = true;
}
if( aUpdateProjDir )
cache->SetProject( this );
return cache;
}
FILENAME_RESOLVER* PROJECT::Get3DFilenameResolver()
{
return Get3DCacheManager()->GetResolver();
return wxEmptyString;
}
+139 -118
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -24,137 +23,77 @@
/**
* @file 3d_cache.h
* defines the display data cache manager for 3D models
*/
#ifndef CACHE_3D_H
#define CACHE_3D_H
#include "3d_info.h"
#include <core/typeinfo.h>
#include "string_utils.h"
#include <list>
#include <map>
#include "plugins/3dapi/c3dmodel.h"
#include <project.h>
#include <wx/string.h>
#include "kicad_string.h"
#include "filename_resolver.h"
#include "3d_info.h"
#include "plugins/3dapi/c3dmodel.h"
class PGM_BASE;
class S3D_CACHE;
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
class S3D_CACHE
{
public:
S3D_CACHE();
virtual ~S3D_CACHE();
KICAD_T Type() noexcept override
{
return S3D_CACHE_T;
}
/**
* Sets 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
* @return true if the model was successfully loaded, otherwise false.
*/
SCENEGRAPH* Load( const wxString& aModelFile, const wxString& aBasePath );
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.
* @return is a pointer to the render data or NULL if not available.
*/
S3DMODEL* GetModel( const wxString& aModelFileName, const wxString& aBasePath );
/**
* 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
/// 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;
/// object to resolve file names
FILENAME_RESOLVER* m_FNResolver;
/// plugin manager
S3D_PLUGIN_MANAGER* m_Plugins;
/// set true if the cache needs to be updated
bool m_DirtyCache;
/// 3D cache directory
wxString m_CacheDir;
/// base configuration path for 3D items
wxString m_ConfigDir;
/// current KiCad project dir
wxString m_ProjDir;
/** 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.
* 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.
* @param[in] aFileName file name (full or partial path)
* @param[out] aCachePtr optional return address for cache entry pointer
* @return SCENEGRAPH object associated with file name
* @retval NULL on error
*/
SCENEGRAPH* checkCache( const wxString& aFileName, S3D_CACHE_ENTRY** aCachePtr = nullptr );
SCENEGRAPH* checkCache( const wxString& aFileName, S3D_CACHE_ENTRY** aCachePtr = NULL );
/**
* Calculate the SHA1 hash of the given file.
* Function getSHA1
* calculates the SHA1 hash of the given file
*
* @param aFileName file name (full path).
* @param aSHA1Sum a 20 byte character array to hold the SHA1 hash.
* @return true on success, otherwise false.
* @param[in] aFileName file name (full path)
* @param[out] aSHA1Sum a 20 byte character array to hold the SHA1 hash
* @retval true success
* @retval false failure
*/
bool getSHA1( const wxString& aFileName, unsigned char* aSHA1Sum );
@@ -165,21 +104,103 @@ private:
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 );
SCENEGRAPH* load( const wxString& aModelFile, S3D_CACHE_ENTRY** aCachePtr = NULL );
/// cache entries
std::list< S3D_CACHE_ENTRY* > m_CacheList;
public:
S3D_CACHE();
virtual ~S3D_CACHE();
/// mapping of file names to cache names and data
std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString > m_CacheMap;
/**
* Function Set3DConfigDir
* Sets 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 );
FILENAME_RESOLVER* m_FNResolver;
/**
* Function Get3DConfigDir
* returns the current 3D configuration directory on
* success, otherwise it returns wxEmptyString. If the
* directory was not previously set via Set3DConfigDir()
* then a default is used which is based on kicad's
* configuration directory code as of September 2015.
*/
wxString Get3DConfigDir( bool createDefault = false );
S3D_PLUGIN_MANAGER* m_Plugins;
/**
* Function SetProjectDir
* sets the current project's working directory; this
* affects the model search path
*/
bool SetProjectDir( const wxString& aProjDir );
PROJECT* m_project;
wxString m_CacheDir;
wxString m_ConfigDir; /// base configuration path for 3D items
/**
* Function SetProgramBase
* sets the filename resolver's pointer to the application's
* PGM_BASE instance; the pointer is used to extract the
* local env vars.
*/
void SetProgramBase( PGM_BASE* aBase );
/**
* Function GetProjectDir
* returns the current project's working directory
*/
wxString GetProjectDir( void );
/**
* Function Load
* attempts 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.
*
* @param aModelFile [in] is the partial or full path to the model to be loaded
* @return true if the model was successfully loaded, otherwise false.
* The model may fail to load if, for example, the plugin does not
* support rendering of the 3D model.
*/
SCENEGRAPH* Load( const wxString& aModelFile );
FILENAME_RESOLVER* GetResolver( void );
/**
* Function GetFileFilters
* returns 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( void ) const;
/**
* Function FlushCache
* frees all data in the cache and by default closes all plugins
*/
void FlushCache( bool closePlugins = true );
/**
* Function ClosePlugins
* unloads plugins to free memory
*/
void ClosePlugins( void );
/**
* Function GetModel
* attempts 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
* @return is a pointer to the render data or NULL if not available
*/
S3DMODEL* GetModel( const wxString& aModelFileName );
wxString GetModelHash( const wxString& aModelFileName );
};
#endif // CACHE_3D_H
+70
View File
@@ -0,0 +1,70 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* 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 <common.h>
#include <pgm_base.h>
#include "3d_cache_wrapper.h"
static wxCriticalSection lock3D_wrapper;
CACHE_WRAPPER::CACHE_WRAPPER()
{
return;
}
CACHE_WRAPPER::~CACHE_WRAPPER()
{
return;
}
S3D_CACHE* PROJECT::Get3DCacheManager( bool updateProjDir )
{
wxCriticalSectionLocker lock( lock3D_wrapper );
CACHE_WRAPPER* cw = (CACHE_WRAPPER*) GetElem( ELEM_3DCACHE );
S3D_CACHE* cache = dynamic_cast<S3D_CACHE*>( cw );
// check that we get the expected type of object or NULL
wxASSERT( !cw || cache );
if( !cw )
{
cw = new CACHE_WRAPPER;
cache = dynamic_cast<S3D_CACHE*>( cw );
wxFileName cfgpath;
cfgpath.AssignDir( GetKicadConfigPath() );
cfgpath.AppendDir( wxT( "3d" ) );
cache->SetProgramBase( &Pgm() );
cache->Set3DConfigDir( cfgpath.GetFullPath() );
SetElem( ELEM_3DCACHE, cw );
updateProjDir = true;
}
if( updateProjDir )
cache->SetProjectDir( GetProjectPath() );
return cache;
}
+39
View File
@@ -0,0 +1,39 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* 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 CACHE_WRAPPER_3D_H
#define CACHE_WRAPPER_3D_H
#include <project.h>
#include "3d_cache.h"
class CACHE_WRAPPER : public S3D_CACHE, public PROJECT::_ELEM
{
public:
KICAD_T Type() override { return CACHE_WRAPPER_T; }
CACHE_WRAPPER();
virtual ~CACHE_WRAPPER();
};
#endif // CACHE_WRAPPER_3D_H
+2 -2
View File
@@ -36,12 +36,12 @@
#include <wx/string.h>
#include <plugins/3dapi/sg_base.h>
class FP_3DMODEL;
class MODULE_3D_SETTINGS;
struct S3D_INFO
{
S3D_INFO();
S3D_INFO( const FP_3DMODEL& aModel );
S3D_INFO( const MODULE_3D_SETTINGS& 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
+192 -109
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020-2023 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
@@ -27,35 +26,29 @@
#include <iostream>
#include <sstream>
#include <wx/config.h>
#include <wx/dir.h>
#include <wx/dynlib.h>
#include <wx/filename.h>
#include <wx/log.h>
#include <wx/stdpaths.h>
#include <wx/string.h>
#include <common.h>
#include <paths.h>
#include <wx_filename.h>
#include "common.h"
#include "pgm_base.h"
#include "3d_plugin_dir.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( " (*.*)|*.*" ) );
m_FileFilters.push_back( _( "All Files (*.*)|*.*" ) );
// discover and load plugins
loadPlugins();
@@ -65,19 +58,19 @@ S3D_PLUGIN_MANAGER::S3D_PLUGIN_MANAGER()
{
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" ) );
wxLogTrace( MASK_3D_PLUGINMGR, " * Extension [plugin name]:\n" );
while( sM != eM )
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " + '%s' [%s]\n" ), sM->first.GetData(),
sM->second->GetKicadPluginName() );
wxLogTrace( MASK_3D_PLUGINMGR, " + '%s' [%s]\n", sM->first.GetData(),
sM->second->GetKicadPluginName() );
++sM;
}
}
else
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * No plugins available\n" ) );
wxLogTrace( MASK_3D_PLUGINMGR, " * No plugins available\n" );
}
@@ -86,19 +79,21 @@ S3D_PLUGIN_MANAGER::S3D_PLUGIN_MANAGER()
/// 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" ) );
wxLogTrace( MASK_3D_PLUGINMGR, " * File filters:\n" );
while( sFF != eFF )
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " + '%s'\n" ), (*sFF).GetData() );
wxLogTrace( MASK_3D_PLUGINMGR, " + '%s'\n", (*sFF).GetData() );
++sFF;
}
}
else
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * No file filters available\n" ) );
wxLogTrace( MASK_3D_PLUGINMGR, " * No file filters available\n" );
}
#endif // DEBUG
return;
}
@@ -115,53 +110,89 @@ S3D_PLUGIN_MANAGER::~S3D_PLUGIN_MANAGER()
}
m_Plugins.clear();
return;
}
void S3D_PLUGIN_MANAGER::loadPlugins( void )
{
std::list<wxString> searchpaths;
std::list<wxString> pluginlist;
wxFileName fn;
std::list< wxString > searchpaths;
std::list< wxString > pluginlist;
wxFileName fn;
#ifndef __WXMAC__
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
#ifdef DEBUG
// 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 ) )
{
// set up to work from the build directory
fn.Assign( wxStandardPaths::Get().GetExecutablePath() );
fn.AppendDir( wxT( ".." ) );
fn.AppendDir( wxT( "plugins" ) );
fn.AppendDir( wxT( "3d" ) );
checkPluginPath( testpath + subdir, searchpaths );
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 ) )
{
while( debugPluginDir.GetNext( &subdir ) )
checkPluginPath( testpath + subdir, searchpaths );
while( debugPluginDir.GetNext( &subdir ) )
checkPluginPath( testpath + subdir, searchpaths );
}
}
#endif
fn.AssignDir( PATHS::GetStockPlugins3DPath() );
#ifndef _WIN32
// PLUGINDIR = CMAKE_INSTALL_FULL_LIBDIR path is the absolute path
// corresponding to the install path used for constructing KICAD_USER_PLUGIN
wxString tfname = wxString::FromUTF8Unchecked( PLUGINDIR );
fn.Assign( tfname, "");
fn.AppendDir( "kicad" );
#else
// on windows the plugins directory is within the executable's directory
fn.Assign( wxStandardPaths::Get().GetExecutablePath() );
#endif
fn.AppendDir( wxT( "plugins" ) );
fn.AppendDir( wxT( "3d" ) );
// checks plugin directory relative to executable path
checkPluginPath( std::string( fn.GetPathWithSep().ToUTF8() ), searchpaths );
#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() );
// check for per-user third party plugins
// note: GetUserDataDir() gives '.pcbnew' rather than '.kicad' since it uses the exe name;
fn.Assign( wxStandardPaths::Get().GetUserDataDir(), "" );
fn.RemoveLastDir();
#ifdef _WIN32
fn.AppendDir( wxT( "kicad" ) );
#else
fn.AppendDir( wxT( ".kicad" ) );
#endif
fn.AppendDir( wxT( "plugins" ) );
fn.AppendDir( wxT( "3d" ) );
checkPluginPath( fn.GetPathWithSep(), searchpaths );
#else
// Search path on OS X is
// (1) User ~/Library/Application Support/kicad/PlugIns/3d
checkPluginPath( GetOSXKicadUserDataDir() + wxT( "/PlugIns/3d" ), searchpaths );
// (2) Machine /Library/Application Support/kicad/PlugIns/3d
checkPluginPath( GetOSXKicadMachineDataDir() + wxT( "/PlugIns/3d" ), searchpaths );
// (3) Bundle kicad.app/Contents/PlugIns/3d
fn.Assign( Pgm().GetExecutablePath() );
fn.AppendDir( wxT( "Contents" ) );
fn.AppendDir( wxT( "PlugIns" ) );
fn.AppendDir( wxT( "3d" ) );
checkPluginPath( fn.GetPathWithSep(), searchpaths );
#endif
std::list< wxString >::iterator sPL = searchpaths.begin();
@@ -169,9 +200,14 @@ void S3D_PLUGIN_MANAGER::loadPlugins( void )
while( sPL != ePL )
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] searching path: '%s'" ),
__FILE__, __FUNCTION__, __LINE__, (*sPL).ToUTF8() );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
ostr << " * [DEBUG] searching path: '" << (*sPL).ToUTF8() << "'";
wxLogTrace( MASK_3D_PLUGINMGR, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
listPlugins( *sPL, pluginlist );
++sPL;
}
@@ -188,14 +224,25 @@ void S3D_PLUGIN_MANAGER::loadPlugins( void )
if( pp->Open( sPL->ToUTF8() ) )
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] adding plugin" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
ostr << "* [DEBUG] adding plugin";
wxLogTrace( MASK_3D_PLUGINMGR, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
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 );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] adding " << nf << " filters";
wxLogTrace( MASK_3D_PLUGINMGR, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
for( int i = 0; i < nf; ++i )
{
@@ -212,24 +259,39 @@ void S3D_PLUGIN_MANAGER::loadPlugins( void )
}
else
{
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] deleting plugin" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
ostr << "* [DEBUG] deleting plugin";
wxLogTrace( MASK_3D_PLUGINMGR, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
delete pp;
}
++sPL;
}
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] plugins loaded" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
ostr << "* [DEBUG] plugins loaded";
wxLogTrace( MASK_3D_PLUGINMGR, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return;
}
void S3D_PLUGIN_MANAGER::listPlugins( const wxString& aPath, std::list< wxString >& aPluginList )
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 nameFilter; // filter for user-loadable libraries (aka modules)
wxString lName; // stores name of enumerated files
wxString fName; // full name of file
wxDir wd;
@@ -248,7 +310,7 @@ void S3D_PLUGIN_MANAGER::listPlugins( const wxString& aPath, std::list< wxString
// 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" ) );
nameFilter.Append( ".so" );
#endif
wxString lp = wd.GetNameWithSep();
@@ -266,20 +328,27 @@ void S3D_PLUGIN_MANAGER::listPlugins( const wxString& aPath, std::list< wxString
}
wd.Close();
return;
}
void S3D_PLUGIN_MANAGER::checkPluginName( const wxString& aPath,
std::list< wxString >& aPluginList )
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 ) );
wxFileName path;
path.Normalize( FN_NORMALIZE_FLAGS );
if( aPath.StartsWith( "${" ) || aPath.StartsWith( "$(" ) )
path.Assign( ExpandEnvVarSubstitutions( aPath ) );
else
path.Assign( aPath );
path.Normalize();
// determine if the path is already in the list
wxString wxpath = path.GetFullPath();
@@ -294,34 +363,37 @@ void S3D_PLUGIN_MANAGER::checkPluginName( const wxString& aPath,
++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() );
#ifdef DEBUG
wxLogTrace( MASK_3D_PLUGINMGR, " * [INFO] found 3D plugin '%s'\n",
wxpath.GetData() );
#endif
return;
}
void S3D_PLUGIN_MANAGER::checkPluginPath( const wxString& aPath,
std::list< wxString >& aSearchList )
std::list< wxString >& aSearchList )
{
// check the existence of a path and add it to the path search list
if( aPath.empty() )
return;
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * [INFO] checking if valid plugin directory '%s'\n" ),
aPath.GetData() );
#ifdef DEBUG
wxLogTrace( MASK_3D_PLUGINMGR, " * [INFO] checking for 3D plugins in '%s'\n",
aPath.GetData() );
#endif
wxFileName path;
path.AssignDir( aPath );
path.Normalize( FN_NORMALIZE_FLAGS );
if( aPath.StartsWith( "${" ) || aPath.StartsWith( "$(" ) )
path.Assign( ExpandEnvVarSubstitutions( aPath ), "" );
else
path.Assign( aPath, "" );
path.Normalize();
if( !wxFileName::DirExists( path.GetFullPath() ) )
return;
@@ -340,6 +412,8 @@ void S3D_PLUGIN_MANAGER::checkPluginPath( const wxString& aPath,
}
aSearchList.push_back( wxpath );
return;
}
@@ -368,13 +442,19 @@ void S3D_PLUGIN_MANAGER::addFilterString( const wxString& aFilterString )
void S3D_PLUGIN_MANAGER::addExtensionMap( KICAD_PLUGIN_LDR_3D* aPlugin )
{
// add entries to the extension map
if( nullptr == aPlugin )
if( NULL == aPlugin )
return;
int nExt = aPlugin->GetNExtensions();
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [INFO] adding %d extensions" ),
__FILE__, __FUNCTION__, __LINE__, nExt );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] adding " << nExt << " extensions";
wxLogTrace( MASK_3D_PLUGINMGR, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
for( int i = 0; i < nExt; ++i )
{
@@ -386,14 +466,16 @@ void S3D_PLUGIN_MANAGER::addExtensionMap( KICAD_PLUGIN_LDR_3D* aPlugin )
if( !ws.empty() )
{
m_ExtMap.emplace( ws, aPlugin );
m_ExtMap.insert( std::pair< const wxString, KICAD_PLUGIN_LDR_3D* >( ws, aPlugin ) );
}
}
return;
}
std::list< wxString > const* S3D_PLUGIN_MANAGER::GetFileFilters( void ) const noexcept
std::list< wxString > const* S3D_PLUGIN_MANAGER::GetFileFilters( void ) const
{
return &m_FileFilters;
}
@@ -402,25 +484,18 @@ std::list< wxString > const* S3D_PLUGIN_MANAGER::GetFileFilters( void ) const no
SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName, std::string& aPluginInfo )
{
wxFileName raw( aFileName );
wxString ext_to_find = raw.GetExt();
wxString ext = raw.GetExt();
#ifdef _WIN32
#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" );
}
ext.LowerCase();
#endif
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 );
items = m_ExtMap.equal_range( ext );
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator sL = items.first;
while( sL != items.second )
@@ -429,7 +504,7 @@ SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName, std::str
{
SCENEGRAPH* sp = sL->second->Load( aFileName.ToUTF8() );
if( nullptr != sp )
if( NULL != sp )
{
sL->second->GetPluginInfo( aPluginInfo );
return sp;
@@ -439,7 +514,7 @@ SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName, std::str
++sL;
}
return nullptr;
return NULL;
}
@@ -448,20 +523,28 @@ 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() ) );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] closing " << m_Plugins.size() << " plugins";
wxLogTrace( MASK_3D_PLUGINMGR, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
while( sP != eP )
{
(*sP)->Close();
++sP;
}
return;
}
bool S3D_PLUGIN_MANAGER::CheckTag( const char* aTag )
{
if( nullptr == aTag || aTag[0] == 0 || m_Plugins.empty() )
if( NULL == aTag || aTag[0] == 0 || m_Plugins.empty() )
return false;
std::string tname = aTag;
+37 -35
View File
@@ -2,7 +2,6 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright (C) 2020 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
@@ -41,35 +40,16 @@ 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:
/// 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;
/// load plugins
void loadPlugins( void );
@@ -88,14 +68,36 @@ private:
/// 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;
public:
S3D_PLUGIN_MANAGER();
virtual ~S3D_PLUGIN_MANAGER();
/// mapping of extensions to available plugins
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* > m_ExtMap;
/**
* Function GetFileFilters
* returns 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;
/// list of file filters
std::list< wxString > m_FileFilters;
SCENEGRAPH* Load3DModel( const wxString& aFileName, std::string& aPluginInfo );
/**
* Function ClosePlugins
* iterates 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 );
/**
* Function CheckTag
* checks 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 );
};
#endif // PLUGIN_MANAGER_3D_H
@@ -0,0 +1,59 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* 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 <wx/filename.h>
#include "3d_info.h"
#include "3d_cache.h"
#include "plugins/3dapi/ifsg_api.h"
#include "3d_cache_dialogs.h"
#include "dialog_configure_paths.h"
#include "dlg_select_3dmodel.h"
bool S3D::Select3DModel( wxWindow* aParent, S3D_CACHE* aCache,
wxString& prevModelSelectDir, int& prevModelWildcard, MODULE_3D_SETTINGS* aModel )
{
if( NULL == aModel )
return false;
DLG_SELECT_3DMODEL* dm = new DLG_SELECT_3DMODEL( aParent, aCache, aModel,
prevModelSelectDir, prevModelWildcard );
if( wxID_OK == dm->ShowModal() )
{
delete dm;
return true;
}
delete dm;
return false;
}
bool S3D::Configure3DPaths( wxWindow* aParent, FILENAME_RESOLVER* aResolver )
{
DIALOG_CONFIGURE_PATHS dlg( aParent, aResolver );
return( dlg.ShowModal() == wxID_OK );
}
@@ -31,8 +31,8 @@ class FILENAME_RESOLVER;
namespace S3D
{
bool Select3DModel( wxWindow* aParent, S3D_CACHE* aCache, wxString& prevModelSelectDir,
int& prevModelWildcard, FP_3DMODEL* aModel );
bool Select3DModel( wxWindow* aParent, S3D_CACHE* aCache,
wxString& prevModelSelectDir, int& prevModelWildcard, MODULE_3D_SETTINGS* aModel );
bool Configure3DPaths( wxWindow* aParent, FILENAME_RESOLVER* aResolver );
}
@@ -0,0 +1,294 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright (C) 2017-2018 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 <set>
#include "dlg_select_3dmodel.h"
#include "project.h"
#include "3d_cache/3d_info.h"
#include "3d_cache/3d_cache.h"
#include "3d_cache_dialogs.h"
#include <3d_model_viewer/c3d_model_viewer.h>
#include <common_ogl/cogl_att_list.h>
#include <pcbnew/class_module.h>
#define ID_FILE_TREE ( wxID_LAST + 1 )
#define ID_SET_DIR ( ID_FILE_TREE + 1 )
#define ID_CFG_PATHS ( ID_SET_DIR + 1 )
wxBEGIN_EVENT_TABLE( DLG_SELECT_3DMODEL, DIALOG_SHIM )
EVT_DIRCTRL_SELECTIONCHANGED( ID_FILE_TREE, DLG_SELECT_3DMODEL::OnSelectionChanged )
EVT_DIRCTRL_FILEACTIVATED( ID_FILE_TREE, DLG_SELECT_3DMODEL::OnFileActivated )
EVT_CHOICE( ID_SET_DIR, DLG_SELECT_3DMODEL::SetRootDir )
EVT_BUTTON( ID_CFG_PATHS, DLG_SELECT_3DMODEL::Cfg3DPaths )
wxEND_EVENT_TABLE()
DLG_SELECT_3DMODEL::DLG_SELECT_3DMODEL( wxWindow* aParent, S3D_CACHE* aCacheManager,
MODULE_3D_SETTINGS* aModelItem, wxString& prevModelSelectDir, int& prevModelWildcard ) :
DIALOG_SHIM( aParent, wxID_ANY, _( "Select 3D Model" ), wxDefaultPosition,
wxSize( 500,200 ), wxCAPTION | wxRESIZE_BORDER | wxCLOSE_BOX
| wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU ),
m_model( aModelItem ), m_cache( aCacheManager ), m_previousDir( prevModelSelectDir ),
m_previousFilterIndex( prevModelWildcard )
{
SetSizeHints( wxSize( 500,200 ), wxDefaultSize );
if( NULL != m_cache )
m_resolver = m_cache->GetResolver();
else
m_resolver = NULL;
wxBoxSizer* bSizer0 = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizer1 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizer2 = new wxBoxSizer( wxVERTICAL );
// set to NULL to avoid segfaults when m_FileTree is instantiated
// and wxGenericDirCtrl events are posted
m_modelViewer = NULL;
dirChoices = NULL;
m_FileTree = new wxGenericDirCtrl( this, ID_FILE_TREE, prevModelSelectDir, wxDefaultPosition,
wxSize( 300,100 ), wxDIRCTRL_3D_INTERNAL | wxDIRCTRL_EDIT_LABELS
| wxDIRCTRL_SELECT_FIRST | wxDIRCTRL_SHOW_FILTERS | wxBORDER_SIMPLE, wxEmptyString, 0 );
m_FileTree->ShowHidden( false );
m_FileTree->SetMinSize( wxSize( 300, 400 ) );
m_FileTree->SetLabel( wxT( "3D_MODEL_SELECTOR" ) );
bSizer2->Add( m_FileTree, 1, wxEXPAND | wxALL, 5 );
bSizer1->Add( bSizer2, 3, wxEXPAND, 5 );
m_modelViewer = new C3D_MODEL_VIEWER( this, COGL_ATT_LIST::GetAttributesList( true ), m_cache );
m_modelViewer->SetMinSize( wxSize( 500, 400 ) );
bSizer1->Add( m_modelViewer, 5, wxEXPAND | wxALL | wxCENTER, 5 );
// create the filter list
if( NULL != m_cache )
{
std::list< wxString > const* fl = m_cache->GetFileFilters();
std::list< wxString >::const_iterator sL = fl->begin();
std::list< wxString >::const_iterator eL = fl->end();
wxString filter;
while( sL != eL )
{
filter.Append( *sL );
++sL;
if( sL != eL )
filter.Append( wxT( "|" ) );
}
if( !filter.empty() )
m_FileTree->SetFilter( filter );
else
m_FileTree->SetFilter( wxFileSelectorDefaultWildcardStr );
if( prevModelWildcard >= 0 && prevModelWildcard < (int)fl->size() )
m_FileTree->SetFilterIndex( prevModelWildcard );
else
{
prevModelWildcard = 0;
m_FileTree->SetFilterIndex( 0 );
}
}
else
{
m_FileTree->SetFilter( wxFileSelectorDefaultWildcardStr );
prevModelWildcard = 0;
m_FileTree->SetFilterIndex( 0 );
}
// Add the path choice box and config button
wxBoxSizer* hboxDirChoice = new wxBoxSizer( wxHORIZONTAL );
dirChoices = new wxChoice( this, ID_SET_DIR, wxDefaultPosition, wxSize( 320, 20 ) );
dirChoices->SetMinSize( wxSize( 320, 12 ) );
wxStaticText* stDirChoice = new wxStaticText( this, -1, _( "Paths:" ) );
wxButton* cfgPaths = new wxButton( this, ID_CFG_PATHS, _( "Configure Paths" ) );
hboxDirChoice->Add( stDirChoice, 0, wxALL | wxCENTER, 5 );
hboxDirChoice->Add( dirChoices, 1, wxEXPAND | wxALL, 5 );
hboxDirChoice->Add( cfgPaths, 0, wxALL, 5 );
wxButton* btn_OK = new wxButton( this, wxID_OK, _( "OK" ) );
wxButton* btn_Cancel = new wxButton( this, wxID_CANCEL, _( "Cancel" ) );
wxStdDialogButtonSizer* hSizer1 = new wxStdDialogButtonSizer();
hSizer1->AddButton( btn_OK );
hSizer1->AddButton( btn_Cancel );
hSizer1->Realize();
bSizer0->Add( bSizer1, 1, wxALL | wxEXPAND, 5 );
bSizer0->Add( hboxDirChoice, 0, wxALL | wxEXPAND, 5 );
bSizer0->Add( hSizer1, 0, wxALL | wxEXPAND, 5 );
updateDirChoiceList();
SetSizerAndFit( bSizer0 );
Layout();
Centre( wxBOTH );
m_modelViewer->Refresh();
m_modelViewer->SetFocus();
}
bool DLG_SELECT_3DMODEL::TransferDataFromWindow()
{
if( NULL == m_model || NULL == m_FileTree )
return true;
m_model->m_Scale.x = 1.0;
m_model->m_Scale.y = 1.0;
m_model->m_Scale.z = 1.0;
m_model->m_Rotation.x = 0.0;
m_model->m_Rotation.y = 0.0;
m_model->m_Rotation.z = 0.0;
m_model->m_Offset = m_model->m_Rotation;
m_model->m_Filename.clear();
wxString name = m_FileTree->GetFilePath();
if( name.empty() )
return true;
m_previousDir = m_FileTree->GetPath();
m_previousFilterIndex = m_FileTree->GetFilterIndex();
// file selection mode: retrieve the filename and specify a
// path relative to one of the config paths
wxFileName fname = m_FileTree->GetFilePath();
fname.Normalize();
m_model->m_Filename = m_resolver->ShortenPath( fname.GetFullPath() );
return true;
}
void DLG_SELECT_3DMODEL::OnSelectionChanged( wxTreeEvent& event )
{
if( m_modelViewer )
m_modelViewer->Set3DModel( m_FileTree->GetFilePath() );
event.Skip();
return;
}
void DLG_SELECT_3DMODEL::OnFileActivated( wxTreeEvent& event )
{
if( m_modelViewer )
m_modelViewer->Set3DModel( m_FileTree->GetFilePath() );
event.Skip();
SetEscapeId( wxID_OK );
Close();
return;
}
void DLG_SELECT_3DMODEL::SetRootDir( wxCommandEvent& event )
{
if( m_FileTree && dirChoices->GetSelection() > 0 )
m_FileTree->SetPath( dirChoices->GetString( dirChoices->GetSelection() ) );
return;
}
void DLG_SELECT_3DMODEL::Cfg3DPaths( wxCommandEvent& event )
{
if( S3D::Configure3DPaths( this, m_resolver ) )
updateDirChoiceList();
}
void DLG_SELECT_3DMODEL::updateDirChoiceList( void )
{
if( NULL == m_FileTree || NULL == m_resolver || NULL == dirChoices )
return;
std::list< SEARCH_PATH > const* md = m_resolver->GetPaths();
std::list< SEARCH_PATH >::const_iterator sL = md->begin();
std::list< SEARCH_PATH >::const_iterator eL = md->end();
std::set< wxString > cl;
wxString prjDir;
// extract the current project dir
if( sL != eL )
{
prjDir = sL->m_pathexp;
++sL;
}
while( sL != eL )
{
if( !sL->m_pathexp.empty() && sL->m_pathexp.compare( prjDir ) )
cl.insert( sL->m_pathexp );
++sL;
}
if( !cl.empty() )
{
unsigned int choice = 0;
dirChoices->Clear();
dirChoices->Append( "" ); //Insert a blank string at the beginning to allow selection
if( !prjDir.empty() )
{
dirChoices->Append( prjDir );
if( prjDir == m_FileTree->GetPath() )
choice = 1;
}
std::set< wxString >::const_iterator sI = cl.begin();
std::set< wxString >::const_iterator eI = cl.end();
while( sI != eI )
{
if( *sI == m_FileTree->GetPath() )
choice = dirChoices->GetCount();
dirChoices->Append( *sI );
++sI;
}
dirChoices->Select( choice );
}
return;
}
@@ -0,0 +1,78 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright (C) 2018 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 dlg_select_3dmodel.h
* creates a dialog to select 3D model files
*/
#ifndef DLG_SELECT_3DMODEL_H
#define DLG_SELECT_3DMODEL_H
#include <wx/event.h>
#include <wx/stattext.h>
#include <wx/button.h>
#include <wx/dialog.h>
#include <wx/dirctrl.h>
#include <wx/sizer.h>
#include <wx/frame.h>
#include <dialog_shim.h>
class MODULE_3D_SETTINGS;
class S3D_CACHE;
class FILENAME_RESOLVER;
class C3D_MODEL_VIEWER;
class DLG_SELECT_3DMODEL : public DIALOG_SHIM
{
private:
MODULE_3D_SETTINGS* m_model; // data for the selected model
S3D_CACHE* m_cache; // cache manager
FILENAME_RESOLVER* m_resolver; // 3D filename resolver
wxString& m_previousDir;
int& m_previousFilterIndex;
wxGenericDirCtrl* m_FileTree;
C3D_MODEL_VIEWER* m_modelViewer;
wxChoice* dirChoices;
void updateDirChoiceList( void );
public:
DLG_SELECT_3DMODEL( wxWindow* aParent, S3D_CACHE* aCacheManager, MODULE_3D_SETTINGS* aModelItem,
wxString& prevModelSelectDir, int& prevModelWildcard );
bool TransferDataFromWindow() override;
void OnSelectionChanged( wxTreeEvent& event );
void OnFileActivated( wxTreeEvent& event );
void SetRootDir( wxCommandEvent& event );
void Cfg3DPaths( wxCommandEvent& event );
wxDECLARE_EVENT_TABLE();
};
#endif // DLG_SELECT_3DMODEL_H
@@ -0,0 +1,310 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jun 5 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "panel_prev_3d_base.h"
///////////////////////////////////////////////////////////////////////////
PANEL_PREV_3D_BASE::PANEL_PREV_3D_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style )
{
wxBoxSizer* bSizermain;
bSizermain = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizerLeft;
bSizerLeft = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* sbSizerScale;
sbSizerScale = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Scale") ), wxVERTICAL );
wxFlexGridSizer* fgSizerScale;
fgSizerScale = new wxFlexGridSizer( 0, 3, 0, 0 );
fgSizerScale->SetFlexibleDirection( wxBOTH );
fgSizerScale->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText1 = new wxStaticText( sbSizerScale->GetStaticBox(), wxID_ANY, _("X:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1->Wrap( -1 );
fgSizerScale->Add( m_staticText1, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
xscale = new wxTextCtrl( sbSizerScale->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerScale->Add( xscale, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spinXscale = new wxSpinButton( sbSizerScale->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
fgSizerScale->Add( m_spinXscale, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText2 = new wxStaticText( sbSizerScale->GetStaticBox(), wxID_ANY, _("Y:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText2->Wrap( -1 );
fgSizerScale->Add( m_staticText2, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
yscale = new wxTextCtrl( sbSizerScale->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerScale->Add( yscale, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spinYscale = new wxSpinButton( sbSizerScale->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
fgSizerScale->Add( m_spinYscale, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText3 = new wxStaticText( sbSizerScale->GetStaticBox(), wxID_ANY, _("Z:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText3->Wrap( -1 );
fgSizerScale->Add( m_staticText3, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 );
zscale = new wxTextCtrl( sbSizerScale->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerScale->Add( zscale, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 );
m_spinZscale = new wxSpinButton( sbSizerScale->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
fgSizerScale->Add( m_spinZscale, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 );
sbSizerScale->Add( fgSizerScale, 0, wxEXPAND|wxRIGHT|wxLEFT, 10 );
bSizerLeft->Add( sbSizerScale, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
wxStaticBoxSizer* sbSizerRotation;
sbSizerRotation = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Rotation") ), wxVERTICAL );
wxFlexGridSizer* fgSizerRotate;
fgSizerRotate = new wxFlexGridSizer( 0, 3, 0, 0 );
fgSizerRotate->SetFlexibleDirection( wxBOTH );
fgSizerRotate->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText11 = new wxStaticText( sbSizerRotation->GetStaticBox(), wxID_ANY, _("X:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText11->Wrap( -1 );
fgSizerRotate->Add( m_staticText11, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
xrot = new wxTextCtrl( sbSizerRotation->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerRotate->Add( xrot, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spinXrot = new wxSpinButton( sbSizerRotation->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
fgSizerRotate->Add( m_spinXrot, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText21 = new wxStaticText( sbSizerRotation->GetStaticBox(), wxID_ANY, _("Y:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText21->Wrap( -1 );
fgSizerRotate->Add( m_staticText21, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
yrot = new wxTextCtrl( sbSizerRotation->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerRotate->Add( yrot, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spinYrot = new wxSpinButton( sbSizerRotation->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
fgSizerRotate->Add( m_spinYrot, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText31 = new wxStaticText( sbSizerRotation->GetStaticBox(), wxID_ANY, _("Z:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText31->Wrap( -1 );
fgSizerRotate->Add( m_staticText31, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 );
zrot = new wxTextCtrl( sbSizerRotation->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerRotate->Add( zrot, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 );
m_spinZrot = new wxSpinButton( sbSizerRotation->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
fgSizerRotate->Add( m_spinZrot, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 );
sbSizerRotation->Add( fgSizerRotate, 0, wxEXPAND|wxRIGHT|wxLEFT, 10 );
bSizerLeft->Add( sbSizerRotation, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
wxStaticBoxSizer* sbSizerOffset;
sbSizerOffset = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Offset") ), wxVERTICAL );
wxFlexGridSizer* fgSizerOffset;
fgSizerOffset = new wxFlexGridSizer( 0, 3, 0, 0 );
fgSizerOffset->SetFlexibleDirection( wxBOTH );
fgSizerOffset->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText12 = new wxStaticText( sbSizerOffset->GetStaticBox(), wxID_ANY, _("X:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText12->Wrap( -1 );
fgSizerOffset->Add( m_staticText12, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
xoff = new wxTextCtrl( sbSizerOffset->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerOffset->Add( xoff, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spinXoffset = new wxSpinButton( sbSizerOffset->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
fgSizerOffset->Add( m_spinXoffset, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText22 = new wxStaticText( sbSizerOffset->GetStaticBox(), wxID_ANY, _("Y:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText22->Wrap( -1 );
fgSizerOffset->Add( m_staticText22, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
yoff = new wxTextCtrl( sbSizerOffset->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerOffset->Add( yoff, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spinYoffset = new wxSpinButton( sbSizerOffset->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
fgSizerOffset->Add( m_spinYoffset, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText32 = new wxStaticText( sbSizerOffset->GetStaticBox(), wxID_ANY, _("Z:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText32->Wrap( -1 );
fgSizerOffset->Add( m_staticText32, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 );
zoff = new wxTextCtrl( sbSizerOffset->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerOffset->Add( zoff, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 );
m_spinZoffset = new wxSpinButton( sbSizerOffset->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
fgSizerOffset->Add( m_spinZoffset, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 );
sbSizerOffset->Add( fgSizerOffset, 0, wxEXPAND|wxLEFT|wxRIGHT, 10 );
bSizerLeft->Add( sbSizerOffset, 0, wxEXPAND|wxALL, 5 );
bSizermain->Add( bSizerLeft, 0, 0, 5 );
wxBoxSizer* bSizerRight;
bSizerRight = new wxBoxSizer( wxVERTICAL );
wxStaticText* staticPreviewLabel;
staticPreviewLabel = new wxStaticText( this, wxID_ANY, _("Preview"), wxDefaultPosition, wxDefaultSize, 0 );
staticPreviewLabel->Wrap( -1 );
staticPreviewLabel->SetFont( wxFont( 11, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
bSizerRight->Add( staticPreviewLabel, 0, wxLEFT, 15 );
m_SizerPanelView = new wxBoxSizer( wxVERTICAL );
bSizerRight->Add( m_SizerPanelView, 1, wxEXPAND|wxBOTTOM, 8 );
bSizermain->Add( bSizerRight, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 4 );
wxBoxSizer* bSizer3DButtons;
bSizer3DButtons = new wxBoxSizer( wxVERTICAL );
bSizer3DButtons->Add( 0, 0, 0, wxEXPAND|wxTOP, 4 );
m_bpvISO = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
m_bpvISO->SetToolTip( _("Change to isometric perspective") );
bSizer3DButtons->Add( m_bpvISO, 0, wxTOP|wxBOTTOM, 5 );
m_bpvLeft = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
bSizer3DButtons->Add( m_bpvLeft, 0, 0, 5 );
m_bpvRight = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
bSizer3DButtons->Add( m_bpvRight, 0, 0, 5 );
m_bpvFront = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
bSizer3DButtons->Add( m_bpvFront, 0, 0, 5 );
m_bpvBack = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
bSizer3DButtons->Add( m_bpvBack, 0, 0, 5 );
m_bpvTop = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
bSizer3DButtons->Add( m_bpvTop, 0, 0, 5 );
m_bpvBottom = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
bSizer3DButtons->Add( m_bpvBottom, 0, 0, 5 );
m_bpUpdate = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
m_bpUpdate->SetToolTip( _("Reload board and 3D models") );
bSizer3DButtons->Add( m_bpUpdate, 0, wxTOP, 5 );
bSizermain->Add( bSizer3DButtons, 0, wxALL|wxEXPAND, 5 );
this->SetSizer( bSizermain );
this->Layout();
bSizermain->Fit( this );
// Connect Events
xscale->Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelScale ), NULL, this );
xscale->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinXscale->Connect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementScale ), NULL, this );
m_spinXscale->Connect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementScale ), NULL, this );
yscale->Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelScale ), NULL, this );
yscale->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinYscale->Connect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementScale ), NULL, this );
m_spinYscale->Connect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementScale ), NULL, this );
zscale->Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelScale ), NULL, this );
zscale->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinZscale->Connect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementScale ), NULL, this );
m_spinZscale->Connect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementScale ), NULL, this );
xrot->Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelRot ), NULL, this );
xrot->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinXrot->Connect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementRot ), NULL, this );
m_spinXrot->Connect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementRot ), NULL, this );
yrot->Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelRot ), NULL, this );
yrot->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinYrot->Connect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementRot ), NULL, this );
m_spinYrot->Connect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementRot ), NULL, this );
zrot->Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelRot ), NULL, this );
zrot->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinZrot->Connect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementRot ), NULL, this );
m_spinZrot->Connect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementRot ), NULL, this );
xoff->Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelOffset ), NULL, this );
xoff->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinXoffset->Connect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementOffset ), NULL, this );
m_spinXoffset->Connect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementOffset ), NULL, this );
yoff->Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelOffset ), NULL, this );
yoff->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinYoffset->Connect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementOffset ), NULL, this );
m_spinYoffset->Connect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementOffset ), NULL, this );
zoff->Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelOffset ), NULL, this );
zoff->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinZoffset->Connect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementOffset ), NULL, this );
m_spinZoffset->Connect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementOffset ), NULL, this );
m_bpvISO->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DISO ), NULL, this );
m_bpvLeft->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DLeft ), NULL, this );
m_bpvRight->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DRight ), NULL, this );
m_bpvFront->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DFront ), NULL, this );
m_bpvBack->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DBack ), NULL, this );
m_bpvTop->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DTop ), NULL, this );
m_bpvBottom->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DBottom ), NULL, this );
m_bpUpdate->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DUpdate ), NULL, this );
}
PANEL_PREV_3D_BASE::~PANEL_PREV_3D_BASE()
{
// Disconnect Events
xscale->Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelScale ), NULL, this );
xscale->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinXscale->Disconnect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementScale ), NULL, this );
m_spinXscale->Disconnect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementScale ), NULL, this );
yscale->Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelScale ), NULL, this );
yscale->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinYscale->Disconnect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementScale ), NULL, this );
m_spinYscale->Disconnect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementScale ), NULL, this );
zscale->Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelScale ), NULL, this );
zscale->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinZscale->Disconnect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementScale ), NULL, this );
m_spinZscale->Disconnect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementScale ), NULL, this );
xrot->Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelRot ), NULL, this );
xrot->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinXrot->Disconnect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementRot ), NULL, this );
m_spinXrot->Disconnect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementRot ), NULL, this );
yrot->Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelRot ), NULL, this );
yrot->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinYrot->Disconnect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementRot ), NULL, this );
m_spinYrot->Disconnect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementRot ), NULL, this );
zrot->Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelRot ), NULL, this );
zrot->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinZrot->Disconnect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementRot ), NULL, this );
m_spinZrot->Disconnect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementRot ), NULL, this );
xoff->Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelOffset ), NULL, this );
xoff->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinXoffset->Disconnect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementOffset ), NULL, this );
m_spinXoffset->Disconnect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementOffset ), NULL, this );
yoff->Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelOffset ), NULL, this );
yoff->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinYoffset->Disconnect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementOffset ), NULL, this );
m_spinYoffset->Disconnect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementOffset ), NULL, this );
zoff->Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( PANEL_PREV_3D_BASE::onMouseWheelOffset ), NULL, this );
zoff->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( PANEL_PREV_3D_BASE::updateOrientation ), NULL, this );
m_spinZoffset->Disconnect( wxEVT_SCROLL_LINEDOWN, wxSpinEventHandler( PANEL_PREV_3D_BASE::onDecrementOffset ), NULL, this );
m_spinZoffset->Disconnect( wxEVT_SCROLL_LINEUP, wxSpinEventHandler( PANEL_PREV_3D_BASE::onIncrementOffset ), NULL, this );
m_bpvISO->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DISO ), NULL, this );
m_bpvLeft->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DLeft ), NULL, this );
m_bpvRight->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DRight ), NULL, this );
m_bpvFront->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DFront ), NULL, this );
m_bpvBack->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DBack ), NULL, this );
m_bpvTop->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DTop ), NULL, this );
m_bpvBottom->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DBottom ), NULL, this );
m_bpUpdate->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PREV_3D_BASE::View3DUpdate ), NULL, this );
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,107 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jun 5 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __PANEL_PREV_3D_BASE_H__
#define __PANEL_PREV_3D_BASE_H__
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/textctrl.h>
#include <wx/spinbutt.h>
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/bmpbuttn.h>
#include <wx/button.h>
#include <wx/panel.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class PANEL_PREV_3D_BASE
///////////////////////////////////////////////////////////////////////////////
class PANEL_PREV_3D_BASE : public wxPanel
{
private:
protected:
wxStaticText* m_staticText1;
wxTextCtrl* xscale;
wxSpinButton* m_spinXscale;
wxStaticText* m_staticText2;
wxTextCtrl* yscale;
wxSpinButton* m_spinYscale;
wxStaticText* m_staticText3;
wxTextCtrl* zscale;
wxSpinButton* m_spinZscale;
wxStaticText* m_staticText11;
wxTextCtrl* xrot;
wxSpinButton* m_spinXrot;
wxStaticText* m_staticText21;
wxTextCtrl* yrot;
wxSpinButton* m_spinYrot;
wxStaticText* m_staticText31;
wxTextCtrl* zrot;
wxSpinButton* m_spinZrot;
wxStaticText* m_staticText12;
wxTextCtrl* xoff;
wxSpinButton* m_spinXoffset;
wxStaticText* m_staticText22;
wxSpinButton* m_spinYoffset;
wxStaticText* m_staticText32;
wxTextCtrl* zoff;
wxSpinButton* m_spinZoffset;
wxBoxSizer* m_SizerPanelView;
wxBitmapButton* m_bpvISO;
wxBitmapButton* m_bpvLeft;
wxBitmapButton* m_bpvRight;
wxBitmapButton* m_bpvFront;
wxBitmapButton* m_bpvBack;
wxBitmapButton* m_bpvTop;
wxBitmapButton* m_bpvBottom;
wxBitmapButton* m_bpUpdate;
// Virtual event handlers, overide them in your derived class
virtual void onMouseWheelScale( wxMouseEvent& event ) { event.Skip(); }
virtual void updateOrientation( wxCommandEvent& event ) { event.Skip(); }
virtual void onDecrementScale( wxSpinEvent& event ) { event.Skip(); }
virtual void onIncrementScale( wxSpinEvent& event ) { event.Skip(); }
virtual void onMouseWheelRot( wxMouseEvent& event ) { event.Skip(); }
virtual void onDecrementRot( wxSpinEvent& event ) { event.Skip(); }
virtual void onIncrementRot( wxSpinEvent& event ) { event.Skip(); }
virtual void onMouseWheelOffset( wxMouseEvent& event ) { event.Skip(); }
virtual void onDecrementOffset( wxSpinEvent& event ) { event.Skip(); }
virtual void onIncrementOffset( wxSpinEvent& event ) { event.Skip(); }
virtual void View3DISO( wxCommandEvent& event ) { event.Skip(); }
virtual void View3DLeft( wxCommandEvent& event ) { event.Skip(); }
virtual void View3DRight( wxCommandEvent& event ) { event.Skip(); }
virtual void View3DFront( wxCommandEvent& event ) { event.Skip(); }
virtual void View3DBack( wxCommandEvent& event ) { event.Skip(); }
virtual void View3DTop( wxCommandEvent& event ) { event.Skip(); }
virtual void View3DBottom( wxCommandEvent& event ) { event.Skip(); }
virtual void View3DUpdate( wxCommandEvent& event ) { event.Skip(); }
public:
wxTextCtrl* yoff;
PANEL_PREV_3D_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL );
~PANEL_PREV_3D_BASE();
};
#endif //__PANEL_PREV_3D_BASE_H__
@@ -0,0 +1,404 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2015-2018 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 panel_prev_model.cpp
*/
#include "panel_prev_model.h"
#include <3d_canvas/eda_3d_canvas.h>
#include <common_ogl/cogl_att_list.h>
#include <class_board.h>
#include <base_units.h>
#include <bitmaps.h>
#include <class_drawpanel.h>
#include <dpi_scaling.h>
#include <pgm_base.h>
#include <project.h>
PANEL_PREV_3D::PANEL_PREV_3D( wxWindow* aParent, PCB_BASE_FRAME* aFrame, MODULE* aModule,
std::vector<MODULE_3D_SETTINGS> *aParentModelList ) :
PANEL_PREV_3D_BASE( aParent, wxID_ANY )
{
m_userUnits = aFrame->GetUserUnits();
initPanel();
// Initialize the color settings to draw the board and the footprint
m_dummyBoard->SetColorsSettings( &aFrame->Settings().Colors() );
m_parentModelList = aParentModelList;
m_dummyModule = new MODULE( *aModule );
m_dummyBoard->Add( m_dummyModule );
// Set 3d viewer configuration for preview
m_settings3Dviewer = new CINFO3D_VISU();
// Create the 3D canvas
m_previewPane = new EDA_3D_CANVAS( this, COGL_ATT_LIST::GetAttributesList( true ),
m_dummyBoard, *m_settings3Dviewer,
aFrame->Prj().Get3DCacheManager() );
loadCommonSettings();
m_SizerPanelView->Add( m_previewPane, 1, wxEXPAND, 5 );
}
PANEL_PREV_3D::~PANEL_PREV_3D()
{
delete m_settings3Dviewer;
delete m_dummyBoard;
delete m_previewPane;
}
void PANEL_PREV_3D::initPanel()
{
m_dummyBoard = new BOARD();
m_selected = -1;
// Set the bitmap of 3D view buttons:
m_bpvTop->SetBitmap( KiBitmap( axis3d_top_xpm ) );
m_bpvFront->SetBitmap( KiBitmap( axis3d_front_xpm ) );
m_bpvBack->SetBitmap( KiBitmap( axis3d_back_xpm ) );
m_bpvLeft->SetBitmap( KiBitmap( axis3d_left_xpm ) );
m_bpvRight->SetBitmap( KiBitmap( axis3d_right_xpm ) );
m_bpvBottom->SetBitmap( KiBitmap( axis3d_bottom_xpm ) );
m_bpvISO->SetBitmap( KiBitmap( ortho_xpm ) );
m_bpUpdate->SetBitmap( KiBitmap( reload_xpm ) );
// Set the min and max values of spin buttons (mandatory on Linux)
// They are not used, so they are set to min and max 32 bits int values
// (the min and max values supported by a wxSpinButton)
// It avoids blocking the up or down arrows when reaching this limit after
// a few clicks.
wxSpinButton* spinButtonList[] =
{
m_spinXscale, m_spinYscale, m_spinZscale,
m_spinXrot, m_spinYrot, m_spinZrot,
m_spinXoffset,m_spinYoffset, m_spinZoffset
};
for( int ii = 0; ii < 9; ii++ )
spinButtonList[ii]->SetRange( INT_MIN, INT_MAX );
}
void PANEL_PREV_3D::loadCommonSettings()
{
wxCHECK_RET( m_previewPane, "Cannot load settings to null canvas" );
wxConfigBase& cmnCfg = *Pgm().CommonSettings();
{
const DPI_SCALING dpi{ &cmnCfg, this };
m_previewPane->SetScaleFactor( dpi.GetScaleFactor() );
}
{
bool option;
cmnCfg.Read( ENBL_MOUSEWHEEL_PAN_KEY, &option, false );
m_settings3Dviewer->SetFlag( FL_MOUSEWHEEL_PANNING, option );
}
}
/**
* @brief rotationFromString
* Ensure -MAX_ROTATION <= rotation <= MAX_ROTATION
* aRotation will be normalized between -MAX_ROTATION and MAX_ROTATION
*/
static double rotationFromString( const wxString& aValue )
{
double rotation = DoubleValueFromString( DEGREES, aValue ) / 10.0;
if( rotation > MAX_ROTATION )
{
int n = rotation / MAX_ROTATION;
rotation -= MAX_ROTATION * n;
}
else if( rotation < -MAX_ROTATION )
{
int n = -rotation / MAX_ROTATION;
rotation += MAX_ROTATION * n;
}
return rotation;
}
wxString PANEL_PREV_3D::formatScaleValue( double aValue )
{
return wxString::Format( "%.4f", aValue );
}
wxString PANEL_PREV_3D::formatRotationValue( double aValue )
{
return wxString::Format( "%.2f %s", aValue, GetAbbreviatedUnitsLabel( DEGREES ) );
}
wxString PANEL_PREV_3D::formatOffsetValue( double aValue )
{
// Convert from internal units (mm) to user units
if( m_userUnits == INCHES )
aValue /= 25.4f;
return wxString::Format( "%.4f %s", aValue, GetAbbreviatedUnitsLabel( m_userUnits ) );
}
void PANEL_PREV_3D::SetSelectedModel( int idx )
{
if( m_parentModelList && idx >= 0 && idx < (int) m_parentModelList->size() )
{
m_selected = idx;
const MODULE_3D_SETTINGS& modelInfo = m_parentModelList->at( (unsigned) m_selected );
// Use ChangeValue() instead of SetValue(). It's not the user making the change, so we
// don't want to generate wxEVT_GRID_CELL_CHANGED events.
xscale->ChangeValue( formatScaleValue( modelInfo.m_Scale.x ) );
yscale->ChangeValue( formatScaleValue( modelInfo.m_Scale.y ) );
zscale->ChangeValue( formatScaleValue( modelInfo.m_Scale.z ) );
xrot->ChangeValue( formatRotationValue( modelInfo.m_Rotation.x ) );
yrot->ChangeValue( formatRotationValue( modelInfo.m_Rotation.y ) );
zrot->ChangeValue( formatRotationValue( modelInfo.m_Rotation.z ) );
xoff->ChangeValue( formatOffsetValue( modelInfo.m_Offset.x ) );
yoff->ChangeValue( formatOffsetValue( modelInfo.m_Offset.y ) );
zoff->ChangeValue( formatOffsetValue( modelInfo.m_Offset.z ) );
}
else
{
m_selected = -1;
xscale->ChangeValue( wxEmptyString );
yscale->ChangeValue( wxEmptyString );
zscale->ChangeValue( wxEmptyString );
xrot->ChangeValue( wxEmptyString );
yrot->ChangeValue( wxEmptyString );
zrot->ChangeValue( wxEmptyString );
xoff->ChangeValue( wxEmptyString );
yoff->ChangeValue( wxEmptyString );
zoff->ChangeValue( wxEmptyString );
}
}
void PANEL_PREV_3D::updateOrientation( wxCommandEvent &event )
{
if( m_parentModelList && m_selected >= 0 && m_selected < (int) m_parentModelList->size() )
{
// Write settings back to the parent
MODULE_3D_SETTINGS* modelInfo = &m_parentModelList->at( (unsigned) m_selected );
modelInfo->m_Scale.x = DoubleValueFromString( UNSCALED_UNITS, xscale->GetValue() );
modelInfo->m_Scale.y = DoubleValueFromString( UNSCALED_UNITS, yscale->GetValue() );
modelInfo->m_Scale.z = DoubleValueFromString( UNSCALED_UNITS, zscale->GetValue() );
modelInfo->m_Rotation.x = rotationFromString( xrot->GetValue() );
modelInfo->m_Rotation.y = rotationFromString( yrot->GetValue() );
modelInfo->m_Rotation.z = rotationFromString( zrot->GetValue() );
modelInfo->m_Offset.x = DoubleValueFromString( m_userUnits, xoff->GetValue() ) / IU_PER_MM;
modelInfo->m_Offset.y = DoubleValueFromString( m_userUnits, yoff->GetValue() ) / IU_PER_MM;
modelInfo->m_Offset.z = DoubleValueFromString( m_userUnits, zoff->GetValue() ) / IU_PER_MM;
// Update the dummy module for the preview
UpdateDummyModule( false );
}
}
void PANEL_PREV_3D::doIncrementScale( wxSpinEvent& event, double aSign )
{
wxSpinButton* spinCtrl = (wxSpinButton*) event.GetEventObject();
wxTextCtrl * textCtrl = xscale;
if( spinCtrl == m_spinYscale )
textCtrl = yscale;
else if( spinCtrl == m_spinZscale )
textCtrl = zscale;
double curr_value = DoubleValueFromString( UNSCALED_UNITS, textCtrl->GetValue() );
curr_value += ( SCALE_INCREMENT * aSign );
curr_value = std::max( 1/MAX_SCALE, curr_value );
curr_value = std::min( curr_value, MAX_SCALE );
textCtrl->SetValue( formatScaleValue( curr_value ) );
}
void PANEL_PREV_3D::doIncrementRotation( wxSpinEvent& aEvent, double aSign )
{
wxSpinButton* spinCtrl = (wxSpinButton*) aEvent.GetEventObject();
wxTextCtrl* textCtrl = xrot;
if( spinCtrl == m_spinYrot )
textCtrl = yrot;
else if( spinCtrl == m_spinZrot )
textCtrl = zrot;
double curr_value = DoubleValueFromString( DEGREES, textCtrl->GetValue() ) / 10.0;
curr_value += ( ROTATION_INCREMENT * aSign );
curr_value = std::max( -MAX_ROTATION, curr_value );
curr_value = std::min( curr_value, MAX_ROTATION );
textCtrl->SetValue( formatRotationValue( curr_value ) );
}
void PANEL_PREV_3D::doIncrementOffset( wxSpinEvent& event, double aSign )
{
wxSpinButton* spinCtrl = (wxSpinButton*) event.GetEventObject();
wxTextCtrl * textCtrl = xoff;
if( spinCtrl == m_spinYoffset )
textCtrl = yoff;
else if( spinCtrl == m_spinZoffset )
textCtrl = zoff;
double step = OFFSET_INCREMENT_MM;
if( m_userUnits == INCHES )
step = OFFSET_INCREMENT_MIL/1000.0;
double curr_value = DoubleValueFromString( m_userUnits, textCtrl->GetValue() ) / IU_PER_MM;
curr_value += ( step * aSign );
curr_value = std::max( -MAX_OFFSET, curr_value );
curr_value = std::min( curr_value, MAX_OFFSET );
textCtrl->SetValue( formatOffsetValue( curr_value ) );
}
void PANEL_PREV_3D::onMouseWheelScale( wxMouseEvent& event )
{
wxTextCtrl* textCtrl = (wxTextCtrl*) event.GetEventObject();
double step = SCALE_INCREMENT;
if( event.ShiftDown( ) )
step = SCALE_INCREMENT_FINE;
if( event.GetWheelRotation() >= 0 )
step = -step;
double curr_value = DoubleValueFromString( UNSCALED_UNITS, textCtrl->GetValue() );
curr_value += step;
curr_value = std::max( 1/MAX_SCALE, curr_value );
curr_value = std::min( curr_value, MAX_SCALE );
textCtrl->SetValue( formatScaleValue( curr_value ) );
}
void PANEL_PREV_3D::onMouseWheelRot( wxMouseEvent& event )
{
wxTextCtrl* textCtrl = (wxTextCtrl*) event.GetEventObject();
double step = ROTATION_INCREMENT_WHEEL;
if( event.ShiftDown( ) )
step = ROTATION_INCREMENT_WHEEL_FINE;
if( event.GetWheelRotation() >= 0 )
step = -step;
double curr_value = DoubleValueFromString( DEGREES, textCtrl->GetValue() ) / 10.0;
curr_value += step;
curr_value = std::max( -MAX_ROTATION, curr_value );
curr_value = std::min( curr_value, MAX_ROTATION );
textCtrl->SetValue( formatRotationValue( curr_value ) );
}
void PANEL_PREV_3D::onMouseWheelOffset( wxMouseEvent& event )
{
wxTextCtrl* textCtrl = (wxTextCtrl*) event.GetEventObject();
double step = OFFSET_INCREMENT_MM;
if( event.ShiftDown( ) )
step = OFFSET_INCREMENT_MM_FINE;
if( m_userUnits == INCHES )
{
step = OFFSET_INCREMENT_MIL/1000.0;
if( event.ShiftDown( ) )
step = OFFSET_INCREMENT_MIL_FINE/1000.0;
}
if( event.GetWheelRotation() >= 0 )
step = -step;
double curr_value = DoubleValueFromString( m_userUnits, textCtrl->GetValue() ) / IU_PER_MM;
curr_value += step;
curr_value = std::max( -MAX_OFFSET, curr_value );
curr_value = std::min( curr_value, MAX_OFFSET );
textCtrl->SetValue( formatOffsetValue( curr_value ) );
}
void PANEL_PREV_3D::UpdateDummyModule( bool aReloadRequired )
{
m_dummyModule->Models().clear();
for( size_t i = 0; i < m_parentModelList->size(); ++i )
{
if( m_parentModelList->at( i ).m_Preview )
{
m_dummyModule->Models().insert( m_dummyModule->Models().end(),
m_parentModelList->at( i ) );
}
}
if( aReloadRequired )
m_previewPane->ReloadRequest();
m_previewPane->Request_refresh();
}
@@ -0,0 +1,200 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright (C) 2015-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 panel_prev_model.h
* @brief Defines a panel which is to be added to a wxFileDialog via
* SetExtraControl();
* The panel shows a preview of the module being edited and provides controls
* to set the offset/rotation/scale of each model 3d shape as per KiCad's
* current behavior. The panel may also be used in the 3D configuration dialog
* to tune the positioning of the models without invoking a file selector dialog.
*/
#ifndef PANEL_PREV_MODEL_H
#define PANEL_PREV_MODEL_H
#include "panel_prev_3d_base.h"
#include <vector>
#include <3d_canvas/eda_3d_canvas.h>
// Define min and max parameter values
#define MAX_SCALE 10000.0
#define MAX_ROTATION 180.0
#define MAX_OFFSET 1000.0
#define SCALE_INCREMENT_FINE 0.02
#define SCALE_INCREMENT 0.1
#define ROTATION_INCREMENT 5 // in degrees, for spin button command
#define ROTATION_INCREMENT_WHEEL 15 // in degrees, for mouse wheel command
#define ROTATION_INCREMENT_WHEEL_FINE 1 // in degrees, for mouse wheel command
#define OFFSET_INCREMENT_MM 0.5
#define OFFSET_INCREMENT_MM_FINE 0.1
#define OFFSET_INCREMENT_MIL 25.0
#define OFFSET_INCREMENT_MIL_FINE 5.0
// Declared classes to create pointers
class S3D_CACHE;
class FILENAME_RESOLVER;
class BOARD;
class CINFO3D_VISU;
class MODULE;
class COLORS_DESIGN_SETTINGS;
class PANEL_PREV_3D: public PANEL_PREV_3D_BASE
{
public:
PANEL_PREV_3D( wxWindow* aParent, PCB_BASE_FRAME* aFrame, MODULE* aModule,
std::vector<MODULE_3D_SETTINGS> *aParentModelList );
~PANEL_PREV_3D();
private:
EDA_3D_CANVAS* m_previewPane;
CINFO3D_VISU* m_settings3Dviewer;
BOARD* m_dummyBoard;
MODULE* m_dummyModule;
std::vector<MODULE_3D_SETTINGS>* m_parentModelList;
int m_selected; /// Index into m_parentInfoList
EDA_UNITS_T m_userUnits;
// Methods of the class
private:
void initPanel();
/**
* Load 3D relevant settings from the user configuration
*/
void loadCommonSettings();
/**
* @brief updateOrientation - it will receive the events from editing the fields
* @param event
*/
void updateOrientation( wxCommandEvent &event ) override;
void onMouseWheelScale( wxMouseEvent& event ) override;
void onMouseWheelRot( wxMouseEvent& event ) override;
void onMouseWheelOffset( wxMouseEvent& event ) override;
void onIncrementRot( wxSpinEvent& event ) override
{
doIncrementRotation( event, 1.0 );
}
void onDecrementRot( wxSpinEvent& event ) override
{
doIncrementRotation( event, -1.0 );
}
void onIncrementScale( wxSpinEvent& event ) override
{
doIncrementScale( event, 1.0 );
}
void onDecrementScale( wxSpinEvent& event ) override
{
doIncrementScale( event, -1.0 );
}
void onIncrementOffset( wxSpinEvent& event ) override
{
doIncrementOffset( event, 1.0 );
}
void onDecrementOffset( wxSpinEvent& event ) override
{
doIncrementOffset( event, -1.0 );
}
void doIncrementScale( wxSpinEvent& aEvent, double aSign );
void doIncrementRotation( wxSpinEvent& aEvent, double aSign );
void doIncrementOffset( wxSpinEvent& aEvent, double aSign );
wxString formatScaleValue( double aValue );
wxString formatRotationValue( double aValue );
wxString formatOffsetValue( double aValue );
void View3DISO( wxCommandEvent& event ) override
{
m_settings3Dviewer->CameraGet().ToggleProjection();
m_previewPane->Refresh();
}
void View3DLeft( wxCommandEvent& event ) override
{
m_previewPane->SetView3D( GR_KB_SHIFT + 'X' );
}
void View3DFront( wxCommandEvent& event ) override
{
m_previewPane->SetView3D( 'Y' );
}
void View3DTop( wxCommandEvent& event ) override
{
m_previewPane->SetView3D( 'Z' );
}
void View3DUpdate( wxCommandEvent& event ) override
{
m_previewPane->ReloadRequest();
m_previewPane->Refresh();
}
void View3DRight( wxCommandEvent& event ) override
{
m_previewPane->SetView3D( 'X' );
}
void View3DBack( wxCommandEvent& event ) override
{
m_previewPane->SetView3D( GR_KB_SHIFT + 'Y' );
}
void View3DBottom( wxCommandEvent& event ) override
{
m_previewPane->SetView3D( GR_KB_SHIFT + 'Z' );
}
public:
/**
* @brief SetModelDataIdx - Sets the currently selected index in the model list so that
* the scale/rotation/offset controls can be updated.
*/
void SetSelectedModel( int idx );
/**
* @brief UpdateModelInfoList - copy shapes from the current shape list which are flagged
* for preview to the copy of module that is on the preview dummy board
*/
void UpdateDummyModule( bool aRelaodRequired = true );
};
#endif // PANEL_PREV_MODEL_H
+2 -11
View File
@@ -44,7 +44,7 @@ if( APPLE )
endif()
find_file( S3DSG_VERSION_FILE sg_version.h
PATHS ${CMAKE_SOURCE_DIR}/include/plugins/3dapi NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
PATHS ${CMAKE_SOURCE_DIR}/include/plugins/3dapi NO_DEFAULT_PATH )
if( NOT ${S3DSG_VERSION_FILE} STREQUAL "S3DSG_VERSION_FILE-NOTFOUND" )
@@ -95,17 +95,8 @@ target_compile_definitions( kicad_3dsg PRIVATE -DCOMPILE_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}
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()
+230 -86
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -25,7 +24,6 @@
#include <iostream>
#include <sstream>
#include <fstream>
#include <memory>
#include <wx/filename.h>
#include <wx/log.h>
#include "plugins/3dapi/ifsg_api.h"
@@ -38,6 +36,10 @@
#include "3d_cache/sg/sg_helpers.h"
#ifdef DEBUG
static char BadNode[] = " * [BUG] NULL pointer passed for aNode\n";
#endif
// version format of the cache file
#define SG_VERSION_TAG "VERSION:2"
@@ -71,13 +73,15 @@ static void formatMaterial( SMATERIAL& mat, SGAPPEARANCE const* app )
mat.m_Shininess = app->shininess;
mat.m_Transparency = app->transparency;
return;
}
bool S3D::WriteVRML( const char* filename, bool overwrite, SGNODE* aTopNode,
bool reuse, bool renameNodes )
bool reuse, bool renameNodes )
{
if( nullptr == filename || filename[0] == 0 )
if( NULL == filename || filename[0] == 0 )
return false;
wxString ofile = wxString::FromUTF8Unchecked( filename );
@@ -92,19 +96,46 @@ bool S3D::WriteVRML( const char* filename, bool overwrite, SGNODE* aTopNode,
return false;
}
wxCHECK( aTopNode && aTopNode->GetNodeType() == S3D::SGTYPE_TRANSFORM, false );
if( NULL == aTopNode )
{
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL pointer passed for aTopNode";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return false;
}
if( S3D::SGTYPE_TRANSFORM != aTopNode->GetNodeType() )
{
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] aTopNode is not a SCENEGRAPH object";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return 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 );
wxString errmsg;
errmsg << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
errmsg << " * [INFO] " << "failed to open file" << " '" << filename << "'";
wxLogTrace( MASK_3D_SG, errmsg );
return false;
}
op.imbue( std::locale::classic() );
op.imbue( std::locale( "C" ) );
op << "#VRML V2.0 utf8\n";
if( renameNodes )
@@ -123,8 +154,10 @@ bool S3D::WriteVRML( const char* filename, bool overwrite, SGNODE* aTopNode,
CLOSE_STREAM( op );
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] problems encountered writing file '%s'" ),
__FILE__, __FUNCTION__, __LINE__, filename );
wxString errmsg;
errmsg << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
errmsg << " * [INFO] " << "problems encountered writing file" << " '" << filename << "'";
wxLogTrace( MASK_3D_SG, errmsg );
return false;
}
@@ -132,44 +165,102 @@ bool S3D::WriteVRML( const char* filename, bool overwrite, SGNODE* aTopNode,
void S3D::ResetNodeIndex( SGNODE* aNode )
{
wxCHECK( aNode, /* void */ );
if( NULL == aNode )
{
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadNode;
wxLogTrace( MASK_3D_SG, "%s", ostr.str().c_str() );
} while( 0 );
#endif
return;
}
aNode->ResetNodeIndex();
return;
}
void S3D::RenameNodes( SGNODE* aNode )
{
wxCHECK( aNode, /* void */ );
if( NULL == aNode )
{
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadNode;
wxLogTrace( MASK_3D_SG, "%s", ostr.str().c_str() );
} while( 0 );
#endif
return;
}
aNode->ReNameNodes();
return;
}
void S3D::DestroyNode( SGNODE* aNode ) noexcept
void S3D::DestroyNode( SGNODE* aNode )
{
wxCHECK( aNode, /* void */ );
if( NULL == aNode )
{
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadNode;
wxLogTrace( MASK_3D_SG, "%s", ostr.str().c_str() );
} while( 0 );
#endif
return;
}
delete aNode;
return;
}
bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode,
const char* aPluginInfo )
const char* aPluginInfo )
{
if( nullptr == aFileName || aFileName[0] == 0 )
if( NULL == aFileName || aFileName[0] == 0 )
return false;
wxString ofile = wxString::FromUTF8Unchecked( aFileName );
wxCHECK( aNode, false );
if( NULL == aNode )
{
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadNode;
wxLogTrace( MASK_3D_SG, "%s", ostr.str().c_str() );
} while( 0 );
#endif
return 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 );
wxString errmsg;
errmsg << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
errmsg << " * [INFO] " << "file exists; not overwriting" << " '";
errmsg << aFileName << "'";
wxLogTrace( MASK_3D_SG, errmsg );
return false;
}
@@ -177,9 +268,11 @@ bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode,
// 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 );
wxString errmsg;
errmsg << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
errmsg << " * [INFO] " << "specified path is a directory" << " '";
errmsg << aFileName << "'";
wxLogTrace( MASK_3D_SG, errmsg );
return false;
}
}
@@ -188,27 +281,34 @@ bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode,
if( output.fail() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] failed to open file '%s'" ),
__FILE__, __FUNCTION__, __LINE__, aFileName );
wxString errmsg;
errmsg << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
errmsg << " * [INFO] " << "failed to open file" << " '" << aFileName << "'";
wxLogTrace( MASK_3D_SG, errmsg );
return false;
}
output << "(" << SG_VERSION_TAG << ")";
if( nullptr != aPluginInfo && aPluginInfo[0] != 0 )
if( NULL != aPluginInfo && aPluginInfo[0] != 0 )
output << "(" << aPluginInfo << ")";
else
output << "(INTERNAL:0.0.0.0)";
bool rval = aNode->WriteCache( output, nullptr );
bool rval = aNode->WriteCache( output, NULL );
CLOSE_STREAM( output );
if( !rval )
{
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [INFO] problems encountered writing cache file '%s'" ),
__FILE__, __FUNCTION__, __LINE__, aFileName );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] problems encountered writing cache file '";
ostr << aFileName << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
// delete the defective file
wxRemoveFile( ofile );
@@ -219,31 +319,53 @@ bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode,
SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
bool (*aTagCheck)( const char*, void* ) )
bool (*aTagCheck)( const char*, void* ) )
{
if( nullptr == aFileName || aFileName[0] == 0 )
return nullptr;
if( NULL == aFileName || aFileName[0] == 0 )
return NULL;
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 );
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
wxString errmsg = _( "no such file" );
ostr << " * [INFO] " << errmsg.ToUTF8() << " '";
ostr << aFileName << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
return nullptr;
return NULL;
}
std::unique_ptr<SGNODE> np = std::make_unique<SCENEGRAPH>( nullptr );
SGNODE* np = new SCENEGRAPH( NULL );
if( NULL == np )
{
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] failed to instantiate SCENEGRAPH";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return NULL;
}
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;
delete np;
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
wxString errmsg = _( "failed to open file" );
ostr << " * [INFO] " << errmsg.ToUTF8() << " '";
ostr << aFileName << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
return NULL;
}
// from SG_VERSION_TAG 1, read the version tag; if it's not the expected tag
@@ -256,13 +378,18 @@ SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
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() ) );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; missing left parenthesis at position ";
ostr << file.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
CLOSE_STREAM( file );
return nullptr;
return NULL;
}
file.get( schar );
@@ -276,7 +403,7 @@ SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
if( name.compare( SG_VERSION_TAG ) )
{
CLOSE_STREAM( file );
return nullptr;
return NULL;
}
} while( 0 );
@@ -291,13 +418,18 @@ SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
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() ) );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; missing left parenthesis at position ";
ostr << file.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
CLOSE_STREAM( file );
return nullptr;
return NULL;
}
file.get( schar );
@@ -309,39 +441,40 @@ SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
}
// check the plugin tag
if( nullptr != aTagCheck && nullptr != aPluginMgr
&& !aTagCheck( name.c_str(), aPluginMgr ) )
if( NULL != aTagCheck && NULL != aPluginMgr && !aTagCheck( name.c_str(), aPluginMgr ) )
{
CLOSE_STREAM( file );
return nullptr;
return NULL;
}
} while( 0 );
bool rval = np->ReadCache( file, nullptr );
bool rval = np->ReadCache( file, NULL );
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;
delete np;
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
wxString errmsg = "problems encountered reading cache file";
ostr << " * [INFO] " << errmsg.ToUTF8() << " '";
ostr << aFileName << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
return NULL;
}
return np.release();
return np;
}
S3DMODEL* S3D::GetModel( SCENEGRAPH* aNode )
{
if( nullptr == aNode )
return nullptr;
if( NULL == aNode )
return NULL;
if( aNode->GetNodeType() != S3D::SGTYPE_TRANSFORM )
return nullptr;
return NULL;
S3D::MATLIST materials;
std::vector< SMESH > meshes;
@@ -351,20 +484,20 @@ S3DMODEL* S3D::GetModel( SCENEGRAPH* aNode )
// 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 );
SGAPPEARANCE app( NULL );
app.ambient = SGCOLOR( 0.6, 0.6, 0.6 );
app.diffuse = SGCOLOR( 0.6, 0.6, 0.6 );
app.specular = app.diffuse;
app.shininess = 0.05f;
app.transparency = 0.0f;
app.shininess = 0.05;
app.transparency = 0.0;
materials.matorder.push_back( &app );
materials.matmap.emplace( &app, 0 );
materials.matmap.insert( std::pair< SGAPPEARANCE const*, int >( &app, 0 ) );
if( aNode->Prepare( nullptr, materials, meshes ) )
if( aNode->Prepare( NULL, materials, meshes ) )
{
if( meshes.empty() )
return nullptr;
return NULL;
S3DMODEL* model = S3D::New3DModel();
@@ -396,31 +529,35 @@ S3DMODEL* S3D::GetModel( SCENEGRAPH* aNode )
for( size_t i = 0; i < j; ++i )
S3D::Free3DMesh( meshes[i] );
return nullptr;
return NULL;
}
void S3D::Destroy3DModel( S3DMODEL** aModel )
{
if( nullptr == aModel || nullptr == *aModel )
if( NULL == aModel || NULL == *aModel )
return;
S3DMODEL* m = *aModel;
S3D::FREE_S3DMODEL( *m );
delete m;
*aModel = nullptr;
*aModel = NULL;
return;
}
void Free3DModel( S3DMODEL& aModel )
{
S3D::FREE_S3DMODEL( aModel );
return;
}
void S3D::Free3DMesh( SMESH& aMesh )
{
S3D::FREE_SMESH( aMesh );
return;
}
@@ -435,17 +572,20 @@ S3DMODEL* S3D::New3DModel( void )
void S3D::Init3DMaterial( SMATERIAL& aMat )
{
S3D::INIT_SMATERIAL( aMat );
return;
}
void S3D::Init3DMesh( SMESH& aMesh )
{
S3D::INIT_SMESH( aMesh );
return;
}
void S3D::GetLibVersion( unsigned char* Major, unsigned char* Minor, unsigned char* Patch,
unsigned char* Revision ) noexcept
void S3D::GetLibVersion( unsigned char* Major, unsigned char* Minor,
unsigned char* Patch, unsigned char* Revision )
{
if( Major )
*Major = KICADSG_VERSION_MAJOR;
@@ -458,6 +598,8 @@ void S3D::GetLibVersion( unsigned char* Major, unsigned char* Minor, unsigned ch
if( Patch )
*Patch = KICADSG_VERSION_PATCH;
return;
}
@@ -484,7 +626,7 @@ SGVECTOR S3D::CalcTriNorm( const SGPOINT& p1, const SGPOINT& p2, const SGPOINT&
S3D::SGTYPES S3D::GetSGNodeType( SGNODE* aNode )
{
if( nullptr == aNode )
if( NULL == aNode )
return SGTYPE_END;
return aNode->GetNodeType();
@@ -493,8 +635,8 @@ S3D::SGTYPES S3D::GetSGNodeType( SGNODE* aNode )
SGNODE* S3D::GetSGNodeParent( SGNODE* aNode )
{
if( nullptr == aNode )
return nullptr;
if( NULL == aNode )
return NULL;
return aNode->GetParent();
}
@@ -502,7 +644,7 @@ SGNODE* S3D::GetSGNodeParent( SGNODE* aNode )
bool S3D::AddSGNodeRef( SGNODE* aParent, SGNODE* aChild )
{
if( nullptr == aParent || nullptr == aChild )
if( NULL == aParent || NULL == aChild )
return false;
return aParent->AddRefNode( aChild );
@@ -511,7 +653,7 @@ bool S3D::AddSGNodeRef( SGNODE* aParent, SGNODE* aChild )
bool S3D::AddSGNodeChild( SGNODE* aParent, SGNODE* aChild )
{
if( nullptr == aParent || nullptr == aChild )
if( NULL == aParent || NULL == aChild )
return false;
return aParent->AddChildNode( aChild );
@@ -520,8 +662,10 @@ bool S3D::AddSGNodeChild( SGNODE* aParent, SGNODE* aChild )
void S3D::AssociateSGNodeWrapper( SGNODE* aObject, SGNODE** aRefPtr )
{
if( nullptr == aObject || nullptr == aRefPtr || aObject != *aRefPtr )
if( NULL == aObject || NULL == aRefPtr || aObject != *aRefPtr )
return;
aObject->AssociateWrapper( aRefPtr );
return;
}
+253 -65
View File
@@ -2,7 +2,6 @@
* 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) 2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -30,39 +29,55 @@
#include "3d_cache/sg/sg_appearance.h"
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_APPEARANCE::IFSG_APPEARANCE( bool create )
{
m_node = nullptr;
m_node = NULL;
if( !create )
return ;
m_node = new SGAPPEARANCE( nullptr );
m_node = new SGAPPEARANCE( NULL );
m_node->AssociateWrapper( &m_node );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_APPEARANCE::IFSG_APPEARANCE( SGNODE* aParent )
{
m_node = new SGAPPEARANCE( nullptr );
m_node = new SGAPPEARANCE( NULL );
if( !m_node->SetParent( aParent ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -70,28 +85,39 @@ IFSG_APPEARANCE::IFSG_APPEARANCE( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
#ifdef DEBUG
#ifdef DEBUG
if( ! pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
}
#endif
#endif
m_node = new SGAPPEARANCE( nullptr );
m_node = new SGAPPEARANCE( NULL );
if( !m_node->SetParent( pp ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -100,7 +126,7 @@ bool IFSG_APPEARANCE::Attach( SGNODE* aNode )
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
m_node = NULL;
if( !aNode )
return false;
@@ -126,13 +152,17 @@ bool IFSG_APPEARANCE::NewNode( SGNODE* 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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] invalid SGNODE parent (";
ostr << aParent->GetNodeTypeName( aParent->GetNodeType() );
ostr << ") to SGAPPEARANCE";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
delete m_node;
m_node = nullptr;
m_node = NULL;
return false;
}
@@ -146,7 +176,17 @@ bool IFSG_APPEARANCE::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
if( NULL == np )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return NewNode( np );
}
@@ -154,131 +194,279 @@ bool IFSG_APPEARANCE::NewNode( IFSG_NODE& aParent )
bool IFSG_APPEARANCE::SetEmissive( float aRVal, float aGVal, float aBVal )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject << "\n";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRVal, aGVal, aBVal );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetEmissive( aRVal, aGVal, aBVal );
}
bool IFSG_APPEARANCE::SetEmissive( const SGCOLOR* aRGBColor )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject << "\n";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRGBColor );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetEmissive( aRGBColor );
}
bool IFSG_APPEARANCE::SetEmissive( const SGCOLOR& aRGBColor )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRGBColor );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetEmissive( aRGBColor );
}
bool IFSG_APPEARANCE::SetDiffuse( float aRVal, float aGVal, float aBVal )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRVal, aGVal, aBVal );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetDiffuse( aRVal, aGVal, aBVal );
}
bool IFSG_APPEARANCE::SetDiffuse( const SGCOLOR* aRGBColor )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRGBColor );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetDiffuse( aRGBColor );
}
bool IFSG_APPEARANCE::SetDiffuse( const SGCOLOR& aRGBColor )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRGBColor );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetDiffuse( aRGBColor );
}
bool IFSG_APPEARANCE::SetSpecular( float aRVal, float aGVal, float aBVal )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRVal, aGVal, aBVal );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetSpecular( aRVal, aGVal, aBVal );
}
bool IFSG_APPEARANCE::SetSpecular( const SGCOLOR* aRGBColor )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRGBColor );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetSpecular( aRGBColor );
}
bool IFSG_APPEARANCE::SetSpecular( const SGCOLOR& aRGBColor )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRGBColor );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetSpecular( aRGBColor );
}
bool IFSG_APPEARANCE::SetAmbient( float aRVal, float aGVal, float aBVal )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRVal, aGVal, aBVal );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetAmbient( aRVal, aGVal, aBVal );
}
bool IFSG_APPEARANCE::SetAmbient( const SGCOLOR* aRGBColor )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRGBColor );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetAmbient( aRGBColor );
}
bool IFSG_APPEARANCE::SetAmbient( const SGCOLOR& aRGBColor )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRGBColor );
return false;
}
return ((SGAPPEARANCE*)m_node)->SetAmbient( aRGBColor );
}
bool IFSG_APPEARANCE::SetShininess( float aShininess ) noexcept
bool IFSG_APPEARANCE::SetShininess( float aShininess )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return 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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] shininess out of range [0..1]";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
( (SGAPPEARANCE*) m_node )->shininess = aShininess;
((SGAPPEARANCE*)m_node)->shininess = aShininess;
return true;
}
bool IFSG_APPEARANCE::SetTransparency( float aTransparency ) noexcept
bool IFSG_APPEARANCE::SetTransparency( float aTransparency )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return 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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] transparency out of range [0..1]";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
( (SGAPPEARANCE*) m_node )->transparency = aTransparency;
((SGAPPEARANCE*)m_node)->transparency = aTransparency;
return true;
}
+118 -40
View File
@@ -2,7 +2,6 @@
* 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) 2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -30,38 +29,52 @@
#include "3d_cache/sg/sg_colors.h"
extern char BadObject[];
extern char BadParent[];
extern char WrongParent[];
IFSG_COLORS::IFSG_COLORS( bool create )
{
m_node = nullptr;
m_node = NULL;
if( !create )
return;
return ;
m_node = new SGCOLORS( nullptr );
m_node = new SGCOLORS( NULL );
m_node->AssociateWrapper( &m_node );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_COLORS::IFSG_COLORS( SGNODE* aParent )
{
m_node = new SGCOLORS( nullptr );
m_node = new SGCOLORS( NULL );
if( !m_node->SetParent( aParent ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d" ), __FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -69,29 +82,39 @@ 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 )
#ifdef DEBUG
if( ! pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
}
#endif
#endif
m_node = new SGCOLORS( nullptr );
m_node = new SGCOLORS( NULL );
if( !m_node->SetParent( pp ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -100,7 +123,7 @@ bool IFSG_COLORS::Attach( SGNODE* aNode )
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
m_node = NULL;
if( !aNode )
return false;
@@ -126,12 +149,17 @@ bool IFSG_COLORS::NewNode( SGNODE* 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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] invalid SGNODE parent (";
ostr << aParent->GetNodeTypeName( aParent->GetNodeType() );
ostr << ") to SGCOLORS";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
delete m_node;
m_node = nullptr;
m_node = NULL;
return false;
}
@@ -145,7 +173,17 @@ bool IFSG_COLORS::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
if( NULL == np )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return NewNode( np );
}
@@ -153,17 +191,37 @@ bool IFSG_COLORS::NewNode( IFSG_NODE& aParent )
bool IFSG_COLORS::GetColorList( size_t& aListSize, SGCOLOR*& aColorList )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGCOLORS*) m_node )->GetColorList( aListSize, aColorList );
return false;
}
return ((SGCOLORS*)m_node)->GetColorList( aListSize, aColorList );
}
bool IFSG_COLORS::SetColorList( size_t aListSize, const SGCOLOR* aColorList )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SGCOLORS*) m_node )->SetColorList( aListSize, aColorList );
return false;
}
((SGCOLORS*)m_node)->SetColorList( aListSize, aColorList );
return true;
}
@@ -171,9 +229,19 @@ bool IFSG_COLORS::SetColorList( size_t aListSize, const SGCOLOR* aColorList )
bool IFSG_COLORS::AddColor( double aRedValue, double aGreenValue, double aBlueValue )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SGCOLORS*) m_node )->AddColor( aRedValue, aGreenValue, aBlueValue );
return false;
}
((SGCOLORS*)m_node)->AddColor( aRedValue, aGreenValue, aBlueValue );
return true;
}
@@ -181,9 +249,19 @@ bool IFSG_COLORS::AddColor( double aRedValue, double aGreenValue, double aBlueVa
bool IFSG_COLORS::AddColor( const SGCOLOR& aColor )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SGCOLORS*) m_node )->AddColor( aColor );
return false;
}
((SGCOLORS*)m_node)->AddColor( aColor );
return true;
}
+55 -21
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -31,39 +30,50 @@
#include "3d_cache/sg/sg_coordindex.h"
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_COORDINDEX::IFSG_COORDINDEX( bool create )
{
m_node = nullptr;
m_node = NULL;
if( !create )
return;
m_node = new SGCOORDINDEX( nullptr );
m_node = new SGCOORDINDEX( NULL );
m_node->AssociateWrapper( &m_node );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_COORDINDEX::IFSG_COORDINDEX( SGNODE* aParent )
{
m_node = new SGCOORDINDEX( nullptr );
m_node = new SGCOORDINDEX( NULL );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = nullptr;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -73,25 +83,35 @@ IFSG_COORDINDEX::IFSG_COORDINDEX( IFSG_NODE& aParent )
if( !pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
m_node = new SGCOORDINDEX( nullptr );
m_node = new SGCOORDINDEX( NULL );
if( !m_node->SetParent( pp ) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
delete m_node;
m_node = nullptr;
m_node = NULL;
return;
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -100,7 +120,7 @@ bool IFSG_COORDINDEX::Attach( SGNODE* aNode )
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
m_node = NULL;
if( !aNode )
return false;
@@ -126,13 +146,17 @@ bool IFSG_COORDINDEX::NewNode( SGNODE* 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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] invalid SGNODE parent (";
ostr << aParent->GetNodeTypeName( aParent->GetNodeType() );
ostr << ") to SGCOORDINDEX";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
delete m_node;
m_node = nullptr;
m_node = NULL;
return false;
}
@@ -146,7 +170,17 @@ bool IFSG_COORDINDEX::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
if( NULL == np )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return NewNode( np );
}
+117 -39
View File
@@ -2,7 +2,6 @@
* 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) 2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -30,39 +29,52 @@
#include "3d_cache/sg/sg_coords.h"
extern char BadObject[];
extern char BadParent[];
extern char WrongParent[];
IFSG_COORDS::IFSG_COORDS( bool create )
{
m_node = nullptr;
m_node = NULL;
if( !create )
return ;
m_node = new SGCOORDS( nullptr );
m_node = new SGCOORDS( NULL );
m_node->AssociateWrapper( &m_node );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_COORDS::IFSG_COORDS( SGNODE* aParent )
{
m_node = new SGCOORDS( nullptr );
m_node = new SGCOORDS( NULL );
if( !m_node->SetParent( aParent ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -70,28 +82,39 @@ IFSG_COORDS::IFSG_COORDS( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
#ifdef DEBUG
if( !pp )
#ifdef DEBUG
if( ! pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
}
#endif
#endif
m_node = new SGCOORDS( nullptr );
m_node = new SGCOORDS( NULL );
if( !m_node->SetParent( pp ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -100,7 +123,7 @@ bool IFSG_COORDS::Attach( SGNODE* aNode )
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
m_node = NULL;
if( !aNode )
return false;
@@ -126,12 +149,17 @@ bool IFSG_COORDS::NewNode( SGNODE* 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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] invalid SGNODE parent (";
ostr << aParent->GetNodeTypeName( aParent->GetNodeType() );
ostr << ") to SGCOORDS";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
delete m_node;
m_node = nullptr;
m_node = NULL;
return false;
}
@@ -145,7 +173,17 @@ bool IFSG_COORDS::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
if( NULL == np )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return NewNode( np );
}
@@ -153,17 +191,37 @@ bool IFSG_COORDS::NewNode( IFSG_NODE& aParent )
bool IFSG_COORDS::GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGCOORDS*) m_node )->GetCoordsList( aListSize, aCoordsList );
return false;
}
return ((SGCOORDS*)m_node)->GetCoordsList( aListSize, aCoordsList );
}
bool IFSG_COORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SGCOORDS*) m_node )->SetCoordsList( aListSize, aCoordsList );
return false;
}
((SGCOORDS*)m_node)->SetCoordsList( aListSize, aCoordsList );
return true;
}
@@ -171,9 +229,19 @@ bool IFSG_COORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
bool IFSG_COORDS::AddCoord( double aXValue, double aYValue, double aZValue )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SGCOORDS*) m_node )->AddCoord( aXValue, aYValue, aZValue );
return false;
}
((SGCOORDS*)m_node)->AddCoord( aXValue, aYValue, aZValue );
return true;
}
@@ -181,9 +249,19 @@ bool IFSG_COORDS::AddCoord( double aXValue, double aYValue, double aZValue )
bool IFSG_COORDS::AddCoord( const SGPOINT& aPoint )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SGCOORDS*) m_node )->AddCoord( aPoint );
return false;
}
((SGCOORDS*)m_node)->AddCoord( aPoint );
return true;
}
+69 -31
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -31,39 +30,52 @@
#include "3d_cache/sg/sg_faceset.h"
extern char BadObject[];
extern char BadParent[];
extern char WrongParent[];
IFSG_FACESET::IFSG_FACESET( bool create )
{
m_node = nullptr;
m_node = NULL;
if( !create )
return ;
m_node = new SGFACESET( nullptr );
m_node = new SGFACESET( NULL );
m_node->AssociateWrapper( &m_node );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_FACESET::IFSG_FACESET( SGNODE* aParent )
{
m_node = new SGFACESET( nullptr );
m_node = new SGFACESET( NULL );
if( !m_node->SetParent( aParent ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -71,28 +83,39 @@ IFSG_FACESET::IFSG_FACESET( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
#ifdef DEBUG
#ifdef DEBUG
if( ! pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
}
#endif
#endif
m_node = new SGFACESET( nullptr );
m_node = new SGFACESET( NULL );
if( !m_node->SetParent( pp ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -101,7 +124,7 @@ bool IFSG_FACESET::Attach( SGNODE* aNode )
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
m_node = NULL;
if( !aNode )
return false;
@@ -127,12 +150,17 @@ bool IFSG_FACESET::NewNode( SGNODE* 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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] invalid SGNODE parent (";
ostr << aParent->GetNodeTypeName( aParent->GetNodeType() );
ostr << ") to SGFACESET";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
delete m_node;
m_node = nullptr;
m_node = NULL;
return false;
}
@@ -146,7 +174,17 @@ bool IFSG_FACESET::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
if( NULL == np )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return NewNode( np );
}
@@ -155,7 +193,7 @@ bool IFSG_FACESET::NewNode( IFSG_NODE& aParent )
bool IFSG_FACESET::CalcNormals( SGNODE** aPtr )
{
if( m_node )
return ( (SGFACESET*) m_node )->CalcNormals( aPtr );
return ((SGFACESET*)m_node)->CalcNormals( aPtr );
return false;
}
+43 -7
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -31,24 +30,51 @@
#include "3d_cache/sg/sg_coordindex.h"
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_INDEX::IFSG_INDEX() : IFSG_NODE()
{
return;
}
bool IFSG_INDEX::GetIndices( size_t& nIndices, int*& aIndexList )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGINDEX*) m_node )->GetIndices( nIndices, aIndexList );
return false;
}
return ((SGINDEX*)m_node)->GetIndices( nIndices, aIndexList );
}
bool IFSG_INDEX::SetIndices( size_t nIndices, int* aIndexList )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SGINDEX*) m_node )->SetIndices( nIndices, aIndexList );
return false;
}
((SGINDEX*)m_node)->SetIndices( nIndices, aIndexList );
return true;
}
@@ -56,9 +82,19 @@ bool IFSG_INDEX::SetIndices( size_t nIndices, int* aIndexList )
bool IFSG_INDEX::AddIndex( int aIndex )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SGINDEX*) m_node )->AddIndex( aIndex );
return false;
}
((SGINDEX*)m_node)->AddIndex( aIndex );
return true;
}
+154 -23
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -31,17 +30,15 @@
#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;
m_node = NULL;
}
@@ -49,6 +46,8 @@ IFSG_NODE::~IFSG_NODE()
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
return;
}
@@ -58,11 +57,13 @@ void IFSG_NODE::Destroy( void )
m_node->DisassociateWrapper( &m_node );
delete m_node;
m_node = nullptr;
m_node = NULL;
return;
}
SGNODE* IFSG_NODE::GetRawPtr( void ) noexcept
SGNODE* IFSG_NODE::GetRawPtr( void )
{
return m_node;
}
@@ -70,7 +71,17 @@ SGNODE* IFSG_NODE::GetRawPtr( void ) noexcept
S3D::SGTYPES IFSG_NODE::GetNodeType( void ) const
{
wxCHECK( m_node, S3D::SGTYPE_END );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return S3D::SGTYPE_END;
}
return m_node->GetNodeType();
}
@@ -78,7 +89,17 @@ S3D::SGTYPES IFSG_NODE::GetNodeType( void ) const
SGNODE* IFSG_NODE::GetParent( void ) const
{
wxCHECK( m_node, nullptr );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return NULL;
}
return m_node->GetParent();
}
@@ -86,7 +107,17 @@ SGNODE* IFSG_NODE::GetParent( void ) const
bool IFSG_NODE::SetParent( SGNODE* aParent )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return m_node->SetParent( aParent );
}
@@ -94,40 +125,90 @@ bool IFSG_NODE::SetParent( SGNODE* aParent )
const char* IFSG_NODE::GetName( void )
{
wxCHECK( m_node, nullptr );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return NULL;
}
return m_node->GetName();
}
bool IFSG_NODE::SetName( const char* aName )
bool IFSG_NODE::SetName( const char *aName )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
m_node->SetName( aName );
return true;
}
const char* IFSG_NODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const
const char * IFSG_NODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const
{
wxCHECK( m_node, nullptr );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return NULL;
}
return m_node->GetNodeTypeName( aNodeType );
}
SGNODE* IFSG_NODE::FindNode( const char* aNodeName )
SGNODE* IFSG_NODE::FindNode( const char *aNodeName )
{
wxCHECK( m_node, nullptr );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return m_node->FindNode( aNodeName, nullptr );
return NULL;
}
return m_node->FindNode( aNodeName, NULL );
}
bool IFSG_NODE::AddRefNode( SGNODE* aNode )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return m_node->AddRefNode( aNode );
}
@@ -135,11 +216,31 @@ bool IFSG_NODE::AddRefNode( SGNODE* aNode )
bool IFSG_NODE::AddRefNode( IFSG_NODE& aNode )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
SGNODE* np = aNode.GetRawPtr();
wxCHECK( np, false );
if( NULL == np )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadOperand;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return m_node->AddRefNode( np );
}
@@ -147,7 +248,17 @@ bool IFSG_NODE::AddRefNode( IFSG_NODE& aNode )
bool IFSG_NODE::AddChildNode( SGNODE* aNode )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return m_node->AddChildNode( aNode );
}
@@ -155,11 +266,31 @@ bool IFSG_NODE::AddChildNode( SGNODE* aNode )
bool IFSG_NODE::AddChildNode( IFSG_NODE& aNode )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
SGNODE* np = aNode.GetRawPtr();
wxCHECK( np, false );
if( NULL == np )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadOperand;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return m_node->AddChildNode( np );
}
+117 -38
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -31,39 +30,53 @@
#include "3d_cache/sg/sg_normals.h"
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_NORMALS::IFSG_NORMALS( bool create )
{
m_node = nullptr;
m_node = NULL;
if( !create )
return;
m_node = new SGNORMALS( nullptr );
m_node = new SGNORMALS( NULL );
m_node->AssociateWrapper( &m_node );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_NORMALS::IFSG_NORMALS( SGNODE* aParent )
{
m_node = new SGNORMALS( nullptr );
m_node = new SGNORMALS( NULL );
if( !m_node->SetParent( aParent ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -71,28 +84,39 @@ IFSG_NORMALS::IFSG_NORMALS( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
#ifdef DEBUG
#ifdef DEBUG
if( ! pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
}
#endif
#endif
m_node = new SGNORMALS( nullptr );
m_node = new SGNORMALS( NULL );
if( !m_node->SetParent( pp ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -101,7 +125,7 @@ bool IFSG_NORMALS::Attach( SGNODE* aNode )
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
m_node = NULL;
if( !aNode )
return false;
@@ -127,12 +151,17 @@ bool IFSG_NORMALS::NewNode( SGNODE* 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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] invalid SGNODE parent (";
ostr << aParent->GetNodeTypeName( aParent->GetNodeType() );
ostr << ") to SGNORMALS";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
delete m_node;
m_node = nullptr;
m_node = NULL;
return false;
}
@@ -146,7 +175,17 @@ bool IFSG_NORMALS::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
if( NULL == np )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return NewNode( np );
}
@@ -154,34 +193,74 @@ bool IFSG_NORMALS::NewNode( IFSG_NODE& aParent )
bool IFSG_NORMALS::GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return ( (SGNORMALS*) m_node )->GetNormalList( aListSize, aNormalList );
return false;
}
return ((SGNORMALS*)m_node)->GetNormalList( aListSize, aNormalList );
}
bool IFSG_NORMALS::SetNormalList( size_t aListSize, const SGVECTOR* aNormalList )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SGNORMALS*) m_node )->SetNormalList( aListSize, aNormalList );
return false;
}
((SGNORMALS*)m_node)->SetNormalList( aListSize, aNormalList );
return true;
}
bool IFSG_NORMALS::AddNormal( double aXValue, double aYValue, double aZValue )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SGNORMALS*) m_node )->AddNormal( aXValue, aYValue, aZValue );
return false;
}
((SGNORMALS*)m_node)->AddNormal( aXValue, aYValue, aZValue );
return true;
}
bool IFSG_NORMALS::AddNormal( const SGVECTOR& aNormal )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SGNORMALS*) m_node )->AddNormal( aNormal );
return false;
}
((SGNORMALS*)m_node)->AddNormal( aNormal );
return true;
}
+70 -31
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -31,39 +30,53 @@
#include "3d_cache/sg/sg_shape.h"
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_SHAPE::IFSG_SHAPE( bool create )
{
m_node = nullptr;
m_node = NULL;
if( !create )
return ;
m_node = new SGSHAPE( nullptr );
m_node = new SGSHAPE( NULL );
m_node->AssociateWrapper( &m_node );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_SHAPE::IFSG_SHAPE( SGNODE* aParent )
{
m_node = new SGSHAPE( nullptr );
m_node = new SGSHAPE( NULL );
if( !m_node->SetParent( aParent ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -71,28 +84,39 @@ IFSG_SHAPE::IFSG_SHAPE( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
#ifdef DEBUG
if( !pp )
#ifdef DEBUG
if( ! pp )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
BadParent );
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
}
#endif
#endif
m_node = new SGSHAPE( nullptr );
m_node = new SGSHAPE( NULL );
if( !m_node->SetParent( pp ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -101,7 +125,7 @@ bool IFSG_SHAPE::Attach( SGNODE* aNode )
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
m_node = NULL;
if( !aNode )
return false;
@@ -127,12 +151,17 @@ bool IFSG_SHAPE::NewNode( SGNODE* 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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] invalid SGNODE parent (";
ostr << aParent->GetNodeTypeName( aParent->GetNodeType() );
ostr << ") to SGSHAPE";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
delete m_node;
m_node = nullptr;
m_node = NULL;
return false;
}
@@ -146,7 +175,17 @@ bool IFSG_SHAPE::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
if( NULL == np )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return NewNode( np );
}
+132 -40
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -31,38 +30,52 @@
#include "3d_cache/sg/scenegraph.h"
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_TRANSFORM::IFSG_TRANSFORM( bool create )
{
m_node = nullptr;
m_node = NULL;
if( !create )
return;
m_node = new SCENEGRAPH( nullptr );
m_node = new SCENEGRAPH( NULL );
m_node->AssociateWrapper( &m_node );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_TRANSFORM::IFSG_TRANSFORM( SGNODE* aParent )
{
m_node = new SCENEGRAPH( nullptr );
m_node = new SCENEGRAPH( NULL );
if( !m_node->SetParent( aParent ) )
if( m_node )
{
delete m_node;
m_node = nullptr;
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
WrongParent );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << WrongParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
return;
}
m_node->AssociateWrapper( &m_node );
}
m_node->AssociateWrapper( &m_node );
return;
}
@@ -71,7 +84,7 @@ bool IFSG_TRANSFORM::Attach( SGNODE* aNode )
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = nullptr;
m_node = NULL;
if( !aNode )
return false;
@@ -97,12 +110,17 @@ bool IFSG_TRANSFORM::NewNode( SGNODE* 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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] invalid SGNODE parent (";
ostr << aParent->GetNodeTypeName( aParent->GetNodeType() );
ostr << ") to SCENEGRAPH";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
delete m_node;
m_node = nullptr;
m_node = NULL;
return false;
}
@@ -116,7 +134,17 @@ bool IFSG_TRANSFORM::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
wxCHECK( np, false );
if( NULL == np )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadParent;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return NewNode( np );
}
@@ -124,20 +152,40 @@ bool IFSG_TRANSFORM::NewNode( IFSG_NODE& aParent )
bool IFSG_TRANSFORM::SetRotation( const SGVECTOR& aRotationAxis, double aAngle )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SCENEGRAPH*) m_node )->rotation_axis = aRotationAxis;
( (SCENEGRAPH*) m_node )->rotation_angle = aAngle;
return false;
}
((SCENEGRAPH*)m_node)->rotation_axis = aRotationAxis;
((SCENEGRAPH*)m_node)->rotation_angle = aAngle;
return true;
}
bool IFSG_TRANSFORM::SetScale( const SGPOINT& aScale ) noexcept
bool IFSG_TRANSFORM::SetScale( const SGPOINT& aScale )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SCENEGRAPH*) m_node )->scale = aScale;
return false;
}
((SCENEGRAPH*)m_node)->scale = aScale;
return true;
}
@@ -145,27 +193,51 @@ bool IFSG_TRANSFORM::SetScale( const SGPOINT& aScale ) noexcept
bool IFSG_TRANSFORM::SetScale( double aScale )
{
wxCHECK( m_node, false );
if( aScale < 1e-8 && aScale > -1e-8 )
if( NULL == m_node )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] |scale| is < 1e-8 - this seems strange" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
( (SCENEGRAPH*) m_node )->scale = SGPOINT( aScale, aScale, aScale );
if( aScale < 1e-8 && aScale > -1e-8 )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] |scale| is < 1e-8 - this seems strange";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
((SCENEGRAPH*)m_node)->scale = SGPOINT( aScale, aScale, aScale );
return true;
}
bool IFSG_TRANSFORM::SetTranslation( const SGPOINT& aTranslation ) noexcept
bool IFSG_TRANSFORM::SetTranslation( const SGPOINT& aTranslation )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SCENEGRAPH*) m_node )->translation = aTranslation;
return false;
}
((SCENEGRAPH*)m_node)->translation = aTranslation;
return true;
}
@@ -173,20 +245,40 @@ bool IFSG_TRANSFORM::SetTranslation( const SGPOINT& aTranslation ) noexcept
bool IFSG_TRANSFORM::SetScaleOrientation( const SGVECTOR& aScaleAxis, double aAngle )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SCENEGRAPH*) m_node )->scale_axis = aScaleAxis;
( (SCENEGRAPH*) m_node )->scale_angle = aAngle;
return false;
}
((SCENEGRAPH*)m_node)->scale_axis = aScaleAxis;
((SCENEGRAPH*)m_node)->scale_angle = aAngle;
return true;
}
bool IFSG_TRANSFORM::SetCenter( const SGPOINT& aCenter ) noexcept
bool IFSG_TRANSFORM::SetCenter( const SGPOINT& aCenter )
{
wxCHECK( m_node, false );
if( NULL == m_node )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << BadObject;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
( (SCENEGRAPH*) m_node )->center = aCenter;
return false;
}
((SCENEGRAPH*)m_node)->center = aCenter;
return true;
}
+197 -113
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -45,19 +44,24 @@ SCENEGRAPH::SCENEGRAPH( SGNODE* aParent ) : SGNODE( aParent )
scale.y = 1.0;
scale.z = 1.0;
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
{
m_Parent = nullptr;
m_Parent = NULL;
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] inappropriate parent to SCENEGRAPH (type %d)" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeType() );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] inappropriate parent to SCENEGRAPH (type ";
ostr << aParent->GetNodeType() << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
}
else if( nullptr != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
else if( NULL != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
@@ -70,12 +74,14 @@ SCENEGRAPH::~SCENEGRAPH()
// delete owned objects
DEL_OBJS( SCENEGRAPH, m_Transforms );
DEL_OBJS( SGSHAPE, m_Shape );
return;
}
bool SCENEGRAPH::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
@@ -84,14 +90,14 @@ bool SCENEGRAPH::SetParent( SGNODE* aParent, bool notify )
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
m_Parent = NULL;
if( nullptr == aParent )
if( NULL == aParent )
return true;
}
// only a transform may be parent to a transform
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
return false;
m_Parent = aParent;
@@ -105,8 +111,8 @@ bool SCENEGRAPH::SetParent( SGNODE* aParent, bool notify )
SGNODE* SCENEGRAPH::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
@@ -115,8 +121,8 @@ SGNODE* SCENEGRAPH::FindNode(const char *aNodeName, const SGNODE *aCaller)
FIND_NODE( SGSHAPE, aNodeName, m_Shape, aCaller );
// query the parent if appropriate
if( aCaller == m_Parent || nullptr == m_Parent )
return nullptr;
if( aCaller == m_Parent || NULL == m_Parent )
return NULL;
return m_Parent->FindNode( aNodeName, this );
}
@@ -124,26 +130,33 @@ SGNODE* SCENEGRAPH::FindNode(const char *aNodeName, const SGNODE *aCaller)
void SCENEGRAPH::unlinkNode( const SGNODE* aNode, bool isChild )
{
if( nullptr == aNode )
if( NULL == 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_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;
case S3D::SGTYPE_SHAPE:
UNLINK_NODE( S3D::SGTYPE_SHAPE, SGSHAPE, aNode, m_Shape, m_RShape, isChild );
break;
default:
break;
default:
break;
}
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unlinkNode() did not find its target";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return;
}
@@ -163,16 +176,30 @@ void SCENEGRAPH::unlinkRefNode( const SGNODE* aNode )
bool SCENEGRAPH::addNode( SGNODE* aNode, bool isChild )
{
wxCHECK( aNode, false );
if( NULL == aNode )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL pointer passed for aNode";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return 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() );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] object '" << aNode->GetName();
ostr << "' is not a valid type for this object (" << aNode->GetNodeType() << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return false;
}
@@ -210,7 +237,7 @@ void SCENEGRAPH::ReNameNodes( void )
++sL;
}
} while( 0 );
} while(0);
// rename all transforms
do
@@ -224,13 +251,16 @@ void SCENEGRAPH::ReNameNodes( void )
++sL;
}
} while( 0 );
} while(0);
return;
}
bool SCENEGRAPH::WriteVRML( std::ostream& aFile, bool aReuseFlag )
{
if( m_Transforms.empty() && m_RTransforms.empty() && m_Shape.empty() && m_RShape.empty() )
if( m_Transforms.empty() && m_RTransforms.empty()
&& m_Shape.empty() && m_RShape.empty() )
{
return false;
}
@@ -336,14 +366,14 @@ bool SCENEGRAPH::WriteVRML( std::ostream& aFile, bool aReuseFlag )
bool SCENEGRAPH::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode && nullptr != m_Parent )
if( NULL == parentNode && NULL != m_Parent )
{
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
while( NULL != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
if( np->WriteCache( aFile, NULL ) )
{
m_written = true;
return true;
@@ -352,9 +382,19 @@ bool SCENEGRAPH::WriteCache( std::ostream& aFile, SGNODE* parentNode )
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( parentNode != m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; parentNode != m_aParent";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
if( nullptr == m_Parent )
return false;
}
if( NULL == m_Parent )
{
// ensure unique node names
ResetNodeIndex();
@@ -363,8 +403,12 @@ bool SCENEGRAPH::WriteCache( std::ostream& aFile, SGNODE* parentNode )
if( aFile.fail() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad stream";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -420,9 +464,12 @@ bool SCENEGRAPH::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad stream while writing child transforms";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -430,20 +477,21 @@ bool SCENEGRAPH::WriteCache( std::ostream& aFile, SGNODE* parentNode )
// 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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad stream while writing child shapes";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -451,7 +499,6 @@ bool SCENEGRAPH::WriteCache( std::ostream& aFile, SGNODE* parentNode )
// write referenced transform names
asize = m_RShape.size();
for( i = 0; i < asize; ++i )
aFile << "[" << m_RShape[i]->GetName() << "]";
@@ -465,20 +512,33 @@ bool SCENEGRAPH::WriteCache( std::ostream& aFile, SGNODE* parentNode )
bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( m_Transforms.empty() && m_RTransforms.empty() && m_Shape.empty() && m_RShape.empty(),
false );
if( !m_Transforms.empty() || !m_RTransforms.empty()
|| !m_Shape.empty() || !m_RShape.empty() )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] non-empty node";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
std::string name; // name of the node
if( nullptr == parentNode )
if( NULL == 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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; tag mismatch at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -512,10 +572,13 @@ bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad child transform tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -525,10 +588,13 @@ bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data while reading transform '";
ostr << name << "' pos " << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -539,10 +605,13 @@ bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad ref transform tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -551,20 +620,26 @@ bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: cannot find ref transform '";
ostr << name << "' pos " << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: type is not TRANSFORM '";
ostr << name << "' pos " << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -577,10 +652,13 @@ bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad child shape tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -590,10 +668,13 @@ bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data while reading shape '";
ostr << name << "' pos " << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -604,10 +685,13 @@ bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad ref shape tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -616,20 +700,26 @@ bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: cannot find ref shape '";
ostr << name << "' pos " << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: type is not SGSHAPE '";
ostr << name << "' pos " << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -644,27 +734,21 @@ bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
}
bool SCENEGRAPH::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
std::vector< SMESH >& meshes )
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 ) );
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 ) );
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 ) );
@@ -676,7 +760,7 @@ bool SCENEGRAPH::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
// tx0 = tM * cM * rM * srM * sM * nsrM * ncM
glm::dmat4 tx0;
if( nullptr != aTransform )
if( NULL != aTransform )
tx0 = (*aTransform) * tM * cM * rM * srM * sM * nsrM * ncM;
else
tx0 = tM * cM * rM * srM * sM * nsrM * ncM;
@@ -704,7 +788,7 @@ bool SCENEGRAPH::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
++sL;
}
} while( 0 );
} while(0);
// prepare all transforms
do
@@ -727,7 +811,7 @@ bool SCENEGRAPH::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
++sL;
}
} while( 0 );
} while(0);
return ok;
}
+32 -36
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -24,6 +23,10 @@
/**
* @file scenegraph.h
* defines 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.
*/
@@ -35,18 +38,38 @@
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
{
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
void unlinkNode( const SGNODE* aNode, bool isChild );
bool addNode( SGNODE* aNode, bool isChild );
public:
void unlinkChildNode( const SGNODE* aNode ) override;
void unlinkRefNode( const SGNODE* aNode ) override;
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
SCENEGRAPH( SGNODE* aParent );
virtual ~SCENEGRAPH();
@@ -61,35 +84,8 @@ public:
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
bool Prepare( const glm::dmat4* aTransform,
S3D::MATLIST& materials, std::vector< SMESH >& meshes );
};
/*
+141 -52
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -30,40 +29,46 @@
#include "3d_cache/sg/sg_appearance.h"
#include "3d_cache/sg/sg_helpers.h"
SGAPPEARANCE::SGAPPEARANCE( SGNODE* aParent ) : SGNODE( aParent )
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 );
ambient.SetColor( 0.05317, 0.17879, 0.01804 );
shininess = 0.2;
transparency = 0.0;
diffuse.SetColor( 0.8, 0.8, 0.8 );
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
{
m_Parent = nullptr;
m_Parent = NULL;
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGAPPEARANCE (type %s )" ),
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] inappropriate parent to SGAPPEARANCE (type ";
ostr << aParent->GetNodeType() << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
}
else if( nullptr != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
else if( NULL != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGAPPEARANCE::~SGAPPEARANCE()
{
return;
}
bool SGAPPEARANCE::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
@@ -72,14 +77,14 @@ bool SGAPPEARANCE::SetParent( SGNODE* aParent, bool notify )
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
m_Parent = NULL;
if( nullptr == aParent )
if( NULL == aParent )
return true;
}
// only a SGSHAPE may be parent to a SGAPPEARANCE
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
return false;
m_Parent = aParent;
@@ -99,7 +104,17 @@ bool SGAPPEARANCE::SetEmissive( float aRVal, float aGVal, float aBVal )
bool SGAPPEARANCE::SetEmissive( const SGCOLOR* aRGBColor )
{
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
if( NULL == aRGBColor )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL pointer passed for aRGBColor";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return emissive.SetColor( aRGBColor );
}
@@ -119,7 +134,17 @@ bool SGAPPEARANCE::SetDiffuse( float aRVal, float aGVal, float aBVal )
bool SGAPPEARANCE::SetDiffuse( const SGCOLOR* aRGBColor )
{
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
if( NULL == aRGBColor )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL pointer passed for aRGBColor";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return diffuse.SetColor( aRGBColor );
}
@@ -139,7 +164,17 @@ bool SGAPPEARANCE::SetSpecular( float aRVal, float aGVal, float aBVal )
bool SGAPPEARANCE::SetSpecular( const SGCOLOR* aRGBColor )
{
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
if( NULL == aRGBColor )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL pointer passed for aRGBColor";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return specular.SetColor( aRGBColor );
}
@@ -158,7 +193,17 @@ bool SGAPPEARANCE::SetAmbient( float aRVal, float aGVal, float aBVal )
bool SGAPPEARANCE::SetAmbient( const SGCOLOR* aRGBColor )
{
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
if( NULL == aRGBColor )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL pointer passed for aRGBColor";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
return ambient.SetColor( aRGBColor );
}
@@ -170,46 +215,66 @@ bool SGAPPEARANCE::SetAmbient( const SGCOLOR& aRGBColor )
}
SGNODE* SGAPPEARANCE::FindNode( const char* aNodeName, const SGNODE* aCaller) noexcept
SGNODE* SGAPPEARANCE::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
return nullptr;
return NULL;
}
void SGAPPEARANCE::unlinkChildNode( const SGNODE* aCaller ) noexcept
void SGAPPEARANCE::unlinkChildNode( const SGNODE* aCaller )
{
wxCHECK_MSG( aCaller, /* void */,
wxT( "unexpected code branch; node should have no children or refs" ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unexpected code branch; node should have no children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
void SGAPPEARANCE::unlinkRefNode( const SGNODE* aCaller ) noexcept
void SGAPPEARANCE::unlinkRefNode( const SGNODE* aCaller )
{
wxCHECK_MSG( aCaller, /* void */,
wxT( "unexpected code branch; node should have no children or refs" ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unexpected code branch; node should have no children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
bool SGAPPEARANCE::AddRefNode( SGNODE* aNode ) noexcept
bool SGAPPEARANCE::AddRefNode( SGNODE* aNode )
{
wxCHECK_MSG( aNode, false, wxT( "this node does not accept children or refs" ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] this node does not accept children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
// This is redundant but it keeps gcc from generating a warning on debug builds.
return false;
}
bool SGAPPEARANCE::AddChildNode( SGNODE* aNode ) noexcept
bool SGAPPEARANCE::AddChildNode( SGNODE* aNode )
{
wxCHECK_MSG( aNode, false, wxT( "this node does not accept children or refs" ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] this node does not accept children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
// This is redundant but it keeps gcc from generating a warning on debug builds.
return false;
}
@@ -253,13 +318,13 @@ bool SGAPPEARANCE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
diffuse.GetColor( ambr, ambg, ambb );
float den = ( 0.212671 * ambr + 0.71516 * ambg + 0.072169 * ambb );
if( den < 0.004f )
den = 0.004f;
if( den < 0.004 )
den = 0.004;
amb /= den;
if( amb > 1.0f )
amb = 1.0f;
if( amb > 1.0 )
amb = 1.0;
S3D::FormatFloat( tmp, amb );
aFile << " ambientIntensity " << tmp << "\n";
@@ -303,16 +368,26 @@ bool SGAPPEARANCE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
bool SGAPPEARANCE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
if( NULL == parentNode )
{
wxCHECK_MSG( m_Parent, false, wxT( "corrupt data; m_aParent is NULL" ) );
if( NULL == m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; m_aParent is NULL";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
while( NULL != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
if( np->WriteCache( aFile, NULL ) )
{
m_written = true;
return true;
@@ -321,20 +396,34 @@ bool SGAPPEARANCE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
return false;
}
wxCHECK_MSG( parentNode == m_Parent, false, wxT( "corrupt data; parentNode != m_aParent" ) );
if( parentNode != m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; parentNode != m_aParent";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad stream";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
aFile << "[" << GetName() << "]";
S3D::WriteColor( aFile, ambient );
aFile.write( (char*) &shininess, sizeof( shininess ) );
aFile.write( (char*) &transparency, sizeof( transparency ) );
aFile.write( (char*)&shininess, sizeof(shininess) );
aFile.write( (char*)&transparency, sizeof(transparency) );
S3D::WriteColor( aFile, diffuse );
S3D::WriteColor( aFile, emissive );
S3D::WriteColor( aFile, specular );
@@ -350,8 +439,8 @@ bool SGAPPEARANCE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
bool SGAPPEARANCE::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
S3D::ReadColor( aFile, ambient );
aFile.read( (char*) &shininess, sizeof( shininess ) );
aFile.read( (char*) &transparency, sizeof( transparency ) );
aFile.read( (char*)&shininess, sizeof(shininess) );
aFile.read( (char*)&transparency, sizeof(transparency) );
S3D::ReadColor( aFile, diffuse );
S3D::ReadColor( aFile, emissive );
S3D::ReadColor( aFile, specular );
+14 -17
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -24,6 +23,7 @@
/**
* @file sg_appearance.h
* defines the generic material appearance of a scenegraph object
*/
#ifndef SG_APPEARANCE_H
@@ -31,15 +31,20 @@
#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;
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
void unlinkChildNode( const SGNODE* aNode ) override;
void unlinkRefNode( const SGNODE* aNode ) override;
public:
SGAPPEARANCE( SGNODE* aParent );
virtual ~SGAPPEARANCE();
@@ -61,23 +66,15 @@ public:
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;
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;
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
+96 -32
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -36,14 +35,20 @@ SGCOLOR::SGCOLOR()
red = 0.0;
green = 0.0;
blue = 0.0;
return;
}
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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] invalid value passed to constructor";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
red = 0.0;
green = 0.0;
blue = 0.0;
@@ -53,32 +58,46 @@ SGCOLOR::SGCOLOR( float aRVal, float aGVal, float aBVal )
red = aRVal;
green = aGVal;
blue = aBVal;
return;
}
void SGCOLOR::GetColor( float& aRedVal, float& aGreenVal, float& aBlueVal ) const noexcept
void SGCOLOR::GetColor( float& aRedVal, float& aGreenVal, float& aBlueVal ) const
{
aRedVal = red;
aGreenVal = green;
aBlueVal = blue;
return;
}
void SGCOLOR::GetColor( SGCOLOR& aColor ) const noexcept
void SGCOLOR::GetColor( SGCOLOR& aColor ) const
{
aColor.red = red;
aColor.green = green;
aColor.blue = blue;
return;
}
void SGCOLOR::GetColor( SGCOLOR* aColor ) const noexcept
void SGCOLOR::GetColor( SGCOLOR* aColor ) const
{
wxCHECK_MSG( aColor, /* void */, wxT( "NULL pointer passed for aRGBColor" ) );
if( NULL == aColor )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL pointer passed for aColor";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
aColor->red = red;
aColor->green = green;
aColor->blue = blue;
return;
}
@@ -95,7 +114,7 @@ bool SGCOLOR::SetColor( float aRedVal, float aGreenVal, float aBlueVal )
}
bool SGCOLOR::SetColor( const SGCOLOR& aColor ) noexcept
bool SGCOLOR::SetColor( const SGCOLOR& aColor )
{
red = aColor.red;
green = aColor.green;
@@ -104,9 +123,19 @@ bool SGCOLOR::SetColor( const SGCOLOR& aColor ) noexcept
}
bool SGCOLOR::SetColor( const SGCOLOR* aColor ) noexcept
bool SGCOLOR::SetColor( const SGCOLOR* aColor )
{
wxCHECK_MSG( aColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
if( NULL == aColor )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL pointer passed for aColor";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
red = aColor->red;
green = aColor->green;
@@ -115,31 +144,42 @@ bool SGCOLOR::SetColor( const SGCOLOR* aColor ) noexcept
}
bool SGCOLOR::checkRange( float aRedVal, float aGreenVal, float aBlueVal ) const noexcept
bool SGCOLOR::checkRange( float aRedVal, float aGreenVal, float aBlueVal ) const
{
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] invalid RED value: " << aRedVal;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
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 );
#ifdef DEBUG
if( ok )
{
wxLogTrace( MASK_3D_SG, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__ );
}
wxLogTrace( MASK_3D_SG, " * [BUG] invalid GREEN value: %f\n", aGreenVal );
#endif
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 );
#ifdef DEBUG
if( ok )
{
wxLogTrace( MASK_3D_SG, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__ );
}
wxLogTrace( MASK_3D_SG, " * [BUG] invalid BLUE value: %f\n", aBlueVal );
#endif
ok = false;
}
@@ -152,10 +192,11 @@ SGPOINT::SGPOINT()
x = 0.0;
y = 0.0;
z = 0.0;
return;
}
SGPOINT::SGPOINT( double aXVal, double aYVal, double aZVal ) noexcept
SGPOINT::SGPOINT( double aXVal, double aYVal, double aZVal )
{
x = aXVal;
y = aYVal;
@@ -163,45 +204,60 @@ SGPOINT::SGPOINT( double aXVal, double aYVal, double aZVal ) noexcept
}
void SGPOINT::GetPoint( const double& aXVal, const double& aYVal, const double& aZVal ) noexcept
void SGPOINT::GetPoint( double& aXVal, double& aYVal, double& aZVal )
{
x = aXVal;
y = aYVal;
z = aZVal;
return;
}
void SGPOINT::GetPoint( const SGPOINT& aPoint ) noexcept
void SGPOINT::GetPoint( SGPOINT& aPoint )
{
x = aPoint.x;
y = aPoint.y;
z = aPoint.z;
return;
}
void SGPOINT::GetPoint( const SGPOINT* aPoint ) noexcept
void SGPOINT::GetPoint( SGPOINT* aPoint )
{
wxCHECK_MSG( aPoint, /* void */, wxT( "NULL pointer passed for aPoint" ) );
if( NULL == aPoint )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL pointer passed for aPoint";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
x = aPoint->x;
y = aPoint->y;
z = aPoint->z;
return;
}
void SGPOINT::SetPoint( double aXVal, double aYVal, double aZVal ) noexcept
void SGPOINT::SetPoint( double aXVal, double aYVal, double aZVal )
{
x = aXVal;
y = aYVal;
z = aZVal;
return;
}
void SGPOINT::SetPoint( const SGPOINT& aPoint ) noexcept
void SGPOINT::SetPoint( const SGPOINT& aPoint )
{
x = aPoint.x;
y = aPoint.y;
z = aPoint.z;
return;
}
@@ -210,6 +266,7 @@ SGVECTOR::SGVECTOR()
vx = 0.0;
vy = 0.0;
vz = 1.0;
return;
}
@@ -219,14 +276,16 @@ SGVECTOR::SGVECTOR( double aXVal, double aYVal, double aZVal )
vy = aYVal;
vz = aZVal;
normalize();
return;
}
void SGVECTOR::GetVector( double& aXVal, double& aYVal, double& aZVal ) const noexcept
void SGVECTOR::GetVector( double& aXVal, double& aYVal, double& aZVal ) const
{
aXVal = vx;
aYVal = vy;
aZVal = vz;
return;
}
@@ -236,25 +295,28 @@ void SGVECTOR::SetVector( double aXVal, double aYVal, double aZVal )
vy = aYVal;
vz = aZVal;
normalize();
return;
}
void SGVECTOR::SetVector( const SGVECTOR& aVector )
{
aVector.GetVector( vx, vy, vz );
return;
}
void SGVECTOR::normalize( void ) noexcept
void SGVECTOR::normalize( void )
{
double dx = vx * vx;
double dy = vy * vy;
double dz = vz * vz;
double dv2 = sqrt( dx + dy + dz );
if( ( dx + dy + dz ) < 1e-8 )
if( (dx + dy + dz) < 1e-8 )
{
// use the default; the numbers are too small to be believable
// use the default; the numbers are too small
// to be believable
vx = 0.0;
vy = 0.0;
vz = 1.0;
@@ -264,10 +326,12 @@ void SGVECTOR::normalize( void ) noexcept
vx /= dv2;
vy /= dv2;
vz /= dv2;
return;
}
SGVECTOR& SGVECTOR::operator=( const SGVECTOR& source ) noexcept
SGVECTOR& SGVECTOR::operator=( const SGVECTOR& source )
{
vx = source.vx;
vy = source.vy;
+99 -36
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -29,35 +28,41 @@
#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() )
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = nullptr;
m_Parent = NULL;
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGCOLORS (type %s)" ),
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] inappropriate parent to SGCOLORS (type ";
ostr << aParent->GetNodeType() << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
}
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
else if( NULL != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGCOLORS::~SGCOLORS()
{
colors.clear();
return;
}
bool SGCOLORS::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
@@ -66,14 +71,14 @@ bool SGCOLORS::SetParent( SGNODE* aParent, bool notify )
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
m_Parent = NULL;
if( nullptr == aParent )
if( NULL == aParent )
return true;
}
// only a SGFACESET may be parent to a SGCOLORS
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
@@ -85,41 +90,65 @@ bool SGCOLORS::SetParent( SGNODE* aParent, bool notify )
}
SGNODE* SGCOLORS::FindNode(const char* aNodeName, const SGNODE *aCaller) noexcept
SGNODE* SGCOLORS::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
return nullptr;
return NULL;
}
void SGCOLORS::unlinkChildNode( const SGNODE* aCaller ) noexcept
void SGCOLORS::unlinkChildNode( const SGNODE* aCaller )
{
wxCHECK( aCaller, /* void */ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unexpected code branch; node should have no children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
void SGCOLORS::unlinkRefNode( const SGNODE* aCaller ) noexcept
void SGCOLORS::unlinkRefNode( const SGNODE* aCaller )
{
wxCHECK( aCaller, /* void */ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unexpected code branch; node should have no children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
bool SGCOLORS::AddRefNode( SGNODE* aNode ) noexcept
bool SGCOLORS::AddRefNode( SGNODE* aNode )
{
wxCHECK( aNode, false );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] this node does not accept children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
bool SGCOLORS::AddChildNode( SGNODE* aNode ) noexcept
bool SGCOLORS::AddChildNode( SGNODE* aNode )
{
wxCHECK( aNode, false );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] this node does not accept children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -130,7 +159,7 @@ bool SGCOLORS::GetColorList( size_t& aListSize, SGCOLOR*& aColorList )
if( colors.empty() )
{
aListSize = 0;
aColorList = nullptr;
aColorList = NULL;
return false;
}
@@ -144,7 +173,7 @@ void SGCOLORS::SetColorList( size_t aListSize, const SGCOLOR* aColorList )
{
colors.clear();
if( 0 == aListSize || nullptr == aColorList )
if( 0 == aListSize || NULL == aColorList )
return;
for( size_t i = 0; i < aListSize; ++i )
@@ -156,7 +185,7 @@ void SGCOLORS::SetColorList( size_t aListSize, const SGCOLOR* aColorList )
void SGCOLORS::AddColor( double aRedValue, double aGreenValue, double aBlueValue )
{
colors.emplace_back( aRedValue, aGreenValue, aBlueValue );
colors.push_back( SGCOLOR( aRedValue, aGreenValue, aBlueValue ) );
return;
}
@@ -238,16 +267,26 @@ bool SGCOLORS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
bool SGCOLORS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
if( NULL == parentNode )
{
wxCHECK( m_Parent, false );
if( NULL == m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; m_aParent is NULL";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
while( NULL != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
if( np->WriteCache( aFile, NULL ) )
{
m_written = true;
return true;
@@ -256,12 +295,26 @@ bool SGCOLORS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( parentNode != m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; parentNode != m_aParent";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad stream";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -283,10 +336,20 @@ bool SGCOLORS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
bool SGCOLORS::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( colors.empty(), false );
if( !colors.empty() )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] non-empty node";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
size_t ncolors;
aFile.read( (char*) &ncolors, sizeof( size_t ) );
aFile.read( (char*)&ncolors, sizeof(size_t) );
SGCOLOR tmp;
if( aFile.fail() )
+10 -12
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -24,6 +23,7 @@
/**
* @file sg_colors.h
* defines an RGB color set for a scenegraph object
*/
#ifndef SG_COLORS_H
@@ -32,23 +32,23 @@
#include <vector>
#include "3d_cache/sg/sg_node.h"
/**
* Define an RGB color set for a scenegraph object.
*/
class SGCOLORS : public SGNODE
{
public:
std::vector< SGCOLOR > colors;
void unlinkChildNode( const SGNODE* aNode ) override;
void unlinkRefNode( const SGNODE* aNode ) override;
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;
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) override;
bool AddRefNode( SGNODE* aNode ) override;
bool AddChildNode( SGNODE* aNode ) override;
bool GetColorList( size_t& aListSize, SGCOLOR*& aColorList );
void SetColorList( size_t aListSize, const SGCOLOR* aColorList );
@@ -60,8 +60,6 @@ public:
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
std::vector< SGCOLOR > colors;
};
#endif // SG_COLORS_H
+6 -2
View File
@@ -2,7 +2,6 @@
* 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) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -29,15 +28,18 @@ SGCOORDINDEX::SGCOORDINDEX( SGNODE* aParent ) : SGINDEX( aParent )
{
m_SGtype = S3D::SGTYPE_COORDINDEX;
if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGCOORDINDEX::~SGCOORDINDEX()
{
return;
}
@@ -47,4 +49,6 @@ void SGCOORDINDEX::GatherCoordIndices( std::vector< int >& aIndexList )
return;
aIndexList.insert( aIndexList.end(), index.begin(), index.end() );
return;
}
+12 -8
View File
@@ -2,7 +2,6 @@
* 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) 2020 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
@@ -24,6 +23,7 @@
/**
* @file sg_coordindex.h
* defines an coordinate index set for a scenegraph object
*/
#ifndef SG_COORDINDEX_H
@@ -32,12 +32,14 @@
#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
* is a class which maintains 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
{
@@ -46,7 +48,9 @@ public:
virtual ~SGCOORDINDEX();
/**
* Add all coordinate indices to the given list in preparation for a normals calculation.
* Function GatherCoordIndices
* adds all coordinate indices to the given list
* in preparation for a normals calculation
*/
void GatherCoordIndices( std::vector< int >& aIndexList );
};
+107 -39
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -36,30 +35,37 @@ SGCOORDS::SGCOORDS( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_COORDS;
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = nullptr;
m_Parent = NULL;
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGCOORDS (type %s)" ),
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] inappropriate parent to SGCOORDS (type ";
ostr << aParent->GetNodeType() << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
}
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
else if( NULL != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGCOORDS::~SGCOORDS()
{
coords.clear();
return;
}
bool SGCOORDS::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
@@ -68,14 +74,14 @@ bool SGCOORDS::SetParent( SGNODE* aParent, bool notify )
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
m_Parent = NULL;
if( nullptr == aParent )
if( NULL == aParent )
return true;
}
// only a SGFACESET may be parent to a SGCOORDS
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
@@ -87,41 +93,65 @@ bool SGCOORDS::SetParent( SGNODE* aParent, bool notify )
}
SGNODE* SGCOORDS::FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept
SGNODE* SGCOORDS::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
return nullptr;
return NULL;
}
void SGCOORDS::unlinkChildNode( const SGNODE* aCaller ) noexcept
void SGCOORDS::unlinkChildNode( const SGNODE* aCaller )
{
wxCHECK( aCaller, /* void */ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unexpected code branch; node should have no children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
void SGCOORDS::unlinkRefNode( const SGNODE* aCaller ) noexcept
void SGCOORDS::unlinkRefNode( const SGNODE* aCaller )
{
wxCHECK( aCaller, /* void */ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unexpected code branch; node should have no children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
bool SGCOORDS::AddRefNode( SGNODE* aNode ) noexcept
bool SGCOORDS::AddRefNode( SGNODE* aNode )
{
wxCHECK( aNode, false );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] this node does not accept children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
bool SGCOORDS::AddChildNode( SGNODE* aNode ) noexcept
bool SGCOORDS::AddChildNode( SGNODE* aNode )
{
wxCHECK( aNode, false );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] this node does not accept children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -132,7 +162,7 @@ bool SGCOORDS::GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList )
if( coords.empty() )
{
aListSize = 0;
aCoordsList = nullptr;
aCoordsList = NULL;
return false;
}
@@ -146,23 +176,27 @@ void SGCOORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
{
coords.clear();
if( 0 == aListSize || nullptr == aCoordsList )
if( 0 == aListSize || NULL == aCoordsList )
return;
for( size_t i = 0; i < aListSize; ++i )
coords.push_back( aCoordsList[i] );
return;
}
void SGCOORDS::AddCoord( double aXValue, double aYValue, double aZValue )
{
coords.emplace_back( aXValue, aYValue, aZValue );
coords.push_back( SGPOINT( aXValue, aYValue, aZValue ) );
return;
}
void SGCOORDS::AddCoord( const SGPOINT& aPoint )
{
coords.push_back( aPoint );
return;
}
@@ -240,16 +274,26 @@ bool SGCOORDS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
bool SGCOORDS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
if( NULL == parentNode )
{
wxCHECK( m_Parent, false );
if( NULL == m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; m_aParent is NULL";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
while( NULL != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
if( np->WriteCache( aFile, NULL ) )
{
m_written = true;
return true;
@@ -258,12 +302,26 @@ bool SGCOORDS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( parentNode != m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; parentNode != m_aParent";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad stream";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -285,10 +343,20 @@ bool SGCOORDS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
bool SGCOORDS::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( coords.empty(), false );
if( !coords.empty() )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] non-empty node";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
size_t npts;
aFile.read( (char*) &npts, sizeof( size_t ) );
aFile.read( (char*)&npts, sizeof(size_t) );
SGPOINT tmp;
if( aFile.fail() )
@@ -309,15 +377,15 @@ bool SGCOORDS::ReadCache( std::istream& aFile, SGNODE* parentNode )
bool SGCOORDS::CalcNormals( SGFACESET* callingNode, SGNODE** aPtr )
{
if( aPtr )
*aPtr = nullptr;
*aPtr = NULL;
if( nullptr == m_Parent || nullptr == callingNode )
if( NULL == m_Parent || NULL == 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;
SGNORMALS* np = NULL;
if( callingNode == m_Parent )
{
@@ -333,7 +401,7 @@ bool SGCOORDS::CalcNormals( SGFACESET* callingNode, SGNODE** aPtr )
++sB;
}
np = ( (SGFACESET*) m_Parent )->m_Normals;
np = ((SGFACESET*)m_Parent)->m_Normals;
if( !np )
np = new SGNORMALS( m_Parent );
+14 -15
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -24,6 +23,7 @@
/**
* @file sg_coords.h
* defines a vertex coordinate set for a scenegraph object
*/
#ifndef SG_COORDS_H
@@ -34,23 +34,23 @@
class SGFACESET;
/**
* Define a vertex coordinate set for a scenegraph object.
*/
class SGCOORDS : public SGNODE
{
public:
std::vector< SGPOINT > coords;
void unlinkChildNode( const SGNODE* aNode ) override;
void unlinkRefNode( const SGNODE* aNode ) override;
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;
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) override;
bool AddRefNode( SGNODE* aNode ) override;
bool AddChildNode( SGNODE* aNode ) override;
bool GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList );
void SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList );
@@ -58,18 +58,17 @@ public:
void AddCoord( const SGPOINT& aPoint );
/**
* Calculate normals for this coordinate list and sets the normals list in the
* parent #SGFACESET.
* Function CalcNormals
* calculates normals for this coordinate list and sets the
* normals list in the parent SGFACESET
*/
bool CalcNormals( SGFACESET* callingNode, SGNODE** aPtr = nullptr );
bool CalcNormals( SGFACESET* callingNode, SGNODE** aPtr = NULL );
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
+335 -190
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -34,33 +33,37 @@
#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;
m_Colors = NULL;
m_Coords = NULL;
m_CoordIndices = NULL;
m_Normals = NULL;
m_RColors = NULL;
m_RCoords = NULL;
m_RNormals = NULL;
valid = false;
validated = false;
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
{
m_Parent = nullptr;
m_Parent = NULL;
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGFACESET (type %s)" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeType() );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] inappropriate parent to SGFACESET (type ";
ostr << aParent->GetNodeType() << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
}
else if( nullptr != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
else if( NULL != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
@@ -70,55 +73,57 @@ SGFACESET::~SGFACESET()
if( m_RColors )
{
m_RColors->delNodeRef( this );
m_RColors = nullptr;
m_RColors = NULL;
}
if( m_RCoords )
{
m_RCoords->delNodeRef( this );
m_RCoords = nullptr;
m_RCoords = NULL;
}
if( m_RNormals )
{
m_RNormals->delNodeRef( this );
m_RNormals = nullptr;
m_RNormals = NULL;
}
// delete owned objects
if( m_Colors )
{
m_Colors->SetParent( nullptr, false );
m_Colors->SetParent( NULL, false );
delete m_Colors;
m_Colors = nullptr;
m_Colors = NULL;
}
if( m_Coords )
{
m_Coords->SetParent( nullptr, false );
m_Coords->SetParent( NULL, false );
delete m_Coords;
m_Coords = nullptr;
m_Coords = NULL;
}
if( m_Normals )
{
m_Normals->SetParent( nullptr, false );
m_Normals->SetParent( NULL, false );
delete m_Normals;
m_Normals = nullptr;
m_Normals = NULL;
}
if( m_CoordIndices )
{
m_CoordIndices->SetParent( nullptr, false );
m_CoordIndices->SetParent( NULL, false );
delete m_CoordIndices;
m_CoordIndices = nullptr;
m_CoordIndices = NULL;
}
return;
}
bool SGFACESET::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
@@ -127,14 +132,14 @@ bool SGFACESET::SetParent( SGNODE* aParent, bool notify )
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
m_Parent = NULL;
if( nullptr == aParent )
if( NULL == aParent )
return true;
}
// only a SGSHAPE may be parent to a SGFACESET
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
return false;
m_Parent = aParent;
@@ -148,13 +153,13 @@ bool SGFACESET::SetParent( SGNODE* aParent, bool notify )
SGNODE* SGFACESET::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
SGNODE* np = nullptr;
SGNODE* np = NULL;
if( m_Colors )
{
@@ -189,8 +194,8 @@ SGNODE* SGFACESET::FindNode(const char *aNodeName, const SGNODE *aCaller)
}
// query the parent if appropriate
if( aCaller == m_Parent || nullptr == m_Parent )
return nullptr;
if( aCaller == m_Parent || NULL == m_Parent )
return NULL;
return m_Parent->FindNode( aNodeName, this );
}
@@ -198,7 +203,7 @@ SGNODE* SGFACESET::FindNode(const char *aNodeName, const SGNODE *aCaller)
void SGFACESET::unlinkNode( const SGNODE* aNode, bool isChild )
{
if( nullptr == aNode )
if( NULL == aNode )
return;
valid = false;
@@ -208,25 +213,25 @@ void SGFACESET::unlinkNode( const SGNODE* aNode, bool isChild )
{
if( aNode == m_Colors )
{
m_Colors = nullptr;
m_Colors = NULL;
return;
}
if( aNode == m_Coords )
{
m_Coords = nullptr;
m_Coords = NULL;
return;
}
if( aNode == m_Normals )
{
m_Normals = nullptr;
m_Normals = NULL;
return;
}
if( aNode == m_CoordIndices )
{
m_CoordIndices = nullptr;
m_CoordIndices = NULL;
return;
}
}
@@ -235,46 +240,66 @@ void SGFACESET::unlinkNode( const SGNODE* aNode, bool isChild )
if( aNode == m_RColors )
{
delNodeRef( this );
m_RColors = nullptr;
m_RColors = NULL;
return;
}
if( aNode == m_RCoords )
{
delNodeRef( this );
m_RCoords = nullptr;
m_RCoords = NULL;
return;
}
if( aNode == m_RNormals )
{
delNodeRef( this );
m_RNormals = nullptr;
m_RNormals = NULL;
return;
}
}
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unlinkNode() did not find its target";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return;
}
void SGFACESET::unlinkChildNode( const SGNODE* aNode )
{
unlinkNode( aNode, true );
return;
}
void SGFACESET::unlinkRefNode( const SGNODE* aNode )
{
unlinkNode( aNode, false );
return;
}
bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
{
wxCHECK( aNode, false );
if( NULL == aNode )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL pointer passed for aNode";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
valid = false;
validated = false;
@@ -285,8 +310,12 @@ bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
{
if( aNode != m_Colors && aNode != m_RColors )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] assigning multiple Colors nodes";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -314,8 +343,12 @@ bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
{
if( aNode != m_Coords && aNode != m_RCoords )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] assigning multiple Coords nodes";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -343,8 +376,12 @@ bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
{
if( aNode != m_Normals && aNode != m_RNormals )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Normals nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] assigning multiple Normals nodes";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -372,9 +409,12 @@ bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
{
if( aNode != m_CoordIndices )
{
wxLogTrace( MASK_3D_SG,
wxT( "%s:%s:%d * [BUG] assigning multiple CoordIndex nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] assigning multiple CoordIndex nodes";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -388,11 +428,16 @@ bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
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() );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] object '" << aNode->GetName();
ostr << "' (type " << aNode->GetNodeType();
ostr << ") is not a valid type for this object (" << aNode->GetNodeType() << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return false;
}
@@ -432,12 +477,15 @@ void SGFACESET::ReNameNodes( void )
// rename all Normals and Indices
if( m_Normals )
m_Normals->ReNameNodes();
return;
}
bool SGFACESET::WriteVRML( std::ostream& aFile, bool aReuseFlag )
{
if( ( nullptr == m_Coords && nullptr == m_RCoords ) || ( nullptr == m_CoordIndices ) )
if( ( NULL == m_Coords && NULL == m_RCoords )
|| ( NULL == m_CoordIndices ) )
{
return false;
}
@@ -492,16 +540,26 @@ bool SGFACESET::WriteVRML( std::ostream& aFile, bool aReuseFlag )
bool SGFACESET::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
if( NULL == parentNode )
{
wxCHECK( m_Parent, false );
if( NULL == m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; m_aParent is NULL";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
while( NULL != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
if( np->WriteCache( aFile, NULL ) )
{
m_written = true;
return true;
@@ -510,24 +568,38 @@ bool SGFACESET::WriteCache( std::ostream& aFile, SGNODE* parentNode )
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( parentNode != m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; parentNode != m_aParent";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad stream";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
// check if any references are unwritten and swap parents if so
if( nullptr != m_RCoords && !m_RCoords->isWritten() )
if( NULL != m_RCoords && !m_RCoords->isWritten() )
m_RCoords->SwapParent( this );
if( nullptr != m_RNormals && !m_RNormals->isWritten() )
if( NULL != m_RNormals && !m_RNormals->isWritten() )
m_RNormals->SwapParent( this );
if( nullptr != m_RColors && !m_RColors->isWritten() )
if( NULL != m_RColors && !m_RColors->isWritten() )
m_RColors->SwapParent( this );
aFile << "[" << GetName() << "]";
@@ -539,35 +611,35 @@ bool SGFACESET::WriteCache( std::ostream& aFile, SGNODE* parentNode )
items[i] = 0;
i = 0;
if( nullptr != m_Coords )
if( NULL != m_Coords )
items[i] = true;
++i;
if( nullptr != m_RCoords )
if( NULL != m_RCoords )
items[i] = true;
++i;
if( nullptr != m_CoordIndices )
if( NULL != m_CoordIndices )
items[i] = true;
++i;
if( nullptr != m_Normals )
if( NULL != m_Normals )
items[i] = true;
++i;
if( nullptr != m_RNormals )
if( NULL != m_RNormals )
items[i] = true;
++i;
if( nullptr != m_Colors )
if( NULL != m_Colors )
items[i] = true;
++i;
if( nullptr != m_RColors )
if( NULL != m_RColors )
items[i] = true;
for( int jj = 0; jj < NITEMS; ++jj )
aFile.write( (char*) &items[jj], sizeof( bool ) );
aFile.write( (char*)&items[jj], sizeof(bool) );
if( items[0] )
m_Coords->WriteCache( aFile, this );
@@ -600,11 +672,16 @@ bool SGFACESET::WriteCache( std::ostream& aFile, SGNODE* parentNode )
bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
if( m_Coords || m_RCoords || m_CoordIndices || m_Colors || m_RColors || m_Normals
|| m_RNormals )
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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] non-empty node";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -613,14 +690,18 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
bool items[NITEMS];
for( int i = 0; i < NITEMS; ++i )
aFile.read( (char*) &items[i], sizeof( bool ) );
aFile.read( (char*)&items[i], sizeof(bool) );
if( ( items[0] && items[1] ) || ( items[3] && items[4] ) || ( items[5] && items[6] ) )
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; multiple item definitions at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -631,10 +712,13 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad child coords tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -644,10 +728,13 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data while reading coords '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -657,10 +744,13 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad ref coords tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -669,20 +759,26 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
if( !np )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; cannot find ref "
"coords '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: cannot find ref coords '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: type is not SGCOORDS '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -695,10 +791,13 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad coord index tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -708,10 +807,13 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data while reading coord index '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -721,10 +823,13 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad child normals tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -734,10 +839,13 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data while reading normals '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -747,10 +855,13 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad ref normals tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -759,19 +870,26 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
if( !np )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt: cannot find ref normals "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: cannot find ref normals '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: type is not SGNORMALS '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -784,10 +902,13 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad child colors tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -797,10 +918,13 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data while reading colors '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -810,10 +934,13 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad ref colors tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -822,20 +949,26 @@ bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
if( !np )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref colors "
"'%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: cannot find ref colors '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: type is not SGCOLORS '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -858,14 +991,16 @@ bool SGFACESET::validate( void )
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 ) )
if( (NULL == m_Coords && NULL == m_RCoords)
|| (NULL == m_Normals && NULL == m_RNormals)
|| (NULL == m_CoordIndices) )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; no vertices, vertex indices, "
"or normals" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad model; no vertices, vertex indices, or normals";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
validated = true;
valid = false;
return false;
@@ -874,18 +1009,21 @@ bool SGFACESET::validate( void )
// check that there are >3 vertices
SGCOORDS* coords = m_Coords;
if( nullptr == coords )
if( NULL == coords )
coords = m_RCoords;
size_t nCoords = 0;
SGPOINT* lCoords = nullptr;
SGPOINT* lCoords = NULL;
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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad model; fewer than 3 vertices";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
validated = true;
valid = false;
return false;
@@ -893,15 +1031,17 @@ bool SGFACESET::validate( void )
// check that nVertices is divisible by 3 (facets are triangles)
size_t nCIdx = 0;
int* lCIdx = nullptr;
int* lCIdx = NULL;
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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad model; no vertex indices or not multiple of 3";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
validated = true;
valid = false;
return false;
@@ -912,10 +1052,12 @@ bool SGFACESET::validate( void )
{
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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad model; vertex index out of bounds";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
validated = true;
valid = false;
return false;
@@ -924,22 +1066,23 @@ bool SGFACESET::validate( void )
// check that there are as many normals as vertices
size_t nNorms = 0;
SGVECTOR* lNorms = nullptr;
SGVECTOR* lNorms = NULL;
SGNORMALS* pNorms = m_Normals;
if( nullptr == pNorms )
if( NULL == 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 ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad model; number of normals (" << nNorms;
ostr << ") does not match number of vertices (" << nCoords << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
validated = true;
valid = false;
return false;
@@ -948,14 +1091,14 @@ bool SGFACESET::validate( void )
// if there are colors then ensure there are as many colors as vertices
SGCOLORS* pColors = m_Colors;
if( nullptr == pColors )
if( NULL == pColors )
pColors = m_RColors;
if( nullptr != pColors )
if( NULL != pColors )
{
// we must have at least as many colors as vertices
size_t nColor = 0;
SGCOLOR* pColor = nullptr;
SGCOLOR* pColor = NULL;
pColors->GetColorList( nColor, pColor );
}
@@ -969,6 +1112,8 @@ void SGFACESET::GatherCoordIndices( std::vector< int >& aIndexList )
{
if( m_CoordIndices )
m_CoordIndices->GatherCoordIndices( aIndexList );
return;
}
@@ -979,7 +1124,7 @@ bool SGFACESET::CalcNormals( SGNODE** aPtr )
if( m_RCoords )
coords = m_RCoords;
if( nullptr == coords || coords->coords.empty() )
if( NULL == coords || coords->coords.empty() )
return false;
if( m_Normals && !m_Normals->norms.empty( ) )
+28 -31
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -24,6 +23,7 @@
/**
* @file sg_faceset.h
* defines an indexed face set for a scenegraph
*/
@@ -40,18 +40,38 @@ class SGNORMALS;
class SGCOLORINDEX;
class SGCOORDINDEX;
/**
* Define an indexed face set for a scenegraph.
*/
class SGFACESET : public SGNODE
{
private:
bool valid;
bool validated;
void unlinkNode( const SGNODE* aNode, bool isChild );
bool addNode( SGNODE* aNode, bool isChild );
public:
// 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;
void unlinkChildNode( const SGNODE* aNode ) override;
void unlinkRefNode( const SGNODE* aNode ) override;
// validate the data held by this face set
bool validate( void );
public:
SGFACESET( SGNODE* aParent );
virtual ~SGFACESET();
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
SGNODE* FindNode( const char* aNodeName, const SGNODE* aCaller ) override;
SGNODE* FindNode( const char *aNodeName, const SGNODE *aCaller ) override;
bool AddRefNode( SGNODE* aNode ) override;
bool AddChildNode( SGNODE* aNode ) override;
@@ -64,34 +84,11 @@ public:
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
/**
* Add all internal coordinate indices to the given list in preparation for a normals
* calculation.
* Function GatherCoordIndices
* adds 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 );
};
/*
+109 -60
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -34,6 +33,7 @@
#include "3d_cache/sg/sg_node.h"
// formats a floating point number for text output to a VRML file
void S3D::FormatFloat( std::string& result, double value )
{
if( value < 1e-8 && value > -1e-8 )
@@ -49,9 +49,10 @@ void S3D::FormatFloat( std::string& result, double value )
result = out.str();
size_t p = result.find( '.' );
size_t p = result.find( "." );
// trim trailing 0 if appropriate
if( std::string::npos == p )
return;
@@ -59,26 +60,28 @@ void S3D::FormatFloat( std::string& result, double value )
if( std::string::npos == p )
{
while( '0' == *( result.rbegin() ) )
while( '0' == *(result.rbegin()) )
result.erase( result.size() - 1 );
return;
}
if( '0' != result.at( p - 1 ) )
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() ) )
while( '0' == *(result.rbegin()) )
result.erase( result.size() - 1 );
result.append( tmp );
return;
}
// format orientation data for VRML output
void S3D::FormatOrientation( std::string& result, const SGVECTOR& axis, double rotation )
{
double aX;
@@ -97,9 +100,11 @@ void S3D::FormatOrientation( std::string& result, const SGVECTOR& axis, double r
FormatFloat( tmp, rotation );
result.append( " " );
result.append( tmp );
return;
}
// format point data for VRML output
void S3D::FormatPoint( std::string& result, const SGPOINT& point )
{
FormatFloat( result, point.x );
@@ -112,9 +117,12 @@ void S3D::FormatPoint( std::string& result, const SGPOINT& point )
FormatFloat( tmp, point.z );
result.append( " " );
result.append( tmp );
return;
}
// format vector data for VRML output
void S3D::FormatVector( std::string& result, const SGVECTOR& aVector )
{
double X, Y, Z;
@@ -129,9 +137,12 @@ void S3D::FormatVector( std::string& result, const SGVECTOR& aVector )
FormatFloat( tmp, Z );
result.append( " " );
result.append( tmp );
return;
}
// format Color data for VRML output
void S3D::FormatColor( std::string& result, const SGCOLOR& aColor )
{
float R, G, B;
@@ -146,14 +157,16 @@ void S3D::FormatColor( std::string& result, const SGCOLOR& aColor )
FormatFloat( tmp, B );
result.append( " " );
result.append( tmp );
return;
}
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 ) );
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;
@@ -166,9 +179,9 @@ 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 ) );
aFile.write( (char*)&x, sizeof(double) );
aFile.write( (char*)&y, sizeof(double) );
aFile.write( (char*)&z, sizeof(double) );
if( aFile.fail() )
return false;
@@ -181,9 +194,9 @@ 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 ) );
aFile.write( (char*)&r, sizeof(float) );
aFile.write( (char*)&g, sizeof(float) );
aFile.write( (char*)&b, sizeof(float) );
if( aFile.fail() )
return false;
@@ -199,10 +212,13 @@ S3D::SGTYPES S3D::ReadTag( std::istream& aFile, std::string& aName )
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; missing left bracket at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return S3D::SGTYPE_END;
}
@@ -218,9 +234,12 @@ S3D::SGTYPES S3D::ReadTag( std::istream& aFile, std::string& aName )
if( schar != ']' )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; could not find right "
"bracket" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; could not find right bracket";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return S3D::SGTYPE_END;
}
@@ -230,9 +249,13 @@ S3D::SGTYPES S3D::ReadTag( std::istream& aFile, std::string& aName )
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; no underscore in name '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return S3D::SGTYPE_END;
}
@@ -256,9 +279,15 @@ S3D::SGTYPES S3D::ReadTag( std::istream& aFile, std::string& aName )
return types[i];
}
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; no node type matching '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; no node type matching '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return S3D::SGTYPE_END;
}
@@ -266,9 +295,9 @@ S3D::SGTYPES S3D::ReadTag( std::istream& aFile, std::string& aName )
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 ) );
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;
@@ -280,9 +309,9 @@ bool S3D::ReadPoint( std::istream& aFile, SGPOINT& aPoint )
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 ) );
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() )
@@ -295,9 +324,9 @@ bool S3D::ReadVector( std::istream& aFile, SGVECTOR& aVector )
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 ) );
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() )
@@ -307,7 +336,7 @@ bool S3D::ReadColor( std::istream& aFile, SGCOLOR& aColor )
}
bool S3D::degenerate( glm::dvec3* pts ) noexcept
bool S3D::degenerate( glm::dvec3* pts )
{
double dx, dy, dz;
@@ -347,19 +376,24 @@ static void calcTriad( glm::dvec3* pts, glm::dvec3& tri )
// normal * 2 * area
tri = glm::cross( pts[1] - pts[0], pts[2] - pts[0] );
return;
}
bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >& index,
std::vector< SGVECTOR >& norms )
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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] invalid vertex set (fewer than 3 vertices)";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -368,16 +402,24 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >
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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] invalid index set (not multiple of 3)";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
if( !norms.empty() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] normals set is not empty" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] normals set is not empty";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -393,14 +435,15 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >
p2 = index[i++];
p3 = index[i++];
if( p1 < 0 || p1 >= (int)vsize || p2 < 0 || p2 >= (int)vsize || p3 < 0 || p3 >= (int)vsize )
if( p1 < 0 || p1 >= (int)vsize || p2 < 0 || p2 >= (int)vsize ||
p3 < 0 || p3 >= (int)vsize )
{
#ifdef DEBUG
#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
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -420,7 +463,8 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >
}
else
{
vmap.emplace( p1, std::list < glm::dvec3 >( 1, tri ) );
vmap.insert( std::pair < int, std::list < glm::dvec3 > >
( p1, std::list < glm::dvec3 >( 1, tri ) ) );
}
ip = vmap.find( p2 );
@@ -431,7 +475,8 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >
}
else
{
vmap.emplace( p2, std::list < glm::dvec3 >( 1, tri ) );
vmap.insert( std::pair < int, std::list < glm::dvec3 > >
( p2, std::list < glm::dvec3 >( 1, tri ) ) );
}
ip = vmap.find( p3 );
@@ -442,7 +487,8 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >
}
else
{
vmap.emplace( p3, std::list < glm::dvec3 >( 1, tri ) );
vmap.insert( std::pair < int, std::list < glm::dvec3 > >
( p3, std::list < glm::dvec3 >( 1, tri ) ) );
}
}
@@ -457,7 +503,7 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >
// assign any skipped coordinates a normal of (0,0,1)
while( item > idx )
{
norms.emplace_back( 0, 0, 1 );
norms.push_back( SGVECTOR( 0, 0, 1 ) );
++idx;
}
@@ -471,7 +517,7 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >
++sT;
}
norms.emplace_back( norm.x, norm.y, norm.z );
norms.push_back( SGVECTOR( norm.x, norm.y, norm.z ) );
++idx;
++sM;
@@ -479,9 +525,12 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >
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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] number of normals does not equal number of vertices";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
+121 -147
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -24,10 +23,10 @@
/**
* @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.
* defines a number of macro functions 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
@@ -45,182 +44,151 @@ 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(); \
#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(); \
#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( NULL, 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 )
#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() ) { \
#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( NULL != 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( NULL == 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 )
} */ \
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 )
#define FIND_NODE( aType, aName, aNodeList, aCallingNode ) do { \
std::vector< aType* >::iterator sLA = aNodeList.begin(); \
std::vector< aType* >::iterator eLA = aNodeList.end(); \
SGNODE* psg = NULL; \
while( sLA != eLA ) { \
if( (SGNODE*)*sLA != aCallingNode ) { \
psg = (SGNODE*) (*sLA)->FindNode( aName, this ); \
if( NULL != psg) \
return psg; \
} \
++sLA; \
} } while ( 0 )
namespace S3D
{
bool degenerate( glm::dvec3* pts ) noexcept;
bool degenerate( glm::dvec3* pts );
//
// 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.
* Function CalcTriangleNormals
* takes 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:
* (a) 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.
* (b) 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.
*
* 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.
* @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 );
std::vector< SGVECTOR >& norms );
//
// VRML related functions
//
// formats a floating point number for text output to a VRML file
void FormatFloat( std::string& result, double value );
@@ -250,13 +218,19 @@ namespace S3D
// write out an RGB color
bool WriteColor( std::ostream& aFile, const SGCOLOR& aColor );
//
// Cache related READ functions
//
/**
* Read the text tag of a binary cache file which is the NodeTag and unique ID number combined.
* Function ReadTag
* reads 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.
* @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 );
+109 -40
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -31,27 +30,33 @@
SGINDEX::SGINDEX( SGNODE* aParent ) : SGNODE( aParent )
{
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = nullptr;
m_Parent = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGINDEX (type "
"'%d')" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeType() );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] inappropriate parent to SGINDEX (type ";
ostr << aParent->GetNodeType() << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
}
return;
}
SGINDEX::~SGINDEX()
{
index.clear();
return;
}
bool SGINDEX::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
@@ -60,14 +65,14 @@ bool SGINDEX::SetParent( SGNODE* aParent, bool notify )
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
m_Parent = NULL;
if( nullptr == aParent )
if( NULL == aParent )
return true;
}
// only a SGFACESET may be parent to a SGINDEX and derived types
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
@@ -79,45 +84,65 @@ bool SGINDEX::SetParent( SGNODE* aParent, bool notify )
}
SGNODE* SGINDEX::FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept
SGNODE* SGINDEX::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
return nullptr;
return NULL;
}
void SGINDEX::unlinkChildNode( const SGNODE* aCaller ) noexcept
void SGINDEX::unlinkChildNode( const SGNODE* aCaller )
{
// Node should have no children or refs.
wxCHECK( false, /* void */ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unexpected code branch; node should have no children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
void SGINDEX::unlinkRefNode( const SGNODE* aCaller ) noexcept
void SGINDEX::unlinkRefNode( const SGNODE* aCaller )
{
// Node should have no children or refs.
wxCHECK( false, /* void */ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unexpected code branch; node should have no children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
bool SGINDEX::AddRefNode( SGNODE* aNode ) noexcept
bool SGINDEX::AddRefNode( SGNODE* aNode )
{
// Node should have no children or refs.
wxCHECK( false, false );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] this node does not accept children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
bool SGINDEX::AddChildNode( SGNODE* aNode ) noexcept
bool SGINDEX::AddChildNode( SGNODE* aNode )
{
// Node should have no children or refs.
wxCHECK( false, false );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] this node does not accept children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -128,7 +153,7 @@ bool SGINDEX::GetIndices( size_t& nIndices, int*& aIndexList )
if( index.empty() )
{
nIndices = 0;
aIndexList = nullptr;
aIndexList = NULL;
return false;
}
@@ -142,7 +167,7 @@ void SGINDEX::SetIndices( size_t nIndices, int* aIndexList )
{
index.clear();
if( 0 == nIndices || nullptr == aIndexList )
if( 0 == nIndices || NULL == aIndexList )
return;
for( size_t i = 0; i < nIndices; ++i )
@@ -155,6 +180,7 @@ void SGINDEX::SetIndices( size_t nIndices, int* aIndexList )
void SGINDEX::AddIndex( int aIndex )
{
index.push_back( aIndex );
return;
}
@@ -184,8 +210,17 @@ 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)" ) );
if( n % 3 )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] coord index is not divisible by three (violates triangle constraint)";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
aFile << " coordIndex [\n ";
@@ -261,16 +296,26 @@ bool SGINDEX::writeIndexList( std::ostream& aFile )
bool SGINDEX::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
if( NULL == parentNode )
{
wxCHECK( m_Parent, false );
if( NULL == m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; m_aParent is NULL";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
while( NULL != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
if( np->WriteCache( aFile, NULL ) )
{
m_written = true;
return true;
@@ -279,12 +324,26 @@ bool SGINDEX::WriteCache( std::ostream& aFile, SGNODE* parentNode )
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( parentNode != m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; parentNode != m_aParent";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad stream";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -306,7 +365,17 @@ bool SGINDEX::WriteCache( std::ostream& aFile, SGNODE* parentNode )
bool SGINDEX::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( index.empty(), false );
if( !index.empty() )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] non-empty node";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
size_t npts;
aFile.read( (char*)&npts, sizeof(size_t) );
@@ -317,7 +386,7 @@ bool SGINDEX::ReadCache( std::istream& aFile, SGNODE* parentNode )
for( size_t i = 0; i < npts; ++i )
{
aFile.read( (char*) &tmp, sizeof( int ) );
aFile.read( (char*)&tmp, sizeof(int) );
if( aFile.fail() )
return false;
+51 -52
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -24,6 +23,7 @@
/**
* @file sg_index.h
* defines a generic Index interface for a scenegraph object
*/
#ifndef SG_INDEX_H
@@ -32,59 +32,8 @@
#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 );
@@ -93,6 +42,56 @@ protected:
public:
// for internal SG consumption only
std::vector< int > index;
void unlinkChildNode( const SGNODE* aCaller ) override;
void unlinkRefNode( const SGNODE* aCaller ) override;
public:
SGINDEX( SGNODE* aParent );
virtual ~SGINDEX();
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;
/**
* Function GetIndices
* retrieves 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 [out] will hold the number of indices in the list
* @param aIndexList [out] 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 );
/**
* Function SetIndices
* sets the number of indices and creates a copy of the given index data.
*
* @param nIndices [in] the number of indices to be stored
* @param aIndexList [in] the index data
*/
void SetIndices( size_t nIndices, int* aIndexList );
/**
* Function AddIndex
* adds 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;
};
#endif // SG_INDEX_H
+143 -50
View File
@@ -2,7 +2,6 @@
* 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) 2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -32,7 +31,6 @@
#include "3d_cache/sg/sg_node.h"
#include "plugins/3dapi/c3dmodel.h"
static const std::string node_names[S3D::SGTYPE_END + 1] = {
"TXFM",
"APP",
@@ -50,7 +48,7 @@ static const std::string node_names[S3D::SGTYPE_END + 1] = {
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
char const* S3D::GetNodeTypeName( S3D::SGTYPES aType )
{
return node_names[aType].c_str();
}
@@ -70,15 +68,19 @@ static void getNodeName( S3D::SGTYPES nodeType, std::string& aName )
std::ostringstream ostr;
ostr << node_names[nodeType] << "_" << seqNum;
aName = ostr.str();
return;
}
SGNODE::SGNODE( SGNODE* aParent )
{
m_Parent = aParent;
m_Association = nullptr;
m_Association = NULL;
m_written = false;
m_SGtype = S3D::SGTYPE_END;
return;
}
@@ -88,7 +90,7 @@ SGNODE::~SGNODE()
m_Parent->unlinkChildNode( this );
if( m_Association )
*m_Association = nullptr;
*m_Association = NULL;
std::list< SGNODE* >::iterator sBP = m_BackPointers.begin();
std::list< SGNODE* >::iterator eBP = m_BackPointers.end();
@@ -98,16 +100,18 @@ SGNODE::~SGNODE()
(*sBP)->unlinkRefNode( this );
++sBP;
}
return;
}
S3D::SGTYPES SGNODE::GetNodeType( void ) const noexcept
S3D::SGTYPES SGNODE::GetNodeType( void ) const
{
return m_SGtype;
}
SGNODE* SGNODE::GetParent( void ) const noexcept
SGNODE* SGNODE::GetParent( void ) const
{
return m_Parent;
}
@@ -118,10 +122,10 @@ bool SGNODE::SwapParent( SGNODE* aNewParent )
if( aNewParent == m_Parent )
return true;
if( nullptr == aNewParent )
if( NULL == aNewParent )
return false;
if( nullptr == m_Parent )
if( NULL == m_Parent )
{
if( aNewParent->AddChildNode( this ) )
return true;
@@ -134,7 +138,7 @@ bool SGNODE::SwapParent( SGNODE* aNewParent )
SGNODE* oldParent = m_Parent;
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
m_Parent = NULL;
aNewParent->unlinkRefNode( this );
aNewParent->AddChildNode( this );
oldParent->AddRefNode( this );
@@ -152,16 +156,18 @@ const char* SGNODE::GetName( void )
}
void SGNODE::SetName( const char* aName )
void SGNODE::SetName( const char *aName )
{
if( nullptr == aName || 0 == aName[0] )
if( NULL == aName || 0 == aName[0] )
getNodeName( m_SGtype, m_Name );
else
m_Name = aName;
return;
}
const char* SGNODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const noexcept
const char * SGNODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const
{
return node_names[aNodeType].c_str();
}
@@ -169,7 +175,7 @@ const char* SGNODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const noexcept
void SGNODE::addNodeRef( SGNODE* aNode )
{
if( nullptr == aNode )
if( NULL == aNode )
return;
std::list< SGNODE* >::iterator np =
@@ -179,12 +185,13 @@ void SGNODE::addNodeRef( SGNODE* aNode )
return;
m_BackPointers.push_back( aNode );
return;
}
void SGNODE::delNodeRef( const SGNODE* aNode )
{
if( nullptr == aNode )
if( NULL == aNode )
return;
std::list< SGNODE* >::iterator np =
@@ -196,49 +203,110 @@ void SGNODE::delNodeRef( const SGNODE* aNode )
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() );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] delNodeRef() did not find its target\n";
ostr << " * This Node Type: " << m_SGtype << ", Referenced node type: ";
ostr << aNode->GetNodeType() << "\n";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
void SGNODE::AssociateWrapper( SGNODE** aWrapperRef ) noexcept
void SGNODE::AssociateWrapper( SGNODE** aWrapperRef )
{
wxCHECK( aWrapperRef && *aWrapperRef == this, /* void */ );
if( NULL == aWrapperRef )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL handle";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
if( *aWrapperRef != this )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] handle value does not match this object's pointer";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
// 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;
*m_Association = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [WARNING] association being broken with "
"previous wrapper" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [WARNING] association being broken with previous wrapper";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
}
m_Association = aWrapperRef;
return;
}
void SGNODE::DisassociateWrapper( SGNODE** aWrapperRef ) noexcept
void SGNODE::DisassociateWrapper( SGNODE** aWrapperRef )
{
if( !m_Association )
return;
wxCHECK( aWrapperRef, /* void */ );
if( !aWrapperRef )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] invalid handle value aWrapperRef";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
wxCHECK( *aWrapperRef == *m_Association && aWrapperRef == m_Association, /* void */ );
return;
}
m_Association = nullptr;
if( *aWrapperRef != *m_Association || aWrapperRef != m_Association )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] *aWrapperRef (" << *aWrapperRef;
ostr << ") does not match *m_Association (" << *m_Association << ") in type ";
ostr << node_names[ m_SGtype] << "\n";
ostr << " * [INFO] OR aWrapperRef(" << aWrapperRef << ") != m_Association(";
ostr << m_Association << ")\n";
ostr << " * [INFO] node name: " << GetName();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
m_Association = NULL;
return;
}
void SGNODE::ResetNodeIndex( void ) noexcept
void SGNODE::ResetNodeIndex( void )
{
for( int i = 0; i < (int)S3D::SGTYPE_END; ++i )
node_counts[i] = 1;
return;
}
@@ -246,7 +314,28 @@ bool S3D::GetMatIndex( MATLIST& aList, SGNODE* aNode, int& aIndex )
{
aIndex = 0;
wxCHECK( aNode && S3D::SGTYPE_APPEARANCE == aNode->GetNodeType(), false );
if( NULL == aNode || S3D::SGTYPE_APPEARANCE != aNode->GetNodeType() )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
ostr.str( "" );
if( NULL == aNode )
{
wxLogTrace( MASK_3D_SG, " * [BUG] aNode is NULL\n" );
}
else
{
ostr << " * [BUG] invalid node type (" << aNode->GetNodeType();
ostr << "), expected " << S3D::SGTYPE_APPEARANCE;
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
}
#endif
return false;
}
SGAPPEARANCE* node = (SGAPPEARANCE*)aNode;
@@ -260,7 +349,7 @@ bool S3D::GetMatIndex( MATLIST& aList, SGNODE* aNode, int& aIndex )
int idx = (int)aList.matorder.size();
aList.matorder.push_back( node );
aList.matmap.emplace( node, idx );
aList.matmap.insert( std::pair< SGAPPEARANCE const*, int >( node, idx ) );
aIndex = idx;
return true;
@@ -273,74 +362,78 @@ void S3D::INIT_SMATERIAL( SMATERIAL& aMaterial )
}
void S3D::INIT_SMESH( SMESH& aMesh ) noexcept
void S3D::INIT_SMESH( SMESH& aMesh )
{
aMesh = {};
}
void S3D::INIT_S3DMODEL( S3DMODEL& aModel ) noexcept
void S3D::INIT_S3DMODEL( S3DMODEL& aModel )
{
aModel = {};
}
void S3D::FREE_SMESH( SMESH& aMesh ) noexcept
void S3D::FREE_SMESH( SMESH& aMesh)
{
if( nullptr != aMesh.m_Positions )
if( NULL != aMesh.m_Positions )
{
delete [] aMesh.m_Positions;
aMesh.m_Positions = nullptr;
aMesh.m_Positions = NULL;
}
if( nullptr != aMesh.m_Normals )
if( NULL != aMesh.m_Normals )
{
delete [] aMesh.m_Normals;
aMesh.m_Normals = nullptr;
aMesh.m_Normals = NULL;
}
if( nullptr != aMesh.m_Texcoords )
if( NULL != aMesh.m_Texcoords )
{
delete [] aMesh.m_Texcoords;
aMesh.m_Texcoords = nullptr;
aMesh.m_Texcoords = NULL;
}
if( nullptr != aMesh.m_Color )
if( NULL != aMesh.m_Color )
{
delete [] aMesh.m_Color;
aMesh.m_Color = nullptr;
aMesh.m_Color = NULL;
}
if( nullptr != aMesh.m_FaceIdx )
if( NULL != aMesh.m_FaceIdx )
{
delete [] aMesh.m_FaceIdx;
aMesh.m_FaceIdx = nullptr;
aMesh.m_FaceIdx = NULL;
}
aMesh.m_VertexSize = 0;
aMesh.m_FaceIdxSize = 0;
aMesh.m_MaterialIdx = 0;
return;
}
void S3D::FREE_S3DMODEL( S3DMODEL& aModel )
{
if( nullptr != aModel.m_Materials )
if( NULL != aModel.m_Materials )
{
delete [] aModel.m_Materials;
aModel.m_Materials = nullptr;
aModel.m_Materials = NULL;
}
aModel.m_MaterialsSize = 0;
if( nullptr != aModel.m_Meshes )
if( NULL != 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_Meshes = NULL;
}
aModel.m_MeshesSize = 0;
return;
}
+121 -107
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -24,6 +23,7 @@
/**
* @file sg_node.h
* defines the base class of the intermediate scene graph NODE
*/
@@ -47,9 +47,10 @@ class SGAPPEARANCE;
namespace S3D
{
/**
* Return the name of the given type of node
* Function GetNodeTypeName
* returns the name of the given type of node
*/
char const* GetNodeTypeName( S3D::SGTYPES aType ) noexcept;
char const* GetNodeTypeName( S3D::SGTYPES aType );
struct MATLIST
{
@@ -60,67 +61,129 @@ namespace S3D
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 INIT_SMESH( SMESH& aMesh );
void INIT_S3DMODEL( S3DMODEL& aModel );
void FREE_SMESH( SMESH& aMesh) noexcept;
void FREE_SMESH( SMESH& aMesh);
void FREE_S3DMODEL( S3DMODEL& aModel );
}
/**
* The base class of all Scene Graph nodes.
* Class SGNODE
* represents the base class of all Scene Graph nodes
*/
class SGNODE
{
private:
SGNODE** m_Association; // handle to the instance held by a wrapper
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 SG node
std::string m_Name; // name to use for referencing the entity by name
bool m_written; // set true when the object has been written after a ReNameNodes()
public:
/**
* Function unlinkChild
* removes references to an owned child; it 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;
/**
* Function unlinkRef
* removes pointers to a referenced node; it 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;
/**
* Function addNodeRef
* adds a pointer to a node which references, but does not own, this node.
* 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 );
/**
* Function delNodeRef
* removes a pointer to a node which references, but does not own, this node.
*
* @param aNode is the node holding a reference to this object
*/
void delNodeRef( const SGNODE* aNode );
/**
* Function IsWritten
* returns true if the object had already been written to a
* cache file or VRML file; for internal use only.
*/
bool isWritten( void )
{
return m_written;
}
public:
SGNODE( SGNODE* aParent );
virtual ~SGNODE();
/**
* Return the type of this node instance.
* Function GetNodeType
* returns the type of this node instance
*/
S3D::SGTYPES GetNodeType( void ) const noexcept;
S3D::SGTYPES GetNodeType( void ) const;
/**
* Returns a pointer to the parent SGNODE of this object or NULL if the object has
* no parent (ie. top level transform).
* Function GetParent
* 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;
SGNODE* GetParent( void ) const;
/**
* Set the parent #SGNODE of this object.
* Function SetParent
* sets 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.
* @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.
* Function SwapParent
* swaps the ownership with the given parent. This operation
* may be required when reordering nodes for optimization.
*
* 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.
* @param aNewParent [in] 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;
const char * GetNodeTypeName( S3D::SGTYPES aNodeType ) const;
/**
* Search the tree of linked nodes and return a reference to the first node found with
* the given name.
* Function FindNode searches the tree of linked nodes and returns a
* reference to the first node found with the given name. The reference
* is then typically added to another node via AddRefNode().
*
* 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.
* @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;
@@ -129,108 +192,59 @@ public:
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.
* Function AssociateWrapper
* associates this object with a handle to itself; this 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;
void AssociateWrapper( SGNODE** aWrapperRef );
/**
* Remove the association between an IFSG* wrapper object and this object.
* Function DisassociateWrapper
* removes the association between an IFSG* wrapper
* object and this object.
*/
void DisassociateWrapper( SGNODE** aWrapperRef ) noexcept;
void DisassociateWrapper( SGNODE** aWrapperRef );
/**
* Reset the global SG* node indices in preparation for write operations.
* Function ResetNodeIndex
* resets the global SG* node indices in preparation for
* Write() operations
*/
void ResetNodeIndex( void ) noexcept;
void ResetNodeIndex( void );
/**
* Rename a node and all its child nodes in preparation for write operations.
* Function ReNameNodes
* renames 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.
* Function WriteVRML
* 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.
* Function WriteCache
* write's 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.
* Function ReadCache
* 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
+103 -36
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -34,31 +33,37 @@ SGNORMALS::SGNORMALS( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_NORMALS;
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = nullptr;
m_Parent = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGNORMALS "
"(type %d)" ),
__FILE__, __FUNCTION__, __LINE__,
aParent->GetNodeType() );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] inappropriate parent to SGNORMALS (type ";
ostr << aParent->GetNodeType() << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
}
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
else if( NULL != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGNORMALS::~SGNORMALS()
{
norms.clear();
return;
}
bool SGNORMALS::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
@@ -67,14 +72,14 @@ bool SGNORMALS::SetParent( SGNODE* aParent, bool notify )
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
m_Parent = NULL;
if( nullptr == aParent )
if( NULL == aParent )
return true;
}
// only a SGFACESET may be parent to a SGNORMALS
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
@@ -86,41 +91,65 @@ bool SGNORMALS::SetParent( SGNODE* aParent, bool notify )
}
SGNODE* SGNORMALS::FindNode( const char* aNodeName, const SGNODE* aCaller ) noexcept
SGNODE* SGNORMALS::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
return nullptr;
return NULL;
}
void SGNORMALS::unlinkChildNode( const SGNODE* aCaller ) noexcept
void SGNORMALS::unlinkChildNode( const SGNODE* aCaller )
{
wxCHECK( false, /* void */ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unexpected code branch; node should have no children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
void SGNORMALS::unlinkRefNode( const SGNODE* aCaller ) noexcept
void SGNORMALS::unlinkRefNode( const SGNODE* aCaller )
{
wxCHECK( false, /* void */ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unexpected code branch; node should have no children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return;
}
bool SGNORMALS::AddRefNode( SGNODE* aNode ) noexcept
bool SGNORMALS::AddRefNode( SGNODE* aNode )
{
wxCHECK( false, false );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] this node does not accept children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
bool SGNORMALS::AddChildNode( SGNODE* aNode ) noexcept
bool SGNORMALS::AddChildNode( SGNODE* aNode )
{
wxCHECK( false, false );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] this node does not accept children or refs";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -131,7 +160,7 @@ bool SGNORMALS::GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList )
if( norms.empty() )
{
aListSize = 0;
aNormalList = nullptr;
aNormalList = NULL;
return false;
}
@@ -145,23 +174,27 @@ void SGNORMALS::SetNormalList( size_t aListSize, const SGVECTOR* aNormalList )
{
norms.clear();
if( 0 == aListSize || nullptr == aNormalList )
if( 0 == aListSize || NULL == aNormalList )
return;
for( int i = 0; i < (int)aListSize; ++i )
norms.push_back( aNormalList[i] );
return;
}
void SGNORMALS::AddNormal( double aXValue, double aYValue, double aZValue )
{
norms.emplace_back( aXValue, aYValue, aZValue );
norms.push_back( SGVECTOR( aXValue, aYValue, aZValue ) );
return;
}
void SGNORMALS::AddNormal( const SGVECTOR& aNormal )
{
norms.push_back( aNormal );
return;
}
@@ -233,16 +266,26 @@ bool SGNORMALS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
bool SGNORMALS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
if( NULL == parentNode )
{
wxCHECK( m_Parent, false );
if( NULL == m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; m_aParent is NULL";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
while( NULL != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
if( np->WriteCache( aFile, NULL ) )
{
m_written = true;
return true;
@@ -251,12 +294,26 @@ bool SGNORMALS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( parentNode != m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; parentNode != m_aParent";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad stream";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -278,10 +335,20 @@ bool SGNORMALS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
bool SGNORMALS::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( norms.empty(), false );
if( !norms.empty() )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] non-empty node";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
size_t npts;
aFile.read( (char*) &npts, sizeof( size_t ) );
aFile.read( (char*)&npts, sizeof(size_t) );
SGVECTOR tmp;
if( aFile.fail() )
+10 -12
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -24,6 +23,7 @@
/**
* @file sg_normals.h
* defines a set of vertex normals for a scene graph object
*/
#ifndef SG_NORMALS_H
@@ -32,20 +32,23 @@
#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:
std::vector< SGVECTOR > norms;
void unlinkChildNode( const SGNODE* aNode ) override;
void unlinkRefNode( const SGNODE* aNode ) override;
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;
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) override;
bool AddRefNode( SGNODE* aNode ) override;
bool AddChildNode( SGNODE* aNode ) override;
bool GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList );
void SetNormalList( size_t aListSize, const SGVECTOR* aNormalList );
@@ -57,11 +60,6 @@ public:
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
+249 -132
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -40,22 +39,29 @@
SGSHAPE::SGSHAPE( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_SHAPE;
m_Appearance = nullptr;
m_RAppearance = nullptr;
m_FaceSet = nullptr;
m_RFaceSet = nullptr;
m_Appearance = NULL;
m_RAppearance = NULL;
m_FaceSet = NULL;
m_RFaceSet = NULL;
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
{
m_Parent = nullptr;
m_Parent = NULL;
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGSHAPE (type %d)" ),
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] inappropriate parent to SGSHAPE (type ";
ostr << aParent->GetNodeType() << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
}
else if( nullptr != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
else if( NULL != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
@@ -65,35 +71,37 @@ SGSHAPE::~SGSHAPE()
if( m_RAppearance )
{
m_RAppearance->delNodeRef( this );
m_RAppearance = nullptr;
m_RAppearance = NULL;
}
if( m_RFaceSet )
{
m_RFaceSet->delNodeRef( this );
m_RFaceSet = nullptr;
m_RFaceSet = NULL;
}
// delete objects
if( m_Appearance )
{
m_Appearance->SetParent( nullptr, false );
m_Appearance->SetParent( NULL, false );
delete m_Appearance;
m_Appearance = nullptr;
m_Appearance = NULL;
}
if( m_FaceSet )
{
m_FaceSet->SetParent( nullptr, false );
m_FaceSet->SetParent( NULL, false );
delete m_FaceSet;
m_FaceSet = nullptr;
m_FaceSet = NULL;
}
return;
}
bool SGSHAPE::SetParent( SGNODE* aParent, bool notify )
{
if( nullptr != m_Parent )
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
@@ -102,14 +110,14 @@ bool SGSHAPE::SetParent( SGNODE* aParent, bool notify )
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = nullptr;
m_Parent = NULL;
if( nullptr == aParent )
if( NULL == aParent )
return true;
}
// only a SGTRANSFORM may be parent to a SGSHAPE
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
if( NULL != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
return false;
m_Parent = aParent;
@@ -121,17 +129,17 @@ bool SGSHAPE::SetParent( SGNODE* aParent, bool notify )
}
SGNODE* SGSHAPE::FindNode( const char* aNodeName, const SGNODE* aCaller )
SGNODE* SGSHAPE::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( nullptr == aNodeName || 0 == aNodeName[0] )
return nullptr;
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
SGNODE* tmp = nullptr;
SGNODE* tmp = NULL;
if( nullptr != m_Appearance )
if( NULL != m_Appearance )
{
tmp = m_Appearance->FindNode( aNodeName, this );
@@ -141,7 +149,7 @@ SGNODE* SGSHAPE::FindNode( const char* aNodeName, const SGNODE* aCaller )
}
}
if( nullptr != m_FaceSet )
if( NULL != m_FaceSet )
{
tmp = m_FaceSet->FindNode( aNodeName, this );
@@ -152,8 +160,8 @@ SGNODE* SGSHAPE::FindNode( const char* aNodeName, const SGNODE* aCaller )
}
// query the parent if appropriate
if( aCaller == m_Parent || nullptr == m_Parent )
return nullptr;
if( aCaller == m_Parent || NULL == m_Parent )
return NULL;
return m_Parent->FindNode( aNodeName, this );
}
@@ -161,20 +169,20 @@ SGNODE* SGSHAPE::FindNode( const char* aNodeName, const SGNODE* aCaller )
void SGSHAPE::unlinkNode( const SGNODE* aNode, bool isChild )
{
if( nullptr == aNode )
if( NULL == aNode )
return;
if( isChild )
{
if( aNode == m_Appearance )
{
m_Appearance = nullptr;
m_Appearance = NULL;
return;
}
if( aNode == m_FaceSet )
{
m_FaceSet = nullptr;
m_FaceSet = NULL;
return;
}
}
@@ -183,38 +191,58 @@ void SGSHAPE::unlinkNode( const SGNODE* aNode, bool isChild )
if( aNode == m_RAppearance )
{
delNodeRef( this );
m_RAppearance = nullptr;
m_RAppearance = NULL;
return;
}
if( aNode == m_RFaceSet )
{
delNodeRef( this );
m_RFaceSet = nullptr;
m_RFaceSet = NULL;
return;
}
}
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] unlinkNode() did not find its target";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return;
}
void SGSHAPE::unlinkChildNode( const SGNODE* aNode )
{
unlinkNode( aNode, true );
return;
}
void SGSHAPE::unlinkRefNode( const SGNODE* aNode )
{
unlinkNode( aNode, false );
return;
}
bool SGSHAPE::addNode( SGNODE* aNode, bool isChild )
{
wxCHECK( aNode, false );
if( NULL == aNode )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] NULL pointer passed for aNode";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
if( S3D::SGTYPE_APPEARANCE == aNode->GetNodeType() )
{
@@ -222,9 +250,12 @@ bool SGSHAPE::addNode( SGNODE* aNode, bool isChild )
{
if( aNode != m_Appearance && aNode != m_RAppearance )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Appearance "
"nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] assigning multiple Appearance nodes";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -252,8 +283,12 @@ bool SGSHAPE::addNode( SGNODE* aNode, bool isChild )
{
if( aNode != m_FaceSet && aNode != m_RFaceSet )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple FaceSet nodes" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] assigning multiple FaceSet nodes";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -275,9 +310,15 @@ bool SGSHAPE::addNode( SGNODE* aNode, bool isChild )
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() );
#ifdef DEBUG
do {
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] object '" << aNode->GetName();
ostr << "' is not a valid type for this object (" << aNode->GetNodeType() << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
} while( 0 );
#endif
return false;
}
@@ -310,12 +351,15 @@ void SGSHAPE::ReNameNodes( void )
// rename FaceSet
if( m_FaceSet )
m_FaceSet->ReNameNodes();
return;
}
bool SGSHAPE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
{
if( !m_Appearance && !m_RAppearance && !m_FaceSet && !m_RFaceSet )
if( !m_Appearance && !m_RAppearance
&& !m_FaceSet && !m_RFaceSet )
{
return false;
}
@@ -358,16 +402,26 @@ bool SGSHAPE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
bool SGSHAPE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
{
if( nullptr == parentNode )
if( NULL == parentNode )
{
wxCHECK( m_Parent, false );
if( NULL == m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; m_aParent is NULL";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
SGNODE* np = m_Parent;
while( nullptr != np->GetParent() )
while( NULL != np->GetParent() )
np = np->GetParent();
if( np->WriteCache( aFile, nullptr ) )
if( np->WriteCache( aFile, NULL ) )
{
m_written = true;
return true;
@@ -376,21 +430,35 @@ bool SGSHAPE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
return false;
}
wxCHECK( parentNode == m_Parent, false );
if( parentNode != m_Parent )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] corrupt data; parentNode != m_aParent";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
if( !aFile.good() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] bad stream" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad stream";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
// check if any references are unwritten and swap parents if so
if( nullptr != m_RAppearance && !m_RAppearance->isWritten() )
if( NULL != m_RAppearance && !m_RAppearance->isWritten() )
m_RAppearance->SwapParent(this);
if( nullptr != m_RFaceSet && !m_RFaceSet->isWritten() )
if( NULL != m_RFaceSet && !m_RFaceSet->isWritten() )
m_RFaceSet->SwapParent( this );
aFile << "[" << GetName() << "]";
@@ -402,23 +470,19 @@ bool SGSHAPE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
items[i] = 0;
i = 0;
if( nullptr != m_Appearance )
if( NULL != m_Appearance )
items[i] = true;
++i;
if( nullptr != m_RAppearance )
if( NULL != m_RAppearance )
items[i] = true;
++i;
if( nullptr != m_FaceSet )
if( NULL != m_FaceSet )
items[i] = true;
++i;
if( nullptr != m_RFaceSet )
if( NULL != m_RFaceSet )
items[i] = true;
for( int jj = 0; jj < NITEMS; ++jj )
@@ -446,8 +510,17 @@ bool SGSHAPE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
wxCHECK( m_Appearance == nullptr && m_RAppearance == nullptr && m_FaceSet == nullptr &&
m_RFaceSet == nullptr, false );
if( m_Appearance || m_RAppearance || m_FaceSet || m_RFaceSet )
{
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [BUG] non-empty node";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
#define NITEMS 4
bool items[NITEMS];
@@ -457,10 +530,13 @@ bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; multiple item definitions at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -471,10 +547,13 @@ bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad child apperance tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -484,9 +563,13 @@ bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data while reading appearance '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -496,10 +579,13 @@ bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad ref appearance tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -508,20 +594,26 @@ bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
if( !np )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref "
"appearance '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: cannot find ref appearance '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: type is not SGAPPEARANCE '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -534,10 +626,13 @@ bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad child face set tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -547,9 +642,13 @@ bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data while reading face set '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -559,10 +658,13 @@ bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
{
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() ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data; bad ref face set tag at position ";
ostr << aFile.tellg();
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -571,20 +673,26 @@ bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
if( !np )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref face "
"set '%s'" ),
__FILE__, __FUNCTION__, __LINE__,
name );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: cannot find ref face set '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
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 );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] corrupt data: type is not SGFACESET '";
ostr << name << "'";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return false;
}
@@ -600,8 +708,8 @@ bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
}
bool SGSHAPE::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
std::vector< SMESH >& meshes )
bool SGSHAPE::Prepare( const glm::dmat4* aTransform,
S3D::MATLIST& materials, std::vector< SMESH >& meshes )
{
SMESH m;
S3D::INIT_SMESH( m );
@@ -609,25 +717,28 @@ bool SGSHAPE::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
SGAPPEARANCE* pa = m_Appearance;
SGFACESET* pf = m_FaceSet;
if( nullptr == pa )
if( NULL == pa )
pa = m_RAppearance;
if( nullptr == pf )
if( NULL == pf )
pf = m_RFaceSet;
// no face sets = nothing to render, which is valid though pointless
if( nullptr == pf )
if( NULL == pf )
return true;
if( !pf->validate() )
{
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; inconsistent data" ),
__FILE__, __FUNCTION__, __LINE__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad model; inconsistent data";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return true;
}
if( nullptr == pa )
if( NULL == pa )
{
m.m_MaterialIdx = 0;
}
@@ -650,22 +761,22 @@ bool SGSHAPE::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
SGCOORDINDEX* vidx = pf->m_CoordIndices;
SGNORMALS* pn = pf->m_Normals;
if( nullptr == pc )
if( NULL == pc )
pc = pf->m_RColors;
if( nullptr == pv )
if( NULL == pv )
pv = pf->m_RCoords;
if( nullptr == pn )
if( NULL == pn )
pn = pf->m_RNormals;
// set the vertex points and indices
size_t nCoords = 0;
SGPOINT* pCoords = nullptr;
SGPOINT* pCoords = NULL;
pv->GetCoordsList( nCoords, pCoords );
size_t nColors = 0;
SGCOLOR* pColors = nullptr;
SGCOLOR* pColors = NULL;
if( pc )
{
@@ -674,18 +785,20 @@ bool SGSHAPE::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
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 ) );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad model; not enough colors per vertex (";
ostr << nColors << " vs " << nCoords << ")";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return true;
}
}
// set the vertex indices
size_t nvidx = 0;
int* lv = nullptr;
int* lv = NULL;
vidx->GetIndices( nvidx, lv );
// note: reduce the vertex set to include only the referenced vertices
@@ -699,21 +812,24 @@ bool SGSHAPE::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
if( mit == indexmap.end() )
{
indexmap.emplace( lv[i], vertices.size() );
indexmap.insert( std::pair< int, unsigned int >( 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__ );
#ifdef DEBUG
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
ostr << " * [INFO] bad model; not enough vertices";
wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
#endif
return true;
}
// construct the final vertex/color list
SFVEC3F* lColors = nullptr;
SFVEC3F* lColors = NULL;
SFVEC3F* lCoords = new SFVEC3F[ vertices.size() ];
int ti;
@@ -723,6 +839,7 @@ bool SGSHAPE::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
m.m_Color = lColors;
}
if( pc )
{
for( size_t i = 0; i < vertices.size(); ++i )
@@ -760,7 +877,7 @@ bool SGSHAPE::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
// set the per-vertex normals
size_t nNorms = 0;
SGVECTOR* pNorms = nullptr;
SGVECTOR* pNorms = NULL;
double x, y, z;
pn->GetNormalList( nNorms, pNorms );
+23 -26
View File
@@ -2,7 +2,6 @@
* 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 (C) 2020 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
@@ -24,6 +23,7 @@
/**
* @file sg_shape.h
* defines a complex 3D shape for a scenegraph object
*/
@@ -36,33 +36,8 @@
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 );
@@ -75,6 +50,28 @@ public:
// referenced nodes
SGAPPEARANCE* m_RAppearance;
SGFACESET* m_RFaceSet;
void unlinkChildNode( const SGNODE* aNode ) override;
void unlinkRefNode( const SGNODE* aNode ) override;
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 );
};
/*
-758
View File
@@ -1,758 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2022 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2023 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_rendering/camera.h"
#include "board_adapter.h"
#include <board_design_settings.h>
#include <board_stackup_manager/board_stackup.h>
#include <board_stackup_manager/stackup_predefined_prms.h>
#include <3d_rendering/raytracing/shapes2D/polygon_2d.h>
#include <board.h>
#include <dialogs/dialog_color_picker.h>
#include <3d_math.h>
#include "3d_fastmath.h"
#include <geometry/geometry_utils.h>
#include <pgm_base.h>
#include <settings/settings_manager.h>
#include <wx/log.h>
#include <pcbnew_settings.h>
#include <advanced_config.h>
#define DEFAULT_BOARD_THICKNESS pcbIUScale.mmToIU( 1.6 )
#define DEFAULT_COPPER_THICKNESS pcbIUScale.mmToIU( 0.035 ) // for 35 um
// The solder mask layer (and silkscreen) thickness
#define DEFAULT_TECH_LAYER_THICKNESS pcbIUScale.mmToIU( 0.025 )
// The solder paste thickness is chosen bigger than the solder mask layer
// to be sure is covers the mask when overlapping.
#define SOLDERPASTE_LAYER_THICKNESS pcbIUScale.mmToIU( 0.04 )
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_SilkscreenColors;
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_MaskColors;
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_PasteColors;
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_FinishColors;
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_BoardColors;
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultBackgroundTop;
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultBackgroundBot;
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSilkscreen;
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSolderMask;
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSolderPaste;
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSurfaceFinish;
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultBoardBody;
// To be used in Raytracing render to create bevels on layer items
float g_BevelThickness3DU = 0.0f;
static bool g_ColorsLoaded = false;
/**
* 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_CINFO3D_VISU". See the wxWidgets documentation on wxLogTrace for
* more information.
*
* @ingroup trace_env_vars
*/
const wxChar *BOARD_ADAPTER::m_logTrace = wxT( "KI_TRACE_EDA_CINFO3D_VISU" );
BOARD_ADAPTER::BOARD_ADAPTER() :
m_Cfg( nullptr ),
m_IsBoardView( true ),
m_MousewheelPanning( true ),
m_IsPreviewer( false ),
m_board( nullptr ),
m_3dModelManager( nullptr ),
m_renderSettings( nullptr ),
m_colors( nullptr ),
m_layerZcoordTop(),
m_layerZcoordBottom()
{
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::BOARD_ADAPTER" ) );
ReloadColorSettings();
m_boardPos = VECTOR2I();
m_boardSize = VECTOR2I();
m_boardCenter = SFVEC3F( 0.0f );
m_boardBoundingBox.Reset();
m_throughHoleIds.Clear();
m_throughHoleOds.Clear();
m_throughHoleAnnularRings.Clear();
m_copperLayersCount = 2;
m_biuTo3Dunits = 1.0;
m_boardBodyThickness3DU = DEFAULT_BOARD_THICKNESS * m_biuTo3Dunits;
m_frontCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
m_backCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
m_nonCopperLayerThickness3DU = DEFAULT_TECH_LAYER_THICKNESS * m_biuTo3Dunits;
m_solderPasteLayerThickness3DU = SOLDERPASTE_LAYER_THICKNESS * m_biuTo3Dunits;
m_trackCount = 0;
m_viaCount = 0;
m_averageViaHoleDiameter = 0.0f;
m_holeCount = 0;
m_averageHoleDiameter = 0.0f;
m_averageTrackWidth = 0.0f;
m_BgColorBot = SFVEC4F( 0.4, 0.4, 0.5, 1.0 );
m_BgColorTop = SFVEC4F( 0.8, 0.8, 0.9, 1.0 );
m_BoardBodyColor = SFVEC4F( 0.4, 0.4, 0.5, 0.9 );
m_SolderMaskColorTop = SFVEC4F( 0.1, 0.2, 0.1, 0.83 );
m_SolderMaskColorBot = SFVEC4F( 0.1, 0.2, 0.1, 0.83 );
m_SolderPasteColor = SFVEC4F( 0.4, 0.4, 0.4, 1.0 );
m_SilkScreenColorTop = SFVEC4F( 0.9, 0.9, 0.9, 1.0 );
m_SilkScreenColorBot = SFVEC4F( 0.9, 0.9, 0.9, 1.0 );
m_CopperColor = SFVEC4F( 0.75, 0.61, 0.23, 1.0 );
m_platedPadsFront = nullptr;
m_platedPadsBack = nullptr;
m_frontPlatedPadPolys = nullptr;
m_backPlatedPadPolys = nullptr;
if( !g_ColorsLoaded )
{
#define ADD_COLOR( list, r, g, b, a, name ) \
list.emplace_back( r/255.0, g/255.0, b/255.0, a, name )
ADD_COLOR( g_SilkscreenColors, 245, 245, 245, 1.0, NotSpecifiedPrm() ); // White
ADD_COLOR( g_SilkscreenColors, 20, 51, 36, 1.0, wxT( "Green" ) );
ADD_COLOR( g_SilkscreenColors, 181, 19, 21, 1.0, wxT( "Red" ) );
ADD_COLOR( g_SilkscreenColors, 2, 59, 162, 1.0, wxT( "Blue" ) );
ADD_COLOR( g_SilkscreenColors, 11, 11, 11, 1.0, wxT( "Black" ) );
ADD_COLOR( g_SilkscreenColors, 245, 245, 245, 1.0, wxT( "White" ) );
ADD_COLOR( g_SilkscreenColors, 32, 2, 53, 1.0, wxT( "Purple" ) );
ADD_COLOR( g_SilkscreenColors, 194, 195, 0, 1.0, wxT( "Yellow" ) );
ADD_COLOR( g_MaskColors, 20, 51, 36, 0.83, NotSpecifiedPrm() ); // Green
ADD_COLOR( g_MaskColors, 20, 51, 36, 0.83, wxT( "Green" ) );
ADD_COLOR( g_MaskColors, 91, 168, 12, 0.83, wxT( "Light Green" ) );
ADD_COLOR( g_MaskColors, 13, 104, 11, 0.83, wxT( "Saturated Green" ) );
ADD_COLOR( g_MaskColors, 181, 19, 21, 0.83, wxT( "Red" ) );
ADD_COLOR( g_MaskColors, 210, 40, 14, 0.83, wxT( "Light Red" ) );
ADD_COLOR( g_MaskColors, 239, 53, 41, 0.83, wxT( "Red/Orange" ) );
ADD_COLOR( g_MaskColors, 2, 59, 162, 0.83, wxT( "Blue" ) );
ADD_COLOR( g_MaskColors, 54, 79, 116, 0.83, wxT( "Light Blue 1" ) );
ADD_COLOR( g_MaskColors, 61, 85, 130, 0.83, wxT( "Light Blue 2" ) );
ADD_COLOR( g_MaskColors, 21, 70, 80, 0.83, wxT( "Green/Blue" ) );
ADD_COLOR( g_MaskColors, 11, 11, 11, 0.83, wxT( "Black" ) );
ADD_COLOR( g_MaskColors, 245, 245, 245, 0.83, wxT( "White" ) );
ADD_COLOR( g_MaskColors, 32, 2, 53, 0.83, wxT( "Purple" ) );
ADD_COLOR( g_MaskColors, 119, 31, 91, 0.83, wxT( "Light Purple" ) );
ADD_COLOR( g_MaskColors, 194, 195, 0, 0.83, wxT( "Yellow" ) );
ADD_COLOR( g_PasteColors, 128, 128, 128, 1.0, wxT( "Grey" ) );
ADD_COLOR( g_PasteColors, 90, 90, 90, 1.0, wxT( "Dark Grey" ) );
ADD_COLOR( g_PasteColors, 213, 213, 213, 1.0, wxT( "Silver" ) );
ADD_COLOR( g_FinishColors, 184, 115, 50, 1.0, wxT( "Copper" ) );
ADD_COLOR( g_FinishColors, 178, 156, 0, 1.0, wxT( "Gold" ) );
ADD_COLOR( g_FinishColors, 213, 213, 213, 1.0, wxT( "Silver" ) );
ADD_COLOR( g_FinishColors, 160, 160, 160, 1.0, wxT( "Tin" ) );
ADD_COLOR( g_BoardColors, 51, 43, 22, 0.83, wxT( "FR4 natural, dark" ) );
ADD_COLOR( g_BoardColors, 109, 116, 75, 0.83, wxT( "FR4 natural" ) );
ADD_COLOR( g_BoardColors, 252, 252, 250, 0.90, wxT( "PTFE natural" ) );
ADD_COLOR( g_BoardColors, 205, 130, 0, 0.68, wxT( "Polyimide" ) );
ADD_COLOR( g_BoardColors, 92, 17, 6, 0.90, wxT( "Phenolic natural" ) );
ADD_COLOR( g_BoardColors, 146, 99, 47, 0.83, wxT( "Brown 1" ) );
ADD_COLOR( g_BoardColors, 160, 123, 54, 0.83, wxT( "Brown 2" ) );
ADD_COLOR( g_BoardColors, 146, 99, 47, 0.83, wxT( "Brown 3" ) );
ADD_COLOR( g_BoardColors, 213, 213, 213, 1.0, wxT( "Aluminum" ) );
g_DefaultBackgroundTop = COLOR4D( 0.80, 0.80, 0.90, 1.0 );
g_DefaultBackgroundBot = COLOR4D( 0.40, 0.40, 0.50, 1.0 );
g_DefaultSilkscreen = COLOR4D( 0.94, 0.94, 0.94, 1.0 );
g_DefaultSolderMask = COLOR4D( 0.08, 0.20, 0.14, 0.83 );
g_DefaultSolderPaste = COLOR4D( 0.50, 0.50, 0.50, 1.0 );
g_DefaultSurfaceFinish = COLOR4D( 0.75, 0.61, 0.23, 1.0 );
g_DefaultBoardBody = COLOR4D( 0.43, 0.45, 0.30, 0.90 );
g_ColorsLoaded = true;
}
#undef ADD_COLOR
}
BOARD_ADAPTER::~BOARD_ADAPTER()
{
destroyLayers();
}
void BOARD_ADAPTER::ReloadColorSettings() noexcept
{
wxASSERT( PgmOrNull() );
PCBNEW_SETTINGS* settings = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
m_colors = Pgm().GetSettingsManager().GetColorSettings( settings->m_ColorTheme );
}
bool BOARD_ADAPTER::Is3dLayerEnabled( PCB_LAYER_ID aLayer ) const
{
wxASSERT( aLayer < PCB_LAYER_ID_COUNT );
if( m_board && !m_board->IsLayerEnabled( aLayer ) )
return false;
// see if layer needs to be shown
// check the flags
switch( aLayer )
{
case B_Adhes:
case F_Adhes:
return m_Cfg->m_Render.show_adhesive;
case B_Paste:
case F_Paste:
return m_Cfg->m_Render.show_solderpaste;
case B_SilkS:
case F_SilkS:
return m_Cfg->m_Render.show_silkscreen;
case B_Mask:
case F_Mask:
return m_Cfg->m_Render.show_soldermask;
case Dwgs_User:
case Cmts_User:
return !m_Cfg->m_Render.realistic && m_Cfg->m_Render.show_comments;
case Eco1_User:
case Eco2_User:
return !m_Cfg->m_Render.realistic && m_Cfg->m_Render.show_eco;
case Edge_Cuts:
return !m_Cfg->m_Render.realistic && !m_Cfg->m_Render.show_board_body;
case Margin:
return !m_Cfg->m_Render.realistic;
case B_Cu:
case F_Cu:
return !m_board || m_board->IsLayerVisible( aLayer ) || m_Cfg->m_Render.realistic
|| m_board->IsFootprintHolder();
default:
// the layer is an internal copper layer, used the visibility
return m_board && m_board->IsLayerVisible( aLayer );
}
}
bool BOARD_ADAPTER::IsFootprintShown( FOOTPRINT_ATTR_T aFPAttributes ) const
{
if( m_IsPreviewer ) // In panel Preview, footprints are always shown, of course
return true;
if( aFPAttributes & FP_EXCLUDE_FROM_POS_FILES )
{
if( !m_Cfg->m_Render.show_footprints_not_in_posfile )
return false;
}
if( aFPAttributes & FP_SMD )
return m_Cfg->m_Render.show_footprints_insert;
if( aFPAttributes & FP_THROUGH_HOLE )
return m_Cfg->m_Render.show_footprints_normal;
return m_Cfg->m_Render.show_footprints_virtual;
}
int BOARD_ADAPTER::GetHolePlatingThickness() const noexcept
{
return m_board ? m_board->GetDesignSettings().GetHolePlatingThickness()
: DEFAULT_COPPER_THICKNESS;
}
unsigned int BOARD_ADAPTER::GetCircleSegmentCount( float aDiameter3DU ) const
{
wxASSERT( aDiameter3DU > 0.0f );
return GetCircleSegmentCount( (int)( aDiameter3DU / m_biuTo3Dunits ) );
}
unsigned int BOARD_ADAPTER::GetCircleSegmentCount( int aDiameterBIU ) const
{
wxASSERT( aDiameterBIU > 0 );
return GetArcToSegmentCount( aDiameterBIU / 2, ARC_HIGH_DEF, FULL_CIRCLE );
}
void BOARD_ADAPTER::InitSettings( REPORTER* aStatusReporter, REPORTER* aWarningReporter )
{
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::InitSettings" ) );
if( aStatusReporter )
aStatusReporter->Report( _( "Build board outline" ) );
wxString msg;
const bool haveOutline = createBoardPolygon( &msg );
if( aWarningReporter )
{
if( !haveOutline )
aWarningReporter->Report( msg, RPT_SEVERITY_WARNING );
else
aWarningReporter->Report( wxEmptyString );
}
BOX2I bbbox;
if( m_board )
{
bbbox = m_board->ComputeBoundingBox( !m_board->IsFootprintHolder()
&& m_Cfg->m_Render.realistic
&& haveOutline );
}
// Gives a non null size to avoid issues in zoom / scale calculations
if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) )
bbbox.Inflate( pcbIUScale.mmToIU( 10 ) );
m_boardSize = bbbox.GetSize();
m_boardPos = bbbox.Centre();
wxASSERT( (m_boardSize.x > 0) && (m_boardSize.y > 0) );
m_boardPos.y = -m_boardPos.y; // The y coord is inverted in 3D viewer
m_copperLayersCount = m_board ? m_board->GetCopperLayerCount() : 2;
// Ensure the board has 2 sides for 3D views, because it is hard to find
// a *really* single side board in the true life...
if( m_copperLayersCount < 2 )
m_copperLayersCount = 2;
// Calculate the conversion to apply to all positions.
m_biuTo3Dunits = RANGE_SCALE_3D / std::max( m_boardSize.x, m_boardSize.y );
m_boardBodyThickness3DU = DEFAULT_BOARD_THICKNESS * m_biuTo3Dunits;
m_frontCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
m_backCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
m_nonCopperLayerThickness3DU = DEFAULT_TECH_LAYER_THICKNESS * m_biuTo3Dunits;
m_solderPasteLayerThickness3DU = SOLDERPASTE_LAYER_THICKNESS * m_biuTo3Dunits;
g_BevelThickness3DU = pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_3DRT_BevelHeight_um / 1000.0 ) * m_biuTo3Dunits;
if( m_board )
{
const BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
if( bds.GetStackupDescriptor().GetCount() )
{
int thickness = 0;
for( BOARD_STACKUP_ITEM* item : bds.GetStackupDescriptor().GetList() )
{
switch( item->GetType() )
{
case BS_ITEM_TYPE_DIELECTRIC:
for( int sublayer = 0; sublayer < item->GetSublayersCount(); sublayer++ )
thickness += item->GetThickness( sublayer );
break;
case BS_ITEM_TYPE_COPPER:
if( item->GetBrdLayerId() == F_Cu )
m_frontCopperThickness3DU = item->GetThickness() * m_biuTo3Dunits;
else if( item->GetBrdLayerId() == B_Cu )
m_backCopperThickness3DU = item->GetThickness() * m_biuTo3Dunits;
else if( item->IsEnabled() )
thickness += item->GetThickness();
break;
default:
break;
}
}
m_boardBodyThickness3DU = thickness * m_biuTo3Dunits;
}
}
// Init Z position of each layer
// calculate z position for each copper layer
// Zstart = -m_epoxyThickness / 2.0 is the z position of the back (bottom layer) (layer id = 31)
// Zstart = +m_epoxyThickness / 2.0 is the z position of the front (top layer) (layer id = 0)
// ____==__________==________==______ <- Bottom = +m_epoxyThickness / 2.0,
// | | Top = Bottom + m_copperThickness
// |__________________________________|
// == == == == <- Bottom = -m_epoxyThickness / 2.0,
// Top = Bottom - m_copperThickness
unsigned int layer;
for( layer = 0; layer < m_copperLayersCount; ++layer )
{
// This approximates internal layer positions (because we're treating all the dielectric
// layers as having the same thickness). But we don't render them anyway so it doesn't
// really matter.
m_layerZcoordBottom[layer] = m_boardBodyThickness3DU / 2.0f -
(m_boardBodyThickness3DU * layer / (m_copperLayersCount - 1) );
if( layer < (m_copperLayersCount / 2) )
m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] + m_frontCopperThickness3DU;
else
m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] - m_backCopperThickness3DU;
}
#define layerThicknessMargin 1.1
const float zpos_offset = m_nonCopperLayerThickness3DU * layerThicknessMargin;
// Fill remaining unused copper layers and back layer zpos with -m_boardBodyThickness / 2.0
for( ; layer < MAX_CU_LAYERS; layer++ )
{
m_layerZcoordBottom[layer] = -( m_boardBodyThickness3DU / 2.0f );
m_layerZcoordTop[layer] = -( m_boardBodyThickness3DU / 2.0f ) - m_backCopperThickness3DU;
}
// This is the top of the copper layer thickness.
const float zpos_copperTop_back = m_layerZcoordTop[B_Cu];
const float zpos_copperTop_front = m_layerZcoordTop[F_Cu];
// calculate z position for each non copper layer
// Solder mask and Solder paste have the same Z position
for( int layer_id = MAX_CU_LAYERS; layer_id < PCB_LAYER_ID_COUNT; ++layer_id )
{
float zposTop;
float zposBottom;
switch( layer_id )
{
case B_Adhes:
zposBottom = zpos_copperTop_back - 2.0f * zpos_offset;
zposTop = zposBottom - m_nonCopperLayerThickness3DU;
break;
case F_Adhes:
zposBottom = zpos_copperTop_front + 2.0f * zpos_offset;
zposTop = zposBottom + m_nonCopperLayerThickness3DU;
break;
case B_Mask:
zposBottom = zpos_copperTop_back;
zposTop = zpos_copperTop_back - m_nonCopperLayerThickness3DU;
break;
case B_Paste:
zposBottom = zpos_copperTop_back;
zposTop = zpos_copperTop_back - m_solderPasteLayerThickness3DU;
break;
case F_Mask:
zposBottom = zpos_copperTop_front;
zposTop = zpos_copperTop_front + m_nonCopperLayerThickness3DU;
break;
case F_Paste:
zposBottom = zpos_copperTop_front;
zposTop = zpos_copperTop_front + m_solderPasteLayerThickness3DU;
break;
case B_SilkS:
zposBottom = zpos_copperTop_back - 1.0f * zpos_offset;
zposTop = zposBottom - m_nonCopperLayerThickness3DU;
break;
case F_SilkS:
zposBottom = zpos_copperTop_front + 1.0f * zpos_offset;
zposTop = zposBottom + m_nonCopperLayerThickness3DU;
break;
// !TODO: review
default:
zposTop = zpos_copperTop_front + (layer_id - MAX_CU_LAYERS + 3.0f) * zpos_offset;
zposBottom = zposTop - m_nonCopperLayerThickness3DU;
break;
}
m_layerZcoordTop[layer_id] = zposTop;
m_layerZcoordBottom[layer_id] = zposBottom;
}
m_boardCenter = SFVEC3F( m_boardPos.x * m_biuTo3Dunits, m_boardPos.y * m_biuTo3Dunits, 0.0f );
SFVEC3F boardSize = SFVEC3F( m_boardSize.x * m_biuTo3Dunits, m_boardSize.y * m_biuTo3Dunits,
0.0f );
boardSize /= 2.0f;
SFVEC3F boardMin = ( m_boardCenter - boardSize );
SFVEC3F boardMax = ( m_boardCenter + boardSize );
boardMin.z = m_layerZcoordTop[B_Adhes];
boardMax.z = m_layerZcoordTop[F_Adhes];
m_boardBoundingBox = BBOX_3D( boardMin, boardMax );
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_startCreateBoardPolyTime = GetRunningMicroSecs();
#endif
if( aStatusReporter )
aStatusReporter->Report( _( "Create layers" ) );
createLayers( aStatusReporter );
COLOR_SETTINGS* colors = Pgm().GetSettingsManager().GetColorSettings();
auto to_SFVEC4F =
[]( const COLOR4D& src )
{
return SFVEC4F( src.r, src.g, src.b, src.a );
};
m_BgColorTop = to_SFVEC4F( colors->GetColor( LAYER_3D_BACKGROUND_TOP ) );
m_BgColorBot = to_SFVEC4F( colors->GetColor( LAYER_3D_BACKGROUND_BOTTOM ) );
m_SolderPasteColor = to_SFVEC4F( colors->GetColor( LAYER_3D_SOLDERPASTE ) );
if( m_board && colors->GetUseBoardStackupColors() )
{
const BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
auto findColor =
[]( const wxString& aColorName, const CUSTOM_COLORS_LIST& aColorSet )
{
if( aColorName.StartsWith( wxT( "#" ) ) )
{
return KIGFX::COLOR4D( aColorName );
}
else
{
for( const CUSTOM_COLOR_ITEM& color : aColorSet )
{
if( color.m_ColorName == aColorName )
return color.m_Color;
}
}
return KIGFX::COLOR4D();
};
m_SilkScreenColorTop = to_SFVEC4F( g_DefaultSilkscreen );
m_SilkScreenColorBot = to_SFVEC4F( g_DefaultSilkscreen );
m_SolderMaskColorTop = to_SFVEC4F( g_DefaultSolderMask );
m_SolderMaskColorBot = to_SFVEC4F( g_DefaultSolderMask );
KIGFX::COLOR4D bodyColor( 0, 0, 0, 0 );
for( const BOARD_STACKUP_ITEM* stackupItem : stackup.GetList() )
{
wxString colorName = stackupItem->GetColor();
switch( stackupItem->GetType() )
{
case BS_ITEM_TYPE_SILKSCREEN:
if( stackupItem->GetBrdLayerId() == F_SilkS )
m_SilkScreenColorTop = to_SFVEC4F( findColor( colorName, g_SilkscreenColors ) );
else
m_SilkScreenColorBot = to_SFVEC4F( findColor( colorName, g_SilkscreenColors ) );
break;
case BS_ITEM_TYPE_SOLDERMASK:
if( stackupItem->GetBrdLayerId() == F_Mask )
m_SolderMaskColorTop = to_SFVEC4F( findColor( colorName, g_MaskColors ) );
else
m_SolderMaskColorBot = to_SFVEC4F( findColor( colorName, g_MaskColors ) );
break;
case BS_ITEM_TYPE_DIELECTRIC:
{
KIGFX::COLOR4D layerColor = findColor( colorName, g_BoardColors );
if( bodyColor == COLOR4D( 0, 0, 0, 0 ) )
bodyColor = layerColor;
else
bodyColor = bodyColor.Mix( layerColor, 1.0 - layerColor.a );
bodyColor.a += ( 1.0 - bodyColor.a ) * layerColor.a / 2;
break;
}
default:
break;
}
}
if( bodyColor != COLOR4D( 0, 0, 0, 0 ) )
m_BoardBodyColor = to_SFVEC4F( bodyColor );
else
m_BoardBodyColor = to_SFVEC4F( g_DefaultBoardBody );
const wxString& finishName = stackup.m_FinishType;
if( finishName.EndsWith( wxT( "OSP" ) ) )
{
m_CopperColor = to_SFVEC4F( findColor( wxT( "Copper" ), g_FinishColors ) );
}
else if( finishName.EndsWith( wxT( "IG" ) )
|| finishName.EndsWith( wxT( "gold" ) ) )
{
m_CopperColor = to_SFVEC4F( findColor( wxT( "Gold" ), g_FinishColors ) );
}
else if( finishName.StartsWith( wxT( "HAL" ) )
|| finishName.StartsWith( wxT( "HASL" ) )
|| finishName.EndsWith( wxT( "tin" ) )
|| finishName.EndsWith( wxT( "nickel" ) ) )
{
m_CopperColor = to_SFVEC4F( findColor( wxT( "Tin" ), g_FinishColors ) );
}
else if( finishName.EndsWith( wxT( "silver" ) ) )
{
m_CopperColor = to_SFVEC4F( findColor( wxT( "Silver" ), g_FinishColors ) );
}
else
{
m_CopperColor = to_SFVEC4F( g_DefaultSurfaceFinish );
}
}
else
{
m_SilkScreenColorBot = to_SFVEC4F( colors->GetColor( LAYER_3D_SILKSCREEN_BOTTOM ) );
m_SilkScreenColorTop = to_SFVEC4F( colors->GetColor( LAYER_3D_SILKSCREEN_TOP ) );
m_SolderMaskColorBot = to_SFVEC4F( colors->GetColor( LAYER_3D_SOLDERMASK_BOTTOM ) );
m_SolderMaskColorTop = to_SFVEC4F( colors->GetColor( LAYER_3D_SOLDERMASK_TOP ) );
m_CopperColor = to_SFVEC4F( colors->GetColor( LAYER_3D_COPPER ) );
m_BoardBodyColor = to_SFVEC4F( colors->GetColor( LAYER_3D_BOARD ) );
}
}
bool BOARD_ADAPTER::createBoardPolygon( wxString* aErrorMsg )
{
m_board_poly.RemoveAllContours();
if( !m_board )
return false;
bool success;
if( m_board->IsFootprintHolder() )
{
if( !m_board->GetFirstFootprint() )
{
if( aErrorMsg )
*aErrorMsg = _( "No footprint loaded." );
return false;
}
// max dist from one endPt to next startPt
int chainingEpsilon = m_board->GetOutlinesChainingEpsilon();
success = BuildFootprintPolygonOutlines( m_board, m_board_poly,
m_board->GetDesignSettings().m_MaxError,
chainingEpsilon );
// Make polygon strictly simple to avoid issues (especially in 3D viewer)
m_board_poly.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
if( !success && aErrorMsg )
{
*aErrorMsg = _( "Footprint outline is missing or malformed. Run Footprint Checker for "
"a full analysis." );
}
}
else
{
success = m_board->GetBoardPolygonOutlines( m_board_poly );
if( !success && aErrorMsg )
*aErrorMsg = _( "Board outline is missing or malformed. Run DRC for a full analysis." );
}
return success;
}
float BOARD_ADAPTER::GetFootprintZPos( bool aIsFlipped ) const
{
if( aIsFlipped )
{
if( m_Cfg->m_Render.show_solderpaste )
return m_layerZcoordBottom[B_SilkS];
else
return m_layerZcoordBottom[B_Paste];
}
else
{
if( m_Cfg->m_Render.show_solderpaste )
return m_layerZcoordTop[F_SilkS];
else
return m_layerZcoordTop[F_Paste];
}
}
SFVEC4F BOARD_ADAPTER::GetLayerColor( PCB_LAYER_ID aLayerId ) const
{
wxASSERT( aLayerId < PCB_LAYER_ID_COUNT );
const COLOR4D color = m_colors->GetColor( aLayerId );
return SFVEC4F( color.r, color.g, color.b, color.a );
}
SFVEC4F BOARD_ADAPTER::GetItemColor( int aItemId ) const
{
return GetColor( m_colors->GetColor( aItemId ) );
}
SFVEC4F BOARD_ADAPTER::GetColor( const COLOR4D& aColor ) const
{
return SFVEC4F( aColor.r, aColor.g, aColor.b, aColor.a );
}
SFVEC2F BOARD_ADAPTER::GetSphericalCoord( int i ) const
{
SFVEC2F sphericalCoord =
SFVEC2F( ( m_Cfg->m_Render.raytrace_lightElevation[i] + 90.0f ) / 180.0f,
m_Cfg->m_Render.raytrace_lightAzimuth[i] / 180.0f );
sphericalCoord.x = glm::clamp( sphericalCoord.x, 0.0f, 1.0f );
sphericalCoord.y = glm::clamp( sphericalCoord.y, 0.0f, 2.0f );
return sphericalCoord;
}
-493
View File
@@ -1,493 +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) 1992-2022 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 "../3d_rendering/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_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;
/**
* 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;
/**
* 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 outling 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
{
return m_layerZcoordTop[aLayerId];
}
/**
* Get the bottom z position.
*
* @param aLayerId layer id.
* @return position in 3D units.
*/
float GetLayerBottomZPos( PCB_LAYER_ID aLayerId ) const noexcept
{
return m_layerZcoordBottom[aLayerId];
}
/**
* 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 MAP_CONTAINER_2D_BASE& GetLayerHoleMap() const noexcept { return m_layerHoleMap; }
const BVH_CONTAINER_2D& GetThroughHoleIds() const noexcept { return m_throughHoleIds; }
const BVH_CONTAINER_2D& GetThroughHoleOds() const noexcept { return m_throughHoleOds; }
/**
* 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& GetThroughHoleOdPolys() const noexcept
{
return m_throughHoleOdPolys;
}
const BVH_CONTAINER_2D& GetThroughHoleAnnularRings() const noexcept
{
return m_throughHoleAnnularRings;
}
const SHAPE_POLY_SET& GetThroughHoleAnnularRingPolys() const noexcept
{
return m_throughHoleAnnularRingPolys;
}
const SHAPE_POLY_SET& GetOuterNonPlatedThroughHolePoly() const noexcept
{
return m_nonPlatedThroughHoleOdPolys;
}
/**
* @return a container with through hole via hole outside diameters.
*/
const BVH_CONTAINER_2D& GetThroughHoleViaOds() const noexcept
{
return m_throughHoleViaOds;
}
const SHAPE_POLY_SET& GetThroughHoleViaOdPolys() const noexcept
{
return m_throughHoleViaOdPolys;
}
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* GetFrontPlatedPadPolys() { return m_frontPlatedPadPolys; }
const SHAPE_POLY_SET* GetBackPlatedPadPolys() { return m_backPlatedPadPolys; }
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 createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer );
void createPadWithMargin( const PAD *aPad, CONTAINER_2D_BASE* aDstContainer,
PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const;
OBJECT_2D* createPadWithDrill( const PAD* aPad, 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 );
void addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aDstContainer,
const BOARD_ITEM* aItem );
void addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM* aOwner );
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 addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aDstContainer,
PCB_LAYER_ID aLayerId );
void transformArcToSegments( const VECTOR2I& aCentre, const VECTOR2I& aStart,
const EDA_ANGLE& aArcAngle, int aCircleToSegmentsCount, int aWidth,
CONTAINER_2D_BASE* aDstContainer, const BOARD_ITEM& aOwner );
void buildPadOutlineAsSegments( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer, int aWidth );
// Helper functions to create poly contours
void buildPadOutlineAsPolygon( const PAD* aPad, SHAPE_POLY_SET& aBuffer, int aWidth) const;
void transformFPShapesToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aBuffer ) const;
public:
static CUSTOM_COLORS_LIST g_SilkscreenColors;
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;
public:
EDA_3D_VIEWER_SETTINGS* m_Cfg;
bool m_IsBoardView;
bool m_MousewheelPanning;
bool m_IsPreviewer; ///< true if the board adaptater is living 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
private:
BOARD* m_board;
S3D_CACHE* m_3dModelManager;
RENDER_SETTINGS* m_renderSettings;
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_frontPlatedPadPolys;
SHAPE_POLY_SET* m_backPlatedPadPolys;
MAP_POLY m_layerHoleOdPolys; ///< Hole outer diameters (per layer)
MAP_POLY m_layerHoleIdPolys; ///< Hole inner diameters (per layer)
SHAPE_POLY_SET m_nonPlatedThroughHoleOdPolys; ///< NPTH outer diameters
SHAPE_POLY_SET m_throughHoleOdPolys; ///< PTH outer diameters
SHAPE_POLY_SET m_throughHoleViaOdPolys; ///< Via hole outer diameters
SHAPE_POLY_SET m_throughHoleAnnularRingPolys; ///< 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_throughHoleOds; ///< List of PTH outer diameters
BVH_CONTAINER_2D m_throughHoleIds; ///< List of PTH inner diameters
BVH_CONTAINER_2D m_throughHoleAnnularRings; ///< List of via annular rings
BVH_CONTAINER_2D m_throughHoleViaOds; ///< List of via hole outer diameters
BVH_CONTAINER_2D m_throughHoleViaIds; ///< List of via hole inner 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::array<float, PCB_LAYER_ID_COUNT> m_layerZcoordTop; ///< Top (End) Z position of each
///< layer in 3D units.
std::array<float, PCB_LAYER_ID_COUNT> 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;
};
class EDA_3D_BOARD_HOLDER
{
public:
virtual BOARD_ADAPTER& GetAdapter() = 0;
virtual CAMERA& GetCurrentCamera() = 0;
virtual ~EDA_3D_BOARD_HOLDER() {};
};
#endif // BOARD_ADAPTER_H
+524
View File
@@ -0,0 +1,524 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 cinfo3d_visu.cpp
* @brief Handles data related with the board to be visualized
*/
#include "../3d_rendering/ccamera.h"
#include "cinfo3d_visu.h"
#include <3d_rendering/3d_render_raytracing/shapes2D/cpolygon2d.h>
#include <class_board.h>
#include <3d_math.h>
#include "3d_fastmath.h"
#include <geometry/geometry_utils.h>
/**
* 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_CINFO3D_VISU". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
const wxChar *CINFO3D_VISU::m_logTrace = wxT( "KI_TRACE_EDA_CINFO3D_VISU" );
CINFO3D_VISU G_null_CINFO3D_VISU;
CINFO3D_VISU::CINFO3D_VISU() :
m_currentCamera( m_trackBallCamera ),
m_trackBallCamera( RANGE_SCALE_3D )
{
wxLogTrace( m_logTrace, wxT( "CINFO3D_VISU::CINFO3D_VISU" ) );
m_board = NULL;
m_3d_model_manager = NULL;
m_3D_grid_type = GRID3D_NONE;
m_drawFlags.resize( FL_LAST, false );
m_render_engine = RENDER_ENGINE_OPENGL_LEGACY;
m_material_mode = MATERIAL_MODE_NORMAL;
m_boardPos = wxPoint();
m_boardSize = wxSize();
m_boardCenter = SFVEC3F( 0.0f );
m_boardBoudingBox.Reset();
m_board2dBBox3DU.Reset();
m_layers_container2D.clear();
m_layers_holes2D.clear();
m_through_holes_inner.Clear();
m_through_holes_outer.Clear();
m_copperLayersCount = -1;
m_epoxyThickness3DU = 0.0f;
m_copperThickness3DU = 0.0f;
m_nonCopperLayerThickness3DU = 0.0f;
m_biuTo3Dunits = 1.0;
m_stats_nr_tracks = 0;
m_stats_nr_vias = 0;
m_stats_via_med_hole_diameter = 0.0f;
m_stats_nr_holes = 0;
m_stats_hole_med_diameter = 0.0f;
m_stats_track_med_width = 0.0f;
m_calc_seg_min_factor3DU = 0.0f;
m_calc_seg_max_factor3DU = 0.0f;
memset( m_layerZcoordTop, 0, sizeof( m_layerZcoordTop ) );
memset( m_layerZcoordBottom, 0, sizeof( m_layerZcoordBottom ) );
SetFlag( FL_USE_REALISTIC_MODE, true );
SetFlag( FL_MODULE_ATTRIBUTES_NORMAL, true );
SetFlag( FL_SHOW_BOARD_BODY, true );
SetFlag( FL_RENDER_OPENGL_COPPER_THICKNESS, true );
SetFlag( FL_MODULE_ATTRIBUTES_NORMAL, true );
SetFlag( FL_MODULE_ATTRIBUTES_NORMAL_INSERT, true );
SetFlag( FL_MODULE_ATTRIBUTES_VIRTUAL, true );
SetFlag( FL_ZONE, true );
SetFlag( FL_SILKSCREEN, true );
SetFlag( FL_SOLDERMASK, true );
m_BgColorBot = SFVEC3D( 0.4, 0.4, 0.5 );
m_BgColorTop = SFVEC3D( 0.8, 0.8, 0.9 );
m_BoardBodyColor = SFVEC3D( 0.4, 0.4, 0.5 );
m_SolderMaskColor = SFVEC3D( 0.1, 0.2, 0.1 );
m_SolderPasteColor = SFVEC3D( 0.4, 0.4, 0.4 );
m_SilkScreenColor = SFVEC3D( 0.9, 0.9, 0.9 );
m_CopperColor = SFVEC3D( 0.75, 0.61, 0.23 );
}
CINFO3D_VISU::~CINFO3D_VISU()
{
destroyLayers();
}
bool CINFO3D_VISU::Is3DLayerEnabled( PCB_LAYER_ID aLayer ) const
{
wxASSERT( aLayer < PCB_LAYER_ID_COUNT );
DISPLAY3D_FLG flg;
// see if layer needs to be shown
// check the flags
switch( aLayer )
{
case B_Adhes:
case F_Adhes:
flg = FL_ADHESIVE;
break;
case B_Paste:
case F_Paste:
flg = FL_SOLDERPASTE;
break;
case B_SilkS:
case F_SilkS:
flg = FL_SILKSCREEN;
break;
case B_Mask:
case F_Mask:
flg = FL_SOLDERMASK;
break;
case Dwgs_User:
case Cmts_User:
if( GetFlag( FL_USE_REALISTIC_MODE ) )
return false;
flg = FL_COMMENTS;
break;
case Eco1_User:
case Eco2_User:
if( GetFlag( FL_USE_REALISTIC_MODE ) )
return false;
flg = FL_ECO;
break;
case Edge_Cuts:
if( GetFlag( FL_SHOW_BOARD_BODY ) || GetFlag( FL_USE_REALISTIC_MODE ) )
return false;
return true;
break;
case Margin:
if( GetFlag( FL_USE_REALISTIC_MODE ) )
return false;
return true;
break;
case B_Cu:
case F_Cu:
return m_board->GetDesignSettings().IsLayerVisible( aLayer ) ||
GetFlag( FL_USE_REALISTIC_MODE );
break;
default:
// the layer is an internal copper layer, used the visibility
if( GetFlag( FL_SHOW_BOARD_BODY ) &&
(m_render_engine == RENDER_ENGINE_OPENGL_LEGACY) )
{
// Do not render internal layers if it is overlap with the board
// (on OpenGL render)
return false;
}
return m_board->GetDesignSettings().IsLayerVisible( aLayer );
}
// The layer has a flag, return the flag
return GetFlag( flg );
}
bool CINFO3D_VISU::GetFlag( DISPLAY3D_FLG aFlag ) const
{
wxASSERT( aFlag < FL_LAST );
return m_drawFlags[aFlag];
}
void CINFO3D_VISU::SetFlag( DISPLAY3D_FLG aFlag, bool aState )
{
wxASSERT( aFlag < FL_LAST );
m_drawFlags[aFlag] = aState;
}
bool CINFO3D_VISU::ShouldModuleBeDisplayed( MODULE_ATTR_T aModuleAttributs ) const
{
if( ( ( aModuleAttributs == MOD_DEFAULT ) &&
GetFlag( FL_MODULE_ATTRIBUTES_NORMAL ) ) ||
( ( ( aModuleAttributs & MOD_CMS) == MOD_CMS ) &&
GetFlag( FL_MODULE_ATTRIBUTES_NORMAL_INSERT ) ) ||
( ( ( aModuleAttributs & MOD_VIRTUAL) == MOD_VIRTUAL ) &&
GetFlag( FL_MODULE_ATTRIBUTES_VIRTUAL ) ) )
{
return true;
}
return false;
}
// !TODO: define the actual copper thickness by user
#define COPPER_THICKNESS KiROUND( 0.035 * IU_PER_MM ) // for 35 um
#define TECH_LAYER_THICKNESS KiROUND( 0.04 * IU_PER_MM )
int CINFO3D_VISU::GetCopperThicknessBIU() const
{
return COPPER_THICKNESS;
}
unsigned int CINFO3D_VISU::GetNrSegmentsCircle( float aDiameter3DU ) const
{
wxASSERT( aDiameter3DU > 0.0f );
return GetNrSegmentsCircle( (int)( aDiameter3DU / m_biuTo3Dunits ) );
}
unsigned int CINFO3D_VISU::GetNrSegmentsCircle( int aDiameterBIU ) const
{
wxASSERT( aDiameterBIU > 0 );
// Require at least 3 segments for a circle
return std::max( GetArcToSegmentCount( aDiameterBIU / 2, ARC_HIGH_DEF, 360.0 ), 3 );
}
double CINFO3D_VISU::GetCircleCorrectionFactor( int aNrSides ) const
{
wxASSERT( aNrSides >= 3 );
return GetCircletoPolyCorrectionFactor( aNrSides );
}
void CINFO3D_VISU::InitSettings( REPORTER *aStatusTextReporter )
{
wxLogTrace( m_logTrace, wxT( "CINFO3D_VISU::InitSettings" ) );
// Calculates the board bounding box
// First, use only the board outlines
EDA_RECT bbbox = m_board->ComputeBoundingBox( true );
// If no outlines, use the board with items
if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) )
bbbox = m_board->ComputeBoundingBox( false );
// Gives a non null size to avoid issues in zoom / scale calculations
if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) )
bbbox.Inflate( Millimeter2iu( 10 ) );
m_boardSize = bbbox.GetSize();
m_boardPos = bbbox.Centre();
wxASSERT( (m_boardSize.x > 0) && (m_boardSize.y > 0) );
m_boardPos.y = -m_boardPos.y; // The y coord is inverted in 3D viewer
m_copperLayersCount = m_board->GetCopperLayerCount();
// Ensure the board has 2 sides for 3D views, because it is hard to find
// a *really* single side board in the true life...
if( m_copperLayersCount < 2 )
m_copperLayersCount = 2;
// Calculate the convertion to apply to all positions.
m_biuTo3Dunits = RANGE_SCALE_3D / std::max( m_boardSize.x, m_boardSize.y );
m_epoxyThickness3DU = m_board->GetDesignSettings().GetBoardThickness() *
m_biuTo3Dunits;
// !TODO: use value defined by user (currently use default values by ctor
m_copperThickness3DU = COPPER_THICKNESS * m_biuTo3Dunits;
m_nonCopperLayerThickness3DU = TECH_LAYER_THICKNESS * m_biuTo3Dunits;
// Init Z position of each layer
// calculate z position for each copper layer
// Zstart = -m_epoxyThickness / 2.0 is the z position of the back (bottom layer) (layer id = 31)
// Zstart = +m_epoxyThickness / 2.0 is the z position of the front (top layer) (layer id = 0)
// all unused copper layer z position are set to 0
// ____==__________==________==______ <- Bottom = +m_epoxyThickness / 2.0,
// | | Top = Bottom + m_copperThickness
// |__________________________________|
// == == == == <- Bottom = -m_epoxyThickness / 2.0,
// Top = Bottom - m_copperThickness
unsigned int layer;
for( layer = 0; layer < m_copperLayersCount; ++layer )
{
m_layerZcoordBottom[layer] = m_epoxyThickness3DU / 2.0f -
(m_epoxyThickness3DU * layer / (m_copperLayersCount - 1) );
if( layer < (m_copperLayersCount / 2) )
m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] + m_copperThickness3DU;
else
m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] - m_copperThickness3DU;
}
#define layerThicknessMargin 1.1
const float zpos_offset = m_nonCopperLayerThickness3DU * layerThicknessMargin;
// Fill remaining unused copper layers and back layer zpos
// with -m_epoxyThickness / 2.0
for( ; layer < MAX_CU_LAYERS; layer++ )
{
m_layerZcoordBottom[layer] = -(m_epoxyThickness3DU / 2.0f);
m_layerZcoordTop[layer] = -(m_epoxyThickness3DU / 2.0f) - m_copperThickness3DU;
}
// This is the top of the copper layer thickness.
const float zpos_copperTop_back = m_layerZcoordTop[B_Cu];
const float zpos_copperTop_front = m_layerZcoordTop[F_Cu];
// calculate z position for each non copper layer
// Solder mask and Solder paste have the same Z position
for( int layer_id = MAX_CU_LAYERS; layer_id < PCB_LAYER_ID_COUNT; ++layer_id )
{
float zposTop;
float zposBottom;
switch( layer_id )
{
case B_Adhes:
zposBottom = zpos_copperTop_back - 2.0f * zpos_offset;
zposTop = zposBottom - m_nonCopperLayerThickness3DU;
break;
case F_Adhes:
zposBottom = zpos_copperTop_front + 2.0f * zpos_offset;
zposTop = zposBottom + m_nonCopperLayerThickness3DU;
break;
case B_Mask:
case B_Paste:
zposBottom = zpos_copperTop_back;
zposTop = zpos_copperTop_back - m_nonCopperLayerThickness3DU;
break;
case F_Mask:
case F_Paste:
zposTop = zpos_copperTop_front + m_nonCopperLayerThickness3DU;
zposBottom = zpos_copperTop_front;
break;
case B_SilkS:
zposBottom = zpos_copperTop_back - 1.0f * zpos_offset;
zposTop = zposBottom - m_nonCopperLayerThickness3DU;
break;
case F_SilkS:
zposBottom = zpos_copperTop_front + 1.0f * zpos_offset;
zposTop = zposBottom + m_nonCopperLayerThickness3DU;
break;
// !TODO: review
default:
zposTop = zpos_copperTop_front + (layer_id - MAX_CU_LAYERS + 3.0f) * zpos_offset;
zposBottom = zposTop - m_nonCopperLayerThickness3DU;
break;
}
m_layerZcoordTop[layer_id] = zposTop;
m_layerZcoordBottom[layer_id] = zposBottom;
}
m_boardCenter = SFVEC3F( m_boardPos.x * m_biuTo3Dunits,
m_boardPos.y * m_biuTo3Dunits,
0.0f );
SFVEC3F boardSize = SFVEC3F( m_boardSize.x * m_biuTo3Dunits,
m_boardSize.y * m_biuTo3Dunits,
0.0f );
boardSize /= 2.0f;
SFVEC3F boardMin = (m_boardCenter - boardSize);
SFVEC3F boardMax = (m_boardCenter + boardSize);
boardMin.z = m_layerZcoordTop[B_Adhes];
boardMax.z = m_layerZcoordTop[F_Adhes];
m_boardBoudingBox = CBBOX( boardMin, boardMax );
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_startCreateBoardPolyTime = GetRunningMicroSecs();
#endif
if( aStatusTextReporter )
aStatusTextReporter->Report( _( "Build board body" ) );
createBoardPolygon();
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_stopCreateBoardPolyTime = GetRunningMicroSecs();
unsigned stats_startCreateLayersTime = stats_stopCreateBoardPolyTime;
#endif
if( aStatusTextReporter )
aStatusTextReporter->Report( _( "Create layers" ) );
createLayers( aStatusTextReporter );
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_stopCreateLayersTime = GetRunningMicroSecs();
printf( "CINFO3D_VISU::InitSettings times\n" );
printf( " CreateBoardPoly: %.3f ms\n",
(float)( stats_stopCreateBoardPolyTime - stats_startCreateBoardPolyTime ) / 1e3 );
printf( " CreateLayers and holes: %.3f ms\n",
(float)( stats_stopCreateLayersTime - stats_startCreateLayersTime ) / 1e3 );
printf( "\n" );
#endif
}
void CINFO3D_VISU::createBoardPolygon()
{
m_board_poly.RemoveAllContours();
wxString errmsg;
if( !m_board->GetBoardPolygonOutlines( m_board_poly, /*allLayerHoles,*/ &errmsg ) )
{
errmsg.append( wxT( "\n\n" ) );
errmsg.append( _( "Cannot determine the board outline." ) );
wxLogMessage( errmsg );
}
Polygon_Calc_BBox_3DU( m_board_poly, m_board2dBBox3DU, m_biuTo3Dunits );
}
float CINFO3D_VISU::GetModulesZcoord3DIU( bool aIsFlipped ) const
{
if( aIsFlipped )
{
if( GetFlag( FL_SOLDERPASTE ) )
return m_layerZcoordBottom[B_SilkS];
else
return m_layerZcoordBottom[B_Paste];
}
else
{
if( GetFlag( FL_SOLDERPASTE ) )
return m_layerZcoordTop[F_SilkS];
else
return m_layerZcoordTop[F_Paste];
}
}
void CINFO3D_VISU::CameraSetType( CAMERA_TYPE aCameraType )
{
switch( aCameraType )
{
case CAMERA_TRACKBALL:
m_currentCamera = m_trackBallCamera;
break;
default:
wxLogMessage( wxT( "CINFO3D_VISU::CameraSetType() error: unknown camera type %d" ),
(int)aCameraType );
break;
}
}
SFVEC3F CINFO3D_VISU::GetLayerColor( PCB_LAYER_ID aLayerId ) const
{
wxASSERT( aLayerId < PCB_LAYER_ID_COUNT );
const COLOR4D color = m_board->Colors().GetLayerColor( aLayerId );
return SFVEC3F( color.r, color.g, color.b );
}
SFVEC3F CINFO3D_VISU::GetItemColor( int aItemId ) const
{
return GetColor( m_board->Colors().GetItemColor( aItemId ) );
}
SFVEC3F CINFO3D_VISU::GetColor( COLOR4D aColor ) const
{
return SFVEC3F( aColor.r, aColor.g, aColor.b );
}
+680
View File
@@ -0,0 +1,680 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 cinfo3d_visu.h
* @brief Handles data related with the board to be visualized
*/
#ifndef CINFO3D_VISU_H
#define CINFO3D_VISU_H
#include <vector>
#include "../3d_rendering/3d_render_raytracing/accelerators/ccontainer2d.h"
#include "../3d_rendering/3d_render_raytracing/accelerators/ccontainer.h"
#include "../3d_rendering/3d_render_raytracing/shapes3D/cbbox.h"
#include "../3d_rendering/ccamera.h"
#include "../3d_rendering/ctrack_ball.h"
#include "../3d_enums.h"
#include "../3d_cache/3d_cache.h"
#include <layers_id_colors_and_visibility.h>
#include <class_pad.h>
#include <class_track.h>
#include <wx/gdicmn.h>
#include <pcb_base_frame.h>
#include <class_pcb_text.h>
#include <class_drawsegment.h>
#include <class_dimension.h>
#include <class_zone.h>
#include <class_module.h>
#include <reporter.h>
/// A type that stores a container of 2d objects for each layer id
typedef std::map< PCB_LAYER_ID, CBVHCONTAINER2D *> MAP_CONTAINER_2D;
/// 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
/**
* Class CINFO3D_VISU
* Helper class to handle information needed to display 3D board
*/
class CINFO3D_VISU
{
public:
CINFO3D_VISU();
~CINFO3D_VISU();
/**
* @brief Set3DCacheManager - Update the Cache manager pointer
* @param aCachePointer: the pointer to the 3d cache manager
*/
void Set3DCacheManager( S3D_CACHE *aCachePointer ) { m_3d_model_manager = aCachePointer; }
/**
* @brief Get3DCacheManager - Return the 3d cache manager pointer
* @return
*/
S3D_CACHE *Get3DCacheManager( ) const { return m_3d_model_manager; }
/**
* @brief GetFlag - get a configuration status of a flag
* @param aFlag: the flag to get the status
* @return true if flag is set, false if not
*/
bool GetFlag( DISPLAY3D_FLG aFlag ) const ;
/**
* @brief SetFlag - set the status of a flag
* @param aFlag: the flag to get the status
* @param aState: status to set
*/
void SetFlag( DISPLAY3D_FLG aFlag, bool aState );
/**
* @brief Is3DLayerEnabled - Check if a layer is enabled
* @param aLayer: layer ID to get status
* @return true if layer should be displayed, false if not
*/
bool Is3DLayerEnabled( PCB_LAYER_ID aLayer ) const;
/**
* @brief ShouldModuleBeDisplayed - Test if module should be displayed in
* relation to attributs and the flags
* @return true if module should be displayed, false if not
*/
bool ShouldModuleBeDisplayed( MODULE_ATTR_T aModuleAttributs ) const;
/**
* @brief SetBoard - Set current board to be rendered
* @param aBoard: board to process
*/
void SetBoard( BOARD *aBoard ) { m_board = aBoard; }
/**
* @brief GetBoard - Get current board to be rendered
* @return BOARD pointer
*/
const BOARD *GetBoard() const { return m_board; }
/**
* @brief InitSettings - Function to be called by the render when it need to
* reload the settings for the board.
* @param aStatusTextReporter: the pointer for the status reporter
*/
void InitSettings( REPORTER *aStatusTextReporter );
/**
* @brief BiuTo3Dunits - Board integer units To 3D units
* @return the conversion factor to transform a position from the board to 3d units
*/
double BiuTo3Dunits() const { return m_biuTo3Dunits; }
/**
* @brief GetBBox3DU - Get the bbox of the pcb board
* @return the board bbox in 3d units
*/
const CBBOX &GetBBox3DU() const { return m_boardBoudingBox; }
/**
* @brief GetEpoxyThickness3DU - Get the current epoxy thickness
* @return thickness in 3d unities
*/
float GetEpoxyThickness3DU() const { return m_epoxyThickness3DU; }
/**
* @brief GetNonCopperLayerThickness3DU - Get the current non copper layers thickness
* @return thickness in 3d unities of non copperlayers
*/
float GetNonCopperLayerThickness3DU() const { return m_nonCopperLayerThickness3DU; }
/**
* @brief GetCopperThickness3DU - Get the current copper layer thickness
* @return thickness in 3d unities of copperlayers
*/
float GetCopperThickness3DU() const { return m_copperThickness3DU; }
/**
* @brief GetCopperThicknessBIU - Get the current copper layer thickness
* @return thickness in board unities
*/
int GetCopperThicknessBIU() const;
/**
* @brief GetBoardSizeBIU - Get the board size
* @return size in BIU unities
*/
wxSize GetBoardSizeBIU() const { return m_boardSize; }
/**
* @brief GetBoardPosBIU - Get the board size
* @return size in BIU unities
*/
wxPoint GetBoardPosBIU() const { return m_boardPos; }
/**
* @brief GetBoardCenter - the board center position in 3d units
* @return board center vector position in 3d units
*/
const SFVEC3F &GetBoardCenter3DU() const { return m_boardCenter; }
/**
* @brief GetModulesZcoord3DIU - Get the position of the module in 3d integer units
* considering if it is flipped or not.
* @param aIsFlipped: true for use in modules on Front (top) layer, false
* if module is on back (bottom) layer
* @return the Z position of 3D shapes, in 3D integer units
*/
float GetModulesZcoord3DIU( bool aIsFlipped ) const ;
/**
* @brief CameraSetType - Set the camera type to use
* @param aCameraType: camera type to use in this canvas
*/
void CameraSetType( CAMERA_TYPE aCameraType );
/**
* @brief CameraGet - get current camera in use
* @return a camera
*/
CCAMERA &CameraGet() const { return m_currentCamera; }
/**
* @brief GridGet - get the current grid
* @return space type of the grid
*/
GRID3D_TYPE GridGet() const { return m_3D_grid_type; }
/**
* @brief GridSet - set the current grid
* @param aGridType = the type space of the grid
*/
void GridSet( GRID3D_TYPE aGridType ) { m_3D_grid_type = aGridType; }
/**
* @brief RenderEngineSet
* @param aRenderEngine = the render engine mode selected
*/
void RenderEngineSet( RENDER_ENGINE aRenderEngine ) { m_render_engine = aRenderEngine; }
/**
* @brief RenderEngineGet
* @return render engine on use
*/
RENDER_ENGINE RenderEngineGet() const { return m_render_engine; }
/**
* @brief MaterialModeSet
* @param aMaterialMode = the render material mode
*/
void MaterialModeSet( MATERIAL_MODE aMaterialMode ) { m_material_mode = aMaterialMode; }
/**
* @brief MaterialModeGet
* @return material rendering mode
*/
MATERIAL_MODE MaterialModeGet() const { return m_material_mode; }
/**
* @brief GetBoardPoly - Get the current polygon of the epoxy board
* @return the shape polygon
*/
const SHAPE_POLY_SET &GetBoardPoly() const { return m_board_poly; }
/**
* @brief GetLayerColor - get the technical color of a layer
* @param aLayerId: the layer to get the color information
* @return the color in SFVEC3F format
*/
SFVEC3F GetLayerColor( PCB_LAYER_ID aLayerId ) const;
/**
* @brief GetItemColor - get the technical color of a layer
* @param aItemId: the item id to get the color information
* @return the color in SFVEC3F format
*/
SFVEC3F GetItemColor( int aItemId ) const;
/**
* @brief GetColor
* @param aColor: the color mapped
* @return the color in SFVEC3F format
*/
SFVEC3F GetColor( COLOR4D aColor ) const;
/**
* @brief GetLayerTopZpos3DU - Get the top z position
* @param aLayerId: layer id
* @return position in 3D unities
*/
float GetLayerTopZpos3DU( PCB_LAYER_ID aLayerId ) const { return m_layerZcoordTop[aLayerId]; }
/**
* @brief GetLayerBottomZpos3DU - Get the bottom z position
* @param aLayerId: layer id
* @return position in 3D unities
*/
float GetLayerBottomZpos3DU( PCB_LAYER_ID aLayerId ) const { return m_layerZcoordBottom[aLayerId]; }
/**
* @brief GetMapLayers - Get the map of container that have the objects per layer
* @return the map containers of this board
*/
const MAP_CONTAINER_2D &GetMapLayers() const { return m_layers_container2D; }
/**
* @brief GetMapLayersHoles -Get the map of container that have the holes per layer
* @return the map containers of holes from this board
*/
const MAP_CONTAINER_2D &GetMapLayersHoles() const { return m_layers_holes2D; }
/**
* @brief GetThroughHole_Outer - Get the inflated ThroughHole container
* @return a container with holes
*/
const CBVHCONTAINER2D &GetThroughHole_Outer() const { return m_through_holes_outer; }
/**
* @brief GetThroughHole_Outer_poly -
* @return
*/
const SHAPE_POLY_SET &GetThroughHole_Outer_poly() const { return m_through_outer_holes_poly; }
/**
* @brief GetThroughHole_Outer_poly_NPTH -
* @return
*/
const SHAPE_POLY_SET &GetThroughHole_Outer_poly_NPTH() const {
return m_through_outer_holes_poly_NPTH; }
/**
* @brief GetThroughHole_Vias_Outer -
* @return a container with via THT holes only
*/
const CBVHCONTAINER2D &GetThroughHole_Vias_Outer() const { return m_through_holes_vias_outer; }
/**
* @brief GetThroughHole_Vias_Inner -
* @return a container with via THT holes only
*/
const CBVHCONTAINER2D &GetThroughHole_Vias_Inner() const { return m_through_holes_vias_inner; }
/**
* @brief GetThroughHole_Vias_Outer_poly -
* @return
*/
const SHAPE_POLY_SET &GetThroughHole_Vias_Outer_poly() const {
return m_through_outer_holes_vias_poly; }
/**
* @brief GetThroughHole_Vias_Inner_poly -
* @return
*/
const SHAPE_POLY_SET &GetThroughHole_Vias_Inner_poly() const {
return m_through_inner_holes_vias_poly; }
/**
* @brief GetThroughHole_Inner - Get the ThroughHole container
* @return a container with holes
*/
const CBVHCONTAINER2D &GetThroughHole_Inner() const { return m_through_holes_inner; }
/**
* @brief GetThroughHole_Inner_poly -
* @return
*/
const SHAPE_POLY_SET &GetThroughHole_Inner_poly() const { return m_through_inner_holes_poly; }
/**
* @brief GetStats_Nr_Vias - Get statistics of the nr of vias
* @return number of vias
*/
unsigned int GetStats_Nr_Vias() const { return m_stats_nr_vias; }
/**
* @brief GetStats_Nr_Holes - Get statistics of the nr of holes
* @return number of holes
*/
unsigned int GetStats_Nr_Holes() const { return m_stats_nr_holes; }
/**
* @brief GetStats_Med_Via_Hole_Diameter3DU - Average diameter of the via holes
* @return dimension in 3D units
*/
float GetStats_Med_Via_Hole_Diameter3DU() const { return m_stats_via_med_hole_diameter; }
/**
* @brief GetStats_Med_Hole_Diameter3DU - Average diameter of holes
* @return dimension in 3D units
*/
float GetStats_Med_Hole_Diameter3DU() const { return m_stats_hole_med_diameter; }
/**
* @brief GetStats_Med_Track_Width - Average width of the tracks
* @return dimensions in 3D units
*/
float GetStats_Med_Track_Width() const { return m_stats_track_med_width; }
/**
* @brief GetNrSegmentsCircle
* @param aDiameter3DU: diameter in 3DU
* @return number of sides that should be used in that circle
*/
unsigned int GetNrSegmentsCircle( float aDiameter3DU ) const;
/**
* @brief GetNrSegmentsCircle
* @param aDiameterBIU: diameter in board internal units
* @return number of sides that should be used in that circle
*/
unsigned int GetNrSegmentsCircle( int aDiameterBIU ) const;
/**
* @brief GetCircleCorrectionFactor - computes a angle correction
* factor used when creating circles
* @param aNrSides: the number of segments sides of the circle
* @return a factor to apply to contour creation
*/
double GetCircleCorrectionFactor( int aNrSides ) const;
/**
* @brief GetPolyMap - Get maps of polygons's layers
* @return the map with polygons's layers
*/
const MAP_POLY &GetPolyMap() const { return m_layers_poly; }
const MAP_POLY &GetPolyMapHoles_Inner() const { return m_layers_inner_holes_poly; }
const MAP_POLY &GetPolyMapHoles_Outer() const { return m_layers_outer_holes_poly; }
private:
void createBoardPolygon();
void createLayers( REPORTER *aStatusTextReporter );
void destroyLayers();
// Helper functions to create the board
COBJECT2D *createNewTrack( const TRACK* aTrack , int aClearanceValue ) const;
void createNewPad( const D_PAD* aPad,
CGENERICCONTAINER2D *aDstContainer,
wxSize aInflateValue ) const;
void createNewPadWithClearance( const D_PAD *aPad,
CGENERICCONTAINER2D *aDstContainer,
wxSize aClearanceValue ) const;
COBJECT2D *createNewPadDrill( const D_PAD* aPad, int aInflateValue );
void AddPadsShapesWithClearanceToContainer( const MODULE *aModule,
CGENERICCONTAINER2D *aDstContainer,
PCB_LAYER_ID aLayerId,
int aInflateValue,
bool aSkipNPTHPadsWihNoCopper );
void AddGraphicsShapesWithClearanceToContainer( const MODULE *aModule,
CGENERICCONTAINER2D *aDstContainer,
PCB_LAYER_ID aLayerId,
int aInflateValue );
void AddShapeWithClearanceToContainer( const TEXTE_PCB *aTextPCB,
CGENERICCONTAINER2D *aDstContainer,
PCB_LAYER_ID aLayerId,
int aClearanceValue );
void AddShapeWithClearanceToContainer( const DRAWSEGMENT *aDrawSegment,
CGENERICCONTAINER2D *aDstContainer,
PCB_LAYER_ID aLayerId,
int aClearanceValue );
void AddShapeWithClearanceToContainer( const DIMENSION *aDimension,
CGENERICCONTAINER2D *aDstContainer,
PCB_LAYER_ID aLayerId,
int aClearanceValue );
void AddSolidAreasShapesToContainer( const ZONE_CONTAINER *aZoneContainer,
CGENERICCONTAINER2D *aDstContainer,
PCB_LAYER_ID aLayerId );
void TransformArcToSegments( const wxPoint &aCentre,
const wxPoint &aStart,
double aArcAngle,
int aCircleToSegmentsCount,
int aWidth,
CGENERICCONTAINER2D *aDstContainer,
const BOARD_ITEM &aBoardItem );
void buildPadShapeThickOutlineAsSegments( const D_PAD *aPad,
CGENERICCONTAINER2D *aDstContainer,
int aWidth );
// Helper functions to create poly contours
void buildPadShapeThickOutlineAsPolygon( const D_PAD *aPad,
SHAPE_POLY_SET &aCornerBuffer,
int aWidth) const;
void transformPadsShapesWithClearanceToPolygon( const DLIST<D_PAD> &aPads,
PCB_LAYER_ID aLayer,
SHAPE_POLY_SET &aCornerBuffer,
int aInflateValue,
bool aSkipNPTHPadsWihNoCopper) const;
void transformGraphicModuleEdgeToPolygonSet( const MODULE *aModule,
PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer ) const;
void buildPadShapePolygon( const D_PAD *aPad,
SHAPE_POLY_SET &aCornerBuffer,
wxSize aInflateValue,
int aSegmentsPerCircle,
double aCorrectionFactor ) const;
public:
SFVEC3D m_BgColorBot; ///< background bottom color
SFVEC3D m_BgColorTop; ///< background top color
SFVEC3D m_BoardBodyColor; ///< in realistic mode: FR4 board color
SFVEC3D m_SolderMaskColor; ///< in realistic mode: solder mask color
SFVEC3D m_SolderPasteColor; ///< in realistic mode: solder paste color
SFVEC3D m_SilkScreenColor; ///< in realistic mode: SilkScreen color
SFVEC3D m_CopperColor; ///< in realistic mode: copper color
private:
/// Current board
BOARD *m_board;
/// pointer to the 3d model manager
S3D_CACHE *m_3d_model_manager;
// Render options
/// options flags to render the board
std::vector< bool > m_drawFlags;
/// Stores the current grid type
GRID3D_TYPE m_3D_grid_type;
/// render engine currently on use
RENDER_ENGINE m_render_engine;
/// mode to render the 3d shape models material
MATERIAL_MODE m_material_mode;
// Pcb board position
/// center board actual position in board units
wxPoint m_boardPos;
/// board actual size in board units
wxSize m_boardSize;
/// 3d center position of the pcb board in 3d units
SFVEC3F m_boardCenter;
// Pcb board bounding boxes
/// 3d bouding box of the pcb board in 3d units
CBBOX m_boardBoudingBox;
/// 2d bouding box of the pcb board in 3d units
CBBOX2D m_board2dBBox3DU;
/// It contains polygon contours for each layer
MAP_POLY m_layers_poly;
/// It contains polygon contours for holes of each layer (outer holes)
MAP_POLY m_layers_outer_holes_poly;
/// It contains polygon contours for holes of each layer (inner holes)
MAP_POLY m_layers_inner_holes_poly;
/// It contains polygon contours for (just) non plated through holes (outer cylinder)
SHAPE_POLY_SET m_through_outer_holes_poly_NPTH;
/// It contains polygon contours for through holes (outer cylinder)
SHAPE_POLY_SET m_through_outer_holes_poly;
/// It contains polygon contours for through holes (inner cylinder)
SHAPE_POLY_SET m_through_inner_holes_poly;
/// It contains polygon contours for through holes vias (outer cylinder)
SHAPE_POLY_SET m_through_outer_holes_vias_poly;
/// It contains polygon contours for through holes vias (inner cylinder)
SHAPE_POLY_SET m_through_inner_holes_vias_poly;
/// PCB board outline polygon
SHAPE_POLY_SET m_board_poly;
// 2D element containers
/// It contains the 2d elements of each layer
MAP_CONTAINER_2D m_layers_container2D;
/// It contains the holes per each layer
MAP_CONTAINER_2D m_layers_holes2D;
/// It contains the list of throughHoles of the board,
/// the radius of the hole is inflated with the copper tickness
CBVHCONTAINER2D m_through_holes_outer;
/// It contains the list of throughHoles of the board,
/// the radius is the inner hole
CBVHCONTAINER2D m_through_holes_inner;
/// It contains the list of throughHoles vias of the board,
/// the radius of the hole is inflated with the copper tickness
CBVHCONTAINER2D m_through_holes_vias_outer;
/// It contains the list of throughHoles vias of the board,
/// the radius of the hole
CBVHCONTAINER2D m_through_holes_vias_inner;
// Layers information
/// Number of copper layers actually used by the board
unsigned int m_copperLayersCount;
/// Normalization scale to convert board internal units to 3D units to
/// normalize 3D units between -1.0 and +1.0
double m_biuTo3Dunits;
/// Top (End) Z position of each layer (normalized)
float m_layerZcoordTop[PCB_LAYER_ID_COUNT];
/// Bottom (Start) Z position of each layer (normalized)
float m_layerZcoordBottom[PCB_LAYER_ID_COUNT];
/// Copper thickness (normalized)
float m_copperThickness3DU;
/// Epoxy thickness (normalized)
float m_epoxyThickness3DU;
/// Non copper layers thickness
float m_nonCopperLayerThickness3DU;
// Cameras
/// Holds a pointer to current camera in use.
CCAMERA &m_currentCamera;
CTRACK_BALL m_trackBallCamera;
/// min factor used for cicle segment approximation calculation
float m_calc_seg_min_factor3DU;
/// max factor used for cicle segment approximation calculation
float m_calc_seg_max_factor3DU;
// Statistics
/// Number of tracks in the board
unsigned int m_stats_nr_tracks;
/// Track average width
float m_stats_track_med_width;
/// Nr of vias
unsigned int m_stats_nr_vias;
/// Computed medium diameter of the via holes in 3D units
float m_stats_via_med_hole_diameter;
/// number of holes in the board
unsigned int m_stats_nr_holes;
/// Computed medium diameter of the holes in 3D units
float m_stats_hole_med_diameter;
/**
* 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_CINFO3D_VISU". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
static const wxChar *m_logTrace;
};
/// This is a dummy visualization configuration
extern CINFO3D_VISU G_null_CINFO3D_VISU;
#endif // CINFO3D_VISU_H
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+188 -34
View File
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
* 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
@@ -25,65 +25,219 @@
/**
* @file create_layer_poly.cpp
* @brief This file implements the creation of the pcb board items in the poly
* contours format.
* contours format. It is based on the function found in the files:
* board_items_to_polygon_shape_transform.cpp
* board_items_to_polygon_shape_transform.cpp
*/
#include "board_adapter.h"
#include <board_design_settings.h>
#include "cinfo3d_visu.h"
#include <convert_basic_shapes_to_polygon.h>
#include <fp_shape.h>
#include <footprint.h>
#include <class_edge_mod.h>
#include <class_module.h>
/*
* This is used to draw pad outlines on silk layers.
*/
void BOARD_ADAPTER::buildPadOutlineAsPolygon( const PAD* aPad, SHAPE_POLY_SET& aBuffer,
int aWidth ) const
// This is the same function as in board_items_to_polygon_shape_transform.cpp
// but it adds the rect/trapezoid shapes with a different winding
void CINFO3D_VISU::buildPadShapePolygon( const D_PAD* aPad,
SHAPE_POLY_SET& aCornerBuffer,
wxSize aInflateValue,
int aSegmentsPerCircle,
double aCorrectionFactor ) const
{
int maxError = m_board->GetDesignSettings().m_MaxError;
if( aPad->GetShape() == PAD_SHAPE::CIRCLE ) // Draw a ring
wxPoint corners[4];
wxPoint PadShapePos = aPad->ShapePos(); /* Note: for pad having a shape offset,
* the pad position is NOT the shape position */
switch( aPad->GetShape() )
{
TransformRingToPolygon( aBuffer, aPad->ShapePos(), aPad->GetSize().x / 2, aWidth, maxError,
ERROR_INSIDE );
case PAD_SHAPE_CIRCLE:
case PAD_SHAPE_OVAL:
case PAD_SHAPE_ROUNDRECT:
{
// We are using TransformShapeWithClearanceToPolygon to build the shape.
// Currently, this method uses only the same inflate value for X and Y dirs.
// so because here this is not the case, we use a inflated dummy pad to build
// the polygonal shape
// TODO: remove this dummy pad when TransformShapeWithClearanceToPolygon will use
// a wxSize to inflate the pad size
D_PAD dummy( *aPad );
wxSize new_size = aPad->GetSize() + aInflateValue + aInflateValue;
dummy.SetSize( new_size );
dummy.TransformShapeWithClearanceToPolygon( aCornerBuffer, 0,
aSegmentsPerCircle, aCorrectionFactor );
}
break;
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_RECT:
{
SHAPE_LINE_CHAIN aLineChain;
aPad->BuildPadPolygon( corners, aInflateValue, aPad->GetOrientation() );
for( int ii = 0; ii < 4; ++ii )
{
corners[3-ii] += PadShapePos; // Shift origin to position
aLineChain.Append( corners[3-ii].x, corners[3-ii].y );
}
aLineChain.SetClosed( true );
aCornerBuffer.AddOutline( aLineChain );
}
break;
case PAD_SHAPE_CUSTOM:
{
SHAPE_POLY_SET polyList; // Will contain the pad outlines in board coordinates
polyList.Append( aPad->GetCustomShapeAsPolygon() );
aPad->CustomShapeAsPolygonToBoardPosition( &polyList, aPad->ShapePos(), aPad->GetOrientation() );
aCornerBuffer.Append( polyList );
}
break;
}
}
void CINFO3D_VISU::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
SHAPE_POLY_SET& aCornerBuffer,
int aWidth ) const
{
if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring
{
unsigned int nr_sides_per_circle = GetNrSegmentsCircle( ( aPad->GetSize().x / 2 +
aWidth / 2 ) * 2 );
TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(),
aPad->GetSize().x / 2, nr_sides_per_circle, aWidth );
return;
}
// For other shapes, add outlines as thick segments in polygon buffer
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( ERROR_INSIDE );
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
// For other shapes, draw polygon outlines
SHAPE_POLY_SET corners;
unsigned int nr_sides_per_circle = GetNrSegmentsCircle( glm::min( aPad->GetSize().x,
aPad->GetSize().y) );
buildPadShapePolygon( aPad, corners, wxSize( 0, 0 ),
nr_sides_per_circle,
GetCircleCorrectionFactor( nr_sides_per_circle ) );
// 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 );
TransformOvalToPolygon( aBuffer, a, b, aWidth, maxError, ERROR_INSIDE );
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
wxPoint( a.x, a.y ),
wxPoint( b.x, b.y ),
nr_sides_per_circle,
aWidth );
}
}
void BOARD_ADAPTER::transformFPShapesToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aBuffer ) const
// Based on the same function name in board_items_to_polyshape_transform.cpp
// It was implemented here to allow dynamic segments count per pad shape
void CINFO3D_VISU::transformPadsShapesWithClearanceToPolygon( const DLIST<D_PAD>& aPads, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue,
bool aSkipNPTHPadsWihNoCopper ) const
{
int maxError = m_board->GetDesignSettings().m_MaxError;
const D_PAD* pad = aPads;
for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
wxSize margin;
for( ; pad != NULL; pad = pad->Next() )
{
if( item->Type() == PCB_FP_SHAPE_T )
{
FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
if( !pad->IsOnLayer(aLayer) )
continue;
if( shape->GetLayer() == aLayer )
shape->TransformShapeToPolygon( aBuffer, aLayer, 0, maxError, ERROR_INSIDE );
// NPTH pads are not drawn on layers if the shape size and pos is the same
// as their hole:
if( aSkipNPTHPadsWihNoCopper && (pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED) )
{
if( (pad->GetDrillSize() == pad->GetSize()) &&
(pad->GetOffset() == wxPoint( 0, 0 )) )
{
switch( pad->GetShape() )
{
case PAD_SHAPE_CIRCLE:
if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
continue;
break;
case PAD_SHAPE_OVAL:
if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
continue;
break;
default:
break;
}
}
}
else if( BaseType( item->Type() ) == PCB_DIMENSION_T )
{
PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( item );
if( dimension->GetLayer() == aLayer )
dimension->TransformShapeToPolygon( aBuffer, aLayer, 0, maxError, ERROR_INSIDE );
switch( aLayer )
{
case F_Mask:
case B_Mask:
margin.x = margin.y = pad->GetSolderMaskMargin() + aInflateValue;
break;
case F_Paste:
case B_Paste:
margin = pad->GetSolderPasteMargin();
margin.x += aInflateValue;
margin.y += aInflateValue;
break;
default:
margin.x = margin.y = aInflateValue;
break;
}
unsigned int aCircleToSegmentsCount = GetNrSegmentsCircle( pad->GetSize().x );
double aCorrectionFactor = GetCircleCorrectionFactor( aCircleToSegmentsCount );
buildPadShapePolygon( pad, aCornerBuffer, margin,
aCircleToSegmentsCount, aCorrectionFactor );
}
}
void CINFO3D_VISU::transformGraphicModuleEdgeToPolygonSet( const MODULE *aModule,
PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer ) const
{
for( const EDA_ITEM* item = aModule->GraphicalItemsList();
item != NULL;
item = item->Next() )
{
switch( item->Type() )
{
case PCB_MODULE_EDGE_T:
{
EDGE_MODULE*outline = (EDGE_MODULE*) item;
if( outline->GetLayer() != aLayer )
break;
unsigned int aCircleToSegmentsCount =
GetNrSegmentsCircle( outline->GetBoundingBox().GetSizeMax() );
double aCorrectionFactor = GetCircleCorrectionFactor( aCircleToSegmentsCount );
outline->TransformShapeWithClearanceToPolygon( aCornerBuffer,
0,
aCircleToSegmentsCount,
aCorrectionFactor );
}
break;
default:
break;
}
}
}
File diff suppressed because it is too large Load Diff
+154 -201
View File
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2019 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
@@ -22,71 +22,61 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file eda_3d_canvas.h
* @brief
*/
#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 "cinfo3d_visu.h"
#include "3d_rendering/c3d_render_base.h"
#include "3d_rendering/3d_render_ogl_legacy/c3d_render_ogl_legacy.h"
#include "3d_rendering/3d_render_raytracing/c3d_render_raytracing.h"
#include "3d_cache/3d_cache.h"
#include <gal/hidpi_gl_3D_canvas.h>
#include <gal/hidpi_gl_canvas.h>
#include <wx/clipbrd.h>
#include <wx/dataobj.h>
#include <wx/image.h>
#include <wx/wupdlock.h>
#include <wx/timer.h>
class WX_INFOBAR;
class wxStatusBar;
class BOARD;
class RENDER_3D_RAYTRACE;
class RENDER_3D_OPENGL;
#include <wx/statusbr.h>
#include <pcb_base_frame.h>
/**
* Implement a canvas based on a wxGLCanvas
*/
class EDA_3D_CANVAS : public HIDPI_GL_3D_CANVAS
class EDA_3D_CANVAS : public HIDPI_GL_CANVAS
{
public:
public:
/**
* Create a new 3D Canvas with an attribute list.
*
* @param aParent the parent creator of this canvas.
* @param aAttribList a list of openGL options created by GetOpenGL_AttributesList.
* @param aBoard The board.
* @param aSettings the settings options to be used by this canvas.
* @brief EDA_3D_CANVAS - Creates a new 3D Canvas with a attribute list
* @param aParent: the parent creator of this canvas
* @param aAttribList: a list of openGL options created by GetOpenGL_AttributesList
* @param aBoard: The board
* @param aSettings: the settings options to be used by this canvas
*/
EDA_3D_CANVAS( wxWindow* aParent, const int* aAttribList,
BOARD_ADAPTER& aSettings, CAMERA& aCamera, S3D_CACHE* a3DCachePointer );
EDA_3D_CANVAS( wxWindow *aParent,
const int *aAttribList = 0,
BOARD *aBoard = NULL,
CINFO3D_VISU &aSettings = G_null_CINFO3D_VISU,
S3D_CACHE *a3DCachePointer = NULL );
~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 SetStatusBar( wxStatusBar* aStatusBar )
{
m_parentStatusBar = aStatusBar;
}
void SetInfoBar( WX_INFOBAR* aInfoBar )
{
m_parentInfoBar = aInfoBar;
}
void ReloadRequest( BOARD* aBoard = nullptr, S3D_CACHE* aCachePointer = nullptr );
void ReloadRequest( BOARD *aBoard = NULL, S3D_CACHE *aCachePointer = NULL );
/**
* Query if there is a pending reload request.
*
* @return true if it wants to reload, false if there is no reload pending.
* @brief IsReloadRequestPending - 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
{
@@ -97,235 +87,198 @@ public:
}
/**
* @return the current render ( a RENDER_3D_RAYTRACE* or a RENDER_3D_OPENGL* render )
*/
RENDER_3D_BASE* GetCurrentRender() const { return m_3d_render; }
/**
* Request to render the current view in Raytracing mode.
* @brief RenderRaytracingRequest - Request to render the current view in Raytracing mode
*/
void RenderRaytracingRequest();
/**
* Request a screenshot and output it to the \a aDstImage
*
* Request a screenshot and output it to the aDstImage
* @param aDstImage - Screenshot destination image
*/
void GetScreenshot( wxImage& aDstImage );
void GetScreenshot( wxImage &aDstImage );
/**
* Helper function to call view commands.
*
* @param aKeycode ascii key commands.
* @return true if the key code was handled, false if no command found for this code.
* @brief SetView3D - Helper function to call view commands
* @param aKeycode: ascii key commands
* @return true if the key code was handled,
* false if no command found for this code.
*/
bool SetView3D( int aKeycode );
/**
* 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.
* @brief RenderEngineChanged - Notify that the render engine was changed
*/
void RenderEngineChanged();
/**
* Update the status bar with the position information.
* @brief DisplayStatus - 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.
* @brief Request_refresh - 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 );
void OnKeyEvent( wxKeyEvent& event );
bool SupportsRayTracing() const { return m_opengl_supports_raytracing; }
bool IsOpenGLInitialized() const { return m_is_opengl_initialized; }
/**
* Get information used to display 3D board.
* Return a structure containing currently used hotkey mapping.
*/
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();
EDA_HOTKEY_CONFIG* GetHotkeyConfig() const;
private:
// The wxPaintEvent event. mainly calls DoRePaint()
void OnPaint( wxPaintEvent& aEvent );
void OnEraseBackground( wxEraseEvent& event );
void OnPaint( wxPaintEvent &event );
void OnRefreshRequest( wxEvent& aEvent );
void OnEraseBackground( wxEraseEvent &event );
void OnMouseWheel( wxMouseEvent& event );
void OnMouseWheel( wxMouseEvent &event );
#if wxCHECK_VERSION( 3, 1, 0 ) || defined( 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 OnMouseMove( wxMouseEvent &event );
void OnLeftDown( wxMouseEvent &event );
void OnLeftUp( wxMouseEvent &event );
void OnMiddleUp( wxMouseEvent &event );
void OnMiddleDown( wxMouseEvent &event );
void OnRightClick( wxMouseEvent &event );
void OnPopUpMenu( wxCommandEvent &event );
void OnCharHook( wxKeyEvent& event );
void OnTimerTimeout_Editing( wxTimerEvent& event );
void OnCloseWindow( wxCloseEvent& event );
void OnResize( wxSizeEvent& event );
/**
* @brief OnCloseWindow - called when the frame is closed
* @param event
*/
void OnCloseWindow( wxCloseEvent &event );
void OnResize( wxSizeEvent &event );
void OnTimerTimeout_Redraw( wxTimerEvent& event );
DECLARE_EVENT_TABLE()
private:
/**
*Stop the editing time so it will not timeout.
* @brief stop_editingTimeOut_Timer - stop the editing time, so it will not timeout
*/
void stop_editingTimeOut_Timer();
/**
* Reset the editing timer.
* @brief restart_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.
* @brief request_start_moving_camera - 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 );
/**
* @brief move_pivot_based_on_cur_mouse_position -
* This function hits a ray to the board and start a moviment
*/
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.
* @brief render_pivot - 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.
* @brief initializeOpenGL
* @return if OpenGL initialization succeed
*/
bool initializeOpenGL();
/**
* Free created targets and openGL context.
* @brief releaseOpenGL - free created targets and openGL context
*/
void releaseOpenGL();
RAY getRayAtCurrentMousePosition();
private:
private:
TOOL_DISPATCHER* m_eventDispatcher;
wxStatusBar* m_parentStatusBar; // Parent statusbar to report progress
WX_INFOBAR* m_parentInfoBar;
/// current OpenGL context
wxGLContext *m_glRC;
wxGLContext* m_glRC; // Current OpenGL context
bool m_is_opengl_initialized;
bool m_is_opengl_version_supported;
/// Parent statusbar to report progress
wxStatusBar *m_parentStatusBar;
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
/// Time timeout will expires after some time sinalizing that the mouse /
/// keyboard movements are over.
wxTimer m_editing_timeout_timer;
bool m_render_pivot; // Render the pivot while camera moving
float m_camera_moving_speed; // 1.0f will be 1:1
unsigned 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
/// This timer will be used to schedule a redraw event
wxTimer m_redraw_trigger_timer;
BOARD_ADAPTER& m_boardAdapter; // Pre-computed 3D info and settings
RENDER_3D_BASE* m_3d_render;
RENDER_3D_RAYTRACE* m_3d_render_raytracing;
RENDER_3D_OPENGL* m_3d_render_opengl;
/// true if mouse activity is on progress
bool m_mouse_is_moving;
bool m_opengl_supports_raytracing;
bool m_render_raytracing_was_requested;
/// true if there was some type of activity, it will be used to render in
/// preview mode
bool m_mouse_was_moved;
ACCELERATOR_3D* m_accelerator3DShapes; // used for mouse over searching
/// true if camera animation is ongoing
bool m_camera_is_moving;
BOARD_ITEM* m_currentRollOverItem;
/// activated the render of pivot while camera moving
bool m_render_pivot;
bool m_render3dmousePivot = false; // Render the 3dmouse pivot
SFVEC3F m_3dmousePivotPos; // The position of the 3dmouse pivot
/// 1.0f will be 1:1
float m_camera_moving_speed;
/// Stores the ticktime when the camera star its movement
unsigned m_strtime_camera_movement;
/// Stores all pre-computed 3D information and visualization settings to render the board
CINFO3D_VISU &m_settings;
/// The current render in used for this canvas
C3D_RENDER_BASE *m_3d_render;
/// Raytracing render class
C3D_RENDER_RAYTRACING *m_3d_render_raytracing;
/// OpenGL legacy render class
C3D_RENDER_OGL_LEGACY *m_3d_render_ogl_legacy;
/// Flag to store if opengl was initialized already
bool m_is_opengl_initialized;
/// Step factor to used with cursor on relation to the current zoom
static const float m_delta_move_step_factor;
/// Flags that the user requested the current view to be render with raytracing
bool m_render_raytracing_was_requested;
bool m_opengl_supports_raytracing;
/**
* Trace mask used to enable or disable the trace output of this class.
@@ -333,7 +286,7 @@ private:
* "KI_TRACE_EDA_3D_CANVAS". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
static const wxChar* m_logTrace;
static const wxChar *m_logTrace;
};
+21 -60
View File
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
* 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
@@ -35,26 +35,26 @@
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[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[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[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 );
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 );
@@ -73,7 +73,7 @@ static void pivot_render_triangles( float t )
}
void EDA_3D_CANVAS::render_pivot( float t, float aScale )
void EDA_3D_CANVAS::render_pivot( float t , float aScale )
{
wxASSERT( aScale >= 0.0f );
wxASSERT( t >= 0.0f );
@@ -81,27 +81,29 @@ void EDA_3D_CANVAS::render_pivot( float t, float aScale )
if( t > 1.0f )
t = 1.0f;
const SFVEC3F &lookAtPos = m_camera.GetLookAtPos_T1();
const SFVEC3F &lookAtPos = m_settings.CameraGet().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() ) );
glLoadMatrixf( glm::value_ptr( m_settings.CameraGet().GetProjectionMatrix() ) );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
glLoadMatrixf( glm::value_ptr( m_settings.CameraGet().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;
@@ -118,44 +120,3 @@ void EDA_3D_CANVAS::render_pivot( float t, float aScale )
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 );
}
@@ -0,0 +1,68 @@
/*
* 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 status_text_reporter.h
* @brief
*/
#ifndef STATUS_TEXT_REPORTER_H_
#define STATUS_TEXT_REPORTER_H_
#include <reporter.h>
/**
* Class STATUS_TEXT_REPORTER
* is a wrapper for reporting to a wxString in a wxFrame status text.
*/
class STATUS_TEXT_REPORTER : public REPORTER
{
private:
wxStatusBar *m_parentStatusBar;
int m_position;
bool m_hasMessage;
public:
STATUS_TEXT_REPORTER( wxStatusBar* aParentStatusBar, int aPosition = 0 ) :
REPORTER(),
m_parentStatusBar( aParentStatusBar ), m_position( aPosition )
{
m_hasMessage = false;
}
REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_UNDEFINED ) override
{
if( !aText.IsEmpty() )
m_hasMessage = true;
if( m_parentStatusBar )
m_parentStatusBar->SetStatusText( aText, m_position );
return *this;
}
bool HasMessage() const override { return m_hasMessage; }
};
#endif // STATUS_TEXT_REPORTER_H_
+46 -26
View File
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
* 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
@@ -30,48 +30,68 @@
#ifndef _3D_ENUMS_H_
#define _3D_ENUMS_H_
/// Rotation direction for the 3d canvas
enum class ROTATION_DIR
{
X_CW,
X_CCW,
Y_CW,
Y_CCW,
Z_CW,
Z_CCW
/// Flags used in rendering options
enum DISPLAY3D_FLG {
FL_AXIS=0, FL_ZONE,
FL_ADHESIVE, FL_SILKSCREEN, FL_SOLDERMASK, FL_SOLDERPASTE,
FL_COMMENTS, FL_ECO,
FL_MODULE_ATTRIBUTES_NORMAL,
FL_MODULE_ATTRIBUTES_NORMAL_INSERT,
FL_MODULE_ATTRIBUTES_VIRTUAL,
FL_SHOW_BOARD_BODY,
FL_MOUSEWHEEL_PANNING,
FL_USE_REALISTIC_MODE,
// OpenGL options
FL_RENDER_OPENGL_SHOW_MODEL_BBOX,
FL_RENDER_OPENGL_COPPER_THICKNESS,
// Raytracing options
FL_RENDER_RAYTRACING_SHADOWS,
FL_RENDER_RAYTRACING_BACKFLOOR,
FL_RENDER_RAYTRACING_REFRACTIONS,
FL_RENDER_RAYTRACING_REFLECTIONS,
FL_RENDER_RAYTRACING_POST_PROCESSING,
FL_RENDER_RAYTRACING_ANTI_ALIASING,
FL_RENDER_RAYTRACING_PROCEDURAL_TEXTURES,
FL_LAST
};
/// Camera types
enum class CAMERA_TYPE
enum CAMERA_TYPE
{
TRACKBALL
CAMERA_TRACKBALL
};
// Do not modify the following enum numbers, they are saved in the config file and used in the UI
/// Grid types
enum class GRID3D_TYPE
enum GRID3D_TYPE
{
NONE = 0,
GRID_1MM = 1,
GRID_2P5MM = 2,
GRID_5MM = 3,
GRID_10MM = 4
GRID3D_NONE,
GRID3D_1MM,
GRID3D_2P5MM,
GRID3D_5MM,
GRID3D_10MM
};
/// Render engine mode
enum class RENDER_ENGINE
enum RENDER_ENGINE
{
OPENGL = 0,
RAYTRACING = 1,
RENDER_ENGINE_OPENGL_LEGACY,
RENDER_ENGINE_RAYTRACING,
};
/// Render 3d model shape materials mode
enum class MATERIAL_MODE
enum MATERIAL_MODE
{
NORMAL = 0, ///< Use all material properties from model file
DIFFUSE_ONLY = 1, ///< Use only diffuse material properties
CAD_MODE = 2 ///< Use a gray shading based on diffuse material
MATERIAL_MODE_NORMAL, ///< Use all material properties from model file
MATERIAL_MODE_DIFFUSE_ONLY, ///< Use only diffuse material properties
MATERIAL_MODE_CAD_MODE ///< Use a gray shading based on diffuse material
};
#endif // _3D_ENUMS_H_
+2 -2
View File
@@ -30,9 +30,9 @@
#ifndef _3D_FASTMATH_H
#define _3D_FASTMATH_H
#include <string.h>
#include <stdint.h>
#include <cmath>
#include <cstdint>
#include <cstring>
// Define this flag to use fast math optimizations
+39 -30
View File
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
* 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
@@ -33,43 +33,44 @@
#include <plugins/3dapi/xv3d_types.h>
#include "3d_fastmath.h"
// https://en.wikipedia.org/wiki/Spherical_coordinate_system
/**
* https://en.wikipedia.org/wiki/Spherical_coordinate_system
*
* @brief SphericalToCartesian
* @param aInclination θ [0, π]
* @param aAzimuth φ [0, 2π]
* @return Cartesian coordinates
* @return Cartesian cordinates
*/
inline SFVEC3F SphericalToCartesian( float aInclination, float aAzimuth )
{
float sinInc = glm::sin( aInclination );
return SFVEC3F( sinInc * glm::cos( aAzimuth ), sinInc * glm::sin( aAzimuth ),
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()
// https://pathtracing.wordpress.com/2011/03/03/cosine-weighted-hemisphere/
// !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 );
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 )
inline SFVEC3F CosWeightedRandomHemisphereDirection( const SFVEC3F &n )
{
const float Xi1 = (float) rand() / (float) RAND_MAX;
const float Xi2 = (float) rand() / (float) RAND_MAX;
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;
@@ -98,19 +99,21 @@ inline SFVEC3F CosWeightedRandomHemisphereDirection( const SFVEC3F& n )
/**
* @brief Refract
* 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.
* @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 )
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 );
@@ -130,7 +133,11 @@ inline bool Refract( const SFVEC3F &aInVector, const SFVEC3F &aNormal, float aRi
}
inline float mapf( float x, float in_min, float in_max, float out_min, float out_max )
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 );
@@ -147,15 +154,17 @@ inline float RGBtoGray( const SFVEC3F &aColor )
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 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 );
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;
return (aDiffuseColor / SFVEC3F(maxValue) ) * 0.125f + luminance* 0.875f;
}
@@ -170,7 +179,7 @@ inline float QuadricEasingInOut( float t )
{
t = t - 1.0f;
return -2.0f * ( t * t ) + 1.0f;
return -2.0f * (t * t) + 1.0f;
}
}
@@ -0,0 +1,471 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2017 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 c3d_model_viewer.cpp
* @brief Implements a model viewer canvas. The propose of model viewer is to
* render 3d models that come in the original data from the files without any
* transformations.
*/
#include <iostream>
#include "3d_rendering/3d_render_ogl_legacy/c_ogl_3dmodel.h"
#include "c3d_model_viewer.h"
#include "../3d_rendering/3d_render_ogl_legacy/ogl_legacy_utils.h"
#include "../3d_cache/3d_cache.h"
#include "common_ogl/ogl_utils.h"
#include <wx/dcclient.h>
#include <base_units.h>
#include <gl_context_mgr.h>
/**
* Scale convertion from 3d model units to pcb units
*/
#define UNITS3D_TO_UNITSPCB (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.
*/
const wxChar * C3D_MODEL_VIEWER::m_logTrace = wxT( "KI_TRACE_EDA_3D_MODEL_VIEWER" );
BEGIN_EVENT_TABLE( C3D_MODEL_VIEWER, wxGLCanvas )
EVT_PAINT( C3D_MODEL_VIEWER::OnPaint )
// mouse events
EVT_LEFT_DOWN( C3D_MODEL_VIEWER::OnLeftDown )
EVT_LEFT_UP( C3D_MODEL_VIEWER::OnLeftUp )
EVT_MIDDLE_UP( C3D_MODEL_VIEWER::OnMiddleUp )
EVT_MIDDLE_DOWN(C3D_MODEL_VIEWER::OnMiddleDown)
EVT_RIGHT_DOWN( C3D_MODEL_VIEWER::OnRightClick )
EVT_MOUSEWHEEL( C3D_MODEL_VIEWER::OnMouseWheel )
EVT_MOTION( C3D_MODEL_VIEWER::OnMouseMove )
#ifdef USE_OSX_MAGNIFY_EVENT
EVT_MAGNIFY( C3D_MODEL_VIEWER::OnMagnify )
#endif
// other events
EVT_ERASE_BACKGROUND( C3D_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
C3D_MODEL_VIEWER::C3D_MODEL_VIEWER(wxWindow *aParent,
const int *aAttribList , S3D_CACHE *aCacheManager) :
HIDPI_GL_CANVAS( aParent,
wxID_ANY,
aAttribList,
wxDefaultPosition,
wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE ),
m_trackBallCamera( RANGE_SCALE_3D * 2.0f ),
m_cacheManager(aCacheManager)
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::C3D_MODEL_VIEWER" ) );
m_ogl_initialized = false;
m_reload_is_needed = false;
m_ogl_3dmodel = NULL;
m_3d_model = NULL;
m_BiuTo3Dunits = 1.0;
m_glRC = NULL;
}
C3D_MODEL_VIEWER::~C3D_MODEL_VIEWER()
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::~C3D_MODEL_VIEWER" ) );
if( m_glRC )
{
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
delete m_ogl_3dmodel;
m_ogl_3dmodel = NULL;
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC );
GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glRC );
}
}
void C3D_MODEL_VIEWER::Set3DModel( const S3DMODEL &a3DModel )
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::Set3DModel with a S3DMODEL" ) );
// Validate a3DModel pointers
wxASSERT( a3DModel.m_Materials != NULL );
wxASSERT( a3DModel.m_Meshes != NULL );
wxASSERT( a3DModel.m_MaterialsSize > 0 );
wxASSERT( a3DModel.m_MeshesSize > 0 );
// Delete the old model
delete m_ogl_3dmodel;
m_ogl_3dmodel = NULL;
m_3d_model = NULL;
if( (a3DModel.m_Materials != NULL) && (a3DModel.m_Meshes != NULL) &&
(a3DModel.m_MaterialsSize > 0) && (a3DModel.m_MeshesSize > 0) )
{
m_3d_model = &a3DModel;
m_reload_is_needed = true;
}
Refresh();
}
void C3D_MODEL_VIEWER::Set3DModel(const wxString &aModelPathName)
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::Set3DModel with a wxString" ) );
if( m_cacheManager )
{
const S3DMODEL* model = m_cacheManager->GetModel( aModelPathName );
if( model )
Set3DModel( (const S3DMODEL &)*model );
else
Clear3DModel();
}
}
void C3D_MODEL_VIEWER::Clear3DModel()
{
// Delete the old model
m_reload_is_needed = false;
delete m_ogl_3dmodel;
m_ogl_3dmodel = NULL;
m_3d_model = NULL;
Refresh();
}
void C3D_MODEL_VIEWER::ogl_initialize()
{
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 );
//glDepthFunc( GL_LEQUAL );
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 C3D_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 C3D_MODEL_VIEWER::OnPaint( wxPaintEvent &event )
{
wxPaintDC( this );
event.Skip( false );
// SwapBuffer requires the window to be shown before calling
if( !IsShownOnScreen() )
{
wxLogTrace( m_logTrace, wxT( "C3D_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 == NULL )
m_glRC = GL_CONTEXT_MANAGER::Get().CreateCtx( this );
GL_CONTEXT_MANAGER::Get().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 = GetClientSize();
if( !m_ogl_initialized )
{
m_ogl_initialized = true;
ogl_initialize();
}
if( m_reload_is_needed )
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnPaint m_reload_is_needed" ) );
m_reload_is_needed = false;
m_ogl_3dmodel = new C_OGL_3DMODEL( *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, 1.0f );
glClearDepth( 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// Set projection and modelview matrixes
// /////////////////////////////////////////////////////////////////////////
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->Draw_opaque();
m_ogl_3dmodel->Draw_transparent();
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 );
OGL_draw_arrow( 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 );
OGL_draw_arrow( 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 );
OGL_draw_arrow( 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();
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC );
}
void C3D_MODEL_VIEWER::OnEraseBackground( wxEraseEvent &event )
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnEraseBackground" ) );
// Do nothing, to avoid flashing.
}
void C3D_MODEL_VIEWER::OnMouseWheel( wxMouseEvent &event )
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnMouseWheel" ) );
if( event.ShiftDown() )
{
//if( event.GetWheelRotation() < 0 )
//SetView3D( WXK_UP ); // move up
//else
//SetView3D( WXK_DOWN ); // move down
}
else if( event.ControlDown() )
{
//if( event.GetWheelRotation() > 0 )
//SetView3D( WXK_RIGHT ); // move right
//else
//SetView3D( WXK_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 C3D_MODEL_VIEWER::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 C3D_MODEL_VIEWER::OnMouseMove( wxMouseEvent &event )
{
m_trackBallCamera.SetCurWindowSize( GetClientSize() );
if( event.Dragging() )
{
if( event.LeftIsDown() ) // Drag
m_trackBallCamera.Drag( event.GetPosition() );
//else if( event.MiddleIsDown() ) // Pan
// m_trackBallCamera.Pan( event.GetPosition() );
// orientation has changed, redraw mesh
Refresh( false );
}
m_trackBallCamera.SetCurMousePosition( event.GetPosition() );
}
void C3D_MODEL_VIEWER::OnLeftDown( wxMouseEvent &event )
{
//m_is_moving_mouse = true;
event.Skip();
}
void C3D_MODEL_VIEWER::OnLeftUp( wxMouseEvent &event )
{
//m_is_moving_mouse = false;
//Refresh( false );
event.Skip();
}
void C3D_MODEL_VIEWER::OnMiddleDown( wxMouseEvent &event )
{
//m_is_moving_mouse = true;
event.Skip();
}
void C3D_MODEL_VIEWER::OnMiddleUp( wxMouseEvent &event )
{
//m_is_moving_mouse = false;
//Refresh( false );
event.Skip();
}
void C3D_MODEL_VIEWER::OnRightClick( wxMouseEvent &event )
{
event.Skip();
}
@@ -0,0 +1,147 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2019 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 c3d_model_viewer.h
* @brief Implements a model viewer canvas. The propose 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/ctrack_ball.h"
#include <gal/hidpi_gl_canvas.h>
class S3D_CACHE;
class C_OGL_3DMODEL;
/**
* Class C3D_MODEL_VIEWER
* Implement a canvas based on a wxGLCanvas
*/
class C3D_MODEL_VIEWER : public HIDPI_GL_CANVAS
{
public:
/**
* Creates a new 3D Canvas with a attribute list
* @param aParent = the parent creator of this canvas
* @param aAttribList = a list of openGL options created by
* COGL_ATT_LIST::GetAttributesList
*/
C3D_MODEL_VIEWER( wxWindow *aParent,
const int *aAttribList = 0,
S3D_CACHE *aCacheManager = NULL );
~C3D_MODEL_VIEWER();
/**
* @brief Set3DModel - Set this model to be displayed
* @param a3DModel - 3d model data
*/
void Set3DModel( const S3DMODEL &a3DModel );
/**
* @brief Set3DModel - Set this model to be displayed
* @param aModelPathName - 3d model path name
*/
void Set3DModel( wxString const& aModelPathName );
/**
* @brief Clear3DModel - Unloads the displayed 3d model
*/
void Clear3DModel();
private:
void ogl_initialize();
void ogl_set_arrow_material();
private:
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()
private:
/// openGL context
wxGLContext *m_glRC;
/// Camera used in this canvas
CTRACK_BALL m_trackBallCamera;
/// Original 3d model data
const S3DMODEL *m_3d_model;
/// Class holder for 3d model to display on openGL
C_OGL_3DMODEL *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_
@@ -1,481 +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) 1992-2021 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 <gl_context_mgr.h>
#include <settings/common_settings.h>
#include <pgm_base.h>
#include <gal/dpi_scaling.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 int* aAttribList,
S3D_CACHE* aCacheManager ) :
HIDPI_GL_CANVAS( aParent, wxID_ANY, aAttribList, 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;
COMMON_SETTINGS* settings = Pgm().GetCommonSettings();
const DPI_SCALING dpi{ settings, this };
SetScaleFactor( dpi.GetScaleFactor() );
}
EDA_3D_MODEL_VIEWER::~EDA_3D_MODEL_VIEWER()
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::~EDA_3D_MODEL_VIEWER" ) );
if( m_glRC )
{
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
delete m_ogl_3dmodel;
m_ogl_3dmodel = nullptr;
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC );
GL_CONTEXT_MANAGER::Get().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 );
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 ) ) );
}
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 = GL_CONTEXT_MANAGER::Get().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;
}
GL_CONTEXT_MANAGER::Get().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, 1.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();
GL_CONTEXT_MANAGER::Get().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( WXK_UP ); // move up
//else
//SetView3D( WXK_DOWN ); // move down
}
else if( event.ControlDown() )
{
//if( event.GetWheelRotation() > 0 )
//SetView3D( WXK_RIGHT ); // move right
//else
//SetView3D( WXK_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,141 +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) 1992-2021 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 c3d_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 aAttribList a list of openGL options created by #OGL_ATT_LIST::GetAttributesList.
*/
EDA_3D_MODEL_VIEWER( wxWindow* aParent, const int* aAttribList = nullptr,
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.
*
* @param aModelPathName 3D model path name.
*/
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_
-25
View File
@@ -1,25 +0,0 @@
add_library(3d-viewer_navlib STATIC
"nl_3d_viewer_plugin.cpp"
"nl_3d_viewer_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,43 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 3Dconnexion
* Copyright (C) 2021 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>
NL_3D_VIEWER_PLUGIN::NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport )
{
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver )
m_impl = new NL_3D_VIEWER_PLUGIN_IMPL( aViewport );
}
NL_3D_VIEWER_PLUGIN::~NL_3D_VIEWER_PLUGIN()
{
delete m_impl;
}
void NL_3D_VIEWER_PLUGIN::SetFocus( bool focus )
{
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver )
m_impl->SetFocus( focus );
}
-60
View File
@@ -1,60 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 3Dconnexion
* Copyright (C) 2021 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_
// 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:
NL_3D_VIEWER_PLUGIN_IMPL* m_impl;
};
#endif // NL_3D_VIEWER_PLUGIN_H_
@@ -1,659 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 3Dconnexion
* Copyright (C) 2021 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>
// 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 ) :
NAV_3D( false, false ), m_canvas( aCanvas ), m_capIsMoving( false )
{
m_camera = dynamic_cast<TRACK_BALL*>( m_canvas->GetCamera() );
PutProfileHint( "KiCAD 3D" );
EnableNavigation( true );
PutFrameTimingSource( TimingSource::SpaceMouse );
exportCommandsAndImages();
}
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 );
}
// 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 )
{
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->GetLabel().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.
if( parent->IsEnabled() )
{
TOOL_MANAGER* tool_manager = static_cast<PCB_BASE_FRAME*>( parent )->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, true );
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,136 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 3Dconnexion
* Copyright (C) 2021 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;
// 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.
*/
NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas );
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 );
private:
/**
* Export the invocable actions and images to the 3Dconnexion UI.
*/
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
View File
@@ -0,0 +1 @@
#define PLUGINDIR "@CMAKE_INSTALL_FULL_LIBDIR@"
@@ -0,0 +1,961 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 c3d_render_createscene_ogl_legacy.cpp
* @brief
*/
#include "c3d_render_ogl_legacy.h"
#include "ogl_legacy_utils.h"
#include <class_board.h>
#include <class_module.h>
#include "../../3d_math.h"
#include "../../3d_fastmath.h"
#include <trigo.h>
#include <project.h>
#include <profile.h> // To use GetRunningMicroSecs or another profiling utility
void C3D_RENDER_OGL_LEGACY::add_object_to_triangle_layer( const CFILLEDCIRCLE2D * aFilledCircle,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot )
{
const SFVEC2F &center = aFilledCircle->GetCenter();
const float radius = aFilledCircle->GetRadius() *
2.0f; // Double because the render triangle
// This is a small adjustment to the circle texture
const float texture_factor = (8.0f / (float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f;
const float f = (sqrtf(2.0f) / 2.0f) * radius * texture_factor;
// Top and Bot segments ends are just triangle semi-circles, so need to add
// it in duplicated
aDstLayer->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, aZtop ),
SFVEC3F( center.x - f, center.y, aZtop ),
SFVEC3F( center.x,
center.y - f, aZtop ) );
aDstLayer->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, aZtop ),
SFVEC3F( center.x + f, center.y, aZtop ),
SFVEC3F( center.x,
center.y + f, aZtop ) );
aDstLayer->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, aZbot ),
SFVEC3F( center.x + f, center.y, aZbot ),
SFVEC3F( center.x,
center.y - f, aZbot ) );
aDstLayer->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, aZbot ),
SFVEC3F( center.x - f, center.y, aZbot ),
SFVEC3F( center.x,
center.y + f, aZbot ) );
}
void C3D_RENDER_OGL_LEGACY::add_object_to_triangle_layer( const CPOLYGON4PTS2D * aPoly,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot )
{
const SFVEC2F &v0 = aPoly->GetV0();
const SFVEC2F &v1 = aPoly->GetV1();
const SFVEC2F &v2 = aPoly->GetV2();
const SFVEC2F &v3 = aPoly->GetV3();
add_triangle_top_bot( aDstLayer, v0, v2, v1, aZtop, aZbot );
add_triangle_top_bot( aDstLayer, v2, v0, v3, aZtop, aZbot );
}
void C3D_RENDER_OGL_LEGACY::generate_ring_contour( const SFVEC2F &aCenter,
float aInnerRadius,
float aOuterRadius,
unsigned int aNr_sides_per_circle,
std::vector< SFVEC2F > &aInnerContourResult,
std::vector< SFVEC2F > &aOuterContourResult,
bool aInvertOrder )
{
aInnerContourResult.clear();
aInnerContourResult.reserve( aNr_sides_per_circle + 2 );
aOuterContourResult.clear();
aOuterContourResult.reserve( aNr_sides_per_circle + 2 );
const int delta = 3600 / aNr_sides_per_circle;
for( int ii = 0; ii < 3600; ii += delta )
{
float angle = (float)( aInvertOrder ? ( 3600 - ii ) : ii )
* 2.0f * glm::pi<float>() / 3600.0f;
const SFVEC2F rotatedDir = SFVEC2F( cos( angle ), sin( angle ) );
aInnerContourResult.push_back( SFVEC2F( aCenter.x + rotatedDir.x * aInnerRadius,
aCenter.y + rotatedDir.y * aInnerRadius ) );
aOuterContourResult.push_back( SFVEC2F( aCenter.x + rotatedDir.x * aOuterRadius,
aCenter.y + rotatedDir.y * aOuterRadius ) );
}
aInnerContourResult.push_back( aInnerContourResult[0] );
aOuterContourResult.push_back( aOuterContourResult[0] );
wxASSERT( aInnerContourResult.size() == aOuterContourResult.size() );
}
void C3D_RENDER_OGL_LEGACY::add_object_to_triangle_layer( const CRING2D * aRing,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot )
{
const SFVEC2F &center = aRing->GetCenter();
const float inner = aRing->GetInnerRadius();
const float outer = aRing->GetOuterRadius();
std::vector< SFVEC2F > innerContour;
std::vector< SFVEC2F > outerContour;
generate_ring_contour( center,
inner,
outer,
m_settings.GetNrSegmentsCircle( outer * 2.0f ),
innerContour,
outerContour,
false );
// This will add the top and bot quads that will form the approximated ring
for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
{
const SFVEC2F &vi0 = innerContour[i + 0];
const SFVEC2F &vi1 = innerContour[i + 1];
const SFVEC2F &vo0 = outerContour[i + 0];
const SFVEC2F &vo1 = outerContour[i + 1];
aDstLayer->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZtop ),
SFVEC3F( vi0.x, vi0.y, aZtop ),
SFVEC3F( vo0.x, vo0.y, aZtop ),
SFVEC3F( vo1.x, vo1.y, aZtop ) );
aDstLayer->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZbot ),
SFVEC3F( vo1.x, vo1.y, aZbot ),
SFVEC3F( vo0.x, vo0.y, aZbot ),
SFVEC3F( vi0.x, vi0.y, aZbot ) );
}
}
void C3D_RENDER_OGL_LEGACY::add_object_to_triangle_layer( const CTRIANGLE2D * aTri,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot )
{
const SFVEC2F &v1 = aTri->GetP1();
const SFVEC2F &v2 = aTri->GetP2();
const SFVEC2F &v3 = aTri->GetP3();
add_triangle_top_bot( aDstLayer, v1, v2, v3, aZtop, aZbot );
}
void C3D_RENDER_OGL_LEGACY::add_object_to_triangle_layer( const CROUNDSEGMENT2D * aSeg,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot )
{
const SFVEC2F leftStart = aSeg->GetLeftStar();
const SFVEC2F leftEnd = aSeg->GetLeftEnd();
const SFVEC2F leftDir = aSeg->GetLeftDir();
const SFVEC2F rightStart = aSeg->GetRightStar();
const SFVEC2F rightEnd = aSeg->GetRightEnd();
const SFVEC2F rightDir = aSeg->GetRightDir();
const float radius = aSeg->GetRadius();
const SFVEC2F start = aSeg->GetStart();
const SFVEC2F end = aSeg->GetEnd();
const float texture_factor = (12.0f / (float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f;
const float texture_factorF= ( 6.0f / (float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f;
const float radius_of_the_square = sqrtf( aSeg->GetRadiusSquared() * 2.0f );
const float radius_triangle_factor = (radius_of_the_square - radius) / radius;
const SFVEC2F factorS = SFVEC2F( -rightDir.y * radius * radius_triangle_factor,
rightDir.x * radius * radius_triangle_factor );
const SFVEC2F factorE = SFVEC2F( -leftDir.y * radius * radius_triangle_factor,
leftDir.x * radius * radius_triangle_factor );
// Top end segment triangles (semi-circles)
aDstLayer->m_layer_top_segment_ends->AddTriangle(
SFVEC3F( rightEnd.x + texture_factor * factorS.x,
rightEnd.y + texture_factor * factorS.y,
aZtop ),
SFVEC3F( leftStart.x + texture_factor * factorE.x,
leftStart.y + texture_factor * factorE.y,
aZtop ),
SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
aZtop ) );
aDstLayer->m_layer_top_segment_ends->AddTriangle(
SFVEC3F( leftEnd.x + texture_factor * factorE.x,
leftEnd.y + texture_factor * factorE.y, aZtop ),
SFVEC3F( rightStart.x + texture_factor * factorS.x,
rightStart.y + texture_factor * factorS.y, aZtop ),
SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
aZtop ) );
// Bot end segment triangles (semi-circles)
aDstLayer->m_layer_bot_segment_ends->AddTriangle(
SFVEC3F( leftStart.x + texture_factor * factorE.x,
leftStart.y + texture_factor * factorE.y,
aZbot ),
SFVEC3F( rightEnd.x + texture_factor * factorS.x,
rightEnd.y + texture_factor * factorS.y,
aZbot ),
SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
aZbot ) );
aDstLayer->m_layer_bot_segment_ends->AddTriangle(
SFVEC3F( rightStart.x + texture_factor * factorS.x,
rightStart.y + texture_factor * factorS.y, aZbot ),
SFVEC3F( leftEnd.x + texture_factor * factorE.x,
leftEnd.y + texture_factor * factorE.y, aZbot ),
SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
aZbot ) );
// Segment top and bot planes
aDstLayer->m_layer_top_triangles->AddQuad(
SFVEC3F( rightEnd.x, rightEnd.y, aZtop ),
SFVEC3F( rightStart.x, rightStart.y, aZtop ),
SFVEC3F( leftEnd.x, leftEnd.y, aZtop ),
SFVEC3F( leftStart.x, leftStart.y, aZtop ) );
aDstLayer->m_layer_bot_triangles->AddQuad(
SFVEC3F( rightEnd.x, rightEnd.y, aZbot ),
SFVEC3F( leftStart.x, leftStart.y, aZbot ),
SFVEC3F( leftEnd.x, leftEnd.y, aZbot ),
SFVEC3F( rightStart.x, rightStart.y, aZbot ) );
}
CLAYERS_OGL_DISP_LISTS *C3D_RENDER_OGL_LEGACY::generate_holes_display_list(
const LIST_OBJECT2D &aListHolesObject2d,
const SHAPE_POLY_SET &aPoly,
float aZtop,
float aZbot,
bool aInvertFaces )
{
CLAYERS_OGL_DISP_LISTS *ret = NULL;
if( aListHolesObject2d.size() > 0 )
{
CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( aListHolesObject2d.size() * 2 );
// Convert the list of objects(filled circles) to triangle layer structure
for( LIST_OBJECT2D::const_iterator itemOnLayer = aListHolesObject2d.begin();
itemOnLayer != aListHolesObject2d.end();
++itemOnLayer )
{
const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);
wxASSERT( (object2d_A->GetObjectType() == OBJ2D_FILLED_CIRCLE) ||
(object2d_A->GetObjectType() == OBJ2D_ROUNDSEG) );
switch( object2d_A->GetObjectType() )
{
case OBJ2D_FILLED_CIRCLE:
add_object_to_triangle_layer( (const CFILLEDCIRCLE2D *)object2d_A,
layerTriangles,
aZtop, aZbot );
break;
case OBJ2D_ROUNDSEG:
add_object_to_triangle_layer( (const CROUNDSEGMENT2D *) object2d_A,
layerTriangles,
aZtop, aZbot );
break;
default:
wxFAIL_MSG("C3D_RENDER_OGL_LEGACY::generate_holes_display_list: Object type is not implemented");
break;
}
}
// Note: he can have a aListHolesObject2d whith holes but without countours
// eg: when there are only NPTH on the list and the contours were not
// added
if( aPoly.OutlineCount() > 0 )
{
layerTriangles->AddToMiddleContourns( aPoly,
aZbot,
aZtop,
m_settings.BiuTo3Dunits(),
aInvertFaces );
}
ret = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
m_ogl_circle_texture,
aZbot,
aZtop );
delete layerTriangles;
}
return ret;
}
void C3D_RENDER_OGL_LEGACY::reload( REPORTER *aStatusTextReporter )
{
m_reloadRequested = false;
ogl_free_all_display_lists();
COBJECT2D_STATS::Instance().ResetStats();
#ifdef PRINT_STATISTICS_3D_VIEWER
printf("InitSettings...\n");
#endif
unsigned stats_startReloadTime = GetRunningMicroSecs();
m_settings.InitSettings( aStatusTextReporter );
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_endReloadTime = GetRunningMicroSecs();
#endif
SFVEC3F camera_pos = m_settings.GetBoardCenter3DU();
m_settings.CameraGet().SetBoardLookAtPos( camera_pos );
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_start_OpenGL_Load_Time = GetRunningMicroSecs();
#endif
if( aStatusTextReporter )
aStatusTextReporter->Report( _( "Load OpenGL: board" ) );
// Create Board
// /////////////////////////////////////////////////////////////////////////
CCONTAINER2D boardContainer;
SHAPE_POLY_SET tmpBoard = m_settings.GetBoardPoly();
Convert_shape_line_polygon_to_triangles( tmpBoard,
boardContainer,
m_settings.BiuTo3Dunits(),
(const BOARD_ITEM &)*m_settings.GetBoard() );
const LIST_OBJECT2D &listBoardObject2d = boardContainer.GetList();
if( listBoardObject2d.size() > 0 )
{
// We will set a unitary Z so it will in future used with transformations
// since the board poly will be used not only to draw itself but also the
// solder mask layers.
const float layer_z_top = 1.0f;
const float layer_z_bot = 0.0f;
CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( listBoardObject2d.size() );
// Convert the list of objects(triangles) to triangle layer structure
for( LIST_OBJECT2D::const_iterator itemOnLayer = listBoardObject2d.begin();
itemOnLayer != listBoardObject2d.end();
++itemOnLayer )
{
const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);
wxASSERT( object2d_A->GetObjectType() == OBJ2D_TRIANGLE );
const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A;
const SFVEC2F &v1 = tri->GetP1();
const SFVEC2F &v2 = tri->GetP2();
const SFVEC2F &v3 = tri->GetP3();
add_triangle_top_bot( layerTriangles,
v1,
v2,
v3,
layer_z_top,
layer_z_bot );
}
const SHAPE_POLY_SET &boardPoly = m_settings.GetBoardPoly();
wxASSERT( boardPoly.OutlineCount() > 0 );
if( boardPoly.OutlineCount() > 0 )
{
layerTriangles->AddToMiddleContourns( boardPoly,
layer_z_bot,
layer_z_top,
m_settings.BiuTo3Dunits(),
false );
m_ogl_disp_list_board = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
m_ogl_circle_texture,
layer_z_top,
layer_z_top );
}
delete layerTriangles;
}
// Create Through Holes and vias
// /////////////////////////////////////////////////////////////////////////
if( aStatusTextReporter )
aStatusTextReporter->Report( _( "Load OpenGL: holes and vias" ) );
m_ogl_disp_list_through_holes_outer = generate_holes_display_list(
m_settings.GetThroughHole_Outer().GetList(),
m_settings.GetThroughHole_Outer_poly(),
1.0f,
0.0f,
false );
SHAPE_POLY_SET bodyHoles = m_settings.GetThroughHole_Outer_poly();
bodyHoles.BooleanAdd( m_settings.GetThroughHole_Outer_poly_NPTH(),
SHAPE_POLY_SET::PM_FAST );
m_ogl_disp_list_through_holes_outer_with_npth = generate_holes_display_list(
m_settings.GetThroughHole_Outer().GetList(),
bodyHoles,
1.0f,
0.0f,
false );
m_ogl_disp_list_through_holes_inner = generate_holes_display_list(
m_settings.GetThroughHole_Inner().GetList(),
m_settings.GetThroughHole_Inner_poly(),
1.0f,
0.0f,
true );
m_ogl_disp_list_through_holes_vias_outer = generate_holes_display_list(
m_settings.GetThroughHole_Vias_Outer().GetList(),
m_settings.GetThroughHole_Vias_Outer_poly(),
1.0f,
0.0f,
false );
// Not in use
//m_ogl_disp_list_through_holes_vias_inner = generate_holes_display_list(
// m_settings.GetThroughHole_Vias_Inner().GetList(),
// m_settings.GetThroughHole_Vias_Inner_poly(),
// 1.0f, 0.0f,
// false );
const MAP_POLY & innerMapHoles = m_settings.GetPolyMapHoles_Inner();
const MAP_POLY & outerMapHoles = m_settings.GetPolyMapHoles_Outer();
wxASSERT( innerMapHoles.size() == outerMapHoles.size() );
const MAP_CONTAINER_2D &map_holes = m_settings.GetMapLayersHoles();
if( outerMapHoles.size() > 0 )
{
float layer_z_bot = 0.0f;
float layer_z_top = 0.0f;
for( MAP_POLY::const_iterator ii = outerMapHoles.begin();
ii != outerMapHoles.end();
++ii )
{
PCB_LAYER_ID layer_id = static_cast<PCB_LAYER_ID>(ii->first);
const SHAPE_POLY_SET *poly = static_cast<const SHAPE_POLY_SET *>(ii->second);
const CBVHCONTAINER2D *container = map_holes.at( layer_id );
get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );
m_ogl_disp_lists_layers_holes_outer[layer_id] = generate_holes_display_list(
container->GetList(), *poly, layer_z_top, layer_z_bot, false );
}
for( MAP_POLY::const_iterator ii = innerMapHoles.begin();
ii != innerMapHoles.end();
++ii )
{
PCB_LAYER_ID layer_id = static_cast<PCB_LAYER_ID>(ii->first);
const SHAPE_POLY_SET *poly = static_cast<const SHAPE_POLY_SET *>(ii->second);
const CBVHCONTAINER2D *container = map_holes.at( layer_id );
get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );
m_ogl_disp_lists_layers_holes_inner[layer_id] = generate_holes_display_list(
container->GetList(), *poly, layer_z_top, layer_z_bot, false );
}
}
// Generate vertical cylinders of vias and pads (copper)
generate_3D_Vias_and_Pads();
// Add layers maps
if( aStatusTextReporter )
aStatusTextReporter->Report( _( "Load OpenGL: layers" ) );
for( MAP_CONTAINER_2D::const_iterator ii = m_settings.GetMapLayers().begin();
ii != m_settings.GetMapLayers().end();
++ii )
{
PCB_LAYER_ID layer_id = static_cast<PCB_LAYER_ID>(ii->first);
if( !m_settings.Is3DLayerEnabled( layer_id ) )
continue;
const CBVHCONTAINER2D *container2d = static_cast<const CBVHCONTAINER2D *>(ii->second);
const LIST_OBJECT2D &listObject2d = container2d->GetList();
if( listObject2d.size() == 0 )
continue;
float layer_z_bot = 0.0f;
float layer_z_top = 0.0f;
get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );
// Calculate an estimation for the nr of triangles based on the nr of objects
unsigned int nrTrianglesEstimation = listObject2d.size() * 8;
CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( nrTrianglesEstimation );
m_triangles[layer_id] = layerTriangles;
// Load the 2D (X,Y axis) component of shapes
for( LIST_OBJECT2D::const_iterator itemOnLayer = listObject2d.begin();
itemOnLayer != listObject2d.end();
++itemOnLayer )
{
const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);
switch( object2d_A->GetObjectType() )
{
case OBJ2D_FILLED_CIRCLE:
add_object_to_triangle_layer( (const CFILLEDCIRCLE2D *)object2d_A,
layerTriangles, layer_z_top, layer_z_bot );
break;
case OBJ2D_POLYGON4PT:
add_object_to_triangle_layer( (const CPOLYGON4PTS2D *)object2d_A,
layerTriangles, layer_z_top, layer_z_bot );
break;
case OBJ2D_RING:
add_object_to_triangle_layer( (const CRING2D *)object2d_A,
layerTriangles, layer_z_top, layer_z_bot );
break;
case OBJ2D_TRIANGLE:
add_object_to_triangle_layer( (const CTRIANGLE2D *)object2d_A,
layerTriangles, layer_z_top, layer_z_bot );
break;
case OBJ2D_ROUNDSEG:
add_object_to_triangle_layer( (const CROUNDSEGMENT2D *) object2d_A,
layerTriangles, layer_z_top, layer_z_bot );
break;
default:
wxFAIL_MSG("C3D_RENDER_OGL_LEGACY: Object type is not implemented");
break;
}
}
const MAP_POLY &map_poly = m_settings.GetPolyMap();
// Load the vertical (Z axis) component of shapes
if( map_poly.find( layer_id ) != map_poly.end() )
{
const SHAPE_POLY_SET *polyList = map_poly.at( layer_id );
if( polyList->OutlineCount() > 0 )
layerTriangles->AddToMiddleContourns( *polyList, layer_z_bot, layer_z_top,
m_settings.BiuTo3Dunits(), false );
}
// Create display list
// /////////////////////////////////////////////////////////////////////
m_ogl_disp_lists_layers[layer_id] = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
m_ogl_circle_texture,
layer_z_bot,
layer_z_top );
}// for each layer on map
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_end_OpenGL_Load_Time = GetRunningMicroSecs();
#endif
// Load 3D models
// /////////////////////////////////////////////////////////////////////////
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_start_models_Load_Time = GetRunningMicroSecs();
#endif
if( aStatusTextReporter )
aStatusTextReporter->Report( _( "Loading 3D models" ) );
load_3D_models( aStatusTextReporter );
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_end_models_Load_Time = GetRunningMicroSecs();
printf( "C3D_RENDER_OGL_LEGACY::reload times:\n" );
printf( " Reload board: %.3f ms\n",
(float)( stats_endReloadTime - stats_startReloadTime ) / 1000.0f );
printf( " Loading to openGL: %.3f ms\n",
(float)( stats_end_OpenGL_Load_Time - stats_start_OpenGL_Load_Time ) / 1000.0f );
printf( " Loading 3D models: %.3f ms\n",
(float)( stats_end_models_Load_Time - stats_start_models_Load_Time ) / 1000.0f );
COBJECT2D_STATS::Instance().PrintStats();
#endif
if( aStatusTextReporter )
{
// Calculation time in seconds
const double calculation_time = (double)( GetRunningMicroSecs() -
stats_startReloadTime) / 1e6;
aStatusTextReporter->Report( wxString::Format( _( "Reload time %.3f s" ),
calculation_time ) );
}
}
void C3D_RENDER_OGL_LEGACY::add_triangle_top_bot( CLAYER_TRIANGLES *aDst,
const SFVEC2F &v0,
const SFVEC2F &v1,
const SFVEC2F &v2,
float top,
float bot )
{
aDst->m_layer_bot_triangles->AddTriangle( SFVEC3F( v0.x, v0.y, bot ),
SFVEC3F( v1.x, v1.y, bot ),
SFVEC3F( v2.x, v2.y, bot ) );
aDst->m_layer_top_triangles->AddTriangle( SFVEC3F( v2.x, v2.y, top ),
SFVEC3F( v1.x, v1.y, top ),
SFVEC3F( v0.x, v0.y, top ) );
}
void C3D_RENDER_OGL_LEGACY::get_layer_z_pos ( PCB_LAYER_ID aLayerID,
float &aOutZtop,
float &aOutZbot ) const
{
aOutZbot = m_settings.GetLayerBottomZpos3DU( aLayerID );
aOutZtop = m_settings.GetLayerTopZpos3DU( aLayerID );
if( aOutZtop < aOutZbot )
{
float tmpFloat = aOutZbot;
aOutZbot = aOutZtop;
aOutZtop = tmpFloat;
}
}
void C3D_RENDER_OGL_LEGACY::generate_cylinder( const SFVEC2F &aCenter,
float aInnerRadius,
float aOuterRadius,
float aZtop,
float aZbot,
unsigned int aNr_sides_per_circle,
CLAYER_TRIANGLES *aDstLayer )
{
std::vector< SFVEC2F > innerContour;
std::vector< SFVEC2F > outerContour;
generate_ring_contour( aCenter,
aInnerRadius,
aOuterRadius,
aNr_sides_per_circle,
innerContour,
outerContour,
false );
for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
{
const SFVEC2F &vi0 = innerContour[i + 0];
const SFVEC2F &vi1 = innerContour[i + 1];
const SFVEC2F &vo0 = outerContour[i + 0];
const SFVEC2F &vo1 = outerContour[i + 1];
aDstLayer->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZtop ),
SFVEC3F( vi0.x, vi0.y, aZtop ),
SFVEC3F( vo0.x, vo0.y, aZtop ),
SFVEC3F( vo1.x, vo1.y, aZtop ) );
aDstLayer->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZbot ),
SFVEC3F( vo1.x, vo1.y, aZbot ),
SFVEC3F( vo0.x, vo0.y, aZbot ),
SFVEC3F( vi0.x, vi0.y, aZbot ) );
}
aDstLayer->AddToMiddleContourns( outerContour, aZbot, aZtop, true );
aDstLayer->AddToMiddleContourns( innerContour, aZbot, aZtop, false );
}
void C3D_RENDER_OGL_LEGACY::generate_3D_Vias_and_Pads()
{
if( m_settings.GetStats_Nr_Vias() )
{
const unsigned int reserve_nr_triangles_estimation =
m_settings.GetNrSegmentsCircle( m_settings.GetStats_Med_Via_Hole_Diameter3DU() ) *
8 *
m_settings.GetStats_Nr_Vias();
CLAYER_TRIANGLES *layerTriangleVIA = new CLAYER_TRIANGLES( reserve_nr_triangles_estimation );
// Insert plated vertical holes inside the board
// /////////////////////////////////////////////////////////////////////////
// Insert vias holes (vertical cylinders)
for( const TRACK* track = m_settings.GetBoard()->m_Track;
track;
track = track->Next() )
{
if( track->Type() == PCB_VIA_T )
{
const VIA *via = static_cast<const VIA*>(track);
const float holediameter = via->GetDrillValue() * m_settings.BiuTo3Dunits();
const float thickness = m_settings.GetCopperThickness3DU();
const int nrSegments = m_settings.GetNrSegmentsCircle( via->GetDrillValue() );
const double correctionFactor = m_settings.GetCircleCorrectionFactor( nrSegments );
const float hole_inner_radius = ( holediameter / 2.0f ) * correctionFactor;
const SFVEC2F via_center( via->GetStart().x * m_settings.BiuTo3Dunits(),
-via->GetStart().y * m_settings.BiuTo3Dunits() );
PCB_LAYER_ID top_layer, bottom_layer;
via->LayerPair( &top_layer, &bottom_layer );
float ztop, zbot, dummy;
get_layer_z_pos( top_layer, ztop, dummy );
get_layer_z_pos( bottom_layer, dummy, zbot );
wxASSERT( zbot < ztop );
generate_cylinder( via_center,
hole_inner_radius,
hole_inner_radius + thickness,
ztop,
zbot,
nrSegments,
layerTriangleVIA );
}
}
m_ogl_disp_list_via = new CLAYERS_OGL_DISP_LISTS( *layerTriangleVIA,
0,
0.0f,
0.0f );
delete layerTriangleVIA;
}
if( m_settings.GetStats_Nr_Holes() > 0 )
{
SHAPE_POLY_SET tht_outer_holes_poly; // Stores the outer poly of the copper holes (the pad)
SHAPE_POLY_SET tht_inner_holes_poly; // Stores the inner poly of the copper holes (the hole)
tht_outer_holes_poly.RemoveAllContours();
tht_inner_holes_poly.RemoveAllContours();
// Insert pads holes (vertical cylinders)
for( const MODULE* module = m_settings.GetBoard()->m_Modules;
module;
module = module->Next() )
{
for( const D_PAD* pad = module->PadsList(); pad; pad = pad->Next() )
{
if( pad->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED )
{
const wxSize drillsize = pad->GetDrillSize();
const bool hasHole = drillsize.x && drillsize.y;
if( !hasHole )
continue;
// we use the hole diameter to calculate the seg count.
// for round holes, drillsize.x == drillsize.y
// for slots, the diameter is the smaller of (drillsize.x, drillsize.y)
int copperThickness = m_settings.GetCopperThicknessBIU();
int radius = std::min( drillsize.x, drillsize.y ) / 2 + copperThickness;
int nrSegments = m_settings.GetNrSegmentsCircle( radius * 2 );
double correctionFactor = m_settings.GetCircleCorrectionFactor( nrSegments );
int correction = radius * ( correctionFactor - 1 );
pad->BuildPadDrillShapePolygon( tht_outer_holes_poly,
copperThickness + correction,
nrSegments );
pad->BuildPadDrillShapePolygon( tht_inner_holes_poly,
correction,
nrSegments );
}
}
}
// Subtract the holes
tht_outer_holes_poly.BooleanSubtract( tht_inner_holes_poly, SHAPE_POLY_SET::PM_FAST );
CCONTAINER2D holesContainer;
Convert_shape_line_polygon_to_triangles( tht_outer_holes_poly,
holesContainer,
m_settings.BiuTo3Dunits(),
(const BOARD_ITEM &)*m_settings.GetBoard() );
const LIST_OBJECT2D &listHolesObject2d = holesContainer.GetList();
if( listHolesObject2d.size() > 0 )
{
float layer_z_top, layer_z_bot, dummy;
get_layer_z_pos( F_Cu, layer_z_top, dummy );
get_layer_z_pos( B_Cu, dummy, layer_z_bot );
CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( listHolesObject2d.size() );
// Convert the list of objects(triangles) to triangle layer structure
for( LIST_OBJECT2D::const_iterator itemOnLayer = listHolesObject2d.begin();
itemOnLayer != listHolesObject2d.end();
++itemOnLayer )
{
const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);
wxASSERT( object2d_A->GetObjectType() == OBJ2D_TRIANGLE );
const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A;
const SFVEC2F &v1 = tri->GetP1();
const SFVEC2F &v2 = tri->GetP2();
const SFVEC2F &v3 = tri->GetP3();
add_triangle_top_bot( layerTriangles, v1, v2, v3,
layer_z_top, layer_z_bot );
}
wxASSERT( tht_outer_holes_poly.OutlineCount() > 0 );
if( tht_outer_holes_poly.OutlineCount() > 0 )
{
layerTriangles->AddToMiddleContourns( tht_outer_holes_poly,
layer_z_bot, layer_z_top,
m_settings.BiuTo3Dunits(),
false );
m_ogl_disp_list_pads_holes = new CLAYERS_OGL_DISP_LISTS(
*layerTriangles,
m_ogl_circle_texture, // not need
layer_z_top, layer_z_top );
}
delete layerTriangles;
}
}
}
/*
* This function will get models from the cache and load it to openGL lists
* in the form of C_OGL_3DMODEL. So this map of models will work as a local
* cache for this render. (cache based on C_OGL_3DMODEL with associated
* openGL lists in GPU memory)
*/
void C3D_RENDER_OGL_LEGACY::load_3D_models( REPORTER *aStatusTextReporter )
{
if( (!m_settings.GetFlag( FL_MODULE_ATTRIBUTES_NORMAL )) &&
(!m_settings.GetFlag( FL_MODULE_ATTRIBUTES_NORMAL_INSERT )) &&
(!m_settings.GetFlag( FL_MODULE_ATTRIBUTES_VIRTUAL )) )
return;
// Go for all modules
for( const MODULE* module = m_settings.GetBoard()->m_Modules;
module; module = module->Next() )
{
if( !module->Models().empty() )
{
// Get the list of model files for this model
auto sM = module->Models().begin();
auto eM = module->Models().end();
while( sM != eM )
{
if( !sM->m_Filename.empty() )
{
if( aStatusTextReporter )
{
// Display the short filename of the 3D model loaded:
// (the full name is usually too long to be displayed)
wxFileName fn( sM->m_Filename );
wxString msg;
msg.Printf( _( "Loading %s" ), fn.GetFullName() );
aStatusTextReporter->Report( msg );
}
// Check if the model is not present in our cache map
// (Not already loaded in memory)
if( m_3dmodel_map.find( sM->m_Filename ) == m_3dmodel_map.end() )
{
// It is not present, try get it from cache
const S3DMODEL *modelPtr =
m_settings.Get3DCacheManager()->GetModel( sM->m_Filename );
// only add it if the return is not NULL
if( modelPtr )
{
C_OGL_3DMODEL* ogl_model =
new C_OGL_3DMODEL( *modelPtr,
m_settings.MaterialModeGet() );
if( ogl_model )
m_3dmodel_map[ sM->m_Filename ] = ogl_model;
}
}
}
++sM;
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,221 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 c3d_render_ogl_legacy.h
* @brief
*/
#ifndef C3D_RENDER_OGL_LEGACY_H_
#define C3D_RENDER_OGL_LEGACY_H_
#include "../c3d_render_base.h"
#include "clayer_triangles.h"
#include "../3d_render_raytracing/shapes2D/cpolygon2d.h"
#include "../3d_render_raytracing/shapes2D/ctriangle2d.h"
#include "../3d_render_raytracing/shapes2D/cpolygon4pts2d.h"
#include "../3d_render_raytracing/shapes2D/cfilledcircle2d.h"
#include "../3d_render_raytracing/shapes2D/cring2d.h"
#include "../3d_render_raytracing/shapes2D/croundsegment2d.h"
#include "c_ogl_3dmodel.h"
#include "3d_cache/3d_info.h"
#include <map>
typedef std::map< PCB_LAYER_ID, CLAYERS_OGL_DISP_LISTS* > MAP_OGL_DISP_LISTS;
typedef std::map< PCB_LAYER_ID, CLAYER_TRIANGLES * > MAP_TRIANGLES;
typedef std::map< wxString, C_OGL_3DMODEL * > MAP_3DMODEL;
#define SIZE_OF_CIRCLE_TEXTURE 1024
/**
* @brief The C3D_RENDER_OGL_LEGACY class render the board using openGL legacy mode
*/
class C3D_RENDER_OGL_LEGACY : public C3D_RENDER_BASE
{
public:
explicit C3D_RENDER_OGL_LEGACY( CINFO3D_VISU &aSettings );
~C3D_RENDER_OGL_LEGACY();
// Imported from C3D_RENDER_BASE
void SetCurWindowSize( const wxSize &aSize ) override;
bool Redraw( bool aIsMoving, REPORTER *aStatusTextReporter ) override;
int GetWaitForEditingTimeOut() override;
private:
bool initializeOpenGL();
void reload( REPORTER *aStatusTextReporter );
void ogl_set_arrow_material();
void ogl_free_all_display_lists();
MAP_OGL_DISP_LISTS m_ogl_disp_lists_layers;
MAP_OGL_DISP_LISTS m_ogl_disp_lists_layers_holes_outer;
MAP_OGL_DISP_LISTS m_ogl_disp_lists_layers_holes_inner;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_board;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_through_holes_outer;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_through_holes_inner;
// User for body render
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_through_holes_outer_with_npth;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_through_holes_vias_outer;
//CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_through_holes_vias_inner; // Not in use
// This is for pads holes of the modules
//CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_vias_and_pad_holes_inner_contourn_and_caps;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_vias_and_pad_holes_outer_contourn_and_caps;
MAP_TRIANGLES m_triangles;
GLuint m_ogl_circle_texture;
GLuint m_ogl_disp_list_grid; ///< oGL list that stores current grid
GRID3D_TYPE m_last_grid_type; ///< Stores the last grid computed
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_via;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_pads_holes;
MAP_3DMODEL m_3dmodel_map;
private:
void generate_through_outer_holes();
void generate_through_inner_holes();
CLAYERS_OGL_DISP_LISTS *generate_holes_display_list( const LIST_OBJECT2D &aListHolesObject2d,
const SHAPE_POLY_SET &aPoly,
float aZtop,
float aZbot,
bool aInvertFaces );
void add_triangle_top_bot( CLAYER_TRIANGLES *aDst,
const SFVEC2F &v0,
const SFVEC2F &v1,
const SFVEC2F &v2,
float top,
float bot );
void add_object_to_triangle_layer( const CRING2D *aRing,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot );
void add_object_to_triangle_layer( const CPOLYGON4PTS2D *aPoly,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot );
void add_object_to_triangle_layer( const CFILLEDCIRCLE2D *aFilledCircle,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot );
void add_object_to_triangle_layer( const CTRIANGLE2D *aTri,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot );
void add_object_to_triangle_layer( const CROUNDSEGMENT2D *aSeg,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot );
void render_solder_mask_layer( PCB_LAYER_ID aLayerID,
float aZPosition,
bool aIsRenderingOnPreviewMode );
void get_layer_z_pos( PCB_LAYER_ID aLayerID,
float &aOutZtop,
float &aOutZbot ) const;
void generate_ring_contour( const SFVEC2F &aCenter,
float aInnerRadius,
float aOuterRadius,
unsigned int aNr_sides_per_circle,
std::vector< SFVEC2F > &aInnerContourResult,
std::vector< SFVEC2F > &aOuterContourResult,
bool aInvertOrder );
void generate_cylinder( const SFVEC2F &aCenter,
float aInnerRadius,
float aOuterRadius,
float aZtop,
float aZbot,
unsigned int aNr_sides_per_circle,
CLAYER_TRIANGLES *aDstLayer );
void generate_3D_Vias_and_Pads();
void load_3D_models( REPORTER *aStatusTextReporter );
/**
* @brief render_3D_models
* @param aRenderTopOrBot - true will render Top, false will render bottom
* @param aRenderTransparentOnly - true will render only the transparent
* objects, false will render opaque
*/
void render_3D_models( bool aRenderTopOrBot, bool aRenderTransparentOnly );
void render_3D_module( const MODULE* module, bool aRenderTransparentOnly );
void setLight_Front( bool enabled );
void setLight_Top( bool enabled );
void setLight_Bottom( bool enabled );
void render_3D_arrows();
void generate_new_3DGrid( GRID3D_TYPE aGridType );
// Materials
void setupMaterials();
struct
{
SMATERIAL m_Paste;
SMATERIAL m_SilkS;
SMATERIAL m_SolderMask;
SMATERIAL m_EpoxyBoard;
SMATERIAL m_Copper;
SMATERIAL m_Plastic;
SMATERIAL m_GrayMaterial;
}m_materials;
void set_layer_material( PCB_LAYER_ID aLayerID );
SFVEC3F get_layer_color( PCB_LAYER_ID aLayerID );
public:
const MAP_OGL_DISP_LISTS &GetLayerDispListMap() const { return m_ogl_disp_lists_layers; }
const CLAYERS_OGL_DISP_LISTS *GetLayerDispList( PCB_LAYER_ID aLayerId ) const { return m_ogl_disp_lists_layers.at( aLayerId ); }
const CLAYERS_OGL_DISP_LISTS *GetBoardDispList() const { return m_ogl_disp_list_board; }
};
#endif // C3D_RENDER_OGL_LEGACY_H_
@@ -0,0 +1,383 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 c_ogl_3dmodel.cpp
* @brief
*/
#include "c_ogl_3dmodel.h"
#include "ogl_legacy_utils.h"
#include "../common_ogl/ogl_utils.h"
#include "../3d_math.h"
#include <wx/debug.h>
C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel,
MATERIAL_MODE aMaterialMode )
{
m_ogl_idx_list_meshes = 0;
m_ogl_idx_list_opaque = 0;
m_ogl_idx_list_transparent = 0;
m_nr_meshes = 0;
m_meshs_bbox = NULL;
// Validate a3DModel pointers
wxASSERT( a3DModel.m_Materials != NULL );
wxASSERT( a3DModel.m_Meshes != NULL );
wxASSERT( a3DModel.m_MaterialsSize > 0 );
wxASSERT( a3DModel.m_MeshesSize > 0 );
if( (a3DModel.m_Materials != NULL) && (a3DModel.m_Meshes != NULL) &&
(a3DModel.m_MaterialsSize > 0) && (a3DModel.m_MeshesSize > 0) )
{
m_nr_meshes = a3DModel.m_MeshesSize;
m_meshs_bbox = new CBBOX[a3DModel.m_MeshesSize];
// Generate m_MeshesSize auxiliar lists to render the meshes
m_ogl_idx_list_meshes = glGenLists( a3DModel.m_MeshesSize );
// Render each mesh of the model
// /////////////////////////////////////////////////////////////////////
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
{
if( glIsList( m_ogl_idx_list_meshes + mesh_i ) )
{
const SMESH &mesh = a3DModel.m_Meshes[mesh_i];
// Validate the mesh pointers
wxASSERT( mesh.m_Positions != NULL );
wxASSERT( mesh.m_FaceIdx != NULL );
wxASSERT( mesh.m_Normals != NULL );
if( (mesh.m_Positions != NULL) &&
(mesh.m_Normals != NULL) &&
(mesh.m_FaceIdx != NULL) &&
(mesh.m_FaceIdxSize > 0) && (mesh.m_VertexSize > 0) )
{
SFVEC4F *pColorRGBA = NULL;
// Create the bbox for this mesh
// /////////////////////////////////////////////////////////
m_meshs_bbox[mesh_i].Reset();
for( unsigned int vertex_i = 0;
vertex_i < mesh.m_VertexSize;
++vertex_i )
{
m_meshs_bbox[mesh_i].Union( mesh.m_Positions[vertex_i] );
}
// Make sure we start with client state disabled
// /////////////////////////////////////////////////////////
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
// Enable arrays client states
// /////////////////////////////////////////////////////////
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_NORMAL_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, mesh.m_Positions );
glNormalPointer( GL_FLOAT, 0, mesh.m_Normals );
if( mesh.m_Color != NULL )
{
glEnableClientState( GL_COLOR_ARRAY );
float transparency = 0.0f;
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
transparency = a3DModel.m_Materials[mesh.m_MaterialIdx].m_Transparency;
if( (transparency > FLT_EPSILON) &&
(aMaterialMode == MATERIAL_MODE_NORMAL) )
{
// Create a new array of RGBA colors
pColorRGBA = new SFVEC4F[mesh.m_VertexSize];
// Copy RGB array and add the Alpha value
for( unsigned int i = 0; i < mesh.m_VertexSize; ++i )
pColorRGBA[i] = SFVEC4F( mesh.m_Color[i],
1.0f - transparency );
// Load an RGBA array
glColorPointer( 4, GL_FLOAT, 0, pColorRGBA );
}
else
{
switch( aMaterialMode )
{
case MATERIAL_MODE_NORMAL:
case MATERIAL_MODE_DIFFUSE_ONLY:
// load the original RGB color array
glColorPointer( 3, GL_FLOAT, 0, mesh.m_Color );
break;
case MATERIAL_MODE_CAD_MODE:
// Create a new array of RGBA colors
pColorRGBA = new SFVEC4F[mesh.m_VertexSize];
// Copy RGB array and add the Alpha value
for( unsigned int i = 0; i < mesh.m_VertexSize; ++i )
{
pColorRGBA[i] =
SFVEC4F( MaterialDiffuseToColorCAD( mesh.m_Color[i] ),
1.0f );
}
// Load an RGBA array
glColorPointer( 4, GL_FLOAT, 0, pColorRGBA );
break;
default:
break;
}
}
}
if( mesh.m_Texcoords != NULL )
{
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glTexCoordPointer( 2, GL_FLOAT, 0, mesh.m_Texcoords );
}
// Compile the display list to store triangles
// /////////////////////////////////////////////////////////
glNewList( m_ogl_idx_list_meshes + mesh_i, GL_COMPILE );
// Set material properties
// /////////////////////////////////////////////////////////
if( mesh.m_Color != NULL )
{
// This enables the use of the Color Pointer information
glEnable( GL_COLOR_MATERIAL );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
}
else
{
glDisable( GL_COLOR_MATERIAL );
}
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
{
switch( aMaterialMode )
{
case MATERIAL_MODE_NORMAL:
OGL_SetMaterial( a3DModel.m_Materials[mesh.m_MaterialIdx] );
break;
case MATERIAL_MODE_DIFFUSE_ONLY:
OGL_SetDiffuseOnlyMaterial(
a3DModel.m_Materials[mesh.m_MaterialIdx].m_Diffuse );
break;
case MATERIAL_MODE_CAD_MODE:
OGL_SetDiffuseOnlyMaterial(
MaterialDiffuseToColorCAD(
a3DModel.m_Materials[mesh.m_MaterialIdx].m_Diffuse ) );
break;
default:
break;
}
}
// Draw mesh
// /////////////////////////////////////////////////////////
glDrawElements( GL_TRIANGLES, mesh.m_FaceIdxSize,
GL_UNSIGNED_INT, mesh.m_FaceIdx );
glDisable( GL_COLOR_MATERIAL );
glEndList();
// Disable arrays client states
// /////////////////////////////////////////////////////////
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
glFlush();
delete [] pColorRGBA;
}
}
}// for each mesh
m_ogl_idx_list_opaque = glGenLists( 1 );
// Check if the generated list is valid
if( glIsList( m_ogl_idx_list_opaque ) )
{
bool have_opaque_meshes = false;
bool have_transparent_meshes = false;
// Compile the model display list
glNewList( m_ogl_idx_list_opaque, GL_COMPILE );
// Render each mesh display list (opaque first)
// /////////////////////////////////////////////////////////////////
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
{
const SMESH &mesh = a3DModel.m_Meshes[mesh_i];
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
{
const SMATERIAL &material = a3DModel.m_Materials[mesh.m_MaterialIdx];
if( material.m_Transparency == 0.0f )
{
have_opaque_meshes = true; // Flag that we have at least one opaque mesh
glCallList( m_ogl_idx_list_meshes + mesh_i );
}
else
{
have_transparent_meshes = true; // Flag that we found a transparent mesh
}
}
}
glEndList();
if( !have_opaque_meshes )
{
// If we dont have opaque meshes, we can free the list
glDeleteLists( m_ogl_idx_list_opaque, 1 );
m_ogl_idx_list_opaque = 0;
}
if( have_transparent_meshes )
{
m_ogl_idx_list_transparent = glGenLists( 1 );
// Check if the generated list is valid
if( glIsList( m_ogl_idx_list_transparent ) )
{
// Compile the model display list
glNewList( m_ogl_idx_list_transparent, GL_COMPILE );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// Render each mesh display list
// /////////////////////////////////////////////////////////
for( unsigned mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
{
const SMESH &mesh = a3DModel.m_Meshes[mesh_i];
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
{
const SMATERIAL &material = a3DModel.m_Materials[mesh.m_MaterialIdx];
// Render the transparent mesh if it have a transparency value
if( material.m_Transparency != 0.0f )
glCallList( m_ogl_idx_list_meshes + mesh_i );
}
}
glDisable( GL_BLEND );
glEndList();
}
else
{
m_ogl_idx_list_transparent = 0;
}
}
}
else
{
m_ogl_idx_list_opaque = 0;
}
// Create the main bbox
// /////////////////////////////////////////////////////////////////////
m_model_bbox.Reset();
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
m_model_bbox.Union( m_meshs_bbox[mesh_i] );
glFlush();
}
}
void C_OGL_3DMODEL::Draw_opaque() const
{
if( glIsList( m_ogl_idx_list_opaque ) )
glCallList( m_ogl_idx_list_opaque );
}
void C_OGL_3DMODEL::Draw_transparent() const
{
if( glIsList( m_ogl_idx_list_transparent ) )
glCallList( m_ogl_idx_list_transparent );
}
C_OGL_3DMODEL::~C_OGL_3DMODEL()
{
if( glIsList( m_ogl_idx_list_opaque ) )
glDeleteLists( m_ogl_idx_list_opaque, 1 );
if( glIsList( m_ogl_idx_list_transparent ) )
glDeleteLists( m_ogl_idx_list_transparent, 1 );
if( glIsList( m_ogl_idx_list_meshes ) )
glDeleteLists( m_ogl_idx_list_meshes, m_nr_meshes );
m_ogl_idx_list_meshes = 0;
m_ogl_idx_list_opaque = 0;
m_ogl_idx_list_transparent = 0;
delete[] m_meshs_bbox;
m_meshs_bbox = NULL;
}
void C_OGL_3DMODEL::Draw_bbox() const
{
OGL_draw_bbox( m_model_bbox );
}
void C_OGL_3DMODEL::Draw_bboxes() const
{
for( unsigned int mesh_i = 0; mesh_i < m_nr_meshes; ++mesh_i )
OGL_draw_bbox( m_meshs_bbox[mesh_i] );
}
bool C_OGL_3DMODEL::Have_opaque() const
{
return glIsList( m_ogl_idx_list_opaque );
}
bool C_OGL_3DMODEL::Have_transparent() const
{
return glIsList( m_ogl_idx_list_transparent );
}
@@ -0,0 +1,97 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 c_ogl_3dmodel.h
* @brief implement a legacy 3dmodel render
*/
#ifndef _C_OGL_3DMODEL_H_
#define _C_OGL_3DMODEL_H_
#include <plugins/3dapi/c3dmodel.h>
#include "../../common_ogl/openGL_includes.h"
#include "../3d_render_raytracing/shapes3D/cbbox.h"
#include "../../3d_enums.h"
///
class C_OGL_3DMODEL
{
public:
/**
* @brief C_OGL_3DMODEL - Load a 3d model. This must be called inside a gl context
* @param a3DModel: a 3d model data to load.
* @param aMaterialMode: a mode to render the materials of the model
*/
C_OGL_3DMODEL( const S3DMODEL &a3DModel, MATERIAL_MODE aMaterialMode );
~C_OGL_3DMODEL();
/**
* @brief Draw_opaque - render the model into the current context
*/
void Draw_opaque() const;
/**
* @brief Draw_transparent - render the model into the current context
*/
void Draw_transparent() const;
/**
* @brief Have_opaque - return true if have opaque meshs to render
*/
bool Have_opaque() const;
/**
* @brief Have_transparent - return true if have transparent meshs to render
*/
bool Have_transparent() const;
/**
* @brief Draw_bbox - draw main bounding box of the model
*/
void Draw_bbox() const;
/**
* @brief Draw_bboxes - draw individual bounding boxes of each mesh
*/
void Draw_bboxes() const;
/**
* @brief GetBBox - Get main bbox
* @return the main model bbox
*/
const CBBOX &GetBBox() const { return m_model_bbox; }
private:
GLuint m_ogl_idx_list_opaque; ///< display list for rendering opaque meshes
GLuint m_ogl_idx_list_transparent; ///< display list for rendering transparent meshes
GLuint m_ogl_idx_list_meshes; ///< display lists for all meshes.
unsigned int m_nr_meshes; ///< number of meshes of this model
CBBOX m_model_bbox; ///< global bounding box for this model
CBBOX *m_meshs_bbox; ///< individual bbox for each mesh
};
#endif // _C_OGL_3DMODEL_H_
@@ -0,0 +1,832 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 clayer_triangles.cpp
* @brief
*/
#include "clayer_triangles.h"
#include <wx/debug.h> // For the wxASSERT
#include <mutex>
#include <thread>
#include <atomic>
CLAYER_TRIANGLE_CONTAINER::CLAYER_TRIANGLE_CONTAINER( unsigned int aNrReservedTriangles,
bool aReserveNormals )
{
wxASSERT( aNrReservedTriangles > 0 );
m_vertexs.clear();
m_normals.clear();
m_vertexs.reserve( aNrReservedTriangles * 3 );
if( aReserveNormals )
m_normals.reserve( aNrReservedTriangles * 3 );
}
void CLAYER_TRIANGLE_CONTAINER::Reserve_More( unsigned int aNrReservedTriangles,
bool aReserveNormals )
{
m_vertexs.reserve( m_vertexs.size() + aNrReservedTriangles * 3 );
if( aReserveNormals )
m_normals.reserve( m_normals.size() + aNrReservedTriangles * 3 );
}
void CLAYER_TRIANGLE_CONTAINER::AddQuad( const SFVEC3F &aV1,
const SFVEC3F &aV2,
const SFVEC3F &aV3,
const SFVEC3F &aV4 )
{
m_vertexs.push_back( aV1 );
m_vertexs.push_back( aV2 );
m_vertexs.push_back( aV3 );
m_vertexs.push_back( aV3 );
m_vertexs.push_back( aV4 );
m_vertexs.push_back( aV1 );
}
void CLAYER_TRIANGLE_CONTAINER::AddTriangle( const SFVEC3F &aV1,
const SFVEC3F &aV2,
const SFVEC3F &aV3 )
{
m_vertexs.push_back( aV1 );
m_vertexs.push_back( aV2 );
m_vertexs.push_back( aV3 );
}
void CLAYER_TRIANGLE_CONTAINER::AddNormal( const SFVEC3F &aN1,
const SFVEC3F &aN2,
const SFVEC3F &aN3 )
{
m_normals.push_back( aN1 );
m_normals.push_back( aN2 );
m_normals.push_back( aN3 );
}
void CLAYER_TRIANGLE_CONTAINER::AddNormal( const SFVEC3F &aN1,
const SFVEC3F &aN2,
const SFVEC3F &aN3,
const SFVEC3F &aN4 )
{
m_normals.push_back( aN1 );
m_normals.push_back( aN2 );
m_normals.push_back( aN3 );
m_normals.push_back( aN3 );
m_normals.push_back( aN4 );
m_normals.push_back( aN1 );
}
CLAYER_TRIANGLES::CLAYER_TRIANGLES( unsigned int aNrReservedTriangles )
{
wxASSERT( aNrReservedTriangles > 0 );
m_layer_top_segment_ends = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles,
false );
m_layer_top_triangles = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles,
false );
m_layer_middle_contourns_quads = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles,
true );
m_layer_bot_triangles = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles,
false );
m_layer_bot_segment_ends = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles,
false );
}
CLAYER_TRIANGLES::~CLAYER_TRIANGLES()
{
delete m_layer_top_segment_ends;
m_layer_top_segment_ends = 0;
delete m_layer_top_triangles;
m_layer_top_triangles = 0;
delete m_layer_middle_contourns_quads;
m_layer_middle_contourns_quads = 0;
delete m_layer_bot_triangles;
m_layer_bot_triangles = 0;
delete m_layer_bot_segment_ends;
m_layer_bot_segment_ends = 0;
}
void CLAYER_TRIANGLES::AddToMiddleContourns( const std::vector< SFVEC2F > &aContournPoints,
float zBot,
float zTop,
bool aInvertFaceDirection )
{
if( aContournPoints.size() >= 4 )
{
// Calculate normals of each segment of the contourn
std::vector< SFVEC2F > contournNormals;
contournNormals.clear();
contournNormals.resize( aContournPoints.size() - 1 );
if( aInvertFaceDirection )
{
for( unsigned int i = 0; i < ( aContournPoints.size() - 1 ); ++i )
{
const SFVEC2F &v0 = aContournPoints[i + 0];
const SFVEC2F &v1 = aContournPoints[i + 1];
const SFVEC2F n = glm::normalize( v1 - v0 );
contournNormals[i] = SFVEC2F( n.y,-n.x );
}
}
else
{
for( unsigned int i = 0; i < ( aContournPoints.size() - 1 ); ++i )
{
const SFVEC2F &v0 = aContournPoints[i + 0];
const SFVEC2F &v1 = aContournPoints[i + 1];
const SFVEC2F n = glm::normalize( v1 - v0 );
contournNormals[i] = SFVEC2F( -n.y, n.x );
}
}
if( aInvertFaceDirection )
std::swap( zBot, zTop );
const unsigned int nContournsToProcess = ( aContournPoints.size() - 1 );
for( unsigned int i = 0; i < nContournsToProcess; ++i )
{
SFVEC2F lastNormal;
if( i > 0 )
lastNormal = contournNormals[i - 1];
else
lastNormal = contournNormals[nContournsToProcess - 1];
SFVEC2F n0 = contournNormals[i];
// Only interpolate the normal if the angle is closer
if( glm::dot( n0, lastNormal ) > 0.5f )
n0 = glm::normalize( n0 + lastNormal );
SFVEC2F nextNormal;
if( i < (nContournsToProcess - 1) )
nextNormal = contournNormals[i + 1];
else
nextNormal = contournNormals[0];
SFVEC2F n1 = contournNormals[i];
if( glm::dot( n1, nextNormal ) > 0.5f )
n1 = glm::normalize( n1 + nextNormal );
const SFVEC3F n3d0 = SFVEC3F( n0.x, n0.y, 0.0f );
const SFVEC3F n3d1 = SFVEC3F( n1.x, n1.y, 0.0f );
const SFVEC2F &v0 = aContournPoints[i + 0];
const SFVEC2F &v1 = aContournPoints[i + 1];
{
std::lock_guard<std::mutex> lock( m_middle_layer_lock );
m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, zTop ),
SFVEC3F( v1.x, v1.y, zTop ),
SFVEC3F( v1.x, v1.y, zBot ),
SFVEC3F( v0.x, v0.y, zBot ) );
m_layer_middle_contourns_quads->AddNormal( n3d0, n3d1, n3d1, n3d0 );
}
}
}
}
void CLAYER_TRIANGLES::AddToMiddleContourns( const SHAPE_LINE_CHAIN &outlinePath,
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection )
{
std::vector< SFVEC2F >contournPoints;
contournPoints.clear();
contournPoints.reserve( outlinePath.PointCount() + 2 );
const VECTOR2I &firstV = outlinePath.CPoint( 0 );
SFVEC2F lastV = SFVEC2F( firstV.x * aBiuTo3Du,
-firstV.y * aBiuTo3Du );
contournPoints.push_back( lastV );
for( unsigned int i = 1; i < (unsigned int)outlinePath.PointCount(); ++i )
{
const VECTOR2I & v = outlinePath.CPoint( i );
const SFVEC2F vf = SFVEC2F( v.x * aBiuTo3Du,
-v.y * aBiuTo3Du );
if( vf != lastV ) // Do not add repeated points
{
lastV = vf;
contournPoints.push_back( vf );
}
}
// Add first position fo the list to close the path
if( lastV != contournPoints[0] )
contournPoints.push_back( contournPoints[0] );
AddToMiddleContourns( contournPoints, zBot, zTop, aInvertFaceDirection );
}
void CLAYER_TRIANGLES::AddToMiddleContourns( const SHAPE_POLY_SET &aPolySet,
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection )
{
if( aPolySet.OutlineCount() == 0 )
return;
// Calculate an estimation of points to reserve
unsigned int nrContournPointsToReserve = 0;
for( int i = 0; i < aPolySet.OutlineCount(); ++i )
{
const SHAPE_LINE_CHAIN& pathOutline = aPolySet.COutline( i );
nrContournPointsToReserve += pathOutline.PointCount();
for( int h = 0; h < aPolySet.HoleCount( i ); ++h )
{
const SHAPE_LINE_CHAIN &hole = aPolySet.CHole( i, h );
nrContournPointsToReserve += hole.PointCount();
}
}
// Request to reserve more space
m_layer_middle_contourns_quads->Reserve_More( nrContournPointsToReserve * 2,
true );
for( int i = 0; i < aPolySet.OutlineCount(); i++ )
{
// Add outline
const SHAPE_LINE_CHAIN& pathOutline = aPolySet.COutline( i );
AddToMiddleContourns( pathOutline, zBot, zTop, aBiuTo3Du, aInvertFaceDirection );
// Add holes for this outline
for( int h = 0; h < aPolySet.HoleCount( i ); ++h )
{
const SHAPE_LINE_CHAIN &hole = aPolySet.CHole( i, h );
AddToMiddleContourns( hole, zBot, zTop, aBiuTo3Du, aInvertFaceDirection );
}
}
}
CLAYERS_OGL_DISP_LISTS::CLAYERS_OGL_DISP_LISTS( const CLAYER_TRIANGLES &aLayerTriangles,
GLuint aTextureIndexForSegEnds,
float aZBot,
float aZTop )
{
m_zBot = aZBot;
m_zTop = aZTop;
m_layer_top_segment_ends = 0;
m_layer_top_triangles = 0;
m_layer_middle_contourns_quads = 0;
m_layer_bot_triangles = 0;
m_layer_bot_segment_ends = 0;
if( aTextureIndexForSegEnds )
{
wxASSERT( glIsTexture( aTextureIndexForSegEnds ) );
if( glIsTexture( aTextureIndexForSegEnds ) )
{
m_layer_top_segment_ends =
generate_top_or_bot_seg_ends( aLayerTriangles.m_layer_top_segment_ends,
true,
aTextureIndexForSegEnds );
m_layer_bot_segment_ends =
generate_top_or_bot_seg_ends( aLayerTriangles.m_layer_bot_segment_ends,
false,
aTextureIndexForSegEnds );
}
}
m_layer_top_triangles = generate_top_or_bot_triangles( aLayerTriangles.m_layer_top_triangles,
true );
m_layer_bot_triangles = generate_top_or_bot_triangles( aLayerTriangles.m_layer_bot_triangles,
false );
if( aLayerTriangles.m_layer_middle_contourns_quads->GetVertexSize() > 0 )
{
m_layer_middle_contourns_quads =
generate_middle_triangles( aLayerTriangles.m_layer_middle_contourns_quads );
}
m_draw_it_transparent = false;
m_haveTransformation = false;
m_zPositionTransformation = 0.0f;
m_zScaleTransformation = 0.0f;
}
CLAYERS_OGL_DISP_LISTS::~CLAYERS_OGL_DISP_LISTS()
{
if( glIsList( m_layer_top_segment_ends ) )
glDeleteLists( m_layer_top_segment_ends, 1 );
if( glIsList( m_layer_top_triangles ) )
glDeleteLists( m_layer_top_triangles, 1 );
if( glIsList( m_layer_middle_contourns_quads ) )
glDeleteLists( m_layer_middle_contourns_quads, 1 );
if( glIsList( m_layer_bot_triangles ) )
glDeleteLists( m_layer_bot_triangles, 1 );
if( glIsList( m_layer_bot_segment_ends ) )
glDeleteLists( m_layer_bot_segment_ends, 1 );
m_layer_top_segment_ends = 0;
m_layer_top_triangles = 0;
m_layer_middle_contourns_quads = 0;
m_layer_bot_triangles = 0;
m_layer_bot_segment_ends = 0;
}
void CLAYERS_OGL_DISP_LISTS::DrawTopAndMiddle() const
{
beginTransformation();
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
if( glIsList( m_layer_top_triangles ) )
glCallList( m_layer_top_triangles );
if( glIsList( m_layer_top_segment_ends ) )
glCallList( m_layer_top_segment_ends );
endTransformation();
}
void CLAYERS_OGL_DISP_LISTS::DrawBotAndMiddle() const
{
beginTransformation();
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
if( glIsList( m_layer_bot_triangles ) )
glCallList( m_layer_bot_triangles );
if( glIsList( m_layer_bot_segment_ends ) )
glCallList( m_layer_bot_segment_ends );
endTransformation();
}
void CLAYERS_OGL_DISP_LISTS::DrawTop() const
{
beginTransformation();
if( glIsList( m_layer_top_triangles ) )
glCallList( m_layer_top_triangles );
if( glIsList( m_layer_top_segment_ends ) )
glCallList( m_layer_top_segment_ends );
endTransformation();
}
void CLAYERS_OGL_DISP_LISTS::DrawBot() const
{
beginTransformation();
if( glIsList( m_layer_bot_triangles ) )
glCallList( m_layer_bot_triangles );
if( glIsList( m_layer_bot_segment_ends ) )
glCallList( m_layer_bot_segment_ends );
endTransformation();
}
void CLAYERS_OGL_DISP_LISTS::DrawMiddle() const
{
beginTransformation();
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
endTransformation();
}
void CLAYERS_OGL_DISP_LISTS::DrawAll( bool aDrawMiddle ) const
{
beginTransformation();
if( aDrawMiddle )
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
if( glIsList( m_layer_top_triangles ) )
glCallList( m_layer_top_triangles );
if( glIsList( m_layer_bot_triangles ) )
glCallList( m_layer_bot_triangles );
if( glIsList( m_layer_top_segment_ends ) )
glCallList( m_layer_top_segment_ends );
if( glIsList( m_layer_bot_segment_ends ) )
glCallList( m_layer_bot_segment_ends );
endTransformation();
}
void CLAYERS_OGL_DISP_LISTS::DrawAllCameraCulled(float zCameraPos, bool aDrawMiddle ) const
{
zCameraPos = m_haveTransformation?( (zCameraPos - m_zPositionTransformation ) /
m_zScaleTransformation ):zCameraPos;
if( aDrawMiddle )
DrawMiddle();
if( zCameraPos > m_zTop )
{
DrawTop();
}
else
{
if( zCameraPos < m_zBot )
{
DrawBot();
}
else
{
// If camera is in the middle dont draw it
}
}
}
void CLAYERS_OGL_DISP_LISTS::DrawAllCameraCulledSubtractLayer(
const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractA,
const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractB,
bool aDrawMiddle ) const
{
if( aDrawMiddle )
DrawMiddle();
glClearStencil( 0x00 );
glClear( GL_STENCIL_BUFFER_BIT );
glEnable( GL_CULL_FACE );
glCullFace( GL_BACK );
glDisable( GL_DEPTH_TEST );
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
glDepthMask( GL_FALSE );
glEnable( GL_STENCIL_TEST );
glStencilFunc( GL_ALWAYS, 1, 0 );
glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
if( aLayerToSubtractA )
aLayerToSubtractA->DrawBot();
if( aLayerToSubtractB )
aLayerToSubtractB->DrawBot();
//if( !m_draw_it_transparent )
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
}
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
glStencilFunc( GL_EQUAL, 0, 1 );
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
DrawBot();
glDisable( GL_DEPTH_TEST );
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
glDepthMask( GL_FALSE );
glEnable( GL_STENCIL_TEST );
glStencilFunc( GL_ALWAYS, 2, 0 );
glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
if( aLayerToSubtractA )
aLayerToSubtractA->DrawTop();
if( aLayerToSubtractB )
aLayerToSubtractB->DrawTop();
//if( !m_draw_it_transparent )
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
}
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
glStencilFunc( GL_NOTEQUAL, 2, 0x03 );
glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
DrawTop();
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );
glCullFace( GL_FRONT );
glStencilFunc( GL_GEQUAL, 3, 0x03 );
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
if( aDrawMiddle )
{
if( aLayerToSubtractA )
aLayerToSubtractA->DrawMiddle();
// It will not render the middle contours of the layer.
// It is used with vias and holes (copper vias and to subtract solder
// mask holes). But since in the vias, it will draw a cylinder
// and in soldermask it doesn't need to draw the contour.
// so it is not used the middle part of B
// if( aLayerToSubtractB )
// aLayerToSubtractB->DrawMiddle();
}
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
glCullFace( GL_BACK );
glDisable( GL_STENCIL_TEST );
/*
if( m_draw_it_transparent )
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
}*/
}
void CLAYERS_OGL_DISP_LISTS::ApplyScalePosition( float aZposition,
float aZscale )
{
wxASSERT( aZscale > FLT_EPSILON );
m_zPositionTransformation = aZposition;
m_zScaleTransformation = aZscale;
m_haveTransformation = true;
}
void CLAYERS_OGL_DISP_LISTS::SetItIsTransparent( bool aSetTransparent )
{
m_draw_it_transparent = aSetTransparent;
}
GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_seg_ends(
const CLAYER_TRIANGLE_CONTAINER *aTriangleContainer,
bool aIsNormalUp,
GLuint aTextureId ) const
{
wxASSERT( aTriangleContainer != NULL );
wxASSERT( (aTriangleContainer->GetVertexSize() % 3) == 0 );
// Top and Bot dont have normals array stored in container
wxASSERT( aTriangleContainer->GetNormalsSize() == 0 );
if( (aTriangleContainer->GetVertexSize() > 0) &&
((aTriangleContainer->GetVertexSize() % 3) == 0) )
{
GLuint listIdx = glGenLists( 1 );
if( glIsList( listIdx ) )
{
// Prepare an array of UV text coordinates
SFVEC2F *uvArray = new SFVEC2F[aTriangleContainer->GetVertexSize()];
for( unsigned int i = 0;
i < aTriangleContainer->GetVertexSize();
i += 3 )
{
uvArray[i + 0] = SFVEC2F( 1.0f, 0.0f );
uvArray[i + 1] = SFVEC2F( 0.0f, 1.0f );
uvArray[i + 2] = SFVEC2F( 0.0f, 0.0f );
}
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, aTriangleContainer->GetVertexPointer() );
glTexCoordPointer( 2, GL_FLOAT, 0, uvArray );
glNewList( listIdx, GL_COMPILE );
glDisable( GL_COLOR_MATERIAL );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, aTextureId );
setBlendfunction();
glAlphaFunc( GL_GREATER, 0.2f );
glEnable( GL_ALPHA_TEST );
glNormal3f( 0.0f, 0.0f, aIsNormalUp?1.0f:-1.0f );
glDrawArrays( GL_TRIANGLES, 0, aTriangleContainer->GetVertexSize() );
glDisable( GL_TEXTURE_2D );
glDisable( GL_ALPHA_TEST );
glDisable( GL_BLEND );
glEndList();
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
delete [] uvArray;
return listIdx;
}
}
return 0;
}
GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_triangles(
const CLAYER_TRIANGLE_CONTAINER *aTriangleContainer,
bool aIsNormalUp ) const
{
wxASSERT( aTriangleContainer != NULL );
wxASSERT( (aTriangleContainer->GetVertexSize() % 3) == 0 );
// Top and Bot dont have normals array stored in container
wxASSERT( aTriangleContainer->GetNormalsSize() == 0 );
if( (aTriangleContainer->GetVertexSize() > 0) &&
( (aTriangleContainer->GetVertexSize() % 3) == 0) )
{
const GLuint listIdx = glGenLists( 1 );
if( glIsList( listIdx ) )
{
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, aTriangleContainer->GetVertexPointer() );
glNewList( listIdx, GL_COMPILE );
setBlendfunction();
glNormal3f( 0.0f, 0.0f, aIsNormalUp?1.0f:-1.0f );
glDrawArrays( GL_TRIANGLES, 0, aTriangleContainer->GetVertexSize() );
glDisable( GL_BLEND );
glEndList();
glDisableClientState( GL_VERTEX_ARRAY );
return listIdx;
}
}
return 0;
}
GLuint CLAYERS_OGL_DISP_LISTS::generate_middle_triangles(
const CLAYER_TRIANGLE_CONTAINER *aTriangleContainer ) const
{
wxASSERT( aTriangleContainer != NULL );
// We expect that it is a multiple of 3 vertex
wxASSERT( (aTriangleContainer->GetVertexSize() % 3) == 0 );
// We expect that it is a multiple of 6 vertex (because we expect to add quads)
wxASSERT( (aTriangleContainer->GetVertexSize() % 6) == 0 );
// We expect that there are normals with same size as vertex
wxASSERT( aTriangleContainer->GetNormalsSize() == aTriangleContainer->GetVertexSize() );
if( ( aTriangleContainer->GetVertexSize() > 0 ) &&
( (aTriangleContainer->GetVertexSize() % 3) == 0 ) &&
( (aTriangleContainer->GetVertexSize() % 6) == 0 ) &&
( aTriangleContainer->GetNormalsSize() == aTriangleContainer->GetVertexSize() ) )
{
const GLuint listIdx = glGenLists( 1 );
if( glIsList( listIdx ) )
{
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glEnableClientState( GL_NORMAL_ARRAY );
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, aTriangleContainer->GetVertexPointer() );
glNormalPointer( GL_FLOAT, 0, aTriangleContainer->GetNormalsPointer() );
glNewList( listIdx, GL_COMPILE );
setBlendfunction();
glDrawArrays( GL_TRIANGLES, 0, aTriangleContainer->GetVertexSize() );
glDisable( GL_BLEND );
glEndList();
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
return listIdx;
}
}
return 0;
}
void CLAYERS_OGL_DISP_LISTS::endTransformation() const
{
if( m_haveTransformation )
{
glPopMatrix();
}
}
void CLAYERS_OGL_DISP_LISTS::setBlendfunction() const
{
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
void CLAYERS_OGL_DISP_LISTS::beginTransformation() const
{
if( m_haveTransformation )
{
glPushMatrix();
glTranslatef( 0.0f, 0.0f, m_zPositionTransformation );
glScalef( 1.0f, 1.0f, m_zScaleTransformation );
}
}
@@ -0,0 +1,300 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 clayer_triangles.h
* @brief
*/
#ifndef CLAYER_TRIANGLES_H_
#define CLAYER_TRIANGLES_H_
#include "../../common_ogl/openGL_includes.h"
#include <plugins/3dapi/xv3d_types.h>
#include <geometry/shape_line_chain.h>
#include <geometry/shape_poly_set.h>
#include <vector>
#include <mutex>
typedef std::vector< SFVEC3F > SFVEC3F_VECTOR;
/**
* @brief The CLAYER_TRIANGLE_CONTAINER class stores an manage vector of triangles
*/
class CLAYER_TRIANGLE_CONTAINER
{
public:
/**
* @brief CLAYER_TRIANGLE_CONTAINER
* @param aNrReservedTriangles: number of triangles expected to be used
* @param aReserveNormals: if you will use normals, set it to bool to pre
* reserve space
*/
CLAYER_TRIANGLE_CONTAINER( unsigned int aNrReservedTriangles, bool aReserveNormals );
/**
* @brief Reserve_More - reserve more triangles
*
*/
void Reserve_More( unsigned int aNrReservedTriangles, bool aReserveNormals );
/**
* @brief AddTriangle
* @param aV1
* @param aV2
* @param aV3
*/
void AddTriangle( const SFVEC3F &aV1, const SFVEC3F &aV2, const SFVEC3F &aV3 );
/**
* @brief AddQuad
* @param aV1
* @param aV2
* @param aV3
* @param aV4
*/
void AddQuad( const SFVEC3F &aV1,
const SFVEC3F &aV2,
const SFVEC3F &aV3,
const SFVEC3F &aV4 );
/**
* @brief AddNormal
* @param aN1
* @param aN2
* @param aN3
*/
void AddNormal( const SFVEC3F &aN1, const SFVEC3F &aN2, const SFVEC3F &aN3 );
/**
* @brief AddNormal
* @param aN1
* @param aN2
* @param aN3
*/
void AddNormal( const SFVEC3F &aN1,
const SFVEC3F &aN2,
const SFVEC3F &aN3,
const SFVEC3F &aN4 );
/**
* @brief GetVertexPointer - Get the array of vertexes
* @return The pointer to the start of array vertex
*/
const float *GetVertexPointer() const { return (const float *)&m_vertexs[0].x; }
/**
* @brief GetNormalsPointer - Get the array of normals
* @return The pointer to start of array of normals
*/
const float *GetNormalsPointer() const { return (const float *)&m_normals[0].x; }
/**
* @brief GetVertexSize
* @return
*/
unsigned int GetVertexSize() const { return (unsigned int)m_vertexs.size(); }
/**
* @brief GetNormalsSize
* @return
*/
unsigned int GetNormalsSize() const { return (unsigned int)m_normals.size(); }
private:
SFVEC3F_VECTOR m_vertexs; ///< vertex array
SFVEC3F_VECTOR m_normals; ///< normals array
};
/**
* @brief The CLAYER_TRIANGLES class stores arrays of triangles to be used to
* create display lists
*/
class CLAYER_TRIANGLES
{
public:
/**
* @brief CLAYER_TRIANGLES - initialize arrays with reserved triangles
* @param aNrReservedTriangles: number of pre alloc triangles to reserve
*/
explicit CLAYER_TRIANGLES( unsigned int aNrReservedTriangles );
/**
* @brief ~CLAYER_TRIANGLES - Free containers
*/
~CLAYER_TRIANGLES();
/**
* @brief IsLayersSizeValid - check if the vertex arrays of the layers are
* as expected
* @return TRUE if layers are correctly setup
*/
bool IsLayersSizeValid();
void AddToMiddleContourns( const SHAPE_LINE_CHAIN &outlinePath,
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection );
void AddToMiddleContourns( const SHAPE_POLY_SET &aPolySet,
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection );
void AddToMiddleContourns( const std::vector< SFVEC2F > &aContournPoints,
float zBot,
float zTop,
bool aInvertFaceDirection );
std::mutex m_middle_layer_lock;
CLAYER_TRIANGLE_CONTAINER *m_layer_top_segment_ends;
CLAYER_TRIANGLE_CONTAINER *m_layer_top_triangles;
CLAYER_TRIANGLE_CONTAINER *m_layer_middle_contourns_quads;
CLAYER_TRIANGLE_CONTAINER *m_layer_bot_triangles;
CLAYER_TRIANGLE_CONTAINER *m_layer_bot_segment_ends;
};
/**
* @brief The CLAYERS_OGL_DISP_LISTS class stores the openGL display lists to
* related with a layer
*/
class CLAYERS_OGL_DISP_LISTS
{
public:
/**
* @brief CLAYERS_OGL_DISP_LISTS - Creates the display lists for a layer
* @param aLayerTriangles: contains the layers array of vertex to render to
* display lists
* @param aTextureIndexForSegEnds: texture index to be used by segment ends.
* It is a black and white squared texture
* with a center circle diameter of the size
* of the texture.
*/
CLAYERS_OGL_DISP_LISTS( const CLAYER_TRIANGLES &aLayerTriangles,
GLuint aTextureIndexForSegEnds,
float aZBot,
float aZTop );
/**
* @brief ~CLAYERS_OGL_DISP_LISTS - Destroy this class while free the display
* lists from GPU mem
*/
~CLAYERS_OGL_DISP_LISTS();
/**
* @brief DrawTopAndMiddle - This function calls the display lists for the
* top elements and middle contourns
*/
void DrawTopAndMiddle() const;
/**
* @brief DrawBotAndMiddle - This function calls the display lists for the
* botton elements and middle contourns
*/
void DrawBotAndMiddle() const;
/**
* @brief DrawTop - This function calls the display lists for the top elements
*/
void DrawTop() const;
/**
* @brief DrawBot - This function calls the display lists for the botton elements
*/
void DrawBot() const;
/**
* @brief DrawMiddle - This function calls the display lists for the middle
* elements
*/
void DrawMiddle() const;
/**
* @brief DrawAll - This function calls all the display lists
*/
void DrawAll( bool aDrawMiddle = true ) const;
/**
* @brief DrawAllCameraCulled - Draw all layers if they are visible by the camera.
* i.e.: if camera position is above the layer. This only works because the
* board is centered and the planes are always perpendicular to the Z axis.
* @param zCameraPos: camera z position
*/
void DrawAllCameraCulled( float zCameraPos, bool aDrawMiddle = true ) const;
void DrawAllCameraCulledSubtractLayer( const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractA,
const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractB,
bool aDrawMiddle = true ) const;
void ApplyScalePosition( float aZposition, float aZscale );
void ClearScalePosition() { m_haveTransformation = false; }
void SetItIsTransparent( bool aSetTransparent );
float GetZBot() const { return m_zBot; }
float GetZTop() const { return m_zTop; }
private:
GLuint generate_top_or_bot_seg_ends( const CLAYER_TRIANGLE_CONTAINER * aTriangleContainer,
bool aIsNormalUp,
GLuint aTextureId ) const;
GLuint generate_top_or_bot_triangles( const CLAYER_TRIANGLE_CONTAINER * aTriangleContainer,
bool aIsNormalUp ) const;
GLuint generate_middle_triangles( const CLAYER_TRIANGLE_CONTAINER * aTriangleContainer ) const;
void beginTransformation() const;
void endTransformation() const;
void setBlendfunction() const;
private:
float m_zBot;
float m_zTop;
GLuint m_layer_top_segment_ends;
GLuint m_layer_top_triangles;
GLuint m_layer_middle_contourns_quads;
GLuint m_layer_bot_triangles;
GLuint m_layer_bot_segment_ends;
bool m_haveTransformation;
float m_zPositionTransformation;
float m_zScaleTransformation;
bool m_draw_it_transparent;
};
#endif // CLAYER_TRIANGLES_H_
@@ -0,0 +1,280 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 ogl_legacy_utils.cpp
* @brief
*/
#include "../../common_ogl/openGL_includes.h"
#include "ogl_legacy_utils.h"
#include <trigo.h>
#include <wx/debug.h> // For the wxASSERT
#define RADPERDEG 0.0174533
void OGL_draw_arrow( SFVEC3F aPosition, SFVEC3F aTargetPos, float aSize )
{
wxASSERT( aSize > 0.0f );
SFVEC3F vec = (aTargetPos - aPosition);
float length = glm::length( vec );
GLUquadricObj *quadObj;
glPushMatrix ();
glTranslatef( aPosition.x, aPosition.y, aPosition.z );
if( ( vec.x != 0.0f ) || ( vec.y != 0.0f ) )
{
glRotatef( atan2( vec.y, vec.x ) / RADPERDEG, 0.0f, 0.0f, 1.0f );
glRotatef( atan2( sqrt( vec.x * vec.x + vec.y * vec.y ), vec.z ) / RADPERDEG,
0.0f,
1.0f,
0.0f );
} else if( vec.z < 0.0f )
{
glRotatef( 180.0f, 1.0f, 0.0f, 0.0f );
}
glTranslatef( 0.0f, 0.0f, length - 4.0f * aSize );
quadObj = gluNewQuadric();
gluQuadricDrawStyle( quadObj, GLU_FILL );
gluQuadricNormals( quadObj, GLU_SMOOTH );
gluCylinder( quadObj, 2.0 * aSize, 0.0, 4.0 * aSize, 12, 1 );
gluDeleteQuadric( quadObj );
quadObj = gluNewQuadric();
gluQuadricDrawStyle( quadObj, GLU_FILL );
gluQuadricNormals( quadObj, GLU_SMOOTH );
gluDisk( quadObj, 0.0, 2.0 * aSize, 12, 1 );
gluDeleteQuadric( quadObj );
quadObj = gluNewQuadric();
gluQuadricDrawStyle( quadObj, GLU_FILL );
gluQuadricNormals( quadObj, GLU_SMOOTH );
gluDisk( quadObj, 0.0, aSize, 12, 1 );
gluDeleteQuadric( quadObj );
quadObj = gluNewQuadric();
gluQuadricDrawStyle( quadObj, GLU_FILL );
gluQuadricNormals( quadObj, GLU_SMOOTH );
gluSphere( quadObj, aSize, 24, 24 );
gluDeleteQuadric( quadObj );
glTranslatef( 0.0f , 0.0f ,-length + 4.0f * aSize );
quadObj = gluNewQuadric();
gluQuadricDrawStyle( quadObj, GLU_FILL );
gluQuadricNormals( quadObj, GLU_SMOOTH );
gluCylinder( quadObj, aSize, aSize, length - 4.0 * aSize, 12, 1 );
gluDeleteQuadric( quadObj );
/*
quadObj = gluNewQuadric();
gluQuadricDrawStyle( quadObj, GLU_FILL );
gluQuadricNormals( quadObj, GLU_SMOOTH );
gluSphere( quadObj, aSize, 24, 24 );
gluDeleteQuadric( quadObj );
*/
quadObj = gluNewQuadric();
gluQuadricDrawStyle( quadObj, GLU_FILL );
gluQuadricNormals( quadObj, GLU_SMOOTH );
gluDisk( quadObj, 0.0, aSize, 12, 1 );
gluDeleteQuadric( quadObj );
glPopMatrix ();
}
void OGL_draw_bbox( const CBBOX &aBBox )
{
wxASSERT( aBBox.IsInitialized() );
glBegin( GL_LINE_LOOP );
glVertex3f( aBBox.Min().x, aBBox.Min().y, aBBox.Min().z );
glVertex3f( aBBox.Max().x, aBBox.Min().y, aBBox.Min().z );
glVertex3f( aBBox.Max().x, aBBox.Max().y, aBBox.Min().z );
glVertex3f( aBBox.Min().x, aBBox.Max().y, aBBox.Min().z );
glEnd();
glBegin( GL_LINE_LOOP );
glVertex3f( aBBox.Min().x, aBBox.Min().y, aBBox.Max().z );
glVertex3f( aBBox.Max().x, aBBox.Min().y, aBBox.Max().z );
glVertex3f( aBBox.Max().x, aBBox.Max().y, aBBox.Max().z );
glVertex3f( aBBox.Min().x, aBBox.Max().y, aBBox.Max().z );
glEnd();
glBegin( GL_LINE_STRIP );
glVertex3f( aBBox.Min().x, aBBox.Min().y, aBBox.Min().z );
glVertex3f( aBBox.Min().x, aBBox.Min().y, aBBox.Max().z );
glEnd();
glBegin( GL_LINE_STRIP );
glVertex3f( aBBox.Max().x, aBBox.Min().y, aBBox.Min().z );
glVertex3f( aBBox.Max().x, aBBox.Min().y, aBBox.Max().z );
glEnd();
glBegin( GL_LINE_STRIP );
glVertex3f( aBBox.Max().x, aBBox.Max().y, aBBox.Min().z );
glVertex3f( aBBox.Max().x, aBBox.Max().y, aBBox.Max().z );
glEnd();
glBegin( GL_LINE_STRIP );
glVertex3f( aBBox.Min().x, aBBox.Max().y, aBBox.Min().z );
glVertex3f( aBBox.Min().x, aBBox.Max().y, aBBox.Max().z );
glEnd();
}
void OGL_draw_half_open_cylinder( unsigned int aNrSidesPerCircle )
{
if( aNrSidesPerCircle > 1 )
{
const float radius = 0.5f;
const int delta = 3600 / aNrSidesPerCircle;
// Generate bottom
glNormal3f( 0.0f, 0.0f,-1.0f );
glBegin( GL_TRIANGLE_FAN );
glVertex3f( 0.0, 0.0, 0.0 ); // This is the V0 of the FAN
for( int ii = 0; ii < 1800; ii += delta )
{
SFVEC2D corner = SFVEC2D( 0.0, radius );
RotatePoint( &corner.x, &corner.y, ii );
glVertex3f( corner.x, corner.y, 0.0 );
}
glVertex3d( 0.0, -radius, 0.0 );
glEnd();
// Generate top
glNormal3f( 0.0f, 0.0f, 1.0f );
glBegin( GL_TRIANGLE_FAN );
glVertex3f( 0.0, 0.0, 1.0 ); // This is the V0 of the FAN
for( int ii = 1800; ii > 0; ii -= delta )
{
SFVEC2D corner = SFVEC2D( 0.0, radius );
RotatePoint( &corner.x, &corner.y, ii );
glVertex3f( corner.x, corner.y, 1.0 );
}
glVertex3f( 0.0, radius, 1.0 );
glEnd();
// Generate contours
glBegin( GL_QUAD_STRIP );
for( int ii = 1800; ii > 0; ii -= delta )
{
SFVEC2D corner = SFVEC2D( 0.0, radius );
RotatePoint( &corner.x, &corner.y, ii );
glNormal3f( corner.x * 2.0f, corner.y * 2.0f, 0.0f );
glVertex3f( corner.x, corner.y, 1.0 );
glVertex3f( corner.x, corner.y, 0.0 );
}
glNormal3f( 0.0, 1.0f, 0.0f );
glVertex3d( 0.0, radius, 1.0 );
glVertex3d( 0.0, radius, 0.0 );
glEnd();
}
}
void OGL_Draw_segment( const CROUNDSEGMENT2D &aSegment,
unsigned int aNrSidesPerCircle )
{
glPushMatrix();
const SFVEC2F start = aSegment.GetStart();
const SFVEC2F end_minus_start = aSegment.GetEnd_minus_Start();
const float radius = aSegment.GetRadius();
const float width = aSegment.GetWidth();
const float length = aSegment.GetLength();
glTranslatef( start.x, start.y, 0.0f );
if( ( end_minus_start.x != 0.0f ) || ( end_minus_start.y != 0.0f ) )
{
glRotatef( atan2( end_minus_start.y, end_minus_start.x ) / RADPERDEG,
0.0f,
0.0f,
1.0f );
}
glPushMatrix();
glTranslatef( length, 0.0, 0.0f );
glScalef( width, width, 1.0f );
OGL_draw_half_open_cylinder( aNrSidesPerCircle );
glPopMatrix();
glBegin( GL_QUADS );
glNormal3f( 0.0,-1.0, 0.0 );
glVertex3f( length,-radius, 1.0 );
glVertex3f( 0.0, -radius, 1.0 );
glVertex3f( 0.0, -radius, 0.0 );
glVertex3f( length,-radius, 0.0 );
glEnd();
glBegin( GL_QUADS );
glNormal3f( 0.0, 1.0, 0.0 );
glVertex3f( length, radius, 0.0 );
glVertex3f( 0.0, radius, 0.0 );
glVertex3f( 0.0, radius, 1.0 );
glVertex3f( length, radius, 1.0 );
glEnd();
glBegin( GL_QUADS );
glNormal3f( 0.0, 0.0, 1.0 );
glVertex3f( length, radius, 1.0 );
glVertex3f( 0.0, radius, 1.0 );
glVertex3f( 0.0, -radius, 1.0 );
glVertex3f( length,-radius, 1.0 );
glEnd();
glBegin( GL_QUADS );
glNormal3f( 0.0, 0.0,-1.0 );
glVertex3f( length,-radius, 0.0 );
glVertex3f( 0.0, -radius, 0.0 );
glVertex3f( 0.0, radius, 0.0 );
glVertex3f( length, radius, 0.0 );
glEnd();
glScalef( width, width, 1.0f );
glRotatef( 180, 0.0, 0.0, 1.0 );
OGL_draw_half_open_cylinder( aNrSidesPerCircle );
glPopMatrix ();
}
@@ -0,0 +1,70 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 ogl_legacy_utils.h
* @brief
*/
#ifndef OGL_LEGACY_UTILS_H_
#define OGL_LEGACY_UTILS_H_
#include "../3d_render_raytracing/shapes3D/cbbox.h"
#include "../3d_render_raytracing/shapes2D/croundsegment2d.h"
/**
* @brief OGL_draw_arrow - draw a round arrow
* @param aPosition: start position of the arrow
* @param aTargetPos: end position of the arror
* @param aSize: diameter size
*/
void OGL_draw_arrow( SFVEC3F aPosition, SFVEC3F aTargetPos, float aSize );
/**
* @brief OGL_draw_bbox - draw the bounding box lines
* @param aBBox is the box to draw
*/
void OGL_draw_bbox( const CBBOX &aBBox );
/**
* @brief OGL_draw_half_open_cylinder - draws an open half cylinder
* with diameter 1.0f and Height 1.0f
* the bottom center is at (0,0,0) and top center is at (0,0,1)
* @param aNrSidesPerCircle is the number of segments to approximate a circle.
*/
void OGL_draw_half_open_cylinder( unsigned int aNrSidesPerCircle );
/**
* @brief OGL_Draw_segment draws a thick segment with rounded ends
* @param aSegment is the thick segment to draw
* @param aNrSidesPerCircle is the number of segments to approximate a circle.
* used to draw the rounded ends of the segment
*/
void OGL_Draw_segment( const CROUNDSEGMENT2D &aSegment,
unsigned int aNrSidesPerCircle );
#endif // OGL_LEGACY_UTILS_H_
@@ -0,0 +1,212 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* 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 PerlinNoise.h
* @brief This source code comes from the project:
* https://github.com/sol-prog/Perlin_Noise
*
* It was changed to work with floats instead of doubles
*
* Original copyright notice:
*
* Perlin_Noise
* Here you could find the code for "Perlin noise in C++11", for more informations visit the project webpage:
* http://solarianprogrammer.com/2012/07/18/perlin-noise-cpp-11/
* You could use this program under the terms of GPL v3, for more details see:
* http://www.gnu.org/copyleft/gpl.html
* Copyright 2012 Sol from www.solarianprogrammer.com
*/
#include "PerlinNoise.h"
#include <cmath>
#include <iostream>
#include <cmath>
#include <random>
#include <algorithm>
#include <numeric>
// THIS IS A DIRECT TRANSLATION TO C++11 FROM THE REFERENCE
// JAVA IMPLEMENTATION OF THE IMPROVED PERLIN FUNCTION (see http://mrl.nyu.edu/~perlin/noise/)
// THE ORIGINAL JAVA IMPLEMENTATION IS COPYRIGHT 2002 KEN PERLIN
// I ADDED AN EXTRA METHOD THAT GENERATES A NEW PERMUTATION VECTOR
// (THIS IS NOT PRESENT IN THE ORIGINAL IMPLEMENTATION)
// Initialize with the reference values for the permutation vector
PerlinNoise::PerlinNoise()
{
// Initialize the permutation vector with the reference values
p = {
151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,
8,99,37,240,21,10,23,190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,
35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,
134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,
55,46,245,40,244,102,143,54, 65,25,63,161,1,216,80,73,209,76,132,187,208, 89,
18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,
250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,
189,28,42,223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167,
43,172,9,129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,
97,228,251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,
107,49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 };
// Duplicate the permutation vector
p.insert(p.end(), p.begin(), p.end());
}
// Generate a new permutation vector based on the value of seed
PerlinNoise::PerlinNoise( unsigned int seed )
{
p.resize( 256 );
// Fill p with values from 0 to 255
std::iota( p.begin(), p.end(), 0 );
// Initialize a random engine with seed
std::default_random_engine engine( seed );
// Suffle using the above random engine
std::shuffle( p.begin(), p.end(), engine );
// Duplicate the permutation vector
p.insert( p.end(), p.begin(), p.end() );
}
float PerlinNoise::noise( float x, float y, float z ) const
{
// Find the unit cube that contains the point
int X = static_cast<int>( std::floor( x ) ) & 255;
int Y = static_cast<int>( std::floor( y ) ) & 255;
int Z = static_cast<int>( std::floor( z ) ) & 255;
// Find relative x, y,z of point in cube
x -= std::floor( x );
y -= std::floor( y );
z -= std::floor( z );
// Compute fade curves for each of x, y, z
const float u = fade( x );
const float v = fade( y );
const float w = fade( z );
// Hash coordinates of the 8 cube corners
const int A = p[X] + Y;
const int AA = p[A] + Z;
const int AB = p[A + 1] + Z;
const int B = p[X + 1] + Y;
const int BA = p[B] + Z;
const int BB = p[B + 1] + Z;
// Add blended results from 8 corners of cube
const float res = lerp( w,
lerp( v,
lerp( u,
grad( p[AA], x , y, z),
grad( p[BA], x - 1, y, z) ),
lerp( u,
grad( p[AB], x , y - 1, z ),
grad( p[BB], x - 1, y - 1, z) ) ),
lerp( v,
lerp( u,
grad( p[AA + 1], x , y, z - 1 ),
grad( p[BA + 1], x - 1, y, z - 1) ),
lerp( u,
grad( p[AB + 1], x , y - 1, z - 1 ),
grad( p[BB + 1], x - 1, y - 1, z - 1 ) ) ) );
return (res + 1.0f) / 2.0f;
}
float PerlinNoise::noise( float x, float y ) const
{
// Find the unit cube that contains the point
int X = static_cast<int>( std::floor( x ) ) & 255;
int Y = static_cast<int>( std::floor( y ) ) & 255;
// Find relative x, y,z of point in cube
x -= std::floor( x );
y -= std::floor( y );
// Compute fade curves for each of x, y
const float u = fade( x );
const float v = fade( y );
// Hash coordinates of the 8 cube corners
const int A = p[X] + Y;
const int AA = p[A] + 0;
const int AB = p[A + 1] + 0;
const int B = p[X + 1] + Y;
const int BA = p[B] + 0;
const int BB = p[B + 1] + 0;
// Add blended results from 8 corners of cube
const float res = lerp( v,
lerp( u,
grad( p[AA], x , y ),
grad( p[BA], x - 1, y ) ),
lerp( u,
grad( p[AB], x , y - 1 ),
grad( p[BB], x - 1, y - 1 ) ) );
return (res + 1.0f) / 2.0f;
}
float PerlinNoise::fade( float t ) const
{
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
}
float PerlinNoise::lerp( float t, float a, float b ) const
{
return a + t * (b - a);
}
float PerlinNoise::grad( int hash, float x, float y, float z ) const
{
const int h = hash & 15;
// Convert lower 4 bits of hash inot 12 gradient directions
const float u = h < 8 ? x : y;
const float v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
float PerlinNoise::grad( int hash, float x, float y ) const
{
const int h = hash & 15;
// Convert lower 4 bits of hash inot 12 gradient directions
const float u = h < 8 ? x : y;
const float v = h < 4 ? y : h == 12 || h == 14 ? x : 0.0f;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}

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