Compare commits

...

15 Commits

Author SHA1 Message Date
d433e8f241 fix: transform offset for object animated with a curve constraint
Related to #214
2021-07-06 14:29:20 +02:00
963a551a1e Merge branch '206-draw-active-mode-in-the-object-presence-overlay-2' into 'develop'
Draw active mode in the object presence overlay

See merge request slumber/multi-user!131
2021-07-01 12:57:01 +00:00
d01a434fb7 fix: Review 2021-07-01 14:53:14 +02:00
3a5a5fc633 fix : draw active mode UI side pannel 2021-07-01 11:58:52 +02:00
8926ab44e1 Merge branch '201-improved-image-support' into 'develop'
Resolve "Improved image support"

See merge request slumber/multi-user!136
2021-07-01 09:55:47 +00:00
a8f96581c5 fix: new mode display 2021-06-30 15:34:03 +02:00
440a4cc1cd feat: add mode visibily 2021-06-29 17:10:59 +02:00
a207c51973 fix: image renamin support
fix: sync Color Space Settings

related to #201
2021-06-29 15:59:26 +02:00
e706c8e0bf Merge branch '209-adding-a-scene-create-node-duplicates' into 'develop'
Resolve "Adding a scene create node duplicates"

See merge request slumber/multi-user!135
2021-06-28 08:30:22 +00:00
e590e896da fix: scene duplicates by using data instead of the update id
Related to #209
2021-06-28 10:27:04 +02:00
4140b62a8e Merge branch '119-add-timeline-marker-sync' into 'develop'
Resolve "Add timeline marker sync"

See merge request slumber/multi-user!133
2021-06-24 15:52:12 +00:00
6d9c9c4532 fix: timeline marker selection
feat: basic test
2021-06-24 17:45:34 +02:00
e9e1911840 Merge branch '208-late-update-logging-error' into 'develop'
Resolve "Late update logging error"

See merge request slumber/multi-user!134
2021-06-24 15:28:56 +00:00
0a8f0b5f88 feat: add mode overlay 2021-06-24 16:01:14 +02:00
2238a15c11 feat: initial markers support 2021-06-24 15:51:01 +02:00
12 changed files with 203 additions and 60 deletions

View File

@ -56,7 +56,7 @@ class BlCamera(ReplicatedDatablock):
background_images = data.get('background_images')
datablock.background_images.clear()
# TODO: Use image uuid
if background_images:
for img_name, img_data in background_images.items():
img_id = img_data.get('image')

View File

@ -69,11 +69,12 @@ class BlImage(ReplicatedDatablock):
@staticmethod
def load(data: dict, datablock: object):
loader = Loader()
loader.load(data, datablock)
loader.load(datablock, data)
# datablock.name = data.get('name')
datablock.source = 'FILE'
datablock.filepath_raw = get_filepath(data['filename'])
color_space_name = data["colorspace_settings"]["name"]
color_space_name = data.get("colorspace")
if color_space_name:
datablock.colorspace_settings.name = color_space_name
@ -92,12 +93,10 @@ class BlImage(ReplicatedDatablock):
"name",
# 'source',
'size',
'height',
'alpha',
'float_buffer',
'alpha_mode',
'colorspace_settings']
'alpha_mode']
data.update(dumper.dump(datablock))
data['colorspace'] = datablock.colorspace_settings.name
return data
@staticmethod
@ -132,10 +131,7 @@ class BlImage(ReplicatedDatablock):
if datablock.is_dirty:
datablock.save()
if not data or (datablock and (datablock.name != data.get('name'))):
return True
else:
return False
return True
_type = bpy.types.Image
_class = BlImage

View File

@ -124,8 +124,7 @@ def dump_node(node: bpy.types.ShaderNode) -> dict:
"show_preview",
"show_texture",
"outputs",
"width_hidden",
"image"
"width_hidden"
]
dumped_node = node_dumper.dump(node)

View File

@ -620,10 +620,8 @@ class BlObject(ReplicatedDatablock):
transform = data.get('transforms', None)
if transform:
datablock.matrix_parent_inverse = mathutils.Matrix(
transform['matrix_parent_inverse'])
datablock.matrix_parent_inverse = mathutils.Matrix(transform['matrix_parent_inverse'])
datablock.matrix_basis = mathutils.Matrix(transform['matrix_basis'])
datablock.matrix_local = mathutils.Matrix(transform['matrix_local'])
@staticmethod

View File

@ -445,6 +445,15 @@ class BlScene(ReplicatedDatablock):
elif datablock.sequence_editor and not sequences:
datablock.sequence_editor_clear()
# Timeline markers
markers = data.get('timeline_markers')
if markers:
datablock.timeline_markers.clear()
for name, frame, camera in markers:
marker = datablock.timeline_markers.new(name, frame=frame)
if camera:
marker.camera = resolve_datablock_from_uuid(camera, bpy.data.objects)
marker.select = False
# FIXME: Find a better way after the replication big refacotoring
# Keep other user from deleting collection object by flushing their history
flush_history()
@ -517,6 +526,10 @@ class BlScene(ReplicatedDatablock):
dumped_sequences[seq.name] = dump_sequence(seq)
data['sequences'] = dumped_sequences
# Timeline markers
if datablock.timeline_markers:
data['timeline_markers'] = [(m.name, m.frame, getattr(m.camera, 'uuid', None)) for m in datablock.timeline_markers]
return data
@staticmethod

View File

@ -52,7 +52,8 @@ def sanitize_deps_graph(remove_nodes: bool = False):
def update_external_dependencies():
"""Force external dependencies(files such as images) evaluation
"""
nodes_ids = [n.uuid for n in session.repository.graph.values() if n.data['type_id'] in ['WindowsPath', 'PosixPath']]
external_types = ['WindowsPath', 'PosixPath', 'Image']
nodes_ids = [n.uuid for n in session.repository.graph.values() if n.data['type_id'] in external_types]
for node_id in nodes_ids:
node = session.repository.graph.get(node_id)
if node and node.owner in [session.repository.username, RP_COMMON]:
@ -103,7 +104,8 @@ def on_scene_update(scene):
else:
continue
elif isinstance(update.id, bpy.types.Scene):
scn_uuid = porcelain.add(session.repository, update.id)
scene = bpy.data.scenes.get(update.id.name)
scn_uuid = porcelain.add(session.repository, scene)
porcelain.commit(session.repository, scn_uuid)
porcelain.push(session.repository, 'origin', scn_uuid)

View File

@ -273,8 +273,7 @@ class SessionStartOperator(bpy.types.Operator):
session_update = timers.SessionStatusUpdate()
session_user_sync = timers.SessionUserSync()
session_background_executor = timers.MainThreadExecutor(
execution_queue=background_execution_queue)
session_background_executor = timers.MainThreadExecutor(execution_queue=background_execution_queue)
session_listen = timers.SessionListenTimer(timeout=0.001)
session_listen.register()

View File

@ -273,6 +273,13 @@ class SessionPrefs(bpy.types.AddonPreferences):
step=1,
subtype='PERCENTAGE',
)
presence_mode_distance: bpy.props.FloatProperty(
name="Distance mode visibilty",
description="Adjust the distance visibilty of user's mode",
min=0.1,
max=1000,
default=100,
)
conf_session_identity_expanded: bpy.props.BoolProperty(
name="Identity",
description="Identity",
@ -446,10 +453,11 @@ class SessionPrefs(bpy.types.AddonPreferences):
col = box.column(align=True)
col.prop(self, "presence_hud_scale", expand=True)
col.prop(self, "presence_hud_hpos", expand=True)
col.prop(self, "presence_hud_vpos", expand=True)
col.prop(self, "presence_mode_distance", expand=True)
if self.category == 'UPDATE':
from . import addon_updater_ops
addon_updater_ops.update_settings_ui(self, context)
@ -538,6 +546,11 @@ class SessionProps(bpy.types.PropertyGroup):
description='Enable user overlay ',
default=True,
)
presence_show_mode: bpy.props.BoolProperty(
name="Show users current mode",
description='Enable user mode overlay ',
default=False,
)
presence_show_far_user: bpy.props.BoolProperty(
name="Show users on different scenes",
description="Show user on different scenes",

View File

@ -251,6 +251,13 @@ class Widget(object):
"""
return True
def configure_bgl(self):
bgl.glLineWidth(2.)
bgl.glEnable(bgl.GL_DEPTH_TEST)
bgl.glEnable(bgl.GL_BLEND)
bgl.glEnable(bgl.GL_LINE_SMOOTH)
def draw(self):
"""How to draw the widget
"""
@ -304,11 +311,6 @@ class UserFrustumWidget(Widget):
{"pos": positions},
indices=self.indices)
bgl.glLineWidth(2.)
bgl.glEnable(bgl.GL_DEPTH_TEST)
bgl.glEnable(bgl.GL_BLEND)
bgl.glEnable(bgl.GL_LINE_SMOOTH)
shader.bind()
shader.uniform_float("color", self.data.get('color'))
batch.draw(shader)
@ -342,7 +344,7 @@ class UserSelectionWidget(Widget):
self.settings.presence_show_selected and \
self.settings.enable_presence
def draw(self):
def draw(self):
user_selection = self.data.get('selected_objects')
for select_obj in user_selection:
obj = find_from_attr("uuid", select_obj, bpy.data.objects)
@ -406,6 +408,62 @@ class UserNameWidget(Widget):
blf.color(0, color[0], color[1], color[2], color[3])
blf.draw(0, self.username)
class UserModeWidget(Widget):
draw_type = 'POST_PIXEL'
def __init__(
self,
username):
self.username = username
self.settings = bpy.context.window_manager.session
self.preferences = get_preferences()
@property
def data(self):
user = session.online_users.get(self.username)
if user:
return user.get('metadata')
else:
return None
def poll(self):
if self.data is None:
return False
scene_current = self.data.get('scene_current')
mode_current = self.data.get('mode_current')
user_selection = self.data.get('selected_objects')
return (scene_current == bpy.context.scene.name or
mode_current == bpy.context.mode or
self.settings.presence_show_far_user) and \
user_selection and \
self.settings.presence_show_mode and \
self.settings.enable_presence
def draw(self):
user_selection = self.data.get('selected_objects')
area, region, rv3d = view3d_find()
viewport_coord = project_to_viewport(region, rv3d, (0, 0))
obj = find_from_attr("uuid", user_selection[0], bpy.data.objects)
if not obj:
return
mode_current = self.data.get('mode_current')
color = self.data.get('color')
origin_coord = project_to_screen(obj.location)
distance_viewport_object = math.sqrt((viewport_coord[0]-obj.location[0])**2+(viewport_coord[1]-obj.location[1])**2+(viewport_coord[2]-obj.location[2])**2)
if distance_viewport_object > self.preferences.presence_mode_distance :
return
if origin_coord :
blf.position(0, origin_coord[0]+8, origin_coord[1]-15, 0)
blf.size(0, 16, 72)
blf.color(0, color[0], color[1], color[2], color[3])
blf.draw(0, mode_current)
class SessionStatusWidget(Widget):
draw_type = 'POST_PIXEL'
@ -488,6 +546,7 @@ class DrawFactory(object):
try:
for widget in self.widgets.values():
if widget.draw_type == 'POST_VIEW' and widget.poll():
widget.configure_bgl()
widget.draw()
except Exception as e:
logging.error(
@ -497,6 +556,7 @@ class DrawFactory(object):
try:
for widget in self.widgets.values():
if widget.draw_type == 'POST_PIXEL' and widget.poll():
widget.configure_bgl()
widget.draw()
except Exception as e:
logging.error(
@ -509,6 +569,7 @@ this.renderer = DrawFactory()
def register():
this.renderer.register_handlers()
this.renderer.add_widget("session_status", SessionStatusWidget())

View File

@ -27,7 +27,7 @@ from replication.interface import session
from replication import porcelain
from . import operators, utils
from .presence import (UserFrustumWidget, UserNameWidget, UserSelectionWidget,
from .presence import (UserFrustumWidget, UserNameWidget, UserModeWidget, UserSelectionWidget,
generate_user_camera, get_view_matrix, refresh_3d_view,
refresh_sidebar_view, renderer)
@ -309,7 +309,8 @@ class ClientUpdate(Timer):
settings.client_color.b,
1),
'frame_current': bpy.context.scene.frame_current,
'scene_current': scene_current
'scene_current': scene_current,
'mode_current': bpy.context.mode
}
porcelain.update_user_metadata(session.repository, metadata)
@ -323,6 +324,9 @@ class ClientUpdate(Timer):
local_user_metadata['view_matrix'] = get_view_matrix(
)
porcelain.update_user_metadata(session.repository, local_user_metadata)
elif bpy.context.mode != local_user_metadata['mode_current']:
local_user_metadata['mode_current'] = bpy.context.mode
porcelain.update_user_metadata(session.repository, local_user_metadata)
class SessionStatusUpdate(Timer):
@ -350,6 +354,7 @@ class SessionUserSync(Timer):
renderer.remove_widget(f"{user.username}_cam")
renderer.remove_widget(f"{user.username}_select")
renderer.remove_widget(f"{user.username}_name")
renderer.remove_widget(f"{user.username}_mode")
ui_users.remove(index)
break
@ -365,6 +370,8 @@ class SessionUserSync(Timer):
f"{user}_select", UserSelectionWidget(user))
renderer.add_widget(
f"{user}_name", UserNameWidget(user))
renderer.add_widget(
f"{user}_mode", UserModeWidget(user))
class MainThreadExecutor(Timer):

View File

@ -107,7 +107,7 @@ class SESSION_PT_settings(bpy.types.Panel):
row = row.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
row.prop(settings.sync_flags, "sync_render_settings",text="",icon_only=True, icon='SCENE')
row.prop(settings.sync_flags, "sync_during_editmode", text="",icon_only=True, icon='EDITMODE_HLT')
row.prop(settings.sync_flags, "sync_active_camera", text="",icon_only=True, icon='OBJECT_DATAMODE')
row.prop(settings.sync_flags, "sync_active_camera", text="",icon_only=True, icon='VIEW_CAMERA')
row= layout.row()
@ -343,9 +343,10 @@ class SESSION_PT_user(bpy.types.Panel):
box = row.box()
split = box.split(factor=0.35)
split.label(text="user")
split = split.split(factor=0.5)
split.label(text="location")
split = split.split(factor=0.3)
split.label(text="mode")
split.label(text="frame")
split.label(text="location")
split.label(text="ping")
row = layout.row()
@ -383,6 +384,8 @@ class SESSION_UL_users(bpy.types.UIList):
ping = '-'
frame_current = '-'
scene_current = '-'
mode_current = '-'
mode_icon = 'BLANK1'
status_icon = 'BLANK1'
if session:
user = session.online_users.get(item.username)
@ -392,13 +395,45 @@ class SESSION_UL_users(bpy.types.UIList):
if metadata and 'frame_current' in metadata:
frame_current = str(metadata.get('frame_current','-'))
scene_current = metadata.get('scene_current','-')
mode_current = metadata.get('mode_current','-')
if mode_current == "OBJECT" :
mode_icon = "OBJECT_DATAMODE"
elif mode_current == "EDIT_MESH" :
mode_icon = "EDITMODE_HLT"
elif mode_current == 'EDIT_CURVE':
mode_icon = "CURVE_DATA"
elif mode_current == 'EDIT_SURFACE':
mode_icon = "SURFACE_DATA"
elif mode_current == 'EDIT_TEXT':
mode_icon = "FILE_FONT"
elif mode_current == 'EDIT_ARMATURE':
mode_icon = "ARMATURE_DATA"
elif mode_current == 'EDIT_METABALL':
mode_icon = "META_BALL"
elif mode_current == 'EDIT_LATTICE':
mode_icon = "LATTICE_DATA"
elif mode_current == 'POSE':
mode_icon = "POSE_HLT"
elif mode_current == 'SCULPT':
mode_icon = "SCULPTMODE_HLT"
elif mode_current == 'PAINT_WEIGHT':
mode_icon = "WPAINT_HLT"
elif mode_current == 'PAINT_VERTEX':
mode_icon = "VPAINT_HLT"
elif mode_current == 'PAINT_TEXTURE':
mode_icon = "TPAINT_HLT"
elif mode_current == 'PARTICLE':
mode_icon = "PARTICLES"
elif mode_current == 'PAINT_GPENCIL' or mode_current =='EDIT_GPENCIL' or mode_current =='SCULPT_GPENCIL' or mode_current =='WEIGHT_GPENCIL' or mode_current =='VERTEX_GPENCIL':
mode_icon = "GREASEPENCIL"
if user['admin']:
status_icon = 'FAKE_USER_ON'
split = layout.split(factor=0.35)
split.label(text=item.username, icon=status_icon)
split = split.split(factor=0.5)
split.label(text=scene_current)
split = split.split(factor=0.3)
split.label(icon=mode_icon)
split.label(text=frame_current)
split.label(text=scene_current)
split.label(text=ping)
@ -425,20 +460,29 @@ class SESSION_PT_presence(bpy.types.Panel):
settings = context.window_manager.session
pref = get_preferences()
layout.active = settings.enable_presence
row = layout.row()
row = row.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
row.prop(settings, "presence_show_selected",text="",icon_only=True, icon='CUBE')
row.prop(settings, "presence_show_user", text="",icon_only=True, icon='CAMERA_DATA')
row.prop(settings, "presence_show_mode", text="",icon_only=True, icon='OBJECT_DATAMODE')
row.prop(settings, "presence_show_far_user", text="",icon_only=True, icon='SCENE_DATA')
col = layout.column()
if settings.presence_show_mode :
row = col.column()
row.prop(pref, "presence_mode_distance", expand=True)
col.prop(settings, "presence_show_session_status")
row = col.column()
row.active = settings.presence_show_session_status
row.prop(pref, "presence_hud_scale", expand=True)
row = col.column(align=True)
row.active = settings.presence_show_session_status
row.prop(pref, "presence_hud_hpos", expand=True)
row.prop(pref, "presence_hud_vpos", expand=True)
col.prop(settings, "presence_show_selected")
col.prop(settings, "presence_show_user")
row = layout.column()
row.active = settings.presence_show_user
row.prop(settings, "presence_show_far_user")
if settings.presence_show_session_status :
row = col.column()
row.active = settings.presence_show_session_status
row.prop(pref, "presence_hud_scale", expand=True)
row = col.column(align=True)
row.active = settings.presence_show_session_status
row.prop(pref, "presence_hud_hpos", expand=True)
row.prop(pref, "presence_hud_vpos", expand=True)
def draw_property(context, parent, property_uuid, level=0):
settings = get_preferences()
@ -585,23 +629,32 @@ class VIEW3D_PT_overlay_session(bpy.types.Panel):
def draw(self, context):
layout = self.layout
view = context.space_data
overlay = view.overlay
display_all = overlay.show_overlays
col = layout.column()
row = col.row(align=True)
settings = context.window_manager.session
pref = get_preferences()
layout.active = settings.enable_presence
row = layout.row()
row = row.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
row.prop(settings, "presence_show_selected",text="",icon_only=True, icon='CUBE')
row.prop(settings, "presence_show_user", text="",icon_only=True, icon='CAMERA_DATA')
row.prop(settings, "presence_show_mode", text="",icon_only=True, icon='OBJECT_DATAMODE')
row.prop(settings, "presence_show_far_user", text="",icon_only=True, icon='SCENE_DATA')
col = layout.column()
if settings.presence_show_mode :
row = col.column()
row.prop(pref, "presence_mode_distance", expand=True)
col.prop(settings, "presence_show_session_status")
col.prop(settings, "presence_show_selected")
col.prop(settings, "presence_show_user")
row = layout.column()
row.active = settings.presence_show_user
row.prop(settings, "presence_show_far_user")
if settings.presence_show_session_status :
row = col.column()
row.active = settings.presence_show_session_status
row.prop(pref, "presence_hud_scale", expand=True)
row = col.column(align=True)
row.active = settings.presence_show_session_status
row.prop(pref, "presence_hud_hpos", expand=True)
row.prop(pref, "presence_hud_vpos", expand=True)
classes = (
SESSION_UL_users,

View File

@ -12,6 +12,8 @@ def test_scene(clear_blend):
get_preferences().sync_flags.sync_render_settings = True
datablock = bpy.data.scenes.new("toto")
datablock.timeline_markers.new('toto', frame=10)
datablock.timeline_markers.new('tata', frame=1)
datablock.view_settings.use_curve_mapping = True
# Test
implementation = BlScene()