''' Copyright (C) 2023 CG Cookie http://cgcookie.com hello@cgcookie.com Created by Jonathan Denning, Jonathan Williamson 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 os import bpy import math import time import urllib import gpu from mathutils import Vector, Matrix from gpu_extras.presets import draw_texture_2d from ...addon_common.cookiecutter.cookiecutter import CookieCutter from ...addon_common.common import gpustate from ...addon_common.common.drawing import DrawCallbacks from ...addon_common.common.globals import Globals from ...addon_common.common.profiler import profiler from ...addon_common.common.debug import tprint from ...addon_common.common.fsm import FSM from ...addon_common.common.hasher import Hasher from ...addon_common.common.maths import Point, Point2D, Vec2D, XForm, clamp from ...addon_common.common.maths import matrix_normal, Direction from ...addon_common.terminal.term_printer import sprint from ...config.options import options, visualization class RetopoFlow_Drawing: def get_view_version(self): return Hasher(self.actions.r3d.view_matrix, self.actions.space.lens, self.actions.r3d.view_distance, self.actions.area.width, self.actions.area.height) def setup_drawing(self): def callback(): Globals.drawing.update_dpi() source_opts = visualization.get_source_settings() target_opts = visualization.get_target_settings() self.rftarget_draw.replace_opts(target_opts) # self.document.body.dirty(cause='--> options changed', children=True) for d in self.rfsources_draw: d.replace_opts(source_opts) options.add_callback(callback) self._draw_count = 0 @DrawCallbacks.on_predraw() def predraw(self): if not self.loading_done: return self.update(timer=False) self._draw_count += 1 def get_view_matrix(self): return self.actions.r3d.view_matrix def get_projection_matrix(self): return None # r3d = self.actions.r3d # if r3d.view_perspective == 'ORTHO': # xdelta = right - left # ydelta = top - bottom # zdelta = farclip - nearclip # return Matrix([ # [2 / xdelta, 0, 0, -(right + left) / xdelta], # [0, 2 / ydelta, 0, -(top + bottom) / ydelta], # [0, 0, -2 / zdelta, -(farclip + nearclip) / zdelta], # [0, 0, 0, 1], # ]) # else: # return # @DrawCallbacks.on_draw('post2d') def draw_selection_buffer(self): return if not self.scene.camera: return sprint(hasattr(self, '_gpuoffscreen')) if not hasattr(self, '_gpuoffscreen'): self._gpuoffscreen = gpu.types.GPUOffScreen(1, 1) #, format='RGBA8') self._gpuoffscreen_draw_count = -1 if not hasattr(self, '_draw_count'): # setup not fully complete yet! return if self._gpuoffscreen_draw_count == self._draw_count: return w, h = int(self.actions.size.x), int(self.actions.size.y) if self._gpuoffscreen.width != w or self._gpuoffscreen.height != h: sprint(f'RESIZING') self._gpuoffscreen.free() self._gpuoffscreen = gpu.types.GPUOffScreen(w, h) #, format='RGBA8') sprint(f'DRAWING GPUOFFSCREEN') self._gpuoffscreen_draw_count = self._draw_count print(self.scene.camera) print(self.scene.camera.matrix_world) view_mat = self.scene.camera.matrix_world.inverted_safe() depsgraph = self.context.view_layer.depsgraph # self.context.evaluated_depsgraph_get() proj_mat = self.scene.camera.calc_matrix_camera(depsgraph, x=w, y=h) print(view_mat) print(proj_mat) with self._gpuoffscreen.bind(): self._gpuoffscreen.draw_view3d( self.scene, # scene to draw self.view_layer, # view layer to draw self.actions.space, # 3D view to get the drawing settings from self.actions.region, # Region of the 3D view view_mat, # view matrix proj_mat, # projection matrix do_color_management=False, draw_background=False, ) gpustate.depth_mask(False) gpustate.blend('ALPHA') draw_texture_2d( self._gpuoffscreen.texture_color, (0, 0), w, h, ) @DrawCallbacks.on_draw('post3d') def draw_target_and_sources(self): if not self.actions.r3d: return if not self.loading_done: return # if self.fps_low_warning: return # skip drawing if low FPS warning is showing buf_matrix_target = self.rftarget_draw.rfmesh.xform.mx_p buf_matrix_target_inv = self.rftarget_draw.rfmesh.xform.imx_p buf_matrix_view = self.actions.r3d.view_matrix buf_matrix_view_invtrans = matrix_normal(self.actions.r3d.view_matrix) buf_matrix_proj = self.actions.r3d.window_matrix view_forward = self.Vec_forward() gpustate.blend('ALPHA') if options['symmetry view'] != 'None' and self.rftarget.mirror_mod.xyz: if options['symmetry view'] in {'Edge', 'Face'}: # get frame of target, used for symmetry decorations on sources ft = self.rftarget.get_frame() # render sources for rs,rfs in zip(self.rfsources, self.rfsources_draw): rfs.draw( view_forward, self.unit_scaling_factor, buf_matrix_target, buf_matrix_target_inv, buf_matrix_view, buf_matrix_view_invtrans, buf_matrix_proj, 1.00, 0.05, # alpha above, alpha below False, 0.5, # cull backfaces, alpha_backfaces False, # draw mirrored symmetry=self.rftarget.mirror_mod.xyz, symmetry_view=options['symmetry view'], symmetry_effect=options['symmetry effect'], symmetry_frame=ft, ) elif options['symmetry view'] == 'Plane': # draw symmetry planes gpustate.depth_test('LESS_EQUAL') gpustate.culling('NONE') drawing = Globals.drawing a = pow(options['symmetry effect'], 2.0) # fudge this value, because effect is different with plane than edge/face r = (1.0, 0.2, 0.2, a) g = (0.2, 1.0, 0.2, a) b = (0.2, 0.2, 1.0, a) w2l = self.rftarget_draw.rfmesh.xform.w2l_point l2w = self.rftarget_draw.rfmesh.xform.l2w_point # for rfs in self.rfsources: # corners = [self.Point_to_Point2D(l2w(p)) for p in rfs.get_local_bbox(w2l).corners] # drawing.draw2D_lines(corners, (1,1,1,1)) corners = [ c for s in self.rfsources for c in s.get_local_bbox(w2l).corners ] mx, Mx = min(c.x for c in corners), max(c.x for c in corners) my, My = min(c.y for c in corners), max(c.y for c in corners) mz, Mz = min(c.z for c in corners), max(c.z for c in corners) cx, cy, cz = mx + (Mx - mx) / 2, my + (My - my) / 2, mz + (Mz - mz) / 2 mx, Mx = cx + (mx - cx) * 1.2, cx + (Mx - cx) * 1.2 my, My = cy + (my - cy) * 1.2, cy + (My - cy) * 1.2 mz, Mz = cz + (mz - cz) * 1.2, cz + (Mz - cz) * 1.2 if self.rftarget.mirror_mod.x: quad = [ l2w(Point((0, my, mz))), l2w(Point((0, my, Mz))), l2w(Point((0, My, Mz))), l2w(Point((0, My, mz))) ] drawing.draw3D_triangles([quad[0], quad[1], quad[2], quad[0], quad[2], quad[3]], [r, r, r, r, r, r]) if self.rftarget.mirror_mod.y: quad = [ l2w(Point((mx, 0, mz))), l2w(Point((mx, 0, Mz))), l2w(Point((Mx, 0, Mz))), l2w(Point((Mx, 0, mz))) ] drawing.draw3D_triangles([quad[0], quad[1], quad[2], quad[0], quad[2], quad[3]], [g, g, g, g, g, g]) if self.rftarget.mirror_mod.z: quad = [ l2w(Point((mx, my, 0))), l2w(Point((mx, My, 0))), l2w(Point((Mx, My, 0))), l2w(Point((Mx, my, 0))) ] drawing.draw3D_triangles([quad[0], quad[1], quad[2], quad[0], quad[2], quad[3]], [b, b, b, b, b, b]) # render target gpustate.blend('ALPHA') if True: alpha_above,alpha_below = options['target alpha'],options['target hidden alpha'] cull_backfaces = options['target cull backfaces'] alpha_backface = options['target alpha backface'] self.rftarget_draw.draw( view_forward, self.unit_scaling_factor, buf_matrix_target, buf_matrix_target_inv, buf_matrix_view, buf_matrix_view_invtrans, buf_matrix_proj, alpha_above, alpha_below, cull_backfaces, alpha_backface, True, # draw_mirrored ) @DrawCallbacks.on_draw('post3d') def draw_greasemarks(self): return # if not self.actions.r3d: return # # THE FOLLOWING CODE NEEDS UPDATED TO NOT USE GLBEGIN! # # grease marks # b_g_l.glBegin(b_g_l.GL_QUADS) # for stroke_data in self.grease_marks: # b_g_l.glColor4f(*stroke_data['color']) # t = stroke_data['thickness'] # s0,p0,n0,d0,d1 = None,None,None,None,None # for s1 in stroke_data['marks']: # p1,n1 = s1 # if p0 and p1: # v01 = p1 - p0 # if d0 is None: d0 = Direction(v01.cross(n0)) # d1 = Direction(v01.cross(n1)) # b_g_l.glVertex3f(*(p0-d0*t+n0*0.001)) # b_g_l.glVertex3f(*(p0+d0*t+n0*0.001)) # b_g_l.glVertex3f(*(p1+d1*t+n1*0.001)) # b_g_l.glVertex3f(*(p1-d1*t+n1*0.001)) # s0,p0,n0,d0 = s1,p1,n1,d1 # b_g_l.glEnd() ################################## # RFTool Drawing @DrawCallbacks.on_draw('predraw') @FSM.onlyinstate({'main', 'quick switch'}) def tool_new_frame(self): if not self.loading_done: return # if self.fsm.state == 'pie menu': return self.rftool._new_frame() @DrawCallbacks.on_draw('pre3d') @FSM.onlyinstate({'main', 'quick switch'}) def draw_tool_pre3d(self): if not self.loading_done: return # if self.fsm.state == 'pie menu': return self.rftool._draw_pre3d() @DrawCallbacks.on_draw('post3d') @FSM.onlyinstate({'main', 'quick switch'}) def draw_tool_post3d(self): if not self.loading_done: return # if self.fsm.state == 'pie menu': return self.rftool._draw_post3d() @DrawCallbacks.on_draw('post2d') @FSM.onlyinstate({'main', 'quick switch'}) def draw_tool_post2d(self): if not self.loading_done: return # if self.fsm.state == 'pie menu': return self.rftool._draw_post2d() ############################# # RFWidget Drawing @DrawCallbacks.on_draw('pre3d') @FSM.onlyinstate({'main', 'quick switch'}) def draw_widget_pre3d(self): if not self.loading_done: return if not self.rftool.rfwidget: return if self._nav: return if self._hover_ui: return # if self.fsm.state == 'pie menu': return self.rftool.rfwidget._draw_pre3d() @DrawCallbacks.on_draw('post3d') @FSM.onlyinstate({'main', 'quick switch'}) def draw_widget_post3d(self): if not self.loading_done: return if not self.rftool.rfwidget: return if self._nav: return if self._hover_ui: return # if self.fsm.state == 'pie menu': return self.rftool.rfwidget._draw_post3d() @DrawCallbacks.on_draw('post2d') @FSM.onlyinstate({'main', 'quick switch'}) def draw_widget_post2d(self): if not self.loading_done: return if not self.rftool.rfwidget: return if self._nav: return if self._hover_ui: return # if self.fsm.state == 'pie menu': return self.rftool.rfwidget._draw_post2d()