Added research data, testing blender mesh generation

This commit is contained in:
itdominator 2021-05-23 15:34:33 -05:00
parent f2efb7c42d
commit 505df54a1e
205 changed files with 124004 additions and 40 deletions

View File

@ -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'}

View File

@ -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")

View File

@ -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()

View File

@ -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)

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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()

File diff suppressed because it is too large Load Diff

View 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')

View 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

View 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