= line ending fix =
[blender.git] / release / scripts / animation_trajectory.py
1 #!BPY
2
3 """ Registration info for Blender menus: <- these words are ignored
4 Name: 'Trajectory'
5 Blender: 242
6 Group: 'Animation'
7 Tip: 'See Trajectory of selected object'
8 """
9
10 __author__ = '3R - R3gis'
11 __version__ = '2.43'
12 __url__ = ["Script's site , http://blenderfrance.free.fr/python/Trajectory_en.htm","Author's site , http://cybercreator.free.fr", "French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender"]
13 __email__=["3R, r3gis@free.fr"]
14
15
16 __bpydoc__ = """
17
18 Usage:
19
20 * Launch with alt+P (or put it in .script folder)
21
22 Allow to see in real time trajectory of selected object.
23
24 On first run, it ask you
25 - If you want that actually selected object have they trajectory always shown
26 - If you want to use Space Handler or a Scriptlink in Redraw mode
27 - Future and Past : it is the frame in past and future
28 of the beggining and the end of the path
29 - Width of line that represent the trajectory
30
31 Then the object's trajectory will be shown in all 3D areas.
32 When trajectory is red, you can modifiy it by moving object.
33 When trajectory is blue and you want to be able to modify it, inser a Key (I-Key)
34
35 Points appears on trajectory :
36 - Left Clic to modify position
37 - Right Clic to go to the frame it represents
38
39 Notes:<br>
40 In scriptlink mode, it create one script link so make sure that 'Enable Script Link' toogle is on
41 In SpaceHandler mode, you have to go in View>>SpaceHandlerScript menu to activate Trajectory
42
43
44 """
45
46
47 # --------------------------------------------------------------------------
48 # ***** BEGIN GPL LICENSE BLOCK *****
49 #
50 # Copyright (C) 2004-2006: Regis Montoya
51 #
52 # This program is free software; you can redistribute it and/or
53 # modify it under the terms of the GNU General Public License
54 # as published by the Free Software Foundation; either version 2
55 # of the License, or (at your option) any later version.
56 #
57 # This program is distributed in the hope that it will be useful,
58 # but WITHOUT ANY WARRANTY; without even the implied warranty of
59 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
60 # GNU General Public License for more details.
61 #
62 # You should have received a copy of the GNU General Public License
63 # along with this program; if not, write to the Free Software Foundation,
64 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
65 #
66 # ***** END GPL LICENCE BLOCK *****
67 # --------------------------------------------------------------------------
68 #################################
69 # by 3R - 26/08/05
70 # for any problem :
71 #       r3gis@free.fr
72 #       ou sur le newsgroup:
73 # http://zoo-logique.org/3D.Blender/
74 #################################
75 #Many thanks to cambo for his fixes
76 #################################
77
78
79
80 import Blender
81
82
83 scene= Blender.Scene.GetCurrent()
84
85         
86 #Writing
87 def write_script(name, script):
88         global scene
89         #List texts and their name
90         #write : type of writing : 1->New, 2->Overwrite
91         scripting= None
92         for text in Blender.Text.Get():
93                 if text.name==name and text.asLines()[1] != "#"+str(__version__):
94                         scripting= Blender.Text.Get(name)
95                         scripting.write(script)
96                         break
97         
98         if not scripting:
99                 scripting= Blender.Text.New(name)
100                 scripting.write(script)
101
102
103 #Linking                        
104 def link_script(name, type):
105         global scene
106         try:
107                 scene.getScriptLinks(type).index(name) # Does nothing. just fails of the script isnt there.
108         except:
109                 scene.addScriptLink(name, type)
110
111
112 #Deleting of a text
113 def text_remove(name):
114         global scene
115         #try to delete text if already linked
116         try:
117                 text= Blender.Text.Get(name)
118                 # Texte.clear()
119                 scene.clearScriptLinks([name])
120                 Blender.Text.unlink(text)
121         except:
122                 print('---Initialisation of Trajectory_'+str(__version__)+'.py---')
123
124 #Whether is already running, also check if it's the last version of the script : second line contain the version fo the script
125 ask_modif= 0 # Default
126 for text in Blender.Text.Get():
127         if text.name == 'Trajectory' and text.asLines()[1] == "#"+str(__version__):
128                 #We ask if script modify his seetings, keep it or stop script
129                 ask_modif= Blender.Draw.PupMenu("Script already launch %t|Modify settings%x0|Keep settings%x1|Stop script%x2|")
130                 if ask_modif==-1: # user canceled.
131                         ask_modif= 1 
132                 break
133
134 selection_mode= 0
135 future= 35
136 past= 20
137 width= 2
138
139 #In modify case
140 if ask_modif==0:
141         handle_mode= Blender.Draw.Create(0)
142         selection_mode= Blender.Draw.Create(0)
143         future= Blender.Draw.Create(35)
144         past= Blender.Draw.Create(20)
145         width= Blender.Draw.Create(2)
146
147         block= []
148         block.append(("Use Space Handlers", handle_mode, "You have to activate for each area by View>>SpaceHandler")) #You can delete this option...
149         block.append(("Always draw for sel.", selection_mode, "Selected object will have their trajectory always shown"))
150         block.append(("Past :", past, 1, 900))
151         block.append(("Futur:", future, 1, 900))
152         block.append(("Width:", width, 1,5))
153         
154         if not Blender.Draw.PupBlock("Trajectory seetings", block):
155                 ask_modif=1
156         
157         handle_mode= handle_mode.val
158         selection_mode= selection_mode.val
159         future= future.val
160         past= past.val
161         width= width.val
162
163
164 #put names of selected objects in objects_select if option choosen by user
165 if selection_mode==1:
166         objects_select= [ob.name for ob in Blender.Object.GetSelected()]
167 else:
168         objects_select= []
169         
170
171 try:
172         if handle_mode==1:
173                 DrawPart="#SPACEHANDLER.VIEW3D.DRAW\n"
174         else:
175                 DrawPart="#!BPY\n"
176 except:DrawPart="#BadlyMade"
177         
178
179 #Here is the script to write in Blender and to link, options are also written now
180 DrawPart=DrawPart+"#"+str(__version__)+"""
181 #This script is a part of Trajectory.py and have to be linked to the scene in Redraw if not in HANDLER mode.
182 #Author : 3R - Regis Montoya
183 #It's better to use the Trajectory_"version_number".py
184 #You can modify the two following value to change the path settings
185 future="""+str(future)+"""
186 past="""+str(past)+"""
187 object_init_names="""+str(objects_select)+"""
188
189
190 import Blender, math
191 from Blender import BGL, Draw, Ipo
192 from Blender.BGL import *
193 from Blender.Draw import *
194 from math import *
195
196 from Blender.Mathutils import Vector
197
198 #take actual frame
199 frameC=Blender.Get('curframe')
200 render_context=Blender.Scene.getCurrent().getRenderingContext()
201 #ajust number of frames with NewMap and OldMapvalue values
202 k=1.00*render_context.oldMapValue()/render_context.newMapValue()
203 if k<1:
204         tr=-1*int(log(k*0.1, 10))
205 else:
206         tr=-1*int(log(k, 10))
207 #The real and integer frame to compare to ipos keys frames
208 frameCtr=round(frameC*k, tr)
209 frameCr=frameC*k
210 frameC=int(round(frameC*k, 0))
211
212
213 #List objects that we have to show trajectory in $objects
214 # In this case, using a dict for unique objects is the fastest way.
215 object_dict= dict([(ob.name, ob) for ob in Blender.Object.GetSelected()])
216 for obname in object_init_names:
217         try: # checking if its alredy there.
218                 object_dict[obname] 
219         except: # Object is not there.
220                 try: # Object may be removed.
221                         object_dict[obname]= Blender.Object.Get(obname)
222                 except:
223                         pass # object was removed.
224
225 #This fonction give the resulting matrix of all parents at a given frame
226 #parent_list is the list of all parents [object, matrix, locX_ipo, locY, Z, rotX, Y, Z, sizeX, Y, Z] of current object
227 def matrixForTraj(frame, parent_list):
228         DecMatC=Blender.Mathutils.Matrix([1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1])
229
230         for parent_data in parent_list:
231                 parent_ob=      parent_data[0]
232                 
233                 try:    X=      parent_data[5][frame]*pi/18
234                 except: X=      parent_ob.RotX
235                 try:    Y=      parent_data[6][frame]*pi/18
236                 except: Y=      parent_ob.RotY
237                 try:    Z=      parent_data[7][frame]*pi/18
238                 except: Z=      parent_ob.RotZ
239                 try:    LX=     parent_data[2][frame]
240                 except: LX=     parent_ob.LocX
241                 try:    LY=     parent_data[3][frame]
242                 except: LY=     parent_ob.LocY
243                 try:    LZ=     parent_data[4][frame]
244                 except: LZ=     parent_ob.LocZ
245                 try:    SX=     parent_data[8][frame]
246                 except: SX=     parent_ob.SizeX
247                 try:    SY=     parent_data[9][frame]
248                 except: SY=     parent_ob.SizeY
249                 try:    SZ=     parent_data[10][frame]
250                 except: SZ=     parent_ob.SizeZ
251
252                 NMat=Blender.Mathutils.Matrix([cos(Y)*cos(Z)*SX,SX*cos(Y)*sin(Z),-SX*sin(Y),0],
253                 [(-cos(X)*sin(Z)+sin(Y)*sin(X)*cos(Z))*SY,(sin(X)*sin(Y)*sin(Z)+cos(X)*cos(Z))*SY,sin(X)*cos(Y)*SY,0],
254                 [(cos(X)*sin(Y)*cos(Z)+sin(X)*sin(Z))*SZ,(cos(X)*sin(Y)*sin(Z)-sin(X)*cos(Z))*SZ,SZ*cos(X)*cos(Y),0],
255                 [LX,LY,LZ,1])
256                 DecMatC=DecMatC*parent_data[1]*NMat
257         return DecMatC
258
259 #####
260 TestLIST=[]
261 matview=Blender.Window.GetPerspMatrix()
262 ###########
263 #Fonction to draw trajectories
264 ###########
265
266 def Trace_Traj(ob):
267                 global TestLIST, matview
268                 #we draw trajectories for all objects in list
269         
270                 LocX=[]
271                 LocY=[]
272                 LocZ=[]
273                 #List with trajectories' vertexs
274                 vertexX=[]
275                 
276                 contextIpo= ob.ipo
277                 if contextIpo:
278                         ipoLocX=contextIpo[Ipo.OB_LOCX]
279                         ipoLocY=contextIpo[Ipo.OB_LOCY]
280                         ipoLocZ=contextIpo[Ipo.OB_LOCZ]
281                         ipoTime=contextIpo[Ipo.OB_TIME]
282                 else: # only do if there is no IPO (if no ipo curves : return None object and don't go in this except)
283                         ipoLocX= ipoLocY= ipoLocZ= ipoTime= None
284                 
285                 if ipoTime:
286                         return 0
287                 
288                 #Get all parents of ob
289                 parent=ob.parent
290                 backup_ob= ob
291                 child= ob
292                 parent_list= []
293                 
294                 #Get parents's infos :
295                 #list of [name, initial matrix at make parent, ipo in X,Y,Z,rotX,rotY,rotZ,sizeX,Y,Z]
296                 while parent:
297                         Init_Mat=Blender.Mathutils.Matrix(child.getMatrix('worldspace')) #must be done like it (it isn't a matrix otherwise)
298                         Init_Mat.invert()
299                         Init_Mat=Init_Mat*child.getMatrix('localspace')
300                         Init_Mat=parent.getMatrix()*Init_Mat
301                         Init_Mat.invert()
302         
303                         contextIpo= parent.ipo # None or IPO
304                         if contextIpo:
305                                 ipo_Parent_LocX=contextIpo[Ipo.OB_LOCX]
306                                 ipo_Parent_LocY=contextIpo[Ipo.OB_LOCY]
307                                 ipo_Parent_LocZ=contextIpo[Ipo.OB_LOCZ]
308                                 ipo_Parent_RotX=contextIpo[Ipo.OB_ROTX]
309                                 ipo_Parent_RotY=contextIpo[Ipo.OB_ROTY]
310                                 ipo_Parent_RotZ=contextIpo[Ipo.OB_ROTZ]
311                                 ipo_Parent_SizeX=contextIpo[Ipo.OB_SIZEX]
312                                 ipo_Parent_SizeY=contextIpo[Ipo.OB_SIZEY]
313                                 ipo_Parent_SizeZ=contextIpo[Ipo.OB_SIZEZ]
314                         else:
315                                 ipo_Parent_LocX=ipo_Parent_LocY=ipo_Parent_LocZ=\
316                                 ipo_Parent_RotX=ipo_Parent_RotY=ipo_Parent_RotZ=\
317                                 ipo_Parent_SizeX=ipo_Parent_SizeY=ipo_Parent_SizeZ= None
318                         
319                         parent_list.append([parent, Init_Mat, ipo_Parent_LocX, ipo_Parent_LocY, ipo_Parent_LocZ, ipo_Parent_RotX, ipo_Parent_RotY, ipo_Parent_RotZ, ipo_Parent_SizeX, ipo_Parent_SizeY, ipo_Parent_SizeZ])
320         
321                         child=parent
322                         parent=parent.parent
323                         
324                 #security : if one of parents object are a path>>follow : trajectory don't work properly so it have to draw nothing
325                 for parent in parent_list:
326                         if parent[0].type == 'Curve':
327                                 if parent[0].data.flag & 1<<4: # Follow path, 4th bit
328                                         return 1
329                 
330                 #ob >> re-assign obj and not parent
331                 ob= backup_ob
332                 ob= backup_ob
333                 
334                 
335                 if ipoLocX: LXC= ipoLocX[frameC]
336                 else:           LXC= ob.LocX
337                 if ipoLocY:     LYC= ipoLocY[frameC]
338                 else:           LYC= ob.LocY
339                 if ipoLocZ:     LZC= ipoLocZ[frameC]
340                 else:           LZC= ob.LocZ
341
342                 vect= Vector([ob.LocX, ob.LocY, ob.LocZ, 1])
343                 color=[0, 1]    
344         
345                 #If trajectory is being modified and we are at a frame where a ipo key already exist
346                 if round(ob.LocX, 5)!=round(LXC, 5):
347                         for bez in ipoLocX.bezierPoints:
348                                 if round(bez.pt[0], tr)==frameCtr:
349                                         bez.pt = [frameCr, vect[0]]
350                         ipoLocX.recalc()
351                 if round(ob.LocY, 5)!=round(LYC, 5):
352                         for bez in ipoLocY.bezierPoints:
353                                 if round(bez.pt[0], tr)==frameCtr:
354                                         bez.pt = [frameCr, vect[1]]
355                         ipoLocY.recalc()
356                 if round(ob.LocZ, 5)!=round(LZC, 5):
357                         for bez in ipoLocZ.bezierPoints:
358                                 if round(bez.pt[0], tr)==frameCtr:
359                                         bez.pt = [frameCr, vect[2]]
360                         ipoLocZ.recalc()
361                 
362                 #change trajectory color if at an ipoKey
363                 VertexFrame=[]
364                 bezier_Coord=0
365                 if ipoLocX: # FIXED like others it was just in case ipoLocX==None
366                         for bez in ipoLocX.bezierPoints:
367                                 bezier_Coord=round(bez.pt[0], tr)
368                                 if bezier_Coord not in VertexFrame:
369                                         VertexFrame.append(bezier_Coord)
370                                 if bezier_Coord==frameCtr:
371                                                 color=[1, color[1]-0.3]
372                 if ipoLocY: # FIXED
373                         for bez in ipoLocY.bezierPoints:
374                                 bezier_Coord=round(bez.pt[0], tr)
375                                 if bezier_Coord not in VertexFrame:
376                                         VertexFrame.append(bezier_Coord)
377                                 if round(bez.pt[0], tr)==frameCtr:
378                                                 color=[1, color[1]-0.3]
379                 if ipoLocZ: # FIXED
380                         for bez in ipoLocZ.bezierPoints:
381                                 bezier_Coord=round(bez.pt[0], tr)
382                                 if bezier_Coord not in VertexFrame:
383                                         VertexFrame.append(bezier_Coord)
384                                 if round(bez.pt[0], tr)==frameCtr:
385                                                 color=[1, color[1]-0.3]
386                 
387         
388                 #put in LocX, LocY and LocZ all points of trajectory
389                 for frame in xrange(frameC-past, frameC+future):
390                         DecMat=matrixForTraj(frame, parent_list)
391
392                         if ipoLocX: LX= ipoLocX[frame]
393                         else:           LX= ob.LocX
394                         if ipoLocY:     LY= ipoLocY[frame]
395                         else:           LY= ob.LocY
396                         if ipoLocZ:     LZ= ipoLocZ[frame]
397                         else:           LZ= ob.LocZ
398                         
399                         vect=Vector(LX, LY, LZ)*DecMat
400                         LocX.append(vect[0])
401                         LocY.append(vect[1])
402                         LocZ.append(vect[2])
403         
404                 
405                 #draw part : get current view
406                 MatPreBuff= [matview[i][j] for i in xrange(4) for j in xrange(4)]
407                         
408                 MatBuff=BGL.Buffer(GL_FLOAT, 16, MatPreBuff)
409                 
410                 glLoadIdentity()
411                 glMatrixMode(GL_PROJECTION)
412                 glPushMatrix()
413                 glLoadMatrixf(MatBuff)
414                 
415                 #draw trajectory line
416                 glLineWidth("""+str(width)+""")
417                 
418                 glBegin(GL_LINE_STRIP)
419                 for i in xrange(len(LocX)):
420                         glColor3f((i+1)*1.00/len(LocX)*color[0], 0, (i+1)*1.00/len(LocX)*color[1])
421                         glVertex3f(LocX[i], LocY[i], LocZ[i])
422                 
423                 glEnd() 
424                 
425                 #draw trajectory's "vertexs"
426                 if not Blender.Window.EditMode():
427                         glPointSize(5)
428                         glBegin(GL_POINTS)
429                         TestPOINTS=[]
430                         TestFRAME=[]
431                         i=0
432                         for frame in VertexFrame:
433                                 ix=int(frame)-frameC+past
434                                 if ix>=0 and ix<len(LocX):
435                                         glColor3f(1, 0.7, 0.2)
436                                         glVertex3f(LocX[ix], LocY[ix], LocZ[ix])
437                                         TestPOINTS.append(Vector([LocX[ix], LocY[ix], LocZ[ix], 1]))
438                                         TestFRAME.append(int(frame))
439                                         i+=1
440                         glEnd()
441                         #this list contains info about where to check if we click over a "vertex" in 3D view
442                         TestLIST.append((ob, TestPOINTS, TestFRAME))
443                 
444                 glLineWidth(1)
445                 return 0
446
447
448 for ob in object_dict.itervalues():
449         Trace_Traj(ob)
450
451 ###########
452 #Fonction to handle trajectories
453 ###########
454
455 def Manip():
456         #use TestLIST and matview defined by Trace_Traj
457         global TestLIST, matview
458         for screen in Blender.Window.GetScreenInfo(Blender.Window.Types.VIEW3D):
459                 if screen['id']==Blender.Window.GetAreaID():
460                         x0, y0, x1, y1= screen['vertices']
461                         break
462         
463         #Projection of GL matrix in 3D view
464         glPushMatrix()
465         glMatrixMode(GL_PROJECTION)
466         glPushMatrix()
467         glLoadIdentity()
468         #Global coordinates' matrix
469         glOrtho(x0, x1, y0, y1, -1, 0)
470         glMatrixMode(GL_MODELVIEW)
471         glLoadIdentity()
472         #Test mouse clics and other events
473         
474         
475         if Blender.Window.QTest():
476                 evt, val= Blender.Window.QRead()
477                 if (evt==LEFTMOUSE or evt==RIGHTMOUSE) and not Blender.Window.EditMode():
478                         mouse_co=Blender.Window.GetMouseCoords()
479                         #if click on trajectory "vertexs"...
480                         for ob, TestPOINTS, TestFRAME in TestLIST: # ob is now used, line 552 to know what object it had to select
481                                 for k, Vect in enumerate(TestPOINTS):
482                                         proj=Vect*matview
483                                         
484                                         pt=[(proj[0]/proj[3])*(x1-x0)/2+(x1+x0)/2, (proj[1]/proj[3])*(y1-y0)/2+(y1+y0)/2]
485
486                                         if mouse_co[0]<pt[0]+4 and mouse_co[0]>pt[0]-4 and mouse_co[1]>pt[1]-4 and mouse_co[1]<pt[1]+4:
487                                                 if evt==LEFTMOUSE:
488                                                         #remember current selected object
489                                                         object_names=[obj.name for obj in Blender.Object.GetSelected()]
490                                                         #this script allow to simulate a GKey, but I have to write a script
491                                                         #another way would made a infinit redraw or don't allow to move object
492                                                         #it auto unlink and delete itself
493                                                         script=\"\"\"
494 import Blender
495 from Blender import Draw, Window
496 from Blender.Window import *
497 from Blender.Draw import *
498
499 from Blender.Mathutils import Vector
500
501 # The following code is a bit of a hack, it allows clicking on the points and dragging directly
502 #It simulate user press GKey 
503 #It also set the cursor position at center (because user have previously clic on area and moved the cursor): 
504 #And I can't get previous cursor position : redraw appear after it has been moved
505 #If there is no better way you can remove this comments
506 f= GetAreaID()
507 SetCursorPos(0,0,0)
508 #SetKeyQualifiers(1) #FIXED : the bug in older versions seems to have been fixed
509 SetKeyQualifiers(0)
510 QAdd(f, Blender.Draw.GKEY, 1, 0)
511 QHandle(f)
512 Blender.Redraw()
513 done=0
514 while not done:
515         while Blender.Window.QTest():
516                 ev=Blender.Window.QRead()[0]
517                 if ev not in (4, 5, 18, 112, 213): #all event needed to move object
518                         #SetKeyQualifiers(1) #FIXED too, same reason that above
519                         #SetKeyQualifiers(0)
520                         SetKeyQualifiers(Blender.Window.GetKeyQualifiers())
521                         QAdd(f, ev, 1, 0)
522                         QHandle(f)
523                         Blender.Redraw()
524                 if ev in (RIGHTMOUSE, LEFTMOUSE, ESCKEY):
525                         done=1
526 Blender.Set('curframe',\"\"\"+str(Blender.Get('curframe'))+\"\"\")
527 Blender.Object.GetSelected()[0].sel= False
528 for obname in \"\"\"+str(object_names)+\"\"\":
529         ob=Blender.Object.Get(obname)
530         ob.sel= True
531 SetCursorPos(0,0,0)
532 scripting=Blender.Text.Get('Edit_Trajectory')
533 scripting.clear()
534 Blender.Text.unlink(scripting)
535                                                 \"\"\"
536                                                         
537                                                         #FIXED Edit_Trajectory was longer : all SetKeyQualifiers removed
538                                                         scene=Blender.Scene.GetCurrent()
539                                                         try:
540                                                                 scripting=Blender.Text.Get('Edit_Trajectory')
541                                                                 scripting.clear()
542                                                         except:
543                                                                 scripting=Blender.Text.New('Edit_Trajectory')
544                                                         
545                                                         scripting.write(script)
546                                                         #script= scripting #FIXED seems not needed anymore
547                                                         
548                                                         #Go to frame that correspond to selected "vertex"
549                                                         Blender.Set('curframe', TestFRAME[k])
550                                                         
551                                                         scene.objects.selected = [] #un select all objects
552                                                         
553                                                         #FIXED TestLIST[j][0].sel=0, but no j. So ob.sel and above variable changed in obj
554                                                         ob.sel= True
555                                                         Blender.Run('Edit_Trajectory')
556                                                 
557                                                 #work well now !!!
558                                                 if evt==RIGHTMOUSE :
559                                                         Blender.Set('curframe', TestFRAME[k])
560
561 Manip()
562 #retrieve a normal matrix
563 glPopMatrix()
564 glMatrixMode(GL_PROJECTION)
565 glPopMatrix()
566 glMatrixMode(GL_MODELVIEW)
567 """
568
569 if ask_modif==0:
570         text_remove('Trajectory')
571         write_script('Trajectory', DrawPart)
572         if handle_mode==1:
573                 Blender.UpdateMenus()
574         else:
575                 link_script('Trajectory', 'Redraw')
576 if ask_modif==2:
577         text_remove('Trajectory')
578         print("---End of Trajectory_"+str(__version__)+".py---\n---   Thanks for use   ---")