Scripts:
- updating some bundled scripts, thanks to authors Jean-Michel Soler, Campbell Barton and Anthony D'Agostino. BPython: - removing wrong fix from BGL.c's glDrawPixels. note: applied guitargeek's setName patch to Blender.Key, but saw that he updated it with more functionality and assigned to stivs, so I won't commit this old version.
This commit is contained in:
@@ -18,11 +18,16 @@ that points to its official homepage, with news, downloads and documentation.
|
|||||||
Usage:<br>
|
Usage:<br>
|
||||||
Type your code and hit "Enter" to get it executed.<br>
|
Type your code and hit "Enter" to get it executed.<br>
|
||||||
- Right mouse click: Console Menu (Save output, etc);<br>
|
- Right mouse click: Console Menu (Save output, etc);<br>
|
||||||
|
- Mousewheel: Scroll text
|
||||||
- Arrow keys: command history and cursor;<br>
|
- Arrow keys: command history and cursor;<br>
|
||||||
- Shift + arrow keys: jump words;<br>
|
- Shift + Backspace: Backspace whole word;<br>
|
||||||
|
- Shift + Arrow keys: jump words;<br>
|
||||||
|
- Ctrl + (+/- or mousewheel): Zoom text size;<br>
|
||||||
- Ctrl + Tab: auto compleate based on variable names and modules loaded -- multiple choices popup a menu;<br>
|
- Ctrl + Tab: auto compleate based on variable names and modules loaded -- multiple choices popup a menu;<br>
|
||||||
- Ctrl + Enter: multiline functions -- delays executing code until only Enter is pressed.
|
- Ctrl + Enter: multiline functions -- delays executing code until only Enter is pressed.
|
||||||
"""
|
"""
|
||||||
|
__author__ = "Campbell Barton AKA Ideasman"
|
||||||
|
__url__ = ["http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun"]
|
||||||
|
|
||||||
import Blender
|
import Blender
|
||||||
from Blender import *
|
from Blender import *
|
||||||
@@ -31,14 +36,18 @@ import StringIO
|
|||||||
import types
|
import types
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
__DELIMETERS__ = '. ,=+-*/%<>&~][{}():'
|
__DELIMETERS__ = '. ,=+-*/%<>&~][{}():\t'
|
||||||
__LINE_HISTORY__ = 200
|
__VARIABLE_DELIMETERS__ = ' ,=+-*/%<>&~{}():\t'
|
||||||
|
|
||||||
|
__LINE_HISTORY__ = 500
|
||||||
|
|
||||||
global __LINE_HEIGHT__
|
|
||||||
__LINE_HEIGHT__ = 14
|
|
||||||
global __FONT_SIZE__
|
global __FONT_SIZE__
|
||||||
__FONT_SIZE__ = "normal"
|
|
||||||
|
|
||||||
|
__FONT_SIZES__ = ( ('tiny', 10), ('small', 12), ('normal', 14), ('large', 16) )
|
||||||
|
__FONT_SIZE__ = 2 # index for the list above, normal default.
|
||||||
|
|
||||||
|
global __CONSOLE_LINE_OFFSET__
|
||||||
|
__CONSOLE_LINE_OFFSET__ = 0
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# Generic Blender functions
|
# Generic Blender functions
|
||||||
@@ -52,10 +61,93 @@ def getActScriptWinRect():
|
|||||||
return None
|
return None
|
||||||
'''
|
'''
|
||||||
|
|
||||||
class cmdLine:
|
|
||||||
# cmd: is the command string, or any other message
|
# menuText, # per group
|
||||||
# type: 0:user input 1:program feedback 2:error message. 3:option feedback
|
def PupMenuLess(menu, groupSize=35):
|
||||||
# exe; 0- not yet executed 1:executed
|
more = [' more...']
|
||||||
|
less = [' less...']
|
||||||
|
|
||||||
|
menuList= menu.split('|')
|
||||||
|
|
||||||
|
# No Less Needed, just call.
|
||||||
|
if len(menuList) < groupSize:
|
||||||
|
return Draw.PupMenu(menu)
|
||||||
|
|
||||||
|
title = menuList[0].split('%t')[0]
|
||||||
|
|
||||||
|
# Split the list into groups
|
||||||
|
menuGroups = [[]]
|
||||||
|
for li in menuList[1:]:
|
||||||
|
if len(menuGroups[-1]) < groupSize:
|
||||||
|
menuGroups[-1].append(li)
|
||||||
|
else:
|
||||||
|
menuGroups.append([li])
|
||||||
|
|
||||||
|
# Stores teh current menu group we are looking at
|
||||||
|
groupIdx = 0
|
||||||
|
while 1:
|
||||||
|
# Give us a title with the menu number
|
||||||
|
numTitle = [ ' '.join([title, str(groupIdx + 1), 'of', str(len(menuGroups)), '%t'])]
|
||||||
|
if groupIdx == 0:
|
||||||
|
menuString = '|'.join(numTitle + menuGroups[groupIdx] + more)
|
||||||
|
elif groupIdx == len(menuGroups)-1:
|
||||||
|
menuString = '|'.join(numTitle + less + menuGroups[groupIdx])
|
||||||
|
else: # In the middle somewhere so Show a more and less
|
||||||
|
menuString = '|'.join(numTitle + less + menuGroups[groupIdx] + more)
|
||||||
|
result = Draw.PupMenu(menuString)
|
||||||
|
# User Exit
|
||||||
|
if result == -1:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
if groupIdx == 0: # First menu
|
||||||
|
if result-1 < groupSize:
|
||||||
|
return result
|
||||||
|
else: # must be more
|
||||||
|
groupIdx +=1
|
||||||
|
elif groupIdx == len(menuGroups): # Last Menu
|
||||||
|
if result == 1: # Must be less
|
||||||
|
groupIdx -= 1
|
||||||
|
else: # Must be a choice
|
||||||
|
return result + (groupIdx*groupSize)
|
||||||
|
|
||||||
|
else:
|
||||||
|
if result == 1: # Must be less
|
||||||
|
groupIdx -= 1
|
||||||
|
elif result-2 == groupSize:
|
||||||
|
groupIdx +=1
|
||||||
|
else:
|
||||||
|
return result - 1 + (groupIdx*groupSize)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def unzip(list):
|
||||||
|
|
||||||
|
"""
|
||||||
|
unzip: inverse of zip - converts a list of tuples into a tuple of lists
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
a,b = unzip(zip(a,b))
|
||||||
|
|
||||||
|
* note: all tuples in list have to have the same length, if not,
|
||||||
|
this function will fail
|
||||||
|
"""
|
||||||
|
|
||||||
|
if len(list) == 0: return ()
|
||||||
|
l = []
|
||||||
|
for t in range(len(list[0])):
|
||||||
|
l.append(map( lambda x,t=t: x[t], list ))
|
||||||
|
return tuple(l)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Use newstyle classes, Im not bothering with inheretence
|
||||||
|
# but slots are faster.
|
||||||
|
class cmdLine(object):
|
||||||
|
__slots__ = [\
|
||||||
|
'cmd', # is the command string, or any other message
|
||||||
|
'type',# type: 0:user input 1:program feedback 2:error message. 3:option feedback
|
||||||
|
'exe' # 0- not yet executed 1:executed
|
||||||
|
]
|
||||||
def __init__(self, cmd, type, exe):
|
def __init__(self, cmd, type, exe):
|
||||||
self.cmd = cmd
|
self.cmd = cmd
|
||||||
self.type = type
|
self.type = type
|
||||||
@@ -97,13 +189,33 @@ def insertCmdData(cmdBuffer):
|
|||||||
COLLECTED_VAR_NAMES = {} # a list of keys, each key has a list of absolute paths
|
COLLECTED_VAR_NAMES = {} # a list of keys, each key has a list of absolute paths
|
||||||
|
|
||||||
# Pain and simple recursice dir(), accepts a string
|
# Pain and simple recursice dir(), accepts a string
|
||||||
def rdir(dirString):
|
def rdir(dirString, depth=0):
|
||||||
|
|
||||||
|
# MAX DEPTH SET HERE
|
||||||
|
if depth > 4:
|
||||||
|
print 'maxdepoth reached.'
|
||||||
|
return
|
||||||
|
|
||||||
global COLLECTED_VAR_NAMES
|
global COLLECTED_VAR_NAMES
|
||||||
dirStringSplit = dirString.split('.')
|
dirStringSplit = dirString.split('.')
|
||||||
|
|
||||||
exec('dirList = dir(%s)' % dirString)
|
exec('dirList = dir(%s)' % dirString)
|
||||||
for dirItem in dirList:
|
for dirItem in dirList:
|
||||||
if not dirItem.startswith('_'):
|
if dirItem.startswith('_'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
dirData = None
|
||||||
|
try:
|
||||||
|
# Rare cases this can mess up, material.shader was a problem.
|
||||||
|
exec('dirData = %s.%s' % (dirString, dirItem))
|
||||||
|
#print dirData
|
||||||
|
except:
|
||||||
|
# Dont bother with this data.
|
||||||
|
continue
|
||||||
|
|
||||||
|
if type(dirItem) != type('str'):
|
||||||
|
print dirItem, type(dirItem)
|
||||||
|
|
||||||
if dirItem not in COLLECTED_VAR_NAMES.keys():
|
if dirItem not in COLLECTED_VAR_NAMES.keys():
|
||||||
COLLECTED_VAR_NAMES[dirItem] = []
|
COLLECTED_VAR_NAMES[dirItem] = []
|
||||||
|
|
||||||
@@ -113,16 +225,32 @@ def rdir(dirString):
|
|||||||
COLLECTED_VAR_NAMES[dirItem].append(splitD)
|
COLLECTED_VAR_NAMES[dirItem].append(splitD)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Stops recursice stuff, overlooping
|
# Stops recursice stuff, overlooping
|
||||||
if type(dirItem) == types.ClassType or \
|
#print type(dirItem)
|
||||||
type(dirItem) == types.ModuleType:
|
#if type(dirData) == types.ClassType or \
|
||||||
|
# type(dirData) == types.ModuleType:
|
||||||
print dirString, splitD, dirItem
|
|
||||||
|
|
||||||
|
if type(dirData) != types.StringType and\
|
||||||
|
type(dirData) != types.DictType and\
|
||||||
|
type(dirData) != types.DictionaryType and\
|
||||||
|
type(dirData) != types.FloatType and\
|
||||||
|
type(dirData) != types.IntType and\
|
||||||
|
type(dirData) != types.NoneType and\
|
||||||
|
type(dirData) != types.StringTypes and\
|
||||||
|
type(dirData) != types.TypeType and\
|
||||||
|
type(dirData) != types.TupleType and\
|
||||||
|
type(dirData) != types.BuiltinFunctionType:
|
||||||
|
# print type(dirData), dirItem
|
||||||
# Dont loop up dirs for strings ints etc.
|
# Dont loop up dirs for strings ints etc.
|
||||||
if d not in dirStringSplit:
|
if dirItem not in dirStringSplit:
|
||||||
rdir( '%s.%s' % (dirString, d))
|
rdir( '%s.%s' % (dirString, dirItem), depth+1)
|
||||||
|
'''
|
||||||
|
elif depth == 0: # Add local variables
|
||||||
|
# print type(dirData), dirItem
|
||||||
|
# Dont loop up dirs for strings ints etc.
|
||||||
|
if dirItem not in dirStringSplit:
|
||||||
|
rdir( '%s.%s' % (dirString, dirItem), depth+1)
|
||||||
|
'''
|
||||||
|
|
||||||
def recursive_dir():
|
def recursive_dir():
|
||||||
global COLLECTED_VAR_NAMES
|
global COLLECTED_VAR_NAMES
|
||||||
@@ -148,13 +276,17 @@ def runUserCode(__USER_CODE_STRING__):
|
|||||||
# Try and run the user entered line(s)
|
# Try and run the user entered line(s)
|
||||||
try:
|
try:
|
||||||
# Load all variabls from global dict to local space.
|
# Load all variabls from global dict to local space.
|
||||||
for __TMP_VAR_NAME__ in __CONSOLE_VAR_DICT__.keys():
|
for __TMP_VAR_NAME__, __TMP_VAR__ in __CONSOLE_VAR_DICT__.items():
|
||||||
exec('%s%s%s%s' % (__TMP_VAR_NAME__,'=__CONSOLE_VAR_DICT__["', __TMP_VAR_NAME__, '"]'))
|
exec('%s%s' % (__TMP_VAR_NAME__,'=__TMP_VAR__'))
|
||||||
del __TMP_VAR_NAME__
|
del __TMP_VAR_NAME__
|
||||||
|
del __TMP_VAR__
|
||||||
|
|
||||||
# Now all the vars are loaded, execute the code. # Newline thanks to phillip,
|
# Now all the vars are loaded, execute the code. # Newline thanks to phillip,
|
||||||
exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'single')) #exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'exec'))
|
exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'single')) #exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'exec'))
|
||||||
|
|
||||||
|
# Flush global dict, allow the user to remove items.
|
||||||
|
__CONSOLE_VAR_DICT__ = {}
|
||||||
|
|
||||||
# Write local veriables to global __CONSOLE_VAR_DICT__
|
# Write local veriables to global __CONSOLE_VAR_DICT__
|
||||||
for __TMP_VAR_NAME__ in dir():
|
for __TMP_VAR_NAME__ in dir():
|
||||||
if __TMP_VAR_NAME__ != '__FILE_LIKE_STRING__' and\
|
if __TMP_VAR_NAME__ != '__FILE_LIKE_STRING__' and\
|
||||||
@@ -167,14 +299,16 @@ def runUserCode(__USER_CODE_STRING__):
|
|||||||
del __TMP_VAR_NAME__
|
del __TMP_VAR_NAME__
|
||||||
|
|
||||||
except: # Prints the REAL exception.
|
except: # Prints the REAL exception.
|
||||||
error = str(python_sys.exc_value)
|
error = '%s: %s' % (python_sys.exc_type, python_sys.exc_value)
|
||||||
for errorLine in error.split('\n'):
|
for errorLine in error.split('\n'):
|
||||||
cmdBuffer.append(cmdLine(errorLine, 2, None)) # new line to type into
|
cmdBuffer.append(cmdLine(errorLine, 2, None)) # new line to type into
|
||||||
|
|
||||||
python_sys.stdout = __STD_OUTPUT__ # Go back to output to the normal blender console
|
python_sys.stdout = __STD_OUTPUT__ # Go back to output to the normal blender console
|
||||||
|
|
||||||
# Copy all new output to cmdBuffer
|
# Copy all new output to cmdBuffer
|
||||||
|
|
||||||
__FILE_LIKE_STRING__.seek(0) # the readline function requires that we go back to the start of the file.
|
__FILE_LIKE_STRING__.seek(0) # the readline function requires that we go back to the start of the file.
|
||||||
|
|
||||||
for line in __FILE_LIKE_STRING__.readlines():
|
for line in __FILE_LIKE_STRING__.readlines():
|
||||||
cmdBuffer.append(cmdLine(line, 1, None))
|
cmdBuffer.append(cmdLine(line, 1, None))
|
||||||
|
|
||||||
@@ -203,34 +337,61 @@ def handle_event(evt, val):
|
|||||||
#------------------------------------------------------------------------------#
|
#------------------------------------------------------------------------------#
|
||||||
def actionEnterKey():
|
def actionEnterKey():
|
||||||
global histIndex, cursor, cmdBuffer
|
global histIndex, cursor, cmdBuffer
|
||||||
# Check for the neter kay hit
|
|
||||||
if Window.GetKeyQualifiers() & Window.Qual.CTRL: # HOLDING DOWN SHIFT, GO TO NEXT LINE.
|
def getIndent(string):
|
||||||
cmdBuffer.append(cmdLine(' ', 0, 0))
|
# Gather white space to add in the previous line
|
||||||
|
# Ignore the last char since its padding.
|
||||||
|
whiteSpace = ''
|
||||||
|
#for i in range(len(cmdBuffer[-1].cmd)):
|
||||||
|
for i in range(len(string)-1):
|
||||||
|
if cmdBuffer[-1].cmd[i] == ' ' or cmdBuffer[-1].cmd[i] == '\t':
|
||||||
|
whiteSpace += string[i]
|
||||||
else:
|
else:
|
||||||
|
break
|
||||||
|
return whiteSpace
|
||||||
|
|
||||||
|
# Are we in the moddle of a multiline part or not?
|
||||||
|
# try be smart about it
|
||||||
|
if cmdBuffer[-1].cmd.split('#')[0].rstrip().endswith(':'):
|
||||||
|
# : indicates an indent is needed
|
||||||
|
cmdBuffer.append(cmdLine('\t%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0))
|
||||||
|
print ': indicates an indent is needed'
|
||||||
|
|
||||||
|
elif cmdBuffer[-1].cmd[0] in [' ', '\t'] and len(cmdBuffer[-1].cmd) > 1 and cmdBuffer[-1].cmd.split():
|
||||||
|
# white space at the start means he havnt finished the multiline.
|
||||||
|
cmdBuffer.append(cmdLine('%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0))
|
||||||
|
print 'white space at the start means he havnt finished the multiline.'
|
||||||
|
|
||||||
|
elif Window.GetKeyQualifiers() & Window.Qual.CTRL:
|
||||||
|
# Crtl forces multiline
|
||||||
|
cmdBuffer.append(cmdLine('%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0))
|
||||||
|
print 'Crtl forces multiline'
|
||||||
|
|
||||||
|
else: # Execute multiline code block
|
||||||
|
|
||||||
# Multiline code will still run with 1 line,
|
# Multiline code will still run with 1 line,
|
||||||
multiLineCode = ['if 1:']
|
multiLineCode = ['if 1:'] # End of the multiline first.
|
||||||
if cmdBuffer[-1].cmd != ' ':
|
|
||||||
multiLineCode = ['%s%s' % (' ', cmdBuffer[-1].cmd)] # added space for fake if.
|
# Seek the start of the file multiline
|
||||||
else:
|
i = 1
|
||||||
cmdBuffer[-1].type = 1
|
|
||||||
multiLineCode = []
|
|
||||||
cmdBuffer[-1].exe = 1
|
|
||||||
i = 2
|
|
||||||
while cmdBuffer[-i].exe == 0:
|
while cmdBuffer[-i].exe == 0:
|
||||||
|
i+=1
|
||||||
|
|
||||||
|
while i > 1:
|
||||||
|
i-=1
|
||||||
|
|
||||||
if cmdBuffer[-i].cmd == ' ':# Tag as an output type so its not used in the key history
|
if cmdBuffer[-i].cmd == ' ':# Tag as an output type so its not used in the key history
|
||||||
cmdBuffer[-i].type = 1
|
cmdBuffer[-i].type = 1
|
||||||
else: # space added at the start for added if 1: statement
|
else: # Tab added at the start for added if 1: statement
|
||||||
multiLineCode.append('%s%s' % (' ', cmdBuffer[-i].cmd) )
|
multiLineCode.append('\t%s' % cmdBuffer[-i].cmd )
|
||||||
|
|
||||||
# Mark as executed
|
# Mark as executed
|
||||||
cmdBuffer[-i].exe = 1
|
cmdBuffer[-i].exe = 1
|
||||||
i+=1
|
|
||||||
|
|
||||||
# add if to the end, reverse will make it the start.
|
multiLineCode.append('\tpass') # reverse will make this the start.
|
||||||
multiLineCode.append('if 1:')
|
|
||||||
multiLineCode.reverse()
|
|
||||||
multiLineCode.append(' pass') # Now this is the end
|
|
||||||
|
|
||||||
|
# Dubug, print the code that is executed.
|
||||||
|
#for m in multiLineCode: print m
|
||||||
|
|
||||||
runUserCode('\n'.join(multiLineCode))
|
runUserCode('\n'.join(multiLineCode))
|
||||||
|
|
||||||
@@ -262,9 +423,8 @@ def handle_event(evt, val):
|
|||||||
|
|
||||||
def actionRightMouse():
|
def actionRightMouse():
|
||||||
global __FONT_SIZE__
|
global __FONT_SIZE__
|
||||||
global __LINE_HEIGHT__
|
choice = Draw.PupMenu('Console Menu%t|Write Input Data (white)|Write Output Data (blue)|Write Error Data (red)|Write All Text|%l|Insert Blender text|%l|Font Size|%l|Quit')
|
||||||
choice = Draw.PupMenu('Console Menu%t|Write Input Data (white)|Write Output Data (blue)|Write Error Data (red)|Write All Text|%l|Insert Blender text|%l|Font Size|%l|Help|%l|Quit')
|
|
||||||
# print choice
|
|
||||||
if choice == 1:
|
if choice == 1:
|
||||||
writeCmdData(cmdBuffer, 0) # type 0 user
|
writeCmdData(cmdBuffer, 0) # type 0 user
|
||||||
elif choice == 2:
|
elif choice == 2:
|
||||||
@@ -274,54 +434,55 @@ def handle_event(evt, val):
|
|||||||
elif choice == 4:
|
elif choice == 4:
|
||||||
writeCmdData(cmdBuffer, 3) # All
|
writeCmdData(cmdBuffer, 3) # All
|
||||||
elif choice == 6:
|
elif choice == 6:
|
||||||
insertCmdData(cmdBuffer) # All
|
insertCmdData(cmdBuffer) # Insert text from Blender and run it.
|
||||||
elif choice == 8:
|
elif choice == 8:
|
||||||
# Fontsize.
|
# Fontsize.
|
||||||
font_choice = Draw.PupMenu('Font Size%t|Large|Normal|Small|Tiny')
|
font_choice = Draw.PupMenu('Font Size%t|Large|Normal|Small|Tiny')
|
||||||
if font_choice != -1:
|
if font_choice != -1:
|
||||||
if font_choice == 1:
|
if font_choice == 1:
|
||||||
__FONT_SIZE__ = 'large'
|
__FONT_SIZE__ = 3
|
||||||
__LINE_HEIGHT__ = 16
|
|
||||||
elif font_choice == 2:
|
elif font_choice == 2:
|
||||||
__FONT_SIZE__ = 'normal'
|
__FONT_SIZE__ = 2
|
||||||
__LINE_HEIGHT__ = 14
|
|
||||||
elif font_choice == 3:
|
elif font_choice == 3:
|
||||||
__FONT_SIZE__ = 'small'
|
__FONT_SIZE__ = 1
|
||||||
__LINE_HEIGHT__ = 12
|
|
||||||
elif font_choice == 4:
|
elif font_choice == 4:
|
||||||
__FONT_SIZE__ = 'tiny'
|
__FONT_SIZE__ = 0
|
||||||
__LINE_HEIGHT__ = 10
|
|
||||||
Draw.Redraw()
|
Draw.Redraw()
|
||||||
elif choice == 10:
|
|
||||||
Blender.ShowHelp('console.py')
|
elif choice == 10: # Exit
|
||||||
elif choice == 12: # Exit
|
|
||||||
Draw.Exit()
|
Draw.Exit()
|
||||||
|
|
||||||
|
|
||||||
# Auto compleating, quite complex- use recutsice dir for the moment.
|
# Auto compleating, quite complex- use recutsice dir for the moment.
|
||||||
def actionAutoCompleate(): # Ctrl + Tab
|
def actionAutoCompleate(): # Ctrl + Tab
|
||||||
|
if not cmdBuffer[-1].cmd[:cursor].split():
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
RECURSIVE_DIR = recursive_dir()
|
RECURSIVE_DIR = recursive_dir()
|
||||||
|
|
||||||
# get last name of user input
|
# get last name of user input
|
||||||
editVar = cmdBuffer[-1].cmd[:cursor]
|
editVar = cmdBuffer[-1].cmd[:cursor]
|
||||||
|
|
||||||
# Split off spaces operators etc from the staryt of the command so we can use the startswith function.
|
# Split off spaces operators etc from the staryt of the command so we can use the startswith function.
|
||||||
for splitChar in __DELIMETERS__:
|
for splitChar in __VARIABLE_DELIMETERS__:
|
||||||
editVar = editVar.split(splitChar)[-1]
|
editVar = editVar[:-1].split(splitChar)[-1] + editVar[-1]
|
||||||
|
|
||||||
|
|
||||||
# Now we should have the var by its self
|
# Now we should have the var by its self
|
||||||
if editVar:
|
if editVar:
|
||||||
|
|
||||||
possibilities = []
|
possibilities = []
|
||||||
|
|
||||||
print editVar, 'editVar'
|
|
||||||
for __TMP_VAR_NAME__ in RECURSIVE_DIR.keys():
|
for __TMP_VAR_NAME__ in RECURSIVE_DIR.keys():
|
||||||
|
#print '\t', __TMP_VAR_NAME__
|
||||||
if __TMP_VAR_NAME__ == editVar:
|
if __TMP_VAR_NAME__ == editVar:
|
||||||
# print 'ADITVAR IS A VAR'
|
# print 'ADITVAR IS A VAR'
|
||||||
continue
|
pass
|
||||||
|
'''
|
||||||
elif __TMP_VAR_NAME__.startswith( editVar ):
|
elif __TMP_VAR_NAME__.startswith( editVar ):
|
||||||
|
print __TMP_VAR_NAME__, 'aaa'
|
||||||
|
possibilities.append( __TMP_VAR_NAME__ )
|
||||||
|
'''
|
||||||
possibilities.append( __TMP_VAR_NAME__ )
|
possibilities.append( __TMP_VAR_NAME__ )
|
||||||
|
|
||||||
|
|
||||||
if len(possibilities) == 1:
|
if len(possibilities) == 1:
|
||||||
cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], possibilities[0], cmdBuffer[-1].cmd[cursor:]))
|
cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], possibilities[0], cmdBuffer[-1].cmd[cursor:]))
|
||||||
@@ -332,36 +493,50 @@ def handle_event(evt, val):
|
|||||||
# Text choice
|
# Text choice
|
||||||
#cmdBuffer.insert(-1, cmdLine('options: %s' % ' '.join(possibilities), 3, None))
|
#cmdBuffer.insert(-1, cmdLine('options: %s' % ' '.join(possibilities), 3, None))
|
||||||
|
|
||||||
menuText = 'Choices (hold shift for whole name)%t|'
|
menuList = [] # A lits of tuples- ABSOLUTE, RELATIVE
|
||||||
menuList = []
|
|
||||||
menuListAbs = []
|
|
||||||
possibilities.sort() # make nice :)
|
|
||||||
for __TMP_VAR_NAME__ in possibilities:
|
for __TMP_VAR_NAME__ in possibilities:
|
||||||
for usage in RECURSIVE_DIR[__TMP_VAR_NAME__]:
|
for usage in RECURSIVE_DIR[__TMP_VAR_NAME__]:
|
||||||
# Account for non absolute (variables for eg.)
|
# Account for non absolute (variables for eg.)
|
||||||
if usage: # not ''
|
if usage: # not ''
|
||||||
menuListAbs.append('%s.%s' % (usage, __TMP_VAR_NAME__)) # Used for names and can be entered when pressing shift.
|
absName = '%s.%s' % (usage, __TMP_VAR_NAME__)
|
||||||
else:
|
if absName.find('.'+editVar) != -1 or\
|
||||||
menuListAbs.append(__TMP_VAR_NAME__) # Used for names and can be entered when pressing shift.
|
absName.startswith(editVar) or\
|
||||||
|
__TMP_VAR_NAME__.startswith(editVar):
|
||||||
|
#print editVar, 'found in', absName
|
||||||
|
menuList.append( # Used for names and can be entered when pressing shift.
|
||||||
|
(absName, # Absolute name
|
||||||
|
__TMP_VAR_NAME__) # Relative name, non shift
|
||||||
|
)
|
||||||
|
#else:
|
||||||
|
# if absName.find(editVar) != -1:
|
||||||
|
# menuList.append((__TMP_VAR_NAME__, __TMP_VAR_NAME__)) # Used for names and can be entered when pressing shift.
|
||||||
|
|
||||||
menuList.append(__TMP_VAR_NAME__) # Used for non Shift
|
# No items to display? no menu
|
||||||
|
if not menuList:
|
||||||
|
return
|
||||||
|
|
||||||
|
menuList.sort()
|
||||||
|
|
||||||
|
choice = PupMenuLess( # Menu for the user to choose the autocompleate
|
||||||
|
'Choices (Shift for Whole name, Ctrl for Docs)%t|' + # Title Text
|
||||||
|
'|'.join(['%s, %s' % m for m in menuList])) # Use Absolute names m[0]
|
||||||
|
|
||||||
#choice = Draw.PupMenu('Select Variabe name%t|' + '|'.join(possibilities) )
|
|
||||||
choice = Draw.PupMenu(menuText + '|'.join(menuListAbs))
|
|
||||||
if choice != -1:
|
if choice != -1:
|
||||||
|
if Window.GetKeyQualifiers() & Window.Qual.CTRL: # Help
|
||||||
|
cmdBuffer[-1].cmd = ('help(%s%s) ' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0]))
|
||||||
|
elif Window.GetKeyQualifiers() & Window.Qual.SHIFT: # Put in the long name
|
||||||
|
cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0], cmdBuffer[-1].cmd[cursor:]))
|
||||||
|
else: # Only paste in the Short name
|
||||||
|
cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][1], cmdBuffer[-1].cmd[cursor:]))
|
||||||
|
|
||||||
if not Window.GetKeyQualifiers() & Window.Qual.SHIFT: # Only paste in the Short name
|
|
||||||
cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1], cmdBuffer[-1].cmd[cursor:]))
|
|
||||||
else: # Put in the long name
|
|
||||||
cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuListAbs[choice-1], cmdBuffer[-1].cmd[cursor:]))
|
|
||||||
else:
|
else:
|
||||||
# print 'NO EDITVAR'
|
# print 'NO EDITVAR'
|
||||||
return
|
return
|
||||||
|
|
||||||
# ------------------end------------------#
|
# ------------------end------------------ #
|
||||||
|
|
||||||
|
|
||||||
|
# Quit from menu only
|
||||||
#if (evt == Draw.ESCKEY and not val):
|
#if (evt == Draw.ESCKEY and not val):
|
||||||
# Draw.Exit()
|
# Draw.Exit()
|
||||||
if evt == Draw.MOUSEX: # AVOID TOO MANY REDRAWS.
|
if evt == Draw.MOUSEX: # AVOID TOO MANY REDRAWS.
|
||||||
@@ -370,11 +545,16 @@ def handle_event(evt, val):
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
global cursor
|
global cursor
|
||||||
global histIndex
|
global histIndex
|
||||||
|
global __FONT_SIZE__
|
||||||
|
global __CONSOLE_LINE_OFFSET__
|
||||||
|
|
||||||
ascii = Blender.event
|
ascii = Blender.event
|
||||||
|
|
||||||
|
resetScroll = True
|
||||||
|
|
||||||
#------------------------------------------------------------------------------#
|
#------------------------------------------------------------------------------#
|
||||||
# key codes and key handling #
|
# key codes and key handling #
|
||||||
#------------------------------------------------------------------------------#
|
#------------------------------------------------------------------------------#
|
||||||
@@ -436,23 +616,57 @@ def handle_event(evt, val):
|
|||||||
else:
|
else:
|
||||||
insCh('\t')
|
insCh('\t')
|
||||||
|
|
||||||
elif (evt == Draw.BACKSPACEKEY and val): cmdBuffer[-1].cmd = ('%s%s' % (cmdBuffer[-1].cmd[:cursor-1] , cmdBuffer[-1].cmd[cursor:]))
|
elif (evt == Draw.BACKSPACEKEY and val):
|
||||||
|
if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
|
||||||
|
i = -1
|
||||||
|
for d in __DELIMETERS__:
|
||||||
|
i = max(i, cmdBuffer[-1].cmd[:cursor-1].rfind(d))
|
||||||
|
if i == -1:
|
||||||
|
i=0
|
||||||
|
cmdBuffer[-1].cmd = ('%s%s' % (cmdBuffer[-1].cmd[:i] , cmdBuffer[-1].cmd[cursor:]))
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Normal backspace.
|
||||||
|
cmdBuffer[-1].cmd = ('%s%s' % (cmdBuffer[-1].cmd[:cursor-1] , cmdBuffer[-1].cmd[cursor:]))
|
||||||
|
|
||||||
elif (evt == Draw.DELKEY and val) and cursor < -1:
|
elif (evt == Draw.DELKEY and val) and cursor < -1:
|
||||||
cmdBuffer[-1].cmd = cmdBuffer[-1].cmd[:cursor] + cmdBuffer[-1].cmd[cursor+1:]
|
cmdBuffer[-1].cmd = cmdBuffer[-1].cmd[:cursor] + cmdBuffer[-1].cmd[cursor+1:]
|
||||||
cursor +=1
|
cursor +=1
|
||||||
|
|
||||||
elif ((evt == Draw.RETKEY or evt == Draw.PADENTER) and val): actionEnterKey()
|
elif ((evt == Draw.RETKEY or evt == Draw.PADENTER) and val): actionEnterKey()
|
||||||
elif (evt == Draw.RIGHTMOUSE and not val):actionRightMouse(); return
|
elif (evt == Draw.RIGHTMOUSE and not val): actionRightMouse(); return
|
||||||
|
|
||||||
|
elif (evt == Draw.PADPLUSKEY or evt == Draw.EQUALKEY or evt == Draw.WHEELUPMOUSE) and val and Window.GetKeyQualifiers() & Window.Qual.CTRL:
|
||||||
|
__FONT_SIZE__ += 1
|
||||||
|
__FONT_SIZE__ = min(len(__FONT_SIZES__)-1, __FONT_SIZE__)
|
||||||
|
elif (evt == Draw.PADMINUS or evt == Draw.MINUSKEY or evt == Draw.WHEELDOWNMOUSE) and val and Window.GetKeyQualifiers() & Window.Qual.CTRL:
|
||||||
|
__FONT_SIZE__ -=1
|
||||||
|
__FONT_SIZE__ = max(0, __FONT_SIZE__)
|
||||||
|
|
||||||
|
|
||||||
|
elif evt == Draw.WHEELUPMOUSE and val:
|
||||||
|
__CONSOLE_LINE_OFFSET__ += 1
|
||||||
|
__CONSOLE_LINE_OFFSET__ = min(len(cmdBuffer)-2, __CONSOLE_LINE_OFFSET__)
|
||||||
|
resetScroll = False
|
||||||
|
|
||||||
|
elif evt == Draw.WHEELDOWNMOUSE and val:
|
||||||
|
__CONSOLE_LINE_OFFSET__ -= 1
|
||||||
|
__CONSOLE_LINE_OFFSET__ = max(0, __CONSOLE_LINE_OFFSET__)
|
||||||
|
resetScroll = False
|
||||||
|
|
||||||
|
|
||||||
elif ascii:
|
elif ascii:
|
||||||
insCh(chr(ascii))
|
insCh(chr(ascii))
|
||||||
else:
|
else:
|
||||||
return # dont redraw.
|
return # dont redraw.
|
||||||
|
|
||||||
|
# If the user types in anything then scroll to bottom.
|
||||||
|
if resetScroll:
|
||||||
|
__CONSOLE_LINE_OFFSET__ = 0
|
||||||
Draw.Redraw()
|
Draw.Redraw()
|
||||||
|
|
||||||
|
|
||||||
def draw_gui():
|
def draw_gui():
|
||||||
|
|
||||||
# Get the bounds from ObleGL directly
|
# Get the bounds from ObleGL directly
|
||||||
__CONSOLE_RECT__ = BGL.Buffer(BGL.GL_FLOAT, 4)
|
__CONSOLE_RECT__ = BGL.Buffer(BGL.GL_FLOAT, 4)
|
||||||
BGL.glGetFloatv(BGL.GL_SCISSOR_BOX, __CONSOLE_RECT__)
|
BGL.glGetFloatv(BGL.GL_SCISSOR_BOX, __CONSOLE_RECT__)
|
||||||
@@ -462,20 +676,24 @@ def draw_gui():
|
|||||||
BGL.glClearColor(0.0, 0.0, 0.0, 1.0)
|
BGL.glClearColor(0.0, 0.0, 0.0, 1.0)
|
||||||
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) # use it to clear the color buffer
|
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) # use it to clear the color buffer
|
||||||
|
|
||||||
|
|
||||||
|
# Fixed margin. use a margin since 0 margin can be hard to seewhen close to a crt's edge.
|
||||||
|
margin = 4
|
||||||
|
|
||||||
# Draw cursor location colour
|
# Draw cursor location colour
|
||||||
cmd2curWidth = Draw.GetStringWidth(cmdBuffer[-1].cmd[:cursor], __FONT_SIZE__)
|
if __CONSOLE_LINE_OFFSET__ == 0:
|
||||||
|
cmd2curWidth = Draw.GetStringWidth(cmdBuffer[-1].cmd[:cursor], __FONT_SIZES__[__FONT_SIZE__][0])
|
||||||
BGL.glColor3f(0.8, 0.2, 0.2)
|
BGL.glColor3f(0.8, 0.2, 0.2)
|
||||||
if cmd2curWidth == 0:
|
if cmd2curWidth == 0:
|
||||||
BGL.glRecti(0,2,2, __LINE_HEIGHT__+2)
|
BGL.glRecti(margin,2,margin+2, __FONT_SIZES__[__FONT_SIZE__][1]+2)
|
||||||
else:
|
else:
|
||||||
BGL.glRecti(cmd2curWidth-2,2,cmd2curWidth, __LINE_HEIGHT__+2)
|
BGL.glRecti(margin + cmd2curWidth-2,2, margin+cmd2curWidth, __FONT_SIZES__[__FONT_SIZE__][1]+2)
|
||||||
|
|
||||||
BGL.glColor3f(1,1,1)
|
BGL.glColor3f(1,1,1)
|
||||||
# Draw the set of cammands to the buffer
|
# Draw the set of cammands to the buffer
|
||||||
|
consoleLineIdx = __CONSOLE_LINE_OFFSET__ + 1
|
||||||
consoleLineIdx = 1
|
|
||||||
wrapLineIndex = 0
|
wrapLineIndex = 0
|
||||||
while consoleLineIdx < len(cmdBuffer) and __CONSOLE_RECT__[3] > consoleLineIdx*__LINE_HEIGHT__ :
|
while consoleLineIdx < len(cmdBuffer) and __CONSOLE_RECT__[3] > (consoleLineIdx - __CONSOLE_LINE_OFFSET__) * __FONT_SIZES__[__FONT_SIZE__][1]:
|
||||||
if cmdBuffer[-consoleLineIdx].type == 0:
|
if cmdBuffer[-consoleLineIdx].type == 0:
|
||||||
BGL.glColor3f(1, 1, 1)
|
BGL.glColor3f(1, 1, 1)
|
||||||
elif cmdBuffer[-consoleLineIdx].type == 1:
|
elif cmdBuffer[-consoleLineIdx].type == 1:
|
||||||
@@ -488,17 +706,18 @@ def draw_gui():
|
|||||||
BGL.glColor3f(1, 1, 0)
|
BGL.glColor3f(1, 1, 0)
|
||||||
|
|
||||||
if consoleLineIdx == 1: # NEVER WRAP THE USER INPUT
|
if consoleLineIdx == 1: # NEVER WRAP THE USER INPUT
|
||||||
BGL.glRasterPos2i(0, (__LINE_HEIGHT__*consoleLineIdx) - 8)
|
BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * (consoleLineIdx-__CONSOLE_LINE_OFFSET__)) - 8)
|
||||||
Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZE__)
|
# BUG, LARGE TEXT DOSENT DISPLAY
|
||||||
|
Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0])
|
||||||
|
|
||||||
|
|
||||||
else: # WRAP?
|
else: # WRAP?
|
||||||
# LINE WRAP
|
# LINE WRAP
|
||||||
if Draw.GetStringWidth(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZE__) > __CONSOLE_RECT__[2]:
|
if Draw.GetStringWidth(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0]) > __CONSOLE_RECT__[2]:
|
||||||
wrapLineList = []
|
wrapLineList = []
|
||||||
copyCmd = [cmdBuffer[-consoleLineIdx].cmd, '']
|
copyCmd = [cmdBuffer[-consoleLineIdx].cmd, '']
|
||||||
while copyCmd != ['','']:
|
while copyCmd != ['','']:
|
||||||
while Draw.GetStringWidth(copyCmd[0], __FONT_SIZE__) > __CONSOLE_RECT__[2]:
|
while margin + Draw.GetStringWidth(copyCmd[0], __FONT_SIZES__[__FONT_SIZE__][0]) > __CONSOLE_RECT__[2]:
|
||||||
#print copyCmd
|
#print copyCmd
|
||||||
copyCmd[1] = '%s%s'% (copyCmd[0][-1], copyCmd[1]) # Add the char on the end
|
copyCmd[1] = '%s%s'% (copyCmd[0][-1], copyCmd[1]) # Add the char on the end
|
||||||
copyCmd[0] = copyCmd[0][:-1]# remove last chat
|
copyCmd[0] = copyCmd[0][:-1]# remove last chat
|
||||||
@@ -513,16 +732,15 @@ def draw_gui():
|
|||||||
# Now we have a list of lines, draw them (OpenGLs reverse ordering requires this odd change)
|
# Now we have a list of lines, draw them (OpenGLs reverse ordering requires this odd change)
|
||||||
wrapLineList.reverse()
|
wrapLineList.reverse()
|
||||||
for wline in wrapLineList:
|
for wline in wrapLineList:
|
||||||
BGL.glRasterPos2i(0, (__LINE_HEIGHT__*(consoleLineIdx + wrapLineIndex)) - 8)
|
BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1]*((consoleLineIdx-__CONSOLE_LINE_OFFSET__) + wrapLineIndex)) - 8)
|
||||||
Draw.Text(wline, __FONT_SIZE__)
|
Draw.Text(wline, __FONT_SIZES__[__FONT_SIZE__][0])
|
||||||
wrapLineIndex += 1
|
wrapLineIndex += 1
|
||||||
wrapLineIndex-=1 # otherwise we get a silly extra line.
|
wrapLineIndex-=1 # otherwise we get a silly extra line.
|
||||||
|
|
||||||
else: # no wrapping.
|
else: # no wrapping.
|
||||||
|
|
||||||
BGL.glRasterPos2i(0, (__LINE_HEIGHT__*(consoleLineIdx+wrapLineIndex)) - 8)
|
BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * ((consoleLineIdx-__CONSOLE_LINE_OFFSET__)+wrapLineIndex)) - 8)
|
||||||
Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZE__)
|
Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0])
|
||||||
|
|
||||||
|
|
||||||
consoleLineIdx += 1
|
consoleLineIdx += 1
|
||||||
|
|
||||||
@@ -536,42 +754,45 @@ def handle_button_event(evt):
|
|||||||
__CONSOLE_VAR_DICT__ = {} # Initialize var dict
|
__CONSOLE_VAR_DICT__ = {} # Initialize var dict
|
||||||
|
|
||||||
|
|
||||||
# Print Startup lines
|
# Print Startup lines, add __bpydoc__ to the console startup.
|
||||||
cmdBuffer = [cmdLine("Welcome to Ideasman's Blender Console", 1, None),\
|
cmdBuffer = []
|
||||||
cmdLine(' * Right Click: Console Menu (Save output, etc.)', 1, None),\
|
for l in __bpydoc__.split('<br>'):
|
||||||
cmdLine(' * Arrow Keys: Command history and cursor', 1, None),\
|
cmdBuffer.append( cmdLine(l, 1, None) )
|
||||||
cmdLine(' * Shift With Arrow Keys: Jump words', 1, None),\
|
|
||||||
cmdLine(' * Ctrl + Tab: Auto compleate based on variable names and modules loaded, multiple choices popup a menu', 1, None),\
|
|
||||||
cmdLine(' * Ctrl + Enter: Multiline functions, delays executing code until only Enter is pressed.', 1, None)]
|
|
||||||
|
|
||||||
histIndex = cursor = -1 # How far back from the first letter are we? - in current CMD line, history if for moving up and down lines.
|
histIndex = cursor = -1 # How far back from the first letter are we? - in current CMD line, history if for moving up and down lines.
|
||||||
|
|
||||||
# Autoexec, startup code.
|
# Autoexec, startup code.
|
||||||
console_autoexec = '%s%s' % (Get('datadir'), '/console_autoexec.py')
|
scriptDir = Get('scriptsdir')
|
||||||
|
if not scriptDir.endswith(Blender.sys.sep):
|
||||||
|
scriptDir += Blender.sys.sep
|
||||||
|
|
||||||
|
console_autoexec = '%s%s' % (scriptDir, 'console_autoexec.py')
|
||||||
|
|
||||||
if not sys.exists(console_autoexec):
|
if not sys.exists(console_autoexec):
|
||||||
# touch the file
|
# touch the file
|
||||||
|
cmdBuffer.append(cmdLine('...console_autoexec.py not found, making new in scripts dir', 1, None))
|
||||||
open(console_autoexec, 'w').close()
|
open(console_autoexec, 'w').close()
|
||||||
cmdBuffer.append(cmdLine('...console_autoexec.py not found, making new in scripts data dir', 1, None))
|
|
||||||
else:
|
else:
|
||||||
cmdBuffer.append(cmdLine('...Using existing console_autoexec.py in scripts data dir', 1, None))
|
cmdBuffer.append(cmdLine('...Using existing console_autoexec.py in scripts dir', 1, None))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#-Autoexec---------------------------------------------------------------------#
|
#-Autoexec---------------------------------------------------------------------#
|
||||||
# Just use the function to jump into local naming mode.
|
# Just use the function to jump into local naming mode.
|
||||||
# This is so we can loop through all of the autoexec functions / vars and add them to the __CONSOLE_VAR_DICT__
|
# This is so we can loop through all of the autoexec functions / vars and add them to the __CONSOLE_VAR_DICT__
|
||||||
def autoexecToVarList():
|
def include_console(includeFile):
|
||||||
global __CONSOLE_VAR_DICT__ # write autoexec vars to this.
|
global __CONSOLE_VAR_DICT__ # write autoexec vars to this.
|
||||||
|
|
||||||
# Execute an external py file as if local
|
# Execute an external py file as if local
|
||||||
exec(include(console_autoexec))
|
exec(include(includeFile))
|
||||||
|
|
||||||
# Write local to global __CONSOLE_VAR_DICT__ for reuse,
|
# Write local to global __CONSOLE_VAR_DICT__ for reuse,
|
||||||
for __TMP_VAR_NAME__ in dir() + dir(Blender):
|
for __TMP_VAR_NAME__ in dir() + dir(Blender):
|
||||||
# Execute the local > global coversion.
|
# Execute the local > global coversion.
|
||||||
exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__))
|
exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__))
|
||||||
|
|
||||||
autoexecToVarList() # pass the blender module
|
include_console(console_autoexec) # pass the blender module
|
||||||
#-end autoexec-----------------------------------------------------------------#
|
#-end autoexec-----------------------------------------------------------------#
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
""" Registration info for Blender menus: <- these words are ignored
|
""" Registration info for Blender menus: <- these words are ignored
|
||||||
Name: 'Dispaint'
|
Name: 'Dispaint'
|
||||||
Blender: 233
|
Blender: 237
|
||||||
Group: 'Mesh'
|
Group: 'Mesh'
|
||||||
Tip: 'use vertex paint color value to modify shape displacing vertices along normal'
|
Tip: 'use vertex paint color value to modify shape displacing vertices along normal'
|
||||||
"""
|
"""
|
||||||
@@ -11,7 +11,7 @@ __author__ = "Jean-Michel Soler (jms)"
|
|||||||
__url__ = ("blender", "elysiun",
|
__url__ = ("blender", "elysiun",
|
||||||
"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_displacementpainting.htm",
|
"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_displacementpainting.htm",
|
||||||
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
|
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
|
||||||
__version__ = "233i"
|
__version__ = "237"
|
||||||
|
|
||||||
__bpydoc__ = """\
|
__bpydoc__ = """\
|
||||||
This script displaces mesh vertices according to vertex color values.
|
This script displaces mesh vertices according to vertex color values.
|
||||||
@@ -81,6 +81,7 @@ from Blender.Draw import *
|
|||||||
from Blender.BGL import *
|
from Blender.BGL import *
|
||||||
from Blender.Noise import *
|
from Blender.Noise import *
|
||||||
from Blender.Scene import *
|
from Blender.Scene import *
|
||||||
|
from Blender.Window import *
|
||||||
sc=Scene.getCurrent()
|
sc=Scene.getCurrent()
|
||||||
|
|
||||||
# niveau du deplacement
|
# niveau du deplacement
|
||||||
@@ -117,6 +118,7 @@ E_AXESELX = 46
|
|||||||
E_AXESELY = 47
|
E_AXESELY = 47
|
||||||
E_AXESELZ = 48
|
E_AXESELZ = 48
|
||||||
|
|
||||||
|
|
||||||
E_NOISEME = 49
|
E_NOISEME = 49
|
||||||
E_NOISEH = 50
|
E_NOISEH = 50
|
||||||
E_NOISELAC = 51
|
E_NOISELAC = 51
|
||||||
@@ -126,10 +128,28 @@ E_NOISEBAS = 54
|
|||||||
E_NOISEVAL=[E_NOISEH,E_NOISELAC,E_NOISEOCT,E_NOISEOFF,E_NOISEBAS]
|
E_NOISEVAL=[E_NOISEH,E_NOISELAC,E_NOISEOCT,E_NOISEOFF,E_NOISEBAS]
|
||||||
E_NOISEDIM = 55
|
E_NOISEDIM = 55
|
||||||
|
|
||||||
|
E_GETCOLORS = 56
|
||||||
|
E_UVCOLORS = 57
|
||||||
|
E_SAVECOLORS = 58
|
||||||
|
B_SAVECOLORS = 0
|
||||||
|
|
||||||
|
E_RESTCOLORS = 60
|
||||||
|
V_RESTCOL=0
|
||||||
|
F_RESTCOL=0
|
||||||
|
|
||||||
|
BUF_COLORS=[]
|
||||||
|
|
||||||
|
RVBA_VALUE=61
|
||||||
|
RVBA_VERTICES=62
|
||||||
|
RVBA_FACES=63
|
||||||
|
|
||||||
ExitTIP="Exit from this script session "
|
ExitTIP="Exit from this script session "
|
||||||
CreateTIP="Create a new copy of the selected shape"
|
CreateTIP="Create a new copy of the selected shape"
|
||||||
ActionTIP="Do the current selected actions"
|
ActionTIP="Do the current selected actions"
|
||||||
|
|
||||||
|
UVCOLORSTIP="Get colrs from first available UV image "
|
||||||
|
GETCOLORSTIP="Get color from textures "
|
||||||
|
REPEATTIP="Replay the same action with new values ."
|
||||||
|
|
||||||
def copy_transform(ozero,Obis):
|
def copy_transform(ozero,Obis):
|
||||||
Obis.setSize(ozero.getSize());
|
Obis.setSize(ozero.getSize());
|
||||||
@@ -298,9 +318,23 @@ def DOCMat_list(TMATList):
|
|||||||
TMATList[0]=0
|
TMATList[0]=0
|
||||||
return TMATList
|
return TMATList
|
||||||
|
|
||||||
MOname = "MODE MENU %t|Normal %x1|Material %x2|Selected %x3"
|
MOname = "MODE MENU %t|Normal %x1|Material %x2|Selected %x3| Find color %x4"
|
||||||
|
MOname_doc=["",
|
||||||
|
"Displace all vertices",
|
||||||
|
"Displace vertices only on selected materials . ",
|
||||||
|
"Displace only selected vertices .",
|
||||||
|
"Try to find and set selected the vertices with this color."]
|
||||||
|
|
||||||
ORname = "ORIENT MENU %t|From Normal %x1|Local Axes %x2| Noise %x3"
|
ORname = "ORIENT MENU %t|From Normal %x1|Local Axes %x2| Noise %x3"
|
||||||
NOname = "NOISE MENU %t|BLENDER %x1|STDPERLIN %x2|NEWPERLIN %x3|VORONOI_F1%x4|VORONOI_F2%x5|VORONOI_F3%x6|VORONOI_F4%x7|VORONOI_F2F1%x8|VORONOI_CRACKLE%x9|CELLNOISE%x10|HETEROTENOISE%x11"
|
ORname_doc=["",
|
||||||
|
"Use normal orientation to calculate displacement",
|
||||||
|
"Use selected axes value to calculate displacement",
|
||||||
|
"Blend the color value with Nosie values to calculate the displacement"]
|
||||||
|
|
||||||
|
NOname = "NOISE MENU %t|BLENDER %x1|STDPERLIN %x2|\
|
||||||
|
NEWPERLIN %x3|VORONOI_F1%x4|VORONOI_F2%x5|\
|
||||||
|
VORONOI_F3%x6|VORONOI_F4%x7|VORONOI_F2F1%x8|\
|
||||||
|
VORONOI_CRACKLE%x9|CELLNOISE%x10|HETEROTENOISE%x11"
|
||||||
|
|
||||||
MODEMenu = Create(1)
|
MODEMenu = Create(1)
|
||||||
ORIENTMenu = Create(1)
|
ORIENTMenu = Create(1)
|
||||||
@@ -351,14 +385,128 @@ glCl3=glColor3f
|
|||||||
glCl4=glColor4f
|
glCl4=glColor4f
|
||||||
glRct=glRectf
|
glRct=glRectf
|
||||||
|
|
||||||
|
def triangle(a,b,c):
|
||||||
|
glBegin(GL_TRIANGLES);
|
||||||
|
glColor3f(a[2],a[3],a[4])
|
||||||
|
glVertex2f(a[0],a[1]);
|
||||||
|
glVertex2f(b[0],b[1]);
|
||||||
|
glVertex2f(c[0],c[1]);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
def triangleFcolor(a,b,c):
|
||||||
|
glBegin(GL_TRIANGLES);
|
||||||
|
glColor4f(a[2],a[3],a[4],a[5])
|
||||||
|
glVertex2f(a[0],a[1]);
|
||||||
|
glColor4f(b[2],b[3],b[4],a[5])
|
||||||
|
glVertex2f(b[0],b[1]);
|
||||||
|
glColor4f(c[2],c[3],c[4],a[5])
|
||||||
|
glVertex2f(c[0],c[1]);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
def Ltriangle(a,b,c,LC=0.5):
|
||||||
|
TL=[a,b,c,a]
|
||||||
|
for v in [0,1,2] :
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glColor3f(LC,LC,LC)
|
||||||
|
glVertex2f(TL[v][0],TL[v][1]);
|
||||||
|
glVertex2f(TL[v+1][0],TL[v+1][1]);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
|
||||||
|
def carreFcolor(a,b,c,d):
|
||||||
|
triangleFcolor(a,b,c)
|
||||||
|
triangleFcolor(a,c,d)
|
||||||
|
|
||||||
|
RVBA=[Create(255),Create(255),Create(255),Create(255),Create(0)]
|
||||||
|
|
||||||
|
# _*_ p1
|
||||||
|
# _/ \_
|
||||||
|
# _/ \_
|
||||||
|
# / \_
|
||||||
|
# p0*_ /* p2
|
||||||
|
# | \_ _/ |
|
||||||
|
# | \_ _/ |
|
||||||
|
# | \_ _/ |
|
||||||
|
# | * p3 |
|
||||||
|
# | | |
|
||||||
|
# *_ | /* p4
|
||||||
|
# p6 \_ | _/
|
||||||
|
# \_ | _/
|
||||||
|
# \_|_/
|
||||||
|
# * p5
|
||||||
|
|
||||||
|
def flatcolorcube(r,g,b,a,m,x,y):
|
||||||
|
h0=60
|
||||||
|
v0=40
|
||||||
|
A=[x, y, (r-m)/255.0,g/255.0,b/255.0,a/255.0] #p0
|
||||||
|
B=[x+h0,y-v0, r/255.0,g/255.0,b/255.0,a/255.0] #p3
|
||||||
|
c=[x+h0*2,y, r/255.0, g/255.0, (b-m)/255.0,a/255.0] #p2
|
||||||
|
d=[x+h0,y+v0, (r-m)/255.0,g/255.0,(b-m)/255.0,a/255.0] #p1
|
||||||
|
carreFcolor(A,B,c,d)
|
||||||
|
|
||||||
|
|
||||||
|
A=[x,y,(r-m)/255.0,g/255.0,b/255.0,a/255.0] #p0
|
||||||
|
B=[x+h0,y-v0,r/255.0,g/255.0,b/255.0,a/255.0] #p3
|
||||||
|
c=[x+h0,y-v0*2.5, r/255.0, (g-m)/255.0, b/255.0,a/255.0] #p5
|
||||||
|
d=[x,y-v0*1.5,(r-m)/255.0,(g-m)/255.0,b/255.0,a/255.0] #p6
|
||||||
|
carreFcolor(A,B,c,d)
|
||||||
|
|
||||||
|
d=[x+h0,y-v0,r/255.0,g/255.0,b/255.0,a/255.0] #p3
|
||||||
|
A=[x+h0*2,y,r/255.0,g/255.0,(b-m)/255.0,a/255.0] #p2
|
||||||
|
B=[x+h0*2,y-v0*1.5, r/255.0, (g-m)/255.0,(b-m)/255.0,a/255.0] #p4
|
||||||
|
c=[x+h0,y-v0*2.5,r/255.0,(g-m)/255.0,b/255.0,a/255.0] #p5
|
||||||
|
carreFcolor(A,B,c,d)
|
||||||
|
|
||||||
|
def col_egal2col(col,RVBA):
|
||||||
|
eps=RVBA[4].val
|
||||||
|
if ( (RVBA[0].val-col[0]>=0 and RVBA[0].val-col[0]<=eps) and
|
||||||
|
(RVBA[1].val-col[1]>=0 and RVBA[1].val-col[1]<=eps) and
|
||||||
|
(RVBA[2].val-col[2]>=0 and RVBA[2].val-col[2]<=eps) and
|
||||||
|
(RVBA[3].val-col[3]>=0 and RVBA[3].val-col[3]<=eps) ) :
|
||||||
|
#print 'ok',col, [RVBA[n].val-col[n] for n in 0,1,2,3]
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
#print 'not',col, [RVBA[n].val-col[n] for n in 0,1,2,3]
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def select_bycolors(TYPE,RVBA):
|
||||||
|
global RVBA_VERTICES, RVBA_FACES
|
||||||
|
SEL = Blender.NMesh.FaceFlags['SELECT']
|
||||||
|
try:
|
||||||
|
ME=Blender.Scene.getCurrent().getActiveObject().getData()
|
||||||
|
VC={}
|
||||||
|
for f in ME.faces:
|
||||||
|
for v in f.v:
|
||||||
|
try:
|
||||||
|
VC[v].append(f)
|
||||||
|
except:
|
||||||
|
VC[v]=[f]
|
||||||
|
#print '.',
|
||||||
|
for C in VC.iteritems():
|
||||||
|
color=[0,0,0]
|
||||||
|
for f in C[1]:
|
||||||
|
col=f.col[f.v.index(C[0])]
|
||||||
|
col=[col.r,col.g,col.b,col.a]
|
||||||
|
if col_egal2col(col,RVBA):
|
||||||
|
if TYPE== RVBA_VERTICES:
|
||||||
|
C[0].sel=1
|
||||||
|
else:
|
||||||
|
f.sel=1
|
||||||
|
f.flag |= SEL
|
||||||
|
#VC[C[0]].append(color[:])
|
||||||
|
ME.update()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
def draw():
|
def draw():
|
||||||
global MODEMenu, NSIZE, TDOCMat,TMATList, TAXEList
|
global MODEMenu, NSIZE, TDOCMat,TMATList, TAXEList
|
||||||
global mat, ORIName, NEWName, ORIENTMenu
|
global mat, ORIName, NEWName, ORIENTMenu
|
||||||
global NRepeat, ERROR, TextERROR , NOISE, NOISEMenu, NOISEDIMbout,NOISEDIM
|
global NRepeat, ERROR, TextERROR , NOISE, NOISEMenu
|
||||||
|
global NOISEDIMbout,NOISEDIM, RVBA,RVB_VALUE, RVBA_VERTICES
|
||||||
global HBout,lacunarityBout,octavesBout,offsetBout,basisBout
|
global HBout,lacunarityBout,octavesBout,offsetBout,basisBout
|
||||||
global noiseTYPE, ExitTIP, CreateTIP, ActionTIP
|
global noiseTYPE, ExitTIP, CreateTIP, ActionTIP, E_GETCOLORS
|
||||||
|
global E_UVCOLORS, UVCOLORSTIP, GETCOLORSTIP, REPEATTIP,RVBA_FACES
|
||||||
|
global E_SAVECOLORS, B_SAVECOLORS, E_RESTCOLORS, MOname_doc, ORname_doc
|
||||||
|
|
||||||
size=Buffer(GL_FLOAT, 4)
|
size=Buffer(GL_FLOAT, 4)
|
||||||
glGetFloatv(GL_SCISSOR_BOX, size)
|
glGetFloatv(GL_SCISSOR_BOX, size)
|
||||||
@@ -366,33 +514,61 @@ def draw():
|
|||||||
|
|
||||||
for s in [0,1,2,3]: size[s]=int(size[s])
|
for s in [0,1,2,3]: size[s]=int(size[s])
|
||||||
|
|
||||||
|
glClearColor(0.72,0.72,0.72,1.0)
|
||||||
glClear(GL_COLOR_BUFFER_BIT)
|
glClear(GL_COLOR_BUFFER_BIT)
|
||||||
|
|
||||||
glColor3f(0.0,0.0,0.0)
|
glColor3f(0.66,0.66,0.66)
|
||||||
glRectf(4,size[3],534,size[3]-32 )
|
glRectf(4,size[3]-4,404,size[3]-32 )
|
||||||
|
|
||||||
|
glColor3f(0.76,0.76,0.76)
|
||||||
|
glRectf(4,size[3]-32,404,size[3]-294 )
|
||||||
|
|
||||||
|
triangle([4+9,size[3],0.72,0.72,0.72],
|
||||||
|
[4,size[3],],
|
||||||
|
[4,size[3]-9])
|
||||||
|
|
||||||
|
triangle([404-9,size[3],0.72,0.72,0.72],
|
||||||
|
[404,size[3],],
|
||||||
|
[404,size[3]-9])
|
||||||
|
|
||||||
|
triangle([404,size[3]-294,.72,0.72,0.72],
|
||||||
|
[404,size[3]-294+9,],
|
||||||
|
[404-9,size[3]-294])
|
||||||
|
|
||||||
|
triangle([4,size[3]-294,.72,0.72,0.72],
|
||||||
|
[4,size[3]-294+9,],
|
||||||
|
[4+9,size[3]-294])
|
||||||
|
|
||||||
glColor3f(1.0,1.0,1.0)
|
glColor3f(1.0,1.0,1.0)
|
||||||
glRasterPos2f(20, size[3]-15)
|
glRasterPos2f(20, size[3]-15)
|
||||||
Text("Script Python de displacement paintingt")
|
Text("Script Python de displacement painting")
|
||||||
|
|
||||||
glRasterPos2f(20, size[3]-28)
|
glRasterPos2f(20, size[3]-28)
|
||||||
Text("Jean-michel Soler, juillet 2004")
|
Text("Jean-michel Soler, Aout 2005")
|
||||||
|
|
||||||
|
|
||||||
n0=70
|
n0=70
|
||||||
n1=55
|
n1=55
|
||||||
|
if MODEMenu.val<4 :
|
||||||
|
Button("Create" ,E_CREATE ,5 ,size[3]-n0+11 ,60 ,20,CreateTIP)
|
||||||
|
Button("Action" ,E_ACTION ,5 ,size[3]-n0-11 ,60 ,20,ActionTIP)
|
||||||
|
NRepeat=Number("repeat" ,E_REPEAT ,5 ,size[3]-n0-56 ,75 ,20, NRepeat.val,1,10,REPEATTIP)
|
||||||
|
|
||||||
|
Button("Exit" ,E_EXIT ,5 ,size[3]-n0-32 ,60 ,20,ExitTIP)
|
||||||
|
Button("Tex colors" ,E_GETCOLORS ,5 ,size[3]-n0-80 ,75 ,20,GETCOLORSTIP)
|
||||||
|
Button("UV colors" ,E_UVCOLORS ,5 ,size[3]-n0-102 ,75 ,20,UVCOLORSTIP)
|
||||||
|
if B_SAVECOLORS :
|
||||||
|
Button("Rest colors" ,E_RESTCOLORS ,5 ,size[3]-n0-146 ,75 ,20,UVCOLORSTIP)
|
||||||
|
else:
|
||||||
|
Button("Save colors" ,E_SAVECOLORS ,5 ,size[3]-n0-124 ,75 ,20,GETCOLORSTIP)
|
||||||
|
|
||||||
Button("Create" ,E_CREATE ,5 ,size[3]-n0+16 ,60 ,20,CreateTIP)
|
|
||||||
Button("Action" ,E_ACTION ,5 ,size[3]-n0-4 ,60 ,20,ActionTIP)
|
|
||||||
Button("Exit" ,E_EXIT ,5 ,size[3]-n0-24 ,60 ,20,ExitTIP)
|
|
||||||
|
|
||||||
NRepeat=Number("repeat" ,E_REPEAT ,5 ,size[3]-n0-50 ,75 ,20, NRepeat.val,1,10)
|
|
||||||
|
|
||||||
glColor3f(0.0,0.0,0.0)
|
glColor3f(0.0,0.0,0.0)
|
||||||
glRasterPos2f(80 ,size[3]-n0+24)
|
glRasterPos2f(80 ,size[3]-n0+24)
|
||||||
Text("MODE")
|
Text("MODE")
|
||||||
|
|
||||||
MODEMenu= Menu(MOname, E_MODE ,80 ,size[3]-n0 ,100,20, MODEMenu.val, "MODE menu.")
|
MODEMenu= Menu(MOname, E_MODE ,80 ,size[3]-n0 ,100,20, MODEMenu.val, MOname_doc[MODEMenu.val])
|
||||||
|
|
||||||
if MODEMenu.val==2:
|
if MODEMenu.val==2:
|
||||||
TDOCMat=Toggle("Doc Mat" ,E_DOCMAT ,180 ,size[3]-n0 ,60 ,20,TDOCMat.val)
|
TDOCMat=Toggle("Doc Mat" ,E_DOCMAT ,180 ,size[3]-n0 ,60 ,20,TDOCMat.val)
|
||||||
@@ -402,14 +578,22 @@ def draw():
|
|||||||
glCl3(TMATList[1][t][0],
|
glCl3(TMATList[1][t][0],
|
||||||
TMATList[1][t][1],
|
TMATList[1][t][1],
|
||||||
TMATList[1][t][2])
|
TMATList[1][t][2])
|
||||||
|
|
||||||
|
if t<=7:
|
||||||
glRct(80+t*40,
|
glRct(80+t*40,
|
||||||
size[3]-n0-60,
|
size[3]-n0-60,
|
||||||
80+t*40+40,
|
80+t*40+40,
|
||||||
size[3]-n0-60+40)
|
size[3]-n0-60+40)
|
||||||
TMATList[2][t]=Toggle("%s"%t , 32+t ,80+t*40+5 ,size[3]-n0-50 ,30 , 20,TMATList[2][t].val)
|
TMATList[2][t]=Toggle("%s"%(t+1) , 32+t ,80+t*40+5 ,size[3]-n0-50 ,30 , 20,TMATList[2][t].val)
|
||||||
|
else:
|
||||||
|
glRct(80+(t-8)*40,
|
||||||
|
size[3]-n0-50-50,
|
||||||
|
80+(t-8)*40+40,
|
||||||
|
size[3]-n0-60)
|
||||||
|
TMATList[2][t]=Toggle("%s"%(t+1) , 32+t ,80+(t-8)*40+5 ,size[3]-n0-45*2 ,30 , 20,TMATList[2][t].val)
|
||||||
|
|
||||||
glColor3f(1.0,0.3,0.0)
|
glColor3f(1.0,0.3,0.0)
|
||||||
glRasterPos2f(80+40+5 ,size[3]-n0-80)
|
glRasterPos2f(80+40+5 ,size[3]-n0-110)
|
||||||
if ERROR>1:
|
if ERROR>1:
|
||||||
Text('Last error : '+TextERROR)
|
Text('Last error : '+TextERROR)
|
||||||
else:
|
else:
|
||||||
@@ -417,35 +601,66 @@ def draw():
|
|||||||
|
|
||||||
glColor3f(0.0,0.0,0.0)
|
glColor3f(0.0,0.0,0.0)
|
||||||
glRasterPos2f(240 ,size[3]-n0+24)
|
glRasterPos2f(240 ,size[3]-n0+24)
|
||||||
Text("ORIENTATION")
|
|
||||||
ORIENTMenu= Menu(ORname, E_ORIENT ,240 ,size[3]-n0 ,100,20, ORIENTMenu.val, "ORIENT menu.")
|
|
||||||
|
|
||||||
|
if MODEMenu.val<4:
|
||||||
|
Text("ORIENTATION")
|
||||||
|
ORIENTMenu= Menu(ORname, E_ORIENT ,240 ,size[3]-n0 ,100,20, ORIENTMenu.val, ORname_doc[ORIENTMenu.val])
|
||||||
if ORIENTMenu.val==2 :
|
if ORIENTMenu.val==2 :
|
||||||
for t in range(3):
|
for t in [0,1]:
|
||||||
TAXEList[1][t]=Toggle("%s"%TAXEList[0][t],
|
TAXEList[1][t]=Toggle("%s"%TAXEList[0][t],
|
||||||
E_AXESEL+t,
|
E_AXESEL+t,
|
||||||
240+100+t*30 , size[3]-n0 ,30 , 20,
|
240+100+t*30+2 , size[3]-n0+10 ,28 , 18,
|
||||||
TAXEList[1][t].val)
|
TAXEList[1][t].val)
|
||||||
|
TAXEList[1][2]=Toggle("%s"%TAXEList[0][2],
|
||||||
|
E_AXESEL+2,
|
||||||
|
int(240+100+.5*30+2) , size[3]-n0-10 ,28 , 18,
|
||||||
|
TAXEList[1][2].val)
|
||||||
if ORIENTMenu.val==3 :
|
if ORIENTMenu.val==3 :
|
||||||
glRasterPos2f(240 ,size[3]-n0-90-4)
|
glRasterPos2f(240 ,size[3]-n0-120-4)
|
||||||
Text("NOISE")
|
Text("NOISE")
|
||||||
NOISEMenu= Menu(NOname, E_NOISEME , 240 ,size[3]-n0-118 ,110,20, NOISEMenu.val, "NOISE menu.")
|
NOISEMenu= Menu(NOname, E_NOISEME , 240 ,size[3]-n0-148 ,110,20, NOISEMenu.val, "NOISE menu.")
|
||||||
NOISEDIMbout=Number(" Dim: " ,E_NOISEDIM , 240 ,size[3]-n0-138 ,110,20, NOISEDIMbout.val, 1,100)
|
NOISEDIMbout=Number(" Dim: " ,E_NOISEDIM , 240 ,size[3]-n0-172 ,110,20, NOISEDIMbout.val, 1,100)
|
||||||
|
|
||||||
if NOISEMenu.val==11:
|
if NOISEMenu.val==11:
|
||||||
basisBout=Slider(noiseTYPE[basisBout.val],
|
basisBout=Slider(noiseTYPE[basisBout.val],
|
||||||
E_NOISEBAS ,40 ,size[3]-n0-118 ,175,20, basisBout.val, 0,9,)
|
E_NOISEBAS ,40 ,size[3]-n0-178 ,175,20, basisBout.val, 0,9,)
|
||||||
HBout= Slider("H", E_NOISEH ,40 ,size[3]-n0-138 ,175,20, HBout.val, -2.0,+2.0,0,)
|
HBout= Slider("H", E_NOISEH ,40 ,size[3]-n0-198 ,175,20, HBout.val, -2.0,+2.0,0,)
|
||||||
lacunarityBout=Slider("lacunarity", E_NOISELAC ,40 ,size[3]-n0-158 ,175,20, lacunarityBout.val, -4.0,+4.0,0,)
|
lacunarityBout=Slider("lacunarity", E_NOISELAC ,40 ,size[3]-n0-218 ,175,20, lacunarityBout.val, -4.0,+4.0,0,)
|
||||||
octavesBout=Slider("octave", E_NOISEOCT ,40 ,size[3]-n0-178 ,175,20, octavesBout.val, -10.0,+10.0,0,)
|
octavesBout=Slider("octave", E_NOISEOCT ,219 ,size[3]-n0-198 ,175,20, octavesBout.val, -10.0,+10.0,0,)
|
||||||
offsetBout=Slider("offset", E_NOISEOFF ,40 ,size[3]-n0-198 ,175,20, offsetBout.val, -5.0,+5.0,0,)
|
offsetBout=Slider("offset", E_NOISEOFF ,219 ,size[3]-n0-218 ,175,20, offsetBout.val, -5.0,+5.0,0,)
|
||||||
|
|
||||||
NSIZE= Slider("Disp Size", E_NSIZE ,80 ,size[3]-n0-20 ,260,20, NSIZE.val, -4.0,+4.0,0,"SIZE.")
|
NSIZE= Slider("Disp Size", E_NSIZE ,80 ,size[3]-n0-20 ,260,20, NSIZE.val, -4.0,+4.0,0,"SIZE.")
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
# degrades de couleurs
|
||||||
|
glShadeModel(GL_SMOOTH)
|
||||||
|
#transparence
|
||||||
|
glEnable(GL_BLEND)
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
||||||
|
|
||||||
|
RVBA[0]=Slider("Red :", RVBA_VALUE , 105 ,size[3]-n0-25 ,280,20, RVBA[0].val, 0,255,0,"")
|
||||||
|
RVBA[1]=Slider("Green :", RVBA_VALUE , 105 ,size[3]-n0-47 ,280,20, RVBA[1].val, 0,255,0,"")
|
||||||
|
RVBA[2]=Slider("Blue :", RVBA_VALUE , 105 ,size[3]-n0-69 ,280,20, RVBA[2].val, 0,255,0,"")
|
||||||
|
RVBA[3]=Slider("Alpha :", RVBA_VALUE , 105 ,size[3]-n0-91 ,150,20, RVBA[3].val, 0,255,0,"")
|
||||||
|
RVBA[4]=Slider("margin :", RVBA_VALUE , 105 ,size[3]-n0-113 ,150,20, RVBA[4].val, 0,255,0,"")
|
||||||
|
flatcolorcube(RVBA[0].val,
|
||||||
|
RVBA[1].val,
|
||||||
|
RVBA[2].val,
|
||||||
|
RVBA[3].val,
|
||||||
|
RVBA[4].val,
|
||||||
|
270,size[3]-n0-120)
|
||||||
|
|
||||||
|
Button("Vertex" ,RVBA_VERTICES ,5 ,size[3]-n0-148 ,75 ,20,CreateTIP)
|
||||||
|
Button("Faces" ,RVBA_FACES ,5 ,size[3]-n0-169 ,75 ,20,ActionTIP)
|
||||||
|
|
||||||
|
|
||||||
|
def on_MESH():
|
||||||
|
Me=Object.GetSelected()
|
||||||
|
if Me!=[] and Me[0].getType()=='Mesh':
|
||||||
|
editmode = Window.EditMode()
|
||||||
|
if editmode: Window.EditMode(0)
|
||||||
|
return 1,Me[0].getData()
|
||||||
|
else:
|
||||||
|
return 0, None
|
||||||
|
|
||||||
def event(evt, val):
|
def event(evt, val):
|
||||||
if (evt== QKEY and not val): Exit()
|
if (evt== QKEY and not val): Exit()
|
||||||
@@ -455,21 +670,20 @@ def bevent(evt):
|
|||||||
global mat, ORIENTMenu, NRepeat, TAXEList
|
global mat, ORIENTMenu, NRepeat, TAXEList
|
||||||
global ERROR,TextERROR, NOISE, NOISEMenu, NOISEDIMbout,NOISEDIM
|
global ERROR,TextERROR, NOISE, NOISEMenu, NOISEDIMbout,NOISEDIM
|
||||||
global HBout,lacunarityBout,octavesBout,offsetBout,basisBout
|
global HBout,lacunarityBout,octavesBout,offsetBout,basisBout
|
||||||
global H,lacunarity,octaves,offset,basis
|
global H,lacunarity,octaves,offset,basis, E_RESTCOLORS, RVBA_VERTICES
|
||||||
|
global E_GETCOLORS, E_UVCOLORS, E_SAVECOLORS, B_SAVECOLORS
|
||||||
|
global V_RESTCOLORS, F_RESTCOLORS, BUF_COLORS, RVBA, RVBA_FACES
|
||||||
|
|
||||||
if (evt== E_EXIT):
|
if (evt== E_EXIT):
|
||||||
Exit()
|
Exit()
|
||||||
|
|
||||||
|
|
||||||
elif (evt== E_ACTION):
|
elif (evt== E_ACTION):
|
||||||
for n in range(NRepeat.val):
|
for n in range(NRepeat.val):
|
||||||
paint()
|
paint()
|
||||||
|
|
||||||
elif (evt== E_NSIZE):
|
elif (evt== E_NSIZE):
|
||||||
ng=NSIZE.val
|
ng=NSIZE.val
|
||||||
|
|
||||||
elif (evt== E_DOCMAT) or (evt in E_MATVAL):
|
elif (evt== E_DOCMAT) or (evt in E_MATVAL):
|
||||||
Me=Object.GetSelected()
|
Me=Object.GetSelected()
|
||||||
|
|
||||||
if Me!=[]:
|
if Me!=[]:
|
||||||
if Me[0].getType()=='Mesh':
|
if Me[0].getType()=='Mesh':
|
||||||
TMATList=DOCMat_list(TMATList)
|
TMATList=DOCMat_list(TMATList)
|
||||||
@@ -484,29 +698,68 @@ def bevent(evt):
|
|||||||
else:
|
else:
|
||||||
ERROR=1
|
ERROR=1
|
||||||
TextERROR='No Selected Object.'
|
TextERROR='No Selected Object.'
|
||||||
|
|
||||||
|
|
||||||
elif (evt== E_CREATE):
|
elif (evt== E_CREATE):
|
||||||
|
|
||||||
NEWMEcreation(Blender.Object.GetSelected()[0])
|
NEWMEcreation(Blender.Object.GetSelected()[0])
|
||||||
Blender.Draw.Redraw()
|
Blender.Draw.Redraw()
|
||||||
|
|
||||||
ERROR=1
|
ERROR=1
|
||||||
TextERROR='No Selected Object.'
|
TextERROR='No Selected Object.'
|
||||||
|
|
||||||
elif (evt== E_NOISEME):
|
elif (evt== E_NOISEME):
|
||||||
NOISE=NOISEMenu.val-1
|
NOISE=NOISEMenu.val-1
|
||||||
|
|
||||||
elif (evt in E_NOISEVAL):
|
elif (evt in E_NOISEVAL):
|
||||||
H=HBout.val
|
H=HBout.val
|
||||||
lacunarity=lacunarityBout.val
|
lacunarity=lacunarityBout.val
|
||||||
octaves=octavesBout.val
|
octaves=octavesBout.val
|
||||||
offset=offsetBout.val
|
offset=offsetBout.val
|
||||||
basis=basisBout.val
|
basis=basisBout.val
|
||||||
|
|
||||||
elif (evt== E_NOISEDIM):
|
elif (evt== E_NOISEDIM):
|
||||||
NOISEDIM=NOISEDIMbout.val
|
NOISEDIM=NOISEDIMbout.val
|
||||||
|
elif (evt == E_GETCOLORS):
|
||||||
|
OK,MESH=on_MESH()
|
||||||
|
if OK: MESH.update(1,0,1)
|
||||||
|
elif (evt == E_UVCOLORS):
|
||||||
|
OK,MESH=on_MESH()
|
||||||
|
if OK and MESH.hasFaceUV():
|
||||||
|
for f in MESH.faces:
|
||||||
|
if f.image:
|
||||||
|
im=Blender.Image.Get(f.image.name)
|
||||||
|
break
|
||||||
|
imX,imY = im.getMaxXY()
|
||||||
|
for f in MESH.faces:
|
||||||
|
for uv in f.uv:
|
||||||
|
color=[int(c*255.0) for c in im.getPixelF(abs(uv[0]*imX%imX), abs(uv[1]*imY%imY))]
|
||||||
|
f.col[f.uv.index(uv)].r=color[0]
|
||||||
|
f.col[f.uv.index(uv)].g=color[1]
|
||||||
|
f.col[f.uv.index(uv)].b=color[2]
|
||||||
|
f.col[f.uv.index(uv)].a=color[3]
|
||||||
|
MESH.update()
|
||||||
|
elif (evt == E_SAVECOLORS):
|
||||||
|
OK,MESH=on_MESH()
|
||||||
|
print OK, MESH
|
||||||
|
if OK and (MESH.hasFaceUV() or MESH.hasVertexColours()):
|
||||||
|
F_RESTCOLORS=1
|
||||||
|
for f in MESH.faces:
|
||||||
|
b=[MESH.faces.index(f)]
|
||||||
|
for c in f.col:
|
||||||
|
b.append([c.r,c.g,c.b,c.a])
|
||||||
|
BUF_COLORS.append(b)
|
||||||
|
B_SAVECOLORS = 1
|
||||||
|
else:
|
||||||
|
B_SAVECOLORS = 0
|
||||||
|
elif (evt == E_RESTCOLORS):
|
||||||
|
OK,MESH=on_MESH()
|
||||||
|
print F_RESTCOLORS, len(BUF_COLORS),len(MESH.faces)
|
||||||
|
if OK and F_RESTCOLORS==1 and len(BUF_COLORS)==len(MESH.faces):
|
||||||
|
for b in BUF_COLORS:
|
||||||
|
ncol=0
|
||||||
|
for c in MESH.faces[b[0]].col :
|
||||||
|
print b[ncol+1]
|
||||||
|
c.r,c.g,c.b,c.a= b[ncol+1]
|
||||||
|
ncol+=1
|
||||||
|
F_RESTCOLORS=0
|
||||||
|
B_SAVECOLORS = 0
|
||||||
|
BUF_COLORS=[]
|
||||||
|
MESH.update()
|
||||||
|
elif (evt == RVBA_VERTICES or evt == RVBA_FACES):
|
||||||
|
select_bycolors(evt,RVBA)
|
||||||
Blender.Draw.Redraw()
|
Blender.Draw.Redraw()
|
||||||
|
|
||||||
Register(draw, event, bevent)
|
Register(draw, event, bevent)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
""" Registration info for Blender menus:
|
""" Registration info for Blender menus:
|
||||||
Name: 'HotKey and MouseAction Reference'
|
Name: 'HotKey and MouseAction Reference'
|
||||||
Blender: 232
|
Blender: 237
|
||||||
Group: 'Help'
|
Group: 'Help'
|
||||||
Tip: 'All the hotkeys/short keys'
|
Tip: 'All the hotkeys/short keys'
|
||||||
"""
|
"""
|
||||||
@@ -11,7 +11,7 @@ __author__ = "Jean-Michel Soler (jms)"
|
|||||||
__url__ = ("blender", "elysiun",
|
__url__ = ("blender", "elysiun",
|
||||||
"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm",
|
"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm",
|
||||||
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
|
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
|
||||||
__version__ = "10/2004"
|
__version__ = "10/04/2005"
|
||||||
|
|
||||||
__bpydoc__ = """\
|
__bpydoc__ = """\
|
||||||
This script is a reference about all hotkeys and mouse actions in Blender.
|
This script is a reference about all hotkeys and mouse actions in Blender.
|
||||||
@@ -22,6 +22,8 @@ Open the script from the Help menu and select group of keys to browse.
|
|||||||
|
|
||||||
Notes:<br>
|
Notes:<br>
|
||||||
Additional entries in the database (c) 2004 by Bart.
|
Additional entries in the database (c) 2004 by Bart.
|
||||||
|
Additional entries in the database for blender 2.37 (c) 2005 by jms.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# $Id$
|
# $Id$
|
||||||
@@ -67,11 +69,12 @@ from Blender.Draw import *
|
|||||||
from Blender.BGL import *
|
from Blender.BGL import *
|
||||||
|
|
||||||
hotkeys={
|
hotkeys={
|
||||||
|
'Search ':[['', '']],
|
||||||
'Specials 1 ':[
|
'Specials 1 ':[
|
||||||
[',', 'Set Bounding Box rotation scaling pivot'],
|
[',', 'Set Bounding Box rotation scaling pivot'],
|
||||||
['Ctrl-,', 'Set Median Point rotation scaling pivot'],
|
['Ctrl-,', 'Set Median Point rotation scaling pivot'],
|
||||||
['.', 'Set 3D cursor as rotation scaling pivot'],
|
['.', 'Set 3D cursor as rotation scaling pivot'],
|
||||||
['Ctrl-.', 'Set Individual Object Centers as rotation scaling pivot'] ,
|
['Ctrl-.', 'Set Individual Object Centers as rotation scaling pivot'],
|
||||||
['~', 'Display all layers (German keys: <20>)'],
|
['~', 'Display all layers (German keys: <20>)'],
|
||||||
['Shift-~', 'Display all/previous layers (German keys: Shift-<2D>)'],
|
['Shift-~', 'Display all/previous layers (German keys: Shift-<2D>)'],
|
||||||
['Space', 'Popup menu'],
|
['Space', 'Popup menu'],
|
||||||
@@ -82,9 +85,10 @@ hotkeys={
|
|||||||
['TAB', 'IPO: Edit selected'],
|
['TAB', 'IPO: Edit selected'],
|
||||||
['Ctrl-TAB', 'Enter/exit Pose Mode'],
|
['Ctrl-TAB', 'Enter/exit Pose Mode'],
|
||||||
['Shift-TAB', 'Enter Object Mode'],
|
['Shift-TAB', 'Enter Object Mode'],
|
||||||
['Ctrl-Open menu/', ''],
|
['Ctrl-Open menu /', ''],
|
||||||
['Ctrl-Load Image', 'Opens a thumbnail browser instead of file browser for images']
|
['Ctrl-Load Image', 'Opens a thumbnail browser instead of file browser for images']
|
||||||
],
|
],
|
||||||
|
|
||||||
'Mouse ':[
|
'Mouse ':[
|
||||||
['Actions:', ''],
|
['Actions:', ''],
|
||||||
['LMB', '3D View: Set 3D Cursor'],
|
['LMB', '3D View: Set 3D Cursor'],
|
||||||
@@ -111,6 +115,7 @@ hotkeys={
|
|||||||
['MMB', 'Toggle optional transform feature'],
|
['MMB', 'Toggle optional transform feature'],
|
||||||
['RMB', 'Abort transformation']
|
['RMB', 'Abort transformation']
|
||||||
],
|
],
|
||||||
|
|
||||||
'F-Keys ':[
|
'F-Keys ':[
|
||||||
['F1', 'Open File'],
|
['F1', 'Open File'],
|
||||||
['F2', 'Save File'],
|
['F2', 'Save File'],
|
||||||
@@ -133,13 +138,18 @@ hotkeys={
|
|||||||
['Shift-F7', 'Buttons Window'],
|
['Shift-F7', 'Buttons Window'],
|
||||||
['Shift-F8', 'Video Sequencer Window'],
|
['Shift-F8', 'Video Sequencer Window'],
|
||||||
['Shift-F9', 'OOP Window'],
|
['Shift-F9', 'OOP Window'],
|
||||||
|
['Alt-Shift-F9', 'OutLiner Window'],
|
||||||
['Shift-F10', 'UV Image Editor'],
|
['Shift-F10', 'UV Image Editor'],
|
||||||
['Shift-F11', 'Text Editor'],
|
['Shift-F11', 'Text Editor'],
|
||||||
['Shift-F12', 'Action Editor']
|
['Shift-F12', 'Action Editor'],
|
||||||
|
['Ctrl-F2', 'Save/export in vrml 1.0 format' ],
|
||||||
|
['Ctrl-F3', 'Save image : dump 3d view'],
|
||||||
|
['Ctrl-Shift-F3', 'Save image : dump screen']
|
||||||
],
|
],
|
||||||
|
|
||||||
'Numbers ':[
|
'Numbers ':[
|
||||||
['1..2..0-=', 'Show layer 1..2..12'],
|
['1..2..0-=', 'Show layer 1..2..12'],
|
||||||
|
['1..2..0-=', 'Edit Mode with Size, Grab, rotate tools : enter value'],
|
||||||
['Alt-1..2..0', 'Show layer 11..12..20'],
|
['Alt-1..2..0', 'Show layer 11..12..20'],
|
||||||
['Shift-1..2..0-=', 'Toggle layer 1..2..12'],
|
['Shift-1..2..0-=', 'Toggle layer 1..2..12'],
|
||||||
['Shift-ALT-...', 'Toggle layer 11..12..20']
|
['Shift-ALT-...', 'Toggle layer 11..12..20']
|
||||||
@@ -150,10 +160,12 @@ hotkeys={
|
|||||||
['Numpad /', 'Local view on object (hide others)'],
|
['Numpad /', 'Local view on object (hide others)'],
|
||||||
['Numpad *', 'Rotate view to objects local axes'],
|
['Numpad *', 'Rotate view to objects local axes'],
|
||||||
['Numpad +', 'Zoom in (works everywhere)'],
|
['Numpad +', 'Zoom in (works everywhere)'],
|
||||||
['Numpad +', 'Proportional vertex Edit Mode: Increase range of influence'],
|
['Numpad +', 'In OutLiner window, Collapse one level of the hierarchy'],
|
||||||
|
['Alt-Numpad +', 'Proportional vertex Edit Mode: Increase range of influence'],
|
||||||
['Ctrl-Numpad +', 'Edit Mode: Select More vertices'],
|
['Ctrl-Numpad +', 'Edit Mode: Select More vertices'],
|
||||||
['Numpad -', 'Zoom out (works everywhere)'],
|
['Numpad -', 'Zoom out (works everywhere)'],
|
||||||
['Numpad -', 'Proportional vertex Edit Mode: Decrease range of influence'],
|
['Numpad +', 'In OutLiner window, Expand one level of the hierarchy'],
|
||||||
|
['Alt-Numpad -', 'Proportional vertex Edit Mode: Decrease range of influence'],
|
||||||
['Ctrl-Numpad +', 'Edit Mode: Select Less vertices'],
|
['Ctrl-Numpad +', 'Edit Mode: Select Less vertices'],
|
||||||
['Numpad INS', 'Set Camera view'],
|
['Numpad INS', 'Set Camera view'],
|
||||||
['Ctrl-Numpad INS', 'Set active object as camera'],
|
['Ctrl-Numpad INS', 'Set active object as camera'],
|
||||||
@@ -174,10 +186,19 @@ hotkeys={
|
|||||||
|
|
||||||
'Arrows ':[
|
'Arrows ':[
|
||||||
['Home/Pos1', 'View all'],
|
['Home/Pos1', 'View all'],
|
||||||
|
['Home', 'In OutLiner Windows, Show hierarchy'],
|
||||||
|
['PgUp', 'Edit Mode and Proportionnal Editing Tools, increase influence'],
|
||||||
|
['PgUp', 'Strip Editor, Move Down'],
|
||||||
|
['PgUn', 'TimeLine: Jump to next marker'],
|
||||||
['PgUp', 'IPO: Select next keyframe'],
|
['PgUp', 'IPO: Select next keyframe'],
|
||||||
['Ctrl-PgUp', 'IPO: Select and jump to next keyframe'],
|
['Ctrl-PgUp', 'IPO: Select and jump to next keyframe'],
|
||||||
|
['Ctrl-PgUn', 'TimeLine: Jump to next key'],
|
||||||
|
['PgDn', 'Edit Mode and Proportionnal Editing Tools, decrease influence'],
|
||||||
|
['PgDn', 'Strip Editor, Move Up'],
|
||||||
|
['PgDn', 'TimeLine: Jump to prev marker'],
|
||||||
['PgDn', 'IPO: Select previous keyframe'],
|
['PgDn', 'IPO: Select previous keyframe'],
|
||||||
['Ctrl-PgDn', 'IPO: Select and jump to previous keyframe'],
|
['Ctrl-PgDn', 'IPO: Select and jump to previous keyframe'],
|
||||||
|
['Ctrl-PgDn', 'TimeLine: Jump to prev key'],
|
||||||
['Left', 'One frame backwards'],
|
['Left', 'One frame backwards'],
|
||||||
['Right', 'One frame forwards'],
|
['Right', 'One frame forwards'],
|
||||||
['Down', '10 frames backwards'],
|
['Down', '10 frames backwards'],
|
||||||
@@ -191,7 +212,9 @@ hotkeys={
|
|||||||
['Shift-Arrow', 'Toggle first frame/ last frame']
|
['Shift-Arrow', 'Toggle first frame/ last frame']
|
||||||
],
|
],
|
||||||
|
|
||||||
'Letters ':[ {"A":[
|
'Letters ':[
|
||||||
|
{
|
||||||
|
"A":[
|
||||||
['A', 'Select all/Deselect all'],
|
['A', 'Select all/Deselect all'],
|
||||||
['Alt-A', 'Play animation in current window'],
|
['Alt-A', 'Play animation in current window'],
|
||||||
['Ctrl-A', 'Apply objects size/rotation to object data'],
|
['Ctrl-A', 'Apply objects size/rotation to object data'],
|
||||||
@@ -199,7 +222,8 @@ hotkeys={
|
|||||||
['Shift-A', 'Sequencer: Add menu'],
|
['Shift-A', 'Sequencer: Add menu'],
|
||||||
['Shift-A', '3D-View: Add menu'],
|
['Shift-A', '3D-View: Add menu'],
|
||||||
['Shift-ALT-A', 'Play animation in all windows'],
|
['Shift-ALT-A', 'Play animation in all windows'],
|
||||||
['Shift-CTRL-A', 'Apply lattice / Make dupliverts real']
|
['Shift-CTRL-A', 'Apply lattice / Make dupliverts real'],
|
||||||
|
['Shift-CTRL-A', 'Apply Deform ']
|
||||||
],
|
],
|
||||||
|
|
||||||
"B":[
|
"B":[
|
||||||
@@ -214,6 +238,7 @@ hotkeys={
|
|||||||
['C', 'UV Image Editor: Active Face Select toggle'],
|
['C', 'UV Image Editor: Active Face Select toggle'],
|
||||||
['C', 'Sequencer: Change images'],
|
['C', 'Sequencer: Change images'],
|
||||||
['C', 'IPO: Snap current frame to selected key'],
|
['C', 'IPO: Snap current frame to selected key'],
|
||||||
|
['C', 'TimeLine: Center View'],
|
||||||
['Alt-C', 'Object Mode: Convert menu'],
|
['Alt-C', 'Object Mode: Convert menu'],
|
||||||
['Alt-C', 'Text Editor: Copy selection to clipboard'],
|
['Alt-C', 'Text Editor: Copy selection to clipboard'],
|
||||||
['Ctrl-C', 'Copy menu (Copy properties of active to selected objects)'],
|
['Ctrl-C', 'Copy menu (Copy properties of active to selected objects)'],
|
||||||
@@ -232,6 +257,7 @@ hotkeys={
|
|||||||
"E":[
|
"E":[
|
||||||
['E', 'Edit Mode: Extrude'],
|
['E', 'Edit Mode: Extrude'],
|
||||||
['E', 'UV Image Editor: LSCM Unwrap'],
|
['E', 'UV Image Editor: LSCM Unwrap'],
|
||||||
|
['E', 'TimeLine: Set End'],
|
||||||
['ER', 'Edit Mode: Extrude Rotate'],
|
['ER', 'Edit Mode: Extrude Rotate'],
|
||||||
['ES', 'Edit Mode: Extrude Scale'],
|
['ES', 'Edit Mode: Extrude Scale'],
|
||||||
['ESX', 'Edit Mode: Extrude Scale X axis'],
|
['ESX', 'Edit Mode: Extrude Scale X axis'],
|
||||||
@@ -267,10 +293,13 @@ hotkeys={
|
|||||||
"H":[
|
"H":[
|
||||||
['H', 'Hide selected vertices/faces'],
|
['H', 'Hide selected vertices/faces'],
|
||||||
['H', 'Curves: Set handle type'],
|
['H', 'Curves: Set handle type'],
|
||||||
|
['H', 'Action editor: Handle type aligned'],
|
||||||
|
['H', 'Action editor: Handle type free'],
|
||||||
['Alt-H', 'Show Hidden vertices/faces'],
|
['Alt-H', 'Show Hidden vertices/faces'],
|
||||||
['Ctrl-H', 'Curves: Automatic handle calculation'],
|
['Shift-H', 'Curves: Automatic handle calculation'],
|
||||||
['Shift-H', 'Hide deselected vertices/faces'],
|
['Shift-H', 'Action editor: Handle type auto'],
|
||||||
['Shift-H', 'Curves: Set handle type']
|
['Shift-H', 'Edit Mode, Hide deselected vertices/faces'],
|
||||||
|
['Ctrl-H', 'Edit Mode, Add a hook on selected points or show the hook menu .']
|
||||||
],
|
],
|
||||||
|
|
||||||
"I":[
|
"I":[
|
||||||
@@ -284,7 +313,6 @@ hotkeys={
|
|||||||
['Ctrl-J', 'Join selected objects'],
|
['Ctrl-J', 'Join selected objects'],
|
||||||
['Ctrl-J', 'Nurbs: Add segment'],
|
['Ctrl-J', 'Nurbs: Add segment'],
|
||||||
['Ctrl-J', 'IPO: Join keyframes menu'],
|
['Ctrl-J', 'IPO: Join keyframes menu'],
|
||||||
['Alt-J', 'Edit Mode: convert quads to triangles']
|
|
||||||
],
|
],
|
||||||
|
|
||||||
"K":[
|
"K":[
|
||||||
@@ -304,7 +332,7 @@ hotkeys={
|
|||||||
['L', 'Edit mode: Select linked vertices (near mouse pointer)'],
|
['L', 'Edit mode: Select linked vertices (near mouse pointer)'],
|
||||||
['L', 'OOPS window: Select linked objects'],
|
['L', 'OOPS window: Select linked objects'],
|
||||||
['L', 'UV Face Select: Select linked faces'],
|
['L', 'UV Face Select: Select linked faces'],
|
||||||
['Ctrl-L', 'Make links menu'],
|
['Ctrl-L', 'Make links menu (for instance : to scene...)'],
|
||||||
['Shift-L', 'Select links menu']
|
['Shift-L', 'Select links menu']
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -312,8 +340,12 @@ hotkeys={
|
|||||||
['M', 'Move object to different layer'],
|
['M', 'Move object to different layer'],
|
||||||
['M', 'Sequencer: Make meta strip (group) from selected strips'],
|
['M', 'Sequencer: Make meta strip (group) from selected strips'],
|
||||||
['M', 'Edit Mode: Mirros Axis menu'],
|
['M', 'Edit Mode: Mirros Axis menu'],
|
||||||
|
['M', 'Video Sequence Editor : Make Meta strip...'],
|
||||||
|
['M', 'TimeLine: Add marker'],
|
||||||
['Alt-M', 'Edit Mode: Merge vertices menu'],
|
['Alt-M', 'Edit Mode: Merge vertices menu'],
|
||||||
['Ctrl-M', 'Object Mode: Mirros Axis menu']
|
['Alt-M', 'Video Sequence Editor : Separate Meta strip...'],
|
||||||
|
['Ctrl-M', 'Object Mode: Mirros Axis menu'],
|
||||||
|
['Ctrl-M', 'TimeLine: Name marker']
|
||||||
],
|
],
|
||||||
|
|
||||||
"N":[
|
"N":[
|
||||||
@@ -360,6 +392,7 @@ hotkeys={
|
|||||||
|
|
||||||
"S":[
|
"S":[
|
||||||
['S', 'Scale'] ,
|
['S', 'Scale'] ,
|
||||||
|
['S', 'TimeLine: Set Start'],
|
||||||
['SX', 'Flip around X axis'] ,
|
['SX', 'Flip around X axis'] ,
|
||||||
['SY', 'Flip around Y axis'] ,
|
['SY', 'Flip around Y axis'] ,
|
||||||
['SZ', 'Flip around Z axis'] ,
|
['SZ', 'Flip around Z axis'] ,
|
||||||
@@ -376,14 +409,15 @@ hotkeys={
|
|||||||
['T', 'Adjust texture space'] ,
|
['T', 'Adjust texture space'] ,
|
||||||
['T', 'Edit mode: Flip 3d curve'] ,
|
['T', 'Edit mode: Flip 3d curve'] ,
|
||||||
['T', 'IPO: Change IPO type'] ,
|
['T', 'IPO: Change IPO type'] ,
|
||||||
|
['T', 'TimeLine: Show second'],
|
||||||
['Alt-T', 'Clear tracking of object'] ,
|
['Alt-T', 'Clear tracking of object'] ,
|
||||||
['Ctrl-T', 'Make selected object track active object'] ,
|
['Ctrl-T', 'Make selected object track active object'] ,
|
||||||
['Ctrl-T', 'Edit Mode: Convert to triangles'] ,
|
['Ctrl-T', 'Edit Mode: Convert to triangles'] ,
|
||||||
['Ctrl-ALT-T', 'Benchmark'] ],
|
['Ctrl-ALT-T', 'Benchmark'] ],
|
||||||
|
|
||||||
"U":[
|
"U":[
|
||||||
['U', 'Make single user menu'] ,
|
['U', 'Make single user menu (for import completly linked object to another scene for instance) '] ,
|
||||||
['U', '3D View: Global undo'] ,
|
['U', '3D View: Make Single user Menu'] ,
|
||||||
['U', 'Edit Mode: Reload object data from before entering Edit Mode'] ,
|
['U', 'Edit Mode: Reload object data from before entering Edit Mode'] ,
|
||||||
['U', 'UV Face Select: Automatic UV calculation menu'] ,
|
['U', 'UV Face Select: Automatic UV calculation menu'] ,
|
||||||
['U', 'Vertex-/Weightpaint mode: Undo'] ,
|
['U', 'Vertex-/Weightpaint mode: Undo'] ,
|
||||||
@@ -395,9 +429,11 @@ hotkeys={
|
|||||||
['V', 'Curves/Nurbs: Vector handle'],
|
['V', 'Curves/Nurbs: Vector handle'],
|
||||||
['V', 'Vertexpaint mode'],
|
['V', 'Vertexpaint mode'],
|
||||||
['V', 'UV Image Editor: Stitch UVs'],
|
['V', 'UV Image Editor: Stitch UVs'],
|
||||||
|
['V', 'Action editor: Vector'],
|
||||||
['Alt-V', "Scale object to match image texture's aspect ratio"],
|
['Alt-V', "Scale object to match image texture's aspect ratio"],
|
||||||
['Shift-V', 'Edit mode: Align view to selected vertices'],
|
['Shift-V', 'Edit mode: Align view to selected vertices'],
|
||||||
['Shift-V', 'UV Image Editor: Limited Stitch UVs popup'],
|
['Shift-V', 'UV Image Editor: Limited Stitch UVs popup'],
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
"W":[
|
"W":[
|
||||||
@@ -408,11 +444,16 @@ hotkeys={
|
|||||||
['WY', 'UV Image Editor: Weld/Align Y axis'],
|
['WY', 'UV Image Editor: Weld/Align Y axis'],
|
||||||
['Ctrl-W', 'Save current file'] ,
|
['Ctrl-W', 'Save current file'] ,
|
||||||
['Ctrl-W', 'Nurbs: Switch direction'] ,
|
['Ctrl-W', 'Nurbs: Switch direction'] ,
|
||||||
['Shift-W', 'Warp/bend selected vertices around cursor'] ],
|
['Shift-W', 'Warp/bend selected vertices around cursor'],
|
||||||
|
['alt-W', 'Export in videoscape format']
|
||||||
|
],
|
||||||
|
|
||||||
"X":[
|
"X":[
|
||||||
['X', 'Delete menu'] ,
|
['X', 'Delete menu'] ,
|
||||||
['Ctrl-X', 'Restore default state (Erase all)'] ],
|
['X', 'TimeLine: Remove marker'],
|
||||||
|
['Ctrl-X', 'Restore default state (Erase all)']
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
"Y":[
|
"Y":[
|
||||||
['Y', 'Mesh: Split selected vertices/faces from the rest'] ],
|
['Y', 'Mesh: Split selected vertices/faces from the rest'] ],
|
||||||
@@ -429,6 +470,12 @@ hotkeys={
|
|||||||
up=128
|
up=128
|
||||||
down=129
|
down=129
|
||||||
UP=0
|
UP=0
|
||||||
|
SEARCH=131
|
||||||
|
OLDSEARCHLINE=''
|
||||||
|
SEARCHLINE=Create('')
|
||||||
|
LINE=130
|
||||||
|
FINDED=[]
|
||||||
|
LEN=0
|
||||||
|
|
||||||
for k in hotkeys.keys():
|
for k in hotkeys.keys():
|
||||||
hotkeys[k].append(Create(0))
|
hotkeys[k].append(Create(0))
|
||||||
@@ -442,6 +489,24 @@ hotL.sort()
|
|||||||
hot=hotkeys.keys()
|
hot=hotkeys.keys()
|
||||||
hot.sort()
|
hot.sort()
|
||||||
|
|
||||||
|
def searchfor(SEARCHLINE):
|
||||||
|
global hotkeys, hot
|
||||||
|
FINDLIST=[]
|
||||||
|
for k in hot:
|
||||||
|
if k not in ['Letters ', 'Search '] :
|
||||||
|
for l in hotkeys[k][:-1]:
|
||||||
|
#print 'k, l : ', k, l, l[1]
|
||||||
|
if l[1].upper().find(SEARCHLINE.upper())!=-1:
|
||||||
|
FINDLIST.append(l)
|
||||||
|
elif k == 'Letters ':
|
||||||
|
for l in hotL :
|
||||||
|
for l0 in hotkeys['Letters '][0][l][:-1]:
|
||||||
|
#print 'k, l : ',l, k, l0
|
||||||
|
if l0[1].upper().find(SEARCHLINE.upper())!=-1:
|
||||||
|
FINDLIST.append(l0)
|
||||||
|
return FINDLIST
|
||||||
|
|
||||||
|
|
||||||
glCr=glRasterPos2d
|
glCr=glRasterPos2d
|
||||||
glCl3=glColor3f
|
glCl3=glColor3f
|
||||||
glCl4=glColor4f
|
glCl4=glColor4f
|
||||||
@@ -462,8 +527,8 @@ def trace_rectangle3(r,c,c1):
|
|||||||
glCl3(c1[0],c1[1],c1[2])
|
glCl3(c1[0],c1[1],c1[2])
|
||||||
|
|
||||||
def draw():
|
def draw():
|
||||||
global r,c,c1,hotkeys, hot, hotL, up, down, UP
|
global r,c,c1,hotkeys, hot, hotL, up, down, UP, SEARCH, SEARCHLINE,LINE
|
||||||
|
global OLDSEARCHLINE, FINDED, SCROLL, LEN
|
||||||
size=Buffer(GL_FLOAT, 4)
|
size=Buffer(GL_FLOAT, 4)
|
||||||
glGetFloatv(GL_SCISSOR_BOX, size)
|
glGetFloatv(GL_SCISSOR_BOX, size)
|
||||||
size= size.list
|
size= size.list
|
||||||
@@ -499,14 +564,12 @@ def draw():
|
|||||||
for k in hot:
|
for k in hot:
|
||||||
#hotkeys[k][-1]=Toggle(k, hot.index(k)+10, 4+(20*26)/6*hot.index(k), size[3]-(42), len(k)*8, 20, hotkeys[k][-1].val )
|
#hotkeys[k][-1]=Toggle(k, hot.index(k)+10, 4+(20*26)/6*hot.index(k), size[3]-(42), len(k)*8, 20, hotkeys[k][-1].val )
|
||||||
hotkeys[k][-1]=Toggle(k, hot.index(k)+10, 78*hot.index(k), size[3]-(47), 78, 24, hotkeys[k][-1].val )
|
hotkeys[k][-1]=Toggle(k, hot.index(k)+10, 78*hot.index(k), size[3]-(47), 78, 24, hotkeys[k][-1].val )
|
||||||
|
|
||||||
l+=len(k)
|
l+=len(k)
|
||||||
|
|
||||||
if hotkeys[k][-1].val==1.0:
|
if hotkeys[k][-1].val==1.0:
|
||||||
listed=hot.index(k)
|
listed=hot.index(k)
|
||||||
l=0
|
l=0
|
||||||
size[3]=size[3]-4
|
size[3]=size[3]-4
|
||||||
if hot[listed]!='Letters ':
|
if hot[listed]!='Letters ' and hot[listed]!='Search ' :
|
||||||
size[3]=size[3]-8
|
size[3]=size[3]-8
|
||||||
SCROLL=size[3]/21
|
SCROLL=size[3]/21
|
||||||
END=-1
|
END=-1
|
||||||
@@ -520,9 +583,7 @@ def draw():
|
|||||||
UP=len(hotkeys[hot[listed]][:-1])-SCROLL
|
UP=len(hotkeys[hot[listed]][:-1])-SCROLL
|
||||||
else :
|
else :
|
||||||
UP=0
|
UP=0
|
||||||
|
|
||||||
for n in hotkeys[hot[listed]][:-1][UP:END]:
|
for n in hotkeys[hot[listed]][:-1][UP:END]:
|
||||||
|
|
||||||
if l%2==0:
|
if l%2==0:
|
||||||
r=[0,size[3]-(21*l+66),
|
r=[0,size[3]-(21*l+66),
|
||||||
size[2], size[3]-(21*l+43)]
|
size[2], size[3]-(21*l+43)]
|
||||||
@@ -533,20 +594,50 @@ def draw():
|
|||||||
glRasterPos2f(4+8*15, size[3]-(58+21*l))
|
glRasterPos2f(4+8*15, size[3]-(58+21*l))
|
||||||
Text(' : '+n[1])
|
Text(' : '+n[1])
|
||||||
l+=1
|
l+=1
|
||||||
|
elif hot[listed]=='Search ' :
|
||||||
|
r=[0,size[3]-70,
|
||||||
|
size[2], size[3]-44]
|
||||||
|
trace_rectangle4(r,c2)
|
||||||
|
SEARCHLINE=String(' ', LINE, 42, size[3]-68,200,18,SEARCHLINE.val, 256,'')
|
||||||
|
if len(FINDED)>0:
|
||||||
|
LEN=len(FINDED)
|
||||||
|
size[3]=size[3]-8
|
||||||
|
SCROLL=size[3]/21
|
||||||
|
END=-1
|
||||||
|
if SCROLL < len(FINDED):
|
||||||
|
Button('/\\',up,4,size[3]+8,20,14,'Scroll up')
|
||||||
|
Button('\\/',down,4,size[3]-8,20,14,'Scroll down')
|
||||||
|
if (SCROLL+UP)<len(FINDED):
|
||||||
|
END=(UP+SCROLL-1)
|
||||||
|
else:
|
||||||
|
END=-1
|
||||||
|
#UP=len(FINDED)-SCROLL
|
||||||
|
else:
|
||||||
|
UP=0
|
||||||
|
for n in FINDED[UP:END]:
|
||||||
|
if l%2==0:
|
||||||
|
r=[0,size[3]-(21*l+66+24),
|
||||||
|
size[2], size[3]-(21*l+43+24)]
|
||||||
|
trace_rectangle4(r,c2)
|
||||||
|
glColor3f(0,0,0)
|
||||||
|
glRasterPos2f(4+8, size[3]-(58+24+21*l))
|
||||||
|
Text(n[0])
|
||||||
|
glRasterPos2f(4+8*15, size[3]-(58+24+21*l))
|
||||||
|
Text(' : '+n[1])
|
||||||
|
l+=1
|
||||||
else:
|
else:
|
||||||
for k in hotL:
|
for k in hotL:
|
||||||
pos=hotL.index(k)
|
pos=hotL.index(k)
|
||||||
hotkeys['Letters '][0][k][-1]=Toggle(k,pos+20,hotL.index(k)*21, size[3]-(52+18), 21, 18, hotkeys['Letters '][0][k][-1].val )
|
hotkeys['Letters '][0][k][-1]=Toggle(k,pos+20,hotL.index(k)*21, size[3]-(52+18), 21, 18, hotkeys['Letters '][0][k][-1].val )
|
||||||
if hotkeys['Letters '][0][k][-1].val==1.0:
|
if hotkeys['Letters '][0][k][-1].val==1.0:
|
||||||
Llisted=pos
|
Llisted=pos
|
||||||
|
|
||||||
size[3]=size[3]-8
|
size[3]=size[3]-8
|
||||||
|
|
||||||
SCROLL=(size[3]-88)/21
|
SCROLL=(size[3]-88)/21
|
||||||
END=-1
|
END=-1
|
||||||
if SCROLL < len(hotkeys['Letters '][0][hotL[Llisted]]):
|
if SCROLL < len(hotkeys['Letters '][0][hotL[Llisted]]):
|
||||||
Button('/\\',up,4,size[3]+8,20,14,'Scroll up')
|
LEN=len(hotkeys['Letters '][0][hotL[Llisted]])
|
||||||
Button('\\/',down,4,size[3]-8,20,14,'Scroll down')
|
Button('/\\',up,4,size[3]+8,20,14,'Scroll up, you can use arrow or page keys too ')
|
||||||
|
Button('\\/',down,4,size[3]-8,20,14,'Scroll down, you can use arrow or page keys too ')
|
||||||
if (UP+SCROLL)<len(hotkeys['Letters '][0][hotL[Llisted]]):
|
if (UP+SCROLL)<len(hotkeys['Letters '][0][hotL[Llisted]]):
|
||||||
END=(UP+SCROLL)
|
END=(UP+SCROLL)
|
||||||
else:
|
else:
|
||||||
@@ -569,13 +660,27 @@ def draw():
|
|||||||
l+=1
|
l+=1
|
||||||
|
|
||||||
def event(evt, val):
|
def event(evt, val):
|
||||||
global hotkeys, UP
|
global hotkeys, UP, SCROLL , LEN
|
||||||
if ((evt== QKEY or evt== ESCKEY) and not val):
|
if (evt== QKEY or evt== ESCKEY):
|
||||||
Exit()
|
Exit()
|
||||||
|
elif val:
|
||||||
|
if (evt== PAGEUPKEY):
|
||||||
|
if (UP+SCROLL)<LEN-5:
|
||||||
|
UP+=5
|
||||||
|
elif (evt== PAGEDOWNKEY):
|
||||||
|
if UP>4:
|
||||||
|
UP-=5
|
||||||
|
elif (evt== UPARROWKEY):
|
||||||
|
if (UP+SCROLL)<LEN-1:
|
||||||
|
UP+=1
|
||||||
|
elif (evt== DOWNARROWKEY):
|
||||||
|
if UP>0:
|
||||||
|
UP-=1
|
||||||
|
Redraw()
|
||||||
|
|
||||||
def bevent(evt):
|
def bevent(evt):
|
||||||
global hotkeysmhot, hotL, up,down,UP
|
global hotkeysmhot, hotL, up,down,UP, FINDED
|
||||||
|
global SEARCH, SEARCHLINE,LINE, OLDSEARCHLINE
|
||||||
|
|
||||||
if (evt== 1):
|
if (evt== 1):
|
||||||
Exit()
|
Exit()
|
||||||
@@ -602,4 +707,11 @@ def bevent(evt):
|
|||||||
if UP>0: UP-=1
|
if UP>0: UP-=1
|
||||||
Blender.Window.Redraw()
|
Blender.Window.Redraw()
|
||||||
|
|
||||||
|
elif (evt==LINE):
|
||||||
|
if SEARCHLINE.val!='' and SEARCHLINE.val!=OLDSEARCHLINE:
|
||||||
|
OLDSEARCHLINE=SEARCHLINE.val
|
||||||
|
FINDED=searchfor(OLDSEARCHLINE)
|
||||||
|
Blender.Window.Redraw()
|
||||||
|
|
||||||
|
|
||||||
Register(draw, event, bevent)
|
Register(draw, event, bevent)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Usage:<br>
|
|||||||
Supported:<br>
|
Supported:<br>
|
||||||
UV Coordinates, Meshes, Materials, Material Indices, Specular
|
UV Coordinates, Meshes, Materials, Material Indices, Specular
|
||||||
Highlights, and Vertex Colors. For added functionality, each object is
|
Highlights, and Vertex Colors. For added functionality, each object is
|
||||||
placed on its own layer.
|
placed on its own layer. Someone added the CLIP chunk and imagename support.
|
||||||
|
|
||||||
Missing:<br>
|
Missing:<br>
|
||||||
Not too much, I hope! :).
|
Not too much, I hope! :).
|
||||||
@@ -95,6 +95,7 @@ def write(filename):
|
|||||||
bbox = generate_bbox(mesh)
|
bbox = generate_bbox(mesh)
|
||||||
pols = generate_pols(mesh)
|
pols = generate_pols(mesh)
|
||||||
ptag = generate_ptag(mesh, material_names)
|
ptag = generate_ptag(mesh, material_names)
|
||||||
|
clip = generate_clip(mesh, material_names)
|
||||||
|
|
||||||
if mesh.hasFaceUV():
|
if mesh.hasFaceUV():
|
||||||
vmad_uv = generate_vmad_uv(mesh) # per face
|
vmad_uv = generate_vmad_uv(mesh) # per face
|
||||||
@@ -111,10 +112,6 @@ def write(filename):
|
|||||||
write_chunk(meshdata, "POLS", pols); chunks.append(pols)
|
write_chunk(meshdata, "POLS", pols); chunks.append(pols)
|
||||||
write_chunk(meshdata, "PTAG", ptag); chunks.append(ptag)
|
write_chunk(meshdata, "PTAG", ptag); chunks.append(ptag)
|
||||||
|
|
||||||
if mesh.hasFaceUV():
|
|
||||||
write_chunk(meshdata, "VMAD", vmad_uv)
|
|
||||||
chunks.append(vmad_uv)
|
|
||||||
|
|
||||||
if meshtools.has_vertex_colors(mesh):
|
if meshtools.has_vertex_colors(mesh):
|
||||||
if meshtools.average_vcols:
|
if meshtools.average_vcols:
|
||||||
write_chunk(meshdata, "VMAP", vmap_vc)
|
write_chunk(meshdata, "VMAP", vmap_vc)
|
||||||
@@ -122,6 +119,13 @@ def write(filename):
|
|||||||
else:
|
else:
|
||||||
write_chunk(meshdata, "VMAD", vmad_vc)
|
write_chunk(meshdata, "VMAD", vmad_vc)
|
||||||
chunks.append(vmad_vc)
|
chunks.append(vmad_vc)
|
||||||
|
|
||||||
|
if mesh.hasFaceUV():
|
||||||
|
write_chunk(meshdata, "VMAD", vmad_uv)
|
||||||
|
chunks.append(vmad_uv)
|
||||||
|
write_chunk(meshdata, "CLIP", clip)
|
||||||
|
chunks.append(clip)
|
||||||
|
|
||||||
layer_index += 1
|
layer_index += 1
|
||||||
|
|
||||||
for surf in surfs:
|
for surf in surfs:
|
||||||
@@ -135,6 +139,7 @@ def write(filename):
|
|||||||
file.write(meshdata.getvalue()); meshdata.close()
|
file.write(meshdata.getvalue()); meshdata.close()
|
||||||
for surf in surfs:
|
for surf in surfs:
|
||||||
write_chunk(file, "SURF", surf)
|
write_chunk(file, "SURF", surf)
|
||||||
|
write_chunk(file, "DATE", "August 19, 2005")
|
||||||
|
|
||||||
Blender.Window.DrawProgressBar(1.0, "") # clear progressbar
|
Blender.Window.DrawProgressBar(1.0, "") # clear progressbar
|
||||||
file.close()
|
file.close()
|
||||||
@@ -456,6 +461,46 @@ def generate_surf(material_name):
|
|||||||
comment = generate_nstring(comment)
|
comment = generate_nstring(comment)
|
||||||
data.write(struct.pack(">H", len(comment)))
|
data.write(struct.pack(">H", len(comment)))
|
||||||
data.write(comment)
|
data.write(comment)
|
||||||
|
|
||||||
|
# Check if the material contains any image maps
|
||||||
|
mtextures = material.getTextures() # Get a list of textures linked to the material
|
||||||
|
for mtex in mtextures:
|
||||||
|
if (mtex) and (mtex.tex.type == Blender.Texture.Types.IMAGE): # Check if the texture is of type "IMAGE"
|
||||||
|
data.write("BLOK") # Surface BLOK header
|
||||||
|
data.write(struct.pack(">H", 104)) # Hardcoded and ugly! Will only handle 1 image per material
|
||||||
|
|
||||||
|
# IMAP subchunk (image map sub header)
|
||||||
|
data.write("IMAP")
|
||||||
|
data_tmp = cStringIO.StringIO()
|
||||||
|
data_tmp.write(struct.pack(">H", 0)) # Hardcoded - not sure what it represents
|
||||||
|
data_tmp.write("CHAN")
|
||||||
|
data_tmp.write(struct.pack(">H", 4))
|
||||||
|
data_tmp.write("COLR")
|
||||||
|
data_tmp.write("OPAC") # Hardcoded texture layer opacity
|
||||||
|
data_tmp.write(struct.pack(">H", 8))
|
||||||
|
data_tmp.write(struct.pack(">H", 0))
|
||||||
|
data_tmp.write(struct.pack(">f", 1.0))
|
||||||
|
data_tmp.write(struct.pack(">H", 0))
|
||||||
|
data_tmp.write("ENAB")
|
||||||
|
data_tmp.write(struct.pack(">HH", 2, 1)) # 1 = texture layer enabled
|
||||||
|
data_tmp.write("NEGA")
|
||||||
|
data_tmp.write(struct.pack(">HH", 2, 0)) # Disable negative image (1 = invert RGB values)
|
||||||
|
data_tmp.write("AXIS")
|
||||||
|
data_tmp.write(struct.pack(">HH", 2, 1))
|
||||||
|
data.write(struct.pack(">H", len(data_tmp.getvalue())))
|
||||||
|
data.write(data_tmp.getvalue())
|
||||||
|
|
||||||
|
# IMAG subchunk
|
||||||
|
data.write("IMAG")
|
||||||
|
data.write(struct.pack(">HH", 2, 1))
|
||||||
|
data.write("PROJ")
|
||||||
|
data.write(struct.pack(">HH", 2, 5)) # UV projection
|
||||||
|
|
||||||
|
data.write("VMAP")
|
||||||
|
uvname = generate_nstring("Blender's UV Coordinates")
|
||||||
|
data.write(struct.pack(">H", len(uvname)))
|
||||||
|
data.write(uvname)
|
||||||
|
|
||||||
return data.getvalue()
|
return data.getvalue()
|
||||||
|
|
||||||
# =============================================
|
# =============================================
|
||||||
@@ -536,6 +581,27 @@ def generate_icon():
|
|||||||
#print len(icon_data)
|
#print len(icon_data)
|
||||||
return data.getvalue()
|
return data.getvalue()
|
||||||
|
|
||||||
|
# ===============================================
|
||||||
|
# === Generate CLIP chunk with STIL subchunks ===
|
||||||
|
# ===============================================
|
||||||
|
def generate_clip(mesh, material_names):
|
||||||
|
data = cStringIO.StringIO()
|
||||||
|
clipid = 1
|
||||||
|
for i in range(len(mesh.materials)): # Run through list of materials used by mesh
|
||||||
|
material = Blender.Material.Get(mesh.materials[i].name)
|
||||||
|
mtextures = material.getTextures() # Get a list of textures linked to the material
|
||||||
|
for mtex in mtextures:
|
||||||
|
if (mtex) and (mtex.tex.type == Blender.Texture.Types.IMAGE): # Check if the texture is of type "IMAGE"
|
||||||
|
pathname = mtex.tex.image.filename # If full path is needed use filename in place of name
|
||||||
|
pathname = pathname[0:2] + pathname.replace("\\", "/")[3:] # Convert to Modo standard path
|
||||||
|
imagename = generate_nstring(pathname)
|
||||||
|
data.write(struct.pack(">L", clipid)) # CLIP sequence/id
|
||||||
|
data.write("STIL") # STIL image
|
||||||
|
data.write(struct.pack(">H", len(imagename))) # Size of image name
|
||||||
|
data.write(imagename)
|
||||||
|
clipid += 1
|
||||||
|
return data.getvalue()
|
||||||
|
|
||||||
# ===================
|
# ===================
|
||||||
# === Write Chunk ===
|
# === Write Chunk ===
|
||||||
# ===================
|
# ===================
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ Tooltip: 'Save a Wavefront OBJ File'
|
|||||||
|
|
||||||
__author__ = "Campbell Barton, Jiri Hnidek"
|
__author__ = "Campbell Barton, Jiri Hnidek"
|
||||||
__url__ = ["blender", "elysiun"]
|
__url__ = ["blender", "elysiun"]
|
||||||
__version__ = "0.9"
|
__version__ = "1.0"
|
||||||
|
|
||||||
__bpydoc__ = """\
|
__bpydoc__ = """\
|
||||||
This script is an exporter to OBJ file format.
|
This script is an exporter to OBJ file format.
|
||||||
@@ -49,73 +49,155 @@ def newFName(ext):
|
|||||||
return Get('filename')[: -len(Get('filename').split('.', -1)[-1]) ] + ext
|
return Get('filename')[: -len(Get('filename').split('.', -1)[-1]) ] + ext
|
||||||
|
|
||||||
|
|
||||||
|
def fixName(name):
|
||||||
|
if name == None:
|
||||||
|
return 'None'
|
||||||
|
else:
|
||||||
|
return name.replace(' ', '_')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from Blender import *
|
from Blender import *
|
||||||
|
|
||||||
NULL_MAT = '(null)'
|
global MTL_DICT
|
||||||
NULL_IMG = '(null)' # from docs at http://astronomy.swin.edu.au/~pbourke/geomformats/obj/ also could be 'off'
|
|
||||||
|
# A Dict of Materials
|
||||||
|
# (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
|
||||||
|
MTL_DICT = {}
|
||||||
|
|
||||||
def save_mtl(filename):
|
def save_mtl(filename):
|
||||||
file = open(filename, "w")
|
global MTL_DICT
|
||||||
file.write('# Blender MTL File: %s\n' % (Get('filename')))
|
|
||||||
for mat in Material.Get():
|
|
||||||
file.write('newmtl %s\n' % (mat.getName())) # Define a new material
|
|
||||||
file.write('Ns %s\n' % ((mat.getHardness()-1) * 1.9607843137254901 ) ) # Hardness, convert blenders 1-511 to MTL's
|
|
||||||
file.write('Kd %.6f %.6f %.6f\n' % tuple(mat.getRGBCol())) # Diffuse
|
|
||||||
file.write('Ka %.6f %.6f %.6f\n' % tuple(mat.getMirCol())) # Ambient, uses mirror colour,
|
|
||||||
file.write('Ks %.6f %.6f %.6f\n' % tuple(mat.getSpecCol())) # Specular
|
|
||||||
file.write('Ni %.6f\n' % mat.getIOR()) # Refraction index
|
|
||||||
file.write('d %.6f\n' % mat.getAlpha()) # Alpha (obj uses 'd' for dissolve)
|
|
||||||
|
|
||||||
# illum, 0 to disable lightng, 2 is normal.
|
world = World.GetCurrent()
|
||||||
if mat.getMode() & Material.Modes['SHADELESS']:
|
if world:
|
||||||
file.write('illum 0\n\n') # ignore lighting
|
worldAmb = world.getAmb()
|
||||||
else:
|
else:
|
||||||
file.write('illum 2\n\n') # light normaly
|
worldAmb = (0,0,0) # Default value
|
||||||
|
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write('# Blender MTL File: %s\n' % Get('filename').split('\\')[-1].split('/')[-1])
|
||||||
|
file.write('# Material Count: %i\n' % len(MTL_DICT))
|
||||||
|
# Write material/image combinations we have used.
|
||||||
|
for key, mtl_mat_name in MTL_DICT.iteritems():
|
||||||
|
|
||||||
|
# Get the Blender data for the material and the image.
|
||||||
|
# Having an image named None will make a bug, dont do it :)
|
||||||
|
|
||||||
|
file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname
|
||||||
|
|
||||||
|
if key[0] == None:
|
||||||
|
#write a dummy material here?
|
||||||
|
file.write('Ns 0\n')
|
||||||
|
file.write('Ka %s %s %s\n' % tuple([round(c, 6) for c in worldAmb]) ) # Ambient, uses mirror colour,
|
||||||
|
file.write('Kd 0.8 0.8 0.8\n')
|
||||||
|
file.write('Ks 0.8 0.8 0.8\n')
|
||||||
|
file.write('d 1\n') # No alpha
|
||||||
|
file.write('illum 2\n') # light normaly
|
||||||
|
|
||||||
|
else:
|
||||||
|
mat = Material.Get(key[0])
|
||||||
|
file.write('Ns %s\n' % round((mat.getHardness()-1) * 1.9607843137254901 ) ) # Hardness, convert blenders 1-511 to MTL's
|
||||||
|
file.write('Ka %s %s %s\n' % tuple([round(c*mat.getAmb(), 6) for c in worldAmb]) ) # Ambient, uses mirror colour,
|
||||||
|
file.write('Kd %s %s %s\n' % tuple([round(c*mat.getRef(), 6) for c in mat.getRGBCol()]) ) # Diffuse
|
||||||
|
file.write('Ks %s %s %s\n' % tuple([round(c*mat.getSpec(), 6) for c in mat.getSpecCol()]) ) # Specular
|
||||||
|
file.write('Ni %s\n' % round(mat.getIOR(), 6)) # Refraction index
|
||||||
|
file.write('d %s\n' % round(mat.getAlpha(), 6)) # Alpha (obj uses 'd' for dissolve)
|
||||||
|
|
||||||
|
# 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting.
|
||||||
|
if mat.getMode() & Material.Modes['SHADELESS']:
|
||||||
|
file.write('illum 0\n') # ignore lighting
|
||||||
|
elif mat.getSpec() == 0:
|
||||||
|
file.write('illum 1\n') # no specular.
|
||||||
|
else:
|
||||||
|
file.write('illum 2\n') # light normaly
|
||||||
|
|
||||||
|
|
||||||
|
# Write images!
|
||||||
|
if key[1] != None: # We have an image on the face!
|
||||||
|
img = Image.Get(key[1])
|
||||||
|
file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image
|
||||||
|
|
||||||
|
elif key[0] != None: # No face image. if we havea material search for MTex image.
|
||||||
|
for mtex in mat.getTextures():
|
||||||
|
if mtex and mtex.tex.type == Texture.Types.IMAGE:
|
||||||
|
try:
|
||||||
|
filename = mtex.tex.image.filename.split('\\')[-1].split('/')[-1]
|
||||||
|
file.write('map_Kd %s\n' % filename) # Diffuse mapping image
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
# Texture has no image though its an image type, best ignore.
|
||||||
|
pass
|
||||||
|
|
||||||
|
file.write('\n\n')
|
||||||
|
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def save_obj(filename):
|
def save_obj(filename):
|
||||||
|
global MTL_DICT
|
||||||
|
|
||||||
time1 = sys.time()
|
time1 = sys.time()
|
||||||
scn = Scene.GetCurrent()
|
scn = Scene.GetCurrent()
|
||||||
# First output all material
|
|
||||||
mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
|
|
||||||
save_mtl(mtlfilename)
|
|
||||||
|
|
||||||
file = open(filename, "w")
|
file = open(filename, "w")
|
||||||
|
|
||||||
# Write Header
|
# Write Header
|
||||||
file.write('# Blender OBJ File: %s\n' % (Get('filename')))
|
file.write('# Blender OBJ File: %s\n' % (Get('filename').split('/')[-1].split('\\')[-1] ))
|
||||||
file.write('# www.blender.org\n')
|
file.write('# www.blender.org\n')
|
||||||
|
|
||||||
# Tell the obj file what material file to use.
|
# Tell the obj file what material file to use.
|
||||||
|
mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
|
||||||
file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] ))
|
file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] ))
|
||||||
|
|
||||||
# Initialize totals, these are updated each object
|
# Initialize totals, these are updated each object
|
||||||
totverts = totuvco = 0
|
totverts = totuvco = totno = 1
|
||||||
|
|
||||||
globalUVCoords = {}
|
globalUVCoords = {}
|
||||||
|
globalNormals = {}
|
||||||
|
|
||||||
# Get all meshs
|
# Get all meshs
|
||||||
for ob in scn.getChildren():
|
for ob in scn.getChildren():
|
||||||
if ob.getType() != 'Mesh':
|
#for ob in Object.GetSelected():
|
||||||
continue
|
try:
|
||||||
|
# Will work for non meshes now! :)
|
||||||
m = NMesh.GetRawFromObject(ob.name)
|
m = NMesh.GetRawFromObject(ob.name)
|
||||||
m.transform(ob.matrix)
|
except:
|
||||||
|
continue
|
||||||
if not m.faces: # Make sure there is somthing to write
|
|
||||||
continue #dont bother with this mesh.
|
|
||||||
|
|
||||||
faces = [ f for f in m.faces if len(f) > 2 ]
|
faces = [ f for f in m.faces if len(f) > 2 ]
|
||||||
materials = m.materials
|
|
||||||
|
|
||||||
# Sort by Material so we dont over context switch in the obj file.
|
if not faces: # Make sure there is somthing to write
|
||||||
if len(materials) > 1:
|
continue # dont bother with this mesh.
|
||||||
faces.sort(lambda a,b: cmp(a.mat, b.mat))
|
|
||||||
|
|
||||||
# Set the default mat
|
m.transform(ob.matrix)
|
||||||
currentMatName = NULL_MAT
|
|
||||||
currentImgName = NULL_IMG
|
|
||||||
|
|
||||||
file.write('o %s_%s\n' % (ob.getName(), m.name)) # Write Object name
|
# # Crash Blender
|
||||||
|
#materials = m.getMaterials(1) # 1 == will return None in the list.
|
||||||
|
materials = m.getMaterials()
|
||||||
|
|
||||||
|
|
||||||
|
if materials:
|
||||||
|
materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.
|
||||||
|
else:
|
||||||
|
materialNames = []
|
||||||
|
|
||||||
|
# Possible there null materials, will mess up indicies
|
||||||
|
# but at least it will export, wait until Blender gets fixed.
|
||||||
|
materialNames.extend((16-len(materialNames)) * [None])
|
||||||
|
|
||||||
|
|
||||||
|
# Sort by Material, then images
|
||||||
|
# so we dont over context switch in the obj file.
|
||||||
|
faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
|
||||||
|
|
||||||
|
|
||||||
|
# Set the default mat to no material and no image.
|
||||||
|
contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get.
|
||||||
|
contextSmooth = None # Will either be true or false, set bad to force initialization switch.
|
||||||
|
|
||||||
|
file.write('o %s_%s\n' % (fixName(ob.name), fixName(m.name))) # Write Object name
|
||||||
|
|
||||||
# Vert
|
# Vert
|
||||||
for v in m.verts:
|
for v in m.verts:
|
||||||
@@ -124,59 +206,130 @@ def save_obj(filename):
|
|||||||
# UV
|
# UV
|
||||||
if m.hasFaceUV():
|
if m.hasFaceUV():
|
||||||
for f in faces:
|
for f in faces:
|
||||||
for uv in f.uv:
|
for uvKey in f.uv:
|
||||||
uvKey = '%.6f %.6f' % uv
|
if not globalUVCoords.has_key(uvKey):
|
||||||
try:
|
|
||||||
dummy = globalUVCoords[uvKey]
|
|
||||||
except KeyError:
|
|
||||||
totuvco +=1 # 1 based index.
|
|
||||||
globalUVCoords[uvKey] = totuvco
|
globalUVCoords[uvKey] = totuvco
|
||||||
file.write('vt %s 0.0\n' % uvKey)
|
totuvco +=1
|
||||||
|
file.write('vt %.6f %.6f 0.0\n' % uvKey)
|
||||||
|
|
||||||
|
# NORMAL, Smooth/Non smoothed.
|
||||||
|
|
||||||
|
for f in faces:
|
||||||
|
if f.smooth:
|
||||||
|
for v in f.v:
|
||||||
|
noKey = tuple(v.no)
|
||||||
|
if not globalNormals.has_key( noKey ):
|
||||||
|
globalNormals[noKey] = totno
|
||||||
|
totno +=1
|
||||||
|
file.write('vn %.6f %.6f %.6f\n' % noKey)
|
||||||
|
else:
|
||||||
|
# Hard, 1 normal from the face.
|
||||||
|
noKey = tuple(f.no)
|
||||||
|
if not globalNormals.has_key( noKey ):
|
||||||
|
globalNormals[noKey] = totno
|
||||||
|
totno +=1
|
||||||
|
file.write('vn %.6f %.6f %.6f\n' % noKey)
|
||||||
|
|
||||||
# NORMAL
|
|
||||||
for v in m.verts:
|
|
||||||
file.write('vn %.6f %.6f %.6f\n' % tuple(v.no))
|
|
||||||
|
|
||||||
uvIdx = 0
|
uvIdx = 0
|
||||||
for f in faces:
|
for f in faces:
|
||||||
# Check material and change if needed.
|
|
||||||
if len(materials) > 0:
|
|
||||||
if currentMatName != materials[f.mat].getName():
|
|
||||||
currentMatName = materials[f.mat].getName()
|
|
||||||
file.write('usemtl %s\n' % (currentMatName))
|
|
||||||
|
|
||||||
elif currentMatName != NULL_MAT:
|
# MAKE KEY
|
||||||
currentMatName = NULL_MAT
|
if f.image: # Object is always true.
|
||||||
file.write('usemtl %s\n' % (currentMatName))
|
key = materialNames[f.mat], f.image.name
|
||||||
|
else:
|
||||||
|
key = materialNames[f.mat], None # No image, use None instead.
|
||||||
|
|
||||||
# UV IMAGE
|
# CHECK FOR CONTEXT SWITCH
|
||||||
# If the face uses a different image from the one last set then add a usemap line.
|
if key == contextMat:
|
||||||
if f.image:
|
pass # Context alredy switched, dont do anythoing
|
||||||
if f.image.filename != currentImgName:
|
elif key[0] == None and key[1] == None:
|
||||||
currentImgName = f.image.filename
|
# Write a null material, since we know the context has changed.
|
||||||
# Set a new image for all following faces
|
file.write('usemtl (null)\n') # mat, image
|
||||||
file.write( 'usemap %s\n' % currentImgName.split('\\')[-1].split('/')[-1] )
|
|
||||||
|
|
||||||
elif currentImgName != NULL_IMG: # Not using an image so set to NULL_IMG
|
else:
|
||||||
currentImgName = NULL_IMG
|
try: # Faster to try then 2x dict lookups.
|
||||||
# Set a ne w image for all following faces
|
|
||||||
file.write( 'usemap %s\n' % currentImgName) # No splitting needed.
|
# We have the material, just need to write the context switch,
|
||||||
|
file.write('usemtl %s\n' % MTL_DICT[key]) # mat, image
|
||||||
|
|
||||||
|
except KeyError:
|
||||||
|
# First add to global dict so we can export to mtl
|
||||||
|
# Then write mtl
|
||||||
|
|
||||||
|
# Make a new names from the mat and image name,
|
||||||
|
# converting any spaces to underscores with fixName.
|
||||||
|
|
||||||
|
# If none image dont bother adding it to the name
|
||||||
|
if key[1] == None:
|
||||||
|
tmp_matname = MTL_DICT[key] ='%s' % fixName(key[0])
|
||||||
|
file.write('usemtl %s\n' % tmp_matname) # mat, image
|
||||||
|
|
||||||
|
else:
|
||||||
|
tmp_matname = MTL_DICT[key] = '%s_%s' % (fixName(key[0]), fixName(key[1]))
|
||||||
|
file.write('usemtl %s\n' % tmp_matname) # mat, image
|
||||||
|
|
||||||
|
contextMat = key
|
||||||
|
|
||||||
|
if f.smooth != contextSmooth:
|
||||||
|
if f.smooth:
|
||||||
|
file.write('s 1\n')
|
||||||
|
else:
|
||||||
|
file.write('s off\n')
|
||||||
|
contextSmooth = f.smooth
|
||||||
|
|
||||||
file.write('f')
|
file.write('f')
|
||||||
if m.hasFaceUV():
|
if m.hasFaceUV():
|
||||||
|
if f.smooth: # Smoothed, use vertex normals
|
||||||
for vi, v in enumerate(f.v):
|
for vi, v in enumerate(f.v):
|
||||||
uvIdx = globalUVCoords[ '%.6f %.6f' % f.uv[vi] ]
|
file.write( ' %d/%d/%d' % (\
|
||||||
i = v.index + totverts + 1
|
v.index+totverts,\
|
||||||
file.write( ' %d/%d/%d' % (i, uvIdx, i)) # vert, uv, normal
|
globalUVCoords[ f.uv[vi] ],\
|
||||||
|
globalNormals[ tuple(v.no) ])) # vert, uv, normal
|
||||||
|
else: # No smoothing, face normals
|
||||||
|
no = globalNormals[ tuple(f.no) ]
|
||||||
|
for vi, v in enumerate(f.v):
|
||||||
|
file.write( ' %d/%d/%d' % (\
|
||||||
|
v.index+totverts,\
|
||||||
|
globalUVCoords[ f.uv[vi] ],\
|
||||||
|
no)) # vert, uv, normal
|
||||||
|
|
||||||
else: # No UV's
|
else: # No UV's
|
||||||
|
if f.smooth: # Smoothed, use vertex normals
|
||||||
for v in f.v:
|
for v in f.v:
|
||||||
file.write( ' %d' % (v.index + totverts+1))
|
file.write( ' %d//%d' % (\
|
||||||
|
v.index+totverts,\
|
||||||
|
globalNormals[ tuple(v.no) ]))
|
||||||
|
else: # No smoothing, face normals
|
||||||
|
no = globalNormals[ tuple(f.no) ]
|
||||||
|
for v in f.v:
|
||||||
|
file.write( ' %d//%d' % (\
|
||||||
|
v.index+totverts,\
|
||||||
|
no))
|
||||||
|
|
||||||
file.write('\n')
|
file.write('\n')
|
||||||
|
|
||||||
# Make the indicies global rather then per mesh
|
# Make the indicies global rather then per mesh
|
||||||
totverts += len(m.verts)
|
totverts += len(m.verts)
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
|
||||||
|
# Now we have all our materials, save them
|
||||||
|
save_mtl(mtlfilename)
|
||||||
|
|
||||||
print "obj export time: %.2f" % (sys.time() - time1)
|
print "obj export time: %.2f" % (sys.time() - time1)
|
||||||
|
|
||||||
Window.FileSelector(save_obj, 'Export Wavefront OBJ', newFName('obj'))
|
Window.FileSelector(save_obj, 'Export Wavefront OBJ', newFName('obj'))
|
||||||
|
|
||||||
|
'''
|
||||||
|
TIME = sys.time()
|
||||||
|
import os
|
||||||
|
OBJDIR = '/obj_out/'
|
||||||
|
for scn in Scene.Get():
|
||||||
|
scn.makeCurrent()
|
||||||
|
obj = OBJDIR + scn.name
|
||||||
|
print obj
|
||||||
|
save_obj(obj)
|
||||||
|
|
||||||
|
print "TOTAL EXPORT TIME: ", sys.time() - TIME
|
||||||
|
'''
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
Name: 'Wavefront (.obj)...'
|
Name: 'Wavefront (.obj)...'
|
||||||
Blender: 237
|
Blender: 237
|
||||||
Group: 'Import'
|
Group: 'Import'
|
||||||
Tooltip: 'Load a Wavefront OBJ File'
|
Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__author__ = "Campbell Barton"
|
__author__ = "Campbell Barton"
|
||||||
@@ -43,14 +43,6 @@ Run this script from "File->Import" menu and then load the desired OBJ file.
|
|||||||
# ***** END GPL LICENCE BLOCK *****
|
# ***** END GPL LICENCE BLOCK *****
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
|
|
||||||
ABORT_MENU = 'Failed Reading OBJ%t|File is probably another type|if not send this file to|cbarton@metavr.com|with MTL and image files for further testing.'
|
|
||||||
|
|
||||||
NULL_MAT = '(null)' # Name for mesh's that have no mat set.
|
|
||||||
NULL_IMG = '(null)' # Name for mesh's that have no mat set.
|
|
||||||
|
|
||||||
MATLIMIT = 16 # This isnt about to change but probably should not be hard coded.
|
|
||||||
|
|
||||||
DIR = ''
|
|
||||||
|
|
||||||
#==============================================#
|
#==============================================#
|
||||||
# Return directory, where the file is #
|
# Return directory, where the file is #
|
||||||
@@ -71,51 +63,242 @@ def stripPath(path):
|
|||||||
# Strips the prefix off the name before writing #
|
# Strips the prefix off the name before writing #
|
||||||
#====================================================#
|
#====================================================#
|
||||||
def stripExt(name): # name is a string
|
def stripExt(name): # name is a string
|
||||||
return name[ : name.rfind('.') ]
|
index = name.rfind('.')
|
||||||
|
if index != -1:
|
||||||
|
return name[ : index ]
|
||||||
|
else:
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
from Blender import *
|
from Blender import *
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Adds a slash to the end of a path if its not there.
|
||||||
|
def addSlash(path):
|
||||||
|
if path.endswith('\\') or path.endswith('/'):
|
||||||
|
return path
|
||||||
|
return path + sys.sep
|
||||||
|
|
||||||
|
|
||||||
|
def getExt(name):
|
||||||
|
index = name.rfind('.')
|
||||||
|
if index != -1:
|
||||||
|
return name[index+1:]
|
||||||
|
return name
|
||||||
|
|
||||||
|
try:
|
||||||
|
import os
|
||||||
|
except:
|
||||||
|
# So we know if os exists.
|
||||||
|
print 'Module "os" not found, install python to enable comprehensive image finding and batch loading.'
|
||||||
|
os = None
|
||||||
|
|
||||||
|
#===========================================================================#
|
||||||
|
# Comprehansive image loader, will search and find the image #
|
||||||
|
# Will return a blender image or none if the image is missing #
|
||||||
|
#===========================================================================#
|
||||||
|
def comprehansiveImageLoad(imagePath, filePath):
|
||||||
|
|
||||||
|
# When we have the file load it with this. try/except niceness.
|
||||||
|
def imageLoad(path):
|
||||||
|
try:
|
||||||
|
img = Image.Load(path)
|
||||||
|
print '\t\tImage loaded "%s"' % path
|
||||||
|
return img
|
||||||
|
except:
|
||||||
|
print '\t\tImage failed loading "%s", mabe its not a format blender can read.' % (path)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Image formats blender can read
|
||||||
|
IMAGE_EXT = ['jpg', 'jpeg', 'png', 'tga', 'bmp', 'rgb', 'sgi', 'bw', 'iff', 'lbm', # Blender Internal
|
||||||
|
'gif', 'psd', 'tif', 'tiff', 'pct', 'pict', 'pntg', 'qtif'] # Quacktime, worth a try.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
print '\tAttempting to load "%s"' % imagePath
|
||||||
|
if sys.exists(imagePath):
|
||||||
|
print '\t\tFile found where expected.'
|
||||||
|
return imageLoad(imagePath)
|
||||||
|
|
||||||
|
imageFileName = stripPath(imagePath) # image path only
|
||||||
|
imageFileName_lower = imageFileName.lower() # image path only
|
||||||
|
imageFileName_noext = stripExt(imageFileName) # With no extension.
|
||||||
|
imageFileName_noext_lower = stripExt(imageFileName_lower) # With no extension.
|
||||||
|
imageFilePath = stripFile(imagePath)
|
||||||
|
|
||||||
|
# Remove relative path from image path
|
||||||
|
if imageFilePath.startswith('./') or imageFilePath.startswith('.\\'):
|
||||||
|
imageFilePath = imageFilePath[2:]
|
||||||
|
|
||||||
|
|
||||||
|
# Attempt to load from obj path.
|
||||||
|
tmpPath = stripFile(filePath) + stripFile(imageFilePath)
|
||||||
|
if sys.exists(tmpPath):
|
||||||
|
print '\t\tFile found in obj dir.'
|
||||||
|
return imageLoad(imagePath)
|
||||||
|
|
||||||
|
# OS NEEDED IF WE GO ANY FURTHER.
|
||||||
|
if not os:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
# We have os.
|
||||||
|
# GATHER PATHS.
|
||||||
|
paths = {} # Store possible paths we may use, dict for no doubles.
|
||||||
|
tmpPath = addSlash(sys.expandpath('//')) # Blenders path
|
||||||
|
if sys.exists(tmpPath):
|
||||||
|
print '\t\tSearching in %s' % tmpPath
|
||||||
|
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||||
|
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||||
|
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||||
|
|
||||||
|
tmpPath = imageFilePath
|
||||||
|
if sys.exists(tmpPath):
|
||||||
|
print '\t\tSearching in %s' % tmpPath
|
||||||
|
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||||
|
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||||
|
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||||
|
|
||||||
|
tmpPath = stripFile(filePath)
|
||||||
|
if sys.exists(tmpPath):
|
||||||
|
print '\t\tSearching in %s' % tmpPath
|
||||||
|
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||||
|
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||||
|
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||||
|
|
||||||
|
tmpPath = addSlash(Get('texturesdir'))
|
||||||
|
if tmpPath and sys.exists(tmpPath):
|
||||||
|
print '\t\tSearching in %s' % tmpPath
|
||||||
|
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||||
|
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||||
|
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||||
|
|
||||||
|
# Add path if relative image patrh was given.
|
||||||
|
for k in paths.iterkeys():
|
||||||
|
tmpPath = k + imageFilePath
|
||||||
|
if sys.exists(tmpPath):
|
||||||
|
paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading
|
||||||
|
paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
|
||||||
|
paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
|
||||||
|
# DONE
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
for path, files in paths.iteritems():
|
||||||
|
|
||||||
|
if sys.exists(path + imageFileName):
|
||||||
|
return imageLoad(path + imageFileName)
|
||||||
|
|
||||||
|
# If the files not there then well do a case insensitive seek.
|
||||||
|
filesOrigCase = files[0]
|
||||||
|
filesLower = files[1]
|
||||||
|
filesLowerNoExt = files[2]
|
||||||
|
|
||||||
|
# We are going to try in index the file directly, if its not there just keep on
|
||||||
|
index = None
|
||||||
|
try:
|
||||||
|
# Is it just a case mismatch?
|
||||||
|
index = filesLower.index(imageFileName_lower)
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
# Have the extensions changed?
|
||||||
|
index = filesLowerNoExt.index(imageFileName_noext_lower)
|
||||||
|
|
||||||
|
ext = getExt( filesLower[index] ) # Get the extension of the file that matches all but ext.
|
||||||
|
|
||||||
|
# Check that the ext is useable eg- not a 3ds file :)
|
||||||
|
if ext.lower() not in IMAGE_EXT:
|
||||||
|
index = None
|
||||||
|
|
||||||
|
except:
|
||||||
|
index = None
|
||||||
|
|
||||||
|
if index != None:
|
||||||
|
tmpPath = path + filesOrigCase[index]
|
||||||
|
img = imageLoad( tmpPath )
|
||||||
|
if img != None:
|
||||||
|
print '\t\tImage Found "%s"' % tmpPath
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
# IMAGE NOT FOUND IN ANY OF THE DIRS!, DO A RECURSIVE SEARCH.
|
||||||
|
print '\t\tImage Not Found in any of the dirs, doing a recusrive search'
|
||||||
|
for path in paths.iterkeys():
|
||||||
|
# Were not going to use files
|
||||||
|
|
||||||
|
|
||||||
|
#------------------
|
||||||
|
# finds the file starting at the root.
|
||||||
|
# def findImage(findRoot, imagePath):
|
||||||
|
#W---------------
|
||||||
|
|
||||||
|
# ROOT, DIRS, FILES
|
||||||
|
pathWalk = os.walk(path)
|
||||||
|
pathList = [True]
|
||||||
|
|
||||||
|
matchList = [] # Store a list of (match, size), choose the biggest.
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
pathList = pathWalk.next()
|
||||||
|
except:
|
||||||
|
break
|
||||||
|
|
||||||
|
for file in pathList[2]:
|
||||||
|
file_lower = file.lower()
|
||||||
|
# FOUND A MATCH
|
||||||
|
if (file_lower == imageFileName_lower) or\
|
||||||
|
(stripExt(file_lower) == imageFileName_noext_lower and getExt(file_lower) in IMAGE_EXT):
|
||||||
|
name = pathList[0] + sys.sep + file
|
||||||
|
size = os.path.getsize(name)
|
||||||
|
print '\t\t\tfound:', name
|
||||||
|
matchList.append( (name, size) )
|
||||||
|
|
||||||
|
if matchList:
|
||||||
|
# Sort by file size
|
||||||
|
matchList.sort(lambda A, B: cmp(B[1], A[1]) )
|
||||||
|
|
||||||
|
print '\t\tFound "%s"' % matchList[0][0]
|
||||||
|
|
||||||
|
# Loop through all we have found
|
||||||
|
img = None
|
||||||
|
for match in matchList:
|
||||||
|
img = imageLoad(match[0]) # 0 - first, 0 - pathname
|
||||||
|
if img != None:
|
||||||
|
break
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# No go.
|
||||||
|
print '\t\tImage Not Found "%s"' % imagePath
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#==================================================================================#
|
#==================================================================================#
|
||||||
# This function sets textures defined in .mtl file #
|
# This function sets textures defined in .mtl file #
|
||||||
#==================================================================================#
|
#==================================================================================#
|
||||||
def getImg(img_fileName, dir):
|
# ___ Replaced by comprehensive imahge get
|
||||||
img_fileName_strip = stripPath(img_fileName)
|
|
||||||
for i in Image.Get():
|
|
||||||
if stripPath(i.filename) == img_fileName_strip:
|
|
||||||
return i
|
|
||||||
|
|
||||||
try: # Absolute dir
|
|
||||||
return Image.Load(img_fileName)
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Relative dir
|
|
||||||
if img_fileName.startswith('/'):
|
|
||||||
img_fileName = img_fileName[1:]
|
|
||||||
elif img_fileName.startswith('./'):
|
|
||||||
img_fileName = img_fileName[2:]
|
|
||||||
elif img_fileName.startswith('\\'):
|
|
||||||
img_fileName = img_fileName[1:]
|
|
||||||
elif img_fileName.startswith('.\\'):
|
|
||||||
img_fileName = img_fileName[2:]
|
|
||||||
|
|
||||||
# if we are this far it means the image hasnt been loaded.
|
|
||||||
try:
|
|
||||||
return Image.Load( dir + img_fileName)
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Its unlikely but the image might be with the OBJ file, and the path provided not relevent.
|
|
||||||
# if the user extracted an archive with no paths this could happen.
|
|
||||||
try:
|
|
||||||
return Image.Load( dir + img_fileName_strip)
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
print '\tunable to open image file: "%s"' % img_fileName
|
|
||||||
return None
|
|
||||||
|
|
||||||
#==================================================================================#
|
#==================================================================================#
|
||||||
# This function sets textures defined in .mtl file #
|
# This function sets textures defined in .mtl file #
|
||||||
@@ -127,7 +310,7 @@ def loadMaterialImage(mat, img_fileName, type, meshDict, dir):
|
|||||||
texture.setType('Image')
|
texture.setType('Image')
|
||||||
|
|
||||||
# Absolute path - c:\.. etc would work here
|
# Absolute path - c:\.. etc would work here
|
||||||
image = getImg(img_fileName, dir)
|
image = comprehansiveImageLoad(img_fileName, dir)
|
||||||
|
|
||||||
if image:
|
if image:
|
||||||
texture.image = image
|
texture.image = image
|
||||||
@@ -135,7 +318,7 @@ def loadMaterialImage(mat, img_fileName, type, meshDict, dir):
|
|||||||
# adds textures to faces (Textured/Alt-Z mode)
|
# adds textures to faces (Textured/Alt-Z mode)
|
||||||
# Only apply the diffuse texture to the face if the image has not been set with the inline usemat func.
|
# Only apply the diffuse texture to the face if the image has not been set with the inline usemat func.
|
||||||
if image and type == 'Kd':
|
if image and type == 'Kd':
|
||||||
for meshPair in meshDict.values():
|
for meshPair in meshDict.itervalues():
|
||||||
for f in meshPair[0].faces:
|
for f in meshPair[0].faces:
|
||||||
#print meshPair[0].materials[f.mat].name, mat.name
|
#print meshPair[0].materials[f.mat].name, mat.name
|
||||||
if meshPair[0].materials[f.mat].name == mat.name:
|
if meshPair[0].materials[f.mat].name == mat.name:
|
||||||
@@ -201,11 +384,11 @@ def load_mtl(dir, mtl_file, meshDict, materialDict):
|
|||||||
elif l[0] == 'newmtl':
|
elif l[0] == 'newmtl':
|
||||||
currentMat = getMat('_'.join(l[1:]), materialDict) # Material should alredy exist.
|
currentMat = getMat('_'.join(l[1:]), materialDict) # Material should alredy exist.
|
||||||
elif l[0] == 'Ka':
|
elif l[0] == 'Ka':
|
||||||
currentMat.setMirCol(float(l[1]), float(l[2]), float(l[3]))
|
currentMat.setMirCol((float(l[1]), float(l[2]), float(l[3])))
|
||||||
elif l[0] == 'Kd':
|
elif l[0] == 'Kd':
|
||||||
currentMat.setRGBCol(float(l[1]), float(l[2]), float(l[3]))
|
currentMat.setRGBCol((float(l[1]), float(l[2]), float(l[3])))
|
||||||
elif l[0] == 'Ks':
|
elif l[0] == 'Ks':
|
||||||
currentMat.setSpecCol(float(l[1]), float(l[2]), float(l[3]))
|
currentMat.setSpecCol((float(l[1]), float(l[2]), float(l[3])))
|
||||||
elif l[0] == 'Ns':
|
elif l[0] == 'Ns':
|
||||||
currentMat.setHardness( int((float(l[1])*0.51)) )
|
currentMat.setHardness( int((float(l[1])*0.51)) )
|
||||||
elif l[0] == 'Ni': # Refraction index
|
elif l[0] == 'Ni': # Refraction index
|
||||||
@@ -238,7 +421,9 @@ def load_mtl(dir, mtl_file, meshDict, materialDict):
|
|||||||
|
|
||||||
lIdx+=1
|
lIdx+=1
|
||||||
except:
|
except:
|
||||||
print '\tERROR: Unable to parse MTL file.'
|
print '\tERROR: Unable to parse MTL file: "%s"' % mtl_file
|
||||||
|
return
|
||||||
|
print '\tUsing MTL: "%s"' % mtl_file
|
||||||
#===========================================================================#
|
#===========================================================================#
|
||||||
# Returns unique name of object/mesh (preserve overwriting existing meshes) #
|
# Returns unique name of object/mesh (preserve overwriting existing meshes) #
|
||||||
#===========================================================================#
|
#===========================================================================#
|
||||||
@@ -262,6 +447,9 @@ def getUniqueName(name):
|
|||||||
# This loads data from .obj file #
|
# This loads data from .obj file #
|
||||||
#==================================================================================#
|
#==================================================================================#
|
||||||
def load_obj(file):
|
def load_obj(file):
|
||||||
|
|
||||||
|
print '\nImporting OBJ file: "%s"' % file
|
||||||
|
|
||||||
time1 = sys.time()
|
time1 = sys.time()
|
||||||
|
|
||||||
# Deselect all objects in the scene.
|
# Deselect all objects in the scene.
|
||||||
@@ -274,7 +462,7 @@ def load_obj(file):
|
|||||||
# Get the file name with no path or .obj
|
# Get the file name with no path or .obj
|
||||||
fileName = stripExt( stripPath(file) )
|
fileName = stripExt( stripPath(file) )
|
||||||
|
|
||||||
mtl_fileName = None
|
mtl_fileName = [] # Support multiple mtl files if needed.
|
||||||
|
|
||||||
DIR = stripFile(file)
|
DIR = stripFile(file)
|
||||||
|
|
||||||
@@ -282,11 +470,11 @@ def load_obj(file):
|
|||||||
fileLines = tempFile.readlines()
|
fileLines = tempFile.readlines()
|
||||||
tempFile.close()
|
tempFile.close()
|
||||||
|
|
||||||
uvMapList = [(0,0)] # store tuple uv pairs here
|
uvMapList = [] # store tuple uv pairs here
|
||||||
|
|
||||||
# This dummy vert makes life a whole lot easier-
|
# This dummy vert makes life a whole lot easier-
|
||||||
# pythons index system then aligns with objs, remove later
|
# pythons index system then aligns with objs, remove later
|
||||||
vertList = [None] # Could havea vert but since this is a placeholder theres no Point
|
vertList = [] # Could havea vert but since this is a placeholder theres no Point
|
||||||
|
|
||||||
|
|
||||||
# Store all imported images in a dict, names are key
|
# Store all imported images in a dict, names are key
|
||||||
@@ -297,7 +485,7 @@ def load_obj(file):
|
|||||||
contextMeshMatIdx = -1
|
contextMeshMatIdx = -1
|
||||||
|
|
||||||
# Keep this out of the dict for easy accsess.
|
# Keep this out of the dict for easy accsess.
|
||||||
nullMat = Material.New(NULL_MAT)
|
nullMat = Material.New('(null)')
|
||||||
|
|
||||||
currentMat = nullMat # Use this mat.
|
currentMat = nullMat # Use this mat.
|
||||||
currentImg = None # Null image is a string, otherwise this should be set to an image object.\
|
currentImg = None # Null image is a string, otherwise this should be set to an image object.\
|
||||||
@@ -320,7 +508,7 @@ def load_obj(file):
|
|||||||
materialDict = {} # Store all imported materials as unique dict, names are key
|
materialDict = {} # Store all imported materials as unique dict, names are key
|
||||||
lIdx = 0
|
lIdx = 0
|
||||||
print '\tfile length: %d' % len(fileLines)
|
print '\tfile length: %d' % len(fileLines)
|
||||||
try:
|
|
||||||
while lIdx < len(fileLines):
|
while lIdx < len(fileLines):
|
||||||
# Ignore vert normals
|
# Ignore vert normals
|
||||||
if fileLines[lIdx].startswith('vn'):
|
if fileLines[lIdx].startswith('vn'):
|
||||||
@@ -368,9 +556,6 @@ def load_obj(file):
|
|||||||
nonVertFileLines.append(l)
|
nonVertFileLines.append(l)
|
||||||
lIdx+=1
|
lIdx+=1
|
||||||
|
|
||||||
except:
|
|
||||||
print Draw.PupMenu(ABORT_MENU)
|
|
||||||
return
|
|
||||||
|
|
||||||
del fileLines
|
del fileLines
|
||||||
fileLines = nonVertFileLines
|
fileLines = nonVertFileLines
|
||||||
@@ -382,7 +567,7 @@ def load_obj(file):
|
|||||||
print '\tfound %d smoothing groups.' % (len(smoothingGroups) -1)
|
print '\tfound %d smoothing groups.' % (len(smoothingGroups) -1)
|
||||||
|
|
||||||
# Add materials to Blender for later is in teh OBJ
|
# Add materials to Blender for later is in teh OBJ
|
||||||
for k in materialDict.keys():
|
for k in materialDict.iterkeys():
|
||||||
materialDict[k] = Material.New(k)
|
materialDict[k] = Material.New(k)
|
||||||
|
|
||||||
|
|
||||||
@@ -419,12 +604,13 @@ def load_obj(file):
|
|||||||
# 0:NMesh, 1:SmoothGroups[UsedVerts[0,0,0,0]], 2:materialMapping['matname':matIndexForThisNMesh]
|
# 0:NMesh, 1:SmoothGroups[UsedVerts[0,0,0,0]], 2:materialMapping['matname':matIndexForThisNMesh]
|
||||||
meshDict[currentObjectName] = (currentMesh, currentUsedVertList, currentMaterialMeshMapping)
|
meshDict[currentObjectName] = (currentMesh, currentUsedVertList, currentMaterialMeshMapping)
|
||||||
|
|
||||||
|
# Only show the bad uv error once
|
||||||
|
badObjUvs = 0
|
||||||
|
badObjFaceVerts = 0
|
||||||
|
badObjFaceTexCo = 0
|
||||||
|
|
||||||
|
|
||||||
|
#currentMesh.verts.append(vertList[0]) # So we can sync with OBJ indicies where 1 is the first item.
|
||||||
|
|
||||||
|
|
||||||
currentMesh.verts.append(vertList[0]) # So we can sync with OBJ indicies where 1 is the first item.
|
|
||||||
if len(uvMapList) > 1:
|
if len(uvMapList) > 1:
|
||||||
currentMesh.hasFaceUV(1) # Turn UV's on if we have ANY texture coords in this obj file.
|
currentMesh.hasFaceUV(1) # Turn UV's on if we have ANY texture coords in this obj file.
|
||||||
|
|
||||||
@@ -432,7 +618,6 @@ def load_obj(file):
|
|||||||
#==================================================================================#
|
#==================================================================================#
|
||||||
# Load all faces into objects, main loop #
|
# Load all faces into objects, main loop #
|
||||||
#==================================================================================#
|
#==================================================================================#
|
||||||
try:
|
|
||||||
lIdx = 0
|
lIdx = 0
|
||||||
# Face and Object loading LOOP
|
# Face and Object loading LOOP
|
||||||
while lIdx < len(fileLines):
|
while lIdx < len(fileLines):
|
||||||
@@ -446,7 +631,7 @@ def load_obj(file):
|
|||||||
if contextMeshMatIdx == -1:
|
if contextMeshMatIdx == -1:
|
||||||
tmpMatLs = currentMesh.materials
|
tmpMatLs = currentMesh.materials
|
||||||
|
|
||||||
if len(tmpMatLs) == MATLIMIT:
|
if len(tmpMatLs) == 16:
|
||||||
contextMeshMatIdx = 0 # Use first material
|
contextMeshMatIdx = 0 # Use first material
|
||||||
print 'material overflow, attempting to use > 16 materials. defaulting to first.'
|
print 'material overflow, attempting to use > 16 materials. defaulting to first.'
|
||||||
else:
|
else:
|
||||||
@@ -459,7 +644,9 @@ def load_obj(file):
|
|||||||
# Start with a dummy objects so python accepts OBJs 1 is the first index.
|
# Start with a dummy objects so python accepts OBJs 1 is the first index.
|
||||||
vIdxLs = []
|
vIdxLs = []
|
||||||
vtIdxLs = []
|
vtIdxLs = []
|
||||||
fHasUV = len(uvMapList)-1 # Assume the face has a UV until it sho it dosent, if there are no UV coords then this will start as 0.
|
|
||||||
|
|
||||||
|
fHasUV = len(uvMapList) # Assume the face has a UV until it sho it dosent, if there are no UV coords then this will start as 0.
|
||||||
for v in l[1:]:
|
for v in l[1:]:
|
||||||
# OBJ files can have // or / to seperate vert/texVert/normal
|
# OBJ files can have // or / to seperate vert/texVert/normal
|
||||||
# this is a bit of a pain but we must deal with it.
|
# this is a bit of a pain but we must deal with it.
|
||||||
@@ -467,15 +654,24 @@ def load_obj(file):
|
|||||||
|
|
||||||
# Vert Index - OBJ supports negative index assignment (like python)
|
# Vert Index - OBJ supports negative index assignment (like python)
|
||||||
|
|
||||||
vIdxLs.append(int(objVert[0]))
|
vIdxLs.append(int(objVert[0])-1)
|
||||||
if fHasUV:
|
if fHasUV:
|
||||||
# UV
|
# UV
|
||||||
|
index = 0 # Dummy var
|
||||||
if len(objVert) == 1:
|
if len(objVert) == 1:
|
||||||
#vtIdxLs.append(int(objVert[0])) # replace with below.
|
index = vIdxLs[-1]
|
||||||
vtIdxLs.append(vIdxLs[-1]) # Sticky UV coords
|
|
||||||
elif objVert[1]: # != '' # Its possible that theres no texture vert just he vert and normal eg 1//2
|
elif objVert[1]: # != '' # Its possible that theres no texture vert just he vert and normal eg 1//2
|
||||||
vtIdxLs.append(int(objVert[1])) # Seperate UV coords
|
index = int(objVert[1])-1
|
||||||
|
|
||||||
|
if len(uvMapList) > index:
|
||||||
|
vtIdxLs.append(index) # Seperate UV coords
|
||||||
else:
|
else:
|
||||||
|
# BAD FILE, I have found this so I account for it.
|
||||||
|
# INVALID UV COORD
|
||||||
|
# Could ignore this- only happens with 1 in 1000 files.
|
||||||
|
badObjFaceTexCo +=1
|
||||||
|
vtIdxLs.append(0)
|
||||||
|
|
||||||
fHasUV = 0
|
fHasUV = 0
|
||||||
|
|
||||||
# Dont add a UV to the face if its larger then the UV coord list
|
# Dont add a UV to the face if its larger then the UV coord list
|
||||||
@@ -484,48 +680,30 @@ def load_obj(file):
|
|||||||
if len(vtIdxLs) > 0:
|
if len(vtIdxLs) > 0:
|
||||||
if vtIdxLs[-1] > len(uvMapList):
|
if vtIdxLs[-1] > len(uvMapList):
|
||||||
fHasUV = 0
|
fHasUV = 0
|
||||||
print 'badly written OBJ file, invalid references to UV Texture coordinates.'
|
|
||||||
|
|
||||||
|
badObjUvs +=1 # ERROR, Cont
|
||||||
# Quads only, we could import quads using the method below but it polite to import a quad as a quad.
|
# Quads only, we could import quads using the method below but it polite to import a quad as a quad.
|
||||||
if len(vIdxLs) == 4:
|
if len(vIdxLs) == 4:
|
||||||
'''
|
|
||||||
f = NMesh.Face()
|
# Have found some files where wach face references the same vert
|
||||||
|
# - This causes a bug and stopts the import so lets check here
|
||||||
|
if vIdxLs[0] == vIdxLs[1] or\
|
||||||
|
vIdxLs[0] == vIdxLs[2] or\
|
||||||
|
vIdxLs[0] == vIdxLs[3] or\
|
||||||
|
vIdxLs[1] == vIdxLs[2] or\
|
||||||
|
vIdxLs[1] == vIdxLs[3] or\
|
||||||
|
vIdxLs[2] == vIdxLs[3]:
|
||||||
|
badObjFaceVerts+=1
|
||||||
|
else:
|
||||||
for i in quadList: # quadList == [0,1,2,3]
|
for i in quadList: # quadList == [0,1,2,3]
|
||||||
if currentUsedVertListSmoothGroup[vIdxLs[i]] == 0:
|
if currentUsedVertListSmoothGroup[vIdxLs[i]] == 0:
|
||||||
v = vertList[vIdxLs[i]]
|
faceQuadVList[i] = vertList[vIdxLs[i]]
|
||||||
currentMesh.verts.append(v)
|
currentMesh.verts.append(faceQuadVList[i])
|
||||||
f.append(v)
|
|
||||||
currentUsedVertListSmoothGroup[vIdxLs[i]] = len(currentMesh.verts)-1
|
currentUsedVertListSmoothGroup[vIdxLs[i]] = len(currentMesh.verts)-1
|
||||||
else:
|
else:
|
||||||
f.v.append(currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[i]]])
|
faceQuadVList[i] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[i]]]
|
||||||
'''
|
|
||||||
if currentUsedVertListSmoothGroup[vIdxLs[0]] == 0:
|
|
||||||
faceQuadVList[0] = vertList[vIdxLs[0]]
|
|
||||||
currentUsedVertListSmoothGroup[vIdxLs[0]] = len(currentMesh.verts)
|
|
||||||
else:
|
|
||||||
faceQuadVList[0] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[0]]]
|
|
||||||
|
|
||||||
if currentUsedVertListSmoothGroup[vIdxLs[1]] == 0:
|
|
||||||
faceQuadVList[1] = vertList[vIdxLs[1]]
|
|
||||||
currentUsedVertListSmoothGroup[vIdxLs[1]] = len(currentMesh.verts)+1
|
|
||||||
else:
|
|
||||||
faceQuadVList[1] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[1]]]
|
|
||||||
|
|
||||||
if currentUsedVertListSmoothGroup[vIdxLs[2]] == 0:
|
|
||||||
faceQuadVList[2] = vertList[vIdxLs[2]]
|
|
||||||
currentUsedVertListSmoothGroup[vIdxLs[2]] = len(currentMesh.verts)+2
|
|
||||||
else:
|
|
||||||
faceQuadVList[2] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[2]]]
|
|
||||||
|
|
||||||
if currentUsedVertListSmoothGroup[vIdxLs[3]] == 0:
|
|
||||||
faceQuadVList[3] = vertList[vIdxLs[3]]
|
|
||||||
currentUsedVertListSmoothGroup[vIdxLs[3]] = len(currentMesh.verts)+3
|
|
||||||
else:
|
|
||||||
faceQuadVList[3] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[3]]]
|
|
||||||
|
|
||||||
currentMesh.verts.extend(faceQuadVList)
|
|
||||||
f = NMesh.Face(faceQuadVList)
|
f = NMesh.Face(faceQuadVList)
|
||||||
|
|
||||||
# UV MAPPING
|
# UV MAPPING
|
||||||
if fHasUV:
|
if fHasUV:
|
||||||
f.uv = [uvMapList[ vtIdxLs[0] ],uvMapList[ vtIdxLs[1] ],uvMapList[ vtIdxLs[2] ],uvMapList[ vtIdxLs[3] ]]
|
f.uv = [uvMapList[ vtIdxLs[0] ],uvMapList[ vtIdxLs[1] ],uvMapList[ vtIdxLs[2] ],uvMapList[ vtIdxLs[3] ]]
|
||||||
@@ -540,41 +718,21 @@ def load_obj(file):
|
|||||||
|
|
||||||
elif len(vIdxLs) >= 3: # This handles tri's and fans
|
elif len(vIdxLs) >= 3: # This handles tri's and fans
|
||||||
for i in range(len(vIdxLs)-2):
|
for i in range(len(vIdxLs)-2):
|
||||||
'''
|
if vIdxLs[0] == vIdxLs[i+1] or\
|
||||||
f = NMesh.Face()
|
vIdxLs[0] == vIdxLs[i+2] or\
|
||||||
for ii in [0, i+1, i+2]:
|
vIdxLs[i+1] == vIdxLs[i+2]:
|
||||||
if currentUsedVertListSmoothGroup[vIdxLs[ii]] == 0:
|
badObjFaceVerts+=1
|
||||||
v = vertList[vIdxLs[ii]]
|
|
||||||
currentMesh.verts.append(v)
|
|
||||||
f.append(v)
|
|
||||||
currentUsedVertListSmoothGroup[vIdxLs[ii]] = len(currentMesh.verts)-1
|
|
||||||
else:
|
else:
|
||||||
f.v.append(currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[ii]]])
|
for k, j in [(0,0), (1,i+1), (2,i+2)]:
|
||||||
'''
|
if currentUsedVertListSmoothGroup[vIdxLs[j]] == 0:
|
||||||
|
faceTriVList[k] = vertList[vIdxLs[j]]
|
||||||
|
currentMesh.verts.append(faceTriVList[k])
|
||||||
if currentUsedVertListSmoothGroup[vIdxLs[0]] == 0:
|
currentUsedVertListSmoothGroup[vIdxLs[j]] = len(currentMesh.verts)-1
|
||||||
faceTriVList[0] = vertList[vIdxLs[0]]
|
|
||||||
currentUsedVertListSmoothGroup[vIdxLs[0]] = len(currentMesh.verts)
|
|
||||||
else:
|
else:
|
||||||
faceTriVList[0] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[0]]]
|
faceTriVList[k] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[j]]]
|
||||||
|
|
||||||
if currentUsedVertListSmoothGroup[vIdxLs[i+1]] == 0:
|
|
||||||
faceTriVList[1] = vertList[vIdxLs[i+1]]
|
|
||||||
currentUsedVertListSmoothGroup[vIdxLs[i+1]] = len(currentMesh.verts)+1
|
|
||||||
else:
|
|
||||||
faceTriVList[1] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[i+1]]]
|
|
||||||
|
|
||||||
if currentUsedVertListSmoothGroup[vIdxLs[i+2]] == 0:
|
|
||||||
faceTriVList[2] = vertList[vIdxLs[i+2]]
|
|
||||||
currentUsedVertListSmoothGroup[vIdxLs[i+2]] = len(currentMesh.verts)+2
|
|
||||||
else:
|
|
||||||
faceTriVList[2] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[i+2]]]
|
|
||||||
|
|
||||||
currentMesh.verts.extend(faceTriVList)
|
|
||||||
f = NMesh.Face(faceTriVList)
|
f = NMesh.Face(faceTriVList)
|
||||||
|
|
||||||
|
|
||||||
# UV MAPPING
|
# UV MAPPING
|
||||||
if fHasUV:
|
if fHasUV:
|
||||||
f.uv = [uvMapList[vtIdxLs[0]], uvMapList[vtIdxLs[i+1]], uvMapList[vtIdxLs[i+2]]]
|
f.uv = [uvMapList[vtIdxLs[0]], uvMapList[vtIdxLs[i+1]], uvMapList[vtIdxLs[i+2]]]
|
||||||
@@ -637,7 +795,7 @@ def load_obj(file):
|
|||||||
|
|
||||||
# If we are new, or we are not yet in the list of added meshes
|
# If we are new, or we are not yet in the list of added meshes
|
||||||
# then make us new mesh.
|
# then make us new mesh.
|
||||||
if len(l) == 1 or currentObjectName not in meshDict.keys():
|
if len(l) == 1 or (not meshDict.has_key(currentObjectName)):
|
||||||
currentMesh = NMesh.GetRaw()
|
currentMesh = NMesh.GetRaw()
|
||||||
|
|
||||||
currentUsedVertList = {}
|
currentUsedVertList = {}
|
||||||
@@ -650,7 +808,6 @@ def load_obj(file):
|
|||||||
|
|
||||||
meshDict[currentObjectName] = (currentMesh, currentUsedVertList, currentMaterialMeshMapping)
|
meshDict[currentObjectName] = (currentMesh, currentUsedVertList, currentMaterialMeshMapping)
|
||||||
currentMesh.hasFaceUV(1)
|
currentMesh.hasFaceUV(1)
|
||||||
currentMesh.verts.append( vertList[0] )
|
|
||||||
contextMeshMatIdx = -1
|
contextMeshMatIdx = -1
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -670,7 +827,7 @@ def load_obj(file):
|
|||||||
|
|
||||||
# MATERIAL
|
# MATERIAL
|
||||||
elif l[0] == 'usemtl':
|
elif l[0] == 'usemtl':
|
||||||
if len(l) == 1 or l[1] == NULL_MAT:
|
if len(l) == 1 or l[1] == '(null)':
|
||||||
currentMat = nullMat # We know we have a null mat.
|
currentMat = nullMat # We know we have a null mat.
|
||||||
else:
|
else:
|
||||||
currentMat = materialDict['_'.join(l[1:])]
|
currentMat = materialDict['_'.join(l[1:])]
|
||||||
@@ -693,7 +850,7 @@ def load_obj(file):
|
|||||||
|
|
||||||
except KeyError: # Not in dict, add for first time.
|
except KeyError: # Not in dict, add for first time.
|
||||||
# Image has not been added, Try and load the image
|
# Image has not been added, Try and load the image
|
||||||
currentImg = getImg(newImgName, DIR) # Use join in case of spaces
|
currentImg = comprehansiveImageLoad(newImgName, DIR) # Use join in case of spaces
|
||||||
imageDict[newImgName] = currentImg
|
imageDict[newImgName] = currentImg
|
||||||
# These may be None, thats okay.
|
# These may be None, thats okay.
|
||||||
|
|
||||||
@@ -701,24 +858,24 @@ def load_obj(file):
|
|||||||
|
|
||||||
# MATERIAL FILE
|
# MATERIAL FILE
|
||||||
elif l[0] == 'mtllib':
|
elif l[0] == 'mtllib':
|
||||||
mtl_fileName = ' '.join(l[1:]) # SHOULD SUPPORT MULTIPLE MTL?
|
mtl_fileName.append(' '.join(l[1:]) ) # SHOULD SUPPORT MULTIPLE MTL?
|
||||||
lIdx+=1
|
lIdx+=1
|
||||||
|
|
||||||
# Applies material properties to materials alredy on the mesh as well as Textures.
|
# Applies material properties to materials alredy on the mesh as well as Textures.
|
||||||
if mtl_fileName:
|
for mtl in mtl_fileName:
|
||||||
load_mtl(DIR, mtl_fileName, meshDict, materialDict)
|
load_mtl(DIR, mtl, meshDict, materialDict)
|
||||||
|
|
||||||
|
|
||||||
importedObjects = []
|
importedObjects = []
|
||||||
for mk in meshDict.keys():
|
for mk, me in meshDict.iteritems():
|
||||||
meshDict[mk][0].verts.pop(0)
|
nme = me[0]
|
||||||
|
|
||||||
# Ignore no vert meshes.
|
# Ignore no vert meshes.
|
||||||
if not meshDict[mk][0].verts:
|
if not nme.verts: # == []
|
||||||
continue
|
continue
|
||||||
|
|
||||||
name = getUniqueName(mk)
|
name = getUniqueName(mk)
|
||||||
ob = NMesh.PutRaw(meshDict[mk][0], name)
|
ob = NMesh.PutRaw(nme, name)
|
||||||
ob.name = name
|
ob.name = name
|
||||||
|
|
||||||
importedObjects.append(ob)
|
importedObjects.append(ob)
|
||||||
@@ -726,37 +883,56 @@ def load_obj(file):
|
|||||||
# Select all imported objects.
|
# Select all imported objects.
|
||||||
for ob in importedObjects:
|
for ob in importedObjects:
|
||||||
ob.sel = 1
|
ob.sel = 1
|
||||||
|
if badObjUvs > 0:
|
||||||
|
print '\tERROR: found %d faces with badly formatted UV coords. everything else went okay.' % badObjUvs
|
||||||
|
|
||||||
|
if badObjFaceVerts > 0:
|
||||||
|
print '\tERROR: found %d faces reusing the same vertex. everything else went okay.' % badObjFaceVerts
|
||||||
|
|
||||||
|
if badObjFaceTexCo > 0:
|
||||||
|
print '\tERROR: found %d faces with invalit texture coords. everything else went okay.' % badObjFaceTexCo
|
||||||
|
|
||||||
|
|
||||||
print "obj import time: ", sys.time() - time1
|
print "obj import time: ", sys.time() - time1
|
||||||
|
|
||||||
except:
|
# Batch directory loading.
|
||||||
print Draw.PupMenu(ABORT_MENU)
|
def load_obj_dir(obj_dir):
|
||||||
return
|
|
||||||
|
|
||||||
|
# Strip file
|
||||||
|
obj_dir = stripFile(obj_dir)
|
||||||
|
time = sys.time()
|
||||||
|
|
||||||
def load_obj_callback(file):
|
objFiles = [f for f in os.listdir(obj_dir) if f.lower().endswith('obj')]
|
||||||
# Try/Fails should realy account for these, but if somthing realy bad happens then Popup error.
|
|
||||||
try:
|
|
||||||
load_obj(file)
|
|
||||||
except:
|
|
||||||
print Draw.PupMenu(ABORT_MENU)
|
|
||||||
|
|
||||||
Window.FileSelector(load_obj_callback, 'Import Wavefront OBJ')
|
Window.DrawProgressBar(0, '')
|
||||||
|
count = 0
|
||||||
|
obj_len = len(objFiles)
|
||||||
|
for obj in objFiles:
|
||||||
|
count+=1
|
||||||
|
|
||||||
# For testing compatibility
|
|
||||||
'''
|
|
||||||
TIME = sys.time()
|
|
||||||
import os
|
|
||||||
for obj in os.listdir('/obj/'):
|
|
||||||
if obj.lower().endswith('obj'):
|
|
||||||
print obj
|
|
||||||
newScn = Scene.New(obj)
|
newScn = Scene.New(obj)
|
||||||
newScn.makeCurrent()
|
newScn.makeCurrent()
|
||||||
load_obj('/obj/' + obj)
|
|
||||||
|
|
||||||
print "TOTAL IMPORT TIME: ", sys.time() - TIME
|
Window.DrawProgressBar((float(count)/obj_len) - 0.01, '%s: %i of %i' % (obj, count, obj_len))
|
||||||
'''
|
|
||||||
#load_obj('/obj/foot_bones.obj')
|
load_obj(obj_dir + obj)
|
||||||
#load_obj('/obj/mba1.obj')
|
|
||||||
#load_obj('/obj/PixZSphere50.OBJ')
|
Window.DrawProgressBar(1, '')
|
||||||
#load_obj('/obj/obj_test/LHand.obj')
|
print 'Total obj import "%s" dir: %.2f' % (obj_dir, sys.time() - time)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
TEXT_IMPORT = 'Import a Wavefront OBJ'
|
||||||
|
TEXT_BATCH_IMPORT = 'Import *.obj to Scenes'
|
||||||
|
|
||||||
|
if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
|
||||||
|
if not os:
|
||||||
|
Draw.PupMenu('Module "os" not found, needed for batch load, using normal selector.')
|
||||||
|
Window.FileSelector(load_obj, TEXT_IMPORT)
|
||||||
|
else:
|
||||||
|
Window.FileSelector(load_obj_dir, TEXT_BATCH_IMPORT)
|
||||||
|
else:
|
||||||
|
Window.FileSelector(load_obj, TEXT_IMPORT)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
#!BPY
|
#!BPY
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Name: 'Bridge/Skin/Loft'
|
Name: 'Bridge Faces/Edge-Loops'
|
||||||
Blender: 234
|
Blender: 237
|
||||||
Group: 'Mesh'
|
Group: 'Mesh'
|
||||||
Tooltip: 'Select 2 or more vert loops, then run this script'
|
Tooltip: 'Select 2 vert loops, then run this script.'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__author__ = "Campbell Barton AKA Ideasman"
|
__author__ = "Campbell Barton AKA Ideasman"
|
||||||
__url__ = ["http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun"]
|
__url__ = ["http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun"]
|
||||||
__version__ = "1.1 2005/06/13"
|
__version__ = "1.0 2004/04/25"
|
||||||
|
|
||||||
__bpydoc__ = """\
|
__bpydoc__ = """\
|
||||||
With this script vertex loops can be skinned: faces are created to connect the
|
With this script vertex loops can be skinned: faces are created to connect the
|
||||||
@@ -19,11 +19,7 @@ Usage:
|
|||||||
|
|
||||||
In mesh Edit mode select the vertices of the loops (closed paths / curves of
|
In mesh Edit mode select the vertices of the loops (closed paths / curves of
|
||||||
vertices: circles, for example) that should be skinned, then run this script.
|
vertices: circles, for example) that should be skinned, then run this script.
|
||||||
A pop-up will provide further options.
|
A pop-up will provide further options, if the results of a method are not adequate try one of the others.
|
||||||
|
|
||||||
Notes:
|
|
||||||
|
|
||||||
If the results of a method chosen from the pop-up are not adequate, undo and try one of the others.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -51,536 +47,443 @@ If the results of a method chosen from the pop-up are not adequate, undo and try
|
|||||||
# ***** END GPL LICENCE BLOCK *****
|
# ***** END GPL LICENCE BLOCK *****
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Made by Ideasman/Campbell 2005/06/15 - ideasman@linuxmail.org
|
||||||
|
|
||||||
# Made by Ideasman/Campbell 2004/04/25 - ideasman@linuxmail.org
|
|
||||||
|
|
||||||
import Blender
|
import Blender
|
||||||
from Blender import *
|
from Blender import *
|
||||||
import math
|
|
||||||
from math import *
|
BIG_NUM = 1<<30
|
||||||
|
|
||||||
|
global CULL_METHOD
|
||||||
|
CULL_METHOD = 0
|
||||||
|
|
||||||
|
class edge:
|
||||||
|
def __init__(self, v1,v2):
|
||||||
|
self.v1 = v1
|
||||||
|
self.v2 = v2
|
||||||
|
|
||||||
|
# uv1 uv2 vcol1 vcol2 # Add later
|
||||||
|
self.length = (v1.co - v2.co).length
|
||||||
|
|
||||||
|
self.removed = 0 # Have we been culled from the eloop
|
||||||
|
self.match = None # The other edge were making a face with
|
||||||
|
|
||||||
|
|
||||||
choice = Draw.PupMenu(\
|
class edgeLoop:
|
||||||
'Loft-loop - shortest edge method|\
|
def __init__(self, loop): # Vert loop
|
||||||
Loft-loop - even method|\
|
# Use next and prev, nextDist, prevDist
|
||||||
Loft-segment - shortest edge|\
|
|
||||||
Loft-segment - even method')
|
|
||||||
|
|
||||||
if choice == 1:
|
# Get Loops centre.
|
||||||
arg='A1'
|
self.centre = Mathutils.Vector()
|
||||||
elif choice == 2:
|
f = 1.0/len(loop)
|
||||||
arg='A2'
|
for v in loop:
|
||||||
elif choice == 3:
|
self.centre += v.co * f
|
||||||
arg='B1'
|
|
||||||
elif choice == 4:
|
|
||||||
arg='B2'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#================#
|
|
||||||
# Math functions #
|
|
||||||
#================#
|
|
||||||
|
|
||||||
# Measure 2 points
|
# Convert Vert loop to Edges.
|
||||||
def measure(v1, v2):
|
self.edges = []
|
||||||
return Mathutils.Vector([v1[0]-v2[0], v1[1] - v2[1], v1[2] - v2[2]]).length
|
vIdx = 0
|
||||||
|
while vIdx < len(loop):
|
||||||
|
self.edges.append( edge(loop[vIdx-1], loop[vIdx]) )
|
||||||
|
vIdx += 1
|
||||||
|
|
||||||
# Clamp
|
# Assign linked list
|
||||||
def clamp(max, number):
|
for eIdx in range(len(self.edges)-1):
|
||||||
while number >= max:
|
self.edges[eIdx].next = self.edges[eIdx+1]
|
||||||
number = number - max
|
self.edges[eIdx].prev = self.edges[eIdx-1]
|
||||||
return number
|
# Now last
|
||||||
|
self.edges[-1].next = self.edges[0]
|
||||||
#=============================================================#
|
self.edges[-1].prev = self.edges[-2]
|
||||||
# List func that takes the last item and adds it to the front #
|
|
||||||
#=============================================================#
|
|
||||||
def listRotate(ls):
|
|
||||||
ls.append(ls.pop(0))
|
|
||||||
|
|
||||||
#=================================================================#
|
|
||||||
# Recieve a list of locs: [x,y,z] and return the average location #
|
|
||||||
#=================================================================#
|
|
||||||
def averageLocation(locList):
|
|
||||||
avLoc = [0,0,0]
|
|
||||||
|
|
||||||
# Loop through x/y/z
|
|
||||||
for coordIdx in [0,1,2]:
|
|
||||||
|
|
||||||
# Add all the values from 1 of the 3 coords at the avLoc.
|
|
||||||
for loc in locList:
|
|
||||||
avLoc[coordIdx] += loc[coordIdx]
|
|
||||||
|
|
||||||
avLoc[coordIdx] = avLoc[coordIdx] / len(locList)
|
|
||||||
return avLoc
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#=============================#
|
# GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP.
|
||||||
# Blender functions/shortcuts #
|
self.normal = Mathutils.Vector()
|
||||||
#=============================#
|
for e in self.edges:
|
||||||
def error(str):
|
n = Mathutils.CrossVecs(self.centre-e.v1.co, self.centre-e.v2.co)
|
||||||
Draw.PupMenu('ERROR%t|'+str)
|
# Do we realy need tot normalize?
|
||||||
|
n.normalize()
|
||||||
# Returns a new face that has the same properties as the origional face
|
self.normal += n
|
||||||
# With no verts though
|
self.normal.normalize()
|
||||||
def copyFace(face):
|
|
||||||
newFace = NMesh.Face()
|
|
||||||
# Copy some generic properties
|
|
||||||
newFace.mode = face.mode
|
|
||||||
if face.image != None:
|
|
||||||
newFace.image = face.image
|
|
||||||
newFace.flag = face.flag
|
|
||||||
newFace.mat = face.mat
|
|
||||||
newFace.smooth = face.smooth
|
|
||||||
return newFace
|
|
||||||
|
|
||||||
#=============================================#
|
|
||||||
# Find a selected vert that 2 faces share. #
|
|
||||||
#=============================================#
|
|
||||||
def selVertBetween2Faces(face1, face2):
|
|
||||||
for v1 in face1.v:
|
|
||||||
if v1.sel:
|
|
||||||
for v2 in face2.v:
|
|
||||||
if v1 == v2:
|
|
||||||
return v1
|
|
||||||
|
|
||||||
|
|
||||||
#=======================================================#
|
# Generate a normal for each edge.
|
||||||
# Measure the total distance between all the edges in #
|
for e in self.edges:
|
||||||
# 2 vertex loops #
|
|
||||||
#=======================================================#
|
|
||||||
def measureVloop(mesh, v1loop, v2loop, surplusFaces, bestSoFar):
|
|
||||||
totalDist = 0
|
|
||||||
|
|
||||||
# Rotate the vertloops to cycle through each pair.
|
n1 = e.v1.co
|
||||||
# of faces to compate the distance between the 2 poins
|
n2 = e.v2.co
|
||||||
for ii in range(len(v1loop)):
|
n3 = e.prev.v1.co
|
||||||
if ii not in surplusFaces:
|
|
||||||
# Clamp
|
|
||||||
v2clampii = ii
|
|
||||||
while v2clampii >= len(v2loop):
|
|
||||||
v2clampii -= len(v2loop)
|
|
||||||
print v2clampii
|
|
||||||
|
|
||||||
V1 = selVertBetween2Faces(mesh.faces[v1loop[ii-1]], mesh.faces[v1loop[ii]])
|
a = n1-n2
|
||||||
V2 = selVertBetween2Faces(mesh.faces[v2loop[v2clampii-1]], mesh.faces[v2loop[v2clampii]])
|
b = n1-n3
|
||||||
|
normal1 = Mathutils.CrossVecs(a,b)
|
||||||
|
normal1.normalize()
|
||||||
|
|
||||||
totalDist += measure(V1, V2)
|
n1 = e.v2.co
|
||||||
# Bail out early if not an improvement on previously measured.
|
n3 = e.next.v2.co
|
||||||
if bestSoFar != None and totalDist > bestSoFar:
|
n2 = e.v1.co
|
||||||
return totalDist
|
|
||||||
|
|
||||||
#selVertBetween2Faces(mesh.faces[v2loop[0]], mesh.faces[v2loop[1]])
|
a = n1-n2
|
||||||
return totalDist
|
b = n1-n3
|
||||||
|
|
||||||
# Remove the shortest edge from a vert loop
|
normal2 = Mathutils.CrossVecs(a,b)
|
||||||
def removeSmallestFace(mesh, vloop):
|
normal2.normalize()
|
||||||
bestDistSoFar = None
|
|
||||||
bestFIdxSoFar = None
|
|
||||||
for fIdx in vloop:
|
|
||||||
vSelLs = []
|
|
||||||
for v in mesh.faces[fIdx].v:
|
|
||||||
if v.sel:
|
|
||||||
vSelLs.append(v)
|
|
||||||
|
|
||||||
dist = measure(vSelLs[0].co, vSelLs[1].co)
|
# Reuse normal1 var
|
||||||
|
normal1 += normal1 + normal2
|
||||||
|
normal1.normalize()
|
||||||
|
|
||||||
if bestDistSoFar == None:
|
e.normal = normal1
|
||||||
bestDistSoFar = dist
|
#print e.normal
|
||||||
bestFIdxSoFar = fIdx
|
|
||||||
elif dist < bestDistSoFar:
|
|
||||||
bestDistSoFar = dist
|
|
||||||
bestFIdxSoFar = fIdx
|
|
||||||
|
|
||||||
# Return the smallest face index of the vloop that was sent
|
|
||||||
return bestFIdxSoFar
|
|
||||||
|
|
||||||
|
|
||||||
#=============================================#
|
|
||||||
# Take 2 vert loops and skin them #
|
|
||||||
#=============================================#
|
|
||||||
def skinVertLoops(mesh, v1loop, v2loop):
|
|
||||||
|
|
||||||
|
|
||||||
#=============================================#
|
def backup(self):
|
||||||
# Handle uneven vert loops, this is tricky #
|
# Keep a backup of the edges
|
||||||
#=============================================#
|
self.backupEdges = self.edges[:]
|
||||||
# Reorder so v1loop is always the biggest
|
|
||||||
if len(v1loop) < len(v2loop):
|
|
||||||
v1loop, v2loop = v2loop, v1loop
|
|
||||||
|
|
||||||
# Work out if the vert loops are equel or not, if not remove the extra faces from the larger
|
def restore(self):
|
||||||
surplusFaces = []
|
self.edges = self.backupEdges[:]
|
||||||
tempv1loop = v1loop[:] # strip faces off this one, use it to keep track of which we have taken faces from.
|
for e in self.edges:
|
||||||
if len(v1loop) > len(v2loop):
|
e.removed = 0
|
||||||
|
|
||||||
# Even face method.
|
def reverse(self):
|
||||||
if arg[1] == '2':
|
self.edges.reverse()
|
||||||
remIdx = 0
|
for e in self.edges:
|
||||||
faceStepping = len( v1loop) / len(v2loop)
|
e.normal = -e.normal
|
||||||
while len(v1loop) - len(surplusFaces) > len(v2loop):
|
e.v1, e.v2 = e.v2, e.v1
|
||||||
remIdx += faceStepping
|
self.normal = -self.normal
|
||||||
surplusFaces.append(tempv1loop[ clamp(len(tempv1loop),remIdx) ])
|
|
||||||
tempv1loop.remove(surplusFaces[-1])
|
|
||||||
|
|
||||||
# Shortest face
|
# Removes N Smallest edges and backs up
|
||||||
elif arg[1] == '1':
|
def removeSmallest(self, cullNum, otherLoopLen):
|
||||||
while len(v1loop) - len(surplusFaces) > len(v2loop):
|
global CULL_METHOD
|
||||||
surplusFaces.append(removeSmallestFace(mesh, tempv1loop))
|
if CULL_METHOD == 0: # Shortest edge
|
||||||
tempv1loop.remove(surplusFaces[-1])
|
|
||||||
|
eloopCopy = self.edges[:]
|
||||||
|
eloopCopy.sort(lambda e1, e2: cmp(e1.length, e2.length )) # Length sort, smallest first
|
||||||
|
eloopCopy = eloopCopy[:cullNum]
|
||||||
|
for e in eloopCopy:
|
||||||
|
e.removed = 1
|
||||||
|
self.edges.remove( e ) # Remove from own list, still in linked list.
|
||||||
|
|
||||||
|
else: # CULL METHOD is even
|
||||||
|
|
||||||
|
culled = 0
|
||||||
|
|
||||||
|
step = int(otherLoopLen / float(cullNum))
|
||||||
|
|
||||||
|
currentEdge = self.edges[0]
|
||||||
|
while culled < cullNum:
|
||||||
|
|
||||||
|
# Get the shortest face in the next STEP
|
||||||
|
while currentEdge.removed == 1:
|
||||||
|
# Bug here!
|
||||||
|
currentEdge = currentEdge.next
|
||||||
|
smallestEdge = currentEdge
|
||||||
|
|
||||||
|
for i in range(step):
|
||||||
|
currentEdge = currentEdge.next
|
||||||
|
while currentEdge.removed == 1:
|
||||||
|
currentEdge = currentEdge.next
|
||||||
|
if smallestEdge.length > currentEdge.length:
|
||||||
|
smallestEdge = currentEdge
|
||||||
|
|
||||||
|
# In that stepping length we have the smallest edge.remove it
|
||||||
|
smallestEdge.removed = 1
|
||||||
|
self.edges.remove(smallestEdge)
|
||||||
|
|
||||||
|
culled+=1
|
||||||
|
|
||||||
|
|
||||||
tempv1loop = None
|
# Returns face edges.
|
||||||
|
# face must have edge data.
|
||||||
v2loop = optimizeLoopOrdedShortEdge(mesh, v1loop, v2loop, surplusFaces)
|
def faceEdges(me, f):
|
||||||
|
if len(f) == 3:
|
||||||
# make Faces from
|
return [\
|
||||||
lenVloop = len(v1loop)
|
me.findEdge(f[0], f[1]),\
|
||||||
lenSupFaces = len(surplusFaces)
|
me.findEdge(f[1], f[2]),\
|
||||||
fIdx = 0
|
me.findEdge(f[2], f[0])\
|
||||||
offset = 0
|
]
|
||||||
while fIdx < lenVloop:
|
elif len(f) == 4:
|
||||||
|
return [\
|
||||||
face = copyFace( mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]] )
|
me.findEdge(f[0], f[1]),\
|
||||||
|
me.findEdge(f[1], f[2]),\
|
||||||
if v1loop[fIdx] in surplusFaces:
|
me.findEdge(f[2], f[3]),\
|
||||||
# Draw a try, this face does not catch with an edge.
|
me.findEdge(f[3], f[0])\
|
||||||
# So we must draw a tri and wedge it in.
|
]
|
||||||
|
|
||||||
# Copy old faces properties
|
|
||||||
|
|
||||||
face.v.append( selVertBetween2Faces(\
|
|
||||||
mesh.faces[v1loop[clamp(lenVloop, fIdx)]],\
|
|
||||||
mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]]) )
|
|
||||||
|
|
||||||
face.v.append( selVertBetween2Faces(\
|
|
||||||
mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]],\
|
|
||||||
mesh.faces[v1loop[clamp(lenVloop, fIdx+2)]]) )
|
|
||||||
|
|
||||||
#face.v.append( selVertBetween2Faces(\
|
|
||||||
#mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset +1 ))]],\
|
|
||||||
#mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset + 2))]]) )
|
|
||||||
|
|
||||||
face.v.append( selVertBetween2Faces(\
|
|
||||||
mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset))]],\
|
|
||||||
mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, fIdx - offset + 1)]]) )
|
|
||||||
|
|
||||||
mesh.faces.append(face)
|
|
||||||
|
|
||||||
# We need offset to work out how much smaller v2loop is at this current index.
|
|
||||||
offset+=1
|
|
||||||
|
|
||||||
|
|
||||||
|
def getSelectedEdges(me, ob):
|
||||||
|
SEL_FLAG = NMesh.EdgeFlags['SELECT']
|
||||||
|
FGON_FLAG = NMesh.EdgeFlags['FGON']
|
||||||
|
|
||||||
|
edges = [e for e in me.edges if e.flag & SEL_FLAG if (e.flag & FGON_FLAG) == 0 ]
|
||||||
|
|
||||||
|
# Now remove edges that face 2 or more selected faces usoing them
|
||||||
|
edgeFromSelFaces = []
|
||||||
|
for f in me.faces:
|
||||||
|
if len(f) >2 and f.sel:
|
||||||
|
edgeFromSelFaces.extend(faceEdges(me, f))
|
||||||
|
|
||||||
|
# Remove all edges with 2 or more selected faces as uses.
|
||||||
|
for e in edgeFromSelFaces:
|
||||||
|
if edgeFromSelFaces.count(e) > 1:
|
||||||
|
me.removeEdge(e.v1, e.v2)
|
||||||
|
|
||||||
|
# Remove selected faces?
|
||||||
|
fIdx = len(me.faces)
|
||||||
|
while fIdx:
|
||||||
|
fIdx-=1
|
||||||
|
if len(me.faces[fIdx]) > 2:
|
||||||
|
if me.faces[fIdx].sel:
|
||||||
|
me.faces.pop(fIdx)
|
||||||
|
return [e for e in edges if edgeFromSelFaces.count(e) < 2]
|
||||||
|
|
||||||
|
|
||||||
|
# Like vert loops
|
||||||
|
def getVertLoops(selEdges):
|
||||||
|
mainVertLoops = []
|
||||||
|
while selEdges:
|
||||||
|
e = selEdges.pop()
|
||||||
|
contextVertLoop= [e.v1, e.v2] # start the vert loop
|
||||||
|
|
||||||
|
eIdx = 1 # Get us into the loop. dummy var.
|
||||||
|
|
||||||
|
# if eIdx == 0 then it means we searched and found no matches...
|
||||||
|
# time for a new vert loop,
|
||||||
|
while eIdx:
|
||||||
|
eIdx = len(selEdges)
|
||||||
|
while eIdx:
|
||||||
|
eIdx-=1
|
||||||
|
|
||||||
|
# Check for edge attached at the head of the loop.
|
||||||
|
if contextVertLoop[0] == selEdges[eIdx].v1:
|
||||||
|
contextVertLoop.insert(0, selEdges.pop(eIdx).v2)
|
||||||
|
elif contextVertLoop[0] == selEdges[eIdx].v2:
|
||||||
|
contextVertLoop.insert(0, selEdges.pop(eIdx).v1)
|
||||||
|
|
||||||
|
# Chech for edge vert at the tail.
|
||||||
|
elif contextVertLoop[-1] == selEdges[eIdx].v1:
|
||||||
|
contextVertLoop.append(selEdges.pop(eIdx).v2)
|
||||||
|
elif contextVertLoop[-1] == selEdges[eIdx].v2:
|
||||||
|
contextVertLoop.append(selEdges.pop(eIdx).v1)
|
||||||
else:
|
else:
|
||||||
# Draw a normal quad between the 2 edges/faces
|
# None found? Keep looking
|
||||||
|
continue
|
||||||
|
|
||||||
face.v.append( selVertBetween2Faces(\
|
# Once found we.
|
||||||
mesh.faces[v1loop[clamp(lenVloop, fIdx)]],\
|
|
||||||
mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]]) )
|
|
||||||
|
|
||||||
face.v.append( selVertBetween2Faces(\
|
|
||||||
mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]],\
|
|
||||||
mesh.faces[v1loop[clamp(lenVloop, fIdx+2)]]) )
|
|
||||||
|
|
||||||
face.v.append( selVertBetween2Faces(\
|
|
||||||
mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset +1 ))]],\
|
|
||||||
mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset + 2))]]) )
|
|
||||||
|
|
||||||
face.v.append( selVertBetween2Faces(\
|
|
||||||
mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset))]],\
|
|
||||||
mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, fIdx - offset + 1)]]) )
|
|
||||||
|
|
||||||
mesh.faces.append(face)
|
|
||||||
|
|
||||||
fIdx +=1
|
|
||||||
|
|
||||||
return mesh
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#=======================================================#
|
|
||||||
# Takes a face and returns the number of selected verts #
|
|
||||||
#=======================================================#
|
|
||||||
def faceVSel(face):
|
|
||||||
vSel = 0
|
|
||||||
for v in face.v:
|
|
||||||
if v.sel:
|
|
||||||
vSel +=1
|
|
||||||
return vSel
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#================================================================#
|
|
||||||
# This function takes a face and returns its selected vert loop #
|
|
||||||
# it returns a list of face indicies
|
|
||||||
#================================================================#
|
|
||||||
def vertLoop(mesh, startFaceIdx, fIgLs): # fIgLs is a list of faces to ignore.
|
|
||||||
# Here we store the faces indicies that
|
|
||||||
# are a part of the first vertex loop
|
|
||||||
vertLoopLs = [startFaceIdx]
|
|
||||||
|
|
||||||
restart = 0
|
|
||||||
while restart == 0:
|
|
||||||
# this keeps the face loop going until its told to stop,
|
|
||||||
# If the face loop does not find an adjacent face then the vert loop has been compleated
|
|
||||||
restart = 1
|
|
||||||
|
|
||||||
# Get my selected verts for the active face/edge.
|
|
||||||
selVerts = []
|
|
||||||
for v in mesh.faces[vertLoopLs[-1]].v:
|
|
||||||
selVerts.append(v)
|
|
||||||
|
|
||||||
fIdx = 0
|
|
||||||
while fIdx < len(mesh.faces) and restart:
|
|
||||||
# Not already added to the vert list
|
|
||||||
if fIdx not in fIgLs + vertLoopLs:
|
|
||||||
# Has 2 verts selected
|
|
||||||
if faceVSel(mesh.faces[fIdx]) > 1:
|
|
||||||
# Now we need to find if any of the selected verts
|
|
||||||
# are shared with our active face. (are we next to ActiveFace)
|
|
||||||
for v in mesh.faces[fIdx].v:
|
|
||||||
if v in selVerts:
|
|
||||||
vertLoopLs.append(fIdx)
|
|
||||||
restart = 0 # restart the face loop.
|
|
||||||
break
|
break
|
||||||
|
|
||||||
fIdx +=1
|
# Is this a loop? if so then its forst and last vert must be teh same.
|
||||||
|
if contextVertLoop[0].index == contextVertLoop[-1].index:
|
||||||
|
contextVertLoop.pop() # remove double vert
|
||||||
|
mainVertLoops.append(contextVertLoop)
|
||||||
|
|
||||||
return vertLoopLs
|
# Build context vert loops
|
||||||
|
return mainVertLoops
|
||||||
|
|
||||||
|
|
||||||
|
def skin2EdgeLoops(eloop1, eloop2, me, ob, MODE):
|
||||||
|
# Make sure e1 loops is bigger then e2
|
||||||
|
if len(eloop1.edges) != len(eloop2.edges):
|
||||||
|
if len(eloop1.edges) < len(eloop2.edges):
|
||||||
|
eloop1, eloop2 = eloop2, eloop1
|
||||||
|
|
||||||
|
eloop1.backup() # were about to cull faces
|
||||||
|
CULL_FACES = len(eloop1.edges) - len(eloop2.edges)
|
||||||
|
eloop1.removeSmallest(CULL_FACES, len(eloop1.edges))
|
||||||
|
else:
|
||||||
|
CULL_FACES = 0
|
||||||
|
# First make sure poly vert loops are in sync with eachother.
|
||||||
|
|
||||||
|
# The vector allong which we are skinning.
|
||||||
|
skinVector = eloop1.centre - eloop2.centre
|
||||||
|
|
||||||
|
loopDist = skinVector.length
|
||||||
|
|
||||||
|
|
||||||
#================================================================#
|
# IS THE LOOP FLIPPED, IF SO FLIP BACK.
|
||||||
# Now we work out the optimum order to 'skin' the 2 vert loops #
|
angleBetweenLoopNormals = Mathutils.AngleBetweenVecs(eloop1.normal, eloop2.normal)
|
||||||
# by measuring the total distance of all edges created, #
|
|
||||||
# test this for every possible series of joins #
|
|
||||||
# and find the shortest, Once this is done the #
|
|
||||||
# shortest dist can be skinned. #
|
|
||||||
# returns only the 2nd-reordered vert loop #
|
|
||||||
#================================================================#
|
|
||||||
def optimizeLoopOrded(mesh, v1loop, v2loop):
|
|
||||||
bestSoFar = None
|
|
||||||
|
|
||||||
# Measure the dist, ii is just a counter
|
if angleBetweenLoopNormals > 90:
|
||||||
for ii in range(len(v1loop)):
|
eloop2.reverse()
|
||||||
|
|
||||||
# Loop twice , Once for the forward test, and another for the revearsed
|
|
||||||
for iii in [None, None]:
|
|
||||||
dist = measureVloop(mesh, v1loop, v2loop, bestSoFar)
|
|
||||||
# Initialize the Best distance recorded
|
|
||||||
if bestSoFar == None or dist < bestSoFar:
|
|
||||||
bestSoFar = dist
|
|
||||||
bestv2Loop = v2loop[:]
|
|
||||||
|
|
||||||
# We might have got the vert loop backwards, try the other way
|
|
||||||
v2loop.reverse()
|
|
||||||
listRotate(v2loop)
|
|
||||||
return bestv2Loop
|
|
||||||
|
|
||||||
|
|
||||||
#================================================================#
|
bestEloopDist = BIG_NUM
|
||||||
# Now we work out the optimum order to 'skin' the 2 vert loops #
|
bestOffset = 0
|
||||||
# by measuring the total distance of all edges created, #
|
# Loop rotation offset to test.1
|
||||||
# test this for every possible series of joins #
|
eLoopIdxs = range(len(eloop1.edges))
|
||||||
# and find the shortest, Once this is done the #
|
for offset in range(len(eloop1.edges)):
|
||||||
# shortest dist can be skinned. #
|
totEloopDist = 0 # Measure this total distance for thsi loop.
|
||||||
# returns only the 2nd-reordered vert loop #
|
|
||||||
#================================================================#
|
|
||||||
def optimizeLoopOrdedShortEdge(mesh, v1loop, v2loop, surplusFaces):
|
|
||||||
bestSoFar = None
|
|
||||||
|
|
||||||
# Measure the dist, ii is just a counter
|
offsetIndexLs = eLoopIdxs[offset:] + eLoopIdxs[:offset] # Make offset index list
|
||||||
for ii in range(len(v2loop)):
|
|
||||||
|
|
||||||
# Loop twice , Once for the forward test, and another for the revearsed
|
# e1Idx is always from 0 to N, e2Idx is offset.
|
||||||
for iii in [None, None]:
|
for e1Idx, e2Idx in enumerate(offsetIndexLs):
|
||||||
dist = measureVloop(mesh, v1loop, v2loop, surplusFaces, bestSoFar)
|
# Measure the vloop distance ===============
|
||||||
print 'dist', dist
|
totEloopDist += ((eloop1.edges[e1Idx].v1.co - eloop2.edges[e2Idx].v1.co).length / loopDist) #/ nangle1
|
||||||
# Initialize the Best distance recorded
|
totEloopDist += ((eloop1.edges[e1Idx].v2.co - eloop2.edges[e2Idx].v2.co).length / loopDist) #/ nangle1
|
||||||
if bestSoFar == None or dist < bestSoFar:
|
|
||||||
bestSoFar = dist
|
|
||||||
bestv2Loop = v2loop[:]
|
|
||||||
|
|
||||||
|
# Premeture break if where no better off
|
||||||
# We might have got the vert loop backwards, try the other way
|
if totEloopDist > bestEloopDist:
|
||||||
v2loop.reverse()
|
|
||||||
#v2loop = listRotate(v2loop)
|
|
||||||
listRotate(v2loop)
|
|
||||||
print 'best so far ', bestSoFar
|
|
||||||
return bestv2Loop
|
|
||||||
|
|
||||||
|
|
||||||
#==============================#
|
|
||||||
# Find our vert loop list #
|
|
||||||
#==============================#
|
|
||||||
# Find a face with 2 verts selected,
|
|
||||||
#this will be the first face in out vert loop
|
|
||||||
def findVertLoop(mesh, fIgLs): # fIgLs is a list of faces to ignore.
|
|
||||||
|
|
||||||
startFaceIdx = None
|
|
||||||
|
|
||||||
fIdx = 0
|
|
||||||
while fIdx < len(mesh.faces):
|
|
||||||
if fIdx not in fIgLs:
|
|
||||||
# Do we have an edge?
|
|
||||||
if faceVSel(mesh.faces[fIdx]) > 1:
|
|
||||||
# THIS IS THE STARTING FACE.
|
|
||||||
startFaceIdx = fIdx
|
|
||||||
break
|
break
|
||||||
fIdx+=1
|
|
||||||
|
|
||||||
# Here we access the function that generates the real vert loop
|
if totEloopDist < bestEloopDist:
|
||||||
if startFaceIdx != None:
|
bestOffset = offset
|
||||||
return vertLoop(mesh, startFaceIdx, fIgLs)
|
bestEloopDist = totEloopDist
|
||||||
|
|
||||||
|
# Modify V2 LS for Best offset
|
||||||
|
eloop2.edges = eloop2.edges[bestOffset:] + eloop2.edges[:bestOffset]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for loopIdx in range(len(eloop2.edges)):
|
||||||
|
e1 = eloop1.edges[loopIdx]
|
||||||
|
e2 = eloop2.edges[loopIdx]
|
||||||
|
|
||||||
|
# Remember the pairs for fan filling culled edges.
|
||||||
|
e1.match = e2; e2.match = e1
|
||||||
|
|
||||||
|
# need some smart face flipping code here.
|
||||||
|
f = NMesh.Face([e1.v1, e1.v2, e2.v2, e2.v1])
|
||||||
|
|
||||||
|
f.sel = 1
|
||||||
|
me.faces.append(f)
|
||||||
|
|
||||||
|
# FAN FILL MISSING FACES.
|
||||||
|
if CULL_FACES:
|
||||||
|
# Culled edges will be in eloop1.
|
||||||
|
FAN_FILLED_FACES = 0
|
||||||
|
|
||||||
|
contextEdge = eloop1.edges[0] # The larger of teh 2
|
||||||
|
while FAN_FILLED_FACES < CULL_FACES:
|
||||||
|
while contextEdge.next.removed == 0:
|
||||||
|
contextEdge = contextEdge.next
|
||||||
|
|
||||||
|
vertFanPivot = contextEdge.match.v2
|
||||||
|
|
||||||
|
while contextEdge.next.removed == 1:
|
||||||
|
|
||||||
|
f = NMesh.Face([contextEdge.next.v1, contextEdge.next.v2, vertFanPivot] )
|
||||||
|
|
||||||
|
|
||||||
|
f.sel = 1
|
||||||
|
me.faces.append(f)
|
||||||
|
|
||||||
|
# Should we use another var?, this will work for now.
|
||||||
|
contextEdge.next.removed = 1
|
||||||
|
|
||||||
|
contextEdge = contextEdge.next
|
||||||
|
FAN_FILLED_FACES += 1
|
||||||
|
|
||||||
|
eloop1.restore() # Add culled back into the list.
|
||||||
|
#if angleBetweenLoopNormals > 90:
|
||||||
|
# eloop2.reverse()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
global CULL_METHOD
|
||||||
|
|
||||||
|
is_editmode = Window.EditMode()
|
||||||
|
if is_editmode: Window.EditMode(0)
|
||||||
|
ob = Scene.GetCurrent().getActiveObject()
|
||||||
|
if ob == None or ob.getType() != 'Mesh':
|
||||||
|
return
|
||||||
|
|
||||||
|
me = ob.getData()
|
||||||
|
if not me.edges:
|
||||||
|
Draw.PupMenu('Error, add edge data first')
|
||||||
|
if is_editmode: Window.EditMode(1)
|
||||||
|
return
|
||||||
|
|
||||||
|
# BAD BLENDER PYTHON API, NEED TO ENTER EXIT EDIT MODE FOR ADDING EDGE DATA.
|
||||||
|
# ADD EDGE DATA HERE, Python API CANT DO IT YET, LOOSES SELECTION
|
||||||
|
|
||||||
|
selEdges = getSelectedEdges(me, ob)
|
||||||
|
vertLoops = getVertLoops(selEdges) # list of lists of edges.
|
||||||
|
|
||||||
|
if len(vertLoops) > 2:
|
||||||
|
choice = Draw.PupMenu('Loft '+str(len(vertLoops))+' edge loops%t|loop|segment')
|
||||||
|
if choice == -1:
|
||||||
|
if is_editmode: Window.EditMode(1)
|
||||||
|
return
|
||||||
|
elif len(vertLoops) < 2:
|
||||||
|
Draw.PupMenu('Error, No Vertloops found%t|if you have a valid selection, go in and out of face edit mode to update the selection state.')
|
||||||
|
if is_editmode: Window.EditMode(1)
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
# We are out'a vert loops, return a None,
|
choice = 2
|
||||||
return None
|
|
||||||
|
|
||||||
#===================================#
|
|
||||||
# Get the average loc of a vertloop #
|
|
||||||
# This is used when working out the #
|
|
||||||
# order to loft an object #
|
|
||||||
#===================================#
|
|
||||||
def vLoopAverageLoc(mesh, vertLoop):
|
|
||||||
locList = [] # List of vert locations
|
|
||||||
|
|
||||||
fIdx = 0
|
|
||||||
while fIdx < len(mesh.faces):
|
|
||||||
if fIdx in vertLoop:
|
|
||||||
for v in mesh.faces[fIdx].v:
|
|
||||||
if v.sel:
|
|
||||||
locList.append(v.co)
|
|
||||||
fIdx+=1
|
|
||||||
|
|
||||||
return averageLocation(locList)
|
|
||||||
|
|
||||||
|
|
||||||
|
# The line below checks if any of the vert loops are differenyt in length.
|
||||||
|
if False in [len(v) == len(vertLoops[0]) for v in vertLoops]:
|
||||||
|
CULL_METHOD = Draw.PupMenu('Small to large edge loop distrobution method%t|remove edges evenly|remove smallest edges edges')
|
||||||
|
if CULL_METHOD == -1:
|
||||||
|
if is_editmode: Window.EditMode(1)
|
||||||
|
return
|
||||||
|
|
||||||
#=================================================#
|
if CULL_METHOD ==1: # RESET CULL_METHOD
|
||||||
# Vert loop group functions
|
CULL_METHOD = 0 # shortest
|
||||||
|
|
||||||
def getAllVertLoops(mesh):
|
|
||||||
# Make a chain of vert loops.
|
|
||||||
fIgLs = [] # List of faces to ignore
|
|
||||||
allVLoops = [findVertLoop(mesh, fIgLs)]
|
|
||||||
while allVLoops[-1] != None:
|
|
||||||
|
|
||||||
# In future ignore all faces in this vert loop
|
|
||||||
fIgLs += allVLoops[-1]
|
|
||||||
|
|
||||||
# Add the new vert loop to the list
|
|
||||||
allVLoops.append( findVertLoop(mesh, fIgLs) )
|
|
||||||
|
|
||||||
return allVLoops[:-1] # Remove the last Value- None.
|
|
||||||
|
|
||||||
|
|
||||||
def reorderCircularVLoops(mesh, allVLoops):
|
|
||||||
# Now get a location for each vert loop.
|
|
||||||
allVertLoopLocs = []
|
|
||||||
for vLoop in allVLoops:
|
|
||||||
allVertLoopLocs.append( vLoopAverageLoc(mesh, vLoop) )
|
|
||||||
|
|
||||||
# We need to find the longest distance between 2 vert loops so we can
|
|
||||||
reorderedVLoopLocs = []
|
|
||||||
|
|
||||||
# Start with this one, then find the next closest.
|
|
||||||
# in doing this make a new list called reorderedVloop
|
|
||||||
currentVLoop = 0
|
|
||||||
reorderedVloopIdx = [currentVLoop]
|
|
||||||
newOrderVLoops = [allVLoops[0]] # This is a re-ordered allVLoops
|
|
||||||
while len(reorderedVloopIdx) != len(allVLoops):
|
|
||||||
bestSoFar = None
|
|
||||||
bestVIdxSoFar = None
|
|
||||||
for vLoopIdx in range(len(allVLoops)):
|
|
||||||
if vLoopIdx not in reorderedVloopIdx + [currentVLoop]:
|
|
||||||
if bestSoFar == None:
|
|
||||||
bestSoFar = measure( allVertLoopLocs[vLoopIdx], allVertLoopLocs[currentVLoop] )
|
|
||||||
bestVIdxSoFar = vLoopIdx
|
|
||||||
else:
|
else:
|
||||||
newDist = measure( allVertLoopLocs[vLoopIdx], allVertLoopLocs[currentVLoop] )
|
CULL_METHOD = 1 # even
|
||||||
if newDist < bestSoFar:
|
|
||||||
bestSoFar = newDist
|
|
||||||
bestVIdxSoFar = vLoopIdx
|
|
||||||
|
|
||||||
reorderedVloopIdx.append(bestVIdxSoFar)
|
|
||||||
reorderedVLoopLocs.append(allVertLoopLocs[bestVIdxSoFar])
|
|
||||||
newOrderVLoops.append( allVLoops[bestVIdxSoFar] )
|
|
||||||
|
|
||||||
# Start looking for the next best fit
|
|
||||||
currentVLoop = bestVIdxSoFar
|
|
||||||
|
|
||||||
# This is not the locicle place to put this but its convieneint.
|
|
||||||
# Here we find the 2 vert loops that are most far apart
|
|
||||||
# We use this to work out which 2 vert loops not to skin when making an open loft.
|
|
||||||
vLoopIdx = 0
|
|
||||||
# Longest measured so far - 0 dummy.
|
|
||||||
bestSoFar = 0
|
|
||||||
while vLoopIdx < len(reorderedVLoopLocs):
|
|
||||||
|
|
||||||
# Skin back to the start if needs be, becuase this is a crcular loft
|
|
||||||
toSkin2 = vLoopIdx + 1
|
|
||||||
if toSkin2 == len(reorderedVLoopLocs):
|
|
||||||
toSkin2 = 0
|
|
||||||
|
|
||||||
newDist = measure( reorderedVLoopLocs[vLoopIdx], reorderedVLoopLocs[toSkin2] )
|
|
||||||
|
|
||||||
if newDist >= bestSoFar:
|
|
||||||
bestSoFar = newDist
|
|
||||||
vLoopIdxNotToSkin = vLoopIdx + 1
|
|
||||||
|
|
||||||
vLoopIdx +=1
|
|
||||||
|
|
||||||
return newOrderVLoops, vLoopIdxNotToSkin
|
|
||||||
|
|
||||||
|
|
||||||
is_editmode = Window.EditMode()
|
time1 = sys.time()
|
||||||
if is_editmode: Window.EditMode(0)
|
# Convert to special edge data.
|
||||||
|
edgeLoops = []
|
||||||
|
for vloop in vertLoops:
|
||||||
|
edgeLoops.append(edgeLoop(vloop))
|
||||||
|
|
||||||
# Get a mesh and raise errors if we cant
|
|
||||||
mesh = None
|
|
||||||
if choice == -1:
|
|
||||||
pass
|
|
||||||
elif len(Object.GetSelected()) > 0:
|
|
||||||
if Object.GetSelected()[0].getType() == 'Mesh':
|
|
||||||
mesh = Object.GetSelected()[0].getData()
|
|
||||||
else:
|
|
||||||
error('please select a mesh')
|
|
||||||
else:
|
|
||||||
error('no mesh object selected')
|
|
||||||
|
|
||||||
time1 = sys.time()
|
# VERT LOOP ORDERING CODE
|
||||||
if mesh != None:
|
# Build a worm list - grow from Both ends
|
||||||
Window.WaitCursor(1)
|
edgeOrderedList = [edgeLoops.pop()]
|
||||||
allVLoops = getAllVertLoops(mesh)
|
|
||||||
|
|
||||||
# Re order the vert loops
|
# Find the closest.
|
||||||
allVLoops, vLoopIdxNotToSkin = reorderCircularVLoops(mesh, allVLoops)
|
bestSoFar = BIG_NUM
|
||||||
|
bestIdxSoFar = None
|
||||||
|
for edLoopIdx, edLoop in enumerate(edgeLoops):
|
||||||
|
l =(edgeOrderedList[-1].centre - edLoop.centre).length
|
||||||
|
if l < bestSoFar:
|
||||||
|
bestIdxSoFar = edLoopIdx
|
||||||
|
bestSoFar = l
|
||||||
|
|
||||||
vloopIdx = 0
|
edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) )
|
||||||
while vloopIdx < len(allVLoops):
|
|
||||||
#print range(len(allVLoops) )
|
|
||||||
#print vloopIdx
|
|
||||||
#print allVLoops[vloopIdx]
|
|
||||||
|
|
||||||
# Skin back to the start if needs be, becuase this is a crcular loft
|
# Now we have the 2 closest, append to either end-
|
||||||
toSkin2 = vloopIdx + 1
|
# Find the closest.
|
||||||
if toSkin2 == len(allVLoops):
|
while edgeLoops:
|
||||||
toSkin2 = 0
|
bestSoFar = BIG_NUM
|
||||||
|
bestIdxSoFar = None
|
||||||
|
first_or_last = 0 # Zero is first
|
||||||
|
for edLoopIdx, edLoop in enumerate(edgeLoops):
|
||||||
|
l1 =(edgeOrderedList[-1].centre - edLoop.centre).length
|
||||||
|
|
||||||
# Circular loft or not?
|
if l1 < bestSoFar:
|
||||||
if arg[0] == 'B': # B for open
|
bestIdxSoFar = edLoopIdx
|
||||||
if vloopIdx != vLoopIdxNotToSkin:
|
bestSoFar = l1
|
||||||
mesh = skinVertLoops(mesh, allVLoops[vloopIdx], allVLoops[toSkin2])
|
first_or_last = 1 # last
|
||||||
elif arg[0] == 'A': # A for closed
|
|
||||||
mesh = skinVertLoops(mesh, allVLoops[vloopIdx], allVLoops[toSkin2])
|
|
||||||
|
|
||||||
vloopIdx +=1
|
l2 =(edgeOrderedList[0].centre - edLoop.centre).length
|
||||||
|
if l2 < bestSoFar:
|
||||||
|
bestIdxSoFar = edLoopIdx
|
||||||
|
bestSoFar = l2
|
||||||
|
first_or_last = 0 # last
|
||||||
|
|
||||||
mesh.update(1,(mesh.edges != []),0)
|
if first_or_last: # add closest Last
|
||||||
|
edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) )
|
||||||
|
else: # Add closest First
|
||||||
|
edgeOrderedList.insert(0, edgeLoops.pop(bestIdxSoFar) ) # First
|
||||||
|
|
||||||
if is_editmode: Window.EditMode(1)
|
for i in range(len(edgeOrderedList)-1):
|
||||||
Window.WaitCursor(0)
|
skin2EdgeLoops(edgeOrderedList[i], edgeOrderedList[i+1], me, ob, 0)
|
||||||
print "skinning time: %.2f" % (sys.time() - time1)
|
if choice == 1 and len(edgeOrderedList) > 2: # Loop
|
||||||
|
skin2EdgeLoops(edgeOrderedList[0], edgeOrderedList[-1], me, ob, 0)
|
||||||
|
|
||||||
|
me.update(1, 1, 0)
|
||||||
|
if is_editmode: Window.EditMode(1)
|
||||||
|
|
||||||
|
main()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
""" Registration info for Blender menus:
|
""" Registration info for Blender menus:
|
||||||
Name: 'Texture Baker'
|
Name: 'Texture Baker'
|
||||||
Blender: 237
|
Blender: 236
|
||||||
Group: 'UV'
|
Group: 'UV'
|
||||||
Tooltip: 'Procedural to uvmapped texture baker'
|
Tooltip: 'Procedural to uvmapped texture baker'
|
||||||
"""
|
"""
|
||||||
@@ -11,10 +11,11 @@ __author__ = "Jean-Michel Soler (jms)"
|
|||||||
__url__ = ("blender", "elysiun",
|
__url__ = ("blender", "elysiun",
|
||||||
"Official Page, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_mesh3d2uv2d_en.htm",
|
"Official Page, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_mesh3d2uv2d_en.htm",
|
||||||
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
|
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
|
||||||
__version__ = "0.2.8 2005/7/20"
|
__version__ = "0.3.0 2005/10/09"
|
||||||
|
|
||||||
__bpydoc__ = """\
|
__bpydoc__ = """\
|
||||||
Texture Baker "bakes" Blender procedural materials (including textures): it saves them as 2d uv-mapped images.
|
This script "bakes" Blender procedural materials (including textures): it saves
|
||||||
|
them as 2d uv-mapped images.
|
||||||
|
|
||||||
This script saves an uv texture layout of the chosen mesh, that can be used as
|
This script saves an uv texture layout of the chosen mesh, that can be used as
|
||||||
an uv map for it. It is a way to export procedurals from Blender as normal
|
an uv map for it. It is a way to export procedurals from Blender as normal
|
||||||
@@ -23,21 +24,22 @@ with the mesh in games and other 3d applications.
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
a) Enter face mode and define uv coordinates for your mesh (do not forget to choose a development shape);<br>
|
a) Enter face mode and define uv coordinates for your mesh;<br>
|
||||||
b) Define its materials and textures;<br>
|
b) Define its materials and textures ;
|
||||||
c) Run this script and check the console.
|
c) Run this script and check the console.
|
||||||
|
|
||||||
Global variables:
|
Global variables
|
||||||
|
|
||||||
a) FRAME (integer): the last frame of the animation, autodocumented.<br>
|
a) FRAME integer, the last frame of the animation, autodocumented .
|
||||||
b) LIMIT (integer): 0 or 1, uvcoords may exceed limits 0.0 to 1.0, this variable obliges the script to do a complete framing of the uvcoord.
|
b) LIMIT integer, 0 or 1, uvcoords may exceed limits 0.0 to 1.0 , this variable
|
||||||
|
obliges the script to do a complete framing of the uvcoord .
|
||||||
|
|
||||||
Notes:<br>
|
Notes:<br>
|
||||||
This script was based on a suggestion by Martin (Theeth) Poirier.
|
This script was based on a suggestion by Martin (Theeth) Poirier;<br>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#---------------------------------------------
|
#---------------------------------------------
|
||||||
# Last release : 0.2.8 , 2005/07/20 , 17h10
|
# Last release : 0.3.0 , 2005/10/09 , 23h23
|
||||||
#---------------------------------------------
|
#---------------------------------------------
|
||||||
#---------------------------------------------
|
#---------------------------------------------
|
||||||
# (c) jm soler 07/2004 : 'Procedural Texture Baker'
|
# (c) jm soler 07/2004 : 'Procedural Texture Baker'
|
||||||
@@ -47,6 +49,14 @@ Notes:<br>
|
|||||||
#
|
#
|
||||||
# Released under Blender Artistic Licence
|
# Released under Blender Artistic Licence
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
# 0.3.0
|
||||||
|
# TAILLEIMAGE variable
|
||||||
|
#
|
||||||
|
# 0.2.9
|
||||||
|
# -- little probleme with the KEEPRENDERWINDOW variable .
|
||||||
|
# removed . script seems to works correctly now .
|
||||||
|
#
|
||||||
# 0.2.8
|
# 0.2.8
|
||||||
# -- added the forgotten image property in face
|
# -- added the forgotten image property in face
|
||||||
# data. a little longer but better.
|
# data. a little longer but better.
|
||||||
@@ -201,6 +211,8 @@ DEBUG=1
|
|||||||
RENDERLAYER=20
|
RENDERLAYER=20
|
||||||
SCENELAYERS=[]
|
SCENELAYERS=[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
helpmsg = """
|
helpmsg = """
|
||||||
Texture Baker:
|
Texture Baker:
|
||||||
|
|
||||||
@@ -250,6 +262,7 @@ def RenameImage(RDIR, MYDIR, FILENAME, name):
|
|||||||
"""
|
"""
|
||||||
newfname = RDIR + MYDIR + name
|
newfname = RDIR + MYDIR + name
|
||||||
if newfname.find('.png', -4) < 0 : newfname += '.png'
|
if newfname.find('.png', -4) < 0 : newfname += '.png'
|
||||||
|
|
||||||
if not Blender.sys.exists(newfname):
|
if not Blender.sys.exists(newfname):
|
||||||
os.rename(FILENAME, newfname)
|
os.rename(FILENAME, newfname)
|
||||||
else:
|
else:
|
||||||
@@ -290,7 +303,7 @@ def SAVE_image (rc, name, FRAME, result):
|
|||||||
rc.startFrame(NEWFRAME)
|
rc.startFrame(NEWFRAME)
|
||||||
rc.endFrame(NEWFRAME)
|
rc.endFrame(NEWFRAME)
|
||||||
rc.renderAnim()
|
rc.renderAnim()
|
||||||
if result!=2 and not KEEPRENDERWINDOW:
|
if result!=2 :
|
||||||
Blender.Scene.Render.CloseRenderWindow()
|
Blender.Scene.Render.CloseRenderWindow()
|
||||||
FILENAME = "%04d" % NEWFRAME
|
FILENAME = "%04d" % NEWFRAME
|
||||||
FILENAME = FILENAME.replace (' ', '0')
|
FILENAME = FILENAME.replace (' ', '0')
|
||||||
@@ -346,14 +359,24 @@ def SHOOT (XYlimit, frame, obj, name, FRAME, result):
|
|||||||
OLDy = context.imageSizeY()
|
OLDy = context.imageSizeY()
|
||||||
OLDx = context.imageSizeX()
|
OLDx = context.imageSizeX()
|
||||||
|
|
||||||
tres = Draw.PupMenu('TEXTURE OUT RESOLUTION : %t | 256 %x1 | 512 %x2 | 768 %x3 | 1024 %x4 | 2048 %x5 ')
|
TAILLEIMAGE='TEXTURE OUT RESOLUTION : %t |'
|
||||||
|
TAILLEIMAGE+='256 %x1 |'
|
||||||
|
TAILLEIMAGE+='512 %x2 |'
|
||||||
|
TAILLEIMAGE+='768 %x3 |'
|
||||||
|
TAILLEIMAGE+='1024 %x4 |'
|
||||||
|
TAILLEIMAGE+='2048 %x5 '
|
||||||
|
#TAILLEIMAGE+='| 4096 %x6 '
|
||||||
|
tres = Draw.PupMenu(TAILLEIMAGE)
|
||||||
|
|
||||||
if (tres) == 1: res = 256
|
if (tres) == 1: res = 256
|
||||||
elif (tres) == 2: res = 512
|
elif (tres) == 2: res = 512
|
||||||
elif (tres) == 3: res = 768
|
elif (tres) == 3: res = 768
|
||||||
elif (tres) == 4: res = 1024
|
elif (tres) == 4: res = 1024
|
||||||
elif (tres) == 5: res = 2048
|
elif (tres) == 5: res = 2048
|
||||||
|
# elif (tres) == 6: res = 4096
|
||||||
else: res = 512
|
else: res = 512
|
||||||
|
#...
|
||||||
|
|
||||||
|
|
||||||
SCENELAYERS=SC.layers
|
SCENELAYERS=SC.layers
|
||||||
SC.layers = [20]
|
SC.layers = [20]
|
||||||
@@ -419,7 +442,7 @@ def Mesh2UVCoord (LIMIT):
|
|||||||
"""
|
"""
|
||||||
global PUTRAW, FRAME, SCENELAYERS
|
global PUTRAW, FRAME, SCENELAYERS
|
||||||
|
|
||||||
try:
|
try :
|
||||||
MESH3D = Object.GetSelected()[0]
|
MESH3D = Object.GetSelected()[0]
|
||||||
if MESH3D.getType() == 'Mesh':
|
if MESH3D.getType() == 'Mesh':
|
||||||
MESH = MESH3D.getData()
|
MESH = MESH3D.getData()
|
||||||
@@ -464,6 +487,7 @@ def Mesh2UVCoord (LIMIT):
|
|||||||
NewOBJECT.setLocation (OBJPOS, OBJPOS, 0.0)
|
NewOBJECT.setLocation (OBJPOS, OBJPOS, 0.0)
|
||||||
NewOBJECT.setEuler (0.0, 0.0, 0.0)
|
NewOBJECT.setEuler (0.0, 0.0, 0.0)
|
||||||
|
|
||||||
|
|
||||||
MESH2.removeAllKeys()
|
MESH2.removeAllKeys()
|
||||||
MESH2.update()
|
MESH2.update()
|
||||||
MESH2.insertKey (1, 'absolute')
|
MESH2.insertKey (1, 'absolute')
|
||||||
@@ -471,7 +495,7 @@ def Mesh2UVCoord (LIMIT):
|
|||||||
|
|
||||||
imagename = 'uvtext'
|
imagename = 'uvtext'
|
||||||
|
|
||||||
name = "CHANGE IMAGE NAME ? %t | Replace it | No replacing | Script help"
|
name = "CHANGE IMAGE NAME ? %t | Replace it | No replace | Script help"
|
||||||
result = Draw.PupMenu(name)
|
result = Draw.PupMenu(name)
|
||||||
|
|
||||||
if result == 1:
|
if result == 1:
|
||||||
@@ -501,17 +525,16 @@ def Mesh2UVCoord (LIMIT):
|
|||||||
Blender.Redraw()
|
Blender.Redraw()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
Blender.ShowHelp('tex2uvbaker.py')
|
Draw.PupMenu("Ready%t|Please check console for instructions")
|
||||||
#Draw.PupMenu("Ready%t|Please check console for instructions")
|
print helpmsg
|
||||||
if DEBUG: print helpmsg
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
name = "ERROR: active object is not a mesh or has no UV coordinates"
|
name = "Error%t|Active object is not a mesh or has no UV coordinates"
|
||||||
result = Draw.PupMenu(name)
|
result = Draw.PupMenu(name)
|
||||||
print 'problem : no object selected or not mesh'
|
print 'problem : no object selected or not mesh'
|
||||||
|
|
||||||
except:
|
except:
|
||||||
name = "ERROR: active object is not a mesh or has no UV coordinates"
|
name = "Error%t|Active object is not a mesh or has no UV coordinates"
|
||||||
result = Draw.PupMenu(name)
|
result = Draw.PupMenu(name)
|
||||||
print 'problem : no object selected or not mesh'
|
print 'problem : no object selected or not mesh'
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ __author__ = "Jean-Michel Soler (jms)"
|
|||||||
__url__ = ("blender", "elysiun",
|
__url__ = ("blender", "elysiun",
|
||||||
"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_uvpainting.htm",
|
"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_uvpainting.htm",
|
||||||
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
|
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
|
||||||
__version__ = "0.5 05/2004"
|
__version__ = "0.8 08/2005"
|
||||||
|
|
||||||
__bpydoc__ = """\
|
__bpydoc__ = """\
|
||||||
This script "paints" uv-mappings with the model's vertex colors.
|
This script "paints" uv-mappings with the model's vertex colors.
|
||||||
@@ -33,6 +33,29 @@ Notes:<br>
|
|||||||
the "Make" VColors button in the edit mesh buttons win, the current light setup
|
the "Make" VColors button in the edit mesh buttons win, the current light setup
|
||||||
is saved as vertex colors for the model;<br>
|
is saved as vertex colors for the model;<br>
|
||||||
Check the script's homepage for example images.
|
Check the script's homepage for example images.
|
||||||
|
|
||||||
|
Short keys Documentation
|
||||||
|
|
||||||
|
KEYS
|
||||||
|
M : dipslay GUI Menu
|
||||||
|
D : Set/Unset Documentation
|
||||||
|
S : Save current window content
|
||||||
|
in a tga file
|
||||||
|
Q or ESC : Exit
|
||||||
|
T : Set/Unset Transparency
|
||||||
|
L : Set/Unset lines
|
||||||
|
E : Set/Unset outline
|
||||||
|
B : Set lines color to Black
|
||||||
|
W : Set lines color to white
|
||||||
|
ARROW : displace model on
|
||||||
|
UP/DOWN/LEFT/RIGHT side
|
||||||
|
PADPLUS : increase ZOOM
|
||||||
|
PADMINUS : decrease ZOOM
|
||||||
|
HOME : cancel display modifs
|
||||||
|
|
||||||
|
Mouse button
|
||||||
|
RIGHTMOUSE : same as arrows
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# $Id$
|
# $Id$
|
||||||
@@ -99,18 +122,87 @@ def exist(path):
|
|||||||
return 0
|
return 0
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
loc0= Blender.sys.dirname(Blender.Get ("filename"))
|
loc0= Blender.Get ("filename").replace('\\','/')
|
||||||
loc2=loc0+Blender.sys.dirsep+'test00.tga'
|
loc0=loc0[:loc0.rfind('/')]
|
||||||
|
|
||||||
|
loc2=loc0+'/'+'test00.tga'
|
||||||
|
|
||||||
|
|
||||||
|
mouse_x,mouse_y=0,0
|
||||||
|
mouse_xr=1
|
||||||
|
mouse_yr=1
|
||||||
|
POS=[0,0]
|
||||||
|
ANC=[0,0]
|
||||||
|
XY=[0,0]
|
||||||
|
size=[]
|
||||||
|
sel=0
|
||||||
|
X,Y=0,0
|
||||||
|
TRANSP,EMPTY,DOCU=0,0,0
|
||||||
|
MENU, SAVE =1,0
|
||||||
|
|
||||||
glCr=glRasterPos2d
|
glCr=glRasterPos2d
|
||||||
glCl3=glColor3f
|
glCl3=glColor3f
|
||||||
glCl4=glColor4f
|
glCl4=glColor4f
|
||||||
glRct=glRectf
|
glRct=glRectf
|
||||||
|
|
||||||
|
LC=1.0
|
||||||
|
|
||||||
xlimit=0
|
xlimit=0
|
||||||
selmatlist=[]
|
selmatlist=[]
|
||||||
|
LIM=[0.0,0.0,0.0,0.0]
|
||||||
|
NOLIM=1
|
||||||
|
if not NOLIM : LIM=[-1.0,1.0,-1.0,1.0]
|
||||||
|
|
||||||
def triangle(a,b,c):
|
TR=0.8
|
||||||
|
|
||||||
|
def Doc(size):
|
||||||
|
S0,S1=40,50
|
||||||
|
|
||||||
|
a=[S0,size[3]-S1, .8,.8,.8]
|
||||||
|
b=[S0*7,size[3]-S1, .8,0.8,0.8]
|
||||||
|
c=[S0*7,size[3]-S1*7, 0.8,0.8,0.8]
|
||||||
|
d=[S0,size[3]-S1*7, 0.8,0.8,0.8]
|
||||||
|
Tcarre(a,b,c,d,0.8)
|
||||||
|
Lcarre(a,b,c,d,0.0)
|
||||||
|
DOC=[' ',
|
||||||
|
'Documentation',
|
||||||
|
' ',
|
||||||
|
'KEYS ',
|
||||||
|
'M : dipslay GUI Menu',
|
||||||
|
'D : Set/Unset Documentation',
|
||||||
|
'S : Save current window content',
|
||||||
|
' in a tga file',
|
||||||
|
'Q or ESC : Exit',
|
||||||
|
'T : Set/Unset Transparency',
|
||||||
|
'L : Set/Unset lines',
|
||||||
|
'E : Set/Unset outline',
|
||||||
|
'B : Set lines color to Black ',
|
||||||
|
'W : Set lines color to white',
|
||||||
|
'ARROW : displace model on ',
|
||||||
|
' UP/DOWN/LEFT/RIGHT side' ,
|
||||||
|
'PADPLUS : increase ZOOM ',
|
||||||
|
'PADMINUS : decrease ZOOM ',
|
||||||
|
'HOME : cancel display modifs',
|
||||||
|
' ',
|
||||||
|
'Mouse button',
|
||||||
|
'RIGHTMOUSE : same as arrows',
|
||||||
|
]
|
||||||
|
glColor3f(0.0,0.0,0.0)
|
||||||
|
for D in DOC :
|
||||||
|
glRasterPos2f(S0+8, size[3]-S1-13*DOC.index(D))
|
||||||
|
Text(D)
|
||||||
|
|
||||||
|
def Ttriangle(a,b,c):
|
||||||
|
glBegin(GL_TRIANGLES);
|
||||||
|
glColor4f(a[2],a[3],a[4],TR)
|
||||||
|
glVertex2f(a[0],a[1]);
|
||||||
|
glColor4f(b[2],b[3],b[4],TR)
|
||||||
|
glVertex2f(b[0],b[1]);
|
||||||
|
glColor4f(c[2],c[3],c[4],TR)
|
||||||
|
glVertex2f(c[0],c[1]);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
def Ftriangle(a,b,c):
|
||||||
glBegin(GL_TRIANGLES);
|
glBegin(GL_TRIANGLES);
|
||||||
glColor3f(a[2],a[3],a[4])
|
glColor3f(a[2],a[3],a[4])
|
||||||
glVertex2f(a[0],a[1]);
|
glVertex2f(a[0],a[1]);
|
||||||
@@ -120,33 +212,46 @@ def triangle(a,b,c):
|
|||||||
glVertex2f(c[0],c[1]);
|
glVertex2f(c[0],c[1]);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
def Ltriangle(a,b,c):
|
def Ltriangle(a,b,c,LC=0.5):
|
||||||
|
TL=[a,b,c,a]
|
||||||
|
for v in [0,1,2] :
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
glColor3f(1.0,1.0,1.0)
|
glColor4f(LC,LC,LC,TR+0.2)
|
||||||
glVertex2f(a[0],a[1]);
|
glVertex2f(TL[v][0],TL[v][1]);
|
||||||
glVertex2f(b[0],b[1]);
|
glVertex2f(TL[v+1][0],TL[v+1][1]);
|
||||||
glVertex2f(c[0],c[1]);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
def carre(a,b,c,d):
|
|
||||||
triangle(a,b,c)
|
|
||||||
triangle(a,c,d)
|
|
||||||
|
|
||||||
def Lcarre(a,b,c,d):
|
|
||||||
glBegin(GL_LINES);
|
|
||||||
glColor3f(1.0,1.0,1.0)
|
|
||||||
glVertex2f(a[0],a[1]);
|
|
||||||
glVertex2f(b[0],b[1]);
|
|
||||||
glVertex2f(c[0],c[1]);
|
|
||||||
glVertex2f(d[0],d[1]);
|
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
|
|
||||||
|
def Tcarre(a,b,c,d,LC=1.0):
|
||||||
|
Ttriangle(a,b,c)
|
||||||
|
Ttriangle(a,c,d)
|
||||||
|
|
||||||
def transface(f,x,y):
|
def Fcarre(a,b,c,d,LC=1.0):
|
||||||
global xlimit
|
Ftriangle(a,b,c)
|
||||||
|
Ftriangle(a,c,d)
|
||||||
|
|
||||||
|
def Lcarre(a,b,c,d,LC=0.5):
|
||||||
|
TL=[a,b,c,d,a]
|
||||||
|
for v in [0,1,2,3] :
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glColor4f(LC,LC,LC,TR+0.2)
|
||||||
|
glVertex2f(TL[v][0],TL[v][1]);
|
||||||
|
glVertex2f(TL[v+1][0],TL[v+1][1]);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
|
||||||
|
def transface(f,x,y,u=0.0, v=0.0):
|
||||||
|
global xlimit, LIM
|
||||||
|
global mouse_xr,sel, ANC, X,Y
|
||||||
|
global mouse_yr, POS, XY,size
|
||||||
|
global mouse_x, mouse_y
|
||||||
|
|
||||||
|
mouse_x=mouse_xr-size[0]
|
||||||
|
mouse_y=mouse_yr-size[1]
|
||||||
|
|
||||||
|
if sel==1:
|
||||||
|
POS=[mouse_x-ANC[0],mouse_y-ANC[1]]
|
||||||
|
u,v=POS
|
||||||
|
|
||||||
a=[0,0,0.0, 0.0,0.0,0.0]
|
a=[0,0,0.0, 0.0,0.0,0.0]
|
||||||
b=[0,0,0.0, 0.0,0.0,0.0]
|
b=[0,0,0.0, 0.0,0.0,0.0]
|
||||||
@@ -154,8 +259,8 @@ def transface(f,x,y):
|
|||||||
d=[0,0,0.0, 0.0,0.0,0.0]
|
d=[0,0,0.0, 0.0,0.0,0.0]
|
||||||
|
|
||||||
if len(f.v)>=3:
|
if len(f.v)>=3:
|
||||||
a[0]=int(f.uv[0][0]*x)
|
a[0]=int((f.uv[0][0]-LIM[1])*x+u)
|
||||||
a[1]=int(f.uv[0][1]*y)
|
a[1]=int((f.uv[0][1]-LIM[3])*y+v)
|
||||||
|
|
||||||
if a[0]>xlimit:
|
if a[0]>xlimit:
|
||||||
xlimit=a[0]
|
xlimit=a[0]
|
||||||
@@ -164,8 +269,8 @@ def transface(f,x,y):
|
|||||||
a[3]=f.col[0].g/255.0
|
a[3]=f.col[0].g/255.0
|
||||||
a[4]=f.col[0].b/255.0
|
a[4]=f.col[0].b/255.0
|
||||||
|
|
||||||
c[0]=int(f.uv[2][0]*x)
|
c[0]=int((f.uv[2][0]-LIM[1])*x+u)
|
||||||
c[1]=int(f.uv[2][1]*y)
|
c[1]=int((f.uv[2][1]-LIM[3])*y+v)
|
||||||
|
|
||||||
if c[0]>xlimit:
|
if c[0]>xlimit:
|
||||||
xlimit=c[0]
|
xlimit=c[0]
|
||||||
@@ -175,8 +280,8 @@ def transface(f,x,y):
|
|||||||
c[4]=f.col[2].b/255.0
|
c[4]=f.col[2].b/255.0
|
||||||
|
|
||||||
|
|
||||||
b[0]=int(f.uv[1][0]*x)
|
b[0]=int((f.uv[1][0]-LIM[1])*x+u)
|
||||||
b[1]=int(f.uv[1][1]*y)
|
b[1]=int((f.uv[1][1]-LIM[3])*y+v)
|
||||||
|
|
||||||
if b[0]>xlimit:
|
if b[0]>xlimit:
|
||||||
xlimit=b[0]
|
xlimit=b[0]
|
||||||
@@ -187,8 +292,8 @@ def transface(f,x,y):
|
|||||||
|
|
||||||
|
|
||||||
if len(f.v)==4:
|
if len(f.v)==4:
|
||||||
d[0]=int(f.uv[3][0]*x)
|
d[0]=int((f.uv[3][0]-LIM[1])*x+u)
|
||||||
d[1]=int(f.uv[3][1]*y)
|
d[1]=int((f.uv[3][1]-LIM[3])*y+v)
|
||||||
|
|
||||||
if d[0]>xlimit:
|
if d[0]>xlimit:
|
||||||
xlimit=d[0]
|
xlimit=d[0]
|
||||||
@@ -214,44 +319,53 @@ def extract_faces(me,MENU):
|
|||||||
return listf
|
return listf
|
||||||
|
|
||||||
def affiche_mesh(ME,x,y):
|
def affiche_mesh(ME,x,y):
|
||||||
global LINE,xlimit,MMENU,XLIMIT,xwin,xlimit
|
global LINE,xlimit,MMENU,XLIMIT,xwin,xlimit,LC
|
||||||
|
global LIM, EMPTY,TRANSP
|
||||||
|
if not NOLIM : LIM=[-1.0,1.0,-1.0,1.0]
|
||||||
|
|
||||||
if ME.getType()=='Mesh':
|
if ME.getType()=='Mesh':
|
||||||
me=GetRaw(ME.getData().name)
|
me=ME.getData()
|
||||||
|
|
||||||
if MMENU.val==1:
|
if MMENU.val==1:
|
||||||
se=me.faces
|
se=me.faces
|
||||||
|
|
||||||
elif MMENU.val==3:
|
elif MMENU.val==3:
|
||||||
se=me.getSelectedFaces()
|
se=[s for s in me.faces if s in me.getSelectedFaces() or s.sel]
|
||||||
|
|
||||||
elif MMENU.val==2:
|
elif MMENU.val==2:
|
||||||
se=extract_faces(me,2)
|
se=extract_faces(me,2)
|
||||||
|
if not NOLIM :
|
||||||
|
for s in se:
|
||||||
|
for u in s.uv:
|
||||||
|
if u[0] >LIM[0] : LIM[0]=u[0]
|
||||||
|
if u[0] <LIM[1] : LIM[1]=u[0]
|
||||||
|
if u[1] >LIM[2] : LIM[2]=u[1]
|
||||||
|
if u[1] <LIM[3] : LIM[3]=u[1]
|
||||||
xlimit=0
|
xlimit=0
|
||||||
for f in se:
|
for f in se:
|
||||||
a,b,c,d=transface(f,x,y)
|
a,b,c,d=transface(f,x,y)
|
||||||
|
if not EMPTY and not TRANSP:
|
||||||
if len(f.v)==4:
|
if len(f.v)==4:
|
||||||
triangle(a,b,c)
|
Ftriangle(a,b,c)
|
||||||
triangle(a,c,d)
|
Ftriangle(a,c,d)
|
||||||
elif len(f.v)==3:
|
elif len(f.v)==3:
|
||||||
triangle(a,b,c)
|
Ftriangle(a,b,c)
|
||||||
|
elif not EMPTY :
|
||||||
|
if len(f.v)==4:
|
||||||
|
Ttriangle(a,b,c)
|
||||||
|
Ttriangle(a,c,d)
|
||||||
|
elif len(f.v)==3:
|
||||||
|
Ttriangle(a,b,c)
|
||||||
|
|
||||||
if LINE.val==1:
|
if LINE.val==1 or EMPTY:
|
||||||
for f in se:
|
for f in se:
|
||||||
a,b,c,d=transface(f,x,y)
|
a,b,c,d=transface(f,x,y)
|
||||||
if len(f.v)==4:
|
if len(f.v)==4:
|
||||||
Lcarre(a,b,c,d)
|
Lcarre(a,b,c,d,LC)
|
||||||
elif len(f.v)==3:
|
elif len(f.v)==3:
|
||||||
Ltriangle(a,b,c)
|
Ltriangle(a,b,c,LC)
|
||||||
|
|
||||||
if XLIMIT.val==0:
|
if XLIMIT.val==0:
|
||||||
Lcarre([1,1],[1,y-2],[xlimit+2,y-2],[xlimit+2,1])
|
Lcarre([1,1],[1,y-2],[xlimit+2,y-2],[xlimit+2,1])
|
||||||
else:
|
else:
|
||||||
Lcarre([1,1],[1,y-2],[xwin-2,y-2],[xwin-2,1])
|
Lcarre([1,1],[1,y-2],[xwin-2,y-2],[xwin-2,1])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def write_tgafile(loc2,bitmap,width,height,profondeur):
|
def write_tgafile(loc2,bitmap,width,height,profondeur):
|
||||||
|
|
||||||
f=open(loc2,'wb')
|
f=open(loc2,'wb')
|
||||||
@@ -286,10 +400,13 @@ def write_tgafile(loc2,bitmap,width,height,profondeur):
|
|||||||
|
|
||||||
|
|
||||||
def save(x0,y0,dx,dy):
|
def save(x0,y0,dx,dy):
|
||||||
|
global SAVE
|
||||||
im = Buffer(GL_BYTE,[dx*(dy+1),4])
|
im = Buffer(GL_BYTE,[dx*(dy+1),4])
|
||||||
glReadPixels(x0,y0,dx,dy,GL_RGBA, GL_BYTE,im);
|
glReadPixels(x0,y0,dx,dy,GL_RGBA, GL_BYTE,im);
|
||||||
print len(im), dx*dy, dx, dy, len(im)/dy
|
print len(im), dx*dy, dx, dy, len(im)/dy
|
||||||
write_tgafile(loc2,im,dx,dy+1,4)
|
write_tgafile(loc2,im,dx,dy+1,4)
|
||||||
|
SAVE=0
|
||||||
|
Blender.Redraw()
|
||||||
|
|
||||||
def DOCMat_list(TMATList,ME):
|
def DOCMat_list(TMATList,ME):
|
||||||
me=Blender.NMesh.GetRaw(ME.getData().name)
|
me=Blender.NMesh.GetRaw(ME.getData().name)
|
||||||
@@ -342,8 +459,12 @@ TEXT=Create(loc2)
|
|||||||
# uvpaint4
|
# uvpaint4
|
||||||
# ----------
|
# ----------
|
||||||
TMENU="MODE MENU %t|All %x1|Material %x2|Selected %x3"
|
TMENU="MODE MENU %t|All %x1|Material %x2|Selected %x3"
|
||||||
|
# ----------
|
||||||
# coming soon : "|Bone %x4", perhaps in uvpainter v0.5
|
# uvpaint4
|
||||||
|
# ----------
|
||||||
|
# coming soon : "|vertex group %x4", perhaps in uvpainter v0.5
|
||||||
|
LCOLOR= Create(64)
|
||||||
|
SAVE=0
|
||||||
|
|
||||||
MMENU=Create(3)
|
MMENU=Create(3)
|
||||||
TDOCMat = Create(0)
|
TDOCMat = Create(0)
|
||||||
@@ -370,13 +491,14 @@ n0=32
|
|||||||
|
|
||||||
def draw():
|
def draw():
|
||||||
global NSIZE,LINE,x0,y0,y,x,TEXT,MMENU,TDOCMat
|
global NSIZE,LINE,x0,y0,y,x,TEXT,MMENU,TDOCMat
|
||||||
global XLIMIT,selmatlist,xwin
|
global XLIMIT,selmatlist,xwin, LCOLOR, SAVE
|
||||||
|
global mouse_xr,sel, ANC, X,Y, TRANSP, DOCU
|
||||||
|
global mouse_yr, POS, XY,size, TRANSP,EMPTY
|
||||||
|
global MENU, SAVE
|
||||||
|
|
||||||
size=Buffer(GL_FLOAT, 4)
|
size=Buffer(GL_FLOAT, 4)
|
||||||
glGetFloatv(GL_SCISSOR_BOX, size)
|
glGetFloatv(GL_SCISSOR_BOX, size)
|
||||||
size= size.list
|
size=[int(s) for s in size ]
|
||||||
|
|
||||||
for s in [0,1,2,3]: size[s]=int(size[s])
|
|
||||||
|
|
||||||
n0=32
|
n0=32
|
||||||
x0=size[0]
|
x0=size[0]
|
||||||
@@ -390,34 +512,39 @@ def draw():
|
|||||||
|
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT)
|
glClear(GL_COLOR_BUFFER_BIT)
|
||||||
|
|
||||||
glShadeModel(GL_SMOOTH)
|
glShadeModel(GL_SMOOTH)
|
||||||
SelecMESH=Blender.Object.GetSelected()
|
#transparence
|
||||||
if SelecMESH!=[]:
|
if TRANSP :
|
||||||
if SelecMESH[0].getType()=='Mesh':
|
glEnable(GL_BLEND)
|
||||||
affiche_mesh(SelecMESH[0],int(y*NSIZE.val),int(y*NSIZE.val-n0-2))
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
||||||
|
|
||||||
|
SelecMESH=Blender.Object.GetSelected()
|
||||||
|
if SelecMESH!=[] and SelecMESH[0].getType()=='Mesh':
|
||||||
|
affiche_mesh(SelecMESH[0],int(y*NSIZE.val),int(y*NSIZE.val-2))
|
||||||
|
|
||||||
|
if MENU:
|
||||||
glColor3f(0.0,0.0,0.0)
|
glColor3f(0.0,0.0,0.0)
|
||||||
glRectf(4,size[3],555,size[3]-32 )
|
glRectf(4,size[3],555,size[3]-32 )
|
||||||
|
|
||||||
glColor3f(1.0,1.0,1.0)
|
glColor3f(1.0,1.0,1.0)
|
||||||
|
|
||||||
glRasterPos2f(8, size[3]-13)
|
glRasterPos2f(8, size[3]-13)
|
||||||
Text("uvpainter v0.5")
|
Text("uvpainter v0.8")
|
||||||
|
|
||||||
glRasterPos2f(8, size[3]-28)
|
glRasterPos2f(8, size[3]-28)
|
||||||
Text("Jm Soler, 05/2004")
|
Text("Jm Soler, 08/2005")
|
||||||
|
|
||||||
Button("ReDraw" ,16 ,290-118+61 ,size[3]-30 ,60 ,13)
|
Button("ReDraw" ,16 ,290-118+61 ,size[3]-30 ,60 ,13)
|
||||||
Button("Exit" ,1 ,250-122+63 ,size[3]-30 ,38 ,13)
|
Button("Exit" ,1 ,250-122+63 ,size[3]-30 ,38 ,13)
|
||||||
Button("Save" ,6 ,250-16+61 ,size[3]-30 ,40 ,13)
|
Button("Save" ,6 ,250-16+61 ,size[3]-30 ,40 ,13)
|
||||||
|
|
||||||
NSIZE= Slider("Sc:",4 ,290-118+61 ,size[3]-15 , 102, 13, NSIZE.val, 0.1,1.5,0,"SIZE.")
|
NSIZE= Slider("Sc:",4 ,290-118+61 ,size[3]-15 , 102, 13, NSIZE.val, 0.1,5.0,0,"SIZE.")
|
||||||
LINE=Toggle("line", 5 ,250-122+63 ,size[3]-15 , 38, 13, LINE.val, "Draw lines")
|
LINE=Toggle("line", 5 ,250-122+63 ,size[3]-15 , 38, 13, LINE.val, "Draw lines")
|
||||||
|
|
||||||
glRasterPos2f(250-130 ,size[3]-13,)
|
glRasterPos2f(250-130 ,size[3]-13,)
|
||||||
Text("Mode")
|
Text("Mode")
|
||||||
|
|
||||||
|
LCOLOR=Number("", 50, 250-77,size[3]-15,18,13,LCOLOR.val,1,64,'Line color, 64-lighter, 1-darker.')
|
||||||
|
|
||||||
MMENU= Menu(TMENU ,2 ,250-130, size[3]-30, 63, 13, MMENU.val, "MODE menu.")
|
MMENU= Menu(TMENU ,2 ,250-130, size[3]-30, 63, 13, MMENU.val, "MODE menu.")
|
||||||
|
|
||||||
if MMENU.val==1 or MMENU.val==3:
|
if MMENU.val==1 or MMENU.val==3:
|
||||||
@@ -453,15 +580,70 @@ def draw():
|
|||||||
size[3]-30,)
|
size[3]-30,)
|
||||||
TMATList[2][t]=Toggle("%s"%t , 32+t ,(293-16+61)+t*20 ,size[3]-13 ,20 , 13,TMATList[2][t].val)
|
TMATList[2][t]=Toggle("%s"%t , 32+t ,(293-16+61)+t*20 ,size[3]-13 ,20 , 13,TMATList[2][t].val)
|
||||||
|
|
||||||
|
#else:
|
||||||
|
# save()
|
||||||
|
|
||||||
|
if DOCU:
|
||||||
|
Doc(size)
|
||||||
|
|
||||||
def event(evt, val):
|
def event(evt, val):
|
||||||
if (evt== QKEY and not val): Exit()
|
global mouse_x, x, mouse_y, y, LC
|
||||||
|
global LCOLOR, DOCU, MENU, SAVE
|
||||||
|
global mouse_xr,sel, ANC, X,Y ,NSIZE
|
||||||
|
global mouse_yr, POS, XY,size, TRANSP,EMPTY
|
||||||
|
|
||||||
|
if (evt== QKEY or evt== ESCKEY and not val):
|
||||||
|
Exit()
|
||||||
|
elif (evt== TKEY and not val):
|
||||||
|
TRANSP=abs(TRANSP-1)
|
||||||
|
elif (evt== EKEY and not val):
|
||||||
|
EMPTY=abs(EMPTY-1)
|
||||||
|
elif (evt== MKEY and not val):
|
||||||
|
MENU=abs(MENU-1)
|
||||||
|
elif (evt== SKEY and not val):
|
||||||
|
SAVE=abs(MENU-1)
|
||||||
|
elif (evt== WKEY and not val):
|
||||||
|
LC=1.0
|
||||||
|
LCOLOR.val=64
|
||||||
|
elif (evt== BKEY and not val):
|
||||||
|
LC=0.0
|
||||||
|
LCOLOR.val=1
|
||||||
|
elif (evt==LEFTARROWKEY and not val) :
|
||||||
|
POS[0]-=10
|
||||||
|
elif (evt==RIGHTARROWKEY and not val) :
|
||||||
|
POS[0]+=10
|
||||||
|
elif (evt==UPARROWKEY and not val) :
|
||||||
|
POS[1]+=10
|
||||||
|
elif (evt==DOWNARROWKEY and not val) :
|
||||||
|
POS[1]-=10
|
||||||
|
elif (evt==PADMINUS and not val) :
|
||||||
|
NSIZE.val-=0.1
|
||||||
|
elif (evt==PADPLUSKEY and not val) :
|
||||||
|
NSIZE.val+=0.1
|
||||||
|
elif (evt==LKEY and not val) :
|
||||||
|
LINE.val=abs(LINE.val-1)
|
||||||
|
elif (evt==HOMEKEY and not val) :
|
||||||
|
NSIZE.val=1.0
|
||||||
|
POS=[0,0]
|
||||||
|
elif (evt==DKEY and not val) :
|
||||||
|
DOCU=abs(DOCU-1)
|
||||||
|
elif (evt == MOUSEX): mouse_xr = val
|
||||||
|
elif (evt == MOUSEY): mouse_yr = val
|
||||||
|
|
||||||
|
elif (evt == RIGHTMOUSE and val):
|
||||||
|
if (sel==0 ) :
|
||||||
|
ANC=[(mouse_xr-size[0])-POS[0],(mouse_yr-size[1])-POS[1]]
|
||||||
|
sel=1
|
||||||
|
elif (evt == RIGHTMOUSE and not val):
|
||||||
|
sel=0
|
||||||
|
ANC=0,0
|
||||||
|
Redraw(1)
|
||||||
|
|
||||||
|
|
||||||
def bevent(evt):
|
def bevent(evt):
|
||||||
global LINE,NSIZE,n0,x0,y0,y,TEXT, loc2
|
global LINE,NSIZE,n0,x0,y0,y,TEXT, loc2
|
||||||
global TMATList, selmatlist, TDOCMat,XLIMIT
|
global TMATList, selmatlist, TDOCMat,XLIMIT
|
||||||
global xlimit
|
global xlimit,LCOLOR,LC,SAVE
|
||||||
|
|
||||||
if (evt== 1):
|
if (evt== 1):
|
||||||
Exit()
|
Exit()
|
||||||
@@ -475,10 +657,10 @@ def bevent(evt):
|
|||||||
elif (evt== 6):
|
elif (evt== 6):
|
||||||
if XLIMIT.val==1:
|
if XLIMIT.val==1:
|
||||||
xi=xwin
|
xi=xwin
|
||||||
|
save(x0,y0,xi+2,int(y-n0))
|
||||||
else:
|
else:
|
||||||
xi=xlimit
|
xi=xlimit
|
||||||
|
save(x0,y0,xi+2,int(y*NSIZE.val)-n0)
|
||||||
save(x0,y0,xi+2,int(y*NSIZE.val-n0))
|
|
||||||
|
|
||||||
elif (evt== 7):
|
elif (evt== 7):
|
||||||
if exist(TEXT.val):
|
if exist(TEXT.val):
|
||||||
@@ -489,6 +671,9 @@ def bevent(evt):
|
|||||||
elif (evt== 24) or (evt in [32,33,34,35,36,37,38,39,40,41,42,43,44]):
|
elif (evt== 24) or (evt in [32,33,34,35,36,37,38,39,40,41,42,43,44]):
|
||||||
SELMat_list()
|
SELMat_list()
|
||||||
|
|
||||||
|
elif (evt== 50):
|
||||||
|
LC=float(LCOLOR.val)/64.0
|
||||||
|
|
||||||
|
|
||||||
Blender.Redraw()
|
Blender.Redraw()
|
||||||
|
|
||||||
@@ -322,28 +322,6 @@ def write(filename):
|
|||||||
Blender.Draw.PupMenu("Wings Export error|Unable to generate Edge Table for mesh")
|
Blender.Draw.PupMenu("Wings Export error|Unable to generate Edge Table for mesh")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
# if 0:
|
|
||||||
# import Tkinter, tkMessageBox
|
|
||||||
# sys.argv=['wings.pyo','wings.pyc'] # ?
|
|
||||||
#
|
|
||||||
# #Tkinter.NoDefaultRoot()
|
|
||||||
# win1 = Tkinter.Tk()
|
|
||||||
# ans = tkMessageBox.showerror("Error", message)
|
|
||||||
# win1.pack()
|
|
||||||
# print ans
|
|
||||||
# if ans:
|
|
||||||
# win1.quit()
|
|
||||||
# win1.mainloop()
|
|
||||||
#
|
|
||||||
# else:
|
|
||||||
# from Tkinter import Label
|
|
||||||
# sys.argv = 'wings.py'
|
|
||||||
# widget = Label(None, text=message)
|
|
||||||
# #widget.title("Error")
|
|
||||||
# widget.pack()
|
|
||||||
# widget.mainloop()
|
|
||||||
|
|
||||||
data = generate_data(objname, edge_table, mesh)
|
data = generate_data(objname, edge_table, mesh)
|
||||||
dsize = len(data)
|
dsize = len(data)
|
||||||
Blender.Window.DrawProgressBar(0.98, "Compressing Data")
|
Blender.Window.DrawProgressBar(0.98, "Compressing Data")
|
||||||
|
|||||||
@@ -423,33 +423,6 @@ static PyObject *Buffer_repr(PyObject *self)
|
|||||||
return repr;
|
return repr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not a macro so that buffer dimensions are checked.
|
|
||||||
* XXX There are other places where buffers are used, so a new macro to handle
|
|
||||||
* all such cases may be a good idea. */
|
|
||||||
static PyObject *Method_DrawPixels (PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
int bgl_var1, bgl_var2, bgl_var3, bgl_var4;
|
|
||||||
Buffer *bgl_buffer5;
|
|
||||||
int i, bufsize;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i" "i" "i" "i" "O!",
|
|
||||||
&bgl_var1, &bgl_var2, &bgl_var3, &bgl_var4, &buffer_Type, &bgl_buffer5))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
bufsize = 1;
|
|
||||||
for (i = 0; i < bgl_buffer5->ndimensions; i++)
|
|
||||||
bufsize *= bgl_buffer5->dimensions[i];
|
|
||||||
|
|
||||||
if (bgl_var1*bgl_var2 > bufsize)
|
|
||||||
return EXPP_ReturnPyObjError(PyExc_AttributeError,
|
|
||||||
"pixel buffer size can't be smaller than drawing rect area");
|
|
||||||
|
|
||||||
glDrawPixels (bgl_var1, bgl_var2, bgl_var3, bgl_var4,
|
|
||||||
(bgl_buffer5)->buf.asvoid);
|
|
||||||
|
|
||||||
return EXPP_incr_ret(Py_None);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BGL_Wrap(2, Accum, void, (GLenum, GLfloat))
|
BGL_Wrap(2, Accum, void, (GLenum, GLfloat))
|
||||||
BGL_Wrap(2, AlphaFunc, void, (GLenum, GLclampf))
|
BGL_Wrap(2, AlphaFunc, void, (GLenum, GLclampf))
|
||||||
@@ -511,7 +484,7 @@ BGL_Wrap(1, DepthMask, void, (GLboolean))
|
|||||||
BGL_Wrap(2, DepthRange, void, (GLclampd, GLclampd))
|
BGL_Wrap(2, DepthRange, void, (GLclampd, GLclampd))
|
||||||
BGL_Wrap(1, Disable, void, (GLenum))
|
BGL_Wrap(1, Disable, void, (GLenum))
|
||||||
BGL_Wrap(1, DrawBuffer, void, (GLenum))
|
BGL_Wrap(1, DrawBuffer, void, (GLenum))
|
||||||
/*BGL_Wrap(5, DrawPixels, void, (GLsizei, GLsizei, GLenum, GLenum, GLvoidP))*/
|
BGL_Wrap(5, DrawPixels, void, (GLsizei, GLsizei, GLenum, GLenum, GLvoidP))
|
||||||
BGL_Wrap(1, EdgeFlag, void, (GLboolean))
|
BGL_Wrap(1, EdgeFlag, void, (GLboolean))
|
||||||
BGL_Wrap(1, EdgeFlagv, void, (GLbooleanP))
|
BGL_Wrap(1, EdgeFlagv, void, (GLbooleanP))
|
||||||
BGL_Wrap(1, Enable, void, (GLenum))
|
BGL_Wrap(1, Enable, void, (GLenum))
|
||||||
|
|||||||
Reference in New Issue
Block a user