Compare commits
191 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f35e384c1 | |||
| 6b1b6d4ff7 | |||
| be070d95be | |||
| 17f7921311 | |||
| 631f6d53d3 | |||
| aba04c6ec5 | |||
| 133cb01f79 | |||
| 464175e995 | |||
| c0fab4b350 | |||
| 17c8198c05 | |||
| 683da9acd1 | |||
| 5a67fc99d3 | |||
| a7223a95b9 | |||
| 58f90b3adb | |||
| a374f46b5e | |||
| bfacf02360 | |||
| 4e8a35cb84 | |||
| 6a9f38ecc4 | |||
| 593136aca3 | |||
| 1754b42ba3 | |||
| 3ae069ed4f | |||
| fc527f3cc1 | |||
| 7a5e632455 | |||
| 82d7a4e61e | |||
| 63569551a4 | |||
| 3b7aa48d16 | |||
| 249b0a0ce5 | |||
| 3c6959b7de | |||
| e5307ca1fb | |||
| d1f8dbb9de | |||
| 99d7a35797 | |||
| 0145a03f79 | |||
| df191606ab | |||
| 556be7b431 | |||
| e15ba3bf32 | |||
| c23c52834c | |||
| 981fddc649 | |||
| 5127a6bd09 | |||
| 136ba26896 | |||
| 575b22d018 | |||
| 5f01ca8f88 | |||
| 5a3c944b2a | |||
| 50a4b5553a | |||
| 4cb084cd63 | |||
| a458342cfc | |||
| 8023c7a794 | |||
| 65fe561a4b | |||
| 18f77b894e | |||
| 94a3390544 | |||
| cec3e300a8 | |||
| a262445047 | |||
| 0fbdec4c08 | |||
| de52ae6c70 | |||
| 9ca6405bcb | |||
| 1dc747c0ae | |||
| 183835ee67 | |||
| 6dbe262b53 | |||
| e074c798bf | |||
| bd1aae9071 | |||
| 6382db4ebf | |||
| 8151ec387c | |||
| 6e1d45c79e | |||
| 1d05076761 | |||
| 89e7d89223 | |||
| 115d70e060 | |||
| 1a89a0601a | |||
| ca0aa6c971 | |||
| 5b4542231e | |||
| fa85cb3a8b | |||
| 853984120c | |||
| be62a1ade6 | |||
| 3b4cdd96ab | |||
| f776b7c3fb | |||
| 9d233b4cdb | |||
| 19c54933c1 | |||
| 7aca6174d6 | |||
| 5f98fc0591 | |||
| bcdcaa724d | |||
| 32f24289bd | |||
| 021320be1b | |||
| e309ca10d1 | |||
| a65b7963d1 | |||
| 26c5485be9 | |||
| 48d2ac15d5 | |||
| 2ab90d6d20 | |||
| 81cc0b4c42 | |||
| 95b84f4a8d | |||
| 6c25b29e9f | |||
| 1f6789e692 | |||
| e4307a86cc | |||
| ce181e6e0a | |||
| 4212d99c3d | |||
| 535f3ae006 | |||
| 90ed0183c8 | |||
| 2bb695b767 | |||
| c980e6999a | |||
| 1e7ba6c644 | |||
| 53f6bf29c7 | |||
| 8e4098f3f1 | |||
| 7179a71cdc | |||
| 606978297d | |||
| 648b7d53b5 | |||
| 93c5e5e4aa | |||
| 7940f0773c | |||
| 226d56433c | |||
| 5cf68726d6 | |||
| 3c233ae08e | |||
| 9810236314 | |||
| 7dbf84a9bd | |||
| b73a71c696 | |||
| e4e635d3b5 | |||
| 2ffdc0d03d | |||
| 91f34a9478 | |||
| 67ab1be495 | |||
| fdc4d2a8a9 | |||
| 72f19ded75 | |||
| 3c8bed9c92 | |||
| 6a33549b68 | |||
| ab99c58ead | |||
| c8daccbe0e | |||
| b6dedd9f5b | |||
| fd054f566e | |||
| 4a665f492e | |||
| a0d41f75ff | |||
| 5f72cca19a | |||
| 8191327fc2 | |||
| a19a52398a | |||
| f3d173fe64 | |||
| 3076e98b29 | |||
| 1d55823fef | |||
| 62475d0464 | |||
| 1060d4ac6e | |||
| 44038c47c6 | |||
| fef0759155 | |||
| 16dbe11868 | |||
| 68725bc20c | |||
| 963b4d5ed6 | |||
| 6657981553 | |||
| 286f6a426b | |||
| cc058033cc | |||
| 18f07d8efb | |||
| 6d3e1b9391 | |||
| 79fe4a0acb | |||
| 5c4fbbec43 | |||
| 7d0299f153 | |||
| e9570fddd6 | |||
| 34217c0199 | |||
| ab0e3d0ce2 | |||
| c8b2971d1c | |||
| 9b0bd7ca1f | |||
| fd009f924a | |||
| 48e2addd69 | |||
| a773ecc735 | |||
| dcd81e23f4 | |||
| bff0068065 | |||
| d0932944fc | |||
| 5c3a56bdcc | |||
| e9bfcc28c3 | |||
| 3cdac44ac2 | |||
| 2cebaa2d79 | |||
| 609b996abe | |||
| ea0c187e09 | |||
| bf6cd8445a | |||
| c50763bd5b | |||
| 1aa6932b12 | |||
| 342ec2be0e | |||
| d451800d0a | |||
| 48435c5cb3 | |||
| 8999ae9fb2 | |||
| 8184ba1cf3 | |||
| 228ed4ea41 | |||
| 3031a3f5cf | |||
| 42aa93e34b | |||
| eb8b407717 | |||
| eaea15fbef | |||
| 72a69f9428 | |||
| c66656c5d4 | |||
| 14363262c2 | |||
| 509e71fdb3 | |||
| 6c5e2f3900 | |||
| f46272bed9 | |||
| 2f7b3ab56e | |||
| b526227529 | |||
| e93c815e02 | |||
| 5c8f7c7a3a | |||
| 7fb6698e29 | |||
| f11b426151 | |||
| 827dad3197 | |||
| 593c974063 | |||
| a68b3cb486 | |||
| ce81524b83 |
+50
@@ -0,0 +1,50 @@
|
||||
boost_root
|
||||
.downloads-by-cmake
|
||||
Build
|
||||
build
|
||||
common/netlist_keywords.*
|
||||
common/netlist_lexer.h
|
||||
common/pcb_plot_params_lexer.h
|
||||
common/page_layout/page_layout_reader_keywords.cpp
|
||||
common/fp_lib_table_keywords.*
|
||||
common/gal/opengl/shader_src.h
|
||||
include/fp_lib_table_lexer.h
|
||||
include/netlist_lexer.h
|
||||
include/page_layout_reader_lexer.h
|
||||
eeschema/cmp_library_lexer.h
|
||||
eeschema/cmp_library_keywords.*
|
||||
eeschema/dialogs/dialog_bom_cfg_keywords.cpp
|
||||
eeschema/dialogs/dialog_bom_cfg_lexer.h
|
||||
eeschema/dialogs/dialog_bom_help_html.h
|
||||
eeschema/template_fieldnames_keywords.*
|
||||
eeschema/template_fieldnames_lexer.h
|
||||
pcbnew/dialogs/dialog_freeroute_exchange_help_html.h
|
||||
pcbnew/pcb_plot_params_keywords.cpp
|
||||
pcbnew/pcb_plot_params_lexer.h
|
||||
Makefile
|
||||
CMakeCache.txt
|
||||
auto_renamed_to_cpp
|
||||
Testing
|
||||
version.h
|
||||
config.h
|
||||
install_manifest.txt
|
||||
Documentation/doxygen
|
||||
Documentation/development/doxygen
|
||||
*.bak
|
||||
.*.swp
|
||||
*.~*
|
||||
common/pcb_plot_params_keywords.cpp
|
||||
include/pcb_plot_params_lexer.h
|
||||
pcbnew/specctra_keywords.cpp
|
||||
pcbnew/specctra_lexer.h
|
||||
pcb_calculator/pcb_calculator_datafile_keywords.cpp
|
||||
pcb_calculator/pcb_calculator_datafile_lexer.h
|
||||
new/html
|
||||
new/sch_lib_table_keywords.cpp
|
||||
new/sch_lib_table_lexer.h
|
||||
new/sweet_keywords.cpp
|
||||
new/sweet_lexer.h
|
||||
bitmaps_png/png*
|
||||
bitmaps_png/tmp
|
||||
common/pcb_keywords.cpp
|
||||
include/pcb_lexer.h
|
||||
@@ -1,57 +0,0 @@
|
||||
# minimum clang-format 10
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: true
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: None
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeBraces: Allman
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 100
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ForEachMacros: [ BOOST_FOREACH ]
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: Inner
|
||||
PointerAlignment: Left
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: Never
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: true
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: c++11
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
@@ -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'
|
||||
@@ -1,36 +0,0 @@
|
||||
|
||||
# Custom attribute to mark source files using KiCad C++ formatting
|
||||
[attr]kicad-cpp-source text=auto whitepace=tab-in-indent format.clang-format-kicad
|
||||
|
||||
# Custom attribute to mark KiCad's own CMake files
|
||||
[attr]kicad-cmake-source text=auto whitespace=tab-in-indent
|
||||
|
||||
# Custom attribute for auto-generated sources:
|
||||
# * Do not perform whitespace checking
|
||||
# * Do not format
|
||||
[attr]generated whitespace=-tab-in-indent,-indent-with-non-tab -format.clang-format-kicad
|
||||
|
||||
# By default, all C and C++ files conform to KiCad formatting,
|
||||
# unless overridden
|
||||
*.c kicad-cpp-source
|
||||
*.cpp kicad-cpp-source
|
||||
*.h kicad-cpp-source
|
||||
|
||||
*.cmake kicad-cmake-source
|
||||
*.txt kicad-cmake-source
|
||||
*.md text=auto
|
||||
|
||||
# Compiled bitmap sources
|
||||
bitmaps_png/cpp_*/*.cpp generated
|
||||
|
||||
# wxFormBuilder-generated files
|
||||
**/dialog*/*_base.cpp generated
|
||||
**/dialog*/*_base.h generated
|
||||
|
||||
# Lemon grammars
|
||||
common/libeval/grammar.c generated
|
||||
common/libeval/grammar.h generated
|
||||
|
||||
# Scripts
|
||||
*.sh text eol=lf
|
||||
*.bat text eol=crlf
|
||||
@@ -0,0 +1,2 @@
|
||||
[core]
|
||||
excludesfile .bzrignore
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Git "hook chain", used to execute multiple scripts per hook.
|
||||
# To use:
|
||||
# * create a directory called <hookname>.d
|
||||
# * add scripts to this directory (executable)
|
||||
# * ln -s hook-chain <hookname>
|
||||
#
|
||||
# Now the scripts in that directory should be called in order.
|
||||
#
|
||||
# Set $HOOKCHAIN_DEBUG to see the names of invoked scripts.
|
||||
#
|
||||
# Based on script by Oliver Reflalo:
|
||||
# https://stackoverflow.com/questions/8730514/chaining-git-hooks
|
||||
#
|
||||
|
||||
hookname=`basename $0`
|
||||
|
||||
# Temp file for stdin, cleared at exit
|
||||
FILE=`mktemp`
|
||||
trap 'rm -f $FILE' EXIT
|
||||
cat - > $FILE
|
||||
|
||||
# Git hooks directory (this dir)
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
|
||||
# Execute hooks in the directory one by one
|
||||
for hook in $DIR/$hookname.d/*;
|
||||
do
|
||||
if [ -x "$hook" ]; then
|
||||
|
||||
if [ "$HOOKCHAIN_DEBUG" ]; then
|
||||
echo "Running hook $hook"
|
||||
fi
|
||||
|
||||
cat $FILE | $hook "$@"
|
||||
status=$?
|
||||
|
||||
if [ $status -ne 0 ]; then
|
||||
echo "Hook $hook failed with error code $status"
|
||||
echo "To commit anyway, use --no-verify"
|
||||
exit $status
|
||||
else
|
||||
if [ "$HOOKCHAIN_DEBUG" ]; then
|
||||
echo "Hook passed: $hook"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
@@ -1 +0,0 @@
|
||||
hook-chain
|
||||
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Runs clang-format on changed regions before commit.
|
||||
#
|
||||
# Remaining installation checks/instructions will be printed when you commit.
|
||||
#
|
||||
# Based on clang-format pre-commit hook by Alex Eagle
|
||||
# https://gist.github.com/alexeagle/c8ed91b14a407342d9a8e112b5ac7dab
|
||||
|
||||
# Set kicad.check-format to allow this hook to run
|
||||
# If not set, the hook always succeeds.
|
||||
|
||||
do_format=false
|
||||
|
||||
# Check if formatting is configured
|
||||
if [ "$(git config --get kicad.check-format)" = true ]; then
|
||||
do_format=true
|
||||
fi
|
||||
|
||||
# Older env variable method
|
||||
if [ ! -z "$KICAD_CHECK_FORMAT" ]; then
|
||||
do_format=true
|
||||
fi
|
||||
|
||||
if [ ! ${do_format} = true ]; then
|
||||
# No formatting required
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
check_clang_format() {
|
||||
if hash git-clang-format 2>/dev/null; then
|
||||
return
|
||||
else
|
||||
echo "SETUP ERROR: no git-clang-format executable found, or it is not executable"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_git_config() {
|
||||
if [[ "$(git config --get clangFormat.style)" != "file" ]]; then
|
||||
echo "SETUP ERROR: git config clangFormat.style is wrong (should be 'file'). Fix this with:"
|
||||
echo "git config clangFormat.style file"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
get_filtered_filenames()
|
||||
{
|
||||
format_attr='clang-format-kicad'
|
||||
|
||||
# command to get list of candidate files
|
||||
git_list_files='git diff --cached --name-only --diff-filter=ACM'
|
||||
|
||||
files=$(${git_list_files} |
|
||||
|
||||
# Filter for format-controlled files
|
||||
git check-attr --stdin format.${format_attr} |
|
||||
|
||||
# output only the file names
|
||||
grep ": set$" |
|
||||
cut -d: -f1)
|
||||
|
||||
echo ${files}
|
||||
}
|
||||
|
||||
check_clang_format
|
||||
check_git_config
|
||||
|
||||
files_to_check=$(get_filtered_filenames)
|
||||
|
||||
if [ -z "${files_to_check}" ]; then
|
||||
# No controlled files to check
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
git_clang_format_cmd="git clang-format -v --diff -- ${files_to_check}"
|
||||
|
||||
readonly out=$(${git_clang_format_cmd})
|
||||
|
||||
# In these cases, there is no formatting issues, so we succeed
|
||||
if [[ "$out" == *"no modified files to format"* ]]; then exit 0; fi
|
||||
if [[ "$out" == *"clang-format did not modify any files"* ]]; then exit 0; fi
|
||||
|
||||
# Any other case implies formatting results
|
||||
echo "ERROR: you need to run clang-format (e.g. using tools/check_coding.sh) on your commit"
|
||||
|
||||
# print the errors to show what's the issue
|
||||
${git_clang_format_cmd}
|
||||
|
||||
# fail the pre-commit
|
||||
exit 1
|
||||
@@ -1,2 +0,0 @@
|
||||
custom: "https://donate.kicad.org"
|
||||
community_bridge: kicad
|
||||
@@ -1,26 +0,0 @@
|
||||
name: 'Redirect PRs'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: opened
|
||||
|
||||
jobs:
|
||||
lockdown:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/repo-lockdown@v2
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
pr-comment: >
|
||||
Thank you for offering to help improve KiCad.
|
||||
This repository is a one-way mirror that can not accept pull requests.
|
||||
Please submit your merge request to the official KiCad repository
|
||||
at https://gitlab.com/kicad/code/kicad/-/merge_requests
|
||||
While we know that _your_ PR is not spam, we mark it as such to dissuade
|
||||
the Hacktoberfest PRs. Please join us over at GitLab. You can even use
|
||||
your GitHub credentials to log in there without creating a new account.
|
||||
skip-closed-pr-comment: true
|
||||
pr-labels: 'spam'
|
||||
close-pr: true
|
||||
lock-pr: true
|
||||
pr-lock-reason: 'spam'
|
||||
+22
-106
@@ -1,44 +1,47 @@
|
||||
.downloads-by-cmake
|
||||
.gdb_history
|
||||
boost_root
|
||||
/Build*
|
||||
/build*
|
||||
/cmake-build-*
|
||||
common/fp_lib_table_keywords.cpp
|
||||
common/drc_rules_keywords.cpp
|
||||
common/drc_rules_lexer.h
|
||||
.downloads-by-cmake
|
||||
Build*
|
||||
build*
|
||||
common/netlist_keywords.*
|
||||
common/netlist_lexer.h
|
||||
common/pcb_plot_params_lexer.h
|
||||
common/drawing_sheet/drawing_sheet_reader_keywords.cpp
|
||||
common/page_layout/page_layout_reader_keywords.cpp
|
||||
common/lib_table_keywords.*
|
||||
common/gal/opengl/shader_src.h
|
||||
include/fp_lib_table_lexer.h
|
||||
include/lib_table_lexer.h
|
||||
include/netlist_lexer.h
|
||||
include/page_layout_reader_lexer.h
|
||||
eeschema/cmp_library_lexer.h
|
||||
eeschema/cmp_library_keywords.*
|
||||
eeschema/dialogs/dialog_bom_cfg_keywords.cpp
|
||||
eeschema/dialogs/dialog_bom_cfg_lexer.h
|
||||
common/template_fieldnames_keywords.cpp
|
||||
common/template_fieldnames_lexer.h
|
||||
eeschema/schematic_keywords.*
|
||||
eeschema/dialogs/dialog_bom_help_html.h
|
||||
eeschema/template_fieldnames_keywords.*
|
||||
eeschema/template_fieldnames_lexer.h
|
||||
pcbnew/dialogs/dialog_freeroute_exchange_help_html.h
|
||||
pcbnew/pcb_plot_params_keywords.cpp
|
||||
pcbnew/pcb_plot_params_lexer.h
|
||||
pcb_calculator/attenuators/bridget_tee_formula.h
|
||||
pcb_calculator/attenuators/pi_formula.h
|
||||
pcb_calculator/attenuators/splitter_formula.h
|
||||
pcb_calculator/attenuators/tee_formula.h
|
||||
Makefile
|
||||
CMakeUserPresets.json
|
||||
CMakeCache.txt
|
||||
.cache/
|
||||
auto_renamed_to_cpp
|
||||
Testing
|
||||
version.h
|
||||
config.h
|
||||
install_manifest.txt
|
||||
doxygen/out
|
||||
Documentation/doxygen
|
||||
Documentation/development/doxygen
|
||||
*.bak
|
||||
*.pyc
|
||||
.*.swp
|
||||
*~
|
||||
common/pcb_plot_params_keywords.cpp
|
||||
include/pcb_plot_params_lexer.h
|
||||
pcbnew/specctra_import_export/specctra_keywords.cpp
|
||||
pcbnew/specctra_import_export/specctra_lexer.h
|
||||
pcbnew/specctra_keywords.cpp
|
||||
pcbnew/specctra_lexer.h
|
||||
pcb_calculator/pcb_calculator_datafile_keywords.cpp
|
||||
pcb_calculator/pcb_calculator_datafile_lexer.h
|
||||
new/html
|
||||
@@ -46,94 +49,7 @@ new/sch_lib_table_keywords.cpp
|
||||
new/sch_lib_table_lexer.h
|
||||
new/sweet_keywords.cpp
|
||||
new/sweet_lexer.h
|
||||
bitmaps_png/png*
|
||||
bitmaps_png/tmp
|
||||
common/pcb_keywords.cpp
|
||||
include/pcb_lexer.h
|
||||
fp-info-cache
|
||||
qa/tests/output/**
|
||||
|
||||
# demo project auxiliary files
|
||||
demos/**/*-bak
|
||||
demos/**/_autosave-*
|
||||
demos/**/fp-info-cache
|
||||
demos/**/~*.lck
|
||||
|
||||
# MacOS package info created by CMake
|
||||
bitmap2component/Info.plist
|
||||
cvpcb/Info.plist
|
||||
eeschema/Info.plist
|
||||
gerbview/Info.plist
|
||||
kicad/Info.plist
|
||||
pagelayout_editor/Info.plist
|
||||
pcb_calculator/Info.plist
|
||||
pcbnew/Info.plist
|
||||
|
||||
# editor/OS fluff
|
||||
.*.swp
|
||||
*~
|
||||
.idea
|
||||
.DS_Store
|
||||
*.png
|
||||
*.kiface
|
||||
*.o
|
||||
*.o.*
|
||||
*.a
|
||||
*.a.*
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.old
|
||||
*.gch
|
||||
*.orig
|
||||
*.patch
|
||||
|
||||
# These CMake files are wanted
|
||||
!cmake/**/*.cmake
|
||||
|
||||
# Eclipse IDE
|
||||
.settings/
|
||||
.project
|
||||
.cproject
|
||||
.pydevproject
|
||||
__pycache__
|
||||
|
||||
# Visual Studio
|
||||
.vs/
|
||||
.editorconfig
|
||||
CMakeSettings.json
|
||||
.vscode/
|
||||
compile_commands.json
|
||||
/vcpkg_installed
|
||||
CMakePresets.json
|
||||
|
||||
# Sublime Text
|
||||
*.sublime-*
|
||||
|
||||
# KDevelop
|
||||
.kdev4/
|
||||
*.kdev4
|
||||
|
||||
# Qt Creator
|
||||
CMakeLists.txt.user
|
||||
*.autosave
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
i18n_status.svg
|
||||
i18n_status.csv
|
||||
|
||||
# Project local settings files and backups (in demos and qa tests)
|
||||
*.kicad_prl
|
||||
*-backups
|
||||
|
||||
# QA dataoutput
|
||||
qa/data/**/*.csv
|
||||
|
||||
# Don't actually ignore any of these files, since we need them in the tree
|
||||
!resources/linux/icons/hicolor/**/**/*
|
||||
!resources/linux/icons-nightly/hicolor/**/**/*
|
||||
!CMakeModules/**/*
|
||||
!resources/bitmaps_png/png/**/*
|
||||
|
||||
# Junk temp files generated by MSVC for resource files
|
||||
/resources/msw/RC*
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- report
|
||||
|
||||
variables:
|
||||
DEFAULT_FEDORA_IMAGE: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:40
|
||||
|
||||
default:
|
||||
image:
|
||||
name: $DEFAULT_FEDORA_IMAGE
|
||||
entrypoint: ["/bin/sh", "-c"]
|
||||
|
||||
include:
|
||||
- local: '/.gitlab/templates.yml'
|
||||
- local: '/.gitlab/Fedora-Linux-CI.yml'
|
||||
- local: '/.gitlab/Ubuntu-20.04-CI.yml'
|
||||
- local: '/.gitlab/Windows-CI.yml'
|
||||
- local: '/.gitlab/macOS-CI.yml'
|
||||
- local: '/.gitlab/coverity.yml'
|
||||
- local: '/.gitlab/linux-metadata-validate.yml'
|
||||
- local: '/.gitlab/doxygen.yml'
|
||||
- local: '/.gitlab/mr_formatting.yml'
|
||||
@@ -1,179 +0,0 @@
|
||||
##########################################################################
|
||||
# Build KiCad on Fedora and save the results
|
||||
##########################################################################
|
||||
.fedora_build_linux_base:
|
||||
stage: build
|
||||
# Don't tag until we have separate CI for MRs
|
||||
# tags:
|
||||
# - kicad-fedora
|
||||
image: $DEFAULT_FEDORA_IMAGE
|
||||
extends: .only_code
|
||||
interruptible: false
|
||||
cache:
|
||||
key: "cache-fedora-linux"
|
||||
paths:
|
||||
- ccache/
|
||||
before_script:
|
||||
# CCache Config
|
||||
- mkdir -p ccache
|
||||
- export CCACHE_BASEDIR=${PWD}
|
||||
- export CCACHE_DIR=${PWD}/ccache
|
||||
script:
|
||||
- mkdir -p build/linux
|
||||
- cd build/linux
|
||||
- cmake
|
||||
-G Ninja
|
||||
-DCMAKE_BUILD_TYPE=QABUILD
|
||||
-DKICAD_STDLIB_LIGHT_DEBUG=ON
|
||||
-DKICAD_BUILD_I18N=ON
|
||||
-DKICAD_TEST_XML_OUTPUT=ON
|
||||
-DKICAD_BUILD_PNS_DEBUG_TOOL=ON
|
||||
-DKICAD_USE_CMAKE_FINDPROTOBUF=ON
|
||||
../../
|
||||
- ninja 2>&1 | tee compilation_log.txt
|
||||
- cd ../../
|
||||
artifacts:
|
||||
# Only save the artifacts that are needed for running the tests in the next stage
|
||||
# and the compilation log. The entire build directory is too large to save as an
|
||||
# artifact.
|
||||
expire_in: 2 hrs
|
||||
when: always
|
||||
paths:
|
||||
- build/linux/3d-viewer/
|
||||
- build/linux/api/libkiapi.so*
|
||||
- build/linux/common/libkicommon.so*
|
||||
- build/linux/common/gal/libkigal.so*
|
||||
- build/linux/eeschema/_eeschema.kiface
|
||||
- build/linux/cvpcb/_cvpcb.kiface
|
||||
- build/linux/kicad/kicad-cli
|
||||
- build/linux/pcbnew/pcbnew.py
|
||||
- build/linux/pcbnew/_pcbnew.kiface
|
||||
- build/linux/pcbnew/_pcbnew.so
|
||||
- build/linux/qa/
|
||||
- build/linux/schemas/
|
||||
- build/linux/compilation_log.txt
|
||||
exclude:
|
||||
- build/linux/**/*.o
|
||||
- build/linux/**/*.a
|
||||
|
||||
# This split is to ensure we can always use our runner for our jobs
|
||||
fedora_build_linux_kicad:
|
||||
extends: .fedora_build_linux_base
|
||||
tags:
|
||||
- kicad-fedora
|
||||
only:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
fedora_build_linux_public:
|
||||
extends: .fedora_build_linux_base
|
||||
tags:
|
||||
- saas-linux-medium-amd64
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
|
||||
# Upload the compilation log in an easily downloadable form
|
||||
.fedora_report_build_warn:
|
||||
stage: report
|
||||
extends: .only_code
|
||||
when: always
|
||||
script:
|
||||
- echo "Uploading compilation log"
|
||||
- cp build/linux/compilation_log.txt compilation_log.txt
|
||||
artifacts:
|
||||
expire_in: 1 year
|
||||
expose_as: 'Build log'
|
||||
name: "build_log.txt"
|
||||
paths:
|
||||
- compilation_log.txt
|
||||
|
||||
fedora_report_build_warn_kicad:
|
||||
extends: .fedora_report_build_warn
|
||||
tags:
|
||||
- kicad-fedora
|
||||
needs:
|
||||
- job: fedora_build_linux_kicad
|
||||
artifacts: true
|
||||
only:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
fedora_report_build_warn_public:
|
||||
extends: .fedora_report_build_warn
|
||||
needs:
|
||||
- job: fedora_build_linux_public
|
||||
artifacts: true
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
|
||||
# Report on the metrics of the code
|
||||
.fedora_report_metrics:
|
||||
stage: report
|
||||
extends: .only_code
|
||||
when: always
|
||||
script:
|
||||
- cat build/linux/compilation_log.txt | { grep "warning:" || test $? = 1; } | awk 'END{print "number_of_fedora_warnings "NR}' > metrics.txt
|
||||
- cat metrics.txt
|
||||
artifacts:
|
||||
reports:
|
||||
metrics: metrics.txt
|
||||
|
||||
fedora_report_metrics_kicad:
|
||||
extends: .fedora_report_metrics
|
||||
tags:
|
||||
- kicad-fedora
|
||||
needs:
|
||||
- job: fedora_build_linux_kicad
|
||||
artifacts: true
|
||||
only:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
fedora_report_metrics_public:
|
||||
extends: .fedora_report_metrics
|
||||
needs:
|
||||
- job: fedora_build_linux_public
|
||||
artifacts: true
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
##########################################################################
|
||||
# Run the code unit tests.
|
||||
##########################################################################
|
||||
.fedora_qa:
|
||||
image: $DEFAULT_FEDORA_IMAGE
|
||||
extends:
|
||||
- .unit_test
|
||||
- .only_code
|
||||
before_script:
|
||||
- if [ "$TEST" == "cli" ] || [ "$TEST" == "python" ]; then python3 -m pip install -r qa/tests/requirements.txt; fi
|
||||
- if [ "$TEST" == "cli" ]; then sudo dnf -y install gerbv; fi
|
||||
parallel:
|
||||
matrix:
|
||||
# The name of the test without the qa_ prefix
|
||||
- TEST: [python, cli, common, gerbview, pcbnew, pns_regressions, eeschema, kimath, sexpr, kicad2step, spice, api]
|
||||
|
||||
fedora_qa_kicad:
|
||||
extends: .fedora_qa
|
||||
tags:
|
||||
- kicad-fedora
|
||||
needs:
|
||||
- job: fedora_build_linux_kicad
|
||||
artifacts: true
|
||||
only:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
fedora_qa_public:
|
||||
extends: .fedora_qa
|
||||
needs:
|
||||
- job: fedora_build_linux_public
|
||||
artifacts: true
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
@@ -1,118 +0,0 @@
|
||||
##########################################################################
|
||||
# Build KiCad on Ubuntu 20.04 and save the results
|
||||
##########################################################################
|
||||
.ubuntu20.04_build:
|
||||
stage: build
|
||||
tags:
|
||||
- kicad-ubuntu20.04
|
||||
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/ubuntu:20.04
|
||||
only:
|
||||
- branches@kicad/code/kicad
|
||||
- tags@kicad/code/kicad
|
||||
except:
|
||||
- schedules
|
||||
interruptible: false
|
||||
cache:
|
||||
key: "cache-ubuntu20.04-linux"
|
||||
paths:
|
||||
- ccache/
|
||||
before_script:
|
||||
# CCache Config
|
||||
- mkdir -p ccache
|
||||
- export CCACHE_BASEDIR=${PWD}
|
||||
- export CCACHE_DIR=${PWD}/ccache
|
||||
script:
|
||||
- mkdir -p build/linux
|
||||
- cd build/linux
|
||||
- cmake
|
||||
-G Ninja
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DKICAD_STDLIB_LIGHT_DEBUG=ON
|
||||
-DKICAD_SCRIPTING_WXPYTHON=ON
|
||||
-DKICAD_USE_OCC=ON
|
||||
-DKICAD_BUILD_I18N=ON
|
||||
-DKICAD_BUILD_PNS_DEBUG_TOOL=ON
|
||||
../../
|
||||
- ninja 2>&1 | tee compilation_log.txt
|
||||
- cd ../../
|
||||
artifacts:
|
||||
# Only save the artifacts that are needed for running the tests in the next stage
|
||||
# and the compilation log. The entire build directory is too large to save as an
|
||||
# artifact.
|
||||
expire_in: 2 hrs
|
||||
when: always
|
||||
paths:
|
||||
- build/linux/3d-viewer/
|
||||
- build/linux/pcbnew/pcbnew.py
|
||||
- build/linux/pcbnew/_pcbnew.kiface
|
||||
- build/linux/pcbnew/_pcbnew.so
|
||||
- build/linux/qa/
|
||||
- build/linux/compilation_log.txt
|
||||
exclude:
|
||||
- build/linux/**/*.o
|
||||
- build/linux/**/*.a
|
||||
|
||||
# Upload the compilation log in an easily downloadable form
|
||||
.ubuntu20.04_report_build_warn:
|
||||
stage: report
|
||||
when: always
|
||||
only:
|
||||
- branches@kicad/code/kicad
|
||||
- tags@kicad/code/kicad
|
||||
except:
|
||||
- schedules
|
||||
needs:
|
||||
- job: ubuntu20.04_build
|
||||
artifacts: true
|
||||
script:
|
||||
- echo "Uploading compilation log"
|
||||
- cp build/linux/compilation_log.txt compilation_log.txt
|
||||
artifacts:
|
||||
expire_in: 1 year
|
||||
expose_as: 'Build log'
|
||||
name: "build_log.txt"
|
||||
paths:
|
||||
- compilation_log.txt
|
||||
|
||||
# Report on the metrics of the code
|
||||
.ubuntu20.04_report_metrics:
|
||||
stage: report
|
||||
when: always
|
||||
only:
|
||||
- branches@kicad/code/kicad
|
||||
- tags@kicad/code/kicad
|
||||
except:
|
||||
- schedules
|
||||
needs:
|
||||
- job: ubuntu20.04_build
|
||||
artifacts: true
|
||||
script:
|
||||
- cat build/linux/compilation_log.txt | { grep "warning:" || test $? = 1; } | awk 'END{print "number_of_ubuntu_20.04_warnings "NR}' > metrics.txt
|
||||
- cat metrics.txt
|
||||
artifacts:
|
||||
reports:
|
||||
metrics: metrics.txt
|
||||
|
||||
##########################################################################
|
||||
# Run the code unit tests.
|
||||
##########################################################################
|
||||
.ubuntu20.04_qa:
|
||||
extends:
|
||||
- .unit_test
|
||||
needs:
|
||||
- job: ubuntu20.04_build
|
||||
artifacts: true
|
||||
tags:
|
||||
- kicad-ubuntu20.04
|
||||
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/ubuntu:20.04
|
||||
only:
|
||||
- branches@kicad/code/kicad
|
||||
- tags@kicad/code/kicad
|
||||
except:
|
||||
- schedules
|
||||
parallel:
|
||||
matrix:
|
||||
# The name of the test without the qa_ prefix
|
||||
- TEST: [python, common, gerbview, pcbnew, eeschema, kimath, sexpr, kicad2step, spice]
|
||||
@@ -1,47 +0,0 @@
|
||||
##########################################################################
|
||||
# Build KiCad on Windows and save the results
|
||||
##########################################################################
|
||||
win64_build:
|
||||
stage: build
|
||||
tags:
|
||||
- kicad-windows-ltsc2022
|
||||
interruptible: false
|
||||
image: registry.gitlab.com/kicad/kicad-ci/windows-build-image/ltsc2022-msvc:latest
|
||||
variables:
|
||||
# Switch the compressor to fastzip and reduce the compression level
|
||||
FF_USE_FASTZIP: "true"
|
||||
CACHE_COMPRESSION_LEVEL: "fast"
|
||||
cache:
|
||||
key: win64-vcpkg-$CI_COMMIT_REF_SLUG
|
||||
paths:
|
||||
- build\windows\vcpkg_installed
|
||||
- .vcpkgCache
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
when: never
|
||||
- if: $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
script:
|
||||
- C:\builder\build.ps1 -Env -Arch x64
|
||||
- $vcpkgCache=Join-Path -Path (Get-Location) -ChildPath ".vcpkgCache";$env:VCPKG_DEFAULT_BINARY_CACHE=$vcpkgCache;New-Item -ItemType Directory -Force -Path $vcpkgCache
|
||||
- mkdir -p build/windows -Force
|
||||
- cd build/windows
|
||||
- cmake `
|
||||
-G "Ninja" `
|
||||
-DCMAKE_TOOLCHAIN_FILE=C:\builder\vcpkg\scripts\buildsystems\vcpkg.cmake `
|
||||
-DCMAKE_BUILD_TYPE=Debug `
|
||||
-DKICAD_SCRIPTING_WXPYTHON=OFF `
|
||||
-DKICAD_USE_OCC=ON `
|
||||
-DKICAD_BUILD_PNS_DEBUG_TOOL=ON `
|
||||
-DKICAD_USE_3DCONNEXION=ON `
|
||||
-DVCPKG_BUILD_TYPE=debug `
|
||||
../../
|
||||
- cmake --build . 2>&1 | tee compilation_log.txt
|
||||
- cd ../../
|
||||
artifacts:
|
||||
# Only save the artifacts that are needed for running the tests in the next stage
|
||||
# and the compilation log. The entire build directory is too large to save as an
|
||||
# artifact.
|
||||
expire_in: 2 hrs
|
||||
when: always
|
||||
paths:
|
||||
- build/windows/compilation_log.txt
|
||||
@@ -1,76 +0,0 @@
|
||||
# This script is responsible for configuring the coverity file from the cache
|
||||
# (e.g. extracting it or updating it if needed)
|
||||
.coverity_cache_prep: &coverity_cache_prep |
|
||||
echo "Downloading MD5 hash of current Coverity Scan version to compare against cache"
|
||||
curl --output cov-analysis-linux64.md5 https://scan.coverity.com/download/linux64 \
|
||||
--form project=$COVERITY_SCAN_PROJECT_NAME \
|
||||
--form token=$COVERITY_SCAN_TOKEN \
|
||||
--form md5=1
|
||||
echo " *cov-analysis-linux64.tgz" >> cov-analysis-linux64.md5
|
||||
(md5sum --ignore-missing -c cov-analysis-linux64.md5) || (
|
||||
echo "Downloading new Coverity Scan version"
|
||||
curl --output cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64 \
|
||||
--form project=$COVERITY_SCAN_PROJECT_NAME \
|
||||
--form token=$COVERITY_SCAN_TOKEN
|
||||
)
|
||||
echo "Extracting Coverity Scan"
|
||||
mkdir coverity/
|
||||
tar xzf cov-analysis-linux64.tgz --strip-components=1 -C coverity
|
||||
test -d coverity/bin
|
||||
|
||||
# This script is responsible for tar'ing and submitting the results of the build.
|
||||
# These results will be saved for 1 day if the build fails.
|
||||
.coverity_submit: &coverity_submit |
|
||||
echo "Creating tar file of scan results"
|
||||
export COV_INT_FILENAME=cov-int-$(date +"%Y%m%d%H%M").tar.gz
|
||||
tar cfz $COV_INT_FILENAME cov-int
|
||||
echo "Submitting scan results"
|
||||
s5cmd/s5cmd cp $COV_INT_FILENAME s3://$KICAD_CI_R2_BUCKET/coverity/
|
||||
export FILE_URL="$KICAD_CI_R2_PUBLIC_BASE/coverity/$COV_INT_FILENAME"
|
||||
export KICAD_VERSION=$(sed 's/[()]//g' kicad_build_version.txt)
|
||||
curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME \
|
||||
--form token=$COVERITY_SCAN_TOKEN \
|
||||
--form email=$GITLAB_USER_EMAIL \
|
||||
--form url="$FILE_URL" \
|
||||
--form version="$KICAD_VERSION" \
|
||||
--form description="$KICAD_VERSION / $CI_COMMIT_TITLE" 2>&1 \
|
||||
| tee curl-response.txt
|
||||
grep -q 'Build successfully submitted' curl-response.txt
|
||||
|
||||
|
||||
Coverity:
|
||||
tags:
|
||||
- coverity
|
||||
stage: build
|
||||
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:40
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULED_JOB_NAME == "coverity"
|
||||
cache:
|
||||
key: coverity
|
||||
paths:
|
||||
- cov-analysis-linux64.tgz
|
||||
before_script:
|
||||
- export COVERITY_SCAN_PROJECT_NAME="kicad"
|
||||
- test "$(git rev-parse --is-shallow-repository)" = "false" || (git fetch --unshallow)
|
||||
- git fetch origin
|
||||
- curl -LO https://github.com/peak/s5cmd/releases/download/v2.0.0/s5cmd_2.0.0_Linux-64bit.tar.gz
|
||||
- mkdir s5cmd
|
||||
- tar -xvf ./s5cmd_2.0.0_Linux-64bit.tar.gz -C s5cmd
|
||||
- export AWS_ACCESS_KEY_ID=$KICAD_CI_R2_KEY_ID
|
||||
- export AWS_SECRET_ACCESS_KEY=$KICAD_CI_R2_ACCESS_KEY
|
||||
- export S3_ENDPOINT_URL=$KICAD_CI_R2_ENDPOINT
|
||||
script:
|
||||
- *coverity_cache_prep
|
||||
- cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DKICAD_STDLIB_LIGHT_DEBUG=ON
|
||||
-DKICAD_SCRIPTING_WXPYTHON=ON
|
||||
-DKICAD_USE_CMAKE_FINDPROTOBUF=ON
|
||||
- coverity/bin/cov-build --dir cov-int make -j10
|
||||
- *coverity_submit
|
||||
artifacts:
|
||||
expire_in: 1 year
|
||||
expose_as: 'Coverity log'
|
||||
name: "coverity_log.txt"
|
||||
paths:
|
||||
- cov-int/build-log.txt
|
||||
@@ -1,15 +0,0 @@
|
||||
build_doxygen_docker:
|
||||
image: docker:stable
|
||||
services:
|
||||
- docker:dind
|
||||
stage: build
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULED_JOB_NAME == "doxygen"
|
||||
tags:
|
||||
- gitlab-org-docker
|
||||
before_script:
|
||||
- docker info
|
||||
- docker login -u gitlab-ci-token -p "$CI_JOB_TOKEN" "$CI_REGISTRY"
|
||||
script:
|
||||
- docker build -t "${CI_REGISTRY_IMAGE}/doxygen:$CI_COMMIT_BRANCH" -f ./doxygen/doxygen.Dockerfile .
|
||||
- docker push "${CI_REGISTRY_IMAGE}/doxygen:$CI_COMMIT_BRANCH"
|
||||
@@ -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
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
##########################################################################
|
||||
# Run a validation of the metadata files for Linux
|
||||
##########################################################################
|
||||
validate_linux_metadata:
|
||||
stage: test
|
||||
needs: []
|
||||
interruptible: false
|
||||
image: $DEFAULT_FEDORA_IMAGE
|
||||
# Due to bug https://github.com/hughsie/appstream-glib/issues/381, this doesn't think our description tag
|
||||
# is localized even though it actually is.
|
||||
allow_failure: true
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
when: never
|
||||
- if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- resources/linux/**/*
|
||||
- qa/resources/linux/**/*
|
||||
- translation/**/*
|
||||
# Only build the metadata files in this CI job
|
||||
script:
|
||||
- mkdir -p build/linux
|
||||
- cd build/linux
|
||||
- cmake
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
-DKICAD_STDLIB_LIGHT_DEBUG=ON
|
||||
-DKICAD_SCRIPTING_WXPYTHON=ON
|
||||
-DKICAD_BUILD_I18N=ON
|
||||
../../
|
||||
- make metadata
|
||||
- cd ../../
|
||||
- ./qa/resources/linux/verifyMetadataFiles.sh ./ ./build/linux
|
||||
@@ -1,29 +0,0 @@
|
||||
##########################################################################
|
||||
# Build KiCad on Windows and save the results
|
||||
##########################################################################
|
||||
macos_build:
|
||||
stage: build
|
||||
tags:
|
||||
- kicad-macos
|
||||
interruptible: false
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
when: never
|
||||
- if: $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
script:
|
||||
- mkdir -p build/macos
|
||||
- cd build/macos
|
||||
- cmake
|
||||
-G Ninja
|
||||
-DCMAKE_TOOLCHAIN_FILE=/Users/$USER/kicad-mac-builder/toolchain/kicad-mac-builder.cmake
|
||||
../../
|
||||
- cmake --build . 2>&1 | tee compilation_log.txt
|
||||
- cd ../../
|
||||
artifacts:
|
||||
# Only save the artifacts that are needed for running the tests in the next stage
|
||||
# and the compilation log. The entire build directory is too large to save as an
|
||||
# artifact.
|
||||
expire_in: 2 hrs
|
||||
when: always
|
||||
paths:
|
||||
- build/macos/compilation_log.txt
|
||||
@@ -1,27 +0,0 @@
|
||||
##########################################################################
|
||||
# Test the formatting in a merge request using clang-format
|
||||
##########################################################################
|
||||
# The variable CI_COMMIT_BEFORE_SHA is not available in normal merge requests
|
||||
# so we must build the commit hash ourselves, see:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/12850
|
||||
test_formatting:
|
||||
stage: test
|
||||
needs: []
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
allow_failure: true
|
||||
before_script:
|
||||
# We must manually add the KiCad remote to ensure it is named sensibly
|
||||
- git remote add product https://gitlab.com/kicad/code/kicad.git ||
|
||||
git remote set-url product https://gitlab.com/kicad/code/kicad.git
|
||||
- git remote add source ${CI_MERGE_REQUEST_SOURCE_PROJECT_URL}.git ||
|
||||
git remote set-url source ${CI_MERGE_REQUEST_SOURCE_PROJECT_URL}.git
|
||||
- git fetch -n product
|
||||
- git fetch -n source
|
||||
# Get the SHAs of the commits
|
||||
- "TARGET_HEAD_SHA=$(git rev-parse product/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME})"
|
||||
- "SOURCE_HEAD_SHA=$(git rev-parse source/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME})"
|
||||
- "MERGE_BASE_SHA=$(git merge-base ${TARGET_HEAD_SHA} ${SOURCE_HEAD_SHA})"
|
||||
script:
|
||||
- echo "Testing formatting from commit ${MERGE_BASE_SHA}"
|
||||
- ./tools/check_coding.sh --diff --ci --commit ${MERGE_BASE_SHA}
|
||||
@@ -1,37 +0,0 @@
|
||||
##########################################################################
|
||||
# This will allow the job to run whenever code events trigger it.
|
||||
##########################################################################
|
||||
.only_code:
|
||||
only:
|
||||
- master
|
||||
- branches
|
||||
- merge_requests
|
||||
- pushes
|
||||
except:
|
||||
- schedules
|
||||
|
||||
##########################################################################
|
||||
# Define a template for all the unit tests, since each one is run in a separate
|
||||
# job to make the display nicer.
|
||||
##########################################################################
|
||||
.unit_test:
|
||||
stage: test
|
||||
when: on_success
|
||||
variables:
|
||||
BOOST_TEST_LOGGER: 'JUNIT,warning,test_results.${TEST}.xml:HRF,message'
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
script:
|
||||
- cd build/linux/qa
|
||||
- ctest -R qa_${TEST}
|
||||
# GitLab supports displaying the results in the GUI through JUNIT artifacts
|
||||
# (https://docs.gitlab.com/ee/ci/junit_test_reports.html)
|
||||
# so we upload the JUNIT results.
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- build/linux/qa/**/*.log
|
||||
- build/linux/qa/**/output/*
|
||||
- build/linux/qa/**/*.xml
|
||||
reports:
|
||||
junit:
|
||||
- build/linux/qa/**/*.xml
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_aux.cpp
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
|
||||
#include <common.h>
|
||||
#include <trigo.h>
|
||||
#include <wxBasePcbFrame.h>
|
||||
|
||||
#include <class_board_design_settings.h>
|
||||
#include <class_zone.h>
|
||||
#include <class_text_mod.h>
|
||||
#include <class_module.h>
|
||||
#include <class_drawsegment.h>
|
||||
#include <class_pcb_text.h>
|
||||
|
||||
#include <3d_viewer.h>
|
||||
#include <3d_canvas.h>
|
||||
#include <info3d_visu.h>
|
||||
#include <trackball.h>
|
||||
|
||||
|
||||
void S3D_MASTER::ObjectCoordsTo3DUnits( std::vector< S3D_VERTEX >& aVertices )
|
||||
{
|
||||
/* adjust object scale, rotation and offset position */
|
||||
for( unsigned ii = 0; ii < aVertices.size(); ii++ )
|
||||
{
|
||||
aVertices[ii].x *= m_MatScale.x;
|
||||
aVertices[ii].y *= m_MatScale.y;
|
||||
aVertices[ii].z *= m_MatScale.z;
|
||||
|
||||
// adjust rotation
|
||||
if( m_MatRotation.x )
|
||||
{
|
||||
double a = aVertices[ii].y;
|
||||
double b = aVertices[ii].z;
|
||||
RotatePoint( &a, &b, m_MatRotation.x * 10 );
|
||||
aVertices[ii].y = (float)a;
|
||||
aVertices[ii].z = (float)b;
|
||||
}
|
||||
|
||||
if( m_MatRotation.y )
|
||||
{
|
||||
double a = aVertices[ii].z;
|
||||
double b = aVertices[ii].x;
|
||||
RotatePoint( &a, &b, m_MatRotation.x * 10 );
|
||||
aVertices[ii].z = (float)a;
|
||||
aVertices[ii].x = (float)b;
|
||||
}
|
||||
|
||||
if( m_MatRotation.z )
|
||||
{
|
||||
double a = aVertices[ii].x;
|
||||
double b = aVertices[ii].y;
|
||||
RotatePoint( &a, &b, m_MatRotation.x * 10 );
|
||||
aVertices[ii].x = (float)a;
|
||||
aVertices[ii].y = (float)b;
|
||||
}
|
||||
|
||||
/* adjust offset position (offset is given in UNIT 3D (0.1 inch) */
|
||||
aVertices[ii].x += m_MatPosition.x * SCALE_3D_CONV;
|
||||
aVertices[ii].y += m_MatPosition.y * SCALE_3D_CONV;
|
||||
aVertices[ii].z += m_MatPosition.z * SCALE_3D_CONV;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits )
|
||||
{
|
||||
unsigned ii;
|
||||
GLfloat ax, ay, az, bx, by, bz, nx, ny, nz, r;
|
||||
|
||||
/* ignore faces with less than 3 points */
|
||||
if( aVertices.size() < 3 )
|
||||
return;
|
||||
|
||||
/* calculate normal direction */
|
||||
ax = aVertices[1].x - aVertices[0].x;
|
||||
ay = aVertices[1].y - aVertices[0].y;
|
||||
az = aVertices[1].z - aVertices[0].z;
|
||||
|
||||
bx = aVertices[2].x - aVertices[0].x;
|
||||
by = aVertices[2].y - aVertices[0].y;
|
||||
bz = aVertices[2].z - aVertices[0].z;
|
||||
|
||||
nx = ay * bz - az * by;
|
||||
ny = az * bx - ax * bz;
|
||||
nz = ax * by - ay * bx;
|
||||
|
||||
r = sqrt( nx * nx + ny * ny + nz * nz );
|
||||
|
||||
if( r >= 0.000001 ) /* avoid division by zero */
|
||||
{
|
||||
nx /= r;
|
||||
ny /= r;
|
||||
nz /= r;
|
||||
glNormal3f( nx, ny, nz );
|
||||
}
|
||||
|
||||
/* glBegin/glEnd */
|
||||
switch( aVertices.size() )
|
||||
{
|
||||
case 3:
|
||||
glBegin( GL_TRIANGLES );
|
||||
break;
|
||||
|
||||
case 4:
|
||||
glBegin( GL_QUADS );
|
||||
break;
|
||||
|
||||
default:
|
||||
glBegin( GL_POLYGON );
|
||||
break;
|
||||
}
|
||||
|
||||
/* draw polygon/triangle/quad */
|
||||
for( ii = 0; ii < aVertices.size(); ii++ )
|
||||
{
|
||||
glVertex3d( aVertices[ii].x * aBiuTo3DUnits,
|
||||
aVertices[ii].y * aBiuTo3DUnits,
|
||||
aVertices[ii].z * aBiuTo3DUnits );
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
S3DPOINT_VALUE_CTRL::S3DPOINT_VALUE_CTRL( wxWindow* aParent, wxBoxSizer* aBoxSizer )
|
||||
{
|
||||
wxString text;
|
||||
|
||||
wxFlexGridSizer* gridSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
|
||||
gridSizer->AddGrowableCol( 1 );
|
||||
gridSizer->SetFlexibleDirection( wxHORIZONTAL );
|
||||
gridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
|
||||
aBoxSizer->Add( gridSizer, 0, wxEXPAND, 5 );
|
||||
|
||||
wxStaticText* msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "X:" ) );
|
||||
gridSizer->Add( msgtitle, 0, wxALL , 5 );
|
||||
|
||||
m_XValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
|
||||
wxDefaultPosition,wxDefaultSize, 0 );
|
||||
gridSizer->Add( m_XValueCtrl, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "Y:" ), wxDefaultPosition,
|
||||
wxDefaultSize, 0 );
|
||||
gridSizer->Add( msgtitle, 0, wxALL, 5 );
|
||||
|
||||
m_YValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
|
||||
wxDefaultPosition, wxDefaultSize, 0 );
|
||||
gridSizer->Add( m_YValueCtrl, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "Z:" ), wxDefaultPosition,
|
||||
wxDefaultSize, 0 );
|
||||
gridSizer->Add( msgtitle, 0, wxALL, 5 );
|
||||
|
||||
m_ZValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
|
||||
wxDefaultPosition, wxDefaultSize, 0 );
|
||||
gridSizer->Add( m_ZValueCtrl, 0, wxALL|wxEXPAND, 5 );
|
||||
}
|
||||
|
||||
|
||||
S3DPOINT_VALUE_CTRL::~S3DPOINT_VALUE_CTRL()
|
||||
{
|
||||
// Nothing to delete: all items are managed by the parent window.
|
||||
}
|
||||
|
||||
|
||||
S3DPOINT S3DPOINT_VALUE_CTRL::GetValue()
|
||||
{
|
||||
S3DPOINT value;
|
||||
double dtmp;
|
||||
|
||||
m_XValueCtrl->GetValue().ToDouble( &dtmp );
|
||||
value.x = dtmp;
|
||||
m_YValueCtrl->GetValue().ToDouble( &dtmp );
|
||||
value.y = dtmp;
|
||||
m_ZValueCtrl->GetValue().ToDouble( &dtmp );
|
||||
value.z = dtmp;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
void S3DPOINT_VALUE_CTRL::SetValue( S3DPOINT vertex )
|
||||
{
|
||||
wxString text;
|
||||
|
||||
text.Printf( wxT( "%f" ), vertex.x );
|
||||
m_XValueCtrl->Clear();
|
||||
m_XValueCtrl->AppendText( text );
|
||||
|
||||
text.Printf( wxT( "%f" ), vertex.y );
|
||||
m_YValueCtrl->Clear();
|
||||
m_YValueCtrl->AppendText( text );
|
||||
|
||||
text.Printf( wxT( "%f" ), vertex.z );
|
||||
m_ZValueCtrl->Clear();
|
||||
m_ZValueCtrl->AppendText( text );
|
||||
}
|
||||
|
||||
|
||||
void S3DPOINT_VALUE_CTRL::Enable( bool onoff )
|
||||
{
|
||||
m_XValueCtrl->Enable( onoff );
|
||||
m_YValueCtrl->Enable( onoff );
|
||||
m_ZValueCtrl->Enable( onoff );
|
||||
}
|
||||
@@ -1,616 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2022 CERN
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
#include <wx/datetime.h>
|
||||
#include <wx/dir.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/stdpaths.h>
|
||||
|
||||
#include "3d_cache.h"
|
||||
#include "3d_info.h"
|
||||
#include "3d_plugin_manager.h"
|
||||
#include "sg/scenegraph.h"
|
||||
#include "plugins/3dapi/ifsg_api.h"
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <common.h> // For ExpandEnvVarSubstitutions
|
||||
#include <filename_resolver.h>
|
||||
#include <mmh3_hash.h>
|
||||
#include <paths.h>
|
||||
#include <pgm_base.h>
|
||||
#include <project.h>
|
||||
#include <settings/common_settings.h>
|
||||
#include <settings/settings_manager.h>
|
||||
#include <wx_filename.h>
|
||||
|
||||
|
||||
#define MASK_3D_CACHE "3D_CACHE"
|
||||
|
||||
static std::mutex mutex3D_cache;
|
||||
|
||||
|
||||
static bool checkTag( const char* aTag, void* aPluginMgrPtr )
|
||||
{
|
||||
if( nullptr == aTag || nullptr == aPluginMgrPtr )
|
||||
return false;
|
||||
|
||||
S3D_PLUGIN_MANAGER *pp = (S3D_PLUGIN_MANAGER*) aPluginMgrPtr;
|
||||
|
||||
return pp->CheckTag( aTag );
|
||||
}
|
||||
|
||||
|
||||
class S3D_CACHE_ENTRY
|
||||
{
|
||||
public:
|
||||
S3D_CACHE_ENTRY();
|
||||
~S3D_CACHE_ENTRY();
|
||||
|
||||
void SetHash( const HASH_128& aHash );
|
||||
const wxString GetCacheBaseName();
|
||||
|
||||
wxDateTime modTime; // file modification time
|
||||
HASH_128 m_hash;
|
||||
std::string pluginInfo; // PluginName:Version string
|
||||
SCENEGRAPH* sceneData;
|
||||
S3DMODEL* renderData;
|
||||
|
||||
private:
|
||||
// prohibit assignment and default copy constructor
|
||||
S3D_CACHE_ENTRY( const S3D_CACHE_ENTRY& source );
|
||||
S3D_CACHE_ENTRY& operator=( const S3D_CACHE_ENTRY& source );
|
||||
|
||||
wxString m_CacheBaseName; // base name of cache file
|
||||
};
|
||||
|
||||
|
||||
S3D_CACHE_ENTRY::S3D_CACHE_ENTRY()
|
||||
{
|
||||
sceneData = nullptr;
|
||||
renderData = nullptr;
|
||||
m_hash.Clear();
|
||||
}
|
||||
|
||||
|
||||
S3D_CACHE_ENTRY::~S3D_CACHE_ENTRY()
|
||||
{
|
||||
delete sceneData;
|
||||
|
||||
if( nullptr != renderData )
|
||||
S3D::Destroy3DModel( &renderData );
|
||||
}
|
||||
|
||||
|
||||
void S3D_CACHE_ENTRY::SetHash( const HASH_128& aHash )
|
||||
{
|
||||
m_hash = aHash;
|
||||
}
|
||||
|
||||
|
||||
const wxString S3D_CACHE_ENTRY::GetCacheBaseName()
|
||||
{
|
||||
if( m_CacheBaseName.empty() )
|
||||
m_CacheBaseName = m_hash.ToString();
|
||||
|
||||
return m_CacheBaseName;
|
||||
}
|
||||
|
||||
|
||||
S3D_CACHE::S3D_CACHE()
|
||||
{
|
||||
m_FNResolver = new FILENAME_RESOLVER;
|
||||
m_project = nullptr;
|
||||
m_Plugins = new S3D_PLUGIN_MANAGER;
|
||||
}
|
||||
|
||||
|
||||
S3D_CACHE::~S3D_CACHE()
|
||||
{
|
||||
FlushCache();
|
||||
|
||||
delete m_FNResolver;
|
||||
delete m_Plugins;
|
||||
}
|
||||
|
||||
|
||||
SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, const wxString& aBasePath,
|
||||
S3D_CACHE_ENTRY** aCachePtr, const EMBEDDED_FILES* aEmbeddedFiles )
|
||||
{
|
||||
if( aCachePtr )
|
||||
*aCachePtr = nullptr;
|
||||
|
||||
wxString full3Dpath = m_FNResolver->ResolvePath( aModelFile, aBasePath, aEmbeddedFiles );
|
||||
|
||||
if( full3Dpath.empty() )
|
||||
{
|
||||
// the model cannot be found; we cannot proceed
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * [3D model] could not find model '%s'\n" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aModelFile );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// check cache if file is already loaded
|
||||
std::lock_guard<std::mutex> lock( mutex3D_cache );
|
||||
|
||||
std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString >::iterator mi;
|
||||
mi = m_CacheMap.find( full3Dpath );
|
||||
|
||||
if( mi != m_CacheMap.end() )
|
||||
{
|
||||
wxFileName fname( full3Dpath );
|
||||
|
||||
if( fname.FileExists() ) // Only check if file exists. If not, it will
|
||||
{ // use the same model in cache.
|
||||
bool reload = ADVANCED_CFG::GetCfg().m_Skip3DModelMemoryCache;
|
||||
wxDateTime fmdate = fname.GetModificationTime();
|
||||
|
||||
if( fmdate != mi->second->modTime )
|
||||
{
|
||||
HASH_128 hashSum;
|
||||
getHash( full3Dpath, hashSum );
|
||||
mi->second->modTime = fmdate;
|
||||
|
||||
if( hashSum != mi->second->m_hash )
|
||||
{
|
||||
mi->second->SetHash( hashSum );
|
||||
reload = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( reload )
|
||||
{
|
||||
if( nullptr != mi->second->sceneData )
|
||||
{
|
||||
S3D::DestroyNode( mi->second->sceneData );
|
||||
mi->second->sceneData = nullptr;
|
||||
}
|
||||
|
||||
if( nullptr != mi->second->renderData )
|
||||
S3D::Destroy3DModel( &mi->second->renderData );
|
||||
|
||||
mi->second->sceneData = m_Plugins->Load3DModel( full3Dpath,
|
||||
mi->second->pluginInfo );
|
||||
}
|
||||
}
|
||||
|
||||
if( nullptr != aCachePtr )
|
||||
*aCachePtr = mi->second;
|
||||
|
||||
return mi->second->sceneData;
|
||||
}
|
||||
|
||||
// a cache item does not exist; search the Filename->Cachename map
|
||||
return checkCache( full3Dpath, aCachePtr );
|
||||
}
|
||||
|
||||
|
||||
SCENEGRAPH* S3D_CACHE::Load( const wxString& aModelFile, const wxString& aBasePath,
|
||||
const EMBEDDED_FILES* aEmbeddedFiles )
|
||||
{
|
||||
return load( aModelFile, aBasePath, nullptr, aEmbeddedFiles );
|
||||
}
|
||||
|
||||
|
||||
SCENEGRAPH* S3D_CACHE::checkCache( const wxString& aFileName, S3D_CACHE_ENTRY** aCachePtr )
|
||||
{
|
||||
if( aCachePtr )
|
||||
*aCachePtr = nullptr;
|
||||
|
||||
HASH_128 hashSum;
|
||||
S3D_CACHE_ENTRY* ep = new S3D_CACHE_ENTRY;
|
||||
m_CacheList.push_back( ep );
|
||||
wxFileName fname( aFileName );
|
||||
ep->modTime = fname.GetModificationTime();
|
||||
|
||||
if( !getHash( aFileName, hashSum ) || m_CacheDir.empty() )
|
||||
{
|
||||
// just in case we can't get a hash digest (for example, on access issues)
|
||||
// or we do not have a configured cache file directory, we create an
|
||||
// entry to prevent further attempts at loading the file
|
||||
|
||||
if( m_CacheMap.emplace( aFileName, ep ).second == false )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
m_CacheList.pop_back();
|
||||
delete ep;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aCachePtr )
|
||||
*aCachePtr = ep;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( m_CacheMap.emplace( aFileName, ep ).second == false )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
m_CacheList.pop_back();
|
||||
delete ep;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( aCachePtr )
|
||||
*aCachePtr = ep;
|
||||
|
||||
ep->SetHash( hashSum );
|
||||
|
||||
wxString bname = ep->GetCacheBaseName();
|
||||
wxString cachename = m_CacheDir + bname + wxT( ".3dc" );
|
||||
|
||||
if( !ADVANCED_CFG::GetCfg().m_Skip3DModelFileCache && wxFileName::FileExists( cachename )
|
||||
&& loadCacheData( ep ) )
|
||||
return ep->sceneData;
|
||||
|
||||
ep->sceneData = m_Plugins->Load3DModel( aFileName, ep->pluginInfo );
|
||||
|
||||
if( !ADVANCED_CFG::GetCfg().m_Skip3DModelFileCache && nullptr != ep->sceneData )
|
||||
saveCacheData( ep );
|
||||
|
||||
return ep->sceneData;
|
||||
}
|
||||
|
||||
|
||||
bool S3D_CACHE::getHash( const wxString& aFileName, HASH_128& aHash )
|
||||
{
|
||||
if( aFileName.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * [BUG] empty filename" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
FILE* fp = _wfopen( aFileName.wc_str(), L"rb" );
|
||||
#else
|
||||
FILE* fp = fopen( aFileName.ToUTF8(), "rb" );
|
||||
#endif
|
||||
|
||||
if( nullptr == fp )
|
||||
return false;
|
||||
|
||||
MMH3_HASH dblock( 0xA1B2C3D4 );
|
||||
std::vector<char> block( 4096 );
|
||||
size_t bsize = 0;
|
||||
|
||||
while( ( bsize = fread( block.data(), 1, 4096, fp ) ) > 0 )
|
||||
dblock.add( block );
|
||||
|
||||
fclose( fp );
|
||||
aHash = dblock.digest();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D_CACHE::loadCacheData( S3D_CACHE_ENTRY* aCacheItem )
|
||||
{
|
||||
wxString bname = aCacheItem->GetCacheBaseName();
|
||||
|
||||
if( bname.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( " * [3D model] cannot load cached model; no file hash available" ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_CacheDir.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( " * [3D model] cannot load cached model; config directory unknown" ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString fname = m_CacheDir + bname + wxT( ".3dc" );
|
||||
|
||||
if( !wxFileName::FileExists( fname ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( " * [3D model] cannot open file '%s'" ), fname.GetData() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( nullptr != aCacheItem->sceneData )
|
||||
S3D::DestroyNode( (SGNODE*) aCacheItem->sceneData );
|
||||
|
||||
aCacheItem->sceneData = (SCENEGRAPH*)S3D::ReadCache( fname.ToUTF8(), m_Plugins, checkTag );
|
||||
|
||||
if( nullptr == aCacheItem->sceneData )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D_CACHE::saveCacheData( S3D_CACHE_ENTRY* aCacheItem )
|
||||
{
|
||||
if( nullptr == aCacheItem )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * NULL passed for aCacheItem" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( nullptr == aCacheItem->sceneData )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * aCacheItem has no valid scene data" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString bname = aCacheItem->GetCacheBaseName();
|
||||
|
||||
if( bname.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( " * [3D model] cannot load cached model; no file hash available" ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_CacheDir.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( " * [3D model] cannot load cached model; config directory unknown" ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString fname = m_CacheDir + bname + wxT( ".3dc" );
|
||||
|
||||
if( wxFileName::Exists( fname ) )
|
||||
{
|
||||
if( !wxFileName::FileExists( fname ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( " * [3D model] path exists but is not a regular file '%s'" ), fname );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return S3D::WriteCache( fname.ToUTF8(), true, (SGNODE*)aCacheItem->sceneData,
|
||||
aCacheItem->pluginInfo.c_str() );
|
||||
}
|
||||
|
||||
|
||||
bool S3D_CACHE::Set3DConfigDir( const wxString& aConfigDir )
|
||||
{
|
||||
if( !m_ConfigDir.empty() )
|
||||
return false;
|
||||
|
||||
wxFileName cfgdir( ExpandEnvVarSubstitutions( aConfigDir, m_project ), wxEmptyString );
|
||||
|
||||
cfgdir.Normalize( FN_NORMALIZE_FLAGS );
|
||||
|
||||
if( !cfgdir.DirExists() )
|
||||
{
|
||||
cfgdir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
|
||||
|
||||
if( !cfgdir.DirExists() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * failed to create 3D configuration directory '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, cfgdir.GetPath() );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_ConfigDir = cfgdir.GetPath();
|
||||
|
||||
// inform the file resolver of the config directory
|
||||
if( !m_FNResolver->Set3DConfigDir( m_ConfigDir ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * could not set 3D Config Directory on filename resolver\n"
|
||||
" * config directory: '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, m_ConfigDir );
|
||||
}
|
||||
|
||||
// 3D cache data must go to a user's cache directory;
|
||||
// unfortunately wxWidgets doesn't seem to provide
|
||||
// functions to retrieve such a directory.
|
||||
//
|
||||
// 1. OSX: ~/Library/Caches/kicad/3d/
|
||||
// 2. Linux: ${XDG_CACHE_HOME}/kicad/3d ~/.cache/kicad/3d/
|
||||
// 3. MSWin: AppData\Local\kicad\3d
|
||||
wxFileName cacheDir;
|
||||
cacheDir.AssignDir( PATHS::GetUserCachePath() );
|
||||
cacheDir.AppendDir( wxT( "3d" ) );
|
||||
|
||||
if( !cacheDir.DirExists() )
|
||||
{
|
||||
cacheDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
|
||||
|
||||
if( !cacheDir.DirExists() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * failed to create 3D cache directory '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, cacheDir.GetPath() );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_CacheDir = cacheDir.GetPathWithSep();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D_CACHE::SetProject( PROJECT* aProject )
|
||||
{
|
||||
m_project = aProject;
|
||||
|
||||
bool hasChanged = false;
|
||||
|
||||
if( m_FNResolver->SetProject( aProject, &hasChanged ) && hasChanged )
|
||||
{
|
||||
m_CacheMap.clear();
|
||||
|
||||
std::list< S3D_CACHE_ENTRY* >::iterator sL = m_CacheList.begin();
|
||||
std::list< S3D_CACHE_ENTRY* >::iterator eL = m_CacheList.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
delete *sL;
|
||||
++sL;
|
||||
}
|
||||
|
||||
m_CacheList.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void S3D_CACHE::SetProgramBase( PGM_BASE* aBase )
|
||||
{
|
||||
m_FNResolver->SetProgramBase( aBase );
|
||||
}
|
||||
|
||||
|
||||
FILENAME_RESOLVER* S3D_CACHE::GetResolver() noexcept
|
||||
{
|
||||
return m_FNResolver;
|
||||
}
|
||||
|
||||
|
||||
std::list< wxString > const* S3D_CACHE::GetFileFilters() const
|
||||
{
|
||||
return m_Plugins->GetFileFilters();
|
||||
}
|
||||
|
||||
|
||||
void S3D_CACHE::FlushCache( bool closePlugins )
|
||||
{
|
||||
std::list< S3D_CACHE_ENTRY* >::iterator sCL = m_CacheList.begin();
|
||||
std::list< S3D_CACHE_ENTRY* >::iterator eCL = m_CacheList.end();
|
||||
|
||||
while( sCL != eCL )
|
||||
{
|
||||
delete *sCL;
|
||||
++sCL;
|
||||
}
|
||||
|
||||
m_CacheList.clear();
|
||||
m_CacheMap.clear();
|
||||
|
||||
if( closePlugins )
|
||||
ClosePlugins();
|
||||
}
|
||||
|
||||
|
||||
void S3D_CACHE::ClosePlugins()
|
||||
{
|
||||
if( m_Plugins )
|
||||
m_Plugins->ClosePlugins();
|
||||
}
|
||||
|
||||
|
||||
S3DMODEL* S3D_CACHE::GetModel( const wxString& aModelFileName, const wxString& aBasePath,
|
||||
const EMBEDDED_FILES* aEmbeddedFiles )
|
||||
{
|
||||
S3D_CACHE_ENTRY* cp = nullptr;
|
||||
SCENEGRAPH* sp = load( aModelFileName, aBasePath, &cp, aEmbeddedFiles );
|
||||
|
||||
if( !sp )
|
||||
return nullptr;
|
||||
|
||||
if( !cp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * [BUG] model loaded with no associated S3D_CACHE_ENTRY" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( cp->renderData )
|
||||
return cp->renderData;
|
||||
|
||||
S3DMODEL* mp = S3D::GetModel( sp );
|
||||
cp->renderData = mp;
|
||||
|
||||
return mp;
|
||||
}
|
||||
|
||||
void S3D_CACHE::CleanCacheDir( int aNumDaysOld )
|
||||
{
|
||||
wxDir dir;
|
||||
wxString fileSpec = wxT( "*.3dc" );
|
||||
wxArrayString fileList; // Holds list of ".3dc" files found in cache directory
|
||||
size_t numFilesFound = 0;
|
||||
|
||||
wxFileName thisFile;
|
||||
wxDateTime lastAccess, thresholdDate;
|
||||
wxDateSpan durationInDays;
|
||||
|
||||
// Calc the threshold date above which we delete cache files
|
||||
durationInDays.SetDays( aNumDaysOld );
|
||||
thresholdDate = wxDateTime::Now() - durationInDays;
|
||||
|
||||
// If the cache directory can be found and opened, then we'll try and clean it up
|
||||
if( dir.Open( m_CacheDir ) )
|
||||
{
|
||||
thisFile.SetPath( m_CacheDir ); // Set the base path to the cache folder
|
||||
|
||||
// Get a list of all the ".3dc" files in the cache directory
|
||||
numFilesFound = dir.GetAllFiles( m_CacheDir, &fileList, fileSpec );
|
||||
|
||||
for( unsigned int i = 0; i < numFilesFound; i++ )
|
||||
{
|
||||
// Completes path to specific file so we can get its "last access" date
|
||||
thisFile.SetFullName( fileList[i] );
|
||||
|
||||
// Only get "last access" time to compare against. Don't need the other 2 timestamps.
|
||||
if( thisFile.GetTimes( &lastAccess, nullptr, nullptr ) )
|
||||
{
|
||||
if( lastAccess.IsEarlierThan( thresholdDate ) )
|
||||
{
|
||||
// This file is older than the threshold so delete it
|
||||
wxRemoveFile( thisFile.GetFullPath() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_cache.h
|
||||
*/
|
||||
|
||||
#ifndef CACHE_3D_H
|
||||
#define CACHE_3D_H
|
||||
|
||||
#include "3d_info.h"
|
||||
#include <core/typeinfo.h>
|
||||
#include "string_utils.h"
|
||||
#include <hash_128.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include "plugins/3dapi/c3dmodel.h"
|
||||
#include <project.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
class EMBEDDED_FILES;
|
||||
class PGM_BASE;
|
||||
class S3D_CACHE_ENTRY;
|
||||
class SCENEGRAPH;
|
||||
class FILENAME_RESOLVER;
|
||||
class S3D_PLUGIN_MANAGER;
|
||||
|
||||
|
||||
/**
|
||||
* Cache for storing the 3D shapes. This cache is able to be stored as a project
|
||||
* element (since it inherits from PROJECT::_ELEM).
|
||||
*/
|
||||
class S3D_CACHE : public PROJECT::_ELEM
|
||||
{
|
||||
public:
|
||||
S3D_CACHE();
|
||||
virtual ~S3D_CACHE();
|
||||
|
||||
PROJECT::ELEM ProjectElementType() noexcept override
|
||||
{
|
||||
return PROJECT::ELEM::S3DCACHE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the configuration directory to be used by the model manager for storing 3D
|
||||
* model manager configuration data and the model cache.
|
||||
*
|
||||
* The config directory may only be set once in the lifetime of the object.
|
||||
*
|
||||
* @param aConfigDir is the configuration directory to use for 3D model manager data
|
||||
* @return true on success
|
||||
*/
|
||||
bool Set3DConfigDir( const wxString& aConfigDir );
|
||||
|
||||
/**
|
||||
* Set the current project's working directory; this affects the model search path.
|
||||
*/
|
||||
bool SetProject( PROJECT* aProject );
|
||||
|
||||
/**
|
||||
* Set the filename resolver's pointer to the application's PGM_BASE instance.
|
||||
*
|
||||
* The pointer is used to extract the local environment variables.
|
||||
*/
|
||||
void SetProgramBase( PGM_BASE* aBase );
|
||||
|
||||
/**
|
||||
* Attempt to load the scene data for a model.
|
||||
*
|
||||
* It will consult the internal cache list and load from cache if possible before invoking
|
||||
* the load() function of the available plugins. The model may fail to load if, for example,
|
||||
* the plugin does not support rendering of the 3D model.
|
||||
|
||||
*
|
||||
* @param aModelFile is the partial or full path to the model to be loaded.
|
||||
* @param aBasePath is the path to search for any relative files
|
||||
* @param aEmbeddedFiles is a pointer to the embedded files list.
|
||||
* @return true if the model was successfully loaded, otherwise false.
|
||||
*/
|
||||
SCENEGRAPH* Load( const wxString& aModelFile, const wxString& aBasePath,
|
||||
const EMBEDDED_FILES* aEmbeddedFiles );
|
||||
|
||||
FILENAME_RESOLVER* GetResolver() noexcept;
|
||||
|
||||
/**
|
||||
* Return the list of file filters retrieved from the plugins.
|
||||
*
|
||||
* This will contain at least the default "All Files (*.*)|*.*"
|
||||
*
|
||||
* @return a pointer to the filter list.
|
||||
*/
|
||||
std::list< wxString > const* GetFileFilters() const;
|
||||
|
||||
/**
|
||||
* Free all data in the cache and by default closes all plugins.
|
||||
*/
|
||||
void FlushCache( bool closePlugins = true );
|
||||
|
||||
/**
|
||||
* Unload plugins to free memory.
|
||||
*/
|
||||
void ClosePlugins();
|
||||
|
||||
/**
|
||||
* Attempt to load the scene data for a model and to translate it into an S3D_MODEL
|
||||
* structure for display by a renderer.
|
||||
*
|
||||
* @param aModelFileName is the full path to the model to be loaded.
|
||||
* @param aBasePath is the path to search for any relative files.
|
||||
* @param aEmbeddedFiles is a pointer to the embedded files list.
|
||||
* @return is a pointer to the render data or NULL if not available.
|
||||
*/
|
||||
S3DMODEL* GetModel( const wxString& aModelFileName, const wxString& aBasePath,
|
||||
const EMBEDDED_FILES* aEmbeddedFiles );
|
||||
|
||||
/**
|
||||
* Delete up old cache files in cache directory.
|
||||
*
|
||||
* Deletes ".3dc" files in the cache directory that are older than \a aNumDaysOld.
|
||||
*
|
||||
* @param aNumDaysOld is age threshold to delete ".3dc" cache files.
|
||||
*/
|
||||
void CleanCacheDir( int aNumDaysOld );
|
||||
|
||||
private:
|
||||
/**
|
||||
* Find or create cache entry for file name
|
||||
*
|
||||
* Searches the cache list for the given filename and retrieves the cache data; a cache
|
||||
* entry is created if one does not already exist.
|
||||
*
|
||||
* @param aFileName is the file name (full or partial path).
|
||||
* @param aCachePtr is an optional return address for cache entry pointer.
|
||||
* @return SCENEGRAPH object associated with file name or NULL on error.
|
||||
*/
|
||||
SCENEGRAPH* checkCache( const wxString& aFileName, S3D_CACHE_ENTRY** aCachePtr = nullptr );
|
||||
|
||||
/**
|
||||
* Calculate the SHA1 hash of the given file.
|
||||
*
|
||||
* @param aFileName file name (full path).
|
||||
* @param aHash a 128 bit hash to hold the hash.
|
||||
* @return true on success, otherwise false.
|
||||
*/
|
||||
bool getHash( const wxString& aFileName, HASH_128& aHash );
|
||||
|
||||
// load scene data from a cache file
|
||||
bool loadCacheData( S3D_CACHE_ENTRY* aCacheItem );
|
||||
|
||||
// save scene data to a cache file
|
||||
bool saveCacheData( S3D_CACHE_ENTRY* aCacheItem );
|
||||
|
||||
// the real load function (can supply a cache entry pointer to member functions)
|
||||
SCENEGRAPH* load( const wxString& aModelFile, const wxString& aBasePath,
|
||||
S3D_CACHE_ENTRY** aCachePtr = nullptr,
|
||||
const EMBEDDED_FILES* aEmbeddedFiles = nullptr );
|
||||
|
||||
/// Cache entries.
|
||||
std::list< S3D_CACHE_ENTRY* > m_CacheList;
|
||||
|
||||
/// Mapping of file names to cache names and data.
|
||||
std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString > m_CacheMap;
|
||||
|
||||
FILENAME_RESOLVER* m_FNResolver;
|
||||
|
||||
S3D_PLUGIN_MANAGER* m_Plugins;
|
||||
|
||||
PROJECT* m_project;
|
||||
wxString m_CacheDir;
|
||||
wxString m_ConfigDir; ///< base configuration path for 3D items.
|
||||
};
|
||||
|
||||
#endif // CACHE_3D_H
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_info.h
|
||||
* defines the basic data associated with a single 3D model.
|
||||
*/
|
||||
|
||||
#ifndef INFO_3D_H
|
||||
#define INFO_3D_H
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <plugins/3dapi/sg_base.h>
|
||||
|
||||
class FP_3DMODEL;
|
||||
|
||||
struct S3D_INFO
|
||||
{
|
||||
S3D_INFO();
|
||||
S3D_INFO( const FP_3DMODEL& aModel );
|
||||
|
||||
SGPOINT m_Scale; ///< scaling factors for the 3D footprint shape
|
||||
SGPOINT m_Rotation; ///< an X,Y,Z rotation (unit = degrees) for the 3D shape
|
||||
SGPOINT m_Offset; ///< an offset (unit = inch) for the 3D shape
|
||||
wxString m_Filename; ///< The 3D shape filename in 3D library
|
||||
};
|
||||
|
||||
#endif // INFO_3D_H
|
||||
@@ -1,535 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include <wx/dir.h>
|
||||
#include <wx/dynlib.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include <common.h>
|
||||
#include <paths.h>
|
||||
#include <wx_filename.h>
|
||||
#include "3d_plugin_manager.h"
|
||||
#include "plugins/3d/3d_plugin.h"
|
||||
#include "3d_cache/sg/scenegraph.h"
|
||||
#include "plugins/ldr/3d/pluginldr3D.h"
|
||||
|
||||
|
||||
/**
|
||||
* Flag to enable 3D plugin manager debug tracing.
|
||||
*
|
||||
* Use "KI_TRACE_EDA_3D_VIEWER" to enable.
|
||||
*
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
#define MASK_3D_PLUGINMGR "3D_PLUGIN_MANAGER"
|
||||
|
||||
|
||||
S3D_PLUGIN_MANAGER::S3D_PLUGIN_MANAGER()
|
||||
{
|
||||
// create the initial file filter list entry
|
||||
m_FileFilters.emplace_back( _( "All Files" ) + wxT( " (*.*)|*.*" ) );
|
||||
|
||||
// discover and load plugins
|
||||
loadPlugins();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( !m_ExtMap.empty() )
|
||||
{
|
||||
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::const_iterator sM = m_ExtMap.begin();
|
||||
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::const_iterator eM = m_ExtMap.end();
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * Extension [plugin name]:\n" ) );
|
||||
|
||||
while( sM != eM )
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " + '%s' [%s]\n" ), sM->first.GetData(),
|
||||
sM->second->GetKicadPluginName() );
|
||||
++sM;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * No plugins available\n" ) );
|
||||
}
|
||||
|
||||
|
||||
if( !m_FileFilters.empty() )
|
||||
{
|
||||
/// list of file filters
|
||||
std::list< wxString >::const_iterator sFF = m_FileFilters.begin();
|
||||
std::list< wxString >::const_iterator eFF = m_FileFilters.end();
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * File filters:\n" ) );
|
||||
|
||||
while( sFF != eFF )
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " + '%s'\n" ), (*sFF).GetData() );
|
||||
++sFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * No file filters available\n" ) );
|
||||
}
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
|
||||
S3D_PLUGIN_MANAGER::~S3D_PLUGIN_MANAGER()
|
||||
{
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator sP = m_Plugins.begin();
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator eP = m_Plugins.end();
|
||||
|
||||
while( sP != eP )
|
||||
{
|
||||
(*sP)->Close();
|
||||
delete *sP;
|
||||
++sP;
|
||||
}
|
||||
|
||||
m_Plugins.clear();
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::loadPlugins( void )
|
||||
{
|
||||
std::list<wxString> searchpaths;
|
||||
std::list<wxString> pluginlist;
|
||||
wxFileName fn;
|
||||
|
||||
#ifndef __WXMAC__
|
||||
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
|
||||
{
|
||||
// set up to work from the build directory
|
||||
fn.Assign( wxStandardPaths::Get().GetExecutablePath() );
|
||||
fn.AppendDir( wxT( ".." ) );
|
||||
fn.AppendDir( wxT( "plugins" ) );
|
||||
fn.AppendDir( wxT( "3d" ) );
|
||||
|
||||
std::string testpath = std::string( fn.GetPathWithSep().ToUTF8() );
|
||||
checkPluginPath( testpath, searchpaths );
|
||||
|
||||
// add subdirectories too
|
||||
wxDir debugPluginDir;
|
||||
wxString subdir;
|
||||
|
||||
debugPluginDir.Open( testpath );
|
||||
|
||||
if( debugPluginDir.IsOpened()
|
||||
&& debugPluginDir.GetFirst( &subdir, wxEmptyString, wxDIR_DIRS ) )
|
||||
{
|
||||
checkPluginPath( testpath + subdir, searchpaths );
|
||||
|
||||
while( debugPluginDir.GetNext( &subdir ) )
|
||||
checkPluginPath( testpath + subdir, searchpaths );
|
||||
}
|
||||
}
|
||||
|
||||
fn.AssignDir( PATHS::GetStockPlugins3DPath() );
|
||||
checkPluginPath( std::string( fn.GetPathWithSep().ToUTF8() ), searchpaths );
|
||||
#else
|
||||
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
|
||||
{
|
||||
// Exe will be at <build_dir>/pcbnew/pcbnew.app/Contents/MacOS/pcbnew for standalone
|
||||
// Plugin will be at <build_dir>/kicad/KiCad.app/Contents/PlugIns/3d
|
||||
fn.Assign( wxStandardPaths::Get().GetExecutablePath() );
|
||||
|
||||
if( fn.GetName() == wxT( "kicad" ) )
|
||||
{
|
||||
fn.AppendDir( wxT( ".." ) ); // Contents
|
||||
}
|
||||
else
|
||||
{
|
||||
fn.AppendDir( wxT( ".." ) ); // Contents
|
||||
fn.AppendDir( wxT( ".." ) ); // pcbnew.app
|
||||
fn.AppendDir( wxT( ".." ) ); // pcbnew
|
||||
fn.AppendDir( wxT( ".." ) ); // Build root
|
||||
fn.AppendDir( wxT( "kicad" ) );
|
||||
fn.AppendDir( wxT( "KiCad.app" ) );
|
||||
fn.AppendDir( wxT( "Contents" ) );
|
||||
}
|
||||
|
||||
fn.AppendDir( wxT( "PlugIns" ) );
|
||||
fn.AppendDir( wxT( "3d" ) );
|
||||
fn.MakeAbsolute();
|
||||
|
||||
std::string testpath = std::string( fn.GetPathWithSep().ToUTF8() );
|
||||
checkPluginPath( testpath, searchpaths );
|
||||
|
||||
// Also check when running KiCad manager from build dir
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search path on OS X is
|
||||
// (1) Machine /Library/Application Support/kicad/PlugIns/3d
|
||||
checkPluginPath( PATHS::GetOSXKicadMachineDataDir() + wxT( "/PlugIns/3d" ), searchpaths );
|
||||
|
||||
// (2) Bundle kicad.app/Contents/PlugIns/3d
|
||||
fn.AssignDir( PATHS::GetStockPlugins3DPath() );
|
||||
checkPluginPath( fn.GetPathWithSep(), searchpaths );
|
||||
}
|
||||
#endif
|
||||
|
||||
std::list< wxString >::iterator sPL = searchpaths.begin();
|
||||
std::list< wxString >::iterator ePL = searchpaths.end();
|
||||
|
||||
while( sPL != ePL )
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] searching path: '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, (*sPL).ToUTF8() );
|
||||
|
||||
listPlugins( *sPL, pluginlist );
|
||||
++sPL;
|
||||
}
|
||||
|
||||
if( pluginlist.empty() )
|
||||
return;
|
||||
|
||||
sPL = pluginlist.begin();
|
||||
ePL = pluginlist.end();
|
||||
|
||||
while( sPL != ePL )
|
||||
{
|
||||
KICAD_PLUGIN_LDR_3D* pp = new KICAD_PLUGIN_LDR_3D;
|
||||
|
||||
if( pp->Open( sPL->ToUTF8() ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] adding plugin" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
m_Plugins.push_back( pp );
|
||||
int nf = pp->GetNFilters();
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] adding %d filters" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, nf );
|
||||
|
||||
for( int i = 0; i < nf; ++i )
|
||||
{
|
||||
char const* cp = pp->GetFileFilter( i );
|
||||
|
||||
if( cp )
|
||||
addFilterString( cp );
|
||||
}
|
||||
|
||||
addExtensionMap( pp );
|
||||
|
||||
// close the loaded library
|
||||
pp->Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] deleting plugin" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
delete pp;
|
||||
}
|
||||
|
||||
++sPL;
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] plugins loaded" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::listPlugins( const wxString& aPath, std::list< wxString >& aPluginList )
|
||||
{
|
||||
// list potential plugins given a search path
|
||||
wxString nameFilter; // filter for user-loadable libraries (aka footprints)
|
||||
wxString lName; // stores name of enumerated files
|
||||
wxString fName; // full name of file
|
||||
wxDir wd;
|
||||
wd.Open( aPath );
|
||||
|
||||
if( !wd.IsOpened() )
|
||||
return;
|
||||
|
||||
nameFilter = wxT( "*" );
|
||||
|
||||
#ifndef __WXMAC__
|
||||
nameFilter.Append( wxDynamicLibrary::GetDllExt( wxDL_MODULE ) );
|
||||
#else
|
||||
// wxDynamicLibrary::GetDllExt( wxDL_MODULE ) will return ".bundle" on OS X.
|
||||
// This might be correct, but cmake builds a ".so" for a library MODULE.
|
||||
// Per definition a loadable "xxx.bundle" is similar to an "xxx.app" app
|
||||
// bundle being a folder with some special content in it. We obviously don't
|
||||
// want to have that here for our loadable module, so just use ".so".
|
||||
nameFilter.Append( wxS( ".so" ) );
|
||||
#endif
|
||||
|
||||
wxString lp = wd.GetNameWithSep();
|
||||
|
||||
if( wd.GetFirst( &lName, nameFilter, wxDIR_FILES ) )
|
||||
{
|
||||
fName = lp + lName;
|
||||
checkPluginName( fName, aPluginList );
|
||||
|
||||
while( wd.GetNext( &lName ) )
|
||||
{
|
||||
fName = lp + lName;
|
||||
checkPluginName( fName, aPluginList );
|
||||
}
|
||||
}
|
||||
|
||||
wd.Close();
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::checkPluginName( const wxString& aPath,
|
||||
std::list< wxString >& aPluginList )
|
||||
{
|
||||
// check the existence of a plugin name and add it to the list
|
||||
|
||||
if( aPath.empty() || !wxFileName::FileExists( aPath ) )
|
||||
return;
|
||||
|
||||
wxFileName path( ExpandEnvVarSubstitutions( aPath, nullptr ) );
|
||||
|
||||
path.Normalize( FN_NORMALIZE_FLAGS );
|
||||
|
||||
// determine if the path is already in the list
|
||||
wxString wxpath = path.GetFullPath();
|
||||
std::list< wxString >::iterator bl = aPluginList.begin();
|
||||
std::list< wxString >::iterator el = aPluginList.end();
|
||||
|
||||
while( bl != el )
|
||||
{
|
||||
if( 0 == (*bl).Cmp( wxpath ) )
|
||||
return;
|
||||
|
||||
++bl;
|
||||
}
|
||||
|
||||
// prevent loading non-plugin dlls
|
||||
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
|
||||
{
|
||||
if( !path.GetName().StartsWith( "s3d_plugin" )
|
||||
&& !path.GetName().StartsWith( "libs3d_plugin" ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
aPluginList.push_back( wxpath );
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * [INFO] found 3D plugin '%s'\n" ), wxpath.GetData() );
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::checkPluginPath( const wxString& aPath,
|
||||
std::list< wxString >& aSearchList )
|
||||
{
|
||||
if( aPath.empty() )
|
||||
return;
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * [INFO] checking if valid plugin directory '%s'\n" ),
|
||||
aPath.GetData() );
|
||||
|
||||
wxFileName path;
|
||||
path.AssignDir( aPath );
|
||||
path.Normalize( FN_NORMALIZE_FLAGS );
|
||||
|
||||
if( !wxFileName::DirExists( path.GetFullPath() ) )
|
||||
return;
|
||||
|
||||
// determine if the directory is already in the list
|
||||
wxString wxpath = path.GetFullPath();
|
||||
std::list< wxString >::iterator bl = aSearchList.begin();
|
||||
std::list< wxString >::iterator el = aSearchList.end();
|
||||
|
||||
while( bl != el )
|
||||
{
|
||||
if( 0 == (*bl).Cmp( wxpath ) )
|
||||
return;
|
||||
|
||||
++bl;
|
||||
}
|
||||
|
||||
aSearchList.push_back( wxpath );
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::addFilterString( const wxString& aFilterString )
|
||||
{
|
||||
// add an entry to the file filter list
|
||||
if( aFilterString.empty() )
|
||||
return;
|
||||
|
||||
std::list< wxString >::iterator sFF = m_FileFilters.begin();
|
||||
std::list< wxString >::iterator eFF = m_FileFilters.end();
|
||||
|
||||
while( sFF != eFF )
|
||||
{
|
||||
if( 0 == (*sFF).Cmp( aFilterString ) )
|
||||
return;
|
||||
|
||||
++sFF;
|
||||
}
|
||||
|
||||
m_FileFilters.push_back( aFilterString );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::addExtensionMap( KICAD_PLUGIN_LDR_3D* aPlugin )
|
||||
{
|
||||
// add entries to the extension map
|
||||
if( nullptr == aPlugin )
|
||||
return;
|
||||
|
||||
int nExt = aPlugin->GetNExtensions();
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [INFO] adding %d extensions" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, nExt );
|
||||
|
||||
for( int i = 0; i < nExt; ++i )
|
||||
{
|
||||
char const* cp = aPlugin->GetModelExtension( i );
|
||||
wxString ws;
|
||||
|
||||
if( cp )
|
||||
ws = wxString( cp );
|
||||
|
||||
if( !ws.empty() )
|
||||
{
|
||||
m_ExtMap.emplace( ws, aPlugin );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::list< wxString > const* S3D_PLUGIN_MANAGER::GetFileFilters( void ) const noexcept
|
||||
{
|
||||
return &m_FileFilters;
|
||||
}
|
||||
|
||||
|
||||
SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName, std::string& aPluginInfo )
|
||||
{
|
||||
wxFileName raw( aFileName );
|
||||
wxString ext_to_find = raw.GetExt();
|
||||
|
||||
#ifdef _WIN32
|
||||
// note: plugins only have a lowercase filter within Windows; including an uppercase
|
||||
// filter will result in duplicate file entries and should be avoided.
|
||||
ext_to_find.MakeLower();
|
||||
#endif
|
||||
|
||||
// .gz files are compressed versions that may have additional information in the previous
|
||||
// extension.
|
||||
if( ext_to_find == wxT( "gz" ) )
|
||||
{
|
||||
wxFileName second( raw.GetName() );
|
||||
ext_to_find = second.GetExt() + wxT( ".gz" );
|
||||
}
|
||||
|
||||
std::pair < std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator,
|
||||
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator > items;
|
||||
|
||||
items = m_ExtMap.equal_range( ext_to_find );
|
||||
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator sL = items.first;
|
||||
|
||||
while( sL != items.second )
|
||||
{
|
||||
if( sL->second->CanRender() )
|
||||
{
|
||||
SCENEGRAPH* sp = sL->second->Load( aFileName.ToUTF8() );
|
||||
|
||||
if( nullptr != sp )
|
||||
{
|
||||
sL->second->GetPluginInfo( aPluginInfo );
|
||||
return sp;
|
||||
}
|
||||
}
|
||||
|
||||
++sL;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::ClosePlugins( void )
|
||||
{
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator sP = m_Plugins.begin();
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator eP = m_Plugins.end();
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [INFO] closing %d extensions" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, static_cast<int>( m_Plugins.size() ) );
|
||||
|
||||
while( sP != eP )
|
||||
{
|
||||
(*sP)->Close();
|
||||
++sP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool S3D_PLUGIN_MANAGER::CheckTag( const char* aTag )
|
||||
{
|
||||
if( nullptr == aTag || aTag[0] == 0 || m_Plugins.empty() )
|
||||
return false;
|
||||
|
||||
std::string tname = aTag;
|
||||
std::string pname; // plugin name
|
||||
|
||||
size_t cpos = tname.find( ':' );
|
||||
|
||||
// if there is no colon or plugin name then the tag is bad
|
||||
if( cpos == std::string::npos || cpos == 0 )
|
||||
return false;
|
||||
|
||||
pname = tname.substr( 0, cpos );
|
||||
std::string ptag; // tag from the plugin
|
||||
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator pS = m_Plugins.begin();
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator pE = m_Plugins.end();
|
||||
|
||||
while( pS != pE )
|
||||
{
|
||||
ptag.clear();
|
||||
(*pS)->GetPluginInfo( ptag );
|
||||
|
||||
// if the plugin name matches then the version must also match
|
||||
if( !ptag.compare( 0, pname.size(), pname ) )
|
||||
{
|
||||
if( ptag.compare( tname ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
++pS;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_plugin_manager.h
|
||||
* manages 3D model plugins
|
||||
*/
|
||||
|
||||
#ifndef PLUGIN_MANAGER_3D_H
|
||||
#define PLUGIN_MANAGER_3D_H
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
|
||||
class wxWindow;
|
||||
class KICAD_PLUGIN_LDR_3D;
|
||||
class SCENEGRAPH;
|
||||
|
||||
class S3D_PLUGIN_MANAGER
|
||||
{
|
||||
public:
|
||||
S3D_PLUGIN_MANAGER();
|
||||
virtual ~S3D_PLUGIN_MANAGER();
|
||||
|
||||
/**
|
||||
* Return the list of file filters; this will contain at least the default
|
||||
* "All Files (*.*)|*.*" and the file filters supported by any available plugins.
|
||||
*
|
||||
* @return a pointer to the internal filter list.
|
||||
*/
|
||||
std::list< wxString > const* GetFileFilters( void ) const noexcept;
|
||||
|
||||
SCENEGRAPH* Load3DModel( const wxString& aFileName, std::string& aPluginInfo );
|
||||
|
||||
/**
|
||||
* Iterate through all discovered plugins and closes them to reclaim memory.
|
||||
*
|
||||
* The individual plugins will be automatically reloaded as calls are made to load
|
||||
* specific models.
|
||||
*/
|
||||
void ClosePlugins( void );
|
||||
|
||||
/**
|
||||
* Check the given tag and returns true if the plugin named in the tag is not loaded
|
||||
* or the plugin is loaded and the version matches.
|
||||
*/
|
||||
bool CheckTag( const char* aTag );
|
||||
|
||||
private:
|
||||
/// load plugins
|
||||
void loadPlugins( void );
|
||||
|
||||
/// list potential plugins
|
||||
void listPlugins( const wxString& aPath, std::list< wxString >& aPluginList );
|
||||
|
||||
/// check the existence of a plugin name and add it to the list
|
||||
void checkPluginName( const wxString& aPath, std::list< wxString >& aPluginList );
|
||||
|
||||
/// check the existence of a path and add it to the path search list
|
||||
void checkPluginPath( const wxString& aPath, std::list< wxString >& aSearchList );
|
||||
|
||||
/// add an entry to the file filter list
|
||||
void addFilterString( const wxString& aFilterString );
|
||||
|
||||
/// add entries to the extension map
|
||||
void addExtensionMap( KICAD_PLUGIN_LDR_3D* aPlugin );
|
||||
|
||||
/// list of discovered plugins
|
||||
std::list< KICAD_PLUGIN_LDR_3D* > m_Plugins;
|
||||
|
||||
/// mapping of extensions to available plugins
|
||||
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* > m_ExtMap;
|
||||
|
||||
/// list of file filters
|
||||
std::list< wxString > m_FileFilters;
|
||||
};
|
||||
|
||||
#endif // PLUGIN_MANAGER_3D_H
|
||||
@@ -1 +0,0 @@
|
||||
add_subdirectory( sg )
|
||||
@@ -1,111 +0,0 @@
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/3d-viewer
|
||||
)
|
||||
|
||||
set( SG_FILES
|
||||
sg_base.cpp
|
||||
sg_node.cpp
|
||||
sg_helpers.cpp
|
||||
scenegraph.cpp
|
||||
sg_appearance.cpp
|
||||
sg_faceset.cpp
|
||||
sg_shape.cpp
|
||||
sg_colors.cpp
|
||||
sg_coords.cpp
|
||||
sg_normals.cpp
|
||||
sg_index.cpp
|
||||
sg_coordindex.cpp
|
||||
ifsg_node.cpp
|
||||
ifsg_transform.cpp
|
||||
ifsg_appearance.cpp
|
||||
ifsg_index.cpp
|
||||
ifsg_coordindex.cpp
|
||||
ifsg_colors.cpp
|
||||
ifsg_coords.cpp
|
||||
ifsg_faceset.cpp
|
||||
ifsg_normals.cpp
|
||||
ifsg_shape.cpp
|
||||
ifsg_api.cpp
|
||||
)
|
||||
|
||||
if( MINGW )
|
||||
list( APPEND SG_FILES ${CMAKE_SOURCE_DIR}/common/streamwrapper.cpp )
|
||||
endif( MINGW )
|
||||
|
||||
add_library( kicad_3dsg SHARED ${SG_FILES} )
|
||||
|
||||
if( APPLE )
|
||||
# puts library into the main kicad.app bundle in build tree
|
||||
set_target_properties( kicad_3dsg PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY "${OSX_BUNDLE_BUILD_LIB_DIR}"
|
||||
INSTALL_NAME_DIR "${OSX_BUNDLE_BUILD_LIB_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
find_file( S3DSG_VERSION_FILE sg_version.h
|
||||
PATHS ${CMAKE_SOURCE_DIR}/include/plugins/3dapi NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
|
||||
|
||||
if( NOT ${S3DSG_VERSION_FILE} STREQUAL "S3DSG_VERSION_FILE-NOTFOUND" )
|
||||
|
||||
# extract the "#define KICADSG_VERSION_*" lines
|
||||
file( STRINGS ${S3DSG_VERSION_FILE} _version
|
||||
REGEX "^[' ','\t']*#define[' ','\t']*KICADSG_VERSION_.*" )
|
||||
|
||||
foreach( SVAR ${_version} )
|
||||
string( REGEX MATCH KICADSG_VERSION_[M,A,J,O,R,I,N,P,T,C,H,E,V]* _VARNAME ${SVAR} )
|
||||
string( REGEX MATCH [0-9]+ _VALUE ${SVAR} )
|
||||
|
||||
if( NOT ${_VARNAME} STREQUAL "" )
|
||||
if( NOT ${_VALUE} STREQUAL "" )
|
||||
set( ${_VARNAME} ${_VALUE} )
|
||||
else()
|
||||
set( ${_VARNAME} 0 )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endforeach()
|
||||
|
||||
if( NOT KICADSG_VERSION_MAJOR AND NOT ${KICADSG_VERSION_MAJOR} STREQUAL "0" )
|
||||
message( FATAL_ERROR "Cannot determine the S3DSG library version" )
|
||||
endif()
|
||||
|
||||
#ensure that NOT SG_VERSION* will evaluate to '0'
|
||||
if( NOT KICADSG_VERSION_MINOR )
|
||||
set( KICADSG_VERSION_MINOR 0 )
|
||||
endif()
|
||||
|
||||
if( NOT KICADSG_VERSION_PATCH )
|
||||
set( KICADSG_VERSION_PATCH 0 )
|
||||
endif()
|
||||
|
||||
set_target_properties( kicad_3dsg
|
||||
PROPERTIES SOVERSION
|
||||
${KICADSG_VERSION_MAJOR}.${KICADSG_VERSION_MINOR}.${KICADSG_VERSION_PATCH} )
|
||||
|
||||
message( STATUS "S3DSG version: ${KICADSG_VERSION_MAJOR}.${KICADSG_VERSION_MINOR}.${KICADSG_VERSION_PATCH}" )
|
||||
else()
|
||||
message( FATAL_ERROR "Cannot determine the S3DSG library version" )
|
||||
endif()
|
||||
|
||||
unset( S3DSG_VERSION_FILE CACHE )
|
||||
|
||||
# Define a flag to expose the appropriate EXPORT macro at build time
|
||||
target_compile_definitions( kicad_3dsg PRIVATE COMPILE_SGLIB )
|
||||
|
||||
target_link_libraries( kicad_3dsg ${wxWidgets_LIBRARIES} )
|
||||
|
||||
# Don't specify the ARCHIVE DESTINATION parameter to prevent
|
||||
# the install of the import library on Windows
|
||||
# https://cmake.org/pipermail/cmake/2011-November/047746.html
|
||||
install( TARGETS
|
||||
kicad_3dsg
|
||||
RUNTIME DESTINATION ${KICAD_LIB}
|
||||
LIBRARY DESTINATION ${KICAD_LIB}
|
||||
COMPONENT binary
|
||||
)
|
||||
|
||||
if( KICAD_WIN32_INSTALL_PDBS )
|
||||
# Get the PDBs to copy over for MSVC
|
||||
install(FILES $<TARGET_PDB_FILE:kicad_3dsg> DESTINATION ${KICAD_BIN})
|
||||
endif()
|
||||
@@ -1,527 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/log.h>
|
||||
#include "plugins/3dapi/ifsg_api.h"
|
||||
#include "plugins/3dapi/sg_version.h"
|
||||
#include "streamwrapper.h"
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
#include "3d_cache/sg/scenegraph.h"
|
||||
#include "3d_cache/sg/sg_appearance.h"
|
||||
#include "3d_cache/sg/sg_shape.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
// version format of the cache file
|
||||
#define SG_VERSION_TAG "VERSION:2"
|
||||
|
||||
|
||||
static void formatMaterial( SMATERIAL& mat, SGAPPEARANCE const* app )
|
||||
{
|
||||
float v0, v1, v2;
|
||||
|
||||
app->ambient.GetColor( v0, v1, v2 );
|
||||
mat.m_Ambient.x = v0;
|
||||
mat.m_Ambient.y = v1;
|
||||
mat.m_Ambient.z = v2;
|
||||
|
||||
app->diffuse.GetColor( v0, v1, v2 );
|
||||
mat.m_Diffuse.x = v0;
|
||||
mat.m_Diffuse.y = v1;
|
||||
mat.m_Diffuse.z = v2;
|
||||
mat.m_Ambient.x *= v0;
|
||||
mat.m_Ambient.y *= v1;
|
||||
mat.m_Ambient.z *= v2;
|
||||
|
||||
app->emissive.GetColor( v0, v1, v2 );
|
||||
mat.m_Emissive.x = v0;
|
||||
mat.m_Emissive.y = v1;
|
||||
mat.m_Emissive.z = v2;
|
||||
|
||||
app->specular.GetColor( v0, v1, v2 );
|
||||
mat.m_Specular.x = v0;
|
||||
mat.m_Specular.y = v1;
|
||||
mat.m_Specular.z = v2;
|
||||
|
||||
mat.m_Shininess = app->shininess;
|
||||
mat.m_Transparency = app->transparency;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::WriteVRML( const char* filename, bool overwrite, SGNODE* aTopNode,
|
||||
bool reuse, bool renameNodes )
|
||||
{
|
||||
if( nullptr == filename || filename[0] == 0 )
|
||||
return false;
|
||||
|
||||
wxString ofile = wxString::FromUTF8Unchecked( filename );
|
||||
|
||||
if( wxFileName::Exists( ofile ) )
|
||||
{
|
||||
if( !overwrite )
|
||||
return false;
|
||||
|
||||
// make sure we make no attempt to write a directory
|
||||
if( !wxFileName::FileExists( ofile ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( aTopNode && aTopNode->GetNodeType() == S3D::SGTYPE_TRANSFORM, false );
|
||||
|
||||
OPEN_OSTREAM( op, filename );
|
||||
|
||||
if( op.fail() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] failed to open file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, filename );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
op.imbue( std::locale::classic() );
|
||||
op << "#VRML V2.0 utf8\n";
|
||||
|
||||
if( renameNodes )
|
||||
{
|
||||
aTopNode->ResetNodeIndex();
|
||||
aTopNode->ReNameNodes();
|
||||
}
|
||||
|
||||
aTopNode->WriteVRML( op, reuse );
|
||||
|
||||
if( !op.fail() )
|
||||
{
|
||||
CLOSE_STREAM( op );
|
||||
return true;
|
||||
}
|
||||
|
||||
CLOSE_STREAM( op );
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] problems encountered writing file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, filename );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void S3D::ResetNodeIndex( SGNODE* aNode )
|
||||
{
|
||||
wxCHECK( aNode, /* void */ );
|
||||
|
||||
aNode->ResetNodeIndex();
|
||||
}
|
||||
|
||||
|
||||
void S3D::RenameNodes( SGNODE* aNode )
|
||||
{
|
||||
wxCHECK( aNode, /* void */ );
|
||||
|
||||
aNode->ReNameNodes();
|
||||
}
|
||||
|
||||
|
||||
void S3D::DestroyNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( aNode, /* void */ );
|
||||
|
||||
delete aNode;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode,
|
||||
const char* aPluginInfo )
|
||||
{
|
||||
if( nullptr == aFileName || aFileName[0] == 0 )
|
||||
return false;
|
||||
|
||||
wxString ofile = wxString::FromUTF8Unchecked( aFileName );
|
||||
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
if( wxFileName::Exists( ofile ) )
|
||||
{
|
||||
if( !overwrite )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] file exists not overwriting '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure we make no attempt to write a directory
|
||||
if( !wxFileName::FileExists( aFileName ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] specified path is a directory '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
OPEN_OSTREAM( output, aFileName );
|
||||
|
||||
if( output.fail() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] failed to open file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
output << "(" << SG_VERSION_TAG << ")";
|
||||
|
||||
if( nullptr != aPluginInfo && aPluginInfo[0] != 0 )
|
||||
output << "(" << aPluginInfo << ")";
|
||||
else
|
||||
output << "(INTERNAL:0.0.0.0)";
|
||||
|
||||
bool rval = aNode->WriteCache( output, nullptr );
|
||||
CLOSE_STREAM( output );
|
||||
|
||||
if( !rval )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [INFO] problems encountered writing cache file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
// delete the defective file
|
||||
wxRemoveFile( ofile );
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
|
||||
bool (*aTagCheck)( const char*, void* ) )
|
||||
{
|
||||
if( nullptr == aFileName || aFileName[0] == 0 )
|
||||
return nullptr;
|
||||
|
||||
wxString ofile = wxString::FromUTF8Unchecked( aFileName );
|
||||
|
||||
if( !wxFileName::FileExists( aFileName ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] no such file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<SGNODE> np = std::make_unique<SCENEGRAPH>( nullptr );
|
||||
|
||||
OPEN_ISTREAM( file, aFileName );
|
||||
|
||||
if( file.fail() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] failed to open file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// from SG_VERSION_TAG 1, read the version tag; if it's not the expected tag
|
||||
// then we fail to read the cache file
|
||||
do
|
||||
{
|
||||
std::string name;
|
||||
char schar;
|
||||
file.get( schar );
|
||||
|
||||
if( '(' != schar )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; missing left parenthesis"
|
||||
" at position '%d'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( file.tellg() ) );
|
||||
|
||||
CLOSE_STREAM( file );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
file.get( schar );
|
||||
|
||||
while( ')' != schar && file.good() )
|
||||
{
|
||||
name.push_back( schar );
|
||||
file.get( schar );
|
||||
}
|
||||
|
||||
if( name.compare( SG_VERSION_TAG ) )
|
||||
{
|
||||
CLOSE_STREAM( file );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
// from SG_VERSION_TAG 2, read the PluginInfo string and check that it matches
|
||||
// version tag; if it's not the expected tag then we fail to read the file
|
||||
do
|
||||
{
|
||||
std::string name;
|
||||
char schar;
|
||||
file.get( schar );
|
||||
|
||||
if( '(' != schar )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; missing left parenthesis"
|
||||
" at position '%d'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( file.tellg() ) );
|
||||
|
||||
CLOSE_STREAM( file );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
file.get( schar );
|
||||
|
||||
while( ')' != schar && file.good() )
|
||||
{
|
||||
name.push_back( schar );
|
||||
file.get( schar );
|
||||
}
|
||||
|
||||
// check the plugin tag
|
||||
if( nullptr != aTagCheck && nullptr != aPluginMgr
|
||||
&& !aTagCheck( name.c_str(), aPluginMgr ) )
|
||||
{
|
||||
CLOSE_STREAM( file );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
bool rval = np->ReadCache( file, nullptr );
|
||||
CLOSE_STREAM( file );
|
||||
|
||||
if( !rval )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] problems encountered reading cache file "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aFileName );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return np.release();
|
||||
}
|
||||
|
||||
|
||||
S3DMODEL* S3D::GetModel( SCENEGRAPH* aNode )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return nullptr;
|
||||
|
||||
if( aNode->GetNodeType() != S3D::SGTYPE_TRANSFORM )
|
||||
return nullptr;
|
||||
|
||||
S3D::MATLIST materials;
|
||||
std::vector< SMESH > meshes;
|
||||
|
||||
// the materials list shall have a default color; although the VRML
|
||||
// default is an opaque black, the default used here shall be a median
|
||||
// gray in hopes that it may help highlight faulty models; this color is
|
||||
// also typical of MCAD applications. When a model has no associated
|
||||
// material color it shall be assigned the index 0.
|
||||
SGAPPEARANCE app( nullptr );
|
||||
app.ambient = SGCOLOR( 0.6f, 0.6f, 0.6f );
|
||||
app.diffuse = SGCOLOR( 0.6f, 0.6f, 0.6f );
|
||||
app.specular = app.diffuse;
|
||||
app.shininess = 0.05f;
|
||||
app.transparency = 0.0f;
|
||||
|
||||
materials.matorder.push_back( &app );
|
||||
materials.matmap.emplace( &app, 0 );
|
||||
|
||||
if( aNode->Prepare( nullptr, materials, meshes ) )
|
||||
{
|
||||
if( meshes.empty() )
|
||||
return nullptr;
|
||||
|
||||
S3DMODEL* model = S3D::New3DModel();
|
||||
|
||||
// add all the materials
|
||||
size_t j = materials.matorder.size();
|
||||
SMATERIAL* lmat = new SMATERIAL[j];
|
||||
|
||||
for( size_t i = 0; i < j; ++i )
|
||||
formatMaterial( lmat[i], materials.matorder[i] );
|
||||
|
||||
model->m_Materials = lmat;
|
||||
model->m_MaterialsSize = j;
|
||||
|
||||
// add all the meshes
|
||||
j = meshes.size();
|
||||
SMESH* lmesh = new SMESH[j];
|
||||
|
||||
for( size_t i = 0; i < j; ++i )
|
||||
lmesh[i] = meshes[i];
|
||||
|
||||
model->m_Meshes = lmesh;
|
||||
model->m_MeshesSize = j;
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
size_t j = meshes.size();
|
||||
|
||||
for( size_t i = 0; i < j; ++i )
|
||||
S3D::Free3DMesh( meshes[i] );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void S3D::Destroy3DModel( S3DMODEL** aModel )
|
||||
{
|
||||
if( nullptr == aModel || nullptr == *aModel )
|
||||
return;
|
||||
|
||||
S3DMODEL* m = *aModel;
|
||||
S3D::FREE_S3DMODEL( *m );
|
||||
delete m;
|
||||
*aModel = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void Free3DModel( S3DMODEL& aModel )
|
||||
{
|
||||
S3D::FREE_S3DMODEL( aModel );
|
||||
}
|
||||
|
||||
|
||||
void S3D::Free3DMesh( SMESH& aMesh )
|
||||
{
|
||||
S3D::FREE_SMESH( aMesh );
|
||||
}
|
||||
|
||||
|
||||
S3DMODEL* S3D::New3DModel( void )
|
||||
{
|
||||
S3DMODEL* mp = new S3DMODEL;
|
||||
S3D::INIT_S3DMODEL( *mp );
|
||||
return mp;
|
||||
}
|
||||
|
||||
|
||||
void S3D::Init3DMaterial( SMATERIAL& aMat )
|
||||
{
|
||||
S3D::INIT_SMATERIAL( aMat );
|
||||
}
|
||||
|
||||
|
||||
void S3D::Init3DMesh( SMESH& aMesh )
|
||||
{
|
||||
S3D::INIT_SMESH( aMesh );
|
||||
}
|
||||
|
||||
|
||||
void S3D::GetLibVersion( unsigned char* Major, unsigned char* Minor, unsigned char* Patch,
|
||||
unsigned char* Revision ) noexcept
|
||||
{
|
||||
if( Major )
|
||||
*Major = KICADSG_VERSION_MAJOR;
|
||||
|
||||
if( Minor )
|
||||
*Minor = KICADSG_VERSION_MINOR;
|
||||
|
||||
if( Revision )
|
||||
*Revision = KICADSG_VERSION_REVISION;
|
||||
|
||||
if( Patch )
|
||||
*Patch = KICADSG_VERSION_PATCH;
|
||||
}
|
||||
|
||||
|
||||
SGVECTOR S3D::CalcTriNorm( const SGPOINT& p1, const SGPOINT& p2, const SGPOINT& p3 )
|
||||
{
|
||||
glm::dvec3 tri = glm::dvec3( 0.0, 0.0, 0.0 );
|
||||
glm::dvec3 pts[3];
|
||||
|
||||
pts[0] = glm::dvec3( p1.x, p1.y, p1.z );
|
||||
pts[1] = glm::dvec3( p2.x, p2.y, p2.z );
|
||||
pts[2] = glm::dvec3( p3.x, p3.y, p3.z );
|
||||
|
||||
// degenerate points are given a default 0, 0, 1 normal
|
||||
if( S3D::degenerate( pts ) )
|
||||
return SGVECTOR( 0.0, 0.0, 1.0 );
|
||||
|
||||
// normal
|
||||
tri = glm::cross( pts[1] - pts[0], pts[2] - pts[0] );
|
||||
(void)glm::normalize( tri );
|
||||
|
||||
return SGVECTOR( tri.x, tri.y, tri.z );
|
||||
}
|
||||
|
||||
|
||||
S3D::SGTYPES S3D::GetSGNodeType( SGNODE* aNode )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return SGTYPE_END;
|
||||
|
||||
return aNode->GetNodeType();
|
||||
}
|
||||
|
||||
|
||||
SGNODE* S3D::GetSGNodeParent( SGNODE* aNode )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return nullptr;
|
||||
|
||||
return aNode->GetParent();
|
||||
}
|
||||
|
||||
|
||||
bool S3D::AddSGNodeRef( SGNODE* aParent, SGNODE* aChild )
|
||||
{
|
||||
if( nullptr == aParent || nullptr == aChild )
|
||||
return false;
|
||||
|
||||
return aParent->AddRefNode( aChild );
|
||||
}
|
||||
|
||||
|
||||
bool S3D::AddSGNodeChild( SGNODE* aParent, SGNODE* aChild )
|
||||
{
|
||||
if( nullptr == aParent || nullptr == aChild )
|
||||
return false;
|
||||
|
||||
return aParent->AddChildNode( aChild );
|
||||
}
|
||||
|
||||
|
||||
void S3D::AssociateSGNodeWrapper( SGNODE* aObject, SGNODE** aRefPtr )
|
||||
{
|
||||
if( nullptr == aObject || nullptr == aRefPtr || aObject != *aRefPtr )
|
||||
return;
|
||||
|
||||
aObject->AssociateWrapper( aRefPtr );
|
||||
}
|
||||
@@ -1,284 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
#include "plugins/3dapi/ifsg_appearance.h"
|
||||
#include "3d_cache/sg/sg_appearance.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_APPEARANCE::IFSG_APPEARANCE( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return ;
|
||||
|
||||
m_node = new SGAPPEARANCE( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_APPEARANCE::IFSG_APPEARANCE( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGAPPEARANCE( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_APPEARANCE::IFSG_APPEARANCE( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( ! pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGAPPEARANCE( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_APPEARANCE != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGAPPEARANCE( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGAPPEARANCE" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetEmissive( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetEmissive( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetEmissive( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetDiffuse( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetDiffuse( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetDiffuse( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetSpecular( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetSpecular( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetSpecular( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetAmbient( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetAmbient( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetAmbient( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetShininess( float aShininess ) noexcept
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
if( aShininess < 0 || aShininess > 1.0 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] shininess out of range [0..1]" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
( (SGAPPEARANCE*) m_node )->shininess = aShininess;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetTransparency( float aTransparency ) noexcept
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
if( aTransparency < 0 || aTransparency > 1.0 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] transparency out of range [0..1]" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
( (SGAPPEARANCE*) m_node )->transparency = aTransparency;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_colors.h"
|
||||
#include "3d_cache/sg/sg_colors.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_COLORS::IFSG_COLORS( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return;
|
||||
|
||||
m_node = new SGCOLORS( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COLORS::IFSG_COLORS( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGCOLORS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d" ), __FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COLORS::IFSG_COLORS( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
// Braces needed due to dangling else warning from wxLogTrace macro
|
||||
if( !pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGCOLORS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_COLORS != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGCOLORS( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGCOLORS" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::GetColorList( size_t& aListSize, SGCOLOR*& aColorList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGCOLORS*) m_node )->GetColorList( aListSize, aColorList );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::SetColorList( size_t aListSize, const SGCOLOR* aColorList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOLORS*) m_node )->SetColorList( aListSize, aColorList );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::AddColor( double aRedValue, double aGreenValue, double aBlueValue )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOLORS*) m_node )->AddColor( aRedValue, aGreenValue, aBlueValue );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::AddColor( const SGCOLOR& aColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOLORS*) m_node )->AddColor( aColor );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_coordindex.h"
|
||||
#include "3d_cache/sg/sg_coordindex.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_COORDINDEX::IFSG_COORDINDEX( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return;
|
||||
|
||||
m_node = new SGCOORDINDEX( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COORDINDEX::IFSG_COORDINDEX( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGCOORDINDEX( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COORDINDEX::IFSG_COORDINDEX( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
if( !pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node = new SGCOORDINDEX( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDINDEX::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_COORDINDEX != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDINDEX::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGCOORDINDEX( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGCOORDINDEX" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDINDEX::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_coords.h"
|
||||
#include "3d_cache/sg/sg_coords.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_COORDS::IFSG_COORDS( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return ;
|
||||
|
||||
m_node = new SGCOORDS( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COORDS::IFSG_COORDS( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGCOORDS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COORDS::IFSG_COORDS( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( !pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGCOORDS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_COORDS != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGCOORDS( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGCOORDS" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGCOORDS*) m_node )->GetCoordsList( aListSize, aCoordsList );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOORDS*) m_node )->SetCoordsList( aListSize, aCoordsList );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::AddCoord( double aXValue, double aYValue, double aZValue )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOORDS*) m_node )->AddCoord( aXValue, aYValue, aZValue );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::AddCoord( const SGPOINT& aPoint )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOORDS*) m_node )->AddCoord( aPoint );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_faceset.h"
|
||||
#include "3d_cache/sg/sg_faceset.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_FACESET::IFSG_FACESET( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return ;
|
||||
|
||||
m_node = new SGFACESET( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_FACESET::IFSG_FACESET( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGFACESET( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_FACESET::IFSG_FACESET( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( ! pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGFACESET( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_FACESET::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_FACESET != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_FACESET::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGFACESET( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGFACESET" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_FACESET::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_FACESET::CalcNormals( SGNODE** aPtr )
|
||||
{
|
||||
if( m_node )
|
||||
return ( (SGFACESET*) m_node )->CalcNormals( aPtr );
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_index.h"
|
||||
#include "3d_cache/sg/sg_coordindex.h"
|
||||
|
||||
|
||||
IFSG_INDEX::IFSG_INDEX() : IFSG_NODE()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_INDEX::GetIndices( size_t& nIndices, int*& aIndexList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGINDEX*) m_node )->GetIndices( nIndices, aIndexList );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_INDEX::SetIndices( size_t nIndices, int* aIndexList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGINDEX*) m_node )->SetIndices( nIndices, aIndexList );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_INDEX::AddIndex( int aIndex )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGINDEX*) m_node )->AddIndex( aIndex );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_node.h"
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
#include "plugins/3dapi/ifsg_api.h"
|
||||
|
||||
|
||||
// collection of common error strings used by the wrappers
|
||||
char BadObject[] = " * [BUG] operating on an invalid wrapper (object may have been deleted)";
|
||||
char BadOperand[] = " * [BUG] parameter aNode is an invalid wrapper; its data may have been deleted";
|
||||
char BadParent[] = " * [BUG] invalid parent node (data may have been deleted)";
|
||||
char WrongParent[] = " * [BUG] parent node type is incompatible";
|
||||
|
||||
|
||||
IFSG_NODE::IFSG_NODE()
|
||||
{
|
||||
m_node = nullptr;
|
||||
}
|
||||
|
||||
|
||||
IFSG_NODE::~IFSG_NODE()
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
void IFSG_NODE::Destroy( void )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* IFSG_NODE::GetRawPtr( void ) noexcept
|
||||
{
|
||||
return m_node;
|
||||
}
|
||||
|
||||
|
||||
S3D::SGTYPES IFSG_NODE::GetNodeType( void ) const
|
||||
{
|
||||
wxCHECK( m_node, S3D::SGTYPE_END );
|
||||
|
||||
return m_node->GetNodeType();
|
||||
}
|
||||
|
||||
|
||||
SGNODE* IFSG_NODE::GetParent( void ) const
|
||||
{
|
||||
wxCHECK( m_node, nullptr );
|
||||
|
||||
return m_node->GetParent();
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::SetParent( SGNODE* aParent )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return m_node->SetParent( aParent );
|
||||
}
|
||||
|
||||
|
||||
const char* IFSG_NODE::GetName( void )
|
||||
{
|
||||
wxCHECK( m_node, nullptr );
|
||||
|
||||
return m_node->GetName();
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::SetName( const char* aName )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
m_node->SetName( aName );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const char* IFSG_NODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const
|
||||
{
|
||||
wxCHECK( m_node, nullptr );
|
||||
|
||||
return m_node->GetNodeTypeName( aNodeType );
|
||||
}
|
||||
|
||||
|
||||
SGNODE* IFSG_NODE::FindNode( const char* aNodeName )
|
||||
{
|
||||
wxCHECK( m_node, nullptr );
|
||||
|
||||
return m_node->FindNode( aNodeName, nullptr );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::AddRefNode( SGNODE* aNode )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return m_node->AddRefNode( aNode );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::AddRefNode( IFSG_NODE& aNode )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
SGNODE* np = aNode.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return m_node->AddRefNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::AddChildNode( SGNODE* aNode )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return m_node->AddChildNode( aNode );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::AddChildNode( IFSG_NODE& aNode )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
SGNODE* np = aNode.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return m_node->AddChildNode( np );
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_normals.h"
|
||||
#include "3d_cache/sg/sg_normals.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_NORMALS::IFSG_NORMALS( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return;
|
||||
|
||||
m_node = new SGNORMALS( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_NORMALS::IFSG_NORMALS( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGNORMALS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_NORMALS::IFSG_NORMALS( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( ! pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGNORMALS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_NORMALS != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGNORMALS( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGNORMALS" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGNORMALS*) m_node )->GetNormalList( aListSize, aNormalList );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::SetNormalList( size_t aListSize, const SGVECTOR* aNormalList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGNORMALS*) m_node )->SetNormalList( aListSize, aNormalList );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::AddNormal( double aXValue, double aYValue, double aZValue )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGNORMALS*) m_node )->AddNormal( aXValue, aYValue, aZValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::AddNormal( const SGVECTOR& aNormal )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGNORMALS*) m_node )->AddNormal( aNormal );
|
||||
return true;
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_shape.h"
|
||||
#include "3d_cache/sg/sg_shape.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_SHAPE::IFSG_SHAPE( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return ;
|
||||
|
||||
m_node = new SGSHAPE( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_SHAPE::IFSG_SHAPE( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGSHAPE( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_SHAPE::IFSG_SHAPE( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( !pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGSHAPE( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_SHAPE::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_SHAPE != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_SHAPE::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGSHAPE( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGSHAPE" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_SHAPE::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_transform.h"
|
||||
#include "3d_cache/sg/scenegraph.h"
|
||||
|
||||
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_TRANSFORM::IFSG_TRANSFORM( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return;
|
||||
|
||||
m_node = new SCENEGRAPH( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_TRANSFORM::IFSG_TRANSFORM( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SCENEGRAPH( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_TRANSFORM != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SCENEGRAPH( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SCENEGRAPH" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetRotation( const SGVECTOR& aRotationAxis, double aAngle )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SCENEGRAPH*) m_node )->rotation_axis = aRotationAxis;
|
||||
( (SCENEGRAPH*) m_node )->rotation_angle = aAngle;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetScale( const SGPOINT& aScale ) noexcept
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SCENEGRAPH*) m_node )->scale = aScale;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetScale( double aScale )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
if( aScale < 1e-8 && aScale > -1e-8 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] |scale| is < 1e-8 - this seems strange" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
( (SCENEGRAPH*) m_node )->scale = SGPOINT( aScale, aScale, aScale );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetTranslation( const SGPOINT& aTranslation ) noexcept
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SCENEGRAPH*) m_node )->translation = aTranslation;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetScaleOrientation( const SGVECTOR& aScaleAxis, double aAngle )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SCENEGRAPH*) m_node )->scale_axis = aScaleAxis;
|
||||
( (SCENEGRAPH*) m_node )->scale_angle = aAngle;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetCenter( const SGPOINT& aCenter ) noexcept
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SCENEGRAPH*) m_node )->center = aCenter;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,733 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/ext.hpp>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/scenegraph.h"
|
||||
#include "3d_cache/sg/sg_shape.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
SCENEGRAPH::SCENEGRAPH( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_TRANSFORM;
|
||||
rotation_angle = 0.0;
|
||||
scale_angle = 0.0;
|
||||
|
||||
scale.x = 1.0;
|
||||
scale.y = 1.0;
|
||||
scale.z = 1.0;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] inappropriate parent to SCENEGRAPH (type %d)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SCENEGRAPH::~SCENEGRAPH()
|
||||
{
|
||||
// drop references
|
||||
DROP_REFS( SCENEGRAPH, m_RTransforms );
|
||||
DROP_REFS( SGSHAPE, m_RShape );
|
||||
|
||||
// delete owned objects
|
||||
DEL_OBJS( SCENEGRAPH, m_Transforms );
|
||||
DEL_OBJS( SGSHAPE, m_Shape );
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a transform may be parent to a transform
|
||||
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SCENEGRAPH::FindNode(const char *aNodeName, const SGNODE *aCaller)
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
FIND_NODE( SCENEGRAPH, aNodeName, m_Transforms, aCaller );
|
||||
FIND_NODE( SGSHAPE, aNodeName, m_Shape, aCaller );
|
||||
|
||||
// query the parent if appropriate
|
||||
if( aCaller == m_Parent || nullptr == m_Parent )
|
||||
return nullptr;
|
||||
|
||||
return m_Parent->FindNode( aNodeName, this );
|
||||
}
|
||||
|
||||
|
||||
void SCENEGRAPH::unlinkNode( const SGNODE* aNode, bool isChild )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return;
|
||||
|
||||
switch( aNode->GetNodeType() )
|
||||
{
|
||||
case S3D::SGTYPE_TRANSFORM:
|
||||
UNLINK_NODE( S3D::SGTYPE_TRANSFORM, SCENEGRAPH, aNode, m_Transforms, m_RTransforms,
|
||||
isChild );
|
||||
break;
|
||||
|
||||
case S3D::SGTYPE_SHAPE:
|
||||
UNLINK_NODE( S3D::SGTYPE_SHAPE, SGSHAPE, aNode, m_Shape, m_RShape, isChild );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
void SCENEGRAPH::unlinkChildNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, true );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SCENEGRAPH::unlinkRefNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, false );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::addNode( SGNODE* aNode, bool isChild )
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
ADD_NODE( S3D::SGTYPE_TRANSFORM, SCENEGRAPH, aNode, m_Transforms, m_RTransforms, isChild );
|
||||
ADD_NODE( S3D::SGTYPE_SHAPE, SGSHAPE, aNode, m_Shape, m_RShape, isChild );
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] object '%s' is not a valid type for this object (%d)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aNode->GetName(),
|
||||
aNode->GetNodeType() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::AddRefNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, false );
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::AddChildNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, true );
|
||||
}
|
||||
|
||||
|
||||
void SCENEGRAPH::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
|
||||
// rename all shapes
|
||||
do
|
||||
{
|
||||
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
|
||||
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->ReNameNodes();
|
||||
++sL;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
// rename all transforms
|
||||
do
|
||||
{
|
||||
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
|
||||
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->ReNameNodes();
|
||||
++sL;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( m_Transforms.empty() && m_RTransforms.empty() && m_Shape.empty() && m_RShape.empty() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << "DEF " << GetName() << " Transform {\n";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << "USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " Transform {\n";
|
||||
}
|
||||
|
||||
// convert center to 1VRML unit = 0.1 inch
|
||||
SGPOINT pt = center;
|
||||
pt.x /= 2.54;
|
||||
pt.y /= 2.54;
|
||||
pt.z /= 2.54;
|
||||
|
||||
S3D::FormatPoint( tmp, pt );
|
||||
aFile << " center " << tmp << "\n";
|
||||
S3D::FormatOrientation( tmp, rotation_axis, rotation_angle );
|
||||
aFile << " rotation " << tmp << "\n";
|
||||
S3D::FormatPoint( tmp, scale );
|
||||
aFile << " scale " << tmp << "\n";
|
||||
S3D::FormatOrientation( tmp, scale_axis, scale_angle );
|
||||
aFile << " scaleOrientation " << tmp << "\n";
|
||||
|
||||
// convert translation to 1VRML unit = 0.1 inch
|
||||
pt = translation;
|
||||
pt.x /= 2.54;
|
||||
pt.y /= 2.54;
|
||||
pt.z /= 2.54;
|
||||
S3D::FormatPoint( tmp, pt );
|
||||
aFile << " translation " << tmp << "\n";
|
||||
|
||||
aFile << " children [\n";
|
||||
|
||||
if( !m_Transforms.empty() )
|
||||
{
|
||||
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
|
||||
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->WriteVRML( aFile, aReuseFlag );
|
||||
++sL;
|
||||
}
|
||||
}
|
||||
|
||||
if( !m_RTransforms.empty() )
|
||||
{
|
||||
std::vector< SCENEGRAPH* >::iterator sL = m_RTransforms.begin();
|
||||
std::vector< SCENEGRAPH* >::iterator eL = m_RTransforms.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->WriteVRML( aFile, aReuseFlag );
|
||||
++sL;
|
||||
}
|
||||
}
|
||||
|
||||
if( !m_Shape.empty() )
|
||||
{
|
||||
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
|
||||
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->WriteVRML( aFile, aReuseFlag );
|
||||
++sL;
|
||||
}
|
||||
}
|
||||
|
||||
if( !m_RShape.empty() )
|
||||
{
|
||||
std::vector< SGSHAPE* >::iterator sL = m_RShape.begin();
|
||||
std::vector< SGSHAPE* >::iterator eL = m_RShape.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->WriteVRML( aFile, aReuseFlag );
|
||||
++sL;
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "] }\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode && nullptr != m_Parent )
|
||||
{
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( nullptr == m_Parent )
|
||||
{
|
||||
// ensure unique node names
|
||||
ResetNodeIndex();
|
||||
ReNameNodes();
|
||||
}
|
||||
|
||||
if( aFile.fail() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
S3D::WritePoint( aFile, center );
|
||||
S3D::WritePoint( aFile, translation );
|
||||
S3D::WriteVector( aFile, rotation_axis );
|
||||
aFile.write( (char*)&rotation_angle, sizeof( rotation_angle ) );
|
||||
S3D::WritePoint( aFile, scale );
|
||||
S3D::WriteVector( aFile, scale_axis );
|
||||
aFile.write( (char*)&scale_angle, sizeof( scale_angle ) );
|
||||
|
||||
// Transfer ownership of any Transform references which hadn't been written
|
||||
size_t asize = m_RTransforms.size();
|
||||
size_t i;
|
||||
|
||||
for( i = 0; i < asize; ++i )
|
||||
{
|
||||
if( !m_RTransforms[i]->isWritten() )
|
||||
{
|
||||
m_RTransforms[i]->SwapParent( this );
|
||||
--asize;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer ownership of any Shape references which hadn't been written
|
||||
asize = m_RShape.size();
|
||||
|
||||
for( i = 0; i < asize; ++i )
|
||||
{
|
||||
if( !m_RShape[i]->isWritten() )
|
||||
{
|
||||
m_RShape[i]->SwapParent( this );
|
||||
--asize;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
asize = m_Transforms.size();
|
||||
aFile.write( (char*)&asize, sizeof( size_t ) );
|
||||
asize = m_RTransforms.size();
|
||||
aFile.write( (char*)&asize, sizeof( size_t ) );
|
||||
asize = m_Shape.size();
|
||||
aFile.write( (char*)&asize, sizeof( size_t ) );
|
||||
asize = m_RShape.size();
|
||||
aFile.write( (char*)&asize, sizeof( size_t ) );
|
||||
asize = m_Transforms.size();
|
||||
|
||||
// write child transforms
|
||||
for( i = 0; i < asize; ++i )
|
||||
{
|
||||
if( !m_Transforms[i]->WriteCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [INFO] bad stream while writing child transforms" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// write referenced transform names
|
||||
asize = m_RTransforms.size();
|
||||
|
||||
for( i = 0; i < asize; ++i )
|
||||
aFile << "[" << m_RTransforms[i]->GetName() << "]";
|
||||
|
||||
// write child shapes
|
||||
asize = m_Shape.size();
|
||||
|
||||
for( i = 0; i < asize; ++i )
|
||||
{
|
||||
if( !m_Shape[i]->WriteCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [INFO] bad stream while writing child shapes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// write referenced transform names
|
||||
asize = m_RShape.size();
|
||||
|
||||
for( i = 0; i < asize; ++i )
|
||||
aFile << "[" << m_RShape[i]->GetName() << "]";
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( m_Transforms.empty() && m_RTransforms.empty() && m_Shape.empty() && m_RShape.empty(),
|
||||
false );
|
||||
|
||||
std::string name; // name of the node
|
||||
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
// we need to read the tag and verify its type
|
||||
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; tag mismatch at position "
|
||||
"%ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Name = name;
|
||||
}
|
||||
|
||||
// read fixed member data
|
||||
S3D::ReadPoint( aFile, center );
|
||||
S3D::ReadPoint( aFile, translation );
|
||||
S3D::ReadVector( aFile, rotation_axis );
|
||||
aFile.read( (char*)&rotation_angle, sizeof( rotation_angle ) );
|
||||
S3D::ReadPoint( aFile, scale );
|
||||
S3D::ReadVector( aFile, scale_axis );
|
||||
aFile.read( (char*)&scale_angle, sizeof( scale_angle ) );
|
||||
|
||||
size_t sizeCT = 0; // child transforms
|
||||
size_t sizeRT = 0; // referenced transforms
|
||||
size_t sizeCS = 0; // child shapes
|
||||
size_t sizeRS = 0; // referenced shapes
|
||||
|
||||
aFile.read( (char*)&sizeCT, sizeof( size_t ) );
|
||||
aFile.read( (char*)&sizeRT, sizeof( size_t ) );
|
||||
aFile.read( (char*)&sizeCS, sizeof( size_t ) );
|
||||
aFile.read( (char*)&sizeRS, sizeof( size_t ) );
|
||||
|
||||
size_t i;
|
||||
|
||||
// read child transforms
|
||||
for( i = 0; i < sizeCT; ++i )
|
||||
{
|
||||
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child transform tag "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SCENEGRAPH* sp = new SCENEGRAPH( this );
|
||||
sp->SetName( name.c_str() );
|
||||
|
||||
if( !sp->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading transform "
|
||||
"%ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// read referenced transforms
|
||||
for( i = 0; i < sizeRT; ++i )
|
||||
{
|
||||
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref transform tag at "
|
||||
"position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* sp = FindNode( name.c_str(), this );
|
||||
|
||||
if( !sp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref "
|
||||
"transform at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_TRANSFORM != sp->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not TRANSFORM "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AddRefNode( sp );
|
||||
}
|
||||
|
||||
// read child shapes
|
||||
for( i = 0; i < sizeCS; ++i )
|
||||
{
|
||||
if( S3D::SGTYPE_SHAPE != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child shape tag at "
|
||||
"position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGSHAPE* sp = new SGSHAPE( this );
|
||||
sp->SetName( name.c_str() );
|
||||
|
||||
if( !sp->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; corrupt data while "
|
||||
"reading shape at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// read referenced shapes
|
||||
for( i = 0; i < sizeRS; ++i )
|
||||
{
|
||||
if( S3D::SGTYPE_SHAPE != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref shape tag at "
|
||||
"position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* sp = FindNode( name.c_str(), this );
|
||||
|
||||
if( !sp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref shape "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_SHAPE != sp->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGSHAPE at "
|
||||
"position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AddRefNode( sp );
|
||||
}
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
|
||||
std::vector< SMESH >& meshes )
|
||||
{
|
||||
// calculate the accumulated transform
|
||||
double rX, rY, rZ;
|
||||
|
||||
// rotation
|
||||
rotation_axis.GetVector( rX, rY, rZ );
|
||||
glm::dmat4 rM = glm::rotate( glm::dmat4( 1.0 ), rotation_angle, glm::dvec3( rX, rY, rZ ) );
|
||||
|
||||
// translation
|
||||
glm::dmat4 tM = glm::translate( glm::dmat4( 1.0 ), glm::dvec3( translation.x, translation.y,
|
||||
translation.z ) );
|
||||
// center
|
||||
glm::dmat4 cM = glm::translate( glm::dmat4( 1.0 ), glm::dvec3( center.x, center.y, center.z ) );
|
||||
glm::dmat4 ncM = glm::translate( glm::dmat4( 1.0 ), glm::dvec3( -center.x, -center.y,
|
||||
-center.z ) );
|
||||
|
||||
// scale
|
||||
glm::dmat4 sM = glm::scale( glm::dmat4( 1.0 ), glm::dvec3( scale.x, scale.y, scale.z ) );
|
||||
|
||||
// scaleOrientation
|
||||
scale_axis.GetVector( rX, rY, rZ );
|
||||
glm::dmat4 srM = glm::rotate( glm::dmat4( 1.0 ), scale_angle, glm::dvec3( rX, rY, rZ ) );
|
||||
glm::dmat4 nsrM = glm::rotate( glm::dmat4( 1.0 ), -scale_angle, glm::dvec3( rX, rY, rZ ) );
|
||||
|
||||
// resultant point:
|
||||
// P' = T x C x R x SR x S x -SR x -C x P
|
||||
// resultant transform:
|
||||
// tx0 = tM * cM * rM * srM * sM * nsrM * ncM
|
||||
glm::dmat4 tx0;
|
||||
|
||||
if( nullptr != aTransform )
|
||||
tx0 = (*aTransform) * tM * cM * rM * srM * sM * nsrM * ncM;
|
||||
else
|
||||
tx0 = tM * cM * rM * srM * sM * nsrM * ncM;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
// prepare all shapes
|
||||
do
|
||||
{
|
||||
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
|
||||
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
|
||||
|
||||
while( sL != eL && ok )
|
||||
{
|
||||
ok = (*sL)->Prepare( &tx0, materials, meshes );
|
||||
++sL;
|
||||
}
|
||||
|
||||
sL = m_RShape.begin();
|
||||
eL = m_RShape.end();
|
||||
|
||||
while( sL != eL && ok )
|
||||
{
|
||||
ok = (*sL)->Prepare( &tx0, materials, meshes );
|
||||
++sL;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
// prepare all transforms
|
||||
do
|
||||
{
|
||||
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
|
||||
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
|
||||
|
||||
while( sL != eL && ok )
|
||||
{
|
||||
ok = (*sL)->Prepare( &tx0, materials, meshes );
|
||||
++sL;
|
||||
}
|
||||
|
||||
sL = m_RTransforms.begin();
|
||||
eL = m_RTransforms.end();
|
||||
|
||||
while( sL != eL && ok )
|
||||
{
|
||||
ok = (*sL)->Prepare( &tx0, materials, meshes );
|
||||
++sL;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
return ok;
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file scenegraph.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SCENE_GRAPH_H
|
||||
#define SCENE_GRAPH_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
class SGSHAPE;
|
||||
|
||||
/**
|
||||
* Define the basic data set required to represent a 3D model.
|
||||
*
|
||||
* This model must remain compatible with VRML2.0 in order to facilitate VRML export of
|
||||
* scene graph data created by available 3D plugins.
|
||||
*/
|
||||
class SCENEGRAPH : public SGNODE
|
||||
{
|
||||
public:
|
||||
void unlinkChildNode( const SGNODE* aNode ) override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) override;
|
||||
|
||||
SCENEGRAPH( SGNODE* aParent );
|
||||
virtual ~SCENEGRAPH();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) override;
|
||||
bool AddRefNode( SGNODE* aNode ) override;
|
||||
bool AddChildNode( SGNODE* aNode ) override;
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
bool Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
|
||||
std::vector< SMESH >& meshes );
|
||||
|
||||
private:
|
||||
void unlinkNode( const SGNODE* aNode, bool isChild );
|
||||
bool addNode( SGNODE* aNode, bool isChild );
|
||||
|
||||
public:
|
||||
// note: order of transformation is Translate, Rotate, Offset
|
||||
SGPOINT center;
|
||||
SGPOINT translation;
|
||||
SGVECTOR rotation_axis;
|
||||
double rotation_angle; // radians
|
||||
SGPOINT scale;
|
||||
SGVECTOR scale_axis;
|
||||
double scale_angle; // radians
|
||||
|
||||
private:
|
||||
// The following are items which may be defined for reuse
|
||||
// in a VRML output file. They do not necessarily correspond
|
||||
// to the use of DEF within a VRML input file; it is the
|
||||
// responsibility of the plugin to perform any necessary
|
||||
// conversions to comply with the restrictions imposed by
|
||||
// this scene graph structure
|
||||
std::vector< SCENEGRAPH* > m_Transforms; // local Transform nodes
|
||||
std::vector< SGSHAPE* > m_Shape; // local Shape nodes
|
||||
|
||||
std::vector< SCENEGRAPH* > m_RTransforms; // referenced Transform nodes
|
||||
std::vector< SGSHAPE* > m_RShape; // referenced Shape nodes
|
||||
};
|
||||
|
||||
/*
|
||||
p.120
|
||||
Transform {
|
||||
center 0 0 0
|
||||
children []
|
||||
rotation 0 0 1 0
|
||||
scale 1 1 1
|
||||
scaleOrientation 0 0 1 0
|
||||
translation 0 0 0
|
||||
bboxCenter 0 0 0
|
||||
bboxSize -1 -1 -1
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // SCENE_GRAPH_H
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_appearance.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
SGAPPEARANCE::SGAPPEARANCE( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_APPEARANCE;
|
||||
|
||||
// defaults in accord with VRML2.0 spec
|
||||
ambient.SetColor( 0.05317f, 0.17879f, 0.01804f );
|
||||
shininess = 0.2f;
|
||||
transparency = 0.0f;
|
||||
diffuse.SetColor( 0.8f, 0.8f, 0.8f );
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGAPPEARANCE (type %s )" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGAPPEARANCE::~SGAPPEARANCE()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGSHAPE may be parent to a SGAPPEARANCE
|
||||
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetEmissive( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
return emissive.SetColor( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetEmissive( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
return emissive.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetEmissive( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
return emissive.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetDiffuse( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
return diffuse.SetColor( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetDiffuse( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
return diffuse.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetDiffuse( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
return diffuse.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetSpecular( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
return specular.SetColor( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetSpecular( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
return specular.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
bool SGAPPEARANCE::SetSpecular( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
return specular.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetAmbient( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
return ambient.SetColor( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetAmbient( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
return ambient.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetAmbient( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
return ambient.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGAPPEARANCE::FindNode( const char* aNodeName, const SGNODE* aCaller) noexcept
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGAPPEARANCE::unlinkChildNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aCaller, /* void */,
|
||||
wxT( "unexpected code branch; node should have no children or refs" ) );
|
||||
}
|
||||
|
||||
|
||||
void SGAPPEARANCE::unlinkRefNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aCaller, /* void */,
|
||||
wxT( "unexpected code branch; node should have no children or refs" ) );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::AddRefNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aNode, false, wxT( "this node does not accept children or refs" ) );
|
||||
|
||||
// This is redundant but it keeps gcc from generating a warning on debug builds.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::AddChildNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aNode, false, wxT( "this node does not accept children or refs" ) );
|
||||
|
||||
// This is redundant but it keeps gcc from generating a warning on debug builds.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void SGAPPEARANCE::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << " appearance DEF " << GetName() << " Appearance {\n";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " appearance USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " appearance Appearance {\n";
|
||||
}
|
||||
|
||||
aFile << " material Material {\n";
|
||||
|
||||
std::string tmp;
|
||||
float ambr, ambg, ambb;
|
||||
ambient.GetColor( ambr, ambg, ambb );
|
||||
float amb = ( 0.212671 * ambr + 0.71516 * ambg + 0.072169 * ambb );
|
||||
diffuse.GetColor( ambr, ambg, ambb );
|
||||
float den = ( 0.212671 * ambr + 0.71516 * ambg + 0.072169 * ambb );
|
||||
|
||||
if( den < 0.004f )
|
||||
den = 0.004f;
|
||||
|
||||
amb /= den;
|
||||
|
||||
if( amb > 1.0f )
|
||||
amb = 1.0f;
|
||||
|
||||
S3D::FormatFloat( tmp, amb );
|
||||
aFile << " ambientIntensity " << tmp << "\n";
|
||||
|
||||
float red, green, blue;
|
||||
diffuse.GetColor( red, green, blue );
|
||||
S3D::FormatFloat( tmp, red );
|
||||
aFile << " diffuseColor " << tmp << " ";
|
||||
S3D::FormatFloat( tmp, green );
|
||||
aFile << tmp << " ";
|
||||
S3D::FormatFloat( tmp, blue);
|
||||
aFile << tmp << "\n";
|
||||
|
||||
emissive.GetColor( red, green, blue );
|
||||
S3D::FormatFloat( tmp, red );
|
||||
aFile << " emissiveColor " << tmp << " ";
|
||||
S3D::FormatFloat( tmp, green );
|
||||
aFile << tmp << " ";
|
||||
S3D::FormatFloat( tmp, blue);
|
||||
aFile << tmp << "\n";
|
||||
|
||||
S3D::FormatFloat( tmp, shininess );
|
||||
aFile << " shininess " << tmp << "\n";
|
||||
|
||||
specular.GetColor( red, green, blue );
|
||||
S3D::FormatFloat( tmp, red );
|
||||
aFile << " specularColor " << tmp << " ";
|
||||
S3D::FormatFloat( tmp, green );
|
||||
aFile << tmp << " ";
|
||||
S3D::FormatFloat( tmp, blue);
|
||||
aFile << tmp << "\n";
|
||||
|
||||
S3D::FormatFloat( tmp, transparency );
|
||||
aFile << " transparency " << tmp << "\n";
|
||||
|
||||
aFile << "} }\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK_MSG( m_Parent, false, wxT( "corrupt data; m_aParent is NULL" ) );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK_MSG( parentNode == m_Parent, false, wxT( "corrupt data; parentNode != m_aParent" ) );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
S3D::WriteColor( aFile, ambient );
|
||||
aFile.write( (char*) &shininess, sizeof( shininess ) );
|
||||
aFile.write( (char*) &transparency, sizeof( transparency ) );
|
||||
S3D::WriteColor( aFile, diffuse );
|
||||
S3D::WriteColor( aFile, emissive );
|
||||
S3D::WriteColor( aFile, specular );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
S3D::ReadColor( aFile, ambient );
|
||||
aFile.read( (char*) &shininess, sizeof( shininess ) );
|
||||
aFile.read( (char*) &transparency, sizeof( transparency ) );
|
||||
S3D::ReadColor( aFile, diffuse );
|
||||
S3D::ReadColor( aFile, emissive );
|
||||
S3D::ReadColor( aFile, specular );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_appearance.h
|
||||
*/
|
||||
|
||||
#ifndef SG_APPEARANCE_H
|
||||
#define SG_APPEARANCE_H
|
||||
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
/**
|
||||
* Defines the generic material appearance of a scenegraph object.
|
||||
*/
|
||||
class SGAPPEARANCE : public SGNODE
|
||||
{
|
||||
public:
|
||||
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
|
||||
|
||||
SGAPPEARANCE( SGNODE* aParent );
|
||||
virtual ~SGAPPEARANCE();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
bool SetEmissive( float aRVal, float aGVal, float aBVal );
|
||||
bool SetEmissive( const SGCOLOR* aRGBColor );
|
||||
bool SetEmissive( const SGCOLOR& aRGBColor );
|
||||
|
||||
bool SetDiffuse( float aRVal, float aGVal, float aBVal );
|
||||
bool SetDiffuse( const SGCOLOR* aRGBColor );
|
||||
bool SetDiffuse( const SGCOLOR& aRGBColor );
|
||||
|
||||
bool SetSpecular( float aRVal, float aGVal, float aBVal );
|
||||
bool SetSpecular( const SGCOLOR* aRGBColor );
|
||||
bool SetSpecular( const SGCOLOR& aRGBColor );
|
||||
|
||||
bool SetAmbient( float aRVal, float aGVal, float aBVal );
|
||||
bool SetAmbient( const SGCOLOR* aRGBColor );
|
||||
bool SetAmbient( const SGCOLOR& aRGBColor );
|
||||
|
||||
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override;
|
||||
bool AddRefNode( SGNODE* aNode ) noexcept override;
|
||||
bool AddChildNode( SGNODE* aNode ) noexcept override;
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
float shininess; // default 0.2
|
||||
float transparency; // default 0.0
|
||||
SGCOLOR ambient; // default 0.05317 0.17879 0.01804
|
||||
SGCOLOR diffuse; // default 0.8 0.8 0.8
|
||||
SGCOLOR emissive; // default 0.0 0.0 0.0
|
||||
SGCOLOR specular; // default 0.0 0.0 0.0
|
||||
|
||||
};
|
||||
|
||||
#endif // SG_APPEARANCE_H
|
||||
@@ -1,276 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/sg_base.h"
|
||||
|
||||
|
||||
SGCOLOR::SGCOLOR()
|
||||
{
|
||||
red = 0.0;
|
||||
green = 0.0;
|
||||
blue = 0.0;
|
||||
}
|
||||
|
||||
SGCOLOR::SGCOLOR( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
if( !checkRange( aRVal, aGVal, aBVal ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid value passed to constructor" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
red = 0.0;
|
||||
green = 0.0;
|
||||
blue = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
red = aRVal;
|
||||
green = aGVal;
|
||||
blue = aBVal;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLOR::GetColor( float& aRedVal, float& aGreenVal, float& aBlueVal ) const noexcept
|
||||
{
|
||||
aRedVal = red;
|
||||
aGreenVal = green;
|
||||
aBlueVal = blue;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLOR::GetColor( SGCOLOR& aColor ) const noexcept
|
||||
{
|
||||
aColor.red = red;
|
||||
aColor.green = green;
|
||||
aColor.blue = blue;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLOR::GetColor( SGCOLOR* aColor ) const noexcept
|
||||
{
|
||||
wxCHECK_MSG( aColor, /* void */, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
aColor->red = red;
|
||||
aColor->green = green;
|
||||
aColor->blue = blue;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLOR::SetColor( float aRedVal, float aGreenVal, float aBlueVal )
|
||||
{
|
||||
if( !checkRange( aRedVal, aGreenVal, aBlueVal ) )
|
||||
return false;
|
||||
|
||||
red = aRedVal;
|
||||
green = aGreenVal;
|
||||
blue = aBlueVal;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLOR::SetColor( const SGCOLOR& aColor ) noexcept
|
||||
{
|
||||
red = aColor.red;
|
||||
green = aColor.green;
|
||||
blue = aColor.blue;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLOR::SetColor( const SGCOLOR* aColor ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
red = aColor->red;
|
||||
green = aColor->green;
|
||||
blue = aColor->blue;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLOR::checkRange( float aRedVal, float aGreenVal, float aBlueVal ) const noexcept
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if( aRedVal < 0.0 || aRedVal > 1.0 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid RED value: %g" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aRedVal );
|
||||
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if( aGreenVal < 0.0 || aGreenVal > 1.0 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid GREEN value: %g" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aGreenVal );
|
||||
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if( aBlueVal < 0.0 || aBlueVal > 1.0 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid BLUE value: %g" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aBlueVal );
|
||||
|
||||
ok = false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
SGPOINT::SGPOINT()
|
||||
{
|
||||
x = 0.0;
|
||||
y = 0.0;
|
||||
z = 0.0;
|
||||
}
|
||||
|
||||
|
||||
SGPOINT::SGPOINT( double aXVal, double aYVal, double aZVal ) noexcept
|
||||
{
|
||||
x = aXVal;
|
||||
y = aYVal;
|
||||
z = aZVal;
|
||||
}
|
||||
|
||||
|
||||
void SGPOINT::GetPoint( const double& aXVal, const double& aYVal, const double& aZVal ) noexcept
|
||||
{
|
||||
x = aXVal;
|
||||
y = aYVal;
|
||||
z = aZVal;
|
||||
}
|
||||
|
||||
|
||||
void SGPOINT::GetPoint( const SGPOINT& aPoint ) noexcept
|
||||
{
|
||||
x = aPoint.x;
|
||||
y = aPoint.y;
|
||||
z = aPoint.z;
|
||||
}
|
||||
|
||||
|
||||
void SGPOINT::GetPoint( const SGPOINT* aPoint ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aPoint, /* void */, wxT( "NULL pointer passed for aPoint" ) );
|
||||
|
||||
x = aPoint->x;
|
||||
y = aPoint->y;
|
||||
z = aPoint->z;
|
||||
}
|
||||
|
||||
|
||||
void SGPOINT::SetPoint( double aXVal, double aYVal, double aZVal ) noexcept
|
||||
{
|
||||
x = aXVal;
|
||||
y = aYVal;
|
||||
z = aZVal;
|
||||
}
|
||||
|
||||
|
||||
void SGPOINT::SetPoint( const SGPOINT& aPoint ) noexcept
|
||||
{
|
||||
x = aPoint.x;
|
||||
y = aPoint.y;
|
||||
z = aPoint.z;
|
||||
}
|
||||
|
||||
|
||||
SGVECTOR::SGVECTOR()
|
||||
{
|
||||
vx = 0.0;
|
||||
vy = 0.0;
|
||||
vz = 1.0;
|
||||
}
|
||||
|
||||
|
||||
SGVECTOR::SGVECTOR( double aXVal, double aYVal, double aZVal )
|
||||
{
|
||||
vx = aXVal;
|
||||
vy = aYVal;
|
||||
vz = aZVal;
|
||||
normalize();
|
||||
}
|
||||
|
||||
|
||||
void SGVECTOR::GetVector( double& aXVal, double& aYVal, double& aZVal ) const noexcept
|
||||
{
|
||||
aXVal = vx;
|
||||
aYVal = vy;
|
||||
aZVal = vz;
|
||||
}
|
||||
|
||||
|
||||
void SGVECTOR::SetVector( double aXVal, double aYVal, double aZVal )
|
||||
{
|
||||
vx = aXVal;
|
||||
vy = aYVal;
|
||||
vz = aZVal;
|
||||
normalize();
|
||||
}
|
||||
|
||||
|
||||
void SGVECTOR::SetVector( const SGVECTOR& aVector )
|
||||
{
|
||||
aVector.GetVector( vx, vy, vz );
|
||||
}
|
||||
|
||||
|
||||
void SGVECTOR::normalize( void ) noexcept
|
||||
{
|
||||
double dx = vx * vx;
|
||||
double dy = vy * vy;
|
||||
double dz = vz * vz;
|
||||
double dv2 = sqrt( dx + dy + dz );
|
||||
|
||||
if( ( dx + dy + dz ) < 1e-8 )
|
||||
{
|
||||
// use the default; the numbers are too small to be believable
|
||||
vx = 0.0;
|
||||
vy = 0.0;
|
||||
vz = 1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
vx /= dv2;
|
||||
vy /= dv2;
|
||||
vz /= dv2;
|
||||
}
|
||||
|
||||
|
||||
SGVECTOR& SGVECTOR::operator=( const SGVECTOR& source ) noexcept
|
||||
{
|
||||
vx = source.vx;
|
||||
vy = source.vy;
|
||||
vz = source.vz;
|
||||
return *this;
|
||||
}
|
||||
@@ -1,304 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_colors.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
SGCOLORS::SGCOLORS( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_COLORS;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGCOLORS (type %s)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGCOLORS::~SGCOLORS()
|
||||
{
|
||||
colors.clear();
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGFACESET may be parent to a SGCOLORS
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGCOLORS::FindNode(const char* aNodeName, const SGNODE *aCaller) noexcept
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::unlinkChildNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( aCaller, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::unlinkRefNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( aCaller, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::AddRefNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::AddChildNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::GetColorList( size_t& aListSize, SGCOLOR*& aColorList )
|
||||
{
|
||||
if( colors.empty() )
|
||||
{
|
||||
aListSize = 0;
|
||||
aColorList = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
aListSize = colors.size();
|
||||
aColorList = &colors[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::SetColorList( size_t aListSize, const SGCOLOR* aColorList )
|
||||
{
|
||||
colors.clear();
|
||||
|
||||
if( 0 == aListSize || nullptr == aColorList )
|
||||
return;
|
||||
|
||||
for( size_t i = 0; i < aListSize; ++i )
|
||||
colors.push_back( aColorList[i] );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::AddColor( double aRedValue, double aGreenValue, double aBlueValue )
|
||||
{
|
||||
colors.emplace_back( aRedValue, aGreenValue, aBlueValue );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::AddColor( const SGCOLOR& aColor )
|
||||
{
|
||||
colors.push_back( aColor );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( colors.empty() )
|
||||
return false;
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << "color DEF " << GetName() << " Color { color [\n ";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << "color USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << "color Color { color [\n ";
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
size_t n = colors.size();
|
||||
bool nline = false;
|
||||
|
||||
for( size_t i = 0; i < n; )
|
||||
{
|
||||
S3D::FormatColor( tmp, colors[i] );
|
||||
float r,g,b;
|
||||
colors[i].GetColor(r, g, b);
|
||||
aFile << tmp ;
|
||||
++i;
|
||||
|
||||
if( i < n )
|
||||
{
|
||||
aFile << ",";
|
||||
|
||||
if( nline )
|
||||
{
|
||||
aFile << "\n ";
|
||||
nline = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
nline = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "] }\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
size_t ncolors = colors.size();
|
||||
aFile.write( (char*)&ncolors, sizeof(size_t) );
|
||||
|
||||
for( size_t i = 0; i < ncolors; ++i )
|
||||
S3D::WriteColor( aFile, colors[i] );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( colors.empty(), false );
|
||||
|
||||
size_t ncolors;
|
||||
aFile.read( (char*) &ncolors, sizeof( size_t ) );
|
||||
SGCOLOR tmp;
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
for( size_t i = 0; i < ncolors; ++i )
|
||||
{
|
||||
if( !S3D::ReadColor( aFile, tmp ) || aFile.fail() )
|
||||
return false;
|
||||
|
||||
colors.push_back( tmp );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_colors.h
|
||||
*/
|
||||
|
||||
#ifndef SG_COLORS_H
|
||||
#define SG_COLORS_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
/**
|
||||
* Define an RGB color set for a scenegraph object.
|
||||
*/
|
||||
class SGCOLORS : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGCOLORS( SGNODE* aParent );
|
||||
virtual ~SGCOLORS();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
|
||||
|
||||
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override;
|
||||
bool AddRefNode( SGNODE* aNode ) noexcept override;
|
||||
bool AddChildNode( SGNODE* aNode ) noexcept override;
|
||||
|
||||
bool GetColorList( size_t& aListSize, SGCOLOR*& aColorList );
|
||||
void SetColorList( size_t aListSize, const SGCOLOR* aColorList );
|
||||
void AddColor( double aRedValue, double aGreenValue, double aBlueValue );
|
||||
void AddColor( const SGCOLOR& aColor );
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
std::vector< SGCOLOR > colors;
|
||||
};
|
||||
|
||||
#endif // SG_COLORS_H
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "3d_cache/sg/sg_coordindex.h"
|
||||
|
||||
|
||||
SGCOORDINDEX::SGCOORDINDEX( SGNODE* aParent ) : SGINDEX( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_COORDINDEX;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGCOORDINDEX::~SGCOORDINDEX()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDINDEX::GatherCoordIndices( std::vector< int >& aIndexList )
|
||||
{
|
||||
if( index.empty() )
|
||||
return;
|
||||
|
||||
aIndexList.insert( aIndexList.end(), index.begin(), index.end() );
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_coordindex.h
|
||||
*/
|
||||
|
||||
#ifndef SG_COORDINDEX_H
|
||||
#define SG_COORDINDEX_H
|
||||
|
||||
#include "3d_cache/sg/sg_index.h"
|
||||
|
||||
/**
|
||||
* An object to maintain a coordinate index list.
|
||||
*
|
||||
* Users must ensure that coordinate indices are specified as triplets (triangular faces)
|
||||
* since no checking is performed. In instances where it is not possible to determine which
|
||||
* side of the triangle is to be rendered (for example IGES entities) then the user must
|
||||
* supply each triplet in both point orders.
|
||||
*/
|
||||
class SGCOORDINDEX : public SGINDEX
|
||||
{
|
||||
public:
|
||||
SGCOORDINDEX( SGNODE* aParent );
|
||||
virtual ~SGCOORDINDEX();
|
||||
|
||||
/**
|
||||
* Add all coordinate indices to the given list in preparation for a normals calculation.
|
||||
*/
|
||||
void GatherCoordIndices( std::vector< int >& aIndexList );
|
||||
};
|
||||
|
||||
#endif // SG_COORDINDEX_H
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_coords.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
#include "3d_cache/sg/sg_normals.h"
|
||||
#include "3d_cache/sg/sg_faceset.h"
|
||||
|
||||
|
||||
SGCOORDS::SGCOORDS( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_COORDS;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGCOORDS (type %s)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGCOORDS::~SGCOORDS()
|
||||
{
|
||||
coords.clear();
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGFACESET may be parent to a SGCOORDS
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGCOORDS::FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::unlinkChildNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( aCaller, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::unlinkRefNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( aCaller, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::AddRefNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::AddChildNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList )
|
||||
{
|
||||
if( coords.empty() )
|
||||
{
|
||||
aListSize = 0;
|
||||
aCoordsList = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
aListSize = coords.size();
|
||||
aCoordsList = &coords[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
|
||||
{
|
||||
coords.clear();
|
||||
|
||||
if( 0 == aListSize || nullptr == aCoordsList )
|
||||
return;
|
||||
|
||||
for( size_t i = 0; i < aListSize; ++i )
|
||||
coords.push_back( aCoordsList[i] );
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::AddCoord( double aXValue, double aYValue, double aZValue )
|
||||
{
|
||||
coords.emplace_back( aXValue, aYValue, aZValue );
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::AddCoord( const SGPOINT& aPoint )
|
||||
{
|
||||
coords.push_back( aPoint );
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( coords.empty() )
|
||||
return false;
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << " coord DEF " << GetName() << " Coordinate { point [\n ";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " coord USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " coord Coordinate { point [\n ";
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
size_t n = coords.size();
|
||||
bool nline = false;
|
||||
SGPOINT pt;
|
||||
|
||||
for( size_t i = 0; i < n; )
|
||||
{
|
||||
// ensure VRML output has 1U = 0.1 inch as per legacy kicad expectations
|
||||
pt = coords[i];
|
||||
pt.x /= 2.54;
|
||||
pt.y /= 2.54;
|
||||
pt.z /= 2.54;
|
||||
S3D::FormatPoint( tmp, pt );
|
||||
aFile << tmp ;
|
||||
++i;
|
||||
|
||||
if( i < n )
|
||||
{
|
||||
aFile << ",";
|
||||
|
||||
if( nline )
|
||||
{
|
||||
aFile << "\n ";
|
||||
nline = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
nline = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "] }\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
size_t npts = coords.size();
|
||||
aFile.write( (char*)&npts, sizeof(size_t) );
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
S3D::WritePoint( aFile, coords[i] );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( coords.empty(), false );
|
||||
|
||||
size_t npts;
|
||||
aFile.read( (char*) &npts, sizeof( size_t ) );
|
||||
SGPOINT tmp;
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
{
|
||||
if( !S3D::ReadPoint( aFile, tmp ) || aFile.fail() )
|
||||
return false;
|
||||
|
||||
coords.push_back( tmp );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::CalcNormals( SGFACESET* callingNode, SGNODE** aPtr )
|
||||
{
|
||||
if( aPtr )
|
||||
*aPtr = nullptr;
|
||||
|
||||
if( nullptr == m_Parent || nullptr == callingNode )
|
||||
return false;
|
||||
|
||||
// the parent and all references must have indices; collect all
|
||||
// indices into one std::vector<>
|
||||
std::vector< int > ilist;
|
||||
SGNORMALS* np = nullptr;
|
||||
|
||||
if( callingNode == m_Parent )
|
||||
{
|
||||
((SGFACESET*)m_Parent)->GatherCoordIndices( ilist );
|
||||
|
||||
std::list< SGNODE* >::iterator sB = m_BackPointers.begin();
|
||||
std::list< SGNODE* >::iterator eB = m_BackPointers.end();
|
||||
|
||||
while( sB != eB )
|
||||
{
|
||||
SGFACESET* fp = (SGFACESET*)(*sB);
|
||||
fp->GatherCoordIndices( ilist );
|
||||
++sB;
|
||||
}
|
||||
|
||||
np = ( (SGFACESET*) m_Parent )->m_Normals;
|
||||
|
||||
if( !np )
|
||||
np = new SGNORMALS( m_Parent );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
callingNode->GatherCoordIndices( ilist );
|
||||
np = callingNode->m_Normals;
|
||||
|
||||
if( !np )
|
||||
np = new SGNORMALS( callingNode );
|
||||
|
||||
}
|
||||
|
||||
if( S3D::CalcTriangleNormals( coords, ilist, np->norms ) )
|
||||
{
|
||||
if( aPtr )
|
||||
*aPtr = np;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
delete np;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_coords.h
|
||||
*/
|
||||
|
||||
#ifndef SG_COORDS_H
|
||||
#define SG_COORDS_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
class SGFACESET;
|
||||
|
||||
/**
|
||||
* Define a vertex coordinate set for a scenegraph object.
|
||||
*/
|
||||
class SGCOORDS : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGCOORDS( SGNODE* aParent );
|
||||
virtual ~SGCOORDS();
|
||||
|
||||
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override;
|
||||
bool AddRefNode( SGNODE* aNode ) noexcept override;
|
||||
bool AddChildNode( SGNODE* aNode ) noexcept override;
|
||||
|
||||
bool GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList );
|
||||
void SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList );
|
||||
void AddCoord( double aXValue, double aYValue, double aZValue );
|
||||
void AddCoord( const SGPOINT& aPoint );
|
||||
|
||||
/**
|
||||
* Calculate normals for this coordinate list and sets the normals list in the
|
||||
* parent #SGFACESET.
|
||||
*/
|
||||
bool CalcNormals( SGFACESET* callingNode, SGNODE** aPtr = nullptr );
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
std::vector< SGPOINT > coords;
|
||||
};
|
||||
|
||||
#endif // SG_COORDS_H
|
||||
@@ -1,992 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_faceset.h"
|
||||
#include "3d_cache/sg/sg_colors.h"
|
||||
#include "3d_cache/sg/sg_coords.h"
|
||||
#include "3d_cache/sg/sg_normals.h"
|
||||
#include "3d_cache/sg/sg_coordindex.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
SGFACESET::SGFACESET( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_FACESET;
|
||||
m_Colors = nullptr;
|
||||
m_Coords = nullptr;
|
||||
m_CoordIndices = nullptr;
|
||||
m_Normals = nullptr;
|
||||
m_RColors = nullptr;
|
||||
m_RCoords = nullptr;
|
||||
m_RNormals = nullptr;
|
||||
valid = false;
|
||||
validated = false;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGFACESET (type %s)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGFACESET::~SGFACESET()
|
||||
{
|
||||
// drop references
|
||||
if( m_RColors )
|
||||
{
|
||||
m_RColors->delNodeRef( this );
|
||||
m_RColors = nullptr;
|
||||
}
|
||||
|
||||
if( m_RCoords )
|
||||
{
|
||||
m_RCoords->delNodeRef( this );
|
||||
m_RCoords = nullptr;
|
||||
}
|
||||
|
||||
if( m_RNormals )
|
||||
{
|
||||
m_RNormals->delNodeRef( this );
|
||||
m_RNormals = nullptr;
|
||||
}
|
||||
|
||||
// delete owned objects
|
||||
if( m_Colors )
|
||||
{
|
||||
m_Colors->SetParent( nullptr, false );
|
||||
delete m_Colors;
|
||||
m_Colors = nullptr;
|
||||
}
|
||||
|
||||
if( m_Coords )
|
||||
{
|
||||
m_Coords->SetParent( nullptr, false );
|
||||
delete m_Coords;
|
||||
m_Coords = nullptr;
|
||||
}
|
||||
|
||||
if( m_Normals )
|
||||
{
|
||||
m_Normals->SetParent( nullptr, false );
|
||||
delete m_Normals;
|
||||
m_Normals = nullptr;
|
||||
}
|
||||
|
||||
if( m_CoordIndices )
|
||||
{
|
||||
m_CoordIndices->SetParent( nullptr, false );
|
||||
delete m_CoordIndices;
|
||||
m_CoordIndices = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGSHAPE may be parent to a SGFACESET
|
||||
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGFACESET::FindNode(const char *aNodeName, const SGNODE *aCaller)
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
SGNODE* np = nullptr;
|
||||
|
||||
if( m_Colors )
|
||||
{
|
||||
np = m_Colors->FindNode( aNodeName, this );
|
||||
|
||||
if( np )
|
||||
return np;
|
||||
}
|
||||
|
||||
if( m_Coords )
|
||||
{
|
||||
np = m_Coords->FindNode( aNodeName, this );
|
||||
|
||||
if( np )
|
||||
return np;
|
||||
}
|
||||
|
||||
if( m_CoordIndices )
|
||||
{
|
||||
np = m_CoordIndices->FindNode( aNodeName, this );
|
||||
|
||||
if( np )
|
||||
return np;
|
||||
}
|
||||
|
||||
if( m_Normals )
|
||||
{
|
||||
np = m_Normals->FindNode( aNodeName, this );
|
||||
|
||||
if( np )
|
||||
return np;
|
||||
}
|
||||
|
||||
// query the parent if appropriate
|
||||
if( aCaller == m_Parent || nullptr == m_Parent )
|
||||
return nullptr;
|
||||
|
||||
return m_Parent->FindNode( aNodeName, this );
|
||||
}
|
||||
|
||||
|
||||
void SGFACESET::unlinkNode( const SGNODE* aNode, bool isChild )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return;
|
||||
|
||||
valid = false;
|
||||
validated = false;
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
if( aNode == m_Colors )
|
||||
{
|
||||
m_Colors = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_Coords )
|
||||
{
|
||||
m_Coords = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_Normals )
|
||||
{
|
||||
m_Normals = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_CoordIndices )
|
||||
{
|
||||
m_CoordIndices = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aNode == m_RColors )
|
||||
{
|
||||
delNodeRef( this );
|
||||
m_RColors = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_RCoords )
|
||||
{
|
||||
delNodeRef( this );
|
||||
m_RCoords = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_RNormals )
|
||||
{
|
||||
delNodeRef( this );
|
||||
m_RNormals = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
void SGFACESET::unlinkChildNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, true );
|
||||
}
|
||||
|
||||
|
||||
void SGFACESET::unlinkRefNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, false );
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
valid = false;
|
||||
validated = false;
|
||||
|
||||
if( S3D::SGTYPE_COLORS == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_Colors || m_RColors )
|
||||
{
|
||||
if( aNode != m_Colors && aNode != m_RColors )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
m_Colors = (SGCOLORS*)aNode;
|
||||
m_Colors->SetParent( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RColors = (SGCOLORS*)aNode;
|
||||
m_RColors->addNodeRef( this );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_COORDS == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_Coords || m_RCoords )
|
||||
{
|
||||
if( aNode != m_Coords && aNode != m_RCoords )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
m_Coords = (SGCOORDS*)aNode;
|
||||
m_Coords->SetParent( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RCoords = (SGCOORDS*)aNode;
|
||||
m_RCoords->addNodeRef( this );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_NORMALS == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_Normals || m_RNormals )
|
||||
{
|
||||
if( aNode != m_Normals && aNode != m_RNormals )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Normals nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
m_Normals = (SGNORMALS*)aNode;
|
||||
m_Normals->SetParent( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RNormals = (SGNORMALS*)aNode;
|
||||
m_RNormals->addNodeRef( this );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_COORDINDEX == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_CoordIndices )
|
||||
{
|
||||
if( aNode != m_CoordIndices )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] assigning multiple CoordIndex nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
m_CoordIndices = (SGCOORDINDEX*)aNode;
|
||||
m_CoordIndices->SetParent( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] object type '%s' is not a valid type for "
|
||||
"this object '%d'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aNode->GetName(),
|
||||
aNode->GetNodeType() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::AddRefNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, false );
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::AddChildNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, true );
|
||||
}
|
||||
|
||||
|
||||
void SGFACESET::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
|
||||
// rename all Colors and Indices
|
||||
if( m_Colors )
|
||||
m_Colors->ReNameNodes();
|
||||
|
||||
// rename all Coordinates and Indices
|
||||
if( m_Coords )
|
||||
m_Coords->ReNameNodes();
|
||||
|
||||
if( m_CoordIndices )
|
||||
m_CoordIndices->ReNameNodes();
|
||||
|
||||
// rename all Normals and Indices
|
||||
if( m_Normals )
|
||||
m_Normals->ReNameNodes();
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( ( nullptr == m_Coords && nullptr == m_RCoords ) || ( nullptr == m_CoordIndices ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << " geometry DEF " << GetName() << " IndexedFaceSet {\n";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << "USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " geometry IndexedFaceSet {\n";
|
||||
}
|
||||
|
||||
if( m_Coords )
|
||||
m_Coords->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_RCoords )
|
||||
m_RCoords->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_CoordIndices )
|
||||
m_CoordIndices->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_Normals || m_RNormals )
|
||||
aFile << " normalPerVertex TRUE\n";
|
||||
|
||||
if( m_Normals )
|
||||
m_Normals->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_RNormals )
|
||||
m_RNormals->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_Colors )
|
||||
m_Colors->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_RColors )
|
||||
m_RColors->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
aFile << "}\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if any references are unwritten and swap parents if so
|
||||
if( nullptr != m_RCoords && !m_RCoords->isWritten() )
|
||||
m_RCoords->SwapParent( this );
|
||||
|
||||
if( nullptr != m_RNormals && !m_RNormals->isWritten() )
|
||||
m_RNormals->SwapParent( this );
|
||||
|
||||
if( nullptr != m_RColors && !m_RColors->isWritten() )
|
||||
m_RColors->SwapParent( this );
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
#define NITEMS 7
|
||||
bool items[NITEMS];
|
||||
int i;
|
||||
|
||||
for( i = 0; i < NITEMS; ++i )
|
||||
items[i] = 0;
|
||||
|
||||
i = 0;
|
||||
if( nullptr != m_Coords )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_RCoords )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_CoordIndices )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_Normals )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_RNormals )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_Colors )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_RColors )
|
||||
items[i] = true;
|
||||
|
||||
for( int jj = 0; jj < NITEMS; ++jj )
|
||||
aFile.write( (char*) &items[jj], sizeof( bool ) );
|
||||
|
||||
if( items[0] )
|
||||
m_Coords->WriteCache( aFile, this );
|
||||
|
||||
if( items[1] )
|
||||
aFile << "[" << m_RCoords->GetName() << "]";
|
||||
|
||||
if( items[2] )
|
||||
m_CoordIndices->WriteCache( aFile, this );
|
||||
|
||||
if( items[3] )
|
||||
m_Normals->WriteCache( aFile, this );
|
||||
|
||||
if( items[4] )
|
||||
aFile << "[" << m_RNormals->GetName() << "]";
|
||||
|
||||
if( items[5] )
|
||||
m_Colors->WriteCache( aFile, this );
|
||||
|
||||
if( items[6] )
|
||||
aFile << "[" << m_RColors->GetName() << "]";
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( m_Coords || m_RCoords || m_CoordIndices || m_Colors || m_RColors || m_Normals
|
||||
|| m_RNormals )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] non-empty node" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define NITEMS 7
|
||||
bool items[NITEMS];
|
||||
|
||||
for( int i = 0; i < NITEMS; ++i )
|
||||
aFile.read( (char*) &items[i], sizeof( bool ) );
|
||||
|
||||
if( ( items[0] && items[1] ) || ( items[3] && items[4] ) || ( items[5] && items[6] ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; multiple item definitions "
|
||||
"at position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
if( items[0] )
|
||||
{
|
||||
if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child coords tag at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Coords = new SGCOORDS( this );
|
||||
m_Coords->SetName( name.c_str() );
|
||||
|
||||
if( !m_Coords->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; corrupt data while "
|
||||
"reading coords '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[1] )
|
||||
{
|
||||
if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref coords tag at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* np = FindNode( name.c_str(), this );
|
||||
|
||||
if( !np )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; cannot find ref "
|
||||
"coords '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_COORDS != np->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; type is not SGCOORDS "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_RCoords = (SGCOORDS*)np;
|
||||
m_RCoords->addNodeRef( this );
|
||||
}
|
||||
|
||||
if( items[2] )
|
||||
{
|
||||
if( S3D::SGTYPE_COORDINDEX != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad coord index tag at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_CoordIndices = new SGCOORDINDEX( this );
|
||||
m_CoordIndices->SetName( name.c_str() );
|
||||
|
||||
if( !m_CoordIndices->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading coord "
|
||||
"index '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[3] )
|
||||
{
|
||||
if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child normals tag "
|
||||
"at position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Normals = new SGNORMALS( this );
|
||||
m_Normals->SetName( name.c_str() );
|
||||
|
||||
if( !m_Normals->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading normals "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[4] )
|
||||
{
|
||||
if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref normals tag at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* np = FindNode( name.c_str(), this );
|
||||
|
||||
if( !np )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt: cannot find ref normals "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_NORMALS != np->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt: type is not SGNORMALS '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_RNormals = (SGNORMALS*)np;
|
||||
m_RNormals->addNodeRef( this );
|
||||
}
|
||||
|
||||
if( items[5] )
|
||||
{
|
||||
if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child colors tag "
|
||||
"at position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Colors = new SGCOLORS( this );
|
||||
m_Colors->SetName( name.c_str() );
|
||||
|
||||
if( !m_Colors->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading colors "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[6] )
|
||||
{
|
||||
if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref colors tag at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* np = FindNode( name.c_str(), this );
|
||||
|
||||
if( !np )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref colors "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_COLORS != np->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGCOLORS "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_RColors = (SGCOLORS*)np;
|
||||
m_RColors->addNodeRef( this );
|
||||
}
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::validate( void )
|
||||
{
|
||||
// verify the integrity of this object's data
|
||||
if( validated )
|
||||
return valid;
|
||||
|
||||
// ensure we have at least coordinates and their normals
|
||||
if( ( nullptr == m_Coords && nullptr == m_RCoords )
|
||||
|| ( nullptr == m_Normals && nullptr == m_RNormals )
|
||||
|| ( nullptr == m_CoordIndices ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; no vertices, vertex indices, "
|
||||
"or normals" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
validated = true;
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// check that there are >3 vertices
|
||||
SGCOORDS* coords = m_Coords;
|
||||
|
||||
if( nullptr == coords )
|
||||
coords = m_RCoords;
|
||||
|
||||
size_t nCoords = 0;
|
||||
SGPOINT* lCoords = nullptr;
|
||||
coords->GetCoordsList( nCoords, lCoords );
|
||||
|
||||
if( nCoords < 3 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; fewer than 3 vertices" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
validated = true;
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// check that nVertices is divisible by 3 (facets are triangles)
|
||||
size_t nCIdx = 0;
|
||||
int* lCIdx = nullptr;
|
||||
m_CoordIndices->GetIndices( nCIdx, lCIdx );
|
||||
|
||||
if( nCIdx < 3 || ( nCIdx % 3 > 0 ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; no vertex indices or not "
|
||||
"multiple of 3" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
validated = true;
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// check that vertex[n] >= 0 and < nVertices
|
||||
for( size_t i = 0; i < nCIdx; ++i )
|
||||
{
|
||||
if( lCIdx[i] < 0 || lCIdx[i] >= (int)nCoords )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; vertex index out of "
|
||||
"bounds" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
validated = true;
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check that there are as many normals as vertices
|
||||
size_t nNorms = 0;
|
||||
SGVECTOR* lNorms = nullptr;
|
||||
SGNORMALS* pNorms = m_Normals;
|
||||
|
||||
if( nullptr == pNorms )
|
||||
pNorms = m_RNormals;
|
||||
|
||||
pNorms->GetNormalList( nNorms, lNorms );
|
||||
|
||||
if( nNorms != nCoords )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; number of normals (%ul) does "
|
||||
"not match number of vertices (%ul)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( nNorms ),
|
||||
static_cast<unsigned long>( nCoords ) );
|
||||
|
||||
validated = true;
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// if there are colors then ensure there are as many colors as vertices
|
||||
SGCOLORS* pColors = m_Colors;
|
||||
|
||||
if( nullptr == pColors )
|
||||
pColors = m_RColors;
|
||||
|
||||
if( nullptr != pColors )
|
||||
{
|
||||
// we must have at least as many colors as vertices
|
||||
size_t nColor = 0;
|
||||
SGCOLOR* pColor = nullptr;
|
||||
pColors->GetColorList( nColor, pColor );
|
||||
}
|
||||
|
||||
validated = true;
|
||||
valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SGFACESET::GatherCoordIndices( std::vector< int >& aIndexList )
|
||||
{
|
||||
if( m_CoordIndices )
|
||||
m_CoordIndices->GatherCoordIndices( aIndexList );
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::CalcNormals( SGNODE** aPtr )
|
||||
{
|
||||
SGCOORDS* coords = m_Coords;
|
||||
|
||||
if( m_RCoords )
|
||||
coords = m_RCoords;
|
||||
|
||||
if( nullptr == coords || coords->coords.empty() )
|
||||
return false;
|
||||
|
||||
if( m_Normals && !m_Normals->norms.empty( ) )
|
||||
return true;
|
||||
|
||||
if( m_RNormals && !m_RNormals->norms.empty( ) )
|
||||
return true;
|
||||
|
||||
return coords->CalcNormals( this, aPtr );
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_faceset.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SG_FACESET_H
|
||||
#define SG_FACESET_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
|
||||
class SGCOLORS;
|
||||
class SGCOORDS;
|
||||
class SGNORMALS;
|
||||
class SGCOLORINDEX;
|
||||
class SGCOORDINDEX;
|
||||
|
||||
/**
|
||||
* Define an indexed face set for a scenegraph.
|
||||
*/
|
||||
class SGFACESET : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGFACESET( SGNODE* aParent );
|
||||
virtual ~SGFACESET();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
SGNODE* FindNode( const char* aNodeName, const SGNODE* aCaller ) override;
|
||||
bool AddRefNode( SGNODE* aNode ) override;
|
||||
bool AddChildNode( SGNODE* aNode ) override;
|
||||
|
||||
bool CalcNormals( SGNODE** aPtr );
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
/**
|
||||
* Add all internal coordinate indices to the given list in preparation for a normals
|
||||
* calculation.
|
||||
*/
|
||||
void GatherCoordIndices( std::vector< int >& aIndexList );
|
||||
|
||||
void unlinkChildNode( const SGNODE* aNode ) override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) override;
|
||||
|
||||
// validate the data held by this face set
|
||||
bool validate( void );
|
||||
|
||||
// owned objects
|
||||
SGCOLORS* m_Colors;
|
||||
SGCOORDS* m_Coords;
|
||||
SGCOORDINDEX* m_CoordIndices;
|
||||
SGNORMALS* m_Normals;
|
||||
|
||||
// referenced objects
|
||||
SGCOLORS* m_RColors;
|
||||
SGCOORDS* m_RCoords;
|
||||
SGNORMALS* m_RNormals;
|
||||
|
||||
private:
|
||||
bool valid;
|
||||
bool validated;
|
||||
void unlinkNode( const SGNODE* aNode, bool isChild );
|
||||
bool addNode( SGNODE* aNode, bool isChild );
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
p.88
|
||||
IndexedFaceSet {
|
||||
color NULL
|
||||
coord NULL
|
||||
normal NULL
|
||||
texCoord NULL
|
||||
ccw TRUE
|
||||
colorIndex []
|
||||
colorPerVertex TRUE
|
||||
convex TRUE
|
||||
coordIndex []
|
||||
creaseAngle 0
|
||||
normalIndex []
|
||||
normalPerVertex TRUE
|
||||
solid TRUE
|
||||
texCoordIndex []
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // SG_FACESET_H
|
||||
@@ -1,490 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
|
||||
void S3D::FormatFloat( std::string& result, double value )
|
||||
{
|
||||
if( value < 1e-8 && value > -1e-8 )
|
||||
{
|
||||
result = "0";
|
||||
return;
|
||||
}
|
||||
|
||||
// note: many VRML implementations use float so we use the max.
|
||||
// precision here of 8 digits.
|
||||
std::ostringstream out;
|
||||
out << std::setprecision( 8 ) << value;
|
||||
|
||||
result = out.str();
|
||||
|
||||
size_t p = result.find( '.' );
|
||||
|
||||
// trim trailing 0 if appropriate
|
||||
if( std::string::npos == p )
|
||||
return;
|
||||
|
||||
p = result.find_first_of( "eE" );
|
||||
|
||||
if( std::string::npos == p )
|
||||
{
|
||||
while( '0' == *( result.rbegin() ) )
|
||||
result.erase( result.size() - 1 );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( '0' != result.at( p - 1 ) )
|
||||
return;
|
||||
|
||||
// trim all 0 to the left of 'p'
|
||||
std::string tmp = result.substr( p );
|
||||
result = result.substr( 0, p );
|
||||
|
||||
while( '0' == *( result.rbegin() ) )
|
||||
result.erase( result.size() - 1 );
|
||||
|
||||
result.append( tmp );
|
||||
}
|
||||
|
||||
|
||||
void S3D::FormatOrientation( std::string& result, const SGVECTOR& axis, double rotation )
|
||||
{
|
||||
double aX;
|
||||
double aY;
|
||||
double aZ;
|
||||
|
||||
axis.GetVector( aX, aY, aZ );
|
||||
FormatFloat( result, aX );
|
||||
std::string tmp;
|
||||
FormatFloat( tmp, aY );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
FormatFloat( tmp, aZ );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
FormatFloat( tmp, rotation );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
}
|
||||
|
||||
|
||||
void S3D::FormatPoint( std::string& result, const SGPOINT& point )
|
||||
{
|
||||
FormatFloat( result, point.x );
|
||||
|
||||
std::string tmp;
|
||||
FormatFloat( tmp, point.y );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
|
||||
FormatFloat( tmp, point.z );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
}
|
||||
|
||||
|
||||
void S3D::FormatVector( std::string& result, const SGVECTOR& aVector )
|
||||
{
|
||||
double X, Y, Z;
|
||||
aVector.GetVector( X, Y, Z );
|
||||
FormatFloat( result, X );
|
||||
|
||||
std::string tmp;
|
||||
FormatFloat( tmp, Y );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
|
||||
FormatFloat( tmp, Z );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
}
|
||||
|
||||
|
||||
void S3D::FormatColor( std::string& result, const SGCOLOR& aColor )
|
||||
{
|
||||
float R, G, B;
|
||||
aColor.GetColor( R, G, B );
|
||||
FormatFloat( result, R );
|
||||
|
||||
std::string tmp;
|
||||
FormatFloat( tmp, G );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
|
||||
FormatFloat( tmp, B );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
}
|
||||
|
||||
|
||||
bool S3D::WritePoint( std::ostream& aFile, const SGPOINT& aPoint )
|
||||
{
|
||||
aFile.write( (char*) &aPoint.x, sizeof( aPoint.x ) );
|
||||
aFile.write( (char*) &aPoint.y, sizeof( aPoint.y ) );
|
||||
aFile.write( (char*) &aPoint.z, sizeof( aPoint.z ) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::WriteVector( std::ostream& aFile, const SGVECTOR& aVector )
|
||||
{
|
||||
double x, y, z;
|
||||
aVector.GetVector( x, y, z );
|
||||
aFile.write( (char*) &x, sizeof( double ) );
|
||||
aFile.write( (char*) &y, sizeof( double ) );
|
||||
aFile.write( (char*) &z, sizeof( double ) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::WriteColor( std::ostream& aFile, const SGCOLOR& aColor )
|
||||
{
|
||||
float r, g, b;
|
||||
aColor.GetColor( r, g, b );
|
||||
aFile.write( (char*) &r, sizeof( float ) );
|
||||
aFile.write( (char*) &g, sizeof( float ) );
|
||||
aFile.write( (char*) &b, sizeof( float ) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
S3D::SGTYPES S3D::ReadTag( std::istream& aFile, std::string& aName )
|
||||
{
|
||||
char schar;
|
||||
aFile.get( schar );
|
||||
|
||||
if( '[' != schar )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; missing left bracket at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return S3D::SGTYPE_END;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
aFile.get( schar );
|
||||
|
||||
while( ']' != schar && aFile.good() )
|
||||
{
|
||||
name.push_back( schar );
|
||||
aFile.get( schar );
|
||||
}
|
||||
|
||||
if( schar != ']' )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; could not find right "
|
||||
"bracket" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return S3D::SGTYPE_END;
|
||||
}
|
||||
|
||||
aName = name;
|
||||
size_t upos = name.find( '_' );
|
||||
|
||||
if( std::string::npos == upos )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; no underscore in name '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return S3D::SGTYPE_END;
|
||||
}
|
||||
|
||||
name = name.substr( 0, upos );
|
||||
S3D::SGTYPES types[S3D::SGTYPE_END] = {
|
||||
SGTYPE_TRANSFORM,
|
||||
SGTYPE_APPEARANCE,
|
||||
SGTYPE_COLORS,
|
||||
SGTYPE_COLORINDEX,
|
||||
SGTYPE_FACESET,
|
||||
SGTYPE_COORDS,
|
||||
SGTYPE_COORDINDEX,
|
||||
SGTYPE_NORMALS,
|
||||
SGTYPE_SHAPE
|
||||
};
|
||||
|
||||
for( int i = 0; i < S3D::SGTYPE_END; ++i )
|
||||
{
|
||||
if( !name.compare( S3D::GetNodeTypeName( types[i] ) ) )
|
||||
return types[i];
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; no node type matching '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return S3D::SGTYPE_END;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::ReadPoint( std::istream& aFile, SGPOINT& aPoint )
|
||||
{
|
||||
aFile.read( (char*) &aPoint.x, sizeof( aPoint.x ) );
|
||||
aFile.read( (char*) &aPoint.y, sizeof( aPoint.y ) );
|
||||
aFile.read( (char*) &aPoint.z, sizeof( aPoint.z ) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::ReadVector( std::istream& aFile, SGVECTOR& aVector )
|
||||
{
|
||||
double x, y, z;
|
||||
aFile.read( (char*) &x, sizeof( double ) );
|
||||
aFile.read( (char*) &y, sizeof( double ) );
|
||||
aFile.read( (char*) &z, sizeof( double ) );
|
||||
aVector.SetVector( x, y, z );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::ReadColor( std::istream& aFile, SGCOLOR& aColor )
|
||||
{
|
||||
float r, g, b;
|
||||
aFile.read( (char*) &r, sizeof( float ) );
|
||||
aFile.read( (char*) &g, sizeof( float ) );
|
||||
aFile.read( (char*) &b, sizeof( float ) );
|
||||
aColor.SetColor( r, g, b );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::degenerate( glm::dvec3* pts ) noexcept
|
||||
{
|
||||
double dx, dy, dz;
|
||||
|
||||
dx = pts[1].x - pts[0].x;
|
||||
dy = pts[1].y - pts[0].y;
|
||||
dz = pts[1].z - pts[0].z;
|
||||
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
|
||||
return true;
|
||||
|
||||
dx = pts[2].x - pts[0].x;
|
||||
dy = pts[2].y - pts[0].y;
|
||||
dz = pts[2].z - pts[0].z;
|
||||
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
|
||||
return true;
|
||||
|
||||
dx = pts[2].x - pts[1].x;
|
||||
dy = pts[2].y - pts[1].y;
|
||||
dz = pts[2].z - pts[1].z;
|
||||
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void calcTriad( glm::dvec3* pts, glm::dvec3& tri )
|
||||
{
|
||||
if( S3D::degenerate( pts ) )
|
||||
{
|
||||
// degenerate points should contribute nothing to the result
|
||||
tri = glm::dvec3( 0.0, 0.0, 0.0 );
|
||||
return;
|
||||
}
|
||||
|
||||
// normal * 2 * area
|
||||
tri = glm::cross( pts[1] - pts[0], pts[2] - pts[0] );
|
||||
}
|
||||
|
||||
|
||||
bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >& index,
|
||||
std::vector< SGVECTOR >& norms )
|
||||
{
|
||||
size_t vsize = coords.size();
|
||||
|
||||
if( vsize < 3 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] invalid vertex set (fewer than 3 "
|
||||
"vertices)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t isize = index.size();
|
||||
|
||||
if( 0 != isize % 3 || index.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] invalid index set (not multiple of 3)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !norms.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] normals set is not empty" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map< int, std::list< glm::dvec3 > >vmap;
|
||||
|
||||
int p1, p2, p3;
|
||||
|
||||
// create the map of indices to facet sets
|
||||
for( size_t i = 0; i < isize; )
|
||||
{
|
||||
p1 = index[i++];
|
||||
p2 = index[i++];
|
||||
p3 = index[i++];
|
||||
|
||||
if( p1 < 0 || p1 >= (int)vsize || p2 < 0 || p2 >= (int)vsize || p3 < 0 || p3 >= (int)vsize )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::ostringstream ostr;
|
||||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
||||
ostr << " * [INFO] invalid index set; index out of bounds";
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s\n" ), ostr.str().c_str() );
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::dvec3 tri;
|
||||
glm::dvec3 trip[3];
|
||||
trip[0] = glm::dvec3( coords[p1].x, coords[p1].y, coords[p1].z );
|
||||
trip[1] = glm::dvec3( coords[p2].x, coords[p2].y, coords[p2].z );
|
||||
trip[2] = glm::dvec3( coords[p3].x, coords[p3].y, coords[p3].z );
|
||||
calcTriad( trip, tri );
|
||||
|
||||
std::map< int, std::list< glm::dvec3 > >::iterator ip = vmap.find( p1 );
|
||||
|
||||
if( ip != vmap.end() )
|
||||
{
|
||||
ip->second.push_back( tri );
|
||||
}
|
||||
else
|
||||
{
|
||||
vmap.emplace( p1, std::list < glm::dvec3 >( 1, tri ) );
|
||||
}
|
||||
|
||||
ip = vmap.find( p2 );
|
||||
|
||||
if( ip != vmap.end() )
|
||||
{
|
||||
ip->second.push_back( tri );
|
||||
}
|
||||
else
|
||||
{
|
||||
vmap.emplace( p2, std::list < glm::dvec3 >( 1, tri ) );
|
||||
}
|
||||
|
||||
ip = vmap.find( p3 );
|
||||
|
||||
if( ip != vmap.end() )
|
||||
{
|
||||
ip->second.push_back( tri );
|
||||
}
|
||||
else
|
||||
{
|
||||
vmap.emplace( p3, std::list < glm::dvec3 >( 1, tri ) );
|
||||
}
|
||||
}
|
||||
|
||||
std::map< int, std::list< glm::dvec3 > >::iterator sM = vmap.begin();
|
||||
std::map< int, std::list< glm::dvec3 > >::iterator eM = vmap.end();
|
||||
size_t idx = 0;
|
||||
|
||||
while( sM != eM )
|
||||
{
|
||||
size_t item = sM->first;
|
||||
|
||||
// assign any skipped coordinates a normal of (0,0,1)
|
||||
while( item > idx )
|
||||
{
|
||||
norms.emplace_back( 0, 0, 1 );
|
||||
++idx;
|
||||
}
|
||||
|
||||
std::list< glm::dvec3 >::iterator sT = sM->second.begin();
|
||||
std::list< glm::dvec3 >::iterator eT = sM->second.end();
|
||||
glm::dvec3 norm( 0.0, 0.0, 0.0 );
|
||||
|
||||
while( sT != eT )
|
||||
{
|
||||
norm += *sT;
|
||||
++sT;
|
||||
}
|
||||
|
||||
norms.emplace_back( norm.x, norm.y, norm.z );
|
||||
|
||||
++idx;
|
||||
++sM;
|
||||
}
|
||||
|
||||
if( norms.size() != coords.size() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] number of normals does not equal number "
|
||||
"of vertices" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_helpers.h
|
||||
*
|
||||
* Define a number of macros to aid in repetitious code which is probably best expressed
|
||||
* as a preprocessor macro rather than as a template. This header also declares a number
|
||||
* of functions which are only of use within the sg_* classes.
|
||||
*/
|
||||
|
||||
#ifndef SG_HELPERS_H
|
||||
#define SG_HELPERS_H
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "plugins/3dapi/sg_base.h"
|
||||
#include "plugins/3dapi/sg_types.h"
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class SGNORMALS;
|
||||
class SGCOORDS;
|
||||
class SGCOORDINDEX;
|
||||
|
||||
|
||||
// Function to drop references within an SGNODE
|
||||
// The node being destroyed must remove itself from the object reference's
|
||||
// backpointer list in order to avoid a segfault.
|
||||
#define DROP_REFS( aType, aList ) \
|
||||
do \
|
||||
{ \
|
||||
std::vector<aType*>::iterator sL = aList.begin(); \
|
||||
std::vector<aType*>::iterator eL = aList.end(); \
|
||||
while( sL != eL ) \
|
||||
{ \
|
||||
( (SGNODE*) *sL )->delNodeRef( this ); \
|
||||
++sL; \
|
||||
} \
|
||||
aList.clear(); \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
// Function to delete owned objects within an SGNODE
|
||||
// The owned object's parent is set to NULL before
|
||||
// deletion to avoid a redundant 'unlinkChildNode' call.
|
||||
#define DEL_OBJS( aType, aList ) \
|
||||
do \
|
||||
{ \
|
||||
std::vector<aType*>::iterator sL = aList.begin(); \
|
||||
std::vector<aType*>::iterator eL = aList.end(); \
|
||||
while( sL != eL ) \
|
||||
{ \
|
||||
( (SGNODE*) *sL )->SetParent( nullptr, false ); \
|
||||
delete *sL; \
|
||||
++sL; \
|
||||
} \
|
||||
aList.clear(); \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
// Function to unlink a child or reference node when that child or
|
||||
// reference node is being destroyed.
|
||||
#define UNLINK_NODE( aNodeID, aType, aNode, aOwnedList, aRefList, isChild ) \
|
||||
do \
|
||||
{ \
|
||||
if( aNodeID == aNode->GetNodeType() ) \
|
||||
{ \
|
||||
std::vector<aType*>* oSL; \
|
||||
std::vector<aType*>::iterator sL; \
|
||||
std::vector<aType*>::iterator eL; \
|
||||
if( isChild ) \
|
||||
{ \
|
||||
oSL = &aOwnedList; \
|
||||
sL = oSL->begin(); \
|
||||
eL = oSL->end(); \
|
||||
while( sL != eL ) \
|
||||
{ \
|
||||
if( (SGNODE*) *sL == aNode ) \
|
||||
{ \
|
||||
oSL->erase( sL ); \
|
||||
return; \
|
||||
} \
|
||||
++sL; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
oSL = &aRefList; \
|
||||
sL = oSL->begin(); \
|
||||
eL = oSL->end(); \
|
||||
while( sL != eL ) \
|
||||
{ \
|
||||
if( (SGNODE*) *sL == aNode ) \
|
||||
{ \
|
||||
delNodeRef( this ); \
|
||||
oSL->erase( sL ); \
|
||||
return; \
|
||||
} \
|
||||
++sL; \
|
||||
} \
|
||||
} \
|
||||
return; \
|
||||
} \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
// Function to check a node type, check for an existing reference,
|
||||
// and add the node type to the reference list if applicable
|
||||
#define ADD_NODE( aNodeID, aType, aNode, aOwnedList, aRefList, isChild ) \
|
||||
do \
|
||||
{ \
|
||||
if( aNodeID == aNode->GetNodeType() ) \
|
||||
{ \
|
||||
std::vector<aType*>::iterator sL; \
|
||||
sL = std::find( aOwnedList.begin(), aOwnedList.end(), aNode ); \
|
||||
if( sL != aOwnedList.end() ) \
|
||||
return true; \
|
||||
sL = std::find( aRefList.begin(), aRefList.end(), aNode ); \
|
||||
if( sL != aRefList.end() ) \
|
||||
return true; \
|
||||
if( isChild ) \
|
||||
{ \
|
||||
SGNODE* ppn = (SGNODE*) aNode->GetParent(); \
|
||||
if( nullptr != ppn ) \
|
||||
{ \
|
||||
if( this != ppn ) \
|
||||
{ \
|
||||
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; \
|
||||
std::cerr << " * [BUG] object '" << aNode->GetName(); \
|
||||
std::cerr << "' has multiple parents '" << ppn->GetName() << "', '"; \
|
||||
std::cerr << m_Name << "'\n"; \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
aOwnedList.push_back( (aType*) aNode ); \
|
||||
aNode->SetParent( this, false ); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
/*if( nullptr == aNode->GetParent() ) { \
|
||||
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; \
|
||||
std::cerr << " * [BUG] object '" << aNode->GetName(); \
|
||||
std::cerr << "' has no parent\n"; \
|
||||
std::cerr << " * [INFO] possible copy assignment or copy constructor bug\n"; \
|
||||
return false; \
|
||||
} */ \
|
||||
aRefList.push_back( (aType*) aNode ); \
|
||||
aNode->addNodeRef( this ); \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
// Function to find a node object given a (non-unique) node name
|
||||
#define FIND_NODE( aType, aName, aNodeList, aCallingNode ) \
|
||||
do \
|
||||
{ \
|
||||
std::vector<aType*>::iterator sLA = aNodeList.begin(); \
|
||||
std::vector<aType*>::iterator eLA = aNodeList.end(); \
|
||||
SGNODE* psg = nullptr; \
|
||||
while( sLA != eLA ) \
|
||||
{ \
|
||||
if( (SGNODE*) *sLA != aCallingNode ) \
|
||||
{ \
|
||||
psg = (SGNODE*) ( *sLA )->FindNode( aName, this ); \
|
||||
if( nullptr != psg ) \
|
||||
return psg; \
|
||||
} \
|
||||
++sLA; \
|
||||
} \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
namespace S3D
|
||||
{
|
||||
bool degenerate( glm::dvec3* pts ) noexcept;
|
||||
|
||||
//
|
||||
// Normals calculations from triangles
|
||||
//
|
||||
|
||||
/*
|
||||
* Take an array of 3D coordinates and its corresponding index set and calculates
|
||||
* the normals assuming that indices are given in CCW order.
|
||||
*
|
||||
* Care must be taken in using this function to ensure that:
|
||||
* -# All coordinates are indexed; unindexed coordinates are assigned normal(0,0,1);
|
||||
* when dealing with VRML models which may list and reuse one large coordinate set it
|
||||
* is necessary to gather all index sets and perform this operation only once.
|
||||
* -# Index sets must represent triangles (multiple of 3 indices) and must not be
|
||||
* degenerate, that is all indices and coordinates in a triad must be unique.
|
||||
*
|
||||
* @param coords is the array of 3D vertices.
|
||||
* @param index is the array of 3x vertex indices (triads).
|
||||
* @param norms is an empty array which holds the normals corresponding to each vector.
|
||||
* @return true on success; otherwise false.
|
||||
*/
|
||||
bool CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >& index,
|
||||
std::vector< SGVECTOR >& norms );
|
||||
|
||||
// formats a floating point number for text output to a VRML file
|
||||
void FormatFloat( std::string& result, double value );
|
||||
|
||||
// format orientation data for VRML output
|
||||
void FormatOrientation( std::string& result, const SGVECTOR& axis, double rotation );
|
||||
|
||||
// format point data for VRML output
|
||||
void FormatPoint( std::string& result, const SGPOINT& point );
|
||||
|
||||
// format vector data for VRML output
|
||||
void FormatVector( std::string& result, const SGVECTOR& aVector );
|
||||
|
||||
// format Color data for VRML output
|
||||
void FormatColor( std::string& result, const SGCOLOR& aColor );
|
||||
|
||||
//
|
||||
// Cache related WRITE functions
|
||||
//
|
||||
|
||||
// write out an XYZ vertex
|
||||
bool WritePoint( std::ostream& aFile, const SGPOINT& aPoint );
|
||||
|
||||
// write out a unit vector
|
||||
bool WriteVector( std::ostream& aFile, const SGVECTOR& aVector );
|
||||
|
||||
// write out an RGB color
|
||||
bool WriteColor( std::ostream& aFile, const SGCOLOR& aColor );
|
||||
|
||||
/**
|
||||
* Read the text tag of a binary cache file which is the NodeTag and unique ID number combined.
|
||||
*
|
||||
* @param aFile is a binary file open for reading.
|
||||
* @param aName will hold the tag name on successful return.
|
||||
* @return will be the NodeType which the tag represents or S3D::SGTYPES::SGTYPE_END on
|
||||
* failure.
|
||||
*/
|
||||
S3D::SGTYPES ReadTag( std::istream& aFile, std::string& aName );
|
||||
|
||||
// read an XYZ vertex
|
||||
bool ReadPoint( std::istream& aFile, SGPOINT& aPoint );
|
||||
|
||||
// read a unit vector
|
||||
bool ReadVector( std::istream& aFile, SGVECTOR& aVector );
|
||||
|
||||
// read an RGB color
|
||||
bool ReadColor( std::istream& aFile, SGCOLOR& aColor );
|
||||
}
|
||||
|
||||
#endif // SG_HELPERS_H
|
||||
@@ -1,329 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_index.h"
|
||||
|
||||
|
||||
SGINDEX::SGINDEX( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGINDEX (type "
|
||||
"'%d')" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeType() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGINDEX::~SGINDEX()
|
||||
{
|
||||
index.clear();
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGFACESET may be parent to a SGINDEX and derived types
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGINDEX::FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGINDEX::unlinkChildNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
// Node should have no children or refs.
|
||||
wxCHECK( false, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
void SGINDEX::unlinkRefNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
// Node should have no children or refs.
|
||||
wxCHECK( false, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::AddRefNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
// Node should have no children or refs.
|
||||
wxCHECK( false, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::AddChildNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
// Node should have no children or refs.
|
||||
wxCHECK( false, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::GetIndices( size_t& nIndices, int*& aIndexList )
|
||||
{
|
||||
if( index.empty() )
|
||||
{
|
||||
nIndices = 0;
|
||||
aIndexList = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
nIndices = index.size();
|
||||
aIndexList = & index[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SGINDEX::SetIndices( size_t nIndices, int* aIndexList )
|
||||
{
|
||||
index.clear();
|
||||
|
||||
if( 0 == nIndices || nullptr == aIndexList )
|
||||
return;
|
||||
|
||||
for( size_t i = 0; i < nIndices; ++i )
|
||||
index.push_back( aIndexList[i] );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SGINDEX::AddIndex( int aIndex )
|
||||
{
|
||||
index.push_back( aIndex );
|
||||
}
|
||||
|
||||
|
||||
void SGINDEX::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( index.empty() )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_COORDINDEX == m_SGtype )
|
||||
return writeCoordIndex( aFile );
|
||||
|
||||
return writeColorIndex( aFile );
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::writeCoordIndex( std::ostream& aFile )
|
||||
{
|
||||
size_t n = index.size();
|
||||
|
||||
wxCHECK_MSG( n % 3 == 0, false, wxT( "Coordinate index is not divisible by three (violates "
|
||||
"triangle constraint)" ) );
|
||||
|
||||
aFile << " coordIndex [\n ";
|
||||
|
||||
// indices to control formatting
|
||||
int nv0 = 0;
|
||||
int nv1 = 0;
|
||||
|
||||
for( size_t i = 0; i < n; )
|
||||
{
|
||||
aFile << index[i];
|
||||
++i;
|
||||
|
||||
if( ++nv0 == 3 )
|
||||
{
|
||||
aFile << ",-1";
|
||||
++nv1;
|
||||
nv0 = 0;
|
||||
}
|
||||
|
||||
if( i < n )
|
||||
{
|
||||
aFile << ",";
|
||||
|
||||
if( nv1 == 8 )
|
||||
{
|
||||
nv1 = 0;
|
||||
aFile << "\n ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "]\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::writeColorIndex( std::ostream& aFile )
|
||||
{
|
||||
aFile << " colorIndex [\n ";
|
||||
return writeIndexList( aFile );
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::writeIndexList( std::ostream& aFile )
|
||||
{
|
||||
// index to control formatting
|
||||
int nv = 0;
|
||||
size_t n = index.size();
|
||||
|
||||
for( size_t i = 0; i < n; )
|
||||
{
|
||||
aFile << index[i];
|
||||
++i;
|
||||
|
||||
if( i < n )
|
||||
{
|
||||
aFile << ",";
|
||||
|
||||
if( ++nv == 20 )
|
||||
{
|
||||
aFile << "\n ";
|
||||
nv = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "]\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
size_t npts = index.size();
|
||||
aFile.write( (char*)&npts, sizeof(size_t) );
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
aFile.write( (char*)&index[i], sizeof(int) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( index.empty(), false );
|
||||
|
||||
size_t npts;
|
||||
aFile.read( (char*)&npts, sizeof(size_t) );
|
||||
int tmp;
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
{
|
||||
aFile.read( (char*) &tmp, sizeof( int ) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
index.push_back( tmp );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_index.h
|
||||
*/
|
||||
|
||||
#ifndef SG_INDEX_H
|
||||
#define SG_INDEX_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
/**
|
||||
* Define a generic index interface for a scenegraph object.
|
||||
*/
|
||||
class SGINDEX : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGINDEX( SGNODE* aParent );
|
||||
virtual ~SGINDEX();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
SGNODE* FindNode(const char* aNodeName, const SGNODE* aCaller) noexcept override;
|
||||
bool AddRefNode( SGNODE* aNode ) noexcept override;
|
||||
bool AddChildNode( SGNODE* aNode ) noexcept override;
|
||||
|
||||
void unlinkChildNode( const SGNODE* aCaller ) noexcept override;
|
||||
void unlinkRefNode( const SGNODE* aCaller ) noexcept override;
|
||||
|
||||
/**
|
||||
* Retrieve the number of indices and a pointer to the list.
|
||||
*
|
||||
* @note The returned pointer may be invalidated by future operations on the SGNODE. The
|
||||
* caller must make immediate use of the data and must not rely on the pointer's
|
||||
* validity in the future.
|
||||
*
|
||||
* @param nIndices will hold the number of indices in the list.
|
||||
* @param aIndexList will store a pointer to the data.
|
||||
* @return true if there was available data (nIndices > 0) otherwise false.
|
||||
*/
|
||||
bool GetIndices( size_t& nIndices, int*& aIndexList );
|
||||
|
||||
/**
|
||||
* Set the number of indices and creates a copy of the given index data.
|
||||
*
|
||||
* @param nIndices the number of indices to be stored.
|
||||
* @param aIndexList the index data.
|
||||
*/
|
||||
void SetIndices( size_t nIndices, int* aIndexList );
|
||||
|
||||
|
||||
/**
|
||||
* Add a single index to the list.
|
||||
*
|
||||
* @param aIndex is the index to add.
|
||||
*/
|
||||
void AddIndex( int aIndex );
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
protected:
|
||||
bool writeCoordIndex( std::ostream& aFile );
|
||||
bool writeColorIndex( std::ostream& aFile );
|
||||
bool writeIndexList( std::ostream& aFile );
|
||||
|
||||
public:
|
||||
// for internal SG consumption only
|
||||
std::vector< int > index;
|
||||
};
|
||||
|
||||
#endif // SG_INDEX_H
|
||||
@@ -1,346 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
#include "plugins/3dapi/c3dmodel.h"
|
||||
|
||||
|
||||
static const std::string node_names[S3D::SGTYPE_END + 1] = {
|
||||
"TXFM",
|
||||
"APP",
|
||||
"COL",
|
||||
"COLIDX",
|
||||
"FACE",
|
||||
"COORD",
|
||||
"COORDIDX",
|
||||
"NORM",
|
||||
"SHAPE",
|
||||
"INVALID"
|
||||
};
|
||||
|
||||
|
||||
static unsigned int node_counts[S3D::SGTYPE_END] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
||||
|
||||
|
||||
char const* S3D::GetNodeTypeName( S3D::SGTYPES aType ) noexcept
|
||||
{
|
||||
return node_names[aType].c_str();
|
||||
}
|
||||
|
||||
|
||||
static void getNodeName( S3D::SGTYPES nodeType, std::string& aName )
|
||||
{
|
||||
if( nodeType < 0 || nodeType >= S3D::SGTYPE_END )
|
||||
{
|
||||
aName = node_names[S3D::SGTYPE_END];
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int seqNum = node_counts[nodeType];
|
||||
++node_counts[nodeType];
|
||||
|
||||
std::ostringstream ostr;
|
||||
ostr << node_names[nodeType] << "_" << seqNum;
|
||||
aName = ostr.str();
|
||||
}
|
||||
|
||||
|
||||
SGNODE::SGNODE( SGNODE* aParent )
|
||||
{
|
||||
m_Parent = aParent;
|
||||
m_Association = nullptr;
|
||||
m_written = false;
|
||||
m_SGtype = S3D::SGTYPE_END;
|
||||
}
|
||||
|
||||
|
||||
SGNODE::~SGNODE()
|
||||
{
|
||||
if( m_Parent )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
if( m_Association )
|
||||
*m_Association = nullptr;
|
||||
|
||||
std::list< SGNODE* >::iterator sBP = m_BackPointers.begin();
|
||||
std::list< SGNODE* >::iterator eBP = m_BackPointers.end();
|
||||
|
||||
while( sBP != eBP )
|
||||
{
|
||||
(*sBP)->unlinkRefNode( this );
|
||||
++sBP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
S3D::SGTYPES SGNODE::GetNodeType( void ) const noexcept
|
||||
{
|
||||
return m_SGtype;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGNODE::GetParent( void ) const noexcept
|
||||
{
|
||||
return m_Parent;
|
||||
}
|
||||
|
||||
|
||||
bool SGNODE::SwapParent( SGNODE* aNewParent )
|
||||
{
|
||||
if( aNewParent == m_Parent )
|
||||
return true;
|
||||
|
||||
if( nullptr == aNewParent )
|
||||
return false;
|
||||
|
||||
if( nullptr == m_Parent )
|
||||
{
|
||||
if( aNewParent->AddChildNode( this ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( aNewParent->GetNodeType() != m_Parent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
SGNODE* oldParent = m_Parent;
|
||||
m_Parent->unlinkChildNode( this );
|
||||
m_Parent = nullptr;
|
||||
aNewParent->unlinkRefNode( this );
|
||||
aNewParent->AddChildNode( this );
|
||||
oldParent->AddRefNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const char* SGNODE::GetName( void )
|
||||
{
|
||||
if( m_Name.empty() )
|
||||
getNodeName( m_SGtype, m_Name );
|
||||
|
||||
return m_Name.c_str();
|
||||
}
|
||||
|
||||
|
||||
void SGNODE::SetName( const char* aName )
|
||||
{
|
||||
if( nullptr == aName || 0 == aName[0] )
|
||||
getNodeName( m_SGtype, m_Name );
|
||||
else
|
||||
m_Name = aName;
|
||||
}
|
||||
|
||||
|
||||
const char* SGNODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const noexcept
|
||||
{
|
||||
return node_names[aNodeType].c_str();
|
||||
}
|
||||
|
||||
|
||||
void SGNODE::addNodeRef( SGNODE* aNode )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return;
|
||||
|
||||
std::list< SGNODE* >::iterator np =
|
||||
std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
|
||||
|
||||
if( np != m_BackPointers.end() )
|
||||
return;
|
||||
|
||||
m_BackPointers.push_back( aNode );
|
||||
}
|
||||
|
||||
|
||||
void SGNODE::delNodeRef( const SGNODE* aNode )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return;
|
||||
|
||||
std::list< SGNODE* >::iterator np =
|
||||
std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
|
||||
|
||||
if( np != m_BackPointers.end() )
|
||||
{
|
||||
m_BackPointers.erase( np );
|
||||
return;
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] delNodeRef() did not find its target, this "
|
||||
"node type %d, referenced node type %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
m_SGtype,
|
||||
aNode->GetNodeType() );
|
||||
}
|
||||
|
||||
|
||||
void SGNODE::AssociateWrapper( SGNODE** aWrapperRef ) noexcept
|
||||
{
|
||||
wxCHECK( aWrapperRef && *aWrapperRef == this, /* void */ );
|
||||
|
||||
// if there is an existing association then break it and emit a warning
|
||||
// just in case the behavior is undesired
|
||||
if( m_Association )
|
||||
{
|
||||
*m_Association = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [WARNING] association being broken with "
|
||||
"previous wrapper" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
}
|
||||
|
||||
m_Association = aWrapperRef;
|
||||
}
|
||||
|
||||
void SGNODE::DisassociateWrapper( SGNODE** aWrapperRef ) noexcept
|
||||
{
|
||||
if( !m_Association )
|
||||
return;
|
||||
|
||||
wxCHECK( aWrapperRef, /* void */ );
|
||||
|
||||
wxCHECK( *aWrapperRef == *m_Association && aWrapperRef == m_Association, /* void */ );
|
||||
|
||||
m_Association = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGNODE::ResetNodeIndex( void ) noexcept
|
||||
{
|
||||
for( int i = 0; i < (int)S3D::SGTYPE_END; ++i )
|
||||
node_counts[i] = 1;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::GetMatIndex( MATLIST& aList, SGNODE* aNode, int& aIndex )
|
||||
{
|
||||
aIndex = 0;
|
||||
|
||||
wxCHECK( aNode && S3D::SGTYPE_APPEARANCE == aNode->GetNodeType(), false );
|
||||
|
||||
SGAPPEARANCE* node = (SGAPPEARANCE*)aNode;
|
||||
|
||||
std::map< SGAPPEARANCE const*, int >::iterator it = aList.matmap.find( node );
|
||||
|
||||
if( it != aList.matmap.end() )
|
||||
{
|
||||
aIndex = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
int idx = (int)aList.matorder.size();
|
||||
aList.matorder.push_back( node );
|
||||
aList.matmap.emplace( node, idx );
|
||||
aIndex = idx;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void S3D::INIT_SMATERIAL( SMATERIAL& aMaterial )
|
||||
{
|
||||
aMaterial = {};
|
||||
}
|
||||
|
||||
|
||||
void S3D::INIT_SMESH( SMESH& aMesh ) noexcept
|
||||
{
|
||||
aMesh = {};
|
||||
}
|
||||
|
||||
|
||||
void S3D::INIT_S3DMODEL( S3DMODEL& aModel ) noexcept
|
||||
{
|
||||
aModel = {};
|
||||
}
|
||||
|
||||
|
||||
void S3D::FREE_SMESH( SMESH& aMesh ) noexcept
|
||||
{
|
||||
if( nullptr != aMesh.m_Positions )
|
||||
{
|
||||
delete [] aMesh.m_Positions;
|
||||
aMesh.m_Positions = nullptr;
|
||||
}
|
||||
|
||||
if( nullptr != aMesh.m_Normals )
|
||||
{
|
||||
delete [] aMesh.m_Normals;
|
||||
aMesh.m_Normals = nullptr;
|
||||
}
|
||||
|
||||
if( nullptr != aMesh.m_Texcoords )
|
||||
{
|
||||
delete [] aMesh.m_Texcoords;
|
||||
aMesh.m_Texcoords = nullptr;
|
||||
}
|
||||
|
||||
if( nullptr != aMesh.m_Color )
|
||||
{
|
||||
delete [] aMesh.m_Color;
|
||||
aMesh.m_Color = nullptr;
|
||||
}
|
||||
|
||||
if( nullptr != aMesh.m_FaceIdx )
|
||||
{
|
||||
delete [] aMesh.m_FaceIdx;
|
||||
aMesh.m_FaceIdx = nullptr;
|
||||
}
|
||||
|
||||
aMesh.m_VertexSize = 0;
|
||||
aMesh.m_FaceIdxSize = 0;
|
||||
aMesh.m_MaterialIdx = 0;
|
||||
}
|
||||
|
||||
|
||||
void S3D::FREE_S3DMODEL( S3DMODEL& aModel )
|
||||
{
|
||||
if( nullptr != aModel.m_Materials )
|
||||
{
|
||||
delete [] aModel.m_Materials;
|
||||
aModel.m_Materials = nullptr;
|
||||
}
|
||||
|
||||
aModel.m_MaterialsSize = 0;
|
||||
|
||||
if( nullptr != aModel.m_Meshes )
|
||||
{
|
||||
for( unsigned int i = 0; i < aModel.m_MeshesSize; ++i )
|
||||
FREE_SMESH( aModel.m_Meshes[i] );
|
||||
|
||||
delete [] aModel.m_Meshes;
|
||||
aModel.m_Meshes = nullptr;
|
||||
}
|
||||
|
||||
aModel.m_MeshesSize = 0;
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_node.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SG_NODE_H
|
||||
#define SG_NODE_H
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "plugins/3dapi/c3dmodel.h"
|
||||
#include "plugins/3dapi/sg_base.h"
|
||||
#include "plugins/3dapi/sg_types.h"
|
||||
|
||||
class SGNODE;
|
||||
class SGAPPEARANCE;
|
||||
|
||||
namespace S3D
|
||||
{
|
||||
/**
|
||||
* Return the name of the given type of node
|
||||
*/
|
||||
char const* GetNodeTypeName( S3D::SGTYPES aType ) noexcept;
|
||||
|
||||
struct MATLIST
|
||||
{
|
||||
std::vector< SGAPPEARANCE const* > matorder; // materials in order of addition
|
||||
std::map< SGAPPEARANCE const*, int > matmap; // mapping from material to index
|
||||
};
|
||||
|
||||
bool GetMatIndex( MATLIST& aList, SGNODE* aNode, int& aIndex );
|
||||
|
||||
void INIT_SMATERIAL( SMATERIAL& aMaterial );
|
||||
void INIT_SMESH( SMESH& aMesh ) noexcept;
|
||||
void INIT_S3DMODEL( S3DMODEL& aModel ) noexcept;
|
||||
|
||||
void FREE_SMESH( SMESH& aMesh) noexcept;
|
||||
void FREE_S3DMODEL( S3DMODEL& aModel );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The base class of all Scene Graph nodes.
|
||||
*/
|
||||
class SGNODE
|
||||
{
|
||||
public:
|
||||
SGNODE( SGNODE* aParent );
|
||||
virtual ~SGNODE();
|
||||
|
||||
/**
|
||||
* Return the type of this node instance.
|
||||
*/
|
||||
S3D::SGTYPES GetNodeType( void ) const noexcept;
|
||||
|
||||
/**
|
||||
* Returns a pointer to the parent SGNODE of this object or NULL if the object has
|
||||
* no parent (ie. top level transform).
|
||||
*/
|
||||
SGNODE* GetParent( void ) const noexcept;
|
||||
|
||||
/**
|
||||
* Set the parent #SGNODE of this object.
|
||||
*
|
||||
* @param aParent [in] is the desired parent node
|
||||
* @return true if the operation succeeds; false if the given node is not allowed to
|
||||
* be a parent to the derived object.
|
||||
*/
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) = 0;
|
||||
|
||||
/**
|
||||
* Swap the ownership with the given parent.
|
||||
*
|
||||
* This operation may be required when reordering nodes for optimization.
|
||||
*
|
||||
* @param aNewParent will become the new parent to the object; it must be the same type
|
||||
* as the parent of this instance.
|
||||
*/
|
||||
bool SwapParent( SGNODE* aNewParent );
|
||||
|
||||
const char* GetName( void );
|
||||
void SetName(const char *aName);
|
||||
|
||||
const char * GetNodeTypeName( S3D::SGTYPES aNodeType ) const noexcept;
|
||||
|
||||
/**
|
||||
* Search the tree of linked nodes and return a reference to the first node found with
|
||||
* the given name.
|
||||
*
|
||||
* The reference is then typically added to another node via AddRefNode().
|
||||
*
|
||||
* @param aNodeName is the name of the node to search for.
|
||||
* @param aCaller is a pointer to the node invoking this function.
|
||||
* @return is a valid node pointer on success, otherwise NULL.
|
||||
*/
|
||||
virtual SGNODE* FindNode( const char *aNodeName, const SGNODE *aCaller ) = 0;
|
||||
|
||||
virtual bool AddRefNode( SGNODE* aNode ) = 0;
|
||||
|
||||
virtual bool AddChildNode( SGNODE* aNode ) = 0;
|
||||
|
||||
/**
|
||||
* Associate this object with a handle to itself.
|
||||
*
|
||||
* The handle is typically held by an IFSG* wrapper and the pointer which it refers to
|
||||
* is set to NULL upon destruction of this object. This mechanism provides a scheme
|
||||
* by which a wrapper can be notified of the destruction of the object which it wraps.
|
||||
*/
|
||||
void AssociateWrapper( SGNODE** aWrapperRef ) noexcept;
|
||||
|
||||
/**
|
||||
* Remove the association between an IFSG* wrapper object and this object.
|
||||
*/
|
||||
void DisassociateWrapper( SGNODE** aWrapperRef ) noexcept;
|
||||
|
||||
/**
|
||||
* Reset the global SG* node indices in preparation for write operations.
|
||||
*/
|
||||
void ResetNodeIndex( void ) noexcept;
|
||||
|
||||
/**
|
||||
* Rename a node and all its child nodes in preparation for write operations.
|
||||
*/
|
||||
virtual void ReNameNodes( void ) = 0;
|
||||
|
||||
/**
|
||||
* Writes this node's data to a VRML file.
|
||||
*
|
||||
* This includes all data of child and referenced nodes.
|
||||
*/
|
||||
virtual bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) = 0;
|
||||
|
||||
/**
|
||||
* Write this node's data to a binary cache file.
|
||||
*
|
||||
* The data includes all data of children and references to children. If this function
|
||||
* is invoked by the user, parentNode must be set to NULL in order to ensure coherent data.
|
||||
*/
|
||||
virtual bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) = 0;
|
||||
|
||||
/**
|
||||
* Reads binary format data from a cache file.
|
||||
*
|
||||
* To read a cache file, open the file for reading and invoke this function from a new
|
||||
* #SCENEGRAPH node.
|
||||
*/
|
||||
virtual bool ReadCache( std::istream& aFile, SGNODE* parentNode ) = 0;
|
||||
|
||||
/**
|
||||
* Remove references to an owned child.
|
||||
*
|
||||
* This is invoked by the child upon destruction to ensure that the parent has no
|
||||
* invalid references.
|
||||
*
|
||||
* @param aNode is the child which is being deleted.
|
||||
*/
|
||||
virtual void unlinkChildNode( const SGNODE* aNode ) = 0;
|
||||
|
||||
/**
|
||||
* Remove pointers to a referenced node.
|
||||
*
|
||||
* This is invoked by the referenced node upon destruction to ensure that the referring
|
||||
* node has no invalid references.
|
||||
*
|
||||
* @param aNode is the node which is being deleted.
|
||||
*/
|
||||
virtual void unlinkRefNode( const SGNODE* aNode ) = 0;
|
||||
|
||||
/**
|
||||
* Add a pointer to a node which references this node, but does not own.
|
||||
*
|
||||
* Such back-pointers are required to ensure that invalidated references are removed
|
||||
* when a node is deleted.
|
||||
*
|
||||
* @param aNode is the node holding a reference to this object.
|
||||
*/
|
||||
void addNodeRef( SGNODE* aNode );
|
||||
|
||||
/**
|
||||
* Remove a pointer to a node which references this node, but does not own.
|
||||
*
|
||||
* @param aNode is the node holding a reference to this object.
|
||||
*/
|
||||
void delNodeRef( const SGNODE* aNode );
|
||||
|
||||
/**
|
||||
* Return true if the object had already been written to a cache file or VRML file
|
||||
*
|
||||
* For internal use only.
|
||||
*/
|
||||
bool isWritten( void ) noexcept
|
||||
{
|
||||
return m_written;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::list< SGNODE* > m_BackPointers; ///< nodes which hold a reference to this.
|
||||
SGNODE* m_Parent; ///< Pointer to parent node; may be NULL for top level transform.
|
||||
S3D::SGTYPES m_SGtype; ///< Type of Scene Graph node.
|
||||
std::string m_Name; ///< name to use for referencing the entity by name.
|
||||
bool m_written; ///< Set to true when the object has been written after a ReNameNodes().
|
||||
|
||||
private:
|
||||
SGNODE** m_Association; ///< Handle to the instance held by a wrapper.
|
||||
};
|
||||
|
||||
#endif // SG_NODE_H
|
||||
@@ -1,299 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_normals.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
SGNORMALS::SGNORMALS( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_NORMALS;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGNORMALS "
|
||||
"(type %d)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGNORMALS::~SGNORMALS()
|
||||
{
|
||||
norms.clear();
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGFACESET may be parent to a SGNORMALS
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGNORMALS::FindNode( const char* aNodeName, const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::unlinkChildNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( false, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::unlinkRefNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( false, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::AddRefNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( false, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::AddChildNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( false, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList )
|
||||
{
|
||||
if( norms.empty() )
|
||||
{
|
||||
aListSize = 0;
|
||||
aNormalList = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
aListSize = norms.size();
|
||||
aNormalList = &norms[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::SetNormalList( size_t aListSize, const SGVECTOR* aNormalList )
|
||||
{
|
||||
norms.clear();
|
||||
|
||||
if( 0 == aListSize || nullptr == aNormalList )
|
||||
return;
|
||||
|
||||
for( int i = 0; i < (int)aListSize; ++i )
|
||||
norms.push_back( aNormalList[i] );
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::AddNormal( double aXValue, double aYValue, double aZValue )
|
||||
{
|
||||
norms.emplace_back( aXValue, aYValue, aZValue );
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::AddNormal( const SGVECTOR& aNormal )
|
||||
{
|
||||
norms.push_back( aNormal );
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( norms.empty() )
|
||||
return false;
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << " normal DEF " << GetName() << " Normal { vector [\n ";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " normal USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " normal Normal { vector [\n ";
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
size_t n = norms.size();
|
||||
bool nline = false;
|
||||
|
||||
for( size_t i = 0; i < n; )
|
||||
{
|
||||
S3D::FormatVector( tmp, norms[i] );
|
||||
aFile << tmp ;
|
||||
++i;
|
||||
|
||||
if( i < n )
|
||||
{
|
||||
aFile << ",";
|
||||
|
||||
if( nline )
|
||||
{
|
||||
aFile << "\n ";
|
||||
nline = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
nline = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "] }\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
size_t npts = norms.size();
|
||||
aFile.write( (char*)&npts, sizeof(size_t) );
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
S3D::WriteVector( aFile, norms[i] );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( norms.empty(), false );
|
||||
|
||||
size_t npts;
|
||||
aFile.read( (char*) &npts, sizeof( size_t ) );
|
||||
SGVECTOR tmp;
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
{
|
||||
if( !S3D::ReadVector( aFile, tmp ) || aFile.fail() )
|
||||
return false;
|
||||
|
||||
norms.push_back( tmp );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_normals.h
|
||||
*/
|
||||
|
||||
#ifndef SG_NORMALS_H
|
||||
#define SG_NORMALS_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
/**
|
||||
* Define a set of vertex normals for a scene graph object
|
||||
*/
|
||||
class SGNORMALS : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGNORMALS( SGNODE* aParent );
|
||||
virtual ~SGNORMALS();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
SGNODE* FindNode( const char* aNodeName, const SGNODE* aCaller ) noexcept override;
|
||||
bool AddRefNode( SGNODE* aNode ) noexcept override;
|
||||
bool AddChildNode( SGNODE* aNode ) noexcept override;
|
||||
|
||||
bool GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList );
|
||||
void SetNormalList( size_t aListSize, const SGVECTOR* aNormalList );
|
||||
void AddNormal( double aXValue, double aYValue, double aZValue );
|
||||
void AddNormal( const SGVECTOR& aNormal );
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
|
||||
|
||||
std::vector< SGVECTOR > norms;
|
||||
};
|
||||
|
||||
#endif // SG_NORMALS_H
|
||||
@@ -1,783 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_shape.h"
|
||||
#include "3d_cache/sg/sg_faceset.h"
|
||||
#include "3d_cache/sg/sg_appearance.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
#include "3d_cache/sg/sg_coordindex.h"
|
||||
#include "3d_cache/sg/sg_coords.h"
|
||||
#include "3d_cache/sg/sg_colors.h"
|
||||
#include "3d_cache/sg/sg_normals.h"
|
||||
|
||||
|
||||
SGSHAPE::SGSHAPE( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_SHAPE;
|
||||
m_Appearance = nullptr;
|
||||
m_RAppearance = nullptr;
|
||||
m_FaceSet = nullptr;
|
||||
m_RFaceSet = nullptr;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGSHAPE (type %d)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGSHAPE::~SGSHAPE()
|
||||
{
|
||||
// drop references
|
||||
if( m_RAppearance )
|
||||
{
|
||||
m_RAppearance->delNodeRef( this );
|
||||
m_RAppearance = nullptr;
|
||||
}
|
||||
|
||||
if( m_RFaceSet )
|
||||
{
|
||||
m_RFaceSet->delNodeRef( this );
|
||||
m_RFaceSet = nullptr;
|
||||
}
|
||||
|
||||
// delete objects
|
||||
if( m_Appearance )
|
||||
{
|
||||
m_Appearance->SetParent( nullptr, false );
|
||||
delete m_Appearance;
|
||||
m_Appearance = nullptr;
|
||||
}
|
||||
|
||||
if( m_FaceSet )
|
||||
{
|
||||
m_FaceSet->SetParent( nullptr, false );
|
||||
delete m_FaceSet;
|
||||
m_FaceSet = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGTRANSFORM may be parent to a SGSHAPE
|
||||
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGSHAPE::FindNode( const char* aNodeName, const SGNODE* aCaller )
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
SGNODE* tmp = nullptr;
|
||||
|
||||
if( nullptr != m_Appearance )
|
||||
{
|
||||
tmp = m_Appearance->FindNode( aNodeName, this );
|
||||
|
||||
if( tmp )
|
||||
{
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if( nullptr != m_FaceSet )
|
||||
{
|
||||
tmp = m_FaceSet->FindNode( aNodeName, this );
|
||||
|
||||
if( tmp )
|
||||
{
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// query the parent if appropriate
|
||||
if( aCaller == m_Parent || nullptr == m_Parent )
|
||||
return nullptr;
|
||||
|
||||
return m_Parent->FindNode( aNodeName, this );
|
||||
}
|
||||
|
||||
|
||||
void SGSHAPE::unlinkNode( const SGNODE* aNode, bool isChild )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return;
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
if( aNode == m_Appearance )
|
||||
{
|
||||
m_Appearance = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_FaceSet )
|
||||
{
|
||||
m_FaceSet = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aNode == m_RAppearance )
|
||||
{
|
||||
delNodeRef( this );
|
||||
m_RAppearance = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_RFaceSet )
|
||||
{
|
||||
delNodeRef( this );
|
||||
m_RFaceSet = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
void SGSHAPE::unlinkChildNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, true );
|
||||
}
|
||||
|
||||
|
||||
void SGSHAPE::unlinkRefNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, false );
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::addNode( SGNODE* aNode, bool isChild )
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
if( S3D::SGTYPE_APPEARANCE == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_Appearance || m_RAppearance )
|
||||
{
|
||||
if( aNode != m_Appearance && aNode != m_RAppearance )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Appearance "
|
||||
"nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
m_Appearance = (SGAPPEARANCE*)aNode;
|
||||
m_Appearance->SetParent( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RAppearance = (SGAPPEARANCE*)aNode;
|
||||
m_RAppearance->addNodeRef( this );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_FACESET == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_FaceSet || m_RFaceSet )
|
||||
{
|
||||
if( aNode != m_FaceSet && aNode != m_RFaceSet )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple FaceSet nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
m_FaceSet = (SGFACESET*)aNode;
|
||||
m_FaceSet->SetParent( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RFaceSet = (SGFACESET*)aNode;
|
||||
m_RFaceSet->addNodeRef( this );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] object %s is not a valid type for this "
|
||||
"object (%d)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aNode->GetName(), aNode->GetNodeType() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::AddRefNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, false );
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::AddChildNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, true );
|
||||
}
|
||||
|
||||
|
||||
void SGSHAPE::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
|
||||
// rename Appearance
|
||||
if( m_Appearance )
|
||||
m_Appearance->ReNameNodes();
|
||||
|
||||
// rename FaceSet
|
||||
if( m_FaceSet )
|
||||
m_FaceSet->ReNameNodes();
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( !m_Appearance && !m_RAppearance && !m_FaceSet && !m_RFaceSet )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << "DEF " << GetName() << " Shape {\n";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " Shape {\n";
|
||||
}
|
||||
|
||||
if( m_Appearance )
|
||||
m_Appearance->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_RAppearance )
|
||||
m_RAppearance->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_FaceSet )
|
||||
m_FaceSet->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_RFaceSet )
|
||||
m_RFaceSet->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
aFile << "}\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if any references are unwritten and swap parents if so
|
||||
if( nullptr != m_RAppearance && !m_RAppearance->isWritten() )
|
||||
m_RAppearance->SwapParent(this);
|
||||
|
||||
if( nullptr != m_RFaceSet && !m_RFaceSet->isWritten() )
|
||||
m_RFaceSet->SwapParent( this );
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
#define NITEMS 4
|
||||
bool items[NITEMS];
|
||||
int i;
|
||||
|
||||
for( i = 0; i < NITEMS; ++i )
|
||||
items[i] = 0;
|
||||
|
||||
i = 0;
|
||||
|
||||
if( nullptr != m_Appearance )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
|
||||
if( nullptr != m_RAppearance )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
|
||||
if( nullptr != m_FaceSet )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
|
||||
if( nullptr != m_RFaceSet )
|
||||
items[i] = true;
|
||||
|
||||
for( int jj = 0; jj < NITEMS; ++jj )
|
||||
aFile.write( (char*)&items[jj], sizeof(bool) );
|
||||
|
||||
if( items[0] )
|
||||
m_Appearance->WriteCache( aFile, this );
|
||||
|
||||
if( items[1] )
|
||||
aFile << "[" << m_RAppearance->GetName() << "]";
|
||||
|
||||
if( items[2] )
|
||||
m_FaceSet->WriteCache( aFile, this );
|
||||
|
||||
if( items[3] )
|
||||
aFile << "[" << m_RFaceSet->GetName() << "]";
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( m_Appearance == nullptr && m_RAppearance == nullptr && m_FaceSet == nullptr &&
|
||||
m_RFaceSet == nullptr, false );
|
||||
|
||||
#define NITEMS 4
|
||||
bool items[NITEMS];
|
||||
|
||||
for( int i = 0; i < NITEMS; ++i )
|
||||
aFile.read( (char*)&items[i], sizeof(bool) );
|
||||
|
||||
if( ( items[0] && items[1] ) || ( items[2] && items[3] ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; multiple item definitions "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
if( items[0] )
|
||||
{
|
||||
if( S3D::SGTYPE_APPEARANCE != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child appearance "
|
||||
"tag at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Appearance = new SGAPPEARANCE( this );
|
||||
m_Appearance->SetName( name.c_str() );
|
||||
|
||||
if( !m_Appearance->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading appearance "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[1] )
|
||||
{
|
||||
if( S3D::SGTYPE_APPEARANCE != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref appearance tag "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* np = FindNode( name.c_str(), this );
|
||||
|
||||
if( !np )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref "
|
||||
"appearance '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_APPEARANCE != np->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not "
|
||||
"SGAPPEARANCE '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_RAppearance = (SGAPPEARANCE*)np;
|
||||
m_RAppearance->addNodeRef( this );
|
||||
}
|
||||
|
||||
if( items[2] )
|
||||
{
|
||||
if( S3D::SGTYPE_FACESET != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child face set tag "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_FaceSet = new SGFACESET( this );
|
||||
m_FaceSet->SetName( name.c_str() );
|
||||
|
||||
if( !m_FaceSet->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading face set "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[3] )
|
||||
{
|
||||
if( S3D::SGTYPE_FACESET != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref face set tag at "
|
||||
"position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* np = FindNode( name.c_str(), this );
|
||||
|
||||
if( !np )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref face "
|
||||
"set '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_FACESET != np->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGFACESET "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_RFaceSet = (SGFACESET*)np;
|
||||
m_RFaceSet->addNodeRef( this );
|
||||
}
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
|
||||
std::vector< SMESH >& meshes )
|
||||
{
|
||||
SMESH m;
|
||||
S3D::INIT_SMESH( m );
|
||||
|
||||
SGAPPEARANCE* pa = m_Appearance;
|
||||
SGFACESET* pf = m_FaceSet;
|
||||
|
||||
if( nullptr == pa )
|
||||
pa = m_RAppearance;
|
||||
|
||||
if( nullptr == pf )
|
||||
pf = m_RFaceSet;
|
||||
|
||||
// no face sets = nothing to render, which is valid though pointless
|
||||
if( nullptr == pf )
|
||||
return true;
|
||||
|
||||
if( !pf->validate() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; inconsistent data" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( nullptr == pa )
|
||||
{
|
||||
m.m_MaterialIdx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx;
|
||||
|
||||
if( !S3D::GetMatIndex( materials, pa, idx ) )
|
||||
{
|
||||
m.m_MaterialIdx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m.m_MaterialIdx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
SGCOLORS* pc = pf->m_Colors;
|
||||
SGCOORDS* pv = pf->m_Coords;
|
||||
SGCOORDINDEX* vidx = pf->m_CoordIndices;
|
||||
SGNORMALS* pn = pf->m_Normals;
|
||||
|
||||
if( nullptr == pc )
|
||||
pc = pf->m_RColors;
|
||||
|
||||
if( nullptr == pv )
|
||||
pv = pf->m_RCoords;
|
||||
|
||||
if( nullptr == pn )
|
||||
pn = pf->m_RNormals;
|
||||
|
||||
// set the vertex points and indices
|
||||
size_t nCoords = 0;
|
||||
SGPOINT* pCoords = nullptr;
|
||||
pv->GetCoordsList( nCoords, pCoords );
|
||||
|
||||
size_t nColors = 0;
|
||||
SGCOLOR* pColors = nullptr;
|
||||
|
||||
if( pc )
|
||||
{
|
||||
// check the vertex colors
|
||||
pc->GetColorList( nColors, pColors );
|
||||
|
||||
if( nColors < nCoords )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; not enough colors per "
|
||||
"vertex (%ul vs %ul)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, static_cast<unsigned long>( nColors ),
|
||||
static_cast<unsigned long>( nCoords ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// set the vertex indices
|
||||
size_t nvidx = 0;
|
||||
int* lv = nullptr;
|
||||
vidx->GetIndices( nvidx, lv );
|
||||
|
||||
// note: reduce the vertex set to include only the referenced vertices
|
||||
std::vector< int > vertices; // store the list of temp vertex indices
|
||||
std::map< int, unsigned int > indexmap; // map temp vertex to true vertex
|
||||
std::map< int, unsigned int >::iterator mit;
|
||||
|
||||
for( unsigned int i = 0; i < nvidx; ++i )
|
||||
{
|
||||
mit = indexmap.find( lv[i] );
|
||||
|
||||
if( mit == indexmap.end() )
|
||||
{
|
||||
indexmap.emplace( lv[i], vertices.size() );
|
||||
vertices.push_back( lv[i] );
|
||||
}
|
||||
}
|
||||
|
||||
if( vertices.size() < 3 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; not enough vertices" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// construct the final vertex/color list
|
||||
SFVEC3F* lColors = nullptr;
|
||||
SFVEC3F* lCoords = new SFVEC3F[ vertices.size() ];
|
||||
int ti;
|
||||
|
||||
if( pc )
|
||||
{
|
||||
lColors = new SFVEC3F[vertices.size()];
|
||||
m.m_Color = lColors;
|
||||
}
|
||||
|
||||
if( pc )
|
||||
{
|
||||
for( size_t i = 0; i < vertices.size(); ++i )
|
||||
{
|
||||
ti = vertices[i];
|
||||
glm::dvec4 pt( pCoords[ti].x, pCoords[ti].y, pCoords[ti].z, 1.0 );
|
||||
pt = (*aTransform) * pt;
|
||||
pColors[ti].GetColor( lColors[i].x, lColors[i].y, lColors[i].z );
|
||||
lCoords[i] = SFVEC3F( pt.x, pt.y, pt.z );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( size_t i = 0; i < vertices.size(); ++i )
|
||||
{
|
||||
ti = vertices[i];
|
||||
glm::dvec4 pt( pCoords[ti].x, pCoords[ti].y, pCoords[ti].z, 1.0 );
|
||||
pt = (*aTransform) * pt;
|
||||
lCoords[i] = SFVEC3F( pt.x, pt.y, pt.z );
|
||||
}
|
||||
}
|
||||
|
||||
m.m_VertexSize = (unsigned int) vertices.size();
|
||||
m.m_Positions = lCoords;
|
||||
unsigned int* lvidx = new unsigned int[ nvidx ];
|
||||
|
||||
for( unsigned int i = 0; i < nvidx; ++i )
|
||||
{
|
||||
mit = indexmap.find( lv[i] );
|
||||
lvidx[i] = mit->second;
|
||||
}
|
||||
|
||||
m.m_FaceIdxSize = (unsigned int )nvidx;
|
||||
m.m_FaceIdx = lvidx;
|
||||
|
||||
// set the per-vertex normals
|
||||
size_t nNorms = 0;
|
||||
SGVECTOR* pNorms = nullptr;
|
||||
double x, y, z;
|
||||
|
||||
pn->GetNormalList( nNorms, pNorms );
|
||||
SFVEC3F* lNorms = new SFVEC3F[ vertices.size() ];
|
||||
|
||||
for( size_t i = 0; i < vertices.size(); ++i )
|
||||
{
|
||||
ti = vertices[i];
|
||||
pNorms[ti].GetVector( x, y, z );
|
||||
glm::dvec4 pt( x, y, z, 0.0 );
|
||||
pt = (*aTransform) * pt;
|
||||
|
||||
lNorms[i] = SFVEC3F( pt.x, pt.y, pt.z );
|
||||
}
|
||||
|
||||
m.m_Normals = lNorms;
|
||||
meshes.push_back( m );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_shape.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SG_SHAPE_H
|
||||
#define SG_SHAPE_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
class SGAPPEARANCE;
|
||||
class SGFACESET;
|
||||
|
||||
/**
|
||||
* Define a complex 3D shape for a scenegraph object.
|
||||
*/
|
||||
class SGSHAPE : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGSHAPE( SGNODE* aParent );
|
||||
virtual ~SGSHAPE();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
SGNODE* FindNode(const char* aNodeName, const SGNODE* aCaller) override;
|
||||
bool AddRefNode( SGNODE* aNode ) override;
|
||||
bool AddChildNode( SGNODE* aNode ) override;
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
bool Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
|
||||
std::vector< SMESH >& meshes );
|
||||
|
||||
void unlinkChildNode( const SGNODE* aNode ) override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) override;
|
||||
|
||||
private:
|
||||
void unlinkNode( const SGNODE* aNode, bool isChild );
|
||||
bool addNode( SGNODE* aNode, bool isChild );
|
||||
|
||||
public:
|
||||
// owned node
|
||||
SGAPPEARANCE* m_Appearance;
|
||||
SGFACESET* m_FaceSet;
|
||||
|
||||
// referenced nodes
|
||||
SGAPPEARANCE* m_RAppearance;
|
||||
SGFACESET* m_RFaceSet;
|
||||
};
|
||||
|
||||
/*
|
||||
p.107
|
||||
Shape {
|
||||
appearance NULL
|
||||
geometry NULL
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // SG_SHAPE_H
|
||||
@@ -0,0 +1,735 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_canvas.cpp
|
||||
*/
|
||||
#include <fctsys.h>
|
||||
#include <trigo.h>
|
||||
#include <project.h>
|
||||
#include <gestfich.h>
|
||||
|
||||
#include <wx/image.h>
|
||||
|
||||
#if !wxUSE_GLCANVAS
|
||||
#error Please set wxUSE_GLCANVAS to 1 in setup.h.
|
||||
#endif
|
||||
|
||||
#include <wx/dataobj.h>
|
||||
#include <wx/clipbrd.h>
|
||||
#include <wx/wupdlock.h>
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <GL/glew.h> // must be included before gl.h
|
||||
#endif
|
||||
|
||||
#include <3d_viewer.h>
|
||||
#include <3d_canvas.h>
|
||||
#include <info3d_visu.h>
|
||||
#include <trackball.h>
|
||||
#include <3d_viewer_id.h>
|
||||
|
||||
#include <textures/text_silk.h>
|
||||
#include <textures/text_pcb.h>
|
||||
|
||||
|
||||
static const double DELTA_MOVE_STEP = 0.7;
|
||||
|
||||
|
||||
/*
|
||||
* EDA_3D_CANVAS implementation
|
||||
*/
|
||||
|
||||
BEGIN_EVENT_TABLE( EDA_3D_CANVAS, wxGLCanvas )
|
||||
EVT_PAINT( EDA_3D_CANVAS::OnPaint )
|
||||
|
||||
// key event:
|
||||
EVT_CHAR( EDA_3D_CANVAS::OnChar )
|
||||
|
||||
// mouse events
|
||||
EVT_RIGHT_DOWN( EDA_3D_CANVAS::OnRightClick )
|
||||
EVT_MOUSEWHEEL( EDA_3D_CANVAS::OnMouseWheel )
|
||||
#ifdef USE_OSX_MAGNIFY_EVENT
|
||||
EVT_MAGNIFY( EDA_3D_CANVAS::OnMagnify )
|
||||
#endif
|
||||
EVT_MOTION( EDA_3D_CANVAS::OnMouseMove )
|
||||
|
||||
// other events
|
||||
EVT_ERASE_BACKGROUND( EDA_3D_CANVAS::OnEraseBackground )
|
||||
EVT_MENU_RANGE( ID_POPUP_3D_VIEW_START, ID_POPUP_3D_VIEW_END, EDA_3D_CANVAS::OnPopUpMenu )
|
||||
END_EVENT_TABLE()
|
||||
|
||||
// Define an invalid value for some unsigned int indexes
|
||||
#define INVALID_INDEX GL_INVALID_VALUE
|
||||
|
||||
EDA_3D_CANVAS::EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList ) :
|
||||
wxGLCanvas( parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
|
||||
wxFULL_REPAINT_ON_RESIZE )
|
||||
{
|
||||
m_init = false;
|
||||
m_reportWarnings = true;
|
||||
m_shadow_init = false;
|
||||
// set an invalid value to not yet initialized indexes managing
|
||||
// textures created to enhance 3D rendering
|
||||
m_text_pcb = m_text_silk = INVALID_INDEX;
|
||||
m_text_fake_shadow_front = INVALID_INDEX;
|
||||
m_text_fake_shadow_back = INVALID_INDEX;
|
||||
m_text_fake_shadow_board = INVALID_INDEX;
|
||||
|
||||
// position of the front and back layers
|
||||
// (will be initialized to a better value later)
|
||||
m_ZBottom = 0.0;
|
||||
m_ZTop = 0.0;
|
||||
|
||||
m_lightPos = S3D_VERTEX(0.0f, 0.0f, 30.0f);
|
||||
|
||||
// Clear all gl list identifiers:
|
||||
for( int ii = GL_ID_BEGIN; ii < GL_ID_END; ii++ )
|
||||
m_glLists[ii] = 0;
|
||||
|
||||
// Explicitly create a new rendering context instance for this canvas.
|
||||
m_glRC = new wxGLContext( this );
|
||||
|
||||
DisplayStatus();
|
||||
}
|
||||
|
||||
|
||||
EDA_3D_CANVAS::~EDA_3D_CANVAS()
|
||||
{
|
||||
ClearLists();
|
||||
m_init = false;
|
||||
delete m_glRC;
|
||||
|
||||
// Free the list of parsers list
|
||||
for( unsigned int i = 0; i < m_model_parsers_list.size(); i++ )
|
||||
delete m_model_parsers_list[i];
|
||||
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::ClearLists( int aGlList )
|
||||
{
|
||||
if( aGlList )
|
||||
{
|
||||
if( m_glLists[aGlList] > 0 )
|
||||
glDeleteLists( m_glLists[aGlList], 1 );
|
||||
|
||||
m_glLists[aGlList] = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for( int ii = GL_ID_BEGIN; ii < GL_ID_END; ii++ )
|
||||
{
|
||||
if( m_glLists[ii] > 0 )
|
||||
glDeleteLists( m_glLists[ii], 1 );
|
||||
|
||||
m_glLists[ii] = 0;
|
||||
}
|
||||
|
||||
// When m_text_fake_shadow_??? is set to INVALID_INDEX, textures are not yet created.
|
||||
if( m_text_fake_shadow_front != INVALID_INDEX )
|
||||
glDeleteTextures( 1, &m_text_fake_shadow_front );
|
||||
|
||||
if( m_text_fake_shadow_back != INVALID_INDEX )
|
||||
glDeleteTextures( 1, &m_text_fake_shadow_back );
|
||||
|
||||
if( m_text_fake_shadow_board != INVALID_INDEX )
|
||||
glDeleteTextures( 1, &m_text_fake_shadow_board );
|
||||
|
||||
m_shadow_init = false;
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnChar( wxKeyEvent& event )
|
||||
{
|
||||
SetView3D( event.GetKeyCode() );
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::SetView3D( int keycode )
|
||||
{
|
||||
int ii;
|
||||
double delta_move = DELTA_MOVE_STEP * GetPrm3DVisu().m_Zoom;
|
||||
|
||||
switch( keycode )
|
||||
{
|
||||
case WXK_LEFT:
|
||||
m_draw3dOffset.x -= delta_move;
|
||||
break;
|
||||
|
||||
case WXK_RIGHT:
|
||||
m_draw3dOffset.x += delta_move;
|
||||
break;
|
||||
|
||||
case WXK_UP:
|
||||
m_draw3dOffset.y += delta_move;
|
||||
break;
|
||||
|
||||
case WXK_DOWN:
|
||||
m_draw3dOffset.y -= delta_move;
|
||||
break;
|
||||
|
||||
case WXK_HOME:
|
||||
GetPrm3DVisu().m_Zoom = 1.0;
|
||||
m_draw3dOffset.x = m_draw3dOffset.y = 0;
|
||||
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
break;
|
||||
|
||||
case WXK_END:
|
||||
break;
|
||||
|
||||
case WXK_F1:
|
||||
GetPrm3DVisu().m_Zoom /= 1.4;
|
||||
if( GetPrm3DVisu().m_Zoom <= 0.01 )
|
||||
GetPrm3DVisu().m_Zoom = 0.01;
|
||||
break;
|
||||
|
||||
case WXK_F2:
|
||||
GetPrm3DVisu().m_Zoom *= 1.4;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
break;
|
||||
|
||||
case '-':
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
case 'R':
|
||||
m_draw3dOffset.x = m_draw3dOffset.y = 0;
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
GetPrm3DVisu().m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
GetPrm3DVisu().m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
GetPrm3DVisu().m_ROTZ = -90;
|
||||
GetPrm3DVisu().m_ROTX = -90;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
GetPrm3DVisu().m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
GetPrm3DVisu().m_ROTZ = 90;
|
||||
GetPrm3DVisu().m_ROTX = -90;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
GetPrm3DVisu().m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
GetPrm3DVisu().m_ROTX = -90;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
GetPrm3DVisu().m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
GetPrm3DVisu().m_ROTX = -90;
|
||||
GetPrm3DVisu().m_ROTZ = -180;
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
GetPrm3DVisu().m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
GetPrm3DVisu().m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
GetPrm3DVisu().m_ROTX = -180;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayStatus();
|
||||
Refresh( false );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent& event )
|
||||
{
|
||||
double delta = DELTA_MOVE_STEP * GetPrm3DVisu().m_Zoom;
|
||||
if ( GetPrm3DVisu().GetFlag( FL_MOUSEWHEEL_PANNING ) )
|
||||
delta *= 0.05 * event.GetWheelRotation();
|
||||
else
|
||||
if ( event.GetWheelRotation() < 0 )
|
||||
delta = -delta;
|
||||
|
||||
if( GetPrm3DVisu().GetFlag( FL_MOUSEWHEEL_PANNING ) )
|
||||
{
|
||||
if( event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL )
|
||||
m_draw3dOffset.x -= delta;
|
||||
else
|
||||
m_draw3dOffset.y -= delta;
|
||||
}
|
||||
else if( event.ShiftDown() )
|
||||
{
|
||||
m_draw3dOffset.y -= delta;
|
||||
}
|
||||
else if( event.ControlDown() )
|
||||
{
|
||||
m_draw3dOffset.x += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( event.GetWheelRotation() > 0 )
|
||||
{
|
||||
GetPrm3DVisu().m_Zoom /= 1.4;
|
||||
|
||||
if( GetPrm3DVisu().m_Zoom <= 0.01 )
|
||||
GetPrm3DVisu().m_Zoom = 0.01;
|
||||
}
|
||||
else
|
||||
GetPrm3DVisu().m_Zoom *= 1.4;
|
||||
|
||||
}
|
||||
|
||||
DisplayStatus();
|
||||
Refresh( false );
|
||||
GetPrm3DVisu().m_Beginx = event.GetX();
|
||||
GetPrm3DVisu().m_Beginy = event.GetY();
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_OSX_MAGNIFY_EVENT
|
||||
void EDA_3D_CANVAS::OnMagnify( wxMouseEvent& event )
|
||||
{
|
||||
double magnification = ( event.GetMagnification() + 1.0f );
|
||||
|
||||
GetPrm3DVisu().m_Zoom /= magnification;
|
||||
|
||||
if( GetPrm3DVisu().m_Zoom <= 0.01 )
|
||||
{
|
||||
GetPrm3DVisu().m_Zoom = 0.01;
|
||||
}
|
||||
|
||||
DisplayStatus();
|
||||
Refresh( false );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent& event )
|
||||
{
|
||||
wxSize size( GetClientSize() );
|
||||
double spin_quat[4];
|
||||
|
||||
if( event.Dragging() )
|
||||
{
|
||||
if( event.LeftIsDown() )
|
||||
{
|
||||
/* drag in progress, simulate trackball */
|
||||
trackball( spin_quat,
|
||||
(2.0 * GetPrm3DVisu().m_Beginx - size.x) / size.x,
|
||||
(size.y - 2.0 * GetPrm3DVisu().m_Beginy) / size.y,
|
||||
( 2.0 * event.GetX() - size.x) / size.x,
|
||||
( size.y - 2.0 * event.GetY() ) / size.y );
|
||||
|
||||
add_quats( spin_quat, GetPrm3DVisu().m_Quat, GetPrm3DVisu().m_Quat );
|
||||
}
|
||||
else if( event.MiddleIsDown() )
|
||||
{
|
||||
/* middle button drag -> pan */
|
||||
|
||||
/* Current zoom and an additional factor are taken into account
|
||||
* for the amount of panning. */
|
||||
const double PAN_FACTOR = 8.0 * GetPrm3DVisu().m_Zoom;
|
||||
m_draw3dOffset.x -= PAN_FACTOR *
|
||||
( GetPrm3DVisu().m_Beginx - event.GetX() ) / size.x;
|
||||
m_draw3dOffset.y -= PAN_FACTOR *
|
||||
(event.GetY() - GetPrm3DVisu().m_Beginy) / size.y;
|
||||
}
|
||||
|
||||
/* orientation has changed, redraw mesh */
|
||||
DisplayStatus();
|
||||
Refresh( false );
|
||||
}
|
||||
|
||||
GetPrm3DVisu().m_Beginx = event.GetX();
|
||||
GetPrm3DVisu().m_Beginy = event.GetY();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnRightClick( wxMouseEvent& event )
|
||||
{
|
||||
wxPoint pos;
|
||||
wxMenu PopUpMenu;
|
||||
|
||||
pos.x = event.GetX();
|
||||
pos.y = event.GetY();
|
||||
|
||||
wxMenuItem* item = new wxMenuItem( &PopUpMenu, ID_POPUP_ZOOMIN, _( "Zoom +" ) );
|
||||
item->SetBitmap( KiBitmap( zoom_in_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_ZOOMOUT, _( "Zoom -" ) );
|
||||
item->SetBitmap( KiBitmap( zoom_out_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
PopUpMenu.AppendSeparator();
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZPOS, _( "Top View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_top_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZNEG, _( "Bottom View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_bottom_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
PopUpMenu.AppendSeparator();
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_XPOS, _( "Right View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_right_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_XNEG, _( "Left View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_left_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
PopUpMenu.AppendSeparator();
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_YPOS, _( "Front View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_front_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_YNEG, _( "Back View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_back_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
PopUpMenu.AppendSeparator();
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_LEFT, _( "Move left <-" ) );
|
||||
item->SetBitmap( KiBitmap( left_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_RIGHT, _( "Move right ->" ) );
|
||||
item->SetBitmap( KiBitmap( right_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_UP, _( "Move Up ^" ) );
|
||||
item->SetBitmap( KiBitmap( up_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_DOWN, _( "Move Down" ) );
|
||||
item->SetBitmap( KiBitmap( down_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
PopupMenu( &PopUpMenu, pos );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnPopUpMenu( wxCommandEvent& event )
|
||||
{
|
||||
int key = 0;
|
||||
|
||||
switch( event.GetId() )
|
||||
{
|
||||
case ID_POPUP_ZOOMIN:
|
||||
key = WXK_F1;
|
||||
break;
|
||||
|
||||
case ID_POPUP_ZOOMOUT:
|
||||
key = WXK_F2;
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_XPOS:
|
||||
key = 'x';
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_XNEG:
|
||||
key = 'X';
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_YPOS:
|
||||
key = 'y';
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_YNEG:
|
||||
key = 'Y';
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_ZPOS:
|
||||
key = 'z';
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_ZNEG:
|
||||
key = 'Z';
|
||||
break;
|
||||
|
||||
case ID_POPUP_MOVE3D_LEFT:
|
||||
key = WXK_LEFT;
|
||||
break;
|
||||
|
||||
case ID_POPUP_MOVE3D_RIGHT:
|
||||
key = WXK_RIGHT;
|
||||
break;
|
||||
|
||||
case ID_POPUP_MOVE3D_UP:
|
||||
key = WXK_UP;
|
||||
break;
|
||||
|
||||
case ID_POPUP_MOVE3D_DOWN:
|
||||
key = WXK_DOWN;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
SetView3D( key );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::DisplayStatus()
|
||||
{
|
||||
wxString msg;
|
||||
|
||||
msg.Printf( wxT( "dx %3.2f" ), m_draw3dOffset.x );
|
||||
Parent()->SetStatusText( msg, 1 );
|
||||
|
||||
msg.Printf( wxT( "dy %3.2f" ), m_draw3dOffset.y );
|
||||
Parent()->SetStatusText( msg, 2 );
|
||||
|
||||
msg.Printf( _( "Zoom: %3.1f" ), 45 * GetPrm3DVisu().m_Zoom );
|
||||
Parent()->SetStatusText( msg, 3 );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnPaint( wxPaintEvent& event )
|
||||
{
|
||||
wxPaintDC dc( this );
|
||||
|
||||
Redraw();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnEraseBackground( wxEraseEvent& event )
|
||||
{
|
||||
// Do nothing, to avoid flashing.
|
||||
}
|
||||
|
||||
typedef struct s_sImage
|
||||
{
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
|
||||
unsigned char pixel_data[64 * 64 * 4 + 1];
|
||||
}tsImage;
|
||||
|
||||
|
||||
GLuint load_and_generate_texture( tsImage *image )
|
||||
{
|
||||
|
||||
GLuint texture;
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
|
||||
glPixelStorei (GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
glGenTextures( 1, &texture );
|
||||
glBindTexture( GL_TEXTURE_2D, texture );
|
||||
gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, image->width, image->height,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, image->pixel_data );
|
||||
|
||||
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
|
||||
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::InitGL()
|
||||
{
|
||||
if( !m_init )
|
||||
{
|
||||
m_init = true;
|
||||
|
||||
|
||||
m_text_pcb = load_and_generate_texture( (tsImage *)&text_pcb );
|
||||
m_text_silk = load_and_generate_texture( (tsImage *)&text_silk );
|
||||
|
||||
GetPrm3DVisu().m_Zoom = 1.0;
|
||||
m_ZBottom = 1.0;
|
||||
m_ZTop = 10.0;
|
||||
|
||||
glDisable( GL_CULL_FACE ); // show back faces
|
||||
glEnable( GL_DEPTH_TEST ); // Enable z-buffering
|
||||
glEnable( GL_ALPHA_TEST );
|
||||
glEnable( GL_LINE_SMOOTH );
|
||||
// glEnable(GL_POLYGON_SMOOTH); // creates issues with some graphic cards
|
||||
glEnable( GL_NORMALIZE );
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
|
||||
|
||||
// speedups
|
||||
//glEnable( GL_DITHER );
|
||||
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE );
|
||||
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
|
||||
glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
|
||||
|
||||
// Initialize alpha blending function.
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::SetLights()
|
||||
{
|
||||
// activate light. the source is above the xy plane, at source_pos
|
||||
GLfloat source_pos[4] = { m_lightPos.x, m_lightPos.y, m_lightPos.z, 0.0f };
|
||||
GLfloat light_color[4]; // color of lights (RGBA values)
|
||||
light_color[3] = 1.0;
|
||||
|
||||
// Light above the xy plane
|
||||
light_color[0] = light_color[1] = light_color[2] = 0.0;
|
||||
glLightfv( GL_LIGHT0, GL_AMBIENT, light_color );
|
||||
|
||||
light_color[0] = light_color[1] = light_color[2] = 1.0;
|
||||
glLightfv( GL_LIGHT0, GL_DIFFUSE, light_color );
|
||||
|
||||
light_color[0] = light_color[1] = light_color[2] = 1.0;
|
||||
glLightfv( GL_LIGHT0, GL_SPECULAR, light_color );
|
||||
|
||||
glLightfv( GL_LIGHT0, GL_POSITION, source_pos );
|
||||
|
||||
light_color[0] = light_color[1] = light_color[2] = 0.2;
|
||||
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, light_color );
|
||||
|
||||
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
|
||||
|
||||
glEnable( GL_LIGHT0 ); // White spot on Z axis ( top )
|
||||
glEnable( GL_LIGHTING );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::TakeScreenshot( wxCommandEvent& event )
|
||||
{
|
||||
static wxFileName fn; // Remember path between saves during this session only.
|
||||
wxString FullFileName;
|
||||
wxString file_ext, mask;
|
||||
bool fmt_is_jpeg = false;
|
||||
|
||||
// First time path is set to the project path.
|
||||
if( !fn.IsOk() )
|
||||
fn = Parent()->Prj().GetProjectFullName();
|
||||
|
||||
if( event.GetId() == ID_MENU_SCREENCOPY_JPEG )
|
||||
fmt_is_jpeg = true;
|
||||
|
||||
if( event.GetId() != ID_TOOL_SCREENCOPY_TOCLIBBOARD )
|
||||
{
|
||||
file_ext = fmt_is_jpeg ? wxT( "jpg" ) : wxT( "png" );
|
||||
mask = wxT( "*." ) + file_ext;
|
||||
fn.SetExt( file_ext );
|
||||
|
||||
FullFileName = EDA_FILE_SELECTOR( _( "3D Image File Name:" ), fn.GetPath(),
|
||||
fn.GetFullName(), file_ext, mask, this,
|
||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT, true );
|
||||
|
||||
if( FullFileName.IsEmpty() )
|
||||
return;
|
||||
|
||||
fn = FullFileName;
|
||||
|
||||
// Be sure the screen area destroyed by the file dialog is redrawn before making
|
||||
// a screen copy.
|
||||
// Without this call, under Linux the screen refresh is made to late.
|
||||
wxYield();
|
||||
}
|
||||
|
||||
struct viewport_params
|
||||
{
|
||||
GLint originx;
|
||||
GLint originy;
|
||||
GLint x;
|
||||
GLint y;
|
||||
} viewport;
|
||||
|
||||
// Be sure we have the latest 3D view (remember 3D view is buffered)
|
||||
Refresh();
|
||||
wxYield();
|
||||
|
||||
// Build image from the 3D buffer
|
||||
wxWindowUpdateLocker noUpdates( this );
|
||||
glGetIntegerv( GL_VIEWPORT, (GLint*) &viewport );
|
||||
|
||||
unsigned char* pixelbuffer = (unsigned char*) malloc( viewport.x * viewport.y * 3 );
|
||||
unsigned char* alphabuffer = (unsigned char*) malloc( viewport.x * viewport.y );
|
||||
wxImage image( viewport.x, viewport.y );
|
||||
|
||||
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
|
||||
glReadBuffer( GL_BACK_LEFT );
|
||||
glReadPixels( viewport.originx, viewport.originy,
|
||||
viewport.x, viewport.y,
|
||||
GL_RGB, GL_UNSIGNED_BYTE, pixelbuffer );
|
||||
glReadPixels( viewport.originx, viewport.originy,
|
||||
viewport.x, viewport.y,
|
||||
GL_ALPHA, GL_UNSIGNED_BYTE, alphabuffer );
|
||||
|
||||
image.SetData( pixelbuffer );
|
||||
image.SetAlpha( alphabuffer );
|
||||
image = image.Mirror( false );
|
||||
wxBitmap bitmap( image );
|
||||
|
||||
if( event.GetId() == ID_TOOL_SCREENCOPY_TOCLIBBOARD )
|
||||
{
|
||||
if( wxTheClipboard->Open() )
|
||||
{
|
||||
wxBitmapDataObject* dobjBmp = new wxBitmapDataObject( bitmap );
|
||||
|
||||
if( !wxTheClipboard->SetData( dobjBmp ) )
|
||||
wxMessageBox( _( "Failed to copy image to clipboard" ) );
|
||||
|
||||
wxTheClipboard->Flush(); /* the data in clipboard will stay
|
||||
* available after the application exits */
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
|
||||
if( !image.SaveFile( FullFileName,
|
||||
fmt_is_jpeg ? wxBITMAP_TYPE_JPEG : wxBITMAP_TYPE_PNG ) )
|
||||
wxMessageBox( _( "Can't save file" ) );
|
||||
|
||||
image.Destroy();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_viewer.h
|
||||
*/
|
||||
|
||||
#ifndef _3D_CANVAS_H_
|
||||
#define _3D_CANVAS_H_
|
||||
|
||||
#include <wx/glcanvas.h>
|
||||
|
||||
#ifdef __WXMAC__
|
||||
# ifdef __DARWIN__
|
||||
# include <OpenGL/glu.h>
|
||||
# else
|
||||
# include <glu.h>
|
||||
# endif
|
||||
#else
|
||||
# include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
#include <3d_struct.h>
|
||||
#include <modelparsers.h>
|
||||
#include <class_module.h>
|
||||
#include <CBBox.h>
|
||||
|
||||
class BOARD_DESIGN_SETTINGS;
|
||||
class EDA_3D_FRAME;
|
||||
class SHAPE_POLY_SET;
|
||||
class REPORTER;
|
||||
|
||||
class VIA;
|
||||
class D_PAD;
|
||||
|
||||
// We are using GL lists to store layers and other items
|
||||
// to draw or not
|
||||
// GL_LIST_ID are the GL lists indexes in m_glLists
|
||||
enum GL_LIST_ID
|
||||
{
|
||||
GL_ID_BEGIN = 0,
|
||||
GL_ID_AXIS = GL_ID_BEGIN, // list id for 3D axis
|
||||
GL_ID_GRID, // list id for 3D grid
|
||||
GL_ID_BOARD, // List id for copper layers
|
||||
GL_ID_TECH_LAYERS, // List id for non copper layers (masks...)
|
||||
GL_ID_AUX_LAYERS, // List id for user layers (draw, eco, comment)
|
||||
GL_ID_3DSHAPES_SOLID_FRONT, // List id for 3D shapes, non transparent entities
|
||||
GL_ID_3DSHAPES_TRANSP_FRONT,// List id for 3D shapes, transparent entities
|
||||
GL_ID_3DSHAPES_SOLID_BACK, // List id for 3D shapes, non transparent entities
|
||||
GL_ID_3DSHAPES_TRANSP_BACK, // List id for 3D shapes, transparent entities
|
||||
GL_ID_SHADOW_FRONT,
|
||||
GL_ID_SHADOW_BACK,
|
||||
GL_ID_SHADOW_BOARD,
|
||||
GL_ID_BODY, // Body only list
|
||||
GL_ID_END
|
||||
};
|
||||
|
||||
class EDA_3D_CANVAS : public wxGLCanvas
|
||||
{
|
||||
private:
|
||||
bool m_init;
|
||||
bool m_reportWarnings; ///< true to report all warnings when building the 3D scene
|
||||
///< false to report errors only
|
||||
GLuint m_glLists[GL_ID_END]; ///< GL lists
|
||||
wxGLContext* m_glRC;
|
||||
wxRealPoint m_draw3dOffset; ///< offset to draw the 3D mesh.
|
||||
double m_ZBottom; ///< position of the back layer
|
||||
double m_ZTop; ///< position of the front layer
|
||||
|
||||
GLuint m_text_pcb; ///< an index to the texture generated for pcb texts
|
||||
GLuint m_text_silk; ///< an index to the texture generated for silk layers
|
||||
|
||||
// Index to the textures generated for shadows
|
||||
bool m_shadow_init;
|
||||
GLuint m_text_fake_shadow_front;
|
||||
GLuint m_text_fake_shadow_back;
|
||||
GLuint m_text_fake_shadow_board;
|
||||
|
||||
CBBOX m_boardAABBox; ///< Axis Align Bounding Box of the board
|
||||
CBBOX m_fastAABBox; ///< Axis Align Bounding Box that contain the other bounding boxes
|
||||
CBBOX m_fastAABBox_Shadow; ///< A bit scalled version of the m_fastAABBox
|
||||
|
||||
S3D_VERTEX m_lightPos;
|
||||
|
||||
/// Stores the list of parsers for each new file name (dont repeat files already loaded)
|
||||
std::vector<S3D_MODEL_PARSER *> m_model_parsers_list;
|
||||
std::vector<wxString> m_model_filename_list;
|
||||
|
||||
void create_and_render_shadow_buffer( GLuint *aDst_gl_texture,
|
||||
GLuint aTexture_size, bool aDraw_body, int aBlurPasses );
|
||||
|
||||
void calcBBox();
|
||||
|
||||
public:
|
||||
EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList = 0 );
|
||||
~EDA_3D_CANVAS();
|
||||
|
||||
EDA_3D_FRAME* Parent() const { return static_cast<EDA_3D_FRAME*>( GetParent() ); }
|
||||
|
||||
BOARD* GetBoard() { return Parent()->GetBoard(); }
|
||||
|
||||
/**
|
||||
* Function ClearLists
|
||||
* Clear the display list.
|
||||
* @param aGlList = the list to clear.
|
||||
* if 0 (default) all lists are cleared
|
||||
*/
|
||||
void ClearLists( int aGlList = 0 );
|
||||
|
||||
// Event functions:
|
||||
void OnPaint( wxPaintEvent& event );
|
||||
void OnEraseBackground( wxEraseEvent& event );
|
||||
void OnChar( wxKeyEvent& event );
|
||||
void OnMouseWheel( wxMouseEvent& event );
|
||||
#ifdef USE_OSX_MAGNIFY_EVENT
|
||||
void OnMagnify( wxMouseEvent& event );
|
||||
#endif
|
||||
void OnMouseMove( wxMouseEvent& event );
|
||||
void OnRightClick( wxMouseEvent& event );
|
||||
void OnPopUpMenu( wxCommandEvent& event );
|
||||
|
||||
/**
|
||||
* Function TakeScreenshot
|
||||
*
|
||||
* creates a screenshot of the current 3D view and save to file as png or jpeg or image
|
||||
* is copied to the clipboard
|
||||
*/
|
||||
void TakeScreenshot( wxCommandEvent& event );
|
||||
void OnEnterWindow( wxMouseEvent& event );
|
||||
|
||||
// Display functions
|
||||
void SetView3D( int keycode );
|
||||
void DisplayStatus();
|
||||
void Redraw();
|
||||
void Render();
|
||||
|
||||
/**
|
||||
* Function CreateDrawGL_List
|
||||
* Prepares the parameters of the OpenGL draw list
|
||||
* creates the OpenGL draw list items (board, grid ...)
|
||||
* @param aErrorMessages = a REPORTER which will filled with error messages,
|
||||
* if any
|
||||
* @param aActivity = a REPORTER to display activity state
|
||||
*/
|
||||
void CreateDrawGL_List( REPORTER* aErrorMessages, REPORTER* aActivity );
|
||||
void InitGL();
|
||||
|
||||
void ReportWarnings( bool aReport ) { m_reportWarnings = aReport; }
|
||||
|
||||
void SetLights();
|
||||
|
||||
void SetOffset(double aPosX, double aPosY)
|
||||
{
|
||||
m_draw3dOffset.x = aPosX;
|
||||
m_draw3dOffset.y = aPosY;
|
||||
}
|
||||
|
||||
/** @return the INFO3D_VISU which contains the current parameters
|
||||
* to draw the 3D view og the board
|
||||
*/
|
||||
INFO3D_VISU& GetPrm3DVisu() const;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* return true if we are in realistic mode render
|
||||
*/
|
||||
bool isRealisticMode() const;
|
||||
|
||||
/**
|
||||
* @return true if aItem should be displayed
|
||||
* @param aItem = an item of DISPLAY3D_FLG enum
|
||||
*/
|
||||
bool isEnabled( DISPLAY3D_FLG aItem ) const;
|
||||
|
||||
/** Helper function
|
||||
* @return true if aLayer should be displayed, false otherwise
|
||||
*/
|
||||
bool is3DLayerEnabled( LAYER_ID aLayer ) const;
|
||||
|
||||
/**
|
||||
* @return the size of the board in pcb units
|
||||
*/
|
||||
wxSize getBoardSize() const;
|
||||
|
||||
/**
|
||||
* @return the position of the board center in pcb units
|
||||
*/
|
||||
wxPoint getBoardCenter() const;
|
||||
|
||||
/**
|
||||
* Helper function setGLTechLayersColor
|
||||
* Initialize the color to draw the non copper layers
|
||||
* in realistic mode and normal mode.
|
||||
*/
|
||||
void setGLTechLayersColor( LAYER_NUM aLayer );
|
||||
|
||||
/**
|
||||
* Helper function setGLCopperColor
|
||||
* Initialize the copper color to draw the board
|
||||
* in realistic mode (a golden yellow color )
|
||||
*/
|
||||
void setGLCopperColor();
|
||||
|
||||
/**
|
||||
* Helper function setGLEpoxyColor
|
||||
* Initialize the color to draw the epoxy body board in realistic mode.
|
||||
*/
|
||||
void setGLEpoxyColor( float aTransparency = 1.0 );
|
||||
|
||||
/**
|
||||
* Helper function setGLSolderMaskColor
|
||||
* Initialize the color to draw the solder mask layers in realistic mode.
|
||||
*/
|
||||
void setGLSolderMaskColor( float aTransparency = 1.0 );
|
||||
|
||||
/**
|
||||
* Function buildBoard3DView
|
||||
* Called by CreateDrawGL_List()
|
||||
* Populates the OpenGL GL_ID_BOARD draw list with board items only on copper layers.
|
||||
* 3D footprint shapes, tech layers and aux layers are not on this list
|
||||
* Fills aErrorMessages with error messages created by some calculation function
|
||||
* display activity state
|
||||
* @param aBoardList =
|
||||
* @param aBodyOnlyList =
|
||||
* @param aErrorMessages = a REPORTER to add error and warning messages
|
||||
* created by the build process (can be NULL)
|
||||
* @param aActivity = a REPORTER to display activity state
|
||||
*/
|
||||
void buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
|
||||
REPORTER* aErrorMessages, REPORTER* aActivity );
|
||||
|
||||
/**
|
||||
* Function buildTechLayers3DView
|
||||
* Called by CreateDrawGL_List()
|
||||
* Populates the OpenGL GL_ID_TECH_LAYERS draw list with items on tech layers
|
||||
* @param aErrorMessages = a REPORTER to add error and warning messages
|
||||
* created by the build process (can be NULL)
|
||||
* @param aActivity = a REPORTER to display activity state
|
||||
*/
|
||||
void buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* aActivity );
|
||||
|
||||
/**
|
||||
* Function buildBoardThroughHolesPolygonList
|
||||
* Helper funtion to build the list of the board through holes polygons
|
||||
* @param allBoardHoles = the SHAPE_POLY_SET to populate
|
||||
* @param aSegCountPerCircle = the number of segments to approximate a circle
|
||||
* @param aOptimizeLargeCircles = true to use more than aSegCountPerCircle
|
||||
* for large circles (a large circle dimatere is > 1mm )
|
||||
*/
|
||||
void buildBoardThroughHolesPolygonList( SHAPE_POLY_SET& allBoardHoles,
|
||||
int aSegCountPerCircle, bool aOptimizeLargeCircles );
|
||||
|
||||
/**
|
||||
* Function buildShadowList
|
||||
* Called by CreateDrawGL_List()
|
||||
*/
|
||||
void buildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList );
|
||||
|
||||
/**
|
||||
* Function buildFootprintShape3DList
|
||||
* Called by CreateDrawGL_List()
|
||||
* Fills the OpenGL GL_ID_3DSHAPES_SOLID and GL_ID_3DSHAPES_TRANSP
|
||||
* draw lists with 3D footprint shapes
|
||||
* @param aOpaqueList is the gl list for non transparent items
|
||||
* @param aTransparentList is the gl list for non transparent items,
|
||||
* @param aErrorMessages = a REPORTER to add error and warning messages
|
||||
* created by the build process (can be NULL)
|
||||
* @param aActivity = a REPORTER to display activity state
|
||||
* which need to be drawn after all other items
|
||||
*/
|
||||
void buildFootprintShape3DList( GLuint aOpaqueList,
|
||||
GLuint aTransparentList,
|
||||
REPORTER* aErrorMessages, REPORTER* aActivity );
|
||||
/**
|
||||
* Function buildBoard3DAuxLayers
|
||||
* Called by CreateDrawGL_List()
|
||||
* Fills the OpenGL GL_ID_AUX_LAYERS draw list
|
||||
* with items on aux layers only
|
||||
* @param aErrorMessages = a REPORTER to add error and warning messages
|
||||
* created by the build process (can be NULL)
|
||||
* @param aActivity = a REPORTER to display activity state
|
||||
* which need to be drawn after all other items
|
||||
*/
|
||||
void buildBoard3DAuxLayers( REPORTER* aErrorMessages, REPORTER* aActivity );
|
||||
|
||||
void draw3DGrid( double aGriSizeMM );
|
||||
void draw3DAxis();
|
||||
|
||||
/**
|
||||
* Helper function BuildPadShapeThickOutlineAsPolygon:
|
||||
* Build a pad outline as non filled polygon, to draw pads on silkscreen layer
|
||||
* with a line thickness = aWidth
|
||||
* Used only to draw pads outlines on silkscreen layers.
|
||||
*/
|
||||
void buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
|
||||
SHAPE_POLY_SET& aCornerBuffer,
|
||||
int aWidth,
|
||||
int aCircleToSegmentsCount,
|
||||
double aCorrectionFactor );
|
||||
|
||||
|
||||
/**
|
||||
* Helper function draw3DViaHole:
|
||||
* Draw the via hole:
|
||||
* Build a vertical hole (a cylinder) between the first and the last via layers
|
||||
*/
|
||||
void draw3DViaHole( const VIA * aVia );
|
||||
|
||||
/**
|
||||
* Helper function draw3DPadHole:
|
||||
* Draw the pad hole:
|
||||
* Build a vertical hole (round or oblong) between the front and back layers
|
||||
*/
|
||||
void draw3DPadHole( const D_PAD * aPad );
|
||||
|
||||
/**
|
||||
* function render3DComponentShape
|
||||
* insert mesh in gl list
|
||||
* @param module
|
||||
* @param aIsRenderingJustNonTransparentObjects = true to load non transparent objects
|
||||
* @param aIsRenderingJustTransparentObjects = true to load non transparent objects
|
||||
* in openGL, transparent objects should be drawn *after* non transparent objects
|
||||
*/
|
||||
void render3DComponentShape( MODULE* module,
|
||||
bool aIsRenderingJustNonTransparentObjects,
|
||||
bool aIsRenderingJustTransparentObjects );
|
||||
|
||||
/**
|
||||
* function read3DComponentShape
|
||||
* read the 3D component shape(s) of the footprint (physical shape).
|
||||
* @param module
|
||||
* @return true if load was succeeded, false otherwise
|
||||
*/
|
||||
bool read3DComponentShape( MODULE* module );
|
||||
|
||||
/**
|
||||
* function generateFakeShadowsTextures
|
||||
* creates shadows of the board an footprints
|
||||
* for aesthetical purpose
|
||||
* @param aErrorMessages = a REPORTER to add error and warning messages
|
||||
* created by the build process (can be NULL)
|
||||
* @param aActivity = a REPORTER to display activity state
|
||||
*/
|
||||
void generateFakeShadowsTextures( REPORTER* aErrorMessages, REPORTER* aActivity );
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
void CheckGLError(const char *aFileName, int aLineNumber);
|
||||
|
||||
#endif /* _3D_CANVAS_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,537 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2023 CERN
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef BOARD_ADAPTER_H
|
||||
#define BOARD_ADAPTER_H
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "../3d_rendering/raytracing/accelerators/container_2d.h"
|
||||
#include "../3d_rendering/raytracing/accelerators/container_3d.h"
|
||||
#include "../3d_rendering/raytracing/shapes3D/bbox_3d.h"
|
||||
#include <gal/3d/camera.h>
|
||||
#include <3d_enums.h>
|
||||
#include "../3d_cache/3d_cache.h"
|
||||
#include "../common_ogl/ogl_attr_list.h"
|
||||
#include "../3d_viewer/eda_3d_viewer_settings.h"
|
||||
|
||||
#include <layer_ids.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_track.h>
|
||||
#include <pcb_base_frame.h>
|
||||
#include <pcb_text.h>
|
||||
#include <pcb_textbox.h>
|
||||
#include <pcb_table.h>
|
||||
#include <pcb_shape.h>
|
||||
#include <pcb_dimension.h>
|
||||
#include <zone.h>
|
||||
#include <footprint.h>
|
||||
#include <reporter.h>
|
||||
#include <dialogs/dialog_color_picker.h>
|
||||
|
||||
class COLOR_SETTINGS;
|
||||
class PCB_TEXTBOX;
|
||||
|
||||
/// A type that stores a container of 2d objects for each layer id
|
||||
typedef std::map<PCB_LAYER_ID, BVH_CONTAINER_2D*> MAP_CONTAINER_2D_BASE;
|
||||
|
||||
/// A type that stores polysets for each layer id
|
||||
typedef std::map<PCB_LAYER_ID, SHAPE_POLY_SET*> MAP_POLY;
|
||||
|
||||
/// This defines the range that all coord will have to be rendered.
|
||||
/// It will use this value to convert to a normalized value between
|
||||
/// -(RANGE_SCALE_3D/2) .. +(RANGE_SCALE_3D/2)
|
||||
#define RANGE_SCALE_3D 8.0f
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to handle information needed to display 3D board.
|
||||
*/
|
||||
class BOARD_ADAPTER
|
||||
{
|
||||
public:
|
||||
BOARD_ADAPTER();
|
||||
|
||||
~BOARD_ADAPTER();
|
||||
|
||||
/**
|
||||
* Update the cache manager pointer.
|
||||
*
|
||||
* @param aCachePointer: the pointer to the 3D cache manager.
|
||||
*/
|
||||
void Set3dCacheManager( S3D_CACHE* aCacheMgr ) noexcept { m_3dModelManager = aCacheMgr; }
|
||||
S3D_CACHE* Get3dCacheManager() const noexcept { return m_3dModelManager; }
|
||||
|
||||
/**
|
||||
* Check if a layer is enabled.
|
||||
*
|
||||
* @param aLayer layer ID to get status.
|
||||
*/
|
||||
bool Is3dLayerEnabled( PCB_LAYER_ID aLayer,
|
||||
const std::bitset<LAYER_3D_END>& aVisibilityFlags ) const;
|
||||
|
||||
/**
|
||||
* Test if footprint should be displayed in relation to attributes and the flags.
|
||||
*/
|
||||
bool IsFootprintShown( FOOTPRINT_ATTR_T aFPAttributes ) const;
|
||||
|
||||
/**
|
||||
* Set current board to be rendered.
|
||||
*
|
||||
* @param aBoard board to process.
|
||||
*/
|
||||
void SetBoard( BOARD* aBoard ) noexcept { m_board = aBoard; }
|
||||
const BOARD* GetBoard() const noexcept { return m_board; }
|
||||
|
||||
void ReloadColorSettings() noexcept;
|
||||
|
||||
/**
|
||||
* Build a color list which is used to store colors layers
|
||||
*/
|
||||
std::map<int, COLOR4D> GetLayerColors() const;
|
||||
|
||||
/**
|
||||
* Build the copper color list used by the board editor, and store it in m_BoardEditorColors
|
||||
*/
|
||||
void GetBoardEditorCopperLayerColors( PCBNEW_SETTINGS* aCfg );
|
||||
|
||||
std::map<int, COLOR4D> GetDefaultColors() const;
|
||||
void SetLayerColors( const std::map<int, COLOR4D>& aColors );
|
||||
|
||||
std::bitset<LAYER_3D_END> GetVisibleLayers() const;
|
||||
std::bitset<LAYER_3D_END> GetDefaultVisibleLayers() const;
|
||||
void SetVisibleLayers( const std::bitset<LAYER_3D_END>& aLayers );
|
||||
|
||||
/**
|
||||
* Function to be called by the render when it need to reload the settings for the board.
|
||||
*
|
||||
* @param aStatusReporter the pointer for the status reporter.
|
||||
* @param aWarningReporter pointer for the warning reporter.
|
||||
*/
|
||||
void InitSettings( REPORTER* aStatusReporter, REPORTER* aWarningReporter );
|
||||
|
||||
/**
|
||||
* Board integer units To 3D units.
|
||||
*
|
||||
* @return the conversion factor to transform a position from the board to 3D units.
|
||||
*/
|
||||
double BiuTo3dUnits() const noexcept { return m_biuTo3Dunits; }
|
||||
|
||||
/**
|
||||
* Get the board outline bounding box.
|
||||
*
|
||||
* @return the board bounding box in 3D units.
|
||||
*/
|
||||
const BBOX_3D& GetBBox() const noexcept { return m_boardBoundingBox; }
|
||||
|
||||
/**
|
||||
* Get the board body thickness, including internal copper layers (in 3D units).
|
||||
*/
|
||||
float GetBoardBodyThickness() const noexcept { return m_boardBodyThickness3DU; }
|
||||
|
||||
/**
|
||||
* Get the non copper layers thickness (in 3D units).
|
||||
*/
|
||||
float GetNonCopperLayerThickness() const noexcept { return m_nonCopperLayerThickness3DU; }
|
||||
|
||||
/**
|
||||
* Get the copper layer thicknesses (in 3D units).
|
||||
*/
|
||||
float GetFrontCopperThickness() const noexcept { return m_frontCopperThickness3DU; }
|
||||
float GetBackCopperThickness() const noexcept { return m_backCopperThickness3DU; }
|
||||
|
||||
/**
|
||||
* Get the hole plating thickness (NB: in BOARD UNITS!).
|
||||
*/
|
||||
int GetHolePlatingThickness() const noexcept;
|
||||
|
||||
/**
|
||||
* Get the board size.
|
||||
*
|
||||
* @return size in BIU units.
|
||||
*/
|
||||
VECTOR2I GetBoardSize() const noexcept { return m_boardSize; }
|
||||
|
||||
/**
|
||||
* Get the board center.
|
||||
*
|
||||
* @return position in BIU units.
|
||||
*/
|
||||
VECTOR2I GetBoardPos() const noexcept { return m_boardPos; }
|
||||
|
||||
/**
|
||||
* The board center position in 3D units.
|
||||
*
|
||||
* @return board center vector position in 3D units.
|
||||
*/
|
||||
const SFVEC3F& GetBoardCenter() const noexcept { return m_boardCenter; }
|
||||
|
||||
/**
|
||||
* Get the position of the footprint in 3d integer units considering if it is flipped or not.
|
||||
*
|
||||
* @param aIsFlipped true for use in footprints on Front (top) layer, false
|
||||
* if footprint is on back (bottom) layer.
|
||||
* @return the Z position of 3D shapes, in 3D integer units.
|
||||
*/
|
||||
float GetFootprintZPos( bool aIsFlipped ) const ;
|
||||
|
||||
/**
|
||||
* Get the current polygon of the epoxy board.
|
||||
*
|
||||
* @return the shape polygon
|
||||
*/
|
||||
const SHAPE_POLY_SET& GetBoardPoly() const noexcept { return m_board_poly; }
|
||||
|
||||
/**
|
||||
* Get the technical color of a layer.
|
||||
*
|
||||
* @param aLayerId the layer to get the color information.
|
||||
* @return the color in SFVEC3F format.
|
||||
*/
|
||||
SFVEC4F GetLayerColor( PCB_LAYER_ID aLayerId ) const;
|
||||
|
||||
/**
|
||||
* Get the technical color of a layer.
|
||||
*
|
||||
* @param aItemId the item id to get the color information.
|
||||
* @return the color in SFVEC3F format.
|
||||
*/
|
||||
SFVEC4F GetItemColor( int aItemId ) const;
|
||||
|
||||
/**
|
||||
* @param[in] aColor is the color mapped.
|
||||
* @return the color in SFVEC3F format
|
||||
*/
|
||||
SFVEC4F GetColor( const COLOR4D& aColor ) const;
|
||||
|
||||
SFVEC2F GetSphericalCoord( int i ) const;
|
||||
|
||||
/**
|
||||
* Get the top z position.
|
||||
*
|
||||
* @param aLayerId layer id.
|
||||
* @return position in 3D units.
|
||||
*/
|
||||
float GetLayerTopZPos( PCB_LAYER_ID aLayerId ) const noexcept
|
||||
{
|
||||
auto it = m_layerZcoordTop.find( aLayerId );
|
||||
|
||||
if( it != m_layerZcoordTop.end() )
|
||||
return it->second;
|
||||
else
|
||||
return -( m_boardBodyThickness3DU / 2.0f );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bottom z position.
|
||||
*
|
||||
* @param aLayerId layer id.
|
||||
* @return position in 3D units.
|
||||
*/
|
||||
float GetLayerBottomZPos( PCB_LAYER_ID aLayerId ) const noexcept
|
||||
{
|
||||
auto it = m_layerZcoordBottom.find( aLayerId );
|
||||
|
||||
if( it != m_layerZcoordBottom.end() )
|
||||
return it->second;
|
||||
else
|
||||
return -( m_boardBodyThickness3DU / 2.0f ) - m_backCopperThickness3DU;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map of containers that have the objects per layer.
|
||||
*
|
||||
* @return the map containers of this board.
|
||||
*/
|
||||
const MAP_CONTAINER_2D_BASE& GetLayerMap() const noexcept { return m_layerMap; }
|
||||
const BVH_CONTAINER_2D* GetPlatedPadsFront() const noexcept { return m_platedPadsFront; }
|
||||
const BVH_CONTAINER_2D* GetPlatedPadsBack() const noexcept { return m_platedPadsBack; }
|
||||
const BVH_CONTAINER_2D* GetOffboardPadsFront() const noexcept { return m_offboardPadsFront; }
|
||||
const BVH_CONTAINER_2D* GetOffboardPadsBack() const noexcept { return m_offboardPadsBack; }
|
||||
|
||||
const MAP_CONTAINER_2D_BASE& GetLayerHoleMap() const noexcept { return m_layerHoleMap; }
|
||||
const BVH_CONTAINER_2D& GetTH_IDs() const noexcept { return m_TH_IDs; }
|
||||
const BVH_CONTAINER_2D& GetTH_ODs() const noexcept { return m_TH_ODs; }
|
||||
|
||||
/**
|
||||
* Get through hole outside diameter 2D polygons.
|
||||
*
|
||||
* The outside diameter 2D polygon is the hole diameter plus the plating thickness.
|
||||
*
|
||||
* @return a container with through hold outside diameter 2D polygons.
|
||||
*/
|
||||
const SHAPE_POLY_SET& GetTH_ODPolys() const noexcept
|
||||
{
|
||||
return m_TH_ODPolys;
|
||||
}
|
||||
|
||||
const BVH_CONTAINER_2D& GetViaAnnuli() const noexcept
|
||||
{
|
||||
return m_viaAnnuli;
|
||||
}
|
||||
|
||||
const SHAPE_POLY_SET& GetViaAnnuliPolys() const noexcept
|
||||
{
|
||||
return m_viaAnnuliPolys;
|
||||
}
|
||||
|
||||
const SHAPE_POLY_SET& GetNPTH_ODPolys() const noexcept
|
||||
{
|
||||
return m_NPTH_ODPolys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a container with through hole via hole outside diameters.
|
||||
*/
|
||||
const BVH_CONTAINER_2D& GetViaTH_ODs() const noexcept
|
||||
{
|
||||
return m_viaTH_ODs;
|
||||
}
|
||||
|
||||
const SHAPE_POLY_SET& GetViaTH_ODPolys() const noexcept
|
||||
{
|
||||
return m_viaTH_ODPolys;
|
||||
}
|
||||
|
||||
unsigned int GetViaCount() const noexcept { return m_viaCount; }
|
||||
unsigned int GetHoleCount() const noexcept { return m_holeCount; }
|
||||
|
||||
/**
|
||||
* @return via hole average diameter dimension in 3D units.
|
||||
*/
|
||||
float GetAverageViaHoleDiameter() const noexcept { return m_averageViaHoleDiameter; }
|
||||
|
||||
/**
|
||||
* @return the average diameter of through holes in 3D units.
|
||||
*/
|
||||
float GetAverageHoleDiameter() const noexcept { return m_averageHoleDiameter; }
|
||||
|
||||
/**
|
||||
* @return average track width in 3D units.
|
||||
*/
|
||||
float GetAverageTrackWidth() const noexcept { return m_averageTrackWidth; }
|
||||
|
||||
/**
|
||||
* @param aDiameter3DU diameter in 3DU.
|
||||
* @return number of sides that should be used in a circle with \a aDiameter3DU.
|
||||
*/
|
||||
unsigned int GetCircleSegmentCount( float aDiameter3DU ) const;
|
||||
|
||||
/**
|
||||
* @param aDiameterBIU diameter in board internal units.
|
||||
* @return number of sides that should be used in circle with \a aDiameterBIU.
|
||||
*/
|
||||
unsigned int GetCircleSegmentCount( int aDiameterBIU ) const;
|
||||
|
||||
/**
|
||||
* Get map of polygon's layers.
|
||||
*
|
||||
* @return the map with polygon's layers.
|
||||
*/
|
||||
const MAP_POLY& GetPolyMap() const noexcept { return m_layers_poly; }
|
||||
|
||||
const SHAPE_POLY_SET* GetFrontPlatedPadAndGraphicPolys()
|
||||
{
|
||||
return m_frontPlatedPadAndGraphicPolys;
|
||||
}
|
||||
|
||||
const SHAPE_POLY_SET* GetBackPlatedPadAndGraphicPolys()
|
||||
{
|
||||
return m_backPlatedPadAndGraphicPolys;
|
||||
}
|
||||
|
||||
const MAP_POLY& GetHoleIdPolysMap() const noexcept { return m_layerHoleIdPolys; }
|
||||
const MAP_POLY& GetHoleOdPolysMap() const noexcept { return m_layerHoleOdPolys; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Create the board outline polygon.
|
||||
*
|
||||
* @return false if the outline could not be created
|
||||
*/
|
||||
bool createBoardPolygon( wxString* aErrorMsg );
|
||||
void createLayers( REPORTER* aStatusReporter );
|
||||
void destroyLayers();
|
||||
|
||||
// Helper functions to create the board
|
||||
void createTrackWithMargin( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayer, int aMargin = 0 );
|
||||
|
||||
void createPadWithMargin( const PAD *aPad, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const;
|
||||
|
||||
void createPadWithHole( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer,
|
||||
int aInflateValue );
|
||||
|
||||
void addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads );
|
||||
|
||||
void addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayerId,
|
||||
const std::bitset<LAYER_3D_END>& aVisibilityFlags );
|
||||
|
||||
void addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aDstContainer,
|
||||
const BOARD_ITEM* aOwner );
|
||||
|
||||
void addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner, PCB_LAYER_ID aLayer );
|
||||
|
||||
void addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aDstContainer,
|
||||
const BOARD_ITEM* aOwner );
|
||||
|
||||
void addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner );
|
||||
|
||||
void addTable( const PCB_TABLE* aTable, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner );
|
||||
|
||||
void addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayerId );
|
||||
|
||||
void createArcSegments( const VECTOR2I& aCentre, const VECTOR2I& aStart,
|
||||
const EDA_ANGLE& aArcAngle, int aCircleToSegmentsCount, int aWidth,
|
||||
CONTAINER_2D_BASE* aContainer, const BOARD_ITEM& aOwner );
|
||||
|
||||
void buildPadOutlineAsSegments( const PAD* aPad, PCB_LAYER_ID aLayer,
|
||||
CONTAINER_2D_BASE* aDstContainer, int aWidth );
|
||||
|
||||
public:
|
||||
static CUSTOM_COLORS_LIST g_SilkColors;
|
||||
static CUSTOM_COLORS_LIST g_MaskColors;
|
||||
static CUSTOM_COLORS_LIST g_PasteColors;
|
||||
static CUSTOM_COLORS_LIST g_FinishColors;
|
||||
static CUSTOM_COLORS_LIST g_BoardColors;
|
||||
|
||||
static KIGFX::COLOR4D g_DefaultBackgroundTop;
|
||||
static KIGFX::COLOR4D g_DefaultBackgroundBot;
|
||||
static KIGFX::COLOR4D g_DefaultSilkscreen;
|
||||
static KIGFX::COLOR4D g_DefaultSolderMask;
|
||||
static KIGFX::COLOR4D g_DefaultSolderPaste;
|
||||
static KIGFX::COLOR4D g_DefaultSurfaceFinish;
|
||||
static KIGFX::COLOR4D g_DefaultBoardBody;
|
||||
static KIGFX::COLOR4D g_DefaultComments;
|
||||
static KIGFX::COLOR4D g_DefaultECOs;
|
||||
|
||||
public:
|
||||
EDA_3D_VIEWER_SETTINGS* m_Cfg;
|
||||
|
||||
bool m_IsBoardView;
|
||||
bool m_MousewheelPanning;
|
||||
bool m_IsPreviewer; ///< true if we're in a 3D preview panel, false
|
||||
///< for the standard 3D viewer
|
||||
|
||||
SFVEC4F m_BgColorBot; ///< background bottom color
|
||||
SFVEC4F m_BgColorTop; ///< background top color
|
||||
SFVEC4F m_BoardBodyColor; ///< in realistic mode: FR4 board color
|
||||
SFVEC4F m_SolderMaskColorBot; ///< in realistic mode: solder mask color ( bot )
|
||||
SFVEC4F m_SolderMaskColorTop; ///< in realistic mode: solder mask color ( top )
|
||||
SFVEC4F m_SolderPasteColor; ///< in realistic mode: solder paste color
|
||||
SFVEC4F m_SilkScreenColorBot; ///< in realistic mode: SilkScreen color ( bot )
|
||||
SFVEC4F m_SilkScreenColorTop; ///< in realistic mode: SilkScreen color ( top )
|
||||
SFVEC4F m_CopperColor; ///< in realistic mode: copper color
|
||||
SFVEC4F m_UserDrawingsColor;
|
||||
SFVEC4F m_UserCommentsColor;
|
||||
SFVEC4F m_ECO1Color;
|
||||
SFVEC4F m_ECO2Color;
|
||||
|
||||
std::map<int, COLOR4D> m_ColorOverrides; ///< allows to override color scheme colors
|
||||
std::map<int, COLOR4D> m_BoardEditorColors; ///< list of colors used by the board editor
|
||||
|
||||
private:
|
||||
BOARD* m_board;
|
||||
S3D_CACHE* m_3dModelManager;
|
||||
COLOR_SETTINGS* m_colors;
|
||||
|
||||
VECTOR2I m_boardPos; ///< Board center position in board internal units.
|
||||
VECTOR2I m_boardSize; ///< Board size in board internal units.
|
||||
SFVEC3F m_boardCenter; ///< 3D center position of the board in 3D units.
|
||||
BBOX_3D m_boardBoundingBox; ///< 3D bounding box of the board in 3D units.
|
||||
|
||||
MAP_POLY m_layers_poly; ///< Amalgamated polygon contours for various types
|
||||
///< of items
|
||||
|
||||
SHAPE_POLY_SET* m_frontPlatedPadAndGraphicPolys;
|
||||
SHAPE_POLY_SET* m_backPlatedPadAndGraphicPolys;
|
||||
SHAPE_POLY_SET* m_frontPlatedCopperPolys;
|
||||
SHAPE_POLY_SET* m_backPlatedCopperPolys;
|
||||
|
||||
MAP_POLY m_layerHoleOdPolys; ///< Hole outer diameters (per layer)
|
||||
MAP_POLY m_layerHoleIdPolys; ///< Hole inner diameters (per layer)
|
||||
|
||||
SHAPE_POLY_SET m_NPTH_ODPolys; ///< NPTH outer diameters
|
||||
SHAPE_POLY_SET m_TH_ODPolys; ///< PTH outer diameters
|
||||
SHAPE_POLY_SET m_viaTH_ODPolys; ///< Via hole outer diameters
|
||||
SHAPE_POLY_SET m_viaAnnuliPolys; ///< Via annular ring outer diameters
|
||||
|
||||
SHAPE_POLY_SET m_board_poly; ///< Board outline polygon.
|
||||
|
||||
MAP_CONTAINER_2D_BASE m_layerMap; ///< 2D elements for each layer.
|
||||
MAP_CONTAINER_2D_BASE m_layerHoleMap; ///< Holes for each layer.
|
||||
|
||||
BVH_CONTAINER_2D* m_platedPadsFront;
|
||||
BVH_CONTAINER_2D* m_platedPadsBack;
|
||||
BVH_CONTAINER_2D* m_offboardPadsFront;
|
||||
BVH_CONTAINER_2D* m_offboardPadsBack;
|
||||
|
||||
BVH_CONTAINER_2D m_TH_ODs; ///< List of PTH outer diameters
|
||||
BVH_CONTAINER_2D m_TH_IDs; ///< List of PTH inner diameters
|
||||
BVH_CONTAINER_2D m_viaAnnuli; ///< List of via annular rings
|
||||
BVH_CONTAINER_2D m_viaTH_ODs; ///< List of via hole outer diameters
|
||||
|
||||
unsigned int m_copperLayersCount;
|
||||
|
||||
double m_biuTo3Dunits; ///< Scale factor to convert board internal units
|
||||
///< to 3D units normalized between -1.0 and 1.0.
|
||||
|
||||
std::map<PCB_LAYER_ID, float> m_layerZcoordTop; ///< Top (End) Z position of each
|
||||
///< layer in 3D units.
|
||||
|
||||
std::map<PCB_LAYER_ID, float> m_layerZcoordBottom; ///< Bottom (Start) Z position of
|
||||
///< each layer in 3D units.
|
||||
|
||||
float m_frontCopperThickness3DU;
|
||||
float m_backCopperThickness3DU;
|
||||
float m_boardBodyThickness3DU;
|
||||
float m_nonCopperLayerThickness3DU;
|
||||
float m_solderPasteLayerThickness3DU;
|
||||
|
||||
unsigned int m_trackCount;
|
||||
float m_averageTrackWidth;
|
||||
unsigned int m_viaCount;
|
||||
float m_averageViaHoleDiameter;
|
||||
unsigned int m_holeCount;
|
||||
float m_averageHoleDiameter;
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable debug output for this class. Output can be turned
|
||||
* on by setting the WXTRACE environment variable to "KI_TRACE_EDA_CINFO3D_VISU". See the
|
||||
* wxWidgets documentation on wxLogTrace for more information.
|
||||
*/
|
||||
static const wxChar* m_logTrace;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // BOARD_ADAPTER_H
|
||||
@@ -1,840 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2023 CERN
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file create_3Dgraphic_brd_items.cpp
|
||||
* @brief This file implements the creation of 2D graphic primitives of pcb items:
|
||||
* pads, tracks, drawsegments, texts....
|
||||
*/
|
||||
|
||||
#include "../3d_rendering/raytracing/shapes2D/ring_2d.h"
|
||||
#include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h"
|
||||
#include "../3d_rendering/raytracing/shapes2D/round_segment_2d.h"
|
||||
#include "../3d_rendering/raytracing/shapes2D/triangle_2d.h"
|
||||
#include <board_adapter.h>
|
||||
#include <board.h>
|
||||
#include <footprint.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_text.h>
|
||||
#include <pcb_textbox.h>
|
||||
#include <pcb_table.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <pcb_painter.h> // for PCB_RENDER_SETTINGS
|
||||
#include <zone.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <trigo.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <geometry/shape_circle.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <geometry/shape_simple.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <wx/log.h>
|
||||
#include <macros.h>
|
||||
#include <callback_gal.h>
|
||||
|
||||
|
||||
#define TO_3DU( x ) ( ( x ) * m_biuTo3Dunits )
|
||||
|
||||
#define TO_SFVEC2F( vec ) SFVEC2F( TO_3DU( vec.x ), TO_3DU( -vec.y ) )
|
||||
|
||||
|
||||
void addFILLED_CIRCLE_2D( CONTAINER_2D_BASE* aContainer, const SFVEC2F& aCenter, float aRadius,
|
||||
const BOARD_ITEM& aBoardItem )
|
||||
{
|
||||
if( aRadius > 0.0f )
|
||||
aContainer->Add( new FILLED_CIRCLE_2D( aCenter, aRadius, aBoardItem ) );
|
||||
}
|
||||
|
||||
|
||||
void addRING_2D( CONTAINER_2D_BASE* aContainer, const SFVEC2F& aCenter, float aInnerRadius,
|
||||
float aOuterRadius, const BOARD_ITEM& aBoardItem )
|
||||
{
|
||||
if( aOuterRadius > aInnerRadius && aInnerRadius > 0.0f )
|
||||
aContainer->Add( new RING_2D( aCenter, aInnerRadius, aOuterRadius, aBoardItem ) );
|
||||
}
|
||||
|
||||
|
||||
void addROUND_SEGMENT_2D( CONTAINER_2D_BASE* aContainer, const SFVEC2F& aStart, const SFVEC2F& aEnd,
|
||||
float aWidth, const BOARD_ITEM& aBoardItem )
|
||||
{
|
||||
if( Is_segment_a_circle( aStart, aEnd ) )
|
||||
{
|
||||
// Cannot add segments that have the same start and end point
|
||||
addFILLED_CIRCLE_2D( aContainer, aStart, aWidth / 2, aBoardItem );
|
||||
return;
|
||||
}
|
||||
|
||||
if( aWidth > 0.0f )
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( aStart, aEnd, aWidth, aBoardItem ) );
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner )
|
||||
{
|
||||
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
|
||||
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
|
||||
float penWidth_3DU = TO_3DU( aText->GetEffectiveTextPenWidth() );
|
||||
KIFONT::FONT* font = aText->GetFont();
|
||||
wxString shownText = aText->GetShownText( true );
|
||||
|
||||
if( !font )
|
||||
font = KIFONT::FONT::GetFont( wxEmptyString, aText->IsBold(), aText->IsItalic() );
|
||||
|
||||
if( aOwner && aOwner->IsKnockout() )
|
||||
{
|
||||
SHAPE_POLY_SET finalPoly;
|
||||
const PCB_TEXT* pcbText = static_cast<const PCB_TEXT*>( aOwner );
|
||||
|
||||
pcbText->TransformTextToPolySet( finalPoly, 0, m_board->GetDesignSettings().m_MaxError,
|
||||
ERROR_INSIDE );
|
||||
|
||||
// Do not call finalPoly.Fracture() here: ConvertPolygonToTriangles() call it
|
||||
// if needed, and Fracture() called twice can create bad results and is useless
|
||||
ConvertPolygonToTriangles( finalPoly, *aContainer, m_biuTo3Dunits, *aOwner );
|
||||
}
|
||||
else
|
||||
{
|
||||
CALLBACK_GAL callback_gal( empty_opts,
|
||||
// Stroke callback
|
||||
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
|
||||
{
|
||||
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( aPt1 ), TO_SFVEC2F( aPt2 ),
|
||||
penWidth_3DU, *aOwner );
|
||||
},
|
||||
// Triangulation callback
|
||||
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
|
||||
{
|
||||
aContainer->Add( new TRIANGLE_2D( TO_SFVEC2F( aPt1 ), TO_SFVEC2F( aPt2 ),
|
||||
TO_SFVEC2F( aPt3 ), *aOwner ) );
|
||||
} );
|
||||
|
||||
attrs.m_Angle = aText->GetDrawRotation();
|
||||
|
||||
if( auto* cache = aText->GetRenderCache( font, shownText ) )
|
||||
{
|
||||
callback_gal.DrawGlyphs( *cache );
|
||||
}
|
||||
else
|
||||
{
|
||||
font->Draw( &callback_gal, shownText, aText->GetDrawPos(), attrs,
|
||||
aOwner->GetFontMetrics() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner )
|
||||
{
|
||||
addText( aDimension, aContainer, aDimension );
|
||||
|
||||
const int linewidth = aDimension->GetLineThickness();
|
||||
|
||||
for( const std::shared_ptr<SHAPE>& shape : aDimension->GetShapes() )
|
||||
{
|
||||
switch( shape->Type() )
|
||||
{
|
||||
case SH_SEGMENT:
|
||||
{
|
||||
const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
|
||||
|
||||
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( seg.A ), TO_SFVEC2F( seg.B ),
|
||||
TO_3DU( linewidth ), *aOwner );
|
||||
break;
|
||||
}
|
||||
|
||||
case SH_CIRCLE:
|
||||
{
|
||||
int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
|
||||
float innerR3DU = TO_3DU( radius ) - TO_3DU( aDimension->GetLineThickness() ) / 2.0f;
|
||||
float outerR3DU = TO_3DU( radius ) + TO_3DU( aDimension->GetLineThickness() ) / 2.0f;
|
||||
|
||||
addRING_2D( aContainer, TO_SFVEC2F( shape->Centre() ), innerR3DU, outerR3DU, *aOwner );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer,
|
||||
PCB_LAYER_ID aLayerId,
|
||||
const std::bitset<LAYER_3D_END>& aVisibilityFlags )
|
||||
{
|
||||
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
|
||||
|
||||
for( PCB_FIELD* field : aFootprint->GetFields() )
|
||||
{
|
||||
if( field->GetLayer() == aLayerId && field->IsVisible() )
|
||||
{
|
||||
if( !aVisibilityFlags.test( LAYER_FP_TEXT ) )
|
||||
continue;
|
||||
else if( field->IsReference() && !aVisibilityFlags.test( LAYER_FP_REFERENCES ) )
|
||||
continue;
|
||||
else if( field->IsValue() && !aVisibilityFlags.test( LAYER_FP_VALUES ) )
|
||||
continue;
|
||||
|
||||
addText( field, aContainer, field );
|
||||
}
|
||||
}
|
||||
|
||||
for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
|
||||
{
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_TEXT_T:
|
||||
{
|
||||
PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
|
||||
|
||||
if( text->GetLayer() == aLayerId && text->IsVisible() )
|
||||
{
|
||||
if( !aVisibilityFlags.test( LAYER_FP_TEXT ) )
|
||||
continue;
|
||||
else if( text->GetText() == wxT( "${REFERENCE}" )
|
||||
&& !aVisibilityFlags.test( LAYER_FP_REFERENCES ) )
|
||||
continue;
|
||||
else if( text->GetText() == wxT( "${VALUE}" )
|
||||
&& !aVisibilityFlags.test( LAYER_FP_VALUES ) )
|
||||
continue;
|
||||
|
||||
addText( text, aContainer, text );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_TEXTBOX_T:
|
||||
{
|
||||
PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
|
||||
|
||||
if( textbox->GetLayer() == aLayerId )
|
||||
addShape( textbox, aContainer, aFootprint );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_TABLE_T:
|
||||
{
|
||||
PCB_TABLE* table = static_cast<PCB_TABLE*>( item );
|
||||
|
||||
if( table->GetLayer() == aLayerId )
|
||||
addTable( table, aContainer, aFootprint );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_DIM_ALIGNED_T:
|
||||
case PCB_DIM_CENTER_T:
|
||||
case PCB_DIM_ORTHOGONAL_T:
|
||||
case PCB_DIM_RADIAL_T:
|
||||
case PCB_DIM_LEADER_T:
|
||||
{
|
||||
PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( item );
|
||||
|
||||
if( dimension->GetLayer() == aLayerId )
|
||||
addShape( dimension, aContainer, aFootprint );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_SHAPE_T:
|
||||
{
|
||||
PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
|
||||
|
||||
if( shape->IsOnLayer( aLayerId ) )
|
||||
addShape( shape, aContainer, aFootprint, aLayerId );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::createTrackWithMargin( const PCB_TRACK* aTrack,
|
||||
CONTAINER_2D_BASE* aDstContainer, PCB_LAYER_ID aLayer,
|
||||
int aMargin )
|
||||
{
|
||||
SFVEC2F start3DU = TO_SFVEC2F( aTrack->GetStart() );
|
||||
SFVEC2F end3DU = TO_SFVEC2F( aTrack->GetEnd() );
|
||||
|
||||
switch( aTrack->Type() )
|
||||
{
|
||||
case PCB_VIA_T:
|
||||
{
|
||||
const PCB_VIA* via = static_cast<const PCB_VIA*>( aTrack );
|
||||
float width3DU = TO_3DU( via->GetWidth( aLayer ) + aMargin * 2 );
|
||||
|
||||
addFILLED_CIRCLE_2D( aDstContainer, start3DU, width3DU / 2.0, *aTrack );
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_ARC_T:
|
||||
{
|
||||
const PCB_ARC* arc = static_cast<const PCB_ARC*>( aTrack );
|
||||
|
||||
if( arc->IsDegenerated() )
|
||||
{
|
||||
// Draw this very small arc like a track segment (a PCB_TRACE_T)
|
||||
PCB_TRACK track( arc->GetParent() );
|
||||
track.SetStart( arc->GetStart() );
|
||||
track.SetEnd( arc->GetEnd() );
|
||||
track.SetWidth( arc->GetWidth() );
|
||||
track.SetLayer( arc->GetLayer() );
|
||||
|
||||
createTrackWithMargin( &track, aDstContainer, aLayer, aMargin );
|
||||
return;
|
||||
}
|
||||
|
||||
VECTOR2I center( arc->GetCenter() );
|
||||
EDA_ANGLE arc_angle = arc->GetAngle();
|
||||
double radius = arc->GetRadius();
|
||||
int arcsegcount = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF, arc_angle );
|
||||
int circlesegcount;
|
||||
|
||||
// Avoid arcs that cannot be drawn
|
||||
if( radius < std::numeric_limits<double>::min() || arc_angle.IsZero() )
|
||||
break;
|
||||
|
||||
// We need a circle to segment count. However, the arc angle can be small, and the
|
||||
// radius very big. so we calculate a reasonable value for circlesegcount.
|
||||
if( arcsegcount <= 1 ) // The arc will be approximated by a segment
|
||||
{
|
||||
circlesegcount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
circlesegcount = KiROUND( arcsegcount * 360.0 / std::abs( arc_angle.AsDegrees() ) );
|
||||
circlesegcount = std::clamp( circlesegcount, 1, 128 );
|
||||
}
|
||||
|
||||
createArcSegments( center, arc->GetStart(), arc_angle, circlesegcount,
|
||||
arc->GetWidth() + aMargin * 2,
|
||||
aDstContainer, *arc );
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_TRACE_T: // Track is a usual straight segment
|
||||
{
|
||||
float width3DU = TO_3DU( aTrack->GetWidth() + aMargin * 2 );
|
||||
addROUND_SEGMENT_2D( aDstContainer, start3DU, end3DU, width3DU, *aTrack );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aContainer,
|
||||
PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const
|
||||
{
|
||||
SHAPE_POLY_SET poly;
|
||||
int maxError = GetBoard()->GetDesignSettings().m_MaxError;
|
||||
VECTOR2I clearance = aMargin;
|
||||
|
||||
// Our shape-based builder can't handle negative or differing x:y clearance values (the
|
||||
// former are common for solder paste while the later get generated when a relative paste
|
||||
// margin is used with an oblong pad). So we apply this huge hack and fake a larger pad to
|
||||
// run the general-purpose polygon builder on.
|
||||
// Of course being a hack it falls down when dealing with custom shape pads (where the size
|
||||
// is only the size of the anchor), so for those we punt and just use aMargin.x.
|
||||
|
||||
if( ( clearance.x < 0 || clearance.x != clearance.y )
|
||||
&& aPad->GetShape( aLayer ) != PAD_SHAPE::CUSTOM )
|
||||
{
|
||||
VECTOR2I dummySize = VECTOR2I( aPad->GetSize( aLayer ) ) + clearance + clearance;
|
||||
|
||||
if( dummySize.x <= 0 || dummySize.y <= 0 )
|
||||
return;
|
||||
|
||||
PAD dummy( *aPad );
|
||||
dummy.SetSize( aLayer, VECTOR2I( dummySize.x, dummySize.y ) );
|
||||
dummy.TransformShapeToPolygon( poly, aLayer, 0, maxError, ERROR_INSIDE );
|
||||
clearance = { 0, 0 };
|
||||
|
||||
// Remove group membership from dummy item before deleting
|
||||
dummy.SetParentGroup( nullptr );
|
||||
}
|
||||
else if( aPad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
|
||||
{
|
||||
// A custom pad can have many complex subshape items. To avoid issues, use its
|
||||
// final polygon shape, not its basic shape set. One cannot apply the clearance
|
||||
// to each subshape: it does no work
|
||||
aPad->TransformShapeToPolygon( poly, aLayer, 0, maxError );
|
||||
}
|
||||
else
|
||||
{
|
||||
auto padShapes =
|
||||
std::static_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape( aLayer ) );
|
||||
|
||||
for( const SHAPE* shape : padShapes->Shapes() )
|
||||
{
|
||||
switch( shape->Type() )
|
||||
{
|
||||
case SH_SEGMENT:
|
||||
{
|
||||
const SHAPE_SEGMENT* seg = static_cast<const SHAPE_SEGMENT*>( shape );
|
||||
|
||||
addROUND_SEGMENT_2D( aContainer,
|
||||
TO_SFVEC2F( seg->GetSeg().A ),
|
||||
TO_SFVEC2F( seg->GetSeg().B ),
|
||||
TO_3DU( seg->GetWidth() + clearance.x * 2 ),
|
||||
*aPad );
|
||||
break;
|
||||
}
|
||||
|
||||
case SH_CIRCLE:
|
||||
{
|
||||
const SHAPE_CIRCLE* circle = static_cast<const SHAPE_CIRCLE*>( shape );
|
||||
|
||||
addFILLED_CIRCLE_2D( aContainer,
|
||||
TO_SFVEC2F( circle->GetCenter() ),
|
||||
TO_3DU( circle->GetRadius() + clearance.x ),
|
||||
*aPad );
|
||||
break;
|
||||
}
|
||||
|
||||
case SH_RECT:
|
||||
{
|
||||
const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>( shape );
|
||||
|
||||
poly.NewOutline();
|
||||
poly.Append( rect->GetPosition() );
|
||||
poly.Append( rect->GetPosition().x + rect->GetSize().x, rect->GetPosition().y );
|
||||
poly.Append( rect->GetPosition() + rect->GetSize() );
|
||||
poly.Append( rect->GetPosition().x, rect->GetPosition().y + rect->GetSize().y );
|
||||
break;
|
||||
}
|
||||
|
||||
case SH_SIMPLE:
|
||||
poly.AddOutline( static_cast<const SHAPE_SIMPLE*>( shape )->Vertices() );
|
||||
break;
|
||||
|
||||
case SH_POLY_SET:
|
||||
poly.Append( *static_cast<const SHAPE_POLY_SET*>( shape ) );
|
||||
break;
|
||||
|
||||
case SH_ARC:
|
||||
{
|
||||
const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( shape );
|
||||
SHAPE_LINE_CHAIN l = arc->ConvertToPolyline( maxError );
|
||||
|
||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
||||
{
|
||||
SHAPE_SEGMENT seg( l.Segment( i ).A, l.Segment( i ).B, arc->GetWidth() );
|
||||
|
||||
addROUND_SEGMENT_2D( aContainer,
|
||||
TO_SFVEC2F( seg.GetSeg().A ),
|
||||
TO_SFVEC2F( seg.GetSeg().B ),
|
||||
TO_3DU( arc->GetWidth() + clearance.x * 2 ),
|
||||
*aPad );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( SHAPE_TYPE_asString( shape->Type() ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !poly.IsEmpty() )
|
||||
{
|
||||
if( clearance.x )
|
||||
poly.Inflate( clearance.x, CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
|
||||
|
||||
// Add the PAD polygon
|
||||
ConvertPolygonToTriangles( poly, *aContainer, m_biuTo3Dunits, *aPad );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::createPadWithHole( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer,
|
||||
int aInflateValue )
|
||||
{
|
||||
if( !aPad->HasHole() )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::createPadWithHole - found an invalid pad" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
|
||||
|
||||
addROUND_SEGMENT_2D( aDstContainer,
|
||||
TO_SFVEC2F( slot->GetSeg().A ),
|
||||
TO_SFVEC2F( slot->GetSeg().B ),
|
||||
TO_3DU( slot->GetWidth() + aInflateValue * 2 ),
|
||||
*aPad );
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer,
|
||||
PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads )
|
||||
{
|
||||
for( PAD* pad : aFootprint->Pads() )
|
||||
{
|
||||
if( !pad->IsOnLayer( aLayerId ) )
|
||||
continue;
|
||||
|
||||
if( IsCopperLayer( aLayerId ) )
|
||||
{
|
||||
// Skip pad annulus when there isn't one (note: this is more discerning than
|
||||
// pad->IsOnLayer(), which doesn't check for NPTH pads with holes that consume
|
||||
// the entire pad).
|
||||
if( !pad->IsOnCopperLayer() )
|
||||
continue;
|
||||
|
||||
// Skip pad annulus when not connected on this layer (if removing is enabled)
|
||||
if( !pad->FlashLayer( aLayerId ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
VECTOR2I margin( 0, 0 );
|
||||
|
||||
switch( aLayerId )
|
||||
{
|
||||
case F_Cu:
|
||||
if( aSkipPlatedPads && pad->FlashLayer( F_Mask ) )
|
||||
continue;
|
||||
|
||||
if( aSkipNonPlatedPads && !pad->FlashLayer( F_Mask ) )
|
||||
continue;
|
||||
|
||||
break;
|
||||
|
||||
case B_Cu:
|
||||
if( aSkipPlatedPads && pad->FlashLayer( B_Mask ) )
|
||||
continue;
|
||||
|
||||
if( aSkipNonPlatedPads && !pad->FlashLayer( B_Mask ) )
|
||||
continue;
|
||||
|
||||
break;
|
||||
|
||||
case F_Mask:
|
||||
case B_Mask:
|
||||
margin.x += pad->GetSolderMaskExpansion( aLayerId );
|
||||
margin.y += pad->GetSolderMaskExpansion( aLayerId );
|
||||
break;
|
||||
|
||||
case F_Paste:
|
||||
case B_Paste:
|
||||
margin += pad->GetSolderPasteMargin( aLayerId );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
createPadWithMargin( pad, aContainer, aLayerId, margin );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// based on TransformArcToPolygon function from
|
||||
// common/convert_basic_shapes_to_polygon.cpp
|
||||
void BOARD_ADAPTER::createArcSegments( const VECTOR2I& aCentre, const VECTOR2I& aStart,
|
||||
const EDA_ANGLE& aArcAngle, int aCircleToSegmentsCount,
|
||||
int aWidth, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM& aOwner )
|
||||
{
|
||||
// Don't attempt to render degenerate shapes
|
||||
if( aWidth == 0 )
|
||||
return;
|
||||
|
||||
VECTOR2I arc_start, arc_end;
|
||||
EDA_ANGLE arcAngle( aArcAngle );
|
||||
EDA_ANGLE delta = ANGLE_360 / aCircleToSegmentsCount; // rotate angle
|
||||
|
||||
arc_end = arc_start = aStart;
|
||||
|
||||
if( arcAngle != ANGLE_360 )
|
||||
RotatePoint( arc_end, aCentre, -arcAngle );
|
||||
|
||||
if( arcAngle < ANGLE_0 )
|
||||
{
|
||||
std::swap( arc_start, arc_end );
|
||||
arcAngle = -arcAngle;
|
||||
}
|
||||
|
||||
// Compute the ends of segments and creates poly
|
||||
VECTOR2I curr_end = arc_start;
|
||||
VECTOR2I curr_start = arc_start;
|
||||
|
||||
for( EDA_ANGLE ii = delta; ii < arcAngle; ii += delta )
|
||||
{
|
||||
curr_end = arc_start;
|
||||
RotatePoint( curr_end, aCentre, -ii );
|
||||
|
||||
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( curr_start ), TO_SFVEC2F( curr_end ),
|
||||
TO_3DU( aWidth ), aOwner );
|
||||
|
||||
curr_start = curr_end;
|
||||
}
|
||||
|
||||
if( curr_end != arc_end )
|
||||
{
|
||||
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( curr_end ), TO_SFVEC2F( arc_end ),
|
||||
TO_3DU( aWidth ), aOwner );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
// The full width of the lines to create
|
||||
int linewidth = aShape->GetWidth();
|
||||
int margin = 0;
|
||||
|
||||
if( IsSolderMaskLayer( aLayer )
|
||||
&& aShape->HasSolderMask()
|
||||
&& IsExternalCopperLayer( aShape->GetLayer() ) )
|
||||
{
|
||||
margin = aShape->GetSolderMaskExpansion();
|
||||
linewidth += margin * 2;
|
||||
}
|
||||
|
||||
float linewidth3DU = TO_3DU( linewidth );
|
||||
|
||||
LINE_STYLE lineStyle = aShape->GetStroke().GetLineStyle();
|
||||
|
||||
if( lineStyle <= LINE_STYLE::FIRST_TYPE )
|
||||
{
|
||||
switch( aShape->GetShape() )
|
||||
{
|
||||
case SHAPE_T::CIRCLE:
|
||||
{
|
||||
SFVEC2F center3DU = TO_SFVEC2F( aShape->GetCenter() );
|
||||
float innerR3DU = TO_3DU( aShape->GetRadius() ) - linewidth3DU / 2.0;
|
||||
float outerR3DU = TO_3DU( aShape->GetRadius() ) + linewidth3DU / 2.0;
|
||||
|
||||
if( aShape->IsFilled() || innerR3DU <= 0.0 )
|
||||
addFILLED_CIRCLE_2D( aContainer, center3DU, outerR3DU, *aOwner );
|
||||
else
|
||||
addRING_2D( aContainer, center3DU, innerR3DU, outerR3DU, *aOwner );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::RECTANGLE:
|
||||
if( aShape->IsFilled() )
|
||||
{
|
||||
SHAPE_POLY_SET polyList;
|
||||
|
||||
aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
|
||||
ERROR_INSIDE );
|
||||
|
||||
polyList.Simplify();
|
||||
|
||||
if( margin != 0 )
|
||||
{
|
||||
polyList.Inflate( margin, CORNER_STRATEGY::ROUND_ALL_CORNERS,
|
||||
GetBoard()->GetDesignSettings().m_MaxError );
|
||||
}
|
||||
|
||||
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
|
||||
|
||||
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[0] ), TO_SFVEC2F( pts[1] ),
|
||||
linewidth3DU, *aOwner );
|
||||
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[1] ), TO_SFVEC2F( pts[2] ),
|
||||
linewidth3DU, *aOwner );
|
||||
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[2] ), TO_SFVEC2F( pts[3] ),
|
||||
linewidth3DU, *aOwner );
|
||||
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[3] ), TO_SFVEC2F( pts[0] ),
|
||||
linewidth3DU, *aOwner );
|
||||
}
|
||||
break;
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
{
|
||||
unsigned int segCount = GetCircleSegmentCount( aShape->GetBoundingBox().GetSizeMax() );
|
||||
|
||||
createArcSegments( aShape->GetCenter(), aShape->GetStart(), aShape->GetArcAngle(),
|
||||
segCount, linewidth, aContainer, *aOwner );
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::SEGMENT:
|
||||
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( aShape->GetStart() ),
|
||||
TO_SFVEC2F( aShape->GetEnd() ), linewidth3DU, *aOwner );
|
||||
break;
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
case SHAPE_T::POLY:
|
||||
{
|
||||
SHAPE_POLY_SET polyList;
|
||||
|
||||
aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
|
||||
ERROR_INSIDE );
|
||||
|
||||
// Some polygons can be a bit complex (especially when coming from a
|
||||
// picture of a text converted to a polygon
|
||||
// So call Simplify before calling ConvertPolygonToTriangles, just in case.
|
||||
polyList.Simplify();
|
||||
|
||||
if( polyList.IsEmpty() ) // Just for caution
|
||||
break;
|
||||
|
||||
if( margin != 0 )
|
||||
{
|
||||
CORNER_STRATEGY cornerStr = margin >= 0 ? CORNER_STRATEGY::ROUND_ALL_CORNERS
|
||||
: CORNER_STRATEGY::ALLOW_ACUTE_CORNERS;
|
||||
|
||||
polyList.Inflate( margin, cornerStr, GetBoard()->GetDesignSettings().m_MaxError );
|
||||
}
|
||||
|
||||
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( wxT( "BOARD_ADAPTER::addShape no implementation for " )
|
||||
+ aShape->SHAPE_T_asString() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
|
||||
SFVEC2F a3DU;
|
||||
SFVEC2F b3DU;
|
||||
|
||||
const PCB_PLOT_PARAMS& plotParams = aShape->GetBoard()->GetPlotOptions();
|
||||
KIGFX::PCB_RENDER_SETTINGS renderSettings;
|
||||
|
||||
renderSettings.SetDashLengthRatio( plotParams.GetDashedLineDashRatio() );
|
||||
renderSettings.SetGapLengthRatio( plotParams.GetDashedLineGapRatio() );
|
||||
|
||||
for( SHAPE* shape : shapes )
|
||||
{
|
||||
STROKE_PARAMS::Stroke( shape, lineStyle, aShape->GetWidth(), &renderSettings,
|
||||
[&]( const VECTOR2I& a, const VECTOR2I& b )
|
||||
{
|
||||
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( a ), TO_SFVEC2F( b ),
|
||||
linewidth3DU, *aOwner );
|
||||
} );
|
||||
}
|
||||
|
||||
for( SHAPE* shape : shapes )
|
||||
delete shape;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner )
|
||||
{
|
||||
addText( aTextBox, aContainer, aOwner );
|
||||
|
||||
if( !aTextBox->IsBorderEnabled() )
|
||||
return;
|
||||
|
||||
// We cannot use PCB_TEXTBOX::TransformShapeToPolygon because it convert the textbox
|
||||
// as filled polygon even if there's no background colour.
|
||||
// So for polygon, we use PCB_SHAPE::TransformShapeToPolygon
|
||||
|
||||
if( aTextBox->GetShape() == SHAPE_T::RECTANGLE )
|
||||
{
|
||||
addShape( static_cast<const PCB_SHAPE*>( aTextBox ), aContainer, aOwner, UNDEFINED_LAYER );
|
||||
}
|
||||
else
|
||||
{
|
||||
SHAPE_POLY_SET polyList;
|
||||
|
||||
aTextBox->PCB_SHAPE::TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
|
||||
ERROR_INSIDE );
|
||||
|
||||
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addTable( const PCB_TABLE* aTable, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner )
|
||||
{
|
||||
// JEY TODO: tables
|
||||
// add borders
|
||||
|
||||
for( PCB_TABLECELL* cell : aTable->GetCells() )
|
||||
addText( cell, aContainer, aOwner );
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aContainer,
|
||||
PCB_LAYER_ID aLayerId )
|
||||
{
|
||||
// This convert the poly in outline and holes
|
||||
ConvertPolygonToTriangles( *aZone->GetFilledPolysList( aLayerId ), *aContainer, m_biuTo3Dunits,
|
||||
*aZone );
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::buildPadOutlineAsSegments( const PAD* aPad, PCB_LAYER_ID aLayer,
|
||||
CONTAINER_2D_BASE* aContainer, int aWidth )
|
||||
{
|
||||
if( aPad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE ) // Draw a ring
|
||||
{
|
||||
const SFVEC2F center3DU = TO_SFVEC2F( aPad->ShapePos( aLayer ) );
|
||||
const int radius = aPad->GetSize( aLayer ).x / 2;
|
||||
const float inner_radius3DU = TO_3DU( radius - aWidth / 2.0 );
|
||||
const float outer_radius3DU = TO_3DU( radius + aWidth / 2.0 );
|
||||
|
||||
addRING_2D( aContainer, center3DU, inner_radius3DU, outer_radius3DU, *aPad );
|
||||
}
|
||||
else
|
||||
{
|
||||
// For other shapes, add outlines as thick segments in polygon buffer
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( aLayer,
|
||||
ERROR_INSIDE );
|
||||
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
|
||||
|
||||
for( int j = 0; j < path.PointCount(); j++ )
|
||||
{
|
||||
SFVEC2F start3DU = TO_SFVEC2F( path.CPoint( j ) );
|
||||
SFVEC2F end3DU = TO_SFVEC2F( path.CPoint( j + 1 ) );
|
||||
|
||||
addROUND_SEGMENT_2D( aContainer, start3DU, end3DU, TO_3DU( aWidth ), *aPad );
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,348 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef EDA_3D_CANVAS_H
|
||||
#define EDA_3D_CANVAS_H
|
||||
|
||||
#include <atomic>
|
||||
#include "board_adapter.h"
|
||||
#include "3d_rendering/raytracing/accelerators/accelerator_3d.h"
|
||||
#include "3d_rendering/render_3d_base.h"
|
||||
#include "3d_cache/3d_cache.h"
|
||||
#include <gal/hidpi_gl_3D_canvas.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/timer.h>
|
||||
|
||||
|
||||
class WX_INFOBAR;
|
||||
class wxStatusBar;
|
||||
class BOARD;
|
||||
class RENDER_3D_RAYTRACE_GL;
|
||||
class RENDER_3D_OPENGL;
|
||||
|
||||
|
||||
#define EDA_3D_CANVAS_ID wxID_HIGHEST + 1321
|
||||
|
||||
/**
|
||||
* Implement a canvas based on a wxGLCanvas
|
||||
*/
|
||||
class EDA_3D_CANVAS : public HIDPI_GL_3D_CANVAS
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a new 3D Canvas with an attribute list.
|
||||
*
|
||||
* @param aParent the parent creator of this canvas.
|
||||
* @param aGLAttribs openGL attributes created by #OGL_ATT_LIST::GetAttributesList.
|
||||
* @param aBoard The board.
|
||||
* @param aSettings the settings options to be used by this canvas.
|
||||
*/
|
||||
EDA_3D_CANVAS( wxWindow* aParent, const wxGLAttributes& aGLAttribs, BOARD_ADAPTER& aSettings,
|
||||
CAMERA& aCamera, S3D_CACHE* a3DCachePointer );
|
||||
|
||||
~EDA_3D_CANVAS();
|
||||
|
||||
/**
|
||||
* Set a dispatcher that processes events and forwards them to tools.
|
||||
*
|
||||
* #DRAW_PANEL_GAL does not take over the ownership. Passing NULL disconnects all event
|
||||
* handlers from the DRAW_PANEL_GAL and parent frame.
|
||||
*
|
||||
* @param aEventDispatcher is the object that will be used for dispatching events.
|
||||
*/
|
||||
void SetEventDispatcher( TOOL_DISPATCHER* aEventDispatcher );
|
||||
|
||||
void SetStatusBar( wxStatusBar* aStatusBar )
|
||||
{
|
||||
m_parentStatusBar = aStatusBar;
|
||||
}
|
||||
|
||||
void SetInfoBar( WX_INFOBAR* aInfoBar )
|
||||
{
|
||||
m_parentInfoBar = aInfoBar;
|
||||
}
|
||||
|
||||
void ReloadRequest( BOARD* aBoard = nullptr, S3D_CACHE* aCachePointer = nullptr );
|
||||
|
||||
/**
|
||||
* Query if there is a pending reload request.
|
||||
*
|
||||
* @return true if it wants to reload, false if there is no reload pending.
|
||||
*/
|
||||
bool IsReloadRequestPending() const
|
||||
{
|
||||
if( m_3d_render )
|
||||
return m_3d_render->IsReloadRequestPending();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current render ( a RENDER_3D_RAYTRACE_GL* or a RENDER_3D_OPENGL* render )
|
||||
*/
|
||||
RENDER_3D_BASE* GetCurrentRender() const { return m_3d_render; }
|
||||
|
||||
/**
|
||||
* Request to render the current view in Raytracing mode.
|
||||
*/
|
||||
void RenderRaytracingRequest();
|
||||
|
||||
/**
|
||||
* Request a screenshot and output it to the \a aDstImage.
|
||||
*
|
||||
* @param aDstImage - Screenshot destination image.
|
||||
*/
|
||||
void GetScreenshot( wxImage& aDstImage );
|
||||
|
||||
/**
|
||||
* Select a specific 3D view or operation.
|
||||
*
|
||||
* @param aRequestedView the view to move to.
|
||||
* @return true if the view request was handled, false if no command found for this view.
|
||||
*/
|
||||
bool SetView3D( VIEW3D_TYPE aRequestedView );
|
||||
|
||||
/**
|
||||
* Enable or disable camera animation when switching to a pre-defined view.
|
||||
*/
|
||||
void SetAnimationEnabled( bool aEnable ) { m_animation_enabled = aEnable; }
|
||||
bool GetAnimationEnabled() const { return m_animation_enabled; }
|
||||
|
||||
/**
|
||||
* Set the camera animation moving speed multiplier option.
|
||||
*
|
||||
* @param aMultiplier one of the possible integer options: [1,2,3,4,5].
|
||||
*/
|
||||
void SetMovingSpeedMultiplier( int aMultiplier ) { m_moving_speed_multiplier = aMultiplier; }
|
||||
int GetMovingSpeedMultiplier() const { return m_moving_speed_multiplier; }
|
||||
|
||||
int GetProjectionMode() const { return (int) m_camera.GetProjection(); };
|
||||
void SetProjectionMode( int aMode ) { m_camera.SetProjection( (PROJECTION_TYPE) aMode ); }
|
||||
|
||||
/**
|
||||
* Notify that the render engine was changed.
|
||||
*/
|
||||
void RenderEngineChanged();
|
||||
|
||||
/**
|
||||
* Update the status bar with the position information.
|
||||
*/
|
||||
void DisplayStatus();
|
||||
|
||||
/**
|
||||
* Schedule a refresh update of the canvas.
|
||||
*
|
||||
* @param aRedrawImmediately true will request a redraw, false will schedule a redraw
|
||||
* after a short timeout.
|
||||
*/
|
||||
void Request_refresh( bool aRedrawImmediately = true );
|
||||
|
||||
/**
|
||||
* Used to forward events to the canvas from popups, etc.
|
||||
*/
|
||||
void OnEvent( wxEvent& aEvent );
|
||||
|
||||
/**
|
||||
* Get information used to display 3D board.
|
||||
*/
|
||||
const BOARD_ADAPTER& GetBoardAdapter() const { return m_boardAdapter; }
|
||||
|
||||
/**
|
||||
* Get a value indicating whether to render the pivot.
|
||||
*/
|
||||
bool GetRenderPivot() { return m_render_pivot; }
|
||||
|
||||
/**
|
||||
* Set aValue indicating whether to render the pivot.
|
||||
*
|
||||
* @param aValue true will cause the pivot to be rendered on the next redraw.
|
||||
*/
|
||||
void SetRenderPivot( bool aValue ) { m_render_pivot = aValue; }
|
||||
|
||||
/**
|
||||
* Get a value indicating whether to render the 3dmouse pivot.
|
||||
*/
|
||||
bool GetRender3dmousePivot()
|
||||
{
|
||||
return m_render3dmousePivot;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set aValue indicating whether to render the 3dmouse pivot.
|
||||
*
|
||||
* @param aValue true will cause the pivot to be rendered on the next redraw.
|
||||
*/
|
||||
void SetRender3dmousePivot( bool aValue )
|
||||
{
|
||||
m_render3dmousePivot = aValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the position of the the 3dmouse pivot.
|
||||
*
|
||||
* @param aPos is the position of the 3dmouse rotation pivot
|
||||
*/
|
||||
void Set3dmousePivotPos( const SFVEC3F& aPos )
|
||||
{
|
||||
m_3dmousePivotPos = aPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual function to repaint the canvas.
|
||||
*
|
||||
* It is usually called by OnPaint() but because it does not use a wxPaintDC it can be
|
||||
* called outside a wxPaintEvent
|
||||
*/
|
||||
void DoRePaint();
|
||||
|
||||
void OnCloseWindow( wxCloseEvent& event );
|
||||
|
||||
private:
|
||||
// The wxPaintEvent event. mainly calls DoRePaint()
|
||||
void OnPaint( wxPaintEvent& aEvent );
|
||||
|
||||
void OnEraseBackground( wxEraseEvent& event );
|
||||
|
||||
void OnRefreshRequest( wxEvent& aEvent );
|
||||
|
||||
void OnMouseWheel( wxMouseEvent& event );
|
||||
|
||||
void OnMagnify( wxMouseEvent& event );
|
||||
void OnMouseMove( wxMouseEvent& event );
|
||||
void OnLeftDown( wxMouseEvent& event );
|
||||
void OnLeftUp( wxMouseEvent& event );
|
||||
void OnMiddleUp( wxMouseEvent& event );
|
||||
void OnMiddleDown( wxMouseEvent& event );
|
||||
void OnTimerTimeout_Editing( wxTimerEvent& event );
|
||||
void OnResize( wxSizeEvent& event );
|
||||
void OnTimerTimeout_Redraw( wxTimerEvent& event );
|
||||
|
||||
void OnZoomGesture( wxZoomGestureEvent& event );
|
||||
void OnPanGesture( wxPanGestureEvent& event );
|
||||
void OnRotateGesture( wxRotateGestureEvent& event );
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
/**
|
||||
*Stop the editing time so it will not timeout.
|
||||
*/
|
||||
void stop_editingTimeOut_Timer();
|
||||
|
||||
/**
|
||||
* Reset the editing timer.
|
||||
*/
|
||||
void restart_editingTimeOut_Timer();
|
||||
|
||||
/**
|
||||
* Start a camera movement.
|
||||
*
|
||||
* @param aMovingSpeed the time speed.
|
||||
* @param aRenderPivot if it should display pivot cursor while move.
|
||||
*/
|
||||
void request_start_moving_camera( float aMovingSpeed = 2.0f, bool aRenderPivot = true );
|
||||
|
||||
/**
|
||||
* This function hits a ray to the board and start a movement.
|
||||
*/
|
||||
void move_pivot_based_on_cur_mouse_position();
|
||||
|
||||
/**
|
||||
* Render the pivot cursor.
|
||||
*
|
||||
* @param t time between 0.0 and 1.0.
|
||||
* @param aScale scale to apply on the cursor.
|
||||
*/
|
||||
void render_pivot( float t, float aScale );
|
||||
|
||||
/**
|
||||
* Render the 3dmouse pivot cursor.
|
||||
*
|
||||
* @param aScale scale to apply on the cursor.
|
||||
*/
|
||||
void render3dmousePivot( float aScale );
|
||||
|
||||
/**
|
||||
* @return true if OpenGL initialization succeeded.
|
||||
*/
|
||||
bool initializeOpenGL();
|
||||
|
||||
/**
|
||||
* Free created targets and openGL context.
|
||||
*/
|
||||
void releaseOpenGL();
|
||||
|
||||
RAY getRayAtCurrentMousePosition();
|
||||
|
||||
private:
|
||||
TOOL_DISPATCHER* m_eventDispatcher;
|
||||
wxStatusBar* m_parentStatusBar; // Parent statusbar to report progress
|
||||
WX_INFOBAR* m_parentInfoBar;
|
||||
|
||||
wxGLContext* m_glRC; // Current OpenGL context
|
||||
bool m_is_opengl_initialized;
|
||||
bool m_is_opengl_version_supported;
|
||||
|
||||
wxTimer m_editing_timeout_timer; // Expires after some time signaling that
|
||||
// the mouse / keyboard movements are over
|
||||
wxTimer m_redraw_trigger_timer; // Used to schedule a redraw event
|
||||
std::atomic_flag m_is_currently_painting; // Avoid drawing twice at the same time
|
||||
|
||||
bool m_render_pivot; // Render the pivot while camera moving
|
||||
float m_camera_moving_speed; // 1.0f will be 1:1
|
||||
int64_t m_strtime_camera_movement; // Ticktime of camera movement start
|
||||
bool m_animation_enabled; // Camera animation enabled
|
||||
int m_moving_speed_multiplier; // Camera animation speed multiplier option
|
||||
|
||||
BOARD_ADAPTER& m_boardAdapter; // Pre-computed 3D info and settings
|
||||
RENDER_3D_BASE* m_3d_render;
|
||||
RENDER_3D_RAYTRACE_GL* m_3d_render_raytracing;
|
||||
RENDER_3D_OPENGL* m_3d_render_opengl;
|
||||
|
||||
bool m_opengl_supports_raytracing;
|
||||
bool m_render_raytracing_was_requested;
|
||||
|
||||
ACCELERATOR_3D* m_accelerator3DShapes; // used for mouse over searching
|
||||
|
||||
BOARD_ITEM* m_currentRollOverItem;
|
||||
|
||||
bool m_render3dmousePivot = false; // Render the 3dmouse pivot
|
||||
SFVEC3F m_3dmousePivotPos; // The position of the 3dmouse pivot
|
||||
|
||||
/// Used to track gesture events.
|
||||
double m_gestureLastZoomFactor = 1.0;
|
||||
double m_gestureLastAngle = 0.0;
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
* The debug output can be turned on by setting the WXTRACE environment variable to
|
||||
* "KI_TRACE_EDA_3D_CANVAS". See the wxWidgets documentation on wxLogTrace for
|
||||
* more information.
|
||||
*/
|
||||
static const wxChar* m_logTrace;
|
||||
};
|
||||
|
||||
|
||||
#endif // EDA_3D_CANVAS_H
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file eda_3d_canvas_pivot.cpp
|
||||
* @brief Implementation of a 3d cursor
|
||||
*/
|
||||
|
||||
#include "../common_ogl/openGL_includes.h"
|
||||
#include "../common_ogl/ogl_utils.h"
|
||||
#include "eda_3d_canvas.h"
|
||||
|
||||
|
||||
static void pivot_render_triangles( float t )
|
||||
{
|
||||
wxASSERT( t >= 0.0f );
|
||||
|
||||
SFVEC3F vertexPointer[12];
|
||||
|
||||
const float u = 1.0f / 6.0f;
|
||||
|
||||
vertexPointer[0] = SFVEC3F( ( -3.0f + t ) * u, -2.0f * u, 0.0f );
|
||||
vertexPointer[1] = SFVEC3F( ( -3.0f + t ) * u, 2.0f * u, 0.0f );
|
||||
vertexPointer[2] = SFVEC3F( ( -1.0f + t ) * u, 0.0f * u, 0.0f );
|
||||
|
||||
vertexPointer[3] = SFVEC3F( -2.0f * u, ( -3.0f + t ) * u, 0.0f );
|
||||
vertexPointer[4] = SFVEC3F( 2.0f * u, ( -3.0f + t ) * u, 0.0f );
|
||||
vertexPointer[5] = SFVEC3F( 0.0f * u, ( -1.0f + t ) * u, 0.0f );
|
||||
|
||||
vertexPointer[6] = SFVEC3F( ( 3.0f - t ) * u, -2.0f * u, 0.0f );
|
||||
vertexPointer[7] = SFVEC3F( ( 3.0f - t ) * u, 2.0f * u, 0.0f );
|
||||
vertexPointer[8] = SFVEC3F( ( 1.0f - t ) * u, 0.0f * u, 0.0f );
|
||||
|
||||
vertexPointer[9] = SFVEC3F( 2.0f * u, ( 3.0f - t ) * u, 0.0f );
|
||||
vertexPointer[10] = SFVEC3F( -2.0f * u, ( 3.0f - t ) * u, 0.0f );
|
||||
vertexPointer[11] = SFVEC3F( 0.0f * u, ( 1.0f - t ) * u, 0.0f );
|
||||
|
||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
glDisableClientState( GL_COLOR_ARRAY );
|
||||
glDisableClientState( GL_NORMAL_ARRAY );
|
||||
glEnableClientState( GL_VERTEX_ARRAY );
|
||||
glVertexPointer( 3, GL_FLOAT, 0, vertexPointer );
|
||||
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
glDrawArrays( GL_TRIANGLES, 0, 4 * 3 );
|
||||
|
||||
glDisable( GL_BLEND );
|
||||
|
||||
glDisableClientState( GL_VERTEX_ARRAY );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::render_pivot( float t, float aScale )
|
||||
{
|
||||
wxASSERT( aScale >= 0.0f );
|
||||
wxASSERT( t >= 0.0f );
|
||||
|
||||
if( t > 1.0f )
|
||||
t = 1.0f;
|
||||
|
||||
const SFVEC3F &lookAtPos = m_camera.GetLookAtPos_T1();
|
||||
|
||||
glDisable( GL_LIGHTING );
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
glDisable( GL_CULL_FACE );
|
||||
|
||||
// Set projection and modelview matrixes
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
|
||||
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
|
||||
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
glColor4f( 0.0f, 1.0f, 0.0f, 0.75f - t * 0.75f );
|
||||
|
||||
// Translate to the look at position
|
||||
glTranslatef( lookAtPos.x, lookAtPos.y, lookAtPos.z );
|
||||
|
||||
glScalef( aScale, aScale, aScale );
|
||||
pivot_render_triangles( t * 0.5f );
|
||||
|
||||
t = t * 0.80f;
|
||||
glScalef( 1.0f - t, 1.0f - t, 1.0f - t );
|
||||
glColor4f( 0.0f, 1.0f, 0.0f, 0.8f - t );
|
||||
|
||||
glPushMatrix();
|
||||
glRotatef( t * 90.0f, 0.0f, 0.0f, 1.0f );
|
||||
pivot_render_triangles( t * 0.5f );
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glRotatef( -t * 90.0f, 0.0f, 0.0f, 1.0f );
|
||||
pivot_render_triangles( t * 0.5f );
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::render3dmousePivot( float aScale )
|
||||
{
|
||||
wxASSERT( aScale >= 0.0f );
|
||||
|
||||
glDisable( GL_LIGHTING );
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
glDisable( GL_CULL_FACE );
|
||||
|
||||
// Set projection and modelview matrixes
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
|
||||
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
|
||||
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
glColor4f( 0.0f, 0.667f, 0.902f, 0.75f );
|
||||
|
||||
// Translate to the look at position
|
||||
glTranslatef( m_3dmousePivotPos.x, m_3dmousePivotPos.y, m_3dmousePivotPos.z );
|
||||
|
||||
glPointSize( 16.0f );
|
||||
glEnable( GL_POINT_SMOOTH );
|
||||
glHint( GL_POINT_SMOOTH_HINT, GL_NICEST );
|
||||
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
glScalef( aScale, aScale, aScale );
|
||||
|
||||
// Draw a point at the look at position.
|
||||
glBegin( GL_POINTS );
|
||||
glVertex3f( 0, 0, 0 );
|
||||
glEnd();
|
||||
|
||||
glDisable( GL_BLEND );
|
||||
glDisable( GL_POINT_SMOOTH );
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_class.cpp
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
|
||||
#include "3d_viewer.h"
|
||||
#include "3d_struct.h"
|
||||
#include "modelparsers.h"
|
||||
|
||||
|
||||
void S3D_MASTER::Insert( S3D_MATERIAL* aMaterial )
|
||||
{
|
||||
aMaterial->SetNext( m_Materials );
|
||||
m_Materials = aMaterial;
|
||||
}
|
||||
|
||||
|
||||
void S3D_MASTER::Copy( S3D_MASTER* pattern )
|
||||
{
|
||||
SetShape3DName( pattern->GetShape3DName() );
|
||||
m_MatScale = pattern->m_MatScale;
|
||||
m_MatRotation = pattern->m_MatRotation;
|
||||
m_MatPosition = pattern->m_MatPosition;
|
||||
m_3D_Drawings = NULL;
|
||||
m_Materials = NULL;
|
||||
}
|
||||
|
||||
|
||||
S3D_MASTER::S3D_MASTER( EDA_ITEM* aParent ) :
|
||||
EDA_ITEM( aParent, NOT_USED )
|
||||
{
|
||||
m_MatScale.x = m_MatScale.y = m_MatScale.z = 1.0;
|
||||
|
||||
m_3D_Drawings = NULL;
|
||||
m_Materials = NULL;
|
||||
m_parser = NULL;
|
||||
m_ShapeType = FILE3D_NONE;
|
||||
|
||||
m_use_modelfile_diffuseColor = true;
|
||||
m_use_modelfile_emissiveColor = true;
|
||||
m_use_modelfile_specularColor = true;
|
||||
m_use_modelfile_ambientIntensity = true;
|
||||
m_use_modelfile_transparency = true;
|
||||
m_use_modelfile_shininess = true;
|
||||
}
|
||||
|
||||
|
||||
S3D_MASTER:: ~S3D_MASTER()
|
||||
{
|
||||
STRUCT_3D_SHAPE* next;
|
||||
S3D_MATERIAL* nextmat;
|
||||
|
||||
for( ; m_3D_Drawings != NULL; m_3D_Drawings = next )
|
||||
{
|
||||
next = m_3D_Drawings->Next();
|
||||
delete m_3D_Drawings;
|
||||
m_3D_Drawings = 0;
|
||||
}
|
||||
|
||||
for( ; m_Materials != NULL; m_Materials = nextmat )
|
||||
{
|
||||
nextmat = m_Materials->Next();
|
||||
delete m_Materials;
|
||||
m_Materials = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool S3D_MASTER::Is3DType( enum FILE3D_TYPE aShapeType )
|
||||
{
|
||||
// type 'none' is not valid and will always return false
|
||||
if( aShapeType == FILE3D_NONE )
|
||||
return false;
|
||||
|
||||
// no one is interested if we have no file
|
||||
if( m_Shape3DName.empty() )
|
||||
return false;
|
||||
|
||||
if( aShapeType == m_ShapeType )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void S3D_MASTER::SetShape3DName( const wxString& aShapeName )
|
||||
{
|
||||
m_ShapeType = FILE3D_NONE;
|
||||
m_Shape3DName = aShapeName;
|
||||
|
||||
if( m_Shape3DName.empty() )
|
||||
return;
|
||||
|
||||
wxFileName fn = m_Shape3DName;
|
||||
m_Shape3DNameExtension = fn.GetExt();
|
||||
|
||||
if( m_Shape3DNameExtension == wxT( "wrl" ) ||
|
||||
m_Shape3DNameExtension == wxT( "x3d" ) )
|
||||
m_ShapeType = FILE3D_VRML;
|
||||
else if( m_Shape3DNameExtension == wxT( "idf" ) )
|
||||
m_ShapeType = FILE3D_IDF;
|
||||
else
|
||||
m_ShapeType = FILE3D_UNKNOWN;
|
||||
|
||||
// Expand any environment variables embedded in footprint's m_Shape3DName field.
|
||||
// To ensure compatibility with most of footprint's m_Shape3DName field,
|
||||
// if the m_Shape3DName is not an absolute path the default path
|
||||
// given by the environment variable KISYS3DMOD will be used
|
||||
|
||||
if( m_Shape3DName.StartsWith( wxT("${") ) )
|
||||
m_Shape3DFullFilename = wxExpandEnvVars( m_Shape3DName );
|
||||
else
|
||||
m_Shape3DFullFilename = m_Shape3DName;
|
||||
|
||||
wxFileName fnFull( m_Shape3DFullFilename );
|
||||
|
||||
if( !( fnFull.IsAbsolute() || m_Shape3DFullFilename.StartsWith( wxT(".") ) ) )
|
||||
{
|
||||
wxString default_path;
|
||||
wxGetEnv( KISYS3DMOD, &default_path );
|
||||
|
||||
if( !( default_path.IsEmpty() ) )
|
||||
{
|
||||
|
||||
if( !default_path.EndsWith( wxT("/") ) && !default_path.EndsWith( wxT("\\") ) )
|
||||
default_path += wxT("/");
|
||||
|
||||
m_Shape3DFullFilename = default_path + m_Shape3DFullFilename;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const wxString S3D_MASTER::GetShape3DFullFilename()
|
||||
{
|
||||
return m_Shape3DFullFilename;
|
||||
}
|
||||
|
||||
|
||||
const wxString S3D_MASTER::GetShape3DExtension()
|
||||
{
|
||||
return m_Shape3DNameExtension;
|
||||
}
|
||||
|
||||
|
||||
STRUCT_3D_SHAPE::STRUCT_3D_SHAPE( EDA_ITEM* aParent ) :
|
||||
EDA_ITEM( aParent, NOT_USED )
|
||||
{
|
||||
m_3D_Coord = NULL;
|
||||
m_3D_CoordIndex = NULL;
|
||||
m_3D_Points = 0;
|
||||
}
|
||||
|
||||
|
||||
STRUCT_3D_SHAPE:: ~STRUCT_3D_SHAPE()
|
||||
{
|
||||
delete m_3D_Coord;
|
||||
delete m_3D_CoordIndex;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_draw_basic_functions.cpp
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <trigo.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
|
||||
#include <3d_viewer.h>
|
||||
#include <info3d_visu.h>
|
||||
#include <3d_draw_basic_functions.h>
|
||||
#include <modelparsers.h>
|
||||
|
||||
// Number of segments to approximate a circle by segments
|
||||
#define SEGM_PER_CIRCLE 24
|
||||
|
||||
#ifndef CALLBACK
|
||||
#define CALLBACK
|
||||
#endif
|
||||
|
||||
// Variables used to pass a value to call back openGL functions
|
||||
static float s_textureScale;
|
||||
static double s_currentZpos;
|
||||
static double s_biuTo3Dunits;
|
||||
bool s_useTextures;
|
||||
|
||||
// CALLBACK functions for GLU_TESS
|
||||
static void CALLBACK tessBeginCB( GLenum which );
|
||||
static void CALLBACK tessEndCB();
|
||||
static void CALLBACK tessErrorCB( GLenum errorCode );
|
||||
static void CALLBACK tessCPolyPt2Vertex( const GLvoid* data );
|
||||
|
||||
void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
|
||||
|
||||
/* Draw3D_VerticalPolygonalCylinder is a helper function.
|
||||
*
|
||||
* draws a "vertical cylinder" having a polygon shape
|
||||
* from Z position = aZpos to aZpos + aHeight
|
||||
* Used to create the vertical sides of 3D horizontal shapes with thickness.
|
||||
*/
|
||||
static void Draw3D_VerticalPolygonalCylinder( const SHAPE_POLY_SET& aPolysList,
|
||||
int aHeight, int aZpos,
|
||||
bool aInside, double aBiuTo3DUnits )
|
||||
{
|
||||
if( aHeight == 0 )
|
||||
return;
|
||||
|
||||
std::vector<S3D_VERTEX> coords;
|
||||
coords.resize( 4 );
|
||||
|
||||
// Init Z position of the 4 points of a GL_QUAD
|
||||
if( aInside )
|
||||
{
|
||||
coords[0].z = aZpos;
|
||||
coords[1].z = aZpos + aHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
coords[0].z = aZpos + aHeight;
|
||||
coords[1].z = aZpos;
|
||||
}
|
||||
coords[2].z = coords[1].z;
|
||||
coords[3].z = coords[0].z;
|
||||
|
||||
// Draw the vertical polygonal side
|
||||
for( int idx = 0; idx < aPolysList.OutlineCount(); idx++ )
|
||||
{
|
||||
// Each polygon in aPolysList is a polygon with holes
|
||||
const SHAPE_POLY_SET::POLYGON& curr_polywithholes = aPolysList.CPolygon( idx );
|
||||
|
||||
// Draw the outline of each simple polygon inside the polygon with holes:
|
||||
for( unsigned ipoly = 0; ipoly < curr_polywithholes.size(); ipoly++ )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& path = curr_polywithholes[ipoly]; // a simple polygon
|
||||
|
||||
for( int jj = 0; jj < path.PointCount(); jj++ )
|
||||
{
|
||||
const VECTOR2I& a = path.CPoint( jj );
|
||||
const VECTOR2I& b = path.CPoint( jj + 1 );
|
||||
|
||||
// Build the 4 vertices of each GL_QUAD
|
||||
coords[0].x = a.x;
|
||||
coords[0].y = -a.y;
|
||||
coords[1].x = coords[0].x;
|
||||
coords[1].y = coords[0].y; // only z change
|
||||
coords[2].x = b.x;
|
||||
coords[2].y = -b.y;
|
||||
coords[3].x = coords[2].x;
|
||||
coords[3].y = coords[2].y; // only z change
|
||||
|
||||
// Creates the GL_QUAD
|
||||
TransfertToGLlist( coords, aBiuTo3DUnits );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SetGLColor( EDA_COLOR_T color, double alpha )
|
||||
{
|
||||
const StructColors &colordata = g_ColorRefs[ColorGetBase( color )];
|
||||
|
||||
float red = colordata.m_Red / 255.0;
|
||||
float blue = colordata.m_Blue / 255.0;
|
||||
float green = colordata.m_Green / 255.0;
|
||||
glColor4f( red, green, blue, (float)alpha );
|
||||
}
|
||||
|
||||
|
||||
void SetGLColor( S3D_COLOR& aColor, float aTransparency )
|
||||
{
|
||||
glColor4f( aColor.m_Red, aColor.m_Green, aColor.m_Blue, aTransparency );
|
||||
}
|
||||
|
||||
|
||||
void SetGLTexture( GLuint text_id, float scale )
|
||||
{
|
||||
glEnable( GL_TEXTURE_2D );
|
||||
glBindTexture( GL_TEXTURE_2D, text_id );
|
||||
s_textureScale = scale; // for Tess callback functions
|
||||
}
|
||||
|
||||
|
||||
/* draw all solid polygons found in aPolysList
|
||||
* aZpos = z position in board internal units
|
||||
* aThickness = thickness in board internal units
|
||||
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
|
||||
* If aThickness > 0, a solid object is drawn.
|
||||
* The top side is located at aZpos + aThickness / 2
|
||||
* The bottom side is located at aZpos - aThickness / 2
|
||||
*/
|
||||
void Draw3D_SolidHorizontalPolyPolygons( const SHAPE_POLY_SET& aPolysList,
|
||||
int aZpos, int aThickness, double aBiuTo3DUnits,
|
||||
bool aUseTextures,
|
||||
float aNormal_Z_Orientation )
|
||||
{
|
||||
// for Tess callback functions:
|
||||
s_biuTo3Dunits = aBiuTo3DUnits;
|
||||
s_useTextures = aUseTextures;
|
||||
|
||||
GLUtesselator* tess = gluNewTess();
|
||||
|
||||
gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*) () )tessBeginCB );
|
||||
gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*) () )tessEndCB );
|
||||
gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*) () )tessErrorCB );
|
||||
gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )tessCPolyPt2Vertex );
|
||||
|
||||
GLdouble v_data[3];
|
||||
double zpos = ( aZpos + (aThickness / 2.0) ) * aBiuTo3DUnits;
|
||||
s_currentZpos = zpos; // for Tess callback functions
|
||||
v_data[2] = zpos;
|
||||
|
||||
// Set normal toward positive Z axis, for a solid object on the top side
|
||||
|
||||
//gluTessProperty( tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE );
|
||||
gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD );
|
||||
|
||||
glNormal3f( 0.0, 0.0, aNormal_Z_Orientation );
|
||||
|
||||
// Draw solid areas contained in this list
|
||||
SHAPE_POLY_SET polylist = aPolysList; // temporary copy for gluTessVertex
|
||||
|
||||
for( int side = 0; side < 2; side++ )
|
||||
{
|
||||
|
||||
for ( int idx = 0; idx < polylist.OutlineCount(); ++idx )
|
||||
{
|
||||
gluTessBeginPolygon( tess, NULL );
|
||||
|
||||
SHAPE_POLY_SET::POLYGON& curr_polywithholes = polylist.Polygon( idx ); // a polygon with holes
|
||||
|
||||
for( unsigned ipoly = 0; ipoly < curr_polywithholes.size(); ipoly++ )
|
||||
{
|
||||
SHAPE_LINE_CHAIN& curr_poly = curr_polywithholes[ipoly]; // a simple polygon
|
||||
|
||||
gluTessBeginContour( tess );
|
||||
|
||||
for( int ipt = 0; ipt < curr_poly.PointCount(); ipt++ )
|
||||
{
|
||||
v_data[0] = curr_poly.Point( ipt ).x * aBiuTo3DUnits;
|
||||
v_data[1] = -curr_poly.Point( ipt ).y * aBiuTo3DUnits;
|
||||
// gluTessVertex store pointers on data, not data, so do not store
|
||||
// different corners values in a temporary variable
|
||||
// but send pointer on each CPolyPt value in polylist
|
||||
// before calling gluDeleteTess
|
||||
gluTessVertex( tess, v_data, &curr_poly.Point( ipt ) );
|
||||
}
|
||||
|
||||
gluTessEndContour( tess );
|
||||
}
|
||||
|
||||
gluTessEndPolygon( tess );
|
||||
}
|
||||
|
||||
|
||||
if( aThickness == 0 )
|
||||
break;
|
||||
|
||||
// Prepare the bottom side of solid areas
|
||||
zpos = ( aZpos - (aThickness / 2.0) ) * aBiuTo3DUnits;
|
||||
s_currentZpos = zpos; // for Tess callback functions
|
||||
v_data[2] = zpos;
|
||||
|
||||
glNormal3f( 0.0, 0.0, -aNormal_Z_Orientation );
|
||||
}
|
||||
|
||||
gluDeleteTess( tess );
|
||||
|
||||
if( aThickness == 0 )
|
||||
return;
|
||||
|
||||
// Build the 3D data : vertical side
|
||||
Draw3D_VerticalPolygonalCylinder( polylist, aThickness, aZpos - (aThickness / 2.0),
|
||||
true, aBiuTo3DUnits );
|
||||
}
|
||||
|
||||
|
||||
/* draw a cylinder (a tube) using 3D primitives.
|
||||
* the cylinder axis is parallel to the Z axis
|
||||
* If aHeight = height of the cylinder is 0, only one ring will be drawn
|
||||
* If aThickness = 0, only one cylinder will be drawn
|
||||
*/
|
||||
void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
|
||||
int aHeight, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits )
|
||||
{
|
||||
const int slice = SEGM_PER_CIRCLE;
|
||||
SHAPE_POLY_SET outer_cornerBuffer;
|
||||
|
||||
TransformCircleToPolygon( outer_cornerBuffer, aCenterPos,
|
||||
aRadius + (aThickness / 2), slice );
|
||||
|
||||
std::vector<S3D_VERTEX> coords;
|
||||
coords.resize( 4 );
|
||||
|
||||
SHAPE_POLY_SET inner_cornerBuffer;
|
||||
|
||||
if( aThickness ) // build the the vertical inner polygon (hole)
|
||||
TransformCircleToPolygon( inner_cornerBuffer, aCenterPos,
|
||||
aRadius - (aThickness / 2), slice );
|
||||
|
||||
if( aHeight )
|
||||
{
|
||||
|
||||
// Draw the vertical outer side
|
||||
Draw3D_VerticalPolygonalCylinder( outer_cornerBuffer,
|
||||
aHeight, aZpos, false, aBiuTo3DUnits );
|
||||
|
||||
if( aThickness )
|
||||
// Draws the vertical inner side (hole)
|
||||
Draw3D_VerticalPolygonalCylinder( inner_cornerBuffer,
|
||||
aHeight, aZpos, true, aBiuTo3DUnits );
|
||||
}
|
||||
|
||||
if( aThickness )
|
||||
{
|
||||
// draw top (front) and bottom (back) horizontal sides (rings)
|
||||
outer_cornerBuffer.AddHole( inner_cornerBuffer.COutline( 0 ) );
|
||||
|
||||
// draw top (front) horizontal ring
|
||||
Draw3D_SolidHorizontalPolyPolygons( outer_cornerBuffer, aZpos + aHeight,
|
||||
0, aBiuTo3DUnits, false, 1.0f );
|
||||
|
||||
if( aHeight )
|
||||
{
|
||||
// draw bottom (back) horizontal ring
|
||||
Draw3D_SolidHorizontalPolyPolygons( outer_cornerBuffer, aZpos,
|
||||
0, aBiuTo3DUnits, false, -1.0f );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function Draw3D_ZaxisOblongCylinder:
|
||||
* draw a segment with an oblong hole.
|
||||
* Used to draw oblong holes
|
||||
* If aHeight = height of the cylinder is 0, only one ring will be drawn
|
||||
* If aThickness = 0, only one cylinder will be drawn
|
||||
*/
|
||||
void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
|
||||
int aRadius, int aHeight, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits )
|
||||
{
|
||||
const int slice = SEGM_PER_CIRCLE;
|
||||
|
||||
// Build the points to approximate oblong cylinder by segments
|
||||
SHAPE_POLY_SET cornerBuffer;
|
||||
|
||||
int segm_width = (aRadius * 2) + aThickness;
|
||||
TransformRoundedEndsSegmentToPolygon( cornerBuffer, aAxis1Pos,
|
||||
aAxis2Pos, slice, segm_width );
|
||||
|
||||
// Draw the oblong outer cylinder
|
||||
if( aHeight )
|
||||
Draw3D_VerticalPolygonalCylinder( cornerBuffer, aHeight, aZpos,
|
||||
false, aBiuTo3DUnits );
|
||||
|
||||
if( aThickness )
|
||||
{
|
||||
SHAPE_POLY_SET inner_cornerBuffer;
|
||||
segm_width = aRadius * 2;
|
||||
TransformRoundedEndsSegmentToPolygon( inner_cornerBuffer, aAxis1Pos,
|
||||
aAxis2Pos, slice, segm_width );
|
||||
|
||||
// Draw the oblong inner cylinder
|
||||
if( aHeight )
|
||||
Draw3D_VerticalPolygonalCylinder( inner_cornerBuffer, aHeight,
|
||||
aZpos, true, aBiuTo3DUnits );
|
||||
|
||||
// Build the horizontal full polygon shape
|
||||
// (outer polygon shape - inner polygon shape)
|
||||
cornerBuffer.AddHole( inner_cornerBuffer.COutline( 0 ) );
|
||||
|
||||
// draw top (front) horizontal side (ring)
|
||||
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos + aHeight, 0, aBiuTo3DUnits, false,
|
||||
1.0f );
|
||||
|
||||
if( aHeight )
|
||||
{
|
||||
// draw bottom (back) horizontal side (ring)
|
||||
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, 0, aBiuTo3DUnits, false,
|
||||
-1.0f );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* draw a thick segment using 3D primitives, in a XY plane
|
||||
* wxPoint aStart, wxPoint aEnd = YX position of end in board units
|
||||
* aWidth = width of segment in board units
|
||||
* aThickness = thickness of segment in board units
|
||||
* aZpos = z position of segment in board units
|
||||
*/
|
||||
void Draw3D_SolidSegment( const wxPoint& aStart, const wxPoint& aEnd,
|
||||
int aWidth, int aThickness, int aZpos, double aBiuTo3DUnits )
|
||||
{
|
||||
SHAPE_POLY_SET cornerBuffer;
|
||||
const int slice = SEGM_PER_CIRCLE;
|
||||
|
||||
TransformRoundedEndsSegmentToPolygon( cornerBuffer, aStart, aEnd, slice, aWidth );
|
||||
|
||||
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, aThickness, aBiuTo3DUnits, false, 1.0f );
|
||||
}
|
||||
|
||||
|
||||
void Draw3D_ArcSegment( const wxPoint& aCenterPos, const wxPoint& aStartPoint,
|
||||
double aArcAngle, int aWidth, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits )
|
||||
{
|
||||
const int slice = SEGM_PER_CIRCLE;
|
||||
|
||||
SHAPE_POLY_SET cornerBuffer;
|
||||
TransformArcToPolygon( cornerBuffer, aCenterPos, aStartPoint, aArcAngle,
|
||||
slice, aWidth );
|
||||
|
||||
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, aThickness, aBiuTo3DUnits, false, 1.0f );
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
// GLU_TESS CALLBACKS
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CALLBACK tessBeginCB( GLenum which )
|
||||
{
|
||||
glBegin( which );
|
||||
}
|
||||
|
||||
|
||||
void CALLBACK tessEndCB()
|
||||
{
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
void CALLBACK tessCPolyPt2Vertex( const GLvoid* data )
|
||||
{
|
||||
// cast back to double type
|
||||
const VECTOR2I* ptr = (const VECTOR2I*) data;
|
||||
|
||||
if( s_useTextures )
|
||||
{
|
||||
glTexCoord2f( ptr->x * s_biuTo3Dunits * s_textureScale,
|
||||
-ptr->y * s_biuTo3Dunits * s_textureScale);
|
||||
}
|
||||
|
||||
glVertex3d( ptr->x * s_biuTo3Dunits, -ptr->y * s_biuTo3Dunits, s_currentZpos );
|
||||
}
|
||||
|
||||
|
||||
void CALLBACK tessErrorCB( GLenum errorCode )
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
const GLubyte* errorStr;
|
||||
|
||||
errorStr = gluErrorString( errorCode );
|
||||
|
||||
// DEBUG //
|
||||
DBG( printf( "Tess ERROR: %s\n", errorStr ); )
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_draw_basic_functions.h
|
||||
*/
|
||||
#ifndef _3D_DRAW_BASIC_FUNCTIONS_H_
|
||||
#define _3D_DRAW_BASIC_FUNCTIONS_H_
|
||||
|
||||
// angle increment to draw a circle, approximated by segments
|
||||
#define ANGLE_INC( x ) ( 3600 / (x) )
|
||||
|
||||
/** draw all solid polygons found in aPolysList
|
||||
* @param aPolysList = the poligon list to draw
|
||||
* @param aZpos = z position in board internal units
|
||||
* @param aThickness = thickness in board internal units
|
||||
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
|
||||
* @param aUseTextures = true to use textxures for the polygons
|
||||
* @param aNormal_Z_Orientation = the normal Z orientation to apply
|
||||
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
|
||||
* If aThickness > 0, a solid object is drawn.
|
||||
* The top side is located at aZpos + aThickness / 2
|
||||
* The bottom side is located at aZpos - aThickness / 2
|
||||
*/
|
||||
void Draw3D_SolidHorizontalPolyPolygons( const SHAPE_POLY_SET& aPolysList,
|
||||
int aZpos, int aThickness, double aBiuTo3DUnits,
|
||||
bool aUseTextures,
|
||||
float aNormal_Z_Orientation );
|
||||
|
||||
/** draw a thick segment using 3D primitives, in a XY plane
|
||||
* @param aStart = YX position of start point in board units
|
||||
* @param aEnd = YX position of end point in board units
|
||||
* @param aWidth = width of segment in board units
|
||||
* @param aThickness = thickness of segment in board units
|
||||
* @param aZpos = z position of segment in board units
|
||||
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
|
||||
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
|
||||
* If aThickness > 0, a solid object is drawn.
|
||||
* The top side is located at aZpos + aThickness / 2
|
||||
* The bottom side is located at aZpos - aThickness / 2
|
||||
*/
|
||||
void Draw3D_SolidSegment( const wxPoint& aStart, const wxPoint& aEnd,
|
||||
int aWidth, int aThickness, int aZpos,
|
||||
double aBiuTo3DUnits );
|
||||
|
||||
/** draw an arc using 3D primitives, in a XY plane
|
||||
* @param aCenterPos = XY position of the center in board units
|
||||
* @param aStartPoint = start point coordinate of arc in board units
|
||||
* @param aWidth = width of the circle in board units
|
||||
* @param aArcAngle = arc angle in 1/10 degrees
|
||||
* @param aWidth = thickness of arc
|
||||
* @param aThickness = thickness of segment in board units
|
||||
* @param aZpos = z position of segment in board units
|
||||
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
|
||||
*/
|
||||
void Draw3D_ArcSegment( const wxPoint& aCenterPos, const wxPoint& aStartPoint,
|
||||
double aArcAngle, int aWidth, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits );
|
||||
|
||||
|
||||
/** draw a thick cylinder (a tube) using 3D primitives.
|
||||
* the cylinder axis is parallel to the Z axis
|
||||
* @param aCenterPos = XY position of the axis cylinder ( board internal units)
|
||||
* @param aRadius = radius of the cylinder ( board internal units)
|
||||
* @param aHeight = height of the cylinder ( boardinternal units)
|
||||
* @param aThickness = tichkness of tube ( boardinternal units)
|
||||
* @param aZpos = Z position of the bottom side of the cylinder ( board internal units)
|
||||
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
|
||||
*
|
||||
* If aHeight = height of the cylinder is 0, only one ring will be drawn
|
||||
* If aThickness = 0, only one cylinder (not a tube) will be drawn
|
||||
*/
|
||||
void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
|
||||
int aHeight, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits );
|
||||
|
||||
/** draw an oblong cylinder (oblong tube) using 3D primitives.
|
||||
* the cylinder axis are parallel to the Z axis
|
||||
* @param aAxis1Pos = position of the first axis cylinder
|
||||
* @param aAxis2Pos = position of the second axis cylinder
|
||||
* @param aRadius = radius of the cylinder ( board internal units )
|
||||
* @param aHeight = height of the cylinder ( board internal units )
|
||||
* @param aThickness = tichkness of tube ( board internal units )
|
||||
* @param aZpos = Z position of the bottom side of the cylinder ( board internal units )
|
||||
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
|
||||
*/
|
||||
void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
|
||||
int aRadius, int aHeight, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits );
|
||||
/**
|
||||
* Set the current 3D color from a Kicad color, with optional transparency
|
||||
* @param aColor = a EDA_COLOR_T kicad color index
|
||||
* @param aTransparency = the color transparency (default = 1.0 = no transparency)
|
||||
*/
|
||||
void SetGLColor( EDA_COLOR_T aColor, double aTransparency = 1.0 );
|
||||
|
||||
/**
|
||||
* Set the current 3D color from a S3D_COLOR color, with optional transparency
|
||||
* @param aColor = a S3D_COLOR RGB color index
|
||||
* @param aTransparency = the color transparency (default = 1.0 = no transparency)
|
||||
*/
|
||||
void SetGLColor( S3D_COLOR& aColor, float aTransparency );
|
||||
|
||||
|
||||
/**
|
||||
* Set a texture id and a scale to apply when rendering the polygons
|
||||
* @param text_id = texture ID created by glGenTextures
|
||||
* @param scale = scale to apply to texture coords
|
||||
*/
|
||||
void SetGLTexture( GLuint text_id, float scale );
|
||||
|
||||
|
||||
#endif // _3D_DRAW_BASIC_FUNCTIONS_H_
|
||||
@@ -0,0 +1,640 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_draw_board_body.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <common.h>
|
||||
#include <trigo.h>
|
||||
#include <pcbstruct.h>
|
||||
#include <drawtxt.h>
|
||||
#include <layers_id_colors_and_visibility.h>
|
||||
|
||||
#include <wxBasePcbFrame.h>
|
||||
#include <class_board.h>
|
||||
#include <class_module.h>
|
||||
#include <class_track.h>
|
||||
#include <class_edge_mod.h>
|
||||
#include <class_zone.h>
|
||||
#include <class_drawsegment.h>
|
||||
#include <class_pcb_text.h>
|
||||
#include <colors_selection.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
|
||||
#include <gal/opengl/opengl_compositor.h>
|
||||
#ifdef __WINDOWS__
|
||||
#include <GL/glew.h> // must be included before gl.h
|
||||
#endif
|
||||
|
||||
#include <3d_viewer.h>
|
||||
#include <3d_canvas.h>
|
||||
#include <info3d_visu.h>
|
||||
#include <trackball.h>
|
||||
#include <3d_draw_basic_functions.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/shape_file_io.h>
|
||||
|
||||
|
||||
#include <CImage.h>
|
||||
#include <reporter.h>
|
||||
|
||||
// An option for all operations on polygons:
|
||||
// when useFastModeForPolygons = true, calculations can be *a lot* faster.
|
||||
// but created polygons can be not stricty simple (can share edges)
|
||||
// Although stricty simple are better for glu tesselation functions, I do not see
|
||||
// any issue when allowing not stricty simple polygons.
|
||||
// But I see *very* long calculations when setting useFastMode to false.
|
||||
// So, be careful if changing thie option
|
||||
bool useFastModeForPolygons = true;
|
||||
|
||||
/* returns the Z orientation parameter 1.0 or -1.0 for aLayer
|
||||
* Z orientation is 1.0 for all layers but "back" layers:
|
||||
* B_Cu , B_Adhes, B_Paste ), B_SilkS
|
||||
* used to calculate the Z orientation parameter for glNormal3f
|
||||
*/
|
||||
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer );
|
||||
|
||||
void EDA_3D_CANVAS::buildBoardThroughHolesPolygonList( SHAPE_POLY_SET& allBoardHoles,
|
||||
int aSegCountPerCircle, bool aOptimizeLargeCircles )
|
||||
{
|
||||
// hole diameter value to change seg count by circle:
|
||||
int small_hole_limit = Millimeter2iu( 1.0 );
|
||||
int copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
||||
|
||||
BOARD* pcb = GetBoard();
|
||||
|
||||
// Build holes of through vias:
|
||||
for( TRACK* track = pcb->m_Track; track; track = track->Next() )
|
||||
{
|
||||
if( track->Type() != PCB_VIA_T )
|
||||
continue;
|
||||
|
||||
VIA *via = static_cast<VIA*>( track );
|
||||
|
||||
if( via->GetViaType() != VIA_THROUGH )
|
||||
continue;
|
||||
|
||||
int holediameter = via->GetDrillValue();
|
||||
int hole_outer_radius = (holediameter + copper_thickness) / 2;
|
||||
|
||||
TransformCircleToPolygon( allBoardHoles,
|
||||
via->GetStart(), hole_outer_radius,
|
||||
aSegCountPerCircle );
|
||||
}
|
||||
|
||||
// Build holes of through pads:
|
||||
for( MODULE* footprint = pcb->m_Modules; footprint; footprint = footprint->Next() )
|
||||
{
|
||||
for( D_PAD* pad = footprint->Pads(); pad; pad = pad->Next() )
|
||||
{
|
||||
// Calculate a factor to apply to segcount for large holes ( > 1 mm)
|
||||
// (bigger pad drill size -> more segments) because holes in pads can have
|
||||
// very different sizes and optimizing this segcount gives a better look
|
||||
// Mainly mounting holes have a size bigger than small_hole_limit
|
||||
wxSize padHole = pad->GetDrillSize();
|
||||
|
||||
if( ! padHole.x ) // Not drilled pad like SMD pad
|
||||
continue;
|
||||
|
||||
// we use the hole diameter to calculate the seg count.
|
||||
// for round holes, padHole.x == padHole.y
|
||||
// for oblong holes, the diameter is the smaller of (padHole.x, padHole.y)
|
||||
int diam = std::min( padHole.x, padHole.y );
|
||||
int segcount = aSegCountPerCircle;
|
||||
|
||||
if( diam > small_hole_limit )
|
||||
{
|
||||
double segFactor = (double)diam / small_hole_limit;
|
||||
segcount = (int)(aSegCountPerCircle * segFactor);
|
||||
|
||||
// limit segcount to 48. For a circle this is a very good approx.
|
||||
if( segcount > 48 )
|
||||
segcount = 48;
|
||||
}
|
||||
|
||||
// The hole in the body is inflated by copper thickness.
|
||||
int inflate = copper_thickness;
|
||||
|
||||
// If not plated, no copper.
|
||||
if( pad->GetAttribute () == PAD_ATTRIB_HOLE_NOT_PLATED )
|
||||
inflate = 0;
|
||||
|
||||
pad->BuildPadDrillShapePolygon( allBoardHoles, inflate, segcount );
|
||||
}
|
||||
}
|
||||
|
||||
allBoardHoles.Simplify( useFastModeForPolygons );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
|
||||
REPORTER* aErrorMessages, REPORTER* aActivity )
|
||||
{
|
||||
BOARD* pcb = GetBoard();
|
||||
|
||||
// If FL_RENDER_SHOW_HOLES_IN_ZONES is true, holes are correctly removed from copper zones areas.
|
||||
// If FL_RENDER_SHOW_HOLES_IN_ZONES is false, holes are not removed from copper zones areas,
|
||||
// but the calculation time is twice shorter.
|
||||
bool remove_Holes = isEnabled( FL_RENDER_SHOW_HOLES_IN_ZONES );
|
||||
|
||||
bool realistic_mode = isRealisticMode();
|
||||
bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );
|
||||
|
||||
// Number of segments to convert a circle to polygon
|
||||
// We use 2 values: the first gives a good shape (for instanes rond pads)
|
||||
// the second is used to speed up calculations, when a poor approximation is acceptable (holes)
|
||||
const int segcountforcircle = 18;
|
||||
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2.0) );
|
||||
const int segcountLowQuality = 12; // segments to draw a circle with low quality
|
||||
// to reduce time calculations
|
||||
// for holes and items which do not need
|
||||
// a fine representation
|
||||
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2.0) );
|
||||
|
||||
SHAPE_POLY_SET bufferPolys; // copper areas: tracks, pads and filled zones areas
|
||||
// when holes are removed from zones
|
||||
SHAPE_POLY_SET bufferPcbOutlines; // stores the board main outlines
|
||||
SHAPE_POLY_SET bufferZonesPolys; // copper filled zones areas
|
||||
// when holes are not removed from zones
|
||||
SHAPE_POLY_SET currLayerHoles; // Contains holes for the current layer
|
||||
SHAPE_POLY_SET allLayerHoles; // Contains holes for all layers
|
||||
|
||||
// Build a polygon from edge cut items
|
||||
wxString msg;
|
||||
|
||||
if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
|
||||
{
|
||||
if( aErrorMessages )
|
||||
{
|
||||
msg << wxT("\n") << _("Unable to calculate the board outlines.\n"
|
||||
"Therefore use the board boundary box.") << wxT("\n\n");
|
||||
|
||||
aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
|
||||
}
|
||||
}
|
||||
|
||||
// Build board holes, with optimization of large holes shape.
|
||||
buildBoardThroughHolesPolygonList( allLayerHoles, segcountLowQuality, true );
|
||||
|
||||
LSET cu_set = LSET::AllCuMask( GetPrm3DVisu().m_CopperLayersCount );
|
||||
|
||||
glNewList( aBoardList, GL_COMPILE );
|
||||
|
||||
for( LSEQ cu = cu_set.CuStack(); cu; ++cu )
|
||||
{
|
||||
LAYER_ID layer = *cu;
|
||||
|
||||
// Skip non enabled layers in normal mode,
|
||||
// and internal layers in realistic mode
|
||||
if( !is3DLayerEnabled( layer ) )
|
||||
continue;
|
||||
|
||||
if( aActivity )
|
||||
aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );
|
||||
|
||||
bufferPolys.RemoveAllContours();
|
||||
bufferZonesPolys.RemoveAllContours();
|
||||
currLayerHoles.RemoveAllContours();
|
||||
|
||||
// Draw track shapes:
|
||||
for( TRACK* track = pcb->m_Track; track; track = track->Next() )
|
||||
{
|
||||
if( !track->IsOnLayer( layer ) )
|
||||
continue;
|
||||
|
||||
track->TransformShapeWithClearanceToPolygon( bufferPolys,
|
||||
0, segcountforcircle,
|
||||
correctionFactor );
|
||||
|
||||
// Add blind/buried via holes
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
{
|
||||
VIA *via = static_cast<VIA*>( track );
|
||||
|
||||
if( via->GetViaType() == VIA_THROUGH )
|
||||
continue; // already done
|
||||
|
||||
int holediameter = via->GetDrillValue();
|
||||
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
||||
int hole_outer_radius = (holediameter + thickness) / 2;
|
||||
|
||||
TransformCircleToPolygon( currLayerHoles,
|
||||
via->GetStart(), hole_outer_radius,
|
||||
segcountLowQuality );
|
||||
}
|
||||
}
|
||||
|
||||
// draw pad shapes
|
||||
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
|
||||
{
|
||||
// Note: NPTH pads are not drawn on copper layers when the pad
|
||||
// has same shape as its hole
|
||||
module->TransformPadsShapesWithClearanceToPolygon( layer,
|
||||
bufferPolys,
|
||||
0,
|
||||
segcountforcircle,
|
||||
correctionFactor, true );
|
||||
|
||||
// Micro-wave modules may have items on copper layers
|
||||
module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
|
||||
bufferPolys,
|
||||
0,
|
||||
segcountforcircle,
|
||||
correctionFactor );
|
||||
|
||||
// pad holes are already in list.
|
||||
}
|
||||
|
||||
// Draw copper zones. Note:
|
||||
// * if the holes are removed from copper zones
|
||||
// the polygons are stored in bufferPolys (which contains all other polygons)
|
||||
// * if the holes are NOT removed from copper zones
|
||||
// the polygons are stored in bufferZonesPolys
|
||||
if( isEnabled( FL_ZONE ) )
|
||||
{
|
||||
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
|
||||
{
|
||||
ZONE_CONTAINER* zone = pcb->GetArea( ii );
|
||||
LAYER_NUM zonelayer = zone->GetLayer();
|
||||
|
||||
if( zonelayer == layer )
|
||||
{
|
||||
zone->TransformSolidAreasShapesToPolygonSet(
|
||||
remove_Holes ? bufferPolys : bufferZonesPolys,
|
||||
segcountLowQuality, correctionFactorLQ );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw graphic items on copper layers (texts)
|
||||
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
|
||||
{
|
||||
if( !item->IsOnLayer( layer ) )
|
||||
continue;
|
||||
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_LINE_T: // should not exist on copper layers
|
||||
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
|
||||
bufferPolys, 0, segcountforcircle, correctionFactor );
|
||||
break;
|
||||
|
||||
case PCB_TEXT_T:
|
||||
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
|
||||
bufferPolys, 0, segcountLowQuality, correctionFactor );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// bufferPolys contains polygons to merge. Many overlaps .
|
||||
// Calculate merged polygons
|
||||
if( bufferPolys.IsEmpty() )
|
||||
continue;
|
||||
|
||||
// Use Clipper lib to subtract holes to copper areas
|
||||
if( currLayerHoles.OutlineCount() )
|
||||
{
|
||||
currLayerHoles.Append(allLayerHoles);
|
||||
currLayerHoles.Simplify( useFastModeForPolygons );
|
||||
bufferPolys.BooleanSubtract( currLayerHoles, useFastModeForPolygons );
|
||||
}
|
||||
else
|
||||
bufferPolys.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
|
||||
|
||||
int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
|
||||
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
|
||||
|
||||
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)
|
||||
|
||||
// If we are not using thickness, then the z-normal has to match the layer direction
|
||||
// because just one plane will be drawn
|
||||
if( !thickness )
|
||||
zNormal = Get3DLayer_Z_Orientation( layer );
|
||||
|
||||
if( realistic_mode )
|
||||
{
|
||||
setGLCopperColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
|
||||
SetGLColor( color );
|
||||
}
|
||||
|
||||
// If holes are removed from copper zones, bufferPolys contains all polygons
|
||||
// to draw (tracks+zones+texts).
|
||||
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos, thickness,
|
||||
GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
||||
zNormal );
|
||||
|
||||
// If holes are not removed from copper zones (for calculation time reasons,
|
||||
// the zone polygons are stored in bufferZonesPolys and have to be drawn now:
|
||||
if( !bufferZonesPolys.IsEmpty() )
|
||||
{
|
||||
Draw3D_SolidHorizontalPolyPolygons( bufferZonesPolys, zpos, thickness,
|
||||
GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
||||
zNormal );
|
||||
}
|
||||
}
|
||||
|
||||
if( aActivity )
|
||||
aActivity->Report( _( "Build board body" ) );
|
||||
|
||||
// Draw plated vertical holes inside the board, but not always. They are drawn:
|
||||
// - if the board body is not shown, to show the holes.
|
||||
// - or if the copper thickness is shown
|
||||
if( !isEnabled( FL_SHOW_BOARD_BODY ) || isEnabled( FL_USE_COPPER_THICKNESS ) )
|
||||
{
|
||||
// Draw vias holes (vertical cylinders)
|
||||
for( const TRACK* track = pcb->m_Track; track; track = track->Next() )
|
||||
{
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
{
|
||||
const VIA *via = static_cast<const VIA*>(track);
|
||||
draw3DViaHole( via );
|
||||
}
|
||||
}
|
||||
|
||||
// Draw pads holes (vertical cylinders)
|
||||
for( const MODULE* module = pcb->m_Modules; module; module = module->Next() )
|
||||
{
|
||||
for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
|
||||
if( pad->GetAttribute () != PAD_ATTRIB_HOLE_NOT_PLATED )
|
||||
draw3DPadHole( pad );
|
||||
}
|
||||
}
|
||||
|
||||
glEndList();
|
||||
|
||||
// Build the body board:
|
||||
glNewList( aBodyOnlyList, GL_COMPILE );
|
||||
|
||||
if( isRealisticMode() )
|
||||
{
|
||||
setGLEpoxyColor( 1.00 );
|
||||
}
|
||||
else
|
||||
{
|
||||
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( Edge_Cuts );
|
||||
SetGLColor( color, 0.7 );
|
||||
}
|
||||
|
||||
float copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
||||
|
||||
// a small offset between substrate and external copper layer to avoid artifacts
|
||||
// when drawing copper items on board
|
||||
float epsilon = Millimeter2iu( 0.01 );
|
||||
float zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
|
||||
float board_thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
|
||||
- GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
|
||||
|
||||
// items on copper layers and having a thickness = copper_thickness
|
||||
// are drawn from zpos - copper_thickness/2 to zpos + copper_thickness
|
||||
// therefore substrate position is copper_thickness/2 to
|
||||
// substrate_height - copper_thickness/2
|
||||
zpos += (copper_thickness + epsilon) / 2.0f;
|
||||
board_thickness -= copper_thickness + epsilon;
|
||||
|
||||
bufferPcbOutlines.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
|
||||
|
||||
if( !bufferPcbOutlines.IsEmpty() )
|
||||
{
|
||||
Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness / 2.0,
|
||||
board_thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
||||
1.0f );
|
||||
}
|
||||
|
||||
glEndList();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* aActivity )
|
||||
{
|
||||
BOARD* pcb = GetBoard();
|
||||
bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );
|
||||
|
||||
// Number of segments to draw a circle using segments
|
||||
const int segcountforcircle = 18;
|
||||
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) );
|
||||
const int segcountLowQuality = 12; // segments to draw a circle with low quality
|
||||
// to reduce time calculations
|
||||
// for holes and items which do not need
|
||||
// a fine representation
|
||||
|
||||
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2) );
|
||||
|
||||
// segments to draw a circle to build texts. Is is used only to build
|
||||
// the shape of each segment of the stroke font, therefore no need to have
|
||||
// many segments per circle.
|
||||
const int segcountInStrokeFont = 8;
|
||||
|
||||
SHAPE_POLY_SET bufferPolys;
|
||||
SHAPE_POLY_SET allLayerHoles; // Contains through holes, calculated only once
|
||||
SHAPE_POLY_SET bufferPcbOutlines; // stores the board main outlines
|
||||
|
||||
// Build a polygon from edge cut items
|
||||
wxString msg;
|
||||
|
||||
if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
|
||||
{
|
||||
if( aErrorMessages )
|
||||
{
|
||||
msg << wxT("\n") <<
|
||||
_("Unable to calculate the board outlines.\n"
|
||||
"Therefore use the board boundary box.") << wxT("\n\n");
|
||||
aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
|
||||
}
|
||||
}
|
||||
|
||||
// Build board holes, with no optimization of large holes shape.
|
||||
buildBoardThroughHolesPolygonList( allLayerHoles, segcountLowQuality, false );
|
||||
|
||||
// draw graphic items, on technical layers
|
||||
|
||||
static const LAYER_ID teckLayerList[] = {
|
||||
B_Adhes,
|
||||
F_Adhes,
|
||||
B_Paste,
|
||||
F_Paste,
|
||||
B_SilkS,
|
||||
F_SilkS,
|
||||
B_Mask,
|
||||
F_Mask,
|
||||
};
|
||||
|
||||
// User layers are not drawn here, only technical layers
|
||||
for( LSEQ seq = LSET::AllTechMask().Seq( teckLayerList, DIM( teckLayerList ) ); seq; ++seq )
|
||||
{
|
||||
LAYER_ID layer = *seq;
|
||||
|
||||
if( !is3DLayerEnabled( layer ) )
|
||||
continue;
|
||||
|
||||
if( layer == Edge_Cuts && isEnabled( FL_SHOW_BOARD_BODY ) )
|
||||
continue;
|
||||
|
||||
if( aActivity )
|
||||
aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );
|
||||
|
||||
bufferPolys.RemoveAllContours();
|
||||
|
||||
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
|
||||
{
|
||||
if( !item->IsOnLayer( layer ) )
|
||||
continue;
|
||||
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_LINE_T:
|
||||
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
|
||||
bufferPolys, 0, segcountforcircle, correctionFactor );
|
||||
break;
|
||||
|
||||
case PCB_TEXT_T:
|
||||
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
|
||||
bufferPolys, 0, segcountLowQuality, 1.0 );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
|
||||
{
|
||||
if( layer == F_SilkS || layer == B_SilkS )
|
||||
{
|
||||
// On silk screen layers, the pad shape is only the pad outline
|
||||
// never a filled shape
|
||||
D_PAD* pad = module->Pads();
|
||||
int linewidth = g_DrawDefaultLineThickness;
|
||||
|
||||
for( ; pad; pad = pad->Next() )
|
||||
{
|
||||
if( !pad->IsOnLayer( layer ) )
|
||||
continue;
|
||||
|
||||
buildPadShapeThickOutlineAsPolygon( pad, bufferPolys,
|
||||
linewidth, segcountforcircle, correctionFactor );
|
||||
}
|
||||
}
|
||||
else
|
||||
module->TransformPadsShapesWithClearanceToPolygon( layer,
|
||||
bufferPolys, 0, segcountforcircle, correctionFactor );
|
||||
|
||||
// On tech layers, use a poor circle approximation, only for texts (stroke font)
|
||||
module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
|
||||
bufferPolys, 0, segcountforcircle, correctionFactor, segcountInStrokeFont );
|
||||
}
|
||||
|
||||
// Draw non copper zones
|
||||
if( isEnabled( FL_ZONE ) )
|
||||
{
|
||||
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
|
||||
{
|
||||
ZONE_CONTAINER* zone = pcb->GetArea( ii );
|
||||
|
||||
if( !zone->IsOnLayer( layer ) )
|
||||
continue;
|
||||
|
||||
zone->TransformSolidAreasShapesToPolygonSet(
|
||||
bufferPolys, segcountLowQuality, correctionFactorLQ );
|
||||
}
|
||||
}
|
||||
|
||||
// bufferPolys contains polygons to merge. Many overlaps .
|
||||
// Calculate merged polygons and remove pads and vias holes
|
||||
if( layer != B_Mask && layer != F_Mask && bufferPolys.IsEmpty() )
|
||||
// if a layer has no iten to draw, skip it
|
||||
// However solder mask layers are negative layers, so no item
|
||||
// means only a full layer mask
|
||||
continue;
|
||||
|
||||
// Solder mask layers are "negative" layers.
|
||||
// Shapes should be removed from the full board area.
|
||||
if( layer == B_Mask || layer == F_Mask )
|
||||
{
|
||||
SHAPE_POLY_SET cuts = bufferPolys;
|
||||
bufferPolys = bufferPcbOutlines;
|
||||
|
||||
cuts.Append(allLayerHoles);
|
||||
cuts.Simplify( useFastModeForPolygons );
|
||||
|
||||
bufferPolys.BooleanSubtract( cuts, useFastModeForPolygons );
|
||||
}
|
||||
// Remove holes from Solder paste layers and silkscreen
|
||||
else if( layer == B_Paste || layer == F_Paste
|
||||
|| layer == B_SilkS || layer == F_SilkS )
|
||||
{
|
||||
bufferPolys.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
|
||||
}
|
||||
|
||||
int thickness = 0;
|
||||
|
||||
if( layer != B_Mask && layer != F_Mask )
|
||||
thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
|
||||
|
||||
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
|
||||
|
||||
if( layer == Edge_Cuts )
|
||||
{
|
||||
thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
|
||||
- GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
|
||||
zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu )
|
||||
+ (thickness / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// for Draw3D_SolidHorizontalPolyPolygons, zpos it the middle between bottom and top
|
||||
// sides.
|
||||
// However for top layers, zpos should be the bottom layer pos,
|
||||
// and for bottom layers, zpos should be the top layer pos.
|
||||
if( Get3DLayer_Z_Orientation( layer ) > 0 )
|
||||
zpos += thickness/2;
|
||||
else
|
||||
zpos -= thickness/2 ;
|
||||
}
|
||||
|
||||
|
||||
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)
|
||||
|
||||
// If we are not using thickness, then the znormal must face the layer direction
|
||||
// because it will draw just one plane
|
||||
if( !thickness )
|
||||
zNormal = Get3DLayer_Z_Orientation( layer );
|
||||
|
||||
|
||||
setGLTechLayersColor( layer );
|
||||
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos,
|
||||
thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
||||
zNormal );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,493 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_draw_helper_functions.cpp
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
|
||||
#include <PolyLine.h>
|
||||
#include <colors.h>
|
||||
#include <colors_selection.h>
|
||||
#include <class_pad.h>
|
||||
#include <class_track.h>
|
||||
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
|
||||
#include <3d_viewer.h>
|
||||
#include <3d_canvas.h>
|
||||
#include <info3d_visu.h>
|
||||
#include <3d_draw_basic_functions.h>
|
||||
|
||||
#define TEXTURE_PCB_SCALE 5.0
|
||||
|
||||
// -----------------
|
||||
// helper function (from wxWidgets, opengl/cube.cpp sample
|
||||
// -----------------
|
||||
void CheckGLError(const char *aFileName, int aLineNumber)
|
||||
{
|
||||
GLenum errLast = GL_NO_ERROR;
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
GLenum err = glGetError();
|
||||
if ( err == GL_NO_ERROR )
|
||||
return;
|
||||
|
||||
// normally the error is reset by the call to glGetError() but if
|
||||
// glGetError() itself returns an error, we risk looping forever here
|
||||
// so check that we get a different error than the last time
|
||||
if ( err == errLast )
|
||||
{
|
||||
wxLogError(wxT("OpenGL error state couldn't be reset."));
|
||||
return;
|
||||
}
|
||||
|
||||
errLast = err;
|
||||
|
||||
wxLogError( wxT( "OpenGL error %d At: %s, line: %d" ), err,
|
||||
GetChars( FROM_UTF8( aFileName ) ), aLineNumber );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
INFO3D_VISU& EDA_3D_CANVAS::GetPrm3DVisu() const
|
||||
{
|
||||
return Parent()->GetPrm3DVisu();
|
||||
}
|
||||
|
||||
wxSize EDA_3D_CANVAS::getBoardSize() const
|
||||
{
|
||||
// return the size of the board in pcb units
|
||||
return GetPrm3DVisu().m_BoardSize;
|
||||
}
|
||||
|
||||
|
||||
wxPoint EDA_3D_CANVAS::getBoardCenter() const
|
||||
{
|
||||
// return the position of the board center in pcb units
|
||||
return GetPrm3DVisu().m_BoardPos;
|
||||
}
|
||||
|
||||
// return true if we are in realistic mode render
|
||||
bool EDA_3D_CANVAS::isRealisticMode() const
|
||||
{
|
||||
return GetPrm3DVisu().IsRealisticMode();
|
||||
}
|
||||
|
||||
// return true if aItem should be displayed
|
||||
bool EDA_3D_CANVAS::isEnabled( DISPLAY3D_FLG aItem ) const
|
||||
{
|
||||
return GetPrm3DVisu().GetFlag( aItem );
|
||||
}
|
||||
|
||||
|
||||
// Helper function: initialize the copper color to draw the board
|
||||
// in realistic mode.
|
||||
void EDA_3D_CANVAS::setGLCopperColor()
|
||||
{
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
SetGLColor( GetPrm3DVisu().m_CopperColor, 1.0 );
|
||||
}
|
||||
|
||||
// Helper function: initialize the color to draw the epoxy
|
||||
// body board in realistic mode.
|
||||
void EDA_3D_CANVAS::setGLEpoxyColor( float aTransparency )
|
||||
{
|
||||
// Generates an epoxy color, near board color
|
||||
SetGLColor( GetPrm3DVisu().m_BoardBodyColor, aTransparency );
|
||||
|
||||
if( isEnabled( FL_RENDER_TEXTURES ) )
|
||||
{
|
||||
SetGLTexture( m_text_pcb, TEXTURE_PCB_SCALE );
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function: initialize the color to draw the
|
||||
// solder mask layers in realistic mode.
|
||||
void EDA_3D_CANVAS::setGLSolderMaskColor( float aTransparency )
|
||||
{
|
||||
// Generates a solder mask color
|
||||
SetGLColor( GetPrm3DVisu().m_SolderMaskColor, aTransparency );
|
||||
|
||||
if( isEnabled( FL_RENDER_TEXTURES ) )
|
||||
{
|
||||
SetGLTexture( m_text_pcb, TEXTURE_PCB_SCALE );
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function: initialize the color to draw the non copper layers
|
||||
// in realistic mode and normal mode.
|
||||
void EDA_3D_CANVAS::setGLTechLayersColor( LAYER_NUM aLayer )
|
||||
{
|
||||
EDA_COLOR_T color;
|
||||
|
||||
if( isRealisticMode() )
|
||||
{
|
||||
switch( aLayer )
|
||||
{
|
||||
case B_Paste:
|
||||
case F_Paste:
|
||||
SetGLColor( GetPrm3DVisu().m_SolderPasteColor, 1 );
|
||||
break;
|
||||
|
||||
case B_SilkS:
|
||||
case F_SilkS:
|
||||
SetGLColor( GetPrm3DVisu().m_SilkScreenColor, 0.96 );
|
||||
|
||||
if( isEnabled( FL_RENDER_TEXTURES ) )
|
||||
{
|
||||
SetGLTexture( m_text_silk, 10.0f );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case B_Mask:
|
||||
case F_Mask:
|
||||
setGLSolderMaskColor( 0.90 );
|
||||
break;
|
||||
|
||||
default:
|
||||
color = g_ColorsSettings.GetLayerColor( aLayer );
|
||||
SetGLColor( color, 0.7 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = g_ColorsSettings.GetLayerColor( aLayer );
|
||||
SetGLColor( color, 0.7 );
|
||||
}
|
||||
}
|
||||
|
||||
void EDA_3D_CANVAS::draw3DAxis()
|
||||
{
|
||||
if( ! m_glLists[GL_ID_AXIS] )
|
||||
{
|
||||
m_glLists[GL_ID_AXIS] = glGenLists( 1 );
|
||||
glNewList( m_glLists[GL_ID_AXIS], GL_COMPILE );
|
||||
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
glBegin( GL_LINES );
|
||||
SetGLColor( RED );
|
||||
glNormal3f( 0.0f, 0.0f, 1.0f ); // Normal is Z axis
|
||||
glVertex3f( 0.0f, 0.0f, 0.0f );
|
||||
glVertex3f( -10.0f, 0.0f, 0.0f );
|
||||
glVertex3f( 0.0f, 0.0f, 0.0f );
|
||||
glVertex3f( 10.0f, 0.0f, 0.0f ); // X axis
|
||||
SetGLColor( GREEN );
|
||||
glVertex3f( 0.0f, 0.0f, 0.0f );
|
||||
glVertex3f( 0.0f, -10.0f, 0.0f ); // Y axis
|
||||
glVertex3f( 0.0f, 0.0f, 0.0f );
|
||||
glVertex3f( 0.0f, 10.0f, 0.0f );
|
||||
SetGLColor( BLUE );
|
||||
glNormal3f( 1.0f, 0.0f, 0.0f ); // Normal is Y axis
|
||||
glVertex3f( 0.0f, 0.0f, 0.0f );
|
||||
glVertex3f( 0.0f, 0.0f, -10.0f );
|
||||
glVertex3f( 0.0f, 0.0f, 0.0f );
|
||||
glVertex3f( 0.0f, 0.0f, 10.0f ); // Z axis
|
||||
glEnd();
|
||||
|
||||
glEndList();
|
||||
}
|
||||
}
|
||||
|
||||
// draw a 3D grid: an horizontal grid (XY plane and Z = 0,
|
||||
// and a vertical grid (XZ plane and Y = 0)
|
||||
void EDA_3D_CANVAS::draw3DGrid( double aGriSizeMM )
|
||||
{
|
||||
double zpos = 0.0;
|
||||
EDA_COLOR_T gridcolor = DARKGRAY; // Color of grid lines
|
||||
EDA_COLOR_T gridcolor_marker = LIGHTGRAY; // Color of grid lines every 5 lines
|
||||
const double scale = GetPrm3DVisu().m_BiuTo3Dunits;
|
||||
const double transparency = 0.3;
|
||||
|
||||
glNormal3f( 0.0, 0.0, 1.0 );
|
||||
|
||||
wxSize brd_size = getBoardSize();
|
||||
wxPoint brd_center_pos = getBoardCenter();
|
||||
brd_center_pos.y = -brd_center_pos.y;
|
||||
|
||||
int xsize = std::max( brd_size.x, Millimeter2iu( 100 ) ) * 1.2;
|
||||
int ysize = std::max( brd_size.y, Millimeter2iu( 100 ) ) * 1.2;
|
||||
|
||||
// Grid limits, in 3D units
|
||||
double xmin = (brd_center_pos.x - xsize / 2) * scale;
|
||||
double xmax = (brd_center_pos.x + xsize / 2) * scale;
|
||||
double ymin = (brd_center_pos.y - ysize / 2) * scale;
|
||||
double ymax = (brd_center_pos.y + ysize / 2) * scale;
|
||||
double zmin = Millimeter2iu( -50 ) * scale;
|
||||
double zmax = Millimeter2iu( 100 ) * scale;
|
||||
|
||||
// Draw horizontal grid centered on 3D origin (center of the board)
|
||||
for( int ii = 0; ; ii++ )
|
||||
{
|
||||
if( (ii % 5) )
|
||||
SetGLColor( gridcolor, transparency );
|
||||
else
|
||||
SetGLColor( gridcolor_marker, transparency );
|
||||
|
||||
int delta = KiROUND( ii * aGriSizeMM * IU_PER_MM );
|
||||
|
||||
if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
|
||||
{
|
||||
glBegin( GL_LINES );
|
||||
glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
|
||||
glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
|
||||
glEnd();
|
||||
|
||||
if( ii != 0 )
|
||||
{
|
||||
glBegin( GL_LINES );
|
||||
glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
|
||||
glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
|
||||
{
|
||||
glBegin( GL_LINES );
|
||||
glVertex3f( xmin, -(brd_center_pos.y + delta) * scale, zpos );
|
||||
glVertex3f( xmax, -(brd_center_pos.y + delta) * scale, zpos );
|
||||
glEnd();
|
||||
|
||||
if( ii != 0 )
|
||||
{
|
||||
glBegin( GL_LINES );
|
||||
glVertex3f( xmin, -(brd_center_pos.y - delta) * scale, zpos );
|
||||
glVertex3f( xmax, -(brd_center_pos.y - delta) * scale, zpos );
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw vertical grid on Z axis
|
||||
glNormal3f( 0.0, -1.0, 0.0 );
|
||||
|
||||
// Draw vertical grid lines (parallel to Z axis)
|
||||
double posy = -brd_center_pos.y * scale;
|
||||
|
||||
for( int ii = 0; ; ii++ )
|
||||
{
|
||||
if( (ii % 5) )
|
||||
SetGLColor( gridcolor, transparency );
|
||||
else
|
||||
SetGLColor( gridcolor_marker, transparency );
|
||||
|
||||
double delta = ii * aGriSizeMM * IU_PER_MM;
|
||||
|
||||
glBegin( GL_LINES );
|
||||
xmax = (brd_center_pos.x + delta) * scale;
|
||||
|
||||
glVertex3f( xmax, posy, zmin );
|
||||
glVertex3f( xmax, posy, zmax );
|
||||
glEnd();
|
||||
|
||||
if( ii != 0 )
|
||||
{
|
||||
glBegin( GL_LINES );
|
||||
xmin = (brd_center_pos.x - delta) * scale;
|
||||
glVertex3f( xmin, posy, zmin );
|
||||
glVertex3f( xmin, posy, zmax );
|
||||
glEnd();
|
||||
}
|
||||
|
||||
if( delta > xsize / 2.0f )
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw horizontal grid lines on Z axis (parallel to X axis)
|
||||
for( int ii = 0; ; ii++ )
|
||||
{
|
||||
if( (ii % 5) )
|
||||
SetGLColor( gridcolor, transparency);
|
||||
else
|
||||
SetGLColor( gridcolor_marker, transparency );
|
||||
|
||||
double delta = ii * aGriSizeMM * IU_PER_MM * scale;
|
||||
|
||||
if( delta <= zmax )
|
||||
{
|
||||
// Draw grid lines on Z axis (positive Z axis coordinates)
|
||||
glBegin( GL_LINES );
|
||||
glVertex3f( xmin, posy, delta );
|
||||
glVertex3f( xmax, posy, delta );
|
||||
glEnd();
|
||||
}
|
||||
|
||||
if( delta <= -zmin && ( ii != 0 ) )
|
||||
{
|
||||
// Draw grid lines on Z axis (negative Z axis coordinates)
|
||||
glBegin( GL_LINES );
|
||||
glVertex3f( xmin, posy, -delta );
|
||||
glVertex3f( xmax, posy, -delta );
|
||||
glEnd();
|
||||
}
|
||||
|
||||
if( ( delta > zmax ) && ( delta > -zmin ) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Draw 3D pads.
|
||||
void EDA_3D_CANVAS::draw3DPadHole( const D_PAD* aPad )
|
||||
{
|
||||
// Draw the pad hole
|
||||
wxSize drillsize = aPad->GetDrillSize();
|
||||
bool hasHole = drillsize.x && drillsize.y;
|
||||
|
||||
if( !hasHole )
|
||||
return;
|
||||
|
||||
// Store here the points to approximate hole by segments
|
||||
SHAPE_POLY_SET holecornersBuffer;
|
||||
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
||||
int height = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu ) -
|
||||
GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
|
||||
|
||||
if( isRealisticMode() )
|
||||
setGLCopperColor();
|
||||
else
|
||||
SetGLColor( DARKGRAY );
|
||||
|
||||
int holeZpoz = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu ) - thickness / 2;
|
||||
int holeHeight = height + thickness;
|
||||
|
||||
if( drillsize.x == drillsize.y ) // usual round hole
|
||||
{
|
||||
int hole_radius = ( drillsize.x + thickness ) / 2;
|
||||
Draw3D_ZaxisCylinder( aPad->GetPosition(),
|
||||
hole_radius, holeHeight,
|
||||
thickness, holeZpoz, GetPrm3DVisu().m_BiuTo3Dunits );
|
||||
}
|
||||
else // Oblong hole
|
||||
{
|
||||
wxPoint ends_offset;
|
||||
int width;
|
||||
|
||||
if( drillsize.x > drillsize.y ) // Horizontal oval
|
||||
{
|
||||
ends_offset.x = ( drillsize.x - drillsize.y ) / 2;
|
||||
width = drillsize.y;
|
||||
}
|
||||
else // Vertical oval
|
||||
{
|
||||
ends_offset.y = ( drillsize.y - drillsize.x ) / 2;
|
||||
width = drillsize.x;
|
||||
}
|
||||
|
||||
RotatePoint( &ends_offset, aPad->GetOrientation() );
|
||||
|
||||
wxPoint start = aPad->GetPosition() + ends_offset;
|
||||
wxPoint end = aPad->GetPosition() - ends_offset;
|
||||
int hole_radius = ( width + thickness ) / 2;
|
||||
|
||||
// Draw the hole
|
||||
Draw3D_ZaxisOblongCylinder( start, end, hole_radius, holeHeight,
|
||||
thickness, holeZpoz, GetPrm3DVisu().m_BiuTo3Dunits );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::draw3DViaHole( const VIA* aVia )
|
||||
{
|
||||
LAYER_ID top_layer, bottom_layer;
|
||||
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
||||
int inner_radius = (int)((float)aVia->GetDrillValue() * 1.01f) / 2.0f; // This add a bit more in order to correct a draw artifact while using tickness
|
||||
|
||||
aVia->LayerPair( &top_layer, &bottom_layer );
|
||||
|
||||
// Drawing via hole:
|
||||
if( isRealisticMode() )
|
||||
setGLCopperColor();
|
||||
else
|
||||
{
|
||||
EDA_COLOR_T color = g_ColorsSettings.GetItemColor( VIAS_VISIBLE + aVia->GetViaType() );
|
||||
SetGLColor( color );
|
||||
}
|
||||
|
||||
int height = GetPrm3DVisu().GetLayerZcoordBIU( top_layer ) -
|
||||
GetPrm3DVisu().GetLayerZcoordBIU( bottom_layer ) + thickness;
|
||||
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( bottom_layer ) - thickness / 2;
|
||||
|
||||
Draw3D_ZaxisCylinder( aVia->GetStart(), inner_radius, height,
|
||||
thickness, zpos, GetPrm3DVisu().m_BiuTo3Dunits );
|
||||
}
|
||||
|
||||
/* Build a pad outline as non filled polygon, to draw pads on silkscreen layer
|
||||
* Used only to draw pads outlines on silkscreen layers.
|
||||
*/
|
||||
void EDA_3D_CANVAS::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
|
||||
SHAPE_POLY_SET& aCornerBuffer,
|
||||
int aWidth,
|
||||
int aCircleToSegmentsCount,
|
||||
double aCorrectionFactor )
|
||||
{
|
||||
if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring
|
||||
{
|
||||
TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(),
|
||||
aPad->GetSize().x / 2, aCircleToSegmentsCount, aWidth );
|
||||
return;
|
||||
}
|
||||
|
||||
// For other shapes, draw polygon outlines
|
||||
SHAPE_POLY_SET corners;
|
||||
aPad->BuildPadShapePolygon( corners, wxSize( 0, 0 ),
|
||||
aCircleToSegmentsCount, aCorrectionFactor );
|
||||
|
||||
// Add outlines as thick segments in polygon buffer
|
||||
|
||||
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
|
||||
|
||||
for( int ii = 0; ii < path.PointCount(); ii++ )
|
||||
{
|
||||
const VECTOR2I& a = path.CPoint( ii );
|
||||
const VECTOR2I& b = path.CPoint( ii + 1 );
|
||||
|
||||
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
|
||||
wxPoint( a.x, a.y ),
|
||||
wxPoint( b.x, b.y ),
|
||||
aCircleToSegmentsCount, aWidth );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer )
|
||||
{
|
||||
double nZ = 1.0;
|
||||
|
||||
if( ( aLayer == B_Cu )
|
||||
|| ( aLayer == B_Adhes )
|
||||
|| ( aLayer == B_Paste )
|
||||
|| ( aLayer == B_SilkS )
|
||||
|| ( aLayer == B_Mask ) )
|
||||
nZ = -1.0;
|
||||
|
||||
return nZ;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_fastmath.cpp
|
||||
* @brief
|
||||
*/
|
||||
|
||||
|
||||
#include "3d_fastmath.h"
|
||||
|
||||
|
||||
// Fast Float Random Numbers
|
||||
// a small and fast implementation for random float numbers in the range [-1,1]
|
||||
// References : Posted by dominik.ries[AT]gmail[DOT]com
|
||||
// http://www.musicdsp.org/showone.php?id=273
|
||||
|
||||
|
||||
// set the initial seed to whatever you like
|
||||
static int s_randSeed = 1;
|
||||
|
||||
// fast rand float, using full 32bit precision
|
||||
// returns in the range [-1, 1] (not confirmed)
|
||||
float Fast_RandFloat()
|
||||
{
|
||||
s_randSeed *= 16807;
|
||||
|
||||
return (float)s_randSeed * 4.6566129e-010f;
|
||||
}
|
||||
|
||||
|
||||
// Fast rand, as described here:
|
||||
// http://wiki.osdev.org/Random_Number_Generator
|
||||
|
||||
static unsigned long int s_nextRandSeed = 1;
|
||||
|
||||
int Fast_rand( void ) // RAND_MAX assumed to be 32767
|
||||
{
|
||||
s_nextRandSeed = s_nextRandSeed * 1103515245 + 12345;
|
||||
|
||||
return (unsigned int)(s_nextRandSeed >> 16) & 0x7FFF;
|
||||
}
|
||||
|
||||
void Fast_srand( unsigned int seed )
|
||||
{
|
||||
s_nextRandSeed = seed;
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_fastmath.h
|
||||
* @brief Defines math related functions
|
||||
*/
|
||||
|
||||
#ifndef _3D_FASTMATH_H
|
||||
#define _3D_FASTMATH_H
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
// Define this flag to use fast math optimizations
|
||||
#define FASTMATH_USE
|
||||
|
||||
#define L1_CACHE_LINE_SIZE 64
|
||||
|
||||
#ifdef FASTMATH_USE
|
||||
#define INTFLOORF(s) (lrintf( (s) - (0.5f - FLT_EPSILON) ))
|
||||
#else
|
||||
#define INTFLOORF(s) ((int)( floor(s) ))
|
||||
#endif
|
||||
|
||||
|
||||
// Fast Float Random Numbers
|
||||
// a small and fast implementation for random float numbers in the range [-1,1]
|
||||
// This is not thread safe
|
||||
float Fast_RandFloat();
|
||||
|
||||
int Fast_rand( void );
|
||||
void Fast_srand( unsigned int seed );
|
||||
|
||||
/**
|
||||
* This part contains some functions from the PBRT 3 source code.
|
||||
* https://github.com/mmp/pbrt-v3/blob/master/src/core/pbrt.h
|
||||
*/
|
||||
|
||||
/*
|
||||
pbrt source code is Copyright(c) 1998-2015
|
||||
Matt Pharr, Greg Humphreys, and Wenzel Jakob.
|
||||
|
||||
This file is part of pbrt.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// Global Inline Functions
|
||||
inline uint32_t FloatToBits( float f )
|
||||
{
|
||||
uint32_t ui;
|
||||
|
||||
memcpy( &ui, &f, sizeof( float ) );
|
||||
|
||||
return ui;
|
||||
}
|
||||
|
||||
|
||||
inline float BitsToFloat( uint32_t ui )
|
||||
{
|
||||
float f;
|
||||
|
||||
memcpy( &f, &ui, sizeof (uint32_t ) );
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
inline uint64_t FloatToBits( double f )
|
||||
{
|
||||
uint64_t ui;
|
||||
|
||||
memcpy( &ui, &f, sizeof( double ) );
|
||||
|
||||
return ui;
|
||||
}
|
||||
|
||||
|
||||
inline double BitsToFloat( uint64_t ui )
|
||||
{
|
||||
double f;
|
||||
|
||||
memcpy( &f, &ui, sizeof( uint64_t ) );
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
inline float NextFloatUp( float v )
|
||||
{
|
||||
// Handle infinity and negative zero for _NextFloatUp()_
|
||||
if( std::isinf( v ) && (v > 0.) )
|
||||
return v;
|
||||
|
||||
if( v == -0.f )
|
||||
v = 0.f;
|
||||
|
||||
// Advance _v_ to next higher float
|
||||
uint32_t ui = FloatToBits( v );
|
||||
|
||||
if( v >= 0. )
|
||||
++ui;
|
||||
else
|
||||
--ui;
|
||||
|
||||
return BitsToFloat( ui );
|
||||
}
|
||||
|
||||
|
||||
inline float NextFloatDown( float v )
|
||||
{
|
||||
// Handle infinity and positive zero for _NextFloatDown()_
|
||||
if( std::isinf( v ) && (v < 0.) )
|
||||
return v;
|
||||
|
||||
if( v == 0.f )
|
||||
v = -0.f;
|
||||
|
||||
uint32_t ui = FloatToBits( v );
|
||||
|
||||
if( v > 0. )
|
||||
--ui;
|
||||
else
|
||||
++ui;
|
||||
|
||||
return BitsToFloat( ui );
|
||||
}
|
||||
|
||||
#endif // 3D_FASTMATH_H
|
||||
@@ -0,0 +1,915 @@
|
||||
/**
|
||||
* @file 3d_frame.cpp
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <kiface_i.h>
|
||||
#include <pgm_base.h>
|
||||
#include <macros.h>
|
||||
|
||||
#include <3d_viewer.h>
|
||||
#include <3d_canvas.h>
|
||||
#include <info3d_visu.h>
|
||||
#include <trackball.h>
|
||||
|
||||
#include <wx/colordlg.h>
|
||||
#include <3d_viewer_id.h>
|
||||
#include <wxBasePcbFrame.h>
|
||||
|
||||
INFO3D_VISU g_Parm_3D_Visu;
|
||||
|
||||
// Key to store 3D Viewer config:
|
||||
static const wxChar keyBgColor_Red[] = wxT( "BgColor_Red" );
|
||||
static const wxChar keyBgColor_Green[] = wxT( "BgColor_Green" );
|
||||
static const wxChar keyBgColor_Blue[] = wxT( "BgColor_Blue" );
|
||||
|
||||
static const wxChar keyBgColor_Red_Top[] = wxT( "BgColor_Red_Top" );
|
||||
static const wxChar keyBgColor_Green_Top[] = wxT( "BgColor_Green_Top" );
|
||||
static const wxChar keyBgColor_Blue_Top[] = wxT( "BgColor_Blue_Top" );
|
||||
|
||||
static const wxChar keySMaskColor_Red[] = wxT( "SMaskColor_Red" );
|
||||
static const wxChar keySMaskColor_Green[] = wxT( "SMaskColor_Green" );
|
||||
static const wxChar keySMaskColor_Blue[] = wxT( "SMaskColor_Blue" );
|
||||
|
||||
static const wxChar keySPasteColor_Red[] = wxT( "SPasteColor_Red" );
|
||||
static const wxChar keySPasteColor_Green[] = wxT( "SPasteColor_Green" );
|
||||
static const wxChar keySPasteColor_Blue[] = wxT( "SPasteColor_Blue" );
|
||||
|
||||
static const wxChar keySilkColor_Red[] = wxT( "SilkColor_Red" );
|
||||
static const wxChar keySilkColor_Green[] = wxT( "SilkColor_Green" );
|
||||
static const wxChar keySilkColor_Blue[] = wxT( "SilkColor_Blue" );
|
||||
|
||||
static const wxChar keyCopperColor_Red[] = wxT( "CopperColor_Red" );
|
||||
static const wxChar keyCopperColor_Green[] = wxT( "CopperColor_Green" );
|
||||
static const wxChar keyCopperColor_Blue[] = wxT( "CopperColor_Blue" );
|
||||
|
||||
static const wxChar keyBoardBodyColor_Red[] = wxT( "BoardBodyColor_Red" );
|
||||
static const wxChar keyBoardBodyColor_Green[] = wxT( "BoardBodyColor_Green" );
|
||||
static const wxChar keyBoardBodyColor_Blue[]= wxT( "BoardBodyColor_Blue" );
|
||||
|
||||
static const wxChar keyMousewheelPanning[] = wxT( "MousewheelPAN3D" );
|
||||
|
||||
static const wxChar keyShowRealisticMode[] = wxT( "ShowRealisticMode" );
|
||||
static const wxChar keyRenderShadows[] = wxT( "Render_Shadows" );
|
||||
static const wxChar keyRenderRemoveHoles[] = wxT( "Render_RemoveHoles" );
|
||||
static const wxChar keyRenderTextures[] = wxT( "Render_Textures" );
|
||||
static const wxChar keyRenderSmoothNormals[] = wxT( "Render_Smooth_Normals" );
|
||||
static const wxChar keyRenderUseModelNormals[] =wxT( "Render_Use_Model_Normals" );
|
||||
static const wxChar keyRenderMaterial[] = wxT( "Render_Material" );
|
||||
static const wxChar keyRenderShowModelBBox[] = wxT( "Render_ShowModelBoudingBoxes" );
|
||||
|
||||
static const wxChar keyShowAxis[] = wxT( "ShowAxis" );
|
||||
static const wxChar keyShowGrid[] = wxT( "ShowGrid3D" );
|
||||
static const wxChar keyShowGridSize[] = wxT( "Grid3DSize" );
|
||||
static const wxChar keyShowZones[] = wxT( "ShowZones" );
|
||||
static const wxChar keyShowFootprints[] = wxT( "ShowFootprints" );
|
||||
static const wxChar keyShowCopperThickness[] = wxT( "ShowCopperThickness" );
|
||||
static const wxChar keyShowAdhesiveLayers[] = wxT( "ShowAdhesiveLayers" );
|
||||
static const wxChar keyShowSilkScreenLayers[] = wxT( "ShowSilkScreenLayers" );
|
||||
static const wxChar keyShowSolderMaskLayers[] = wxT( "ShowSolderMasLayers" );
|
||||
static const wxChar keyShowSolderPasteLayers[] =wxT( "ShowSolderPasteLayers" );
|
||||
static const wxChar keyShowCommentsLayer[] = wxT( "ShowCommentsLayers" );
|
||||
static const wxChar keyShowBoardBody[] = wxT( "ShowBoardBody" );
|
||||
static const wxChar keyShowEcoLayers[] = wxT( "ShowEcoLayers" );
|
||||
|
||||
|
||||
BEGIN_EVENT_TABLE( EDA_3D_FRAME, EDA_BASE_FRAME )
|
||||
EVT_ACTIVATE( EDA_3D_FRAME::OnActivate )
|
||||
|
||||
EVT_TOOL_RANGE( ID_ZOOM_IN, ID_ZOOM_PAGE, EDA_3D_FRAME::Process_Zoom )
|
||||
EVT_TOOL_RANGE( ID_START_COMMAND_3D, ID_END_COMMAND_3D,
|
||||
EDA_3D_FRAME::Process_Special_Functions )
|
||||
EVT_TOOL( ID_TOOL_SET_VISIBLE_ITEMS, EDA_3D_FRAME::Process_Special_Functions )
|
||||
EVT_MENU( wxID_EXIT, EDA_3D_FRAME::Exit3DFrame )
|
||||
EVT_MENU( ID_MENU_SCREENCOPY_PNG, EDA_3D_FRAME::Process_Special_Functions )
|
||||
EVT_MENU( ID_MENU_SCREENCOPY_JPEG, EDA_3D_FRAME::Process_Special_Functions )
|
||||
|
||||
EVT_MENU_RANGE( ID_MENU3D_GRID, ID_MENU3D_GRID_END,
|
||||
EDA_3D_FRAME::On3DGridSelection )
|
||||
|
||||
EVT_CLOSE( EDA_3D_FRAME::OnCloseWindow )
|
||||
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
EDA_3D_FRAME::EDA_3D_FRAME( KIWAY* aKiway, PCB_BASE_FRAME* aParent,
|
||||
const wxString& aTitle, long style ) :
|
||||
KIWAY_PLAYER( aKiway, aParent, FRAME_PCB_DISPLAY3D, aTitle,
|
||||
wxDefaultPosition, wxDefaultSize, style, wxT( "Frame3D" ) )
|
||||
{
|
||||
m_canvas = NULL;
|
||||
m_reloadRequest = false;
|
||||
m_ortho = false;
|
||||
|
||||
// Give it an icon
|
||||
wxIcon icon;
|
||||
icon.CopyFromBitmap( KiBitmap( icon_3d_xpm ) );
|
||||
SetIcon( icon );
|
||||
|
||||
LoadSettings( config() );
|
||||
SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y );
|
||||
|
||||
// Create the status line
|
||||
static const int status_dims[4] = { -1, 130, 130, 170 };
|
||||
|
||||
CreateStatusBar( DIM( status_dims ) );
|
||||
SetStatusWidths( DIM( status_dims ), status_dims );
|
||||
|
||||
CreateMenuBar();
|
||||
ReCreateMainToolbar();
|
||||
|
||||
// Make a EDA_3D_CANVAS
|
||||
// Note: We try to use anti aliasing if the graphic card allows that,
|
||||
// but only on wxWidgets >= 3.0.0 (this option does not exist on wxWidgets 2.8)
|
||||
int attrs[] = { // This array should be 2*n+1
|
||||
// Sadly wxwidgets / glx < 13 allowed
|
||||
// a thing named "boolean attributes" that don't take a value.
|
||||
// (See src/unix/glx11.cpp -> wxGLCanvasX11::ConvertWXAttrsToGL() ).
|
||||
// To avoid problems due to this, just specify those attributes twice.
|
||||
// Only WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_STEREO are such boolean
|
||||
// attributes.
|
||||
|
||||
// Boolean attributes (using itself at padding):
|
||||
WX_GL_RGBA, WX_GL_RGBA,
|
||||
WX_GL_DOUBLEBUFFER, WX_GL_DOUBLEBUFFER,
|
||||
|
||||
// Normal attributes with values:
|
||||
WX_GL_DEPTH_SIZE, 16,
|
||||
WX_GL_STENCIL_SIZE, 1,
|
||||
WX_GL_SAMPLE_BUFFERS, 1, // Enable multisampling support (antialiasing).
|
||||
WX_GL_SAMPLES, 0, // Disable AA for the start.
|
||||
0 }; // NULL termination
|
||||
|
||||
|
||||
// Check if the canvas supports multisampling.
|
||||
if( EDA_3D_CANVAS::IsDisplaySupported( attrs ) )
|
||||
{
|
||||
// Check for possible sample sizes, start form the top.
|
||||
int maxSamples = 8; // Any higher doesn't change anything.
|
||||
int samplesOffset = 0;
|
||||
|
||||
for( unsigned int ii = 0; ii < DIM( attrs ); ii += 2 )
|
||||
{
|
||||
if( attrs[ii] == WX_GL_SAMPLES )
|
||||
{
|
||||
samplesOffset = ii+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
attrs[samplesOffset] = maxSamples;
|
||||
|
||||
for( ; maxSamples > 0 && !EDA_3D_CANVAS::IsDisplaySupported( attrs );
|
||||
maxSamples = maxSamples>>1 )
|
||||
{
|
||||
attrs[samplesOffset] = maxSamples;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable multisampling
|
||||
for( unsigned int ii = 0; ii < DIM( attrs ); ii += 2 )
|
||||
{
|
||||
if( attrs[ii] == WX_GL_SAMPLE_BUFFERS )
|
||||
{
|
||||
attrs[ii+1] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_canvas = new EDA_3D_CANVAS( this, attrs );
|
||||
|
||||
m_auimgr.SetManagedWindow( this );
|
||||
|
||||
|
||||
EDA_PANEINFO horiztb;
|
||||
horiztb.HorizontalToolbarPane();
|
||||
|
||||
m_auimgr.AddPane( m_mainToolBar,
|
||||
wxAuiPaneInfo( horiztb ).Name( wxT( "m_mainToolBar" ) ).Top() );
|
||||
|
||||
m_auimgr.AddPane( m_canvas,
|
||||
wxAuiPaneInfo().Name( wxT( "DrawFrame" ) ).CentrePane() );
|
||||
|
||||
m_auimgr.Update();
|
||||
|
||||
// Fixes bug in Windows (XP and possibly others) where the canvas requires the focus
|
||||
// in order to receive mouse events. Otherwise, the user has to click somewhere on
|
||||
// the canvas before it will respond to mouse wheel events.
|
||||
m_canvas->SetFocus();
|
||||
}
|
||||
|
||||
|
||||
EDA_3D_FRAME::~EDA_3D_FRAME()
|
||||
{
|
||||
m_auimgr.UnInit();
|
||||
}
|
||||
|
||||
void EDA_3D_FRAME::Exit3DFrame( wxCommandEvent& event )
|
||||
{
|
||||
Close( true );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::OnCloseWindow( wxCloseEvent& Event )
|
||||
{
|
||||
if( Parent() )
|
||||
Parent()->m_Draw3DFrame = NULL;
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::LoadSettings( wxConfigBase* aCfg )
|
||||
{
|
||||
EDA_BASE_FRAME::LoadSettings( aCfg );
|
||||
|
||||
INFO3D_VISU& prms = GetPrm3DVisu();
|
||||
|
||||
aCfg->Read( keyBgColor_Red, &GetPrm3DVisu().m_BgColor.m_Red, 0.4 );
|
||||
aCfg->Read( keyBgColor_Green, &GetPrm3DVisu().m_BgColor.m_Green, 0.4 );
|
||||
aCfg->Read( keyBgColor_Blue, &GetPrm3DVisu().m_BgColor.m_Blue, 0.5 );
|
||||
|
||||
aCfg->Read( keyBgColor_Red_Top, &GetPrm3DVisu().m_BgColor_Top.m_Red, 0.8 );
|
||||
aCfg->Read( keyBgColor_Green_Top, &GetPrm3DVisu().m_BgColor_Top.m_Green, 0.8 );
|
||||
aCfg->Read( keyBgColor_Blue_Top, &GetPrm3DVisu().m_BgColor_Top.m_Blue, 0.9 );
|
||||
|
||||
// m_SolderMaskColor default value = dark grey-green
|
||||
aCfg->Read( keySMaskColor_Red, &GetPrm3DVisu().m_SolderMaskColor.m_Red, 100.0 * 0.2 / 255.0 );
|
||||
aCfg->Read( keySMaskColor_Green, &GetPrm3DVisu().m_SolderMaskColor.m_Green, 255.0 * 0.2 / 255.0 );
|
||||
aCfg->Read( keySMaskColor_Blue, &GetPrm3DVisu().m_SolderMaskColor.m_Blue, 180.0 * 0.2 / 255.0 );
|
||||
|
||||
// m_SolderPasteColor default value = light grey
|
||||
aCfg->Read( keySPasteColor_Red, &GetPrm3DVisu().m_SolderPasteColor.m_Red, 128.0 /255.0 );
|
||||
aCfg->Read( keySPasteColor_Green, &GetPrm3DVisu().m_SolderPasteColor.m_Green, 128.0 /255.0 );
|
||||
aCfg->Read( keySPasteColor_Blue, &GetPrm3DVisu().m_SolderPasteColor.m_Blue, 128.0 /255.0 );
|
||||
|
||||
// m_SilkScreenColor default value = white
|
||||
aCfg->Read( keySilkColor_Red, &GetPrm3DVisu().m_SilkScreenColor.m_Red, 0.9 );
|
||||
aCfg->Read( keySilkColor_Green, &GetPrm3DVisu().m_SilkScreenColor.m_Green, 0.9 );
|
||||
aCfg->Read( keySilkColor_Blue, &GetPrm3DVisu().m_SilkScreenColor.m_Blue, 0.9 );
|
||||
|
||||
// m_CopperColor default value = gold
|
||||
aCfg->Read( keyCopperColor_Red, &GetPrm3DVisu().m_CopperColor.m_Red, 255.0 * 0.7 / 255.0 );
|
||||
aCfg->Read( keyCopperColor_Green, &GetPrm3DVisu().m_CopperColor.m_Green, 223.0 * 0.7 / 255.0 );
|
||||
aCfg->Read( keyCopperColor_Blue, &GetPrm3DVisu().m_CopperColor.m_Blue, 0.0 /255.0 );
|
||||
|
||||
// m_BoardBodyColor default value = FR4, in realistic mode
|
||||
aCfg->Read( keyBoardBodyColor_Red, &GetPrm3DVisu().m_BoardBodyColor.m_Red, 51.0 / 255.0 );
|
||||
aCfg->Read( keyBoardBodyColor_Green, &GetPrm3DVisu().m_BoardBodyColor.m_Green, 43.0 / 255.0 );
|
||||
aCfg->Read( keyBoardBodyColor_Blue, &GetPrm3DVisu().m_BoardBodyColor.m_Blue, 22.0 /255.0 );
|
||||
|
||||
bool tmp;
|
||||
aCfg->Read( keyMousewheelPanning, &tmp, false );
|
||||
prms.SetFlag( FL_MOUSEWHEEL_PANNING, tmp );
|
||||
|
||||
aCfg->Read( keyShowRealisticMode, &tmp, false );
|
||||
prms.SetFlag( FL_USE_REALISTIC_MODE, tmp );
|
||||
|
||||
aCfg->Read( keyRenderShadows, &tmp, false );
|
||||
prms.SetFlag( FL_RENDER_SHADOWS, tmp );
|
||||
|
||||
aCfg->Read( keyRenderRemoveHoles, &tmp, false );
|
||||
prms.SetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES, tmp );
|
||||
|
||||
aCfg->Read( keyRenderTextures, &tmp, false );
|
||||
prms.SetFlag( FL_RENDER_TEXTURES, tmp );
|
||||
|
||||
aCfg->Read( keyRenderSmoothNormals, &tmp, false );
|
||||
prms.SetFlag( FL_RENDER_SMOOTH_NORMALS, tmp );
|
||||
|
||||
aCfg->Read( keyRenderUseModelNormals, &tmp, false );
|
||||
prms.SetFlag( FL_RENDER_USE_MODEL_NORMALS, tmp );
|
||||
|
||||
aCfg->Read( keyRenderMaterial, &tmp, false );
|
||||
prms.SetFlag( FL_RENDER_MATERIAL, tmp );
|
||||
|
||||
aCfg->Read( keyRenderShowModelBBox, &tmp, false );
|
||||
prms.SetFlag( FL_RENDER_SHOW_MODEL_BBOX, tmp );
|
||||
|
||||
aCfg->Read( keyShowAxis, &tmp, true );
|
||||
prms.SetFlag( FL_AXIS, tmp );
|
||||
|
||||
aCfg->Read( keyShowGrid, &tmp, true );
|
||||
prms.SetFlag( FL_GRID, tmp );
|
||||
|
||||
aCfg->Read( keyShowGridSize, &prms.m_3D_Grid, 10.0 );
|
||||
|
||||
aCfg->Read( keyShowFootprints, &tmp, true );
|
||||
prms.SetFlag( FL_MODULE, tmp );
|
||||
|
||||
aCfg->Read( keyShowCopperThickness, &tmp, false );
|
||||
prms.SetFlag( FL_USE_COPPER_THICKNESS, tmp );
|
||||
|
||||
aCfg->Read( keyShowZones, &tmp, true );
|
||||
prms.SetFlag( FL_ZONE, tmp );
|
||||
|
||||
aCfg->Read( keyShowAdhesiveLayers, &tmp, true );
|
||||
prms.SetFlag( FL_ADHESIVE, tmp );
|
||||
|
||||
aCfg->Read( keyShowSilkScreenLayers, &tmp, true );
|
||||
prms.SetFlag( FL_SILKSCREEN, tmp );
|
||||
|
||||
aCfg->Read( keyShowSolderMaskLayers, &tmp, true );
|
||||
prms.SetFlag( FL_SOLDERMASK, tmp );
|
||||
|
||||
aCfg->Read( keyShowSolderPasteLayers, &tmp, true );
|
||||
prms.SetFlag( FL_SOLDERPASTE, tmp );
|
||||
|
||||
aCfg->Read( keyShowCommentsLayer, &tmp, true );
|
||||
prms.SetFlag( FL_COMMENTS, tmp );
|
||||
|
||||
aCfg->Read( keyShowEcoLayers, &tmp, true );
|
||||
prms.SetFlag( FL_ECO, tmp );
|
||||
|
||||
aCfg->Read( keyShowBoardBody, &tmp, true );
|
||||
prms.SetFlag( FL_SHOW_BOARD_BODY, tmp );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::SaveSettings( wxConfigBase* aCfg )
|
||||
{
|
||||
EDA_BASE_FRAME::SaveSettings( aCfg );
|
||||
|
||||
INFO3D_VISU& prms = GetPrm3DVisu();
|
||||
|
||||
aCfg->Write( keyBgColor_Red, GetPrm3DVisu().m_BgColor.m_Red );
|
||||
aCfg->Write( keyBgColor_Green, GetPrm3DVisu().m_BgColor.m_Green );
|
||||
aCfg->Write( keyBgColor_Blue, GetPrm3DVisu().m_BgColor.m_Blue );
|
||||
|
||||
aCfg->Write( keyBgColor_Red_Top, GetPrm3DVisu().m_BgColor_Top.m_Red );
|
||||
aCfg->Write( keyBgColor_Green_Top, GetPrm3DVisu().m_BgColor_Top.m_Green );
|
||||
aCfg->Write( keyBgColor_Blue_Top, GetPrm3DVisu().m_BgColor_Top.m_Blue );
|
||||
|
||||
aCfg->Write( keySMaskColor_Red, GetPrm3DVisu().m_SolderMaskColor.m_Red );
|
||||
aCfg->Write( keySMaskColor_Green, GetPrm3DVisu().m_SolderMaskColor.m_Green );
|
||||
aCfg->Write( keySMaskColor_Blue, GetPrm3DVisu().m_SolderMaskColor.m_Blue );
|
||||
|
||||
aCfg->Write( keySPasteColor_Red, GetPrm3DVisu().m_SolderPasteColor.m_Red );
|
||||
aCfg->Write( keySPasteColor_Green, GetPrm3DVisu().m_SolderPasteColor.m_Green );
|
||||
aCfg->Write( keySPasteColor_Blue, GetPrm3DVisu().m_SolderPasteColor.m_Blue );
|
||||
|
||||
aCfg->Write( keySilkColor_Red, GetPrm3DVisu().m_SilkScreenColor.m_Red );
|
||||
aCfg->Write( keySilkColor_Green, GetPrm3DVisu().m_SilkScreenColor.m_Green );
|
||||
aCfg->Write( keySilkColor_Blue, GetPrm3DVisu().m_SilkScreenColor.m_Blue );
|
||||
|
||||
aCfg->Write( keyCopperColor_Red, GetPrm3DVisu().m_CopperColor.m_Red );
|
||||
aCfg->Write( keyCopperColor_Green, GetPrm3DVisu().m_CopperColor.m_Green );
|
||||
aCfg->Write( keyCopperColor_Blue, GetPrm3DVisu().m_CopperColor.m_Blue );
|
||||
|
||||
aCfg->Write( keyBoardBodyColor_Red, GetPrm3DVisu().m_BoardBodyColor.m_Red );
|
||||
aCfg->Write( keyBoardBodyColor_Green, GetPrm3DVisu().m_BoardBodyColor.m_Green );
|
||||
aCfg->Write( keyBoardBodyColor_Blue, GetPrm3DVisu().m_BoardBodyColor.m_Blue );
|
||||
|
||||
aCfg->Write( keyMousewheelPanning, prms.GetFlag( FL_MOUSEWHEEL_PANNING ) );
|
||||
|
||||
aCfg->Write( keyShowRealisticMode, prms.GetFlag( FL_USE_REALISTIC_MODE ) );
|
||||
|
||||
aCfg->Write( keyRenderShadows, prms.GetFlag( FL_RENDER_SHADOWS ) );
|
||||
aCfg->Write( keyRenderRemoveHoles, prms.GetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES ) );
|
||||
aCfg->Write( keyRenderTextures, prms.GetFlag( FL_RENDER_TEXTURES ) );
|
||||
aCfg->Write( keyRenderSmoothNormals, prms.GetFlag( FL_RENDER_SMOOTH_NORMALS ) );
|
||||
aCfg->Write( keyRenderUseModelNormals, prms.GetFlag( FL_RENDER_USE_MODEL_NORMALS ) );
|
||||
aCfg->Write( keyRenderMaterial, prms.GetFlag( FL_RENDER_MATERIAL ) );
|
||||
aCfg->Write( keyRenderShowModelBBox, prms.GetFlag( FL_RENDER_SHOW_MODEL_BBOX ) );
|
||||
|
||||
aCfg->Write( keyShowAxis, prms.GetFlag( FL_AXIS ) );
|
||||
aCfg->Write( keyShowGrid, prms.GetFlag( FL_GRID ) );
|
||||
aCfg->Write( keyShowGridSize, prms.m_3D_Grid );
|
||||
aCfg->Write( keyShowFootprints, prms.GetFlag( FL_MODULE ) );
|
||||
aCfg->Write( keyShowCopperThickness, prms.GetFlag( FL_USE_COPPER_THICKNESS ) );
|
||||
aCfg->Write( keyShowZones, prms.GetFlag( FL_ZONE ) );
|
||||
aCfg->Write( keyShowAdhesiveLayers, prms.GetFlag( FL_ADHESIVE ) );
|
||||
aCfg->Write( keyShowSilkScreenLayers, prms.GetFlag( FL_SILKSCREEN ) );
|
||||
aCfg->Write( keyShowSolderMaskLayers, prms.GetFlag( FL_SOLDERMASK ) );
|
||||
aCfg->Write( keyShowSolderPasteLayers, prms.GetFlag( FL_SOLDERPASTE ) );
|
||||
aCfg->Write( keyShowCommentsLayer, prms.GetFlag( FL_COMMENTS ) );
|
||||
aCfg->Write( keyShowEcoLayers, prms.GetFlag( FL_ECO ) );
|
||||
aCfg->Write( keyShowBoardBody, prms.GetFlag( FL_SHOW_BOARD_BODY ) );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::Process_Zoom( wxCommandEvent& event )
|
||||
{
|
||||
int ii;
|
||||
|
||||
switch( event.GetId() )
|
||||
{
|
||||
case ID_ZOOM_PAGE:
|
||||
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
GetPrm3DVisu().m_Rot[ii] = 0.0;
|
||||
|
||||
GetPrm3DVisu().m_Zoom = 1.0;
|
||||
m_canvas->SetOffset( 0.0, 0.0 );
|
||||
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
break;
|
||||
|
||||
case ID_ZOOM_IN:
|
||||
GetPrm3DVisu().m_Zoom /= 1.2;
|
||||
|
||||
if( GetPrm3DVisu().m_Zoom <= 0.01 )
|
||||
GetPrm3DVisu().m_Zoom = 0.01;
|
||||
|
||||
break;
|
||||
|
||||
case ID_ZOOM_OUT:
|
||||
GetPrm3DVisu().m_Zoom *= 1.2;
|
||||
break;
|
||||
|
||||
case ID_ZOOM_REDRAW:
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
m_canvas->Refresh( false );
|
||||
m_canvas->DisplayStatus();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
double EDA_3D_FRAME::BestZoom()
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
||||
{
|
||||
#define ROT_ANGLE 10.0
|
||||
int id = event.GetId();
|
||||
bool isChecked = event.IsChecked();
|
||||
|
||||
switch( id )
|
||||
{
|
||||
case ID_TOOL_SET_VISIBLE_ITEMS:
|
||||
Install_3D_ViewOptionDialog( event );
|
||||
break;
|
||||
|
||||
case ID_RELOAD3D_BOARD:
|
||||
m_reloadRequest = true;
|
||||
NewDisplay();
|
||||
return;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_X_POS:
|
||||
GetPrm3DVisu().m_ROTX += ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_X_NEG:
|
||||
GetPrm3DVisu().m_ROTX -= ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_Y_POS:
|
||||
GetPrm3DVisu().m_ROTY += ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_Y_NEG:
|
||||
GetPrm3DVisu().m_ROTY -= ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_Z_POS:
|
||||
GetPrm3DVisu().m_ROTZ += ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_Z_NEG:
|
||||
GetPrm3DVisu().m_ROTZ -= ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_MOVE3D_LEFT:
|
||||
m_canvas->SetView3D( WXK_LEFT );
|
||||
return;
|
||||
|
||||
case ID_MOVE3D_RIGHT:
|
||||
m_canvas->SetView3D( WXK_RIGHT );
|
||||
return;
|
||||
|
||||
case ID_MOVE3D_UP:
|
||||
m_canvas->SetView3D( WXK_UP );
|
||||
return;
|
||||
|
||||
case ID_MOVE3D_DOWN:
|
||||
m_canvas->SetView3D( WXK_DOWN );
|
||||
return;
|
||||
|
||||
case ID_ORTHO:
|
||||
ToggleOrtho();
|
||||
return;
|
||||
|
||||
case ID_TOOL_SCREENCOPY_TOCLIBBOARD:
|
||||
case ID_MENU_SCREENCOPY_PNG:
|
||||
case ID_MENU_SCREENCOPY_JPEG:
|
||||
m_canvas->TakeScreenshot( event );
|
||||
break;
|
||||
|
||||
case ID_MENU3D_BGCOLOR_BOTTOM_SELECTION:
|
||||
if( Set3DColorFromUser( GetPrm3DVisu().m_BgColor, _( "Background Color, Bottom" ) ) )
|
||||
m_canvas->Refresh( true );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_BGCOLOR_TOP_SELECTION:
|
||||
if( Set3DColorFromUser( GetPrm3DVisu().m_BgColor_Top, _( "Background Color, Top" ) ) )
|
||||
m_canvas->Refresh( true );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SILKSCREEN_COLOR_SELECTION:
|
||||
Set3DSilkScreenColorFromUser();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SOLDERMASK_COLOR_SELECTION:
|
||||
Set3DSolderMaskColorFromUser();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SOLDERPASTE_COLOR_SELECTION:
|
||||
Set3DSolderPasteColorFromUser();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_COPPER_COLOR_SELECTION:
|
||||
Set3DCopperColorFromUser();
|
||||
break;
|
||||
|
||||
case ID_MENU3D_PCB_BODY_COLOR_SELECTION:
|
||||
Set3DBoardBodyColorFromUser();
|
||||
break;
|
||||
|
||||
case ID_MENU3D_MOUSEWHEEL_PANNING:
|
||||
GetPrm3DVisu().SetFlag( FL_MOUSEWHEEL_PANNING, isChecked );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_REALISTIC_MODE:
|
||||
GetPrm3DVisu().SetFlag( FL_USE_REALISTIC_MODE, isChecked );
|
||||
GetMenuBar()->FindItem( ID_MENU3D_COMMENTS_ONOFF )->Enable( !isChecked );
|
||||
GetMenuBar()->FindItem( ID_MENU3D_ECO_ONOFF )->Enable( !isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_FL_RENDER_SHADOWS:
|
||||
GetPrm3DVisu().SetFlag( FL_RENDER_SHADOWS, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_FL_RENDER_SHOW_HOLES_IN_ZONES:
|
||||
GetPrm3DVisu().SetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_FL_RENDER_TEXTURES:
|
||||
GetPrm3DVisu().SetFlag( FL_RENDER_TEXTURES, isChecked );
|
||||
NewDisplay(GL_ID_BOARD);
|
||||
NewDisplay(GL_ID_TECH_LAYERS);
|
||||
return;
|
||||
|
||||
case ID_MENU3D_FL_RENDER_SMOOTH_NORMALS:
|
||||
GetPrm3DVisu().SetFlag( FL_RENDER_SMOOTH_NORMALS, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_FL_RENDER_USE_MODEL_NORMALS:
|
||||
GetPrm3DVisu().SetFlag( FL_RENDER_USE_MODEL_NORMALS, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_FL_RENDER_MATERIAL:
|
||||
GetPrm3DVisu().SetFlag( FL_RENDER_MATERIAL, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_FL_RENDER_SHOW_MODEL_BBOX:
|
||||
GetPrm3DVisu().SetFlag( FL_RENDER_SHOW_MODEL_BBOX, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SHOW_BOARD_BODY:
|
||||
GetPrm3DVisu().SetFlag( FL_SHOW_BOARD_BODY, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_AXIS_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_AXIS, isChecked );
|
||||
m_canvas->Refresh();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_MODULE_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_MODULE, isChecked );
|
||||
m_canvas->Refresh();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_USE_COPPER_THICKNESS:
|
||||
GetPrm3DVisu().SetFlag( FL_USE_COPPER_THICKNESS, isChecked );
|
||||
NewDisplay( GL_ID_BOARD );
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_ZONE_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_ZONE, isChecked );
|
||||
NewDisplay( GL_ID_BOARD );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_ADHESIVE_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_ADHESIVE, isChecked );
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SILKSCREEN_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_SILKSCREEN, isChecked );
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SOLDER_MASK_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_SOLDERMASK, isChecked );
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SOLDER_PASTE_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_SOLDERPASTE, isChecked );
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_COMMENTS_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_COMMENTS, isChecked );
|
||||
NewDisplay( GL_ID_AUX_LAYERS );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_ECO_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_ECO, isChecked );
|
||||
NewDisplay( GL_ID_AUX_LAYERS );
|
||||
return;
|
||||
|
||||
default:
|
||||
wxLogMessage( wxT( "EDA_3D_FRAME::Process_Special_Functions() error: unknown command" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
m_canvas->Refresh( true );
|
||||
m_canvas->DisplayStatus();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::On3DGridSelection( wxCommandEvent& event )
|
||||
{
|
||||
int id = event.GetId();
|
||||
|
||||
for( int ii = ID_MENU3D_GRID_NOGRID; ii < ID_MENU3D_GRID_END; ii++ )
|
||||
{
|
||||
if( event.GetId() == ii )
|
||||
continue;
|
||||
|
||||
GetMenuBar()->Check( ii, false );
|
||||
}
|
||||
|
||||
switch( id )
|
||||
{
|
||||
case ID_MENU3D_GRID_NOGRID:
|
||||
GetPrm3DVisu().SetFlag( FL_GRID, false );
|
||||
break;
|
||||
|
||||
case ID_MENU3D_GRID_10_MM:
|
||||
GetPrm3DVisu().SetFlag( FL_GRID, true );
|
||||
GetPrm3DVisu().m_3D_Grid = 10.0;
|
||||
break;
|
||||
|
||||
case ID_MENU3D_GRID_5_MM:
|
||||
GetPrm3DVisu().SetFlag( FL_GRID, true );
|
||||
GetPrm3DVisu().m_3D_Grid = 5.0;
|
||||
break;
|
||||
|
||||
case ID_MENU3D_GRID_2P5_MM:
|
||||
GetPrm3DVisu().SetFlag( FL_GRID, true );
|
||||
GetPrm3DVisu().m_3D_Grid = 2.5;
|
||||
break;
|
||||
|
||||
case ID_MENU3D_GRID_1_MM:
|
||||
GetPrm3DVisu().SetFlag( FL_GRID, true );
|
||||
GetPrm3DVisu().m_3D_Grid = 1.0;
|
||||
break;
|
||||
|
||||
default:
|
||||
wxLogMessage( wxT( "EDA_3D_FRAME::On3DGridSelection() error: unknown command" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
NewDisplay( GL_ID_GRID );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::NewDisplay( int aGlList )
|
||||
{
|
||||
m_canvas->ClearLists( aGlList );
|
||||
|
||||
// Rebuild the 3D board and refresh the view on reload request:
|
||||
if( m_reloadRequest )
|
||||
m_canvas->ReportWarnings( true );
|
||||
|
||||
m_canvas->Refresh( true );
|
||||
|
||||
m_canvas->DisplayStatus();
|
||||
m_reloadRequest = false;
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::OnActivate( wxActivateEvent& event )
|
||||
{
|
||||
// Reload data if 3D frame shows a board,
|
||||
// because it can be changed since last frame activation
|
||||
if( m_reloadRequest )
|
||||
NewDisplay();
|
||||
|
||||
event.Skip(); // required under wxMAC
|
||||
}
|
||||
|
||||
|
||||
bool EDA_3D_FRAME::Set3DColorFromUser( S3D_COLOR &aColor, const wxString& aTitle,
|
||||
wxColourData* aPredefinedColors )
|
||||
{
|
||||
wxColour newcolor, oldcolor;
|
||||
|
||||
oldcolor.Set( KiROUND( aColor.m_Red * 255 ),
|
||||
KiROUND( aColor.m_Green * 255 ),
|
||||
KiROUND( aColor.m_Blue * 255 ) );
|
||||
|
||||
wxColourData emptyColorSet; // Provides a empty predefined set of colors
|
||||
// if no color set available to avoid use of an
|
||||
// old color set
|
||||
|
||||
if( aPredefinedColors == NULL )
|
||||
aPredefinedColors = &emptyColorSet;
|
||||
|
||||
newcolor = wxGetColourFromUser( this, oldcolor, aTitle, aPredefinedColors );
|
||||
|
||||
if( !newcolor.IsOk() ) // Cancel command
|
||||
return false;
|
||||
|
||||
if( newcolor != oldcolor )
|
||||
{
|
||||
aColor.m_Red = (double) newcolor.Red() / 255.0;
|
||||
aColor.m_Green = (double) newcolor.Green() / 255.0;
|
||||
aColor.m_Blue = (double) newcolor.Blue() / 255.0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool EDA_3D_FRAME::Set3DSilkScreenColorFromUser()
|
||||
{
|
||||
wxColourData definedColors;
|
||||
|
||||
definedColors.SetCustomColour(0, wxColour( 241, 241, 241 ) ); // White
|
||||
definedColors.SetCustomColour(1, wxColour( 180, 180, 180 ) ); // Gray
|
||||
|
||||
bool change = Set3DColorFromUser( GetPrm3DVisu().m_SilkScreenColor,
|
||||
_( "Silk Screen Color" ),
|
||||
&definedColors );
|
||||
|
||||
if( change )
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
|
||||
bool EDA_3D_FRAME::Set3DSolderMaskColorFromUser()
|
||||
{
|
||||
wxColourData definedColors;
|
||||
|
||||
definedColors.SetCustomColour(0, wxColour( 20, 51, 36 ) ); // Green
|
||||
definedColors.SetCustomColour(1, wxColour( 43, 10, 65 ) ); // Purple
|
||||
definedColors.SetCustomColour(2, wxColour( 117, 19, 21 ) ); // Red
|
||||
definedColors.SetCustomColour(3, wxColour( 54, 79, 116) ); // Light blue
|
||||
definedColors.SetCustomColour(4, wxColour( 11, 11, 11 ) ); // Black
|
||||
definedColors.SetCustomColour(5, wxColour( 241, 241,241) ); // White
|
||||
|
||||
bool change = Set3DColorFromUser( GetPrm3DVisu().m_SolderMaskColor,
|
||||
_( "Solder Mask Color" ),
|
||||
&definedColors );
|
||||
|
||||
if( change )
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
|
||||
bool EDA_3D_FRAME::Set3DCopperColorFromUser()
|
||||
{
|
||||
wxColourData definedColors;
|
||||
|
||||
definedColors.SetCustomColour( 0, wxColour( 184, 115, 50 ) ); // Copper
|
||||
definedColors.SetCustomColour( 1, wxColour( 233, 221, 82 ) ); // Gold
|
||||
definedColors.SetCustomColour( 2, wxColour( 213, 213, 213) ); // Silver
|
||||
definedColors.SetCustomColour( 3, wxColour( 160, 160, 160) ); // tin
|
||||
|
||||
|
||||
bool change = Set3DColorFromUser( GetPrm3DVisu().m_CopperColor,
|
||||
_( "Copper Color" ),
|
||||
&definedColors );
|
||||
|
||||
if( change )
|
||||
NewDisplay( GL_ID_BOARD );
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
|
||||
bool EDA_3D_FRAME::Set3DBoardBodyColorFromUser()
|
||||
{
|
||||
wxColourData definedColors;
|
||||
|
||||
definedColors.SetCustomColour( 0, wxColour( 51, 43, 22 ) ); // FR4 natural, dark
|
||||
definedColors.SetCustomColour( 1, wxColour( 109, 116, 75 ) ); // FR4 natural
|
||||
definedColors.SetCustomColour( 2, wxColour( 78, 14, 5 ) ); // brown/red
|
||||
definedColors.SetCustomColour( 3, wxColour( 146, 99, 47 ) ); // brown 1
|
||||
definedColors.SetCustomColour( 4, wxColour( 160, 123, 54 ) ); // brown 2
|
||||
definedColors.SetCustomColour( 5, wxColour( 146, 99, 47 ) ); // brown 3
|
||||
definedColors.SetCustomColour( 6, wxColour( 63, 126, 71 ) ); // green 1
|
||||
definedColors.SetCustomColour( 7, wxColour( 117, 122, 90 ) ); // green 2
|
||||
|
||||
bool change = Set3DColorFromUser( GetPrm3DVisu().m_BoardBodyColor,
|
||||
_( "Board Body Color" ),
|
||||
&definedColors );
|
||||
|
||||
if( change )
|
||||
NewDisplay( GL_ID_BOARD );
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
|
||||
bool EDA_3D_FRAME::Set3DSolderPasteColorFromUser()
|
||||
{
|
||||
wxColourData definedColors;
|
||||
|
||||
definedColors.SetCustomColour(0, wxColour( 128, 128, 128 ) ); // grey
|
||||
definedColors.SetCustomColour(1, wxColour( 213, 213, 213 ) ); // Silver
|
||||
definedColors.SetCustomColour(2, wxColour( 90, 90, 90 ) ); // grey 2
|
||||
|
||||
bool change = Set3DColorFromUser( GetPrm3DVisu().m_SolderPasteColor,
|
||||
_( "Solder Paste Color" ),
|
||||
&definedColors );
|
||||
|
||||
if( change )
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
|
||||
BOARD* EDA_3D_FRAME::GetBoard()
|
||||
{
|
||||
return Parent()->GetBoard();
|
||||
}
|
||||
|
||||
|
||||
INFO3D_VISU& EDA_3D_FRAME::GetPrm3DVisu() const
|
||||
{
|
||||
// return the INFO3D_VISU which contains the current parameters
|
||||
// to draw the 3D view of the board
|
||||
return g_Parm_3D_Visu;
|
||||
}
|
||||
|
||||
|
||||
bool EDA_3D_FRAME::IsEnabled( DISPLAY3D_FLG aItem ) const
|
||||
{
|
||||
// return true if aItem must be displayed
|
||||
return GetPrm3DVisu().GetFlag( aItem );
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
/**
|
||||
* @file 3d_class.cpp
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <3d_struct.h>
|
||||
#include <3d_material.h>
|
||||
#include <info3d_visu.h>
|
||||
|
||||
#ifdef __WXMAC__
|
||||
# ifdef __DARWIN__
|
||||
# include <OpenGL/glu.h>
|
||||
# else
|
||||
# include <glu.h>
|
||||
# endif
|
||||
#else
|
||||
# include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
S3D_MATERIAL::S3D_MATERIAL( S3D_MASTER* father, const wxString& name ) :
|
||||
EDA_ITEM( father, NOT_USED )
|
||||
{
|
||||
m_Name = name;
|
||||
m_AmbientColor.clear();
|
||||
m_DiffuseColor.clear();
|
||||
m_EmissiveColor.clear();
|
||||
m_SpecularColor.clear();
|
||||
m_Shininess.clear();
|
||||
m_Transparency.clear();
|
||||
m_ColorPerVertex = false;
|
||||
}
|
||||
|
||||
|
||||
void SetOpenGlDefaultMaterial()
|
||||
{
|
||||
glm::vec4 ambient( 0.2f, 0.2f, 0.2f, 1.0f );
|
||||
glm::vec4 specular( 0.0f, 0.0f, 0.0f, 1.0f );
|
||||
glm::vec4 emissive( 0.0f, 0.0f, 0.0f, 1.0f );
|
||||
glm::vec4 diffuse( 0.0f, 0.0f, 0.0f, 1.0f );
|
||||
GLint shininess_value = 0;
|
||||
|
||||
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
|
||||
glMateriali ( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value );
|
||||
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.x );
|
||||
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.x );
|
||||
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.x );
|
||||
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.x );
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool S3D_MATERIAL::SetOpenGLMaterial( unsigned int aMaterialIndex, bool aUseMaterial )
|
||||
{
|
||||
if( aUseMaterial )
|
||||
{
|
||||
float transparency_value = 0.0f;
|
||||
|
||||
if( m_Transparency.size() > aMaterialIndex )
|
||||
{
|
||||
transparency_value = m_Transparency[aMaterialIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
if( m_Transparency.size() > 0 )
|
||||
transparency_value = m_Transparency[0];
|
||||
}
|
||||
|
||||
if( m_DiffuseColor.size() > aMaterialIndex )
|
||||
{
|
||||
glm::vec3 color = m_DiffuseColor[aMaterialIndex];
|
||||
|
||||
glColor4f( color.x, color.y, color.z, 1.0f - transparency_value );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( m_DiffuseColor.size() == 0 )
|
||||
{
|
||||
glColor4f( 0.8f, 0.8f, 0.8f, 1.0f );
|
||||
}
|
||||
}
|
||||
|
||||
if( m_Shininess.size() > 0 )
|
||||
{
|
||||
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, m_Shininess[0] );
|
||||
}
|
||||
|
||||
// emissive
|
||||
if( m_EmissiveColor.size() > aMaterialIndex )
|
||||
{
|
||||
glm::vec4 emissive;
|
||||
emissive[0] = m_EmissiveColor[aMaterialIndex].x;
|
||||
emissive[1] = m_EmissiveColor[aMaterialIndex].y;
|
||||
emissive[2] = m_EmissiveColor[aMaterialIndex].z;
|
||||
emissive[3] = 1.0f;
|
||||
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.x );
|
||||
}
|
||||
|
||||
// specular
|
||||
if( m_SpecularColor.size() > aMaterialIndex )
|
||||
{
|
||||
glm::vec4 specular;
|
||||
specular[0] = m_SpecularColor[aMaterialIndex].x;
|
||||
specular[1] = m_SpecularColor[aMaterialIndex].y;
|
||||
specular[2] = m_SpecularColor[aMaterialIndex].z;
|
||||
specular[3] = 1.0f;
|
||||
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.x );
|
||||
}
|
||||
|
||||
// ambient
|
||||
if( m_AmbientColor.size() > aMaterialIndex )
|
||||
{
|
||||
glm::vec4 ambient;
|
||||
ambient[0] = m_AmbientColor[aMaterialIndex].x;
|
||||
ambient[1] = m_AmbientColor[aMaterialIndex].y;
|
||||
ambient[2] = m_AmbientColor[aMaterialIndex].z;
|
||||
ambient[3] = 1.0f;
|
||||
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.x );
|
||||
}
|
||||
|
||||
return (transparency_value != 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( m_DiffuseColor.size() > aMaterialIndex )
|
||||
{
|
||||
glm::vec3 color = m_DiffuseColor[aMaterialIndex];
|
||||
glColor4f( color.x, color.y, color.z, 1.0 );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_material.h
|
||||
*/
|
||||
|
||||
#ifndef STRUCT_3D_MATERIAL_H
|
||||
#define STRUCT_3D_MATERIAL_H
|
||||
|
||||
#include <common.h>
|
||||
#include <base_struct.h>
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <gal/opengl/glm/glm.hpp>
|
||||
|
||||
class S3D_MASTER;
|
||||
|
||||
class S3D_MATERIAL : public EDA_ITEM // openGL "material" data
|
||||
{
|
||||
public:
|
||||
wxString m_Name;
|
||||
|
||||
// Material list
|
||||
std::vector< glm::vec3 > m_AmbientColor;
|
||||
std::vector< glm::vec3 > m_DiffuseColor;
|
||||
std::vector< glm::vec3 > m_EmissiveColor;
|
||||
std::vector< glm::vec3 > m_SpecularColor;
|
||||
std::vector< float > m_Shininess;
|
||||
std::vector< float > m_Transparency;
|
||||
bool m_ColorPerVertex;
|
||||
|
||||
public:
|
||||
S3D_MATERIAL( S3D_MASTER* father, const wxString& name );
|
||||
|
||||
S3D_MATERIAL* Next() const { return (S3D_MATERIAL*) Pnext; }
|
||||
S3D_MATERIAL* Back() const { return (S3D_MATERIAL*) Pback; }
|
||||
|
||||
/**
|
||||
* Initialize the material prms.
|
||||
* @param aMaterialIndex = the index in list of available materials
|
||||
* @param aUseMaterial = true to use the values found in the available material
|
||||
* = false to use only the color, and other prms are fixed
|
||||
* @return true if the material is transparency
|
||||
*/
|
||||
bool SetOpenGLMaterial(unsigned int aMaterialIndex, bool aUseMaterial);
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override
|
||||
#endif
|
||||
|
||||
/** Get class name
|
||||
* @return string "S3D_MATERIAL"
|
||||
*/
|
||||
virtual wxString GetClass() const
|
||||
{
|
||||
return wxT( "S3D_MATERIAL" );
|
||||
}
|
||||
};
|
||||
|
||||
void SetOpenGlDefaultMaterial();
|
||||
|
||||
#endif
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_math.cpp
|
||||
* @brief
|
||||
*/
|
||||
|
||||
|
||||
#include "3d_math.h"
|
||||
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_math.h
|
||||
* @brief Defines math related functions
|
||||
*/
|
||||
|
||||
#ifndef _3D_MATH_H
|
||||
#define _3D_MATH_H
|
||||
|
||||
#include <plugins/3dapi/xv3d_types.h>
|
||||
#include "3d_fastmath.h"
|
||||
|
||||
/**
|
||||
* https://en.wikipedia.org/wiki/Spherical_coordinate_system
|
||||
*
|
||||
* @param aInclination θ ∈ [0, π]
|
||||
* @param aAzimuth φ ∈ [0, 2π]
|
||||
* @return Cartesian coordinates
|
||||
*/
|
||||
inline SFVEC3F SphericalToCartesian( float aInclination, float aAzimuth )
|
||||
{
|
||||
float sinInc = glm::sin( aInclination );
|
||||
|
||||
return SFVEC3F( sinInc * glm::cos( aAzimuth ), sinInc * glm::sin( aAzimuth ),
|
||||
glm::cos( aInclination ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo This is not correct because it is not a gaussian random.
|
||||
*/
|
||||
inline SFVEC3F UniformRandomHemisphereDirection()
|
||||
{
|
||||
// It was experienced that this function is slow! do not use it :/
|
||||
// SFVEC3F b( (rand()/(float)RAND_MAX) - 0.5f,
|
||||
// (rand()/(float)RAND_MAX) - 0.5f,
|
||||
// (rand()/(float)RAND_MAX) - 0.5f );
|
||||
|
||||
SFVEC3F b( Fast_RandFloat() * 0.5f, Fast_RandFloat() * 0.5f, Fast_RandFloat() * 0.5f );
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
// https://pathtracing.wordpress.com/2011/03/03/cosine-weighted-hemisphere/
|
||||
inline SFVEC3F CosWeightedRandomHemisphereDirection( const SFVEC3F& n )
|
||||
{
|
||||
const float Xi1 = (float) rand() / (float) RAND_MAX;
|
||||
const float Xi2 = (float) rand() / (float) RAND_MAX;
|
||||
|
||||
const float theta = acos( sqrt( 1.0f - Xi1 ) );
|
||||
const float phi = 2.0f * glm::pi<float>() * Xi2;
|
||||
|
||||
const float xs = sinf( theta ) * cosf( phi );
|
||||
const float ys = cosf( theta );
|
||||
const float zs = sinf( theta ) * sinf( phi );
|
||||
|
||||
const SFVEC3F y( n.x, n.y, n.z );
|
||||
SFVEC3F h = y;
|
||||
|
||||
if( fabs( h.x ) <= fabs( h.y ) && fabs( h.x ) <= fabs( h.z ) )
|
||||
h.x= 1.0f;
|
||||
else if( fabs( h.y ) <= fabs( h.x ) && fabs( h.y ) <= fabs( h.z ) )
|
||||
h.y= 1.0f;
|
||||
else
|
||||
h.z= 1.0f;
|
||||
|
||||
|
||||
const SFVEC3F x = glm::normalize( glm::cross( h, y ) );
|
||||
const SFVEC3F z = glm::normalize( glm::cross( x, y ) );
|
||||
|
||||
SFVEC3F direction = xs * x + ys * y + zs * z;
|
||||
return glm::normalize( direction );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Based on:
|
||||
* https://github.com/mmp/pbrt-v3/blob/master/src/core/reflection.h
|
||||
* See also:
|
||||
* http://www.flipcode.com/archives/Raytracing_Topics_Techniques-Part_3_Refractions_and_Beers_Law.shtml
|
||||
*
|
||||
* @param aInVector incoming vector.
|
||||
* @param aNormal normal in the intersection point.
|
||||
* @param aRin_over_Rout incoming refraction index / out refraction index.
|
||||
* @param aOutVector the refracted vector.
|
||||
* @return true
|
||||
*/
|
||||
inline bool Refract( const SFVEC3F &aInVector, const SFVEC3F &aNormal, float aRin_over_Rout,
|
||||
SFVEC3F& aOutVector )
|
||||
{
|
||||
float cosThetaI = -glm::dot( aNormal, aInVector );
|
||||
float sin2ThetaI = glm::max( 0.0f, 1.0f - cosThetaI * cosThetaI );
|
||||
float sin2ThetaT = aRin_over_Rout * aRin_over_Rout * sin2ThetaI;
|
||||
|
||||
// Handle total internal reflection for transmission
|
||||
if( sin2ThetaT >= 1.0f )
|
||||
return false;
|
||||
|
||||
float cosThetaT = sqrtf( 1.0f - sin2ThetaT );
|
||||
|
||||
aOutVector = glm::normalize( aRin_over_Rout * aInVector +
|
||||
( aRin_over_Rout * cosThetaI - cosThetaT ) *
|
||||
aNormal );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
inline float mapf( float x, float in_min, float in_max, float out_min, float out_max )
|
||||
{
|
||||
x = glm::clamp( x, in_min, in_max );
|
||||
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
inline float RGBtoGray( const SFVEC3F &aColor )
|
||||
{
|
||||
return (aColor.r * 0.2126f +
|
||||
aColor.g * 0.7152f +
|
||||
aColor.b * 0.0722f);
|
||||
}
|
||||
|
||||
inline SFVEC3F MaterialDiffuseToColorCAD( const SFVEC3F &aDiffuseColor )
|
||||
{
|
||||
// convert to a discret scale of grays
|
||||
const float luminance = glm::min(
|
||||
( ( (float) ( (unsigned int) ( 4.0f * RGBtoGray( aDiffuseColor ) ) ) + 0.5f ) / 4.0f )
|
||||
* 1.0f,
|
||||
1.0f );
|
||||
|
||||
const float maxValue = glm::max( glm::max( glm::max( aDiffuseColor.r, aDiffuseColor.g ),
|
||||
aDiffuseColor.b ), FLT_EPSILON );
|
||||
|
||||
return ( aDiffuseColor / SFVEC3F( maxValue ) ) * 0.125f + luminance * 0.875f;
|
||||
}
|
||||
|
||||
|
||||
// http://fooplot.com/#W3sidHlwZSI6MCwiZXEiOiJ4KngqMiIsImNvbG9yIjoiIzAwMDAwMCJ9LHsidHlwZSI6MCwiZXEiOiItKCh4LTEpXjIpKjIrMSIsImNvbG9yIjoiIzAwMDAwMCJ9LHsidHlwZSI6MTAwMCwid2luZG93IjpbIi0xLjM4NzUwMDAwMDAwMDAwMDIiLCIxLjg2MjQ5OTk5OTk5OTk5OTgiLCItMC43IiwiMS4zIl19XQ--
|
||||
inline float QuadricEasingInOut( float t )
|
||||
{
|
||||
if( t <= 0.5f )
|
||||
{
|
||||
return t * t * 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = t - 1.0f;
|
||||
|
||||
return -2.0f * ( t * t ) + 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// http://www.wolframalpha.com/input/?i=t%5E2(3-2t)
|
||||
inline float BezierBlend( float t )
|
||||
{
|
||||
return t * t * ( 3.0f - 2.0f * t );
|
||||
}
|
||||
|
||||
#endif // 3D_MATH_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_mesh_model.h
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef __3D_MESH_MODEL_H__
|
||||
#define __3D_MESH_MODEL_H__
|
||||
|
||||
#include <memory>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <vector>
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <gal/opengl/glm/glm.hpp>
|
||||
#include "3d_struct.h"
|
||||
#include "3d_material.h"
|
||||
#include "CBBox.h"
|
||||
|
||||
class S3D_MESH;
|
||||
|
||||
/** A smart pointer to an S3D_MESH object */
|
||||
typedef boost::shared_ptr<S3D_MESH> S3D_MESH_PTR;
|
||||
|
||||
/** A container of smar S3D_MESH object pointers */
|
||||
typedef std::vector<S3D_MESH_PTR> S3D_MESH_PTRS;
|
||||
|
||||
class S3D_MESH
|
||||
{
|
||||
public:
|
||||
|
||||
S3D_MESH();
|
||||
~S3D_MESH();
|
||||
|
||||
void openGL_RenderAllChilds( bool aIsRenderingJustNonTransparentObjects,
|
||||
bool aIsRenderingJustTransparentObjects );
|
||||
|
||||
S3D_MATERIAL *m_Materials;
|
||||
|
||||
// Point and index list
|
||||
std::vector< S3D_VERTEX > m_Point;
|
||||
std::vector< std::vector<int> > m_CoordIndex;
|
||||
std::vector< std::vector<int> > m_NormalIndex;
|
||||
std::vector< S3D_VERTEX > m_PerFaceColor;
|
||||
std::vector< S3D_VERTEX > m_PerFaceNormalsNormalized;
|
||||
std::vector< S3D_VERTEX > m_PerVertexNormalsNormalized;
|
||||
std::vector< int > m_MaterialIndexPerFace;
|
||||
std::vector< std::vector<int> > m_MaterialIndexPerVertex;
|
||||
S3D_MESH_PTRS childs;
|
||||
|
||||
S3D_VERTEX m_translation;
|
||||
glm::vec4 m_rotation;
|
||||
S3D_VERTEX m_scale;
|
||||
|
||||
CBBOX &getBBox();
|
||||
|
||||
private:
|
||||
std::vector< S3D_VERTEX > m_PerFaceNormalsRaw_X_PerFaceSquaredArea;
|
||||
std::vector< std::vector< S3D_VERTEX > > m_PerFaceVertexNormals;
|
||||
std::vector< S3D_VERTEX > m_PointNormalized;
|
||||
|
||||
std::vector< std::vector<int> > m_InvalidCoordIndexes; //!TODO: check for invalid CoordIndex in file and remove the index and the same material index
|
||||
|
||||
bool isPerFaceNormalsComputed;
|
||||
void calcPerFaceNormals ();
|
||||
|
||||
bool isPointNormalizedComputed;
|
||||
void calcPointNormalized();
|
||||
|
||||
bool isPerPointNormalsComputed;
|
||||
void calcPerPointNormals();
|
||||
|
||||
bool isPerVertexNormalsVerified;
|
||||
void perVertexNormalsVerify_and_Repair();
|
||||
|
||||
void calcBBox();
|
||||
void calcBBoxAllChilds();
|
||||
|
||||
CBBOX m_BBox;
|
||||
|
||||
void openGL_Render( bool aIsRenderingJustNonTransparentObjects,
|
||||
bool aIsRenderingJustTransparentObjects );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,483 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Implements a model viewer canvas. The purpose of the model viewer is to render
|
||||
* 3d models that come in the original data from the files without any transformations.
|
||||
*/
|
||||
|
||||
#include <gal/opengl/kiglew.h> // Must be included first
|
||||
#include <iostream>
|
||||
#include "3d_rendering/opengl/3d_model.h"
|
||||
#include "eda_3d_model_viewer.h"
|
||||
#include "../3d_rendering/opengl/opengl_utils.h"
|
||||
#include "../3d_cache/3d_cache.h"
|
||||
#include <wx/dcclient.h>
|
||||
#include <base_units.h>
|
||||
#include <build_version.h>
|
||||
#include <gal/opengl/gl_context_mgr.h>
|
||||
#include <settings/common_settings.h>
|
||||
#include <pgm_base.h>
|
||||
#include <dpi_scaling_common.h>
|
||||
#include <class_draw_panel_gal.h>
|
||||
#include <macros.h>
|
||||
|
||||
/**
|
||||
* Scale conversion from 3d model units to pcb units
|
||||
*/
|
||||
#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
* The debug output can be turned on by setting the WXTRACE environment variable to
|
||||
* "KI_TRACE_EDA_3D_MODEL_VIEWER". See the wxWidgets documentation on wxLogTrace for
|
||||
* more information.
|
||||
*
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
const wxChar* EDA_3D_MODEL_VIEWER::m_logTrace = wxT( "KI_TRACE_EDA_3D_MODEL_VIEWER" );
|
||||
|
||||
|
||||
BEGIN_EVENT_TABLE( EDA_3D_MODEL_VIEWER, wxGLCanvas )
|
||||
EVT_PAINT( EDA_3D_MODEL_VIEWER::OnPaint )
|
||||
|
||||
// mouse events
|
||||
EVT_LEFT_DOWN( EDA_3D_MODEL_VIEWER::OnLeftDown )
|
||||
EVT_LEFT_UP( EDA_3D_MODEL_VIEWER::OnLeftUp )
|
||||
EVT_MIDDLE_UP( EDA_3D_MODEL_VIEWER::OnMiddleUp )
|
||||
EVT_MIDDLE_DOWN( EDA_3D_MODEL_VIEWER::OnMiddleDown)
|
||||
EVT_RIGHT_DOWN( EDA_3D_MODEL_VIEWER::OnRightClick )
|
||||
EVT_MOUSEWHEEL( EDA_3D_MODEL_VIEWER::OnMouseWheel )
|
||||
EVT_MOTION( EDA_3D_MODEL_VIEWER::OnMouseMove )
|
||||
|
||||
#ifdef USE_OSX_MAGNIFY_EVENT
|
||||
EVT_MAGNIFY( EDA_3D_MODEL_VIEWER::OnMagnify )
|
||||
#endif
|
||||
|
||||
// other events
|
||||
EVT_ERASE_BACKGROUND( EDA_3D_MODEL_VIEWER::OnEraseBackground )
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
// This defines the range that all coord will have to be rendered.
|
||||
// It will use this value to convert to a normalized value between
|
||||
// -(RANGE_SCALE_3D/2) .. +(RANGE_SCALE_3D/2)
|
||||
#define RANGE_SCALE_3D 8.0f
|
||||
|
||||
|
||||
EDA_3D_MODEL_VIEWER::EDA_3D_MODEL_VIEWER( wxWindow* aParent, const wxGLAttributes& aGLAttribs,
|
||||
S3D_CACHE* aCacheManager ) :
|
||||
HIDPI_GL_CANVAS( EDA_DRAW_PANEL_GAL::GetVcSettings(), aParent, aGLAttribs, wxID_ANY,
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
wxFULL_REPAINT_ON_RESIZE ),
|
||||
m_trackBallCamera( RANGE_SCALE_3D * 4.0f ),
|
||||
m_cacheManager( aCacheManager )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::EDA_3D_MODEL_VIEWER" ) );
|
||||
|
||||
m_ogl_initialized = false;
|
||||
m_reload_is_needed = false;
|
||||
m_ogl_3dmodel = nullptr;
|
||||
m_3d_model = nullptr;
|
||||
m_BiuTo3dUnits = 1.0;
|
||||
|
||||
m_glRC = nullptr;
|
||||
}
|
||||
|
||||
|
||||
EDA_3D_MODEL_VIEWER::~EDA_3D_MODEL_VIEWER()
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::~EDA_3D_MODEL_VIEWER" ) );
|
||||
GL_CONTEXT_MANAGER* gl_mgr = Pgm().GetGLContextManager();
|
||||
|
||||
if( m_glRC )
|
||||
{
|
||||
gl_mgr->LockCtx( m_glRC, this );
|
||||
|
||||
delete m_ogl_3dmodel;
|
||||
m_ogl_3dmodel = nullptr;
|
||||
|
||||
gl_mgr->UnlockCtx( m_glRC );
|
||||
gl_mgr->DestroyCtx( m_glRC );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::Set3DModel( const S3DMODEL& a3DModel )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::Set3DModel with a S3DMODEL" ) );
|
||||
|
||||
// Validate a3DModel pointers
|
||||
wxASSERT( a3DModel.m_Materials != nullptr );
|
||||
wxASSERT( a3DModel.m_Meshes != nullptr );
|
||||
wxASSERT( a3DModel.m_MaterialsSize > 0 );
|
||||
wxASSERT( a3DModel.m_MeshesSize > 0 );
|
||||
|
||||
// Delete the old model
|
||||
delete m_ogl_3dmodel;
|
||||
m_ogl_3dmodel = nullptr;
|
||||
|
||||
m_3d_model = nullptr;
|
||||
|
||||
if( ( a3DModel.m_Materials != nullptr ) && ( a3DModel.m_Meshes != nullptr )
|
||||
&& ( a3DModel.m_MaterialsSize > 0 ) && ( a3DModel.m_MeshesSize > 0 ) )
|
||||
{
|
||||
m_3d_model = &a3DModel;
|
||||
m_reload_is_needed = true;
|
||||
}
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::Set3DModel( const wxString& aModelPathName)
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::Set3DModel with a wxString" ) );
|
||||
|
||||
if( m_cacheManager )
|
||||
{
|
||||
const S3DMODEL* model = m_cacheManager->GetModel( aModelPathName, wxEmptyString, nullptr );
|
||||
|
||||
if( model )
|
||||
Set3DModel( (const S3DMODEL &)*model );
|
||||
else
|
||||
Clear3DModel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::Clear3DModel()
|
||||
{
|
||||
// Delete the old model
|
||||
m_reload_is_needed = false;
|
||||
|
||||
delete m_ogl_3dmodel;
|
||||
m_ogl_3dmodel = nullptr;
|
||||
|
||||
m_3d_model = nullptr;
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::ogl_initialize()
|
||||
{
|
||||
const GLenum err = glewInit();
|
||||
|
||||
if( GLEW_OK != err )
|
||||
{
|
||||
const wxString msgError = (const char*) glewGetErrorString( err );
|
||||
|
||||
wxLogMessage( msgError );
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::ogl_initialize Using GLEW version %s" ),
|
||||
From_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
|
||||
}
|
||||
|
||||
SetOpenGLInfo( (const char*) glGetString( GL_VENDOR ), (const char*) glGetString( GL_RENDERER ),
|
||||
(const char*) glGetString( GL_VERSION ) );
|
||||
|
||||
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
|
||||
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
|
||||
glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
|
||||
|
||||
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
glEnable( GL_CULL_FACE );
|
||||
glShadeModel( GL_SMOOTH );
|
||||
glEnable( GL_LINE_SMOOTH );
|
||||
glEnable( GL_NORMALIZE );
|
||||
|
||||
// Setup light
|
||||
// https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
|
||||
const GLfloat ambient[] = { 0.01f, 0.01f, 0.01f, 1.0f };
|
||||
const GLfloat diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
const GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
|
||||
// defines a directional light that points along the negative z-axis
|
||||
const GLfloat position[] = { 0.0f, 0.0f, 2.0f * RANGE_SCALE_3D, 0.0f };
|
||||
|
||||
const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
|
||||
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
|
||||
glLightfv( GL_LIGHT0, GL_SPECULAR, specular );
|
||||
glLightfv( GL_LIGHT0, GL_POSITION, position );
|
||||
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::ogl_set_arrow_material()
|
||||
{
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
|
||||
|
||||
const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
|
||||
|
||||
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
|
||||
glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
|
||||
{
|
||||
event.Skip( false );
|
||||
|
||||
// SwapBuffer requires the window to be shown before calling
|
||||
if( !IsShownOnScreen() )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnPaint !IsShown" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// "Makes the OpenGL state that is represented by the OpenGL rendering
|
||||
// context context current, i.e. it will be used by all subsequent OpenGL calls.
|
||||
// This function may only be called when the window is shown on screen"
|
||||
if( m_glRC == nullptr )
|
||||
m_glRC = Pgm().GetGLContextManager()->CreateCtx( this );
|
||||
|
||||
// CreateCtx could and does fail per sentry crash events, lets be graceful
|
||||
if( m_glRC == nullptr )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnPaint creating gl context failed" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
Pgm().GetGLContextManager()->LockCtx( m_glRC, this );
|
||||
|
||||
// Set the OpenGL viewport according to the client size of this canvas.
|
||||
// This is done here rather than in a wxSizeEvent handler because our
|
||||
// OpenGL rendering context (and thus viewport setting) is used with
|
||||
// multiple canvases: If we updated the viewport in the wxSizeEvent
|
||||
// handler, changing the size of one canvas causes a viewport setting that
|
||||
// is wrong when next another canvas is repainted.
|
||||
wxSize clientSize = GetNativePixelSize();
|
||||
|
||||
if( !m_ogl_initialized )
|
||||
{
|
||||
m_ogl_initialized = true;
|
||||
ogl_initialize();
|
||||
}
|
||||
|
||||
if( m_reload_is_needed )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnPaint m_reload_is_needed" ) );
|
||||
|
||||
m_reload_is_needed = false;
|
||||
m_ogl_3dmodel = new MODEL_3D( *m_3d_model, MATERIAL_MODE::NORMAL );
|
||||
|
||||
// It convert a model as it was a board, so get the max size dimension of the board
|
||||
// and compute the conversion scale
|
||||
m_BiuTo3dUnits =
|
||||
(double) RANGE_SCALE_3D
|
||||
/ ( (double) m_ogl_3dmodel->GetBBox().GetMaxDimension() * UNITS3D_TO_UNITSPCB );
|
||||
}
|
||||
|
||||
glViewport( 0, 0, clientSize.x, clientSize.y );
|
||||
|
||||
m_trackBallCamera.SetCurWindowSize( clientSize );
|
||||
|
||||
// clear color and depth buffers
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
|
||||
glClearDepth( 1.0f );
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
// Set projection and modelview matrices
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadMatrixf( glm::value_ptr( m_trackBallCamera.GetProjectionMatrix() ) );
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadMatrixf( glm::value_ptr( m_trackBallCamera.GetViewMatrix() ) );
|
||||
glEnable( GL_LIGHTING );
|
||||
glEnable( GL_LIGHT0 );
|
||||
|
||||
// Render Model
|
||||
if( m_ogl_3dmodel )
|
||||
{
|
||||
glPushMatrix();
|
||||
|
||||
double modelunit_to_3d_units_factor = m_BiuTo3dUnits * UNITS3D_TO_UNITSPCB;
|
||||
|
||||
glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
|
||||
modelunit_to_3d_units_factor );
|
||||
|
||||
// Center model in the render viewport
|
||||
const SFVEC3F model_center = m_ogl_3dmodel->GetBBox().GetCenter();
|
||||
|
||||
glTranslatef( -model_center.x, -model_center.y, -model_center.z );
|
||||
|
||||
m_ogl_3dmodel->BeginDrawMulti( true );
|
||||
|
||||
m_ogl_3dmodel->DrawOpaque( false );
|
||||
|
||||
glDepthMask( GL_FALSE );
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
m_ogl_3dmodel->DrawTransparent( 1.0f, false );
|
||||
|
||||
glDisable( GL_BLEND );
|
||||
glDepthMask( GL_TRUE );
|
||||
|
||||
m_ogl_3dmodel->EndDrawMulti();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
// YxY squared view port
|
||||
glViewport( 0, 0, clientSize.y / 8 , clientSize.y / 8 );
|
||||
glClear( GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity();
|
||||
gluPerspective( 45.0f, 1.0f, 0.01f, RANGE_SCALE_3D * 2.0f );
|
||||
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
|
||||
const glm::mat4 TranslationMatrix = glm::translate( glm::mat4(1.0f),
|
||||
SFVEC3F( 0.0f, 0.0f, -RANGE_SCALE_3D ) );
|
||||
|
||||
const glm::mat4 ViewMatrix = TranslationMatrix * m_trackBallCamera.GetRotationMatrix();
|
||||
|
||||
glLoadMatrixf( glm::value_ptr( ViewMatrix ) );
|
||||
|
||||
ogl_set_arrow_material();
|
||||
|
||||
glColor3f( 0.9f, 0.0f, 0.0f );
|
||||
DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( RANGE_SCALE_3D / 2.65f, 0.0f, 0.0f ),
|
||||
0.275f );
|
||||
|
||||
glColor3f( 0.0f, 0.9f, 0.0f );
|
||||
DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, RANGE_SCALE_3D / 2.65f, 0.0f ),
|
||||
0.275f );
|
||||
|
||||
glColor3f( 0.0f, 0.0f, 0.9f );
|
||||
DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, 0.0f, RANGE_SCALE_3D / 2.65f ),
|
||||
0.275f );
|
||||
|
||||
// "Swaps the double-buffer of this window, making the back-buffer the
|
||||
// front-buffer and vice versa, so that the output of the previous OpenGL
|
||||
// commands is displayed on the window."
|
||||
SwapBuffers();
|
||||
|
||||
Pgm().GetGLContextManager()->UnlockCtx( m_glRC );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnEraseBackground( wxEraseEvent& event )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnEraseBackground" ) );
|
||||
// Do nothing, to avoid flashing.
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnMouseWheel( wxMouseEvent& event )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnMouseWheel" ) );
|
||||
|
||||
if( event.ShiftDown() )
|
||||
{
|
||||
//if( event.GetWheelRotation() < 0 )
|
||||
//SetView3D( VIEW_3D_TYPE::VIEW3D_PAN_UP ); // move up
|
||||
//else
|
||||
//SetView3D( VIEW_3D_TYPE::VIEW3D_PAN_DOWN ); // move down
|
||||
}
|
||||
else if( event.ControlDown() )
|
||||
{
|
||||
//if( event.GetWheelRotation() > 0 )
|
||||
//SetView3D( VIEW_3D_TYPE::VIEW3D_PAN_RIGHT ); // move right
|
||||
//else
|
||||
//SetView3D( VIEW_3D_TYPE::VIEW3D_PAN_LEFT ); // move left
|
||||
}
|
||||
else
|
||||
{
|
||||
m_trackBallCamera.Zoom( event.GetWheelRotation() > 0 ? 1.1f : 1/1.1f );
|
||||
|
||||
//DisplayStatus();
|
||||
Refresh( false );
|
||||
}
|
||||
|
||||
m_trackBallCamera.SetCurMousePosition( event.GetPosition() );
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_OSX_MAGNIFY_EVENT
|
||||
void EDA_3D_MODEL_VIEWER::OnMagnify( wxMouseEvent& event )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnMouseMove( wxMouseEvent& event )
|
||||
{
|
||||
const wxSize& nativeWinSize = GetNativePixelSize();
|
||||
const wxPoint& nativePosition = GetNativePosition( event.GetPosition() );
|
||||
|
||||
m_trackBallCamera.SetCurWindowSize( nativeWinSize );
|
||||
|
||||
if( event.Dragging() )
|
||||
{
|
||||
if( event.LeftIsDown() ) // Drag
|
||||
m_trackBallCamera.Drag( nativePosition );
|
||||
|
||||
// orientation has changed, redraw mesh
|
||||
Refresh( false );
|
||||
}
|
||||
|
||||
m_trackBallCamera.SetCurMousePosition( nativePosition );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnLeftDown( wxMouseEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnLeftUp( wxMouseEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnMiddleDown( wxMouseEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnMiddleUp( wxMouseEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnRightClick( wxMouseEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file eda_3d_model_viewer.h
|
||||
* @brief Implements a model viewer canvas.
|
||||
*
|
||||
* The purpose of model viewer is to render 3d models that come in the original data from
|
||||
* the files without any transformations.
|
||||
*/
|
||||
|
||||
#ifndef _C3D_MODEL_VIEWER_H_
|
||||
#define _C3D_MODEL_VIEWER_H_
|
||||
|
||||
#include "3d_rendering/track_ball.h"
|
||||
#include <gal/hidpi_gl_canvas.h>
|
||||
|
||||
class S3D_CACHE;
|
||||
class MODEL_3D;
|
||||
|
||||
/**
|
||||
* Implement a canvas based on a wxGLCanvas.
|
||||
*/
|
||||
class EDA_3D_MODEL_VIEWER : public HIDPI_GL_CANVAS
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a new 3D Canvas with a attribute list.
|
||||
*
|
||||
* @param aParent the parent creator of this canvas.
|
||||
* @param aGLAttribs openGL attributes created by #OGL_ATT_LIST::GetAttributesList.
|
||||
*/
|
||||
EDA_3D_MODEL_VIEWER( wxWindow* aParent, const wxGLAttributes& aGLAttribs,
|
||||
S3D_CACHE* aCacheManager = nullptr );
|
||||
|
||||
~EDA_3D_MODEL_VIEWER();
|
||||
|
||||
/**
|
||||
* Set this model to be displayed.
|
||||
*
|
||||
* @param a3DModel 3D model data.
|
||||
*/
|
||||
void Set3DModel( const S3DMODEL& a3DModel );
|
||||
|
||||
/**
|
||||
* Set this model to be displayed.
|
||||
*
|
||||
* N.B. This will not load a model from the internal cache. Only from on disk.
|
||||
*
|
||||
* @param aModelPathName 3D model path name. Must be a file on disk.
|
||||
*/
|
||||
void Set3DModel( const wxString& aModelPathName );
|
||||
|
||||
/**
|
||||
* Unload the displayed 3D model.
|
||||
*/
|
||||
void Clear3DModel();
|
||||
|
||||
private:
|
||||
void ogl_initialize();
|
||||
void ogl_set_arrow_material();
|
||||
|
||||
void OnPaint( wxPaintEvent& event );
|
||||
|
||||
void OnEraseBackground( wxEraseEvent& event );
|
||||
|
||||
void OnMouseWheel( wxMouseEvent& event );
|
||||
|
||||
#ifdef USE_OSX_MAGNIFY_EVENT
|
||||
void OnMagnify( wxMouseEvent& event );
|
||||
#endif
|
||||
|
||||
void OnMouseMove( wxMouseEvent& event );
|
||||
|
||||
void OnLeftDown( wxMouseEvent& event );
|
||||
|
||||
void OnLeftUp( wxMouseEvent& event );
|
||||
|
||||
void OnMiddleUp( wxMouseEvent& event );
|
||||
|
||||
void OnMiddleDown( wxMouseEvent& event );
|
||||
|
||||
void OnRightClick( wxMouseEvent& event );
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
/// openGL context
|
||||
wxGLContext* m_glRC;
|
||||
|
||||
/// Camera used in this canvas
|
||||
TRACK_BALL m_trackBallCamera;
|
||||
|
||||
/// Original 3d model data
|
||||
const S3DMODEL* m_3d_model;
|
||||
|
||||
/// Class holder for 3d model to display on openGL
|
||||
MODEL_3D* m_ogl_3dmodel;
|
||||
|
||||
/// Flag that we have a new model and it need to be reloaded when the paint is called
|
||||
bool m_reload_is_needed;
|
||||
|
||||
/// Flag if open gl was initialized
|
||||
bool m_ogl_initialized;
|
||||
|
||||
/// factor to convert the model or any other items to keep it in relation to
|
||||
/// the +/-RANGE_SCALE_3D
|
||||
/// (it is named same as the board render for better understanding proposes)
|
||||
double m_BiuTo3dUnits;
|
||||
|
||||
/// Optional cache manager
|
||||
S3D_CACHE* m_cacheManager;
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
* The debug output can be turned on by setting the WXTRACE environment variable to
|
||||
* "KI_TRACE_EDA_3D_MODEL_VIEWER". See the wxWidgets documentation on wxLogTrace for
|
||||
* more information.
|
||||
*/
|
||||
static const wxChar* m_logTrace;
|
||||
};
|
||||
|
||||
#endif // _C3D_MODEL_VIEWER_H_
|
||||
@@ -1,27 +0,0 @@
|
||||
add_library(3d-viewer_navlib STATIC
|
||||
"nl_3d_viewer_plugin.cpp"
|
||||
"nl_3d_viewer_plugin_impl.cpp"
|
||||
"nl_footprint_properties_plugin.cpp"
|
||||
"nl_footprint_properties_plugin_impl.cpp"
|
||||
)
|
||||
|
||||
# 3d-viewer_navlib depends on make_lexer outputs in common
|
||||
add_dependencies( 3d-viewer_navlib pcbcommon )
|
||||
|
||||
# Find the 3DxWare SDK component 3DxWare::NlClient
|
||||
# find_package(TDxWare_SDK 4.0 REQUIRED COMPONENTS 3DxWare::Navlib)
|
||||
target_compile_definitions(3d-viewer_navlib PRIVATE
|
||||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_COMPILE_DEFINITIONS>
|
||||
)
|
||||
target_compile_options(3d-viewer_navlib PRIVATE
|
||||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_COMPILE_OPTIONS>
|
||||
)
|
||||
target_include_directories(3d-viewer_navlib PRIVATE
|
||||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:pcbnew_kiface_objects,INCLUDE_DIRECTORIES>
|
||||
)
|
||||
target_link_libraries(3d-viewer_navlib
|
||||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_LINK_LIBRARIES>
|
||||
3DxWare::Navlib
|
||||
)
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021 3Dconnexion
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "nl_3d_viewer_plugin.h"
|
||||
#include "nl_3d_viewer_plugin_impl.h"
|
||||
#include <advanced_config.h>
|
||||
#include <kiplatform/drivers.h>
|
||||
|
||||
|
||||
NL_3D_VIEWER_PLUGIN::NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport )
|
||||
{
|
||||
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver
|
||||
&& KIPLATFORM::DRIVERS::Valid3DConnexionDriverVersion() )
|
||||
{
|
||||
m_impl = std::make_unique<NL_3D_VIEWER_PLUGIN_IMPL>( aViewport, "KiCAD 3D" );
|
||||
m_impl->Connect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NL_3D_VIEWER_PLUGIN::~NL_3D_VIEWER_PLUGIN() = default;
|
||||
|
||||
|
||||
void NL_3D_VIEWER_PLUGIN::SetFocus( bool focus )
|
||||
{
|
||||
if( m_impl )
|
||||
m_impl->SetFocus( focus );
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021 3Dconnexion
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nl_3d_viewer_plugin.h
|
||||
* @brief Declaration of the NL_3D_VIEWER_PLUGIN class
|
||||
*/
|
||||
|
||||
#ifndef NL_3D_VIEWER_PLUGIN_H_
|
||||
#define NL_3D_VIEWER_PLUGIN_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
// Forward declarations.
|
||||
class EDA_3D_CANVAS;
|
||||
class NL_3D_VIEWER_PLUGIN_IMPL;
|
||||
|
||||
/**
|
||||
* The class that implements the public interface to the SpaceMouse plug-in.
|
||||
*/
|
||||
class NL_3D_VIEWER_PLUGIN
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes a new instance of the NL_3D_VIEWER_PLUGIN.
|
||||
*
|
||||
* @param aViewport is the viewport to be navigated.
|
||||
*/
|
||||
NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport );
|
||||
|
||||
virtual ~NL_3D_VIEWER_PLUGIN();
|
||||
|
||||
/**
|
||||
* Set the connection to the 3Dconnexion driver to the focus state so that
|
||||
* 3DMouse data is routed here.
|
||||
*
|
||||
* @param aFocus is true to set the connection active.
|
||||
*/
|
||||
void SetFocus( bool aFocus = true );
|
||||
|
||||
private:
|
||||
std::unique_ptr<NL_3D_VIEWER_PLUGIN_IMPL> m_impl;
|
||||
};
|
||||
|
||||
#endif // NL_3D_VIEWER_PLUGIN_H_
|
||||
@@ -1,663 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2024 3Dconnexion
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "nl_3d_viewer_plugin_impl.h"
|
||||
|
||||
// 3d-viewer
|
||||
#include <3d-viewer/3d_rendering/track_ball.h>
|
||||
#include <3d-viewer/3d_canvas/eda_3d_canvas.h>
|
||||
|
||||
// KiCad includes
|
||||
#include <tool/action_manager.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <tool/tools_holder.h>
|
||||
|
||||
// stdlib
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/mstream.h>
|
||||
|
||||
/**
|
||||
* Flag to enable the NL_3D_VIEWER_PLUGIN debug tracing.
|
||||
*
|
||||
* Use "KI_TRACE_NL_3D_VIEWER_PLUGIN" to enable.
|
||||
*
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
const wxChar* NL_3D_VIEWER_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_3D_VIEWER_PLUGIN" );
|
||||
|
||||
|
||||
/**
|
||||
* Template to compare two glm::mat<T> values for equality within a required epsilon.
|
||||
*
|
||||
* @param aFirst value to compare.
|
||||
* @param aSecond value to compare.
|
||||
* @param aEpsilon allowed error.
|
||||
* @return true if the values considered equal within the specified epsilon, otherwise false.
|
||||
*/
|
||||
template <glm::length_t L, glm::length_t C, class T, glm::qualifier Q>
|
||||
bool equals( glm::mat<L, C, T, Q> const& aFirst, glm::mat<L, C, T, Q> const& aSecond,
|
||||
T aEpsilon = static_cast<T>( FLT_EPSILON * 10 ) )
|
||||
{
|
||||
T const* first = glm::value_ptr( aFirst );
|
||||
T const* second = glm::value_ptr( aSecond );
|
||||
|
||||
for( glm::length_t j = 0; j < L * C; ++j )
|
||||
{
|
||||
if( !equals( first[j], second[j], aEpsilon ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
NL_3D_VIEWER_PLUGIN_IMPL::NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas,
|
||||
const std::string& aProfileHint ) :
|
||||
NAV_3D( false, false ),
|
||||
m_canvas( aCanvas ),
|
||||
m_capIsMoving( false ),
|
||||
m_newWidth( 0.0 )
|
||||
{
|
||||
m_camera = dynamic_cast<TRACK_BALL*>( m_canvas->GetCamera() );
|
||||
|
||||
PutProfileHint( aProfileHint );
|
||||
}
|
||||
|
||||
|
||||
NL_3D_VIEWER_PLUGIN_IMPL::~NL_3D_VIEWER_PLUGIN_IMPL()
|
||||
{
|
||||
EnableNavigation( false );
|
||||
}
|
||||
|
||||
|
||||
void NL_3D_VIEWER_PLUGIN_IMPL::SetFocus( bool aFocus )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "NL_3D_VIEWER_PLUGIN_IMPL::SetFocus %d" ), aFocus );
|
||||
NAV_3D::Write( navlib::focus_k, aFocus );
|
||||
}
|
||||
|
||||
|
||||
EDA_3D_CANVAS* NL_3D_VIEWER_PLUGIN_IMPL::GetCanvas() const
|
||||
{
|
||||
return m_canvas;
|
||||
}
|
||||
|
||||
|
||||
void NL_3D_VIEWER_PLUGIN_IMPL::Connect()
|
||||
{
|
||||
EnableNavigation(true);
|
||||
PutFrameTimingSource(TimingSource::SpaceMouse);
|
||||
exportCommandsAndImages();
|
||||
}
|
||||
|
||||
|
||||
CATEGORY_STORE::iterator add_category( std::string aCategoryPath, CATEGORY_STORE& aCategoryStore )
|
||||
{
|
||||
using TDx::SpaceMouse::CCategory;
|
||||
|
||||
CATEGORY_STORE::iterator parent_iter = aCategoryStore.begin();
|
||||
std::string::size_type pos = aCategoryPath.find_last_of( '.' );
|
||||
|
||||
if( pos != std::string::npos )
|
||||
{
|
||||
std::string parentPath = aCategoryPath.substr( 0, pos );
|
||||
parent_iter = aCategoryStore.find( parentPath );
|
||||
|
||||
if( parent_iter == aCategoryStore.end() )
|
||||
{
|
||||
parent_iter = add_category( parentPath, aCategoryStore );
|
||||
}
|
||||
}
|
||||
|
||||
std::string name = aCategoryPath.substr( pos + 1 );
|
||||
std::unique_ptr<CCategory> categoryNode =
|
||||
std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() );
|
||||
|
||||
CATEGORY_STORE::iterator iter = aCategoryStore.insert(
|
||||
aCategoryStore.end(), CATEGORY_STORE::value_type( aCategoryPath, categoryNode.get() ) );
|
||||
|
||||
parent_iter->second->push_back( std::move( categoryNode ) );
|
||||
return iter;
|
||||
}
|
||||
|
||||
|
||||
void NL_3D_VIEWER_PLUGIN_IMPL::exportCommandsAndImages()
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "NL_3D_VIEWER_PLUGIN_IMPL::exportCommandsAndImages" ) );
|
||||
|
||||
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
|
||||
|
||||
if( actions.size() == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using TDx::SpaceMouse::CCommand;
|
||||
using TDx::SpaceMouse::CCommandSet;
|
||||
|
||||
// The root action set node
|
||||
CCommandSet commandSet( "EDA_3D_CANVAS", "3D Viewer" );
|
||||
|
||||
// Activate the command set
|
||||
NAV_3D::PutActiveCommands( commandSet.GetId() );
|
||||
|
||||
// temporary store for the categories
|
||||
CATEGORY_STORE categoryStore;
|
||||
|
||||
std::vector<TDx::CImage> vImages;
|
||||
|
||||
// add the action set to the category_store
|
||||
categoryStore.insert( categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) );
|
||||
|
||||
std::list<TOOL_ACTION*>::const_iterator it;
|
||||
|
||||
for( it = actions.begin(); it != actions.end(); ++it )
|
||||
{
|
||||
const TOOL_ACTION* action = *it;
|
||||
std::string label = action->GetMenuLabel().ToStdString();
|
||||
|
||||
if( label.empty() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name = action->GetName();
|
||||
|
||||
// Do no export commands for the Pcbnew app.
|
||||
if( name.rfind( "pcbnew.", 0 ) == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string strCategory = action->GetToolName();
|
||||
CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
|
||||
|
||||
if( iter == categoryStore.end() )
|
||||
{
|
||||
iter = add_category( std::move( strCategory ), categoryStore );
|
||||
}
|
||||
|
||||
std::string description = action->GetDescription().ToStdString();
|
||||
|
||||
// Arbitrary 8-bit data stream
|
||||
wxMemoryOutputStream imageStream;
|
||||
|
||||
if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
|
||||
{
|
||||
wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
|
||||
image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
|
||||
image.Destroy();
|
||||
|
||||
if( imageStream.GetSize() )
|
||||
{
|
||||
wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
|
||||
TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
|
||||
tdxImage.AssignImage( std::string( reinterpret_cast<const char*>(
|
||||
streamBuffer->GetBufferStart() ),
|
||||
streamBuffer->GetBufferSize() ),
|
||||
0 );
|
||||
|
||||
wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
|
||||
vImages.push_back( std::move( tdxImage ) );
|
||||
}
|
||||
}
|
||||
|
||||
wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
|
||||
name, description, iter->first );
|
||||
|
||||
iter->second->push_back(
|
||||
CCommand( std::move( name ), std::move( label ), std::move( description ) ) );
|
||||
}
|
||||
|
||||
NAV_3D::AddCommandSet( commandSet );
|
||||
NAV_3D::AddImages( vImages );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
|
||||
{
|
||||
// cache the camera matrix so that we can tell if the view has been moved and
|
||||
// calculate a delta transform if required.
|
||||
m_cameraMatrix = m_camera->GetViewMatrix();
|
||||
|
||||
std::copy_n( glm::value_ptr( glm::inverse( m_cameraMatrix ) ), 16, matrix.m );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
|
||||
{
|
||||
SFVEC3F origin, direction;
|
||||
m_camera->MakeRayAtCurrentMousePosition( origin, direction );
|
||||
|
||||
position = { origin.x, origin.y, origin.z };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
|
||||
{
|
||||
if( m_camera->GetProjection() == PROJECTION_TYPE::PERSPECTIVE )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
||||
}
|
||||
|
||||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
|
||||
|
||||
double half_width = f.fw / 2.;
|
||||
double half_height = f.fh / 2.;
|
||||
extents = { -half_width, -half_height, f.nearD, half_width, half_height, f.farD };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewFOV( double& aFov ) const
|
||||
{
|
||||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
|
||||
|
||||
aFov = glm::radians( f.angle );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& aFrustum ) const
|
||||
{
|
||||
if( m_camera->GetProjection() != PROJECTION_TYPE::PERSPECTIVE )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
||||
}
|
||||
|
||||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
|
||||
double half_width = f.nw / 2.;
|
||||
double half_height = f.nh / 2.;
|
||||
aFrustum = { -half_width, half_width, -half_height, half_height, f.nearD, f.farD };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
|
||||
{
|
||||
perspective = m_camera->GetProjection() == PROJECTION_TYPE::PERSPECTIVE ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& aCameraMatrix )
|
||||
{
|
||||
long result = 0;
|
||||
|
||||
glm::mat4 cam, viewMatrix;
|
||||
std::copy_n( aCameraMatrix.m, 16, glm::value_ptr( cam ) );
|
||||
viewMatrix = glm::inverse( cam );
|
||||
|
||||
glm::mat4 camera = m_camera->GetViewMatrix();
|
||||
|
||||
// The navlib does not move the camera in its z-axis in an orthographic projection
|
||||
// as this does not change the viewed object size. However ...
|
||||
|
||||
if( m_camera->GetProjection() == PROJECTION_TYPE::ORTHO )
|
||||
{
|
||||
// ... the CAMERA class couples zoom and distance to the object: we need to
|
||||
// ensure that The CAMERA's z position relative to the lookat_pos is not changed
|
||||
// in an orthographic projection.
|
||||
glm::vec4 lookat( m_camera->GetLookAtPos(), 1.0f );
|
||||
glm::vec4 lookat_new = viewMatrix * lookat;
|
||||
glm::vec4 lookat_old = camera * lookat;
|
||||
|
||||
viewMatrix[3].z += lookat_old.z - lookat_new.z;
|
||||
}
|
||||
|
||||
if( !equals( camera, m_cameraMatrix ) )
|
||||
{
|
||||
// Some other input device has moved the camera. Apply only the intended delta
|
||||
// transform ...
|
||||
m_camera->SetViewMatrix( viewMatrix * glm::inverse( m_cameraMatrix ) * camera );
|
||||
m_camera->Update();
|
||||
|
||||
// .., cache the intended camera matrix so that we can calculate the delta
|
||||
// transform when needed ...
|
||||
m_cameraMatrix = viewMatrix;
|
||||
|
||||
// ... and let the 3DMouse controller know, that something is amiss.
|
||||
return navlib::make_result_code( navlib::navlib_errc::error );
|
||||
}
|
||||
|
||||
m_camera->SetViewMatrix( viewMatrix );
|
||||
m_camera->Update();
|
||||
|
||||
// cache the view matrix so that we know when it has changed.
|
||||
m_cameraMatrix = m_camera->GetViewMatrix();
|
||||
|
||||
// The camera has a constraint on the z position so we need to check that ...
|
||||
|
||||
if( !equals( m_cameraMatrix[3].z, viewMatrix[3].z ) )
|
||||
{
|
||||
// ... and let the 3DMouse controller know, when something is amiss.
|
||||
return navlib::make_result_code( navlib::navlib_errc::error );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
|
||||
{
|
||||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
|
||||
|
||||
float factor = f.nw / ( extents.max_x - extents.min_x );
|
||||
float zoom = m_camera->GetZoom() / factor;
|
||||
|
||||
m_camera->Zoom( factor );
|
||||
|
||||
// The camera auto positions the camera to match the zoom values. We need to
|
||||
// update our cached camera matrix to match the new z value
|
||||
m_cameraMatrix[3].z = m_camera->GetViewMatrix()[3].z;
|
||||
|
||||
// The camera has a constraint on the zoom factor so we need to check that ...
|
||||
if( zoom != m_camera->GetZoom() )
|
||||
{
|
||||
// ... and let the 3DMouse controller know, when something is amiss.
|
||||
return navlib::make_result_code( navlib::navlib_errc::error );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewFOV( double fov )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::permission_denied );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
|
||||
{
|
||||
SFVEC3F min = m_canvas->GetBoardAdapter().GetBBox().Min();
|
||||
SFVEC3F max = m_canvas->GetBoardAdapter().GetBBox().Max();
|
||||
|
||||
extents = { min.x, min.y, min.z, max.x, max.y, max.z };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsSelectionEmpty( navlib::bool_t& empty ) const
|
||||
{
|
||||
empty = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
|
||||
{
|
||||
SFVEC3F lap = m_camera->GetLookAtPos();
|
||||
|
||||
position = { lap.x, lap.y, lap.z };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
|
||||
{
|
||||
userPivot = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
|
||||
{
|
||||
SFVEC3F pivotPos = SFVEC3F( position.x, position.y, position.z );
|
||||
|
||||
// Set the 3dmouse pivot position.
|
||||
m_canvas->Set3dmousePivotPos( pivotPos );
|
||||
|
||||
// Set the camera lookat pos.
|
||||
m_camera->SetLookAtPos_T1( pivotPos );
|
||||
|
||||
m_canvas->Request_refresh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
|
||||
{
|
||||
visible = m_canvas->GetRender3dmousePivot();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetPivotVisible( bool visible )
|
||||
{
|
||||
m_canvas->SetRender3dmousePivot( visible );
|
||||
|
||||
m_canvas->Request_refresh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
|
||||
{
|
||||
RAY mouseRay;
|
||||
mouseRay.Init( m_rayOrigin, m_rayDirection );
|
||||
|
||||
float hit;
|
||||
glm::vec3 vec;
|
||||
|
||||
// Test it with the board bounding box
|
||||
|
||||
if( m_canvas->GetBoardAdapter().GetBBox().Intersect( mouseRay, &hit ) )
|
||||
{
|
||||
vec = mouseRay.at( hit );
|
||||
position = { vec.x, vec.y, vec.z };
|
||||
return 0;
|
||||
}
|
||||
|
||||
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitAperture( double aperture )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
|
||||
{
|
||||
m_rayDirection = { direction.x, direction.y, direction.z };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
|
||||
{
|
||||
m_rayOrigin = { eye.x, eye.y, eye.z };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitSelectionOnly( bool onlySelection )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetActiveCommand( std::string commandId )
|
||||
{
|
||||
if( commandId.empty() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
|
||||
TOOL_ACTION* context = nullptr;
|
||||
|
||||
for( std::list<TOOL_ACTION*>::const_iterator it = actions.begin(); it != actions.end(); it++ )
|
||||
{
|
||||
TOOL_ACTION* action = *it;
|
||||
std::string nm = action->GetName();
|
||||
|
||||
if( commandId == nm )
|
||||
{
|
||||
context = action;
|
||||
}
|
||||
}
|
||||
|
||||
if( context != nullptr )
|
||||
{
|
||||
wxWindow* parent = m_canvas->GetParent();
|
||||
|
||||
// Only allow command execution if the window is enabled. i.e. there is not a modal dialog
|
||||
// currently active.
|
||||
TOOLS_HOLDER* tools_holder = nullptr;
|
||||
|
||||
if( parent->IsEnabled() && ( tools_holder = dynamic_cast<TOOLS_HOLDER*>( parent ) ) )
|
||||
{
|
||||
TOOL_MANAGER* tool_manager = tools_holder->GetToolManager();
|
||||
|
||||
if( tool_manager == nullptr )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
||||
}
|
||||
|
||||
// Get the selection to use to test if the action is enabled
|
||||
SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
|
||||
|
||||
bool runAction = true;
|
||||
|
||||
if( const ACTION_CONDITIONS* aCond =
|
||||
tool_manager->GetActionManager()->GetCondition( *context ) )
|
||||
{
|
||||
runAction = aCond->enableCondition( sel );
|
||||
}
|
||||
|
||||
if( runAction )
|
||||
{
|
||||
tool_manager->RunAction( *context );
|
||||
m_canvas->Request_refresh();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetSettingsChanged( long change )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetMotionFlag( bool value )
|
||||
{
|
||||
m_capIsMoving = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetTransaction( long value )
|
||||
{
|
||||
if( value != 0L )
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
m_canvas->Request_refresh( true );
|
||||
wxLogTrace( m_logTrace, wxT( "End of transaction" ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
|
||||
{
|
||||
matrix = { 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1 };
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
|
||||
{
|
||||
// Use the right-handed coordinate system X-right, Z-up, Y-in (row vectors)
|
||||
matrix = { 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1 };
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
|
||||
{
|
||||
isRotatable = true;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2024 3Dconnexion
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nl_3d_viewer_plugin_impl.h
|
||||
* @brief Declaration of the NL_3D_VIEWER_PLUGIN_IMPL class
|
||||
*/
|
||||
|
||||
#ifndef NL_3D_VIEWER_PLUGIN_IMPL_H_
|
||||
#define NL_3D_VIEWER_PLUGIN_IMPL_H_
|
||||
|
||||
// TDxWare SDK.
|
||||
#include <SpaceMouse/CNavigation3D.hpp>
|
||||
|
||||
// KiCad
|
||||
#include <include/plugins/3dapi/xv3d_types.h>
|
||||
|
||||
// wx
|
||||
#include <wx/chartype.h>
|
||||
|
||||
// glm
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
// Forward declarations.
|
||||
class EDA_3D_CANVAS;
|
||||
class TRACK_BALL;
|
||||
|
||||
// temporary store for the categories
|
||||
typedef std::map<std::string, TDx::CCommandTreeNode*> CATEGORY_STORE;
|
||||
|
||||
/**
|
||||
* Add a category to the store.
|
||||
*
|
||||
* The function adds category paths of the format "A.B" where B is a sub-category of A.
|
||||
*
|
||||
* @param aCategoryPath is the std::string representation of the category.
|
||||
* @param aCategoryStore is the CATEGORY_STORE instance to add to.
|
||||
* @return a CATEGORY_STORE::iterator where the category was added.
|
||||
*/
|
||||
CATEGORY_STORE::iterator add_category( std::string aCategoryPath, CATEGORY_STORE& aCategoryStore );
|
||||
|
||||
// Convenience typedef.
|
||||
typedef TDx::SpaceMouse::Navigation3D::CNavigation3D NAV_3D;
|
||||
|
||||
/**
|
||||
* The class that implements the accessors and mutators required for
|
||||
* 3D navigation in an EDA_3D_CANVAS using a SpaceMouse.
|
||||
*/
|
||||
class NL_3D_VIEWER_PLUGIN_IMPL : public NAV_3D
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes a new instance of the NL_3DVIEWER_PLUGIN.
|
||||
*
|
||||
* @param aCanvas is the viewport to be navigated.
|
||||
* @param aProfileHint tells the 3DConnexion UI which profile to use.
|
||||
*/
|
||||
NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas, const std::string& aProfileHint );
|
||||
|
||||
virtual ~NL_3D_VIEWER_PLUGIN_IMPL();
|
||||
|
||||
/**
|
||||
* Set the connection to the 3Dconnexion driver to the focus state so that
|
||||
* 3DMouse data is routed here.
|
||||
*
|
||||
* @param aFocus is true to set the connection active.
|
||||
*/
|
||||
void SetFocus( bool aFocus = true );
|
||||
|
||||
/**
|
||||
* Get the m_canvas pointer.
|
||||
*/
|
||||
EDA_3D_CANVAS* GetCanvas() const;
|
||||
|
||||
/**
|
||||
* Connect plugin implementation to the driver.
|
||||
*/
|
||||
void Connect();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Export the invocable actions and images to the 3Dconnexion UI.
|
||||
*/
|
||||
virtual void exportCommandsAndImages();
|
||||
|
||||
long GetCameraMatrix( navlib::matrix_t& aMatrix ) const override;
|
||||
long GetPointerPosition( navlib::point_t& aPosition ) const override;
|
||||
long GetViewExtents( navlib::box_t& aExtents ) const override;
|
||||
long GetViewFOV( double& aFov ) const override;
|
||||
long GetViewFrustum( navlib::frustum_t& aFrustum ) const override;
|
||||
long GetIsViewPerspective( navlib::bool_t& aPerspective ) const override;
|
||||
long SetCameraMatrix( const navlib::matrix_t& aMatrix ) override;
|
||||
long SetViewExtents( const navlib::box_t& aExtents ) override;
|
||||
long SetViewFOV( double aFov ) override;
|
||||
long SetViewFrustum( const navlib::frustum_t& aFrustum ) override;
|
||||
long GetModelExtents( navlib::box_t& aExtents ) const override;
|
||||
long GetSelectionExtents( navlib::box_t& aExtents ) const override;
|
||||
long GetSelectionTransform( navlib::matrix_t& aTransform ) const override;
|
||||
long GetIsSelectionEmpty( navlib::bool_t& aEmpty ) const override;
|
||||
long SetSelectionTransform( const navlib::matrix_t& aMatrix ) override;
|
||||
long GetPivotPosition( navlib::point_t& aPosition ) const override;
|
||||
long IsUserPivot( navlib::bool_t& aUserPivot ) const override;
|
||||
long SetPivotPosition( const navlib::point_t& aPosition ) override;
|
||||
long GetPivotVisible( navlib::bool_t& aVisible ) const override;
|
||||
long SetPivotVisible( bool aVisible ) override;
|
||||
long GetHitLookAt( navlib::point_t& aPosition ) const override;
|
||||
long SetHitAperture( double aAperture ) override;
|
||||
long SetHitDirection( const navlib::vector_t& aDirection ) override;
|
||||
long SetHitLookFrom( const navlib::point_t& aPosition ) override;
|
||||
long SetHitSelectionOnly( bool aSelectionOnly ) override;
|
||||
long SetActiveCommand( std::string aCommandId ) override;
|
||||
|
||||
long SetSettingsChanged( long aChangeNumber ) override;
|
||||
long SetMotionFlag( bool aValue ) override;
|
||||
long SetTransaction( long aValue ) override;
|
||||
long SetCameraTarget( const navlib::point_t& aPosition ) override;
|
||||
|
||||
long GetFrontView( navlib::matrix_t& aMatrix ) const override;
|
||||
long GetCoordinateSystem( navlib::matrix_t& aMatrix ) const override;
|
||||
long GetIsViewRotatable( navlib::bool_t& isRotatable ) const override;
|
||||
|
||||
|
||||
private:
|
||||
EDA_3D_CANVAS* m_canvas;
|
||||
TRACK_BALL* m_camera;
|
||||
bool m_capIsMoving;
|
||||
double m_newWidth;
|
||||
SFVEC3F m_rayOrigin;
|
||||
SFVEC3F m_rayDirection;
|
||||
|
||||
// The cached CAMERA affine matrix. This is used to determine if the camera has been
|
||||
// moved. The camera matrix is the world to camera affine.
|
||||
mutable glm::mat4 m_cameraMatrix;
|
||||
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
* The debug output can be turned on by setting the WXTRACE environment variable to
|
||||
* "KI_TRACE_NL_3DVIEWER_PLUGIN". See the wxWidgets documentation on wxLogTrace for
|
||||
* more information.
|
||||
*/
|
||||
static const wxChar* m_logTrace;
|
||||
};
|
||||
|
||||
#endif // NL_3D_VIEWER_PLUGIN_IMPL_H_
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2024 3Dconnexion
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "nl_footprint_properties_plugin.h"
|
||||
#include "nl_footprint_properties_plugin_impl.h"
|
||||
#include <advanced_config.h>
|
||||
#include <kiplatform/drivers.h>
|
||||
|
||||
|
||||
NL_FOOTPRINT_PROPERTIES_PLUGIN::NL_FOOTPRINT_PROPERTIES_PLUGIN( EDA_3D_CANVAS* aViewport )
|
||||
{
|
||||
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver
|
||||
&& KIPLATFORM::DRIVERS::Valid3DConnexionDriverVersion() )
|
||||
{
|
||||
m_impl = std::make_unique<NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL>( aViewport );
|
||||
m_impl->Connect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NL_FOOTPRINT_PROPERTIES_PLUGIN::~NL_FOOTPRINT_PROPERTIES_PLUGIN() = default;
|
||||
|
||||
|
||||
void NL_FOOTPRINT_PROPERTIES_PLUGIN::SetFocus( bool focus )
|
||||
{
|
||||
if( m_impl )
|
||||
m_impl->SetFocus( focus );
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2024 3Dconnexion
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nl_footprint_properties_plugin.h
|
||||
* @brief declaration of the nl_footprint_properties_plugin class
|
||||
*/
|
||||
|
||||
#ifndef NL_FOOTPRINT_PROPERTIES_PLUGIN_H_
|
||||
#define NL_FOOTPRINT_PROPERTIES_PLUGIN_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
// Forward declarations.
|
||||
class EDA_3D_CANVAS;
|
||||
class NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL;
|
||||
|
||||
/**
|
||||
* The class that implements the public interface to the SpaceMouse plug-in.
|
||||
*/
|
||||
class NL_FOOTPRINT_PROPERTIES_PLUGIN
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes a new instance of the NL_FOOTPRINT_PROPERTIES_PLUGIN.
|
||||
*
|
||||
* @param aViewport is the viewport to be navigated.
|
||||
*/
|
||||
NL_FOOTPRINT_PROPERTIES_PLUGIN( EDA_3D_CANVAS* aViewport );
|
||||
|
||||
virtual ~NL_FOOTPRINT_PROPERTIES_PLUGIN();
|
||||
|
||||
/**
|
||||
* Set the connection to the 3Dconnexion driver to the focus state so that
|
||||
* 3DMouse data is routed here.
|
||||
*
|
||||
* @param aFocus is true to set the connection active.
|
||||
*/
|
||||
void SetFocus( bool aFocus = true );
|
||||
|
||||
private:
|
||||
std::unique_ptr<NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL> m_impl;
|
||||
};
|
||||
|
||||
#endif // NL_FOOTPRINT_PROPERTIES_PLUGIN_H_
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2024 3Dconnexion
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "nl_footprint_properties_plugin_impl.h"
|
||||
#include <3d-viewer/3d_canvas/eda_3d_canvas.h>
|
||||
|
||||
// KiCAD includes
|
||||
#include <tool/action_manager.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <tool/tools_holder.h>
|
||||
|
||||
#include <wx/mstream.h>
|
||||
|
||||
#define BOUNDING_BOX_SCALE_FACTOR 1.3f
|
||||
|
||||
/**
|
||||
* Flag to enable the NL_FOOTPRINT_PROPERTIES_PLUGIN debug tracing.
|
||||
*
|
||||
* Use "KI_TRACE_NL_FOOTPRINT_PROPERTIES_PLUGIN" to enable.
|
||||
*
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
const wxChar* NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::m_logTrace =
|
||||
wxT( "KI_TRACE_NL_FOOTPRINT_PROPERTIES_PLUGIN" );
|
||||
|
||||
|
||||
NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL(EDA_3D_CANVAS* aCanvas) :
|
||||
NL_3D_VIEWER_PLUGIN_IMPL(aCanvas, "KiCAD Footprint Properties")
|
||||
{}
|
||||
|
||||
|
||||
long NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
|
||||
{
|
||||
SFVEC3F min = NL_3D_VIEWER_PLUGIN_IMPL::GetCanvas()->GetBoardAdapter().GetBBox().Min();
|
||||
SFVEC3F max = NL_3D_VIEWER_PLUGIN_IMPL::GetCanvas()->GetBoardAdapter().GetBBox().Max();
|
||||
|
||||
SFVEC3F diff = ( BOUNDING_BOX_SCALE_FACTOR - 1.f ) / 2.f * ( max - min );
|
||||
|
||||
min -= diff;
|
||||
max += diff;
|
||||
|
||||
extents = { min.x, min.y, min.z, max.x, max.y, max.z };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::exportCommandsAndImages()
|
||||
{
|
||||
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
|
||||
|
||||
if( actions.size() == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using TDx::SpaceMouse::CCommand;
|
||||
using TDx::SpaceMouse::CCommandSet;
|
||||
|
||||
// The root action set node
|
||||
CCommandSet commandSet( "EDA_3D_CANVAS", "3D Viewer" );
|
||||
|
||||
// Activate the command set
|
||||
NAV_3D::PutActiveCommands( commandSet.GetId() );
|
||||
|
||||
// temporary store for the categories
|
||||
CATEGORY_STORE categoryStore;
|
||||
|
||||
std::vector<TDx::CImage> vImages;
|
||||
|
||||
// add the action set to the category_store
|
||||
categoryStore.insert( categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) );
|
||||
|
||||
std::list<TOOL_ACTION*>::const_iterator it;
|
||||
|
||||
for( it = actions.begin(); it != actions.end(); ++it )
|
||||
{
|
||||
const TOOL_ACTION* action = *it;
|
||||
std::string label = action->GetMenuLabel().ToStdString();
|
||||
|
||||
if( label.empty() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name = action->GetName();
|
||||
|
||||
// Do no export commands for the pcbnew app.
|
||||
if( name.rfind( "pcbnew.", 0 ) == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude commands which can't be used in the footprint properties.
|
||||
if( name.rfind( "3DViewer.Control.pivotCenter", 0 ) == 0
|
||||
|| name.rfind( "3DViewer.Control.material", 0 ) == 0
|
||||
|| name.rfind( "3DViewer.Control.attribute", 0 ) == 0
|
||||
|| name.rfind( "3DViewer.Control.show", 0 ) == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string strCategory = action->GetToolName();
|
||||
CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
|
||||
|
||||
if( iter == categoryStore.end() )
|
||||
{
|
||||
iter = add_category( std::move( strCategory ), categoryStore );
|
||||
}
|
||||
|
||||
std::string description = action->GetDescription().ToStdString();
|
||||
|
||||
// Arbitrary 8-bit data stream
|
||||
wxMemoryOutputStream imageStream;
|
||||
|
||||
if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
|
||||
{
|
||||
wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
|
||||
image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
|
||||
image.Destroy();
|
||||
|
||||
if( imageStream.GetSize() )
|
||||
{
|
||||
wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
|
||||
TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
|
||||
tdxImage.AssignImage( std::string( reinterpret_cast<const char*>(
|
||||
streamBuffer->GetBufferStart() ),
|
||||
streamBuffer->GetBufferSize() ),
|
||||
0 );
|
||||
|
||||
wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
|
||||
vImages.push_back( std::move( tdxImage ) );
|
||||
}
|
||||
}
|
||||
|
||||
wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
|
||||
name, description, iter->first );
|
||||
|
||||
iter->second->push_back(
|
||||
CCommand( std::move( name ), std::move( label ), std::move( description ) ) );
|
||||
}
|
||||
|
||||
NAV_3D::AddCommandSet( commandSet );
|
||||
NAV_3D::AddImages( vImages );
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2024 3Dconnexion
|
||||
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nl_footprint_properties_plugin_impl.h
|
||||
* @brief declaration of the nl_footprint_properties_plugin_impl class
|
||||
*/
|
||||
|
||||
#ifndef NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL_H_
|
||||
#define NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL_H_
|
||||
|
||||
#include "nl_3d_viewer_plugin_impl.h"
|
||||
// TDxWare SDK.
|
||||
#include <SpaceMouse/CNavigation3D.hpp>
|
||||
|
||||
/**
|
||||
* The class that adjusts NL_3D_VIEWER_PLUGIN_IMPL implementation for 3D Model preview in
|
||||
* footprint properties dialog.
|
||||
*/
|
||||
class NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL : public NL_3D_VIEWER_PLUGIN_IMPL
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initialize a new instance of the NL_FOOTPRINT_PROPERTIES_PLUGIN.
|
||||
*
|
||||
* @param aCanvas is the viewport to be navigated.
|
||||
*/
|
||||
NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas );
|
||||
|
||||
private:
|
||||
/**
|
||||
* Get Footprint 3D Model extents.
|
||||
*
|
||||
* @param extents is the box around the 3D model.
|
||||
*/
|
||||
long GetModelExtents( navlib::box_t& extents ) const override;
|
||||
|
||||
/**
|
||||
* Export the invocable actions and images to the 3Dconnexion UI.
|
||||
*/
|
||||
void exportCommandsAndImages() override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
* The debug output can be turned on by setting the WXTRACE environment variable to
|
||||
* "KI_TRACE_NL_FOOTPRINT_PROPERTIES_PLUGIN". See the wxWidgets documentation on
|
||||
* wxLogTrace for more information.
|
||||
*/
|
||||
static const wxChar* m_logTrace;
|
||||
};
|
||||
#endif // NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL_H_
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras@wanadoo.fr
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_read_mesh.cpp
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <common.h>
|
||||
#include <macros.h>
|
||||
#include <kicad_string.h>
|
||||
#include <pgm_base.h>
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
|
||||
#include <3d_viewer.h>
|
||||
#include <info3d_visu.h>
|
||||
#include "3d_struct.h"
|
||||
#include "modelparsers.h"
|
||||
|
||||
|
||||
S3D_MODEL_PARSER *S3D_MODEL_PARSER::Create( S3D_MASTER* aMaster,
|
||||
const wxString aExtension )
|
||||
{
|
||||
if ( aExtension == wxT( "x3d" ) )
|
||||
return new X3D_MODEL_PARSER( aMaster );
|
||||
else if ( aExtension == wxT( "wrl" ) )
|
||||
return new VRML_MODEL_PARSER( aMaster );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int S3D_MASTER::ReadData( S3D_MODEL_PARSER* aParser )
|
||||
{
|
||||
if( m_Shape3DFullFilename.IsEmpty() || aParser == NULL )
|
||||
return -1;
|
||||
|
||||
wxString filename = m_Shape3DFullFilename;
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
filename.Replace( wxT( "/" ), wxT( "\\" ) );
|
||||
#else
|
||||
filename.Replace( wxT( "\\" ), wxT( "/" ) );
|
||||
#endif
|
||||
|
||||
if( wxFileName::FileExists( filename ) )
|
||||
{
|
||||
wxFileName fn( filename );
|
||||
|
||||
if( aParser->Load( filename ) )
|
||||
{
|
||||
// Invalidate bounding boxes
|
||||
m_fastAABBox.Reset();
|
||||
m_BBox.Reset();
|
||||
|
||||
m_parser = aParser;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
wxLogDebug( wxT( "3D shape '%s' not found, even tried '%s' after env var substitution." ),
|
||||
GetChars( m_Shape3DName ),
|
||||
GetChars( filename ) );
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void S3D_MASTER::Render( bool aIsRenderingJustNonTransparentObjects,
|
||||
bool aIsRenderingJustTransparentObjects )
|
||||
{
|
||||
if( m_parser == NULL )
|
||||
return;
|
||||
|
||||
double aVrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
|
||||
|
||||
glScalef( aVrmlunits_to_3Dunits, aVrmlunits_to_3Dunits, aVrmlunits_to_3Dunits );
|
||||
|
||||
glTranslatef( m_MatPosition.x * SCALE_3D_CONV,
|
||||
m_MatPosition.y * SCALE_3D_CONV,
|
||||
m_MatPosition.z * SCALE_3D_CONV );
|
||||
|
||||
glRotatef( -m_MatRotation.z, 0.0f, 0.0f, 1.0f );
|
||||
glRotatef( -m_MatRotation.y, 0.0f, 1.0f, 0.0f );
|
||||
glRotatef( -m_MatRotation.x, 1.0f, 0.0f, 0.0f );
|
||||
|
||||
glScalef( m_MatScale.x, m_MatScale.y, m_MatScale.z );
|
||||
|
||||
for( unsigned int idx = 0; idx < m_parser->childs.size(); idx++ )
|
||||
m_parser->childs[idx]->openGL_RenderAllChilds( aIsRenderingJustNonTransparentObjects,
|
||||
aIsRenderingJustTransparentObjects );
|
||||
}
|
||||
|
||||
|
||||
CBBOX &S3D_MASTER::getBBox( )
|
||||
{
|
||||
if( !m_BBox.IsInitialized() )
|
||||
calcBBox();
|
||||
|
||||
return m_BBox;
|
||||
}
|
||||
|
||||
|
||||
CBBOX &S3D_MASTER::getFastAABBox( )
|
||||
{
|
||||
if( !m_fastAABBox.IsInitialized() )
|
||||
calcBBox();
|
||||
|
||||
return m_fastAABBox;
|
||||
}
|
||||
|
||||
|
||||
void S3D_MASTER::calcBBox()
|
||||
{
|
||||
if( m_parser == NULL )
|
||||
return;
|
||||
|
||||
bool firstBBox = true;
|
||||
|
||||
for( unsigned int idx = 0; idx < m_parser->childs.size(); idx++ )
|
||||
if( firstBBox )
|
||||
{
|
||||
firstBBox = false;
|
||||
m_BBox = m_parser->childs[idx]->getBBox();
|
||||
}
|
||||
else
|
||||
m_BBox.Union( m_parser->childs[idx]->getBBox() );
|
||||
|
||||
// Calc transformation matrix to apply in AABBox
|
||||
|
||||
float aVrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
|
||||
|
||||
glm::mat4 fullTransformMatrix;
|
||||
|
||||
fullTransformMatrix = glm::scale( glm::mat4(), S3D_VERTEX( aVrmlunits_to_3Dunits,
|
||||
aVrmlunits_to_3Dunits,
|
||||
aVrmlunits_to_3Dunits ) );
|
||||
|
||||
fullTransformMatrix = glm::translate( fullTransformMatrix, S3D_VERTEX( m_MatPosition.x * SCALE_3D_CONV,
|
||||
m_MatPosition.y * SCALE_3D_CONV,
|
||||
m_MatPosition.z * SCALE_3D_CONV) );
|
||||
|
||||
if( m_MatRotation.z != 0.0 )
|
||||
fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians(-(float)m_MatRotation.z), S3D_VERTEX( 0.0f, 0.0f, 1.0f ) );
|
||||
if( m_MatRotation.y != 0.0 )
|
||||
fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians(-(float)m_MatRotation.y), S3D_VERTEX( 0.0f, 1.0f, 0.0f ) );
|
||||
if( m_MatRotation.x != 0.0 )
|
||||
fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians(-(float)m_MatRotation.x), S3D_VERTEX( 1.0f, 0.0f, 0.0f ) );
|
||||
|
||||
fullTransformMatrix = glm::scale( fullTransformMatrix, S3D_VERTEX( m_MatScale.x, m_MatScale.y, m_MatScale.z ) );
|
||||
|
||||
// Apply transformation
|
||||
m_fastAABBox = m_BBox;
|
||||
m_fastAABBox.ApplyTransformationAA( fullTransformMatrix );
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user