167 lines
5.0 KiB
Python
167 lines
5.0 KiB
Python
|
'''
|
||
|
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 <http://www.gnu.org/licenses/>.
|
||
|
'''
|
||
|
|
||
|
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()
|