import bpy, gpu, math, time, mathutils, random
from mathutils import Vector
from gpu_extras.batch import batch_for_shader
from bpy.props import StringProperty, BoolProperty
from ...ui_framework.graphics.draw import render_geo, draw_border_lines, render_quad, render_text
from ...ui_framework.utils.geo import get_blf_text_dims
from ... utility import addon
from ...utility import method_handler
from ...utils.blender_ui import get_dpi, get_dpi_factor
##############################################################################
# Global Data
##############################################################################
HANDLE = None # The draw handle for shader
HOLD_DURATION = 2 # How long to show the uvs before fading
FADE_DURATION = 4 # How long to fade out for
class Data:
'''Global communications from operator to ui modal.'''
containers = []
currently_drawing = False
reset = False # Tell the modal to reset itself
@staticmethod
def reset_data():
Data.containers = []
class Container:
'''The drawing data container.'''
def __init__(self):
# Edges
self.uv_loop_verts = []
# Faces
self.loop_tris = [] # Indices
self.uv_points = [] # Points
# Color
self.color = addon.preference().color.Hops_UI_uv_color
# Map Name
self.name = ""
##############################################################################
# Launch Operator
##############################################################################
class HOPS_OT_Draw_UV_Launcher(bpy.types.Operator):
bl_idname = "hops.draw_uv_launcher"
bl_label = "UV Draw Launcher"
bl_options = {"INTERNAL"}
target_obj: StringProperty(
name = 'Target UV Obj',
description = 'The target object to draw uvs for',
default = '')
use_selected_meshes: BoolProperty(
name = "Use selected mesh",
default = False)
use_selected_faces: BoolProperty(
name = "Use the selected faces",
default = False)
def execute(self, context):
# Not called properly
if self.target_obj == '':
if self.use_selected_meshes == False:
return {'FINISHED'}
# Draw all selected meshes
if self.use_selected_meshes == True:
set_uv_draw_data_multi(context, self.use_selected_faces)
# Single draw data
else:
if self.target_obj in bpy.data.objects.keys():
obj = bpy.data.objects[self.target_obj]
set_uv_draw_data_single(obj, self.use_selected_faces)
if len(Data.containers) < 1:
bpy.ops.hops.display_notification(info="No UV Maps Found")
return {'FINISHED'}
# Trigger modal to reset its timers and start fade over again
if Data.currently_drawing == True:
Data.reset = True
# Call a fresh operator if none is currently running
if Data.reset == False:
bpy.ops.hops.draw_uvs('INVOKE_DEFAULT')
return {'FINISHED'}
##############################################################################
# Utils for Launcher
##############################################################################
def set_uv_draw_data_single(obj, use_selected_faces=False):
'''Get a list of list vector 2 that represents the uv edges. [[Vec2, Vec2, Vec2], ... ]'''
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
Data.reset_data()
mesh = obj.data
container = build_and_append_draw_data(mesh)
Data.containers.append(container)
def set_uv_draw_data_multi(context, use_selected_faces=False):
'''Get a list of list vector 2 that represents the uv edges. [[Vec2, Vec2, Vec2], ... ]'''
selected = context.selected_objects[:]
in_mode = context.objects_in_mode[:]
objects = set(selected + in_mode)
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
Data.reset_data()
meshes = [obj.data for obj in objects if obj.type == 'MESH']
for mesh in meshes:
container = build_and_append_draw_data(mesh, use_selected_faces)
if container != None:
Data.containers.append(container)
if len(Data.containers) > 1:
for container in Data.containers:
container.color = (random.uniform(.5, .25), random.uniform(.5, .25), random.uniform(.5, .25), 1)
def build_and_append_draw_data(mesh, use_selected_faces=False):
'''Take the mesh and build the draw data. Returns the new draw data instance.'''
# Validate
if len(mesh.uv_layers) < 1:
return None
offset = addon.preference().ui.Hops_uv_padding * get_dpi_factor()
scale = addon.preference().ui.Hops_uv_scale * get_dpi_factor()
container = Container() # Create a new container
mesh.update()
mesh.calc_loop_triangles()
# For drawing faces
for tri in mesh.loop_triangles:
# If only use selected faces
if use_selected_faces:
polygon = mesh.polygons[tri.polygon_index]
if not polygon.select:
continue
container.loop_tris.append(tri.loops[:])
uv_data = mesh.uv_layers.active.data
for ud in uv_data:
point = ud.uv * scale
point[0] += offset
point[1] += offset
container.uv_points.append(point)
# For drawing edges
uv_layer = mesh.uv_layers.active
container.name = uv_layer.name # Get name
uvs = [uv_loop.uv for uv_loop in uv_layer.data]
for polygon in mesh.polygons:
# If only use selected faces
if use_selected_faces and not polygon.select:
continue
points = [uvs[index] for index in polygon.loop_indices]
for i in range(len(points)):
point = [points[i][0] * scale + offset, points[i][1] * scale + offset]
container.uv_loop_verts.append(point)
if i < len(points) - 1:
point = [points[i + 1][0] * scale + offset, points[i + 1][1] * scale + offset]
container.uv_loop_verts.append(point)
else:
point = [points[-1][0] * scale + offset, points[-1][1] * scale + offset]
point = [points[0][0] * scale + offset, points[0][1] * scale + offset]
container.uv_loop_verts.append(point)
return container
##############################################################################
# Drawing Modal
##############################################################################
class HOPS_OT_Draw_UV(bpy.types.Operator):
'''UI Modal'''
bl_idname = "hops.draw_uvs"
bl_label = "Drawing for uvs"
bl_options = {"INTERNAL"}
def invoke(self, context, event):
# Global
Data.currently_drawing = True
Data.reset = False
# Props
self.prefs = addon.preference()
# Registers
self.shader = Shader(context)
self.timer = context.window_manager.event_timer_add(0.075, window=context.window)
# Time
self.start_time = time.time()
self.time_diff = 0
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
def modal(self, context, event):
# Resest every thing if new drawing is initialized
self.__check_for_reset()
# Capture the difference in start time and now
self.time_diff = time.time() - self.start_time
# Tigger fade
if self.time_diff >= HOLD_DURATION:
self.shader.start_fade = True
# Hold + Fade : completed
if self.time_diff >= HOLD_DURATION + FADE_DURATION:
self.__finished(context)
return {'FINISHED'}
# Redraw the viewport
if context.area != None:
context.area.tag_redraw()
return {'PASS_THROUGH'}
def __check_for_reset(self):
'''Check if the draw should start over due to another op call.'''
if Data.reset == True:
Data.reset = False
Data.currently_drawing = True
self.start_time = time.time()
self.time_diff = 0
self.shader.reset()
def __finished(self, context):
'''Remove the timer, shader, and reset Data'''
# Global
Data.currently_drawing = False
Data.reset = False
Data.reset_data()
# Unregister
if self.timer != None:
context.window_manager.event_timer_remove(self.timer)
if self.shader != None:
self.shader.destroy()
if context.area != None:
context.area.tag_redraw()
##############################################################################
# Draw Shader
##############################################################################
class Shader():
def __init__(self, context):
self.context = context
self.prefs = addon.preference()
self.start_fade = False
self.__captured_start_fade_time = False
self.__start_fade_time = 0
color = self.prefs.color.Hops_UI_uv_color
self.__og_alpha = color[3]
self.__alpha = color[3]
self.__setup_handle()
# BG props
self.bg_color = self.prefs.color.Hops_UI_cell_background_color
self.br_color = self.prefs.color.Hops_UI_border_color
offset = self.prefs.ui.Hops_uv_padding * get_dpi_factor()
scale = self.prefs.ui.Hops_uv_scale * get_dpi_factor()
self.padding = 15 * get_dpi_factor()
far_left = offset - self.padding
far_right = offset + scale + self.padding
bottom = offset - self.padding
top = offset + scale + self.padding
self.top_left = (far_left, top)
self.bot_left = (far_left, bottom)
self.top_right = (far_right, top)
self.bot_right = (far_right, bottom)
# Text
self.font_color = self.prefs.color.Hops_UI_text_color
self.font_size = 14
self.__full_alpha = 1
def __setup_handle(self):
'''Setup the draw handle for the UI'''
global HANDLE
if HANDLE == None:
HANDLE = bpy.types.SpaceView3D.draw_handler_add(self.safe_draw, (self.context, ), "WINDOW", "POST_PIXEL")
def safe_draw(self, context):
method_handler(self.draw,
arguments = (context,),
identifier = 'UV Draw Shader',
exit_method = self.destroy)
def draw(self, context):
'''Draw the UVs.'''
self.__fade_alpha()
# Validate
if Data.containers == []:
return
self.__draw_bg()
self.__draw_label()
self.__draw_uvs()
def __fade_alpha(self):
if self.start_fade == True:
# Capture fade start fade time
if self.__captured_start_fade_time == False:
self.__captured_start_fade_time = True
self.__start_fade_time = time.time()
# Fade alpha
duration = FADE_DURATION
diff = time.time() - self.__start_fade_time
ratio = diff / duration
self.__alpha = self.__og_alpha - (self.__og_alpha * ratio)
self.__full_alpha = 1 - (1 * ratio) # Used with text to start at 1
def __draw_bg(self):
'''Draw the background behind the UVs.'''
bg_color = (self.bg_color[0], self.bg_color[1], self.bg_color[2], self.__alpha)
br_color = (self.br_color[0], self.br_color[1], self.br_color[2], self.__alpha)
render_quad(
quad=(self.top_left, self.bot_left, self.top_right, self.bot_right),
color=bg_color)
draw_border_lines(
vertices=[self.top_left, self.bot_left, self.top_right, self.bot_right],
width=2,
color=br_color,
format_lines=True)
def __draw_label(self):
'''Draw the text over the uvs box.'''
color = (self.font_color[0], self.font_color[1], self.font_color[2], self.__full_alpha)
label = "UV Display"
label_x = get_blf_text_dims(label, self.font_size)[0]
render_text(
text=label,
position=(self.top_left[0], self.top_left[1] + self.padding),
size=self.font_size,
color=color)
# Draw the uv maps on the right hand side
if len(Data.containers) > 1:
y_offset = 0
for container in Data.containers:
height = get_blf_text_dims(container.name, self.font_size)[1]
color = (container.color[0] + .25, container.color[1] + .25, container.color[2] + .25, self.__full_alpha)
render_text(
text=container.name,
position=(self.bot_right[0] + self.padding, self.bot_right[1] + y_offset),
size=self.font_size,
color=color)
y_offset += height + self.padding
elif len(Data.containers) == 1:
container = Data.containers[0]
color = (container.color[0] + .25, container.color[1] + .25, container.color[2] + .25, self.__full_alpha)
render_text(
text=container.name,
position=(self.top_left[0] + self.padding + label_x, self.top_left[1] + self.padding),
size=self.font_size,
color=color)
def __draw_uvs(self):
'''Draw the mesh uvs.'''
# Draw faces
for container in Data.containers:
color = (container.color[0], container.color[1], container.color[2], self.__alpha)
render_geo(verts=container.uv_points, indices=container.loop_tris, color=color)
# Draw edges
for container in Data.containers:
built_in_shader = 'UNIFORM_COLOR' if bpy.app.version[0] >=4 else '2D_UNIFORM_COLOR'
shader = gpu.shader.from_builtin(built_in_shader)
#Enable(GL_LINE_SMOOTH)
gpu.state.blend_set('ALPHA')
gpu.state.line_width_set(1)
batch = batch_for_shader(shader, 'LINES', {"pos": container.uv_loop_verts})
shader.bind()
shader.uniform_float("color", (0, 0, 0,self.__alpha))
batch.draw(shader)
gpu.state.blend_set('NONE')
del shader
del batch
def reset(self):
'''Reset the shader for new drawing before being deleted.'''
self.start_fade = False
color = self.prefs.color.Hops_UI_uv_color
self.__alpha = color[3]
self.__full_alpha = 1
self.__start_fade_time = 0
self.__captured_start_fade_time = False
def destroy(self):
'''Remove the shader.'''
global HANDLE
if HANDLE != None:
bpy.types.SpaceView3D.draw_handler_remove(HANDLE, "WINDOW")
HANDLE = None
Data.reset_data() # Extra clean up call
##############################################################################
# Remove On App Reload
##############################################################################
from bpy.app.handlers import persistent
@persistent
def remove_uv_draw_shader(dummy):
global HANDLE
if HANDLE != None:
bpy.types.SpaceView3D.draw_handler_remove(HANDLE, "WINDOW")
HANDLE = None
# Reset draw data
Data.reset_data()
Data.currently_drawing = False
Data.reset = False
# PART 2 -------------------------------------
import bpy, gpu, math, time, mathutils, random
from mathutils import Vector
from gpu_extras.batch import batch_for_shader
from bpy.props import StringProperty, BoolProperty
from ...ui_framework.graphics.draw import render_geo, draw_border_lines, render_quad, render_text
from ...ui_framework.utils.geo import get_blf_text_dims
from ... utility import addon
from ...utility import method_handler
from ...utils.blender_ui import get_dpi, get_dpi_factor
##############################################################################
# Global Data
##############################################################################
HANDLE = None # The draw handle for shader
HOLD_DURATION = 2 # How long to show the uvs before fading
FADE_DURATION = 4 # How long to fade out for
class Data:
'''Global communications from operator to ui modal.'''
containers = []
currently_drawing = False
reset = False # Tell the modal to reset itself
@staticmethod
def reset_data():
Data.containers = []
class Container:
'''The drawing data container.'''
def __init__(self):
# Edges
self.uv_loop_verts = []
# Faces
self.loop_tris = [] # Indices
self.uv_points = [] # Points
# Color
self.color = addon.preference().color.Hops_UI_uv_color
# Map Name
self.name = ""
##############################################################################
# Launch Operator
##############################################################################
class HOPS_OT_Draw_UV_Launcher(bpy.types.Operator):
bl_idname = "hops.draw_uv_launcher"
bl_label = "UV Draw Launcher"
bl_options = {"INTERNAL"}
target_obj: StringProperty(
name = 'Target UV Obj',
description = 'The target object to draw uvs for',
default = '')
use_selected_meshes: BoolProperty(
name = "Use selected mesh",
default = False)
use_selected_faces: BoolProperty(
name = "Use the selected faces",
default = False)
use_tagged_faces: BoolProperty(
name = "Use the tagged faces",
default = False)
show_all_and_highlight_sel: BoolProperty(
name = "Show all and highlight selected uvs",
default = False)
def execute(self, context):
# Not called properly
if self.target_obj == '':
if self.use_selected_meshes == False:
return {'FINISHED'}
# Draw all selected meshes
# if self.use_selected_meshes == True:
# set_uv_draw_data_multi(context, self.use_selected_faces)
# Valeriy sketch - Draw all selected meshes ----
if self.use_selected_meshes == True:
set_uv_draw_data_multi(context, self.use_selected_faces, self.use_tagged_faces, self.show_all_and_highlight_sel)
# -----------------------------------
# Single draw data
else:
if self.target_obj in bpy.data.objects.keys():
obj = bpy.data.objects[self.target_obj]
set_uv_draw_data_single(obj, self.use_selected_faces, self.use_tagged_faces, self.show_all_and_highlight_sel)
if len(Data.containers) < 1:
bpy.ops.hops.display_notification(info="No UV Maps Found")
return {'FINISHED'}
# Trigger modal to reset its timers and start fade over again
if Data.currently_drawing == True:
Data.reset = True
# Call a fresh operator if none is currently running
if Data.reset == False:
bpy.ops.hops.draw_uvs('INVOKE_DEFAULT')
return {'FINISHED'}
##############################################################################
# Utils for Launcher
##############################################################################
def set_uv_draw_data_single(obj, use_selected_faces=False, use_tagged_faces=False, show_all_and_highlight_sel=False):
'''Get a list of list vector 2 that represents the uv edges. [[Vec2, Vec2, Vec2], ... ]'''
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
Data.reset_data()
mesh = obj.data
# Override to show all uvs and highlight selected
use_selected_faces = not show_all_and_highlight_sel if show_all_and_highlight_sel else use_selected_faces
container = build_and_append_draw_data(mesh, use_selected_faces)
Data.containers.append(container)
# Layer on a selection layer
if show_all_and_highlight_sel:
for mesh in meshes:
container = highlight_layer(mesh)
if container != None:
Data.containers.append(container)
container.color = (random.uniform(.75, .875), random.uniform(.75, .875), random.uniform(.75, .875), 1)
container.name = ""
def set_uv_draw_data_multi(context, use_selected_faces=False, use_tagged_faces=False, show_all_and_highlight_sel=False):
'''Get a list of list vector 2 that represents the uv edges. [[Vec2, Vec2, Vec2], ... ]'''
selected = context.selected_objects[:]
in_mode = context.objects_in_mode[:]
objects = set(selected + in_mode)
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
Data.reset_data()
meshes = [obj.data for obj in objects if obj.type == 'MESH']
for mesh in meshes:
# Override to show all uvs and highlight selected
use_selected_faces = not show_all_and_highlight_sel if show_all_and_highlight_sel else use_selected_faces
container = build_and_append_draw_data(mesh, use_selected_faces, use_tagged_faces)
if container != None:
Data.containers.append(container)
if len(Data.containers) > 1:
for container in Data.containers:
container.color = (random.uniform(.5, .25), random.uniform(.5, .25), random.uniform(.5, .25), 1)
# Layer on a selection layer
if show_all_and_highlight_sel:
for mesh in meshes:
container = highlight_layer(mesh)
if container != None:
Data.containers.append(container)
container.color = (random.uniform(.75, .875), random.uniform(.75, .875), random.uniform(.75, .875), 1)
container.name = ""
def build_and_append_draw_data(mesh, use_selected_faces=False, use_tagged_faces=False):
'''Take the mesh and build the draw data. Returns the new draw data instance.'''
# Validate
if len(mesh.uv_layers) < 1:
return None
offset = addon.preference().ui.Hops_uv_padding * get_dpi_factor()
scale = addon.preference().ui.Hops_uv_scale * get_dpi_factor()
container = Container() # Create a new container
mesh.update()
mesh.calc_loop_triangles()
# For drawing faces
for tri in mesh.loop_triangles:
# If only use selected faces
if use_selected_faces:
polygon = mesh.polygons[tri.polygon_index]
if not polygon.select:
continue
container.loop_tris.append(tri.loops[:])
uv_data = mesh.uv_layers.active.data
for ud in uv_data:
point = ud.uv * scale
point[0] += offset
point[1] += offset
container.uv_points.append(point)
# For drawing edges
uv_layer = mesh.uv_layers.active
container.name = uv_layer.name # Get name
uvs = [uv_loop.uv for uv_loop in uv_layer.data]
for polygon in mesh.polygons:
# If only use selected faces
if use_selected_faces and not polygon.select:
continue
# Valeriy sketch ---- # If use tagged faces
if use_tagged_faces and display_facemap and display_facemap.data[polygon.index].value == 0:
continue
# ---------------------------------
points = [uvs[index] for index in polygon.loop_indices]
for i in range(len(points)):
point = [points[i][0] * scale + offset, points[i][1] * scale + offset]
container.uv_loop_verts.append(point)
if i < len(points) - 1:
point = [points[i + 1][0] * scale + offset, points[i + 1][1] * scale + offset]
container.uv_loop_verts.append(point)
else:
point = [points[-1][0] * scale + offset, points[-1][1] * scale + offset]
point = [points[0][0] * scale + offset, points[0][1] * scale + offset]
container.uv_loop_verts.append(point)
return container
def highlight_layer(mesh):
# Validate
if len(mesh.uv_layers) < 1:
return None
offset = addon.preference().ui.Hops_uv_padding * get_dpi_factor()
scale = addon.preference().ui.Hops_uv_scale * get_dpi_factor()
container = Container() # Create a new container
# For drawing faces
for tri in mesh.loop_triangles:
polygon = mesh.polygons[tri.polygon_index]
if not polygon.select:
continue
container.loop_tris.append(tri.loops[:])
uv_data = mesh.uv_layers.active.data
for ud in uv_data:
point = ud.uv * scale
point[0] += offset
point[1] += offset
container.uv_points.append(point)
# For drawing edges
uv_layer = mesh.uv_layers.active
container.name = uv_layer.name # Get name
uvs = [uv_loop.uv for uv_loop in uv_layer.data]
for polygon in mesh.polygons:
if not polygon.select:
continue
points = [uvs[index] for index in polygon.loop_indices]
for i in range(len(points)):
point = [points[i][0] * scale + offset, points[i][1] * scale + offset]
container.uv_loop_verts.append(point)
if i < len(points) - 1:
point = [points[i + 1][0] * scale + offset, points[i + 1][1] * scale + offset]
container.uv_loop_verts.append(point)
else:
point = [points[-1][0] * scale + offset, points[-1][1] * scale + offset]
point = [points[0][0] * scale + offset, points[0][1] * scale + offset]
container.uv_loop_verts.append(point)
return container
##############################################################################
# Drawing Modal
##############################################################################
class HOPS_OT_Draw_UV(bpy.types.Operator):
'''UI Modal'''
bl_idname = "hops.draw_uvs"
bl_label = "Drawing for uvs"
bl_options = {"INTERNAL"}
def invoke(self, context, event):
# Global
Data.currently_drawing = True
Data.reset = False
# Props
self.prefs = addon.preference()
# Registers
self.shader = Shader(context)
self.timer = context.window_manager.event_timer_add(0.075, window=context.window)
# Time
self.start_time = time.time()
self.time_diff = 0
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
def modal(self, context, event):
# Resest every thing if new drawing is initialized
self.__check_for_reset()
# Capture the difference in start time and now
self.time_diff = time.time() - self.start_time
# Tigger fade
if self.time_diff >= HOLD_DURATION:
self.shader.start_fade = True
# Hold + Fade : completed
if self.time_diff >= HOLD_DURATION + FADE_DURATION:
self.__finished(context)
return {'FINISHED'}
# Redraw the viewport
if context.area != None:
context.area.tag_redraw()
return {'PASS_THROUGH'}
def __check_for_reset(self):
'''Check if the draw should start over due to another op call.'''
if Data.reset == True:
Data.reset = False
Data.currently_drawing = True
self.start_time = time.time()
self.time_diff = 0
self.shader.reset()
def __finished(self, context):
'''Remove the timer, shader, and reset Data'''
# Global
Data.currently_drawing = False
Data.reset = False
Data.reset_data()
# Unregister
if self.timer != None:
context.window_manager.event_timer_remove(self.timer)
if self.shader != None:
self.shader.destroy()
if context.area != None:
context.area.tag_redraw()
##############################################################################
# Draw Shader
##############################################################################
class Shader():
def __init__(self, context):
self.context = context
self.prefs = addon.preference()
self.start_fade = False
self.__captured_start_fade_time = False
self.__start_fade_time = 0
color = self.prefs.color.Hops_UI_uv_color
self.__og_alpha = color[3]
self.__alpha = color[3]
self.__setup_handle()
# BG props
self.bg_color = self.prefs.color.Hops_UI_cell_background_color
self.br_color = self.prefs.color.Hops_UI_border_color
offset = self.prefs.ui.Hops_uv_padding * get_dpi_factor()
scale = self.prefs.ui.Hops_uv_scale * get_dpi_factor()
self.padding = 15 * get_dpi_factor()
far_left = offset - self.padding
far_right = offset + scale + self.padding
bottom = offset - self.padding
top = offset + scale + self.padding
self.top_left = (far_left, top)
self.bot_left = (far_left, bottom)
self.top_right = (far_right, top)
self.bot_right = (far_right, bottom)
# Text
self.font_color = self.prefs.color.Hops_UI_text_color
self.font_size = 14
self.__full_alpha = 1
def __setup_handle(self):
'''Setup the draw handle for the UI'''
global HANDLE
if HANDLE == None:
HANDLE = bpy.types.SpaceView3D.draw_handler_add(self.safe_draw, (self.context, ), "WINDOW", "POST_PIXEL")
def safe_draw(self, context):
method_handler(self.draw,
arguments = (context,),
identifier = 'UV Draw Shader',
exit_method = self.destroy)
def draw(self, context):
'''Draw the UVs.'''
self.__fade_alpha()
# Validate
if Data.containers == []:
return
self.__draw_bg()
self.__draw_label()
self.__draw_uvs()
def __fade_alpha(self):
if self.start_fade == True:
# Capture fade start fade time
if self.__captured_start_fade_time == False:
self.__captured_start_fade_time = True
self.__start_fade_time = time.time()
# Fade alpha
duration = FADE_DURATION
diff = time.time() - self.__start_fade_time
ratio = diff / duration
self.__alpha = self.__og_alpha - (self.__og_alpha * ratio)
self.__full_alpha = 1 - (1 * ratio) # Used with text to start at 1
def __draw_bg(self):
'''Draw the background behind the UVs.'''
bg_color = (self.bg_color[0], self.bg_color[1], self.bg_color[2], self.__alpha)
br_color = (self.br_color[0], self.br_color[1], self.br_color[2], self.__alpha)
render_quad(
quad=(self.top_left, self.bot_left, self.top_right, self.bot_right),
color=bg_color)
draw_border_lines(
vertices=[self.top_left, self.bot_left, self.top_right, self.bot_right],
width=2,
color=br_color,
format_lines=True)
def __draw_label(self):
'''Draw the text over the uvs box.'''
color = (self.font_color[0], self.font_color[1], self.font_color[2], self.__full_alpha)
label = "UV Display"
label_x = get_blf_text_dims(label, self.font_size)[0]
render_text(
text=label,
position=(self.top_left[0], self.top_left[1] + self.padding),
size=self.font_size,
color=color)
# Draw the uv maps on the right hand side
if len(Data.containers) > 1:
y_offset = 0
for container in Data.containers:
if container.name == "": continue
height = get_blf_text_dims(container.name, self.font_size)[1]
color = (container.color[0] + .25, container.color[1] + .25, container.color[2] + .25, self.__full_alpha)
render_text(
text=container.name,
position=(self.bot_right[0] + self.padding, self.bot_right[1] + y_offset),
size=self.font_size,
color=color)
y_offset += height + self.padding
elif len(Data.containers) == 1:
container = Data.containers[0]
if container.name == "": return
color = (container.color[0] + .25, container.color[1] + .25, container.color[2] + .25, self.__full_alpha)
render_text(
text=container.name,
position=(self.top_left[0] + self.padding + label_x, self.top_left[1] + self.padding),
size=self.font_size,
color=color)
def __draw_uvs(self):
'''Draw the mesh uvs.'''
# Draw faces
for container in Data.containers:
color = (container.color[0], container.color[1], container.color[2], self.__alpha)
render_geo(verts=container.uv_points, indices=container.loop_tris, color=color)
# Draw edges
for container in Data.containers:
built_in_shader = 'UNIFORM_COLOR' if bpy.app.version[0] >=4 else '2D_UNIFORM_COLOR'
shader = gpu.shader.from_builtin(built_in_shader)
#Enable(GL_LINE_SMOOTH)
gpu.state.blend_set('ALPHA')
gpu.state.line_width_set(1)
batch = batch_for_shader(shader, 'LINES', {"pos": container.uv_loop_verts})
shader.bind()
shader.uniform_float("color", (0, 0, 0,self.__alpha))
batch.draw(shader)
gpu.state.blend_set('NONE')
del shader
del batch
def reset(self):
'''Reset the shader for new drawing before being deleted.'''
self.start_fade = False
color = self.prefs.color.Hops_UI_uv_color
self.__alpha = color[3]
self.__full_alpha = 1
self.__start_fade_time = 0
self.__captured_start_fade_time = False
def destroy(self):
'''Remove the shader.'''
global HANDLE
if HANDLE != None:
bpy.types.SpaceView3D.draw_handler_remove(HANDLE, "WINDOW")
HANDLE = None
Data.reset_data() # Extra clean up call
##############################################################################
# Remove On App Reload
##############################################################################
from bpy.app.handlers import persistent
@persistent
def remove_uv_draw_shader(dummy):
global HANDLE
if HANDLE != None:
bpy.types.SpaceView3D.draw_handler_remove(HANDLE, "WINDOW")
HANDLE = None
# Reset draw data
Data.reset_data()
Data.currently_drawing = False
Data.reset = False