''' Copyright (C) 2021 - 2023 Akaneyu This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ''' import sys import os import ctypes import math import bpy import bpy.utils.previews import blf import numpy as np from . ui_renderer import UIRenderer as UIRenderer from . import utils class Session: def __init__(self): self.icons = None self.ui_renderer = None self.draw_handler = None self.previous_object = None self.brush_position = None self.brush_size = 50.0 self.selecting_direction = False self.brush_active = False self.resizing_brush = False def get_session(): global session return session def draw_handler(): global session context = bpy.context wm = context.window_manager props = wm.symmetrizetexture_properties mirror_axis = props.image_mirror_axis info_text = None if not session.ui_renderer: session.ui_renderer = UIRenderer() # direction setup if session.selecting_direction: if mirror_axis == 'x_axis': border_pos1 = context.region.view2d.view_to_region(0.5, 0, clip=False) border_pos2 = context.region.view2d.view_to_region(0.5, 1.0, clip=False) else: border_pos1 = context.region.view2d.view_to_region(0, 0.5, clip=False) border_pos2 = context.region.view2d.view_to_region(1.0, 0.5, clip=False) session.ui_renderer.render_border(border_pos1, border_pos2) center = context.region.view2d.view_to_region(0.5, 0.5, clip=False) if mirror_axis == 'x_axis': arrow_angle = 0 if session.direction > 0 else np.pi else: arrow_angle = np.pi / 2.0 if session.direction > 0 else np.pi * 1.5 session.ui_renderer.render_arrow(center, arrow_angle) info_text = "LMB: Perform\n" \ + "RMB: Cancel" # brush if session.brush_active and session.brush_position: session.ui_renderer.render_brush_frame(session.brush_position, session.brush_size) info_text = "LMB: Perform\n" \ + "RMB: Finish\n" \ + "F: Change brush size" area_height = context.area.height # info text if info_text: blf.enable(0, blf.WORD_WRAP) blf.word_wrap(0, 200) blf.color(0, 1.0, 1.0, 1.0, 1.0) if bpy.context.area.type == 'VIEW_3D': blf.position(0, 85, area_height - 150, 0) else: blf.position(0, 85, area_height - 70, 0) blf.size(0, 14, 72) blf.draw(0, info_text) blf.disable(0, blf.WORD_WRAP) def load_icons(): global session script_dir = os.path.dirname(os.path.realpath(__file__)) icons = bpy.utils.previews.new() icons_dir = os.path.join(script_dir, "icons") for file_name in os.listdir(icons_dir): icon_name = os.path.splitext(file_name)[0] icons.load(icon_name, os.path.join(icons_dir, file_name), 'IMAGE') session.icons = icons def dispose_icons(): global session bpy.utils.previews.remove(session.icons) def load_native_library(): script_dir = os.path.dirname(os.path.realpath(__file__)) if os.name == 'nt': lib_file_name = 'symmetrize_texture.dll' else: lib_file_name = 'libsymmetrize_texture.so' lib = ctypes.CDLL(os.path.join(script_dir, lib_file_name)) return lib def unload_native_library(lib): if os.name == 'nt': kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) kernel32.FreeLibrary.argtypes = [ctypes.c_void_p] kernel32.FreeLibrary(lib._handle) else: stdlib = ctypes.CDLL("") stdlib.dlclose.argtypes = [ctypes.c_void_p] stdlib.dlclose(lib._handle) def get_image_previews(self, context): image_previews = [] for i, img in enumerate(bpy.data.images): image_previews.append((img.name, img.name, img.name, bpy.types.UILayout.icon(img), i)) return image_previews class SYMMETRIZE_TEXTURE_PropertyGroup(bpy.types.PropertyGroup): image_preview: bpy.props.EnumProperty(items=get_image_previews, options={'LIBRARY_EDITABLE'}) # created in the register(): image_mirror_axis brush_strength: bpy.props.FloatProperty(name='Strength', default=1.0, min=0, max=1.0, precision=3) brush_falloff: bpy.props.EnumProperty(items=( ('smooth', 'Smooth', 'Smooth', 'SMOOTHCURVE', 0), ('constant', 'Constant', 'Constant', 'NOCURVE', 1))) session = Session()