forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			392 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			392 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import bpy
 | 
						|
import blf
 | 
						|
import gpu
 | 
						|
from mathutils import Vector
 | 
						|
from gpu_extras.batch import batch_for_shader
 | 
						|
from gpu_extras.presets import *
 | 
						|
from math import pi, cos, sin
 | 
						|
 | 
						|
if bpy.app.version < (4, 0, 0):
 | 
						|
    uniform_color = '2D_UNIFORM_COLOR'
 | 
						|
else:
 | 
						|
    uniform_color = 'UNIFORM_COLOR'
 | 
						|
 | 
						|
def getDpiFactor():
 | 
						|
    return getDpi() / 72
 | 
						|
 | 
						|
def getDpi():
 | 
						|
    systemPreferences = bpy.context.preferences.system
 | 
						|
    retinaFactor = getattr(systemPreferences, "pixel_size", 1)
 | 
						|
    return systemPreferences.dpi * retinaFactor
 | 
						|
 | 
						|
def getNodeBottomCornerLocations(node):
 | 
						|
    region = bpy.context.region
 | 
						|
    dpiFactor = getDpiFactor()
 | 
						|
    location = node.getViewLocation() * dpiFactor
 | 
						|
    dimensions = node.dimensions
 | 
						|
    x = location.x
 | 
						|
    y = location.y - dimensions.y
 | 
						|
 | 
						|
    viewToRegion = region.view2d.view_to_region
 | 
						|
    leftBottom = Vector(viewToRegion(x, y, clip = False))
 | 
						|
    rightBottom = Vector(viewToRegion(x + dimensions.x, y, clip = False))
 | 
						|
    return leftBottom, rightBottom
 | 
						|
 | 
						|
class BlendSpaceGUI:
 | 
						|
    def __init__(self, node):
 | 
						|
        self.boundary = RectangleWithGrid()
 | 
						|
        self.points = Points([])
 | 
						|
        self.node = node
 | 
						|
 | 
						|
    def calculateBoundaries(self):
 | 
						|
        dpiFactor = getDpiFactor()
 | 
						|
        location = self.node.getViewLocation() * dpiFactor
 | 
						|
        dimensions = self.node.dimensions
 | 
						|
        x1 = location.x
 | 
						|
        x2 = x1 + dimensions.x
 | 
						|
        y1 = location.y - dimensions.y
 | 
						|
        y2 = y1 - (x2 - x1)
 | 
						|
 | 
						|
        self.boundary.resetPosition(x1, y1, x2, y2)
 | 
						|
 | 
						|
    def getHeight(self):
 | 
						|
        return self.boundary.height
 | 
						|
    
 | 
						|
    def setPointSize(self):
 | 
						|
        self.node.point_size = self.points.point_size
 | 
						|
    
 | 
						|
    def setGUIBounds(self):
 | 
						|
        self.node.gui_bounds = [self.boundary.x1 + self.boundary.offsetInner, self.boundary.y1 - self.boundary.offsetInner, self.boundary.widthInner]
 | 
						|
 | 
						|
    def draw(self):
 | 
						|
        self.calculateBoundaries()
 | 
						|
        self.boundary.draw()
 | 
						|
        self.points.calcPoints(self.node.property0, self.node.property1, self.boundary.x1 + self.boundary.offsetInner, self.boundary.y1 - self.boundary.offsetInner, self.boundary.widthInner, self.node.show_numbers)
 | 
						|
        self.setGUIBounds()
 | 
						|
        self.setPointSize()
 | 
						|
        self.points.drawPointCirc()
 | 
						|
 | 
						|
class Rectangle:
 | 
						|
    def __init__(self, x1 = 0, y1 = 0, x2 = 0, y2 = 0):
 | 
						|
        self.resetPosition(x1, y1, x2, y2)
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def fromRegionDimensions(cls, region):
 | 
						|
        return cls(0, 0, region.width, region.height)
 | 
						|
 | 
						|
    def resetPosition(self, x1 = 0, y1 = 0, x2 = 0, y2 = 0):
 | 
						|
        self.x1 = float(x1)
 | 
						|
        self.y1 =  float(y1)
 | 
						|
        self.x2 =  float(x2)
 | 
						|
        self.y2 =  float(y2)
 | 
						|
 | 
						|
    def copy(self):
 | 
						|
        return Rectangle(self.x1, self.y1, self.x2, self.y2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def width(self):
 | 
						|
        return abs(self.x1 - self.x2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def height(self):
 | 
						|
        return abs(self.y1 - self.y2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def left(self):
 | 
						|
        return min(self.x1, self.x2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def right(self):
 | 
						|
        return max(self.x1, self.x2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def top(self):
 | 
						|
        return max(self.y1, self.y2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def bottom(self):
 | 
						|
        return min(self.y1, self.y2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def center(self):
 | 
						|
        return Vector((self.centerX, self.centerY))
 | 
						|
 | 
						|
    @property
 | 
						|
    def centerX(self):
 | 
						|
        return (self.x1 + self.x2) / 2
 | 
						|
 | 
						|
    @property
 | 
						|
    def centerY(self):
 | 
						|
        return (self.y1 + self.y2) / 2
 | 
						|
 | 
						|
    def getInsetRectangle(self, amount):
 | 
						|
        return Rectangle(self.left + amount, self.top - amount, self.right - amount, self.bottom + amount)
 | 
						|
 | 
						|
    def contains(self, point):
 | 
						|
        return self.left <= point[0] <= self.right and self.bottom <= point[1] <= self.top
 | 
						|
 | 
						|
    def draw(self, color = (0.8, 0.8, 0.8, 1.0), borderColor = (0.1, 0.1, 0.1, 1.0), borderThickness = 0):
 | 
						|
        locations = (
 | 
						|
            (self.x1, self.y1),
 | 
						|
            (self.x2, self.y1),
 | 
						|
            (self.x1, self.y2),
 | 
						|
            (self.x2, self.y2))
 | 
						|
        shader = gpu.shader.from_builtin(uniform_color)
 | 
						|
        batch = batch_for_shader(shader, 'TRI_STRIP', {"pos": locations})
 | 
						|
 | 
						|
        shader.bind()
 | 
						|
        shader.uniform_float("color", color)
 | 
						|
 | 
						|
        batch.draw(shader)
 | 
						|
 | 
						|
 | 
						|
        if borderThickness == 0: return
 | 
						|
 | 
						|
        offset = borderThickness // 2
 | 
						|
        bWidth = offset * 2 if borderThickness > 0 else 0
 | 
						|
        borderLocations = (
 | 
						|
            (self.x1 - bWidth, self.y1 + offset), (self.x2 + bWidth, self.y1 + offset),
 | 
						|
            (self.x2 + offset, self.y1 + bWidth), (self.x2 + offset, self.y2 - bWidth),
 | 
						|
            (self.x2 + bWidth, self.y2 - offset), (self.x1 - bWidth, self.y2 - offset),
 | 
						|
            (self.x1 - offset, self.y2 - bWidth), (self.x1 - offset, self.y1 + bWidth))
 | 
						|
        batch = batch_for_shader(shader, 'LINES',{"pos": borderLocations})
 | 
						|
 | 
						|
        shader.bind()
 | 
						|
        shader.uniform_float("color", borderColor)
 | 
						|
        gpu.state.line_width_set(abs(borderThickness))
 | 
						|
 | 
						|
        batch.draw(shader)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "({}, {}) - ({}, {})".format(self.x1, self.y1, self.x2, self.y2)
 | 
						|
 | 
						|
class Points:
 | 
						|
 | 
						|
    def __init__(self, points = []):
 | 
						|
        self.points = points
 | 
						|
        self.point_size = 0.025
 | 
						|
        self.width = 0.0
 | 
						|
        self.colors = [ (0.4, 0.5, 0.9, 1.0),
 | 
						|
                        (1.0, 0.0, 1.0, 1.0),
 | 
						|
                        (0.0, 1.0, 1.0, 1.0),
 | 
						|
                        (1.0, 1.0, 0.0, 1.0),
 | 
						|
                        (0.0, 0.0, 1.0, 1.0),
 | 
						|
                        (0.0, 1.0, 0.0, 1.0),
 | 
						|
                        (1.0, 0.0, 0.0, 1.0),
 | 
						|
                        (0.8, 0.6, 1.0, 1.0),
 | 
						|
                        (0.6, 0.8, 1.0, 1.0),
 | 
						|
                        (1.0, 0.6, 0.8, 1.0), 
 | 
						|
                        (1.0, 1.0, 1.0, 1.0)]
 | 
						|
        self.circle_coords = self.circle(0.0, 0.0, self.point_size, 4)
 | 
						|
        self.square_coord = self.circle(0.0, 0.0, self.point_size, 5)
 | 
						|
        self.visible = []
 | 
						|
        self.show_numbers = False
 | 
						|
    
 | 
						|
    def get_points_list(self):
 | 
						|
        p = []
 | 
						|
        for p1 in self.points:
 | 
						|
            for p2 in p1:
 | 
						|
                p.append(p2)
 | 
						|
        
 | 
						|
        return p
 | 
						|
 | 
						|
    def calcPoints(self, points, visible, x1, y1, width, show_numbers):
 | 
						|
        self.width = width
 | 
						|
        self.points = []
 | 
						|
        self.visible = visible
 | 
						|
        self.show_numbers = show_numbers
 | 
						|
 | 
						|
        for i in range(len(points) // 2):
 | 
						|
            point = []
 | 
						|
            point.append(x1 + width * points[i * 2])
 | 
						|
            point.append(y1 - width + width * points[i * 2 + 1])
 | 
						|
            self.points.append(point)
 | 
						|
 | 
						|
    def reset_circle(self, point):
 | 
						|
        new_coords = []
 | 
						|
        for coord in self.circle_coords:
 | 
						|
            x = coord[0] * self.width + point[0]
 | 
						|
            y = coord[1] * self.width + point[1]
 | 
						|
            new_coords.append((x, y))
 | 
						|
        return new_coords
 | 
						|
    
 | 
						|
    def reset_square(self, point):
 | 
						|
        new_coords = []
 | 
						|
        for coord in self.square_coord:
 | 
						|
            x = coord[0] * self.width + point[0]
 | 
						|
            y = coord[1] * self.width + point[1]
 | 
						|
            new_coords.append((x, y))
 | 
						|
        return new_coords
 | 
						|
    
 | 
						|
    def circle(self, x, y, radius, segments):
 | 
						|
        coords = []
 | 
						|
        m = (1.0 / (segments - 1)) * (pi * 2)
 | 
						|
 | 
						|
        for p in range(segments):
 | 
						|
            p1 = x + cos(m * p) * radius
 | 
						|
            p2 = y + sin(m * p) * radius
 | 
						|
            coords.append((p1, p2))
 | 
						|
        return coords
 | 
						|
    
 | 
						|
    def drawPointCirc(self):
 | 
						|
        shader = gpu.shader.from_builtin(uniform_color)
 | 
						|
        for i in range(len(self.points) - 1):
 | 
						|
            if(self.visible[i]):
 | 
						|
                pos = self.points[i]
 | 
						|
                circle_co = self.reset_circle(pos)
 | 
						|
                batch = batch_for_shader(shader, 'TRI_FAN',{"pos": circle_co})
 | 
						|
                shader.bind()
 | 
						|
                col = self.colors[i]
 | 
						|
                shader.uniform_float("color", col)
 | 
						|
                batch.draw(shader)
 | 
						|
                if self.show_numbers:
 | 
						|
                    blf.color(0, col[0], col[1], col[2], col[3])
 | 
						|
                    blf.size(0, self.width/10, int(getDpi()))
 | 
						|
                    blf.position(0, pos[0], pos[1], 0)
 | 
						|
                    blf.draw(0, str(i + 1))
 | 
						|
        square_co = self.reset_square(self.points[len(self.points) - 1])
 | 
						|
        batch = batch_for_shader(shader, 'TRI_FAN',{"pos": square_co})
 | 
						|
        shader.bind()
 | 
						|
        shader.uniform_float("color", self.colors[len(self.points) - 1])
 | 
						|
        batch.draw(shader)
 | 
						|
        
 | 
						|
 | 
						|
    
 | 
						|
class RectangleWithGrid:
 | 
						|
    def __init__(self, x1 = 0, y1 = 0, x2 = 0, y2 = 0):
 | 
						|
        self.resetPosition(x1, y1, x2, y2)
 | 
						|
        self.numGrids = 21
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def fromRegionDimensions(cls, region):
 | 
						|
        return cls(0, 0, region.width, region.height)
 | 
						|
 | 
						|
    def resetPosition(self, x1 = 0, y1 = 0, x2 = 0, y2 = 0):
 | 
						|
        self.x1 = float(x1)
 | 
						|
        self.y1 =  float(y1)
 | 
						|
        self.x2 =  float(x2)
 | 
						|
        self.y2 =  float(y2)
 | 
						|
 | 
						|
    def copy(self):
 | 
						|
        return Rectangle(self.x1, self.y1, self.x2, self.y2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def width(self):
 | 
						|
        return abs(self.x1 - self.x2)
 | 
						|
    
 | 
						|
    @property
 | 
						|
    def widthInner(self):
 | 
						|
        return abs(self.width - (2 * self.width/self.numGrids))
 | 
						|
 | 
						|
    @property
 | 
						|
    def offsetInner(self):
 | 
						|
        return abs(self.width/self.numGrids)
 | 
						|
 | 
						|
 | 
						|
    @property
 | 
						|
    def height(self):
 | 
						|
        return abs(self.y1 - self.y2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def left(self):
 | 
						|
        return min(self.x1, self.x2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def right(self):
 | 
						|
        return max(self.x1, self.x2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def top(self):
 | 
						|
        return max(self.y1, self.y2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def bottom(self):
 | 
						|
        return min(self.y1, self.y2)
 | 
						|
 | 
						|
    @property
 | 
						|
    def center(self):
 | 
						|
        return Vector((self.centerX, self.centerY))
 | 
						|
 | 
						|
    @property
 | 
						|
    def centerX(self):
 | 
						|
        return (self.x1 + self.x2) / 2
 | 
						|
 | 
						|
    @property
 | 
						|
    def centerY(self):
 | 
						|
        return (self.y1 + self.y2) / 2
 | 
						|
 | 
						|
    def getInsetRectangle(self, amount):
 | 
						|
        return Rectangle(self.left + amount, self.top - amount, self.right - amount, self.bottom + amount)
 | 
						|
 | 
						|
    def contains(self, point):
 | 
						|
        return self.left <= point[0] <= self.right and self.bottom <= point[1] <= self.top
 | 
						|
 | 
						|
    def draw(self, color = (0.5, 0.5, 0.5, 1.0), borderColor = (0.3, 0.3, 0.3, 1.0), gridColor = (0.5, 0.5, 0.5, 1.0), borderThickness = 3, gridLineThickness = 1):
 | 
						|
        locations = (
 | 
						|
            (self.x1, self.y1),
 | 
						|
            (self.x2, self.y1),
 | 
						|
            (self.x1, self.y2),
 | 
						|
            (self.x2, self.y2))
 | 
						|
        shader = gpu.shader.from_builtin(uniform_color)
 | 
						|
        batch = batch_for_shader(shader, 'TRI_STRIP', {"pos": locations})
 | 
						|
 | 
						|
        shader.bind()
 | 
						|
        shader.uniform_float("color", color)
 | 
						|
 | 
						|
        batch.draw(shader)
 | 
						|
 | 
						|
        locations = (
 | 
						|
            (self.x1 + self.width/self.numGrids, self.y1 - self.height/self.numGrids),
 | 
						|
            (self.x2 - self.width/self.numGrids, self.y1 - self.height/self.numGrids),
 | 
						|
            (self.x1 + self.width/self.numGrids, self.y2 + self.height/self.numGrids),
 | 
						|
            (self.x2 - self.width/self.numGrids, self.y2 + self.height/self.numGrids))
 | 
						|
        shader = gpu.shader.from_builtin(uniform_color)
 | 
						|
        batch = batch_for_shader(shader, 'TRI_STRIP', {"pos": locations})
 | 
						|
 | 
						|
        shader.bind()
 | 
						|
        shader.uniform_float("color", borderColor)
 | 
						|
 | 
						|
        batch.draw(shader)
 | 
						|
 | 
						|
        if borderThickness == 0: return
 | 
						|
 | 
						|
        offset = borderThickness // 2
 | 
						|
        borderLocations = (
 | 
						|
            (self.x1, self.y1), (self.x2, self.y1),
 | 
						|
            (self.x2, self.y1), (self.x2, self.y2),
 | 
						|
            (self.x2, self.y2), (self.x1, self.y2),
 | 
						|
            (self.x1, self.y2), (self.x1, self.y1),
 | 
						|
            (self.centerX, self.y1), (self.centerX, self.y2),
 | 
						|
            (self.x1, self.centerY), (self.x2, self.centerY))
 | 
						|
        batch = batch_for_shader(shader, 'LINES',{"pos": borderLocations})
 | 
						|
 | 
						|
        shader.bind()
 | 
						|
        shader.uniform_float("color", gridColor)
 | 
						|
        gpu.state.line_width_set(abs(borderThickness))
 | 
						|
 | 
						|
        batch.draw(shader)
 | 
						|
 | 
						|
        offset = (self.x2 - self.x1) / (self.numGrids + 1)
 | 
						|
        gridPoints = []
 | 
						|
        for l in range(21):
 | 
						|
            p1 = (self.x1 + (offset * (l + 1)), self.y1)
 | 
						|
            p2 = (self.x1 + (offset * (l + 1)), self.y2)
 | 
						|
            gridPoints.append(p1)
 | 
						|
            gridPoints.append(p2)
 | 
						|
        for l in range(21):
 | 
						|
            p1 = (self.x1, self.y1 - (offset * (l + 1)))
 | 
						|
            p2 = (self.x2, self.y1 - (offset * (l + 1)))
 | 
						|
            gridPoints.append(p1)
 | 
						|
            gridPoints.append(p2)
 | 
						|
        
 | 
						|
        batch = batch_for_shader(shader, 'LINES',{"pos": gridPoints})
 | 
						|
 | 
						|
        shader.bind()
 | 
						|
        shader.uniform_float("color", gridColor)
 | 
						|
        gpu.state.line_width_set(abs(gridLineThickness))
 | 
						|
 | 
						|
        batch.draw(shader)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "({}, {}) - ({}, {})".format(self.x1, self.y1, self.x2, self.y2)
 |