blender/release/scripts/uvcalc_quad_clickproj.py
Campbell Barton aee06ac0d0 added an active face for the mesh editmode and normal mesh - this is needed because the TFace flag was not always easy to access from editmode.
using the last selected face was almost good enough however when selecting verts and edges the last selected face would become inactive and the space image would flicker about too much.
The active face is used for getting the space image at the moment and keeps scripts that use this flag working also.

This has 2 commands to get and set, so the variable is not accessed directly.

all "UV Calculate" scripts work now

last commit crashed when in solid draw mode, it seems subsurf modifier is ignoring the displayMask since MTFACE is available. just made it do a null check for now.

uvcalc_follow_active_coords.py - should be done inC and put in the snap menu.
2007-09-22 17:54:13 +00:00

267 lines
7.6 KiB
Python

#!BPY
""" Registration info for Blender menus: <- these words are ignored
Name: 'Click project from face'
Blender: 242
Group: 'UVCalculation'
Tooltip: '3 Clicks to project uvs onto selected faces.'
"""
__author__ = ["Campbell Barton"]
__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/")
__version__ = "0.1"
__bpydoc__=\
'''
http://mediawiki.blender.org/index.php/Scripts/Manual/UV_Calculate/Click_project_from_face
"
'''
# --------------------------------------------------------------------------
# Click project v0.1 by Campbell Barton (AKA Ideasman)
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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 2
# 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, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
import Blender
import bpy
import BPyMesh
import BPyWindow
mouseViewRay= BPyWindow.mouseViewRay
from Blender import Mathutils, Window, Scene, Draw, sys
from Blender.Mathutils import CrossVecs, Vector, Matrix, LineIntersect, Intersect #, AngleBetweenVecs, Intersect
LMB= Window.MButs.L
RMB= Window.MButs.R
def using_modifier(ob):
for m in ob.modifiers:
if m[Blender.Modifier.Settings.REALTIME]:
return True
return False
def mouseup():
# Loop until click
mouse_buttons = Window.GetMouseButtons()
while not mouse_buttons & LMB:
sys.sleep(10)
mouse_buttons = Window.GetMouseButtons()
while mouse_buttons & LMB:
sys.sleep(10)
mouse_buttons = Window.GetMouseButtons()
def mousedown_wait():
# If the menu has just been pressed dont use its mousedown,
mouse_buttons = Window.GetMouseButtons()
while mouse_buttons & LMB:
mouse_buttons = Window.GetMouseButtons()
sys.sleep(10)
def main():
scn = bpy.data.scenes.active
ob = scn.objects.active
if not ob or ob.type!='Mesh':
return
is_editmode = Window.EditMode()
if is_editmode:
Window.EditMode(0)
mousedown_wait() # so the menu items clicking dosnt trigger the mouseclick
Window.DrawProgressBar (0.0, '')
Window.DrawProgressBar (0.1, '(1 of 3) Click on a face corner')
# wait for a click
mouse_buttons = Window.GetMouseButtons()
while not mouse_buttons & LMB:
sys.sleep(10)
mouse_buttons = Window.GetMouseButtons()
# Allow for RMB cancel
if mouse_buttons & RMB:
return
while mouse_buttons & LMB:
sys.sleep(10)
mouse_buttons = Window.GetMouseButtons()
Window.DrawProgressBar (0.2, '(2 of 3 ) Click confirms the U coords')
mousedown_wait()
obmat= ob.matrixWorld
screen_x, screen_y = Window.GetMouseCoords()
mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat)
if not mouseInView or not OriginA:
return
me = ob.getData(mesh=1)
# Get the face under the mouse
face_click, isect, side = BPyMesh.pickMeshRayFace(me, OriginA, DirectionA)
if not face_click:
return
proj_z_component = face_click.no
if not face_click:
return
# Find the face vertex thats closest to the mouse,
# this vert will be used as the corner to map from.
best_v= None
best_length = 10000000
vi1 = None
for i, v in enumerate(face_click.v):
l = (v.co-isect).length
if l < best_length:
best_v = v
best_length = l
vi1 = i
# now get the 2 edges in the face that connect to v
# we can work it out fairly easerly
if len(face_click)==4:
if vi1==0: vi2, vi3= 3,1
elif vi1==1: vi2, vi3= 0,2
elif vi1==2: vi2, vi3= 1,3
elif vi1==3: vi2, vi3= 2,0
else:
if vi1==0: vi2, vi3= 2,1
elif vi1==1: vi2, vi3= 0,2
elif vi1==2: vi2, vi3= 1,0
face_corner_main =face_click.v[vi1].co
face_corner_a =face_click.v[vi2].co
face_corner_b =face_click.v[vi3].co
line_a_len = (face_corner_a-face_corner_main).length
line_b_len = (face_corner_b-face_corner_main).length
orig_cursor = Window.GetCursorPos()
Window.SetCursorPos(face_corner_main.x, face_corner_main.y, face_corner_main.z)
SHIFT = Window.Qual.SHIFT
MODE = 0 # firstclick, 1, secondclick
mouse_buttons = Window.GetMouseButtons()
project_mat = Matrix([0,0,0], [0,0,0], [0,0,0])
def get_face_coords(f):
f_uv = f.uv
return [(v.co-face_corner_main, f_uv[i]) for i,v in enumerate(f.v)]
coords = [ (co,uv) for f in me.faces if f.sel for co, uv in get_face_coords(f)]
coords_orig = [uv.copy() for co, uv in coords]
USE_MODIFIER = using_modifier(ob)
while 1:
if mouse_buttons & LMB:
if MODE == 0:
mousedown_wait()
Window.DrawProgressBar (0.8, '(3 of 3 ) Click confirms the V coords')
MODE = 1 # second click
# Se we cont continually set the length and get float error
proj_y_component_orig = proj_y_component.copy()
else:
break
elif mouse_buttons & RMB:
# Restore old uvs
for i, uv_orig in enumerate(coords_orig):
coords[i][1][:] = uv_orig
break
mouse_buttons = Window.GetMouseButtons()
screen_x, screen_y = Window.GetMouseCoords()
mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat)
if not mouseInView:
continue
# Do a ray tri intersection, not clipped by the tri
new_isect = Intersect(face_corner_main, face_corner_a, face_corner_b, DirectionA, OriginA, False)
new_isect_alt = new_isect + DirectionA*0.0001
# The distance from the mouse cursor ray vector to the edge
line_isect_a_pair = LineIntersect(new_isect, new_isect_alt, face_corner_main, face_corner_a)
line_isect_b_pair = LineIntersect(new_isect, new_isect_alt, face_corner_main, face_corner_b)
# SHIFT to flip the axis.
is_shift = Window.GetKeyQualifiers() & SHIFT
if MODE == 0:
line_dist_a = (line_isect_a_pair[0]-line_isect_a_pair[1]).length
line_dist_b = (line_isect_b_pair[0]-line_isect_b_pair[1]).length
if line_dist_a < line_dist_b:
proj_x_component = face_corner_a - face_corner_main
y_axis_length = line_b_len
x_axis_length = (line_isect_a_pair[1]-face_corner_main).length
else:
proj_x_component = face_corner_b - face_corner_main
y_axis_length = line_a_len
x_axis_length = (line_isect_b_pair[1]-face_corner_main).length
proj_y_component = CrossVecs(proj_x_component, proj_z_component)
proj_y_component.length = 1/y_axis_length
proj_x_component.length = 1/x_axis_length
if is_shift: proj_x_component.negate()
else:
proj_y_component[:] = proj_y_component_orig
if line_dist_a < line_dist_b:
proj_y_component.length = 1/(line_isect_a_pair[1]-new_isect).length
else:
proj_y_component.length = 1/(line_isect_b_pair[1]-new_isect).length
if is_shift: proj_y_component.negate()
# Use the existing matrix to make a new 3x3 projecton matrix
project_mat[0][:] = -proj_y_component
project_mat[1][:] = -proj_x_component
project_mat[2][:] = proj_z_component
# Apply the projection matrix
for proj_co, uv in coords:
uv[:] = (project_mat * proj_co)[0:2]
if USE_MODIFIER:
me.update()
Window.Redraw(Window.Types.VIEW3D)
Window.SetCursorPos(*orig_cursor)
if is_editmode:
Window.EditMode(1)
Window.RedrawAll()
if __name__=='__main__':
main()
Window.DrawProgressBar(1.0, '')