Implement basic addon reloading

This commit is contained in:
Moritz Brückner 2021-08-04 22:49:38 +02:00
parent b664e3a010
commit ea8c13686c
63 changed files with 738 additions and 83 deletions

View file

@ -0,0 +1,26 @@
import importlib
import types
# This gets cleared if this package/the __init__ module is reloaded
_module_cache: dict[str, types.ModuleType] = {}
def reload_module(module: types.ModuleType) -> types.ModuleType:
"""Wrapper around importlib.reload() to make sure no module is
reloaded twice.
Make sure to call this function in the same order in which the
modules are imported to make sure that the reloading respects the
module dependencies. Otherwise modules could depend on other modules
that are not yet reloaded.
If you import classes or functions from a module, make sure to
re-import them after the module is reloaded.
"""
mod = _module_cache.get(module.__name__, None)
if mod is None:
mod = importlib.reload(module)
_module_cache[module.__name__] = mod
return mod

View file

@ -4,7 +4,14 @@ from bpy.types import Material, UILayout
from arm.material.shader import ShaderContext from arm.material.shader import ShaderContext
drivers: Dict[str, Dict] = dict() if "DO_RELOAD_MODULE" in locals():
import arm
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import ShaderContext
else:
drivers: Dict[str, Dict] = dict()
DO_RELOAD_MODULE = True
def add_driver(driver_name: str, def add_driver(driver_name: str,

View file

@ -6,6 +6,12 @@ import bpy
import arm.log as log import arm.log as log
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
log = arm.reload_module(log)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
assets = [] assets = []
reserved_names = ['return.'] reserved_names = ['return.']
khafile_params = [] khafile_params = []

View file

@ -32,7 +32,19 @@ import arm.material.mat_batch as mat_batch
import arm.utils import arm.utils
import arm.profiler import arm.profiler
import arm.log as log if "DO_RELOAD_MODULE" in locals():
assets = arm.reload_module(assets)
exporter_opt = arm.reload_module(exporter_opt)
log = arm.reload_module(log)
make_renderpath = arm.reload_module(make_renderpath)
cycles = arm.reload_module(cycles)
make_material = arm.reload_module(make_material)
mat_batch = arm.reload_module(mat_batch)
arm.utils = arm.reload_module(arm.utils)
arm.profiler = arm.reload_module(arm.profiler)
else:
DO_RELOAD_MODULE = True
@unique @unique
class NodeType(Enum): class NodeType(Enum):

View file

@ -1,11 +1,20 @@
"""
Exports smaller geometry but is slower.
To be replaced with https://github.com/zeux/meshoptimizer
"""
from mathutils import * from mathutils import *
import numpy as np import numpy as np
import arm.utils
import arm.log as log import arm.log as log
import arm.utils
if "DO_RELOAD_MODULE" in locals():
log = arm.reload_module(log)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
# Exports smaller geometry but is slower
# To be replaced with https://github.com/zeux/meshoptimizer
class Vertex: class Vertex:
__slots__ = ("co", "normal", "uvs", "col", "loop_indices", "index", "bone_weights", "bone_indices", "bone_count", "vertex_index") __slots__ = ("co", "normal", "uvs", "col", "loop_indices", "index", "bone_weights", "bone_indices", "bone_count", "vertex_index")

View file

@ -15,6 +15,18 @@ import arm.make_state as state
import arm.props as props import arm.props as props
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
arm.api = arm.reload_module(arm.api)
live_patch = arm.reload_module(live_patch)
arm_nodes = arm.reload_module(arm_nodes)
arm.nodes_logic = arm.reload_module(arm.nodes_logic)
make = arm.reload_module(make)
state = arm.reload_module(state)
props = arm.reload_module(props)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
@persistent @persistent
def on_depsgraph_update_post(self): def on_depsgraph_update_post(self):

View file

@ -1,8 +1,16 @@
import bpy import bpy
import arm.props_ui as props_ui import arm.props_ui as props_ui
if "DO_RELOAD_MODULE" in locals():
import arm
props_ui = arm.reload_module(props_ui)
else:
DO_RELOAD_MODULE = True
arm_keymaps = [] arm_keymaps = []
def register(): def register():
wm = bpy.context.window_manager wm = bpy.context.window_manager
addon_keyconfig = wm.keyconfigs.addon addon_keyconfig = wm.keyconfigs.addon
@ -21,6 +29,7 @@ def register():
km.keymap_items.new("tlm.clean_lightmaps", type='F7', value='PRESS') km.keymap_items.new("tlm.clean_lightmaps", type='F7', value='PRESS')
arm_keymaps.append(km) arm_keymaps.append(km)
def unregister(): def unregister():
wm = bpy.context.window_manager wm = bpy.context.window_manager
for km in arm_keymaps: for km in arm_keymaps:

View file

@ -20,9 +20,10 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
# #
import struct
import io import io
import numpy as np import numpy as np
import struct
def _pack_integer(obj, fp): def _pack_integer(obj, fp):
if obj < 0: if obj < 0:

View file

@ -1,7 +1,7 @@
import atexit
import http.server import http.server
import socketserver import socketserver
import subprocess import subprocess
import atexit
haxe_server = None haxe_server = None

View file

@ -5,23 +5,37 @@ from typing import Any, Type
import bpy import bpy
import arm.assets import arm.assets
import arm.node_utils
from arm.exporter import ArmoryExporter from arm.exporter import ArmoryExporter
import arm.log as log import arm.log as log
from arm.logicnode.arm_nodes import ArmLogicTreeNode from arm.logicnode.arm_nodes import ArmLogicTreeNode
import arm.make as make import arm.make as make
import arm.make_state as state import arm.make_state as state
import arm.node_utils
import arm.utils import arm.utils
# Current patch id if "DO_RELOAD_MODULE" in locals():
patch_id = 0 arm.assets = arm.reload_module(arm.assets)
arm.exporter = arm.reload_module(arm.exporter)
from arm.exporter import ArmoryExporter
log = arm.reload_module(log)
arm.logicnode.arm_nodes = arm.reload_module(arm.logicnode.arm_nodes)
from arm.logicnode.arm_nodes import ArmLogicTreeNode
make = arm.reload_module(make)
state = arm.reload_module(state)
arm.node_utils = arm.reload_module(arm.node_utils)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
patch_id = 0
"""Current patch id"""
__running = False
"""Whether live patch is currently active"""
# Any object can act as a message bus owner # Any object can act as a message bus owner
msgbus_owner = object() msgbus_owner = object()
# Whether live patch is currently active
__running = False
def start(): def start():
"""Start the live patch session.""" """Start the live patch session."""
@ -43,9 +57,10 @@ def start():
def stop(): def stop():
"""Stop the live patch session.""" """Stop the live patch session."""
global __running global __running, patch_id
if __running: if __running:
__running = False __running = False
patch_id = 0
log.debug("Live patch session stopped") log.debug("Live patch session stopped")
bpy.msgbus.clear_by_owner(msgbus_owner) bpy.msgbus.clear_by_owner(msgbus_owner)

View file

@ -1,13 +1,29 @@
import importlib import importlib
import inspect import inspect
import pkgutil import pkgutil
import sys
import arm
import arm.logicnode.arm_nodes as arm_nodes import arm.logicnode.arm_nodes as arm_nodes
from arm.logicnode.arm_props import *
import arm.logicnode.arm_sockets as arm_sockets import arm.logicnode.arm_sockets as arm_sockets
from arm.logicnode.replacement import NodeReplacement
if "DO_RELOAD_MODULE" in locals():
arm_nodes = arm.reload_module(arm_nodes)
arm.logicnode.arm_props = arm.reload_module(arm.logicnode.arm_props)
from arm.logicnode.arm_props import *
arm_sockets = arm.reload_module(arm_sockets)
arm.logicnode.replacement = arm.reload_module(arm.logicnode.replacement)
from arm.logicnode.replacement import NodeReplacement
HAS_RELOADED = True
else:
DO_RELOAD_MODULE = True
def init_categories(): def init_categories():
# Register node menu categories """Register default node menu categories."""
arm_nodes.add_category('Logic', icon='OUTLINER', section="basic", arm_nodes.add_category('Logic', icon='OUTLINER', section="basic",
description="Logic nodes are used to control execution flow using branching, loops, gates etc.") description="Logic nodes are used to control execution flow using branching, loops, gates etc.")
arm_nodes.add_category('Event', icon='INFO', section="basic") arm_nodes.add_category('Event', icon='INFO', section="basic")
@ -56,8 +72,15 @@ def init_nodes():
# The package must be loaded as well so that the modules from that package can be accessed (see the # The package must be loaded as well so that the modules from that package can be accessed (see the
# pkgutil.walk_packages documentation for more information on this) # pkgutil.walk_packages documentation for more information on this)
loader.find_module(module_name).load_module(module_name) loader.find_module(module_name).load_module(module_name)
else:
_module = importlib.import_module(module_name) # Only look at modules in sub packages
elif module_name.rsplit('.', 1)[0] != __package__:
if 'HAS_RELOADED' not in globals():
_module = importlib.import_module(module_name)
else:
# Reload the module if the SDK was reloaded at least once
_module = importlib.reload(sys.modules[module_name])
for name, obj in inspect.getmembers(_module, inspect.isclass): for name, obj in inspect.getmembers(_module, inspect.isclass):
if name == "ArmLogicTreeNode": if name == "ArmLogicTreeNode":
continue continue

View file

@ -1,5 +1,5 @@
import itertools
from collections import OrderedDict from collections import OrderedDict
import itertools
from typing import Any, Generator, List, Optional, Type from typing import Any, Generator, List, Optional, Type
from typing import OrderedDict as ODict # Prevent naming conflicts from typing import OrderedDict as ODict # Prevent naming conflicts
@ -14,6 +14,15 @@ from arm.logicnode.arm_props import *
from arm.logicnode.replacement import NodeReplacement from arm.logicnode.replacement import NodeReplacement
import arm.node_utils import arm.node_utils
if "DO_RELOAD_MODULE" in locals():
arm.logicnode.arm_props = arm.reload_module(arm.logicnode.arm_props)
from arm.logicnode.arm_props import *
arm.logicnode.replacement = arm.reload_module(arm.logicnode.replacement)
from arm.logicnode.replacement import NodeReplacement
arm.node_utils = arm.reload_module(arm.node_utils)
else:
DO_RELOAD_MODULE = True
# When passed as a category to add_node(), this will use the capitalized # When passed as a category to add_node(), this will use the capitalized
# name of the package of the node as the category to make renaming # name of the package of the node as the category to make renaming
# categories easier. # categories easier.

View file

@ -15,6 +15,20 @@ from typing import Any, Callable, Sequence, Union
import bpy import bpy
from bpy.props import * from bpy.props import *
__all__ = [
'HaxeBoolProperty',
'HaxeBoolVectorProperty',
'HaxeCollectionProperty',
'HaxeEnumProperty',
'HaxeFloatProperty',
'HaxeFloatVectorProperty',
'HaxeIntProperty',
'HaxeIntVectorProperty',
'HaxePointerProperty',
'HaxeStringProperty',
'RemoveHaxeProperty'
]
def __haxe_prop(prop_type: Callable, prop_name: str, *args, **kwargs) -> Any: def __haxe_prop(prop_type: Callable, prop_name: str, *args, **kwargs) -> Any:
"""Declares a logic node property as a property that will be """Declares a logic node property as a property that will be

View file

@ -4,6 +4,11 @@ from bpy.types import NodeSocket
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
def _on_update_socket(self, context): def _on_update_socket(self, context):
self.node.on_socket_val_update(context, self) self.node.on_socket_val_update(context, self)

View file

@ -20,6 +20,14 @@ import arm.logicnode.arm_nodes as arm_nodes
import arm.logicnode.arm_sockets import arm.logicnode.arm_sockets
import arm.node_utils as node_utils import arm.node_utils as node_utils
if "DO_RELOAD_MODULE" in locals():
log = arm.reload_module(log)
arm_nodes = arm.reload_module(arm_nodes)
arm.logicnode.arm_sockets = arm.reload_module(arm.logicnode.arm_sockets)
node_utils = arm.reload_module(node_utils)
else:
DO_RELOAD_MODULE = True
# List of errors that occurred during the replacement # List of errors that occurred during the replacement
# Format: (error identifier, node.bl_idname (or None), tree name, exception traceback (optional)) # Format: (error identifier, node.bl_idname (or None), tree name, exception traceback (optional))
replacement_errors: List[Tuple[str, Optional[str], str, Optional[str]]] = [] replacement_errors: List[Tuple[str, Optional[str], str, Optional[str]]] = []

View file

@ -27,6 +27,23 @@ import arm.make_world as make_world
import arm.utils import arm.utils
import arm.write_data as write_data import arm.write_data as write_data
if "DO_RELOAD_MODULE" in locals():
assets = arm.reload_module(assets)
arm.exporter = arm.reload_module(arm.exporter)
from arm.exporter import ArmoryExporter
arm.lib.make_datas = arm.reload_module(arm.lib.make_datas)
arm.lib.server = arm.reload_module(arm.lib.server)
live_patch = arm.reload_module(live_patch)
log = arm.reload_module(log)
make_logic = arm.reload_module(make_logic)
make_renderpath = arm.reload_module(make_renderpath)
state = arm.reload_module(state)
make_world = arm.reload_module(make_world)
arm.utils = arm.reload_module(arm.utils)
write_data = arm.reload_module(write_data)
else:
DO_RELOAD_MODULE = True
scripts_mtime = 0 # Monitor source changes scripts_mtime = 0 # Monitor source changes
profile_time = 0 profile_time = 0

View file

@ -8,6 +8,15 @@ import arm.log
import arm.node_utils import arm.node_utils
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
arm.exporter = arm.reload_module(arm.exporter)
from arm.exporter import ArmoryExporter
arm.log = arm.reload_module(arm.log)
arm.node_utils = arm.reload_module(arm.node_utils)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
parsed_nodes = [] parsed_nodes = []
parsed_ids = dict() # Sharing node data parsed_ids = dict() # Sharing node data
function_nodes = dict() function_nodes = dict()

View file

@ -1,9 +1,19 @@
import bpy import bpy
import arm.api
import arm.assets as assets import arm.assets as assets
import arm.utils
import arm.log as log import arm.log as log
import arm.make_state as state import arm.make_state as state
import arm.api import arm.utils
if "DO_RELOAD_MODULE" in locals():
arm.api = arm.reload_module(arm.api)
assets = arm.reload_module(assets)
log = arm.reload_module(log)
state = arm.reload_module(state)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
callback = None callback = None

View file

@ -1,15 +1,18 @@
redraw_ui = False if "DO_RELOAD_MODULE" not in locals():
target = 'krom' DO_RELOAD_MODULE = True
last_target = 'krom'
export_gapi = '' redraw_ui = False
last_resx = 0 target = 'krom'
last_resy = 0 last_target = 'krom'
last_scene = '' export_gapi = ''
last_world_defs = '' last_resx = 0
proc_play = None last_resy = 0
proc_build = None last_scene = ''
proc_publish_build = None last_world_defs = ''
mod_scripts = [] proc_play = None
is_export = False proc_build = None
is_play = False proc_publish_build = None
is_publish = False mod_scripts = []
is_export = False
is_play = False
is_publish = False

View file

@ -12,6 +12,21 @@ import arm.node_utils as node_utils
import arm.utils import arm.utils
import arm.write_probes as write_probes import arm.write_probes as write_probes
if "DO_RELOAD_MODULE" in locals():
arm.assets = arm.reload_module(arm.assets)
arm.log = arm.reload_module(arm.log)
arm.material = arm.reload_module(arm.material)
arm.material.parser_state = arm.reload_module(arm.material.parser_state)
from arm.material.parser_state import ParserState, ParserContext
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import ShaderContext, Shader
cycles = arm.reload_module(cycles)
node_utils = arm.reload_module(node_utils)
arm.utils = arm.reload_module(arm.utils)
write_probes = arm.reload_module(write_probes)
else:
DO_RELOAD_MODULE = True
callback = None callback = None
shader_datas = [] shader_datas = []

View file

@ -0,0 +1 @@
import arm

View file

@ -5,6 +5,17 @@ from arm.material.arm_nodes.arm_nodes import add_node
from arm.material.shader import Shader from arm.material.shader import Shader
from arm.material.cycles import * from arm.material.cycles import *
if "DO_RELOAD_MODULE" in locals():
import arm
arm.material.arm_nodes.arm_nodes = arm.reload_module(arm.material.arm_nodes.arm_nodes)
from arm.material.arm_nodes.arm_nodes import add_node
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import Shader
arm.material.cycles = arm.reload_module(arm.material.cycles)
from arm.material.cycles import *
else:
DO_RELOAD_MODULE = True
class CustomParticleNode(Node): class CustomParticleNode(Node):
"""Input data for paricles.""" """Input data for paricles."""
@ -174,7 +185,7 @@ class CustomParticleNode(Node):
if self.posZ: if self.posZ:
vertshdr.write(f'spos.z += {pos}.z;') vertshdr.write(f'spos.z += {pos}.z;')
vertshdr.write('wposition = vec4(W * spos).xyz;') vertshdr.write('wposition = vec4(W * spos).xyz;')

View file

@ -4,6 +4,15 @@ from bpy.types import Node
from arm.material.arm_nodes.arm_nodes import add_node from arm.material.arm_nodes.arm_nodes import add_node
from arm.material.shader import Shader from arm.material.shader import Shader
if "DO_RELOAD_MODULE" in locals():
import arm
arm.material.arm_nodes.arm_nodes = arm.reload_module(arm.material.arm_nodes.arm_nodes)
from arm.material.arm_nodes.arm_nodes import add_node
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import Shader
else:
DO_RELOAD_MODULE = True
class ShaderDataNode(Node): class ShaderDataNode(Node):
"""Allows access to shader data such as uniforms and inputs.""" """Allows access to shader data such as uniforms and inputs."""

View file

@ -30,6 +30,23 @@ from arm.material.parser_state import ParserState, ParserContext
from arm.material.shader import Shader, ShaderContext, floatstr, vec3str from arm.material.shader import Shader, ShaderContext, floatstr, vec3str
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
arm.assets = arm.reload_module(arm.assets)
log = arm.reload_module(log)
arm.make_state = arm.reload_module(arm.make_state)
c_functions = arm.reload_module(c_functions)
arm.material.cycles_nodes = arm.reload_module(arm.material.cycles_nodes)
from arm.material.cycles_nodes import *
mat_state = arm.reload_module(mat_state)
arm.material.parser_state = arm.reload_module(arm.material.parser_state)
from arm.material.parser_state import ParserState, ParserContext
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import Shader, ShaderContext, floatstr, vec3str
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
# Particle info export # Particle info export
particle_info: Dict[str, bool] = {} particle_info: Dict[str, bool] = {}

View file

@ -6,6 +6,18 @@ import arm.material.cycles_functions as c_functions
from arm.material.parser_state import ParserState from arm.material.parser_state import ParserState
from arm.material.shader import floatstr, vec3str from arm.material.shader import floatstr, vec3str
if "DO_RELOAD_MODULE" in locals():
import arm
log = arm.reload_module(log)
c = arm.reload_module(c)
c_functions = arm.reload_module(c_functions)
arm.material.parser_state = arm.reload_module(arm.material.parser_state)
from arm.material.parser_state import ParserState
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import floatstr, vec3str
else:
DO_RELOAD_MODULE = True
def parse_brightcontrast(node: bpy.types.ShaderNodeBrightContrast, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str: def parse_brightcontrast(node: bpy.types.ShaderNodeBrightContrast, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
out_col = c.parse_vector_input(node.inputs[0]) out_col = c.parse_vector_input(node.inputs[0])

View file

@ -8,6 +8,19 @@ import arm.material.cycles_functions as c_functions
from arm.material.parser_state import ParserState from arm.material.parser_state import ParserState
from arm.material.shader import floatstr, vec3str from arm.material.shader import floatstr, vec3str
if "DO_RELOAD_MODULE" in locals():
import arm
log = arm.reload_module(log)
c = arm.reload_module(c)
c_functions = arm.reload_module(c_functions)
arm.material.parser_state = arm.reload_module(arm.material.parser_state)
from arm.material.parser_state import ParserState
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import floatstr, vec3str
else:
DO_RELOAD_MODULE = True
def parse_maprange(node: bpy.types.ShaderNodeMapRange, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr: def parse_maprange(node: bpy.types.ShaderNodeMapRange, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr:
interp = node.interpolation_type interp = node.interpolation_type
@ -40,7 +53,7 @@ def parse_maprange(node: bpy.types.ShaderNodeMapRange, out_socket: bpy.types.Nod
return f'map_range_smootherstep({value}, {fromMin}, {fromMax}, {toMin}, {toMax})' return f'map_range_smootherstep({value}, {fromMin}, {fromMax}, {toMin}, {toMax})'
def parse_blackbody(node: bpy.types.ShaderNodeBlackbody, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str: def parse_blackbody(node: bpy.types.ShaderNodeBlackbody, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
t = c.parse_value_input(node.inputs[0]) t = c.parse_value_input(node.inputs[0])
state.curshader.add_function(c_functions.str_blackbody) state.curshader.add_function(c_functions.str_blackbody)

View file

@ -10,6 +10,18 @@ from arm.material.parser_state import ParserState, ParserContext
from arm.material.shader import floatstr, vec3str from arm.material.shader import floatstr, vec3str
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
log = arm.reload_module(log)
c = arm.reload_module(c)
c_functions = arm.reload_module(c_functions)
arm.material.parser_state = arm.reload_module(arm.material.parser_state)
from arm.material.parser_state import ParserState, ParserContext
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import floatstr, vec3str
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
def parse_attribute(node: bpy.types.ShaderNodeAttribute, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]: def parse_attribute(node: bpy.types.ShaderNodeAttribute, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
out_type = 'float' if out_socket.type == 'VALUE' else 'vec3' out_type = 'float' if out_socket.type == 'VALUE' else 'vec3'

View file

@ -4,6 +4,14 @@ from bpy.types import NodeSocket
import arm.material.cycles as c import arm.material.cycles as c
from arm.material.parser_state import ParserState from arm.material.parser_state import ParserState
if "DO_RELOAD_MODULE" in locals():
import arm
c = arm.reload_module(c)
arm.material.parser_state = arm.reload_module(arm.material.parser_state)
from arm.material.parser_state import ParserState
else:
DO_RELOAD_MODULE = True
def parse_mixshader(node: bpy.types.ShaderNodeMixShader, out_socket: NodeSocket, state: ParserState) -> None: def parse_mixshader(node: bpy.types.ShaderNodeMixShader, out_socket: NodeSocket, state: ParserState) -> None:
prefix = '' if node.inputs[0].is_linked else 'const ' prefix = '' if node.inputs[0].is_linked else 'const '

View file

@ -6,13 +6,27 @@ import bpy
import arm.assets as assets import arm.assets as assets
import arm.log as log import arm.log as log
import arm.material.cycles_functions as c_functions
import arm.material.cycles as c import arm.material.cycles as c
import arm.material.cycles_functions as c_functions
from arm.material.parser_state import ParserState, ParserContext from arm.material.parser_state import ParserState, ParserContext
from arm.material.shader import floatstr, vec3str from arm.material.shader import floatstr, vec3str
import arm.utils import arm.utils
import arm.write_probes as write_probes import arm.write_probes as write_probes
if "DO_RELOAD_MODULE" in locals():
assets = arm.reload_module(assets)
log = arm.reload_module(log)
c = arm.reload_module(c)
c_functions = arm.reload_module(c_functions)
arm.material.parser_state = arm.reload_module(arm.material.parser_state)
from arm.material.parser_state import ParserState, ParserContext
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import floatstr, vec3str
arm.utils = arm.reload_module(arm.utils)
write_probes = arm.reload_module(write_probes)
else:
DO_RELOAD_MODULE = True
def parse_tex_brick(node: bpy.types.ShaderNodeTexBrick, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]: def parse_tex_brick(node: bpy.types.ShaderNodeTexBrick, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
state.curshader.add_function(c_functions.str_tex_brick) state.curshader.add_function(c_functions.str_tex_brick)

View file

@ -8,6 +8,17 @@ import arm.material.cycles_functions as c_functions
from arm.material.parser_state import ParserState from arm.material.parser_state import ParserState
from arm.material.shader import floatstr, vec3str from arm.material.shader import floatstr, vec3str
if "DO_RELOAD_MODULE" in locals():
import arm
c = arm.reload_module(c)
c_functions = arm.reload_module(c_functions)
arm.material.parser_state = arm.reload_module(arm.material.parser_state)
from arm.material.parser_state import ParserState
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import floatstr, vec3str
else:
DO_RELOAD_MODULE = True
def parse_curvevec(node: bpy.types.ShaderNodeVectorCurve, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str: def parse_curvevec(node: bpy.types.ShaderNodeVectorCurve, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
fac = c.parse_value_input(node.inputs[0]) fac = c.parse_value_input(node.inputs[0])
@ -144,7 +155,7 @@ def parse_displacement(node: bpy.types.ShaderNodeDisplacement, out_socket: bpy.t
return f'(vec3({height}) * {scale})' return f'(vec3({height}) * {scale})'
def parse_vectorrotate(node: bpy.types.ShaderNodeVectorRotate, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str: def parse_vectorrotate(node: bpy.types.ShaderNodeVectorRotate, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
type = node.rotation_type type = node.rotation_type
input_vector: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[0]) input_vector: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[0])
input_center: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[1]) input_center: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[1])
@ -166,9 +177,9 @@ def parse_vectorrotate(node: bpy.types.ShaderNodeVectorRotate, out_socket: bpy.t
elif type == 'Y_AXIS': elif type == 'Y_AXIS':
return f'vec3( rotate_around_axis({input_vector} - {input_center}, vec3(0.0, 1.0, 0.0), {input_angle} * {input_invert}) + {input_center} )' return f'vec3( rotate_around_axis({input_vector} - {input_center}, vec3(0.0, 1.0, 0.0), {input_angle} * {input_invert}) + {input_center} )'
elif type == 'Z_AXIS': elif type == 'Z_AXIS':
return f'vec3( rotate_around_axis({input_vector} - {input_center}, vec3(0.0, 0.0, 1.0), {input_angle} * {input_invert}) + {input_center} )' return f'vec3( rotate_around_axis({input_vector} - {input_center}, vec3(0.0, 0.0, 1.0), {input_angle} * {input_invert}) + {input_center} )'
elif type == 'EULER_XYZ': elif type == 'EULER_XYZ':
state.curshader.add_function(c_functions.str_euler_to_mat3) state.curshader.add_function(c_functions.str_euler_to_mat3)
return f'vec3( mat3(({input_invert} < 0.0) ? transpose(euler_to_mat3({input_rotation})) : euler_to_mat3({input_rotation})) * ({input_vector} - {input_center}) + {input_center})' return f'vec3( mat3(({input_invert} < 0.0) ? transpose(euler_to_mat3({input_rotation})) : euler_to_mat3({input_rotation})) * ({input_vector} - {input_center}) + {input_center})'
return f'(vec3(1.0, 0.0, 0.0))' return f'(vec3(1.0, 0.0, 0.0))'

View file

@ -10,6 +10,15 @@ import arm.material.mat_batch as mat_batch
import arm.node_utils import arm.node_utils
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
cycles = arm.reload_module(cycles)
make_shader = arm.reload_module(make_shader)
mat_batch = arm.reload_module(mat_batch)
arm.node_utils = arm.reload_module(arm.node_utils)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
def glsl_value(val): def glsl_value(val):
if str(type(val)) == "<class 'bpy_prop_array'>": if str(type(val)) == "<class 'bpy_prop_array'>":

View file

@ -9,6 +9,19 @@ import arm.material.make_tess as make_tess
from arm.material.shader import Shader, ShaderContext from arm.material.shader import Shader, ShaderContext
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
cycles = arm.reload_module(cycles)
mat_state = arm.reload_module(mat_state)
make_skin = arm.reload_module(make_skin)
make_particle = arm.reload_module(make_particle)
make_inst = arm.reload_module(make_inst)
make_tess = arm.reload_module(make_tess)
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import Shader, ShaderContext
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
def write_vertpos(vert): def write_vertpos(vert):
billboard = mat_state.material.arm_billboard billboard = mat_state.material.arm_billboard

View file

@ -1,10 +1,19 @@
import bpy import bpy
import arm.material.cycles as cycles import arm.material.cycles as cycles
import arm.material.mat_state as mat_state import arm.material.mat_state as mat_state
import arm.material.mat_utils as mat_utils
import arm.material.make_finalize as make_finalize import arm.material.make_finalize as make_finalize
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
cycles = arm.reload_module(cycles)
mat_state = arm.reload_module(mat_state)
make_finalize = arm.reload_module(make_finalize)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
def make(context_id): def make(context_id):
wrd = bpy.data.worlds['Arm'] wrd = bpy.data.worlds['Arm']

View file

@ -1,4 +1,5 @@
import bpy import bpy
import arm.material.cycles as cycles import arm.material.cycles as cycles
import arm.material.mat_state as mat_state import arm.material.mat_state as mat_state
import arm.material.mat_utils as mat_utils import arm.material.mat_utils as mat_utils
@ -10,6 +11,21 @@ import arm.material.make_finalize as make_finalize
import arm.assets as assets import arm.assets as assets
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
cycles = arm.reload_module(cycles)
mat_state = arm.reload_module(mat_state)
mat_utils = arm.reload_module(mat_utils)
make_skin = arm.reload_module(make_skin)
make_inst = arm.reload_module(make_inst)
make_tess = arm.reload_module(make_tess)
make_particle = arm.reload_module(make_particle)
make_finalize = arm.reload_module(make_finalize)
assets = arm.reload_module(assets)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
def make(context_id, rpasses, shadowmap=False): def make(context_id, rpasses, shadowmap=False):
is_disp = mat_utils.disp_linked(mat_state.output_node) is_disp = mat_utils.disp_linked(mat_state.output_node)

View file

@ -3,6 +3,14 @@ import bpy
import arm.material.make_tess as make_tess import arm.material.make_tess as make_tess
from arm.material.shader import ShaderContext from arm.material.shader import ShaderContext
if "DO_RELOAD_MODULE" in locals():
import arm
make_tess = arm.reload_module(make_tess)
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import ShaderContext
else:
DO_RELOAD_MODULE = True
def make(con_mesh: ShaderContext): def make(con_mesh: ShaderContext):
vert = con_mesh.vert vert = con_mesh.vert

View file

@ -1,4 +1,5 @@
import bpy import bpy
import arm.assets as assets import arm.assets as assets
import arm.material.mat_state as mat_state import arm.material.mat_state as mat_state
import arm.material.mat_utils as mat_utils import arm.material.mat_utils as mat_utils
@ -10,6 +11,20 @@ import arm.material.make_finalize as make_finalize
import arm.material.make_attrib as make_attrib import arm.material.make_attrib as make_attrib
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
assets = arm.reload_module(assets)
mat_state = arm.reload_module(mat_state)
mat_utils = arm.reload_module(mat_utils)
cycles = arm.reload_module(cycles)
make_tess = arm.reload_module(make_tess)
make_particle = arm.reload_module(make_particle)
make_cluster = arm.reload_module(make_cluster)
make_finalize = arm.reload_module(make_finalize)
make_attrib = arm.reload_module(make_attrib)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
is_displacement = False is_displacement = False
write_material_attribs = None write_material_attribs = None
write_material_attribs_post = None write_material_attribs_post = None

View file

@ -3,6 +3,15 @@ import arm.material.make_mesh as make_mesh
import arm.material.mat_state as mat_state import arm.material.mat_state as mat_state
import arm.material.mat_utils as mat_utils import arm.material.mat_utils as mat_utils
if "DO_RELOAD_MODULE" in locals():
import arm
make_finalize = arm.reload_module(make_finalize)
make_mesh = arm.reload_module(make_mesh)
mat_state = arm.reload_module(mat_state)
mat_utils = arm.reload_module(mat_utils)
else:
DO_RELOAD_MODULE = True
def make(context_id): def make(context_id):
con = { 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise' } con = { 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise' }

View file

@ -1,7 +1,13 @@
import arm.utils import arm.utils
import arm.material.mat_state as mat_state import arm.material.mat_state as mat_state
if "DO_RELOAD_MODULE" in locals():
arm.utils = arm.reload_module(arm.utils)
mat_state = arm.reload_module(mat_state)
else:
DO_RELOAD_MODULE = True
def write(vert, particle_info=None, shadowmap=False): def write(vert, particle_info=None, shadowmap=False):
# Outs # Outs
@ -17,7 +23,7 @@ def write(vert, particle_info=None, shadowmap=False):
str_tex_hash = "float fhash(float n) { return fract(sin(n) * 43758.5453); }\n" str_tex_hash = "float fhash(float n) { return fract(sin(n) * 43758.5453); }\n"
vert.add_function(str_tex_hash) vert.add_function(str_tex_hash)
prep = 'float ' prep = 'float '
if out_age: if out_age:
prep = '' prep = ''
@ -45,7 +51,7 @@ def write(vert, particle_info=None, shadowmap=False):
vert.write('}') vert.write('}')
# vert.write('p_age /= 2;') # Match # vert.write('p_age /= 2;') # Match
# object_align_factor / 2 + gxyz # object_align_factor / 2 + gxyz
prep = 'vec3 ' prep = 'vec3 '
if out_velocity: if out_velocity:

View file

@ -22,6 +22,26 @@ import arm.material.mat_utils as mat_utils
from arm.material.shader import Shader, ShaderContext, ShaderData from arm.material.shader import Shader, ShaderContext, ShaderData
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
arm.api = arm.reload_module(arm.api)
assets = arm.reload_module(assets)
arm.exporter = arm.reload_module(arm.exporter)
log = arm.reload_module(log)
cycles = arm.reload_module(cycles)
make_decal = arm.reload_module(make_decal)
make_depth = arm.reload_module(make_depth)
make_mesh = arm.reload_module(make_mesh)
make_overlay = arm.reload_module(make_overlay)
make_transluc = arm.reload_module(make_transluc)
make_voxel = arm.reload_module(make_voxel)
mat_state = arm.reload_module(mat_state)
mat_utils = arm.reload_module(mat_utils)
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import Shader, ShaderContext, ShaderData
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
rpass_hook = None rpass_hook = None

View file

@ -1,5 +1,11 @@
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
def skin_pos(vert): def skin_pos(vert):
vert.add_include('compiled.inc') vert.add_include('compiled.inc')
@ -15,6 +21,7 @@ def skin_pos(vert):
vert.write_attrib('spos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate') vert.write_attrib('spos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate')
vert.write_attrib('spos.xyz /= posUnpack;') vert.write_attrib('spos.xyz /= posUnpack;')
def skin_nor(vert, prep): def skin_nor(vert, prep):
rpdat = arm.utils.get_rp() rpdat = arm.utils.get_rp()
vert.write_attrib(prep + 'wnormal = normalize(N * (vec3(nor.xy, pos.w) + 2.0 * cross(skinA.xyz, cross(skinA.xyz, vec3(nor.xy, pos.w)) + skinA.w * vec3(nor.xy, pos.w))));') vert.write_attrib(prep + 'wnormal = normalize(N * (vec3(nor.xy, pos.w) + 2.0 * cross(skinA.xyz, cross(skinA.xyz, vec3(nor.xy, pos.w)) + skinA.w * vec3(nor.xy, pos.w))));')

View file

@ -1,10 +1,22 @@
import bpy import bpy
import arm.material.cycles as cycles import arm.material.cycles as cycles
import arm.material.mat_state as mat_state import arm.material.mat_state as mat_state
import arm.material.make_mesh as make_mesh import arm.material.make_mesh as make_mesh
import arm.material.make_finalize as make_finalize import arm.material.make_finalize as make_finalize
import arm.assets as assets import arm.assets as assets
if "DO_RELOAD_MODULE" in locals():
import arm
cycles = arm.reload_module(cycles)
mat_state = arm.reload_module(mat_state)
make_mesh = arm.reload_module(make_mesh)
make_finalize = arm.reload_module(make_finalize)
assets = arm.reload_module(assets)
else:
DO_RELOAD_MODULE = True
def make(context_id): def make(context_id):
con_transluc = mat_state.data.add_context({ 'name': context_id, 'depth_write': False, 'compare_mode': 'less', 'cull_mode': 'clockwise', \ con_transluc = mat_state.data.add_context({ 'name': context_id, 'depth_write': False, 'compare_mode': 'less', 'cull_mode': 'clockwise', \
'blend_source': 'blend_one', 'blend_destination': 'blend_one', 'blend_operation': 'add', \ 'blend_source': 'blend_one', 'blend_destination': 'blend_one', 'blend_operation': 'add', \
@ -26,7 +38,7 @@ def make(context_id):
if '_VoxelAOvar' in wrd.world_defs: if '_VoxelAOvar' in wrd.world_defs:
frag.write('indirect *= 0.25;') frag.write('indirect *= 0.25;')
frag.write('vec4 premultipliedReflect = vec4(vec3(direct + indirect * 0.5) * opacity, opacity);') frag.write('vec4 premultipliedReflect = vec4(vec3(direct + indirect * 0.5) * opacity, opacity);')
frag.write('float w = clamp(pow(min(1.0, premultipliedReflect.a * 10.0) + 0.01, 3.0) * 1e8 * pow(1.0 - (gl_FragCoord.z) * 0.9, 3.0), 1e-2, 3e3);') frag.write('float w = clamp(pow(min(1.0, premultipliedReflect.a * 10.0) + 0.01, 3.0) * 1e8 * pow(1.0 - (gl_FragCoord.z) * 0.9, 3.0), 1e-2, 3e3);')
frag.write('fragColor[0] = vec4(premultipliedReflect.rgb * w, premultipliedReflect.a);') frag.write('fragColor[0] = vec4(premultipliedReflect.rgb * w, premultipliedReflect.a);')
frag.write('fragColor[1] = vec4(premultipliedReflect.a * w, 0.0, 0.0, 1.0);') frag.write('fragColor[1] = vec4(premultipliedReflect.a * w, 0.0, 0.0, 1.0);')

View file

@ -1,11 +1,16 @@
import bpy import bpy
import arm.utils import arm.utils
import arm.assets as assets import arm.assets as assets
import arm.material.cycles as cycles
import arm.material.mat_state as mat_state import arm.material.mat_state as mat_state
import arm.material.mat_utils as mat_utils
import arm.material.make_particle as make_particle if "DO_RELOAD_MODULE" in locals():
import arm.make_state as state arm.utils = arm.reload_module(arm.utils)
assets = arm.reload_module(assets)
mat_state = arm.reload_module(mat_state)
else:
DO_RELOAD_MODULE = True
def make(context_id): def make(context_id):
rpdat = arm.utils.get_rp() rpdat = arm.utils.get_rp()
@ -108,7 +113,7 @@ def make_ao(context_id):
if rpdat.arm_voxelgi_revoxelize and rpdat.arm_voxelgi_camera: if rpdat.arm_voxelgi_revoxelize and rpdat.arm_voxelgi_camera:
vert.add_uniform('vec3 eyeSnap', '_cameraPositionSnap') vert.add_uniform('vec3 eyeSnap', '_cameraPositionSnap')
vert.write('voxpositionGeom = (vec3(W * vec4(pos.xyz, 1.0)) - eyeSnap) / voxelgiHalfExtents;') vert.write('voxpositionGeom = (vec3(W * vec4(pos.xyz, 1.0)) - eyeSnap) / voxelgiHalfExtents;')
else: else:
vert.write('voxpositionGeom = vec3(W * vec4(pos.xyz, 1.0)) / voxelgiHalfExtents;') vert.write('voxpositionGeom = vec3(W * vec4(pos.xyz, 1.0)) / voxelgiHalfExtents;')
geom.add_out('vec3 voxposition') geom.add_out('vec3 voxposition')

View file

@ -1,8 +1,15 @@
import bpy
import arm.material.cycles as cycles import arm.material.cycles as cycles
import arm.material.make_shader as make_shader import arm.material.make_shader as make_shader
import arm.material.mat_state as mat_state import arm.material.mat_state as mat_state
if "DO_RELOAD_MODULE" in locals():
import arm
cycles = arm.reload_module(cycles)
make_shader = arm.reload_module(make_shader)
mat_state = arm.reload_module(mat_state)
else:
DO_RELOAD_MODULE = True
# TODO: handle groups # TODO: handle groups
# TODO: handle cached shaders # TODO: handle cached shaders
@ -21,7 +28,7 @@ def traverse_tree(node, sign):
def get_signature(mat): def get_signature(mat):
nodes = mat.node_tree.nodes nodes = mat.node_tree.nodes
output_node = cycles.node_by_type(nodes, 'OUTPUT_MATERIAL') output_node = cycles.node_by_type(nodes, 'OUTPUT_MATERIAL')
if output_node != None: if output_node != None:
sign = traverse_tree(output_node, '') sign = traverse_tree(output_node, '')
# Append flags # Append flags
@ -40,7 +47,7 @@ def traverse_tree2(node, ar):
def get_sorted(mat): def get_sorted(mat):
nodes = mat.node_tree.nodes nodes = mat.node_tree.nodes
output_node = cycles.node_by_type(nodes, 'OUTPUT_MATERIAL') output_node = cycles.node_by_type(nodes, 'OUTPUT_MATERIAL')
if output_node != None: if output_node != None:
ar = [] ar = []
traverse_tree2(output_node, ar) traverse_tree2(output_node, ar)

View file

@ -1,9 +1,18 @@
import bpy import bpy
import arm.utils import arm.utils
import arm.make_state as make_state import arm.make_state as make_state
import arm.material.cycles as cycles import arm.material.cycles as cycles
import arm.log as log import arm.log as log
if "DO_RELOAD_MODULE" in locals():
arm.utils = arm.reload_module(arm.utils)
make_state = arm.reload_module(make_state)
cycles = arm.reload_module(cycles)
log = arm.reload_module(log)
else:
DO_RELOAD_MODULE = True
add_mesh_contexts = [] add_mesh_contexts = []
def disp_linked(output_node): def disp_linked(output_node):
@ -42,7 +51,7 @@ def get_rpasses(material):
ar.append('voxel') ar.append('voxel')
if rpdat.rp_renderer == 'Forward' and rpdat.rp_depthprepass and not material.arm_blending and not material.arm_particle_flag: if rpdat.rp_renderer == 'Forward' and rpdat.rp_depthprepass and not material.arm_blending and not material.arm_particle_flag:
ar.append('depth') ar.append('depth')
if material.arm_cast_shadow and rpdat.rp_shadows and ('mesh' in ar): if material.arm_cast_shadow and rpdat.rp_shadows and ('mesh' in ar):
ar.append('shadowmap') ar.append('shadowmap')

View file

@ -5,6 +5,13 @@ import bpy
from arm.material.shader import Shader, ShaderContext, vec3str, floatstr from arm.material.shader import Shader, ShaderContext, vec3str, floatstr
if "DO_RELOAD_MODULE" in locals():
import arm
arm.material.shader = arm.reload_module(arm.material.shader)
from arm.material.shader import Shader, ShaderContext, vec3str, floatstr
else:
DO_RELOAD_MODULE = True
class ParserContext(Enum): class ParserContext(Enum):
"""Describes which kind of node tree is parsed.""" """Describes which kind of node tree is parsed."""

View file

@ -1,5 +1,10 @@
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
# Type aliases for type hints to make it easier to see which kind of # Type aliases for type hints to make it easier to see which kind of
# shader data type is stored in a string # shader data type is stored in a string
floatstr = str floatstr = str

View file

@ -10,6 +10,13 @@ import arm.log
import arm.logicnode.arm_sockets import arm.logicnode.arm_sockets
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
arm.log = arm.reload_module(arm.log)
arm.logicnode.arm_sockets = arm.reload_module(arm.logicnode.arm_sockets)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
def find_node_by_link(node_group, to_node, inp): def find_node_by_link(node_group, to_node, inp):
for link in node_group.links: for link in node_group.links:

View file

@ -11,6 +11,16 @@ import arm.props_traits
import arm.ui_icons as ui_icons import arm.ui_icons as ui_icons
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
arm_nodes = arm.reload_module(arm_nodes)
arm.logicnode.replacement = arm.reload_module(arm.logicnode.replacement)
arm.logicnode = arm.reload_module(arm.logicnode)
arm.props_traits = arm.reload_module(arm.props_traits)
ui_icons = arm.reload_module(ui_icons)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
registered_nodes = [] registered_nodes = []
registered_categories = [] registered_categories = []

View file

@ -7,6 +7,14 @@ import arm.material.arm_nodes.arm_nodes as arm_nodes
# even if it looks unused # even if it looks unused
from arm.material.arm_nodes import * from arm.material.arm_nodes import *
if "DO_RELOAD_MODULE" in locals():
import arm
arm_nodes = arm.reload_module(arm_nodes)
arm.material.arm_nodes = arm.reload_module(arm.material.arm_nodes)
from arm.material.arm_nodes import *
else:
DO_RELOAD_MODULE = True
registered_nodes = [] registered_nodes = []

View file

@ -5,6 +5,13 @@ import pstats
import arm.log as log import arm.log as log
import arm.utils as utils import arm.utils as utils
if "DO_RELOAD_MODULE" in locals():
import arm
log = arm.reload_module(log)
utils = arm.reload_module(utils)
else:
DO_RELOAD_MODULE = True
class Profile: class Profile:
"""Context manager for profiling the enclosed code when the given condition is true. """Context manager for profiling the enclosed code when the given condition is true.

View file

@ -10,6 +10,16 @@ import arm.nodes_logic
import arm.proxy import arm.proxy
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
assets = arm.reload_module(assets)
arm.logicnode.replacement = arm.reload_module(arm.logicnode.replacement)
arm.make = arm.reload_module(arm.make)
arm.nodes_logic = arm.reload_module(arm.nodes_logic)
arm.proxy = arm.reload_module(arm.proxy)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
# Armory version # Armory version
arm_version = '2021.7' arm_version = '2021.7'
arm_commit = '$Id$' arm_commit = '$Id$'

View file

@ -1,10 +1,19 @@
import arm.utils
import arm.assets
import bpy import bpy
from bpy.types import Menu, Panel, UIList from bpy.types import Menu, Panel, UIList
from bpy.props import * from bpy.props import *
from arm.lightmapper import operators, properties, utility from arm.lightmapper import operators, properties, utility
import arm.assets
import arm.utils
if "DO_RELOAD_MODULE" in locals():
arm.assets = arm.reload_module(arm.assets)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
class ArmBakeListItem(bpy.types.PropertyGroup): class ArmBakeListItem(bpy.types.PropertyGroup):
obj: PointerProperty(type=bpy.types.Object, description="The object to bake") obj: PointerProperty(type=bpy.types.Object, description="The object to bake")
res_x: IntProperty(name="X", description="Texture resolution", default=1024) res_x: IntProperty(name="X", description="Texture resolution", default=1024)
@ -166,7 +175,7 @@ class ArmBakeButton(bpy.types.Operator):
img_node.image = img img_node.image = img
img_node.select = True img_node.select = True
nodes.active = img_node nodes.active = img_node
obs = bpy.context.view_layer.objects obs = bpy.context.view_layer.objects
# Unwrap # Unwrap
@ -379,4 +388,4 @@ def unregister():
#Unregister lightmapper #Unregister lightmapper
operators.unregister() operators.unregister()
properties.unregister() properties.unregister()

View file

@ -1,14 +1,23 @@
import os import os
import shutil import shutil
import arm.assets as assets
import arm.utils
import bpy
import stat import stat
import subprocess import subprocess
import webbrowser import webbrowser
import bpy
from bpy.types import Menu, Panel, UIList from bpy.types import Menu, Panel, UIList
from bpy.props import * from bpy.props import *
import arm.assets as assets
import arm.utils
if "DO_RELOAD_MODULE" in locals():
assets = arm.reload_module(assets)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
def remove_readonly(func, path, excinfo): def remove_readonly(func, path, excinfo):
os.chmod(path, stat.S_IWRITE) os.chmod(path, stat.S_IWRITE)
func(path) func(path)
@ -417,7 +426,7 @@ def register():
bpy.types.World.arm_exporterlist = CollectionProperty(type=ArmExporterListItem) bpy.types.World.arm_exporterlist = CollectionProperty(type=ArmExporterListItem)
bpy.types.World.arm_exporterlist_index = IntProperty(name="Index for my_list", default=0) bpy.types.World.arm_exporterlist_index = IntProperty(name="Index for my_list", default=0)
bpy.types.World.arm_exporter_android_permission_list = CollectionProperty(type=ArmExporterAndroidPermissionListItem) bpy.types.World.arm_exporter_android_permission_list = CollectionProperty(type=ArmExporterAndroidPermissionListItem)
bpy.types.World.arm_exporter_android_permission_list_index = IntProperty(name="Index for my_list", default=0) bpy.types.World.arm_exporter_android_permission_list_index = IntProperty(name="Index for my_list", default=0)
bpy.types.World.arm_exporter_android_abi_list = CollectionProperty(type=ArmExporterAndroidAbiListItem) bpy.types.World.arm_exporter_android_abi_list = CollectionProperty(type=ArmExporterAndroidAbiListItem)
bpy.types.World.arm_exporter_android_abi_list_index = IntProperty(name="Index for my_list", default=0) bpy.types.World.arm_exporter_android_abi_list_index = IntProperty(name="Index for my_list", default=0)

View file

@ -1,5 +1,4 @@
import bpy import bpy
from bpy.types import Menu, Panel, UIList
from bpy.props import * from bpy.props import *
def update_size_prop(self, context): def update_size_prop(self, context):

View file

@ -4,6 +4,12 @@ from bpy.props import *
import arm.assets as assets import arm.assets as assets
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
assets = arm.reload_module(assets)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
atlas_sizes = [ ('256', '256', '256'), atlas_sizes = [ ('256', '256', '256'),
('512', '512', '512'), ('512', '512', '512'),
('1024', '1024', '1024'), ('1024', '1024', '1024'),

View file

@ -6,6 +6,7 @@ from typing import Union
import webbrowser import webbrowser
from bpy.types import NodeTree from bpy.types import NodeTree
from bpy.props import *
import bpy.utils.previews import bpy.utils.previews
import arm.make as make import arm.make as make
@ -15,6 +16,17 @@ import arm.ui_icons as ui_icons
import arm.utils import arm.utils
import arm.write_data as write_data import arm.write_data as write_data
if "DO_RELOAD_MODULE" in locals():
arm.make = arm.reload_module(arm.make)
arm.props_traits_props = arm.reload_module(arm.props_traits_props)
from arm.props_traits_props import *
proxy = arm.reload_module(proxy)
ui_icons = arm.reload_module(ui_icons)
arm.utils = arm.reload_module(arm.utils)
arm.write_data = arm.reload_module(arm.write_data)
else:
DO_RELOAD_MODULE = True
ICON_HAXE = ui_icons.get_id('haxe') ICON_HAXE = ui_icons.get_id('haxe')
ICON_NODES = 'NODETREE' ICON_NODES = 'NODETREE'
ICON_CANVAS = 'NODE_COMPOSITING' ICON_CANVAS = 'NODE_COMPOSITING'
@ -103,13 +115,13 @@ class ARM_UL_TraitList(bpy.types.UIList):
custom_icon = "NONE" custom_icon = "NONE"
custom_icon_value = 0 custom_icon_value = 0
if item.type_prop == "Haxe Script": if item.type_prop == "Haxe Script":
custom_icon_value = ui_icons.get_id("haxe") custom_icon_value = ICON_HAXE
elif item.type_prop == "WebAssembly": elif item.type_prop == "WebAssembly":
custom_icon_value = ui_icons.get_id("wasm") custom_icon_value = ICON_WASM
elif item.type_prop == "UI Canvas": elif item.type_prop == "UI Canvas":
custom_icon = "NODE_COMPOSITING" custom_icon = "NODE_COMPOSITING"
elif item.type_prop == "Bundled Script": elif item.type_prop == "Bundled Script":
custom_icon_value = ui_icons.get_id("bundle") custom_icon_value = ICON_BUNDLED
elif item.type_prop == "Logic Nodes": elif item.type_prop == "Logic Nodes":
custom_icon = 'NODETREE' custom_icon = 'NODETREE'

View file

@ -1,6 +1,8 @@
import bpy import bpy
from bpy.props import * from bpy.props import *
__all__ = ['ArmTraitPropWarning', 'ArmTraitPropListItem', 'ARM_UL_PropList']
PROP_TYPE_ICONS = { PROP_TYPE_ICONS = {
"String": "SORTALPHA", "String": "SORTALPHA",
"Int": "CHECKBOX_DEHLT", "Int": "CHECKBOX_DEHLT",

View file

@ -5,6 +5,8 @@ import shutil
import bpy import bpy
from bpy.props import * from bpy.props import *
from arm.lightmapper.panels import scene
import arm.api import arm.api
import arm.assets as assets import arm.assets as assets
from arm.exporter import ArmoryExporter from arm.exporter import ArmoryExporter
@ -20,10 +22,24 @@ import arm.proxy
import arm.ui_icons as ui_icons import arm.ui_icons as ui_icons
import arm.utils import arm.utils
from arm.lightmapper.utility import icon if "DO_RELOAD_MODULE" in locals():
from arm.lightmapper.properties.denoiser import oidn, optix arm.api = arm.reload_module(arm.api)
from arm.lightmapper.panels import scene assets = arm.reload_module(assets)
import importlib arm.exporter = arm.reload_module(arm.exporter)
from arm.exporter import ArmoryExporter
log = arm.reload_module(log)
arm.logicnode.replacement = arm.reload_module(arm.logicnode.replacement)
make = arm.reload_module(make)
state = arm.reload_module(state)
props = arm.reload_module(props)
arm.props_properties = arm.reload_module(arm.props_properties)
arm.props_traits = arm.reload_module(arm.props_traits)
arm.nodes_logic = arm.reload_module(arm.nodes_logic)
arm.proxy = arm.reload_module(arm.proxy)
ui_icons = arm.reload_module(ui_icons)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
class ARM_PT_ObjectPropsPanel(bpy.types.Panel): class ARM_PT_ObjectPropsPanel(bpy.types.Panel):
@ -213,7 +229,7 @@ class ARM_PT_PhysicsPropsPanel(bpy.types.Panel):
if obj.soft_body is not None: if obj.soft_body is not None:
layout.prop(obj, 'arm_soft_body_margin') layout.prop(obj, 'arm_soft_body_margin')
if obj.rigid_body_constraint is not None: if obj.rigid_body_constraint is not None:
layout.prop(obj, 'arm_relative_physics_constraint') layout.prop(obj, 'arm_relative_physics_constraint')

View file

@ -6,6 +6,19 @@ from typing import Optional
import bpy.utils.previews import bpy.utils.previews
if "DO_RELOAD_MODULE" in locals():
# _unload_icons is not available in the module scope yet
def __unload():
_unload_icons()
# Refresh icons after reload
__unload()
else:
DO_RELOAD_MODULE = True
__all__ = ["get_id"]
_icons_dict: Optional[bpy.utils.previews.ImagePreviewCollection] = None _icons_dict: Optional[bpy.utils.previews.ImagePreviewCollection] = None
"""Dictionary of all loaded icons, or `None` if not loaded""" """Dictionary of all loaded icons, or `None` if not loaded"""
@ -13,21 +26,28 @@ _icons_dir = os.path.join(os.path.dirname(__file__), "custom_icons")
"""Directory of the icon files""" """Directory of the icon files"""
def _load_icons() -> None: def _load_icons():
"""(Re)loads all icons""" """(Re)loads all icons."""
global _icons_dict global _icons_dict
if _icons_dict is not None: _unload_icons()
bpy.utils.previews.remove(_icons_dict)
_icons_dict = bpy.utils.previews.new() _icons_dict = bpy.utils.previews.new()
_icons_dict.load("bundle", os.path.join(_icons_dir, "bundle.png"), 'IMAGE') _icons_dict.load("bundle", os.path.join(_icons_dir, "bundle.png"), 'IMAGE', force_reload=True)
_icons_dict.load("haxe", os.path.join(_icons_dir, "haxe.png"), 'IMAGE') _icons_dict.load("haxe", os.path.join(_icons_dir, "haxe.png"), 'IMAGE', force_reload=True)
_icons_dict.load("wasm", os.path.join(_icons_dir, "wasm.png"), 'IMAGE') _icons_dict.load("wasm", os.path.join(_icons_dir, "wasm.png"), 'IMAGE', force_reload=True)
def _unload_icons():
"""Unloads all icons."""
global _icons_dict
if _icons_dict is not None:
bpy.utils.previews.remove(_icons_dict)
_icons_dict = None
def get_id(identifier: str) -> int: def get_id(identifier: str) -> int:
"""Returns the icon ID from the given identifier""" """Returns the icon ID from the given identifier."""
if _icons_dict is None: if _icons_dict is None:
_load_icons() _load_icons()
return _icons_dict[identifier].icon_id return _icons_dict[identifier].icon_id

View file

@ -1,13 +1,14 @@
from enum import Enum, unique
import glob import glob
import json import json
import locale
import os import os
import platform import platform
import re import re
import shlex
import subprocess import subprocess
from typing import Any, Dict, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple
import webbrowser import webbrowser
import shlex
import locale
import numpy as np import numpy as np
@ -18,7 +19,17 @@ from arm.lib.lz4 import LZ4
import arm.log as log import arm.log as log
import arm.make_state as state import arm.make_state as state
import arm.props_renderpath import arm.props_renderpath
from enum import Enum, unique
if "DO_RELOAD_MODULE" in locals():
arm.lib.armpack = arm.reload_module(arm.lib.armpack)
arm.lib.lz4 = arm.reload_module(arm.lib.lz4)
from arm.lib.lz4 import LZ4
log = arm.reload_module(log)
state = arm.reload_module(state)
arm.props_renderpath = arm.reload_module(arm.props_renderpath)
else:
DO_RELOAD_MODULE = True
class NumpyEncoder(json.JSONEncoder): class NumpyEncoder(json.JSONEncoder):
def default(self, obj): def default(self, obj):

View file

@ -11,6 +11,14 @@ import arm.assets as assets
import arm.make_state as state import arm.make_state as state
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
import arm
assets = arm.reload_module(assets)
state = arm.reload_module(state)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
def on_same_drive(path1: str, path2: str) -> bool: def on_same_drive(path1: str, path2: str) -> bool:
drive_path1, _ = os.path.splitdrive(path1) drive_path1, _ = os.path.splitdrive(path1)

View file

@ -11,6 +11,14 @@ import arm.assets as assets
import arm.log as log import arm.log as log
import arm.utils import arm.utils
if "DO_RELOAD_MODULE" in locals():
import arm
assets = arm.reload_module(assets)
log = arm.reload_module(log)
arm.utils = arm.reload_module(arm.utils)
else:
DO_RELOAD_MODULE = True
def add_irr_assets(output_file_irr): def add_irr_assets(output_file_irr):
assets.add(output_file_irr + '.arm') assets.add(output_file_irr + '.arm')

View file

@ -1,3 +1,7 @@
import time
import arm
import arm.log
import arm.nodes_logic import arm.nodes_logic
import arm.nodes_material import arm.nodes_material
import arm.props_traits_props import arm.props_traits_props
@ -15,8 +19,38 @@ import arm.handlers
import arm.utils import arm.utils
import arm.keymap import arm.keymap
reload_started = 0
if "DO_RELOAD_MODULE" in locals():
arm.log.debug('Reloading Armory SDK...')
reload_started = time.time()
# Clear the module cache
import importlib
arm = importlib.reload(arm) # type: ignore
arm.nodes_logic = arm.reload_module(arm.nodes_logic)
arm.nodes_material = arm.reload_module(arm.nodes_material)
arm.props_traits_props = arm.reload_module(arm.props_traits_props)
arm.props_traits = arm.reload_module(arm.props_traits)
arm.props_lod = arm.reload_module(arm.props_lod)
arm.props_tilesheet = arm.reload_module(arm.props_tilesheet)
arm.props_exporter = arm.reload_module(arm.props_exporter)
arm.props_bake = arm.reload_module(arm.props_bake)
arm.props_renderpath = arm.reload_module(arm.props_renderpath)
arm.props_properties = arm.reload_module(arm.props_properties)
arm.props_collision_filter_mask = arm.reload_module(arm.props_collision_filter_mask)
arm.props = arm.reload_module(arm.props)
arm.props_ui = arm.reload_module(arm.props_ui)
arm.handlers = arm.reload_module(arm.handlers)
arm.utils = arm.reload_module(arm.utils)
arm.keymap = arm.reload_module(arm.keymap)
else:
DO_RELOAD_MODULE = True
registered = False registered = False
def register(local_sdk=False): def register(local_sdk=False):
global registered global registered
registered = True registered = True
@ -37,6 +71,10 @@ def register(local_sdk=False):
arm.handlers.register() arm.handlers.register()
arm.props_collision_filter_mask.register() arm.props_collision_filter_mask.register()
if reload_started != 0:
arm.log.debug(f'Armory SDK: Reloading finished in {time.time() - reload_started:.3f}s')
def unregister(): def unregister():
global registered global registered
registered = False registered = False