Added research data, testing blender mesh generation
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 2
|
||||
@@ -18,8 +18,8 @@
|
||||
from .msh2 import msh2
|
||||
|
||||
|
||||
msh = msh2.MSH2(None)
|
||||
bl_info = {
|
||||
msh_handler = msh2.MSH2(None)
|
||||
bl_info = {
|
||||
"name": "Zero Editor MSH2 format",
|
||||
"author": "Maxim Stewart",
|
||||
"version": (0, 0, 1),
|
||||
@@ -100,8 +100,49 @@ class ImportMSH2(bpy.types.Operator, ImportHelper, IOOBJOrientationHelper):
|
||||
import os
|
||||
keywords["relpath"] = os.path.dirname(bpy.data.filepath)
|
||||
|
||||
data = {**keywords}
|
||||
msh.import_file(data["filepath"])
|
||||
data = {**keywords}
|
||||
msh_handler.import_file(data["filepath"])
|
||||
msh = msh_handler.get_mesh_obj()
|
||||
sceen = bpy.context.scene
|
||||
|
||||
# Test adding mesh2 to blender
|
||||
for model in msh.models:
|
||||
name = model.name.decode("utf-8")
|
||||
# print(model)
|
||||
# print(model.name)
|
||||
# print(model.index)
|
||||
# print(model.collection)
|
||||
# print("")
|
||||
# Create a mesh data block
|
||||
mesh2 = bpy.data.meshes.new("{}".format(name))
|
||||
|
||||
verts = []
|
||||
edges = []
|
||||
faces = []
|
||||
segments = model.segments
|
||||
for segment in segments:
|
||||
if segment.classname == "SegmentGeometry":
|
||||
vertices = segment.vertices
|
||||
for vert in vertices:
|
||||
x = vert.x
|
||||
y = vert.y
|
||||
z = vert.z
|
||||
verts.append((x, y, z))
|
||||
|
||||
sfaces = segment.faces
|
||||
for face in sfaces:
|
||||
'''Using CCW order for importing.'''
|
||||
faces.append(face.SIindices())
|
||||
|
||||
# Add the vertices to the mesh
|
||||
mesh2.from_pydata(verts, edges, faces)
|
||||
|
||||
# Create an object that uses the mesh data
|
||||
myobj = bpy.data.objects.new("{}_obj".format(name), mesh2)
|
||||
|
||||
# Link the object to the scene
|
||||
sceen.objects.link(myobj)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
|
||||
@@ -6,8 +6,12 @@
|
||||
from msh2 import msh2
|
||||
|
||||
|
||||
msh = msh2.MSH2(None)
|
||||
msh_wrapper = msh2.MSH2(None)
|
||||
|
||||
msh.import_file("../../msh/all_weap_inf_lightsabre.msh")
|
||||
# /home/abaddon/Downloads/my-py-msh-parser/msh/KAS/msh
|
||||
msh_wrapper.import_file("../../msh/KAS/msh/kas2_prop_rock_L.msh")
|
||||
msh_wrapper.export_file("kas2_prop_rock_L.msh")
|
||||
|
||||
# msh.export_file("all_weap_inf_lightsabre.msh")
|
||||
|
||||
# msh_wrapper.import_file("../../msh/uta1_prop_gunship.msh")
|
||||
# msh_wrapper.export_file("uta1_prop_gunship.msh")
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Python imports
|
||||
import faulthandler
|
||||
import traceback
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
# Gtk imports
|
||||
|
||||
@@ -18,15 +20,31 @@ class MSH2():
|
||||
self.msh = None
|
||||
|
||||
|
||||
def get_mesh_obj(self):
|
||||
return self.msh
|
||||
|
||||
def import_file(self, file_name):
|
||||
try:
|
||||
self.msh = msh2_unpack.MSHUnpack(file_name, self.msh_config).unpack()
|
||||
unpacker = msh2_unpack.MSHUnpack(file_name, self.msh_config)
|
||||
self.msh = unpacker.unpack()
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
|
||||
def export_file(self, file_name):
|
||||
def export_file(self, file):
|
||||
logging.info('==========================================')
|
||||
logging.info('Starting export at {0}.'.format(datetime.now()))
|
||||
logging.info('.msh file path: {0}'.format(file))
|
||||
try:
|
||||
self.msh.save(file_name)
|
||||
# Convert materials from Blender to msh2.
|
||||
# self.msh.materials = msh2.MaterialCollection(self.msh)
|
||||
# self.msh.materials.replace([])
|
||||
|
||||
self.msh.models.assign_indices()
|
||||
self.msh.models.assign_parents()
|
||||
self.msh.models.remove_multi([])
|
||||
self.msh.models.assign_cloth_collisions()
|
||||
|
||||
self.msh.save(file)
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
@@ -131,10 +131,17 @@ def return_lowest_bits(n):
|
||||
return n & 0xFFFFFFFF
|
||||
|
||||
|
||||
def crc(string):
|
||||
def crc(_string):
|
||||
'''Calculate the Zero CRC from string and return it as number.'''
|
||||
crc_ = 0
|
||||
crc_ = return_lowest_bits(~crc_)
|
||||
crc_ = 0
|
||||
crc_ = return_lowest_bits(~crc_)
|
||||
# string = _string.decode("ascii")
|
||||
string = _string.decode("utf-8")
|
||||
print("")
|
||||
print("")
|
||||
print(string)
|
||||
print("")
|
||||
print("")
|
||||
if string:
|
||||
for char in string:
|
||||
ind = (crc_ >> 24)
|
||||
|
||||
@@ -7,7 +7,13 @@
|
||||
for more information regarding the file format.
|
||||
'''
|
||||
import os
|
||||
import itertools
|
||||
# import itertools
|
||||
# iZip is only available in 2.x
|
||||
try:
|
||||
from itertools import izip as zip
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
import struct
|
||||
import math
|
||||
# import logging
|
||||
@@ -16,9 +22,9 @@ import math
|
||||
from .Logger import Logger
|
||||
logging = Logger("Msh2").get_logger()
|
||||
|
||||
# import json
|
||||
try:
|
||||
import bson
|
||||
json = bson
|
||||
import bson as json
|
||||
except Exception as e:
|
||||
import json
|
||||
|
||||
@@ -120,6 +126,10 @@ class Msh(Packer):
|
||||
with open(filepath, 'wb') as fh:
|
||||
fh.write(self.pack())
|
||||
|
||||
def save_unchanged(self, filepath):
|
||||
with open(filepath, 'wb') as fh:
|
||||
fh.write(self.repack())
|
||||
|
||||
def save_json(self, filepath):
|
||||
'''Saves the .msh in JSON format.'''
|
||||
data = {
|
||||
@@ -326,7 +336,7 @@ class SceneInfo(Packer):
|
||||
def pack(self):
|
||||
'''Packs the scene information data.'''
|
||||
data = [b'SINF']
|
||||
data.append('size_ind')
|
||||
data.append('size')
|
||||
data.append(self.pack_NAME())
|
||||
data.append(self.pack_FRAM())
|
||||
data.append(self.bbox.pack())
|
||||
@@ -459,7 +469,7 @@ class Material(Packer):
|
||||
def pack(self):
|
||||
'''Packs the material into a MATD chunk.'''
|
||||
data = [b'MATD']
|
||||
data.append('size_indicator')
|
||||
data.append('size')
|
||||
data.append(self.pack_NAME())
|
||||
data.append(self.pack_DATA())
|
||||
data.append(self.pack_ATRB())
|
||||
@@ -660,7 +670,7 @@ class Model(Packer):
|
||||
|
||||
@classmethod
|
||||
def load_segmented_json(cls, folder, name):
|
||||
logging.debug('LOADING SEGMENTED MODEL %s %s', folder, name)
|
||||
# logging.debug('LOADING SEGMENTED MODEL %s %s', folder, name)
|
||||
with open(os.path.join(folder, '{0}.txt'.format(name)), 'r') as fh:
|
||||
model = Model.from_json(json.loads(fh.read()))
|
||||
seg_start = '{0} seg '.format(name)
|
||||
@@ -734,7 +744,7 @@ class Model(Packer):
|
||||
|
||||
def pack(self):
|
||||
'''Packs the MODL chunk. This should be used to retrieve the model in packed form.'''
|
||||
data = [b'MODL', 'sizeind']
|
||||
data = [b'MODL', 'size']
|
||||
data.append(self.pack_MTYP())
|
||||
data.append(self.pack_MNDX())
|
||||
data.append(self.pack_NAME())
|
||||
@@ -797,7 +807,7 @@ class Model(Packer):
|
||||
|
||||
def repack(self):
|
||||
'''Repacks the MODL chunk. This should be used to retrieve the model in packed form.'''
|
||||
data = [b'MODL', 'sizeind']
|
||||
data = [b'MODL', 'size']
|
||||
data.append(self.pack_MTYP())
|
||||
data.append(self.pack_MNDX())
|
||||
data.append(self.pack_NAME())
|
||||
@@ -915,7 +925,7 @@ class ModelCollection(object):
|
||||
'''Get model.index for model with name modelname.'''
|
||||
for model in self.models:
|
||||
if model.name == modelname:
|
||||
logging.debug('ModelCollection.get_index: {0} - {1}'.format(model.name, model.index))
|
||||
# logging.debug('ModelCollection.get_index: {0} - {1}'.format(model.name, model.index))
|
||||
return model.index
|
||||
return 0
|
||||
|
||||
@@ -1085,14 +1095,14 @@ class SegmentCollection(object):
|
||||
|
||||
def pack(self):
|
||||
data = []
|
||||
logging.debug(type(self.segments))
|
||||
logging.debug(self.segments)
|
||||
# logging.debug(type(self.segments))
|
||||
# logging.debug(self.segments)
|
||||
for segment in self.segments:
|
||||
data.append(segment.pack())
|
||||
return b''.join(data)
|
||||
|
||||
def repack(self):
|
||||
data = [bsegment.repack() for segment in self.segments]
|
||||
data = [segment.repack() for segment in self.segments]
|
||||
return b''.join(data)
|
||||
|
||||
|
||||
@@ -1156,7 +1166,7 @@ class SegmentGeometry(Packer):
|
||||
len_new_verts += 1
|
||||
self.vertices.vertices = new_vertices
|
||||
|
||||
logging.debug('Cleared %s doubles.', num_cleared_vertices)
|
||||
# logging.debug('Cleared %s doubles.', num_cleared_vertices)
|
||||
|
||||
def dump(self, fh):
|
||||
'''Dump information to open filehandler fileh.'''
|
||||
@@ -1190,7 +1200,7 @@ class ShadowGeometry(Packer):
|
||||
def __init__(self, collection=None):
|
||||
self.collection = collection
|
||||
self.classname = 'ShadowGeometry'
|
||||
self.data = ''
|
||||
self.data = b''
|
||||
self.positions = []
|
||||
self.edges = []
|
||||
|
||||
@@ -1218,7 +1228,7 @@ class ShadowGeometry(Packer):
|
||||
fh.write('\t\t\t\tNo data available.\n')
|
||||
|
||||
def repack(self):
|
||||
data = [b'SHDW', 'size', self.data]
|
||||
data = [b'SHDW', 'size', self.data.encode("ascii")]
|
||||
data[1] = struct.pack('<L', len(self.data))
|
||||
return b''.join(data)
|
||||
|
||||
@@ -1612,35 +1622,36 @@ class Face(object):
|
||||
|
||||
def pack(self):
|
||||
'''Packs the vertex indices for the STRP chunk.'''
|
||||
# index_map = self.collection.segment.index_map
|
||||
index_map = None
|
||||
if self.collection:
|
||||
if self.collection.segment:
|
||||
index_map = self.collection.segment.index_map
|
||||
|
||||
if (self.sides == 4) and (index_map is not None):
|
||||
logging.debug(f"Vertex indices for the STRP index_map chunk are: {self.sides}...")
|
||||
# logging.debug(f"Vertex indices for the STRP index_map chunk are: {self.sides}...")
|
||||
return struct.pack('<HHHH', index_map[self.vertices[0]] + 0x8000,
|
||||
index_map[self.vertices[1]] + 0x8000,
|
||||
index_map[self.vertices[2]],
|
||||
index_map[self.vertices[3]])
|
||||
elif (self.sides == 3) and (index_map is not None):
|
||||
logging.debug(f"Vertex indices for the STRP index_map chunk are: {self.sides}...")
|
||||
# logging.debug(f"Vertex indices for the STRP index_map chunk are: {self.sides}...")
|
||||
return struct.pack('<HHH', index_map[self.vertices[0]] + 0x8000,
|
||||
index_map[self.vertices[1]] + 0x8000,
|
||||
index_map[self.vertices[2]])
|
||||
elif (self.sides == 4) and (index_map is None):
|
||||
logging.debug(f"Vertex indices for the STRP chunk are: {self.sides}...")
|
||||
# logging.debug(f"Vertex indices for the STRP chunk are: {self.sides}...")
|
||||
return struct.pack('<HHHH', self.vertices[0] + 0x8000,
|
||||
self.vertices[1] + 0x8000,
|
||||
self.vertices[2],
|
||||
self.vertices[3])
|
||||
elif (self.sides == 3) and (index_map is None):
|
||||
logging.debug(f"Vertex indices for the STRP chunk are: {self.sides}...")
|
||||
# logging.debug(f"Vertex indices for the STRP chunk are: {self.sides}...")
|
||||
return struct.pack('<HHH', self.vertices[0] + 0x8000,
|
||||
self.vertices[1] + 0x8000,
|
||||
self.vertices[2])
|
||||
else:
|
||||
logging.debug("Vertex indices for the STRP chunk are empty...")
|
||||
# logging.debug("Vertex indices for the STRP chunk are empty...")
|
||||
return b''
|
||||
|
||||
def pack_tris(self):
|
||||
@@ -1976,7 +1987,7 @@ class Vertex(object):
|
||||
|
||||
def pack_weights(self):
|
||||
data = []
|
||||
for index, weight in itertools.izip(self.deformer_indices, self.weights):
|
||||
for index, weight in zip(self.deformer_indices, self.weights):
|
||||
data.append(struct.pack('<Lf', index, weight))
|
||||
return b''.join(data)
|
||||
|
||||
@@ -2073,7 +2084,7 @@ class VertexCollection(object):
|
||||
return b''.join(data)
|
||||
|
||||
def set_uvs(self, uv_list):
|
||||
for uv, vertex in itertools.izip(uv_list, self.vertices):
|
||||
for uv, vertex in zip(uv_list, self.vertices):
|
||||
vertex.u = uv[0]
|
||||
vertex.v = uv[1]
|
||||
|
||||
@@ -2083,7 +2094,7 @@ class VertexCollection(object):
|
||||
yield vertex.color.get()
|
||||
|
||||
def set_colors(self, color_list):
|
||||
for color, vertex in itertools.izip(color_list, self.vertices):
|
||||
for color, vertex in zip(color_list, self.vertices):
|
||||
vertex.color = color
|
||||
|
||||
def pack_colors(self):
|
||||
@@ -2108,7 +2119,7 @@ class VertexCollection(object):
|
||||
return weights
|
||||
|
||||
def set_weights(self, weights, deformers, indices):
|
||||
for weight, deformer_tuple, index_tpl, vertex in itertools.izip(weights, deformers, indices, self.vertices):
|
||||
for weight, deformer_tuple, index_tpl, vertex in zip(weights, deformers, indices, self.vertices):
|
||||
vertex.weights = weight
|
||||
vertex.deformers = deformer_tuple
|
||||
vertex.deformer_indices = index_tpl
|
||||
|
||||
2594
src/blender_addon/io_mesh_vrml2/backup/import_web3d.py
Normal file
2594
src/blender_addon/io_mesh_vrml2/backup/import_web3d.py
Normal file
File diff suppressed because it is too large
Load Diff
1300
src/blender_addon/io_mesh_vrml2/backup/vrml97_export.py
Normal file
1300
src/blender_addon/io_mesh_vrml2/backup/vrml97_export.py
Normal file
File diff suppressed because it is too large
Load Diff
2594
src/blender_addon/io_mesh_vrml2/import_web3d.py
Normal file
2594
src/blender_addon/io_mesh_vrml2/import_web3d.py
Normal file
File diff suppressed because it is too large
Load Diff
1297
src/blender_addon/io_mesh_vrml2/vrml97_export.py
Normal file
1297
src/blender_addon/io_mesh_vrml2/vrml97_export.py
Normal file
File diff suppressed because it is too large
Load Diff
1019
src_research_readme/blender_2.43_scripts/3ds_export.py
Normal file
1019
src_research_readme/blender_2.43_scripts/3ds_export.py
Normal file
File diff suppressed because it is too large
Load Diff
1007
src_research_readme/blender_2.43_scripts/3ds_import.py
Normal file
1007
src_research_readme/blender_2.43_scripts/3ds_import.py
Normal file
File diff suppressed because it is too large
Load Diff
125
src_research_readme/blender_2.43_scripts/Axiscopy.py
Normal file
125
src_research_readme/blender_2.43_scripts/Axiscopy.py
Normal file
@@ -0,0 +1,125 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus: <- these words are ignored
|
||||
Name: 'Axis Orientation Copy'
|
||||
Blender: 242
|
||||
Group: 'Object'
|
||||
Tip: 'Copy local axis orientation of active object to all selected meshes (changes mesh data)'
|
||||
"""
|
||||
|
||||
__author__ = "A Vanpoucke (xand)"
|
||||
__url__ = ("blenderartists.org", "www.blender.org",
|
||||
"French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
|
||||
__version__ = "2 17/12/05"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script copies the axis orientation -- X, Y and Z rotations -- of the
|
||||
active object to all selected meshes.
|
||||
|
||||
It's useful to align the orientations of all meshes of a structure, a human
|
||||
skeleton, for example.
|
||||
|
||||
Usage:
|
||||
|
||||
Select all mesh objects that need to have their orientations changed
|
||||
(reminder: keep SHIFT pressed after the first, to add each new one to the
|
||||
selection), then select the object whose orientation will be copied from and
|
||||
finally run this script to update the angles.
|
||||
|
||||
Notes:<br>
|
||||
This script changes mesh data: the vertices are transformed.<br>
|
||||
Before copying the orientation to each object, the script stores its
|
||||
transformation matrix. Then the angles are copied and after that the object's
|
||||
vertices are transformed "back" so that they still have the same positions as
|
||||
before. In other words, the rotations are updated, but you won't notice that
|
||||
just from looking at the objects.<br>
|
||||
Checking their X, Y and Z rotation values with "Transform Properties" in
|
||||
the 3D View's Object menu shows the angles are now the same of the active
|
||||
object. Or simply look at the transform manipulator handles in local transform
|
||||
orientation.
|
||||
"""
|
||||
|
||||
|
||||
# $Id: Axiscopy.py 9470 2006-12-25 23:14:48Z campbellbarton $
|
||||
#
|
||||
#----------------------------------------------
|
||||
# A Vanpoucke (xand)
|
||||
#from the previous script realignaxis
|
||||
#----------------------------------------------
|
||||
# Communiquer les problemes et erreurs sur:
|
||||
# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2003, 2004: A Vanpoucke
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
from Blender import *
|
||||
from Blender import Mathutils
|
||||
from Blender.Mathutils import *
|
||||
import BPyMessages
|
||||
|
||||
def realusers(data):
|
||||
users = data.users
|
||||
if data.fakeUser: users -= 1
|
||||
return users
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
scn_obs= Scene.GetCurrent().objects
|
||||
ob_act = scn_obs.active
|
||||
scn_obs = scn_obs.context
|
||||
|
||||
if not ob_act:
|
||||
BPyMessages.Error_NoActive()
|
||||
|
||||
obs = [(ob, ob.getData(mesh=1)) for ob in scn_obs if ob != ob_act]
|
||||
|
||||
for ob, me in obs:
|
||||
|
||||
if ob.type != 'Mesh':
|
||||
Draw.PupMenu("Error%t|Selection must be made up of mesh objects only")
|
||||
return
|
||||
|
||||
if realusers(me) != 1:
|
||||
Draw.PupMenu("Error%t|Meshes must be single user")
|
||||
return
|
||||
|
||||
if len(obs) < 1:
|
||||
Draw.PupMenu("Error: you must select at least 2 objects")
|
||||
return
|
||||
|
||||
result = Draw.PupMenu("Copy axis orientation from: " + ob_act.name + " ?%t|OK")
|
||||
if result == -1:
|
||||
return
|
||||
|
||||
for ob_target, me_target in obs:
|
||||
if ob_act.rot != ob_target.rot:
|
||||
rot_target = ob_target.matrixWorld.rotationPart().toEuler().toMatrix()
|
||||
rot_source = ob_act.matrixWorld.rotationPart().toEuler().toMatrix()
|
||||
rot_source_inv = rot_source.copy().invert()
|
||||
tx_mat = rot_target * rot_source_inv
|
||||
tx_mat.resize4x4()
|
||||
me_target.transform(tx_mat)
|
||||
ob_target.rot=ob_act.rot
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
1196
src_research_readme/blender_2.43_scripts/DirectX8Exporter.py
Normal file
1196
src_research_readme/blender_2.43_scripts/DirectX8Exporter.py
Normal file
File diff suppressed because it is too large
Load Diff
238
src_research_readme/blender_2.43_scripts/DirectX8Importer.py
Normal file
238
src_research_readme/blender_2.43_scripts/DirectX8Importer.py
Normal file
@@ -0,0 +1,238 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus:
|
||||
Name: 'DirectX(.x)...'
|
||||
Blender: 244
|
||||
Group: 'Import'
|
||||
|
||||
Tip: 'Import from DirectX text file format format.'
|
||||
"""
|
||||
# DirectXImporter.py version 1.2
|
||||
# Copyright (C) 2005 Arben OMARI -- omariarben@everyday.com
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# This script import meshes from DirectX text file format
|
||||
|
||||
# Grab the latest version here :www.omariben.too.it
|
||||
import bpy
|
||||
import Blender
|
||||
from Blender import Mesh,Object,Material,Texture,Image,Draw
|
||||
|
||||
|
||||
class xImport:
|
||||
def __init__(self, filename):
|
||||
global my_path
|
||||
self.file = open(filename, "r")
|
||||
my_path = Blender.sys.dirname(filename)
|
||||
|
||||
#
|
||||
self.lines = [l_split for l in self.file.readlines() for l_split in (' '.join(l.split()),) if l_split]
|
||||
|
||||
def Import(self):
|
||||
lines = self.lines
|
||||
print "importing into Blender ..."
|
||||
scene = bpy.data.scenes.active
|
||||
|
||||
mesh_indicies = {} # the index of each 'Mesh' is used as the key for those meshes indicies
|
||||
context_indicies = None # will raise an error if used!
|
||||
|
||||
|
||||
#Get the line of Texture Coords
|
||||
nr_uv_ind = 0
|
||||
|
||||
#Get Materials
|
||||
nr_fac_mat = 0
|
||||
i = -1
|
||||
mat_list = []
|
||||
tex_list = []
|
||||
mesh_line_indicies = []
|
||||
for j, line in enumerate(lines):
|
||||
l = line.strip()
|
||||
words = line.split()
|
||||
if words[0] == "Material" :
|
||||
#context_indicies["Material"] = j
|
||||
self.loadMaterials(j, mat_list, tex_list)
|
||||
elif words[0] == "MeshTextureCoords" :
|
||||
context_indicies["MeshTextureCoords"] = j
|
||||
#nr_uv_ind = j
|
||||
elif words[0] == "MeshMaterialList" :
|
||||
context_indicies["MeshMaterialList"] = j+2
|
||||
#nr_fac_mat = j + 2
|
||||
elif words[0] == "Mesh": # Avoid a second loop
|
||||
context_indicies = mesh_indicies[j] = {'MeshTextureCoords':0, 'MeshMaterialList':0}
|
||||
|
||||
for mesh_index, value in mesh_indicies.iteritems():
|
||||
mesh = Mesh.New()
|
||||
self.loadVertices(mesh_index, mesh, value['MeshTextureCoords'], value['MeshMaterialList'], tex_list)
|
||||
|
||||
mesh.materials = mat_list[:16]
|
||||
if value['MeshMaterialList']:
|
||||
self.loadMeshMaterials(value['MeshMaterialList'], mesh)
|
||||
scene.objects.new(mesh)
|
||||
|
||||
self.file.close()
|
||||
print "... finished"
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# CREATE THE MESH
|
||||
#------------------------------------------------------------------------------
|
||||
def loadVertices(self, nr_vr_ind, mesh, nr_uv, nr_fac_mat, tex_list):
|
||||
v_ind = nr_vr_ind + 1
|
||||
lin = self.lines[v_ind]
|
||||
if lin :
|
||||
lin_c = self.CleanLine(lin)
|
||||
nr_vert = int((lin_c.split()[0]))
|
||||
else :
|
||||
v_ind = nr_vr_ind + 2
|
||||
lin = self.lines[v_ind]
|
||||
lin_c = self.CleanLine(lin)
|
||||
nr_vert = int((lin_c.split()[0]))
|
||||
|
||||
#--------------------------------------------------
|
||||
nr_fac_li = v_ind + nr_vert +1
|
||||
lin_f = self.lines[nr_fac_li]
|
||||
if lin_f :
|
||||
lin_fc = self.CleanLine(lin_f)
|
||||
nr_face = int((lin_fc.split()[0]))
|
||||
else :
|
||||
nr_fac_li = v_ind + nr_vert +1
|
||||
lin_f = self.lines[nr_fac_li]
|
||||
lin_fc = self.CleanLine(lin_f)
|
||||
nr_face = int((lin_fc.split()[0]))
|
||||
|
||||
#Get Coordinates
|
||||
verts_list = [(0,0,0)] # WARNING - DUMMY VERT - solves EEKADOODLE ERROR
|
||||
for l in xrange(v_ind + 1, (v_ind + nr_vert +1)):
|
||||
line_v = self.lines[l]
|
||||
lin_v = self.CleanLine(line_v)
|
||||
words = lin_v.split()
|
||||
if len(words)==3:
|
||||
verts_list.append((float(words[0]),float(words[1]),float(words[2])))
|
||||
|
||||
mesh.verts.extend(verts_list)
|
||||
del verts_list
|
||||
|
||||
face_list = []
|
||||
#Make Faces
|
||||
i = 0
|
||||
mesh_verts = mesh.verts
|
||||
for f in xrange(nr_fac_li + 1, (nr_fac_li + nr_face + 1)):
|
||||
i += 1
|
||||
line_f = self.lines[f]
|
||||
lin_f = self.CleanLine(line_f)
|
||||
|
||||
# +1 for dummy vert only!
|
||||
words = lin_f.split()
|
||||
if len(words) == 5:
|
||||
face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3]), 1+int(words[4])))
|
||||
elif len(words) == 4:
|
||||
face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3])))
|
||||
|
||||
mesh.faces.extend(face_list)
|
||||
del face_list
|
||||
|
||||
if nr_uv :
|
||||
mesh.faceUV = True
|
||||
for f in mesh.faces:
|
||||
fuv = f.uv
|
||||
for ii, v in enumerate(f):
|
||||
# _u, _v = self.CleanLine(self.lines[nr_uv + 2 + v.index]).split()
|
||||
|
||||
# Use a dummy vert
|
||||
_u, _v = self.CleanLine(self.lines[nr_uv + 1 + v.index]).split()
|
||||
|
||||
fuv[ii].x = float(_u)
|
||||
fuv[ii].y = float(_v)
|
||||
|
||||
if nr_fac_mat :
|
||||
fac_line = self.lines[nr_fac_mat + i]
|
||||
fixed_fac = self.CleanLine(fac_line)
|
||||
w_tex = int(fixed_fac.split()[0])
|
||||
f.image = tex_list[w_tex]
|
||||
|
||||
# remove dummy vert
|
||||
mesh.verts.delete([0,])
|
||||
|
||||
def CleanLine(self,line):
|
||||
return line.replace(\
|
||||
";", " ").replace(\
|
||||
'"', ' ').replace(\
|
||||
"{", " ").replace(\
|
||||
"}", " ").replace(\
|
||||
",", " ").replace(\
|
||||
"'", " ")
|
||||
|
||||
#------------------------------------------------------------------
|
||||
# CREATE MATERIALS
|
||||
#------------------------------------------------------------------
|
||||
def loadMaterials(self, nr_mat, mat_list, tex_list):
|
||||
|
||||
def load_image(name):
|
||||
try:
|
||||
return Image.Load(Blender.sys.join(my_path,name))
|
||||
except:
|
||||
return None
|
||||
|
||||
mat = bpy.data.materials.new()
|
||||
line = self.lines[nr_mat + 1]
|
||||
fixed_line = self.CleanLine(line)
|
||||
words = fixed_line.split()
|
||||
mat.rgbCol = [float(words[0]),float(words[1]),float(words[2])]
|
||||
mat.setAlpha(float(words[3]))
|
||||
mat_list.append(mat)
|
||||
l = self.lines[nr_mat + 5]
|
||||
fix_3_line = self.CleanLine(l)
|
||||
tex_n = fix_3_line.split()
|
||||
|
||||
if tex_n and tex_n[0] == "TextureFilename" :
|
||||
|
||||
if len(tex_n) > 1:
|
||||
tex_list.append(load_image(tex_n[1]))
|
||||
|
||||
if len(tex_n) <= 1 :
|
||||
|
||||
l_succ = self.lines[nr_mat + 6]
|
||||
fix_3_succ = self.CleanLine(l_succ)
|
||||
tex_n_succ = fix_3_succ.split()
|
||||
tex_list.append(load_image(tex_n_succ[0]))
|
||||
else :
|
||||
tex_list.append(None) # no texture for this index
|
||||
|
||||
return mat_list, tex_list
|
||||
#------------------------------------------------------------------
|
||||
# SET MATERIALS
|
||||
#------------------------------------------------------------------
|
||||
def loadMeshMaterials(self, nr_fc_mat, mesh):
|
||||
for face in mesh.faces:
|
||||
nr_fc_mat += 1
|
||||
line = self.lines[nr_fc_mat]
|
||||
fixed_line = self.CleanLine(line)
|
||||
wrd = fixed_line.split()
|
||||
mat_idx = int(wrd[0])
|
||||
face.mat = mat_idx
|
||||
|
||||
#------------------------------------------------------------------
|
||||
# MAIN
|
||||
#------------------------------------------------------------------
|
||||
def my_callback(filename):
|
||||
if not filename.lower().endswith('.x'): print "Not an .x file"
|
||||
ximport = xImport(filename)
|
||||
ximport.Import()
|
||||
|
||||
arg = __script__['arg']
|
||||
|
||||
if __name__ == '__main__':
|
||||
Blender.Window.FileSelector(my_callback, "Import DirectX", "*.x")
|
||||
|
||||
#my_callback('/fe/x/directxterrain.x')
|
||||
#my_callback('/fe/x/Male_Normal_MAX.X')
|
||||
#my_callback('/fe/x/male_ms3d.x')
|
||||
523
src_research_readme/blender_2.43_scripts/IDPropBrowser.py
Normal file
523
src_research_readme/blender_2.43_scripts/IDPropBrowser.py
Normal file
@@ -0,0 +1,523 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'ID Property Browser'
|
||||
Blender: 242
|
||||
Group: 'Help'
|
||||
Tooltip: 'Browse ID properties'
|
||||
"""
|
||||
|
||||
__author__ = "Joe Eagar"
|
||||
__version__ = "0.3.108"
|
||||
__email__ = "joeedh@gmail.com"
|
||||
__bpydoc__ = """\
|
||||
|
||||
Allows browsing, creating and editing of ID Properties
|
||||
for various ID block types such as mesh, scene, object,
|
||||
etc.
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# ID Property Browser.
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
from Blender import *
|
||||
from Blender.BGL import *
|
||||
from Blender.Types import IDGroupType, IDArrayType
|
||||
import Blender
|
||||
|
||||
def IsInRectWH(mx, my, x, y, wid, hgt):
|
||||
if mx >= x and mx <= x + wid:
|
||||
if my >= y and my <= y + hgt:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
Button_Back = 1
|
||||
Button_New = 2
|
||||
Button_MatMenu = 3
|
||||
Button_TypeMenu = 4
|
||||
|
||||
ButStart = 55
|
||||
|
||||
IDP_String = 0
|
||||
IDP_Int = 1
|
||||
IDP_Float = 2
|
||||
IDP_Array = 5
|
||||
IDP_Group = 6
|
||||
|
||||
ButDelStart = 255
|
||||
#max limit for string input button
|
||||
strmax = 100
|
||||
|
||||
State_Normal = 0
|
||||
State_InArray = 1
|
||||
|
||||
#IDTypeModules entries are of form [module, active_object_index, module_name]
|
||||
IDTypeModules = [[Scene, 0, "Scenes"], [Object, 0, "Objects"], [Mesh, 0, "Meshes"]]
|
||||
IDTypeModules += [[Material, 0, "Materials"], [Texture, 0, "Textures"]]
|
||||
IDTypeModules += [[Image, 0, "Images"]]
|
||||
|
||||
class IDArrayBrowser:
|
||||
array = 0
|
||||
parentbrowser = 0
|
||||
buts = 0
|
||||
|
||||
def __init__(self):
|
||||
self.buts = []
|
||||
|
||||
def Draw(self):
|
||||
pb = self.parentbrowser
|
||||
x = pb.x
|
||||
y = pb.y
|
||||
width = pb.width
|
||||
height = pb.height
|
||||
pad = pb.pad
|
||||
itemhgt = pb.itemhgt
|
||||
cellwid = 65
|
||||
y = y + height - itemhgt - pad
|
||||
|
||||
Draw.PushButton("Back", Button_Back, x, y, 40, 20)
|
||||
y -= itemhgt + pad
|
||||
|
||||
self.buts = []
|
||||
Draw.BeginAlign()
|
||||
for i in xrange(len(self.array)):
|
||||
st = ""
|
||||
if type(self.array[0]) == float:
|
||||
st = "%.5f" % self.array[i]
|
||||
else: st = str(self.array[i])
|
||||
|
||||
b = Draw.String("", ButStart+i, x, y, cellwid, itemhgt, st, 30)
|
||||
self.buts.append(b)
|
||||
x += cellwid + pad
|
||||
if x + cellwid + pad > width:
|
||||
x = 0
|
||||
y -= itemhgt + pad
|
||||
Draw.EndAlign()
|
||||
def Button(self, bval):
|
||||
if bval == Button_Back:
|
||||
self.parentbrowser.state = State_Normal
|
||||
self.parentbrowser.array = 0
|
||||
self.buts = []
|
||||
Draw.Draw()
|
||||
self.array = 0
|
||||
elif bval >= ButStart:
|
||||
i = bval - ButStart
|
||||
st = self.buts[i].val
|
||||
n = 0
|
||||
if type(self.array[0]) == float:
|
||||
try:
|
||||
n = int(st)
|
||||
except:
|
||||
return
|
||||
elif type(self.array[0]) == int:
|
||||
try:
|
||||
n = float(st)
|
||||
except:
|
||||
return
|
||||
|
||||
self.array[i] = n
|
||||
Draw.Draw()
|
||||
|
||||
def Evt(self, evt, val):
|
||||
if evt == Draw.ESCKEY:
|
||||
Draw.Exit()
|
||||
|
||||
class IDPropertyBrowser:
|
||||
width = 0
|
||||
height = 0
|
||||
x = 0
|
||||
y = 0
|
||||
scrollx = 0
|
||||
scrolly = 0
|
||||
itemhgt = 22
|
||||
pad = 2
|
||||
|
||||
group = 0
|
||||
parents = 0 #list stack of parent groups
|
||||
active_item = -1
|
||||
mousecursor = 0
|
||||
_i = 0
|
||||
buts = []
|
||||
|
||||
state = 0
|
||||
array = 0
|
||||
prop = 0
|
||||
|
||||
IDList = 0
|
||||
idindex = 0
|
||||
idblock = 0
|
||||
|
||||
type = 0 # attach buildin type() method to class
|
||||
# since oddly it's not available to button
|
||||
# callbacks! EEK! :(
|
||||
|
||||
def __init__(self, idgroup, mat, x, y, wid, hgt):
|
||||
self.group = idgroup
|
||||
self.prop = idgroup
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.width = wid
|
||||
self.height = hgt
|
||||
self.mousecursor = [0, 0]
|
||||
self.parents = []
|
||||
self.idblock = mat
|
||||
self.type = type
|
||||
|
||||
def DrawBox(self, glmode, x, y, width, height):
|
||||
glBegin(glmode)
|
||||
glVertex2f(x, y)
|
||||
glVertex2f(x+width, y)
|
||||
glVertex2f(x+width, y+height)
|
||||
glVertex2f(x, y+height)
|
||||
glEnd()
|
||||
|
||||
def Draw(self):
|
||||
global IDTypeModules
|
||||
|
||||
#first draw outlining box :)
|
||||
glColor3f(0, 0, 0)
|
||||
self.DrawBox(GL_LINE_LOOP, self.x, self.y, self.width, self.height)
|
||||
|
||||
itemhgt = self.itemhgt
|
||||
pad = self.pad
|
||||
x = self.x
|
||||
y = self.y + self.height - itemhgt - pad
|
||||
|
||||
if self.state == State_InArray:
|
||||
self.array.Draw()
|
||||
return
|
||||
|
||||
plist = []
|
||||
self.buts = []
|
||||
for p in self.group.iteritems():
|
||||
plist.append(p)
|
||||
|
||||
#-------do top buttons----------#
|
||||
Draw.BeginAlign()
|
||||
Draw.PushButton("New", Button_New, x, y, 40, 20)
|
||||
x += 40 + pad
|
||||
#do the menu button for all materials
|
||||
st = ""
|
||||
|
||||
blocks = IDTypeModules[self.IDList][0].Get()
|
||||
i = 1
|
||||
mi = 0
|
||||
for m in blocks:
|
||||
if m.name == self.idblock.name:
|
||||
mi = i
|
||||
st += m.name + " %x" + str(i) + "|"
|
||||
i += 1
|
||||
|
||||
self.menubut = Draw.Menu(st, Button_MatMenu, x, y, 100, 20, mi)
|
||||
|
||||
x += 100 + pad
|
||||
|
||||
st = ""
|
||||
i = 0
|
||||
for e in IDTypeModules:
|
||||
st += e[2] + " %x" + str(i+1) + "|"
|
||||
i += 1
|
||||
|
||||
cur = self.IDList + 1
|
||||
self.idmenu = Draw.Menu(st, Button_TypeMenu, x, y, 100, 20, cur)
|
||||
x = self.x
|
||||
y -= self.itemhgt + self.pad
|
||||
Draw.EndAlign()
|
||||
|
||||
|
||||
#-----------do property items---------#
|
||||
i = 0
|
||||
while y > self.y - 20 - pad and i < len(plist):
|
||||
k = plist[i][0]
|
||||
p = plist[i][1]
|
||||
if i == self.active_item:
|
||||
glColor3f(0.5, 0.4, 0.3)
|
||||
self.DrawBox(GL_POLYGON, x+pad, y, self.width-pad*2, itemhgt)
|
||||
|
||||
glColor3f(0, 0, 0)
|
||||
self.DrawBox(GL_LINE_LOOP, x+pad, y, self.width-pad*2, itemhgt)
|
||||
|
||||
glRasterPos2f(x+pad*2, y+5)
|
||||
Draw.Text(str(k)) #str(self.mousecursor) + " " + str(self.active_item)) #p.name)
|
||||
tlen = Draw.GetStringWidth(str(k))
|
||||
|
||||
type_p = type(p)
|
||||
if type_p == str:
|
||||
b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 200, itemhgt, p, strmax)
|
||||
self.buts.append(b)
|
||||
elif type_p in [int, float]:
|
||||
#only do precision to 5 points on floats
|
||||
st = ""
|
||||
if type_p == float:
|
||||
st = "%.5f" % p
|
||||
else: st = str(p)
|
||||
b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 75, itemhgt, st, strmax)
|
||||
self.buts.append(b)
|
||||
else:
|
||||
glRasterPos2f(x+pad*2 +tlen+10, y+5)
|
||||
if type_p == Types.IDArrayType:
|
||||
Draw.Text('(array, click to edit)')
|
||||
elif type_p == Types.IDGroupType:
|
||||
Draw.Text('(group, click to edit)')
|
||||
|
||||
|
||||
self.buts.append(None)
|
||||
|
||||
Draw.PushButton("Del", ButDelStart+i, x+self.width-35, y, 30, 20)
|
||||
|
||||
i += 1
|
||||
y -= self.itemhgt + self.pad
|
||||
|
||||
if len(self.parents) != 0:
|
||||
Draw.PushButton("Back", Button_Back, x, y, 40, 20)
|
||||
x = x + 40 + pad
|
||||
|
||||
def SetActive(self):
|
||||
m = self.mousecursor
|
||||
itemhgt = self.itemhgt
|
||||
pad = self.pad
|
||||
|
||||
x = self.x + pad
|
||||
y = self.y + self.height - itemhgt - pad - itemhgt
|
||||
|
||||
plist = []
|
||||
for p in self.group.iteritems():
|
||||
plist.append(p)
|
||||
|
||||
self.active_item = -1
|
||||
i = 0
|
||||
while y > self.y and i < len(plist):
|
||||
p = plist[i]
|
||||
if IsInRectWH(m[0], m[1], x, y, self.width-pad, itemhgt):
|
||||
self.active_item = i
|
||||
|
||||
i += 1
|
||||
y -= self.itemhgt + self.pad
|
||||
|
||||
def EventIn(self, evt, val):
|
||||
if self.state == State_InArray:
|
||||
self.array.Evt(evt, val)
|
||||
|
||||
if evt == Draw.ESCKEY:
|
||||
Draw.Exit()
|
||||
if evt == Draw.MOUSEX or evt == Draw.MOUSEY:
|
||||
size = Buffer(GL_FLOAT, 4)
|
||||
glGetFloatv(GL_SCISSOR_BOX, size)
|
||||
if evt == Draw.MOUSEX:
|
||||
self.mousecursor[0] = val - size[0]
|
||||
else:
|
||||
self.mousecursor[1] = val - size[1]
|
||||
del size
|
||||
|
||||
self.SetActive()
|
||||
self._i += 1
|
||||
if self._i == 5:
|
||||
Draw.Draw()
|
||||
self._i = 0
|
||||
|
||||
|
||||
if evt == Draw.LEFTMOUSE and val == 1:
|
||||
plist = list(self.group.iteritems())
|
||||
a = self.active_item
|
||||
if a >= 0 and a < len(plist):
|
||||
p = plist[a]
|
||||
|
||||
basictypes = [IDGroupType, float, str, int]
|
||||
if type(p[1]) == IDGroupType:
|
||||
self.parents.append(self.group)
|
||||
self.group = p[1]
|
||||
self.active_item = -1
|
||||
Draw.Draw()
|
||||
elif type(p[1]) == IDArrayType:
|
||||
self.array = IDArrayBrowser()
|
||||
self.array.array = p[1]
|
||||
self.array.parentbrowser = self
|
||||
self.state = State_InArray
|
||||
Draw.Draw()
|
||||
|
||||
if evt == Draw.TKEY and val == 1:
|
||||
try:
|
||||
self.prop['float'] = 0.0
|
||||
self.prop['int'] = 1
|
||||
self.prop['string'] = "hi!"
|
||||
self.prop['float array'] = [0, 0, 1.0, 0]
|
||||
self.prop['int array'] = [0, 0, 0, 0]
|
||||
self.prop.data['a subgroup'] = {"int": 0, "float": 0.0, "anothergroup": {"a": 0.0, "intarr": [0, 0, 0, 0]}}
|
||||
Draw.Draw()
|
||||
except:
|
||||
Draw.PupMenu("Can only do T once per block, the test names are already taken!")
|
||||
|
||||
|
||||
def Button(self, bval):
|
||||
global IDTypeModules
|
||||
if self.state == State_InArray:
|
||||
self.array.Button(bval)
|
||||
return
|
||||
|
||||
if bval == Button_MatMenu:
|
||||
global IDTypeModules
|
||||
|
||||
val = self.idindex = self.menubut.val - 1
|
||||
i = self.IDList
|
||||
block = IDTypeModules[i][0].Get()[val]
|
||||
self.idblock = block
|
||||
self.prop = block.properties
|
||||
self.group = self.prop
|
||||
self.active_item = -1
|
||||
self.parents = []
|
||||
Draw.Draw()
|
||||
|
||||
if bval == Button_TypeMenu:
|
||||
i = IDTypeModules[self.idmenu.val-1]
|
||||
if len(i[0].Get()) == 0:
|
||||
Draw.PupMenu("Error%t|There are no " + i[2] + "!")
|
||||
return
|
||||
|
||||
IDTypeModules[self.IDList][1] = self.idindex
|
||||
self.IDList = self.idmenu.val-1
|
||||
val = self.idindex = IDTypeModules[self.IDList][1]
|
||||
i = self.IDList
|
||||
block = IDTypeModules[i][0].Get()[val]
|
||||
self.idblock = block
|
||||
self.prop = block.properties
|
||||
self.group = self.prop
|
||||
self.active_item = -1
|
||||
self.parents = []
|
||||
Draw.Draw()
|
||||
|
||||
if bval >= ButDelStart:
|
||||
plist = [p for p in self.group]
|
||||
prop = plist[bval - ButDelStart]
|
||||
del self.group[prop]
|
||||
Draw.Draw()
|
||||
|
||||
elif bval >= ButStart:
|
||||
plist = list(self.group.iteritems())
|
||||
|
||||
prop = plist[bval - ButStart]
|
||||
print prop
|
||||
|
||||
if self.type(prop[1]) == str:
|
||||
self.group[prop[0]] = self.buts[bval - ButStart].val
|
||||
elif self.type(prop[1]) == int:
|
||||
i = self.buts[bval - ButStart].val
|
||||
try:
|
||||
i = int(i)
|
||||
self.group[prop[0]] = i
|
||||
except:
|
||||
Draw.Draw()
|
||||
return
|
||||
Draw.Draw()
|
||||
elif self.type(prop[1]) == float:
|
||||
f = self.buts[bval - ButStart].val
|
||||
try:
|
||||
f = float(f)
|
||||
self.group[prop[0]] = f
|
||||
except:
|
||||
Draw.Draw()
|
||||
return
|
||||
Draw.Draw()
|
||||
|
||||
elif bval == Button_Back:
|
||||
self.group = self.parents[len(self.parents)-1]
|
||||
self.parents.pop(len(self.parents)-1)
|
||||
Draw.Draw()
|
||||
|
||||
elif bval == Button_New:
|
||||
name = Draw.Create("untitled")
|
||||
stype = Draw.Create(0)
|
||||
gtype = Draw.Create(0)
|
||||
ftype = Draw.Create(0)
|
||||
itype = Draw.Create(0)
|
||||
atype = Draw.Create(0)
|
||||
|
||||
block = []
|
||||
block.append(("Name: ", name, 0, 30, "Click to type in the name of the new ID property"))
|
||||
block.append("Type")
|
||||
block.append(("String", stype))
|
||||
block.append(("Subgroup", gtype))
|
||||
block.append(("Float", ftype))
|
||||
block.append(("Int", itype))
|
||||
block.append(("Array", atype))
|
||||
|
||||
retval = Blender.Draw.PupBlock("New IDProperty", block)
|
||||
if retval == 0: return
|
||||
|
||||
name = name.val
|
||||
i = 1
|
||||
stop = 0
|
||||
while stop == 0:
|
||||
stop = 1
|
||||
for p in self.group:
|
||||
if p == name:
|
||||
d = name.rfind(".")
|
||||
if d != -1:
|
||||
name = name[:d]
|
||||
name = name + "." + str(i).zfill(3)
|
||||
i += 1
|
||||
stop = 0
|
||||
|
||||
type = "String"
|
||||
if stype.val:
|
||||
self.group[name] = ""
|
||||
elif gtype.val:
|
||||
self.group[name] = {}
|
||||
elif ftype.val:
|
||||
self.group[name] = 0.0
|
||||
elif itype.val:
|
||||
self.group[name] = 0 #newProperty("Int", name, 0)
|
||||
elif atype.val:
|
||||
arrfloat = Draw.Create(1)
|
||||
arrint = Draw.Create(0)
|
||||
arrlen = Draw.Create(3)
|
||||
block = []
|
||||
block.append("Type")
|
||||
block.append(("Float", arrfloat, "Make a float array"))
|
||||
block.append(("Int", arrint, "Make an integer array"))
|
||||
block.append(("Len", arrlen, 2, 200))
|
||||
|
||||
if Blender.Draw.PupBlock("Array Properties", block):
|
||||
if arrfloat.val:
|
||||
tmpl = 0.0
|
||||
elif arrint.val:
|
||||
tmpl = 0
|
||||
else:
|
||||
return
|
||||
|
||||
self.group[name] = [tmpl] * arrlen.val
|
||||
|
||||
|
||||
def Go(self):
|
||||
Draw.Register(self.Draw, self.EventIn, self.Button)
|
||||
|
||||
scenes = Scene.Get()
|
||||
|
||||
size = Window.GetAreaSize()
|
||||
browser = IDPropertyBrowser(scenes[0].properties, scenes[0], 2, 2, size[0], size[1])
|
||||
browser.Go()
|
||||
|
||||
#a = prop.newProperty("String", "hwello!", "bleh")
|
||||
#b = prop.newProperty("Group", "subgroup")
|
||||
|
||||
#for p in prop:
|
||||
#print p.name
|
||||
828
src_research_readme/blender_2.43_scripts/ac3d_export.py
Normal file
828
src_research_readme/blender_2.43_scripts/ac3d_export.py
Normal file
@@ -0,0 +1,828 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus:
|
||||
Name: 'AC3D (.ac)...'
|
||||
Blender: 243
|
||||
Group: 'Export'
|
||||
Tip: 'Export selected meshes to AC3D (.ac) format'
|
||||
"""
|
||||
|
||||
__author__ = "Willian P. Germano"
|
||||
__url__ = ("blender", "blenderartists.org", "AC3D's homepage, http://www.ac3d.org",
|
||||
"PLib 3d gaming lib, http://plib.sf.net")
|
||||
__version__ = "2.44 2007-05-05"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script exports selected Blender meshes to AC3D's .ac file format.
|
||||
|
||||
AC3D is a simple commercial 3d modeller also built with OpenGL.
|
||||
The .ac file format is an easy to parse text format well supported,
|
||||
for example, by the PLib 3d gaming library (AC3D 3.x).
|
||||
|
||||
Supported:<br>
|
||||
UV-textured meshes with hierarchy (grouping) information.
|
||||
|
||||
Missing:<br>
|
||||
The 'url' tag, specific to AC3D. It is easy to add by hand to the exported
|
||||
file, if needed.
|
||||
|
||||
Known issues:<br>
|
||||
The ambient and emit data we can retrieve from Blender are single values,
|
||||
that this script copies to R, G, B, giving shades of gray.<br>
|
||||
Loose edges (lines) receive the first material found in the mesh, if any, or a default white material.<br>
|
||||
In AC3D 4 "compatibility mode":<br>
|
||||
- shininess of materials is taken from the shader specularity value in Blender, mapped from [0.0, 2.0] to [0, 128];<br>
|
||||
- crease angle is exported, but in Blender it is limited to [1, 80], since there are other more powerful ways to control surface smoothing. In AC3D 4.0 crease's range is [0.0, 180.0];
|
||||
|
||||
Config Options:<br>
|
||||
toggle:<br>
|
||||
- AC3D 4 mode: unset it to export without the 'crease' tag that was
|
||||
introduced with AC3D 4.0 and with the old material handling;<br>
|
||||
- global coords: transform all vertices of all meshes to global coordinates;<br>
|
||||
- skip data: set it if you don't want mesh names (ME:, not OB: field)
|
||||
to be exported as strings for AC's "data" tags (19 chars max);<br>
|
||||
- rgb mirror color can be exported as ambient and/or emissive if needed,
|
||||
since Blender handles these differently;<br>
|
||||
- default mat: a default (white) material is added if some mesh was
|
||||
left without mats -- it's better to always add your own materials;<br>
|
||||
- no split: don't split meshes (see above);<br>
|
||||
- set texture dir: override the actual textures path with a given default
|
||||
path (or simply export the texture names, without dir info, if the path is
|
||||
empty);<br>
|
||||
- per face 1 or 2 sided: override the "Double Sided" button that defines this behavior per whole mesh in favor of the UV Face Select mode "twosided" per face atribute;<br>
|
||||
- only selected: only consider selected objects when looking for meshes
|
||||
to export (read notes below about tokens, too);<br>
|
||||
strings:<br>
|
||||
- export dir: default dir to export to;<br>
|
||||
- texture dir: override textures path with this path if 'set texture dir'
|
||||
toggle is "on".
|
||||
|
||||
Notes:<br>
|
||||
This version updates:<br>
|
||||
- modified meshes are correctly exported, no need to apply the modifiers in Blender;<br>
|
||||
- correctly export each used material, be it assigned to the object or to its mesh data;<br>
|
||||
- exporting lines (edges) is again supported; color comes from first material found in the mesh, if any, or a default white one.<br>
|
||||
- there's a new option to choose between exporting meshes with transformed (global) coordinates or local ones;<br>
|
||||
Multiple textures per mesh are supported (mesh gets split);<br>
|
||||
Parents are exported as a group containing both the parent and its children;<br>
|
||||
Start mesh object names (OB: field) with "!" or "#" if you don't want them to be exported;<br>
|
||||
Start mesh object names (OB: field) with "=" or "$" to prevent them from being split (meshes with multiple textures or both textured and non textured faces are split unless this trick is used or the "no split" option is set.
|
||||
"""
|
||||
|
||||
# $Id: ac3d_export.py 14530 2008-04-23 14:04:05Z campbellbarton $
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# AC3DExport version 2.44
|
||||
# Program versions: Blender 2.42+ and AC3Db files (means version 0xb)
|
||||
# new: updated for new Blender version and Mesh module; supports lines (edges) again;
|
||||
# option to export vertices transformed to global coordinates or not; now the modified
|
||||
# (by existing mesh modifiers) mesh is exported; materials are properly exported, no
|
||||
# matter if each of them is linked to the mesh or to the object. New (2.43.1): loose
|
||||
# edges use color of first material found in the mesh, if any.
|
||||
# --------------------------------------------------------------------------
|
||||
# Thanks: Steve Baker for discussions and inspiration; for testing, bug
|
||||
# reports, suggestions, patches: David Megginson, Filippo di Natale,
|
||||
# Franz Melchior, Campbell Barton, Josh Babcock, Ralf Gerlich, Stewart Andreason.
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
from Blender import Object, Mesh, Material, Image, Mathutils, Registry
|
||||
from Blender import sys as bsys
|
||||
|
||||
# Globals
|
||||
REPORT_DATA = {
|
||||
'main': [],
|
||||
'errors': [],
|
||||
'warns': [],
|
||||
'nosplit': [],
|
||||
'noexport': []
|
||||
}
|
||||
TOKENS_DONT_EXPORT = ['!', '#']
|
||||
TOKENS_DONT_SPLIT = ['=', '$']
|
||||
|
||||
MATIDX_ERROR = 0
|
||||
|
||||
# flags:
|
||||
LOOSE = Mesh.EdgeFlags['LOOSE']
|
||||
FACE_TWOSIDED = Mesh.FaceModes['TWOSIDE']
|
||||
MESH_TWOSIDED = Mesh.Modes['TWOSIDED']
|
||||
|
||||
REG_KEY = 'ac3d_export'
|
||||
|
||||
# config options:
|
||||
GLOBAL_COORDS = True
|
||||
SKIP_DATA = False
|
||||
MIRCOL_AS_AMB = False
|
||||
MIRCOL_AS_EMIS = False
|
||||
ADD_DEFAULT_MAT = True
|
||||
SET_TEX_DIR = True
|
||||
TEX_DIR = ''
|
||||
AC3D_4 = True # export crease value, compatible with AC3D 4 loaders
|
||||
NO_SPLIT = False
|
||||
ONLY_SELECTED = True
|
||||
EXPORT_DIR = ''
|
||||
PER_FACE_1_OR_2_SIDED = True
|
||||
|
||||
tooltips = {
|
||||
'GLOBAL_COORDS': "transform all vertices of all meshes to global coordinates",
|
||||
'SKIP_DATA': "don't export mesh names as data fields",
|
||||
'MIRCOL_AS_AMB': "export mirror color as ambient color",
|
||||
'MIRCOL_AS_EMIS': "export mirror color as emissive color",
|
||||
'ADD_DEFAULT_MAT': "always add a default white material",
|
||||
'SET_TEX_DIR': "don't export default texture paths (edit also \"tex dir\")",
|
||||
'EXPORT_DIR': "default / last folder used to export .ac files to",
|
||||
'TEX_DIR': "(see \"set tex dir\") dir to prepend to all exported texture names (leave empty for no dir)",
|
||||
'AC3D_4': "compatibility mode, adds 'crease' tag and slightly better material support",
|
||||
'NO_SPLIT': "don't split meshes with multiple textures (or both textured and non textured polygons)",
|
||||
'ONLY_SELECTED': "export only selected objects",
|
||||
'PER_FACE_1_OR_2_SIDED': "override \"Double Sided\" button in favor of per face \"twosided\" attribute (UV Face Select mode)"
|
||||
}
|
||||
|
||||
def update_RegistryInfo():
|
||||
d = {}
|
||||
d['SKIP_DATA'] = SKIP_DATA
|
||||
d['MIRCOL_AS_AMB'] = MIRCOL_AS_AMB
|
||||
d['MIRCOL_AS_EMIS'] = MIRCOL_AS_EMIS
|
||||
d['ADD_DEFAULT_MAT'] = ADD_DEFAULT_MAT
|
||||
d['SET_TEX_DIR'] = SET_TEX_DIR
|
||||
d['TEX_DIR'] = TEX_DIR
|
||||
d['AC3D_4'] = AC3D_4
|
||||
d['NO_SPLIT'] = NO_SPLIT
|
||||
d['EXPORT_DIR'] = EXPORT_DIR
|
||||
d['ONLY_SELECTED'] = ONLY_SELECTED
|
||||
d['PER_FACE_1_OR_2_SIDED'] = PER_FACE_1_OR_2_SIDED
|
||||
d['tooltips'] = tooltips
|
||||
d['GLOBAL_COORDS'] = GLOBAL_COORDS
|
||||
Registry.SetKey(REG_KEY, d, True)
|
||||
|
||||
# Looking for a saved key in Blender.Registry dict:
|
||||
rd = Registry.GetKey(REG_KEY, True)
|
||||
|
||||
if rd:
|
||||
try:
|
||||
AC3D_4 = rd['AC3D_4']
|
||||
SKIP_DATA = rd['SKIP_DATA']
|
||||
MIRCOL_AS_AMB = rd['MIRCOL_AS_AMB']
|
||||
MIRCOL_AS_EMIS = rd['MIRCOL_AS_EMIS']
|
||||
ADD_DEFAULT_MAT = rd['ADD_DEFAULT_MAT']
|
||||
SET_TEX_DIR = rd['SET_TEX_DIR']
|
||||
TEX_DIR = rd['TEX_DIR']
|
||||
EXPORT_DIR = rd['EXPORT_DIR']
|
||||
ONLY_SELECTED = rd['ONLY_SELECTED']
|
||||
NO_SPLIT = rd['NO_SPLIT']
|
||||
PER_FACE_1_OR_2_SIDED = rd['PER_FACE_1_OR_2_SIDED']
|
||||
GLOBAL_COORDS = rd['GLOBAL_COORDS']
|
||||
except KeyError: update_RegistryInfo()
|
||||
|
||||
else:
|
||||
update_RegistryInfo()
|
||||
|
||||
VERBOSE = True
|
||||
CONFIRM_OVERWRITE = True
|
||||
|
||||
# check General scripts config key for default behaviors
|
||||
rd = Registry.GetKey('General', True)
|
||||
if rd:
|
||||
try:
|
||||
VERBOSE = rd['verbose']
|
||||
CONFIRM_OVERWRITE = rd['confirm_overwrite']
|
||||
except: pass
|
||||
|
||||
|
||||
# The default material to be used when necessary (see ADD_DEFAULT_MAT)
|
||||
DEFAULT_MAT = \
|
||||
'MATERIAL "DefaultWhite" rgb 1 1 1 amb 1 1 1 emis 0 0 0 \
|
||||
spec 0.5 0.5 0.5 shi 64 trans 0'
|
||||
|
||||
# This transformation aligns Blender and AC3D coordinate systems:
|
||||
BLEND_TO_AC3D_MATRIX = Mathutils.Matrix([1,0,0,0], [0,0,-1,0], [0,1,0,0], [0,0,0,1])
|
||||
|
||||
def Round_s(f):
|
||||
"Round to default precision and turn value to a string"
|
||||
r = round(f,6) # precision set to 10e-06
|
||||
if r == int(r):
|
||||
return str(int(r))
|
||||
else:
|
||||
return str(r)
|
||||
|
||||
def transform_verts(verts, m):
|
||||
vecs = []
|
||||
for v in verts:
|
||||
x, y, z = v.co
|
||||
vec = Mathutils.Vector([x, y, z, 1])
|
||||
vecs.append(vec*m)
|
||||
return vecs
|
||||
|
||||
def get_loose_edges(mesh):
|
||||
loose = LOOSE
|
||||
return [e for e in mesh.edges if e.flag & loose]
|
||||
|
||||
# ---
|
||||
|
||||
# meshes with more than one texture assigned
|
||||
# are split and saved as these foomeshes
|
||||
class FooMesh:
|
||||
|
||||
class FooVert:
|
||||
def __init__(self, v):
|
||||
self.v = v
|
||||
self.index = 0
|
||||
|
||||
class FooFace:
|
||||
def __init__(self, foomesh, f):
|
||||
self.f = f
|
||||
foov = foomesh.FooVert
|
||||
self.v = [foov(f.v[0]), foov(f.v[1])]
|
||||
len_fv = len(f.v)
|
||||
if len_fv > 2 and f.v[2]:
|
||||
self.v.append(foov(f.v[2]))
|
||||
if len_fv > 3 and f.v[3]: self.v.append(foov(f.v[3]))
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr == 'v': return self.v
|
||||
return getattr(self.f, attr)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.f)
|
||||
|
||||
def __init__(self, tex, faces, mesh):
|
||||
self.name = mesh.name
|
||||
self.mesh = mesh
|
||||
self.looseEdges = []
|
||||
self.faceUV = mesh.faceUV
|
||||
self.degr = mesh.degr
|
||||
vidxs = [0]*len(mesh.verts)
|
||||
foofaces = []
|
||||
for f in faces:
|
||||
foofaces.append(self.FooFace(self, f))
|
||||
for v in f.v:
|
||||
if v: vidxs[v.index] = 1
|
||||
i = 0
|
||||
fooverts = []
|
||||
for v in mesh.verts:
|
||||
if vidxs[v.index]:
|
||||
fooverts.append(v)
|
||||
vidxs[v.index] = i
|
||||
i += 1
|
||||
for f in foofaces:
|
||||
for v in f.v:
|
||||
if v: v.index = vidxs[v.v.index]
|
||||
self.faces = foofaces
|
||||
self.verts = fooverts
|
||||
|
||||
|
||||
class AC3DExport: # the ac3d exporter part
|
||||
|
||||
def __init__(self, scene_objects, file):
|
||||
|
||||
global ARG, SKIP_DATA, ADD_DEFAULT_MAT, DEFAULT_MAT
|
||||
|
||||
header = 'AC3Db'
|
||||
self.file = file
|
||||
self.buf = ''
|
||||
self.mbuf = []
|
||||
self.mlist = []
|
||||
world_kids = 0
|
||||
parents_list = self.parents_list = []
|
||||
kids_dict = self.kids_dict = {}
|
||||
objs = []
|
||||
exp_objs = self.exp_objs = []
|
||||
tree = {}
|
||||
|
||||
file.write(header+'\n')
|
||||
|
||||
objs = \
|
||||
[o for o in scene_objects if o.type in ['Mesh', 'Empty']]
|
||||
|
||||
# create a tree from parents to children objects
|
||||
|
||||
for obj in objs[:]:
|
||||
parent = obj.parent
|
||||
lineage = [obj]
|
||||
|
||||
while parent:
|
||||
parents_list.append(parent.name)
|
||||
obj = parent
|
||||
parent = parent.getParent()
|
||||
lineage.insert(0, obj)
|
||||
|
||||
d = tree
|
||||
for i in xrange(len(lineage)):
|
||||
lname = lineage[i].getType()[:2] + lineage[i].name
|
||||
if lname not in d.keys():
|
||||
d[lname] = {}
|
||||
d = d[lname]
|
||||
|
||||
# traverse the tree to get an ordered list of names of objects to export
|
||||
self.traverse_dict(tree)
|
||||
|
||||
world_kids = len(tree.keys())
|
||||
|
||||
# get list of objects to export, start writing the .ac file
|
||||
|
||||
objlist = [Object.Get(name) for name in exp_objs]
|
||||
|
||||
meshlist = [o for o in objlist if o.type == 'Mesh']
|
||||
|
||||
# create a temporary mesh to hold actual (modified) mesh data
|
||||
TMP_mesh = Mesh.New('tmp_for_ac_export')
|
||||
|
||||
# write materials
|
||||
|
||||
self.MATERIALS(meshlist, TMP_mesh)
|
||||
mbuf = self.mbuf
|
||||
if not mbuf or ADD_DEFAULT_MAT:
|
||||
mbuf.insert(0, "%s\n" % DEFAULT_MAT)
|
||||
mbuf = "".join(mbuf)
|
||||
file.write(mbuf)
|
||||
|
||||
file.write('OBJECT world\nkids %s\n' % world_kids)
|
||||
|
||||
# write the objects
|
||||
|
||||
for obj in objlist:
|
||||
self.obj = obj
|
||||
|
||||
objtype = obj.type
|
||||
objname = obj.name
|
||||
kidsnum = kids_dict[objname]
|
||||
|
||||
# A parent plus its children are exported as a group.
|
||||
# If the parent is a mesh, its rot and loc are exported as the
|
||||
# group rot and loc and the mesh (w/o rot and loc) is added to the group.
|
||||
if kidsnum:
|
||||
self.OBJECT('group')
|
||||
self.name(objname)
|
||||
if objtype == 'Mesh':
|
||||
kidsnum += 1
|
||||
if not GLOBAL_COORDS:
|
||||
localmatrix = obj.getMatrix('localspace')
|
||||
if not obj.getParent():
|
||||
localmatrix *= BLEND_TO_AC3D_MATRIX
|
||||
self.rot(localmatrix.rotationPart())
|
||||
self.loc(localmatrix.translationPart())
|
||||
self.kids(kidsnum)
|
||||
|
||||
if objtype == 'Mesh':
|
||||
mesh = TMP_mesh # temporary mesh to hold actual (modified) mesh data
|
||||
mesh.getFromObject(objname)
|
||||
self.mesh = mesh
|
||||
if mesh.faceUV:
|
||||
meshes = self.split_mesh(mesh)
|
||||
else:
|
||||
meshes = [mesh]
|
||||
if len(meshes) > 1:
|
||||
if NO_SPLIT or self.dont_split(objname):
|
||||
self.export_mesh(mesh, ob)
|
||||
REPORT_DATA['nosplit'].append(objname)
|
||||
else:
|
||||
self.OBJECT('group')
|
||||
self.name(objname)
|
||||
self.kids(len(meshes))
|
||||
counter = 0
|
||||
for me in meshes:
|
||||
self.export_mesh(me, obj,
|
||||
name = '%s_%s' % (obj.name, counter), foomesh = True)
|
||||
self.kids()
|
||||
counter += 1
|
||||
else:
|
||||
self.export_mesh(mesh, obj)
|
||||
self.kids()
|
||||
|
||||
|
||||
def traverse_dict(self, d):
|
||||
kids_dict = self.kids_dict
|
||||
exp_objs = self.exp_objs
|
||||
keys = d.keys()
|
||||
keys.sort() # sort for predictable output
|
||||
keys.reverse()
|
||||
for k in keys:
|
||||
objname = k[2:]
|
||||
klen = len(d[k])
|
||||
kids_dict[objname] = klen
|
||||
if self.dont_export(objname):
|
||||
d.pop(k)
|
||||
parent = Object.Get(objname).getParent()
|
||||
if parent: kids_dict[parent.name] -= 1
|
||||
REPORT_DATA['noexport'].append(objname)
|
||||
continue
|
||||
if klen:
|
||||
self.traverse_dict(d[k])
|
||||
exp_objs.insert(0, objname)
|
||||
else:
|
||||
if k.find('Em', 0) == 0: # Empty w/o children
|
||||
d.pop(k)
|
||||
parent = Object.Get(objname).getParent()
|
||||
if parent: kids_dict[parent.name] -= 1
|
||||
else:
|
||||
exp_objs.insert(0, objname)
|
||||
|
||||
def dont_export(self, name): # if name starts with '!' or '#'
|
||||
length = len(name)
|
||||
if length >= 1:
|
||||
if name[0] in TOKENS_DONT_EXPORT: # '!' or '#' doubled (escaped): export
|
||||
if length > 1 and name[1] == name[0]:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def dont_split(self, name): # if name starts with '=' or '$'
|
||||
length = len(name)
|
||||
if length >= 1:
|
||||
if name[0] in TOKENS_DONT_SPLIT: # '=' or '$' doubled (escaped): split
|
||||
if length > 1 and name[1] == name[0]:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def split_mesh(self, mesh):
|
||||
tex_dict = {0:[]}
|
||||
for f in mesh.faces:
|
||||
if f.image:
|
||||
if not f.image.name in tex_dict: tex_dict[f.image.name] = []
|
||||
tex_dict[f.image.name].append(f)
|
||||
else: tex_dict[0].append(f)
|
||||
keys = tex_dict.keys()
|
||||
len_keys = len(keys)
|
||||
if not tex_dict[0]:
|
||||
len_keys -= 1
|
||||
tex_dict.pop(0)
|
||||
keys.remove(0)
|
||||
elif len_keys > 1:
|
||||
lines = []
|
||||
anyimgkey = [k for k in keys if k != 0][0]
|
||||
for f in tex_dict[0]:
|
||||
if len(f.v) < 3:
|
||||
lines.append(f)
|
||||
if len(tex_dict[0]) == len(lines):
|
||||
for l in lines:
|
||||
tex_dict[anyimgkey].append(l)
|
||||
len_keys -= 1
|
||||
tex_dict.pop(0)
|
||||
if len_keys > 1:
|
||||
foo_meshes = []
|
||||
for k in keys:
|
||||
faces = tex_dict[k]
|
||||
foo_meshes.append(FooMesh(k, faces, mesh))
|
||||
foo_meshes[0].edges = get_loose_edges(mesh)
|
||||
return foo_meshes
|
||||
return [mesh]
|
||||
|
||||
def export_mesh(self, mesh, obj, name = None, foomesh = False):
|
||||
file = self.file
|
||||
self.OBJECT('poly')
|
||||
if not name: name = obj.name
|
||||
self.name(name)
|
||||
if not SKIP_DATA:
|
||||
meshname = obj.getData(name_only = True)
|
||||
self.data(len(meshname), meshname)
|
||||
if mesh.faceUV:
|
||||
texline = self.texture(mesh.faces)
|
||||
if texline: file.write(texline)
|
||||
if AC3D_4:
|
||||
self.crease(mesh.degr)
|
||||
|
||||
# If exporting using local coordinates, children object coordinates should not be
|
||||
# transformed to ac3d's coordinate system, since that will be accounted for in
|
||||
# their topmost parents (the parents w/o parents) transformations.
|
||||
if not GLOBAL_COORDS:
|
||||
# We hold parents in a list, so they also don't get transformed,
|
||||
# because for each parent we create an ac3d group to hold both the
|
||||
# parent and its children.
|
||||
if obj.name not in self.parents_list:
|
||||
localmatrix = obj.getMatrix('localspace')
|
||||
if not obj.getParent():
|
||||
localmatrix *= BLEND_TO_AC3D_MATRIX
|
||||
self.rot(localmatrix.rotationPart())
|
||||
self.loc(localmatrix.translationPart())
|
||||
matrix = None
|
||||
else:
|
||||
matrix = obj.getMatrix() * BLEND_TO_AC3D_MATRIX
|
||||
|
||||
self.numvert(mesh.verts, matrix)
|
||||
self.numsurf(mesh, foomesh)
|
||||
|
||||
def MATERIALS(self, meshlist, me):
|
||||
for meobj in meshlist:
|
||||
me.getFromObject(meobj)
|
||||
mats = me.materials
|
||||
mbuf = []
|
||||
mlist = self.mlist
|
||||
for m in mats:
|
||||
if not m: continue
|
||||
name = m.name
|
||||
if name not in mlist:
|
||||
mlist.append(name)
|
||||
M = Material.Get(name)
|
||||
material = 'MATERIAL "%s"' % name
|
||||
mirCol = "%s %s %s" % (Round_s(M.mirCol[0]), Round_s(M.mirCol[1]),
|
||||
Round_s(M.mirCol[2]))
|
||||
rgb = "rgb %s %s %s" % (Round_s(M.R), Round_s(M.G), Round_s(M.B))
|
||||
ambval = Round_s(M.amb)
|
||||
amb = "amb %s %s %s" % (ambval, ambval, ambval)
|
||||
spec = "spec %s %s %s" % (Round_s(M.specCol[0]),
|
||||
Round_s(M.specCol[1]), Round_s(M.specCol[2]))
|
||||
if AC3D_4:
|
||||
emit = Round_s(M.emit)
|
||||
emis = "emis %s %s %s" % (emit, emit, emit)
|
||||
shival = int(M.spec * 64)
|
||||
else:
|
||||
emis = "emis 0 0 0"
|
||||
shival = 72
|
||||
shi = "shi %s" % shival
|
||||
trans = "trans %s" % (Round_s(1 - M.alpha))
|
||||
if MIRCOL_AS_AMB:
|
||||
amb = "amb %s" % mirCol
|
||||
if MIRCOL_AS_EMIS:
|
||||
emis = "emis %s" % mirCol
|
||||
mbuf.append("%s %s %s %s %s %s %s\n" \
|
||||
% (material, rgb, amb, emis, spec, shi, trans))
|
||||
self.mlist = mlist
|
||||
self.mbuf.append("".join(mbuf))
|
||||
|
||||
def OBJECT(self, type):
|
||||
self.file.write('OBJECT %s\n' % type)
|
||||
|
||||
def name(self, name):
|
||||
if name[0] in TOKENS_DONT_EXPORT or name[0] in TOKENS_DONT_SPLIT:
|
||||
if len(name) > 1: name = name[1:]
|
||||
self.file.write('name "%s"\n' % name)
|
||||
|
||||
def kids(self, num = 0):
|
||||
self.file.write('kids %s\n' % num)
|
||||
|
||||
def data(self, num, str):
|
||||
self.file.write('data %s\n%s\n' % (num, str))
|
||||
|
||||
def texture(self, faces):
|
||||
tex = ""
|
||||
for f in faces:
|
||||
if f.image:
|
||||
tex = f.image.name
|
||||
break
|
||||
if tex:
|
||||
image = Image.Get(tex)
|
||||
texfname = image.filename
|
||||
if SET_TEX_DIR:
|
||||
texfname = bsys.basename(texfname)
|
||||
if TEX_DIR:
|
||||
texfname = bsys.join(TEX_DIR, texfname)
|
||||
buf = 'texture "%s"\n' % texfname
|
||||
xrep = image.xrep
|
||||
yrep = image.yrep
|
||||
buf += 'texrep %s %s\n' % (xrep, yrep)
|
||||
self.file.write(buf)
|
||||
|
||||
def rot(self, matrix):
|
||||
rot = ''
|
||||
not_I = 0 # not identity
|
||||
matstr = []
|
||||
for i in [0, 1, 2]:
|
||||
r = map(Round_s, matrix[i])
|
||||
not_I += (r[0] != '0')+(r[1] != '0')+(r[2] != '0')
|
||||
not_I -= (r[i] == '1')
|
||||
for j in [0, 1, 2]:
|
||||
matstr.append(' %s' % r[j])
|
||||
if not_I: # no need to write identity
|
||||
self.file.write('rot%s\n' % "".join(matstr))
|
||||
|
||||
def loc(self, loc):
|
||||
loc = map(Round_s, loc)
|
||||
if loc != ['0', '0', '0']: # no need to write default
|
||||
self.file.write('loc %s %s %s\n' % (loc[0], loc[1], loc[2]))
|
||||
|
||||
def crease(self, crease):
|
||||
self.file.write('crease %f\n' % crease)
|
||||
|
||||
def numvert(self, verts, matrix):
|
||||
file = self.file
|
||||
nvstr = []
|
||||
nvstr.append("numvert %s\n" % len(verts))
|
||||
|
||||
if matrix:
|
||||
verts = transform_verts(verts, matrix)
|
||||
for v in verts:
|
||||
v = map (Round_s, v)
|
||||
nvstr.append("%s %s %s\n" % (v[0], v[1], v[2]))
|
||||
else:
|
||||
for v in verts:
|
||||
v = map(Round_s, v.co)
|
||||
nvstr.append("%s %s %s\n" % (v[0], v[1], v[2]))
|
||||
|
||||
file.write("".join(nvstr))
|
||||
|
||||
def numsurf(self, mesh, foomesh = False):
|
||||
|
||||
global MATIDX_ERROR
|
||||
|
||||
# local vars are faster and so better in tight loops
|
||||
lc_ADD_DEFAULT_MAT = ADD_DEFAULT_MAT
|
||||
lc_MATIDX_ERROR = MATIDX_ERROR
|
||||
lc_PER_FACE_1_OR_2_SIDED = PER_FACE_1_OR_2_SIDED
|
||||
lc_FACE_TWOSIDED = FACE_TWOSIDED
|
||||
lc_MESH_TWOSIDED = MESH_TWOSIDED
|
||||
|
||||
faces = mesh.faces
|
||||
hasFaceUV = mesh.faceUV
|
||||
if foomesh:
|
||||
looseEdges = mesh.looseEdges
|
||||
else:
|
||||
looseEdges = get_loose_edges(mesh)
|
||||
|
||||
file = self.file
|
||||
|
||||
file.write("numsurf %s\n" % (len(faces) + len(looseEdges)))
|
||||
|
||||
if not foomesh: verts = list(self.mesh.verts)
|
||||
|
||||
materials = self.mesh.materials
|
||||
mlist = self.mlist
|
||||
matidx_error_reported = False
|
||||
objmats = []
|
||||
for omat in materials:
|
||||
if omat: objmats.append(omat.name)
|
||||
else: objmats.append(None)
|
||||
for f in faces:
|
||||
if not objmats:
|
||||
m_idx = 0
|
||||
elif objmats[f.mat] in mlist:
|
||||
m_idx = mlist.index(objmats[f.mat])
|
||||
else:
|
||||
if not lc_MATIDX_ERROR:
|
||||
rdat = REPORT_DATA['warns']
|
||||
rdat.append("Object %s" % self.obj.name)
|
||||
rdat.append("has at least one material *index* assigned but not")
|
||||
rdat.append("defined (not linked to an existing material).")
|
||||
rdat.append("Result: some faces may be exported with a wrong color.")
|
||||
rdat.append("You can assign materials in the Edit Buttons window (F9).")
|
||||
elif not matidx_error_reported:
|
||||
midxmsg = "- Same for object %s." % self.obj.name
|
||||
REPORT_DATA['warns'].append(midxmsg)
|
||||
lc_MATIDX_ERROR += 1
|
||||
matidx_error_reported = True
|
||||
m_idx = 0
|
||||
if lc_ADD_DEFAULT_MAT: m_idx -= 1
|
||||
refs = len(f)
|
||||
flaglow = 0 # polygon
|
||||
if lc_PER_FACE_1_OR_2_SIDED and hasFaceUV: # per face attribute
|
||||
two_side = f.mode & lc_FACE_TWOSIDED
|
||||
else: # global, for the whole mesh
|
||||
two_side = self.mesh.mode & lc_MESH_TWOSIDED
|
||||
two_side = (two_side > 0) << 1
|
||||
flaghigh = f.smooth | two_side
|
||||
surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow)
|
||||
if lc_ADD_DEFAULT_MAT and objmats: m_idx += 1
|
||||
matstr = "mat %s\n" % m_idx
|
||||
refstr = "refs %s\n" % refs
|
||||
u, v, vi = 0, 0, 0
|
||||
fvstr = []
|
||||
if foomesh:
|
||||
for vert in f.v:
|
||||
fvstr.append(str(vert.index))
|
||||
if hasFaceUV:
|
||||
u = f.uv[vi][0]
|
||||
v = f.uv[vi][1]
|
||||
vi += 1
|
||||
fvstr.append(" %s %s\n" % (u, v))
|
||||
else:
|
||||
for vert in f.v:
|
||||
fvstr.append(str(verts.index(vert)))
|
||||
if hasFaceUV:
|
||||
u = f.uv[vi][0]
|
||||
v = f.uv[vi][1]
|
||||
vi += 1
|
||||
fvstr.append(" %s %s\n" % (u, v))
|
||||
|
||||
fvstr = "".join(fvstr)
|
||||
|
||||
file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr))
|
||||
|
||||
# material for loose edges
|
||||
edges_mat = 0 # default to first material
|
||||
for omat in objmats: # but look for a material from this mesh
|
||||
if omat in mlist:
|
||||
edges_mat = mlist.index(omat)
|
||||
if lc_ADD_DEFAULT_MAT: edges_mat += 1
|
||||
break
|
||||
|
||||
for e in looseEdges:
|
||||
fvstr = []
|
||||
#flaglow = 2 # 1 = closed line, 2 = line
|
||||
#flaghigh = 0
|
||||
#surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow)
|
||||
surfstr = "SURF 0x02\n"
|
||||
|
||||
fvstr.append("%d 0 0\n" % verts.index(e.v1))
|
||||
fvstr.append("%d 0 0\n" % verts.index(e.v2))
|
||||
fvstr = "".join(fvstr)
|
||||
|
||||
matstr = "mat %d\n" % edges_mat # for now, use first material
|
||||
refstr = "refs 2\n" # 2 verts
|
||||
|
||||
file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr))
|
||||
|
||||
MATIDX_ERROR = lc_MATIDX_ERROR
|
||||
|
||||
# End of Class AC3DExport
|
||||
|
||||
from Blender.Window import FileSelector
|
||||
|
||||
def report_data():
|
||||
global VERBOSE
|
||||
|
||||
if not VERBOSE: return
|
||||
|
||||
d = REPORT_DATA
|
||||
msgs = {
|
||||
'0main': '%s\nExporting meshes to AC3D format' % str(19*'-'),
|
||||
'1warns': 'Warnings',
|
||||
'2errors': 'Errors',
|
||||
'3nosplit': 'Not split (because name starts with "=" or "$")',
|
||||
'4noexport': 'Not exported (because name starts with "!" or "#")'
|
||||
}
|
||||
if NO_SPLIT:
|
||||
l = msgs['3nosplit']
|
||||
l = "%s (because OPTION NO_SPLIT is set)" % l.split('(')[0]
|
||||
msgs['3nosplit'] = l
|
||||
keys = msgs.keys()
|
||||
keys.sort()
|
||||
for k in keys:
|
||||
msgk = msgs[k]
|
||||
msg = '\n'.join(d[k[1:]])
|
||||
if msg:
|
||||
print '\n-%s:' % msgk
|
||||
print msg
|
||||
|
||||
# File Selector callback:
|
||||
def fs_callback(filename):
|
||||
global EXPORT_DIR, OBJS, CONFIRM_OVERWRITE, VERBOSE
|
||||
|
||||
if not filename.endswith('.ac'): filename = '%s.ac' % filename
|
||||
|
||||
if bsys.exists(filename) and CONFIRM_OVERWRITE:
|
||||
if Blender.Draw.PupMenu('OVERWRITE?%t|File exists') != 1:
|
||||
return
|
||||
|
||||
Blender.Window.WaitCursor(1)
|
||||
starttime = bsys.time()
|
||||
|
||||
export_dir = bsys.dirname(filename)
|
||||
if export_dir != EXPORT_DIR:
|
||||
EXPORT_DIR = export_dir
|
||||
update_RegistryInfo()
|
||||
|
||||
try:
|
||||
file = open(filename, 'w')
|
||||
except IOError, (errno, strerror):
|
||||
error = "IOError #%s: %s" % (errno, strerror)
|
||||
REPORT_DATA['errors'].append("Saving failed - %s." % error)
|
||||
error_msg = "Couldn't save file!%%t|%s" % error
|
||||
Blender.Draw.PupMenu(error_msg)
|
||||
return
|
||||
|
||||
try:
|
||||
test = AC3DExport(OBJS, file)
|
||||
except:
|
||||
file.close()
|
||||
raise
|
||||
else:
|
||||
file.close()
|
||||
endtime = bsys.time() - starttime
|
||||
REPORT_DATA['main'].append("Done. Saved to: %s" % filename)
|
||||
REPORT_DATA['main'].append("Data exported in %.3f seconds." % endtime)
|
||||
|
||||
if VERBOSE: report_data()
|
||||
Blender.Window.WaitCursor(0)
|
||||
|
||||
|
||||
# -- End of definitions
|
||||
|
||||
scn = Blender.Scene.GetCurrent()
|
||||
|
||||
if ONLY_SELECTED:
|
||||
OBJS = list(scn.objects.context)
|
||||
else:
|
||||
OBJS = list(scn.objects)
|
||||
|
||||
if not OBJS:
|
||||
Blender.Draw.PupMenu('ERROR: no objects selected')
|
||||
else:
|
||||
fname = bsys.makename(ext=".ac")
|
||||
if EXPORT_DIR:
|
||||
fname = bsys.join(EXPORT_DIR, bsys.basename(fname))
|
||||
FileSelector(fs_callback, "Export AC3D", fname)
|
||||
783
src_research_readme/blender_2.43_scripts/ac3d_import.py
Normal file
783
src_research_readme/blender_2.43_scripts/ac3d_import.py
Normal file
@@ -0,0 +1,783 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus:
|
||||
Name: 'AC3D (.ac)...'
|
||||
Blender: 243
|
||||
Group: 'Import'
|
||||
Tip: 'Import an AC3D (.ac) file.'
|
||||
"""
|
||||
|
||||
__author__ = "Willian P. Germano"
|
||||
__url__ = ("blender", "blenderartists.org", "AC3D's homepage, http://www.ac3d.org",
|
||||
"PLib 3d gaming lib, http://plib.sf.net")
|
||||
__version__ = "2.48.1 2009-01-11"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script imports AC3D models into Blender.
|
||||
|
||||
AC3D is a simple and affordable commercial 3d modeller also built with OpenGL.
|
||||
The .ac file format is an easy to parse text format well supported,
|
||||
for example, by the PLib 3d gaming library.
|
||||
|
||||
Supported:<br>
|
||||
UV-textured meshes with hierarchy (grouping) information.
|
||||
|
||||
Missing:<br>
|
||||
The url tag is irrelevant for Blender.
|
||||
|
||||
Known issues:<br>
|
||||
- Some objects may be imported with wrong normals due to wrong information in the model itself. This can be noticed by strange shading, like darker than expected parts in the model. To fix this, select the mesh with wrong normals, enter edit mode and tell Blender to recalculate the normals, either to make them point outside (the usual case) or inside.<br>
|
||||
|
||||
Config Options:<br>
|
||||
- display transp (toggle): if "on", objects that have materials with alpha < 1.0 are shown with translucency (transparency) in the 3D View.<br>
|
||||
- subdiv (toggle): if "on", ac3d objects meant to be subdivided receive a SUBSURF modifier in Blender.<br>
|
||||
- emis as mircol: store the emissive rgb color from AC3D as mirror color in Blender -- this is a hack to preserve the values and be able to export them using the equivalent option in the exporter.<br>
|
||||
- textures dir (string): if non blank, when imported texture paths are
|
||||
wrong in the .ac file, Blender will also look for them at this dir.
|
||||
|
||||
Notes:<br>
|
||||
- When looking for assigned textures, Blender tries in order: the actual
|
||||
paths from the .ac file, the .ac file's dir and the default textures dir path
|
||||
users can configure (see config options above).
|
||||
"""
|
||||
|
||||
# $Id: ac3d_import.py 18451 2009-01-11 16:17:41Z ianwill $
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# AC3DImport version 2.43.1 Feb 21, 2007
|
||||
# Program versions: Blender 2.43 and AC3Db files (means version 0xb)
|
||||
# changed: better triangulation of ngons, more fixes to support bad .ac files,
|
||||
# option to display transp mats in 3d view, support "subdiv" tag (via SUBSURF modifier)
|
||||
# --------------------------------------------------------------------------
|
||||
# Thanks: Melchior Franz for extensive bug testing and reporting, making this
|
||||
# version cope much better with old or bad .ac files, among other improvements;
|
||||
# Stewart Andreason for reporting a serious crash; Francesco Brisa for the
|
||||
# emis as mircol functionality (w/ patch).
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2004-2009: Willian P. Germano, wgermano _at_ ig.com.br
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
from math import radians
|
||||
|
||||
import Blender
|
||||
from Blender import Scene, Object, Mesh, Lamp, Registry, sys as bsys, Window, Image, Material, Modifier
|
||||
from Blender.sys import dirsep
|
||||
from Blender.Mathutils import Vector, Matrix, Euler
|
||||
from Blender.Geometry import PolyFill
|
||||
|
||||
# Default folder for AC3D textures, to override wrong paths, change to your
|
||||
# liking or leave as "":
|
||||
TEXTURES_DIR = ""
|
||||
|
||||
DISPLAY_TRANSP = True
|
||||
|
||||
SUBDIV = True
|
||||
|
||||
EMIS_AS_MIRCOL = False
|
||||
|
||||
|
||||
tooltips = {
|
||||
'DISPLAY_TRANSP': 'Turn transparency on in the 3d View for objects using materials with alpha < 1.0.',
|
||||
'SUBDIV': 'Apply a SUBSURF modifier to objects meant to appear subdivided.',
|
||||
'TEXTURES_DIR': 'Additional folder to look for missing textures.',
|
||||
'EMIS_AS_MIRCOL': 'Store emis color as mirror color in Blender.'
|
||||
}
|
||||
|
||||
def update_registry():
|
||||
global TEXTURES_DIR, DISPLAY_TRANSP, EMIS_AS_MIRCOL
|
||||
rd = dict([('tooltips', tooltips), ('TEXTURES_DIR', TEXTURES_DIR), ('DISPLAY_TRANSP', DISPLAY_TRANSP), ('SUBDIV', SUBDIV), ('EMIS_AS_MIRCOL', EMIS_AS_MIRCOL)])
|
||||
Registry.SetKey('ac3d_import', rd, True)
|
||||
|
||||
rd = Registry.GetKey('ac3d_import', True)
|
||||
|
||||
if rd:
|
||||
if 'GROUP' in rd:
|
||||
update_registry()
|
||||
try:
|
||||
TEXTURES_DIR = rd['TEXTURES_DIR']
|
||||
DISPLAY_TRANSP = rd['DISPLAY_TRANSP']
|
||||
SUBDIV = rd['SUBDIV']
|
||||
EMIS_AS_MIRCOL = rd['EMIS_AS_MIRCOL']
|
||||
except:
|
||||
update_registry()
|
||||
else: update_registry()
|
||||
|
||||
if TEXTURES_DIR:
|
||||
oldtexdir = TEXTURES_DIR
|
||||
if dirsep == '/': TEXTURES_DIR = TEXTURES_DIR.replace('\\', '/')
|
||||
if TEXTURES_DIR[-1] != dirsep: TEXTURES_DIR = "%s%s" % (TEXTURES_DIR, dirsep)
|
||||
if oldtexdir != TEXTURES_DIR: update_registry()
|
||||
|
||||
|
||||
VERBOSE = True
|
||||
rd = Registry.GetKey('General', True)
|
||||
if rd:
|
||||
if rd.has_key('verbose'):
|
||||
VERBOSE = rd['verbose']
|
||||
|
||||
|
||||
errmsg = ""
|
||||
|
||||
# Matrix to align ac3d's coordinate system with Blender's one,
|
||||
# it's a -90 degrees rotation around the x axis:
|
||||
AC_TO_BLEND_MATRIX = Matrix([1, 0, 0], [0, 0, 1], [0, -1, 0])
|
||||
|
||||
AC_WORLD = 0
|
||||
AC_GROUP = 1
|
||||
AC_POLY = 2
|
||||
AC_LIGHT = 3
|
||||
AC_OB_TYPES = {
|
||||
'world': AC_WORLD,
|
||||
'group': AC_GROUP,
|
||||
'poly': AC_POLY,
|
||||
'light': AC_LIGHT
|
||||
}
|
||||
|
||||
AC_OB_BAD_TYPES_LIST = [] # to hold references to unknown (wrong) ob types
|
||||
|
||||
def inform(msg):
|
||||
global VERBOSE
|
||||
if VERBOSE: print msg
|
||||
|
||||
def euler_in_radians(eul):
|
||||
"Used while there's a bug in the BPY API"
|
||||
eul.x = radians(eul.x)
|
||||
eul.y = radians(eul.y)
|
||||
eul.z = radians(eul.z)
|
||||
return eul
|
||||
|
||||
class Obj:
|
||||
|
||||
def __init__(self, type):
|
||||
self.type = type
|
||||
self.dad = None
|
||||
self.name = ''
|
||||
self.data = ''
|
||||
self.tex = ''
|
||||
self.texrep = [1,1]
|
||||
self.texoff = None
|
||||
self.loc = []
|
||||
self.rot = []
|
||||
self.size = []
|
||||
self.crease = 30
|
||||
self.subdiv = 0
|
||||
self.vlist = []
|
||||
self.flist_cfg = []
|
||||
self.flist_v = []
|
||||
self.flist_uv = []
|
||||
self.elist = []
|
||||
self.matlist = []
|
||||
self.kids = 0
|
||||
|
||||
self.bl_obj = None # the actual Blender object created from this data
|
||||
|
||||
class AC3DImport:
|
||||
|
||||
def __init__(self, filename):
|
||||
|
||||
global errmsg
|
||||
|
||||
self.scene = Scene.GetCurrent()
|
||||
|
||||
self.i = 0
|
||||
errmsg = ''
|
||||
self.importdir = bsys.dirname(filename)
|
||||
try:
|
||||
file = open(filename, 'r')
|
||||
except IOError, (errno, strerror):
|
||||
errmsg = "IOError #%s: %s" % (errno, strerror)
|
||||
Blender.Draw.PupMenu('ERROR: %s' % errmsg)
|
||||
inform(errmsg)
|
||||
return None
|
||||
header = file.read(5)
|
||||
header, version = header[:4], header[-1]
|
||||
if header != 'AC3D':
|
||||
file.close()
|
||||
errmsg = 'AC3D header not found (invalid file)'
|
||||
Blender.Draw.PupMenu('ERROR: %s' % errmsg)
|
||||
inform(errmsg)
|
||||
return None
|
||||
elif version != 'b':
|
||||
inform('AC3D file version 0x%s.' % version)
|
||||
inform('This importer is for version 0xb, so it may fail.')
|
||||
|
||||
self.token = {'OBJECT': self.parse_obj,
|
||||
'numvert': self.parse_vert,
|
||||
'numsurf': self.parse_surf,
|
||||
'name': self.parse_name,
|
||||
'data': self.parse_data,
|
||||
'kids': self.parse_kids,
|
||||
'loc': self.parse_loc,
|
||||
'rot': self.parse_rot,
|
||||
'MATERIAL': self.parse_mat,
|
||||
'texture': self.parse_tex,
|
||||
'texrep': self.parse_texrep,
|
||||
'texoff': self.parse_texoff,
|
||||
'subdiv': self.parse_subdiv,
|
||||
'crease': self.parse_crease}
|
||||
|
||||
self.objlist = []
|
||||
self.mlist = []
|
||||
self.kidsnumlist = []
|
||||
self.dad = None
|
||||
|
||||
self.lines = file.readlines()
|
||||
self.lines.append('')
|
||||
self.parse_file()
|
||||
file.close()
|
||||
|
||||
self.testAC3DImport()
|
||||
|
||||
def parse_obj(self, value):
|
||||
kidsnumlist = self.kidsnumlist
|
||||
if kidsnumlist:
|
||||
while not kidsnumlist[-1]:
|
||||
kidsnumlist.pop()
|
||||
if kidsnumlist:
|
||||
self.dad = self.dad.dad
|
||||
else:
|
||||
inform('Ignoring unexpected data at end of file.')
|
||||
return -1 # bad file with more objects than reported
|
||||
kidsnumlist[-1] -= 1
|
||||
if value in AC_OB_TYPES:
|
||||
new = Obj(AC_OB_TYPES[value])
|
||||
else:
|
||||
if value not in AC_OB_BAD_TYPES_LIST:
|
||||
AC_OB_BAD_TYPES_LIST.append(value)
|
||||
inform('Unexpected object type keyword: "%s". Assuming it is of type: "poly".' % value)
|
||||
new = Obj(AC_OB_TYPES['poly'])
|
||||
new.dad = self.dad
|
||||
new.name = value
|
||||
self.objlist.append(new)
|
||||
|
||||
def parse_kids(self, value):
|
||||
kids = int(value)
|
||||
if kids:
|
||||
self.kidsnumlist.append(kids)
|
||||
self.dad = self.objlist[-1]
|
||||
self.objlist[-1].kids = kids
|
||||
|
||||
def parse_name(self, value):
|
||||
name = value.split('"')[1]
|
||||
self.objlist[-1].name = name
|
||||
|
||||
def parse_data(self, value):
|
||||
data = self.lines[self.i].strip()
|
||||
self.objlist[-1].data = data
|
||||
|
||||
def parse_tex(self, value):
|
||||
line = self.lines[self.i - 1] # parse again to properly get paths with spaces
|
||||
texture = line.split('"')[1]
|
||||
self.objlist[-1].tex = texture
|
||||
|
||||
def parse_texrep(self, trash):
|
||||
trep = self.lines[self.i - 1]
|
||||
trep = trep.split()
|
||||
trep = [float(trep[1]), float(trep[2])]
|
||||
self.objlist[-1].texrep = trep
|
||||
self.objlist[-1].texoff = [0, 0]
|
||||
|
||||
def parse_texoff(self, trash):
|
||||
toff = self.lines[self.i - 1]
|
||||
toff = toff.split()
|
||||
toff = [float(toff[1]), float(toff[2])]
|
||||
self.objlist[-1].texoff = toff
|
||||
|
||||
def parse_mat(self, value):
|
||||
i = self.i - 1
|
||||
lines = self.lines
|
||||
line = lines[i].split()
|
||||
mat_name = ''
|
||||
mat_col = mat_amb = mat_emit = mat_spec_col = mat_mir_col = [0,0,0]
|
||||
mat_alpha = 1
|
||||
mat_spec = 1.0
|
||||
|
||||
while line[0] == 'MATERIAL':
|
||||
mat_name = line[1].split('"')[1]
|
||||
mat_col = map(float,[line[3],line[4],line[5]])
|
||||
v = map(float,[line[7],line[8],line[9]])
|
||||
mat_amb = (v[0]+v[1]+v[2]) / 3.0
|
||||
v = map(float,[line[11],line[12],line[13]])
|
||||
mat_emit = (v[0]+v[1]+v[2]) / 3.0
|
||||
if EMIS_AS_MIRCOL:
|
||||
mat_emit = 0
|
||||
mat_mir_col = map(float,[line[11],line[12],line[13]])
|
||||
|
||||
mat_spec_col = map(float,[line[15],line[16],line[17]])
|
||||
mat_spec = float(line[19]) / 64.0
|
||||
mat_alpha = float(line[-1])
|
||||
mat_alpha = 1 - mat_alpha
|
||||
self.mlist.append([mat_name, mat_col, mat_amb, mat_emit, mat_spec_col, mat_spec, mat_mir_col, mat_alpha])
|
||||
i += 1
|
||||
line = lines[i].split()
|
||||
|
||||
self.i = i
|
||||
|
||||
def parse_rot(self, trash):
|
||||
i = self.i - 1
|
||||
ob = self.objlist[-1]
|
||||
rot = self.lines[i].split(' ', 1)[1]
|
||||
rot = map(float, rot.split())
|
||||
matrix = Matrix(rot[:3], rot[3:6], rot[6:])
|
||||
ob.rot = matrix
|
||||
size = matrix.scalePart() # vector
|
||||
ob.size = size
|
||||
|
||||
def parse_loc(self, trash):
|
||||
i = self.i - 1
|
||||
loc = self.lines[i].split(' ', 1)[1]
|
||||
loc = map(float, loc.split())
|
||||
self.objlist[-1].loc = Vector(loc)
|
||||
|
||||
def parse_crease(self, value):
|
||||
# AC3D: range is [0.0, 180.0]; Blender: [1, 80]
|
||||
value = float(value)
|
||||
self.objlist[-1].crease = int(value)
|
||||
|
||||
def parse_subdiv(self, value):
|
||||
self.objlist[-1].subdiv = int(value)
|
||||
|
||||
def parse_vert(self, value):
|
||||
i = self.i
|
||||
lines = self.lines
|
||||
obj = self.objlist[-1]
|
||||
vlist = obj.vlist
|
||||
n = int(value)
|
||||
|
||||
while n:
|
||||
line = lines[i].split()
|
||||
line = map(float, line)
|
||||
vlist.append(line)
|
||||
n -= 1
|
||||
i += 1
|
||||
|
||||
if vlist: # prepend a vertex at 1st position to deal with vindex 0 issues
|
||||
vlist.insert(0, line)
|
||||
|
||||
self.i = i
|
||||
|
||||
def parse_surf(self, value):
|
||||
i = self.i
|
||||
is_smooth = 0
|
||||
double_sided = 0
|
||||
lines = self.lines
|
||||
obj = self.objlist[-1]
|
||||
vlist = obj.vlist
|
||||
matlist = obj.matlist
|
||||
numsurf = int(value)
|
||||
NUMSURF = numsurf
|
||||
|
||||
badface_notpoly = badface_multirefs = 0
|
||||
|
||||
while numsurf:
|
||||
flags = lines[i].split()[1][2:]
|
||||
if len(flags) > 1:
|
||||
flaghigh = int(flags[0])
|
||||
flaglow = int(flags[1])
|
||||
else:
|
||||
flaghigh = 0
|
||||
flaglow = int(flags[0])
|
||||
|
||||
is_smooth = flaghigh & 1
|
||||
twoside = flaghigh & 2
|
||||
nextline = lines[i+1].split()
|
||||
if nextline[0] != 'mat': # the "mat" line may be missing (found in one buggy .ac file)
|
||||
matid = 0
|
||||
if not matid in matlist: matlist.append(matid)
|
||||
i += 2
|
||||
else:
|
||||
matid = int(nextline[1])
|
||||
if not matid in matlist: matlist.append(matid)
|
||||
nextline = lines[i+2].split()
|
||||
i += 3
|
||||
refs = int(nextline[1])
|
||||
face = []
|
||||
faces = []
|
||||
edges = []
|
||||
fuv = []
|
||||
fuvs = []
|
||||
rfs = refs
|
||||
|
||||
while rfs:
|
||||
line = lines[i].split()
|
||||
v = int(line[0]) + 1 # + 1 to avoid vindex == 0
|
||||
uv = [float(line[1]), float(line[2])]
|
||||
face.append(v)
|
||||
fuv.append(Vector(uv))
|
||||
rfs -= 1
|
||||
i += 1
|
||||
|
||||
if flaglow: # it's a line or closed line, not a polygon
|
||||
while len(face) >= 2:
|
||||
cut = face[:2]
|
||||
edges.append(cut)
|
||||
face = face[1:]
|
||||
|
||||
if flaglow == 1 and edges: # closed line
|
||||
face = [edges[-1][-1], edges[0][0]]
|
||||
edges.append(face)
|
||||
|
||||
else: # polygon
|
||||
|
||||
# check for bad face, that references same vertex more than once
|
||||
lenface = len(face)
|
||||
if lenface < 3:
|
||||
# less than 3 vertices, not a face
|
||||
badface_notpoly += 1
|
||||
elif sum(map(face.count, face)) != lenface:
|
||||
# multiple references to the same vertex
|
||||
badface_multirefs += 1
|
||||
else: # ok, seems fine
|
||||
if len(face) > 4: # ngon, triangulate it
|
||||
polyline = []
|
||||
for vi in face:
|
||||
polyline.append(Vector(vlist[vi]))
|
||||
tris = PolyFill([polyline])
|
||||
for t in tris:
|
||||
tri = [face[t[0]], face[t[1]], face[t[2]]]
|
||||
triuvs = [fuv[t[0]], fuv[t[1]], fuv[t[2]]]
|
||||
faces.append(tri)
|
||||
fuvs.append(triuvs)
|
||||
else: # tri or quad
|
||||
faces.append(face)
|
||||
fuvs.append(fuv)
|
||||
|
||||
obj.flist_cfg.extend([[matid, is_smooth, twoside]] * len(faces))
|
||||
obj.flist_v.extend(faces)
|
||||
obj.flist_uv.extend(fuvs)
|
||||
obj.elist.extend(edges) # loose edges
|
||||
|
||||
numsurf -= 1
|
||||
|
||||
if badface_notpoly or badface_multirefs:
|
||||
inform('Object "%s" - ignoring bad faces:' % obj.name)
|
||||
if badface_notpoly:
|
||||
inform('\t%d face(s) with less than 3 vertices.' % badface_notpoly)
|
||||
if badface_multirefs:
|
||||
inform('\t%d face(s) with multiple references to a same vertex.' % badface_multirefs)
|
||||
|
||||
self.i = i
|
||||
|
||||
def parse_file(self):
|
||||
i = 1
|
||||
lines = self.lines
|
||||
line = lines[i].split()
|
||||
|
||||
while line:
|
||||
kw = ''
|
||||
for k in self.token.keys():
|
||||
if line[0] == k:
|
||||
kw = k
|
||||
break
|
||||
i += 1
|
||||
if kw:
|
||||
self.i = i
|
||||
result = self.token[kw](line[1])
|
||||
if result:
|
||||
break # bad .ac file, stop parsing
|
||||
i = self.i
|
||||
line = lines[i].split()
|
||||
|
||||
# for each group of meshes we try to find one that can be used as
|
||||
# parent of the group in Blender.
|
||||
# If not found, we can use an Empty as parent.
|
||||
def found_parent(self, groupname, olist):
|
||||
l = [o for o in olist if o.type == AC_POLY \
|
||||
and not o.kids and not o.rot and not o.loc]
|
||||
if l:
|
||||
for o in l:
|
||||
if o.name == groupname:
|
||||
return o
|
||||
#return l[0]
|
||||
return None
|
||||
|
||||
def build_hierarchy(self):
|
||||
blmatrix = AC_TO_BLEND_MATRIX
|
||||
|
||||
olist = self.objlist[1:]
|
||||
olist.reverse()
|
||||
|
||||
scene = self.scene
|
||||
|
||||
newlist = []
|
||||
|
||||
for o in olist:
|
||||
kids = o.kids
|
||||
if kids:
|
||||
children = newlist[-kids:]
|
||||
newlist = newlist[:-kids]
|
||||
if o.type == AC_GROUP:
|
||||
parent = self.found_parent(o.name, children)
|
||||
if parent:
|
||||
children.remove(parent)
|
||||
o.bl_obj = parent.bl_obj
|
||||
else: # not found, use an empty
|
||||
empty = scene.objects.new('Empty', o.name)
|
||||
o.bl_obj = empty
|
||||
|
||||
bl_children = [c.bl_obj for c in children if c.bl_obj != None]
|
||||
|
||||
o.bl_obj.makeParent(bl_children, 0, 1)
|
||||
for child in children:
|
||||
blob = child.bl_obj
|
||||
if not blob: continue
|
||||
if child.rot:
|
||||
eul = euler_in_radians(child.rot.toEuler())
|
||||
blob.setEuler(eul)
|
||||
if child.size:
|
||||
blob.size = child.size
|
||||
if not child.loc:
|
||||
child.loc = Vector(0.0, 0.0, 0.0)
|
||||
blob.setLocation(child.loc)
|
||||
|
||||
newlist.append(o)
|
||||
|
||||
for o in newlist: # newlist now only has objs w/o parents
|
||||
blob = o.bl_obj
|
||||
if not blob:
|
||||
continue
|
||||
if o.size:
|
||||
o.bl_obj.size = o.size
|
||||
if not o.rot:
|
||||
blob.setEuler([1.5707963267948966, 0, 0])
|
||||
else:
|
||||
matrix = o.rot * blmatrix
|
||||
eul = euler_in_radians(matrix.toEuler())
|
||||
blob.setEuler(eul)
|
||||
if o.loc:
|
||||
o.loc *= blmatrix
|
||||
else:
|
||||
o.loc = Vector(0.0, 0.0, 0.0)
|
||||
blob.setLocation(o.loc) # forces DAG update, so we do it even for 0, 0, 0
|
||||
|
||||
# XXX important: until we fix the BPy API so it doesn't increase user count
|
||||
# when wrapping a Blender object, this piece of code is needed for proper
|
||||
# object (+ obdata) deletion in Blender:
|
||||
for o in self.objlist:
|
||||
if o.bl_obj:
|
||||
o.bl_obj = None
|
||||
|
||||
def testAC3DImport(self):
|
||||
|
||||
FACE_TWOSIDE = Mesh.FaceModes['TWOSIDE']
|
||||
FACE_TEX = Mesh.FaceModes['TEX']
|
||||
MESH_AUTOSMOOTH = Mesh.Modes['AUTOSMOOTH']
|
||||
|
||||
MAT_MODE_ZTRANSP = Material.Modes['ZTRANSP']
|
||||
MAT_MODE_TRANSPSHADOW = Material.Modes['TRANSPSHADOW']
|
||||
|
||||
scene = self.scene
|
||||
|
||||
bl_images = {} # loaded texture images
|
||||
missing_textures = [] # textures we couldn't find
|
||||
|
||||
objlist = self.objlist[1:] # skip 'world'
|
||||
|
||||
bmat = []
|
||||
has_transp_mats = False
|
||||
for mat in self.mlist:
|
||||
name = mat[0]
|
||||
m = Material.New(name)
|
||||
m.rgbCol = (mat[1][0], mat[1][1], mat[1][2])
|
||||
m.amb = mat[2]
|
||||
m.emit = mat[3]
|
||||
m.specCol = (mat[4][0], mat[4][1], mat[4][2])
|
||||
m.spec = mat[5]
|
||||
m.mirCol = (mat[6][0], mat[6][1], mat[6][2])
|
||||
m.alpha = mat[7]
|
||||
if m.alpha < 1.0:
|
||||
m.mode |= MAT_MODE_ZTRANSP
|
||||
has_transp_mats = True
|
||||
bmat.append(m)
|
||||
|
||||
if has_transp_mats:
|
||||
for mat in bmat:
|
||||
mat.mode |= MAT_MODE_TRANSPSHADOW
|
||||
|
||||
obj_idx = 0 # index of current obj in loop
|
||||
for obj in objlist:
|
||||
if obj.type == AC_GROUP:
|
||||
continue
|
||||
elif obj.type == AC_LIGHT:
|
||||
light = Lamp.New('Lamp')
|
||||
object = scene.objects.new(light, obj.name)
|
||||
#object.select(True)
|
||||
obj.bl_obj = object
|
||||
if obj.data:
|
||||
light.name = obj.data
|
||||
continue
|
||||
|
||||
# type AC_POLY:
|
||||
|
||||
# old .ac files used empty meshes as groups, convert to a real ac group
|
||||
if not obj.vlist and obj.kids:
|
||||
obj.type = AC_GROUP
|
||||
continue
|
||||
|
||||
mesh = Mesh.New()
|
||||
object = scene.objects.new(mesh, obj.name)
|
||||
#object.select(True)
|
||||
obj.bl_obj = object
|
||||
if obj.data: mesh.name = obj.data
|
||||
mesh.degr = obj.crease # will auto clamp to [1, 80]
|
||||
|
||||
if not obj.vlist: # no vertices? nothing more to do
|
||||
continue
|
||||
|
||||
mesh.verts.extend(obj.vlist)
|
||||
|
||||
objmat_indices = []
|
||||
for mat in bmat:
|
||||
if bmat.index(mat) in obj.matlist:
|
||||
objmat_indices.append(bmat.index(mat))
|
||||
mesh.materials += [mat]
|
||||
if DISPLAY_TRANSP and mat.alpha < 1.0:
|
||||
object.transp = True
|
||||
|
||||
for e in obj.elist:
|
||||
mesh.edges.extend(e)
|
||||
|
||||
if obj.flist_v:
|
||||
mesh.faces.extend(obj.flist_v)
|
||||
|
||||
facesnum = len(mesh.faces)
|
||||
|
||||
if facesnum == 0: # shouldn't happen, of course
|
||||
continue
|
||||
|
||||
mesh.faceUV = True
|
||||
|
||||
# checking if the .ac file had duplicate faces (Blender ignores them)
|
||||
if facesnum != len(obj.flist_v):
|
||||
# it has, ugh. Let's clean the uv list:
|
||||
lenfl = len(obj.flist_v)
|
||||
flist = obj.flist_v
|
||||
uvlist = obj.flist_uv
|
||||
cfglist = obj.flist_cfg
|
||||
for f in flist:
|
||||
f.sort()
|
||||
fi = lenfl
|
||||
while fi > 0: # remove data related to duplicates
|
||||
fi -= 1
|
||||
if flist[fi] in flist[:fi]:
|
||||
uvlist.pop(fi)
|
||||
cfglist.pop(fi)
|
||||
|
||||
img = None
|
||||
if obj.tex != '':
|
||||
if obj.tex in bl_images.keys():
|
||||
img = bl_images[obj.tex]
|
||||
elif obj.tex not in missing_textures:
|
||||
texfname = None
|
||||
objtex = obj.tex
|
||||
baseimgname = bsys.basename(objtex)
|
||||
if bsys.exists(objtex) == 1:
|
||||
texfname = objtex
|
||||
elif bsys.exists(bsys.join(self.importdir, objtex)):
|
||||
texfname = bsys.join(self.importdir, objtex)
|
||||
else:
|
||||
if baseimgname.find('\\') > 0:
|
||||
baseimgname = bsys.basename(objtex.replace('\\','/'))
|
||||
objtex = bsys.join(self.importdir, baseimgname)
|
||||
if bsys.exists(objtex) == 1:
|
||||
texfname = objtex
|
||||
else:
|
||||
objtex = bsys.join(TEXTURES_DIR, baseimgname)
|
||||
if bsys.exists(objtex):
|
||||
texfname = objtex
|
||||
if texfname:
|
||||
try:
|
||||
img = Image.Load(texfname)
|
||||
# Commented because it's unnecessary:
|
||||
#img.xrep = int(obj.texrep[0])
|
||||
#img.yrep = int(obj.texrep[1])
|
||||
if img:
|
||||
bl_images[obj.tex] = img
|
||||
except:
|
||||
inform("Couldn't load texture: %s" % baseimgname)
|
||||
else:
|
||||
missing_textures.append(obj.tex)
|
||||
inform("Couldn't find texture: %s" % baseimgname)
|
||||
|
||||
for i in range(facesnum):
|
||||
f = obj.flist_cfg[i]
|
||||
fmat = f[0]
|
||||
is_smooth = f[1]
|
||||
twoside = f[2]
|
||||
bface = mesh.faces[i]
|
||||
bface.smooth = is_smooth
|
||||
if twoside: bface.mode |= FACE_TWOSIDE
|
||||
if img:
|
||||
bface.mode |= FACE_TEX
|
||||
bface.image = img
|
||||
bface.mat = objmat_indices.index(fmat)
|
||||
fuv = obj.flist_uv[i]
|
||||
if obj.texoff:
|
||||
uoff = obj.texoff[0]
|
||||
voff = obj.texoff[1]
|
||||
urep = obj.texrep[0]
|
||||
vrep = obj.texrep[1]
|
||||
for uv in fuv:
|
||||
uv[0] *= urep
|
||||
uv[1] *= vrep
|
||||
uv[0] += uoff
|
||||
uv[1] += voff
|
||||
|
||||
mesh.faces[i].uv = fuv
|
||||
|
||||
# finally, delete the 1st vertex we added to prevent vindices == 0
|
||||
mesh.verts.delete(0)
|
||||
|
||||
mesh.calcNormals()
|
||||
|
||||
mesh.mode = MESH_AUTOSMOOTH
|
||||
|
||||
# subdiv: create SUBSURF modifier in Blender
|
||||
if SUBDIV and obj.subdiv > 0:
|
||||
subdiv = obj.subdiv
|
||||
subdiv_render = subdiv
|
||||
# just to be safe:
|
||||
if subdiv_render > 6: subdiv_render = 6
|
||||
if subdiv > 3: subdiv = 3
|
||||
modif = object.modifiers.append(Modifier.Types.SUBSURF)
|
||||
modif[Modifier.Settings.LEVELS] = subdiv
|
||||
modif[Modifier.Settings.RENDLEVELS] = subdiv_render
|
||||
|
||||
obj_idx += 1
|
||||
|
||||
self.build_hierarchy()
|
||||
scene.update()
|
||||
|
||||
# End of class AC3DImport
|
||||
|
||||
def filesel_callback(filename):
|
||||
|
||||
inform("\nTrying to import AC3D model(s) from:\n%s ..." % filename)
|
||||
Window.WaitCursor(1)
|
||||
starttime = bsys.time()
|
||||
test = AC3DImport(filename)
|
||||
Window.WaitCursor(0)
|
||||
endtime = bsys.time() - starttime
|
||||
inform('Done! Data imported in %.3f seconds.\n' % endtime)
|
||||
|
||||
Window.EditMode(0)
|
||||
|
||||
Window.FileSelector(filesel_callback, "Import AC3D", "*.ac")
|
||||
13
src_research_readme/blender_2.43_scripts/add_mesh_empty.py
Normal file
13
src_research_readme/blender_2.43_scripts/add_mesh_empty.py
Normal file
@@ -0,0 +1,13 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Empty mesh'
|
||||
Blender: 243
|
||||
Group: 'AddMesh'
|
||||
"""
|
||||
import BPyAddMesh
|
||||
import Blender
|
||||
|
||||
def main():
|
||||
BPyAddMesh.add_mesh_simple('EmptyMesh', [], [], [])
|
||||
|
||||
main()
|
||||
69
src_research_readme/blender_2.43_scripts/add_mesh_torus.py
Normal file
69
src_research_readme/blender_2.43_scripts/add_mesh_torus.py
Normal file
@@ -0,0 +1,69 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Torus'
|
||||
Blender: 243
|
||||
Group: 'AddMesh'
|
||||
"""
|
||||
import BPyAddMesh
|
||||
import Blender
|
||||
try: from math import cos, sin, pi
|
||||
except: math = None
|
||||
|
||||
def add_torus(PREF_MAJOR_RAD, PREF_MINOR_RAD, PREF_MAJOR_SEG, PREF_MINOR_SEG):
|
||||
Vector = Blender.Mathutils.Vector
|
||||
RotationMatrix = Blender.Mathutils.RotationMatrix
|
||||
verts = []
|
||||
faces = []
|
||||
i1 = 0
|
||||
tot_verts = PREF_MAJOR_SEG * PREF_MINOR_SEG
|
||||
for major_index in xrange(PREF_MAJOR_SEG):
|
||||
verts_tmp = []
|
||||
mtx = RotationMatrix( 360 * float(major_index)/PREF_MAJOR_SEG, 3, 'z' )
|
||||
|
||||
for minor_index in xrange(PREF_MINOR_SEG):
|
||||
angle = 2*pi*minor_index/PREF_MINOR_SEG
|
||||
|
||||
verts.append( Vector(PREF_MAJOR_RAD+(cos(angle)*PREF_MINOR_RAD), 0, (sin(angle)*PREF_MINOR_RAD)) * mtx )
|
||||
if minor_index+1==PREF_MINOR_SEG:
|
||||
i2 = (major_index)*PREF_MINOR_SEG
|
||||
i3 = i1 + PREF_MINOR_SEG
|
||||
i4 = i2 + PREF_MINOR_SEG
|
||||
|
||||
else:
|
||||
i2 = i1 + 1
|
||||
i3 = i1 + PREF_MINOR_SEG
|
||||
i4 = i3 + 1
|
||||
|
||||
if i2>=tot_verts: i2 = i2-tot_verts
|
||||
if i3>=tot_verts: i3 = i3-tot_verts
|
||||
if i4>=tot_verts: i4 = i4-tot_verts
|
||||
|
||||
faces.append( (i3,i4,i2,i1) )
|
||||
i1+=1
|
||||
|
||||
return verts, faces
|
||||
|
||||
def main():
|
||||
Draw = Blender.Draw
|
||||
PREF_MAJOR_RAD = Draw.Create(1.0)
|
||||
PREF_MINOR_RAD = Draw.Create(0.25)
|
||||
PREF_MAJOR_SEG = Draw.Create(48)
|
||||
PREF_MINOR_SEG = Draw.Create(16)
|
||||
|
||||
if not Draw.PupBlock('Add Torus', [\
|
||||
('Major Radius:', PREF_MAJOR_RAD, 0.01, 100, 'Radius for the main ring of the torus'),\
|
||||
('Minor Radius:', PREF_MINOR_RAD, 0.01, 100, 'Radius for the minor ring of the torus setting the thickness of the ring'),\
|
||||
('Major Segments:', PREF_MAJOR_SEG, 3, 256, 'Number of segments for the main ring of the torus'),\
|
||||
('Minor Segments:', PREF_MINOR_SEG, 3, 256, 'Number of segments for the minor ring of the torus'),\
|
||||
]):
|
||||
return
|
||||
|
||||
verts, faces = add_torus(PREF_MAJOR_RAD.val, PREF_MINOR_RAD.val, PREF_MAJOR_SEG.val, PREF_MINOR_SEG.val)
|
||||
|
||||
BPyAddMesh.add_mesh_simple('Torus', verts, [], faces)
|
||||
|
||||
if cos and sin and pi:
|
||||
main()
|
||||
else:
|
||||
Blender.Draw.PupMenu("Error%t|This script requires a full python installation")
|
||||
|
||||
@@ -0,0 +1,792 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Bake Constraints'
|
||||
Blender: 246
|
||||
Group: 'Animation'
|
||||
Tooltip: 'Bake a Constrained object/rig to IPOs'
|
||||
Fillename: 'Bake_Constraint.py'
|
||||
"""
|
||||
|
||||
__author__ = "Roger Wickes (rogerwickes(at)yahoo.com)"
|
||||
__script__ = "Animation Bake Constraints"
|
||||
__version__ = "0.7"
|
||||
__url__ = ["Communicate problems and errors, http://www.blenderartists.com/forum/private.php?do=newpm to PapaSmurf"]
|
||||
__email__= ["Roger Wickes, rogerwickes@yahoo.com", "scripts"]
|
||||
__bpydoc__ = """\
|
||||
|
||||
bake_constraints
|
||||
|
||||
This script bakes the real-world LocRot of an object (the net effect of any constraints -
|
||||
(Copy, Limit, Track, Follow, - that affect Location, Rotation)
|
||||
(usually one constrained to match another's location and/or Tracked to another)
|
||||
and creates a clone with a set of Ipo Curves named Ipo<objname>
|
||||
These curves control a non-constrained object and thus make it mimic the constrained object
|
||||
Actions can be then be edited without the need for the drivers/constraining objects
|
||||
|
||||
Developed for use with MoCap data, where a bone is constrained to point at an empty
|
||||
moving through space and time. This records the actual locrot of the armature
|
||||
so that the motion can be edited, reoriented, scaled, and used as NLA Actions
|
||||
|
||||
see also wiki Scripts/Manual/ Tutorial/Motion Capture <br>
|
||||
|
||||
Usage: <br>
|
||||
- Select the reference Object(s) you want to bake <br>
|
||||
- Set the frame range to bake in the Anim Panel <br>
|
||||
- Set the test code (if you want a self-test) in the RT field in the Anim Panel <br>
|
||||
-- Set RT:1 to create a test armature <br>
|
||||
-- Set RT: up to 100 for more debug messages and status updates <br>
|
||||
<br>
|
||||
- Run the script <br>
|
||||
- The clone copy of the object is created and it has an IPO curve assigned to it. <br>
|
||||
- The clone shadows the object by an offset locrot (see usrDelta) <br>
|
||||
- That Object has Ipo Location and Rotation curves that make the clone mimic the movement <br>
|
||||
of the selected object, but without using constraints. <br>
|
||||
- If the object was an Armature, the clone's bones move identically in relation to the <br>
|
||||
original armature, and an Action is created that drives the bone movements. <br>
|
||||
|
||||
Version History:
|
||||
0.1: bakes Loc Rot for a constrained object
|
||||
0.2: bakes Loc and Rot for the bones within Armature object
|
||||
0.3: UI for setting options
|
||||
0.3.1 add manual to script library
|
||||
0.4: bake multiple objects
|
||||
0.5: root bone worldspace rotation
|
||||
0.6: re-integration with BPyArmature
|
||||
0.7: bakes parents and leaves clones selected
|
||||
|
||||
License, Copyright, and Attribution:
|
||||
by Roger WICKES May 2008, released under Blender Artistic Licence to Public Domain
|
||||
feel free to add to any Blender Python Scripts Bundle.
|
||||
Thanks to Jean-Baptiste PERIN, IdeasMan42 (Campbell Barton), Basil_Fawlty/Cage_drei (Andrew Cruse)
|
||||
much lifted/learned from blender.org/documentation/245PytonDoc and wiki
|
||||
some modules based on c3D_Import.py, PoseLib16.py and IPO/Armature code examples e.g. camera jitter
|
||||
|
||||
Pseudocode:
|
||||
Initialize
|
||||
If at least one object is selected
|
||||
For each selected object,
|
||||
create a cloned object
|
||||
remove any constraints on the clone
|
||||
create or reset an ipo curve named like the object
|
||||
for each frame
|
||||
set the clone's locrot key based on the reference object
|
||||
if it's an armature,
|
||||
create an action (which is an Ipo for each bone)
|
||||
for each frame of the animation
|
||||
for each bone in the armature
|
||||
set the key
|
||||
Else you're a smurf
|
||||
|
||||
Test Conditions and Regressions:
|
||||
1. (v0.1) Non-armatures (the cube), with ipo curve and constraints at the object level
|
||||
2. armatures, with ipo curve and constraints at the object level
|
||||
3. armatures, with bones that have ipo curves and constraints
|
||||
4. objects without parents, children with unselected parents, select children first.
|
||||
|
||||
Naming conventions:
|
||||
arm = a specific objec type armature
|
||||
bone = bones that make up the skeleton of an armature
|
||||
|
||||
ob = object, an instance of an object type
|
||||
ebone = edit bone, a bone in edit mode
|
||||
pbone = pose bone, a posed bone in an object
|
||||
tst = testing, self-test routines
|
||||
usr = user-entered or designated stuff
|
||||
"""
|
||||
########################################
|
||||
|
||||
import Blender
|
||||
from Blender import *
|
||||
from Blender.Mathutils import *
|
||||
import struct
|
||||
import string
|
||||
import bpy
|
||||
import BPyMessages
|
||||
import BPyArmature
|
||||
# reload(BPyArmature)
|
||||
from BPyArmature import getBakedPoseData
|
||||
|
||||
Vector= Blender.Mathutils.Vector
|
||||
Euler= Blender.Mathutils.Euler
|
||||
Matrix= Blender.Mathutils.Matrix #invert() function at least
|
||||
RotationMatrix = Blender.Mathutils.RotationMatrix
|
||||
TranslationMatrix= Blender.Mathutils.TranslationMatrix
|
||||
Quaternion = Blender.Mathutils.Quaternion
|
||||
Vector = Blender.Mathutils.Vector
|
||||
POSE_XFORM= [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT]
|
||||
|
||||
#=================
|
||||
# Global Variables
|
||||
#=================
|
||||
|
||||
# set senstitivity for displaying debug/console messages. 0=none, 100=max
|
||||
# then call debug(num,string) to conditionally display status/info in console window
|
||||
MODE=Blender.Get('rt') #execution mode: 0=run normal, 1=make test armature
|
||||
DEBUG=Blender.Get('rt') #how much detail on internal processing for user to see. range 0-100
|
||||
BATCH=False #called from command line? is someone there? Would you like some cake?
|
||||
|
||||
#there are two coordinate systems, the real, or absolute 3D space,
|
||||
# and the local relative to a parent.
|
||||
COORDINATE_SYSTEMS = ['local','real']
|
||||
COORD_LOCAL = 0
|
||||
COORD_REAL = 1
|
||||
|
||||
# User Settings - Change these options manually or via GUI (future TODO)
|
||||
usrCoord = COORD_REAL # what the user wants
|
||||
usrParent = False # True=clone keeps original parent, False = clone's parent is the clone of the original parent (if cloned)
|
||||
usrFreeze = 2 #2=yes, 0=no. Freezes shadow object in place at current frame as origin
|
||||
# delta is amount to offset/change from the reference object. future set in a ui, so technically not a constant
|
||||
usrDelta = [10,10,0,0,0,0] #order specific - Loc xyz Rot xyz
|
||||
usrACTION = True # Offset baked Action frames to start at frame 1
|
||||
|
||||
CURFRAME = 'curframe' #keyword to use when getting the frame number that the scene is presently on
|
||||
ARMATURE = 'Armature' #en anglais
|
||||
BONE_SPACES = ['ARMATURESPACE','BONESPACE']
|
||||
# 'ARMATURESPACE' - this matrix of the bone in relation to the armature
|
||||
# 'BONESPACE' - the matrix of the bone in relation to itself
|
||||
|
||||
#Ipo curves created are prefixed with a name, like Ipo_ or Bake_ followed by the object/bone name
|
||||
#bakedArmName = "b." #used for both the armature class and object instance
|
||||
usrObjectNamePrefix= ""
|
||||
#ipoBoneNamePrefix = ""
|
||||
# for example, if on entry an armature named Man was selected, and the object prefix was "a."
|
||||
# on exit an armature and an IPO curve named a.Man exists for the object as a whole
|
||||
# if that armature had bones (spine, neck, arm) and the bone prefix was "a."
|
||||
# the bones and IPO curves will be (a.spine, a.neck, a.arm)
|
||||
|
||||
R2D = 18/3.141592653589793 # radian to grad
|
||||
BLENDER_VERSION = Blender.Get('version')
|
||||
|
||||
# Gets the current scene, there can be many scenes in 1 blend file.
|
||||
scn = Blender.Scene.GetCurrent()
|
||||
|
||||
#=================
|
||||
# Methods
|
||||
#=================
|
||||
########################################
|
||||
def debug(num,msg): #use log4j or just console here.
|
||||
if DEBUG >= num:
|
||||
if BATCH == False:
|
||||
print 'debug: '[:num/10+7]+msg
|
||||
#TODO: else write out to file (runs faster if it doesnt have to display details)
|
||||
return
|
||||
|
||||
########################################
|
||||
def error(str):
|
||||
debug(0,'ERROR: '+str)
|
||||
if BATCH == False:
|
||||
Draw.PupMenu('ERROR%t|'+str)
|
||||
return
|
||||
|
||||
########################################
|
||||
def getRenderInfo():
|
||||
context=scn.getRenderingContext()
|
||||
staframe = context.startFrame()
|
||||
endframe = context.endFrame()
|
||||
if endframe<staframe: endframe=staframe
|
||||
curframe = Blender.Get(CURFRAME)
|
||||
debug(90,'Scene is on frame %i and frame range is %i to %i' % (curframe,staframe,endframe))
|
||||
return (staframe,endframe,curframe)
|
||||
|
||||
########################################
|
||||
def sortObjects(obs): #returns a list of objects sorted based on parent dependency
|
||||
obClones= []
|
||||
while len(obClones) < len(obs):
|
||||
for ob in obs:
|
||||
if not ob in obClones:
|
||||
par= ob.getParent()
|
||||
#if no parent, or the parent is not scheduled to be cloned
|
||||
if par==None:
|
||||
obClones.append(ob) # add the independent
|
||||
elif par not in obs: # parent will not be cloned
|
||||
obClones.append(ob) # add the child
|
||||
elif par in obClones: # is it on the list?
|
||||
obClones.append(ob) # add the child
|
||||
# parent may be a child, so it will be caught next time thru
|
||||
debug(100,'clone object order: \n%s' % obClones)
|
||||
return obClones # ordered list of (ob, par) tuples
|
||||
|
||||
########################################
|
||||
def sortBones(xbones): #returns a sorted list of bones that should be added,sorted based on parent dependency
|
||||
# while there are bones to add,
|
||||
# look thru the list of bones we need to add
|
||||
# if we have not already added this bone
|
||||
# if it does not have a parent
|
||||
# add it
|
||||
# else, it has a parent
|
||||
# if we already added it's parent
|
||||
# add it now.
|
||||
# else #we need to keep cycling and catch its parent
|
||||
# else it is a root bone
|
||||
# add it
|
||||
# else skip it, it's already in there
|
||||
# endfor
|
||||
# endwhile
|
||||
xboneNames=[]
|
||||
for xbone in xbones: xboneNames.append(xbone.name)
|
||||
debug (80,'reference bone order: \n%s' % xboneNames)
|
||||
eboneNames=[]
|
||||
while len(eboneNames) < len(xboneNames):
|
||||
for xbone in xbones:
|
||||
if not xbone.name in eboneNames:
|
||||
if not xbone.parent:
|
||||
eboneNames.append(xbone.name)
|
||||
else:
|
||||
if xbone.parent.name in eboneNames:
|
||||
eboneNames.append(xbone.name)
|
||||
#else skip it
|
||||
#endif
|
||||
#else prego
|
||||
#endfor
|
||||
#endwhile
|
||||
debug (80,'clone bone order: \n%s' % eboneNames)
|
||||
return eboneNames
|
||||
|
||||
########################################
|
||||
def dupliArmature(ob): #makes a copy in current scn of the armature used by ob and its bones
|
||||
ob_mat = ob.matrixWorld
|
||||
ob_data = ob.getData()
|
||||
debug(49,'Reference object uses %s' % ob_data)
|
||||
arm_ob = Armature.Get(ob_data.name) #the armature used by the passed object
|
||||
|
||||
arm = Blender.Armature.New()
|
||||
debug(20,'Cloning Armature %s to create %s' % (arm_ob.name, arm.name))
|
||||
arm.drawType = Armature.STICK #set the draw type
|
||||
|
||||
arm.makeEditable() #enter editmode
|
||||
|
||||
# for each bone in the object's armature,
|
||||
xbones=ob.data.bones.values()
|
||||
usrSpace = 0 #0=armature, 1=local
|
||||
space=[BONE_SPACES[usrSpace]][0]
|
||||
|
||||
#we have to make a list of bones, then figure out our parents, then add to the arm
|
||||
#when creating a child, we cannot link to a parent if it does not yet exist in our armature
|
||||
ebones = [] #list of the bones I want to create for my arm
|
||||
|
||||
eboneNames = sortBones(xbones)
|
||||
|
||||
i=0
|
||||
# error('bones sorted. continue?')
|
||||
for abone in eboneNames: #set all editable attributes to fully define the bone.
|
||||
for bone in xbones:
|
||||
if bone.name == abone: break # get the reference bone
|
||||
ebone = Armature.Editbone() #throw me a bone, bone-man!
|
||||
ebones.append(ebone) #you're on my list, buddy
|
||||
|
||||
ebone.name = bone.name
|
||||
ebone.headRadius = bone.headRadius
|
||||
ebone.tailRadius = bone.tailRadius
|
||||
ebone.weight = bone.weight
|
||||
ebone.options = bone.options
|
||||
|
||||
ebone.head = bone.head[space] #dictionary lookups
|
||||
ebone.tail = bone.tail[space]
|
||||
ebone.matrix = bone.matrix[space]
|
||||
ebone.roll = bone.roll[space]
|
||||
|
||||
debug(30,'Generating new %s as child of %s' % (bone,bone.parent))
|
||||
if bone.hasParent():
|
||||
# parent=bone.parent.name
|
||||
# debug(100,'looking for %s' % parent)
|
||||
# for parbone in xbones: if parbone.name == parent: break # get the parent bone
|
||||
# ebone.parent = arm.bones[ebones[j].name]
|
||||
ebone.parent = arm.bones[bone.parent.name]
|
||||
# else:
|
||||
# ebone.parent = None
|
||||
debug(30,'Generating new editbone %s as child of %s' % (ebone,ebone.parent))
|
||||
arm.bones[ebone.name] = ebone # i would have expected an append or add function, but this works
|
||||
|
||||
debug (100,'arm.bones: \n%s' % arm.bones)
|
||||
debug (20,'Cloned %i bones now in armature %s' %(len(arm.bones),arm.name))
|
||||
|
||||
myob = scn.objects.new(arm) #interestingly, object must be created before
|
||||
arm.update() #armature can be saved
|
||||
debug(40,'dupArm finished %s instanced as object %s' % (arm.name,myob.getName()))
|
||||
print ob.matrix
|
||||
print myob.matrix
|
||||
|
||||
return myob
|
||||
########################################
|
||||
def scrub(): # scrubs to startframe
|
||||
staFrame,endFrame,curFrame = getRenderInfo()
|
||||
|
||||
# eye-candy, go from current to start, fwd or back
|
||||
if not BATCH:
|
||||
debug(100, "Positioning to start...")
|
||||
frameinc=(staFrame-curFrame)/10
|
||||
if abs(frameinc) >= 1:
|
||||
for i in range(10):
|
||||
curFrame+=frameinc
|
||||
Blender.Set(CURFRAME,curFrame) # computes the constrained location of the 'real' objects
|
||||
Blender.Redraw()
|
||||
Blender.Set(CURFRAME, staFrame)
|
||||
return
|
||||
|
||||
########################################
|
||||
def bakeBones(ref_ob,arm_ob): #copy pose from ref_ob to arm_ob
|
||||
scrub()
|
||||
staFrame,endFrame,curFrame = getRenderInfo()
|
||||
act = getBakedPoseData(ref_ob, staFrame, endFrame, ACTION_BAKE = True, ACTION_BAKE_FIRST_FRAME = usrACTION) # bake the pose positions of the reference ob to the armature ob
|
||||
arm_ob.action = act
|
||||
scrub()
|
||||
|
||||
# user comprehension feature - change action name and channel ipo names to match the names of the bone they drive
|
||||
debug (80,'Renaming each action ipo to match the bone they pose')
|
||||
act.name = arm_ob.name
|
||||
arm_channels = act.getAllChannelIpos()
|
||||
pose= arm_ob.getPose()
|
||||
pbones= pose.bones.values() #we want the bones themselves, not the dictionary lookup
|
||||
for pbone in pbones:
|
||||
debug (100,'Channel listing for %s: %s' % (pbone.name,arm_channels[pbone.name] ))
|
||||
ipo=arm_channels[pbone.name]
|
||||
ipo.name = pbone.name # since bone names are unique within an armature, the pose names can be the same since they are within an Action
|
||||
|
||||
return
|
||||
|
||||
########################################
|
||||
def getOrCreateCurve(ipo, curvename):
|
||||
"""
|
||||
Retrieve or create a Blender Ipo Curve named C{curvename} in the C{ipo} Ipo
|
||||
Either an ipo curve named C{curvename} exists before the call then this curve is returned,
|
||||
Or such a curve doesn't exist before the call .. then it is created into the c{ipo} Ipo and returned
|
||||
"""
|
||||
try:
|
||||
mycurve = ipo.getCurve(curvename)
|
||||
if mycurve != None:
|
||||
pass
|
||||
else:
|
||||
mycurve = ipo.addCurve(curvename)
|
||||
except:
|
||||
mycurve = ipo.addCurve(curvename)
|
||||
return mycurve
|
||||
|
||||
########################################
|
||||
def eraseCurve(ipo,numCurves):
|
||||
debug(90,'Erasing %i curves for %' % (numCurves,ipo.GetName()))
|
||||
for i in range(numCurves):
|
||||
nbBezPoints= ipo.getNBezPoints(i)
|
||||
for j in range(nbBezPoints):
|
||||
ipo.delBezPoint(i)
|
||||
return
|
||||
|
||||
########################################
|
||||
def resetIPO(ipo):
|
||||
debug(60,'Resetting ipo curve named %s' %ipo.name)
|
||||
numCurves = ipo.getNcurves() #like LocX, LocY, etc
|
||||
if numCurves > 0:
|
||||
eraseCurve(ipo, numCurves) #erase data if one exists
|
||||
return
|
||||
|
||||
########################################
|
||||
def resetIPOs(ob): #resets all IPO curvess assocated with an object and its bones
|
||||
debug(30,'Resetting any ipo curves linked to %s' %ob.getName())
|
||||
ipo = ob.getIpo() #may be None
|
||||
ipoName = ipo.getName() #name of the IPO that guides/controls this object
|
||||
debug(70,'Object IPO is %s' %ipoName)
|
||||
try:
|
||||
ipo = Ipo.Get(ipoName)
|
||||
except:
|
||||
ipo = Ipo.New('Object', ipoName)
|
||||
resetIPO(ipo)
|
||||
if ob.getType() == ARMATURE:
|
||||
arm_data=ob.getData()
|
||||
bones=arm_data.bones.values()
|
||||
for bone in bones:
|
||||
#for each bone: get the name and check for a Pose IPO
|
||||
debug(10,'Processing '+ bone.name)
|
||||
return
|
||||
|
||||
########################################
|
||||
def parse(string,delim):
|
||||
index = string.find(delim) # -1 if not found, else pointer to delim
|
||||
if index+1: return string[:index]
|
||||
return string
|
||||
|
||||
########################################
|
||||
def newIpo(ipoName): #add a new Ipo object to the Blender scene
|
||||
ipo=Blender.Ipo.New('Object',ipoName)
|
||||
|
||||
ipo.addCurve('LocX')
|
||||
ipo.addCurve('LocY')
|
||||
ipo.addCurve('LocZ')
|
||||
ipo.addCurve('RotX')
|
||||
ipo.addCurve('RotY')
|
||||
ipo.addCurve('RotZ')
|
||||
return ipo
|
||||
|
||||
########################################
|
||||
def makeUpaName(type,name): #i know this exists in Blender somewhere...
|
||||
debug(90,'Making up a new %s name using %s as a basis.' % (type,name))
|
||||
name = (parse(name,'.'))
|
||||
if type == 'Ipo':
|
||||
ipoName = name # maybe we get lucky today
|
||||
ext = 0
|
||||
extlen = 3 # 3 digit extensions, like hello.002
|
||||
success = False
|
||||
while not(success):
|
||||
try:
|
||||
debug(100,'Trying %s' % ipoName)
|
||||
ipo = Ipo.Get(ipoName)
|
||||
#that one exists if we get here. add on extension and keep trying
|
||||
ext +=1
|
||||
if ext>=10**extlen: extlen +=1 # go to more digits if 999 not found
|
||||
ipoName = '%s.%s' % (name, str(ext).zfill(extlen))
|
||||
except: # could not find it
|
||||
success = True
|
||||
name=ipoName
|
||||
else:
|
||||
debug (0,'FATAL ERROR: I dont know how to make up a new %s name based on %s' % (type,ob))
|
||||
return None
|
||||
return name
|
||||
|
||||
########################################
|
||||
def createIpo(ob): #create an Ipo and curves and link them to this object
|
||||
#first, we have to create a unique name
|
||||
#try first with just the name of the object to keep things simple.
|
||||
ipoName = makeUpaName('Ipo',ob.getName()) # make up a name for a new Ipo based on the object name
|
||||
debug(20,'Ipo and LocRot curves called %s' % ipoName)
|
||||
ipo=newIpo(ipoName)
|
||||
ob.setIpo(ipo) #link them
|
||||
return ipo
|
||||
|
||||
########################################
|
||||
def getLocLocal(ob):
|
||||
key = [
|
||||
ob.LocX,
|
||||
ob.LocY,
|
||||
ob.LocZ,
|
||||
ob.RotX*R2D, #get the curves in this order
|
||||
ob.RotY*R2D,
|
||||
ob.RotZ*R2D
|
||||
]
|
||||
return key
|
||||
|
||||
########################################
|
||||
def getLocReal(ob):
|
||||
obMatrix = ob.matrixWorld #Thank you IdeasMan42
|
||||
loc = obMatrix.translationPart()
|
||||
rot = obMatrix.toEuler()
|
||||
key = [
|
||||
loc.x,
|
||||
loc.y,
|
||||
loc.z,
|
||||
rot.x/10,
|
||||
rot.y/10,
|
||||
rot.z/10
|
||||
]
|
||||
return key
|
||||
|
||||
########################################
|
||||
def getLocRot(ob,space):
|
||||
if space in xrange(len(COORDINATE_SYSTEMS)):
|
||||
if space == COORD_LOCAL:
|
||||
key = getLocLocal(ob)
|
||||
return key
|
||||
elif space == COORD_REAL:
|
||||
key = getLocReal(ob)
|
||||
return key
|
||||
else: #hey, programmers make mistakes too.
|
||||
debug(0,'Fatal Error: getLoc called with %i' % space)
|
||||
return
|
||||
|
||||
########################################
|
||||
def getCurves(ipo):
|
||||
ipos = [
|
||||
ipo[Ipo.OB_LOCX],
|
||||
ipo[Ipo.OB_LOCY],
|
||||
ipo[Ipo.OB_LOCZ],
|
||||
ipo[Ipo.OB_ROTX], #get the curves in this order
|
||||
ipo[Ipo.OB_ROTY],
|
||||
ipo[Ipo.OB_ROTZ]
|
||||
]
|
||||
return ipos
|
||||
|
||||
########################################
|
||||
def addPoint(time,keyLocRot,ipos):
|
||||
if BLENDER_VERSION < 245:
|
||||
debug(0,'WARNING: addPoint uses BezTriple')
|
||||
for i in range(len(ipos)):
|
||||
point = BezTriple.New() #this was new with Blender 2.45 API
|
||||
point.pt = (time, keyLocRot[i])
|
||||
point.handleTypes = [1,1]
|
||||
|
||||
ipos[i].append(point)
|
||||
return ipos
|
||||
|
||||
########################################
|
||||
def bakeFrames(ob,myipo): #bakes an object in a scene, returning the IPO containing the curves
|
||||
myipoName = myipo.getName()
|
||||
debug(20,'Baking frames for scene %s object %s to ipo %s' % (scn.getName(),ob.getName(),myipoName))
|
||||
ipos = getCurves(myipo)
|
||||
#TODO: Gui setup idea: myOffset
|
||||
# reset action to start at frame 1 or at location
|
||||
myOffset=0 #=1-staframe
|
||||
#loop through frames in the animation. Often, there is rollup and the mocap starts late
|
||||
staframe,endframe,curframe = getRenderInfo()
|
||||
for frame in range(staframe, endframe+1):
|
||||
debug(80,'Baking Frame %i' % frame)
|
||||
#tell Blender to advace to frame
|
||||
Blender.Set(CURFRAME,frame) # computes the constrained location of the 'real' objects
|
||||
if not BATCH: Blender.Redraw() # no secrets, let user see what we are doing
|
||||
|
||||
#using the constrained Loc Rot of the object, set the location of the unconstrained clone. Yea! Clones are FreeMen
|
||||
key = getLocRot(ob,usrCoord) #a key is a set of specifed exact channel values (LocRotScale) for a certain frame
|
||||
key = [a+b for a,b in zip(key, usrDelta)] #offset to the new location
|
||||
|
||||
myframe= frame+myOffset
|
||||
Blender.Set(CURFRAME,myframe)
|
||||
|
||||
time = Blender.Get('curtime') #for BezTriple
|
||||
ipos = addPoint(time,key,ipos) #add this data at this time to the ipos
|
||||
debug(100,'%s %i %.3f %.2f %.2f %.2f %.2f %.2f %.2f' % (myipoName, myframe, time, key[0], key[1], key[2], key[3], key[4], key[5]))
|
||||
# eye-candy - smoothly rewind the animation, showing now how the clone match moves
|
||||
if endframe-staframe <400 and not BATCH:
|
||||
for frame in range (endframe,staframe,-1): #rewind
|
||||
Blender.Set(CURFRAME,frame) # computes the constrained location of the 'real' objects
|
||||
Blender.Redraw()
|
||||
Blender.Set(CURFRAME,staframe)
|
||||
Blender.Redraw()
|
||||
|
||||
return ipos
|
||||
|
||||
########################################
|
||||
def duplicateLinked(ob):
|
||||
obType = ob.type
|
||||
debug(10,'Duplicating %s Object named %s' % (obType,ob.getName()))
|
||||
scn.objects.selected = [ob]
|
||||
## rdw: simplified by just duplicating armature. kept code as reference for creating armatures
|
||||
## disadvantage is that you cant have clone as stick and original as octahedron
|
||||
## since they share the same Armature. User can click Make Single User button.
|
||||
## if obType == ARMATURE: #build a copy from scratch
|
||||
## myob= dupliArmature(ob)
|
||||
## else:
|
||||
Blender.Object.Duplicate() # Duplicate linked, including pose constraints.
|
||||
myobs = Object.GetSelected() #duplicate is top on the list
|
||||
myob = myobs[0]
|
||||
if usrParent == False:
|
||||
myob.clrParent(usrFreeze)
|
||||
debug(20,'=myob= was created as %s' % myob.getName())
|
||||
return myob
|
||||
|
||||
########################################
|
||||
def removeConstraints(ob):
|
||||
for const in ob.constraints:
|
||||
debug(90,'removed %s => %s' % (ob.name, const))
|
||||
ob.constraints.remove(const)
|
||||
return
|
||||
|
||||
########################################
|
||||
def removeConstraintsOb(ob): # from object or armature
|
||||
debug(40,'Removing constraints from '+ob.getName())
|
||||
if BLENDER_VERSION > 241: #constraints module not available before 242
|
||||
removeConstraints(ob)
|
||||
if ob.getType() == ARMATURE:
|
||||
pose = ob.getPose()
|
||||
for pbone in pose.bones.values():
|
||||
#bone = pose.bones[bonename]
|
||||
removeConstraints(pbone)
|
||||
#should also check if it is a deflector?
|
||||
return
|
||||
|
||||
########################################
|
||||
def deLinkOb(type,ob): #remove linkages
|
||||
if type == 'Ipo':
|
||||
success = ob.clearIpo() #true=there was one
|
||||
if success: debug(80,'deLinked Ipo curve to %s' % ob.getName())
|
||||
return
|
||||
|
||||
########################################
|
||||
def bakeObject(ob): #bakes the core object locrot and assigns the Ipo to a Clone
|
||||
if ob != None:
|
||||
# Clone the object - duplicate it, clean the clone, and create an ipo curve for the clone
|
||||
myob = duplicateLinked(ob) #clone it
|
||||
myob.setName(usrObjectNamePrefix + ob.getName())
|
||||
removeConstraintsOb(myob) #my object is a free man
|
||||
deLinkOb('Ipo',myob) #kids, it's not nice to share. you've been lied to
|
||||
if ob.getType() != ARMATURE: # baking armatures is based on bones, not object
|
||||
myipo = createIpo(myob) #create own IPO and curves for the clone object
|
||||
ipos = bakeFrames(ob,myipo) #bake the locrot for this obj for the scene frames
|
||||
return myob
|
||||
|
||||
########################################
|
||||
def bake(ob,par): #bakes an object of any type, linking it to parent
|
||||
debug(0,'Baking %s object %s' % (ob.getType(), ob))
|
||||
clone = bakeObject(ob) #creates and bakes the object motion
|
||||
if par!= None:
|
||||
par.makeParent([clone])
|
||||
debug(20,"assigned object to parent %s" % par)
|
||||
if ob.getType() == ARMATURE:
|
||||
## error('Object baked. Continue with bones?')
|
||||
bakeBones(ob,clone) #go into the bones and copy from -> to in frame range
|
||||
#future idea: bakeMesh (net result of Shapekeys, Softbody, Cloth, Fluidsim,...)
|
||||
return clone
|
||||
|
||||
########################################
|
||||
def tstCreateArm(): #create a test armature in scene
|
||||
# rip-off from http://www.blender.org/documentation/245PythonDoc/Pose-module.html - thank you!
|
||||
|
||||
debug(0,'Making Test Armature')
|
||||
# New Armature
|
||||
arm_data= Armature.New('myArmature')
|
||||
print arm_data
|
||||
arm_ob = scn.objects.new(arm_data)
|
||||
arm_data.makeEditable()
|
||||
|
||||
# Add 4 bones
|
||||
ebones = [Armature.Editbone(), Armature.Editbone(), Armature.Editbone(), Armature.Editbone()]
|
||||
|
||||
# Name the editbones
|
||||
ebones[0].name = 'Bone.001'
|
||||
ebones[1].name = 'Bone.002'
|
||||
ebones[2].name = 'Bone.003'
|
||||
ebones[3].name = 'Bone.004'
|
||||
|
||||
# Assign the editbones to the armature
|
||||
for eb in ebones:
|
||||
arm_data.bones[eb.name]= eb
|
||||
|
||||
# Set the locations of the bones
|
||||
ebones[0].head= Mathutils.Vector(0,0,0)
|
||||
ebones[0].tail= Mathutils.Vector(0,0,1) #tip
|
||||
ebones[1].head= Mathutils.Vector(0,0,1)
|
||||
ebones[1].tail= Mathutils.Vector(0,0,2)
|
||||
ebones[2].head= Mathutils.Vector(0,0,2)
|
||||
ebones[2].tail= Mathutils.Vector(0,0,3)
|
||||
ebones[3].head= Mathutils.Vector(0,0,3)
|
||||
ebones[3].tail= Mathutils.Vector(0,0,4)
|
||||
|
||||
ebones[1].parent= ebones[0]
|
||||
ebones[2].parent= ebones[1]
|
||||
ebones[3].parent= ebones[2]
|
||||
|
||||
arm_data.update()
|
||||
# Done with editing the armature
|
||||
|
||||
# Assign the pose animation
|
||||
arm_pose = arm_ob.getPose()
|
||||
|
||||
act = arm_ob.getAction()
|
||||
if not act: # Add a pose action if we dont have one
|
||||
act = Armature.NLA.NewAction()
|
||||
act.setActive(arm_ob)
|
||||
|
||||
xbones=arm_ob.data.bones.values()
|
||||
pbones = arm_pose.bones.values()
|
||||
|
||||
frame = 1
|
||||
for pbone in pbones: # set bones to no rotation
|
||||
pbone.quat[:] = 1.000,0.000,0.000,0.0000
|
||||
pbone.insertKey(arm_ob, frame, Object.Pose.ROT)
|
||||
|
||||
# Set a different rotation at frame 25
|
||||
pbones[0].quat[:] = 1.000,0.1000,0.2000,0.20000
|
||||
pbones[1].quat[:] = 1.000,0.6000,0.5000,0.40000
|
||||
pbones[2].quat[:] = 1.000,0.1000,0.3000,0.40000
|
||||
pbones[3].quat[:] = 1.000,-0.2000,-0.3000,0.30000
|
||||
|
||||
frame = 25
|
||||
for i in xrange(4):
|
||||
pbones[i].insertKey(arm_ob, frame, Object.Pose.ROT)
|
||||
|
||||
pbones[0].quat[:] = 1.000,0.000,0.000,0.0000
|
||||
pbones[1].quat[:] = 1.000,0.000,0.000,0.0000
|
||||
pbones[2].quat[:] = 1.000,0.000,0.000,0.0000
|
||||
pbones[3].quat[:] = 1.000,0.000,0.000,0.0000
|
||||
|
||||
frame = 50
|
||||
for pbone in pbones: # set bones to no rotation
|
||||
pbone.quat[:] = 1.000,0.000,0.000,0.0000
|
||||
pbone.insertKey(arm_ob, frame, Object.Pose.ROT)
|
||||
|
||||
return arm_ob
|
||||
|
||||
########################################
|
||||
def tstMoveOb(ob): # makes a simple LocRot animation of object in the scene
|
||||
anim = [
|
||||
#Loc Rot/10
|
||||
#
|
||||
( 0,0,0, 0, 0, 0), #frame 1 origin
|
||||
( 1,0,0, 0, 0, 0), #frame 2
|
||||
( 1,1,0, 0, 0, 0),
|
||||
( 1,1,1, 0, 0, 0),
|
||||
( 1,1,1,4.5, 0, 0),
|
||||
( 1,1,1,4.5,4.5, 0),
|
||||
( 1,1,1,4.5,4.5,4.5)
|
||||
]
|
||||
space = COORD_LOCAL
|
||||
ipo = createIpo(ob) #create an Ipo and curves for this object
|
||||
ipos = getCurves(ipo)
|
||||
|
||||
# span this motion over the currently set anim range
|
||||
# to set points, i need time but do not know how it is computed, so will have to advance the animation
|
||||
staframe,endframe,curframe = getRenderInfo()
|
||||
|
||||
frame = staframe #x position of new ipo datapoint. set to staframe if you want a match
|
||||
frameDelta=(endframe-staframe)/(len(anim)) #accomplish the animation in frame range
|
||||
for key in anim: #effectively does a getLocRot()
|
||||
#tell Blender to advace to frame
|
||||
Blender.Set('curframe',frame) # computes the constrained location of the 'real' objects
|
||||
time = Blender.Get('curtime')
|
||||
|
||||
ipos = addPoint(time,key,ipos) #add this data at this time to the ipos
|
||||
|
||||
debug(100,'%s %i %.3f %.2f %.2f %.2f %.2f %.2f %.2f' % (ipo.name, frame, time, key[0], key[1], key[2], key[3], key[4], key[5]))
|
||||
frame += frameDelta
|
||||
Blender.Set(CURFRAME,curframe) # reset back to where we started
|
||||
return
|
||||
#=================
|
||||
# Program Template
|
||||
#=================
|
||||
########################################
|
||||
def main():
|
||||
# return code set via rt button in Blender Buttons Scene Context Anim panel
|
||||
if MODE == 1: #create test armature #1
|
||||
ob = tstCreateArm() # make test arm and select it
|
||||
tstMoveOb(ob)
|
||||
scn.objects.selected = [ob]
|
||||
|
||||
obs= Blender.Object.GetSelected() #scn.objects.selected
|
||||
obs= sortObjects(obs)
|
||||
debug(0,'Baking %i objects' % len(obs))
|
||||
|
||||
if len(obs) >= 1: # user might have multiple objects selected
|
||||
i= 0
|
||||
clones=[] # my clone army
|
||||
for ob in obs:
|
||||
par= ob.getParent()
|
||||
if not usrParent:
|
||||
if par in obs:
|
||||
par= clones[obs.index(par)]
|
||||
clones.append(bake(ob,par))
|
||||
scn.objects.selected = clones
|
||||
else:
|
||||
error('Please select at least one object')
|
||||
return
|
||||
|
||||
########################################
|
||||
def benchmark(): # This lets you benchmark (time) the script's running duration
|
||||
Window.WaitCursor(1)
|
||||
t = sys.time()
|
||||
debug(60,'%s began at %.0f' %(__script__,sys.time()))
|
||||
|
||||
# Run the function on the active scene
|
||||
in_editmode = Window.EditMode()
|
||||
if in_editmode: Window.EditMode(0)
|
||||
|
||||
main()
|
||||
|
||||
if in_editmode: Window.EditMode(1)
|
||||
|
||||
# Timing the script is a good way to be aware on any speed hits when scripting
|
||||
debug(0,'%s Script finished in %.2f seconds' % (__script__,sys.time()-t) )
|
||||
Window.WaitCursor(0)
|
||||
return
|
||||
|
||||
########################################
|
||||
# This lets you can import the script without running it
|
||||
if __name__ == '__main__':
|
||||
debug(0, "------------------------------------")
|
||||
debug(0, "%s %s Script begins with mode=%i debug=%i batch=%s" % (__script__,__version__,MODE,DEBUG,BATCH))
|
||||
benchmark()
|
||||
192
src_research_readme/blender_2.43_scripts/animation_clean.py
Normal file
192
src_research_readme/blender_2.43_scripts/animation_clean.py
Normal file
@@ -0,0 +1,192 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Clean Animation Curves'
|
||||
Blender: 249
|
||||
Group: 'Animation'
|
||||
Tooltip: 'Remove unused keyframes for ipo curves'
|
||||
"""
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2008-2009: Blender Foundation
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import bpy
|
||||
from Blender import IpoCurve, Draw, Window
|
||||
|
||||
def clean_ipos(ipos):
|
||||
eul = 0.001
|
||||
|
||||
def isflat(vec):
|
||||
prev_y = vec[0][1]
|
||||
mid_y = vec[1][1]
|
||||
next_y = vec[2][1]
|
||||
|
||||
# flat status for prev and next
|
||||
return abs(mid_y-prev_y) < eul, abs(mid_y-next_y) < eul
|
||||
|
||||
|
||||
|
||||
X=0
|
||||
Y=1
|
||||
PREV=0
|
||||
MID=1
|
||||
NEXT=2
|
||||
|
||||
LEFT = 0
|
||||
RIGHT = 1
|
||||
|
||||
TOT = 0
|
||||
TOTBEZ = 0
|
||||
# for ipo in bpy.data.ipos:
|
||||
for ipo in ipos:
|
||||
if ipo.lib:
|
||||
continue
|
||||
# print ipo
|
||||
for icu in ipo:
|
||||
interp = icu.interpolation
|
||||
extend = icu.extend
|
||||
|
||||
bezierPoints = icu.bezierPoints
|
||||
bezierVecs = [bez.vec for bez in bezierPoints]
|
||||
|
||||
l = len(bezierPoints)
|
||||
|
||||
TOTBEZ += l
|
||||
|
||||
# our aim is to simplify this ipo as much as possible!
|
||||
if interp == IpoCurve.InterpTypes.BEZIER or interp == interp == IpoCurve.InterpTypes.LINEAR:
|
||||
#print "Not yet supported"
|
||||
|
||||
if interp == IpoCurve.InterpTypes.BEZIER:
|
||||
flats = [isflat(bez) for bez in bezierVecs]
|
||||
else:
|
||||
# A bit of a waste but fake the locations for these so they will always be flats
|
||||
# IS better then too much duplicate code.
|
||||
flats = [(True, True)] * l
|
||||
for v in bezierVecs:
|
||||
v[PREV][Y] = v[NEXT][Y] = v[MID][Y]
|
||||
|
||||
|
||||
# remove middle points
|
||||
if l>2:
|
||||
done_nothing = False
|
||||
|
||||
while not done_nothing and len(bezierVecs) > 2:
|
||||
done_nothing = True
|
||||
i = l-2
|
||||
|
||||
while i > 0:
|
||||
#print i
|
||||
#print i, len(bezierVecs)
|
||||
if flats[i]==(True,True) and flats[i-1][RIGHT] and flats[i+1][LEFT]:
|
||||
|
||||
if abs(bezierVecs[i][MID][Y] - bezierVecs[i-1][MID][Y]) < eul and abs(bezierVecs[i][MID][Y] - bezierVecs[i+1][MID][Y]) < eul:
|
||||
done_nothing = False
|
||||
|
||||
del flats[i]
|
||||
del bezierVecs[i]
|
||||
icu.delBezier(i)
|
||||
TOT += 1
|
||||
l-=1
|
||||
i-=1
|
||||
|
||||
# remove endpoints
|
||||
if extend == IpoCurve.ExtendTypes.CONST and len(bezierVecs) > 1:
|
||||
#print l, len(bezierVecs)
|
||||
# start
|
||||
|
||||
while l > 2 and (flats[0][RIGHT] and flats[1][LEFT] and (abs(bezierVecs[0][MID][Y] - bezierVecs[1][MID][Y]) < eul)):
|
||||
print "\tremoving 1 point from start of the curve"
|
||||
del flats[0]
|
||||
del bezierVecs[0]
|
||||
icu.delBezier(0)
|
||||
TOT += 1
|
||||
l-=1
|
||||
|
||||
|
||||
# End
|
||||
while l > 2 and flats[-2][RIGHT] and flats[-1][LEFT] and (abs(bezierVecs[-2][MID][Y] - bezierVecs[-1][MID][Y]) < eul):
|
||||
print "\tremoving 1 point from end of the curve", l
|
||||
del flats[l-1]
|
||||
del bezierVecs[l-1]
|
||||
icu.delBezier(l-1)
|
||||
TOT += 1
|
||||
l-=1
|
||||
|
||||
|
||||
|
||||
if l==2:
|
||||
if isflat( bezierVecs[0] )[RIGHT] and isflat( bezierVecs[1] )[LEFT] and abs(bezierVecs[0][MID][Y] - bezierVecs[1][MID][Y]) < eul:
|
||||
# remove the second point
|
||||
print "\tremoving 1 point from 2 point bez curve"
|
||||
# remove the second point
|
||||
del flats[1]
|
||||
del bezierVecs[1]
|
||||
icu.delBezier(1)
|
||||
TOT+=1
|
||||
l-=1
|
||||
|
||||
# Change to linear for faster evaluation
|
||||
'''
|
||||
if l==1:
|
||||
print 'Linear'
|
||||
icu.interpolation = IpoCurve.InterpTypes.LINEAR
|
||||
'''
|
||||
|
||||
|
||||
|
||||
|
||||
if interp== IpoCurve.InterpTypes.CONST:
|
||||
print "Not yet supported"
|
||||
|
||||
print 'total', TOT, TOTBEZ
|
||||
return TOT, TOTBEZ
|
||||
|
||||
def main():
|
||||
ret = Draw.PupMenu('Clean Selected Objects Ipos%t|Object IPO%x1|Object Action%x2|%l|All IPOs (be careful!)%x3')
|
||||
|
||||
sce = bpy.data.scenes.active
|
||||
ipos = []
|
||||
|
||||
if ret == 3:
|
||||
ipos.extend(list(bpy.data.ipos))
|
||||
else:
|
||||
for ob in sce.objects.context:
|
||||
if ret == 1:
|
||||
ipo = ob.ipo
|
||||
if ipo:
|
||||
ipos.append(ipo)
|
||||
|
||||
elif ret == 2:
|
||||
action = ob.action
|
||||
if action:
|
||||
ipos.extend([ipo for ipo in action.getAllChannelIpos().values() if ipo])
|
||||
|
||||
|
||||
|
||||
if not ipos:
|
||||
Draw.PupMenu('Error%t|No ipos found')
|
||||
else:
|
||||
total_removed, total = clean_ipos(ipos)
|
||||
Draw.PupMenu('Done!%t|Removed ' + str(total_removed) + ' of ' + str(total) + ' points')
|
||||
|
||||
Window.RedrawAll()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
575
src_research_readme/blender_2.43_scripts/animation_trajectory.py
Normal file
575
src_research_readme/blender_2.43_scripts/animation_trajectory.py
Normal file
@@ -0,0 +1,575 @@
|
||||
#!BPY
|
||||
|
||||
""" Registration info for Blender menus: <- these words are ignored
|
||||
Name: 'Trajectory'
|
||||
Blender: 243
|
||||
Group: 'Animation'
|
||||
Tip: 'See Trajectory of selected object'
|
||||
"""
|
||||
|
||||
__author__ = '3R - R3gis'
|
||||
__version__ = '2.43'
|
||||
__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"]
|
||||
__email__=["3R, r3gis@free.fr"]
|
||||
|
||||
|
||||
__bpydoc__ = """
|
||||
|
||||
Usage:
|
||||
|
||||
* Launch with alt+P (or put it in .script folder)
|
||||
|
||||
Allow to see in real time trajectory of selected object.
|
||||
|
||||
On first run, it ask you
|
||||
- If you want that actually selected object have they trajectory always shown
|
||||
- If you want to use Space Handler or a Scriptlink in Redraw mode
|
||||
- Future and Past : it is the frame in past and future
|
||||
of the beggining and the end of the path
|
||||
- Width of line that represent the trajectory
|
||||
|
||||
Then the object's trajectory will be shown in all 3D areas.
|
||||
When trajectory is red, you can modifiy it by moving object.
|
||||
When trajectory is blue and you want to be able to modify it, inser a Key (I-Key)
|
||||
|
||||
Points appears on trajectory :
|
||||
- Left Clic to modify position
|
||||
- Right Clic to go to the frame it represents
|
||||
|
||||
Notes:<br>
|
||||
In scriptlink mode, it create one script link so make sure that 'Enable Script Link' toogle is on
|
||||
In SpaceHandler mode, you have to go in View>>SpaceHandlerScript menu to activate Trajectory
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2004-2006: Regis Montoya
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
#################################
|
||||
# by 3R - 26/08/05
|
||||
# for any problem :
|
||||
# r3gis@free.fr
|
||||
# ou sur le newsgroup:
|
||||
# http://zoo-logique.org/3D.Blender/
|
||||
#################################
|
||||
#Many thanks to cambo for his fixes
|
||||
#################################
|
||||
|
||||
|
||||
|
||||
import Blender
|
||||
|
||||
|
||||
scene= Blender.Scene.GetCurrent()
|
||||
|
||||
|
||||
#Writing
|
||||
def write_script(name, script):
|
||||
global scene
|
||||
#List texts and their name
|
||||
#write : type of writing : 1->New, 2->Overwrite
|
||||
scripting= None
|
||||
for text in Blender.Text.Get():
|
||||
if text.name==name and text.asLines()[1] != "#"+str(__version__):
|
||||
scripting = text
|
||||
scripting.clear()
|
||||
scripting.write(script)
|
||||
break
|
||||
|
||||
if not scripting:
|
||||
scripting= Blender.Text.New(name)
|
||||
scripting.write(script)
|
||||
|
||||
def link_script(name, type):
|
||||
global scene
|
||||
scriptlinks = scene.getScriptLinks(type) # none or list
|
||||
if not scriptlinks or name not in scriptlinks:
|
||||
scene.addScriptLink(name, type)
|
||||
|
||||
|
||||
#Deleting of a text
|
||||
def text_remove(name):
|
||||
global scene
|
||||
#try to delete text if already linked
|
||||
try:
|
||||
text= Blender.Text.Get(name)
|
||||
# Texte.clear()
|
||||
scene.clearScriptLinks([name])
|
||||
Blender.Text.unlink(text)
|
||||
except:
|
||||
print('---Initialisation of Trajectory_'+str(__version__)+'.py---')
|
||||
|
||||
#Whether is already running, also check if it's the last version of the script : second line contain the version fo the script
|
||||
ask_modif= 0 # Default
|
||||
for text in Blender.Text.Get():
|
||||
if text.name == 'Trajectory' and text.asLines()[1] == "#"+str(__version__):
|
||||
#We ask if script modify his seetings, keep it or stop script
|
||||
ask_modif= Blender.Draw.PupMenu("Script already launch %t|Modify settings%x0|Keep settings%x1|Stop script%x2|")
|
||||
if ask_modif==-1: # user canceled.
|
||||
ask_modif= 1
|
||||
break
|
||||
|
||||
selection_mode= 0
|
||||
future= 35
|
||||
past= 20
|
||||
width= 2
|
||||
|
||||
#In modify case
|
||||
if ask_modif==0:
|
||||
handle_mode= Blender.Draw.Create(0)
|
||||
selection_mode= Blender.Draw.Create(0)
|
||||
future= Blender.Draw.Create(35)
|
||||
past= Blender.Draw.Create(20)
|
||||
width= Blender.Draw.Create(2)
|
||||
|
||||
block= []
|
||||
block.append(("Space Handlers", handle_mode, "You have to activate for each area by View>>SpaceHandler")) #You can delete this option...
|
||||
block.append(("Always Draw", selection_mode, "Selected object will have their trajectory always shown"))
|
||||
block.append(("Past :", past, 1, 900))
|
||||
block.append(("Futur:", future, 1, 900))
|
||||
block.append(("Width:", width, 1,5))
|
||||
|
||||
if not Blender.Draw.PupBlock("Trajectory seetings", block):
|
||||
ask_modif=1
|
||||
|
||||
handle_mode= handle_mode.val
|
||||
selection_mode= selection_mode.val
|
||||
future= future.val
|
||||
past= past.val
|
||||
width= width.val
|
||||
|
||||
|
||||
#put names of selected objects in objects_select if option choosen by user
|
||||
if selection_mode==1:
|
||||
objects_select= [ob.name for ob in scene.objects.context]
|
||||
else:
|
||||
objects_select= []
|
||||
|
||||
|
||||
try:
|
||||
if handle_mode==1:
|
||||
DrawPart="#SPACEHANDLER.VIEW3D.DRAW\n"
|
||||
else:
|
||||
DrawPart="#!BPY\n"
|
||||
except:DrawPart="#BadlyMade"
|
||||
|
||||
|
||||
#Here is the script to write in Blender and to link, options are also written now
|
||||
DrawPart=DrawPart+"#"+str(__version__)+"""
|
||||
#This script is a part of Trajectory.py and have to be linked to the scene in Redraw if not in HANDLER mode.
|
||||
#Author : 3R - Regis Montoya
|
||||
#It's better to use the Trajectory_"version_number".py
|
||||
#You can modify the two following value to change the path settings
|
||||
future="""+str(future)+"""
|
||||
past="""+str(past)+"""
|
||||
object_init_names="""+str(objects_select)+"""
|
||||
|
||||
|
||||
import Blender, math
|
||||
from Blender import BGL, Draw, Ipo
|
||||
from Blender.BGL import *
|
||||
from Blender.Draw import *
|
||||
from math import *
|
||||
|
||||
from Blender.Mathutils import Vector
|
||||
|
||||
#take actual frame
|
||||
frameC=Blender.Get('curframe')
|
||||
scene = Blender.Scene.GetCurrent()
|
||||
render_context=scene.getRenderingContext()
|
||||
#ajust number of frames with NewMap and OldMapvalue values
|
||||
k=1.00*render_context.oldMapValue()/render_context.newMapValue()
|
||||
if k<1:
|
||||
tr=-1*int(log(k*0.1, 10))
|
||||
else:
|
||||
tr=-1*int(log(k, 10))
|
||||
#The real and integer frame to compare to ipos keys frames
|
||||
frameCtr=round(frameC*k, tr)
|
||||
frameCr=frameC*k
|
||||
frameC=int(round(frameC*k, 0))
|
||||
|
||||
|
||||
#List objects that we have to show trajectory in $objects
|
||||
# In this case, using a dict for unique objects is the fastest way.
|
||||
object_dict= dict([(ob.name, ob) for ob in scene.objects.context])
|
||||
for obname in object_init_names:
|
||||
if not object_dict.has_key(obname):
|
||||
try: # Object may be removed.
|
||||
object_dict[obname]= Blender.Object.Get(obname)
|
||||
except:
|
||||
pass # object was removed.
|
||||
|
||||
#This fonction give the resulting matrix of all parents at a given frame
|
||||
#parent_list is the list of all parents [object, matrix, locX_ipo, locY, Z, rotX, Y, Z, sizeX, Y, Z] of current object
|
||||
def matrixForTraj(frame, parent_list):
|
||||
DecMatC=Blender.Mathutils.Matrix([1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1])
|
||||
|
||||
for parent_data in parent_list:
|
||||
parent_ob= parent_data[0]
|
||||
|
||||
try: X= parent_data[5][frame]*pi/18
|
||||
except: X= parent_ob.RotX
|
||||
try: Y= parent_data[6][frame]*pi/18
|
||||
except: Y= parent_ob.RotY
|
||||
try: Z= parent_data[7][frame]*pi/18
|
||||
except: Z= parent_ob.RotZ
|
||||
try: LX= parent_data[2][frame]
|
||||
except: LX= parent_ob.LocX
|
||||
try: LY= parent_data[3][frame]
|
||||
except: LY= parent_ob.LocY
|
||||
try: LZ= parent_data[4][frame]
|
||||
except: LZ= parent_ob.LocZ
|
||||
try: SX= parent_data[8][frame]
|
||||
except: SX= parent_ob.SizeX
|
||||
try: SY= parent_data[9][frame]
|
||||
except: SY= parent_ob.SizeY
|
||||
try: SZ= parent_data[10][frame]
|
||||
except: SZ= parent_ob.SizeZ
|
||||
|
||||
NMat=Blender.Mathutils.Matrix([cos(Y)*cos(Z)*SX,SX*cos(Y)*sin(Z),-SX*sin(Y),0],
|
||||
[(-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],
|
||||
[(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],
|
||||
[LX,LY,LZ,1])
|
||||
DecMatC=DecMatC*parent_data[1]*NMat
|
||||
return DecMatC
|
||||
|
||||
#####
|
||||
TestLIST=[]
|
||||
matview=Blender.Window.GetPerspMatrix()
|
||||
###########
|
||||
#Fonction to draw trajectories
|
||||
###########
|
||||
|
||||
def Trace_Traj(ob):
|
||||
global TestLIST, matview
|
||||
#we draw trajectories for all objects in list
|
||||
|
||||
LocX=[]
|
||||
LocY=[]
|
||||
LocZ=[]
|
||||
#List with trajectories' vertexs
|
||||
vertexX=[]
|
||||
|
||||
contextIpo= ob.ipo
|
||||
if contextIpo:
|
||||
ipoLocX=contextIpo[Ipo.OB_LOCX]
|
||||
ipoLocY=contextIpo[Ipo.OB_LOCY]
|
||||
ipoLocZ=contextIpo[Ipo.OB_LOCZ]
|
||||
ipoTime=contextIpo[Ipo.OB_TIME]
|
||||
else: # only do if there is no IPO (if no ipo curves : return None object and don't go in this except)
|
||||
ipoLocX= ipoLocY= ipoLocZ= ipoTime= None
|
||||
|
||||
if ipoTime:
|
||||
return 0
|
||||
|
||||
#Get all parents of ob
|
||||
parent=ob.parent
|
||||
backup_ob= ob
|
||||
child= ob
|
||||
parent_list= []
|
||||
|
||||
#Get parents's infos :
|
||||
#list of [name, initial matrix at make parent, ipo in X,Y,Z,rotX,rotY,rotZ,sizeX,Y,Z]
|
||||
while parent:
|
||||
Init_Mat=Blender.Mathutils.Matrix(child.getMatrix('worldspace')) #must be done like it (it isn't a matrix otherwise)
|
||||
Init_Mat.invert()
|
||||
Init_Mat=Init_Mat*child.getMatrix('localspace')
|
||||
Init_Mat=parent.getMatrix()*Init_Mat
|
||||
Init_Mat.invert()
|
||||
|
||||
contextIpo= parent.ipo # None or IPO
|
||||
if contextIpo:
|
||||
ipo_Parent_LocX=contextIpo[Ipo.OB_LOCX]
|
||||
ipo_Parent_LocY=contextIpo[Ipo.OB_LOCY]
|
||||
ipo_Parent_LocZ=contextIpo[Ipo.OB_LOCZ]
|
||||
ipo_Parent_RotX=contextIpo[Ipo.OB_ROTX]
|
||||
ipo_Parent_RotY=contextIpo[Ipo.OB_ROTY]
|
||||
ipo_Parent_RotZ=contextIpo[Ipo.OB_ROTZ]
|
||||
ipo_Parent_SizeX=contextIpo[Ipo.OB_SIZEX]
|
||||
ipo_Parent_SizeY=contextIpo[Ipo.OB_SIZEY]
|
||||
ipo_Parent_SizeZ=contextIpo[Ipo.OB_SIZEZ]
|
||||
else:
|
||||
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= None
|
||||
|
||||
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])
|
||||
|
||||
child=parent
|
||||
parent=parent.parent
|
||||
|
||||
#security : if one of parents object are a path>>follow : trajectory don't work properly so it have to draw nothing
|
||||
for parent in parent_list:
|
||||
if parent[0].type == 'Curve':
|
||||
if parent[0].data.flag & 1<<4: # Follow path, 4th bit
|
||||
return 1
|
||||
|
||||
#ob >> re-assign obj and not parent
|
||||
ob= backup_ob
|
||||
ob= backup_ob
|
||||
|
||||
|
||||
if ipoLocX: LXC= ipoLocX[frameC]
|
||||
else: LXC= ob.LocX
|
||||
if ipoLocY: LYC= ipoLocY[frameC]
|
||||
else: LYC= ob.LocY
|
||||
if ipoLocZ: LZC= ipoLocZ[frameC]
|
||||
else: LZC= ob.LocZ
|
||||
|
||||
vect= Vector([ob.LocX, ob.LocY, ob.LocZ, 1])
|
||||
color=[0, 1]
|
||||
|
||||
#If trajectory is being modified and we are at a frame where a ipo key already exist
|
||||
if round(ob.LocX, 5)!=round(LXC, 5):
|
||||
for bez in ipoLocX.bezierPoints:
|
||||
if round(bez.pt[0], tr)==frameCtr:
|
||||
bez.pt = [frameCr, vect[0]]
|
||||
ipoLocX.recalc()
|
||||
if round(ob.LocY, 5)!=round(LYC, 5):
|
||||
for bez in ipoLocY.bezierPoints:
|
||||
if round(bez.pt[0], tr)==frameCtr:
|
||||
bez.pt = [frameCr, vect[1]]
|
||||
ipoLocY.recalc()
|
||||
if round(ob.LocZ, 5)!=round(LZC, 5):
|
||||
for bez in ipoLocZ.bezierPoints:
|
||||
if round(bez.pt[0], tr)==frameCtr:
|
||||
bez.pt = [frameCr, vect[2]]
|
||||
ipoLocZ.recalc()
|
||||
|
||||
#change trajectory color if at an ipoKey
|
||||
VertexFrame=[]
|
||||
bezier_Coord=0
|
||||
if ipoLocX: # FIXED like others it was just in case ipoLocX==None
|
||||
for bez in ipoLocX.bezierPoints:
|
||||
bezier_Coord=round(bez.pt[0], tr)
|
||||
if bezier_Coord not in VertexFrame:
|
||||
VertexFrame.append(bezier_Coord)
|
||||
if bezier_Coord==frameCtr:
|
||||
color=[1, color[1]-0.3]
|
||||
if ipoLocY: # FIXED
|
||||
for bez in ipoLocY.bezierPoints:
|
||||
bezier_Coord=round(bez.pt[0], tr)
|
||||
if bezier_Coord not in VertexFrame:
|
||||
VertexFrame.append(bezier_Coord)
|
||||
if round(bez.pt[0], tr)==frameCtr:
|
||||
color=[1, color[1]-0.3]
|
||||
if ipoLocZ: # FIXED
|
||||
for bez in ipoLocZ.bezierPoints:
|
||||
bezier_Coord=round(bez.pt[0], tr)
|
||||
if bezier_Coord not in VertexFrame:
|
||||
VertexFrame.append(bezier_Coord)
|
||||
if round(bez.pt[0], tr)==frameCtr:
|
||||
color=[1, color[1]-0.3]
|
||||
|
||||
|
||||
#put in LocX, LocY and LocZ all points of trajectory
|
||||
for frame in xrange(frameC-past, frameC+future):
|
||||
DecMat=matrixForTraj(frame, parent_list)
|
||||
|
||||
if ipoLocX: LX= ipoLocX[frame]
|
||||
else: LX= ob.LocX
|
||||
if ipoLocY: LY= ipoLocY[frame]
|
||||
else: LY= ob.LocY
|
||||
if ipoLocZ: LZ= ipoLocZ[frame]
|
||||
else: LZ= ob.LocZ
|
||||
|
||||
vect=Vector(LX, LY, LZ)*DecMat
|
||||
LocX.append(vect[0])
|
||||
LocY.append(vect[1])
|
||||
LocZ.append(vect[2])
|
||||
|
||||
|
||||
#draw part : get current view
|
||||
MatPreBuff= [matview[i][j] for i in xrange(4) for j in xrange(4)]
|
||||
|
||||
MatBuff=BGL.Buffer(GL_FLOAT, 16, MatPreBuff)
|
||||
|
||||
glLoadIdentity()
|
||||
glMatrixMode(GL_PROJECTION)
|
||||
glPushMatrix()
|
||||
glLoadMatrixf(MatBuff)
|
||||
|
||||
#draw trajectory line
|
||||
glLineWidth("""+str(width)+""")
|
||||
|
||||
glBegin(GL_LINE_STRIP)
|
||||
for i in xrange(len(LocX)):
|
||||
glColor3f((i+1)*1.00/len(LocX)*color[0], 0, (i+1)*1.00/len(LocX)*color[1])
|
||||
glVertex3f(LocX[i], LocY[i], LocZ[i])
|
||||
|
||||
glEnd()
|
||||
|
||||
#draw trajectory's "vertexs"
|
||||
if not Blender.Window.EditMode():
|
||||
glPointSize(5)
|
||||
glBegin(GL_POINTS)
|
||||
TestPOINTS=[]
|
||||
TestFRAME=[]
|
||||
i=0
|
||||
for frame in VertexFrame:
|
||||
ix=int(frame)-frameC+past
|
||||
if ix>=0 and ix<len(LocX):
|
||||
glColor3f(1, 0.7, 0.2)
|
||||
glVertex3f(LocX[ix], LocY[ix], LocZ[ix])
|
||||
TestPOINTS.append(Vector([LocX[ix], LocY[ix], LocZ[ix], 1]))
|
||||
TestFRAME.append(int(frame))
|
||||
i+=1
|
||||
glEnd()
|
||||
#this list contains info about where to check if we click over a "vertex" in 3D view
|
||||
TestLIST.append((ob, TestPOINTS, TestFRAME))
|
||||
|
||||
glLineWidth(1)
|
||||
return 0
|
||||
|
||||
|
||||
for ob in object_dict.itervalues():
|
||||
Trace_Traj(ob)
|
||||
|
||||
###########
|
||||
#Fonction to handle trajectories
|
||||
###########
|
||||
|
||||
def Manip():
|
||||
#use TestLIST and matview defined by Trace_Traj
|
||||
global TestLIST, matview
|
||||
for screen in Blender.Window.GetScreenInfo(Blender.Window.Types.VIEW3D):
|
||||
if screen['id']==Blender.Window.GetAreaID():
|
||||
x0, y0, x1, y1= screen['vertices']
|
||||
break
|
||||
|
||||
#Projection of GL matrix in 3D view
|
||||
glPushMatrix()
|
||||
glMatrixMode(GL_PROJECTION)
|
||||
glPushMatrix()
|
||||
glLoadIdentity()
|
||||
#Global coordinates' matrix
|
||||
glOrtho(x0, x1, y0, y1, -1, 0)
|
||||
glMatrixMode(GL_MODELVIEW)
|
||||
glLoadIdentity()
|
||||
#Test mouse clics and other events
|
||||
|
||||
|
||||
if Blender.Window.QTest():
|
||||
evt, val= Blender.Window.QRead()
|
||||
if (evt==LEFTMOUSE or evt==RIGHTMOUSE) and not Blender.Window.EditMode():
|
||||
mouse_co=Blender.Window.GetMouseCoords()
|
||||
#if click on trajectory "vertexs"...
|
||||
for ob, TestPOINTS, TestFRAME in TestLIST: # ob is now used, line 552 to know what object it had to select
|
||||
for k, Vect in enumerate(TestPOINTS):
|
||||
proj=Vect*matview
|
||||
|
||||
pt=[(proj[0]/proj[3])*(x1-x0)/2+(x1+x0)/2, (proj[1]/proj[3])*(y1-y0)/2+(y1+y0)/2]
|
||||
|
||||
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:
|
||||
if evt==LEFTMOUSE:
|
||||
#remember current selected object
|
||||
object_names=[obj.name for obj in Blender.Object.GetSelected()]
|
||||
#this script allow to simulate a GKey, but I have to write a script
|
||||
#another way would made a infinit redraw or don't allow to move object
|
||||
#it auto unlink and delete itself
|
||||
script=\"\"\"
|
||||
import Blender
|
||||
from Blender import Draw, Window
|
||||
from Blender.Window import *
|
||||
from Blender.Draw import *
|
||||
|
||||
from Blender.Mathutils import Vector
|
||||
|
||||
# The following code is a bit of a hack, it allows clicking on the points and dragging directly
|
||||
#It simulate user press GKey
|
||||
#It also set the cursor position at center (because user have previously clic on area and moved the cursor):
|
||||
#And I can't get previous cursor position : redraw appear after it has been moved
|
||||
#If there is no better way you can remove this comments
|
||||
f= GetAreaID()
|
||||
SetCursorPos(0,0,0)
|
||||
#SetKeyQualifiers(1) #FIXED : the bug in older versions seems to have been fixed
|
||||
SetKeyQualifiers(0)
|
||||
QAdd(f, Blender.Draw.GKEY, 1, 0)
|
||||
QHandle(f)
|
||||
Blender.Redraw()
|
||||
done=0
|
||||
while not done:
|
||||
while Blender.Window.QTest():
|
||||
ev=Blender.Window.QRead()[0]
|
||||
if ev not in (4, 5, 18, 112, 213): #all event needed to move object
|
||||
#SetKeyQualifiers(1) #FIXED too, same reason that above
|
||||
#SetKeyQualifiers(0)
|
||||
SetKeyQualifiers(Blender.Window.GetKeyQualifiers())
|
||||
QAdd(f, ev, 1, 0)
|
||||
QHandle(f)
|
||||
Blender.Redraw()
|
||||
if ev in (RIGHTMOUSE, LEFTMOUSE, ESCKEY):
|
||||
done=1
|
||||
Blender.Set('curframe',\"\"\"+str(Blender.Get('curframe'))+\"\"\")
|
||||
Blender.Object.GetSelected()[0].sel= False
|
||||
for obname in \"\"\"+str(object_names)+\"\"\":
|
||||
ob=Blender.Object.Get(obname)
|
||||
ob.sel= True
|
||||
SetCursorPos(0,0,0)
|
||||
scripting=Blender.Text.Get('Edit_Trajectory')
|
||||
scripting.clear()
|
||||
Blender.Text.unlink(scripting)
|
||||
\"\"\"
|
||||
|
||||
#FIXED Edit_Trajectory was longer : all SetKeyQualifiers removed
|
||||
scene=Blender.Scene.GetCurrent()
|
||||
try:
|
||||
scripting=Blender.Text.Get('Edit_Trajectory')
|
||||
scripting.clear()
|
||||
except:
|
||||
scripting=Blender.Text.New('Edit_Trajectory')
|
||||
|
||||
scripting.write(script)
|
||||
#script= scripting #FIXED seems not needed anymore
|
||||
|
||||
#Go to frame that correspond to selected "vertex"
|
||||
Blender.Set('curframe', TestFRAME[k])
|
||||
|
||||
scene.objects.selected = [] #un select all objects
|
||||
|
||||
#FIXED TestLIST[j][0].sel=0, but no j. So ob.sel and above variable changed in obj
|
||||
ob.sel= True
|
||||
Blender.Run('Edit_Trajectory')
|
||||
|
||||
#work well now !!!
|
||||
if evt==RIGHTMOUSE :
|
||||
Blender.Set('curframe', TestFRAME[k])
|
||||
|
||||
Manip()
|
||||
#retrieve a normal matrix
|
||||
glPopMatrix()
|
||||
glMatrixMode(GL_PROJECTION)
|
||||
glPopMatrix()
|
||||
glMatrixMode(GL_MODELVIEW)
|
||||
"""
|
||||
|
||||
if ask_modif==0:
|
||||
text_remove('Trajectory')
|
||||
write_script('Trajectory', DrawPart)
|
||||
if handle_mode==1:
|
||||
Blender.UpdateMenus()
|
||||
else:
|
||||
link_script('Trajectory', 'Redraw')
|
||||
if ask_modif==2:
|
||||
text_remove('Trajectory')
|
||||
print("---End of Trajectory_"+str(__version__)+".py---\n--- Thanks for use ---")
|
||||
325
src_research_readme/blender_2.43_scripts/armature_symmetry.py
Normal file
325
src_research_readme/blender_2.43_scripts/armature_symmetry.py
Normal file
@@ -0,0 +1,325 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Armature Symmetry'
|
||||
Blender: 242
|
||||
Group: 'Armature'
|
||||
Tooltip: 'Make an Armature symmetrical'
|
||||
"""
|
||||
|
||||
__author__ = "Campbell Barton"
|
||||
__url__ = ("blender", "blenderartist")
|
||||
__version__ = "1.0 2006-7-26"
|
||||
|
||||
__doc__ = """\
|
||||
This script creates perfectly symmetrical armatures,
|
||||
based on the best fit when comparing the mirrored locations of 2 bones.
|
||||
Hidden bones are ignored, and optionally only operate on selected bones.
|
||||
"""
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Script copyright (C) Campbell J Barton 2006
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
import bpy
|
||||
Vector= Blender.Mathutils.Vector
|
||||
|
||||
|
||||
def VecXFlip(vec):
|
||||
'''
|
||||
Return a copy of this vector x flipped.
|
||||
'''
|
||||
x,y,z= vec
|
||||
return Vector(-x,y,z)
|
||||
|
||||
def editbone_mirror_diff(editbone1, editbone2):
|
||||
'''
|
||||
X Mirror bone compare
|
||||
return a float representing the difference between the 2 bones
|
||||
the smaller the better the match
|
||||
'''
|
||||
h1= editbone1.head
|
||||
h2= editbone2.head
|
||||
|
||||
t1= editbone1.tail
|
||||
t2= editbone2.tail
|
||||
|
||||
# Mirror bone2's location
|
||||
h2= VecXFlip(h2)
|
||||
t2= VecXFlip(t2)
|
||||
|
||||
#return (h1-h2).length + (t1-t2).length # returns the length only
|
||||
|
||||
# For this function its easier to return the bones also
|
||||
return ((h1-h2).length + (t1-t2).length)/2, editbone1, editbone2
|
||||
|
||||
def editbone_mirror_merge(editbone1, editbone2, PREF_MODE_L2R, PREF_MODE_R2L):
|
||||
'''
|
||||
Merge these 2 bones to their mirrored locations
|
||||
'''
|
||||
h1= editbone1.head
|
||||
h2= editbone2.head
|
||||
|
||||
t1= editbone1.tail
|
||||
t2= editbone2.tail
|
||||
|
||||
if PREF_MODE_L2R and PREF_MODE_R2L:
|
||||
# Median, flip bone2's locations and average, then apply to editbone1, flip and apply to editbone2
|
||||
h2_f= VecXFlip(h2)
|
||||
t2_f= VecXFlip(t2)
|
||||
|
||||
h_med= (h1+h2_f)*0.5 # middle between t1 and flipped t2
|
||||
t_med= (t1+t2_f)*0.5 # middle between h1 and flipped h2
|
||||
|
||||
# Apply the median to editbone1
|
||||
editbone1.head= h_med
|
||||
editbone1.tail= t_med
|
||||
|
||||
# Flip in place for editbone2
|
||||
h_med.x= -h_med.x
|
||||
t_med.x= -t_med.x
|
||||
|
||||
# Apply the median to editbone2
|
||||
editbone2.head= h_med
|
||||
editbone2.tail= t_med
|
||||
|
||||
# Average the roll, this might need some logical work, but looks good for now.
|
||||
r1= editbone1.roll
|
||||
r2= -editbone2.roll
|
||||
# print 'rolls are', r1,r2
|
||||
r_med= (r1+r2)/2
|
||||
# print 'new roll is', r_med
|
||||
editbone1.roll= r_med
|
||||
editbone2.roll= -r_med # mirror roll
|
||||
|
||||
else: # Copy from 1 side to another
|
||||
|
||||
# Crafty function we can use so L>R and R>L can use the same code
|
||||
def IS_XMIRROR_SOURCE(xval):
|
||||
'''Source means is this the value we want to copy from'''
|
||||
|
||||
if PREF_MODE_L2R:
|
||||
if xval<0: return True
|
||||
else: return False
|
||||
else: # PREF_MODE_R2L
|
||||
if xval<0: return False
|
||||
else: return True
|
||||
|
||||
if IS_XMIRROR_SOURCE( h1.x ):# head bone 1s negative, so copy it to h2
|
||||
editbone2.head= VecXFlip(h1)
|
||||
else:
|
||||
'''
|
||||
assume h2.x<0 - not a big deal if were wrong,
|
||||
its unlikely to ever happen because the bones would both be on the same side.
|
||||
'''
|
||||
|
||||
# head bone 2s negative, so copy it to h1
|
||||
editbone1.head= VecXFlip(h2)
|
||||
|
||||
# Same as above for tail
|
||||
if IS_XMIRROR_SOURCE(t1.x):
|
||||
editbone2.tail= VecXFlip(t1)
|
||||
else:
|
||||
editbone1.tail= VecXFlip(t2)
|
||||
|
||||
# Copy roll from 1 bone to another, use the head's location to decide which side it's on.
|
||||
if IS_XMIRROR_SOURCE(editbone1.head):
|
||||
editbone2.roll= -editbone1.roll
|
||||
else:
|
||||
editbone1.roll= -editbone2.roll
|
||||
|
||||
|
||||
def armature_symetry(\
|
||||
arm_ob,\
|
||||
PREF_MAX_DIST,\
|
||||
PREF_XMID_SNAP,\
|
||||
PREF_XZERO_THRESH,\
|
||||
PREF_MODE_L2R,\
|
||||
PREF_MODE_R2L,\
|
||||
PREF_SEL_ONLY):
|
||||
|
||||
'''
|
||||
Main function that does all the work,
|
||||
return the number of
|
||||
'''
|
||||
arm_data= arm_ob.data
|
||||
arm_data.makeEditable()
|
||||
|
||||
# Get the bones
|
||||
bones= []
|
||||
HIDDEN_EDIT= Blender.Armature.HIDDEN_EDIT
|
||||
BONE_SELECTED= Blender.Armature.BONE_SELECTED
|
||||
|
||||
if PREF_SEL_ONLY:
|
||||
for eb in arm_data.bones.values():
|
||||
options= eb.options
|
||||
if HIDDEN_EDIT not in options and BONE_SELECTED in options:
|
||||
bones.append(eb)
|
||||
else:
|
||||
# All non hidden bones
|
||||
for eb in arm_data.bones.values():
|
||||
options= eb.options
|
||||
if HIDDEN_EDIT not in options:
|
||||
bones.append(eb)
|
||||
|
||||
del HIDDEN_EDIT # remove temp variables
|
||||
del BONE_SELECTED
|
||||
|
||||
# Store the numder of bones we have modified for a message
|
||||
tot_editbones= len(bones)
|
||||
tot_editbones_modified= 0
|
||||
|
||||
if PREF_XMID_SNAP:
|
||||
# Remove bones that are in the middle (X Zero)
|
||||
# reverse loop so we can remove items in the list.
|
||||
for eb_idx in xrange(len(bones)-1, -1, -1):
|
||||
edit_bone= bones[eb_idx]
|
||||
if abs(edit_bone.head.x) + abs(edit_bone.tail.x) <= PREF_XZERO_THRESH/2:
|
||||
|
||||
# This is a center bone, clamp and remove from the bone list so we dont use again.
|
||||
if edit_bone.tail.x or edit_bone.head.x:
|
||||
tot_editbones_modified += 1
|
||||
|
||||
edit_bone.tail.x= edit_bone.head.x= 0
|
||||
del bones[eb_idx]
|
||||
|
||||
|
||||
|
||||
|
||||
bone_comparisons= []
|
||||
|
||||
# Compare every bone with every other bone, shouldn't be too slow.
|
||||
# These 2 "for" loops only compare once
|
||||
for eb_idx_a in xrange(len(bones)-1, -1, -1):
|
||||
edit_bone_a= bones[eb_idx_a]
|
||||
for eb_idx_b in xrange(eb_idx_a-1, -1, -1):
|
||||
edit_bone_b= bones[eb_idx_b]
|
||||
# Error float the first value from editbone_mirror_diff() so we can sort the resulting list.
|
||||
bone_comparisons.append(editbone_mirror_diff(edit_bone_a, edit_bone_b))
|
||||
|
||||
|
||||
bone_comparisons.sort() # best matches first
|
||||
|
||||
# Make a dict() of bone names that have been used so we dont mirror more then once
|
||||
bone_mirrored= {}
|
||||
|
||||
for error, editbone1, editbone2 in bone_comparisons:
|
||||
# print 'Trying to merge at error %.3f' % error
|
||||
if error > PREF_MAX_DIST:
|
||||
# print 'breaking, max error limit reached PREF_MAX_DIST: %.3f' % PREF_MAX_DIST
|
||||
break
|
||||
|
||||
if not bone_mirrored.has_key(editbone1.name) and not bone_mirrored.has_key(editbone2.name):
|
||||
# Were not used, execute the mirror
|
||||
editbone_mirror_merge(editbone1, editbone2, PREF_MODE_L2R, PREF_MODE_R2L)
|
||||
# print 'Merging bones'
|
||||
|
||||
# Add ourselves so we aren't touched again
|
||||
bone_mirrored[editbone1.name] = None # dummy value, would use sets in python 2.4
|
||||
bone_mirrored[editbone2.name] = None
|
||||
|
||||
# If both options are enabled, then we have changed 2 bones
|
||||
tot_editbones_modified+= PREF_MODE_L2R + PREF_MODE_R2L
|
||||
|
||||
arm_data.update() # get out of armature editmode
|
||||
return tot_editbones, tot_editbones_modified
|
||||
|
||||
|
||||
def main():
|
||||
'''
|
||||
User interface function that gets the options and calls armature_symetry()
|
||||
'''
|
||||
|
||||
scn= bpy.data.scenes.active
|
||||
arm_ob= scn.objects.active
|
||||
|
||||
if not arm_ob or arm_ob.type!='Armature':
|
||||
Blender.Draw.PupMenu('No Armature object selected.')
|
||||
return
|
||||
|
||||
# Cant be in editmode for armature.makeEditable()
|
||||
is_editmode= Blender.Window.EditMode()
|
||||
if is_editmode: Blender.Window.EditMode(0)
|
||||
Draw= Blender.Draw
|
||||
|
||||
# Defaults for the user input
|
||||
PREF_XMID_SNAP= Draw.Create(1)
|
||||
PREF_MAX_DIST= Draw.Create(0.4)
|
||||
PREF_XZERO_THRESH= Draw.Create(0.02)
|
||||
|
||||
PREF_MODE_L2R= Draw.Create(1)
|
||||
PREF_MODE_R2L= Draw.Create(0)
|
||||
PREF_SEL_ONLY= Draw.Create(1)
|
||||
|
||||
pup_block = [\
|
||||
'Left (-), Right (+)',\
|
||||
('Left > Right', PREF_MODE_L2R, 'Copy from the Left to Right of the mesh. Enable Both for a mid loc.'),\
|
||||
('Right > Left', PREF_MODE_R2L, 'Copy from the Right to Left of the mesh. Enable Both for a mid loc.'),\
|
||||
'',\
|
||||
('MaxDist:', PREF_MAX_DIST, 0.0, 4.0, 'Maximum difference in mirror bones to match up pairs.'),\
|
||||
('XZero limit:', PREF_XZERO_THRESH, 0.0, 2.0, 'Tolerance for locking bones into the middle (X/zero).'),\
|
||||
('XMidSnap Bones', PREF_XMID_SNAP, 'Snap middle verts to X Zero (uses XZero limit)'),\
|
||||
('Selected Only', PREF_SEL_ONLY, 'Only xmirror selected bones.'),\
|
||||
]
|
||||
|
||||
# Popup, exit if the user doesn't click OK
|
||||
if not Draw.PupBlock("X Mirror mesh tool", pup_block):
|
||||
return
|
||||
|
||||
# Replace the variables with their button values.
|
||||
PREF_XMID_SNAP= PREF_XMID_SNAP.val
|
||||
PREF_MAX_DIST= PREF_MAX_DIST.val
|
||||
PREF_MODE_L2R= PREF_MODE_L2R.val
|
||||
PREF_MODE_R2L= PREF_MODE_R2L.val
|
||||
PREF_XZERO_THRESH= PREF_XZERO_THRESH.val
|
||||
PREF_SEL_ONLY= PREF_SEL_ONLY.val
|
||||
|
||||
# If both are off assume mid-point and enable both
|
||||
if not PREF_MODE_R2L and not PREF_MODE_L2R:
|
||||
PREF_MODE_R2L= PREF_MODE_L2R= True
|
||||
|
||||
|
||||
tot_editbones, tot_editbones_modified = armature_symetry(\
|
||||
arm_ob,\
|
||||
PREF_MAX_DIST,\
|
||||
PREF_XMID_SNAP,\
|
||||
PREF_XZERO_THRESH,\
|
||||
PREF_MODE_L2R,\
|
||||
PREF_MODE_R2L,\
|
||||
PREF_SEL_ONLY)
|
||||
|
||||
if is_editmode: Blender.Window.EditMode(1)
|
||||
|
||||
# Redraw all views before popup
|
||||
Blender.Window.RedrawAll()
|
||||
|
||||
# Print results
|
||||
if PREF_SEL_ONLY:
|
||||
msg= 'moved %i bones of %i selected' % (tot_editbones_modified, tot_editbones)
|
||||
else:
|
||||
msg= 'moved %i bones of %i visible' % (tot_editbones_modified, tot_editbones)
|
||||
|
||||
|
||||
Blender.Draw.PupMenu(msg)
|
||||
|
||||
# Check for __main__ so this function can be imported by other scripts without running the script.
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
474
src_research_readme/blender_2.43_scripts/bevel_center.py
Normal file
474
src_research_readme/blender_2.43_scripts/bevel_center.py
Normal file
@@ -0,0 +1,474 @@
|
||||
#!BPY
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Registration info for Blender menus
|
||||
Name: 'Bevel Center'
|
||||
Blender: 243
|
||||
Group: 'Mesh'
|
||||
Tip: 'Bevel selected faces, edges, and vertices'
|
||||
"""
|
||||
|
||||
__author__ = "Loic BERTHE"
|
||||
__url__ = ("blender", "blenderartists.org")
|
||||
__version__ = "2.0"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script implements vertex and edges bevelling in Blender.
|
||||
|
||||
Usage:
|
||||
|
||||
Select the mesh you want to work on, enter Edit Mode and select the edges
|
||||
to bevel. Then run this script from the 3d View's Mesh->Scripts menu.
|
||||
|
||||
You can control the thickness of the bevel with the slider -- redefine the
|
||||
end points for bigger or smaller ranges. The thickness can be changed even
|
||||
after applying the bevel, as many times as needed.
|
||||
|
||||
For an extra smoothing after or instead of direct bevel, set the level of
|
||||
recursiveness and use the "Recursive" button.
|
||||
|
||||
This "Recursive" Button, won't work in face select mode, unless you choose
|
||||
"faces" in the select mode menu.
|
||||
|
||||
Notes:<br>
|
||||
You can undo and redo your steps just like with normal mesh operations in
|
||||
Blender.
|
||||
"""
|
||||
|
||||
######################################################################
|
||||
# Bevel Center v2.0 for Blender
|
||||
|
||||
# This script lets you bevel the selected vertices or edges and control the
|
||||
# thickness of the bevel
|
||||
|
||||
# (c) 2004-2006 Loรฏc Berthe (loic+blender@lilotux.net)
|
||||
# released under Blender Artistic License
|
||||
|
||||
######################################################################
|
||||
|
||||
import Blender
|
||||
from Blender import NMesh, Window, Scene
|
||||
from Blender.Draw import *
|
||||
from Blender.Mathutils import *
|
||||
from Blender.BGL import *
|
||||
import BPyMessages
|
||||
#PY23 NO SETS#
|
||||
'''
|
||||
try:
|
||||
set()
|
||||
except:
|
||||
from sets import set
|
||||
'''
|
||||
|
||||
######################################################################
|
||||
# Functions to handle the global structures of the script NF, NE and NC
|
||||
# which contain informations about faces and corners to be created
|
||||
|
||||
global E_selected
|
||||
E_selected = NMesh.EdgeFlags['SELECT']
|
||||
|
||||
old_dist = None
|
||||
|
||||
def act_mesh_ob():
|
||||
scn = Scene.GetCurrent()
|
||||
ob = scn.objects.active
|
||||
if ob == None or ob.type != 'Mesh':
|
||||
BPyMessages.Error_NoMeshActive()
|
||||
return
|
||||
|
||||
if ob.getData(mesh=1).multires:
|
||||
BPyMessages.Error_NoMeshMultiresEdit()
|
||||
return
|
||||
|
||||
return ob
|
||||
|
||||
def make_sel_vert(*co):
|
||||
v= NMesh.Vert(*co)
|
||||
v.sel = 1
|
||||
me.verts.append(v)
|
||||
return v
|
||||
|
||||
def make_sel_face(verts):
|
||||
f = NMesh.Face(verts)
|
||||
f.sel = 1
|
||||
me.addFace(f)
|
||||
|
||||
def add_to_NV(old,dir,new):
|
||||
try:
|
||||
NV[old][dir] = new
|
||||
except:
|
||||
NV[old] = {dir:new}
|
||||
|
||||
def get_v(old, *neighbors):
|
||||
# compute the direction of the new vert
|
||||
if len(neighbors) == 1: dir = (neighbors[0].co - old.co).normalize()
|
||||
#dir
|
||||
else: dir = (neighbors[0].co - old.co).normalize() + (neighbors[1].co-old.co).normalize()
|
||||
|
||||
# look in NV if this vert already exists
|
||||
key = tuple(dir)
|
||||
if old in NV and key in NV[old] : return NV[old][key]
|
||||
|
||||
# else, create it
|
||||
new = old.co + dist.val*dir
|
||||
v = make_sel_vert(new.x,new.y,new.z)
|
||||
add_to_NV(old,key,v)
|
||||
return v
|
||||
|
||||
def make_faces():
|
||||
""" Analyse the mesh, make the faces corresponding to selected faces and
|
||||
fill the structures NE and NC """
|
||||
|
||||
# make the differents flags consistent
|
||||
for e in me.edges:
|
||||
if e.flag & E_selected :
|
||||
e.v1.sel = 1
|
||||
e.v2.sel = 1
|
||||
|
||||
NF =[] # NF : New faces
|
||||
for f in me.faces:
|
||||
V = f.v
|
||||
nV = len(V)
|
||||
enumV = range(nV)
|
||||
E = [me.findEdge(V[i],V[(i+1) % nV]) for i in enumV]
|
||||
Esel = [x.flag & E_selected for x in E]
|
||||
|
||||
# look for selected vertices and creates a list containing the new vertices
|
||||
newV = V[:]
|
||||
changes = False
|
||||
for (i,v) in enumerate(V):
|
||||
if v.sel :
|
||||
changes = True
|
||||
if Esel[i-1] == 0 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1])
|
||||
elif Esel[i-1] == 1 and Esel[i] == 0 : newV[i] = get_v(v,V[(i+1) % nV])
|
||||
elif Esel[i-1] == 1 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1],V[(i+1) % nV])
|
||||
else : newV[i] = [get_v(v,V[i-1]),get_v(v,V[(i+1) % nV])]
|
||||
|
||||
if changes:
|
||||
# determine and store the face to be created
|
||||
|
||||
lenV = [len(x) for x in newV]
|
||||
if 2 not in lenV :
|
||||
new_f = NMesh.Face(newV)
|
||||
if sum(Esel) == nV : new_f.sel = 1
|
||||
NF.append(new_f)
|
||||
|
||||
else :
|
||||
nb2 = lenV.count(2)
|
||||
|
||||
if nV == 4 : # f is a quad
|
||||
if nb2 == 1 :
|
||||
ind2 = lenV.index(2)
|
||||
NF.append(NMesh.Face([newV[ind2-1],newV[ind2][0],newV[ind2][1],newV[ind2-3]]))
|
||||
NF.append(NMesh.Face([newV[ind2-1],newV[ind2-2],newV[ind2-3]]))
|
||||
|
||||
elif nb2 == 2 :
|
||||
# We must know if the tuples are neighbours
|
||||
ind2 = ''.join([str(x) for x in lenV+lenV[:1]]).find('22')
|
||||
|
||||
if ind2 != -1 : # They are
|
||||
NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-3][0],newV[ind2-3][1]]))
|
||||
NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2],newV[ind2-3][1]]))
|
||||
|
||||
else: # They aren't
|
||||
ind2 = lenV.index(2)
|
||||
NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-2][0],newV[ind2-2][1]]))
|
||||
NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3],newV[ind2-2][0]]))
|
||||
NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2][1]]))
|
||||
|
||||
elif nb2 == 3 :
|
||||
ind2 = lenV.index(3)
|
||||
NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-3][0]]))
|
||||
NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2-3][0],newV[ind2-3][1]]))
|
||||
NF.append(NMesh.Face([newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0]]))
|
||||
|
||||
else:
|
||||
if (newV[0][1].co-newV[3][0].co).length + (newV[1][0].co-newV[2][1].co).length \
|
||||
< (newV[0][0].co-newV[1][1].co).length + (newV[2][0].co-newV[3][1].co).length :
|
||||
ind2 = 0
|
||||
else :
|
||||
ind2 = 1
|
||||
NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2][0],newV[ind2][1]]))
|
||||
NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3][0],newV[ind2-2][1],newV[ind2-1][0]]))
|
||||
NF.append(NMesh.Face([newV[ind2-3][0],newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1]]))
|
||||
|
||||
else : # f is a tri
|
||||
if nb2 == 1:
|
||||
ind2 = lenV.index(2)
|
||||
NF.append(NMesh.Face([newV[ind2-2],newV[ind2-1],newV[ind2][0],newV[ind2][1]]))
|
||||
|
||||
elif nb2 == 2:
|
||||
ind2 = lenV.index(3)
|
||||
NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-2][0]]))
|
||||
NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]]))
|
||||
|
||||
else:
|
||||
ind2 = min( [((newV[i][1].co-newV[i-1][0].co).length, i) for i in enumV] )[1]
|
||||
NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2][0],newV[ind2][1],newV[ind2-2][0]]))
|
||||
NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]]))
|
||||
|
||||
# Preparing the corners
|
||||
for i in enumV:
|
||||
if lenV[i] == 2 : NC.setdefault(V[i],[]).append(newV[i])
|
||||
|
||||
|
||||
old_faces.append(f)
|
||||
|
||||
# Preparing the Edges
|
||||
for i in enumV:
|
||||
if Esel[i]:
|
||||
verts = [newV[i],newV[(i+1) % nV]]
|
||||
if V[i].index > V[(i+1) % nV].index : verts.reverse()
|
||||
NE.setdefault(E[i],[]).append(verts)
|
||||
|
||||
# Create the faces
|
||||
for f in NF: me.addFace(f)
|
||||
|
||||
def make_edges():
|
||||
""" Make the faces corresponding to selected edges """
|
||||
|
||||
for old,new in NE.iteritems() :
|
||||
if len(new) == 1 : # This edge was on a border
|
||||
oldv = [old.v1, old.v2]
|
||||
if old.v1.index < old.v2.index : oldv.reverse()
|
||||
|
||||
make_sel_face(oldv+new[0])
|
||||
|
||||
me.findEdge(*oldv).flag |= E_selected
|
||||
me.findEdge(*new[0]).flag |= E_selected
|
||||
|
||||
#PY23 NO SETS# for v in oldv : NV_ext.add(v)
|
||||
for v in oldv : NV_ext[v]= None
|
||||
|
||||
else:
|
||||
make_sel_face(new[0] + new[1][::-1])
|
||||
|
||||
me.findEdge(*new[0]).flag |= E_selected
|
||||
me.findEdge(*new[1]).flag |= E_selected
|
||||
|
||||
def make_corners():
|
||||
""" Make the faces corresponding to corners """
|
||||
|
||||
for v in NV.iterkeys():
|
||||
V = NV[v].values()
|
||||
nV = len(V)
|
||||
|
||||
if nV == 1: pass
|
||||
|
||||
elif nV == 2 :
|
||||
#PY23 NO SETS# if v in NV_ext:
|
||||
if v in NV_ext.iterkeys():
|
||||
make_sel_face(V+[v])
|
||||
me.findEdge(*V).flag |= E_selected
|
||||
|
||||
else:
|
||||
#PY23 NO SETS# if nV == 3 and v not in NV_ext : make_sel_face(V)
|
||||
if nV == 3 and v not in NV_ext.iterkeys() : make_sel_face(V)
|
||||
|
||||
|
||||
else :
|
||||
|
||||
# We need to know which are the edges around the corner.
|
||||
# First, we look for the quads surrounding the corner.
|
||||
eed = []
|
||||
for old, new in NE.iteritems():
|
||||
if v in (old.v1,old.v2) :
|
||||
if v.index == min(old.v1.index,old.v2.index) : ind = 0
|
||||
else : ind = 1
|
||||
|
||||
if len(new) == 1: eed.append([v,new[0][ind]])
|
||||
else : eed.append([new[0][ind],new[1][ind]])
|
||||
|
||||
# We will add the edges coming from faces where only one vertice is selected.
|
||||
# They are stored in NC.
|
||||
if v in NC: eed = eed+NC[v]
|
||||
|
||||
# Now we have to sort these vertices
|
||||
hc = {}
|
||||
for (a,b) in eed :
|
||||
hc.setdefault(a,[]).append(b)
|
||||
hc.setdefault(b,[]).append(a)
|
||||
|
||||
for x0,edges in hc.iteritems():
|
||||
if len(edges) == 1 : break
|
||||
|
||||
b = [x0] # b will contain the sorted list of vertices
|
||||
|
||||
for i in xrange(len(hc)-1):
|
||||
for x in hc[x0] :
|
||||
if x not in b : break
|
||||
b.append(x)
|
||||
x0 = x
|
||||
|
||||
b.append(b[0])
|
||||
|
||||
# Now we can create the faces
|
||||
if len(b) == 5: make_sel_face(b[:4])
|
||||
|
||||
else:
|
||||
New_V = Vector(0.0, 0.0,0.0)
|
||||
New_d = [0.0, 0.0,0.0]
|
||||
|
||||
for x in hc.iterkeys(): New_V += x.co
|
||||
for dir in NV[v] :
|
||||
for i in xrange(3): New_d[i] += dir[i]
|
||||
|
||||
New_V *= 1./len(hc)
|
||||
for i in xrange(3) : New_d[i] /= nV
|
||||
|
||||
center = make_sel_vert(New_V.x,New_V.y,New_V.z)
|
||||
add_to_NV(v,tuple(New_d),center)
|
||||
|
||||
for k in xrange(len(b)-1): make_sel_face([center, b[k], b[k+1]])
|
||||
|
||||
if 2 < nV and v in NC :
|
||||
for edge in NC[v] : me.findEdge(*edge).flag |= E_selected
|
||||
|
||||
def clear_old():
|
||||
""" Erase old faces and vertices """
|
||||
|
||||
for f in old_faces: me.removeFace(f)
|
||||
|
||||
for v in NV.iterkeys():
|
||||
#PY23 NO SETS# if v not in NV_ext : me.verts.remove(v)
|
||||
if v not in NV_ext.iterkeys() : me.verts.remove(v)
|
||||
|
||||
for e in me.edges:
|
||||
if e.flag & E_selected :
|
||||
e.v1.sel = 1
|
||||
e.v2.sel = 1
|
||||
|
||||
|
||||
######################################################################
|
||||
# Interface
|
||||
|
||||
global dist
|
||||
|
||||
dist = Create(0.2)
|
||||
left = Create(0.0)
|
||||
right = Create(1.0)
|
||||
num = Create(2)
|
||||
|
||||
# Events
|
||||
EVENT_NOEVENT = 1
|
||||
EVENT_BEVEL = 2
|
||||
EVENT_UPDATE = 3
|
||||
EVENT_RECURS = 4
|
||||
EVENT_EXIT = 5
|
||||
|
||||
def draw():
|
||||
global dist, left, right, num, old_dist
|
||||
global EVENT_NOEVENT, EVENT_BEVEL, EVENT_UPDATE, EVENT_RECURS, EVENT_EXIT
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
Button("Bevel",EVENT_BEVEL,10,100,280,25)
|
||||
|
||||
BeginAlign()
|
||||
left=Number('', EVENT_NOEVENT,10,70,45, 20,left.val,0,right.val,'Set the minimum of the slider')
|
||||
dist=Slider("Thickness ",EVENT_UPDATE,60,70,180,20,dist.val,left.val,right.val,0, \
|
||||
"Thickness of the bevel, can be changed even after bevelling")
|
||||
right = Number("",EVENT_NOEVENT,245,70,45,20,right.val,left.val,200,"Set the maximum of the slider")
|
||||
|
||||
EndAlign()
|
||||
glRasterPos2d(8,40)
|
||||
Text('To finish, you can use recursive bevel to smooth it')
|
||||
|
||||
|
||||
if old_dist != None:
|
||||
num=Number('', EVENT_NOEVENT,10,10,40, 16,num.val,1,100,'Recursion level')
|
||||
Button("Recursive",EVENT_RECURS,55,10,100,16)
|
||||
|
||||
Button("Exit",EVENT_EXIT,210,10,80,20)
|
||||
|
||||
def event(evt, val):
|
||||
if ((evt == QKEY or evt == ESCKEY) and not val): Exit()
|
||||
|
||||
def bevent(evt):
|
||||
if evt == EVENT_EXIT : Exit()
|
||||
elif evt == EVENT_BEVEL : bevel()
|
||||
elif evt == EVENT_UPDATE :
|
||||
try: bevel_update()
|
||||
except NameError : pass
|
||||
elif evt == EVENT_RECURS : recursive()
|
||||
|
||||
Register(draw, event, bevent)
|
||||
|
||||
######################################################################
|
||||
def bevel():
|
||||
""" The main function, which creates the bevel """
|
||||
global me,NV,NV_ext,NE,NC, old_faces,old_dist
|
||||
|
||||
ob = act_mesh_ob()
|
||||
if not ob: return
|
||||
|
||||
Window.WaitCursor(1) # Change the Cursor
|
||||
t= Blender.sys.time()
|
||||
is_editmode = Window.EditMode()
|
||||
if is_editmode: Window.EditMode(0)
|
||||
|
||||
me = ob.data
|
||||
|
||||
NV = {}
|
||||
#PY23 NO SETS# NV_ext = set()
|
||||
NV_ext= {}
|
||||
NE = {}
|
||||
NC = {}
|
||||
old_faces = []
|
||||
|
||||
make_faces()
|
||||
make_edges()
|
||||
make_corners()
|
||||
clear_old()
|
||||
|
||||
old_dist = dist.val
|
||||
print '\tbevel in %.6f sec' % (Blender.sys.time()-t)
|
||||
me.update(1)
|
||||
if is_editmode: Window.EditMode(1)
|
||||
Window.WaitCursor(0)
|
||||
Blender.Redraw()
|
||||
|
||||
def bevel_update():
|
||||
""" Use NV to update the bevel """
|
||||
global dist, old_dist
|
||||
|
||||
if old_dist == None:
|
||||
# PupMenu('Error%t|Must bevel first.')
|
||||
return
|
||||
|
||||
is_editmode = Window.EditMode()
|
||||
if is_editmode: Window.EditMode(0)
|
||||
|
||||
fac = dist.val - old_dist
|
||||
old_dist = dist.val
|
||||
|
||||
for old_v in NV.iterkeys():
|
||||
for dir in NV[old_v].iterkeys():
|
||||
for i in xrange(3):
|
||||
NV[old_v][dir].co[i] += fac*dir[i]
|
||||
|
||||
me.update(1)
|
||||
if is_editmode: Window.EditMode(1)
|
||||
Blender.Redraw()
|
||||
|
||||
def recursive():
|
||||
""" Make a recursive bevel... still experimental """
|
||||
global dist
|
||||
from math import pi, sin
|
||||
|
||||
if num.val > 1:
|
||||
a = pi/4
|
||||
ang = []
|
||||
for k in xrange(num.val):
|
||||
ang.append(a)
|
||||
a = (pi+2*a)/4
|
||||
|
||||
l = [2*(1-sin(x))/sin(2*x) for x in ang]
|
||||
R = dist.val/sum(l)
|
||||
l = [x*R for x in l]
|
||||
|
||||
dist.val = l[0]
|
||||
bevel_update()
|
||||
|
||||
for x in l[1:]:
|
||||
dist.val = x
|
||||
bevel()
|
||||
|
||||
729
src_research_readme/blender_2.43_scripts/blenderLipSynchro.py
Normal file
729
src_research_readme/blender_2.43_scripts/blenderLipSynchro.py
Normal file
@@ -0,0 +1,729 @@
|
||||
#!BPY
|
||||
# coding: utf-8
|
||||
"""
|
||||
Name: 'BlenderLipSynchro'
|
||||
Blender: 242
|
||||
Group: 'Animation'
|
||||
Tooltip: 'Import phonemes from Papagayo or JLipSync for lip synchronization'
|
||||
"""
|
||||
|
||||
__author__ = "Dienben: Benoit Foucque dienben_mail@yahoo.fr"
|
||||
__url__ = ["blenderLipSynchro Blog, http://blenderlipsynchro.blogspot.com/",
|
||||
"Papagayo (Python), http://www.lostmarble.com/papagayo/index.shtml",
|
||||
"JLipSync (Java), http://jlipsync.sourceforge.net/"]
|
||||
__version__ = "2.0"
|
||||
__bpydoc__ = """\
|
||||
Description:
|
||||
|
||||
This script imports Voice Export made by Papagayo or JLipSync and maps the export with your shapes.
|
||||
|
||||
Usage:
|
||||
|
||||
Import a Papagayo or JLipSync voice export file and link it with your shapes.
|
||||
|
||||
Note:<br>
|
||||
- Naturally, you need files exported from one of the supported lip synching
|
||||
programs. Check their sites to learn more and download them.
|
||||
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# BlenderLipSynchro
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#il y a 3 etapes
|
||||
#la deuxieme on charge le dictionnaire de correspondance
|
||||
#la troisieme on fait le choix des correpondance
|
||||
#la quatrieme on construit les cles a partir du fichiers frame
|
||||
|
||||
#there are 3 stages
|
||||
#the second one load the mapping dictionnary
|
||||
#the tird make the mapping
|
||||
#the fourth make the key in the IPO Curve
|
||||
|
||||
#voici mes differents imports
|
||||
#the imports
|
||||
import os
|
||||
import Blender
|
||||
|
||||
from Blender import Ipo
|
||||
from Blender.Draw import *
|
||||
from Blender.BGL import *
|
||||
from Blender.sys import basename
|
||||
|
||||
|
||||
|
||||
#ici commencent mes fonctions
|
||||
#here begin my functions
|
||||
#cette fonction trace l'interface graphique
|
||||
#this functions draw the User interface
|
||||
def trace():
|
||||
#voici mes variables pouvant etre modifie
|
||||
#my variables
|
||||
global nbr_phoneme, mon_fichier_dico
|
||||
global let01, let02, let03, let04,let05, let06, let07, let08, let09, let10
|
||||
global let11, let12, let13, let14,let15, let16, let17, let18, let19, let20
|
||||
global let21, let22, let23, let24
|
||||
|
||||
global let01selectkey,let02selectkey,let03selectkey,let04selectkey,let05selectkey
|
||||
global let06selectkey,let07selectkey,let08selectkey,let09selectkey,let10selectkey,let11selectkey
|
||||
global let12selectkey,let13selectkey,let14selectkey,let15selectkey,let16selectkey,let17selectkey
|
||||
global let18selectkey,let19selectkey,let20selectkey,let21selectkey,let22selectkey,let23selectkey
|
||||
global let24selectkey
|
||||
|
||||
glClearColor(0.4,0.5,0.6 ,0.0)
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(87, 375)
|
||||
Text("Blendersynchro V 2.0")
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(84, 360)
|
||||
Text("Programming: Dienben")
|
||||
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(13, 342)
|
||||
Text("Lip Synchronization Tool")
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(13, 326)
|
||||
Text("Thanks to Chris Clawson and Liubomir Kovatchev")
|
||||
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(5, 320)
|
||||
Text("_______________________________________________________")
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(6, 318)
|
||||
Text("_______________________________________________________")
|
||||
|
||||
|
||||
if (etape==1):
|
||||
#cette etape permet de choisi la correspondance entre les phonemes et les cles
|
||||
#this stage offer the possibility to choose the mapping between phonems and shapes
|
||||
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(140, 300)
|
||||
Text("Objet: "+Blender.Object.GetSelected()[0].getName() )
|
||||
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(5, 215)
|
||||
Text("Assign phonems to shapes:")
|
||||
|
||||
#on mesure la taille de la liste de phonemes
|
||||
#this is the lenght of the phonem list
|
||||
nbr_phoneme=len(liste_phoneme)
|
||||
|
||||
#on dessine les listes de choix
|
||||
#we draw the choice list
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 0):
|
||||
let01 = String(" ", 4, 5, 185, 30, 16, liste_phoneme[0], 3)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 188)
|
||||
Text("=")
|
||||
let01selectkey = Menu(key_menu, 50, 50, 185, 70, 16, let01selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 1):
|
||||
let02 = String(" ", 4, 150, 185, 30, 16, liste_phoneme[1], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 188)
|
||||
Text("=")
|
||||
let02selectkey = Menu(key_menu, 51, 195, 185, 70, 16, let02selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 2):
|
||||
let03 = String(" ", 4, 5, 165, 30, 16, liste_phoneme[2], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 168)
|
||||
Text("=")
|
||||
let03selectkey = Menu(key_menu, 52, 50, 165, 70, 16, let03selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 3):
|
||||
let04 = String(" ", 4, 150, 165, 30, 16, liste_phoneme[3], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 168)
|
||||
Text("=")
|
||||
let04selectkey = Menu(key_menu, 53, 195, 165, 70, 16, let04selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 4):
|
||||
let05 = String(" ", 4, 5, 145, 30, 16, liste_phoneme[4], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 148)
|
||||
Text("=")
|
||||
let05selectkey = Menu(key_menu, 54, 50, 145, 70, 16, let05selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 5):
|
||||
let06 = String(" ", 4, 150, 145, 30, 16, liste_phoneme[5], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 148)
|
||||
Text("=")
|
||||
let06selectkey = Menu(key_menu, 55, 195, 145, 70, 16, let06selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 6):
|
||||
let07 = String(" ", 4, 5, 125, 30, 16, liste_phoneme[6], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 128)
|
||||
Text("=")
|
||||
let07selectkey = Menu(key_menu, 56, 50, 125, 70, 16, let07selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 7):
|
||||
let08 = String(" ", 4, 150, 125, 30, 16, liste_phoneme[7], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 128)
|
||||
Text("=")
|
||||
let08selectkey = Menu(key_menu, 57, 195, 125, 70, 16,let08selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 8):
|
||||
let09 = String(" ", 4, 5, 105, 30, 16, liste_phoneme[8], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 108)
|
||||
Text("=")
|
||||
let09selectkey = Menu(key_menu, 58, 50, 105, 70, 16,let09selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 9):
|
||||
let10 = String(" ", 4, 150, 105, 30, 16, liste_phoneme[9], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 108)
|
||||
Text("=")
|
||||
let10selectkey = Menu(key_menu, 59, 195, 105, 70, 16, let10selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 10):
|
||||
let11 = String(" ", 4, 5, 85, 30, 16, liste_phoneme[10], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 88)
|
||||
Text("=")
|
||||
let11selectkey = Menu(key_menu, 60, 50, 85, 70, 16, let11selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 11):
|
||||
let12 = String(" ", 4, 150, 85, 30, 16, liste_phoneme[11], 2)
|
||||
glColor3d(0,0,0)
|
||||
Text("=")
|
||||
let12selectkey = Menu(key_menu, 61, 195, 85, 70, 16, let12selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 12):
|
||||
let13 = String(" ", 4, 5, 65, 30, 16, liste_phoneme[12], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 68)
|
||||
Text("=")
|
||||
let13selectkey = Menu(key_menu, 62, 50, 65, 70, 16, let13selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 13):
|
||||
let14 = String(" ", 4, 150, 65, 30, 16, liste_phoneme[13], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 68)
|
||||
Text("=")
|
||||
let14selectkey = Menu(key_menu, 63, 195, 65, 70, 16, let14selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 14):
|
||||
let15 = String(" ", 4, 5, 45, 30, 16, liste_phoneme[14], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(40, 48)
|
||||
Text("=")
|
||||
let15selectkey = Menu(key_menu, 64, 50, 45, 70, 16, let15selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 15):
|
||||
let16 = String(" ", 4, 150, 45, 30, 16, liste_phoneme[15], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(185, 48)
|
||||
Text("=")
|
||||
let16selectkey = Menu(key_menu, 65, 195, 45, 70, 16, let16selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 16):
|
||||
let17 = String(" ", 4, 295, 185, 30, 16, liste_phoneme[16], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 188)
|
||||
Text("=")
|
||||
let17selectkey = Menu(key_menu, 66, 340, 185, 70, 16, let17selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 17):
|
||||
let18 = String(" ", 4, 440, 185, 70, 16, liste_phoneme[17], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 188)
|
||||
Text("=")
|
||||
let18selectkey = Menu(key_menu, 67, 525, 185, 70, 16, let18selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 18):
|
||||
let19 = String(" ", 4, 295, 165, 30, 16, liste_phoneme[18], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 168)
|
||||
Text("=")
|
||||
let19selectkey = Menu(key_menu, 68, 340, 165, 70, 16, let19selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 19):
|
||||
let20 = String(" ", 4, 440, 165, 70, 16, liste_phoneme[19], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 168)
|
||||
Text("=")
|
||||
let20selectkey = Menu(key_menu, 69, 525, 165, 70, 16, let20selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 20):
|
||||
let21 = String(" ", 4, 295, 145, 30, 16, liste_phoneme[20], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 148)
|
||||
Text("=")
|
||||
let21selectkey = Menu(key_menu, 70, 340, 145, 70, 16, let21selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 21):
|
||||
let22 = String(" ", 4, 440, 145, 70, 16, liste_phoneme[21], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 148)
|
||||
Text("=")
|
||||
let22selectkey = Menu(key_menu, 71, 525, 145, 70, 16, let22selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 22):
|
||||
let23 = String(" ", 4, 295, 125, 30, 16, liste_phoneme[22], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 128)
|
||||
Text("=")
|
||||
let23selectkey = Menu(key_menu, 72, 340, 125, 70, 16,let23selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 23):
|
||||
let24 = String(" ", 4, 440, 125, 70, 16, liste_phoneme[23], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 128)
|
||||
Text("=")
|
||||
let24selectkey = Menu(key_menu, 73, 525, 125, 70, 16, let24selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 24):
|
||||
let25 = String(" ", 4, 295, 105, 30, 16, liste_phoneme[24], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 108)
|
||||
Text("=")
|
||||
let25selectkey = Menu(key_menu, 74, 340, 105, 70, 16, let25selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 25):
|
||||
let26 = String(" ", 4, 440, 105, 70, 16, liste_phoneme[25], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 108)
|
||||
Text("=")
|
||||
let26selectkey = Menu(key_menu, 75, 525, 105, 70, 16,let26selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 26):
|
||||
let27 = String(" ", 4, 295, 85, 30, 16, liste_phoneme[26], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 88)
|
||||
Text("=")
|
||||
let27selectkey = Menu(key_menu, 76, 340, 85, 70, 16, let27selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 27):
|
||||
let28 = String(" ", 4, 440, 85, 70, 16, liste_phoneme[27], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 88)
|
||||
Text("=")
|
||||
let28selectkey = Menu(key_menu, 77, 525, 85, 70, 16,let28selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 28):
|
||||
let29 = String(" ", 4, 295, 65, 30, 16, liste_phoneme[28], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 68)
|
||||
Text("=")
|
||||
let29selectkey = Menu(key_menu, 78, 340, 65, 70, 16, let29selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 29):
|
||||
let30 = String(" ", 4, 440, 65, 70, 16, liste_phoneme[29], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 68)
|
||||
Text("=")
|
||||
let30selectkey = Menu(key_menu, 79, 525, 65, 70, 16, let30selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 30):
|
||||
let31 = String(" ", 4, 295, 45, 30, 16, liste_phoneme[30], 2)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(330, 48)
|
||||
Text("=")
|
||||
let31selectkey = Menu(key_menu, 80, 340, 45, 70, 16, let31selectkey.val)
|
||||
|
||||
#
|
||||
if (nbr_phoneme > 31):
|
||||
let32 = String(" ", 4, 440, 45, 70, 16, liste_phoneme[31], 8)
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(515, 48)
|
||||
Text("=")
|
||||
let32selectkey = Menu(key_menu, 81, 525, 45, 70, 16, let32selectkey.val)
|
||||
|
||||
Button("Go", 3, 155, 5, 145, 22)
|
||||
|
||||
if (etape==2):
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(125, 200)
|
||||
Text("Operation Completed")
|
||||
|
||||
if (etape==0):
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(125, 200)
|
||||
Text("Please select a Mesh'Object and Create all the IPO Curves for your Shapes")
|
||||
|
||||
if (etape==3):
|
||||
#this stage permits to load a custom dictionnary
|
||||
load_file_text = "Load File"
|
||||
if mon_fichier_dico:
|
||||
Button("Import Loaded File", 2, 5, 5, 145, 22)
|
||||
glColor3d(1,1,1)
|
||||
glRasterPos2i(6, 50)
|
||||
Text("loaded file: %s" % basename(mon_fichier_dico))
|
||||
load_file_text = "Choose Another File"
|
||||
Button(load_file_text, 8, 125, 180, 145, 22)
|
||||
|
||||
glRasterPos2i(6, 40)
|
||||
Text("_______________________________________________________")
|
||||
glColor3d(0,0,0)
|
||||
glRasterPos2i(6, 38)
|
||||
Text("_______________________________________________________")
|
||||
|
||||
Button("Exit", 1, 305, 5, 80, 22)
|
||||
|
||||
|
||||
|
||||
#cette fonction sur evenement quite en cas d'ESC
|
||||
#this functions catch the ESC event and quit
|
||||
def event(evt,val):
|
||||
if (evt == ESCKEY and not val): Exit()
|
||||
|
||||
#cette fonction gere les evenements
|
||||
#the event functions
|
||||
def bevent(evt):
|
||||
global etape,soft_type,liste_phoneme,dico_phoneme_export
|
||||
|
||||
if (evt == 1):
|
||||
Exit()
|
||||
|
||||
elif (evt == 2):
|
||||
#c'est l'import du dictionnaire
|
||||
#we create and import the dictionnary
|
||||
lecture_chaine(mon_fichier_dico,dico_phoneme_export)
|
||||
construction_dictionnaire_phoneme()
|
||||
#we change the stage
|
||||
etape=1
|
||||
|
||||
elif (evt == 3):
|
||||
#c'est l'import
|
||||
#we import
|
||||
lecture_chaine(mon_fichier_export,dico_phoneme_export)
|
||||
construction_dico_correspondance()
|
||||
construction_lipsynchro()
|
||||
#on change d'etape
|
||||
#we change the stage
|
||||
etape=2
|
||||
|
||||
elif (evt == 8):
|
||||
#we choose the file
|
||||
Blender.Window.FileSelector(selectionner_fichier,"Select File")
|
||||
|
||||
Blender.Redraw()
|
||||
|
||||
#cette fonction recupere le nom et le chemin du fichier dictionnaire
|
||||
#we catch the name and the path of the dictionnary
|
||||
def selectionner_fichier(filename):
|
||||
global mon_fichier_dico,mon_fichier_export
|
||||
mon_fichier_dico=filename
|
||||
mon_fichier_export=filename
|
||||
|
||||
#fonction de lecture de la liste frame phoneme
|
||||
#we read the frame and phonems
|
||||
def lecture_chaine(fichier,liste):
|
||||
mon_fichier=open(fichier)
|
||||
#je lis la premiere ligne qui contiens la version de moho
|
||||
#first, we read the moho version
|
||||
mon_fichier.readline()
|
||||
|
||||
#je lis jusqu'a la fin
|
||||
#then we read until the end of the file
|
||||
while 1:
|
||||
ma_ligne=mon_fichier.readline()
|
||||
if ma_ligne=='':
|
||||
break
|
||||
decoup=ma_ligne.split()
|
||||
liste[decoup[0]]=decoup[1]
|
||||
print liste
|
||||
|
||||
|
||||
|
||||
|
||||
#fonction qui construit la liste dictionnaire simple
|
||||
#we make the dictionnary
|
||||
def construction_dictionnaire_phoneme():
|
||||
global liste_phoneme
|
||||
index_liste=0
|
||||
#je transforme mon dictionnaire en list de tulpes
|
||||
#we transform the list in tulpes
|
||||
ma_liste=dico_phoneme_export.items()
|
||||
#je parcours ma liste a la recherche d'elements non existant
|
||||
#we read the list to find non existing elements
|
||||
print dico_phoneme
|
||||
for index in range(len(ma_liste)):
|
||||
if ma_liste[index][1] not in liste_phoneme:
|
||||
liste_phoneme[index_liste:index_liste]=[ma_liste[index][1]]
|
||||
index_liste=index_liste+1
|
||||
print liste_phoneme
|
||||
|
||||
|
||||
#cette fonction recupere les courbes cible
|
||||
#this functon catch the IPO curve
|
||||
def recuperation_courbe():
|
||||
global key_menu,dico_key
|
||||
|
||||
#on recupere le nom des shapes
|
||||
#we catch the shapes
|
||||
key=Blender.Object.GetSelected()[0].getData().getKey().getBlocks()
|
||||
for n in range(len(key)):
|
||||
#on vire la premi<6D>re cle (en effet basic n'est pas une cle en tant que telle)
|
||||
#we threw away the basic shapes
|
||||
if (n>0):
|
||||
key_menu=key_menu+key[n].name + " %x" + str(n-1) + "|"
|
||||
dico_key[str(n-1)]=Blender.Object.GetSelected()[0].getData().getKey().getIpo().getCurves()[n-1]
|
||||
|
||||
|
||||
print "dico_key"
|
||||
print dico_key
|
||||
print 'end dico_key'
|
||||
|
||||
#cette fonction construit un dictionnaire de correspondance entre les phonemes prononces et les cles a utiliser
|
||||
#we make the dictionnary for the mapping between shapes and phonems
|
||||
def construction_dico_correspondance():
|
||||
global dico_correspondance
|
||||
#je parcours les phonemes
|
||||
#we read the phonems
|
||||
if (nbr_phoneme>0):
|
||||
dico_correspondance[liste_phoneme[0]]=dico_key[str(let01selectkey.val)]
|
||||
if (nbr_phoneme>1):
|
||||
dico_correspondance[liste_phoneme[1]]=dico_key[str(let02selectkey.val)]
|
||||
if (nbr_phoneme>2):
|
||||
dico_correspondance[liste_phoneme[2]]=dico_key[str(let03selectkey.val)]
|
||||
if (nbr_phoneme>3):
|
||||
dico_correspondance[liste_phoneme[3]]=dico_key[str(let04selectkey.val)]
|
||||
if (nbr_phoneme>4):
|
||||
dico_correspondance[liste_phoneme[4]]=dico_key[str(let05selectkey.val)]
|
||||
if (nbr_phoneme>5):
|
||||
dico_correspondance[liste_phoneme[5]]=dico_key[str(let06selectkey.val)]
|
||||
if (nbr_phoneme>6):
|
||||
dico_correspondance[liste_phoneme[6]]=dico_key[str(let07selectkey.val)]
|
||||
if (nbr_phoneme>7):
|
||||
dico_correspondance[liste_phoneme[7]]=dico_key[str(let08selectkey.val)]
|
||||
if (nbr_phoneme>8):
|
||||
dico_correspondance[liste_phoneme[8]]=dico_key[str(let09selectkey.val)]
|
||||
if (nbr_phoneme>9):
|
||||
dico_correspondance[liste_phoneme[9]]=dico_key[str(let10selectkey.val)]
|
||||
if (nbr_phoneme>10):
|
||||
dico_correspondance[liste_phoneme[10]]=dico_key[str(let11selectkey.val)]
|
||||
if (nbr_phoneme>11):
|
||||
dico_correspondance[liste_phoneme[11]]=dico_key[str(let12selectkey.val)]
|
||||
if (nbr_phoneme>12):
|
||||
dico_correspondance[liste_phoneme[12]]=dico_key[str(let13selectkey.val)]
|
||||
if (nbr_phoneme>13):
|
||||
dico_correspondance[liste_phoneme[13]]=dico_key[str(let14selectkey.val)]
|
||||
if (nbr_phoneme>14):
|
||||
dico_correspondance[liste_phoneme[14]]=dico_key[str(let15selectkey.val)]
|
||||
if (nbr_phoneme>15):
|
||||
dico_correspondance[liste_phoneme[15]]=dico_key[str(let16selectkey.val)]
|
||||
if (nbr_phoneme>16):
|
||||
dico_correspondance[liste_phoneme[16]]=dico_key[str(let17selectkey.val)]
|
||||
if (nbr_phoneme>17):
|
||||
dico_correspondance[liste_phoneme[17]]=dico_key[str(let18selectkey.val)]
|
||||
if (nbr_phoneme>18):
|
||||
dico_correspondance[liste_phoneme[18]]=dico_key[str(let19selectkey.val)]
|
||||
if (nbr_phoneme>19):
|
||||
dico_correspondance[liste_phoneme[19]]=dico_key[str(let20selectkey.val)]
|
||||
if (nbr_phoneme>20):
|
||||
dico_correspondance[liste_phoneme[20]]=dico_key[str(let21selectkey.val)]
|
||||
if (nbr_phoneme>21):
|
||||
dico_correspondance[liste_phoneme[21]]=dico_key[str(let22selectkey.val)]
|
||||
if (nbr_phoneme>22):
|
||||
dico_correspondance[liste_phoneme[22]]=dico_key[str(let23selectkey.val)]
|
||||
if (nbr_phoneme>23):
|
||||
dico_correspondance[liste_phoneme[23]]=dico_key[str(let24selectkey.val)]
|
||||
if (nbr_phoneme>24):
|
||||
dico_correspondance[liste_phoneme[24]]=dico_key[str(let25selectkey.val)]
|
||||
if (nbr_phoneme>25):
|
||||
dico_correspondance[liste_phoneme[25]]=dico_key[str(let26selectkey.val)]
|
||||
if (nbr_phoneme>26):
|
||||
dico_correspondance[liste_phoneme[26]]=dico_key[str(let27selectkey.val)]
|
||||
if (nbr_phoneme>27):
|
||||
dico_correspondance[liste_phoneme[27]]=dico_key[str(let28selectkey.val)]
|
||||
if (nbr_phoneme>28):
|
||||
dico_correspondance[liste_phoneme[28]]=dico_key[str(let29selectkey.val)]
|
||||
if (nbr_phoneme>29):
|
||||
dico_correspondance[liste_phoneme[29]]=dico_key[str(let30selectkey.val)]
|
||||
if (nbr_phoneme>30):
|
||||
dico_correspondance[liste_phoneme[30]]=dico_key[str(let31selectkey.val)]
|
||||
if (nbr_phoneme>31):
|
||||
dico_correspondance[liste_phoneme[31]]=dico_key[str(let32selectkey.val)]
|
||||
|
||||
print dico_correspondance
|
||||
|
||||
|
||||
#cette fonction ajoute un points a la cle donnee a la frame donnee
|
||||
#we add a point to the IPO curve Target
|
||||
def ajoute_point(cle,frame,valeur):
|
||||
cle.setInterpolation('Linear')
|
||||
cle.append((frame,valeur))
|
||||
cle.Recalc()
|
||||
|
||||
#cette fonction parcours le dictionnaire des frame <20> ajouter et construit les points
|
||||
#we add all the point to the IPO Curve
|
||||
def construction_lipsynchro():
|
||||
print "je construit"
|
||||
doublet_old=""
|
||||
#construction de la liste des frame
|
||||
cpt=0
|
||||
liste_frame=[]
|
||||
for frame in dico_phoneme_export:
|
||||
liste_frame.append(int(frame))
|
||||
cpt=cpt+1
|
||||
liste_frame.sort()
|
||||
print "listeframe"
|
||||
print liste_frame
|
||||
print "fini"
|
||||
|
||||
for doublet in liste_frame:
|
||||
ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],doublet,1)
|
||||
if (doublet_old==""):
|
||||
ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],(doublet-2),0)
|
||||
if (doublet_old!=''):
|
||||
if (dico_correspondance[dico_phoneme_export[str(doublet)]]!=dico_correspondance[dico_phoneme_export[doublet_old]]):
|
||||
print "doublet:"+str(doublet)
|
||||
print "doublet old:"+doublet_old
|
||||
ajoute_point(dico_correspondance[dico_phoneme_export[doublet_old]],(int(doublet_old)+2),0)
|
||||
ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],(doublet-2),0)
|
||||
doublet_old=str(doublet)
|
||||
|
||||
|
||||
#end of my functions we begin the execution
|
||||
#je commence l execution-----------------------------------------------------------------------------------------------
|
||||
#voici mes variables
|
||||
|
||||
#declaration et instanciation
|
||||
#decleration and instanciation
|
||||
|
||||
|
||||
#voici mon objet de travail
|
||||
objet_travail=Create(0)
|
||||
|
||||
#my soft type
|
||||
soft_type=1
|
||||
|
||||
#voici la liste des phoneme effectivement utilise
|
||||
#the phonems'list
|
||||
#liste_phoneme_papagayo=['AI','E','O','U','FV','L','WQ','MBP','etc','rest']
|
||||
#liste_phoneme_jlipsinch=['A','B','C','Closed','D','E','F','G','I','K','L','M','N','O','P','Q','R','S','SH','T','TH','U','V','W']
|
||||
|
||||
liste_phoneme=[]
|
||||
#voici mon dictionnaire des frames o
|
||||
dico_phoneme_export = Create(0)
|
||||
dico_phoneme_export={}
|
||||
dico_phoneme={}
|
||||
|
||||
|
||||
#voici mes cle
|
||||
key_menu=""
|
||||
dico_key={}
|
||||
|
||||
#voici mes ipo
|
||||
dico_bloc={}
|
||||
iponame = Create(0)
|
||||
|
||||
#voici mon dictionnaire de correspondance
|
||||
dico_correspondance={}
|
||||
|
||||
try:
|
||||
#on verifie est bien une mesh et qu'il a des courbes
|
||||
if ((Blender.Object.GetSelected()[0].getType()=='Mesh')):
|
||||
#on verifie que l'objet a bien toute ses Courbes
|
||||
if (len(Blender.Object.GetSelected()[0].getData().getKey().getBlocks())-1==Blender.Object.GetSelected()[0].getData().getKey().getIpo().getNcurves()):
|
||||
etape=3
|
||||
#on lance la creation du dictionnaire
|
||||
recuperation_courbe()
|
||||
else:
|
||||
print "not the good number of IPO Curve"
|
||||
etape = 0
|
||||
else:
|
||||
print "error: bad object Type:"
|
||||
print Blender.Object.GetSelected()[0].getType()
|
||||
etape = 0
|
||||
except:
|
||||
print 'error: exception'
|
||||
etape = 0
|
||||
|
||||
|
||||
#voici le fichier dictionnaire
|
||||
mon_fichier_dico=""
|
||||
|
||||
#voici le fichier export pamela
|
||||
mon_fichier_export=""
|
||||
|
||||
|
||||
let01selectkey = Create(0)
|
||||
let02selectkey = Create(0)
|
||||
let03selectkey = Create(0)
|
||||
let04selectkey = Create(0)
|
||||
let05selectkey = Create(0)
|
||||
let06selectkey = Create(0)
|
||||
let07selectkey = Create(0)
|
||||
let08selectkey = Create(0)
|
||||
let09selectkey = Create(0)
|
||||
let10selectkey = Create(0)
|
||||
let11selectkey = Create(0)
|
||||
let12selectkey = Create(0)
|
||||
let13selectkey = Create(0)
|
||||
let14selectkey = Create(0)
|
||||
let15selectkey = Create(0)
|
||||
let16selectkey = Create(0)
|
||||
let17selectkey = Create(0)
|
||||
let18selectkey = Create(0)
|
||||
let19selectkey = Create(0)
|
||||
let20selectkey = Create(0)
|
||||
let21selectkey = Create(0)
|
||||
let22selectkey = Create(0)
|
||||
let23selectkey = Create(0)
|
||||
let24selectkey = Create(0)
|
||||
|
||||
|
||||
Register (trace,event,bevent)
|
||||
121
src_research_readme/blender_2.43_scripts/bpydata/KUlang.txt
Normal file
121
src_research_readme/blender_2.43_scripts/bpydata/KUlang.txt
Normal file
@@ -0,0 +1,121 @@
|
||||
Version 3.233-2004
|
||||
******************
|
||||
Espanol
|
||||
Sale del programa
|
||||
Utilidades de...%t|Alinea objetos%x1|Creacion%x2|Edita mallas%x3|Edita objetos%x4
|
||||
11
|
||||
Mov
|
||||
Esc
|
||||
Encaja
|
||||
Abarca
|
||||
Separa
|
||||
Alinea
|
||||
Rota
|
||||
Incr.
|
||||
Crea nuevos objetos
|
||||
Es+
|
||||
Es*
|
||||
Separar entre:%t|Origenes%x1|Centros geometricos%x2|Minimos%x3|Maximos%x4|Baricentro%x5|Objetos%x6
|
||||
Crear%t|Arco (3 ptos.)%x1|Arco (interactivo)%x2|Circunferencia (3 ptos.)%x3
|
||||
12
|
||||
Puntos
|
||||
Centro
|
||||
Orden
|
||||
Objeto
|
||||
AngIni:
|
||||
AngFin:
|
||||
Angulo:
|
||||
Radio:
|
||||
Puntos:
|
||||
Centro
|
||||
Nombre:
|
||||
Puntos
|
||||
Modifica vertices%t|Subdivide%x1|Envia a un plano%x2|Aplica LocRotSize%x3
|
||||
Partes
|
||||
Proyectar en el plano:%t|Coordenado global...%x1|Coordenado local...%x2
|
||||
Actuar sobre el plano%t|Yz%x1|Zx%x2|Xy%x3
|
||||
En la direcci<63>n%t|X%x1|Y%x2|Z%x3|Ortogonal al plano%x4
|
||||
Captura
|
||||
Buffer%t|Copia vector diferencia%x1|Copia distancia%x2|Copia diferencia de rotacion%x3|Copia media LocRotSiz%x4|Ver buffer en consola%x5
|
||||
Transformar LocRotSize%t|Hacia el obj. activo%x1|Aleatoriamente%x2
|
||||
Poner a distancia fija%x1|Sumar (desp. absoluto)%x2|Multiplicar (desp. relativo)%x3
|
||||
********************
|
||||
English
|
||||
Exit program
|
||||
Utils about:%t|Align Objects%x1|Create%x2|Edit Meshes%x3|Edit Objects%x4
|
||||
11
|
||||
Mov
|
||||
Sca
|
||||
Fit
|
||||
Embrace
|
||||
Separate
|
||||
Align
|
||||
Rota
|
||||
Incr.
|
||||
Create new objects
|
||||
Sc+
|
||||
Sc*
|
||||
Separate between:%t|Origins%x1|Geometric centers%x2|Minimum%x3|Maximum%x4|Baricenter%x5|Objects%x6
|
||||
Create what%t|Arc (3 pts.)%x1|Arc (interactive)%x2|Circunference (3 pts.)%x3
|
||||
12
|
||||
Points
|
||||
Centre
|
||||
Sort
|
||||
Object
|
||||
AngIni:
|
||||
AngEnd:
|
||||
Angle:
|
||||
Radius:
|
||||
Points:
|
||||
Centre
|
||||
ObjName:
|
||||
Points
|
||||
Modify vertices%t|Subdivide edges%x1|Send to a plane%x2|Set LocRotSize%x3
|
||||
Parts
|
||||
Project onto the plane:%t|Global coordinated...%x1|Local coordinated...%x2
|
||||
Act on plane%t|Yz%x1|Zx%x2|Xy%x3
|
||||
In direction%t|X%x1|Y%x2|Z%x3|Ortogonal to plane%x4
|
||||
Get
|
||||
Buffer%t|Copy diference vector%x1|Copy distance%x2|Copy rot diference%x3|Copy LocRotSiz average%x4|Show Buffer in Console%x5
|
||||
Transform LocRotSize%t|Close to active%x1|Randomly%x2
|
||||
Set at fixed distance%x1|Add (absolute displ.)%x2|Multiply (relative displ.)%x3
|
||||
********************
|
||||
Catala
|
||||
Surt del programa
|
||||
Utilitats de...%t|Alinea objectes%x1|Creacio%x2|Edita malles%x3|Edita objetes%x4
|
||||
11
|
||||
Mov
|
||||
Esc
|
||||
Encaixa
|
||||
Abarca
|
||||
Separa
|
||||
Alinea
|
||||
Rotacio
|
||||
Incr.
|
||||
Crea objectes nous
|
||||
Es+
|
||||
Es*
|
||||
Separa entra:%t|Origens%x1|Centres geometrics%x2|Minims%x3|Maxims%x4|Baricentre%x5|Objectes%x6
|
||||
Crear%t|Arc (3 pts.)%x1|Arc (interactiu)%x2|Circumferencia (3 pts.)%x3
|
||||
12
|
||||
Punts
|
||||
Centre
|
||||
Ordre
|
||||
Objecte
|
||||
AngIni:
|
||||
AngFi:
|
||||
Angle:
|
||||
Radi:
|
||||
Punts:
|
||||
Centre
|
||||
Nom:
|
||||
Punts
|
||||
Modifica vertex%t|Subdivideix%x1|Envia a un pla%x2|Aplica LocRotSize%x3
|
||||
Parts
|
||||
Projectar en el pla:%t|Coordenacio global...%x1|Coordenacio local...%x2
|
||||
Actuar sobre el pla%t|Yz%x1|Zx%x2|Xy%x3
|
||||
En la direccio%t|X%x1|Y%x2|Z%x3|Ortogonal al pla%x4
|
||||
Captura
|
||||
Buffer%t|Copia vector diferencia%x1|Copia distancia%x2|Copia diferencia de rotacio%x3|Copia mitjana LocRotSiz%x4|Veure buffer en consola%x5
|
||||
Transformar LocRotSize%t|Cap al obj. actiu%x1|Aleatoriamente%x2
|
||||
Posar a distancia fixa%x1|Sumar (desp. absolut)%x2|Multiplicar (desp. relatiu)%x3
|
||||
@@ -0,0 +1,6 @@
|
||||
This folder is for automatically saved scripts configuration data.
|
||||
|
||||
To use this feature scripts just need to set a proper Blender.Registry key.
|
||||
|
||||
To know more, check the API Reference doc (specifically the API_related and
|
||||
Registry parts) and the documentation for the "Scripts Config Editor" script.
|
||||
@@ -0,0 +1,5 @@
|
||||
vrml97_export = {
|
||||
'selection_only': 1,
|
||||
'compressed': 0,
|
||||
'rotate_z_to_y': 0,
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
This directory is the default place for scripts to put their data,
|
||||
like internal files needed by the script and its saved configuration.
|
||||
|
||||
Scripts can find the path to this dir using Blender.Get("datadir").
|
||||
Ex:
|
||||
|
||||
import Blender
|
||||
print Blender.Get("datadir")
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
import Blender
|
||||
from Blender.Window import EditMode, GetCursorPos, GetViewQuat
|
||||
import bpy
|
||||
import BPyMessages
|
||||
|
||||
def add_mesh_simple(name, verts, edges, faces):
|
||||
'''
|
||||
Adds a mesh from verts, edges and faces
|
||||
|
||||
name - new object/mesh name
|
||||
verts - list of 3d vectors
|
||||
edges - list of int pairs
|
||||
faces - list of int triplets/quads
|
||||
'''
|
||||
|
||||
scn = bpy.data.scenes.active
|
||||
if scn.lib: return
|
||||
ob_act = scn.objects.active
|
||||
|
||||
is_editmode = EditMode()
|
||||
|
||||
cursor = GetCursorPos()
|
||||
quat = None
|
||||
if is_editmode or Blender.Get('add_view_align'): # Aligning seems odd for editmode, but blender does it, oh well
|
||||
try: quat = Blender.Mathutils.Quaternion(GetViewQuat())
|
||||
except: pass
|
||||
|
||||
# Exist editmode for non mesh types
|
||||
if ob_act and ob_act.type != 'Mesh' and is_editmode:
|
||||
EditMode(0)
|
||||
|
||||
# We are in mesh editmode
|
||||
if EditMode():
|
||||
me = ob_act.getData(mesh=1)
|
||||
|
||||
if me.multires:
|
||||
BPyMessages.Error_NoMeshMultiresEdit()
|
||||
return
|
||||
|
||||
# Add to existing mesh
|
||||
# must exit editmode to modify mesh
|
||||
EditMode(0)
|
||||
|
||||
me.sel = False
|
||||
|
||||
vert_offset = len(me.verts)
|
||||
edge_offset = len(me.edges)
|
||||
face_offset = len(me.faces)
|
||||
|
||||
# transform the verts
|
||||
txmat = Blender.Mathutils.TranslationMatrix(Blender.Mathutils.Vector(cursor))
|
||||
if quat:
|
||||
mat = quat.toMatrix()
|
||||
mat.invert()
|
||||
mat.resize4x4()
|
||||
txmat = mat * txmat
|
||||
|
||||
txmat = txmat * ob_act.matrixWorld.copy().invert()
|
||||
|
||||
|
||||
me.verts.extend(verts)
|
||||
# Transform the verts by the cursor and view rotation
|
||||
me.transform(txmat, selected_only=True)
|
||||
|
||||
if vert_offset:
|
||||
me.edges.extend([[i+vert_offset for i in e] for e in edges])
|
||||
me.faces.extend([[i+vert_offset for i in f] for f in faces])
|
||||
else:
|
||||
# Mesh with no data, unlikely
|
||||
me.edges.extend(edges)
|
||||
me.faces.extend(faces)
|
||||
else:
|
||||
|
||||
# Object mode add new
|
||||
|
||||
me = bpy.data.meshes.new(name)
|
||||
me.verts.extend(verts)
|
||||
me.edges.extend(edges)
|
||||
me.faces.extend(faces)
|
||||
me.sel = True
|
||||
|
||||
# Object creation and location
|
||||
scn.objects.selected = []
|
||||
ob_act = scn.objects.new(me, name)
|
||||
scn.objects.active = ob_act
|
||||
|
||||
if quat:
|
||||
mat = quat.toMatrix()
|
||||
mat.invert()
|
||||
mat.resize4x4()
|
||||
ob_act.setMatrix(mat)
|
||||
|
||||
ob_act.loc = cursor
|
||||
|
||||
me.calcNormals()
|
||||
|
||||
if is_editmode or Blender.Get('add_editmode'):
|
||||
EditMode(1)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def write_mesh_script(filepath, me):
|
||||
'''
|
||||
filepath - path to py file
|
||||
me - mesh to write
|
||||
'''
|
||||
|
||||
name = me.name
|
||||
file = open(filepath, 'w')
|
||||
|
||||
file.write('#!BPY\n')
|
||||
file.write('"""\n')
|
||||
file.write('Name: \'%s\'\n' % name)
|
||||
file.write('Blender: 245\n')
|
||||
file.write('Group: \'AddMesh\'\n')
|
||||
file.write('"""\n\n')
|
||||
file.write('import BPyAddMesh\n')
|
||||
file.write('from Blender.Mathutils import Vector\n\n')
|
||||
|
||||
file.write('verts = [\\\n')
|
||||
for v in me.verts:
|
||||
file.write('Vector(%f,%f,%f),\\\n' % tuple(v.co))
|
||||
file.write(']\n')
|
||||
|
||||
file.write('edges = []\n') # TODO, write loose edges
|
||||
|
||||
file.write('faces = [\\\n')
|
||||
for f in me.faces:
|
||||
file.write('%s,\\\n' % str(tuple([v.index for v in f])))
|
||||
file.write(']\n')
|
||||
|
||||
file.write('BPyAddMesh.add_mesh_simple("%s", verts, edges, faces)\n' % name)
|
||||
|
||||
# The script below can make a file from a mesh with teh above function...
|
||||
'''
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Mesh as AddMesh Script'
|
||||
Blender: 242
|
||||
Group: 'Mesh'
|
||||
Tip: ''
|
||||
"""
|
||||
import BPyAddMesh
|
||||
reload(BPyAddMesh)
|
||||
|
||||
import bpy
|
||||
|
||||
def main():
|
||||
# Add error checking
|
||||
scn = bpy.data.scenes.active
|
||||
ob = scn.objects.active
|
||||
me = ob.getData(mesh=1)
|
||||
|
||||
BPyAddMesh.write_mesh_script('/test.py', me)
|
||||
|
||||
main()
|
||||
'''
|
||||
@@ -0,0 +1,152 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# Version History:
|
||||
# 1.0 original release bakes an armature into a matrix
|
||||
# 1.1 optional params (ACTION_BAKE, ACTION_BAKE_FIRST_FRAME, direct function to key and return the Action
|
||||
|
||||
import Blender
|
||||
from Blender import sys
|
||||
import bpy
|
||||
def getBakedPoseData(ob_arm, start_frame, end_frame, ACTION_BAKE = False, ACTION_BAKE_FIRST_FRAME = True):
|
||||
'''
|
||||
If you are currently getting IPO's this function can be used to
|
||||
ACTION_BAKE==False: return a list of frame aligned bone dictionary's
|
||||
ACTION_BAKE==True: return an action with keys aligned to bone constrained movement
|
||||
if ACTION_BAKE_FIRST_FRAME is not supplied or is true: keys begin at frame 1
|
||||
|
||||
The data in these can be swaped in for the IPO loc and quat
|
||||
|
||||
If you want to bake an action, this is not as hard and the ipo hack can be removed.
|
||||
'''
|
||||
|
||||
# --------------------------------- Dummy Action! Only for this functon
|
||||
backup_action = ob_arm.action
|
||||
backup_frame = Blender.Get('curframe')
|
||||
|
||||
DUMMY_ACTION_NAME = '~DONT_USE~'
|
||||
# Get the dummy action if it has no users
|
||||
try:
|
||||
new_action = bpy.data.actions[DUMMY_ACTION_NAME]
|
||||
if new_action.users:
|
||||
new_action = None
|
||||
except:
|
||||
new_action = None
|
||||
|
||||
if not new_action:
|
||||
new_action = bpy.data.actions.new(DUMMY_ACTION_NAME)
|
||||
new_action.fakeUser = False
|
||||
# ---------------------------------- Done
|
||||
|
||||
Matrix = Blender.Mathutils.Matrix
|
||||
Quaternion = Blender.Mathutils.Quaternion
|
||||
Vector = Blender.Mathutils.Vector
|
||||
POSE_XFORM= [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT]
|
||||
|
||||
# Each dict a frame
|
||||
bake_data = [{} for i in xrange(1+end_frame-start_frame)]
|
||||
|
||||
pose= ob_arm.getPose()
|
||||
armature_data= ob_arm.getData();
|
||||
pose_bones= pose.bones
|
||||
|
||||
# --------------------------------- Build a list of arma data for reuse
|
||||
armature_bone_data = []
|
||||
bones_index = {}
|
||||
for bone_name, rest_bone in armature_data.bones.items():
|
||||
pose_bone = pose_bones[bone_name]
|
||||
rest_matrix = rest_bone.matrix['ARMATURESPACE']
|
||||
rest_matrix_inv = rest_matrix.copy().invert()
|
||||
armature_bone_data.append( [len(bones_index), -1, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, None ])
|
||||
bones_index[bone_name] = len(bones_index)
|
||||
|
||||
# Set the parent ID's
|
||||
for bone_name, pose_bone in pose_bones.items():
|
||||
parent = pose_bone.parent
|
||||
if parent:
|
||||
bone_index= bones_index[bone_name]
|
||||
parent_index= bones_index[parent.name]
|
||||
armature_bone_data[ bone_index ][1]= parent_index
|
||||
# ---------------------------------- Done
|
||||
|
||||
|
||||
|
||||
# --------------------------------- Main loop to collect IPO data
|
||||
frame_index = 0
|
||||
NvideoFrames= end_frame-start_frame
|
||||
for current_frame in xrange(start_frame, end_frame+1):
|
||||
if frame_index==0: start=sys.time()
|
||||
elif frame_index==15: print NvideoFrames*(sys.time()-start),"seconds estimated..." #slows as it grows *3
|
||||
elif frame_index >15:
|
||||
percom= frame_index*100/NvideoFrames
|
||||
print "Frame %i Overall %i percent complete\r" % (current_frame, percom),
|
||||
ob_arm.action = backup_action
|
||||
#pose.update() # not needed
|
||||
Blender.Set('curframe', current_frame)
|
||||
#Blender.Window.RedrawAll()
|
||||
#frame_data = bake_data[frame_index]
|
||||
ob_arm.action = new_action
|
||||
###for i,pose_bone in enumerate(pose_bones):
|
||||
|
||||
for index, parent_index, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, ipo in armature_bone_data:
|
||||
matrix= pose_bone.poseMatrix
|
||||
parent_bone= rest_bone.parent
|
||||
if parent_index != -1:
|
||||
parent_pose_matrix = armature_bone_data[parent_index][6].poseMatrix
|
||||
parent_bone_matrix_inv = armature_bone_data[parent_index][5]
|
||||
matrix= matrix * parent_pose_matrix.copy().invert()
|
||||
rest_matrix= rest_matrix * parent_bone_matrix_inv
|
||||
|
||||
matrix=matrix * rest_matrix.copy().invert()
|
||||
pose_bone.quat= matrix.toQuat()
|
||||
pose_bone.loc= matrix.translationPart()
|
||||
if ACTION_BAKE==False:
|
||||
pose_bone.insertKey(ob_arm, 1, POSE_XFORM) # always frame 1
|
||||
|
||||
# THIS IS A BAD HACK! IT SUCKS BIGTIME BUT THE RESULT ARE NICE
|
||||
# - use a temp action and bake into that, always at the same frame
|
||||
# so as not to make big IPO's, then collect the result from the IPOs
|
||||
|
||||
# Now get the data from the IPOs
|
||||
if not ipo: ipo = armature_bone_data[index][7] = new_action.getChannelIpo(bone_name)
|
||||
|
||||
loc = Vector()
|
||||
quat = Quaternion()
|
||||
|
||||
for curve in ipo:
|
||||
val = curve.evaluate(1)
|
||||
curve_name= curve.name
|
||||
if curve_name == 'LocX': loc[0] = val
|
||||
elif curve_name == 'LocY': loc[1] = val
|
||||
elif curve_name == 'LocZ': loc[2] = val
|
||||
elif curve_name == 'QuatW': quat[3] = val
|
||||
elif curve_name == 'QuatX': quat[0] = val
|
||||
elif curve_name == 'QuatY': quat[1] = val
|
||||
elif curve_name == 'QuatZ': quat[2] = val
|
||||
|
||||
bake_data[frame_index][bone_name] = loc, quat
|
||||
else:
|
||||
if ACTION_BAKE_FIRST_FRAME: pose_bone.insertKey(ob_arm, frame_index+1, POSE_XFORM)
|
||||
else: pose_bone.insertKey(ob_arm, current_frame , POSE_XFORM)
|
||||
frame_index+=1
|
||||
print "\nBaking Complete."
|
||||
ob_arm.action = backup_action
|
||||
if ACTION_BAKE==False:
|
||||
Blender.Set('curframe', backup_frame)
|
||||
return bake_data
|
||||
elif ACTION_BAKE==True:
|
||||
return new_action
|
||||
else: print "ERROR: Invalid ACTION_BAKE %i sent to BPyArmature" % ACTION_BAKE
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# $Id: BPyBlender.py 5652 2005-10-30 19:19:38Z aphex $
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# BPyBlender.py version 0.3 Mar 20, 2005
|
||||
# --------------------------------------------------------------------------
|
||||
# helper functions to be used by other scripts
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# Basic set of modules Blender should have in all supported platforms.
|
||||
# The second and third lines are the contents of the Python23.zip file
|
||||
# included with Windows Blender binaries along with zlib.pyd.
|
||||
# Other platforms are assumed to have Python installed.
|
||||
basic_modules = [
|
||||
'Blender',
|
||||
'chunk','colorsys','copy','copy_reg','gzip','os','random','repr','stat',
|
||||
'string','StringIO','types','UserDict','webbrowser', 'zlib', 'math',
|
||||
'BPyBlender', 'BPyRegistry'
|
||||
]
|
||||
@@ -0,0 +1,79 @@
|
||||
# --------------------------------------------------------------------------
|
||||
# BPyImage.py version 0.15
|
||||
# --------------------------------------------------------------------------
|
||||
# helper functions to be used by other scripts
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
from Blender import *
|
||||
|
||||
def curve2vecs(ob, WORLDSPACE= True):
|
||||
'''
|
||||
Takes a curve object and retuirns a list of vec lists (polylines)
|
||||
one list per curve
|
||||
|
||||
This is usefull as a way to get a polyline per curve
|
||||
so as not to have to deal with the spline types directly
|
||||
'''
|
||||
if ob.type != 'Curve':
|
||||
raise 'must be a curve object'
|
||||
|
||||
me_dummy = Mesh.New()
|
||||
me_dummy.getFromObject(ob)
|
||||
|
||||
if WORLDSPACE:
|
||||
me_dummy.transform(ob.matrixWorld)
|
||||
|
||||
# build an edge dict
|
||||
edges = {} # should be a set
|
||||
|
||||
def sort_pair(i1, i2):
|
||||
if i1 > i2: return i2, i1
|
||||
else: return i1, i2
|
||||
|
||||
for ed in me_dummy.edges:
|
||||
edges[sort_pair(ed.v1.index,ed.v2.index)] = None # dummy value
|
||||
|
||||
# now set the curves
|
||||
first_time = True
|
||||
|
||||
current_vecs = []
|
||||
vec_list = [current_vecs]
|
||||
|
||||
for v in me_dummy.verts:
|
||||
if first_time:
|
||||
first_time = False
|
||||
current_vecs.append(v.co.copy())
|
||||
last_index = v.index
|
||||
else:
|
||||
index = v.index
|
||||
if edges.has_key(sort_pair(index, last_index)):
|
||||
current_vecs.append( v.co.copy() )
|
||||
else:
|
||||
current_vecs = []
|
||||
vec_list.append(current_vecs)
|
||||
|
||||
last_index = index
|
||||
|
||||
me_dummy.verts = None
|
||||
|
||||
return vec_list
|
||||
|
||||
|
||||
318
src_research_readme/blender_2.43_scripts/bpymodules/BPyImage.py
Normal file
318
src_research_readme/blender_2.43_scripts/bpymodules/BPyImage.py
Normal file
@@ -0,0 +1,318 @@
|
||||
# --------------------------------------------------------------------------
|
||||
# BPyImage.py version 0.15
|
||||
# --------------------------------------------------------------------------
|
||||
# helper functions to be used by other scripts
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
#===========================================================================#
|
||||
# Comprehensive image loader, will search and find the image #
|
||||
# Will return a blender image or a new image if the image is missing #
|
||||
#===========================================================================#
|
||||
import bpy
|
||||
from Blender import sys
|
||||
try:
|
||||
import os
|
||||
except:
|
||||
os=None
|
||||
|
||||
#==============================================#
|
||||
# Return directory, where the file is #
|
||||
#==============================================#
|
||||
def stripFile(path):
|
||||
lastSlash = max(path.rfind('\\'), path.rfind('/'))
|
||||
if lastSlash != -1:
|
||||
path = path[:lastSlash]
|
||||
newpath= '%s%s' % (path, sys.sep)
|
||||
else:
|
||||
newpath= path
|
||||
return newpath
|
||||
|
||||
#==============================================#
|
||||
# Strips the slashes from the back of a string #
|
||||
#==============================================#
|
||||
def stripPath(path):
|
||||
return path.split('/')[-1].split('\\')[-1]
|
||||
|
||||
#====================================================#
|
||||
# Strips the prefix off the name before writing #
|
||||
#====================================================#
|
||||
def stripExt(name): # name is a string
|
||||
index = name.rfind('.')
|
||||
if index != -1:
|
||||
return name[ : index ]
|
||||
else:
|
||||
return name
|
||||
|
||||
def getExt(name):
|
||||
index = name.rfind('.')
|
||||
if index != -1:
|
||||
return name[index+1:]
|
||||
return name
|
||||
|
||||
#====================================================#
|
||||
# Adds a slash to the end of a path if its not there #
|
||||
#====================================================#
|
||||
def addSlash(path):
|
||||
if not path:
|
||||
return ''
|
||||
|
||||
elif path.endswith('\\') or path.endswith('/'):
|
||||
return path
|
||||
return path + sys.sep
|
||||
|
||||
|
||||
def comprehensiveImageLoad(imagePath, filePath, PLACE_HOLDER= True, RECURSIVE=True, VERBOSE=False, CONVERT_CALLBACK=None):
|
||||
'''
|
||||
imagePath: The image filename
|
||||
If a path precedes it, this will be searched as well.
|
||||
|
||||
filePath: is the directory where the image may be located - any file at teh end will be ignored.
|
||||
|
||||
PLACE_HOLDER: if True a new place holder image will be created.
|
||||
this is usefull so later you can relink the image to its original data.
|
||||
|
||||
VERBOSE: If True debug info will be printed.
|
||||
|
||||
RECURSIVE: If True, directories will be recursivly searched.
|
||||
Be carefull with this if you have files in your root directory because it may take a long time.
|
||||
|
||||
CASE_INSENSITIVE: for non win32 systems, find the correct case for the file.
|
||||
|
||||
CONVERT_CALLBACK: a function that takes an existing path and returns a new one.
|
||||
Use this when loading image formats blender may not support, the CONVERT_CALLBACK
|
||||
can take the path for a GIF (for example), convert it to a PNG and return the PNG's path.
|
||||
For formats blender can read, simply return the path that is given.
|
||||
'''
|
||||
|
||||
# VERBOSE = True
|
||||
|
||||
if VERBOSE: print 'img:', imagePath, 'file:', filePath
|
||||
|
||||
if os == None and CASE_INSENSITIVE:
|
||||
CASE_INSENSITIVE = True
|
||||
|
||||
# When we have the file load it with this. try/except niceness.
|
||||
def imageLoad(path):
|
||||
#if path.endswith('\\') or path.endswith('/'):
|
||||
# raise 'INVALID PATH'
|
||||
|
||||
if CONVERT_CALLBACK:
|
||||
path = CONVERT_CALLBACK(path)
|
||||
|
||||
try:
|
||||
img = bpy.data.images.new(filename=path)
|
||||
if VERBOSE: print '\t\tImage loaded "%s"' % path
|
||||
return img
|
||||
except:
|
||||
if VERBOSE:
|
||||
if sys.exists(path): print '\t\tImage failed loading "%s", mabe its not a format blender can read.' % (path)
|
||||
else: print '\t\tImage not found, making a place holder "%s"' % (path)
|
||||
if PLACE_HOLDER:
|
||||
img= bpy.data.images.new(stripPath(path),4,4)
|
||||
img.filename= path
|
||||
return img #blank image
|
||||
else:
|
||||
return None
|
||||
|
||||
# Image formats blender can read
|
||||
IMAGE_EXT = ['jpg', 'jpeg', 'png', 'tga', 'bmp', 'rgb', 'sgi', 'bw', 'iff', 'lbm', # Blender Internal
|
||||
'gif', 'psd', 'tif', 'tiff', 'pct', 'pict', 'pntg', 'qtif'] # Quacktime, worth a try.
|
||||
|
||||
imageFileName = stripPath(imagePath) # image path only
|
||||
imageFileName_lower = imageFileName.lower() # image path only
|
||||
|
||||
if VERBOSE: print '\tSearchingExisting Images for "%s"' % imagePath
|
||||
for i in bpy.data.images:
|
||||
if stripPath(i.filename.lower()) == imageFileName_lower:
|
||||
if VERBOSE: print '\t\tUsing existing image.'
|
||||
return i
|
||||
|
||||
|
||||
if VERBOSE: print '\tAttempting to load "%s"' % imagePath
|
||||
if sys.exists(imagePath):
|
||||
if VERBOSE: print '\t\tFile found where expected "%s".' % imagePath
|
||||
return imageLoad(imagePath)
|
||||
|
||||
|
||||
|
||||
imageFileName_noext = stripExt(imageFileName) # With no extension.
|
||||
imageFileName_noext_lower = stripExt(imageFileName_lower) # With no extension.
|
||||
imageFilePath = stripFile(imagePath)
|
||||
|
||||
# Remove relative path from image path
|
||||
if imageFilePath.startswith('./') or imageFilePath.startswith('.\\'):
|
||||
imageFilePath = imageFilePath[2:]
|
||||
|
||||
|
||||
# Attempt to load from obj path.
|
||||
tmpPath = stripFile(filePath) + stripPath(imageFileName)
|
||||
if sys.exists(tmpPath):
|
||||
if VERBOSE: print '\t\tFile found in path (1)"%s".' % tmpPath
|
||||
return imageLoad(tmpPath)
|
||||
|
||||
|
||||
# os needed if we go any further.
|
||||
if not os:
|
||||
if VERBOSE: print '\t\tCreating a placeholder with a face path: "%s".' % imagePath
|
||||
return imageLoad(imagePath) # Will jus treturn a placeholder.
|
||||
|
||||
|
||||
# We have os.
|
||||
# GATHER PATHS.
|
||||
paths = {} # Store possible paths we may use, dict for no doubles.
|
||||
tmpPath = addSlash(sys.expandpath('//')) # Blenders path
|
||||
if sys.exists(tmpPath):
|
||||
if VERBOSE: print '\t\tSearching in %s' % tmpPath
|
||||
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||
else:
|
||||
if VERBOSE: print '\tNo Path: "%s"' % tmpPath
|
||||
|
||||
tmpPath = imageFilePath
|
||||
if sys.exists(tmpPath):
|
||||
if VERBOSE: print '\t\tSearching in %s' % tmpPath
|
||||
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||
else:
|
||||
if VERBOSE: print '\tNo Path: "%s"' % tmpPath
|
||||
|
||||
tmpPath = stripFile(filePath)
|
||||
if sys.exists(tmpPath):
|
||||
if VERBOSE: print '\t\tSearching in %s' % tmpPath
|
||||
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||
else:
|
||||
if VERBOSE: print '\tNo Path: "%s"' % tmpPath
|
||||
|
||||
tmpPath = addSlash(bpy.config.textureDir)
|
||||
if tmpPath and sys.exists(tmpPath):
|
||||
if VERBOSE: print '\t\tSearching in %s' % tmpPath
|
||||
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||
else:
|
||||
if VERBOSE: print '\tNo Path: "%s"' % tmpPath
|
||||
|
||||
# Add path if relative image patrh was given.
|
||||
tmp_paths= paths.keys()
|
||||
for k in tmp_paths:
|
||||
tmpPath = k + imageFilePath
|
||||
if sys.exists(tmpPath):
|
||||
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||
else:
|
||||
if VERBOSE: print '\tNo Path: "%s"' % tmpPath
|
||||
# DONE
|
||||
#
|
||||
for path, files in paths.iteritems():
|
||||
if sys.exists(path + imageFileName):
|
||||
if VERBOSE: print '\tFound image at path: "%s" file" "%s"' % (path, imageFileName)
|
||||
return imageLoad(path + imageFileName)
|
||||
|
||||
# If the files not there then well do a case insensitive seek.
|
||||
filesOrigCase = files[0]
|
||||
filesLower = files[1]
|
||||
filesLowerNoExt = files[2]
|
||||
|
||||
# We are going to try in index the file directly, if its not there just keep on
|
||||
|
||||
index = None
|
||||
try:
|
||||
# Is it just a case mismatch?
|
||||
index = filesLower.index(imageFileName_lower)
|
||||
except:
|
||||
try:
|
||||
# Have the extensions changed?
|
||||
index = filesLowerNoExt.index(imageFileName_noext_lower)
|
||||
|
||||
ext = getExt( filesLower[index] ) # Get the extension of the file that matches all but ext.
|
||||
|
||||
# Check that the ext is useable eg- not a 3ds file :)
|
||||
if ext.lower() not in IMAGE_EXT:
|
||||
index = None
|
||||
|
||||
except:
|
||||
index = None
|
||||
|
||||
if index != None:
|
||||
tmpPath = path + filesOrigCase[index]
|
||||
img = imageLoad( tmpPath )
|
||||
if img != None:
|
||||
if VERBOSE: print '\t\tImage Found "%s"' % tmpPath
|
||||
return img
|
||||
|
||||
if RECURSIVE:
|
||||
# IMAGE NOT FOUND IN ANY OF THE DIRS!, DO A RECURSIVE SEARCH.
|
||||
if VERBOSE: print '\t\tImage Not Found in any of the dirs, doing a recusrive search'
|
||||
for path in paths.iterkeys():
|
||||
# Were not going to use files
|
||||
if path == '/' or len(path) == 3 and path[1:] == ':\\':
|
||||
continue
|
||||
|
||||
# print path , 'ASS'
|
||||
|
||||
#------------------
|
||||
# finds the file starting at the root.
|
||||
# def findImage(findRoot, imagePath):
|
||||
#W---------------
|
||||
|
||||
# ROOT, DIRS, FILES
|
||||
pathWalk = os.walk(path)
|
||||
pathList = [True]
|
||||
|
||||
matchList = [] # Store a list of (match, size), choose the biggest.
|
||||
while True:
|
||||
try:
|
||||
pathList = pathWalk.next()
|
||||
except:
|
||||
break
|
||||
|
||||
for file in pathList[2]:
|
||||
file_lower = file.lower()
|
||||
# FOUND A MATCH
|
||||
if (file_lower == imageFileName_lower) or\
|
||||
(stripExt(file_lower) == imageFileName_noext_lower and getExt(file_lower) in IMAGE_EXT):
|
||||
name = pathList[0] + sys.sep + file
|
||||
size = os.path.getsize(name)
|
||||
if VERBOSE: print '\t\t\tfound:', name
|
||||
matchList.append( (name, size) )
|
||||
|
||||
if matchList:
|
||||
# Sort by file size
|
||||
matchList.sort(lambda A, B: cmp(B[1], A[1]) )
|
||||
|
||||
if VERBOSE: print '\t\tFound "%s"' % matchList[0][0]
|
||||
|
||||
# Loop through all we have found
|
||||
img = None
|
||||
for match in matchList:
|
||||
img = imageLoad(match[0]) # 0 - first, 0 - pathname
|
||||
if img != None:
|
||||
break
|
||||
return img
|
||||
|
||||
# No go.
|
||||
if VERBOSE: print '\t\tImage Not Found after looking everywhere! "%s"' % imagePath
|
||||
return imageLoad(imagePath) # Will jus treturn a placeholder.
|
||||
@@ -0,0 +1,228 @@
|
||||
# $Id: BPyMathutils.py 20333 2009-05-22 03:45:46Z campbellbarton $
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# helper functions to be used by other scripts
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
from Blender.Mathutils import *
|
||||
|
||||
# ------ Mersenne Twister - start
|
||||
|
||||
# Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura.
|
||||
# Any feedback is very welcome. For any question, comments,
|
||||
# see http://www.math.keio.ac.jp/matumoto/emt.html or email
|
||||
# matumoto@math.keio.ac.jp
|
||||
|
||||
# The link above is dead, this is the new one:
|
||||
# http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/emt.html
|
||||
# And here the license info, from Mr. Matsumoto's site:
|
||||
# Until 2001/4/6, MT had been distributed under GNU Public License,
|
||||
# but after 2001/4/6, we decided to let MT be used for any purpose, including
|
||||
# commercial use. 2002-versions mt19937ar.c, mt19937ar-cok.c are considered
|
||||
# to be usable freely.
|
||||
#
|
||||
# So from the year above (1997), this code is under GPL.
|
||||
|
||||
# Period parameters
|
||||
N = 624
|
||||
M = 397
|
||||
MATRIX_A = 0x9908b0dfL # constant vector a
|
||||
UPPER_MASK = 0x80000000L # most significant w-r bits
|
||||
LOWER_MASK = 0x7fffffffL # least significant r bits
|
||||
|
||||
# Tempering parameters
|
||||
TEMPERING_MASK_B = 0x9d2c5680L
|
||||
TEMPERING_MASK_C = 0xefc60000L
|
||||
|
||||
def TEMPERING_SHIFT_U(y):
|
||||
return (y >> 11)
|
||||
|
||||
def TEMPERING_SHIFT_S(y):
|
||||
return (y << 7)
|
||||
|
||||
def TEMPERING_SHIFT_T(y):
|
||||
return (y << 15)
|
||||
|
||||
def TEMPERING_SHIFT_L(y):
|
||||
return (y >> 18)
|
||||
|
||||
mt = [] # the array for the state vector
|
||||
mti = N+1 # mti==N+1 means mt[N] is not initialized
|
||||
|
||||
# initializing the array with a NONZERO seed
|
||||
def sgenrand(seed):
|
||||
# setting initial seeds to mt[N] using
|
||||
# the generator Line 25 of Table 1 in
|
||||
# [KNUTH 1981, The Art of Computer Programming
|
||||
# Vol. 2 (2nd Ed.), pp102]
|
||||
|
||||
global mt, mti
|
||||
|
||||
mt = []
|
||||
|
||||
mt.append(seed & 0xffffffffL)
|
||||
for i in xrange(1, N + 1):
|
||||
mt.append((69069 * mt[i-1]) & 0xffffffffL)
|
||||
|
||||
mti = i
|
||||
# end sgenrand
|
||||
|
||||
|
||||
def genrand():
|
||||
global mt, mti
|
||||
|
||||
mag01 = [0x0L, MATRIX_A]
|
||||
# mag01[x] = x * MATRIX_A for x=0,1
|
||||
y = 0
|
||||
|
||||
if mti >= N: # generate N words at one time
|
||||
if mti == N+1: # if sgenrand() has not been called,
|
||||
sgenrand(4357) # a default initial seed is used
|
||||
|
||||
for kk in xrange((N-M) + 1):
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK)
|
||||
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1]
|
||||
|
||||
for kk in xrange(kk, N):
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK)
|
||||
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1]
|
||||
|
||||
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK)
|
||||
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1]
|
||||
|
||||
mti = 0
|
||||
|
||||
y = mt[mti]
|
||||
mti += 1
|
||||
y ^= TEMPERING_SHIFT_U(y)
|
||||
y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B
|
||||
y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C
|
||||
y ^= TEMPERING_SHIFT_L(y)
|
||||
|
||||
return ( float(y) / 0xffffffffL ) # reals
|
||||
|
||||
#------ Mersenne Twister -- end
|
||||
|
||||
|
||||
|
||||
|
||||
""" 2d convexhull
|
||||
Based from Dinu C. Gherman's work,
|
||||
modified for Blender/Mathutils by Campell Barton
|
||||
"""
|
||||
######################################################################
|
||||
# Public interface
|
||||
######################################################################
|
||||
def convexHull(point_list_2d):
|
||||
"""Calculate the convex hull of a set of vectors
|
||||
The vectors can be 3 or 4d but only the Xand Y are used.
|
||||
returns a list of convex hull indicies to the given point list
|
||||
"""
|
||||
|
||||
######################################################################
|
||||
# Helpers
|
||||
######################################################################
|
||||
|
||||
def _myDet(p, q, r):
|
||||
"""Calc. determinant of a special matrix with three 2D points.
|
||||
|
||||
The sign, "-" or "+", determines the side, right or left,
|
||||
respectivly, on which the point r lies, when measured against
|
||||
a directed vector from p to q.
|
||||
"""
|
||||
return (q.x*r.y + p.x*q.y + r.x*p.y) - (q.x*p.y + r.x*q.y + p.x*r.y)
|
||||
|
||||
def _isRightTurn((p, q, r)):
|
||||
"Do the vectors pq:qr form a right turn, or not?"
|
||||
#assert p[0] != q[0] and q[0] != r[0] and p[0] != r[0]
|
||||
if _myDet(p[0], q[0], r[0]) < 0:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
# Get a local list copy of the points and sort them lexically.
|
||||
points = [(p, i) for i, p in enumerate(point_list_2d)]
|
||||
|
||||
try: points.sort(key = lambda a: (a[0].x, a[0].y))
|
||||
except: points.sort(lambda a,b: cmp((a[0].x, a[0].y), (b[0].x, b[0].y)))
|
||||
|
||||
# Build upper half of the hull.
|
||||
upper = [points[0], points[1]] # cant remove these.
|
||||
for i in xrange(len(points)-2):
|
||||
upper.append(points[i+2])
|
||||
while len(upper) > 2 and not _isRightTurn(upper[-3:]):
|
||||
del upper[-2]
|
||||
|
||||
# Build lower half of the hull.
|
||||
points.reverse()
|
||||
lower = [points.pop(0), points.pop(1)]
|
||||
for p in points:
|
||||
lower.append(p)
|
||||
while len(lower) > 2 and not _isRightTurn(lower[-3:]):
|
||||
del lower[-2]
|
||||
|
||||
# Concatenate both halfs and return.
|
||||
return [p[1] for ls in (upper, lower) for p in ls]
|
||||
|
||||
|
||||
def plane2mat(plane, normalize= False):
|
||||
'''
|
||||
Takes a plane and converts to a matrix
|
||||
points between 0 and 1 are up
|
||||
1 and 2 are right
|
||||
assumes the plane has 90d corners
|
||||
'''
|
||||
cent= (plane[0]+plane[1]+plane[2]+plane[3] ) /4.0
|
||||
|
||||
|
||||
up= cent - ((plane[0]+plane[1])/2.0)
|
||||
right= cent - ((plane[1]+plane[2])/2.0)
|
||||
z= up.cross(right)
|
||||
|
||||
if normalize:
|
||||
up.normalize()
|
||||
right.normalize()
|
||||
z.normalize()
|
||||
|
||||
mat= Matrix(up, right, z)
|
||||
|
||||
# translate
|
||||
mat.resize4x4()
|
||||
tmat= Blender.Mathutils.TranslationMatrix(cent)
|
||||
return mat * tmat
|
||||
|
||||
|
||||
# Used for mesh_solidify.py and mesh_wire.py
|
||||
|
||||
# returns a length from an angle
|
||||
# Imaging a 2d space.
|
||||
# there is a hoz line at Y1 going to inf on both X ends, never moves (LINEA)
|
||||
# down at Y0 is a unit length line point up at (angle) from X0,Y0 (LINEB)
|
||||
# This function returns the length of LINEB at the point it would intersect LINEA
|
||||
# - Use this for working out how long to make the vector - differencing it from surrounding faces,
|
||||
# import math
|
||||
from math import pi, sin, cos, sqrt
|
||||
|
||||
def angleToLength(angle):
|
||||
# Alredy accounted for
|
||||
if angle < 0.000001: return 1.0
|
||||
else: return abs(1.0 / cos(pi*angle/180));
|
||||
1326
src_research_readme/blender_2.43_scripts/bpymodules/BPyMesh.py
Normal file
1326
src_research_readme/blender_2.43_scripts/bpymodules/BPyMesh.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,652 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# (C) Copyright 2006 MetaVR, Inc.
|
||||
# http://www.metavr.com
|
||||
# Written by Campbell Barton
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender
|
||||
import bpy
|
||||
Vector= Blender.Mathutils.Vector
|
||||
Ang= Blender.Mathutils.AngleBetweenVecs
|
||||
MidpointVecs= Blender.Mathutils.MidpointVecs
|
||||
import BPyMesh
|
||||
|
||||
# If python version is less than 2.4, try to get set stuff from module
|
||||
|
||||
try:
|
||||
set
|
||||
except:
|
||||
try:
|
||||
from sets import Set as set
|
||||
except:
|
||||
set= None
|
||||
|
||||
def uv_key(uv):
|
||||
return round(uv.x, 5), round(uv.y, 5)
|
||||
|
||||
def uv_key_mix(uv1, uv2, w1, w2):
|
||||
# Weighted mix. w1+w2==1.0
|
||||
return w1*uv1[0]+w2*uv2[0], w1*uv1[1]+w2*uv2[1]
|
||||
|
||||
def col_key(col):
|
||||
return col.r, col.g, col.b
|
||||
|
||||
def col_key_mix(col1, col2, w1, w2):
|
||||
# Weighted mix. w1+w2==1.0
|
||||
return int(w1*col1[0] + w2*col2[0]), int(w1*col1[1] + w2*col2[1]), int(w1*col1[2]+col2[2]*w2)
|
||||
|
||||
|
||||
def redux(ob, REDUX=0.5, BOUNDRY_WEIGHT=2.0, REMOVE_DOUBLES=False, FACE_AREA_WEIGHT=1.0, FACE_TRIANGULATE=True, DO_UV=True, DO_VCOL=True, DO_WEIGHTS=True, VGROUP_INF_REDUX= None, VGROUP_INF_WEIGHT=0.5):
|
||||
"""
|
||||
BOUNDRY_WEIGHT - 0 is no boundry weighting. 2.0 will make them twice as unlikely to collapse.
|
||||
FACE_AREA_WEIGHT - 0 is no weight. 1 is normal, 2.0 is higher.
|
||||
"""
|
||||
|
||||
if REDUX<0 or REDUX>1.0:
|
||||
raise 'Error, factor must be between 0 and 1.0'
|
||||
elif not set:
|
||||
raise 'Error, this function requires Python 2.4 or a full install of Python 2.3'
|
||||
|
||||
BOUNDRY_WEIGHT= 1+BOUNDRY_WEIGHT
|
||||
|
||||
""" # DEBUG!
|
||||
if Blender.Get('rt') == 1000:
|
||||
DEBUG=True
|
||||
else:
|
||||
DEBUG= False
|
||||
"""
|
||||
|
||||
me= ob.getData(mesh=1)
|
||||
me.hide= False # unhide all data,.
|
||||
if len(me.faces)<5:
|
||||
return
|
||||
|
||||
|
||||
|
||||
if FACE_TRIANGULATE or REMOVE_DOUBLES:
|
||||
me.sel= True
|
||||
|
||||
if FACE_TRIANGULATE:
|
||||
me.quadToTriangle()
|
||||
|
||||
if REMOVE_DOUBLES:
|
||||
me.remDoubles(0.0001)
|
||||
|
||||
vgroups= me.getVertGroupNames()
|
||||
|
||||
if not me.getVertGroupNames():
|
||||
DO_WEIGHTS= False
|
||||
|
||||
if (VGROUP_INF_REDUX!= None and VGROUP_INF_REDUX not in vgroups) or\
|
||||
VGROUP_INF_WEIGHT==0.0:
|
||||
VGROUP_INF_REDUX= None
|
||||
|
||||
try:
|
||||
VGROUP_INF_REDUX_INDEX= vgroups.index(VGROUP_INF_REDUX)
|
||||
except:
|
||||
VGROUP_INF_REDUX_INDEX= -1
|
||||
|
||||
# del vgroups
|
||||
len_vgroups= len(vgroups)
|
||||
|
||||
|
||||
|
||||
OLD_MESH_MODE= Blender.Mesh.Mode()
|
||||
Blender.Mesh.Mode(Blender.Mesh.SelectModes.VERTEX)
|
||||
|
||||
if DO_UV and not me.faceUV:
|
||||
DO_UV= False
|
||||
|
||||
if DO_VCOL and not me.vertexColors:
|
||||
DO_VCOL = False
|
||||
|
||||
current_face_count= len(me.faces)
|
||||
target_face_count= int(current_face_count * REDUX)
|
||||
# % of the collapseable faces to collapse per pass.
|
||||
#collapse_per_pass= 0.333 # between 0.1 - lots of small nibbles, slow but high q. and 0.9 - big passes and faster.
|
||||
collapse_per_pass= 0.333 # between 0.1 - lots of small nibbles, slow but high q. and 0.9 - big passes and faster.
|
||||
|
||||
"""# DEBUG!
|
||||
if DEBUG:
|
||||
COUNT= [0]
|
||||
def rd():
|
||||
if COUNT[0]< 330:
|
||||
COUNT[0]+=1
|
||||
return
|
||||
me.update()
|
||||
Blender.Window.RedrawAll()
|
||||
print 'Press key for next, count "%s"' % COUNT[0]
|
||||
try: input()
|
||||
except KeyboardInterrupt:
|
||||
raise "Error"
|
||||
except:
|
||||
pass
|
||||
|
||||
COUNT[0]+=1
|
||||
"""
|
||||
|
||||
class collapseEdge(object):
|
||||
__slots__ = 'length', 'key', 'faces', 'collapse_loc', 'v1', 'v2','uv1', 'uv2', 'col1', 'col2', 'collapse_weight'
|
||||
def __init__(self, ed):
|
||||
self.init_from_edge(ed) # So we can re-use the classes without using more memory.
|
||||
|
||||
def init_from_edge(self, ed):
|
||||
self.key= ed.key
|
||||
self.length= ed.length
|
||||
self.faces= []
|
||||
self.v1= ed.v1
|
||||
self.v2= ed.v2
|
||||
if DO_UV or DO_VCOL:
|
||||
self.uv1= []
|
||||
self.uv2= []
|
||||
self.col1= []
|
||||
self.col2= []
|
||||
|
||||
# self.collapse_loc= None # new collapse location.
|
||||
# Basic weighting.
|
||||
#self.collapse_weight= self.length * (1+ ((ed.v1.no-ed.v2.no).length**2))
|
||||
self.collapse_weight= 1.0
|
||||
|
||||
def collapse_locations(self, w1, w2):
|
||||
'''
|
||||
Generate a smart location for this edge to collapse to
|
||||
w1 and w2 are vertex location bias
|
||||
'''
|
||||
|
||||
v1co= self.v1.co
|
||||
v2co= self.v2.co
|
||||
v1no= self.v1.no
|
||||
v2no= self.v2.no
|
||||
|
||||
# Basic operation, works fine but not as good as predicting the best place.
|
||||
#between= ((v1co*w1) + (v2co*w2))
|
||||
#self.collapse_loc= between
|
||||