added list2MeshWeight and meshWeight2List - faster then the dict equivilents and...
[blender.git] / release / scripts / bpymodules / mesh_gradient.py
1 # This is not to be used directly, vertexGradientPick can be used externaly
2
3 import Blender
4 import BPyMesh
5 import BPyWindow
6
7
8 mouseViewRay= BPyWindow.mouseViewRay
9 from Blender import Mathutils, Window, Scene, Draw, sys
10 from Blender.Mathutils import CrossVecs, Vector, Intersect, LineIntersect, AngleBetweenVecs
11 LMB= Window.MButs['L']
12
13 def mouseup():
14         # Loop until click
15         mouse_buttons = Window.GetMouseButtons()
16         while not mouse_buttons & LMB:
17                 sys.sleep(10)
18                 mouse_buttons = Window.GetMouseButtons()
19         while mouse_buttons & LMB:
20                 sys.sleep(10)
21                 mouse_buttons = Window.GetMouseButtons()
22
23 def mousedown_wait():
24         # If the menu has just been pressed dont use its mousedown,
25         mouse_buttons = Window.GetMouseButtons()
26         while mouse_buttons & LMB:
27                 mouse_buttons = Window.GetMouseButtons()
28
29 eps= 0.0001
30 def vertexGradientPick(ob, MODE):
31         #MODE 0 == VWEIGHT,  1 == VCOL 
32         
33         me= ob.getData(mesh=1)
34         if not me.faceUV:       me.faceUV= True
35         
36         Window.DrawProgressBar (0.0, '')
37         
38         mousedown_wait()
39         
40         if MODE==0:
41                 act_group= me.activeGroup
42                 if act_group == None:
43                         mousedown_wait()
44                         Draw.PupMenu('Error, mesh has no active group.')
45                         return
46         
47         # Loop until click
48         Window.DrawProgressBar (0.25, 'Click to set gradient start')
49         mouseup()
50         
51         obmat= ob.matrixWorld
52         screen_x, screen_y = Window.GetMouseCoords()
53         mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat)
54         if not mouseInView or not OriginA:
55                 return
56         
57         # get the mouse weight
58         
59         if MODE==0:
60                 pickValA= BPyMesh.pickMeshGroupWeight(me, act_group, OriginA, DirectionA)
61         if MODE==1:
62                 pickValA= BPyMesh.pickMeshGroupVCol(me, OriginA, DirectionA)
63         
64         Window.DrawProgressBar (0.75, 'Click to set gradient end')
65         mouseup()
66         
67         TOALPHA= Window.GetKeyQualifiers() & Window.Qual.SHIFT
68         
69         screen_x, screen_y = Window.GetMouseCoords()
70         mouseInView, OriginB, DirectionB = mouseViewRay(screen_x, screen_y, obmat)
71         if not mouseInView or not OriginB:
72                 return
73         
74         if not TOALPHA: # Only get a second opaque value if we are not blending to alpha
75                 if MODE==0:     pickValB= BPyMesh.pickMeshGroupWeight(me, act_group, OriginB, DirectionB)
76                 else:
77                         pickValB= BPyMesh.pickMeshGroupVCol(me, OriginB, DirectionB)
78         else:
79                 if MODE==0: pickValB= 0.0
80                 else: pickValB= [0.0, 0.0, 0.0] # Dummy value
81         
82         # Neither points touched a face
83         if pickValA == pickValB == None:
84                 return
85         
86         # clicking on 1 non face is fine. just set the weight to 0.0
87         if pickValA==None:
88                 pickValA= 0.0
89                 
90                 # swap A/B
91                 OriginA, OriginB= OriginB, OriginA
92                 DirectionA, DirectionB= DirectionB, DirectionA
93                 pickValA, pickValB= pickValA, pickValB
94                 
95                 TOALPHA= True
96                 
97         if pickValB==None:
98                 pickValB= 0.0
99                 TOALPHA= True
100         
101         
102         # set up 2 lines so we can measure their distances and calc the gradient
103         
104         # make a line 90d to the grad in screenspace.
105         if (OriginA-OriginB).length <= eps: # Persp view. same origin different direction
106                 cross_grad= CrossVecs(DirectionA, DirectionB)
107                 ORTHO= False
108                 
109         else: # Ortho - Same direction, different origin
110                 cross_grad= CrossVecs(DirectionA, OriginA-OriginB)
111                 ORTHO= True
112                 
113         cross_grad= cross_grad.normalize() * 100
114         
115         lineA= (OriginA, OriginA+(DirectionA*100))
116         lineB= (OriginB, OriginB+(DirectionB*100))
117         
118         if not ORTHO:
119                 line_angle= AngleBetweenVecs(lineA[1], lineB[1])/2
120                 line_mid= (lineA[1]+lineB[1])*0.5
121         
122         FSEL= Blender.Mesh.FaceFlags.SELECT
123
124         VSEL= [False] * (len(me.verts))
125         
126         # Get the selected faces and apply the selection to the verts.
127         for f in me.faces:
128                 if f.flag & FSEL:
129                         for v in f.v:
130                                 VSEL[v.index]= True
131         groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
132         
133         
134         
135         def grad_weight_from_co(v):
136                 '''
137                 Takes a vert and retuens its gradient radio between A and B
138                 '''
139                 
140                 if not VSEL[v.index]: # Not bart of a selected face?
141                         return None, None
142                 
143                 v_co= v.co
144                 # make a line 90d to the 2 lines the user clicked.
145                 vert_line= (v_co - cross_grad, v_co + cross_grad)
146                 
147                 xA= LineIntersect(vert_line[0], vert_line[1], lineA[0], lineA[1])
148                 xB= LineIntersect(vert_line[0], vert_line[1], lineB[0], lineB[1])
149                 
150                 if not xA or not xB: # Should never happen but support it anyhow
151                         return None, None
152                 
153                 wA= (xA[0]-xA[1]).length
154                 wB= (xB[0]-xB[1]).length
155                 
156                 wTot= wA+wB
157                 if not wTot: # lines are on the same point.
158                         return None, None
159                 
160                 '''
161                 Get the length of the line between both intersections on the 
162                 2x view lines.
163                 if the dist between  lineA+VertLine and lineB+VertLine is 
164                 greater then the lenth between lineA and lineB intersection points, it means
165                 that the verts are not inbetween the 2 lines.
166                 '''
167                 lineAB_length= (xA[1]-xB[1]).length
168                 
169                 # normalzie
170                 wA= wA/wTot
171                 wB= wB/wTot
172                 
173                 if ORTHO: # Con only use line length method with parelelle lines
174                         if wTot > lineAB_length+eps:
175                                 # vert is outside the range on 1 side. see what side of the grad
176                                 if wA>wB:               wA, wB= 1.0, 0.0
177                                 else:                   wA, wB= 0.0, 1.0
178                 else:
179                         # PERSP, lineA[0] is the same origin as lineB[0]
180                         
181                         # Either xA[0] or xB[0]  can be used instead of a possible x_mid between the 2
182                         # as long as the point is inbetween lineA and lineB it dosent matter.
183                         a= AngleBetweenVecs(lineA[0]-xA[0], line_mid)
184                         if a>line_angle:
185                                 # vert is outside the range on 1 side. see what side of the grad
186                                 if wA>wB:               wA, wB= 1.0, 0.0
187                                 else:                   wA, wB= 0.0, 1.0
188                 
189                 return wA, wB
190                 
191         
192         grad_weights= [grad_weight_from_co(v) for v in me.verts]
193         
194         
195         if MODE==0:
196                 for v in me.verts:
197                         i= v.index
198                         if VSEL[i]:
199                                 wA, wB = grad_weights[i]
200                                 if wA != None: # and wB 
201                                         if TOALPHA:
202                                                 # Do alpha by using the exiting weight for 
203                                                 try:            pickValB= vWeightDict[i][act_group]
204                                                 except: pickValB= 0.0 # The weights not there? assume zero
205                                         # Mix2 2 opaque weights
206                                         vWeightDict[i][act_group]= pickValB*wA + pickValA*wB
207         
208         else: # MODE==1 VCol
209                 for f in me.faces:
210                         if f.flag & FSEL:
211                                 f_v= f.v
212                                 for i in xrange(len(f_v)):
213                                         v= f_v[i]
214                                         wA, wB = grad_weights[v.index]
215                                         
216                                         c= f.col[i]
217                                         
218                                         if TOALPHA:
219                                                 pickValB= c.r, c.g, c.b
220                                         
221                                         c.r = int(pickValB[0]*wA + pickValA[0]*wB)
222                                         c.g = int(pickValB[1]*wA + pickValA[1]*wB)
223                                         c.b = int(pickValB[2]*wA + pickValA[2]*wB)
224                                         
225         
226         
227         
228         # Copy weights back to the mesh.
229         BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
230         Window.DrawProgressBar (1.0, '')
231
232