Blender (jusqu'à 2.49)
Python
Importing 
Framstick's Creatures 
animation

(version française)

Main Index
previous tScript Python
En chantier Suivant

(Transcription HTML of a paper published in the magazine Pixel at the autumn 2004)




Some specialized functions are not always available in a software.  The possibility of writing them oneself offers a great flexibility of work.  Especially if the programming language is simple and easy to implement. 
 

The Povray format
On the track of the macros
The editor of script
The submodules
The functions
Collecting information
As a conclusion
The script 

Python, the free language developed originally by Guido Van Rossum, is an interpreter which can be integrated in any software. It is associated to the Blender 3D bunch since 1999.  To discover it a little, we suggest to fly over the creation of a script wich loads Framsticks animations, an artificial life  software


[figure1] 

The Povray format 
Framsticks makes it possible to export the movements of the creatures under the povray format whose syntax is ideal for an animation importation because data which describe the form and positioning are separated. This method corresponds to what is done in Blender when a linear animation is carried out : an object is created, it is moved and we allot it a key of animation. 

On the track of the macros 
The animation comes as a set of clearly numbered files. The order in which they must be treated is obvious. By studying the content of a file, one finds in the middle of a great number of variables, the BeginJoint(n, n1) expression, which corresponds to a Povray macro located in the framstick.inc file. It only contains a few variables declarations but not any object description. Both of the following macros  JointGeometry(Location1, Location2, Rotation) and EndJoint()


[figure 2]

provide concrete information as well as a call to another macro, CreatureStick(StickLoc1, StickLoc2, StickRot) which contains at least one significant reference to a form of the cylinder type, line 556. The remainder of the macro can be eliminated since they are conditional expressions # if # end. In going on the pruning work of the conditions, one realizes that the positioning information (scale, rotate, relocate) are in the 645th line 


[figure 3] 

BeginJoint(), EndJoint() and JointGeometry() are thus the expressions which a script must identify and use to know at which state is the animation. 

The editor of script 
One reaches the python, simply through an integrated text editor which appears in the active window, (the one whose frame is clearer) when one uses the key combo shift-F11. Alt-N opens a new file. The line : "Blender importation" is the essential key to obtain the loading of the main module which makes interface with most of the software functions . These functions are themselves distributed in submodules by themes. 

The submodules 
Several are requested : 

Draw which gathers the management functions of the python API graphical interface, the various buttons and the management of the events; 
BGL which gathers all the interface functions with the OpenGL displaying (Blender is entirely written and compatible with OpenGL); 
NMesh which gathers the functions of processing the data meshes (networks of polygons); Material which allows to create or read materials; 
Ipo which manages all the interactions of the python with the animation curves; 
Window which allows to carry out some more general displaying operations than those of the python's window ; 
Scene which makes it possible to manage the relations between the objects and the image which will be returned then, 
Render, finally, which gives access to certain displaying data as the size of animation while determining, for example, the starting frame and that of arrival. 
The functions 
In python the functions are identified by a key word def which precedes them and are finished by brackets followed by two points :. The brackets are fundamental, without them the name of the function is regarded as a simple identifier referring to a variable :


[figure 4]

The first importation operation consists in being able to intuitively choose the file which one wishes to treat.  For that, it is possible to create a graphic interface while passing by the Blender.Draw  modules and Blender.BGL. Draw connects three functions to the main Blender engine through the Register() function. The names of these functions are not important. But for the legibility of script, it is preferable to give significant names:   GUI_EVENEMENT(event) and GUI_DESSIN()

The last displays the buttons and should not comprise any variables between its brackets. The first manages the events. The titrated button "Select the importation" 


[figure 5] 

makes it possible to carry out the Blender.Window.FileSelector function to locate the file scene_0001.pov 


[figure 6] 

and to extract from its complete name, the address of the directory in which are stored the pov files. 

Collecting information
It is done in two times. The script initially takes all the file names Scène from which it extracts the numbers (scene_0700.pov gives 700) to arrange them in a dictionary (a list of object whose each element bears a name, (700:' scene_0700.pov '). It then becomes very simple to create the list of the keys (700 is a key) and to order them in an increasing way (line 328 and 363 of script). Script defines also two variables : PREMIERE and DERNIERE which are the extreme limits of animation. They are used to modify the Blender timeline by modifying the values Sta and End


[ figure 7] 

In the second place, and only on the first scene, it seeks for all the creatures and all the elements ' joints' which constitute them, as well as the number of the line on which information is given to avoid wasting time to filter all the lines the following files, and creates them, in the order they are coming, in the shape of Mesh cylinder 


[figure 8]

. These objects are brought to their place by the IPO curves which are allotted to them :  LocX, LocY, LocZ, RotX, RotY, RotZ, SizeX, SizeY, SizeZ. The IPOs curves deal with the combining of the virtual animal, as well as its movements. The successive locations are then read in the other available scenes files and added to each curve as control handles 


[figure 9]

As a conclusion 
Getting a result is what we are aiming to do with this script, but together with preserving a maximum of legibility so that one can easily study the content of it. There is abundance of documentation and one will find many other explanations in it which cannot be given here, due to a lack of place. 
 

#!BPY

""" Registration info for Blender menus: <- these words are ignored
Name: 'framstick'
Blender: 232
Group: 'import'
Tip: 'import framstick animation from povray .inc IMAGEs'
"""
"""
(c) jm soler 2004
"""

#=========================================================
# Personal functions to avoid using the complete version 
# of the python.  Valid on:  win32, linux, irix and macosX...
#=========================================================

try:
    import nt
    os=nt
    os.sep='\\'

except: 
    import posix
    os=posix
    os.sep='/'

def isdir(path):
    try:
        st = os.stat(path)
        return 1 
    except:
        return 0

def split(pathname):
         if pathname.find(os.sep)!=-1:
             k0=pathname.split(os.sep)
         else:
            if os.sep=='/':
                k0=pathname.split('\\')
            else:
                k0=pathname.split('/') 

         directory=pathname.replace(k0[len(k0)-1],'')
         Name=k0[len(k0)-1]
         return directory, Name

def join(l0,l1): 
     return  l0+os.sep+l1

os.isdir=isdir
os.split=split
os.join=join
#=========================================================
# ... end of the  additional fonctions 
#=========================================================
#=========================================================
#  It can be difficult to charge the math module on certain 
#  linux installation .  Generally, the installation of a pack python 
# for developers is necessary.  The problem was signaled to
#  the Blender python API developers , which have, 
# initially, added the math  functions to withdraw them 
# thereafter under the pretext that a module math in the Blender 
# module could  be  misleading . 
#--
# Under win32 (win9x, xp,  NT, 2000) the module math is 
# delivered with the DLL python 
# which accompanies Blender.
#=========================================================
import math
from math import pi,cos,sin
#=========================================================
# Module Python Blender 
#=========================================================
import Blender

#=========================================================
# Sub module for MESHES management
#=========================================================
#from Blender import NMesh
#=========================================================
# Sub module for  graphic management interface
#=========================================================
#from Blender import Draw
#=========================================================
# Sub module for  graphic management interface  d'interface avec les fonctions OpenGL
#=========================================================
#from Blender import BGL
#=========================================================
# Sub module for MATERIAL management 
#=========================================================
#from Blender import Material
#=========================================================
#  Sub module for WINDOW management 
#=========================================================
#from Blender import Window
#=========================================================
#  Sub module for IPO animation curves management 
#=========================================================
#from Blender import Ipo
#=========================================================
#  Sub module for SCENE management 
#  (with so  numerous functions that it was separated in two 
#  and there is now a  sub module Scene.Render )
#=========================================================
from Blender import Scene
SCENE=Blender.Scene.GetCurrent()

#=========================================================
# Python's sys module  to read the current directory and
# add  momentarily a path research to the python
#
#=========================================================
import sys
path=Blender.Get('filename')
dirname=Blender.sys.dirname(path)
oldpath=sys.path
if dirname not in sys.path: sys.path.append(dirname)

#=========================================================
# Some  global variables 
#=========================================================
PROBLEME =             0
REPERTOIRE     =    ""
NOM            =    "e:\\zi^p\\3dgrx\\blender\\reserve_python\\importanimpov\\scene_0700.pov"
FICHIERSELECTIONNE=   -1
DECALE=                0
FRAMESCENE=           ""

E_CHANGECHEMIN=        1
E_IMPORTE=             2
E_QUITTE=              8
E_FAIT=               11
E_IMPORTE_SELECT=     12
E_IMPORTE_CONTR=      13
A_RECALE=             14
A_REDOCU=             15
A_REDESS=             16
M_PARENT=             17
E_CONTINUE=           18 
 

PROBLEME_TEXTE =    {E_IMPORTE_SELECT:' selection de fichier.',
                            E_IMPORTE:' d\' import.',
                            3:' Ce fichier n\'est peut-être pas un fichier framestick.',}

ETAT="En attente..."

#=========================================================
# Dictionary to call a frame by its number
#=========================================================
LISTEFICHIER={}

#=========================================================
# Quelques variables globales pour gerer la progression
# de la lecture de l'animation
#=========================================================
PREMIERE=-1
DERNIERE=-1
IMAGE=-1
#=========================================================
# Dictionnaire contenant les informations relatives
# aux créatures du fichier importe' 
#=========================================================
CREATURES={}

BOUTONS={
#=========================================================
# Bouton utilise dans l'interface graphique pour contenir
# l'adresse du fichier selectionne
#=========================================================
'NOMDEFICHIER':[ Blender.Draw.Create(NOM),"> ",
       "Interface graphique de selection de fichier." +
       "Pointez de preference le premier fichier de la liste des scenes."], 
#=========================================================
# Un bouton de type booleen pour déterminer si le script
# doit faire démarrer l'animation sur l'image 1 ou sur
# le numéro de la premier scene.
#=========================================================
'RecaleANIM' :[ Blender.Draw.Create(0),'RecaleANIM',
                "repositionne toutes les IMAGEs à partir de l\'IMAGE 0"+
                 " de la TimeLine de Blender"],
'ReDocANIM': [ Blender.Draw.Create(0),'ReDocANIM',
               "Met à jour les parametres d'animation interne pour ne calculer que les"+
              " images située entre le début et la fin de cette séquence framsticks."""],

#=========================================================
# Un bouton de type booleen pour déterminer si le script
# doit réafficher l'écran. A desactiver pour des scenes
# lourdes
#=========================================================
'ReDESSINEANIM' : [ Blender.Draw.Create(0),'ReDESSINE',
                "reaffiche toutes les fenêtres ouvertes à l'écran. Peut être source de "+
                "longueurs indésiarables dans le traitement de très gros  ou très"+
                " nombreux fichiers"],

#=========================================================
# Un bouton de type booleen pour déterminer si le script
# doit réafficher l'écran. A desactiver pour des scenes
# lourdes
#=========================================================
'PARENT' : [ Blender.Draw.Create(1),'PARENT',
                "lie l'ensemble des cylindres à  un objet parent unique pour faciliter "+
                "la manipulation."]}

#=========================================================
# Comme  il n'existe pas de forme prédéfinie que l'on puisse
# appeler par l'API python de Blender il faut en creer une
# qui corresponde à l'objet cylindre de povray.
# --
# L'axe de ce cylindre coincide avec l'axe x du monde 3D
# Cette position evite quelques calculs quand on doit
# imiter la macro povray CreatureStick()
#=========================================================
class cylindre:
    def __init__(self,nom='cylindreModele',type='cyl',r1=0.1, r2=0.1,h=1.0, n=8,smooth=1):
          #====================================
          # creation d'un objet mesh vide
          #====================================
          me=Blender.NMesh.GetRaw()
          #====================================
          # creation de la liste des sommets
          #====================================
          # 1/ les rayons sont stocké dans une
          #    liste
          #====================================
          r=[r1,r2]
          #====================================
          # 2/ création des sommets qui constituent
          #    les extremites.
          #    l'utilisation de range plutot
          #    que de la liste r elle-même
          #    permet de localiser la hauteur
          #    du premier disque en 0 et le second
          #    en h 
          #====================================
          for i in range(0,2):
              for j in range(0,n):
                  z=sin(j*pi*2/(n))*r[i]
                  y=cos(j*pi*2/(n))*r[i]
                  x=float(i)*h
                  v=Blender.NMesh.Vert(x,y,z)
                  me.verts.append(v)

          #==================================== 
          # petit tour de passe-passe avec les listes
          # pour traiter tous les segments d'une facettte
          #====================================
          vlist=[v for v in range(n)]
          vlist.append(0)
          #====================================
          # creation de la liste des faces
          #====================================
          for i in range(n):
              f=Blender.NMesh.Face() 
              f.v.append(me.verts[vlist[i]]) 
              f.v.append(me.verts[vlist[i+1]])
              f.v.append(me.verts[vlist[i+1]+n]) 
              f.v.append(me.verts[vlist[i]+n]) 
              me.faces.append(f) 
              f.smooth=smooth
          #====================================
          #  le type 'cyl' permet de fermet
          # les extremites du cylindre en
          # construisant les faces qui les
          # constituent sinon le tube reste
          # ouvert
          #====================================
          if type=='cyl':
              #====================================
              # creation d'un sommet supplementaire
              # au centre de chaque disque
              #====================================
              pos=[[0.0,0.0,0.0],[0.0,0.0,h]]
              V0=Blender.NMesh.Vert(pos[0][0],pos[0][1],pos[0][2])
              V1=Blender.NMesh.Vert(pos[1][0],pos[1][1],pos[1][2])
              me.verts.append(V0)
              me.verts.append(V1)

              for i in range(n):
                  f=Blender.NMesh.Face()
                  f.v.append(me.verts[vlist[i]])
                  f.v.append(me.verts[vlist[i+1]])
                  f.v.append(me.verts[-2])
                  me.faces.append(f) 
                  f.smooth=smooth

                  f=NMesh.Face()
                  f.v.append(me.verts[vlist[i+1]+n]) 
                  f.v.append(me.verts[vlist[i]+n]) 
                  f.v.append(me.verts[-1])
                  me.faces.append(f) 
                  f.smooth=smooth

          self.objet=Blender.NMesh.PutRaw(me,nom,1)
          #print nom, me.name 
          if self.objet==None:
              OBJETS=[]
              for O in Blender.Object.Get():
                  if O.getType()=='Mesh':
                     if nom==O.getData().name: 
                        self.objet=O
#========================================================= 
# une sorte de contournement qui permet d'utiliser la fonction
# et de documenter les variables Window.FileSelector
#=========================================================
def fonctionSELECT(nom):
             global BOUTONS
             print BOUTONS['NOMDEFICHIER'] 
             BOUTONS['NOMDEFICHIER'][0].val=nom
             scan_DIR(nom)

#========================================================= 
# Pour filtrer le répertoire pointé par 
# BOUTONS['NOMDEFICHIER'][0].val, on liste
# tous les fichier pov qui auraient une partie
# de nom
#=========================================================
def scan_DIR(dir):
    global LISTEFICHIER, REPERTOIRE, NOM, DECALE, PROBLEME
    global PREMIERE, DERNIERE, FICHIERSELECTIONNE

    REPERTOIRE, NOM=split(dir)

    if NOM.find("_")==-1:
        PROBLEME=3

    FICHIERSELECTIONNE=1

    if NOM.find(".pov")!=-1 and PROBLEME==0:
       LISTEFICHIER={} 
       for f in os.listdir(REPERTOIRE):
             if f.find('.pov')!=-1:
               try: 
                 IMAGE=int(f[f.find('_')+1:f.find('.')]) 
                 LISTEFICHIER[IMAGE]=f
                 if DERNIERE==-1:
                      DERNIERE=IMAGE
                 elif IMAGE>DERNIERE:
                      DERNIERE=IMAGE
                 if PREMIERE==-1:
                      PREMIERE=IMAGE
                 elif IMAGE<PREMIERE:
                      PREMIERE=IMAGE
               except:
                 pass 
             else:
               print f
       if PREMIERE==0:
              DECALE=1
    else:
        print "Probleme : ce n'est pas un fichier framsticks"

def fonctionIMPORT():
       global  PREMIERE, DERNIERE,  FICHIERSELECTIONNE
       global  REPERTOIRE, NOM, ETAT, BOUTONS, SCENE
       global  CREATURES

       if FICHIERSELECTIONNE==-1:
           REPERTOIRE,NOM=split(NOM)
           scan_DIR(REPERTOIRE+NOM)

       if BOUTONS['ReDocANIM'][0].val:
           RenderContext=Blender.SCENE.getRenderingContext()
           RenderContext.startFrame(1) 
           RenderContext.endFrame(DERNIERE-PREMIERE+1) 
       else:
           print PREMIERE, DERNIERE
           RenderContext=SCENE.getRenderingContext()
           RenderContext.startFrame(PREMIERE+DECALE) 
           RenderContext.endFrame(DERNIERE+DECALE) 

       key=LISTEFICHIER.keys()
       key.sort()
       for k in key:
           ETAT='Analyse de l\'IMAGE : '+ str(k) + '   Patience...'
           AnalyseSCENE(k)
           if BOUTONS['ReDESSINEANIM'][0].val:

               Blender.Window.RedrawAll()
               Blender.Set('curframe',k)
           print ETAT
 

       for c in CREATURES.keys():
           if BOUTONS['PARENT'][0].val==1 : 
                    CREATURES[c]['parent']=Blender.Object.New('Empty',c)

           SCENE.link(CREATURES[c]['parent'])
           ENFANTS=[]
           for j in CREATURES[c]['Joints'].keys():
                o= CREATURES[c]['Joints'][j]['objet']
                ENFANTS.append(o)
           if BOUTONS['PARENT'][0].val==1 : 
                   CREATURES[c]['parent'].makeParent(ENFANTS,1)

#=========================================
# Deux possibilités, soit on traite le premier
# fichier décrivant une scene soit on travaille sur
# les données d'animation exclusivement,
# la première analyse ayant pointé tous
# les numeros de liges où il faut chercher
# les informations, le traitement devrait
# en être plus rapide dan sla mesure où il n'est
# plus nécessaire de controler le contenu de chaque
# ligne.
#==========================================
def AnalyseSCENE(image):
    global IMAGE, PREMIERE, DERNIERE, CREATURES
    IMAGE=image
    IMAGEFile=open(REPERTOIRE+'/'+LISTEFICHIER[IMAGE],'r')
    IMAGElignes=IMAGEFile.readlines()
    IMAGEFile.close()
    if image==PREMIERE:
       CREATURES= EtatCREATURES(IMAGElignes,CREATURES)
    else:
       CREATURES=AnimationCREATURES(IMAGElignes,CREATURES)

#=========================================
#  Pour récuperer les infos qui sont au format
#  texte  dans un format plus comprehensible
#  par le script
#=========================================
def extrait_valeur(l,n0,n1):
    val=l[l.find(n0)+1:l.find(n1)]
    #print val
    if val.find('<')!=-1:
       #=============
       # un vecteurs compose de 3 valeurs décimales
       #=============
       val=val.replace('<','[')
       val=val.replace('>',']')
       exec'val=[%s]'%val 
       return   val
    elif val.find('.')!=-1:
       #=============
       # un seul nombre décimal
       #=============
        return float(val)
    elif val.find('"')!=-1:
       #=============
       # du texte !  débarrassé des fioritures
       #=============
        return val[1:-2]
    elif val.find(',')!=-1:
       #=============
       # liste de deux entiers, ou de quoi que
       # ce soit séparer par une virgule
       #============= 
        exec'val=[%s]'%val 
        return   val
    else:
       #=============
       # Dans tous les autres cas
       # un entier
       #=============
        return int(val)

#=========================================
# pour faciliter la copie de dictionnaire
#=========================================
def copie(d1,d2):
     for k in d2.keys():
         d1[k]=d2[k]

#=========================================
# utilise pour l'echelle des elements 'joints'
#========================================= 
def longueur_vect(p1,p2):
    p2[0]=p2[0]-p1[0]
    p2[1]=p2[1]-p1[1]
    p2[2]=p2[2]-p1[2]
    return [abs(p2[0]**2+p2[1]**2+p2[2]**2)**0.5,1.0,1.0]
 

#========================================= 
# Documente le dictionnaire des CREATURES
# en indiquant :
#  1/ le nom de l'animal
#  2/ tous les batonnets qui la constituent
#  3/ pour chaque batonnet quelle ligne doit être lue
#     dans le prochain fichier
#  4/ pour chaque batonnet, le bloc IPO
#     qui doit etre modifié au prochain
#     fichier.
#=========================================
def EtatCREATURES(IMAGElignes,CREATURES):
    global IMAGE,  PREMIERE, DERNIERE, SCENE
    for l in range(len(IMAGElignes)):
       if IMAGElignes[l].find('field_Creature_name')!=-1:
          joints=0
          CREATURENAME=IMAGElignes[l][IMAGElignes[l].find('"')+1:-2]
          CREATURES[CREATURENAME]={}
          CREATURES[CREATURENAME]['Joints']={} # definis plus tard dans le script 
          jointNUMERO=-1 
          while IMAGElignes[l].find('EndObject()')==-1:
              if IMAGElignes[l].find('field_Creature_numjoints')!=-1:
                  joints=extrait_valeur(IMAGElignes[l],'=',';') 
              if IMAGElignes[l].find('BeginJoint')!=-1:
                 JOINT=extrait_valeur(IMAGElignes[l],'(',')')
                 jointNUMERO+=1
                 CREATURES[CREATURENAME]['Joints'][jointNUMERO]={}
                 mouvements=extrait_valeur(IMAGElignes[l+1],'(',')')
                 CREATURES[CREATURENAME]['Joints'][jointNUMERO]['ligne']=l+1 
                 CREATURES[CREATURENAME]['Joints'][jointNUMERO
                                     ]['StickLoc1']=mouvements[0]
                 CREATURES[CREATURENAME]['Joints'][jointNUMERO
                                     ]['StickSize']=longueur_vect(mouvements[0],mouvements[1])
                 CREATURES[CREATURENAME]['Joints'][jointNUMERO
                                      ]['StickRot']=[mouvements[2][0]*5.7,
                                                            mouvements[2][1]*5.7,mouvements[2][2]*5.7]
              if IMAGElignes[l].find('EndJoint')!=-1:
                     CREATURES[CREATURENAME]['Joints'][jointNUMERO
                            ]['objet'], CREATURES[CREATURENAME]['Joints'
                            ][jointNUMERO]['ipo']=CreatureStick(CREATURENAME,
                             jointNUMERO)
              l+=1
    return CREATURES

#========================================= 
# Dans le ficheir actuellement lu, pour chaque joint 
# de chaque creature, va lire la ligne numero n associee
# a cet objet pour en retirer les informations
# de positionnement. 
#=========================================
def AnimationCREATURES(IMAGElignes,CREATURES):
    global IMAGE, PREMIERE, DERNIERE, SCENE
    for creature in CREATURES.keys():
          for joint in CREATURES[creature]['Joints'].keys():
                 l=CREATURES[creature]['Joints'][joint]['ligne'] 
                 if IMAGElignes[l].find('JointGeometry')!=-1: 
                    mouvements=extrait_valeur(IMAGElignes[l],'(',')')
                    CREATURES[creature]['Joints'][joint]['StickLoc1']=mouvements[0]
                    CREATURES[creature]['Joints'][joint]['StickSize'
                                   ]=longueur_vect(mouvements[0],mouvements[1])
                    CREATURES[creature]['Joints'][joint]['StickRot'
                                   ]=[mouvements[2][0]*5.7,mouvements[2][1]*5.7,mouvements[2][2]*5.7]
                    CreatureStick(creature,joint)
    return CREATURES

#================================
# def doc_COURBESIPO(CREAT,joint,IP,IDENT):
#   pour la creature CREAT ajoute les infos
#   de type  IDENT sur la courbe viser par
#   IP
#================================
def doc_COURBESIPO(CREAT,joint,IP,IDENT): 
        global CREATURES, IMAGE, PREMIERE, DECALE, BOUTONS
        if IMAGE==PREMIERE:
            Lx=IP.addCurve(IDENT[0])
        else: 
            Lx=IP.getCurve(IDENT[0])
        if BOUTONS['RecaleANIM'][0].val:
           Lx.addBezier((float(IMAGE-PREMIERE+DECALE)+1.0,
                          CREATURES[CREAT]['Joints'][joint][IDENT[1]][IDENT[2]]))
        else:
           Lx.addBezier((float(IMAGE+DECALE)+1.0,
                         CREATURES[CREAT]['Joints'][joint][IDENT[1]][IDENT[2]])) 
        Lx.Recalc()
        Lx.update()

#================================
# def CreatureStick(creature,joint):
# à la premiere IMAGE, crée le bloc ipo
# qui contient toutes les courbes d'animations
# aux suivants ajoute simplement les positions
# pour chaque courbes identifiée dans la liste
# identiteIPO
#================================
def CreatureStick(creature,joint): 
    global CREATURES, IMAGE, PREMIERE
    identiteIPO=[['LocX','StickLoc1',0],
             ['LocY','StickLoc1',1],
             ['LocZ','StickLoc1',2],
             ['RotX','StickRot',0],
             ['RotY','StickRot',1],
             ['RotZ','StickRot',2],
             ['SizeX','StickSize',0],
             ['SizeY','StickSize',1],
             ['SizeZ','StickSize',2]]
    if IMAGE==PREMIERE :
        cyl=cylindre(creature.replace(' ','_')+'join_'+str(joint),'tube',0.1,0.1,1.0,6)
        i=Blender.Ipo.New('Object',creature[:6]+'L1j'+str(joint))
        cyl.objet.setIpo(i)
        for ident in identiteIPO:
           doc_COURBESIPO(creature,joint,i,ident)
        return cyl.objet,i
    else:
        i=CREATURES[creature]['Joints'][joint]['ipo']
        for ident in identiteIPO:
           doc_COURBESIPO(creature,joint,i,ident)

#================================
# def GUI_SORTIE ():
#================================
def GUI_SORTIE ():
    Blender.Draw.Exit()

#================================
# def GUI_EVENEMENT (event):
#================================
def GUI_EVENEMENT (event):
      global NOM, REPERTOIRE, PROBLEME, BOUTONS

      if (event==E_IMPORTE):
         fonctionIMPORT()

      elif (event==E_IMPORTE_SELECT): 
         try: 
            Blender.Window.FileSelector (fonctionSELECT, 'SELECTIONNER LE FICHIER .INC')
            REPERTOIRE, NOM=split(BOUTONS['NOMDEFICHIER'][0].val)
         except:
           PROBLEME=E_IMPORTE_SELECT

      elif (event==E_QUITTE):
         GUI_SORTIE()

      elif (event==A_REDOCU):
            pass

      elif (event==E_CONTINUE):
            PROBLEME=0
            Blender.Redraw()

#================================
def GUI_DESSIN():
#================================
      global operation, NOM, REPERTOIRE, ETAT
      global  PROBLEME, PROBLEME_TEXTE
      global PREMIERE , DERNIERE, BOUTONS

      Blender.BGL.glColor3f(0.7, 0.7, 0.7)
      Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT)
      Blender.BGL.glColor3f(0.1, 0.1, 0.15)

      size=Blender.BGL.Buffer(Blender.BGL.GL_FLOAT, 4)
      Blender.BGL.glGetFloatv(Blender.BGL.GL_SCISSOR_BOX, size)
      size= size.list

      for s in [0,1,2,3]: size[s]=int(size[s])
      ligne=20
      Blender.BGL.glRasterPos2f(20, size[3]-ligne+4)
      Blender.Draw.Text("FramStick ANIM Importeur, (c) jm soler 2004")

      Blender.BGL.glRasterPos2f(20, size[3]-ligne*2+6)
      Blender.Draw.Text("IMAGE de depart :"+str(PREMIERE))

      Blender.BGL.glRasterPos2f(
             20+Blender.Draw.GetStringWidth("IMAGE de depart :"+
             str(PREMIERE))+8, size[3]-ligne*2+6)
      Blender.Draw.Text(" IMAGE d'arrivee : "+str(DERNIERE))

      if PROBLEME==0:
        Blender.Draw.Button ("Selectionne l'import",E_IMPORTE_SELECT,20,
                     size[3]-ligne*3+2,
                     Blender.Draw.GetStringWidth("Selectionne l'import")+8,ligne,"")
        BOUTONS['NOMDEFICHIER'][0]=Blender.Draw.String (BOUTONS['NOMDEFICHIER'][1],
                    E_CHANGECHEMIN,
                    Blender.Draw.GetStringWidth("Selectionne l'import")+30,size[3]-ligne*3+2,
                    Blender.Draw.GetStringWidth(BOUTONS['NOMDEFICHIER'][0].val)+
                    Blender.Draw.GetStringWidth(BOUTONS['NOMDEFICHIER'][1])+4 ,
                    ligne, BOUTONS['NOMDEFICHIER'][0].val,320,
                    BOUTONS['NOMDEFICHIER'][2]) 
        Blender.Draw.Button ("Import",E_IMPORTE,20,size[3]-ligne*4,80,ligne-2,"")
        Blender.Draw.Button ("Exit",E_QUITTE,20,size[3]-ligne*5,80,ligne-2,"")
        BOUTONS['RecaleANIM'][0]=Blender.Draw.Toggle(BOUTONS['RecaleANIM'][1],
              A_RECALE,100+2,size[3]-ligne*4,80,
              ligne-2, BOUTONS['RecaleANIM'][0].val, BOUTONS['RecaleANIM'][2])
        BOUTONS['ReDocANIM'][0]=Blender.Draw.Toggle(BOUTONS['ReDocANIM'][1],
              A_REDOCU,100+2,size[3]-ligne*5,80,
              ligne-2, BOUTONS['ReDocANIM'][0].val,BOUTONS['ReDocANIM'][2])
        BOUTONS['ReDESSINEANIM'][0]=Blender.Draw.Toggle(BOUTONS['ReDESSINEANIM'][1],
              A_REDESS,100+2,size[3]-ligne*6,80,
              ligne-2, BOUTONS['ReDESSINEANIM'][0].val,BOUTONS['ReDESSINEANIM'][2])
        BOUTONS['PARENT'][0]=Blender.Draw.Toggle(BOUTONS['PARENT'][1],
              A_REDESS,100+2,size[3]-ligne*7,80,
              ligne-2, BOUTONS['PARENT'][0].val,BOUTONS['PARENT'][2])

        Blender.BGL.glRasterPos2f(20,size[3]-ligne*9)
        Blender.Draw.Text(ETAT)
 

      else:
        Blender.BGL.glRasterPos2f(20, size[3]-ligne*3+8)
        Blender.Draw.Text('Desolé : probleme dans la fonction de '+PROBLEME_TEXTE[PROBLEME])
        Blender.Draw.Button ("Continue",E_CONTINUE,20,size[3]-ligne*4,100,ligne)

#================================
def GUI_ENREGISTRE ():
#================================
    Blender.Draw.Register (GUI_DESSIN,None,GUI_EVENEMENT)

#================================
# PARTIE PRINCIPALE DU SCRIPT
#================================
GUI_ENREGISTRE ()

sys.path=oldpath


 
previousScript Python
 En Chantier Suivant
To the top of the page

Les questions concernant cette page  peuvent être posées sur  :
 news://news.zoo-logique.org/3D.Blender

 
Livre en français
Blender : apprenez, pratiquez, Créez, livre, Ed. Campus Press, coll. Starter Kit
Blender Starter Kit

Forum
FAQ
Lexique
Didacticiels
Compilations
Blender2KT
Débuter
Modelage
Blender python
Materiaux
Lumière
Animation
API python (eng)
Archives nzn
Statistiques
Doc flash Sculptris
Galerie Sculptris

mon site de démos sur youtube