You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Blender-TexTools/__init__.py

1490 lines
57 KiB
Python

bl_info = {
"name": "TexTools",
"description": "Professional UV and Texture tools for Blender.",
"author": "renderhjs, (Port to 2.80 by Sav Martin)",
"version": (1, 3, 00),
"blender": (2, 80, 0),
"category": "UV",
"location": "UV Image Editor > Tools > 'TexTools' panel",
"wiki_url": "http://renderhjs.net/textools/blender/"
}
# Import local modules
# More info: https://wiki.blender.org/index.php/Dev:Py/Scripts/Cookbook/Code_snippets/Multi-File_packages
if "bpy" in locals():
import imp
imp.reload(utilities_ui)
imp.reload(settings)
imp.reload(utilities_bake)
imp.reload(utilities_color)
imp.reload(utilities_texel)
imp.reload(utilities_uv)
imp.reload(utilities_meshtex)
imp.reload(op_align)
imp.reload(op_bake)
imp.reload(op_bake_explode)
imp.reload(op_bake_organize_names)
imp.reload(op_texture_preview)
imp.reload(op_color_assign)
imp.reload(op_color_clear)
imp.reload(op_color_convert_texture)
imp.reload(op_color_convert_vertex_colors)
imp.reload(op_edge_split_bevel)
imp.reload(op_color_from_elements)
imp.reload(op_color_from_materials)
imp.reload(op_color_from_directions)
imp.reload(op_color_io_export)
imp.reload(op_color_io_import)
imp.reload(op_color_select)
imp.reload(op_island_align_edge)
imp.reload(op_island_align_sort)
imp.reload(op_island_align_world)
imp.reload(op_island_mirror)
imp.reload(op_island_rotate_90)
imp.reload(op_island_straighten_edge_loops)
imp.reload(op_rectify)
imp.reload(op_select_islands_identical)
imp.reload(op_select_islands_outline)
imp.reload(op_select_islands_overlap)
imp.reload(op_select_islands_flipped)
imp.reload(op_smoothing_uv_islands)
imp.reload(op_meshtex_create)
imp.reload(op_meshtex_wrap)
imp.reload(op_meshtex_trim)
imp.reload(op_meshtex_trim_collapse)
imp.reload(op_meshtex_pattern)
imp.reload(op_texel_checker_map)
imp.reload(op_texel_density_get)
imp.reload(op_texel_density_set)
imp.reload(op_texture_reload_all)
imp.reload(op_texture_save)
imp.reload(op_texture_open)
imp.reload(op_texture_select)
imp.reload(op_texture_remove)
imp.reload(op_unwrap_faces_iron)
imp.reload(op_unwrap_edge_peel)
imp.reload(op_uv_channel_add)
imp.reload(op_uv_channel_swap)
imp.reload(op_uv_crop)
imp.reload(op_uv_fill)
imp.reload(op_uv_resize)
imp.reload(op_uv_size_get)
else:
from . import settings
from . import utilities_ui
from . import utilities_bake
from . import utilities_color
from . import utilities_texel
from . import utilities_uv
from . import utilities_meshtex
from . import op_align
from . import op_bake
from . import op_bake_explode
from . import op_bake_organize_names
from . import op_texture_preview
from . import op_color_assign
from . import op_color_clear
from . import op_color_convert_texture
from . import op_color_convert_vertex_colors
from . import op_color_from_elements
from . import op_color_from_materials
from . import op_color_from_directions
from . import op_edge_split_bevel
from . import op_color_io_export
from . import op_color_io_import
from . import op_color_select
from . import op_island_align_edge
from . import op_island_align_sort
from . import op_island_align_world
from . import op_island_mirror
from . import op_island_rotate_90
from . import op_island_straighten_edge_loops
from . import op_rectify
from . import op_select_islands_identical
from . import op_select_islands_outline
from . import op_select_islands_overlap
from . import op_select_islands_flipped
from . import op_smoothing_uv_islands
from . import op_meshtex_create
from . import op_meshtex_wrap
from . import op_meshtex_trim
from . import op_meshtex_trim_collapse
from . import op_meshtex_pattern
from . import op_texel_checker_map
from . import op_texel_density_get
from . import op_texel_density_set
from . import op_texture_reload_all
from . import op_texture_save
from . import op_texture_open
from . import op_texture_select
from . import op_texture_remove
from . import op_unwrap_faces_iron
from . import op_unwrap_edge_peel
from . import op_uv_channel_add
from . import op_uv_channel_swap
from . import op_uv_crop
from . import op_uv_fill
from . import op_uv_resize
from . import op_uv_size_get
# Import general modules. Important: must be placed here and not on top
import bpy
import os
import math
import string
import bpy.utils.previews
from bpy.types import Menu, Operator, Panel, UIList
from bpy.props import (
StringProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
EnumProperty,
PointerProperty,
)
class Panel_Preferences(bpy.types.AddonPreferences):
bl_idname = __name__
# Addon Preferences https://docs.blender.org/api/blender_python_api_2_67_release/bpy.types.AddonPreferences.html
swizzle_y_coordinate : bpy.props.EnumProperty(items=
[
('Y+', 'Y+ OpenGL', 'Used in Blender, Maya, Modo, Toolbag, Unity'),
('Y-', 'Y- Direct X', 'Used in 3ds Max, CryENGINE, Source, Unreal Engine')
],
description="Color template",
name = "Swizzle Coordinates",
default = 'Y+'
)
bake_32bit_float : bpy.props.EnumProperty(items=
[
('8', '8 Bit', ''),
('32', '32 Bit', '')
],
description="",
name = "Image depth",
default = '8'
)
def draw(self, context):
layout = self.layout
box = layout.box()
col = box.column(align=True)
col.prop(self, "swizzle_y_coordinate", icon='ORIENTATION_GLOBAL')
if self.swizzle_y_coordinate == 'Y+':
col.label(text="Y+ used in: Blender, Maya, Modo, Toolbag, Unity")
elif self.swizzle_y_coordinate == 'Y-':
col.label(text="Y- used in: 3ds Max, CryENGINE, Source, Unreal Engine")
box.separator()
col = box.column(align=True)
col.prop(self, "bake_32bit_float", icon='IMAGE_RGB')
if self.bake_32bit_float == '8':
col.label(text="8 Bit images are used. Banding may appear in normal maps.")
elif self.bake_32bit_float == '32':
col.label(text="32 Bit images are used. Images may require dithering to 8 bit.")
if not hasattr(bpy.types,"ShaderNodeBevel"):
box.separator()
col = box.column(align=True)
col.label(text="Unlock Bevel Shader", icon='ERROR')
col.operator("wm.url_open", text="Get Blender with Bevel Shader", icon='BLENDER').url = "https://builder.blender.org/download/"
col.label(text="Use nightly builds of Blender 2.79 or 2.8 to access Bevel baking")
box = layout.box()
box.label(text="Additional Links")
col = box.column(align=True)
col.operator("wm.url_open", text="Donate", icon='HELP').url = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZC9X4LE7CPQN6"
col.operator("wm.url_open", text="GIT Code", icon='WORDWRAP_ON').url = "https://bitbucket.org/renderhjs/textools-blender/src"
col.label(text="Discussions")
row = col.row(align=True)
row.operator("wm.url_open", text="BlenderArtists", icon='BLENDER').url = "https://blenderartists.org/forum/showthread.php?443182-TexTools-for-Blender"
row.operator("wm.url_open", text="Polycount").url = "http://polycount.com/discussion/197226/textools-for-blender"
row.operator("wm.url_open", text="Twitter").url = "https://twitter.com/search?q=%23textools"
class UV_OT_op_debug(bpy.types.Operator):
bl_idname = "uv.op_debug"
bl_label = "Debug"
bl_description = "Open console and enable dbug mode"
@classmethod
def poll(cls, context):
return True
def execute(self, context):
bpy.app.debug = True# Debug Vertex indexies
bpy.context.object.data.show_extra_indices = True
bpy.app.debug_value = 1 #Set to Non '0
return {'FINISHED'}
class UV_OT_op_disable_uv_sync(bpy.types.Operator):
bl_idname = "uv.op_disable_uv_sync"
bl_label = "Disable Sync"
bl_description = "Disable UV sync mode"
@classmethod
def poll(cls, context):
return True
def execute(self, context):
bpy.context.scene.tool_settings.use_uv_select_sync = False
bpy.ops.mesh.select_all(action='SELECT')
return {'FINISHED'}
class UV_OT_op_select_bake_set(bpy.types.Operator):
bl_idname = "uv.op_select_bake_set"
bl_label = "Select"
bl_description = "Select this bake set in scene"
select_set : bpy.props.StringProperty(default="")
@classmethod
def poll(cls, context):
return True
def execute(self, context):
print("Set: "+self.select_set)
if self.select_set != "":
for set in settings.sets:
if set.name == self.select_set:
# Select this entire set
bpy.ops.object.select_all(action='DESELECT')
for obj in set.objects_low:
obj.select_set( state = True, view_layer = None)
for obj in set.objects_high:
obj.select_set( state = True, view_layer = None)
for obj in set.objects_cage:
obj.select_set( state = True, view_layer = None)
# Set active object to low poly to better visualize high and low wireframe color
if len(set.objects_low) > 0:
bpy.context.view_layer.objects.active = set.objects_low[0]
break
return {'FINISHED'}
class UV_OT_op_select_bake_type(bpy.types.Operator):
bl_idname = "uv.op_select_bake_type"
bl_label = "Select"
bl_description = "Select bake objects of this type"
select_type : bpy.props.StringProperty(default='low')
@classmethod
def poll(cls, context):
return True
def execute(self, context):
objects = []
for set in settings.sets:
if self.select_type == 'low':
objects+=set.objects_low
elif self.select_type == 'high':
objects+=set.objects_high
elif self.select_type == 'cage':
objects+=set.objects_cage
elif self.select_type == 'float':
objects+=set.objects_float
elif self.select_type == 'issue' and set.has_issues:
objects+=set.objects_low
objects+=set.objects_high
objects+=set.objects_cage
objects+=set.objects_float
bpy.ops.object.select_all(action='DESELECT')
for obj in objects:
obj.select_set( state = True, view_layer = None)
return {'FINISHED'}
def on_dropdown_size(self, context):
# Help: http://elfnor.com/drop-down-and-button-select-menus-for-blender-operator-add-ons.html
size = int(bpy.context.scene.texToolsSettings.size_dropdown)
bpy.context.scene.texToolsSettings.size[0] = size;
bpy.context.scene.texToolsSettings.size[1] = size;
if size <= 128:
bpy.context.scene.texToolsSettings.padding = 2
elif size <= 512:
bpy.context.scene.texToolsSettings.padding = 4
else:
bpy.context.scene.texToolsSettings.padding = 8
def on_dropdown_uv_channel(self, context):
if bpy.context.active_object != None:
if bpy.context.active_object.type == 'MESH':
if bpy.context.object.data.uv_layers:
# Change Mesh UV Channel
index = int(bpy.context.scene.texToolsSettings.uv_channel)
if index < len(bpy.context.object.data.uv_layers):
bpy.context.object.data.uv_layers.active_index = index
bpy.context.object.data.uv_layers[index].active_render = True
def on_color_changed(self, context):
for i in range(0, context.scene.texToolsSettings.color_ID_count):
utilities_color.assign_color(i)
def on_color_dropdown_template(self, context):
# Change Mesh UV Channel
hex_colors = bpy.context.scene.texToolsSettings.color_ID_templates.split(',')
bpy.context.scene.texToolsSettings.color_ID_count = len(hex_colors)
# Assign color slots
for i in range(0, len(hex_colors)):
color = utilities_color.hex_to_color("#"+hex_colors[i])
utilities_color.set_color(i, color)
utilities_color.assign_color(i)
def on_color_count_changed(self, context):
if bpy.context.active_object != None:
utilities_color.validate_face_colors(bpy.context.active_object)
def get_dropdown_uv_values(self, context):
# Requires mesh and UV data
if bpy.context.active_object != None:
if bpy.context.active_object.type == 'MESH':
if bpy.context.object.data.uv_layers:
options = []
step = 0
for uvLoop in bpy.context.object.data.uv_layers:
# options.append((str(step), "#{} {}".format(step+1, uvLoop.name), "Change UV channel to '{}'".format(uvLoop.name), step))
options.append((str(step), "UV {}".format(step+1), "Change UV channel to '{}'".format(uvLoop.name), step))
step+=1
return options
return []
def on_slider_meshtexture_wrap(self, context):
value = bpy.context.scene.texToolsSettings.meshtexture_wrap
obj_uv = utilities_meshtex.find_uv_mesh(bpy.context.selected_objects)
if obj_uv:
obj_uv.data.shape_keys.key_blocks["model"].value = value
class TexToolsSettings(bpy.types.PropertyGroup):
#Width and Height
size : bpy.props.IntVectorProperty(
name = "Size",
size=2,
description="Texture & UV size in pixels",
default = (512,512),
subtype = "XYZ"
)
size_dropdown : bpy.props.EnumProperty(
items = utilities_ui.size_textures,
name = "Texture Size",
update = on_dropdown_size,
default = '512'
)
uv_channel : bpy.props.EnumProperty(
items = get_dropdown_uv_values,
name = "UV",
update = on_dropdown_uv_channel
)
padding : bpy.props.IntProperty(
name = "Padding",
description="padding size in pixels",
default = 4,
min = 0,
max = 256
)
bake_samples : bpy.props.FloatProperty(
name = "Samples",
description = "Samples in Cycles for Baking. The higher the less noise. Default: 64",
default = 8,
min = 1,
max = 4000
)
bake_curvature_size : bpy.props.IntProperty(
name = "Curvature",
description = "Curvature offset in pixels to process",
default = 1,
min = 1,
max = 64
)
bake_wireframe_size : bpy.props.FloatProperty(
name = "Thickness",
description = "Wireframe Thickness in pixels",
default = 1,
min = 0.1,
max = 4.0
)
bake_bevel_size : bpy.props.FloatProperty(
name = "Radius",
description = "Bevel radius 1 to 16",
default = 0.05,
min = 0.0,
max = 1.0
)
bake_bevel_samples : bpy.props.IntProperty(
name = "Bevel Samples",
description = "Bevel Samples",
default = 4,
min = 1,
max = 16
)
bake_ray_distance : bpy.props.FloatProperty(
name = "Ray Dist.",
description = "Ray distance when baking. When using cage used as extrude distance",
default = 0.01,
min = 0.000,
max = 100.00
)
bake_force_single : bpy.props.BoolProperty(
name="Single Texture",
description="Force a single texture bake accross all selected objects",
default = False
)
bake_exclude_others: bpy.props.BoolProperty(
name="Exclude Others",
description="Exclude deselected objects when rendering",
default = False
)
bake_merge_object: bpy.props.BoolProperty(
name="Merge Objects",
description="Merge selected objects when rendering, results in significantly lower bake times",
default = False
)
bake_sampling : bpy.props.EnumProperty(items=
[('1', 'None', 'No Anti Aliasing (Fast)'),
('2', '2x', 'Render 2x and downsample'),
('4', '4x', 'Render 2x and downsample')], name = "AA", default = '1'
)
bake_freeze_selection : bpy.props.BoolProperty(
name="Lock",
description="Lock baking sets, don't change with selection",
default = False
)
texel_mode_scale : bpy.props.EnumProperty(items=
[('ISLAND', 'Islands', 'Scale UV islands to match Texel Density'),
('ALL', 'Combined', 'Scale all UVs together to match Texel Density')],
name = "Mode",
default = 'ISLAND'
)
texel_density : bpy.props.FloatProperty(
name = "Texel",
description = "Texel size or Pixels per 1 unit ratio",
default = 256,
min = 0.0
# max = 100.00
)
meshtexture_wrap : bpy.props.FloatProperty(
name = "Wrap",
description = "Transition of mesh texture wrap",
default = 0,
min = 0,
max = 1,
update = on_slider_meshtexture_wrap,
subtype = 'FACTOR'
)
def get_color(hex = "808080"):
return bpy.props.FloatVectorProperty(
name="Color1",
description="Set Color 1 for the Palette",
subtype="COLOR",
default=utilities_color.hex_to_color(hex),
size=3,
max=1.0, min=0.0,
update=on_color_changed
)#, update=update_color_1
# 10 Color ID's
color_ID_color_0 : get_color(hex="#ff0000")
color_ID_color_1 : get_color(hex="#0000ff")
color_ID_color_2 : get_color(hex="#00ff00")
color_ID_color_3 : get_color(hex="#ffff00")
color_ID_color_4 : get_color(hex="#00ffff")
color_ID_color_5 : get_color()
color_ID_color_6 : get_color()
color_ID_color_7 : get_color()
color_ID_color_8 : get_color()
color_ID_color_9 : get_color()
color_ID_color_10 : get_color()
color_ID_color_11 : get_color()
color_ID_color_12 : get_color()
color_ID_color_13 : get_color()
color_ID_color_14 : get_color()
color_ID_color_15 : get_color()
color_ID_color_16 : get_color()
color_ID_color_17 : get_color()
color_ID_color_18 : get_color()
color_ID_color_19 : get_color()
color_ID_templates : bpy.props.EnumProperty(items=
[
('3d3d3d,7f7f7f,b8b8b8,ffffff', '4 Gray', '...'),
('003153,345d4b,688a42,9db63a,d1e231', '5 Greens', '...'),
('ff0000,0000ff,00ff00,ffff00,00ffff', '5 Code', '...'),
('3a4342,2e302f,242325,d5cc9e,d6412b', '5 Sea Wolf', '...'),
('7f87a0,2d3449,000000,ffffff,f99c21', '5 Mustang', '...'),
('143240,209d8c,fed761,ffab56,fb6941', '5 Sunset', '...'),
('0087ed,23ca7a,eceb1d,e37a29,da1c2c', '5 Heat', '...'),
('9e00af,7026b9,4f44b5,478bf4,39b7d5,229587,47b151,9dcf46,f7f235,f7b824,f95f1e,c5513c,78574a,4d4b4b,9d9d9d', '15 Rainbow', '...')
],
description="Color template",
name = "Preset",
update = on_color_dropdown_template,
default = 'ff0000,0000ff,00ff00,ffff00,00ffff'
)
color_ID_count : bpy.props.IntProperty(
name = "Count",
description="Number of color IDs",
default = 5,
update = on_color_count_changed,
min = 2,
max = 20
)
# bake_do_save = bpy.props.BoolProperty(
# name="Save",
# description="Save the baked texture?",
# default = False)
class UI_PT_Panel_Units(bpy.types.Panel):
bl_label = " "
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_category = "TexTools"
#bl_options = {'HIDE_HEADER'}
def draw_header(self, _):
layout = self.layout
row = layout.row(align=True)
row.label(text ="TexTools")
#layout.label(text="Size: {} x {}".format(bpy.context.scene.texToolsSettings.size[0], bpy.context.scene.texToolsSettings.size[1]))
def draw(self, context):
layout = self.layout
if bpy.app.debug_value != 0:
row = layout.row()
row.alert =True
row.operator("uv.op_debug", text="DEBUG", icon="CONSOLE")
#---------- Settings ------------
# row = layout.row()
col = layout.column(align=True)
r = col.row(align = True)
r.prop(context.scene.texToolsSettings, "size_dropdown", text="Size")
r.operator(op_uv_size_get.op.bl_idname, text="", icon = 'EYEDROPPER')
r = col.row(align = True)
r.prop(context.scene.texToolsSettings, "size", text="")
r = col.row(align = True)
r.prop(context.scene.texToolsSettings, "padding", text="Padding")
r.operator(op_uv_resize.op.bl_idname, text="Resize", icon_value = icon_get("op_extend_canvas_open"))
# col.operator(op_extend_canvas.op.bl_idname, text="Resize", icon_value = icon_get("op_extend_canvas"))
# UV Channel
row = layout.row()
has_uv_channel = False
if bpy.context.active_object and len(bpy.context.selected_objects) == 1:
if bpy.context.active_object in bpy.context.selected_objects:
if bpy.context.active_object.type == 'MESH':
# split = row.split(percentage=0.25)
# c = row.column(align=True)
# r = row.row(align=True)
# r.alignment = 'RIGHT'
# r.expand =
# row.label(text="UV")#, icon='GROUP_UVS'
if not bpy.context.object.data.uv_layers:
# c = split.column(align=True)
# row = c.row(align=True)
# row.label(text="None", icon= 'ERROR')
row.operator(op_uv_channel_add.op.bl_idname, text="Add", icon = 'REMOVE')
else:
# c = split.column(align=True)
# row = c.row(align=True)
group = row.row(align=True)
group.prop(context.scene.texToolsSettings, "uv_channel", text="")
group.operator(op_uv_channel_add.op.bl_idname, text="", icon = 'ADD')
# c = split.column(align=True)
# row = c.row(align=True)
# row.alignment = 'RIGHT'
group = row.row(align=True)
r = group.column(align=True)
r.active = bpy.context.object.data.uv_layers.active_index > 0
r.operator(op_uv_channel_swap.op.bl_idname, text="", icon = 'TRIA_UP_BAR').is_down = False;
r = group.column(align=True)
r.active = bpy.context.object.data.uv_layers.active_index < (len(bpy.context.object.data.uv_layers)-1)
r.operator(op_uv_channel_swap.op.bl_idname, text="", icon = 'TRIA_DOWN_BAR').is_down = True;
has_uv_channel = True
if not has_uv_channel:
row.label(text="UV")
col = layout.column(align=True)
# col.separator()
col.operator(op_texture_reload_all.op.bl_idname, text="Reload Textures", icon_value = icon_get("op_texture_reload_all"))
row = col.row(align=True)
row.scale_y = 1.75
row.operator(op_texel_checker_map.op.bl_idname, text ="Checker Map", icon_value = icon_get("op_texel_checker_map"))
class UI_PT_Panel_Layout(bpy.types.Panel):
bl_label = " "
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_category = "TexTools"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, _):
layout = self.layout
row = layout.row(align=True)
row.operator("wm.url_open", text="", icon='INFO').url = "http://renderhjs.net/textools/blender/index.html#uvlayout"
row.label(text ="UV Layout")
# def draw_header(self, _):
# layout = self.layout
# layout.label(text="", icon_value=icon("logo"))
def draw(self, context):
layout = self.layout
if bpy.app.debug_value != 0:
col = layout.column(align=True)
col.alert = True
row = col.row(align=True)
row.operator(op_island_mirror.op.bl_idname, text="Mirror", icon_value = icon_get("op_island_mirror")).is_stack = False;
row.operator(op_island_mirror.op.bl_idname, text="Stack", icon_value = icon_get("op_island_mirror")).is_stack = True;
#---------- Layout ------------
# layout.label(text="Layout")
box = layout.box()
col = box.column(align=True)
if bpy.context.active_object and bpy.context.active_object.mode == 'EDIT' and bpy.context.scene.tool_settings.use_uv_select_sync:
row = col.row(align=True)
row.alert = True
row.operator("uv.op_disable_uv_sync", text="Disable sync", icon='CANCEL')#, icon='UV_SYNC_SELECT'
row = col.row(align=True)
row.operator(op_uv_crop.op.bl_idname, text="Crop", icon_value = icon_get("op_uv_crop"))
row.operator(op_uv_fill.op.bl_idname, text="Fill", icon_value = icon_get("op_uv_fill"))
row = col.row(align=True)
row.operator(op_island_align_edge.op.bl_idname, text="Align Edge", icon_value = icon_get("op_island_align_edge"))
row = col.row(align=True)
row.operator(op_island_align_world.op.bl_idname, text="Align World", icon_value = icon_get("op_island_align_world"))
if bpy.app.debug_value != 0:
c = col.column(align=True)
c.alert = True
c.operator(op_edge_split_bevel.op.bl_idname, text="Split Bevel")
col.separator()
col_tr = col.column(align=True)
row = col_tr.row(align=True)
col = row.column(align=True)
col.label(text="")
col.operator(op_align.op.bl_idname, text="", icon_value = icon_get("op_align_left")).direction = "left"
col = row.column(align=True)
col.operator(op_align.op.bl_idname, text="", icon_value = icon_get("op_align_top")).direction = "top"
col.operator(op_align.op.bl_idname, text="", icon_value = icon_get("op_align_bottom")).direction = "bottom"
col = row.column(align=True)
col.label(text="")
col.operator(op_align.op.bl_idname, text="", icon_value = icon_get("op_align_right")).direction = "right"
row = col_tr.row(align=True)
row.operator(op_island_rotate_90.op.bl_idname, text="-90°", icon_value = icon_get("op_island_rotate_90_left")).angle = -math.pi / 2
row.operator(op_island_rotate_90.op.bl_idname, text="+90°", icon_value = icon_get("op_island_rotate_90_right")).angle = math.pi / 2
col = box.column(align=True)
row = col.row(align=True)
op = row.operator(op_island_align_sort.op.bl_idname, text="Sort H", icon_value = icon_get("op_island_align_sort_h"))
op.is_vertical = False;
op.padding = utilities_ui.get_padding()
op = row.operator(op_island_align_sort.op.bl_idname, text="Sort V", icon_value = icon_get("op_island_align_sort_v"))
op.is_vertical = True;
op.padding = utilities_ui.get_padding()
aligned = box.row(align=True)
col = aligned.column(align=True)
row = col.row(align=True)
row.operator(op_island_straighten_edge_loops.op.bl_idname, text="Straight", icon_value = icon_get("op_island_straighten_edge_loops"))
row.operator(op_rectify.op.bl_idname, text="Rectify", icon_value = icon_get("op_rectify"))
col.operator(op_unwrap_edge_peel.op.bl_idname, text="Edge Peel", icon_value = icon_get("op_unwrap_edge_peel"))
row = col.row(align=True)
row.scale_y = 1.75
row.operator(op_unwrap_faces_iron.op.bl_idname, text="Iron Faces", icon_value = icon_get("op_unwrap_faces_iron"))
col.separator()
# col = box.column(align=True)
row = col.row(align=True)
row.label(text="" , icon_value = icon_get("texel_density"))
row.separator()
row.prop(context.scene.texToolsSettings, "texel_density", text="")
row.operator(op_texel_density_get.op.bl_idname, text="", icon = 'EYEDROPPER')
row = col.row(align=True)
row.operator(op_texel_density_set.op.bl_idname, text="Apply", icon = 'FACESEL')
row.prop(context.scene.texToolsSettings, "texel_mode_scale", text = "", expand=False)
#---------- Selection ------------
# /box = layout.box()
# box.label(text="Select")
# col = box.column(align=True)
col.separator()
row = col.row(align=True)
row.operator(op_select_islands_identical.op.bl_idname, text="Similar", icon_value = icon_get("op_select_islands_identical"))
row.operator(op_select_islands_overlap.op.bl_idname, text="Overlap", icon_value = icon_get("op_select_islands_overlap"))
row = col.row(align=True)
row.operator(op_select_islands_outline.op.bl_idname, text="Bounds", icon_value = icon_get("op_select_islands_outline"))
row.operator(op_select_islands_flipped.op.bl_idname, text="Flipped", icon_value = icon_get('op_select_islands_flipped'))
col.separator()
col.operator(op_smoothing_uv_islands.op.bl_idname, text="UV Smoothing", icon_value = icon_get("op_smoothing_uv_islands"))
class UI_PT_Panel_Bake(bpy.types.Panel):
bl_label = " "
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_category = "TexTools"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, _):
layout = self.layout
row = layout.row(align=True)
row.operator("wm.url_open", text="", icon='INFO').url = "http://renderhjs.net/textools/blender/index.html#texturebaking"
row.label(text ="Baking")
def draw(self, context):
layout = self.layout
#----------- Baking -------------
row = layout.row()
box = row.box()
col = box.column(align=True)
if not (bpy.context.scene.texToolsSettings.bake_freeze_selection and len(settings.sets) > 0):
# Update sets
settings.sets = utilities_bake.get_bake_sets()
# Bake Button
count = 0
if bpy.context.scene.texToolsSettings.bake_force_single and len(settings.sets) > 0:
count = 1
else:
count = len(settings.sets)
row = col.row(align=True)
row.scale_y = 1.75
row.operator(op_bake.op.bl_idname, text = "Bake {}x".format(count), icon_value = icon_get("op_bake"));
# anti aliasing
col.prop(context.scene.texToolsSettings, "bake_sampling", icon_value =icon_get("bake_anti_alias"))
if bpy.app.debug_value != 0:
row = col.row()
row.alert = True
row.prop(context.scene.texToolsSettings, "bake_force_single", text="Dither Floats")
col.separator()
row = col.row(align=True)
row.prop(context.scene.texToolsSettings, "bake_exclude_others", text="Only Selected")
#row = col.row(align=True)
#row.prop(context.scene.texToolsSettings, "bake_merge_object", text="Merge Selected")
col.separator()
row = col.row(align=True)
row.scale_y = 1.5
row.operator(op_texture_preview.op.bl_idname, text = "Preview Texture", icon_value = icon_get("op_texture_preview"));
images = utilities_bake.get_baked_images(settings.sets)
if len(images) > 0:
image_background = None
for area in bpy.context.screen.areas:
if area.type == 'IMAGE_EDITOR':
if area.spaces[0].image:
image_background = area.spaces[0].image
break
box = col.box()
# box.label(text="{}x images".format(len(images)), icon="IMAGE_DATA")
col_box = box.column(align=True)
for image in images:
row = col_box.row(align=True)
# row.label(text=image.name, icon='')
icon = 'RADIOBUT_OFF'
if image == image_background:
icon = 'RADIOBUT_ON'
row.operator(op_texture_select.op.bl_idname, text=image.name, icon=icon).name = image.name #,
row = row.row(align=True)
row.alignment = 'RIGHT'
if image.filepath != "":
row.operator(op_texture_open.op.bl_idname, text="", icon_value=icon_get("op_texture_open") ).name = image.name
else:
if bpy.app.debug_value != 0:
row.operator(op_texture_save.op.bl_idname, text="", icon_value=icon_get("op_texture_save") ).name = image.name
else:
pass
row.operator(op_texture_remove.op.bl_idname, text="", icon='X' ).name = image.name
col.separator()
# Bake Mode
col.template_icon_view(bpy.context.scene, "TT_bake_mode")
if bpy.app.debug_value != 0:
row = col.row()
row.label(text="--> Mode: '{}'".format(bpy.context.scene.TT_bake_mode))
bake_mode = utilities_ui.get_bake_mode()
# Warning: Wrong bake mode, require
if bake_mode == 'diffuse':
if bpy.context.scene.render.engine != 'CYCLES':
if bpy.context.scene.render.engine != op_bake.modes[bake_mode].engine:
col.label(text="Requires '{}'".format(op_bake.modes[bake_mode].engine), icon='ERROR')
# Optional Parameters
col.separator()
for set in settings.sets:
if len(set.objects_low) > 0 and len(set.objects_high) > 0:
col.prop(context.scene.texToolsSettings, "bake_ray_distance")
break
# Display Bake mode properties / parameters
if bake_mode in op_bake.modes:
params = op_bake.modes[bake_mode].params
if len(params) > 0:
for param in params:
col.prop(context.scene.texToolsSettings, param)
# Warning about projection requirement
if len(settings.sets) > 0 and op_bake.modes[bake_mode].use_project == True:
if len(settings.sets[0].objects_low) == 0 or len(settings.sets[0].objects_high) == 0:
col.label(text="Need high and low", icon='ERROR')
box = layout.box()
col = box.column(align=True)
# Select by type
if len(settings.sets) > 0:
row = col.row(align=True)
row.active = len(settings.sets) > 0
count_types = {
'low':0, 'high':0, 'cage':0, 'float':0, 'issue':0,
}
for set in settings.sets:
if set.has_issues:
count_types['issue']+=1
if len(set.objects_low) > 0:
count_types['low']+=1
if len(set.objects_high) > 0:
count_types['high']+=1
if len(set.objects_cage) > 0:
count_types['cage']+=1
if len(set.objects_float) > 0:
count_types['float']+=1
# Freeze Selection
c = row.column(align=True)
c.active = len(settings.sets) > 0 or bpy.context.scene.texToolsSettings.bake_freeze_selection
icon = 'LOCKED' if bpy.context.scene.texToolsSettings.bake_freeze_selection else 'UNLOCKED'
c.prop(context.scene.texToolsSettings, "bake_freeze_selection",text="Lock {}x".format(len(settings.sets)), icon=icon)
# Select by type
if count_types['issue'] > 0:
row.operator("uv.op_select_bake_type", text = "", icon = 'ERROR').select_type = 'issue'
row.operator("uv.op_select_bake_type", text = "", icon_value = icon_get("bake_obj_low")).select_type = 'low'
row.operator("uv.op_select_bake_type", text = "", icon_value = icon_get("bake_obj_high")).select_type = 'high'
if count_types['float'] > 0:
row.operator("uv.op_select_bake_type", text = "", icon_value = icon_get("bake_obj_float")).select_type = 'float'
if count_types['cage'] > 0:
row.operator("uv.op_select_bake_type", text = "", icon_value = icon_get("bake_obj_cage")).select_type = 'cage'
# List bake sets
box2 = box.box()
row = box2.row()
split = None
countTypes = (0 if count_types['low'] == 0 else 1) + (0 if count_types['high'] == 0 else 1) + (0 if count_types['cage'] == 0 else 1) + (0 if count_types['float'] == 0 else 1)
if countTypes > 2:
# More than 3 types, use less space for label
split = row.split(factor=0.45)
else:
# Only 2 or less types, use more space for label
split = row.split(factor=0.55)
c = split.column(align=True)
for s in range(0, len(settings.sets)):
set = settings.sets[s]
r = c.row(align=True)
r.active = not (bpy.context.scene.texToolsSettings.bake_force_single and s > 0)
if set.has_issues:
r.operator("uv.op_select_bake_set", text=set.name, icon='ERROR').select_set = set.name
else:
r.operator("uv.op_select_bake_set", text=set.name).select_set = set.name
c = split.column(align=True)
for set in settings.sets:
r = c.row(align=True)
r.alignment = "LEFT"
if len(set.objects_low) > 0:
r.label(text="{}".format(len(set.objects_low)), icon_value = icon_get("bake_obj_low"))
elif count_types['low'] > 0:
r.label(text="")
if len(set.objects_high) > 0:
r.label(text="{}".format(len(set.objects_high)), icon_value = icon_get("bake_obj_high"))
elif count_types['high'] > 0:
r.label(text="")
if len(set.objects_float) > 0:
r.label(text="{}".format(len(set.objects_float)), icon_value = icon_get("bake_obj_float"))
elif count_types['float'] > 0:
r.label(text="")
if len(set.objects_cage) > 0:
r.label(text="{}".format(len(set.objects_cage)), icon_value = icon_get("bake_obj_cage"))
elif count_types['cage'] > 0:
r.label(text="")
# Force Single
row = box2.row(align=True)
row.active = len(settings.sets) > 0
row.prop(context.scene.texToolsSettings, "bake_force_single", text="Single Texture")
if len(settings.sets) > 0 and bpy.context.scene.texToolsSettings.bake_force_single:
row.label(text="'{}'".format(settings.sets[0].name))
# else:
# row.label(text="")
col = box.column(align=True)
col.operator(op_bake_organize_names.op.bl_idname, text = "Organize {}x".format(len(bpy.context.selected_objects)), icon = 'BOOKMARKS')
col.operator(op_bake_explode.op.bl_idname, text = "Explode", icon_value = icon_get("op_bake_explode"));
class UI_MT_op_color_dropdown_io(bpy.types.Menu):
bl_idname = "UI_MT_op_color_dropdown_io"
bl_label = "IO"
def draw(self, context):
layout = self.layout
layout.operator(op_color_io_export.op.bl_idname, text="Export Colors", icon = 'EXPORT')
layout.operator(op_color_io_import.op.bl_idname, text="Import Colors", icon = 'IMPORT')
class UI_MT_op_color_dropdown_convert_from(bpy.types.Menu):
bl_idname = "UI_MT_op_color_dropdown_convert_from"
bl_label = "From"
bl_description = "Create Color IDs from ..."
def draw(self, context):
layout = self.layout
layout.operator(op_color_from_elements.op.bl_idname, text="Mesh Elements", icon_value = icon_get('op_color_from_elements'))
layout.operator(op_color_from_materials.op.bl_idname, text="Materials", icon_value = icon_get('op_color_from_materials'))
layout.operator(op_color_from_directions.op.bl_idname, text="Directions", icon_value = icon_get('op_color_from_directions'))
class UI_MT_op_color_dropdown_convert_to(bpy.types.Menu):
bl_idname = "UI_MT_op_color_dropdown_convert_to"
bl_label = "To"
bl_description = "Convert Color IDs into ..."
def draw(self, context):
layout = self.layout
layout.operator(op_color_convert_texture.op.bl_idname, text="Texture Atlas", icon_value = icon_get('op_color_convert_texture'))
layout.operator(op_color_convert_vertex_colors.op.bl_idname, text="Vertex Colors", icon_value = icon_get("op_color_convert_vertex_colors"))
class UV_OT_op_enable_cycles(bpy.types.Operator):
bl_idname = "uv.textools_enable_cycles"
bl_label = "Enable Cycles"
bl_description = "Enable Cycles render engine"
@classmethod
def poll(cls, context):
return True
def execute(self, context):
bpy.context.scene.render.engine = 'CYCLES'
return {'FINISHED'}
class UI_PT_Panel_Colors(bpy.types.Panel):
bl_label = " "
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_category = "TexTools"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, _):
layout = self.layout
row = layout.row(align=True)
row.operator("wm.url_open", text="", icon='INFO').url = "http://renderhjs.net/textools/blender/index.html#colorid"
row.label(text ="Color ID")
def draw(self, context):
layout = self.layout
# layout.label(text="Select face and color")
if bpy.context.scene.render.engine != 'CYCLES' and bpy.context.scene.render.engine != 'BLENDER_EEVEE':
row = layout.row(align=True)
row.alert = True
row.operator("uv.op_enable_cycles", text="Enable 'CYCLES'", icon='CANCEL')#, icon='UV_SYNC_SELECT'
return
box = layout.box()
col = box.column(align=True)
row = col.row(align=True)
split = row.split(factor=0.60, align=True)
c = split.column(align=True)
c.prop(context.scene.texToolsSettings, "color_ID_templates", text="")
c = split.column(align=True)
c.prop(context.scene.texToolsSettings, "color_ID_count", text="", expand=False)
row = box.row(align=True)
row.operator(op_color_clear.op.bl_idname, text="Clear", icon = 'X')
row.menu(UI_MT_op_color_dropdown_io.bl_idname, icon='COLOR')
max_columns = 5
if context.scene.texToolsSettings.color_ID_count < max_columns:
max_columns = context.scene.texToolsSettings.color_ID_count
count = math.ceil(context.scene.texToolsSettings.color_ID_count / max_columns)*max_columns
for i in range(count):
if i%max_columns == 0:
row = box.row(align=True)
col = row.column(align=True)
if i < context.scene.texToolsSettings.color_ID_count:
col.prop(context.scene.texToolsSettings, "color_ID_color_{}".format(i), text="")
col.operator(op_color_assign.op.bl_idname, text="", icon = "FILE_TICK").index = i
if bpy.context.active_object:
if bpy.context.active_object in bpy.context.selected_objects:
if len(bpy.context.selected_objects) == 1:
if bpy.context.active_object.type == 'MESH':
col.operator(op_color_select.op.bl_idname, text="", icon = "FACESEL").index = i
else:
col.label(text=" ")
# split = row.split(percentage=0.25, align=True)
# c = split.column(align=True)
# c.operator(op_color_clear.op.bl_idname, text="", icon = 'X')
# c = split.column(align=True)
# c.operator(op_color_from_elements.op.bl_idname, text="Color Elements", icon_value = icon_get('op_color_from_elements'))
col = box.column(align=True)
col.label(text="Convert")
row = col.row(align=True)
row.menu(UI_MT_op_color_dropdown_convert_from.bl_idname)#, icon='IMPORT'
row.menu(UI_MT_op_color_dropdown_convert_to.bl_idname,)# icon='EXPORT'
# row = col.row(align=True)
# row.operator(op_color_convert_texture.op.bl_idname, text="From Atlas", icon_value = icon_get('op_color_convert_texture'))
# for i in range(context.scene.texToolsSettings.color_ID_count):
# col = row.column(align=True)
# col.prop(context.scene.texToolsSettings, "color_ID_color_{}".format(i), text="")
# col.operator(op_color_assign.op.bl_idname, text="", icon = "FILE_TICK").index = i
# if bpy.context.active_object:
# if bpy.context.active_object.type == 'MESH':
# if bpy.context.active_object.mode == 'EDIT':
# col.operator(op_color_select.op.bl_idname, text="", icon = "FACESEL").index = i
# https://github.com/blenderskool/kaleidoscope/blob/fb5cb1ab87a57b46618d99afaf4d3154ad934529/spectrum.py
class UI_PT_Panel_MeshTexture(bpy.types.Panel):
bl_label = " "
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_category = "TexTools"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, _):
layout = self.layout
row = layout.row(align=True)
row.operator("wm.url_open", text="", icon='INFO').url = "http://renderhjs.net/textools/blender/index.html#meshtexture"
row.label(text ="Mesh Texture")
def draw(self, context):
layout = self.layout
box = layout.box()
col = box.column(align=True)
row = col.row(align=True)
row.scale_y = 1.5
row.operator(op_meshtex_create.op.bl_idname, text="Create UV Mesh", icon_value = icon_get("op_meshtex_create"))
row = col.row(align=True)
row.operator(op_meshtex_trim.op.bl_idname, text="Trim", icon_value = icon_get("op_meshtex_trim"))
# Warning about trimmed mesh
if op_meshtex_trim_collapse.is_available():
row.operator(op_meshtex_trim_collapse.op.bl_idname, text="Collapse Trim", icon_value=icon_get("op_meshtex_trim_collapse"))
col = box.column(align=True)
row = col.row(align = True)
row.operator(op_meshtex_wrap.op.bl_idname, text="Wrap", icon_value = icon_get("op_meshtex_wrap"))
row = col.row(align = True)
if not utilities_meshtex.find_uv_mesh(bpy.context.selected_objects):
row.enabled = False
row.prop(context.scene.texToolsSettings, "meshtexture_wrap", text="Wrap")
box.operator(op_meshtex_pattern.op.bl_idname, text="Create Pattern", icon_value = icon_get("op_meshtex_pattern"))
keymaps = []
def icon_get(name):
return utilities_ui.icon_get(name)
def menu_IMAGE_uvs(self, context):
layout = self.layout
layout.separator()
layout.operator(op_uv_resize.op.bl_idname, text="Resize", icon_value = icon_get("op_extend_canvas_open"))
layout.operator(op_rectify.op.bl_idname, text="Rectify", icon_value = icon_get("op_rectify"))
layout.operator(op_uv_crop.op.bl_idname, text="Crop", icon_value = icon_get("op_uv_crop"))
layout.operator(op_uv_fill.op.bl_idname, text="Crop", icon_value = icon_get("op_uv_fill"))
layout.separator()
layout.operator(op_island_align_sort.op.bl_idname, text="Sort H", icon_value = icon_get("op_island_align_sort_h"))
layout.operator(op_island_align_sort.op.bl_idname, text="Sort V", icon_value = icon_get("op_island_align_sort_v"))
layout.separator()
layout.operator(op_island_align_edge.op.bl_idname, text="Align Edge", icon_value = icon_get("op_island_align_edge"))
layout.operator(op_island_align_world.op.bl_idname, text="Align World", icon_value = icon_get("op_island_align_world"))
layout.menu(VIEW3D_MT_submenu_align)
class VIEW3D_MT_submenu_align(bpy.types.Menu):
bl_label="Align"
bl_idname="VIEW3D_MT_submenu_align"
def draw(self, context):
layout = self.layout
layout.operator(op_align.op.bl_idname, text="", icon_value = icon_get("op_align_left")).direction = "left"
layout.operator(op_align.op.bl_idname, text="", icon_value = icon_get("op_align_top")).direction = "top"
layout.operator(op_align.op.bl_idname, text="", icon_value = icon_get("op_align_bottom")).direction = "bottom"
layout.operator(op_align.op.bl_idname, text="", icon_value = icon_get("op_align_right")).direction = "right"
def menu_IMAGE_select(self, context):
layout = self.layout
layout.separator()
layout.operator(op_select_islands_identical.op.bl_idname, text="Similar", icon_value = icon_get("op_select_islands_identical"))
layout.operator(op_select_islands_overlap.op.bl_idname, text="Overlap", icon_value = icon_get("op_select_islands_overlap"))
layout.operator(op_select_islands_outline.op.bl_idname, text="Bounds", icon_value = icon_get("op_select_islands_outline"))
layout.operator(op_select_islands_flipped.op.bl_idname, text="Flipped", icon_value = icon_get('op_select_islands_flipped'))
def menu_IMAGE_MT_image(self, context):
layout = self.layout
layout.separator()
layout.operator(op_texture_reload_all.op.bl_idname, text="Reload Textures", icon_value = icon_get("op_texture_reload_all"))
layout.operator(op_texel_checker_map.op.bl_idname, text ="Checker Map", icon_value = icon_get("op_texel_checker_map"))
layout.operator(op_texture_preview.op.bl_idname, text = "Preview Texture", icon_value = icon_get("op_texture_preview"));
def menu_VIEW3D_MT_object(self, context):
self.layout.separator()
self.layout.operator(op_texel_checker_map.op.bl_idname, text ="Checker Map", icon_value = icon_get("op_texel_checker_map"))
self.layout.operator(op_meshtex_create.op.bl_idname, text="Create UV Mesh", icon_value = icon_get("op_meshtex_create"))
def menu_VIEW3D_MT_mesh_add(self, context):
self.layout.operator(op_meshtex_pattern.op.bl_idname, text="Create Pattern", icon_value = icon_get("op_meshtex_pattern"))
def menu_VIEW3D_MT_uv_map(self, context):
layout = self.layout
layout.separator()
layout.operator(op_unwrap_edge_peel.op.bl_idname, text="Peel Edge", icon_value = icon_get("op_unwrap_edge_peel"))
layout.operator(op_unwrap_faces_iron.op.bl_idname, text="Iron Faces", icon_value = icon_get("op_unwrap_faces_iron"))
layout.operator(op_smoothing_uv_islands.op.bl_idname, text="UV Smoothing", icon_value = icon_get("op_smoothing_uv_islands"))
def menu_VIEW3D_MT_object_context_menu(self, context):
layout = self.layout
layout.separator()
layout.operator(op_meshtex_create.op.bl_idname, text="Create UV Mesh", icon_value = icon_get("op_meshtex_create"))
layout.operator(op_meshtex_trim.op.bl_idname, text="Trim", icon_value = icon_get("op_meshtex_trim"))
# Warning about trimmed mesh
if op_meshtex_trim_collapse.is_available():
layout.operator(op_meshtex_trim_collapse.op.bl_idname, text="Collapse Trim", icon='CANCEL')
layout.prop(context.scene.texToolsSettings, "meshtexture_wrap", text="Wrap")
layout.operator(op_meshtex_wrap.op.bl_idname, text="Wrap", icon_value = icon_get("op_meshtex_wrap"))
classes = (
UV_OT_op_debug,
UV_OT_op_disable_uv_sync,
UV_OT_op_select_bake_set,
UV_OT_op_select_bake_type,
TexToolsSettings,
UI_PT_Panel_Units,
UI_PT_Panel_Layout,
UI_PT_Panel_Bake,
UI_MT_op_color_dropdown_io,
UI_MT_op_color_dropdown_convert_from,
UI_MT_op_color_dropdown_convert_to,
UV_OT_op_enable_cycles,
UI_PT_Panel_Colors,
UI_PT_Panel_MeshTexture,
VIEW3D_MT_submenu_align,
Panel_Preferences
)
def register():
from bpy.utils import register_class
for cls in classes:
register_class(cls)
#Register settings
bpy.types.Scene.texToolsSettings = bpy.props.PointerProperty(type=TexToolsSettings)
#GUI Utilities
utilities_ui.register()
# Register Icons
icons = [
"bake_anti_alias.png",
"bake_obj_cage.png",
"bake_obj_float.png",
"bake_obj_high.png",
"bake_obj_low.png",
"op_align_bottom.png",
"op_align_left.png",
"op_align_right.png",
"op_align_top.png",
"op_bake.png",
"op_bake_explode.png",
"op_color_convert_texture.png",
"op_color_convert_vertex_colors.png",
"op_color_from_directions.png",
"op_color_from_elements.png",
"op_color_from_materials.png",
"op_extend_canvas_open.png",
"op_island_align_edge.png",
"op_island_align_sort_h.png",
"op_island_align_sort_v.png",
"op_island_align_world.png",
"op_island_mirror.png",
"op_island_rotate_90_left.png",
"op_island_rotate_90_right.png",
"op_island_straighten_edge_loops.png",
"op_meshtex_create.png",
"op_meshtex_pattern.png",
"op_meshtex_trim.png",
"op_meshtex_trim_collapse.png",
"op_meshtex_wrap.png",
"op_rectify.png",
"op_select_islands_flipped.png",
"op_select_islands_identical.png",
"op_select_islands_outline.png",
"op_select_islands_overlap.png",
"op_smoothing_uv_islands.png",
"op_texel_checker_map.png",
"op_texture_preview.png",
"op_texture_reload_all.png",
"op_texture_save.png",
"op_texture_open.png",
"op_unwrap_faces_iron.png",
"op_unwrap_edge_peel.png",
"op_uv_crop.png",
"op_uv_fill.png",
"texel_density.png"
]
for icon in icons:
utilities_ui.icon_register(icon)
bpy.types.IMAGE_MT_uvs.append(menu_IMAGE_uvs)
bpy.types.IMAGE_MT_select.append(menu_IMAGE_select)
bpy.types.IMAGE_MT_image.append(menu_IMAGE_MT_image)
bpy.types.VIEW3D_MT_object.append(menu_VIEW3D_MT_object)
bpy.types.VIEW3D_MT_add.append(menu_VIEW3D_MT_mesh_add)
bpy.types.VIEW3D_MT_uv_map.append(menu_VIEW3D_MT_uv_map)
bpy.types.VIEW3D_MT_object_context_menu.append(menu_VIEW3D_MT_object_context_menu)
from bpy.utils import unregister_class
for cls in reversed(classes):
unregister_class(cls)
#Unregister Icons
utilities_ui.icon_unregister()
#Unregister Settings
del bpy.types.Scene.texToolsSettings
#handle the keymap
for km, kmi in keymaps:
km.keymap_items.remove(kmi)
keymaps.clear()
#GUI Utilities
utilities_ui.unregister()
bpy.types.IMAGE_MT_uvs.remove(menu_IMAGE_uvs)
bpy.types.IMAGE_MT_select.remove(menu_IMAGE_select)
bpy.types.IMAGE_MT_image.remove(menu_IMAGE_MT_image)
bpy.types.VIEW3D_MT_object.remove(menu_VIEW3D_MT_object)
bpy.types.VIEW3D_MT_add.remove(menu_VIEW3D_MT_mesh_add)
bpy.types.VIEW3D_MT_uv_map.remove(menu_VIEW3D_MT_uv_map)
bpy.types.VIEW3D_MT_object_context_menu.remove(menu_VIEW3D_MT_object_context_menu)
if __name__ == "__main__":
register()