Advertisement
Vearie

bz2ter.py - BZ2 Terrain Parser

Feb 29th, 2016 (edited)
173
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.58 KB | None | 0 0
  1. from struct import pack, unpack
  2. from math import sqrt
  3.  
  4. def from_file(file_path):
  5.     return TER().from_file(file_path)
  6.  
  7. class TER:
  8.     def __init__(self, tiles = None):
  9.         self.chunks = []
  10.        
  11.         # Highest and lowest height points
  12.         self.high = -32767
  13.         self.low = 32767
  14.        
  15.         if tiles:
  16.             self.blank(tiles)
  17.    
  18.     def __str__(self):
  19.         return "TER tiles=%d verts=%d" % (len(self.chunks), len(self.chunks)*16)
  20.    
  21.     def blank(self, tiles):
  22.         self.chunks = []
  23.         for chunk in range(tiles):
  24.             self.chunks += [Chunk()]
  25.    
  26.     def get_height_range(self):
  27.         for chunk in self.chunks:
  28.             for h in chunk.h:
  29.                 self.low = min(self.low, h)
  30.                 self.high = max(self.high, h)
  31.        
  32.         return self.low, self.high
  33.    
  34.     def from_file(self, file_path):
  35.         with open(file_path, "rb") as fl:
  36.             # [Header:16 Bytes]
  37.             magic_number = fl.read(4)
  38.             version = unpack("i", fl.read(4))[0]
  39.             if magic_number != b"TERR" or version != 3:
  40.                 raise Exception("Invalid TER file.")
  41.            
  42.             # Width(inverted), Height(inverted), Width, Height
  43.             size = unpack("HHHH", fl.read(8))
  44.             ter_chunks = (size[2]//2)*(size[3]//2)
  45.            
  46.             # [Chunks:164] Total: (ter_chuks)
  47.             for chunk_id in range(ter_chunks):
  48.                 height = list(unpack("h"*16, fl.read(32)))
  49.                 normal = list(unpack("B"*16, fl.read(16)))
  50.                
  51.                 color = []
  52.                 c_data = unpack("B"*48, fl.read(48))
  53.                 for i in range(len(c_data)//3):
  54.                     color += [[c_data[i*3], c_data[i*3+1], c_data[i*3+2]]]
  55.                
  56.                 alpha1 = list(unpack("B"*16, fl.read(16)))
  57.                 alpha2 = list(unpack("B"*16, fl.read(16)))
  58.                 alpha3 = list(unpack("B"*16, fl.read(16)))
  59.                
  60.                 fl.seek(16, 1) # Unused junk info about pathing
  61.                
  62.                 textures = unpack("H", fl.read(2))[0]
  63.                 tex0 = textures & 0x000F
  64.                 tex1 = (textures >> 4) & 0x000F
  65.                 tex2 = (textures >> 8) & 0x000F
  66.                 tex3 = (textures >> 12) & 0x000F
  67.                 fl.seek(2, 1)
  68.                
  69.                 alpha = [alpha1, alpha2, alpha3]
  70.                 textures = [tex0, tex1, tex2, tex3]
  71.                 self.chunks += [Chunk(height, normal, color, alpha, textures)]
  72.         return self
  73.    
  74.     def to_file(self, file_path):
  75.         with open(file_path, "wb") as fl:
  76.             fl.write(b"TERR")
  77.             fl.write(pack("i", 3))
  78.             size = int(sqrt(len(self.chunks)))
  79.             fl.write(pack("HHHH", 0x10000-size*2, 0x10000-size*2, size*2, size*2))
  80.            
  81.             for chunk in self.chunks:
  82.                 fl.write(chunk.pack())
  83.  
  84. class Chunk:
  85.     def __init__(self,
  86.     height   = None,
  87.     normal   = None,
  88.     rgb      = None,
  89.     alpha    = None,
  90.     textures = None):
  91.         if height is None:
  92.             height = [0 for i in range(16)]
  93.         if normal is None:
  94.             normal = [0 for i in range(16)]
  95.         if rgb is None:
  96.             rgb = [[255 for i in range(3)] for i in range(16)]
  97.         if alpha is None:
  98.             alpha = [[0 for i in range(16)] for i in range(3)]
  99.         if textures is None:
  100.             textures = [0, 1, 2, 3]
  101.        
  102.         self.h = height
  103.         self.n = normal
  104.         self.c = rgb
  105.         self.a = alpha
  106.         self.t = textures
  107.         self.data = None
  108.    
  109.     def pack(self, normals = True):
  110.         """Pack data and return as bytes."""
  111.         data = bytearray(164)
  112.         data[0:32] = pack("h"*16, *self.h)
  113.        
  114.         if normals:
  115.             data[32:48] = pack("B"*16, *self.n)
  116.        
  117.         for color, c in enumerate(self.c):
  118.             i = color*3
  119.             data[48+i:96+i] = pack("B"*3, *c)
  120.        
  121.         texint = self.t[0]
  122.         texint |= self.t[1] << 4
  123.         texint |= self.t[2] << 8
  124.         texint |= self.t[3] << 12
  125.        
  126.         data[96:112] = pack("B"*16, *self.a[0])
  127.         data[112:128] = pack("B"*16, *self.a[1])
  128.         data[128:144] = pack("B"*16, *self.a[2])
  129.         data[144:160] = b"\x00"*16
  130.         data[160:162] = pack("H", texint)
  131.         data[162:164] = b"\x00\x00" # Struct padding
  132.         return data
  133.  
  134. if __name__ == "__main__":
  135.     file = "./Subject.TER"
  136.     ter = TER().from_file(file)
  137.     print(ter)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement