#
# $Id: alc_Classes.py 652 2006-09-28 22:25:35Z trylon $
#
#    Copyright (C) 2005-2006  Alcugs pyprp Project Team
#    See the file AUTHORS for more info about the team
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#    Please see the file COPYING for the full license.
#    Please see the file DISCLAIMER for more details, before doing nothing.
#

try:
    import Blender
    try:
        from Blender import NMesh
    except Exception, detail:
        print detail
except ImportError:
    pass

import md5, random, binascii, cStringIO, copy, Image, math, struct, StringIO, os, os.path, pickle
from enum import Enum
from alcurutypes import *
from alcdxtconv import *
from alchexdump import *
from alcurugeom import *
from alcGObjects import *
from alcConvexHull import *
from alcrespmod import * 
from alc_AbsClasses import *
import alcconfig, alchexdump

def stripIllegalChars(name):
    name=name.replace("*","_")
    name=name.replace("?","_")
    name=name.replace("\\","_")
    name=name.replace("/","_")
    name=name.replace("<","_")
    name=name.replace(">","_")
    name=name.replace(":","_")
    name=name.replace("\"","_")
    name=name.replace("|","_")
    name=name.replace("#","_")
    name=name.strip()
    return name

def Create(version=5):
    if version==6: #Myst 5 Object Types - Add to me!
        Types = Enum('plSceneNode',                                 #Type 0x00
                     'plSceneObject',                               #Type 0x01
                     'hsKeyedObject',                               #Type 0x02
                     'plBitmap',                                    #Type 0x03
                     'plMipMap',                                    #Type 0x04
                     'plCubicEnvironMap',                           #Type 0x05
                     'plLayer',                                     #Type 0x06
                     'hsGMaterial',                                 #Type 0x07
                     'plParticleSystem',                            #Type 0x08
                     'plParticleEffect',                            #Type 0x09
                     'plParticleCollisionEffectBeat',               #Type 0x0A
                     'plParticleFadeVolumeEffect',                  #Type 0x0B
                     'plBoundInterface',                            #Type 0x0C
                     'plRenderTarget',                              #Type 0x0D
                     'plCubicRenderTarget',                         #Type 0x0E
                     'plCubicRenderTargetModifier',                 #Type 0x0F
                     'plObjInterface',                              #Type 0x10
                     'plAudioInterface',                            #Type 0x11
                     'plAudible',                                   #Type 0x12
                     'plAudibleNull',                               #Type 0x13
                     'plWinAudible',                                #Type 0x14
                     'plCoordinateInterface',                       #Type 0x15
                     'plDrawInterface',                             #Type 0x16
                     'plDrawable',                                  #Type 0x17
                     'plAutoWalkRegion',                            #Type 0x18
                     'plDrawableIce',                               #Type 0x19
                     'plPhysical',                                  #Type 0x1A
                     'plCrossfade',                                 #Type 0x1B
                     'plSimulationInterface',                       #Type 0x1C
                     'plParticleFadeOutEffect',                     #Type 0x1D
                     'plModifier',                                  #Type 0x1E
                     'plSingleModifier',                            #Type 0x1F
                     'plSimpleModifier',                            #Type 0x20
                     'plWindBoneMod',                               #Type 0x21
                     'plCameraBrain_NovicePlus',                    #Type 0x22
                     'plGrassShaderMod',                            #Type 0x23
                     'plDetectorModifier',                          #Type 0x24
                     'pfSubtitleMgr',                               #Type 0x25
                     'plPythonFileModConditionalObject',            #Type 0x26
                     'plMultiModifier',                             #Type 0x27
                     'plSynchedObject',                             #Type 0x28
                     'plSoundBuffer',                               #Type 0x29
                     'plPickingDetector',                           #Type 0x2A
                     'plCollisionDetector',                         #Type 0x2B
                     'plLogicModifier',                             #Type 0x2C
                     'plConditionalObject')                         #Type 0x2D
        #fin de list
    else: #Uru Object Types
        Types = Enum('plSceneNode',                                 #Type 0x00
                     'plSceneObject',                               #Type 0x01
                     'hsKeyedObject',                               #Type 0x02
                     'plBitmap',                                    #Type 0x03
                     'plMipMap',                                    #Type 0x04
                     'plCubicEnvironMap',                           #Type 0x05
                     'plLayer',                                     #Type 0x06
                     'hsGMaterial',                                 #Type 0x07
                     'plParticleSystem',                            #Type 0x08
                     'plParticleEffect',                            #Type 0x09
                     'plParticleCollisionEffectBeat',               #Type 0x0A
                     'plParticleFadeVolumeEffect',                  #Type 0x0B
                     'plBoundInterface',                            #Type 0x0C
                     'plRenderTarget',                              #Type 0x0D
                     'plCubicRenderTarget',                         #Type 0x0E
                     'plCubicRenderTargetModifier',                 #Type 0x0F
                     'plObjInterface',                              #Type 0x10
                     'plAudioInterface',                            #Type 0x11
                     'plAudible',                                   #Type 0x12
                     'plAudibleNull',                               #Type 0x13
                     'plWinAudible',                                #Type 0x14
                     'plCoordinateInterface',                       #Type 0x15
                     'plDrawInterface',                             #Type 0x16
                     'plDrawable',                                  #Type 0x17
                     'plDrawableMesh',                              #Type 0x18
                     'plDrawableIce',                               #Type 0x19
                     'plPhysical',                                  #Type 0x1A
                     'plPhysicalMesh',                              #Type 0x1B
                     'plSimulationInterface',                       #Type 0x1C
                     'plCameraModifier',                            #Type 0x1D
                     'plModifier',                                  #Type 0x1E
                     'plSingleModifier',                            #Type 0x1F
                     'plSimpleModifier',                            #Type 0x20
                     'plSimpleTMModifier',                          #Type 0x21
                     'plRandomTMModifier',                          #Type 0x22
                     'plInterestingModifier',                       #Type 0x23
                     'plDetectorModifier',                          #Type 0x24
                     'plSimplePhysicalMesh',                        #Type 0x25
                     'plCompoundPhysicalMesh',                      #Type 0x26
                     'plMultiModifier',                             #Type 0x27
                     'plSynchedObject',                             #Type 0x28
                     'plSoundBuffer',                               #Type 0x29
                     'plAliasModifier',                             #Type 0x2A
                     'plPickingDetector',                           #Type 0x2B
                     'plCollisionDetector',                         #Type 0x2C
                     'plLogicModifier',                             #Type 0x2D
                     'plConditionalObject',                         #Type 0x2E
                     'plANDConditionalObject',                      #Type 0x2F
                     'plORConditionalObject',                       #Type 0x30
                     'plPickedConditionalObject',                   #Type 0x31
                     'plActivatorConditionalObject',                #Type 0x32
                     'plTimerCallbackManager',                      #Type 0x33
                     'plKeyPressConditionalObject',                 #Type 0x34
                     'plAnimationEventConditionalObject',           #Type 0x35
                     'plControlEventConditionalObject',             #Type 0x36
                     'plObjectInBoxConditionalObject',              #Type 0x37
                     'plLocalPlayerInBoxConditionalObject',         #Type 0x38
                     'plObjectIntersectPlaneConditionalObject',     #Type 0x39
                     'plLocalPlayerIntersectPlaneConditionalObject',#Type 0x3A
                     'plPortalDrawable',                            #Type 0x3B
                     'plPortalPhysical',                            #Type 0x3C
                     'plSpawnModifier',                             #Type 0x3D
                     'plFacingConditionalObject',                   #Type 0x3E
                     'plHKPhysical')                                #Type 0x3F
        #fin de list

class plSceneNode(hsKeyedObject):                           #Type 0x00
    def __init__(self,parent,name="unnamed"):               #Members
        hsKeyedObject.__init__(self,parent,name,0x0000)            #Base
        self.SceneObjects=hsTArray([0x01],self.getVersion())                  #plSceneObjects (vector)
        if self.getVersion()==6:
            ##myst5 types
            self.OtherObjects=hsTArray([0xCD,0x6B,0x80,0x8E,0x0110],6)
        else:
            ##Uru types
            self.OtherObjects=hsTArray([0x7A,0x98,0xA8,0xB5,0xE4,0xE8,0xE9,0xEA,0xED,0xF1,0x0109,0x010A,0x0129,0x012A,0x012B],5)


    def changePageRaw(self,sid,did,stype,dtype):
        self.SceneObjects.changePageRaw(sid,did,stype,dtype)
        self.OtherObjects.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.SceneObjects.ReadVector(buf)
        self.OtherObjects.ReadVector(buf)
       # size, = struct.unpack("I",buf.read(4))
       # for i in range(size):
       #     o = UruObjectRef(self.getVersion())
       #     o.read(buf)
       #     #print o
       #     if not o.Key.object_type in self.data1allow:
       #         raise RuntimeError, "Type %04X is not a plSceneObject [0x0000]" % o.Key.object_type
       #     self.data1.append(o)
       # size, = struct.unpack("I",buf.read(4))
       # for i in range(size):
       #     o = UruObjectRef(self.getVersion())
       #     o.read(buf)
       #     if not o.Key.object_type in self.data2allow:
       #         raise RuntimeError, "Type %04X is not in allow list 2" % o.Key.object_type
       #     self.data2.append(o)
       # assert(self.verify())


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        self.SceneObjects.WriteVector(buf)
        self.OtherObjects.WriteVector(buf)
       # buf.write(struct.pack("I",len(self.data1)))
       # for o in self.data1:
       #     #o.update(self.Key)
       #     o.write(buf)
       # buf.write(struct.pack("I",len(self.data2)))
       # for o in self.data2:
       #     #o.update(self.Key)
       #     o.write(buf)


    def dump(self):
        print "BEGIN SceneNode: " + self.Key.name
        hsKeyedObject.dump(self)
        print "SceneObjects - %i" % self.SceneObjects.size
        i=0
        for o in self.SceneObjects:
           print "[%i] %s" %(i,o)
           i=i+1
        print "Other Objects - %i" % self.OtherObjects.size
        i=0
        for o in self.OtherObjects:
           print "[%i] %s" %(i,o)
           i=i+1
        print "# END [%04X] %s" % (self.Key.object_type, self.Key.name)


    def import_all(self):
        root = self.getRoot()
        for ref in self.SceneObjects.vector:
            o=root.findref(ref)
            #print str(ref), o
            print "importing %s" %o.data.Key.name
            #if str(o.data.Key.name)!="Door_Right":
                #continue
            o.dump()
            o.data.import_all()
        Blender.Redraw()


class plSceneObject(plSynchedObject):                       #Type 0x01
    def __init__(self,parent,name="unnamed"):               #Members
        plSynchedObject.__init__(self,parent,name,0x01)
        self.draw=UruObjectRef()                            #Span Info
        self.simulation=UruObjectRef()                      #Animation Info
        self.coordinate=UruObjectRef()                      #Region Info
        self.audio=UruObjectRef()                           #Sound Info
        self.scene=UruObjectRef()                           #SceneNode to which this object belong
        if self.getVersion()==6:
            #myst5 types
            self.data1=hsTArray([0x0C,0x50,0x51,0x52,0x5A,0x5B,0x76,0xB5,0xB6],6)
            self.data2=hsTArray([0x08,0x1B,0x21,0x23,0x2A,0x2C,0x3B,0x3C,0x3E,0x56,0x57,0x5F,0x60,0x62,0x6A,0x6C,0x6D,0x6E,0x7D,0x83,0x87,0x88,0x8A,0x91,0x92,0x94,0x97,0x98,0x9C,0x9E,0xA5,0xAC,0xB4,0xC1,0xD0,0xD4,0xD8,0xE0,0xF1,0x0106,0x010E,0x0113,0x0114],6)
        else:
            #uru types
            self.data1=hsTArray([0x0C,0x55,0x56,0x57,0x67,0x6A,0x88,0xD5,0xD6,0xE2,0xEC,0xF6,0x0116,0x011E,0x0133,0x0134,0x0136],5)
            self.data2=hsTArray([0x08,0x2A,0x2B,0x2D,0x3D,0x40,0x62,0x6C,0x6D,0x6F,0x71,0x76,0x77,0x79,0x7A,0x7B,0x7C,0x8F,0x95,0x9B,0xA1,0xA2,0xA4,0xA9,0xAA,0xAB,0xAC,0xAE,0xAF,0xB1,0xB2,0xB9,0xBA,0xBB,0xBD,0xC0,0xC1,0xC4,0xCB,0xCF,0xD4,0xE5,0xE7,0xEE,0xF3,0xF5,0xFB,0xFC,0xFF,0x0107,0x0108,0x010C,0x010D,0x0119,0x0122,0x012C,0x012E,0x012F,0x0131],5)

    def changePageRaw(self,sid,did,stype,dtype):
        plSynchedObject.changePageRaw(self,sid,did,stype,dtype)
        self.draw.changePageRaw(sid,did,stype,dtype)
        self.simulation.changePageRaw(sid,did,stype,dtype)
        self.coordinate.changePageRaw(sid,did,stype,dtype)
        self.audio.changePageRaw(sid,did,stype,dtype)
        for i in self.data1.vector:
            i.changePageRaw(sid,did,stype,dtype)
        for i in self.data2.vector:
            i.changePageRaw(sid,did,stype,dtype)
        self.scene.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        plSynchedObject.read(self,buf)
        self.draw.setVersion(self.getVersion())
        self.simulation.setVersion(self.getVersion())
        self.coordinate.setVersion(self.getVersion())
        self.audio.setVersion(self.getVersion())
        self.scene.setVersion(self.getVersion())
        self.draw.read(buf)
        #assert(self.draw.checktype(0x0016) or self.draw.checktype(0x00D2)
        self.simulation.read(buf)
        #assert(self.simulation.checktype(0x001C))
        self.coordinate.read(buf)
       # if self.getVersion()==6: #Myst 5
        #    assert(self.coordinate.checktype(0x0015) or self.coordinate.checktype(0x00D7))
       # else:                   #Uru
       #     assert(self.coordinate.checktype(0x0015) or self.coordinate.checktype(0x00FE))
        self.audio.read(buf)
       # assert(self.audio.checktype(0x0011))
        self.data1.ReadVector(buf)
        self.data2.ReadVector(buf)
        self.scene.read(buf)


    def write(self,buf):
        plSynchedObject.write(self,buf)
        #self.draw.update(self.Key)
        self.draw.write(buf)
        #self.simulation.update(self.Key)
        self.simulation.write(buf)
        #self.coordinate.update(self.Key)
        self.coordinate.write(buf)
        #self.audio.update(self.Key)
        self.audio.write(buf)
        self.data1.WriteVector(buf)
        self.data2.WriteVector(buf)
        #self.scene.update(self.Key)
        self.scene.write(buf)


    def dump(self):
        print "BEGIN SceneObject %s" % (self.Key.name)
        plSynchedObject.dump(self)
        print "Draw: %s" % self.draw
        print "Simulation: %s" % self.simulation
        print "Coordinate: %s" % self.coordinate
        print "Audio: %s" % self.audio
        print "Object Refs - %i" % len(self.data1)
        i=0
        for o in self.data1.vector:
           print "[%i] %s" %(i,o)
           i=i+1
        print "Modifier Refs - %i" % len(self.data2)
        i=0
        for o in self.data2.vector:
           print "[%i] %s" %(i,o)
           i=i+1
        print "Scene: %s" % self.scene
        print "# END [%04X] %s" % (self.Key.object_type, self.Key.name)


##    def verify(self):
##        if not self.draw.verify(self.Key):
##            return 0
##        if not self.simulation.verify(self.Key):
##            return 0
##        if not self.coordinate.verify(self.Key):
##            return 0
##        if not self.audio.verify(self.Key):
##            return 0
##        #for o in self.data1:
##            #if not o.verify(self.Key):
##                #return 0
##        #for o in self.data2:
##            #if not o.verify(self.Key):
##                #return 0
##        if not self.scene.verify(self.Key):
##            return 0
##        return 1


    def import_all(self):
        assert(self.draw.checktype(0x0016)) #or self.draw.checktype(0x00D2))
        root = self.getRoot()
        #draw
        draw = root.findref(self.draw)
        if draw!=None:
            draw.dump()
            draw.data.import_all(str(self.Key.name))
        #coordinate
        coordinate = root.findref(self.coordinate)
        matrix2 = hsMatrix44()
        if coordinate!=None and self.getVersion() != 6 and coordinate.data.Key.object_type == 0x0015: # since this ref also accepts 0xFE (FilterCoordinate Types)
            coordinate.dump()
            matrix2=coordinate.data.matrix2
            if draw!=None:
                draw.data.transform(coordinate.data.matrix2)
        #simulation
        phys=None
        simulation = root.findref(self.simulation)
        if simulation!=None and self.getVersion() != 6:
            simulation.dump()
            simulation.data.import_all(str(self.Key.name),matrix2)
            phys=root.findref(simulation.data.physical)
            if draw!=None and phys!=None:
                for objs in draw.data.blenderobjects:
                    for obj in objs:
                        obj.addProperty("mass",float(phys.data.mass))
        pointHandled = 0
        #light
        for li in  self.data1.vector:
            if li.Key.object_type in [0x55,0x56,0x57]:
                light=root.findref(li)
                light.data.import_all(str(self.Key.name),matrix2)
                pointHandled = 1
        #shadow
        for sh in  self.data1.vector:
            if sh.Key.object_type in [0xD5]:
                shadow=root.findref(sh)
                # Robert The Rebuilder 3/14/06: commented out because obj is not defined yet, and this causes an error during import
                #shadow.data.import_obj(obj)
                pointHandled = 1

        #ViewFaceModifier
        for vfm in self.data2.vector:
            if vfm.Key.object_type in [0x40]:
                viewface=root.findref(vfm)
                viewface.dump()
                #There should be some sort of test here to determine if the VFM is not null
                if (viewface != None and draw): #ViewFaceModifier
                    prptype = "viewfacemodifier"
               #     vmod = alcCreateViewFaceMod("ViewFaceModifier")
                    
                    for objs in draw.data.blenderobjects:
                        for obj in objs:
                            try:
                                p=obj.getProperty("alctype")
                                obj.removeProperty(p)
                            except AttributeError:
                                pass
                            obj.addProperty("alctype","sprite")
                            viewface.data.import_obj(obj)    
               #     print "ViewFaceModifier %s" % str(self.Key.name)
               #     pass

        
        #modifiers 1
        rgn_swimsfc = None
        for mod in self.data1.vector:
            if (mod.Key.object_type==0x0133) or (mod.Key.object_type==0x0134) or (mod.Key.object_type==0x0136): #SpawnModifier
                print "Detected Swim Surface Modifier"
                rgn_swimsfc = mod # save this modifier


        #modifiers 2
        rgn_objinvolmod = None
        rgn_camregion = None
        rgn_climbregion = None
        rgn_paniclinkregion = None
        rgn_swimregion = None
        rgn_objinvolmod = None
        rgn_haslogicmod = 0
        rgn_logicmods = []
        rgn_respmod = None
        rgn_ifinfomod = None
        
        cam_cameramod = None
        
        
        for mod in self.data2.vector:
            if mod.Key.object_type==0x3D: #SpawnModifier
                #create a linkInPoint
                pointHandled = 1
                obj=alcCreateLinkInPoint(str(self.Key.name),matrix2,self.getPageNum())
                obj.addProperty("name",str(self.Key.name))
            #Noooooo!!!! There is a better way!
            #elif mod.Key.object_type==0xA2: #PythonFileMod
            #    PyMod = root.findref(mod)
            #    obj = phys.data.blendobj
            #    obj.addProperty("PyMod",PyMod.PyFile)
            #    for i in range(len(PyMod.PyArgs)):
            #        Arg = PyMod.PyArgs[i]
            #        Bad = (6, 7, 8, 9, 10, 11, 12, 14, 15, 18, 19, 20, 21)
            #        if Arg.type in Bad:
            #            print "Skipping PyArg, it is a plKeyRef :("
            #            continue
            #        obj.addProperty("PyArg" + Arg.idx,Arg.data)
            elif mod.Key.object_type==0xA2 and phys:
                obj = phys.data.blendobj
                PyMod = root.findref(mod)
                if PyMod != None:
                    obj.addProperty("PyMod",str(PyMod.data.PyFile))
            elif mod.Key.object_type==0x00B2 and self.getVersion() != 6: #AvLadderMod
                                
                rgn_climbregion = root.findref(mod)

#                climbRegion = root.findref(mod)
#                if climbRegion != None and phys:
#                    obj = phys.data.blendobj
#                    obj.addProperty("alcspecial","climbregion")
#                    climbRegion.data.import_obj(obj)
            elif mod.Key.object_type==0x002D and self.getVersion() != 6: #LogicModifier
                #Contains Volumesensor Object....
                rgn_haslogicmod += 1
                rgn_logicmods.append(root.findref(mod))
                pass
            elif mod.Key.object_type==0x007B and self.getVersion() != 6: #ObjectInvolumeDetector
                rgn_objinvolmod = root.findref(mod)
                # has option c70 (either 0 or 4)
                pass
            elif mod.Key.object_type==0x00CB and self.getVersion() != 6: #InterfaceInfoModifier
                rgn_ifinfomod = root.findref(mod)
                pass
            elif mod.Key.object_type==0x007C and self.getVersion() != 6: #ResponderModifier
                rgn_respmod = 1 #root.findref(mod)
                pass
            elif mod.Key.object_type==0x012E and self.getVersion() != 6: #SwimRegion
                rgn_swimregion = root.findref(mod)
                pass                
            elif mod.Key.object_type==0x006F and self.getVersion() != 6: #CameraRegionDetector
                rgn_camregion = root.findref(mod)
                #cameraregionDetector is not yet implemented!
                #please add processing as implementation follows
                pass
            elif mod.Key.object_type==0x00FC and self.getVersion() != 6: #PaniclinkRegion
                rgn_paniclinkregion = root.findref(mod)
                pass
            elif mod.Key.object_type==0x009B and self.getVersion() != 6: #CameraModifier
                cam_cameramod = root.findref(mod)
                pass                
            
        #see if we have a region (exclude bounding sphere regins, since they aren't supported correctly)
        if(phys and phys.data.format != 2 and
            ( (rgn_objinvolmod != None) or 
              (rgn_camregion != None) or 
              (rgn_climbregion != None) or 
              (rgn_paniclinkregion != None) or 
              (rgn_swimregion != None) or 
              (rgn_swimsfc != None) or 
              ((rgn_objinvolmod != None) and (rgn_haslogicmod != 0) and (rgn_respmod != None) and (rgn_ifinfomod != None))
              ) ):
            
            print "Found Region with name %s" % str(self.Key.name)
            
            isregion = 1
            obj = phys.data.blendobj
            
            try:
                p=obj.getProperty("alctype")
                obj.removeProperty(p)
            except AttributeError:
                pass
            obj.addProperty("alctype","region")
            obj.layers = [4,]
            obj.drawMode=2
            
            # remove object Properties if they are default
            
            # find out what kind of region it is.
            prpregion = "unknown"
            if ((rgn_objinvolmod != None) and 
                  (rgn_haslogicmod == 2) and 
                  (rgn_respmod != None) and 
                  (rgn_ifinfomod != None)):  # Footstep region
                prpregion = "footsteprgn"
                obj.addProperty("prpregion",prpregion)
                
                print "Region %s is a Footstep Sound Region" % str(self.Key.name)
                
                for mylogicmod in rgn_logicmods:
                    # walk through the conditionals and import if it's a VolumeSensor
                    for cond in mylogicmod.data.Conditionals:
                        if cond.Key.object_type == 0x00A6:
                            volsens = root.findref(cond)
                            volsens.data.import_obj(obj)
                
                
                pass
            elif (rgn_camregion != None):  # Camera region
                prpregion = "camerargn"
                obj.addProperty("prpregion",prpregion)
                print "Region %s is a Camera Region" % str(self.Key.name)
                obj.layers = [5,]
                rgn_camregion.data.import_obj(obj)
                pass
            elif (rgn_swimregion != None): #swim Region

                prpregion = "swimrgn"
                obj.addProperty("prpregion",prpregion)
                print "Region %s is a Swim Detector Region" % str(self.Key.name)
                pass
            elif (rgn_swimsfc != None): #swim Region
                print "Region %s is a Swim Surface Region" % str(self.Key.name)
                # set the correct prpregion type
                if rgn_swimsfc.Key.object_type==0x0133:
                    prpregion = "swimplainsfc"
                elif rgn_swimsfc.Key.object_type==0x0134:
                    prpregion = "swimccursfc"
                elif rgn_swimsfc.Key.object_type==0x0136:
                    prpregion = "swimscursfc"

                obj.addProperty("prpregion",prpregion)
                swimsfc = root.findref(rgn_swimsfc)
                swimsfc.data.import_obj(obj)
                pass
            elif (rgn_climbregion != None): # climbing region
                prpregion = "climbregion"
                obj.addProperty("prpregion",prpregion)
                rgn_climbregion.data.import_obj(obj)
                print "Region %s is a Climbing Region" % str(self.Key.name)
                pass
            elif (rgn_paniclinkregion != None): # panic link region
                prpregion = "paniclnkrgn"
                obj.addProperty("prpregion",prpregion)
                print "Region %s is a Panic Link Region" % str(self.Key.name)
                pass
            elif ((rgn_objinvolmod != None) and 
                  (rgn_haslogicmod == 0) and 
                  (rgn_respmod == None) and 
                  (rgn_ifinfomod == None)): # click region 
                prpregion = "clickrgn"
                obj.addProperty("prpregion",prpregion)
                print "Region %s is a Click Region" % str(self.Key.name)
                pass
            else:
                print "Region %s is an Unknown Region" % str(self.Key.name)
                obj.layers = [5,]
                pass


            #remove default properties (depending on the type of region)
            if(prpregion == "swimregion"):
                self.deldefaultproperty(obj,"mass",0.0);
                self.deldefaultproperty(obj,"rc",0.0);
                self.deldefaultproperty(obj,"el",0.0);
                self.deldefaultproperty(obj,"col_type","1");
                self.deldefaultproperty(obj,"col_flags0","0000");
                self.deldefaultproperty(obj,"col_flags1","00020000");
                self.deldefaultproperty(obj,"col_flags2","00000000");
                self.deldefaultproperty(obj,"col_flags3","0000");
                self.deldefaultproperty(obj,"col_flags4","00000000");
                self.deldefaultproperty(obj,"col_flags5","00000000");
            elif (prpregion == "swimplainsfc") or (prpregion == "swimccursfc") or (prpregion == "swimscursfc"):
                self.deldefaultproperty(obj,"mass",0.0);
                self.deldefaultproperty(obj,"rc",0.0);
                self.deldefaultproperty(obj,"el",0.0);
                self.deldefaultproperty(obj,"col_type","4");
                self.deldefaultproperty(obj,"col_flags0","0000");
                self.deldefaultproperty(obj,"col_flags1","00000000");
                self.deldefaultproperty(obj,"col_flags2","00000000");
                self.deldefaultproperty(obj,"col_flags3","0000");
                self.deldefaultproperty(obj,"col_flags4","00000000");
                self.deldefaultproperty(obj,"col_flags5","00000080");
            elif (prpregion == "clickrgn"):
                self.deldefaultproperty(obj,"mass",1.0);
                self.deldefaultproperty(obj,"rc",0.0);
                self.deldefaultproperty(obj,"el",0.0);
                self.deldefaultproperty(obj,"col_type","3");
                self.deldefaultproperty(obj,"col_flags0","0400");
                self.deldefaultproperty(obj,"col_flags1","08000000");
                self.deldefaultproperty(obj,"col_flags2","00000000");
                self.deldefaultproperty(obj,"col_flags3","0000");
                self.deldefaultproperty(obj,"col_flags4","00000004");
                self.deldefaultproperty(obj,"col_flags5","00000000");
            elif (prpregion != "unknown"):
                self.deldefaultproperty(obj,"mass",1.0);
                self.deldefaultproperty(obj,"rc",0.0);
                self.deldefaultproperty(obj,"el",0.0);
                self.deldefaultproperty(obj,"col_type","3");
                self.deldefaultproperty(obj,"col_flags0","0400");
                self.deldefaultproperty(obj,"col_flags1","08000000");
                self.deldefaultproperty(obj,"col_flags2","00000000");
                self.deldefaultproperty(obj,"col_flags3","0000");
                self.deldefaultproperty(obj,"col_flags4","00000004");
                self.deldefaultproperty(obj,"col_flags5","00000000");


                
            
        ###############################
        # Trylon added support for "point" objects - empty meshes with only a coordinate interface
        ###############################
        if simulation == None and coordinate != None and draw == None and pointHandled == 0 :
            name = str(self.Key.name)
            the_name=alcUniqueName(name)
            
            if(cam_cameramod == None):
                # make the point object
                boxsize = 0.5
                obj = alcCreateBox(the_name,boxsize,-(boxsize/2),-(boxsize/2),-(boxsize/2))
                obj.layers=[2,]
                obj.addProperty("alctype","point")

                # apply the matrix
                m=matrix2.get()
                m.transpose()
                obj.setMatrix(m)

                # set the properties
                # to make it extra visible, we delibirately don't set it to wireframe mode
                obj.addProperty("name",str(name))
                obj.addProperty("page_num",str(self.getPageNum()))

            else: # we have a camera
                cam = Blender.Camera.New("persp",the_name)
                obj = Blender.Object.New("Camera")
                obj.link(cam)
                scn = Blender.Scene.getCurrent()
                scn.link(obj)
                obj.layers=[5,]
                obj.addProperty("alctype","camera")
                obj.setName(the_name)
                # apply the matrix
                m=matrix2.get()
                m.transpose()
                obj.setMatrix(m)

                # set the properties 
                # to make it extra visible, we delibirately don't set it to wireframe mode
                obj.addProperty("name",str(name))
                obj.addProperty("page_num",str(self.getPageNum()))

                cam_cameramod.data.import_obj(obj)
                pass

            
        ###############################
        # END Trylon added support for "point" objects - empty meshes with only a coordinate interface
        ###############################

 
    
    def deldefaultproperty(self,obj,propertyname,defaultvalue):
        try:
            p=obj.getProperty(propertyname)
            if(p.getData() == defaultvalue):
                obj.removeProperty(p)
        except AttributeError:
            print "Error removing %s property" % propertyname
        
 
class plMipMap(plBitmap):                                   #Type 0x04
    def __init__(self,parent,name="unnamed"):
        plBitmap.__init__(self,parent,name,0x0004)
        #format
        self.width=0 #U32
        self.height=0 #U32
        self.stride=0 #U32 - mystery
        self.length=0 #U32
        self.levels=0 #Byte
        #if type==0 [
        # for each level in levels
        #  width = width>>level
        #  height = height>>level
        #  data = width*height U32's from buffer (in BGRA) B G R A
        #] elif type==1 [
        # DXT1 or DXT5 data * level
        #] elif type==2 [
        # see tJpgImage class
        #]
        #--------
        #Uncompressed Image information is stored in (R G B A) RGBA
        self.images=[]
        self.useAlpha = 0
        self.BlenderImage=None


    def read(self,buf,really=1):
        plBitmap.read(self,buf,really)
        self.width, self.height, self.stride, self.length = struct.unpack("IIII",buf.read(16))
        #print self.length
        assert(self.width*4==self.stride)
        self.levels, = struct.unpack("B",buf.read(1))
        off_start=buf.tell()
        self.images=[]
        if self.type==0x00:
            for i in range(self.levels):
                data=myImage(self.width>>i,self.height>>i)
                data.read(buf)
                #data.save("dumps/" + stripIllegalChars(str(self.Key.name)) + ".jpg")
                self.images.append(data)
        elif self.type==0x01:
            for i in range(self.levels):
                data=tDxtImage(self.width>>i,self.height>>i,self.subtype)
                data.read(buf)
                self.images.append(data)
        elif self.type==0x02:
            #print "%02X" % self.levels
            #assert(self.levels==11)
            data=tJpgImage(self.width,self.height)
            data.read(buf)
            self.images.append(data)
        off_end=buf.tell()
        #assert(self.length==off_end-off_start)
        if self.type!=0x02 and self.length!=off_end-off_start:
            raise RuntimeError, "incorrect lenght %i - %i" %(self.length,off_end-off_start)


    def write(self,buf,really=1):
        plBitmap.write(self,buf,really)
        self.stride=self.width*4
        #self.length=self.stride*self.height
        self.length=0
        buf.write(struct.pack("III",self.width, self.height, self.stride))
        off_len=buf.tell()
        buf.write(struct.pack("I",self.length))
        self.levels=len(self.images)
        buf.write(struct.pack("B",self.levels))
        off_start=buf.tell()
        for data in self.images:
            data.write(buf)
        off_end=buf.tell()
        self.length=off_end-off_start
        buf.seek(off_len)
        buf.write(struct.pack("I",self.length))
        buf.seek(off_end)


    def dump(self,all=1):
        print "BEGIN MipMap %s " % self.Key.name
        plBitmap.dump(self)
        print "w:%i,h:%i len:%i, levels:%i" %(self.width,self.height,self.length,self.levels)
        print "END MipMap"
        resmanager=hsKeyedObject.getResManager()
        path=resmanager.getBasePath()
        path = path + "/dumps"
        try:
            os.mkdir(path)
        except OSError:
            pass
        all=0
        try:
            os.stat(path + "/index.html")
            html=file(path + "/index.html","a")
        except OSError:
            html=file(path + "/index.html","a")
            html.write("<html><head><title>Texture listing</title></head><body bgcolor=ff00ff>\n")
        e=0
        for i in self.images:
            name=stripIllegalChars(str(self.Key.name)) + "-%i.png" %e
            i.save(path + "/" + name)
            e=e+1
            html.write("<img src=\"" + name + "\"><br />" + name + "<br /><br />\n")
            if not all:
                break
        html.close()
        #return
        #study
        f=file("study.txt","a")
        out="%i %04X %i %i %02X %04X %08X %02X\n" %\
             (self.cpb,self.flags,self.type,self.subtype,self.uk1,self.uk2,self.uk3,self.uk4)
        f.write(out)
        f.close()


    def getBlenderImage(self):
        if self.BlenderImage!=None:
            return self.BlenderImage
        resmanager=self.getResManager()
        path=resmanager.getBasePath()
        path = path + "/TMP_Textures/"
        #print path

        try:
            os.mkdir(path)
        except OSError:
            pass
            
        if len(self.images)==0:
            return None
        print "Loading %s" %str(self.Key)
        i=self.images[0]
        name=stripIllegalChars(str(self.Key.name)) + ".png"
        i.save(path + "/" + name)
        img=Blender.Image.Load(path + "/" + name)
        self.BlenderImage=img
        return img

    def setRawTexture(self,imagebuf,width, height,useAlpha=0,doMipMap=1):
        self.useAlpha = useAlpha
        self.width = width
        self.height = height
        
        imagebuf.seek(0)
        self.images=[]
        #print self.images
        if alcconfig.texture_compression or self.useAlpha:
            print "If you have a good book, then I suggest to start reading it..."
        if alcconfig.texture_resize:
            new_w=2 ** int(math.log(self.width,2))
            new_h=2 ** int(math.log(self.height,2))
            if new_w!=self.width or new_h!=self.height:
                im=Image.new("RGBA",(self.width,self.height))
                im.fromstring(imagebuf.read())
                im2=im.resize((new_w,new_h),Image.ANTIALIAS)
                imagebuf=cStringIO.StringIO()
                imagebuf.write(im2.tostring())
                self.width=new_w
                self.height=new_h
        print "Level 0 %ix%i" %(self.width,self.height)

        if ((alcconfig.texture_compression) or self.useAlpha):
            #Note: we should study the texture and determine which
            # compression method would be better
            if self.useAlpha==2:
                type=5
            else:
                type=1
            myimg=tDxtImage(self.width,self.height,type)
            myimg.data=imagebuf
            myimg.fromRGBA()
            self.images=[myimg,]
            self.type=1
            self.subtype=type
        else:
            myimg=myImage(self.width,self.height)
            myimg.data=imagebuf
            myimg.fromRGBA()
            self.images=[myimg,]
            self.type=0
            self.subtype=0

        if alcconfig.texture_mipmaps and doMipMap:
            i=1
            mw=self.width>>i
            mh=self.height>>i
            while mw!=0 and mh!=0:
                print "Level %i %ix%i" %(i,mw,mh)
                img=copy.copy(myimg)
                img.resize(mw,mh)
                img.fromRGBA()
                self.images.append(img)
                myimg=img
                i=i+1
                mw=self.width>>i
                mh=self.height>>i

    def setBlenderTexture(self,texture,doMipMap=1):
        if(texture == None):
            return
        # 1st build up the necessary filename

        resmanager=self.getResManager()
        path=resmanager.getBasePath()
        cachepath = path + "/" + self.parent.parent.parent.age.name + "_TexCache/"

        #print "Cachepath: " + cachepath

        # and make the directory if texture_cache is enabled
        if (alcconfig.texture_cache):
            try:
                os.mkdir(cachepath)
            except OSError:
                pass

        # and make the filename
        cachefilenm = cachepath + str(self.Key.name) + ".tex"

        # now see if this file exists and is ok
        
        texcacheok = 0 # not currently used, but can be used to automatically jump to the texture buildup, if the cache files
                       # are detected as broken. To implement that, set it to zero at the end of the cache loading sequence,
                       # and delete the broken cache file (to avoid infinite loops ;)

        while texcacheok == 0:
            if ((alcconfig.texture_cache) and (os.path.isfile(cachefilenm))): # unless disabled, check for the texture's cache file
                print "Loading %s from cache" %str(self.Key)

                # load in the data from the file
                f=hsStream(cachefilenm,"rb")
                self.read(f)
                try:
                    self.useAlpha, = struct.unpack("I",f.read(4))
                except:
                    print "WARNING: Problem reading useAlpha variable"
                    print "PLEASE REMOVE YOUR OLD TEXTURE CACHE FILES"
                    self.useAlpha = 0
                
                f.close()

                texcacheok = 1
            else:
                # build up the texture
                texcacheok = 1 # we don't want to do a repeat if we're here
                
                print "Converting %s this will take several minutes" %str(self.Key)
                self.width, self.height = texture.getSize()
                imagebuf=cStringIO.StringIO()
                ignorealpha=0
                self.useAlpha=0
                if str(texture.getFilename())[-4:]==".gif":
                    ignorealpha=1
                for y in range(self.height,0,-1):
                    for x in range(self.width):
                        r,g,b,a = texture.getPixelF(x,y-1)
                        if ignorealpha:
                            a=1.0
                        else:
                            if a<1 and not self.useAlpha:
                                self.useAlpha=1
                            if a>0 and a<1:
                                self.useAlpha=2
                        imagebuf.write(struct.pack("BBBB",r*255,g*255,b*255,a*255))
                print "Continuing with the image compression process...."
                print "This will take several minutes..."
                imagebuf.seek(0)
                self.images=[]
                #print self.images
                if alcconfig.texture_compression or self.useAlpha:
                    print "If you have a good book, then I suggest to start reading it..."
                if alcconfig.texture_resize:
                    new_w=2 ** int(math.log(self.width,2))
                    new_h=2 ** int(math.log(self.height,2))
                    if new_w!=self.width or new_h!=self.height:
                        im=Image.new("RGBA",(self.width,self.height))
                        im.fromstring(imagebuf.read())
                        im2=im.resize((new_w,new_h),Image.ANTIALIAS)
                        imagebuf=cStringIO.StringIO()
                        imagebuf.write(im2.tostring())
                        self.width=new_w
                        self.height=new_h
                print "Level 0 %ix%i" %(self.width,self.height)

                if ((alcconfig.texture_compression) and (not str(self.Key.name)[0:10]=="noCompress")) or self.useAlpha:
                    #Note: we should study the texture and determine which
                    # compression method would be better
                    if self.useAlpha==2:
                        type=5
                    else:
                        type=1
                    myimg=tDxtImage(self.width,self.height,type)
                    myimg.data=imagebuf
                    myimg.fromRGBA()
                    self.images=[myimg,]
                    self.type=1
                    self.subtype=type
                else:
                    if (alcconfig.texture_compression):
                        print 'Compression not allowed: Filename contains noCompress or alpha'
                    myimg=myImage(self.width,self.height)
                    myimg.data=imagebuf
                    myimg.fromRGBA()
                    self.images=[myimg,]
                    self.type=0
                    self.subtype=0
                if alcconfig.texture_mipmaps:
                #Dustin added first 2 lines, indented the rest. Trylon added 3rd condition
                    if (
                            (not str(self.Key.name)[0:8]=="noMipMap")
                            and (not str(self.Key.name)[0:10]=="noCompress")
                            and (self.useAlpha==0)
                            and doMipMap
                        ):
                        print 'Mipmapping allowed by filename (Dustin/Trylon addition)'
                        i=1
                        mw=self.width>>i
                        mh=self.height>>i
                        while mw!=0 and mh!=0:
                            print "Level %i %ix%i" %(i,mw,mh)
                            img=copy.copy(myimg)
                            img.resize(mw,mh)
                            img.fromRGBA()
                            self.images.append(img)
                            myimg=img
                            i=i+1
                            mw=self.width>>i
                            mh=self.height>>i
                    else:
                        print 'Mipmapping not allowed: Filename contains noMipMap,noCompress'
                        print ' (Dustin/Trylon addition)'
                #/Dustin /Trylon
                #Note type 2 is never used for textures, type 2 is used
                # for images rendered inside GUI objects, like books

                # now store the data in a file if texture_cache is enabled
                if (alcconfig.texture_cache):
                    f=hsStream(cachefilenm,"wb")
                    self.write(f)
                    f.write(struct.pack("I",self.useAlpha))
                    f.close()
                
            #/else:
        #/while:

class plCubicEnvironMap(plBitmap):                          #Type 0x05
    def __init__(self,parent,name="unnamed"):
        plBitmap.__init__(self,parent,name,0x0005)
        #format
        #6 faces of a cube
        self.images=[]

        #some non-format vars:
        self.isProcessed = 0

    def read(self,buf):
        plBitmap.read(self,buf)
        for i in range(6):
            if self.getVersion()==6:
                null=UruObjectRef(self.getVersion())
                null.read(buf)
                assert(null.isNull())
            img = plMipMap(self.parent)
            img.Key.name.set(str(self.Key.name) + "-%i" %i)
            img.read(buf,0)
            self.images.append(img)


    def write(self,buf):
        plBitmap.write(self,buf)
        assert(len(self.images)==6)
        for img in self.images:
            img.write(buf,0)


    def dump(self):
        print "BEGIN CubicEnvironMap %s " % self.Key.name
        plBitmap.dump(self)
        for img in self.images:
            img.dump()
        print "END CubicEnvironMap"
        
    def setBlenderCubicMap(self,cubicmap):
        # if we are already set up and ready, don't continue....
        if(self.isProcessed):
            return
    
    
        # first plit up the image in 6 parts
        envimages = []
        
        width, height = cubicmap.getSize()
        
        xpart = width / 3
        ypart = height / 2
        
        # get the image data
        self.useAlpha=0

        rawimages = []

        for i in range(0,6):
            if(i == 0):
                ystart = height
                yend = height - ypart
                xstart = 0
                xend = 0 + xpart
            elif(i == 1):
                ystart = height
                yend = height - ypart
                xstart = xpart
                xend = 0 + 2*xpart
            elif(i == 2):
                ystart = height
                yend = height - ypart
                xstart = 2*xpart
                xend = width
            elif(i == 3):
                ystart = ypart
                yend = 0
                xstart = 0
                xend = 0 + xpart
            elif(i == 4):
                ystart = ypart
                yend = 0
                xstart = xpart
                xend = 0 + 2*xpart
            elif(i == 5):
                ystart = ypart
                yend = 0
                xstart = 2*xpart
                xend = width
            

            imagebuf=cStringIO.StringIO()
            ignorealpha=0
            if str(cubicmap.getFilename())[-4:]==".gif":
                ignorealpha=1
            for y in range(ystart,yend,-1):
                for x in range(xstart,xend):
                    r,g,b,a = cubicmap.getPixelF(x,y-1)
                    if ignorealpha:
                        a=1.0
                    else:
                        if a<1 and not self.useAlpha:
                            self.useAlpha=1
                        if a>0 and a<1:
                            self.useAlpha=2
                    imagebuf.write(struct.pack("BBBB",r*255,g*255,b*255,a*255))
            rawimages.append(imagebuf)
            
        for i in (0,2,5,1,4,3): # for conversion from blender to uru sequence
            envimage = plMipMap(self.parent)
            envimage.Key.name.set(str(self.Key.name) + "+%i" %i)
            print "Setting cube side %i" % i
            envimage.setRawTexture(rawimages[i],xpart,ypart,self.useAlpha)
            envimage.flags = self.useAlpha # experimental
            envimage.isCubEvMapPart = 1
            self.images.append(envimage)
        
        self.cpb = self.images[0].cpb
        self.flags = self.images[0].flags
        self.type = self.images[0].type
        self.texel_size = self.images[0].texel_size
        self.subtype = self.images[0].subtype
        
        # now set that we processed it all
        self.isProcessed = 1
       
        pass


class plLayer(plLayerInterface):                               #Type 0x06
    def __init__(self,parent,name="unnamed"):
        plLayerInterface.__init__(self,parent,name,0x0006)
        self.i78 = []
        for i in range(5):
            self.i78.append(0)
        #format
        # i78[0]:
        # 0x00000000 just a solid texture (GL_REPLACE) (several things are white)
        # 0x00000002 some sort of blending (alpha?)    (hmm)
        # 0x00000004 mul?                              (everything is black and transparent)
        # 0x00000008 highlight/reflection (add?)       (white and transparent)
        # 0x00000100 ? seen in xpuddleripples (water effect?) (everything is transparent)
        # 0x00002002 ? seen with a texture named "null"
        # 0x00004002 alpha blending?                    (sorta transparent)
        # 0x00000000 alpha channels on some textures are inverted. No alpha on decals.
        # 0x00020000 some untextured objects, and same as -^
        # 0x00040000 no-alpha - some untextured objects
        # 0x00080000 object with alpha-textures are not rendered (100% transparent)
        # 0x00200000 same as 0x0000 but there is alpha on decals
        self.matrix=hsMatrix44()
        self.diffuse=RGBA(1.0,1.0,1.0,1.0,type=1)
        #diffuse must be 1.0,1.0,1.0 for vertex colors, if not the color is mixed with the vertex colors
        self.ambient=RGBA(0.0,0.0,0.0,1.0,type=1)
        self.emissive=RGBA(0.0,0.0,0.0,1.0,type=1)
        self.specular=RGBA(0.0,0.0,0.0,1.0,type=1)
        ##i7C: Some control dword
        ##0x30000	set for reflection maps
        ##0x20000	FunkyRampMult
        ##0x00001	?
        self.i7C = 0
        self.f70=1.0 #Opacity
        self.f80=-1.0 #LODBias?
        self.f88=1.0
        self.texture=UruObjectRef()
        self.shader1=UruObjectRef()
        self.shader2=UruObjectRef()
        self.matrix2=hsMatrix44()


    def changePageRaw(self,sid,did,stype,dtype):
        plLayerInterface.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        plLayerInterface.read(self,buf)
        for i in range(5):
            self.i78[i] = buf.Read32()
        self.matrix.read(buf)
        self.diffuse.read(buf)
        self.ambient.read(buf)
        self.emissive.read(buf)
        self.specular.read(buf)
        self.i7C = buf.Read32()
        self.f70 = buf.ReadFloat()
        self.f80 = buf.ReadFloat()
        self.f88 = buf.ReadFloat()
        if self.f70>1.0 or self.f70<0.0:
            #0.9,0.85,0.75,0.3
            raise "f70 is %f" %self.f70
        #if self.f80!=-1.0:
            #raise "f80 is %f" %self.f80
        #if self.f88 not in [0.0,1.0,10.0,16.0,15.0,20.0,25.0,30.0,34.0,38.0,40.0,45.0,48.0,50.0,56.0,60.0,66.0,70.0,84.0]:
        #    raise "f88 is %f" %self.f88
        self.texture.read(buf)
        self.shader1.read(buf)
        self.shader2.read(buf)
        self.matrix2.read(buf)


    def write(self,buf):
        plLayerInterface.write(self,buf)
        for i in range(5):
            buf.Write32(self.i78[i])
        self.matrix.write(buf)
        self.diffuse.write(buf)
        self.ambient.write(buf)
        self.emissive.write(buf)
        self.specular.write(buf)
        buf.Write32(self.i7C)
        buf.WriteFloat(self.f70)
        buf.WriteFloat(self.f80)
        buf.WriteFloat(self.f88)
        self.texture.write(buf)
        self.shader1.write(buf)
        self.shader2.write(buf)
        self.matrix2.write(buf)


    def dump(self):
        print "BEGIN Layer %s " % self.Key.name
        print "i78: %08X %08X %08X %08X %08X" %(self.i78[0],self.i78[1],self.i78[2],self.i78[3],self.i78[4])
        print self.matrix
        print "Diffuse :" , self.diffuse
        print "Ambient :" , self.ambient
        print "Emissive:" , self.emissive
        print "Specular:" , self.specular
        print "i7C: %08X" %(self.i7C)
        print "3floats: %f %f %f" %(self.float1,self.float2,self.float3)
        print self.texture
        print self.shader1
        print self.shader2
        print self.matrix2
        print "END Layer"


    def getBlenderImage(self):
        resmanager=self.getResManager()
        image=resmanager.findref(self.texture)
        if image!=None and image.data.Key.object_type==0x04:
            return image
        else:
            return None


    def enableAlpha(self):
        # Trylon - added flag settings for useAlpha images
        print "Setting transparency for ", self.texture.Key.name
        self.i78[0] = self.i78[0] | 0x00000002 # 0x00000002 sets colors to alpha
       
    def hasAlpha(self):
        return (self.i78[0] & 0x00000002)

class hsGMaterial(plSynchedObject):                           #Type 0x07
    def __init__(self,parent,name="unnamed"):
        plSynchedObject.__init__(self,parent,name,0x0007)
        #format
        self.i68 = 0 #DWORD
        self.flags=0 #DWORD
        #commented out until hsTArray has full implementation (__getitem__)
        #self.layers=hsTArray()
        #self.lightmaps=hsTArray()
        self.layers=[]
        self.lightmaps=[]
        ####
        self.blendermaterial=None
        self.blendertextures=None


    def changePageRaw(self,sid,did,stype,dtype):
        plSynchedObject.changePageRaw(self,sid,did,stype,dtype)
        for i in self.layers:
            i.changePageRaw(sid,did,stype,dtype)
        for i in self.lightmaps:
            i.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        plSynchedObject.read(self,buf)
        self.i68 = buf.Read32()
        self.flags = buf.Read32()
        #0x0000 = Normal
        #0x1000 = generate lightmap & 1 to 4 layers
        #0x2000 = 2 to 10 layers
        #0x0400 = 1 or 2 layers
        #0x2400 = 2 or 4 layers
        if self.flags not in [0x0000,0x1000,0x2000,0x0400,0x2400]:
            raise "material flags %08X" %self.flags
        il = buf.Read32()
        im = buf.Read32()
        for i in range(il):
            j = UruObjectRef()
            j.read(buf)
            self.layers.append(j)
        for i in range(im):
            j = UruObjectRef()
            j.read(buf)
            self.lightmaps.append(j)
        #count1, count2 = struct.unpack("II",buf.read(8))
        #self.layers=[]
        #self.lightmaps=[]
        #for i in range(count1):
        #    ref = UruObjectRef(self.getVersion())
        #    ref.read(buf)
        #    assert(ref.verify(self.Key))
        #    #Myst 5 note: 0x40 is present only in myst5
        #    chklist=[0x06,0x43,0x8E,0xF0]
        #    if self.getVersion()==6:
        #        chklist.append(0x40)
        #    if ref.Key.object_type not in chklist:
        #        raise "layer %08X" %ref.Key.object_type
        #    self.layers.append(ref)
        #for i in range(count2):
        #    ref = UruObjectRef(self.getVersion())
        #    ref.read(buf)
        #    assert(ref.verify(self.Key))
        #    assert(ref.Key.object_type==0x0006)
        #    self.lightmaps.append(ref)


    def write(self,buf):
        plSynchedObject.write(self,buf)
        buf.Write32(self.i68)
        
        if(len(self.lightmaps) > 0 and len(self.layers) < 5 and self.flags == 0x0000):
            self.flags = 0x1000
        elif(len(self.layers) > 1 and self.flags == 0x0000):
            self.flags = 0x2000

        buf.Write32(self.flags)
        buf.Write32(len(self.layers))
        buf.Write32(len(self.lightmaps))
        #commented out until hsTArray has full implementation (__getitem__)
        #for ref in self.layers.vector:
        for ref in self.layers:
            ref.update(self.Key)
            ref.write(buf)
        #commented out until hsTArray has full implementation (__getitem__)
        #for ref in self.lightmaps.vector:
        for ref in self.lightmaps:
            ref.update(self.Key)
            ref.write(buf)


    def dump(self):
        print "BEGIN hsGMaterial %s " % self.Key.name
        plSynchedObject.dump(self)
        print "flags %08X" % (self.flags)
        print "Layers: %i" %(len(self.layers))
        for ref in self.layers:
            print ref
        print "LightMap: %i" % (len(self.lightmaps))
        for ref in self.lightmaps:
            print ref
        print "END hsGMaterialMaterial"


    def getBlenderMaterial(self):
        if self.blendermaterial!=None:
            return self.blendermaterial
        w = str(self.Key.name) + "%i" %int(random.random()*10000)
        rid=md5.new(w).hexdigest().upper()
        name = str(self.Key.name)[:10] + "t%s" %(rid[:6])
        self.blendermaterial=Blender.Material.New(name)
        mat=self.blendermaterial
        matmode=mat.getMode() | Blender.Material.Modes.VCOL_LIGHT | Blender.Material.Modes.VCOL_PAINT \
        | Blender.Material.Modes.TEXFACE
        mat.setMode(matmode)
        resmanager=self.getResManager()
        if len(self.layers)!=0:
            layer=resmanager.findref(self.layers[0])
            if layer!=None:
                if layer.data.Key.object_type==0x8E:
                    layer=resmanager.findref(layer.data.layer)
                if layer!=None and layer.data.Key.object_type==0x06:
                    #mat.setAdd() #glow factor [0.0 - 1.0]
                    #mat.setAlpha() #alpha (transparency) [0.0 - 1.0]
                    #mat.setAmb() #Ambient color blend factor [0.0 - 1.0]
                    #mat.setEmit() #Emitting light intensity [0.0 - 1.0]
                    #mat.setFlareBoost() #flare's extra strenght [0.0 - 10.0]
                    #mat.setFlareSeed() #flare's offset in the seed table [0-255]
                    #mat.setFlareSize() #ratio flareSize/haloSize
                    ##### see pydoc for several other params
                    #mat.setRef() #refelectivity value [0.0 - 1.0]
                    #mat.setMirCol([r,g,b]) #mirror color triplet (map to ???)
                    col=layer.data.diffuse
                    mat.setRGBCol([col.r,col.g,col.b]) #color triplet (map to diffuse)
                    #mat.setSpec() #specularity value [0.0 - 2.0]
                    #mat.setSpecCol([r,g,b]) #specular color triplet (map to specular)
                    #mat.setSpecTransp() #specular transparency
                else:
                    print "WARNING %s unsupported, or not found!!!!!" %str(self.layers[0])
            else:
                print "WARNING %s unsupported, or not found!!!!!" %str(self.layers[0])
        else:
            print "No layers!!!"
        self.blendertextures=[]
        for i in range(len(self.layers)):
            layer=resmanager.findref(self.layers[i])
            if layer!=None:
                if layer.data.Key.object_type==0x8E:
                    layer=resmanager.findref(layer.data.layer)
                if layer!=None and layer.data.Key.object_type==0x06:
                    self.blendertextures.append(layer.data.getBlenderImage())
                else:
                    self.blendertextures.append(None)
                    print "WARNING %s unsupported, or not found!!!!!" %str(self.layers[i])
            else:
                self.blendertextures.append(None)
                print "WARNING %s unsupported, or not found!!!!!" %str(self.layers[i])
        return mat


    def ensureBasicMaterial(self,mat):
        self.blendermaterial=mat
        name = str(self.Key.name)
        resmanager=self.getResManager()
        root=self.getRoot()
        #commented out until hsTArray has full implementation (__getitem__)
        #self.layers=hsTArray()
        #self.lightmaps=hsTArray()
#        self.lightmaps=[]
        self.flags=0x00
        
        # append a default layer, if there are no layers defined yet
        print "Checking layer list (length is %i):" % len(self.layers)
        
        if(len(self.layers) == 0):
            print "No layers linked, need to add one"
            self.addTextureLayer(None,mat,None)
                
    def layerCount(self):
        return len(self.layers)

    def addTextureLayer(self,texture,mat=None,mtex=None):
       
        name = str(self.Key.name)
        resmanager=self.getResManager()
        root=self.getRoot()
        layer=root.find(0x06,name + "_" + str(len(self.layers)),1)
        #self.layers.append(layer.data.getRef())
        if layer==None:
            raise "Layer not found!"
        if texture!=None: # add the texture if it is there
            if alcconfig.export_textures_to_page_prp:
                texprp=self.parent.prp
            else:
                texprp=resmanager.findPrp("Textures")
            if texprp==None:
                raise "Textures PRP file not found"

            tex=texprp.find(0x04,texture.getName(),1)
            
            doMipMap = 1
            if (mtex) and (mtex.tex.type == Blender.Texture.Types.IMAGE):
                doMipMap = mtex.tex.mipmap
            
            tex.data.setBlenderTexture(texture,doMipMap)
            layer.data.texture=tex.data.getRef()
            
        #layer.data.i78 = (0x00000000,0x00,0x00000000,0x00,0x00009400) # various layer properties
       
        self.setLayerSettings(layer,mat,mtex)
        
        if texture:
            if tex.data.useAlpha:
                layer.data.enableAlpha()
        
        self.layers.append(layer.data.getRef())
        
        return layer

    def addCubicMap(self,texture,mat=None,mtex=None):
        if texture==None:
            return
        name = str(self.Key.name)
        resmanager=self.getResManager()
        root=self.getRoot()
        layer=root.find(0x06,name + "_" + str(len(self.layers)),1)
        #self.layers.append(layer.data.getRef())
        if layer==None:
            raise "Layer not found!"
        if alcconfig.export_textures_to_page_prp:
            texprp=self.parent.prp
        else:
            texprp=resmanager.findPrp("Textures")
        if texprp==None:
            raise "Textures PRP file not found"
        qmap=texprp.find(0x05,texture.getName(),1)
        qmap.data.setBlenderCubicMap(texture)
        layer.data.texture=qmap.data.getRef()
            
        # now set the various layer properties specific to qmaps
        layer.data.i78 = (0x00000002,0x00,0x00000000,0x00,0x00009400)
        layer.data.i7C = 0x00030000
        
        self.setLayerSettings(layer,mat,mtex)
        
        self.layers.append(layer.data.getRef())
        return layer

    def getBlenderTextures(self):
        return self.blendertextures

    def setLayerSettings(self,layer,mat,mtex):
        if (mat):
            
            # get the blender diffuse color
            matR,matG,matB = mat.getRGBCol() #color triplet (map to diffuse)
            
            # get the material's general alpha value:
            matA = mat.getAlpha()
            
            # set Diffuse Color to blender diffuse color and materials alpha
            col=RGBA(matR,matG,matB,matA,type=1)
            layer.data.diffuse=col
            
            # set Ambient Color to materials diffuse color * blender ambient world color and materials alpha
            #get the amount of ambient color it should have
            ambfactor = 1 #mat.getAmb()
            #get the abient color of the world
            world = Blender.World.GetCurrent()
            ambR, ambG, ambB = world.getAmb()
           
            # calculate the ambient colors:
            uruambR = ambR * matR * ambfactor
            uruambG = ambG * matG * ambfactor
            uruambB = ambB * matB * ambfactor

            col=RGBA(matR,matG,matB,matA,type=1)
            layer.data.ambient=col
            
            # set Emissive Color to materials diffuse color * emissive value and materials alpha
            #get the amount of emission it has
            emitfactor = mat.getEmit()
            
            #calculat the emissive colors
            emitR = matR * emitfactor
            emitG = matG * emitfactor
            emitB = matB * emitfactor
            
            col=RGBA(emitR,emitG,emitB,matA,type=1)
            layer.data.emissive=col
            
            # set Specular Color to materials speculat color and materials alpha
            specR,specG,specB = mat.getSpecCol() #specular color triplet (map to specular)
            col=RGBA(specR,specG,specB,matA,type=1)
            layer.data.specular=col
            #mat.setSpecTransp() #specular transparency
        
        if (mtex):
            layer.data.f70 = mtex.colfac # factor how texture blends with color used as alpha blend value
            
            if (mtex.tex.type == Blender.Texture.Types.IMAGE):
                
                pass
    


class plCoordinateInterface(plObjInterface):
    def __init__(self,parent,name="unnamed"):
        plObjInterface.__init__(self,parent,name,0x0015)
        #format
        self.matrix=hsMatrix44() #  <- this one does not make much sense, some objects are correctly placed, and some others not
        self.matrixinv=hsMatrix44()
        self.matrix2=hsMatrix44() # <- everthing seems placed in the correct place, also this seems to be an exact copy
                               # of the matrix found in the spans.
        self.matrix2inv=hsMatrix44()
        self.list=hsTArray([0x01],self.getVersion(),True)

    def changePageRaw(self,sid,did,stype,dtype):
        plObjInterface.changePageRaw(self,sid,did,stype,dtype)
        self.list.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        plObjInterface.read(self,buf)
        assert(self.parentref.Key.object_type==0x01)
        self.matrix.read(buf)
        self.matrixinv.read(buf)
        self.matrix2.read(buf)
        self.matrix2inv.read(buf)
        self.list.ReadVector(buf)


    def write(self,buf):
        if len(self.BitFlags) == 0:
            #initialize bit vector to contain one value: 0
            self.BitFlags.append(0)
        plObjInterface.write(self,buf)
        self.matrix.write(buf)
        self.matrixinv.write(buf)
        self.matrix2.write(buf)
        self.matrix2inv.write(buf)
        self.list.WriteVector(buf)


    def dump(self):
        print "BEGIN CoordinateInterface %s " % self.Key.name
        print "flags %08X, parent: %s" % (self.Flags,self.parentref)
        print "BitFlags: size=%08X" %(len(self.BitFlags))
        for i in self.BitFlags.Data:
            print " %08X" %(i)
        print self.matrix
        print self.matrixinv
        print self.matrix2
        print self.matrix2inv
        print "list %i" %(len(self.list))
        for i in self.list.vector:
            print i
        print "END CoordinateInterface"


    def export_matrices(self,obj):
        m=getMatrix(obj)
        m.transpose()
        self.matrix.set(m) 
        self.matrix2.set(m)
        m=getMatrix(obj)
        m.invert()
        m.transpose()
        self.matrixinv.set(m) 
        self.matrix2inv.set(m)


class plDrawInterface(plObjInterface):
    def __init__(self,parent,name="unnamed"):
        plObjInterface.__init__(self,parent,name,0x0016)
        self.reset()
        self.blenderobjects=[]


    def addSpanSet(self,setnum,spanref):
        self.groups.append(setnum)
        self.spans.append(spanref)


    def changePageRaw(self,sid,did,stype,dtype):
        plObjInterface.changePageRaw(self,sid,did,stype,dtype)
        self.spans.changePageRaw(sid,did,stype,dtype)
        self.vis.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        plObjInterface.read(self,buf)
        self.spans.size = buf.Read32()
        # spans are different than normal UruObjectRef reads, since
        # they have the groups intermingled with the refs
        for i in range(self.spans.size):
            gi = buf.ReadSigned32()
            self.groups.append(gi)
            self.spans.ReadRef(buf)
        self.vis.ReadVector(buf)


    def write(self,buf):
        plObjInterface.write(self,buf)
        buf.Write32(self.spans.size)
        for i in range(self.spans.size):
            buf.WriteSigned32(self.groups[i])
            self.spans[i].update(self.Key)
            self.spans[i].write(buf)
        self.vis.WriteVector(buf)


    def dump(self):
        print "BEGIN DrawInterface %s " % self.Key.name
        print "Flags: %08X, Parent: %s" % (self.Flags,self.parentref)
        print "Set:"
        for i in range(len(self.groups)):
            print "%i - %s" %(self.groups[i],self.spans[i])
        print "Vis: %i" % (len(self.vis))
        for ref in self.vis.vector:
            print ref
        print "END DrawInterface"


    def import_all(self,name=""):
        if name=="":
            name=str(self.Key.name)
        root = self.getRoot()
        for i in range(len(self.groups)):
            group = self.groups[i]
            spanref = self.spans[i]
            spans = root.findref(spanref)
            obj=spans.data.import_object(group,name)
            self.blenderobjects.append(obj)


    def transform(self,matrix):
        matrix=matrix.get()
        matrix.transpose()
        for ob in self.blenderobjects:
            for obj in ob:
                obj.setMatrix(matrix)


    def reset(self):
        self.groups=[]
        if self.getVersion()==6:
            self.spans=hsTArray([0x0049],self.getVersion(),True)
        else:
            self.spans=hsTArray([0x004C],self.getVersion(),True)
        self.vis=hsTArray([0x0116],self.getVersion(),True)


class plSimulationInterface(plObjInterface):
    def __init__(self,parent,name="unnamed"):
        plObjInterface.__init__(self,parent,name,0x001C)
        #format
        self.dwords=[] # was uk2
        self.unknown=0 # was uk3
        self.physical=UruObjectRef(self.getVersion()) #plPhysical


    def changePageRaw(self,sid,did,stype,dtype):
        plObjInterface.changePageRaw(self,sid,did,stype,dtype)
        self.physical.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        plObjInterface.read(self,buf)
        count = buf.Read32()
        for i in range(count):
            self.dwords.append(buf.Read32())
        self.unknown = buf.Read32()
        #0x00 on almost all ages
        #0xFFFFFFFF (-1) on GZMarkerDetector01 (hood)
        if self.unknown not in [0x00,0xFFFFFFFFL]:
            raise "unknown %08X" %self.unknown
        self.physical.read(buf)
        self.physical.verify(self.Key)
        assert(self.physical.Key.object_type==0x3F)


    def write(self,buf):
        plObjInterface.write(self,buf)
        buf.Write32(len(self.dwords))
        for i in self.dwords:
            buf.Write32(self.dwords[i])
        buf.Write32(self.unknown)
        self.physical.write(buf)


    def dump(self):
        print "BEGIN SimulationInterface %s " % self.Key.name
        print "Flags: %08X, Parent: %s" % (self.Flags,self.parentref)
        print "dwords size: %08X unknown: %08X" %(len(self.dwords),self.unknown)
        print "ref %s" %str(self.physical)
        print "END SimulationInterface"


    def import_all(self,name,matrix):
        root=self.getRoot()
        phys=root.findref(self.physical)
        phys.data.import_all(name,matrix)


class plSpawnModifier(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x003D)
        #print "init",pid,ptype
        #format
        self.uk1=0 #U32 = 0
        self.uk2=0


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.uk1, self.uk2 = struct.unpack("II",buf.read(4*2))
        if self.uk1 not in [0x00,]:
            raise "uk1 %08X" %self.uk1
        if self.uk2 not in [0x00,]:
            raise "uk2 %08X" %self.uk2


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("II",self.uk1,self.uk2))


    def dump(self):
        print "BEGIN SpawnModifier %s " % self.Key.name
        print "END SpawnModifier"


class plHKPhysical(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x003F)
        #format
        self.flags=0 #U32 (always)
        self.position=[0.0,0.0,0.0] #position?
        self.orientation=[1.0,0.0,0.0,0.0] #orientation?
        self.mass=0.0 #mass? [if 0, coordinate interface and position are ignored]
        self.rc=0.5 #coefient de fregament?
        self.el=0.0 #Elasticity????
        self.format=1 #U32
        # 0x01 Bounding Box (then there should be only 8 vertexs)
        # 0x02 Bounding Sphere (NPI)
        # 0x03 ConvexHull (no face list) - you must compute it, hah!
        # 0x04 ConcaveMesh - Triangles
        # 0x05 PolygonSoup - Terrain
        self.uk1=0    #U16
        # 0x00 almost always
        # 0x01 TreeDummy02 (sphere02)
        self.type=0x0200   #U16
        # 0x0000 Camera colliders, ConeCollision
        # 0x0002 Nidea (onYeeshaNoGlow)- (was:[avatar don't interacts with collision] [confirm if objects interact or not between them])
        # 0x0100 Kickable object? - enable collision with avatars - save state to disk
        # 0x0200 Physical world? - enable collision with avatars - do not save state to disk
        # 0x0400 Game objects - Region sensor (buttons...) [avatar don't interacts with collision]
        self.flags1=0 #U32
        self.flags2=0x02000000 #U32
        # 0x03840002 - YeeshNoGlow
        # 0x03860000 - Quab
        # 0x03800004 - RollingRock01 (tldnSlaveCave)
        # 0x03840000 - DrWatson (interesting...)
        # 0x03800002 - PhysBoard02 (cleft)
        # 0x01800002 - TreeDummy02 (sphere02)
        # 0x00800000 - no effect?
        # 0x02000000 - enables collision with static objects, and other objects
        # 0x01000000 - no effect?
        self.flags3=0 #U16
        ###if BoundingSphere
        self.a=0 #x?
        self.b=0 #y?
        self.c=0 #z?
        self.d=0 #radius?
        ###else
        self.vertexs=[]
        ###if !ConvexHull
        self.faces=[]
        ###fi
        ###fi
        self.sceneobject=UruObjectRef()
        self.uk2=0x01 #U32 (always)
        self.flags4=0x00000000 #U32
        # 0x0001 kDisable
        # 0x0002 kWeightless
        # 0x0004 kPinned
        # 0x0008 kWarp
        # 0x0010 kUpright
        # 0x0020 kPassive
        # 0x0040 kRotationForces
        # 0x0080 kCameraAvoidObject
        # 0x0100 kPhysAnim
        # 0x0200 kStartInactive
        # 0x0400 kNoSynchronize
        # 0x0800 kSuppressed
        self.scene=UruObjectRef()
        self.uk3=0x00000004 #U32
        # 0x41 - Box06 (tldnHarvest)
        # 0x40 - Dissables friction (between avatars and the collider)
        # 0x20 - Refl1 (tldnHarvest)
        # 0x10 - YeeshaNoGlow
        # 0x08 - wall_blocker_medium
        # 0x04 - Camera doesn't go through object walls.
        # 0x01 - -??
        self.subworld=UruObjectRef()
        self.sndgroup=UruObjectRef()

    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)
        self.sceneobject.changePageRaw(sid,did,stype,dtype)
        self.scene.changePageRaw(sid,did,stype,dtype)
        self.subworld.changePageRaw(sid,did,stype,dtype)
        self.sndgroup.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.flags, = struct.unpack("I",buf.read(4))
        if self.flags not in [0x00,]:
            raise "flags %08X" %self.flags
        f1, f2, f3, f4, f5, f6, f7 = struct.unpack("fffffff",buf.read(4*7))
        self.position=[f1,f2,f3]
        self.orientation=[f4,f5,f6,f7]
        self.mass, self.rc, self.el = struct.unpack("fff",buf.read(4*3))
        self.format, = struct.unpack("I",buf.read(4))
        if self.format not in [0x01,0x02,0x03,0x04,0x05]:
            raise "format %08X" %self.format
        self.uk1, self.type = struct.unpack("HH",buf.read(4))
        if self.uk1 not in [0x00,0x02]:
            raise "uk1 %08X" %self.uk1
        #if self.type not in [0x00,0x02,0x0100,0x0200,0x0400]:
            #raise "type %08X" %self.type
        self.flags1, self.flags2 = struct.unpack("II",buf.read(4*2))
        #if self.flags1 not in [0x00,0x020000,0x800000,0x01000000,0x01020000,0x08000000]:
        #    raise "flags1 %08X" %self.flags1
        #if self.flags2 not in [0x00,0x020000,0x01000000,0x02000000,0x01020000,\
        #                       0x01800002,0x03800000,0x03820000,0x03800002,0x03800004,\
        #                       0x03840000,0x03860000,0x03840002]:
        #    raise "flags2 %08X" %self.flags2
        self.flags3, = struct.unpack("H",buf.read(2))
        #if self.flags3 not in [0x00,0x0101]:
        #    raise "flags3 %08X" %self.flags3
        if self.format==0x02: #BoundingSphere
            self.a, self.b, self.c, self.d = struct.unpack("ffff",buf.read(4*4))
        else:
            count, = struct.unpack("I",buf.read(4))
            for i in range(count):
                x, y, z = struct.unpack("fff",buf.read(4*3))
                vertex = [x,y,z]
                self.vertexs.append(vertex)
            if self.format!=3: #not ConvexHull
                count, = struct.unpack("I",buf.read(4))
                for i in range(count):
                    a, b, c = struct.unpack("HHH",buf.read(2*3))
                    face = [a,b,c]
                    self.faces.append(face)
            else: #convexHull
                #DONE, with the vertexs, build a face list
                c=alcConvexHull(self.vertexs)
                self.vertexs=c.vertexs
                self.faces=c.faces
        self.sceneobject.setVersion(self.getVersion())
        self.sceneobject.read(buf)
        self.sceneobject.verify(self.Key)
        assert(self.sceneobject.Key.object_type==0x01) 
        self.uk2, self.flags4 = struct.unpack("II",buf.read(4*2))
        if self.uk2 not in [0x01,]:
            raise "uk2 %08X" %self.uk2
        #if self.flags4 not in [0x00,0x04,0x10,0x24,0x80,0xA4,0x0100,0x0104,0x0124,0x0184,0x0200,0x300]:
        #    raise "flags4 %08X" %self.flags4
        self.scene.setVersion(self.getVersion())
        self.scene.read(buf)
        self.scene.verify(self.Key)
        assert(self.scene.Key.object_type==0x00)
        self.uk3, = struct.unpack("I",buf.read(4*1))
        if self.uk3 not in [0x00,0x01,0x02,0x04,0x05,0x08,0x20,0x40,0x41,0x44,0x45,0x80]:
            raise "uk3 %08X" %self.uk3
        self.subworld.setVersion(self.getVersion())
        self.subworld.read(buf)
        self.subworld.verify(self.Key)
        self.sndgroup.setVersion(self.getVersion())
        self.sndgroup.read(buf)
        self.sndgroup.verify(self.Key)


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("I",self.flags))
        buf.write(struct.pack("fffffff",self.position[0],self.position[1],self.position[2],\
                              self.orientation[0],self.orientation[1],self.orientation[2],self.orientation[3]))
        buf.write(struct.pack("fff",self.mass,self.rc,self.el))
        buf.write(struct.pack("I",self.format))
        buf.write(struct.pack("HH",self.uk1,self.type))
        buf.write(struct.pack("II",self.flags1,self.flags2))
        buf.write(struct.pack("H",self.flags3))
        if self.format==0x02: #BoundingSphere
            buf.write(struct.pack("ffff",self.a,self.b,self.c,self.d))
        else:
            count = len(self.vertexs)
            buf.write(struct.pack("I",count))
            for v in self.vertexs:
                for vi in v:
                    buf.write(struct.pack("f",vi))
            if self.format!=3: #not ConvexHull
                count = len(self.faces)
                buf.write(struct.pack("I",count))
                for f in self.faces:
                    for fi in f:
                        buf.write(struct.pack("H",fi))
        self.sceneobject.write(buf)
        buf.write(struct.pack("II",self.uk2,self.flags4))
        self.scene.write(buf)
        #print self.uk3
        buf.write(struct.pack("I",self.uk3))
        self.subworld.write(buf)
        self.sndgroup.write(buf)


    def dump(self):
        print "BEGIN HKPhysical %s " % self.Key.name
        print "flags %08X" % (self.flags)
        print "Pos: %f %f %f" %(self.position[0],self.position[1],self.position[2])
        print "Ori: %f %f %f %f" %(self.orientation[0],self.orientation[1],self.orientation[2],self.orientation[3])
        print "Mass: %f, rc: %f, el: %f" %(self.mass,self.rc,self.el)
        print "format: %02X, type: %02X" %(self.format,self.type)
        print "flags %08X %08X %08X" %(self.flags1,self.flags2,self.flags3)
        if self.format==2:
            print "Sphere %f %f %f %f" %(self.a,self.b,self.c,self.d)
        else:
            print "%i vertexs, %i faces" %(len(self.vertexs),len(self.faces))
        print "sceneobj %s" %str(self.sceneobject)
        print "flags4 %08X" %(self.flags4)
        print "scene %s" %str(self.scene)
        print "uk3 %08X" %(self.uk3)
        print "subworld %s" %str(self.subworld)
        print "sndgroup %s" %str(self.sndgroup)
        print "END Physical"


    def import_all(self,name,matrix):
        the_name=alcUniqueName(name)
        if self.format in [0x01,0x03,0x04,0x05]:
            obj=alcCreateMesh(the_name,self.vertexs,self.faces)
            m=matrix.get()
            m.transpose()
            obj.setMatrix(m)
            obj.layers=[2,]
            obj.addProperty("name",str(name))
            obj.addProperty("page_num",str(self.getPageNum()))
            obj.addProperty("alctype","collider")
            obj.addProperty("col_type",str(self.format))
            obj.addProperty("mass",float(self.mass))
            obj.addProperty("rc",float(self.rc))
            obj.addProperty("el",float(self.el))
            obj.addProperty("col_flags0",str(alcHex2Ascii(self.type,2)))
            obj.addProperty("col_flags1",str(alcHex2Ascii(self.flags1,4)))
            obj.addProperty("col_flags2",str(alcHex2Ascii(self.flags2,4)))
            obj.addProperty("col_flags3",str(alcHex2Ascii(self.flags3,2)))
            obj.addProperty("col_flags4",str(alcHex2Ascii(self.flags4,4)))
            obj.addProperty("col_flags5",str(alcHex2Ascii(self.uk3,4)))
            obj.drawType=2
            #if name=="StLog28":
                #print m
                #raise "stop"
            #trylon added to be able to import swimcurrent settings
            #save the blend object
            self.blendobj = obj

  
    def export_object(self,obj,isdynamic=0):
        try:
            p=obj.getProperty("mass")
            self.mass=float(p.getData())
        except AttributeError:
            pass
        try:
            p=obj.getProperty("rc")
            self.rc=float(p.getData())
        except AttributeError:
            pass
        try:
            p=obj.getProperty("el")
            self.el=float(p.getData())
        except AttributeError:
            pass
        try:
            p=obj.getProperty("col_flags0")
            self.type=alcAscii2Hex(str(p.getData()),2)
        except AttributeError:
            pass
        try:
            p=obj.getProperty("col_flags1")
            self.flags1=alcAscii2Hex(str(p.getData()),4)
        except AttributeError:
            pass
        try:
            p=obj.getProperty("col_flags2")
            self.flags2=alcAscii2Hex(str(p.getData()),4)
        except AttributeError:
            pass
        try:
            p=obj.getProperty("col_flags3")
            self.flags3=alcAscii2Hex(str(p.getData()),2)
        except AttributeError:
            pass
        try:
            p=obj.getProperty("col_flags4")
            self.flags4=alcAscii2Hex(str(p.getData()),4)
        except AttributeError:
            pass
        try:
            p=obj.getProperty("col_flags5")
            self.uk3=alcAscii2Hex(str(p.getData()),4)
        except AttributeError:
            pass
        if self.format not in [0x01,0x02,0x03,0x04,0x05,0x06,0x07]:
            self.format=0x03
        if self.format==0x01: #Bounding box
            verts=obj.getBoundBox()
            matrix=hsMatrix44()
            m=getMatrix(obj)
            m.invert()
            m.transpose()
            matrix.set(m)
            #transform to local
            tverts=[]
            for vi in verts:
                v=Vertex(vi[0],vi[1],vi[2])
                v.transform(matrix)
                va=[v.x,v.y,v.z]
                tverts.append(va)
            verts=tverts
            #
            c=alcConvexHull(verts)
            self.vertexs=c.vertexs
            self.faces=c.faces
        elif self.format==0x02: #Bounding sphere
            self.vertexs=[]
            self.faces=[]
            #DONE
            verts=[]
            #transform to world for static objects
            matrix=hsMatrix44()
            m=getMatrix(obj)
            m.transpose()
            matrix.set(m)
            for vert in obj.data.verts:
                #v=Vertex(vert.co[0],vert.co[1],vert.co[2])
                v=[vert.co[0],vert.co[1],vert.co[2]]
                #v.transform(matrix) #slow very slow - user should pass already transformed objects
                #v=[v.x,v.y,v.z]
                verts.append(v)
            max=0
            print "computing distance..."
            for i in verts:
                for e in verts:
                    d=distance(i,e)
                    if d>max:
                        max=d
            self.d=max/2
        elif self.format in [0x03,0x06,0x07]: #Convex Hull
            verts=[]
            for vert in obj.data.verts:
                v=[vert.co[0],vert.co[1],vert.co[2]]
                verts.append(v)
            c=alcConvexHull(verts)
            self.vertexs=c.vertexs
            if self.format==0x03:
                self.faces=[]
            else:
                self.faces=c.faces
                self.format=self.format-2
        elif self.format in [0x04,0x05]: #others
            self.vertexs=[]
            self.faces=[]
            for vert in obj.data.verts:
                v=[vert.co[0],vert.co[1],vert.co[2]]
                self.vertexs.append(v)
            for face in obj.data.faces:
                n=len(face.v)
                if n<3:
                    continue
                elif n==3:
                    tface=[]
                    for i in range(3):
                        tface.append(face.v[i].index)
                    self.faces.append(tface)
                elif n==4:
                    tface=[]
                    for i in range(3):
                        tface.append(face.v[i].index)
                    self.faces.append(tface)
                    tface=[]
                    for i in (0,2,3):
                        tface.append(face.v[i].index)
                    self.faces.append(tface)
                else:
                    raise RuntimeError
        #set position and other attribs
        if (self.mass==0 and isdynamic == 0): 
            #transform to world for static objects
            tverts=[]
            matrix=hsMatrix44()
            m=getMatrix(obj)
            m.transpose()
            matrix.set(m)
            for vi in self.vertexs:
                v=Vertex(vi[0],vi[1],vi[2])
                v.transform(matrix)
                va=[v.x,v.y,v.z]
                tverts.append(va)
            self.vertexs=tverts
        else:
            x,y,z = obj.getLocation()
            self.position=[x,y,z]

class plViewFaceModifier(plSingleModifier):
    
    def __init__(self, parent, name="unnamed", type=0x0040):
        plSingleModifier.__init__(self, parent, name, type)
        self.V6C = Vertex()
        self.M78 = hsMatrix44()
        self.MBC = hsMatrix44()
        self.V110 = Vertex()
        self.CA11C = hsBounds3Ext()
        self.SORef = UruObjectRef()

    def read(self, buf):
        plSingleModifier.read(self,buf)
        self.V6C.read(buf)
        self.M78.read(buf)
        self.MBC.read(buf)
        if(self.bitVector.Data[0] & 0x00000100):
            self.SORef.setVersion(self.getVersion())
            self.SORef.read(buf)
        self.V110.read(buf)
        if(self.bitVector.Data[0] & 0x0000800):
            self.CA11C.read(buf)

    def write(self, buf):
        plSingleModifier.write(self,buf)
        self.V6C.write(buf)
        self.M78.write(buf)
        self.MBC.write(buf)
        if(self.bitVector.Data[0] & 0x00000100):
            self.SORef.write(buf)
        self.V110.write(buf)
        if(self.bitVector.Data[0] & 0x0000800):
            self.CA11C.write(buf) # only write this if needed

    def dump(self):
        plSingleModifier.dump(self)
        print "Vertex1:",
        print self.V6C
        print "Matrix1:",
        print self.M78
        print "Matrix2:",
        print self.MBC
        print "Vertex2:",
        print self.V110
        print "END plViewFaceModifier"

    def import_obj(self,obj):
        if(self.bitVector.Count > 0):
            obj.addProperty("sprite_flags",str(alcHex2Ascii(self.bitVector.Data[0],4)))
        else:
            obj.addProperty("sprite_flags",str(alcHex2Ascii(0x00,4)))
    
    def export_obj(self,obj,prp):

        try:
            p=obj.getProperty("sprite_flags")
            BVData=alcAscii2Hex(str(p.getData()),4)
        except AttributeError:
            BVData = 0x821
            pass
        self.bitVector.append(BVData)

        # get the matrices
        LocalToWorld=hsMatrix44()
        m=getMatrix(obj)
        m.transpose()
        LocalToWorld.set(m)
        self.M78 = LocalToWorld

        WorldToLocal=hsMatrix44()
        m=getMatrix(obj)
        m.invert() 
        m.transpose()
        WorldToLocal.set(m)
        self.MBC = WorldToLocal

        #now see if we need to add a bounding box
        if(self.bitVector.Data[0] & 0x0000800):
            # build up a simple bounding box
            # get the object center
            vorigin = Vertex(0,0,0)
            vorigin.transform(LocalToWorld)
    
            # now we need to build up a bounding cube
            # get the objects bounding box
            verts=obj.getBoundBox()
    
            vmin = Vertex(verts[0][0],verts[0][1],verts[0][2])
            vmin.transform(WorldToLocal)
            vmax = Vertex(verts[6][0],verts[6][1],verts[6][2])
            vmax.transform(WorldToLocal)    
            # now determine the largest Delta[XYZ]
            dmax = 0
            dx = vmax.x-vmin.x
            if(dx > dmax):
                dmax = dx
            dy = vmax.y-vmin.y
            if(dy > dmax):
                dmax = dy
            dz = vmax.z-vmin.z
            if(dz > dmax):
                dmax = dz        
        
            # now determine if the box lies withing the origin on X,Y or Z
            if(vmin.x > 0 and vmax.x > 0):
                if(vmin.x > vmax.x):
                    offsetx = vmax.x
                else:
                    offsetx = vmin.x
            elif(vmin.x < 0 and vmax.x < 0):
                if(vmin.x < vmax.x):
                    offsetx = vmax.x
                else:
                    offsetx = vmin.x
            else:
                offsetx = 0
            
            if(vmin.y > 0 and vmax.y > 0):
                if(vmin.y > vmax.y):
                    offsety = vmax.y
                else:
                    offsety = vmin.y
            elif(vmin.y < 0 and vmax.y < 0):
                if(vmin.y < vmax.y):
                    offsety = vmax.y
                else:
                    offsety = vmin.y
            else:
                offsety = 0
            
            if(vmin.z > 0 and vmax.z > 0):
                if(vmin.z > vmax.z):
                    offsetz = vmax.z
                else:
                    offsetz = vmin.z
            elif(vmin.z < 0 and vmax.z < 0):
                if(vmin.z < vmax.z):
                    offsetz = vmax.z
                else:
                    offsetz = vmin.z
            else:
                offsetz = 0
            
            # now determine the approximate minimum distance to the object from the origin
            offsetxy = math.sqrt(math.pow(offsetx,2)+math.pow(offsety,2))
            roffset = math.sqrt(math.pow(offsetz,2)+math.pow(offsetxy,2))
        
            # take the roffset in account with making the bounding cube, and make it slightly 
            # larger than the bare minimum (1.1 times larger)
            
            rmax = ((dmax/2) + roffset) * 1.1
            
            # now build up the new bounding box:
            vmin = Vertex(vorigin.x - rmax,vorigin.y - rmax,vorigin.z - rmax)
            vmax = Vertex(vorigin.x + rmax,vorigin.y + rmax,vorigin.z + rmax)
    
            ##debug## alcCreateMesh("Temp",[[vmin.x,vmin.y,vmin.z],[vmax.x,vmax.y,vmax.z]],[[0,1,0]])
    
            self.CA11C.min = vmin
            self.CA11C.max = vmax
            self.CA11C.flags = 0x01 # a simple bounding box without any other data
        
        self.V6C = Vertex(1,1,1)
        self.V110 = Vertex(0,0,0)


#class plDrawableSpans is in uruspans.py
#0x4C

#list1
class plDirectionalLightInfo(hsKeyedObject):    
    def __init__(self,parent,name="unnamed",type=0x0055):
        hsKeyedObject.__init__(self,parent,name,type)
        #format
        self.uk1=0 #U32 = 0
        self.parentref=UruObjectRef()
        self.word1=0x01 #always
        self.word2=0 #power/strenght?? flags?
        ## 0x0001 ?? (omni) GameTableRTOmni
        ## 0x0002 shadow only? (0x0200??)
        ## 0x0008 animated? (omni) RTImagerFlickerOmni01
        ## 0x0009 (omni) RTMaintainerLight (kemoGarden)
        ## 0x0010 (omni) hutinteriorcenterlight
        ## 0x0011 (omni) RTOmniLight20 (Ercana_ControlRoom)
        ## 0x0018 (omni) RTHallwayOmniAnimated (MaintRoom03)
        ## 0x0030 (dire) desertcol
        ## 0x0031 (omni) RTOmniLight05 (hood)
        ## 0x0038 (omni) RTStoveOutsideLight02
        ## 0x0039 (omni) RTMaintainerLight
        ## 0x00B8 (spot) RTFissureBrightSpot
        ## 0x0100 (omni) RTOmniLight02 (gallery)
        ## 0x0101 (omni) RTCourtYardLight08 (city_courtyard)
        ## 0x0108 (omni) RT-GlowOrange (BahroCave02)
        ## 0x0110 (dire) RTDirLight05 (kemoGarden)
        ## 0x0130 (dire) Sunshine
        ## 0x0138 (omni) RTGZLight (BaronCityOffice)
        ## 0x0200 - shadow light??? (omni) RTShadowOnlyLight
        ## 0x0300 (omni) RTshadowLightCD (canyon)
        ## 0x0301 (omni) RTCourtYardLight18 (city_courtyard)
        ## 0x0322 (spot) RTSpotLight01 (grsnExterior)
        ## 0x0400 (spot) RTSpotLight01 (sphere02)
        ## 0x0401 (omni) RTOmniLight16 (Descent)
        ## 0x0408 (omni) RTomniRed06 (YeeshaCave)
        ## 0x0430 (omni) RTOmniLight01 (BahroCave02)
        ## 0x0438 (omni) RTOmniLighFlameAVATAR (BahroCave02)
        ## 0x0538 (dire) RTDir-SunMain (giraCanyon)
        ## 0x0638 (dire) RTDir-MoonShadow (giraCanyon)
        ## 0x0600 (omni) RTShadowLight
        self.word3=0
        self.word4=0
        self.word5=0
        self.float1=1.0 #(always)
        self.color1=RGBA(0.0,0.0,0.0,1.0,type=1) #RGB color - alpha is for animated lights: timer value for "off"??
        self.color2=RGBA(0.0,0.0,0.0,1.0,type=1) #Other RGB and timer???
        self.matrix=hsMatrix44()
        self.matrixinv=hsMatrix44()
        self.matrix2=hsMatrix44()
        self.matrix2inv=hsMatrix44()
        self.missing=UruObjectRef()
        self.softvolume=UruObjectRef()
        self.scenenode=UruObjectRef()
        self.visregions=[]


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)
        self.parentref.changePageRaw(sid,did,stype,dtype)
        self.missing.changePageRaw(sid,did,stype,dtype)
        self.softvolume.changePageRaw(sid,did,stype,dtype)
        self.scenenode.changePageRaw(sid,did,stype,dtype)
        for i in self.visregions:
            i.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.uk1, = struct.unpack("I",buf.read(4*1))
        if self.uk1 not in [0x00,]:
            raise "uk1 %08X" %self.uk1
        self.parentref.read(buf)
        self.word1, = struct.unpack("I",buf.read(4))
        if self.word1 not in [0x01,]:
            raise "word1 is %08X" %self.word1
        self.word2, = struct.unpack("I",buf.read(4))
##        if self.word2 not in [0x00,0x01,0x08,0x09,0x10,0x11,0x18,0x30,0x31,0x38,0x39,\
##                              0xB8,0x0100,0x0101,0x0108,0x0110,0x0130,0x0138,0x0200,\
##                              0x0230,0x0300,0x0301,\
##                              0x0400,0x0401,0x0408,0x0430,0x0438,0x0538,0x0600,0x0638]:
##            raise "word2 is %08X" %self.word2
        self.word3, = struct.unpack("I",buf.read(4))
        if self.word3 not in [0x00,]:
            raise "word3 is %08X" %self.word3
        self.word4, = struct.unpack("I",buf.read(4))
        if self.word4 not in [0x00,]:
            raise "word4 is %08X" %self.word4
        self.word5, = struct.unpack("I",buf.read(4))
        if self.word5 not in [0x00,]:
            raise "word5 is %08X" %self.word5
        self.float1, = struct.unpack("f",buf.read(4))
        if self.float1 not in [1.0]:
            raise "float1 is %f" %self.float1
        self.color1.read(buf)
        self.color2.read(buf)
        self.matrix.read(buf)
        self.matrixinv.read(buf)
        self.matrix2.read(buf)
        self.matrix2inv.read(buf)
        self.missing.read(buf)
        self.softvolume.read(buf)
        self.scenenode.read(buf)
        count, = struct.unpack("I",buf.read(4))
        self.visregions=[]
        for i in range(count):
            ref=UruObjectRef()
            ref.read(buf)
            self.visregions.append(ref)


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("I",self.uk1))
        self.parentref.write(buf)
        buf.write(struct.pack("IIIII",self.word1,self.word2,self.word3,self.word4,self.word5))
        buf.write(struct.pack("f",self.float1))
        self.color1.write(buf)
        self.color2.write(buf)
        self.matrix.write(buf)
        self.matrixinv.write(buf)
        self.matrix2.write(buf)
        self.matrix2inv.write(buf)
        self.missing.write(buf)
        self.softvolume.write(buf)
        self.scenenode.write(buf)
        buf.write(struct.pack("I",len(self.visregions)))
        for vis in self.visregions:
            vis.write(buf)


    def dump(self):
        print "BEGIN DirectionalLightInfo %s " % self.Key.name
        print "parent: %s" %(str(self.parentref))
        print "5words: %04X %04X %04X %04X %04X" %(self.word1,self.word2,self.word3,self.word4,self.word5)
        print self.color1
        print self.color2
        print self.matrix
        print self.matrixinv
        print self.matrix2
        print self.matrix2inv
        print self.missing
        print self.softvolume
        print self.scenenode
        print "END DirectionalLightInfo"


    def import_all(self,name,matrix):
        #the_name=alcUniqueName(name)
        obj=Blender.Object.New("Lamp",name)
        if self.Key.object_type==0x55:
            type="Area"
        elif self.Key.object_type==0x56:
            type="Lamp"
        elif self.Key.object_type==0x57:
            type="Spot"
        else:
            raise "Unknown Lamp type"
        lamp=Blender.Lamp.New(type,name)
        obj.link(lamp)
        scene = Blender.Scene.getCurrent()
        scene.link(obj)
        obj.data.energy=0.5
        m=matrix.get()
        m.transpose()
        obj.setMatrix(m)
        obj.layers=[1,]
        obj.addProperty("name",str(name))
        obj.addProperty("page_num",str(self.getPageNum()))
        obj.addProperty("alpha1",float(self.color1.a))
        obj.addProperty("alpha2",float(self.color2.a))
        obj.addProperty("a",float(self.color2.r))
        obj.addProperty("b",float(self.color2.g))
        obj.addProperty("c",float(self.color2.b))
        lamp.col=[self.color1.r,self.color1.g,self.color1.b]
        a=struct.pack(">I",self.word2)
        b=binascii.hexlify(a).upper()
        obj.addProperty("flags",b)
        return obj


    def export_object(self,obj):
        lamp=obj.data
        #set lighting flags
        try:
            p=obj.getProperty("flags")
            name=str(p.getData())
            while len(name)<8:
                name = "0" + name
            b=binascii.unhexlify(str(name))
            l,=struct.unpack(">I",b)
        except AttributeError:
            l=0
        self.word2=l
        try:
            p=obj.getProperty("alpha1")
            alpha1=float(p.getData())
        except AttributeError:
            alpha1=1.0
        self.color1=RGBA(lamp.col[0],lamp.col[1],lamp.col[2],alpha1,type=1)
        try:
            p=obj.getProperty("alpha2")
            alpha2=float(p.getData())
        except AttributeError:
            alpha2=1.0
        try:
            p=obj.getProperty("a")
            a=float(p.getData())
        except AttributeError:
            a=0
        try:
            p=obj.getProperty("b")
            b=float(p.getData())
        except AttributeError:
            b=0
        try:
            p=obj.getProperty("c")
            c=float(p.getData())
        except AttributeError:
            c=0
        self.color2=RGBA(a,b,c,alpha2,type=1)
        m=getMatrix(obj)
        m.transpose()

        # Note: matrix and matrix2 are multiplied together in order to
        # transform the light.  Placing the same transform in both
        # matrices will perform the transform twice.  So, the copying
        # of the Blender object's matrix to both matrices was
        # commented out.
        #self.matrix.set(m)
        self.matrix2.set(m)
        m.invert()
        #self.matrixinv.set(m)
        self.matrix2inv.set(m)


#list1
class plOmniLightInfo(plDirectionalLightInfo):    
    def __init__(self,parent,name="unnamed",type=0x0056):
        plDirectionalLightInfo.__init__(self,parent,name,type)
        #format
        self.k0=1.0
        self.k1=0.0
        self.k2=1.0
        self.cutoff=10.0


    def changePageRaw(self,sid,did,stype,dtype):
        plDirectionalLightInfo.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        plDirectionalLightInfo.read(self,buf)
        self.k0, self.k1, self.k2, self.cutoff = struct.unpack("ffff",buf.read(4*4))


    def write(self,buf):
        plDirectionalLightInfo.write(self,buf)
        buf.write(struct.pack("ffff",self.k0, self.k1, self.k2, self.cutoff))


    def dump(self):
        print "BEGIN OmniLightInfo %s " % self.Key.name
        plDirectionalLightInfo.dump(self)
        print self.k0,self.k1,self.k2,self.cutoff
        print "END OmniLightInfo"


    def import_all(self,name,matrix):
        obj=plDirectionalLightInfo.import_all(self,name,matrix)
        obj.data.dist=self.cutoff
        obj.data.mode = obj.data.mode | Blender.Lamp.Modes["Quad"]
        #obj.data.energy=self.k0 #???
        obj.addProperty("k0",float(self.k0))
        obj.data.quad1=self.k1
        obj.data.quad2=self.k2
        return obj


    def export_object(self,obj):
        plDirectionalLightInfo.export_object(self,obj)
        self.cutoff=obj.data.dist
        self.k1=obj.data.quad1
        self.k2=obj.data.quad2
        try:
            p=obj.getProperty("k0")
            self.k0=float(p.getData())
        except AttributeError:
            pass


#list1
class plSpotLightInfo(plOmniLightInfo):    
    def __init__(self,parent,name="unnamed",type=0x0057):
        plOmniLightInfo.__init__(self,parent,name,type)
        #format
        self.uk11=1.0
        self.inner=0.0
        self.outter=0.0


    def changePageRaw(self,sid,did,stype,dtype):
        plOmniLightInfo.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        plOmniLightInfo.read(self,buf)
        self.uk11, self.inner, self.outter = struct.unpack("fff",buf.read(4*3))


    def write(self,buf):
        plOmniLightInfo.write(self,buf)
        buf.write(struct.pack("fff",self.uk11, self.inner, self.outter))


    def dump(self):
        print "BEGIN SpotLightInfo %s " % self.Key.name
        plOmniLightInfo.dump(self)
        print self.uk11,self.inner,self.outter
        print "END SpotLightInfo"


    def import_all(self,name,matrix):
        obj=plOmniLightInfo.import_all(self,name,matrix)
        obj.addProperty("uk11",float(self.uk11))
        lamp=obj.data
        spotSizeDeg = self.outter * 180.0 / 3.1415926536
        lamp.setSpotSize(spotSizeDeg)
        blend=0.0;
        if self.outter > 0:
            blend = self.inner / self.outter
        lamp.setSpotBlend(blend)


    def export_object(self,obj):
        lamp=obj.data
        plOmniLightInfo.export_object(self,obj)
        try:
            p=obj.getProperty("uk11")
            self.uk11=float(p.getData())
        except AttributeError:
            pass
        spotSizeDeg = lamp.getSpotSize()
        self.outter = spotSizeDeg * 3.1415926536 / 180.0
        blend = lamp.getSpotBlend()
        self.inner = blend * self.outter


#list2
class plAGModifier(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x006C)
        #format
        #U32 0
        #U32 0
        self.string=Ustr()


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        unk1, unk2 = struct.unpack("II",buf.read(8))
        ##myst5 unk1: 0x04
        if unk1 not in [0x00,]:
            raise "unk1 %08X" %unk1
        #assert(unk1==0)
        assert(unk2==0)
        self.string.read(buf)


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("II",0,0))
        self.string.write(buf)

    def dump(self):
        print "BEGIN AGModifier %s " % self.Key.name
        print str(self.string)
        print "END AGModifier"


class plAGMasterMod(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x006D)
        #format
        #U32 0
        self.str=str32(type=1)
        self.anims=[] #armature anims


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)
        for i in self.anims:
            i.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        unk1, = struct.unpack("I",buf.read(4))
        ##myst5 unk1: 0x04
        if unk1 not in [0x00,]:
            raise "unk1 %08X" %unk1
        #On tpots always "", on old versions there is something here
        self.str.read(buf)
        if self.getVersion()==6:
            count1, = struct.unpack("H",buf.read(2))
        else:
            count1, = struct.unpack("I",buf.read(4))
        self.anims=[]
        for i in range(count1):
            ref = UruObjectRef(self.getVersion())
            ref.read(buf)
            #print ref, self.Key
            assert(ref.verify(self.Key))
            if ref.Key.object_type not in [0xF1,0xF2]:
                raise "armature anim %08X" %ref.Key.object_type
            self.anims.append(ref)


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("I",0))
        self.str.write(buf)
        buf.write(struct.pack("I",len(self.anims)))
        for ref in self.anims:
            ref.update(self.Key)
            ref.write(buf)


    def dump(self):
        print "BEGIN AGMasterMod %s " % self.Key.name
        print str(self.str)
        print "Anims: %i" %(len(self.anims))
        for ref in self.anims:
            print ref
        print "END AGMasterMod"


class plLayerLinkAnimation(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x008E)
        #format
        self.unk1=0x00 #U32 0
        self.layer=UruObjectRef() #0x06
        #U16 0x8000 x4
        self.xword=0x2D
        self.sceneobject=UruObjectRef()


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)
        self.layer.changePageRaw(sid,did,stype,dtype)
        self.sceneobject.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        unk1,  = struct.unpack("I",buf.read(4))
        if unk1 not in [0x00,]:
            raise "unk1 %08X" %unk1
        self.layer.read(buf)
        if self.layer.Key.object_type not in [0x06,]:
            assert "layer %08X" %(self.layer.Key.object_type)
        for i in range(4):
            word, = struct.unpack("H",buf.read(2))
            assert(word==0x8000)
        word, = struct.unpack("H",buf.read(2))
        assert(word==0x022F)
        for i in range(3):
            word, = struct.unpack("I",buf.read(4))
            assert(word==0x000)
        word, = struct.unpack("I",buf.read(4))
        assert(word==0x01)
        word, = struct.unpack("I",buf.read(4))
        assert(word==0x02)
        word, = struct.unpack("I",buf.read(4))
        assert(word==0x01)
        word, = struct.unpack("I",buf.read(4))
        assert(word==0x00)
        word, = struct.unpack("I",buf.read(4))
        assert(word==0x00)
        f, = struct.unpack("f",buf.read(4))
        assert(f==100.0)
        word, = struct.unpack("I",buf.read(4))
        assert(word==0x01)
        self.xword, = struct.unpack("I",buf.read(4))
        assert(self.xword==0x2D)
        f, = struct.unpack("f",buf.read(4))
        assert(f==1.50)
        word, = struct.unpack("I",buf.read(4))
        assert(word==0x00)
        word, = struct.unpack("H",buf.read(2))
        assert(word==0x8000)
        word, = struct.unpack("I",buf.read(4))
        assert(word==0x01)
        word, = struct.unpack("I",buf.read(4))
        assert(word==0x00)
        f, = struct.unpack("f",buf.read(4))
        assert(f==1.50)
        word, = struct.unpack("I",buf.read(4))
        assert(word==0x00)
        word, = struct.unpack("I",buf.read(4))
        assert(word==0x00)
        f, = struct.unpack("f",buf.read(4))
        assert(f==1.0)
        for i in range(3):
            word, = struct.unpack("H",buf.read(2))
            if word not in [0x8000,]:
                raise "word %08X" %(word)
        for i in range(5):
            word, = struct.unpack("I",buf.read(4))
            assert(word==0x000)
        self.sceneobject.read(buf)
        word, = struct.unpack("B",buf.read(1))
        assert(word==0x01)


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("I",self.unk1))
        self.layer.write(buf)
        for i in range(4):
            buf.write(struct.pack("H",0x8000))
        buf.write(struct.pack("H",0x022F))
        for i in range(3):
            buf.write(struct.pack("I",0x000))
        buf.write(struct.pack("I",0x01))
        buf.write(struct.pack("I",0x02))
        buf.write(struct.pack("I",0x01))
        buf.write(struct.pack("I",0x00))
        buf.write(struct.pack("I",0x00))
        buf.write(struct.pack("f",100.0))
        buf.write(struct.pack("I",0x01))
        buf.write(struct.pack("I",self.xword))
        buf.write(struct.pack("f",1.50))
        buf.write(struct.pack("I",0x00))
        buf.write(struct.pack("H",0x8000))
        buf.write(struct.pack("I",0x01))
        buf.write(struct.pack("I",0x00))
        buf.write(struct.pack("f",1.50))
        buf.write(struct.pack("I",0x00))
        buf.write(struct.pack("I",0x00))
        buf.write(struct.pack("f",1.0))
        for i in range(3):
            buf.write(struct.pack("H",0x8000))
        for i in range(5):
            buf.write(struct.pack("I",0x000))
        self.sceneobject.write(buf)
        buf.write(struct.pack("B",0x01))
    def dump(self):
        print "BEGIN LayerLinkAnimation %s " % self.Key.name
        print self.layer
        print self.sceneobject
        print "END LayerLinkAnimation"


class plPyArg:
    def __init__(self):
        self.idx=0
        self.type=0
        self.data=None
        self.reflist=(0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0E,0x0F,0x10,0x12,0x13,0x14,0x15)


    def changePageRaw(self,sid,did,stype,dtype):
        if self.type in self.reflist:
            self.data.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        self.idx = buf.Read32()
        self.type = buf.Read32()
        if self.type in (0x01,0x03):
            self.data = buf.Read32()
        elif self.type==0x02:
            self.data = buf.ReadFloat()
        elif self.type in (0x04,0x0D): #str32
            s = str32()
            s.read(buf)
            self.data=s
        elif self.type in self.reflist: #ref
            r = UruObjectRef()
            r.read(buf)
            self.data=r
        else:
            raise RuntimeError, "Unexpected argument type %02X" % self.type


    def write(self,buf):
        buf.Write32(self.idx)
        buf.Write32(self.type)
        if self.type in (0x01,0x03): #int, bool?
            buf.Write32(self.data)
        elif self.type==0x02: #float?
            buf.WriteFloat(self.data)
        elif self.type in (0x04,0x0D): #str32
            self.data.write(buf)
        elif self.type in self.reflist: #ref
            self.data.write(buf)
        else:
            raise RuntimeError, "Unexpected argument type %02X" % self.type


    def __str__(self):
        return "%i-%02X %s" %(self.idx,self.type,str(self.data))


#list2
class plPythonFileMod(plMultiModifier):                              #Type 0xA2
    def __init__(self,parent,name="unnamed"):
        plMultiModifier.__init__(self,parent,name,0x00A2)
        self.PyFile = Ustr(name,self.getVersion()) 
        self.PyFMods = hsTArray()
        self.PyArgs = []
    
    
    def addPyArg(self,idx,dat):
        arg = plPyArg()
        arg.idx = idx
        try:
            int(dat)
            try:
                dat = bool(dat)
                arg.type = 3
            except:
                arg.type = 1
        except:
            try:
                dat = float(dat)
                arg.type = 2
            except:
                try:
                    dat = str(dat)
                    arg.type = 4
                except:
                    del arg
                    print "PyArg" + idx + " has an unsupported datatype. Ignoring."
        if arg != None:
            arg.data = dat
            self.PyArgs.append(arg)
    
    
    def read(self,buf):
        plMultiModifier.read(self,buf)
        #self.PyFile = buf.ReadSafeString()
        self.PyFile.read(buf)
        self.PyFMods.read(buf)
        i = buf.Read32()
        for j in range(i):
            k = plPyArg()
            k.read(buf)
            self.PyArgs.append(k)
    
    
    def write(self,buf):
        plMultiModifier.write(self,buf)
        #buf.WriteSafeString(self.PyFile)
        self.PyFile.setType(self.getVersion())
        self.PyFile.write(buf)
        self.PyFMods.write(buf)
        buf.Write32(len(self.PyArgs))
        for i in range(len(self.PyArgs)):
            self.PyArgs[i].write(buf)
    
    
    def dump(self):
        print "BEGIN PythonFileMod " + self.Key.name
        plMultiModifier.dump(self)
        print "Got " + len(self.PyFMods) + " linked PythonFileMods"
        for i in range(len(slef.PyFMods)):
            print "--> # " + i + " Mod: " + self.PyFMods[i].Key.name
        print len(self.PyArgs) + " arguments passed"



class plMsgForwarder(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x00A8)
        #format
        self.mods=[] #modifiers


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)
        for i in self.mods:
            i.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        count1, = struct.unpack("I",buf.read(4))
        self.mods=[]
        for i in range(count1):
            ref = UruObjectRef()
            ref.read(buf)
            ##assert(ref.verify(self.Key))
            if ref.Key.object_type not in [0x6D,]:
                raise "modifier %08X" %ref.Key.object_type
            self.mods.append(ref)


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("I",len(self.mods)))
        for ref in self.mods:
            ##ref.update(self.Key)
            ref.write(buf)


    def dump(self):
        print "BEGIN MsgForwarder %s " % self.Key.name
        print "Modifiers: %i" %(len(self.mods))
        for ref in self.mods:
            print ref
        print "END MsgForwarder"


class plArmatureEffectsMgr(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x00CD)
        #format
        #U32 0


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        unk1,  = struct.unpack("I",buf.read(4))
        if unk1 not in [0x00,]:
            raise "unk1 %08X" %unk1


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("I",0))


    def dump(self):
        print "BEGIN ArmatureEffectsMgr %s " % self.Key.name
        print "END ArmatureEffectsMgr"


#list2
class plShadowCaster(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x00D4)
        #format
        self.byte=0 #Byte = 0
        self.uk1=0 #U32 = 0
        self.uk2=0
        ## 01000000 - YeeshaNoGlow
        self.uk4=1.0
        ## 0.7 - YeeshaNoGlow
        self.uk5=1.0
        self.uk6=0
        ## 0.3 - ShadowCastWindmill_21 (Cleft)


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.byte, = struct.unpack("B",buf.read(1))
        self.uk1, self.uk2 = struct.unpack("II",buf.read(4*2))
        self.uk4, self.uk5, self.uk6 = struct.unpack("fff",buf.read(4*3))
        if self.byte not in [0x00,]:
            raise "byte %08X" %self.byte
        if self.uk1 not in [0x00,]:
            raise "uk1 %08X" %self.uk1
        if self.uk2 not in [0x00,0x01000000]:
            raise "uk2 %08X" %self.uk2
        #if self.uk4 not in [1.0,0.7]:
        #    raise "uk4 %f" %self.uk4
        if self.uk5 not in [1.0,5.0]:
            raise "uk5 %f" %self.uk5
        #if self.uk6 not in [0.0,]:
            #raise "uk6 %f" %self.uk6


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("B",self.byte))
        buf.write(struct.pack("II",self.uk1,self.uk2))
        buf.write(struct.pack("fff",self.uk4,self.uk5,self.uk6))


    def dump(self):
        print "BEGIN ShadowCaster %s " % self.Key.name
        print "END ShadowCaster"


class plATCAnim(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x00F1)
        #format
        #base U32 0


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)


    def write(self,buf):
        hsKeyedObject.write(self,buf)


    def dump(self):
        print "BEGIN ATCAnim %s " % self.Key.name
        print "END ATCAnim"


#list2
class plPanicLinkRegion(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x00FC)
        #format
        self.uk1=0 #U32 = 0
        self.uk2=0
        self.uk3=0
        self.uk4=0x10000000


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.uk1, self.uk2, self.uk3, self.uk4 = struct.unpack("IIII",buf.read(4*4))
        if self.uk1 not in [0x00,]:
            raise "uk1 %08X" %self.uk1
        if self.uk2 not in [0x00,]:
            raise "uk2 %08X" %self.uk2
        if self.uk3 not in [0x00,]:
            raise "uk3 %08X" %self.uk3
        if self.uk4 not in [0x01000000,0x10000000]:
            raise "uk4 %08X" %self.uk4


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("IIII",self.uk1,self.uk2,self.uk3,self.uk4))


    def dump(self):
        print "BEGIN PanicLinkRegion %s " % self.Key.name
        print "END PanicLinkRegion"


#list2
class plSwimRegion(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x012E)
        #format
        self.uk1=0 #U32 = 0
        self.uk2=0 #U32
        self.uk3=0x01 #Byte
        self.uk4=0x0451 #U16
        self.parentref=UruObjectRef() #sceneobject
        self.uk5=0x00 #U32
        self.uk6=0x00 #U32
        self.uk7=0x00 #U32
        self.uk8=0x0810 #U32
        self.uk9=0x01 #Byte
        self.myself=UruObjectRef() #a ref to ME?
        self.uk10=0x01 #Byte
        self.uk11=0x0451 #U16
        self.parentref2=UruObjectRef()
        self.uk12=0x00 #U32
        self.uk13=0x00 #U32
        self.uk14=0x00 #U32
        self.uk15=0x0810 #U32
        self.uk16=0x00 #Byte
        self.myself2=UruObjectRef() #a ref to ME?
        self.uk17=0x00 #U32
        self.uk18=0x00 #U32
        self.uk19=0x00 #Byte


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)
        self.parentref.changePageRaw(sid,did,stype,dtype)
        self.myself.changePageRaw(sid,did,stype,dtype)
        self.parentref2.changePageRaw(sid,did,stype,dtype)
        self.myself2.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.uk1, self.uk2 = struct.unpack("II",buf.read(4*2))
        self.uk3, = struct.unpack("B",buf.read(1))
        self.uk4, = struct.unpack("H",buf.read(2))
        if self.uk1 not in [0x00,]:
            raise "uk1 %08X" %self.uk1
        if self.uk2 not in [0x00,]:
            raise "uk2 %08X" %self.uk2
        if self.uk3 not in [0x01,]:
            raise "uk3 %08X" %self.uk3
        if self.uk4 not in [0x0451,]:
            raise "uk4 %08X" %self.uk4
        self.parentref.read(buf)
        self.uk5, self.uk6, self.uk7, self.uk8 = struct.unpack("IIII",buf.read(4*4))
        self.uk9, = struct.unpack("B",buf.read(1))
        if self.uk5 not in [0x00,]:
            raise "uk5 %08X" %self.uk5
        if self.uk6 not in [0x00,]:
            raise "uk6 %08X" %self.uk6
        if self.uk7 not in [0x00,]:
            raise "uk7 %08X" %self.uk7
        if self.uk8 not in [0x0810,]:
            raise "uk8 %08X" %self.uk8
        if self.uk9 not in [0x01,]:
            raise "uk9 %08X" %self.uk9
        self.myself.read(buf)
        self.uk10, = struct.unpack("B",buf.read(1))
        self.uk11, = struct.unpack("H",buf.read(2))
        if self.uk10 not in [0x01,]:
            raise "uk10 %08X" %self.uk10
        if self.uk11 not in [0x0451,]:
            raise "uk11 %08X" %self.uk11
        self.parentref2.read(buf)
        self.uk12, self.uk13, self.uk14, self.uk15 = struct.unpack("IIII",buf.read(4*4))
        self.uk16, = struct.unpack("B",buf.read(1))
        if self.uk12 not in [0x00,]:
            raise "uk12 %08X" %self.uk12
        if self.uk13 not in [0x00,]:
            raise "uk13 %08X" %self.uk13
        if self.uk14 not in [0x00,]:
            raise "uk14 %08X" %self.uk14
        if self.uk15 not in [0x0810,]:
            raise "uk15 %08X" %self.uk15
        if self.uk16 not in [0x00,]:
            raise "uk16 %08X" %self.uk16
        self.myself2.read(buf)
        self.uk17, self.uk18 = struct.unpack("II",buf.read(4*2))
        self.uk19, = struct.unpack("B",buf.read(1))
        if self.uk17 not in [0x00,]:
            raise "uk17 %08X" %self.uk17
        if self.uk18 not in [0x00,]:
            raise "uk18 %08X" %self.uk18
        if self.uk19 not in [0x00,]:
            raise "uk19 %08X" %self.uk19


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("II",self.uk1,self.uk2))
        buf.write(struct.pack("B",self.uk3))
        buf.write(struct.pack("H",self.uk4))
        self.parentref.write(buf)
        buf.write(struct.pack("IIII",self.uk5,self.uk6,self.uk7,self.uk8))
        buf.write(struct.pack("B",self.uk9))
        self.myself.write(buf)
        buf.write(struct.pack("B",self.uk10))
        buf.write(struct.pack("H",self.uk11))
        self.parentref2.write(buf)
        buf.write(struct.pack("IIII",self.uk12,self.uk13,self.uk14,self.uk15))
        buf.write(struct.pack("B",self.uk16))
        self.myself2.write(buf)
        buf.write(struct.pack("B",self.uk17))
        buf.write(struct.pack("II",self.uk18,self.uk19))


    def dump(self):
        print "BEGIN SwimRegion %s " % self.Key.name
        print self.parentref
        print self.myself
        print self.parentref2
        print self.myself2
        print "END SwimRegion"


#list1
class plSwimRegionInterface(hsKeyedObject):    
    def __init__(self,parent,name="unnamed",type=0x0133):
        hsKeyedObject.__init__(self,parent,name,type)
        #format
        self.uk1=0 #U32 = 0
        self.parentref=UruObjectRef() #sceneobject
        self.if1=0.0
        self.if2=11.0
        self.if3=2.0
        self.if4=5.0


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)
        self.parentref.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.uk1, = struct.unpack("I",buf.read(4*1))
        if self.uk1 not in [0x00,]:
            raise "uk1 %08X" %self.uk1
        self.parentref.read(buf)
        self.if1, self.if2, self.if3, self.if4 = struct.unpack("ffff",buf.read(4*4))


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("I",self.uk1))
        self.parentref.write(buf)
        buf.write(struct.pack("ffff",self.if1,self.if2,self.if3,self.if4))


    def dump(self):
        print "BEGIN SwimRegionInterface %s " % self.Key.name
        print self.parentref
        print "END SwimRegionInterface"


    def import_obj(self,obj):
        pass
    
    def export_obj(self,obj):
            pass


#list1
class plSwimCircularCurrentRegion(plSwimRegionInterface):    
    def __init__(self,parent,name="unnamed"):
        plSwimRegionInterface.__init__(self,parent,name,0x0134)
        #format
        self.f1=-4.0
        self.f2=1.0
        self.f3=2.0
        self.f4=1.0
        self.f5=2.0
        self.dummy=UruObjectRef() # seems to be a sceneobject with only a coordinate interface


    def changePageRaw(self,sid,did,stype,dtype):
        plSwimRegionInterface.changePageRaw(self,sid,did,stype,dtype)
        self.dummy.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        plSwimRegionInterface.read(self,buf)
        self.f1, self.f2, self.f3, self.f4, self.f5 = struct.unpack("fffff",buf.read(4*5))
        ### Inner, Left, Right
        #if self.f1 not in [-4.0,6.0,-6.0]:
        #    raise "f1 %f" %self.f1
        #if self.f2 not in [1.0,25600.0]:
        #    raise "f2 %f" %self.f2
        #if self.f3 not in [2.0,]:
        #    raise "f3 %f" %self.f3
        #if self.f4 not in [1.0,34596.0]:
        #    raise "f4 %f" %self.f4
        #if self.f5 not in [2.0,8.0]:
        #    raise "f5 %f" %self.f5
        self.dummy.read(buf)


    def write(self,buf):
        plSwimRegionInterface.write(self,buf)
        buf.write(struct.pack("fffff",self.f1,self.f2,self.f3,self.f4,self.f5))
        self.dummy.write(buf)


    def dump(self):
        print "BEGIN SwimCircularCurrentRegion %s " % self.Key.name
        plSwimRegionInterface.dump(self)
        print self.dummy
        print "END SwimCircularCurrentRegion"


    def import_obj(self,obj):
        plSwimRegionInterface.import_obj(self,obj)
        obj.addProperty("Centerpoint",str(self.dummy.Key.name))
        obj.addProperty("Rotation",float(self.f1))
#        obj.addProperty("swimsfc_f2",float(self.f2))
#        obj.addProperty("swimsfc_f3",float(self.f3))
#        obj.addProperty("swimsfc_f4",float(self.f4))
        obj.addProperty("Attraction",float(self.f5))
        pass


    def export_obj(self,obj,prp):
        plSwimRegionInterface.export_obj(self,obj)
        # import old-style names (for comaptibility
        self.f1 = getFloatPropertyOrDefault(obj,"swimsfc_f1",self.f1)
        self.f2 = getFloatPropertyOrDefault(obj,"swimsfc_f2",self.f2)
        self.f3 = getFloatPropertyOrDefault(obj,"swimsfc_f3",self.f3)
        self.f4 = getFloatPropertyOrDefault(obj,"swimsfc_f4",self.f4)
        self.f5 = getFloatPropertyOrDefault(obj,"swimsfc_f5",self.f5)
        
        # now read in new-style properties
        self.f1 = getFloatPropertyOrDefault(obj,"Rotation",self.f1)
        self.f5 = getFloatPropertyOrDefault(obj,"Attraction",self.f5)
        
        #try readin in old-style dummyname before doing newstyle
        dummyname = getTextPropertyOrDefault(obj,"currentdummy",None)
        dummyname = getTextPropertyOrDefault(obj,"Centerpoint",dummyname)
                
        if(dummyname != None):
            # find or create the dummy
            dummyobj = prp.find(0x0001,dummyname,1)
            self.dummy = dummyobj.data.getRef()
                             


#list1
class plSwimStraightCurrentRegion(plSwimRegionInterface):    
    def __init__(self,parent,name="unnamed"):
        plSwimRegionInterface.__init__(self,parent,name,0x0136)
        #format
        self.f2=160.0
        self.f3=2.0
        self.f4=186.0
        self.f5=8.0
        self.dummy=UruObjectRef()


    def changePageRaw(self,sid,did,stype,dtype):
        plSwimRegionInterface.changePageRaw(self,sid,did,stype,dtype)
        self.dummy.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        plSwimRegionInterface.read(self,buf)
        self.f2, self.f3, self.f4, self.f5 = struct.unpack("ffff",buf.read(4*4))
        ### Center
        #if self.f2 not in [160.0,]:
        #    raise "f2 %f" %self.f2
        #if self.f3 not in [2.0,]:
        #    raise "f3 %f" %self.f3
        #if self.f4 not in [186.0,]:
        #    raise "f4 %f" %self.f4
        #if self.f5 not in [8.0,]:
        #    raise "f5 %f" %self.f5
        self.dummy.read(buf)


    def write(self,buf):
        plSwimRegionInterface.write(self,buf)
        buf.write(struct.pack("ffff",self.f2,self.f3,self.f4,self.f5))
        self.dummy.write(buf)


    def dump(self):
        print "BEGIN SwimStraightCurrentRegion %s " % self.Key.name
        plSwimRegionInterface.dump(self)
        print self.dummy
        print "END SwimStraightCurrentRegion"


    def import_obj(self,obj):
        plSwimRegionInterface.import_obj(self,obj)
        obj.addProperty("Centerpoint",str(self.dummy.Key.name))
        #obj.addProperty("swimsfc_f2",float(self.f2))
        obj.addProperty("Y-Speed",float(self.f3))
        #obj.addProperty("swimsfc_f4",float(self.f4))
        obj.addProperty("Y+Speed",float(self.f5))


    def export_obj(self,obj,prp):
        plSwimRegionInterface.export_obj(self,obj)
        # import old-style names (for comaptibility
        self.f2 = getFloatPropertyOrDefault(obj,"swimsfc_f2",self.f2)
        self.f3 = getFloatPropertyOrDefault(obj,"swimsfc_f3",self.f3)
        self.f4 = getFloatPropertyOrDefault(obj,"swimsfc_f4",self.f4)
        self.f5 = getFloatPropertyOrDefault(obj,"swimsfc_f5",self.f5)
        
        # now read in new-style properties
        self.f3 = getFloatPropertyOrDefault(obj,"Y-Speed",self.f1)
        self.f5 = getFloatPropertyOrDefault(obj,"Y+Speed",self.f5)
        
        #try readin in old-style dummyname before doing newstyle
        dummyname = getTextPropertyOrDefault(obj,"currentdummy",None)
        dummyname = getTextPropertyOrDefault(obj,"Centerpoint",dummyname)
                
        if(dummyname != None):
            # find or create the dummy
            dummyobj = prp.find(0x0001,dummyname,1)
            self.dummy = dummyobj.data.getRef()


# possible (always true) condition for a logicmodifier.
class plObjectInBoxConditionalObject(plConditionalObject):    
    def __init__(self,parent,name="unnamed",type=0x0037):
        plConditionalObject.__init__(self,parent,name,type)


# TEFSI tested - quality: adequate @ 11 jan 2006
class plVolumeSensorConditionalObject(hsKeyedObject):    
    def __init__(self,parent,name="unnamed",type=0x00A6):
        hsKeyedObject.__init__(self,parent,name,type)
        #format
        self.word0=1 #U16 = 1
        self.dword0=-1 #S32 = 0,1, -1
        self.direction=1 #U32 = 1 for ENTER, 2 for LEAVE
        self.byte0 = 0#byte = 0 
        ####
        # So we can do this:
        # (vsensor.data.direction = vsensensor.data.enter) or
        # (vsensor.data.direction = vsensensor.data.leave)
        self.enter = 1 
        self.leave = 2 


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.word0, = struct.unpack("H",buf.read(2))
        if self.word0 not in [0x01,]:
            raise "word0 %08X" %self.word0
        self.dword0, = struct.unpack("l",buf.read(4))
        if self.dword0 not in [0, 1, -1]:
            raise "dword0 %08X" %self.dword0
        self.direction, = struct.unpack("L",buf.read(4))
        if self.direction not in [0x01, 0x02,]:
            raise "direction %08X" %self.direction
        self.byte0, = struct.unpack("B",buf.read(1))
        # byte0 has been observed different than 00 (0x08)

    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("H",self.word0))
        buf.write(struct.pack("i",self.dword0))
        buf.write(struct.pack("L",self.direction))
        buf.write(struct.pack("B",self.byte0))

    def import_obj(self,obj):
        if(self.direction == self.enter):
            print "VolumeSensorConditionalobject %s import (Enter Region) " % str(self.Key.name)
            
            obj.addProperty("invol_entr_word0",str(alcHex2Ascii(self.word0,1)))
            obj.addProperty("invol_entr_dword0",str(alcHex2Ascii(self.dword0,1)))
            obj.addProperty("invol_entr_byte0",str(alcHex2Ascii(self.byte0,1)))
        elif(self.direction == self.leave):
            print "VolumeSensorConditionalobject %s import (Enter Region) " % str(self.Key.name)

            obj.addProperty("invol_exit_word0",str(alcHex2Ascii(self.word0,1)))
            obj.addProperty("invol_exit_dword0",str(alcHex2Ascii(self.dword0,1)))
            obj.addProperty("invol_exit_byte0",str(alcHex2Ascii(self.byte0,1)))

    def export_obj(self,obj,prp):
        if(self.direction == self.enter):
            try:
                p=obj.getProperty("invol_entr_word0")
                self.word0=alcAscii2Hex(str(p.getData()),2)
            except AttributeError:
                pass
            try:
                p=obj.getProperty("invol_entr_dword0")
                self.dword0=alcAscii2Hex(str(p.getData()),4)
            except AttributeError:
                pass
            try:
                p=obj.getProperty("invol_entr_byte0")
                self.byte0=alcAscii2Hex(str(p.getData()),1)
            except AttributeError:
                pass
        elif(self.direction == self.leave):
            try:
                p=obj.getProperty("invol_exit_word0")
                self.word0=alcAscii2Hex(str(p.getData()),2)
            except AttributeError:
                pass
            try:
                p=obj.getProperty("invol_exit_dword0")
                self.dword0=alcAscii2Hex(str(p.getData()),4)
            except AttributeError:
                pass
            try:
                p=obj.getProperty("invol_exit_byte0")
                self.byte0=alcAscii2Hex(str(p.getData()),1)
            except AttributeError:
                pass
        pass


    def dump(self):
        print "BEGIN ObjectInBoxCondtionalObject %s " % self.Key.name
        if (self.direction == 1):
            print "Direction: ENTER"
        elif (self.direction == 2):
            print "Direction: LEAVE"
        else:
            print "Direction: ILLEGAL?? VALUE"
        print "END ObjectInBoxCondtionalObject"


# used for getting certain things to work when you are in a region.
# like clickables, and footstep sounds
# TEFSI tested - quality: adequate @ 11 jan 2006
class plObjectInVolumeDetector(plCollisionDetector):    
    def __init__(self,parent,name="unnamed"):
        plCollisionDetector.__init__(self,parent,name,0x007B)



##############################################################
# The respondermodifier should get its own python file, since it's relatively complex.
#  its in "alcrespmod.py"
##############################################################

#TYPE 002D - LogicModifier
#{plLogicModifier} : {plSynchedObject}

#BASE
#DWORD ArraySize // Always 0
#DWORD[ArraySize] // Never used
#DWORD 0
#WORD SubType // Always = 02E8 plNotifyMsg
#BYTE 0
#DWORD ModCount // 0 to 3
#URUOBJECTREF Modifiers[ModCount] // 00A2 00AE 007C
#DWORD 0
#DWORD 0
#DWORD 0x00000840
#DWORD 0
#DWORD 0
#DWORD 0
#DWORD 0
#DWORD ArraySize // Always 1
#DWORD[ArraySize] // 1, 9, 40, or 48
#BYTE bool
#DWORD ConditionalCount // 1 or 3
#URUOBJECTREF Conditionals[ConditionalCount] // 0032 0037 003E 00A6
#DWORD // 1 or 5

# TEFSI tested - quality: adequate @ 11 jan 2006
class plLogicModifier(plLogicModBase):   
    def __init__(self,parent,name="unnamed"):
        plLogicModBase.__init__(self,parent,name,0x002D)
        #format
        self.Conditionals = hsTArray([0x32,0x37,0x3E,0xA6],self.getVersion(),True)
        self.i98 = 1 #U32 - 1 or 5 defaults to 1


    def changePageRaw(self,sid,did,stype,dtype):
        plLogicModBase.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        plLogicModBase.read(self,buf)
        self.Conditionals.read(buf)
        self.i98 = buf.Read32()


    def write(self,buf):
        plLogicModBase.write(self,buf)
        self.Conditionals.write(buf)
        buf.Write32(self.i98)


    def dump(self):
        print "BEGIN LogicModifier %s " % self.Key.name
        print "END LogicModifier"


class plPickingDetector(plDetectorModifier):                    #Type 0x002B
    def __init__(self,parent,name="unnamed"):
        #Gotta figure out how to pass the correct type from M5
        #self.getVersion() & plDectorModifier.getVersion() puke :\
        plDetectorModifier.__init__(self,parent,name,0x002B)


    def dump(self):
        plDetectorModifier.dump(self)
        print "BEGIN PickingDetector " + self.Key.name
        for logic in self.logic.Vector:
            print "LogicModifier: " + logic.Key.name
        print "END PickingDetector"


class plActivatorConditionalObject(plConditionalObject):
    def __init__(self,parent,name="unnamed"):
        plConditionalObject.__init__(self,parent,name,0x0032)
        #format
        self.condobjs = hsTArray()


    def changePageRaw(self,sid,did,stype,dtype):
        plConditionalObject.changePageRaw(self,sid,did,stype,dtype)
        self.condobjs.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        plConditionalObject.read(self,buf)
        self.condobjs.ReadVector(buf)

 
    def write(self,buf):
        plConditionalObject.write(self,buf)
        self.condobjs.update(self.Key)
        self.condobjs.WriteVector(buf)


    def dump(self):
        print "BEGIN ActivatorConditionalObject %s " % self.Key.name
        plConditionalObject.dump(self)
        print "PickingDetector:",
        print self.pickdetect
        print "END ActivatorConditionalObject"


# TEFSI tested - quality: adequate @ 11 jan 2006
class plInterfaceInfoModifier(plSingleModifier):    
    def __init__(self,parent,name="unnamed"):
        plSingleModifier.__init__(self,parent,name,0x00CB)
        #format
        self.objects=hsTArray([0x2D],self.getVersion()) # modifiers Type 2D (LogicModifier) 
        ####


    def changePageRaw(self,sid,did,stype,dtype):
        plSingleModifier.changePageRaw(self,sid,did,stype,dtype)
        self.objects.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        plSingleModifier.read(self,buf)
        self.objects.read(buf)


    def write(self,buf):
        plSingleModifier.write(self,buf)
        self.objects.update(self.Key)
        self.objects.write(buf)


    def dump(self):
        print "BEGIN InterfaceInfoModifier %s " % self.Key.name
        print "Refs: %i" %(len(self.objects))
        for ref in self.objects.vector:
            print ref
        print "END InterfaceInfoModifier"


class plFacingConditionalObject(plConditionalObject):
    def __init__(self,parent,name = "unnamed"):
        plConditionalObject.__init__(self,parent,name,0x3E)
        self.float2 = -1.0
        self.byte0 = 0x00


    def read(self,buf):
        plConditionalObject.read(self,buf)
        self.float2 = buf.ReadFloat()
        self.byte0 = buf.ReadByte()

 
    def write(self,buf):
        plConditionalObject.write(self,buf)
        buf.WriteFloat(self.float2)
        buf.WriteByte(self.byte0)


#TYPE 00D5 - PointShadowMaster

#{plInterfaceInfoModifier}

#DWORD 0
#URUOBJECTREF Scenobject (that it's linked to) // Type 0001
#DWORD 1
#WORD uk1 (seen: 0,2)
#DWORD 0
#DWORD flags1 (seen: 0x00004170, 0x00004120)
#DWORD flags2 (seen: 0, 0x00004248)
#WORD flags3 (seen: 0, 0x4216)
#DWORD 0x00000100
#DWORD 0x00000100
#DWORD 0x40000000

# experiment currently failed
class plPointShadowMaster(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x00D5)
        #format
        self.dword0=0 #U32
        #self.sceneobject = parent
        self.dword1=1 #U32
        self.uk0 = 2 #U16
        self.dword2 = 0 # U32
        self.flags0 = 0x4120 #U32
        self.flags1 = 0 #U32
        self.flags2 = 0 #U16
        self.dword3 = 0x0100 #U32
        self.dword4 = 0x0100 #U32
        self.dword5 = 0x40000000 #U32


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.dword0, = struct.unpack("I",buf.read(4))
        self.sceneobject = UruObjectRef(self.getVersion())
        self.sceneobject.read(buf)
        self.dword1 = struct.unpack("I",buf.read(4))
        self.uk0 = struct.unpack("H",buf.read(2))
        self.dword2 = struct.unpack("I",buf.read(4))
        self.flags0 = struct.unpack("I",buf.read(4))
        self.flags1 = struct.unpack("I",buf.read(4))
        self.flags2 = struct.unpack("H",buf.read(2))
        self.dword3 = struct.unpack("I",buf.read(4))
        self.dword4 = struct.unpack("I",buf.read(4))
        self.dword5 = struct.unpack("I",buf.read(4))


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("I",self.dword0))
        self.sceneobject.update(self.Key)
        self.sceneobject.write(buf)
        buf.write(struct.pack("I",self.dword1))
        buf.write(struct.pack("H",self.uk0))
        buf.write(struct.pack("I",self.dword2))
        buf.write(struct.pack("I",self.flags0))
        buf.write(struct.pack("I",self.flags1))
        buf.write(struct.pack("H",self.flags2))
        buf.write(struct.pack("I",self.dword3))
        buf.write(struct.pack("I",self.dword4))
        buf.write(struct.pack("I",self.dword5))


    def dump(self):
        print "BEGIN PointShadowMaster %s " % self.Key.name
        print "Refs: %i" %(len(self.mods))
        for ref in self.refs:
            print ref
        print "END PointShadowMaster"


    def import_obj(self,obj):
        plSwimRegionInterface.import_obj(self,obj)
        obj.addProperty("alcshadow","pointshadow")
        a=struct.pack(">I",self.flags0)
        b=binascii.hexlify(a).upper()
        obj.addProperty("psm_flags0",b)
        a=struct.pack(">I",self.flags1)
        b=binascii.hexlify(a).upper()
        obj.addProperty("psm_flags1",b)
        a=struct.pack(">H",self.flags2)
        b=binascii.hexlify(a).upper()
        obj.addProperty("psm_flags2",b)
        a=struct.pack(">H",self.uk0)
        b=binascii.hexlify(a).upper()
        obj.addProperty("psm_uk0",b)
        return obj


    def export_obj(self,obj):
        lamp = obj.data
        try:
            p=obj.getProperty("psm_uk0")
            name=str(p.getData())
            while len(name)<4:
                name = "0" + name
            b=binascii.unhexlify(str(name))
            l,=struct.unpack(">I",b)
        except AttributeError:
            l=0
        self.uk0=l
        try:
            p=obj.getProperty("psm_flags0")
            name=str(p.getData())
            while len(name)<8:
                name = "0" + name
            b=binascii.unhexlify(str(name))
            l,=struct.unpack(">I",b)
        except AttributeError:
            l=0
        self.flags0=l
        try:
            p=obj.getProperty("psm_flags1")
            name=str(p.getData())
            while len(name)<8:
                name = "0" + name
            b=binascii.unhexlify(str(name))
            l,=struct.unpack(">I",b)
        except AttributeError:
            l=0
        self.flags1=l
        try:
            p=obj.getProperty("psm_flags2")
            name=str(p.getData())
            while len(name)<4:
                name = "0" + name
            b=binascii.unhexlify(str(name))
            l,=struct.unpack(">H",b)
        except AttributeError:
            l=0
        self.flags2=l
        pass


class plAvLadderMod(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x00B2)
        #format
        self.dword0=0 #U32
        self.dword1=0 #U32
        self.climbOffset=0 #U32
        self.climbHeight=0 #U32 
        self.byte0=0x01
        self.bottomFlag=0
        self.fDirectionX=0.0
        self.fDirectionY=0.0
        self.dword2=0 #U32


    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.dword0, = struct.unpack("I",buf.read(4))
        self.dword1, = struct.unpack("I",buf.read(4))
        self.climbOffset, = struct.unpack("I",buf.read(4))
        self.climbHeight, = struct.unpack("I",buf.read(4))
        self.bottomFlag, = struct.unpack("B",buf.read(1))
        self.byte0, = struct.unpack("B",buf.read(1))
        self.fDirectionX, self.fDirectionY, = struct.unpack("ff",buf.read(4*2))
        self.dword2, = struct.unpack("I",buf.read(4))


    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("I",self.dword0))
        buf.write(struct.pack("I",self.dword1))
        buf.write(struct.pack("I",self.climbOffset))
        buf.write(struct.pack("I",self.climbHeight))
        buf.write(struct.pack("B",self.bottomFlag))
        buf.write(struct.pack("B",self.byte0))
        buf.write(struct.pack("ff",self.fDirectionX, self.fDirectionY))
        buf.write(struct.pack("I",self.dword2))


    def dump(self):
        print "BEGIN AvLadderMod %s " % self.Key.name
        print "climbOffset: %i" %(self.climbOffset)
        print "climbHeight: %i" %(self.climbHeight)
        print "bottomFlag: %02X " %(self.bottomFlag)
        print "Direction: (%f,%f) " %(self.fDirectionX,self.fDirectionY)
        print "END AvLadderMod"


    def import_obj(self,obj):
        obj.addProperty("bottomFlag",str(alcHex2Ascii(self.bottomFlag,1)))
        obj.addProperty("climbOffset",int(self.climbOffset))
        obj.addProperty("climbHeight",int(self.climbHeight))


    def export_obj(self,obj,prp):
        try:
            p=obj.getProperty("bottomFlag")
            self.bottomFlag=alcAscii2Hex(str(p.getData()),1)
        except AttributeError:
            pass
        try:
            p=obj.getProperty("climbOffset")
            self.climbOffset=int(p.getData())
        except AttributeError:
            pass
        try:
            p=obj.getProperty("climbHeight")
            self.climbHeight=int(p.getData())
        except AttributeError:
            pass
        #Get the local Y axis of the object, normalize it, then store the inverse of it
        matrix = obj.getMatrix()
        length = matrix[1][0] * matrix[1][0] + matrix[1][1] * matrix[1][1]
        length = math.sqrt(length)
        self.fDirectionX = -matrix[1][0]/length
        self.fDirectionY = -matrix[1][1]/length


class plCameraModifier1(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x009B)
        #format
        self.cambrain=UruObjectRef()
        #self.fieldcount = 0 # DWord
        self.fields = [] #CamTransition Fields
        
        #Ending is almost always like this:
        self.HFOV = 45.0 # Field of View
        self.VFOV = 33.75 #
        self.dword2 = 0 # \
        self.dword3 = 0 #  } Probably not really DWORDS. at least one byte of dword4 is probably an uruobjectREF
        self.dword4 = 0 # /
        self.hasRawAnimData = 0
        
    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf,size):
        start=buf.tell()
        
        hsKeyedObject.read(self,buf)
        self.cambrain.read(buf)
        fieldcount, = struct.unpack("I",buf.read(4))

        print "%i camera modfier Fields" % fieldcount
        for j in range(fieldcount):
            field = CamTransitionField()
            field.read(buf)
            self.fields.append(field)

        self.HFOV, = struct.unpack("f",buf.read(4))
        self.VFOV, = struct.unpack("f",buf.read(4))
        self.dword2, = struct.unpack("I",buf.read(4))
        self.dword3, = struct.unpack("I",buf.read(4))
        self.dword4, = struct.unpack("I",buf.read(4))
        
        myend=buf.tell() - start # get the place we're at now
        

        print "Parsed Size: %i Myend: %i Remaining: %i" % (size, myend, (size-myend))
        
        if(size-myend!= 0):
            # we have some data left
            self.hasRawAnimData = 1
            self.rawdata=cStringIO.StringIO()
            self.rawdata.write(buf.read(size-myend))


    def write(self,buf):
        hsKeyedObject.write(self,buf)

        self.cambrain.write(buf)
        
        buf.write(struct.pack("I",len(self.fields)))

        for field in self.fields:
            field.write(buf)

        buf.write(struct.pack("f",self.HFOV))
        buf.write(struct.pack("f",self.VFOV))
        buf.write(struct.pack("f",self.dword2))
        buf.write(struct.pack("f",self.dword3))
        buf.write(struct.pack("f",self.dword4))

        # see if we should write out extra raw animation data
        if(self.hasRawAnimData):
            self.rawdata.seek(0)
            buf.write(self.rawdata.read())


    def dump(self):
        print "BEGIN CameraModifier %s " % self.Key.name
        print "END CameraModifier"


    def import_obj(self,obj):
        root = self.getRoot()
        obj.addProperty("Cameraname",str(self.Key.name))
        
        # calculate the camera lens (blender has 32 mm camera)
        radianVFOV = self.VFOV / (360/(2*math.pi))
        
        lens = 32/(2*math.tan(radianVFOV/2))
        
        # now set the blender lens property
        obj.data.setLens(lens)
             
        c = 0
        for field in self.fields:
            field.import_obj(obj,c)
            c = c+1

        cbrain = root.findref(self.cambrain)
        cbrain.data.import_obj(obj)

        pass

    def export_obj(self,obj,prp):
        print "Exporting Camera Modifier Object"

        # calculate the FOV's from the lens property
        # (blender has 32 mm camera)

        if(obj.data.getType() == 0): # check for perspective camera
            lens = obj.data.getLens()
            print "Calculating FOV for lens is %i mm" % lens
            
            self.VFOV = 2 * math.atan(32/(2*lens)) * (360/(2*math.pi))
            
            self.HFOV = self.VFOV / 0.750 # I divide by 0.750 becaus I hope it's more accurate than multiplying by 1.33
        else:
            #default them to default values (45:33.75):
            print "Camera is not perpective - please changeit to perspective"
            pass
        
        # create one default camera transition field        
        cfield1 = CamTransitionField()
        self.fields.append(cfield1)

        
class CamTransitionField: 
    def __init__(self):
        self.cammod = UruObjectRef()
        self.byte0 = 0
        self.byte1 = 0
        self.byte2 = 0
        
        # Probably a set of two Vertex3's - both contain the same data...
        self.FloatX1 = 50
        self.FloatY1 = 10
        self.FloatZ1 = 10
        self.FloatX2 = 50
        self.FloatY2 = 10
        self.FloatZ2 = 10


    def read(self,buf):
        self.cammod.read(buf)
        self.byte0, = struct.unpack("B",buf.read(1))
        self.byte1, = struct.unpack("B",buf.read(1))
        self.byte2, = struct.unpack("B",buf.read(1))
        self.FloatX1, self.FloatY1, self.FloatZ1, = struct.unpack("fff",buf.read(3*4))
        self.FloatX2, self.FloatY2, self.FloatZ2, = struct.unpack("fff",buf.read(3*4))
    
    def write(self,buf):
        self.cammod.write(buf)
        buf.write(struct.pack("B",self.byte0))
        buf.write(struct.pack("B",self.byte1))
        buf.write(struct.pack("B",self.byte2))
        buf.write(struct.pack("fff",self.FloatX1, self.FloatY1, self.FloatZ1))
        buf.write(struct.pack("fff",self.FloatX2, self.FloatY2, self.FloatZ2))
        


    def dump(self):
        print "BEGIN CameraModifier Field"
        print "END CameraModifier Field"

    def import_obj(self,obj,c=0):
        # obj.addProperty("Transition"+str(c)+"_to",str(self.cammod.Key.name))
        
        pass

    def export_obj(self,obj,prp):
        pass


class plCameraRegionDetector(hsKeyedObject):    
    def __init__(self,parent,name="unnamed"):
        hsKeyedObject.__init__(self,parent,name,0x006F)
        #format
        self.word0 = 0x0000 #00 00 
        self.dword1 = 0x00000000 #00 00 00 00 
        self.dword2 = 0x00000000 #00 00 00 00 
        self.dword3 = 0x00000000 #00 00 00 00 

        self.dword4 = 0x00000001 #01 00 00 00 
        self.dword5 = 0x0000020A #0A 02 00 00

        self.dword6 = 0x00000000 #00 00 00 00 
        self.dword7 = 0x00000000 #00 00 00 00 
        self.word8 = 0x00000000 #00 00 
        self.byte9 = 0x00 #00 
        self.dword10 = 0x00000801 #01 08 00 00 
        self.dword11 = 0x00000001 #01 00 00 00 
        self.byte12 = 0x00 #this is "0x04" if it should set a default camera
        self.dword13 = 0x00000020 #20 00 00 00 
        self.dword14 = 0x00000000 #00 00 00 00 
        self.dword15 = 0x00000000 #00 00 00 00 

        self.camera=UruObjectRef()
        
        self.dword16 = 0x00
        self.dword17 = 0x00
        self.dword18 = 0x00
        self.dword19 = 0x00
        self.dword20 = 0x00
        self.dword21 = 0x00
        self.dword22 = 0x00
        self.dword23 = 0x00
        self.dword24 = 0x00
        self.dword25 = 0x00
        self.dword26 = 0x00
        self.word27 = 0x00
        
    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)

        self.word0,   = struct.unpack("H",buf.read(2))
        self.dword1,  = struct.unpack("I",buf.read(4))
        self.dword2,  = struct.unpack("I",buf.read(4))
        self.dword3,  = struct.unpack("I",buf.read(4))

        self.dword4,  = struct.unpack("I",buf.read(4))
        self.dword5,  = struct.unpack("I",buf.read(4))

        self.dword6,  = struct.unpack("I",buf.read(4))
        self.dword7,  = struct.unpack("I",buf.read(4))
        self.word8,   = struct.unpack("H",buf.read(2))
        self.byte9,   = struct.unpack("B",buf.read(1))
        self.dword10, = struct.unpack("I",buf.read(4))
        self.dword11, = struct.unpack("I",buf.read(4))
        self.byte12,  = struct.unpack("B",buf.read(1))
        self.dword13, = struct.unpack("I",buf.read(4))
        self.dword14, = struct.unpack("I",buf.read(4))
        self.dword15, = struct.unpack("I",buf.read(4))

        self.camera.read(buf)
        self.dword16, = struct.unpack("I",buf.read(4))
        self.dword17, = struct.unpack("I",buf.read(4))
        self.dword18, = struct.unpack("I",buf.read(4))
        self.dword19, = struct.unpack("I",buf.read(4))
        self.dword20, = struct.unpack("I",buf.read(4))
        self.dword21, = struct.unpack("I",buf.read(4))
        self.dword22, = struct.unpack("I",buf.read(4))
        self.dword23, = struct.unpack("I",buf.read(4))
        self.dword24, = struct.unpack("I",buf.read(4))
        self.dword25, = struct.unpack("I",buf.read(4))
        self.dword26, = struct.unpack("I",buf.read(4))
        self.word27, = struct.unpack("H",buf.read(2))

    def write(self,buf):
        hsKeyedObject.write(self,buf)

        buf.write(struct.pack("H",self.word0))
        buf.write(struct.pack("I",self.dword1))
        buf.write(struct.pack("I",self.dword2))
        buf.write(struct.pack("I",self.dword3))
        buf.write(struct.pack("I",self.dword4))
        buf.write(struct.pack("I",self.dword5))
        buf.write(struct.pack("I",self.dword6))
        buf.write(struct.pack("I",self.dword7))
        buf.write(struct.pack("H",self.word8))
        buf.write(struct.pack("B",self.byte9))
        buf.write(struct.pack("I",self.dword10))
        buf.write(struct.pack("I",self.dword11))
        buf.write(struct.pack("B",self.byte12))
        buf.write(struct.pack("I",self.dword13))
        buf.write(struct.pack("I",self.dword14))
        buf.write(struct.pack("I",self.dword15))

        self.camera.write(buf)
        buf.write(struct.pack("I",self.dword16))
        buf.write(struct.pack("I",self.dword17))
        buf.write(struct.pack("I",self.dword18))
        buf.write(struct.pack("I",self.dword19))
        buf.write(struct.pack("I",self.dword20))
        buf.write(struct.pack("I",self.dword21))
        buf.write(struct.pack("I",self.dword22))
        buf.write(struct.pack("I",self.dword23))
        buf.write(struct.pack("I",self.dword24))
        buf.write(struct.pack("I",self.dword25))
        buf.write(struct.pack("I",self.dword26))
        buf.write(struct.pack("H",self.word27))

    def dump(self):
        print "BEGIN CameraRegionDetector %s " % self.Key.name
        print "END CameraRegionDetector"


    def import_obj(self,obj):
        if(self.byte12 == 0x04):
            obj.addProperty("setDefCam","1")    
        obj.addProperty("cambrain",str(self.camera.Key.name))

    def export_obj(self,obj,prp):
        print "Exporting Camera Region Detector"
        setdefault = getTextPropertyOrDefault(obj,"setDefCam","0")
        if(setdefault != "0" and setdefault != "false" and setdefault != "False"):
            print "Setting camera region to change the default camera region"
            self.byte12 = 0x04
        else:
            print "Setting camera region to temporary switch"
        
    

class plCameraBrain1(hsKeyedObject):    
    def __init__(self,parent,name="unnamed",type=0x0099):
        hsKeyedObject.__init__(self,parent,name,type)
        #format
        self.POA_X = 0.0
        self.POA_Y = 0.0
        self.POA_Z = 6.0 # default to avatar head!

        self.ref1=UruObjectRef()
        self.ref2=UruObjectRef()

        self.DWCount = 1
        self.DWords = [0x25,] # seen 20 and 25
        
        self.float0 = 30
        self.float1 = 30
        self.float2 = 30
        self.float3 = 30
        self.float4 = 30
        self.float5 = 30
        self.float6 = 0 # Various numbers between 0.0 and 0.99999 often similar as float7
        self.float7 = 0 # Various numbers between 0.0 and 0.99999 often similar as float6
        
        self.float8 = 0
        self.float9 = 0
        self.float10 = 0
        
    def changePageRaw(self,sid,did,stype,dtype):
        hsKeyedObject.changePageRaw(self,sid,did,stype,dtype)
        self.ref1.changePageRaw(sid,did,stype,dtype)
        self.ref2.changePageRaw(sid,did,stype,dtype)


    def read(self,buf):
        hsKeyedObject.read(self,buf)
        self.POA_X, self.POA_Y, self.POA_Z, = struct.unpack("fff",buf.read(3*4))

        self.ref1.read(buf)
        self.ref2.read(buf)

        self.DWCount, = struct.unpack("I",buf.read(4))

        for j in range(self.DWCount):
            dw, = struct.unpack("I",buf.read(4))
            self.DWords.append(dw)


        self.float0, = struct.unpack("f",buf.read(4))
        self.float1, = struct.unpack("f",buf.read(4))
        self.float2, = struct.unpack("f",buf.read(4))
        self.float3, = struct.unpack("f",buf.read(4))
        self.float4, = struct.unpack("f",buf.read(4))
        self.float5, = struct.unpack("f",buf.read(4))
        self.float6, = struct.unpack("f",buf.read(4))
        self.float7, = struct.unpack("f",buf.read(4))
        self.float8, = struct.unpack("f",buf.read(4))
        self.float9, = struct.unpack("f",buf.read(4))
        self.float10, = struct.unpack("f",buf.read(4))

    def write(self,buf):
        hsKeyedObject.write(self,buf)
        buf.write(struct.pack("fff",self.POA_X, self.POA_Y, self.POA_Z))

        self.ref1.write(buf)
        self.ref2.write(buf)

        buf.write(struct.pack("I",len(self.DWords)))

        for dw in self.DWords:
            buf.write(struct.pack("I",dw))

        buf.write(struct.pack("f",self.float0))
        buf.write(struct.pack("f",self.float1))
        buf.write(struct.pack("f",self.float2))
        buf.write(struct.pack("f",self.float3))
        buf.write(struct.pack("f",self.float4))
        buf.write(struct.pack("f",self.float5))
        buf.write(struct.pack("f",self.float6))
        buf.write(struct.pack("f",self.float7))
        buf.write(struct.pack("f",self.float8))
        buf.write(struct.pack("f",self.float9))
        buf.write(struct.pack("f",self.float10))

    def dump(self):
        print "BEGIN CameraBrain1 %s " % self.Key.name
        print "END CameraBrain1"


    def import_obj(self,obj):
        obj.addProperty("POA_X",float(self.POA_X))    
        obj.addProperty("POA_Y",float(self.POA_Y))    
        obj.addProperty("POA_Z",float(self.POA_Z))    

        #obj.addProperty("CBr1_ref1",str(self.ref1.Key.name))
        if(str(self.ref2.Key.name) != ""):
            obj.addProperty("RailCamera",str(self.ref2.Key.name))    # links to railcammods
    
       # obj.addProperty("CBr1_float0",float(self.float0))    
       # obj.addProperty("CBr1_float1",float(self.float1))    
       # obj.addProperty("CBr1_float2",float(self.float2))    
       # obj.addProperty("CBr1_float3",float(self.float3))    
       # obj.addProperty("CBr1_float4",float(self.float4))    
       # obj.addProperty("CBr1_float5",float(self.float5))    
       # obj.addProperty("CBr1_float6",float(self.float6))    
       # obj.addProperty("CBr1_float7",float(self.float7))    

    def export_obj(self,obj,prp):
        print "Exporting CameraBrain1"
        self.POA_X = getFloatPropertyOrDefault(obj,"POA_X",self.POA_X)
        self.POA_Y = getFloatPropertyOrDefault(obj,"POA_Y",self.POA_Y)
        self.POA_Z = getFloatPropertyOrDefault(obj,"POA_Z",self.POA_Z)

        self.float0 = getFloatPropertyOrDefault(obj,"CamBr_f0",self.float0)
        self.float1 = getFloatPropertyOrDefault(obj,"CamBr_f1",self.float1)
        self.float2 = getFloatPropertyOrDefault(obj,"CamBr_f2",self.float2)
        self.float3 = getFloatPropertyOrDefault(obj,"CamBr_f3",self.float3)
        self.float4 = getFloatPropertyOrDefault(obj,"CamBr_f4",self.float4)
        self.float5 = getFloatPropertyOrDefault(obj,"CamBr_f5",self.float5)
        self.float6 = getFloatPropertyOrDefault(obj,"CamBr_f6",self.float6)
        self.float7 = getFloatPropertyOrDefault(obj,"CamBr_f7",self.float7)

class plCameraBrain1_Fixed(plCameraBrain1):    
    def __init__(self,parent,name="unnamed"):
        plCameraBrain1.__init__(self,parent,name,0x009F)
        
        # set the Camerabrain1 floats to match defaults for this brain type
        self.float0 = 30
        self.float1 = 30
        self.float2 = 30
        self.float3 = 30
        self.float4 = 30
        self.float5 = 30
        self.float6 = 0 # Various numbers between 0.0 and 0.99999 often similar as float7
        self.float7 = 0 # Various numbers between 0.0 and 0.99999 often similar as float6

        #format
        self.target=UruObjectRef()
        
    def changePageRaw(self,sid,did,stype,dtype):
        plCameraBrain1.changePageRaw(self,sid,did,stype,dtype)
        self.target.changePageRaw(sid,did,stype,dtype)

    def read(self,buf):
        plCameraBrain1.read(self,buf)
        self.target.read(buf)

    def write(self,buf):
        plCameraBrain1.write(self,buf)
        self.target.write(buf)

    def dump(self):
        plCameraBrain1.dump(self)
        print "BEGIN CameraBrain1_Fixed %s " % self.Key.name
        print "END CameraBrain1_Fixed"

    def import_obj(self,obj):
        plCameraBrain1.import_obj(self,obj)
        obj.addProperty("cambrain","fixed")
        obj.addProperty("Fixedcam_target",str(self.target.Key.name))
        

    def export_obj(self,obj,prp):
        plCameraBrain1.export_obj(self,obj,prp)
        print "Exporting CameraBrain1_Fixed"
        

class plCameraBrain1_Circle(plCameraBrain1):    
    def __init__(self,parent,name="unnamed"):
        plCameraBrain1.__init__(self,parent,name,0x00C2)

        # set the Camerabrain1 floats to match defaults for this brain type
        self.float0 = 10
        self.float1 = 10
        self.float2 = 15
        self.float3 = 10
        self.float4 = 10
        self.float5 = 50
        self.float6 = 0 # Various numbers between 0.0 and 0.99999 often similar as float7
        self.float7 = 0 # Various numbers between 0.0 and 0.99999 often similar as float6

        #format
        self.tmp = 0x00000044 #dword "i118 |= tmp???"
        
        self.X2 = 0.0 # \
        self.Y2 = 0.0 #  } Rotation point of camera  
        self.Z2 = 0.0 # /
        self.f12C = 0.0 # unknown value = maybe the Z movement allow
        
        self.ref1 = UruObjectRef()
        self.ref2 = UruObjectRef()
        
        self.f13C = 0.10 # virtually always 0.10
        
    def changePageRaw(self,sid,did,stype,dtype):
        plCameraBrain1.changePageRaw(self,sid,did,stype,dtype)
        self.ref1.changePageRaw(sid,did,stype,dtype)
        self.ref2.changePageRaw(sid,did,stype,dtype)

    def read(self,buf):
        plCameraBrain1.read(self,buf)

        self.tmp, = struct.unpack("I",buf.read(4))
        #self.i118 = struct.unpack("I",buf.read(4))
        self.X2, self.Y2, self.Z2, = struct.unpack("fff",buf.read(3*4))

        self.f12C, = struct.unpack("f",buf.read(4))

        self.ref1.read(buf)
        self.ref2.read(buf)

        self.f13C, = struct.unpack("f",buf.read(4))

    def write(self,buf):
        plCameraBrain1.write(self,buf)

        buf.write(struct.pack("I",self.tmp))
        #buf.write(struct.pack("I",self.i118))

        buf.write(struct.pack("fff",self.X2, self.Y2, self.Z2))
        buf.write(struct.pack("f",self.f12C))
        
        self.ref1.write(buf)
        self.ref2.write(buf)

        buf.write(struct.pack("f",self.f13C))
        
        
    def dump(self):
        print "BEGIN CameraBrain1_Circle %s " % self.Key.name
        print "END CameraBrain1_Circle"

    def import_obj(self,obj):
        plCameraBrain1.import_obj(self,obj)
        obj.addProperty("cambrain","circle")
        
        obj.addProperty("circle_flags",alcHex2Ascii(self.tmp))
        #obj.addProperty("CircleCtr_X",float(self.X2))
        #obj.addProperty("CircleCtr_Y",float(self.Y2))
        #obj.addProperty("CircleCtr_Z",float(self.Z2))
        
        obj.data.setClipEnd(self.f12C)
        obj.data.setMode("showLimits")
     

    def export_obj(self,obj,prp):
        plCameraBrain1.export_obj(self,obj,prp)
        # get the matrices
        LocalToWorld=hsMatrix44()
        m=getMatrix(obj)
        m.transpose()
        LocalToWorld.set(m)
        self.M78 = LocalToWorld

        WorldToLocal=hsMatrix44()
        m=getMatrix(obj)
        m.invert() 
        m.transpose()
        WorldToLocal.set(m)
        self.MBC = WorldToLocal

        self.tmp = getHexPropertyOrDefault(obj,"Circle_flags",4,self.tmp)
        
        # convert the clip-end to the Center point of the camera
        if obj.getType() == 'Camera':
            clip_end = obj.data.getClipEnd()
            rotCenter = Vertex(0,0,0 - clip_end) # camera points to local -Z
            rotCenter.transform(LocalToWorld)
            self.X2 = rotCenter.x
            self.Y2 = rotCenter.y
            self.Z2 = rotCenter.z
            
        self.f12C = clip_end # always seems to define distance from camera to rotation point
        
        #self.f13C = getFloatPropertyOrDefault(obj,"CBR1Circ_float1",self.f13C)

class plCameraBrain1_Avatar(plCameraBrain1):    
    def __init__(self,parent,name="unnamed"):
        plCameraBrain1.__init__(self,parent,name,0x009E)

        # set the Camerabrain1 floats to match defaults for this brain type
        self.float0 = 10
        self.float1 = 10
        self.float2 = 50
        self.float3 = 10
        self.float4 = 10
        self.float5 = 50
        self.float6 = 0 # Various numbers between 0.0 and 0.99999 often similar as float7
        self.float7 = 0 # Various numbers between 0.0 and 0.99999 often similar as float6

        #format
        self.X = 0 #probably Distance from/to Avatar
        self.Y = 5 # default to something stable
        self.Z = 5
        
        
    def changePageRaw(self,sid,did,stype,dtype):
        plCameraBrain1.changePageRaw(self,sid,did,stype,dtype)

    def read(self,buf):
        plCameraBrain1.read(self,buf)
        self.X, self.Y, self.Z, = struct.unpack("fff",buf.read(3*4))

    def write(self,buf):
        plCameraBrain1.write(self,buf)
        buf.write(struct.pack("fff",self.X, self.Y, self.Z))

    def dump(self):
        print "BEGIN CameraBrain1_Avatar %s " % self.Key.name
        print "X = %f, Y = %f Z = %f" % self.X, self.Y, self.Z
        print "END CameraBrain1_Avatar"

    def import_obj(self,obj):
        plCameraBrain1.import_obj(self,obj)
        obj.addProperty("cambrain","avatar")
        obj.addProperty("AvCam_X",float(self.X))
        obj.addProperty("AvCam_Y",float(self.Y))
        obj.addProperty("AvCam_Z",float(self.Z))

    def export_obj(self,obj,prp):
        plCameraBrain1.export_obj(self,obj,prp)
        self.X = getFloatPropertyOrDefault(obj,"AvCam_X",self.X)
        self.Y = getFloatPropertyOrDefault(obj,"AvCam_Y",self.Y)
        self.Z = getFloatPropertyOrDefault(obj,"AvCam_Z",self.Z)

class plCameraBrain1_FirstPerson(plCameraBrain1):    
    def __init__(self,parent,name="unnamed"):
        plCameraBrain1.__init__(self,parent,name,0x00B3)

        # set the Camerabrain1 floats to match defaults for this brain type
        self.float0 = 30
        self.float1 = 30
        self.float2 = 30
        self.float3 = 30
        self.float4 = 30
        self.float5 = 30
        self.float6 = 0 # Various numbers between 0.0 and 0.99999 often similar as float7
        self.float7 = 0 # Various numbers between 0.0 and 0.99999 often similar as float6

        #format
        self.FP_X = 0
        self.FP_Y = 0
        self.FP_Z = 0
        
        
    def changePageRaw(self,sid,did,stype,dtype):
        plCameraBrain1.changePageRaw(self,sid,did,stype,dtype)

    def read(self,buf):
        plCameraBrain1.read(self,buf)
        self.FP_X, self.FP_Y, self.FP_Z, = struct.unpack("fff",buf.read(3*4))

    def write(self,buf):
        plCameraBrain1.write(self,buf)
        buf.write(struct.pack("fff",self.FP_X, self.FP_Y, self.FP_Z))

    def dump(self):
        print "BEGIN CameraBrain1_FirstPerson %s " % self.Key.name
        print "X = %f, Y = %f Z = %f" % self.FP_POA_X, self.FP_POA_Y, self.FP_POA_Z
        print "END CameraBrain1_FirstPerson"

    def import_obj(self,obj):
        plCameraBrain1.import_obj(self,obj)
        obj.addProperty("cambrain","firstperson")
        obj.addProperty("FpCam_X",float(self.FP_X))
        obj.addProperty("FpCam_Y",float(self.FP_Y))
        obj.addProperty("FpCam_Z",float(self.FP_Z))

    def export_obj(self,obj,prp):
        plCameraBrain1.export_obj(self,obj,prp)
        self.FP_X = getFloatPropertyOrDefault(obj,"FpCam_X",self.FP_X)
        self.FP_Y = getFloatPropertyOrDefault(obj,"FpCam_Y",self.FP_Y)
        self.FP_Z = getFloatPropertyOrDefault(obj,"FpCam_Z",self.FP_Z)


class plDynaDecalMgr(plSynchedObject):    
    def __init__(self,parent,name="unnamed",type=0x00E6):
        plSynchedObject.__init__(self,parent,name,type)
        #format
        self.mat1 = UruObjectRef()
        self.mat2 = UruObjectRef()
        
        self.SO1Count
        self.SceneObjects1 = []
        self.SO2Count
        self.SceneObjects2 = []

        self.sA0 = 0x000003E8
        self.sA2 = 0x000003E8
        self.iA4 = 0x00000000

        self.fD0 = 0.0   # fB8 = fD0

        self.fA8
        self.fAC
        self.fB0
        self.fB4
        self.fBC
        self.fC0
        
        self.VC4 = Vertex()
        self.f9C
        
        self.iMsgCount
        self.vMEC = [] # plMessage[MsgCount]
                

    def changePageRaw(self,sid,did,stype,dtype):
        plSynchedObject.changePageRaw(self,sid,did,stype,dtype)


    def read(self,buf,size):
        plSynchedObject.read(self,buf)


    def write(self,buf):
        plSynchedObject.write(self,buf)

        

    def dump(self):
        print "BEGIN DynaFootMgr %s " % self.Key.name
        print "END DynaFootMgr"


    def import_obj(self,obj):
        pass

    def export_obj(self,obj,prp):
        pass
