refactor: started to rewrite presence
fix: weird bounding boxes on various objects types Related to #55
This commit is contained in:
@ -235,35 +235,6 @@ class Draw(Delayable):
|
||||
pass
|
||||
|
||||
|
||||
class DrawClient(Draw):
|
||||
def execute(self):
|
||||
renderer = getattr(presence, 'renderer', None)
|
||||
prefs = utils.get_preferences()
|
||||
|
||||
if session and renderer and session.state['STATE'] == STATE_ACTIVE:
|
||||
settings = bpy.context.window_manager.session
|
||||
users = session.online_users
|
||||
|
||||
# Update users
|
||||
for user in users.values():
|
||||
metadata = user.get('metadata')
|
||||
color = metadata.get('color')
|
||||
scene_current = metadata.get('scene_current')
|
||||
user_showable = scene_current == bpy.context.scene.name or settings.presence_show_far_user
|
||||
if color and scene_current and user_showable:
|
||||
if settings.presence_show_selected and 'selected_objects' in metadata.keys():
|
||||
renderer.draw_client_selection(
|
||||
user['id'], color, metadata['selected_objects'])
|
||||
if settings.presence_show_user and 'view_corners' in metadata:
|
||||
renderer.draw_client_camera(
|
||||
user['id'], metadata['view_corners'], color)
|
||||
if not user_showable:
|
||||
# TODO: remove this when user event drivent update will be
|
||||
# ready
|
||||
renderer.flush_selection()
|
||||
renderer.flush_users()
|
||||
|
||||
|
||||
class ClientUpdate(Timer):
|
||||
def __init__(self, timout=.1):
|
||||
super().__init__(timout)
|
||||
@ -351,8 +322,6 @@ class SessionUserSync(Timer):
|
||||
for index, user in enumerate(ui_users):
|
||||
if user.username not in session_users.keys():
|
||||
ui_users.remove(index)
|
||||
renderer.flush_selection()
|
||||
renderer.flush_users()
|
||||
break
|
||||
|
||||
for user in session_users:
|
||||
@ -360,6 +329,9 @@ class SessionUserSync(Timer):
|
||||
new_key = ui_users.add()
|
||||
new_key.name = user
|
||||
new_key.username = user
|
||||
presence.renderer.register(presence.UserWidget(user))
|
||||
presence.renderer.register(presence.UserSelectionWidget(user))
|
||||
|
||||
|
||||
|
||||
class MainThreadExecutor(Timer):
|
||||
|
@ -81,8 +81,8 @@ def initialize_session():
|
||||
node_ref.apply()
|
||||
|
||||
# Step 3: Launch presence overlay
|
||||
if runtime_settings.enable_presence:
|
||||
presence.renderer.run()
|
||||
# if runtime_settings.enable_presence:
|
||||
# presence.renderer.run()
|
||||
|
||||
# Step 4: Register blender timers
|
||||
for d in delayables:
|
||||
@ -256,7 +256,6 @@ class SessionStartOperator(bpy.types.Operator):
|
||||
|
||||
# Background client updates service
|
||||
delayables.append(delayable.ClientUpdate())
|
||||
delayables.append(delayable.DrawClient())
|
||||
delayables.append(delayable.DynamicRightSelectTimer())
|
||||
|
||||
session_update = delayable.SessionStatusUpdate()
|
||||
|
@ -476,25 +476,25 @@ class SessionProps(bpy.types.PropertyGroup):
|
||||
name="Presence overlay",
|
||||
description='Enable overlay drawing module',
|
||||
default=True,
|
||||
update=presence.update_presence
|
||||
# update=presence.update_presence
|
||||
)
|
||||
presence_show_selected: bpy.props.BoolProperty(
|
||||
name="Show selected objects",
|
||||
description='Enable selection overlay ',
|
||||
default=True,
|
||||
update=presence.update_overlay_settings
|
||||
# update=presence.update_overlay_settings
|
||||
)
|
||||
presence_show_user: bpy.props.BoolProperty(
|
||||
name="Show users",
|
||||
description='Enable user overlay ',
|
||||
default=True,
|
||||
update=presence.update_overlay_settings
|
||||
# update=presence.update_overlay_settings
|
||||
)
|
||||
presence_show_far_user: bpy.props.BoolProperty(
|
||||
name="Show users on different scenes",
|
||||
description="Show user on different scenes",
|
||||
default=False,
|
||||
update=presence.update_overlay_settings
|
||||
# update=presence.update_overlay_settings
|
||||
)
|
||||
filter_owned: bpy.props.BoolProperty(
|
||||
name="filter_owned",
|
||||
|
@ -19,6 +19,7 @@
|
||||
import copy
|
||||
import logging
|
||||
import math
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import bgl
|
||||
@ -28,11 +29,10 @@ import gpu
|
||||
import mathutils
|
||||
from bpy_extras import view3d_utils
|
||||
from gpu_extras.batch import batch_for_shader
|
||||
from replication.interface import session
|
||||
|
||||
from . import utils
|
||||
|
||||
renderer = None
|
||||
|
||||
|
||||
def view3d_find():
|
||||
""" Find the first 'VIEW_3D' windows found in areas
|
||||
@ -56,6 +56,7 @@ def refresh_3d_view():
|
||||
if area and region and rv3d:
|
||||
area.tag_redraw()
|
||||
|
||||
|
||||
def refresh_sidebar_view():
|
||||
""" Refresh the blender sidebar
|
||||
"""
|
||||
@ -64,6 +65,7 @@ def refresh_sidebar_view():
|
||||
if area:
|
||||
area.regions[3].tag_redraw()
|
||||
|
||||
|
||||
def get_target(region, rv3d, coord):
|
||||
target = [0, 0, 0]
|
||||
|
||||
@ -85,6 +87,7 @@ def get_target_far(region, rv3d, coord, distance):
|
||||
|
||||
return [target.x, target.y, target.z]
|
||||
|
||||
|
||||
def get_default_bbox(obj, radius):
|
||||
coords = [
|
||||
(-radius, -radius, -radius), (+radius, -radius, -radius),
|
||||
@ -93,10 +96,11 @@ def get_default_bbox(obj, radius):
|
||||
(-radius, +radius, +radius), (+radius, +radius, +radius)]
|
||||
|
||||
base = obj.matrix_world
|
||||
bbox_corners = [base @ mathutils.Vector(corner) for corner in coords]
|
||||
bbox_corners = [base @ mathutils.Vector(corner) for corner in coords]
|
||||
|
||||
return [(point.x, point.y, point.z)
|
||||
for point in bbox_corners]
|
||||
for point in bbox_corners]
|
||||
|
||||
|
||||
def get_view_corners():
|
||||
area, region, rv3d = view3d_find()
|
||||
@ -134,13 +138,14 @@ def get_client_2d(coords):
|
||||
else:
|
||||
return (0, 0)
|
||||
|
||||
|
||||
def get_bb_coords_from_obj(object, parent=None):
|
||||
base = object.matrix_world if parent is None else parent.matrix_world
|
||||
bbox_corners = [base @ mathutils.Vector(
|
||||
corner) for corner in object.bound_box]
|
||||
corner) for corner in object.bound_box]
|
||||
|
||||
return [(point.x, point.y, point.z)
|
||||
for point in bbox_corners]
|
||||
for point in bbox_corners]
|
||||
|
||||
|
||||
def get_view_matrix():
|
||||
@ -149,9 +154,8 @@ def get_view_matrix():
|
||||
if area and region and rv3d:
|
||||
return [list(v) for v in rv3d.view_matrix]
|
||||
|
||||
def update_presence(self, context):
|
||||
global renderer
|
||||
|
||||
def update_presence(self, context):
|
||||
if 'renderer' in globals() and hasattr(renderer, 'run'):
|
||||
if self.enable_presence:
|
||||
renderer.run()
|
||||
@ -159,24 +163,153 @@ def update_presence(self, context):
|
||||
renderer.stop()
|
||||
|
||||
|
||||
def update_overlay_settings(self, context):
|
||||
global renderer
|
||||
class Widget(object):
|
||||
def poll(self) -> bool:
|
||||
return True
|
||||
|
||||
if renderer and not self.presence_show_selected:
|
||||
renderer.flush_selection()
|
||||
if renderer and not self.presence_show_user:
|
||||
renderer.flush_users()
|
||||
def draw(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class UserWidget(Widget):
|
||||
# Camera widget indices
|
||||
indices = ((1, 3), (2, 1), (3, 0),
|
||||
(2, 0), (4, 5), (1, 6),
|
||||
(2, 6), (3, 6), (0, 6))
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
username):
|
||||
self.username = username
|
||||
self.settings = bpy.context.window_manager.session
|
||||
|
||||
@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')
|
||||
view_corners = self.data.get('view_corners')
|
||||
|
||||
return (scene_current == bpy.context.scene.name or
|
||||
self.settings.presence_show_far_user) and \
|
||||
view_corners and \
|
||||
self.settings.presence_show_user and \
|
||||
self.settings.enable_presence
|
||||
|
||||
def draw(self):
|
||||
location = self.data.get('view_corners')
|
||||
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
|
||||
positions = [tuple(coord) for coord in location]
|
||||
|
||||
if len(positions) != 7:
|
||||
return
|
||||
|
||||
batch = batch_for_shader(
|
||||
shader,
|
||||
'LINES',
|
||||
{"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)
|
||||
|
||||
|
||||
class UserSelectionWidget(Widget):
|
||||
def __init__(
|
||||
self,
|
||||
username):
|
||||
self.username = username
|
||||
self.settings = bpy.context.window_manager.session
|
||||
|
||||
@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
|
||||
|
||||
user_selection = self.data.get('selected_objects')
|
||||
scene_current = self.data.get('scene_current')
|
||||
|
||||
return (scene_current == bpy.context.scene.name or
|
||||
self.settings.presence_show_far_user) and \
|
||||
user_selection and \
|
||||
self.settings.presence_show_selected and \
|
||||
self.settings.enable_presence
|
||||
|
||||
def draw(self):
|
||||
user_selection = self.data.get('selected_objects')
|
||||
for select_ob in user_selection:
|
||||
ob = utils.find_from_attr("uuid", select_ob, bpy.data.objects)
|
||||
if not ob:
|
||||
return
|
||||
|
||||
if ob.type == 'EMPTY':
|
||||
# TODO: Child case
|
||||
# Collection instance case
|
||||
indices = (
|
||||
(0, 1), (1, 2), (2, 3), (0, 3),
|
||||
(4, 5), (5, 6), (6, 7), (4, 7),
|
||||
(0, 4), (1, 5), (2, 6), (3, 7))
|
||||
if ob.instance_collection:
|
||||
for obj in ob.instance_collection.objects:
|
||||
if obj.type == 'MESH':
|
||||
positions = get_bb_coords_from_obj(obj, parent=ob)
|
||||
|
||||
if hasattr(ob, 'bound_box'):
|
||||
indices = (
|
||||
(0, 1), (1, 2), (2, 3), (0, 3),
|
||||
(4, 5), (5, 6), (6, 7), (4, 7),
|
||||
(0, 4), (1, 5), (2, 6), (3, 7))
|
||||
positions = get_bb_coords_from_obj(ob)
|
||||
else:
|
||||
indices = (
|
||||
(0, 1), (0, 2), (1, 3), (2, 3),
|
||||
(4, 5), (4, 6), (5, 7), (6, 7),
|
||||
(0, 4), (1, 5), (2, 6), (3, 7))
|
||||
|
||||
positions = get_default_bbox(ob, ob.scale.x)
|
||||
|
||||
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
|
||||
batch = batch_for_shader(
|
||||
shader,
|
||||
'LINES',
|
||||
{"pos": positions},
|
||||
indices=indices)
|
||||
|
||||
shader.bind()
|
||||
shader.uniform_float("color", self.data.get('color'))
|
||||
batch.draw(shader)
|
||||
|
||||
class DrawFactory(object):
|
||||
def __init__(self):
|
||||
self.d3d_items = {}
|
||||
self.d2d_items = {}
|
||||
self.draw3d_handle = None
|
||||
self.draw2d_handle = None
|
||||
self.post_view_handle = None
|
||||
self.post_pixel_handle = None
|
||||
self.draw_event = None
|
||||
self.coords = None
|
||||
self.active_object = None
|
||||
self.widgets = []
|
||||
|
||||
def run(self):
|
||||
self.register_handlers()
|
||||
@ -188,22 +321,28 @@ class DrawFactory(object):
|
||||
|
||||
refresh_3d_view()
|
||||
|
||||
def register(self, widget):
|
||||
self.widgets.append(widget)
|
||||
|
||||
def unregister(self, widget):
|
||||
self.widgets.remove(widget)
|
||||
|
||||
def register_handlers(self):
|
||||
self.draw3d_handle = bpy.types.SpaceView3D.draw_handler_add(
|
||||
self.draw3d_callback, (), 'WINDOW', 'POST_VIEW')
|
||||
self.draw2d_handle = bpy.types.SpaceView3D.draw_handler_add(
|
||||
self.draw2d_callback, (), 'WINDOW', 'POST_PIXEL')
|
||||
self.post_view_handle = bpy.types.SpaceView3D.draw_handler_add(
|
||||
self.post_view_callback, (), 'WINDOW', 'POST_VIEW')
|
||||
self.post_pixel_handle = bpy.types.SpaceView3D.draw_handler_add(
|
||||
self.post_pixel_callback, (), 'WINDOW', 'POST_PIXEL')
|
||||
|
||||
def unregister_handlers(self):
|
||||
if self.draw2d_handle:
|
||||
if self.post_pixel_handle:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(
|
||||
self.draw2d_handle, "WINDOW")
|
||||
self.draw2d_handle = None
|
||||
self.post_pixel_handle, "WINDOW")
|
||||
self.post_pixel_handle = None
|
||||
|
||||
if self.draw3d_handle:
|
||||
if self.post_view_handle:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(
|
||||
self.draw3d_handle, "WINDOW")
|
||||
self.draw3d_handle = None
|
||||
self.post_view_handle, "WINDOW")
|
||||
self.post_view_handle = None
|
||||
|
||||
self.d3d_items.clear()
|
||||
self.d2d_items.clear()
|
||||
@ -230,92 +369,7 @@ class DrawFactory(object):
|
||||
|
||||
self.d2d_items.clear()
|
||||
|
||||
def draw_client_selection(self, client_id, client_color, client_selection):
|
||||
local_user = utils.get_preferences().username
|
||||
|
||||
if local_user != client_id:
|
||||
self.flush_selection(client_id)
|
||||
|
||||
for select_ob in client_selection:
|
||||
drawable_key = f"{client_id}_select_{select_ob}"
|
||||
|
||||
ob = utils.find_from_attr("uuid", select_ob, bpy.data.objects)
|
||||
if not ob:
|
||||
return
|
||||
|
||||
if ob.type == 'EMPTY':
|
||||
# TODO: Child case
|
||||
# Collection instance case
|
||||
indices = (
|
||||
(0, 1), (1, 2), (2, 3), (0, 3),
|
||||
(4, 5), (5, 6), (6, 7), (4, 7),
|
||||
(0, 4), (1, 5), (2, 6), (3, 7))
|
||||
if ob.instance_collection:
|
||||
for obj in ob.instance_collection.objects:
|
||||
if obj.type == 'MESH':
|
||||
self.append_3d_item(
|
||||
drawable_key,
|
||||
client_color,
|
||||
get_bb_coords_from_obj(obj, parent=ob),
|
||||
indices)
|
||||
|
||||
if ob.type in ['MESH','META']:
|
||||
indices = (
|
||||
(0, 1), (1, 2), (2, 3), (0, 3),
|
||||
(4, 5), (5, 6), (6, 7), (4, 7),
|
||||
(0, 4), (1, 5), (2, 6), (3, 7))
|
||||
|
||||
self.append_3d_item(
|
||||
drawable_key,
|
||||
client_color,
|
||||
get_bb_coords_from_obj(ob),
|
||||
indices)
|
||||
else:
|
||||
indices = (
|
||||
(0, 1), (0, 2), (1, 3), (2, 3),
|
||||
(4, 5), (4, 6), (5, 7), (6, 7),
|
||||
(0, 4), (1, 5), (2, 6), (3, 7))
|
||||
|
||||
self.append_3d_item(
|
||||
drawable_key,
|
||||
client_color,
|
||||
get_default_bbox(ob, ob.scale.x),
|
||||
indices)
|
||||
|
||||
def append_3d_item(self,key,color, coords, indices):
|
||||
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
|
||||
color = color
|
||||
batch = batch_for_shader(
|
||||
shader, 'LINES', {"pos": coords}, indices=indices)
|
||||
|
||||
self.d3d_items[key] = (shader, batch, color)
|
||||
|
||||
def draw_client_camera(self, client_id, client_location, client_color):
|
||||
if client_location:
|
||||
local_user = utils.get_preferences().username
|
||||
|
||||
if local_user != client_id:
|
||||
try:
|
||||
indices = (
|
||||
(1, 3), (2, 1), (3, 0),
|
||||
(2, 0), (4, 5), (1, 6),
|
||||
(2, 6), (3, 6), (0, 6)
|
||||
)
|
||||
|
||||
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
|
||||
position = [tuple(coord) for coord in client_location]
|
||||
color = client_color
|
||||
|
||||
batch = batch_for_shader(
|
||||
shader, 'LINES', {"pos": position}, indices=indices)
|
||||
|
||||
self.d3d_items[client_id] = (shader, batch, color)
|
||||
self.d2d_items[client_id] = (position[1], client_id, color)
|
||||
|
||||
except Exception as e:
|
||||
logging.debug(f"Draw client exception: {e} \n {traceback.format_exc()}\n pos:{position},ind:{indices}")
|
||||
|
||||
def draw3d_callback(self):
|
||||
def post_view_callback(self):
|
||||
bgl.glLineWidth(2.)
|
||||
bgl.glEnable(bgl.GL_DEPTH_TEST)
|
||||
bgl.glEnable(bgl.GL_BLEND)
|
||||
@ -326,10 +380,14 @@ class DrawFactory(object):
|
||||
shader.bind()
|
||||
shader.uniform_float("color", color)
|
||||
batch.draw(shader)
|
||||
except Exception:
|
||||
logging.error("3D Exception")
|
||||
|
||||
def draw2d_callback(self):
|
||||
for widget in self.widgets:
|
||||
if widget.poll():
|
||||
widget.draw()
|
||||
except Exception as e:
|
||||
logging.error(f"3D Exception: {e} \n {traceback.print_exc()}")
|
||||
|
||||
def post_pixel_callback(self):
|
||||
for position, font, color in self.d2d_items.values():
|
||||
try:
|
||||
coords = get_client_2d(position)
|
||||
@ -341,16 +399,14 @@ class DrawFactory(object):
|
||||
blf.draw(0, font)
|
||||
|
||||
except Exception:
|
||||
logging.error("2D EXCEPTION")
|
||||
logging.error(f"2D Exception: {e} \n {traceback.print_exc()}")
|
||||
|
||||
this = sys.modules[__name__]
|
||||
this.renderer = DrawFactory()
|
||||
|
||||
def register():
|
||||
global renderer
|
||||
renderer = DrawFactory()
|
||||
renderer.run()
|
||||
|
||||
|
||||
def unregister():
|
||||
global renderer
|
||||
renderer.unregister_handlers()
|
||||
|
||||
del renderer
|
||||
renderer.stop()
|
||||
|
@ -637,7 +637,6 @@ class VIEW3D_PT_overlay_session(bpy.types.Panel):
|
||||
display_all = overlay.show_overlays
|
||||
|
||||
col = layout.column()
|
||||
col.active = display_all
|
||||
|
||||
row = col.row(align=True)
|
||||
settings = context.window_manager.session
|
||||
|
Reference in New Issue
Block a user