2006-01-17 23:50:06 +00:00
# SPACEHANDLER.VIEW3D.EVENT
# Dont run, event handelers are accessed in the from the 3d View menu.
import Blender
from Blender import Mathutils , Window , Scene , Draw , Mesh , NMesh
from Blender . Mathutils import CrossVecs , Matrix , Vector , Intersect , LineIntersect
# DESCRIPTION:
# screen_x, screen_y the origin point of the pick ray
# it is either the mouse location
# localMatrix is used if you want to have the returned values in an objects localspace.
# this is usefull when dealing with an objects data such as verts.
# or if useMid is true, the midpoint of the current 3dview
# returns
# Origin - the origin point of the pick ray
# Direction - the direction vector of the pick ray
# in global coordinates
epsilon = 1e-3 # just a small value to account for floating point errors
def getPickRay ( screen_x , screen_y , localMatrix = None , useMid = False ) :
# Constant function variables
p = getPickRay . p
d = getPickRay . d
for win3d in Window . GetScreenInfo ( Window . Types . VIEW3D ) : # we search all 3dwins for the one containing the point (screen_x, screen_y) (could be the mousecoords for example)
win_min_x , win_min_y , win_max_x , win_max_y = win3d [ ' vertices ' ]
# calculate a few geometric extents for this window
win_mid_x = ( win_max_x + win_min_x + 1.0 ) * 0.5
win_mid_y = ( win_max_y + win_min_y + 1.0 ) * 0.5
win_size_x = ( win_max_x - win_min_x + 1.0 ) * 0.5
win_size_y = ( win_max_y - win_min_y + 1.0 ) * 0.5
#useMid is for projecting the coordinates when we subdivide the screen into bins
if useMid : # == True
screen_x = win_mid_x
screen_y = win_mid_y
# if the given screencoords (screen_x, screen_y) are within the 3dwin we fount the right one...
if ( win_max_x > screen_x > win_min_x ) and ( win_max_y > screen_y > win_min_y ) :
# first we handle all pending events for this window (otherwise the matrices might come out wrong)
Window . QHandle ( win3d [ ' id ' ] )
# now we get a few matrices for our window...
# sorry - i cannot explain here what they all do
# - if you're not familiar with all those matrices take a look at an introduction to OpenGL...
pm = Window . GetPerspMatrix ( ) # the prespective matrix
pmi = Matrix ( pm ) ; pmi . invert ( ) # the inverted perspective matrix
if ( 1.0 - epsilon < pmi [ 3 ] [ 3 ] < 1.0 + epsilon ) :
# pmi[3][3] is 1.0 if the 3dwin is in ortho-projection mode (toggled with numpad 5)
hms = getPickRay . hms
ortho_d = getPickRay . ortho_d
# ortho mode: is a bit strange - actually there's no definite location of the camera ...
# but the camera could be displaced anywhere along the viewing direction.
ortho_d . x , ortho_d . y , ortho_d . z = Window . GetViewVector ( )
ortho_d . w = 0
# all rays are parallel in ortho mode - so the direction vector is simply the viewing direction
2006-04-11 02:41:11 +00:00
#hms.x, hms.y, hms.z, hms.w = (screen_x-win_mid_x) /win_size_x, (screen_y-win_mid_y) / win_size_y, 0.0, 1.0
hms [ : ] = ( screen_x - win_mid_x ) / win_size_x , ( screen_y - win_mid_y ) / win_size_y , 0.0 , 1.0
2006-01-17 23:50:06 +00:00
# these are the homogenious screencoords of the point (screen_x, screen_y) ranging from -1 to +1
p = ( hms * pmi ) + ( 1000 * ortho_d )
p . resize3D ( )
2006-04-11 02:41:11 +00:00
d [ : ] = ortho_d [ : 3 ]
2006-01-17 23:50:06 +00:00
# Finally we shift the position infinitely far away in
# the viewing direction to make sure the camera if outside the scene
# (this is actually a hack because this function
# is used in sculpt_mesh to initialize backface culling...)
else :
# PERSPECTIVE MODE: here everything is well defined - all rays converge at the camera's location
vmi = Matrix ( Window . GetViewMatrix ( ) ) ; vmi . invert ( ) # the inverse viewing matrix
fp = getPickRay . fp
dx = pm [ 3 ] [ 3 ] * ( ( ( screen_x - win_min_x ) / win_size_x ) - 1.0 ) - pm [ 3 ] [ 0 ]
dy = pm [ 3 ] [ 3 ] * ( ( ( screen_y - win_min_y ) / win_size_y ) - 1.0 ) - pm [ 3 ] [ 1 ]
2006-04-11 02:41:11 +00:00
fp [ : ] = \
2006-01-17 23:50:06 +00:00
pmi [ 0 ] [ 0 ] * dx + pmi [ 1 ] [ 0 ] * dy , \
pmi [ 0 ] [ 1 ] * dx + pmi [ 1 ] [ 1 ] * dy , \
pmi [ 0 ] [ 2 ] * dx + pmi [ 1 ] [ 2 ] * dy
# fp is a global 3dpoint obtained from "unprojecting" the screenspace-point (screen_x, screen_y)
#- figuring out how to calculate this took me quite some time.
# The calculation of dxy and fp are simplified versions of my original code
#- so it's almost impossible to explain what's going on geometrically... sorry
2006-04-11 02:41:11 +00:00
p [ : ] = vmi [ 3 ] [ : 3 ]
2006-01-17 23:50:06 +00:00
# the camera's location in global 3dcoords can be read directly from the inverted viewmatrix
#d.x, d.y, d.z =normalize_v3(sub_v3v3(p, fp))
2006-04-11 02:41:11 +00:00
d [ : ] = p . x - fp . x , p . y - fp . y , p . z - fp . z
2006-01-17 23:50:06 +00:00
#print 'd', d, 'p', p, 'fp', fp
# the direction vector is simply the difference vector from the virtual camera's position
#to the unprojected (screenspace) point fp
# Do we want to return a direction in object's localspace?
if localMatrix :
localInvMatrix = Matrix ( localMatrix )
localInvMatrix . invert ( )
p = p * localInvMatrix
d = d * localInvMatrix # normalize_v3
p . x + = localInvMatrix [ 3 ] [ 0 ]
p . y + = localInvMatrix [ 3 ] [ 1 ]
p . z + = localInvMatrix [ 3 ] [ 2 ]
#else: # Worldspace, do nothing
d . normalize ( )
return True , p , d # Origin, Direction
# Mouse is not in any view, return None.
return False , None , None
# Constant function variables
getPickRay . d = Vector ( 0 , 0 , 0 ) # Perspective, 3d
getPickRay . p = Vector ( 0 , 0 , 0 )
getPickRay . fp = Vector ( 0 , 0 , 0 )
getPickRay . hms = Vector ( 0 , 0 , 0 , 0 ) # ortho only 4d
getPickRay . ortho_d = Vector ( 0 , 0 , 0 , 0 ) # ortho only 4d
def ui_set_preferences ( user_interface = 1 ) :
# Create data and set defaults.
2006-01-21 12:33:58 +00:00
ADAPTIVE_GEOMETRY_but = Draw . Create ( 0 )
2006-01-17 23:50:06 +00:00
BRUSH_MODE_but = Draw . Create ( 1 )
BRUSH_PRESSURE_but = Draw . Create ( 0.05 )
BRUSH_RADIUS_but = Draw . Create ( 0.25 )
RESOLUTION_MIN_but = Draw . Create ( 0.1 )
DISPLACE_NORMAL_MODE_but = Draw . Create ( 2 )
STATIC_NORMAL_but = Draw . Create ( 1 )
XPLANE_CLIP_but = Draw . Create ( 0 )
STATIC_MESH_but = Draw . Create ( 1 )
FIX_TOPOLOGY_but = Draw . Create ( 0 )
# Remember old variables if alredy set.
try :
ADAPTIVE_GEOMETRY_but . val = Blender . bbrush [ ' ADAPTIVE_GEOMETRY ' ]
BRUSH_MODE_but . val = Blender . bbrush [ ' BRUSH_MODE ' ]
BRUSH_PRESSURE_but . val = Blender . bbrush [ ' BRUSH_PRESSURE ' ]
BRUSH_RADIUS_but . val = Blender . bbrush [ ' BRUSH_RADIUS ' ]
RESOLUTION_MIN_but . val = Blender . bbrush [ ' RESOLUTION_MIN ' ]
DISPLACE_NORMAL_MODE_but . val = Blender . bbrush [ ' DISPLACE_NORMAL_MODE ' ]
STATIC_NORMAL_but . val = Blender . bbrush [ ' STATIC_NORMAL ' ]
XPLANE_CLIP_but . val = Blender . bbrush [ ' XPLANE_CLIP ' ]
STATIC_MESH_but . val = Blender . bbrush [ ' STATIC_MESH ' ]
FIX_TOPOLOGY_but . val = Blender . bbrush [ ' FIX_TOPOLOGY ' ]
except :
Blender . bbrush = { }
if user_interface :
pup_block = [ \
' Brush Options ' , \
( ' Adaptive Geometry ' , ADAPTIVE_GEOMETRY_but , ' Add and remove detail as needed. Uses min/max resolution. ' ) , \
( ' Brush Type: ' , BRUSH_MODE_but , 1 , 5 , ' Push/Pull:1, Grow/Shrink:2, Spin:3, Relax:4, Goo:5 ' ) , \
2006-04-11 02:41:11 +00:00
( ' Pressure: ' , BRUSH_PRESSURE_but , 0.0 , 1.0 , ' Pressure of the brush. ' ) , \
( ' Size: ' , BRUSH_RADIUS_but , 0.01 , 2.0 , ' Size of the brush. ' ) , \
2006-01-17 23:50:06 +00:00
( ' Geometry Res: ' , RESOLUTION_MIN_but , 0.01 , 0.5 , ' Size of the brush & Adaptive Subdivision. ' ) , \
( ' Displace Vector: ' , DISPLACE_NORMAL_MODE_but , 1 , 4 , ' Vertex Normal:1, Median Normal:2, Face Normal:3, View Normal:4 ' ) , \
( ' Static Normal ' , STATIC_NORMAL_but , ' Use the initial normal only. ' ) , \
( ' No X Crossing ' , XPLANE_CLIP_but , ' Dont allow verts to have a negative X axis (use for x-mirror). ' ) , \
( ' Static Mesh ' , STATIC_MESH_but , ' During mouse interaction, dont update the mesh. ' ) , \
#('Fix Topology', FIX_TOPOLOGY_but, 'Fix the mesh structure by rotating edges '),\
]
Draw . PupBlock ( ' BlenBrush Prefs (RMB) ' , pup_block )
Blender . bbrush [ ' ADAPTIVE_GEOMETRY ' ] = ADAPTIVE_GEOMETRY_but . val
Blender . bbrush [ ' BRUSH_MODE ' ] = BRUSH_MODE_but . val
Blender . bbrush [ ' BRUSH_PRESSURE ' ] = BRUSH_PRESSURE_but . val
Blender . bbrush [ ' BRUSH_RADIUS ' ] = BRUSH_RADIUS_but . val
Blender . bbrush [ ' RESOLUTION_MIN ' ] = RESOLUTION_MIN_but . val
Blender . bbrush [ ' DISPLACE_NORMAL_MODE ' ] = DISPLACE_NORMAL_MODE_but . val
Blender . bbrush [ ' STATIC_NORMAL ' ] = STATIC_NORMAL_but . val
Blender . bbrush [ ' XPLANE_CLIP ' ] = XPLANE_CLIP_but . val
Blender . bbrush [ ' STATIC_MESH ' ] = STATIC_MESH_but . val
Blender . bbrush [ ' FIX_TOPOLOGY ' ] = FIX_TOPOLOGY_but . val
def triangulateNMesh ( nm ) :
'''
Converts the meshes faces to tris , modifies the mesh in place .
'''
#============================================================================#
# Returns a new face that has the same properties as the origional face #
# but with no verts #
#============================================================================#
def copyFace ( face ) :
newFace = NMesh . Face ( )
# Copy some generic properties
newFace . mode = face . mode
if face . image != None :
newFace . image = face . image
newFace . flag = face . flag
newFace . mat = face . mat
newFace . smooth = face . smooth
return newFace
# 2 List comprehensions are a lot faster then 1 for loop.
tris = [ f for f in nm . faces if len ( f ) == 3 ]
quads = [ f for f in nm . faces if len ( f ) == 4 ]
if quads : # Mesh may have no quads.
has_uv = quads [ 0 ] . uv
has_vcol = quads [ 0 ] . col
for quadFace in quads :
# Triangulate along the shortest edge
#if (quadFace.v[0].co - quadFace.v[2].co).length < (quadFace.v[1].co - quadFace.v[3].co).length:
a1 = Mathutils . TriangleArea ( quadFace . v [ 0 ] . co , quadFace . v [ 1 ] . co , quadFace . v [ 2 ] . co )
a2 = Mathutils . TriangleArea ( quadFace . v [ 0 ] . co , quadFace . v [ 2 ] . co , quadFace . v [ 3 ] . co )
b1 = Mathutils . TriangleArea ( quadFace . v [ 1 ] . co , quadFace . v [ 2 ] . co , quadFace . v [ 3 ] . co )
b2 = Mathutils . TriangleArea ( quadFace . v [ 1 ] . co , quadFace . v [ 3 ] . co , quadFace . v [ 0 ] . co )
a1 , a2 = min ( a1 , a2 ) , max ( a1 , a2 )
b1 , b2 = min ( b1 , b2 ) , max ( b1 , b2 )
if a1 / a2 < b1 / b2 :
# Method 1
triA = 0 , 1 , 2
triB = 0 , 2 , 3
else :
# Method 2
triA = 0 , 1 , 3
triB = 1 , 2 , 3
for tri1 , tri2 , tri3 in ( triA , triB ) :
newFace = copyFace ( quadFace )
newFace . v = [ quadFace . v [ tri1 ] , quadFace . v [ tri2 ] , quadFace . v [ tri3 ] ]
if has_uv : newFace . uv = [ quadFace . uv [ tri1 ] , quadFace . uv [ tri2 ] , quadFace . uv [ tri3 ] ]
if has_vcol : newFace . col = [ quadFace . col [ tri1 ] , quadFace . col [ tri2 ] , quadFace . col [ tri3 ] ]
nm . addEdge ( quadFace . v [ tri1 ] , quadFace . v [ tri3 ] ) # Add an edge where the 2 tris are devided.
tris . append ( newFace )
nm . faces = tris
import mesh_tri2quad
def fix_topolagy ( mesh ) :
ob = Scene . GetCurrent ( ) . getActiveObject ( )
for f in mesh . faces :
f . sel = 1
mesh . quadToTriangle ( 0 )
nmesh = ob . getData ( )
mesh_tri2quad . tri2quad ( nmesh , 100 , 0 )
triangulateNMesh ( nmesh )
nmesh . update ( )
mesh = Mesh . Get ( mesh . name )
for f in mesh . faces :
f . sel = 1
mesh . quadToTriangle ( )
Mesh . Mode ( Mesh . SelectModes [ ' EDGE ' ] )
def event_main ( ) :
#print Blender.event
#mod =[Window.Qual.CTRL, Window.Qual.ALT, Window.Qual.SHIFT]
mod = [ Window . Qual . CTRL , Window . Qual . ALT ]
qual = Window . GetKeyQualifiers ( )
SHIFT_FLAG = Window . Qual . SHIFT
CTRL_FLAG = Window . Qual . CTRL
# UNDO
"""
is_editmode = Window . EditMode ( ) # Exit Editmode.
if is_editmode : Window . EditMode ( 0 )
if Blender . event == Draw . UKEY :
if is_editmode :
Blender . event = Draw . UKEY
return
else :
winId = [ win3d for win3d in Window . GetScreenInfo ( Window . Types . VIEW3D ) ] [ 0 ]
Blender . event = None
Window . QHandle ( winId [ ' id ' ] )
Window . EditMode ( 1 )
Window . QHandle ( winId [ ' id ' ] )
Window . QAdd ( winId [ ' id ' ] , Draw . UKEY , 1 ) # Change KeyPress Here for EditMode
Window . QAdd ( winId [ ' id ' ] , Draw . UKEY , 0 )
Window . QHandle ( winId [ ' id ' ] )
Window . EditMode ( 0 )
Blender . event = None
return
"""
ob = Scene . GetCurrent ( ) . getActiveObject ( )
if not ob or ob . getType ( ) != ' Mesh ' :
return
# Mouse button down with no modifiers.
if Blender . event == Draw . LEFTMOUSE and not [ True for m in mod if m & qual ] :
# Do not exit (draw)
pass
elif Blender . event == Draw . RIGHTMOUSE and not [ True for m in mod if m & qual ] :
ui_set_preferences ( )
return
else :
return
del qual
try :
Blender . bbrush
except :
# First time run
ui_set_preferences ( ) # No ui
return
ADAPTIVE_GEOMETRY = Blender . bbrush [ ' ADAPTIVE_GEOMETRY ' ] # 1
BRUSH_MODE = Blender . bbrush [ ' BRUSH_MODE ' ] # 1
BRUSH_PRESSURE_ORIG = Blender . bbrush [ ' BRUSH_PRESSURE ' ] # 0.1
BRUSH_RADIUS = Blender . bbrush [ ' BRUSH_RADIUS ' ] # 0.5
RESOLUTION_MIN = Blender . bbrush [ ' RESOLUTION_MIN ' ] # 0.08
STATIC_NORMAL = Blender . bbrush [ ' STATIC_NORMAL ' ] # 0
XPLANE_CLIP = Blender . bbrush [ ' XPLANE_CLIP ' ] # 0
DISPLACE_NORMAL_MODE = Blender . bbrush [ ' DISPLACE_NORMAL_MODE ' ] # 'Vertex Normal%x1|Median Normal%x2|Face Normal%x3|View Normal%x4'
STATIC_MESH = Blender . bbrush [ ' STATIC_MESH ' ]
FIX_TOPOLOGY = Blender . bbrush [ ' FIX_TOPOLOGY ' ]
# Angle between Vecs wrapper.
AngleBetweenVecs = Mathutils . AngleBetweenVecs
def ang ( v1 , v2 ) :
try :
return AngleBetweenVecs ( v1 , v2 )
except :
return 180
"""
def Angle2D ( x1 , y1 , x2 , y2 ) :
import math
RAD2DEG = 57.295779513082323
'''
Return the angle between two vectors on a plane
The angle is from vector 1 to vector 2 , positive anticlockwise
The result is between - pi - > pi
'''
dtheta = math . atan2 ( y2 , x2 ) - math . atan2 ( y1 , x1 ) # theta1 - theta2
while dtheta > math . pi :
dtheta - = ( math . pi * 2 )
while dtheta < - math . pi :
dtheta + = ( math . pi * 2 )
return dtheta * RAD2DEG #(180.0 / math.pi)
"""
def faceIntersect ( f ) :
isect = Intersect ( f . v [ 0 ] . co , f . v [ 1 ] . co , f . v [ 2 ] . co , Direction , Origin , 1 ) # Clipped.
if isect :
return isect
elif len ( f . v ) == 4 :
isect = Intersect ( f . v [ 0 ] . co , f . v [ 2 ] . co , f . v [ 3 ] . co , Direction , Origin , 1 ) # Clipped.
return isect
"""
# Unused so farm, too slow.
def removeDouble ( v1 , v2 , me ) :
v1List = [ f for f in me . faces if v1 in f . v ]
v2List = [ f for f in me . faces if v2 in f . v ]
#print v1List
#print v2List
remFaces = [ ]
newFaces = [ ]
for f2 in v2List :
f2ls = list ( f2 . v )
i = f2ls . index ( v2 )
f2ls [ i ] = v1
#remFaces.append(f2)
if f2ls . count ( v1 ) == 1 :
newFaces . append ( tuple ( f2ls ) )
if remFaces :
me . faces . delete ( 1 , remFaces )
#me.verts.delete(v2)
if newFaces :
me . faces . extend ( newFaces )
"""
me = ob . getData ( mesh = 1 )
is_editmode = Window . EditMode ( ) # Exit Editmode.
if is_editmode : Window . EditMode ( 0 )
Mesh . Mode ( Mesh . SelectModes [ ' EDGE ' ] )
# At the moment ADAPTIVE_GEOMETRY is the only thing that uses selection.
if ADAPTIVE_GEOMETRY :
# Deslect all
SEL_FLAG = Mesh . EdgeFlags [ ' SELECT ' ]
'''
for ed in me . edges :
#ed.flag &= ~SEL_FLAG # deselect. 34
ed . flag = 32
'''
2006-01-21 12:33:58 +00:00
#filter(lambda ed: setattr(ed, 'flag', 32), me.edges)
2006-01-17 23:50:06 +00:00
''' for v in me.verts:
v . sel = 0 '''
2006-01-21 12:33:58 +00:00
#filter(lambda v: setattr(v, 'sel', 0), me.verts)
# DESELECT ABSOLUTLY ALL
Mesh . Mode ( Mesh . SelectModes [ ' FACE ' ] )
filter ( lambda f : setattr ( f , ' sel ' , 0 ) , me . faces )
Mesh . Mode ( Mesh . SelectModes [ ' EDGE ' ] )
filter ( lambda ed : setattr ( ed , ' flag ' , 32 ) , me . edges )
Mesh . Mode ( Mesh . SelectModes [ ' VERTEX ' ] )
filter ( lambda v : setattr ( v , ' sel ' , 0 ) , me . verts )
Mesh . Mode ( Mesh . SelectModes [ ' EDGE ' ] )
2006-01-17 23:50:06 +00:00
i = 0
time = Blender . sys . time ( )
last_best_isect = None # used for goo only
old_screen_x , old_screen_y = 1 << 30 , 1 << 30
goo_dir_vec = last_goo_dir_vec = gooRotMatrix = None # goo mode only.
# Normal stuff
iFaceNormal = medainNormal = None
# Store all vert normals for now.
if BRUSH_MODE == 1 and STATIC_NORMAL : # Push pull
vert_orig_normals = dict ( [ ( v , v . no ) for v in me . verts ] )
elif BRUSH_MODE == 4 : # RELAX, BUILD EDGE CONNECTIVITE DATA.
# we need edge connectivity
#vertEdgeUsers = [list() for i in xrange(len(me.verts))]
verts_connected_by_edge = [ list ( ) for i in xrange ( len ( me . verts ) ) ]
for ed in me . edges :
i1 , i2 = ed . v1 . index , ed . v2 . index
#vertEdgeUsers[i1].append(ed)
#vertEdgeUsers[i2].append(ed)
verts_connected_by_edge [ i1 ] . append ( ed . v2 )
verts_connected_by_edge [ i2 ] . append ( ed . v1 )
if STATIC_MESH :
# Try and find a static mesh to reuse.
# this is because we dont want to make a new mesh for each stroke.
mesh_static = None
for _me_name_ in Blender . NMesh . GetNames ( ) :
_me_ = Mesh . Get ( _me_name_ )
#print _me_.users , len(me.verts)
if _me_ . users == 0 and len ( _me_ . verts ) == 0 :
mesh_static = _me_
#print 'using', _me_.name
break
del _me_name_
del _me_
if not mesh_static :
mesh_static = Mesh . New ( )
print ' Making new mesh ' , mesh_static . name
mesh_static . verts . extend ( [ v . co for v in me . verts ] )
mesh_static . faces . extend ( [ tuple ( [ mesh_static . verts [ v . index ] for v in f . v ] ) for f in me . faces ] )
best_isect = gooPlane = None
while Window . GetMouseButtons ( ) == 1 :
i + = 1
screen_x , screen_y = Window . GetMouseCoords ( )
# Skip when no mouse movement, Only for Goo!
if screen_x == old_screen_x and screen_y == old_screen_y :
if BRUSH_MODE == 5 : # Dont modify while mouse is not moved for goo.
continue
else : # mouse has moved get the new mouse ray.
old_screen_x , old_screen_y = screen_x , screen_y
mouseInView , Origin , Direction = getPickRay ( screen_x , screen_y , ob . matrixWorld )
if not mouseInView or not Origin :
return
Origin_SCALE = Origin * 100
# Find an intersecting face!
bestLen = 1 << 30 # start with an assumed realy bad match.
best_isect = None # last intersect is used for goo.
best_face = None
if not last_best_isect :
last_best_isect = best_isect
if not mouseInView :
last_best_isect = None
else :
# Find Face intersection closest to the view.
#for f in [f for f in me.faces if ang(f.no, Direction) < 90]:
# Goo brush only intersects faces once, after that the brush follows teh view plain.
if BRUSH_MODE == 5 and gooPlane != None and gooPlane :
best_isect = Intersect ( gooPlane [ 0 ] , gooPlane [ 1 ] , gooPlane [ 2 ] , Direction , Origin , 0 ) # Non clipped
else :
if STATIC_MESH :
intersectingFaces = [ ( f , ix ) for f in mesh_static . faces for ix in ( faceIntersect ( f ) , ) if ix ]
else :
intersectingFaces = [ ( f , ix ) for f in me . faces for ix in ( faceIntersect ( f ) , ) if ix ]
for f , isect in intersectingFaces :
l = ( Origin_SCALE - isect ) . length
if l < bestLen :
best_face = f
best_isect = isect
bestLen = l
if not best_isect :
# Dont interpolate once the mouse moves off the mesh.
lastGooVec = last_best_isect = None
else : # mouseInView must be true also
# Use the shift key to modify the pressure.
if SHIFT_FLAG & Window . GetKeyQualifiers ( ) :
BRUSH_PRESSURE = - BRUSH_PRESSURE_ORIG
else :
BRUSH_PRESSURE = BRUSH_PRESSURE_ORIG
2006-04-11 02:41:11 +00:00
brush_verts = [ ( v , le ) for v in me . verts for le in ( ( v . co - best_isect ) . length , ) if le < = BRUSH_RADIUS ]
2006-01-17 23:50:06 +00:00
# SETUP ONCE ONLY VARIABLES
if STATIC_NORMAL : # Only set the normal once.
if not iFaceNormal :
iFaceNormal = best_face . no
else :
if best_face :
iFaceNormal = best_face . no
if DISPLACE_NORMAL_MODE == 2 : # MEDIAN NORMAL
2006-04-11 02:41:11 +00:00
if ( STATIC_NORMAL and medainNormal == None ) or not STATIC_NORMAL or str ( medainNormal . x ) == ' nan ' :
2006-01-17 23:50:06 +00:00
medainNormal = Vector ( 0 , 0 , 0 )
2006-04-11 02:41:11 +00:00
if brush_verts :
for v , l in brush_verts :
medainNormal + = v . no * ( BRUSH_RADIUS - l )
medainNormal . normalize ( )
2006-01-17 23:50:06 +00:00
# ================================================================#
# == Tool code, loop on the verts and operate on them ============#
# ================================================================#
if BRUSH_MODE == 1 : # NORMAL PAINT
for v , l in brush_verts :
if XPLANE_CLIP :
origx = False
if abs ( v . co . x ) < 0.001 : origx = True
v . sel = 1 # MARK THE VERT AS DIRTY.
2006-04-11 02:41:11 +00:00
falloff = BRUSH_PRESSURE * ( ( BRUSH_RADIUS - l ) / BRUSH_RADIUS ) # falloff between 0 and 1
2006-01-17 23:50:06 +00:00
if DISPLACE_NORMAL_MODE == 1 : # VERTEX NORMAL
if STATIC_NORMAL :
try :
no = vert_orig_normals [ v ]
except :
no = vert_orig_normals [ v ] = v . no
2006-04-11 02:41:11 +00:00
v . co + = no * falloff
2006-01-17 23:50:06 +00:00
else :
2006-04-11 02:41:11 +00:00
v . co + = no * falloff
2006-01-17 23:50:06 +00:00
elif DISPLACE_NORMAL_MODE == 2 : # MEDIAN NORMAL # FIXME
2006-04-11 02:41:11 +00:00
v . co + = medainNormal * falloff
2006-01-17 23:50:06 +00:00
elif DISPLACE_NORMAL_MODE == 3 : # FACE NORMAL
2006-04-11 02:41:11 +00:00
v . co + = iFaceNormal * falloff
2006-01-17 23:50:06 +00:00
elif DISPLACE_NORMAL_MODE == 4 : # VIEW NORMAL
2006-04-11 02:41:11 +00:00
v . co + = Direction * falloff
2006-01-17 23:50:06 +00:00
# Clamp back to original x if needs be.
if XPLANE_CLIP and origx :
v . co . x = 0
elif BRUSH_MODE == 2 : # SCALE
for v , l in brush_verts :
if XPLANE_CLIP :
origx = False
if abs ( v . co . x ) < 0.001 : origx = True
v . sel = 1 # MARK THE VERT AS DIRTY.
falloff = ( BRUSH_RADIUS - l ) / BRUSH_RADIUS # falloff between 0 and 1
vert_scale_vec = v . co - best_isect
vert_scale_vec . normalize ( )
# falloff needs to be scaled for this tool
falloff = falloff / 10
2006-04-11 02:41:11 +00:00
v . co + = vert_scale_vec * ( BRUSH_PRESSURE * falloff ) # FLAT BRUSH
2006-01-17 23:50:06 +00:00
# Clamp back to original x if needs be.
if XPLANE_CLIP and origx :
v . co . x = 0
if BRUSH_MODE == 3 : # ROTATE.
if DISPLACE_NORMAL_MODE == 1 : # VERTEX NORMAL
ROTATE_MATRIX = Mathutils . RotationMatrix ( BRUSH_PRESSURE * 10 , 4 , ' r ' , iFaceNormal ) # Cant use vertex normal, use face normal
elif DISPLACE_NORMAL_MODE == 2 : # MEDIAN NORMAL
ROTATE_MATRIX = Mathutils . RotationMatrix ( BRUSH_PRESSURE * 10 , 4 , ' r ' , medainNormal ) # Cant use vertex normal, use face normal
elif DISPLACE_NORMAL_MODE == 3 : # FACE NORMAL
ROTATE_MATRIX = Mathutils . RotationMatrix ( BRUSH_PRESSURE * 10 , 4 , ' r ' , iFaceNormal ) # Cant use vertex normal, use face normal
elif DISPLACE_NORMAL_MODE == 4 : # VIEW NORMAL
ROTATE_MATRIX = Mathutils . RotationMatrix ( BRUSH_PRESSURE * 10 , 4 , ' r ' , Direction ) # Cant use vertex normal, use face normal
# Brush code
for v , l in brush_verts :
if XPLANE_CLIP :
origx = False
if abs ( v . co . x ) < 0.001 : origx = True
# MARK THE VERT AS DIRTY.
v . sel = 1
falloff = ( BRUSH_RADIUS - l ) / BRUSH_RADIUS # falloff between 0 and 1
# Vectors handeled with rotation matrix creation.
rot_vert_loc = ( ROTATE_MATRIX * ( v . co - best_isect ) ) + best_isect
v . co = ( v . co * ( 1 - falloff ) ) + ( rot_vert_loc * ( falloff ) )
# Clamp back to original x if needs be.
if XPLANE_CLIP and origx :
v . co . x = 0
elif BRUSH_MODE == 4 : # RELAX
vert_orig_loc = [ Vector ( v . co ) for v in me . verts ] # save orig vert location.
#vertOrigNor = [Vector(v.no) for v in me.verts ] # save orig vert location.
# Brush code
for v , l in brush_verts :
if XPLANE_CLIP :
origx = False
if abs ( v . co . x ) < 0.001 : origx = True
v . sel = 1 # Mark the vert as dirty.
falloff = ( BRUSH_RADIUS - l ) / BRUSH_RADIUS # falloff between 0 and 1
connected_verts = verts_connected_by_edge [ v . index ]
relax_point = reduce ( lambda a , b : a + vert_orig_loc [ b . index ] , connected_verts , Mathutils . Vector ( 0 , 0 , 0 ) ) * ( 1.0 / len ( connected_verts ) )
falloff = falloff * BRUSH_PRESSURE
# Old relax.
#v.co = (v.co*(1-falloff)) + (relax_point*(falloff))
ll = ( v . co - relax_point ) . length
newpoint = ( v . co * ( 1 - falloff ) ) + ( relax_point * ( falloff ) ) - v . co
newpoint = newpoint * ( 1 / ( 1 + ll ) )
v . co = v . co + newpoint
'''
# New relax
relax_normal = vertOrigNor [ v . index ]
v1 , v2 , v3 , v4 = v . co , v . co + relax_normal , relax_point - ( relax_normal * 10 ) , relax_point + ( relax_normal * 10 )
print v1 , v2 , v3 , v4
try :
a , b = LineIntersect ( v1 , v2 , v3 , v4 ) # Scale the normal to make a line. we know we will intersect with.
v . co = ( v . co * ( 1 - falloff ) ) + ( a * ( falloff ) )
except :
pass
'''
# Clamp back to original x if needs be.
if XPLANE_CLIP and origx :
v . co . x = 0
elif BRUSH_MODE == 5 : # GOO
#print last_best_isect, best_isect, 'AA'
if not last_best_isect :
last_best_isect = best_isect
# Set up a triangle orthographic to the view plane
gooPlane = [ best_isect , CrossVecs ( best_isect , Direction ) , None ]
if DISPLACE_NORMAL_MODE == 4 : # View Normal
tempRotMatrix = Mathutils . RotationMatrix ( 90 , 3 , ' r ' , Direction )
else :
tempRotMatrix = Mathutils . RotationMatrix ( 90 , 3 , ' r ' , CrossVecs ( best_face . no , Direction ) )
gooPlane [ 2 ] = best_isect + ( tempRotMatrix * gooPlane [ 1 ] )
gooPlane [ 1 ] = gooPlane [ 1 ] + best_isect
continue # we need another point of reference.
elif last_best_isect == best_isect :
# Mouse has not moved, no point in trying to goo.
continue
else :
if goo_dir_vec :
last_goo_dir_vec = goo_dir_vec
# The direction the mouse moved in 3d space. use for gooing
# Modify best_isect so its not moving allong the view z axis.
# Assume Origin hasnt changed since the view wont change while the mouse is drawing. ATM.
best_isect = Intersect ( gooPlane [ 0 ] , gooPlane [ 1 ] , gooPlane [ 2 ] , Direction , Origin , 0 ) # Non clipped
goo_dir_vec = ( best_isect - last_best_isect ) * 2
# make a goo rotation matrix so the head of the goo rotates with the mouse.
"""
if last_goo_dir_vec and goo_dir_vec != last_goo_dir_vec :
'''
vmi = Matrix ( Window . GetViewMatrix ( ) ) ; vmi . invert ( ) # the inverse viewing matrix
a = last_goo_dir_vec * vmi
b = goo_dir_vec * vmi
c = Angle2D ( a . x , a . y , b . x , b . y )
gooRotMatrix = Mathutils . RotationMatrix ( ( c * goo_dir_vec . length ) * - 20 , 3 , ' r ' , Direction )
'''
pass
else :
gooRotMatrix = None
"""
if goo_dir_vec . x == 0 and goo_dir_vec . y == 0 and goo_dir_vec . z == 0 :
continue
# Brush code
for v , l in brush_verts :
if XPLANE_CLIP :
origx = False
if abs ( v . co . x ) < 0.001 : origx = True
# MARK THE VERT AS DIRTY.
v . sel = 1
''' # ICICLES!!!
a = AngleBetweenVecs ( goo_dir_vec , v . no )
if a > 66 :
continue
l = l * ( ( 1 + a ) / 67.0 )
l = max ( 0.00000001 , l )
'''
falloff = ( BRUSH_RADIUS - l ) / BRUSH_RADIUS # falloff between 0 and 1
goo_loc = ( v . co * ( 1 - falloff ) ) + ( ( v . co + goo_dir_vec ) * falloff )
v . co = ( goo_loc * BRUSH_PRESSURE ) + ( v . co * ( 1 - BRUSH_PRESSURE ) )
'''
if gooRotMatrix :
rotatedVertLocation = ( gooRotMatrix * ( v . co - best_isect ) ) + best_isect
v . co = ( v . co * ( 1 - falloff ) ) + ( rotatedVertLocation * ( falloff ) )
# USe for goo only.
'''
# Clamp back to original x if needs be.
if XPLANE_CLIP and origx :
v . co . x = 0
# Remember for the next sample
last_best_isect = best_isect
last_goo_dir_vec = goo_dir_vec
# Post processing after the verts have moved
# Subdivide any large edges, all but relax.
MAX_SUBDIV = 10 # Maximum number of subdivisions per redraw. makes things useable.
SUBDIV_COUNT = 0
# Cant use adaptive geometry for relax because it keeps connectivity data.
if ADAPTIVE_GEOMETRY and ( BRUSH_MODE == 1 or BRUSH_MODE == 2 or BRUSH_MODE == 3 or BRUSH_MODE == 5 ) :
Mesh . Mode ( Mesh . SelectModes [ ' EDGE ' ] )
orig_len_edges = 0
#print 'ADAPTIVE_GEOMETRY'
while len ( me . edges ) != orig_len_edges and SUBDIV_COUNT < MAX_SUBDIV :
#print 'orig_len_edges', len(me.edges)
#me = ob.getData(mesh=1)
orig_len_edges = len ( me . edges )
EDGE_COUNT = 0
for ed in me . edges :
if ed . v1 . sel or ed . v2 . sel :
l = ( ed . v1 . co - ed . v2 . co ) . length
if l > max ( RESOLUTION_MIN * 1.5 , BRUSH_RADIUS ) :
#if l > BRUSH_RADIUS:
#print 'adding edge'
ed . flag | = SEL_FLAG
#ed.flag = 35
SUBDIV_COUNT + = 1
EDGE_COUNT + = 1
"""
elif l < RESOLUTION_MIN :
'''
print ' removing edge '
v1 = e . v1
v2 = e . v2
v1 . co = v2 . co = ( v1 . co + v2 . co ) * 0.5
v1 . sel = v2 . sel = 1
me . remDoubles ( 0.001 )
me = ob . getData ( mesh = 1 )
break
'''
# Remove edge in python
print ' removing edge '
v1 = ed . v1
v2 = ed . v2
v1 . co = v2 . co = ( v1 . co + v2 . co ) * 0.5
removeDouble ( v1 , v2 , me )
me = ob . getData ( mesh = 1 )
break
"""
if EDGE_COUNT :
me . subdivide ( 1 )
2006-01-21 12:33:58 +00:00
me = ob . getData ( mesh = 1 )
filter ( lambda ed : setattr ( ed , ' flag ' , 32 ) , me . edges )
2006-01-17 23:50:06 +00:00
# Deselect all, we know theres only 2 selected
'''
for ee in me . edges :
if ee . flag & SEL_FLAG :
#ee.flag &= ~SEL_FLAG
ee . flag = 32
elif l < RESOLUTION_MIN :
print ' removing edge '
e . v1 . co = e . v2 . co = ( e . v1 . co + e . v2 . co ) * 0.5
me . remDoubles ( 0.001 )
break
'''
# Done subdividing
# Now remove doubles
#print Mesh.SelectModes['VERT']
#Mesh.Mode(Mesh.SelectModes['VERTEX'])
filter ( lambda v : setattr ( v , ' sel ' , 1 ) , me . verts )
filter ( lambda v : setattr ( v [ 0 ] , ' sel ' , 0 ) , brush_verts )
# Cycling editmode is too slow.
remdoubles = False
for ed in me . edges :
if ( not ed . v1 . sel ) and ( not ed . v1 . sel ) :
2006-01-18 00:22:22 +00:00
if XPLANE_CLIP :
# If 1 vert is on the edge and abother is off dont collapse edge.
if ( abs ( ed . v1 . co . x ) < 0.001 ) != \
( abs ( ed . v2 . co . x ) < 0.001 ) :
continue
2006-01-17 23:50:06 +00:00
l = ( ed . v1 . co - ed . v2 . co ) . length
if l < RESOLUTION_MIN :
ed . v1 . sel = ed . v2 . sel = 1
newco = ( ed . v1 . co + ed . v2 . co ) * 0.5
2006-04-11 02:41:11 +00:00
#ed.v1.co.x = ed.v2.co.x = newco.x
#ed.v1.co.y = ed.v2.co.y = newco.y
#ed.v1.co.z = ed.v2.co.z = newco.z
ed . v1 . co [ : ] = ed . v2 . co [ : ] = newco
2006-01-17 23:50:06 +00:00
remdoubles = True
#if remdoubles:
filter ( lambda v : setattr ( v , ' sel ' , 0 ) , me . verts )
#Mesh.Mode(Mesh.SelectModes['EDGE'])
# WHILE OVER
# Clean up selection.
#for v in me.verts:
# v.sel = 0
'''
for ee in me . edges :
if ee . flag & SEL_FLAG :
ee . flag & = ~ SEL_FLAG
#ee.flag = 32
'''
filter ( lambda ed : setattr ( ed , ' flag ' , 32 ) , me . edges )
if XPLANE_CLIP :
filter ( lambda v : setattr ( v . co , ' x ' , max ( 0 , v . co . x ) ) , me . verts )
me . update ( )
#Window.SetCursorPos(best_isect.x, best_isect.y, best_isect.z)
Window . Redraw ( Window . Types . VIEW3D )
#Window.DrawProgressBar(1.0, '')
if STATIC_MESH :
#try:
mesh_static . verts = None
print len ( mesh_static . verts )
mesh_static . update ( )
#except:
# pass
if FIX_TOPOLOGY :
fix_topolagy ( me )
2006-01-20 02:45:02 +00:00
# Remove short edges of we have edaptive geometry enabled.
if ADAPTIVE_GEOMETRY :
Mesh . Mode ( Mesh . SelectModes [ ' VERTEX ' ] )
filter ( lambda v : setattr ( v , ' sel ' , 1 ) , me . verts )
me . remDoubles ( 0.001 )
print ' removing doubles '
me = ob . getData ( mesh = 1 ) # Get new vert data
Blender . event = Draw . LEFTMOUSE
2006-01-17 23:50:06 +00:00
Mesh . Mode ( Mesh . SelectModes [ ' EDGE ' ] )
2006-01-20 02:45:02 +00:00
2006-01-17 23:50:06 +00:00
if i :
Window . EditMode ( 1 )
if not is_editmode : # User was in edit mode, so stay there.
Window . EditMode ( 0 )
print ' 100 draws in %.6f ' % ( ( ( Blender . sys . time ( ) - time ) / float ( i ) ) * 100 )
2006-04-11 02:41:11 +00:00
Blender . event = None
2006-01-17 23:50:06 +00:00
if __name__ == ' __main__ ' :
event_main ( )