diff --git a/SConstruct b/SConstruct index 2a8adac2338..7e9e0344c3a 100644 --- a/SConstruct +++ b/SConstruct @@ -74,8 +74,8 @@ if not use_color=='1': #on defaut white Os X terminal, some colors are totally unlegible if platform=='darwin': - B.bc.OKGREEN = '\033[34m' - B.bc.WARNING = '\033[36m' + B.bc.OKGREEN = '\033[34m' + B.bc.WARNING = '\033[36m' # arguments print B.bc.HEADER+'Command-line arguments'+B.bc.ENDC @@ -115,6 +115,8 @@ if toolset: env.Tool('mstoolkit', ['tools']) else: env = BlenderEnvironment(tools=[toolset], ENV = os.environ) + if env: + btools.SetupSpawn(env) else: env = BlenderEnvironment(ENV = os.environ) @@ -122,7 +124,7 @@ if not env: print "Could not create a build environment" Exit() -env.SConscriptChdir(0) + cc = B.arguments.get('CC', None) cxx = B.arguments.get('CXX', None) if cc: @@ -135,53 +137,7 @@ if env['CC'] in ['cl', 'cl.exe'] and sys.platform=='win32': elif env['CC'] in ['gcc'] and sys.platform=='win32': platform = 'win32-mingw' -# Fix me! -#if platform == 'win32-mingw': -if 0: - try: - import win32file - import win32event - import win32process - import win32security - import string - - slash= re.compile(r"\\") - - def myesc(b): - if b[0]!= "-": - b = slash.sub(r"\\\\", b[1:-1]) - return "\"" + b + "\"" - else: - return b - - def my_spawn(sh, escape, cmd, args, spawnenv): - for var in spawnenv: - spawnenv[var] = spawnenv[var].encode('ascii', 'replace') - - sAttrs = win32security.SECURITY_ATTRIBUTES() - StartupInfo = win32process.STARTUPINFO() - if cmd=='ar' and args[1]=='r': - args[1] = '-r' - newargs = string.join(map(myesc, args[1:]), ' ') - cmdline = cmd + " " + newargs - - # check for any special operating system commands - if cmd == 'del': - for arg in args[1:]: - win32file.DeleteFile(arg) - exit_code = 0 - else: - # otherwise execute the command. - hProcess, hThread, dwPid, dwTid = win32process.CreateProcess(None, cmdline, None, None, 1, 0, spawnenv, None, StartupInfo) - win32event.WaitForSingleObject(hProcess, win32event.INFINITE) - exit_code = win32process.GetExitCodeProcess(hProcess) - win32file.CloseHandle(hProcess); - win32file.CloseHandle(hThread); - return exit_code - - env['SPAWN'] = my_spawn - except: - print "install win32all from http://sourceforge.net/project/showfiles.php?group_id=78018" +env.SConscriptChdir(0) crossbuild = B.arguments.get('BF_CROSS', None) if crossbuild and platform!='win32': @@ -278,170 +234,6 @@ env['BUILDDIR'] = B.root_build_dir if not B.root_build_dir[-1]==os.sep: B.root_build_dir += os.sep -def NSIS_Installer(): - - if env['OURPLATFORM'] != 'win32-vc' and env['OURPLATFORM'] != 'win32-mingw': - print "NSIS installer is only available on Windows." - Exit() - - install_base_dir = os.getcwd() + "\\" - - if not os.path.exists(install_base_dir+env['BF_INSTALLDIR']+'/plugins/include'): - os.mkdir(install_base_dir+env['BF_INSTALLDIR']+'/plugins/include') - - for f in glob.glob('source/blender/blenpluginapi/*.h'): - shutil.copy(f,install_base_dir+env['BF_INSTALLDIR']+'/plugins/include') - - shutil.copy('source/blender/blenpluginapi/plugin.def',install_base_dir+env['BF_INSTALLDIR']+'/plugins/include/') - - os.chdir("release") - v = open("VERSION") - version = v.read()[:-1] - shortver = version.split('.')[0] + version.split('.')[1] - v.close() - - #### change to suit install dir #### - inst_dir = install_base_dir + env['BF_INSTALLDIR'] - - os.chdir("windows/installer") - - ns = open("00.sconsblender.nsi","r") - - ns_cnt = str(ns.read()) - ns.close() - - # do root - rootlist = [] - rootdir = os.listdir(inst_dir+"\\") - for rootitem in rootdir: - if os.path.isdir(inst_dir+"\\"+ rootitem) == 0: - rootlist.append("File " + inst_dir + "\\" + rootitem) - rootstring = string.join(rootlist, "\n ") - rootstring += "\n\n" - ns_cnt = string.replace(ns_cnt, "[ROOTDIRCONTS]", rootstring) - - # do delete items - delrootlist = [] - for rootitem in rootdir: - if os.path.isdir(inst_dir + rootitem) == 0: - delrootlist.append("Delete $INSTDIR\\" + rootitem) - delrootstring = string.join(delrootlist, "\n ") - delrootstring += "\n" - ns_cnt = string.replace(ns_cnt, "[DELROOTDIRCONTS]", delrootstring) - - # do scripts - scriptlist = [] - scriptpath = "%s%s" % (inst_dir, "\\.blender\\scripts") - scriptdir = os.listdir(scriptpath) - for scriptitem in scriptdir: - scriptfile = "%s\\%s" % (scriptpath, scriptitem) - if os.path.isdir(scriptfile) == 0: - scriptlist.append("File %s" % scriptfile) - scriptstring = string.join(scriptlist, "\n ") - scriptstring += "\n\n" - ns_cnt = string.replace(ns_cnt, "[SCRIPTCONTS]", scriptstring) - - # do scripts\bpymodules - bpymodlist = [] - bpymodpath = "%s%s" % (inst_dir, "\\.blender\\scripts\\bpymodules") - bpymoddir = os.listdir(bpymodpath) - - for bpymoditem in bpymoddir: - bpymodfile = "%s\\%s" % (bpymodpath, bpymoditem) - if os.path.isdir(bpymodfile) == 0: - bpymodlist.append("File %s" % bpymodfile) - bpymodstring = string.join(bpymodlist, "\n ") - bpymodstring += "\n\n" - ns_cnt = string.replace(ns_cnt, "[SCRIPTMODCONTS]", bpymodstring) - - # do scripts\bpymodules\colladaimex - colladalist = [] - bpymodpath = "%s%s" % (inst_dir, "\\.blender\\scripts\\bpymodules\\ColladaImEx") - bpymoddir = os.listdir(bpymodpath) - - for bpymoditem in bpymoddir: - bpymodfile = "%s\\%s" % (bpymodpath, bpymoditem) - if os.path.isdir(bpymodfile) == 0: - colladalist.append("File %s" % bpymodfile) - bpymodstring = string.join(colladalist, "\n ") - bpymodstring += "\n\n" - ns_cnt = string.replace(ns_cnt, "[SCRIPTMODCOLLADACONT]", bpymodstring) - - # do scripts\bpydata - bpydatalist = [] - bpydatapath = "%s%s" % (inst_dir, "\\.blender\\scripts\\bpydata") - bpydatadir = os.listdir(bpydatapath) - for bpydataitem in bpydatadir: - bpydatafile = "%s\\%s" % (bpydatapath, bpydataitem) - if os.path.isdir(bpydatafile) == 0: - bpydatalist.append("File %s" % bpydatafile) - bpydatastring = string.join(bpydatalist, "\n ") - bpydatastring += "\n\n" - ns_cnt = string.replace(ns_cnt, "[SCRIPTDATACONTS]", bpydatastring) - - # do plugins\include - plugincludelist = [] - plugincludepath = "%s%s" % (inst_dir, "\\plugins\\include") - plugincludedir = os.listdir(plugincludepath) - for plugincludeitem in plugincludedir: - plugincludefile = "%s\\%s" % (plugincludepath, plugincludeitem) - if os.path.isdir(plugincludefile) == 0: - if plugincludefile.find('.h') or plugincludefile.find('.DEF'): - plugincludelist.append("File %s" % plugincludefile) - plugincludestring = string.join(plugincludelist, "\n ") - plugincludestring += "\n\n" - ns_cnt = string.replace(ns_cnt, "[PLUGINCONTS]", plugincludestring) - - # do scripts\bpydata\config - cfglist = [] - cfgpath = "%s%s" % (inst_dir, "\\.blender\\scripts\\bpydata\\config") - cfgdir = os.listdir(cfgpath) - for cfgitem in cfgdir: - cfgfile = "%s\\%s" % (cfgpath, cfgitem) - if os.path.isdir(cfgfile) == 0: - cfglist.append("File %s" % cfgfile) - cfgstring = string.join(cfglist, "\n ") - cfgstring += "\n\n" - ns_cnt = string.replace(ns_cnt, "[SCRIPTDATACFGCONTS]", cfgstring) - - # do dotblender - dotblendlist = [] - dotblenddir = os.listdir(inst_dir+"\\.blender") - for dotblenditem in dotblenddir: - if os.path.isdir(inst_dir + "\\.blender\\" + dotblenditem) == 0: - dotblendlist.append("File " + inst_dir + "\\.blender\\" + dotblenditem) - dotblendstring = string.join(dotblendlist, "\n ") - dotblendstring += "\n\n" - ns_cnt = string.replace(ns_cnt, "[DOTBLENDERCONTS]", dotblendstring) - - # do language files - langlist = [] - langfiles = [] - langdir = os.listdir(inst_dir + "\\.blender\\locale") - for langitem in langdir: - if os.path.isdir(inst_dir + "\\.blender\\locale\\" + langitem) == 1: - langfiles.append("SetOutPath $BLENDERHOME\\.blender\\locale\\" + langitem + "\\LC_MESSAGES") - langfiles.append("File " + inst_dir + "\\.blender\\locale\\" + langitem + "\\LC_MESSAGES\\blender.mo") - langstring = string.join(langfiles, "\n ") - langstring += "\n\n" - ns_cnt = string.replace(ns_cnt, "[LANGUAGECONTS]", langstring) - - # var replacements - ns_cnt = string.replace(ns_cnt, "DISTDIR", inst_dir+"\\") - ns_cnt = string.replace(ns_cnt, "SHORTVER", shortver) - ns_cnt = string.replace(ns_cnt, "VERSION", version) - - new_nsis = open("00.blender_tmp.nsi", 'w') - new_nsis.write(ns_cnt) - new_nsis.close() - - sys.stdout = os.popen("makensis 00.blender_tmp.nsi", 'w') - -nsis_build = None -if 'nsis' in B.targets: - NSIS_Installer() - Exit() - # We do a shortcut for clean when no quicklist is given: just delete # builddir without reading in SConscripts do_clean = None @@ -484,8 +276,6 @@ B.init_lib_dict() ##### END SETUP ########## Export('env') -#Export('root_build_dir') # this one is still needed for makesdna -##TODO: improve makesdna usage BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0) SConscript(B.root_build_dir+'/intern/SConscript') @@ -624,6 +414,10 @@ if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'): installtarget = env.Alias('install', allinstall) bininstalltarget = env.Alias('install-bin', blenderinstall) +nsisaction = env.Action(btools.NSIS_Installer, btools.NSIS_print) +nsiscmd = env.Command('nsisinstaller', None, nsisaction) +nsisalias = env.Alias('nsis', nsiscmd) + if env['WITH_BF_PLAYER']: blenderplayer = env.Alias('blenderplayer', B.program_list) Depends(blenderplayer,installtarget) @@ -632,6 +426,8 @@ if not env['WITH_BF_GAMEENGINE']: blendernogame = env.Alias('blendernogame', B.program_list) Depends(blendernogame,installtarget) +Depends(nsiscmd, allinstall) + Default(B.program_list) Default(installtarget) diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index c0f7245eff1..f8f9a8d4735 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -343,6 +343,7 @@ typedef void (*GHOST_NDOFLibraryShutdown_fp)(void* deviceHandle); typedef void* (*GHOST_NDOFDeviceOpen_fp)(void* platformData); typedef int (*GHOST_NDOFEventHandler_fp)(float* result7, void* deviceHandle, unsigned int message, unsigned int* wParam, unsigned long* lParam); +/* original patch used floats, but the driver return ints and uns. We will calibrate in view, no sense on doing conversions twice */ typedef struct { /** N-degree of freedom device data */ float tx, ty, tz; /** -x left, +y up, +z forward */ diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp index 86a9b56c7cc..3ac3d483d18 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.cpp +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -46,6 +46,7 @@ GHOST_NDOFManager::GHOST_NDOFManager() ndofLibraryShutdown = 0; ndofDeviceOpen = 0; ndofEventHandler = 0; + // available = 0; } GHOST_NDOFManager::~GHOST_NDOFManager() @@ -69,9 +70,9 @@ GHOST_NDOFManager::deviceOpen(GHOST_IWindow* window, ndofDeviceOpen = setNdofDeviceOpen; ndofEventHandler = setNdofEventHandler; - if (ndofLibraryInit) + if (ndofLibraryInit && ndofDeviceOpen) { - ndofLibraryInit(); + printf("%i client \n", ndofLibraryInit()); } /* if (ndofDeviceOpen) @@ -96,6 +97,7 @@ GHOST_NDOFManager::handle(unsigned int message, unsigned int* wParam, unsigned l { handled = ndofEventHandler(&sbdata.tx, m_DeviceHandle, message, wParam, lParam); } + printf("handled %i\n", handled); return handled ? &sbdata : 0; } @@ -105,3 +107,4 @@ GHOST_NDOFManager::available() { return m_DeviceHandle != 0; } + diff --git a/intern/ghost/intern/GHOST_WindowCarbon.cpp b/intern/ghost/intern/GHOST_WindowCarbon.cpp index 9b0ccf37ef0..04debe36191 100644 --- a/intern/ghost/intern/GHOST_WindowCarbon.cpp +++ b/intern/ghost/intern/GHOST_WindowCarbon.cpp @@ -49,20 +49,22 @@ AGLContext GHOST_WindowCarbon::s_firstaglCtx = NULL; const GHOST_TInt32 GHOST_WindowCarbon::s_sizeRectSize = 16; #endif //GHOST_DRAW_CARBON_GUTTER -static const GLint sPreferredFormatWindow[9] = { -AGL_RGBA, GL_TRUE, -AGL_DOUBLEBUFFER, GL_TRUE, -AGL_DEPTH_SIZE, 16, +static const GLint sPreferredFormatWindow[8] = { +AGL_RGBA, +AGL_DOUBLEBUFFER, +AGL_ACCELERATED, +AGL_DEPTH_SIZE, 32, AGL_AUX_BUFFERS, 1, AGL_NONE, }; -static const GLint sPreferredFormatFullScreen[7] = { +static const GLint sPreferredFormatFullScreen[9] = { AGL_RGBA, AGL_DOUBLEBUFFER, AGL_ACCELERATED, AGL_FULLSCREEN, -AGL_DEPTH_SIZE, 16, +AGL_DEPTH_SIZE, 32, +AGL_AUX_BUFFERS, 1, AGL_NONE, }; diff --git a/release/scripts/DirectX8Importer.py b/release/scripts/DirectX8Importer.py index 61ae12e8a7e..7e6a8429759 100644 --- a/release/scripts/DirectX8Importer.py +++ b/release/scripts/DirectX8Importer.py @@ -23,7 +23,7 @@ Tip: 'Import from DirectX text file format format.' # 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 NMesh,Object,Material,Texture,Image,Draw @@ -33,123 +33,102 @@ class xImport: global my_path self.file = open(filename, "r") my_path = Blender.sys.dirname(filename) - self.lines = self.file.readlines() + + # + 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 = Blender.Scene.getCurrent() + scene = bpy.data.scenes.active mesh = NMesh.GetRaw() #Get the line of Texture Coords nr_uv_ind = 0 - for line_uv in lines: - l = line_uv.strip() - words = line_uv.split() - if l and words[0] == "MeshTextureCoords" : - nr_uv_ind = lines.index(line_uv) - - - - #Get Materials + + #Get Materials + nr_fac_mat = 0 idx = 0 i = -1 mat_list = [] tex_list = [] - for line_mat in lines: - i += 1 - l = line_mat.strip() - words = line_mat.split() - if l and words[0] == "Material" : - idx += 1 - self.writeMaterials(i, idx, mat_list, tex_list) - - - - nr_fac_mat = 0 - #Assign Materials - for line_m in lines: - l = line_m.strip() - words = line_m.split() - if l and words[0] == "MeshMaterialList" : - nr_fac_mat = lines.index(line_m) + 2 - - #Create The Mesh - for line in lines: + mesh_line_indicies = [] + for j, line in enumerate(lines): l = line.strip() - words = line.split() - if l and words[0] == "Mesh" : - nr_vr_ind = lines.index(line) - self.writeVertices(nr_vr_ind, mesh, nr_uv_ind, nr_fac_mat, tex_list) - - - NMesh.PutRaw(mesh,"Mesh",1) + words = line.split() + if words[0] == "Material" : + idx += 1 + self.writeMaterials(j, idx, mat_list, tex_list) + elif words[0] == "MeshTextureCoords" : + nr_uv_ind = j + elif words[0] == "MeshMaterialList" : + nr_fac_mat = j + 2 + elif words[0] == "Mesh": # Avoid a second loop + mesh_line_indicies.append(j) + + #Create The Mesh + for nr_vr_ind in mesh_line_indicies: + self.writeVertices(nr_vr_ind, mesh, nr_uv_ind, nr_fac_mat, tex_list) + mesh.setMaterials(mat_list) - mesh.update() - - if nr_fac_mat : + if nr_fac_mat: self.writeMeshMaterials(nr_fac_mat, mesh) - + NMesh.PutRaw(mesh,"Mesh",1) + self.file.close() print "... finished" - + #------------------------------------------------------------------------------ # CREATE THE MESH #------------------------------------------------------------------------------ def writeVertices(self, nr_vr_ind, mesh, nr_uv, nr_fac_mat, tex_list): - - lin = self.lines[nr_vr_ind + 1] + v_ind = nr_vr_ind + 1 + lin = self.lines[v_ind] if lin : - lin_c = self.CleanLine(lin) + lin_c = self.CleanLine(lin) nr_vert = int((lin_c.split()[0])) - v_ind = self.lines.index(lin) else : - lin = self.lines.index(nr_vr_ind + 2) - lin_c = self.CleanLine(lin) + v_ind = nr_vr_ind + 2 + lin = self.lines[v_ind] + lin_c = self.CleanLine(lin) nr_vert = int((lin_c.split()[0])) - v_ind = self.lines.index(lin) - + vx_array = range(v_ind + 1, (v_ind + nr_vert +1)) #-------------------------------------------------- - lin_f = self.lines[v_ind + nr_vert +1] + nr_fac_li = v_ind + nr_vert +1 + lin_f = self.lines[nr_fac_li] if lin_f : - lin_fc = self.CleanLine(lin_f) + lin_fc = self.CleanLine(lin_f) nr_face = int((lin_fc.split()[0])) - nr_fac_li = self.lines.index(lin_f) else : - lin_f = self.lines[v_ind + nr_vert +1] - lin_fc = self.CleanLine(lin_f) + 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])) - nr_fac_li = self.lines.index(lin_f) - - - fac_array = range(nr_fac_li + 1, (nr_fac_li + nr_face + 1)) - #Get Coordinates + + fac_array = range(nr_fac_li + 1, (nr_fac_li + nr_face + 1)) + #Get Coordinates for l in vx_array: line_v = self.lines[l] lin_v = self.CleanLine(line_v) - words = lin_v.split() + words = lin_v.split() if len(words)==3: - co_vert_x = float(words[0]) - co_vert_y = float(words[1]) - co_vert_z = float(words[2]) - v=NMesh.Vert(co_vert_x,co_vert_y,co_vert_z) - mesh.verts.append(v) - - - + mesh.verts.append(NMesh.Vert(float(words[0]),float(words[1]),float(words[2]))) + #Make Faces i = 0 + mesh_verts = mesh.verts for f in fac_array: i += 1 line_f = self.lines[f] lin_f = self.CleanLine(line_f) - words = lin_f.split() - if len(words) == 5: - f=NMesh.Face() - f.v.append(mesh.verts[int(words[1])]) - f.v.append(mesh.verts[int(words[2])]) - f.v.append(mesh.verts[int(words[3])]) - f.v.append(mesh.verts[int(words[4])]) + words = lin_f.split() + if len(words) == 5: + f= NMesh.Face([\ + mesh_verts[int(words[1])], + mesh_verts[int(words[2])], + mesh_verts[int(words[3])], + mesh_verts[int(words[4])]]) + mesh.faces.append(f) if nr_uv : uv = [] @@ -193,12 +172,13 @@ class xImport: #Draw.PupMenu("No image to load") #print "No image " + name_tex + " to load" pass - - elif len(words) == 4: - f=NMesh.Face() - f.v.append(mesh.verts[int(words[1])]) - f.v.append(mesh.verts[int(words[2])]) - f.v.append(mesh.verts[int(words[3])]) + + elif len(words) == 4: + f=NMesh.Face([\ + mesh_verts[int(words[1])],\ + mesh_verts[int(words[2])],\ + mesh_verts[int(words[3])]]) + mesh.faces.append(f) if nr_uv : uv = [] @@ -236,10 +216,10 @@ class xImport: #Draw.PupMenu("No image to load") #print "No image " + name_tex + " to load" pass - - - - + + + + def CleanLine(self,line): fix_line = line.replace(";", " ") fix_1_line = fix_line.replace('"', ' ') @@ -248,7 +228,7 @@ class xImport: fix_4_line = fix_3_line.replace(",", " ") fix_5_line = fix_4_line.replace("'", " ") return fix_5_line - + #------------------------------------------------------------------ # CREATE MATERIALS #------------------------------------------------------------------ @@ -257,21 +237,21 @@ class xImport: mat = Material.New(name) line = self.lines[nr_mat + 1] fixed_line = self.CleanLine(line) - words = fixed_line.split() + 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(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() @@ -279,7 +259,7 @@ class xImport: else : tex_name = None tex_list.append(tex_name) - + return mat_list, tex_list #------------------------------------------------------------------ # SET MATERIALS @@ -292,10 +272,8 @@ class xImport: wrd = fixed_line.split() mat_idx = int(wrd[0]) face.materialIndex = mat_idx - mesh.update() - - - + + #------------------------------------------------------------------ # MAIN #------------------------------------------------------------------ @@ -308,4 +286,4 @@ arg = __script__['arg'] if __name__ == '__main__': Blender.Window.FileSelector(my_callback, "Import DirectX", "*.x") - \ No newline at end of file +# my_callback('/directxterrain.x') diff --git a/release/scripts/export_m3g.py b/release/scripts/export_m3g.py new file mode 100644 index 00000000000..afb019fcc1e --- /dev/null +++ b/release/scripts/export_m3g.py @@ -0,0 +1,3047 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'M3G (.m3g, .java)...' +Blender: 244 +Group: 'Export' +Tooltip: 'Export to M3G' +""" +#------------------------------------------------------------------------ +# M3G exporter for blender 2.37 or above +# +# Source: http://www.nelson-games.de/bl2m3g/source +# +# $Id: m3g_export.py,v 0.1 2005/04/19 12:25 gerhardv Exp gerhardv $ +# +# Author: Gerhard Völkl +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2005: gerhard völkl gkvoelkl@yahoo.de +# +# 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 ***** +# +# To use script: +# 1.) load this file in the text window. +# (press SHIFT+F11, Open New via Datablock button) +# 2.) make sure your mouse is over the text edit window and +# run this script. (press ALT+P) +# Or: +# copy to the scripts directory and it will appear in the +# export list. (Needs 2.32 or higher) +# +# Based on informations from: +# wrl2export.py from Rick Kimball and others +# --------------------------------------------------------------------------# +# History 0.2 +# * maximal Precision in VertexArray (with algorithms from Kalle Raita) +# * IPO Animation with mesh: Rotation, Translation and Size +# History 0.3 +# * to find a 3d object in your java programm you can assign a userID +# your blender object has name 'cube#01' your 3d object will have ID 01 +# the number after '#' is taken +# * more than one material per mesh can be used +# * uv texture support (implemented by Aki Koskinen and Juha Laitinen) +# The image which is bound to the faces will be exportet within m3g-file +# Limitations by M3G-API: +# The width and height of the image must be non-negative powers of two, +# but they need not to be equal. Maximum value is 256. +# *.java export: Only PNG images can be used. +# History 0.4 +# * check limitation of texture images (credit to MASTER_ZION for Brasil) +# * Better light: The light modeles of Blender and M3G are naturally +# different. So the export script trys to translate as much as possible +# +# M3G Light type Blender Light type +# -------------------------------------------------------------- +# AMIENT Light Not available as light type in Blender +# DIRECTIONAL Light SUN +# OMNIdirectional light LAMP +# SPOT light SPOT +# not translated HEMI +# not translated AREA +# +# Attributs of M3G Lights: +# +# Attenuation (OMNI,SPOT): +# Intensity of light changes with distance +# The attenuation factor is 1 / (c + l d + q d2) +# where d is the distance between the light and the vertex being lighted +# and c, l, q are the constant, linear, and quadratic coefficients. +# In Blender exists much complex posibilies. To simplify exporter uses +# only button Dist: distance at which the light intensity is half +# the Energy +# Color (ALL) +# Color of light +# Intensity (ALL) +# The RGB color of this Light is multiplied component-wise with the +# intensity. In Blender : energy +# SpotAngle (SPOT) +# the spot cone angle for this Light +# In Blender: spotSize +# SpotExponent (SPOT) +# The spot exponent controls the distribution of the intensity of +# this Light within the spot cone, such that larger values yield +# a more concentrated cone. In Blender: SpotBl +# +# * Some GUI for options +# First prototype of GUI was created using RipSting's Blender-Python +# GUI designer. Download at Http://oregonstate.edu/~dennisa/Blender/BPG/ +# +# * Ambiente light +# Information is taken by world ambiente attribute +# +# * Parenting Part 1 +# In Blender the Empty object is used to group objects. All objects +# which have the same empty as parent are the member of the same group. +# +# empty <-- Parent of -- element 1 +# <-- Parent of -- element 2 +# +# is translated in M3G +# +# group-Node -- Member --> element 1 +# -- Member --> element 2 +# +# In Blender every object can be the parent of every other object +# In M3G that is not possible. Only a group object can be parent. +# (Or the world object which is derived from group). +# That will come later as Parenting Part 2 +# +# * Backface Culling +# you can use backface culling, if option "use backface culloing" is on. +# Culling will be set in PolygonMode object of every mesh. The correct +# winding is controlled. +# History 0.5 +#* Bone Animation - Armature (Part 1) +# +# Armature is the skeleton for skinned meshes. It stores the bones in +# rest position (more information http://www.blender.org/cms/How_Armatures_work.634.0.html) +# You can work in Blender with bones and meshes in different ways. In +# this first attempt only the use of vertex groups is assisted. +# +# Blender-Objekts translated into M3G-Objects +# +# MESH SkinnedMesh +# | | +# v v +# ARMATURE Group +# | | +# v v +# BONE_1 Group +# Group_second +# | | +# V v +# BONE_2 Group +# Group_secound +# +# Every bone is translated into two groups at the moment, because +# the second bone is needed to do the animation in an easy way. +# +# The animations in Blender for meshes are stored in action objects. +# +# Blender Objects translated into M3G-Objects +# +# ARMATURE +# | activ +# v +# ACTION ANIMATIONCONTROLLER +# | 1..n ^ +# v ANIMATIONTRACK --> Group_second +# IPOs | +# v +# KEYSEQUENZE +# +# One action is translated into one animationcontroller. One IPO is +# translated in one KEYSEQUENZE and one ANIMATIONTRACK. +# +# At the moment only the active action of the armature object is translated. +# +#* Print Info, if type of light is used that is not supported +# +# History 0.5 +# +#* New Option exportAllAction (default value: false) +# If that option is true, all actions will be exported - not only the active +# action. +# At the moment you can only assign one action to one armature. +# To know which action is used with which armature the action +# needs a special name : +# #AE# + +# Example: Name of action : walk#A10E250#02 +# Name of armature : man#10 +# End Frame: 250 +# +# History 0.6 +# Include the same image only one time into the m3g-file +# +# All the following changes of this version was made by Claus Hoefele +# +#* Until now all vertices of the faces was been written. +# Now the vertices will be used again if possible: +# normal and texture coordinates of to vertices have to be the same +# +#* Smooth/solid shading can now be defined for every single material: +# in Editing panel (F9)>Link and Materials +# +#* This script uses now correctly the TexFace and Shadless Buttons in +# Shading panel (F5)>Material buttons>Material box. +# TexFace switches on/off the Export of texture coordinates. +# Shadeless does the some with the normal coordinates +# +#* The GUI was redesigned in a PupBlock +# +#* Options: +# +#** Texturing Enabled: Switches on/off export of textures and texture +# coordinates. Attention: the TextFace button switches only +# for one mesh +#** Texturing External: the textures will be included it mg3-file or +# exported in seperate file +#** Lighting Enabled: turns on/off export of lights and normal completly +# Attention: Shadeless only for one mesh +#** Persp. Correction: turns on/off perspective correction in PolygonMode. +#** Smooth Shading: turns on/off smooth shading in PolygonMode. +# +#* Textures in external references are used again (with ImageFactory) +# +#* Blender function: Double Sided button in Editing Context +# (F9)>Mesh panel) +# turn on/off PolygonMode.CULL_BACK anzuschalten. +# +#* Script ingnores meshes that have no faces +# +# History 0.7 +# +# * Exporter can work with texture coordinates greater 1 and smaller 0 +# +# * Adler32 did not work always correct. New implementation made. +# +# * Modul shutil is not needed any longer. Exporter has its own copy_file. +# (realized and inspired by ideasman_42 and Martin Neumann) +# --------------------------------------------------------------------------# +# TODO: Export only selected mesh +# TODO: Optimize Bones <--> Vertex Group mapping +# TODO: Compressed File +# TODO: MTex - Support +# TODO: By Rotating use SQUAD instead of Beziere. It's smoother +import Blender +from Blender import Types,Lamp,Material,Texture,Window,Registry,Draw +from Blender.BGL import * +from Blender.Object import * +from Blender.Camera import * +from Blender.Mesh import * +from array import array +import sys, struct, zlib +from inspect import * +from types import * +from Blender.Mathutils import * +from os.path import * +#import rpdb2 + +# ---- Helper Functions -------------------------------------------------------# +def copy_file(source, dest): + file = open(source, 'rb') + data = file.read() + file.close() + + file = open(dest, 'wb') + file.write(data) + file.close() + +def tracer(frame, event, arg): + '''Global trace function''' + if event=='call': + tmp = getargvalues(frame) + print event, frame.f_code.co_name, frame.f_lineno, \ + formatargvalues(tmp[0],tmp[1],tmp[2],tmp[3]) + elif event=='line': + print event, frame.f_code.co_name, frame.f_lineno + #print event, frame.f_code.co_name, frame.f_lineno, \ + # getsourcelines(frame.f_code)[frame.f_lineno] + elif event=='return': + print event, frame.f_code.co_name, frame.f_lineno, "->", arg + return tracer + +def doSearchDeep(inList,outList): + '''Does deepsearch for all elements in inList''' + for element in inList: + if element != None : outList = element.searchDeep(outList) + return outList + + +def getId(aObject): + ''' returns 0 if Object is None: M3G value for null''' + if aObject == None: return 0 + return aObject.id + +def toJavaBoolean(aValue): + ''' returns java equivalent to boolean''' + if aValue: + return 'true' + else : + return 'false' + +def sign(a): + if a<0 : return -1 + elif a>0 : return 1 + else : return 0 + +def isOrderClockWise(v,normal): + ''' returns true, if order of vertices is clockwise. Important for + culling ''' + # (v2-v0)x(v2-v1)=surface_normal + # + if type(v[0]) is Types.MVertType: + mNormal = TriangleNormal(Vector(v[0].co),Vector(v[1].co),Vector(v[2].co)) + else: + mNormal = TriangleNormal(Vector(v[0]),Vectot(v[1]),Vector(v[2])) + #print "normal ",mNormal.normalize() + #print "BNormal ",normal.normalize() + + # Do not use any longer. Blender does it correct + + result = (sign(normal.x)==sign(mNormal.x) and + sign(normal.y)==sign(mNormal.y) and + sign(normal.z)==sign(mNormal.z)) + #print "Result ",result + + return True + + +# ---- M3G Types --------------------------------------------------------------# +class M3GVertexList: + def __init__(self, wrapList): + self.mlist = wrapList + + def __getitem__(self, key): + item = self.mlist[key] + if type(item) is Types.MVertType: + result =(item.co[0],item.co[1],item.co[2]) + else: + result = item + return result + +class M3GBoneReference: + def __init__(self,first,count): + self.firstVertex=first #UInt32 + self.vertexCount=count #UInt32 + + +class M3GBone: + def __init__(self): + self.verts=[] #List of influenced verts + self.transformNode=None #ObjectIndex + self.references = [] #References to Verts that are needed + self.weight=0 #Int32 + + + def setVerts(self,aVerts): + self.verts = aVerts + self.createReferences() + + def createReferences(self): + #print "createReference::len(verts) ",len(self.verts) + if len(self.verts)==0: return #No Verts available + self.verts.sort() + ref = [] + list = [] + last = self.verts[0]-1 + count = 0 + for vert in self.verts: + #print "vert ",vert + if vert==last+1: + list.append(vert) + else: + ref.append(M3GBoneReference(list[0],len(list))) + #print list[0],len(list) + list=[vert] + last=vert + #print "list ",list + if len(list)>0: + ref.append(M3GBoneReference(list[0],len(list))) + self.references = ref + + +class M3GVector3D: + def __init__(self,ax=0.0,ay=0.0,az=0.0): + self.x = ax #Float32 + self.y = ay #Float32 + self.z = az #Float32 + + def writeJava(self): + return str(self.x)+"f, "+str(self.y)+"f, "+str(self.z)+"f" + + def getData(self): + return struct.pack("<3f",self.x,self.y,self.z) + + def getDataLength(self): + return struct.calcsize("<3f") + +class M3GMatrix: + """ A 4x4 generalized matrix. The 16 elements of the + matrix are output in the same order as they are + retrieved using the API Transform.get method. In + other words, in this order: + 0 1 2 3 + 4 5 6 7 + 8 9 10 11 + 12 13 14 15 """ + def __init__(self): + self.elements=16 * [0.0] #Float32 + + def identity(self): + self.elements[ 0] = 1.0 + self.elements[ 5] = 1.0 + self.elements[10] = 1.0 + self.elements[15] = 1.0 + + def getData(self): + return struct.pack('<16f',self.elements[0],self.elements[1], + self.elements[2],self.elements[3], + self.elements[4],self.elements[5], + self.elements[6],self.elements[7], + self.elements[8],self.elements[9], + self.elements[10],self.elements[11], + self.elements[12],self.elements[13], + self.elements[14],self.elements[15]) + + def getDataLength(self): + return struct.calcsize('<16f') + + +class M3GColorRGB: + """ A color, with no alpha information. Each compo- + nent is scaled so that 0x00 is 0.0, and 0xFF is 1.0. + """ + def __init__(self,ared=0,agreen=0,ablue=0): + self.red = ared #Byte + self.green = agreen #Byte + self.blue = ablue #Byte + + def writeJava(self): + return "0x"+("%02X%02X%02X%02X" % (0.0, self.red, self.green, self.blue)) + + def getData(self): + return struct.pack('3B',self.red,self.green,self.blue) + + def getDataLength(self): + return struct.calcsize('3B') + + +class M3GColorRGBA: + """ A color, with alpha information. Each component + is scaled so that 0x00 is 0.0, and 0xFF is 1.0. The + alpha value is scaled so that 0x00 is completely + transparent, and 0xFF is completely opaque. + """ + def __init__(self,ared=0,agreen=0,ablue=0,aalpha=0): + self.red = ared #Byte + self.green = agreen #Byte + self.blue = ablue #Byte + self.alpha = aalpha #Byte + + def writeJava(self): + return "0x"+("%02X%02X%02X%02X" % (self.alpha, self.red, self.green, self.blue)) + + def getData(self): + return struct.pack('4B',self.red,self.green,self.blue,self.alpha) + + def getDataLength(self): + return struct.calcsize('4B') + + +#ObjectIndex +#The index of a previously encountered object in +#the file. Although this is serialized as a single +#unsigned integer, it is included in the compound +#type list because of the additional semantic infor- +#mation embodied in its type. A value of 0 is +#reserved to indicate a null reference; actual object indices start from 1. Object indices must refer +#only to null or to an object which has already been +#created during the input deserialization of a file - +#they must be less than or equal to the index of the +#object in which they appear. Other values are dis- +#allowed and must be treated as errors. +#UInt32 +#index; + +# ---- M3G Proxy --------------------------------------------------------------- # +class M3GProxy: + def __init__(self): + self.name = "" + self.id=0 + self.ObjectType=0 + self.binaryFormat='' + + def __repr__(self): + return "<"+str(self.__class__)[9:] + ":" + str(self.name) + ":" + str(self.id) + ">" + + +class M3GHeaderObject(M3GProxy): + def __init__(self): + M3GProxy.__init__(self) + self.M3GHeaderObject_binaryFormat = ' 0: + value += struct.calcsize('<'+str(len(self.animationTracks))+'I') + return value + + def writeJava(self,aWriter,aCreate): + if aCreate : pass #Abstract! Could not be created + if len(self.animationTracks) > 0 : + aWriter.write(2) + for iTrack in self.animationTracks: + aWriter.write(2,"BL%i.addAnimationTrack(BL%i);" % (self.id,iTrack.id)) + + +class M3GTransformable(M3GObject3D): + def __init__(self): + M3GObject3D.__init__(self) + self.hasComponentTransform=False #Boolean + #IF hasComponentTransform==TRUE, THEN + self.translation=M3GVector3D(0,0,0) #Vector3D + self.scale=M3GVector3D(1,1,1) #Vector3D + self.orientationAngle=0 #Float32 + self.orientationAxis=M3GVector3D(0,0,0) #Vector3D undefined + #END + self.hasGeneralTransform=False #Boolean + #IF hasGeneralTransform==TRUE, THEN + self.transform = M3GMatrix() #Matrix identity + self.transform.identity() + #END + #If either hasComponentTransform or hasGeneralTransform is false, the omitted fields will be + #initialized to their default values (equivalent to an identity transform in both cases). + + def writeJava(self,aWriter,aCreate): + if aCreate: pass #Abstract Base Class! Cant't be created + M3GObject3D.writeJava(self,aWriter,False) + if self.hasGeneralTransform : + aWriter.write(2,"float[] BL%i_matrix = {" % (self.id)) + aWriter.writeList(self.transform.elements,4,"f") + aWriter.write(2,"};") + aWriter.write(2) + aWriter.write(2,"Transform BL%i_transform = new Transform();" % (self.id)) + aWriter.write(2,"BL%i_transform.set(BL%i_matrix);" % (self.id,self.id)) + aWriter.write(2,"BL%i.setTransform(BL%i_transform);" % (self.id,self.id)) + aWriter.write(2) + if self.hasComponentTransform: + aWriter.write(2,("BL%i.setTranslation("+self.translation.writeJava()+");") + %(self.id)) + + def getData(self): + data = M3GObject3D.getData(self) + data += struct.pack(" 1: + aWriter.write(2,"IndexBuffer[] BL%i_indexArray = {" % (self.id)) + aWriter.write(4,",".join(["BL%i" %(i.id) for i in self.indexBuffer ])) + aWriter.write(2," };") + aWriter.write(2) + aWriter.write(2,"Appearance[] BL%i_appearanceArray = {" % (self.id)) + aWriter.write(4,",".join(["BL%i" %(i.id) for i in self.appearance ])) + aWriter.write(2," };") + aWriter.write(2) + aWriter.write(2,"%s BL%i = new %s(BL%i,BL%i_indexArray,BL%i_appearanceArray%s);" % \ + (aClassName,self.id,aClassName,self.vertexBuffer.id, self.id,self.id,aExtension)) + else: + #print "indexBuffer", len(self.indexBuffer) + #print "appearance", len(self.appearance) + aWriter.write(2,"%s BL%i = new %s(BL%i,BL%i,BL%i%s);" % \ + (aClassName, + self.id, + aClassName, + self.vertexBuffer.id, + self.indexBuffer[0].id, + self.appearance[0].id, + aExtension)) + M3GNode.writeJava(self,aWriter,False) + aWriter.write(2) + + +class M3GSkinnedMesh(M3GMesh): + def __init__(self,aVertexBuffer=None, aIndexBuffer=[], aAppearance=[]): + M3GMesh.__init__(self,aVertexBuffer, aIndexBuffer, aAppearance) + self.ObjectType=16 + self.skeleton=None #ObjectIndex + self.bones={} + #print"M3GSkinnedMesh.__init__::self.vertexBuffer:",self.vertexBuffer + ##ObjectIndex skeleton; + ##UInt32 transformReferenceCount; + ##FOR each bone reference... + ## ObjectIndex transformNode; + ## UInt32 firstVertex; + ## UInt32 vertexCount; + ## Int32 weight; + ##END + + def searchDeep(self,alist): + alist = doSearchDeep([self.skeleton],alist) + return M3GMesh.searchDeep(self,alist) + + def addSecondBone(self): + secondBones = {} + for bone in self.bones.values(): + bone2 = M3GBone() + bone2.verts=bone.verts + bone.verts=[] + mGroup = M3GGroup() + mGroup.name=bone.transformNode.name+"_second" + bone2.transformNode=mGroup + bone2.references = bone.references + bone.references = [] + bone2.weight = bone.weight + bone.weight=0 + mGroup.children = bone.transformNode.children + bone.transformNode.children = [mGroup] + mGroup.animationTracks=bone.transformNode.animationTracks + bone.transformNode.animationTracks = [] + secondBones[bone.transformNode.name+"_second"]=bone2 + for bone in secondBones.values(): + self.bones[bone.transformNode.name] = bone + + def getBlenderIndexes(self): + #print "M3GSkinnedMesh.vertexBuffer:",self.vertexBuffer + return self.vertexBuffer.positions.blenderIndexes + + def writeJava(self,aWriter,aCreate): + self.writeBaseJava(aWriter,aCreate,"SkinnedMesh", + (",BL%i" % (self.skeleton.id))) + aWriter.write(2,"//Transforms") + for bone in self.bones.values(): + #print "bone: ", bone + #print "bone.references: ", bone.references + for ref in bone.references: + aWriter.write(2,"BL%i.addTransform(BL%i,%i,%i,%i);" % + (self.id, + bone.transformNode.id,bone.weight, + ref.firstVertex, ref.vertexCount)) + aWriter.write(2) + + def getDataLength(self): + value = M3GMesh.getDataLength(self) + value += struct.calcsize(' element[i] : minimum[i] = element[i] + if maximum[i] < element[i] : maximum[i] = element[i] + #print i, maximum[i],element[i] + lrange=[0,0,0] + maxRange=0.0 + maxDimension=-1 + for i in range(3): #set bias + lrange[i] = maximum[i]-minimum[i] + self.bias[i] = minimum[i]*0.5+maximum[i]*0.5 + #print "Bias",i,self.bias[i],"min-max",minimum[i],maximum[i],"lrang",lrange[i] + if lrange[i] > maxRange: + maxRange = lrange[i] + maxDimension=i + self.scale = maxRange/65533.0 + #print "MaxRange ",maxRange + #print "scale",self.scale + + + def internalAutoScaling(self): + print "internalAutoScaling" + #Already done? + print self.components.typecode + if not self.autoscaling or self.components.typecode!="f":return + #Find bais and scale + minimum=[] + maximum=[] + for i in range(self.componentCount): + minimum.append(self.components[i]) + maximum.append(self.components[i]) + for i in range(0,len(self.components),self.componentCount): + for j in range(self.componentCount): + if minimum[j] > self.components[i+j] : minimum[j] = self.components[i+j] + if maximum[j] < self.components[i+j] : maximum[j] = self.components[i+j] + #print "i+j=",i+j,"min=",minimum[j],"max=",maximum[j],"elem=",self.components[i+j] + #print "min=", minimum + #print "max=", maximum + lrange=[0] * self.componentCount + maxRange=0.0 + maxDimension=-1 + for i in range(self.componentCount): #set bias + lrange[i] = maximum[i]-minimum[i] + self.bias[i] = minimum[i]*0.5+maximum[i]*0.5 + #print "Bias",i,self.bias[i],"min-max",minimum[i],maximum[i],"lrang",lrange[i] + if lrange[i] > maxRange: + maxRange = lrange[i] + maxDimension=i + maxValue=(2**(8*self.componentSize)*1.0)-2.0 + #print "MaxValue=",maxValue + self.scale = maxRange/maxValue + #print "MaxRange ",maxRange + #print "scale",self.scale + #Copy Components + oldArray=self.components + self.components=self.createComponentArray() + for i in range(0,len(oldArray),self.componentCount): + for j in range(self.componentCount): + element=int((oldArray[i+j]-self.bias[j])/self.scale) + #print "element",element + self.components.append(element) + # Reverse t coordinate because M3G uses a different 2D coordinate system than Blender. + if self.uvmapping: + for i in range(0,len(self.components),2): + self.components[i]= int(self.components[i]*(-1)) + for i in range(len(self.components)): + if abs(self.components[i])>maxValue:raise Exception( i+". element too great/small!") + + def writeJava(self,aWriter,aCreate): + self.internalAutoScaling() + if aCreate: + aWriter.write(2,"// VertexArray " + self.name) + if self.componentSize == 1: + aWriter.write(2,"byte[] BL%i_array = {" % (self.id)) + else: + aWriter.write(2,"short[] BL%i_array = {" % (self.id)) + aWriter.writeList(self.components) + aWriter.write(2,"};") + aWriter.write(2) + aWriter.write(2,"VertexArray BL%i = new VertexArray(BL%i_array.length/%i,%i,%i);" % + (self.id,self.id, + self.componentCount,self.componentCount,self.componentSize)) + aWriter.write(2,"BL%i.set(0,BL%i_array.length/%i,BL%i_array);" % + (self.id,self.id,self.componentCount,self.id)) + M3GObject3D.writeJava(self,aWriter,False) + aWriter.write(2) + + + def getData(self): + self.internalAutoScaling() + self.vertexCount = len(self.components)/self.componentCount + data = M3GObject3D.getData(self) + data += struct.pack('<3BH',self.componentSize, + self.componentCount, + self.encoding, + self.vertexCount) + componentType = "" + if self.componentSize == 1: + componentType = "b" + else: + componentType = "h" + for element in self.components: + data += struct.pack('<'+componentType,element) + return data + + def getDataLength(self): + self.internalAutoScaling() + value = M3GObject3D.getDataLength(self) + value += struct.calcsize('<3BH') + componentType = "" + if self.componentSize == 1: + componentType = "b" + else: + componentType = "h" + value += struct.calcsize('<'+str(len(self.components))+componentType) + return value + + def append(self,element,index=None): + #print "type(element):",type(element) + if type(element) is Types.vectorType : + for i in range(3): + value = int((element[i]-self.bias[i])/self.scale) + #print "append:",i,element[i],(element[i]-self.bias[i]),value + self.components.append(value) + elif type(element) is Types.MVertType: + for i in range(3): + value = int((element.co[i]-self.bias[i])/self.scale) + #print "append:",i,element[i],(element[i]-self.bias[i]),value + self.components.append(value) + if index!=None: + key=str(len(self.blenderIndexes)) + #print"key,index:",key,index + self.blenderIndexes[key]=index + #print"blenderIndexes",self.blenderIndexes + else: + # print "VertexArray.append: element=",element + self.components.append(element) + +class M3GVertexBuffer(M3GObject3D): + def __init__(self): + M3GObject3D.__init__(self) + self.ObjectType=21 + self.defaultColor=M3GColorRGBA(255,255,255) #ColorRGBA 0xFFFFFFFF (opaque white). + self.positions = None #ObjectIndex + self.positionBias = [0.0,0.0,0.0] #Float32[3] + self.positionScale = 1.0 #Float32 + self.normals = None #ObjectIndex + self.colors = None #ObjectIndex + self.texCoordArrays = [] + self.texcoordArrayCount = 0 #UInt32 +## #FOR each texture coordinate array... +## self.texCoords = [] #ObjectIndex +## self.texCoordBias=[] #Float32[3] +## self.texCoordScale=[] #;Float32 +## #END +## #If a texture coordinate array has only two components, the corresponding texCoordBias[2] element +## #must be 0.0. +## #Null texture coordinate arrays are never serialized, regardless of their position. A single texture +## #coordinate array will therefore always be serialized as belonging to texturing unit 0, regardless of +## #its original unit it was assigned to. +## #There are as many references in the texture coordinates array as there are active texture units for +## #this geometry. The texture coordinate references are loaded sequentially from texture unit 0. If the +## #implementation supports more texture units than are specified, these are left in their default, inactive +## #state, with a null texture coordinate reference and an undefined bias and scale. +## #If more texture coordinate references are specified than are supported by the implementation, then +## #this must be treated as an error, as it would be in the API. The application can then decide on an +## #appropriate course of action to handle this case. + + def searchDeep(self,alist): + if self.positions!=None: alist = self.positions.searchDeep(alist) + if self.normals != None: alist = self.normals.searchDeep(alist) + if self.colors!= None: alist = self.colors.searchDeep(alist) + alist = doSearchDeep(self.texCoordArrays, alist) + return M3GObject3D.searchDeep(self,alist) + + def setPositions(self,aVertexArray): + self.positions = aVertexArray + self.positionBias = aVertexArray.bias + self.positionScale = aVertexArray.scale + + def writeJava(self,aWriter,aCreate): + if aCreate: + aWriter.write(2,"//VertexBuffer"+self.name ) + aWriter.write(2,"VertexBuffer BL%i = new VertexBuffer();" % (self.id)) + aWriter.write(2,"float BL%i_Bias[] = { %ff, %ff, %ff};" % + (self.id,self.positionBias[0], + self.positionBias[1],self.positionBias[2])) + aWriter.write(2,"BL%i.setPositions(BL%i,%ff,BL%i_Bias);" % + (self.id, self.positions.id, + self.positionScale,self.id)) + aWriter.write(2,"BL%i.setNormals(BL%i);" % (self.id,self.normals.id)) + #if self.colors != None: aWriter.write(2,"BL%i.setTexCoords(0,BL%i,1.0f,null);" % + # (self.id,self.colors.id)) + lIndex = 0 + for iTexCoord in self.texCoordArrays: + aWriter.write(2,"float BL%i_%i_TexBias[] = { %ff, %ff, %ff};" % + (self.id,lIndex, iTexCoord.bias[0], + iTexCoord.bias[1],iTexCoord.bias[2])) + #int index, javax.microedition.m3g.VertexArray194 texCoords, float scale, float[] bias + aWriter.write(2,"BL%i.setTexCoords(%i,BL%i,%ff,BL%i_%i_TexBias);" % + (self.id, lIndex, iTexCoord.id, iTexCoord.scale,self.id,lIndex)) + lIndex += 1 + + M3GObject3D.writeJava(self,aWriter,False) + + + def getData(self): + self.texcoordArrayCount = len(self.texCoordArrays) + data = M3GObject3D.getData(self) + data += self.defaultColor.getData() + data += struct.pack(' 0 : + value += struct.calcsize('<' + str(len(self.indices)) + 'I') + value += struct.calcsize(' 0: + value+= struct.calcsize('<'+str(len(self.stripLengths))+'I') + return value + + +class M3GAppearance(M3GObject3D): + def __init__(self): + M3GObject3D.__init__(self) + self.ObjectType=3 + self.layer=0 #Byte + self.compositingMode=None #ObjectIndex + self.fog=None #ObjectIndex + self.polygonMode=None #ObjectIndex + self.material=None #ObjectIndex + self.textures=[] #;ObjectIndex[] + + def searchDeep(self,alist): + alist = doSearchDeep([self.compositingMode,self.fog, + self.polygonMode,self.material] + + self.textures,alist) + return M3GObject3D.searchDeep(self,alist) + + def getData(self): + data = M3GObject3D.getData(self) + data += struct.pack(" 0 : + value += struct.calcsize("<"+str(len(self.textures))+'I') + return value + + + def writeJava(self,aWriter,aCreate): + if aCreate: + aWriter.write(2,"//Appearance") + aWriter.write(2,"Appearance BL%i = new Appearance();" % (self.id)) + if self.compositingMode!= None: + aWriter.write(2,"BL%i.setPolygonMode(BL%i);" % + (self.id,self.compositingMode.id)) + if self.fog!=None: + aWriter.write(2,"BL%i.setFog(BL%i);" % + (self.id,self.fog.id)) + if self.polygonMode!=None: + aWriter.write(2,"BL%i.setPolygonMode(BL%i);" % + (self.id,self.polygonMode.id)) + if self.material!=None: + aWriter.write(2,"BL%i.setMaterial(BL%i);" % + (self.id,self.material.id)) + i=0 + for itexture in self.textures: + aWriter.write(2,"BL%i.setTexture(%i,BL%i);" % + (self.id,i,itexture.id)) + i =+ 1 + M3GObject3D.writeJava(self,aWriter,False) + aWriter.write(2) + +class M3GTexture2D(M3GTransformable): + #M3G imposes the following restrictions when assigning textures to a model: + #The dimensions must be powers of two (4, 8, 16, 32, 64, 128...). + + WRAP_REPEAT = 241 + WRAP_CLAMP = 240 + FILTER_BASE_LEVEL=208 + FILTER_LINEAR=209 + FILTER_NEAREST=210 + FUNC_ADD=224 + FUNC_BLEND=225 + FUNC_DECAL=226 + FUNC_MODULATE=227 + FUNC_REPLACE=228 + + def __init__(self,aImage): + M3GTransformable.__init__(self) + self.ObjectType=17 + self.Image = aImage #ObjectIndex + self.blendColor=M3GColorRGB(0,0,0) + self.blending=M3GTexture2D.FUNC_MODULATE #Byte + self.wrappingS=M3GTexture2D.WRAP_REPEAT #Byte + self.wrappingT=M3GTexture2D.WRAP_REPEAT #Byte + self.levelFilter=M3GTexture2D.FILTER_BASE_LEVEL #Byte + self.imageFilter=M3GTexture2D.FILTER_NEAREST #Byte + + def searchDeep(self,alist): + alist = doSearchDeep([self.Image],alist) + return M3GTransformable.searchDeep(self,alist) + + def getData(self): + data = M3GTransformable.getData(self) + data += struct.pack('#AE# + lError = "Armature name " + name + " is not ok. Perhaps you should set option 'ExportAllAction' to false." + #print "name ", name + lLetter = name.find("#") + if lLetter == -1 :raise Exception(lError) + if name[lLetter+1]!='A': raise Exception(lError) + lName = name[lLetter+2:] + #print "lName ", lName + lLetter = lName.find("E") + #print "lLetter ", lLetter + if lLetter == -1 :raise Exception(lError) + #print "lName[:]", lName[:0] + lArmatureID = int(lName[:lLetter]) + lName = lName[lLetter+1:] + lLetter = lName.find("#") + if lLetter == -1:raise Exception(lError) + lEndFrame = int(lName[:lLetter]) + lActionID = int(lName[lLetter+1:]) + return (lArmatureID,lEndFrame,lActionID) + + + def translateWorld(self,scene): + "creates world object" + world = M3GWorld() + + #Background + world.background = M3GBackground() + blWorld= scene.world + #AllWorlds = Blender.World.Get() # Set Color + #if len(AllWorlds)>=1: # world object available + if blWorld != None: + world.background.backgroundColor=self.translateRGBA(blWorld.getHor(),0) # horizon color of the first world + if mOptions.createAmbientLight & mOptions.lightingEnabled: + lLight = M3GLight() + lLight.mode = lLight.modes['AMBIENT'] + lLight.color = self.translateRGB(AllWorlds[0].getAmb()) + self.nodes.append(lLight) + + #TODO: Set background picture from world + + return world + + def translateEmpty(self,obj): + print "translate empty ..." + mGroup = M3GGroup() + self.translateToNode(obj,mGroup) + + def translateCamera(self,obj): + print "translate camera ..." + camera = obj.getData() + if camera.getType()!=0: + print "Only perscpectiv cameras will work korrekt" + return #Type=0 'perspectiv' Camera will be translated + mCamera = M3GCamera() + mCamera.projectionType=mCamera.PERSPECTIVE + mCamera.fovy=60.0 # TODO: Calculate fovy from Blender.lens + mCamera.AspectRatio=4.0/3.0 # TODO: different in every device + mCamera.near=camera.getClipStart() + mCamera.far=camera.getClipEnd() + self.translateToNode(obj,mCamera) + self.world.activeCamera = mCamera # Last one is always the active one + + + def translateMaterials(self, aMaterial, aMesh, aMatIndex, createNormals, createUvs): + print "translate materials ..." + + mAppearance = M3GAppearance() + + if createNormals: + mMaterial = M3GMaterial() + mMaterial.name = aMaterial.name + mMaterial.diffuseColor = self.translateRGBA(aMaterial.rgbCol,1.0) #ColorRGBA + #material.specularColor= self.translateRGB(mat.specCol) #ColorRGB + mAppearance.material = mMaterial + + if createUvs: + # Search file name in mesh face. + lImage = None + for iface in aMesh.faces: + if iface.mat==aMatIndex: + if iface.image != None: + lImage = iface.image + break + if lImage==None: + raise Exception("Mesh " + aMesh.name + ": No image found for uv-texture! Perhaps no uv-coordinates ?") + + # M3G requires textures to have power-of-two dimensions. + [width, height] = lImage.getSize() + powerWidth = 1 + while (powerWidth < width): + powerWidth *= 2 + powerHeight = 1 + while (powerHeight < height): + powerHeight *= 2 + if powerWidth != width or powerHeight != height: + raise Exception("Image " + lImage.filename + ": width and height must be power-of-two!") + + # ImageFactory reuses existing images. + mImage = ImageFactory.getImage(lImage, mOptions.textureExternal) + mTexture = M3GTexture2D(mImage) + mAppearance.textures.append(mTexture) + + mPolygonMode=M3GPolygonMode() + mPolygonMode.perspectiveCorrectionEnabled = mOptions.perspectiveCorrection + if not aMesh.mode & Modes.TWOSIDED: + mPolygonMode.culling=M3GPolygonMode.CULL_BACK + else: + mPolygonMode.culling=M3GPolygonMode.CULL_NONE + if mOptions.smoothShading: + mPolygonMode.shading=M3GPolygonMode.SHADE_SMOOTH + else: + mPolygonMode.shading=M3GPolygonMode.SHADE_FLAT + + mAppearance.polygonMode = mPolygonMode + + return mAppearance + + + def translateMesh(self,obj): + print "translate mesh ..." + str(obj) + + # Mesh data. + mesh = obj.getData(False, True) # get Mesh not NMesh object + if len(mesh.faces) <= 0: # no need to process empty meshes + print "Empty mesh " + str(obj) + " not processed." + return + + vertexBuffer = M3GVertexBuffer() + positions = M3GVertexArray(3, 2) # 3 coordinates - 2 bytes + if mOptions.autoscaling: positions.useMaxPrecision(mesh.verts) + indexBuffers = [] + appearances = [] + print str(len(mesh.materials)) + " material(s) found." + + # Texture coordinates. + createUvs = False + if mOptions.textureEnabled & mesh.faceUV: + for material in mesh.materials: + if material.getMode() & Material.Modes.TEXFACE: createUvs = True; + + if createUvs: + if mOptions.autoscaling: + uvCoordinates = M3GVertexArray(2,2,True,True) #2 coordinates - 2 bytes - autoscaling + else: + uvCoordinates = M3GVertexArray(2, 2) #2 coordinates - 2 bytes + uvCoordinates.bias[0] = 0.5 + uvCoordinates.bias[1] = 0.5 + uvCoordinates.bias[2] = 0.5 + uvCoordinates.scale = 1.0/65535.0 + else: + uvCoordinates = None + + # Normals. + createNormals = False + if mOptions.lightingEnabled: + for material in mesh.materials: + if not (material.getMode() & Material.Modes.SHADELESS): createNormals = True; + + if createNormals: + normals = M3GVertexArray(3, 1) # 3 coordinates - 1 byte + else: + normals = None + + # Create a submesh for each material. + for materialIndex, material in enumerate(mesh.materials): + faces = [face for face in mesh.faces if face.mat == materialIndex] + if len(faces) >= 0: + indexBuffers.append(self.translateFaces(faces, positions, normals, uvCoordinates, createNormals, createUvs)) + appearances.append(self.translateMaterials(material, mesh, materialIndex, createNormals, createUvs)) + + # If the above didn't result in any IndexBuffer (e.g. there's no material), write a single IndexBuffer + # with all faces and a default Appearance. + if len(indexBuffers) == 0: + indexBuffers.append(self.translateFaces(mesh.faces, positions, normals, uvCoordinates, createNormals, createUvs)) + appearances.append(M3GAppearance()) + + vertexBuffer.setPositions(positions) + if createNormals: vertexBuffer.normals = normals + if createUvs: vertexBuffer.texCoordArrays.append(uvCoordinates) + + parent = obj.getParent() + if parent!=None and parent.getType()=='Armature': #Armatures ? + mMesh = M3GSkinnedMesh(vertexBuffer,indexBuffers,appearances) + #print"vertexBuffer.positions:",vertexBuffer.positions + print"mMesh.vertexBuffer:",mMesh.vertexBuffer + self.translateArmature(parent,obj,mMesh) + else: + mMesh = M3GMesh(vertexBuffer,indexBuffers,appearances) + + self.translateToNode(obj,mMesh) + + #Do Animation + self.translateObjectIpo(obj,mMesh) + + def translateFaces(self, faces, positions, normals, uvCoordinates, createNormals, createUvs): + """Translates a list of faces into vertex data and triangle strips.""" + + # Create vertices and triangle strips. + indices = [0, 0, 0, 0] + triangleStrips = M3GTriangleStripArray() + + for face in faces: + for vertexIndex, vertex in enumerate(face.verts): + # Find candidates for sharing (vertices with same Blender ID). + vertexCandidateIds = [int(k) for k, v in positions.blenderIndexes.items() if v == vertex.index] + + # Check normal. + if createNormals and not face.smooth: + # For solid faces, a vertex can only be shared if the the face normal is + # the same as the normal of the shared vertex. + for candidateId in vertexCandidateIds[:]: + for j in range(3): + if face.no[j]*127 != normals.components[candidateId*3 + j]: + vertexCandidateIds.remove(candidateId) + break + + # Check texture coordinates. + if createUvs: + # If texture coordinates are required, a vertex can only be shared if the + # texture coordinates match. + for candidateId in vertexCandidateIds[:]: + s = int((face.uv[vertexIndex][0]-0.5)*65535) + t = int((0.5-face.uv[vertexIndex][1])*65535) + if (s != uvCoordinates.components[candidateId*2 + 0]) or (t != uvCoordinates.components[candidateId*2 + 1]): + vertexCandidateIds.remove(candidateId) + + if len(vertexCandidateIds) > 0: + # Share the vertex. + indices[vertexIndex] = vertexCandidateIds[0] + else: + # Create new vertex. + positions.append(vertex, vertex.index) + indices[vertexIndex] = len(positions.components)/3 - 1 + + # Normal. + if createNormals: + for j in range(3): + if face.smooth: + normals.append(int(vertex.no[j]*127)) # vertex normal + else: + normals.append(int(face.no[j]*127)) # face normal + + # Texture coordinates. + if createUvs: + lUvCoordinatesFound = True + print "face.uv[vertexIndex][0]:",face.uv[vertexIndex][0] + print "face.uv[vertexIndex][1]:",face.uv[vertexIndex][1] + if mOptions.autoscaling: + uvCoordinates.append(face.uv[vertexIndex][0]) + uvCoordinates.append(face.uv[vertexIndex][1]) + else: + uvCoordinates.append(int((face.uv[vertexIndex][0]-0.5)*65535)) + # Reverse t coordinate because M3G uses a different 2D coordinate system than Blender. + uvCoordinates.append(int((0.5-face.uv[vertexIndex][1])*65535)) + + # IndexBuffer. + triangleStrips.stripLengths.append(len(face.verts)) + if len(face.verts) > 3 : + triangleStrips.indices += [indices[1], indices[2], indices[0], indices[3]] # quad + else : + triangleStrips.indices += [indices[0], indices[1], indices[2]] # tri + + return triangleStrips + + + def translateObjectIpo(self,obj,aM3GObject): + if obj.getIpo() == None : return #No Ipo available + print "translate Ipo ..." + + lIpo = obj.getIpo() + self.translateIpo(lIpo,aM3GObject) + + + def translateIpo(self,aIpo,aM3GObject,aM3GAnimContr=None,aEndFrame=0): + #Print info about curves + #for iCurve in lIpo.getCurves(): + # print "Extrapolation",iCurve.getExtrapolation() #Constant, Extrapolation, Cyclic or Cyclic_extrapolation + # print "Interpolation",iCurve.getInterpolation() #Constant, Bezier, or Linear + # print "Name",iCurve.getName() + # for iPoint in iCurve.getPoints(): + # print "Knode points",iPoint.getPoints() + types = ['Loc','Rot','Size','Quat'] + + for type in types: + if aIpo.getCurve(type+'X'): + self.translateIpoCurve(aIpo,aM3GObject,type,aM3GAnimContr,aEndFrame) + + + def translateIpoCurve(self,aIpo,aM3GObject,aCurveType,aM3GAnimContr,aEndFrame=0): + + lContext = self.scene.getRenderingContext() + if aEndFrame==0: + lEndFrame = lContext.endFrame() + else: + lEndFrame = aEndFrame + + lTimePerFrame = 1.0 / lContext.framesPerSec() * 1000 + + lCurveX = aIpo.getCurve(aCurveType+'X') + lCurveY = aIpo.getCurve(aCurveType+'Y') + lCurveZ = aIpo.getCurve(aCurveType+'Z') + if aCurveType=='Quat': lCurveW = aIpo.getCurve(aCurveType+'W') + + lInterpolation = None + if aCurveType == 'Rot' or aCurveType == 'Quat': + lTrackType = M3GAnimationTrack.ORIENTATION + lNumComponents=4 + lCurveFactor= 10 #45 Degrees = 4,5 + if aCurveType == 'Quat': + lTrackType = M3GAnimationTrack.ORIENTATION + lNumComponents=4 + lCurveFactor= 1 + lInterpolation = M3GKeyframeSequence.SLERP + #lInterpolation = M3GKeyframeSequence.SQUAD + elif aCurveType == 'Size': + lTrackType = M3GAnimationTrack.SCALE + lNumComponents=3 + lCurveFactor=1 + else: + lTrackType = M3GAnimationTrack.TRANSLATION + lNumComponents=3 + lCurveFactor=1 + + mSequence = M3GKeyframeSequence(len(lCurveX.getPoints()), + lNumComponents, + lCurveX.getInterpolation(), + lInterpolation) + + #print 'ComponentCount',mSequence.componentCount + + mSequence.duration = lEndFrame * lTimePerFrame + mSequence.setRepeatMode(lCurveX.getExtrapolation()) + + lIndex = 0 + for iPoint in lCurveX.getPoints(): + lPoint = iPoint.getPoints() + + lPointList = [(lPoint[1]*lCurveFactor), + (lCurveY.evaluate(lPoint[0])*lCurveFactor), + (lCurveZ.evaluate(lPoint[0])*lCurveFactor)] + + #print "aCurveType ", aCurveType + + if aCurveType == 'Loc': + #print "PointList ", lPointList + #lorgTransVector = aM3GObject.blenderTransformMatrix.translationPart() + #ltrans = TranslationMatrix(Vector(lPointList)) + #ltrans2 = self.calculateChildMatrix(ltrans,aM3GObject.blenderTransformMatrix) + #lVector = ltrans2.translationPart() + lorgTransVector + #lPointList = [lVector.x, lVector.y,lVector.z] + #print "PointList ", lPointList + pass + + if aCurveType == 'Quat': + lPointList.append(lCurveW.evaluate(lPoint[0])*lCurveFactor) + #lQuat = Quaternion([lPointList[3],lPointList[0],lPointList[1],lPointList[2]]) + #print "Quat ", lQuat + #print "Quat.angel ", lQuat.angle + #print "Quat.axis ", lQuat.axis + #print "PointList ", lPointList + + #print "PointList",lPointList + + if aCurveType =='Rot': + lQuat = Euler(lPointList).toQuat() + #lPointList = [lQuat.w,lQuat.x,lQuat.y,lQuat.z] + lPointList = [lQuat.x,lQuat.y,lQuat.z,lQuat.w] + #print " Quat=", lPointList + + mSequence.setKeyframe(lIndex, + lPoint[0]*lTimePerFrame, + lPointList) + lIndex += 1 + mSequence.validRangeFirst = 0 + mSequence.validRangeLast = lIndex - 1 + + mTrack = M3GAnimationTrack(mSequence,lTrackType) + aM3GObject.animationTracks.append(mTrack) + if aM3GAnimContr==None: aM3GAnimContr = M3GAnimationController() + mTrack.animationController = aM3GAnimContr + + + def translateLamp(self,obj): + print "translate lamp ..." + lamp = obj.getData() + + #Type + lampType=lamp.getType() + if not lampType in [Lamp.Types.Lamp,Lamp.Types.Spot,Lamp.Types.Sun]: + print "INFO: Type of light is not supported. See documentation" + return #create not light; type not supported + mLight = M3GLight() + if lampType == Lamp.Types.Lamp: + mLight.mode = mLight.modes['OMNI'] + elif lampType == Lamp.Types.Spot: + mLight.mode = mLight.modes['SPOT'] + elif lampType == Lamp.Types.Sun: + mLight.mode = mLight.modes['DIRECTIONAL'] + #Attenuation (OMNI,SPOT): + if lampType in [Lamp.Types.Lamp,Lamp.Types.Spot]: + mLight.attenuationConstant = 0.0 + mLight.attenuationLinear = 2.0/lamp.dist + mLight.attenuationQuadratic = 0.0 + #Color + mLight.color = self.translateRGB(lamp.col) + #Energy + mLight.intensity = lamp.energy + #SpotAngle, SpotExponent (SPOT) + if lampType == Lamp.Types.Spot: + mLight.spotAngle = lamp.spotSize + mLight.spotExponent = lamp.spotBlend + self.translateToNode(obj,mLight) + + + def translateCore(self,obj,node): + #Name + node.name = obj.name + node.userID = self.translateUserID(obj.name) + #Location + #node.translation=self.translateLoc(obj.LocX,obj.LocY,obj.LocZ + #node.hasComponentTransform=True + #Transform + #node.transform = self.translateMatrix(obj.getMatrix('localspace')) + if type(obj) is Types.BoneType: + #print "BoneMatrix ",obj.matrix['BONESPACE'] + node.transform = self.translateMatrix(obj.matrix['ARMATURESPACE']) + #'ARMATURESPACE' - this matrix of the bone in relation to the armature + #'BONESPACE' - the matrix of the bone in relation to itself + else: + node.transform = self.translateMatrix(obj.matrixWorld) + node.hasGeneralTransform=True + + + def translateToNode(self,obj,node): + self.translateCore(obj,node) + #Nodes + self.nodes.append(node) + #Link to Blender Object + node.blenderObj = obj + node.blenderMatrixWorld = obj.matrixWorld + lparent = None + if obj.getParent()!=None: + if obj.getParent().getType()!='Armature': + lparent = obj.getParent() + else: + if obj.getParent().getParent()!=None and obj.getParent().getParent().getType()!='Armature': + lparent = obj.getParent().getParent() + node.parentBlenderObj = lparent + + + def translateUserID(self, name): + id = 0 + start = name.find('#') + + # Use digits that follow the # sign for id. + if start != -1: + start += 1 + end = start + for char in name[start:]: + if char.isdigit(): + end += 1 + else: + break + + if end > start: + id = int(name[start:end]) + + return id + + def translateLoc(self,aLocX,aLocY,aLocZ): + return M3GVector3D(aLocX,aLocY,aLocZ) + + def translateRGB(self,color): + return M3GColorRGB(int(color[0]*255), + int(color[1]*255), + int(color[2]*255)) + + def translateRGBA(self,color,alpha): + return M3GColorRGBA(int(color[0]*255), + int(color[1]*255), + int(color[2]*255), + int(alpha*255)) + + def translateMatrix(self,aPyMatrix): + """ +  0   1   2   3  + 4   5   6   7  + 8   9  10  11 + 12  13  14  15 """ + #print "Matrix:", aPyMatrix + lMatrix = M3GMatrix() + lMatrix.elements[0] = aPyMatrix[0][0] + lMatrix.elements[1] = aPyMatrix[1][0] + lMatrix.elements[2] = aPyMatrix[2][0] + lMatrix.elements[3] = aPyMatrix[3][0] + lMatrix.elements[4] = aPyMatrix[0][1] + lMatrix.elements[5] = aPyMatrix[1][1] + lMatrix.elements[6] = aPyMatrix[2][1] + lMatrix.elements[7] = aPyMatrix[3][1] + lMatrix.elements[8] = aPyMatrix[0][2] + lMatrix.elements[9] = aPyMatrix[1][2] + lMatrix.elements[10] = aPyMatrix[2][2] + lMatrix.elements[11] = aPyMatrix[3][2] + lMatrix.elements[12] = aPyMatrix[0][3] + lMatrix.elements[13] = aPyMatrix[1][3] + lMatrix.elements[14] = aPyMatrix[2][3] + lMatrix.elements[15] = aPyMatrix[3][3] + return lMatrix + + +# ---- Exporter ---------------------------------------------------------------- # + +class M3GExporter: + "Exports Blender-Scene to M3D" + def __init__(self, aWriter): + self.writer = aWriter + + + def start(self): + print "Info: starting export ..." + #rpdb2.start_embedded_debugger("t",True) + Translator = M3GTranslator() + world = Translator.start() + + #sys.settrace(tracer) + exportList = self.createDeepSearchList(world) + externalReferences = [element for element in exportList if element.__class__ is M3GExternalReference] + exportList = [element for element in exportList if element.__class__ is not M3GExternalReference] + #sys.settrace(None) + + # 1 is reservated for HeaderObject. + i=1 + + # Next are the external references. + for element in externalReferences: + i += 1 + element.id = i + print "object ",element.id, element + + # And the standard scene objects. + for element in exportList: + i += 1 + element.id = i + print "object ",element.id, element + + self.writer.writeFile(world, exportList, externalReferences) + + print("Ready!") + + + def createDeepSearchList(self,aWorld): + "creates the right order for saving m3g : leafs first" + return aWorld.searchDeep([]) + + + +# ---- Writer ---------------------------------------------------------------- # +class JavaWriter: + "writes a java class which creates m3g-Scene in a j2me programm" + def __init__(self,aFilename): + self.filename = aFilename + self.classname = Blender.sys.basename(aFilename) + self.classname = self.classname[:-5] #without extention ".java" + self.outFile = file(aFilename,"w") + + def write(self, tab, zeile=""): + "writes to file" + #print "\t" * tab + zeile + print >>self.outFile, "\t" * tab + zeile + + def writeFile(self,aWorld,aExportList,externalReferences): + self.world = aWorld + self.writeHeader() + for element in aExportList: + element.writeJava(self,True) + self.writeFooter() + self.outFile.close() + + def writeHeader(self): + "writes class header" + self.write(0,"import javax.microedition.lcdui.Image;") + self.write(0,"import javax.microedition.m3g.*;") + self.write(0,"public final class "+self.classname+" {") + self.write(1,"public static World getRoot(Canvas3D aCanvas) {") + + def writeFooter(self): + self.write(1) + self.write(1,"return BL"+str(self.world.id)+";") + self.write(0,"}}") + + def writeList(self,alist,numberOfElementsPerLine=12,aType=""): + '''Writes numberOfElementsPerLine''' + line="" + lastLine="" + counter=0 + for element in alist: + if counter!=0: + line = line + "," + str(element) + aType + else: + line = str(element) + aType + counter = counter + 1 + if counter == numberOfElementsPerLine: + if len(lastLine)>0: + self.write(3,lastLine+",") + lastLine=line + line="" + counter = 0 + if len(lastLine)>0: + if len(line)>0: + self.write(3,lastLine+",") + else: + self.write(3,lastLine) + if len(line) > 0: self.write(3,line) + + def writeClass(self,aName,aM3GObject): + self.write(2) + self.write(2,"//"+aName+":"+aM3GObject.name) + + +class M3GSectionObject: + def __init__(self,aObject): + """Object Structure + Each object in the file represents one object in the + scene graph tree, and is stored in a chunk. The + structure of an object chunk is as follows: + Byte ObjectType + UInt32 Length + Byte[] Data""" + #ObjectType + #This field describes what type of object has been serialized. + #The values 0 and 0xFF are special: 0 represents the header object, + #and 0xFF represents an external reference. + #Example: Byte ObjectType = 14 + self.ObjectType = aObject.ObjectType + self.data = aObject.getData() + self.length = aObject.getDataLength() + + def getData(self): + data = struct.pack('mr, BLI_countlist(&me->mr->levels)); vert_copy= MEM_callocN(sizeof(float)*3*lvl->totvert, "multires vert_copy"); for(i=0; itotvert; ++i) - VecCopyf(&vert_copy[i*3], lvl->verts[i].co); + VecCopyf(&vert_copy[i*3], me->mr->verts[i].co); /* Goto the pin level for multires */ me->mr->newlvl= me->mr->pinlvl; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 278d49e2198..4c6bfda1517 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -504,7 +504,7 @@ static float *make_orco_mesh_internal(Object *ob, int render) if(me->mr) { lvl = multires_level_n(me->mr, me->mr->pinlvl); vcos = MEM_callocN(sizeof(*vcos)*lvl->totvert, "orco mr mesh"); - mvert = lvl->verts; + mvert = me->mr->verts; totvert = lvl->totvert; } else { diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index a348aef0399..961ea21d088 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -141,7 +141,10 @@ bActionStrip *convert_action_to_strip (Object *ob) //set_active_strip(ob, nstrip); /* is in editnla as does UI calls */ nstrip->repeat = 1.0; - + + if(ob->nlastrips.first == NULL) + ob->nlaflag |= OB_NLA_OVERRIDE; + BLI_addtail(&ob->nlastrips, nstrip); return nstrip; /* is created, malloced etc. here so is safe to just return the pointer? this is needed for setting this active in UI, and probably useful for API too */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 842e07cebe7..e7b7b36aaa4 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -2322,6 +2322,9 @@ static void registerCompositNodes(ListBase *ntypelist) nodeRegisterType(ntypelist, &cmp_node_curve_rgb); nodeRegisterType(ntypelist, &cmp_node_mix_rgb); nodeRegisterType(ntypelist, &cmp_node_hue_sat); + nodeRegisterType(ntypelist, &cmp_node_brightcontrast); + nodeRegisterType(ntypelist, &cmp_node_gamma); + nodeRegisterType(ntypelist, &cmp_node_invert); nodeRegisterType(ntypelist, &cmp_node_alphaover); nodeRegisterType(ntypelist, &cmp_node_zcombine); @@ -2361,9 +2364,6 @@ static void registerCompositNodes(ListBase *ntypelist) nodeRegisterType(ntypelist, &cmp_node_flip); nodeRegisterType(ntypelist, &cmp_node_displace); nodeRegisterType(ntypelist, &cmp_node_mapuv); - - nodeRegisterType(ntypelist, &cmp_node_brightcontrast); - nodeRegisterType(ntypelist, &cmp_node_gamma); } static void registerShaderNodes(ListBase *ntypelist) @@ -2383,9 +2383,11 @@ static void registerShaderNodes(ListBase *ntypelist) nodeRegisterType(ntypelist, &sh_node_squeeze); nodeRegisterType(ntypelist, &sh_node_camera); nodeRegisterType(ntypelist, &sh_node_material); + nodeRegisterType(ntypelist, &sh_node_material_ext); nodeRegisterType(ntypelist, &sh_node_value); nodeRegisterType(ntypelist, &sh_node_rgb); nodeRegisterType(ntypelist, &sh_node_texture); + nodeRegisterType(ntypelist, &sh_node_invert); } void init_nodesystem(void) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 118c2779ac0..1b595b1e3fc 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2554,6 +2554,8 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh) mesh->mr->edge_flags= MEM_callocN(sizeof(short)*lvl->totedge, "Multires Edge Flags"); if(!mesh->mr->edge_creases) mesh->mr->edge_creases= MEM_callocN(sizeof(char)*lvl->totedge, "Multires Edge Creases"); + + mesh->mr->verts = newdataadr(fd, mesh->mr->verts); for(; lvl; lvl= lvl->next) { lvl->verts= newdataadr(fd, lvl->verts); @@ -6465,9 +6467,28 @@ static void do_versions(FileData *fd, Library *lib, Main *main) if(main->versionfile <= 244) { Scene *sce; - if(main->subversionfile < 1) { + if(main->versionfile != 244 || main->subversionfile < 2) { + Mesh *me; for(sce= main->scene.first; sce; sce= sce->id.next) sce->r.mode |= R_SSS; + + /* Copy over old per-level multires vertex data + into a single vertex array in struct Multires */ + + for(me = main->mesh.first; me; me=me->id.next) { + if(me->mr) { + MultiresLevel *lvl = me->mr->levels.last; + if(lvl) { + me->mr->verts = lvl->verts; + lvl->verts = NULL; + /* Don't need the other vert arrays */ + for(lvl = lvl->prev; lvl; lvl = lvl->prev) { + MEM_freeN(lvl->verts); + lvl->verts = NULL; + } + } + } + } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 0d4d9d82ee1..226561ab97b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1156,13 +1156,17 @@ static void write_meshs(WriteData *wd, ListBase *idbase) writedata(wd, DATA, sizeof(short)*lvl->totedge, mesh->mr->edge_flags); writedata(wd, DATA, sizeof(char)*lvl->totedge, mesh->mr->edge_creases); } + for(; lvl; lvl= lvl->next) { writestruct(wd, DATA, "MultiresLevel", 1, lvl); - writestruct(wd, DATA, "MVert", lvl->totvert, lvl->verts); writestruct(wd, DATA, "MultiresFace", lvl->totface, lvl->faces); writestruct(wd, DATA, "MultiresEdge", lvl->totedge, lvl->edges); writestruct(wd, DATA, "MultiresColFace", lvl->totface, lvl->colfaces); } + + lvl= mesh->mr->levels.last; + if(lvl) + writestruct(wd, DATA, "MVert", lvl->totvert, mesh->mr->verts); } /* PMV data */ diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index fccb3aba7fc..69390951a25 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -258,17 +258,17 @@ static int isffmpeg (char *filename) { BLI_testextensie(filename, ".wav")) return 0; if(av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)!=0) { - fprintf(stderr, "isffmpeg: av_open_input_file failed\n"); + if(UTIL_DEBUG) fprintf(stderr, "isffmpeg: av_open_input_file failed\n"); return 0; } if(av_find_stream_info(pFormatCtx)<0) { - fprintf(stderr, "isffmpeg: av_find_stream_info failed\n"); + if(UTIL_DEBUG) fprintf(stderr, "isffmpeg: av_find_stream_info failed\n"); av_close_input_file(pFormatCtx); return 0; } - dump_format(pFormatCtx, 0, filename, 0); + if(UTIL_DEBUG) dump_format(pFormatCtx, 0, filename, 0); /* Find the first video stream */ @@ -315,19 +315,33 @@ int imb_get_anim_type(char * name) { if(UTIL_DEBUG) printf("in getanimtype: %s\n", name); -#ifdef WITH_FFMPEG +#ifndef _WIN32 +# ifdef WITH_FFMPEG /* stat test below fails on large files > 4GB */ if (isffmpeg(name)) return (ANIM_FFMPEG); -#endif - +# endif if (ib_stat(name,&st) == -1) return(0); if (((st.st_mode) & S_IFMT) != S_IFREG) return(0); if (isavi(name)) return (ANIM_AVI); if (ismovie(name)) return (ANIM_MOVIE); -#ifdef WITH_QUICKTIME +# ifdef WITH_QUICKTIME if (isqtime(name)) return (ANIM_QTIME); +# endif +#else + if (ib_stat(name,&st) == -1) return(0); + if (((st.st_mode) & S_IFMT) != S_IFREG) return(0); + + if (isavi(name)) return (ANIM_AVI); + + if (ismovie(name)) return (ANIM_MOVIE); +# ifdef WITH_QUICKTIME + if (isqtime(name)) return (ANIM_QTIME); +# endif +# ifdef WITH_FFMPEG + if (isffmpeg(name)) return (ANIM_FFMPEG); +# endif #endif type = IMB_ispic(name); if (type == ANIM) return (ANIM_ANIM5); diff --git a/source/blender/include/BIF_editaction.h b/source/blender/include/BIF_editaction.h index 2d92b120b9a..6e180418cd8 100644 --- a/source/blender/include/BIF_editaction.h +++ b/source/blender/include/BIF_editaction.h @@ -92,6 +92,7 @@ void snap_keys_to_frame(int snap_mode); void mirror_action_keys(short mirror_mode); void clean_shapekeys(struct Key *key); void clean_actionchannels(struct bAction *act); +void insertkey_action(void); /* Marker Operations */ void column_select_shapekeys(struct Key *key, int mode); diff --git a/source/blender/include/BIF_editdeform.h b/source/blender/include/BIF_editdeform.h index 69f03652887..2a8f43c14e7 100644 --- a/source/blender/include/BIF_editdeform.h +++ b/source/blender/include/BIF_editdeform.h @@ -67,5 +67,8 @@ void vertexgroup_select_by_name(struct Object *ob, char *name); extern void object_apply_deform(struct Object *ob); +void vgroup_assign_with_menu(void); +void vgroup_operation_with_menu(void); + #endif diff --git a/source/blender/include/multires.h b/source/blender/include/multires.h index 6c33af2d5e3..069dbee802f 100644 --- a/source/blender/include/multires.h +++ b/source/blender/include/multires.h @@ -31,6 +31,7 @@ #define MULTIRES_H struct CustomData; +struct EditMesh; struct Object; struct MDeformVert; struct Mesh; @@ -65,6 +66,7 @@ int multires_modifier_warning(); /* multires-firstlevel.c */ /* Generic */ +void multires_update_first_level(struct Mesh *me, struct EditMesh *em); void multires_update_customdata(struct MultiresLevel *lvl1, struct CustomData *src, struct CustomData *dst, const int type); void multires_customdata_to_mesh(struct Mesh *me, struct EditMesh *em, struct MultiresLevel *lvl, diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 4d78f577137..af9c1ae629d 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -109,7 +109,6 @@ struct MultiresMapNode; typedef struct MultiresLevel { struct MultiresLevel *next, *prev; - MVert *verts; MultiresFace *faces; MultiresColFace *colfaces; MultiresEdge *edges; @@ -118,10 +117,15 @@ typedef struct MultiresLevel { struct MultiresMapNode *map_mem; unsigned int totvert, totface, totedge, pad; + + /* Kept for compatibility with older files */ + MVert *verts; } MultiresLevel; typedef struct Multires { ListBase levels; + MVert *verts; + unsigned char level_count, current, newlvl, edgelvl, pinlvl, renderlvl; unsigned char use_col, pad; diff --git a/source/blender/nodes/CMP_node.h b/source/blender/nodes/CMP_node.h index ea15d4dbe73..3410238c0a2 100644 --- a/source/blender/nodes/CMP_node.h +++ b/source/blender/nodes/CMP_node.h @@ -53,6 +53,9 @@ extern bNodeType cmp_node_output_file; extern bNodeType cmp_node_curve_rgb; extern bNodeType cmp_node_mix_rgb; extern bNodeType cmp_node_hue_sat; +extern bNodeType cmp_node_brightcontrast; +extern bNodeType cmp_node_gamma; +extern bNodeType cmp_node_invert; extern bNodeType cmp_node_alphaover; extern bNodeType cmp_node_zcombine; @@ -93,9 +96,6 @@ extern bNodeType cmp_node_flip; extern bNodeType cmp_node_displace; extern bNodeType cmp_node_mapuv; -extern bNodeType cmp_node_brightcontrast; -extern bNodeType cmp_node_gamma; - #endif diff --git a/source/blender/nodes/SHD_node.h b/source/blender/nodes/SHD_node.h index b443a39624b..688494d6de5 100644 --- a/source/blender/nodes/SHD_node.h +++ b/source/blender/nodes/SHD_node.h @@ -56,6 +56,8 @@ extern bNodeType sh_node_curve_rgb; extern bNodeType sh_node_math; extern bNodeType sh_node_vect_math; extern bNodeType sh_node_squeeze; +extern bNodeType sh_node_material_ext; +extern bNodeType sh_node_invert; #endif diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c b/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c index aedaa036d67..f108098750c 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c @@ -90,12 +90,12 @@ static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **i return; /* input no image? then only color operation */ - if(in[1]->data==NULL) { + if(in[1]->data==NULL && in[2]->data==NULL) { do_alphaover_premul(node, out[0]->vec, in[1]->vec, in[2]->vec, in[0]->vec); } else { /* make output size of input image */ - CompBuf *cbuf= in[1]->data; + CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data; CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ if(node->custom1) diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_curves.c b/source/blender/nodes/intern/CMP_nodes/CMP_curves.c index 754d016fb25..17d9821a5ef 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_curves.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_curves.c @@ -172,10 +172,10 @@ static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **i CompBuf *cbuf= in[1]->data; CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ - if(in[0]->data) - composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_curves_fac, CB_RGBA, CB_VAL); - else + if(in[0]->vec[0] == 1.0) composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_curves, CB_RGBA); + else + composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_curves_fac, CB_RGBA, CB_VAL); out[0]->data= stackbuf; } diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_invert.c b/source/blender/nodes/intern/CMP_nodes/CMP_invert.c new file mode 100644 index 00000000000..1d4be2bc09f --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_invert.c @@ -0,0 +1,134 @@ +/** + * $Id: CMP_mixrgb.c,v 1.4 2007/04/04 13:58:10 jesterking Exp $ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include "../CMP_util.h" + +/* **************** INVERT ******************** */ +static bNodeSocketType cmp_node_invert_in[]= { + { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType cmp_node_invert_out[]= { + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void do_invert(bNode *node, float *out, float *in) +{ + if(node->custom1 & CMP_CHAN_RGB) { + out[0] = 1.0f - in[0]; + out[1] = 1.0f - in[1]; + out[2] = 1.0f - in[2]; + } else + VECCOPY(out, in); + + if(node->custom1 & CMP_CHAN_A) + out[3] = 1.0f - in[3]; + else + out[3] = in[3]; +} + +static void do_invert_fac(bNode *node, float *out, float *in, float *fac) +{ + float col[4], facm; + + do_invert(node, col, in); + + /* blend inverted result against original input with fac */ + facm = 1.0 - fac[0]; + + if(node->custom1 & CMP_CHAN_RGB) { + col[0] = fac[0]*col[0] + (facm*in[0]); + col[1] = fac[0]*col[1] + (facm*in[1]); + col[2] = fac[0]*col[2] + (facm*in[2]); + } + if(node->custom1 & CMP_CHAN_A) + col[3] = fac[0]*col[3] + (facm*in[3]); + + QUATCOPY(out, col); +} + +static void node_composit_exec_invert(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + /* stack order in: fac, Image, Image */ + /* stack order out: Image */ + float *fac= in[0]->vec; + + if(out[0]->hasoutput==0) return; + + /* input no image? then only color operation */ + if(in[1]->data==NULL && in[0]->data==NULL) { + do_invert_fac(node, out[0]->vec, in[1]->vec, fac); + } + else { + /* make output size of first available input image, or then size of fac */ + CompBuf *cbuf= in[1]->data?in[1]->data:in[0]->data; + + /* if neither RGB or A toggled on, pass through */ + if (node->custom1 != 0) { + CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ + + if (fac[0] < 1.0f || in[0]->data!=NULL) + composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, fac, do_invert_fac, CB_RGBA, CB_VAL); + else + composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_invert, CB_RGBA); + out[0]->data= stackbuf; + return; + + } else { + out[0]->data = pass_on_compbuf(cbuf); + return; + } + } +} + +static void node_composit_init_invert(bNode *node) +{ + node->custom1 |= CMP_CHAN_RGB; +} + +/* custom1 = mix type */ +bNodeType cmp_node_invert= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_INVERT, + /* name */ "Invert", + /* width+range */ 120, 120, 140, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ cmp_node_invert_in, + /* output sock */ cmp_node_invert_out, + /* storage */ "", + /* execfunc */ node_composit_exec_invert, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_invert, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c b/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c index 790b24a105a..6a4916b3fac 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c @@ -81,7 +81,7 @@ bNodeType cmp_node_mix_rgb= { /* *next,*prev */ NULL, NULL, /* type code */ CMP_NODE_MIX_RGB, /* name */ "Mix", - /* width+range */ 80, 60, 120, + /* width+range */ 110, 60, 120, /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, /* input sock */ cmp_node_mix_rgb_in, /* output sock */ cmp_node_mix_rgb_out, diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c b/source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c index d56baecb587..a7e0e28989b 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c @@ -46,7 +46,7 @@ static void node_composit_exec_setalpha(void *data, bNode *node, bNodeStack **in /* stack order in: col, alpha */ /* input no image? then only color operation */ - if(in[0]->data==NULL) { + if(in[0]->data==NULL && in[1]->data==NULL) { out[0]->vec[0] = in[0]->vec[0]; out[0]->vec[1] = in[0]->vec[1]; out[0]->vec[2] = in[0]->vec[2]; @@ -54,7 +54,7 @@ static void node_composit_exec_setalpha(void *data, bNode *node, bNodeStack **in } else { /* make output size of input image */ - CompBuf *cbuf= in[0]->data; + CompBuf *cbuf= in[0]->data?in[0]->data:in[1]->data; CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */ if(in[1]->data==NULL && in[1]->vec[0]==1.0f) { diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_geom.c b/source/blender/nodes/intern/SHD_nodes/SHD_geom.c index 3875dead2b0..b15aa6802f3 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_geom.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_geom.c @@ -41,6 +41,7 @@ static bNodeSocketType sh_node_geom_out[]= { { SOCK_VECTOR, 0, "UV", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, { SOCK_RGBA, 0, "Vertex Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Front/Back", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { -1, 0, "" } }; @@ -52,6 +53,7 @@ static void node_shader_exec_geom(void *data, bNode *node, bNodeStack **in, bNod NodeGeometry *ngeo= (NodeGeometry*)node->storage; ShadeInputUV *suv= &shi->uv[0]; static float defaultvcol[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + static float front= 0.0; int i; if(ngeo->uvname[0]) { @@ -105,6 +107,15 @@ static void node_shader_exec_geom(void *data, bNode *node, bNodeStack **in, bNod out[GEOM_OUT_NORMAL]->data= shi->dxno; out[GEOM_OUT_NORMAL]->datatype= NS_OSA_VECTORS; } + + /* front/back + * check the original un-flipped normals to determine front or back side */ + if (shi->orignor[2] < FLT_EPSILON) { + front= 1.0f; + } else { + front = 0.0f; + } + out[GEOM_OUT_FRONTBACK]->vec[0]= front; } } diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_invert.c b/source/blender/nodes/intern/SHD_nodes/SHD_invert.c new file mode 100644 index 00000000000..4d1ce282fce --- /dev/null +++ b/source/blender/nodes/intern/SHD_nodes/SHD_invert.c @@ -0,0 +1,83 @@ +/** + * $Id: SHD_math.c,v 1.4 2007/04/04 13:58:12 jesterking Exp $ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../SHD_util.h" + + + +/* **************** INVERT ******************** */ +static bNodeSocketType sh_node_invert_in[]= { + { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_invert_out[]= { + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_exec_invert(void *data, bNode *node, bNodeStack **in, +bNodeStack **out) +{ + float col[3], facm; + + col[0] = 1.0f - in[1]->vec[0]; + col[1] = 1.0f - in[1]->vec[1]; + col[2] = 1.0f - in[1]->vec[2]; + + /* if fac, blend result against original input */ + if (in[0]->vec[0] < 1.0f) { + facm = 1.0 - in[0]->vec[0]; + + col[0] = in[0]->vec[0]*col[0] + (facm*in[1]->vec[0]); + col[1] = in[0]->vec[0]*col[1] + (facm*in[1]->vec[1]); + col[2] = in[0]->vec[0]*col[2] + (facm*in[1]->vec[2]); + } + + VECCOPY(out[0]->vec, col); +} + +bNodeType sh_node_invert= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_INVERT, + /* name */ "Invert", + /* width+range */ 90, 80, 100, + /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS, + /* input sock */ sh_node_invert_in, + /* output sock */ sh_node_invert_out, + /* storage */ "", + /* execfunc */ node_shader_exec_invert, + /* butfunc */ NULL, + /* initfunc */ NULL, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL +}; + diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_material.c b/source/blender/nodes/intern/SHD_nodes/SHD_material.c index 1dc18f97496..bdceb134c0d 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_material.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_material.c @@ -39,11 +39,6 @@ static bNodeSocketType sh_node_material_in[]= { { -1, 0, "" } }; -/* output socket defines */ -#define MAT_OUT_COLOR 0 -#define MAT_OUT_ALPHA 1 -#define MAT_OUT_NORMAL 2 - static bNodeSocketType sh_node_material_out[]= { { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, @@ -51,6 +46,34 @@ static bNodeSocketType sh_node_material_out[]= { { -1, 0, "" } }; +/* **************** EXTENDED MATERIAL ******************** */ + +static bNodeSocketType sh_node_material_ext_in[]= { + { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Spec", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Refl", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_RGBA, 1, "Mirror", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "AmbCol", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Ambient", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Emit", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "SpecTra", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Ray Mirror", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Alpha", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 1, "Translucency", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType sh_node_material_ext_out[]= { + { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_RGBA, 0, "Diffuse", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "Spec", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 0, "AO", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { if(data && node->id) { @@ -91,6 +114,25 @@ static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, shi->vn[2]= -shi->vn[2]; } + if (node->type == SH_NODE_MATERIAL_EXT) { + if(in[MAT_IN_MIR]->hasinput) + nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]); + if(in[MAT_IN_AMBCOL]->hasinput) + nodestack_get_vec(&shi->ambr, SOCK_VECTOR, in[MAT_IN_AMBCOL]); + if(in[MAT_IN_AMB]->hasinput) + nodestack_get_vec(&shi->amb, SOCK_VALUE, in[MAT_IN_AMB]); + if(in[MAT_IN_EMIT]->hasinput) + nodestack_get_vec(&shi->emit, SOCK_VALUE, in[MAT_IN_EMIT]); + if(in[MAT_IN_SPECTRA]->hasinput) + nodestack_get_vec(&shi->spectra, SOCK_VALUE, in[MAT_IN_SPECTRA]); + if(in[MAT_IN_RAY_MIRROR]->hasinput) + nodestack_get_vec(&shi->ray_mirror, SOCK_VALUE, in[MAT_IN_RAY_MIRROR]); + if(in[MAT_IN_ALPHA]->hasinput) + nodestack_get_vec(&shi->alpha, SOCK_VALUE, in[MAT_IN_ALPHA]); + if(in[MAT_IN_TRANSLUCENCY]->hasinput) + nodestack_get_vec(&shi->translucency, SOCK_VALUE, in[MAT_IN_TRANSLUCENCY]); + } + node_shader_lamp_loop(shi, &shrnode); /* clears shrnode */ /* write to outputs */ @@ -122,6 +164,15 @@ static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, VECCOPY(out[MAT_OUT_NORMAL]->vec, shi->vn); + /* Extended material options */ + if (node->type == SH_NODE_MATERIAL_EXT) { + /* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside + * a node tree :( */ + VECCOPY(out[MAT_OUT_DIFFUSE]->vec, shrnode.diff); + VECCOPY(out[MAT_OUT_SPEC]->vec, shrnode.spec); + VECCOPY(out[MAT_OUT_AO]->vec, shrnode.ao); + } + /* copy passes, now just active node */ if(node->flag & NODE_ACTIVE_ID) *(shcd->shr)= shrnode; @@ -153,3 +204,21 @@ bNodeType sh_node_material= { }; +bNodeType sh_node_material_ext= { + /* *next,*prev */ NULL, NULL, + /* type code */ SH_NODE_MATERIAL_EXT, + /* name */ "Extended Material", + /* width+range */ 120, 80, 240, + /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW, + /* input sock */ sh_node_material_ext_in, + /* output sock */ sh_node_material_ext_out, + /* storage */ "", + /* execfunc */ node_shader_exec_material, + /* butfunc */ NULL, + /* initfunc */ node_shader_init_material, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, + /* id */ NULL + +}; + diff --git a/source/blender/nodes/intern/SHD_util.c b/source/blender/nodes/intern/SHD_util.c index 8401c302386..c9f58fbce49 100644 --- a/source/blender/nodes/intern/SHD_util.c +++ b/source/blender/nodes/intern/SHD_util.c @@ -145,7 +145,7 @@ void nodeShaderSynchronizeID(bNode *node, int copyto) { if(node->id==NULL) return; - if(node->type==SH_NODE_MATERIAL) { + if(ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) { bNodeSocket *sock; Material *ma= (Material *)node->id; int a; @@ -161,6 +161,20 @@ void nodeShaderSynchronizeID(bNode *node, int copyto) VECCOPY(&ma->specr, sock->ns.vec); break; case MAT_IN_REFL: ma->ref= sock->ns.vec[0]; break; + case MAT_IN_MIR: + VECCOPY(&ma->mirr, sock->ns.vec); break; + case MAT_IN_AMB: + VECCOPY(&ma->ambr, sock->ns.vec); break; + case MAT_IN_EMIT: + ma->emit= sock->ns.vec[0]; break; + case MAT_IN_SPECTRA: + ma->spectra= sock->ns.vec[0]; break; + case MAT_IN_RAY_MIRROR: + ma->ray_mirror= sock->ns.vec[0]; break; + case MAT_IN_ALPHA: + ma->alpha= sock->ns.vec[0]; break; + case MAT_IN_TRANSLUCENCY: + ma->translucency= sock->ns.vec[0]; break; } } else { @@ -171,6 +185,20 @@ void nodeShaderSynchronizeID(bNode *node, int copyto) VECCOPY(sock->ns.vec, &ma->specr); break; case MAT_IN_REFL: sock->ns.vec[0]= ma->ref; break; + case MAT_IN_MIR: + VECCOPY(sock->ns.vec, &ma->mirr); break; + case MAT_IN_AMB: + VECCOPY(sock->ns.vec, &ma->ambr); break; + case MAT_IN_EMIT: + sock->ns.vec[0]= ma->emit; break; + case MAT_IN_SPECTRA: + sock->ns.vec[0]= ma->spectra; break; + case MAT_IN_RAY_MIRROR: + sock->ns.vec[0]= ma->ray_mirror; break; + case MAT_IN_ALPHA: + sock->ns.vec[0]= ma->alpha; break; + case MAT_IN_TRANSLUCENCY: + sock->ns.vec[0]= ma->translucency; break; } } } diff --git a/source/blender/nodes/intern/SHD_util.h b/source/blender/nodes/intern/SHD_util.h index 6b9a26de350..f75802b7c15 100644 --- a/source/blender/nodes/intern/SHD_util.h +++ b/source/blender/nodes/intern/SHD_util.h @@ -108,12 +108,30 @@ typedef struct ShaderCallData { #define GEOM_OUT_UV 4 #define GEOM_OUT_NORMAL 5 #define GEOM_OUT_VCOL 6 +#define GEOM_OUT_FRONTBACK 7 + /* input socket defines */ #define MAT_IN_COLOR 0 #define MAT_IN_SPEC 1 #define MAT_IN_REFL 2 #define MAT_IN_NORMAL 3 +#define MAT_IN_MIR 4 +#define MAT_IN_AMBCOL 5 +#define MAT_IN_AMB 6 +#define MAT_IN_EMIT 7 +#define MAT_IN_SPECTRA 8 +#define MAT_IN_RAY_MIRROR 9 +#define MAT_IN_ALPHA 10 +#define MAT_IN_TRANSLUCENCY 11 + +/* output socket defines */ +#define MAT_OUT_COLOR 0 +#define MAT_OUT_ALPHA 1 +#define MAT_OUT_NORMAL 2 +#define MAT_OUT_DIFFUSE 3 +#define MAT_OUT_SPEC 4 +#define MAT_OUT_AO 5 extern void node_ID_title_cb(void *node_v, void *unused_v); diff --git a/source/blender/python/api2_2x/Blender.c b/source/blender/python/api2_2x/Blender.c index 174c2be95a7..9a5163022ff 100644 --- a/source/blender/python/api2_2x/Blender.c +++ b/source/blender/python/api2_2x/Blender.c @@ -521,14 +521,7 @@ static PyObject *Blender_Get( PyObject * self, PyObject * args ) /*****************************************************************************/ static PyObject *Blender_Redraw( PyObject * self, PyObject * args ) { - int wintype = SPACE_VIEW3D; - - if( !PyArg_ParseTuple( args, "|i", &wintype ) ) { - return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected int argument (or nothing)" ); - } - - return M_Window_Redraw( self, PyInt_FromLong( (long)wintype ) ); + return M_Window_Redraw( self, args ); } /*****************************************************************************/ diff --git a/source/blender/python/api2_2x/Key.c b/source/blender/python/api2_2x/Key.c index 49fd55ed5c2..4e5d4278fd3 100644 --- a/source/blender/python/api2_2x/Key.c +++ b/source/blender/python/api2_2x/Key.c @@ -315,7 +315,7 @@ static PyObject *Key_repr( BPy_Key * self ) static PyObject *Key_getIpo( BPy_Key * self ) { if (self->key->ipo) - Ipo_CreatePyObject( self->key->ipo ); + return Ipo_CreatePyObject( self->key->ipo ); Py_RETURN_NONE; } diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c index b64259553bf..bd78900f625 100644 --- a/source/blender/python/api2_2x/Mesh.c +++ b/source/blender/python/api2_2x/Mesh.c @@ -6922,45 +6922,26 @@ static PyObject *Mesh_fill( BPy_Mesh * self ) /* * "pointInside" function */ - +#define SIDE_OF_LINE(pa,pb,pp) ((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1])) +#define POINT_IN_TRI(p0,p1,p2,p3) ((SIDE_OF_LINE(p1,p2,p0)>=0) && (SIDE_OF_LINE(p2,p3,p0)>=0) && (SIDE_OF_LINE(p3,p1,p0)>=0)) static short pointInside_internal(float *vec, float *v1, float *v2, float *v3 ) { - float a,a1,a2,a3, /*areas, used for point in tri test */ - z,w1,w2,w3,wtot; - float bounds[5]; + float z,w1,w2,w3,wtot; - /*min,max*/ - bounds[0] = MIN3(v1[0], v2[0], v3[0]); - bounds[1] = MAX3(v1[0], v2[0], v3[0]); - bounds[2] = MIN3(v1[1], v2[1], v3[1]); - bounds[3] = MAX3(v1[1], v2[1], v3[1]); - /*bounds[4] = MIN3(v1[2], v2[2], v3[2]); - ZMIN isnt used*/ - bounds[4] = MAX3(v1[2], v2[2], v3[2]); /* reuse 4 index as the max */ + if (!POINT_IN_TRI(vec, v1,v2,v3)) + return 0; - if ( /* is the vertex in the bounds of the face? */ - (bounds[0] < vec[0] && vec[0] < bounds[1]) && - (bounds[2] < vec[1] && vec[1] < bounds[3]) && - (bounds[4] < vec[2]) /* the vector must be above the face on the Z axis */ - ) - { - /* these areas are used for calculating the Z value where the vector is over the face */ - a = AreaF2Dfl(v1, v2, v3); - w1=a1= AreaF2Dfl(vec, v2, v3); - if (a1>a) return 0; /*outside*/ - w2=a2= AreaF2Dfl(v1, vec, v3); - if (a1+a2>a) return 0; /*outside*/ - w3=a3= AreaF2Dfl(v1, v2, vec); - if ((a1+a2+a3) - 0.000001 > a) return 0; /*outside*/ - + if (vec[2] < MAX3(v1[2], v2[2], v3[2])) { + w1= AreaF2Dfl(vec, v2, v3); + w2= AreaF2Dfl(v1, vec, v3); + w3= AreaF2Dfl(v1, v2, vec); wtot = w1+w2+w3; - if (!wtot) return 0; w1/=wtot; w2/=wtot; w3/=wtot; z =((v1[2] * (w2+w3)) + (v2[2] * (w1+w3)) + (v3[2] * (w1+w2))) * 0.5; - /* only return true if the face is above vec*/ - if (vec[2] > z ) + if (vec[2] < z ) return 1; } return 0; diff --git a/source/blender/python/api2_2x/NMesh.c b/source/blender/python/api2_2x/NMesh.c index 5c86a344896..0a4e8b50406 100644 --- a/source/blender/python/api2_2x/NMesh.c +++ b/source/blender/python/api2_2x/NMesh.c @@ -524,16 +524,18 @@ static PyObject *new_NMFace( PyObject * vertexlist ) vlcopy = PyList_New( len ); - if( !vlcopy ) + if( !vlcopy ) { + Py_DECREF(mf); return EXPP_ReturnPyObjError( PyExc_MemoryError, "couldn't create PyList" ); - + } for( i = 0; i < len; i++ ) { item = PySequence_GetItem( vertexlist, i ); /* PySequence increfs */ if( item ) PyList_SET_ITEM( vlcopy, i, item ); else { + Py_DECREF(mf); Py_DECREF(vlcopy); return EXPP_ReturnPyObjError ( PyExc_RuntimeError, @@ -582,7 +584,7 @@ static PyObject *NMFace_append( PyObject * self, PyObject * args ) PyList_Append( f->v, vert ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } #undef MethodDef @@ -616,7 +618,7 @@ static PyObject *NMFace_getattr( PyObject * self, char *name ) if( mf->image ) return Image_CreatePyObject( mf->image ); else - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } else if( strcmp( name, "mode" ) == 0 ) @@ -1169,7 +1171,7 @@ static PyObject *NMesh_setMaterials( PyObject * self, PyObject * args ) Py_DECREF( me->materials ); me->materials = EXPP_incr_ret( pymats ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *NMesh_addMaterial( PyObject * self, PyObject * args ) @@ -1200,7 +1202,7 @@ static PyObject *NMesh_addMaterial( PyObject * self, PyObject * args ) PyList_Append( me->materials, ( PyObject * ) pymat ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *NMesh_getKey( BPy_NMesh * self ) @@ -1269,40 +1271,38 @@ static PyObject *NMesh_insertKey( PyObject * self, PyObject * args ) if( fra > 0 ) G.scene->r.cfra = (int)oldfra; - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *NMesh_getSelectedFaces( PyObject * self, PyObject * args ) { BPy_NMesh *nm = ( BPy_NMesh * ) self; Mesh *me = nm->mesh; - int flag = 0; - - MTFace *tf; - int i; - PyObject *l = PyList_New( 0 ), *pyval; - - if( me == NULL ) - return NULL; - - tf = me->mtface; - if( tf == 0 ) - return l; + int i, totfaces, flag = 0; + PyObject *l, *pyval; if( !PyArg_ParseTuple( args, "|i", &flag ) ) - return NULL; - + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected int argument (or nothing)" ); + + l = PyList_New( 0 ); + if( me == NULL || me->mface == NULL) + return l; + + /* make sure not to write more faces then we have */ + totfaces= MIN2(me->totface, PySequence_Length(nm->faces)); + if( flag ) { - for( i = 0; i < me->totface; i++ ) { - if( tf[i].flag & TF_SELECT ) { + for( i = 0; i < totfaces; i++ ) { + if( me->mface[i].flag & ME_FACE_SEL ) { pyval = PyInt_FromLong( i ); PyList_Append( l, pyval ); Py_DECREF(pyval); } } } else { - for( i = 0; i < me->totface; i++ ) { - if( tf[i].flag & TF_SELECT ) + for( i = 0; i < totfaces; i++ ) { + if( me->mface[i].flag & ME_FACE_SEL ) PyList_Append( l, PyList_GetItem( nm->faces, i ) ); } } @@ -1312,7 +1312,7 @@ static PyObject *NMesh_getSelectedFaces( PyObject * self, PyObject * args ) static PyObject *NMesh_getActiveFace( PyObject * self ) { if( ( ( BPy_NMesh * ) self )->sel_face < 0 ) - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; return Py_BuildValue( "i", ( ( BPy_NMesh * ) self )->sel_face ); } @@ -1576,8 +1576,7 @@ static PyObject *NMesh_setMaxSmoothAngle( PyObject * self, PyObject * args ) ( short ) EXPP_ClampInt( value, NMESH_SMOOTHRESH_MIN, NMESH_SMOOTHRESH_MAX ); - Py_INCREF( Py_None ); - return Py_None; + Py_RETURN_NONE; } static PyObject *NMesh_getSubDivLevels( BPy_NMesh * self ) @@ -1609,8 +1608,7 @@ static PyObject *NMesh_setSubDivLevels( PyObject * self, PyObject * args ) ( short ) EXPP_ClampInt( render, NMESH_SUBDIV_MIN, NMESH_SUBDIV_MAX ); - Py_INCREF( Py_None ); - return Py_None; + Py_RETURN_NONE; } static PyObject *NMesh_getMode( BPy_NMesh * self ) @@ -1662,8 +1660,7 @@ static PyObject *NMesh_setMode( PyObject * self, PyObject * args ) nmesh->mode = mode; - Py_INCREF( Py_None ); - return Py_None; + Py_RETURN_NONE; } /* METH_VARARGS: function(PyObject *self, PyObject *args) */ @@ -2827,7 +2824,7 @@ PyObject *NMesh_assignMaterials_toObject( BPy_NMesh * nmesh, Object * ob ) ob->colbits = old_matmask; /*@ HACK */ ob->actcol = 1; - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static void fill_medge_from_nmesh(Mesh * mesh, BPy_NMesh * nmesh) @@ -3193,7 +3190,7 @@ static PyObject *M_NMesh_PutRaw( PyObject * self, PyObject * args ) EXPP_newMaterialList_fromPyList( nmesh->materials ); EXPP_incr_mats_us( mesh->mat, PyList_Size( nmesh->materials ) ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } } @@ -3421,7 +3418,7 @@ static PyObject *findEdge( BPy_NMesh *nmesh, BPy_NMVert *v1, BPy_NMVert *v2, int return newEdge; } else - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static void removeEdge( BPy_NMesh *nmesh, BPy_NMVert *v1, BPy_NMVert *v2, int ununsedOnly) @@ -3526,7 +3523,7 @@ static PyObject *NMesh_removeEdge( PyObject * self, PyObject * args ) "vertices must be different" ); removeEdge(bmesh, v1, v2, 0); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } @@ -3579,7 +3576,7 @@ static PyObject *NMesh_addFace( PyObject * self, PyObject * args ) return edges; } - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *NMesh_removeFace( PyObject * self, PyObject * args ) @@ -3626,7 +3623,7 @@ static PyObject *NMesh_removeFace( PyObject * self, PyObject * args ) } } - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *NMesh_printDebug( PyObject * self ) @@ -3675,7 +3672,7 @@ static PyObject *NMesh_printDebug( PyObject * self ) } } - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *NMesh_addVertGroup( PyObject * self, PyObject * args ) @@ -3702,7 +3699,7 @@ static PyObject *NMesh_addVertGroup( PyObject * self, PyObject * args ) EXPP_allqueue( REDRAWBUTSALL, 1 ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *NMesh_removeVertGroup( PyObject * self, PyObject * args ) @@ -3738,7 +3735,7 @@ static PyObject *NMesh_removeVertGroup( PyObject * self, PyObject * args ) EXPP_allqueue( REDRAWBUTSALL, 1 ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *NMesh_assignVertsToGroup( PyObject * self, PyObject * args ) @@ -3824,7 +3821,7 @@ static PyObject *NMesh_assignVertsToGroup( PyObject * self, PyObject * args ) add_vert_defnr( object, nIndex, tempInt, weight, assignmode ); } - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *NMesh_removeVertsFromGroup( PyObject * self, PyObject * args ) @@ -3910,7 +3907,7 @@ static PyObject *NMesh_removeVertsFromGroup( PyObject * self, PyObject * args ) } } - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *NMesh_getVertsFromGroup( PyObject * self, PyObject * args ) @@ -4098,7 +4095,7 @@ static PyObject *NMesh_renameVertGroup( PyObject * self, PyObject * args ) PyOS_snprintf( defGroup->name, 32, newGr ); unique_vertexgroup_name( defGroup, ( ( BPy_NMesh * ) self )->object ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *NMesh_getVertGroupNames( PyObject * self ) @@ -4191,6 +4188,5 @@ static PyObject *NMesh_transform (PyObject *self, PyObject *args) /* should we alternatively return a list of changed verts (and preserve * the original ones) ? */ - Py_INCREF( Py_None ); - return Py_None; + Py_RETURN_NONE; } diff --git a/source/blender/python/api2_2x/Scene.c b/source/blender/python/api2_2x/Scene.c index 39a7f0d77f4..fd139c4fe6e 100644 --- a/source/blender/python/api2_2x/Scene.c +++ b/source/blender/python/api2_2x/Scene.c @@ -1343,16 +1343,18 @@ static PyObject *SceneObSeq_item( BPy_SceneObSeq * self, int i ) if (self->mode==EXPP_OBSEQ_NORMAL) for (base= scene->base.first; base && i!=index; base= base->next, index++) {} /* selected */ - else if (self->mode==EXPP_OBSEQ_SELECTED) + else if (self->mode==EXPP_OBSEQ_SELECTED) { for (base= scene->base.first; base && i!=index; base= base->next) if (base->flag & SELECT) index++; + } /* context */ - else if (self->mode==EXPP_OBSEQ_CONTEXT) + else if (self->mode==EXPP_OBSEQ_CONTEXT) { if (G.vd) for (base= scene->base.first; base && i!=index; base= base->next) if TESTBASE(base) index++; + } if (!(base)) return EXPP_ReturnPyObjError( PyExc_IndexError, diff --git a/source/blender/python/api2_2x/doc/Render.py b/source/blender/python/api2_2x/doc/Render.py index adadf54c488..9c9f58f6074 100644 --- a/source/blender/python/api2_2x/doc/Render.py +++ b/source/blender/python/api2_2x/doc/Render.py @@ -498,7 +498,7 @@ class RenderData: def setOversamplingLevel(level): """ - Set the edge color for toon shading. + Set the level of over-sampling (anti-aliasing). @type level: int @param level: can be either 5, 8, 11, or 16 """ diff --git a/source/blender/python/api2_2x/doc/Scene.py b/source/blender/python/api2_2x/doc/Scene.py index fb852f2aa49..93d3e7d830e 100644 --- a/source/blender/python/api2_2x/doc/Scene.py +++ b/source/blender/python/api2_2x/doc/Scene.py @@ -107,6 +107,8 @@ class Scene: @ivar objects: The scene's objects. The sequence supports the methods .link(ob), .unlink(ob), and .new(obdata), and can be iterated over. @type cursor: Vector (wrapped) @ivar cursor: the 3d cursor location for this scene. + @type camera: Camera or None + @ivar camera: The active camera for this scene (can be set) @type world: World or None @ivar world: The world that this scene uses (if any) @type timeline: Timeline diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index c1b20da53b7..364535736ae 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -151,6 +151,10 @@ typedef struct ShadeInput int samplenr; /* sample counter, to detect if we should do shadow again */ int depth; /* 1 or larger on raytrace shading */ + /* stored copy of original face normal (facenor) + * before flipping. Used in Front/back output on geometry node */ + float orignor[3]; + /* from initialize, part or renderlayer */ short do_preview; /* for nodes, in previewrender */ short thread, sample; /* sample: ShadeSample array index */ @@ -158,6 +162,7 @@ typedef struct ShadeInput int layflag, passflag, combinedflag; struct Group *light_override; struct Material *mat_override; + } ShadeInput; diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 51157cb83f4..ca661469b36 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -259,6 +259,11 @@ void shade_input_set_triangle_i(ShadeInput *shi, VlakRen *vlr, short i1, short i /* facenormal copy, can get flipped */ VECCOPY(shi->facenor, vlr->n); + /* copy of original pre-flipped normal, for geometry->front/back node output */ + VECCOPY(shi->orignor, vlr->n); + if (vlr->noflag & R_FLIPPED_NO) { + VECMUL(shi->orignor, -1.0f); + } } /* note, facenr declared volatile due to over-eager -O2 optimizations diff --git a/source/blender/src/SConscript b/source/blender/src/SConscript index 815cf532c88..729e79dcb6f 100644 --- a/source/blender/src/SConscript +++ b/source/blender/src/SConscript @@ -4,18 +4,6 @@ Import ('env') # TODO: src_env.Append (CCFLAGS = user_options_dict['SDL_CFLAGS']) sources = env.Glob('*.c') -numobj = len(sources) -maxobj = 30 - -numlibs = numobj / maxobj -if (numobj % maxobj): - numlibs = numlibs + 1 -subsources = [] - -if (env['OURPLATFORM'] == 'win32-mingw'): - for i in range(numlibs - 1): - subsources.append(sources[i*maxobj:(i+1)*maxobj]) - subsources.append(sources[(numlibs-1)*maxobj:]) incs = ' #/intern/guardedalloc #/intern/memutil' incs += ' ../blenlib ../makesdna ../blenkernel' @@ -67,8 +55,4 @@ if env['WITH_BF_VERSE']: if env['BF_BUILDINFO'] == 1: defs.append('NAN_BUILDINFO') -if (env['OURPLATFORM'] == 'win32-mingw'): - for i in range(numlibs): - env.BlenderLib ( libname = 'src%d' % (i), sources = subsources[i], includes = Split(incs), defines = defs, libtype=['core', 'intern'], priority = [5, 25] ) -else: - env.BlenderLib ( libname = 'src', sources = sources, includes = Split(incs), defines = defs, libtype=['core', 'intern'], priority = [5, 25] ) +env.BlenderLib ( libname = 'src', sources = sources, includes = Split(incs), defines = defs, libtype=['core', 'intern'], priority = [5, 25] ) diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 3760b17f039..ec2b7b3b274 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -4447,7 +4447,7 @@ static void editing_panel_links(Object *ob) block= uiNewBlock(&curarea->uiblocks, "editing_panel_links", UI_EMBOSS, UI_HELV, curarea->win); if(uiNewPanel(curarea, block, "Link and Materials", "Editing", 0, 0, 318, 204)==0) return; - uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE); + uiSetButLock((ob && ob->id.lib), ERROR_LIBDATA_MESSAGE); buttons_active_id(&id, &idfrom); diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index e47a80fe9fa..bb5ac2ba682 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -2462,11 +2462,22 @@ static void object_softbodies__enable(void *ob_v, void *arg2) allqueue(REDRAWBUTSEDIT, 0); } +static int _can_softbodies_at_all(Object *ob) +{ + // list of Yes + if ((ob->type==OB_MESH) + || (ob->type==OB_CURVE) + || (ob->type==OB_LATTICE) + || (ob->type==OB_SURF) + ) return 1; + // else deny + return 0; +} static void object_softbodies_II(Object *ob) { uiBlock *block; static int val; - + if(!_can_softbodies_at_all(ob)) return; block= uiNewBlock(&curarea->uiblocks, "object_softbodies_II", UI_EMBOSS, UI_HELV, curarea->win); uiNewPanelTabbed("Soft Body", "Physics"); if(uiNewPanel(curarea, block, "Soft Body Collision", "Physics", 651, 0, 318, 204)==0) return; @@ -2545,9 +2556,9 @@ static void object_softbodies(Object *ob) uiBlock *block; static int val; uiBut *but; + if(!_can_softbodies_at_all(ob)) return; block= uiNewBlock(&curarea->uiblocks, "object_softbodies", UI_EMBOSS, UI_HELV, curarea->win); if(uiNewPanel(curarea, block, "Soft Body", "Physics", 640, 0, 318, 204)==0) return; - uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE); val = modifiers_isSoftbodyEnabled(ob); diff --git a/source/blender/src/drawmesh.c b/source/blender/src/drawmesh.c index b1ce86dd045..6307307345b 100644 --- a/source/blender/src/drawmesh.c +++ b/source/blender/src/drawmesh.c @@ -320,7 +320,6 @@ int set_tpage(MTFace *tface) else fCurtile= tface->tile; if(tilemode) { - if(ima->repbind==0) make_repbind(ima); if(fCurtile>=ima->totbind) fCurtile= 0; diff --git a/source/blender/src/drawnode.c b/source/blender/src/drawnode.c index e1cab659171..883fd05909f 100644 --- a/source/blender/src/drawnode.c +++ b/source/blender/src/drawnode.c @@ -622,6 +622,7 @@ static void node_shader_set_butfunc(bNodeType *ntype) /* case NODE_GROUP: note, typeinfo for group is generated... see "XXX ugly hack" */ case SH_NODE_MATERIAL: + case SH_NODE_MATERIAL_EXT: ntype->butfunc= node_shader_buts_material; break; case SH_NODE_TEXTURE: @@ -1508,6 +1509,21 @@ static int node_composit_buts_scale(uiBlock *block, bNodeTree *ntree, bNode *nod return 20; } +static int node_composit_buts_invert(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +{ + if(block) { + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, CMP_CHAN_RGB, B_NODE_EXEC+node->nr, "RGB", + butr->xmin, butr->ymin, (butr->xmax-butr->xmin)/2, 20, + &node->custom1, 0, 0, 0, 0, ""); + uiDefButBitS(block, TOG, CMP_CHAN_A, B_NODE_EXEC+node->nr, "A", + butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin, (butr->xmax-butr->xmin)/2, 20, + &node->custom1, 0, 0, 0, 0, ""); + uiBlockEndAlign(block); + } + return 20; +} + /* only once called */ static void node_composit_set_butfunc(bNodeType *ntype) { @@ -1609,6 +1625,9 @@ static void node_composit_set_butfunc(bNodeType *ntype) case CMP_NODE_MATH: ntype->butfunc= node_buts_math; break; + case CMP_NODE_INVERT: + ntype->butfunc= node_composit_buts_invert; + break; default: ntype->butfunc= NULL; } diff --git a/source/blender/src/editaction.c b/source/blender/src/editaction.c index 4c698674bbf..1b0429abda2 100644 --- a/source/blender/src/editaction.c +++ b/source/blender/src/editaction.c @@ -2568,6 +2568,9 @@ void snap_keys_to_frame(int snap_mode) else if (key) { set_snap_meshchannels(key, snap_mode); } + else { + return; + } BIF_undo_push(str); allspace(REMAKEIPO, 0); @@ -2670,6 +2673,9 @@ void mirror_action_keys(short mirror_mode) else if (key) { mirror_meshchannels(key, mirror_mode); } + else { + return; + } BIF_undo_push(str); allspace(REMAKEIPO, 0); @@ -2678,6 +2684,82 @@ void mirror_action_keys(short mirror_mode) allqueue(REDRAWNLA, 0); } +/* This function allows the user to insert keyframes on the current + * frame from the Action Editor, using the current values of the channels + * to be keyframed. + */ +void insertkey_action(void) +{ + bAction *act; + Key *key; + Object *ob= OBACT; + IpoCurve *icu; + short mode; + float cfra; + + /* get data */ + act = G.saction->action; + key = get_action_mesh_key(); + cfra = frame_to_float(CFRA); + + if (act) { + bActionChannel *achan; + bConstraintChannel *conchan; + + /* ask user what to keyframe */ + mode = pupmenu("Insert Key%t|All Channels%x1|Only Selected Channels%x2"); + if (mode == 0) return; + + for (achan= act->chanbase.first; achan; achan=achan->next) { + if (EDITABLE_ACHAN(achan)) { + if (achan->ipo && (SEL_ACHAN(achan) || (mode == 1))) { + for (icu= achan->ipo->curve.first; icu; icu=icu->next) { + if (ob) + insertkey((ID *)ob, icu->blocktype, achan->name, NULL, icu->adrcode); + else + insert_vert_ipo(icu, cfra, icu->curval); + } + } + + if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) { + for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) { + if (EDITABLE_CONCHAN(conchan)) { + if (conchan->ipo && (SEL_ACHAN(conchan) || (mode == 1))) { + for (icu= conchan->ipo->curve.first; icu; icu=icu->next) { + /* // commented out as this doesn't seem to work right for some reason + if (ob) + insertkey((ID *)ob, ID_CO, achan->name, conchan->name, CO_ENFORCE); + else + insert_vert_ipo(icu, cfra, icu->curval); + */ + insert_vert_ipo(icu, cfra, icu->curval); + } + } + } + } + } + } + } + } + else if (key) { + /* ask user if they want to insert a keyframe */ + mode = okee("Insert Keyframe?"); + if (mode == 0) return; + + if (key->ipo) { + for (icu= key->ipo->curve.first; icu; icu=icu->next) { + insert_vert_ipo(icu, cfra, icu->curval); + } + } + } + + BIF_undo_push("Insert Key"); + allspace(REMAKEIPO, 0); + allqueue(REDRAWACTION, 0); + allqueue(REDRAWIPO, 0); + allqueue(REDRAWNLA, 0); +} + static void select_all_keys_frames(bAction *act, short *mval, short *mvalo, int selectmode) { @@ -2886,7 +2968,7 @@ static void borderselect_function(void (*select_func)(bAction *act, select_func(act, mval, mvalo, SELECT_SUBTRACT); } - BIF_undo_push("Border select Action"); + BIF_undo_push("Border Select Action"); } static void clever_keyblock_names(Key *key, short* mval){ @@ -3255,7 +3337,7 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt) } } break; - + case KKEY: if (G.qual & LR_CTRLKEY) { markers_selectkeys_between(); @@ -3278,8 +3360,10 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt) case MKEY: if (G.qual & LR_SHIFTKEY) { /* mirror keyframes */ - val = pupmenu("Mirror Keys Over%t|Current Frame%x1|Vertical Axis%x2|Horizontal Axis %x3|Selected Marker %x4"); - mirror_action_keys(val); + if (act || key) { + val = pupmenu("Mirror Keys Over%t|Current Frame%x1|Vertical Axis%x2|Horizontal Axis %x3|Selected Marker %x4"); + mirror_action_keys(val); + } } else { /* marker operations */ @@ -3329,8 +3413,10 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt) case SKEY: if (mval[0]>=ACTWIDTH) { if(G.qual & LR_SHIFTKEY) { - val = pupmenu("Snap Keys To%t|Nearest Frame%x1|Current Frame%x2|Nearest Marker %x3"); - snap_keys_to_frame(val); + if (act || key) { + val = pupmenu("Snap Keys To%t|Nearest Frame%x1|Current Frame%x2|Nearest Marker %x3"); + snap_keys_to_frame(val); + } } else { if (act) diff --git a/source/blender/src/editdeform.c b/source/blender/src/editdeform.c index 305d01a8aea..7a086ed5be3 100644 --- a/source/blender/src/editdeform.c +++ b/source/blender/src/editdeform.c @@ -55,12 +55,16 @@ #include "BKE_mesh.h" #include "BKE_utildefines.h" +#include "BIF_interface.h" #include "BIF_editdeform.h" #include "BIF_editmesh.h" +#include "BIF_space.h" #include "BIF_toolbox.h" #include "BSE_edit.h" +#include "butspace.h" +#include "mydevice.h" #include "editmesh.h" #include "multires.h" @@ -788,6 +792,99 @@ void vertexgroup_select_by_name(Object *ob, char *name) ob->actdef=0; // this signals on painting to create a new one, if a bone in posemode is selected */ } +/* This function provides a shortcut for adding/removing verts from + * vertex groups. It is called by the Ctrl-G hotkey in EditMode for Meshes + * and Lattices. (currently only restricted to those two) + * It is only responsible for + */ +void vgroup_assign_with_menu(void) +{ + Object *ob= G.obedit; + int defCount; + int mode; + + /* prevent crashes */ + if (ob==NULL) return; + + defCount= BLI_countlist(&ob->defbase); + + /* give user choices of adding to current/new or removing from current */ + if (defCount && ob->actdef) + mode = pupmenu("Vertex Groups %t|Add Selected to New Group %x1|Add Selected to Active Group %x2|Remove Selected from Active Group %x3"); + else + mode= pupmenu("Vertex Groups %t|Add Selected to New Group %x1"); + + /* handle choices */ + switch (mode) { + case 1: /* add to new group */ + add_defgroup(ob); + assign_verts_defgroup(); + allqueue(REDRAWVIEW3D, 1); + BIF_undo_push("Assign to vertex group"); + break; + case 2: /* add to current group */ + assign_verts_defgroup(); + allqueue(REDRAWVIEW3D, 1); + BIF_undo_push("Assign to vertex group"); + break; + case 3: /* remove from current group */ + remove_verts_defgroup(0); + allqueue(REDRAWVIEW3D, 1); + BIF_undo_push("Remove from vertex group"); + break; + } +} + +/* This function provides a shortcut for commonly used vertex group + * functions - change weight (not implemented), change active group, delete active group, + * when Ctrl-Shift-G is used in EditMode, for Meshes and Lattices (only for now). + */ +void vgroup_operation_with_menu(void) +{ + Object *ob= G.obedit; + int defCount; + int mode; + + /* prevent crashes and useless cases */ + if (ob==NULL) return; + + defCount= BLI_countlist(&ob->defbase); + if (defCount == 0) return; + + /* give user choices of adding to current/new or removing from current */ + if (ob->actdef) + mode = pupmenu("Vertex Groups %t|Change Active Group%x1|Delete Active Group%x2"); + else + mode= pupmenu("Vertex Groups %t|Change Active Group%x1"); + + /* handle choices */ + switch (mode) { + case 1: /* change active group*/ + { + char *menustr= get_vertexgroup_menustr(ob); + short nr; + + if (menustr) { + nr= pupmenu(menustr); + + if ((nr >= 1) && (nr <= defCount)) + ob->actdef= nr; + + MEM_freeN(menustr); + } + allqueue(REDRAWBUTSALL, 0); + } + break; + case 2: /* delete active group */ + { + del_defgroup(ob); + allqueue (REDRAWVIEW3D, 1); + allqueue(REDRAWOOPS, 0); + BIF_undo_push("Delete vertex group"); + } + break; + } +} /* ******************* other deform edit stuff ********** */ diff --git a/source/blender/src/editipo.c b/source/blender/src/editipo.c index 95e998d3496..ad5ffacf103 100644 --- a/source/blender/src/editipo.c +++ b/source/blender/src/editipo.c @@ -2426,6 +2426,9 @@ void common_insertkey(void) if(curarea->spacetype==SPACE_IPO) { insertkey_editipo(); } + else if(curarea->spacetype==SPACE_ACTION) { + insertkey_action(); + } else if(curarea->spacetype==SPACE_BUTS) { if(G.buts->mainb==CONTEXT_SHADING) { int tab= G.buts->tab[CONTEXT_SHADING]; diff --git a/source/blender/src/editnla.c b/source/blender/src/editnla.c index d204fa2b703..73eea2b5aa4 100644 --- a/source/blender/src/editnla.c +++ b/source/blender/src/editnla.c @@ -526,6 +526,9 @@ static void add_nla_block(short event) if(strip->object) id_lib_extern(&strip->object->id); /* checks lib data, sets correct flag for saving then */ + if(ob->nlastrips.first == NULL) + ob->nlaflag |= OB_NLA_OVERRIDE; + BLI_addtail(&ob->nlastrips, strip); BIF_undo_push("Add NLA strip"); @@ -580,6 +583,9 @@ static void add_nla_block_by_name(char name[32], Object *ob, short hold, short a act->id.us++; + if(ob->nlastrips.first == NULL) + ob->nlaflag |= OB_NLA_OVERRIDE; + BLI_addtail(&ob->nlastrips, strip); } diff --git a/source/blender/src/ghostwinlay.c b/source/blender/src/ghostwinlay.c index 9df293a0fda..19e858a9f59 100644 --- a/source/blender/src/ghostwinlay.c +++ b/source/blender/src/ghostwinlay.c @@ -881,10 +881,8 @@ Window *winlay_get_active_window(void) { void window_open_ndof(Window* win) { - PILdynlib* ndofLib = PIL_dynlib_open("NDOFPlugin.plug"); - printf("passing here \n"); + PILdynlib* ndofLib = PIL_dynlib_open("spaceplug.plug"); if (ndofLib) { - printf("and here \n"); GHOST_OpenNDOF(g_system, win->ghostwin, PIL_dynlib_find_symbol(ndofLib, "ndofInit"), diff --git a/source/blender/src/multires-firstlevel.c b/source/blender/src/multires-firstlevel.c index db39a429c22..2be867b5db0 100644 --- a/source/blender/src/multires-firstlevel.c +++ b/source/blender/src/multires-firstlevel.c @@ -55,6 +55,8 @@ MDeformVert *subdivide_dverts(MDeformVert *src, MultiresLevel *lvl); MTFace *subdivide_mtfaces(MTFace *src, MultiresLevel *lvl); +void multires_update_edge_flags(Mesh *me, EditMesh *em); +void eed_to_medge_flag(EditEdge *eed, short *flag, char *crease); /*********** Generic ***********/ @@ -221,6 +223,41 @@ void multires_del_lower_customdata(Multires *mr, MultiresLevel *cr_lvl) mr->fdata= cdf; } +/* Update all special first-level data, if the first-level is active */ +void multires_update_first_level(Mesh *me, EditMesh *em) +{ + if(me && me->mr && me->mr->current == 1) { + multires_update_customdata(me->mr->levels.first, em ? &em->vdata : &me->vdata, + &me->mr->vdata, CD_MDEFORMVERT); + multires_update_customdata(me->mr->levels.first, em ? &em->fdata : &me->fdata, + &me->mr->fdata, CD_MTFACE); + multires_update_edge_flags(me, em); + } +} + +/*********** Multires.edge_flags ***********/ +void multires_update_edge_flags(Mesh *me, EditMesh *em) +{ + MultiresLevel *lvl= me->mr->levels.first; + EditEdge *eed= NULL; + int i; + + if(em) eed= em->edges.first; + for(i=0; itotedge; ++i) { + if(em) { + me->mr->edge_flags[i]= 0; + eed_to_medge_flag(eed, &me->mr->edge_flags[i], &me->mr->edge_creases[i]); + eed= eed->next; + } + else { + me->mr->edge_flags[i]= me->medge[i].flag; + me->mr->edge_creases[i]= me->medge[i].crease; + } + } +} + + + /*********** Multires.vdata ***********/ /* MDeformVert */ diff --git a/source/blender/src/multires.c b/source/blender/src/multires.c index d1ae24e73a8..33b85bd27b6 100644 --- a/source/blender/src/multires.c +++ b/source/blender/src/multires.c @@ -52,6 +52,7 @@ #include "BKE_key.h" #include "BKE_mesh.h" #include "BKE_modifier.h" +#include "BKE_object.h" #include "BIF_editmesh.h" #include "BIF_screen.h" @@ -483,13 +484,14 @@ void multires_get_face(MultiresFace *f, EditFace *efa, MFace *m) tmp.v3= efa->v3->tmp.l; tmp.v4= 0; if(efa->v4) tmp.v4= efa->v4->tmp.l; - tmp.flag= efa->flag; - if(efa->f & 1) tmp.flag |= ME_FACE_SEL; - else f->flag &= ~ME_FACE_SEL; - if(efa->h) tmp.flag |= ME_HIDE; test_index_face(&tmp, NULL, 0, efa->v4?4:3); for(j=0; j<4; ++j) f->v[j]= (&tmp.v1)[j]; - f->flag= tmp.flag; + + /* Flags */ + f->flag= efa->flag; + if(efa->f & 1) f->flag |= ME_FACE_SEL; + else f->flag &= ~ME_FACE_SEL; + if(efa->h) f->flag |= ME_HIDE; f->mat_nr= efa->mat_nr; } else { f->v[0]= m->v1; @@ -574,12 +576,12 @@ void multires_make(void *ob, void *me_v) /* Load vertices and vdata (MDeformVerts) */ lvl->totvert= em ? BLI_countlist(&em->verts) : me->totvert; - lvl->verts= MEM_callocN(sizeof(MVert)*lvl->totvert,"multires verts"); + me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert,"multires verts"); multires_update_customdata(me->mr->levels.first, em ? &em->vdata : &me->vdata, &me->mr->vdata, CD_MDEFORMVERT); if(em) eve= em->verts.first; for(i=0; itotvert; ++i) { - multires_get_vert(&lvl->verts[i], eve, &me->mvert[i], i); + multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i); if(em) eve= eve->next; } @@ -635,7 +637,6 @@ MultiresLevel *multires_level_copy(MultiresLevel *orig) MultiresLevel *lvl= MEM_dupallocN(orig); lvl->next= lvl->prev= NULL; - lvl->verts= MEM_dupallocN(orig->verts); lvl->faces= MEM_dupallocN(orig->faces); lvl->colfaces= MEM_dupallocN(orig->colfaces); lvl->edges= MEM_dupallocN(orig->edges); @@ -657,6 +658,8 @@ Multires *multires_copy(Multires *orig) for(lvl= orig->levels.first; lvl; lvl= lvl->next) BLI_addtail(&mr->levels, multires_level_copy(lvl)); + + mr->verts= MEM_dupallocN(orig->verts); lvl= mr->levels.first; if(lvl) { @@ -689,6 +692,8 @@ void multires_free(Multires *mr) lvl= lvl->next; } + MEM_freeN(mr->verts); + BLI_freelistN(&mr->levels); MEM_freeN(mr); @@ -699,7 +704,6 @@ void multires_free(Multires *mr) void multires_free_level(MultiresLevel *lvl) { if(lvl) { - if(lvl->verts) MEM_freeN(lvl->verts); if(lvl->faces) MEM_freeN(lvl->faces); if(lvl->edges) MEM_freeN(lvl->edges); if(lvl->colfaces) MEM_freeN(lvl->colfaces); @@ -843,6 +847,7 @@ void multires_add_level(void *ob, void *me_v) Mesh *me= me_v; MultiresLevel *lvl= MEM_callocN(sizeof(MultiresLevel), "multireslevel"); MultiApplyData data; + MVert *oldverts= NULL; multires_check_state(); @@ -858,15 +863,16 @@ void multires_add_level(void *ob, void *me_v) /* Create vertices =============== */ lvl->totvert= lvl->prev->totvert + lvl->prev->totedge + lvl->prev->totface; - lvl->verts= MEM_callocN(sizeof(MVert)*lvl->totvert,"multires verts"); - /* Copy previous level's verts */ + oldverts= me->mr->verts; + me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert, "multitres verts"); + /* Copy old verts */ for(i=0; iprev->totvert; ++i) - lvl->verts[i]= lvl->prev->verts[i]; + me->mr->verts[i]= oldverts[i]; /* Create new edge verts */ for(i=0; iprev->totedge; ++i) { - VecMidf(lvl->verts[lvl->prev->totvert + i].co, - lvl->prev->verts[lvl->prev->edges[i].v[0]].co, - lvl->prev->verts[lvl->prev->edges[i].v[1]].co); + VecMidf(me->mr->verts[lvl->prev->totvert + i].co, + oldverts[lvl->prev->edges[i].v[0]].co, + oldverts[lvl->prev->edges[i].v[1]].co); lvl->prev->edges[i].mid= lvl->prev->totvert + i; } /* Create new face verts */ @@ -936,38 +942,42 @@ void multires_add_level(void *ob, void *me_v) =============== */ for(i=0; iprev->totface; ++i) { const MultiresFace *f= &lvl->prev->faces[i]; - data.corner1= lvl->prev->verts[f->v[0]].co; - data.corner2= lvl->prev->verts[f->v[1]].co; - data.corner3= lvl->prev->verts[f->v[2]].co; - data.corner4= lvl->prev->verts[f->v[3]].co; + data.corner1= oldverts[f->v[0]].co; + data.corner2= oldverts[f->v[1]].co; + data.corner3= oldverts[f->v[2]].co; + data.corner4= oldverts[f->v[3]].co; data.quad= f->v[3] ? 1 : 0; - multi_apply(lvl->verts[f->mid].co, &data, 3, catmullclark_smooth_face); + multi_apply(me->mr->verts[f->mid].co, &data, 3, catmullclark_smooth_face); } if(G.scene->toolsettings->multires_subdiv_type == 0) { for(i=0; iprev->totedge; ++i) { const MultiresEdge *e= &lvl->prev->edges[i]; data.boundary= multires_edge_is_boundary(lvl->prev,i); - edge_face_neighbor_midpoints_accum(&data,lvl->prev,lvl->verts,sizeof(MVert),e); - data.endpoint1= lvl->prev->verts[e->v[0]].co; - data.endpoint2= lvl->prev->verts[e->v[1]].co; - multi_apply(lvl->verts[e->mid].co, &data, 3, catmullclark_smooth_edge); + edge_face_neighbor_midpoints_accum(&data,lvl->prev, me->mr->verts, sizeof(MVert),e); + data.endpoint1= oldverts[e->v[0]].co; + data.endpoint2= oldverts[e->v[1]].co; + multi_apply(me->mr->verts[e->mid].co, &data, 3, catmullclark_smooth_edge); } for(i=0; iprev->totvert; ++i) { data.boundary= multires_vert_is_boundary(lvl->prev,i); - data.original= lvl->verts[i].co; + data.original= oldverts[i].co; data.edge_count= BLI_countlist(&lvl->prev->vert_edge_map[i]); if(data.boundary) - boundary_edges_average(&data,lvl->prev,lvl->prev->verts,sizeof(MVert),i); + boundary_edges_average(&data,lvl->prev, oldverts, sizeof(MVert),i); else { - vert_face_neighbor_midpoints_average(&data,lvl->prev,lvl->verts,sizeof(MVert),i); - vert_edge_neighbor_midpoints_average(&data,lvl->prev,lvl->prev->verts,sizeof(MVert),i); + vert_face_neighbor_midpoints_average(&data,lvl->prev, me->mr->verts, + sizeof(MVert),i); + vert_edge_neighbor_midpoints_average(&data,lvl->prev, oldverts, + sizeof(MVert),i); } - multi_apply(lvl->verts[i].co, &data, 3, catmullclark_smooth_vert); + multi_apply(me->mr->verts[i].co, &data, 3, catmullclark_smooth_vert); } } + MEM_freeN(oldverts); + /* Vertex Colors ============= */ curf= 0; @@ -1093,13 +1103,13 @@ void multires_level_to_mesh(Object *ob, Mesh *me, const int render) for(i=0; itotvert; ++i) { if(em) { - eves[i]= addvertlist(lvl->verts[i].co, NULL); /* TODO */ - if(lvl->verts[i].flag & 1) eves[i]->f |= SELECT; - if(lvl->verts[i].flag & ME_HIDE) eves[i]->h= 1; + eves[i]= addvertlist(me->mr->verts[i].co, NULL); + if(me->mr->verts[i].flag & 1) eves[i]->f |= SELECT; + if(me->mr->verts[i].flag & ME_HIDE) eves[i]->h= 1; eves[i]->data= NULL; } else - me->mvert[i]= lvl->verts[i]; + me->mvert[i]= me->mr->verts[i]; } for(i=0; itotedge; ++i) { if(em) { @@ -1114,9 +1124,12 @@ void multires_level_to_mesh(Object *ob, Mesh *me, const int render) if(em) { EditVert *eve4= lvl->faces[i].v[3] ? eves[lvl->faces[i].v[3]] : NULL; EditFace *efa= addfacelist(eves[lvl->faces[i].v[0]], eves[lvl->faces[i].v[1]], - eves[lvl->faces[i].v[2]], eve4, NULL, NULL); /* TODO */ - efa->flag= lvl->faces[i].flag; + eves[lvl->faces[i].v[2]], eve4, NULL, NULL); + efa->flag= lvl->faces[i].flag & ~ME_HIDE; efa->mat_nr= lvl->faces[i].mat_nr; + if(lvl->faces[i].flag & ME_FACE_SEL) + efa->f |= SELECT; + if(lvl->faces[i].flag & ME_HIDE) efa->h= 1; efa->data= NULL; } else { @@ -1159,6 +1172,14 @@ void multires_level_to_mesh(Object *ob, Mesh *me, const int render) } } } + + if(em) { + eed= em->edges.first; + for(i=0, eed= em->edges.first; itotedge; ++i, eed= eed->next) { + eed->h= me->mr->verts[lvl->edges[i].v[0]].flag & ME_HIDE || + me->mr->verts[lvl->edges[i].v[1]].flag & ME_HIDE; + } + } EM_select_flush(); @@ -1205,6 +1226,7 @@ void multires_level_to_mesh(Object *ob, Mesh *me, const int render) /* friendly check for background render */ if(G.background==0) { + object_handle_update(ob); countall(); if(G.vd && G.vd->depths) G.vd->depths->damaged= 1; @@ -1311,108 +1333,65 @@ void multires_update_colors(Mesh *me) } } -void multires_update_edge_flags(Multires *mr, Mesh *me, EditMesh *em) +/* Update vertex locations and vertex flags */ +void multires_update_vertices(Mesh *me, EditMesh *em) { - MultiresLevel *lvl= current_level(mr); - EditEdge *eed= NULL; - int i; - - if(em) eed= em->edges.first; - for(i=0; itotedge; ++i) { - if(em) { - mr->edge_flags[i]= 0; - eed_to_medge_flag(eed, &mr->edge_flags[i], &mr->edge_creases[i]); - eed= eed->next; - } - else { - mr->edge_flags[i]= me->medge[i].flag; - mr->edge_creases[i]= me->medge[i].crease; - } - } -} - -void multires_update_levels(Mesh *me, const int render) -{ - /* cr=current, pr=previous, or=original */ - MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl; - MultiresLevel *or_lvl= cr_lvl; - vec3f *pr_deltas= NULL, *cr_deltas= NULL; - char *pr_flag_damaged= NULL, *cr_flag_damaged= NULL, *pr_mat_damaged= NULL, *cr_mat_damaged= NULL; - char *or_flag_damaged= NULL, *or_mat_damaged= NULL; - EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL; + MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL, + *last_lvl= me->mr->levels.last; + vec3f *pr_deltas= NULL, *cr_deltas= NULL, *swap_deltas= NULL; EditVert *eve= NULL; - EditFace *efa= NULL; MultiApplyData data; - unsigned i,j,curf; - - /* Update special first-level data */ - if(cr_lvl==me->mr->levels.first) { - multires_update_customdata(me->mr->levels.first, em ? &em->vdata : &me->vdata, - &me->mr->vdata, CD_MDEFORMVERT); - multires_update_customdata(me->mr->levels.first, em ? &em->fdata : &me->fdata, - &me->mr->fdata, CD_MTFACE); - multires_update_edge_flags(me->mr, me, em); - } + int i, j; /* Prepare deltas */ - cr_deltas= MEM_callocN(sizeof(vec3f)*cr_lvl->totvert,"initial deltas"); + pr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 1"); + cr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 2"); /* Calculate initial deltas -- current mesh subtracted from current level*/ if(em) eve= em->verts.first; for(i=0; itotvert; ++i) { if(em) { - VecSubf(&cr_deltas[i].x, eve->co, cr_lvl->verts[i].co); + VecSubf(&cr_deltas[i].x, eve->co, me->mr->verts[i].co); eve= eve->next; } else - VecSubf(&cr_deltas[i].x, me->mvert[i].co, cr_lvl->verts[i].co); + VecSubf(&cr_deltas[i].x, me->mvert[i].co, me->mr->verts[i].co); } - - /* Faces -- find whether flag/mat has changed */ - cr_flag_damaged= MEM_callocN(sizeof(char)*cr_lvl->totface, "flag_damaged 1"); - cr_mat_damaged= MEM_callocN(sizeof(char)*cr_lvl->totface, "mat_damaged 1"); - if(em) efa= em->faces.first; - for(i=0; itotface; ++i) { - if(cr_lvl->faces[i].flag != (em ? efa->flag : me->mface[i].flag)) - cr_flag_damaged[i]= 1; - if(cr_lvl->faces[i].mat_nr != (em ? efa->mat_nr : me->mface[i].mat_nr)) - cr_mat_damaged[i]= 1; - if(em) efa= efa->next; - } - or_flag_damaged= MEM_dupallocN(cr_flag_damaged); - or_mat_damaged= MEM_dupallocN(cr_mat_damaged); - /* Update current level -- copy current mesh into current level */ - if(em) { - eve= em->verts.first; - efa= em->faces.first; + + /* Copy current level's vertex flags and clear the rest */ + if(em) eve= em->verts.first; + for(i=0; i < last_lvl->totvert; ++i) { + if(i < cr_lvl->totvert) { + MVert mvflag; + multires_get_vert(&mvflag, eve, &me->mvert[i], i); + if(em) eve= eve->next; + me->mr->verts[i].flag= mvflag.flag; + } + else + me->mr->verts[i].flag= 0; } - for(i=0; itotvert; ++i) { - multires_get_vert(&cr_lvl->verts[i], eve, &me->mvert[i], i); - if(em) eve= eve->next; - } - for(i=0; itotface; ++i) { - cr_lvl->faces[i].flag= em ? efa->flag : me->mface[i].flag; - cr_lvl->faces[i].mat_nr= em ? efa->mat_nr : me->mface[i].mat_nr; - if(em) efa= efa->next; + + /* If already on the highest level, copy current verts (including flags) into current level */ + if(cr_lvl == last_lvl) { + if(em) + eve= em->verts.first; + for(i=0; itotvert; ++i) { + multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i); + if(em) eve= eve->next; + } } /* Update higher levels */ pr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); cr_lvl= pr_lvl->next; while(cr_lvl) { - /* Set up new deltas, but keep the ones from the previous level */ - if(pr_deltas) MEM_freeN(pr_deltas); + /* Swap the old/new deltas */ + swap_deltas= pr_deltas; pr_deltas= cr_deltas; - cr_deltas= MEM_callocN(sizeof(vec3f)*cr_lvl->totvert,"deltas"); - if(pr_flag_damaged) MEM_freeN(pr_flag_damaged); - pr_flag_damaged= cr_flag_damaged; - cr_flag_damaged= MEM_callocN(sizeof(char)*cr_lvl->totface,"flag_damaged 2"); - if(pr_mat_damaged) MEM_freeN(pr_mat_damaged); - pr_mat_damaged= cr_mat_damaged; - cr_mat_damaged= MEM_callocN(sizeof(char)*cr_lvl->totface,"mat_damaged 2"); + cr_deltas= swap_deltas; /* Calculate and add new deltas - ============================*/ + ============================ */ for(i=0; itotface; ++i) { const MultiresFace *f= &pr_lvl->faces[i]; data.corner1= &pr_deltas[f->v[0]].x; @@ -1421,18 +1400,9 @@ void multires_update_levels(Mesh *me, const int render) data.corner4= &pr_deltas[f->v[3]].x; data.quad= f->v[3] ? 1 : 0; multi_apply(&cr_deltas[f->mid].x, &data, 3, catmullclark_smooth_face); - - VecAddf(cr_lvl->verts[f->mid].co, - cr_lvl->verts[f->mid].co, - &cr_deltas[f->mid].x); - cr_lvl->verts[f->mid].flag= 0; - for(j=0; j<(data.quad?4:3); ++j) { - if(pr_lvl->verts[f->v[j]].flag & 1) - cr_lvl->verts[f->mid].flag |= 1; - if(pr_lvl->verts[f->v[j]].flag & ME_HIDE) - cr_lvl->verts[f->mid].flag |= ME_HIDE; - } + for(j=0; j<(data.quad?4:3); ++j) + me->mr->verts[f->mid].flag |= me->mr->verts[f->v[j]].flag; } for(i=0; itotedge; ++i) { @@ -1442,20 +1412,9 @@ void multires_update_levels(Mesh *me, const int render) data.endpoint1= &pr_deltas[e->v[0]].x; data.endpoint2= &pr_deltas[e->v[1]].x; multi_apply(&cr_deltas[e->mid].x, &data, 3, catmullclark_smooth_edge); - - cr_lvl->verts[e->mid].flag= 0; - for(j=0; j<2; ++j) { - if(pr_lvl->verts[e->v[j]].flag & 1) - cr_lvl->verts[e->mid].flag |= 1; - if(pr_lvl->verts[e->v[j]].flag & ME_HIDE) - cr_lvl->verts[e->mid].flag |= ME_HIDE; - } - } - for(i=0; itotedge; ++i) { - const unsigned ndx= pr_lvl->edges[i].mid; - VecAddf(cr_lvl->verts[ndx].co, - cr_lvl->verts[ndx].co, - &cr_deltas[ndx].x); + + for(j=0; j<2; ++j) + me->mr->verts[e->mid].flag |= me->mr->verts[e->v[j]].flag; } for(i=0; itotvert; ++i) { @@ -1469,31 +1428,13 @@ void multires_update_levels(Mesh *me, const int render) vert_edge_neighbor_midpoints_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i); } multi_apply(&cr_deltas[i].x, &data, 3, catmullclark_smooth_vert); - cr_lvl->verts[i].flag= 0; - if(pr_lvl->verts[i].flag & 1) cr_lvl->verts[i].flag |= 1; - if(pr_lvl->verts[i].flag & ME_HIDE) cr_lvl->verts[i].flag |= ME_HIDE; - } - for(i=0; itotvert; ++i) { - VecAddf(cr_lvl->verts[i].co, - cr_lvl->verts[i].co, - &cr_deltas[i].x); } - /* Update faces */ - curf= 0; - for(i=0; itotface; ++i) { - const int sides= cr_lvl->prev->faces[i].v[3] ? 4 : 3; - for(j=0; jfaces[curf].flag= pr_lvl->faces[i].flag; - cr_flag_damaged[curf]= 1; - } - if(pr_mat_damaged[i]) { - cr_lvl->faces[curf].mat_nr= pr_lvl->faces[i].mat_nr; - cr_mat_damaged[curf]= 1; - } - ++curf; - } + /* Apply deltas to vertex locations */ + for(i=0; (cr_lvl == last_lvl) && (i < cr_lvl->totvert); ++i) { + VecAddf(me->mr->verts[i].co, + me->mr->verts[i].co, + &cr_deltas[i].x); } pr_lvl= pr_lvl->next; @@ -1502,34 +1443,51 @@ void multires_update_levels(Mesh *me, const int render) if(pr_deltas) MEM_freeN(pr_deltas); if(cr_deltas) MEM_freeN(cr_deltas); - /* Update lower levels */ - cr_lvl= me->mr->levels.last; - cr_lvl= cr_lvl->prev; - /* Update Verts */ - while(cr_lvl) { - for(i=0; itotvert; ++i) - cr_lvl->verts[i]= cr_lvl->next->verts[i]; - cr_lvl= cr_lvl->prev; - } - - /* Update Faces */ - - /* Clear to original damages */ - if(cr_flag_damaged) MEM_freeN(cr_flag_damaged); - if(cr_mat_damaged) MEM_freeN(cr_mat_damaged); - cr_flag_damaged= or_flag_damaged; - cr_mat_damaged= or_mat_damaged; - - cr_lvl= or_lvl->prev; - while(cr_lvl) { - if(pr_flag_damaged) MEM_freeN(pr_flag_damaged); - pr_flag_damaged= cr_flag_damaged; - cr_flag_damaged= MEM_callocN(sizeof(char)*cr_lvl->totface,"flag_damaged 3"); - if(pr_mat_damaged) MEM_freeN(pr_mat_damaged); - pr_mat_damaged= cr_mat_damaged; - cr_mat_damaged= MEM_callocN(sizeof(char)*cr_lvl->totface,"mat_damaged 3"); +} + +void multires_update_faces(Mesh *me, EditMesh *em) +{ + MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL, + *last_lvl= me->mr->levels.last; + char *pr_flag_damaged= NULL, *cr_flag_damaged= NULL, *or_flag_damaged= NULL, + *pr_mat_damaged= NULL, *cr_mat_damaged= NULL, *or_mat_damaged= NULL, *swap= NULL; + EditFace *efa= NULL; + unsigned i,j,curf; + + /* Find for each face whether flag/mat has changed */ + pr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1"); + cr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1"); + pr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1"); + cr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1"); + if(em) efa= em->faces.first; + for(i=0; itotface; ++i) { + MultiresFace mftmp; + multires_get_face(&mftmp, efa, &me->mface[i]); + if(cr_lvl->faces[i].flag != mftmp.flag) + cr_flag_damaged[i]= 1; + if(cr_lvl->faces[i].mat_nr != mftmp.mat_nr) + cr_mat_damaged[i]= 1; + + /* Update current level */ + cr_lvl->faces[i].flag= mftmp.flag; + cr_lvl->faces[i].mat_nr= mftmp.mat_nr; + + if(em) efa= efa->next; + } + or_flag_damaged= MEM_dupallocN(cr_flag_damaged); + or_mat_damaged= MEM_dupallocN(cr_mat_damaged); + + /* Update lower levels */ + cr_lvl= cr_lvl->prev; + while(cr_lvl) { + swap= pr_flag_damaged; + pr_flag_damaged= cr_flag_damaged; + cr_flag_damaged= swap; + + swap= pr_mat_damaged; + pr_mat_damaged= cr_mat_damaged; + cr_mat_damaged= swap; - /* Update faces */ curf= 0; for(i=0; itotface; ++i) { const int sides= cr_lvl->faces[i].v[3] ? 4 : 3; @@ -1549,14 +1507,58 @@ void multires_update_levels(Mesh *me, const int render) cr_lvl= cr_lvl->prev; } + + /* Clear to original damages */ + if(cr_flag_damaged) MEM_freeN(cr_flag_damaged); + if(cr_mat_damaged) MEM_freeN(cr_mat_damaged); + cr_flag_damaged= or_flag_damaged; + cr_mat_damaged= or_mat_damaged; + + /* Update higher levels */ + pr_lvl= current_level(me->mr); + cr_lvl= pr_lvl->next; + while(cr_lvl) { + swap= pr_flag_damaged; + pr_flag_damaged= cr_flag_damaged; + cr_flag_damaged= swap; + + swap= pr_mat_damaged; + pr_mat_damaged= cr_mat_damaged; + cr_mat_damaged= swap; + + /* Update faces */ + for(i=0, curf= 0; itotface; ++i) { + const int sides= cr_lvl->prev->faces[i].v[3] ? 4 : 3; + for(j=0; jfaces[curf].flag= pr_lvl->faces[i].flag; + cr_flag_damaged[curf]= 1; + } + if(pr_mat_damaged[i]) { + cr_lvl->faces[curf].mat_nr= pr_lvl->faces[i].mat_nr; + cr_mat_damaged[curf]= 1; + } + } + } + + pr_lvl= pr_lvl->next; + cr_lvl= cr_lvl->next; + } if(pr_flag_damaged) MEM_freeN(pr_flag_damaged); if(cr_flag_damaged) MEM_freeN(cr_flag_damaged); if(pr_mat_damaged) MEM_freeN(pr_mat_damaged); if(cr_mat_damaged) MEM_freeN(cr_mat_damaged); +} +void multires_update_levels(Mesh *me, const int render) +{ + EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL; + + multires_update_first_level(me, em); + multires_update_vertices(me, em); + multires_update_faces(me, em); multires_update_colors(me); - } void multires_calc_level_maps(MultiresLevel *lvl) diff --git a/source/blender/src/space.c b/source/blender/src/space.c index c5a485b67cf..bcb3a2784d6 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -97,6 +97,7 @@ #include "BIF_drawscript.h" #include "BIF_editarmature.h" #include "BIF_editconstraint.h" +#include "BIF_editdeform.h" #include "BIF_editfont.h" #include "BIF_editgroup.h" #include "BIF_editkey.h" @@ -1839,8 +1840,20 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) break; case GKEY: - if(G.qual == LR_CTRLKEY) - group_operation_with_menu(); + if((G.qual == LR_CTRLKEY)) { + if(G.obedit) { + if(ELEM(G.obedit->type, OB_MESH, OB_LATTICE)) + vgroup_assign_with_menu(); + } + else + group_operation_with_menu(); + } + else if((G.qual == (LR_CTRLKEY|LR_SHIFTKEY))) { + if(G.obedit) { + if(ELEM(G.obedit->type, OB_MESH, OB_LATTICE)) + vgroup_operation_with_menu(); + } + } else if((G.qual==LR_SHIFTKEY)) if(G.obedit) { if(G.obedit->type==OB_MESH) diff --git a/source/blender/src/transform_manipulator.c b/source/blender/src/transform_manipulator.c index 765c74461f2..773ae3d17ec 100644 --- a/source/blender/src/transform_manipulator.c +++ b/source/blender/src/transform_manipulator.c @@ -697,11 +697,13 @@ static void draw_manipulator_axes(int colcode, int flagx, int flagy, int flagz) /* only called while G.moving */ static void draw_manipulator_rotate_ghost(float mat[][4], int drawflags) { - GLUquadricObj *qobj= gluNewQuadric(); + GLUquadricObj *qobj; float size, phi, startphi, vec[3], svec[3], matt[4][4], cross[3], tmat[3][3]; int arcs= (G.rt!=2); glDisable(GL_DEPTH_TEST); + + qobj= gluNewQuadric(); gluQuadricDrawStyle(qobj, GLU_FILL); glColor4ub(0,0,0,64); @@ -832,7 +834,7 @@ static void draw_manipulator_rotate_ghost(float mat[][4], int drawflags) static void draw_manipulator_rotate(float mat[][4], int moving, int drawflags, int combo) { - GLUquadricObj *qobj= gluNewQuadric(); + GLUquadricObj *qobj; double plane[4]; float size, vec[3], unitmat[4][4]; float cywid= 0.33f*0.01f*(float)U.tw_handlesize; @@ -849,6 +851,8 @@ static void draw_manipulator_rotate(float mat[][4], int moving, int drawflags, i /* Init stuff */ glDisable(GL_DEPTH_TEST); Mat4One(unitmat); + + qobj= gluNewQuadric(); gluQuadricDrawStyle(qobj, GLU_FILL); /* prepare for screen aligned draw */ @@ -1153,7 +1157,7 @@ static void draw_cylinder(GLUquadricObj *qobj, float len, float width) static void draw_manipulator_translate(float mat[][4], int moving, int drawflags, int combo, int colcode) { - GLUquadricObj *qobj = gluNewQuadric(); + GLUquadricObj *qobj; float cylen= 0.01f*(float)U.tw_handlesize; float cywid= 0.25f*cylen, dz, size; float unitmat[4][4]; @@ -1163,6 +1167,8 @@ static void draw_manipulator_translate(float mat[][4], int moving, int drawflags if(moving) glTranslatef(Trans.vec[0], Trans.vec[1], Trans.vec[2]); glDisable(GL_DEPTH_TEST); + + qobj= gluNewQuadric(); gluQuadricDrawStyle(qobj, GLU_FILL); /* center circle, do not add to selection when shift is pressed (planar constraint) */ @@ -1225,19 +1231,21 @@ static void draw_manipulator_translate(float mat[][4], int moving, int drawflags static void draw_manipulator_rotate_cyl(float mat[][4], int moving, int drawflags, int combo, int colcode) { - GLUquadricObj *qobj = gluNewQuadric(); + GLUquadricObj *qobj; float size; float cylen= 0.01f*(float)U.tw_handlesize; float cywid= 0.25f*cylen; /* when called while moving in mixed mode, do not draw when... */ if((drawflags & MAN_ROT_C)==0) return; - + /* prepare for screen aligned draw */ glPushMatrix(); size= screen_aligned(mat); glDisable(GL_DEPTH_TEST); + + qobj= gluNewQuadric(); /* Screen aligned view rot circle */ if(drawflags & MAN_ROT_V) { diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index 91c527f1980..4bf13a09fb4 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -190,8 +190,9 @@ double BL_ArmatureObject::GetLastFrame() bool BL_ArmatureObject::GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix) const { - // ton hack - bPoseChannel *pchan= get_pose_channel(m_pose, bone->name); + Object* par_arma = m_objArma; + where_is_pose(par_arma); + bPoseChannel *pchan= get_pose_channel(par_arma->pose, bone->name); if(pchan) { matrix.setValue(&pchan->pose_mat[0][0]); diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp index 4e32d2cced9..ab0479eb88b 100644 --- a/source/gameengine/Ketsji/BL_Shader.cpp +++ b/source/gameengine/Ketsji/BL_Shader.cpp @@ -1,4 +1,5 @@ -// ------------------------------------ + + #ifdef WIN32 #include #endif // WIN32 diff --git a/tools/btools.py b/tools/btools.py index fba884ed09b..1dc35bb7248 100755 --- a/tools/btools.py +++ b/tools/btools.py @@ -1,7 +1,12 @@ -import sys -import StringIO +import os +import os.path import SCons.Options import SCons.Options.BoolOption +import subprocess +import string +import glob +import shutil +import sys Options = SCons.Options BoolOption = SCons.Options.BoolOption @@ -84,33 +89,26 @@ def validate_targets(targs, bc): print '\t'+bc.WARNING+'Invalid target: '+bc.ENDC+t return oklist - +class ourSpawn: + def ourspawn(self, sh, escape, cmd, args, env): + newargs = string.join(args[1:], ' ') + cmdline = cmd + " " + newargs + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False) + data, err = proc.communicate() + rv = proc.wait() + if rv: + print "=====" + print err + print "=====" + return rv -class idBuffering: - def buffered_spawn( self, sh, escape, cmd, args, env ): - stderr = StringIO.StringIO() - stdout = StringIO.StringIO() - command_string = '' - for i in args: - if ( len( command_string ) ): - command_string += ' ' - command_string += i - try: - retval = self.env['PSPAWN']( sh, escape, cmd, args, env, stdout, stderr ) - except OSError, x: - if x.errno != 10: - raise x - print 'OSError ignored on command: %s' % command_string - retval = 0 - sys.stdout.write( stdout.getvalue() ) - sys.stderr.write( stderr.getvalue() ) - return retval - -# get a clean error output when running multiple jobs -def SetupBufferedOutput( env ): - buf = idBuffering() - buf.env = env - env['SPAWN'] = buf.buffered_spawn +def SetupSpawn( env ): + buf = ourSpawn() + buf.ourenv = env + env['SPAWN'] = buf.ourspawn def read_opts(cfg, args): @@ -297,3 +295,186 @@ def read_opts(cfg, args): return localopts +def NSIS_print(target, source, env): + return "Creating NSIS installer for Blender 3D" + +def NSIS_Installer(target=None, source=None, env=None): + + if env['OURPLATFORM'] != 'win32-vc' and env['OURPLATFORM'] != 'win32-mingw': + print "NSIS installer is only available on Windows." + Exit() + + start_dir = os.getcwd() + rel_dir = start_dir + "\\release\\windows\\installer\\" + install_base_dir = start_dir + "\\" + + if not os.path.exists(install_base_dir+env['BF_INSTALLDIR']+'/plugins/include'): + os.mkdir(install_base_dir+env['BF_INSTALLDIR']+'/plugins/include') + + for f in glob.glob('source/blender/blenpluginapi/*.h'): + shutil.copy(f,install_base_dir+env['BF_INSTALLDIR']+'/plugins/include') + + shutil.copy('source/blender/blenpluginapi/plugin.def',install_base_dir+env['BF_INSTALLDIR']+'/plugins/include/') + + os.chdir("release") + v = open("VERSION") + version = v.read()[:-1] + shortver = version.split('.')[0] + version.split('.')[1] + v.close() + + #### change to suit install dir #### + inst_dir = install_base_dir + env['BF_INSTALLDIR'] + + os.chdir("windows/installer") + + ns = open("00.sconsblender.nsi","r") + + ns_cnt = str(ns.read()) + ns.close() + + # do root + rootlist = [] + rootdir = os.listdir(inst_dir+"\\") + for rootitem in rootdir: + if os.path.isdir(inst_dir+"\\"+ rootitem) == 0: + rootlist.append("File \"" + os.path.normpath(inst_dir) + "\\" + rootitem+"\"") + rootstring = string.join(rootlist, "\n ") + rootstring += "\n\n" + ns_cnt = string.replace(ns_cnt, "[ROOTDIRCONTS]", rootstring) + + # do delete items + delrootlist = [] + for rootitem in rootdir: + if os.path.isdir(inst_dir + rootitem) == 0: + delrootlist.append("Delete $INSTDIR\\" + rootitem) + delrootstring = string.join(delrootlist, "\n ") + delrootstring += "\n" + ns_cnt = string.replace(ns_cnt, "[DELROOTDIRCONTS]", delrootstring) + + # do scripts + scriptlist = [] + scriptpath = "%s%s" % (inst_dir, "\\.blender\\scripts") + scriptdir = os.listdir(scriptpath) + for scriptitem in scriptdir: + scriptfile = "%s\\%s" % (scriptpath, scriptitem) + if os.path.isdir(scriptfile) == 0: + scriptfile = os.path.normpath(scriptfile) + scriptlist.append("File \"%s\"" % scriptfile) + scriptstring = string.join(scriptlist, "\n ") + scriptstring += "\n\n" + ns_cnt = string.replace(ns_cnt, "[SCRIPTCONTS]", scriptstring) + + # do scripts\bpymodules + bpymodlist = [] + bpymodpath = "%s%s" % (inst_dir, "\\.blender\\scripts\\bpymodules") + bpymoddir = os.listdir(bpymodpath) + + for bpymoditem in bpymoddir: + bpymodfile = "%s\\%s" % (bpymodpath, bpymoditem) + if os.path.isdir(bpymodfile) == 0: + bpymodfile = os.path.normpath(bpymodfile) + bpymodlist.append("File \"%s\"" % bpymodfile) + bpymodstring = string.join(bpymodlist, "\n ") + bpymodstring += "\n\n" + ns_cnt = string.replace(ns_cnt, "[SCRIPTMODCONTS]", bpymodstring) + + # do scripts\bpymodules\colladaimex + colladalist = [] + bpymodpath = "%s%s" % (inst_dir, "\\.blender\\scripts\\bpymodules\\ColladaImEx") + bpymoddir = os.listdir(bpymodpath) + + for bpymoditem in bpymoddir: + bpymodfile = "%s\\%s" % (bpymodpath, bpymoditem) + if os.path.isdir(bpymodfile) == 0: + bpymodfile=os.path.normpath(bpymodfile) + colladalist.append("File \"%s\"" % bpymodfile) + bpymodstring = string.join(colladalist, "\n ") + bpymodstring += "\n\n" + ns_cnt = string.replace(ns_cnt, "[SCRIPTMODCOLLADACONT]", bpymodstring) + + # do scripts\bpydata + bpydatalist = [] + bpydatapath = "%s%s" % (inst_dir, "\\.blender\\scripts\\bpydata") + bpydatadir = os.listdir(bpydatapath) + for bpydataitem in bpydatadir: + bpydatafile = "%s\\%s" % (bpydatapath, bpydataitem) + if os.path.isdir(bpydatafile) == 0: + bpydatalist.append("File \"%s\"" % bpydatafile) + bpydatastring = string.join(bpydatalist, "\n ") + bpydatastring += "\n\n" + ns_cnt = string.replace(ns_cnt, "[SCRIPTDATACONTS]", bpydatastring) + + # do plugins\include + plugincludelist = [] + plugincludepath = "%s%s" % (inst_dir, "\\plugins\\include") + plugincludedir = os.listdir(plugincludepath) + for plugincludeitem in plugincludedir: + plugincludefile = "%s\\%s" % (plugincludepath, plugincludeitem) + if os.path.isdir(plugincludefile) == 0: + if plugincludefile.find('.h') or plugincludefile.find('.DEF'): + plugincludefile = os.path.normpath(plugincludefile) + plugincludelist.append("File \"%s\"" % plugincludefile) + plugincludestring = string.join(plugincludelist, "\n ") + plugincludestring += "\n\n" + ns_cnt = string.replace(ns_cnt, "[PLUGINCONTS]", plugincludestring) + + # do scripts\bpydata\config + cfglist = [] + cfgpath = "%s%s" % (inst_dir, "\\.blender\\scripts\\bpydata\\config") + cfgdir = os.listdir(cfgpath) + for cfgitem in cfgdir: + cfgfile = "%s\\%s" % (cfgpath, cfgitem) + if os.path.isdir(cfgfile) == 0: + cfglist.append("File \"%s\"" % cfgfile) + cfgstring = string.join(cfglist, "\n ") + cfgstring += "\n\n" + ns_cnt = string.replace(ns_cnt, "[SCRIPTDATACFGCONTS]", cfgstring) + + # do dotblender + dotblendlist = [] + dotblenddir = os.listdir(inst_dir+"\\.blender") + for dotblenditem in dotblenddir: + if os.path.isdir(inst_dir + "\\.blender\\" + dotblenditem) == 0: + dotblendlist.append("File \"" + os.path.normpath(inst_dir) + "\\.blender\\" + + dotblenditem+"\"") + dotblendstring = string.join(dotblendlist, "\n ") + dotblendstring += "\n\n" + ns_cnt = string.replace(ns_cnt, "[DOTBLENDERCONTS]", dotblendstring) + + # do language files + langlist = [] + langfiles = [] + langdir = os.listdir(inst_dir + "\\.blender\\locale") + for langitem in langdir: + if os.path.isdir(inst_dir + "\\.blender\\locale\\" + langitem) == 1: + langfiles.append("SetOutPath $BLENDERHOME\\.blender\\locale\\" + langitem + "\\LC_MESSAGES") + langfiles.append("File \"" + os.path.normpath(inst_dir) + "\\.blender\\locale\\" + + langitem + "\\LC_MESSAGES\\blender.mo\"") + langstring = string.join(langfiles, "\n ") + langstring += "\n\n" + ns_cnt = string.replace(ns_cnt, "[LANGUAGECONTS]", langstring) + + # var replacements + ns_cnt = string.replace(ns_cnt, "DISTDIR", os.path.normpath(inst_dir+"\\")) + ns_cnt = string.replace(ns_cnt, "SHORTVER", shortver) + ns_cnt = string.replace(ns_cnt, "VERSION", version) + ns_cnt = string.replace(ns_cnt, "RELDIR", os.path.normpath(rel_dir)) + + tmpnsi = os.path.normpath(install_base_dir+os.sep+env['BF_BUILDDIR']+os.sep+"00.blender_tmp.nsi") + new_nsis = open(tmpnsi, 'w') + new_nsis.write(ns_cnt) + new_nsis.close() + + os.chdir(start_dir) + + cmdline = "makensis " + "\""+tmpnsi+"\"" + + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, startupinfo=startupinfo, shell = True) + data, err = proc.communicate() + rv = proc.wait() + + return 0 +