home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Multimedia / k3d-setup-0.7.11.0.exe / lib / site-packages / cgkit / lwob.py < prev    next >
Encoding:
Python Source  |  2007-01-11  |  34.6 KB  |  1,017 lines

  1. # ***** BEGIN LICENSE BLOCK *****
  2. # Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. #
  4. # The contents of this file are subject to the Mozilla Public License Version
  5. # 1.1 (the "License"); you may not use this file except in compliance with
  6. # the License. You may obtain a copy of the License at
  7. # http://www.mozilla.org/MPL/
  8. #
  9. # Software distributed under the License is distributed on an "AS IS" basis,
  10. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. # for the specific language governing rights and limitations under the
  12. # License.
  13. #
  14. # The Original Code is the Python Computer Graphics Kit.
  15. #
  16. # The Initial Developer of the Original Code is Matthias Baas.
  17. # Portions created by the Initial Developer are Copyright (C) 2004
  18. # the Initial Developer. All Rights Reserved.
  19. #
  20. # Contributor(s):
  21. #
  22. # Alternatively, the contents of this file may be used under the terms of
  23. # either the GNU General Public License Version 2 or later (the "GPL"), or
  24. # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  25. # in which case the provisions of the GPL or the LGPL are applicable instead
  26. # of those above. If you wish to allow use of your version of this file only
  27. # under the terms of either the GPL or the LGPL, and not to allow others to
  28. # use your version of this file under the terms of the MPL, indicate your
  29. # decision by deleting the provisions above and replace them with the notice
  30. # and other provisions required by the GPL or the LGPL. If you do not delete
  31. # the provisions above, a recipient may use your version of this file under
  32. # the terms of any one of the MPL, the GPL or the LGPL.
  33. #
  34. # ***** END LICENSE BLOCK *****
  35. # $Id: lwob.py,v 1.1 2006/03/12 22:41:42 mbaas Exp $
  36.  
  37. import struct
  38. from cgtypes import vec3
  39.  
  40. class LWOBError(Exception):
  41.     pass
  42.  
  43. # Texture
  44. class Texture:
  45.     """Texture description.
  46.  
  47.     A value remains None if it wasn't set in the LWOB file.
  48.     """
  49.     def __init__(self):
  50.         self.type = None        # str
  51.         self.flags = None       # int
  52.         self.size = None        # vec3
  53.         self.center = None      # vec3
  54.         self.falloff = None     # vec3
  55.         self.velocity = None    # vec3
  56.         self.color = None       # 3-tuple
  57.         self.value = None       # int
  58.         self.bumpamplitude = None # float
  59.         self.floatparams = 10*[None]  # list of floats
  60.         self.intparams = 10*[None]    # list of ints
  61.         self.imagename = None   # str
  62.         self.alphaname = None   # str
  63.         self.widthwrap = None   # int
  64.         self.heightwrap = None  # int
  65.         self.antialiasingstrength = None # float
  66.         self.opacity = None     # float
  67.         self.shader = []        # list of str
  68.         self.shaderdata = []    # list of str
  69.         self.seq_offset = None  # int
  70.         self.seq_flags = None   # int
  71.         self.seq_looplength = None # int
  72.         self.flyer_begin = None # int
  73.         self.flyer_end = None   # int
  74.         self.cycle_speed = None # int
  75.         self.cycle_low = None   # int
  76.         self.cycle_high = None  # int
  77.  
  78. # Surface
  79. class Surface:
  80.     """Surface description.
  81.  
  82.     A value remains None if it wasn't set in the LWOB file.    
  83.     """
  84.     
  85.     def __init__(self, name):
  86.         self.name = name
  87.         
  88.         self.color = None          # 3-tuple
  89.         self.flags = None          # int
  90.         self.luminosity = None     # float
  91.         self.diffuse = None        # float
  92.         self.specular = None       # float
  93.         self.reflection = None     # float
  94.         self.transparency = None   # float
  95.         self.glossiness = None     # int
  96.         self.reflectionmode = None # int
  97.         self.refmap = None         # str
  98.         self.refmap_seamangle = None # float
  99.         self.refractiveindex = None  # float
  100.         self.edgetransp = None     # float
  101.         self.maxsmoothangle = None # float
  102.  
  103.         self.tex_color = []        # list of Texture objects
  104.         self.tex_diffuse = []
  105.         self.tex_specular = []
  106.         self.tex_reflection = []
  107.         self.tex_transparency = []
  108.         self.tex_luminosity = []
  109.         self.tex_bump = []
  110.         
  111.  
  112. # LWOBReader
  113. class LWOBReader:
  114.     """Lightwave Object reader.
  115.  
  116.     This class reads Lightwave Object (*.lwo) files and calls handler
  117.     methods for each chunk found. The following handler methods can be
  118.     implemented in derived classes:
  119.  
  120.     - handlePNTS(points):  points is a list of vec3 objects containing
  121.                            all vertices.
  122.     - handleSRFS(names):   names is a list of strings containing the names
  123.                            of all surface definitions.
  124.     - handlePOLS(polys):   polys is a list of polygons. Each polygon is a
  125.                            tuple (verts, surface) where verts is a list of
  126.                            vertex indices and surface the index of the surface
  127.                            that is used by this polygon.
  128.     - handleCRVS(curves):  curves is a list of curves. Each curve is a
  129.                            tuple (verts, surface, flags).
  130.     - handlePCHS(patches): patches is a list of patches. Each patch is a
  131.                            tuple (verts, surface).
  132.     - handleSURF(surface): surface is a Surface object that contains the
  133.                            surface attributes.
  134.     """
  135.  
  136.     def __init__(self):
  137.         """Constructor.
  138.         """
  139.         # The file handle
  140.         self._file = None
  141.         # The number of bytes that are left in the file.
  142.         # After the FORM has been read, it is initialized with the
  143.         # FORM length and is used to determine whether there are still
  144.         # more chunks left or not.
  145.         self._bytes_left = 12
  146.  
  147.         # Current Surface object when reading a SURF chunk
  148.         self._current_surface = None
  149.         # Current Texture object
  150.         self._current_tex = None
  151.  
  152.     def read(self, file):
  153.         """Read the lwo file.
  154.  
  155.         file is a file-like object that provides the read() and seek()
  156.         methods.
  157.         """
  158.         self._file = file
  159.         self._bytes_left = 12
  160.         
  161.         # Read the FORM header...
  162.         tag, length = self.readChunkHeader()
  163.         self.onChunk(tag, length, 0)
  164.         self._bytes_left = length
  165.         if tag!="FORM":
  166.             raise LWOBError("Not a Lightwave object file")
  167.  
  168.         # Read the LWOB tag...
  169.         lwob = self.readNBytes(4)
  170.         if lwob!="LWOB":
  171.             raise LWOBError("Not a Lightwave object file")
  172.  
  173.         # Read the contained chunks and call the 'reader' method if available.
  174.         # If no reader is defined for a chunk this chunk is skipped.
  175.         while not self._eofReached():
  176.             tag,length = self.readChunkHeader()
  177.             self.onChunk(tag, length, 1)
  178. #            print tag, length
  179.             handlername = "read%s"%tag
  180.             handler = getattr(self, handlername, None)
  181.             if handler==None:
  182.                 self.skipChunk(length)
  183.             else:
  184.                 handler(length)
  185.  
  186.  
  187.     # Handler methods. These methods can be overridden in derived classes.
  188.  
  189.     def onChunk(self, tag, length, level): pass
  190.  
  191.     def handlePNTS(self, points): pass
  192.     def handleSRFS(self, names): pass
  193.     def handlePOLS(self, polys): pass
  194.     def handleCRVS(self, curves): pass
  195.     def handlePCHS(self, patches): pass
  196.     def handleSURF(self, surface): pass
  197.  
  198.  
  199.     ### readXXXX() reader methods (XXXX is the chunk tag)
  200.     ### A reader takes the chunk length as argument and has to read
  201.     ### its data from the file and call an appropriate handler method
  202.     ### (handleXXXX(...))
  203.  
  204.     def readPNTS(self, length):
  205.         """Read a PNTS chunk and call the PNTS handler.
  206.         """
  207.         if length%12!=0:
  208.             raise LWOBError, "Invalid PNTS chunk size (%d)"%length
  209.         
  210.         numpnts = int(length/12)
  211.         # Read the chunk data...
  212.         data = self.readNBytes(length)
  213.         # Unpack the coordinates...
  214.         coords = struct.unpack(">%s"%(numpnts*"fff"), data)
  215.         # Initialize vec3s...
  216.         pnts = []
  217.         for i in range(numpnts):
  218.             pnts.append(vec3(coords[i*3:(i+1)*3]))
  219.             
  220.         self.handlePNTS(pnts)
  221.  
  222.     def readSRFS(self, length):
  223.         """Read a SRFS chunk and call the SRFS handler.
  224.         """
  225.         data = self.readNBytes(length)
  226.         names = []
  227.         while len(data)>0:
  228.             n = data.find("\000")
  229.             if n==-1:
  230.                 n = len(data)
  231.             names.append(data[:n])
  232.             if n%2==0:
  233.                 n+=1
  234.             data = data[n+1:]
  235.  
  236.         self.handleSRFS(names)
  237.  
  238.     def readPOLS(self, length):
  239.         """Read a POLS chunk and call the POLS handler.
  240.         """
  241.         data = self.readNBytes(length)
  242.         idx = 0
  243.         unpack = struct.unpack
  244.         polys = []
  245.         # The number of detail polygons that follow
  246.         # (detail polygons are ignored)
  247.         details_left = 0
  248.         while idx<len(data):
  249.             numverts = unpack(">H", data[idx:idx+2])[0]
  250.             idx += 2
  251.             verts = unpack(">%s"%(numverts*"H"), data[idx:idx+numverts*2])
  252.             idx += numverts*2
  253.             surf = unpack(">H", data[idx:idx+2])[0]
  254.             idx += 2
  255.             if details_left==0:
  256.                 polys.append((verts, surf))
  257.             else:
  258.                 details_left -= 1
  259.  
  260.             # Does the polygon have detail polygons?
  261.             if surf<0:
  262.                 details_left = unpack(">H", data[idx:idx+2])[0]
  263.                 idx += 2
  264.  
  265.         self.handlePOLS(polys)
  266.  
  267.     def readCRVS(self, length):
  268.         """Read a CRVS chunk and call the CRVS handler.
  269.         """
  270.         data = self.readNBytes(length)
  271.         idx = 0
  272.         unpack = struct.unpack
  273.         curves = []
  274.         while idx<len(data):
  275.             numverts = unpack(">H", data[idx:idx+2])[0]
  276.             idx += 2
  277.             verts = unpack(">%s"%(numverts*"H"), data[idx:idx+numverts*2])
  278.             idx += numverts*2
  279.             surf,flags = unpack(">HH", data[idx:idx+4])
  280.             idx += 4
  281.             curves.append((verts, surf, flags))
  282.  
  283.         self.handleCRVS(curves)
  284.         
  285.     def readPCHS(self, length):
  286.         """Read a PCHS chunk and call the PCHS handler.
  287.         """
  288.         data = self.readNBytes(length)
  289.         idx = 0
  290.         unpack = struct.unpack
  291.         patches = []
  292.         while idx<len(data):
  293.             numverts = unpack(">H", data[idx:idx+2])[0]
  294.             idx += 2
  295.             verts = unpack(">%s"%(numverts*"H"), data[idx:idx+numverts*2])
  296.             idx += numverts*2
  297.             surf = unpack(">H", data[idx:idx+2])[0]
  298.             idx += 2
  299.             patched.append((verts, surf))
  300.  
  301.         self.handlePCHS(patches)
  302.  
  303.     def readSURF(self, length):
  304.         """Read a SURF chunk and call the SURF handler.
  305.         """
  306.         # Read the surface name byte by byte...
  307.         name = ""
  308.         while 1:
  309.             c = self.readNBytes(1)
  310.             length -= 1
  311.             if ord(c)==0:
  312.                 if len(name)%2==0:
  313.                     # Skip the pad byte
  314.                     self.readNBytes(1)
  315.                     length -= 1
  316.                 break
  317.             name += c
  318.  
  319.         self._current_surface = Surface(name)
  320.         self._current_tex = None
  321.         
  322. #        print "SURFACE",name
  323.         while length>0:
  324.             tag,sublength = self.readSubChunkHeader()
  325.             self.onChunk(tag, sublength, 2)
  326.             length -= 6+sublength
  327. #            print " ",tag,sublength
  328.             handlername = "readSURF_%s"%tag
  329.             handler = getattr(self, handlername, None)
  330.             if handler==None:
  331.                 self.skipChunk(sublength)
  332.             else:
  333.                 handler(sublength)
  334.  
  335.         self.handleSURF(self._current_surface)
  336.         self._current_tex = None
  337.         self._current_surface = None
  338.  
  339.     def readSURF_COLR(self, length):
  340.         """COLR chunk."""
  341.         if length!=4:
  342.             raise LWOBError, "Invalid COLR size (%d instead of 4)"%length
  343.         data = self.readNBytes(4)
  344.         color = struct.unpack(">BBB", data[:3])
  345.         self._current_surface.color = color
  346.  
  347.     def readSURF_FLAG(self, length):
  348.         """FLAG chunk."""
  349.         if length!=2:
  350.             raise LWOBError, "Invalid FLAG size (%d instead of 2)"%length
  351.         data = self.readNBytes(2)
  352.         flags = struct.unpack(">H", data)[0]
  353.         self._current_surface.flags = flags
  354.         
  355.     def readSURF_LUMI(self, length):
  356.         """LUMI chunk."""
  357.         if length!=2:
  358.             raise LWOBError, "Invalid LUMI size (%d instead of 2)"%length
  359.         data = self.readNBytes(2)
  360.         lumi = struct.unpack(">H", data)[0]
  361.         if self._current_surface.luminosity==None:
  362.             self._current_surface.luminosity = lumi/256.0
  363.  
  364.     def readSURF_VLUM(self, length):
  365.         """VLUM chunk."""
  366.         if length!=4:
  367.             raise LWOBError, "Invalid VLUM size (%d instead of 4)"%length
  368.         data = self.readNBytes(4)
  369.         lum = struct.unpack(">f", data)[0]
  370.         self._current_surface.luminosity = lum
  371.  
  372.     def readSURF_DIFF(self, length):
  373.         """DIFF chunk."""
  374.         if length!=2:
  375.             raise LWOBError, "Invalid DIFF size (%d instead of 2)"%length
  376.         data = self.readNBytes(2)
  377.         diff = struct.unpack(">H", data)[0]
  378.         if self._current_surface.diffuse==None:
  379.             self._current_surface.diffuse = diff/256.0
  380.  
  381.     def readSURF_VDIF(self, length):
  382.         """VDIF chunk."""
  383.         if length!=4:
  384.             raise LWOBError, "Invalid VDIF size (%d instead of 4)"%length
  385.         data = self.readNBytes(4)
  386.         diff = struct.unpack(">f", data)[0]
  387.         self._current_surface.diffuse = diff
  388.  
  389.     def readSURF_SPEC(self, length):
  390.         """SPEC chunk."""
  391.         if length!=2:
  392.             raise LWOBError, "Invalid SPEC size (%d instead of 2)"%length
  393.         data = self.readNBytes(2)
  394.         spec = struct.unpack(">H", data)[0]
  395.         if self._current_surface.specular==None:
  396.             self._current_surface.specular = spec/256.0
  397.  
  398.     def readSURF_VSPC(self, length):
  399.         """VSPC chunk."""
  400.         if length!=4:
  401.             raise LWOBError, "Invalid VSPC size (%d instead of 4)"%length
  402.         data = self.readNBytes(4)
  403.         spec = struct.unpack(">f", data)[0]
  404.         self._current_surface.specular = spec
  405.  
  406.     def readSURF_REFL(self, length):
  407.         """REFL chunk."""
  408.         if length!=2:
  409.             raise LWOBError, "Invalid REFL size (%d instead of 2)"%length
  410.         data = self.readNBytes(2)
  411.         refl = struct.unpack(">H", data)[0]
  412.         if self._current_surface.reflection==None:
  413.             self._current_surface.reflection = refl/256.0
  414.  
  415.     def readSURF_VRFL(self, length):
  416.         """VRFL chunk."""
  417.         if length!=4:
  418.             raise LWOBError, "Invalid VRFL size (%d instead of 4)"%length
  419.         data = self.readNBytes(4)
  420.         refl = struct.unpack(">f", data)[0]
  421.         self._current_surface.reflection = refl
  422.  
  423.     def readSURF_TRAN(self, length):
  424.         """TRAN chunk."""
  425.         if length!=2:
  426.             raise LWOBError, "Invalid TRAN size (%d instead of 2)"%length
  427.         data = self.readNBytes(2)
  428.         tran = struct.unpack(">H", data)[0]
  429.         if self._current_surface.transparency==None:
  430.             self._current_surface.transparency = tran/256.0
  431.  
  432.     def readSURF_VTRN(self, length):
  433.         """VTRN chunk."""
  434.         if length!=4:
  435.             raise LWOBError, "Invalid VTRN size (%d instead of 4)"%length
  436.         data = self.readNBytes(4)
  437.         tran = struct.unpack(">f", data)[0]
  438.         self._current_surface.transparency = tran
  439.  
  440.     def readSURF_GLOS(self, length):
  441.         """GLOS chunk."""
  442.         if length!=2:
  443.             raise LWOBError, "Invalid GLOS size (%d instead of 2)"%length
  444.         data = self.readNBytes(2)
  445.         glos = struct.unpack(">H", data)[0]
  446.         self._current_surface.glossiness = glos
  447.  
  448.     def readSURF_RFLT(self, length):
  449.         """RFLT chunk."""
  450.         if length!=2:
  451.             raise LWOBError, "Invalid RFLT size (%d instead of 2)"%length
  452.         data = self.readNBytes(2)
  453.         mode = struct.unpack(">H", data)[0]
  454.         self._current_surface.reflectionmode = mode
  455.  
  456.     def readSURF_RIMG(self, length):
  457.         """RIMG chunk."""
  458.         data = self.readNBytes(length)
  459.         n = data.find("\000")
  460.         if n!=-1:
  461.             data = data[:n]
  462.         self._current_surface.refmap = data
  463.  
  464.     def readSURF_RSAN(self, length):
  465.         """RSAN chunk."""
  466.         if length!=4:
  467.             raise LWOBError, "Invalid RSAN size (%d instead of 4)"%length
  468.         data = self.readNBytes(4)
  469.         deg = struct.unpack(">f", data)[0]
  470.         self._current_surface.refmap_seamangle = deg
  471.  
  472.     def readSURF_RIND(self, length):
  473.         """RIND chunk."""
  474.         if length!=4:
  475.             raise LWOBError, "Invalid RIND size (%d instead of 4)"%length
  476.         data = self.readNBytes(4)
  477.         ior = struct.unpack(">f", data)[0]
  478.         self._current_surface.refractiveindex = ior
  479.  
  480.     def readSURF_EDGE(self, length):
  481.         """EDGE chunk."""
  482.         if length!=4:
  483.             raise LWOBError, "Invalid EDGE size (%d instead of 4)"%length
  484.         data = self.readNBytes(4)
  485.         edge = struct.unpack(">f", data)[0]
  486.         self._current_surface.edgetransp = edge
  487.  
  488.     def readSURF_SMAN(self, length):
  489.         """SMAN chunk."""
  490.         if length!=4:
  491.             raise LWOBError, "Invalid SMAN size (%d instead of 4)"%length
  492.         data = self.readNBytes(4)
  493.         sman = struct.unpack(">f", data)[0]
  494.         self._current_surface.maxsmoothangle = sman
  495.  
  496.     def readSURF_CTEX(self, length):
  497.         """CTEX chunk."""
  498.         data = self.readNBytes(length)
  499.         n = data.find("\000")
  500.         if n!=-1:
  501.             data = data[:n]
  502.  
  503.         tex = Texture()
  504.         tex.type = data
  505.         self._current_tex = tex
  506.         self._current_surface.tex_color.append(tex)
  507.  
  508.     def readSURF_DTEX(self, length):
  509.         """DTEX chunk."""
  510.         data = self.readNBytes(length)
  511.         n = data.find("\000")
  512.         if n!=-1:
  513.             data = data[:n]
  514.  
  515.         tex = Texture()
  516.         tex.type = data
  517.         self._current_tex = tex
  518.         self._current_surface.tex_diffuse.append(tex)
  519.  
  520.     def readSURF_STEX(self, length):
  521.         """STEX chunk."""
  522.         data = self.readNBytes(length)
  523.         n = data.find("\000")
  524.         if n!=-1:
  525.             data = data[:n]
  526.  
  527.         tex = Texture()
  528.         tex.type = data
  529.         self._current_tex = tex
  530.         self._current_surface.tex_specular.append(tex)
  531.  
  532.     def readSURF_RTEX(self, length):
  533.         """RTEX chunk."""
  534.         data = self.readNBytes(length)
  535.         n = data.find("\000")
  536.         if n!=-1:
  537.             data = data[:n]
  538.  
  539.         tex = Texture()
  540.         tex.type = data
  541.         self._current_tex = tex
  542.         self._current_surface.tex_reflection.append(tex)
  543.  
  544.     def readSURF_TTEX(self, length):
  545.         """TTEX chunk."""
  546.         data = self.readNBytes(length)
  547.         n = data.find("\000")
  548.         if n!=-1:
  549.             data = data[:n]
  550.  
  551.         tex = Texture()
  552.         tex.type = data
  553.         self._current_tex = tex
  554.         self._current_surface.tex_transparency.append(tex)
  555.  
  556.     def readSURF_LTEX(self, length):
  557.         """LTEX chunk."""
  558.         data = self.readNBytes(length)
  559.         n = data.find("\000")
  560.         if n!=-1:
  561.             data = data[:n]
  562.  
  563.         tex = Texture()
  564.         tex.type = data
  565.         self._current_tex = tex
  566.         self._current_surface.tex_luminosity.append(tex)
  567.  
  568.     def readSURF_BTEX(self, length):
  569.         """BTEX chunk."""
  570.         data = self.readNBytes(length)
  571.         n = data.find("\000")
  572.         if n!=-1:
  573.             data = data[:n]
  574.  
  575.         tex = Texture()
  576.         tex.type = data
  577.         self._current_tex = tex
  578.         self._current_surface.tex_bump.append(tex)
  579.  
  580.     def readSURF_TFLG(self, length):
  581.         """TFLG chunk."""
  582.         if length!=2:
  583.             raise LWOBError, "Invalid TFLG size (%d instead of 2)"%length
  584.         if self._current_tex==None:
  585.             raise LWOBError, "Invalid position of the TFLG chunk"
  586.         data = self.readNBytes(2)
  587.         flags = struct.unpack(">H", data)[0]
  588.         self._current_tex.flags = flags
  589.  
  590.     def readSURF_TSIZ(self, length):
  591.         """TSIZ chunk."""
  592.         if length!=12:
  593.             raise LWOBError, "Invalid TSIZ size (%d instead of 12)"%length
  594.         if self._current_tex==None:
  595.             raise LWOBError, "Invalid position of the TSIZ chunk"
  596.         data = self.readNBytes(12)
  597.         v = vec3(struct.unpack(">fff", data))
  598.         self._current_tex.size = v
  599.  
  600.     def readSURF_TCTR(self, length):
  601.         """TCTR chunk."""
  602.         if length!=12:
  603.             raise LWOBError, "Invalid TCTR size (%d instead of 12)"%length
  604.         if self._current_tex==None:
  605.             raise LWOBError, "Invalid position of the TCTR chunk"
  606.         data = self.readNBytes(12)
  607.         v = vec3(struct.unpack(">fff", data))
  608.         self._current_tex.center = v
  609.  
  610.     def readSURF_TFAL(self, length):
  611.         """TFAL chunk."""
  612.         if length!=12:
  613.             raise LWOBError, "Invalid TFAL size (%d instead of 12)"%length
  614.         if self._current_tex==None:
  615.             raise LWOBError, "Invalid position of the TFAL chunk"
  616.         data = self.readNBytes(12)
  617.         v = vec3(struct.unpack(">fff", data))
  618.         self._current_tex.falloff = v
  619.  
  620.     def readSURF_TVEL(self, length):
  621.         """TVEL chunk."""
  622.         if length!=12:
  623.             raise LWOBError, "Invalid TVEL size (%d instead of 12)"%length
  624.         if self._current_tex==None:
  625.             raise LWOBError, "Invalid position of the TVEL chunk"
  626.         data = self.readNBytes(12)
  627.         v = vec3(struct.unpack(">fff", data))
  628.         self._current_tex.velocity = v
  629.  
  630.     def readSURF_TCLR(self, length):
  631.         """TCLR chunk."""
  632.         if length!=4:
  633.             raise LWOBError, "Invalid TCLR size (%d instead of 4)"%length
  634.         if self._current_tex==None:
  635.             raise LWOBError, "Invalid position of the TCLR chunk"
  636.         data = self.readNBytes(4)
  637.         col = struct.unpack(">BBB", data[:3])
  638.         self._current_tex.color = v
  639.  
  640.     def readSURF_TVAL(self, length):
  641.         """TVAL chunk."""
  642.         if length!=2:
  643.             raise LWOBError, "Invalid TVAL size (%d instead of 2)"%length
  644.         if self._current_tex==None:
  645.             raise LWOBError, "Invalid position of the TVAL chunk"
  646.         data = self.readNBytes(2)
  647.         val = struct.unpack(">H", data)[0]
  648.         self._current_tex.value = val
  649.  
  650.     def readSURF_TAMP(self, length):
  651.         """TAMP chunk."""
  652.         if length!=4:
  653.             raise LWOBError, "Invalid TAMP size (%d instead of 4)"%length
  654.         if self._current_tex==None:
  655.             raise LWOBError, "Invalid position of the TAMP chunk"
  656.         data = self.readNBytes(4)
  657.         amp = struct.unpack(">f", data)[0]
  658.         self._current_tex.bumpamplitude = amp
  659.  
  660.     def readSURF_TFP0(self, length):
  661.         """TFP0 chunk."""
  662.         if length!=4:
  663.             raise LWOBError, "Invalid TFP0 size (%d instead of 4)"%length
  664.         if self._current_tex==None:
  665.             raise LWOBError, "Invalid position of the TFP0 chunk"
  666.         data = self.readNBytes(4)
  667.         f = struct.unpack(">f", data)[0]
  668.         self._current_tex.floatparams[0] = f
  669.  
  670.     def readSURF_TFP1(self, length):
  671.         """TFP1 chunk."""
  672.         if length!=4:
  673.             raise LWOBError, "Invalid TFP1 size (%d instead of 4)"%length
  674.         if self._current_tex==None:
  675.             raise LWOBError, "Invalid position of the TFP1 chunk"
  676.         data = self.readNBytes(4)
  677.         f = struct.unpack(">f", data)[0]
  678.         self._current_tex.floatparams[1] = f
  679.  
  680.     def readSURF_TFP2(self, length):
  681.         """TFP2 chunk."""
  682.         if length!=4:
  683.             raise LWOBError, "Invalid TFP2 size (%d instead of 4)"%length
  684.         if self._current_tex==None:
  685.             raise LWOBError, "Invalid position of the TFP2 chunk"
  686.         data = self.readNBytes(4)
  687.         f = struct.unpack(">f", data)[0]
  688.         self._current_tex.floatparams[2] = f
  689.  
  690.     def readSURF_TFP3(self, length):
  691.         """TFP3 chunk."""
  692.         if length!=4:
  693.             raise LWOBError, "Invalid TFP3 size (%d instead of 4)"%length
  694.         if self._current_tex==None:
  695.             raise LWOBError, "Invalid position of the TFP3 chunk"
  696.         data = self.readNBytes(4)
  697.         f = struct.unpack(">f", data)[0]
  698.         self._current_tex.floatparams[3] = f
  699.  
  700.     def readSURF_TFP4(self, length):
  701.         """TFP4 chunk."""
  702.         if length!=4:
  703.             raise LWOBError, "Invalid TFP4 size (%d instead of 4)"%length
  704.         if self._current_tex==None:
  705.             raise LWOBError, "Invalid position of the TFP4 chunk"
  706.         data = self.readNBytes(4)
  707.         f = struct.unpack(">f", data)[0]
  708.         self._current_tex.floatparams[4] = f
  709.  
  710.     def readSURF_TFP5(self, length):
  711.         """TFP5 chunk."""
  712.         if length!=4:
  713.             raise LWOBError, "Invalid TFP5 size (%d instead of 4)"%length
  714.         if self._current_tex==None:
  715.             raise LWOBError, "Invalid position of the TFP5 chunk"
  716.         data = self.readNBytes(4)
  717.         f = struct.unpack(">f", data)[0]
  718.         self._current_tex.floatparams[5] = f
  719.  
  720.     def readSURF_TFP6(self, length):
  721.         """TFP6 chunk."""
  722.         if length!=4:
  723.             raise LWOBError, "Invalid TFP6 size (%d instead of 4)"%length
  724.         if self._current_tex==None:
  725.             raise LWOBError, "Invalid position of the TFP6 chunk"
  726.         data = self.readNBytes(4)
  727.         f = struct.unpack(">f", data)[0]
  728.         self._current_tex.floatparams[6] = f
  729.  
  730.     def readSURF_TFP7(self, length):
  731.         """TFP7 chunk."""
  732.         if length!=4:
  733.             raise LWOBError, "Invalid TFP7 size (%d instead of 4)"%length
  734.         if self._current_tex==None:
  735.             raise LWOBError, "Invalid position of the TFP7 chunk"
  736.         data = self.readNBytes(4)
  737.         f = struct.unpack(">f", data)[0]
  738.         self._current_tex.floatparams[7] = f
  739.  
  740.     def readSURF_TFP8(self, length):
  741.         """TFP8 chunk."""
  742.         if length!=4:
  743.             raise LWOBError, "Invalid TFP8 size (%d instead of 4)"%length
  744.         if self._current_tex==None:
  745.             raise LWOBError, "Invalid position of the TFP8 chunk"
  746.         data = self.readNBytes(4)
  747.         f = struct.unpack(">f", data)[0]
  748.         self._current_tex.floatparams[8] = f
  749.  
  750.     def readSURF_TFP9(self, length):
  751.         """TFP9 chunk."""
  752.         if length!=4:
  753.             raise LWOBError, "Invalid TFP9 size (%d instead of 4)"%length
  754.         if self._current_tex==None:
  755.             raise LWOBError, "Invalid position of the TFP9 chunk"
  756.         data = self.readNBytes(4)
  757.         f = struct.unpack(">f", data)[0]
  758.         self._current_tex.floatparams[9] = f
  759.  
  760.     def readSURF_TIP0(self, length):
  761.         """TIP0 chunk."""
  762.         if length!=2:
  763.             raise LWOBError, "Invalid TIP0 size (%d instead of 2)"%length
  764.         if self._current_tex==None:
  765.             raise LWOBError, "Invalid position of the TIP0 chunk"
  766.         data = self.readNBytes(2)
  767.         i = struct.unpack(">h", data)[0]
  768.         self._current_tex.intparams[0] = i
  769.  
  770.     def readSURF_TIP1(self, length):
  771.         """TIP1 chunk."""
  772.         if length!=2:
  773.             raise LWOBError, "Invalid TIP1 size (%d instead of 2)"%length
  774.         if self._current_tex==None:
  775.             raise LWOBError, "Invalid position of the TIP1 chunk"
  776.         data = self.readNBytes(2)
  777.         i = struct.unpack(">h", data)[0]
  778.         self._current_tex.intparams[1] = i
  779.  
  780.     def readSURF_TIP2(self, length):
  781.         """TIP2 chunk."""
  782.         if length!=2:
  783.             raise LWOBError, "Invalid TIP2 size (%d instead of 2)"%length
  784.         if self._current_tex==None:
  785.             raise LWOBError, "Invalid position of the TIP2 chunk"
  786.         data = self.readNBytes(2)
  787.         i = struct.unpack(">h", data)[0]
  788.         self._current_tex.intparams[2] = i
  789.  
  790.     def readSURF_TIP3(self, length):
  791.         """TIP3 chunk."""
  792.         if length!=2:
  793.             raise LWOBError, "Invalid TIP3 size (%d instead of 2)"%length
  794.         if self._current_tex==None:
  795.             raise LWOBError, "Invalid position of the TIP3 chunk"
  796.         data = self.readNBytes(2)
  797.         i = struct.unpack(">h", data)[0]
  798.         self._current_tex.intparams[3] = i
  799.  
  800.     def readSURF_TIP4(self, length):
  801.         """TIP4 chunk."""
  802.         if length!=2:
  803.             raise LWOBError, "Invalid TIP4 size (%d instead of 2)"%length
  804.         if self._current_tex==None:
  805.             raise LWOBError, "Invalid position of the TIP4 chunk"
  806.         data = self.readNBytes(2)
  807.         i = struct.unpack(">h", data)[0]
  808.         self._current_tex.intparams[4] = i
  809.  
  810.     def readSURF_TIP5(self, length):
  811.         """TIP5 chunk."""
  812.         if length!=2:
  813.             raise LWOBError, "Invalid TIP5 size (%d instead of 2)"%length
  814.         if self._current_tex==None:
  815.             raise LWOBError, "Invalid position of the TIP5 chunk"
  816.         data = self.readNBytes(2)
  817.         i = struct.unpack(">h", data)[0]
  818.         self._current_tex.intparams[5] = i
  819.  
  820.     def readSURF_TIP6(self, length):
  821.         """TIP6 chunk."""
  822.         if length!=2:
  823.             raise LWOBError, "Invalid TIP6 size (%d instead of 2)"%length
  824.         if self._current_tex==None:
  825.             raise LWOBError, "Invalid position of the TIP6 chunk"
  826.         data = self.readNBytes(2)
  827.         i = struct.unpack(">h", data)[0]
  828.         self._current_tex.intparams[6] = i
  829.  
  830.     def readSURF_TIP7(self, length):
  831.         """TIP7 chunk."""
  832.         if length!=2:
  833.             raise LWOBError, "Invalid TIP7 size (%d instead of 2)"%length
  834.         if self._current_tex==None:
  835.             raise LWOBError, "Invalid position of the TIP7 chunk"
  836.         data = self.readNBytes(2)
  837.         i = struct.unpack(">h", data)[0]
  838.         self._current_tex.intparams[7] = i
  839.  
  840.     def readSURF_TIP8(self, length):
  841.         """TIP8 chunk."""
  842.         if length!=2:
  843.             raise LWOBError, "Invalid TIP8 size (%d instead of 2)"%length
  844.         if self._current_tex==None:
  845.             raise LWOBError, "Invalid position of the TIP8 chunk"
  846.         data = self.readNBytes(2)
  847.         i = struct.unpack(">h", data)[0]
  848.         self._current_tex.intparams[8] = i
  849.  
  850.     def readSURF_TIP9(self, length):
  851.         """TIP9 chunk."""
  852.         if length!=2:
  853.             raise LWOBError, "Invalid TIP9 size (%d instead of 2)"%length
  854.         if self._current_tex==None:
  855.             raise LWOBError, "Invalid position of the TIP9 chunk"
  856.         data = self.readNBytes(2)
  857.         i = struct.unpack(">h", data)[0]
  858.         self._current_tex.intparams[9] = i
  859.  
  860.     def readSURF_TIMG(self, length):
  861.         """TIMG chunk."""
  862.         if self._current_tex==None:
  863.             raise LWOBError, "Invalid position of the TIMG chunk"
  864.         data = self.readNBytes(length)
  865.         n = data.find("\000")
  866.         if n!=-1:
  867.             data = data[:n]
  868.  
  869.         self._current_tex.imagename = data
  870.  
  871.     def readSURF_TALP(self, length):
  872.         """TALP chunk."""
  873.         if self._current_tex==None:
  874.             raise LWOBError, "Invalid position of the TALP chunk"
  875.         data = self.readNBytes(length)
  876.         n = data.find("\000")
  877.         if n!=-1:
  878.             data = data[:n]
  879.  
  880.         self._current_tex.alphaname = data
  881.  
  882.     def readSURF_TWRP(self, length):
  883.         """TWRP chunk."""
  884.         if length!=4:
  885.             raise LWOBError, "Invalid TWRP size (%d instead of 4)"%length
  886.         if self._current_tex==None:
  887.             raise LWOBError, "Invalid position of the TWRP chunk"
  888.         data = self.readNBytes(4)
  889.         w,h = struct.unpack(">HH", data)
  890.         self._current_tex.widthwrap = w
  891.         self._current_tex.heightwrap = h
  892.  
  893.     def readSURF_TAAS(self, length):
  894.         """TAAS chunk."""
  895.         if length!=4:
  896.             raise LWOBError, "Invalid TAAS size (%d instead of 4)"%length
  897.         if self._current_tex==None:
  898.             raise LWOBError, "Invalid position of the TAAS chunk"
  899.         data = self.readNBytes(4)
  900.         aa = struct.unpack(">f", data)[0]
  901.         self._current_tex.antialiasingstrength = aa
  902.  
  903.     def readSURF_TOPC(self, length):
  904.         """TOPC chunk."""
  905.         if length!=4:
  906.             raise LWOBError, "Invalid TOPC size (%d instead of 4)"%length
  907.         if self._current_tex==None:
  908.             raise LWOBError, "Invalid position of the TOPC chunk"
  909.         data = self.readNBytes(4)
  910.         op = struct.unpack(">f", data)[0]
  911.         self._current_tex.opacity = op
  912.  
  913.     def readSURF_SHDR(self, length):
  914.         """SHDR chunk."""
  915.         if self._current_tex==None:
  916.             raise LWOBError, "Invalid position of the SHDR chunk"
  917.         name = self.readNBytes(length)
  918.         n = name.find("\000")
  919.         if n!=-1:
  920.             name = name[:n]
  921.  
  922.         self._current_tex.shader.append(name)
  923.  
  924.     def readSURF_SDAT(self, length):
  925.         """SDAT chunk."""
  926.         if self._current_tex==None:
  927.             raise LWOBError, "Invalid position of the SDAT chunk"
  928.         data = self.readNBytes(length)
  929.         self._current_tex.shaderdata.append(data)
  930.  
  931.     def readSURF_IMSQ(self, length):
  932.         """IMSQ chunk."""
  933.         if length!=6:
  934.             raise LWOBError, "Invalid IMSQ size (%d instead of 6)"%length
  935.         if self._current_tex==None:
  936.             raise LWOBError, "Invalid position of the IMSQ chunk"
  937.         data = self.readNBytes(6)
  938.         offset,flags,looplen = struct.unpack(">HHH", data)
  939.         self._current_tex.seq_offset = offset
  940.         self._current_tex.seq_flags = flags
  941.         self._current_tex.seq_looplength = looplen
  942.  
  943.     def readSURF_FLYR(self, length):
  944.         """FLYR chunk."""
  945.         if length!=8:
  946.             raise LWOBError, "Invalid FLYR size (%d instead of 8)"%length
  947.         if self._current_tex==None:
  948.             raise LWOBError, "Invalid position of the FLYR chunk"
  949.         data = self.readNBytes(8)
  950.         b,e = struct.unpack(">II", data)
  951.         self._current_tex.flyer_begin = b
  952.         self._current_tex.flyer_end = e
  953.  
  954.     def readSURF_IMCC(self, length):
  955.         """IMCC chunk."""
  956.         if length!=6:
  957.             raise LWOBError, "Invalid IMCC size (%d instead of 6)"%length
  958.         if self._current_tex==None:
  959.             raise LWOBError, "Invalid position of the IMCC chunk"
  960.         data = self.readNBytes(6)
  961.         speed,low,high = struct.unpack(">HHH", data)
  962.         self._current_tex.cycle_speed = speed
  963.         self._current_tex.cycle_low = low
  964.         self._current_tex.cycle_high = high
  965.  
  966.  
  967.     #####
  968.  
  969.     def skipChunk(self, length):
  970.         """Skip a chunk/sub chunk in the file (without reading it).
  971.  
  972.         Sets the file's position to the begin of the next chunk.
  973.         length is the chunk length as it is stored in the file.
  974.         The method takes care of adding the pad byte if length is odd.
  975.         """
  976.         if length%2==1:
  977.             length += 1
  978.         self._file.seek(length, 1)
  979.         self._bytes_left -= length
  980.  
  981.     def readChunkHeader(self):
  982.         """Read the head of the next chunk.
  983.  
  984.         Returns a tuple (tag, length).
  985.         """
  986.         s = self.readNBytes(8)
  987.         tag = s[:4]
  988.         length = struct.unpack(">I", s[4:])[0]
  989.         return tag, length
  990.  
  991.     def readSubChunkHeader(self):
  992.         """Read the head of the next sub chunk.
  993.  
  994.         Returns a tuple (tag, length).
  995.         """
  996.         s = self.readNBytes(6)
  997.         tag = s[:4]
  998.         length = struct.unpack(">H", s[4:])[0]
  999.         return tag, length
  1000.  
  1001.     def readNBytes(self, n):
  1002.         """Read n bytes.
  1003.  
  1004.         Throws an exception if less than n bytes were read.
  1005.         """
  1006.         s = self._file.read(n)
  1007.         self._bytes_left -= len(s)
  1008.         if len(s)!=n:
  1009.             raise LWOBError, "premature end of file"
  1010.         return s
  1011.  
  1012.     def _eofReached(self):
  1013.         """Return True when the end of the file has been reached.
  1014.         """
  1015.         return self._bytes_left<=1
  1016.             
  1017.