Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWillian Padovani Germano <wpgermano@gmail.com>2005-10-11 06:32:58 +0400
committerWillian Padovani Germano <wpgermano@gmail.com>2005-10-11 06:32:58 +0400
commitb970eadedfd9b70ba08a0c99e5f3fac3c31ec1e7 (patch)
treef8c2b04668ed3a951a98d8788d99fd49e9ff668e /release
parent93a4f6a876108a4dbbcbdbb5be9f3d690519ab5b (diff)
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.
Diffstat (limited to 'release')
-rw-r--r--release/scripts/console.py485
-rw-r--r--release/scripts/disp_paint.py387
-rw-r--r--release/scripts/hotkeys.py184
-rw-r--r--release/scripts/lightwave_export.py76
-rw-r--r--release/scripts/lightwave_import.py1694
-rw-r--r--release/scripts/obj_export.py301
-rw-r--r--release/scripts/obj_import.py938
-rw-r--r--release/scripts/skin.py905
-rw-r--r--release/scripts/tex2uvbaker.py67
-rw-r--r--release/scripts/uvpaint.py (renamed from release/scripts/UVpaint05.py)447
-rw-r--r--release/scripts/wings_export.py22
11 files changed, 3987 insertions, 1519 deletions
diff --git a/release/scripts/console.py b/release/scripts/console.py
index e95d6bc34b1..4ce58e06e10 100644
--- a/release/scripts/console.py
+++ b/release/scripts/console.py
@@ -18,11 +18,16 @@ that points to its official homepage, with news, downloads and documentation.
Usage:<br>
Type your code and hit "Enter" to get it executed.<br>
- Right mouse click: Console Menu (Save output, etc);<br>
+ - Mousewheel: Scroll text
- 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 + 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
from Blender import *
@@ -31,14 +36,18 @@ import StringIO
import types
# Constants
-__DELIMETERS__ = '. ,=+-*/%<>&~][{}():'
-__LINE_HISTORY__ = 200
+__DELIMETERS__ = '. ,=+-*/%<>&~][{}():\t'
+__VARIABLE_DELIMETERS__ = ' ,=+-*/%<>&~{}():\t'
+
+__LINE_HISTORY__ = 500
-global __LINE_HEIGHT__
-__LINE_HEIGHT__ = 14
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
@@ -52,10 +61,93 @@ def getActScriptWinRect():
return None
'''
-class cmdLine:
- # cmd: is the command string, or any other message
- # type: 0:user input 1:program feedback 2:error message. 3:option feedback
- # exe; 0- not yet executed 1:executed
+
+# menuText, # per group
+def PupMenuLess(menu, groupSize=35):
+ 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):
self.cmd = cmd
self.type = type
@@ -97,32 +189,68 @@ def insertCmdData(cmdBuffer):
COLLECTED_VAR_NAMES = {} # a list of keys, each key has a list of absolute paths
# 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
dirStringSplit = dirString.split('.')
exec('dirList = dir(%s)' % dirString)
for dirItem in dirList:
- if not dirItem.startswith('_'):
- if dirItem not in COLLECTED_VAR_NAMES.keys():
- COLLECTED_VAR_NAMES[dirItem] = []
+ if dirItem.startswith('_'):
+ continue
- # Add the string
- splitD = dirString.split('"')[-2]
- if splitD not in COLLECTED_VAR_NAMES[dirItem]:
- COLLECTED_VAR_NAMES[dirItem].append(splitD)
-
-
-
- # Stops recursice stuff, overlooping
- if type(dirItem) == types.ClassType or \
- type(dirItem) == types.ModuleType:
-
- print dirString, splitD, dirItem
-
- # Dont loop up dirs for strings ints etc.
- if d not in dirStringSplit:
- rdir( '%s.%s' % (dirString, d))
+ 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():
+ COLLECTED_VAR_NAMES[dirItem] = []
+
+ # Add the string
+ splitD = dirString.split('"')[-2]
+ if splitD not in COLLECTED_VAR_NAMES[dirItem]:
+ COLLECTED_VAR_NAMES[dirItem].append(splitD)
+
+
+ # Stops recursice stuff, overlooping
+ #print type(dirItem)
+ #if type(dirData) == types.ClassType or \
+ # type(dirData) == types.ModuleType:
+
+ 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.
+ if dirItem not in dirStringSplit:
+ 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():
global COLLECTED_VAR_NAMES
@@ -148,13 +276,17 @@ def runUserCode(__USER_CODE_STRING__):
# Try and run the user entered line(s)
try:
# Load all variabls from global dict to local space.
- for __TMP_VAR_NAME__ in __CONSOLE_VAR_DICT__.keys():
- exec('%s%s%s%s' % (__TMP_VAR_NAME__,'=__CONSOLE_VAR_DICT__["', __TMP_VAR_NAME__, '"]'))
+ for __TMP_VAR_NAME__, __TMP_VAR__ in __CONSOLE_VAR_DICT__.items():
+ exec('%s%s' % (__TMP_VAR_NAME__,'=__TMP_VAR__'))
del __TMP_VAR_NAME__
+ del __TMP_VAR__
# 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'))
+ # Flush global dict, allow the user to remove items.
+ __CONSOLE_VAR_DICT__ = {}
+
# Write local veriables to global __CONSOLE_VAR_DICT__
for __TMP_VAR_NAME__ in dir():
if __TMP_VAR_NAME__ != '__FILE_LIKE_STRING__' and\
@@ -167,14 +299,16 @@ def runUserCode(__USER_CODE_STRING__):
del __TMP_VAR_NAME__
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'):
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
# 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.
+
for line in __FILE_LIKE_STRING__.readlines():
cmdBuffer.append(cmdLine(line, 1, None))
@@ -203,34 +337,61 @@ def handle_event(evt, val):
#------------------------------------------------------------------------------#
def actionEnterKey():
global histIndex, cursor, cmdBuffer
- # Check for the neter kay hit
- if Window.GetKeyQualifiers() & Window.Qual.CTRL: # HOLDING DOWN SHIFT, GO TO NEXT LINE.
- cmdBuffer.append(cmdLine(' ', 0, 0))
- else:
+
+ def getIndent(string):
+ # 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:
+ 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,
- multiLineCode = ['if 1:']
- if cmdBuffer[-1].cmd != ' ':
- multiLineCode = ['%s%s' % (' ', cmdBuffer[-1].cmd)] # added space for fake if.
- else:
- cmdBuffer[-1].type = 1
- multiLineCode = []
- cmdBuffer[-1].exe = 1
- i = 2
+ multiLineCode = ['if 1:'] # End of the multiline first.
+
+ # Seek the start of the file multiline
+ i = 1
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
cmdBuffer[-i].type = 1
- else: # space added at the start for added if 1: statement
- multiLineCode.append('%s%s' % (' ', cmdBuffer[-i].cmd) )
+ else: # Tab added at the start for added if 1: statement
+ multiLineCode.append('\t%s' % cmdBuffer[-i].cmd )
# Mark as executed
- cmdBuffer[-i].exe = 1
- i+=1
-
- # add if to the end, reverse will make it the start.
- multiLineCode.append('if 1:')
- multiLineCode.reverse()
- multiLineCode.append(' pass') # Now this is the end
+ cmdBuffer[-i].exe = 1
+
+ multiLineCode.append('\tpass') # reverse will make this the start.
+ # Dubug, print the code that is executed.
+ #for m in multiLineCode: print m
runUserCode('\n'.join(multiLineCode))
@@ -262,9 +423,8 @@ def handle_event(evt, val):
def actionRightMouse():
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|Help|%l|Quit')
- # print choice
+ 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')
+
if choice == 1:
writeCmdData(cmdBuffer, 0) # type 0 user
elif choice == 2:
@@ -274,55 +434,56 @@ def handle_event(evt, val):
elif choice == 4:
writeCmdData(cmdBuffer, 3) # All
elif choice == 6:
- insertCmdData(cmdBuffer) # All
+ insertCmdData(cmdBuffer) # Insert text from Blender and run it.
elif choice == 8:
# Fontsize.
font_choice = Draw.PupMenu('Font Size%t|Large|Normal|Small|Tiny')
if font_choice != -1:
if font_choice == 1:
- __FONT_SIZE__ = 'large'
- __LINE_HEIGHT__ = 16
+ __FONT_SIZE__ = 3
elif font_choice == 2:
- __FONT_SIZE__ = 'normal'
- __LINE_HEIGHT__ = 14
+ __FONT_SIZE__ = 2
elif font_choice == 3:
- __FONT_SIZE__ = 'small'
- __LINE_HEIGHT__ = 12
+ __FONT_SIZE__ = 1
elif font_choice == 4:
- __FONT_SIZE__ = 'tiny'
- __LINE_HEIGHT__ = 10
+ __FONT_SIZE__ = 0
Draw.Redraw()
- elif choice == 10:
- Blender.ShowHelp('console.py')
- elif choice == 12: # Exit
+
+ elif choice == 10: # Exit
Draw.Exit()
# Auto compleating, quite complex- use recutsice dir for the moment.
def actionAutoCompleate(): # Ctrl + Tab
+ if not cmdBuffer[-1].cmd[:cursor].split():
+ return
+
+
RECURSIVE_DIR = recursive_dir()
# get last name of user input
editVar = cmdBuffer[-1].cmd[:cursor]
-
# Split off spaces operators etc from the staryt of the command so we can use the startswith function.
- for splitChar in __DELIMETERS__:
- editVar = editVar.split(splitChar)[-1]
+ for splitChar in __VARIABLE_DELIMETERS__:
+ editVar = editVar[:-1].split(splitChar)[-1] + editVar[-1]
+
# Now we should have the var by its self
if editVar:
-
possibilities = []
- print editVar, 'editVar'
for __TMP_VAR_NAME__ in RECURSIVE_DIR.keys():
+ #print '\t', __TMP_VAR_NAME__
if __TMP_VAR_NAME__ == editVar:
# print 'ADITVAR IS A VAR'
- continue
+ pass
+ '''
elif __TMP_VAR_NAME__.startswith( editVar ):
+ print __TMP_VAR_NAME__, 'aaa'
possibilities.append( __TMP_VAR_NAME__ )
-
-
+ '''
+ possibilities.append( __TMP_VAR_NAME__ )
+
if len(possibilities) == 1:
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
#cmdBuffer.insert(-1, cmdLine('options: %s' % ' '.join(possibilities), 3, None))
- menuText = 'Choices (hold shift for whole name)%t|'
- menuList = []
- menuListAbs = []
- possibilities.sort() # make nice :)
+ menuList = [] # A lits of tuples- ABSOLUTE, RELATIVE
+
for __TMP_VAR_NAME__ in possibilities:
for usage in RECURSIVE_DIR[__TMP_VAR_NAME__]:
# Account for non absolute (variables for eg.)
if usage: # not ''
- menuListAbs.append('%s.%s' % (usage, __TMP_VAR_NAME__)) # Used for names and can be entered when pressing shift.
- else:
- menuListAbs.append(__TMP_VAR_NAME__) # Used for names and can be entered when pressing shift.
-
- menuList.append(__TMP_VAR_NAME__) # Used for non Shift
+ absName = '%s.%s' % (usage, __TMP_VAR_NAME__)
+ if absName.find('.'+editVar) != -1 or\
+ 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.
+
+ # 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 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:]))
+ 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:]))
+
else:
# print 'NO EDITVAR'
return
- # ------------------end------------------#
-
+ # ------------------end------------------ #
+ # Quit from menu only
#if (evt == Draw.ESCKEY and not val):
# Draw.Exit()
if evt == Draw.MOUSEX: # AVOID TOO MANY REDRAWS.
@@ -370,15 +545,20 @@ def handle_event(evt, val):
return
+
global cursor
global histIndex
+ global __FONT_SIZE__
+ global __CONSOLE_LINE_OFFSET__
ascii = Blender.event
+ resetScroll = True
+
#------------------------------------------------------------------------------#
# key codes and key handling #
#------------------------------------------------------------------------------#
-
+
# UP DOWN ARROW KEYS, TO TRAVERSE HISTORY
if (evt == Draw.UPARROWKEY and val): actionUpKey()
elif (evt == Draw.DOWNARROWKEY and val): actionDownKey()
@@ -436,23 +616,57 @@ def handle_event(evt, val):
else:
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:
cmdBuffer[-1].cmd = cmdBuffer[-1].cmd[:cursor] + cmdBuffer[-1].cmd[cursor+1:]
cursor +=1
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:
insCh(chr(ascii))
else:
return # dont redraw.
+
+ # If the user types in anything then scroll to bottom.
+ if resetScroll:
+ __CONSOLE_LINE_OFFSET__ = 0
Draw.Redraw()
def draw_gui():
-
# Get the bounds from ObleGL directly
__CONSOLE_RECT__ = BGL.Buffer(BGL.GL_FLOAT, 4)
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.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
- cmd2curWidth = Draw.GetStringWidth(cmdBuffer[-1].cmd[:cursor], __FONT_SIZE__)
- BGL.glColor3f(0.8, 0.2, 0.2)
- if cmd2curWidth == 0:
- BGL.glRecti(0,2,2, __LINE_HEIGHT__+2)
- else:
- BGL.glRecti(cmd2curWidth-2,2,cmd2curWidth, __LINE_HEIGHT__+2)
+ 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)
+ if cmd2curWidth == 0:
+ BGL.glRecti(margin,2,margin+2, __FONT_SIZES__[__FONT_SIZE__][1]+2)
+ else:
+ BGL.glRecti(margin + cmd2curWidth-2,2, margin+cmd2curWidth, __FONT_SIZES__[__FONT_SIZE__][1]+2)
BGL.glColor3f(1,1,1)
# Draw the set of cammands to the buffer
-
- consoleLineIdx = 1
+ consoleLineIdx = __CONSOLE_LINE_OFFSET__ + 1
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:
BGL.glColor3f(1, 1, 1)
elif cmdBuffer[-consoleLineIdx].type == 1:
@@ -484,21 +702,22 @@ def draw_gui():
BGL.glColor3f(1.0, 0, 0)
elif cmdBuffer[-consoleLineIdx].type == 3:
BGL.glColor3f(0, 0.8, 0)
- else:
+ else:
BGL.glColor3f(1, 1, 0)
if consoleLineIdx == 1: # NEVER WRAP THE USER INPUT
- BGL.glRasterPos2i(0, (__LINE_HEIGHT__*consoleLineIdx) - 8)
- Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZE__)
+ BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * (consoleLineIdx-__CONSOLE_LINE_OFFSET__)) - 8)
+ # BUG, LARGE TEXT DOSENT DISPLAY
+ Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0])
else: # 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 = []
copyCmd = [cmdBuffer[-consoleLineIdx].cmd, '']
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
copyCmd[1] = '%s%s'% (copyCmd[0][-1], copyCmd[1]) # Add the char on the end
copyCmd[0] = copyCmd[0][:-1]# remove last chat
@@ -513,17 +732,16 @@ def draw_gui():
# Now we have a list of lines, draw them (OpenGLs reverse ordering requires this odd change)
wrapLineList.reverse()
for wline in wrapLineList:
- BGL.glRasterPos2i(0, (__LINE_HEIGHT__*(consoleLineIdx + wrapLineIndex)) - 8)
- Draw.Text(wline, __FONT_SIZE__)
+ BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1]*((consoleLineIdx-__CONSOLE_LINE_OFFSET__) + wrapLineIndex)) - 8)
+ Draw.Text(wline, __FONT_SIZES__[__FONT_SIZE__][0])
wrapLineIndex += 1
wrapLineIndex-=1 # otherwise we get a silly extra line.
else: # no wrapping.
- BGL.glRasterPos2i(0, (__LINE_HEIGHT__*(consoleLineIdx+wrapLineIndex)) - 8)
- Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZE__)
-
-
+ BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * ((consoleLineIdx-__CONSOLE_LINE_OFFSET__)+wrapLineIndex)) - 8)
+ Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0])
+
consoleLineIdx += 1
@@ -536,42 +754,45 @@ def handle_button_event(evt):
__CONSOLE_VAR_DICT__ = {} # Initialize var dict
-# Print Startup lines
-cmdBuffer = [cmdLine("Welcome to Ideasman's Blender Console", 1, None),\
- cmdLine(' * Right Click: Console Menu (Save output, etc.)', 1, None),\
- cmdLine(' * Arrow Keys: Command history and cursor', 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)]
+# Print Startup lines, add __bpydoc__ to the console startup.
+cmdBuffer = []
+for l in __bpydoc__.split('<br>'):
+ cmdBuffer.append( cmdLine(l, 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.
# 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):
# touch the file
+ cmdBuffer.append(cmdLine('...console_autoexec.py not found, making new in scripts dir', 1, None))
open(console_autoexec, 'w').close()
- cmdBuffer.append(cmdLine('...console_autoexec.py not found, making new in scripts data dir', 1, None))
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---------------------------------------------------------------------#
# 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__
-def autoexecToVarList():
+def include_console(includeFile):
global __CONSOLE_VAR_DICT__ # write autoexec vars to this.
# Execute an external py file as if local
- exec(include(console_autoexec))
+ exec(include(includeFile))
# Write local to global __CONSOLE_VAR_DICT__ for reuse,
for __TMP_VAR_NAME__ in dir() + dir(Blender):
# Execute the local > global coversion.
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-----------------------------------------------------------------#
diff --git a/release/scripts/disp_paint.py b/release/scripts/disp_paint.py
index e7628a00cae..e5ce81f65f3 100644
--- a/release/scripts/disp_paint.py
+++ b/release/scripts/disp_paint.py
@@ -2,7 +2,7 @@
""" Registration info for Blender menus: <- these words are ignored
Name: 'Dispaint'
-Blender: 233
+Blender: 237
Group: 'Mesh'
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",
"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")
-__version__ = "233i"
+__version__ = "237"
__bpydoc__ = """\
This script displaces mesh vertices according to vertex color values.
@@ -81,6 +81,7 @@ from Blender.Draw import *
from Blender.BGL import *
from Blender.Noise import *
from Blender.Scene import *
+from Blender.Window import *
sc=Scene.getCurrent()
# niveau du deplacement
@@ -117,6 +118,7 @@ E_AXESELX = 46
E_AXESELY = 47
E_AXESELZ = 48
+
E_NOISEME = 49
E_NOISEH = 50
E_NOISELAC = 51
@@ -126,10 +128,28 @@ E_NOISEBAS = 54
E_NOISEVAL=[E_NOISEH,E_NOISELAC,E_NOISEOCT,E_NOISEOFF,E_NOISEBAS]
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 "
CreateTIP="Create a new copy of the selected shape"
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):
Obis.setSize(ozero.getSize());
@@ -298,9 +318,23 @@ def DOCMat_list(TMATList):
TMATList[0]=0
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"
-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)
ORIENTMenu = Create(1)
@@ -351,48 +385,190 @@ glCl3=glColor3f
glCl4=glColor4f
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():
global MODEMenu, NSIZE, TDOCMat,TMATList, TAXEList
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 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)
glGetFloatv(GL_SCISSOR_BOX, size)
size= size.list
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)
- glColor3f(0.0,0.0,0.0)
- glRectf(4,size[3],534,size[3]-32 )
+ glColor3f(0.66,0.66,0.66)
+ 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)
glRasterPos2f(20, size[3]-15)
- Text("Script Python de displacement paintingt")
+ Text("Script Python de displacement painting")
glRasterPos2f(20, size[3]-28)
- Text("Jean-michel Soler, juillet 2004")
+ Text("Jean-michel Soler, Aout 2005")
n0=70
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)
glRasterPos2f(80 ,size[3]-n0+24)
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:
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],
TMATList[1][t][1],
TMATList[1][t][2])
- glRct(80+t*40,
- size[3]-n0-60,
- 80+t*40+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)
+
+ if t<=7:
+ glRct(80+t*40,
+ size[3]-n0-60,
+ 80+t*40+40,
+ size[3]-n0-60+40)
+ 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)
- glRasterPos2f(80+40+5 ,size[3]-n0-80)
+ glRasterPos2f(80+40+5 ,size[3]-n0-110)
if ERROR>1:
Text('Last error : '+TextERROR)
else:
@@ -417,35 +601,66 @@ def draw():
glColor3f(0.0,0.0,0.0)
glRasterPos2f(240 ,size[3]-n0+24)
- Text("ORIENTATION")
- ORIENTMenu= Menu(ORname, E_ORIENT ,240 ,size[3]-n0 ,100,20, ORIENTMenu.val, "ORIENT menu.")
- if ORIENTMenu.val==2 :
- for t in range(3):
- TAXEList[1][t]=Toggle("%s"%TAXEList[0][t],
- E_AXESEL+t,
- 240+100+t*30 , size[3]-n0 ,30 , 20,
- TAXEList[1][t].val)
+ 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 :
+ for t in [0,1]:
+ TAXEList[1][t]=Toggle("%s"%TAXEList[0][t],
+ E_AXESEL+t,
+ 240+100+t*30+2 , size[3]-n0+10 ,28 , 18,
+ 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 :
+ glRasterPos2f(240 ,size[3]-n0-120-4)
+ Text("NOISE")
+ 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-172 ,110,20, NOISEDIMbout.val, 1,100)
+ if NOISEMenu.val==11:
+ basisBout=Slider(noiseTYPE[basisBout.val],
+ E_NOISEBAS ,40 ,size[3]-n0-178 ,175,20, basisBout.val, 0,9,)
+ 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-218 ,175,20, lacunarityBout.val, -4.0,+4.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 ,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.")
-
- if ORIENTMenu.val==3 :
- glRasterPos2f(240 ,size[3]-n0-90-4)
- Text("NOISE")
- NOISEMenu= Menu(NOname, E_NOISEME , 240 ,size[3]-n0-118 ,110,20, NOISEMenu.val, "NOISE menu.")
- NOISEDIMbout=Number(" Dim: " ,E_NOISEDIM , 240 ,size[3]-n0-138 ,110,20, NOISEDIMbout.val, 1,100)
-
- if NOISEMenu.val==11:
- basisBout=Slider(noiseTYPE[basisBout.val],
- E_NOISEBAS ,40 ,size[3]-n0-118 ,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,)
- lacunarityBout=Slider("lacunarity", E_NOISELAC ,40 ,size[3]-n0-158 ,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,)
- offsetBout=Slider("offset", E_NOISEOFF ,40 ,size[3]-n0-198 ,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.")
-
-
+ 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):
if (evt== QKEY and not val): Exit()
@@ -455,21 +670,20 @@ def bevent(evt):
global mat, ORIENTMenu, NRepeat, TAXEList
global ERROR,TextERROR, NOISE, NOISEMenu, NOISEDIMbout,NOISEDIM
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):
Exit()
-
-
elif (evt== E_ACTION):
for n in range(NRepeat.val):
paint()
-
elif (evt== E_NSIZE):
ng=NSIZE.val
-
elif (evt== E_DOCMAT) or (evt in E_MATVAL):
Me=Object.GetSelected()
+
if Me!=[]:
if Me[0].getType()=='Mesh':
TMATList=DOCMat_list(TMATList)
@@ -484,29 +698,68 @@ def bevent(evt):
else:
ERROR=1
TextERROR='No Selected Object.'
-
-
elif (evt== E_CREATE):
-
NEWMEcreation(Blender.Object.GetSelected()[0])
Blender.Draw.Redraw()
-
ERROR=1
TextERROR='No Selected Object.'
-
elif (evt== E_NOISEME):
NOISE=NOISEMenu.val-1
-
elif (evt in E_NOISEVAL):
H=HBout.val
lacunarity=lacunarityBout.val
octaves=octavesBout.val
offset=offsetBout.val
basis=basisBout.val
-
elif (evt== E_NOISEDIM):
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()
-
Register(draw, event, bevent)
diff --git a/release/scripts/hotkeys.py b/release/scripts/hotkeys.py
index ca2ef1689cb..d56951959c3 100644
--- a/release/scripts/hotkeys.py
+++ b/release/scripts/hotkeys.py
@@ -2,7 +2,7 @@
""" Registration info for Blender menus:
Name: 'HotKey and MouseAction Reference'
-Blender: 232
+Blender: 237
Group: 'Help'
Tip: 'All the hotkeys/short keys'
"""
@@ -11,7 +11,7 @@ __author__ = "Jean-Michel Soler (jms)"
__url__ = ("blender", "elysiun",
"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")
-__version__ = "10/2004"
+__version__ = "10/04/2005"
__bpydoc__ = """\
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>
Additional entries in the database (c) 2004 by Bart.
+ Additional entries in the database for blender 2.37 (c) 2005 by jms.
+
"""
# $Id$
@@ -67,11 +69,12 @@ from Blender.Draw import *
from Blender.BGL import *
hotkeys={
+'Search ':[['', '']],
'Specials 1 ':[
[',', 'Set Bounding Box rotation scaling pivot'],
['Ctrl-,', 'Set Median Point 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: ö)'],
['Shift-~', 'Display all/previous layers (German keys: Shift-ö)'],
['Space', 'Popup menu'],
@@ -82,9 +85,10 @@ hotkeys={
['TAB', 'IPO: Edit selected'],
['Ctrl-TAB', 'Enter/exit Pose 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']
],
+
'Mouse ':[
['Actions:', ''],
['LMB', '3D View: Set 3D Cursor'],
@@ -111,6 +115,7 @@ hotkeys={
['MMB', 'Toggle optional transform feature'],
['RMB', 'Abort transformation']
],
+
'F-Keys ':[
['F1', 'Open File'],
['F2', 'Save File'],
@@ -133,13 +138,18 @@ hotkeys={
['Shift-F7', 'Buttons Window'],
['Shift-F8', 'Video Sequencer Window'],
['Shift-F9', 'OOP Window'],
+['Alt-Shift-F9', 'OutLiner Window'],
['Shift-F10', 'UV Image 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 ':[
['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'],
['Shift-1..2..0-=', 'Toggle layer 1..2..12'],
['Shift-ALT-...', 'Toggle layer 11..12..20']
@@ -150,10 +160,12 @@ hotkeys={
['Numpad /', 'Local view on object (hide others)'],
['Numpad *', 'Rotate view to objects local axes'],
['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'],
['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'],
['Numpad INS', 'Set Camera view'],
['Ctrl-Numpad INS', 'Set active object as camera'],
@@ -174,10 +186,19 @@ hotkeys={
'Arrows ':[
['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'],
['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'],
['Ctrl-PgDn', 'IPO: Select and jump to previous keyframe'],
+['Ctrl-PgDn', 'TimeLine: Jump to prev key'],
['Left', 'One frame backwards'],
['Right', 'One frame forwards'],
['Down', '10 frames backwards'],
@@ -191,7 +212,9 @@ hotkeys={
['Shift-Arrow', 'Toggle first frame/ last frame']
],
-'Letters ':[ {"A":[
+'Letters ':[
+{
+"A":[
['A', 'Select all/Deselect all'],
['Alt-A', 'Play animation in current window'],
['Ctrl-A', 'Apply objects size/rotation to object data'],
@@ -199,7 +222,8 @@ hotkeys={
['Shift-A', 'Sequencer: Add menu'],
['Shift-A', '3D-View: Add menu'],
['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":[
@@ -214,6 +238,7 @@ hotkeys={
['C', 'UV Image Editor: Active Face Select toggle'],
['C', 'Sequencer: Change images'],
['C', 'IPO: Snap current frame to selected key'],
+['C', 'TimeLine: Center View'],
['Alt-C', 'Object Mode: Convert menu'],
['Alt-C', 'Text Editor: Copy selection to clipboard'],
['Ctrl-C', 'Copy menu (Copy properties of active to selected objects)'],
@@ -232,6 +257,7 @@ hotkeys={
"E":[
['E', 'Edit Mode: Extrude'],
['E', 'UV Image Editor: LSCM Unwrap'],
+['E', 'TimeLine: Set End'],
['ER', 'Edit Mode: Extrude Rotate'],
['ES', 'Edit Mode: Extrude Scale'],
['ESX', 'Edit Mode: Extrude Scale X axis'],
@@ -267,10 +293,13 @@ hotkeys={
"H":[
['H', 'Hide selected vertices/faces'],
['H', 'Curves: Set handle type'],
+['H', 'Action editor: Handle type aligned'],
+['H', 'Action editor: Handle type free'],
['Alt-H', 'Show Hidden vertices/faces'],
-['Ctrl-H', 'Curves: Automatic handle calculation'],
-['Shift-H', 'Hide deselected vertices/faces'],
-['Shift-H', 'Curves: Set handle type']
+['Shift-H', 'Curves: Automatic handle calculation'],
+['Shift-H', 'Action editor: Handle type auto'],
+['Shift-H', 'Edit Mode, Hide deselected vertices/faces'],
+['Ctrl-H', 'Edit Mode, Add a hook on selected points or show the hook menu .']
],
"I":[
@@ -279,12 +308,11 @@ hotkeys={
"J":[
['J', 'IPO: Join menu'],
-['J', 'Mesh: Join all adjacent triangles to quads'],
+['J', 'Mesh: Join all adjacent triangles to quads'],
['J', 'Render Window: Swap render buffer'],
['Ctrl-J', 'Join selected objects'],
['Ctrl-J', 'Nurbs: Add segment'],
['Ctrl-J', 'IPO: Join keyframes menu'],
-['Alt-J', 'Edit Mode: convert quads to triangles']
],
"K":[
@@ -304,7 +332,7 @@ hotkeys={
['L', 'Edit mode: Select linked vertices (near mouse pointer)'],
['L', 'OOPS window: Select linked objects'],
['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']
],
@@ -312,8 +340,12 @@ hotkeys={
['M', 'Move object to different layer'],
['M', 'Sequencer: Make meta strip (group) from selected strips'],
['M', 'Edit Mode: Mirros Axis menu'],
+['M', 'Video Sequence Editor : Make Meta strip...'],
+['M', 'TimeLine: Add marker'],
['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":[
@@ -360,6 +392,7 @@ hotkeys={
"S":[
['S', 'Scale'] ,
+['S', 'TimeLine: Set Start'],
['SX', 'Flip around X axis'] ,
['SY', 'Flip around Y axis'] ,
['SZ', 'Flip around Z axis'] ,
@@ -376,14 +409,15 @@ hotkeys={
['T', 'Adjust texture space'] ,
['T', 'Edit mode: Flip 3d curve'] ,
['T', 'IPO: Change IPO type'] ,
+['T', 'TimeLine: Show second'],
['Alt-T', 'Clear tracking of object'] ,
['Ctrl-T', 'Make selected object track active object'] ,
['Ctrl-T', 'Edit Mode: Convert to triangles'] ,
['Ctrl-ALT-T', 'Benchmark'] ],
"U":[
-['U', 'Make single user menu'] ,
-['U', '3D View: Global undo'] ,
+['U', 'Make single user menu (for import completly linked object to another scene for instance) '] ,
+['U', '3D View: Make Single user Menu'] ,
['U', 'Edit Mode: Reload object data from before entering Edit Mode'] ,
['U', 'UV Face Select: Automatic UV calculation menu'] ,
['U', 'Vertex-/Weightpaint mode: Undo'] ,
@@ -395,9 +429,11 @@ hotkeys={
['V', 'Curves/Nurbs: Vector handle'],
['V', 'Vertexpaint mode'],
['V', 'UV Image Editor: Stitch UVs'],
+['V', 'Action editor: Vector'],
['Alt-V', "Scale object to match image texture's aspect ratio"],
['Shift-V', 'Edit mode: Align view to selected vertices'],
['Shift-V', 'UV Image Editor: Limited Stitch UVs popup'],
+
],
"W":[
@@ -408,11 +444,16 @@ hotkeys={
['WY', 'UV Image Editor: Weld/Align Y axis'],
['Ctrl-W', 'Save current file'] ,
['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', 'Delete menu'] ,
-['Ctrl-X', 'Restore default state (Erase all)'] ],
+['X', 'TimeLine: Remove marker'],
+['Ctrl-X', 'Restore default state (Erase all)']
+
+ ],
"Y":[
['Y', 'Mesh: Split selected vertices/faces from the rest'] ],
@@ -429,6 +470,12 @@ hotkeys={
up=128
down=129
UP=0
+SEARCH=131
+OLDSEARCHLINE=''
+SEARCHLINE=Create('')
+LINE=130
+FINDED=[]
+LEN=0
for k in hotkeys.keys():
hotkeys[k].append(Create(0))
@@ -442,6 +489,24 @@ hotL.sort()
hot=hotkeys.keys()
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
glCl3=glColor3f
glCl4=glColor4f
@@ -462,8 +527,8 @@ def trace_rectangle3(r,c,c1):
glCl3(c1[0],c1[1],c1[2])
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)
glGetFloatv(GL_SCISSOR_BOX, size)
size= size.list
@@ -490,7 +555,7 @@ def draw():
glRasterPos2f(42, size[3]-25)
Text("HotKey and MouseAction Reference")
-
+
l=0
listed=0
Llisted=0
@@ -499,14 +564,12 @@ def draw():
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, 78*hot.index(k), size[3]-(47), 78, 24, hotkeys[k][-1].val )
-
l+=len(k)
-
if hotkeys[k][-1].val==1.0:
listed=hot.index(k)
l=0
size[3]=size[3]-4
- if hot[listed]!='Letters ':
+ if hot[listed]!='Letters ' and hot[listed]!='Search ' :
size[3]=size[3]-8
SCROLL=size[3]/21
END=-1
@@ -520,9 +583,7 @@ def draw():
UP=len(hotkeys[hot[listed]][:-1])-SCROLL
else :
UP=0
-
for n in hotkeys[hot[listed]][:-1][UP:END]:
-
if l%2==0:
r=[0,size[3]-(21*l+66),
size[2], size[3]-(21*l+43)]
@@ -533,20 +594,50 @@ def draw():
glRasterPos2f(4+8*15, size[3]-(58+21*l))
Text(' : '+n[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:
for k in hotL:
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 )
if hotkeys['Letters '][0][k][-1].val==1.0:
Llisted=pos
-
size[3]=size[3]-8
-
SCROLL=(size[3]-88)/21
END=-1
if SCROLL < len(hotkeys['Letters '][0][hotL[Llisted]]):
- Button('/\\',up,4,size[3]+8,20,14,'Scroll up')
- Button('\\/',down,4,size[3]-8,20,14,'Scroll down')
+ LEN=len(hotkeys['Letters '][0][hotL[Llisted]])
+ 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]]):
END=(UP+SCROLL)
else:
@@ -569,13 +660,27 @@ def draw():
l+=1
def event(evt, val):
- global hotkeys, UP
- if ((evt== QKEY or evt== ESCKEY) and not val):
+ global hotkeys, UP, SCROLL , LEN
+ if (evt== QKEY or evt== ESCKEY):
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):
- global hotkeysmhot, hotL, up,down,UP
+ global hotkeysmhot, hotL, up,down,UP, FINDED
+ global SEARCH, SEARCHLINE,LINE, OLDSEARCHLINE
if (evt== 1):
Exit()
@@ -602,4 +707,11 @@ def bevent(evt):
if UP>0: UP-=1
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)
diff --git a/release/scripts/lightwave_export.py b/release/scripts/lightwave_export.py
index dc14d036503..a109acc02c1 100644
--- a/release/scripts/lightwave_export.py
+++ b/release/scripts/lightwave_export.py
@@ -26,7 +26,7 @@ Usage:<br>
Supported:<br>
UV Coordinates, Meshes, Materials, Material Indices, Specular
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>
Not too much, I hope! :).
@@ -95,6 +95,7 @@ def write(filename):
bbox = generate_bbox(mesh)
pols = generate_pols(mesh)
ptag = generate_ptag(mesh, material_names)
+ clip = generate_clip(mesh, material_names)
if mesh.hasFaceUV():
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, "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.average_vcols:
write_chunk(meshdata, "VMAP", vmap_vc)
@@ -122,6 +119,13 @@ def write(filename):
else:
write_chunk(meshdata, "VMAD", 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
for surf in surfs:
@@ -135,6 +139,7 @@ def write(filename):
file.write(meshdata.getvalue()); meshdata.close()
for surf in surfs:
write_chunk(file, "SURF", surf)
+ write_chunk(file, "DATE", "August 19, 2005")
Blender.Window.DrawProgressBar(1.0, "") # clear progressbar
file.close()
@@ -456,6 +461,46 @@ def generate_surf(material_name):
comment = generate_nstring(comment)
data.write(struct.pack(">H", len(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()
# =============================================
@@ -536,6 +581,27 @@ def generate_icon():
#print len(icon_data)
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 ===
# ===================
diff --git a/release/scripts/lightwave_import.py b/release/scripts/lightwave_import.py
index 7e479536678..8680890b0ce 100644
--- a/release/scripts/lightwave_import.py
+++ b/release/scripts/lightwave_import.py
@@ -1,46 +1,22 @@
#!BPY
-
"""
-Name: 'LightWave (.lwo)...'
-Blender: 232
+Name: 'LightWave + Materials (.lwo)...'
+Blender: 237
Group: 'Import'
Tooltip: 'Import LightWave Object File Format (.lwo)'
"""
-__author__ = "Anthony D'Agostino (Scorpius)"
+__author__ = "Alessandro Pirovano, Anthony D'Agostino (Scorpius)"
__url__ = ("blender", "elysiun",
-"Author's homepage, http://www.redrival.com/scorpius")
-__version__ = "Part of IOSuite 0.5"
-
-__bpydoc__ = """\
-This script imports LightWave files to Blender.
-
-LightWave is a full-featured commercial modeling and rendering
-application. The lwo file format is composed of 'chunks,' is well
-defined, and easy to read and write. It is similar in structure to the
-trueSpace cob format.
-
-Usage:<br>
- Execute this script from the "File->Import" menu and choose a LightWave
-file to open.
-
-Supported:<br>
- Meshes only.
-
-Missing:<br>
- Materials, UV Coordinates, and Vertex Color info will be ignored.
-
-Known issues:<br>
- Triangulation of convex polygons works fine, and uses a very simple
-fanning algorithm. Convex polygons (i.e., shaped like the letter "U")
-require a different algorithm, and will be triagulated incorrectly.
-
-Notes:<br>
- Also reads lwo files in the old LW v5.5 format.
-"""
+"Author's homepage, http://www.redrival.com/scorpius", "Author's homepage, http://uaraus.altervista.org")
-# $Id$
-#
+importername = "lwo_import 0.1.16"
+# +---------------------------------------------------------+
+# | Save your work before and after use. |
+# | Please report any useful comment to: |
+# | uaraus-dem@yahoo.it |
+# | Thanks |
+# +---------------------------------------------------------+
# +---------------------------------------------------------+
# | Copyright (c) 2002 Anthony D'Agostino |
# | http://www.redrival.com/scorpius |
@@ -51,156 +27,1578 @@ Notes:<br>
# +---------------------------------------------------------+
# | Read and write LightWave Object File Format (*.lwo) |
# +---------------------------------------------------------+
+# +---------------------------------------------------------+
+# | Alessandro Pirovano tweaked starting on March 2005 |
+# | http://uaraus.altervista.org |
+# +---------------------------------------------------------+
+# +---------------------------------------------------------+
+# | Release log: |
+# | 0.1.16: fixed (try 2) texture offset calculations |
+# | added hint on axis mapping |
+# | added hint on texture blending mode |
+# | added hint on texture transparency setting |
+# | search images in original directory first |
+# | fixed texture order application |
+# | 0.1.15: added release log |
+# | fixed texture offset calculations (non-UV) |
+# | fixed reverting vertex order in face generation |
+# | associate texture on game-engine settings |
+# | vector math definitely based on mathutils |
+# | search images in "Images" and "../Images" dir |
+# | revised logging facility |
+# | fixed subsurf texture and material mappings |
+# | 0.1.14: patched missing mod_vector (not definitive) |
+# | 0.1.13: first public release |
+# +---------------------------------------------------------+
+
+#blender related import
+import Blender
+
+#iosuite related import
+try: #new naming
+ import meshtools as my_meshtools
+except ImportError: #fallback to the old one
+ print "using old mod_meshtools"
+ import mod_meshtools as my_meshtools
+
+#python specific modules import
+import struct, chunk, os, cStringIO, time, operator, copy
-import Blender, meshtools
-import struct, chunk, os, cStringIO, time, operator
+# ===========================================================
+# === Utility Preamble ======================================
+# ===========================================================
+
+textname = "lwo_log"
+#uncomment the following line to disable logging facility
+#textname = None 1
+
+# ===========================================================
+
+class dotext:
+
+ _NO = 0 #use internal to class only
+ LOG = 1 #write only to LOG
+ CON = 2 #write to both LOG and CONSOLE
+
+ def __init__(self, tname, where=LOG):
+ self.dwhere = where #defaults on console only
+ if (tname==None):
+ print "*** not using text object to log script"
+ self.txtobj = None
+ return
+ tlist = Blender.Text.get()
+ for i in range(len(tlist)):
+ if (tlist[i].getName()==tname):
+ tlist[i].clear()
+ #print tname, " text object found and cleared!"
+ self.txtobj = tlist[i]
+ return
+ #print tname, " text object not found and created!"
+ self.txtobj = Blender.Text.New(tname)
+ # end def __init__
+
+ def write(self, wstring, maxlen=100):
+ if (self.txtobj==None): return
+ while (1):
+ ll = len(wstring)
+ if (ll>maxlen):
+ self.txtobj.write((wstring[:maxlen]))
+ self.txtobj.write("\n")
+ wstring = (wstring[maxlen:])
+ else:
+ self.txtobj.write(wstring)
+ break
+ # end def write
+
+ def pstring(self, ppstring, where = _NO):
+ if where == dotext._NO: where = self.dwhere
+ if where == dotext.CON:
+ print ppstring
+ self.write(ppstring)
+ self.write("\n")
+ # end def pstring
+
+ def plist(self, pplist, where = _NO):
+ self.pprint ("list:[")
+ for pp in range(len(pplist)):
+ self.pprint ("[%d] -> %s" % (pp, pplist[pp]), where)
+ self.pprint ("]")
+ # end def plist
+
+ def pdict(self, pdict, where = _NO):
+ self.pprint ("dict:{", where)
+ for pp in pdict.keys():
+ self.pprint ("[%s] -> %s" % (pp, pdict[pp]), where)
+ self.pprint ("}")
+ # end def pdict
+
+ def pprint(self, parg, where = _NO):
+ if parg == None:
+ self.pstring("_None_", where)
+ elif type(parg) == type ([]):
+ self.plist(parg, where)
+ elif type(parg) == type ({}):
+ self.pdict(parg, where)
+ else:
+ self.pstring(parg, where)
+ # end def pprint
+
+ def logcon(self, parg):
+ self.pprint(parg, dotext.CON)
+ # end def logcon
+# endclass dotext
+
+tobj=dotext(textname)
+#uncomment the following line to log all messages on both console and logfile
+#tobj=dotext(textname,dotext.CON)
+
+
+# ===========================================================
+# === Main read functions ===================================
+# ===========================================================
# =============================
# === Read LightWave Format ===
# =============================
def read(filename):
- start = time.clock()
- file = open(filename, "rb")
-
- # === LWO header ===
- form_id, form_size, form_type = struct.unpack(">4s1L4s", file.read(12))
- if (form_type != "LWOB") and (form_type != "LWO2"):
- print "Can't read a file with the form_type:", form_type
- return
-
- objname = os.path.splitext(os.path.basename(filename))[0]
-
- while 1:
- try:
- lwochunk = chunk.Chunk(file)
- except EOFError:
- break
- if lwochunk.chunkname == "LAYR":
- objname = read_layr(lwochunk)
- elif lwochunk.chunkname == "PNTS": # Verts
- verts = read_verts(lwochunk)
- elif lwochunk.chunkname == "POLS" and form_type == "LWO2": # Faces v6.0
- faces = read_faces_6(lwochunk)
- meshtools.create_mesh(verts, faces, objname)
- elif lwochunk.chunkname == "POLS" and form_type == "LWOB": # Faces v5.5
- faces = read_faces_5(lwochunk)
- meshtools.create_mesh(verts, faces, objname)
- else: # Misc Chunks
- lwochunk.skip()
-
- Blender.Window.DrawProgressBar(1.0, "") # clear progressbar
- file.close()
- end = time.clock()
- seconds = " in %.2f %s" % (end-start, "seconds")
- if form_type == "LWO2": fmt = " (v6.0 Format)"
- if form_type == "LWOB": fmt = " (v5.5 Format)"
- message = "Successfully imported " + os.path.basename(filename) + fmt + seconds
- meshtools.print_boxed(message)
+ global tobj
+
+ tobj.logcon ("#####################################################################")
+ tobj.logcon ("This is: %s" % importername)
+ tobj.logcon ("Importing file:")
+ tobj.logcon (filename)
+ tobj.pprint ("#####################################################################")
+
+ start = time.clock()
+ file = open(filename, "rb")
+
+ # === LWO header ===
+ form_id, form_size, form_type = struct.unpack(">4s1L4s", file.read(12))
+ if (form_type == "LWOB"):
+ read_lwob(file, filename)
+ elif (form_type == "LWO2"):
+ read_lwo2(file, filename)
+ else:
+ tobj.logcon ("Can't read a file with the form_type: %s" %form_type)
+ return
+
+ Blender.Window.DrawProgressBar(1.0, "") # clear progressbar
+ file.close()
+ end = time.clock()
+ seconds = " in %.2f %s" % (end-start, "seconds")
+ if form_type == "LWO2": fmt = " (v6.0 Format)"
+ if form_type == "LWOB": fmt = " (v5.5 Format)"
+ message = "Successfully imported " + os.path.basename(filename) + fmt + seconds
+ #my_meshtools.print_boxed(message)
+ tobj.pprint ("#####################################################################")
+ tobj.logcon (message)
+ tobj.logcon ("#####################################################################")
+# enddef read
+
+
+# =================================
+# === Read LightWave 5.5 format ===
+# =================================
+def read_lwob(file, filename):
+ global tobj
+
+ tobj.logcon("LightWave 5.5 format")
+ objname = os.path.splitext(os.path.basename(filename))[0]
+
+ while 1:
+ try:
+ lwochunk = chunk.Chunk(file)
+ except EOFError:
+ break
+ if lwochunk.chunkname == "LAYR":
+ objname = read_layr(lwochunk)
+ elif lwochunk.chunkname == "PNTS": # Verts
+ verts = read_verts(lwochunk)
+ elif lwochunk.chunkname == "POLS": # Faces v5.5
+ faces = read_faces_5(lwochunk)
+ my_meshtools.create_mesh(verts, faces, objname)
+ else: # Misc Chunks
+ lwochunk.skip()
+ return
+# enddef read_lwob
+
+
+# =============================
+# === Read LightWave Format ===
+# =============================
+def read_lwo2(file, filename, typ="LWO2"):
+ global tobj
+
+ tobj.logcon("LightWave 6 (and above) format")
+
+ dir_part = Blender.sys.dirname(filename)
+ fname_part = Blender.sys.basename(filename)
+
+ #first initialization of data structures
+ defaultname = os.path.splitext(fname_part)[0]
+ tag_list = [] #tag list: global for the whole file?
+ surf_list = [] #surf list: global for the whole file?
+ clip_list = [] #clip list: global for the whole file?
+ object_index = 0
+ object_list = None
+ # init value is: object_list = [[None, {}, [], [], {}, {}, 0, {}, {}]]
+ #0 - objname #original name
+ #1 - obj_dict = {TAG} #objects created
+ #2 - verts = [] #object vertexes
+ #3 - faces = [] #object faces (associations poly -> vertexes)
+ #4 - obj_dim_dict = {TAG} #tuples size and pos in local object coords - used for NON-UV mappings
+ #5 - polytag_dict = {TAG} #tag to polygon mapping
+ #6 - patch_flag #0 = surf; 1 = patch (subdivision surface) - it was the image list
+ #7 - uvcoords_dict = {name} #uvmap coordinates (mixed mode per face/per vertex)
+ #8 - facesuv_dict = {name} #uvmap coordinates associations poly -> uv tuples
+
+ while 1:
+ try:
+ lwochunk = chunk.Chunk(file)
+ except EOFError:
+ break
+ tobj.pprint(" ")
+ if lwochunk.chunkname == "LAYR":
+ tobj.pprint("---- LAYR")
+ objname = read_layr(lwochunk)
+ tobj.pprint(objname)
+ if object_list == None:
+ object_list = [[objname, {}, [], [], {}, {}, 0, {}, {}]]
+ else:
+ object_list.append([objname, {}, [], [], {}, {}, 0, {}, {}])
+ object_index += 1
+ elif lwochunk.chunkname == "PNTS": # Verts
+ tobj.pprint("---- PNTS")
+ verts = read_verts(lwochunk)
+ object_list[object_index][2] = verts
+ elif lwochunk.chunkname == "VMAP": # MAPS (UV)
+ tobj.pprint("---- VMAP")
+ object_list[object_index][7], object_list[object_index][8] = read_vmap(object_list[object_index][7], object_list[object_index][8], object_list[object_index][3], len(object_list[object_index][2]), lwochunk)
+ elif lwochunk.chunkname == "VMAD": # MAPS (UV) per-face
+ tobj.pprint("---- VMAD")
+ object_list[object_index][7], object_list[object_index][8] = read_vmad(object_list[object_index][7], object_list[object_index][8], object_list[object_index][3], len(object_list[object_index][2]), lwochunk)
+ elif lwochunk.chunkname == "POLS": # Faces v6.0
+ tobj.pprint("-------- POLS(6)")
+ faces, flag = read_faces_6(lwochunk)
+ #flag is 0 for regular polygon, 1 for patches (= subsurf), 2 for anything else to be ignored
+ if flag<2:
+ if object_list[object_index][3] != []:
+ object_list.append([object_list[object_index][0], #update name
+ {}, #init
+ copy.deepcopy(object_list[object_index][2]), #same vertexes
+ [], #no faces
+ {}, #no need to copy - filled at runtime
+ {}, #polygon tagging will follow
+ flag, #patch flag
+ copy.deepcopy(object_list[object_index][7]), #same uvcoords
+ {}]) #no uv mapping
+ object_index += 1
+ #end if already has a face list
+ #update uv coords mapping if VMAP already encountered
+ for uvname in object_list[object_index][7]:
+ tobj.pprint("updating uv to face mapping for %s" % uvname)
+ object_list[object_index][8][uvname] = copy.deepcopy(faces)
+ object_list[object_index][3] = faces
+ objname = object_list[object_index][0]
+ if objname == None:
+ objname = defaultname
+ #end if processing a valid poly type
+ elif lwochunk.chunkname == "TAGS": # Tags
+ tobj.pprint("---- TAGS")
+ tag_list.extend(read_tags(lwochunk))
+ elif lwochunk.chunkname == "PTAG": # PTags
+ tobj.pprint("---- PTAG")
+ polytag_dict = read_ptags(lwochunk, tag_list)
+ for kk in polytag_dict.keys(): object_list[object_index][5][kk] = polytag_dict[kk]
+ elif lwochunk.chunkname == "SURF": # surfaces
+ tobj.pprint("---- SURF")
+ surf_list.append(read_surfs(lwochunk, surf_list, tag_list))
+ elif lwochunk.chunkname == "CLIP": # texture images
+ tobj.pprint("---- CLIP")
+ clip_list.append(read_clip(lwochunk))
+ tobj.pprint("read total %s clips" % len(clip_list))
+ else: # Misc Chunks
+ tobj.pprint("---- %s: skipping" % lwochunk.chunkname)
+ lwochunk.skip()
+ #uncomment here to log data structure as it is built
+ #tobj.pprint(object_list)
+
+ tobj.pprint ("\n#####################################################################")
+ tobj.pprint("Found %d objects:" % len(object_list))
+ tobj.pprint ("#####################################################################")
+ for objspec_list in object_list:
+ tobj.pprint ("\n#===================================================================#")
+ tobj.pprint("Processing Object: %s" % objspec_list[0])
+ tobj.pprint ("#===================================================================#")
+ objspec_list[3], objspec_list[5], objspec_list[8] = recalc_faces(objspec_list[2], objspec_list[3], objspec_list[5], objspec_list[8]) #recalculate faces, polytag_dict and uv_mapping get rid of faces fanning
+
+ create_objects(objspec_list)
+
+ if surf_list != []:
+ create_material(clip_list, surf_list, objspec_list, dir_part) #give it all the object
+ return
+# enddef read_lwo2
+
+
+
+
+
+
+# ===========================================================
+# === File reading routines =================================
+# ===========================================================
# ==================
# === Read Verts ===
# ==================
def read_verts(lwochunk):
- data = cStringIO.StringIO(lwochunk.read())
- numverts = lwochunk.chunksize/12
- #$verts = []
- verts = [None] * numverts
- for i in range(numverts):
- if not i%100 and meshtools.show_progress:
- Blender.Window.DrawProgressBar(float(i)/numverts, "Reading Verts")
- x, y, z = struct.unpack(">fff", data.read(12))
- #$verts.append((x, z, y))
- verts[i] = (x, z, y)
- return verts
+ global tobj
+
+ data = cStringIO.StringIO(lwochunk.read())
+ numverts = lwochunk.chunksize/12
+ #$verts = []
+ verts = [None] * numverts
+ for i in range(numverts):
+ if not i%100 and my_meshtools.show_progress:
+ Blender.Window.DrawProgressBar(float(i)/numverts, "Reading Verts")
+ x, y, z = struct.unpack(">fff", data.read(12))
+ verts[i] = (x, z, y)
+ tobj.pprint("read %d vertexes" % (i+1))
+ return verts
+# enddef read_verts
+
# =================
# === Read Name ===
# =================
+# modified to deal with odd lenght strings
def read_name(file):
- name = ""
- while 1:
- char = file.read(1)
- if char == "\0": break
- else: name += char
- return name
+ name = ""
+ while 1:
+ char = file.read(1)
+ if char == "\0": break
+ else: name += char
+ len_name = len(name) + 1 #count the trailing zero
+ if len_name%2==1:
+ char = file.read(1) #remove zero padding to even lenght
+ len_name += 1
+ return name, len_name
+
# ==================
# === Read Layer ===
# ==================
def read_layr(lwochunk):
- data = cStringIO.StringIO(lwochunk.read())
- idx, flags = struct.unpack(">hh", data.read(4))
- pivot = struct.unpack(">fff", data.read(12))
- layer_name = read_name(data)
- if not layer_name: layer_name = "No Name"
- return layer_name
+ data = cStringIO.StringIO(lwochunk.read())
+ idx, flags = struct.unpack(">hh", data.read(4))
+ pivot = struct.unpack(">fff", data.read(12))
+ layer_name, discard = read_name(data)
+ if not layer_name: layer_name = "NoName"
+ return layer_name
+# enddef read_layr
+
# ======================
# === Read Faces 5.5 ===
# ======================
def read_faces_5(lwochunk):
- data = cStringIO.StringIO(lwochunk.read())
- faces = []
- i = 0
- while i < lwochunk.chunksize:
- if not i%100 and meshtools.show_progress:
- Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces")
- facev = []
- numfaceverts, = struct.unpack(">H", data.read(2))
- for j in range(numfaceverts):
- index, = struct.unpack(">H", data.read(2))
- facev.append(index)
- facev.reverse()
- faces.append(facev)
- surfaceindex, = struct.unpack(">H", data.read(2))
- if surfaceindex < 0:
- print "detail polygons follow, error."
- return
- i += (4+numfaceverts*2)
- return faces
+ data = cStringIO.StringIO(lwochunk.read())
+ faces = []
+ i = 0
+ while i < lwochunk.chunksize:
+ if not i%100 and my_meshtools.show_progress:
+ Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces")
+ facev = []
+ numfaceverts, = struct.unpack(">H", data.read(2))
+ for j in range(numfaceverts):
+ index, = struct.unpack(">H", data.read(2))
+ facev.append(index)
+ facev.reverse()
+ faces.append(facev)
+ surfaceindex, = struct.unpack(">H", data.read(2))
+ if surfaceindex < 0:
+ tobj.logcon ("***Error. Referencing uncorrect surface index")
+ return
+ i += (4+numfaceverts*2)
+ return faces
+
# ==================================
# === Read Variable-Length Index ===
# ==================================
def read_vx(data):
- byte1, = struct.unpack(">B", data.read(1))
- if byte1 != 0xFF: # 2-byte index
- byte2, = struct.unpack(">B", data.read(1))
- index = byte1*256 + byte2
- index_size = 2
- else: # 4-byte index
- byte2, byte3, byte4 = struct.unpack(">3B", data.read(3))
- index = byte2*65536 + byte3*256 + byte4
- index_size = 4
- return index, index_size
+ byte1, = struct.unpack(">B", data.read(1))
+ if byte1 != 0xFF: # 2-byte index
+ byte2, = struct.unpack(">B", data.read(1))
+ index = byte1*256 + byte2
+ index_size = 2
+ else: # 4-byte index
+ byte2, byte3, byte4 = struct.unpack(">3B", data.read(3))
+ index = byte2*65536 + byte3*256 + byte4
+ index_size = 4
+ return index, index_size
+
+
+# ======================
+# === Read uvmapping ===
+# ======================
+def read_vmap(uvcoords_dict, facesuv_dict, faces, maxvertnum, lwochunk):
+ if maxvertnum == 0:
+ tobj.pprint ("Found VMAP but no vertexes to map!")
+ return uvcoords_dict, facesuv_dict
+ data = cStringIO.StringIO(lwochunk.read())
+ map_type = data.read(4)
+ if map_type != "TXUV":
+ tobj.pprint ("Reading VMAP: No Texture UV map Were Found. Map Type: %s" % map_type)
+ return uvcoords_dict, facesuv_dict
+ dimension, = struct.unpack(">H", data.read(2))
+ name, i = read_name(data) #i initialized with string lenght + zeros
+ tobj.pprint ("TXUV %d %s" % (dimension, name))
+ #my_uv_list = [None] * maxvertnum
+ my_uv_list = [(0.0, 0.0)] * maxvertnum #more safe to have some default coordinates to associate in any case?
+ while (i < lwochunk.chunksize - 6): #4+2 header bytes already read
+ vertnum, vnum_size = read_vx(data)
+ u, v = struct.unpack(">ff", data.read(8))
+ if vertnum >= maxvertnum:
+ tobj.pprint ("Hem: more uvmap than vertexes? ignoring uv data for vertex %d" % vertnum)
+ else:
+ my_uv_list[vertnum] = (u, v)
+ i += 8 + vnum_size
+ #end loop on uv pairs
+ uvcoords_dict[name] = my_uv_list
+ #this is a per-vertex mapping AND the uv tuple is vertex-ordered, so faces_uv is the same as faces
+ if faces == []:
+ tobj.pprint ("no faces read yet! delaying uv to face assignments")
+ facesuv_dict[name] = []
+ else:
+ #deepcopy so we could modify it without actually modify faces
+ tobj.pprint ("faces already present: proceeding with assignments")
+ facesuv_dict[name] = copy.deepcopy(faces)
+ return uvcoords_dict, facesuv_dict
+
+
+# ========================
+# === Read uvmapping 2 ===
+# ========================
+def read_vmad(uvcoords_dict, facesuv_dict, faces, maxvertnum, lwochunk):
+ maxfacenum = len(faces)
+ if maxvertnum == 0 or maxfacenum == 0:
+ tobj.pprint ("Found VMAD but no vertexes to map!")
+ return uvcoords_dict, facesuv_dict
+ data = cStringIO.StringIO(lwochunk.read())
+ map_type = data.read(4)
+ if map_type != "TXUV":
+ tobj.pprint ("Reading VMAD: No Texture UV map Were Found. Map Type: %s" % map_type)
+ return uvcoords_dict, facesuv_dict
+ dimension, = struct.unpack(">H", data.read(2))
+ name, i = read_name(data) #i initialized with string lenght + zeros
+ tobj.pprint ("TXUV %d %s" % (dimension, name))
+ if uvcoords_dict.has_key(name):
+ my_uv_list = uvcoords_dict[name] #update existing
+ my_facesuv_list = facesuv_dict[name]
+ else:
+ my_uv_list = [(0.0, 0.0)] * maxvertnum #start a brand new: this could be made more smart
+ my_facesuv_list = copy.deepcopy(faces)
+ #end variable initialization
+ lastindex = len(my_uv_list) - 1
+ while (i < lwochunk.chunksize - 6): #4+2 header bytes already read
+ vertnum, vnum_size = read_vx(data)
+ i += vnum_size
+ polynum, vnum_size = read_vx(data)
+ i += vnum_size
+ u, v = struct.unpack(">ff", data.read(8))
+ if polynum >= maxfacenum or vertnum >= maxvertnum:
+ tobj.pprint ("Hem: more uvmap than vertexes? ignorig uv data for vertex %d" % vertnum)
+ else:
+ my_uv_list.append( (u,v) )
+ newindex = len(my_uv_list) - 1
+ for vi in range(len(my_facesuv_list[polynum])): #polynum starting from 1 or from 0?
+ if my_facesuv_list[polynum][vi] == vertnum:
+ my_facesuv_list[polynum][vi] = newindex
+ #end loop on current face vertexes
+ i += 8
+ #end loop on uv pairs
+ uvcoords_dict[name] = my_uv_list
+ facesuv_dict[name] = my_facesuv_list
+ tobj.pprint ("updated %d vertexes data" % (newindex-lastindex))
+ return uvcoords_dict, facesuv_dict
+
+
+# =================
+# === Read tags ===
+# =================
+def read_tags(lwochunk):
+ data = cStringIO.StringIO(lwochunk.read())
+ tag_list = []
+ current_tag = ""
+ i = 0
+ while i < lwochunk.chunksize:
+ char = data.read(1)
+ if char == "\0":
+ tag_list.append(current_tag)
+ if (len(current_tag) % 2 == 0): char = data.read(1)
+ current_tag = ""
+ else:
+ current_tag += char
+ i += 1
+ tobj.pprint("read %d tags, list follows:" % len(tag_list))
+ tobj.pprint( tag_list)
+ return tag_list
+
+
+# ==================
+# === Read Ptags ===
+# ==================
+def read_ptags(lwochunk, tag_list):
+ data = cStringIO.StringIO(lwochunk.read())
+ polygon_type = data.read(4)
+ if polygon_type != "SURF":
+ tobj.pprint ("No Surf Were Found. Polygon Type: %s" % polygon_type)
+ return {}
+ ptag_dict = {}
+ i = 0
+ while(i < lwochunk.chunksize-4): #4 bytes polygon type already read
+ if not i%100 and my_meshtools.show_progress:
+ Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading PTAGS")
+ poln, poln_size = read_vx(data)
+ i += poln_size
+ tag_index, = struct.unpack(">H", data.read(2))
+ if tag_index > (len(tag_list)):
+ tobj.pprint ("Reading PTAG: Surf belonging to undefined TAG: %d. Skipping" % tag_index)
+ return {}
+ i += 2
+ tag_key = tag_list[tag_index]
+ if not(ptag_dict.has_key(tag_key)):
+ ptag_dict[tag_list[tag_index]] = [poln]
+ else:
+ ptag_dict[tag_list[tag_index]].append(poln)
+ for i in ptag_dict.keys():
+ tobj.pprint ("read %d polygons belonging to TAG %s" % (len(ptag_dict[i]), i))
+ return ptag_dict
+
+
+
+# ==================
+# === Read Clips ===
+# ==================
+def read_clip(lwochunk):
+ clip_dict = {}
+ data = cStringIO.StringIO(lwochunk.read())
+ image_index, = struct.unpack(">L", data.read(4))
+ clip_dict['ID'] = image_index
+ i = 4
+ while(i < lwochunk.chunksize):
+ subchunkname, = struct.unpack("4s", data.read(4))
+ subchunklen, = struct.unpack(">H", data.read(2))
+ if subchunkname == "STIL":
+ tobj.pprint("-------- STIL")
+ clip_name, k = read_name(data)
+ #now split text independently from platform
+ #depend on the system where image was saved. NOT the one where the script is run
+ no_sep = "\\"
+ if Blender.sys.sep == no_sep: no_sep ="/"
+ if (no_sep in clip_name):
+ clip_name = clip_name.replace(no_sep, Blender.sys.sep)
+ short_name = Blender.sys.basename(clip_name)
+ if (clip_name == "") or (short_name == ""):
+ tobj.pprint ("Reading CLIP: Empty clip name not allowed. Skipping")
+ discard = data.read(subchunklen-k)
+ clip_dict['NAME'] = clip_name
+ clip_dict['BASENAME'] = short_name
+ elif subchunkname == "XREF": #cross reference another image
+ tobj.pprint("-------- XREF")
+ image_index, = struct.unpack(">L", data.read(4))
+ clip_name, k = read_name(data)
+ clip_dict['NAME'] = clip_name
+ clip_dict['XREF'] = image_index
+ elif subchunkname == "NEGA": #negate texture effect
+ tobj.pprint("-------- NEGA")
+ n, = struct.unpack(">H", data.read(2))
+ clip_dict['NEGA'] = n
+ else: # Misc Chunks
+ tobj.pprint("-------- SURF:%s: skipping" % subchunkname)
+ discard = data.read(subchunklen)
+ i = i + 6 + subchunklen
+ #end loop on surf chunks
+ tobj.pprint("read image:%s" % clip_dict)
+ return clip_dict
+
+
+# ===========================
+# === Read Surfaces Block ===
+# ===========================
+def read_surfblok(subchunkdata):
+ lenght = len(subchunkdata)
+ my_dict = {}
+ my_uvname = ""
+ data = cStringIO.StringIO(subchunkdata)
+ ##############################################################
+ # blok header sub-chunk
+ ##############################################################
+ subchunkname, = struct.unpack("4s", data.read(4))
+ subchunklen, = struct.unpack(">h", data.read(2))
+ accumulate_i = subchunklen + 6
+ if subchunkname != 'IMAP':
+ tobj.pprint("---------- SURF: BLOK: %s: block aborting" % subchunkname)
+ return {}, ""
+ tobj.pprint ("---------- IMAP")
+ ordinal, i = read_name(data)
+ my_dict['ORD'] = ordinal
+ my_dict['g_ORD'] = -1
+ my_dict['ENAB'] = True
+ while(i < subchunklen): # ---------left 6------------------------- loop on header parameters
+ sub2chunkname, = struct.unpack("4s", data.read(4))
+ sub2chunklen, = struct.unpack(">h", data.read(2))
+ i = i + 6 + sub2chunklen
+ if sub2chunkname == "CHAN":
+ tobj.pprint("------------ CHAN")
+ sub2chunkname, = struct.unpack("4s", data.read(4))
+ my_dict['CHAN'] = sub2chunkname
+ sub2chunklen -= 4
+ elif sub2chunkname == "ENAB": #only present if is to be disabled
+ tobj.pprint("------------ ENAB")
+ ena, = struct.unpack(">h", data.read(2))
+ my_dict['ENAB'] = ena
+ sub2chunklen -= 2
+ elif sub2chunkname == "NEGA": #only present if is to be enabled
+ tobj.pprint("------------ NEGA")
+ ena, = struct.unpack(">h", data.read(2))
+ if ena == 1:
+ my_dict['NEGA'] = ena
+ sub2chunklen -= 2
+ elif sub2chunkname == "OPAC": #only present if is to be disabled
+ tobj.pprint("------------ OPAC")
+ opa, = struct.unpack(">h", data.read(2))
+ s, = struct.unpack(">f", data.read(4))
+ envelope, env_size = read_vx(data)
+ my_dict['OPAC'] = opa
+ my_dict['OPACVAL'] = s
+ sub2chunklen -= 6
+ elif sub2chunkname == "AXIS":
+ tobj.pprint("------------ AXIS")
+ ena, = struct.unpack(">h", data.read(2))
+ my_dict['DISPLAXIS'] = ena
+ sub2chunklen -= 2
+ else: # Misc Chunks
+ tobj.pprint("------------ SURF: BLOK: IMAP: %s: skipping" % sub2chunkname)
+ discard = data.read(sub2chunklen)
+ #end loop on blok header subchunks
+ ##############################################################
+ # blok attributes sub-chunk
+ ##############################################################
+ subchunkname, = struct.unpack("4s", data.read(4))
+ subchunklen, = struct.unpack(">h", data.read(2))
+ accumulate_i += subchunklen + 6
+ if subchunkname != 'TMAP':
+ tobj.pprint("---------- SURF: BLOK: %s: block aborting" % subchunkname)
+ return {}, ""
+ tobj.pprint ("---------- TMAP")
+ i = 0
+ while(i < subchunklen): # -----------left 6----------------------- loop on header parameters
+ sub2chunkname, = struct.unpack("4s", data.read(4))
+ sub2chunklen, = struct.unpack(">h", data.read(2))
+ i = i + 6 + sub2chunklen
+ if sub2chunkname == "CNTR":
+ tobj.pprint("------------ CNTR")
+ x, y, z = struct.unpack(">fff", data.read(12))
+ envelope, env_size = read_vx(data)
+ my_dict['CNTR'] = [x, y, z]
+ sub2chunklen -= (12+env_size)
+ elif sub2chunkname == "SIZE":
+ tobj.pprint("------------ SIZE")
+ x, y, z = struct.unpack(">fff", data.read(12))
+ envelope, env_size = read_vx(data)
+ my_dict['SIZE'] = [x, y, z]
+ sub2chunklen -= (12+env_size)
+ elif sub2chunkname == "ROTA":
+ tobj.pprint("------------ ROTA")
+ x, y, z = struct.unpack(">fff", data.read(12))
+ envelope, env_size = read_vx(data)
+ my_dict['ROTA'] = [x, y, z]
+ sub2chunklen -= (12+env_size)
+ elif sub2chunkname == "CSYS":
+ tobj.pprint("------------ CSYS")
+ ena, = struct.unpack(">h", data.read(2))
+ my_dict['CSYS'] = ena
+ sub2chunklen -= 2
+ else: # Misc Chunks
+ tobj.pprint("------------ SURF: BLOK: TMAP: %s: skipping" % sub2chunkname)
+ if sub2chunklen > 0:
+ discard = data.read(sub2chunklen)
+ #end loop on blok attributes subchunks
+ ##############################################################
+ # ok, now other attributes without sub_chunks
+ ##############################################################
+ while(accumulate_i < lenght): # ---------------------------------- loop on header parameters: lenght has already stripped the 6 bypes header
+ subchunkname, = struct.unpack("4s", data.read(4))
+ subchunklen, = struct.unpack(">H", data.read(2))
+ accumulate_i = accumulate_i + 6 + subchunklen
+ if subchunkname == "PROJ":
+ tobj.pprint("---------- PROJ")
+ p, = struct.unpack(">h", data.read(2))
+ my_dict['PROJ'] = p
+ subchunklen -= 2
+ elif subchunkname == "AXIS":
+ tobj.pprint("---------- AXIS")
+ a, = struct.unpack(">h", data.read(2))
+ my_dict['MAJAXIS'] = a
+ subchunklen -= 2
+ elif subchunkname == "IMAG":
+ tobj.pprint("---------- IMAG")
+ i, i_size = read_vx(data)
+ my_dict['IMAG'] = i
+ subchunklen -= i_size
+ elif subchunkname == "WRAP":
+ tobj.pprint("---------- WRAP")
+ ww, wh = struct.unpack(">hh", data.read(4))
+ #reduce width and height to just 1 parameter for both
+ my_dict['WRAP'] = max([ww,wh])
+ #my_dict['WRAPWIDTH'] = ww
+ #my_dict['WRAPHEIGHT'] = wh
+ subchunklen -= 4
+ elif subchunkname == "WRPW":
+ tobj.pprint("---------- WRPW")
+ w, = struct.unpack(">f", data.read(4))
+ my_dict['WRPW'] = w
+ envelope, env_size = read_vx(data)
+ subchunklen -= (env_size+4)
+ elif subchunkname == "WRPH":
+ tobj.pprint("---------- WRPH")
+ w, = struct.unpack(">f", data.read(4))
+ my_dict['WRPH'] = w
+ envelope, env_size = read_vx(data)
+ subchunklen -= (env_size+4)
+ elif subchunkname == "VMAP":
+ tobj.pprint("---------- VMAP")
+ vmp, i = read_name(data)
+ my_dict['VMAP'] = vmp
+ my_uvname = vmp
+ subchunklen -= i
+ else: # Misc Chunks
+ tobj.pprint("---------- SURF: BLOK: %s: skipping" % subchunkname)
+ if subchunklen > 0:
+ discard = data.read(subchunklen)
+ #end loop on blok subchunks
+ return my_dict, my_uvname
+
+
+# =====================
+# === Read Surfaces ===
+# =====================
+def read_surfs(lwochunk, surf_list, tag_list):
+ my_dict = {}
+ data = cStringIO.StringIO(lwochunk.read())
+ surf_name, i = read_name(data)
+ parent_name, j = read_name(data)
+ i += j
+ if (surf_name == "") or not(surf_name in tag_list):
+ tobj.pprint ("Reading SURF: Actually empty surf name not allowed. Skipping")
+ return {}
+ if (parent_name != ""):
+ parent_index = [x['NAME'] for x in surf_list].count(parent_name)
+ if parent_index >0:
+ my_dict = surf_list[parent_index-1]
+ my_dict['NAME'] = surf_name
+ tobj.pprint ("Surface data for TAG %s" % surf_name)
+ while(i < lwochunk.chunksize):
+ subchunkname, = struct.unpack("4s", data.read(4))
+ subchunklen, = struct.unpack(">H", data.read(2))
+ i = i + 6 + subchunklen #6 bytes subchunk header
+ if subchunkname == "COLR": #color: mapped on color
+ tobj.pprint("-------- COLR")
+ r, g, b = struct.unpack(">fff", data.read(12))
+ envelope, env_size = read_vx(data)
+ my_dict['COLR'] = [r, g, b]
+ subchunklen -= (12+env_size)
+ elif subchunkname == "DIFF": #diffusion: mapped on reflection (diffuse shader)
+ tobj.pprint("-------- DIFF")
+ s, = struct.unpack(">f", data.read(4))
+ envelope, env_size = read_vx(data)
+ my_dict['DIFF'] = s
+ subchunklen -= (4+env_size)
+ elif subchunkname == "SPEC": #specularity: mapped to specularity (spec shader)
+ tobj.pprint("-------- SPEC")
+ s, = struct.unpack(">f", data.read(4))
+ envelope, env_size = read_vx(data)
+ my_dict['SPEC'] = s
+ subchunklen -= (4+env_size)
+ elif subchunkname == "REFL": #reflection: mapped on raymirror
+ tobj.pprint("-------- REFL")
+ s, = struct.unpack(">f", data.read(4))
+ envelope, env_size = read_vx(data)
+ my_dict['REFL'] = s
+ subchunklen -= (4+env_size)
+ elif subchunkname == "TRNL": #translucency: mapped on same param
+ tobj.pprint("-------- TRNL")
+ s, = struct.unpack(">f", data.read(4))
+ envelope, env_size = read_vx(data)
+ my_dict['TRNL'] = s
+ subchunklen -= (4+env_size)
+ elif subchunkname == "GLOS": #glossiness: mapped on specularity hardness (spec shader)
+ tobj.pprint("-------- GLOS")
+ s, = struct.unpack(">f", data.read(4))
+ envelope, env_size = read_vx(data)
+ my_dict['GLOS'] = s
+ subchunklen -= (4+env_size)
+ elif subchunkname == "TRAN": #transparency: inverted and mapped on alpha channel
+ tobj.pprint("-------- TRAN")
+ s, = struct.unpack(">f", data.read(4))
+ envelope, env_size = read_vx(data)
+ my_dict['TRAN'] = s
+ subchunklen -= (4+env_size)
+ elif subchunkname == "LUMI": #luminosity: mapped on emit channel
+ tobj.pprint("-------- LUMI")
+ s, = struct.unpack(">f", data.read(4))
+ envelope, env_size = read_vx(data)
+ my_dict['LUMI'] = s
+ subchunklen -= (4+env_size)
+ elif subchunkname == "GVAL": #glow: mapped on add channel
+ tobj.pprint("-------- GVAL")
+ s, = struct.unpack(">f", data.read(4))
+ envelope, env_size = read_vx(data)
+ my_dict['GVAL'] = s
+ subchunklen -= (4+env_size)
+ elif subchunkname == "SMAN": #smoothing angle
+ tobj.pprint("-------- SMAN")
+ s, = struct.unpack(">f", data.read(4))
+ my_dict['SMAN'] = s
+ subchunklen -= 4
+ elif subchunkname == "SIDE": #double sided?
+ tobj.pprint("-------- SIDE") #if 1 side do not define key
+ s, = struct.unpack(">H", data.read(2))
+ if s == 3:
+ my_dict['SIDE'] = s
+ subchunklen -= 2
+ elif subchunkname == "RIND": #Refraction: mapped on IOR
+ tobj.pprint("-------- RIND")
+ s, = struct.unpack(">f", data.read(4))
+ envelope, env_size = read_vx(data)
+ my_dict['RIND'] = s
+ subchunklen -= (4+env_size)
+ elif subchunkname == "BLOK": #blocks
+ tobj.pprint("-------- BLOK")
+ rr, uvname = read_surfblok(data.read(subchunklen))
+ #paranoia setting: preventing adding an empty dict
+ if rr != {}:
+ if not(my_dict.has_key('BLOK')):
+ my_dict['BLOK'] = [rr]
+ else:
+ my_dict['BLOK'].append(rr)
+ if uvname != "":
+ my_dict['UVNAME'] = uvname #theoretically there could be a number of them: only one used per surf
+ subchunklen = 0 #force ending
+ else: # Misc Chunks
+ tobj.pprint("-------- SURF:%s: skipping" % subchunkname)
+ if subchunklen > 0:
+ discard = data.read(subchunklen)
+ #end loop on surf chunks
+ if my_dict.has_key('BLOK'):
+ my_dict['BLOK'].reverse()
+ return my_dict
+
+
+
+
+
+
+# ===========================================================
+# === Generation Routines ===================================
+# ===========================================================
+# ==================================================
+# === Compute vector distance between two points ===
+# ==================================================
+def dist_vector (head, tail): #vector from head to tail
+ return Blender.Mathutils.Vector([head[0] - tail[0], head[1] - tail[1], head[2] - tail[2]])
+
+
+# ================
+# === Find Ear ===
+# ================
+def find_ear(normal, list_dict, verts, face):
+ nv = len(list_dict['MF'])
+ #looping through vertexes trying to find an ear
+ #most likely in case of panic
+ mlc = 0
+ mla = 1
+ mlb = 2
+
+ for c in range(nv):
+ a = (c+1) % nv; b = (a+1) % nv
+
+ if list_dict['P'][a] > 0.0: #we have to start from a convex vertex
+ #if (list_dict['P'][a] > 0.0) and (list_dict['P'][b] <= 0.0): #we have to start from a convex vertex
+ mlc = c
+ mla = a
+ mlb = b
+ #tobj.pprint ("## mmindex: %s, %s, %s 'P': %s, %s, %s" % (c, a, b, list_dict['P'][c],list_dict['P'][a],list_dict['P'][b]))
+ #tobj.pprint (" ok, this one passed")
+ concave = 0
+ concave_inside = 0
+ for xx in range(nv): #looking for concave vertex
+ if (list_dict['P'][xx] <= 0.0) and (xx != b) and (xx != c): #cannot be a: it's convex
+ #ok, found concave vertex
+ concave = 1
+ #a, b, c, xx are all meta-meta vertex indexes
+ mva = list_dict['MF'][a] #meta-vertex-index
+ mvb = list_dict['MF'][b]
+ mvc = list_dict['MF'][c]
+ mvxx = list_dict['MF'][xx]
+ va = face[mva] #vertex
+ vb = face[mvb]
+ vc = face[mvc]
+ vxx = face[mvxx]
+
+ #Distances
+ d_ac_v = list_dict['D'][c]
+ d_ba_v = list_dict['D'][a]
+ d_cb_v = dist_vector(verts[vc], verts[vb])
+
+ #distance from triangle points
+ d_xxa_v = dist_vector(verts[vxx], verts[va])
+ d_xxb_v = dist_vector(verts[vxx], verts[vb])
+ d_xxc_v = dist_vector(verts[vxx], verts[vc])
+
+ #normals
+ n_xxa_v = Blender.Mathutils.CrossVecs(d_ba_v, d_xxa_v)
+ n_xxb_v = Blender.Mathutils.CrossVecs(d_cb_v, d_xxb_v)
+ n_xxc_v = Blender.Mathutils.CrossVecs(d_ac_v, d_xxc_v)
+
+ #how are oriented the normals?
+ p_xxa_v = Blender.Mathutils.DotVecs(normal, n_xxa_v)
+ p_xxb_v = Blender.Mathutils.DotVecs(normal, n_xxb_v)
+ p_xxc_v = Blender.Mathutils.DotVecs(normal, n_xxc_v)
+
+ #if normals are oriented all to same directions - so it is insida
+ if ((p_xxa_v > 0.0) and (p_xxb_v > 0.0) and (p_xxc_v > 0.0)) or ((p_xxa_v <= 0.0) and (p_xxb_v <= 0.0) and (p_xxc_v <= 0.0)):
+ #print "vertex %d: concave inside" % xx
+ concave_inside = 1
+ break
+ #endif found a concave vertex
+ #end loop looking for concave vertexes
+ if (concave == 0) or (concave_inside == 0):
+ #no concave vertexes in polygon (should not be): return immediately
+ #looped all concave vertexes and no one inside found
+ return [c, a, b]
+ #no convex vertex, try another one
+ #end loop to find a suitable base vertex for ear
+ #looped all candidate ears and find no-one suitable
+ tobj.pprint ("Reducing face: no valid ear found to reduce!")
+ return [mlc, mla, mlb] #uses most likely
+
+
+
+
+# ====================
+# === Reduce Faces ===
+# ====================
+# http://www-cgrl.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian/cutting_ears.html per l'import
+def reduce_face(verts, face):
+ nv = len (face)
+ if nv == 3: return [[0,1,2]] #trivial decomposition list
+ list_dict = {}
+ #meta-vertex indexes
+ list_dict['MF'] = range(nv) # these are meta-vertex-indexes
+ list_dict['D'] = [None] * nv
+ list_dict['X'] = [None] * nv
+ list_dict['P'] = [None] * nv
+ #list of distances
+ for mvi in list_dict['MF']:
+ #vector between two vertexes
+ mvi_hiend = (mvi+1) % nv #last-to-first
+ vi_hiend = face[mvi_hiend] #vertex
+ vi = face[mvi]
+ list_dict['D'][mvi] = dist_vector(verts[vi_hiend], verts[vi])
+ #list of cross products - normals evaluated into vertexes
+ for vi in range(nv):
+ list_dict['X'][vi] = Blender.Mathutils.CrossVecs(list_dict['D'][vi], list_dict['D'][vi-1])
+ my_face_normal = Blender.Mathutils.Vector([list_dict['X'][0][0], list_dict['X'][0][1], list_dict['X'][0][2]])
+ #list of dot products
+ list_dict['P'][0] = 1.0
+ for vi in range(1, nv):
+ list_dict['P'][vi] = Blender.Mathutils.DotVecs(my_face_normal, list_dict['X'][vi])
+ #is there at least one concave vertex?
+ #one_concave = reduce(lambda x, y: (x) or (y<=0.0), list_dict['P'], 0)
+ one_concave = reduce(lambda x, y: (x) + (y<0.0), list_dict['P'], 0)
+ decomposition_list = []
+
+ while 1:
+ if nv == 3: break
+ if one_concave:
+ #look for triangle
+ ct = find_ear(my_face_normal, list_dict, verts, face)
+ mv0 = list_dict['MF'][ct[0]] #meta-vertex-index
+ mv1 = list_dict['MF'][ct[1]]
+ mv2 = list_dict['MF'][ct[2]]
+ #add the triangle to output list
+ decomposition_list.append([mv0, mv1, mv2])
+ #update data structures removing remove middle vertex from list
+ #distances
+ v0 = face[mv0] #vertex
+ v1 = face[mv1]
+ v2 = face[mv2]
+ list_dict['D'][ct[0]] = dist_vector(verts[v2], verts[v0])
+ #cross products
+ list_dict['X'][ct[0]] = Blender.Mathutils.CrossVecs(list_dict['D'][ct[0]], list_dict['D'][ct[0]-1])
+ list_dict['X'][ct[2]] = Blender.Mathutils.CrossVecs(list_dict['D'][ct[2]], list_dict['D'][ct[0]])
+ #list of dot products
+ list_dict['P'][ct[0]] = Blender.Mathutils.DotVecs(my_face_normal, list_dict['X'][ct[0]])
+ list_dict['P'][ct[2]] = Blender.Mathutils.DotVecs(my_face_normal, list_dict['X'][ct[2]])
+ #physical removal
+ list_dict['MF'].pop(ct[1])
+ list_dict['D'].pop(ct[1])
+ list_dict['X'].pop(ct[1])
+ list_dict['P'].pop(ct[1])
+ one_concave = reduce(lambda x, y: (x) or (y<0.0), list_dict['P'], 0)
+ nv -=1
+ else: #here if no more concave vertexes
+ if nv == 4: break #quads only if no concave vertexes
+ decomposition_list.append([list_dict['MF'][0], list_dict['MF'][1], list_dict['MF'][2]])
+ #physical removal
+ list_dict['MF'].pop(1)
+ nv -=1
+ #end while there are more my_face to triangulate
+ decomposition_list.append(list_dict['MF'])
+ return decomposition_list
+
+
+# =========================
+# === Recalculate Faces ===
+# =========================
+# --------- this do the standard face + ptag_dict + uv-map recalc
+def recalc_faces(verts, faces, polytag_dict, facesuv_dict):
+ # init local face list
+ my_faces = []
+ # init local uvface dict
+ my_facesuv = {}
+ for uvname in facesuv_dict:
+ my_facesuv[uvname] = []
+ replaced_faces_dict = {}
+ j = 0
+ if len(faces)==0:
+ return faces, polytag_dict, facesuv_dict
+ for i in range(len(faces)):
+ # i = index that spans on original faces
+ # j = index that spans on new faces
+ if not i%100 and my_meshtools.show_progress: Blender.Window.DrawProgressBar(float(i)/len(faces), "Recalculating faces")
+ numfaceverts=len(faces[i])
+ if numfaceverts < 4: #This face is a triangle or quad: more strict - it has to be a triangle
+ my_faces.append(faces[i]) #ok, leave it alone ....
+ for uvname in facesuv_dict:
+ my_facesuv[uvname].append(facesuv_dict[uvname][i])
+ replaced_faces_dict[i] = [j] #.... but change the nuber order of the face
+ j += 1
+ else: # Reduce n-sided convex polygon.
+ meta_faces = reduce_face(verts, faces[i]) # Indices of triangles.
+ this_faces = [] # list of triangles poly replacing original face
+ this_faces_index = []
+ for mf in meta_faces:
+ ll = len(mf)
+ if ll == 3: #triangle
+ this_faces.append([faces[i][mf[0]], faces[i][mf[1]], faces[i][mf[2]]])
+ else: #quads
+ this_faces.append([faces[i][mf[0]], faces[i][mf[1]], faces[i][mf[2]], faces[i][mf[3]]])
+ for uvname in facesuv_dict:
+ if ll == 3: #triangle
+ my_facesuv[uvname].append([facesuv_dict[uvname][i][mf[0]], facesuv_dict[uvname][i][mf[1]], facesuv_dict[uvname][i][mf[2]]])
+ else: #quads
+ my_facesuv[uvname].append([facesuv_dict[uvname][i][mf[0]], facesuv_dict[uvname][i][mf[1]], facesuv_dict[uvname][i][mf[2]], facesuv_dict[uvname][i][mf[3]]])
+ this_faces_index.append(j)
+ j +=1
+ my_faces.extend(this_faces)
+ replaced_faces_dict[i] = this_faces_index #face i substituted by this list of faces
+ #endif on face vertex number
+ #end loop on every face
+ #now we have the new faces list and a dictionary replacement.
+ #going for polygon tagging
+ my_ptag_dict = {}
+ for tag in polytag_dict: #for every tag group
+ my_ptag_dict[tag] = [] #rebuild a new entry
+ for poly in polytag_dict[tag]: #take every element of old face list
+ my_ptag_dict[tag].extend(replaced_faces_dict[poly]) #substitutes the element of new face list
+ return my_faces, my_ptag_dict, my_facesuv
+
+
+# ========================================
+# === Revert list keeping first vertex ===
+# ========================================
+def revert (llist):
+ #different flavors: the reverse one is the one that works better
+ #rhead = [llist[0]]
+ #rtail = llist[1:]
+ #rhead.extend(rtail)
+ #return rhead
+ #--------------
+ rhead=copy.deepcopy(llist)
+ rhead.reverse()
+ return rhead
+ #--------------
+ #return llist
+
+# ====================================
+# === Modified Create Blender Mesh ===
+# ====================================
+def my_create_mesh(complete_vertlist, complete_facelist, current_facelist, objname, not_used_faces):
+ #take the needed faces and update the not-used face list
+ vertex_map = [-1] * len(complete_vertlist)
+ cur_ptag_faces = []
+ for ff in current_facelist:
+ cur_face = complete_facelist[ff]
+ cur_ptag_faces.append(cur_face)
+ if not_used_faces != []: not_used_faces[ff] = -1
+ for vv in cur_face:
+ vertex_map[vv] = 1
+ #end loop on vertex on this face
+ #end loop on faces
+
+ mesh = Blender.NMesh.GetRaw()
+
+ #append vertexes
+ jj = 0
+ for i in range(len(complete_vertlist)):
+ if vertex_map[i] == 1:
+ if not i%100 and my_meshtools.show_progress: Blender.Window.DrawProgressBar(float(i)/len(complete_vertlist), "Generating Verts")
+ x, y, z = complete_vertlist[i]
+ mesh.verts.append(Blender.NMesh.Vert(x, y, z))
+ vertex_map[i] = jj
+ jj += 1
+ #end sweep over vertexes
+
+ #append faces
+ for i in range(len(cur_ptag_faces)):
+ if not i%100 and my_meshtools.show_progress: Blender.Window.DrawProgressBar(float(i)/len(cur_ptag_faces), "Generating Faces")
+ face = Blender.NMesh.Face()
+ rev_face = revert(cur_ptag_faces[i])
+ for vi in rev_face:
+ #for vi in cur_ptag_faces[i]:
+ index = vertex_map[vi]
+ face.v.append(mesh.verts[index])
+ #end sweep over vertexes
+ mesh.faces.append(face)
+ #end sweep over faces
+
+ if not my_meshtools.overwrite_mesh_name:
+ objname = my_meshtools.versioned_name(objname)
+ Blender.NMesh.PutRaw(mesh, objname) # Name the Mesh
+ obj = Blender.Object.GetSelected()[0]
+ obj.name=objname # Name the Object
+ Blender.Redraw()
+ return obj, not_used_faces #return the created object
+
+
+# ============================================
+# === Set Subsurf attributes on given mesh ===
+# ============================================
+def set_subsurf(obj):
+ msh = obj.getData()
+ msh.setSubDivLevels([2, 2])
+ msh.mode |= Blender.NMesh.Modes.SUBSURF
+ msh.update(1)
+ obj.makeDisplayList()
+ return
+
+
+# =================================
+# === object size and dimension ===
+# =================================
+def obj_size_pos(obj):
+ bbox = obj.getBoundBox()
+ bbox_min = map(lambda *row: min(row), *bbox) #transpose & get min
+ bbox_max = map(lambda *row: max(row), *bbox) #transpose & get max
+ obj_size = (bbox_max[0]-bbox_min[0], bbox_max[1]-bbox_min[1], bbox_max[2]-bbox_min[2])
+ obj_pos = ( (bbox_max[0]+bbox_min[0]) / 2, (bbox_max[1]+bbox_min[1]) / 2, (bbox_max[2]+bbox_min[2]) / 2)
+ return (obj_size, obj_pos)
+
+
+# =========================
+# === Create the object ===
+# =========================
+def create_objects(objspec_list):
+ nf = len(objspec_list[3])
+ not_used_faces = range(nf)
+ ptag_dict = objspec_list[5]
+ obj_dict = {} #links tag names to object, used for material assignments
+ obj_dim_dict = {}
+ obj_list = [] #have it handy for parent association
+ middlechar = "+"
+ endchar = ""
+ if (objspec_list[6] == 1):
+ middlechar = endchar = "#"
+ for cur_tag in ptag_dict.keys():
+ if ptag_dict[cur_tag] != []:
+ cur_obj, not_used_faces= my_create_mesh(objspec_list[2], objspec_list[3], ptag_dict[cur_tag], objspec_list[0][:9]+middlechar+cur_tag[:9], not_used_faces)
+ if objspec_list[6] == 1:
+ set_subsurf(cur_obj)
+ obj_dict[cur_tag] = cur_obj
+ obj_dim_dict[cur_tag] = obj_size_pos(cur_obj)
+ obj_list.append(cur_obj)
+ #end loop on current group
+ #and what if some faces not used in any named PTAG? get rid of unused faces
+ for ff in range(nf):
+ tt = nf-1-ff #reverse order
+ if not_used_faces[tt] == -1:
+ not_used_faces.pop(tt)
+ #end sweep on unused face list
+ if not_used_faces != []:
+ cur_obj, not_used_faces = my_create_mesh(objspec_list[2], objspec_list[3], not_used_faces, objspec_list[0][:9]+middlechar+"lone", [])
+ #my_meshtools.create_mesh(objspec_list[2], not_used_faces, "_unk") #vert, faces, name
+ #cur_obj = Blender.Object.GetSelected()[0]
+ if objspec_list[6] == 1:
+ set_subsurf(cur_obj)
+ obj_dict["lone"] = cur_obj
+ obj_dim_dict["lone"] = obj_size_pos(cur_obj)
+ obj_list.append(cur_obj)
+ objspec_list[1] = obj_dict
+ objspec_list[4] = obj_dim_dict
+ scene = Blender.Scene.getCurrent () # get the current scene
+ ob = Blender.Object.New ('Empty', objspec_list[0]+endchar) # make empty object
+ scene.link (ob) # link the object into the scene
+ ob.makeParent(obj_list, 1, 0) # set the root for created objects (no inverse, update scene hyerarchy (slow))
+ Blender.Redraw()
+ return
+
+
+# =====================
+# === Load an image ===
+# =====================
+#extensively search for image name
+def load_image(dir_part, name):
+ img = None
+ nname = Blender.sys.splitext(name)
+ lname = [c.lower() for c in nname]
+ ext_list = []
+ if lname[1] != nname[1]:
+ ext_list.append(lname[1])
+ ext_list.extend(['.tga', '.png', '.jpg', '.gif', '.bmp']) #order from best to worst (personal judgement) bmp last cause of nasty bug
+ #first round: original "case"
+ current = Blender.sys.join(dir_part, name)
+ name_list = [current]
+ name_list.extend([Blender.sys.makename(current, ext) for ext in ext_list])
+ #second round: lower "case"
+ if lname[0] != nname[0]:
+ current = Blender.sys.join(dir_part, lname[0])
+ name_list.extend([Blender.sys.makename(current, ext) for ext in ext_list])
+ for nn in name_list:
+ if Blender.sys.exists(nn) == 1:
+ break
+ try:
+ img = Blender.Image.Load(nn)
+ return img
+ except IOError:
+ return None
+
+
+# ===========================================
+# === Lookup for image index in clip_list ===
+# ===========================================
+def lookup_imag(clip_list,ima_id):
+ for ii in clip_list:
+ if ii['ID'] == ima_id:
+ if ii.has_key('XREF'):
+ #cross reference - recursively look for images
+ return lookup_imag(clip_list, ii['XREF'])
+ else:
+ return ii
+ return None
+
+
+# ===================================================
+# === Create and assign image mapping to material ===
+# ===================================================
+def create_blok(surf, mat, clip_list, dir_part, obj_size, obj_pos):
+
+ def output_size_ofs(size, pos, blok):
+ #just automate repetitive task
+ c_map = [0,1,2]
+ c_map_txt = [" X--", " -Y-", " --Z"]
+ if blok['MAJAXIS'] == 0:
+ c_map = [1,2,0]
+ if blok['MAJAXIS'] == 2:
+ c_map = [0,2,1]
+ tobj.pprint ("!!!axis mapping:")
+ for mp in c_map: tobj.pprint (c_map_txt[mp])
+
+ s = ["1.0 (Forced)"] * 3
+ o = ["0.0 (Forced)"] * 3
+ if blok['SIZE'][0] > 0.0: #paranoia controls
+ s[0] = "%.5f" % (size[0]/blok['SIZE'][0])
+ o[0] = "%.5f" % ((blok['CNTR'][0]-pos[0])/blok['SIZE'][0])
+ if blok['SIZE'][1] > 0.0:
+ s[2] = "%.5f" % (size[2]/blok['SIZE'][1])
+ o[2] = "%.5f" % ((blok['CNTR'][1]-pos[2])/blok['SIZE'][1])
+ if blok['SIZE'][2] > 0.0:
+ s[1] = "%.5f" % (size[1]/blok['SIZE'][2])
+ o[1] = "%.5f" % ((blok['CNTR'][2]-pos[1])/blok['SIZE'][2])
+ tobj.pprint ("!!!texture size and offsets:")
+ tobj.pprint (" sizeX = %s; sizeY = %s; sizeZ = %s" % (s[c_map[0]], s[c_map[1]], s[c_map[2]]))
+ tobj.pprint (" ofsX = %s; ofsY = %s; ofsZ = %s" % (o[c_map[0]], o[c_map[1]], o[c_map[2]]))
+ return
+
+ ti = 0
+ for blok in surf['BLOK']:
+ tobj.pprint ("#...................................................................#")
+ tobj.pprint ("# Processing texture block no.%s for surf %s" % (ti,surf['NAME']))
+ tobj.pprint ("#...................................................................#")
+ tobj.pdict (blok)
+ if ti > 9: break #only 8 channels 0..7 allowed for texture mapping
+ if not blok['ENAB']:
+ tobj.pprint ( "***Image is not ENABled! Quitting this block")
+ break
+ if not(blok.has_key('IMAG')):
+ tobj.pprint ( "***No IMAGe for this block? Quitting")
+ break #extract out the image index within the clip_list
+ tobj.pprint ("looking for image number %d" % blok['IMAG'])
+ ima = lookup_imag(clip_list, blok['IMAG'])
+ if ima == None:
+ tobj.pprint ( "***Block index image not within CLIP list? Quitting Block")
+ break #safety check (paranoia setting)
+ #look for images
+ img = load_image("",ima['NAME'])
+ if img == None:
+ tobj.pprint ( "***No image %s found: trying LWO file subdir" % ima['NAME'])
+ img = load_image(dir_part,ima['BASENAME'])
+ if img == None:
+ tobj.pprint ( "***No image %s found in directory %s: trying Images subdir" % (ima['BASENAME'], dir_part))
+ img = load_image(dir_part+Blender.sys.sep+"Images",ima['BASENAME'])
+ if img == None:
+ tobj.pprint ( "***No image %s found: trying alternate Images subdir" % ima['BASENAME'])
+ img = load_image(dir_part+Blender.sys.sep+".."+Blender.sys.sep+"Images",ima['BASENAME'])
+ if img == None:
+ tobj.pprint ( "***No image %s found: giving up" % ima['BASENAME'])
+ break
+ #lucky we are: we have an image
+ tname = str(ima['ID'])
+ if blok.has_key('CHAN'):
+ tname = tname + "+" + blok['CHAN']
+ newtex = Blender.Texture.New(tname)
+ newtex.setType('Image') # make it an image texture
+ newtex.image = img
+ #how does it extends beyond borders
+ if blok.has_key('WRAP'):
+ if (blok['WRAP'] == 3) or (blok['WRAP'] == 2):
+ newtex.setExtend('Extend')
+ elif (blok['WRAP'] == 1):
+ newtex.setExtend('Repeat')
+ elif (blok['WRAP'] == 0):
+ newtex.setExtend('Clip')
+ tobj.pprint ("generated texture %s" % tname)
+
+ blendmode_list = ['Mix',
+ 'Subtractive',
+ 'Difference',
+ 'Multiply',
+ 'Divide',
+ 'Mix (CalcAlpha already set; try setting Stencil!',
+ 'Texture Displacement',
+ 'Additive']
+ set_blendmode = 7 #default additive
+ if blok.has_key('OPAC'):
+ set_blendmode = blok['OPAC']
+ if set_blendmode == 5: #transparency
+ newtex.imageFlags |= Blender.Texture.ImageFlags.CALCALPHA
+ tobj.pprint ("!!!Set Texture -> MapTo -> Blending Mode = %s" % blendmode_list[set_blendmode])
+
+ set_dvar = 1.0
+ if blok.has_key('OPACVAL'):
+ set_dvar = blok['OPACVAL']
+
+ #MapTo is determined by CHAN parameter
+ mapflag = Blender.Texture.MapTo.COL #default to color
+ if blok.has_key('CHAN'):
+ if blok['CHAN'] == 'COLR':
+ tobj.pprint ("!!!Set Texture -> MapTo -> Col = %.3f" % set_dvar)
+ if set_blendmode == 0:
+ surf['g_IM'] = img #do not set anything, just save image object for later assignment
+ if blok['CHAN'] == 'BUMP':
+ mapflag = Blender.Texture.MapTo.NOR
+ tobj.pprint ("!!!Set Texture -> MapTo -> Nor = %.3f" % set_dvar)
+ if blok['CHAN'] == 'LUMI':
+ mapflag = Blender.Texture.MapTo.EMIT
+ tobj.pprint ("!!!Set Texture -> MapTo -> DVar = %.3f" % set_dvar)
+ if blok['CHAN'] == 'DIFF':
+ mapflag = Blender.Texture.MapTo.REF
+ tobj.pprint ("!!!Set Texture -> MapTo -> DVar = %.3f" % set_dvar)
+ if blok['CHAN'] == 'SPEC':
+ mapflag = Blender.Texture.MapTo.SPEC
+ tobj.pprint ("!!!Set Texture -> MapTo -> DVar = %.3f" % set_dvar)
+ if blok['CHAN'] == 'TRAN':
+ mapflag = Blender.Texture.MapTo.ALPHA
+ tobj.pprint ("!!!Set Texture -> MapTo -> DVar = %.3f" % set_dvar)
+ if blok.has_key('NEGA'):
+ tobj.pprint ("!!!Watch-out: effect of this texture channel must be INVERTED!")
+
+ #the TexCo flag is determined by PROJ parameter
+ if blok.has_key('PROJ'):
+ if blok['PROJ'] == 0: #0 - Planar
+ tobj.pprint ("!!!Flat projection")
+ coordflag = Blender.Texture.TexCo.ORCO
+ output_size_ofs(obj_size, obj_pos, blok)
+ elif blok['PROJ'] == 1: #1 - Cylindrical
+ tobj.pprint ("!!!Cylindrical projection")
+ coordflag = Blender.Texture.TexCo.ORCO
+ output_size_ofs(obj_size, obj_pos, blok)
+ elif blok['PROJ'] == 2: #2 - Spherical
+ tobj.pprint ("!!!Spherical projection")
+ coordflag = Blender.Texture.TexCo.ORCO
+ output_size_ofs(obj_size, obj_pos, blok)
+ elif blok['PROJ'] == 3: #3 - Cubic
+ tobj.pprint ("!!!Cubic projection")
+ coordflag = Blender.Texture.TexCo.ORCO
+ output_size_ofs(obj_size, obj_pos, blok)
+ elif blok['PROJ'] == 4: #4 - Front Projection
+ tobj.pprint ("!!!Front projection")
+ coordflag = Blender.Texture.TexCo.ORCO
+ output_size_ofs(obj_size, obj_pos, blok)
+ elif blok['PROJ'] == 5: #5 - UV
+ tobj.pprint ("UVMapped")
+ coordflag = Blender.Texture.TexCo.UV
+ mat.setTexture(ti, newtex, coordflag, mapflag)
+ ti += 1
+ #end loop over bloks
+ return
+
+
+
+
+# ========================================
+# === Create and assign a new material ===
+# ========================================
+#def create_material(surf_list, ptag_dict, obj, clip_list, uv_dict, dir_part):
+def create_material(clip_list, surf_list, objspec, dir_part):
+ if (surf_list == []) or (objspec[5] == {}) or (objspec[1] == {}):
+ tobj.pprint( surf_list)
+ tobj.pprint( objspec[5])
+ tobj.pprint( objspec[1])
+ tobj.pprint( "something getting wrong in create_material ...")
+ return
+ obj_dict = objspec[1]
+ obj_dim_dict = objspec[4]
+ ptag_dict = objspec[5]
+ uvcoords_dict = objspec[7]
+ facesuv_dict = objspec[8]
+ for surf in surf_list:
+ if (surf['NAME'] in ptag_dict.keys()):
+ tobj.pprint ("#-------------------------------------------------------------------#")
+ tobj.pprint ("Processing surface (material): %s" % surf['NAME'])
+ tobj.pprint ("#-------------------------------------------------------------------#")
+ #material set up
+ facelist = ptag_dict[surf['NAME']]
+ #bounding box and position
+ cur_obj = obj_dict[surf['NAME']]
+ obj_size = obj_dim_dict[surf['NAME']][0]
+ obj_pos = obj_dim_dict[surf['NAME']][1]
+ tobj.pprint(surf)
+ mat = Blender.Material.New(surf['NAME'])
+ if surf.has_key('COLR'):
+ mat.rgbCol = surf['COLR']
+ if surf.has_key('LUMI'):
+ mat.setEmit(surf['LUMI'])
+ if surf.has_key('GVAL'):
+ mat.setAdd(surf['GVAL'])
+ if surf.has_key('SPEC'):
+ mat.setSpec(surf['SPEC']) #it should be * 2 but seems to be a bit higher lwo [0.0, 1.0] - blender [0.0, 2.0]
+ if surf.has_key('DIFF'):
+ mat.setRef(surf['DIFF']) #lwo [0.0, 1.0] - blender [0.0, 1.0]
+ if surf.has_key('REFL'):
+ mat.setRayMirr(surf['REFL']) #lwo [0.0, 1.0] - blender [0.0, 1.0]
+ #mat.setMode('RAYMIRROR')
+ mat.mode |= Blender.Material.Modes.RAYMIRROR
+ #WARNING translucency not implemented yet check 2.36 API
+ #if surf.has_key('TRNL'):
+ #
+ if surf.has_key('GLOS'): #lwo [0.0, 1.0] - blender [0, 255]
+ glo = int(371.67 * surf['GLOS'] - 42.334) #linear mapping - seems to work better than exp mapping
+ if glo <32: glo = 32 #clamped to 32-255
+ if glo >255: glo = 255
+ mat.setHardness(glo)
+ if surf.has_key('TRAN'):
+ mat.setAlpha(1.0-surf['TRAN']) #lwo [0.0, 1.0] - blender [1.0, 0.0]
+ mat.mode |= Blender.Material.Modes.RAYTRANSP
+ if surf.has_key('RIND'):
+ s = surf['RIND']
+ if s < 1.0: s = 1.0
+ if s > 3.0: s = 3.0
+ mat.setIOR(s) #clipped to blender [1.0, 3.0]
+ mat.mode |= Blender.Material.Modes.RAYTRANSP
+ if surf.has_key('BLOK') and surf['BLOK'] != []:
+ #update the material according to texture.
+ create_blok(surf, mat, clip_list, dir_part, obj_size, obj_pos)
+ #finished setting up the material
+ #associate material to mesh
+ msh = cur_obj.getData()
+ mat_index = len(msh.getMaterials(1))
+ msh.addMaterial(mat)
+ msh.mode |= Blender.NMesh.Modes.AUTOSMOOTH #smooth it anyway
+ msh.update(1)
+ for f in range(len(msh.faces)):
+ msh.faces[f].materialIndex = mat_index
+ msh.faces[f].smooth = 1 #smooth it anyway
+ msh.faces[f].mode |= Blender.NMesh.FaceModes.TWOSIDE #set it anyway
+ msh.faces[f].transp = Blender.NMesh.FaceTranspModes['SOLID']
+ msh.faces[f].flag = Blender.NMesh.FaceTranspModes['SOLID']
+ if surf.has_key('SMAN'):
+ #not allowed mixed mode mesh (all the mesh is smoothed and all with the same angle)
+ #only one smoothing angle will be active! => take the max one
+ s = int(surf['SMAN']/3.1415926535897932384626433832795*180.0) #lwo in radians - blender in degrees
+ if msh.getMaxSmoothAngle() < s: msh.setMaxSmoothAngle(s)
+ #if surf.has_key('SIDE'):
+ # msh.faces[f].mode |= Blender.NMesh.FaceModes.TWOSIDE #set it anyway
+ if surf.has_key('TRAN') and mat.getAlpha()<1.0:
+ msh.faces[f].transp = Blender.NMesh.FaceTranspModes['ALPHA']
+ if surf.has_key('UVNAME') and facesuv_dict.has_key(surf['UVNAME']):
+ #assign uv-data
+ msh.hasFaceUV(1)
+ #WARNING every block could have its own uvmap set of coordinate. take only the first one
+ facesuv_list = facesuv_dict[surf['UVNAME']]
+ #print "facesuv_list: ",f , facelist[f]
+ rev_face = revert(facesuv_list[facelist[f]])
+ for vi in rev_face:
+ msh.faces[f].uv.append(uvcoords_dict[surf['UVNAME']][vi])
+ if surf.has_key('g_IM'):
+ msh.faces[f].mode |= Blender.NMesh.FaceModes['TEX']
+ msh.faces[f].image = surf['g_IM']
+ #end loop over faces
+ msh.update(1)
+ mat_index += 1
+ #end if exist faces ib this object belonging to surf
+ #end loop on surfaces
+ return
+
# ======================
# === Read Faces 6.0 ===
# ======================
def read_faces_6(lwochunk):
- data = cStringIO.StringIO(lwochunk.read())
- faces = []
- polygon_type = data.read(4)
- if polygon_type != "FACE":
- print "No Faces Were Found. Polygon Type:", polygon_type
- return ""
- i = 0
- while(i < lwochunk.chunksize-4):
- if not i%100 and meshtools.show_progress:
- Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces")
- facev = []
- numfaceverts, = struct.unpack(">H", data.read(2))
- i += 2
-
- for j in range(numfaceverts):
- index, index_size = read_vx(data)
- i += index_size
- facev.append(index)
- facev.reverse()
- faces.append(facev)
- return faces
+ data = cStringIO.StringIO(lwochunk.read())
+ faces = []
+ polygon_type = data.read(4)
+ subsurf = 0
+ if polygon_type != "FACE" and polygon_type != "PTCH":
+ tobj.pprint("No FACE/PATCH Were Found. Polygon Type: %s" % polygon_type)
+ return "", 2
+ if polygon_type == 'PTCH': subsurf = 1
+ i = 0
+ while(i < lwochunk.chunksize-4):
+ if not i%100 and my_meshtools.show_progress:
+ Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces")
+ facev = []
+ numfaceverts, = struct.unpack(">H", data.read(2))
+ i += 2
+
+ for j in range(numfaceverts):
+ index, index_size = read_vx(data)
+ i += index_size
+ facev.append(index)
+ faces.append(facev)
+ tobj.pprint("read %s faces; type of block %d (0=FACE; 1=PATCH)" % (len(faces), subsurf))
+ return faces, subsurf
+
+
+
+# ===========================================================
+# === Start the show and main callback ======================
+# ===========================================================
def fs_callback(filename):
- read(filename)
+ read(filename)
Blender.Window.FileSelector(fs_callback, "Import LWO")
diff --git a/release/scripts/obj_export.py b/release/scripts/obj_export.py
index 205a280f878..c220d66b709 100644
--- a/release/scripts/obj_export.py
+++ b/release/scripts/obj_export.py
@@ -9,7 +9,7 @@ Tooltip: 'Save a Wavefront OBJ File'
__author__ = "Campbell Barton, Jiri Hnidek"
__url__ = ["blender", "elysiun"]
-__version__ = "0.9"
+__version__ = "1.0"
__bpydoc__ = """\
This script is an exporter to OBJ file format.
@@ -49,134 +49,287 @@ def newFName(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 *
-NULL_MAT = '(null)'
-NULL_IMG = '(null)' # from docs at http://astronomy.swin.edu.au/~pbourke/geomformats/obj/ also could be 'off'
+global MTL_DICT
+
+# A Dict of Materials
+# (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
+MTL_DICT = {}
def save_mtl(filename):
+ global MTL_DICT
+
+ world = World.GetCurrent()
+ if world:
+ worldAmb = world.getAmb()
+ else:
+ worldAmb = (0,0,0) # Default value
+
file = open(filename, "w")
- 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.
- if mat.getMode() & Material.Modes['SHADELESS']:
- file.write('illum 0\n\n') # ignore lighting
+ 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:
- file.write('illum 2\n\n') # light normaly
+ 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()
+
+
def save_obj(filename):
+ global MTL_DICT
+
time1 = sys.time()
scn = Scene.GetCurrent()
- # First output all material
- mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
- save_mtl(mtlfilename)
file = open(filename, "w")
# 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')
# 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] ))
# Initialize totals, these are updated each object
- totverts = totuvco = 0
+ totverts = totuvco = totno = 1
globalUVCoords = {}
+ globalNormals = {}
# Get all meshs
for ob in scn.getChildren():
- if ob.getType() != 'Mesh':
+ #for ob in Object.GetSelected():
+ try:
+ # Will work for non meshes now! :)
+ m = NMesh.GetRawFromObject(ob.name)
+ except:
continue
- m = NMesh.GetRawFromObject(ob.name)
+
+ faces = [ f for f in m.faces if len(f) > 2 ]
+
+ if not faces: # Make sure there is somthing to write
+ continue # dont bother with this mesh.
+
m.transform(ob.matrix)
- if not m.faces: # Make sure there is somthing to write
- continue #dont bother with this mesh.
+ # # Crash Blender
+ #materials = m.getMaterials(1) # 1 == will return None in the list.
+ materials = m.getMaterials()
- 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 len(materials) > 1:
- faces.sort(lambda a,b: cmp(a.mat, b.mat))
+ 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])
- # Set the default mat
- currentMatName = NULL_MAT
- currentImgName = NULL_IMG
- file.write('o %s_%s\n' % (ob.getName(), m.name)) # Write Object name
+ # 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
for v in m.verts:
file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
-
+
# UV
if m.hasFaceUV():
for f in faces:
- for uv in f.uv:
- uvKey = '%.6f %.6f' % uv
- try:
- dummy = globalUVCoords[uvKey]
- except KeyError:
- totuvco +=1 # 1 based index.
+ for uvKey in f.uv:
+ if not globalUVCoords.has_key(uvKey):
globalUVCoords[uvKey] = totuvco
- file.write('vt %s 0.0\n' % uvKey)
-
- # NORMAL
- for v in m.verts:
- file.write('vn %.6f %.6f %.6f\n' % tuple(v.no))
+ 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)
+
uvIdx = 0
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:
- currentMatName = NULL_MAT
- file.write('usemtl %s\n' % (currentMatName))
-
- # UV IMAGE
- # If the face uses a different image from the one last set then add a usemap line.
- if f.image:
- if f.image.filename != currentImgName:
- currentImgName = f.image.filename
- # Set a new image for all following faces
- file.write( 'usemap %s\n' % currentImgName.split('\\')[-1].split('/')[-1] )
+ # MAKE KEY
+ if f.image: # Object is always true.
+ key = materialNames[f.mat], f.image.name
+ else:
+ key = materialNames[f.mat], None # No image, use None instead.
+
+ # CHECK FOR CONTEXT SWITCH
+ if key == contextMat:
+ pass # Context alredy switched, dont do anythoing
+ elif key[0] == None and key[1] == None:
+ # Write a null material, since we know the context has changed.
+ file.write('usemtl (null)\n') # mat, image
- elif currentImgName != NULL_IMG: # Not using an image so set to NULL_IMG
- currentImgName = NULL_IMG
- # Set a ne w image for all following faces
- file.write( 'usemap %s\n' % currentImgName) # No splitting needed.
+ else:
+ try: # Faster to try then 2x dict lookups.
+
+ # 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')
if m.hasFaceUV():
- for vi, v in enumerate(f.v):
- uvIdx = globalUVCoords[ '%.6f %.6f' % f.uv[vi] ]
- i = v.index + totverts + 1
- file.write( ' %d/%d/%d' % (i, uvIdx, i)) # vert, uv, normal
-
+ if f.smooth: # Smoothed, use vertex normals
+ for vi, v in enumerate(f.v):
+ file.write( ' %d/%d/%d' % (\
+ v.index+totverts,\
+ 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
- for v in f.v:
- file.write( ' %d' % (v.index + totverts+1))
+ if f.smooth: # Smoothed, use vertex normals
+ for v in f.v:
+ 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')
# Make the indicies global rather then per mesh
totverts += len(m.verts)
file.close()
+
+
+ # Now we have all our materials, save them
+ save_mtl(mtlfilename)
+
print "obj export time: %.2f" % (sys.time() - time1)
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
+'''
diff --git a/release/scripts/obj_import.py b/release/scripts/obj_import.py
index 268bf44f353..d8788f6d042 100644
--- a/release/scripts/obj_import.py
+++ b/release/scripts/obj_import.py
@@ -4,7 +4,7 @@
Name: 'Wavefront (.obj)...'
Blender: 237
Group: 'Import'
-Tooltip: 'Load a Wavefront OBJ File'
+Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.'
"""
__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 *****
# --------------------------------------------------------------------------
-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 #
@@ -71,52 +63,243 @@ def stripPath(path):
# Strips the prefix off the name before writing #
#====================================================#
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 *
-#==================================================================================#
-# This function sets textures defined in .mtl file #
-#==================================================================================#
-def getImg(img_fileName, dir):
- 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
+
+# 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.
+
- # 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
+
+ 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 #
+#==================================================================================#
+# ___ Replaced by comprehensive imahge get
+
#==================================================================================#
# This function sets textures defined in .mtl file #
#==================================================================================#
@@ -127,7 +310,7 @@ def loadMaterialImage(mat, img_fileName, type, meshDict, dir):
texture.setType('Image')
# Absolute path - c:\.. etc would work here
- image = getImg(img_fileName, dir)
+ image = comprehansiveImageLoad(img_fileName, dir)
if image:
texture.image = image
@@ -135,7 +318,7 @@ def loadMaterialImage(mat, img_fileName, type, meshDict, dir):
# 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.
if image and type == 'Kd':
- for meshPair in meshDict.values():
+ for meshPair in meshDict.itervalues():
for f in meshPair[0].faces:
#print 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':
currentMat = getMat('_'.join(l[1:]), materialDict) # Material should alredy exist.
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':
- 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':
- 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':
currentMat.setHardness( int((float(l[1])*0.51)) )
elif l[0] == 'Ni': # Refraction index
@@ -238,7 +421,9 @@ def load_mtl(dir, mtl_file, meshDict, materialDict):
lIdx+=1
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) #
#===========================================================================#
@@ -262,6 +447,9 @@ def getUniqueName(name):
# This loads data from .obj file #
#==================================================================================#
def load_obj(file):
+
+ print '\nImporting OBJ file: "%s"' % file
+
time1 = sys.time()
# Deselect all objects in the scene.
@@ -274,7 +462,7 @@ def load_obj(file):
# Get the file name with no path or .obj
fileName = stripExt( stripPath(file) )
- mtl_fileName = None
+ mtl_fileName = [] # Support multiple mtl files if needed.
DIR = stripFile(file)
@@ -282,11 +470,11 @@ def load_obj(file):
fileLines = tempFile.readlines()
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-
# 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
@@ -297,7 +485,7 @@ def load_obj(file):
contextMeshMatIdx = -1
# Keep this out of the dict for easy accsess.
- nullMat = Material.New(NULL_MAT)
+ nullMat = Material.New('(null)')
currentMat = nullMat # Use this mat.
currentImg = None # Null image is a string, otherwise this should be set to an image object.\
@@ -320,57 +508,54 @@ def load_obj(file):
materialDict = {} # Store all imported materials as unique dict, names are key
lIdx = 0
print '\tfile length: %d' % len(fileLines)
- try:
- while lIdx < len(fileLines):
- # Ignore vert normals
- if fileLines[lIdx].startswith('vn'):
- lIdx+=1
- continue
+
+ while lIdx < len(fileLines):
+ # Ignore vert normals
+ if fileLines[lIdx].startswith('vn'):
+ lIdx+=1
+ continue
+
+ # Dont Bother splitting empty or comment lines.
+ if len(fileLines[lIdx]) == 0 or\
+ fileLines[lIdx][0] == '\n' or\
+ fileLines[lIdx][0] == '#':
+ pass
+
+ else:
+ fileLines[lIdx] = fileLines[lIdx].split()
+ l = fileLines[lIdx]
- # Dont Bother splitting empty or comment lines.
- if len(fileLines[lIdx]) == 0 or\
- fileLines[lIdx][0] == '\n' or\
- fileLines[lIdx][0] == '#':
+ # Splitting may
+ if len(l) == 0:
pass
+ # Verts
+ elif l[0] == 'v':
+ vertList.append( NMesh.Vert(float(l[1]), float(l[2]), float(l[3]) ) )
+
+ # UV COORDINATE
+ elif l[0] == 'vt':
+ uvMapList.append( (float(l[1]), float(l[2])) )
+
+ # Smoothing groups, make a list of unique.
+ elif l[0] == 's':
+ if len(l) > 1:
+ smoothingGroups['_'.join(l[1:])] = None # Can we assign something more usefull? cant use sets yet
+
+ # Keep Smoothing group line
+ nonVertFileLines.append(l)
+
+ # Smoothing groups, make a list of unique.
+ elif l[0] == 'usemtl':
+ if len(l) > 1:
+ materialDict['_'.join(l[1:])] = None # Can we assign something more usefull? cant use sets yet
+
+ # Keep Smoothing group line
+ nonVertFileLines.append(l)
else:
- fileLines[lIdx] = fileLines[lIdx].split()
- l = fileLines[lIdx]
-
- # Splitting may
- if len(l) == 0:
- pass
- # Verts
- elif l[0] == 'v':
- vertList.append( NMesh.Vert(float(l[1]), float(l[2]), float(l[3]) ) )
-
- # UV COORDINATE
- elif l[0] == 'vt':
- uvMapList.append( (float(l[1]), float(l[2])) )
-
- # Smoothing groups, make a list of unique.
- elif l[0] == 's':
- if len(l) > 1:
- smoothingGroups['_'.join(l[1:])] = None # Can we assign something more usefull? cant use sets yet
-
- # Keep Smoothing group line
- nonVertFileLines.append(l)
-
- # Smoothing groups, make a list of unique.
- elif l[0] == 'usemtl':
- if len(l) > 1:
- materialDict['_'.join(l[1:])] = None # Can we assign something more usefull? cant use sets yet
-
- # Keep Smoothing group line
- nonVertFileLines.append(l)
-
- else:
- nonVertFileLines.append(l)
- lIdx+=1
-
- except:
- print Draw.PupMenu(ABORT_MENU)
- return
+ nonVertFileLines.append(l)
+ lIdx+=1
+
del fileLines
fileLines = nonVertFileLines
@@ -382,7 +567,7 @@ def load_obj(file):
print '\tfound %d smoothing groups.' % (len(smoothingGroups) -1)
# 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)
@@ -419,113 +604,106 @@ def load_obj(file):
# 0:NMesh, 1:SmoothGroups[UsedVerts[0,0,0,0]], 2:materialMapping['matname':matIndexForThisNMesh]
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:
currentMesh.hasFaceUV(1) # Turn UV's on if we have ANY texture coords in this obj file.
-
+
#==================================================================================#
# Load all faces into objects, main loop #
#==================================================================================#
- try:
- lIdx = 0
- # Face and Object loading LOOP
- while lIdx < len(fileLines):
- l = fileLines[lIdx]
+ lIdx = 0
+ # Face and Object loading LOOP
+ while lIdx < len(fileLines):
+ l = fileLines[lIdx]
+
+ # FACE
+ if l[0] == 'f':
+ # Make a face with the correct material.
- # FACE
- if l[0] == 'f':
- # Make a face with the correct material.
+ # Add material to mesh
+ if contextMeshMatIdx == -1:
+ tmpMatLs = currentMesh.materials
- # Add material to mesh
- if contextMeshMatIdx == -1:
- tmpMatLs = currentMesh.materials
-
- if len(tmpMatLs) == MATLIMIT:
- contextMeshMatIdx = 0 # Use first material
- print 'material overflow, attempting to use > 16 materials. defaulting to first.'
- else:
- contextMeshMatIdx = len(tmpMatLs)
- currentMaterialMeshMapping[currentMat.name] = contextMeshMatIdx
- currentMesh.addMaterial(currentMat)
+ if len(tmpMatLs) == 16:
+ contextMeshMatIdx = 0 # Use first material
+ print 'material overflow, attempting to use > 16 materials. defaulting to first.'
+ else:
+ contextMeshMatIdx = len(tmpMatLs)
+ currentMaterialMeshMapping[currentMat.name] = contextMeshMatIdx
+ currentMesh.addMaterial(currentMat)
+
+ # Set up vIdxLs : Verts
+ # Set up vtIdxLs : UV
+ # Start with a dummy objects so python accepts OBJs 1 is the first index.
+ vIdxLs = []
+ vtIdxLs = []
+
+
+ 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:]:
+ # OBJ files can have // or / to seperate vert/texVert/normal
+ # this is a bit of a pain but we must deal with it.
+ objVert = v.split('/')
- # Set up vIdxLs : Verts
- # Set up vtIdxLs : UV
- # Start with a dummy objects so python accepts OBJs 1 is the first index.
- vIdxLs = []
- 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.
- for v in l[1:]:
- # OBJ files can have // or / to seperate vert/texVert/normal
- # this is a bit of a pain but we must deal with it.
- objVert = v.split('/')
-
- # Vert Index - OBJ supports negative index assignment (like python)
+ # Vert Index - OBJ supports negative index assignment (like python)
+
+ vIdxLs.append(int(objVert[0])-1)
+ if fHasUV:
+ # UV
+ index = 0 # Dummy var
+ if len(objVert) == 1:
+ index = vIdxLs[-1]
+ elif objVert[1]: # != '' # Its possible that theres no texture vert just he vert and normal eg 1//2
+ index = int(objVert[1])-1
- vIdxLs.append(int(objVert[0]))
- if fHasUV:
- # UV
- if len(objVert) == 1:
- #vtIdxLs.append(int(objVert[0])) # replace with below.
- 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
- vtIdxLs.append(int(objVert[1])) # Seperate UV coords
- else:
- fHasUV = 0
+ if len(uvMapList) > index:
+ vtIdxLs.append(index) # Seperate UV coords
+ 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
- # Dont add a UV to the face if its larger then the UV coord list
- # The OBJ file would have to be corrupt or badly written for thi to happen
- # but account for it anyway.
- if len(vtIdxLs) > 0:
- if vtIdxLs[-1] > len(uvMapList):
- fHasUV = 0
- print 'badly written OBJ file, invalid references to UV Texture coordinates.'
+ # Dont add a UV to the face if its larger then the UV coord list
+ # The OBJ file would have to be corrupt or badly written for thi to happen
+ # but account for it anyway.
+ if len(vtIdxLs) > 0:
+ if vtIdxLs[-1] > len(uvMapList):
+ fHasUV = 0
+
+ badObjUvs +=1 # ERROR, Cont
+ # Quads only, we could import quads using the method below but it polite to import a quad as a quad.
+ if len(vIdxLs) == 4:
- # Quads only, we could import quads using the method below but it polite to import a quad as a quad.
- 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]
if currentUsedVertListSmoothGroup[vIdxLs[i]] == 0:
- v = vertList[vIdxLs[i]]
- currentMesh.verts.append(v)
- f.append(v)
+ faceQuadVList[i] = vertList[vIdxLs[i]]
+ currentMesh.verts.append(faceQuadVList[i])
currentUsedVertListSmoothGroup[vIdxLs[i]] = len(currentMesh.verts)-1
else:
- f.v.append(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]]]
+ faceQuadVList[i] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[i]]]
- 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)
-
# UV MAPPING
if fHasUV:
f.uv = [uvMapList[ vtIdxLs[0] ],uvMapList[ vtIdxLs[1] ],uvMapList[ vtIdxLs[2] ],uvMapList[ vtIdxLs[3] ]]
@@ -537,43 +715,23 @@ def load_obj(file):
f.mat = contextMeshMatIdx
f.smooth = currentSmooth
currentMesh.faces.append(f) # move the face onto the mesh
-
- elif len(vIdxLs) >= 3: # This handles tri's and fans
- for i in range(len(vIdxLs)-2):
- '''
- f = NMesh.Face()
- for ii in [0, i+1, i+2]:
- if currentUsedVertListSmoothGroup[vIdxLs[ii]] == 0:
- v = vertList[vIdxLs[ii]]
- currentMesh.verts.append(v)
- f.append(v)
- currentUsedVertListSmoothGroup[vIdxLs[ii]] = len(currentMesh.verts)-1
+
+ elif len(vIdxLs) >= 3: # This handles tri's and fans
+ for i in range(len(vIdxLs)-2):
+ if vIdxLs[0] == vIdxLs[i+1] or\
+ vIdxLs[0] == vIdxLs[i+2] or\
+ vIdxLs[i+1] == vIdxLs[i+2]:
+ badObjFaceVerts+=1
+ else:
+ 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])
+ currentUsedVertListSmoothGroup[vIdxLs[j]] = len(currentMesh.verts)-1
else:
- f.v.append(currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[ii]]])
- '''
-
-
- if currentUsedVertListSmoothGroup[vIdxLs[0]] == 0:
- faceTriVList[0] = vertList[vIdxLs[0]]
- currentUsedVertListSmoothGroup[vIdxLs[0]] = len(currentMesh.verts)
- else:
- faceTriVList[0] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[0]]]
-
- 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)
+ faceTriVList[k] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[j]]]
+ f = NMesh.Face(faceTriVList)
# UV MAPPING
if fHasUV:
@@ -586,177 +744,195 @@ def load_obj(file):
f.mat = contextMeshMatIdx
f.smooth = currentSmooth
currentMesh.faces.append(f) # move the face onto the mesh
-
- # FACE SMOOTHING
- elif l[0] == 's':
- # No value? then turn on.
- if len(l) == 1:
- currentSmooth = True
+
+ # FACE SMOOTHING
+ elif l[0] == 's':
+ # No value? then turn on.
+ if len(l) == 1:
+ currentSmooth = True
+ currentSmoothGroup = '(null)'
+ try:
+ currentUsedVertListSmoothGroup = currentUsedVertList[currentSmoothGroup]
+ except KeyError:
+ currentUsedVertListSmoothGroup = VERT_USED_LIST[:]
+ currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup
+
+ else:
+ if l[1] == 'off':
+ currentSmooth = False
currentSmoothGroup = '(null)'
- try:
- currentUsedVertListSmoothGroup = currentUsedVertList[currentSmoothGroup]
- except KeyError:
- currentUsedVertListSmoothGroup = VERT_USED_LIST[:]
- currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup
-
- else:
- if l[1] == 'off':
- currentSmooth = False
- currentSmoothGroup = '(null)'
- # We all have a null group so dont need to try
- currentUsedVertListSmoothGroup = currentUsedVertList['(null)']
- else:
- currentSmooth = True
- currentSmoothGroup = '_'.join(l[1:])
-
- # OBJECT / GROUP
- elif l[0] == 'o' or l[0] == 'g':
+ # We all have a null group so dont need to try
+ currentUsedVertListSmoothGroup = currentUsedVertList['(null)']
+ else:
+ currentSmooth = True
+ currentSmoothGroup = '_'.join(l[1:])
+
+ # OBJECT / GROUP
+ elif l[0] == 'o' or l[0] == 'g':
+
+ # Forget about the current image
+ currentImg = None
+
+ # This makes sure that if an object and a group have the same name then
+ # they are not put into the same object.
+
+ # Only make a new group.object name if the verts in the existing object have been used, this is obscure
+ # but some files face groups seperating verts and faces which results in silly things. (no groups have names.)
+ if len(l) > 1:
+ currentObjectName = '_'.join(l[1:])
+ else: # No name given
+ # Make a new empty name
+ if l[0] == 'g': # Make a blank group name
+ currentObjectName = 'unnamed_grp_%d' % currentUnnamedGroupIdx
+ currentUnnamedGroupIdx +=1
+ else: # is an object.
+ currentObjectName = 'unnamed_ob_%d' % currentUnnamedObjectIdx
+ currentUnnamedObjectIdx +=1
+
+
+ # If we havnt written to this mesh before then do so.
+ # if we have then we'll just keep appending to it, this is required for soem files.
+
+ # If we are new, or we are not yet in the list of added meshes
+ # then make us new mesh.
+ if len(l) == 1 or (not meshDict.has_key(currentObjectName)):
+ currentMesh = NMesh.GetRaw()
- # Forget about the current image
- currentImg = None
+ currentUsedVertList = {}
- # This makes sure that if an object and a group have the same name then
- # they are not put into the same object.
+ # Sg is a string
+ currentSmoothGroup = '(null)'
+ currentUsedVertListSmoothGroup = VERT_USED_LIST[:]
+ currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup
+ currentMaterialMeshMapping = {}
- # Only make a new group.object name if the verts in the existing object have been used, this is obscure
- # but some files face groups seperating verts and faces which results in silly things. (no groups have names.)
- if len(l) > 1:
- currentObjectName = '_'.join(l[1:])
- else: # No name given
- # Make a new empty name
- if l[0] == 'g': # Make a blank group name
- currentObjectName = 'unnamed_grp_%d' % currentUnnamedGroupIdx
- currentUnnamedGroupIdx +=1
- else: # is an object.
- currentObjectName = 'unnamed_ob_%d' % currentUnnamedObjectIdx
- currentUnnamedObjectIdx +=1
+ meshDict[currentObjectName] = (currentMesh, currentUsedVertList, currentMaterialMeshMapping)
+ currentMesh.hasFaceUV(1)
+ contextMeshMatIdx = -1
+ else:
+ # Since we have this in Blender then we will check if the current Mesh has the material.
+ # set the contextMeshMatIdx to the meshs index but only if we have it.
+ currentMesh, currentUsedVertList, currentMaterialMeshMapping = meshDict[currentObjectName]
+ #getMeshMaterialIndex(currentMesh, currentMat)
- # If we havnt written to this mesh before then do so.
- # if we have then we'll just keep appending to it, this is required for soem files.
+ try:
+ contextMeshMatIdx = currentMaterialMeshMapping[currentMat.name] #getMeshMaterialIndex(currentMesh, currentMat)
+ except KeyError:
+ contextMeshMatIdx -1
- # If we are new, or we are not yet in the list of added meshes
- # then make us new mesh.
- if len(l) == 1 or currentObjectName not in meshDict.keys():
- currentMesh = NMesh.GetRaw()
-
- currentUsedVertList = {}
-
- # Sg is a string
- currentSmoothGroup = '(null)'
- currentUsedVertListSmoothGroup = VERT_USED_LIST[:]
- currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup
- currentMaterialMeshMapping = {}
-
- meshDict[currentObjectName] = (currentMesh, currentUsedVertList, currentMaterialMeshMapping)
- currentMesh.hasFaceUV(1)
- currentMesh.verts.append( vertList[0] )
- contextMeshMatIdx = -1
-
- else:
- # Since we have this in Blender then we will check if the current Mesh has the material.
- # set the contextMeshMatIdx to the meshs index but only if we have it.
- currentMesh, currentUsedVertList, currentMaterialMeshMapping = meshDict[currentObjectName]
- #getMeshMaterialIndex(currentMesh, currentMat)
-
- try:
- contextMeshMatIdx = currentMaterialMeshMapping[currentMat.name] #getMeshMaterialIndex(currentMesh, currentMat)
- except KeyError:
- contextMeshMatIdx -1
-
- # For new meshes switch smoothing groups to null
- currentSmoothGroup = '(null)'
- currentUsedVertListSmoothGroup = currentUsedVertList[currentSmoothGroup]
+ # For new meshes switch smoothing groups to null
+ currentSmoothGroup = '(null)'
+ currentUsedVertListSmoothGroup = currentUsedVertList[currentSmoothGroup]
+
+ # MATERIAL
+ elif l[0] == 'usemtl':
+ if len(l) == 1 or l[1] == '(null)':
+ currentMat = nullMat # We know we have a null mat.
+ else:
+ currentMat = materialDict['_'.join(l[1:])]
+ try:
+ contextMeshMatIdx = currentMaterialMeshMapping[currentMat.name]
+ except KeyError:
+ contextMeshMatIdx = -1 #getMeshMaterialIndex(currentMesh, currentMat)
- # MATERIAL
- elif l[0] == 'usemtl':
- if len(l) == 1 or l[1] == NULL_MAT:
- currentMat = nullMat # We know we have a null mat.
- else:
- currentMat = materialDict['_'.join(l[1:])]
- try:
- contextMeshMatIdx = currentMaterialMeshMapping[currentMat.name]
- except KeyError:
- contextMeshMatIdx = -1 #getMeshMaterialIndex(currentMesh, currentMat)
+ # IMAGE
+ elif l[0] == 'usemat' or l[0] == 'usemap':
+ if len(l) == 1 or l[1] == '(null)' or l[1] == 'off':
+ currentImg = None
+ else:
+ # Load an image.
+ newImgName = stripPath(' '.join(l[1:])) # Use space since its a file name.
- # IMAGE
- elif l[0] == 'usemat' or l[0] == 'usemap':
- if len(l) == 1 or l[1] == '(null)' or l[1] == 'off':
- currentImg = None
- else:
- # Load an image.
- newImgName = stripPath(' '.join(l[1:])) # Use space since its a file name.
+ try:
+ # Assume its alredy set in the dict (may or maynot be loaded)
+ currentImg = imageDict[newImgName]
+
+ except KeyError: # Not in dict, add for first time.
+ # Image has not been added, Try and load the image
+ currentImg = comprehansiveImageLoad(newImgName, DIR) # Use join in case of spaces
+ imageDict[newImgName] = currentImg
+ # These may be None, thats okay.
- try:
- # Assume its alredy set in the dict (may or maynot be loaded)
- currentImg = imageDict[newImgName]
- except KeyError: # Not in dict, add for first time.
- # Image has not been added, Try and load the image
- currentImg = getImg(newImgName, DIR) # Use join in case of spaces
- imageDict[newImgName] = currentImg
- # These may be None, thats okay.
-
-
-
- # MATERIAL FILE
- elif l[0] == 'mtllib':
- mtl_fileName = ' '.join(l[1:]) # SHOULD SUPPORT MULTIPLE MTL?
- lIdx+=1
- # Applies material properties to materials alredy on the mesh as well as Textures.
- if mtl_fileName:
- load_mtl(DIR, mtl_fileName, meshDict, materialDict)
+ # MATERIAL FILE
+ elif l[0] == 'mtllib':
+ mtl_fileName.append(' '.join(l[1:]) ) # SHOULD SUPPORT MULTIPLE MTL?
+ lIdx+=1
+
+ # Applies material properties to materials alredy on the mesh as well as Textures.
+ for mtl in mtl_fileName:
+ load_mtl(DIR, mtl, meshDict, materialDict)
+
+
+ importedObjects = []
+ for mk, me in meshDict.iteritems():
+ nme = me[0]
+ # Ignore no vert meshes.
+ if not nme.verts: # == []
+ continue
- importedObjects = []
- for mk in meshDict.keys():
- meshDict[mk][0].verts.pop(0)
-
- # Ignore no vert meshes.
- if not meshDict[mk][0].verts:
- continue
-
- name = getUniqueName(mk)
- ob = NMesh.PutRaw(meshDict[mk][0], name)
- ob.name = name
-
- importedObjects.append(ob)
+ name = getUniqueName(mk)
+ ob = NMesh.PutRaw(nme, name)
+ ob.name = name
- # Select all imported objects.
- for ob in importedObjects:
- ob.sel = 1
+ importedObjects.append(ob)
- print "obj import time: ", sys.time() - time1
+ # Select all imported objects.
+ for ob in importedObjects:
+ ob.sel = 1
+ if badObjUvs > 0:
+ print '\tERROR: found %d faces with badly formatted UV coords. everything else went okay.' % badObjUvs
- except:
- print Draw.PupMenu(ABORT_MENU)
- return
-
+ 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
+
+# Batch directory loading.
+def load_obj_dir(obj_dir):
+
+ # Strip file
+ obj_dir = stripFile(obj_dir)
+ time = sys.time()
+
+ objFiles = [f for f in os.listdir(obj_dir) if f.lower().endswith('obj')]
+
+ Window.DrawProgressBar(0, '')
+ count = 0
+ obj_len = len(objFiles)
+ for obj in objFiles:
+ count+=1
+
+ newScn = Scene.New(obj)
+ newScn.makeCurrent()
+
+ Window.DrawProgressBar((float(count)/obj_len) - 0.01, '%s: %i of %i' % (obj, count, obj_len))
+
+ load_obj(obj_dir + obj)
+
+ Window.DrawProgressBar(1, '')
+ print 'Total obj import "%s" dir: %.2f' % (obj_dir, sys.time() - time)
-def load_obj_callback(file):
- # 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')
+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)
-# 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.makeCurrent()
- load_obj('/obj/' + obj)
-
-print "TOTAL IMPORT TIME: ", sys.time() - TIME
-'''
-#load_obj('/obj/foot_bones.obj')
-#load_obj('/obj/mba1.obj')
-#load_obj('/obj/PixZSphere50.OBJ')
-#load_obj('/obj/obj_test/LHand.obj')
+if __name__ == '__main__':
+ main()
diff --git a/release/scripts/skin.py b/release/scripts/skin.py
index d3d1d034db7..adf49b1af7b 100644
--- a/release/scripts/skin.py
+++ b/release/scripts/skin.py
@@ -1,15 +1,15 @@
#!BPY
"""
-Name: 'Bridge/Skin/Loft'
-Blender: 234
+Name: 'Bridge Faces/Edge-Loops'
+Blender: 237
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"
__url__ = ["http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun"]
-__version__ = "1.1 2005/06/13"
+__version__ = "1.0 2004/04/25"
__bpydoc__ = """\
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
vertices: circles, for example) that should be skinned, then run this script.
-A pop-up will provide further options.
-
-Notes:
-
-If the results of a method chosen from the pop-up are not adequate, undo and try one of the others.
+A pop-up will provide further options, if the results of a method are not adequate 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 *****
# --------------------------------------------------------------------------
-
-
-# Made by Ideasman/Campbell 2004/04/25 - ideasman@linuxmail.org
+# Made by Ideasman/Campbell 2005/06/15 - ideasman@linuxmail.org
import Blender
from Blender import *
-import math
-from math import *
-
-
-choice = Draw.PupMenu(\
-'Loft-loop - shortest edge method|\
-Loft-loop - even method|\
-Loft-segment - shortest edge|\
-Loft-segment - even method')
-
-if choice == 1:
- arg='A1'
-elif choice == 2:
- arg='A2'
-elif choice == 3:
- arg='B1'
-elif choice == 4:
- arg='B2'
-
-
-#================#
-# Math functions #
-#================#
+BIG_NUM = 1<<30
-# Measure 2 points
-def measure(v1, v2):
- return Mathutils.Vector([v1[0]-v2[0], v1[1] - v2[1], v1[2] - v2[2]]).length
-
-# Clamp
-def clamp(max, number):
- while number >= max:
- number = number - max
- return number
+global CULL_METHOD
+CULL_METHOD = 0
-#=============================================================#
-# 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]:
+class edge:
+ def __init__(self, v1,v2):
+ self.v1 = v1
+ self.v2 = v2
- # Add all the values from 1 of the 3 coords at the avLoc.
- for loc in locList:
- avLoc[coordIdx] += loc[coordIdx]
+ # uv1 uv2 vcol1 vcol2 # Add later
+ self.length = (v1.co - v2.co).length
- avLoc[coordIdx] = avLoc[coordIdx] / len(locList)
- return avLoc
-
-
+ self.removed = 0 # Have we been culled from the eloop
+ self.match = None # The other edge were making a face with
-#=============================#
-# Blender functions/shortcuts #
-#=============================#
-def error(str):
- Draw.PupMenu('ERROR%t|'+str)
-# Returns a new face that has the same properties as the origional face
-# With no verts though
-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
-
-
-#=======================================================#
-# Measure the total distance between all the edges in #
-# 2 vertex loops #
-#=======================================================#
-def measureVloop(mesh, v1loop, v2loop, surplusFaces, bestSoFar):
- totalDist = 0
-
- # Rotate the vertloops to cycle through each pair.
- # of faces to compate the distance between the 2 poins
- for ii in range(len(v1loop)):
- 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]])
- V2 = selVertBetween2Faces(mesh.faces[v2loop[v2clampii-1]], mesh.faces[v2loop[v2clampii]])
-
- totalDist += measure(V1, V2)
- # Bail out early if not an improvement on previously measured.
- if bestSoFar != None and totalDist > bestSoFar:
- return totalDist
-
- #selVertBetween2Faces(mesh.faces[v2loop[0]], mesh.faces[v2loop[1]])
- return totalDist
-
-# Remove the shortest edge from a vert loop
-def removeSmallestFace(mesh, vloop):
- 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)
-
- if bestDistSoFar == None:
- bestDistSoFar = dist
- 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):
-
-
- #=============================================#
- # Handle uneven vert loops, this is tricky #
- #=============================================#
- # 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
- surplusFaces = []
- tempv1loop = v1loop[:] # strip faces off this one, use it to keep track of which we have taken faces from.
- if len(v1loop) > len(v2loop):
-
- # Even face method.
- if arg[1] == '2':
- remIdx = 0
- faceStepping = len( v1loop) / len(v2loop)
- while len(v1loop) - len(surplusFaces) > len(v2loop):
- remIdx += faceStepping
- surplusFaces.append(tempv1loop[ clamp(len(tempv1loop),remIdx) ])
- tempv1loop.remove(surplusFaces[-1])
-
- # Shortest face
- elif arg[1] == '1':
- while len(v1loop) - len(surplusFaces) > len(v2loop):
- surplusFaces.append(removeSmallestFace(mesh, tempv1loop))
- tempv1loop.remove(surplusFaces[-1])
-
-
- tempv1loop = None
-
- v2loop = optimizeLoopOrdedShortEdge(mesh, v1loop, v2loop, surplusFaces)
-
- # make Faces from
- lenVloop = len(v1loop)
- lenSupFaces = len(surplusFaces)
- fIdx = 0
- offset = 0
- while fIdx < lenVloop:
+class edgeLoop:
+ def __init__(self, loop): # Vert loop
+ # Use next and prev, nextDist, prevDist
- face = copyFace( mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]] )
+ # Get Loops centre.
+ self.centre = Mathutils.Vector()
+ f = 1.0/len(loop)
+ for v in loop:
+ self.centre += v.co * f
- if v1loop[fIdx] in surplusFaces:
- # Draw a try, this face does not catch with an edge.
- # So we must draw a tri and wedge it in.
-
- # Copy old faces properties
+
+
+
+ # Convert Vert loop to Edges.
+ self.edges = []
+ vIdx = 0
+ while vIdx < len(loop):
+ self.edges.append( edge(loop[vIdx-1], loop[vIdx]) )
+ vIdx += 1
+
+ # Assign linked list
+ for eIdx in range(len(self.edges)-1):
+ self.edges[eIdx].next = self.edges[eIdx+1]
+ self.edges[eIdx].prev = self.edges[eIdx-1]
+ # Now last
+ self.edges[-1].next = self.edges[0]
+ self.edges[-1].prev = self.edges[-2]
+
+
+
+ # GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP.
+ self.normal = Mathutils.Vector()
+ for e in self.edges:
+ n = Mathutils.CrossVecs(self.centre-e.v1.co, self.centre-e.v2.co)
+ # Do we realy need tot normalize?
+ n.normalize()
+ self.normal += n
+ self.normal.normalize()
+
+
+ # Generate a normal for each edge.
+ for e in self.edges:
- face.v.append( selVertBetween2Faces(\
- mesh.faces[v1loop[clamp(lenVloop, fIdx)]],\
- mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]]) )
+ n1 = e.v1.co
+ n2 = e.v2.co
+ n3 = e.prev.v1.co
- face.v.append( selVertBetween2Faces(\
- mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]],\
- mesh.faces[v1loop[clamp(lenVloop, fIdx+2)]]) )
+ a = n1-n2
+ b = n1-n3
+ normal1 = Mathutils.CrossVecs(a,b)
+ normal1.normalize()
- #face.v.append( selVertBetween2Faces(\
- #mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset +1 ))]],\
- #mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset + 2))]]) )
+ n1 = e.v2.co
+ n3 = e.next.v2.co
+ n2 = e.v1.co
- face.v.append( selVertBetween2Faces(\
- mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset))]],\
- mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, fIdx - offset + 1)]]) )
+ a = n1-n2
+ b = n1-n3
- mesh.faces.append(face)
+ normal2 = Mathutils.CrossVecs(a,b)
+ normal2.normalize()
- # We need offset to work out how much smaller v2loop is at this current index.
- offset+=1
+ # Reuse normal1 var
+ normal1 += normal1 + normal2
+ normal1.normalize()
+ e.normal = normal1
+ #print e.normal
+
- else:
- # Draw a normal quad between the 2 edges/faces
-
- face.v.append( selVertBetween2Faces(\
- mesh.faces[v1loop[clamp(lenVloop, fIdx)]],\
- mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]]) )
+
+
+ def backup(self):
+ # Keep a backup of the edges
+ self.backupEdges = self.edges[:]
- face.v.append( selVertBetween2Faces(\
- mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]],\
- mesh.faces[v1loop[clamp(lenVloop, fIdx+2)]]) )
+ def restore(self):
+ self.edges = self.backupEdges[:]
+ for e in self.edges:
+ e.removed = 0
+
+ def reverse(self):
+ self.edges.reverse()
+ for e in self.edges:
+ e.normal = -e.normal
+ e.v1, e.v2 = e.v2, e.v1
+ self.normal = -self.normal
+
+ # Removes N Smallest edges and backs up
+ def removeSmallest(self, cullNum, otherLoopLen):
+ global CULL_METHOD
+ if CULL_METHOD == 0: # Shortest edge
- face.v.append( selVertBetween2Faces(\
- mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset +1 ))]],\
- mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset + 2))]]) )
+ 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.
- face.v.append( selVertBetween2Faces(\
- mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset))]],\
- mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, fIdx - offset + 1)]]) )
+ else: # CULL METHOD is even
+
+ culled = 0
- mesh.faces.append(face)
+ step = int(otherLoopLen / float(cullNum))
- 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]
+ 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
+
- 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
+# Returns face edges.
+# face must have edge data.
+def faceEdges(me, f):
+ if len(f) == 3:
+ return [\
+ me.findEdge(f[0], f[1]),\
+ me.findEdge(f[1], f[2]),\
+ me.findEdge(f[2], f[0])\
+ ]
+ elif len(f) == 4:
+ return [\
+ me.findEdge(f[0], f[1]),\
+ me.findEdge(f[1], f[2]),\
+ me.findEdge(f[2], f[3]),\
+ me.findEdge(f[3], f[0])\
+ ]
+
+
+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)
- fIdx +=1
-
- return vertLoopLs
-
-
+ # 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:
+ # None found? Keep looking
+ continue
+
+ # Once found we.
+ break
+
+ # 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)
+
+ # Build context vert loops
+ return mainVertLoops
-#================================================================#
-# Now we work out the optimum order to 'skin' the 2 vert loops #
-# 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
- for ii in range(len(v1loop)):
-
- # 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
-
-
-#================================================================#
-# Now we work out the optimum order to 'skin' the 2 vert loops #
-# 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 optimizeLoopOrdedShortEdge(mesh, v1loop, v2loop, surplusFaces):
- bestSoFar = None
-
- # Measure the dist, ii is just a counter
- for ii in range(len(v2loop)):
-
- # Loop twice , Once for the forward test, and another for the revearsed
- for iii in [None, None]:
- dist = measureVloop(mesh, v1loop, v2loop, surplusFaces, bestSoFar)
- print 'dist', dist
- # 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()
- #v2loop = listRotate(v2loop)
- listRotate(v2loop)
- print 'best so far ', bestSoFar
- return bestv2Loop
+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.
-
-#==============================#
-# 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
+ # The vector allong which we are skinning.
+ skinVector = eloop1.centre - eloop2.centre
+
+ loopDist = skinVector.length
+
+
+ # IS THE LOOP FLIPPED, IF SO FLIP BACK.
+ angleBetweenLoopNormals = Mathutils.AngleBetweenVecs(eloop1.normal, eloop2.normal)
+
+ if angleBetweenLoopNormals > 90:
+ eloop2.reverse()
+
+
+ bestEloopDist = BIG_NUM
+ bestOffset = 0
+ # Loop rotation offset to test.1
+ eLoopIdxs = range(len(eloop1.edges))
+ for offset in range(len(eloop1.edges)):
+ totEloopDist = 0 # Measure this total distance for thsi loop.
+
+ offsetIndexLs = eLoopIdxs[offset:] + eLoopIdxs[:offset] # Make offset index list
+
+ # e1Idx is always from 0 to N, e2Idx is offset.
+ for e1Idx, e2Idx in enumerate(offsetIndexLs):
+ # Measure the vloop distance ===============
+ totEloopDist += ((eloop1.edges[e1Idx].v1.co - eloop2.edges[e2Idx].v1.co).length / loopDist) #/ nangle1
+ totEloopDist += ((eloop1.edges[e1Idx].v2.co - eloop2.edges[e2Idx].v2.co).length / loopDist) #/ nangle1
+
+ # Premeture break if where no better off
+ if totEloopDist > bestEloopDist:
break
- fIdx+=1
+
+ if totEloopDist < bestEloopDist:
+ bestOffset = offset
+ bestEloopDist = totEloopDist
- # Here we access the function that generates the real vert loop
- if startFaceIdx != None:
- return vertLoop(mesh, startFaceIdx, fIgLs)
- else:
- # We are out'a vert loops, return a None,
- 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)
-
-
+ # 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()
-#=================================================#
-# Vert loop group functions
-def getAllVertLoops(mesh):
- # Make a chain of vert loops.
- fIgLs = [] # List of faces to ignore
- allVLoops = [findVertLoop(mesh, fIgLs)]
- while allVLoops[-1] != None:
+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:
+ choice = 2
+
+
+ # 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
- # In future ignore all faces in this vert loop
- fIgLs += allVLoops[-1]
+ if CULL_METHOD ==1: # RESET CULL_METHOD
+ CULL_METHOD = 0 # shortest
+ else:
+ CULL_METHOD = 1 # even
+
+
+ time1 = sys.time()
+ # Convert to special edge data.
+ edgeLoops = []
+ for vloop in vertLoops:
+ edgeLoops.append(edgeLoop(vloop))
- # Add the new vert loop to the list
- allVLoops.append( findVertLoop(mesh, fIgLs) )
- return allVLoops[:-1] # Remove the last Value- None.
+ # VERT LOOP ORDERING CODE
+ # Build a worm list - grow from Both ends
+ edgeOrderedList = [edgeLoops.pop()]
+ # Find the closest.
+ 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
+
+ edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) )
-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:
- newDist = measure( allVertLoopLocs[vLoopIdx], allVertLoopLocs[currentVLoop] )
- 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
+ # Now we have the 2 closest, append to either end-
+ # Find the closest.
+ while edgeLoops:
+ 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
+
+ if l1 < bestSoFar:
+ bestIdxSoFar = edLoopIdx
+ bestSoFar = l1
+ first_or_last = 1 # last
+
+ l2 =(edgeOrderedList[0].centre - edLoop.centre).length
+ if l2 < bestSoFar:
+ bestIdxSoFar = edLoopIdx
+ bestSoFar = l2
+ first_or_last = 0 # last
+
+ if first_or_last: # add closest Last
+ edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) )
+ else: # Add closest First
+ edgeOrderedList.insert(0, edgeLoops.pop(bestIdxSoFar) ) # First
- return newOrderVLoops, vLoopIdxNotToSkin
-
-
-is_editmode = Window.EditMode()
-if is_editmode: Window.EditMode(0)
-
-# 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()
-if mesh != None:
- Window.WaitCursor(1)
- allVLoops = getAllVertLoops(mesh)
-
- # Re order the vert loops
- allVLoops, vLoopIdxNotToSkin = reorderCircularVLoops(mesh, allVLoops)
-
- vloopIdx = 0
- 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
- toSkin2 = vloopIdx + 1
- if toSkin2 == len(allVLoops):
- toSkin2 = 0
-
- # Circular loft or not?
- if arg[0] == 'B': # B for open
- if vloopIdx != vLoopIdxNotToSkin:
- mesh = skinVertLoops(mesh, allVLoops[vloopIdx], allVLoops[toSkin2])
- elif arg[0] == 'A': # A for closed
- mesh = skinVertLoops(mesh, allVLoops[vloopIdx], allVLoops[toSkin2])
-
- vloopIdx +=1
-
- mesh.update(1,(mesh.edges != []),0)
+ for i in range(len(edgeOrderedList)-1):
+ skin2EdgeLoops(edgeOrderedList[i], edgeOrderedList[i+1], me, ob, 0)
+ 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)
-if is_editmode: Window.EditMode(1)
-Window.WaitCursor(0)
-print "skinning time: %.2f" % (sys.time() - time1)
+main()
diff --git a/release/scripts/tex2uvbaker.py b/release/scripts/tex2uvbaker.py
index 0d0f4dfe065..b4a9d9bc188 100644
--- a/release/scripts/tex2uvbaker.py
+++ b/release/scripts/tex2uvbaker.py
@@ -2,7 +2,7 @@
""" Registration info for Blender menus:
Name: 'Texture Baker'
-Blender: 237
+Blender: 236
Group: 'UV'
Tooltip: 'Procedural to uvmapped texture baker'
"""
@@ -11,10 +11,11 @@ __author__ = "Jean-Michel Soler (jms)"
__url__ = ("blender", "elysiun",
"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")
-__version__ = "0.2.8 2005/7/20"
+__version__ = "0.3.0 2005/10/09"
__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
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:
-a) Enter face mode and define uv coordinates for your mesh (do not forget to choose a development shape);<br>
-b) Define its materials and textures;<br>
+a) Enter face mode and define uv coordinates for your mesh;<br>
+b) Define its materials and textures ;
c) Run this script and check the console.
-Global variables:
+Global variables
-a) FRAME (integer): the last frame of the animation, autodocumented.<br>
-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.
+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 .
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'
@@ -47,6 +49,14 @@ Notes:<br>
#
# 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
# -- added the forgotten image property in face
# data. a little longer but better.
@@ -201,6 +211,8 @@ DEBUG=1
RENDERLAYER=20
SCENELAYERS=[]
+
+
helpmsg = """
Texture Baker:
@@ -250,6 +262,7 @@ def RenameImage(RDIR, MYDIR, FILENAME, name):
"""
newfname = RDIR + MYDIR + name
if newfname.find('.png', -4) < 0 : newfname += '.png'
+
if not Blender.sys.exists(newfname):
os.rename(FILENAME, newfname)
else:
@@ -290,13 +303,13 @@ def SAVE_image (rc, name, FRAME, result):
rc.startFrame(NEWFRAME)
rc.endFrame(NEWFRAME)
rc.renderAnim()
- if result!=2 and not KEEPRENDERWINDOW:
+ if result!=2 :
Blender.Scene.Render.CloseRenderWindow()
FILENAME = "%04d" % NEWFRAME
FILENAME = FILENAME.replace (' ', '0')
FILENAME = RDIR + MYDIR + FILENAME + '.png'
RenameImage(RDIR, MYDIR, FILENAME, name)
-
+
rc.endFrame(OLDEFRAME)
rc.startFrame(OLDSFRAME)
rc.setRenderPath(RENDERDIR)
@@ -346,14 +359,24 @@ def SHOOT (XYlimit, frame, obj, name, FRAME, result):
OLDy = context.imageSizeY()
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
elif (tres) == 2: res = 512
elif (tres) == 3: res = 768
elif (tres) == 4: res = 1024
elif (tres) == 5: res = 2048
+ # elif (tres) == 6: res = 4096
else: res = 512
+ #...
+
SCENELAYERS=SC.layers
SC.layers = [20]
@@ -419,7 +442,7 @@ def Mesh2UVCoord (LIMIT):
"""
global PUTRAW, FRAME, SCENELAYERS
- try:
+ try :
MESH3D = Object.GetSelected()[0]
if MESH3D.getType() == 'Mesh':
MESH = MESH3D.getData()
@@ -444,7 +467,7 @@ def Mesh2UVCoord (LIMIT):
v1.co[2] = 0.0
MESH2.verts.append(v1)
f1.v.append(MESH2.verts[len(MESH2.verts) - 1])
-
+
MESH2.faces.append(f1)
f1.uv = f.uv[:]
f1.col = f.col[:]
@@ -464,6 +487,7 @@ def Mesh2UVCoord (LIMIT):
NewOBJECT.setLocation (OBJPOS, OBJPOS, 0.0)
NewOBJECT.setEuler (0.0, 0.0, 0.0)
+
MESH2.removeAllKeys()
MESH2.update()
MESH2.insertKey (1, 'absolute')
@@ -471,7 +495,7 @@ def Mesh2UVCoord (LIMIT):
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)
if result == 1:
@@ -501,18 +525,17 @@ def Mesh2UVCoord (LIMIT):
Blender.Redraw()
else:
- Blender.ShowHelp('tex2uvbaker.py')
- #Draw.PupMenu("Ready%t|Please check console for instructions")
- if DEBUG: print helpmsg
+ Draw.PupMenu("Ready%t|Please check console for instructions")
+ print helpmsg
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)
print 'problem : no object selected or not mesh'
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)
print 'problem : no object selected or not mesh'
-Mesh2UVCoord(LIMIT)
+Mesh2UVCoord(LIMIT)
diff --git a/release/scripts/UVpaint05.py b/release/scripts/uvpaint.py
index 5217d942109..357c2d94aed 100644
--- a/release/scripts/UVpaint05.py
+++ b/release/scripts/uvpaint.py
@@ -11,7 +11,7 @@ __author__ = "Jean-Michel Soler (jms)"
__url__ = ("blender", "elysiun",
"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")
-__version__ = "0.5 05/2004"
+__version__ = "0.8 08/2005"
__bpydoc__ = """\
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
is saved as vertex colors for the model;<br>
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$
@@ -99,54 +122,136 @@ def exist(path):
return 0
return 1
-loc0= Blender.sys.dirname(Blender.Get ("filename"))
-loc2=loc0+Blender.sys.dirsep+'test00.tga'
+loc0= Blender.Get ("filename").replace('\\','/')
+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
glCl3=glColor3f
glCl4=glColor4f
glRct=glRectf
+LC=1.0
+
xlimit=0
selmatlist=[]
+LIM=[0.0,0.0,0.0,0.0]
+NOLIM=1
+if not NOLIM : LIM=[-1.0,1.0,-1.0,1.0]
+
+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 triangle(a,b,c):
+def Ttriangle(a,b,c):
glBegin(GL_TRIANGLES);
- glColor3f(a[2],a[3],a[4])
- glVertex2f(a[0],a[1]);
- glColor3f(b[2],b[3],b[4])
- glVertex2f(b[0],b[1]);
- glColor3f(c[2],c[3],c[4])
- glVertex2f(c[0],c[1]);
- glEnd();
-
-def Ltriangle(a,b,c):
- glBegin(GL_LINES);
- glColor3f(1.0,1.0,1.0)
+ 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 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)
+def Ftriangle(a,b,c):
+ glBegin(GL_TRIANGLES);
+ glColor3f(a[2],a[3],a[4])
glVertex2f(a[0],a[1]);
+ glColor3f(b[2],b[3],b[4])
glVertex2f(b[0],b[1]);
+ glColor3f(c[2],c[3],c[4])
glVertex2f(c[0],c[1]);
- glVertex2f(d[0],d[1]);
glEnd();
+def Ltriangle(a,b,c,LC=0.5):
+ TL=[a,b,c,a]
+ for v in [0,1,2] :
+ 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 Tcarre(a,b,c,d,LC=1.0):
+ Ttriangle(a,b,c)
+ Ttriangle(a,c,d)
+
+def Fcarre(a,b,c,d,LC=1.0):
+ 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):
- global xlimit
+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]
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]
if len(f.v)>=3:
- a[0]=int(f.uv[0][0]*x)
- a[1]=int(f.uv[0][1]*y)
+ a[0]=int((f.uv[0][0]-LIM[1])*x+u)
+ a[1]=int((f.uv[0][1]-LIM[3])*y+v)
if a[0]>xlimit:
xlimit=a[0]
@@ -164,8 +269,8 @@ def transface(f,x,y):
a[3]=f.col[0].g/255.0
a[4]=f.col[0].b/255.0
- c[0]=int(f.uv[2][0]*x)
- c[1]=int(f.uv[2][1]*y)
+ c[0]=int((f.uv[2][0]-LIM[1])*x+u)
+ c[1]=int((f.uv[2][1]-LIM[3])*y+v)
if c[0]>xlimit:
xlimit=c[0]
@@ -175,8 +280,8 @@ def transface(f,x,y):
c[4]=f.col[2].b/255.0
- b[0]=int(f.uv[1][0]*x)
- b[1]=int(f.uv[1][1]*y)
+ b[0]=int((f.uv[1][0]-LIM[1])*x+u)
+ b[1]=int((f.uv[1][1]-LIM[3])*y+v)
if b[0]>xlimit:
xlimit=b[0]
@@ -187,8 +292,8 @@ def transface(f,x,y):
if len(f.v)==4:
- d[0]=int(f.uv[3][0]*x)
- d[1]=int(f.uv[3][1]*y)
+ d[0]=int((f.uv[3][0]-LIM[1])*x+u)
+ d[1]=int((f.uv[3][1]-LIM[3])*y+v)
if d[0]>xlimit:
xlimit=d[0]
@@ -214,44 +319,53 @@ def extract_faces(me,MENU):
return listf
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':
- me=GetRaw(ME.getData().name)
-
+ me=ME.getData()
if MMENU.val==1:
se=me.faces
-
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:
- 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
for f in se:
a,b,c,d=transface(f,x,y)
- if len(f.v)==4:
- triangle(a,b,c)
- triangle(a,c,d)
- elif len(f.v)==3:
- triangle(a,b,c)
+ if not EMPTY and not TRANSP:
+ if len(f.v)==4:
+ Ftriangle(a,b,c)
+ Ftriangle(a,c,d)
+ elif len(f.v)==3:
+ 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:
a,b,c,d=transface(f,x,y)
if len(f.v)==4:
- Lcarre(a,b,c,d)
+ Lcarre(a,b,c,d,LC)
elif len(f.v)==3:
- Ltriangle(a,b,c)
-
+ Ltriangle(a,b,c,LC)
if XLIMIT.val==0:
Lcarre([1,1],[1,y-2],[xlimit+2,y-2],[xlimit+2,1])
else:
Lcarre([1,1],[1,y-2],[xwin-2,y-2],[xwin-2,1])
-
-
-
+
def write_tgafile(loc2,bitmap,width,height,profondeur):
f=open(loc2,'wb')
@@ -286,10 +400,13 @@ def write_tgafile(loc2,bitmap,width,height,profondeur):
def save(x0,y0,dx,dy):
+ global SAVE
im = Buffer(GL_BYTE,[dx*(dy+1),4])
glReadPixels(x0,y0,dx,dy,GL_RGBA, GL_BYTE,im);
print len(im), dx*dy, dx, dy, len(im)/dy
write_tgafile(loc2,im,dx,dy+1,4)
+ SAVE=0
+ Blender.Redraw()
def DOCMat_list(TMATList,ME):
me=Blender.NMesh.GetRaw(ME.getData().name)
@@ -342,9 +459,13 @@ TEXT=Create(loc2)
# uvpaint4
# ----------
TMENU="MODE MENU %t|All %x1|Material %x2|Selected %x3"
+# ----------
+# uvpaint4
+# ----------
+# coming soon : "|vertex group %x4", perhaps in uvpainter v0.5
+LCOLOR= Create(64)
+SAVE=0
-# coming soon : "|Bone %x4", perhaps in uvpainter v0.5
-
MMENU=Create(3)
TDOCMat = Create(0)
# ----------
@@ -370,13 +491,14 @@ n0=32
def draw():
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)
glGetFloatv(GL_SCISSOR_BOX, size)
- size= size.list
-
- for s in [0,1,2,3]: size[s]=int(size[s])
+ size=[int(s) for s in size ]
n0=32
x0=size[0]
@@ -390,78 +512,138 @@ def draw():
glClear(GL_COLOR_BUFFER_BIT)
-
glShadeModel(GL_SMOOTH)
- SelecMESH=Blender.Object.GetSelected()
- if SelecMESH!=[]:
- if SelecMESH[0].getType()=='Mesh':
- affiche_mesh(SelecMESH[0],int(y*NSIZE.val),int(y*NSIZE.val-n0-2))
-
- glColor3f(0.0,0.0,0.0)
- glRectf(4,size[3],555,size[3]-32 )
-
- glColor3f(1.0,1.0,1.0)
-
- glRasterPos2f(8, size[3]-13)
- Text("uvpainter v0.5")
-
- glRasterPos2f(8, size[3]-28)
- Text("Jm Soler, 05/2004")
-
- Button("ReDraw" ,16 ,290-118+61 ,size[3]-30 ,60 ,13)
- Button("Exit" ,1 ,250-122+63 ,size[3]-30 ,38 ,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.")
- LINE=Toggle("line", 5 ,250-122+63 ,size[3]-15 , 38, 13, LINE.val, "Draw lines")
+ #transparence
+ if TRANSP :
+ glEnable(GL_BLEND)
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
- glRasterPos2f(250-130 ,size[3]-13,)
- Text("Mode")
-
- MMENU= Menu(TMENU ,2 ,250-130, size[3]-30, 63, 13, MMENU.val, "MODE menu.")
-
- if MMENU.val==1 or MMENU.val==3:
- glRasterPos2f( 250-16+61+42+80,size[3]-13)
- if XLIMIT.val:
- xl=xwin
- else:
- xl=xlimit
-
- Text("x :"+"%d"%(xl+2))
-
- glRasterPos2f(250-16+61+42+65*2,size[3]-13)
- Text("y :"+"%d"%(y-n0+1))
-
- TEXT=String("to:", 7 , 278+61 ,size[3]-28 , 213, 13, TEXT.val, 256, "Draw lines")
- if XLIMIT.val==1:
- limit='winlimit'
- else:
- limit='maxXlimit'
- XLIMIT=Toggle(limit, 9 , 250-16+61+42 ,size[3]-15 , 60, 13, XLIMIT.val, "to save picture from x max uv limit, or x window max limit")
-
- if MMENU.val==2:
- TDOCMat=Toggle("doc" ,24,250-130+35 ,size[3]-13 , 28, 13, TDOCMat.val)
- if TDOCMat.val==1:
- SELMat_list()
- for t in range(TMATList[0]):
- glCl3(TMATList[1][t][0],
- TMATList[1][t][1],
- TMATList[1][t][2])
- glRct((293-16+61)+t*20,
- size[3]-13,
- (293-16+61)+t*20+20,
- 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)
-
-
+ SelecMESH=Blender.Object.GetSelected()
+ if SelecMESH!=[] and SelecMESH[0].getType()=='Mesh':
+ affiche_mesh(SelecMESH[0],int(y*NSIZE.val),int(y*NSIZE.val-2))
-def event(evt, val):
- if (evt== QKEY and not val): Exit()
+ if MENU:
+ glColor3f(0.0,0.0,0.0)
+ glRectf(4,size[3],555,size[3]-32 )
+ glColor3f(1.0,1.0,1.0)
+
+ glRasterPos2f(8, size[3]-13)
+ Text("uvpainter v0.8")
+
+ glRasterPos2f(8, size[3]-28)
+ Text("Jm Soler, 08/2005")
+
+ Button("ReDraw" ,16 ,290-118+61 ,size[3]-30 ,60 ,13)
+ Button("Exit" ,1 ,250-122+63 ,size[3]-30 ,38 ,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,5.0,0,"SIZE.")
+ LINE=Toggle("line", 5 ,250-122+63 ,size[3]-15 , 38, 13, LINE.val, "Draw lines")
+
+ glRasterPos2f(250-130 ,size[3]-13,)
+ 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.")
+
+ if MMENU.val==1 or MMENU.val==3:
+ glRasterPos2f( 250-16+61+42+80,size[3]-13)
+ if XLIMIT.val:
+ xl=xwin
+ else:
+ xl=xlimit
+
+ Text("x :"+"%d"%(xl+2))
+
+ glRasterPos2f(250-16+61+42+65*2,size[3]-13)
+ Text("y :"+"%d"%(y-n0+1))
+
+ TEXT=String("to:", 7 , 278+61 ,size[3]-28 , 213, 13, TEXT.val, 256, "Draw lines")
+ if XLIMIT.val==1:
+ limit='winlimit'
+ else:
+ limit='maxXlimit'
+ XLIMIT=Toggle(limit, 9 , 250-16+61+42 ,size[3]-15 , 60, 13, XLIMIT.val, "to save picture from x max uv limit, or x window max limit")
+
+ if MMENU.val==2:
+ TDOCMat=Toggle("doc" ,24,250-130+35 ,size[3]-13 , 28, 13, TDOCMat.val)
+ if TDOCMat.val==1:
+ SELMat_list()
+ for t in range(TMATList[0]):
+ glCl3(TMATList[1][t][0],
+ TMATList[1][t][1],
+ TMATList[1][t][2])
+ glRct((293-16+61)+t*20,
+ size[3]-13,
+ (293-16+61)+t*20+20,
+ 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)
+
+ #else:
+ # save()
+
+ if DOCU:
+ Doc(size)
+
+def event(evt, val):
+ 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):
global LINE,NSIZE,n0,x0,y0,y,TEXT, loc2
global TMATList, selmatlist, TDOCMat,XLIMIT
- global xlimit
+ global xlimit,LCOLOR,LC,SAVE
if (evt== 1):
Exit()
@@ -474,11 +656,11 @@ def bevent(evt):
elif (evt== 6):
if XLIMIT.val==1:
- xi=xwin
+ xi=xwin
+ save(x0,y0,xi+2,int(y-n0))
else:
- xi=xlimit
-
- save(x0,y0,xi+2,int(y*NSIZE.val-n0))
+ xi=xlimit
+ save(x0,y0,xi+2,int(y*NSIZE.val)-n0)
elif (evt== 7):
if exist(TEXT.val):
@@ -487,7 +669,10 @@ def bevent(evt):
TEXT.val=loc2
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()
diff --git a/release/scripts/wings_export.py b/release/scripts/wings_export.py
index 424ee2513d4..c262f3faabd 100644
--- a/release/scripts/wings_export.py
+++ b/release/scripts/wings_export.py
@@ -322,28 +322,6 @@ def write(filename):
Blender.Draw.PupMenu("Wings Export error|Unable to generate Edge Table for mesh")
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)
dsize = len(data)
Blender.Window.DrawProgressBar(0.98, "Compressing Data")