Compare commits
10 Commits
e6ada5028d
...
b921c3b5cd
Author | SHA1 | Date |
---|---|---|
Sofus Albert Høgsbro Rose | b921c3b5cd | |
Sofus Albert Høgsbro Rose | 0d5c9b78f7 | |
Sofus Albert Høgsbro Rose | fdcd52e937 | |
Sofus Albert Høgsbro Rose | 06ad0d62a5 | |
Sofus Albert Høgsbro Rose | 383f7d9bfd | |
Sofus Albert Høgsbro Rose | 55235c7032 | |
Sofus Albert Høgsbro Rose | 12362b3cbd | |
Sofus Albert Høgsbro Rose | 606d336683 | |
Sofus Albert Høgsbro Rose | 514b49160e | |
Sofus Albert Høgsbro Rose | ad548b8f03 |
|
@ -20,17 +20,27 @@ repos:
|
|||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.4.3
|
||||
rev: v0.6.8
|
||||
hooks:
|
||||
# ruff lint
|
||||
#- id: ruff
|
||||
# args: [ --fix ]
|
||||
#args: [ --fix ]
|
||||
# ruff fmt
|
||||
- id: ruff-format
|
||||
|
||||
- repo: https://github.com/commitizen-tools/commitizen
|
||||
rev: master
|
||||
rev: v3.29.1
|
||||
hooks:
|
||||
- id: commitizen
|
||||
- id: commitizen-branch
|
||||
stages: [push]
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: pytest
|
||||
name: pytest
|
||||
entry: ./.venv/bin/pytest tests
|
||||
language: system
|
||||
types: [python]
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
|
|
|
@ -14,221 +14,88 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""A visual DSL for electromagnetic simulation design and analysis implemented as a Blender node editor."""
|
||||
|
||||
"""A Blender-based system for electromagnetic simulation design and analysis, with deep Tidy3D integration.
|
||||
from functools import reduce
|
||||
|
||||
# `bl_info`
|
||||
`bl_info` declares information about the addon to Blender.
|
||||
from . import contracts as ct
|
||||
|
||||
However, it is not _dynamically_ read: Blender traverses it using `ast.parse`.
|
||||
This makes it difficult to synchronize `bl_info` with the project's `pyproject.toml`.
|
||||
As a workaround, **the addon zip-packer will replace `bl_info` entries**.
|
||||
# from . import node_trees
|
||||
from . import operators, preferences, registration
|
||||
from .utils import logger
|
||||
|
||||
The following `bl_info` entries are currently replaced when the ZIP is built:
|
||||
|
||||
- `description`: To match the description in `pyproject.toml`.
|
||||
- `version`: To match the version in `pyproject.toml`.
|
||||
|
||||
For more information, see `scripts.pack.BL_INFO_REPLACEMENTS`.
|
||||
|
||||
**NOTE**: The find/replace procedure is "dumb" (aka. no regex, no `ast` traversal, etc.).
|
||||
|
||||
This is surprisingly robust, so long as use of the deterministic code-formatter `ruff fmt` is enforced.
|
||||
|
||||
Still. Be careful around `bl_info`.
|
||||
|
||||
Attributes:
|
||||
bl_info: Information about the addon declared to Blender.
|
||||
BL_REGISTER_BEFORE_DEPS: Blender classes to register before dependencies are verified as installed.
|
||||
BL_HOTKEYS: Blender keymap item defs to register before dependencies are verified as installed.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from .nodeps.utils import simple_logger
|
||||
|
||||
# Initialize Logging Defaults
|
||||
## Initial logger settings (ex. log level) must be set somehow.
|
||||
## The Addon ZIP-packer makes this decision, and packs it into files.
|
||||
## AddonPreferences will, once loaded, override this.
|
||||
_PATH_ADDON_ROOT = Path(__file__).resolve().parent
|
||||
_PATH_BOOTSTRAP_LOG_LEVEL = _PATH_ADDON_ROOT / '.bootstrap_log_level'
|
||||
with _PATH_BOOTSTRAP_LOG_LEVEL.open('r') as f:
|
||||
_BOOTSTRAP_LOG_LEVEL = int(f.read().strip())
|
||||
|
||||
simple_logger.init_simple_logger_defaults(console_level=_BOOTSTRAP_LOG_LEVEL)
|
||||
|
||||
# Import Statements
|
||||
import bpy # noqa: E402
|
||||
|
||||
from . import contracts as ct # noqa: E402
|
||||
from . import preferences, registration # noqa: E402
|
||||
from .nodeps import operators as nodeps_operators # noqa: E402
|
||||
from .nodeps.utils import pydeps # noqa: E402
|
||||
|
||||
log = simple_logger.get(__name__)
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
||||
####################
|
||||
# - Load and Register Addon
|
||||
####################
|
||||
BL_REGISTER_BEFORE_DEPS: list[ct.BLClass] = [
|
||||
*nodeps_operators.BL_REGISTER,
|
||||
*preferences.BL_REGISTER,
|
||||
]
|
||||
|
||||
## TODO: BL_HANDLERS and BL_SOCKET_DEFS
|
||||
|
||||
BL_HOTKEYS_BEFORE_DEPS: list[ct.KeymapItemDef] = [
|
||||
*nodeps_operators.BL_HOTKEYS,
|
||||
]
|
||||
|
||||
|
||||
def load_main_blclasses(path_pydeps: Path) -> list[ct.BLClass]:
|
||||
"""Imports all addon classes that rely on Python dependencies.
|
||||
|
||||
Notes:
|
||||
`sys.path` is modified while executing this function.
|
||||
|
||||
Parameters:
|
||||
path_pydeps: The path to the Python dependencies.
|
||||
|
||||
Returns:
|
||||
An ordered list of Blender classes to register.
|
||||
"""
|
||||
with pydeps.importable_addon_deps(path_pydeps):
|
||||
from . import assets, node_trees, operators
|
||||
return [
|
||||
BL_REGISTER: list[ct.BLClass] = [
|
||||
*operators.BL_REGISTER,
|
||||
*assets.BL_REGISTER,
|
||||
*node_trees.BL_REGISTER,
|
||||
]
|
||||
# *node_trees.BL_REGISTER,
|
||||
]
|
||||
|
||||
BL_HANDLERS: ct.BLHandlers = reduce(
|
||||
lambda a, b: a + b,
|
||||
[
|
||||
operators.BL_HANDLERS,
|
||||
# node_trees.BL_HANDLERS,
|
||||
],
|
||||
ct.BLHandlers(),
|
||||
)
|
||||
|
||||
def load_main_blhotkeys(path_deps: Path) -> list[ct.KeymapItemDef]:
|
||||
"""Imports all keymap item defs that rely on Python dependencies.
|
||||
|
||||
Notes:
|
||||
`sys.path` is modified while executing this function.
|
||||
|
||||
Parameters:
|
||||
path_pydeps: The path to the Python dependencies.
|
||||
|
||||
Returns:
|
||||
An ordered list of Blender keymap item defs to register.
|
||||
"""
|
||||
with pydeps.importable_addon_deps(path_deps):
|
||||
from . import assets, operators
|
||||
return [
|
||||
*operators.BL_HOTKEYS,
|
||||
*assets.BL_HOTKEYS,
|
||||
]
|
||||
BL_KEYMAP_ITEMS: list[ct.BLKeymapItem] = [
|
||||
*operators.BL_KEYMAP_ITEMS,
|
||||
# node_trees.BL_KEYMAP_ITEMS,
|
||||
]
|
||||
|
||||
|
||||
####################
|
||||
# - Registration
|
||||
####################
|
||||
@bpy.app.handlers.persistent
|
||||
def manage_pydeps(*_):
|
||||
# ct.addon.operator(
|
||||
# ct.OperatorType.ManagePyDeps,
|
||||
# 'INVOKE_DEFAULT',
|
||||
# path_addon_pydeps='',
|
||||
# path_addon_reqs='',
|
||||
# )
|
||||
log.debug('PyDeps: Analyzing Post-File Load')
|
||||
ct.addon.prefs().on_addon_pydeps_changed(show_popup_if_deps_invalid=True)
|
||||
|
||||
|
||||
def register() -> None:
|
||||
"""Implements a multi-stage addon registration, which accounts for Python dependency management.
|
||||
|
||||
# Multi-Stage Registration
|
||||
The trouble is that many classes in our addon might require Python dependencies.
|
||||
|
||||
## Stage 1: Barebones Addon
|
||||
Many classes in our addon might require Python dependencies.
|
||||
However, they may not yet be installed.
|
||||
|
||||
To solve this bootstrapping problem in a streamlined manner, we only **guarantee** the registration of a few key classes, including:
|
||||
|
||||
- `AddonPreferences`: The addon preferences provide an interface for the user to fix Python dependency problems, thereby triggering subsequent stages.
|
||||
- `InstallPyDeps`: An operator that installs missing Python dependencies, using Blender's embeded `pip`.
|
||||
- `UninstallPyDeps`: An operator that uninstalls Python dependencies.
|
||||
|
||||
**These classes provide just enough interface to help the user install the missing Python dependencies**.
|
||||
|
||||
## Stage 2: Declare Delayed Registration
|
||||
We may not be able to register any classes that rely on Python dependencies.
|
||||
However, we can use `registration.delay_registration()` to **delay the registration until it is determined that the Python dependencies are satisfied**.`
|
||||
|
||||
For now, we just pass a callback that will import + return a list of classes to register (`load_main_blclasses()`) when the time comes.
|
||||
|
||||
## Stage 3: Trigger "PyDeps Changed"
|
||||
The addon preferences is responsible for storing (and exposing to the user) the path to the Python dependencies.
|
||||
|
||||
Thus, the addon preferences method `on_addon_pydeps_changed()` has the responsibility for checking when the dependencies are valid, and running the delayed registrations (and any other delayed setup) in response.
|
||||
In general, `on_addon_pydeps_changed()` runs whenever the PyDeps path is changed, but it can also be run manually.
|
||||
|
||||
As the last part of this process, that's exactly what `register()` does: Runs `on_addon_pydeps_changed()` manually.
|
||||
Depending on the addon preferences (which persist), one of two things can happen:
|
||||
|
||||
1. **Deps Satisfied**: The addon will load without issue: The just-declared "delayed registrations" will run immediately, and all is well.
|
||||
2. **Deps Not Satisfied**: The user must take action to fix the conflicts due to Python dependencies, before the addon can load. **A popup will show to help the user do so.
|
||||
|
||||
"""Implements addon registration in a way that respects the availability of addon preferences and loggers.
|
||||
|
||||
Notes:
|
||||
Called by Blender when enabling the addon.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If addon preferences fail to register.
|
||||
"""
|
||||
log.info('Commencing Registration of Addon: %s', ct.addon.NAME)
|
||||
bpy.app.handlers.load_post.append(manage_pydeps)
|
||||
log.info('Registering Addon Preferences: %s', ct.addon.NAME)
|
||||
registration.register_classes(preferences.BL_REGISTER)
|
||||
|
||||
# Register Barebones Addon
|
||||
## Contains all no-dependency BLClasses:
|
||||
## - Contains AddonPreferences.
|
||||
## Contains all BLClasses from 'nodeps'.
|
||||
registration.register_classes(BL_REGISTER_BEFORE_DEPS)
|
||||
registration.register_hotkeys(BL_HOTKEYS_BEFORE_DEPS)
|
||||
addon_prefs = ct.addon.prefs()
|
||||
if addon_prefs is not None:
|
||||
# Update Loggers
|
||||
# - This updates existing loggers to use settings defined by preferences.
|
||||
addon_prefs.on_addon_logging_changed()
|
||||
|
||||
# Delay Complete Registration until DEPS_SATISFIED
|
||||
registration.delay_registration_until(
|
||||
registration.BLRegisterEvent.DepsSatisfied,
|
||||
then_register_classes=load_main_blclasses,
|
||||
then_register_hotkeys=load_main_blhotkeys,
|
||||
)
|
||||
log.info('Registering Addon: %s', ct.addon.NAME)
|
||||
|
||||
# Trigger PyDeps Check
|
||||
## Deps ARE OK: Delayed registration will trigger.
|
||||
## Deps NOT OK: User must fix the pydeps, then trigger this method.
|
||||
ct.addon.prefs().on_addon_pydeps_changed()
|
||||
registration.register_classes(BL_REGISTER)
|
||||
registration.register_handlers(BL_HANDLERS)
|
||||
registration.register_keymaps(BL_KEYMAP_ITEMS)
|
||||
|
||||
log.info('Finished Registration of Addon: %s', ct.addon.NAME)
|
||||
else:
|
||||
msg = 'Addon preferences did not register for addon {ct.addon.NAME} - something is very wrong!'
|
||||
raise RuntimeError(msg)
|
||||
|
||||
|
||||
def unregister() -> None:
|
||||
"""Unregisters anything that was registered by the addon.
|
||||
|
||||
Notes:
|
||||
Run by Blender when disabling the addon.
|
||||
Run by Blender when disabling and/or uninstalling the addon.
|
||||
|
||||
This doesn't clean `sys.modules`.
|
||||
To fully revert to Blender's state before the addon was in use (especially various import-related caches in the Python process), Blender must be restarted.
|
||||
We rely on the hope that Blender has extension-extension module isolation.
|
||||
"""
|
||||
log.info('Starting %s Unregister', ct.addon.NAME)
|
||||
|
||||
registration.unregister_keymaps()
|
||||
registration.unregister_handlers()
|
||||
registration.unregister_classes()
|
||||
registration.unregister_hotkeys()
|
||||
registration.clear_delayed_registrations()
|
||||
|
||||
log.info('Finished %s Unregister', ct.addon.NAME)
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -14,21 +14,7 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Independent constants and types, which represent a kind of 'social contract' governing communication between all components of the addon."""
|
||||
|
||||
from . import addon
|
||||
from .bl import (
|
||||
|
@ -36,24 +22,30 @@ from .bl import (
|
|||
BLColorRGBA,
|
||||
BLEnumElement,
|
||||
BLEnumID,
|
||||
BLEventType,
|
||||
BLEventValue,
|
||||
BLIcon,
|
||||
BLIconSet,
|
||||
BLIDStruct,
|
||||
BLImportMethod,
|
||||
BLKeymapItem,
|
||||
BLModifierType,
|
||||
BLNodeTreeInterfaceID,
|
||||
BLOperatorStatus,
|
||||
BLPropFlag,
|
||||
BLRegionType,
|
||||
BLSpaceType,
|
||||
KeymapItemDef,
|
||||
ManagedObjName,
|
||||
PresetName,
|
||||
PropName,
|
||||
SocketName,
|
||||
)
|
||||
from .bl_types import BLEnumStrEnum
|
||||
from .bl_handlers import BLHandlers
|
||||
from .bl_keymap import BLKeymapItem
|
||||
from .icons import Icon
|
||||
from .mobj_types import ManagedObjType
|
||||
from .node_tree_types import (
|
||||
NodeTreeType,
|
||||
)
|
||||
from .operator_types import (
|
||||
OperatorType,
|
||||
)
|
||||
|
@ -67,6 +59,8 @@ __all__ = [
|
|||
'BLColorRGBA',
|
||||
'BLEnumElement',
|
||||
'BLEnumID',
|
||||
'BLEventType',
|
||||
'BLEventValue',
|
||||
'BLIcon',
|
||||
'BLIconSet',
|
||||
'BLIDStruct',
|
||||
|
@ -80,12 +74,15 @@ __all__ = [
|
|||
'BLSpaceType',
|
||||
'KeymapItemDef',
|
||||
'ManagedObjName',
|
||||
'ManagedObjType',
|
||||
'PresetName',
|
||||
'PropName',
|
||||
'SocketName',
|
||||
'BLEnumStrEnum',
|
||||
'BLHandlers',
|
||||
'Icon',
|
||||
'BLInstance',
|
||||
'InstanceID',
|
||||
'NodeTreeType',
|
||||
'OperatorType',
|
||||
'PanelType',
|
||||
]
|
||||
|
|
|
@ -14,105 +14,82 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Basic 'single-source-of-truth' static and dynamic information about this addon.
|
||||
|
||||
import sys
|
||||
Information is mined both from `bpy`, and from the addon's bundled manifest file.
|
||||
"""
|
||||
|
||||
import os
|
||||
import tomllib
|
||||
import typing as typ
|
||||
from pathlib import Path
|
||||
|
||||
import bpy
|
||||
import bpy_restrict_state
|
||||
|
||||
PATH_ADDON_ROOT = Path(__file__).resolve().parent.parent
|
||||
with (PATH_ADDON_ROOT / 'pyproject.toml').open('rb') as f:
|
||||
PROJ_SPEC = tomllib.load(f)
|
||||
## bl_info is filled with PROJ_SPEC when packing the .zip.
|
||||
PATH_MANIFEST = PATH_ADDON_ROOT / 'blender_manifest.toml'
|
||||
|
||||
NAME = PROJ_SPEC['project']['name']
|
||||
VERSION = PROJ_SPEC['project']['version']
|
||||
with PATH_MANIFEST.open('rb') as f:
|
||||
MANIFEST = tomllib.load(f)
|
||||
|
||||
NAME: str = MANIFEST['id']
|
||||
VERSION: str = MANIFEST['version']
|
||||
|
||||
####################
|
||||
# - Assets
|
||||
####################
|
||||
PATH_ASSETS = PATH_ADDON_ROOT / 'assets'
|
||||
PATH_ASSETS: Path = PATH_ADDON_ROOT / 'assets'
|
||||
|
||||
####################
|
||||
# - PyDeps Info
|
||||
####################
|
||||
PATH_REQS = PATH_ADDON_ROOT / 'requirements.lock'
|
||||
DEFAULT_PATH_DEPS = PATH_ADDON_ROOT / '.addon_dependencies'
|
||||
DEFAULT_PATH_DEPS.mkdir(exist_ok=True)
|
||||
## requirements.lock is written when packing the .zip.
|
||||
## By default, the addon pydeps are kept in the addon dir.
|
||||
|
||||
ORIGINAL_SYS_PATH = sys.path.copy()
|
||||
|
||||
####################
|
||||
# - Local Addon Cache
|
||||
####################
|
||||
DEFAULT_ADDON_CACHE = PATH_ADDON_ROOT / '.addon_cache'
|
||||
DEFAULT_ADDON_CACHE.mkdir(exist_ok=True)
|
||||
|
||||
PIP_INSTALL_LOG = DEFAULT_ADDON_CACHE / 'pip_install.log'
|
||||
if 'RUNNING_BLEXT_TESTS' in os.environ:
|
||||
PATH_CACHE: Path = (
|
||||
PATH_ADDON_ROOT.parent / 'dev' / 'local'
|
||||
) ## TODO: Consult init_settings
|
||||
else:
|
||||
PATH_CACHE: Path = Path(bpy.utils.extension_path_user(__package__, create=True)) # type: ignore[no-redef]
|
||||
|
||||
|
||||
####################
|
||||
# - Dynamic Addon Information
|
||||
####################
|
||||
def is_loading() -> bool:
|
||||
"""Checks whether the addon is currently loading.
|
||||
def operator(
|
||||
name: str, *operator_args: list[typ.Any], **operator_kwargs: dict[str, typ.Any]
|
||||
) -> None:
|
||||
"""Convenienve method to call an operator from this addon.
|
||||
|
||||
While an addon is loading, `bpy.context` is temporarily very limited.
|
||||
For example, operators can't run while the addon is loading.
|
||||
This avoids having to use `bpy.ops.<addon_name>.operator_name`, which isn't generic.
|
||||
|
||||
By checking whether `bpy.context` is limited like this, we can determine whether the addon is currently loading.
|
||||
Only operators from this addon may be called using this method.
|
||||
|
||||
Notes:
|
||||
Since `bpy_restrict_state._RestrictContext` is a very internal thing, this function may be prone to breakage on Blender updates.
|
||||
|
||||
**Keep an eye out**!
|
||||
|
||||
Returns:
|
||||
Whether the addon has been fully loaded, such that `bpy.context` is fully accessible.
|
||||
Raises:
|
||||
ValueError: If an addon from outside this operator is attempted to be used.
|
||||
"""
|
||||
return isinstance(bpy.context, bpy_restrict_state._RestrictContext)
|
||||
|
||||
|
||||
def operator(name: str, *operator_args, **operator_kwargs) -> None:
|
||||
# Parse Operator Name
|
||||
operator_namespace, operator_name = name.split('.')
|
||||
if operator_namespace != NAME:
|
||||
msg = f'Tried to call operator {operator_name}, but addon operators may only use the addon operator namespace "{operator_namespace}.<name>"'
|
||||
raise RuntimeError(msg)
|
||||
raise ValueError(msg)
|
||||
|
||||
# Addon Not Loading: Run Operator
|
||||
if not is_loading():
|
||||
operator = getattr(getattr(bpy.ops, NAME), operator_name)
|
||||
operator(*operator_args, **operator_kwargs)
|
||||
else:
|
||||
msg = f'Tried to call operator "{operator_name}" while addon is loading'
|
||||
raise RuntimeError(msg)
|
||||
# Run Operator
|
||||
bl_operator = getattr(getattr(bpy.ops, NAME), operator_name)
|
||||
bl_operator(*operator_args, **operator_kwargs)
|
||||
## TODO: Can't we constrain 'name' to be an OperatorType somehow?
|
||||
|
||||
|
||||
def prefs() -> bpy.types.AddonPreferences | None:
|
||||
if (addon := bpy.context.preferences.addons.get(NAME)) is None:
|
||||
msg = 'Addon is not installed'
|
||||
raise RuntimeError(msg)
|
||||
"""Retrieve the preferences of this addon, if they are available yet.
|
||||
|
||||
Notes:
|
||||
While registering the addon, one may wish to use the addon preferences.
|
||||
This isn't possible - not even for default values.
|
||||
|
||||
Either a bad idea is at work, or `oscillode.utils.init_settings` should be consulted until the preferences are available.
|
||||
|
||||
Returns:
|
||||
The addon preferences, if the addon is registered and loaded - otherwise None.
|
||||
"""
|
||||
addon = bpy.context.preferences.addons.get(NAME)
|
||||
if addon is None:
|
||||
return None
|
||||
return addon.preferences
|
||||
|
||||
|
||||
|
|
|
@ -14,21 +14,7 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Explicit type annotations for Blender objects, making it easier to guarantee correctness in communications with Blender."""
|
||||
|
||||
import typing as typ
|
||||
|
||||
|
@ -109,7 +95,6 @@ BLIDStruct: typ.TypeAlias = (
|
|||
| bpy.types.WorkSpace
|
||||
| bpy.types.World
|
||||
)
|
||||
BLKeymapItem: typ.TypeAlias = typ.Any ## TODO: Better Type
|
||||
BLPropFlag: typ.TypeAlias = typ.Literal[
|
||||
'HIDDEN',
|
||||
'SKIP_SAVE',
|
||||
|
@ -126,6 +111,24 @@ BLColorRGBA = tuple[float, float, float, float]
|
|||
####################
|
||||
# - Operators
|
||||
####################
|
||||
BLRegionType: typ.TypeAlias = typ.Literal[
|
||||
'WINDOW',
|
||||
'HEADER',
|
||||
'CHANNELS',
|
||||
'TEMPORARY',
|
||||
'UI',
|
||||
'TOOLS',
|
||||
'TOOL_PROPS',
|
||||
'ASSET_SHELF',
|
||||
'ASSET_SHELF_HEADER',
|
||||
'PREVIEW',
|
||||
'HUD',
|
||||
'NAVIGATION_BAR',
|
||||
'EXECUTE',
|
||||
'FOOTER',
|
||||
'TOOL_HEADER',
|
||||
'XR',
|
||||
]
|
||||
BLSpaceType: typ.TypeAlias = typ.Literal[
|
||||
'EMPTY',
|
||||
'VIEW_3D',
|
||||
|
@ -147,32 +150,151 @@ BLSpaceType: typ.TypeAlias = typ.Literal[
|
|||
'SPREADSHEET',
|
||||
'PREFERENCES',
|
||||
]
|
||||
BLRegionType: typ.TypeAlias = typ.Literal[
|
||||
'WINDOW',
|
||||
'HEADER',
|
||||
'CHANNELS',
|
||||
'TEMPORARY',
|
||||
'UI',
|
||||
'TOOLS',
|
||||
'TOOL_PROPS',
|
||||
'ASSET_SHELF',
|
||||
'ASSET_SHELF_HEADER',
|
||||
'PREVIEW',
|
||||
'HUD',
|
||||
'NAVIGATION_BAR',
|
||||
'EXECUTE',
|
||||
'FOOTER',
|
||||
'TOOL_HEADER',
|
||||
'XR',
|
||||
]
|
||||
BLOperatorStatus: typ.TypeAlias = set[
|
||||
typ.Literal['RUNNING_MODAL', 'CANCELLED', 'FINISHED', 'PASS_THROUGH', 'INTERFACE']
|
||||
]
|
||||
|
||||
####################
|
||||
# - Operators
|
||||
####################
|
||||
## TODO: Write the rest in.
|
||||
BLEventType: typ.TypeAlias = typ.Literal[
|
||||
'NONE',
|
||||
'LEFTMOUSE',
|
||||
'MIDDLEMOUSE',
|
||||
'RIGHTMOUSE',
|
||||
'BUTTON4MOUSE',
|
||||
'BUTTON5MOUSE',
|
||||
'BUTTON6MOUSE',
|
||||
'BUTTON7MOUSE',
|
||||
'PEN',
|
||||
'ERASOR',
|
||||
'MOUSEMOVE',
|
||||
'INBETWEEN_MOUSEMOVE',
|
||||
'TRACKPADPAN',
|
||||
'TRACKPADZOOM',
|
||||
'MOUSEROTATE',
|
||||
'MOUSESMARTZOOM',
|
||||
'WHEELUPMOUSE',
|
||||
'WHEELDOWNMOUSE',
|
||||
'WHEELINMOUSE',
|
||||
'WHEELOUTMOUSE',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'I',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'M',
|
||||
'N',
|
||||
'O',
|
||||
'P',
|
||||
'Q',
|
||||
'R',
|
||||
'S',
|
||||
'T',
|
||||
'U',
|
||||
'V',
|
||||
'W',
|
||||
'X',
|
||||
'Y',
|
||||
'Z',
|
||||
'ZERO',
|
||||
'ONE',
|
||||
'TWO',
|
||||
'THREE',
|
||||
'FOUR',
|
||||
'FIVE',
|
||||
'SIX',
|
||||
'SEVEN',
|
||||
'EIGHT',
|
||||
'NINE',
|
||||
'LEFT_CTRL',
|
||||
'LEFT_ALT',
|
||||
'LEFT_SHIFT',
|
||||
'RIGHT_ALT',
|
||||
'RIGHT_CTRL',
|
||||
'RIGHT_SHIFT',
|
||||
'ESC',
|
||||
'TAB',
|
||||
'RET', ## Enter
|
||||
'SPACE',
|
||||
'LINE_FEED',
|
||||
'BACK_SPACE',
|
||||
'DEL',
|
||||
'SEMI_COLON',
|
||||
'PERIOD',
|
||||
'COMMA',
|
||||
'QUOTE',
|
||||
'ACCENT_GRAVE',
|
||||
'MINUS',
|
||||
'PLUS',
|
||||
'SLASH',
|
||||
'BACK_SLASH',
|
||||
'EQUAL',
|
||||
'LEFT_BRACKET',
|
||||
'RIGHT_BRACKET',
|
||||
'LEFT_ARROW',
|
||||
'DOWN_ARROW',
|
||||
'RIGHT_ARROW',
|
||||
'UP_ARROW',
|
||||
'NUMPAD_0',
|
||||
'NUMPAD_1',
|
||||
'NUMPAD_2',
|
||||
'NUMPAD_3',
|
||||
'NUMPAD_4',
|
||||
'NUMPAD_5',
|
||||
'NUMPAD_6',
|
||||
'NUMPAD_7',
|
||||
'NUMPAD_8',
|
||||
'NUMPAD_9',
|
||||
'NUMPAD_PERIOD',
|
||||
'NUMPAD_SLASH',
|
||||
'NUMPAD_ASTERIX',
|
||||
'NUMPAD_MINUS',
|
||||
'NUMPAD_PLUS',
|
||||
'NUMPAD_ENTER',
|
||||
'F1',
|
||||
'F2',
|
||||
'F3',
|
||||
'F4',
|
||||
'F5',
|
||||
'F6',
|
||||
'F7',
|
||||
'F8',
|
||||
'F9',
|
||||
'F10',
|
||||
'F11',
|
||||
'F12',
|
||||
'PAUSE',
|
||||
'INSERT',
|
||||
'HOME',
|
||||
'PAGE_UP',
|
||||
'PAGE_DOWN',
|
||||
'END',
|
||||
'MEDIA_PLAY',
|
||||
'MEDIA_STOP',
|
||||
'MEDIA_FIRST',
|
||||
'MEDIA_LAST',
|
||||
]
|
||||
BLEventValue: typ.TypeAlias = typ.Literal[
|
||||
'ANY',
|
||||
'PRESS',
|
||||
'RELEASE',
|
||||
'CLICK',
|
||||
'DOUBLE_CLICK',
|
||||
'CLICK_DRAG',
|
||||
'NOTHING',
|
||||
]
|
||||
####################
|
||||
# - Addon Types
|
||||
####################
|
||||
KeymapItemDef: typ.TypeAlias = typ.Any
|
||||
ManagedObjName = str
|
||||
|
||||
####################
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
# oscillode
|
||||
# Copyright (C) 2024 oscillode Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Declares types for working with `bpy.app.handlers` callbacks."""
|
||||
|
||||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from oscillode.utils.staticproperty import staticproperty
|
||||
|
||||
BLHandler = typ.Callable[[], None]
|
||||
BLHandlerWithFile = typ.Callable[[str], None]
|
||||
BLHandlerWithRenderStats = typ.Callable[[typ.Any], None]
|
||||
|
||||
|
||||
class BLHandlers(pyd.BaseModel):
|
||||
"""Contains lists of handlers associated with this addon."""
|
||||
|
||||
animation_playback_post: tuple[BLHandler, ...] = ()
|
||||
animation_playback_pre: tuple[BLHandler, ...] = ()
|
||||
annotation_post: tuple[BLHandler, ...] = ()
|
||||
annotation_pre: tuple[BLHandler, ...] = ()
|
||||
composite_cancel: tuple[BLHandler, ...] = ()
|
||||
composite_post: tuple[BLHandler, ...] = ()
|
||||
composite_pre: tuple[BLHandler, ...] = ()
|
||||
depsgraph_update_post: tuple[BLHandler, ...] = ()
|
||||
depsgraph_update_pre: tuple[BLHandler, ...] = ()
|
||||
frame_change_post: tuple[BLHandler, ...] = ()
|
||||
frame_change_pre: tuple[BLHandler, ...] = ()
|
||||
load_factory_preferences_post: tuple[BLHandler, ...] = ()
|
||||
load_factory_startup_post: tuple[BLHandler, ...] = ()
|
||||
load_post: tuple[BLHandlerWithFile, ...] = ()
|
||||
load_post_fail: tuple[BLHandlerWithFile, ...] = ()
|
||||
load_pre: tuple[BLHandlerWithFile, ...] = ()
|
||||
object_bake_cancel: tuple[BLHandler, ...] = ()
|
||||
object_bake_complete: tuple[BLHandler, ...] = ()
|
||||
object_bake_pre: tuple[BLHandler, ...] = ()
|
||||
redo_post: tuple[BLHandler, ...] = ()
|
||||
redo_pre: tuple[BLHandler, ...] = ()
|
||||
render_cancel: tuple[BLHandler, ...] = ()
|
||||
render_complete: tuple[BLHandler, ...] = ()
|
||||
render_init: tuple[BLHandler, ...] = ()
|
||||
render_post: tuple[BLHandler, ...] = ()
|
||||
render_pre: tuple[BLHandler, ...] = ()
|
||||
render_stats: tuple[BLHandler, ...] = ()
|
||||
## TODO: Verify these type signatures.
|
||||
|
||||
## TODO: A validator to check that all handlers are decorated with bpy.app.handlers.persistent
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
@staticproperty # type: ignore[arg-type]
|
||||
def handler_categories() -> tuple[str, ...]: # type: ignore[misc]
|
||||
"""Returns an immutable string sequence of handler categories."""
|
||||
return (
|
||||
'animation_playback_post',
|
||||
'animation_playback_pre',
|
||||
'annotation_post',
|
||||
'annotation_pre',
|
||||
'composite_cancel',
|
||||
'composite_post',
|
||||
'composite_pre',
|
||||
'depsgraph_update_post',
|
||||
'depsgraph_update_pre',
|
||||
'frame_change_post',
|
||||
'frame_change_pre',
|
||||
'load_factory_preferences_post',
|
||||
'load_factory_startup_post',
|
||||
'load_post',
|
||||
'load_post_fail',
|
||||
'load_pre',
|
||||
'object_bake_cancel',
|
||||
'object_bake_complete',
|
||||
'object_bake_pre',
|
||||
'redo_post',
|
||||
'redo_pre',
|
||||
'render_cancel',
|
||||
'render_complete',
|
||||
'render_init',
|
||||
'render_post',
|
||||
'render_pre',
|
||||
'render_stats',
|
||||
)
|
||||
|
||||
####################
|
||||
# - Merging
|
||||
####################
|
||||
def __add__(self, other: typ.Self) -> typ.Self:
|
||||
"""Concatenate the handlers of two `BLHandlers` objects."""
|
||||
return BLHandlers(
|
||||
**{
|
||||
hndl_cat: getattr(self, hndl_cat) + getattr(self, hndl_cat)
|
||||
for hndl_cat in self.handler_categories
|
||||
}
|
||||
)
|
||||
|
||||
def register(self) -> None:
|
||||
"""Registers all handlers declared by-category."""
|
||||
for handler_category in BLHandlers.handler_categories:
|
||||
for handler in getattr(self, handler_category):
|
||||
getattr(bpy.app.handlers, handler_category).append(handler)
|
||||
|
||||
def unregister(self) -> None:
|
||||
"""Unregisters only this addon's handlers from bpy.app.handlers."""
|
||||
for handler_category in BLHandlers.handler_categories:
|
||||
for handler in getattr(self, handler_category):
|
||||
bpy_handlers = getattr(bpy.app.handlers, handler_category)
|
||||
if handler in bpy_handlers:
|
||||
bpy_handlers.remove(handler)
|
|
@ -0,0 +1,60 @@
|
|||
# oscillode
|
||||
# Copyright (C) 2024 oscillode Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Declares types for working with `bpy.types.KeyMap`s."""
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from .bl import BLEventType, BLEventValue, BLSpaceType
|
||||
from .operator_types import OperatorType
|
||||
|
||||
|
||||
class BLKeymapItem(pyd.BaseModel):
|
||||
"""Contains lists of handlers associated with this addon."""
|
||||
|
||||
operator: OperatorType
|
||||
|
||||
event_type: BLEventType
|
||||
event_value: BLEventValue
|
||||
|
||||
shift: bool = False
|
||||
ctrl: bool = False
|
||||
alt: bool = False
|
||||
key_modifier: BLEventType = 'NONE'
|
||||
|
||||
space_type: BLSpaceType = 'EMPTY'
|
||||
|
||||
def register(self, addon_keymap: bpy.types.KeyMap) -> bpy.types.KeyMapItem:
|
||||
"""Registers this hotkey with an addon keymap.
|
||||
|
||||
Raises:
|
||||
ValueError: If the `space_type` constraint of the addon keymap does not match the `space_type` constraint of this `BLKeymapItem`.
|
||||
"""
|
||||
if self.space_type == addon_keymap.space_type:
|
||||
addon_keymap.keymap_items.new(
|
||||
self.operator,
|
||||
self.event_type,
|
||||
self.event_value,
|
||||
shift=self.shift,
|
||||
ctrl=self.ctrl,
|
||||
alt=self.alt,
|
||||
key_modifier=self.key_modifier,
|
||||
)
|
||||
|
||||
msg = f'Addon keymap space type {addon_keymap.space_type} does not match space_type of BLKeymapItem to register: {self}'
|
||||
raise ValueError(msg)
|
||||
## TODO: Check if space_type matches?
|
|
@ -1,44 +0,0 @@
|
|||
# oscillode
|
||||
# Copyright (C) 2024 oscillode Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import typing as typ
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Enum (w/EnumProperty support)
|
||||
####################
|
||||
class BLEnumStrEnum(typ.Protocol):
|
||||
@staticmethod
|
||||
def to_name(value: typ.Self) -> str: ...
|
||||
|
||||
@staticmethod
|
||||
def to_icon(value: typ.Self) -> str: ...
|
|
@ -14,26 +14,14 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Provides an enum that semantically constrains the use of icons throughout the addon."""
|
||||
|
||||
import enum
|
||||
|
||||
|
||||
class Icon(enum.StrEnum):
|
||||
"""Identifiers for icons used throughout this addon."""
|
||||
|
||||
# Node Tree
|
||||
SimNodeEditor = 'MOD_SIMPLEDEFORM'
|
||||
|
|
@ -14,28 +14,16 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Provides identifiers for objects in Blender that are managed on behalf of the user, for use by the addon, in order to provide a safe and streamlined integration of more complex data representations that flow between the addon and Blender."""
|
||||
|
||||
import enum
|
||||
|
||||
from blender_maxwell.utils import blender_type_enum
|
||||
from oscillode.utils import blender_type_enum
|
||||
|
||||
|
||||
class ManagedObjType(blender_type_enum.BlenderTypeEnum):
|
||||
"""Identifiers for 'managed objects', which encapsulates a particular Blender object and provides alternative semantics more suited to the needs of this addon."""
|
||||
|
||||
ManagedBLImage = enum.auto()
|
||||
|
||||
ManagedBLCollection = enum.auto()
|
|
@ -0,0 +1,28 @@
|
|||
# oscillode
|
||||
# Copyright (C) 2024 oscillode Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Provides identifiers for node trees defined by this addon."""
|
||||
|
||||
import enum
|
||||
|
||||
from oscillode.utils import blender_type_enum
|
||||
|
||||
|
||||
@blender_type_enum.append_cls_name_to_values
|
||||
class NodeTreeType(blender_type_enum.BlenderTypeEnum):
|
||||
"""Identifiers for addon-defined node trees."""
|
||||
|
||||
MaxwellSim = enum.auto()
|
|
@ -14,27 +14,12 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Defines Operator Types as an enum, making it easy for any part of the addon to refer to any operator."""
|
||||
"""Provides identifiers for Blender operators defined by this addon."""
|
||||
|
||||
import enum
|
||||
|
||||
from ..nodeps.utils import blender_type_enum
|
||||
from oscillode.utils import blender_type_enum
|
||||
|
||||
from .addon import NAME as ADDON_NAME
|
||||
|
||||
|
||||
|
|
|
@ -14,27 +14,11 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Defines Panel Types as an enum, making it easy for any part of the addon to refer to any panel."""
|
||||
|
||||
import enum
|
||||
|
||||
from blender_maxwell.nodeps.utils import blender_type_enum
|
||||
from oscillode.utils import blender_type_enum
|
||||
|
||||
from .addon import NAME as ADDON_NAME
|
||||
|
||||
|
|
|
@ -14,29 +14,10 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Provides various useful managed objects, which enables the clean and safe use of objects external to this addon."""
|
||||
|
||||
from .base import ManagedObj
|
||||
|
||||
# from .managed_bl_empty import ManagedBLEmpty
|
||||
from .managed_bl_image import ManagedBLImage
|
||||
|
||||
# from .managed_bl_collection import ManagedBLCollection
|
||||
# from .managed_bl_object import ManagedBLObject
|
||||
from .managed_bl_mesh import ManagedBLMesh
|
||||
|
||||
# from .managed_bl_volume import ManagedBLVolume
|
||||
|
@ -44,13 +25,8 @@ from .managed_bl_modifier import ManagedBLModifier
|
|||
|
||||
__all__ = [
|
||||
'ManagedObj',
|
||||
#'ManagedBLEmpty',
|
||||
'ManagedBLImage',
|
||||
#'ManagedBLCollection',
|
||||
#'ManagedBLObject',
|
||||
'ManagedBLMesh',
|
||||
#'ManagedBLVolume',
|
||||
'ManagedBLModifier',
|
||||
]
|
||||
|
||||
## REMEMBER: Add the appropriate entry to the bl_cache.DECODER
|
|
@ -0,0 +1,125 @@
|
|||
# oscillode
|
||||
# Copyright (C) 2024 oscillode Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Provides the base protocol on which all ManagedObjs are derived, as well as explicit protocols describing common features supported by some `ManagedObjs`."""
|
||||
|
||||
import abc
|
||||
import typing as typ
|
||||
|
||||
from blender_maxwell.utils import logger, serialize
|
||||
|
||||
from .. import contracts as ct
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
||||
class ManagedObj(typ.Protocol):
|
||||
"""A weak name-based reference to some kind of object external to this software.
|
||||
|
||||
While the object doesn't have to come from Blender's `bpy.types`, that is the driving motivation for this class: To encapsulate access to the powerful visual tools granted by Blender's 3D viewport, image editor, and UI.
|
||||
Through extensive trial-and-error, this transparently-cached immediate-mode interface has emerged as the best compromise.
|
||||
|
||||
While not suited to all use cases, the `ManagedObj` paradigm is ideal for the common situation of 'node ownership of external logic'.
|
||||
For example, a plotting node needs access to its own image buffer; however, for it to be displayable, that image buffer must be owned by Blender.
|
||||
This is where `ManagedObj` provides the ability of the plotting node to "loosely own" a particular Blender image, which both allows the user to see/interact with the image as a typical Blender image, but also allows the node to drive ex. lifecycle (like removing the image plot when the node is deleted).
|
||||
|
||||
This approach of loose name-coupling is not perfect. To name a few examples:
|
||||
|
||||
- A particular challenge is that of identifying and namespacing managed datablocks. The user may, for example, change the name of an object - and what do we do then? Is generating new data under the now-vacant name a feature? Or is it a systematic memory leak backed by dangling fake-owned datablocks?
|
||||
- The precise definition of "loose ownership" is itself a matter of taste. Stronger ownership presumptions allow for stronger guarantees and simpler caching - but at the cost of more brittle breaks when the underlying objects are manipulated in ways we don't expect.
|
||||
- `.blend` persistance is not the default when it comes to certain Blender objects, which raises deeper UX questions about how opinionated we should be about where users put data.
|
||||
- Solving this doesn't help actually deal with data. There's a lot of very specific nuance in every single data pipeline, and that complexity is only added to watever this approach incurs.
|
||||
|
||||
This abstract base class serves to provide a few of the most basic of commonly-available operations.
|
||||
In particular, implementations of `dump_as_msgspec`/`parse_as_msgspec` are enforced, for use with `oscillode.utils.serialize`.
|
||||
This way, ex. opening a `.blend` file will allow a newly-deserialized `ManagedObj` to re-attach transparently to the also-persisted underlying datablock.
|
||||
|
||||
Parameters:
|
||||
managed_obj_type: Enum identifier indicating which of the `ct.ManagedObjType` the instance should declare itself as.
|
||||
"""
|
||||
|
||||
managed_obj_type: ct.ManagedObjType
|
||||
|
||||
@abc.abstractmethod
|
||||
def __init__(self, name: ct.ManagedObjName, prev_name: str | None = None):
|
||||
"""Initializes the managed object with a unique name.
|
||||
|
||||
Use `prev_name` to indicate that the managed object will initially be avaiable under `prev_name`, but that it should be renamed to `name`.
|
||||
"""
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def name(self) -> str:
|
||||
"""Retrieve the name of the managed object."""
|
||||
|
||||
@name.setter
|
||||
@abc.abstractmethod
|
||||
def name(self, value: str) -> None:
|
||||
"""Retrieve the name of the managed object."""
|
||||
|
||||
####################
|
||||
# - Methods
|
||||
####################
|
||||
@abc.abstractmethod
|
||||
def free(self) -> None:
|
||||
"""Cleanup the resources managed by the managed object."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def hide_preview(self) -> None:
|
||||
"""Hide any active preview of the managed object, if it exists, and if such an operation makes sense."""
|
||||
|
||||
####################
|
||||
# - Serialization
|
||||
####################
|
||||
def dump_as_msgspec(self) -> serialize.NaiveRepresentation:
|
||||
"""Bijectively transform this managed object into a 'naive representation' that uses only basic Python types, which may be serialized cleanly."""
|
||||
return [
|
||||
serialize.TypeID.ManagedObj,
|
||||
self.__class__.__name__,
|
||||
self.name,
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def parse_as_msgspec(obj: serialize.NaiveRepresentation) -> typ.Self:
|
||||
"""Bijectively construct an instance of this managed object from the 'naive representation', which may have been deserialized into."""
|
||||
return next(
|
||||
subclass(obj[2])
|
||||
for subclass in ManagedObj.__subclasses__()
|
||||
if subclass.__name__ == obj[1]
|
||||
)
|
||||
|
||||
|
||||
####################
|
||||
# - Support Flags
|
||||
####################
|
||||
class SupportsBlenderSelect(typ.Protocol):
|
||||
"""Protocol guaranteeing the ability to select the object in Blender."""
|
||||
|
||||
def bl_select(self) -> None:
|
||||
"""Select the managed object in Blender."""
|
||||
|
||||
|
||||
class Supportsreview(typ.Protocol):
|
||||
"""Protocol guaranteeing support for previewing the object."""
|
||||
|
||||
def show_preview(self) -> None:
|
||||
"""Shows a preview of the managed object."""
|
||||
|
||||
def hide_preview(self) -> None:
|
||||
"""Hide any active preview of the managed object, if it exists."""
|
|
@ -32,12 +32,12 @@
|
|||
|
||||
import bpy
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
from oscillode.utils import logger
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
MANAGED_COLLECTION_NAME = 'BLMaxwell'
|
||||
PREVIEW_COLLECTION_NAME = 'BLMaxwell Visible'
|
||||
MANAGED_COLLECTION_NAME = 'Oscillode'
|
||||
PREVIEW_COLLECTION_NAME = 'Oscillode Visible'
|
||||
|
||||
|
||||
####################
|
|
@ -14,23 +14,7 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Declares `ManagedBLImage`."""
|
||||
"""Declares an object encapsulating access to a Blender image datablock from this addon."""
|
||||
|
||||
import time
|
||||
import typing as typ
|
||||
|
@ -39,15 +23,17 @@ import bpy
|
|||
import matplotlib.axis as mpl_ax
|
||||
import numpy as np
|
||||
|
||||
from blender_maxwell.utils import image_ops, logger
|
||||
from oscillode.utils import image_ops, logger
|
||||
|
||||
from .. import contracts as ct
|
||||
from . import base
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
AREA_TYPE = 'IMAGE_EDITOR'
|
||||
SPACE_TYPE = 'IMAGE_EDITOR'
|
||||
AREA_TYPE: ct.BLSpaceType = (
|
||||
'IMAGE_EDITOR' ##TODO: Is SpaceType different than AreaType?
|
||||
)
|
||||
SPACE_TYPE: ct.BLSpaceType = 'IMAGE_EDITOR'
|
||||
|
||||
|
||||
####################
|
||||
|
@ -60,7 +46,7 @@ class ManagedBLImage(base.ManagedObj):
|
|||
name: The name of the image.
|
||||
"""
|
||||
|
||||
managed_obj_type = ct.ManagedObjType.ManagedBLImage
|
||||
managed_obj_type: str = ct.ManagedObjType.ManagedBLImage
|
||||
_bl_image_name: str
|
||||
|
||||
def __init__(self, name: str, prev_name: str | None = None):
|
||||
|
@ -186,6 +172,7 @@ class ManagedBLImage(base.ManagedObj):
|
|||
####################
|
||||
# - Methods
|
||||
####################
|
||||
## TODO: Rename to show_preview()
|
||||
def bl_select(self) -> None:
|
||||
"""Selects the image by loading it into an on-screen UI area/space.
|
||||
|
|
@ -14,22 +14,6 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import contextlib
|
||||
|
||||
import bmesh
|
||||
|
@ -37,7 +21,7 @@ import bpy
|
|||
import jax
|
||||
import numpy as np
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
from oscillode.utils import logger
|
||||
|
||||
from .. import contracts as ct
|
||||
from . import base
|
|
@ -14,31 +14,17 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""A managed Blender modifier, associated with some Blender object."""
|
||||
|
||||
## TODO: Make a common core for modifier manipulation, then specify each modifier as a seperate ManagedObj.
|
||||
|
||||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import jax
|
||||
import numpy as np
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
from oscillode.utils import logger
|
||||
|
||||
from .. import bl_socket_map
|
||||
from .. import contracts as ct
|
||||
|
@ -140,7 +126,7 @@ def write_modifier_geonodes(
|
|||
modifier_altered = True
|
||||
## TODO: More fine-grained alterations?
|
||||
|
||||
return modifier_altered # noqa: RET504
|
||||
return modifier_altered
|
||||
|
||||
|
||||
####################
|
||||
|
@ -170,6 +156,8 @@ def write_modifier(
|
|||
# - ManagedObj
|
||||
####################
|
||||
class ManagedBLModifier(base.ManagedObj):
|
||||
"""Manages a particular modifier attached to a Blender mesh also managed by this construction."""
|
||||
|
||||
managed_obj_type = ct.ManagedObjType.ManagedBLModifier
|
||||
_modifier_name: str | None = None
|
||||
twin_bl_mesh: ManagedBLMesh | None = None
|
|
@ -14,32 +14,13 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Declares `ManagedBLText`."""
|
||||
|
||||
import time
|
||||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import matplotlib.axis as mpl_ax
|
||||
import numpy as np
|
||||
|
||||
from blender_maxwell.utils import image_ops, logger
|
||||
from oscillode.utils import logger
|
||||
|
||||
from .. import contracts as ct
|
||||
from . import base
|
||||
|
@ -54,10 +35,10 @@ SPACE_TYPE = 'IMAGE_EDITOR'
|
|||
# - Managed BL Image
|
||||
####################
|
||||
class ManagedBLText(base.ManagedObj):
|
||||
"""Represents a Blender Image datablock, encapsulating various useful interactions with it.
|
||||
"""Represents a Blender text datablock, encapsulating various useful interactions with it.
|
||||
|
||||
Attributes:
|
||||
name: The name of the image.
|
||||
name: The name of the text datablock.
|
||||
"""
|
||||
|
||||
managed_obj_type = ct.ManagedObjType.ManagedBLText
|
|
@ -14,33 +14,32 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Internal assets for use via the Python API and/or directly by the user as an asset library."""
|
||||
|
||||
from functools import reduce
|
||||
|
||||
import oscillode.contracts as ct
|
||||
|
||||
from . import geonodes
|
||||
|
||||
BL_REGISTER = [
|
||||
BL_REGISTER: list[ct.BLClass] = [
|
||||
*geonodes.BL_REGISTER,
|
||||
]
|
||||
|
||||
BL_HOTKEYS = [
|
||||
*geonodes.BL_HOTKEYS,
|
||||
BL_HANDLERS: ct.BLHandlers = reduce(
|
||||
lambda a, b: a + b,
|
||||
[
|
||||
geonodes.BL_HANDLERS,
|
||||
],
|
||||
ct.BLHandlers(),
|
||||
)
|
||||
|
||||
BL_KEYMAP_ITEMS: list[ct.BLKeymapItem] = [
|
||||
*geonodes.BL_KEYMAP_ITEMS,
|
||||
]
|
||||
|
||||
__all__ = [
|
||||
'BL_REGISTER',
|
||||
'BL_HANDLERS',
|
||||
'BL_HOTKEYS',
|
||||
]
|
|
@ -14,22 +14,6 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Provides for the linking and/or appending of geometry nodes trees from vendored libraries included in Blender maxwell."""
|
||||
|
||||
import enum
|
||||
|
@ -37,8 +21,8 @@ from pathlib import Path
|
|||
|
||||
import bpy
|
||||
|
||||
from blender_maxwell import contracts as ct
|
||||
from blender_maxwell.utils import logger
|
||||
from oscillode import contracts as ct
|
||||
from oscillode.utils import logger
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
@ -48,17 +32,17 @@ log = logger.get(__name__)
|
|||
####################
|
||||
# GeoNodes Paths
|
||||
## Internal
|
||||
GN_INTERNAL_PATH = ct.addon.PATH_ASSETS / 'internal'
|
||||
GN_INTERNAL_INPUTS_PATH = GN_INTERNAL_PATH / 'input'
|
||||
GN_INTERNAL_SOURCES_PATH = GN_INTERNAL_PATH / 'source'
|
||||
GN_INTERNAL_STRUCTURES_PATH = GN_INTERNAL_PATH / 'structure'
|
||||
GN_INTERNAL_MONITORS_PATH = GN_INTERNAL_PATH / 'monitor'
|
||||
GN_INTERNAL_SIMULATIONS_PATH = GN_INTERNAL_PATH / 'simulation'
|
||||
GN_INTERNAL_PATH: Path = ct.addon.PATH_ASSETS / 'internal'
|
||||
GN_INTERNAL_INPUTS_PATH: Path = GN_INTERNAL_PATH / 'input'
|
||||
GN_INTERNAL_SOURCES_PATH: Path = GN_INTERNAL_PATH / 'source'
|
||||
GN_INTERNAL_STRUCTURES_PATH: Path = GN_INTERNAL_PATH / 'structure'
|
||||
GN_INTERNAL_MONITORS_PATH: Path = GN_INTERNAL_PATH / 'monitor'
|
||||
GN_INTERNAL_SIMULATIONS_PATH: Path = GN_INTERNAL_PATH / 'simulation'
|
||||
|
||||
## Structures
|
||||
GN_STRUCTURES_PATH = ct.addon.PATH_ASSETS / 'structures'
|
||||
GN_STRUCTURES_PRIMITIVES_PATH = GN_STRUCTURES_PATH / 'primitives'
|
||||
GN_STRUCTURES_ARRAYS_PATH = GN_STRUCTURES_PATH / 'arrays'
|
||||
GN_STRUCTURES_PATH: Path = ct.addon.PATH_ASSETS / 'structures'
|
||||
GN_STRUCTURES_PRIMITIVES_PATH: Path = GN_STRUCTURES_PATH / 'primitives'
|
||||
GN_STRUCTURES_ARRAYS_PATH: Path = GN_STRUCTURES_PATH / 'arrays'
|
||||
|
||||
|
||||
class GeoNodes(enum.StrEnum):
|
||||
|
@ -121,7 +105,7 @@ class GeoNodes(enum.StrEnum):
|
|||
ArrayRing = 'array_ring'
|
||||
|
||||
@property
|
||||
def dedicated_node_type(self) -> ct.BLImportMethod:
|
||||
def dedicated_node_type(self) -> str: ## TODO: How to correlate to node_tree?
|
||||
"""Deduces the denode type that implements a vendored GeoNodes tree (usually just "GeoNodes Structure").
|
||||
|
||||
Generally, "GeoNodes Structure' is the generic triangle-mesh node that can do everything.
|
||||
|
@ -401,7 +385,7 @@ class GeoNodesToStructureNode(bpy.types.Operator):
|
|||
####################
|
||||
def invoke(
|
||||
self, context: bpy.types.Context, _: bpy.types.Event
|
||||
) -> set[ct.BLOperatorStatus]:
|
||||
) -> ct.BLOperatorStatus:
|
||||
"""Commences the drag-and-drop of a GeoNodes asset.
|
||||
|
||||
- Starts the modal timer, which listens for a mouse-release event.
|
||||
|
@ -490,10 +474,10 @@ class GeoNodesToStructureNode(bpy.types.Operator):
|
|||
## 3. We compute it manually, to avoid the jank.
|
||||
node_location = get_view_location(
|
||||
editor_region,
|
||||
[
|
||||
(
|
||||
event.mouse_x - editor_region.x,
|
||||
event.mouse_y - editor_region.y,
|
||||
],
|
||||
),
|
||||
context.preferences.system.ui_scale,
|
||||
)
|
||||
|
||||
|
@ -542,8 +526,8 @@ ASSET_LIB_SPECS: dict[str, Path] = {
|
|||
}
|
||||
|
||||
|
||||
@bpy.app.handlers.persistent
|
||||
def initialize_asset_libraries(_: bpy.types.Scene):
|
||||
@bpy.app.handlers.persistent # type: ignore[misc]
|
||||
def initialize_asset_libraries(_: bpy.types.Scene) -> None:
|
||||
"""Before loading a `.blend` file, ensure that the WindowManager properties relied on by NodeAssetPanel are available.
|
||||
|
||||
- Several asset libraries, defined under the global `ASSET_LIB_SPECS`, are added/replaced such that the name:path map is respected.
|
||||
|
@ -596,11 +580,11 @@ def initialize_asset_libraries(_: bpy.types.Scene):
|
|||
)
|
||||
|
||||
|
||||
bpy.app.handlers.load_pre.append(initialize_asset_libraries)
|
||||
|
||||
BL_REGISTER = [
|
||||
NodeAssetPanel,
|
||||
GeoNodesToStructureNode,
|
||||
]
|
||||
|
||||
BL_HOTKEYS = []
|
||||
BL_HANDLERS: ct.BLHandlers = ct.BLHandlers(load_pre=(initialize_asset_libraries,))
|
||||
|
||||
BL_KEYMAP_ITEMS: list[ct.BLKeymapItem] = []
|
|
@ -38,7 +38,6 @@ Attributes:
|
|||
"""
|
||||
|
||||
import bpy
|
||||
|
||||
from blender_maxwell.utils import logger as _logger
|
||||
|
||||
from . import contracts as ct
|
||||
|
@ -46,6 +45,8 @@ from . import sockets
|
|||
|
||||
log = _logger.get(__name__)
|
||||
|
||||
## TODO: Coordinate w/refactor of managed modifiers; for example, the contents of this file would be ideally specified as the implementation of a Protocol, for the particular case of this node tree.
|
||||
|
||||
|
||||
####################
|
||||
# - Blender -> Socket Def(s)
|
||||
|
|
|
@ -38,6 +38,9 @@ import nodeitems_utils
|
|||
from . import contracts as ct
|
||||
from .nodes import BL_NODES
|
||||
|
||||
## TODO: Completely refactor this file, and rename it to reflect that it doesn't define or implement any categories - it simply, dumbly, implements the menu.
|
||||
## - Actually; we could delete this file by refactoring it, implementing the logic in a utils/ module, then running the dangling registration as a rote-registration matter in __init__.py.
|
||||
|
||||
DYNAMIC_SUBMENU_REGISTRATIONS = []
|
||||
|
||||
|
||||
|
@ -117,7 +120,7 @@ BL_REGISTER = [*DYNAMIC_SUBMENU_REGISTRATIONS] ## Must be run after, right now.
|
|||
|
||||
|
||||
def menu_draw(self, context):
|
||||
if context.space_data.tree_type == ct.TreeType.MaxwellSim.value:
|
||||
if context.space_data.tree_type == ct.NodeTreeType.MaxwellSim.value:
|
||||
for nodeitem_or_submenu in BL_NODE_CATEGORIES:
|
||||
if isinstance(nodeitem_or_submenu, str):
|
||||
submenu_id = nodeitem_or_submenu
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from blender_maxwell.contracts import (
|
||||
UNITS_BLENDER,
|
||||
UNITS_TIDY3D,
|
||||
BLClass,
|
||||
BLColorRGBA,
|
||||
BLEnumElement,
|
||||
|
@ -45,8 +47,11 @@ from blender_maxwell.contracts import (
|
|||
BLPropFlag,
|
||||
BLRegionType,
|
||||
BLSpaceType,
|
||||
Icon,
|
||||
KeymapItemDef,
|
||||
ManagedObjName,
|
||||
ManagedObjType,
|
||||
NodeTreeType,
|
||||
OperatorType,
|
||||
PanelType,
|
||||
PresetName,
|
||||
|
@ -72,8 +77,6 @@ from .flow_kinds import (
|
|||
ValueFlow,
|
||||
)
|
||||
from .flow_signals import FlowSignal
|
||||
from .icons import Icon
|
||||
from .mobj_types import ManagedObjType
|
||||
from .node_types import NodeType
|
||||
from .sim_types import (
|
||||
BoundCondType,
|
||||
|
@ -90,8 +93,6 @@ from .sim_types import (
|
|||
)
|
||||
from .socket_colors import SOCKET_COLORS
|
||||
from .socket_types import SocketType
|
||||
from .tree_types import TreeType
|
||||
from .unit_systems import UNITS_BLENDER, UNITS_TIDY3D
|
||||
|
||||
__all__ = [
|
||||
'BLClass',
|
||||
|
@ -108,16 +109,17 @@ __all__ = [
|
|||
'BLPropFlag',
|
||||
'BLRegionType',
|
||||
'BLSpaceType',
|
||||
'Icon',
|
||||
'KeymapItemDef',
|
||||
'ManagedObjName',
|
||||
'ManagedObjType',
|
||||
'NodeTreeType',
|
||||
'OperatorType',
|
||||
'PanelType',
|
||||
'PresetName',
|
||||
'PropName',
|
||||
'SocketName',
|
||||
'addon',
|
||||
'Icon',
|
||||
'TreeType',
|
||||
'SocketType',
|
||||
'SOCKET_COLORS',
|
||||
'SOCKET_SHAPES',
|
||||
|
@ -139,7 +141,6 @@ __all__ = [
|
|||
'manual_amp_time',
|
||||
'NodeCategory',
|
||||
'NODE_CAT_LABELS',
|
||||
'ManagedObjType',
|
||||
'FlowEvent',
|
||||
'ArrayFlow',
|
||||
'CapabilitiesFlow',
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## TODO: Unify w/category_types.py
|
||||
|
||||
from .category_types import NodeCategory as NC # noqa: N817
|
||||
|
||||
NODE_CAT_LABELS = {
|
||||
|
|
|
@ -14,22 +14,6 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import enum
|
||||
|
||||
from blender_maxwell.utils import blender_type_enum
|
||||
|
|
|
@ -14,23 +14,9 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Socket base colors for Maxwell Sim sockets."""
|
||||
|
||||
from .socket_types import SocketType as ST
|
||||
from .socket_types import SocketType as ST # noqa: N817
|
||||
|
||||
## TODO: Don't just presume sRGB.
|
||||
SOCKET_COLORS = {
|
||||
|
|
|
@ -14,22 +14,6 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import enum
|
||||
|
||||
from blender_maxwell.utils import blender_type_enum
|
||||
|
@ -37,6 +21,8 @@ from blender_maxwell.utils import blender_type_enum
|
|||
|
||||
@blender_type_enum.append_cls_name_to_values
|
||||
class SocketType(blender_type_enum.BlenderTypeEnum):
|
||||
"""Identifiers for valid sockets in Maxwell Sim node trees."""
|
||||
|
||||
Expr = enum.auto()
|
||||
|
||||
# Base
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
# oscillode
|
||||
# Copyright (C) 2024 oscillode Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import enum
|
||||
|
||||
from blender_maxwell.utils import blender_type_enum
|
||||
|
||||
|
||||
@blender_type_enum.append_cls_name_to_values
|
||||
class TreeType(blender_type_enum.BlenderTypeEnum):
|
||||
MaxwellSim = enum.auto()
|
|
@ -1,111 +0,0 @@
|
|||
# oscillode
|
||||
# Copyright (C) 2024 oscillode Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import abc
|
||||
import typing as typ
|
||||
|
||||
from blender_maxwell.utils import logger, serialize
|
||||
|
||||
from .. import contracts as ct
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
||||
class ManagedObj(abc.ABC):
|
||||
"""A weak name-based reference to some kind of object external to this software.
|
||||
|
||||
While the object doesn't have to come from Blender's `bpy.types`, that is admittedly the driving motivation for this class: To encapsulate access to the powerful visual tools granted by Blender's 3D viewport, image editor, and UI.
|
||||
Through extensive testing, the functionality of an implicitly-cached, semi-strictly immediate-mode interface, demanding only a weakly-referenced name as persistance, has emerged (with all of the associated tradeoffs).
|
||||
|
||||
While not suited to all use cases, the `ManagedObj` paradigm is perfect for many situations where a node needs to "loosely own" something external and non-trivial.
|
||||
Intriguingly, the precise definition of "loose" has grown to vary greatly between subclasses, as it ends of demonstrating itself to be a matter of taste more than determinism.
|
||||
|
||||
This abstract base class serves to provide a few of the most basic of commonly-available - especially the `dump_as_msgspec`/`parse_as_msgspec` methods that allow it to be persisted using `blender_maxwell.utils.serialize`.
|
||||
|
||||
Parameters:
|
||||
managed_obj_type: Enum identifier indicating which of the `ct.ManagedObjType` the instance should declare itself as.
|
||||
"""
|
||||
|
||||
managed_obj_type: ct.ManagedObjType
|
||||
|
||||
@abc.abstractmethod
|
||||
def __init__(self, name: ct.ManagedObjName, prev_name: str | None = None):
|
||||
"""Initializes the managed object with a unique name.
|
||||
|
||||
Use `prev_name` to indicate that the managed object will initially be avaiable under `prev_name`, but that it should be renamed to `name`.
|
||||
"""
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def name(self) -> str:
|
||||
"""Retrieve the name of the managed object."""
|
||||
|
||||
@name.setter
|
||||
@abc.abstractmethod
|
||||
def name(self, value: str) -> None:
|
||||
"""Retrieve the name of the managed object."""
|
||||
|
||||
####################
|
||||
# - Methods
|
||||
####################
|
||||
@abc.abstractmethod
|
||||
def free(self) -> None:
|
||||
"""Cleanup the resources managed by the managed object."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def bl_select(self) -> None:
|
||||
"""Select the managed object in Blender, if such an operation makes sense."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def hide_preview(self) -> None:
|
||||
"""Hide any active preview of the managed object, if it exists, and if such an operation makes sense."""
|
||||
|
||||
####################
|
||||
# - Serialization
|
||||
####################
|
||||
def dump_as_msgspec(self) -> serialize.NaiveRepresentation:
|
||||
return [
|
||||
serialize.TypeID.ManagedObj,
|
||||
self.__class__.__name__,
|
||||
self.name,
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def parse_as_msgspec(obj: serialize.NaiveRepresentation) -> typ.Self:
|
||||
return next(
|
||||
subclass(obj[2])
|
||||
for subclass in ManagedObj.__subclasses__()
|
||||
if subclass.__name__ == obj[1]
|
||||
)
|
|
@ -1,32 +0,0 @@
|
|||
# oscillode
|
||||
# Copyright (C) 2024 oscillode Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
|
@ -14,33 +14,17 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# TODO: Factor this stuff into a dedicated utils/ module, so that this particular node tree becomes simple (aka. the deathly complicated logic is factored out, and can be ex. unit tested all on its own).
|
||||
## - Then this file can focus on what is special about a Maxwell Sim node tree, as opposed to the lower-level details of how we've chosen to structure our node trees in general.
|
||||
## - Right now there may not be a distinction. And there may never be. But it's a healthy way to think about the problem.
|
||||
|
||||
import contextlib
|
||||
import functools
|
||||
import queue
|
||||
import typing as typ
|
||||
|
||||
import bpy
|
||||
|
||||
from blender_maxwell.utils import logger, serialize
|
||||
from blender_maxwell.utils import logger
|
||||
|
||||
from . import contracts as ct
|
||||
from .managed_objs.managed_bl_image import ManagedBLImage
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
@ -320,7 +304,7 @@ class MaxwellSimTree(bpy.types.NodeTree):
|
|||
In general, only one `MaxwellSimTree` should be active at a time.
|
||||
"""
|
||||
|
||||
bl_idname = ct.TreeType.MaxwellSim.value
|
||||
bl_idname = ct.NodeTreeType.MaxwellSim.value
|
||||
bl_label = 'Maxwell Sim Editor'
|
||||
bl_icon = ct.Icon.SimNodeEditor
|
||||
|
||||
|
@ -328,6 +312,8 @@ class MaxwellSimTree(bpy.types.NodeTree):
|
|||
default=True,
|
||||
)
|
||||
|
||||
viewer_node_type: ct.NodeType = ct.NodeType.Viewer
|
||||
|
||||
####################
|
||||
# - Init Methods
|
||||
####################
|
||||
|
@ -552,7 +538,8 @@ def populate_missing_persistence(_) -> None:
|
|||
for node_tree in [
|
||||
_node_tree
|
||||
for _node_tree in bpy.data.node_groups
|
||||
if _node_tree.bl_idname == ct.TreeType.MaxwellSim.value and _node_tree.is_active
|
||||
if _node_tree.bl_idname == ct.NodeTreeType.MaxwellSim.value
|
||||
and _node_tree.is_active
|
||||
]:
|
||||
log.debug(
|
||||
'%s: Regenerating Dynamic Field Persistance for NodeTree nodes/sockets',
|
||||
|
|
|
@ -14,22 +14,6 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# blender_maxwell
|
||||
# Copyright (C) 2024 blender_maxwell Project Contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from . import (
|
||||
analysis,
|
||||
inputs,
|
||||
|
|
|
@ -41,7 +41,6 @@ import jax.numpy as jnp
|
|||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
import xarray
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger, sim_symbols
|
||||
|
||||
from ... import contracts as ct
|
||||
|
|
|
@ -37,7 +37,6 @@ import typing as typ
|
|||
|
||||
import bpy
|
||||
import sympy as sp
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger, sim_symbols
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ See `blender_maxwell.maxwell_sim_nodes.math_system` for the actual mathematics i
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@ import bpy
|
|||
import jax
|
||||
import jax.numpy as jnp
|
||||
import numpy as np
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger, sim_symbols
|
||||
|
||||
from .... import contracts as ct
|
||||
|
|
|
@ -37,7 +37,6 @@ import typing as typ
|
|||
|
||||
import bpy
|
||||
import sympy as sp
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger, sim_symbols
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -38,10 +38,9 @@ import jaxtyping as jtyp
|
|||
import matplotlib.axis as mpl_ax
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
from frozendict import frozendict
|
||||
|
||||
from blender_maxwell.utils import bl_cache, image_ops, logger, sim_symbols
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
from frozendict import frozendict
|
||||
|
||||
from ... import contracts as ct
|
||||
from ... import managed_objs, sockets
|
||||
|
|
|
@ -43,7 +43,6 @@ from collections import defaultdict
|
|||
from types import MappingProxyType
|
||||
|
||||
import bpy
|
||||
|
||||
from blender_maxwell.utils import bl_cache, bl_instance, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
@ -1196,7 +1195,7 @@ class MaxwellSimNode(bpy.types.Node, bl_instance.BLInstance):
|
|||
Returns:
|
||||
Whether or not the node can be instantiated within the given node tree.
|
||||
"""
|
||||
return node_tree.bl_idname == ct.TreeType.MaxwellSim.value
|
||||
return node_tree.bl_idname == ct.NodeTreeType.MaxwellSim
|
||||
|
||||
def init(self, _: bpy.types.Context) -> None:
|
||||
"""Initialize the node instance, including ID, name, socket, presets, and the execution of any `on_value_changed` methods with the `run_on_init` keyword set.
|
||||
|
|
|
@ -36,14 +36,11 @@ import typing as typ
|
|||
import uuid
|
||||
from collections import defaultdict
|
||||
from fractions import Fraction
|
||||
from types import MappingProxyType
|
||||
|
||||
import bpy
|
||||
import jax
|
||||
import numpy as np
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
from blender_maxwell.utils.frozendict import FrozenDict, frozendict
|
||||
|
|
|
@ -36,10 +36,9 @@ import typing as typ
|
|||
|
||||
import bpy
|
||||
import sympy as sp
|
||||
from frozendict import frozendict
|
||||
|
||||
from blender_maxwell.utils import bl_cache, sci_constants, sim_symbols
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
from frozendict import frozendict
|
||||
|
||||
from .... import contracts as ct
|
||||
from .... import sockets
|
||||
|
|
|
@ -38,7 +38,6 @@ from fractions import Fraction
|
|||
|
||||
import bpy
|
||||
import sympy as sp
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger, sim_symbols
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@ from pathlib import Path
|
|||
import bpy
|
||||
import sympy as sp
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger, sim_symbols
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ from pathlib import Path
|
|||
|
||||
import bpy
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
|
||||
from .... import contracts as ct
|
||||
|
|
|
@ -37,7 +37,6 @@ import typing as typ
|
|||
import bpy
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
@ -146,7 +145,8 @@ def update_scene_node_after_frame_changed(
|
|||
for node_tree in [
|
||||
_node_tree
|
||||
for _node_tree in bpy.data.node_groups
|
||||
if _node_tree.bl_idname == ct.TreeType.MaxwellSim.value and _node_tree.is_active
|
||||
if _node_tree.bl_idname == ct.NodeTreeType.MaxwellSim.value
|
||||
and _node_tree.is_active
|
||||
]:
|
||||
for node in [
|
||||
_node
|
||||
|
|
|
@ -36,7 +36,6 @@ import typing as typ
|
|||
|
||||
import bpy
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.services import tdcloud
|
||||
from blender_maxwell.utils import bl_cache, logger, sim_symbols
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
|
|
@ -40,11 +40,10 @@ import bpy
|
|||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
from tidy3d.material_library.material_library import MaterialItem as Tidy3DMediumItem
|
||||
from tidy3d.material_library.material_library import VariantItem as Tidy3DMediumVariant
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger, sci_constants
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
from tidy3d.material_library.material_library import MaterialItem as Tidy3DMediumItem
|
||||
from tidy3d.material_library.material_library import VariantItem as Tidy3DMediumVariant
|
||||
|
||||
from ... import contracts as ct
|
||||
from ... import managed_objs, sockets
|
||||
|
|
|
@ -36,7 +36,6 @@ import functools
|
|||
import typing as typ
|
||||
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import typing as typ
|
|||
|
||||
import bpy
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import typing as typ
|
|||
|
||||
import bpy
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import bpy
|
|||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
import tidy3d.plugins.dispersion as td_dispersion
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import bpy
|
|||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.assets.geonodes import GeoNodes, import_geonodes
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
|
|
@ -39,7 +39,6 @@ import bpy
|
|||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.assets.geonodes import GeoNodes, import_geonodes
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
|
|
@ -34,7 +34,6 @@ import typing as typ
|
|||
|
||||
import sympy as sp
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.assets.geonodes import GeoNodes, import_geonodes
|
||||
from blender_maxwell.utils import logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
|
|
@ -34,7 +34,6 @@ import typing as typ
|
|||
from pathlib import Path
|
||||
|
||||
import bpy
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -115,10 +115,9 @@ class JSONFileExporterNode(base.MaxwellSimNode):
|
|||
return data.json()
|
||||
|
||||
# Pydantic Models: Call .model_dump_json()
|
||||
elif isinstance(data, pyd.BaseModel):
|
||||
if isinstance(data, pyd.BaseModel):
|
||||
return data.model_dump_json()
|
||||
|
||||
else:
|
||||
json.dumps(data)
|
||||
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ import typing as typ
|
|||
import bpy
|
||||
import sympy as sp
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import typing as typ
|
|||
|
||||
import bpy
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.services import tdcloud
|
||||
from blender_maxwell.utils import bl_cache, logger, sim_symbols
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ import typing as typ
|
|||
import bpy
|
||||
import sympy as sp
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import typing as typ
|
|||
|
||||
import bpy
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
|
||||
from .... import contracts as ct
|
||||
|
|
|
@ -37,7 +37,6 @@ import typing as typ
|
|||
import bpy
|
||||
import sympy as sp
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
import typing as typ
|
||||
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
|
||||
from ... import contracts as ct
|
||||
|
|
|
@ -36,12 +36,9 @@ import itertools
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import jax
|
||||
import numpy as np
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger, sim_symbols
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
from blender_maxwell.utils.frozendict import frozendict
|
||||
|
|
|
@ -36,7 +36,6 @@ import typing as typ
|
|||
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from blender_maxwell.assets.geonodes import GeoNodes, import_geonodes
|
||||
from blender_maxwell.utils import logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
|
|
@ -36,7 +36,6 @@ import typing as typ
|
|||
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
|
||||
from ... import contracts as ct
|
||||
|
|
|
@ -36,7 +36,6 @@ import typing as typ
|
|||
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
|
||||
from .... import contracts as ct
|
||||
|
|
|
@ -36,7 +36,6 @@ import typing as typ
|
|||
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
|
||||
from .... import contracts as ct
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
|
||||
from blender_maxwell.services import tdcloud
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
|
|
@ -38,7 +38,6 @@ import typing as typ
|
|||
import bpy
|
||||
import sympy as sp
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
from blender_maxwell.utils.frozendict import frozendict
|
||||
|
|
|
@ -37,7 +37,6 @@ import typing as typ
|
|||
import bpy
|
||||
import sympy as sp
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.assets.geonodes import GeoNodes, import_geonodes
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
import typing as typ
|
||||
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
from blender_maxwell.utils.frozendict import frozendict
|
||||
|
|
|
@ -37,7 +37,6 @@ import typing as typ
|
|||
import bpy
|
||||
import sympy as sp
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.assets.geonodes import GeoNodes, import_geonodes
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
|
|
@ -37,7 +37,6 @@ import typing as typ
|
|||
import bpy
|
||||
import sympy as sp
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.assets.geonodes import GeoNodes, import_geonodes
|
||||
from blender_maxwell.utils import bl_cache, logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
|
|
@ -40,14 +40,13 @@ import numpy as np
|
|||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
from blender_maxwell.utils import bl_cache, logger, sim_symbols
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
from tidy3d.components.data.data_array import TimeDataArray as td_TimeDataArray
|
||||
from tidy3d.components.data.dataset import TimeDataset as td_TimeDataset
|
||||
|
||||
from blender_maxwell.utils import bl_cache, logger, sim_symbols
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
from ... import contracts as ct
|
||||
from ... import managed_objs, sockets
|
||||
from ... import sockets
|
||||
from .. import base, events
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
|
|
@ -38,7 +38,6 @@ import typing as typ
|
|||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.utils import logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ import typing as typ
|
|||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.assets.geonodes import GeoNodes, import_geonodes
|
||||
from blender_maxwell.utils import logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
|
|
@ -37,7 +37,6 @@ import typing as typ
|
|||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from blender_maxwell.assets.geonodes import GeoNodes, import_geonodes
|
||||
from blender_maxwell.utils import logger
|
||||
from blender_maxwell.utils import sympy_extra as spux
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue