New cache

This commit is contained in:
luboslenco 2018-12-19 20:10:34 +01:00
parent e79ff975e9
commit c9ef079452
10 changed files with 78 additions and 102 deletions

View file

@ -1161,7 +1161,6 @@ class ArmoryExporter:
mesh_obj['mesh_datas'] = [o]
arm.utils.write_arm(fp, mesh_obj)
bobject.data.arm_cached = True
bobject.arm_cached = True
else:
self.output['mesh_datas'].append(o)
@ -1402,7 +1401,7 @@ class ArmoryExporter:
if ArmoryExporter.option_mesh_per_file:
fp = self.get_meshes_file_path('mesh_' + oid, compressed=self.is_compress())
assets.add(fp)
if self.is_mesh_cached(bobject) == True and os.path.exists(fp):
if bobject.data.arm_cached and os.path.exists(fp):
return
else:
fp = None
@ -1682,7 +1681,7 @@ class ArmoryExporter:
return
mat = bpy.data.materials.new(name=mat_name)
# if default_exists:
# mat.is_cached = True
# mat.arm_cached = True
if is_particle:
mat.arm_particle_flag = True
mat.use_nodes = True
@ -1759,7 +1758,7 @@ class ArmoryExporter:
# Recache material
signature = self.get_signature(material)
if signature != material.signature:
material.is_cached = False
material.arm_cached = False
if signature != None:
material.signature = signature
@ -1825,7 +1824,7 @@ class ArmoryExporter:
ob.data.arm_cached = False
self.output['material_datas'].append(o)
material.is_cached = True
material.arm_cached = True
# Auto-enable render-path featues
rebuild_rp = False
@ -2187,7 +2186,7 @@ class ArmoryExporter:
orig_mat.export_uvs = slot.material.export_uvs
orig_mat.export_vcols = slot.material.export_vcols
orig_mat.export_tangents = slot.material.export_tangents
orig_mat.is_cached = slot.material.is_cached
orig_mat.arm_cached = slot.material.arm_cached
slot.material = orig_mat
for mat in matvars:
bpy.data.materials.remove(mat, do_unlink=True)
@ -2238,14 +2237,6 @@ class ArmoryExporter:
self.output['objects'].append(o)
self.output['camera_ref'] = 'DefaultCamera'
# Callbacks
def is_mesh_cached(self, bobject):
if bobject.type == 'FONT' or bobject.type == 'META': # No verts
return bobject.data.arm_cached
if not bobject.arm_cached:
return False
return bobject.data.arm_cached
def get_export_tangents(self, mesh):
for m in mesh.materials:
if m != None and m.export_tangents == True:

View file

@ -5,91 +5,50 @@ import importlib
from bpy.app.handlers import persistent
import arm.utils
import arm.props as props
import arm.make as make
import arm.make_state as state
import arm.api
last_operator = None
@persistent
def on_scene_update_pre(context):
global last_operator
def on_depsgraph_update_post(self):
if state.proc_build != None:
return
if state.redraw_ui and bpy.context.screen != None:
for area in bpy.context.screen.areas:
depsgraph = bpy.context.depsgraph
for update in depsgraph.updates:
uid = update.id
if hasattr(uid, 'arm_cached'):
# uid.arm_cached = False # TODO: does not trigger update
if isinstance(uid, bpy.types.Mesh):
bpy.data.meshes[uid.name].arm_cached = False
elif isinstance(uid, bpy.types.Curve):
bpy.data.curves[uid.name].arm_cached = False
elif isinstance(uid, bpy.types.MetaBall):
bpy.data.metaballs[uid.name].arm_cached = False
elif isinstance(uid, bpy.types.Armature):
bpy.data.armatures[uid.name].arm_cached = False
elif isinstance(uid, bpy.types.NodeTree):
bpy.data.node_groups[uid.name].arm_cached = False
elif isinstance(uid, bpy.types.Material):
bpy.data.materials[uid.name].arm_cached = False
def always():
if state.redraw_ui and context_screen != None:
for area in context_screen.areas:
if area.type == 'VIEW_3D' or area.type == 'PROPERTIES':
area.tag_redraw()
state.redraw_ui = False
# Recache edited data
ops = bpy.context.window_manager.operators
operators_changed = False
if len(ops) > 0 and last_operator != ops[-1]:
last_operator = ops[-1]
operators_changed = True
if hasattr(bpy.context, 'active_object'):
obj = bpy.context.active_object
if obj != None:
if obj.data != None and obj.data.is_updated:
recache(obj)
if len(ops) > 0 and ops[-1].bl_idname == 'OBJECT_OT_transform_apply':
recache(obj)
# New children
if obj.type == 'ARMATURE':
for c in obj.children:
if c.data != None and c.data.is_updated:
recache(c)
if hasattr(bpy.context, 'sculpt_object') and bpy.context.sculpt_object != None:
recache(bpy.context.sculpt_object)
if hasattr(bpy.context, 'active_pose_bone') and bpy.context.active_pose_bone != None:
recache(bpy.context.active_object)
if hasattr(bpy.context, 'object'):
obj = bpy.context.object
if obj != None:
if operators_changed:
op_changed(ops[-1], obj)
if obj.active_material != None and obj.active_material.is_updated:
if obj.active_material.lock_cache == True: # is_cached was set to true, resulting in a is_updated call
obj.active_material.lock_cache = False
else:
obj.active_material.is_cached = False
# Invalidate logic node tree cache if it is being edited..
space = arm.utils.logic_editor_space()
if space != None:
space.node_tree.is_cached = False
def recache(obj):
# Moving keyframes triggers is_updated_data..
if state.proc_build != None:
return
if obj.data == None:
return
if hasattr(obj.data, 'arm_cached'):
obj.data.arm_cached = False
def op_changed(op, obj):
# Recache mesh data
if op.bl_idname == 'OBJECT_OT_modifier_add' or \
op.bl_idname == 'OBJECT_OT_modifier_remove' or \
op.bl_idname == 'OBJECT_OT_transform_apply' or \
op.bl_idname == 'APPLY_OT_transformlocrotscale' or \
op.bl_idname == 'OBJECT_OT_shade_smooth' or \
op.bl_idname == 'OBJECT_OT_shade_flat':
# Note: Blender reverts object data when manipulating
# OBJECT_OT_transform_apply operator.. recaching object flag instead
obj.arm_cached = False
if op.bl_idname.startswith('MARKER_OT_'):
# Marker changed, recache action
obj.data.arm_cached = False
return 0.5
appended_py_paths = []
context_screen = None
@persistent
def on_load_post(context):
global appended_py_paths
global context_screen
context_screen = bpy.context.screen
props.init_properties_on_load()
reload_blend_data()
@ -137,6 +96,10 @@ def load_library(asset_name):
def register():
bpy.app.handlers.load_post.append(on_load_post)
bpy.app.handlers.depsgraph_update_post.append(on_depsgraph_update_post)
# bpy.app.handlers.undo_post.append(on_undo_post)
bpy.app.timers.register(always, persistent=True)
# TODO: On windows, on_load_post is not called when opening .blend file from explorer
if arm.utils.get_os() == 'win' and arm.utils.get_fp() != '':
on_load_post(None)
@ -144,3 +107,5 @@ def register():
def unregister():
bpy.app.handlers.load_post.remove(on_load_post)
bpy.app.handlers.depsgraph_update_post.remove(on_depsgraph_update_post)
# bpy.app.handlers.undo_post.remove(on_undo_post)

View file

@ -565,6 +565,6 @@ def clean():
# To recache signatures for batched materials
for mat in bpy.data.materials:
mat.signature = ''
mat.is_cached = False
mat.arm_cached = False
print('Project cleaned')

View file

@ -54,7 +54,7 @@ def build_node_tree(node_group):
prop = getattr(node, 'property0')
ArmoryExporter.import_traits.append(prop)
if node_group.is_cached and os.path.isfile(file):
if node_group.arm_cached and os.path.isfile(file):
return
with open(file, 'w') as f:
@ -93,7 +93,7 @@ def build_node_tree(node_group):
f.write('\t\treturn this.functionOutputNodes["' + function_node_outputs[function_name] + '"].result;\n')
f.write('\t}\n\n')
f.write('}')
node_group.is_cached = True
node_group.arm_cached = True
def build_node(node, f):
global parsed_nodes

View file

@ -108,7 +108,7 @@ def build(material, mat_users, mat_armusers):
return rpasses, mat_state.data, shader_data_name, bind_constants, bind_textures
def write_shaders(rel_path, con, rpass, matname):
keep_cache = mat_state.material.is_cached
keep_cache = mat_state.material.arm_cached
write_shader(rel_path, con.vert, 'vert', rpass, matname, keep_cache=keep_cache)
write_shader(rel_path, con.frag, 'frag', rpass, matname, keep_cache=keep_cache)
write_shader(rel_path, con.geom, 'geom', rpass, matname, keep_cache=keep_cache)

View file

@ -78,7 +78,7 @@ def build(materialArray, mat_users, mat_armusers):
# Update signatures
for mat in materialArray:
if mat.signature == '' or not mat.is_cached:
if mat.signature == '' or not mat.arm_cached:
mat.signature = get_signature(mat)
# Group signatures
if mat.signature in signatureDict:

View file

@ -57,6 +57,7 @@ class ArmLogicNodePanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
if context.active_node != None and context.active_node.bl_idname.startswith('LN'):
layout.prop(context.active_node, 'arm_logic_id')
layout.prop(context.active_node, 'arm_watch')

View file

@ -24,17 +24,11 @@ def invalidate_instance_cache(self, context):
return
invalidate_mesh_cache(self, context)
for slot in context.object.material_slots:
slot.material.is_cached = False
slot.material.arm_cached = False
def invalidate_compiler_cache(self, context):
bpy.data.worlds['Arm'].arm_recompile = True
def update_mat_cache(self, context):
if self.is_cached == True:
self.lock_cache = True
else:
pass
def proxy_sync_loc(self, context):
if context.object == None or context.object.proxy == None:
return
@ -188,7 +182,6 @@ def init_properties():
bpy.types.Object.arm_proxy_sync_materials = BoolProperty(name="Materials", description="Keep materials synchronized with proxy object", default=True, update=proxy_sync_materials)
bpy.types.Object.arm_proxy_sync_modifiers = BoolProperty(name="Modifiers", description="Keep modifiers synchronized with proxy object", default=True, update=proxy_sync_modifiers)
bpy.types.Object.arm_proxy_sync_traits = BoolProperty(name="Traits", description="Keep traits synchronized with proxy object", default=True, update=proxy_sync_traits)
bpy.types.Object.arm_cached = BoolProperty(name="Object Cached", description="No need to reexport object data", default=True)
# For speakers
bpy.types.Speaker.arm_play_on_start = BoolProperty(name="Play on Start", description="Play this sound automatically", default=False)
bpy.types.Speaker.arm_loop = BoolProperty(name="Loop", description="Loop this sound", default=False)
@ -335,10 +328,9 @@ def init_properties():
bpy.types.Material.arm_skip_context = StringProperty(name="Skip Context", default='')
bpy.types.Material.arm_material_id = IntProperty(name="ID", default=0)
bpy.types.NodeSocket.is_uniform = BoolProperty(name="Is Uniform", description="Mark node sockets to be processed as material uniforms", default=False)
bpy.types.NodeTree.is_cached = BoolProperty(name="Node Tree Cached", description="No need to reexport node tree", default=False)
bpy.types.NodeTree.arm_cached = BoolProperty(name="Node Tree Cached", description="No need to reexport node tree", default=False)
bpy.types.Material.signature = StringProperty(name="Signature", description="Unique string generated from material nodes", default="")
bpy.types.Material.is_cached = BoolProperty(name="Material Cached", description="No need to reexport material data", default=False, update=update_mat_cache)
bpy.types.Material.lock_cache = BoolProperty(name="Lock Material Cache", description="Prevent is_cached from updating", default=False)
bpy.types.Material.arm_cached = BoolProperty(name="Material Cached", description="No need to reexport material data", default=False)
bpy.types.Node.arm_material_param = BoolProperty(name="Parameter", description="Control this node from script", default=False)
bpy.types.Node.arm_logic_id = StringProperty(name="ID", description="Nodes with equal identifier will share data", default='')
bpy.types.Node.arm_watch = BoolProperty(name="Watch", description="Watch value of this node in debug console", default=False)

View file

@ -420,6 +420,7 @@ class ArmTraitsPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
obj = bpy.context.object
draw_traits(layout, obj, is_object=True)
@ -432,6 +433,7 @@ class ArmSceneTraitsPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
obj = bpy.context.scene
draw_traits(layout, obj, is_object=False)

View file

@ -22,6 +22,8 @@ class ObjectPropsPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
obj = bpy.context.object
if obj == None:
return
@ -58,6 +60,7 @@ class ModifiersPropsPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
obj = bpy.context.object
if obj == None:
return
@ -73,6 +76,7 @@ class ParticlesPropsPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
obj = bpy.context.particle_system
if obj == None:
return
@ -89,6 +93,7 @@ class PhysicsPropsPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
obj = bpy.context.object
if obj == None:
return
@ -115,6 +120,7 @@ class DataPropsPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
obj = bpy.context.object
if obj == None:
return
@ -149,6 +155,7 @@ class ScenePropsPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = bpy.context.scene
if scene == None:
return
@ -171,7 +178,7 @@ class InvalidateMaterialCacheButton(bpy.types.Operator):
bl_label = "Invalidate Cache"
def execute(self, context):
context.material.is_cached = False
context.material.arm_cached = False
context.material.signature = ''
return{'FINISHED'}
@ -184,6 +191,7 @@ class MaterialPropsPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
mat = bpy.context.material
if mat == None:
return
@ -231,6 +239,7 @@ class ArmoryPlayerPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
row = layout.row(align=True)
row.alignment = 'EXPAND'
@ -252,6 +261,7 @@ class ArmoryExporterPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
row = layout.row(align=True)
row.alignment = 'EXPAND'
@ -313,6 +323,7 @@ class ArmoryProjectPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
row = layout.row(align=True)
@ -368,6 +379,7 @@ class ArmVirtualInputPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
class ArmNavigationPanel(bpy.types.Panel):
bl_label = "Armory Navigation"
@ -378,6 +390,7 @@ class ArmNavigationPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = bpy.context.scene
if scene == None:
return
@ -593,6 +606,7 @@ class ArmRenderPathPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
rows = 2
@ -637,6 +651,7 @@ class ArmRenderPathRendererPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
@ -694,6 +709,7 @@ class ArmRenderPathShadowsPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
@ -726,6 +742,7 @@ class ArmRenderPathVoxelsPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
@ -771,6 +788,7 @@ class ArmRenderPathWorldPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
@ -826,6 +844,7 @@ class ArmRenderPathPostProcessPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
@ -903,6 +922,7 @@ class ArmRenderPathCompositorPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
@ -949,6 +969,7 @@ class ArmBakePanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scn = context.scene
row = layout.row(align=True)
@ -1041,6 +1062,7 @@ class ArmLodPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
obj = bpy.context.object
# Mesh only for now
@ -1090,6 +1112,7 @@ class ArmTilesheetPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
rows = 2
@ -1147,6 +1170,7 @@ class ArmProxyPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
layout.operator("arm.make_proxy")
obj = bpy.context.object
if obj != None and obj.proxy != None:
@ -1251,6 +1275,7 @@ class ArmMaterialNodePanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
n = context.active_node
if n != None and (n.bl_idname == 'ShaderNodeRGB' or n.bl_idname == 'ShaderNodeValue' or n.bl_idname == 'ShaderNodeTexImage'):
layout.prop(context.active_node, 'arm_material_param')