Scripts:
[blender.git] / release / scripts / disp_paint.py
1 #!BPY
2
3 """ Registration info for Blender menus: <- these words are ignored
4 Name: 'Dispaint'
5 Blender: 233
6 Group: 'Mesh'
7 Tip: 'Use vertex paint color value to modify shape displacing vertices along normal.'
8 """
9
10 # $Id$
11 #
12 #----------------------------------------------
13 # jm soler, displacement paint 03/2002 - > 05/2004:  disp_paintf
14 # Terrain Noise added suugered by Jimmy Haze  
15 #----------------------------------------------
16 # Page officielle :
17 #  http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_displacementpainting.htm
18 # Communiquer les problemes et erreurs sur:
19 #  http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
20 # --------------------------------------------------------------------------
21 # ce script est proposé sous licence GPL pour etre associe
22 # a la distribution de Blender 2.33
23 # --------------------------------------------------------------------------
24 # this script is released under GPL licence
25 # for the Blender 2.33 scripts package
26 # --------------------------------------------------------------------------
27 # ***** BEGIN GPL LICENSE BLOCK *****
28 #
29 # Copyright (C) 2003, 2004: Jean-Michel Soler
30 #
31 # This program is free software; you can redistribute it and/or
32 # modify it under the terms of the GNU General Public License
33 # as published by the Free Software Foundation; either version 2
34 # of the License, or (at your option) any later version.
35 #
36 # This program is distributed in the hope that it will be useful,
37 # but WITHOUT ANY WARRANTY; without even the implied warranty of
38 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
39 # GNU General Public License for more details.
40 #
41 # You should have received a copy of the GNU General Public License
42 # along with this program; if not, write to the Free Software Foundation,
43 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
44 #
45 # ***** END GPL LICENCE BLOCK *****
46 # --------------------------------------------------------------------------
47 #  09/07/04 : Noise functions based on a piece of script by Jimmy Haze.
48 # --------------------------------------------------------------------------
49 import Blender
50 from Blender import *
51 from Blender.Draw import *
52 from Blender.BGL import *
53 from Blender.Noise import *
54 from Blender.Scene  import *
55 sc=Scene.getCurrent()
56
57 # niveau du deplacement
58 ng=0.5
59
60 # noise default
61 NOISE=1
62
63 # profondeur des couleurs primaires rgb
64 maxcol=255.0*3
65
66 # limitation de la zone de travail sur le
67 # le materiau numer mat du tableau d'indices 
68 # des materiaux. Par defaut mat =-1 ce qui signifie 
69 # que toute la surface est traitee
70 mat=[]
71 vindex=[]
72 ORIName=''
73 NEWName=''
74 ERROR=0
75 TextERROR=''
76
77 def copy_transform(ozero,Obis):
78          Obis.setSize(ozero.getSize());
79          Obis.setEuler(ozero.getEuler());
80          Obis.setLocation(ozero.getLocation())
81          return Obis
82
83 def traite_face(f):
84       global vindexm, ng, NOISE
85       global H,lacunarity,octaves,offset,basis
86
87       if ORIENTMenu.val==1:
88          for z in range(len(f.v)):
89             c=0.0
90             if vindex[f.v[z].index]!=0:
91                c=float(f.col[z].r+f.col[z].b+f.col[z].g)/maxcol*ng/vindex[f.v[z].index]
92             else:
93               c=0
94
95             f.v[z].co[0]=f.v[z].co[0]+f.v[z].no[0]*c
96             f.v[z].co[1]=f.v[z].co[1]+f.v[z].no[1]*c 
97             f.v[z].co[2]=f.v[z].co[2]+f.v[z].no[2]*c
98
99       elif ORIENTMenu.val==2:
100           for z in range(len(f.v)): 
101             c=0.0
102             if vindex[f.v[z].index]!=0:
103                c=float(f.col[z].r+f.col[z].b+f.col[z].g)/maxcol*ng/vindex[f.v[z].index]
104             else:
105               c=0
106             for t in range(3):
107                if TAXEList[1][t].val==1:
108                   f.v[z].co[t]=f.v[z].co[t]+c
109  
110       elif ORIENTMenu.val==3 and NOISE<9:
111          for z in range(len(f.v)):
112             c=0.0
113             if vindex[f.v[z].index]!=0:
114                nx=f.v[z].co[0]/4
115                ny=f.v[z].co[1]/4
116                nz=f.v[z].co[2]/4
117                nn = ng + noise((nx,ny,nz),NOISE)
118                c=float(f.col[z].r+f.col[z].b+f.col[z].g)/maxcol*nn/vindex[f.v[z].index]
119             else:
120               c=0
121             f.v[z].co[0]=f.v[z].co[0]+f.v[z].no[0]*c
122             f.v[z].co[1]=f.v[z].co[1]+f.v[z].no[1]*c
123             f.v[z].co[2]=f.v[z].co[2]+f.v[z].no[2]*c
124
125       elif ORIENTMenu.val==3 and NOISE==9:
126          for z in range(len(f.v)):
127             c=0.0
128             if vindex[f.v[z].index]!=0:
129                nx=f.v[z].co[0]/4
130                ny=f.v[z].co[1]/4
131                nz=f.v[z].co[2]/4
132                nn = ng + cellNoise((nx,ny,nz))
133                c=float(f.col[z].r+f.col[z].b+f.col[z].g)/maxcol*nn/vindex[f.v[z].index]
134             else:
135               c=0
136             f.v[z].co[0]=f.v[z].co[0]+f.v[z].no[0]*c
137             f.v[z].co[1]=f.v[z].co[1]+f.v[z].no[1]*c
138             f.v[z].co[2]=f.v[z].co[2]+f.v[z].no[2]*c
139
140       elif ORIENTMenu.val==3 and NOISE==10:
141          for z in range(len(f.v)):
142             c=0.0
143             if vindex[f.v[z].index]!=0:
144                nx=f.v[z].co[0]/4
145                ny=f.v[z].co[1]/4
146                nz=f.v[z].co[2]/4
147                nn = ng + heteroTerrain((nx,ny,nz),H,lacunarity,octaves,offset,basis)
148                c=float(f.col[z].r+f.col[z].b+f.col[z].g)/maxcol*nn/vindex[f.v[z].index]
149             else:
150               c=0
151             f.v[z].co[0]=f.v[z].co[0]+f.v[z].no[0]*c
152             f.v[z].co[1]=f.v[z].co[1]+f.v[z].no[1]*c
153             f.v[z].co[2]=f.v[z].co[2]+f.v[z].no[2]*c
154
155  
156 def paint():
157       global MODEMenu, vindex,ng, mat, ORIName, NEWName     
158       Me=Object.GetSelected()
159       if Me!=[]:
160          if Me[0].getType()=='Mesh':   
161
162                vindex=[]
163                ORIName=Me[0].getData().name
164                me1=NMesh.GetRaw(Me[0].getData().name)
165
166                try:
167                  o=Object.Get('newMESH')
168                  me=o.getData()
169                  me=me1
170
171                except:
172                  o=Object.New('Mesh','newMESH')
173                  sc.link(o)
174                  me=me1
175
176                name='new.002'
177                
178                for m in me.verts:
179                   vindex.append(0)
180
181                for f in me.faces:
182                    for v in f.v:
183                            if MODEMenu.val!=2:
184                               if MODEMenu.val==1:    
185                                  vindex[v.index]+=1
186                               else:
187                                  if v.sel==1:
188                                      vindex[v.index]+=1                                       
189                            else:
190                               #print mat 
191                               if f.mat in mat:
192                                  vindex[v.index]+=1
193                for f in me.faces:
194                  if MODEMenu.val==2: 
195                    if f.mat in mat:
196                       traite_face(f) 
197                  else:
198                       traite_face(f)
199
200
201                Me[0].link(me)
202                #o=copy_transform(Me[0],o)
203
204 def NEWMEcreation(name):
205       nomdelobjet=""; objnumber=-1; namelist=[]
206       obj=Object.Get()
207
208       for ozero in obj:
209          if ozero.getType()=='Mesh': 
210              namelist.append(ozero.getData().name)
211              if ozero.getData().name==name:
212                 objnumber=obj.index(ozero) 
213
214       if objnumber!=-1:
215          ozero=obj[objnumber]
216          nomdelobjet=ozero.getName()
217          Mesh=Blender.NMesh.GetRawFromObject(nomdelobjet)
218
219          n=0; name2=name[:];ok=0  
220
221          while ok==0:
222              for n0 in namelist:
223                  if n0.find(name2)==0:
224                     ok=0;name2=name[0:name.find('.')+1]+'%s'%(n+1) 
225                  else: ok=1
226                  n+=1
227          Mesh.name=name2
228          Obis = Blender.NMesh.PutRaw(Mesh,name2)
229          copy_transform(ozero,Obis)
230          Obis.makeDisplayList()
231
232 def DOCMat_list(TMATList):
233     global mat    
234     Me=Object.GetSelected()
235     if Me!=[]:
236        if Me[0].getType()=='Mesh':
237             me=NMesh.GetRaw(Me[0].getData().name) 
238             if len(me.materials)!=0: 
239                 n=0 
240                 for mat in me.materials:
241                     TMATList[1][n][0]=mat.R
242                     TMATList[1][n][1]=mat.G
243                     TMATList[1][n][2]=mat.B
244                     n+=1
245                 TMATList[0]=n
246             else:
247               TMATList[0]=0
248             return TMATList
249  
250 MOname = "MODE MENU %t|Normal %x1|Material %x2|Selected %x3"
251 ORname = "ORIENT MENU %t|From Normal %x1|Local Axes %x2| Noise %x3"
252 NOname = "NOISE MENU %t|BLENDER %x1|STDPERLIN %x2|NEWPERLIN %x3|VORONOI_F1%x4|VORONOI_F2%x5|VORONOI_F3%x6|VORONOI_F4%x7|VORONOI_F2F1%x8|VORONOI_CRACKLE%x9|CELLNOISE%x10|HETEROTENOISE%x11"
253
254 MODEMenu = Create(1)
255 ORIENTMenu = Create(1)
256 NOISEMenu = Create(1)
257
258 NSIZE = Create(1.0)
259 TDOCMat = Create(0)
260 NRepeat = Create(1)
261
262 H=1.0
263 lacunarity=2.0
264 octaves=5.0
265 offset=1.0
266 basis=3
267
268 HBout=Create(H)
269 lacunarityBout=Create(lacunarity)
270 octavesBout=Create(octaves)
271 offsetBout=Create(offset)
272 basisBout=Create(basis)
273
274 TMATList= [0,[],[]] 
275
276 for t in range(16):
277     TMATList[1].append([0.0,0.0,0.0])
278     TMATList[2].append(Create(0))
279
280 TAXEList=[['X','Y','Z'],[]]
281 for t in range(3):
282     TAXEList[1].append(Create(0))
283
284 glCr=glRasterPos2d
285 glCl3=glColor3f
286 glCl4=glColor4f
287 glRct=glRectf
288
289
290
291 def draw():
292     global MODEMenu, NSIZE, TDOCMat,TMATList, TAXEList
293     global mat, ORIName, NEWName, ORIENTMenu 
294     global NRepeat, ERROR, TextERROR , NOISE, NOISEMenu
295     global HBout,lacunarityBout,octavesBout,offsetBout,basisBout
296     
297     size=Buffer(GL_FLOAT, 4)
298     glGetFloatv(GL_SCISSOR_BOX, size)
299     size= size.list
300
301     for s in [0,1,2,3]: size[s]=int(size[s])
302     
303     glClear(GL_COLOR_BUFFER_BIT)
304
305     glColor3f(0.0,0.0,0.0)
306     glRectf(4,size[3],534,size[3]-32 )
307
308     glColor3f(1.0,1.0,1.0)
309     glRasterPos2f(20, size[3]-15)
310     Text("Script Python de displacement painting")
311
312     glRasterPos2f(20, size[3]-28)
313     Text("Jean-michel Soler, juillet 2004")
314
315    
316     n0=70
317     n1=55
318
319     Button("Create"                ,17  ,5  ,size[3]-n0+16  ,60 ,20)
320     Button("Action"                ,16  ,5  ,size[3]-n0-4  ,60 ,20)
321     Button("Exit"                  ,1   ,5  ,size[3]-n0-24  ,60 ,20)
322     
323     NRepeat=Number("repeat"        ,5   ,5  ,size[3]-n0-50     ,75 ,20, NRepeat.val,1,10)    
324     
325     glColor3f(0.0,0.0,0.0)
326     glRasterPos2f(80  ,size[3]-n0+24)
327     Text("MODE")
328
329     MODEMenu= Menu(MOname,          2  ,80  ,size[3]-n0 ,100,20, MODEMenu.val, "MODE menu.")
330
331     if MODEMenu.val==2:
332        TDOCMat=Toggle("Doc Mat"     ,24  ,180  ,size[3]-n0 ,60 ,20,TDOCMat.val)    
333        if TDOCMat.val==1:
334              #print TMATList 
335              for t in range(TMATList[0]):
336                  glCl3(TMATList[1][t][0],
337                        TMATList[1][t][1],
338                        TMATList[1][t][2]) 
339                  glRct(80+t*40,
340                        size[3]-n0-60,
341                        80+t*40+40,
342                        size[3]-n0-60+40)
343                  TMATList[2][t]=Toggle("%s"%t , 32+t ,80+t*40+5  ,size[3]-n0-50  ,30 , 20,TMATList[2][t].val)
344     glColor3f(1.0,0.3,0.0)
345     glRasterPos2f(80+40+5  ,size[3]-n0-80)
346     if ERROR==1:
347          Text('Last error : '+TextERROR)
348     else:
349          Text('Last error :                      ')
350
351     glColor3f(0.0,0.0,0.0)
352     glRasterPos2f(240  ,size[3]-n0+24)
353     Text("ORIENTATION")
354     ORIENTMenu= Menu(ORname,        3    ,240  ,size[3]-n0 ,100,20, ORIENTMenu.val, "ORIENT menu.")
355
356     if ORIENTMenu.val==2 :
357        for t in range(3):
358           TAXEList[1][t]=Toggle("%s"%TAXEList[0][t],
359                          40+t, 
360                          240+100+t*30 , size[3]-n0  ,30 , 20,
361                          TAXEList[1][t].val)
362
363     
364     if ORIENTMenu.val==3 :
365        glRasterPos2f(20  ,size[3]-n0-90+24)
366        Text("NOISE")
367        NOISEMenu= Menu(NOname,         45    , 240  ,size[3]-n0-110 ,110,20, NOISEMenu.val, "NOISE menu.")
368        if NOISEMenu.val==11:
369           HBout= Slider("H",      46  ,110  ,size[3]-n0-190 ,125,20, HBout.val, -2.0,+2.0,0,)
370           lacunarityBout=Slider("lacunarity",47  ,110  ,size[3]-n0-110 ,125,20, lacunarityBout.val, -4.0,+4.0,0,)
371           octavesBout=Slider("octave",       48  ,110  ,size[3]-n0-130 ,125,20, octavesBout.val, -10.0,+10.0,0,)
372           offsetBout=Slider("offset",        49  ,110  ,size[3]-n0-150 ,125,20, offsetBout.val, -5.0,+5.0,0,)
373           basisBout=Slider("noise",          50  ,110  ,size[3]-n0-170 ,125,20, basisBout.val, 0,9,0,)
374
375     NSIZE= Slider("Disp Size",      4  ,80  ,size[3]-n0-20 ,260,20, NSIZE.val, -4.0,+4.0,0,"SIZE.")
376
377
378                  
379
380 def event(evt, val):    
381     if ((evt== QKEY or evt== ESCKEY) and not val): Exit()
382
383 def bevent(evt):
384     global MODEMenu, NSIZE, ng, TMATList
385     global mat, ORIENTMenu, NRepeat, TAXEList 
386     global ERROR,TextERROR, NOISE, NOISEMenu
387     global HBout,lacunarityBout,octavesBout,offsetBout,basisBout
388     global H,lacunarity,octaves,offset,basis
389     
390     if   (evt== 1):
391         Exit()
392
393
394     elif   (evt== 16):
395        for n in range(NRepeat.val):
396           paint()
397
398     elif   (evt== 4):
399        ng=NSIZE.val
400
401     elif   (evt== 24) or (evt in [32,33,34,35,36,37,38,39,40,41,42,43,44]):
402       Me=Object.GetSelected()
403       if Me!=[]:
404          if Me[0].getType()=='Mesh':   
405             TMATList=DOCMat_list(TMATList)
406             mat=[]
407             for TMat in TMATList[2]:
408                if TMat.val==1.0:
409                    mat.append(TMATList[2].index(TMat))  
410             ERROR=0
411          else:
412             ERROR=1
413             TextERROR='Selected Object is not a mesh.'    
414       else:
415           ERROR=1
416           TextERROR='No Selected Object.'  
417   
418     elif   (evt== 17):  
419            NEWMEcreation('new.002')
420
421     elif   (evt== 45):
422        NOISE=NOISEMenu.val-1
423
424     elif   (evt in [46,47,48,49, 50]):
425        H=HBout.val
426        lacunarity=lacunarityBout.val
427        octaves=octavesBout.val
428        offset=offsetBout.val
429        basis=basisBout.val
430
431     Blender.Redraw()
432  
433 Window.EditMode(0)
434 Register(draw, event, bevent)