Main.py :  » Game-2D-3D » Prim.Blender » prim.blender » Lib » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Game 2D 3D » Prim.Blender 
Prim.Blender » prim.blender » Lib » Main.py
#=========================================================================
'''

This script defines the core behaviors of this program.



If you find this to be useful, please visit us and donate 
at the following SLURL:
http://slurl.com/secondlife/Great%20Pubnico/23/71/93/

Importers for this tool may also be found there.

If you find this tool to be useful, PLEASE DONATE at the
location listed above. Or at the very least, tell me that
you find my work useful so I may continue improving it. :)


To run this script, right-click this window and select
"Execute Script" or press Alt-P.



Some functionality has been imported from Domino import 
Marama's sculpty scripts for Blender. His URL is:
http://www.dominodesigns.info/

And his import and export tools are available at:
http://www.dominodesigns.info/downloads/second_life/import_sculptie_svn.zip

Many default sculpty maps provided with this tool were 
created by camilla Yosuke. These maps are released under
a tentative BSD license by their author.


Functions, descriptions, and subroutines can be found 
by using the handy Table of Contents below.

Good luck! =)


NOTE: This software is licensed under GPL2.
You should have received a copy of the license with
this script. If not, it may be obtained here:
http://www.gnu.org/licenses/gpl.html

A quick definition may be found on Wikipedia here:
http://en.wikipedia.org/wiki/GPL

For alternate licensing terms, please contact me:
Mercen4ry (at) gmail (dot) com

'''
#=========================================================================

'''

Table of Contents:
Use "Find" for each section, outline symbol included. (I., B., iii., etc.)


I. Initialization

        A. Imports
        B. Initialization Routines


II. Constants

        A. Internal Constants
        B. Boolean Calls
        C. Prim Type Constants
        D. Other Descriptive Primitive Params
        E. Hole Shape Constants
        F. Bumpmapping Constants
        G. Shininess Constants
        H. Material Constants
        I. Trig Constants
        J. Vectors and Rotations
        K. Event Handlers
        L. Sculpt Types
        M. Other Constants


III. Variables

        A. Position
        B. Rotation
        C. Scale
        D. Deformations
        E. Base Properties
        F. Other Properties


IV. Classes

        A. Class Primitive
        B. Class PrimRegistry

                i.   __init__
                ii.  add
                iii. get
                iv.  getParams
                v.   remove
                vi.  removeGhosts
                vii. setParams
                viii.sync

        C. Default Prim Registry
        D. Sculpt Classes by Domino Marama

                i.   [Class] pixel

                        1. __init__
                        2. __cmp__
                        3. __sub__
                        4. __add__
                        5. __mul__
                        6. __repr__

                ii.  [Class] scaleRange

                        1. __init__
                        2. normalise
                        3. normaliseVert
                        4. denormalise

        E. Custom Classes


V. Functions

        A. llCopyPrims
        B. llDialog
        C. llDrawConsole
        D. llDrawConsoleBEvent
        E. llDrawConsoleEvent
        F. llDrawConsoleGUI
        G. llDrawEnd
        H. llDrawPrimMesh

                i.   cutBoxen
                ii.  cutCircle
                iii. cutHalfHex
                iv.  cutTri

        I. llExtrudeVerts
        J. llGetPrimitiveParams
        K. llLatheVerts

                i.   rotateVerts
                ii.  scaleVerts
                iii. translateVerts
                iv.  twistVerts

        L. llLoadPrims
        M. llMirrorPrim
        N. llNewPrim

                i.   internalKey

        O. llParams2Buffer
        P. llParamSelected2Prim
        Q. llRedrawPrim (Deprecated)
        R. llSavePrims
        S. llSculptMesh
        T. llSetPrimitiveParams
        U. Sculpt Functions by Domino Marama

                i.   Compatibility for previous versions of Python
                ii.  update_sculpty_from_map
                iii. default_sculpty
                iv.  new_sculpty
                v.   generate_base_mesh
                vi.  load_sculpty
                vii. load_sculpty_from_callback
                viii.drawTri
                ix.  drawHLine
                x.   drawVLine
                xi.  expandPixels
                xii. getFirstX
                xiii.getFirstY
                xiv. fillX
                xv.  fillY
                xvi. updateSculptyMap

        V. Custom functions


VI. Post-data

        A. Default Post-data
        B. Post-initialization Routines

'''

#=========================================================================











#=========================================================================
'''

I. Initialization:

This section defines core commands prior to execution.

'''
#=========================================================================


# A. Imports
import Blender                          # Import Blender module
from Blender.NMesh import *# Import NMesh (GetRaw; PutRaw support)
fromBlender.Draw*# Import Draw (for our GUI)
fromBlender.Window*# Import Window (ditto)
fromBlender.BGL*# Import BGL (direct OpenGL drawing; GUI)
fromBlender.Image*# Import Image (GUI too!)
fromBlender.Object*# Import Object (Object manipulation stuffs)
fromBlender.Mathutils*# Import Math stuffs (Quaternion, etc)x
fromBlender.sysexpandpath# Import expandpath (for image path)
fromBlender.systime# Import time (for timer used in script)
math# Import more math stuffs (sine, cosine, etc)
frommath*# Link math out to regular calls
string# Imports string functions for Python 2.3 and earlier
fromsysversion_info# Import Python version information
try:
        import md5                      # Import MD5 hashing (image culling)
except:
        PupMenu("MD5 import failed. Please install a full version of Python 2.5 or Bad Things may happen.") 
import os                               # Import OS-specific functionality (ie. os.path.join)
import random                           # Imports random number generation


# B. Initialization Routines
# Place custom code here
print "hippos!"


#=========================================================================











#=========================================================================
'''

II. Constants:

These constants are in line with the existing ones in LSL, for convenience
If this concept works, I will extend it to LSL-syntax functions similar to
llSetRot, llSetPos, etc.

I'm pulling these expressly off the LSL Wiki.

[Old] Links:
http://secondlife.com/badgeo/wakka.php?wakka=constants
http://secondlife.com/badgeo/wakka.php?wakka=llSetPrimitiveParams

And just for fun, SCITE should happily pick these up when checking for
syntax. Nerds rejoice!

'''
#=========================================================================


# A. Internal Constants
REFRESH_TIME            = 2.0                                   # Draw refresh interval (Lowered to 2 seconds)
                                                                # @Bug: Due to the way Blender handles events, this
                                                                # will occasionally reset certain changes in the GUI
#PATH                    = expandpath("//")                     # Image path (widgets are now stored internally)
IMAGE                   = Blender.Image.Get("button_panel.png")       
                                                                # Image file for interface
SCULPTY_IMAGE           = Blender.Image.Get("default.tga")       
                                                                # Image file for default sculpt map
VERSION                 = 2                                     # Format version; currently 2
SMOOTH_ANGLE            = 0                                     # If non-zero, sets smoothing for curved faces
#PREF_MAPS               = {}                                   # Dictionary of prefmaps loaded from PrefMaps folder


# B. Boolean Calls
TRUE                    = 1
FALSE                   = 0


# C. Prim Type Constants
PRIM_TYPE_BOX           = 0
PRIM_TYPE_CYLINDER      = 1
PRIM_TYPE_PRISM         = 2
PRIM_TYPE_SPHERE        = 3
PRIM_TYPE_TORUS         = 4
PRIM_TYPE_TUBE          = 5
PRIM_TYPE_RING          = 6
PRIM_TYPE_SCULPT        = 7


# D. Other Descriptive Primitive Params
PRIM_MATERIAL           = 2
PRIM_PHYSICS            = 3
PRIM_TEMP_ON_REZ        = 4
PRIM_PHANTOM            = 5
PRIM_POSITION           = 6
PRIM_SIZE               = 7
PRIM_ROTATION           = 8
PRIM_TYPE               = 9
PRIM_TEXTURE            = 17
PRIM_COLOR              = 18
PRIM_BUMP_SHINY         = 19
PRIM_FULLBRIGHT         = 20
PRIM_FLEXIBLE           = 21
PRIM_TEXGEN             = 22
PRIM_POINT_LIGHT        = 23


# E. Hole Shape Constants
PRIM_HOLE_DEFAULT       = 0
PRIM_HOLE_SQUARE        = 1
PRIM_HOLE_CIRCLE        = 2
PRIM_HOLE_TRIANGLE      = 3


# F. Bumpmapping Constants
PRIM_BUMP_NONE          = 0
PRIM_BUMP_BRIGHT        = 1
PRIM_BUMP_DARK          = 2
PRIM_BUMP_WOOD          = 3
PRIM_BUMP_BARK          = 4
PRIM_BUMP_BRICKS        = 5
PRIM_BUMP_CHECKER       = 6
PRIM_BUMP_CONCRETE      = 7
PRIM_BUMP_TILE          = 8
PRIM_BUMP_STONE         = 9
PRIM_BUMP_DISKS         = 10
PRIM_BUMP_GRAVEL        = 11
PRIM_BUMP_BLOBS         = 12
PRIM_BUMP_SIDING        = 13
PRIM_BUMP_LARGETILE     = 14
PRIM_BUMP_STUCCO        = 15
PRIM_BUMP_SUCTION       = 16
PRIM_BUMP_WEAVE         = 17


# G. Shininess Constants
PRIM_SHINY_NONE         = 0
PRIM_SHINY_LOW          = 1
PRIM_SHINY_MEDIUM       = 2
PRIM_SHINY_HIGH         = 3


# H. Material Constants
PRIM_MATERIAL_STONE     = 0
PRIM_MATERIAL_METAL     = 1
PRIM_MATERIAL_GLASS     = 2
PRIM_MATERIAL_WOOD      = 3
PRIM_MATERIAL_FLESH     = 4
PRIM_MATERIAL_PLASTIC   = 5
PRIM_MATERIAL_RUBBER    = 6
PRIM_MATERIAL_LIGHT     = 7


# I. Trig Constants (rough equivalent since we're too lazy to use Python Pi, et al)
PI                      = 3.1415926535897932
TWO_PI                  = 6.2831853071795864
PI_BY_TWO               = 1.5707963267948966
DEG_TO_RAD              = 0.0174532925199432
RAD_TO_DEG              = 57.295779513082323
SQRT2                   = 1.4142135623730950


# J. Vectors and Rotations
ZERO_VECTOR             = (0.0,0.0,0.0)
ZERO_ROTATION           = (0.0,0.0,0.0,0.0)


# K. Event Handlers (Now a bitfield for OR multiplexing of events)
EVENT_NOEVENT           = 0x0000
EVENT_UPDATEVARS        = 0x0001
EVENT_DRAW              = 0x0002
EVENT_REDRAW            = 0x0004
EVENT_EXIT              = 0x0008
EVENT_TYPE              = 0x0010
EVENT_SAVE              = 0x0020
EVENT_LOAD              = 0x0040
EVENT_MIRROR_X          = 0x0080
EVENT_MIRROR_Y          = 0x0100
EVENT_MIRROR_Z          = 0x0200
EVENT_COPY              = 0x0400
EVENT_BAKE_SCULPTY      = 0x0800
EVENT_RESET_SCULPTY     = 0x1000
EVENT_LOAD_SCULPTY      = 0x2000


# L. Sculpt Types
PRIM_SCULPT_TYPE_SPHERE         = 1
PRIM_SCULPT_TYPE_TORUS          = 2
PRIM_SCULPT_TYPE_PLANE          = 3
PRIM_SCULPT_TYPE_CYLINDER       = 4


# M. Other Constants
# Constants imported for compatibility with Domino's library
# (A few of these are dupes, but are kept for paranoid compatibility)
SPHERE                  = 1
TORUS                   = 2
PLANE                   = 3
CYLINDER                = 4
FACES_X                 = 8
FACES_Y                 = 8


# These really serve no purpose, and are added for sake of completeness
NULL_KEY                = "00000000-0000-0000-0000-000000000000"
EOF                     = "/n/n/n"
AGENT                   = 1
ACTIVE                  = 2
PASSIVE                 = 4
SCRIPTED                = 8

#=========================================================================











#=========================================================================
'''

III. Variables:

These variables describe various primitive params, list data, object data,
etc. These are used in the normal operation of this program for holding 
data, which is pretty much what the name implies.

Some of the names will conform to the standards set forth here:
http://secondlife.com/badgeo/wakka.php?wakka=llSetPrimitiveParams

'''
#=========================================================================


# A. Position
posx            = Create(0.0)
posy            = Create(0.0)
posz            = Create(0.0)


# B. Rotation
rotx            = Create(0.0)
roty            = Create(90.0)
rotz            = Create(0.0)


# C. Scale
sizex           = Create(0.5)
sizey           = Create(0.5)
sizez           = Create(0.5)


# D. Deformations
cutx            = Create(0.0)
cuty            = Create(1.0)
dimplex         = Create(0.0)
dimpley         = Create(1.0)
advancedcutx    = Create(0.0)
advancedcuty    = Create(1.0)
hollow          = Create(0)
twistx          = Create(0)
twisty          = Create(0)
topsizex        = Create(0.0)
topsizey        = Create(0.0)
holesizex       = Create(1.0)
holesizey       = Create(0.5)
topshearx       = Create(0.0)
topsheary       = Create(0.0)
taperx          = Create(0.0)
tapery          = Create(0.0)
revolutions     = Create(1.0)
radiusoffset    = Create(0.0)
skew            = Create(0.0)
sculpttype      = Create(1)
sculptimage     = Create("")
sculptfacesx    = Create(8)
sculptfacesy    = Create(8)
sculptmultires  = Create(2)
#repeats        = Create(1.0)
#offsets        = Create(0.0)


# E. Base Properties
primType        = Create(0)
material        = Create(3)
mirrorframe     = Create(0)
hollowshape     = Create(0)
physics         = Create(0)
temponrez       = Create(0)
phantom         = Create(0)
levelofdetail   = Create(3)     # NOTE: Changed back to 3
name            = Create("")


# F. Other Properties
lastevt         = 0             # Gets last event
lasttime        = time()        # Gets current time() value
lastmouse       = [0,0]         # Gets last mouse position when clicked


#=========================================================================











#=========================================================================
'''

IV. Classes:

This section defines classes for primitive objects. These classes are used
by this script to store data in each individual primitive for later
retrieval.

'''
#=========================================================================


# A. Class Primitive
class Primitive:

        # This class specifies a primitive and all its attributes

        UUID            = "Num_-1"
        name            = "Object"
        description     = ""
        levelofdetail   = 3
        type            = 0
        position        = (0.0,0.0,0.0)
        rotation        = (0.0,0.0,0.0)
        size            = (0.5,0.5,0.5)
        cut             = (0.0,1.0,0.0)
        dimple          = (0.0,1.0,0.0)
        advancedcut     = (0.0,1.0,0.0)
        hollow          = 0
        twist           = (0.0,0.0,0.0)
        topsize         = (1.0,1.0,0.0)
        holesize        = (1.0,0.5,0.0)
        topshear        = (0.0,0.0,0.0)
        taper           = (0.0,0.0,0.0)
        revolutions     = 1.0
        radiusoffset    = 0.0
        skew            = 0.0
        material        = 3
        hollowshape     = 0
        physics         = 0
        temponrez       = 0
        phantom         = 0
        sculpttype      = 1
        sculptimage     = ""
        sculpthash      = ""
        sculptfaces     = (8,8,2)
        sculptmirror    = False
        hooks           = ()





# B. Class PrimRegistry
class PrimRegistry:

        # The prim registry is a wrapper for retrieving prims, as well
        # as useful function data, like UUID, name, etc.


        # i.   __init__
        # Initialization
        def __init__(me):
                oldprims = Blender.Registry.GetKey("Prim.Blender Prims Registry",False)

                # @Fix: Because the Blender Registry persists in Blender between unrelated sessions,
                #       and NOT when saving and loading, this behavior has been deprecated in favor
                #       of using the mesh propery method in the next block.

                if True: #else:
                        print "Using Object Data to recover prim registry"
                        me.primList = []
                        me.primDict = {}

                        # Get the current scene
                        scene = Blender.Scene.GetCurrent()

                        # Load any primitives that have attributes set
                        for i in scene.objects:
                                try:
                                        i.getProperty('PRIM.BLENDER: UUID')
                                except:
                                        print i.name,' does not appear to be a prim...'
                                        continue

                                # Set up the prim data
                                id = Primitive()

                                # Irritatingly, we get to do a whoooole lot of this manually (!)
                                id.UUID            = i.getProperty('PRIM.BLENDER: UUID').getData()
                                id.name            = i.getProperty('PRIM.BLENDER: name').getData() 
                                id.description     = i.getProperty('PRIM.BLENDER: description').getData() 
                                id.levelofdetail   = i.getProperty('PRIM.BLENDER: levelofdetail').getData() 
                                id.type            = i.getProperty('PRIM.BLENDER: type').getData() 
                                id.position        = (i.getProperty('PRIM.BLENDER: position.x').getData() 
                                                      ,i.getProperty('PRIM.BLENDER: position.y').getData() 
                                                      ,i.getProperty('PRIM.BLENDER: position.z').getData())
                                id.rotation        = (i.getProperty('PRIM.BLENDER: rotation.x').getData() 
                                                      ,i.getProperty('PRIM.BLENDER: rotation.y').getData() 
                                                      ,i.getProperty('PRIM.BLENDER: rotation.z').getData()) 
                                id.size            = (i.getProperty('PRIM.BLENDER: size.x').getData() 
                                                      ,i.getProperty('PRIM.BLENDER: size.y').getData() 
                                                      ,i.getProperty('PRIM.BLENDER: size.z').getData())
                                id.cut             = (i.getProperty('PRIM.BLENDER: cut.x').getData()
                                                      ,i.getProperty('PRIM.BLENDER: cut.y').getData()
                                                      ,0.0)
                                id.dimple          = (i.getProperty('PRIM.BLENDER: dimple.x').getData()
                                                      ,i.getProperty('PRIM.BLENDER: dimple.y').getData()
                                                      ,0.0)
                                id.advancedcut     = (i.getProperty('PRIM.BLENDER: advancedcut.x').getData()
                                                      ,i.getProperty('PRIM.BLENDER: advancedcut.y').getData()
                                                      ,0.0)
                                id.hollow          = i.getProperty('PRIM.BLENDER: hollow').getData()
                                id.twist           = (i.getProperty('PRIM.BLENDER: twist.x').getData()
                                                      ,i.getProperty('PRIM.BLENDER: twist.y').getData()
                                                      ,0.0)
                                id.topsize         = (i.getProperty('PRIM.BLENDER: topsize.x').getData()
                                                      ,i.getProperty('PRIM.BLENDER: topsize.y').getData()
                                                      ,0.0)
                                id.holesize        = (i.getProperty('PRIM.BLENDER: holesize.x').getData()
                                                      ,i.getProperty('PRIM.BLENDER: holesize.y').getData()
                                                      ,0.0)
                                id.topshear        = (i.getProperty('PRIM.BLENDER: topshear.x').getData()
                                                      ,i.getProperty('PRIM.BLENDER: topshear.y').getData()
                                                      ,0.0)
                                id.taper           = (i.getProperty('PRIM.BLENDER: taper.x').getData()
                                                      ,i.getProperty('PRIM.BLENDER: taper.y').getData()
                                                      ,0.0)
                                id.revolutions     = i.getProperty('PRIM.BLENDER: revolutions').getData()
                                id.radiusoffset    = i.getProperty('PRIM.BLENDER: radiusoffset').getData()
                                id.skew            = i.getProperty('PRIM.BLENDER: skew').getData()
                                id.material        = i.getProperty('PRIM.BLENDER: material').getData()
                                id.hollowshape     = i.getProperty('PRIM.BLENDER: hollowshape').getData()
                                id.physics         = i.getProperty('PRIM.BLENDER: physics').getData()
                                id.temponrez       = i.getProperty('PRIM.BLENDER: temponrez').getData()
                                id.phantom         = i.getProperty('PRIM.BLENDER: phantom').getData()
                                id.sculpttype      = i.getProperty('PRIM.BLENDER: sculpttype').getData()
                                id.sculptimage     = i.getProperty('PRIM.BLENDER: sculptimage').getData()
                                id.sculpthash      = i.getProperty('PRIM.BLENDER: sculpthash').getData()
                                id.sculptfaces     = (i.getProperty('PRIM.BLENDER: sculptfaces.x').getData()
                                                      ,i.getProperty('PRIM.BLENDER: sculptfaces.y').getData()
                                                      ,i.getProperty('PRIM.BLENDER: sculptfaces.z').getData())
                                #id.hooks           = i.getProperty('PRIM.BLENDER: hooks').getData()
                                
                                # Test if the prim and object match
                                if ("Prim_" + id.UUID) == i.name:
                                        # Prim in current scene. Load it.
                                        print "Prim Properties: Loaded UUID:",id.UUID
                                        me.add(id)
                                else:
                                        # Delete this (broken?) primitive from the registry
                                        del(id)
                        

                        Blender.Registry.SetKey("Prim.Blender Prims Registry",{'primList':me.primList,'primDict':me.primDict},False)


        # ii.  add
        # Adds a prim to the list
        def add(me,id):
                me.primList.append(id)

                # Recalculate prim dictionary
                me.primDict = {}
                for i in range(0,len(me.primList)):
                        del id
                        id = me.primList[i]
                        me.primDict[id.UUID] = i
                        

        # iii. get
        # Gets primitive from registry by UUID
        def get(me,UUID):
                id = Primitive()
                id.UUID = "-1" # Sentinel value for not found
                for i in range(0, len(me.primList)):
                        compare = me.primList[i]
                        if compare.UUID == UUID:
                                id = compare
                return id # Returns a prim


        # iv.  getParams
        # Get params via llGetPrimitiveParams; timesaver.
        def getParams(me,UUID,params):
                id = me.get(UUID)
                if id.UUID != "-1":
                        return llGetPrimitiveParams(id,params) # Returns a list...
                else:
                        return [] # ... or empty set if not found.


        # v.   remove
        # Removes a prim from the list, if existing
        def remove(me,UUID):
                id = Primitive()
                id.UUID = "-1" # Sentinel value for not found
                for i in range(0, len(me.primList)):
                        compare = me.primList[i]
                        if compare.UUID == UUID:
                                id = compare
                if id.UUID != "-1":
                        me.primList.remove(id)
                        del me.primDict[id.UUID]

                        # Garbage collection again. If it existed...
                        #del id

                        # Recalculate prim dictionary
                        me.primDict = {}
                        for i in range(0,len(me.primList)):
                                del id
                                id = me.primList[i]
                                me.primDict[id.UUID] = i
                else:
                        print "Warning: This prim is NOT in your current registry!"
                        return


        # vi.  removeGhosts
        # Removes ghosts, if any, that have been deleted
        def removeGhosts(me):
                tempPrimList = []
                tempPrimDict = {}
                scene = Blender.Scene.GetCurrent()
                allObjs = scene.objects
                index = 0
                print me.primDict

                # Uncomment for garbage collection, which Blender
                # Does not currently appear to support...
                #trash = []


                lenAllObjs = len(allObjs)
                for i in range(0,lenAllObjs):
                        objname = allObjs[i].getName()
                        if objname.find('Prim_') != -1:
                                objname = allObjs[i].getData(1)
                                print objname
                                if me.primDict.has_key(objname):
                                        tempPrimList.append(me.primList[me.primDict[objname]])
                                        tempPrimDict[objname] = index
                                        index += 1

                        #elif not me.primDict.has_key(objname):
                                #trash.append(allObjs[i])

                #while len(trash) > 0:
                #  del trash[0]

                me.primList = tempPrimList
                me.primDict = tempPrimDict
                print me.primDict


        # vii. setParams
        # Invokes llSetPrimitiveParams; timesaver.
        def setParams(me,UUID,params):
                id = me.get(UUID)
                if id.UUID != "-1":
                        llSetPrimitiveParams(id,params)


        # viii.sync
        # Syncs primitives to BlenderSpace values
        # Also prepares data for saving as a .blend file
        def sync(me):

                # @Fix: Sync all images (PackAll still has b-b-b-bugs)
                for image in Blender.Image.Get():
                        #print "Packing image file:",image.name
                        image.fakeUser = True # @Fix: Need fakeUser for UI image packing
                        image.pack()
                
                      
                # @Fix: Transitioned from Blender.Object.Get() to scene.objects due to bugs with the former call
                scene = Blender.Scene.GetCurrent()
                for i in scene.objects:
                        if i.getType() == "Mesh":
                                if string.find(i.name,"Prim_") == -1:
                                        continue
                                key = string.replace(i.name,"Prim_","")
                                id = me.get(key)

                                # Sync primitive params to object data for saving as a .blend file
                                # This is A LOT of manual processing. 
                                # We do this to avoid using some otherwise dirty hacks
                                # (He says as he throws the whole thing into a try-catch conditional)
                                #print 'Syncing mesh data for: ',key
                                try:
                                        i.getProperty('PRIM.BLENDER: UUID').setData(id.UUID)
                                        i.getProperty('PRIM.BLENDER: name').setData(id.name) 
                                        i.getProperty('PRIM.BLENDER: description').setData(id.description) 
                                        i.getProperty('PRIM.BLENDER: levelofdetail').setData(id.levelofdetail) 
                                        i.getProperty('PRIM.BLENDER: type').setData(id.type) 
                                        i.getProperty('PRIM.BLENDER: position.x').setData(id.position[0]) 
                                        i.getProperty('PRIM.BLENDER: position.y').setData(id.position[1]) 
                                        i.getProperty('PRIM.BLENDER: position.z').setData(id.position[2]) 
                                        i.getProperty('PRIM.BLENDER: rotation.x').setData(id.rotation[0])
                                        i.getProperty('PRIM.BLENDER: rotation.y').setData(id.rotation[1]) 
                                        i.getProperty('PRIM.BLENDER: rotation.z').setData(id.rotation[2]) 
                                        i.getProperty('PRIM.BLENDER: size.x').setData(id.size[0]) 
                                        i.getProperty('PRIM.BLENDER: size.y').setData(id.size[1]) 
                                        i.getProperty('PRIM.BLENDER: size.z').setData(id.size[2]) 
                                        i.getProperty('PRIM.BLENDER: cut.x').setData(id.cut[0])
                                        i.getProperty('PRIM.BLENDER: cut.y').setData(id.cut[1])
                                        i.getProperty('PRIM.BLENDER: dimple.x').setData(id.dimple[0])
                                        i.getProperty('PRIM.BLENDER: dimple.y').setData(id.dimple[1])
                                        i.getProperty('PRIM.BLENDER: advancedcut.x').setData(id.advancedcut[0])
                                        i.getProperty('PRIM.BLENDER: advancedcut.y').setData(id.advancedcut[1])
                                        i.getProperty('PRIM.BLENDER: hollow').setData(id.hollow)
                                        i.getProperty('PRIM.BLENDER: twist.x').setData(id.twist[0])
                                        i.getProperty('PRIM.BLENDER: twist.y').setData(id.twist[1])
                                        i.getProperty('PRIM.BLENDER: topsize.x').setData(id.topsize[0])
                                        i.getProperty('PRIM.BLENDER: topsize.y').setData(id.topsize[1])
                                        i.getProperty('PRIM.BLENDER: holesize.x').setData(id.holesize[0])
                                        i.getProperty('PRIM.BLENDER: holesize.y').setData(id.holesize[1])
                                        i.getProperty('PRIM.BLENDER: topshear.x').setData(id.topshear[0])
                                        i.getProperty('PRIM.BLENDER: topshear.y').setData(id.topshear[1])
                                        i.getProperty('PRIM.BLENDER: taper.x').setData(id.taper[0])
                                        i.getProperty('PRIM.BLENDER: taper.y').setData(id.taper[1])
                                        i.getProperty('PRIM.BLENDER: revolutions').setData(id.revolutions)
                                        i.getProperty('PRIM.BLENDER: radiusoffset').setData(id.radiusoffset)
                                        i.getProperty('PRIM.BLENDER: skew').setData(id.skew)
                                        i.getProperty('PRIM.BLENDER: material').setData(id.material)
                                        i.getProperty('PRIM.BLENDER: hollowshape').setData(id.hollowshape)
                                        i.getProperty('PRIM.BLENDER: physics').setData(id.physics)
                                        i.getProperty('PRIM.BLENDER: temponrez').setData(id.temponrez)
                                        i.getProperty('PRIM.BLENDER: phantom').setData(id.phantom)
                                        i.getProperty('PRIM.BLENDER: sculpttype').setData(id.sculpttype)
                                        i.getProperty('PRIM.BLENDER: sculptimage').setData(id.sculptimage)
                                        i.getProperty('PRIM.BLENDER: sculpthash').setData(id.sculpthash)
                                        i.getProperty('PRIM.BLENDER: sculptfaces.x').setData(id.sculptfaces[0])
                                        i.getProperty('PRIM.BLENDER: sculptfaces.y').setData(id.sculptfaces[1])
                                        i.getProperty('PRIM.BLENDER: sculptfaces.z').setData(id.sculptfaces[2])
                                        #i.getProperty('PRIM.BLENDER: hooks').setData(??)
                                except:
                                        i.addProperty('PRIM.BLENDER: UUID',id.UUID,'STRING')
                                        i.addProperty('PRIM.BLENDER: name',id.name,'STRING') 
                                        i.addProperty('PRIM.BLENDER: description',id.description,'STRING') 
                                        i.addProperty('PRIM.BLENDER: levelofdetail',id.levelofdetail,'INT') 
                                        i.addProperty('PRIM.BLENDER: type',id.type,'INT') 
                                        i.addProperty('PRIM.BLENDER: position.x',id.position[0],'FLOAT') 
                                        i.addProperty('PRIM.BLENDER: position.y',id.position[1],'FLOAT') 
                                        i.addProperty('PRIM.BLENDER: position.z',id.position[2],'FLOAT') 
                                        i.addProperty('PRIM.BLENDER: rotation.x',id.rotation[0],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: rotation.y',id.rotation[1],'FLOAT') 
                                        i.addProperty('PRIM.BLENDER: rotation.z',id.rotation[2],'FLOAT') 
                                        i.addProperty('PRIM.BLENDER: size.x',id.size[0],'FLOAT') 
                                        i.addProperty('PRIM.BLENDER: size.y',id.size[1],'FLOAT') 
                                        i.addProperty('PRIM.BLENDER: size.z',id.size[2],'FLOAT') 
                                        i.addProperty('PRIM.BLENDER: cut.x',id.cut[0],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: cut.y',id.cut[1],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: dimple.x',id.dimple[0],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: dimple.y',id.dimple[1],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: advancedcut.x',id.advancedcut[0],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: advancedcut.y',id.advancedcut[1],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: hollow',id.hollow,'INT')
                                        i.addProperty('PRIM.BLENDER: twist.x',id.twist[0],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: twist.y',id.twist[1],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: topsize.x',id.topsize[0],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: topsize.y',id.topsize[1],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: holesize.x',id.holesize[0],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: holesize.y',id.holesize[1],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: topshear.x',id.topshear[0],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: topshear.y',id.topshear[1],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: taper.x',id.taper[0],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: taper.y',id.taper[1],'FLOAT')
                                        i.addProperty('PRIM.BLENDER: revolutions',id.revolutions,'FLOAT')
                                        i.addProperty('PRIM.BLENDER: radiusoffset',id.radiusoffset,'FLOAT')
                                        i.addProperty('PRIM.BLENDER: skew',id.skew,'FLOAT')
                                        i.addProperty('PRIM.BLENDER: material',id.material,'INT')
                                        i.addProperty('PRIM.BLENDER: hollowshape',id.hollowshape,'INT')
                                        i.addProperty('PRIM.BLENDER: physics',id.physics,'INT')
                                        i.addProperty('PRIM.BLENDER: temponrez',id.temponrez,'INT')
                                        i.addProperty('PRIM.BLENDER: phantom',id.phantom,'INT')
                                        i.addProperty('PRIM.BLENDER: sculpttype',id.sculpttype,'INT')
                                        i.addProperty('PRIM.BLENDER: sculptimage',id.sculptimage,'STRING')
                                        i.addProperty('PRIM.BLENDER: sculpthash',id.sculpthash,'STRING')
                                        i.addProperty('PRIM.BLENDER: sculptfaces.x',id.sculptfaces[0],'INT')
                                        i.addProperty('PRIM.BLENDER: sculptfaces.y',id.sculptfaces[1],'INT')
                                        i.addProperty('PRIM.BLENDER: sculptfaces.z',id.sculptfaces[2],'INT')
                                        #i.addProperty('PRIM.BLENDER: hooks',??,'??')

                                
                                id.position = i.getLocation()
                                temp = i.getEuler()
                                x = temp[0] * 180.0 / PI
                                y = temp[1] * 180.0 / PI
                                z = temp[2] * 180.0 / PI
                                del temp

                                # Format the variable so we're in-bounds...
                                while x < 0.0:
                                        x += 360.0
                                while x >= 360.0:
                                        x -= 360.0

                                while y < 0.0:
                                        y += 360.0
                                while y >= 360.0:
                                        y -= 360.0

                                while z < 0.0:
                                        z += 360.0
                                while z >= 360.0:
                                        z -= 360.0
                                id.rotation = (x,y,z)

                                temp = i.getSize()
                                x = 0.0
                                y = 0.0
                                z = 0.0

                                # Blender size is used for Sculpt Meshes ONLY (should be one unit otherwise;
                                # we do this to preserve the mesh between scaling)
                                if id.type != 7:
                                        x = abs(id.size[0] * temp[0])
                                        y = abs(id.size[1] * temp[1])
                                        z = abs(id.size[2] * temp[2])
                                        i.setSize(1.0,1.0,1.0)
                                else:
                                        # Because scaling is only accessible on one or three axes in Blender,
                                        # we make a check to see if uniform or axis scaling went into the negative
                                        # This is automatically corrected for when exporting, despite our warnings.

                                        x = abs(temp[0])
                                        y = abs(temp[1])
                                        z = abs(temp[2])
                                        i.setSize(x,y,z)

                                        if (temp[0] * temp[1] * temp[2] < 0):
                                                pass


                                if x > 10.0:
                                        x = 10.0
                                elif x < 0.01:
                                        x = 0.01

                                if y > 10.0:
                                        y = 10.0
                                elif y < 0.01:
                                        y = 0.01

                                if z > 10.0:
                                        z = 10.0
                                elif z < 0.01:
                                        z = 0.01

                                id.size = (x,y,z)





# C. Default Prim Registry
PrimHolder = PrimRegistry()
# Unfortunately, I had to hardcode this registry.
# Blame Blender and its required "callback" feature =/





# D. Sculpt Classes by Domino Marama
# These classes were originally written by Domino Marama as stand alones for Blender's toolchain.
# These have been preserved for the most part; the calls through them have been modified to suit
# the Prim.Blender UI, as well as copying and mirroring.


# i.   [Class] pixel
# Represents a single pixel on a sculpted prim's image map, including defines for math functionality
class pixel:

        # 1. __init__
        def __init__(self, x, y, r, g, b):
                self.x = x
                self.y = y
                self.r = r
                self.g = g
                self.b = b

        # 2. __cmp__
        def __cmp__(self, other):
                if self.x == other.x:
                        return cmp(self.y, other.y)
                else:
                        return cmp(self.x, other.x)

        # 3. __sub__
        def __sub__(self, other):
                return pixel(
                        self.x - other.x,
                        self.y - other.y,
                        self.r - other.r,
                        self.g - other.g,
                        self.b - other.b
                )

        # 4. __add__
        def __add__(self, other):
                return pixel(
                        self.x + other.x,
                        self.y + other.y,
                        self.r + other.r,
                        self.g + other.g,
                        self.b + other.b
                )

        # 5. __mul__
        def __mul__(self, scalar):
                return pixel(
                        self.x * scalar,
                        self.y * scalar,
                        self.r * scalar,
                        self.g * scalar,
                        self.b * scalar,
                )

        # 6. __repr__
        def __repr__(self):
                return "pixel(" + str(self.x) + ", " +\
                        str(self.y) + ", " +\
                        str(self.r) + ", " +\
                        str(self.g) + ", " +\
                        str(self.b) + ")"


# ii.  [Class] scaleRange
# Gets the minimum and maximum range of sculpted prims, and allows for normalization and fill functionality
class scaleRange:

        # 1. __init__
        def __init__ ( self, objects, normalise = False ):
                self.minx = None
                for ob in objects:
                        if ob.type == 'Mesh':
                                mesh = Blender.Mesh.New()
                                mesh.getFromObject( ob, 0, 1 )

                                # @Fix: This was a poor implementation; we should offset from the center of the *object*,
                                #       not the center of the vert sequence! Because of this, we must base our bounding 
                                #       box math a bit differently.
                
                                # Start by getting the location of the object in 3D space:
                                if self.minx == None:
                                        self.minx = mesh.verts[0].co.x
                                        self.maxx = self.minx
                                        self.miny = mesh.verts[0].co.y
                                        self.maxy = self.miny
                                        self.minz = mesh.verts[0].co.z
                                        self.maxz = self.minz
                                for v in mesh.verts[1:-1]:
                                        if v.co.x < self.minx :
                                                self.minx = v.co.x
                                        elif v.co.x > self.maxx :
                                                self.maxx = v.co.x
                                        if v.co.y < self.miny :
                                                self.miny = v.co.y
                                        elif v.co.y > self.maxy :
                                                self.maxy = v.co.y
                                        if v.co.z < self.minz :
                                                self.minz = v.co.z
                                        elif v.co.z > self.maxz :
                                                self.maxz = v.co.z

                                # Now, compare max and min to the center of the object. We use the points that are
                                # the MOST distant from the center to compute our bounding box

                                # We also convert these values to a cube, to allow for proper object scaling
                                self.dev = max(abs(self.minx),abs(self.maxx)
                                              ,abs(self.miny),abs(self.maxy)
                                              ,abs(self.minz),abs(self.maxz))

                                self.minx = self.miny = self.minz = -1.0 * self.dev
                                self.maxx = self.maxy = self.maxz = self.dev

                        self.x = abs(self.maxx - self.minx)
                        self.y = abs(self.maxy - self.miny)
                        self.z = abs(self.maxz - self.minz)

                        # avoid divide by zero errors
                        if self.x == 0.0: self.x = 1.0
                        if self.y == 0.0: self.y = 1.0
                        if self.z == 0.0: self.z = 1.0


        # 2. normalise
        # Returns normalised color values at R,G,B
        def normalise( self, co ):
                return 1.0 - ((self.maxx - co[0]) / self.x), 1.0 - ((self.maxy - co[1]) / self.y), 1.0 - ((self.maxz - co[2]) / self.z)


        # 3. normaliseVert
        # Returns normalised vert values for properly normalising a sculpt mesh
        def normaliseVert( self, vert ):
                return vert[0] / self.x, vert[1] / self.y, vert[2] / self.z


        # 4. denormalise
        # Returns the inverse of the normalisation factor
        # This is used to recalculate the size of the target prim after the image is normalised
        def denormalise( self ):
                return self.x, self.y, self.z







# E. Custom Classes
# Add any custom class definitions here.


#=========================================================================











#=========================================================================
'''

Functions:

This section defines functions and behaviors that are called throughout
this and other scripts.

Most functions will contain an "ll" prefix version to emulate functions 
found within Second Life. This prefix is not required to call any of these
functions, and is added more as a mnemonic device than an actual need.

Note that NOT using the "ll" prefix may double the slack memory used for
parameters. This is usually negligible.

'''
#=========================================================================


# A. llCopyPrims
def CopyPrims(primlist):
        llCopyPrims(primlist)
def llCopyPrims(primlist):

        # Unset edit mode (required for mesh edits by script)
        editmode = 0
        if Blender.Window.EditMode():
                editmode = 1
        Blender.Window.EditMode(0)

        # Average the location of all of the prims in the set; 
        # this will be used to reconstitute the object after we finish
        x,y,z = 0.0,0.0,0.0
        for prim in primlist:
                x += prim.position[0]
                y += prim.position[1]
                z += prim.position[2]

        x,y,z = x / float(len(primlist)),y / float(len(primlist)),z / float(len(primlist))

        newobjs = []
        for prim in primlist:

                # Commented properties are deliberately not used
                newprim = llNewPrim(0, PrimHolder)
                newprim.name = prim.name
                newprim.description = prim.description
                #newprim.position = prim.position
                newprim.rotation = prim.rotation
                newprim.size = prim.size
                newprim.cut = prim.cut
                newprim.dimple = prim.dimple
                newprim.advancedcut = prim.advancedcut
                newprim.hollow = prim.hollow
                newprim.twist = prim.twist
                newprim.topsize = prim.topsize
                newprim.holesize = prim.holesize
                newprim.topshear = prim.topshear
                newprim.taper = prim.taper
                newprim.revolutions = prim.revolutions
                newprim.radiusoffset = prim.radiusoffset
                newprim.skew = prim.skew
                newprim.type = prim.type
                newprim.material = prim.material
                newprim.hollowshape = prim.hollowshape
                newprim.physics = prim.physics
                newprim.temponrez = prim.temponrez
                newprim.phantom = prim.phantom
                newprim.levelofdetail = prim.levelofdetail
                newprim.sculpttype = prim.sculpttype
                #newprim.sculptimage = prim.sculptimage
                newprim.sculptfaces = prim.sculptfaces
                newprim.sculptmirror = prim.sculptmirror

                # Unselect all objects and select the current one
                scene = Blender.Scene.GetCurrent()
                for obj in scene.objects:
                        obj.select(0)

                obj = Blender.Object.Get("Prim_" + newprim.UUID)
                if obj:
                        # Append to the list of new objects to select after this operation completes
                        newobjs.append(obj)


                        # The position component requires special handling

                        # We get the location of the new prim (== cursor location),
                        # plus original distance, minus the average.
                        # This gives us a new set of prims in their relative locations,
                        # centered on the cursor
                        newprim.position = obj.getLocation()
                        newprim.position = (newprim.position[0] + prim.position[0] - x
                                            ,newprim.position[1] + prim.position[1] - y
                                            ,newprim.position[2] + prim.position[2] - z)

                        # Select this mesh and draw its basic params
                        obj.select(1)
                        llDrawPrimMesh(newprim)

                        # Also update position
                        obj.setLocation(newprim.position[0], newprim.position[1], newprim.position[2])

                        # And update rotation
                        obj.setEuler([newprim.rotation[0] * PI / 180.0, newprim.rotation[1] * PI / 180.0, newprim.rotation[2] * PI / 180.0])
                        # Update multires level (safe operation for mesh data)
                        if newprim.type == 7:

                                # Copy mesh data
                                Blender.NMesh.PutRaw(Blender.NMesh.GetRaw(prim.UUID),newprim.UUID)
                                mesh = Blender.Mesh.Get(newprim.UUID)

                                # Update the mesh from its copy
                                obj.link(mesh)

                                # Make SURE we have multires data for this mesh
                                if mesh and mesh.multires:
                                        mesh.multiresDrawLevel = newprim.levelofdetail

                                # Set the correct mesh scaling
                                obj.setSize(newprim.size[0],newprim.size[1],newprim.size[2])
                else:
                        llDialog("Warning: Could not find object associated with this mesh.")

                llParams2Buffer(newprim)
        
        # @Consistency: Select each new prim after copy is complete
        for obj in newobjs:
                obj.select(1)

        # Reset edit mode if it was present
        if editmode:
                Blender.Window.EditMode(1)



# B. llDialog
def Dialog(message):
        llDialog(message)
def llDialog(message):
        '''
        This function prints a popup dialog with message 
        and list of options given.

        This reminds me of llDialog, so I'm using that name here!
        '''
        PupMenu("Script Dialog %t|" + message) 





# C. llDrawConsole
def DrawConsole(id):
        llDrawConsole(id)
def llDrawConsole(id):
        '''
        This function redraws the console every time a new primitive is invoked.

        If no primitive is present, we draw the create menu only and any
        placeholders we wish to add to point the user in the right direction.
        '''
        Register(llDrawConsoleGUI,llDrawConsoleEvent,llDrawConsoleBEvent)





# D. llDrawConsoleBEvent
def DrawConsoleBEvent(evt):
        llDrawConsoleBEvent(evt)
def llDrawConsoleBEvent(evt):

        '''
        This one is used for actual events, most notably button inputs
        This registers when a slider is moved, a button has been pressed,
        or any other event has been called.
        '''

        # Set up globals
        global EVENT_NOEVENT, EVENT_UPDATEVARS, EVENT_DRAW, EVENT_TYPE, EVENT_EXIT, EVENT_SAVE, EVENT_LOAD, EVENT_MIRROR_X, EVENT_MIRROR_Y, EVENT_MIRROR_Z, EVENT_COPY, EVENT_BAKE_SCULPTY, EVENT_RESET_SCULPTY

        # Manage GUI Events
        test = Primitive()
        selected = Blender.Object.GetSelected()
        if len(selected) > 0 and selected[0].getType() == "Mesh":
                key = selected[0].getData(1)
                test = PrimHolder.get(key)

        if string.find(selected[0].name,"Prim_") == -1:
                return

        # Exit out of the program. Unlike previous versions, this will not hose all current prims.
        if evt & EVENT_EXIT:
                check = PupMenu("Really quit?%t|Yes%x1|No%x2")
                if check == 1:

                        # Sync all primitive data
                        PrimHolder.sync()

                        # Update scene registry
                        Blender.Registry.SetKey("Prim.Blender Prims Registry",{'primList':PrimHolder.primList,'primDict':PrimHolder.primDict},False)
                        
                        # Quit out
                        Exit()

        # Change this prim's type (requires a console redraw; deprecated)
        #if evt & EVENT_TYPE:
        #        Exit()  # Required in some versions to redraw the GUI
        #        test.type = primType.val
        #        llDrawConsole(0)

        # Mirror on the X-axis
        if evt & EVENT_MIRROR_X:
                for i in range(0,len(selected)):
                        if selected[i].getType() == "Mesh":
                                key = selected[i].getData(1)
                                test = PrimHolder.get(key)
                                llMirrorPrim(test,0,selected[i])

        # Mirror on the Y-axis
        if evt & EVENT_MIRROR_Y:
                for i in range(0,len(selected)):
                        if selected[i].getType() == "Mesh":
                                key = selected[i].getData(1)
                                test = PrimHolder.get(key)
                                llMirrorPrim(test,1,selected[i])

        # Mirror on the Z-axis
        if evt & EVENT_MIRROR_Z:
                for i in range(0,len(selected)):
                        if selected[i].getType() == "Mesh":
                                key = selected[i].getData(1)
                                test = PrimHolder.get(key)
                                llMirrorPrim(test,2,selected[i])

        # Save .prims file
        if evt & EVENT_SAVE:
                FileSelector(llSavePrims, 'Save Prims','save.prims')

        # Load .prims file
        if evt & EVENT_LOAD:
                FileSelector(llLoadPrims, 'Load Prims','load.prims')

        # Copy a prim
        if evt & EVENT_COPY:
                primlist = []
                for i in range(0,len(selected)):
                        if selected[i].getType() == "Mesh":
                                key = selected[i].getData(1)
                                test = PrimHolder.get(key)
                                primlist.append(test)
                llCopyPrims(primlist)

        # Bake a sculpty texture
        if evt & EVENT_BAKE_SCULPTY:

                # If this is a sculpted prim, bake the sculpt image
                doFill = False
                doNorm = False
                time1 = Blender.sys.time()  #for timing purposes
                ob = Blender.Object.Get("Prim_" + test.UUID)
                meshscale = scaleRange( [ob], doNorm )
                if meshscale.minx == None:
                        Blender.Draw.PupBlock( "Sculptie Bake Error", ["No objects to bake"] )

                updateSculptyMap( ob, test, None, meshscale, doFill )

                print 'finished baking: in %.4f sec.' % ((Blender.sys.time()-time1))
                sculptimage.val = test.sculptimage

        # Load a sculpty texture
        if evt & EVENT_LOAD_SCULPTY:
                FileSelector(load_sculpty_from_callback,'Load Sculpty Texture','load.tga')

                # Redraw GUI after loading the new map
                '''
                llParamSelected2Prim(PrimHolder)
                selected = Blender.Object.GetSelected()
                if len(selected) > 0 and selected[0].getType() == "Mesh":
                        llParams2Buffer(PrimHolder.get(selected[0].getData(1)))
                llDrawConsoleGUI()
                '''

        # Update this prim's state variables
        if evt & EVENT_UPDATEVARS:
                if test.UUID == "Num_-1" or test.UUID == "-1":
                        print "GUI Silent Fail: Attempting to draw with nothing selected!"
                else:
                        check = 0
                        rescalePrimFromSculpt = 0 # Used only when converting from sculpted back to a normal prim
                        test.name = name.val
                        test.physics = physics.val
                        test.temponrez = temponrez.val
                        test.phantom = phantom.val
                        if test.type == 7 and primType.val != test.type:
                                check = PupMenu("Changing from a sculpted to a regular prim will ERASE THIS PRIM'S SCULPT DATA. Really change to a different prim?%t|Yes%x1|No%x2")
                                if check != 1:
                                        primType.val = 7
                                        return # Exit before a redraw, to prevent nuking the sculpt shape
                                else:
                                        rescalePrimFromSculpt = 1
                        test.type = primType.val
                        test.material = material.val
                        # Paranoia, to prevent two possible edge cases
                        if test.type == 7 and levelofdetail.val > 3:
                                levelofdetail.val = 3
                        elif levelofdetail.val < 1:
                                levelofdetail.val = 1
                        test.levelofdetail = levelofdetail.val
                        test.position = (posx.val,posy.val,posz.val)
                        test.size = (sizex.val,sizey.val,sizez.val)
                        test.rotation = (rotx.val,roty.val,rotz.val)
                        test.cut = (cutx.val,cuty.val,0.0)
                        test.advancedcut = (advancedcutx.val,advancedcuty.val,0.0)
                        test.hollow = hollow.val
                        test.hollowshape = hollowshape.val
                        test.twist = (twistx.val,twisty.val,0.0)
                        test.dimple = (dimplex.val,dimpley.val,0.0)
                        # Alter values since the "real value" is a bit different than the display version
                        test.topsize = ((-1.0 * topsizex.val) + 1.0,(-1.0 * topsizey.val) + 1.0,0.0)
                        test.topshear = (topshearx.val,topsheary.val,0.0)
                        test.taper = (taperx.val,tapery.val,0.0)
                        test.radiusoffset = radiusoffset.val
                        test.revolutions = revolutions.val
                        test.skew = skew.val
                        if sculpttype.val != test.sculpttype or evt & EVENT_RESET_SCULPTY:
                                check = PupMenu("This action will ERASE THIS PRIM'S SCULPT DATA. Continue?%t|Yes%x1|No%x2")
                                if check != 1:
                                        holesizex.val = test.holesize[0]
                                        holesizey.val = test.holesize[1]
                                        sculpttype.val = test.sculpttype
                                        sculptfacesx.val = test.sculptfaces[0]
                                        sculptfacesy.val = test.sculptfaces[1]
                                        sculptmultires.val = test.sculptfaces[2]

                                        return # Exit before a redraw, to prevent nuking the sculpt shape

                        if test.type == 7:
                                # If we're raising the sculpt multires level and already okayed this, 
                                # up the level of detail to the new maximum
                                if test.sculptfaces[2] != sculptmultires.val:
                                        test.levelofdetail = sculptmultires.val

                                # Set the sculpt faces (Z = depth of multires)
                                test.sculptfaces = (sculptfacesx.val,sculptfacesy.val,sculptmultires.val)

                                # ASSERT: For sculpties, level of detail must be <= multiresDrawLevel
                                if test.levelofdetail > test.sculptfaces[2]:
                                        test.levelofdetail = test.sculptfaces[2] + 1


                                # If "Reset Mesh" is given for sculpttype, alter the value to the "correct" one
                                if sculpttype.val == 5:
                                        sculpttype.val = test.sculpttype

                        test.holesize = (holesizex.val,holesizey.val,0.0)
                        test.sculpttype = sculpttype.val # Parity is only altered if the dialog is okayed above.
                        selected = Blender.Object.GetSelected()
                        if len(selected) > 0 and selected[0].getType() == "Mesh":
                                selected[0].setLocation(test.position[0],test.position[1],test.position[2])
                                selected[0].setEuler([test.rotation[0] * PI / 180.0,test.rotation[1] * PI / 180.0, test.rotation[2] * PI / 180.0])
                                # Update multires level (safe operation for mesh data)
                                if test.type == 7:

                                        # Get the mesh from the object
                                        if test.UUID == "-1" or test.UUID == "Num_-1":
                                                print "Silent fail; Mesh data not loaded."
                                                return
                                        mesh = Blender.Mesh.Get(test.UUID)

                                        # Make sure mesh data is linked (annoying that we must do this every time)
                                        obj = Blender.Object.Get("Prim_" + test.UUID)
                                        if obj:
                                                obj.link(mesh)

                                                # ASSERT: Disable multires if value == 0
                                                if test.sculptfaces[2] == 0:
                                                        mesh.multires = False

                                                # Make SURE we have multires data for this mesh
                                                if mesh and mesh.multires:
                                                        mesh.multiresDrawLevel = test.levelofdetail

                                                # Set the correct mesh scaling
                                                obj.setSize(test.size[0],test.size[1],test.size[2])
                                        else:
                                                llDialog("Warning: Could not find object associated with this mesh.")
                                elif rescalePrimFromSculpt:
                                        # Get the mesh from the object
                                        if test.UUID == "-1" or test.UUID == "Num_-1":
                                                print "Silent fail; Mesh data not loaded."
                                                return
                                        obj = Blender.Object.Get("Prim_" + test.UUID)
                                        if obj:
                                                # Prevents the editor from rescaling a normal prim
                                                obj.setSize(1.0,1.0,1.0) 
                                #Blender.Redraw()

        # Draw changes to this object's mesh
        if evt & EVENT_DRAW:

                        # Sync all primitive data
                        PrimHolder.sync()

                        # Draw the mesh
                        llDrawPrimMesh(test)
        
        # Update scene registry
        Blender.Registry.SetKey("Prim.Blender Prims Registry",{'primList':PrimHolder.primList,'primDict':PrimHolder.primDict},False)





# E. llDrawConsoleEvent
def DrawConsoleEvent(evt,val):
        llDrawConsoleEvent(evt,val)
def llDrawConsoleEvent(evt, val):

        '''
        This function is used to register events, like keyboard inputs
        We use this for our nifty loops to redraw the GUI, too!
        '''

        global lastevt, lastmouse, lasttime
        size = GetAreaSize()
        height = size[1] + 25
        mouse = GetMouseCoords()
        litmus = abs(lastmouse[0] - mouse[0]) + abs(lastmouse[1] - mouse[1])
        currtime = time()

        if(evt == QKEY and not val):
                check = PupMenu("Really quit?%t|Yes%x1|No%x2")
                if check == 1:
                        Exit()
        elif(evt == LEFTMOUSE and not val):
                if (lastevt == LEFTMOUSE and litmus < 30):
                        # Check if we're selecting a primitive or special option that 
                        # isn't a button...
                        if mouse[0] > 17 and mouse[1] < height - 12 and mouse[0] < 58 and mouse[1] > height - 53:
                                llNewPrim(0,PrimHolder)
                        elif mouse[0] > 58 and mouse[1] < height - 12 and mouse[0] < 99 and mouse[1] > height - 53:
                                llNewPrim(1,PrimHolder)
                        elif mouse[0] > 99 and mouse[1] < height - 12 and mouse[0] < 140 and mouse[1] > height - 53:
                                llNewPrim(2,PrimHolder)
                        elif mouse[0] > 140 and mouse[1] < height - 12 and mouse[0] < 181 and mouse[1] > height - 53:
                                llNewPrim(3,PrimHolder)
                        elif mouse[0] > 181 and mouse[1] < height - 12 and mouse[0] < 222 and mouse[1] > height - 53:
                                llNewPrim(4,PrimHolder)
                        elif mouse[0] > 222 and mouse[1] < height - 12 and mouse[0] < 263 and mouse[1] > height - 53:
                                llNewPrim(5,PrimHolder)
                        elif mouse[0] > 263 and mouse[1] < height - 12 and mouse[0] < 304 and mouse[1] > height - 53:
                                llNewPrim(6,PrimHolder)
                        elif mouse[0] > 37 and mouse[1] < height - 57 and mouse[0] < 78 and mouse[1] > height - 98:
                                llNewPrim(7,PrimHolder)
                        elif mouse[0] > 78 and mouse[1] < height - 57 and mouse[0] < 119 and mouse[1] > height - 98:
                                llNewPrim(8,PrimHolder)
                        elif mouse[0] > 119 and mouse[1] < height - 57 and mouse[0] < 160 and mouse[1] > height - 98:
                                llNewPrim(9,PrimHolder)
                        elif mouse[0] > 160 and mouse[1] < height - 57 and mouse[0] < 201 and mouse[1] > height - 98:
                                llNewPrim(10,PrimHolder)
                        elif mouse[0] > 201 and mouse[1] < height - 57 and mouse[0] < 242 and mouse[1] > height - 98:
                                llNewPrim(11,PrimHolder)
                        elif mouse[0] > 242 and mouse[1] < height - 57 and mouse[0] < 283 and mouse[1] > height - 98:
                                llNewPrim(12,PrimHolder)
                lastmouse = mouse
                lasttime = currtime
        elif evt and (evt > 5 or (evt > 3 and currtime - lasttime > REFRESH_TIME)):
                print evt
                llParamSelected2Prim(PrimHolder)
                selected = Blender.Object.GetSelected()
                if len(selected) > 0 and selected[0].getType() == "Mesh":
                        llParams2Buffer(PrimHolder.get(selected[0].getData(1)))
                llDrawConsole(0)

                # @fix: Sync all primitive data periodically, to prevent any Ctrl-Z mishaps
                PrimHolder.sync()

                lasttime = currtime
        lastevt = evt





# F. llDrawConsoleGUI 
def DrawConsoleGUI():
        llDrawConsoleGUI()
def llDrawConsoleGUI():

        '''
        This function is a wrapper class called by Blender events
        Its name has been preserved just in case!
        '''

        # Position (truncated)
        global posx, posy, posz

        # Rotation
        global rotx, roty, rotz

        # Scale
        global sizex, sizey, sizez

        # Deformations
        global cutx, cuty, dimplex, dimpley, advancedcutx, advancedcuty
        global hollow, twistx, twisty, topsizex, topsizey, holesizex, holesizey 
        global topshearx, topsheary, taperx, tapery, revolutions, radiusoffset 
        global skew, primType, levelofdetail, name, mirrorframe, sculpttype 
        global sculptimage, sculptfacesx, sculptfacesy, sculptmultires


        # Base Properties
        global material, hollowshape, physics, temponrez, phantom

        # Get Area for Draw Operation
        size = GetAreaSize()
        height = size[1]

        # Clear the window
        glClear(GL_COLOR_BUFFER_BIT)
        glColor3ui(0,0,0)

        # Draw Prim Helper Image

        for i in range(0,5):
                Image(IMAGE,13 - i,height - (6 + i),2,2,5 - i,1,145 + i, 1)

        Image(IMAGE,8,height - 99,1,1,0,5,300,95)

        for i in range(0,5):
                Image(IMAGE,9 + i,height - (100 + i),2,2,1 + i,1,149 - i, 1)


        # Titles
        glRasterPos2d(270, 15)
        Text("v0.6.5")

        selected = Blender.Object.GetSelected()
        if len(selected) > 0 and selected[0].getType() == "Mesh" and string.find(selected[0].name,"Prim_") != -1:  
                
                # Style Lines
                Image(IMAGE,5,height - 110,1.02,1,0,0,300,1)
                Image(IMAGE,5,height - 185,1.02,1,0,0,300,1)
                Image(IMAGE,5,height - 630,1,5.48,0,0,1,100)
                Image(IMAGE,5,height - 630,1.02,1,0,0,300,1)
                Image(IMAGE,309,height - 630,1,5.48,0,0,1,100)

                # GUI Buttons
                physics = Toggle(" ", EVENT_UPDATEVARS, 10, height - 135, 14, 14, physics.val, "Enable Physics when rezzed into Second Life. Press to Toggle. Off by Default.")
                glRasterPos2d(30, height - 132)
                Text("Physics")
                temponrez = Toggle(" ", EVENT_UPDATEVARS, 10, height - 155, 14, 14, temponrez.val, "Enable Temporary On Rez when rezzed into Second Life. Press to Toggle. Off by Default.")
                glRasterPos2d(30, height - 152)
                Text("Temporary")
                phantom = Toggle(" ", EVENT_UPDATEVARS, 10, height - 175, 14, 14, phantom.val, "Enable Phantom when rezzed into Second Life. Press to Toggle. Off by Default.")
                glRasterPos2d(30, height - 172)
                Text("Phantom")

                glRasterPos2d(11, height - 210)
                Text("Position (meters)")
                posx = Number("X ", EVENT_UPDATEVARS, 10, height - 235, 110, 18, posx.val, -512.0, 512.0, "X Position for this Primitive");
                posy = Number("Y ", EVENT_UPDATEVARS, 10, height - 255, 110, 18, posy.val, -512.0, 512.0, "Y Position for this Primitive");
                posz = Number("Z ", EVENT_UPDATEVARS, 10, height - 275, 110, 18, posz.val, -512.0, 512.0, "Z Position for this Primitive");

                # A redraw is required for scale events of regular prims, but NOT sculpted prims
                scaleevt = EVENT_UPDATEVARS|EVENT_DRAW
                if primType.val == 7:
                        scaleevt = EVENT_UPDATEVARS
                glRasterPos2d(11, height - 310)
                Text("Size (meters)")
                sizex = Number("X ", scaleevt, 10, height - 335, 110, 18, sizex.val, 0.01, 10.0, "X Scale for this Primitive");
                sizey = Number("Y ", scaleevt, 10, height - 355, 110, 18, sizey.val, 0.01, 10.0, "Y Scale for this Primitive");
                sizez = Number("Z ", scaleevt, 10, height - 375, 110, 18, sizez.val, 0.01, 10.0, "Z Scale for this Primitive");

                glRasterPos2d(11, height - 410)
                Text("Rotation (degrees)")
                rotx = Number("X ", EVENT_UPDATEVARS, 10, height - 435, 110, 18, rotx.val, 0.0, 360.0, "X Rotation for this Primitive");
                roty = Number("Y ", EVENT_UPDATEVARS, 10, height - 455, 110, 18, roty.val, 0.0, 360.0, "Y Rotation for this Primitive");
                rotz = Number("Z ", EVENT_UPDATEVARS, 10, height - 475, 110, 18, rotz.val, 0.0, 360.0, "Z Rotation for this Primitive");

                glRasterPos2d(11, height - 510)
                Text("Material")
                material = Menu("Material %t|Stone %x0|Metal %x1|Glass %x2|Wood %x3|Flesh %x4|Plastic %x5|Rubber %x6", EVENT_UPDATEVARS, 10, height - 535, 110, 18, material.val, "Material class for this Primitive")

                glRasterPos2d(11, height - 570)
                Text("Mirror and Buffer")
                Button("X",EVENT_MIRROR_X, 10, height - 595, 16, 18)
                Button("Y",EVENT_MIRROR_Y, 28, height - 595, 16, 18)
                Button("Z",EVENT_MIRROR_Z, 46, height - 595, 16, 18)
                Button("Copy",EVENT_COPY, 65, height - 595, 55, 18)
                mirrorframe = Menu("Mirror Reference %t|Local %x0|Global %x1", EVENT_UPDATEVARS, 10, height - 620, 110, 18, mirrorframe.val, "Mirror Frame-of-Reference")

                # Note: This var requires special treatment, since setting overlapping values is prohibited
                if primType.val < 7:
                        glRasterPos2d(146, height - 210)
                        Text("Path Cut Begin and End")
                        cutx = Number("B ", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 235, 70, 18, cutx.val, 0.0, cuty.val - 0.02, "Initial Cut Amount for this Primitive");
                        cuty = Number("E ", EVENT_UPDATEVARS|EVENT_DRAW, 225, height - 235, 70, 18, cuty.val, cutx.val + 0.02, 1.0, "Final Cut Amount for this Primitive");

                        glRasterPos2d(146, height - 250)
                        Text("Hollow")
                        hollow = Number("", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 275, 70, 18, hollow.val, 0, 95, "Hollow Amount for this Primitive");

                        glRasterPos2d(146, height - 300)
                        Text("Hollow Shape")
                        hollowshape = Menu("Hollow Shape %t|Default %x0|Square %x1|Circle %x2|Triangle %x3", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 325, 70, 18, hollowshape.val, "Hollow Type for this Primitive");

                if primType.val < 3:
                        bounds = 180.0
                else:
                        bounds = 360.0
                if primType.val < 7:
                        glRasterPos2d(146, height - 350)
                        Text("Twist Begin and End")
                        twistx = Number("B ", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 375, 70, 18, twistx.val, -1.0 * bounds, bounds, "Initial Twist for this Primitive");
                        twisty = Number("E ", EVENT_UPDATEVARS|EVENT_DRAW, 225, height - 375, 70, 18, twisty.val, -1.0 * bounds, bounds, "Final Twist for this Primitive");

                if primType.val < 3:
                        glRasterPos2d(146, height - 400)
                        Text("Taper (Top Size)")
                        topsizex = Number("X ", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 425, 70, 18, topsizex.val, -1.0, 1.0, "X Taper (Top Size) for this Primitive");
                        topsizey = Number("Y ", EVENT_UPDATEVARS|EVENT_DRAW, 225, height - 425, 70, 18, topsizey.val, -1.0, 1.0, "Y Taper (Top Size) for this Primitive");

                if primType.val != 3 and primType.val < 7:
                        glRasterPos2d(146, height - 450)
                        Text("Top Shear")
                        topshearx = Number("X ", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 475, 70, 18, topshearx.val, -0.5, 0.5, "X Top Shear for this Primitive");
                        topsheary = Number("Y ", EVENT_UPDATEVARS|EVENT_DRAW, 225, height - 475, 70, 18, topsheary.val, -0.5, 0.5, "Y Top Shear for this Primitive");

                if primType.val == 3:
                        glRasterPos2d(146, height - 450)
                        Text("Dimple")

                        # Added to enforce Second Life editor standards
                        max = dimpley.val - 0.02
                        if max > 0.95:
                                max = 0.95

                        min = dimplex.val + 0.02
                        if min < 0.05:
                                min = 0.05

                        dimplex = Number("B ", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 475, 70, 18, dimplex.val, 0.0, max, "Initial Dimple for this Primitive");
                        dimpley = Number("E ", EVENT_UPDATEVARS|EVENT_DRAW, 225, height - 475, 70, 18, dimpley.val, min, 1.0, "Final Dimple for this Primitive");

                if primType.val > 3 and primType.val < 7:
                        glRasterPos2d(226, height - 250)
                        Text("Skew")
                        skew = Number("", EVENT_UPDATEVARS|EVENT_DRAW, 225, height - 275, 70, 18, skew.val, -1.0, 1.0, "Skew Value for this Primitive");


                        glRasterPos2d(146, height - 400)
                        Text("Hole Size")
                        holesizex = Number("X ", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 425, 70, 18, holesizex.val, 0.05, 1.0, "X Hole Size for this Primitive");
                        holesizey = Number("Y ", EVENT_UPDATEVARS|EVENT_DRAW, 225, height - 425, 70, 18, holesizey.val, 0.05, 0.5, "Y Hole Size for this Primitive");

                        # Note: Special treatment vs. conflict again. 0.05 discrepancy
                        glRasterPos2d(146, height - 500)
                        Text("Profile Cut Begin and End")

                        # Added to enforce Second Life editor standards
                        max = advancedcuty.val - 0.02
                        if max > 0.95:
                                max = 0.95

                        min = advancedcutx.val + 0.02
                        if min < 0.05:
                                min = 0.05

                        advancedcutx = Number("B ", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 525, 70, 18, advancedcutx.val, 0.0, max, "Initial Advanced Cut for this Primitive");
                        advancedcuty = Number("E ", EVENT_UPDATEVARS|EVENT_DRAW, 225, height - 525, 70, 18, advancedcuty.val, min, 1.0, "Final Advanced Cut for this Primitive");

                        glRasterPos2d(146, height - 550)
                        Text("Taper")
                        taperx = Number("X ", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 575, 70, 18, taperx.val, -1.0, 1.0, "X Taper for this Primitive");
                        tapery =  Number("Y ", EVENT_UPDATEVARS|EVENT_DRAW, 225, height - 575, 70, 18, tapery.val, -1.0, 1.0, "Y Taper for this Primitive");

                        glRasterPos2d(146, height - 600)
                        Text("Radius Delta   Revolutions")
                        radiusoffset = Number(" ", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 625, 70, 18, radiusoffset.val, -1.0, 1.0, "Radius Delta for this Primitive");
                        revolutions = Number(" ", EVENT_UPDATEVARS|EVENT_DRAW, 225, height - 625, 70, 18, revolutions.val, 1.0, 4.0, "Number of Revolutions for this Primitive");

                if primType.val == 7:      
                        glRasterPos2d(146, height - 210)
                        Text("Number of Wrapped Faces")
                        sculptfacesx = Menu("X Faces %t|X: 4 %x4|X: 8 %x8|X: 16 %x16|X: 32 %x32", EVENT_UPDATEVARS|EVENT_DRAW|EVENT_RESET_SCULPTY, 145, height - 235, 70, 18, sculptfacesx.val, "X Faces for this sculpty");
                        sculptfacesy = Menu("Y Faces %t|Y: 4 %x4|Y: 8 %x8|Y: 16 %x16|Y: 32 %x32", EVENT_UPDATEVARS|EVENT_DRAW|EVENT_RESET_SCULPTY, 225, height - 235, 70, 18, sculptfacesy.val, "Y Faces for this sculpty");

                        glRasterPos2d(146, height - 250)
                        Text("Multires")
                        sculptmultires = Menu("Multires %t|Z: Off %x0|Z: +1 %x1|Z: +2 %x2", EVENT_UPDATEVARS|EVENT_DRAW|EVENT_RESET_SCULPTY, 145, height - 275, 70, 18, sculptmultires.val, "Adds multires levels to this object");
                        
                        glRasterPos2d(226, height - 250)
                        Text("Stitch Type")
                        sculpttype = Menu("Type %t|Sphere %x1|Torus %x2|Plane %x3|Cylinder %x4|Reset Mesh %x5", EVENT_UPDATEVARS|EVENT_DRAW|EVENT_RESET_SCULPTY, 225, height - 275, 70, 18, sculpttype.val, "Defines the base geometry of this sculpted primitive");

                        # Load default image
                        if sculptimage.val == "":
                                Image(SCULPTY_IMAGE,149,height - 422,2.18,2.18,0,5,128,128)
                        else:
                                try:
                                        guiimage = Blender.Image.Get(sculptimage.val)
                                        Image(guiimage,149,height - 422,139.52 / float(guiimage.size[0]),139.52 / float(guiimage.size[1]),0,5,128,128)
                                except:
                                        Image(SCULPTY_IMAGE,149,height - 422,2.18,2.18,0,5,128,128)

                        # Style Lines
                        Image(IMAGE,146,height - 291,1.08,1,0,0,134,1)
                        Image(IMAGE,146,height - 425,1.08,1,0,0,134,1)
                        Image(IMAGE,146,height - 425,1,1.42,0,0,1,134)
                        Image(IMAGE,291,height - 425,1,1.42,0,0,1,134)

                        # Button to rebake texture
                        Button("Bake",EVENT_BAKE_SCULPTY, 149, height - 450, 50, 18)
                        Button("Load Sculpty",EVENT_LOAD_SCULPTY, 201, height - 450, 85, 18)

                        if sculpttype.val == 2:
                                glRasterPos2d(146, height - 475)
                                Text("Hole Size")
                                holesizex = Number("X ", EVENT_UPDATEVARS|EVENT_DRAW|EVENT_RESET_SCULPTY, 145, height - 500, 70, 18, holesizex.val, 0.05, 1.0, "X Hole Size for this Primitive");
                                holesizey = Number("Y ", EVENT_UPDATEVARS|EVENT_DRAW|EVENT_RESET_SCULPTY, 225, height - 500, 70, 18, holesizey.val, 0.05, 0.5, "Y Hole Size for this Primitive");

                glRasterPos2d(146, height - 150)
                Text("Type             Detail")
                primType = Menu("Type %t|Box %x0|Cylinder %x1|Prism %x2|Sphere %x3|Torus %x4|Tube %x5|Ring %x6|Sculpted %x7", EVENT_UPDATEVARS|EVENT_DRAW, 145, height - 175, 70, 18, primType.val, "Prim Type for this Primitive")

                # Max LOD of 3 on sculpted objects (with multires). 
                # Will default to "3" when first created.
                # ALSO NOTE: EVENT_DRAW is ONLY called for regular (non-sculpted) prims
                # This is because the DRAW event is ONLY used for new mesh shapes
                if primType.val == 7:
                        levelofdetail = Number("", EVENT_UPDATEVARS, 225, height - 175, 70, 18, levelofdetail.val, 1, sculptmultires.val + 1, "Detail Level to draw for this Primitive");
                else:
                        levelofdetail = Number("", EVENT_UPDATEVARS|EVENT_DRAW, 225, height - 175, 70, 18, levelofdetail.val, 1, 12, "Detail Level to draw for this Primitive");
                glRasterPos2d(146, height - 132)
                Text("Name")
                name = String("", EVENT_UPDATEVARS, 185, height - 135, 110, 16, name.val, 80, "Name for this Primitive")
        else:
                # Print helpful text
                glRasterPos2d(5, height - 132)
                Text("No Primitive currently selected. Click above to add one.")

        # Draw Our Buttons
        Button("Save",EVENT_SAVE, 10, 10, 60, 18)
        Button("Load",EVENT_LOAD, 75, 10, 60, 18)
        Button("Exit",EVENT_EXIT, 180, 10, 60, 18)



# G. llDrawEnd
def DrawEnd(mesh, outer, inner, id):
        llDrawEnd(mesh, outer, inner, id)
def llDrawEnd(mesh, outer, inner, id):
        '''
        This function draws faces of end values on specific prims
        Example: Cubes, Prisms, and Cylinders all have two flat sides
        This function "caps" them proceedurally.

        Since Blender can only handle tris and quads (for newbies, that's 
        faces of three and four sides), we have to handle these lists very
        carefully so we don't get too many vertices. Simple enough.
        '''

        if len(outer) < 1 or len(inner) < 1:
                llDialog("Error in llDrawEnd: No vertices given as argument. Please try again.")
                return

        count = len(outer)
        out = count

        lowProx = 0.0
        z1 = outer[1][2]
        if id.type < 3:
                lowProx = -0.5 - z1 # Proximity to the bottom of the prim


        # Messy hack for 1.10.x compliance...
        if id.topsize[0] <= 1.0:
                topx = lowProx * (1 - id.topsize[0])
        else:
                topx = (z1 - 0.5) * (id.topsize[0] - 1)
        if id.topsize[1] <= 1.0:
                topy = lowProx * (1 - id.topsize[1])
        else:
                topy = (z1 - 0.5) * (id.topsize[1] - 1)


        for j in range(0,out):
                v = outer[j]
                x = v[0]
                y = v[1]
                z = v[2]
                mesh.verts.append(Vert((x + (x * topx) + (lowProx * id.topshear[0])) * id.size[0],(y + (y * topy) + (lowProx * id.topshear[1])) * id.size[1],z * id.size[2]))

        in1 = len(inner)
        if in1 > count:
                count = in1

        for j in range(0,in1):
                v = inner[j]
                x = v[0]
                y = v[1]
                z = v[2]
                mesh.verts.append(Vert((x + (x * topx) + (lowProx * id.topshear[0])) * id.size[0],(y + (y * topy) + (lowProx * id.topshear[1])) * id.size[1],z * id.size[2]))

        token = len(mesh.verts) - len(outer) - len(inner)

        print "Drawing end using token: "
        print token

        # Note: Must find closest point to render holes properly.
        for i in range(0,count - 1):
                f = Face()
                f.v.append(mesh.verts[(i * out / count) + token])
                f.v.append(mesh.verts[((i + 1) * out / count) + token])
                f.v.append(mesh.verts[((i + 1) * (in1 / count)) + out + token])
                f.v.append(mesh.verts[(i * (in1 / count)) + out + token])
                #print f

                mesh.faces.append(f)

        return mesh





# H. llDrawPrimMesh
def DrawPrimMesh(id):
        llDrawPrimMesh(id)
def llDrawPrimMesh(id):
        '''
        This function draws the actual prim from theparametersgiven. import 
        If you're interested in the inner workings of prims, or your name
        is Strife Onizuka, you may want to start here...

        First, let's define our internal (hole) vertices.
        If we have no hole, we just use a point in the center of the face.
        '''
        inner = []
        outer = []

        # Unset edit mode (required for mesh edits by script)
        editmode = 0
        if Blender.Window.EditMode():
                editmode = 1
        Blender.Window.EditMode(0)

        # @Fix: Sculpties do not require this ginormous logic block
        if id.type != PRIM_TYPE_SCULPT:
                if id.hollow > 95 or id.hollow < 0:
                        temp_string = ": %(amt)s percent. Using closest hollow." % {"amt": id.hollow}
                        llDialog("Warning: Invalid hollow amount in prim " + id.UUID + temp_string)
                        if id.hollow < 0:
                                id.hollow = 0
                        else:
                                id.hollow = 95

                if id.levelofdetail < 5:
                        if id.type < 3:
                                if id.cut[1] - id.cut[0] < 0.1:
                                        llDialog("Warning: Level of Detail too low for cut amount. Using detail level 8 in prim " + id.UUID)
                                        id.levelofdetail = 8
                        if id.type == 3:
                                if id.dimple[1] - id.dimple[0] < 0.1:
                                        llDialog("Warning: Level of Detail too low for dimple amount. Using detail level 8 in prim " + id.UUID)
                                        id.levelofdetail = 8
                        elif id.advancedcut[1] - id.advancedcut[0] < 0.1:
                                llDialog("Warning: Level of Detail too low for advanced cut amount. Using detail level 8 in prim " + id.UUID)
                                id.levelofdetail = 8


                if id.hollow > 70:
                        if (id.type == PRIM_TYPE_CYLINDER or id.type == PRIM_TYPE_PRISM or id.type == PRIM_TYPE_TORUS or id.type == PRIM_TYPE_RING) and id.hollowshape == PRIM_HOLE_SQUARE:
                                temp_string = ": %(amt)s percent. Using closest hollow (70)" % {"amt": id.hollow}
                                llDialog("Warning: Invalid hollow amount in prim " + id.UUID + temp_string)
                                id.hollow = 70
                        elif id.type == PRIM_TYPE_SPHERE and id.hollowshape == PRIM_HOLE_TRIANGLE:
                                temp_string = ": %(amt)s percent. Using closest hollow (70)" % {"amt": id.hollow}
                                llDialog("Warning: Invalid hollow amount in prim " + id.UUID + temp_string)
                                id.hollow = 70

                if id.hollow == 0 and id.type != 3:
                        inner = [(0,0,0.5)]

                temphs = id.hollowshape

                tempcut = (0.0,0.0,0.0)
                if id.type < 3:
                        tempcut = id.cut
                else:
                        tempcut = id.advancedcut

                if id.hollow <= 95 and id.hollow > 0 and id.type != PRIM_TYPE_SPHERE:
                        if temphs == 0:
                                if id.type == PRIM_TYPE_CYLINDER or id.type == PRIM_TYPE_SPHERE or id.type == PRIM_TYPE_TORUS:
                                        temphs = PRIM_HOLE_CIRCLE
                                elif id.type == PRIM_TYPE_PRISM or id.type == PRIM_TYPE_RING:
                                        temphs = PRIM_HOLE_TRIANGLE
                                else:
                                        temphs = PRIM_HOLE_SQUARE

                        if temphs == PRIM_HOLE_SQUARE:
                                '''
                                This should be (more or less) easy to figure out on your
                                own. It's basically a system for getting the hollow shape
                                of a square region. This is simply plugging in versus the
                                bounding box (or size of the prim).
                                '''
                                count = id.levelofdetail
                                for i in range(-1 * count,count):
                                        inner.append((i * id.hollow / (200.0 * id.levelofdetail),-1.0 * id.hollow / 200.0,0.5))
                                for i in range(-1 * count,count):
                                        inner.append((id.hollow / 200.0,i * id.hollow / (200.0 * id.levelofdetail),0.5))
                                for i in range(-1 * count,count):
                                        inner.append((-1.0 * i * id.hollow / (200.0 * id.levelofdetail),id.hollow / 200.0,0.5))
                                for i in range(-1 * count,count + 1):
                                        inner.append((-1.0 * id.hollow / 200.0,-1.0 * i * id.hollow / (200.0 * id.levelofdetail),0.5))

                                count = len(inner)
                                shear = 0

                                if tempcut[1] < 1.0:
                                        shear = tempcut[1] * (count - 1)
                                        point = cutBoxen(tempcut[1],id)
                                        point = (point[0] * id.hollow / 100,point[1] * id.hollow / 100,point[2])
                                        inner = inner[:int(shear) + 1]
                                        inner.append(point)

                                if tempcut[0] > 0.0:
                                        shear = tempcut[0] * count
                                        point = cutBoxen(tempcut[0],id)
                                        point = (point[0] * id.hollow / 100,point[1] * id.hollow / 100,point[2])
                                        inner = [point] + inner[int(shear) + 1:]


                        elif temphs == PRIM_HOLE_CIRCLE:
                                count = id.levelofdetail * 8
                                step = TWO_PI / count

                                for i in range(0,count + 1):
                                        inner.append((cos(i * step) * id.hollow / 200.0,sin(i * step) * id.hollow / 200.0,0.5))

                                count = len(inner)
                                shear = 0

                                if tempcut[1] < 1.0:
                                        shear = tempcut[1] * (count - 1)
                                        point = cutCircle(tempcut[1],id)
                                        point = (point[0] * id.hollow / 100,point[1] * id.hollow / 100,point[2])
                                        inner = inner[:int(shear) + 1]
                                        inner.append(point)

                                if tempcut[0] > 0.0:
                                        shear = tempcut[0] * count
                                        point = cutCircle(tempcut[0],id)
                                        point = (point[0] * id.hollow / 100,point[1] * id.hollow / 100,point[2])
                                        inner = [point] + inner[int(shear) + 1:]

                        elif temphs == PRIM_HOLE_TRIANGLE:
                                '''
                                This deserves some explanation, because it's not as easy to 
                                come to as the hollow of a square region.

                                Basically, with this we must come out to a number of points
                                EXACTLY equal to our outer region. Because this is not a
                                multiple of four, we have to approximate it first.

                                Then if we're lucky, we draw the resulting triangle.
                                '''


                                count = int(id.levelofdetail * 4 / 3)
                                max = (id.levelofdetail * 8) + 1

                                # For some reason, we need an extra vert for non-perfect squares
                                if sqrt(id.levelofdetail) - int(sqrt(id.levelofdetail)) != 0: 
                                        inner.append((0,count * id.hollow / (200.0 * count),0.5))

                                for i in range(-1 * count, count + 1):
                                        inner.append((-1.0 * (i + count) * 0.577350269 * id.hollow / (200.0 * count),-1.0 * i * id.hollow / (200.0 * count),0.5))
                                for i in range(-1 * count, count + 1):
                                        inner.append((i * 0.577350269 * id.hollow / (100.0 * count),-1.0 * id.hollow / 200.0,0.5))
                                for i in range(-1 * count, count + 1):
                                        inner.append((-1.0 * (i - count) * 0.577350269 * id.hollow / (200.0 * count),i * id.hollow / (200.0 * count),0.5))

                                while len(inner) < max:
                                        inner.append((0,id.hollow / 200.0,0.5))

                                count = len(inner)
                                shear = 0
                                notSquare = 0;
                                if (sqrt(id.levelofdetail) - int(sqrt(id.levelofdetail)) != 0):
                                        notSquare = 1;

                                if tempcut[1] < 1.0:
                                        shear = tempcut[1] * (count - 1 - notSquare)
                                        point = cutTri(tempcut[1],id)
                                        point = (point[0] * id.hollow / 100,point[1] * id.hollow / 100,point[2])
                                        inner = inner[:int(shear) + 1]
                                        inner.append(point)

                                        while len(inner) < (tempcut[1] * (count - 1)) + 2:
                                                inner.append(point)

                                if tempcut[0] > 0.0:
                                        shear = tempcut[0] * (count - notSquare)
                                        point = cutTri(tempcut[0],id)
                                        point = (point[0] * id.hollow / 100,point[1] * id.hollow / 100,point[2])
                                        inner = [point] + inner[int(shear) + 1 + notSquare:]

                                        if notSquare:
                                                inner = [point] + inner

                                        #while len(inner) < (count * (tempcut[1] - tempcut[0])) + 1:
                                        #  inner.append(point)



                # Now let's get our external vertices
                if id.type == PRIM_TYPE_BOX or id.type == PRIM_TYPE_TUBE:
                        '''
                        PRIM_TYPE_BOX, PRIM_TYPE_TUBE
                        '''
                        count = id.levelofdetail
                        for i in range(-1 * count,count):
                                outer.append((i / (2.0 * id.levelofdetail),-0.5,0.5))
                        for i in range(-1 * count,count):
                                outer.append((0.5,i / (2.0 * id.levelofdetail),0.5))
                        for i in range(-1 * count,count):
                                outer.append((-1 * i / (2.0 * id.levelofdetail),0.5,0.5))
                        for i in range(-1 * count,count + 1):
                                outer.append((-0.5,-1 * i / (2.0 * id.levelofdetail),0.5))



                        count = len(outer)
                        shear = 0


                        if tempcut[1] < 1.0:
                                shear = tempcut[1] * (count - 1)
                                point = cutBoxen(tempcut[1],id)
                                outer = outer[:int(shear) + 1]
                                outer.append(point)

                        if tempcut[0] > 0.0:
                                shear = tempcut[0] * count
                                point = cutBoxen(tempcut[0],id)
                                outer = [point] + outer[int(shear) + 1:]


                        # Transform our points based on the shape we're using
                        if(hollow > 0):
                                if temphs == PRIM_HOLE_SQUARE:
                                        pass
                                elif temphs == PRIM_HOLE_CIRCLE:
                                        TRIG_CONST = -0.707106781 # This is the sine/cosine constant for 45 degrees
                                        count = len(inner)
                                        for i in range(0,count):
                                                consider = inner[0]
                                                consider = (TRIG_CONST * (consider[0] - consider[1]),TRIG_CONST * (consider[0] + consider[1]),consider[2])
                                                inner.append(consider)
                                                inner = inner[1:]
                                elif temphs == PRIM_HOLE_TRIANGLE:
                                        TRIG_CONST = 0.707106781 # This is the sine/cosine constant for 45 degrees
                                        count = len(inner)
                                        for i in range(0,count):
                                                consider = inner[0]
                                                consider = (((-0.71 * TRIG_CONST * (consider[1] + consider[0])) - (0.0009 * id.hollow)),(0.71 * TRIG_CONST * (consider[0] - consider[1])) - (0.0009 * id.hollow),consider[2])
                                                inner.append(consider)
                                                inner = inner[1:]


                        if id.type == PRIM_TYPE_TUBE:
                                count = len(outer)
                                for i in range(0,count):
                                        consider = outer[0]
                                        consider = (-1.0 * consider[0],-1.0 * consider[1],consider[2])
                                        outer.append(consider)
                                        outer = outer[1:]

                                count = len(inner)
                                for i in range(0,count):
                                        consider = inner[0]
                                        consider = (-1.0 * consider[0],-1.0 * consider[1],consider[2])
                                        inner.append(consider)
                                        inner = inner[1:]


                elif id.type == PRIM_TYPE_CYLINDER or id.type == PRIM_TYPE_TORUS:
                        '''
                        PRIM_TYPE_CYLINDER, PRIM_TYPE_TORUS
                        '''
                        count = id.levelofdetail * 8
                        step = TWO_PI / count

                        for i in range(0,count + 1):
                                outer.append((cos(i * step) / 2.0,sin(i * step) / 2.0,0.5))

                        count = len(outer)
                        shear = 0

                        if tempcut[1] < 1.0:
                                shear = tempcut[1] * (count - 1)
                                point = cutCircle(tempcut[1],id)
                                outer = outer[:int(shear) + 1]
                                outer.append(point)

                        if tempcut[0] > 0.0:
                                shear = tempcut[0] * count
                                point = cutCircle(tempcut[0],id)
                                outer = [point] + outer[int(shear) + 1:]


                        # Transform our points based on the shape we're using
                        if(hollow > 0):
                                if temphs == PRIM_HOLE_SQUARE:
                                        TRIG_CONST = -0.707106781 # This is the sine/cosine constant for 45 degrees
                                        count = len(inner)
                                        for i in range(0,count):
                                                consider = inner[0]
                                                consider = (TRIG_CONST * (consider[0] + consider[1]),TRIG_CONST * (consider[1] - consider[0]),consider[2])
                                                inner.append(consider)
                                                inner = inner[1:]
                                elif temphs == PRIM_HOLE_CIRCLE:
                                        pass
                                elif temphs == PRIM_HOLE_TRIANGLE:
                                        count = len(inner)
                                        for i in range(0,count):
                                                consider = inner[0]
                                                consider = (((0.71 * consider[1]) + (0.00127 * id.hollow)),-0.71 * consider[0],consider[2])
                                                inner.append(consider)
                                                inner = inner[1:]

                        if id.type == PRIM_TYPE_TORUS:
                                TRIG_CONST = -0.707106781 # This is the sine/cosine constant for 45 degrees
                                count = len(outer)
                                for i in range(0,count):
                                        consider = outer[0]
                                        consider = (-1.0 * consider[0],-1.0 * consider[1],consider[2])
                                        outer.append(consider)
                                        outer = outer[1:]

                                count = len(inner)
                                for i in range(0,count):
                                        consider = inner[0]
                                        consider = (-1.0 * consider[0],-1.0 * consider[1],consider[2])
                                        inner.append(consider)
                                        inner = inner[1:]

                elif id.type == PRIM_TYPE_PRISM or id.type == PRIM_TYPE_RING:
                        '''
                        PRIM_TYPE_PRISM, PRIM_TYPE_RING
                        '''
                        count = int(id.levelofdetail * 4 / 3)
                        max = (id.levelofdetail * 8) + 1

                        # For some reason, we need an extra vert for non-perfect squares
                        if sqrt(id.levelofdetail) - int(sqrt(id.levelofdetail)) != 0: 
                                outer.append((0,0.5,0.5))

                        # Invert the axes here as we twist them into shape in a later step
                        for i in range(-1 * count, count + 1):
                                outer.append((-1 * (i + count) * 0.577350269 / (2.0 * count),-1 * i / (2.0 * count),0.5))
                        for i in range(-1 * count, count + 1):
                                outer.append((i * 0.577350269 / count,-0.5,0.5))
                        for i in range(-1 * count, count + 1):
                                outer.append((-1 * (i - count) * 0.577350269 / (2.0 * count),i / (2.0 * count),0.5))

                        while len(outer) < max:
                                outer.append((0,0.5,0.5))

                        count = len(outer)
                        shear = 0
                        notSquare = 0;
                        if (sqrt(id.levelofdetail) - int(sqrt(id.levelofdetail)) != 0):
                                notSquare = 1

                        if tempcut[1] < 1.0:
                                shear = tempcut[1] * (count - 1 - notSquare)
                                point = cutTri(tempcut[1],id)
                                outer = outer[:int(shear) + 1]
                                outer.append(point)

                                while len(outer) < (tempcut[1] * (count - 1)) + 2:
                                        outer.append(point)

                        if tempcut[0] > 0.0:
                                shear = tempcut[0] * (count - notSquare)
                                point = cutTri(tempcut[0],id)
                                outer = [point] + outer[int(shear) + 1 + notSquare:]

                                if notSquare:
                                        outer = [point] + outer

                                #while len(outer) < (count * (tempcut[1] - tempcut[0])) + 1:
                                #  outer.append(point)


                        # Translate points up 25% due to how this prim is shaped
                        count = len(outer)
                        for i in range(0,count):
                                consider = outer[0]
                                consider = (0.75 * consider[1] + 0.125,consider[0] * 0.865,consider[2])
                                outer.append(consider)
                                outer = outer[1:]

                        # Transform our points based on the shape we're using
                        if(hollow > 0):
                                if temphs == PRIM_HOLE_SQUARE:
                                        TRIG_CONST = 0.707106781 # This is the sine/cosine constant for 45 degrees

                                        while len(outer) > len(inner):
                                                inner.append(inner[len(inner) - 1])

                                        count = len(inner)
                                        for i in range(0,count):
                                                consider = inner[0]
                                                consider = (-1.0 * TRIG_CONST * 0.4714 * (consider[1] + consider[0]),-1.0 * TRIG_CONST * 0.4714 * (consider[0] - consider[1]),consider[2])
                                                inner.append(consider)
                                                inner = inner[1:]
                                elif temphs == PRIM_HOLE_CIRCLE:
                                        TRIG_CONST = 0.707106781 # This is the sine/cosine constant for 45 degrees
                                        while len(outer) > len(inner):
                                                inner.append(inner[len(inner) - 1])

                                        count = len(inner)
                                        for i in range(0,count):
                                                consider = inner[0]
                                                consider = (0.4714 * consider[0],-0.4714 * consider[1],consider[2])
                                                inner.append(consider)
                                                inner = inner[1:]
                                elif temphs == PRIM_HOLE_TRIANGLE:
                                        count = len(inner)
                                        for i in range(0,count):
                                                consider = inner[0]
                                                consider = (((0.5325 * consider[1]) + (0.00125 * id.hollow)),0.61415 * consider[0],consider[2]) # 0.71 times modifiers
                                                inner.append(consider)
                                                inner = inner[1:]


                        if id.type == PRIM_TYPE_RING:
                                count = len(outer)
                                for i in range(0,count):
                                        consider = outer[0]
                                        consider = (-1.0 * consider[0],consider[1],consider[2])
                                        outer.append(consider)
                                        outer = outer[1:]

                                count = len(inner)
                                for i in range(0,count):
                                        consider = inner[0]
                                        consider = (-1.0 * consider[0],consider[1],consider[2])
                                        inner.append(consider)
                                        inner = inner[1:]

                        else:
                                count = len(inner)
                                for i in range(0,count):
                                        consider = inner[0]
                                        consider = (consider[0],-1.0 * consider[1],consider[2])
                                        inner.append(consider)
                                        inner = inner[1:]

                                count = len(outer)
                                for i in range(0,count):
                                        consider = outer[0]
                                        consider = (consider[0],-1.0 * consider[1],consider[2])
                                        outer.append(consider)
                                        outer = outer[1:]


                elif id.type == PRIM_TYPE_SPHERE:
                        '''
                        PRIM_TYPE_SPHERE

                        Let me be honest. Spheres suck. Due to their nature, they don't easily fit into
                        ANY of the algorithms here. So... they get their own treatment.
                        '''
                        if id.hollow == 0:
                                inner = [(0,0,0)]

                        elif id.hollow <= 95 and id.hollow > 0:
                                if temphs == PRIM_HOLE_SQUARE:
                                        '''
                                        This should be (more or less) easy to figure out on your
                                        own. It's basically a system for getting the hollow shape
                                        of a square region. This is simply plugging in versus the
                                        bounding box (or size of the prim).
                                        '''


                                        count = id.levelofdetail
                                        for i in range(-1 * count,count):
                                                inner.append((i * id.hollow / (200.0 * id.levelofdetail),-1.0 * id.hollow / 200.0,0.0))
                                        for i in range(-1 * count,count + 1):
                                                inner.append((id.hollow / 200.0,i * id.hollow / (200.0 * id.levelofdetail),0.0))

                                        count = len(inner)
                                        shear = 0

                                        if id.dimple[1] < 1.0:
                                                shear = id.dimple[1] * (count - 1.0)
                                                point = cutBoxen(id.dimple[1] / 2.0,id)
                                                point = (point[0] * id.hollow / 100.0,point[1] * id.hollow / 100.0,0.0)
                                                inner = inner[:int(shear) + 1]
                                                inner.append(point)

                                        if id.dimple[0] > 0.0:
                                                shear = id.dimple[0] * count
                                                point = cutBoxen(id.dimple[0] / 2.0,id)
                                                point = (point[0] * id.hollow / 100.0,point[1] * id.hollow / 100.0,0.0)
                                                inner = [point] + inner[int(shear) + 1:]


                                        TRIG_CONST = 0.707106781 # This is the sine/cosine constant for 45 degrees
                                        count = len(inner)
                                        for i in range(0,count):
                                                consider = inner[0]
                                                consider = (0.8547 * TRIG_CONST * (consider[0] + consider[1]),0.8547 * TRIG_CONST * (consider[1] - consider[0]),0.8547 * consider[2])
                                                inner.append(consider)
                                                inner = inner[1:]



                                elif temphs == PRIM_HOLE_CIRCLE or temphs == PRIM_HOLE_DEFAULT:
                                        count = id.levelofdetail * 8
                                        step = TWO_PI / count

                                        for i in range(0,(count / 2) + 1):
                                                inner.append((1.17 * cos(i * step) / -2.0,1.17 * sin(i * step) / -2.0,0.0))

                                        count = len(inner)
                                        shear = 0

                                        if id.dimple[1] < 1.0:
                                                shear = id.dimple[1] * (count - 1)
                                                point = (1.17 * cos(PI * id.dimple[1]) / -2.0,1.17 * sin(PI * id.dimple[1]) / -2.0,0.0)
                                                inner = inner[:int(shear) + 1]
                                                inner.append(point)

                                        if id.dimple[0] > 0.0:
                                                shear = id.dimple[0] * count
                                                point = (1.17 * cos(PI * id.dimple[0]) / -2.0,1.17 * sin(PI * id.dimple[0]) / -2.0,0.0)
                                                inner = [point] + inner[int(shear) + 1:]

                                elif temphs == PRIM_HOLE_TRIANGLE:
                                        '''
                                        Again, this deserves some explanation, because it's not as easy to 
                                        come to as the hollow of a square region.

                                        Basically, with this we must come out to a number of points
                                        EXACTLY equal to our outer region. Because this is not a
                                        multiple of four, we have to approximate it first.

                                        Then if we're lucky, we draw the resulting hexagon.
                                        '''

                                        count = int(id.levelofdetail * 4 / 3)
                                        max = id.levelofdetail * 4

                                        # For some reason, we need an extra vert for non-perfect squares
                                        if sqrt(id.levelofdetail) - int(sqrt(id.levelofdetail)) != 0: 
                                                inner.append((id.hollow / -100.0,0.0,0.0))

                                        for i in range(0, count):
                                                inner.append(((i * 0.5 * id.hollow / (100.0 * count)) - (id.hollow / 100.0),-0.866 * i * id.hollow / (100.0 * count),0.0))
                                        for i in range(0, count):
                                                inner.append(((i * id.hollow / (100.0 * count)) - 0.35,0.866 * id.hollow / -100.0,0.0))
                                        for i in range(-1 * count,1):
                                                inner.append(((i * 0.5 * id.hollow / (100.0 * count)) + (id.hollow / 100.0),0.866 * i * id.hollow / (100.0 * count),0.0))


                                        while len(inner) < max:
                                                inner.append((id.hollow / 100.0,0.0,0.0))


                                        count = len(inner)
                                        shear = 0
                                        notSquare = 0;
                                        if (sqrt(id.levelofdetail) - int(sqrt(id.levelofdetail)) != 0):
                                                notSquare = 1;

                                        isLow = 0
                                        if id.levelofdetail < 3:
                                                isLow = 1

                                        if 1: # id.dimple[1] < 1.0:
                                                shear = id.dimple[1] * (count - 1 - notSquare)
                                                point = cutHalfHex(id.dimple[1],id)
                                                point = (point[0] * id.hollow / 100,point[1] * id.hollow / 100,point[2])
                                                inner = inner[:int(shear) + 1 + notSquare]
                                                inner.append(point)

                                                while len(inner) < (id.dimple[1] * (count - 1)) + 2:
                                                        inner.append(point)

                                        if 1: # id.dimple[0] > 0.0:
                                                shear = id.dimple[0] * (count - notSquare)
                                                if id.levelofdetail < 3:
                                                        if id.dimple[0] < 0.144 and id.levelofdetail == 2:
                                                                shear += 1
                                                        elif id.dimple[0] < 0.250 and id.levelofdetail == 1:
                                                                shear += 1
                                                point = cutHalfHex(id.dimple[0],id)
                                                point = (point[0] * id.hollow / 100,point[1] * id.hollow / 100,point[2])
                                                inner = [point] + inner[int(shear) + 1 + notSquare - isLow:]

                                                if notSquare:
                                                        inner = [point] + inner

                                                while len(inner) < (count * (id.dimple[1] - id.dimple[0])) + 1:
                                                        inner.append(point)




                        count = id.levelofdetail * 8
                        step = TWO_PI / count

                        for i in range(0,(count / 2) + 1):
                                outer.append((1.17 * cos(i * step) / -2.0,1.17 * sin(i * step) / -2.0,0.0))

                        count = len(outer)
                        shear = 0

                        if id.dimple[1] < 1.0:
                                shear = id.dimple[1] * (count - 1)
                                point = (1.17 * cos(PI * id.dimple[1]) / -2.0,1.17 * sin(PI * id.dimple[1]) / -2.0,0.0)
                                outer = outer[:int(shear) + 1]
                                outer.append(point)

                        if id.dimple[0] > 0.0:
                                shear = id.dimple[0] * count
                                point = (1.17 * cos(PI * id.dimple[0]) / -2.0,1.17 * sin(PI * id.dimple[0]) / -2.0,0.0)
                                outer = [point] + outer[int(shear) + 1:]


                if id.twist != (0.0,0.0,0.0) and id.type < 3:
                        count = len(outer)
                        temptheta = -1 * id.twist[0] * PI / 180.0
                        for i in range(0,count):
                                consider = outer[0]
                                consider = ((consider[0] * cos(temptheta)) - (consider[1] * sin(temptheta)),(consider[0] * sin(temptheta)) + (consider[1] * cos(temptheta)),consider[2])
                                outer.append(consider)
                                outer = outer[1:]

                        count = len(inner)
                        for i in range(0,count):
                                consider = inner[0]
                                consider = ((consider[0] * cos(temptheta)) - (consider[1] * sin(temptheta)),(consider[0] * sin(temptheta)) + (consider[1] * cos(temptheta)),consider[2])
                                inner.append(consider)
                                inner = inner[1:]

        # Remove any active multires, if present
        # Additionally, make sure the mesh and its object are linked
        # This prevents a bug that explodes all the verts and crashes Python
        if id.UUID == "-1" or id.UUID == "Num_-1":
                print "Silent fail; Mesh data not loaded yet."
                return

        mesh = Blender.Mesh.Get(id.UUID)
        obj = Blender.Object.Get("Prim_" + id.UUID)
        obj.link(mesh)
        mesh.multires = False

        # Create a new mesh
        mesh = GetRaw()
        args = []

        if id.type < 3:
                args = llExtrudeVerts(mesh,outer,inner,id)
        elif id.type < 7:
                if id.type == 3:
                        args = rotateVerts(outer,inner,PI,id)
                        outer = args[0]
                        inner = args[1]
                args = llLatheVerts(mesh,outer,inner,id)
        if id.type < 7:
                outer = args[0]
                inner = args[1]
                mesh = llDrawEnd(mesh,outer,inner,id)

        # Perform Blender.NMesh.PutRaw(*) on the existing mesh 
        # (this will wipe out a sculpt mesh as well)
        obj = PutRaw(mesh,id.UUID,TRUE)
        if obj:
                obj.setName("Prim_" + id.UUID) # Paranoia


        # If we were called for a sculpt, create the sculpt mesh
        if id.type == 7:
                mesh = Blender.Mesh.Get(id.UUID)
                mesh = llSculptMesh(id, mesh)
                if mesh and mesh.multires:

                        # ASSERT: For sculpties, level of detail must be <= multiresDrawLevel
                        if id.levelofdetail > id.sculptfaces[2]:
                                id.levelofdetail = id.sculptfaces[2] + 1

                        # ASSERT: Disable multires if value == 0
                        if id.sculptfaces[2] == 0:
                                mesh.multires = False

                        # Set multires draw level
                        mesh.multiresDrawLevel = id.levelofdetail
                #Blender.Redraw()
        else:
                Blender.Redraw()
                #llRedrawPrim(mesh,id.UUID,id.name) # Deprecated
        
        #llSetPrimitiveParams([PRIM_POSITION,pos,PRIM_ROTATION,rot])

        # Reset edit mode if it was present
        if editmode:
                Blender.Window.EditMode(1)



# i.   cutBoxen
def cutBoxen(val,id):
        point = ()
        if val < 0.25:
                point = ((val - 0.125) * 4.0,-0.5,0.5)
        elif val >= 0.25 and val < 0.5:
                point = (0.5,(val - 0.375) * 4.0,0.5)
        elif val >= 0.5 and val < 0.75:
                point = (-1.0 * (val - 0.625) * 4.0,0.5,0.5)
        else:
                point = (-0.5,-1.0 * (val - 0.875) * 4.0,0.5)

        return point



# ii.  cutCircle
def cutCircle(val,id):
        count = id.levelofdetail * 8
        step = TWO_PI / count
        return ((cos(val * count * step) / 2.0,sin(val * count * step) / 2.0,0.5))



# iii. cutHalfHex
def cutHalfHex(val,id):
        point = ()
        val *= 3
        if val < 1:  
                point = ((-0.5 * (1 - val)) - 0.5,-0.866 * val,0.0)
        elif val >= 1 and val < 2:
                point = ((val - 1.5) * 0.5,-0.866,0.0)
        else:
                point = ((0.5 * (val - 2)) + 0.5,-0.866 * (3 - val),0.0)

        return point



# iv.  cutTri
def cutTri(val,id):
        point = ()
        val *= 3
        if val < 1:  
                point = (-1.0 * val * 0.577350269,-1 * (val - 0.5),0.5)
        elif val >= 1 and val < 2:
                point = ((val - 1.5) * 1.154700538,-0.5,0.5)
        else:
                point = (-1.0 * (val - 3) * 0.577350269,(val - 2.5),0.5)

        return point




# I. llExtrudeVerts
def ExtrudeVerts(mesh, outer, inner, id):
        llExtrudeVerts(mesh, outer, inner, id)
def llExtrudeVerts(mesh, outer, inner, id):
        ''' 
        This function will extrude the vertices given through 3D space.
        Basically, this is the workhorse of llSetPrimitiveParams, below.

        The idea here is to form the core primitive first, before we rotate 
        it and move it to its final location.
        '''


        mesh = llDrawEnd(mesh,outer,inner,id)
        print "Outer is:"
        print outer
        print "Inner is:"
        print inner

        if len(outer) < 1 or len(inner) < 1:
                llDialog("Error in llExtrudeVerts: No vertices given as argument. Please try again.")
                return [[],[]]

        out = len(outer)
        in1 = len(inner)

        count = id.levelofdetail
        for i in range((-1 * count) + 1,count + 1):

                z = i / (count * -2.0)

                lowProx = 0.0
                if id.type < 3:
                        lowProx = -0.5 - z # Proximity to the bottom of the prim

                # Messy hack for 1.10.x compliance...

                if id.topsize[0] <= 1.0:
                        topx = lowProx * (1 - id.topsize[0])
                else:
                        topx = (z - 0.5) * (id.topsize[0] - 1)
                if id.topsize[1] <= 1.0:
                        topy = lowProx * (1 - id.topsize[1])
                else:
                        topy = (z - 0.5) * (id.topsize[1] - 1)

                incrTheta = (id.twist[1] - id.twist[0]) * PI / (-360.0 * count)

                for i in range(0,in1):
                        consider = inner[0]
                        consider = ((consider[0] * cos(incrTheta)) - (consider[1] * sin(incrTheta)),(consider[0] * sin(incrTheta)) + (consider[1] * cos(incrTheta)),z)
                        inner.append(consider)
                        inner = inner[1:]

                for i in range(0,out):
                        consider = outer[0]
                        consider = ((consider[0] * cos(incrTheta)) - (consider[1] * sin(incrTheta)),(consider[0] * sin(incrTheta)) + (consider[1] * cos(incrTheta)),z)
                        outer.append(consider)
                        outer = outer[1:]

                for j in range(0,out):
                        v = outer[j]
                        x = v[0]
                        y = v[1]
                        mesh.verts.append(Vert((x + (x * topx) + (lowProx * id.topshear[0])) * id.size[0],(y + (y * topy) + (lowProx * id.topshear[1])) * id.size[1],z * id.size[2]))

                #if in1 > 1 or id.cut[0] > 0.0 or id.cut[1] < 1:
                for j in range(0,in1):
                        v = inner[j]
                        x = v[0]
                        y = v[1]
                        mesh.verts.append(Vert((x + (x * topx) + (lowProx * id.topshear[0])) * id.size[0],(y + (y * topy) + (lowProx * id.topshear[1])) * id.size[1],z * id.size[2]))


                token = len(mesh.verts)
                for j in range(0,out - 1):
                        f = Face()
                        f.smooth = SMOOTH_ANGLE
                        f.v.append(mesh.verts[token - in1 - out + j])
                        f.v.append(mesh.verts[token - in1 - out + j + 1])
                        f.v.append(mesh.verts[token - (2 * in1) - (2 * out) + j + 1])
                        f.v.append(mesh.verts[token - (2 * in1) - (2 * out) + j])

                        mesh.faces.append(f)

                if id.cut[0] > 0.0 or id.cut[1] < 1.0:

                        f = Face()
                        f.smooth = SMOOTH_ANGLE
                        f.v.append(mesh.verts[token - in1 - 1])
                        f.v.append(mesh.verts[token - 1])
                        f.v.append(mesh.verts[token - in1 - out - 1])
                        f.v.append(mesh.verts[token - (2 * in1) - out - 1])

                        mesh.faces.append(f)

                        for j in range(0,in1 - 1):
                                f = Face()
                                f.smooth = SMOOTH_ANGLE
                                f.v.append(mesh.verts[token - 1 - j])
                                f.v.append(mesh.verts[token - 2 - j])
                                f.v.append(mesh.verts[token - in1 - out - 2 - j])
                                f.v.append(mesh.verts[token - in1 - out - 1 - j])

                                mesh.faces.append(f)

                        f = Face()
                        f.smooth = SMOOTH_ANGLE
                        f.v.append(mesh.verts[token - in1])
                        f.v.append(mesh.verts[token - in1 - out])
                        f.v.append(mesh.verts[token - (2 * in1) - (2 * out)])
                        f.v.append(mesh.verts[token - (2 * in1) - out])

                        mesh.faces.append(f)

                else:
                        f = Face()
                        f.smooth = SMOOTH_ANGLE
                        f.v.append(mesh.verts[token - in1 - 1])
                        f.v.append(mesh.verts[token - in1 - out])
                        f.v.append(mesh.verts[token - (2 * in1) - (2 * out)])
                        f.v.append(mesh.verts[token - (2 * in1) - out - 1])

                        mesh.faces.append(f)

                        if in1 > 1:
                                for j in range(0,in1 - 1):
                                        f = Face()
                                        f.smooth = SMOOTH_ANGLE
                                        f.v.append(mesh.verts[token - in1 + j])
                                        f.v.append(mesh.verts[token - in1 + j + 1])
                                        f.v.append(mesh.verts[token - (2 * in1) - out + j + 1])
                                        f.v.append(mesh.verts[token - (2 * in1) - out + j])

                                        mesh.faces.append(f)

                                f = Face()
                                f.smooth = SMOOTH_ANGLE
                                f.v.append(mesh.verts[token - 1])
                                f.v.append(mesh.verts[token - in1])
                                f.v.append(mesh.verts[token - (2 * in1) - out])
                                f.v.append(mesh.verts[token - in1 - out - 1])

                                mesh.faces.append(f)



        return [outer,inner]




# J. llGetPrimitiveParams
def GetPrimitiveParams(id,params):
        llGetPrimitiveParams(id,params)
def llGetPrimitiveParams(id,params):
        '''
        This function expressly emulates the llGetPrimitiveParams function found
        within Second Life, and is made to conform with SciTE and reduce
        the learning curve of this code.
        '''
        count = len(params)
        dump = []
        last = 0
        for i in range(0,count):

                param = params[i]
                if param == 9:
                        # PRIM_TYPE
                        dump.append(id.type)

                elif param < 3 and last == 9:
                        # PRIM_TYPE_BOX
                        # PRIM_TYPE_CYLINDER
                        # PRIM_TYPE_PRISM
                        dump.append(id.hollowshape)
                        dump.append(id.cut) 
                        dump.append(id.hollow) 
                        dump.append(id.twist) 
                        dump.append(id.topsize) 
                        dump.append(id.topshear)

                elif param == 3 and last == 9:
                        # PRIM_TYPE_SPHERE
                        dump.append(id.hollowshape) 
                        dump.append(id.cut)
                        dump.append(id.hollow) 
                        dump.append(id.twist)
                        dump.append(id.dimple)

                elif param > 3 and param < 7 and last == 9:
                        # PRIM_TYPE_TORUS
                        # PRIM_TYPE_TUBE
                        # PRIM_TYPE_RING
                        dump.append(id.hollowshape) 
                        dump.append(id.cut)
                        dump.append(id.hollow)
                        dump.append(id.twist)
                        dump.append(id.holesize)
                        dump.append(id.topshear)
                        dump.append(id.advancedcut)
                        dump.append(id.taper)
                        dump.append(id.revolutions)
                        dump.append(id.radiusoffset)
                        dump.append(id.skew)

                elif param == 7 and last == 9:
                        # PRIM_TYPE_SCULPT
                        dump.append(id.sculpttype)
                        dump.append(id.sculptimage)


                if param == 2:
                        # PRIM_MATERIAL
                        dump.append(id.material)

                if param == 3:
                        # PRIM_PHYSICS
                        dump.append(id.physics)

                if param == 4:
                        # PRIM_TEMP_ON_REZ
                        dump.append(id.temponrez)

                if param == 5:
                        # PRIM_PHANTOM
                        dump.append(id.phantom)

                if param == 6:
                        # PRIM_POSITION
                        dump.append(id.pos)

                if param == 7:
                        # PRIM_SIZE
                        dump.append(id.size)

                if param == 8:
                        # PRIM_ROTATION
                        tempRot = Euler(id.rot[0],id.rot[1],id.rot[2]).toQuat()
                        dump.append((tempRot[1],tempRot[2],tempRot[3],tempRot[0]))


                # These parameters are not currently supported and WILL SILENTLY FAIL
                '''
                if param == 17:
                        # PRIM_TEXTURE
                        dump.append(id.texture)

                if param == 18:
                        # PRIM_COLOR
                        dump.append(id.color)

                if param == 19:
                        # PRIM_BUMP_SHINY
                        dump.append(id.bumpshiny)

                if param == 20:
                        # PRIM_FULLBRIGHT
                        dump.append(id.bright)

                if param == 21:
                        # PRIM_FLEXIBLE
                        dump.append(id.flex)

                if param == 22:
                        # PRIM_TEXGEN
                        dump.append(id.map)

                if param == 23:
                        # PRIM_POINT_LIGHT
                        dump.append(id.light)
                '''

                last = param

        return dump





# K. llLatheVerts
def LatheVerts(mesh, outer, inner, id):
        llLatheVerts(mesh, outer, inner, id)
def llLatheVerts(mesh, outer, inner, id):
        '''
        This function spins points around a central axis. It's used by spheres,
        tubes, rings, and torii to form the final primitive.
        '''
        numVerts = len(outer) + len(inner)

        count = id.levelofdetail * 8
        step = TWO_PI / count
        currStep = (id.cut[0] * TWO_PI)
        out = len(outer)
        in1 = len(inner)


        incrTheta = (id.twist[1] - id.twist[0]) * PI / (180.0 * count) * id.revolutions
        currTheta = ((id.twist[0] * PI) / 180.0) + (id.cut[0] * incrTheta * count) * id.revolutions

        tinner = []
        touter = []
        tinner += inner
        touter += outer
        if id.type != 3:
                args = scaleVerts(touter,tinner,currStep,id)
                touter = args[0]
                tinner = args[1]
        if id.twist != (0.0,0.0,0.0):
                args = twistVerts(touter,tinner,currTheta,id)
                touter = args[0]
                tinner = args[1]
        if id.type != 3:
                args = translateVerts(touter,tinner,currStep,id)
                touter = args[0]
                tinner = args[1]
        args = rotateVerts(touter,tinner,id.cut[0] * TWO_PI,id)
        touter = args[0]
        tinner = args[1]

        mesh = llDrawEnd(mesh,touter,tinner,id)

        print "Outer is:"
        print outer
        print "Inner is:"
        print inner

        '''
        Instead of manipulating this list subtractively, as with earlier functions,
        we simply start at the opening cut and end at the final cut.

        This saves us time from manipulatingtheactualmeshparameters. import 
        '''

        high = int(id.cut[1] * count)
        low = int(id.cut[0] * count) 
        terminus = high - low

        for i in range(0,terminus):
                currTheta += incrTheta
                currStep += step
                tinner = []
                touter = []
                tinner += inner
                touter += outer
                if i == terminus - 1:
                        if id.type != 3:
                                args = scaleVerts(touter,tinner,id.cut[1] * TWO_PI,id)
                                touter = args[0]
                                tinner = args[1]
                        if id.twist != (0.0,0.0,0.0):
                                args = twistVerts(touter,tinner,((id.twist[0] * PI) / 180.0) + (id.cut[1] * incrTheta * count),id)
                                touter = args[0]
                                tinner = args[1]
                        if id.type != 3:
                                args = translateVerts(touter,tinner,id.cut[1] * TWO_PI,id)
                                touter = args[0]
                                tinner = args[1]
                        args = rotateVerts(touter,tinner,id.cut[1] * TWO_PI,id)
                        touter = args[0]
                        tinner = args[1]

                else:
                        if id.type != 3:
                                args = scaleVerts(touter,tinner,currStep,id)
                                touter = args[0]
                                tinner = args[1]
                        if id.twist != (0.0,0.0,0.0):
                                args = twistVerts(touter,tinner,currTheta,id)
                                touter = args[0]
                                tinner = args[1]
                        if id.type != 3:
                                args = translateVerts(touter,tinner,currStep,id)
                                touter = args[0]
                                tinner = args[1]
                        args = rotateVerts(touter,tinner,currStep,id)
                        touter = args[0]
                        tinner = args[1]

                for j in range(0,out):
                        v = touter[j]
                        x = v[0]
                        y = v[1]
                        z = v[2]
                        mesh.verts.append(Vert(x * id.size[0],y * id.size[1],z * id.size[2]))

                if 1: #if in1 > 1 or id.advancedcut[0] > 0.0 or id.advancedcut[1] < 1:
                        for j in range(0,in1):
                                v = tinner[j]
                                x = v[0]
                                y = v[1]
                                z = v[2]
                                mesh.verts.append(Vert(x * id.size[0],y * id.size[1],z * id.size[2]))

                token = len(mesh.verts)
                for j in range(0,out - 1):
                        f = Face()
                        f.smooth = SMOOTH_ANGLE
                        f.v.append(mesh.verts[token - in1 - out + j])
                        f.v.append(mesh.verts[token - in1 - out + j + 1])
                        f.v.append(mesh.verts[token - (2 * in1) - (2 * out) + j + 1])
                        f.v.append(mesh.verts[token - (2 * in1) - (2 * out) + j])

                        mesh.faces.append(f)

                if id.advancedcut[0] > 0.0 or id.advancedcut[1] < 1.0 or id.cut[0] > 0.0 or id.cut[1] < 1.0 or id.type == PRIM_TYPE_SPHERE:

                        f = Face()
                        f.smooth = SMOOTH_ANGLE
                        f.v.append(mesh.verts[token - in1 - 1])
                        f.v.append(mesh.verts[token - 1])
                        f.v.append(mesh.verts[token - in1 - out - 1])
                        f.v.append(mesh.verts[token - (2 * in1) - out - 1])

                        mesh.faces.append(f)

                        for j in range(0,in1 - 1):
                                f = Face()
                                f.smooth = SMOOTH_ANGLE
                                f.v.append(mesh.verts[token - 1 - j])
                                f.v.append(mesh.verts[token - 2 - j])
                                f.v.append(mesh.verts[token - in1 - out - 2 - j])
                                f.v.append(mesh.verts[token - in1 - out - 1 - j])

                                mesh.faces.append(f)

                        f = Face()
                        f.smooth = SMOOTH_ANGLE
                        f.v.append(mesh.verts[token - in1])
                        f.v.append(mesh.verts[token - in1 - out])
                        f.v.append(mesh.verts[token - (2 * in1) - (2 * out)])
                        f.v.append(mesh.verts[token - (2 * in1) - out])

                        mesh.faces.append(f)

                else:
                        f = Face()
                        f.smooth = SMOOTH_ANGLE
                        f.v.append(mesh.verts[token - in1 - 1])
                        f.v.append(mesh.verts[token - in1 - out])
                        f.v.append(mesh.verts[token - (2 * in1) - (2 * out)])
                        f.v.append(mesh.verts[token - (2 * in1) - out - 1])

                        mesh.faces.append(f)

                        if in1 > 1:
                                for j in range(0,in1 - 1):
                                        f = Face()
                                        f.smooth = SMOOTH_ANGLE
                                        f.v.append(mesh.verts[token - in1 + j])
                                        f.v.append(mesh.verts[token - in1 + j + 1])
                                        f.v.append(mesh.verts[token - (2 * in1) - out + j + 1])
                                        f.v.append(mesh.verts[token - (2 * in1) - out + j])

                                        mesh.faces.append(f)

                                f = Face()
                                f.smooth = SMOOTH_ANGLE
                                f.v.append(mesh.verts[token - 1])
                                f.v.append(mesh.verts[token - in1])
                                f.v.append(mesh.verts[token - (2 * in1) - out])
                                f.v.append(mesh.verts[token - in1 - out - 1])

                                mesh.faces.append(f)



        return [touter,tinner]



# i.   rotateVerts
def rotateVerts(outer,inner,theta,id):
        theta *= id.revolutions
        in1 = len(inner)
        out = len(outer)
        for j in range(0,in1):
                consider = inner[0]
                consider = (consider[0],((consider[1] * cos(theta)) - (consider[2] * sin(theta))),((consider[1] * sin(theta)) + (consider[2] * cos(theta))))
                if id.type == PRIM_TYPE_SPHERE:
                        consider = (consider[0] * id.hollow / 100.0, consider[1] * id.hollow / 100.0, consider[2] * id.hollow / 100.0)
                consider = (consider[0] + (consider[2] * id.topshear[0]),consider[1] + (consider[2] * id.topshear[1]),consider[2])
                inner.append(consider)
                inner = inner[1:]


        for j in range(0,out):
                consider = outer[0]
                consider = (consider[0],(consider[1] * cos(theta)) - (consider[2] * sin(theta)) ,(consider[1] * sin(theta)) + (consider[2] * cos(theta)))
                consider = (consider[0] + (consider[2] * id.topshear[0]),consider[1] + (consider[2] * id.topshear[1]),consider[2])
                outer.append(consider)
                outer = outer[1:]
        return [outer,inner]



# ii.  scaleVerts
def scaleVerts(outer,inner,theta,id):
        place = theta / TWO_PI
        taperx = id.taper[0]
        tapery = id.taper[1]
        radiusoffset = id.radiusoffset

        if taperx >= 0.0:
                taperx = place + ((1 - place) * (1 - taperx))
        else:
                taperx = (1 - place) + (place * (1 + taperx))
        if tapery >= 0.0:
                tapery = place + ((1 - place) * (1 - tapery))
        else:
                tapery = (1 - place) + (place * (1 + tapery))
        if radiusoffset >= 0.0:
                radiusoffset = place + ((1 - place) * (1 - radiusoffset))
        else:
                radiusoffset = (1 - place) + (place * (1 + radiusoffset))

        count = len(outer)
        for i in range(0,count):
                consider = outer[0]
                consider = (taperx * id.holesize[0] * consider[0],radiusoffset * tapery * id.holesize[1] * consider[1],0.0)
                outer.append(consider)
                outer = outer[1:]


        count = len(inner)
        for i in range(0,count):
                consider = inner[0]
                consider = (taperx * id.holesize[0] * consider[0],radiusoffset * tapery * id.holesize[1] * consider[1],0.0)
                inner.append(consider)
                inner = inner[1:]
        return [outer,inner]



# iii. translateVerts
def translateVerts(outer,inner,theta,id):
        place = (-1.0 * theta / TWO_PI)
        skew = id.skew * (place - 0.5)

        radiusoffset = id.radiusoffset

        if radiusoffset >= 0.0:
                radiusoffset = place + ((1 - place) * (1 - radiusoffset))
        else:
                radiusoffset = (1 - place) + (place * (1 + radiusoffset))


        count = len(outer)
        for i in range(0,count):
                consider = outer[0]
                consider = (consider[0] + skew,radiusoffset * (consider[1] + 0.5 - (id.holesize[1] / 2.0)),0.0)
                outer.append(consider)
                outer = outer[1:]


        count = len(inner)
        for i in range(0,count):
                consider = inner[0]
                consider = (consider[0] + skew,radiusoffset * (consider[1] + 0.5 - (id.holesize[1] / 2.0)),0.0)
                inner.append(consider)
                inner = inner[1:]
        return [outer,inner]



# iv.  twistVerts
def twistVerts(outer,inner,theta,id):
        count = len(outer)
        temptheta = 1 * theta
        for i in range(0,count):
                consider = outer[0]
                consider = ((consider[0] * cos(temptheta)) - (consider[1] * sin(temptheta)),(consider[0] * sin(temptheta)) + (consider[1] * cos(temptheta)),consider[2])
                outer.append(consider)
                outer = outer[1:]

        count = len(inner)
        for i in range(0,count):
                consider = inner[0]
                consider = ((consider[0] * cos(temptheta)) - (consider[1] * sin(temptheta)),(consider[0] * sin(temptheta)) + (consider[1] * cos(temptheta)),consider[2])
                inner.append(consider)
                inner = inner[1:]
        return [outer,inner]





# L. llLoadPrims
def LoadPrims(filename):
        llLoadPrims(filename)
def llLoadPrims(filename):
        ''' 
        This function loads prims from afileintothecurrentregistry. import 
        '''
        if not os.path.isfile(filename):
                llDialog("Please specify a valid .prims file")
                return
        file = open(filename,'r')
        filestring = ""
        notEOF = 1
        tags = []
        buffer = []

        Blender.Window.WaitCursor(1)
        in_editmode = Blender.Window.EditMode()

        # MUST leave edit mode before changing an active mesh:
        if in_editmode:
                Blender.Window.EditMode(0)


        while notEOF:
                line = file.readline()                     # Reads a new line

                if line.find("\n") == -1:
                        notEOF = 0
                else:
                        line = line[0:len(line) - 1]       # Otherwise, we remove "\n"
                line = string.replace(line,"\r","")
                filestring += line

        filebuffer = string.split(filestring,'<')
        del filestring
        file.close()

        # Store a default prim so we don't crash if Bad Stuff happens
        prim = Primitive()

        bufferlen = len(filebuffer)
        for i in range(0,bufferlen):
                currline = filebuffer[i]
                if string.strip(currline) != '':
                        if string.find(currline,'>') == -1:
                                llDialog("Loading prims failed: Missing > character")
                                return

                        # Uncomment to strip anything after the ">" character
                        #currline = string.split(currline,'>')[0]

                        # Take a slice BEFORE STRING DATA to determine tag type
                        slice = string.replace(string.lower(string.split(currline,'"')[0])," ","")

                        # Actual tag operations happen here
                        

                        # Closing tags start first
                        if string.find(slice[:10],'/primitive') != -1 and string.find(slice[:11],'/primitives') == -1:
                                tags.remove('primitive')
                                llDrawPrimMesh(prim)
                                
                                if prim.type == 7:
                                        imagefile = os.path.join(string.rsplit(string.rsplit(filename,'/',1)[0],'\\',1)[0],prim.sculptimage)
                                        load_sculpty(prim,imagefile)
                                
                                selected = Blender.Object.GetSelected()
                                if len(selected) > 0 and selected[0].getType() == "Mesh":
                                        selected[0].setLocation(prim.position[0],prim.position[1],prim.position[2])
                                        selected[0].setEuler([prim.rotation[0] * PI / 180.0,prim.rotation[1] * PI / 180.0, prim.rotation[2] * PI / 180.0])
                        elif string.find(slice[:7],'/states') != -1:
                                tags.remove('states')
                        elif string.find(slice[:8],'/physics') != -1:
                                tags.remove('physics')
                        elif string.find(slice[:10],'/temporary') != -1:
                                tags.remove('temporary')
                        elif string.find(slice[:8],'/phantom') != -1:
                                tags.remove('phantom')
                        elif string.find(slice[:11],'/properties') != -1:
                                tags.remove('properties')
                        elif string.find(slice[:9],'/textures') != -1:
                                tags.remove('textures')
                        elif string.find(slice[:8],'/scripts') != -1:
                                tags.remove('scripts')


                        elif string.find(slice[:9],'primitive') != -1 and string.find(slice[:10],'primitives') == -1:

                                # Primitive Tag

                                # Attributes:
                                # key -- Defines a key. Default is a random internal key
                                # name -- Defines a name. Default is "Object"
                                # description -- Defines a description. None by default
                                # version -- Defines a version number for tags. Default is current

                                tags.append('primitive')

                                # Strip off tag name
                                currline = currline[9:]

                                # Key attribute
                                litmus = string.find(string.lower(currline),'key')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        key = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        key = internalKey(PrimHolder)

                                # Name attribute
                                litmus = string.find(string.lower(currline),'name')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        name = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        name = "Object"

                                # Description attribute
                                litmus = string.find(string.lower(currline),'description')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        description = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        description = ""

                                # Version attribute
                                litmus = string.find(string.lower(currline),'version')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        version = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        version = str(VERSION)

                                # Make the new prim with basic stuffs
                                prim = llNewPrim(0,PrimHolder,key)
                                prim.UUID = key
                                prim.name = name
                                prim.description = description


                        elif string.find(slice[:6],'states') != -1:

                                # States Tag
                                # Used to enclose state definitions

                                # Child tags include:
                                # Physics: Define physics params and whether the system is currently on
                                # Temporary: Define temp-on-rez parameters (if added) and state
                                # Phantom: Define phantom params (if added in future versions) and state

                                # Note that lock is not used, since it is currently not automated by scripts


                                # Note the states tag is arbitrary
                                tags.append('states')


                        elif string.find(slice[:7],'physics') != -1:

                                # Physics Tag

                                # Attributes:
                                # Params -- accept arbitrary parameters

                                # Enable tag state
                                tags.append('physics')

                                # Strip off tag name
                                currline = currline[7:]

                                # Params attribute
                                litmus = string.find(string.lower(currline),'params')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        params = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        params = ""
                                # Note this data currently goes nowhere.
                                # It is included for your hacking convenience


                                # Check for on or off
                                litmus = string.find(currline,'>')

                                litmus = string.find(string.upper(currline),'TRUE',litmus)
                                if litmus != -1:
                                        prim.physics = 1
                                else:
                                        prim.physics = 0


                        elif string.find(slice[:9],'temporary') != -1:

                                # Temporary Tag

                                # Attributes:
                                # Params -- accept arbitrary parameters

                                # Enable tag state
                                tags.append('temporary')

                                # Strip off tag name
                                currline = currline[9:]

                                # Params attribute
                                litmus = string.find(string.lower(currline),'params')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        params = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        params = ""
                                # Note this data currently goes nowhere.
                                # It is included for your hacking convenience


                                # Check for on or off
                                litmus = string.find(currline,'>')

                                litmus = string.find(string.upper(currline),'TRUE',litmus)
                                if litmus != -1:
                                        prim.temponrez = 1
                                else:
                                        prim.temponrez = 0


                        elif string.find(slice[:7],'phantom') != -1:

                                # Phantom Tag

                                # Attributes:
                                # Params -- accept arbitrary parameters

                                # Enable tag state
                                tags.append('phantom')

                                # Strip off tag name
                                currline = currline[7:]

                                # Params attribute
                                litmus = string.find(string.lower(currline),'params')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        params = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        params = ""
                                # Note this data currently goes nowhere.
                                # It is included for your hacking convenience


                                # Check for on or off
                                litmus = string.find(currline,'>')

                                litmus = string.find(string.upper(currline),'TRUE',litmus)
                                if litmus != -1:
                                        prim.phantom = 1
                                else:
                                        prim.phantom = 0


                        elif string.find(slice[:10],'properties') != -1:

                                # Properties Tag
                                # Used to enclose property definitions

                                # Child tags include:
                                # Textures: Define texture data. Currently unsupported by this tool
                                # Scripts: Optional field for script "hooks" to enable when rezzed into the world

                                # Other tags:

                                # NOTE: Some of these are consolidated in Second Life proper.
                                # These are separated here for simplicity, as well as the possibility Second Life
                                # may alter their file specification again.

                                # Level of detail: An added feature for versioning prim detail. Quite handy!
                                # Type: Prim type (Box, Cylinder, Sphere, etc)
                                # Position: Prim's position in Blender units (X,Y,Z)
                                # Rotation: Prim's quaternion rotation (X,Y,Z,S)
                                # WARNING: This differs from Blender's Quaternion syntax, which uses S first!
                                # Size: Prim's size in Blender units
                                # Cut: Prim's normal cut amount
                                # Dimple: Prim's dimple amount
                                # Advanced Cut: Prim's "advanced cut" amount
                                # Hollow: Prim's hollow amount
                                # Twist: Prim's twist amount
                                # Topsize: Prim's top size (taper in 1.10.x) amount
                                # Holesize: Prim's hole size amount
                                # Topshear: Prim's top shear amount
                                # Taper: Prim's actual taper value (pre- and post-1.10.x)
                                # Revolutions: Prim's number of revolutions
                                # Skew: Prim's skew amount
                                # Material: Prim's material type
                                # Hollowshape: Prim's hollow shape (circle, square, triangle, or default)
                                # Sculpttype: Prim's sculpt type (sculpties only!)
                                # Sculptimage: Prim's sculpt image (sculpties only!)
                                # Sculptfaces: Number of faces (x, y) and multires (z) (sculpties only!)


                                # This tag is arbitrary, and need not be included
                                tags.append('properties')


                        elif string.find(slice[:13],'levelofdetail') != -1:

                                # Level-of-Detail Tag

                                # Attributes:
                                # Val: Value for this variable

                                # Strip off tag name
                                currline = currline[13:]

                                # Val attribute
                                litmus = string.find(string.lower(currline),'val')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        val = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        val = "2"

                                prim.levelofdetail = int(val)


                        elif string.find(slice[:8],'position') != -1:

                                # Position Tag

                                # Attributes:
                                # X, Y, Z: Definitions for each value

                                # Strip off tag name
                                currline = currline[8:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.0"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.0"

                                # Z attribute
                                litmus = string.find(string.lower(currline),'z')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        z = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        z = "0.0"

                                prim.position = (float(x),float(y),float(z))


                        elif string.find(slice[:8],'rotation') != -1:

                                # Rotation Tag

                                # Attributes:
                                # X, Y, Z: Definitions for each value

                                # Strip off tag name
                                currline = currline[8:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.0"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.0"

                                # Z attribute
                                litmus = string.find(string.lower(currline),'z')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        z = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        z = "0.0"

                                # S attribute
                                litmus = string.find(string.lower(currline),'s')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        s = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        s = "1.0"

                                # Need to convert from quaternion notation.
                                # ALSO, note that S is first in Blender!
                                tempRot = Quaternion(float(s),float(x),float(y),float(z)).toEuler()
                                prim.rotation = (tempRot[0],tempRot[1],tempRot[2])


                        elif string.find(slice[:7],'topsize') != -1:

                                # Top Size Tag
                                # Preceeds normal "size" in the chain!

                                # Attributes:
                                # X, Y: Definitions for each value

                                # Strip off tag name
                                currline = currline[7:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.0"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.0"

                                prim.topsize = (float(x),float(y),0.0)


                        elif string.find(slice[:8],'holesize') != -1:

                                # Hole Size Tag
                                # Preceeds normal "size" in the chain!

                                # Attributes:
                                # X, Y: Definitions for each value

                                # Strip off tag name
                                currline = currline[7:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.0"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.0"

                                prim.holesize = (float(x),float(y),0.0)


                        elif string.find(slice[:4],'size') != -1:

                                # Size Tag

                                # Attributes:
                                # X, Y, Z: Definitions for each value

                                # Strip off tag name
                                currline = currline[4:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.5"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.5"

                                # Z attribute
                                litmus = string.find(string.lower(currline),'z')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        z = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        z = "0.5"

                                prim.size = (float(x),float(y),float(z))


                        elif string.find(slice[:11],'advancedcut') != -1:

                                # Advanced Cut Tag
                                # Preceeds cut here for naming reasons

                                # Attributes:
                                # X, Y: Definitions for each value

                                # Strip off tag name
                                currline = currline[11:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.0"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.0"

                                prim.advancedcut = (float(x),float(y),0.0)


                        elif string.find(slice[:3],'cut') != -1:

                                # Cut Tag

                                # Attributes:
                                # X, Y: Definitions for each value

                                # Strip off tag name
                                currline = currline[3:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.0"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.0"

                                prim.cut = (float(x),float(y),0.0)


                        elif string.find(slice[:6],'dimple') != -1:

                                # Dimple Tag

                                # Attributes:
                                # X, Y: Definitions for each value

                                # Strip off tag name
                                currline = currline[6:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.0"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.0"

                                prim.dimple = (float(x),float(y),0.0)


                        elif string.find(slice[:11],'hollowshape') != -1:

                                # Hollow Shape Tag
                                # Must be before hollow for naming reasons

                                # Attributes:
                                # Val: Value for this variable

                                # Strip off tag name
                                currline = currline[11:]

                                # Val attribute
                                litmus = string.find(string.lower(currline),'val')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        val = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        val = "0"

                                prim.hollowshape = int(val)


                        elif string.find(slice[:6],'hollow') != -1:

                                # Hollow Tag

                                # Attributes:
                                # Val: Value for this variable

                                # Strip off tag name
                                currline = currline[6:]

                                # Val attribute
                                litmus = string.find(string.lower(currline),'val')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        val = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        val = "0"

                                prim.hollow = int(val)


                        elif string.find(slice[:5],'twist') != -1:

                                # Twist Tag

                                # Attributes:
                                # X, Y: Definitions for each value

                                # Strip off tag name
                                currline = currline[5:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.0"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.0"

                                prim.twist = (float(x),float(y),0.0)


                        elif string.find(slice[:8],'topshear') != -1:  

                                # Top Shear Tag

                                # Attributes:
                                # X, Y: Definitions for each value

                                # Strip off tag name
                                currline = currline[8:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.0"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.0"

                                prim.topshear = (float(x),float(y),0.0)


                        elif string.find(slice[:5],'taper') != -1:

                                # Taper Tag

                                # Attributes:
                                # X, Y: Definitions for each value

                                # Strip off tag name
                                currline = currline[5:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.0"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.0"

                                prim.taper = (float(x),float(y),0.0)


                        elif string.find(slice[:11],'revolutions') != -1:

                                # Revolutions Tag

                                # Attributes:
                                # Val: Value for this variable

                                # Strip off tag name
                                currline = currline[11:]

                                # Val attribute
                                litmus = string.find(string.lower(currline),'val')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        val = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        val = "1.0"

                                prim.revolutions = float(val)


                        elif string.find(slice[:12],'radiusoffset') != -1:

                                # Radius Offset Tag

                                # Attributes:
                                # Val: Value for this variable

                                # Strip off tag name
                                currline = currline[12:]

                                # Val attribute
                                litmus = string.find(string.lower(currline),'val')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        val = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        val = "0.0"

                                prim.radiusoffset = float(val)


                        elif string.find(slice[:4],'skew') != -1:

                                # Skew Tag

                                # Attributes:
                                # Val: Value for this variable

                                # Strip off tag name
                                currline = currline[4:]

                                # Val attribute
                                litmus = string.find(string.lower(currline),'val')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        val = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        val = "0.0"

                                prim.skew = float(val)


                        elif string.find(slice[:8],'material') != -1:

                                # Material Tag

                                # Attributes:
                                # Val: Value for this variable

                                # Strip off tag name
                                currline = currline[8:]

                                # Val attribute
                                litmus = string.find(string.lower(currline),'val')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        val = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        val = "3"

                                prim.material = int(val)


                        elif string.find(slice[:4],'type') != -1:

                                # Type Tag

                                # Attributes:
                                # Val: Value for this variable

                                # Strip off tag name
                                currline = currline[4:]

                                # Val attribute
                                litmus = string.find(string.lower(currline),'val')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        val = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        val = "1"

                                prim.type = int(val)


                        elif string.find(slice[:10],'sculpttype') != -1:

                                # Sculpt Type Tag

                                # Attributes:
                                # Val: Value for this variable

                                # Strip off tag name
                                currline = currline[8:]

                                # Val attribute
                                litmus = string.find(string.lower(currline),'val')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        val = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        val = "1"

                                prim.sculpttype = int(val)


                        elif string.find(slice[:11],'sculptimage') != -1:

                                # Sculpt Image Tag

                                # Attributes:
                                # Val: Value for this variable

                                # Strip off tag name
                                currline = currline[8:]

                                # Val attribute
                                litmus = string.find(string.lower(currline),'val')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        val = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        val = ""

                                prim.sculptimage = val

                        elif string.find(slice[:11],'sculptfaces') != -1:

                                # Sculpt Faces
                                # Specify the face counts for a sculpty

                                # Attributes:
                                # X, Y, Z: Definitions for each value
                                # X, Y = Canonical face counts
                                # Z    = Depth of multires value 

                                # Strip off tag name
                                currline = currline[11:]

                                # X attribute
                                litmus = string.find(string.lower(currline),'x')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        x = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        x = "0.0"

                                # Y attribute
                                litmus = string.find(string.lower(currline),'y')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        y = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        y = "0.0"

                                # Z attribute
                                litmus = string.find(string.lower(currline),'z')
                                if litmus != -1:
                                        litmus = string.find(currline,'"', string.find(currline,'=', litmus))
                                        z = currline[litmus + 1:string.find(currline,'"',litmus + 1)]
                                else:
                                        z = "0.0"

                                prim.sculptfaces = (int(x),int(y),int(z))
                                

                        elif string.find(slice[:9],'textures') != -1:

                                # Textures tag
                                # Currently unsupported other than as a recognized convention.

                                # Add your own code here using the plentiful examples above
                                tags.append('textures')


                        elif string.find(slice[:7],'scripts') != -1:

                                # Scripts tag
                                # Currently unsupported other than as a recognized convention.

                                # Add your own code here using the plentiful examples above
                                tags.append('scripts')

        # Return to edit mode if present
        if in_editmode:
                Blender.Window.EditMode(1)
        Blender.Window.WaitCursor(0)



# M. llMirrorPrim
def MirrorPrim(id,axis,mesh):
        llMirrorPrim(id,axis,mesh)
def llMirrorPrim(id,axis,mesh):
        '''
        This function mirrors prim id along a given global axis.
        0 for X, 1 for Y, 2 for Z
        '''

        # Unset edit mode (required for mesh edits by script)
        editmode = 0
        if Blender.Window.EditMode():
                editmode = 1
        Blender.Window.EditMode(0)

        global mirrorframe
        if mirrorframe.val == 1:
                if axis == 0:
                        id.position = (id.position[0] * -1.0, id.position[1], id.position[2])
                elif axis == 1:
                        id.position = (id.position[0], id.position[1] * -1.0, id.position[2])
                elif axis == 2:
                        id.position = (id.position[0], id.position[1], id.position[2] * -1.0)

        id.cut = (1.0 - id.cut[1], 1.0 - id.cut[0], 0.0)
        id.twist = (id.twist[1],id.twist[0],0.0)
        id.taper = (id.taper[0] * -1.0, id.taper[1] * -1.0, 0.0)
        id.radiusoffset *= -1.0
        id.skew *= -1.0
        id.topshear = (id.topshear[0] * -1.0,id.topshear[1] * -1.0,0.0)
        id.topsize = ((-1.0 * (id.topsize[0] - 1.0)) + 1.0,(-1.0 * (id.topsize[1] - 1.0)) + 1.0,0.0)


        if id.type < 3:
                id.cut = (1.0 - id.cut[1], 1.0 - id.cut[0], 0.0)

        # Sculpt maps are mirrored without the requirement of a rotation change
        # @NewFeature: This has been changed to support Qarl's mirroring implementation

        if id.type != 7:
                if axis == 0:
                        id.rotation = (-1.0 * id.rotation[0], 180.0 - id.rotation[1], -1.0 * id.rotation[2])

                elif axis == 1:
                        id.rotation = (180.0 - id.rotation[0], id.rotation[1], -1.0 * id.rotation[2])

                elif axis == 2:
                        id.rotation = (180.0 - id.rotation[0], id.rotation[1] + 180.0, id.rotation[2] + 180.0)
        else:
                # In quaternion math, the rotation must be equal (but opposite) 
                # when a sculpty is mirrored on a given axis

                # Legacy code
                if axis == 0:
                        id.rotation = (id.rotation[0] + 180.0, id.rotation[1] + 180.0, 180.0 - id.rotation[2])
                
                elif axis == 1:
                        id.rotation = (-1.0 * id.rotation[0], id.rotation[1], -1.0 * id.rotation[2])
                                        
                elif axis == 2:
                        id.rotation = (180.0 - id.rotation[0], id.rotation[1] + 180.0, id.rotation[2] + 180.0)

                # This code is in preparation of Qarl's X mirror trick, which we implement in order to save
                # you, the humble user, even MORE L$ when uploading textures :D
                # This will be enabled when the feature is supported in SL 1.21
                '''
                if axis == 0:   # Works in 1.21
                        id.rotation = (id.rotation[0] + 180.0, id.rotation[1] + 180.0, 180.0 - id.rotation[2])
                
                elif axis == 1: # Works in 1.21
                        id.rotation = (id.rotation[0], id.rotation[1], 180.0 - id.rotation[2])
                                        
                elif axis == 2: # Does not work yet
                        id.rotation = (180.0 - id.rotation[0], id.rotation[1], id.rotation[2] + 180.0)
                '''

        selected = Blender.Object.GetSelected()
        if mesh.getType() == "Mesh":
                mesh.setLocation(id.position[0],id.position[1],id.position[2])
                mesh.setEuler([id.rotation[0] * PI / 180.0,id.rotation[1] * PI / 180.0, id.rotation[2] * PI / 180.0])
        

        # Sculpties are mirrored by inverting texture values and reloading the prim
        # This is significantly easier to implement than relying on mesh modifiers,
        # because the tris, normals, and map will all appear as expected

        if id.type == 7:
              
                # @NewFeature: Flip sculpty mirror mode
                id.sculptmirror = not id.sculptmirror

                # If this is a sculpted prim, save and mirror the sculpt image
                doFill = False
                doNorm = False
                time1 = Blender.sys.time()  #for timing purposes
                ob = Blender.Object.Get("Prim_" + id.UUID)
                meshscale = scaleRange( [ob], doNorm )
                updateSculptyMap( ob, id, None, meshscale, doFill)

                # @Limitation: This method, while as accurate as possible,
                # is lossy through multiple iterations of update_sculpty_from_map

                # Get image data and mirror in the desired direction
                # We will reload the sculpty after this operation is complete
                if axis >= 0 and axis <= 2:

                        # Load the sculptimage
                        image = Blender.Image.Get(id.sculptimage)

                        # Gather image data into a list
                        grid = []
                        for u in xrange( image.size[0] ):
                                vline = []
                                for v in xrange( image.size[1] ):
                                        vline.append(image.getPixelI(u, v))
                                grid.append(vline)

                        # Update the image with new data
                        for u in xrange( image.size[0] ):
                                for v in xrange( image.size[1] ):

                                        # Flip the image horizontally (effectively a normal invert)
                                        pixel = grid[u][image.size[1] - v - 1]
                                        
                                        # @NewFeature: Qarl will be implementing mirroring on X only. 
                                        #              Mirror images must then be rotated into place.
                                        #              This will be implemented after SL 1.21
                
                                        # Invert desired pixel value
                                        if axis == 0:
                                                pixel[0] = round(255.0 - pixel[0])

                                        if axis == 1:
                                                pixel[1] = round(255.0 - pixel[1])

                                        if axis == 2:
                                                pixel[2] = round(255.0 - pixel[2])

                                        # @Fix: Blender accidentally "floats" pixels in some cases
                                        pixel[0] = int(pixel[0])
                                        pixel[1] = int(pixel[1])
                                        pixel[2] = int(pixel[2])

                                        # Set the updated pixel into the image
                                        image.setPixelI(int(u), int(v), pixel)

                        # Reload the sculpty with the new map
                        update_sculpty_from_map( Blender.Mesh.Get(id.UUID), image, id.sculpttype )

                        Blender.Redraw()

                print 'finished mirroring: in %.4f sec.' % ((Blender.sys.time()-time1))

                # Reload the UI image after baking
                global sculptimage
                sculptimage.val = id.sculptimage
                return
        
        # Only perform a redraw if this isn't a sculpty!
        llDrawPrimMesh(id)

        # Reset edit mode if it was present
        if editmode:
                Blender.Window.EditMode(1)





# N. llNewPrim
def NewPrim(type,register,key = None):
        if key:
                llNewPrim(type,register,key)
        else:
                llNewPrim(type,register)
def llNewPrim(type,register,key = None):
        '''
        This function creates a new prim in our existing memory buffer
        '''

        prim = Primitive()
        if key:
                # print key
                pass
        else:
                key = internalKey(register)

        cursor = GetCursorPos()

        # Create a new display mesh and its mesh data
        mesh = Blender.Mesh.New(key)
        scene = Blender.Scene.GetCurrent()
        ob = scene.objects.new( mesh, "Prim_" + key )
        #ob = Blender.Object.Get("Prim_" + key)
        ob.setLocation( Blender.Window.GetCursorPos() )

        prim.UUID = key
        prim.levelofdetail = 3
        prim.position = (cursor[0],cursor[1],cursor[2])

        if type > 7:
                prim.rotation = (0.0,90.0,0.0)

        if type == 0:
                prim.type = PRIM_TYPE_BOX
        if type == 1:
                prim.type = PRIM_TYPE_BOX
                prim.topsize = (0.0,1.0,0.0)
                prim.topshear = (-0.5,0.0,0.0)
        if type == 2:
                prim.type = PRIM_TYPE_BOX
                prim.topsize = (0.0,0.0,0.0)
        if type == 3:
                prim.type = PRIM_TYPE_PRISM
                prim.topsize = (0.0,0.0,0.0)
        if type == 4:
                prim.type = PRIM_TYPE_CYLINDER
        if type == 5:
                prim.type = PRIM_TYPE_CYLINDER
                prim.cut = (0.25,0.75,0.0)
        if type == 6:
                prim.type = PRIM_TYPE_CYLINDER
                prim.topsize = (0.0,0.0,0.0)
        if type == 7:
                prim.type = PRIM_TYPE_CYLINDER
                prim.cut = (0.25,0.75,0.0)
                prim.topsize = (0.0,0.0,0.0)
        if type == 8:
                prim.type = PRIM_TYPE_SPHERE
        if type == 9:
                prim.type = PRIM_TYPE_SPHERE
                prim.cut = (0.0,0.5,0.0)
                prim.rotation = (0.0,0.0,0.0)
        if type == 10:
                prim.type = PRIM_TYPE_TORUS
                prim.holesize = (1.0,0.25,0.0)
        if type == 11:
                prim.type = PRIM_TYPE_TUBE
                prim.holesize = (1.0,0.25,0.0)
        if type == 12:
                prim.type = PRIM_TYPE_RING
                prim.holesize = (1.0,0.25,0.0)

        # Unselect all objects and select the current one
        scene = Blender.Scene.GetCurrent()
        for obj in scene.objects:
                obj.select(0)
        
        # Select the new prim
        ob.select(1)

        llParams2Buffer(prim)
        register.add(prim)
        llDrawPrimMesh(prim)

        ob.setLocation(prim.position[0],prim.position[1],prim.position[2])
        ob.setEuler([prim.rotation[0] * PI / 180.0,prim.rotation[1] * PI / 180.0, prim.rotation[2] * PI / 180.0])
        llParamSelected2Prim(PrimHolder)
        return prim



# i.   internalKey
def internalKey(register):
        # Returns an internal (script-specific) key value for sorting prims
        random.randint(0,1) # Prevents repeats...
        key = 'Num_' + str(random.randint(0,999999999))
        while register.primDict.has_key(key):
                random.randint(0,1)
                key = 'Num_' + str(random.randint(0,999999999))

        return key





# O. llParams2Buffer
def Params2Buffer(id):
        llParams2Buffer(id)
def llParams2Buffer(id):
        '''
        Copies params of prim id to GUI buffer
        '''
        name.val = id.name
        posx.val = id.position[0]
        posy.val = id.position[1]
        posz.val = id.position[2]
        rotx.val = id.rotation[0]
        roty.val = id.rotation[1]
        rotz.val = id.rotation[2]
        sizex.val = id.size[0]
        sizey.val = id.size[1]
        sizez.val = id.size[2]
        cutx.val = id.cut[0]
        cuty.val = id.cut[1]
        dimplex.val = id.dimple[0]
        dimpley.val = id.dimple[1]
        advancedcutx.val = id.advancedcut[0]
        advancedcuty.val = id.advancedcut[1]
        hollow.val = id.hollow
        twistx.val = id.twist[0]
        twisty.val = id.twist[1]
        # Change things since real value is not that expressed in actual params...
        topsizex.val = -1.0 * (id.topsize[0] - 1.0)
        topsizey.val = -1.0 * (id.topsize[1] - 1.0)
        holesizex.val = id.holesize[0]
        holesizey.val = id.holesize[1]
        topshearx.val = id.topshear[0]
        topsheary.val = id.topshear[1]
        taperx.val = id.taper[0]
        tapery.val = id.taper[1]
        revolutions.val = id.revolutions
        radiusoffset.val = id.radiusoffset
        skew.val = id.skew
        primType.val = id.type
        material.val = id.material
        hollowshape.val = id.hollowshape
        physics.val = id.physics
        temponrez.val = id.temponrez
        phantom.val = id.phantom
        levelofdetail.val = id.levelofdetail
        sculpttype.val = id.sculpttype
        sculptimage.val = id.sculptimage
        sculptfacesx.val = id.sculptfaces[0]
        sculptfacesy.val = id.sculptfaces[1]
        sculptmultires.val = id.sculptfaces[2]




# P. llParamSelected2Prim
def ParamSelected2Prim(register):
        llParamSelected2Prim(register)
def llParamSelected2Prim(register):
        '''
        This time, we yoink position, rotation, etc. from selectedparams import 
        stuff them into our prim to update. Yay!

        Stores prim back to given registry
        '''
        selected = Blender.Object.GetSelected()
        selectedlen = len(selected)
        if len(selected) > 0:
                for i in range(0,selectedlen):
                        if selected[i].getType() == "Mesh":
                                key = selected[i].getData(1)
                                id = register.get(key)
                                if id.UUID == "-1":
                                        return
                                #register.remove(key)
                                id.position = selected[i].getLocation()
                                temp = selected[i].getEuler()
                                x = temp[0] * 180.0 / PI
                                y = temp[1] * 180.0 / PI
                                z = temp[2] * 180.0 / PI
                                del temp

                                # Format the variable so we're in-bounds...
                                while x < 0.0:
                                        x += 360.0
                                while x >= 360.0:
                                        x -= 360.0

                                while y < 0.0:
                                        y += 360.0
                                while y >= 360.0:
                                        y -= 360.0

                                while z < 0.0:
                                        z += 360.0
                                while z >= 360.0:
                                        z -= 360.0
                                id.rotation = (x,y,z)

                                temp = selected[i].getSize()
                                x = 0.0
                                y = 0.0
                                z = 0.0

                                # Blender size is used for Sculpt Meshes ONLY (should be one unit otherwise;
                                # we do this to preserve the mesh between scaling)
                                if id.type != 7:
                                        x = abs(id.size[0] * temp[0])
                                        y = abs(id.size[1] * temp[1])
                                        z = abs(id.size[2] * temp[2])
                                        selected[i].setSize(1.0,1.0,1.0)
                                else:
                                        # Because scaling is only accessible on one or three axes in Blender,
                                        # we make a check to see if uniform or axis scaling went into the negative
                                        # This is automatically corrected for when exporting, despite our warnings.

                                        x = abs(temp[0])
                                        y = abs(temp[1])
                                        z = abs(temp[2])
                                        # @Fix: Move setSize to after x/y/z changes are accounted for
                                        
                                        if (temp[0] * temp[1] * temp[2] < 0):
                                                llDialog("Warning: Prim has negative scaling values. This has been corrected.")
                                                


                                if x > 10.0:
                                        llDialog("Warning: Updating prim with X scale > 10 meters. Throttling to Second Life maximum.")
                                        x = 10.0
                                elif x < 0.01:
                                        llDialog("Warning: Updating prim with X scale < 0.01 meters. Throttling to Second Life minimum.")
                                        x = 0.01

                                if y > 10.0:
                                        llDialog("Warning: Updating prim with Y scale > 10 meters. Throttling to Second Life maximum.")
                                        y = 10.0
                                elif y < 0.01:
                                        llDialog("Warning: Updating prim with Y scale < 0.01 meters. Throttling to Second Life minimum.")
                                        y = 0.01

                                if z > 10.0:
                                        llDialog("Warning: Updating prim with Z scale > 10 meters. Throttling to Second Life maximum.")
                                        z = 10.0
                                elif z < 0.01:
                                        llDialog("Warning: Updating prim with Z scale < 0.01 meters. Throttling to Second Life minimum.")
                                        z = 0.01

                                id.size = (x,y,z)
                                if id.type != 7:
                                        llDrawPrimMesh(id)
                                else:
                                        selected[i].setSize(x,y,z)
                                        Blender.Redraw()

                llDrawConsole(0)





# Q. llRedrawPrim (Deprecated)
def RedrawPrim(prim,UUID,name):
        llRedrawPrim(prim,UUID,name)
def llRedrawPrim(prim,UUID,name):
        ''' 
        This function parses the data into the final mesh and calls a redraw.
        '''
        #scene = Blender.Scene.GetCurrent()
        #try:
        #        obj.scene.link(Blender.Object.Get("Prim_" + UUID))
        #except:
        #        llDialog("Error: Could not link prim to current scene.")
        Blender.Redraw()
        #prim.removeAllKeys()





# R. llSavePrims  
def SavePrims(filename):
        llSavePrims(filename)
def llSavePrims(filename):
        '''
        This function writes prims in the current registry to a file
        '''
        if os.path.isdir(filename):
                llDialog("Please specify a valid .prims output location (directory was given)")
                return

        # Remove prims that do not have meshes (ie. that we've deleted)
        PrimHolder.removeGhosts()

        # Sync prims in case loop didn't catch any changes
        PrimHolder.sync()

        # Dictionary of sculpt hashes (used to cull duplicate images)
        sculpthashes = {}

        file = open(filename,'w')
        file.write('<primitives>\r\n')
        regSize = len(PrimHolder.primList)
        Blender.Window.WaitCursor(1)
        for i in range(0,regSize):
                # Get our current primitive
                id = PrimHolder.primList[i]
                
                if id:
                        # Get our quaternion. Because blender uses a different Euler system,
                        # we take an absolute quaternion for use in Second Life.
                        tempRot = Euler(id.rotation[0],id.rotation[1],id.rotation[2]).toQuat()

                        # Initial header tag
                        file.write('<primitive name="' + id.name + '" description="' + id.description + '" key="' + str(id.UUID) + '" version="3">\r\n\r\n')

                        # States
                        file.write('<states>\r\n')
                        file.write('<physics params="">')
                        if id.physics:
                                file.write('TRUE')
                        else:
                                file.write('FALSE')
                        file.write('</physics>\r\n')

                        file.write('<temporary params="">')
                        if id.temponrez:
                                file.write('TRUE')
                        else:
                                file.write('FALSE')
                        file.write('</temporary>\r\n')

                        file.write('<phantom params="">')
                        if id.phantom:
                                file.write('TRUE')
                        else:
                                file.write('FALSE')
                        file.write('</phantom>\r\n')
                        file.write('</states>\r\n\r\n')

                        # Properties
                        file.write('<properties>\r\n')
                        file.write('<type val="' + str(id.type) + '" />\r\n')
                        if id.type == 7:

                                # Force the sculptimage name to its UUID (fixes several save bugs)
                                id.sculptimage = id.UUID + ".tga"

                                # If this is a sculpted prim, bake the sculpt images out to disk
                                # We also write these properties out after generating them
                                doFill = False
                                doNorm = False
                                time1 = Blender.sys.time()  #for timing purposes
                                ob = Blender.Object.Get("Prim_" + id.UUID)
                                meshscale = scaleRange( [ob], doNorm )
                                if meshscale.minx == None:
                                        Blender.Draw.PupBlock( "Sculptie Bake Error", ["No objects selected"] )

                                # @Fix: Bake twice when saving, to capture any possible mesh changes
                                updateSculptyMap( ob, id, None, meshscale, doFill )
                                meshscale = scaleRange( [ob], doNorm )
                                updateSculptyMap( ob, id, string.rsplit(string.rsplit(filename,'/',1)[0],'\\',1)[0], meshscale, doFill )

                                print 'finished baking: in %.4f sec.' % ((Blender.sys.time()-time1))

                                # Write out sculpty type
                                file.write('<sculpttype val="' + str(id.sculpttype) + '" />\r\n')

                                # Image culling: Combines duplicate images to lower number of required images
                                print id.sculptimage,": ",id.sculpthash
                                if sculpthashes.has_key(id.sculpthash):
                                        # If the hash is already in our dictionary, we cull the duplicate by
                                        # using the same image for this prim.
                                        print "Culling ",id.sculptimage,"with hash",id.sculpthash
                                        id.sculptimage = sculpthashes[id.sculpthash]
                                else:
                                        # If the hash differs, add it to our list and save to disk
                                        sculpthashes[id.sculpthash] = id.sculptimage

                                        # Attempt to save out the image to disk. If we fail, inform the user
                                        try:
                                                image = Blender.Image.Get(id.sculptimage)
                                                image.save()
                                        except:
                                                llDialog("Could not save sculpt image %s to disk. You will need to do this manually.") % image.name


                                # Image name is relative to the location of this object's .prims file
                                # Currently, this MUST be located in the same directory.
                                file.write('<sculptimage val="' + str(id.sculptimage) + '" />\r\n')

                                # Write faces and multires value
                                file.write('<sculptfaces x="' + str(id.sculptfaces[0]) + '" y="' + str(id.sculptfaces[1]) + '" z="' + str(id.sculptfaces[2]) + '" />\r\n')

                        file.write('<levelofdetail val="' + str(id.levelofdetail) + '" />\r\n')
                        file.write('<position x="' + str(id.position[0]) + '" y="' + str(id.position[1]) + '" z="' + str(id.position[2]) + '" />\r\n')
                        file.write('<rotation x="' + str(tempRot[1]) + '" y="' + str(tempRot[2]) + '" z="' + str(tempRot[3]) + '" s="' + str(tempRot[0]) + '" />\r\n')
                        file.write('<size x="' + str(id.size[0]) + '" y="' + str(id.size[1]) + '" z="' + str(id.size[2]) + '" />\r\n')
                        file.write('<cut x="' + str(id.cut[0]) + '" y="' + str(id.cut[1]) + '" />\r\n')
                        file.write('<dimple x="' + str(id.dimple[0]) + '" y="' + str(id.dimple[1]) + '" />\r\n')
                        file.write('<advancedcut x="' + str(id.advancedcut[0]) + '" y="' + str(id.advancedcut[1]) + '" />\r\n')
                        file.write('<hollow val="' + str(id.hollow) + '" />\r\n')
                        file.write('<twist x="' + str(id.twist[0]) + '" y="' + str(id.twist[1]) + '" />\r\n')
                        file.write('<topsize x="' + str(id.topsize[0]) + '" y="' + str(id.topsize[1]) + '" />\r\n')
                        file.write('<holesize x="' + str(id.holesize[0]) + '" y="' + str(id.holesize[1]) + '" />\r\n')
                        file.write('<topshear x="' + str(id.topshear[0]) + '" y="' + str(id.topshear[1]) + '" />\r\n')
                        file.write('<taper x="' + str(id.taper[0]) + '" y="' + str(id.taper[1]) + '" />\r\n')
                        file.write('<revolutions val="' + str(id.revolutions) + '" />\r\n')
                        file.write('<radiusoffset val="' + str(id.radiusoffset) + '" />\r\n')
                        file.write('<skew val="' + str(id.skew) + '" />\r\n')
                        file.write('<material val="' + str(id.material) + '" />\r\n')
                        file.write('<hollowshape val="' + str(id.hollowshape) + '" />\r\n\r\n')

                        file.write('<textures params="">\r\n</textures>\r\n\r\n')

                        file.write('<scripts params="">\r\n</scripts>\r\n\r\n')

                        file.write('</properties>\r\n\r\n')

                        file.write('</primitive>\r\n')

                
        file.write('</primitives>\r\n')
        file.close()
        Blender.Window.WaitCursor(0)




# S. llSculptMesh
def SculptMesh(id, mesh):
        llSculptMesh(id, mesh)
def llSculptMesh(id, mesh):
        # Make sure this mesh is linked to this Prim's information
        obj = Blender.Object.Get("Prim_" + id.UUID)
        obj.link(mesh)

        # Change the LOD to 3 when we create a new sculpt shape
        id.levelofdetail = 3
        #levelofdetail.val = 3

        # Create the sculpt mesh
        return new_sculpty(id, mesh,faces_x = id.sculptfaces[0],faces_y = id.sculptfaces[1],multires = id.sculptfaces[2])





# T. llSetPrimitiveParams
def SetPrimitiveParams(id,params):
        llSetPrimitiveParams(id,params)
def llSetPrimitiveParams(id,params):
        '''
        This function expressly emulates the llSetPrimitiveParams function found
        within Second Life, is made to conform with SciTE-EZ, and overall reduce 
        the learning curve of this code.

        It is worth note, however, that some options may slightly differ from  import 
        the in-world function in early versions of this tool. These differences
        will be commented and may print warnings when deemed necessary.

        Though frankly, you should just use the internal class methods.

        This function is also currently UNTESTED. USE AT OWN RISK.
        '''
        count = len(params)
        for i in range(0,count):
                step = params[i]
                if step == 9:
                        ++i
                        step = params[i]
                        if step < 3 and step > -1:
                                # PRIM_TYPE_BOX
                                '''
                                integer hollowshape, vector cut, float hollow, vector twist, 
                                vector topsize, vector topshear
                                '''
                                if len(params) - i > 5:
                                        id.hollowshape = params[++i]
                                        id.cut = params[++i]
                                        id.hollow = params[++i]
                                        id.twist = params[++i]
                                        id.topsize = params[++i]
                                        id.topshear = params[++i]
                                else:
                                        if step == PRIM_TYPE_BOX:
                                                llDialog("Error: Invalid number of arguments given in llSetPrimitiveParams at param # %(placeholder)s for PRIM_TYPE_BOX. Please try again.") % {'placeholder': i}

                                        elif step == PRIM_TYPE_CYLINDER:
                                                llDialog("Error: Invalid number of arguments given in llSetPrimitiveParams at param # %(placeholder)s for PRIM_TYPE_CYLINDER. Please try again.") % {'placeholder': i}

                                        elif step == PRIM_TYPE_PRISM:
                                                llDialog("Error: Invalid number of arguments given in llSetPrimitiveParams at param # %(placeholder)s for PRIM_TYPE_PRISM. Please try again.") % {'placeholder': i}
                                        return

                        elif step == 3:
                                # PRIM_TYPE_SPHERE
                                '''
                                integer hollowshape, vector cut, float hollow, vector twist, 
                                vector dimple
                                '''
                                if len(params) - i > 4:
                                        id.hollowshape = params[++i]
                                        id.cut = params[++i]
                                        id.hollow = params[++i]
                                        id.twist = params[++i]
                                        id.dimple = params[++i]
                                else:
                                        llDialog("Error: Invalid number of arguments given in llSetPrimitiveParams at param # %(placeholder)s for PRIM_TYPE_SPHERE. Please try again.") % {'placeholder': i}
                                        return

                        elif step > 3 and step < 7:
                                # PRIM_TYPE_TORUS, PRIM_TYPE_TUBE, and PRIM_TYPE_RING
                                '''
                                integer hollowshape, vector cut, float hollow, vector twist, 
                                vector holesize, vector topshear, vector advancedcut, 
                                vector taper, float revolutions, float radiusoffset, float skew
                                '''
                                if len(params) - i > 5:
                                        id.hollowshape = params[++i]
                                        id.cut = params[++i]
                                        id.hollow = params[++i]
                                        id.twist = params[++i]
                                        id.holesize = params[++i]
                                        id.topshear = params[++i]
                                        id.advancedcut = params[++i]
                                        id.taper = params[++i]
                                        id.revolutions = params[++i]
                                        id.radiusoffset = params[++i]
                                        id.skew = params[++i]
                                else:
                                        if step == PRIM_TYPE_TUBE:
                                                llDialog("Error: Invalid number of arguments given in llSetPrimitiveParams at param # %(placeholder)s for PRIM_TYPE_TUBE. Please try again.") % {'placeholder': i}

                                        elif step == PRIM_TYPE_TORUS:
                                                llDialog("Error: Invalid number of arguments given in llSetPrimitiveParams at param # %(placeholder)s for PRIM_TYPE_TORUS. Please try again.") % {'placeholder': i}

                                        elif step == PRIM_TYPE_RING:
                                                llDialog("Error: Invalid number of arguments given in llSetPrimitiveParams at param # %(placeholder)s for PRIM_TYPE_RING. Please try again.") % {'placeholder': i}
                                        return
                        elif step == 7:
                                # PRIM_TYPE_SCULPT
                                '''
                                string map, integer type
                                '''
                                id.sculpttype = params[++i]
                                id.sculptimage = params[++i]
                        else:
                                llDialog("Error: Unknown Rule at param # %(placeholder)s in llSetPrimitiveParams. Expected a PRIM_TYPE constant (eg. PRIM_TYPE_BOX). Please try again.") % {'placeholder': i}
                                return

                elif step == 2:
                        # PRIM_MATERIAL
                        id.material = params[++i]

                elif step == 3:
                        # PRIM_PHYSICS
                        id.physics = params[++i]

                elif step == 4:
                        # PRIM_TEMP_ON_REZ
                        id.temponrez = params[++i]

                elif step == 5:
                        # PRIM_PHANTOM
                        id.phantom = params[++i]

                elif step == 6:
                        # PRIM_POSITION
                        id.position = params[++i]

                elif step == 7:
                        # PRIM_SIZE
                        id.size = params[++i]

                elif step == 8:
                        # PRIM_ROTATION
                        ++i
                        tempRot = Quaternion(params[i][1],params[i][2],params[i][3],params[i][0]).toEuler()
                        id.rotation = (tempRot[0],tempRot[1],tempRot[2])

                elif step == 17:
                        # PRIM_TEXTURE
                        llDialog("Warning: PRIM_TEXTURE is currently NOT supported!")
                        i += 5

                elif step == 18:
                        # PRIM_COLOR
                        llDialog("Warning: PRIM_COLOR is currently NOT supported!")
                        i += 2

                elif step == 19:
                        # PRIM_BUMP_SHINY
                        llDialog("Warning: PRIM_BUMP_SHINY is currently NOT supported!")
                        i += 2

                elif step == 20:
                        # PRIM_FULLBRIGHT
                        llDialog("Warning: PRIM_FULLBRIGHT is currently NOT supported!")
                        ++i

                elif step == 21:
                        # PRIM_FLEXIBLE
                        llDialog("Warning: PRIM_FLEXIBLE is currently NOT supported!")
                        i += 7

                elif step == 22:
                        # PRIM_TEXGEN
                        llDialog("Warning: PRIM_TEXGEN is currently NOT supported!")
                        i += 2

                elif step == 23:
                        # PRIM_POINT_LIGHT
                        llDialog("Warning: PRIM_POINT_LIGHT is currently NOT supported!")
                        i += 5



# U. Sculpt Functions by Domino Marama
# These functions were originally written by Domino Marama as stand alones for Blender's toolchain.
# These have been preserved for the most part; the calls through them have been modified to suit
# the Prim.Blender UI, as well as copying and mirroring.

# i.   Compatibility for previous versions of Python
if version_info[0] == 2 and version_info[1] < 4:
        # sorted function for python 2.3
        def sorted(seq):
            newseq = seq[:]
            newseq.sort()
            return newseq


# ii.  update_sculpty_from_map
# Name is preserved from Domino's scripts; updates a sculpt map from an image file
def update_sculpty_from_map(mesh, image, sculpt_type):
        wrap_x = ( sculpt_type != PLANE )
        wrap_y = ( sculpt_type == TORUS )
        verts = range( len( mesh.verts ) )
        for f in mesh.faces:
                for vi in xrange( 4 ):
                        if f.verts[ vi ].index in verts:
                                verts.remove( f.verts[ vi ].index )
                                u, v = f.uv[ vi ]
                                u = int( u * image.size[0])
                                v = int( v * image.size[1])
                                if u == image.size[0]:
                                        if wrap_x:
                                                u = 0
                                        else:
                                                u = image.size[0] - 1
                                if v == 0:
                                        if ( sculpt_type == SPHERE ):
                                                u = image.size[0] / 2
                                if v == image.size[1]:
                                        if wrap_y:
                                                v = 0
                                        else:
                                                v = image.size[1] - 1
                                                if ( sculpt_type == SPHERE ):
                                                        u = image.size[0] / 2
                                p  = image.getPixelF( u, v )
                                f.verts[ vi ].co = Blender.Mathutils.Vector(( p[0] - 0.5),
                                                (p[1] - 0.5),
                                                (p[2] - 0.5))
        mesh.update()
        mesh.sel = True
        mesh.recalcNormals( 0 )


# iii. default_sculpty
# Name is preserved from Domino's scripts; generates a default sculpted prim
def default_sculpty( mesh, sculpty_type, holesize ):
        verts = range( len( mesh.verts ) )
        halfpi = pi * 0.5
        twopi = pi * 2.0
        for f in mesh.faces:
                for vi in xrange( 4 ):
                        if f.verts[ vi ].index in verts:
                                verts.remove( f.verts[ vi ].index )
                                u, v = f.uv[ vi ]
                                if sculpty_type == PLANE:
                                        f.verts[ vi ].co = Blender.Mathutils.Vector( u - 0.5, v -0.5, 0.0 )

                                elif sculpty_type == CYLINDER:
                                        a = pi + twopi * u
                                        f.verts[ vi ].co = Blender.Mathutils.Vector( cos( a )/2.0,
                                                                                sin( a )/2.0,
                                                                                v - 0.5 )
                                elif sculpty_type == SPHERE:
                                        a = pi + twopi * u
                                        s = sin( pi * v ) / 2.0
                                        f.verts[ vi ].co = Blender.Mathutils.Vector( cos( a ) * s,
                                                                                sin( a ) * s,
                                                                                -cos( pi * v ) / 2.0 )

                                elif sculpty_type == TORUS:
                                        a = pi + twopi * u
                                        s = (( 1.0 - holesize[1] ) - sin( 2.0 * pi * v) * holesize[1]) / 2.0
                                        f.verts[ vi ].co = Blender.Mathutils.Vector( cos( a ) * s,
                                                                                sin( a ) * s,
                                                                                cos( twopi * v ) / 2.0 * holesize[0] )

        mesh.update()
        mesh.sel = True
        mesh.recalcNormals( 0 )


# iv.  new_sculpty
# Name is preserved from Domino's scripts; generates a new sculpty (which calls through default_sculpty above)
# Notes: Altered this somewhat to support Prim.Blender mesh wrangling. Fixed a typo or two, too. :)
def new_sculpty( prim, mesh, faces_x=FACES_X, faces_y=FACES_Y, multires=2):
        if not prim or not mesh:
                print "new_sculpty: Silent fail: No mesh for this object"
                return

        Blender.Window.WaitCursor(1)

        if multires and 'addMultiresLevel' not in dir( mesh ):
                print "Warning: this version of Blender does not support addMultiresLevel, get a later build from http://www.blender.org/ (2.46+), http://www.graphicall.org, or your favorite package manager for full functionality"
                for i in range(multires):
                        faces_x *= 2
                        faces_y *= 2
                multires = 0
                mesh = generate_base_mesh(mesh, prim.sculpttype, faces_x + 1, faces_y + 1 )
        else:
                pass
                mesh = generate_base_mesh(mesh, prim.sculpttype, faces_x + 1, faces_y + 1 )
        
        mesh.flipNormals()
        
        if multires and not mesh.multires:
                mesh.multires = True
                mesh.addMultiresLevel( multires,'simple' )
        else:
                mesh.multires = False
        
        default_sculpty(mesh, prim.sculpttype, prim.holesize) # Get Y value of Holesize

        # @Fix: Removed a portion of Domino's code here that attempts to set the facing of a new sculpty
        # Due to "ob" being defined outside of this function's scope, it was causing a series of issues
        # with the "setMatrix" command, and has been entirely removed.

        Blender.Window.WaitCursor(0)
        return mesh


# v.   generate_base_mesh
# Name is preserved from Domino's scripts; generates the base mesh for a sculpty (also called through from above)
# Notes: Removed new object creation in generate_base_mesh to support prims
def generate_base_mesh(mesh, sculpt_type, verts_x, verts_y ):
        uv = []
        verts = []
        faces = []
        wrap_x = ( sculpt_type != PLANE )
        wrap_y = ( sculpt_type == TORUS )
        actual_x = verts_x - wrap_x
        actual_y = verts_y - wrap_y
        uvgrid_y = []
        uvgrid_x = []
        for x in xrange( verts_x ):
                uvgrid_x.append( float( x ) / ( verts_x - 1 ) )
        for y in xrange( verts_y ):
                uvgrid_y.append( float( y ) / ( verts_y - 1 ) )
        for y in xrange( actual_y ):
                for x in xrange( actual_x ):
                        mesh.verts.extend([ ( 0.0, 0.0, 0.0 )])
                        verts.append( mesh.verts[-1] )
                if wrap_x:
                        verts.append( mesh.verts[ -actual_x ] )
        if wrap_y:
                verts.extend( verts[:verts_x] )
        for y in xrange( verts_y - 1 ):
                offset_y = y * verts_x
                for x in xrange( verts_x - 1 ):
                        faces.append( ( verts[offset_y + x], verts[offset_y + verts_x + x],
                                        verts[offset_y + verts_x + x + 1], verts[offset_y + x + 1] ) )
                        if wrap_x and x == actual_x - 1 and (y == 0 or y == actual_y -1):

                                # Blender auto alters vert order - correct uv to match
                                uv.append( ( Blender.Mathutils.Vector( uvgrid_x[ x + 1 ], uvgrid_y[ y + 1 ] ),
                                        Blender.Mathutils.Vector( uvgrid_x[ x + 1 ], uvgrid_y[ y ] ),
                                        Blender.Mathutils.Vector( uvgrid_x[ x ], uvgrid_y[ y ] ),
                                        Blender.Mathutils.Vector( uvgrid_x[ x ], uvgrid_y[ y + 1 ] ) ) )
                        else:
                                uv.append( ( Blender.Mathutils.Vector( uvgrid_x[ x ], uvgrid_y[ y ] ),
                                        Blender.Mathutils.Vector( uvgrid_x[ x ], uvgrid_y[ y + 1 ] ),
                                        Blender.Mathutils.Vector( uvgrid_x[ x + 1 ], uvgrid_y[ y + 1 ] ),
                                        Blender.Mathutils.Vector( uvgrid_x[ x + 1 ], uvgrid_y[ y ] ) ) )
        mesh.faces.extend( faces )
        mesh.faceUV = True 
        for f in xrange( len(mesh.faces) ):
                mesh.faces[ f ].uv = uv[ f ]
                mesh.faces[ f ].smooth = True # By default, make this mesh's faces appear smooth
        return mesh  


# vi.  load_sculpty
# Name is preserved from Domino's scripts; loads a sculpt map from an image file
def load_sculpty( prim, imagefile ):
        
        if prim and imagefile and imagefile != "":
                try:
                        image = Blender.Image.Load( imagefile )
                except:
                        llDialog("Image loading %s failed. Using default sculpty." % imagefile)

                # This block has been removed as we now blow away sculpt maps
                # Since we rely on saving to disk more than we do the editor,
                # this is less of a problem
                #if image.fakeUser:
                # Already imported make new one.. where's make single user?
                #        result = Blender.Draw.PupMenu( "Image " + image.name + " already exists. Create duplicate?%t|Yes|No")
                #        if result == 1:
                #                image2 = Blender.Image.New( ob.name.replace("Prim_","") + ".tga", image.size[0], image.size[1], image.depth )
                #                for cx in xrange( image.size[0] ):
                #                        for cy in xrange( image.size[1] ):
                #                                image2.setPixelF( cx, cy, image.getPixelF( cx, cy ))
                #                image = image2

                image.fakeUser = True
                image.name = prim.UUID + ".tga"
                try:
                        prim.sculptimage = image.name   # Grab the image name
                except:
                        try:
                                image = Blender.Image.Get(image.name)
                                image.setFilename(imagefile)
                                image.reload()
                        except:
                                llDialog("Error: Could not load image.");

                # Update the mesh for sculpt data
                mesh = Blender.Mesh.Get(prim.UUID)
                update_sculpty_from_map( mesh, image, prim.sculpttype )

                # Make sure mesh data is linked (annoying that we must do this every time)
                obj = Blender.Object.Get("Prim_" + prim.UUID)
                if obj:
                        obj.link(mesh)

                        # Make SURE we have multires data for this mesh
                        if mesh:
                                if mesh.multires:

                                        # ASSERT: For sculpties, level of detail must be <= multiresDrawLevel
                                        if prim.levelofdetail > prim.sculptfaces[2]:
                                                prim.levelofdetail = prim.sculptfaces[2] + 1

                                        # ASSERT: Disable multires if value == 0
                                        if prim.sculptfaces[2] == 0:
                                                mesh.multires = False

                                        # Set multires draw level
                                        mesh.multiresDrawLevel = prim.levelofdetail

                                # Set the correct mesh scaling
                                obj.setSize(prim.size[0],prim.size[1],prim.size[2])
                        else:
                                llDialog("Warning: Could not find object associated with this mesh.")


# vii. load_sculpty_from_callback
# Not part of Domino's API, but added as an extension; used to load a sculpty from a FileSelector callback
def load_sculpty_from_callback(filename):
        selected = Blender.Object.GetSelected()
        llParamSelected2Prim(PrimHolder)
        if len(selected) > 0 and selected[0].getType() == "Mesh":
                load_sculpty(PrimHolder.get(selected[0].getData(1)),filename)
                llParams2Buffer(PrimHolder.get(selected[0].getData(1)))
                
        llDrawConsole(0)
        

# viii.drawTri
# Name is preserved from Domino's scripts; draw a tri to an image file
def drawTri( image, verts ):
        scanlines = [ verts[0] ]
        if int(verts[0].x) != int(verts[1].x):
                scanlines.extend( [ verts[0] ])
                if int(verts[1].x) == int(verts[2].x):
                        scanlines.extend( [ verts[1], verts[2] ] )
                else:
                        n = verts[0] + (( verts[2] - verts[0] ) * (( verts[1].x - verts[0].x ) / ( verts[2].x - verts[0].x )))
                        if verts[1].y < verts[2].y:
                                scanlines.extend( [ verts[1], n, verts[1], n, verts[2], verts[2] ] )
                        else:
                                scanlines.extend( [ n, verts[1], n, verts[1], verts[2], verts[2] ] )
        else:
                scanlines.extend( [ verts[1], verts[2], verts[2] ] )
        while scanlines:
                s1 = scanlines[ 0 ]
                s2 = scanlines[ 1 ]
                e1 = scanlines[ 2 ]
                e2 = scanlines[ 3 ]
                scanlines = scanlines[4:]
                r1 = e1 - s1
                r2 = e2 - s2
                x = float(int(s1.x))
                ex = float(int(e1.x))
                while x <= ex and x <= image.size[0]:
                        s = ( x - s1.x ) / r1.x
                        if s < 0.0:
                                x += 1.0
                                continue

                        drawVLine( image, int(x),
                                int( s1.y + r1.y * s ),
                                int( s2.y + r2.y * s ),
                                s1.r + r1.r * s,
                                s1.g + r1.g * s,
                                s1.b + r1.b * s,
                                s2.r + r2.r * s,
                                s2.g + r2.g * s,
                                s2.b + r2.b * s
                        )
                        x += 1.0


# ix.  drawHLine
# Name is preserved from Domino's scripts; draw a horizontal scanline

# This function isn't called, since the only callthrough (via fill functions)
# are not used in Prim.Blender
def drawHLine( image, y, s, e, sr, sg, sb, er, eg, eb ):
        if s - e == 0:
                image.setPixelF( s, y, ( sr, sg, sb, 1.0 ) )
                return

        dr = ( er - sr ) / ( e - s )
        dg = ( eg - sg ) / ( e - s )
        db = ( eb - sb ) / ( e - s )
        for u in xrange( s, e + 1 ):
                image.setPixelF( u, y, ( sr, sg, sb, 1.0 ) )
                sr += dr
                sg += dg
                sb += db
                if sr < 0:
                        sr = 0
                if sg < 0:
                        sg = 0
                if sb < 0:
                        sb = 0
                if sr > 1.0:
                        sr = 1.0
                if sg > 1.0:
                        sg = 1.0
                if sb > 1.0:
                        sb = 1.0

                


# x.   drawVLine
# Name is preserved from Domino's scripts; draw a vertical scanline
def drawVLine( image, x, s, e, sr, sg, sb, er, eg, eb ):
        if x < 0 or s < 0 or x > image.size[0] or e > image.size[1]:
                raise ValueError
        if x == image.size[0]:
                x -= 1
        if s - e == 0:
                if s == image.size[1]:
                        s -= 1
                image.setPixelF( x, s, ( sr, sg, sb, 1.0 ) )
                return

        dr = ( er - sr ) / ( e - s )
        dg = ( eg - sg ) / ( e - s )
        db = ( eb - sb ) / ( e - s )
        for v in xrange( s, e + 1 ):
                if v == image.size[1]:
                        image.setPixelF( x, v - 1, ( sr, sg, sb, 1.0 ) )
                else:
                        image.setPixelF( x, v, ( sr, sg, sb, 1.0 ) )
                sr += dr
                sg += dg
                sb += db
                if sr < 0:
                        sr = 0
                if sg < 0:
                        sg = 0
                if sb < 0:
                        sb = 0
                if sr > 1.0:
                        sr = 1.0
                if sg > 1.0:
                        sg = 1.0
                if sb > 1.0:
                        sb = 1.0
                


# xi.  expandPixels
# Name is preserved from Domino's scripts; make images compressible (and non-lossy for mirroring)
def expandPixels( image ):
  dx = image.size[0] / 32
  if ( dx != int(dx) ):
    print "Unable to make " + image.name + "' compressible as X size is not a multiple of 32"
    return
  dy = image.size[1] / 32
  if ( dy != int(dy) ):
    print "Unable to make '" + image.name + "' compressible as Y size is not a multiple of 32"
    return
  for y in xrange( 0, image.size[1], dy ):
    for x in xrange( 0, image.size[0] - 1):
      if x % dx:
        image.setPixelF( x, y, c )
      else:
        c = image.getPixelF( x, y )
  y = image.size[1] - 1
  for x in xrange( 0, image.size[0] - 1):
      if x % dx:
        image.setPixelF( x, y, c )
      else:
        c = image.getPixelF( x, y )
  for x in xrange( 0, image.size[0] ):
    for y in xrange( 0, image.size[1] -1 ):
      if y % dy:
        image.setPixelF( x, y, c )
      else:
        c = image.getPixelF( x, y )


# xii. getFirstX
# Name is preserved from Domino's scripts; used for fill functionality (not used)
def getFirstX( y ):
        for x in xrange( sculptyimage.size[0] ):
                c = sculptyimage.getPixelF( x, y )
                if c[3] != 0:
                        if x > 0: fill = True
                        return c
        return None


# xiii.getFirstY
# Name is preserved from Domino's scripts; used for fill functionality (not used)
def getFirstY( x ):
        for y in xrange( sculptyimage.size[1] ):
                c = sculptyimage.getPixelF( x, y )
                if c[3] != 0:
                        if y > 0: fill = True
                        return c
        return None


# xiv. fillX
# Name is preserved from Domino's scripts; used for fill functionality (not used)

# Fill is not used in the workflow of Prim.Blender, and is thus in native form.
def fillX():
        skipx = fill = False
        for v in xrange( sculptyimage.size[1] ):
                c = getFirstX( v )
                if not c : 
                        skipx= True
                        continue
                sr = c[0]
                sg = c[1]
                sb = c[2]
                s = 0
                for u in xrange( 1, sculptyimage.size[0] ):
                        nc = sculptyimage.getPixelF( u, v )
                        if nc[3] == 0:
                                if not fill:
                                        fill = True
                        else:
                                if fill:
                                        fill = False
                                        drawHLine( sculptyimage, v, s, u, sr, sg, sb, nc[0], nc[1], nc[2] )
                                s = u
                                sr = nc[0]
                                sg = nc[1]
                                sb = nc[2]
                if fill:
                        fill = False
                        drawHLine( sculptyimage, v, s, u, sr, sg, sb, sr, sg, sb )
        return skipx


# xv.  fillY
# Name is preserved from Domino's scripts; used for fill functionality (not used)

# Fill is not used in the workflow of Prim.Blender, and is thus in native form.
def fillY():
        fill = False
        for u in xrange( sculptyimage.size[0] ):
                c = getFirstY( u )
                if not c :
                        continue
                sr = c[0]
                sg = c[1]
                sb = c[2]
                s = 0
                for v in xrange( 1, sculptyimage.size[1] ):
                        nc = sculptyimage.getPixelF( u, v )
                        if nc[3] == 0:
                                if not fill:
                                        fill = True
                        else:
                                if fill:
                                        fill = False
                                        drawVLine( sculptyimage, u, s, v, sr, sg, sb, nc[0], nc[1], nc[2] )
                                s = v
                                sr = nc[0]
                                sg = nc[1]
                                sb = nc[2]
                if fill:
                        fill = False
                        drawVLine( sculptyimage, u, s, v, sr, sg, sb, sr, sg, sb )


# xvi. updateSculptyMap 
# Name is preserved from Domino's scripts; bakes a sculpty map to a filename
def updateSculptyMap( ob, prim, filename = None, scale = None, fill = False, expand = True):
        if not ob or not prim:
                print "updateSculptyMap: Error: Was given ob of %s and prim of %s" % (ob, prim)
                return
        print "Baking image for %s" % prim.UUID

        if scale == None:
                scale = scaleRange( [ob] ) # This code path is broken in the original,
                                         # And has been updated such that normalised is True by default
        if ob.type == 'Mesh':

                # This data is now captured in its own prim class and does not depend on object data
                # A whole lot of try-catch loops have been removed here 
                primtype = prim.type
                sculpty_type = prim.sculpttype
                if primtype != 7:
                        print "Skipping:", ob.name," -- prim type is not a sculpty"
                        return
                else:
                        sculpty_type = prim.sculpttype

                if sculpty_type < 1:
                        print "Skipping:", ob.name, " -- sculpty type is 'NONE'"
                        return
                
                # Cleaned up this logic considerably
                # Due to how we run our prim register, we should *never* have name collisions relevant to operation
                # See the register's internalKey function for more details
                sculpty_map = prim.sculptimage
                sculptyimage = None

                try:
                        sculptyimage = Blender.Image.Get( ob.name.replace("Prim_","") + ".tga" )
                except:
                        sculptyimage = Blender.Image.New( ob.name.replace("Prim_","") + ".tga", 64, 64, 32 )

                #print sculptyimage
                if not sculptyimage:
                        sculptyimage = Blender.Image.New( ob.name.replace("Prim_","") + ".tga", 64, 64, 32 )
                
                sculptyimage.fakeUser = True

                     
                # Prepare the image for baking and saving (as a TGA file)
                sculpty_map = sculptyimage.name
                prim.sculptimage = sculpty_map # Add this data to the primitive
                sculptyimage.makeCurrent()
                
                # This all should be far better documented.
                # In brief, we create a new mesh as a copy of our current object,
                # mangle its params into a sculpt map, save (if possible) and exit
                mesh = Blender.Mesh.New()
                mesh.getFromObject( ob, 0, 1 )

                # Create a MD5 hash for image culling
                md5hash = ""
                try:
                        md5hash = md5.new()
                except:
                        print "WARNING: Couldn't create a new md5. We'll assume this is because a full Python install is missing."

                # Perform the image draw
                for u in xrange( sculptyimage.size[0] ):
                        for v in xrange( sculptyimage.size[1] ):
                                sculptyimage.setPixelI(u, v, (0, 0, 0, 0))
                try:
                        for f in mesh.faces:
                                for t in Blender.Geometry.PolyFill([ f.uv ]):
                                        nf = []
                                        for i in t:
                                                r, g, b = scale.normalise( f.verts[ i ].co )
                                                md5hash.update(chr(round(r * 255.0)) + chr(round(g * 255.0)) + chr(round(b * 255.0)))
                                                
                                                nf.append(
                                                        pixel(
                                                                round(f.uv[ i ][0] * sculptyimage.size[0]),
                                                                round(f.uv[ i ][1] * sculptyimage.size[1]),
                                                                round( r * 255.0 ) / 255.0, round( g * 255.0 ) / 255.0, round( b * 255.0 ) / 255.0
                                                        )
                                                )
                                        
                                        # While drawing, update the hash value
                                        drawTri( sculptyimage, sorted( nf ) )

                except ValueError:
                        Blender.Draw.PupBlock( "Sculpty Bake Error", ["The UV map is outside","the image area"] )
                        return

                # @Fix: Normalize the vertex coordinates and resize the mesh to match
                # This is necessary for "correct" baking and mirroring in the context of Prim.Blender
                obmesh = ob.getData(mesh=True)
                if obmesh:
                        for v in obmesh.verts:
                                v.co = Blender.Mathutils.Vector(scale.normaliseVert( v.co ))

                        denorm = scale.denormalise()
                        cursize = ob.getSize()

                        ob.setSize(cursize[0] * denorm[0]
                                  ,cursize[1] * denorm[1]
                                  ,cursize[2] * denorm[2])

                        # Sync prim size to current object size
                        prim.size = (cursize[0] * denorm[0]
                                    ,cursize[1] * denorm[1]
                                    ,cursize[2] * denorm[2])
                


                # Create the compressible version of this image
    if expand:
      expandPixels ( sculptyimage )

                # Remove the orphaned mesh after baking
                del(mesh)

                # Output a simple hash for later image culling
                # If the user doesn't have a full python build, use the UUID instead
                try:
                        prim.sculpthash = md5hash.hexdigest()
                except:
                        prim.sculpthash = prim.UUID
                
                # If a filename is given, set it for the sculpty's image data
                if filename:
                        sculptyimage.setFilename(os.path.join(filename,sculptyimage.name))
                
                # This does not work during the saving callback (must be called as False during saving)
                # In fact, due to this behavior, it is not used in the workflow of Prim.Blender at all
                #if fill:
                #        skipx = fillX()
                #        fillY()
                #        if skipx: fillX()
                
                        

# V. Custom functions
# Add custom functions here...


#=========================================================================  











#=========================================================================
'''

VI. Post-data:

This section defines core commands to be executed once functions have been
defined.

'''
#=========================================================================


# A. Default Post-data

# Deselect all currently selected prims, to avoid Ctrl-Z mishaps
for ob in Blender.Scene.GetCurrent().objects:
        ob.select(0)

# Kick off the GUI
llDrawConsole(0)                

# Add a starter prim if registry is empty (that is, if no prims were 
# created in this scene before we start up)
PrimHolder.removeGhosts()
regSize = len(PrimHolder.primList)
if regSize == 0:
        llNewPrim(0,PrimHolder) 

# Unpacks all images and packed data; not needed currently
#Blender.UnpackAll(Blender.UnpackModes['USE_LOCAL'])


# B. Post-initialization Routines
# Add custom code here


#=========================================================================



# Yes. This is really the end of the script. Cookie?
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.